local STEP_SIZE = 5 local STEP_SIZE_OFFLINE = 1 local _mej = { ['logic@bar_zastava_guard_1_walk'] = "logic@duty_guard1", ['logic@bar_zastava_guard_2_walk'] = "logic@duty_guard2", ['logic@bar_zastava_guard_3_walk'] = "logic@duty_guard3", ['logic@bar_zastava_guard_4_walk'] = "logic@duty_guard4", ['logic@bar_zastava_guard_5_walk'] = "logic@duty_guard5", ['logic@bar_zastava_guard_6_walk'] = "logic@duty_guard6", ['logic@bar_zastava_guard_7_walk'] = "logic@duty_guard7", ['logic@bar_zastava_guard_8_walk'] = "logic@duty_guard8", ['logic@bar_zastava_guard_9_walk'] = "logic@duty_guard9", ['logic@follower_bar_zastava_guard_1_walk'] = "logic@duty_guard1", ['logic@follower_bar_zastava_guard_2_walk'] = "logic@duty_guard2", ['logic@follower_bar_zastava_guard_4_walk'] = "logic@duty_guard4", ['logic@follower_bar_zastava_guard_5_walk'] = "logic@duty_guard5", ['logic@follower_bar_zastava_guard_6_walk'] = "logic@duty_guard6", ['logic@follower_bar_zastava_guard_7_walk'] = "logic@duty_guard7", ['logic@follower_bar_zastava_guard_8_walk'] = "logic@duty_guard8", } local function allowed(a) -- printf('allowed: %s',a.section) if not _mej[a.section] then return true end for k in pairs(db.storage) do if tonumber(k) and db.storage[k] and db.storage[k].section_logic == _mej[a.section] then -- printf('[%s] disallowed because [%s] (%s) taken', a.section, db.storage[k].section_logic, _mej[a.section]) return false end end return true end local function job_avail_to_npc(npc_info, job, smart) --[[ if (smart.dead_time[job.section]) then return false end --]] local precond = gulag_general.get_job_precondition(job) if (precond) then return allowed({ section = job.section}) and precond(npc_info.se_obj, smart, job, npc_info) end return true end function smart_terrain.se_smart_terrain:unregister_npc(obj) --utils_data.debug_write(strformat("%s:%s:unregister_npc %s",self:name(),self.id,obj and obj:name())) self.arriving_npc[obj.id] = nil if (obj.clear_smart_terrain) then obj:clear_smart_terrain() end self:clear_job(obj.id,true) ---[[GhenTuong: ---------------------------------------- if (xr_logic_ex and xr_logic_ex.ignore_smart_job and xr_logic_ex.ignore_smart_job(obj)) then return end ------------------------------------------------------]] local st = db.storage[obj.id] if (st and st.object) then local cls = obj.clsid and obj:clsid() if not (cls) then return end local stype = IsStalker(nil,cls) and 0 or IsMonster(nil,cls) and 1 or IsHelicopter(nil,cls) and 3 or nil if not (stype) then return end xr_logic.initialize_obj(st.object, st, false, db.actor, stype) end --printf("self.npc_info[obj.id] = nil !!! obj.id=%s [%s]", obj.id,obj:name()) end function smart_terrain.se_smart_terrain:select_npc_job(npc_info,now,surge_started) if (self.disabled or not self.is_on_actor_level) then return end ---[[GhenTuong: ---------------------------------------- if (xr_logic_ex and xr_logic_ex.ignore_smart_job and xr_logic_ex.ignore_smart_job(npc_info and npc_info.se_obj)) then return end ------------------------------------------------------]] --utils_data.debug_write(strformat("%s:select_npc_job %s",self:name())) if not (npc_info and npc_info.se_obj and npc_info.stype) then return printf("%s no npc_info!",self:name()) end -- reference job table according to race local jobs = npc_info.stype == 0 and self.stalker_jobs or npc_info.stype == 1 and self.monster_jobs or npc_info.stype == 3 and self.heli_jobs if not (jobs) then return printf("%s no job table for %s [stype = %s]",self:name(),npc_info.se_obj:name(),npc_info.stype) end local new_job local npc_by_job_section = self.npc_by_job_section -- If the NPC has an existing job link, validate it and iterate job table -- for a higher priority job according to defined STEP_SIZE if (npc_info.job) then -- Make sure current job is still available if (npc_by_job_section[npc_info.job.section] == npc_info.se_obj.id) then -- Make sure current job is still available if (job_avail_to_npc(npc_info,npc_info.job,self)) then if (npc_info.current_index == nil or now) then npc_info.current_index = 1 end local get_job_prior = gulag_general.get_job_prior local itr_job local npc_id local step = 1 while (new_job == nil and step <= (now and #jobs or st and STEP_SIZE or STEP_SIZE_OFFLINE)) do step = step + 1 if (npc_info.current_index > #jobs) then npc_info.current_index = 1 break end -- Step through job table one step at a time looking for a higher prior job itr_job = jobs[npc_info.current_index] npc_info.current_index = npc_info.current_index + 1 npc_id = npc_by_job_section[itr_job.section] -- Check empty job --if (npc_id == nil or npc_id == npc_info.se_obj.id) then if (npc_id == nil) then -- Find only higher priority jobs if already linked to a job if (get_job_prior(itr_job) > get_job_prior(npc_info.job)) then if (job_avail_to_npc(npc_info, itr_job, self)) then -- Only take this higher priority job if when there is either no surge or if job is not in surge cover during surge; takes exclusive no matter what if (itr_job.exclusive or not xr_conditions.surge_started() or not surge_manager.job_in_surge_cover(npc_info.se_obj,npc_info.job)) then new_job = itr_job npc_info.current_index = 1 end end end end end else -- Job is no longer available, unlink job info for sec,npcid in pairs(npc_by_job_section) do if (npcid == npc_info.se_obj.id) then npc_by_job_section[sec] = nil end end npc_info.job = nil npc_info.current_index = 1 end else -- Job is not linked properly, npc_id doesn't match owner se_obj for sec,npcid in pairs(npc_by_job_section) do if (npcid == npc_info.se_obj.id) then npc_by_job_section[sec] = nil end end npc_info.job = nil npc_info.current_index = 1 end end if not (npc_info.job) then if (npc_info.current_index == nil or now) then npc_info.current_index = 1 end local itr_job,npc_id local step = 1 local st = db.storage[npc_info.se_obj.id] local STEP_SIZE_NO_JOB = #jobs while (new_job == nil and step <= (now and STEP_SIZE_NO_JOB or st and STEP_SIZE_NO_JOB or STEP_SIZE_OFFLINE)) do step = step + 1 if (npc_info.current_index > STEP_SIZE_NO_JOB) then npc_info.current_index = 1 break end -- Step through job table one step at a time looking for a high prior job itr_job = jobs[npc_info.current_index] npc_info.current_index = npc_info.current_index + 1 npc_id = npc_by_job_section[itr_job.section] -- validate existing job link if (npc_id and not self.npc_info[npc_id]) then npc_by_job_section[itr_job.section] = nil end -- Check empty job or re-take current job if (npc_id == nil or npc_id == npc_info.se_obj.id) and (job_avail_to_npc(npc_info, itr_job, self)) then new_job = itr_job npc_info.current_index = 1 end end if not (new_job) then return end end local id = npc_info.se_obj.id -- newly selected job if (new_job and new_job ~= npc_info.job) then -- Unassign npc_id from old job and unreference job section for sec,npcid in pairs(npc_by_job_section) do if (npcid == id) then npc_by_job_section[sec] = nil end end -- setup table that references NPCs by their job section npc_by_job_section[new_job.section] = id -- link up NPC info and references npc_info.job = new_job npc_info.begin_job = false -- grab storage and ensure object is online. local st = self.online and db.storage[id] -- If NPC has storage, it is online, so switch logic if (st and st.object) then --xr_logic.switch_to_section(st.object, self.ltx, "nil") npc_info.begin_job = true empty_table(db.offline_objects[id]) self:setup_logic(st.object) return true end end if (npc_info.begin_job ~= true and npc_info.job) then -- grab storage and ensure object is online. local st = self.online and db.storage[id] -- If NPC has storage it is online, so switch logic if (st and st.object) then npc_info.begin_job = true empty_table(db.offline_objects[id]) self:setup_logic(st.object) return true end end end function smart_terrain.setup_gulag_and_logic_on_spawn(obj, st, se_obj, stype, loaded) --utils_data.debug_write(strformat("smart_terrain.setup_gulag_and_logic_on_spawn %s",obj and obj:name())) local sim = alife() ---[[GhenTuong: ---------------------------------------- if (xr_logic_ex and xr_logic_ex.ignore_smart_job and xr_logic_ex.ignore_smart_job(se_obj)) then return end ------------------------------------------------------]] -- Expedite arrival and job assignment local smart = se_obj.m_smart_terrain_id and se_obj.m_smart_terrain_id ~= 65535 and sim:object(se_obj.m_smart_terrain_id) if (smart and smart:clsid() == clsid.smart_terrain) then local npc_info = smart.npc_info[se_obj.id] if (npc_info) then if not (npc_info.job) then smart:select_npc_job(npc_info,true) local smart_task = smart.npc_info[se_obj.id].job and smart.npc_info[se_obj.id].job.alife_task if (smart_task) then db.spawned_vertex_by_id[se_obj.id] = smart_task:level_vertex_id() end elseif (npc_info.job) then -- if already job begin then don't spawn at job local smart_task = npc_info.begin_job ~= true and npc_info.job and npc_info.job.alife_task or nil if (smart_task) then db.spawned_vertex_by_id[se_obj.id] = smart_task:level_vertex_id() end npc_info.begin_job = true empty_table(db.offline_objects[se_obj.id]) smart:setup_logic(obj) end return end end xr_logic.initialize_obj(obj, st, loaded, db.actor, stype) end