Divergent/mods/Zone Customization Project/gamedata/scripts/sim_board.script

438 lines
14 KiB
Plaintext
Raw Permalink Blame History

--'******************************************************
--'*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)
--' <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
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