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
|
|||
|
|