---==================================================================================================================--- --- --- --- Original Author(s) : NLTP_ASHES --- --- Edited : N/A --- --- Date : 17/04/2023 --- --- License : Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0) --- --- --- --- Script used to manage the tasks of the first act of the addon's storyline. --- --- --- --- Each task is composed of the following elements : --- --- - A act_1_task_X_start(...) function, used to start the task; --- --- - A act_1_task_X_end(...) function, used to end the task; --- --- - A xr_effects.act_1_task_X_init(...) function, called when the task has started; --- --- - A xr_effects.act_1_task_X_complete(...) function, called when the task was successfully completed; --- --- - A xr_effects.act_1_task_X_fail(...) function, called when the task was failed; --- --- - A task_functor.act_1_task_X_title_f(...) function, called periodically to get the name; --- --- - A task_functor.act_1_task_X_descr_f(...) function, called periodically to get the description; --- --- - A task_functor.act_1_task_X_target_f(...) function, called periodically to get the target (for the PDA); --- --- - A task_status_functor.act_1_task_X_status_f(...) function, called periodically to run the core logic. --- --- --- ---==================================================================================================================--- -- --------------------------------------------------------------------------------------------------------------------- -- Constants, global variables and imported functions -- --------------------------------------------------------------------------------------------------------------------- -- Imported functions local dbg_printf = western_goods_utils.dbg_printf local level_object_by_id = western_goods_utils.level_object_by_id local spawn_squad = western_goods_utils.spawn_squad local spawn_dead_squad = western_goods_utils.spawn_dead_squad local spawn_story_squad = western_goods_utils.spawn_story_squad local send_dialog = western_goods_dialogs_manager.send_dialog local heli_spawn = western_goods_helicopter.heli_spawn local heli_register = western_goods_helicopter.heli_register local HELICOPTERS_MODES = western_goods_helicopter.HELICOPTERS_MODES -- Constants local CONST_TASK_2_HARD_DELAY = 1800000 -- milliseconds local CONST_TASK_3_HARD_DELAY = 1800000 -- milliseconds local CONST_TASK_1_HELI_DIST = 625 -- meters squared local CONST_TASK_1_SUPPLIES_DIST = 25 -- meters squared local CONST_TASK_1_PROGRESS_DELAY = 43000 -- milliseconds local CONST_TASK_2_HELI_DELAY = 50000 -- milliseconds local CONST_TASK_2_SHOW_TARGETS_DELAY = 300000 -- milliseconds local CONST_TASK_2_REP_THEFT = -100 -- reputation points local CONST_TASK_3_PROGRESS_DELAY = 38000 -- milliseconds local CONST_TASK_3_SHOW_TARGETS_DELAY = 300000 -- milliseconds local CONST_TASK_3_DIALOG_DIST = 625 -- meters squared local CONST_TASK_3_DIALOG_EX_DIST = 2500 -- meters squared local CONST_TASK_3_BRIDGE_DIST = 10000 -- meters squared local CONST_TASK_3_HELI_DIST = 100 -- meters squared local CONST_TASK_3_NPC_DIST = 25 -- meters squared -- Task variables TASK_1_CACHE = {} TASK_2_CACHE = {} TASK_3_CACHE = {} -- --------------------------------------------------------------------------------------------------------------------- -- ACT 1 - HELICOPTER DELIVERY -- --------------------------------------------------------------------------------------------------------------------- -- TASK 1 - ROAD BUMPS -- --------------------------------------------------------------------------------------------------------------------- --- Function used to start Act 1, Task 1. --- @param first_speaker cse_alife_object --- @param second_speaker cse_alife_object --- @return nil function act_1_task_1_start(first_speaker, second_speaker) local npc = dialogs.who_is_npc(first_speaker, second_speaker) task_manager.get_task_manager():give_task("western_goods_act_1_task_1", npc:id()) dbg_printf("[WG] Tasks Act 1 | Task 1 - Task started...") end --- Function used to end Act 1, Task 1. --- @return nil function act_1_task_1_end() task_manager.get_task_manager():set_task_completed("western_goods_act_1_task_1") dbg_printf("[WG] Tasks Act 1 | Task 1 - Task completed...") end --- Function called when the task is initiated. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_1_init(actor,npc) -- Process info portions western_goods_utils.give_info("western_goods_act_1_task_1_active") western_goods_utils.give_info("western_goods_act_1_task_1_init") end --- Function called when the task is successfully completed. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_1_complete(actor,npc) -- Process info portions western_goods_utils.rem_info("western_goods_act_1_task_1_active") western_goods_utils.give_info("western_goods_act_1_task_1_finished") western_goods_utils.rem_info("western_goods_act_1_task_1_init") -- Process quest items xr_effects.remove_item(actor, npc, {"wg_act_1_task_1_quest_item"}) -- Set up task 2 TASK_2_CACHE.available_time = time_global() + CONST_TASK_2_HARD_DELAY -- Process reward xr_effects.reward_random_money(actor,npc,{"5000","10000"}) xr_effects.reward_stash(actor,npc,{"true"}) xr_effects.complete_task_inc_goodwill(actor,npc,{"75","killer"}) end --- Function called when the task is failed. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_1_fail(actor,npc) -- Process info portions western_goods_utils.rem_info("western_goods_act_1_task_1_active") western_goods_utils.rem_info("western_goods_act_1_task_1_init") -- Process penalty xr_effects.fail_task_dec_goodwill(actor,npc,{"75","killer"}) end --- Function used to retrieve the title of the mission (displayed in the PDA). --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return string function task_functor.act_1_task_1_title_f(task_id,field,p,tsk) if true then return western_goods_utils.get_translation("st_wg_act_1_task_1_title") end end --- Function used to retrieve the description of the mission (displayed in the PDA). --- Warning : naming contract on the translation string : st_wg_trader_act_1_task_1_stage__descr. --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return string function task_functor.act_1_task_1_descr_f(task_id,field,p,tsk) if true then return western_goods_utils.get_translation("st_wg_act_1_task_1_stage_" .. tostring(tsk.stage) .. "_descr") end end --- Function used to retrieve the target of the mission (marker displayed (or not) in the PDA). --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return number function task_functor.act_1_task_1_target_f(task_id,field,p,tsk) if western_goods_utils.has_info("western_goods_act_1_task_1_init") then if tsk.stage == 0 then local heli_se = western_goods_utils.server_object_by_sid("western_goods_helicopter_landed") return heli_se and heli_se.id end if tsk.stage == 1 then local quest_item_se = western_goods_utils.server_object_by_sid("wg_act_1_task_1_quest_item") return quest_item_se and quest_item_se.parent_id == 65535 and quest_item_se.id end if tsk.stage == 2 then local quest_item_se = western_goods_utils.server_object_by_sid("wg_act_1_task_1_quest_item") return quest_item_se and quest_item_se.parent_id == 65535 and quest_item_se.id end if tsk.stage == 3 then return tsk.task_giver_id end end end --- Function used to manage the mission logic as a whole. --- @param tsk CGameTask --- @param task_id number --- @return string function task_status_functor.act_1_task_1_status_f(tsk,task_id) if western_goods_utils.has_info("western_goods_act_1_task_1_init") then -- First stage : Get to the helicopter if tsk.stage == 0 then -- Retrieve the server and game objects (they may not always exist - if they aren't spawned yet or unavailable) local helicopter_se = western_goods_utils.server_object_by_sid("western_goods_helicopter_landed") local helicopter_obj = western_goods_utils.level_object_by_sid("western_goods_helicopter_landed") -- If the heli hasn't been created, then create it if not helicopter_se then create_story_helicopter("zaton") return end -- Continue if the player is closer than 25m from the helicopter if not helicopter_obj or western_goods_utils.get_distance_sqr(helicopter_obj:position(), db.actor:position()) > CONST_TASK_1_HELI_DIST then return end -- Send a dialog between the task giver and the player if not TASK_1_CACHE.stage_0_dialog_sent then local sender_1 = alife():actor() local sender_2 = tsk.task_giver_id and alife_object(tsk.task_giver_id) local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name=sender_2:character_name(), icon=sender_2:character_icon()} send_dialog({ {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_0_message_1")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_0_message_2")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_0_message_3")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_0_message_4")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_0_message_5")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_0_message_6")} }) TASK_1_CACHE.progress_timer = time_global() + CONST_TASK_1_PROGRESS_DELAY TASK_1_CACHE.stage_0_dialog_sent = true end dbg_printf("[WG] Tasks Act 1 | Task 1 - Stage 0 - Player arrived at helicopter...") -- Progress the task if TASK_1_CACHE.progress_timer < time_global() then tsk.stage = 1 return end end -- Second stage : Get to the crew at the sawmill and recover the supplies if tsk.stage == 1 then -- Retrieve the server and game objects (they may not always exist - if they aren't spawned yet or unavailable) local supplies_se = western_goods_utils.server_object_by_sid("wg_act_1_task_1_quest_item") local supplies_obj = western_goods_utils.level_object_by_sid("wg_act_1_task_1_quest_item") -- Spawn the crew of the helicopter dead at the sawmill if not TASK_1_CACHE.stage_1_npcs_spawned then -- Spawn the merc squad, dead, at the sawmill spawn_dead_squad("western_goods_act_1_task_1_heli_crew_squad", "zat_b104_zombied") -- Spawn the zombies that supposedly killed them spawn_dead_squad("western_goods_act_1_task_1_zombie_1_squad", "zat_b104_zombied") spawn_dead_squad("western_goods_act_1_task_1_zombie_2_squad", "zat_b104_zombied") spawn_dead_squad("western_goods_act_1_task_1_zombie_3_squad", "zat_b104_zombied") spawn_dead_squad("western_goods_act_1_task_1_zombie_4_squad", "zat_b104_zombied") -- Give an info portion so the spawning code doesn't run twice TASK_1_CACHE.stage_1_npcs_spawned = true -- Return so the squad has time to spawn in the game world return end -- Spawn the supplies if they don't exist in the world if not supplies_se then -- Spawn the supplies, objective the player has to retrieve supplies_se = alife_create("wg_act_1_task_1_quest_item", vector():set(-317.4,9.8,425.5), 327181, 4137) dbg_printf("[WG] Tasks Act 1 | Task 1 - Stage 1 - Quest item spawned %s", supplies_se.id) return end -- Wait for the player to be close to the supplies if not supplies_obj or western_goods_utils.get_distance_sqr(supplies_obj:position(), db.actor:position()) > CONST_TASK_1_SUPPLIES_DIST then return end -- Send a dialog between the task giver and the player if not TASK_1_CACHE.stage_1_dialog_sent then local sender_1 = alife():actor() local sender_2 = tsk.task_giver_id and alife_object(tsk.task_giver_id) local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name=sender_2:character_name(), icon=sender_2:character_icon()} send_dialog({ {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_1_message_1")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_1_message_2")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_1_message_3")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_1_stage_1_message_4")} }) TASK_1_CACHE.stage_1_dialog_sent = true end dbg_printf("[WG] Tasks Act 1 | Task 1 - Stage 1 - Player arrived at the dead squad...") -- Progress the task tsk.stage = 2 return end -- Third stage : Take the supplies and bring them back to the trader if tsk.stage == 2 then -- Retrieve the server object (they may not exist - if they have been picked up by the player) local supplies_se = western_goods_utils.server_object_by_sid("wg_act_1_task_1_quest_item") -- If the supplies cannot be found (which is odd), roll back to stage 1 if not supplies_se then -- Spawn the supplies, objective the player has to retrieve supplies_se = alife_create("wg_act_1_task_1_quest_item", vector():set(-317.4,9.8,425.5), 327181, 4137) dbg_printf("[WG] Tasks Act 1 | Task 1 - Stage 2 - Quest item respawned %s", supplies_se.id) return end -- If the player picked up the supplies, progress to stage 3 if not (supplies_se and (supplies_se.parent_id ~= AC_ID)) then dbg_printf("[WG] Tasks Act 1 | Task 1 - Stage 2 - Player picked up the supplies %s", supplies_se.id) tsk.stage = 3 return end end -- Fourth stage : Bringing the supplies to the trader. If the supplies are dropped, rollback to the previous stage if tsk.stage == 3 then -- Retrieve the server object (they may exist - if they have been dropped by the player) local supplies_se = western_goods_utils.server_object_by_sid("wg_act_1_task_1_quest_item") -- If the supplies cannot be found (which is odd), roll back to stage 2 if not supplies_se then dbg_printf("[WG] Tasks Act 1 | Task 1 - Stage 3 - Supplies disappeared, rolling back to stage 2...") tsk.stage = 2 return end if not western_goods_utils.has_info("western_goods_act_1_task_1_ready_finished") then dbg_printf("[WG] Tasks Act 1 | Task 1 - Task ready to be completed...") western_goods_utils.give_info("western_goods_act_1_task_1_ready_finished") end -- If the player dropped the supplies, rollback to stage 2 if supplies_se and (supplies_se.parent_id ~= AC_ID) then dbg_printf("[WG] Tasks Act 1 | Task 1 - Stage 3 - Player dropped the supplies %s", supplies_se.id) if western_goods_utils.has_info("western_goods_act_1_task_1_ready_finished") then dbg_printf("[WG] Tasks Act 1 | Task 1 - Task no longer ready to be completed...") western_goods_utils.rem_info("western_goods_act_1_task_1_ready_finished") end tsk.stage = 2 return end end end end -- --------------------------------------------------------------------------------------------------------------------- -- TASK 2 - CONSPIRACY -- --------------------------------------------------------------------------------------------------------------------- --- Function used to start Act 1, Task 2. --- @param first_speaker cse_alife_object --- @param second_speaker cse_alife_object --- @return nil function act_1_task_2_start(first_speaker, second_speaker) local npc = dialogs.who_is_npc(first_speaker, second_speaker) task_manager.get_task_manager():give_task("western_goods_act_1_task_2", npc:id()) dbg_printf("[WG] Tasks Act 1 | Task 2 - Task started...") end --- Function used to end Act 1, Task 2. --- @return nil function act_1_task_2_end() task_manager.get_task_manager():set_task_completed("western_goods_act_1_task_2") dbg_printf("[WG] Tasks Act 1 | Task 2 - Task completed...") end --- Function called when the task is initiated. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_2_init(actor,npc) -- Process info portions western_goods_utils.give_info("western_goods_act_1_task_2_active") western_goods_utils.give_info("western_goods_act_1_task_2_init") end --- Function called when the task is successfully completed. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_2_complete(actor,npc) -- Process info portions western_goods_utils.rem_info("western_goods_act_1_task_2_active") western_goods_utils.rem_info("western_goods_act_1_task_2_init") western_goods_utils.give_info("western_goods_act_1_task_2_finished") -- Process quest items xr_effects.remove_item(actor, npc, {"wg_act_1_task_2_quest_item_1"}) xr_effects.remove_item(actor, npc, {"wg_act_1_task_2_quest_item_2"}) -- Set up task 3 TASK_3_CACHE.available_time = time_global() + CONST_TASK_3_HARD_DELAY -- Process reward xr_effects.reward_random_money(actor,npc,{"10000","20000"}) xr_effects.complete_task_inc_goodwill(actor,npc,{"75","killer"}) end --- Function called when the task is failed. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_2_fail(actor,npc) -- Process info portions western_goods_utils.rem_info("western_goods_act_1_task_2_active") western_goods_utils.rem_info("western_goods_act_1_task_2_init") western_goods_utils.rem_info("western_goods_jupiter_informant_first_meet_over") -- Process penalty xr_effects.fail_task_dec_goodwill(actor,npc,{"50","killer"}) end --- Function used to retrieve the title of the mission (displayed in the PDA). --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return string function task_functor.act_1_task_2_title_f(task_id,field,p,tsk) if true then -- Cond to force my IDE to fold this fucking function correctly return western_goods_utils.get_translation("st_wg_act_1_task_2_title") end end --- Function used to retrieve the description of the mission (displayed in the PDA). --- Warning : naming contract on the translation string : st_wg_trader_act_1_task_2_stage__descr. --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return string function task_functor.act_1_task_2_descr_f(task_id,field,p,tsk) if true then -- Cond to force my IDE to fold this fucking function correctly return western_goods_utils.get_translation("st_wg_act_1_task_2_stage_" .. tostring(tsk.stage) .. "_descr") end end --- Function used to retrieve the target of the mission (marker displayed (or not) in the PDA). --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return number function task_functor.act_1_task_2_target_f(task_id,field,p,tsk) if western_goods_utils.has_info("western_goods_act_1_task_2_init") then if tsk.stage == 0 then if western_goods_mcm.get_config("guided_tasks") then local informant_se = western_goods_utils.server_object_by_sid("stalker_jupiter_informant_squad") return informant_se and informant_se.id end end if tsk.stage == 1 then if western_goods_mcm.get_config("guided_tasks") then local quest_item_1 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_1") local quest_item_2 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_2") return (quest_item_1 and quest_item_1.parent_id == 65535 and quest_item_1.id) or (quest_item_2 and quest_item_2.parent_id == 65535 and quest_item_2.id) end end if tsk.stage == 2 then local timer = TASK_2_CACHE.stage_2_show_targets_timer if timer and timer < time_global() then local squad_1_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_2_bandit_4_squad") local squad_2_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_2_bandit_5_squad") local squad_3_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_2_bandit_6_squad") return (squad_1_se and squad_1_se.id) or (squad_2_se and squad_2_se.id) or (squad_3_se and squad_3_se.id) end end if tsk.stage == 3 then local quest_item_1 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_1") local quest_item_2 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_2") return (quest_item_1 and quest_item_1.parent_id == 65535 and quest_item_1.id) or (quest_item_2 and quest_item_2.parent_id == 65535 and quest_item_2.id) end if tsk.stage == 4 then return tsk.task_giver_id end end end --- Function used to manage the mission logic as a whole. --- @param tsk CGameTask --- @param task_id number --- @return string function task_status_functor.act_1_task_2_status_f(tsk,task_id) if western_goods_utils.has_info("western_goods_act_1_task_2_init") then -- First stage : Find and question the informant at Yanov Station if tsk.stage == 0 then -- Retrieve the server object (they may not always exist - if they aren't spawned yet or unavailable) local informant_squad_se = western_goods_utils.server_object_by_sid("stalker_jupiter_informant_squad") -- Delete the old helicopter from the lake in Zaton if not TASK_2_CACHE.stage_0_zaton_heli_released then release_story_helicopter() TASK_2_CACHE.stage_0_zaton_heli_released = true end -- Spawn a new one at the Water Processing Station if not TASK_2_CACHE.stage_0_wps_heli_created then create_story_helicopter("wps") TASK_2_CACHE.stage_0_wps_heli_created = true end -- Spawn the informant if it doesn't exist if not informant_squad_se then informant_squad_se = spawn_story_squad("stalker_jupiter_informant_squad", vector():set(-55,3.8,211), SIMBOARD.smarts_by_names["jup_a6"]) return end -- When the player is done talking with the informant if not western_goods_utils.has_info("western_goods_jupiter_informant_first_meet_over") then return end -- Send a dialog between the task giver and the player if not TASK_2_CACHE.stage_0_dialog_sent then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 0 - Player met informant...") local sender_1 = alife():actor() local sender_2 = tsk.task_giver_id and alife_object(tsk.task_giver_id) local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name=sender_2:character_name(), icon=sender_2:character_icon()} send_dialog({ {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_0_message_1")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_0_message_2")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_0_message_3")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_0_message_4")} }) TASK_2_CACHE.stage_0_dialog_sent = true end tsk.stage = 1 return end -- Second stage : Go to the container warehouse and find clues as to what happened to the helicopter if tsk.stage == 1 then -- Retrieve the server object (they may not always exist - if they aren't spawned yet) local helicopter_se = TASK_2_CACHE.stage_1_helicopter_id and alife_object(TASK_2_CACHE.stage_1_helicopter_id) -- Retrieve the server objects (they may not always exist - if they aren't spawned yet) local quest_item_1_se = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_1") local quest_item_2_se = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_2") -- Populate the bandit camp if not TASK_2_CACHE.stage_1_bandits_spawned then local se_squad_1 = spawn_squad("western_goods_act_1_task_2_bandit_1_squad", vector():set(-424.8,0,-339.4), 12910, 4469) local se_squad_2 = spawn_squad("western_goods_act_1_task_2_bandit_2_squad", vector():set(-394.9,0,-386.9), 52206, 4470) local se_squad_3 = spawn_squad("western_goods_act_1_task_2_bandit_3_squad", vector():set(-405,0,-344), 36889, 4469) se_squad_1.scripted_target = "jup_a12" se_squad_2.scripted_target = "jup_a12" se_squad_3.scripted_target = "jup_a12" TASK_2_CACHE.stage_1_bandits_spawned = true return end -- Delete the old helicopter from the Water Processing Station in Zaton if not TASK_2_CACHE.stage_1_wps_heli_released then release_story_helicopter() TASK_2_CACHE.stage_1_wps_heli_released = true end -- Spawn the helicopter and make it go towards Yanov station, then make it head to the container warehouse if not TASK_2_CACHE.stage_1_helicopter_spawned then helicopter_se = heli_spawn("western_goods_helicopter",vector():set(346.7,7,984.4),674394,4724) TASK_2_CACHE.stage_1_heli_ready_timer = time_global() + CONST_TASK_2_HELI_DELAY TASK_2_CACHE.stage_1_helicopter_id = helicopter_se.id TASK_2_CACHE.stage_1_helicopter_spawned = true return end -- Spawn the Gauss rifle if it hasn't been spawned yet if not quest_item_1_se then quest_item_1_se = alife_create("wg_act_1_task_2_quest_item_1",vector():set(-445,0.8,-356.8),1056,4818) dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Quest item no 1 spawned %s", quest_item_1_se.id) return end -- Spawn the note if it hasn't been spawned yet if not quest_item_2_se then quest_item_2_se = alife_create("wg_act_1_task_2_quest_item_2",vector():set(-446.9,1.2,-384.3),756,4818) dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Quest item no 2 spawned %s", quest_item_2_se.id) return end -- Send a message and set the helicopter to move to the player after 60 seconds local timer = TASK_2_CACHE.stage_1_heli_ready_timer if not timer or timer >= time_global() then return end -- Send the helicopter to protect the player, and send a dialog to the player if not TASK_2_CACHE.stage_1_helicopter_sent then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Helicopter moving to player...") heli_register(TASK_2_CACHE.stage_1_helicopter_id,HELICOPTERS_MODES.PROTECT_ACTOR,nil) local attack_key_str = western_goods_utils.get_key_translation(western_goods_mcm.get_config("heli_attack")) -- Send a dialog to the player to inform him the helicopter is coming local dialog_sender = {name="Mercenary helicopter", icon="ui_inGame2_PD_DownToEarth"} send_dialog({ {sender=dialog_sender.name, icon=dialog_sender.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_1_message_1",attack_key_str)} }) TASK_2_CACHE.stage_1_helicopter_sent = true end -- If the player picked one of the items, isn't wearing a disguise, and hasn't been punished yet (punish the player only once, not every refresh...) if not TASK_2_CACHE.stage_1_target_1_robbed and not (quest_item_1_se and quest_item_1_se.parent_id == 65535) then local nearest_npc, nearest_npc_dist = utils_obj.get_nearest_stalker(db.actor) -- Punish the player if he's not wearing a disguise, and a bandit is close to him if nearest_npc_dist and nearest_npc:character_community() == "bandit" and nearest_npc_dist < 10 and not gameplay_disguise.is_actor_disguised() then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Nearest %s %s is %s m away", nearest_npc:character_community(), nearest_npc:section(), nearest_npc_dist) -- Degrade player reputation game_relations.change_faction_relations("bandit", get_actor_true_community(), CONST_TASK_2_REP_THEFT) dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Player punished for stealing %s", CONST_TASK_2_REP_THEFT) -- Make the npc send a message to the player local dialog_sender = { name= nearest_npc:character_name(), icon= nearest_npc:character_icon()} send_dialog({ {sender=dialog_sender.name, icon=dialog_sender.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_1_message_3")} },true) end -- Save that the item has been robbed (so that the player doesn't get punished if he gets exposed way later) TASK_2_CACHE.stage_1_target_1_robbed = true end -- If the player picked one of the items, isn't wearing a disguise, and hasn't been punished yet (punish the player only once, not every refresh...) if not TASK_2_CACHE.stage_1_target_2_robbed and not (quest_item_2_se and quest_item_2_se.parent_id == 65535) then local nearest_npc, nearest_npc_dist = utils_obj.get_nearest_stalker(db.actor) -- Punish the player if he's not wearing a disguise, and a bandit is close to him if nearest_npc_dist and nearest_npc:character_community() == "bandit" and nearest_npc_dist < 10 and not gameplay_disguise.is_actor_disguised() then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Nearest %s %s is %s m away", nearest_npc:character_community(), nearest_npc:section(), nearest_npc_dist) -- Degrade player reputation game_relations.change_faction_relations("bandit", get_actor_true_community(), CONST_TASK_2_REP_THEFT) dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Player punished for stealing %s", CONST_TASK_2_REP_THEFT) -- Make the npc send a message to the player local dialog_sender = { name= nearest_npc:character_name(), icon= nearest_npc:character_icon()} send_dialog({ {sender=dialog_sender.name, icon=dialog_sender.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_1_message_4")} },true) end -- Save that the item has been robbed (so that the player doesn't get punished if he gets exposed way later) TASK_2_CACHE.stage_1_target_2_robbed = true end -- If the player picked up both quest items, progress the task if not (quest_item_1_se and quest_item_1_se.parent_id == 65535) and not (quest_item_2_se and quest_item_2_se.parent_id == 65535) then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 1 - Player picked up the items - %s - %s", quest_item_1_se.id, quest_item_2_se.id) -- If the player is hostile to bandits, progress to stage 2, otherwise, progress to stage 3 if game_relations.is_factions_enemies(get_actor_true_community(), "bandit") and not gameplay_disguise.is_actor_disguised() then -- Spawn the bandit reinforcements around the Container Warehouse area if not TASK_2_CACHE.stage_2_bandit_squads_spawned then local squad_1_se = spawn_squad("western_goods_act_1_task_2_bandit_4_squad", vector():set(-424.8,0,-339.4), 12910, 4469) local squad_2_se = spawn_squad("western_goods_act_1_task_2_bandit_5_squad", vector():set(-394.9,0,-386.9), 52206, 4470) local squad_3_se = spawn_squad("western_goods_act_1_task_2_bandit_6_squad", vector():set(-405,0,-344), 36889, 4469) squad_1_se.scripted_target = "jup_a12" squad_2_se.scripted_target = "jup_a12" squad_3_se.scripted_target = "jup_a12" -- Save the time the fight was started at, to indicate the targets after 2 in-game hours TASK_2_CACHE.stage_2_show_targets_timer = time_global() + CONST_TASK_2_SHOW_TARGETS_DELAY TASK_2_CACHE.stage_2_bandit_squads_spawned = true -- Alert the player about the incoming bandits local dialog_sender = {name="Mercenary helicopter", icon="ui_inGame2_PD_DownToEarth"} send_dialog({ {sender=dialog_sender.name, icon=dialog_sender.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_2_message_1")} }) return end tsk.stage = 2 return else -- Return the helicopter to the processing station heli_register(TASK_2_CACHE.stage_1_helicopter_id,HELICOPTERS_MODES.LEAVE_AT_POINT,vector():set(346.7,7,984.4)) -- Spawn a new one at the Water Processing Station create_story_helicopter("wps") -- Notify the player that the heli is leaving local dialog_sender = {name="Mercenary helicopter", icon="ui_inGame2_PD_DownToEarth"} send_dialog({ {sender=dialog_sender.name, icon=dialog_sender.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_1_message_2")} }) tsk.stage = 3 return end end end -- Third stage : Face off the bandits reinforcements if tsk.stage == 2 then -- Retrieve the server objects (they may not always exist - if they aren't spawned yet or unavailable) local squad_1_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_2_bandit_4_squad") local squad_2_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_2_bandit_5_squad") local squad_3_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_2_bandit_6_squad") -- If all of the squads are dead, or the player is wearing a disguise if (not squad_1_se and not squad_2_se and not squad_3_se) or gameplay_disguise.is_actor_disguised() then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 2 - Bandit squads cleared...") -- Retrieve the game object (may not exist if the helicopter has been destroyed) local helicopter_se = TASK_2_CACHE.stage_1_helicopter_id and alife_object(TASK_2_CACHE.stage_1_helicopter_id) local helicopter_obj = helicopter_se and level_object_by_id(helicopter_se.id) if helicopter_obj then -- Return the helicopter to the processing station heli_register(helicopter_obj:id(),HELICOPTERS_MODES.LEAVE_AT_POINT,vector():set(346.7,7,984.4)) dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 2 - Helicopter moving out to WPS...") -- Inform the player that the helicopter is leaving local dialog_sender = {name="Mercenary helicopter", icon="ui_inGame2_PD_DownToEarth"} send_dialog({ {sender=dialog_sender.name, icon=dialog_sender.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_2_stage_2_message_2")} }) end -- And progress the task tsk.stage = 3 return end end -- Fourth stage : Bring back the quest items if tsk.stage == 3 then -- Retrieve the server objects local quest_item_1 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_1") local quest_item_2 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_2") -- Spawn the Gauss rifle if it disappeared if not quest_item_1 then quest_item_1 = alife_create("wg_act_1_task_2_quest_item_1",vector():set(-445,0.8,-356.8),1056,4818) dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 3 - Quest item no 1 respawned %s", quest_item_1.id) return end -- Spawn the note if it disappeared if not quest_item_2 then quest_item_2 = alife_create("wg_act_1_task_2_quest_item_2",vector():set(-446.9,1.2,-384.3),756,4818) dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 3 - Quest item no 2 respawned %s", quest_item_2.id) return end -- If the player picked up both quest items, progress to stage 4 if not (quest_item_1 and quest_item_1.parent_id ~= AC_ID) and not (quest_item_2 and quest_item_2.parent_id ~= AC_ID) then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 3 - Player picked up the items - %s - %s", quest_item_1.id, quest_item_2.id) tsk.stage = 4 return end end -- Fifth stage : If one of the quest items are dropped, roll back to fourth stage if tsk.stage == 4 then -- Retrieve the server objects local quest_item_1 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_1") local quest_item_2 = western_goods_utils.server_object_by_sid("wg_act_1_task_2_quest_item_2") if not western_goods_utils.has_info("western_goods_act_1_task_2_ready_finished") then dbg_printf("[WG] Tasks Act 1 | Task 2 - Task ready to be completed...") western_goods_utils.give_info("western_goods_act_1_task_2_ready_finished") end -- If the player dropped one of the quest items, rollback to stage 3 if (not quest_item_1 or quest_item_1 and quest_item_1.parent_id ~= AC_ID) or (not quest_item_2 or quest_item_2 and quest_item_2.parent_id ~= AC_ID) then dbg_printf("[WG] Tasks Act 1 | Task 2 - Stage 4 - Player dropped the items - %s - %s", quest_item_1.id, quest_item_2.id) if western_goods_utils.has_info("western_goods_act_1_task_2_ready_finished") then dbg_printf("[WG] Tasks Act 1 | Task 2 - Task no longer ready to be completed...") western_goods_utils.rem_info("western_goods_act_1_task_2_ready_finished") end tsk.stage = 3 return end end end end -- --------------------------------------------------------------------------------------------------------------------- -- TASK 3 - THE RESCUE -- --------------------------------------------------------------------------------------------------------------------- --- Function used to start Act 1, Task 3. --- @param first_speaker cse_alife_object --- @param second_speaker cse_alife_object --- @return nil function act_1_task_3_start(first_speaker, second_speaker) local npc = dialogs.who_is_npc(first_speaker, second_speaker) task_manager.get_task_manager():give_task("western_goods_act_1_task_3", npc:id()) dbg_printf("[WG] Tasks Act 1 | Task 3 - Task started...") end --- Function used to end Act 1, Task 3. --- @return nil function act_1_task_3_end() task_manager.get_task_manager():set_task_completed("western_goods_act_1_task_3") dbg_printf("[WG] Tasks Act 1 | Task 3 - Task completed...") end --- Function called when the task is initiated. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_3_init(actor,npc) -- Process info portions western_goods_utils.give_info("western_goods_act_1_task_3_active") western_goods_utils.give_info("western_goods_act_1_task_3_init") end --- Function called when the task is successfully completed. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_3_complete(actor,npc) -- Process info portions western_goods_utils.rem_info("western_goods_act_1_task_3_active") western_goods_utils.rem_info("western_goods_act_1_task_3_init") western_goods_utils.give_info("western_goods_act_1_task_3_finished") western_goods_utils.give_info("western_goods_act_1_finished") -- Process reward xr_effects.reward_random_money(actor,npc,{"10000","15000"}) xr_effects.complete_task_inc_goodwill(actor,npc,{"100","killer"}) end --- Function called when the task is failed. --- @param actor cse_alife_object --- @param npc cse_alife_object --- @return nil function xr_effects.act_1_task_3_fail(actor,npc) -- Process info portions western_goods_utils.rem_info("western_goods_act_1_task_3_active") western_goods_utils.rem_info("western_goods_act_1_task_3_init") western_goods_utils.rem_info("western_goods_crew_member_rescue_over") -- Process penalty xr_effects.fail_task_dec_goodwill(actor,npc,{"35","killer"}) end --- Function used to retrieve the title of the mission (displayed in the PDA). --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return string function task_functor.act_1_task_3_title_f(task_id,field,p,tsk) if true then -- Cond to force my IDE to fold this fucking function correctly return western_goods_utils.get_translation("st_wg_act_1_task_3_title") end end --- Function used to retrieve the description of the mission (displayed in the PDA). --- Warning : naming contract on the translation string : st_wg_trader_act_1_task_3_stage__descr. --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return string function task_functor.act_1_task_3_descr_f(task_id,field,p,tsk) if true then -- Cond to force my IDE to fold this fucking function correctly return western_goods_utils.get_translation("st_wg_act_1_task_3_stage_" .. tostring(tsk.stage) .. "_descr") end end --- Function used to retrieve the target of the mission (marker displayed (or not) in the PDA). --- @param task_id number --- @param field string --- @param p any --- @param tsk CGameTask --- @return number function task_functor.act_1_task_3_target_f(task_id,field,p,tsk) if western_goods_utils.has_info("western_goods_act_1_task_3_init") then if tsk.stage == 0 then local crew_member_se = western_goods_utils.server_object_by_sid("stalker_crew_member") return crew_member_se and crew_member_se.id end if tsk.stage == 1 then local smart = SIMBOARD:get_smart_by_name("red_smart_terrain_bridge") return smart and smart.id end if tsk.stage == 2 then -- Wait 5 real life minutes before starting to indicate where the remaining enemies are local timer = TASK_3_CACHE.stage_2_show_targets_timer if timer and timer <= time_global() then local squad_1_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_3_mono_bridge_1_squad") local squad_2_se = western_goods_utils.server_object_by_sid("western_goods_act_1_task_3_mono_bridge_2_squad") return (squad_1_se and squad_1_se.id) or (squad_2_se and squad_2_se.id) end end if tsk.stage == 3 then local smart = SIMBOARD:get_smart_by_name("red_smart_terrain_bridge") return smart and smart.id end if tsk.stage == 4 then return tsk.task_giver_id end end end --- Function used to manage the mission logic as a whole. --- @param tsk CGameTask --- @param task_id number --- @return string function task_status_functor.act_1_task_3_status_f(tsk,task_id) if western_goods_utils.has_info("western_goods_act_1_task_3_init") then -- First stage : Find and rescue the crew member if tsk.stage == 0 then -- Retrieve the server and game objects (they may not always exist - if they aren't spawned yet or unavailable) local crew_member_se = western_goods_utils.server_object_by_sid("stalker_crew_member") local crew_member_obj = crew_member_se and level_object_by_id(crew_member_se.id) -- Retrieve the server and game objects (they may not always exist - if they aren't spawned yet or unavailable) local crew_member_squad_se = western_goods_utils.server_object_by_sid("stalker_crew_member_squad") -- Spawn the crew member squad if not crew_member_squad_se then crew_member_squad_se = spawn_story_squad("stalker_crew_member_squad", vector():set(35.3,1,42.9), SIMBOARD.smarts_by_names["lim_smart_terrain_6"]) return end -- Spawn monolith squads to guard the crew member if not TASK_3_CACHE.stage_0_mono_guard_spawned then local se_squad_1 = spawn_squad("western_goods_act_1_task_3_mono_guards_1_squad", vector():set(17.2,1,47.3), 35710, 2475) local se_squad_2 = spawn_squad("western_goods_act_1_task_3_mono_guards_2_squad", vector():set(42,-3,50.4), 48878, 2475) se_squad_1.scripted_target = "lim_smart_terrain_6" se_squad_2.scripted_target = "lim_smart_terrain_6" TASK_3_CACHE.stage_0_mono_guard_spawned = true return end -- When the player has rescued the crew member, progress further if not western_goods_utils.has_info("western_goods_crew_member_rescue_over") then return end if crew_member_obj and not TASK_3_CACHE.stage_0_crew_member_companion then dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 0 - Player rescued crew member...") -- Add the crew member to the player squad dialogs_axr_companion.become_actor_companion(db.actor,crew_member_obj) TASK_3_CACHE.stage_0_crew_member_companion = true end -- Send a dialog between the player and the task giver if not TASK_3_CACHE.stage_0_dialog_sent then local sender_1 = alife():actor() local sender_2 = alife_object(tsk.task_giver_id) local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name=sender_2:character_name(), icon=sender_2:character_icon()} send_dialog({ {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_0_message_1")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_0_message_2")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_0_message_3")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_0_message_4")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_0_message_5")} }) TASK_3_CACHE.progress_timer = time_global() + CONST_TASK_3_PROGRESS_DELAY TASK_3_CACHE.stage_0_dialog_sent = true end -- Progress the task if TASK_3_CACHE.progress_timer < time_global() then tsk.stage = 1 return end end -- Second stage : Get to the bridge in the Red Forest if tsk.stage == 1 then -- Retrieve the server and game objects local crew_member_squad_se = western_goods_utils.server_object_by_sid("stalker_crew_member_squad") -- Respawn the crew member squad if not crew_member_squad_se then crew_member_squad_se = spawn_story_squad("stalker_crew_member_squad", vector():set(35.3,1,42.9), SIMBOARD.smarts_by_names["lim_smart_terrain_6"]) return end -- Spawn the enemy squads at the bridge in the Red Forest, if they haven't already, or if they all died if not TASK_3_CACHE.stage_1_mono_bridge_spawned then -- Spawn the squads local monolith_se_squad_1 = spawn_squad("western_goods_act_1_task_3_mono_bridge_1_squad", vector():set(-114,-0.6,-214.3), 8509, 2792) local monolith_se_squad_2 = spawn_squad("western_goods_act_1_task_3_mono_bridge_2_squad", vector():set(-111.5,-0.6,-210.6), 8905, 2792) monolith_se_squad_1.scripted_target = "red_smart_terrain_bridge" monolith_se_squad_2.scripted_target = "red_smart_terrain_bridge" TASK_3_CACHE.stage_1_mono_bridge_spawned = true return end -- Wait for the player to be in Limansk if level.name() == "l10_limansk" then local player_pos = db.actor:position() -- Positions of the smart terrains the player needs to reach to get a lore dump local dialog_1_activation_pos = SIMBOARD:get_smart_by_name("lim_smart_terrain_5").position local dialog_2_activation_pos = SIMBOARD:get_smart_by_name("lim_smart_terrain_3").position local dialog_3_activation_pos = SIMBOARD:get_smart_by_name("lim_smart_terrain_1").position -- Distances between the player and the smart terrains local dist_to_dialog_1 = dialog_1_activation_pos and western_goods_utils.get_distance_sqr(player_pos, dialog_1_activation_pos) local dist_to_dialog_2 = dialog_2_activation_pos and western_goods_utils.get_distance_sqr(player_pos, dialog_2_activation_pos) local dist_to_dialog_3 = dialog_3_activation_pos and western_goods_utils.get_distance_sqr(player_pos, dialog_3_activation_pos) -- Conditions for dialogs local dialog_1_cond = dist_to_dialog_1 < CONST_TASK_3_DIALOG_DIST and not TASK_3_CACHE.stage_1_dialog_1_sent local dialog_2_cond = dist_to_dialog_2 < CONST_TASK_3_DIALOG_DIST and not TASK_3_CACHE.stage_1_dialog_2_sent and TASK_3_CACHE.stage_1_dialog_1_sent local dialog_3_cond = dist_to_dialog_3 < CONST_TASK_3_DIALOG_EX_DIST and not TASK_3_CACHE.stage_1_dialog_3_sent and TASK_3_CACHE.stage_1_dialog_2_sent if dialog_1_cond then dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 1 - Player reached dialog point 1...") local sender_1 = alife():actor() local sender_2 = western_goods_utils.server_object_by_sid("stalker_crew_member") local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name=sender_2:character_name(), icon=sender_2:character_icon()} send_dialog({ {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_1")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_2")} }) TASK_3_CACHE.stage_1_dialog_1_sent = true end if dialog_2_cond then dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 1 - Player reached dialog point 2...") local sender_1 = alife():actor() local sender_2 = western_goods_utils.server_object_by_sid("stalker_crew_member") local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name=sender_2:character_name(), icon=sender_2:character_icon()} send_dialog({ {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_3")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_4")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_5")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_6")} }) TASK_3_CACHE.stage_1_dialog_2_sent = true end if dialog_3_cond then dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 1 - Player reached dialog point 3...") local sender_1 = alife():actor() local sender_2 = western_goods_utils.server_object_by_sid("stalker_crew_member") local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name=sender_2:character_name(), icon=sender_2:character_icon()} send_dialog({ {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_7")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_8")}, {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_9")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_1_message_10")} }) TASK_3_CACHE.stage_1_dialog_3_sent = true end end -- Wait for the player to be in the Red Forest if level.name() == "l10_red_forest" then -- Retrieve the player and target positions local player_pos = db.actor:position() local objective_pos = SIMBOARD:get_smart_by_name("red_smart_terrain_bridge").position -- Wait for the player to be closer than 100m from the bridge if not objective_pos or western_goods_utils.get_distance_sqr(player_pos, objective_pos) > CONST_TASK_3_BRIDGE_DIST then return end dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 1 - Player reached Read Forest's bridge to Limansk...") -- Save the time to indicate the remaining enemies on the PDA 5 real-life mins later TASK_3_CACHE.stage_2_show_targets_timer = time_global() + CONST_TASK_3_SHOW_TARGETS_DELAY -- Progress the task tsk.stage = 2 return end end -- Third stage : Fight off the enemy squads if tsk.stage == 2 then -- Retrieve the server objects (they may not always exist - if they aren't spawned yet or unavailable) local monolith_se_squad_1 = western_goods_utils.server_object_by_sid("western_goods_act_1_task_3_mono_bridge_1_squad") local monolith_se_squad_2 = western_goods_utils.server_object_by_sid("western_goods_act_1_task_3_mono_bridge_2_squad") -- Retrieve the server objects local crew_member_squad_se = western_goods_utils.server_object_by_sid("stalker_crew_member_squad") -- Respawn the crew member squad if not crew_member_squad_se then crew_member_squad_se = spawn_story_squad("stalker_crew_member_squad", vector():set(35.3,1,42.9), SIMBOARD.smarts_by_names["lim_smart_terrain_6"]) return end -- Progress only when all enemy squads are dead if monolith_se_squad_1 or monolith_se_squad_2 then return end dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 2 - All Monolith squads dead...") -- Progress the task tsk.stage = 3 return end -- Fourth stage : Wait for the helicopter to pickup the rescued crew member if tsk.stage == 3 then -- Retrieve the server object of the rescue helicopter local helicopter_se = TASK_3_CACHE.stage_3_helicopter_id and alife_object(TASK_3_CACHE.stage_3_helicopter_id) local helicopter_obj = helicopter_se and level_object_by_id(helicopter_se.id) -- Retrieve the server and game object of the crew member local crew_member_se = western_goods_utils.server_object_by_sid("stalker_crew_member") local crew_member_obj = crew_member_se and level_object_by_id(crew_member_se.id) -- Retrieve the server and game object of the crew member's squad local crew_member_squad_se = western_goods_utils.server_object_by_sid("stalker_crew_member_squad") -- Define the helicopter spawn and landing positions local heli_spawn_pos = vector():set(348.8,10.9,149.2) local heli_landing_pos = vector():set(-188.7,5.3,-195.8) -- Delete the old helicopter from the Water Processing Station in Zaton if not TASK_3_CACHE.stage_3_wps_heli_released then release_story_helicopter() TASK_2_CACHE.stage_3_wps_heli_released = true end -- Spawn the helicopter and direct it to the landing zone if not TASK_3_CACHE.stage_3_helicopter_spawned then helicopter_se = heli_spawn("western_goods_helicopter",heli_spawn_pos,8256,2792) dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 3 - Helicopter spawned %s", helicopter_se.id) heli_register(helicopter_se.id,HELICOPTERS_MODES.LAND_AT_POINT, heli_landing_pos) dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 3 - Helicopter moving to player...") TASK_3_CACHE.stage_3_helicopter_id = helicopter_se.id TASK_3_CACHE.stage_3_helicopter_spawned = true return end -- If the evac helicopter was destroyed, fail the task if helicopter_obj and helicopter_obj:get_helicopter():GetfHealth() <= 0 then dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 3 - Helicopter was destroyed - task failed") return "fail" end -- If the crew member hasn't extracted, and isn't alive, respawn him if not crew_member_squad_se and not western_goods_utils.has_info("western_goods_act_1_task_3_crew_member_extracted") then crew_member_squad_se = spawn_story_squad("stalker_crew_member_squad", vector():set(35.3,1,42.9), SIMBOARD.smarts_by_names["lim_smart_terrain_6"]) return end -- Send a dialog to the player to inform him the helicopter is coming if not TASK_3_CACHE.stage_3_dialog_sent then local sender_1 = alife():actor() local dialog_sender_1 = { name=sender_1:character_name(), icon=sender_1:character_icon()} local dialog_sender_2 = { name="Mercenary helicopter", icon="ui_inGame2_PD_DownToEarth"} send_dialog({ {sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_3_message_1")}, {sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_1_task_3_stage_3_message_2")} }) TASK_3_CACHE.stage_3_dialog_sent = true end -- Get the distance between the helicopter and the landing zone, and wait for it to be smaller than 5m local dist_to_landing = helicopter_obj and western_goods_utils.get_distance_sqr(helicopter_obj:position(), heli_landing_pos) if (not dist_to_landing) or dist_to_landing and dist_to_landing > CONST_TASK_3_HELI_DIST then return end -- Set the rescued companion to head towards the helicopter if not TASK_3_CACHE.stage_3_evac_order_given then dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 3 - Helicopter reached landing zone (dist:%s)", dist_to_landing) -- Remove companion from player squad axr_companions.remove_from_actor_squad(crew_member_obj) -- Force the npc logic back in, because dialogs_axr_companion fails to restore it for some reason xr_logic.set_new_scheme_and_logic(crew_member_obj,"beh","beh@get_to_heli","logic",nil,"scripts\\western_goods_crew_member.ltx") crew_member_se.scripted_target = "red_smart_terrain_bridge" dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 3 - Crew member freed and moving to helicopter...") TASK_3_CACHE.stage_3_evac_order_given = true end -- Get the distance to the heli, and wait for it to be smaller than 5m local dist_to_heli = crew_member_obj and western_goods_utils.get_distance_sqr(crew_member_obj:position(), heli_landing_pos) if (not dist_to_heli) or dist_to_heli and dist_to_heli > CONST_TASK_3_NPC_DIST then return end -- Extract the squad member if not TASK_3_CACHE.stage_3_crew_member_extracted then -- Release the squad member (as in he got in the helicopter) alife_release(crew_member_se) -- Give the info that the crew member was successfully extracted western_goods_utils.give_info("western_goods_act_1_task_3_crew_member_extracted") dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 3 - Crew member extracted...") -- Make the heli leave the level heli_register(helicopter_se.id,HELICOPTERS_MODES.LEAVE_AT_POINT,heli_spawn_pos) -- Spawn a new one at the Water Processing Station create_story_helicopter("wps") dbg_printf("[WG] Tasks Act 1 | Task 3 - Stage 3 - Helicopter leaving to Book Store...") TASK_3_CACHE.stage_3_crew_member_extracted = true end -- Progress the task tsk.stage = 4 return end -- Fifth stage : Return for the reward if tsk.stage == 4 then local crew_member_squad_se = western_goods_utils.server_object_by_sid("stalker_crew_member_squad") if not western_goods_utils.has_info("western_goods_act_1_task_3_ready_finished") then dbg_printf("[WG] Tasks Act 1 | Task 3 - Task ready to be completed...") western_goods_utils.give_info("western_goods_act_1_task_3_ready_finished") end -- Spawn the rescued crew member in the book store if not crew_member_squad_se then crew_member_squad_se = spawn_squad("stalker_crew_member_squad", vector():set(-182.1,0.6,-343.9), 33349, 5019) crew_member_squad_se.scripted_target = "pri_a18_smart_terrain" return end end end end -- --------------------------------------------------------------------------------------------------------------------- -- Callbacks registration -- --------------------------------------------------------------------------------------------------------------------- --- Function used to register callbacks. --- @return nil function on_game_start() RegisterScriptCallback("save_state", save_state) RegisterScriptCallback("load_state", load_state) RegisterScriptCallback("actor_on_first_update", task_2_setup) RegisterScriptCallback("actor_on_first_update", task_3_setup) end -- --------------------------------------------------------------------------------------------------------------------- -- Data persistence -- --------------------------------------------------------------------------------------------------------------------- --- Function used to store information in the save file. --- @param m_data table --- @return nil function save_state(m_data) -- Prepare save tables local TASK_1_SAVE = {} local TASK_2_SAVE = {} local TASK_3_SAVE = {} -- Make copies of task caches copy_table(TASK_1_SAVE, TASK_1_CACHE) copy_table(TASK_2_SAVE, TASK_2_CACHE) copy_table(TASK_3_SAVE, TASK_3_CACHE) -- Pre-process tables TASK_1_SAVE.progress_timer = (TASK_1_SAVE.progress_timer or 0) - time_global() TASK_2_SAVE.available_time = (TASK_2_SAVE.available_time or 0) - time_global() TASK_3_SAVE.available_time = (TASK_3_SAVE.available_time or 0) - time_global() TASK_3_SAVE.progress_timer = (TASK_3_SAVE.progress_timer or 0) - time_global() TASK_2_SAVE.stage_1_heli_ready_timer = (TASK_2_SAVE.stage_1_heli_ready_timer or 0) - time_global() TASK_2_SAVE.stage_2_show_targets_timer = (TASK_2_SAVE.stage_2_show_targets_timer or 0) - time_global() TASK_3_SAVE.stage_2_show_targets_timer = (TASK_3_SAVE.stage_2_show_targets_timer or 0) - time_global() -- Save tables m_data.wg_act_1_task_1_cache = TASK_1_SAVE m_data.wg_act_1_task_2_cache = TASK_2_SAVE m_data.wg_act_1_task_3_cache = TASK_3_SAVE -- Debug prints dbg_printf("[WG] Tasks Act 1 | Task 1 - Saved variables...\n%s",utils_data.print_table(TASK_1_SAVE, false, true)) dbg_printf("[WG] Tasks Act 1 | Task 2 - Saved variables...\n%s",utils_data.print_table(TASK_2_SAVE, false, true)) dbg_printf("[WG] Tasks Act 1 | Task 3 - Saved variables...\n%s",utils_data.print_table(TASK_3_SAVE, false, true)) end --- Function used to load information stored in the save file. --- @param m_data table --- @return nil function load_state(m_data) -- Retrieve save tables local TASK_1_SAVE = m_data.wg_act_1_task_1_cache or {} local TASK_2_SAVE = m_data.wg_act_1_task_2_cache or {} local TASK_3_SAVE = m_data.wg_act_1_task_3_cache or {} -- Post-process tables TASK_1_SAVE.progress_timer = (TASK_1_SAVE.progress_timer or 0) + time_global() TASK_2_SAVE.available_time = (TASK_2_SAVE.available_time or 0) + time_global() TASK_3_SAVE.available_time = (TASK_3_SAVE.available_time or 0) + time_global() TASK_3_SAVE.progress_timer = (TASK_3_SAVE.progress_timer or 0) + time_global() TASK_2_SAVE.stage_1_heli_ready_timer = (TASK_2_SAVE.stage_1_heli_ready_timer or 0) + time_global() TASK_2_SAVE.stage_2_show_targets_timer = (TASK_2_SAVE.stage_2_show_targets_timer or 0) + time_global() TASK_3_SAVE.stage_2_show_targets_timer = (TASK_3_SAVE.stage_2_show_targets_timer or 0) + time_global() -- Restore task caches copy_table(TASK_1_CACHE, TASK_1_SAVE) copy_table(TASK_2_CACHE, TASK_2_SAVE) copy_table(TASK_3_CACHE, TASK_3_SAVE) -- Debug prints dbg_printf("[WG] Tasks Act 1 | Task 1 - Loaded variables...\n%s",utils_data.print_table(TASK_1_CACHE, false, true)) dbg_printf("[WG] Tasks Act 1 | Task 2 - Loaded variables...\n%s",utils_data.print_table(TASK_2_CACHE, false, true)) dbg_printf("[WG] Tasks Act 1 | Task 3 - Loaded variables...\n%s",utils_data.print_table(TASK_3_CACHE, false, true)) end -- --------------------------------------------------------------------------------------------------------------------- -- General functions -- --------------------------------------------------------------------------------------------------------------------- --- Function used to setup the automatic start of Act 2, Task 2. --- @return nil function task_2_setup() -- Conditions local task_1_done = western_goods_utils.has_info("western_goods_act_1_task_1_finished") local task_2_started = western_goods_utils.has_info("western_goods_act_1_task_2_active") local task_2_done = western_goods_utils.has_info("western_goods_act_1_task_2_finished") local timeout_ready = time_global() > (TASK_2_CACHE.available_time or 0) -- If the task is available if not task_1_done or task_2_started or task_2_done then return end -- If the task should be set up if timeout_ready then dbg_printf("[WG] Tasks Act 1 | Task 2 - Task set up...") western_goods_utils.give_info("western_goods_act_1_task_2_available") else dbg_printf("[WG] Tasks Act 1 | Task 2 - What's missing? timeout_ready:%s (%s/%s)", timeout_ready, time_global(), TASK_2_CACHE.available_time) end end function task_3_setup() -- Conditions local task_2_done = western_goods_utils.has_info("western_goods_act_1_task_2_finished") local task_3_started = western_goods_utils.has_info("western_goods_act_1_task_3_active") local task_3_done = western_goods_utils.has_info("western_goods_act_1_task_3_finished") local timeout_ready = time_global() > (TASK_3_CACHE.available_time or 0) -- If the task is available if not task_2_done or task_3_started or task_3_done then return end -- If the task should be set up if timeout_ready then dbg_printf("[WG] Tasks Act 1 | Task 3 - Task set up...") western_goods_utils.give_info("western_goods_act_1_task_3_available") else dbg_printf("[WG] Tasks Act 1 | Task 3 - What's missing? timeout_ready:%s (%s/%s)", timeout_ready, time_global(), TASK_3_CACHE.available_time) end end --- Function used to give the player an item at the start of Act 1, Task 1. --- Warning : This function should be called while a dialog is running. --- @param first_speaker cse_alife_object --- @param second_speaker cse_alife_object --- @return nil function task_1_give_item(first_speaker, second_speaker) dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, "wg_gps") end --- Function used to spawn a static helicopter at the Waste Processing Station if it doesn't exist. --- @param location string --- @return boolean function create_story_helicopter(location) local const_sec = "western_goods_helicopter_landed" if not western_goods_utils.server_object_by_sid(const_sec) then local pos, lvid, gvid if location == "zaton" then pos = vector():set(-4.5,-7,536.8) lvid = 676572 gvid = 4330 elseif location == "wps" then pos = vector():set(284.1,28.1,-364) lvid = 1598393 gvid = 4454 else printf("![WG] ERROR | Tasks Act 1 | Invalid spawn location for %s : loc:%s", const_sec, location) return false end local heli_se = alife_create(const_sec,pos,lvid,gvid) if heli_se then dbg_printf("[WG] Tasks Act 1 | Created %s(%s) at loc:%s x:%s,y:%s,z:%s lvid:%s gvid:%s", const_sec, heli_se.id, location, pos.x, pos.y, pos.z, lvid, gvid) return true else printf("![WG] ERROR | Tasks Act 1 | Failed to create %s at loc:%s x:%s,y:%s,z:%s lvid:%s gvid:%s", const_sec, location, pos.x, pos.y, pos.z, lvid, gvid) return false end end return false end --- Function used to release the helicopter at the Waste Processing Station if it exists. --- @return nil function release_story_helicopter() local wps_heli_se = western_goods_utils.server_object_by_sid("western_goods_helicopter_landed") if wps_heli_se then alife_release(wps_heli_se) dbg_printf("[WG] Tasks Act 1 | Released western_goods_helicopter_landed(%s)", wps_heli_se.id) return true end return false end --- Function used to give the player a reward for finishing act 1. --- Warning : This function should be called while a dialog is running. --- @param first_speaker cse_alife_object --- @param second_speaker cse_alife_object --- @return nil function give_final_reward(first_speaker, second_speaker) dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, "af_compass_af_aam") end