--'****************************************************** --'*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) return false end function general_base_precondition(squad,target) -- Any faction can target a base occupied by their own community / or empty if (target.faction == nil or target.faction == squad.player_id) then return true end -- if a base is occupied by enemies, squad can target it during early sunrise time if (game_relations.is_valid(squad.player_id) and game_relations.is_valid(target.faction)) then if (game_relations.is_factions_enemies(squad.player_id,target.faction)) then return in_time_interval(3,6) else return true end end return false end function general_territory_precondition(squad,target) -- Mutants target territories based on their species and proper time 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_valid(squad.player_id) and game_relations.is_valid(target.faction)) then if (game_relations.is_factions_enemies(squad.player_id,target.faction)) then return in_time_interval(9,15) else return true end end return false end function general_resource_precondition(squad,target) return in_time_interval(10,6) end function general_lair_precondition(squad,target) 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) --utils_data.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) --utils_data.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) ---- Set the player grouping db.actor:set_character_community(actor_communitites[community], 0, 0) end -- Smart initialization function simulation_board:init_smart(obj) --utils_data.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 --' Create a new squad function simulation_board:create_squad(spawn_smart, sq_id) --utils_data.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 (ini_sys: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 -- SMR smr_debug.get_log().info("simboard", "setting up civil war relations for squad %s (smart: %s)", squad:section_name(), spawn_smart:name()) smr_civil_war.setup_civil_war_squad(squad, spawn_smart:name()) -- SMR END return squad end function simulation_board:create_squad_at_named_location(loc_name, squad_id) -- tdef -- if not (ini_file('misc\\squad_descr.ltx'):section_exist(squad_id)) then if not (ini_sys:section_exist(squad_id)) then callstack() printf("create_squad_at_named_location: squad section does not exist in misc\\squad_descr.ltx: %s",squad_id) return end local str = utils_data.read_from_ini(ini_file("named_locations.ltx"),loc_name,'position') if not str then callstack() printf('create_squad_at_named_location: named location not defined in named_locations.ltx: %s',loc_name) return end -- printf('%s: %s',loc_name, str) local function str_explode_num(str,sep,plain) if not (sep ~= "" and string.find(str,sep,1,plain)) then return { str } end local t = {} local size = 0 for s in str:gsplit(sep,plain) do size = size + 1 t[size] = tonumber(s) if not t[size] then printf("str_explode_num: warning: %s couldn't be parsed as number", s) end end return t end local data = str_explode_num(str,',') -- for k,v in pairs(data) do -- printf('data[%s] = %s (%s)',k, v, type(v)) -- end local pos = vector():set(data[1], data[2], data[3]) local squad = alife_create(squad_id, pos, data[4], data[5]) if squad then -- printf('create_squad_at_named_location: squad created %s',squad.id) end squad:create_npc(nil, pos, data[4], data[5]) 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) -- Alundaio end end return squad end --' Remove squad function simulation_board:remove_squad(squad) --utils_data.debug_write(strformat("simulation_board:remove_squad %s",squad and squad:name())) self:assign_squad_to_smart(squad, nil) squad:remove_squad() end --' Assignment squad in smart. function simulation_board:assign_squad_to_smart(squad, smart_id) --utils_data.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 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) SendScriptCallback("squad_on_leave_smart",squad,self.smarts[old_smart_id].smrt) 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] = true 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 SendScriptCallback("squad_on_enter_smart",squad,self.smarts[smart_id].smrt) end local community_groups = {} -- Set squad and group according to work function simulation_board:setup_squad_and_group(se_obj) --utils_data.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 -- Filling start location for squads from "simulation.ltx" function simulation_board:fill_start_position() -- SMR smr_civil_war.setup_factions_relation() -- SMR END -- Test map if (axr_main.config:r_value("character_creation","new_game_test",1) == true) then axr_main.config:w_value("character_creation","new_game_test") axr_main.config:save() -- Prevent spawn terrains from spawning NPCs if ui_debug_launcher then ui_debug_launcher.toggle_respawn() end printf("---------------- Welcome To Test Map ----------------") return end SendScriptCallback("fill_start_position") if self.start_position_filled == true then return end self.start_position_filled = true -- SMR local setting_ini = smr_pop.get_population_preset() local stalker_pop_factor = smr_pop.get_stalker_pop_factor() local monster_pop_factor = smr_pop.get_monster_pop_factor() -- SMR END 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 local common = ini_sys:r_bool_ex(squad_section,"common") local faction = ini_sys:r_string_ex(squad_section,"faction") if common then -- Common mutants if is_squad_monster[faction] then count = count*monster_pop_factor if (count == 0.5) then count = math.random(0,1) else count = round_idp(count) end -- Common stalkers else count = count*stalker_pop_factor if (count == 0.5) then -- just randomly 0 or 1 instead of always rounding to 1 count = math.random(0,1) else count = round_idp(count) end end else end for i=1,count do -- SMR smr_pop.smr_handle_spawn(squad_section, smart) -- SMR END end else printf("sim_board:fill_start_position incorrect smart by name %s",section) end end end ) end -- Return smart by its name. function simulation_board:get_smart_by_name(name) return self.smarts_by_names[name] end -- Returns the number of units in smart. function simulation_board:get_smart_population(smart) return self.smarts[smart.id].population end -- Getting the playing field. function get_sim_board() if _G.SIMBOARD == nil then _G.SIMBOARD = simulation_board() end return _G.SIMBOARD end local priority_tasks = {} function simulation_board:get_squad_target(squad) local size_t = 0 local object_registry = simulation_objects.object_registry local is_available = simulation_objects.available_by_id for index=1,simulation_objects.object_registry_size do local se_target = object_registry[index] if (not se_target.locked and se_target.id ~= squad.id and is_available[se_target.id]) then local curr_prior = se_target:evaluate_prior(squad) if (curr_prior > 0 and se_target:target_precondition(squad)) then -- Prioritize 5 potential targets if (size_t < 5) then size_t = size_t + 1 priority_tasks[size_t] = {se_target,curr_prior} elseif (curr_prior > priority_tasks[size_t][2]) then for i=1,size_t do if (curr_prior > priority_tasks[i][2]) then priority_tasks[i][2] = curr_prior priority_tasks[i][1] = se_target break end end end end end end -- Tronex, get target with highest prior local highest_prior = 0 local best_target for i=1,size_t do if highest_prior < priority_tasks[i][2] then highest_prior = priority_tasks[i][2] best_target = priority_tasks[i][1] end end if (size_t > 0) then --local target = priority_tasks[math.random(size_t)][1] local target = (math.random(1,100) <= 50) and priority_tasks[math.random(size_t)][1] or best_target -- Tronex --printf("squad=%s size=%s target=%s",squad:name(),size_t,target:name()) iempty_table(priority_tasks) -- It is better to reuse table to avoid GC return target end end -- Nilling the list on the creation of the game. function clear() _G.SIMBOARD = nil end