442 lines
15 KiB
TypeScript
442 lines
15 KiB
TypeScript
import { Menu, Point, UIMenuSliderItem, UIMenuItem, Color, UIMenuListItem, ItemsCollection } from "../libs/NativeUI";
|
|
import { createMenuItem } from "../util";
|
|
import moneyformat from "../moneyformat";
|
|
import { getAnimFromId } from "../util/animationSync";
|
|
import { getCreatedPedByName } from "../Ped/PedCreator";
|
|
import KeyBinder from 'ragemp-better-bindings';
|
|
|
|
export const hanfPlantObjects = {
|
|
stage1: mp.game.joaat('bkr_prop_weed_bud_pruned_01a'),
|
|
stage2: mp.game.joaat('bkr_prop_weed_bud_01b'),
|
|
stage3: mp.game.joaat('prop_weed_02'),
|
|
stage4: mp.game.joaat('prop_weed_01')
|
|
};
|
|
|
|
const hanfTimeToObject = [
|
|
{
|
|
minutes: 15,
|
|
object: hanfPlantObjects.stage1,
|
|
},
|
|
{
|
|
minutes: 60 * 1,
|
|
object: hanfPlantObjects.stage2
|
|
},
|
|
{
|
|
minutes: 60 * 3,
|
|
object: hanfPlantObjects.stage3
|
|
},
|
|
{
|
|
minutes: 60 * 4,
|
|
object: hanfPlantObjects.stage4
|
|
}
|
|
]
|
|
|
|
const minimumPlantDistance = 2;
|
|
|
|
const maximumPlantDuration = 6 * 60 * 60 * 1000; // 6 Stunden / 360 Minuten / 21600 Sekunden / 21600000 Millisekunden
|
|
const timeToHarvestPlant = 4 * 60 * 60 * 1000; // 4 Stunden
|
|
|
|
export default function hanfSystem(globalData: IGlobalData) {
|
|
|
|
let currentPlantingPreviewObject: ObjectMp = null;
|
|
let currentPlantingMarkerPreview: MarkerMp = null;
|
|
let currentlyPlanting: boolean = false;
|
|
let lastPlantingState = true;
|
|
|
|
mp.events.add("SERVER:Hanf_BuySeed", (maxSeedsToBuy, price) => {
|
|
if (globalData.InMenu || globalData.InChat) {
|
|
return;
|
|
}
|
|
|
|
globalData.InMenu = true;
|
|
|
|
var menu = new Menu("Samen kaufen", "Kaufe dir Hanfsamen", new Point(50, 50));
|
|
|
|
var seedsToBuy = 0;
|
|
|
|
var countItems = [...Array(maxSeedsToBuy).keys()].map(x => x + 1);
|
|
|
|
var soloPriceItem = createMenuItem("Einzelpreis", "Preis pro Samen", item => {
|
|
item.SetRightLabel("$" + moneyformat(price));
|
|
});
|
|
menu.AddItem(soloPriceItem);
|
|
|
|
var countItem = new UIMenuListItem("Anzahl", "Wähle die Anzahl der Samen aus", new ItemsCollection(countItems), 0);
|
|
menu.AddItem(countItem);
|
|
|
|
var buyItem = new UIMenuItem("Kaufen", "Kaufe die Samen");
|
|
buyItem.BackColor = new Color(0, 100, 0);
|
|
buyItem.HighlightedBackColor = new Color(0, 150, 0);
|
|
menu.AddItem(buyItem);
|
|
|
|
var completePriceItem = new UIMenuItem("Gesamtpreis", "Preis für alle Samen");
|
|
menu.AddItem(completePriceItem);
|
|
|
|
menu.ListChange.on((item, index) => {
|
|
if (item === countItem) {
|
|
seedsToBuy = Number(countItem.SelectedValue);
|
|
completePriceItem.SetRightLabel("$" + moneyformat(seedsToBuy * price));
|
|
}
|
|
});
|
|
|
|
menu.ItemSelect.on((item, index) => {
|
|
if (item === buyItem) {
|
|
mp.events.callRemote("CLIENT:Hanf_BuySeeds", seedsToBuy);
|
|
menu.Close();
|
|
}
|
|
});
|
|
|
|
menu.MenuClose.on(() => {
|
|
globalData.InMenu = false;
|
|
});
|
|
|
|
menu.Open();
|
|
});
|
|
|
|
mp.events.add("SERVER:Hanf_SellCannabisMenu", (maxCannabisToSell, price) => {
|
|
if (globalData.InMenu || globalData.InChat) {
|
|
return;
|
|
}
|
|
|
|
globalData.InMenu = true;
|
|
|
|
var menu = new Menu("Cannabis verkaufen", "Verkaufe dein Cannabis", new Point(50, 50));
|
|
|
|
var cannabisToSell = 0;
|
|
|
|
var countItems = [...Array(maxCannabisToSell).keys()].map(x => x + 1);
|
|
|
|
var soloPriceItem = createMenuItem("Einzelpreis", "Preis pro Hanfblüte", item => {
|
|
item.SetRightLabel("$" + moneyformat(price));
|
|
});
|
|
menu.AddItem(soloPriceItem);
|
|
|
|
var countItem = new UIMenuListItem("Anzahl", "Wähle die Anzahl der Blüten aus", new ItemsCollection(countItems), 0);
|
|
menu.AddItem(countItem);
|
|
|
|
var buyItem = new UIMenuItem("Verkaufen", "Verkaufe dein Cannabis");
|
|
buyItem.BackColor = new Color(0, 100, 0);
|
|
buyItem.HighlightedBackColor = new Color(0, 150, 0);
|
|
menu.AddItem(buyItem);
|
|
|
|
var completePriceItem = new UIMenuItem("Gesamtpreis", "Preis für alle Blüten");
|
|
menu.AddItem(completePriceItem);
|
|
|
|
menu.ListChange.on((item, index) => {
|
|
if (item === countItem) {
|
|
cannabisToSell = Number(countItem.SelectedValue);
|
|
completePriceItem.SetRightLabel("$" + moneyformat(cannabisToSell * price));
|
|
}
|
|
});
|
|
|
|
menu.ItemSelect.on((item, index) => {
|
|
if (item === buyItem) {
|
|
mp.events.callRemote("CLIENT:Hanf_SellCannabis", cannabisToSell);
|
|
menu.Close();
|
|
}
|
|
});
|
|
|
|
menu.MenuClose.on(() => {
|
|
globalData.InMenu = false;
|
|
});
|
|
|
|
menu.Open();
|
|
});
|
|
|
|
mp.events.add("SERVER:Hanf_PlayManufacturerAnim", animId => {
|
|
var anim = getAnimFromId(animId);
|
|
var npc = getCreatedPedByName("hanf_verarbeiter_typ");
|
|
npc.taskPlayAnim(anim.dict, anim.name, 1, 0, 1000 * 10, 1, 0, !1, !1, !1);
|
|
setTimeout(() => {
|
|
npc.stopAnim(anim.name, anim.dict, 3);
|
|
npc.stopAnimTask(anim.dict, anim.name, 3);
|
|
}, 1000 * 10);
|
|
});
|
|
|
|
mp.events.add("SERVER:Hanf_StartPlanting", _ => {
|
|
let player = mp.players.local;
|
|
currentPlantingPreviewObject = mp.objects.new(hanfPlantObjects.stage1, player.position, {
|
|
alpha: 255
|
|
});
|
|
currentPlantingPreviewObject.notifyStreaming = true;
|
|
|
|
currentlyPlanting = true;
|
|
});
|
|
|
|
mp.events.add(RageEnums.EventKey.RENDER, _ => {
|
|
if (!currentlyPlanting) {
|
|
return;
|
|
}
|
|
|
|
var player = mp.players.local;
|
|
|
|
lastPlantingState = isAbleToPlant();
|
|
|
|
var markerColor: [number, number, number, number] = [0, 255, 0, 255];
|
|
if (!lastPlantingState) {
|
|
markerColor = [255, 0, 0, 255];
|
|
}
|
|
|
|
if (currentPlantingMarkerPreview) {
|
|
currentPlantingMarkerPreview.destroy();
|
|
}
|
|
|
|
var playerPos = player.position;
|
|
var objectPos = new mp.Vector3(playerPos.x, playerPos.y, playerPos.z - 1.0);
|
|
|
|
currentPlantingMarkerPreview = mp.markers.new(25, objectPos, 0.7, {
|
|
color: markerColor,
|
|
visible: true,
|
|
rotation: new mp.Vector3(1, 0, 0)
|
|
});
|
|
});
|
|
|
|
mp.events.add(RageEnums.EventKey.ENTITY_STREAM_IN, entity => {
|
|
if (entity === currentPlantingPreviewObject) {
|
|
currentPlantingPreviewObject.attachTo(Number(mp.players.local.handle), 0, 0, 0.2, -0.95, 0, 0, 0, true, false, false, false, 0, true);
|
|
}
|
|
});
|
|
|
|
function isAbleToPlant() {
|
|
var player = mp.players.local;
|
|
|
|
if (isNearPlant(minimumPlantDistance)) {
|
|
return false;
|
|
}
|
|
|
|
if (!isSurfaceAllowed()) {
|
|
return false;
|
|
}
|
|
|
|
if (currentPlantingPreviewObject) {
|
|
var objectPos = getPlantPreviewPosition();
|
|
var realZ = mp.game.gameplay.getGroundZFor3dCoord(objectPos.x, objectPos.y, objectPos.z + 1, 0, false);
|
|
if (realZ > objectPos.z + 1) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
if (player.isSwimming() || player.isSwimmingUnderWater() || !player.isOnFoot() || player.isSprinting() || player.isShooting()) {
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
const RAYCAST_POINT_TO_POINT_NATIVE = "0x377906D8A31E5586";
|
|
const GET_RAYCAST_RESULT_NATIVE = "0x65287525D951F6BE";
|
|
|
|
function isSurfaceAllowed() {
|
|
return true;
|
|
const player = mp.players.local;
|
|
var position = getPlantPreviewPosition();
|
|
var raycast = mp.game.invoke(RAYCAST_POINT_TO_POINT_NATIVE, position.x, position.y, position.z + 5, position.x, position.y, position.z - 5, 1, 0, 7);
|
|
mp.gui.chat.push("raycast = " + raycast);
|
|
var resultObj = {
|
|
hit: [false],
|
|
coord: [new mp.Vector3()],
|
|
surface: [new mp.Vector3()],
|
|
material: [0],
|
|
entityHit: [null]
|
|
};
|
|
|
|
var raycastResult = -1;
|
|
var retries = 10;
|
|
|
|
do {
|
|
raycastResult = mp.game.invoke(GET_RAYCAST_RESULT_NATIVE, raycast, resultObj.hit, resultObj.coord, resultObj.surface, resultObj.material, resultObj.entityHit);
|
|
retries--;
|
|
} while (raycastResult != 0 && raycastResult != 2 && retries > 0);
|
|
|
|
|
|
mp.gui.chat.push("result: " + raycastResult + ", result = " + JSON.stringify(resultObj));
|
|
|
|
return true;
|
|
}
|
|
|
|
KeyBinder.bind('e', _ => {
|
|
if (globalData.InChat) {
|
|
return;
|
|
}
|
|
|
|
if (!currentlyPlanting) {
|
|
var nearPlant = isNearPlant(0.5);
|
|
|
|
if (!nearPlant) {
|
|
return;
|
|
}
|
|
|
|
mp.events.callRemote("CLIENT:Hanf_HarvestHanf", nearPlant.Id);
|
|
|
|
return;
|
|
}
|
|
|
|
if (!lastPlantingState) {
|
|
mp.game.graphics.notify("~r~Hier kann kein Hanf platziert werden");
|
|
return;
|
|
}
|
|
|
|
currentlyPlanting = false;
|
|
|
|
var player = mp.players.local;
|
|
|
|
if (currentPlantingPreviewObject) {
|
|
currentPlantingPreviewObject.destroy();
|
|
currentPlantingPreviewObject = null;
|
|
}
|
|
|
|
if (currentPlantingMarkerPreview) {
|
|
currentPlantingMarkerPreview.destroy();
|
|
currentPlantingMarkerPreview = null;
|
|
}
|
|
|
|
var position = getPlantPreviewPosition();
|
|
var realZ = mp.game.gameplay.getGroundZFor3dCoord(position.x, position.y, position.z + 2, 0, false);
|
|
|
|
mp.events.callRemote("CLIENT:Hanf_PlantHanf", position.x, position.y, realZ);
|
|
});
|
|
|
|
function getPlantPreviewPosition(): Vector3Mp {
|
|
return mp.players.local.getOffsetFromInWorldCoords(0, 0.2, -1);
|
|
}
|
|
|
|
function getPlantText(plant: CannabisData) {
|
|
var time = Date.now() - Date.parse(plant.Time);
|
|
if (time > maximumPlantDuration) {
|
|
return ("~g~Hanf~n~~r~Verrottet");
|
|
}
|
|
return (`~g~Hanf~n~Fortschritt: ${getPlantPercentage(plant).toFixed(2)}%`);
|
|
}
|
|
|
|
function getPlantPercentage(plant: CannabisData) {
|
|
var time = Date.now() - Date.parse(plant.Time);
|
|
return Math.min((time / timeToHarvestPlant) * 100, 100);
|
|
}
|
|
|
|
function isNearPlant(distance: number): CannabisData {
|
|
var pos = getPlantPreviewPosition();
|
|
var nearPlants = currentHanfData.filter(h =>
|
|
mp.game.gameplay.getDistanceBetweenCoords(pos.x, pos.y, pos.z, h.X, h.Y, h.Z, true) < distance);
|
|
|
|
if (!nearPlants || nearPlants.length == 0) {
|
|
return null;
|
|
}
|
|
|
|
nearPlants = nearPlants.sort((a, b) =>
|
|
Number(mp.game.gameplay.getDistanceBetweenCoords(pos.x, pos.y, pos.z, a.X, a.Y, a.Z, true) <
|
|
mp.game.gameplay.getDistanceBetweenCoords(pos.x, pos.y, pos.z, b.X, b.Y, b.Z, true)));
|
|
|
|
return nearPlants[0];
|
|
}
|
|
|
|
let currentHanfData: Array<CannabisData> = [];
|
|
let hanfDataIdToObjectMap: Map<number, ObjectMp> = new Map<number, ObjectMp>();
|
|
let hanfDataIdToTextLabelMap: Map<number, TextLabelMp> = new Map<number, TextLabelMp>();
|
|
|
|
mp.events.add("SERVER:Hanf_UpdateHanf", (dataJsonArr: string[]) => {
|
|
var dataJson = dataJsonArr.join('');
|
|
var data: Array<CannabisData> = <Array<CannabisData>>JSON.parse(dataJson)
|
|
|
|
var newPlants = data.filter(d => currentHanfData.filter(x => x.Id === d.Id).length == 0);
|
|
var removedPlants = currentHanfData.filter(d => data.filter(x => x.Id === d.Id).length == 0);
|
|
var existingPlants = data.filter(d => currentHanfData.filter(x => x.Id === d.Id).length == 1);
|
|
|
|
newPlants.forEach(plant => {
|
|
var model = getPlantModel(plant);
|
|
var object = mp.objects.new(getPlantModel(plant), new mp.Vector3(plant.X, plant.Y, plant.Z));
|
|
hanfDataIdToObjectMap.set(plant.Id, object);
|
|
|
|
var textLabel = mp.labels.new(getPlantText(plant), new mp.Vector3(plant.X, plant.Y, plant.Z + 1), {
|
|
los: true,
|
|
drawDistance: 2
|
|
});
|
|
hanfDataIdToTextLabelMap.set(plant.Id, textLabel);
|
|
});
|
|
|
|
removedPlants.forEach(plant => {
|
|
var object = hanfDataIdToObjectMap.get(plant.Id);
|
|
hanfDataIdToObjectMap.delete(plant.Id);
|
|
object.destroy();
|
|
var textLabel = hanfDataIdToTextLabelMap.get(plant.Id);
|
|
textLabel.destroy();
|
|
hanfDataIdToTextLabelMap.delete(plant.Id);
|
|
});
|
|
|
|
existingPlants.forEach(plant => {
|
|
var object = hanfDataIdToObjectMap.get(plant.Id);
|
|
var model = getPlantModel(plant);
|
|
if (model != object.model) {
|
|
object.destroy();
|
|
var object = mp.objects.new(model, new mp.Vector3(plant.X, plant.Y, plant.Z));
|
|
hanfDataIdToObjectMap.delete(plant.Id);
|
|
hanfDataIdToObjectMap.set(plant.Id, object);
|
|
}
|
|
|
|
var textLabel = hanfDataIdToTextLabelMap.get(plant.Id);
|
|
textLabel.text = getPlantText(plant);
|
|
});
|
|
|
|
currentHanfData = data;
|
|
});
|
|
|
|
function getPlantModel(plant: CannabisData): number {
|
|
var diff = Date.now() - Date.parse(plant.Time);
|
|
var model = -1;
|
|
|
|
var dbgTxt;
|
|
|
|
if (diff <= 30 * 60 * 1000) { // 0 - 30 Minuten
|
|
model = hanfPlantObjects.stage1;
|
|
dbgTxt = "30 Minuten";
|
|
} else if (diff <= 4 * 60 * 60 * 1000) { // 30 - 240 Minuten / 4 Stunden
|
|
model = hanfPlantObjects.stage3;
|
|
dbgTxt = "3 Stunden";
|
|
} else { // Ausgewachsen / Ab 4 Stunden
|
|
model = hanfPlantObjects.stage4;
|
|
dbgTxt = "4 Stunden";
|
|
}
|
|
|
|
//mp.gui.chat.push("plant id = " + plant.Id + ", age = " + dbgTxt);
|
|
|
|
return model;
|
|
}
|
|
|
|
mp.events.addProc("SERVER:Hanf_GetModelToGivePlayer", id => {
|
|
var plant = currentHanfData.filter(x => x.Id == id)[0];
|
|
var model = getPlantModel(plant);
|
|
if (model == hanfPlantObjects.stage1) {
|
|
return 1;
|
|
} else if (model == hanfPlantObjects.stage3) {
|
|
return 2;
|
|
} else if (model == hanfPlantObjects.stage4) {
|
|
return 3;
|
|
}
|
|
});
|
|
|
|
//var rotationTestObject: ObjectMp = null;
|
|
//var a1: number, a2: number, a3: number, a4: number, a5: number, a6: number;
|
|
//mp.events.add(RageEnums.EventKey.PLAYER_COMMAND, (f) => {
|
|
// var args = f.split(' ');
|
|
// if (args[0] != "a") {
|
|
// return;
|
|
// }
|
|
|
|
// a1 = parseFloat(args[1] || "0");
|
|
// a2 = parseFloat(args[2] || "0");
|
|
// a3 = parseFloat(args[3] || "0");
|
|
// a4 = parseFloat(args[4] || "0");
|
|
// a5 = parseFloat(args[5] || "0");
|
|
// a6 = parseFloat(args[6] || "0");
|
|
|
|
// mp.gui.chat.push(`a1: ${a1.toFixed(2)}, a2: ${a2.toFixed(2)}, a3: ${a3.toFixed(2)}, a4: ${a4.toFixed(2)}, a5: ${a5.toFixed(2)}, a6: ${a6.toFixed(2)},`)
|
|
|
|
// if (rotationTestObject != null) {
|
|
// rotationTestObject.attachTo(Number(mp.players.local.handle), mp.players.local.getBoneIndex(57005), a1, a2, a3, a4, a5, a6, true, false, false, false, 0, true);
|
|
// return;
|
|
// }
|
|
|
|
// rotationTestObject = mp.objects.new(mp.game.joaat("prop_cs_trowel"), mp.players.local.position, {
|
|
// alpha: 255
|
|
// });
|
|
//});
|
|
} |