3848 lines
131 KiB
Plaintext
3848 lines
131 KiB
Plaintext
-- ======================================================================
|
|
--[[ Personal Adjustable Waypoint &
|
|
Pins Recording Intel, Notes, or Terrain
|
|
Yes, I see what I did there, and so do you.
|
|
-- ======================================================================
|
|
Author: Catspaw
|
|
I post gameplay video on my Youtube channel, Catspaw Adventures:
|
|
https://www.youtube.com/channel/UCtG8fiWPUZEzWlkUn60btAw
|
|
|
|
Source: https://www.moddb.com/mods/stalker-anomaly/addons/personal-adjustable-waypoint-for-anomaly-151-152-and-gamma
|
|
Version: 2.0.2
|
|
Updated: 20231204
|
|
|
|
You may alter any part of this mod and do whatever you like with it,
|
|
just give credit where due.
|
|
|
|
Right-click on any visible map point to set/move/remove a waypoint
|
|
or map pins. Map pins can be named, renamed, removed, and given
|
|
custom icons. The waypoint is tracked like a task. Semicolon (default)
|
|
toggles the current or most recent waypoint on/off.
|
|
|
|
To see map points, hold Slash (default, configurable in MCM) to
|
|
enter Cartography Mode. In this mode, all terrain smart points are
|
|
visible. Both the hold and the terrain display are options in MCM.
|
|
|
|
While in Cartography Mode, you can also Ping the map from the context
|
|
menu, creating a temporary grid of visible mapspots that you can use
|
|
for more precise placement.
|
|
|
|
Press Apostrophe (default) to drop a Quick Pin at the player's
|
|
current location.
|
|
|
|
Press Period or Comma (default) to cycle through active pins in the
|
|
current set, or hold Alt while doing this to cycle sets instead.
|
|
|
|
Credits: HarukaSai, RavenAscendant, Ghen Tuong, demonized, and
|
|
many others who've assisted in ways big and small.
|
|
-- ======================================================================
|
|
-- SHORTCUTS, FLAGS, AND SYSTEM STUFF
|
|
(Most of which you probably shouldn't muck with)
|
|
-- ===================================================================--]]
|
|
script_version = "2.0.2"
|
|
release_date = 20231204
|
|
local scriptname = "tasks_placeable_waypoints"
|
|
local logprefix = "<PAW> "
|
|
local language = "eng"
|
|
debuglogs = false -- Controls debug logging if you don't have MCM
|
|
verbose = true
|
|
-- Verbose being on won't do anything if debuglogs isn't also enabled,
|
|
-- but it will ensure that if anyone has to turn on debug logging,
|
|
-- their logs will contain the maximum amount of info automatically.
|
|
-- It's noisy and you can turn it off here if you have to.
|
|
-- ======================================================================
|
|
modxml_map_spots_paw.load_me = function() end
|
|
-- ======================================================================
|
|
function dl(logtext,...)
|
|
-- Debug logging - to disable, set debuglogs to false
|
|
if logtext and debuglogs then
|
|
printf (logprefix..logtext,...)
|
|
end
|
|
end
|
|
|
|
function vl(logtext,...)
|
|
-- Verbose logging - to disable, set either debuglogs or verbose to false
|
|
if logtext and debuglogs and verbose then
|
|
dl("[V] "..logtext,...)
|
|
end
|
|
end
|
|
-- ======================================================================
|
|
mcm_killswitch = false
|
|
-- Enabling the killswitch will hard-cutoff any attempt
|
|
-- to load values from MCM, in case that is causing issues.
|
|
disable_mcm_updates = false
|
|
-- This flag will disable the immediate MCM updates that happen
|
|
-- when changing icons or sets in-game.
|
|
paw_enabled = true -- setting false will killswitch the entire addon
|
|
local icoset_changed = nil
|
|
started = false -- runtime flag
|
|
waypoint_active = false -- runtime flag
|
|
waypoint_canceling = false -- runtime flag
|
|
disable_load_warning = false
|
|
local load_failed = false -- runtime flag
|
|
local welcome_msg_shown = false
|
|
local get_game_time = game.get_game_time
|
|
local get_start_time = level.get_start_time
|
|
local ts = game.translate_string
|
|
local tm = task_manager.get_task_manager()
|
|
local psk = utils_data.parse_string_keys
|
|
local task_info = tm.task_info
|
|
local floor,ceil = math.floor,math.ceil
|
|
local pow,sqrt = math.pow,math.sqrt
|
|
-- ======================================================================
|
|
mousewheel_override = false
|
|
--[[ If set to true, mousewheel_override will skip the autodetection of
|
|
mousewheel support and force it to be on. This may have bad results
|
|
if your binaries don't actually support it.
|
|
|
|
Mousewheel support can also be forced on by setting the following
|
|
MCM config value (not exposed in the menu):
|
|
|
|
pawsys/pawbinds/mwheel_override = true
|
|
--]]
|
|
right_click_override = false
|
|
-- Similarly with right_click_override, but for the on_map_right_click callback
|
|
mwheel_enabled = false -- managed at runtime
|
|
mwheel_notify = true -- news tip on state change
|
|
mwheel_poll_interval = 50 -- interval between checks for mouse wheel input
|
|
mwheel_next_poll = time_global()
|
|
local mwheel_exe_ver = 20230701 -- mouse wheel support added to demonized binaries in this version
|
|
local rclick_exe_ver = 20230922 -- right-click map support added to demonized binaries in this version
|
|
local game_version = ts("ui_st_game_version")
|
|
local gamma_modpack = game_version:find("G.A.M.M.A.")
|
|
mwheel_avail = mousewheel_override or (MODDED_EXES_VERSION and (MODDED_EXES_VERSION >= mwheel_exe_ver))
|
|
right_click_avail = right_click_override or gamma_modpack or (MODDED_EXES_VERSION and (MODDED_EXES_VERSION >= rclick_exe_ver))
|
|
last_clicked_id = nil
|
|
-- ======================================================================
|
|
unsquish_ratio = 1
|
|
local DIK_name = ui_mcm and ui_mcm.dispaly_key or (function() return "" end)-- typo is in the mcm script
|
|
local default_id = 15797 -- WP defaults to Rookie Village if missing for any reason to avoid crash
|
|
local mcm_update_throttle = 3019 -- minimum time between MCM updates of icon/set data
|
|
local next_mcm_update = time_global()
|
|
local wp_proxcheck_interval = 837 -- Time between checks for waypoint proximity
|
|
local next_wp_proxcheck = time_global()
|
|
local garbcollect_interval = 4984 -- Time between pin/sz garbage collection checks
|
|
local next_gc_check = time_global()
|
|
local wp_clear_dist = 5
|
|
local widget_hide_delay = 5000
|
|
local next_pin = time_global()
|
|
local pin_delay = 1000 -- timeout to prevent dupe actions from registering
|
|
local ping_lifetime = 10000
|
|
local ping_grid_size = 10
|
|
local ping_grid_radius = 10
|
|
--local max_dynamic_faves = 5 -- not yet implemented
|
|
local current_active_set = "pins"
|
|
local active_theme = "classicauto"
|
|
local current_set_max = 1
|
|
local current_ico_max = 1
|
|
placed_waypoint = nil
|
|
last_waypoint = nil
|
|
-- ======================================================================
|
|
local toggle_bind = DIK_keys.DIK_SEMICOLON
|
|
local toggle_mod = 2
|
|
local quickpin_bind = DIK_keys.DIK_APOSTROPHE
|
|
local quickpin_mod = 0
|
|
local cart_mode_hold = DIK_keys.DIK_SLASH
|
|
local cart_mode_mod = 0
|
|
local mcm_keybinds = ui_mcm and ui_mcm.key_hold
|
|
cart_mode = false
|
|
cartography_must_hold = false
|
|
cart_shows_smarts = true
|
|
cartmode_unfade = true
|
|
tip_on_icoset_change = false
|
|
allow_non_wp_targets = false
|
|
clear_pin_on_death = true -- pin will be cleared if set on a living thing that dies
|
|
pin_near_fade_dist = 5 -- min distance within which pins will begin to fade out, set to 0 to disable
|
|
pin_far_fade_dist = 0 -- distance beyond which pins will begin to fade out, set to 0 to disable
|
|
pin_far_hide_dist = 10 -- max distance after far_fade at which pins will hide, set to 0 to disable
|
|
-- ======================================================================
|
|
enable_wp_proxcheck = true
|
|
show_pins = true
|
|
local custom_task_info = false
|
|
local icon_cycle_active = false
|
|
local set_cycle_active = false
|
|
widget_enabled = true
|
|
widget_active = true
|
|
hide_widget = true
|
|
widget_use_custom_pos = false
|
|
widget_custom_pos = {x=491,y=670}
|
|
widget_last_used = time_global()
|
|
wp_hud_icon_enabled = true
|
|
pin_hud_icon_default = true
|
|
manual_smart_pins = false
|
|
mark_on_positive_id = true
|
|
reticle_mustzoom = true
|
|
reticle_mode = 2
|
|
autotag_milpda_feature = false -- not implemented yet
|
|
autotag_persistence = false -- if enabled, autotags are cleared on map change or the below timeout value
|
|
autotag_lifetime = 120 * 6 -- time in ms before autotags are cleared (def 2 minutes)
|
|
autotags_time_out = autotag_lifetime > 0
|
|
ret_fade_attack_time = 400
|
|
ret_fade_decay_time = 600
|
|
|
|
reticle_color = {
|
|
["a"] = 150,
|
|
["r"] = 255,
|
|
["g"] = 255,
|
|
["b"] = 255,
|
|
}
|
|
|
|
show_marker_dist = {
|
|
["pins"] = 4,
|
|
["wp"] = 4,
|
|
}
|
|
|
|
show_marker_hint = {
|
|
["pins"] = 2,
|
|
["wp"] = 0, -- not implemented yet
|
|
}
|
|
|
|
-- ======================================================================
|
|
-- STRINGS AND LTX DATA
|
|
-- ======================================================================
|
|
local cartmode = "cartmode"
|
|
local sep = "_"
|
|
local snd_path = "catspaw\\"
|
|
local snd_ping = snd_path.."paw_ping"
|
|
local snd_cycle_blip = snd_path.."paw_blip"
|
|
local snd_tag_target = snd_path.."paw_blip"
|
|
local use_ping_snd = true
|
|
local use_ui_snd = true
|
|
local add_mapspot_functor = scriptname..".func_add_mapspot"
|
|
local ren_mapspot_functor = scriptname..".func_ren_mapspot"
|
|
local ren_wp_functor = scriptname..".func_ren_waypoint"
|
|
local task_id = "task_placeable_waypoint"
|
|
local pawmenu_path = "ui_mcm_pawsys_pawmenu_"
|
|
-- Don't change any of these icon definitions. If you want to
|
|
-- override PAW's pin icons with any of yours, use MCM or
|
|
-- see below for how to add your own, it's easy.
|
|
current_body_icon = nil
|
|
body_icon_mode = "off"
|
|
patch_res = "badge"
|
|
local custom_pin_icon = false
|
|
local default_mapspot = "paw_pin_redpush32"
|
|
local smart_terrain_icon = "paw_pin_magnifier32"
|
|
local icon_pingspot = "paw_ping_alpha50"
|
|
waypoint_mapspot = "paw_task_default"
|
|
map_pin_icon = default_mapspot
|
|
force_icon_override = nil
|
|
-- If force_icon_override is set to anything, PAW will try to use it
|
|
-- for pins instead of what it normally would.
|
|
-- This is purely a debugging tool. There are better ways to use your own
|
|
-- custom icons.
|
|
-- ======================================================================
|
|
icons_ini = ini_file_ex("scripts\\paw\\icons.ltx")
|
|
icon_sets_ini = ini_file_ex("scripts\\paw\\icon_sets.ltx")
|
|
actions_ini = ini_file_ex("scripts\\paw\\menu_actions.ltx")
|
|
task_ini = ini_file_ex("scripts\\paw\\task_config.ltx")
|
|
clsids_ini = ini_file_ex("scripts\\paw\\valid_clsids.ltx")
|
|
icon_ltx = icons_ini:collect_section("icons")
|
|
iconset_ltx = icon_sets_ini:get_sections(true)
|
|
actions_ltx = actions_ini:get_sections(true)
|
|
clsids_ltx = clsids_ini:collect_section("valid_clsids")
|
|
task_cfg = task_ini:collect_section("task_config")
|
|
custom_name = (task_cfg and task_cfg.name)
|
|
custom_desc = (task_cfg and task_cfg.desc)
|
|
icons = icon_ltx
|
|
curr_menu_options = {}
|
|
icon_sets = {}
|
|
action_codes = {}
|
|
action = {}
|
|
texture_data = {}
|
|
icon_index = {}
|
|
set_index = {}
|
|
valid_clsids = {}
|
|
local script_zones = {}
|
|
local pings = {}
|
|
local pawdata = {
|
|
pins = {},
|
|
--dynamic_faves = {},
|
|
curr_set_ind = 1,
|
|
curr_ico_ind = 1,
|
|
curr_set_name = "pins",
|
|
curr_ico_name = default_mapspot,
|
|
}
|
|
pawdata.smart_pins = {
|
|
["human_f"] = {
|
|
pin = "chevron_friendly",
|
|
enabled = false,
|
|
},
|
|
["human_n"] = {
|
|
pin = "chevron_neutral",
|
|
enabled = false,
|
|
},
|
|
["human_e"] = {
|
|
pin = "chevron_enemy",
|
|
enabled = true,
|
|
},
|
|
["monster"] = {
|
|
pin = "chevron_enemy",
|
|
enabled = true,
|
|
},
|
|
["stash"] = {
|
|
pin = "bwhr_loot",
|
|
enabled = false,
|
|
},
|
|
}
|
|
pawdata.npc_ident = {
|
|
delay_id = true,
|
|
id_bodies = false,
|
|
id_speed = 0.3,
|
|
lenience = 0.99,
|
|
tick_speed = 200,
|
|
progress = {},
|
|
}
|
|
npc_ident = pawdata.npc_ident
|
|
smart_pins = pawdata.smart_pins
|
|
pins = pawdata.pins
|
|
dynamic_faves = pawdata.dynamic_faves
|
|
|
|
-- ======================================================================
|
|
pda_defs = {
|
|
-- By default, all PDAs support waypointing
|
|
["device_pda_1"] = {
|
|
show_w = true,
|
|
},
|
|
["device_pda_2"] = {
|
|
show_w = true,
|
|
},
|
|
["device_pda_3"] = {
|
|
show_w = true,
|
|
},
|
|
["device_pda_milspec"] = {
|
|
show_w = true,
|
|
},
|
|
-- If you use an addon with an unsupported PDA section, add it here
|
|
-- ["device_pda_added_by_your_mod"] = {
|
|
-- show_w = false,
|
|
-- },
|
|
}
|
|
|
|
managed_factions = {
|
|
-- editing this may cause crashes or other unexpected results
|
|
["army"] = true,
|
|
["bandit"] = true,
|
|
["csky"] = true,
|
|
["dolg"] = true,
|
|
["ecolog"] = true,
|
|
["freedom"] = true,
|
|
["killer"] = true,
|
|
["monolith"] = true,
|
|
["stalker"] = true,
|
|
["greh"] = true,
|
|
["isg"] = true,
|
|
["renegade"] = true,
|
|
}
|
|
|
|
managed_options = {
|
|
-- editing this may cause context menus to behave oddly
|
|
["mping"] = true,
|
|
["wp_set"] = true,
|
|
["wp_mov"] = true,
|
|
["wp_del"] = true,
|
|
-- ["wp_ren"] = true,
|
|
["waypoint_rename"] = true,
|
|
["waypoint_redesc"] = true,
|
|
["hud_vis_on"] = true,
|
|
["hud_vis_off"] = true,
|
|
["show_all_pins"] = true,
|
|
["hide_all_pins"] = true,
|
|
["pn_add"] = true,
|
|
["pn_del"] = true,
|
|
["pn_ren"] = true,
|
|
["pn_clr"] = true,
|
|
["lock_pin"] = true,
|
|
["unlock_pin"] = true,
|
|
["cm_dbg"] = true,
|
|
}
|
|
|
|
hud_themes = {
|
|
["classicauto"] = {
|
|
name = "classicauto",
|
|
node = "pawhudind",
|
|
style = "full",
|
|
tex = "ui_paw_hud_indicator_classic",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=890,y=620},
|
|
w = 136,
|
|
h = 75,
|
|
pda_thm = "vertright",
|
|
},
|
|
["classic"] = {
|
|
name = "classic",
|
|
node = "pawhudind",
|
|
style = "full",
|
|
tex = "ui_paw_hud_indicator_classic",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=890,y=620},
|
|
w = 136,
|
|
h = 75,
|
|
},
|
|
["vertright"] = {
|
|
name = "vertright",
|
|
node = "pawhudind_vertright",
|
|
style = "minimal",
|
|
tex = "ui_paw_hud_indicator_vertright",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=922,y=440},
|
|
w = 100,
|
|
h = 154,
|
|
},
|
|
["vertleft"] = {
|
|
name = "vertleft",
|
|
node = "pawhudind_vertleft",
|
|
style = "minimal",
|
|
tex = "ui_paw_hud_indicator_vertleft",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=4,y=570},
|
|
w = 100,
|
|
h = 154,
|
|
},
|
|
["gamma_right"] = {
|
|
name = "gamma_right",
|
|
node = "pawhudind_gamma_right",
|
|
style = "full",
|
|
tex = "ui_paw_hud_indicator_gamma_right",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=888,y=440},
|
|
w = 130,
|
|
h = 150,
|
|
},
|
|
["gamma_left"] = {
|
|
name = "gamma_left",
|
|
node = "pawhudind_gamma_left",
|
|
style = "full",
|
|
tex = "ui_paw_hud_indicator_gamma_left",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=4,y=440},
|
|
w = 130,
|
|
h = 150,
|
|
},
|
|
["minimal_h"] = {
|
|
name = "minimal_h",
|
|
node = "pawhudind_minimal_h",
|
|
style = "minimal",
|
|
tex = "ui_paw_hud_indicator_minimal_h",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=924,y=645},
|
|
w = 94,
|
|
h = 52,
|
|
},
|
|
["minimal_v"] = {
|
|
name = "minimal_v",
|
|
node = "pawhudind_minimal_v",
|
|
style = "minimal",
|
|
tex = "ui_paw_hud_indicator_minimal_v",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=924,y=440},
|
|
w = 92,
|
|
h = 112,
|
|
},
|
|
["minicom"] = {
|
|
name = "minicom",
|
|
node = "pawhudind_minicom",
|
|
style = "compact",
|
|
tex = "ui_paw_hud_indicator_minicom",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=820,y=725},
|
|
w = 38,
|
|
h = 37,
|
|
},
|
|
["compact_noui"] = {
|
|
name = "compact_noui",
|
|
node = "pawhudind_minicom",
|
|
style = "compact",
|
|
file = "paw_hud_indicator.xml",
|
|
pos = {x=820,y=725},
|
|
w = 32,
|
|
h = 37,
|
|
pre_tex = "ui_paw_hud_indicator_minicom",
|
|
},
|
|
}
|
|
|
|
|
|
colors = {
|
|
dimmed = GetARGB(100, 255, 255, 255),
|
|
active = GetARGB(255, 255, 255, 255),
|
|
}
|
|
|
|
text_colors = {
|
|
["clr_255"] = "%" .. "%c[255,255,255,255]",
|
|
["clr_red"] = "%" .. "%c[255,255,0,0]",
|
|
["clr_grn"] = "%" .. "%c[255,0,255,0]",
|
|
["clr_blu"] = "%" .. "%c[255,0,0,255]",
|
|
["clr_lbl"] = "%" .. "%c[255,0,200,220]",
|
|
["clr_yel"] = "%" .. "%c[255,250,218,94]",
|
|
["clr_wht"] = "%" .. "%c[255,220,220,220]",
|
|
["clr_prp"] = "%" .. "%c[255,138,43,226]",
|
|
["clr_blk"] = "%" .. "%c[255,0,0,0]",
|
|
}
|
|
|
|
|
|
local keybinds = {
|
|
["cartmode"] = {
|
|
enabled = function() return paw_enabled end,
|
|
hold = cartography_must_hold,
|
|
bind = DIK_keys.DIK_SLASH,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_cartmode",
|
|
action = function(tf)
|
|
if tf == nil then
|
|
tf = not cart_mode
|
|
end
|
|
cartography_mode(tf)
|
|
end,
|
|
},
|
|
|
|
["wp_target_obj"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_SEMICOLON,
|
|
mod = 3,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_wp_target",
|
|
action = function() wp_target_obj() end,
|
|
},
|
|
["pin_target_obj"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_APOSTROPHE,
|
|
mod = 3,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_pin_target",
|
|
action = function() pin_target_obj(nil,nil,nil,manual_smart_pins) end,
|
|
},
|
|
["quickpin"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_APOSTROPHE,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_quickpin",
|
|
action = function() drop_quick_pin() end,
|
|
},
|
|
["wptoggle"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_SEMICOLON,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_wptoggle",
|
|
action = function() toggle_waypoint() end,
|
|
},
|
|
["set_next"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_PERIOD,
|
|
mod = 3,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_set_next",
|
|
action = function() cycle_items(1,"set",tip_on_icoset_change) end,
|
|
},
|
|
["set_prev"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_COMMA,
|
|
mod = 3,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_set_prev",
|
|
action = function() cycle_items(-1,"set",tip_on_icoset_change) end,
|
|
},
|
|
["ico_next"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_PERIOD,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_ico_next",
|
|
action = function() cycle_items(1,"icon",tip_on_icoset_change) end,
|
|
},
|
|
["ico_prev"] = {
|
|
enabled = function() return paw_enabled end,
|
|
bind = DIK_keys.DIK_COMMA,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_ico_prev",
|
|
action = function() cycle_items(-1,"icon",tip_on_icoset_change) end,
|
|
},
|
|
["ico_scroll"] = {
|
|
enabled = function() return paw_enabled and mwheel_enabled end,
|
|
bind = DIK_keys.DIK_Z,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_ico_scroll",
|
|
mod = 3,
|
|
hold = true,
|
|
action = function(tf) icon_cycle(true,tf) end,
|
|
},
|
|
["set_scroll"] = {
|
|
enabled = function() return paw_enabled and mwheel_enabled end,
|
|
bind = DIK_keys.DIK_Z,
|
|
name = "ui_mcm_pawsys_pawbinds_bind_set_scroll",
|
|
mod = 2,
|
|
hold = true,
|
|
action = function(tf) set_cycle(true,tf) end,
|
|
},
|
|
}
|
|
|
|
-- ======================================================================
|
|
-- GENERAL UTILITY FUNCTIONS
|
|
-- ======================================================================
|
|
|
|
function exec(str,...)
|
|
if str then
|
|
str = str_explode(str,"%.")
|
|
if str[1] and str[2] and _G[ str[1] ] and _G[ str[1] ][ str[2] ] then
|
|
_G[ str[1] ][ str[2] ](...)
|
|
else
|
|
dl("Could not exec function %s", str)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function delay_exec_of(func,secs,...)
|
|
if not func then return end
|
|
secs = secs or 0
|
|
CreateTimeEvent("pawdelay","paw"..func..tostring(time_global()),secs,func,...)
|
|
end
|
|
|
|
|
|
function dotip(tiptext,dur,src,beep,icon,snd)
|
|
vl("Tip call received: dur %s | src \"%s\" | beep %s\n\"%s\"",dur,src,beep,tiptext)
|
|
if tiptext == nil then return end
|
|
db.actor:give_game_news(src or "PAW System", tiptext, icon or "ui_inGame2_Mesta_evakuatsii", 0, dur or 5000)
|
|
|
|
if beep then
|
|
xr_sound.set_sound_play(AC_ID, snd or "pda_tips")
|
|
end
|
|
end
|
|
|
|
function get_time_elapsed()
|
|
return math.floor(get_game_time():diffSec(get_start_time()))
|
|
end
|
|
|
|
function round2(n)
|
|
return (math.floor(n * 100) / 100)
|
|
end
|
|
|
|
|
|
function roll(val,min,max)
|
|
if not (val and min and max) then return end
|
|
if val > max then
|
|
return min
|
|
elseif val < min then
|
|
return max
|
|
else
|
|
return val
|
|
end
|
|
end
|
|
|
|
function lerp(a, b, f)
|
|
if a and b and f then
|
|
return a + f * (b - a)
|
|
else
|
|
return a or b or 0
|
|
end
|
|
end
|
|
|
|
function paw_enabled_check()
|
|
if not paw_enabled then
|
|
actor_menu.set_msg(1,game.translate_string("st_paw_system_disabled"),5)
|
|
end
|
|
return paw_enabled
|
|
end
|
|
|
|
function valid_bind(kb)
|
|
return (kb ~= nil) and (kb ~= "") and (kb ~= "<!!!>") and (kb ~= -1)
|
|
end
|
|
|
|
|
|
function bindtext(kb,km)
|
|
local kbt = ""
|
|
local kmt = ""
|
|
local mt = ""
|
|
local vbkb = valid_bind(kb)
|
|
local vbkm = km and km > 0
|
|
if vbkb then
|
|
kbt = DIK_name(kb)
|
|
end
|
|
if vbkm then
|
|
if km and km < 29 then
|
|
km = ((km == 1) and 42) or ((km == 2) and 29) or ((km == 3) and 56)
|
|
end
|
|
if km then
|
|
kmt = DIK_name(km)
|
|
end
|
|
end
|
|
|
|
if vbkb and vbkm then
|
|
mt = "+"
|
|
elseif not (vbkb or vbkm) then
|
|
kmt = "[UNBOUND]"
|
|
mt = ""
|
|
kbt = ""
|
|
end
|
|
|
|
return string.format("%s%s%s",kmt,mt,kbt)
|
|
end
|
|
|
|
|
|
-- ======================================================================
|
|
function safeid(obj)
|
|
local id = obj and obj.id
|
|
if not id and obj then return end
|
|
if type(id) ~= "number" then id = obj:id() end
|
|
return id
|
|
end
|
|
|
|
function safename(id)
|
|
if not (id and (id > 0)) then return end
|
|
local text = ts("st_paw_unknown")
|
|
local se_obj = alife_object(id)
|
|
if not se_obj then return text end
|
|
local name = se_obj:name() or text
|
|
local cls = se_obj:clsid()
|
|
|
|
if pins[id] then
|
|
-- If there's a pin for this ID, use its label above all else
|
|
text = pins[id].text or pins[id].name
|
|
vl("%s (%s) is a pin: %s",name,id,text)
|
|
elseif (cls == clsid.script_zone) then
|
|
text = ts("st_paw_pin_default_name")
|
|
vl("%s (%s) is a script zone: %s",name,id,text)
|
|
elseif (cls == clsid.script_restr) then
|
|
local _,_,hint = txr_routes.get_route_info(name)
|
|
if hint then
|
|
text = hint and ts(hint) or text
|
|
else
|
|
text = ts(name)
|
|
end
|
|
vl("%s (%s) is a level transition: %s",name,id,text)
|
|
elseif (cls == clsid.smart_terrain) then
|
|
text = ts("st_"..name.."_name"):gsub("%."," -")
|
|
vl("%s (%s) is a smart terrain: %s",name,id,text)
|
|
elseif (cls == clsid.online_offline_group_s) then
|
|
local comm = se_obj.player_id
|
|
local sq = ts("st_paw_squad")
|
|
if managed_factions[comm] then
|
|
text = ts(comm)
|
|
end
|
|
text = text.." "..sq
|
|
if debuglogs then
|
|
text = text..": "..name
|
|
end
|
|
vl("%s (%s) is NPC squad with faction %s: %s",name,id,comm,text)
|
|
elseif IsInvbox(nil,cls) then
|
|
local locst = "st_"..name.."_name"
|
|
text = ts(locst)
|
|
if text == locst then
|
|
dl("No localization found for stash %s",locst)
|
|
text = ts("st_paw_unknown").." "..ts("st_paw_stash")
|
|
if debuglogs then
|
|
text = text..": "..name
|
|
end
|
|
end
|
|
vl("%s (%s) is a stash marker: %s",name,id,text)
|
|
elseif IsStalker(nil,cls) then
|
|
text = se_obj:character_name()
|
|
vl("%s (%s) is a stalker: %s",name,id,text)
|
|
elseif IsMonster(nil,cls) then
|
|
local obj = get_object_by_id(id)
|
|
local section = obj and obj:section()
|
|
if not section then
|
|
return text
|
|
end
|
|
--[[
|
|
Hack adapted from ui_enemy_health.script
|
|
This logic acts as a translation layer for
|
|
any monster kind/species that doesn't line
|
|
up with the name of its encyclopedia entry
|
|
--]]
|
|
local special_cases = {
|
|
dog = "blind_dog",
|
|
bird = "crow",
|
|
giant = "pseudogiant",
|
|
SM_KARLIK = "karlik",
|
|
SM_LURKER = "lurker",
|
|
SM_POLTER_G = "poltergeist",
|
|
SM_PYRO_G = "pyrogeist",
|
|
SM_PSEUDO_G = "pseudogeist",
|
|
SM_PSYSUCKER = "psysucker",
|
|
}
|
|
if string.find(section,'rotan') then
|
|
text = "rat"
|
|
elseif string.find(section,'psy_dog') then
|
|
text = "psydog"
|
|
else
|
|
local what = ini_sys:r_string_ex(section,"kind") or ini_sys:r_string_ex(section,"species") or nil
|
|
text = special_cases[what] or what
|
|
end
|
|
--text = string.lower(ts("encyclopedia_mutants_"..text))
|
|
text = ts("encyclopedia_mutants_"..text)
|
|
vl("%s (%s) is a creature: %s",name,id,text)
|
|
else
|
|
text = ts(name)
|
|
if text == name then
|
|
text = ts(name.."_name")
|
|
if text == name.."_name" then
|
|
text = name
|
|
dl("No localization or other name found for object %s (%s)",name,id)
|
|
end
|
|
end
|
|
end
|
|
dl("safename returns %s for %s",text,name)
|
|
return text
|
|
end
|
|
|
|
|
|
function valid_pda()
|
|
local dev = db.actor:item_in_slot(8)
|
|
local sec = dev and dev:section()
|
|
if dev and pda_defs[sec] then
|
|
if pda_defs[sec].show_w then return true end
|
|
elseif item_device.device_npc_pda[sec] then
|
|
local text = ts("st_paw_npc_pda_equipped")
|
|
dotip(text)
|
|
else
|
|
dl("WARNING: Equipped PDA %s not found in pda_defs - if this is a valid player PDA, add to that table to enable support",sec)
|
|
end
|
|
return false
|
|
end
|
|
|
|
|
|
function blacklisted_object(id)
|
|
if not (id and (id > 0)) then return true end
|
|
|
|
local se_obj = alife_object(id)
|
|
|
|
if not se_obj then return true end
|
|
|
|
local cls = se_obj:clsid()
|
|
if (cls == clsid.poltergeist_s) or
|
|
(cls == clsid.psy_dog_phantom_s) then
|
|
return true end
|
|
|
|
end
|
|
|
|
function valid_waypoint_target(se_obj)
|
|
if not se_obj then return end
|
|
if blacklisted_object(se_obj.id) then return end
|
|
-- can add other smart types to this logic later if needed
|
|
local clsid = se_obj:clsid()
|
|
local valid = (valid_clsids[clsid] ~= nil) or
|
|
IsStalker(se_obj) or
|
|
IsMonster(se_obj) or
|
|
isLc(se_obj)
|
|
return valid
|
|
end
|
|
|
|
function feature_valid_in_mode(mode)
|
|
-- -1: debug mode only
|
|
-- 0: disabled
|
|
-- 1: enabled in normal view only
|
|
-- 2: enabled in cartography mode only
|
|
-- 4: enabled in both
|
|
return ((mode < 0) and debuglogs) or
|
|
((mode == 1) and not cart_mode) or
|
|
((mode >= 2) and cart_mode) or
|
|
(mode >= 4)
|
|
end
|
|
|
|
|
|
function play_sound_for_actor(effect)
|
|
local snd = xr_sound.get_safe_sound_object(effect)
|
|
snd:play(db.actor, 0, sound_object.s2d)
|
|
end
|
|
|
|
|
|
function add_mapspot(text,id,icon)
|
|
if not id then return end
|
|
icon = icon or default_mapspot
|
|
vl("Adding mapspot %s for id %s with icon %s",text,id,icon)
|
|
level.map_add_object_spot(id,icon,text)
|
|
end
|
|
|
|
|
|
function remove_mapspot(id,icon)
|
|
if not (id and icon) then return end
|
|
vl("Trying to remove mapspot for id %s with icon %s",id,icon)
|
|
level.map_remove_object_spot(id,icon)
|
|
level.map_remove_object_spot(id,icon)
|
|
return true
|
|
end
|
|
|
|
--[[
|
|
-- this isn't working yet, don't enable
|
|
function rotate_dynamic_favorites(icon)
|
|
if not icon then return end
|
|
|
|
local mdf = tonumber(max_dynamic_faves) or 0
|
|
local faves = 0
|
|
if (mdf and (mdf == 0)) then return end
|
|
vl("rotate_dynamic_favorites called with new mapspot %s",icon)
|
|
if dynamic_faves and (type(dynamic_faves) == "table") then
|
|
faves = #dynamic_faves or 0
|
|
if faves > 1 then
|
|
for i = 1,faves do
|
|
if (faves[i] == icon) then
|
|
vl("%s already in favorites, ignoring")
|
|
return
|
|
|
|
|
|
end
|
|
if faves < mdf then
|
|
faves = faves + 1
|
|
elseif (mdf > 1) and (faves >= mdf) then
|
|
for i = 2,faves do
|
|
vl("%s was in position %s, shuffling down to %s",dynamic_faves[i],i,i-1)
|
|
dynamic_faves[i - 1] = dynamic_faves[i]
|
|
end
|
|
end
|
|
else
|
|
dynamic_faves = {}
|
|
end
|
|
dynamic_faves[faves] = icon
|
|
vl("%s added to top of dynamic_faves",icon)
|
|
end
|
|
--]]
|
|
|
|
function func_add_mapspot(text,args)
|
|
local id = args.id
|
|
local icon = args.icon or map_pin_icon
|
|
if text == "" or text == nil then
|
|
set_pin_persistence(id,false)
|
|
set_pingspot_persistence(id,false)
|
|
pins[id] = nil
|
|
vl("Empty text input returned for pin %s, removing",id)
|
|
return end
|
|
vl("func_add_mapspot called for id %s | %s | %s",id,icon,text)
|
|
pins[id].text = text
|
|
add_mapspot(text,id,icon)
|
|
end
|
|
|
|
function func_ren_mapspot(text,args)
|
|
local id = args.id
|
|
local icon = map_pin_icon
|
|
local old_icon = args.icon
|
|
if text == "" or text == nil then
|
|
vl("Empty text input returned for pin %s, making no change",id)
|
|
text = pins[id].text
|
|
icon = old_icon
|
|
end
|
|
pins[id].text = text
|
|
vl("func_ren_mapspot called for id %s | %s | %s",id,icon,text)
|
|
remove_mapspot(id,old_icon)
|
|
add_mapspot(text,id,old_icon)
|
|
end
|
|
|
|
function func_ren_waypoint(text,args)
|
|
if text == "" then text = nil end
|
|
local field = args.field
|
|
if field == "name" then
|
|
custom_name = text
|
|
elseif field == "desc" then
|
|
custom_desc = text
|
|
end
|
|
end
|
|
|
|
|
|
function pins_exist()
|
|
return not is_empty(pins)
|
|
end
|
|
|
|
|
|
function waypoint_task_cleanup()
|
|
end
|
|
|
|
|
|
function cancel_task()
|
|
local id = placed_waypoint and placed_waypoint.id
|
|
tm.task_info[task_id] = nil
|
|
remove_mapspot(id, waypoint_mapspot)
|
|
_ = set_pingspot_persistence(id,false)
|
|
waypoint_active = false
|
|
placed_waypoint = nil
|
|
_ = dl("Waypoint task cancellation complete for %s",id)
|
|
waypoint_canceling = false
|
|
return true
|
|
end
|
|
|
|
|
|
function end_waypoint_task()
|
|
waypoint_canceling = true
|
|
return cancel_task()
|
|
end
|
|
|
|
|
|
function set_current_waypoint(se_obj)
|
|
if not se_obj then return end
|
|
local id = se_obj.id
|
|
set_pingspot_persistence(id)
|
|
if waypoint_active then
|
|
last_waypoint = placed_waypoint
|
|
set_pingspot_persistence(id,false)
|
|
end
|
|
placed_waypoint = {
|
|
id = id,
|
|
name = safename(id),
|
|
}
|
|
waypoint_active = true
|
|
waypoint_canceling = false
|
|
end
|
|
|
|
function valid_travel_target(id)
|
|
-- To enable interaction with the Fair Fast Travel
|
|
-- system addon, allowing fast travel to pins, but
|
|
-- only those that we know are within the playable
|
|
-- area--ones spawned at a spot where the player was
|
|
-- standing at the time.
|
|
local pin = pins and pins[id]
|
|
local valid = pin and pin.quick
|
|
vl("valid_travel_target | id %s is pin: %s | is quick pin %s",pin,valid)
|
|
return valid
|
|
end
|
|
|
|
function init_new_pin(id,name,text,icon)
|
|
if id and not pins[id] then
|
|
icon = icon or default_mapspot
|
|
set_pingspot_persistence(id)
|
|
pins[id] = {
|
|
id = id,
|
|
name = name or ts("st_paw_pin_default_name"),
|
|
text = text or name,
|
|
icon = icon,
|
|
hud = false
|
|
}
|
|
--rotate_dynamic_favorites(icon)
|
|
vl("New pin initialized: %s (%s) | %s | %s",pins[id].name,id,icon,text)
|
|
end
|
|
end
|
|
|
|
|
|
function register_script_zone(...)
|
|
local se_obj = alife_create("script_zone",...)
|
|
if not se_obj then return end
|
|
local id = se_obj.id
|
|
local now = time_global()
|
|
script_zones[id] = {
|
|
id = se_obj.id,
|
|
pos = se_obj.position,
|
|
created = now,
|
|
cleanup = now + ping_lifetime,
|
|
}
|
|
vl("Script zone %s spawned for ping spot",id)
|
|
return se_obj
|
|
end
|
|
|
|
|
|
function deregister_script_zone(id)
|
|
if not id then return end
|
|
local se_obj = alife_object(id)
|
|
if not se_obj then return end
|
|
alife_release(se_obj)
|
|
script_zones[id] = nil
|
|
vl("Script zone %s released",id)
|
|
end
|
|
|
|
|
|
function generate_scripted_mapspot_at(pos,lv,gv)
|
|
if not (pos and lv and gv) then return end
|
|
local sz = register_script_zone(pos,gv,lv)
|
|
if not sz then return end
|
|
return sz.id
|
|
end
|
|
|
|
|
|
function generate_scripted_mapspot_on(obj)
|
|
if not (obj and obj.id) then return end
|
|
local sz = register_script_zone(obj)
|
|
if not sz then return end
|
|
return sz.id
|
|
end
|
|
|
|
|
|
function spawn_pingspot(pid,pos,lv,gv)
|
|
if not (pid and pos and lv and gv) then return end
|
|
local sz = register_script_zone(pos,gv,lv)
|
|
if not sz then return end
|
|
|
|
local text = ts("st_paw_pingspot")
|
|
local id = sz.id
|
|
pings[id] = script_zones[id]
|
|
pings[id].pid = pid
|
|
add_mapspot(text,id,icon_pingspot)
|
|
-- vl("Spawned temporary pingspot at %s,%s with id %s",pos.x,pos.z,id)
|
|
return id
|
|
end
|
|
|
|
|
|
function despawn_pingspot(id)
|
|
-- vl("despawn_pingspot(%s): deregistering script zone and nulling ping record",id)
|
|
deregister_script_zone(id)
|
|
pings[id] = nil
|
|
end
|
|
|
|
|
|
function script_zone_cleanup()
|
|
local now = get_time_elapsed()
|
|
for k,v in pairs(script_zones) do
|
|
if v.cleanup and (v.cleanup < now) then
|
|
deregister_script_zone(k)
|
|
end
|
|
end
|
|
dl("script_zone_cleanup completed")
|
|
return true
|
|
end
|
|
|
|
function temp_pin_cleanup(wipe_all)
|
|
local now = get_time_elapsed()
|
|
for k,v in pairs(pins) do
|
|
if v.cleanup then
|
|
local expired = autotags_time_out and (v.cleanup < now)
|
|
if expired or wipe_all then
|
|
do_waypoint("pn_del",nil,nil,{syscall=true,id=k})
|
|
end
|
|
end
|
|
end
|
|
dl("temp_pin_cleanup completed")
|
|
return true
|
|
end
|
|
|
|
function set_pin_persistence(id,onoff,lifetime)
|
|
if not (id and (id > 0)) then return end
|
|
if not pins[id] then return end
|
|
if onoff or (onoff == nil) then
|
|
pins[id].cleanup = nil
|
|
dl("Pin %s given persistence, it will not be subject to cleanup",id)
|
|
else
|
|
local now = get_time_elapsed()
|
|
pins[id].cleanup = now + (lifetime or autotag_lifetime or 0)
|
|
dl("Pin %s flagged as temporary, it will be subject to cleanup at %s",id,pins[id].cleanup)
|
|
end
|
|
return true
|
|
end
|
|
|
|
function set_pingspot_persistence(id,onoff)
|
|
if not (id and script_zones[id]) then return end
|
|
if onoff or (onoff == nil) then
|
|
pings[id] = nil
|
|
script_zones[id].cleanup = nil
|
|
dl("Temporary pingspot %s given persistence, it will not be subject to cleanup",id)
|
|
else
|
|
script_zones[id].cleanup = get_time_elapsed()
|
|
dl("Persistent pingspot %s flagged as unused, it will be subject to cleanup",id)
|
|
end
|
|
return true
|
|
end
|
|
|
|
function ping_area_around(obj)
|
|
if not obj then return end
|
|
local now = time_global()
|
|
local pid = tostring(now)
|
|
local span = ping_grid_radius or 10 -- radius of grid in squares
|
|
local grid = ping_grid_size or 10 -- dimension of grid squares in game units
|
|
local rad = span * grid -- actual ping radius in game units
|
|
local anch_id = obj.id
|
|
local anch_pos = obj.position
|
|
local ax = anch_pos.x
|
|
local ay = anch_pos.y
|
|
local az = anch_pos.z
|
|
local gv = obj.m_game_vertex_id
|
|
local lv = game_graph():vertex(gv):level_id()
|
|
|
|
for z = (az-(span*grid)),(az+(span*grid)),grid do
|
|
for x = (ax-(span*grid)),(ax+(span*grid)),grid do
|
|
local pos = vector():set(x,ay,z)
|
|
if distance_2d(pos,anch_pos) <= (rad + 1) then
|
|
spawn_pingspot(pid,pos,gv,lv)
|
|
end
|
|
end
|
|
end
|
|
|
|
if use_ping_snd and snd_ping then play_sound_for_actor(snd_ping) end
|
|
|
|
CreateTimeEvent("paw_ping_cleanup","ping_"..pid,11,tasks_placeable_waypoints.ping_cleanup,pid)
|
|
end
|
|
|
|
|
|
function do_waypoint(act,se_obj,acode,args)
|
|
args = args or {}
|
|
local syscall = args.syscall and true or false
|
|
if (not syscall) and valid_pda() and not (paw_enabled and act) then return end
|
|
acode = acode or act
|
|
local id,name
|
|
if se_obj then
|
|
id = se_obj.id
|
|
name = safename(id)
|
|
elseif args and args.id then
|
|
id = args.id
|
|
se_obj = alife_object(id) or se_obj
|
|
end
|
|
local ac = action_codes[acode]
|
|
|
|
dl("Received waypoint call \"%s\" on target %s (id %s)",act,name,id)
|
|
|
|
if act == "wp_set" then
|
|
if not se_obj then
|
|
dl("do_waypoint called with action %s but no valid se_obj!",act)
|
|
return end
|
|
set_current_waypoint(se_obj)
|
|
tm:give_task("task_placeable_waypoint")
|
|
waypoint_active = true
|
|
elseif act == "wp_mov" then
|
|
if not se_obj then
|
|
dl("do_waypoint called with action %s but no valid se_obj!",act)
|
|
return end
|
|
if tm.task_info[task_id] then
|
|
local id = se_obj.id
|
|
local task = tm.task_info[task_id]
|
|
local atsk = db.actor:get_task(task_id, true)
|
|
task.target = id
|
|
task.current_target = id
|
|
atsk:change_map_location(task.spot, id)
|
|
level.map_add_object_spot(id, waypoint_mapspot, "")
|
|
set_current_waypoint(se_obj)
|
|
xr_sound.set_sound_play(AC_ID, "pda_tips")
|
|
else
|
|
dl("task_info[task_id] is nil!")
|
|
end
|
|
waypoint_active = true
|
|
elseif act == "wp_del" then
|
|
end_waypoint_task()
|
|
last_waypoint = nil
|
|
elseif act == "waypoint_rename" then
|
|
dl("Received call to rename waypoint")
|
|
local func = ren_wp_functor
|
|
local title = ts("ui_mcm_pawsys_pawmenu_waypoint_rename")
|
|
local itex = "ui_inGame2_PDA_icon_Secondary_mission"
|
|
args.field = "name"
|
|
cartography_mode(false)
|
|
get_text(title,itex,name,func,args)
|
|
elseif act == "waypoint_redesc" then
|
|
dl("Received call to redesc waypoint")
|
|
local func = ren_wp_functor
|
|
local title = ts("ui_mcm_pawsys_pawmenu_waypoint_redesc")
|
|
local itex = "ui_inGame2_PDA_icon_Secondary_mission"
|
|
args.field = "desc"
|
|
cartography_mode(false)
|
|
get_text(title,itex,name,func,args)
|
|
elseif act == "pn_add" then
|
|
dl("Received call to add new pin to map for %s (%s)",name,id)
|
|
local func = add_mapspot_functor
|
|
local icon = icons[ac.icon] or map_pin_icon
|
|
local itex = texture_for_icon(icon)
|
|
local title = ts("ui_mcm_pawsys_pawmenu_pn_add")
|
|
init_new_pin(id,name,ts("st_paw_pin_default_name"),icon)
|
|
cartography_mode(false)
|
|
--vl("pin data before input call: %s (%s) % | %",pins[id].name,pins[id].id,pins[id].icon,pins[id].text)
|
|
get_text(title,itex,nil,func,pins[id])
|
|
elseif act == "pn_ren" then
|
|
if not (id and pins[id]) then return end
|
|
dl("Received call to rename map pin %s (%s)",name,id)
|
|
if not pins[id].locked then
|
|
remove_mapspot(id,icon)
|
|
local func = ren_mapspot_functor
|
|
local icon = pins[id] and pins[id].icon
|
|
local itex = texture_for_icon(icon)
|
|
local name = pins[id] and pins[id].name
|
|
local title = ts("ui_mcm_pawsys_pawmenu_pn_ren")
|
|
cartography_mode(false)
|
|
get_text(title,itex,name,func,pins[id])
|
|
end
|
|
elseif act == "pn_del" then
|
|
if not (id and pins[id]) then return end
|
|
if syscall or not pins[id].locked then
|
|
local icon = pins[id] and pins[id].icon
|
|
if hud_pin_objs[id] then
|
|
vl("Removing pin %s from HUD",id)
|
|
get_hud():RemoveDialogToRender(hud_pin_objs[id])
|
|
hud_pin_objs[id] = nil
|
|
end
|
|
vl("Pin %s (%s) deleted",pins[id].text,id)
|
|
pins[id] = nil
|
|
if icon then remove_mapspot(id,icon) end
|
|
end
|
|
elseif act == "lock_pin" then
|
|
if not (id and pins[id]) then return end
|
|
pins[id].locked = true
|
|
elseif act == "unlock_pin" then
|
|
if not (id and pins[id]) then return end
|
|
pins[id].locked = false
|
|
elseif act == "pn_clr" then
|
|
local wipe_all = args and args.wipe_all
|
|
if not is_empty(hud_pin_objs) then
|
|
for k,v in pairs(hud_pin_objs) do
|
|
if wipe_all or not (pins[k] and pins[k].locked) then
|
|
vl("Hiding HUD pin for %s",k)
|
|
get_hud():RemoveDialogToRender(hud_pin_objs[k])
|
|
hud_pin_objs[k] = nil
|
|
end
|
|
end
|
|
end
|
|
for k,v in pairs(pins) do
|
|
if wipe_all or not v.locked then
|
|
local icon = v.icon
|
|
remove_mapspot(k,icon)
|
|
pins[k] = nil
|
|
end
|
|
end
|
|
elseif act == "mping" then
|
|
ping_area_around(se_obj)
|
|
elseif act == "hud_vis_on" then
|
|
if not (id and pins[id]) then return end
|
|
if syscall or not pins[id].locked then
|
|
pins[id].hud = true
|
|
show_hud_pin(id)
|
|
end
|
|
elseif act == "hud_vis_off" then
|
|
if not (id and pins[id]) then return end
|
|
if syscall or not pins[id].locked then
|
|
pins[id].hud = false
|
|
hide_hud_pin(id)
|
|
end
|
|
elseif act == "show_pins" then
|
|
show_all_pins(true)
|
|
elseif act == "hide_pins" then
|
|
show_all_pins(false)
|
|
elseif act == "cm_dbg" then
|
|
local clsid = se_obj and se_obj:clsid() or "empty"
|
|
property_ui:AddItem("[PAW Debug] Mapspot for %s (id %s) has clsid %s)",name,id,clsid)
|
|
else
|
|
dl("invalid action %s passed to do_waypoint",act)
|
|
end
|
|
return true
|
|
end
|
|
|
|
|
|
function add_context_option(property_ui,act,maptbl)
|
|
local ac = action_codes[act]
|
|
vl("add_context_option \"%s\" | cart_mode is %s",act,cart_mode)
|
|
if ac and ac.enable then
|
|
--printf("action %s is enabled",act)
|
|
if type(ac.mode) ~= "number" then
|
|
dl("WARNING: mode (%s) for action %s was not a number, resetting to 0",ac.mode,act)
|
|
ac.mode = 0
|
|
end
|
|
-- -1: debug mode only
|
|
-- 0: disabled
|
|
-- 1: enabled in normal view only
|
|
-- 2: enabled in cartography mode only
|
|
-- 4: enabled in both
|
|
--[[
|
|
if ((ac.mode < 0) and debuglogs) or
|
|
(ac.mode == 1 and not cart_mode) or
|
|
((ac.mode >= 2) and cart_mode) or
|
|
(ac.mode >= 4) then
|
|
-]]
|
|
if feature_valid_in_mode(ac.mode) then
|
|
local text = ts(ac.text)
|
|
vl("add_context_option(%s): Adding context option %s",act,text)
|
|
property_ui:AddItem(text)
|
|
curr_menu_options[text] = maptbl
|
|
end
|
|
else
|
|
vl("Action %s is missing or not enabled, ignoring",act)
|
|
end
|
|
end
|
|
|
|
function nearest_smart_to_actor()
|
|
vl("nearest_smart_to_actor")
|
|
|
|
local levelid = alife():level_id()
|
|
local smart_nearest,dist_nearest,name_nearest,result
|
|
for name,smart in pairs(SIMBOARD.smarts_by_names) do
|
|
if levelid == game_graph():vertex(smart.m_game_vertex_id):level_id() then
|
|
-- vl("%s is same map as actor",name)
|
|
local dist = smart.position:distance_to(db.actor:position())
|
|
if (SIMBOARD.smarts[smart.id]) and (not smart_nearest or (dist < dist_nearest)) then
|
|
vl("%s (%s) is nearest so far at %s",name,smart.id,dist)
|
|
smart_nearest = smart
|
|
dist_nearest = dist
|
|
name_nearest = name
|
|
end
|
|
end
|
|
end
|
|
|
|
if not smart_nearest then
|
|
dl("!ERROR! No nearby smarts found to actor, this shouldn't be possible")
|
|
return {id=0,name="oops"} end
|
|
|
|
result = {
|
|
smart = smart_nearest,
|
|
id = smart_nearest.id or 0,
|
|
dist = dist_nearest or 0,
|
|
name = name_nearest or "oops",
|
|
pos = smart_nearest.position, -- not used yet
|
|
}
|
|
vl("nearest_smart: %s at %s",name_nearest,dist_nearest)
|
|
return result
|
|
end
|
|
|
|
|
|
function show_smarts(onoff)
|
|
vl("show_smarts: %s",onoff)
|
|
local toggle = onoff or false
|
|
local levelid = alife():level_id()
|
|
local smart_nearest,dist_nearest,name_nearest,result
|
|
for name,smart in pairs(SIMBOARD.smarts_by_names) do
|
|
if (SIMBOARD.smarts[smart.id]) then
|
|
local text = name
|
|
local id = smart.id
|
|
local icon = smart_terrain_icon
|
|
if toggle then
|
|
-- vl("Adding temporary smart %s (%s) with icon %s",text,id,icon)
|
|
level.map_add_object_spot(id,icon,text)
|
|
else
|
|
-- vl("Removing temporary smart %s (%s)",text,id)
|
|
level.map_remove_object_spot(id,icon)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function wp_target_obj()
|
|
dl("wp_target_obj called")
|
|
local obj = level.get_target_obj()
|
|
local id = obj and obj:id()
|
|
vl("ID returned by level.get_target_obj is %s | obj exists: %s",id,obj ~= nil)
|
|
if id and (id > 0) then
|
|
local se_obj = alife_object(id)
|
|
if not (se_obj and (allow_non_wp_targets or valid_waypoint_target(se_obj))) then return end
|
|
|
|
if placed_waypoint then
|
|
if id == placed_waypoint.id then
|
|
vl("Waypoint is currently active on %s (%s), disabling",se_obj:name(),id)
|
|
--do_waypoint("wp_del",se_obj)
|
|
toggle_waypoint()
|
|
else
|
|
vl("Waypoint is currently active, moving to %s (%s)",se_obj:name(),id)
|
|
do_waypoint("wp_mov",se_obj)
|
|
end
|
|
else
|
|
vl("No current waypoint, setting to target object %s (%s)",se_obj:name(),id)
|
|
do_waypoint("wp_set",se_obj)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function get_smart_target_type(obj)
|
|
--printf("get_smart_target_type(%s)",obj and obj:name())
|
|
local target_type
|
|
|
|
if obj then
|
|
if IsStalker(obj) then
|
|
local acomm = get_actor_true_community()
|
|
local comm = obj:character_community() or "stalker"
|
|
local is_enemy = game_relations.is_factions_enemies(acomm,comm)
|
|
--printf("Targeted object %s (%s) is stalker | actor comm %s | target comm %s | is_enemy %s",obj:character_name(),obj:id(),acomm,comm,is_enemy)
|
|
if comm == acomm then
|
|
target_type = "human_f"
|
|
elseif is_enemy then
|
|
target_type = "human_e"
|
|
else
|
|
target_type = "human_n"
|
|
end
|
|
elseif IsMonster(obj) then
|
|
target_type = "monster"
|
|
elseif IsInvbox(obj) then
|
|
target_type = "stash"
|
|
end
|
|
end
|
|
|
|
return target_type
|
|
end
|
|
|
|
function get_smart_icon_for_obj(obj,mapspot)
|
|
local mapspot = mapspot or map_pin_icon
|
|
local target_type = get_smart_target_type(obj)
|
|
local target = target_type and smart_pins[target_type]
|
|
mapspot = (target and icons[target.pin]) or mapspot
|
|
|
|
vl("get_smart_icon_for_obj %s: best icon for %s was %s",obj and obj:character_name(),target_type,mapspot)
|
|
return mapspot
|
|
end
|
|
|
|
|
|
function pin_target_obj(mapspot,notip,silent,smart)
|
|
vl("pin_target_obj: mapspot %s | notip %s | silent %s | smart %s",mapspot,notip,silent,smart)
|
|
local obj = level.get_target_obj()
|
|
local id = obj and obj:id()
|
|
if id and (id > 0) then
|
|
if blacklisted_object(id) then return end
|
|
if smart then
|
|
mapspot = get_smart_icon_for_obj(obj)
|
|
vl("pin_target_obj: pin %s is smart, assigned mapspot %s",id,mapspot)
|
|
end
|
|
local se_obj = alife_object(id)
|
|
if not (se_obj and (allow_non_wp_targets or valid_waypoint_target(se_obj))) then return end
|
|
local name = safename(id)
|
|
if pins[id] then
|
|
if not pins[id].locked then
|
|
local hint = pins[id].text or pins[id].name or ts("st_paw_pin_default_name")
|
|
local text = string.format(ts("st_paw_pin_removed_from_target"),name,hint)
|
|
text = psk(text,text_colors)
|
|
|
|
do_waypoint("pn_del",se_obj)
|
|
dotip(text,5,nil,false)
|
|
end
|
|
else
|
|
local hint = name or ts("st_paw_pin_default_name")
|
|
drop_quick_pin(id,hint,mapspot,true,true)
|
|
if pin_hud_icon_default and pins[id] then
|
|
pins[id].hud = true
|
|
show_hud_pin(id)
|
|
end
|
|
if not silent then
|
|
play_sound_for_actor(snd_tag_target)
|
|
end
|
|
if not notip then
|
|
local icon = ts("ui_mcm_lst_"..(mapspot or pawdata.curr_ico_name))
|
|
local nxtb = keybinds["ico_next"].text
|
|
local prvb = keybinds["ico_prev"].text
|
|
local text = string.format(ts("st_paw_pin_added_to_target"),name,icon,nxtb,prvb)
|
|
text = psk(text,text_colors)
|
|
dotip(text,5,nil,false)
|
|
end
|
|
end
|
|
end
|
|
return id
|
|
end
|
|
|
|
|
|
function create_smart_pin(notip,silent)
|
|
--local mapspot = get_smart_icon_for_obj(obj)
|
|
return pin_target_obj(nil,notip,silent,true)
|
|
end
|
|
|
|
function autotag_target(notip,silent)
|
|
local id = create_smart_pin(true)
|
|
set_pingspot_persistence(id,autotag_persistence)
|
|
set_pin_persistence(id,autotag_persistence)
|
|
return id
|
|
end
|
|
|
|
function drop_quick_pin(id,force_text,force_pin,no_tip,no_fast_travel)
|
|
if not paw_enabled_check() then return end
|
|
if next_pin > time_global() then return end
|
|
next_pin = time_global() + pin_delay
|
|
|
|
if not id then
|
|
id = generate_scripted_mapspot_on(db.actor)
|
|
end
|
|
|
|
local se_obj = alife_object(id)
|
|
if not se_obj then return end
|
|
|
|
local name = se_obj:name() or "none"
|
|
local icon = force_pin or map_pin_icon
|
|
local mapspot_text = force_text or ts("st_paw_pin_quick_name")
|
|
local tip_text = ts("st_paw_pin_dropped")
|
|
init_new_pin(id,name,mapspot_text,icon)
|
|
pins[id].quick = not no_fast_travel
|
|
dl("calling add_mapspot with %s | %s | %s",mapspot_text,id,icon)
|
|
add_mapspot(mapspot_text,id,icon)
|
|
if not no_tip then dotip(tip_text,10000) end
|
|
end
|
|
|
|
|
|
function toggle_waypoint(force)
|
|
dl("toggle_waypoint called")
|
|
if (force ~= nil) then
|
|
waypoint_active = not force
|
|
end
|
|
if not waypoint_active then
|
|
if last_waypoint then
|
|
placed_waypoint = last_waypoint
|
|
local se_obj = alife_object(placed_waypoint.id)
|
|
if not se_obj then return end
|
|
do_waypoint("wp_set",se_obj)
|
|
else
|
|
dotip("st_paw_no_last_wp")
|
|
end
|
|
else
|
|
last_waypoint = placed_waypoint
|
|
end_waypoint_task()
|
|
end
|
|
end
|
|
|
|
|
|
function cartography_mode(onoff)
|
|
if (onoff == nil) then
|
|
cart_mode = not cart_mode
|
|
else
|
|
cart_mode = onoff or false
|
|
end
|
|
vl ("Setting cart_mode to %s and calling show_smarts to toggle",cart_mode)
|
|
show_smarts(cart_shows_smarts and cart_mode)
|
|
end
|
|
|
|
|
|
function get_context_menu_options(property_ui,id,maptbl)
|
|
empty_table(curr_menu_options)
|
|
maptbl = maptbl or {}
|
|
if not id then
|
|
id = maptbl.object_id
|
|
end
|
|
if not paw_enabled then return end
|
|
local se_obj = id and (id > 0) and alife_object(id)
|
|
if not se_obj then return end
|
|
|
|
local name = se_obj:name() or "undefined"
|
|
local clsid = se_obj:clsid() or "unknown"
|
|
local id = se_obj.id
|
|
local pin = id and pins[id]
|
|
vl("get_context_menu_options: %s (%s) | cls %s",name,id,clsid)
|
|
|
|
add_context_option(property_ui,"mping",maptbl)
|
|
if id and valid_waypoint_target(se_obj) then
|
|
if pins[id] then
|
|
vl("Pin exists")
|
|
|
|
if pin.locked then
|
|
add_context_option(property_ui,"unlock_pin",maptbl)
|
|
else
|
|
add_context_option(property_ui,"pn_del",maptbl)
|
|
add_context_option(property_ui,"pn_ren",maptbl)
|
|
if pins[id].hud then
|
|
add_context_option(property_ui,"hud_vis_off",maptbl)
|
|
else
|
|
add_context_option(property_ui,"hud_vis_on",maptbl)
|
|
end
|
|
add_context_option(property_ui,"lock_pin",maptbl)
|
|
end
|
|
else
|
|
vl("No pin")
|
|
add_context_option(property_ui,"pn_add",maptbl)
|
|
end
|
|
|
|
local name = se_obj:name()
|
|
if placed_waypoint == nil then
|
|
vl("No waypoint")
|
|
add_context_option(property_ui,"wp_set",maptbl)
|
|
else
|
|
local wid = placed_waypoint.id or 0
|
|
local sid = se_obj.id or 0
|
|
if wid ~= sid then
|
|
vl("Waypoint exists")
|
|
add_context_option(property_ui,"wp_mov",maptbl)
|
|
end
|
|
vl("Waypoint exists here")
|
|
add_context_option(property_ui,"wp_del",maptbl)
|
|
add_context_option(property_ui,"waypoint_rename",maptbl)
|
|
add_context_option(property_ui,"waypoint_redesc",maptbl)
|
|
end
|
|
end
|
|
|
|
if pins_exist() then
|
|
if show_pins then
|
|
add_context_option(property_ui,"hide_all_pins",maptbl)
|
|
else
|
|
add_context_option(property_ui,"show_all_pins",maptbl)
|
|
end
|
|
end
|
|
|
|
if not (pin and pin.locked) then
|
|
add_context_option(property_ui,"pn_clr",maptbl)
|
|
for k,v in pairs(action_codes) do
|
|
local can_add = true
|
|
if v.act == "pn_add" then
|
|
can_add = (pins[id] == nil)
|
|
end
|
|
local mode = tonumber(v.mode) or 0
|
|
if can_add and v.enable and (mode > 0) and not managed_options[k] then
|
|
add_context_option(property_ui,k,id,maptbl)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function execute_context_menu_option(property_ui,id,level_name,prop)
|
|
vl("passed id : %s",id)
|
|
id = last_clicked_id
|
|
last_clicked_id = nil
|
|
vl("execute_context_menu_option called for id %s\n| prop: %s\n| action %s)",id,prop,action[prop])
|
|
if not (paw_enabled and id and valid_pda()) then return end
|
|
if not (id and (id > 0)) then return end
|
|
local se_obj = alife_object(id)
|
|
if not se_obj then return end
|
|
local ac = action[prop]
|
|
if ac then
|
|
local act = action_codes[ac].act
|
|
do_waypoint(act,se_obj,ac)
|
|
end
|
|
end
|
|
|
|
|
|
function faction_body_icon(comm)
|
|
vl("faction_body_icon(%s) called",comm)
|
|
local icon = nil
|
|
if comm and managed_factions[comm] then
|
|
local bi = body_icon_mode or "badge"
|
|
icon = "paw_"..patch_res..sep..comm
|
|
vl("faction_body_icon generated from quality %s for faction %s: %s",patch_res,comm,icon)
|
|
else
|
|
vl("not a valid human faction, returning %s from bodies set",current_body_icon)
|
|
end
|
|
return icon or current_body_icon
|
|
end
|
|
|
|
function local_set_name(setname)
|
|
local name = ts(setname or icon_sets[pawdata.curr_set_name].name)
|
|
end
|
|
|
|
function local_icon_name(iconame)
|
|
local name = ts(iconame or "ui_mcm_lst_"..pawdata.curr_ico_name)
|
|
end
|
|
|
|
function icon_for_pin(pin_name)
|
|
if icons and pin_name then return icons[pin_name] end
|
|
end
|
|
|
|
|
|
function pin_for_icon(icon)
|
|
if icon and texture_data and texture_data[icon] then return texture_data[icon].id end
|
|
end
|
|
|
|
|
|
function texture_for_icon(icon)
|
|
--printf("texture_for_icon(%s) called",icon)
|
|
local tex = texture_data and texture_data[icon] and texture_data[icon].t
|
|
vl("texture_for_icon(%s) returned %s",icon,tex)
|
|
return tex
|
|
end
|
|
|
|
function texture_for_set(setname)
|
|
if not setname then return end
|
|
local setdata = icon_sets[setname]
|
|
if not (setdata and setdata.active_icon) then
|
|
dl("WARNING: No active icon found for %s",setname)
|
|
return end
|
|
vl("active_icon for %s: %s",setname,setdata.active_icon)
|
|
local td = texture_data[setdata.active_icon]
|
|
vl("texture exists for %s: %s",setdata.active_icon,td ~= nil)
|
|
local tex = td.t
|
|
vl("texture_for_set(%s) returned %s",setname,tex)
|
|
return tex
|
|
end
|
|
|
|
function get_current_texture(set_changed)
|
|
return set_changed and texture_for_set(pawdata.curr_set_name) or texture_for_icon(pawdata.curr_ico_name)
|
|
end
|
|
|
|
function set_or_icon(str)
|
|
return str and ((str ~= "set") and (str ~= "icon"))
|
|
end
|
|
|
|
function set_icon_index(set)
|
|
vl("set_icon_index called for set %s",set)
|
|
local ii = set_index[set].ii
|
|
return ii
|
|
end
|
|
|
|
function set_icon_index_rev(set)
|
|
vl("set_icon_index_rev called for set %s",set)
|
|
local ri = set_index[set].ri
|
|
return ri
|
|
end
|
|
|
|
function set2ind(skey)
|
|
local ind = nil
|
|
vl("set2ind called for set %s, %s sets listed",skey,#set_index)
|
|
for i=1,#set_index,1 do
|
|
local k = set_index[i].id
|
|
if k == skey then
|
|
ind = i
|
|
end
|
|
end
|
|
vl("set2ind(%s) returned %s",skey,ind)
|
|
return ind
|
|
end
|
|
|
|
|
|
function curr_set_i()
|
|
return pawdata.curr_set_ind
|
|
end
|
|
|
|
function next_set_i()
|
|
return roll(curr_set_i() + 1, 1, #set_index)
|
|
end
|
|
|
|
function prev_set_i()
|
|
return roll(curr_set_i() - 1, 1, #set_index)
|
|
end
|
|
|
|
|
|
function curr_ico_i()
|
|
--printf("curr_ico_i returns %s",pawdata.curr_ico_ind)
|
|
return pawdata.curr_ico_ind
|
|
end
|
|
|
|
function next_ico_i()
|
|
local c_ind = curr_ico_i()
|
|
local setdata = icon_sets[pawdata.curr_set_name]
|
|
return roll(c_ind + 1, 1, #setdata.ii)
|
|
end
|
|
|
|
function prev_ico_i()
|
|
local c_ind = curr_ico_i()
|
|
local setdata = icon_sets[pawdata.curr_set_name]
|
|
return roll(c_ind - 1, 1, #setdata.ii)
|
|
end
|
|
|
|
function root_patch_name(patch)
|
|
--printf("root_patch_name called with mapspot %s",patch)
|
|
local name = patch
|
|
local pos_paw = string.find(name,"paw_badge_")
|
|
local pos_qlt = string.find(name,"hr_")
|
|
if pos_paw and pos_qlt then
|
|
name = "paw_badge_"..string.sub(patch,pos_qlt+3)
|
|
vl("root_patch_name strips quality string from %s to get %s",patch,name)
|
|
else
|
|
vl("root_patch_name returning %s as-is",patch)
|
|
end
|
|
return name
|
|
end
|
|
|
|
function active_set(newset)
|
|
vl("active_set(%s) called",newset)
|
|
if newset and type(newset) == "number" then
|
|
pawdata.curr_set_ind = clamp(newset,1,#set_index)
|
|
pawdata.curr_set_name = set_index[pawdata.curr_set_ind].id
|
|
pawdata.curr_set_data = icon_sets[pawdata.curr_set_name]
|
|
current_active_set = pawdata.curr_set_name
|
|
local setdata = pawdata.curr_set_data
|
|
pawdata.curr_ico_name = setdata.active_icon
|
|
pawdata.curr_ico_ind = setdata.ri[root_patch_name(pawdata.curr_ico_name)]
|
|
map_pin_icon = pawdata.curr_ico_name
|
|
vl("active set is now %s (%s), current icon %s (%s)",pawdata.curr_set_name,pawdata.curr_set_ind,pawdata.curr_ico_name,pawdata.curr_ico_ind)
|
|
end
|
|
return pawdata.curr_set_name
|
|
end
|
|
|
|
function get_next_icon()
|
|
local setdata = pawdata.curr_set_data
|
|
return setdata.ii[next_ico_i()]
|
|
end
|
|
|
|
function get_prev_icon()
|
|
local setdata = pawdata.curr_set_data
|
|
return setdata.ii[prev_ico_i()]
|
|
end
|
|
|
|
function get_active_icon(newico)
|
|
if newico and type(newico) == "number" then
|
|
vl("Setting new icon to index %s",newico)
|
|
local setdata = pawdata.curr_set_data
|
|
pawdata.curr_ico_ind = clamp(newico,1,setdata.inum)
|
|
pawdata.curr_ico_name = setdata.ii[pawdata.curr_ico_ind]
|
|
setdata.active_icon = pawdata.curr_ico_name
|
|
map_pin_icon = pawdata.curr_ico_name
|
|
end
|
|
return pawdata.curr_ico_name
|
|
end
|
|
|
|
function notify_icon_change(newset)
|
|
local setdata = pawdata.curr_set_data
|
|
local icon = setdata.active_icon
|
|
local td = texture_data[icon]
|
|
local tex = td.t
|
|
local tiptext = ts("st_paw_change_icon").." "..ts("ui_mcm_lst_"..icon)
|
|
|
|
if newset then
|
|
local name = ts(setdata.name)
|
|
local settext = string.format(ts("st_paw_change_set"),name)
|
|
tiptext = settext .. tiptext
|
|
end
|
|
dotip(tiptext,2,nil,false,tex)
|
|
end
|
|
|
|
|
|
|
|
function cycle_icons(cycle_dir,dotip)
|
|
--printf("cycle_icons: curr_set: %s (%s)",pawdata.curr_set_name,pawdata.curr_set_ind)
|
|
if cycle_dir and type(cycle_dir) ~= "number" then return end
|
|
local setdata = pawdata.curr_set_data
|
|
local next_ind = roll(pawdata.curr_ico_ind + cycle_dir,1,setdata.inum)
|
|
get_active_icon(next_ind)
|
|
if use_ui_snd then play_sound_for_actor(snd_cycle_blip) end
|
|
if dotip then notify_icon_change() end
|
|
end
|
|
|
|
function cycle_sets(cycle_dir,dotip)
|
|
if cycle_dir and type(cycle_dir) ~= "number" then return end
|
|
local next_ind = roll(pawdata.curr_set_ind + cycle_dir,1,#set_index)
|
|
active_set(next_ind)
|
|
if use_ui_snd then play_sound_for_actor(snd_cycle_blip) end
|
|
if dotip then notify_icon_change(true) end
|
|
end
|
|
|
|
function icon_cycle(change,val)
|
|
if not mwheel_enabled then return end
|
|
if change then
|
|
icon_cycle_active = val
|
|
if not mwheel_notify then return icon_cycle_active end
|
|
if icon_cycle_active then
|
|
dotip(ts("st_paw_cycling_icons"))
|
|
else
|
|
dotip(ts("st_paw_mwheel_normal"))
|
|
end
|
|
end
|
|
return icon_cycle_active
|
|
end
|
|
|
|
function set_cycle(change,val)
|
|
if not mwheel_enabled then return end
|
|
if change then
|
|
set_cycle_active = val
|
|
if not mwheel_notify then return icon_cycle_active end
|
|
if set_cycle_active then
|
|
dotip(ts("st_paw_cycling_sets"))
|
|
else
|
|
dotip(ts("st_paw_mwheel_normal"))
|
|
end
|
|
end
|
|
return set_cycle_active
|
|
end
|
|
|
|
function cycle_items(cycle_dir,item_type,dotip)
|
|
if (item_type == nil) then
|
|
if icon_cycle() then
|
|
item_type = "icon"
|
|
elseif set_cycle() then
|
|
item_type = "set"
|
|
end
|
|
end
|
|
if not icoset_changed then icoset_changed = {} end
|
|
if item_type == "icon" then
|
|
icoset_changed.i = true
|
|
vl("cycling icons: %s",cycle_dir)
|
|
cycle_icons(cycle_dir,dotip)
|
|
elseif item_type == "set" then
|
|
icoset_changed.s = true
|
|
vl("cycling sets: %s",cycle_dir)
|
|
cycle_sets(cycle_dir,dotip)
|
|
end
|
|
end
|
|
|
|
|
|
function show_all_pins(onoff)
|
|
show_pins = onoff
|
|
if onoff then
|
|
vl("Showing all recorded pins")
|
|
for id,pin in pairs(pins) do
|
|
local icon = pin.icon
|
|
local mapspot_text = pin.text
|
|
vl("calling add_mapspot with %s | %s | %s",mapspot_text,id,icon)
|
|
add_mapspot(mapspot_text,id,icon)
|
|
end
|
|
else
|
|
vl("Hiding stored pins from map")
|
|
for id,pin in pairs(pins) do
|
|
remove_mapspot(id,pin.icon)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
function load_mcm(pawpath,default)
|
|
local val = ui_mcm and ui_mcm.get("pawsys/"..pawpath)
|
|
if val ~= nil then
|
|
return val
|
|
else
|
|
return default
|
|
end
|
|
end
|
|
|
|
function marker_hint_shown(wpin)
|
|
local mode = show_marker_hint and tonumber(show_marker_hint[wpin])
|
|
local shown = feature_valid_in_mode(mode)
|
|
return shown
|
|
end
|
|
|
|
|
|
function marker_dist_shown(wpin)
|
|
local mode = show_marker_dist and tonumber(show_marker_dist[wpin])
|
|
local shown = feature_valid_in_mode(mode)
|
|
return shown
|
|
end
|
|
|
|
|
|
function mcm_reload_general_settings()
|
|
if not ui_mcm then return end
|
|
local old_paw_en = paw_enabled
|
|
paw_enabled = load_mcm("pawgen/enabled",paw_enabled)
|
|
|
|
if paw_enabled and not old_paw_en then
|
|
on_game_start()
|
|
dl("PAW was disabled and now is not, re-registering actor_on_update")
|
|
elseif not paw_enabled then
|
|
if old_paw_en then
|
|
unregister_all_callbacks()
|
|
end
|
|
printf(logprefix.."Personal Adjustable Waypoint has been disabled, aborting all further action!")
|
|
return false end
|
|
|
|
disable_load_warning = load_mcm("pawgen/disable_load_warning",disable_load_warning)
|
|
wp_hud_icon_enabled = load_mcm("pawgen/wp_hud_icon_enabled",wp_hud_icon_enabled)
|
|
if wp_hud_icon_enabled then
|
|
show_marker_dist["wp"] = tonumber(load_mcm("pawgen/show_dist_wp",show_marker_dist["wp"]))
|
|
show_hud_waypoint()
|
|
else
|
|
hide_hud_waypoint()
|
|
end
|
|
show_marker_dist["pins"] = tonumber(load_mcm("pawgen/show_dist_pins",show_marker_dist["pins"]))
|
|
show_marker_hint["pins"] = tonumber(load_mcm("pawgen/show_hint_pins",show_marker_hint["pins"]))
|
|
pin_near_fade_dist = tonumber(load_mcm("pawgen/pin_near_fade_dist",pin_near_fade_dist))
|
|
pin_far_fade_dist = tonumber(load_mcm("pawgen/pin_far_fade_dist",pin_far_fade_dist))
|
|
pin_far_hide_dist = tonumber(load_mcm("pawgen/pin_far_hide_dist",pin_far_hide_dist))
|
|
wp_clear_dist = tonumber(load_mcm("pawgen/wp_clear_dist",wp_clear_dist))
|
|
tip_on_icoset_change = load_mcm("pawgen/tip_on_icoset_change",tip_on_icoset_change)
|
|
welcome_msg_shown = load_mcm("pawgen/welcome_msg_shown",welcome_msg_shown)
|
|
enable_wp_proxcheck = wp_clear_dist and wp_clear_dist > 0
|
|
mcm_update_throttle = load_mcm("pawgen/mcm_update_throttle",mcm_update_throttle)
|
|
mwheel_poll_interval = load_mcm("pawgen/mwheel_poll_interval",mwheel_poll_interval)
|
|
-- These last two options are not in the MCM menu, but can be manually set as overrides
|
|
return true
|
|
end
|
|
|
|
function mcm_reload_keybind_table()
|
|
if not ui_mcm then return end
|
|
for k,v in pairs(keybinds) do
|
|
local kb = load_mcm("pawbinds/bind_"..k)
|
|
local km = load_mcm("pawbinds/modk_"..k)
|
|
local vbkb = valid_bind(kb)
|
|
local vbkm = valid_bind(km)
|
|
if vbkb then
|
|
keybinds[k].bind = kb
|
|
end
|
|
if vbkm then
|
|
keybinds[k].mod = km
|
|
end
|
|
keybinds[k].text = bindtext(kb,km)
|
|
end
|
|
end
|
|
|
|
function mcm_reload_keybind_settings()
|
|
cartography_must_hold = not load_mcm("pawbinds/cartmode_toggle",cartography_must_hold)
|
|
keybinds[cartmode].hold = cartography_must_hold
|
|
cart_shows_smarts = load_mcm("pawbinds/cart_shows_smarts",cart_shows_smarts)
|
|
mwheel_notify = load_mcm("pawbinds/mwheel_notify")
|
|
cartmode_unfade = load_mcm("pawbinds/cartmode_unfade",cartmode_unfade)
|
|
local tmp = ui_mcm.get("pawsys/pawbinds/mwheel_enabled")
|
|
if tmp and type(tmp) == "number" then
|
|
tmp = (tmp ~= 0)
|
|
end
|
|
mwheel_enabled = tmp and mwheel_avail
|
|
|
|
tmp = ui_mcm.get("pawsys/pawbinds/mwheel_override")
|
|
if tmp ~= nil then
|
|
dl("MCM override found for mwheel_avail (old = %s | new = %s)",mwheel_avail,tmp)
|
|
mwheel_avail = tmp
|
|
end
|
|
|
|
tmp = ui_mcm.get("pawsys/pawbinds/right_click_override")
|
|
-- if set to true, will force on_map_right_click support on
|
|
if tmp ~= nil then
|
|
dl("MCM override found for right_click_avail (old = %s | new = %s)",right_click_avail,tmp)
|
|
right_click_override= tmp
|
|
end
|
|
|
|
tmp = ui_mcm.get("pawsys/pawgen/disable_mcmups")
|
|
if tmp ~= nil then
|
|
dl("MCM override found for disable_mcm_updates (old = %s | new = %s)",disable_mcm_updates,tmp)
|
|
disable_mcm_updates = tmp
|
|
end
|
|
|
|
tmp = load_mcm("pawgen/pingsound")
|
|
if tmp ~= nil then
|
|
use_ping_snd = tmp
|
|
end
|
|
end
|
|
|
|
function mcm_reload_pin_settings()
|
|
patch_res = ui_mcm.get("pawsys/pawpins/patch_res") or "badge"
|
|
local bi = ui_mcm.get("pawsys/pawpins/milpda_body_icon")
|
|
local pig = ui_mcm.get("pawsys/pawpins/pin_icon_group")
|
|
--local mp = ui_mcm.get("pawsys/pawpins/poi_icon_"..(pig or ""))
|
|
local cbi = ui_mcm.get("pawsys/pawpins/poi_icon_bodies")
|
|
|
|
for k,v in pairs(icons) do
|
|
if managed_factions[k] then
|
|
local newbadge = "paw_"..patch_res..sep..k
|
|
vl("MCM: icon for %s was %s, is now %s",k,v,newbadge)
|
|
icons[k] = newbadge
|
|
end
|
|
end
|
|
|
|
load_active_icoset_data()
|
|
local icon = pig and icon_sets[pig] and icon_sets[pig].active_icon or default_mapspot
|
|
icon_sets["bodies"].active_icon = icons[cbi]
|
|
dl("MCM: body icon mode %s | paw icon %s",bi,cbi)
|
|
map_pin_icon = icon
|
|
current_active_set = pig
|
|
|
|
dl("MCM: icon %s | icon set: %s",icon,pig)
|
|
|
|
local cp = ui_mcm.get("pawsys/pawpins/use_custom_pin_icon") or false
|
|
if cp then
|
|
custom_pin_icon = true
|
|
map_pin_icon = ui_mcm.get("pawsys/pawpins/custom_pin_icon") or map_pin_icon
|
|
dl("MCM: Overriding default icon with custom value: %s",map_pin_icon)
|
|
else
|
|
custom_pin_icon = false
|
|
end
|
|
if force_icon_override then
|
|
dl("MCM: Script hardcoded to override map_pin_icon with %s",force_icon_override)
|
|
map_pin_icon = force_icon_override
|
|
default_mapspot = force_icon_override
|
|
end
|
|
|
|
if (bi and ish_kill_tracker) then
|
|
body_icon_mode = bi
|
|
current_body_icon = icons[cbi] or default_mapspot
|
|
ish_kill_tracker.use_paw_icon = (bi == "set") or (bi == "fac")
|
|
end
|
|
widget_enabled = load_mcm("pawhud/widget_enable",widget_enabled)
|
|
active_theme = load_mcm("pawhud/active_theme",active_theme)
|
|
if not hud_themes[active_theme] then active_theme = "classicauto" end
|
|
widget_custom_pos = {
|
|
x = load_mcm("pawhud/pos_x"),
|
|
y = load_mcm("pawhud/pos_y")
|
|
}
|
|
widget_use_custom_pos = load_mcm("pawhud/custompos")
|
|
widget_hide_delay = (tonumber(load_mcm("pawhud/autohide",widget_hide_delay)) * 1000)
|
|
use_ui_snd = load_mcm("pawhud/hudsound")
|
|
|
|
--[[
|
|
local mdf = clamp(tonumber(ui_mcm.get("pawsys/pawpins/fave_recent")),0,10)
|
|
if mdf and (mdf ~= max_dynamic_faves) then
|
|
local old_mdf = max_dynamic_faves
|
|
max_dynamic_faves = mdf
|
|
dl("new max_dynamic_faves: %s (was %s)",mdf,old_mdf)
|
|
if dynamic_faves and (not is_empty(dynamic_faves)) and
|
|
(max_dynamic_faves > 0) then
|
|
local df = {}
|
|
for i = 1,max_dynamic_faves do
|
|
if dynamic_faves[i] then
|
|
vl("dynamic_fave[%s]: %s",i,dynamic_faves[i])
|
|
df[i] = dynamic_faves[i]
|
|
end
|
|
end
|
|
dynamic_faves = df
|
|
end
|
|
end
|
|
--]]
|
|
end
|
|
|
|
function mcm_reload_reticle_settings()
|
|
if ui_mcm then
|
|
mark_on_positive_id = load_mcm("pawret/enable_autotag",mark_on_positive_id)
|
|
autotag_persistence = load_mcm("pawret/autotag_persistence",autotag_persistence)
|
|
autotag_lifetime = load_mcm("pawret/autotag_lifetime",(autotag_lifetime / 6)) * 6
|
|
autotags_time_out = (autotag_lifetime or 0) > 0
|
|
pin_hud_icon_default = load_mcm("pawret/pin_auto_visible",pin_hud_icon_default)
|
|
manual_smart_pins = load_mcm("pawret/manual_smart_pins",manual_smart_pins)
|
|
reticle_mode = load_mcm("pawret/reticle_mode",reticle_mode)
|
|
reticle_mustzoom = load_mcm("pawret/reticle_mustzoom",reticle_mustzoom)
|
|
reticle_color.a = load_mcm("pawret/reticle_alpha",reticle_color.a)
|
|
ret_fade_attack_time = load_mcm("pawret/ret_fade_attack_time",ret_fade_attack_time)
|
|
ret_fade_decay_time = load_mcm("pawret/ret_fade_decay_time",ret_fade_decay_time)
|
|
for k,v in pairs(smart_pins) do
|
|
smart_pins[k].pin = load_mcm("pawret/"..k,v.pin)
|
|
smart_pins[k].enabled = load_mcm("pawret/"..k.."_enable",v.enabled)
|
|
end
|
|
-- Load Crook's facid settings, if present
|
|
local did = ui_mcm.get("targetID/timeID")
|
|
if did ~= nil then
|
|
npc_ident.delay_id = did
|
|
end
|
|
did = ui_mcm.get("targetID/deadID")
|
|
if did ~= nil then
|
|
npc_ident.id_bodies = did
|
|
end
|
|
npc_ident.id_speed = ui_mcm.get("targetID/speedID") or 0.3
|
|
npc_ident.lenience = ui_mcm.get("targetID/targL") or 0.99
|
|
end
|
|
end
|
|
|
|
|
|
function on_option_change()
|
|
if load_failed then return end
|
|
-- Sync all MCM values and propagate changes
|
|
language = ui_options.curr_localization()
|
|
if ui_mcm and not mcm_killswitch then
|
|
debuglogs = load_mcm("pawgen/debuglogs",debuglogs)
|
|
catsy_paw_mcm.debuglogs = debuglogs
|
|
dl("Setting for debuglogs loaded from MCM: %s",debuglogs)
|
|
|
|
if load_mcm("pawgen/wipe_all") then
|
|
ui_mcm.set("pawsys/pawgen/wipe_all",false)
|
|
dl("MCM: Wiping all pin data per player request")
|
|
local args = {wipe_all=true}
|
|
do_waypoint("pn_clr",nil,nil,args)
|
|
end
|
|
|
|
mcm_reload_general_settings()
|
|
if not paw_enabled then
|
|
return
|
|
end
|
|
mcm_reload_keybind_table()
|
|
mcm_reload_keybind_settings()
|
|
mcm_reload_pin_settings()
|
|
mcm_reload_reticle_settings()
|
|
|
|
for k,v in pairs(action_codes) do
|
|
local m = load_mcm("pawmenu/"..k)
|
|
if m ~= nil then
|
|
action_codes[k].mode = tonumber(m) or 0
|
|
vl("MCM: Loading action code mode %s for %s",m,k)
|
|
else
|
|
vl("MCM: No value found for %s, leaving unchanged",k)
|
|
end
|
|
end
|
|
ui_mcm.set("pawsys/pawgen/mcm_ver",script_version)
|
|
end
|
|
|
|
if ish_kill_tracker and item_milpda then ish_kill_tracker.on_option_change() end
|
|
active_set(icon_sets[current_active_set].i)
|
|
if db.actor and get_hud() then
|
|
unsquish_ratio = (device().height / device().width) / (768 / 1024)
|
|
reset_indicator()
|
|
end
|
|
end
|
|
|
|
|
|
function load_active_icoset_data()
|
|
if not ui_mcm then return end
|
|
vl("Loading MCM values for sets and icons")
|
|
local path = "pawsys/pawpins/poi_icon_"
|
|
for k,v in pairs(icon_sets) do
|
|
local val = ui_mcm.get(path..k)
|
|
local icon = icons[val]
|
|
--printf("loading "..path..k..": %s | icons %s | icons[%s]: %s",val,icons,val,icons[val])
|
|
vl("Loading active icon for %s: %s = %s",k,val,icon)
|
|
icon_sets[k].default = val
|
|
icon_sets[k].active_icon = icon
|
|
end
|
|
local setname = ui_mcm.get("pawsys/pawpins/pin_icon_group")
|
|
if set_index[setname] then
|
|
active_set(set_index[setname])
|
|
end
|
|
end
|
|
|
|
function update_mcm_icoset_data()
|
|
if not ui_mcm then return end
|
|
if icoset_changed then
|
|
vl("Updating MCM settings after set/icon change",icoset_changed)
|
|
local curr_set = pawdata.curr_set_name
|
|
if icoset_changed and icoset_changed.s then
|
|
ui_mcm.set("pawsys/pawpins/pin_icon_group",curr_set)
|
|
end
|
|
local path = "pawsys/pawpins/poi_icon_"..curr_set
|
|
local active_pin = pin_for_icon(icon_sets[curr_set].active_icon)
|
|
ui_mcm.set(path,active_pin)
|
|
end
|
|
icoset_changed = nil
|
|
end
|
|
|
|
function check_waypoint_proximity(id)
|
|
local se_obj = id and alife_object(id)
|
|
if (not se_obj) or not (se_obj and se_obj.online) then return end
|
|
local szpos = se_obj.position
|
|
local dist = szpos:distance_to(db.actor:position()) or 0
|
|
if dist <= wp_clear_dist then
|
|
toggle_waypoint(false)
|
|
end
|
|
end
|
|
|
|
function tick()
|
|
if not paw_enabled then
|
|
unregister_all_callbacks()
|
|
return
|
|
end
|
|
local now = time_global()
|
|
if enable_wp_proxcheck and waypoint_active and (next_wp_proxcheck <= now) then
|
|
next_wp_proxcheck = now + wp_proxcheck_interval
|
|
check_waypoint_proximity(placed_waypoint and placed_waypoint.id)
|
|
end
|
|
if (next_gc_check <= now) then
|
|
next_gc_check = now + garbcollect_interval
|
|
script_zone_cleanup()
|
|
temp_pin_cleanup()
|
|
end
|
|
if disable_mcm_updates then return end
|
|
if (next_mcm_update > now) or not icoset_changed then return end
|
|
next_mcm_update = now + mcm_update_throttle
|
|
update_mcm_icoset_data()
|
|
end
|
|
|
|
function paw_welcome_message()
|
|
if welcome_msg_shown then return true end
|
|
vl("Welcome message not shown yet, displaying to player")
|
|
welcome_msg_shown = true
|
|
if ui_mcm then
|
|
ui_mcm.set("pawsys/pawgen/welcome_msg_shown",true)
|
|
end
|
|
local player_name = alife():actor():character_name()
|
|
local kb = keybinds
|
|
toggle_bind = kb["wptoggle"].bind
|
|
toggle_mod = kb["wptoggle"].mod
|
|
quickpin_bind = kb["quickpin"].bind
|
|
quickpin_mod = kb["quickpin"].mod
|
|
cart_mode_hold = kb["cartmode"].bind
|
|
cart_mode_mod = kb["cartmode"].mod
|
|
local toggle_btxt = bindtext(toggle_bind,toggle_mod)
|
|
local quickpin_btxt = bindtext(quickpin_bind,quickpin_mod)
|
|
local cartmode_btxt = bindtext(cart_mode_hold,cart_mode_mod)
|
|
local welcome_msg = string.format(ts("st_pawsys_welcome_msg"),toggle_btxt,quickpin_btxt,cartmode_btxt,player_name)
|
|
welcome_msg = psk(welcome_msg,text_colors)
|
|
dotip(welcome_msg,10000)
|
|
return true
|
|
end
|
|
-- ======================================================================
|
|
-- UI ELEMENTS
|
|
-- ======================================================================
|
|
|
|
-- ======================================================================
|
|
--[[ TEXT INPUT WINDOW
|
|
Originally adapted from parts of the vanilla backpack stash script
|
|
|
|
A more generic, parameterized version used to ship with PAW as its
|
|
own mod (ui_get_input.script)
|
|
-- ====================================================================]]
|
|
|
|
InputGUI = nil
|
|
|
|
function get_text(title_txt,icon_tex,prepop,func,args)
|
|
dl("get_text called:\nTitle: %s\nIcon: %s\nExisting text: %s",title_txt,icon_tex,prepop)
|
|
tex = texdef or tex_defs
|
|
args = args or {}
|
|
|
|
if not InputGUI then
|
|
InputGUI = UITextInputWnd(title_txt,icon_tex,prepop,func,args)
|
|
end
|
|
|
|
if InputGUI and not InputGUI:IsShown() then
|
|
InputGUI:Reset(title_txt,icon_tex,prepop,func,args)
|
|
InputGUI:ShowDialog(true)
|
|
Register_UI("UITextInputWnd","get_text")
|
|
end
|
|
end
|
|
|
|
-- ======================================================================
|
|
|
|
class "UITextInputWnd" (CUIScriptWnd)
|
|
|
|
function UITextInputWnd:__init(title_txt,icon_tex,prepop,func,args) super()
|
|
vl("UITextInputWnd:__init:\nTitle: %s\nIcon: %s\nExisting text: %s",title_txt,icon_tex,prepop)
|
|
self.title_txt = title_txt
|
|
self.icon_tex = icon_tex
|
|
self.prepop = prepop
|
|
self.func = func
|
|
self.args = args
|
|
self:InitControls()
|
|
self:InitCallBacks()
|
|
end
|
|
|
|
function UITextInputWnd:__finalize()
|
|
end
|
|
|
|
function UITextInputWnd:InitControls()
|
|
self:SetWndRect(Frect():set(0,0,1024,768))
|
|
self:SetAutoDelete(true)
|
|
|
|
local tex = {
|
|
file = "paw_input_window.xml",
|
|
tbar = "titlebar",
|
|
paw = "paw",
|
|
icon = "icon",
|
|
text = "text",
|
|
root = "dialog",
|
|
bg = "background",
|
|
input = "input",
|
|
ok = "btn_ok",
|
|
cancel = "btn_cancel",
|
|
}
|
|
|
|
local xml = CScriptXmlInit()
|
|
local tbar = tex.root..":"..tex.tbar
|
|
local paw = tbar..":"..tex.paw
|
|
local icon = tbar..":"..tex.icon
|
|
local text = tbar..":"..tex.text
|
|
local bg = tex.root..":"..tex.bg
|
|
local cancel = tex.root..":"..tex.cancel
|
|
local input = tex.root..":"..tex.input
|
|
local ok = tex.root..":"..tex.ok
|
|
|
|
xml:ParseFile (tex.file)
|
|
|
|
self.dialog = xml:InitStatic(tex.root, self)
|
|
xml:InitStatic(bg, self.dialog)
|
|
self.tbar = xml:InitStatic(tbar,self.dialog)
|
|
self.paw = xml:InitTextWnd(paw,self.tbar)
|
|
self.paw:SetText("PAW".." "..script_version)
|
|
self.paw:SetFont(GetFontSmall())
|
|
self.icon = xml:InitStatic(icon, self.tbar)
|
|
if self.icon_tex then
|
|
self.icon:InitTexture(self.icon_tex)
|
|
else
|
|
dl("Empty icon texture passed to input window")
|
|
end
|
|
self.text = xml:InitTextWnd(text, self.tbar)
|
|
self.text:SetText(self.title_txt)
|
|
self.text:SetFont(GetFontGraffiti22Russian())
|
|
|
|
self.input = xml:InitEditBox(input,self.dialog)
|
|
self:Register(self.input,"fld_input")
|
|
self.input:SetText(self.prepop)
|
|
|
|
local btn = xml:Init3tButton(cancel, self.dialog)
|
|
self:Register(btn,tex.cancel)
|
|
|
|
btn = xml:Init3tButton(ok, self.dialog)
|
|
self:Register(btn,tex.ok)
|
|
end
|
|
|
|
|
|
function UITextInputWnd: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 UITextInputWnd:Reset(title_txt,icon_tex,prepop,func,args)
|
|
self.icon_tex = icon_tex
|
|
self.title_txt = title_txt
|
|
self.prepop = prepop
|
|
self.func = func
|
|
self.args = args
|
|
if self.title_txt then
|
|
self.text:SetText(self.title_txt)
|
|
end
|
|
if self.icon_tex then
|
|
self.icon:InitTexture(self.icon_tex)
|
|
end
|
|
self.input:SetText("")
|
|
end
|
|
|
|
|
|
function UITextInputWnd:Update()
|
|
CUIScriptWnd.Update(self)
|
|
end
|
|
|
|
|
|
function UITextInputWnd:OnAccept()
|
|
local text_input = self.input:GetText()
|
|
if text_input == "" then text_input = nil end
|
|
dl("OnAccept: text_input is %s",text_input)
|
|
if self.func then
|
|
exec(self.func,text_input,self.args)
|
|
end
|
|
self:Close()
|
|
end
|
|
|
|
|
|
function UITextInputWnd:OnKeyboard(dik, keyboard_action)
|
|
local res = CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
|
|
if (res == false) then
|
|
local bind = dik_to_bind(dik)
|
|
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 UITextInputWnd:Close()
|
|
self:HideDialog()
|
|
Unregister_UI("UITextInputWnd")
|
|
end
|
|
|
|
-- ======================================================================
|
|
--[[ ICON AND SET HUD INDICATOR
|
|
See the hud_themes table and PAW's MCM menu for more info
|
|
-- ====================================================================]]
|
|
|
|
|
|
GUI = nil
|
|
|
|
class "UIPAWIndicator" (CUIScriptWnd)
|
|
|
|
function UIPAWIndicator:__init() super()
|
|
vl("PAW init called, active theme is %s | widget_active %s | widget_enabled %s",active_theme,widget_active,widget_enabled)
|
|
if not widget_enabled then return end
|
|
self.theme = hud_themes[active_theme]
|
|
self:InitControls()
|
|
self:DrawIndicator(self.theme)
|
|
get_hud():AddDialogToRender(self)
|
|
RegisterScriptCallback("actor_on_net_destroy", self)
|
|
end
|
|
|
|
|
|
function UIPAWIndicator:__finalize()
|
|
end
|
|
|
|
|
|
function UIPAWIndicator:Reset(theme)
|
|
vl("UIPAWIndicator:Reset called with theme %s",theme and theme.name)
|
|
if not theme then theme = self.theme end
|
|
self.dialog:Show(false)
|
|
self.dialog = nil
|
|
self:InitControls()
|
|
self:DrawIndicator(theme)
|
|
end
|
|
|
|
function UIPAWIndicator:Destroy()
|
|
get_hud():RemoveDialogToRender(self)
|
|
end
|
|
|
|
|
|
function UIPAWIndicator:SetTheme(theme_name)
|
|
vl("UIPAWIndicator:SetTheme called with theme_name %s",theme_name)
|
|
local theme = hud_themes and hud_themes[theme_name]
|
|
if theme then
|
|
self.dialog:Show(false)
|
|
active_theme = theme_name or active_theme
|
|
self.theme = hud_themes[active_theme]
|
|
self:Reset(theme)
|
|
end
|
|
end
|
|
|
|
|
|
function UIPAWIndicator:actor_on_net_destroy()
|
|
get_hud():RemoveDialogToRender(self)
|
|
end
|
|
|
|
|
|
function UIPAWIndicator:DrawIndicator(theme)
|
|
vl("UIPAWIndicator:DrawIndicator called with theme %s | self %s",theme and theme.name,self.theme)
|
|
local pos = theme.pos
|
|
if widget_use_custom_pos then pos = widget_custom_pos end
|
|
local xml = CScriptXmlInit()
|
|
xml:ParseFile(theme.file)
|
|
|
|
self.dialog = xml:InitStatic(theme.node, self)
|
|
self.dialog:SetWndPos(vector2():set(pos.x,pos.y))
|
|
if theme.tex then
|
|
self.dialog:InitTexture(theme.tex)
|
|
end
|
|
self.box_curr = xml:InitStatic(theme.node..":curr", self.dialog)
|
|
self.box_curr:InitTexture(texture_for_icon(self.icon_curr))
|
|
|
|
if theme.style ~= "compact" then
|
|
self.box_prev = xml:InitStatic(theme.node..":prev", self.dialog)
|
|
self.box_prev:InitTexture(texture_for_icon(get_prev_icon()))
|
|
|
|
self.box_next = xml:InitStatic(theme.node..":next", self.dialog)
|
|
self.box_next:InitTexture(texture_for_icon(get_next_icon()))
|
|
|
|
self.box_head = xml:InitStatic(theme.node..":head",self.dialog)
|
|
self.box_text = xml:InitTextWnd(theme.node..":head",self.box_head)
|
|
self.box_prev:SetTextureColor(colors.dimmed)
|
|
self.box_next:SetTextureColor(colors.dimmed)
|
|
end
|
|
if theme.style == "full" then
|
|
self.box_text:SetText(ts("ui_mcm_lst_pawsys_pg_"..self.set_curr))
|
|
self.box_head2 = xml:InitStatic(theme.node..":head2",self.dialog)
|
|
self.box_text2 = xml:InitTextWnd(theme.node..":head2",self.box_head2)
|
|
self.box_text2:SetText(ts("ui_mcm_lst_"..self.icon_curr))
|
|
elseif theme.style == "minimal" then
|
|
self.box_text:SetText(ts("ui_mcm_lst_"..self.icon_curr))
|
|
end
|
|
vl("UIPAWIndicator:DrawIndicator completed")
|
|
end
|
|
|
|
|
|
function UIPAWIndicator:InitControls()
|
|
self.pda_active = item_device.is_pda_active()
|
|
self.icon_curr = get_active_icon()
|
|
self.set_curr = pawdata.curr_set_name
|
|
vl("UIPAWIndicator:InitControls: active icon is %s",self.icon_curr)
|
|
end
|
|
|
|
|
|
function UIPAWIndicator:Update(force)
|
|
CUIScriptWnd.Update(self)
|
|
self.dialog:Show(false)
|
|
if not (widget_enabled and main_hud_shown()) then return end
|
|
|
|
local theme = self.theme
|
|
local pda_changed = false
|
|
|
|
if self.pda_active ~= item_device.is_pda_active() then
|
|
pda_changed = true
|
|
end
|
|
if item_device.is_pda_active() then
|
|
local thm = theme.pda_thm
|
|
if thm then
|
|
|
|
theme = hud_themes[thm]
|
|
end
|
|
end
|
|
if pda_changed then
|
|
vl("PDA mode has changed, resetting theme")
|
|
self:Reset(theme)
|
|
end
|
|
|
|
if theme.tex then self.dialog:InitTexture(theme.tex) end
|
|
local pos = theme.pos
|
|
if widget_use_custom_pos then
|
|
pos = widget_custom_pos
|
|
end
|
|
|
|
self.dialog:SetWndPos(vector2():set(pos.x,pos.y))
|
|
|
|
local acticon = pawdata.curr_ico_name
|
|
if (self.icon_curr ~= acticon) or (self.set_curr ~= pawdata.curr_set_name) then
|
|
vl("UIPAWIndicator:Update - icon/set has changed (new curr icon: %s)",acticon)
|
|
self.set_curr = pawdata.curr_set_name
|
|
self.icon_curr = acticon
|
|
self.box_curr:InitTexture(texture_for_icon(self.icon_curr))
|
|
if theme.style ~= "compact" then
|
|
self.box_prev:InitTexture(texture_for_icon(get_prev_icon()))
|
|
self.box_next:InitTexture(texture_for_icon(get_next_icon()))
|
|
end
|
|
if theme.style == "full" then
|
|
self.box_text:SetText(ts("ui_mcm_lst_pawsys_pg_"..self.set_curr))
|
|
self.box_text2:SetText(ts("ui_mcm_lst_"..self.icon_curr))
|
|
elseif theme.style == "minimal" then
|
|
self.box_text:SetText(ts("ui_mcm_lst_"..self.icon_curr))
|
|
end
|
|
widget_last_used = time_global()
|
|
widget_active = true
|
|
end
|
|
if widget_hide_delay > 0 then
|
|
if time_global() > widget_last_used + widget_hide_delay then widget_active = false end
|
|
end
|
|
self.dialog:Show(widget_active)
|
|
end
|
|
|
|
|
|
function reset_indicator()
|
|
vl("Resetting PAW indicator")
|
|
if GUI then GUI:Destroy() end
|
|
if not widget_enabled then return end
|
|
vl("Re-initializing PAW indicator")
|
|
GUI = UIPAWIndicator()
|
|
end
|
|
|
|
|
|
function show_indicator(tf)
|
|
if not (GUI and widget_enabled) then return end
|
|
if show_indicator == nil then
|
|
widget_active = -widget_active
|
|
else
|
|
widget_active = (tf == true) or false
|
|
end
|
|
GUI:Show(widget_active)
|
|
end
|
|
|
|
|
|
-- ======================================================================
|
|
--[[ WAYPOINT AND PIN HUD ICONS
|
|
Some pieces adapted from GT's "HUD Ubisoft Friendly" addon
|
|
-- ====================================================================]]
|
|
|
|
function unsquish_aspect(element)
|
|
local w = element:GetWidth()
|
|
local h = element:GetHeight()
|
|
element:SetWndSize(vector2():set((w*unsquish_ratio),h))
|
|
end
|
|
|
|
function dist_from_crosshair(position)
|
|
local toPoint = vector():set(position):sub(device().cam_pos):normalize()
|
|
return toPoint:dotproduct(device().cam_dir)
|
|
end
|
|
|
|
--[[
|
|
animate_texture(
|
|
container,
|
|
500,
|
|
{512.5,384.5},
|
|
{512.5,384.5},
|
|
{0,0},
|
|
{200, 200},
|
|
1,
|
|
0,
|
|
function() printf("anim_finished") end,
|
|
function(x) return x^2 end
|
|
)
|
|
--]]
|
|
|
|
function easing_outquint(x)
|
|
if not x then return end
|
|
return 1 - math.pow(1 - x, 5)
|
|
end
|
|
|
|
function easing_inquint(x)
|
|
if not x then return end
|
|
return x * x * x * x * x
|
|
end
|
|
|
|
function abort_fade_in()
|
|
return HUD_RET.fading_out or not HUD_RET.fading_in
|
|
end
|
|
|
|
function abort_fade_out()
|
|
return HUD_RET.fading_in or not HUD_RET.fading_out
|
|
end
|
|
|
|
|
|
function animate_texture(element, duration, start_pos, end_pos, start_size, end_size, alpha_start, alpha_end , on_finish_func, anim_curve_modifier_func, r, g, b)
|
|
r = r or 255
|
|
g = g or 255
|
|
b = b or 255
|
|
|
|
local anim_state = 0
|
|
local start_time = time_global()
|
|
local end_time = time_global() + duration
|
|
local anim_curve_modifier_func = anim_curve_modifier_func or function(x) return x end
|
|
CreateTimeEvent("animate_texture", time_global(), 0, function()
|
|
local x = anim_curve_modifier_func(anim_state)
|
|
local pos_x = lerp(start_pos.x, end_pos.x, x)
|
|
local pos_y = lerp(start_pos.y, end_pos.y, x)
|
|
|
|
local size_x = lerp(start_size.x, end_size.x, x)
|
|
local size_y = lerp(start_size.y, end_size.y, x)
|
|
|
|
local alpha = lerp(alpha_start, alpha_end, x)
|
|
|
|
|
|
if anim_state == 1 then
|
|
if on_finish_func then on_finish_func() end
|
|
return true
|
|
end
|
|
anim_state = math.min(1, normalize(time_global(), start_time, end_time))
|
|
end)
|
|
end
|
|
|
|
local active_anims = {}
|
|
|
|
function anim_fade(box,alpha_start,alpha_end,duration,event_id,instanced, r, g, b, anim_curve_modifier_func, on_finish_func,abort_func)
|
|
if not box then return end
|
|
local fade_dir = (alpha_start > alpha_end) and "out" or "in"
|
|
dl("anim_fade: start %s end %s dur %s | event_id %s | instanced %s ",alpha_start,alpha_end, duration,event_id,instanced)
|
|
if (event_id == nil) then event_id = "anim_fade" end
|
|
local anim_id = event_id.."_"..tostring(time_global())
|
|
r = r or 255
|
|
g = g or 255
|
|
b = b or 255
|
|
|
|
if active_anims[event_id] then
|
|
alpha_start = active_anims[event_id].a
|
|
dl("Repeat invocation of non-instanced fade event, aborting fade-%s and starting new at current alpha (%s)",fade_dir,alpha_start)
|
|
active_anims[event_id] = nil
|
|
if on_finish_func then on_finish_func(box,event_id,alpha_end,r,g,b) end
|
|
--anim_fade(box,alpha_start,alpha_end,duration,event_id,instanced, r, g, b, anim_curve_modifier_func, on_finish_func,abort_func)
|
|
--return true
|
|
end
|
|
|
|
local anim_state = 0
|
|
local start_time= time_global()
|
|
local end_time = time_global() + duration
|
|
local anim_curve_modifier_func = anim_curve_modifier_func or function(x) return x end
|
|
active_anims[event_id] = {
|
|
|
|
box = box,
|
|
instanced = instanced and true or false,
|
|
anim_id = anim_id,
|
|
start_time = start_time,
|
|
end_time = end_time,
|
|
active = true,
|
|
a_start = alpha_start,
|
|
a_end = alpha_end,
|
|
a = alpha_start,
|
|
r = r,
|
|
g = g,
|
|
b = b,
|
|
}
|
|
|
|
--vl("Creating fade-%s time event %s | %s",fade_dir,event_id,anim_id)
|
|
CreateTimeEvent("animate_fade"..event_id..anim_id, time_global(), 0, function()
|
|
local abort = abort_func and abort_func()
|
|
if abort then
|
|
vl("Received abort for %s",event_id)
|
|
anim_state = 1
|
|
else
|
|
local anim = active_anims[event_id]
|
|
if anim then
|
|
local x = anim_curve_modifier_func(anim_state)
|
|
local alpha = lerp(alpha_start, alpha_end, x)
|
|
anim.a,anim.r,anim.g,anim.b = alpha,r,g,b
|
|
box:SetTextureColor(GetARGB(alpha,r,g,b))
|
|
--vl("Fade-%s time event: setting transparency for %s to %s at time %s",fade_dir,event_id,alpha,time_global())
|
|
else
|
|
vl("Event data for %s has cleared, aborting",event_id)
|
|
anim_state = 1
|
|
end
|
|
end
|
|
|
|
if (anim_state == 1) then
|
|
vl("Fade-%s animation %s completed at %s",fade_dir,event_id,time_global())
|
|
if on_finish_func then on_finish_func(box,event_id,alpha_end,r,g,b) end
|
|
return true
|
|
end
|
|
anim_state = math.min(1, normalize(time_global(), start_time, end_time))
|
|
end)
|
|
end
|
|
|
|
function fade_by_dist(element,dist,min,mid,max,alpha,r,g,b,mode)
|
|
-- 0 : fade Static element
|
|
-- 1 : fade text in Static
|
|
-- 2 : fade text in TextWnd
|
|
|
|
alpha = alpha or 255
|
|
r = r or 255
|
|
g = g or 255
|
|
b = b or 255
|
|
if not (cart_mode and cartmode_unfade) then
|
|
if (dist <= min) then
|
|
if dist < min then
|
|
alpha = alpha * (dist / min)
|
|
end
|
|
elseif dist > mid then
|
|
if (mid > 0) then
|
|
if (dist > (mid + max)) then
|
|
alpha = 0
|
|
elseif dist > mid then
|
|
alpha = alpha * (1 - ((dist - mid) / max))
|
|
end
|
|
end
|
|
end
|
|
end
|
|
if mode == 1 then
|
|
element:TextControl():SetTextColor(GetARGB(alpha,r,g,b))
|
|
elseif mode == 2 then
|
|
element:SetTextColor(GetARGB(alpha,r,g,b))
|
|
else
|
|
element:SetTextureColor(GetARGB(alpha,r,g,b))
|
|
end
|
|
end
|
|
|
|
|
|
function scale_by_dist(element,dist,w,h,min,mid,max,unsquish)
|
|
--printf("scale_by_dist for %sx%s element at dist %s | unsquish %s | %s - %s - %s ",w,h,dist,unsquish,min,mid,max)
|
|
dist = clamp(dist,0,max)
|
|
local nw = w
|
|
local nh = h
|
|
if (dist <= min) then
|
|
nw = w + ((1 - (dist / min)) * (w * 0.5))
|
|
nh = h + ((1 - (dist / min)) * (h * 0.5))
|
|
elseif dist > mid then
|
|
nw = w - (((dist - mid) / (max - mid)) * (w * 0.4)) -- trying 0.4 rather than 0.3 to bring down min size
|
|
nh = h - (((dist - mid) / (max - mid)) * (h * 0.4))
|
|
end
|
|
|
|
if unsquish then
|
|
nw = nw * unsquish_ratio
|
|
end
|
|
--printf("scale_by_dist for %sx%s element:\nw %s -> nw %s | h %s -> nh %s | ratio: %s",element:GetWidth(),element:GetHeight(),w,nw,h,nh,unsquish_ratio)
|
|
|
|
return nw,nh
|
|
end
|
|
|
|
|
|
local function zoom_delay_over() zoom_delay = false end
|
|
local zoom_delay = false
|
|
local last_zoom_coef = 1
|
|
local last_zoom_state = false
|
|
|
|
function get_current_zoom_coef()
|
|
if zoom_delay then return last_zoom_coef end
|
|
|
|
local obj = db.actor:active_item()
|
|
if (obj and IsWeapon(obj)) then
|
|
local wpn = obj:cast_Weapon()
|
|
end
|
|
|
|
local is_zoomed = axr_main.binoc_is_zoomed or (wpn and wpn:IsZoomed())
|
|
if is_zoomed ~= last_zoom_state then
|
|
last_zoom_state = is_zoomed
|
|
zoom_delay = true
|
|
CreateTimeEvent("zoomdelay","paw_zoom"..tostring(time_global()),0.25,tasks_placeable_waypoints.zoom_delay_over)
|
|
return last_zoom_coef
|
|
end
|
|
|
|
local fov = device().fov
|
|
local zoom_coef = fov / 85
|
|
last_zoom_coef = zoom_coef
|
|
|
|
return zoom_coef
|
|
end
|
|
|
|
|
|
function get_screen_coords(id)
|
|
local pos = nil
|
|
local is_npc,is_place
|
|
local obj = db.storage[id] and db.storage[id].object or level.object_by_id(id)
|
|
local se_obj = alife_object(id)
|
|
--printf("<PAW> get_screen_coords: id %s -> obj %s (%s) | se_obj %s",id,obj and obj:name(),obj and obj:id(),se_obj and se_obj:name())
|
|
if not (obj or se_obj) then
|
|
local is_wp = (id == (placed_waypoint and placed_waypoint.id)) and (not waypoint_canceling) and end_waypoint_task(id)
|
|
local pin = pins[id] and do_waypoint("pn_del",se_obj,nil,{syscall=true,id=id})
|
|
local exit = (is_wp and " canceling waypoint and") or (pin and " clearing pin and") or ""
|
|
dl("get_screen_coords: no valid game or server object could be found for %s,%s exiting",id,exit)
|
|
return
|
|
end
|
|
|
|
if (obj and IsStalker(obj) or IsMonster(obj)) then
|
|
pos = obj and utils_obj.safe_bone_pos(obj,"bip01_head")
|
|
is_npc = true
|
|
--printf("<PAW> Pinned object %s is an npc",id)
|
|
elseif (se_obj:clsid() == clsid.smart_terrain) or (se_obj:clsid() == clsid.script_zone) then
|
|
pos = se_obj.position
|
|
is_place = true
|
|
--printf("<PAW> Pinned object %s is a place",id)
|
|
elseif (obj and (type(obj.position) == "function")) then
|
|
local tmp = obj:position()
|
|
pos = tmp and vector():set(tmp.x,tmp.y,tmp.z)
|
|
end
|
|
|
|
if (pos == nil) then
|
|
if not (se_obj and se_obj.online) then
|
|
return nil
|
|
elseif (se_obj:clsid() == clsid.online_offline_group_s) then
|
|
local i = se_obj:commander_id()
|
|
local npc = i and db.storage[i] and db.storage[i].object or level.object_by_id(i)
|
|
pos = npc and utils_obj.safe_bone_pos(npc,"bip01_head")
|
|
is_npc = true
|
|
--printf("<PAW> Pinned object %s is an npc squad",id)
|
|
else
|
|
local tmp = se_obj and se_obj.position
|
|
pos = tmp and vector():set(tmp.x,tmp.y,tmp.z)
|
|
end
|
|
end
|
|
if not ((pos and pos.x) and (pos and pos.x) and (pos and pos.z)) then
|
|
dl("WARNING: unable to get valid pos for %s",id)
|
|
return nil
|
|
end
|
|
|
|
--printf("<PAW> pos found for id %s: %s,%s,%s",id,pos and pos.x,pos and pos.y,pos and pos.z)
|
|
|
|
local dist = db.actor:position():distance_to(pos)
|
|
local true_dist = dist -- store this
|
|
local min_dist = 0 -- distance floor for proximity adjustment range
|
|
local near_dist = 15 -- max dist where proximity adjustment range begins
|
|
local mid_dist = 15 -- dist at which far adjustments begin
|
|
local max_dist = 60 -- distance ceiling for the far adjustment range
|
|
local near_adj = 0 -- max icon vertical position change from proximity
|
|
local far_adj = 1.75 -- max icon vertical position change from distance
|
|
local vert_adj = 0 -- icon position above object will be adjusted by this
|
|
|
|
if is_place then
|
|
near_adj = 1.2 -- location spots are usually on or in the ground
|
|
elseif is_npc then
|
|
min_dist = 2 -- to allow for npc bounding box
|
|
near_adj = 0.45 -- max increase in height above npc head from proximity < 12m
|
|
end
|
|
local vert_adj = near_adj
|
|
local dist_prog = 0 -- 0 to 1 progress from beginning to end of adjustment range
|
|
local dist_coef = 1 -- 0 to 1 multiplier based on distance
|
|
dist = clamp(dist,min_dist,max_dist)
|
|
|
|
if (dist <= near_dist) then
|
|
dist_prog = ((near_dist - min_dist) - (dist - min_dist)) * 0.1
|
|
dist_coef = math.abs(math.sqrt(math.pow(dist_prog, 2)))
|
|
vert_adj = near_adj - (near_adj * dist_coef)
|
|
elseif (dist > mid_dist) then
|
|
local far_range = max_dist - mid_dist
|
|
local far_dist = dist - mid_dist
|
|
if dist >= max_dist then
|
|
dist_prog = 1
|
|
else
|
|
dist_prog = (far_dist / far_range)
|
|
end
|
|
dist_coef = dist_prog -- linear
|
|
--dist_coef = math.cos(((1 - dist_prog) * math.pi) / 2) -- eastInSine - this one works ok
|
|
--dist_coef = math.sin((dist_prog * math.pi) / 2) -- easeOutSine
|
|
--dist_coef = math.abs(math.sqrt(math.pow(dist_prog, 2)))
|
|
vert_adj = near_adj + (dist_coef * far_adj)
|
|
end
|
|
--local zoom_coef = get_current_fov_coef() or 1
|
|
local zoom_coef = (device().fov / 85)
|
|
|
|
pos.y = pos.y + 0.575 + (vert_adj * zoom_coef)
|
|
--printf("* Actor is %s from %s (near_dist %s | max_dist %s\n* dist_prog %s | dist_coef %s\n| Final vertical adjustment: %s",true_dist,id,near_dist,max_dist,dist_prog,dist_coef,vert_adj)
|
|
|
|
local vec = pos and game.world2ui(vector():set(pos.x,pos.y,pos.z),false)
|
|
--printf("final vec for %s: %s,%s",id,vec and vec.x,vec and vec.y)
|
|
if (vec and (vec.x ~= -9999) and (vec.y ~= 0)) then
|
|
return vec
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
-- ======================================================================
|
|
|
|
HUD_MT = nil
|
|
|
|
function show_hud_waypoint()
|
|
if not db.actor then return end
|
|
if (HUD_MT == nil) then
|
|
HUD_MT = UIPAWHUDWaypoint()
|
|
get_hud():AddDialogToRender(HUD_MT)
|
|
end
|
|
end
|
|
|
|
function hide_hud_waypoint()
|
|
if not db.actor then return end
|
|
if (HUD_MT ~= nil) then
|
|
HUD_MT:ShowDialog(false)
|
|
get_hud():RemoveDialogToRender(HUD_MT)
|
|
HUD_MT = nil
|
|
end
|
|
end
|
|
|
|
function update_hud_waypoint()
|
|
if not db.actor then return end
|
|
if (HUD_MT ~= nil) then
|
|
HUD_MT:Update(true)
|
|
end
|
|
end
|
|
|
|
-- ======================================================================
|
|
|
|
class "UIPAWHUDWaypoint" (CUIScriptWnd)
|
|
|
|
function UIPAWHUDWaypoint:__init() super()
|
|
self:InitControls()
|
|
RegisterScriptCallback("actor_on_net_destroy", self)
|
|
end
|
|
|
|
|
|
function UIPAWHUDWaypoint:__finalize()
|
|
end
|
|
|
|
|
|
function UIPAWHUDWaypoint:InitControls()
|
|
self:SetAutoDelete(true)
|
|
self.xml = CScriptXmlInit()
|
|
self.xml:ParseFile("paw_hud_wp_icon.xml")
|
|
self.marker = self.xml:InitStatic("marker",self)
|
|
self.dist = self.xml:InitStatic("marker:distance_sh:distance",self)
|
|
self.dist:TextControl():SetTextColor( GetARGB(255,230,230,230) )
|
|
self.dist:TextControl():SetFont(GetFontSmall())
|
|
self.dist_sh = self.xml:InitStatic("marker:distance_sh",self.dist)
|
|
self.dist_sh:TextControl():SetTextColor( GetARGB(255,0,0,0) )
|
|
self.dist_sh:TextControl():SetFont(GetFontSmall())
|
|
self.dist_sh:SetWndPos(vector2():set(1,1))
|
|
self.wref = self.xml:InitStatic("marker:distance_sh:distance",self.dist)
|
|
self.wref:TextControl():SetFont(GetFontSmall())
|
|
self.wref:Show(false)
|
|
end
|
|
|
|
|
|
function UIPAWHUDWaypoint:Destroy()
|
|
get_hud():RemoveDialogToRender(self)
|
|
end
|
|
|
|
|
|
function UIPAWHUDWaypoint:actor_on_net_destroy()
|
|
get_hud():RemoveDialogToRender(self)
|
|
end
|
|
|
|
|
|
|
|
function UIPAWHUDWaypoint:ShowMarker(onoff)
|
|
self.dist:Show(onoff and marker_dist_shown("wp"))
|
|
self.dist_sh:Show(onoff and marker_dist_shown("wp"))
|
|
self.marker:Show(onoff)
|
|
end
|
|
|
|
function UIPAWHUDWaypoint:Update()
|
|
CUIScriptWnd.Update(self)
|
|
if waypoint_active and (main_hud_shown() or axr_main.binoc_is_zoomed or axr_main.scoped_weapon_is_zoomed) and not waypoint_canceling then
|
|
local vec = placed_waypoint and placed_waypoint.id and get_screen_coords(placed_waypoint.id)
|
|
if (vec) then
|
|
self.marker:SetWndPos(vec)
|
|
local id = placed_waypoint and placed_waypoint.id
|
|
local se_obj = id and alife_object(id)
|
|
if se_obj then
|
|
local dist = db.actor:position():distance_to(se_obj.position)
|
|
local h,v = scale_by_dist(self.marker,dist,20,20,50,100,200,true)
|
|
self.marker:SetWndSize(vector2():set(h,v))
|
|
if marker_dist_shown("wp") then
|
|
local pos = self.marker:GetWndPos()
|
|
--local dist_txt = string.format("%.1f",dist)..ts("st_paw_meters_abbr")
|
|
local dist_txt = string.format("%.1f",dist).."m"
|
|
self.dist:Show(false)
|
|
self.dist_sh:Show(false)
|
|
self.dist:TextControl():SetText(dist_txt)
|
|
self.dist_sh:TextControl():SetText(dist_txt)
|
|
self.wref:TextControl():SetText(dist_txt)
|
|
self.wref:AdjustWidthToText()
|
|
local tw = self.wref:GetWidth()
|
|
self.dist:SetWndPos(vector2():set(pos.x - (tw / 2) - 1, pos.y + v - 8))
|
|
end
|
|
self:ShowMarker(se_obj.online and true)
|
|
end
|
|
return
|
|
end
|
|
self:ShowMarker(false)
|
|
else
|
|
self:ShowMarker(false)
|
|
end
|
|
end
|
|
|
|
-- ======================================================================
|
|
|
|
hud_pin_objs = {}
|
|
|
|
function update_hud_pins()
|
|
for k,v in pairs(hud_pin_objs) do
|
|
v:Update(true)
|
|
end
|
|
end
|
|
|
|
function hide_hud_pin(id)
|
|
if not id then return end
|
|
if hud_pin_objs[id] then
|
|
get_hud():RemoveDialogToRender(hud_pin_objs[id])
|
|
hud_pin_objs[id] = nil
|
|
end
|
|
end
|
|
|
|
function show_hud_pin(id)
|
|
vl("show_hud_pin called for pin ID %s",id)
|
|
if hud_pin_objs[id] then
|
|
hide_hud_pin(id)
|
|
end
|
|
hud_pin_objs[id] = UIPAWHUDPin(id)
|
|
get_hud():AddDialogToRender(hud_pin_objs[id])
|
|
end
|
|
|
|
function init_hud_pins()
|
|
for k,v in pairs(pins) do
|
|
local id = v and v.id
|
|
if id and v.hud then
|
|
local se_obj = alife_object(id)
|
|
if se_obj and se_obj.online then
|
|
show_hud_pin(id)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- ======================================================================
|
|
|
|
class "UIPAWHUDPin" (CUIScriptWnd)
|
|
|
|
function UIPAWHUDPin:__init(id) super()
|
|
self.pin_id = id
|
|
self.pin_se_obj = alife_object(id)
|
|
self:InitControls(id)
|
|
RegisterScriptCallback("actor_on_net_destroy", self)
|
|
RegisterScriptCallback("on_localization_change", self)
|
|
self.med_hint_font = (language == "rus")
|
|
end
|
|
|
|
|
|
function UIPAWHUDPin:__finalize()
|
|
end
|
|
|
|
|
|
function UIPAWHUDPin:InitControls(id)
|
|
self:SetAutoDelete(true)
|
|
self.xml = CScriptXmlInit()
|
|
self.xml:ParseFile("paw_hud_pin_icon.xml")
|
|
self.marker = self.xml:InitStatic("marker",self)
|
|
local tex = texture_for_icon(pins[id].icon)
|
|
local name = pins[id].text
|
|
self.marker:InitTexture(tex)
|
|
|
|
self.label = self.xml:InitStatic("marker:label",self)
|
|
self.label:TextControl():SetTextColor( GetARGB(255,230,230,230) )
|
|
|
|
self.label_sh = self.xml:InitStatic("marker:label_sh",self.label)
|
|
self.label_sh:TextControl():SetTextColor( GetARGB(255,0,0,0) )
|
|
self.label_sh:SetWndPos(vector2():set(1,1))
|
|
self.lref = self.xml:InitStatic("marker:label",self.label)
|
|
self.label:TextControl():SetText(name)
|
|
self.label_sh:TextControl():SetText(name)
|
|
self.lref:TextControl():SetFont(GetFontSmall())
|
|
self.lref:Show(false)
|
|
self:on_localization_change()
|
|
vl("Adding label %s to pin %s",name,self.pin_id)
|
|
|
|
self.dist = self.xml:InitStatic("marker:distance",self)
|
|
self.dist:TextControl():SetTextColor( GetARGB(255,230,230,230) )
|
|
self.dist:TextControl():SetFont(GetFontSmall())
|
|
self.dist_sh = self.xml:InitStatic("marker:distance_sh",self.dist)
|
|
self.dist_sh:TextControl():SetTextColor( GetARGB(255,0,0,0) )
|
|
self.dist_sh:TextControl():SetFont(GetFontSmall())
|
|
self.dist_sh:SetWndPos(vector2():set(1,1))
|
|
self.wref = self.xml:InitStatic("marker:distance",self.dist)
|
|
self.wref:TextControl():SetFont(GetFontSmall())
|
|
self.wref:Show(false)
|
|
self.last_dist = nil
|
|
|
|
--local np,dp = self.label:GetWndPos(),self.dist:GetWndPos()
|
|
--local nx,ny,dx,dy = np.x,np.y,dp.x,dp.y
|
|
--printf("Init: name pos %s,%s | dist pos %s,%s",nx,ny,dx,dy)
|
|
end
|
|
|
|
|
|
function UIPAWHUDPin:Destroy()
|
|
hide_hud_pin(self.pin_id)
|
|
get_hud():RemoveDialogToRender(self)
|
|
end
|
|
|
|
function UIPAWHUDPin:on_localization_change()
|
|
self.med_hint_font = (language == "rus")
|
|
if self.med_hint_font then
|
|
self.label:TextControl():SetFont(GetFontMedium())
|
|
self.label_sh:TextControl():SetFont(GetFontMedium())
|
|
self.lref:TextControl():SetFont(GetFontMedium())
|
|
else
|
|
self.label:TextControl():SetFont(GetFontSmall())
|
|
self.label_sh:TextControl():SetFont(GetFontSmall())
|
|
self.lref:TextControl():SetFont(GetFontSmall())
|
|
end
|
|
end
|
|
|
|
function UIPAWHUDPin:actor_on_net_destroy()
|
|
get_hud():RemoveDialogToRender(self)
|
|
end
|
|
|
|
function UIPAWHUDPin:ShowMarker(onoff)
|
|
self.dist:Show(onoff and marker_dist_shown("pins"))
|
|
self.dist_sh:Show(onoff and marker_dist_shown("pins"))
|
|
self.label:Show(onoff and marker_hint_shown("pins"))
|
|
self.label_sh:Show(onoff and marker_hint_shown("pins"))
|
|
self.marker:Show(onoff)
|
|
end
|
|
|
|
function UIPAWHUDPin:Update()
|
|
--printf("UIPAWHUDPin:Update")
|
|
if not (pins and pins[self.pin_id]) then
|
|
self:Destroy()
|
|
end
|
|
if item_device.is_pda_active() or not (self.pin_se_obj and self.pin_se_obj.online) then
|
|
self.marker:Show(false)
|
|
return
|
|
end
|
|
CUIScriptWnd.Update(self)
|
|
if (main_hud_shown() or axr_main.binoc_is_zoomed or axr_main.scoped_weapon_is_zoomed) then
|
|
local vec = self.pin_id and get_screen_coords(self.pin_id)
|
|
|
|
if (vec) then
|
|
local pindist = db.actor:position():distance_to(self.pin_se_obj.position)
|
|
local szx,szy = scale_by_dist(self.marker,pindist,24,24,10,20,50,true)
|
|
|
|
self.marker:SetWndPos(vec)
|
|
self.marker:SetWndSize(vector2():set(szx,szy))
|
|
|
|
local f_near = pin_near_fade_dist
|
|
local f_far = pin_far_fade_dist
|
|
local f_hide = pin_far_hide_dist
|
|
fade_by_dist(self.marker, pindist,f_near,f_far,f_hide)
|
|
fade_by_dist(self.label, pindist,f_near,f_far,f_hide,255,230,230,230,1)
|
|
fade_by_dist(self.label_sh, pindist,f_near,f_far,f_hide,255,0,0,0,1)
|
|
fade_by_dist(self.dist, pindist,f_near,f_far,f_hide,255,230,230,230,1)
|
|
fade_by_dist(self.dist_sh, pindist,f_near,f_far,f_hide,255,0,0,0,1)
|
|
|
|
local name = pins[self.pin_id].text
|
|
local maxd = 100
|
|
local disty = pindist
|
|
if pindist >= maxd then
|
|
disty = maxd
|
|
end
|
|
local yadj = (disty / maxd * 6)
|
|
local pos = self.marker:GetWndPos()
|
|
local nx,ny,dx,dy,tw
|
|
|
|
if marker_hint_shown("pins") then
|
|
self.label:TextControl():SetText(name)
|
|
self.label_sh:TextControl():SetText(name)
|
|
self.lref:TextControl():SetText(name)
|
|
self.lref:AdjustWidthToText()
|
|
tw = self.lref:GetWidth()
|
|
nx = pos.x - (tw * .5)
|
|
ny = pos.y - 22 + yadj
|
|
--printf("Container for pin %s is %sx%s",name,nx,ny)
|
|
self.label:SetWndPos(vector2():set(nx, ny))
|
|
end
|
|
|
|
if marker_dist_shown("pins") then
|
|
self.last_dist = pindist
|
|
--local dist_txt = string.format("%.1f",pindist)..ts("st_paw_meters_abbr")
|
|
local dist_txt = string.format("%.1f",pindist).."m"
|
|
self.dist:TextControl():SetText(dist_txt)
|
|
self.dist_sh:TextControl():SetText(dist_txt)
|
|
self.wref:TextControl():SetText(dist_txt)
|
|
self.wref:AdjustWidthToText()
|
|
tw = self.wref:GetWidth()
|
|
nx = pos.x - (tw * .5)
|
|
ny = pos.y + szy - 11 + yadj
|
|
self.dist:SetWndPos(vector2():set(nx, ny))
|
|
end
|
|
|
|
self:ShowMarker(true)
|
|
return
|
|
end
|
|
self:ShowMarker(false)
|
|
else
|
|
self:ShowMarker(false)
|
|
end
|
|
end
|
|
|
|
-- ======================================================================
|
|
-- HUD RETICLE (see ui_paw_reticle.script)
|
|
-- ======================================================================
|
|
|
|
HUD_RET = nil
|
|
|
|
function enable_vo_crosshair()
|
|
if not db.actor then return end
|
|
if (HUD_RET == nil) then
|
|
HUD_RET = ui_paw_reticle and ui_paw_reticle.UIPAWReticle()
|
|
if HUD_RET then
|
|
get_hud():AddDialogToRender(HUD_RET)
|
|
else
|
|
printf(logprefix.."ERROR: Unable to load ui_paw_reticle.script or initialize its HUD class")
|
|
end
|
|
end
|
|
end
|
|
|
|
function disable_vo_crosshair()
|
|
if not db.actor then return end
|
|
if (HUD_RET ~= nil) then
|
|
HUD_RET:ShowDialog(false)
|
|
get_hud():RemoveDialogToRender(HUD_RET)
|
|
HUD_RET = nil
|
|
end
|
|
end
|
|
|
|
function update_vo_crosshair()
|
|
if not db.actor then return end
|
|
if (HUD_RET ~= nil) then
|
|
HUD_RET:Update(true)
|
|
end
|
|
end
|
|
|
|
-- ======================================================================
|
|
-- CALLBACKS
|
|
-- ======================================================================
|
|
|
|
function npc_on_death_callback(victim,killer)
|
|
vl("npc_on_death_callback: %s (%s) | clear_pin_on_death: %s",victim:name(),victim:id(),clear_pin_on_death)
|
|
if not clear_pin_on_death then return end
|
|
local id = safeid(victim)
|
|
if not (id and (id > 0)) then return end
|
|
if not (id and pins[id]) then return end
|
|
dl("Clearing existing pin for dead body id %s",id)
|
|
local se_obj = alife_object(id)
|
|
do_waypoint("pn_del",se_obj,nil,{syscall=true})
|
|
end
|
|
|
|
|
|
function update_hud_on_show_hide()
|
|
update_hud_waypoint()
|
|
update_vo_crosshair()
|
|
update_hud_pins()
|
|
end
|
|
|
|
local mod_keys = {
|
|
[DIK_keys.DIK_LSHIFT] = {pressed=false,code=1},
|
|
[DIK_keys.DIK_LCONTROL] = {pressed=false,code=2},
|
|
[DIK_keys.DIK_LMENU] = {pressed=false,code=3},
|
|
}
|
|
local mod_key_codes = {
|
|
[1] = DIK_keys.DIK_LSHIFT,
|
|
[2] = DIK_keys.DIK_LCONTROL,
|
|
[3] = DIK_keys.DIK_LMENU,
|
|
}
|
|
local function mod_key_pressed(key)
|
|
if ui_mcm then
|
|
return ui_mcm.get_mod_key(key)
|
|
else
|
|
return mod_keys and mod_keys[key] and mod_keys[key].pressed
|
|
end
|
|
end
|
|
|
|
local function mod_key_held()
|
|
return
|
|
mod_keys[DIK_keys.DIK_LSHIFT].pressed or
|
|
mod_keys[DIK_keys.DIK_LCONTROL].pressed or
|
|
mod_keys[DIK_keys.DIK_LMENU].pressed
|
|
end
|
|
|
|
function on_key_press(key)
|
|
--if not active_binds[key] then return end
|
|
--printf("Monitored keybind %s pressed",key)
|
|
local args
|
|
if mod_keys[key] then
|
|
mod_keys[key].pressed = true
|
|
return
|
|
end
|
|
--local keyname = DIK_name(key)
|
|
--vl("on_key_press(%s) : %s\nModifiers held: Shift %s | Ctrl %s | Alt %s",key,keyname,mod_key_pressed(1),mod_key_pressed(2),mod_key_pressed(3))
|
|
for k,v in pairs(keybinds) do
|
|
if v and v.enabled then
|
|
--local bindtxt = bindtext(v.bind,v.mod)
|
|
--vl("** Checking keybind %s (bind %s | mod %s | hold %s)",k,bindtxt,v.bind,v.mod,v.hold)
|
|
if (key == v.bind) and mod_key_pressed(v.mod) then
|
|
--vl("on_key_press(%s): keybind %s matched %s with bind %s and mod %s",key,k,bindtxt,v.bind,mod)
|
|
if v.hold then
|
|
args = true
|
|
end
|
|
v.action(args)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
--vl("on_key_press: no matching keybind for %s",keyname)
|
|
end
|
|
|
|
|
|
function on_key_release(key)
|
|
local do_action = false
|
|
if mod_keys[key] then
|
|
mod_keys[key].pressed = false
|
|
end
|
|
|
|
--local keyname = DIK_name(key)
|
|
--vl("on_key_release(%s) : %s\nModifiers held: Shift %s | Ctrl %s | Alt %s",key,keyname,mod_key_pressed(1),mod_key_pressed(2),mod_key_pressed(3))
|
|
for k,v in pairs(keybinds) do
|
|
if v and v.enabled and v.hold then
|
|
--local bindtxt = bindtext(v.bind,v.mod)
|
|
--vl("** Checking keybind %s: %s (bind %s | mod %s | hold %s)",k,bindtxt,v.bind,v.mod,v.hold)
|
|
if (key == v.bind) and mod_key_pressed(v.mod) then
|
|
--vl("on_key_release(%s): keybind %s matched %s with bind %s and mod %s",key,k,bindtxt,v.bind,mod)
|
|
v.action(false)
|
|
return
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
|
|
function on_map_right_click(property_ui, map_table)
|
|
if not map_table then return end
|
|
if map_table.object_id ~= 65535 then return end
|
|
|
|
local pos = map_table.pos
|
|
local se_obj = register_script_zone(pos,map_table.lvid,map_table.gvid)
|
|
map_table.object_id = se_obj and se_obj.id
|
|
|
|
if not se_obj then
|
|
dl("<PAW> Right-click capture failed - unable to find or create valid se_obj")
|
|
return
|
|
else
|
|
if mod_key_pressed(1) then
|
|
-- LSHIFT : unused
|
|
elseif mod_key_pressed(2) then
|
|
-- LCTRL : Set/Move Waypoint
|
|
if waypoint_active then
|
|
do_waypoint("wp_mov",se_obj)
|
|
else
|
|
do_waypoint("wp_set",se_obj)
|
|
end
|
|
return
|
|
elseif mod_key_pressed(3) then
|
|
-- LALT : Add Pin
|
|
do_waypoint("pn_add",se_obj)
|
|
return
|
|
end
|
|
dl("<PAW> Passing right-click to get_context_menu_options with id %s and pos %s",se_obj.id,pos)
|
|
last_clicked_id = se_obj.id
|
|
get_context_menu_options(property_ui,se_obj.id,map_table)
|
|
end
|
|
end
|
|
|
|
function map_spot_menu_add_property(property_ui,id)
|
|
last_clicked_id = id
|
|
get_context_menu_options(property_ui,id)
|
|
end
|
|
|
|
|
|
function map_spot_menu_property_clicked(property_ui,id,level_name,prop)
|
|
execute_context_menu_option(property_ui,id,level_name,prop)
|
|
end
|
|
|
|
|
|
function load_file_data()
|
|
dl("<PAW> Loading file data and populating tables")
|
|
local attr_tex = "texture"
|
|
local minimap = "mini_map"
|
|
local levelmap = "level_map"
|
|
local ind = 0
|
|
xml = CScriptXmlInit()
|
|
xml:ParseFile("map_spots.xml")
|
|
for k,v in pairs(icons) do
|
|
local tex,th,tw
|
|
local spot = v
|
|
xml:NavigateToRoot()
|
|
th = xml:ReadAttribute(spot,0,"height")
|
|
tw = xml:ReadAttribute(spot,0,"width")
|
|
xml:NavigateToNode(spot,0)
|
|
vl("trying to find texture data for %s | %s",k,v)
|
|
if xml:NodeExist(attr_tex,0) then
|
|
tex = xml:ReadValue(attr_tex,0)
|
|
vl("texture node found with value %s",tex)
|
|
else
|
|
local spotnode = ""
|
|
local typ = ""
|
|
if xml:NodeExist(minimap) then
|
|
spotnode = xml:ReadAttribute(minimap,0,"spot")
|
|
typ = minimap
|
|
end
|
|
if xml:NodeExist(levelmap) then
|
|
spotnode = xml:ReadAttribute(levelmap,0,"spot")
|
|
typ = levelmap
|
|
end
|
|
if spotnode ~= "" then
|
|
xml:NavigateToRoot()
|
|
th = xml:ReadAttribute(spotnode,0,"height")
|
|
tw = xml:ReadAttribute(spotnode,0,"width")
|
|
vl("ReadAttribute for %s: h %s w %s",v,th,tw)
|
|
xml:NavigateToNode(spotnode,0)
|
|
tex = xml:ReadValue(attr_tex,0)
|
|
vl("%s node found: %s",typ,spotnode)
|
|
end
|
|
end
|
|
|
|
if spot == "paw_pin_redpush32" then
|
|
if not tex then return false end
|
|
end
|
|
|
|
texture_data[spot] = {
|
|
id = k,
|
|
t = tex,
|
|
h = th,
|
|
w = tw,
|
|
}
|
|
ind = ind + 1
|
|
icon_index[ind] = {
|
|
id = k,
|
|
icon = spot,
|
|
data = texture_data[spot],
|
|
}
|
|
vl("Texture for %s: %s (%sx%s)",spot,tex,tw,th)
|
|
end
|
|
current_ico_max = ind
|
|
for k,v in pairs(texture_data) do
|
|
dl("texture_data(%s): tex %s | id %s | %sx%s",k,v.t,v.id,v.w,v.h)
|
|
end
|
|
|
|
ind = 0
|
|
for w, _ in pairs(iconset_ltx) do
|
|
local iconset_ltx_prefix = "iconset_"
|
|
local icons_pos = string.find(w,iconset_ltx_prefix)
|
|
if icons_pos == 1 then
|
|
local group = string.sub(w,icons_pos+string.len(iconset_ltx_prefix))
|
|
local set_cfg = icon_sets_ini:collect_section(w)
|
|
local name = set_cfg.name
|
|
local def = set_cfg.default
|
|
local sec_list = group.."_icons"
|
|
ind = ind + 1
|
|
icon_sets[group] = {
|
|
name = name,
|
|
group = group,
|
|
default = def,
|
|
active_icon = icons[def],
|
|
i = ind,
|
|
}
|
|
local setdata = icon_sets[group]
|
|
set_index[ind] = {
|
|
id = group,
|
|
data = setdata,
|
|
}
|
|
dl("Found icon set %s with group %s, section %s",setdata.name,group,sec_list)
|
|
set_index[ind].ii = {}
|
|
setdata.ii = {}
|
|
setdata.ri = {}
|
|
local iconlist = {}
|
|
local il = icon_sets_ini:collect_section(sec_list)
|
|
local i = 0
|
|
for k,_ in pairs(il) do
|
|
i = i + 1
|
|
local spot = icons[k]
|
|
vl("set %s iconlist: icons[%s] = %s",group,k,spot)
|
|
iconlist[spot] = texture_data[spot].t
|
|
set_index[ind].ii[i] = spot
|
|
setdata.ii[i] = spot
|
|
setdata.ri[spot] = i
|
|
end
|
|
setdata.inum = i
|
|
setdata.icons = iconlist
|
|
end
|
|
end
|
|
current_set_max = ind
|
|
dl("Loading menu actions from actions_ini")
|
|
for w, _ in pairs(actions_ltx) do
|
|
action_codes[w] = actions_ini:collect_section(w)
|
|
local ac = action_codes[w]
|
|
local opt_loc = ts(ac.text)
|
|
dl("<PAW> ac.mode: %s | type: %s | as num: %s | >0: %s",ac and ac.mode,ac and type(ac.mode),ac and tonumber(ac.mode),ac and (tonumber(ac.mode) > 0))
|
|
ac.mode = clamp(tonumber(ac and ac.mode) or 0,0,4)
|
|
ac.enable = (ac.enable == "true")
|
|
action[opt_loc] = w
|
|
if verbose then
|
|
vl("Initializing menu action:\n%s = %s",opt_loc,action[opt_loc])
|
|
for k,v in pairs(ac) do vl("%s = %s",k,v) end
|
|
end
|
|
end
|
|
|
|
dl("Loading and parsing valid clsids (%s)",size_table(clsids_ltx))
|
|
for k,v in pairs(clsids_ltx) do
|
|
dl("%s = %s",k,v)
|
|
if v == "number" then
|
|
local k1 = tonumber(k)
|
|
if k1 and k1 > 0 then
|
|
vl("Found valid clsid number value: %s",k1)
|
|
valid_clsids[tonumber(k1)] = true
|
|
end
|
|
elseif v == "string" then
|
|
if k and clsid[k] then
|
|
local k1 = tonumber(clsid[k])
|
|
vl("Found valid clsid string value: %s = %s",k,k1)
|
|
valid_clsids[tonumber(k1)] = true
|
|
end
|
|
end
|
|
end
|
|
table.sort(icons)
|
|
table.sort(icon_sets)
|
|
catsy_paw_mcm.icon_sets = icon_sets
|
|
table.sort(action_codes)
|
|
dl(logprefix.."All file data loaded")
|
|
--utils_data.print_table(icon_sets)
|
|
started = true
|
|
local load_set_curr = axr_main.config:r_value("mcm", "pawsys/pawpins/pin_icon_group", {val=0}) or "pins"
|
|
local load_pin_curr = axr_main.config:r_value("mcm", "pawsys/pawpins/poi_icon_"..load_set_curr, {val=0})
|
|
|
|
printf(logprefix.."Personal Adjustable Waypoint started at %s",time_global())
|
|
return true
|
|
end
|
|
|
|
|
|
function load_state(data)
|
|
dl("load_state: Checking for saved PAW data")
|
|
|
|
local ps = data.pawsys
|
|
local pd = data.pawdata
|
|
if ps then
|
|
vl("load_state: pawsys found, loading")
|
|
placed_waypoint = ps.current_waypoint
|
|
last_waypoint = ps.last_waypoint
|
|
custom_name = ps.custom_name
|
|
custom_desc = ps.custom_desc
|
|
pins = ps.pins
|
|
if placed_waypoint then waypoint_active = true end
|
|
welcome_msg_shown = ps.welcome_msg_shown
|
|
|
|
end
|
|
if pd and pd.valid then
|
|
dl("load_state: pawdata found, loading")
|
|
pawdata = pd
|
|
pins = pawdata.pins
|
|
else
|
|
dl("load_state: pawdata not found, initializing")
|
|
pawdata.curr_set_name = "pins"
|
|
pawdata.curr_set_data = icon_sets[pawdata.curr_set_name]
|
|
local setdata = pawdata.curr_set_data
|
|
pawdata.curr_set_data = setdata
|
|
pawdata.curr_set_ind = setdata.i
|
|
pawdata.curr_ico_name = setdata.active_icon
|
|
pawdata.curr_ico_ind = setdata.ri[root_patch_name(setdata.active_icon)]
|
|
vl("pawdata: set %s (%s) | icon %s (%s)",pawdata.curr_set_name,pawdata.curr_set_ind,pawdata.curr_ico_name,pawdata.curr_ico_ind)
|
|
end
|
|
end
|
|
|
|
|
|
function save_state(data)
|
|
update_mcm_icoset_data()
|
|
dl("save_state: Cleaning up script zones and temp markers")
|
|
_ = script_zone_cleanup()
|
|
dl("save_state: Saving waypoint and config data")
|
|
data.paw_waypoint_info = nil
|
|
data.pawsys = {}
|
|
data.pawsys.current_waypoint = placed_waypoint
|
|
data.pawsys.last_waypoint = last_waypoint
|
|
data.pawsys.custom_name = custom_name
|
|
data.pawsys.custom_desc = custom_desc
|
|
data.pawsys.dynamic_faves = dynamic_faves
|
|
data.pawsys.welcome_msg_shown = welcome_msg_shown
|
|
data.pawsys.pins = {}
|
|
pawdata.valid = true
|
|
data.pawdata = pawdata
|
|
dl("save_state: Saving player's pins")
|
|
data.pawsys.pins = pins
|
|
end
|
|
|
|
function actor_on_update()
|
|
tick()
|
|
end
|
|
|
|
function actor_on_first_update()
|
|
on_option_change()
|
|
if not paw_enabled then
|
|
UnregisterScriptCallback("actor_on_update",actor_on_update)
|
|
return
|
|
end
|
|
temp_pin_cleanup(true)
|
|
active_set(icon_sets[current_active_set].i)
|
|
show_all_pins(true)
|
|
if waypoint_active then
|
|
local id = placed_waypoint.id
|
|
local se_obj = alife_object(id)
|
|
if not se_obj then return end
|
|
local savelast = last_waypoint
|
|
do_waypoint("wp_mov",se_obj)
|
|
last_waypoint = savelast
|
|
end
|
|
reset_indicator()
|
|
if wp_hud_icon_enabled then
|
|
show_hud_waypoint()
|
|
else
|
|
hide_hud_waypoint()
|
|
end
|
|
if reticle_mode > 0 then
|
|
enable_vo_crosshair()
|
|
else
|
|
disable_vo_crosshair()
|
|
end
|
|
|
|
init_hud_pins()
|
|
if not welcome_msg_shown then
|
|
CreateTimeEvent("paw_welcome_message",0,5,paw_welcome_message)
|
|
end
|
|
end
|
|
|
|
|
|
function actor_on_net_destroy()
|
|
script_zone_cleanup()
|
|
hide_hud_waypoint()
|
|
empty_table(hud_pin_objs)
|
|
end
|
|
|
|
function on_mouse_wheel(scroll_dir, flags)
|
|
if not mwheel_enabled then
|
|
UnregisterScriptCallback("on_mouse_wheel",on_mouse_wheel)
|
|
return
|
|
end
|
|
if not (icon_cycle_active or set_cycle_active) then return end
|
|
if actor_menu.inventory_opened() then return end
|
|
|
|
flags.ret_value = false
|
|
local now = time_global()
|
|
if now < mwheel_next_poll then return end
|
|
mwheel_next_poll = now + mwheel_poll_interval
|
|
-- local cycle_dir = ((scroll_dir == 0) and -1) or scroll_dir
|
|
local cycle_dir = scroll_dir
|
|
if cycle_dir == 0 then cycle_dir = -1 end
|
|
vl("scroll_dir: %s | cycle_dir: %s",scroll_dir,cycle_dir)
|
|
cycle_items(cycle_dir)
|
|
end
|
|
|
|
|
|
function unregister_all_callbacks()
|
|
UnregisterScriptCallback("actor_on_update",actor_on_update)
|
|
UnregisterScriptCallback("actor_on_net_destroy",actor_on_net_destroy)
|
|
UnregisterScriptCallback("actor_on_first_update",actor_on_first_update)
|
|
UnregisterScriptCallback("load_state",load_state)
|
|
UnregisterScriptCallback("save_state",save_state)
|
|
UnregisterScriptCallback("map_spot_menu_add_property",map_spot_menu_add_property)
|
|
UnregisterScriptCallback("map_spot_menu_property_clicked",map_spot_menu_property_clicked)
|
|
UnregisterScriptCallback("on_key_press",on_key_press)
|
|
UnregisterScriptCallback("on_key_release",on_key_release)
|
|
UnregisterScriptCallback("GUI_on_show",update_hud_on_show_hide)
|
|
UnregisterScriptCallback("GUI_on_hide",update_hud_on_show_hide)
|
|
UnregisterScriptCallback("monster_on_death_callback",npc_on_death_callback)
|
|
UnregisterScriptCallback("npc_on_death_callback",npc_on_death_callback)
|
|
if mwheel_avail then
|
|
UnregisterScriptCallback("on_mouse_wheel",on_mouse_wheel)
|
|
end
|
|
if right_click_avail then
|
|
UnregisterScriptCallback("on_map_right_click",on_map_right_click)
|
|
end
|
|
end
|
|
|
|
function register_all_callbacks()
|
|
RegisterScriptCallback("actor_on_update",actor_on_update)
|
|
RegisterScriptCallback("actor_on_net_destroy",actor_on_net_destroy)
|
|
RegisterScriptCallback("actor_on_first_update",actor_on_first_update)
|
|
RegisterScriptCallback("load_state",load_state)
|
|
RegisterScriptCallback("save_state",save_state)
|
|
RegisterScriptCallback("map_spot_menu_add_property",map_spot_menu_add_property)
|
|
RegisterScriptCallback("map_spot_menu_property_clicked",map_spot_menu_property_clicked)
|
|
RegisterScriptCallback("on_key_press",on_key_press)
|
|
RegisterScriptCallback("on_key_release",on_key_release)
|
|
RegisterScriptCallback("GUI_on_show",update_hud_on_show_hide)
|
|
RegisterScriptCallback("GUI_on_hide",update_hud_on_show_hide)
|
|
RegisterScriptCallback("monster_on_death_callback",npc_on_death_callback)
|
|
RegisterScriptCallback("npc_on_death_callback",npc_on_death_callback)
|
|
if mwheel_avail then
|
|
RegisterScriptCallback("on_mouse_wheel",on_mouse_wheel)
|
|
end
|
|
if right_click_avail then
|
|
RegisterScriptCallback("on_map_right_click",on_map_right_click)
|
|
end
|
|
end
|
|
|
|
function on_game_start()
|
|
if load_failed then return end
|
|
RegisterScriptCallback("on_option_change",on_option_change)
|
|
register_all_callbacks()
|
|
on_option_change()
|
|
end
|
|
|
|
|
|
-- ======================================================================
|
|
-- TASK FUNCTORS
|
|
-- ======================================================================
|
|
|
|
|
|
task_functor.waypoint_task_target_functor = function (task_id,field,p,tsk)
|
|
if not paw_enabled then return end
|
|
-- vl("waypoint_task_target_functor called with task_id %s | field %s",task_id,field)
|
|
|
|
if placed_waypoint == nil then
|
|
dl("WARNING: waypoint_task_target_functor called but placed_waypoint is nil, cancelling waypoint task to avoid crash")
|
|
end_waypoint_task()
|
|
return default_id
|
|
end
|
|
|
|
if (field == "target") then
|
|
tsk.target = placed_waypoint.id
|
|
tsk.current_target = placed_waypoint.id
|
|
return placed_waypoint.id
|
|
end
|
|
end
|
|
|
|
|
|
task_functor.waypoint_task_text_functor = function (task_id,field,p,tsk)
|
|
if not (paw_enabled and placed_waypoint) then return end
|
|
-- vl("waypoint_task_text_functor called with task_id %s | field %s",task_id,field)
|
|
if (field == "title") then
|
|
-- vl("custom_name: %s")
|
|
return custom_name or ts("st_paw_placed_waypoint")..(": "..placed_waypoint.name or "")
|
|
elseif (field == "descr") then
|
|
-- vl("custom_desc: %s")
|
|
return custom_desc or ts("st_paw_proceed")
|
|
end
|
|
end
|
|
|
|
-- ======================================================================
|
|
-- LOAD FILE DATA - KILLSWITCH AND NOTIFY ON FAILURE
|
|
-- ======================================================================
|
|
|
|
if not load_file_data() then
|
|
disable_mcm_updates = true
|
|
load_failed = true
|
|
paw_enabled = false
|
|
started = false
|
|
_ = unregister_all_callbacks()
|
|
|
|
if not disable_load_warning then
|
|
local tiperr = psk(game.translate_string("st_paw_texture_load_error_tip"),text_colors)
|
|
RegisterScriptCallback("actor_on_first_update",
|
|
function()
|
|
CreateTimeEvent("pawerror",0,5,(
|
|
function()
|
|
db.actor:give_game_news("PAW System",tiperr,"ui_inGame2_Mesta_evakuatsii",0,15000)
|
|
xr_sound.set_sound_play(AC_ID,"pda_tips")
|
|
return true
|
|
end
|
|
))
|
|
end
|
|
)
|
|
end
|
|
|
|
local errstr = game.translate_string("st_paw_texture_load_error1").."\n\n"..game.translate_string("st_paw_texture_load_error2")
|
|
assert(not load_failed, "\n\n"..
|
|
"~ ------------------------------------------------------------------------\n"..
|
|
errstr.."\n"..
|
|
"~ ------------------------------------------------------------------------\n"
|
|
)
|
|
end
|
|
|
|
-- ======================================================================
|