Divergent/mods/Hideout Furniture/gamedata/scripts/hf_map_objects.script

273 lines
7.8 KiB
Plaintext

local mcm_keybinds = ui_mcm and ui_mcm.key_hold
local record_on_place = false
local record_on_keypress = false
local bind_record = DIK_keys.DIK_APOSTROPHE
---@class UIRecordObj
GUI = nil -- instance, don't touch
function add_obj_prompt(section, position, level_vertex_id, game_vertex_id, rotation)
if not DEV_DEBUG then
return
end
hide_hud_inventory()
if (not GUI) then
GUI = UIRecordObj()
end
if (GUI) and (not GUI:IsShown()) then
GUI:ShowDialog(true)
GUI:Reset(section, position, level_vertex_id, game_vertex_id, rotation)
Register_UI("UIRecordObj","hf_record_on_place")
end
end
------------------------------------------------------------------
-- UI
-------------------------------------------------------------------
class "UIRecordObj" (CUIScriptWnd)
function UIRecordObj:__init() super()
self:InitControls()
self:InitCallBacks()
end
function UIRecordObj:__finalize()
end
function UIRecordObj:InitControls()
self:SetWndRect(Frect():set(0,0,1024,768))
self:SetAutoDelete(true)
--self:Enable(true)
local xml = CScriptXmlInit()
xml:ParseFile ("ui_items_backpack.xml")
self.dialog = xml:InitStatic("backpack", self)
xml:InitStatic("backpack:background", self.dialog)
self.input = xml:InitEditBox("backpack:input",self.dialog)
self:Register(self.input,"fld_input")
local btn = xml:Init3tButton("backpack:btn_cancel", self.dialog)
self:Register(btn,"btn_cancel")
btn = xml:Init3tButton("backpack:btn_ok", self.dialog)
self:Register(btn,"btn_ok")
end
function UIRecordObj:InitCallBacks()
self:AddCallback("btn_ok", ui_events.BUTTON_CLICKED, self.OnAccept, self)
self:AddCallback("btn_cancel", ui_events.BUTTON_CLICKED, self.Close, self)
end
function UIRecordObj:Reset(section, position, level_vertex_id, game_vertex_id, rotation)
self.input:SetText("")
self.section = section
self.position = position
self.level_vertex_id = level_vertex_id
self.game_vertex_id = game_vertex_id
self.rotation = rotation
end
function UIRecordObj:Update()
CUIScriptWnd.Update(self)
end
function UIRecordObj:OnAccept()
local spawn_name = self.input:GetText()
local data = {
["object"] = self.section,
["position"] = self.position,
["lvid"] = self.level_vertex_id,
["gvid"] = self.game_vertex_id,
["rotation"] = self.rotation,
}
add_obj_to_ltx(spawn_name, data)
self:Close()
end
function UIRecordObj:OnKeyboard(dik, keyboard_action)
local res = CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
if (res == false) then
if keyboard_action == ui_events.WINDOW_KEY_PRESSED then
if dik == DIK_keys.DIK_ESCAPE then
self:Close()
end
end
end
return res
end
function UIRecordObj:Close()
self:HideDialog()
Unregister_UI("UIRecordObj")
end
----------------------------------
-- Storing object data to LTX
----------------------------------
local function is_vector(var)
if type(var) ~= "userdata" then return false end
if var.x and var.y and var.z then return true end
return false
end
function add_obj_to_ltx(spawn_name, data)
---@type ini_file_ex
local ini_cc = ui_debug_launcher.ini_cc
if spawn_name == nil or spawn_name == "" then
spawn_name = os.date("%Y/%m/%d-%H:%M:%S")
end
for key, value in pairs(data) do
ini_cc:w_value(spawn_name, key, is_vector(value) and utils_data.vector_to_string(value) or value)
end
ini_cc:save()
end
----------------------------------
-- Spawning objects on new game
----------------------------------
---A map of spawned objects, pointing to their object id if object still exists, true if released, nil otherwise
---@type table<string, number|true>
spawned_objects = {}
-- Map of object ids to spawn id (used for cleanup)
id_to_spawn_id = {}
---Generates a list of objects to be spawned, reading from objects.ltx (old format) and spawns.ltx (new format)
---@return {section: string, location: vector, lvid: number, gvid: number, rotation: vector, spawn_id: number, story_id: string|nil}[]
function generate_spawn_list()
local obj_tbl = {}
-- Iterate over objects.ltx, reading every entry for every map (section)
local ini_map_objects = ini_file_ex("plugins\\world_objects\\objects.ltx")
local j = 1
for _, section in pairs(ini_map_objects:get_sections()) do
local n = ini_map_objects.ini:line_count(section)
for i=0,n-1 do
local result, id, value = ini_map_objects.ini:r_line_ex(section,i)
local p = str_explode(value,",")
if (p) then
obj_tbl[j] = {
section = p[1],
location = vector():set(tonumber(p[2]), tonumber(p[3]), tonumber(p[4])),
lvid = tonumber(p[5]),
gvid = tonumber(p[6]),
rotation = vector():set(tonumber(p[7]), tonumber(p[8]), tonumber(p[9])),
spawn_id = id,
}
j = j + 1
end
end
end
-- Iterate over spawns.ltx, reading every entry (section)
local ini_spawns = ini_file_ex("plugins\\world_objects\\spawns.ltx")
for _, section in pairs(ini_spawns:get_sections()) do
local entry = {
section = ini_spawns:r_string_ex(section, "object"),
location = utils_data.string_to_vector(ini_spawns:r_string_ex(section, "position")),
rotation = utils_data.string_to_vector(ini_spawns:r_string_ex(section, "rotation")),
lvid = ini_spawns:r_float_ex(section, "lvid"),
gvid = ini_spawns:r_float_ex(section, "gvid"),
spawn_id = section,
story_id = ini_spawns:r_string_ex(section, "story_id"),
}
table.insert(obj_tbl, entry)
end
return obj_tbl
end
function actor_on_first_update()
-- Spawn world objects
for k, v in pairs(generate_spawn_list()) do
if spawned_objects[v.spawn_id] then goto continue end
local obj_id = placeable_furniture.create_object(v.section, v.location, v.rotation, v.lvid, v.gvid)
if not obj_id then goto continue end
-- Set world_obj flag: Disable pickup
hf_obj_manager.update_data(obj_id, {is_world_obj=true})
-- Track spawned objects
spawned_objects[v.spawn_id] = obj_id
id_to_spawn_id[obj_id] = v.spawn_id
-- Register story_id if it exists
if v.story_id then
story_objects.register(obj_id, v.story_id)
end
::continue::
end
end
function save_state(m_data)
m_data.spawned_objects = spawned_objects
end
function load_state(m_data)
spawned_objects = m_data.spawned_objects or spawned_objects
end
function on_key_press(dik)
if dik ~= bind_record or not record_on_keypress then return end
---@type game_object
local obj = placeable_furniture.get_obj_at_crosshair()
if not obj then return end
local bone_name = obj:bone_name(0)
local angle_hpb = obj:bone_direction(bone_name)
local true_angle = vector():set(angle_hpb.y, angle_hpb.x, angle_hpb.z)
add_obj_prompt(obj:section(), obj:position(), obj:level_vertex_id(), obj:game_vertex_id(), true_angle)
end
function on_option_change(mcm) --new in mcm 1.6.0 mcm passes true to the on_option_change callback
if mcm then
record_on_place = ui_mcm.get("aol_hf/world_obj/flag_record_on_place")
record_on_keypress = ui_mcm.get("aol_hf/world_obj/flag_record_on_keypress")
bind_record = ui_mcm.get("aol_hf/world_obj/bind_record") or bind_record
end
end
-- Open record prompt if MCM option is on
function hf_on_furniture_place(id)
if not record_on_place then return end
local obj = alife_object(id)
if not obj then return end
add_obj_prompt(obj:section_name(), obj.position, obj.m_level_vertex_id, obj.m_game_vertex_id, obj.angle)
end
function server_entity_on_unregister(se_obj,type_name)
local spawn_id = id_to_spawn_id[se_obj.id]
if not spawn_id then return end
spawned_objects[spawn_id] = true
id_to_spawn_id[se_obj.id] = nil
end
function on_game_start()
RegisterScriptCallback("on_option_change",on_option_change)
on_option_change(mcm_keybinds)
RegisterScriptCallback("on_key_press", on_key_press)
RegisterScriptCallback("actor_on_first_update",actor_on_first_update)
RegisterScriptCallback("save_state",save_state)
RegisterScriptCallback("load_state",load_state)
RegisterScriptCallback("hf_on_furniture_place", hf_on_furniture_place)
RegisterScriptCallback("server_entity_on_unregister", server_entity_on_unregister)
end