--============================================================= -- -- sim_board.script -- CoC 1.5b r4 - DoctorX Dynamic Population 1.0 -- -- Modified by: DoctorX -- Last revised: April 21, 2018 -- --============================================================= --'****************************************************** --'*Registry of smart terrains. The playing field simulation. -- Edited by Alundaio --'****************************************************** ------------------- local level,alife,game_graph,math,pairs,tostring,tonumber,tsort,tinsert = level,alife,game_graph,math,pairs,tostring,tonumber,table.sort,table.insert ------------------- ----------------------------------------------------------------------------------- -- Public ----------------------------------------------------------------------------------- function general_squad_precondition(squad,target) -- duty and freedom target eachother --[[ if (squad.player_id == "dolg") then if (target.player_id == "freedom" or is_squad_monster[target.player_id]) then return in_time_interval(8,19) end elseif (squad.player_id == "freedom") then if (target.player_id == "dolg") then return in_time_interval(8,19) end end -- if target squad is not monster if (is_squad_monster[target.player_id] ~= true) then if (squad.player_id == "monster_predatory_day") then return in_time_interval(6,19) elseif (squad.player_id == "monster_predatory_night") then return in_time_interval(19,6) elseif (squad.player_id == "monster_zombied_day") then return in_time_interval(6,19) elseif (squad.player_id == "monster_zombied_night") then return in_time_interval(19,6) end end --]] return false end -- ._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._. -- -- general_base_precondition() -- -- Changelist -- ---------- -- 11/08/2024 2:52:37 AM [moonshroom] -- -> Tweaked code to mitigate weirdness when NPCs are travelling -- to base smarts (going around in circles, being indecisive, etc.) -- 23/07/2024 5:39:16 PM [moonshroom] -- -> Modified so squads will not target smart terrains -- that is occupied by a different, neutral faction. -- (ex: csky won't target smart terrain occupied by stalkers) -- -- ._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._.-._. function general_base_precondition( squad, target ) -- Factions can target a smart that is either empty or occupied by their faction. if (target.faction == nil or target.faction == squad.player_id) then return true end if ( game_relations.is_factions_enemies( squad.player_id, target.faction ) == true ) then return in_time_interval( 6, 10 ) or in_time_interval( 14, 18 ) end -- printf("Squad %s targetted %s, returned %s", squad:section_name(), SIMBOARD.smarts[target.id].smrt:name(), game.translate_string(retval)) return false --[[ -- Old code. local need_squads = 0 if (squad.player_id == "dolg") then if (target.faction == "freedom") then need_squads = 1 end elseif (squad.player_id == "freedom") then if (target.faction == "dolg") then need_squads = 1 end elseif (squad.player_id == "army") then need_squads = 3 elseif (squad.player_id == "monolith") then need_squads = 1 elseif (squad.player_id == "stalker" or squad.player_id == "csky") then need_squads = 2 elseif (squad.player_id == "bandit") then if (target.faction_controlled and target.faction ~= "bandit") then need_squads = 2 end end if need_squads > target.max_population then need_squads = target.max_population end if (SIMBOARD.smarts[target.id]) and (SIMBOARD.smarts[target.id].squads[squad.id] or SIMBOARD.smarts[target.id].population < target.max_population and SIMBOARD.smarts[target.id].population < need_squads) then return true end return in_time_interval(6,10) --]] end function general_territory_precondition(squad,target) if (squad.player_id == "monster_predatory_day") then return in_time_interval(6,19) elseif (squad.player_id == "monster_predatory_night") then return in_time_interval(19,6) elseif (squad.player_id == "monster_zombied_day") then return in_time_interval(6,19) elseif (squad.player_id == "monster_zombied_night") then return in_time_interval(19,6) elseif (squad.player_id == "monster_vegetarian" or squad.player_id == "zombied") then return true end -- Any squad can target a territory occupied by their own community / or empty if (target.faction == nil or target.faction == squad.player_id) then return true end -- if a territory is occupied by enemies, squad can target it during daytime if (game_relations.is_factions_enemies(squad.player_id,target.faction)) then return in_time_interval(9,15) else return true end return false end function general_resource_precondition(squad,target) return in_time_interval(10,6) end function general_lair_precondition(squad,target) --[[ if (squad.player_id == "monster_predatory_day") then return in_time_interval(19,6) elseif (squad.player_id == "monster_predatory_night") then return in_time_interval(6,19) elseif (squad.player_id == "monster_zombied_day") then return in_time_interval(19,6) elseif (squad.player_id == "monster_zombied_night") then return in_time_interval(6,19) elseif (squad.player_id == "monster_vegetarian" or squad.player_id == "zombied") then return true end return in_time_interval(19,6) --]] return true -- Will fill up all the lairs first, by monster squads end -------------------------------------------------------------------------------------------------------- -- SIMULATION BOARD -------------------------------------------------------------------------------------------------------- class "simulation_board" function simulation_board:__init() --' smart = {smrt, targets = {}, dangers = {}, squads = {}, stayed_squads = {}} self.smarts = {} self.smarts_by_names = {} self.simulation_started = true self.squads = {} self.tmp_assigned_squad = {} end function simulation_board:register_smart(obj) --alun_utils.debug_write(strformat("simulation_board:register_smart %s",obj and obj:name())) if self.smarts[obj.id] ~= nil then printf("Smart already exist in list [%s]", obj:name()) return end --self.smarts[obj.id] = {smrt = obj, squads = {}, stayed_squads = {}, population = 0} self.smarts[obj.id] = {smrt = obj, squads = {}, population = 0} self.smarts_by_names[obj:name()] = obj end function simulation_board:unregister_smart(obj) --alun_utils.debug_write(strformat("simulation_board:unregister_smart %s",obj and obj:name())) self.smarts[obj.id] = nil self.smarts_by_names[obj:name()] = nil end function simulation_board:start_sim() -- Doesn't seem to be used in 1.6 self.simulation_started = true end function simulation_board:stop_sim() -- Doesn't seem to be used in 1.6 self.simulation_started = false end function simulation_board:set_actor_community(community) ---- Устанавливаем группировку игрока db.actor:set_character_community(actor_communitites[community], 0, 0) end -- Инициализация смарта function simulation_board:init_smart(obj) --alun_utils.debug_write(strformat("simulation_board:init_smart %s",obj and obj:name())) if self.tmp_assigned_squad[obj.id] ~= nil then for k,v in pairs(self.tmp_assigned_squad[obj.id]) do self:assign_squad_to_smart(v, obj.id) end self.tmp_assigned_squad[obj.id] = nil end end --' Создание нового отряда function simulation_board:create_squad(spawn_smart, sq_id) --alun_utils.debug_write(strformat("simulation_board:create_squad spawn_smart=%s sq_id=%s",spawn_smart and spawn_smart:name(),sq_id)) local squad_id = tostring(sq_id) -- if not (system_ini():section_exist(squad_id)) then -- printf("squad section does not exist: %s",squad_id) -- return -- end local squad = alife():create(squad_id,spawn_smart.position, spawn_smart.m_level_vertex_id,spawn_smart.m_game_vertex_id) squad:create_npc(spawn_smart) self:assign_squad_to_smart(squad, spawn_smart.id) local sim = alife() for k in squad:squad_members() do local se_obj = k.object or k.id and sim:object(k.id) if (se_obj) then SIMBOARD:setup_squad_and_group(se_obj) -- Alundaio SendScriptCallback("squad_on_npc_creation",squad,se_obj,spawn_smart) -- Alundaio end end return squad end --' Удалить отряд function simulation_board:remove_squad(squad) --alun_utils.debug_write(strformat("simulation_board:remove_squad %s",squad and squad:name())) self:assign_squad_to_smart(squad, nil) squad:remove_squad() end --' Назначение отряда в смарт. function simulation_board:assign_squad_to_smart(squad, smart_id) --alun_utils.debug_write(strformat("simulation_board:assign_squad_to_smart %s smart_id=%s",squad and squad:name(),smart_id)) if (smart_id and self.smarts[smart_id] == nil) then if self.tmp_assigned_squad[smart_id] == nil then self.tmp_assigned_squad[smart_id] = {} end local t = self.tmp_assigned_squad[smart_id] t[#t+1] = squad --table.insert(self.tmp_assigned_squad[smart_id], squad) return end local old_smart_id = squad.smart_id squad.smart_id = nil -- remove squad from old smart if exist if (old_smart_id and self.smarts[old_smart_id] and self.smarts[old_smart_id].squads[squad.id]) then self.smarts[old_smart_id].squads[squad.id] = nil -- get accurate population count excluding squads using target_smart param self.smarts[old_smart_id].population = smart_terrain.smart_terrain_squad_count(SIMBOARD.smarts[old_smart_id].squads) end if smart_id == nil then squad:assign_smart(nil,old_smart_id) return end squad:assign_smart(self.smarts[smart_id].smrt,old_smart_id) --' Прописываем отряд в новом смарте. if not (self.smarts[smart_id].squads[squad.id]) then self.smarts[smart_id].squads[squad.id] = squad if not (squad:get_script_target()) then -- don't count squads with target_smart self.smarts[smart_id].population = self.smarts[smart_id].population + 1 end end end local community_groups = {} -- установить squad и group в соответствии с работой function simulation_board:setup_squad_and_group(se_obj) --alun_utils.debug_write(strformat("simulation_board:setup_squad_and_group %s",obj and obj:name())) local sim = alife() local squad = se_obj.group_id and se_obj.group_id ~= 65535 and sim:object(se_obj.group_id) if not (squad) then change_team_squad_group(se_obj, se_obj.team, se_obj.squad, 0) return end local smart = squad.smart_id and sim:object(squad.smart_id) change_team_squad_group(se_obj, se_obj.team, smart and smart.squad_id or se_obj.squad, 1) end --' Заполнение стартового расположения function simulation_board:fill_start_position() SendScriptCallback("fill_start_position") if self.start_position_filled == true then return end self.start_position_filled = true local setting_ini -- /////////////////////////////////////////////////////////////////////////////////////////////// -- -- Starting Squads Settings File -- -- - Ini requirements: -- configs\drx\drx_dp_config.ltx -- [spawn_modifiers] -- classic_start (bool) -- - Whether to use CoC default starting squads or completely randomize faction populations on game start -- -- Modified by DoctorX -- for DoctorX Dynamic Population 1.0 -- April 21, 2018 -- -- ----------------------------------------------------------------------------------------------- -- Check if CoC classic starting squads or random: local classic_start = true local drx_dp_ini = ini_file( "drx\\drx_dp_config.ltx" ) if ( drx_dp_ini ) then classic_start = drx_dp_ini:r_bool_ex( "spawn_modifiers", "classic_start" ) if ( classic_start == nil ) then classic_start = true end end -- Use survival mode starting squads file to only load stayed squads if survival mode or not classic start: if ( IsSurvivalMode() ) then -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ setting_ini = ini_file("misc\\simulation_survival_mode.ltx") elseif ( not ( classic_start ) ) then setting_ini = ini_file("misc\\simulation_non_classic.ltx") else setting_ini = ini_file("misc\\simulation.ltx") end local stalker_pop_factor = (axr_main.config:r_value("mm_options","alife_stalker_pop",2) or 1) local monster_pop_factor = (axr_main.config:r_value("mm_options","alife_mutant_pop",2) or 1) local result, squad_section, count, li, lc setting_ini:section_for_each(function(section) lc = setting_ini:line_count(section) for li=0,lc-1 do local smart = self.smarts_by_names[section] if (smart) then result, squad_section, count = setting_ini:r_line(section,li,"","") count = tonumber(count) or 1 if (string.find(squad_section,"sim_squad")) then count = count*stalker_pop_factor -- /////////////////////////////////////////////////////////////////////////////////////////////// -- -- Starting Squad NPC Population Factor -- -- - Ini requirements: -- configs\drx\drx_dp_config.ltx -- [spawn_modifiers] -- squad_spawn_chance (float, decimal decimal percent) -- - Percent chance of respawn for each eligible squad -- -- Modified by DoctorX -- for DoctorX Dynamic Population 1.0 -- April 21, 2018 -- -- ----------------------------------------------------------------------------------------------- -- Round adjusted spawn count up or down: local whole = math.floor( count ) local remain = (count - whole) if ( remain > 0 ) then if ( math.random( ) <= remain ) then whole = (whole + 1) end end -- Adjust spawn count for squad spawn chance: local drx_dp_ini = ini_file( "drx\\drx_dp_config.ltx" ) local squad_spawn_chance = (drx_dp_ini:r_float_ex( "spawn_modifiers", "squad_spawn_chance" ) or 0) count = 0 if ( squad_spawn_chance > 0 ) then for i = 1, ( whole ) do if ( math.random( ) <= squad_spawn_chance ) then count = (count + 1) end end end -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ elseif (string.find(squad_section,"simulation")) then count = count*monster_pop_factor -- /////////////////////////////////////////////////////////////////////////////////////////////// -- -- Starting Squad Mutant Population Factor -- -- - Ini requirements: -- configs\drx\drx_dp_config.ltx -- [spawn_modifiers] -- squad_spawn_chance (float, decimal decimal percent) -- - Percent chance of respawn for each eligible squad -- -- Modified by DoctorX -- for DoctorX Dynamic Population 1.0 -- April 21, 2018 -- -- ----------------------------------------------------------------------------------------------- -- Round adjusted spawn count up or down: local whole = math.floor( count ) local remain = (count - whole) if ( remain > 0 ) then if ( math.random( ) <= remain ) then whole = (whole + 1) end end -- Adjust spawn count for squad spawn chance: local drx_dp_ini = ini_file( "drx\\drx_dp_config.ltx" ) local squad_spawn_chance = (drx_dp_ini:r_float_ex( "spawn_modifiers", "squad_spawn_chance" ) or 0) count = 0 if ( squad_spawn_chance > 0 ) then for i = 1, ( whole ) do if ( math.random( ) <= squad_spawn_chance ) then count = (count + 1) end end end -- \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\ end for i=1,count do self:create_squad(smart,squad_section) end else printf("sim_board:fill_start_position incorrect smart by name %s",section) end end end ) end --' Возвратить смарт по его имени. function simulation_board:get_smart_by_name(name) return self.smarts_by_names[name] end --' Возвращает количество отрядов в смарте. function simulation_board:get_smart_population(smart) return self.smarts[smart.id].population end --' Получение игрового поля. function get_sim_board() if _G.SIMBOARD == nil then _G.SIMBOARD = simulation_board() end return _G.SIMBOARD end function simulation_board:get_squad_target(squad) local most_priority_task = nil local most_priority_task_prior = nil local curr_prior = 0 local object_registry = simulation_objects.get_sim_obj_registry().objects for k,v in pairs(object_registry) do curr_prior = -1 if v.id ~= squad.id and not v.locked == true then curr_prior = v:evaluate_prior(squad) end if (curr_prior >= 0 and v:target_precondition(squad)) and (most_priority_task_prior == nil or curr_prior > most_priority_task_prior) then most_priority_task = v most_priority_task_prior = curr_prior end end return most_priority_task end --' Обнуление списка на создании игры. function clear() _G.SIMBOARD = nil end