318 lines
14 KiB
C#
318 lines
14 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using CardealerClient.Exhibits;
|
|
using CardealerClient.Menus;
|
|
using CitizenFX.Core;
|
|
using CitizenFX.Core.Native;
|
|
using static CitizenFX.Core.Native.API;
|
|
using Nexd.ESX.Client;
|
|
|
|
namespace CardealerClient {
|
|
public class CarDealer : BaseScript {
|
|
public static CarDealer Instance;
|
|
|
|
public static ExhibitCar[] RealExhibitCars;
|
|
public static bool[] SlotReady;
|
|
public static string[] CarNames;
|
|
public static bool ExhibitsSpawned;
|
|
|
|
public static bool MenuOpen;
|
|
public static bool DigitalMenuOpen;
|
|
|
|
private static TaskCompletionSource<bool> _dialogTask;
|
|
|
|
public CarDealer() {
|
|
RealExhibitCars = new ExhibitCar[Config.CarSlots.Length];
|
|
SlotReady = new bool[Config.CarSlots.Length];
|
|
CarNames = new string[Config.CarSlots.Length];
|
|
ExhibitsSpawned = false;
|
|
|
|
EventHandlers["onClientResourceStart"] += new Action<string>(OnStart);
|
|
EventHandlers["onResourceStop"] += new Action<string>(OnStop);
|
|
EventHandlers["cardealer:spawnVehicle"] += new Action<int>(SpawnExhibit);
|
|
EventHandlers["cardealer:openmenu"] += new Action(SellMenu.Open);
|
|
EventHandlers["cardealer:testDriveClient"] += new Action<int, bool>((slot, value) => RealExhibitCars[slot]?.SetTestDrive(value));
|
|
EventHandlers["cardealer:openManageMenu"] += new Action(OwnerMenu.Open);
|
|
|
|
EventHandlers["cardealer:dialog_accept"] += new Action(() => _dialogTask?.TrySetResult(true));
|
|
EventHandlers["cardealer:dialog_deny"] += new Action(() => _dialogTask?.TrySetResult(false));
|
|
|
|
Instance = this;
|
|
}
|
|
|
|
public static Task<dynamic> ServerCallback(string name, dynamic args = null) {
|
|
var source = new TaskCompletionSource<dynamic>();
|
|
ESX.TriggerServerCallback(name, new Action<dynamic>(o => {
|
|
source.TrySetResult(o);
|
|
}), args);
|
|
return source.Task;
|
|
}
|
|
|
|
public static Task<int> SpawnVehicle(dynamic model, Vector3 coords, float heading, bool local = false) {
|
|
var source = new TaskCompletionSource<int>();
|
|
|
|
if (local) {
|
|
ESX.Game.Raw.SpawnLocalVehicle(model, coords, heading, new Action<int>(vehicle => {
|
|
source.TrySetResult(vehicle);
|
|
}));
|
|
}
|
|
else {
|
|
ESX.Game.Raw.SpawnVehicle(model, coords, heading, new Action<int>(vehicle => {
|
|
source.TrySetResult(vehicle);
|
|
}));
|
|
}
|
|
|
|
return source.Task;
|
|
}
|
|
|
|
public static Task<List<string>> GetVehicleNames(dynamic models) {
|
|
var source = new TaskCompletionSource<List<string>>();
|
|
TriggerEvent("cardealer:getCarNames", models, new Action<dynamic>(o => {
|
|
source.TrySetResult((o as List<object>).Select(val => val.ToString()).ToList());
|
|
}));
|
|
return source.Task;
|
|
}
|
|
|
|
public static Task<string> DisplayTextDialog(string placeholder, int maxLength) {
|
|
var source = new TaskCompletionSource<string>();
|
|
DisplayOnscreenKeyboard(0, "FMMC_KEY_TIP8", "", placeholder, "", "", "", maxLength);
|
|
|
|
new Thread(() => {
|
|
bool input = true;
|
|
|
|
while (input) {
|
|
if (UpdateOnscreenKeyboard() == 3 || UpdateOnscreenKeyboard() == 2)
|
|
input = false;
|
|
else if (UpdateOnscreenKeyboard() == 1) {
|
|
input = false;
|
|
source.TrySetResult(GetOnscreenKeyboardResult());
|
|
}
|
|
|
|
Thread.Sleep(0);
|
|
}
|
|
}).Start();
|
|
|
|
return source.Task;
|
|
}
|
|
|
|
public static Task<bool> DisplayConfirmationDialog(string title) {
|
|
_dialogTask = new TaskCompletionSource<bool>();
|
|
|
|
TriggerEvent("okokRequests:RequestMenuData", -1, Config.MenuTitle, title, "cardealer:dialog_accept", "client", "", 0, "cardealer:dialog_deny");
|
|
|
|
return _dialogTask.Task;
|
|
}
|
|
|
|
public static void DrawText3D(Vector3 pos, string text, float scale = 1, bool rotate = true) {
|
|
OutputArgument screenX = new OutputArgument(), screenY = new OutputArgument();
|
|
bool onScreen = Function.Call<bool>(Hash.GET_SCREEN_COORD_FROM_WORLD_COORD , pos.X, pos.Y, pos.Z, screenX, screenY);
|
|
if (onScreen) {
|
|
Vector3 cam = GetGameplayCamCoord();
|
|
float dist = GetDistanceBetweenCoords(cam.X, cam.Y, cam.Z, pos.X, pos.Y, pos.Z, true);
|
|
|
|
if (rotate)
|
|
scale = (((1 / dist) * 2) * (1 / GetGameplayCamFov()) * 100) * scale;
|
|
|
|
SetTextColour(220, 220, 220, 255);
|
|
SetTextScale(0.0f * scale, 0.40f * scale);
|
|
SetTextFont(4);
|
|
SetTextProportional(true);
|
|
SetTextCentre(true);
|
|
|
|
SetTextEntry("STRING");
|
|
AddTextComponentString(text);
|
|
EndTextCommandDisplayText(screenX.GetResult<float>(), screenY.GetResult<float>());
|
|
}
|
|
}
|
|
|
|
private void ShowText(int slot) {
|
|
Exhibit exhibit = RealExhibitCars[slot].Exhibit;
|
|
float x = exhibit.Location.X;
|
|
float y = exhibit.Location.Y;
|
|
float z = exhibit.Location.Z;
|
|
|
|
if (RealExhibitCars[slot].TestDrive)
|
|
DrawText3D(new Vector3(x, y, z + 0.8f), "[~r~Dieses Auto ist gerade bei einer Probefahrt~s~]");
|
|
else {
|
|
VehicleData data = RealExhibitCars[slot].Data;
|
|
string turbo = "~r~Nein";
|
|
if (Convert.ToBoolean(data.Properties.Raw.modTurbo)) turbo = "~g~Ja";
|
|
|
|
string line1 = "[~b~" + CarNames[slot] + "~s~]";
|
|
string line2 = "[Turbo : " + turbo + "~s~] [Motor : ~r~" + data.Properties.modEngine + "~s~] [Getriebe : ~r~" + data.Properties.modTransmission + "~s~]";
|
|
string line3 = "[Federung : ~r~" + data.Properties.modSuspension + "~s~] [Panzerung : ~r~" + data.Properties.modArmor + "~s~] [Bremsen : ~r~" + data.Properties.modBrakes + "~s~]";
|
|
string line4 = "[Beschreibung : ~r~" + data.Description + "~s~]";
|
|
string line5 = "Drücke [~r~E~s~] zum kaufen [$~r~" + data.Price + "~s~]";
|
|
string line6 = "Drücke [~r~F~s~] zum probefahren [~r~90 sek~s~]";
|
|
|
|
DrawText3D(new Vector3(x, y, z + 1.1f), line6);
|
|
DrawText3D(new Vector3(x, y, z + 1.2f), line5);
|
|
DrawText3D(new Vector3(x, y, z + 1.3f), line4);
|
|
DrawText3D(new Vector3(x, y, z + 1.4f), line3);
|
|
DrawText3D(new Vector3(x, y, z + 1.5f), line2);
|
|
DrawText3D(new Vector3(x, y, z + 1.6f), line1);
|
|
}
|
|
}
|
|
|
|
public static void SendNotification(string message) {
|
|
SetNotificationTextEntry("STRING");
|
|
AddTextComponentString(message);
|
|
DrawNotification(false, false);
|
|
}
|
|
|
|
public static void Notify(string message, string type, int duration = 5000) {
|
|
TriggerEvent("okokNotify:Alert", Config.MenuTitle, message, duration, type);
|
|
}
|
|
|
|
public static void AddTickHandler(Func<Task> handler) {
|
|
Instance.Tick += handler;
|
|
}
|
|
public static void RemoveTickHandler(Func<Task> handler) {
|
|
Instance.Tick -= handler;
|
|
}
|
|
|
|
private void DisplayHelpTextThisFrame(string text) {
|
|
SetTextComponentFormat("STRING");
|
|
AddTextComponentString(text);
|
|
EndTextCommandDisplayHelp(0, false, true, -1);
|
|
}
|
|
|
|
private void SpawnRealExhibits() {
|
|
if (ExhibitsSpawned) return;
|
|
for (int i = 1; i < Config.CarSlots.Length; i++) {
|
|
TriggerEvent("cardealer:spawnVehicle", i);
|
|
}
|
|
ExhibitsSpawned = true;
|
|
}
|
|
|
|
private void DeleteRealExhibits() {
|
|
if (!ExhibitsSpawned) return;
|
|
for (int i = 1; i < Config.CarSlots.Length; i++) {
|
|
if (SlotReady[i])
|
|
RealExhibitCars[i].Despawn();
|
|
}
|
|
ExhibitsSpawned = false;
|
|
}
|
|
|
|
|
|
// EVENT FUNCTIONS
|
|
|
|
private void OnStart(string resourceName) {
|
|
if (resourceName != GetCurrentResourceName()) return;
|
|
for (int i = 1; i < Config.CarSlots.Length; i++)
|
|
SlotReady[i] = false;
|
|
|
|
Tick += async () => {
|
|
ExhibitCar.RepairVehicles();
|
|
|
|
//EXHIBIT INTERACTION
|
|
Vector3 player = GetEntityCoords(GetPlayerPed(-1), IsDecalAlive(GetPlayerPed(-1)));
|
|
bool playerIsInRadius = GetDistanceBetweenCoords(
|
|
player.X, player.Y, player.Z,
|
|
Config.BlipLocation.X, Config.BlipLocation.Y,
|
|
Config.BlipLocation.Z, false) <
|
|
Config.SpawnRadius;
|
|
|
|
if (!ExhibitsSpawned && playerIsInRadius) SpawnRealExhibits();
|
|
if (ExhibitsSpawned && !playerIsInRadius) DeleteRealExhibits();
|
|
|
|
bool found = false;
|
|
float closestDist = float.MaxValue;
|
|
int closestSlot = 0;
|
|
|
|
for (int i = 0; i < RealExhibitCars.Length; i++) {
|
|
if (!SlotReady[i]) continue;
|
|
Vector4 exPos = RealExhibitCars[i].Exhibit.Location;
|
|
float dist =
|
|
GetDistanceBetweenCoords(player.X, player.Y, player.Z, exPos.X, exPos.Y, exPos.Z, true);
|
|
if (closestDist > dist) {
|
|
closestDist = dist;
|
|
found = true;
|
|
closestSlot = RealExhibitCars[i].Exhibit.Slot;
|
|
}
|
|
}
|
|
|
|
if (found) {
|
|
if (closestDist < 5) {
|
|
ShowText(closestSlot);
|
|
|
|
if (!RealExhibitCars[closestSlot].TestDrive) {
|
|
if (IsControlJustReleased(0, 38) && !RealExhibitCars[closestSlot].TestDrive)
|
|
RealExhibitCars[closestSlot].Buy();
|
|
|
|
if (IsControlJustReleased(0, 23) && !RealExhibitCars[closestSlot].TestDrive)
|
|
RealExhibitCars[closestSlot].StartTestDrive();
|
|
}
|
|
}
|
|
}
|
|
|
|
DigitalExhibit.ShowDigitalText();
|
|
|
|
//BLIP INTERACTION
|
|
if (IsPedInAnyVehicle(GetPlayerPed(-1), false)) {
|
|
DrawMarker(1, Config.BlipLocation.X, Config.BlipLocation.Y, Config.BlipLocation.Z, 0, 0, 0, 0, 0, 0,
|
|
3.7f, 3.7f, 0.2f, 3, 155, 229, 255, false, false, 0, false, null, null, false);
|
|
|
|
float distanceToMarker = GetDistanceBetweenCoords(player.X, player.Y, player.Z, Config.BlipLocation.X,
|
|
Config.BlipLocation.Y, Config.BlipLocation.Z, true);
|
|
if (distanceToMarker <= 4f) {
|
|
if (!MenuOpen)
|
|
DisplayHelpTextThisFrame("Drücke ~INPUT_CONTEXT~ um das Menü zu öffnen");
|
|
|
|
if (IsControlJustReleased(0, 38) && !MenuOpen)
|
|
SellMenu.Open();
|
|
}
|
|
}
|
|
|
|
float digiDist = GetDistanceBetweenCoords(player.X, player.Y, player.Z, Config.DigitalShowPoint.X, Config.DigitalShowPoint.Y, Config.DigitalShowPoint.Z, true);
|
|
if (digiDist < 2 && !DigitalMenuOpen) {
|
|
DrawText3D(Config.DigitalShowPoint, "Drücke ~g~E~s~ um den Katalog zu öffnen");
|
|
|
|
if (IsControlJustReleased(0, 38))
|
|
DigitalExhibit.HandleDigitalExhibit();
|
|
}
|
|
};
|
|
}
|
|
|
|
private void OnStop(string resourceName) {
|
|
if (resourceName != GetCurrentResourceName()) return;
|
|
DeleteRealExhibits();
|
|
}
|
|
|
|
private async void SpawnExhibit(int slot) {
|
|
Exhibit exhibit = Config.CarSlots[slot];
|
|
|
|
ExhibitCar old = RealExhibitCars[slot];
|
|
if (old != null) ESX.Game.DeleteVehicle(old.Vehicle.ToString());
|
|
|
|
var vehicle = await ServerCallback("cardealer:getVehicleData", slot);
|
|
|
|
if (vehicle is List<object>) {
|
|
if (RealExhibitCars[slot] != null) {
|
|
RealExhibitCars[slot].Despawn();
|
|
}
|
|
RealExhibitCars[slot] = null;
|
|
return;
|
|
}
|
|
|
|
VehicleData data = new VehicleData(vehicle);
|
|
|
|
if (data.Properties == null) {
|
|
if (RealExhibitCars[slot] != null) {
|
|
RealExhibitCars[slot].Despawn();
|
|
}
|
|
RealExhibitCars[slot] = null;
|
|
return;
|
|
}
|
|
|
|
ExhibitCar car = new ExhibitCar(exhibit, data);
|
|
car.SetTestDrive(await ServerCallback("cardealer:getTestDrive", slot));
|
|
|
|
RealExhibitCars[slot] = car;
|
|
}
|
|
|
|
}
|
|
} |