public static void Start(MissionType type, int labIndex, List <Vector3> coords, float vehicleHeading, int timeMs, int productAmount = 0) { if (!IsActive) { IsActive = true; _missionType = type; _missionEndTime = Game.GameTime + timeMs; _missionModel = Game.Player.Character.Model.Hash; _missionLabIdx = labIndex; _productAmount = productAmount; _objectiveCoords = coords; if (_missionBarPool == null) { _missionBarPool = new TimerBarPool(); _missionTimeBar = new TextTimerBar("TIME LEFT", "00:00"); _missionBarPool.Add(_missionTimeBar); } foreach (Vector3 pos in _objectiveCoords) { Function.Call(Hash.CLEAR_AREA, pos.X, pos.Y, pos.Z, 5f, true, false, false, false); } // spaghetti switch (_missionType) { case MissionType.Setup: { _missionVehicle = World.CreateVehicle(VehicleHash.Pounder, _objectiveCoords[0], vehicleHeading); _missionVehicle.PrimaryColor = VehicleColor.MetallicBlack; _missionVehicle.SecondaryColor = VehicleColor.MetallicBlack; _missionVehicle.IsPersistent = true; Blip vehicleBlip = _missionVehicle.AddBlip(); vehicleBlip.Sprite = BlipSprite.Package2; vehicleBlip.Color = BlipColor.Blue; vehicleBlip.IsShortRange = false; vehicleBlip.Name = "Supply Truck"; Blip deliveryBlip = World.CreateBlip(_objectiveCoords[1]); deliveryBlip.Sprite = BlipSprite.Standard; deliveryBlip.Color = BlipColor.Yellow; deliveryBlip.IsShortRange = false; deliveryBlip.Alpha = 0; deliveryBlip.Name = "Meth Lab"; _missionBlips.Add("vehicle", vehicleBlip); _missionBlips.Add("deliveryPoint", deliveryBlip); NotificationQueue.Add("LJT", $"{Util.GetCharacterFromModel(_missionModel)}, a gang member posted about their supply truck online. Go to {World.GetZoneName(_objectiveCoords[0])} and take it, they won't even know!", "CHAR_LJT", 1); break; } case MissionType.Delivery: { _missionVehicle = World.CreateVehicle(Constants.DeliveryVehicles[Constants.RandomGenerator.Next(0, Constants.DeliveryVehicles.Length)], _objectiveCoords[0], vehicleHeading); _missionVehicle.IsPersistent = true; Blip vehicleBlip = _missionVehicle.AddBlip(); vehicleBlip.Sprite = BlipSprite.Package2; vehicleBlip.Color = BlipColor.Blue; vehicleBlip.IsShortRange = false; vehicleBlip.Name = "Delivery Vehicle"; Blip deliveryBlip = World.CreateBlip(_objectiveCoords[1]); deliveryBlip.Sprite = BlipSprite.Standard; deliveryBlip.Color = BlipColor.Yellow; deliveryBlip.IsShortRange = false; deliveryBlip.Alpha = 0; deliveryBlip.Name = "Delivery Point"; _missionBlips.Add("vehicle", vehicleBlip); _missionBlips.Add("deliveryPoint", deliveryBlip); NotificationQueue.Add("LJT", $"{Util.GetCharacterFromModel(_missionModel)}, the buyer wants the product to be delivered to {World.GetZoneName(_objectiveCoords[1])}.", "CHAR_LJT", 1); break; } } foreach (Lab lab in Main.MethLabs) { lab.SetBlipVisible(false); } SetStage(MissionStage.GetInVehicle); } }
public void Script_Tick(object sender, EventArgs e) { // Load labs #region Lab Loading if (!MethLabsLoaded && !Game.IsLoading && Game.Player.CanControlCharacter) { try { string labsFile = Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "mod_methoperation"), "methoperation_labs.xml"); if (!File.Exists(labsFile)) { string backupLabsFile = Path.Combine("scripts", "methoperation_labs.xml"); Directory.CreateDirectory(Path.GetDirectoryName(labsFile)); File.Copy(backupLabsFile, labsFile); } if (File.Exists(labsFile)) { MethLabs = XmlUtil.Deserialize <List <Lab> >(File.ReadAllText(labsFile)); foreach (Lab lab in MethLabs) { lab.CreateEntities(); } ManagementBlip = World.CreateBlip(Constants.MethLabLaptop); ManagementBlip.Alpha = 0; ManagementBlip.Sprite = BlipSprite.Laptop; ManagementBlip.IsShortRange = true; Function.Call(Hash.SET_BLIP_DISPLAY, ManagementBlip.Handle, 8); } else { UI.Notify($"~r~MethOperation labs file not found!"); } } catch (Exception ex) { UI.Notify($"~r~MethOperation loading error: {ex.Message}"); } MethLabsLoaded = true; } #endregion // process queued notifications if (!NotificationQueue.IsEmpty()) { if (!Game.IsLoading) { NotificationQueue.ProcessAll(); } } // No need to go further if in a mission if (Mission.IsActive) { return; } // Update player position int gameTime = Game.GameTime; if (gameTime > NextUpdate) { NextUpdate = gameTime + Constants.UpdateInterval; PlayerPosition = Game.Player.Character.Position; if (InsideMethLabIdx != -1) { int interiorID = Function.Call <int>(Hash.GET_INTERIOR_AT_COORDS_WITH_TYPE, PlayerPosition.X, PlayerPosition.Y, PlayerPosition.Z, "bkr_biker_dlc_int_ware01"); if (interiorID != LabInteriorID) { LeftMethLab.Invoke(InsideMethLabIdx, LabExitReason.Teleport); InsideMethLabIdx = -1; } else if (Game.Player.Character.Model.Hash != PlayerLabModel) { LeftMethLab.Invoke(InsideMethLabIdx, LabExitReason.CharacterChange); InsideMethLabIdx = -1; } } } // Draw markers & helptexts #region Drawing if (InsideMethLabIdx != -1) { // Handle NativeUI ManagementMenuPool.ProcessMenus(); // Inside, draw interactable markers World.DrawMarker(MarkerType.VerticalCylinder, Constants.MethLabExit, Vector3.Zero, Vector3.Zero, Constants.MarkerScale, Constants.MarkerColor); World.DrawMarker(MarkerType.VerticalCylinder, Constants.MethLabLaptop, Vector3.Zero, Vector3.Zero, Constants.MarkerScale, Constants.MarkerColor); // Laptop screen if (LaptopRTID != -1) { Function.Call(Hash.SET_TEXT_RENDER_ID, LaptopRTID); Function.Call(Hash._SET_SCREEN_DRAW_POSITION, 73, 73); Function.Call(Hash._SET_2D_LAYER, 4); Function.Call(Hash._0xC6372ECD45D73BCD, true); Function.Call((Hash)0x2BC54A8188768488, "prop_screen_biker_laptop", "prop_screen_biker_laptop_2", 0.5f, 0.5f, 1f, 1f, 0f, 255, 255, 255, 255); Function.Call((Hash)0xE3A3DB414A373DAB); Function.Call(Hash.SET_TEXT_RENDER_ID, 1); } if (PlayerPosition.DistanceTo(Constants.MethLabExit) <= Constants.MarkerInteractionDistance) { CurrentInteractionType = InteractionType.ExitMethLab; Util.DisplayHelpText($"Press {HelpTextKeys.Get(InteractionControl)} to leave the meth lab."); } else if (PlayerPosition.DistanceTo(Constants.MethLabLaptop) <= Constants.MarkerInteractionDistance) { CurrentInteractionType = InteractionType.ManageMethLab; Util.DisplayHelpText($"Press {HelpTextKeys.Get(InteractionControl)} to manage the meth lab."); } else { ManagementMenuPool.CloseAllMenus(); if (IsLeaning) { CurrentInteractionType = InteractionType.CancelLean; Util.DisplayHelpText($"Press {HelpTextKeys.Get(InteractionControl)} to stop leaning on the rail."); } else { if (Game.Player.Character.IsInArea(Constants.LeanAreaMin, Constants.LeanAreaMax)) { CurrentInteractionType = InteractionType.Lean; Util.DisplayHelpText($"Press {HelpTextKeys.Get(InteractionControl)} to lean on the rail."); } } } // Disable some controls inside the interior for (int i = 0; i < Constants.ControlsToDisable.Length; i++) { Function.Call(Hash.DISABLE_CONTROL_ACTION, 2, Constants.ControlsToDisable[i], true); } } else { // Outside, draw lab markers for (int i = 0; i < MethLabs.Count; i++) { DistanceToInteractable = PlayerPosition.DistanceTo(MethLabs[i].Position); if (DistanceToInteractable <= Constants.MarkerDrawDistance) { World.DrawMarker(MarkerType.VerticalCylinder, MethLabs[i].Position, Vector3.Zero, Vector3.Zero, Constants.MarkerScale, Constants.MarkerColor); if (DistanceToInteractable <= Constants.MarkerInteractionDistance) { InteractableLabIdx = i; if (MethLabs[i].HasFlag(LabFlags.IsOwned)) { CurrentInteractionType = InteractionType.EnterMethLab; Util.DisplayHelpText($"Press {HelpTextKeys.Get(InteractionControl)} to enter the meth lab."); } else { CurrentInteractionType = InteractionType.BuyMethLab; Util.DisplayHelpText($"Press {HelpTextKeys.Get(InteractionControl)} to buy the {MethLabs[i].Location} meth lab.~n~Price: ~g~${MethLabs[i].Price:N0}"); } break; } } } } #endregion // Handle interactions #region Interaction Handling if (Game.IsControlJustPressed(2, (Control)InteractionControl)) { int labIdx = InteractableLabIdx == -1 ? InsideMethLabIdx : InteractableLabIdx; if (labIdx == -1) { return; } Character currentCharacter = Util.GetCharacterFromModel(Game.Player.Character.Model.Hash); if (currentCharacter == Character.Unknown) { UI.Notify("Only Michael, Franklin and Trevor can interact with meth labs."); return; } switch (CurrentInteractionType) { case InteractionType.BuyMethLab: if (PlayerPosition.DistanceTo(MethLabs[labIdx].Position) > Constants.MarkerInteractionDistance) { return; } if (Game.Player.Money < MethLabs[labIdx].Price) { UI.Notify("You don't have enough money to buy this meth lab."); return; } MethLabs[labIdx].Owner = currentCharacter; MethLabs[labIdx].LastVisit = Util.GetGameDate(); MethLabs[labIdx].Flags = LabFlags.None; MethLabs[labIdx].AddFlag(LabFlags.IsOwned); Game.Player.Money -= MethLabs[InteractableLabIdx].Price; Save(); Util.NotifyWithPicture("LJT", $"{currentCharacter}, good call buying the {MethLabs[labIdx].Location} meth lab. Go inside and check the laptop to get started.", "CHAR_LJT", 1); break; case InteractionType.EnterMethLab: if (PlayerPosition.DistanceTo(MethLabs[labIdx].Position) > Constants.MarkerInteractionDistance) { return; } if (currentCharacter != MethLabs[labIdx].Owner) { UI.Notify($"Only the owner ({MethLabs[labIdx].Owner}) can enter this meth lab."); return; } if (Game.MissionFlag) { UI.Notify("You can't enter meth labs while being in a mission."); return; } if (Game.Player.WantedLevel > 0) { UI.Notify("You can't enter meth labs while being wanted by the police."); return; } PlayerLabModel = Game.Player.Character.Model.Hash; InsideMethLabIdx = labIdx; EnteredMethLab.Invoke(labIdx); Game.Player.Character.Position = Constants.MethLabExit; Game.Player.Character.Heading = Constants.MethLabHeading; Game.Player.Character.Weapons.Select(WeaponHash.Unarmed); break; case InteractionType.ExitMethLab: if (PlayerPosition.DistanceTo(Constants.MethLabExit) > Constants.MarkerInteractionDistance) { return; } Game.Player.Character.Position = MethLabs[labIdx].Position; LeftMethLab.Invoke(labIdx, LabExitReason.Player); InsideMethLabIdx = -1; break; case InteractionType.ManageMethLab: if (PlayerPosition.DistanceTo(Constants.MethLabLaptop) > Constants.MarkerInteractionDistance) { return; } ManagementMenuPool.RefreshIndex(); ManagementMain.Visible = true; break; case InteractionType.Lean: if (IsLeaning || !Game.Player.Character.IsInArea(Constants.LeanAreaMin, Constants.LeanAreaMax)) { return; } Util.RequestAnimDict("anim@amb@yacht@rail@standing@male@variant_01@"); using (TaskSequence tseq = new TaskSequence()) { Function.Call(Hash.TASK_GO_STRAIGHT_TO_COORD, 0, Constants.LeanPos.X, Constants.LeanPos.Y, Constants.LeanPos.Z, 1.0f, -1, Constants.LeanHeading, 0.0f); tseq.AddTask.PlayAnimation("anim@amb@yacht@rail@standing@male@variant_01@", "enter"); tseq.AddTask.PlayAnimation("anim@amb@yacht@rail@standing@male@variant_01@", "base", 8.0f, -1, AnimationFlags.Loop); tseq.Close(); Game.Player.Character.Task.PerformSequence(tseq); } IsLeaning = true; break; case InteractionType.CancelLean: if (!IsLeaning) { return; } Game.Player.Character.Task.PlayAnimation("anim@amb@yacht@rail@standing@male@variant_01@", "exit"); IsLeaning = false; break; } } #endregion }