1325 lines
65 KiB
Plaintext
1325 lines
65 KiB
Plaintext
---==================================================================================================================---
|
|
--- ---
|
|
--- 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 second act of the addon's storyline. ---
|
|
--- ---
|
|
--- Each task is composed of the following elements : ---
|
|
--- - A act_2_task_X_start(...) function, used to start the task; ---
|
|
--- - A act_2_task_X_end(...) function, used to end the task; ---
|
|
--- - A xr_effects.act_2_task_X_init(...) function, called when the task has started; ---
|
|
--- - A xr_effects.act_2_task_X_complete(...) function, called when the task was successfully completed; ---
|
|
--- - A xr_effects.act_2_task_X_fail(...) function, called when the task was failed; ---
|
|
--- - A task_functor.act_2_task_X_title_f(...) function, called periodically to get the name; ---
|
|
--- - A task_functor.act_2_task_X_descr_f(...) function, called periodically to get the description; ---
|
|
--- - A task_functor.act_2_task_X_target_f(...) function, called periodically to get the target (for the PDA); ---
|
|
--- - A task_status_functor.act_2_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 send_dialog = western_goods_dialogs_manager.send_dialog
|
|
|
|
-- Constants
|
|
local CONST_SPAWN_THROTTLE = 5000 -- milliseconds
|
|
local CONST_TASK_2_HARD_DELAY = 1800000 -- milliseconds
|
|
local CONST_TASK_2_SOFT_DELAY_MIN = 600 -- seconds
|
|
local CONST_TASK_2_SOFT_DELAY_MAX = 1800 -- seconds
|
|
local CONST_TASK_2_ECOLOG_TELEPORT_DELAY = 50000 -- milliseconds
|
|
local CONST_TASK_2_STAGE_6_PROGRESS_DELAY = 30000 -- milliseconds
|
|
local CONST_TASK_2_STAGE_8_PROGRESS_DELAY = 60000 -- milliseconds
|
|
local CONST_TASK_2_STAGE_9_PROGRESS_DELAY = 40000 -- milliseconds
|
|
local CONST_TASK_2_BANDIT_AUTOKILL_DELAY = 40000 -- milliseconds
|
|
local CONST_TASK_2_CLEAR_SMART_DIST = 2500 -- meters squared
|
|
local CONST_TASK_2_ZOMBIE_1_DIST = 15625 -- meters squared
|
|
local CONST_TASK_2_SCHOOL_CLOSE = 400 -- meters squared
|
|
local CONST_TASK_2_SCHOOL_FAR = 4900 -- meters squared
|
|
|
|
-- Task variables
|
|
TASK_1_CACHE = {}
|
|
TASK_2_CACHE = {}
|
|
|
|
-- ---------------------------------------------------------------------------------------------------------------------
|
|
-- ACT 2 - CONTRACT WORK
|
|
-- ---------------------------------------------------------------------------------------------------------------------
|
|
-- TASK 1 - KOLOBOK
|
|
-- ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Function used to start Act 2, Task 1.
|
|
--- @param first_speaker cse_alife_object
|
|
--- @param second_speaker cse_alife_object
|
|
--- @return nil
|
|
function act_2_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_2_task_1", npc:id())
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Task started...")
|
|
end
|
|
|
|
--- Function used to end Act 2, Task 1.
|
|
--- @return nil
|
|
function act_2_task_1_end()
|
|
local kolobok_found = false
|
|
|
|
-- Items in player inventory that have a section among the ones in fallback_items
|
|
local secondary_items_found = {}
|
|
|
|
-- Iterate player inventory to find if he has kolobok, and gather fallback items in the process
|
|
western_goods_utils.inventory_iter(db.actor,function(owner, obj)
|
|
local is_main_item = obj:section() == TASK_1_CACHE.main_item
|
|
local is_secondary_item = western_goods_utils.table_contains(TASK_1_CACHE.secondary_items, obj:section())
|
|
if is_main_item then
|
|
kolobok_found = true
|
|
return true
|
|
elseif is_secondary_item then
|
|
table.insert(secondary_items_found, obj)
|
|
end
|
|
end)
|
|
|
|
-- If the player doesn't have a Kolobok, use one of the fallback items
|
|
if not kolobok_found then
|
|
for _,obj in pairs(secondary_items_found) do
|
|
western_goods_utils.open_container(obj,false)
|
|
break
|
|
end
|
|
end
|
|
|
|
task_manager.get_task_manager():set_task_completed("western_goods_act_2_task_1")
|
|
|
|
TASK_2_CACHE.available_time = time_global() + CONST_TASK_2_HARD_DELAY
|
|
dbg_printf("[WG] Tasks Act 2 | 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_2_task_1_init(actor,npc)
|
|
-- Prepare task cache table
|
|
TASK_1_CACHE.main_item = "af_fuzz_kolobok"
|
|
TASK_1_CACHE.secondary_items = {
|
|
"af_fuzz_kolobok_lead_box",
|
|
"af_fuzz_kolobok_af_aac",
|
|
"af_fuzz_kolobok_af_aam",
|
|
"af_fuzz_kolobok_af_iam"
|
|
}
|
|
|
|
-- Spawn task target if it doesn't exist in the world
|
|
local main_item_exists = false
|
|
|
|
western_goods_utils.server_objects_iter(function(se_obj)
|
|
if se_obj:section_name() == TASK_1_CACHE.main_item then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Main target already exist in the world %s", se_obj.id)
|
|
main_item_exists = true
|
|
return true
|
|
end
|
|
end)
|
|
|
|
if not main_item_exists then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Main target does not exist in the world...")
|
|
|
|
local viable_spawn_anomalies = task_1_get_static_chemical_anomalies() or {}
|
|
local spawn_anomaly_id = random_key_table(viable_spawn_anomalies)
|
|
local spawn_anomaly = spawn_anomaly_id and alife_object(spawn_anomaly_id)
|
|
|
|
if spawn_anomaly then
|
|
alife_create(TASK_1_CACHE.main_item, spawn_anomaly.position, spawn_anomaly.m_level_vertex_id, spawn_anomaly.m_game_vertex_id)
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Spawned main target at pos:%s lvid:%s gvid:%s", spawn_anomaly.position, spawn_anomaly.m_level_vertex_id, spawn_anomaly.m_game_vertex_id)
|
|
end
|
|
end
|
|
|
|
-- Process info portions
|
|
western_goods_utils.give_info("western_goods_act_2_task_1_active")
|
|
western_goods_utils.give_info("western_goods_act_2_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_2_task_1_complete(actor,npc)
|
|
-- Process info portions
|
|
western_goods_utils.rem_info("western_goods_act_2_task_1_active")
|
|
western_goods_utils.rem_info("western_goods_act_2_task_1_init")
|
|
western_goods_utils.give_info("western_goods_act_2_task_1_finished")
|
|
|
|
-- Process quest items
|
|
xr_effects.remove_item(actor, npc, {"af_fuzz_kolobok"})
|
|
|
|
-- Process reward
|
|
xr_effects.reward_random_money(actor,npc,{"10000","15000"})
|
|
xr_effects.complete_task_inc_goodwill(actor,npc,{"25","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_2_task_1_fail(actor,npc)
|
|
-- Process info portions
|
|
western_goods_utils.rem_info("western_goods_act_2_task_1_active")
|
|
western_goods_utils.rem_info("western_goods_act_2_task_1_init")
|
|
|
|
-- 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_2_task_1_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_2_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_2_task_1_stage_<stage>_descr.
|
|
--- @param task_id number
|
|
--- @param field string
|
|
--- @param p any
|
|
--- @param tsk CGameTask
|
|
--- @return string
|
|
function task_functor.act_2_task_1_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_2_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_2_task_1_target_f(task_id,field,p,tsk)
|
|
if western_goods_utils.has_info("western_goods_act_2_task_1_init") then
|
|
if tsk.stage == 0 then
|
|
return nil
|
|
end
|
|
if tsk.stage == 1 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_2_task_1_status_f(tsk,task_id)
|
|
if western_goods_utils.has_info("western_goods_act_2_task_1_init") then
|
|
-- First stage : Find the artefact
|
|
if tsk.stage == 0 then
|
|
western_goods_utils.inventory_iter(db.actor,function(owner, obj)
|
|
local is_main_item = obj:section() == TASK_1_CACHE.main_item
|
|
local is_secondary_item = western_goods_utils.table_contains(TASK_1_CACHE.secondary_items, obj:section())
|
|
if is_main_item or is_secondary_item then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Stage 0 - Player found primary (%s) or secondary item (%s)",is_main_item,is_secondary_item)
|
|
tsk.stage = 1
|
|
return true
|
|
end
|
|
end)
|
|
end
|
|
|
|
-- Second stage : Deliver the artefact
|
|
if tsk.stage == 1 then
|
|
local has_item = false
|
|
|
|
western_goods_utils.inventory_iter(db.actor,function(owner, obj)
|
|
local is_main_item = obj:section() == TASK_1_CACHE.main_item
|
|
local is_secondary_item = western_goods_utils.table_contains(TASK_1_CACHE.secondary_items, obj:section())
|
|
if is_main_item or is_secondary_item then
|
|
has_item = true
|
|
return true
|
|
end
|
|
end)
|
|
|
|
if not has_item then
|
|
if western_goods_utils.has_info("western_goods_act_2_task_1_ready_finished") then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Stage 1 - Task no longer ready to be completed...")
|
|
western_goods_utils.rem_info("western_goods_act_2_task_1_ready_finished")
|
|
end
|
|
tsk.stage = 0
|
|
return
|
|
end
|
|
|
|
if not western_goods_utils.has_info("western_goods_act_2_task_1_ready_finished") then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Stage 1 - Task ready to be completed...")
|
|
western_goods_utils.give_info("western_goods_act_2_task_1_ready_finished")
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------------------------------------------------
|
|
-- TASK 2 - RETRIEVAL MISSION
|
|
-- ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Function used to start Act 2, Task 2.
|
|
--- @param task_giver cse_alife_object
|
|
--- @return nil
|
|
function act_2_task_2_start(task_giver)
|
|
task_manager.get_task_manager():give_task("western_goods_act_2_task_2", task_giver.id)
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Task started...")
|
|
end
|
|
|
|
--- Function used to end Act 2, Task 2.
|
|
--- @return nil
|
|
function act_2_task_2_end()
|
|
task_manager.get_task_manager():set_task_completed("western_goods_act_2_task_2")
|
|
dbg_printf("[WG] Tasks Act 2 | 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_2_task_2_init(actor,npc)
|
|
TASK_2_CACHE = {
|
|
main_item = "wg_act_2_task_2_quest_item",
|
|
marked_enemies = { },
|
|
objects = {
|
|
btr = { sec="veh_btr", x=-32.9, y=-0.5, z=20.9, lvid=155155, gvid=4971 },
|
|
sleeping_bag = { sec="itm_sleepbag", x=26.6, y=-4.3, z=129.2, lvid=232806, gvid=4970 }
|
|
},
|
|
squads = {
|
|
army_spawn_data = { sec="western_goods_act_2_task_2_army_squad", smart="pri_sim_3" },
|
|
mono_spawn_data = { sec="western_goods_act_2_task_2_mono_squad", smart="pri_sim_3" },
|
|
snork_spawn_data = { sec="western_goods_act_2_task_2_snork_squad", smart="pri_b301" },
|
|
ecolog_spawn_data = { sec="western_goods_act_2_task_2_ecolog_squad", smart="pri_a28_school", smart2="pri_b303" },
|
|
zombie_1_spawn_data = { sec="western_goods_act_2_task_2_zombie_1_squad", smart="pri_sim_3" },
|
|
zombie_2_spawn_data = { sec="western_goods_act_2_task_2_zombie_2_squad", smart="pri_sim_3" },
|
|
bandit_1_spawn_data = { sec="western_goods_act_2_task_2_bandit_1_squad", smart="pri_b301" },
|
|
bandit_2_spawn_data = { sec="western_goods_act_2_task_2_bandit_2_squad", smart="pri_a28_school" },
|
|
controller_spawn_data = { sec="western_goods_act_2_task_2_controller_squad", smart="pri_b303" },
|
|
lynn_spawn_data = { sec="stalker_dunn_lynn_squad", smart="ds2_lager_st" },
|
|
lynn_guards_spawn_data = { sec="western_goods_act_2_task_2_lynn_guards_squad", smart="ds2_lager_st" }
|
|
},
|
|
restrictors = {
|
|
zombie = { ax=-97.150344848633, ay=-1.1752129793167, az=-45.473430633545, bx=-81.533813476563, by=5.2640190124512, bz=-64.902114868164 },
|
|
snork = { ax=17.24550819397, ay=-4.823212146759, az=129.98883056641, bx=29.521947860718, by=-1.0844190120697, bz=121.89762878418 },
|
|
school = { ax=2.7305309772491, ay=-4.823212146759, az=180.73071289063, bx=76.082359313965, by=17.772342681885, bz=112.70443725586 },
|
|
overlook = { ax=27.744569778442, ay=7.1062412261963, az=129.99130249023, bx=53.035232543945, by=16.793748855591, bz=121.89153289795 },
|
|
kbo = { ax=3.7310662269592, ay=4.2264876365662, az=272.10140991211, bx=14.69687461853, by=8.0234889984131, bz=265.22302246094 }
|
|
}
|
|
}
|
|
|
|
-- Process info portions
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_active")
|
|
western_goods_utils.give_info("western_goods_act_2_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_2_task_2_complete(actor,npc)
|
|
-- Process info portions
|
|
western_goods_utils.rem_info("western_goods_act_2_task_2_active")
|
|
western_goods_utils.rem_info("western_goods_act_2_task_2_init")
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_finished")
|
|
western_goods_utils.give_info("western_goods_act_2_finished")
|
|
|
|
-- Clean up
|
|
task_2_clean_squads()
|
|
|
|
-- Process quest items
|
|
xr_effects.remove_item(actor, npc, {"wg_act_2_task_2_quest_item"})
|
|
|
|
-- Process reward
|
|
xr_effects.reward_random_money(actor,npc,{"15000","20000"})
|
|
xr_effects.complete_task_inc_goodwill(actor,npc,{"100","isg"})
|
|
xr_effects.complete_task_inc_goodwill(actor,npc,{"25","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_2_task_2_fail(actor,npc)
|
|
-- Process info portions
|
|
western_goods_utils.rem_info("western_goods_act_2_task_2_active")
|
|
western_goods_utils.rem_info("western_goods_act_2_task_2_init")
|
|
|
|
-- Process penalty
|
|
xr_effects.fail_task_dec_goodwill(actor,npc,{"40","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_2_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_2_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_2_task_2_stage_<stage>_descr.
|
|
--- @param task_id number
|
|
--- @param field string
|
|
--- @param p any
|
|
--- @param tsk CGameTask
|
|
--- @return string
|
|
function task_functor.act_2_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_2_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_2_task_2_target_f(task_id,field,p,tsk)
|
|
if western_goods_utils.has_info("western_goods_act_2_task_2_init") then
|
|
if tsk.stage == 0 then
|
|
local smart = SIMBOARD:get_smart_by_name("pri_sim_3")
|
|
return smart and smart.id
|
|
end
|
|
if tsk.stage == 1 then
|
|
local zombie_1_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.zombie_1_spawn_data.sec)
|
|
return zombie_1_squad_se and zombie_1_squad_se.id
|
|
end
|
|
if tsk.stage == 2 then
|
|
local zombie_2_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.zombie_2_spawn_data.sec)
|
|
return zombie_2_squad_se and zombie_2_squad_se.id
|
|
end
|
|
if tsk.stage == 3 then
|
|
-- Put a red marker over all the pursuers (only in pripyat, to avoid cheating)
|
|
if level.name() == "pripyat" then
|
|
task_2_mark_current_enemies(TASK_2_CACHE.marked_enemies)
|
|
end
|
|
|
|
-- Return nil as to not place an actual task marker
|
|
return nil
|
|
end
|
|
if tsk.stage == 4 then
|
|
-- Remove left-over markers (just in case)
|
|
if level.name() == "pripyat" then
|
|
task_2_mark_current_enemies(TASK_2_CACHE.marked_enemies)
|
|
end
|
|
|
|
local restrictor = db.zone_by_name["pri_surge_hide_b301"]
|
|
return restrictor and restrictor:id()
|
|
end
|
|
if tsk.stage == 5 then
|
|
local snork_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.snork_spawn_data.sec)
|
|
local restrictor = db.zone_by_name["pri_surge_hide_b301"]
|
|
return (snork_squad_se and snork_squad_se.id) or (restrictor and restrictor:id())
|
|
end
|
|
if tsk.stage == 6 then
|
|
local restrictor = db.zone_by_name["pri_surge_hide_b301"]
|
|
return restrictor and restrictor:id()
|
|
end
|
|
if tsk.stage == 7 then
|
|
local smart = SIMBOARD:get_smart_by_name("pri_b301")
|
|
return smart and smart.id
|
|
end
|
|
if tsk.stage == 8 then
|
|
local smart = SIMBOARD:get_smart_by_name("pri_b301")
|
|
return smart and smart.id
|
|
end
|
|
if tsk.stage == 9 then
|
|
local smart = SIMBOARD:get_smart_by_name("pri_b301")
|
|
return smart and smart.id
|
|
end
|
|
if tsk.stage == 10 then
|
|
local restrictor = db.zone_by_name["pri_surge_hide_b301"]
|
|
return restrictor and restrictor:id()
|
|
end
|
|
if tsk.stage == 11 then
|
|
local smart = SIMBOARD:get_smart_by_name("pri_b303")
|
|
return smart and smart.id
|
|
end
|
|
if tsk.stage == 12 then
|
|
local supplies_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.main_item)
|
|
return supplies_se and supplies_se.id
|
|
end
|
|
if tsk.stage == 13 then
|
|
local lynn_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.lynn_spawn_data.sec)
|
|
return lynn_squad_se and lynn_squad_se.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_2_task_2_status_f(tsk,task_id)
|
|
if western_goods_utils.has_info("western_goods_act_2_task_2_init") then
|
|
|
|
-- Throughout the whole task : clear the two smarts so nothing interfere with the task
|
|
task_2_clear_smart_terrain("pri_a28_school")
|
|
task_2_clear_smart_terrain("pri_b301")
|
|
task_2_clear_smart_terrain("pri_b303")
|
|
|
|
-- First stage : Get to the Outskirts, somewhere close to the zombies
|
|
if tsk.stage == 0 then
|
|
local zombie_1_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.zombie_1_spawn_data.sec)
|
|
|
|
-- Spawn Zombie squad
|
|
if not TASK_2_CACHE.zombie_1_spawned and not zombie_1_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.zombie_1_spawn_data
|
|
zombie_1_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if zombie_1_squad_se then
|
|
TASK_2_CACHE.zombie_1_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
if level.name() ~= "pripyat" then return end
|
|
|
|
local dist_to_zombies = zombie_1_squad_se and western_goods_utils.get_distance_sqr(alife():actor().position,zombie_1_squad_se.position)
|
|
if (not dist_to_zombies) or dist_to_zombies and dist_to_zombies > CONST_TASK_2_ZOMBIE_1_DIST then return end
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 0 - Player close to Zombied squad %s", dist_to_zombies)
|
|
|
|
tsk.stage = 1
|
|
end
|
|
|
|
-- Second stage : Kill the zombies and get close
|
|
if tsk.stage == 1 then
|
|
local zombie_1_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.zombie_1_spawn_data.sec)
|
|
|
|
-- If the zombie squad is dead, and the player is near them
|
|
if not zombie_1_squad_se and western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.zombie) then
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 1 - First Zombied squad is dead...")
|
|
|
|
local zombie_2_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.zombie_2_spawn_data.sec)
|
|
|
|
-- Spawn Zombie squad for next stage
|
|
if not TASK_2_CACHE.zombie_2_spawned and not zombie_2_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.zombie_2_spawn_data
|
|
zombie_2_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if zombie_2_squad_se then
|
|
TASK_2_CACHE.spawn_throttle = time_global() + CONST_SPAWN_THROTTLE
|
|
TASK_2_CACHE.zombie_2_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
tsk.stage = 2
|
|
end
|
|
end
|
|
|
|
-- Third stage : Wait for zombies to die or take part in the fight
|
|
if tsk.stage == 2 then
|
|
local zombie_2_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.zombie_2_spawn_data.sec)
|
|
local army_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.army_spawn_data.sec)
|
|
|
|
-- Spawn Army squad
|
|
if TASK_2_CACHE.spawn_throttle < time_global() and not TASK_2_CACHE.army_squad_spawned and not army_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.army_spawn_data
|
|
army_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if army_squad_se then
|
|
TASK_2_CACHE.spawn_throttle = time_global() + CONST_SPAWN_THROTTLE
|
|
TASK_2_CACHE.army_squad_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
-- Spawn Army BTR
|
|
if TASK_2_CACHE.spawn_throttle < time_global() and not TASK_2_CACHE.army_btr_spawned then
|
|
local spawn_data = TASK_2_CACHE.objects.btr
|
|
local btr_se = alife_create(spawn_data.sec, vector():set(spawn_data.x, spawn_data.y, spawn_data.z), spawn_data.lvid, spawn_data.gvid)
|
|
|
|
if btr_se then
|
|
btr_se.angle = vector():set(0,-1.5708,0)
|
|
|
|
logic_enforcer.assign(btr_se.id,'scripts\\tasks\\veh_idle.ltx','logic','ph_car@idle')
|
|
|
|
TASK_2_CACHE.spawn_throttle = time_global() + CONST_SPAWN_THROTTLE
|
|
TASK_2_CACHE.army_btr_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s x:%s y:%s z:%s lvid:%s gvid:%s",spawn_data.sec, spawn_data.x, spawn_data.y, spawn_data.z, spawn_data.lvid, spawn_data.gvid)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
-- When zombies are dead, progress task
|
|
if TASK_2_CACHE.zombie_2_spawned and not zombie_2_squad_se then
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 2 - Second Zombied squad is dead...")
|
|
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_2_message_1")}
|
|
})
|
|
|
|
if western_goods_utils.is_player_fighting() then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 2 - Player is fighting :\n%s", utils_data.print_table(xr_combat_ignore.fighting_with_actor_npcs, false, true))
|
|
tsk.stage = 3
|
|
else
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 2 - Player is not fighting...")
|
|
tsk.stage = 4
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Fourth stage : Get to the basement of the school but kill pursuers
|
|
if tsk.stage == 3 then
|
|
if western_goods_utils.is_player_fighting() then
|
|
local restrictor = db.zone_by_name["pri_surge_hide_b301"]
|
|
local dist_to_basement = restrictor and western_goods_utils.get_distance_sqr(alife():actor().position,restrictor:position())
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 3 - Player is fighting :\n%s", utils_data.print_table(xr_combat_ignore.fighting_with_actor_npcs, false, true))
|
|
|
|
if dist_to_basement and dist_to_basement <= CONST_TASK_2_SCHOOL_FAR and dist_to_basement >= CONST_TASK_2_SCHOOL_CLOSE then
|
|
if not TASK_2_CACHE.message_school_pursuers_far_sent then
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_message_school_pursuers_far")}
|
|
},true)
|
|
TASK_2_CACHE.message_school_pursuers_far_sent = true
|
|
end
|
|
return
|
|
elseif dist_to_basement and dist_to_basement < CONST_TASK_2_SCHOOL_CLOSE then
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_message_school_pursuers_close")}
|
|
},true)
|
|
return "fail"
|
|
else
|
|
TASK_2_CACHE.message_school_pursuers_far_sent = false
|
|
return
|
|
end
|
|
else
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 3 - Player is not fighting...")
|
|
TASK_2_CACHE.message_school_pursuers_far_sent = false
|
|
tsk.stage = 4
|
|
end
|
|
end
|
|
|
|
-- Fifth stage : Get to the basement of the school without being seen
|
|
if tsk.stage == 4 then
|
|
local restrictor = db.zone_by_name["pri_surge_hide_b301"]
|
|
|
|
if not western_goods_utils.is_player_fighting() then
|
|
local dist_to_basement = restrictor and western_goods_utils.get_distance_sqr(alife():actor().position,restrictor:position())
|
|
if dist_to_basement and dist_to_basement < CONST_TASK_2_SCHOOL_CLOSE then
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 4 - Player arrived at the school dist(sqr):%s",dist_to_basement)
|
|
|
|
local snork_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.snork_spawn_data.sec)
|
|
|
|
-- Spawn snork squad
|
|
if not TASK_2_CACHE.snork_spawned and not snork_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.snork_spawn_data
|
|
snork_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if snork_squad_se then
|
|
TASK_2_CACHE.snork_spawned = true
|
|
tsk.stage = 5
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
end
|
|
else
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 4 - Player is fighting :\n%s", utils_data.print_table(xr_combat_ignore.fighting_with_actor_npcs, false, true))
|
|
tsk.stage = 3
|
|
end
|
|
end
|
|
|
|
-- Sixth stage : Kill the snorks
|
|
if tsk.stage == 5 then
|
|
local snork_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.snork_spawn_data.sec)
|
|
|
|
-- Dialog when player reaches school
|
|
if not TASK_2_CACHE.stage_5_dialog_sent then
|
|
|
|
local dialog_sender_1 = { name=alife():actor():character_name(), icon=alife():actor():character_icon()}
|
|
local dialog_sender_2 = { name="Anonymous", icon="ui_inGame2_no_data"}
|
|
|
|
send_dialog({
|
|
{sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_5_message_1")},
|
|
{sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_5_message_2")}
|
|
})
|
|
|
|
TASK_2_CACHE.stage_5_dialog_sent = true
|
|
end
|
|
|
|
-- Spawn sleeping bag
|
|
if not TASK_2_CACHE.sleeping_bag_spawned then
|
|
local spawn_data = TASK_2_CACHE.objects.sleeping_bag
|
|
local sleep_bag_se = alife_create(spawn_data.sec, vector():set(spawn_data.x, spawn_data.y, spawn_data.z), spawn_data.lvid, spawn_data.gvid)
|
|
|
|
if sleep_bag_se then
|
|
TASK_2_CACHE.sleeping_bag_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s x:%s y:%s z:%s lvid:%s gvid:%s",spawn_data.sec, spawn_data.x, spawn_data.y, spawn_data.z, spawn_data.lvid, spawn_data.gvid)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
-- Fail task if player gets out of school
|
|
if not western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.school) then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 5 - Player left restrictor bounds...")
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_message_left_position")}
|
|
},true)
|
|
return "fail"
|
|
end
|
|
|
|
-- If the zombie squad is dead, and the player is near them
|
|
if TASK_2_CACHE.snork_spawned and not snork_squad_se and western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.snork) then
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 5 - Snork squad is dead...")
|
|
|
|
local bandit_1_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.bandit_1_spawn_data.sec)
|
|
|
|
-- Spawn bandit squad for next stage
|
|
if not TASK_2_CACHE.bandit_1_spawned and not bandit_1_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.bandit_1_spawn_data
|
|
bandit_1_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if bandit_1_squad_se then
|
|
TASK_2_CACHE.bandit_1_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
tsk.stage = 6
|
|
end
|
|
end
|
|
|
|
-- Seventh stage : Kill the bandits
|
|
if tsk.stage == 6 then
|
|
local bandit_1_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.bandit_1_spawn_data.sec)
|
|
|
|
-- Fail task if player gets out of school
|
|
if not western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.school) then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 6 - Player left restrictor bounds...")
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_message_left_position")}
|
|
},true)
|
|
return "fail"
|
|
end
|
|
|
|
-- If bandits are dead, or if they are not enemy with the player
|
|
if TASK_2_CACHE.bandit_1_spawned and not bandit_1_squad_se then
|
|
|
|
if not TASK_2_CACHE.stage_6_dialog_sent then
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 6 - First bandit squad is dead...")
|
|
|
|
local dialog_sender_1 = { name="Anonymous", icon="ui_inGame2_no_data"}
|
|
local dialog_sender_2 = { name=alife():actor():character_name(), icon=alife():actor():character_icon()}
|
|
|
|
send_dialog({
|
|
{sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_6_message_1")},
|
|
{sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_6_message_2")},
|
|
{sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_6_message_3")},
|
|
{sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_6_message_4")}
|
|
})
|
|
|
|
TASK_2_CACHE.progress_timer = time_global() + CONST_TASK_2_STAGE_6_PROGRESS_DELAY
|
|
TASK_2_CACHE.stage_6_dialog_sent = true
|
|
end
|
|
|
|
if TASK_2_CACHE.progress_timer < time_global() then
|
|
tsk.stage = 7
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Eighth stage : Get to the 3rd floor of the school
|
|
if tsk.stage == 7 then
|
|
-- When the player gets in position, progress task
|
|
if western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.overlook) then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 7 - Player reached third floor of school...")
|
|
tsk.stage = 8
|
|
return
|
|
end
|
|
end
|
|
|
|
-- Ninth stage : Wait for ecologs to arrive
|
|
if tsk.stage == 8 then
|
|
local ecolog_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.ecolog_spawn_data.sec)
|
|
|
|
-- Spawn Ecolog squad
|
|
if not TASK_2_CACHE.ecolog_spawned and not ecolog_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.ecolog_spawn_data
|
|
ecolog_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if ecolog_squad_se then
|
|
TASK_2_CACHE.progress_timer = time_global() + CONST_TASK_2_STAGE_8_PROGRESS_DELAY
|
|
TASK_2_CACHE.ecolog_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
-- If player leaves his position, fail task
|
|
if not western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.overlook) then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 8 - Player left restrictor bounds...")
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_message_left_position")}
|
|
},true)
|
|
return "fail"
|
|
end
|
|
|
|
-- After 45s, progress task
|
|
if TASK_2_CACHE.progress_timer < time_global() then
|
|
tsk.stage = 9
|
|
end
|
|
end
|
|
|
|
-- Tenth stage : Wait for the bandits to die
|
|
if tsk.stage == 9 then
|
|
local bandit_1_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.bandit_1_spawn_data.sec)
|
|
local bandit_2_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.bandit_2_spawn_data.sec)
|
|
|
|
-- Spawn Bandit squad
|
|
if not TASK_2_CACHE.bandit_2_squad_spawned and not bandit_2_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.bandit_2_spawn_data
|
|
bandit_2_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if bandit_2_squad_se then
|
|
|
|
-- Dialog when bandit spawn
|
|
if not TASK_2_CACHE.stage_9_dialog_sent then
|
|
|
|
local dialog_sender = { name="Anonymous", icon="ui_inGame2_no_data"}
|
|
|
|
send_dialog({
|
|
{sender=dialog_sender.name, icon=dialog_sender.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_9_message")}
|
|
})
|
|
|
|
TASK_2_CACHE.stage_9_dialog_sent = true
|
|
end
|
|
|
|
TASK_2_CACHE.bandit_2_autokill_timer = time_global() + CONST_TASK_2_BANDIT_AUTOKILL_DELAY
|
|
TASK_2_CACHE.bandit_2_squad_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
-- If player leaves his position, fail task
|
|
if not western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.overlook) then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 9 - Player left restrictor bounds...")
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_message_left_position")}
|
|
},true)
|
|
return "fail"
|
|
end
|
|
|
|
-- After 20s, start killing the bandits (both bandit_1 and bandit_2 squads) automatically
|
|
if not TASK_2_CACHE.bandit_2_autokilled and TASK_2_CACHE.bandit_2_autokill_timer < time_global() then
|
|
if bandit_1_squad_se then
|
|
for npc in bandit_1_squad_se:squad_members() do
|
|
local npc_obj = db.storage[npc.id] and db.storage[npc.id].object
|
|
if (npc_obj and npc_obj:alive()) then
|
|
western_goods_utils.next_tick(surge_manager.make_dead,npc_obj:id())
|
|
end
|
|
end
|
|
end
|
|
if bandit_2_squad_se then
|
|
for npc in bandit_2_squad_se:squad_members() do
|
|
local npc_obj = db.storage[npc.id] and db.storage[npc.id].object
|
|
if (npc_obj and npc_obj:alive()) then
|
|
western_goods_utils.next_tick(surge_manager.make_dead,npc_obj:id())
|
|
end
|
|
end
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 9 - Bandit squads auto-killed...")
|
|
end
|
|
TASK_2_CACHE.progress_timer = time_global() + CONST_TASK_2_STAGE_9_PROGRESS_DELAY
|
|
TASK_2_CACHE.bandit_2_autokilled = true
|
|
end
|
|
|
|
-- When all bandits are dead, progress task
|
|
if not bandit_1_squad_se and not bandit_2_squad_se and TASK_2_CACHE.progress_timer < time_global() then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 9 - Both bandit squads are dead...")
|
|
tsk.stage = 10
|
|
end
|
|
end
|
|
|
|
-- Eleventh stage : Take cover from the emission
|
|
if tsk.stage == 10 then
|
|
local ecolog_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.ecolog_spawn_data.sec)
|
|
|
|
-- Start emission and make ecologs flee
|
|
if not TASK_2_CACHE.surge_started then
|
|
surge_manager.start_surge()
|
|
|
|
-- Give info to link script with logic scheme
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_ecolog_flee")
|
|
TASK_2_CACHE.ecolog_teleport_timer = time_global() + CONST_TASK_2_ECOLOG_TELEPORT_DELAY
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 10 - Emission started...")
|
|
|
|
TASK_2_CACHE.surge_started = true
|
|
end
|
|
|
|
-- Teleport ecolog squad because stalker and pathfinding definitely don't make one...
|
|
if TASK_2_CACHE.ecolog_teleport_timer < time_global() and not TASK_2_CACHE.ecolog_teleported or not ecolog_squad_se then
|
|
local cond_no_rem_no_exist = not TASK_2_CACHE.old_ecolog_squad_removed and not ecolog_squad_se
|
|
local cond_no_rem_exist = not TASK_2_CACHE.old_ecolog_squad_removed and ecolog_squad_se
|
|
local cond_rem_no_exist = TASK_2_CACHE.old_ecolog_squad_removed and not ecolog_squad_se
|
|
|
|
-- Release 'old' squad
|
|
if cond_no_rem_exist then
|
|
SIMBOARD:remove_squad(ecolog_squad_se)
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 10 - Ecolog squad removed...")
|
|
TASK_2_CACHE.old_ecolog_squad_removed = true
|
|
return
|
|
end
|
|
|
|
-- Create 'new' squad at new location
|
|
if cond_rem_no_exist or cond_no_rem_no_exist then
|
|
local spawn_data = TASK_2_CACHE.squads.ecolog_spawn_data
|
|
ecolog_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart2)
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 10 - Ecolog squad re-added...")
|
|
TASK_2_CACHE.ecolog_teleported = true
|
|
return
|
|
end
|
|
end
|
|
|
|
if TASK_2_CACHE.surge_started and surge_manager.is_finished() and TASK_2_CACHE.ecolog_teleported and ecolog_squad_se then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 10 - Emission finished...")
|
|
for member in ecolog_squad_se:squad_members() do
|
|
local member_se = alife_object(member.id)
|
|
if member_se:section_name() ~= "stalker_ecolog_convoy_yellow" then
|
|
CreateTimeEvent("western_goods_delay_kill_squad",member.id,0,surge_manager.make_dead,member.id)
|
|
end
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 10 - Trimmed Ecolog squad...")
|
|
end
|
|
|
|
local dialog_sender_1 = { name="Anonymous", icon="ui_inGame2_no_data"}
|
|
local dialog_sender_2 = { name=alife():actor():character_name(), icon=alife():actor():character_icon()}
|
|
|
|
send_dialog({
|
|
{sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_10_message_1")},
|
|
{sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_10_message_2")},
|
|
{sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_10_message_3")}
|
|
})
|
|
|
|
tsk.stage = 11
|
|
end
|
|
end
|
|
|
|
-- Twelfth stage : Get to the yellow crewmate & kill the controller
|
|
if tsk.stage == 11 then
|
|
local controller_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.controller_spawn_data.sec)
|
|
local supplies_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.main_item)
|
|
|
|
-- Wait for the player to reach the KBO
|
|
if not TASK_2_CACHE.kbo_room_reached then
|
|
if not western_goods_restrictors.in_bounds(db.actor, TASK_2_CACHE.restrictors.kbo) then
|
|
return
|
|
end
|
|
TASK_2_CACHE.kbo_room_reached = true
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_ecolog_calm")
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 11 - Calmed Yellow crewmate...")
|
|
end
|
|
|
|
-- Send signal to logic scheme
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_ecolog_calm")
|
|
|
|
-- Wait for player to finish dialog with crewmate
|
|
if not western_goods_utils.has_info("western_goods_ecolog_convoy_yellow_meet_over") then return end
|
|
|
|
-- Spawn Controller squad
|
|
if not TASK_2_CACHE.controller_squad_spawned and not controller_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.controller_spawn_data
|
|
controller_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if controller_squad_se then
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_controller_spawned")
|
|
TASK_2_CACHE.controller_squad_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
-- Wait for controller to be dead
|
|
if not TASK_2_CACHE.controller_squad_killed then
|
|
if TASK_2_CACHE.controller_squad_spawned and controller_squad_se then
|
|
return
|
|
end
|
|
TASK_2_CACHE.controller_squad_killed = true
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_controller_killed")
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 11 - Controller is dead...")
|
|
end
|
|
|
|
-- Send signal to logic scheme
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_controller_killed")
|
|
|
|
-- Wait for player to finish second dialog
|
|
if not western_goods_utils.has_info("western_goods_ecolog_convoy_yellow_second_meet_over") then return end
|
|
|
|
local lynn_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.lynn_spawn_data.sec)
|
|
local lynn_guards_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.lynn_guards_spawn_data.sec)
|
|
|
|
-- Spawn Dunn Lynn squad
|
|
if not TASK_2_CACHE.lynn_squad_spawned and not lynn_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.lynn_spawn_data
|
|
lynn_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if lynn_squad_se then
|
|
|
|
local dialog_sender_1 = { name=alife():actor():character_name(), icon=alife():actor():character_icon()}
|
|
local dialog_sender_2 = { name="Anonymous", icon="ui_inGame2_no_data"}
|
|
|
|
send_dialog({
|
|
{sender=dialog_sender_1.name, icon=dialog_sender_1.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_11_message_1")},
|
|
{sender=dialog_sender_2.name, icon=dialog_sender_2.icon, message=western_goods_utils.get_translation("st_wg_trader_act_2_task_2_stage_11_message_2")}
|
|
})
|
|
|
|
TASK_2_CACHE.lynn_squad_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
-- Spawn Dunn Lynn guards squad
|
|
if not TASK_2_CACHE.lynn_guards_squad_spawned and not lynn_guards_squad_se then
|
|
local spawn_data = TASK_2_CACHE.squads.lynn_guards_spawn_data
|
|
lynn_guards_squad_se = western_goods_utils.spawn_squad_smart(spawn_data.sec, spawn_data.smart)
|
|
|
|
if lynn_guards_squad_se then
|
|
TASK_2_CACHE.lynn_guards_squad_spawned = true
|
|
return
|
|
else
|
|
printf("![WG] ERROR | Tasks Act 2 | Failed to spawn %s smart:%s",spawn_data.sec, spawn_data.smart)
|
|
return "fail"
|
|
end
|
|
end
|
|
|
|
if not (supplies_se and (supplies_se.parent_id ~= AC_ID)) then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 11 - Player has the main item %s",supplies_se.id)
|
|
tsk.stage = 13
|
|
else
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 11 - Player does not have the main item...")
|
|
tsk.stage = 12
|
|
end
|
|
end
|
|
|
|
-- Thirteenth stage : Get the case
|
|
if tsk.stage == 12 then
|
|
local supplies_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.main_item)
|
|
|
|
-- If the supplies cannot be found, respawn them
|
|
if not supplies_se then
|
|
-- Spawn the supplies, objective the player has to retrieve
|
|
supplies_se = alife_create(TASK_2_CACHE.main_item, vector():set(4.8,4.6,269.3), 204172, 4926)
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 12 - Main 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 2 | Task 2 - Stage 12 - Player picked up the main item %s", supplies_se.id)
|
|
tsk.stage = 13
|
|
return
|
|
end
|
|
end
|
|
|
|
-- Thirteenth stage : Return the case
|
|
if tsk.stage == 13 then
|
|
local supplies_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.main_item)
|
|
|
|
-- If the supplies cannot be found (which is odd), roll back to stage 12
|
|
if not supplies_se then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Stage 13 - Main item disappeared, rolling back to stage 12...")
|
|
tsk.stage = 12
|
|
return
|
|
end
|
|
|
|
western_goods_utils.give_info("western_goods_act_2_task_2_ready_finished")
|
|
|
|
-- 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 2 | Task 2 - Stage 13 - Player dropped the main item %s", supplies_se.id)
|
|
|
|
western_goods_utils.rem_info("western_goods_act_2_task_2_ready_finished")
|
|
|
|
tsk.stage = 12
|
|
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("on_game_load", task_2_prefetch_models)
|
|
RegisterScriptCallback("actor_on_first_update", task_2_setup)
|
|
RegisterScriptCallback("actor_on_first_update", task_2_remove_dunn_lynn_after_task)
|
|
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 = {}
|
|
|
|
-- Make copies of task caches
|
|
copy_table(TASK_1_SAVE, TASK_1_CACHE)
|
|
copy_table(TASK_2_SAVE, TASK_2_CACHE)
|
|
|
|
-- Pre-process tables
|
|
TASK_2_SAVE.available_time = (TASK_2_SAVE.available_time or 0) - time_global()
|
|
TASK_2_SAVE.spawn_throttle = (TASK_2_SAVE.spawn_throttle or 0) - time_global()
|
|
TASK_2_SAVE.progress_timer = (TASK_2_SAVE.progress_timer or 0) - time_global()
|
|
TASK_2_SAVE.bandit_2_autokill_timer = (TASK_2_SAVE.bandit_2_autokill_timer or 0) - time_global()
|
|
|
|
-- Save tables
|
|
m_data.wg_act_2_task_1_cache = TASK_1_SAVE
|
|
m_data.wg_act_2_task_2_cache = TASK_2_SAVE
|
|
|
|
-- Debug prints
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Saved variables...\n%s",utils_data.print_table(TASK_1_SAVE, false, true))
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Saved variables...\n%s",utils_data.print_table(TASK_2_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_2_task_1_cache or {}
|
|
local TASK_2_SAVE = m_data.wg_act_2_task_2_cache or {}
|
|
|
|
-- Post-process tables
|
|
TASK_2_SAVE.available_time = (TASK_2_SAVE.available_time or 0) + time_global()
|
|
TASK_2_SAVE.spawn_throttle = (TASK_2_SAVE.spawn_throttle or 0) + time_global()
|
|
TASK_2_SAVE.progress_timer = (TASK_2_SAVE.progress_timer or 0) + time_global()
|
|
TASK_2_SAVE.bandit_2_autokill_timer = (TASK_2_SAVE.bandit_2_autokill_timer or 0) + time_global()
|
|
|
|
-- Restore task caches
|
|
copy_table(TASK_1_CACHE, TASK_1_SAVE)
|
|
copy_table(TASK_2_CACHE, TASK_2_SAVE)
|
|
|
|
-- Debug prints
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Loaded variables...\n%s",utils_data.print_table(TASK_1_CACHE, false, true))
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Loaded variables...\n%s",utils_data.print_table(TASK_2_CACHE, false, true))
|
|
end
|
|
|
|
-- ---------------------------------------------------------------------------------------------------------------------
|
|
-- General functions
|
|
-- ---------------------------------------------------------------------------------------------------------------------
|
|
|
|
--- Function used to get a table where keys are IDs of chemical anomalies and values are boolean true.
|
|
--- @return table
|
|
function task_1_get_static_chemical_anomalies()
|
|
|
|
local viable_anomalies = {}
|
|
|
|
-- Set to false all dynamic anomalies
|
|
for _,v in pairs(bind_anomaly_field.dyn_anomalies) do
|
|
for id, _ in pairs(v) do
|
|
viable_anomalies[id] = false
|
|
end
|
|
end
|
|
|
|
-- Go through all IDs
|
|
western_goods_utils.server_objects_iter(function(se_obj)
|
|
if IsAnomaly(se_obj) then
|
|
if viable_anomalies[se_obj.id] == nil then
|
|
-- If the ID is unknown, then check for correct type of anomalies
|
|
if string.find(se_obj:section_name(), "chemical") or string.find(se_obj:section_name(), "acidic") then
|
|
viable_anomalies[se_obj.id] = true
|
|
end
|
|
else
|
|
-- If the ID isn't nil, then it's a dynamic anomaly, we set to nil
|
|
viable_anomalies[se_obj.id] = nil
|
|
end
|
|
end
|
|
end)
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 1 - Number of matching anomalies : %s", size_table(viable_anomalies))
|
|
|
|
return viable_anomalies
|
|
end
|
|
|
|
--- 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_2_task_1_finished")
|
|
local task_2_started = western_goods_utils.has_info("western_goods_act_2_task_2_active")
|
|
local task_2_done = western_goods_utils.has_info("western_goods_act_2_task_2_finished")
|
|
local task_opted_in = western_goods_utils.has_info("western_goods_act_2_task_2_opted_in")
|
|
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 task_opted_in and timeout_ready then
|
|
local delay = math.random(CONST_TASK_2_SOFT_DELAY_MIN, CONST_TASK_2_SOFT_DELAY_MAX)
|
|
CreateTimeEvent("western_goods_setup_task", "act_2_task_2", delay, function ()
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Task set up, time before start : %s",delay)
|
|
|
|
-- Give the task some time after loading the save
|
|
act_2_task_2_start(western_goods_utils.server_object_by_sid("cit_killers_merc_trader_stalker"))
|
|
|
|
-- Send a message to the player
|
|
send_dialog({
|
|
{sender="Anonymous", icon="ui_inGame2_no_data", message=western_goods_utils.get_translation("st_wg_act_2_task_2_job_descr")}
|
|
}, true)
|
|
|
|
return true
|
|
end)
|
|
else
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - What's missing? task_opted_in:%s - timeout_ready:%s (%s/%s)", task_opted_in, timeout_ready, time_global(), TASK_2_CACHE.available_time)
|
|
end
|
|
end
|
|
|
|
--- Function used to clean up the squads after Act 2, Task 2.
|
|
--- @return nil
|
|
function task_2_clean_squads()
|
|
western_goods_utils.server_objects_iter(function(se_obj)
|
|
for _,spawn_data in pairs(TASK_2_CACHE.squads) do
|
|
local is_from_task_2 = se_obj:section_name() == spawn_data.sec
|
|
local is_not_dunn_lynn = se_obj:section_name() ~= TASK_2_CACHE.squads.lynn_spawn_data.sec
|
|
local is_not_dunn_guards = se_obj:section_name() ~= TASK_2_CACHE.squads.lynn_guards_spawn_data.sec
|
|
if is_from_task_2 and is_not_dunn_lynn and is_not_dunn_guards then
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Removing '%s'",se_obj:name())
|
|
SIMBOARD:remove_squad(se_obj)
|
|
end
|
|
end
|
|
end)
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Removed squads ...")
|
|
end
|
|
|
|
--- Function used to mark on the PDA the enemies currently fighting with the player.
|
|
--- @param marked_enemies table
|
|
--- @return nil
|
|
function task_2_mark_current_enemies(marked_enemies)
|
|
for _,id in pairs(marked_enemies) do
|
|
level.map_remove_object_spot(id, "anomaly_thermal")
|
|
end
|
|
empty_table(marked_enemies)
|
|
for id,_ in pairs(xr_combat_ignore.fighting_with_actor_npcs) do
|
|
if not western_goods_utils.table_contains(marked_enemies, id) then
|
|
table.insert(marked_enemies, id)
|
|
level.map_add_object_spot_ser(id, "anomaly_thermal", "Enemy")
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Function called from dialog to give the player the quest item during Act 2, Task 2.
|
|
--- @param first_speaker game_object
|
|
--- @param second_speaker game_object
|
|
--- @return nil
|
|
function task_2_give_quest_item(first_speaker, second_speaker)
|
|
dialogs.relocate_item_section_to_actor(first_speaker, second_speaker, "wg_act_2_task_2_quest_item")
|
|
end
|
|
|
|
--- Function used to desspawn Dunn Lynn and his guards after Act 2, Task 2 is done and the player is on another level.
|
|
--- @return nil
|
|
function task_2_remove_dunn_lynn_after_task()
|
|
if western_goods_utils.has_info("western_goods_act_2_task_2_finished") and not (TASK_2_CACHE.lynn_squad_removed and TASK_2_CACHE.lynn_guards_squad_removed) then
|
|
local lynn_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.lynn_spawn_data.sec)
|
|
local lynn_guards_squad_se = western_goods_utils.server_object_by_sid(TASK_2_CACHE.squads.lynn_guards_spawn_data.sec)
|
|
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Trying to remove Lynn and/or his guards")
|
|
|
|
-- Remove Dunn Lynn squad if it wasn't removed yet
|
|
if not TASK_2_CACHE.lynn_squad_removed and lynn_squad_se and not simulation_objects.is_on_the_same_level(alife():actor(), lynn_squad_se) then
|
|
SIMBOARD:remove_squad(lynn_squad_se)
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Removed '%s'", lynn_squad_se:section_name())
|
|
end
|
|
-- Remove Dunn Lynn guards squad if it wasn't removed yet
|
|
if not TASK_2_CACHE.lynn_guards_squad_removed and lynn_guards_squad_se and not simulation_objects.is_on_the_same_level(alife():actor(), lynn_guards_squad_se)then
|
|
SIMBOARD:remove_squad(lynn_guards_squad_se)
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Removed '%s'", lynn_guards_squad_se:section_name())
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Function used to clear all the squads at a given smart terrain, except the squads defined in TASK_2_CACHE.
|
|
--- @param smart_name string
|
|
--- @return nil
|
|
function task_2_clear_smart_terrain(smart_name)
|
|
local smart_clear = SIMBOARD:get_smart_by_name(smart_name)
|
|
for id,bool in pairs(SIMBOARD.smarts[smart_clear.id].squads) do
|
|
local can_stay = false
|
|
local squad = alife_object(id)
|
|
if squad then
|
|
for _,spawn_data in pairs(TASK_2_CACHE.squads) do
|
|
if squad:section_name() == spawn_data.sec then
|
|
can_stay = true
|
|
end
|
|
end
|
|
local is_another_map = not simulation_objects.is_on_the_same_level(alife():actor(), squad)
|
|
local distance = western_goods_utils.get_distance_sqr(alife():actor().position,squad.position)
|
|
if not can_stay and (is_another_map or distance > CONST_TASK_2_CLEAR_SMART_DIST) then
|
|
SIMBOARD:remove_squad(squad)
|
|
dbg_printf("[WG] Tasks Act 2 | Task 2 - Released random squad '%s' from smart '%s' (dist(sqr):%s)",squad:name(),smart_clear:name(),distance)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--- Function used to front load some models if Act 2, Task 2 is active.
|
|
--- @return nil
|
|
function task_2_prefetch_models()
|
|
local tsk = task_manager.get_task_manager().task_info["western_goods_act_2_task_2"]
|
|
if tsk and level.name() == "pripyat" then
|
|
game.prefetch_model([[dynamics\vehicles\veh_btr\veh_btr_u_01.ogf]])
|
|
end
|
|
end |