using System; using System.Collections.Generic; using System.Linq; using CitizenFX.Core; using CitizenFX.Core.Native; using CitizenFX.Core.UI; using Nexd.ESX.Client; using TaxiJob.Client.Extensions; using TaxiJob.Shared; namespace TaxiJob.Client.Handler { public static class JobHandler { private static bool _vehicleSpawned; private static Blip _vehicleBlip; private static Blip _taskBlip; private static int _lastJob; private static bool _arrived; private static bool _lookStarted; private static Ped _npc; private static int _nextSpeech; private static int _lastUpdate = 0; private static Vector3 _lastPos = Vector3.Zero; private static int _requestTime = 0; public static Vehicle Vehicle; public static bool InJob; public static bool PendingJob; public static bool IsNpcJob; public static Vector3 Destination; public static string JobId; public static void RequestJob(Vector3 destination, string jobId) { _requestTime = Game.GameTime; Destination = destination; JobId = jobId; PendingJob = true; TaxiJob.SetServiceStatus(false); } public static void OnTick() { HandleVehicleSpawner(); HandleVehicleDeleter(); HandleVehicleBlip(); HandleNpcJob(); HandleJob(); HandleJobAcception(); if (!InJob && _vehicleSpawned && _vehicleBlip == null && Game.GameTime - _lastJob >= TaxiJob.Config.TimeToNpcJob && !PendingJob) { IsNpcJob = true; _requestTime = Game.GameTime; PendingJob = true; TaxiJob.SetServiceStatus(false); Game.PlaySound("SELECT", "HUD_FRONTEND_DEFAULT_SOUNDSET"); } if (Game.PlayerPed.IsDead && InJob) StopJob(); } private static async void HandleVehicleSpawner() { if (_vehicleSpawned || Game.PlayerPed.IsInVehicle()) return; var dist = World.GetDistance(Game.PlayerPed.Position, TaxiJob.Config.VehicleSpawner.Position); if (dist >= TaxiJob.Config.DrawDistance) return; TaxiJob.Config.VehicleSpawner.Render(); if (dist <= TaxiJob.Config.VehicleSpawner.Size.X) { Screen.DisplayHelpTextThisFrame("Drücke ~INPUT_CONTEXT~ um das Taxi aus der Garage zu holen"); if (Game.IsControlJustReleased(0, Control.Context)) { if (!await TaxiJob.ServerCallback("esx_license:hasLicense", "drive")) { Notify.Error("Du hast keinen Führerschein!"); return; } if (!ESX.Game.IsSpawnPointClear(TaxiJob.Config.VehicleSpawnPoint.ToVector3(), 5.0)) { Notify.Error("Ein Fahrzeug blockiert den Spawnpunkt!"); return; } Vehicle = await TaxiJob.SpawnVehicle(API.GetHashKey(TaxiJob.Config.VehicleModel), TaxiJob.Config.VehicleSpawnPoint); Vehicle.Mods.LicensePlate = await TaxiJob.GeneratePlate(); BaseScript.TriggerEvent("craftix:refuelVehicle", Vehicle.Handle); Game.PlayerPed.SetIntoVehicle(Vehicle, VehicleSeat.Driver); _lastJob = Game.GameTime; _vehicleSpawned = true; TaxiJob.SetServiceStatus(true); } } } private static void HandleVehicleDeleter() { if (_vehicleSpawned) { if (!Vehicle.Exists() || Vehicle.IsDead) { _vehicleBlip?.Delete(); StopJob(); _vehicleSpawned = false; _vehicleBlip = null; Vehicle = null; return; } } if (!_vehicleSpawned || !Game.PlayerPed.IsInVehicle(Vehicle)) return; World.DrawMarker(MarkerType.HorizontalCircleSkinny, TaxiJob.Config.VehicleDeleter, Vector3.Zero, Vector3.Zero, new Vector3(3.7f, 3.7f, 0.2f), TaxiJob.Config.VehicleSpawner.Color); var dist = World.GetDistance(Game.PlayerPed.Position, TaxiJob.Config.VehicleDeleter); if (dist >= 4.0f) return; Screen.DisplayHelpTextThisFrame("Drücke ~INPUT_CONTEXT~ um das Auto in die Garage zu stellen"); if (Game.IsControlJustReleased(0, Control.Context)) { Vehicle?.Delete(); _vehicleBlip?.Delete(); StopJob(); _vehicleSpawned = false; _vehicleBlip = null; Vehicle = null; Taximeter.Reset(); TaxiJob.SetServiceStatus(false); } } private static void HandleVehicleBlip() { if (!_vehicleSpawned) return; var inVehicle = Game.PlayerPed.IsInVehicle(Vehicle); if (inVehicle && _vehicleBlip != null) { _lastJob = Game.GameTime; _vehicleBlip?.Delete(); _vehicleBlip = null; } else if (!inVehicle && _vehicleBlip == null) { _vehicleBlip = new Blip(API.AddBlipForEntity(Game.PlayerPed.LastVehicle.Handle)); _vehicleBlip.Sprite = (BlipSprite)198; _vehicleBlip.Color = BlipColor.Yellow; _vehicleBlip.Name = "Dienstwagen"; API.SetBlipDisplay(_vehicleBlip.Handle, 4); } if (inVehicle && Game.IsControlJustReleased(0, Control.SelectCharacterFranklin)) { if (TaxiMenuHandler.MenuOpen) TaxiMenuHandler.CloseMenu(); else TaxiMenuHandler.OpenMenu(); } if (inVehicle) HandleTaximeter(); } private static void HandleJob() { if (!InJob || IsNpcJob) return; if (!_arrived && _taskBlip != null) { if (!Game.PlayerPed.IsInVehicle()) return; var dist = World.GetDistance(Game.PlayerPed.CurrentVehicle.Position, _taskBlip.Position); if (dist <= 30.0 && Game.PlayerPed.CurrentVehicle.Speed <= 1) { _taskBlip.Delete(); _taskBlip = null; } } if (!_arrived && Game.PlayerPed.CurrentVehicle?.PassengerCount != 0) { _arrived = true; Taximeter.ActivateForClient(true); _taskBlip?.Delete(); _taskBlip = null; Taximeter.Attributes.CurrentFare = "000.00"; Taximeter.Attributes.DistanceTraveled = 0; Taximeter.Pause(false); } if (_arrived && Game.PlayerPed.CurrentVehicle?.PassengerCount == 0) { var price = (int)Math.Round(Convert.ToSingle(Taximeter.Attributes.CurrentFare) + 0.5f); BaseScript.TriggerServerEvent("taxijob:server:bill", price, Taximeter.CurrentClient); BaseScript.TriggerServerEvent("taxijob:server:payout", (int)Math.Floor(price * 0.9f)); StopJob(); } } private static void HandleNpcJob() { if (!InJob || !IsNpcJob) return; if (!_arrived) { if (!Game.PlayerPed.IsInVehicle()) return; var dist = World.GetDistance(Game.PlayerPed.Position, _npc.Position); if (!_lookStarted && dist <= 50.0 && dist > 30.0) { _npc.Task.LookAt(Game.PlayerPed, int.MaxValue); _lookStarted = true; } if (dist <= 30.0 && Game.PlayerPed.CurrentVehicle.Speed <= 1) { _npc.Task.ClearAllImmediately(); _npc.Task.EnterVehicleOnFreeSeat(Game.PlayerPed.CurrentVehicle, VehicleSeat.RightRear); _npc.PlayAmbientSpeech("GENERIC_HI"); _taskBlip.Delete(); _taskBlip = null; _arrived = true; var random = new Random(); _nextSpeech = Game.GameTime + (random.Next(5000) + 20000); } } if (_arrived && _taskBlip == null && _npc.IsInVehicle()) { var playerPos = Game.PlayerPed.Position; var target = TaxiJob.Config.Positions .Where(pos => World.GetDistance(playerPos, pos) >= 500.0f) .Random(); _taskBlip = new Blip(API.AddBlipForCoord(target.X, target.Y, target.Z)); _taskBlip.Name = "Ziel"; _taskBlip.ShowRoute = true; Notify.Info("Zielposition wurde im Navi eingegeben."); } if (_arrived && _taskBlip != null) { if (!Game.PlayerPed.IsInVehicle()) return; var dist = World.GetDistance(Game.PlayerPed.Position, _taskBlip.Position); if (_nextSpeech <= Game.GameTime) { var random = new Random(); _nextSpeech = Game.GameTime + (random.Next(5000) + 20000); _npc.PlayAmbientSpeech("GENERIC_HOWS_IT_GOING"); } if (dist <= 30.0 && Game.PlayerPed.CurrentVehicle.Speed <= 1) { InJob = false; _npc.Task.LeaveVehicle(_npc.CurrentVehicle, true); _npc.PlayAmbientSpeech("GENERIC_THANKS"); _npc.MarkAsNoLongerNeeded(); _npc = null; var price = (int)Math.Floor(Convert.ToSingle(Taximeter.Attributes.CurrentFare) * 0.9f); StopJob(); BaseScript.TriggerServerEvent("taxijob:server:payout", price); Notify.Success($"Auftrag beendet!\nDu hast ${price} bekommen."); } } } private static void HandleTaximeter() { if (!InJob || Taximeter.Attributes.MeterPause || Taximeter.Attributes.DistanceTraveled >= 15000) return; var current = Game.GameTime; if (current - _lastUpdate < 2000) return; _lastUpdate = current; var pos = Game.PlayerPed.CurrentVehicle.Position; if (_lastPos == Vector3.Zero) _lastPos = pos; Taximeter.CalculatePrice(_lastPos, pos); _lastPos = pos; } private static void HandleJobAcception() { if (!PendingJob) return; Screen.DisplayHelpTextThisFrame("Neuer Auftrag!~n~~INPUT_SELECT_WEAPON_UNARMED~ Annehmen~n~~INPUT_SELECT_WEAPON_MELEE~ Ablehnen"); if (Game.IsControlJustReleased(0, Control.SelectWeaponUnarmed)) { if (IsNpcJob) StartNpcJob(); else { BaseScript.TriggerServerEvent("taxijob:server:accept", true, JobId); StartJob(); } } if (Game.IsControlJustReleased(0, Control.SelectWeaponMelee) || Game.GameTime - _requestTime > 30000) { BaseScript.TriggerServerEvent("taxijob:server:accept", false, JobId); StopJob(); } } public static void StartJob() { TaxiMenuHandler.CloseMenu(); Taximeter.Reset(Taximeter.Attributes.MeterVisible); var dest = Destination; StopJob(false); TaxiJob.SetServiceStatus(false); _taskBlip = new Blip(API.AddBlipForCoord(dest.X, dest.Y, dest.Z)); _taskBlip.Name = "Kunde"; _taskBlip.ShowRoute = true; InJob = true; } private static async void StartNpcJob() { TaxiMenuHandler.CloseMenu(); Taximeter.Reset(Taximeter.Attributes.MeterVisible); StopJob(false); TaxiJob.SetServiceStatus(false); var target = TaxiJob.Config.Positions.Random(); _taskBlip = new Blip(API.AddBlipForCoord(target.X, target.Y, target.Z)); _taskBlip.Name = "Kunde"; _taskBlip.ShowRoute = true; var model = new Model(TaxiJob.Config.Npcs.Random()); await model.Load(); _npc = await World.CreatePed(model, target); _npc.AsMissionEntry(); _npc.Task.ClearAllImmediately(); _npc.LootAtStreet(); _npc.SetBlockingOfNonTemporaryEvents(true); _npc.IsInvincible = true; _npc.Task.StandStill(int.MaxValue); IsNpcJob = true; InJob = true; Taximeter.Pause(false); } public static void StopJob(bool updateService = true) { _taskBlip?.Delete(); _taskBlip = null; _npc?.Task.ClearAllImmediately(); _npc?.MarkAsNoLongerNeeded(); _npc = null; InJob = false; IsNpcJob = false; _arrived = false; _lookStarted = false; _lastJob = Game.GameTime; PendingJob = false; Destination = Vector3.Zero; JobId = null; Taximeter.Pause(true); if (updateService) TaxiJob.SetServiceStatus(true); Taximeter.ActivateForClient(false); } } }