438 lines
14 KiB
Plaintext
438 lines
14 KiB
Plaintext
--'******************************************************
|
||
--'*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
|
||
|