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

932 lines
28 KiB
Plaintext
Raw Normal View History

2024-03-17 20:18:03 -04:00
gc = game.translate_string
-- util stuff
local function pr(...)
local debug = true
if debug then
printf("placeable_furniture: " .. ...)
end
end
local function print_msg(string_id)
local msg = gc(string_id)
if ui_popup_messages then
ui_popup_messages.GUI:AddMessage(msg)
else
actor_menu.set_msg(1, msg, 3)
end
end
-- keybinds
local mcm_keybinds = ui_mcm and ui_mcm.key_hold
local key_place = bind_to_dik(key_bindings.kUSE)
local key_toggle_collision = DIK_keys.DIK_TAB
local key_toggle_align = DIK_keys.DIK_CAPITAL
local key_toggle_controls = DIK_keys.DIK_HOME
states = {
IDLE=1,
HOLDING=2,
ADV_CTRL=3,
PREVIEW=4
}
local state = states.IDLE
align_states = {
ACTOR = 1,
SURFACE = 2,
}
align_state = align_states.ACTOR
local check_collision = true
local place_coordinates = nil
local place_sound = xr_sound.get_safe_sound_object( "interface\\place_object" )
local item_id = nil
local phy_obj_section = nil
local location_offset = vector():set(0, 0, 0)
local rotation_offset = 0
local base_rot = 0
local base_loc = vector():set(0, 0, 0)
local player_pos = nil
local player_dir = nil
local player_dist = nil
local bbox = nil
local bbox_drawer = aol_bshape.bshape_renderer()
---------------------
-- State Management
---------------------
function reset_offsets()
location_offset = utils_data.string_to_vector(ui_mcm.get("aol_hf/debug/location_offset"))
rotation_offset = 0
end
transition_functors = {
[states.HOLDING] = {
[states.ADV_CTRL] = function ()
player_pos = vector():set(device().cam_pos)
player_dir = vector():set(device().cam_dir)
player_dist = level.get_target_dist()
end
},
[states.ADV_CTRL] = {
[states.HOLDING] = reset_offsets
},
[states.PREVIEW] = {
[states.HOLDING] = reset_offsets
},
[states.IDLE] = {
[states.HOLDING] = reset_offsets
}
}
-- Perform some function when a state transitions occurs
function on_state_transition(old_state, new_state)
local func = transition_functors[old_state] and transition_functors[old_state][new_state]
if func then
func()
end
end
function get_state()
return state
end
function set_state(new_state)
local old_state = state
state = new_state
on_state_transition(old_state, new_state)
end
function is_state(check_state)
return state == check_state
end
function in_placing_state()
return get_state() ~= states.IDLE
end
---------------------
-- Objects and their data
---------------------
---Creates and places an object in the world.
---Also initialises additional data depending on their placeable_type as defined in their section
---@param placeable_section string
---@param location vector
---@param rotation aol_rotation.Quaternion|vector
---@param lvid integer? Level Vertex ID
---@param gvid integer? Game Vertex ID
---@return integer|nil obj.id
function create_object(placeable_section, location, rotation, lvid, gvid)
-- Exit early if placeable_section is not supplied
if not placeable_section then
pr("Could not find associated object with item")
return
end
location = location or vector():set(0,0,0)
rotation = rotation or vector():set(0,0,0)
local obj = alife_create(placeable_section, location, lvid or db.actor:level_vertex_id(), gvid or db.actor:game_vertex_id())
if not obj then return end
-- Rotate object with quaternion or vector
if rotation.w then
obj.angle = rotation:to_euler_angles()
else
obj.angle = vector():set(rotation.x, rotation.y, rotation.z)
end
-- Initialise data store
hf_obj_manager.set_data(obj.id, {})
-- Initialise additional data
local placeable_type = ini_sys:r_string_ex(placeable_section, "placeable_type") or "prop"
local type_functor = hf_furniture_types.get_func(placeable_type)
if type_functor then
type_functor(obj.id)
end
-- Remove flags
local data = utils_stpk.get_physic_data(obj)
local remove_flags = 128
local flag_mask = bit_not(remove_flags)
data.object_flags = bit_and(data.object_flags, flag_mask)
utils_stpk.set_physic_data(data, obj)
return obj.id
end
function transfer_item_data(item_id, obj_id)
if not item_id or not obj_id then return end
-- Copy data from item to obj and delete item data
local hf_data = hf_obj_manager.get_data(item_id)
if hf_data then
hf_obj_manager.update_data(obj_id, hf_data)
hf_obj_manager.delete_data(item_id)
end
-- Update condition if item is online
local item = get_object_by_id(item_id)
if not item then return end
hf_obj_manager.update_data(obj_id, {condition=item:condition()})
end
---------------------
-- Placement System
---------------------
local function actor_on_update()
if not in_placing_state() then return end
local cam_pos = nil
local cam_dir = nil
local dist = nil
if is_state(states.HOLDING) then
cam_pos = device().cam_pos
cam_dir = device().cam_dir
dist = level.get_target_dist()
else
cam_pos = player_pos
cam_dir = player_dir
dist = player_dist
end
-- get position of point that the player is looking at
local pos = vector()
pos:mad(cam_pos, cam_dir,dist)
-- rotate to point towards player + offset
if align_state == align_states.ACTOR then
local rot = cam_dir:getH() + (((base_rot+rotation_offset) * math.pi) / 180)
local q0 = aol_rotation.get_rotation_around(vector():set(0, 1, 0), rot)
bbox.rotation = q0
local angle = cam_dir:getH()
-- Rotate vector about y
local c = math.cos (angle)
local s = math.sin (angle)
local rotated_x = location_offset.x * c - location_offset.z * s
local rotated_z = location_offset.x * s + location_offset.z * c
pos:add(vector():set(rotated_x,
location_offset.y,
rotated_z))
-- automatic alignment to surface
elseif align_state == align_states.SURFACE then
-- Rotation
local rot_z = ((base_rot+rotation_offset) * math.pi) / 180
local u = vector():set(0, 1, 0)
local v = demonized_geometry_ray.get_surface_normal(cam_pos, cam_dir)
if not v then return end
-- rotate from upwards vector to normal vector on surface
local q0 = aol_rotation.get_rotation_between(u, v)
-- rotate to point downwards + offset
local angle_to_downwards = 0
local similarity_to_upwards_axis = v:dotproduct(vector():set(0,1,0))
if similarity_to_upwards_axis > 0.9999 then -- pointing upwards
angle_to_downwards = cam_dir:getH()
elseif similarity_to_upwards_axis < -0.9999 then -- pointing downwards
angle_to_downwards = math.pi - cam_dir:getH()
else
angle_to_downwards = angle_to_downwards + v:getH() + math.pi
end
local q1 = aol_rotation.get_rotation_around(v, angle_to_downwards + rot_z)
-- perform each rotation in succession
local q = aol_rotation.Quaternion():multiply(q0):multiply(q1)
-- Location
local q1_2 = aol_rotation.get_rotation_around(v, angle_to_downwards)
local q_loc = aol_rotation.Quaternion():multiply(q0):multiply(q1_2)
local rotated_loc_offset = q_loc:rotate_vector(location_offset)
bbox.rotation = q
pos:add(rotated_loc_offset)
end
bbox:SetWorldOrigin(vector():set(pos))
-- Update position of vertices in bounding box
bbox:UpdateBBox()
if check_collision then
bbox:CheckForCollisions()
else
bbox.is_colliding = false
end
bbox_drawer:DrawBShapeCollider(bbox)
place_coordinates = pos
end
local direction_keys = {
[key_bindings.kFWD] = true,
[key_bindings.kBACK] = true,
[key_bindings.kL_STRAFE] = true,
[key_bindings.kR_STRAFE] = true,
[key_bindings.kCROUCH] = true,
[key_bindings.kACCEL] = true,
[key_bindings.kWPN_FIRE] = true,
[key_bindings.kWPN_ZOOM] = true,
[key_bindings.kL_LOOKOUT] = true,
[key_bindings.kR_LOOKOUT] = true,
[key_bindings.kJUMP] = true,
[key_bindings.kQUIT] = true,
[7] = true,
[key_bindings.kCONSOLE] = true,
}
---@return game_object|nil
function get_obj_at_crosshair()
if level.get_target_dist() > 5 then return end
local obj = level.get_target_obj()
if not obj then return end
return obj
end
---@return bind_hf_base.hf_binder_wrapper|nil
function get_wrapper_at_crosshair()
local obj = get_obj_at_crosshair()
if not obj then return end
local binder = obj:binded_object()
if not binder then return end
local wrapper = binder.wrapper
if not wrapper then return end
return wrapper
end
local function on_key_hold(dik)
if dik_to_bind(dik) ~= key_bindings.kUSE then return end
if Check_UI("UIRadialMenu") then return end
if not in_placing_state() then
if ui_mcm.key_hold("hf_interact_adv", dik) then
local wrapper = get_wrapper_at_crosshair()
if not wrapper then return end
if Check_UI() then return end
open_interact_gui(wrapper)
end
end
end
local function on_key_press(dik)
if dik_to_bind(dik) == key_bindings.kUSE then
if Check_UI("UIRadialMenu") then return end
if not in_placing_state() then
ui_mcm.simple_press("hf_interact_simple", dik, function ()
local wrapper = get_wrapper_at_crosshair()
if not wrapper then return end
wrapper:use_callback_simple()
end)
end
end
if dik == key_place then
if in_placing_state() then
-- Prevent placement if target pos is too far away
if level.get_target_dist() > 5 and not DEV_DEBUG then
print_msg("st_far_popup")
pr("Cannot place object that far away - max range of 5 units")
return
end
-- Prevent placement if bounding box is colliding with something
if bbox.is_colliding then
print_msg("st_collision_warning")
return
end
local obj_id = create_object(phy_obj_section, place_coordinates, bbox.rotation)
if obj_id then transfer_item_data(item_id, obj_id) end
SendScriptCallback("hf_on_furniture_place", obj_id)
place_sound:play_no_feedback(db.actor, sound_object.s3d, 0, place_coordinates, 1.0, 1.0)
bbox_drawer:Stop()
-- Reset variables
base_rot = 0
phy_obj_section = nil
-- Delete item
if item_id then
alife():release(alife():object(item_id), true)
item_id = nil
end
set_state(states.IDLE)
pr("state=PLACING")
end
elseif dik == key_toggle_collision then
if in_placing_state() then
check_collision = not check_collision
if check_collision then
print_msg("st_enable_collision")
else
print_msg("st_disable_collision")
end
end
elseif dik == key_toggle_align then
if in_placing_state() then
if align_state == align_states.ACTOR then
align_state = align_states.SURFACE
print_msg("st_align_surface")
elseif align_state == align_states.SURFACE then
align_state = align_states.ACTOR
print_msg("st_align_actor")
end
end
elseif dik == key_toggle_controls then
if state == states.IDLE then
return
elseif state == states.HOLDING or
state == states.PREVIEW then
set_state(states.ADV_CTRL)
end
open_gui()
else
local bind = dik_to_bind(dik)
if state ~= states.IDLE and not direction_keys[bind] then
pr("Interrupting placement")
set_state(states.IDLE)
bbox_drawer:Stop()
end
end
end
-- Cancel placement state with ESCAPE key
-- turns out this fires after on_key_press
local function on_before_key_press(key, bind, dis, flags)
if bind == key_bindings.kQUIT and
(is_state(states.HOLDING) or is_state(states.PREVIEW)) then
flags.ret_value = false
set_state(states.IDLE)
bbox_drawer:Stop()
end
end
------
function start_placing_item(section)
if state ~= states.IDLE then
item_id = nil
return
end
print_msg("st_place_popup")
hide_hud_inventory()
db.actor:activate_slot(0)
set_state(states.HOLDING)
local bbox_size_str = ini_sys:r_string_ex(section, "bounding_box_size", "0.5,0.5,0.5")
local bbox_size = str_explode(bbox_size_str,",")
local bbox_origin_str = ini_sys:r_string_ex(section, "bounding_box_origin", "0,0.25,0")
local bbox_origin = str_explode(bbox_origin_str,",")
base_rot = ini_sys:r_float_ex(section, "base_rotation", 0) or 0
base_loc = vector():set(tonumber(bbox_origin[1]), tonumber(bbox_origin[2]), tonumber(bbox_origin[3]))
bbox = hf_bbox.bbox_collider(tonumber(bbox_size[1]), tonumber(bbox_size[2]), tonumber(bbox_size[3]))
bbox:OffsetVertices(base_loc)
local crosshair_vertex = bbox:GetCrosshairVertex()
crosshair_vertex:sub(base_loc)
bbox:SetCrosshairVertex(crosshair_vertex)
phy_obj_section = section
end
function place_item(obj)
return gc("st_place_furniture")
end
function func_place_item(obj)
item_id = obj:id()
print_msg("st_place_popup")
physic_section = ini_sys:r_string_ex(obj:section(), "placeable_section")
if physic_section == nil then
pr("No section of physical object to place")
return
end
start_placing_item(physic_section)
end
------
-- Helper to determine if item is a placeable furniture that requires fuel
-- function is_fueled_furniture(obj)
-- local section = obj and obj:section() or false
-- if section then
-- return SYS_GetParam(0, section, "placeable_type") and SYS_GetParam(0, section, "use_condition")
-- end
-- return false
-- end
-- Monkey patch for adding fuel amount on items // DEPRECATED: using item_device binder instead, which makes these items devices
-- local clr_r = utils_xml.get_color("d_red")
-- local clr_g = utils_xml.get_color("d_green")
-- local clr_y = utils_xml.get_color("yellow")
-- local clr_2 = utils_xml.get_color("ui_gray_1")
-- original_build_desc_header = ui_item.build_desc_header
-- function ui_item.build_desc_header(obj, sec, str)
-- local _str = ""
-- local _str2 = original_build_desc_header(obj, sec, str)
-- -- display power + psu
-- if obj and is_fueled_furniture(obj) then
-- local fuel = math.ceil(obj:condition() * 100)
-- local clr = utils_xml.get_color_con(fuel)
-- _str = clr .. " <20> " .. clr_2 .. gc("st_fuel") .. ": " .. clr .. tostring(fuel) .. "%" .. "\\n \\n" .. clr_2
-- end
-- _str = _str .. _str2
-- return _str
-- end
-------
-- UI
-------
-- Advanced Controls
---@class placeable_furniture.UIAdvancedControls
GUI = nil -- instance, don't touch
function open_gui()
if not DEV_DEBUG then
return
end
hide_hud_inventory()
if (not GUI) then
GUI = UIAdvancedControls()
end
if (GUI) and (not GUI:IsShown()) then
GUI:Reset()
GUI:ShowDialog(true)
Register_UI("UIAdvancedControls","hf_advanced_controls")
end
end
class "UIAdvancedControls" (CUIScriptWnd)
function UIAdvancedControls:__init() super()
self:InitControls()
self:InitCallBacks()
self.states = {
IDLE = 1, -- idle
XZ_DRAG_LOC = 2, -- Horizontal Plane
Y_DRAG_LOC = 3, -- Up/Down
Y_DRAG_ROT = 4, -- Rotate about upward axis
}
self.state = self.states.IDLE
self.snap = false
self.shift = false
self.pos = {x=0, y=0}
self.prev_pos = nil
self.prev_offset = vector():set(location_offset)
self.init = false
end
function UIAdvancedControls:__finalize()
end
function UIAdvancedControls:KeyPress(dik, kb_action)
local funcs = self.key_to_functor[dik]
if funcs then
local func = funcs[kb_action]
if func then func() end
end
end
function UIAdvancedControls:InitControls()
self:SetWndRect(Frect():set(0,0,1024,768))
self:SetAutoDelete(true)
-- Questionable table, but i got tired of if-elses
self.key_to_functor = {
-- XZ Displacement
[DIK_keys.MOUSE_1] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
if self.shift then
self.state = self.state == self.states.IDLE and self.states.Y_DRAG_LOC or self.state
else
self.state = self.state == self.states.IDLE and self.states.XZ_DRAG_LOC or self.state
end
end,
[ui_events.WINDOW_KEY_RELEASED] = function()
self.prev_offset = vector():set(location_offset)
self.state = self.states.IDLE
self.prev_pos = nil
end
},
-- Y Displacement
[DIK_keys.DIK_LSHIFT] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
self.shift = true
end,
[ui_events.WINDOW_KEY_RELEASED] = function()
self.shift = false
end
},
-- Y Rotation
[DIK_keys.MOUSE_2] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
self.state = self.state == self.states.IDLE and self.states.Y_DRAG_ROT or self.state
end,
[ui_events.WINDOW_KEY_RELEASED] = function()
self.prev_rot = rotation_offset
self.state = self.states.IDLE
self.prev_pos = nil
end
},
-- Finer control, adjust at 1/10th speed
[DIK_keys.DIK_LCONTROL] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
self.fine_control = true
end,
[ui_events.WINDOW_KEY_RELEASED] = function()
self.fine_control = false
end
},
-- SNAP
[DIK_keys.DIK_LMENU] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
self.snap = true
end,
[ui_events.WINDOW_KEY_RELEASED] = function()
self.snap = false
end
},
-- Place
[key_place] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
on_key_press(key_place)
self:Close()
end
},
-- Toggle Collision
[key_toggle_collision] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
on_key_press(key_toggle_collision)
end
},
-- Toggle Alignment mode
[key_toggle_align] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
on_key_press(key_toggle_align)
end
},
-- Swap to PREVIEW mode
[key_toggle_controls] = {
[ui_events.WINDOW_KEY_PRESSED] = function()
set_state(states.PREVIEW)
self:Close()
end
}
}
end
function UIAdvancedControls:InitCallBacks()
end
function UIAdvancedControls:Reset()
self.state = self.states.IDLE
self.snap = false
self.pos = {x=0, y=0}
self.prev_pos = nil
self.prev_offset = vector():set(location_offset)
self.location_offset_copy = vector():set(location_offset)
self.prev_rot = rotation_offset
self.prev_rot_copy = rotation_offset
self.init = false
end
function UIAdvancedControls:Update()
CUIScriptWnd.Update(self)
if self.state == self.states.IDLE then return end
if self.prev_pos == nil then
self.prev_pos = GetCursorPosition()
end
local mouse_pos = GetCursorPosition()
local diff_x = (mouse_pos.x - self.prev_pos.x)
local diff_y = -(mouse_pos.y - self.prev_pos.y)
if self.fine_control then
diff_x = diff_x / 10
diff_y = diff_y / 10
end
if self.state == self.states.XZ_DRAG_LOC then
diff_x = diff_x / 200
diff_y = diff_y / 200
if self.snap then
if math.abs(diff_x) > math.abs(diff_y) then
diff_y = 0
else
diff_x = 0
end
end
location_offset = vector():set(self.prev_offset.x+diff_x, self.prev_offset.y, self.prev_offset.z+diff_y)
elseif self.state == self.states.Y_DRAG_LOC then
diff_y = diff_y / 200
location_offset = vector():set(self.prev_offset.x, self.prev_offset.y+diff_y, self.prev_offset.z)
elseif self.state == self.states.Y_DRAG_ROT then
diff_x = diff_x/2
rotation_offset = self.prev_rot + diff_x
if self.snap then
local n = 15
rotation_offset = (rotation_offset % n) > n/2 and rotation_offset + n - rotation_offset%n or rotation_offset - rotation_offset%n
end
end
end
function UIAdvancedControls:OnKeyboard(dik, keyboard_action)
local res = CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
if not self.init then
self.init = true
return
end
if (res == false) then
self:KeyPress(dik, keyboard_action)
if keyboard_action == ui_events.WINDOW_KEY_PRESSED then
if dik == DIK_keys.DIK_ESCAPE then
if self.state == self.states.IDLE then
location_offset = vector():set(self.location_offset_copy)
rotation_offset = self.prev_rot_copy
set_state(states.HOLDING)
self:Close()
else
location_offset = vector():set(self.prev_offset)
rotation_offset = self.prev_rot
self.state = self.states.IDLE
end
end
end
end
return res
end
function UIAdvancedControls:Close()
self:HideDialog()
Unregister_UI("UIAdvancedControls")
end
-- Advanced Interaction Menu
---@class arm.UIRadialMenu
RadialGUI = nil
function create_interact_gui()
local RadialGUI = arm.UIRadialMenu()
-- Pickup
local opt_pickup = arm.OptionData("opt_pickup", function (state)
return arm.get_stateful_texture("ui_hf_radial_icon_pickup", state)
end)
opt_pickup:SetColour(function (state)
return arm.get_stateful_colour(state) -- stateful colour
end) -- stateful colour
-- Text
opt_pickup:SetText({title = gc("st_pickup")})
-- Open UI
local opt_ui = arm.OptionData("opt_use", function (state)
return arm.get_stateful_texture("ui_hf_radial_icon_use", state)
end)
opt_ui:SetColour(function (state)
return arm.get_stateful_colour(state) -- stateful colour
end) -- stateful colour
-- Text
opt_ui:SetText({title = gc("st_open_adv_ui")})
-- Freeze/Unfreeze
local opt_freeze = arm.OptionData("opt_freeze", function(state)
if state == arm.States.HIGHLIGHTED then
return "ui_hf_radial_icon_frozen"
else
return "ui_hf_radial_icon_unfrozen"
end
end)
opt_freeze:SetColour(function (state)
return arm.get_stateful_colour(state) -- stateful colour
end) -- stateful colour
-- Text
opt_freeze:SetText({title = gc("st_freeze")})
-- Upgrade
local opt_upgrade = arm.OptionData("opt_upgrade", "ui_hf_radial_icon_upgrade")
opt_upgrade:SetColour(function (state)
return arm.get_stateful_colour(state) -- stateful colour
end) -- stateful colour
-- Text
opt_upgrade:SetText({title = gc("st_cap_upgrades"),
description = gc("st_not_implemented")})
opt_upgrade:SetState(arm.States.DISABLED)
-- Wire Connections
local opt_connections = arm.OptionData("opt_connections", "ui_hf_radial_icon_connections")
opt_connections:SetColour(function (state)
return arm.get_stateful_colour(state) -- stateful colour
end)
-- Text
opt_connections:SetText({title = gc("st_open_connections"),
description = gc("st_not_implemented")})
opt_connections:SetState(arm.States.DISABLED)
RadialGUI:RegisterCallback("opt_pickup", function ()
local obj = get_obj_at_crosshair()
if not obj then return end
pickup_obj(obj)
end)
RadialGUI:RegisterCallback("opt_use", function ()
local wrapper = get_wrapper_at_crosshair()
if not wrapper then return end
wrapper:use_callback()
end)
RadialGUI:RegisterCallback("opt_freeze", function ()
local wrapper = get_wrapper_at_crosshair()
if not wrapper then return end
wrapper:set_frozen(not wrapper.is_frozen)
if wrapper.is_frozen then
opt_freeze:SetState(arm.States.HIGHLIGHTED)
opt_freeze:SetText({title = gc("st_unfreeze")})
else
opt_freeze:SetState(arm.States.ENABLED)
opt_freeze:SetText({title = gc("st_freeze")})
end
end)
RadialGUI:AddOption(opt_ui)
RadialGUI:AddOption(opt_pickup)
RadialGUI:AddOption(opt_freeze)
RadialGUI:AddOption(opt_upgrade)
RadialGUI:AddOption(opt_connections)
RadialGUI:DrawOptions()
return RadialGUI
end
---@param wrapper bind_hf_base.hf_binder_wrapper
function update_radial_gui(wrapper)
local is_pickupable = wrapper:is_pickupable()
if is_pickupable then
RadialGUI:GetOption("opt_pickup"):SetState(arm.States.ENABLED)
else
RadialGUI:GetOption("opt_pickup"):SetState(arm.States.DISABLED)
end
local type = hf_furniture_types.get_type(wrapper.object)
if type == "prop" or type == nil then
RadialGUI:GetOption("opt_use"):SetState(arm.States.DISABLED)
else
RadialGUI:GetOption("opt_use"):SetState(arm.States.ENABLED)
end
if wrapper.is_frozen then
RadialGUI:GetOption("opt_freeze"):SetState(arm.States.HIGHLIGHTED)
RadialGUI:GetOption("opt_freeze"):SetText({title = gc("st_unfreeze")})
else
RadialGUI:GetOption("opt_freeze"):SetState(arm.States.ENABLED)
RadialGUI:GetOption("opt_freeze"):SetText({title = gc("st_freeze")})
end
end
---@param wrapper bind_hf_base.hf_binder_wrapper
function open_interact_gui(wrapper)
hide_hud_inventory()
if (not RadialGUI) then
RadialGUI = create_interact_gui()
end
if (RadialGUI) and (not RadialGUI:IsShown()) then
update_radial_gui(wrapper)
RadialGUI:ShowDialog(true)
_GUIs_keyfree["UIRadialMenu"] = true
Register_UI("UIRadialMenu","placeable_furniture")
end
end
-------
function on_option_change(mcm) --new in mcm 1.6.0 mcm passes true to the on_option_change callback
if mcm then
key_toggle_collision = ui_mcm.get("aol_hf/controls/bind_collision") or key_toggle_collision
key_toggle_align = ui_mcm.get("aol_hf/controls/bind_alignment") or key_toggle_align
key_toggle_controls = ui_mcm.get("aol_hf/controls/bind_place_mode") or key_toggle_controls
end
key_place = bind_to_dik(key_bindings.kUSE)
end
-- Allow drag n drop of fuel onto furniture items
local function on_item_drag_dropped(obj_b, obj_d, slot_from, slot_to)
-- Check capability
if not (slot_from == EDDListType.iActorBag and (slot_to == EDDListType.iActorBag or slot_to == EDDListType.iActorSlot)) then
return
end
local sec_b = obj_b:section() -- fuel
local sec_d = obj_d:section() -- light source
local req_fuel = ini_sys:r_string_ex(sec_d, "fuel_section")
if req_fuel and (sec_b == req_fuel) then
if sec_b == "batteries_dead" then
alife_create_item("batteries_dead", db.actor, {cond=obj_d:condition()})
obj_d:set_condition(obj_b:condition())
else
utils_item.discharge(obj_b, 1)
obj_d:set_condition(1.0)
end
utils_obj.play_sound("interface\\items\\inv_items_generic_1")
end
end
---@param obj game_object
function pickup_obj(obj)
local wrapper = bind_hf_base.get_wrapper(obj:id())
if not wrapper then return end
if wrapper:is_pickupable() then
wrapper:pickup()
print_msg("Picked up object")
end
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("on_key_hold", on_key_hold)
RegisterScriptCallback("on_before_key_press", on_before_key_press)
RegisterScriptCallback("actor_on_update", actor_on_update)
RegisterScriptCallback("ActorMenu_on_item_drag_drop", on_item_drag_dropped)
end