2024-03-17 20:18:03 -04:00
-- ======================================================================
--[[ 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
2024-03-20 06:40:41 -04:00
Version: 2.1.2
Updated: 20240320
2024-03-17 20:18:03 -04:00
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.
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
-- ======================================================================
-- SHORTCUTS, FLAGS, AND SYSTEM STUFF
(Most of which you probably shouldn't muck with)
-- ===================================================================--]]
2024-03-20 06:40:41 -04:00
script_version = "2.1.2"
release_date = 20240320
2024-03-17 20:18:03 -04:00
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.
-- ======================================================================
2024-03-20 06:40:41 -04:00
modxml_map_spots_paw.load_me = function() end -- forces DXML mapspots to load
2024-03-17 20:18:03 -04:00
-- ======================================================================
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
2024-03-20 06:40:41 -04:00
welcome_msg_shown = false -- if you don't have MCM, setting this true will disable the welcome message
2024-03-17 20:18:03 -04:00
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")
2024-03-20 06:40:41 -04:00
local gamma_modpack = game_version:find("G.A.M.M.A.") -- GAMMA now supports both features (mwheel and rclick)
mwheel_avail = mousewheel_override or gamma_modpack or (MODDED_EXES_VERSION and (MODDED_EXES_VERSION >= mwheel_exe_ver))
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
local pin_tooltip_mode = 2
2024-03-17 20:18:03 -04:00
-- ======================================================================
enable_wp_proxcheck = true
show_pins = true
2024-03-20 06:40:41 -04:00
local script_zone_changed = false -- runtime flag
2024-03-17 20:18:03 -04:00
local custom_task_info = false
local icon_cycle_active = false
local set_cycle_active = false
2024-03-20 06:40:41 -04:00
local psw_sidebar_state = true
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
autotag_mode = 0
autotag_milpda_feature = true
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
clear_pin_on_death = true -- when set on a living thing, pin will be cleared if it 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 = 100 -- distance beyond which pins will begin to fade out, set to 0 to disable
pin_far_hide_dist = 150 -- max distance after far_fade at which pins will hide, set to 0 to disable
wp_near_fade_dist = 5 -- same but for waypoints
wp_far_fade_dist = 100 -- same but for waypoints
wp_far_hide_dist = 150 -- same but for waypoints
2024-03-17 20:18:03 -04:00
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"
2024-03-20 06:40:41 -04:00
local snd_place_pin = snd_path.."paw_pin"
local snd_note = "device\\pda\\pda_note"
2024-03-17 20:18:03 -04:00
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_"
2024-03-20 06:40:41 -04:00
local hint_path = "ui_paw_hint_"
2024-03-17 20:18:03 -04:00
-- 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
2024-03-20 06:40:41 -04:00
use_custom_backpack_icon = false -- Customize the icon for player stashes
init_backpack_as_pin = true -- Player stash icons are created as pins
2024-03-17 20:18:03 -04:00
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 = {}
2024-03-20 06:40:41 -04:00
map_labels = {}
waypoint_history = {} -- not implemented yet
2024-03-17 20:18:03 -04:00
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 = {},
}
2024-03-20 06:40:41 -04:00
pawdata.wphist = {}
waypoint_history = pawdata.wphist
2024-03-17 20:18:03 -04:00
npc_ident = pawdata.npc_ident
smart_pins = pawdata.smart_pins
pins = pawdata.pins
2024-03-20 06:40:41 -04:00
dynamic_faves = pawdata.dynamic_faves -- not implemented yet
2024-03-17 20:18:03 -04:00
-- ======================================================================
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,
-- },
}
2024-03-20 06:40:41 -04:00
local default_stash_icon_basic = "treasure"
local default_stash_icon_rare = "treasure_searched"
local default_stash_icon_isg = "treasure_unique"
local default_stash_icon_player = "paw_stash_backpack"
stash_icons = {
["basic"] = axr_main.config:r_value("mcm", "pawsys/custom_stash_icon_basic", {val=0}) or default_stash_icon_basic, -- Normal stashes
["rare"] = axr_main.config:r_value("mcm", "pawsys/custom_stash_icon_rare", {val=0}) or default_stash_icon_rare, -- Rare stashes
["isg"] = axr_main.config:r_value("mcm", "pawsys/custom_stash_icon_isg", {val=0}) or default_stash_icon_isg, -- Special (e.g. ISG) stashes
["player"] = axr_main.config:r_value("mcm", "pawsys/custom_stash_icon_player", {val=0}) or default_stash_icon_player, -- Custom player backpack stashes
}
2024-03-17 20:18:03 -04:00
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,
2024-03-20 06:40:41 -04:00
["waypoint_rename"] = true, -- deprecated, included here so it doesn't appear if someone re-adds it
["waypoint_redesc"] = true, -- deprecated
2024-03-17 20:18:03 -04:00
["hud_vis_on"] = true,
["hud_vis_off"] = true,
["show_all_pins"] = true,
["hide_all_pins"] = true,
2024-03-20 06:40:41 -04:00
["show_label"] = true,
["hide_label"] = true,
2024-03-17 20:18:03 -04:00
["pn_add"] = true,
["pn_del"] = true,
2024-03-20 06:40:41 -04:00
["pn_ren"] = true, -- deprecated
2024-03-17 20:18:03 -04:00
["pn_clr"] = true,
2024-03-20 06:40:41 -04:00
["pn_settings"] = true,
["wp_settings"] = true,
2024-03-17 20:18:03 -04:00
["lock_pin"] = true,
["unlock_pin"] = true,
2024-03-20 06:40:41 -04:00
["convert_to_pin"] = true,
2024-03-17 20:18:03 -04:00
["cm_dbg"] = true,
}
hud_themes = {
["classicauto"] = {
name = "classicauto",
node = "pawhudind",
style = "full",
tex = "ui_paw_hud_indicator_classic",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
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",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
pos = {x=890,y=620},
w = 136,
h = 75,
},
["vertright"] = {
name = "vertright",
node = "pawhudind_vertright",
style = "minimal",
tex = "ui_paw_hud_indicator_vertright",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
pos = {x=922,y=440},
w = 100,
h = 154,
},
["vertleft"] = {
name = "vertleft",
node = "pawhudind_vertleft",
style = "minimal",
tex = "ui_paw_hud_indicator_vertleft",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
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",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
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",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
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",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
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",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
pos = {x=924,y=440},
w = 92,
h = 112,
},
["minicom"] = {
name = "minicom",
node = "pawhudind_minicom",
style = "compact",
tex = "ui_paw_hud_indicator_minicom",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
pos = {x=820,y=725},
w = 38,
h = 37,
},
["compact_noui"] = {
name = "compact_noui",
node = "pawhudind_minicom",
style = "compact",
2024-03-20 06:40:41 -04:00
file = "paw_ui_elements.xml",
2024-03-17 20:18:03 -04:00
pos = {x=820,y=725},
w = 32,
h = 37,
pre_tex = "ui_paw_hud_indicator_minicom",
},
2024-03-20 06:40:41 -04:00
["pin_sidebar"] = {
name = "pin_sidebar",
node = "pawhudind_pin_sidebar",
style = "full",
tex = "ui_paw_dialog_sidebar",
file = "paw_ui_elements.xml",
pos = {x=0,y=0},
w = 161.25,
h = 188,
},
2024-03-17 20:18:03 -04:00
}
colors = {
dimmed = GetARGB(100, 255, 255, 255),
active = GetARGB(255, 255, 255, 255),
}
text_colors = {
2024-03-20 06:40:41 -04:00
["clr_255"] = "%" .. "%c[255,255,255,255]",
["clr_red"] = "%" .. "%c[255,255,0,0]",
["clr_orn"] = "%" .. "%c[255,255,140,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]",
2024-03-17 20:18:03 -04:00
["clr_blk"] = "%" .. "%c[255,0,0,0]",
}
2024-03-20 06:40:41 -04:00
null_tokens = {
["clr_255"] = "",
["clr_red"] = "",
["clr_grn"] = "",
["clr_blu"] = "",
["clr_lbl"] = "",
["clr_yel"] = "",
["clr_wht"] = "",
["clr_prp"] = "",
["clr_blk"] = "",
}
2024-03-17 20:18:03 -04:00
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,
},
}
2024-03-20 06:40:41 -04:00
local hover_elements = {
["btn_iprev"] = "icon",
["btn_inext"] = "icon",
["btn_sprev"] = "set",
["btn_snext"] = "set",
["logo_set"] = "set",
["box_curr"] = "icon",
["box_prev"] = "icon",
["box_next"] = "icon",
["box_text"] = "set",
["box_text2"] = "icon",
["btn_apply"] = "icon",
}
2024-03-17 20:18:03 -04:00
-- ======================================================================
-- 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
2024-03-20 06:40:41 -04:00
CreateTimeEvent("pawdelay","paw"..tostring(time_global()),secs,func,...)
2024-03-17 20:18:03 -04:00
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()
2024-03-20 06:40:41 -04:00
if pins[id] and not script_zones[id] then
-- If there's a pin for this ID, use its text above all else
text = pins[id].name
2024-03-17 20:18:03 -04:00
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()
2024-03-20 06:40:41 -04:00
local dev = db.actor and db.actor:item_in_slot(8)
2024-03-17 20:18:03 -04:00
local sec = dev and dev:section()
2024-03-20 06:40:41 -04:00
if not sec then return false end
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
function play_ui_sound(effect)
if effect and use_ui_snd then
play_sound_for_actor(effect)
end
end
2024-03-17 20:18:03 -04:00
function add_mapspot(text,id,icon)
if not id then return end
icon = icon or default_mapspot
2024-03-20 06:40:41 -04:00
text = text or get_tooltip_for_pin(id) or ""
2024-03-17 20:18:03 -04:00
vl("Adding mapspot %s for id %s with icon %s",text,id,icon)
level.map_add_object_spot(id,icon,text)
2024-03-20 06:40:41 -04:00
if not pins[id] then return end
local pin = pins[id]
if pin.custom_colors and pin.colors then
local clr = pin.colors
local spot = level.map_get_object_spot_static(id,icon)
spot:SetTextureColor(GetARGB(clr.a, clr.r, clr.g, clr.b))
end
if pin.hud then
show_hud_pin(id)
end
if pin.show_label then
show_pin_label(id,true)
end
return true
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
local pin = pins[id]
if pin and pin.show_label then
show_pin_label(id,false,true)
end
if pin and pin.hud then
hide_hud_pin(id)
end
2024-03-17 20:18:03 -04:00
level.map_remove_object_spot(id,icon)
2024-03-20 06:40:41 -04:00
level.map_remove_object_spot(id,icon) -- this operation sometimes doesn't work the first time
2024-03-17 20:18:03 -04:00
return true
end
2024-03-20 06:40:41 -04:00
function change_mapspot(text,id,icon,old_icon)
if not id then return end
text = text or get_tooltip_for_pin(id)
icon = icon or (pins and pins[id] and pins[id].icon) or default_mapspot
old_icon = old_icon or icon
vl("Trying to change mapspot with id %s from icon %s to icon %s with text %s",id,old_icon,icon,text)
remove_mapspot(id,old_icon)
return add_mapspot(text,id,icon)
end
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
function get_tooltip_for_pin(id)
local pin = pins and pins[id]
local text = ""
if pin then
local mode = pin.tooltip or pin_tooltip_mode
if mode > 1 then
text = pin.text or pin.name or ts("st_paw_pin_default_name")
elseif mode > 0 then
text = pin.name or ts("st_paw_pin_default_name")
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
vl("get_tooltip_for_pin(%s): tooltip mode %s\n* Returning hint: \"%s\"",id,mode,text)
return text
end
end
function has_mapspot(id,icon)
return level.map_has_object_spot(id,icon) == 1
end
function get_mapspot(id,icon)
local found
if icon then
return has_mapspot(id,icon) and icon
2024-03-17 20:18:03 -04:00
else
2024-03-20 06:40:41 -04:00
for k,v in pairs(stash_icons) do
local has_spot = has_mapspot(id,v)
--printf("id %s has mapspot %s: %s",id,v,has_spot)
if has_spot then
found = v
--printf("found %s",found)
--return v
end
end
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
return found
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function set_mapspot_colors(id,icon,a,r,g,b)
if not (id and icon and a and r and g and b) then return end
local pin = pins[id]
if pin and pin.colors then
local clr = pin.colors
local spot = level.map_get_object_spot_static(id,icon)
if spot then spot:SetTextureColor(GetARGB(clr.a, clr.r, clr.g, clr.b)) end
end
end
function remove_stash_mapspots(id)
level.map_remove_object_spot(id,"treasure")
level.map_remove_object_spot(id,"treasure")
for _,mapspot in pairs(stash_icons) do
dl("Attempting to remove stash mapspot \"%s\" for ID %s",mapspot,id)
level.map_remove_object_spot(id,mapspot)
level.map_remove_object_spot(id,mapspot)
end
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
function pin_exists(id)
return pins[id] and true or false
end
function can_convert_to_pin(id)
if not (id and (id > 0) and (id < 65535)) then return end
local se_obj = alife_object(id)
if not se_obj then return end
local cls = se_obj:clsid()
local is_stash = IsInvbox(nil,cls)
local mapspot = get_mapspot(id)
local is_pin = pin_exists(id)
local can_convert = mapspot and is_stash and not is_pin
vl("can_convert_to_pin(%s): is_stash: %s | is a pin: %s | mapspot: %s | can_convert = %s",id,is_stash,is_pin,mapspot,can_convert)
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
return can_convert
2024-03-17 20:18:03 -04:00
end
function cancel_task()
local id = placed_waypoint and placed_waypoint.id
tm.task_info[task_id] = nil
2024-03-20 06:40:41 -04:00
if id then
remove_mapspot(id, waypoint_mapspot)
set_pingspot_persistence(id,false)
end
2024-03-17 20:18:03 -04:00
waypoint_active = false
placed_waypoint = nil
2024-03-20 06:40:41 -04:00
dl("Waypoint task cancellation complete for %s",id)
2024-03-17 20:18:03 -04:00
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
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.
2024-03-20 06:40:41 -04:00
local pin = pins and id and pins[id]
2024-03-17 20:18:03 -04:00
local valid = pin and pin.quick
2024-03-20 06:40:41 -04:00
vl("valid_travel_target | id %s is pin: %s | is quick pin %s",id,pin,valid)
2024-03-17 20:18:03 -04:00
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"),
2024-03-20 06:40:41 -04:00
text = text,
2024-03-17 20:18:03 -04:00
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,
}
2024-03-20 06:40:41 -04:00
script_zone_changed = true
vl("Script zone %s spawned for mapspot",id)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
script_zone_changed = true
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
script_zone_changed = false
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
do_paw_action("pn_del",nil,nil,{syscall=true,id=k})
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
script_zone_changed = true
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
script_zone_changed = true
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
if use_ping_snd and snd_ping then play_ui_sound(snd_ping) end
2024-03-17 20:18:03 -04:00
CreateTimeEvent("paw_ping_cleanup","ping_"..pid,11,tasks_placeable_waypoints.ping_cleanup,pid)
end
2024-03-20 06:40:41 -04:00
function init_mapspot_label_wnd(mapspot_text,id,icon,anchor)
vl("init_mapspot_label_wnd(%s,%s,%s)",mapspot_text,id,icon)
mapspot_text = mapspot_text or ""
local anchor = anchor or level.map_get_object_spot_static(id,icon)
local xml = CScriptXmlInit()
local xmlroot = "paw_ui_wnd_box"
local frm = xmlroot..":frm_"
xml:ParseFile("paw_ui_elements.xml")
local cap = {}
cap.id = id
cap.box = xml:InitStatic(xmlroot,anchor)
local tokens = 0
if string.find(mapspot_text,"$") then
local levelname = ts(level.name())
local se_obj = alife_object(id)
local pos = se_obj and se_obj.position
local coord_x,coord_y,coord_z,coords
if pos then
coord_x = string.format("%.2f",pos.x)
coord_y = string.format("%.2f",pos.y)
coord_z = string.format("%.2f",pos.z)
--coords = string.format("XYZ %s, %s, %s",coord_x,coord_y,coord_z)
end
local token_subs = {
["obj_id"] = id,
["name"] = safename(id),
--["level"] = levelname,-- currently wrong
--["coords"] = coords, -- XYZ coordinates formatted as above
["coord_x"] = coord_x, -- X coordinate to 2 decimal places
["coord_y"] = coord_y, -- Y coordinate to 2 decimal places
["coord_z"] = coord_z, -- Z coordinate to 2 decimal places
}
mapspot_text = psk(mapspot_text,token_subs)
_,tokens = mapspot_text:gsub("%$","%$")
plaintext = psk(mapspot_text,null_tokens)
mapspot_text = psk(mapspot_text,text_colors)
end
local token_adj = tokens * 17
_, nlcnt = mapspot_text:gsub("\\n", "\\n")
local w = clamp(#mapspot_text * 6,15,200)
local h = ((floor(clamp((#mapspot_text - token_adj) / 35,1,3)) + nlcnt) * 15) + 4
cap.box:SetWndPos(vector2():set(15,-h))
cap.drop = xml:InitStatic(xmlroot..":min_full",cap.box)
cap.drop:SetWndSize(vector2():set(w,h))
cap.text_sh = xml:InitStatic(xmlroot..":content:text_sh",cap.drop)
cap.text_sh:SetWndSize(vector2():set(w,h))
cap.text_sh:TextControl():SetText(plaintext)
cap.text_sh:TextControl():SetTextColor(GetARGB(220,0,0,0))
cap.text = xml:InitStatic(xmlroot..":content:text",cap.drop)
cap.text:SetWndSize(vector2():set(w,h))
cap.text:TextControl():SetText(mapspot_text)
cap.text:TextControl():SetTextColor(GetARGB(220,220,220,220))
cap.BL = xml:InitStatic(frm.."BL_extend",cap.drop)
cap.BP = xml:InitStatic(frm.."BP",cap.drop)
cap.BL:SetWndPos(vector2():set(0,h - 7))
cap.BP:SetWndPos(vector2():set(0,h - 7))
cap.BM = xml:InitStatic(frm.."BM_extend",cap.BP)
local bmh = cap.BM:GetHeight()
cap.BM:SetWndSize(vector2():set(w,bmh))
cap.Show = (
function(tf)
pins[cap.id].show_label = tf
cap.box:Show(tf)
end
)
return cap
end
function show_pin_label(id,onoff,destroy)
vl("show_pin_label(%s,%s,%s)",id,onoff,destroy)
if not (id and pins[id]) then return end
onoff = onoff and true or false
if not map_labels[id] then
--printf("pin label container doesn't exist yet")
local icon = pins[id].icon
local text = pins[id].text or pins[id].name
if not (icon and text) then return end
map_labels[id] = init_mapspot_label_wnd(text,id,icon)
end
map_labels[id].box:Show(onoff)
pins[id].show_label = onoff
if not destroy then return end
dl("Destroying map label for id %s",id)
map_labels[id] = nil
return onoff
end
function do_paw_action(act,se_obj,acode,args)
2024-03-17 20:18:03 -04:00
args = args or {}
local syscall = args.syscall and true or false
2024-03-20 06:40:41 -04:00
if (not syscall) and not (paw_enabled and act) then return end
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
name = safename(id)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
local ac = action_codes[acode]
2024-03-20 06:40:41 -04:00
dl("Received paw action call \"%s\" on target %s (id %s)",act,name,id)
2024-03-17 20:18:03 -04:00
if act == "wp_set" then
if not se_obj then
2024-03-20 06:40:41 -04:00
dl("do_paw_action called with action %s but no valid se_obj!",act)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
dl("do_paw_action called with action %s but no valid se_obj!",act)
2024-03-17 20:18:03 -04:00
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 == "pn_add" then
dl("Received call to add new pin to map for %s (%s)",name,id)
local icon = icons[ac.icon] or map_pin_icon
2024-03-20 06:40:41 -04:00
local text = ts("st_paw_pin_default_name")
if not script_zones[id] then
text = name
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
init_new_pin(id,name,text,icon)
add_mapspot(text,id,icon)
open_pin_settings(id)
elseif act == "pn_settings" then
if not (id and pins[id]) then return end
dl("Received call to open settings for pin %s (%s)",name,id)
open_pin_settings(id)
elseif act == "wp_settings" then
dl("Received call to open waypoint settings")
open_waypoint_settings()
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
show_pin_label(id,false,true)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
vl("Pin %s (%s) deleted",pins[id].name,id)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
elseif act == "convert_to_pin" then
local mapspot = get_mapspot(id)
if can_convert_to_pin(id) then
if not texture_data[mapspot] then
get_mapspot_data(mapspot)
end
remove_stash_mapspots(id)
local hint = safename(id)
init_new_pin(id,name,hint,mapspot)
add_mapspot(hint,id,mapspot)
open_pin_settings(id)
end
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
elseif act == "show_label" then
if not (id and pins[id]) then return end
show_pin_label(id,true)
elseif act == "hide_label" then
if not (id and pins[id]) then return end
show_pin_label(id,false)
2024-03-17 20:18:03 -04:00
elseif act == "cm_dbg" then
2024-03-20 06:40:41 -04:00
local cls = se_obj and se_obj:clsid() or "empty"
property_ui:AddItem("[PAW Debug] Mapspot for %s (id %s) has clsid %s)",name,id,cls)
2024-03-17 20:18:03 -04:00
else
2024-03-20 06:40:41 -04:00
dl("invalid action %s passed to do_paw_action",act)
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
--do_paw_action("wp_del",se_obj)
2024-03-17 20:18:03 -04:00
toggle_waypoint()
else
vl("Waypoint is currently active, moving to %s (%s)",se_obj:name(),id)
2024-03-20 06:40:41 -04:00
do_paw_action("wp_mov",se_obj)
2024-03-17 20:18:03 -04:00
end
else
vl("No current waypoint, setting to target object %s (%s)",se_obj:name(),id)
2024-03-20 06:40:41 -04:00
do_paw_action("wp_set",se_obj)
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
do_paw_action("pn_del",se_obj)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
play_ui_sound(snd_tag_target)
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
pins[id].quick = not no_fast_travel
2024-03-17 20:18:03 -04:00
dl("calling add_mapspot with %s | %s | %s",mapspot_text,id,icon)
2024-03-20 06:40:41 -04:00
play_ui_sound(snd_place_pin)
2024-03-17 20:18:03 -04:00
add_mapspot(mapspot_text,id,icon)
if not no_tip then dotip(tip_text,10000) end
end
function toggle_waypoint(force)
2024-03-20 06:40:41 -04:00
dl("toggle_waypoint action called")
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
do_paw_action("wp_set",se_obj)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
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]
local pinset = false
2024-03-17 20:18:03 -04:00
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")
2024-03-20 06:40:41 -04:00
add_context_option(property_ui,"pn_settings",maptbl)
pinset = true
2024-03-17 20:18:03 -04:00
if pin.locked then
add_context_option(property_ui,"unlock_pin",maptbl)
else
add_context_option(property_ui,"pn_del",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
2024-03-20 06:40:41 -04:00
if pins[id].show_label then
add_context_option(property_ui,"hide_label",maptbl)
else
add_context_option(property_ui,"show_label",maptbl)
end
2024-03-17 20:18:03 -04:00
add_context_option(property_ui,"lock_pin",maptbl)
end
else
vl("No pin")
2024-03-20 06:40:41 -04:00
if can_convert_to_pin(id) then
add_context_option(property_ui,"convert_to_pin",maptbl)
else
add_context_option(property_ui,"pn_add",maptbl)
end
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
if not pinset then
-- If already showing the pin settings option, don't also clutter the menu with waypoint settings
add_context_option(property_ui,"wp_settings",maptbl)
end
2024-03-17 20:18:03 -04:00
if wid ~= sid then
2024-03-20 06:40:41 -04:00
vl("Waypoint exists elsewhere")
2024-03-17 20:18:03 -04:00
add_context_option(property_ui,"wp_mov",maptbl)
2024-03-20 06:40:41 -04:00
else
vl("Waypoint exists here")
2024-03-17 20:18:03 -04:00
end
add_context_option(property_ui,"wp_del",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
2024-03-20 06:40:41 -04:00
vl("execute_context_menu_option called for id %s\n| prop: %s\n| action %s",id,prop,action[prop])
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
do_paw_action(act,se_obj,ac)
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
return ts(setname or icon_sets[pawdata.curr_set_name].name)
2024-03-17 20:18:03 -04:00
end
function local_icon_name(iconame)
2024-03-20 06:40:41 -04:00
return ts(iconame or "ui_mcm_lst_"..pawdata.curr_ico_name)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
--vl("texture_for_icon(%s) returned %s",icon,tex)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
--vl("active_icon for %s: %s",setname,setdata.active_icon)
2024-03-17 20:18:03 -04:00
local td = texture_data[setdata.active_icon]
2024-03-20 06:40:41 -04:00
--vl("texture exists for %s: %s",setdata.active_icon,td ~= nil)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
function get_mapspot_data(spot)
local attr_tex = "texture"
local attr_minimap = "mini_map"
local attr_levelmap = "level_map"
xml:ParseFile("map_spots.xml")
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",spot)
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(attr_minimap) then
spotnode = xml:ReadAttribute(attr_minimap,0,"spot")
typ = attr_minimap
end
if xml:NodeExist(attr_levelmap) then
spotnode = xml:ReadAttribute(attr_levelmap,0,"spot")
typ = attr_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",spot,th,tw)
xml:NavigateToNode(spotnode,0)
tex = xml:ReadValue(attr_tex,0)
vl("%s node found: %s",typ,spotnode)
end
end
texture_data[spot] = {
id = k,
t = tex,
h = th,
w = tw,
}
local ind = #icon_index + 1
icon_index[ind] = {
id = k,
icon = spot,
data = texture_data[spot],
}
vl("Texture for %s: %s (%sx%s)",spot,tex,tw,th)
return texture_data[spot],ind
end
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
play_ui_sound(snd_cycle_blip)
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
play_ui_sound(snd_cycle_blip)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
local mapspot_text = get_tooltip_for_pin(id)
2024-03-17 20:18:03 -04:00
vl("calling add_mapspot with %s | %s | %s",mapspot_text,id,icon)
add_mapspot(mapspot_text,id,icon)
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
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))
2024-03-20 06:40:41 -04:00
wp_near_fade_dist = tonumber(load_mcm("pawgen/wp_near_fade_dist",wp_near_fade_dist))
wp_far_fade_dist = tonumber(load_mcm("pawgen/wp_far_fade_dist",wp_far_fade_dist))
wp_far_hide_dist = tonumber(load_mcm("pawgen/wp_far_hide_dist",wp_far_hide_dist))
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
local tmp
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
mwheel_override = tmp
if mwheel_override then
mwheel_avail = true
end
end
tmp = ui_mcm.get("pawsys/pawbinds/mwheel_enabled")
if tmp and type(tmp) == "number" then
tmp = (tmp ~= 0)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
mwheel_enabled = tmp and mwheel_avail
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
right_click_override = tmp
if right_click_override then
right_click_avail = true
RegisterScriptCallback("on_map_right_click",on_map_right_click)
end
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
--[[
use_custom_backpack_icon = load_mcm("pawpins/use_custom_backpack_icon",use_custom_backpack_icon)
if use_custom_backpack_icon then
local psicon = stash_icons["player"]
local newicon = ui_mcm.get("pawsys/pawpins/custom_backpack_icon")
if newicon ~= nil then
stash_icons["player"] = icons[newicon]
end
dl("MCM: Overriding player stash icon with custom value: %s",stash_icons["player"])
end
--]]
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
autotag_mode = load_mcm("pawret/reticle_mode",autotag_mode)
2024-03-17 20:18:03 -04:00
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()
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
-- 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")
2024-03-20 06:40:41 -04:00
local args = {wipe_all=true,syscall=true}
do_paw_action("pn_clr",nil,nil,args)
2024-03-17 20:18:03 -04:00
end
mcm_reload_general_settings()
if not paw_enabled then
2024-03-20 06:40:41 -04:00
printf(logprefix.."Personal Adjustable Waypoint has been disabled, aborting all further action!")
return end
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
UnregisterScriptCallback("actor_on_update",actor_on_update)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
if script_zone_changed then
script_zone_cleanup()
end
2024-03-17 20:18:03 -04:00
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
-- ======================================================================
2024-03-20 06:40:41 -04:00
function setwndpos(wnd,x,y)
if not (wnd and x and y) then return end
wnd:SetWndPos(vector2():set(x,y))
end
2024-03-17 20:18:03 -04:00
-- ======================================================================
--[[ 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)
-- ====================================================================]]
2024-03-20 06:40:41 -04:00
GUI_WP = nil
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
function open_waypoint_settings()
dl("open_waypoint_settings called")
2024-03-17 20:18:03 -04:00
tex = texdef or tex_defs
args = args or {}
2024-03-20 06:40:41 -04:00
if not GUI_WP then GUI_WP = UIWPSettings() end
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
if GUI_WP and not GUI_WP:IsShown() then
GUI_WP:ShowDialog(true)
Register_UI("UIWPSettings","open_waypoint_settings")
2024-03-17 20:18:03 -04:00
end
end
2024-03-20 06:40:41 -04:00
local function destroy_wp_window()
if GUI_WP then
GUI_WP:HideDialog()
GUI_WP = nil
end
end
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
-- ======================================================================
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
class "UIWPSettings" (CUIScriptWnd)
function UIWPSettings:__init() super()
vl("UIWPSettings:__init:\nTitle: %s\nIcon: %s\nExisting text: %s",title_txt,icon_tex,prepop)
self.init_time = tostring(get_time_elapsed())
self.init_wp = placed_waypoint
self.init_state = waypoint_active
self.def_wpname = custom_name or ts("st_paw_placed_waypoint")..(": "..placed_waypoint.name or "")
self.def_wpdesc = custom_desc or ts("st_paw_proceed")
self.pin_text = title_txt
self.icon_tex = "ui_inGame2_PDA_icon_Secondary_mission"
2024-03-17 20:18:03 -04:00
self.prepop = prepop
self.func = func
self.args = args
2024-03-20 06:40:41 -04:00
self.cap = {}
2024-03-17 20:18:03 -04:00
self:InitControls()
self:InitCallBacks()
2024-03-20 06:40:41 -04:00
self.control_hints = {
["btn_wpreset"] = true,
}
self.hint_wnd = utils_ui.UIHint(self)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIWPSettings:__finalize()
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIWPSettings:InitControls()
2024-03-17 20:18:03 -04:00
self:SetWndRect(Frect():set(0,0,1024,768))
self:SetAutoDelete(true)
local xml = CScriptXmlInit()
2024-03-20 06:40:41 -04:00
local file = "paw_input_window.xml"
local root = "wp_dialog"
local rootand = root..":"
local tbar = rootand.."titlebar"
local paw = tbar..":paw"
local text = tbar..":text"
local icon = tbar..":icon"
local reset = rootand.."btn_wpreset"
local cancel = rootand.."btn_cancel"
local input_n = rootand.."input_name"
local input_d = rootand.."input_desc"
local btn_ok = rootand.."btn_ok"
local caption = rootand.."caption"
xml:ParseFile (file)
self.dialog = xml:InitStatic(root, self)
local bg_top = xml:InitStatic(rootand.."bg_top",self.dialog)
local bg_btm = xml:InitStatic(rootand.."bg_btm",self.dialog)
self.bg_wpdesc = xml:InitStatic(rootand.."bg_desc",self.dialog)
self.wpname = xml:InitEditBox(input_n,self.dialog)
self:Register(self.wpname,"fld_input_name")
self.wpname:SetText(self.def_wpname)
self.wpname:SetWndSize(vector2():set(220,30))
--self.descbg = xml:InitStatic(input_d,self.dialog)
--self.descbg:InitTexture("ui_paw_dialog_large_text_field")
self.wpdesc = xml:InitEditBox(input_d, self.bg_wpdesc)
self:Register(self.wpdesc,"fld_input_desc")
self.wpdesc:SetText(self.def_wpdesc)
--self.descbg:SetWndSize(vector2():set(171,188))
self.wpdesc:SetWndSize(vector2():set(220,30))
2024-03-17 20:18:03 -04:00
self.tbar = xml:InitStatic(tbar,self.dialog)
2024-03-20 06:40:41 -04:00
local paw = xml:InitTextWnd(paw,self.tbar)
paw:SetText("PAW".." "..script_version)
paw:SetFont(GetFontSmall())
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
self.titletxt = xml:InitTextWnd(text, self.tbar)
self.titletxt:SetText(ts("ui_mcm_pawsys_pawmenu_wp_settings"))
self.titletxt:SetFont(GetFontDI())
self.targetname = xml:InitStatic(rootand.."target",self.dialog)
self.tartxt = ts("st_paw_target")..": "
self.tarclr = "$clr_wht"
if placed_waypoint and placed_waypoint.id then
self.tarclr = "$clr_yel"
local tartxt = self.tartxt..self.tarclr..safename(placed_waypoint.id)
self.tartxt = psk(tartxt,text_colors)
self.targetname:TextControl():SetText(self.tartxt)
else
self.targetname:TextControl():SetText(ts("st_paw_none"))
end
local function setup_checkbox(setting,pos_x,pos_y,captext,default)
local checkopt = "check_"..setting
vl("Initializing checkbox %s (%s) at %s,%s | %s",checkopt,setting,pos_x,pos_y,captext)
self[checkopt] = xml:InitCheck(rootand.."check",self.dialog)
self:Register(self[checkopt], checkopt..self.init_time)
self[checkopt]:SetWndPos(vector2():set(pos_x,pos_y))
self[checkopt]:SetCheck(default)
if captext then
self.cap[checkopt] = xml:InitTextWnd(caption,self[checkopt])
self.cap[checkopt]:SetWndPos(vector2():set(30,8))
self.cap[checkopt]:SetText(captext)
self.cap[checkopt]:SetVTextAlignment(1)
end
end
function setup_button(button,pos_x,pos_y,xmlnode)
local buttonx = "btn_"..button
vl("Initializing button %s (%s) at %s,%s",buttonx,button,pos_x,pos_y)
self[buttonx] = xml:Init3tButton(xmlnode,self.dialog)
self:Register(self[buttonx],buttonx)
self[buttonx]:SetWndPos(vector2():set(pos_x,pos_y))
end
setup_checkbox( "wpactive", 15, 152, ts("st_paw_wp_active"), waypoint_active )
setup_checkbox( "wphud", 15, 178, ts("ui_mcm_pawsys_pawgen_wp_hud_icon_enabled"), wp_hud_icon_enabled )
self.check_wpactive:SetCheck(self.init_state)
self.check_wphud:SetCheck(wp_hud_icon_enabled)
setwndpos( paw, 215, 26 )
setwndpos( self.titletxt, 7, 7 )
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
setwndpos( self.icon, 17, 121 )
setwndpos( self.targetname, 50, 130 )
setwndpos( self.wpname, 25, 38 )
--setwndpos( self.descbg, 25, 90 )
setwndpos( self.wpdesc, 25, 4 )
setup_button( "wpreset", 20, 210, reset )
setup_button( "ok", 112, 210, btn_ok )
setup_button( "cancel", 183, 210, cancel )
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIWPSettings:InitCallBacks()
self:AddCallback("btn_wpreset", ui_events.BUTTON_CLICKED, self.Reset, self)
2024-03-17 20:18:03 -04:00
self:AddCallback("btn_ok", ui_events.BUTTON_CLICKED, self.OnAccept, self)
self:AddCallback("btn_cancel", ui_events.BUTTON_CLICKED, self.Close, self)
end
2024-03-20 06:40:41 -04:00
function UIWPSettings:ShowHint(hint)
if hint then
hint = psk(hint,text_colors)
--vl("* [%s] Showing hint_wnd text: %s",time_global(),hint)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
self.hint_wnd:Update(hint)
end
function UIWPSettings:Reset()
dl("Restoring default waypoint settings")
--self.icon_tex = "ui_inGame2_PDA_icon_Secondary_mission"
--self.icon:InitTexture(self.icon_tex)
custom_name = nil
custom_desc = nil
self.wpname:SetText(self.def_wpname)
self.wpdesc:SetText(self.def_wpdesc)
wp_hud_icon_enabled = true
self.check_wphud:SetCheck(true)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIWPSettings:Update()
2024-03-17 20:18:03 -04:00
CUIScriptWnd.Update(self)
2024-03-20 06:40:41 -04:00
self.hint = nil
for ctrl,enable in pairs(self.control_hints) do
if enable and self[ctrl] and self[ctrl]:IsCursorOverWindow() then
local st_hint = hint_path..ctrl.."_desc"
local hint = ts(st_hint)
self.hint = hint
--vl("Showing hint for %s: %s\n\"%s\"",ctrl,st_hint,hint)
end
end
self:ShowHint(self.hint)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIWPSettings:OnAccept()
local new_wpname = self.wpname:GetText()
if new_wpname ~= self.def_wpname then
custom_name = new_wpname
end
local new_wpdesc = self.wpdesc:GetText()
if new_wpdesc ~= self.def_wpdesc then
custom_desc = new_wpdesc
end
local new_wpstate = self.check_wpactive:GetCheck()
if self.init_state ~= new_wpstate then
toggle_waypoint()
end
local new_hudstate = self.check_wphud:GetCheck()
if new_hudstate and not wp_hud_icon_enabled then
wp_hud_icon_enabled = true
show_hud_waypoint()
elseif wp_hud_icon_enabled and not new_hudstate then
wp_hud_icon_enabled = false
hide_hud_waypoint()
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
dl("UIWPSettings:OnAccept | custom_name: %s | custom_desc: %s",custom_name,custom_desc)
2024-03-17 20:18:03 -04:00
self:Close()
end
2024-03-20 06:40:41 -04:00
function UIWPSettings:OnKeyboard(dik, keyboard_action)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
function UIWPSettings:Close()
2024-03-17 20:18:03 -04:00
self:HideDialog()
2024-03-20 06:40:41 -04:00
Unregister_UI("UIWPSettings")
destroy_wp_window()
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
-- ======================================================================
2024-03-20 06:40:41 -04:00
--[[ PIN SETTINGS WINDOW
2024-03-17 20:18:03 -04:00
-- ====================================================================]]
2024-03-20 06:40:41 -04:00
GUI_PinOpts = nil
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
function pin_window_is_open()
return GUI_PinOpts and GUI_PinOpts:IsShown()
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function open_pin_settings(id,args)
if not GUI_PinOpts then
GUI_PinOpts = UIPinSettingsWnd(id,args)
end
if GUI_PinOpts and not GUI_PinOpts:IsShown() then
GUI_PinOpts:Reset(id)
GUI_PinOpts:ShowDialog(true)
Register_UI("UIPinSettingsWnd","pin_settings")
end
end
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
function destroy_pin_window()
GUI_PinOpts = nil
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
-- ======================================================================
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
class "UIPinSettingsWnd" (CUIScriptWnd)
function UIPinSettingsWnd:__init(id,args) super()
vl("UIPinSettingsWnd:__init(%s,args passed: %s",id,args ~= nil)
if not ((id and id > 0) and pins[id]) then return end
if debuglogs and verbose then
local pin = pins[id]
printf(logprefix.."Initializing settings window for pin %s:\nName: %s\nLocked: %s | Show on HUD %s | Show Label %s | Custom ARGB: %s",
id, pin.name, pin.lock, pin.hud, pin.show_label, pin.custom_colors
)
if pins[id].custom_colors and pins[id].colors then
local colors = pins[id].colors
printf(logprefix.."A: %s | R: %s | G: %s | B: %s",colors.a,colors.r,colors.g,colors.b)
end
end
self.init_time = tostring(get_time_elapsed())
self.next_update = time_global()
self.icon_refresh = true
--self:BackupTempSettings()
self:Reset(id,args)
2024-03-17 20:18:03 -04:00
self:InitControls()
2024-03-20 06:40:41 -04:00
self:HijackWidget()
self:RefreshIcon()
self.hint_wnd = utils_ui.UIHint(self)
self:AllowMovement(true)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIPinSettingsWnd:__finalize()
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIPinSettingsWnd:BackupTempSettings(restore)
if not self.backups then
self.backups = {}
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
if restore then
dl("UIPinSettingsWnd | restoring old settings:\nwidget_enabled = %s\nwidget_hide_delay = %s | active_theme = %s",widget_enable,widget_hide_delay,active_theme)
widget_enabled = self.backups.enable
active_theme = self.backups.active or active_theme
widget_hide_delay = self.backups.autohide or widget_hide_delay
widget_use_custom_pos = self.backups.use_cust_pos or widget_use_custom_pos
widget_custom_pos = self.backups.cust_pos or widget_custom_pos
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
self.backups = {}
else
dl("UIPinSettingsWnd | storing current settings:\nwidget_enabled = %s\nwidget_hide_delay = %s | active_theme = %s",widget_enable,widget_hide_delay,active_theme)
self.backups = {
enabled = widget_enabled,
autohide = widget_hide_delay,
active = active_theme,
use_cust_pos= widget_use_custom_pos,
cust_pos = widget_custom_pos,
}
active_theme = "pin_sidebar"
widget_hide_delay = 0
widget_use_custom_pos = true
end
end
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
function UIPinSettingsWnd:HijackWidget()
reset_indicator(true,self.dialog)
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function UIPinSettingsWnd:InitControls()
self:SetWndRect(Frect():set(0,0,1024,768))
self:SetAutoDelete(true)
self.empty = "ui_paw_emptytex"
self.cap = {}
local pin = self.pin or self.pin_id and pins[self.pin_id]
self.control_hints = {
["check_hud"] = true,
["check_text"] = true,
["check_lock"] = true,
["check_argb"] = true,
["input"] = true,
["input_a"] = true,
["input_r"] = true,
["input_g"] = true,
["input_b"] = true,
["btn_sidebar"] = true,
["btn_ok"] = true,
["btn_cancel"] = true,
["btn_delete"] = true,
["btn_sound"] = true,
}
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
local clrtxt ={
a = ts("st_paw_argb_a"),
r = ts("st_paw_argb_r"),
g = ts("st_paw_argb_g"),
b = ts("st_paw_argb_b")
}
2024-03-17 20:18:03 -04:00
2024-03-20 06:40:41 -04:00
local xml = CScriptXmlInit()
local xmlfile = "paw_input_window.xml"
local xmlroot = "pin_dialog"
local root = xmlroot..":"
local tbar = root.."titlebar"
local icon = root.."icon"
local paw = tbar..":paw"
local icopanel = icon.."_panel"
local icoframe = icon.."_frame"
local icowater = icon.."_watermark"
local caption = root.."caption"
local bg = root.."bg_settings"
local dialog = root.."pin_settings"
local chrome = root.."chrome"
local input = root.."input_name"
local input_a = root.."input_a"
local input_r = root.."input_r"
local input_g = root.."input_g"
local input_b = root.."input_b"
local btn_ok = root.."btn_ok"
local cancel = root.."btn_cancel"
local delete = root.."btn_delete"
local check = root.."check"
local listbox = root.."listbox"
local opt_icon = root.."opt_icon"
local opt_cap = opt_icon..":caption"
local sidebar = root.."sidebar"
local sb_btn = root.."btn_sidebar"
local btn_sound = root.."btn_sound"
local head_txt = self.title
local lock_txt = ts("ui_mcm_pawsys_pawmenu_lock_pin")
local label_txt = ts("ui_mcm_pawsys_pawmenu_show_label")
local hud_txt = ts("ui_mcm_pawsys_pawmenu_hud_vis_on")
local argb_txt = ts("ui_paw_use_custom_color")
local mstt_txt = ts("ui_paw_mapspot_tooltip_mode")
local set_curr = ts("ui_mcm_lst_pawsys_pg_"..pawdata.curr_set_name)
local ico_curr = ts("ui_mcm_lst_"..pawdata.curr_ico_name)
xml:ParseFile (xmlfile)
--================================================================--
--Title bar
if not self.dialog then
self.dialog = xml:InitStatic(dialog, self)
self.dialog:SetWndSize(vector2():set(400,300))
self.dialog:SetWndPos(vector2():set(392,200))
self.chrome = xml:InitStatic(chrome, self.dialog)
self.chrome:InitTexture("ui_paw_dialog_classic_chrome")
local titletab_sh = xml:InitStatic(caption, self.chrome)
local titletab = xml:InitStatic(caption, self.chrome)
titletab_sh:TextControl():SetText(head_txt)
titletab_sh:TextControl():SetFont(GetFontDI())
titletab_sh:TextControl():SetTextColor( GetARGB(255,0,0,0) )
titletab_sh:SetWndPos(vector2():set(18,9))
titletab_sh:InitTexture("ui_paw_fade_cap_bg_full")
titletab:TextControl():SetText(head_txt)
titletab:TextControl():SetFont(GetFontDI())
titletab:SetWndPos(vector2():set(19,9))
self.tbar = xml:InitStatic(tbar,self.dialog)
local paw = xml:InitTextWnd(paw,self.tbar)
paw:SetText("PAW".." "..script_version)
paw:SetFont(GetFontSmall())
paw:SetWndPos(vector2():set(195,34))
psw_sidebar_state = false
show_indicator(false)
end
--================================================================--
-- Rename/relabel input box
vl("Setting up name input box")
self.input = xml:InitEditBox(input,self.dialog)
self:Register(self.input,"fld_input"..self.init_time)
self.input:SetWndSize(vector2():set(190,30))
self.input:SetWndPos(vector2():set(8,7))
vl("Setting name input field to %s",self.pin_text)
self.input:SetText(self.pin_text)
--==== Icon and Set area initialization ==========================--
-- Icon display
if not self.icon_display_panel then
self.icon_display_panel = xml:InitStatic(icopanel, self.dialog)
self.icon_panel = xml:InitStatic(icowater, self.icon_display_panel)
unsquish_aspect(self.icon_panel)
local icoframe = xml:InitStatic(icoframe, self.icon_display_panel)
unsquish_aspect(icoframe)
self.icon = xml:InitStatic(icon, self.icon_display_panel)
unsquish_aspect(self.icon)
local w = self.icon:GetWidth()
self.icon:SetWndPos(vector2():set(11.75,16))
end
self:RefreshIcon(self.icon_tex)
self.argb_controls = xml:InitStatic(root.."argb_chrome",self.dialog)
--================================================================--
local function setup_argb_control(color,pos_x,pos_y)
local inputx = "input_"..color
vl("Initializing ARGB control %s for color %s at %s,%s",inputx,color,pos_x,pos_y)
local xsh = color.."_sh"
local xtx = color.."_tx"
local xmlnode = root..":"..inputx
self.argb_box = {}
self.argb_box[color] = xml:InitStatic(xmlnode,self.argb_controls)
self.argb_box[color]:SetWndSize(vector2():set(65,31))
unsquish_aspect(self.argb_box[color])
self.argb_box[color]:SetWndPos(vector2():set(pos_x,pos_y))
self.argb_box[color]:InitTexture("ui_paw_dialog_argb_single")
self[inputx] = xml:InitEditBox(xmlnode,self.argb_box[color])
self:Register(self[inputx],"fld_input_"..color..self.init_time)
--printf("Original method - %s | color: %s | self.colors[%s]",inputx,color,color,self.colors[color])
self.cap[color] = xml:InitStatic(opt_icon,self.argb_box[color])
self.cap[color]:InitTexture("ui_icons_paw_argb_"..color)
unsquish_aspect(self.cap[color])
--self.cap[xsh] = xml:InitStatic(opt_cap.."_sh",self.cap[color])
--self.cap[xsh]:TextControl():SetTextColor( GetARGB(255,0,0,0) )
--self.cap[xtx] = xml:InitStatic(opt_cap,self.cap[color])
self:SetARGBVal(color,self.colors[color])
self[inputx]:SetWndPos(vector2():set(18.5,2.5))
local boxframe = xml:InitStatic(xmlnode,self.argb_box[color])
boxframe:SetWndSize(vector2():set(65,31))
unsquish_aspect(boxframe)
--boxframe:SetWndPos(vector2():set(pos_x,pos_y))
boxframe:InitTexture("ui_paw_dialog_argb_single_nobg")
end
local function setup_checkbox(setting,pos_x,pos_y,captext)
local checkopt = "check_"..setting
vl("Initializing checkbox %s (%s) at %s,%s | %s",checkopt,setting,pos_x,pos_y,captext)
self[checkopt] = xml:InitCheck(check,self.dialog)
self:Register(self[checkopt], checkopt..self.init_time)
self[checkopt]:SetWndPos(vector2():set(pos_x,pos_y))
if captext then
self.cap[checkopt] = xml:InitTextWnd(caption,self[checkopt])
self.cap[checkopt]:SetWndPos(vector2():set(30,8))
self.cap[checkopt]:SetText(captext)
self.cap[checkopt]:SetVTextAlignment(1)
end
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function setup_button(button,pos_x,pos_y,xmlnode)
local buttonx = "btn_"..button
vl("Initializing button %s (%s) at %s,%s",buttonx,button,pos_x,pos_y)
self[buttonx] = xml:Init3tButton(xmlnode,self.dialog)
self:Register(self[buttonx],buttonx)
self[buttonx]:SetWndPos(vector2():set(pos_x,pos_y))
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
--[[
-- not ready yet
function setup_listbox(setting,pos_x,pos_y,captext,opts)
local num_opts = #opts or 0
if num_opts < 1 then
vl("Unable to initialize list %s, no opts passed",setting)
return
end
local listopt = "lst_"..setting
vl("Initializing list %s at %s,%s with %s options",listopt,pos_x,pos_y,num_opts)
self[listopt] = xml:InitComboBox(listbox,self.dialog)
self[listopt]:SetWndPos(vector2():set(pos_x,pos_y))
if captext then
self.cap[listopt] = xml:InitTextWnd(caption,self[listopt])
self.cap[listopt]:SetWndPos(vector2():set(0,-10))
self.cap[listopt]:SetText(captext)
self.cap[listopt]:SetVTextAlignment(1)
end
local def = pin.tooltip or pin_tooltip_mode
local opt,tsopt
for i=1,num_opts do
tsopt = opts[i][2]
tsopt = tsopt and "ui_mcm_lst_pawsys_"..tsopt
opt = ts(tsopt)
vl("+ Adding list option %s: %s (%s)\n+- %s",i,opts[i][2],opts[i][1],opt)
self[listopt]:AddItem(opt,i)
if opts[i][1] == def then
vl("* +- %s is default value",def)
self[listopt]:enable_id(def)
self[listopt]:SetText(opt)
end
self:Register(self[listopt],listopt)
end
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
--]]
--================================================================--
-- Setup and place all elements
--========================= X ===== Y ============================--
setup_argb_control( "a", 25, 13 )
setup_argb_control( "r", 75, 13 )
setup_argb_control( "g", 125, 13 )
setup_argb_control( "b", 180, 13 )
--[[
-- not ready yet
setup_listbox("tooltip", 5, 70, mstt_txt,
{
{2, "msttmode_text"},
{1, "msttmode_obj"},
{0, "cmenu_off"},
}
)
--]]
setup_checkbox( "hud", 5, 85, hud_txt )
setup_checkbox( "text", 5, 110, label_txt )
setup_checkbox( "lock", 5, 135, lock_txt )
setup_checkbox( "argb", 5, 160, argb_txt )
self:RefreshChecks()
setup_button( "sidebar", 230, -10, sb_btn )
setup_button( "delete", 5.5, 245.5, delete )
setup_button( "ok", 95, 245.5, btn_ok )
setup_button( "cancel", 154, 245.5, cancel )
setup_button( "sound", 235.5, 267.5, btn_sound)
--================================================================--
widget_custom_pos = { x= 141, y= 46 }
self.icon_display_panel:SetWndPos(vector2():set(150,77))
self.argb_controls:SetWndPos(vector2():set( -5.5, 192))
self:InitCallBacks()
self.init_done = true
--self.input:CaptureFocus(true)
end
function UIPinSettingsWnd:InitCallBacks()
vl("UIPinSettingsWnd registering callbacks")
self:AddCallback("btn_ok", ui_events.BUTTON_CLICKED, self.OnAccept, self)
self:AddCallback("btn_cancel", ui_events.BUTTON_CLICKED, self.Close, self)
self:AddCallback("btn_delete", ui_events.BUTTON_CLICKED, self.DeletePin, self)
self:AddCallback("btn_sidebar", ui_events.BUTTON_CLICKED, self.ToggleSidebar, self)
self:AddCallback("btn_sound", ui_events.BUTTON_CLICKED, self.ToggleSound, self)
end
function UIPinSettingsWnd:GetAnchorStatic()
if self.dialog then
return self.dialog
else
dl("ERROR self.dialog was nil!")
end
end
function UIPinSettingsWnd:ApplyIconToPin(icon)
icon = icon or pawdata.curr_ico_name
pins[self.pin_id].text = pins[self.pin_id].text or pins[self.pin_id].name
local text = get_tooltip_for_pin(self.pin_id)
local old_icon = pins[self.pin_id].icon
pins[self.pin_id].icon = icon
change_mapspot(text,self.pin_id,icon,old_icon)
self.new_icon = nil
self.icon_refresh = true
self:RefreshIcon()
end
function UIPinSettingsWnd:SetARGBVal(color,val)
local inputx = "input_"..color
--printf("SetARGB method - inputx: %s | color: %s | val %s",inputx,color,val)
if color and val and self[inputx] then
--printf("Current color for %s is %s, setting to value %s",color,self[inputx]:GetText(),val)
self[inputx]:SetText(val)
end
end
function UIPinSettingsWnd:RefreshIcon(texture)
if not (texture or self.icon_refresh) then return end
if not self.icon then return end
vl("UIPinSettingsWnd:RefreshIcon(%s) %s",texture,self.icon_refresh and "| self.icon_refresh flagged" or "",self.icon_refresh)
self.icon_curr = pins[self.pin_id].icon or self.icon_curr
texture = texture or texture_for_icon(self.icon_curr)
if texture then
self.icon:InitTexture(texture)
self.icon:SetTextureColor(GetARGB(self.colors.a,self.colors.r,self.colors.g,self.colors.b))
self.icon_refresh = false
return true
else
dl("No texture found by UIPinSettingsWnd:RefreshIcon!")
return
end
end
function UIPinSettingsWnd:SetSoundIcon()
if self.btn_sound then
local bstate = use_ui_snd and "on" or "off"
self.btn_sound:InitTexture("ui_paw_btn_sound"..bstate)
end
end
function UIPinSettingsWnd:ToggleSound()
use_ui_snd = not use_ui_snd
vl("Toggling UI sfx to %s",use_ui_snd)
self:SetSoundIcon()
end
function UIPinSettingsWnd:ToggleSidebar()
psw_sidebar_state = not psw_sidebar_state
vl("Toggling sidebar widget to %s",psw_sidebar_state)
GUI_PinInd:ShowDialog(psw_sidebar_state)
if psw_sidebar_state then
self.btn_sidebar:InitTexture("ui_paw_btn_close_sidebar")
else
self.btn_sidebar:InitTexture("ui_paw_btn_open_sidebar")
end
--self.icoset_controls:Show(psw_sidebar_state)
play_ui_sound(snd_cycle_blip)
end
--[[
function UIPinSettingsWnd:Callback_Input(color)
vl("UIPinSettingsWnd:Callback_Input for color %s",color)
-- largely lifted from MCM
local is_color = self.colors[color] and true or false
local value = ctrl:GetText()
local default = self.default_all
local min = 0
local max = 255
local ctrl = is_color and "input" or "input_"..color
if not (value and value ~= "") then
value = default
elseif is_color then
value = tonumber(value)
if (not value) then
ctrl:SetText(default)
return
end
value = clamp(value, min, max)
end
printf("Input callback got value %s",value)
if value ~= ctrl:GetText() then
self.cust_argb = true
end
ctrl:SetText(value)
self.colors[color] = value
local a = self.colors.a
local r = self.colors.r
local g = self.colors.g
local b = self.colors.b
dl("Setting custom ARGB of %s|%s|%s|%s for %s",a,r,g,b)
self.icon:SetTextureColor(GetARGB(a,r,g,b))
end
--]]
function UIPinSettingsWnd:RefreshChecks()
if self.check_text then
self.check_text:SetCheck(self.show_label)
--vl("check_text after refresh: %s",self.check_text:GetCheck())
end
if self.check_hud then
self.check_hud:SetCheck(self.show_hud)
--vl("check_hud after refresh: %s",self.check_hud:GetCheck())
end
if self.check_lock then
self.check_lock:SetCheck(self.locked)
--vl("check_lock after refresh: %s",self.check_lock:GetCheck())
end
if self.check_argb then
self.check_argb:SetCheck(self.cust_argb)
--vl("check_argb after refresh: %s",self.check_argb:GetCheck())
end
self:SetSoundIcon()
end
function UIPinSettingsWnd:Reset(id,args)
self.new_icon = nil
self.args = args
if args and args.wipe then
self.icon_changed = false
self.set_changed = false
self.cust_argb = nil
self.title = nil
self.pin_id = nil
self.pin = nil
self.locked = nil
self.show_hud = nil
self.show_label = nil
self.pin_text = nil
self.init_time = nil
self.icon_tex = nil
self.colors = nil
self.tooltip = nil
self.icon:InitTexture(self.empty)
return
end
self.title = args and args.title or ts("ui_mcm_pawsys_pawmenu_pn_settings")
self.pin_id = id
self.pin = pins[self.pin_id]
self.cust_argb = self.pin.custom_colors
self.locked = self.pin.locked
self.show_hud = self.pin.hud
self.show_label = self.pin.show_label
self.tooltip = self.pin.tooltip
self.pin_text = self.pin.text or self.pin.name
self.init_time = tostring(get_time_elapsed())
self.icon_tex = texture_for_icon(self.pin.icon)
self.colors = self.pin.colors
if not self.colors then
vl("no stored colors in pin %s, defaulting ARGB to 255",id)
self.colors = {
a = 255,
r = 255,
g = 255,
b = 255
}
end
for k,v in pairs(self.colors) do
self:SetARGBVal(k,v)
end
self:RefreshChecks()
if self.input then
self.input:SetText(self.pin_text)
end
self:RefreshIcon()
end
function UIPinSettingsWnd:Update()
--printf("PAW: psw_sidebar_state: %s | widget_active: %s",psw_sidebar_state,widget_active)
if not self.init_done then return end
if time_global() < self.next_update then return end
self.next_update = time_global() + 10
CUIScriptWnd.Update(self)
self.hint = nil
for ctrl,enable in pairs(self.control_hints) do
if enable and self[ctrl] and self[ctrl]:IsCursorOverWindow() then
local st_hint = hint_path..ctrl.."_desc"
local hint = ts(st_hint)
self.hint = hint
--vl("Showing hint for %s: %s\n\"%s\"",ctrl,st_hint,hint)
end
end
self:ShowHint(self.hint)
-- locking
self.cust_argb = self.check_argb:GetCheck()
self.argb_controls:Show(self.cust_argb)
self.last_lock = self.locked
self.locked = self.check_lock:GetCheck()
if self.locked ~= self.last_lock then
self.last_lock = self.locked
self.btn_delete:Enable(not self.locked)
self.check_text:Enable(not self.locked)
self.check_hud:Enable(not self.locked)
self.check_argb:Enable(not self.locked)
--self.input_a:Enable(self.cust_argb and not self.locked)
--self.input_r:Enable(self.cust_argb and not self.locked)
--self.input_g:Enable(self.cust_argb and not self.locked)
--self.input_b:Enable(self.cust_argb and not self.locked)
self.input_a:Enable(not self.locked)
self.input_r:Enable(not self.locked)
self.input_g:Enable(not self.locked)
self.input_b:Enable(not self.locked)
self.input:Enable(not self.locked)
if GUI_PinInd then
GUI_PinInd.btn_apply:Enable(not self.locked)
end
end
local text = self.input:GetText()
local a,r,g,b = clamp(tonumber(self.input_a:GetText()) or 255,0,255),
clamp(tonumber(self.input_r:GetText()) or 255,0,255),
clamp(tonumber(self.input_g:GetText()) or 255,0,255),
clamp(tonumber(self.input_b:GetText()) or 255,0,255)
if not self.colors then
self.colors = {}
end
for c,v in pairs({["a"]=a,["r"]=r,["g"]=g,["b"]=b}) do
if self.colors[c] ~= v then
self.cust_argb = true
end
self.colors[c] = v
end
--self.hint_wnd:Update()
self:RefreshIcon()
end
function UIPinSettingsWnd:OnAccept()
local id = self.pin_id
dl("UIPinSettingsWnd:OnAccept - applying changes to Pin %s",id)
--local old_tooltip = get_tooltip_for_pin(id)
--pins[id].tooltip = self["lst_tooltip"] and self["lst_tooltip"]:CurrentID() or pin_tooltip_mode
--printf("Tooltip mode: %s",pins[id].tooltip)
local new_text = self.input:GetText()
local old_text = pins[id].text or pins[id].name
pins[id].text = new_text
--local hint_is_new = pins[id].tooltip ~= old_tooltip
local has_new_text = old_text ~= new_text
if has_new_text then --or self.new_icon then --or hint_is_new then
--local old_icon = pins[id].icon
--pins[id].icon = self.new_icon or pins[id].icon
local mapspot_text = get_tooltip_for_pin(id)
--dl("UIPinSettingsWnd:OnAccept: Pin %s has new icon or hint, calling change_mapspot\n* Icon: %s\n* Hint: %s",self.pin_id,pins[id].icon,mapspot_text)
--change_mapspot(mapspot_text,id,pins[id].icon,old_icon)
dl("UIPinSettingsWnd:OnAccept: Pin %s has new icon or hint, calling level.map_change_spot_hint",self.pin_id,pins[id].icon,mapspot_text)
level.map_change_spot_hint(id,pins[id].icon,mapspot_text)
end
pins[id].custom_colors = self.cust_argb
if self.cust_argb then
local a,r,g,b = clamp(tonumber(self.input_a:GetText()) or 255,0,255),
clamp(tonumber(self.input_r:GetText()) or 255,0,255),
clamp(tonumber(self.input_g:GetText()) or 255,0,255),
clamp(tonumber(self.input_b:GetText()) or 255,0,255)
if not pins[id].colors then
pins[id].colors = {}
end
pins[id].colors.a = a
pins[id].colors.r = r
pins[id].colors.g = g
pins[id].colors.b = b
set_mapspot_colors(id,pins[id].icon,a,r,g,b)
vl("UIPinSettingsWnd:OnAccept: ARGB is %s|%s|%s|%s",a,r,g,b)
end
self.show_label = self.check_text:GetCheck()
if map_labels[id] and new_name then
show_pin_label(id,false,true)
end
show_pin_label(id,self.show_label)
vl("UIPinSettingsWnd:OnAccept: show_label is %s",self.show_label)
pins[id].hud = self.check_hud:GetCheck()
if pins[id].hud then
show_hud_pin(id)
else
hide_hud_pin(id)
end
vl("UIPinSettingsWnd:OnAccept: show_hud is %s",pins[id].hud)
pins[id].locked = self.check_lock:GetCheck()
vl("UIPinSettingsWnd:OnAccept: locked is %s",pins[id].locked)
play_ui_sound(snd_place_pin)
self:Close()
end
function UIPinSettingsWnd:ShowHint(hint)
if hint then
hint = psk(hint,text_colors)
--vl("* [%s] Showing hint_wnd text: %s",time_global(),hint)
end
self.hint_wnd:Update(hint)
end
function UIPinSettingsWnd: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 UIPinSettingsWnd:DeletePin()
do_paw_action("pn_del",nil,nil,{syscall=true,id=self.pin_id})
self:Close()
end
function UIPinSettingsWnd:Close()
self:HideDialog()
self:Show(false)
Unregister_UI("UIPinSettingsWnd")
if GUI_PinInd then
GUI_PinInd:SettingsMode(false)
end
reset_indicator()
destroy_pin_window()
end
-- ======================================================================
--[[ ICON AND SET HUD INDICATOR
See the hud_themes table and PAW's MCM menu for more info
-- ====================================================================]]
GUI_PinInd = nil
class "UIPAWIndicator" (CUIScriptWnd)
function UIPAWIndicator:__init(settings_mode,anchor) super()
vl("PAW init called, active theme is %s | widget_active %s | widget_enabled %s | settingsmode %s",active_theme,widget_active,widget_enabled,settingsmode)
self.anchor = anchor
if settings_mode then
self:SettingsMode(true)
end
if not widget_enabled then return end
self.theme = hud_themes[active_theme]
self:InitControls()
self:DrawIndicator(self.theme)
self:InitCallBacks()
get_hud():AddDialogToRender(self)
end
function UIPAWIndicator:__finalize()
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
vl("UIPAWIndicator:InitControls: active icon is %s",self.icon_curr)
end
2024-03-20 06:40:41 -04:00
function UIPAWIndicator:GetAnchorStatic()
if self.dialog then
dl("Passing widget handler back to calling func")
return self.dialog
else
dl("ERROR self.dialog was nil!")
end
end
function UIPAWIndicator:BackupRestoreSettings(restore)
if not self.backups then
self.backups = {}
end
if restore then
local pos = self.backups.cust_pos
dl("UIPinSettingsWnd | restoring old settings:\nwidget_enabled = %s\nwidget_hide_delay = %s | active_theme = %s | cust pos = %s,%s",widget_enable,widget_hide_delay,active_theme,pos.x,pos.y)
widget_enabled = self.backups.enable
active_theme = self.backups.active
widget_hide_delay = self.backups.autohide
widget_use_custom_pos = self.backups.use_cust_pos
widget_custom_pos = self.backups.cust_pos
self.anchor = self
self.backups = {}
else
local pos = widget_custom_pos
dl("UIPinSettingsWnd | storing current settings:\nwidget_enabled = %s\nwidget_hide_delay = %s | active_theme = %s | cust pos = %s,%s",widget_enable,widget_hide_delay,active_theme,pos.x,pos.y)
self.backups = {
enabled = widget_enabled,
autohide = widget_hide_delay,
active = active_theme,
use_cust_pos= widget_use_custom_pos,
cust_pos = widget_custom_pos,
}
end
end
function UIPAWIndicator:SettingsMode(onoff)
self.settings_mode = onoff and true or false
if onoff then
self:BackupRestoreSettings()
active_theme = "pin_sidebar"
widget_hide_delay = 0
widget_use_custom_pos = true
widget_enabled = true
else
self:BackupRestoreSettings(true)
end
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:IconPrev()
--printf("UIPAWIndicator:IconPrev fired")
cycle_icons(-1,false)
end
function UIPAWIndicator:IconNext()
--printf("UIPAWIndicator:IconNext fired")
cycle_icons(1,false)
end
function UIPAWIndicator:SetPrev()
--printf("UIPAWIndicator:SetPrev fired")
cycle_sets(-1,false)
end
function UIPAWIndicator:SetNext()
--printf("UIPAWIndicator:SetNext fired")
cycle_sets(1,false)
end
function UIPAWIndicator:InitIcosetControls()
local xml = CScriptXmlInit()
xml:ParseFile("paw_ui_elements.xml")
local icoset_c = "icoset_controls"
local icoset = icoset_c..":"
local btn_iprev = icoset.."btn_ico_prev"
local btn_inext = icoset.."btn_ico_next"
local btn_sprev = icoset.."btn_set_prev"
local btn_snext = icoset.."btn_set_next"
local btn_apply = icoset.."btn_apply"
self.icoset_controls = xml:InitStatic(icoset_c, self.dialog)
self.icon_controls = xml:InitStatic(icoset_c, self.icoset_controls)
self.set_controls = xml:InitStatic(icoset_c, self.icoset_controls)
--printf("icon name: %s | set name: %s",local_icon_name(),local_set_name())
function setup_icoset_ctrl(icoset_arg, pos_x, pos_y)
local btnx_ = "btn_"
local stub = string.sub(icoset_arg,1,3)
local abbr = string.sub(icoset_arg,1,1)
local mwi = "mwi_"
local button_prev = btnx_..abbr.."prev"
local button_next = btnx_..abbr.."next"
local node_prev = icoset..btnx_..stub.."_prev"
local node_next = icoset..btnx_..stub.."_next"
local icoset_ctrl = icoset_arg.."_controls"
local logo = "logo_"..icoset_arg
--local text_cap = (abbr == "s") and
-- local_set_name() or local_icon_name()
--printf("setup_icoset_ctrl(%s,%s,%s) for %s\nstub = %s\nabbr = %s\nbutton_prev = %s\nbutton_next = %s\nnode_prev = %s\nnode_next = %s\nicoset_ctrl = %s\n",icoset_arg, pos_x, pos_y,text_cap,stub,abbr,button_prev,button_next,node_prev,node_next,icoset_ctrl)
self[button_prev] = xml:Init3tButton(node_prev, self[icoset_ctrl])
self:Register(self[button_prev],button_prev)
self[logo] = xml:InitStatic(icoset..logo, self[icoset_ctrl])
unsquish_aspect(self[logo])
self[button_next] = xml:Init3tButton(node_next, self[icoset_ctrl])
self:Register(self[button_next],button_next)
self[mwi..icoset_arg] = xml:InitStatic("mwheel_ind",self.dialog)
--self.cap[icoset_arg] = xml:InitStatic(caption,self[button_prev])
--self.cap[icoset_arg]:TextControl():SetText(text_cap)
self[icoset_ctrl]:SetWndPos(vector2():set(pos_x,pos_y))
end
function setup_button(button,pos_x,pos_y,xmlnode)
local buttonx = "btn_"..button
vl("Initializing button %s (%s) at %s,%s",buttonx,button,pos_x,pos_y)
self[buttonx] = xml:Init3tButton(xmlnode, self.icoset_controls)
self:Register(self[buttonx],buttonx)
self[buttonx]:SetWndPos(vector2():set(pos_x,pos_y))
end
setup_icoset_ctrl( "icon", 92, 34 )
setup_icoset_ctrl( "set", 109.5, 118 )
setup_button( "apply", 82.5, 64, btn_apply )
setwndpos( self.mwi_icon, 145, 8 )
setwndpos( self.mwi_set, 104, 131 )
--================================================================--
self.icoset_controls:Show(self.settings_mode)
end
function UIPAWIndicator:ApplyIconToPin()
GUI_PinOpts:ApplyIconToPin()
end
function UIPAWIndicator:InitCallBacks()
vl("UIPAWIndicator registering callbacks")
RegisterScriptCallback("actor_on_net_destroy", self)
self:AddCallback("btn_apply", ui_events.BUTTON_CLICKED, self.ApplyIconToPin, self)
self:AddCallback("btn_iprev", ui_events.BUTTON_CLICKED, self.IconPrev, self)
self:AddCallback("btn_inext", ui_events.BUTTON_CLICKED, self.IconNext, self)
self:AddCallback("btn_sprev", ui_events.BUTTON_CLICKED, self.SetPrev, self)
self:AddCallback("btn_snext", ui_events.BUTTON_CLICKED, self.SetNext, 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.anchor or self)
local anchor = self.anchor or self--GUI_PinOpts and GUI_PinOpts.dialog
self.dialog = xml:InitStatic(theme.node, anchor)
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))
if self.settings_mode then
self.box_text:SetWndPos(vector2():set(0,0))
self.box_text:SetTextAlignment(1)
self.box_text2:SetWndPos(vector2():set(0,0))
self.box_text2:SetTextAlignment(1)
self:InitIcosetControls()
end
elseif theme.style == "minimal" then
self.box_text:SetText(ts("ui_mcm_lst_"..self.icon_curr))
end
vl("UIPAWIndicator:DrawIndicator completed")
end
2024-03-17 20:18:03 -04:00
function UIPAWIndicator:Update(force)
2024-03-20 06:40:41 -04:00
if self.killswitch then return end
2024-03-17 20:18:03 -04:00
CUIScriptWnd.Update(self)
self.dialog:Show(false)
2024-03-20 06:40:41 -04:00
if not ((widget_enabled and main_hud_shown()) or pin_window_is_open()) then return end
2024-03-17 20:18:03 -04:00
local theme = self.theme
local pda_changed = false
2024-03-20 06:40:41 -04:00
if not pin_window_is_open() then
if self.pda_active ~= item_device.is_pda_active() then
pda_changed = true
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
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
else
widget_active = psw_sidebar_state
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
if widget_active and self.settings_mode then
self.mwi_set:Show(false)
self.mwi_icon:Show(false)
for ctrl,icoset in pairs(hover_elements) do
--printf("Checking hover state for %s element %s",icoset,ctrl)
if self[ctrl]:IsCursorOverWindow() then
self["mwi_"..icoset]:Show(true)
end
end
end
2024-03-17 20:18:03 -04:00
end
2024-03-20 06:40:41 -04:00
function reset_indicator(force,anchor)
2024-03-17 20:18:03 -04:00
vl("Resetting PAW indicator")
2024-03-20 06:40:41 -04:00
if GUI_PinInd then GUI_PinInd:Destroy() end
if not (force or widget_enabled) then return end
2024-03-17 20:18:03 -04:00
vl("Re-initializing PAW indicator")
2024-03-20 06:40:41 -04:00
GUI_PinInd = UIPAWIndicator(force,anchor)
2024-03-17 20:18:03 -04:00
end
function show_indicator(tf)
2024-03-20 06:40:41 -04:00
if not (GUI_PinInd and widget_enabled) then return end
if tf == nil then
widget_active = not widget_active
2024-03-17 20:18:03 -04:00
else
widget_active = (tf == true) or false
end
2024-03-20 06:40:41 -04:00
GUI_PinInd:Show(widget_active)
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
local pin = pins[id] and do_paw_action("pn_del",se_obj,nil,{syscall=true,id=id})
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
end
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
local far_adj = 1.75 -- max icon vertical position change from distance
2024-03-17 20:18:03 -04:00
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))
2024-03-20 06:40:41 -04:00
local f_near = wp_near_fade_dist
local f_far = wp_far_fade_dist
local f_hide = wp_far_hide_dist
fade_by_dist(self.marker, dist,f_near,f_far,f_hide)
fade_by_dist(self.dist, dist,f_near,f_far,f_hide,255,230,230,230,1)
fade_by_dist(self.dist_sh, dist,f_near,f_far,f_hide,255,0,0,0,1)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
return true
2024-03-17 20:18:03 -04:00
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])
2024-03-20 06:40:41 -04:00
return true
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
--local name = pins[id].text or pins[id].name
local name = pins[id].name
2024-03-17 20:18:03 -04:00
self.marker:InitTexture(tex)
2024-03-20 06:40:41 -04:00
local color = colors.active
if pins[id].custom_colors then
self.custom_argb = pins[id].colors
local pcc = self.custom_argb
vl("Pin %s has custom ARGB %s,%s,%s,%s",id,pcc.a,pcc.r,pcc.g,pcc.b)
color = GetARGB(pcc.a,pcc.r,pcc.g,pcc.b)
end
self.marker:SetTextureColor(color) -- this may require logic adjustment for transparency interacting with fades
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
local colors = self.custom_argb or {a=255,r=255,g=255,b=255}
fade_by_dist(self.marker, pindist,f_near,f_far,f_hide,colors.a,colors.r,colors.g,colors.b)
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
-- ======================================================================
-- 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
2024-03-17 20:18:03 -04:00
-- ======================================================================
-- 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)
2024-03-20 06:40:41 -04:00
do_paw_action("pn_del",se_obj,nil,{syscall=true})
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
function ctrl_alt_rclick(se_obj,map_table)
-- not currently implemented - considering uses
end
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
--if mod_key_pressed(3) then
-- CTRL+ALT (unused at this time)
-- ctrl_alt_rclick(se_obj,map_table)
-- return
--end
2024-03-17 20:18:03 -04:00
-- LCTRL : Set/Move Waypoint
if waypoint_active then
2024-03-20 06:40:41 -04:00
do_paw_action("wp_mov",se_obj)
2024-03-17 20:18:03 -04:00
else
2024-03-20 06:40:41 -04:00
do_paw_action("wp_set",se_obj)
2024-03-17 20:18:03 -04:00
end
return
elseif mod_key_pressed(3) then
2024-03-20 06:40:41 -04:00
-- LALT : Add or edit Pin
if pins[se_obj.id] then
open_pin_settings(se_obj.id)
else
do_paw_action("pn_add",se_obj)
return
end
2024-03-17 20:18:03 -04:00
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})
2024-03-20 06:40:41 -04:00
printf(logprefix.."Personal Adjustable Waypoint %s started at %s",script_version,time_global())
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
if pins_exist() then
for k,v in pairs(pins) do
pins[k].label = nil
end
end
2024-03-17 20:18:03 -04:00
end
function save_state(data)
update_mcm_icoset_data()
dl("save_state: Cleaning up script zones and temp markers")
2024-03-20 06:40:41 -04:00
script_zone_cleanup()
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
do_paw_action("wp_mov",se_obj)
2024-03-17 20:18:03 -04:00
last_waypoint = savelast
end
reset_indicator()
if wp_hud_icon_enabled then
show_hud_waypoint()
else
hide_hud_waypoint()
end
2024-03-20 06:40:41 -04:00
if (reticle_mode > 0) or (autotag_mode > 0) then
2024-03-17 20:18:03 -04:00
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
2024-03-20 06:40:41 -04:00
2024-03-17 20:18:03 -04:00
function on_mouse_wheel(scroll_dir, flags)
if not mwheel_enabled then
UnregisterScriptCallback("on_mouse_wheel",on_mouse_wheel)
return
end
local now = time_global()
if now < mwheel_next_poll then return end
mwheel_next_poll = now + mwheel_poll_interval
2024-03-20 06:40:41 -04:00
local cycling_active = (icon_cycle_active or set_cycle_active)
local invalid_uistate = actor_menu.inventory_opened() or not cycling_active
local pin_wnd_open = pin_window_is_open()
--printf("on_mouse_wheel: cycling_active %s | invalid_uistate %s | pin_wnd_open %s",cycling_active,invalid_uistate,pin_wnd_open)
if invalid_uistate and not pin_wnd_open then
--printf("Invalid UI state for mouse wheel use, aborting")
return
end
flags.ret_value = false
local cycle_dir = scroll_dir
2024-03-17 20:18:03 -04:00
if cycle_dir == 0 then cycle_dir = -1 end
vl("scroll_dir: %s | cycle_dir: %s",scroll_dir,cycle_dir)
2024-03-20 06:40:41 -04:00
if pin_wnd_open and GUI_PinInd then
for ctrl,icoset in pairs(hover_elements) do
--printf("Checking hover state for GUI_PinInd[%s]",ctrl)
if GUI_PinInd[ctrl]:IsCursorOverWindow() then
cycle_items(cycle_dir,icoset)
return
end
end
if not cycling_active then
flags.ret_value = true
return
end
end
2024-03-17 20:18:03 -04:00
cycle_items(cycle_dir)
end
2024-03-20 06:40:41 -04:00
--[[
function actor_on_stash_create(data)
-- figure out why this causes busyhands with hideout furniture
if not use_custom_backpack_icon then return end
local id = data and data.stash_id
if not id then return end
local hint = data and data.stash_name
local mapspot = stash_icons["player"] or "treasure"
dl("Player placed backpack stash %s (%s), replacing mapspot with %s",hint,id,mapspot)
function replace_spot()
remove_mapspot(id,stash_icons["basic"])
if init_backpack_as_pin then
local sec = data.stash_section
init_new_pin(id,sec,hint,mapspot)
level.map_add_object_spot(id,mapspot,hint)
else
level.map_add_object_spot_ser(id,mapspot,hint)
end
end
-- For some reason the backpack UI script will shit itself if you don't delay messing with the mapspots
CreateTimeEvent("pawdelay","paw"..tostring(time_global()),0.125,replace_spot)
end
function actor_on_stash_remove(data)
if not use_custom_backpack_icon then return end
local id = data and data.stash_id
if not id then return end
local mapspot = stash_icons["player"] or "treasure"
dl("Player picked up backpack stash %s, removing custom mapspot %s",id,mapspot)
if init_backpack_as_pin then
do_paw_action("pn_del",nil,nil,{syscall=true,id=id})
else
remove_mapspot(id,mapspot)
end
end
--]]
2024-03-17 20:18:03 -04:00
function unregister_all_callbacks()
UnregisterScriptCallback("actor_on_update",actor_on_update)
2024-03-20 06:40:41 -04:00
--UnregisterScriptCallback("actor_on_stash_create",actor_on_stash_create)
--UnregisterScriptCallback("actor_on_stash_remove",actor_on_stash_remove)
UnregisterScriptCallback("actor_on_net_destroy",actor_on_net_destroy)
2024-03-17 20:18:03 -04:00
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)
2024-03-20 06:40:41 -04:00
--RegisterScriptCallback("actor_on_stash_create",actor_on_stash_create)
--RegisterScriptCallback("actor_on_stash_remove",actor_on_stash_remove)
2024-03-17 20:18:03 -04:00
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
-- ======================================================================
-- 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
2024-03-20 06:40:41 -04:00
unregister_all_callbacks()
2024-03-17 20:18:03 -04:00
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
-- ======================================================================
2024-03-20 06:40:41 -04:00