Files
Divergent/mods/UI Rework G.A.M.M.A. Style/gamedata/scripts/ui_inventory.script
T
Rage 255081e1ee Added New Mods; Swapped Mods and Removed Some
Removed EGUI in favor of UI Rework by Sota

Added in GTR Optimized for higher res textures, over Zone Reality Remade and removed all files that conflicted from ZRR to save storage space.
2024-03-30 06:43:01 -04:00

4072 lines
124 KiB
Plaintext

--[[
- Tronex
- 2020/2/3 - 2020/4/3
- Inventory simulation
Modes:
1. Inventory
2. Loot
3. Trade
4. Repair/Upgrade
--]]
--[[
- HarukaSai
- 05/04/2022
- Edited for EFP
+ Recoloring of stat bars and slot highlights based on faction
+ Fixed Modern UI rank displaying on stashes
+ Special sounds per slot type
+ Cleaning up of modern UI code
+ Colored faction badges
-08/04/2022
+ MCM configuration of colors
-14/04/2022
+ Highlights only showing if slot is unlocked
-17/04/2022
+ Alternative rank icons
-26/04/2022
+ Lazy way to make it work without MCM
-12/05/2022
+ Replacement of artis on belt via drag and drop
--]]
local enable_feature = true
local enable_item_picker = true
local is_shift_pressed = false
local weight_unit = game.translate_string("st_kg")
local snd_open = sound_object([[interface\inv_open]])
local snd_close = sound_object([[interface\inv_close]])
local snd_item_to_slot = sound_object([[interface\inv_slot]])
local snd_item_to_belt = sound_object([[interface\inv_belt]])
local snd_item_to_ruck = sound_object([[interface\inv_ruck]])
local snd_properties = sound_object([[interface\inv_properties_2]])
local snd_drop_item = sound_object([[interface\inv_drop]])
local snd_attach_addon = sound_object([[interface\inv_attach_addon]])
local snd_detach_addon = sound_object([[interface\inv_detach_addon]])
local snd_item_use = sound_object([[interface\inv_none]])
local clr_weight = {
[1] = GetARGB(255,255,255,255),
[2] = GetARGB(255,255,50,0),
[3] = GetARGB(255,200,150,0),
}
-- Color settings
color_settings = {
["stat_colors"] = true,
["banner_color"] = true,
["slot_colors"] = true,
["use_alt_ranks"] = 0,
["text_color"] = true,
}
faction_color = {
["stalker"] = GetARGB(255, 228, 185, 69 ),
["bandit"] = GetARGB(255, 217, 217, 217),
["csky"] = GetARGB(255, 0, 182, 222),
["dolg"] = GetARGB(255, 193, 32, 38 ),
["freedom"] = GetARGB(255, 79, 162, 69 ),
["killer"] = GetARGB(255, 3, 94, 168),
["army"] = GetARGB(255, 184, 153, 84 ),
["ecolog"] = GetARGB(255, 67, 134, 120),
["monolith"] = GetARGB(255, 81, 231, 241),
["renegade"] = GetARGB(255, 30, 123, 48 ),
["greh"] = GetARGB(255, 255, 93, 0 ),
["isg"] = GetARGB(255, 145, 5, 0 )
}
stat_colors = {
["health"] = GetARGB(255, 255, 0, 0 ),
["radia"] = GetARGB(255, 253, 208, 23 ),
["acid"] = GetARGB(255, 0, 255, 0 ),
["shock"] = GetARGB(255, 255, 255, 0 ),
["fire"] = GetARGB(255, 255, 0, 128),
["psi"] = GetARGB(255, 0, 255, 255),
["wound"] = GetARGB(255, 255, 255, 255),
["fire_wound"] = GetARGB(255, 255, 128, 0 ),
["power"] = GetARGB(255, 128, 255, 255),
["hunger"] = GetARGB(255, 165, 137, 193),
["thirst"] = GetARGB(255, 154, 206, 223),
["sleep"] = GetARGB(255, 253, 222, 238)
}
slot_colors = {
["belt"] = GetARGB(255, 255, 0, 147),
["quick"] = GetARGB(255, 21, 236, 135),
[1] = GetARGB(255, 185, 70, 255), -- Knife
[2] = GetARGB(255, 255, 216, 0 ), -- Pistol
[3] = GetARGB(255, 255, 126, 70 ), -- Rifle
[4] = GetARGB(255, 255, 0, 0 ), -- Grenade
[5] = GetARGB(255, 75, 181, 255), -- Binoculars
[6] = GetARGB(255, 234, 70, 150), -- Bolt
[7] = GetARGB(255, 70, 103, 234), -- Outfit
[8] = GetARGB(255, 0, 193, 255), -- PDA
[9] = GetARGB(255, 0, 108, 255), -- Detector
[10] = GetARGB(255, 59, 244, 146), -- Torch
[12] = GetARGB(255, 122, 0, 244), -- Helmet
[13] = GetARGB(255, 236, 197, 32 ), -- Backpack
}
faction_text_colors = {
["stalker"] = GetARGB(255, 255, 232, 208),
["bandit"] = GetARGB(255, 255, 232, 208),
["csky"] = GetARGB(255, 255, 232, 208),
["dolg"] = GetARGB(255, 255, 232, 208),
["freedom"] = GetARGB(255, 255, 232, 208),
["killer"] = GetARGB(255, 255, 232, 208),
["army"] = GetARGB(255, 255, 232, 208),
["ecolog"] = GetARGB(255, 255, 232, 208),
["monolith"] = GetARGB(255, 255, 232, 208),
["renegade"] = GetARGB(255, 255, 232, 208),
["greh"] = GetARGB(255, 255, 232, 208),
["isg"] = GetARGB(255, 255, 232, 208)
}
banner_color = GetARGB(255, 39, 39, 160)
player_faction_color = GetARGB(255, 255, 232, 208)
local string_format = string.format
-- UI events
local K_Timer = false
local K_M1 = DIK_keys.MOUSE_1
local K_M2 = DIK_keys.MOUSE_2
local K_CTRL = DIK_keys.DIK_LCONTROL
local K_SHFT = DIK_keys.DIK_LSHIFT
local E_PRESS = ui_events.WINDOW_KEY_PRESSED
local E_RELEASE = ui_events.WINDOW_KEY_RELEASED
-- Utils
local in_actor_inv = utils_item.in_actor_inv
local in_npc_inv = utils_item.in_npc_inv
function keybind_pass()
-- I added this to prevent inventory closing after starting because of release keybind
if (K_Timer and (time_global() > K_Timer + 200)) or (not K_Timer) then
K_Timer = time_global()
return true
end
return false
end
local function init_mode(mode, flags, obj)
if db.actor and db.actor:alive() then
start(mode, obj)
end
flags.ret = true
end
local function on_key_press(key)
if (key == DIK_keys.DIK_LSHIFT) or (key == DIK_keys.DIK_RSHIFT) then
is_shift_pressed = true
--printf( "shift pressed" )
end
end
local function on_key_release(key)
if (key == DIK_keys.DIK_LSHIFT) or (key == DIK_keys.DIK_RSHIFT) then
is_shift_pressed = false
--printf( "shift released" )
end
end
function on_game_start()
if enable_feature then
overrides()
RegisterScriptCallback("ActorMenu_on_before_init_mode",init_mode)
RegisterScriptCallback("on_key_press",on_key_press)
RegisterScriptCallback("on_key_release",on_key_release)
end
end
----------------------------------------------------------------
GUI = nil -- instance, don't touch
function start(mode, obj)
if (not mode) then
return
end
if (mode == "loot") and is_shift_pressed then
return
end
if (not GUI) then
GUI = UIInventory()
end
if (GUI) and (not GUI:IsShown()) and keybind_pass() then
if mode == "inventory" then
change_last_mode(1)
GUI:IMode_Init()
elseif mode == "loot" then
change_last_mode(4)
GUI:LMode_Init(obj)
elseif mode == "trade" then
change_last_mode(2)
GUI:TMode_Init(obj)
elseif mode == "repair" then
change_last_mode(3)
GUI:RMode_Init(obj)
end
GUI:ShowDialog(true)
_GUIs_keyfree["UIInventory"] = true
Register_UI("UIInventory","ui_inventory")
end
end
----------------------------------------------------------------
class "UIInventory" (CUIScriptWnd)
function UIInventory:__init() super()
-- Base
self.mode = nil -- "inventory" / "loot" / "trade" / "repair"
self.npc_id = nil
self.possible_kind = {} -- ["s_all"] = true -> show all item kinds
self.CC = {} -- item cell containers
self.flags = { ret_value = true }
-- Technical
self.hover = { idx = false , bag = false, tg = 0 }
self.slot_hl = { idx = false , bag = false }
self.holding_shift = false
self.holding_ctrl = false
self.update_info = false
self.update_inv = false
self.update_bags = {"actor_bag", "actor_trade", "actor_trade_bag", "npc_bag", "npc_trade", "npc_trade_bag" , "picker"}
self.update_items = {}
self.tg_info = nil
self.tg_info_step = 2 --[ms]
self.tg_inv = 0 --[ms]
self.tg_inv_step = 100 --[ms]
self.tg_stats = 0
self.tg_stats_step = 2000 --[ms]
self.tg_hint = nil
self.tg_hint_step = 1000 --[ms]
self.tg_m1 = 0
self.box_init_update = { state = false , tg = 0 }
-- Item cell containers
self.bag_id = {
["actor_bag"] = EDDListType.iActorBag,
["actor_equ"] = EDDListType.iActorSlot,
["actor_belt"] = EDDListType.iActorBelt,
["actor_quick"] = EDDListType.iQuickSlot,
["actor_trade"] = EDDListType.iActorTrade,
["actor_trade_bag"] = EDDListType.iActorBag,
["npc_bag"] = EDDListType.iDeadBodyBag,
["npc_trade"] = EDDListType.iPartnerTrade,
["npc_trade_bag"] = EDDListType.iPartnerTradeBag,
}
-- Slot = Cell to take
self.slot_cell = { -- base slot = {UI slots to fit in}
[1] = {1}, -- Knife
[2] = {2,1,3}, -- Pistol
[3] = {3,2}, -- Rifle
[4] = {4}, -- Grenade
[5] = {5}, -- Binoculars
[6] = {6}, -- Bolt
[7] = {7}, -- Outfit
[8] = {8}, -- PDA
[9] = {9}, -- Detector
[10] = {10}, -- Torch
[11] = {11}, -- Artefact
[12] = {12}, -- Helmet
[13] = {13}, -- Backpack
}
-- Player stats
self.stat_outfit = {}
self.stat_helm = {}
self.stat_arty = {}
self.stat_boost = {}
self.stat_list = {
["health"] = { min= 0 , max= 1 , hint= "st_ui_health_sensor_inv"},
["radia"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","radio_zone_max_power")) , hint= "ui_inv_radiation_protection"},
["acid"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","acid_zone_max_power")) , hint= "ui_inv_chemical_burn_protection"},
["shock"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","electra_zone_max_power")) , hint= "ui_inv_shock_protection" },
["fire"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","fire_zone_max_power")) , hint= "ui_inv_burn_protection" },
["psi"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","psi_zone_max_power")) , hint= "ui_inv_telepatic_protection"},
["wound"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_wound_protection")) , hint= "ui_inv_wound_protection" },
["fire_wound"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_fire_wound_protection")) , hint= "ui_inv_fire_wound_protection" },
["power"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_power_restore_speed")) , hint= "ui_inv_power_restore" },
-- Edited by Sota - added "hint" variable for HTS bars tooltips
["hunger"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_power_restore_speed")) , hint= hts_inventory_bars.get_satiety_val },
["thirst"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_power_restore_speed")) , hint= hts_inventory_bars.get_thirst_val },
["sleep"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_power_restore_speed")) , hint= hts_inventory_bars.get_sleep_val },
}
self.boost_id = {
[ BoosterID["HpRestore"] ] = "health_restore",
[ BoosterID["RadiationRestore"] ] = "radia_restore",
[ BoosterID["PowerRestore"] ] = "power",
[ BoosterID["RadiationProtection"] ] = "radia",
[ BoosterID["TelepaticProtection"] ] = "psi",
[ BoosterID["ChemicalBurnProtection"] ] = "acid",
}
self.boost_id_inv = invert_table( dup_table(BoosterID) )
for name,v in pairs(self.stat_list) do
self.stat_outfit[name] = 0
self.stat_helm[name] = 0
self.stat_boost[name] = 0
self.stat_arty[name] = 0
end
-- Item properties
self.properties = {
["use"] = { index= 1 , name= "st_use", mode= {"inventory"}, cont= {"actor_bag"}, precondition1= {"Cond_Use"}, action= {"Action_Use"} },
["attach_1"] = { index= 2 , name_func= {"Name_Attach",1}, mode= {"inventory"}, cont= {"actor_bag"}, precondition1= {"Cond_Attach",1}, action= {"Action_Attach",1} },
["attach_2"] = { index= 3 , name_func= {"Name_Attach",2}, mode= {"inventory"}, cont= {"actor_bag"}, precondition1= {"Cond_Attach",2}, action= {"Action_Attach",2} },
["attach_3"] = { index= 4 , name_func= {"Name_Attach",3}, mode= {"inventory"}, cont= {"actor_bag"}, precondition1= {"Cond_Attach",3}, action= {"Action_Attach",3} },
["to_slot"] = { index= 5 , name_func= {"Name_Equip"}, mode= {"inventory"}, cont= {"actor_bag"}, precondition1= {"Cond_Equip"}, action= {"Action_Equip"} },
["to_ruck"] = { index= 6 , name_func= {"Name_UnEquip"}, mode= {"inventory","trade"}, cont= {"actor_equ","actor_belt"}, action= {"Action_UnEquip"} },
["move"] = { index= 7 , name_func= {"Name_Move"}, mode= {"loot","trade"}, cont= {"actor_equ","actor_belt","actor_bag","actor_trade_bag","actor_trade","npc_bag","npc_trade","npc_trade_bag"}, precondition1= {"Cond_Move"}, action= {"Action_Move"} },
["move_all"] = { index= 8 , name= "st_move_all", mode= {"loot","trade"}, cont= {"actor_equ","actor_belt","actor_bag","actor_trade_bag","actor_trade","npc_bag","npc_trade","npc_trade_bag"}, precondition1= {"Cond_Childs"}, precondition2= {"Cond_Move"}, action= {"Action_Move_All"} },
["donate"] = { index= 9 , name= "st_donate", mode= {"trade"}, cont= {"actor_trade_bag","actor_trade"},precondition1= {"Cond_NotQuest"}, action= {"Action_Donate"} },
["unload"] = { index= 10, name= "st_unload_magazine", mode= {"loot","inventory"}, cont= {"actor_equ","actor_bag","npc_bag"}, precondition1= {"Cond_Unload"}, action= {"Action_Unload"} },
["custom_1"] = { index= 11, name_func= {"Name_Custom",1}, mode_func= {"Mode_Custom",1}, cont_func= {"Cont_Custom",1}, precondition1= {"Name_Custom",1 }, action= {"Action_Custom",1} },
["custom_2"] = { index= 12, name_func= {"Name_Custom",2}, mode_func= {"Mode_Custom",2}, cont_func= {"Cont_Custom",2}, precondition1= {"Name_Custom",2 }, action= {"Action_Custom",2} },
["custom_3"] = { index= 13, name_func= {"Name_Custom",3}, mode_func= {"Mode_Custom",3}, cont_func= {"Cont_Custom",3}, precondition1= {"Name_Custom",3 }, action= {"Action_Custom",3} },
["custom_4"] = { index= 14, name_func= {"Name_Custom",4}, mode_func= {"Mode_Custom",4}, cont_func= {"Cont_Custom",4}, precondition1= {"Name_Custom",4 }, action= {"Action_Custom",4} },
["custom_5"] = { index= 15, name_func= {"Name_Custom",5}, mode_func= {"Mode_Custom",5}, cont_func= {"Cont_Custom",5}, precondition1= {"Name_Custom",5 }, action= {"Action_Custom",5} },
["custom_6"] = { index= 16, name_func= {"Name_Custom",6}, mode_func= {"Mode_Custom",6}, cont_func= {"Cont_Custom",6}, precondition1= {"Name_Custom",6 }, action= {"Action_Custom",6} },
["custom_7"] = { index= 17, name_func= {"Name_Custom",7}, mode_func= {"Mode_Custom",7}, cont_func= {"Cont_Custom",7}, precondition1= {"Name_Custom",7 }, action= {"Action_Custom",7} },
["custom_8"] = { index= 18, name_func= {"Name_Custom",8}, mode_func= {"Mode_Custom",8}, cont_func= {"Cont_Custom",8}, precondition1= {"Name_Custom",8 }, action= {"Action_Custom",8} },
["custom_9"] = { index= 19, name_func= {"Name_Custom",9}, mode_func= {"Mode_Custom",9}, cont_func= {"Cont_Custom",9}, precondition1= {"Name_Custom",9 }, action= {"Action_Custom",9} },
["custom_10"] = { index= 20, name_func= {"Name_Custom",10}, mode_func= {"Mode_Custom",10}, cont_func= {"Cont_Custom",10}, precondition1= {"Name_Custom",10}, action= {"Action_Custom",10} },
["detach_silencer"] = { index= 21, name= "st_detach_silencer", mode= {"loot","inventory"}, cont= {"actor_equ","actor_bag","npc_bag"}, precondition1= {"Cond_Detach_Silencer"}, action= {"Action_Detach_Silencer"} },
["detach_scope"] = { index= 22, name= "st_detach_scope", mode= {"loot","inventory"}, cont= {"actor_equ","actor_bag","npc_bag"}, precondition1= {"Cond_Detach_Scope"}, action= {"Action_Detach_Scope"} },
["detach_gl"] = { index= 23, name= "st_detach_gl", mode= {"loot","inventory"}, cont= {"actor_equ","actor_bag","npc_bag"}, precondition1= {"Cond_Detach_GL"}, action= {"Action_Detach_GL"} },
["drop"] = { index= 24, name= "st_drop", mode= {"inventory"}, cont= {"actor_equ","actor_bag"}, precondition1= {"Cond_NotQuest"}, action= {"Action_Drop"} },
["drop_all"] = { index= 25, name= "st_drop_all", mode= {"inventory"}, cont= {"actor_bag"}, precondition1= {"Cond_Childs"}, precondition2= {"Cond_NotQuest"}, action= {"Action_Drop_All"} },
}
for _,props in pairs(self.properties) do
if props.mode then t2k_table(props.mode) end
if props.cont then t2k_table(props.cont) end
end
-- Repair/Upgrade mode
self.upgr = { id = false , sec = false , idx = false , bag = false}
self.upgr_tree = {}
self.upgr_installed = {}
self.upgr_last_row = nil
self.upgr_last_col = nil
self.upgr_last_ii = nil
-- Controls
self:InitControls()
self:InitCallbacks()
-- Callbacks
RegisterScriptCallback("actor_item_to_ruck",self)
RegisterScriptCallback("actor_item_to_slot",self)
RegisterScriptCallback("actor_item_to_belt",self)
RegisterScriptCallback("actor_on_item_drop",self)
RegisterScriptCallback("actor_on_item_use",self)
RegisterScriptCallback("actor_on_item_put_in_box",self)
RegisterScriptCallback("actor_on_item_take_from_box",self)
RegisterScriptCallback("npc_on_item_take",self)
RegisterScriptCallback("npc_on_item_drop",self)
RegisterScriptCallback("npc_on_use",self)
RegisterScriptCallback("physic_object_on_use_callback",self)
RegisterScriptCallback("actor_on_net_destroy",self)
end
function UIInventory:__finalize()
end
function UIInventory:InitControls()
self:SetWndRect (Frect():set(0,0,1024,768))
self:SetAutoDelete(true)
self.xml = CScriptXmlInit()
local xml = self.xml
xml:ParseFile ("ui_inventory.xml")
-- Right side - Player
self.trade_bg = xml:InitStatic("trade_bg", self)
-- Added by Sota - inventory grid
local xml_grid = CScriptXmlInit()
xml_grid:ParseFile("actor_menu_grid.xml")
-- Added by Sota - ratio prefix for wide screen
self.is_widescreen_prefix = (utils_xml.is_widescreen() and "_16" or "")
-- Added by Sota - inventory side plugs
local xml_side_plugs = CScriptXmlInit()
xml_side_plugs:ParseFile("actor_menu_side_plugs.xml")
self.left_side_plug = xml_side_plugs:InitStatic("side_plugs:left", self)
self.left_side_plug:Show(false)
self.right_side_plug = xml_side_plugs:InitStatic("side_plugs:right", self)
self.right_side_plug:Show(false)
-- Edited by Sota - parsing info blocks for (actor, npc, upgrade) from a separate file "actor_info.xml"
self.xml_info = CScriptXmlInit()
local xml_info = self.xml_info
xml_info:ParseFile("actor_info.xml")
self.player_dialog = xml:InitStatic("player", self)
self.player_background = xml:InitStatic("player:background", self.player_dialog)
self.player_grid = xml_grid:InitStatic("player:grid", self.player_dialog)
self.player_community_bg = xml_info:InitStatic("player:community_bg", self.player_dialog)
self.player_community_bg:InitTexture("ui_inGame2_faction_bg" .. self.is_widescreen_prefix)
self.player_community_overlay = xml_info:InitStatic("player:community_overlay", self.player_dialog)
self.player_community_icon = xml_info:InitStatic("player:community_icon", self.player_dialog)
self.player_name = xml_info:InitTextWnd("player:name", self.player_dialog)
self.player_community = xml_info:InitTextWnd("player:community", self.player_dialog)
self.player_rank = xml_info:InitTextWnd("player:rank", self.player_dialog)
self.player_rank_icon = xml_info:InitStatic("player:rank_icon", self.player_dialog)
self.player_icon = xml_info:InitStatic("player:icon", self.player_dialog)
self.player_money = xml_info:InitTextWnd("player:money", self.player_dialog)
self.player_money_icon = xml_info:InitStatic("player:money_icon", self.player_dialog)
self.player_weight_cap = xml:InitStatic("player:weight_caption", self.player_dialog)
self.player_weight = xml:InitTextWnd("player:weight", self.player_dialog)
self.player_weight_max = xml:InitTextWnd("player:weight_max", self.player_dialog)
self.player_putall = xml:Init3tButton("player:putall_button", self.player_dialog)
self:Register(self.player_putall, "put_all")
self.player_trade = xml:InitStatic("player:trade_delimiter", self.player_dialog)
self.player_trade_cap = xml:InitStatic("player:trade_delimiter:trade_caption", self.player_trade)
self.player_trade_price = xml:InitTextWnd("player:trade_delimiter:trade_price", self.player_trade)
self.player_trade_weight = xml:InitTextWnd("player:trade_delimiter:trade_weight_max", self.player_trade)
self.player_trade_sell = xml:Init3tButton("player:trade_delimiter:trade_sell_button", self.player_trade)
self:Register(self.player_trade_sell, "sell")
self.CC["actor_bag"] = utils_ui.UICellContainer("actor_bag", self, nil, "player:cont_bag", self.player_dialog)
self.CC["actor_trade"] = utils_ui.UICellContainer("actor_trade", self, nil, "player:cont_trade", self.player_dialog)
self.CC["actor_trade_bag"] = utils_ui.UICellContainer("actor_trade_bag", self, nil, "player:cont_trade_bag", self.player_dialog)
self.CC["actor_bag"].stack_all = enable_item_picker and true or false
self.CC["actor_trade"].stack_all = enable_item_picker and true or false
self.CC["actor_trade_bag"].stack_all = enable_item_picker and true or false
-- self.CC["actor_bag"].sort_method = "kind"
-- self.CC["actor_trade_bag"].sort_method = "kind"
-- Left side -- NPC
self.npc_dialog = xml:InitStatic("npc", self)
self.npc_background = xml:InitStatic("npc:background", self.npc_dialog)
self.npc_grid = xml_grid:InitStatic("npc:grid", self.npc_dialog)
self.npc_community_bg = xml_info:InitStatic("npc:community_bg", self.npc_dialog)
self.npc_community_bg:InitTexture("ui_inGame2_faction_bg" .. self.is_widescreen_prefix)
self.npc_community_overlay = xml_info:InitStatic("npc:community_overlay", self.npc_dialog)
self.npc_community_icon = xml_info:InitStatic("npc:community_icon", self.npc_dialog)
self.npc_name = xml_info:InitTextWnd("npc:name", self.npc_dialog)
self.npc_community = xml_info:InitTextWnd("npc:community", self.npc_dialog)
self.npc_rank = xml_info:InitTextWnd("npc:rank", self.npc_dialog)
self.npc_rank_icon = xml_info:InitStatic("npc:rank_icon", self.npc_dialog)
self.npc_icon = xml_info:InitStatic("npc:icon", self.npc_dialog)
self.npc_money = xml_info:InitTextWnd("npc:money", self.npc_dialog)
self.npc_money_icon = xml_info:InitStatic("npc:money_icon", self.npc_dialog)
self.npc_weight_cap = xml:InitStatic("npc:weight_caption", self.npc_dialog)
self.npc_weight = xml:InitTextWnd("npc:weight", self.npc_dialog)
self.npc_weight_max = xml:InitTextWnd("npc:weight_max", self.npc_dialog)
self.npc_takeall = xml:Init3tButton("npc:takeall_button", self.npc_dialog)
self:Register(self.npc_takeall, "take_all")
self.npc_trade = xml:InitStatic("npc:trade_delimiter", self.npc_dialog)
self.npc_trade_cap = xml:InitStatic("npc:trade_delimiter:trade_caption", self.npc_trade)
self.npc_trade_price = xml:InitTextWnd("npc:trade_delimiter:trade_price", self.npc_trade)
self.npc_trade_weight = xml:InitTextWnd("npc:trade_delimiter:trade_weight_max", self.npc_trade)
self.npc_trade_buy = xml:Init3tButton("npc:trade_delimiter:trade_buy_button", self.npc_trade)
self:Register(self.npc_trade_buy, "buy")
self.CC["npc_bag"] = utils_ui.UICellContainer("npc_bag", self, nil, "npc:cont_bag", self.npc_dialog)
self.CC["npc_trade"] = utils_ui.UICellContainer("npc_trade", self, nil, "npc:cont_trade", self.npc_dialog)
self.CC["npc_trade_bag"] = utils_ui.UICellContainer("npc_trade_bag", self, nil, "npc:cont_trade_bag", self.npc_dialog)
self.CC["npc_bag"].stack_all = enable_item_picker and true or false
self.CC["npc_trade"].stack_all = enable_item_picker and true or false
self.CC["npc_trade_bag"].stack_all = enable_item_picker and true or false
-- self.CC["npc_bag"].sort_method = "kind"
-- self.CC["npc_trade_bag"].sort_method = "kind"
-- Upgrade/Repair
self.npc_up_dialog = xml:InitStatic("upgrade", self)
self.npc_up_background = xml:InitStatic("upgrade:background", self.npc_up_dialog)
self.npc_up_community_bg = xml_info:InitStatic("upgrade:community_bg", self.npc_up_dialog)
self.npc_up_community_bg:InitTexture("ui_inGame2_faction_bg" .. self.is_widescreen_prefix)
self.npc_up_community_overlay = xml_info:InitStatic("upgrade:community_overlay", self.npc_up_dialog)
self.npc_up_community_icon = xml_info:InitStatic("upgrade:community_icon", self.npc_up_dialog)
self.npc_up_name = xml_info:InitTextWnd("upgrade:name", self.npc_up_dialog)
self.npc_up_community = xml_info:InitTextWnd("upgrade:community", self.npc_up_dialog)
self.npc_up_rank = xml_info:InitTextWnd("upgrade:rank", self.npc_up_dialog)
self.npc_up_rank_icon = xml_info:InitStatic("upgrade:rank_icon", self.npc_up_dialog)
self.npc_up_icon = xml_info:InitStatic("upgrade:icon", self.npc_up_dialog)
self.npc_up_money = xml_info:InitTextWnd("upgrade:money", self.npc_up_dialog)
self.npc_up_money_icon = xml_info:InitStatic("upgrade:money_icon", self.npc_up_dialog)
self.npc_up_scheme = xml:InitScrollView("upgrade:scheme", self.npc_up_dialog)
self.npc_up_item = xml:InitStatic("upgrade:item_static", self.npc_up_dialog)
self.npc_up_repair = xml:Init3tButton("upgrade:repair_button", self.npc_up_dialog)
self:Register(self.npc_up_repair, "repair")
self.equ_dialog = xml:InitStatic("equipment", self)
self.equ_background = xml:InitStatic("equipment:background", self.equ_dialog)
-- Slots
self.CC["actor_equ"] = utils_ui.UICellContainer("actor_equ", self, "equipment:cont_equ", "equipment:cont_equ", self.equ_dialog, true)
self.CC["actor_equ"].disable_callback["On_CC_Add"] = true
self.CC["actor_equ"].disable_callback["On_CC_Remove"] = true
for i=1,13 do self.CC["actor_equ"]:AddItemManual(nil, nil, i) end
self.blocker_helm = xml:InitStatic("equipment:cont_equ:blocker_12", self.CC["actor_equ"].prof)
self.blocker_bkpk = xml:InitStatic("equipment:cont_equ:blocker_13", self.CC["actor_equ"].prof)
-- Belt
self.CC["actor_belt"] = utils_ui.UICellContainer("actor_belt", self, "equipment:cont_belt", "equipment:cont_belt", self.equ_dialog, true)
self.CC["actor_belt"].disable_callback["On_CC_Add"] = true
self.CC["actor_belt"].disable_callback["On_CC_Remove"] = true
self.blocker_arty = {}
for i=1,5 do
self.CC["actor_belt"]:AddItemManual(nil, nil, i)
self.blocker_arty[i] = xml:InitStatic("equipment:cont_belt:blocker_" .. i, self.CC["actor_belt"].prof)
end
-- Quick items
self.CC["actor_quick"] = utils_ui.UICellContainer("actor_quick", self, "equipment:cont_quick", "equipment:cont_quick", self.equ_dialog, true)
self.CC["actor_quick"].disable_drag = true
self.CC["actor_quick"].disable_info = true
self.CC["actor_quick"].disable_callback["On_CC_Add"] = true
self.CC["actor_quick"].disable_callback["On_CC_Remove"] = true
self.CC["actor_quick"].showcase = true
self.quick_txt = {}
for i=1,4 do
--self.CC["actor_quick"]:AddItemManual(nil, "bread", i)
self.CC["actor_quick"]:AddItemManual(nil, nil, i)
self.quick_txt[i] = xml:InitStatic("equipment:cont_quick:cell_" .. i .. ":txt", self.CC["actor_quick"].cell[i].cell)
end
-- Edited by Sota - initialized normal stat icons and background for stat bars
-- also parsing stat bars from a separate file "actor_state_info.xml"
-- Stats
self.xml_stats = CScriptXmlInit()
local xml_stats = self.xml_stats
xml_stats:ParseFile ("actor_state_info.xml")
self.stats_dialog = xml_stats:InitStatic("equipment:actor_state_info", self.equ_dialog)
self.stat = {}
for name,_ in pairs(self.stat_list) do
self.stat[name] = {}
self.stat[name].base = xml_stats:InitStatic("equipment:actor_state_info:" .. name .. "_sensor", self.stats_dialog)
self.stat[name].bar_bg = xml_stats:InitStatic("equipment:actor_state_info:" .. name .. "_sensor:state_progress", self.stat[name].base)
self.stat[name].bar = xml_stats:InitProgressBar("equipment:actor_state_info:" .. name .. "_sensor:state_progress", self.stat[name].base)
self.stat[name].ico_base = xml_stats:InitStatic("equipment:actor_state_info:icon", self.stat[name].base)
self.stat[name].ico_def = xml_stats:InitStatic("equipment:actor_state_info:icon:normal", self.stat[name].ico_base)
self.stat[name].ico_def:InitTexture("ui_inGame2_inv_state_" .. name)
self.stat[name].ico_def:Show(true)
self.stat[name].ico_p = xml_stats:InitStatic("equipment:actor_state_info:icon:active", self.stat[name].ico_base)
self.stat[name].ico_p:InitTexture("ui_inGame2_inv_state_P_" .. name)
self.stat[name].ico_p:Show(false)
self.stat[name].ico_n = xml_stats:InitStatic("equipment:actor_state_info:icon:active", self.stat[name].ico_base)
self.stat[name].ico_n:InitTexture("ui_inGame2_inv_state_N_" .. name)
self.stat[name].ico_n:Show(false)
end
-- Added by Sota - find out if HTS Power is installed
self.is_htsp = ( self.stat["power"].base:GetWndPos().x ~= self.stat["hunger"].base:GetWndPos().x )
-- Added by Sota - for HTS bars tooltips
self.hts_tooltips = {
["hunger"] = {},
["thirst"] = {},
["sleep"] = {},
}
for name,_ in pairs(self.hts_tooltips) do
self.hts_tooltips[name].base = xml_stats:InitStatic("equipment:actor_state_info:" .. name .. "_sensor", self.stats_dialog)
self.hts_tooltips[name].tooltip = xml_stats:InitStatic("equipment:actor_state_info:hts_tooltips", self.hts_tooltips[name].base)
self.hts_tooltips[name].tooltip:Show(false)
end
-- Edited by Sota - parsing sorting button blocks from a separate file "actor_sorter.xml"
-- Sorter
self.xml_sorter = CScriptXmlInit()
local xml_sorter = self.xml_sorter
xml_sorter:ParseFile ("actor_sorter.xml")
self.sort_dialog = xml_sorter:InitStatic("equipment:sorter", self.equ_dialog)
self.sort_btn = {}
-- self.sort_num = {}
for i=1,8 do
self.sort_btn[i] = xml_sorter:InitCheck("equipment:sorter:btn_" .. i, self.sort_dialog)
self.sort_btn[i]:SetCheck(false)
local _wrapper = function(handler) -- we need wrapper in order to pass ctrl to method
self:On_Sort(i)
end
self:Register(self.sort_btn[i], "sort_" .. i)
self:AddCallback("sort_" .. i, ui_events.BUTTON_CLICKED, _wrapper, self)
-- self.sort_num[i] = xml:InitTextWnd("equipment:sorter:txt_" .. i, self.sort_dialog)
-- self.sort_num[i]:SetFont(GetFontSmall())
-- self.sort_num[i]:SetText(i)
self.sort_btn[i].num = xml_sorter:InitTextWnd("equipment:sorter:num", self.sort_btn[i])
self.sort_btn[i].num:SetText(i)
end
-- Trash can
self.trash = xml:InitStatic("npc:trash", self)
-- Item picker
self.CC["picker"] = utils_ui.UICellContainer("picker", self, nil, "equipment:cont_picker", self.equ_dialog, nil)
self.CC["picker"].sort_method = "props"
self.CC["picker"].disable_stack = true
self.CC["picker"].disable_scroll_dragdrop = true
self.CC["picker"].parent = { bag = false , idx = false }
self.CC["picker"].disable_callback["On_CC_Add"] = true -- needed to prevent update loop
self.CC["picker"].disable_callback["On_CC_Remove"] = true
-- Edited by Sota
-- self.CC["picker"].scroll:SetWndPos(vector2():set( 10 , 0 ))
local ratio = utils_xml.screen_ratio()
local file_exist = utils_ui_reduced_inv_icons
self.CC["picker"].scroll:SetWndPos(vector2():set( ( 7 + ( file_exist and 2.75 or 0 ) ) * ratio , 0 ))
self.CC["picker"].scroll:SetWndSize(vector2():set( self.CC["picker"].scroll:GetWidth() , self.CC["picker"].scroll:GetHeight() - ( file_exist and 0 or 19 ) ))
-- self.CC["picker"]:SetGridSpecs()
self.CC["picker"]:Show(false)
-- Message box
self.message_box = CUIMessageBoxEx()
self:Register(self.message_box, "mbr")
self.message_box_up = CUIMessageBoxEx()
self:Register(self.message_box_up, "mbu")
-- Info box
self.item_info = utils_ui.UIInfoItem(self)
self.item_info.can_compare = true
-- Upgrade box
self.upgr_info = utils_ui.UIInfoUpgr(self)
-- Item Properties box
self.item_props = utils_ui.UICellProperties(self)
-- Hint Window
self.hint_wnd = xml:InitFrame("hint_wnd:background",self)
self.hint_wnd:SetAutoDelete(false)
self.hint_wnd_text = xml:InitTextWnd("hint_wnd:text",self.hint_wnd)
self.hint_wnd:Show(false)
end
function UIInventory:InitCallbacks()
self:AddCallback("sell", ui_events.BUTTON_CLICKED, self.TMode_Sell, self)
self:AddCallback("buy" , ui_events.BUTTON_CLICKED, self.TMode_Buy, self)
self:AddCallback("put_all" , ui_events.BUTTON_CLICKED, self.LMode_PutAll, self)
self:AddCallback("take_all" , ui_events.BUTTON_CLICKED, self.LMode_TakeAll, self)
self:AddCallback("repair" , ui_events.BUTTON_CLICKED, self.RMode_OnRepair, self)
self:AddCallback("mbr", ui_events.MESSAGE_BOX_YES_CLICKED, self.RMode_RepairYes, self)
self:AddCallback("mbr", ui_events.MESSAGE_BOX_NO_CLICKED, self.Discard, self)
self:AddCallback("mbr", ui_events.MESSAGE_BOX_OK_CLICKED, self.Discard, self)
self:AddCallback("mbu", ui_events.MESSAGE_BOX_YES_CLICKED, self.RMode_UpgradeYes, self)
self:AddCallback("mbu", ui_events.MESSAGE_BOX_NO_CLICKED, self.Discard, self)
end
function UIInventory:Reset(obj)
local to_show = obj and self:IsInvOwner(obj)
local mode = self.mode
local mI = mode == "inventory"
local mL = mode == "loot"
local mT = mode == "trade"
local mR = mode == "repair"
-- Info
self.npc_id = obj and obj:id() or false
self.npc_is_companion = obj and mL and IsStalker(obj) and obj:alive() and obj:has_info("npcx_is_companion") and true or false
self.npc_is_box = obj and IsInvbox(obj) or false
self.npc_is_not_npc = obj and ((obj:name() == "esc_m_trader") or (obj:section() == "m_lesnik"))
local community = db.actor:character_community()
self.faction_color = faction_color[community:sub(7)] or faction_color.stalker
-- Containers
self.CC["actor_bag"]:Show( mI or mL or mR )
self.CC["actor_trade"]:Show( mT )
self.CC["actor_trade_bag"]:Show( mT )
self.CC["npc_bag"]:Show( mL )
self.CC["npc_trade"]:Show( mT )
self.CC["npc_trade_bag"]:Show( mT )
self:Picker_Toggle()
self.trash:Show( mI )
self.CC["actor_bag"].can_select = mR
self.CC["actor_equ"].can_select = mR
self.CC["picker"].can_select = mR
for name,cc in pairs(self.CC) do
cc.trade_profile = nil
end
-- Elements
self.npc_dialog:Show( mL or mT )
self.npc_up_dialog:Show( mR )
self.trade_bg:Show( mT or mR ) -- Edited by Sota - trade background is now in repair mode
-- Added by Sota - side plugs
self.left_side_plug:Show( mL or mT or mR )
self.right_side_plug:Show( mI or mL or mT or mR )
self.player_trade:Show( mT )
self.player_putall:Show( mL )
self.npc_takeall:Show( mL )
self.npc_trade:Show( mT )
self.npc_money:Show( mT )
self.npc_money_icon:Show( mT and (not self.npc_is_box))
self.npc_weight_max:Show( self.npc_is_companion and mL )
self.npc_name:Show(to_show)
self.npc_community:Show(to_show)
self.npc_icon:Show(to_show)
self.npc_up_repair:Enable(false)
self.npc_rank_icon:Show(not self.npc_is_box)
self:ShowFaction("neutral", "npc")
self:RecolorBars()
self.item_info:Update()
self.upgr_info:Update()
self:SetHint(false)
if self.item_props:IsShown() then
self.item_props:OnHide()
end
-- Reset sorting
self.sort_btn[1]:SetCheck(true)
self:On_Sort(1, true)
self.upgr = { id = false , sec = false , idx = false , bag = false}
self.hover = { idx = false , bag = false, tg = 0 }
self.slot_hl = { idx = false , bag = false }
self.holding_ctrl = false
self.holding_shift = false
-- Allow player movement for this UI
self:AllowMovement( mI )
end
-- General
function UIInventory:ParseInventory(npc, all, id_list, ignore_kind)
local inv = {}
local size_c = 0
local pkind = self.possible_kind
local sec, kind, w, h
local function iterate(owner,obj)
sec = obj:section()
kind = SYS_GetParam(0,sec,"kind") or "na"
-- Parsing for kinds, according to sorter
if ignore_kind or pkind["s_all"] or pkind[kind] then
if id_list then
inv[obj:id()] = obj
else
size_c = size_c + 1
inv[size_c] = obj
end
end
end
if self:IsInvOwner(npc) then
if all then
npc:iterate_inventory(iterate,nil)
else
npc:iterate_ruck(iterate,nil)
end
elseif npc and self.npc_is_box then
npc:iterate_inventory_box(iterate,nil)
end
return inv
end
function UIInventory:ParseInventory_Companion(npc, id_list, ignore_kind)
-- only for alive NPCs, player shouldn't get NPC equipped items
-- companions are a special case, player can only get their assigned items
if npc == nil then return end
local npc_id = npc:id()
local inv = {}
local size_c = 0
local pkind = self.possible_kind
local id, sec, kind
local pass = false
local is_assigned_item = axr_companions.is_assigned_item
npc:iterate_inventory( function(owner,obj)
id = obj:id()
sec = obj:section()
kind = SYS_GetParam(0,sec,"kind") or "na"
pass = false
-- Player's assigned items
if is_assigned_item(npc_id, id) then
pass = true
-- Player's strapped weapons
elseif IsWeapon(obj) and se_load_var(id, nil, "strapped_item") then
pass = true
end
-- Parsing for kinds, according to sorter
if pass then
if ignore_kind or pkind["s_all"] or pkind[kind] then
if id_list then
inv[obj:id()] = obj
else
size_c = size_c + 1
inv[size_c] = obj
end
end
end
end)
return inv
end
function UIInventory:IsMode(bag, mode, ...)
local bags = {...}
if (not mode) or (self.mode == mode) then
for i=1,#bags do
if bags[i] == bag then
return true
end
end
end
return false
end
function UIInventory:Item_On_Mode(name, bag)
local props = self.properties[name]
return props.mode[self.mode] and props.cont[bag]
end
function UIInventory:CheckItem(obj, msg)
if (type(obj) == "number") then
obj = level.object_by_id(obj)
end
if (not obj) then
callstack()
printe("!ERROR Can't get item game object!")
else
self:Print(nil, msg, obj:name())
end
return obj
end
function UIInventory:GetPartner()
if self.npc_id then
return (db.storage[self.npc_id] and db.storage[self.npc_id].object or level.object_by_id(self.npc_id))
end
end
function UIInventory:ValidOwner(obj, state)
local p = obj:parent()
if (not p) then
return false
end
if state then
return p:id() == AC_ID
else
local npc = self:GetPartner()
return npc and p:id() == npc:id()
end
end
function UIInventory:IsInvOwner(npc)
-- We need this cause Sid and Forester are not NPCs
return IsStalker(npc) or self.npc_is_not_npc
end
function UIInventory:InitProperties(obj, bag)
if not (obj and bag) then
return
end
self:Print("InitProperties | bag: %s - obj: %s", bag, obj:name())
local id = obj:id()
local mode = self.mode
local context_str = {}
local context_action = {}
local context_params = {}
for n,props in spairs(self.properties, func_index) do
-- Check if prop is aimed for active container
local bag_allowed = true
if props.cont then
bag_allowed = props.cont[bag] and true or false
end
if props.cont_func and props.cont_func[1] and self[props.cont_func[1]] then
bag_allowed = self[props.cont_func[1]](self, obj, bag, unpack(props.cont_func)) and true or false
end
-- Check if prop is aimed for active mode
local mode_allowed = true
if props.mode then
mode_allowed = props.mode[mode] and true or false
end
if props.mode_func and props.mode_func[1] and self[props.mode_func[1]] then
mode_allowed = self[props.mode_func[1]](self, obj, bag, unpack(props.mode_func)) and true or false
end
if mode_allowed and bag_allowed then
-- Evaluate preconditions
local cond = true
local k = 1
while cond and props["precondition" .. k] do
local precond = props["precondition" .. k]
if precond[1] and self[precond[1]] then
cond = self[precond[1]](self, obj, bag, unpack(precond)) and true or false
else
cond = false
end
k = k + 1
end
if cond then
-- Get prop name
local name = props.name or ""
local func_name = props.name_func
if func_name and func_name[1] and self[func_name[1]] then
name = self[func_name[1]](self, id, bag, unpack(func_name)) or name
end
table.insert(context_str, name)
-- Get action
local func_action = props.action
if func_action and func_action[1] and self[func_action[1]] then
table.insert(context_action, func_action[1])
table.insert(context_params, {id, bag, unpack(func_action)})
end
end
end
end
if is_not_empty(context_action) and is_not_empty(context_str) then
self.item_props:Reset(GetCursorPosition(), context_action, context_str, context_params)
self:PlaySND(snd_properties)
end
end
-- Added by HarukaSai - recolors of stat colors based on settings
function UIInventory:RecolorBars()
for name,_ in pairs(self.stat_list) do
local color = color_settings.stat_colors and self.faction_color or stat_colors[name]
self.stat[name].bar:SetColor(color)
end
end
function UIInventory:Discard()
self:Print(nil, "Discard")
end
-- Property naming
function UIInventory:Name_Equip(obj, bag)
obj = self:CheckItem(obj,"Name_Equip")
local clsid = obj:clsid()
local sec = obj:section()
if IsOutfit(nil,clsid) then
return "st_dress_outfit"
elseif IsHeadgear(nil,clsid) then
return "st_dress_helmet"
elseif IsItem("backpack",sec) then
return "st_equip_backpack"
elseif IsArtefact(nil,clsid) then
return "st_move_on_belt"
end
return "st_move_to_slot"
end
function UIInventory:Name_UnEquip(obj, bag)
obj = self:CheckItem(obj,"Name_UnEquip")
local clsid = obj:clsid()
local sec = obj:section()
if IsOutfit(nil,clsid) then
return "st_undress_outfit"
elseif IsHeadgear(nil,clsid) then
return "st_undress_helmet"
elseif IsItem("backpack",sec) then
return "st_unequip_backpack"
end
return "st_unequip"
end
function UIInventory:Name_Attach(obj, bag, temp, slot)
obj = self:CheckItem(obj,"Name_Attach")
local sec = obj:section()
local wpn = slot and db.actor:item_in_slot(slot)
local name = wpn and ui_item.get_obj_name(wpn) or ""
if IsItem("sil",sec) then
return (game.translate_string("st_attach_silencer_to_pistol") .. " (" .. name .. ")")
elseif IsItem("scope",sec) then
return (game.translate_string("st_attach_scope_to_pistol") .. " (" .. name .. ")")
elseif IsItem("gl",sec) then
return (game.translate_string("st_attach_gl_to_rifle") .. " (" .. name .. ")")
end
end
function UIInventory:Name_Move(obj, bag)
obj = self:CheckItem(obj,"Name_Move")
if (self.mode == "loot") and (bag == "npc_bag") then
return "st_move_to_bag"
end
return "st_move_to"
end
function UIInventory:Name_Custom(obj, bag, temp, i)
obj = self:CheckItem(obj,"Name_Custom " .. i)
local sec = obj:section()
local str = SYS_GetParam(0,sec, "use" .. i .. "_functor")
if str then
str = str_explode(str,"%.") -- dot needs escape character!
if str[1] and str[2] and _G[ str[1] ] and _G[ str[1] ][ str[2] ] then
return _G[ str[1] ][ str[2] ](obj)
else
printe("!ERROR UIInventory:Name_Custom | can't find function (%s) for %s in section [%s]", str[1] .. str[2], "use" .. i .. "_functor", sec)
end
end
return false
end
-- Precondition
function UIInventory:Mode_Custom(obj, bag, temp, i)
obj = self:CheckItem(obj,"Mode_Custom " .. i)
local mode = self.mode
local sec = obj:section()
local str = SYS_GetParam(0,sec, "use" .. i .. "_modes","")
if str then
str = str_explode(str,",")
for i=1,#str do
if (mode == str[i]) then
return true
end
end
end
return (mode == "inventory") -- default
end
function UIInventory:Cont_Custom(obj, bag, temp, i)
obj = self:CheckItem(obj,"Cont_Custom " .. i)
local sec = obj:section()
local str = SYS_GetParam(0,sec, "use" .. i .. "_containers","")
if str then
str = str_explode(str,",")
for i=1,#str do
if (bag == str[i]) then
return true
end
end
end
return (bag == "actor_bag") or (bag == "actor_equ") or (bag == "actor_belt") -- default
end
function UIInventory:DB_Custom(obj, bag, temp, i)
obj = self:CheckItem(obj,"DB_Custom " .. i)
return SYS_GetParam(1,obj:section(), "use" .. i .. "_allow_db",false)
end
function UIInventory:Cond_Childs(obj, bag)
obj = self:CheckItem(obj,"Cond_Childs")
local ci = self.CC[bag]:GetCell_ID(obj:id())
return ci.ID == obj:id() and ci:HasChild()
end
function UIInventory:Cond_Use(obj, bag)
obj = self:CheckItem(obj,"Cond_Use")
return IsItem("consumable",obj:section()) and true or false
end
function UIInventory:Cond_Move(obj, bag, temp, bag_to)
if (not obj) then
return false
end
obj = self:CheckItem(obj,"Cond_Move")
self.flags.ret_value = true
SendScriptCallback("ActorMenu_on_item_before_move", self.flags, self.npc_id, obj, self.mode, self.bag_id[bag])
if (not self.flags.ret_value) then
return false
end
-- For custom use of this function
if bag_to then
if (self.mode == "loot") then
if (bag == "actor_bag") or (bag == "actor_equ") then
if bag_to ~= "npc_bag" then return false end
elseif bag_to == "npc_bag" then
if bag_to ~= "actor_bag" then return false end
end
elseif (self.mode == "trade") then
if (bag == "actor_trade_bag") then
if bag_to ~= "actor_trade" then return false end
elseif (bag == "actor_trade") then
if bag_to ~= "actor_trade_bag" then return false end
elseif (bag == "npc_trade_bag") then
if bag_to ~= "npc_trade" then return false end
elseif (bag == "npc_trade") then
if bag_to ~= "npc_trade_bag" then return false end
end
end
end
-- Don't move quest items
if (bag == "actor_bag") and self:Cond_Quest(obj, bag) then
return false
end
if (self.mode == "loot") then
local npc = self.npc_id and get_object_by_id(self.npc_id)
return npc and true or false
elseif (self.mode == "trade") then
if (bag == "actor_trade") or (bag == "npc_trade") then
return true
elseif (bag == "actor_trade_bag") or (bag == "npc_trade_bag") then
return self.CC[bag]:IsTradable(obj)
end
end
end
function UIInventory:Cond_Quest(obj, bag)
obj = self:CheckItem(obj,"Cond_NotQuest")
return (SYS_GetParam(1,obj:section(),"quest_item") == true)
end
function UIInventory:Cond_NotQuest(obj, bag)
obj = self:CheckItem(obj,"Cond_NotQuest")
return (SYS_GetParam(1,obj:section(),"quest_item") ~= true)
end
function UIInventory:Cond_Attach(obj, bag, temp, slot, wpn)
obj = self:CheckItem(obj,"Cond_Attach")
local add_sec = obj:section()
local is_sil = IsItem("sil",add_sec)
local is_scope = IsItem("scope",add_sec)
local is_gl = IsItem("gl",add_sec)
if not (is_sil or is_scope or is_gl) then
return false
end
local wpn = wpn or slot and db.actor:item_in_slot(slot)
if wpn then
if utils_item.can_attach_scope(wpn, obj) then
return true
elseif utils_item.can_attach_silencer(wpn, obj) then
return true
elseif utils_item.can_attach_gl(wpn, obj) then
return true
end
end
return false
end
function UIInventory:Cond_Equip(obj, bag)
obj = self:CheckItem(obj,"Cond_Equip")
-- Attention: equipping something outside of actor inventory will cause a crash!
if (bag ~= "actor_bag") then
return false
end
local sec = obj:section()
local arty = IsArtefact(obj)
local slot = (SYS_GetParam(2,sec,"slot") or -1) + 1
if arty or (slot == 12) or (slot == 13) then
local outfit = db.actor:item_in_slot(7)
if outfit then
local c_outfit = outfit:cast_CustomOutfit()
if arty then
local arty_rooms = c_outfit:get_artefact_count() or 0
local arty_cnt = db.actor:belt_count()
return (arty_rooms > 0) and (arty_rooms > arty_cnt)
elseif (slot == 12) then
return (c_outfit.bIsHelmetAvaliable and true or false)
elseif (slot == 13) then
return (c_outfit.bIsBackpackAvaliable and true or false)
end
end
end
return (not arty) and (SCANNED_SLOTS[slot] == true)
end
function UIInventory:Cond_Unload(obj, bag)
obj = self:CheckItem(obj,"Cond_Unload")
local sec = obj:section()
if IsWeapon(obj) and (not IsItem("fake_ammo_wpn",sec)) then
return obj:get_ammo_in_magazine() > 0
end
return false
end
function UIInventory:Cond_Detach_Silencer(obj, bag)
obj = self:CheckItem(obj,"Cond_Detach_Silencer")
return utils_item.has_attached_silencer(obj)
end
function UIInventory:Cond_Detach_Scope(obj, bag)
obj = self:CheckItem(obj,"Cond_Detach_Scope")
return utils_item.has_attached_scope(obj)
end
function UIInventory:Cond_Detach_GL(obj, bag)
obj = self:CheckItem(obj,"Cond_Detach_GL")
return utils_item.has_attached_gl(obj)
end
-- Actions
function UIInventory:Action_Use(obj, bag)
obj = self:CheckItem(obj,"Action_Use")
-- Force hiding picker on use
self:Picker_Toggle(nil, nil, nil, true)
if (CInventory__eat(obj) == false) then
return
end
db.actor:eat(obj)
-- Sound effect
self:PlaySND(snd_item_use)
self:On_Item_Update()
end
function UIInventory:Action_Donate(obj, bag)
obj = self:CheckItem(obj,"Action_Donate")
local npc = self.npc_id and get_object_by_id(self.npc_id)
if (not npc) then
return
end
self:On_Item_Exchange(db.actor, npc, obj)
end
function UIInventory:Action_Move(obj, bag)
obj = self:CheckItem(obj,"Action_Move")
if (self.mode == "loot") then
local npc = self.npc_id and get_object_by_id(self.npc_id)
if (not npc) then
return
end
if (bag == "actor_bag") or (bag == "actor_equ") then
self:On_Item_Exchange(db.actor, npc, obj)
elseif (bag == "npc_bag") then
self:On_Item_Exchange(npc, db.actor, obj)
end
elseif (self.mode == "trade") then
local bag_to
if (bag == "actor_trade") then bag_to = "actor_trade_bag"
elseif (bag == "actor_trade_bag") then bag_to = "actor_trade"
elseif (bag == "npc_trade") then bag_to = "npc_trade_bag"
elseif (bag == "npc_trade_bag") then bag_to = "npc_trade"
end
-- Make sure item is tradable first
if (not self.CC[bag]:IsTradable(obj)) then
return
end
if bag_to and self.CC[bag_to] then
self.CC[bag]:TransferItem( self.CC[bag_to] , obj)
end
end
SendScriptCallback("ActorMenu_on_item_after_move", self.npc_id, obj, self.mode, self.bag_id[bag])
self:On_Item_Update()
end
function UIInventory:Action_Move_All(obj, bag)
obj = self:CheckItem(obj,"Action_Move_All")
local ci = self.CC[bag]:GetCell_ID(obj:id())
for id,_ in pairs(ci.childs) do
self:Action_Move(id, bag)
end
self:Action_Move(obj, bag)
end
function UIInventory:Action_UnEquip(obj, bag)
obj = self:CheckItem(obj,"Action_UnEquip")
db.actor:move_to_ruck(obj)
--self:UpdateInfo(true)
self:PlaySND(snd_item_to_ruck)
self:On_Item_Update()
end
function UIInventory:Action_Equip(obj, bag)
obj = self:CheckItem(obj,"Action_Equip")
-- Belt
if IsArtefact(obj) then
db.actor:move_to_belt(obj)
self:PlaySND(snd_item_to_belt)
-- Slots
else
-- Gather free compatible slots
local slot = (SYS_GetParam(2,obj:section(),"slot") or -1) + 1
local cc = self.CC["actor_equ"]
local free_slots = {}
local cslots = self.slot_cell[slot] or {}
for i=1,#cslots do
local ci = cc.cell[cslots[i]]
if ci and (not ci:IsShown()) then
table.insert(free_slots, cslots[i])
end
end
if is_empty(free_slots) then
db.actor:make_item_active(obj)
else
-- Get free slot
local slot_new = free_slots[1]
-- Just to make sure
local obj_in = cc:GetObj(slot_new)
if obj_in then
db.actor:move_to_ruck(obj_in)
end
-- Move to slot
db.actor:move_to_slot(obj, slot_new)
end
self:PlaySND(snd_item_to_slot)
end
self:On_Item_Update()
end
function UIInventory:Action_Attach(obj, bag, temp, slot, wpn)
obj = self:CheckItem(obj,"Action_Attach")
if (bag ~= "actor_bag") then
return
end
local wpn = wpn or slot and db.actor:item_in_slot(slot)
if (not wpn) then
return
end
local add_sec = obj:section()
local typ = (IsItem("scope",add_sec) and "scope") or (IsItem("sil",add_sec) and "sil") or (IsItem("gl",add_sec) and "gl")
if (not typ) then
return
end
utils_item.attach_addon(wpn, obj, typ, true)
self:PlaySND(snd_attach_addon)
self:On_Item_Update()
end
function UIInventory:Action_Custom(obj, bag, temp, i)
obj = self:CheckItem(obj,"Action_Custom " .. i)
local sec = obj:section()
local str = SYS_GetParam(0,sec, "use" .. i .. "_action_functor")
if str then
str = str_explode(str,"%.") -- dot needs escape character!
if str[1] and str[2] and _G[ str[1] ] and _G[ str[1] ][ str[2] ] then
_G[ str[1] ][ str[2] ](obj) -- excute
else
printe("!ERROR UIInventory:Action_Custom | can't find function (%s) for %s in section [%s]", str[1] .. str[2], "use" .. i .. "_action_functor", sec)
end
end
self:On_Item_Update()
end
function UIInventory:Action_Detach_Silencer(obj, bag)
obj = self:CheckItem(obj,"Action_Detach_Silencer")
utils_item.detach_addon(obj, nil, "sil")
self:On_Item_Update()
self:PlaySND(snd_detach_addon)
end
function UIInventory:Action_Detach_Scope(obj, bag)
obj = self:CheckItem(obj,"Action_Detach_Scope")
utils_item.detach_addon(obj, nil, "scope")
self:PlaySND(snd_detach_addon)
self:On_Item_Update()
end
function UIInventory:Action_Detach_GL(obj, bag)
obj = self:CheckItem(obj,"Action_Detach_GL")
utils_item.detach_addon(obj, nil, "gl")
self:PlaySND(snd_detach_addon)
self:On_Item_Update()
end
function UIInventory:Action_Unload(obj, bag)
obj = self:CheckItem(obj,"Action_Unload")
obj:force_unload_magazine(true)
self:On_Item_Update()
if self.mode == "loot" and bag == "npc_bag" then
--self:LMode_ResetNPCInventory()
end
end
function UIInventory:Action_Drop(obj, bag)
obj = self:CheckItem(obj,"Action_Drop")
db.actor:drop_item(obj)
self:PlaySND(snd_drop_item)
end
function UIInventory:Action_Drop_All(obj, bag)
obj = self:CheckItem(obj,"Action_Drop_All")
local ci = self.CC[bag]:GetCell_ID(obj:id())
for id,_ in pairs(ci.childs) do
local obj_c = level.object_by_id(id)
if obj_c then
db.actor:drop_item(obj_c)
end
end
db.actor:drop_item(obj)
self:PlaySND(snd_drop_item)
end
-- Shared
function UIInventory:UpdateInfo(go)
-- Update timer
-- Timer ensures that info update happens only once when something change, regardless of how many calls are done
-- pass (go) as true to update instantly
if (not go) then
if (self.update_info) then
self.update_info = false
self.tg_info = time_global()
return
end
if (not self.tg_info) then
return
end
if (time_global() < self.tg_info + self.tg_info_step) then
return
end
end
self.tg_info = nil
-- Update weight, character and prices
self:UpdateWeight()
self:UpdateCharacter()
self:UpdateSlots()
self:UpdateBelt()
self:UpdateQuick()
self:UpdateStats()
self:UpdateInventories()
self:UpdateItems()
self:Picker_Refresh()
if (self.mode == "trade") then
self:TMode_UpdatePrice(self.player_trade_price, self.player_trade_sell, "actor_trade")
self:TMode_UpdatePrice(self.npc_trade_price, self.npc_trade_buy, "npc_trade")
end
-- Update scroll pads
for bag,cc in pairs(self.CC) do
if cc:IsShown() and cc.pad:IsShown() then
cc.pd.update = true
end
end
end
-- Modern UI functions refactored by HarukaSai and Sota
function UIInventory:ShowRank(rank, view)
local selected
if color_settings.use_alt_ranks == 1 then
selected = "_mui"
elseif color_settings.use_alt_ranks == 2 then
selected = "_svui"
elseif color_settings.use_alt_ranks == 3 then
selected = "_svui_alt"
else
selected = ""
end
local texture = string_format("ui_rank_%s%s", rank, selected)
self:Print(nil, "# UIInventory:ShowRank | Rank Texture %s", texture)
self[string_format("%s_rank_icon", view)]:InitTexture(texture)
end
-- Edited by HarukaSai and Sota
function UIInventory:ShowFaction(faction, view)
faction = faction == "army_npc" and "army" or faction
local element_icon = string_format("%s_community_icon", view)
if faction_color[faction] and faction then
local texture_icon = string_format("ui_mm_faction_icon_%s", faction)
self[element_icon]:InitTexture(texture_icon)
self[element_icon]:Show(true)
else
self[element_icon]:Show(false)
end
local texture = string_format("ui_inGame2_faction_%s%s", (faction_color[faction] and faction or "neutral"), self.is_widescreen_prefix)
local element = string_format("%s_community_overlay", view)
self[element]:InitTexture(texture)
local color = faction_color[faction] or faction_color.stalker
if view == "player" then
color = color_settings.banner_color and color or banner_color
end
self[element]:SetTextureColor(color)
end
-- Edited by HarukaSai
function UIInventory:UpdateCharacter()
local actor = db.actor
local actor_rank = ranks.get_obj_rank_name( actor )
local actor_community = actor:character_community():sub(7)
self.player_name:SetText( alife():actor():character_name() )
self.player_community:SetText( game.translate_string(actor_community) )
self.player_community:SetTextColor( color_settings.text_color and faction_text_colors[actor_community] or player_faction_color )
self.player_icon:InitTexture( actor:character_icon() )
self.player_money:SetText( actor:money() )
self:ShowRank( actor_rank, "player" )
self:ShowFaction( actor_community, "player" )
-- NPC
local npc = self:GetPartner()
if (not npc) or (self.npc_is_box) then
return
end
-- in case of rich NPCs
local npc_money = npc:money()
npc_money = npc_money > 999999 and "..." or npc_money
local character_community = npc:character_community()
local mode = self.mode == "repair" and "npc_up" or "npc"
self[string_format("%s_name", mode)]:SetText( npc:character_name() )
self[string_format("%s_community", mode)]:SetText( game.translate_string(character_community) )
self[string_format("%s_community", mode)]:SetTextColor( faction_text_colors[character_community] or player_faction_color )
self[string_format("%s_icon", mode)]:InitTexture( npc:character_icon() )
self[string_format("%s_money", mode)]:SetText( npc_money )
self:ShowRank( ranks.get_obj_rank_name(npc), mode )
self:ShowFaction( character_community, mode )
end
function UIInventory:UpdateWeight()
-- Player
local actor = db.actor
local outfit = actor:item_in_slot(7)
local backpack = actor:item_in_slot(13)
-- Current weight
local tot_weight = actor:get_total_weight()
-- Additional weight - Actor
local max_weight = actor:get_actor_max_weight()
-- Additional weight - Outfit
max_weight = max_weight + (outfit and outfit:get_additional_max_weight() or 0)
-- Additional weight - Backpack
max_weight = max_weight + (backpack and backpack:get_additional_max_weight() or 0)
-- Additional weight - Artefacts
actor:iterate_belt( function(owner, obj)
local c_arty = obj:cast_Artefact()
max_weight = max_weight + (c_arty and c_arty:AdditionalInventoryWeight() or 0)
end)
-- Additional weight - Booster
actor:cast_Actor():conditions():BoosterForEach( function(booster_type, booster_time, booster_value)
if (booster_type == 4) then --eBoostMaxWeight
max_weight = max_weight + booster_value
end
end)
-- Change weight color according to how heavy the actor is
local clr = clr_weight[1]
if (tot_weight > max_weight) then
clr = clr_weight[2]
elseif (tot_weight + 10 > max_weight) then
clr = clr_weight[3]
end
self.player_weight:SetTextColor( clr )
self.player_weight:SetText( strformat("%s %s", round_idp(tot_weight,1), weight_unit) )
self.player_weight_max:SetText( strformat("(max %s %s)", round_idp(max_weight,1), weight_unit) )
-- NPC
local npc = self:GetPartner()
if npc and (self.mode ~= "repair") then
local weight = 0
if self.npc_is_box then
npc:iterate_inventory_box( function(owner,itm)
weight = weight + itm:weight()
end)
elseif self:IsInvOwner(npc) then
weight = npc:get_total_weight()
end
self.npc_weight:SetText( round_idp(weight,1) .. " " .. weight_unit )
self.npc_weight_max:SetText( strformat("(max %s %s)", 30, weight_unit) )
end
end
function UIInventory:UpdateInventories()
if (self.mode == "inventory") or (self.mode == "repair") then
self:IMode_RefreshInventories()
elseif (self.mode == "loot") then
self:LMode_RefreshInventories()
elseif (self.mode == "trade") then
self:TMode_RefreshInventories()
end
end
function UIInventory:UpdateItems()
for i,bag in ipairs(self.update_bags) do
local cc = self.CC[bag]
if cc:IsShown() then
for idx,ci in pairs(cc.cell) do
if ci:IsShown() then
ci:Update()
end
end
end
end
end
function UIInventory:UpdateSlots()
self:Print(nil, "UpdateSlots")
local cc = self.CC["actor_equ"]
-- update items
local actor = db.actor
for i=1,13 do
local slot = self.slot_cell[i] and self.slot_cell[i][1]
if slot then
local item = actor:item_in_slot(i)
if item then
cc:AddItemManual(item, nil, slot)
else
cc:RemoveItemManual(slot)
end
end
end
-- Helmet/Backpack slots blockers
local helm_block = false
local bkpk_block = false
local outfit = actor:item_in_slot(7)
if outfit then
local c_outfit = outfit:cast_CustomOutfit()
helm_block = not (c_outfit.bIsHelmetAvaliable and true or false)
bkpk_block = not (c_outfit.bIsBackpackAvaliable and true or false)
end
self.blocker_helm:Show( helm_block )
self.blocker_bkpk:Show( bkpk_block )
end
function UIInventory:UpdateBelt()
self:Print(nil, "UpdateBelt")
local cc = self.CC["actor_belt"]
-- update items
local actor = db.actor
local outfit = actor:item_in_slot(7)
local cnt_arty = actor:belt_count()
local cnt_arty_slot = outfit and outfit:cast_CustomOutfit():get_artefact_count() or 0
for i=1,5 do
self.blocker_arty[i]:Show(i > cnt_arty_slot)
local item = i <= cnt_arty and actor:item_on_belt(i-1)
if item then
cc:AddItemManual(item, nil, i)
else
cc:RemoveItemManual(i)
end
end
end
function UIInventory:UpdateQuick()
self:Print(nil, "UpdateQuick")
local cc = self.CC["actor_quick"]
for i=1,4 do
local quick_item = get_console_cmd(0,"slot_" .. (i-1))
if quick_item and ini_sys:section_exist(quick_item) then
if (cc.cell[i].sec ~= quick_item) then
cc:AddItemManual(nil, quick_item, i)
end
cc.cell[i]:Colorize( db.actor:object(quick_item) and "def" or "hide" )
end
end
end
function UIInventory:UpdateStats()
--self:Print(nil, "UpdateStats")
local actor = db.actor
-- Outfit
for name,val in pairs(self.stat_outfit) do
self.stat_outfit[name] = 0
end
self.stat_outfit["health_restore"] = 0
self.stat_outfit["radia_restore"] = 0
local outfit = actor:item_in_slot(7)
if outfit then
local c_outfit = outfit:cast_CustomOutfit()
if (not c_outfit) then
printe("UIInventory | can't get cast_CustomOutfit of [%s]", outfit:name())
end
local sec = outfit:section()
local id = outfit:id()
local cond = outfit:condition()
self.stat_outfit["health_restore"] = c_outfit.m_fHealthRestoreSpeed
self.stat_outfit["radia_restore"] = c_outfit.m_fRadiationRestoreSpeed
self.stat_outfit["fire"] = c_outfit:GetDefHitTypeProtection( HitTypeID["Burn"] ) or 0
self.stat_outfit["shock"] = c_outfit:GetDefHitTypeProtection( HitTypeID["Shock"] ) or 0
self.stat_outfit["acid"] = c_outfit:GetDefHitTypeProtection( HitTypeID["ChemicalBurn"] ) or 0
self.stat_outfit["radia"] = c_outfit:GetDefHitTypeProtection( HitTypeID["Radiation"] ) or 0
self.stat_outfit["psi"] = c_outfit:GetDefHitTypeProtection( HitTypeID["Telepatic"] ) or 0
self.stat_outfit["wound"] = c_outfit:GetDefHitTypeProtection( HitTypeID["Wound"] ) or 0
self.stat_outfit["power"] = (c_outfit.m_fPowerRestoreSpeed or 0) * cond
local bone_value = c_outfit:GetBoneArmor( BoneID["bip01_spine"] ) or 0
if (not c_outfit.bIsHelmetAvaliable) then
bone_value = bone_value + c_outfit:GetBoneArmor( BoneID["bip01_head"] ) or 0
end
self.stat_outfit["fire_wound"] = bone_value * cond
end
-- Helmet
for name,val in pairs(self.stat_helm) do
self.stat_helm[name] = 0
end
local helm = actor:item_in_slot(12)
if helm then
local c_helm = helm:cast_Helmet()
if (not c_helm) then
printe("UIInventory | can't get cast_Helmet of [%s]", outfit:name())
end
local sec = helm:section()
local id = helm:id()
local cond = helm:condition()
self.stat_helm["fire"] = c_helm:GetDefHitTypeProtection( HitTypeID["Burn"] ) or 0
self.stat_helm["shock"] = c_helm:GetDefHitTypeProtection( HitTypeID["Shock"] ) or 0
self.stat_helm["acid"] = c_helm:GetDefHitTypeProtection( HitTypeID["ChemicalBurn"] ) or 0
self.stat_helm["radia"] = c_helm:GetDefHitTypeProtection( HitTypeID["Radiation"] ) or 0
self.stat_helm["psi"] = c_helm:GetDefHitTypeProtection( HitTypeID["Telepatic"] ) or 0
self.stat_helm["wound"] = c_helm:GetDefHitTypeProtection( HitTypeID["Wound"] ) or 0
local bone_value = c_helm:GetBoneArmor( BoneID["bip01_head"] ) or 0
self.stat_helm["fire_wound"] = bone_value * cond
end
-- Artefacts
for name,val in pairs(self.stat_arty) do
self.stat_arty[name] = 0
end
self.stat_arty["health_restore"] = 0
self.stat_arty["radia_restore"] = 0
actor:iterate_belt( function(owner, obj)
local sec = obj:section()
local cond = obj:condition()
local immunities_sec = SYS_GetParam(0,obj:section(),"hit_absorbation_sect")
self.stat_arty["health_restore"] = self.stat_arty["health_restore"] + ( cond * SYS_GetParam(2, sec, "health_restore_speed", 0) )
self.stat_arty["radia_restore"] = self.stat_arty["radia_restore"] + ( cond * SYS_GetParam(2, sec, "radiation_restore_speed", 0) )
self.stat_arty["power"] = self.stat_arty["power"] + ( cond * SYS_GetParam(2, sec, "power_restore_speed", 0) )
self.stat_arty["radia"] = self.stat_arty["radia"] + ( cond * SYS_GetParam(2, immunities_sec, "radiation_immunity", 0) )
self.stat_arty["acid"] = self.stat_arty["acid"] + ( cond * SYS_GetParam(2, immunities_sec, "chemical_burn_immunity", 0) )
self.stat_arty["shock"] = self.stat_arty["shock"] + ( cond * SYS_GetParam(2, immunities_sec, "shock_immunity", 0) )
self.stat_arty["fire"] = self.stat_arty["fire"] + ( cond * SYS_GetParam(2, immunities_sec, "burn_immunity", 0) )
self.stat_arty["psi"] = self.stat_arty["psi"] + ( cond * SYS_GetParam(2, immunities_sec, "telepatic_immunity", 0) )
-- self.stat_arty["wound"] = self.stat_arty["wound"] + ( cond * SYS_GetParam(2, immunities_sec, "wound_immunity", 0) )
-- self.stat_arty["fire_wound"] = self.stat_arty["fire_wound"] + ( cond * SYS_GetParam(2, immunities_sec, "fire_wound_immunity", 0) )
end)
-- Boosters
for name,val in pairs(self.stat_boost) do
self.stat_boost[name] = 0
end
self.stat_boost["health_restore"] = 0
self.stat_boost["radia_restore"] = 0
actor:cast_Actor():conditions():BoosterForEach( function(booster_type, booster_time, booster_value)
local boost_id = self.boost_id[booster_type]
--printf("!Booster: %s - %s - %s - %s", self.boost_id_inv[booster_type], booster_type, booster_time, booster_value)
if boost_id then
self.stat_boost[boost_id] = booster_value
end
end)
-- Progress bars
self.stat["health"].bar:SetProgressPos( clamp( actor.health, 0, 1) )
local radia_val = ((self.stat_outfit["radia"] + self.stat_helm["radia"] + self.stat_arty["radia"] + self.stat_boost["radia"]) / self.stat_list["radia"].max)
self.stat["radia"].bar:SetProgressPos( clamp( radia_val, 0, 1) )
local acid_val = ((self.stat_outfit["acid"] + self.stat_helm["acid"] + self.stat_arty["acid"] + self.stat_boost["acid"]) / self.stat_list["acid"].max)
self.stat["acid"].bar:SetProgressPos( clamp( acid_val, 0, 1) )
local shock_val = ((self.stat_outfit["shock"] + self.stat_helm["shock"] + self.stat_arty["shock"]) / self.stat_list["shock"].max)
self.stat["shock"].bar:SetProgressPos( clamp( shock_val, 0, 1) )
local fire_val = ((self.stat_outfit["fire"] + self.stat_helm["fire"] + self.stat_arty["fire"]) / self.stat_list["fire"].max)
self.stat["fire"].bar:SetProgressPos( clamp( fire_val, 0, 1) )
local psi_val = ((self.stat_outfit["psi"] + self.stat_helm["psi"] + self.stat_arty["psi"] + self.stat_boost["psi"]) / self.stat_list["psi"].max)
self.stat["psi"].bar:SetProgressPos( clamp( psi_val, 0, 1) )
local wound_val = ((self.stat_outfit["wound"] + self.stat_helm["wound"] + self.stat_arty["wound"]) / self.stat_list["wound"].max)
self.stat["wound"].bar:SetProgressPos( clamp( wound_val, 0, 1) )
local fire_wound_val = ((self.stat_outfit["fire_wound"] + self.stat_helm["fire_wound"] + self.stat_arty["fire_wound"]) / self.stat_list["fire_wound"].max)
self.stat["fire_wound"].bar:SetProgressPos( clamp( fire_wound_val, 0, 1) )
-- HTS compatibility added by Sota - the power bar is now displayed if HTS Power is installed
if hts_inventory_bars and (not self.is_htsp) then
self.stat["power"].base:Show(false)
else
self.stat["power"].base:Show(true)
-- Special case for power (similar to engine method)
local power = actor:cast_Actor():conditions():V_SatietyPower() --db.actor.satiety
power = power + self.stat_arty["power"]
if outfit then
power = power + self.stat_outfit["power"]
local power_loss = outfit:cast_CustomOutfit().m_fPowerLoss or 0
if power_loss ~= 0 then
power = power / power_loss
end
else
power = power / 0.5
end
power = power / self.stat_list["power"].max
self.stat["power"].bar:SetProgressPos( clamp( power , 0, 15) )
end
-- Edited by Sota - used HTS utils from "hts_inventory_bars.script" by xcvb
-- Satiety Bar
self.stat["hunger"].bar:SetProgressPos( hts_inventory_bars.get_satiety_val() )
-- Thirst Bar
self.stat["thirst"].bar:SetProgressPos( hts_inventory_bars.get_thirst_val() )
-- Sleep bar
self.stat["sleep"].bar:SetProgressPos( hts_inventory_bars.get_sleep_val() )
-- Blinking Icons
for name,v in pairs(self.stat) do
v.ico_p:Show(false)
v.ico_n:Show(false)
end
-- Health
local health_restore = self.stat_outfit["health_restore"] + self.stat_arty["health_restore"] + self.stat_boost["health_restore"]
if (actor.bleeding > 0) or (health_restore < 0) then
self.stat["health"].ico_n:Show(true)
elseif (health_restore > 0) then
self.stat["health"].ico_p:Show(true)
end
-- HTS compatibility added by Sota - the power bar is now displayed if HTS Power is installed
if (not hts_inventory_bars) or self.is_htsp then
-- Power
if (self.stat_boost["power"] < 0) then
self.stat["power"].ico_n:Show(true)
elseif (self.stat_boost["power"] > 0) then
self.stat["power"].ico_p:Show(true)
end
end
-- Radiation
local radia_restore = self.stat_outfit["radia_restore"] + self.stat_arty["radia_restore"] + self.stat_boost["radia_restore"]
if (actor.radiation > 0) then
self.stat["radia"].ico_n:Show(true)
elseif (radia_restore < 0) or (self.stat_boost["radia"] > 0) then
self.stat["radia"].ico_p:Show(true)
end
-- Psi
if (self.stat_boost["psi"] < 0) then
self.stat["psi"].ico_n:Show(true)
elseif (self.stat_boost["psi"] > 0) then
self.stat["psi"].ico_p:Show(true)
end
-- Chemical
if (self.stat_boost["acid"] < 0) then
self.stat["acid"].ico_n:Show(true)
elseif (self.stat_boost["acid"] > 0) then
self.stat["acid"].ico_p:Show(true)
end
end
function UIInventory:On_Sort(ii, ignore)
self:Print(nil, "On_Sort [%s]", ii)
-- Uncheck the rest of buttons
if (not self.sort_btn[ii]:GetCheck()) then
self.sort_btn[ii]:SetCheck(true)
return
end
for i=1,#self.sort_btn do
if i ~= ii then
self.sort_btn[i]:SetCheck(false)
end
end
-- Collect kinds
self.possible_kind = parse_list(ini_sys, "button_sort_tab_" .. ii, "kinds", true) or { ["s_all"] = true }
if ignore then
return
end
-- Update inventories
if (self.mode == "inventory") or (self.mode == "repair") then
self:IMode_ResetInventories()
elseif (self.mode == "loot") then
self:LMode_ResetInventories()
elseif (self.mode == "trade") then -- Special case because we want to keep trade items there without resetting
local cc_a1 = self.CC["actor_trade"]
local cc_a2 = self.CC["actor_trade_bag"]
local cc_b1 = self.CC["npc_trade"]
local cc_b2 = self.CC["npc_trade_bag"]
local actor_trade_ids = {}
for id,idx in pairs(cc_a1.indx_id) do actor_trade_ids[id] = true end
local npc_trade_ids = {}
for id,idx in pairs(cc_b1.indx_id) do npc_trade_ids[id] = true end
self:TMode_ResetInventories(true)
for id,_ in pairs(actor_trade_ids) do
local obj = level.object_by_id(id)
if obj then
--cc_a1:AddItem(obj)
cc_a2:RemoveItem(obj)
end
end
for id,_ in pairs(npc_trade_ids) do
local obj = level.object_by_id(id)
if obj then
--cc_b1:AddItem(obj)
cc_b2:RemoveItem(obj)
end
end
end
end
function UIInventory:Highlight(sec, bag_id)
for bag, id in pairs(self.bag_id) do
if id == bag_id then
local cc = self.CC[bag]
if cc:IsShown() then
local use_main_clr = (bag == "actor_equ") or (bag == "actor_belt") or (bag == "actor_quick")
for idx,ci in pairs(cc.cell) do
if ci.section == sec then
ci:Highlight(true, "blue", use_main_clr)
-- Edited by HarukaSai to display colors based on settings
if use_main_clr then
local color = color_settings.slot_colors and self.faction_color or (
(bag == "actor_belt") and slot_colors.belt or
(bag == "actor_quick") and slot_colors.quick or
slot_colors[idx]
)
ci.hl:SetTextureColor(color)
end
-- end of edit
end
end
end
end
end
end
function UIInventory:UnHighlight_All()
for bag, cc in pairs(self.CC) do
for idx,ci in pairs(cc.cell) do
if (cc.selected ~= idx) then
ci:Highlight(false)
end
end
end
end
function UIInventory:highlight_section_in_slot(sec, bag_id)
self:Highlight(sec, bag_id)
end
-- Item picker
function UIInventory:Picker_Refresh()
if (not enable_item_picker) then
return
end
local cc = self.CC["picker"]
if (not cc:IsShown()) then
return
end
local bag = cc.parent.bag
local idx = cc.parent.idx
local ci = bag and idx and self.CC[bag].cell[idx]
if not (ci and ci:HasChild()) then
self:Print(nil, "Picker_Toggle(%s, %s) | nothing to deal with -> hide", bag, idx)
self:Picker_Update(true)
return
end
local list = cc.indx_id
local inv = dup_table(ci.childs)
inv[ci.ID] = true
for id,_ in pairs(inv) do
if (not list[id]) then
local obj = level.object_by_id(id)
if obj then
cc:AddItem(obj, obj:section())
end
end
end
for id,idx in pairs(list) do
if (not inv[id]) then
cc:RemoveItem_byID(id)
end
end
end
function UIInventory:Picker_Toggle(bag, idx, update_mode, force_hide)
if (not enable_item_picker) then
return
end
if force_hide then
self:Picker_Update(true)
return
end
-- This is needed to avoid resetting picker when we click on item property
-- (300 ms should be fine because low time scope might not be enough)
local no_hide = self.item_props.action_moment and (time_continual() < self.item_props.action_moment + 300)
-- Avoid hiding picker if we are scrolling a pad
for bag,cc in pairs(self.CC) do
if cc:IsShown() and cc.pad:IsShown() and cc.pad:IsCursorOverWindow() then
no_hide = true
break
end
end
local cc = self.CC["picker"]
if (update_mode) then
if (not cc:IsShown()) then
return
end
bag = cc.parent.bag
idx = cc.parent.idx
if not (bag and idx) then
return
end
no_hide = true
else
if no_hide then
self:Print(nil, "Picker_Toggle(%s, %s) | clicked item property -> continue", bag, idx)
return
end
-- Interacting with picker: hide if clicking outside
if cc:IsShown() then
if cc:IsCursorOverWindow() then
self:Print(nil, "Picker_Toggle(%s, %s) | dealing with picker -> continue", bag, idx)
return
elseif (cc.hold.ico:IsShown()) then
self:Print(nil, "Picker_Toggle(%s, %s) | was holding cell -> continue", bag, idx)
return
else
self:Print(nil, "Picker_Toggle(%s, %s) | clicking outside picker area -> hide", bag, idx)
self:Picker_Update(true)
return
end
end
-- Nothing to interact with
if not (bag and idx) then
self:Print(nil, "Picker_Toggle(%s, %s) | nothing to deal with -> hide", bag, idx)
self:Picker_Update(true)
return
end
-- Interacting with picker cell
if (bag == "picker") then
self:Print(nil, "Picker_Toggle(%s, %s) | dealing with picker -> continue", bag, idx)
return
end
end
-- Interacting with cell
local ci = self.CC[bag].cell[idx]
if not (ci and ci:HasChild() and ( cc:IsCursorOverWindow() or ci:IsCursorOverWindow() or no_hide )) then
self:Print(nil, "Picker_Toggle(%s, %s) | cell has no childs or not focused-> hide", bag, idx)
self:Picker_Update(true)
return
end
local obj = level.object_by_id(ci.ID)
if (not obj) then
self:Print(nil, "Picker_Toggle(%s, %s) | cell has no object -> hide", bag, idx)
self:Picker_Update(true)
return
end
-- No picker for items without condition bar
local clsid = obj:clsid()
local use_cond = SYS_GetParam(1,ci.section,"use_condition") or IsWeapon(nil,clsid) or IsOutfit(nil,clsid) or IsHeadgear(nil,clsid)
if not (use_cond or IsAmmo(nil,clsid)) then
self:Print(nil, "Picker_Toggle(%s, %s) | cell has no condition -> hide", bag, idx)
self:Picker_Update(true)
return
end
-- Prepare picker
local t = {}
t[#t+1] = obj
for id,_ in pairs(ci.childs) do
t[#t+1] = level.object_by_id(id)
end
if self.mode == "trade" then
cc.trade_profile = dup_table( self.CC[bag].trade_profile )
end
cc:Reinit(t)
cc:Show(true)
cc.parent.bag = bag
cc.parent.idx = idx
-- For closing picker if player clicked M1 in outer areas
self.tg_m1 = time_global()
self:Print(nil, "Picker_Toggle(%s, %s) | started picker -> stop", bag, idx)
end
function UIInventory:Picker_Ownership(bag, idx, obj)
if bag == "picker" then
local cc = self.CC["picker"]
local ci = self:Picker_OwnerCell(cc)
if ci and ci:IsShown() and obj and (ci.ID == obj:id() or ci:HasChild(obj)) then
local p = cc.parent
self:Print(nil, "Picker_Ownership | bag: %s - idx: %s", p.bag, p.idx)
return p.bag, p.idx
end
end
return bag, idx
end
function UIInventory:Picker_OwnerCell(cc)
cc = cc or self.CC["picker"]
local p = cc.parent
return p.bag and p.idx and self.CC[p.bag].cell[p.idx]
end
function UIInventory:Picker_IsFocused()
local cc = self.CC["picker"]
if cc:IsShown() then
local ci = self:Picker_OwnerCell(cc)
if cc:IsCursorOverWindow() or (ci and ci:IsShown() and ci:IsCursorOverWindow()) then
return true
end
end
return false
end
function UIInventory:Picker_Update(force_hide)
local cc = self.CC["picker"]
if cc:IsShown() then
-- Get Parent Cell
local ci = self:Picker_OwnerCell(cc)
-- Unhighlight and hide
if (size_table(cc.indx_id) <= 1) or force_hide then
if ci and ci:IsShown() then
ci:Highlight(false)
local cip = cc:GetCell_ID(ci.ID)
if cip and cip:IsShown() then
cip:Highlight(true,"green")
end
end
cc:Show(false)
cc.parent.bag = false
cc.parent.idx = false
return false
-- Highlight parent cell
else
if ci and ci:IsShown() then
ci:Highlight(true,"green")
local cip = cc:GetCell_ID(ci.ID)
if cip and cip:IsShown() then
cip:Highlight(true,"green")
end
return true
end
end
end
return false
end
-- Inventory mode
function UIInventory:IMode_Init()
self:Print(nil, "IMode_Init")
self.mode = "inventory"
-- Show/Hide needed elements
self:Reset()
-- Update inventories
self:IMode_ResetInventories()
-- Update info
self:UpdateInfo(true)
-- Sound effect
self:PlaySND(snd_open)
end
function UIInventory:IMode_ResetInventories()
self:Picker_Toggle()
self.CC["actor_bag"]:Reinit( self:ParseInventory(db.actor) )
end
function UIInventory:IMode_RefreshInventories()
-- Actor
local cc_a = self.CC["actor_bag"]
local list_a = cc_a.indx_id
local inv_a = self:ParseInventory(db.actor, nil, true)
for id,obj in pairs(inv_a) do
if (not list_a[id]) then
cc_a:AddItem(obj, obj:section())
end
end
for id,idx in pairs(list_a) do
if (not inv_a[id]) then
cc_a:RemoveItem_byID(id)
end
end
end
-- Loot mode
function UIInventory:LMode_Init(obj)
self:Print(nil, "LMode_Init | obj: %s", obj and obj:name())
self.mode = "loot"
-- Show/Hide needed elements
self:Reset(obj)
-- We need this because box can spawn items after opening, so they don't update those instantly
if self.npc_is_box and (not self.box_init_update.state) then
self.box_init_update.tg = time_global()
self.box_init_update.state = true
self:LMode_ResetInventories(true)
return
end
self.box_init_update.state = false
-- Update inventories
self:LMode_ResetInventories()
-- Update info
self:UpdateInfo(true)
-- Known info (Special case for corpses)
self:LMode_TransferInfo(obj)
-- Sound effect
self:PlaySND(snd_open)
end
function UIInventory:LMode_ResetInventories(reset_only)
if reset_only then
self.CC["actor_bag"]:Reset()
self.CC["npc_bag"]:Reset()
return
end
local npc = self:GetPartner()
local is_box = npc and IsInvbox(npc)
self:Picker_Toggle()
self.CC["actor_bag"]:Reinit( self:ParseInventory(db.actor) )
if self.npc_is_companion then
self.CC["npc_bag"]:Reinit( self:ParseInventory_Companion(npc) )
else
local all = (not is_box) and (npc and (not npc:alive()))
self.CC["npc_bag"]:Reinit( self:ParseInventory(npc, all) )
end
end
function UIInventory:LMode_ResetNPCInventory()
local npc = self:GetPartner()
local is_box = npc and IsInvbox(npc)
self:Picker_Toggle()
if self.npc_is_companion then
self.CC["npc_bag"]:Reinit( self:ParseInventory_Companion(npc) )
else
local all = (not is_box) and (npc and (not npc:alive()))
self.CC["npc_bag"]:Reinit( self:ParseInventory(npc, all) )
end
end
function UIInventory:LMode_RefreshInventories()
-- Actor
local added, removed = {}, {}
local cc_a = self.CC["actor_bag"]
local list_a = cc_a.indx_id
local inv_a = self:ParseInventory(db.actor, nil, true)
for id,obj in pairs(inv_a) do
if (not list_a[id]) then
cc_a:AddItem(obj, obj:section())
added[id] = true
end
end
for id,idx in pairs(list_a) do
if (not inv_a[id]) then
cc_a:RemoveItem_byID(id)
removed[id] = true
end
end
-- NPC
local npc = self:GetPartner()
local is_box = npc and IsInvbox(npc)
local all = (not is_box) and (npc and (not npc:alive()))
local cc_b = self.CC["npc_bag"]
local list_b = cc_b.indx_id
local inv_b = self.npc_is_companion and self:ParseInventory_Companion(npc, true) or self:ParseInventory(npc, all, true)
for id,obj in pairs(inv_b) do
if (not list_b[id]) then
cc_b:AddItem(obj, obj:section())
if is_box and removed[id] then
SendScriptCallback("actor_on_item_put_in_box", npc, obj)
end
end
end
for id,idx in pairs(list_b) do
if (not inv_b[id]) then
cc_b:RemoveItem_byID(id)
if is_box and added[id] then
SendScriptCallback("actor_on_item_take_from_box", npc, level.object_by_id(id))
end
end
end
end
function UIInventory:LMode_PutAll()
self:Print(nil, "LMode_PutAll")
local npc = self:GetPartner()
if (not npc) then
return
end
local cc = self.CC["actor_bag"]
if (not cc) then
return
end
-- We need to make sure that the other NPC has enough carry weight
if IsStalker(npc) and npc:alive() then
local tot_weight = 0
for id,idx in pairs(cc.indx_id) do
local ci = cc:GetCell_ID(id)
if ci then
-- Transfer item
local obj = level.object_by_id(id)
if self:Cond_Move(obj, "actor_bag") then
tot_weight = tot_weight + obj:weight()
end
end
end
if utils_item.is_overweight(npc, nil, tot_weight) then
return
end
end
-- Move all possible items
for id,idx in pairs(cc.indx_id) do
local ci = cc:GetCell_ID(id)
if ci then
local obj = level.object_by_id(id)
if self:Cond_Move(obj, "actor_bag") then
self:Action_Move(obj, "actor_bag")
end
end
end
-- Update info
self.update_info = true
end
function UIInventory:LMode_TakeAll()
self:Print(nil, "LMode_TakeAll")
local npc = self:GetPartner()
if (not npc) then
return
end
local cc = self.CC["npc_bag"]
if (not cc) then
return
end
for id,idx in pairs(cc.indx_id) do
local ci = cc:GetCell_ID(id)
if ci then
-- Transfer item
local obj = level.object_by_id(id)
if self:Cond_Move(obj, "npc_bag") then
self:Action_Move(obj, "npc_bag")
end
end
end
-- Update info
self.update_info = true
end
function UIInventory:LMode_TransferInfo(npc)
-- Only for dead stalkers
if not (npc and IsStalker(npc) and (not npc:alive())) then
return
end
local custom_data = ini_sys:r_string_ex(npc:section(),"custom_data")
local char_ini = custom_data and ini_file(custom_data)
local known_info = char_ini and char_ini:r_string_ex("logic","known_info")
if known_info and char_ini:section_exist(known_info) then
local n = char_ini:line_count(known_info)
for i=0,n-1 do
local result, id, value = char_ini:r_line(known_info,i,"","")
-- Transfer info portion from corpse to actor
if id and npc:has_info(id) then
npc:disable_info_portion(id)
give_info(id)
end
end
end
end
-- Trade mode
function UIInventory:TMode_Init(npc)
self:Print(nil, "TMode_Init | npc: %s", npc and npc:name())
self.mode = "trade"
-- Show/Hide needed elements
self:Reset(npc)
-- Update inventories
self:TMode_InitProfile(npc)
self:TMode_ResetInventories()
-- Update info
self:UpdateInfo(true)
-- Sound effect
self:PlaySND(snd_open)
end
function UIInventory:TMode_ResetInventories(only_bags)
local npc = self:GetPartner()
self:Picker_Toggle()
if (not only_bags) then
self.CC["actor_trade"]:Reinit()
self.CC["npc_trade"]:Reinit()
end
self.CC["actor_trade_bag"]:Reinit( self:ParseInventory(db.actor) )
self.CC["npc_trade_bag"]:Reinit( self:ParseInventory(npc) )
end
function UIInventory:TMode_RefreshInventories()
-- Actor
local cc_a = self.CC["actor_trade_bag"]
local cc_at = self.CC["actor_trade"]
local list_a = cc_a.indx_id
local list_at = cc_at.indx_id
local inv_a = self:ParseInventory(db.actor, nil, true)
for id,obj in pairs(inv_a) do
if (not list_a[id]) and (not list_at[id]) then
cc_a:AddItem(obj, obj:section())
end
end
for id,idx in pairs(list_a) do
if (not inv_a[id]) then
cc_a:RemoveItem_byID(id)
end
end
for id,idx in pairs(list_at) do
if (not inv_a[id]) then
local obj = level.object_by_id(id)
if obj and (not in_actor_inv(obj)) then -- Important because trade bag is proccessed differently
cc_at:RemoveItem_byID(id)
end
end
end
-- NPC
local npc = self:GetPartner()
local cc_b = self.CC["npc_trade_bag"]
local cc_bt = self.CC["npc_trade"]
local list_b = cc_b.indx_id
local list_bt = cc_bt.indx_id
local inv_b = self:ParseInventory(npc, nil, true)
for id,obj in pairs(inv_b) do
if (not list_b[id]) and (not list_bt[id]) then
cc_b:AddItem(obj, obj:section())
end
end
for id,idx in pairs(list_b) do
if (not inv_b[id]) then
cc_b:RemoveItem_byID(id)
end
end
--
for id,idx in pairs(list_bt) do
if (not inv_b[id]) then
local obj = level.object_by_id(id)
if obj and (not in_npc_inv(npc, obj)) then -- Important because trade bag is proccessed differently
cc_bt:RemoveItem_byID(id)
end
end
end
--
end
function UIInventory:TMode_InitProfile(npc)
self:Print(nil, "TMode_InitProfile | npc: %s", npc and npc:name())
local id = npc:id()
-- Actor
local actor_trade_profile = {
mode = 1,
cfg = trade_manager.get_trade_profile(id, "cfg_ltx"),
list = trade_manager.get_trade_profile(id, "current_buy_condition"), -- list of all items that npc can buy
cond_factor = trade_manager.get_trade_profile(id, "current_buy_item_condition_factor"), -- no buy below this condition
cond_exponent = trade_manager.get_trade_profile(id, "current_buy_item_exponent"), -- multiplier for condition
discount = trade_manager.get_buy_discount(id), -- cost factor for items in player side
}
local actor_trade_bags = {"actor_trade","actor_trade_bag","actor_equ","actor_belt"}
for i,bag in ipairs(actor_trade_bags) do
self.CC[bag].trade_profile = dup_table(actor_trade_profile)
end
-- NPC
local npc_trade_profile = {
mode = 2,
cfg = trade_manager.get_trade_profile(id, "cfg_ltx"),
list = trade_manager.get_trade_profile(id, "current_sell_condition"), -- list of all items that npc can sell
-- cond_factor = 1,
cond_exponent = trade_manager.get_trade_profile(id, "current_sell_item_exponent"), -- multiplier for condition
discount = trade_manager.get_sell_discount(id), -- cost factor for items in npc side
}
local npc_trade_bags = {"npc_trade","npc_trade_bag"}
for i,bag in ipairs(npc_trade_bags) do
self.CC[bag].trade_profile = dup_table(npc_trade_profile)
end
--[[
['current_sell_item_exponent'] = 0.75,
['cfg_ltx'] = 'items\trade\trade_mercenary.ltx',
['current_buy_item_condition_factor'] = 0.6,
['resupply_time'] = {
['M'] = 10,
['s'] = 58,
['ms'] = 674,
['Y'] = 2018,
['h'] = 9,
['m'] = 40,
['D'] = 25
},
['current_sell_condition'] = 'trade_generic_sell',
['current_buy_condition'] = 'trade_generic_buy',
['checked'] = true,
['current_buy_item_exponent'] = 2.25,
['current_buy_supplies'] = 'supplies_1'
--]]
end
function UIInventory:TMode_UpdatePrice(ele_txt, ele_btn, bag)
self:Print(nil, "TMode_UpdatePrice | bag: %s", bag)
local tot_cost = 0
local cc = self.CC[bag]
if (not cc) then
return
end
for idx,ci in pairs(cc.cell) do
tot_cost = tot_cost + cc:GetCellCost(ci)
end
tot_cost = math.floor(tot_cost)
ele_txt:SetText(tot_cost .. " RU")
ele_btn:Enable( tot_cost > 0 )
end
function UIInventory:TMode_Sell()
self:Print(nil, "TMode_Sell")
local npc = self:GetPartner()
if (not npc) then
return
end
local cc = self.CC["actor_trade"]
if (not cc) then
return
end
if not npc:alive() then
return
end
-- Calculate full price
local tot_cost = 0
for idx,ci in pairs(cc.cell) do
tot_cost = tot_cost + cc:GetCellCost(ci)
end
tot_cost = math.floor(tot_cost)
-- Don't processed if NPC doesn't have enough money
if npc:money() < tot_cost then
self.message_box:InitMessageBox("message_box_ok")
self.message_box:SetText( game.translate_string("not_enough_money_partner") )
self.message_box:ShowDialog(true)
return
end
-- Transfer items
for id,idx in pairs(cc.indx_id) do
local ci = cc:GetCell_ID(id)
if ci then
self:On_Item_Exchange(db.actor, npc, level.object_by_id(id))
end
end
-- Transfer money
db.actor:give_money(tot_cost)
npc:give_money(-tot_cost)
-- Update UI
self.update_info = true
end
function UIInventory:TMode_Buy()
self:Print(nil, "TMode_Buy")
local npc = self:GetPartner()
if (not npc) then
return
end
local cc = self.CC["npc_trade"]
if (not cc) then
return
end
-- Calculate full price
local tot_cost = 0
for idx,ci in pairs(cc.cell) do
tot_cost = tot_cost + cc:GetCellCost(ci)
end
tot_cost = math.floor(tot_cost)
-- Don't processed if player doesn't have enough money
if db.actor:money() < tot_cost then
self.message_box:InitMessageBox("message_box_ok")
self.message_box:SetText( game.translate_string("not_enough_money_actor") )
self.message_box:ShowDialog(true)
return
end
-- Transfer items
for id,idx in pairs(cc.indx_id) do
local ci = cc:GetCell_ID(id)
if ci then
self:On_Item_Exchange(npc, db.actor, level.object_by_id(id))
end
end
-- Transfer money
npc:give_money(tot_cost)
db.actor:give_money(-tot_cost)
-- Update UI
self.update_info = true
end
-- Repair/Upgrade mode
function UIInventory:RMode_Init(npc)
self:Print(nil, "RMode_Init | %s", npc and npc:name())
self.mode = "repair"
-- Show/Hide needed elements
self:Reset(npc)
-- Update inventories
self:IMode_ResetInventories()
-- Hide existing tree
self:RMode_InitItem()
-- Update info
self:UpdateInfo(true)
-- Sound effect
self:PlaySND(snd_open)
end
function UIInventory:RMode_InitElements()
self:Print(nil, "RMode_InitElements")
local xml = self.xml
self.upx = {} -- upgrade_xml
-- All possible rows
for r=1,5 do
local _st = xml:InitStatic("upgrade:st", nil)
-- All possible elements
for c=1,6 do
-- In case colomn has solo element
for s=1,2 do
local str = ""
if odd(c) then
str = (s == 2) and "b" or ""
end
if not ((s == 2) and (not odd(c))) then
local ii = (r..c..str)
self:Print(nil, "RMode_InitElements | init for index: %s", ii)
self.upx[ii] = {}
self.upx[ii].base = xml:InitStatic("upgrade:row_cells:cell_" .. (c..str), _st)
self.upx[ii].ico = xml:InitStatic("upgrade:cell_upgrade:ico", self.upx[ii].base)
self.upx[ii].btn = xml:InitCheck("upgrade:cell_upgrade:btn", self.upx[ii].base)
self.upx[ii].row = r
self.upx[ii].col = c
-- Callback
self:Register(self.upx[ii].btn, "btn_up_" .. ii)
local _wrapper = function(self) -- we need wrapper in order to pass ctrl to method
self:RMode_OnUpgrade(r, c, ii)
end
self:AddCallback("btn_up_" .. ii, ui_events.BUTTON_CLICKED, _wrapper, self)
end
end
end
self.npc_up_scheme:AddWindow(_st, true)
_st:SetAutoDelete(false)
end
-- Upgrade order table
self.upgr_order = {}
local upg_gr = {
[1] = "first",
[2] = "secon",
[3] = "third",
[4] = "fourt",
[5] = "fifth",
}
local upg_ind = {
[1] = "a",
[2] = "b",
[3] = "c",
[4] = "d",
[5] = "e",
[6] = "f",
}
for i=1,#upg_gr do
for ii=1,#upg_ind do
self.upgr_order[#self.upgr_order + 1] = upg_gr[i] .. upg_ind[ii]
end
end
end
function UIInventory:RMode_InitItem(obj, bag, idx)
self:Print(nil, "RMode_InitItem | %s", obj and obj:name())
-- Init upgrade scheme if it's not set
if is_empty(self.upx) then
self:RMode_InitElements()
end
-- Clear old data, assign new
empty_table(self.upgr_tree)
empty_table(self.upgr_installed)
-- Hide all possible upgrades
for ii,ele in pairs(self.upx) do
ele.base:Show(false)
ele.btn:Enable(true)
ele.btn:SetCheck(false)
ele.section = nil
ele.prereq = ""
end
-- No object -> reset and return
if (not obj) then
self.upgr = { id = false , sec = false , idx = false , bag = false}
self.npc_up_repair:Enable(false)
self:RMode_InitItemIcon()
return
end
-- Selected object -> get id and section
local id = obj:id()
local sec = obj:section()
self.upgr.id = id
self.upgr.sec = sec
self.upgr.bag = bag
self.upgr.idx = idx
-- Set up upgrade icon
self:RMode_InitItemIcon(obj)
-- Repair button state
self.npc_up_repair:Enable( inventory_upgrades.can_repair_item(sec) and (obj:condition() < 0.99) )
-- Parse mechanic's discount condition
local can_upgrade = inventory_upgrades.can_upgrade_item()
if (not can_upgrade) then
return
end
-- Upgrades tree
self.upgr_tree = utils_item.get_upgrades_tree(sec, true)
if is_empty(self.upgr_tree) then
return
end
-- Installed upgrades
self.upgr_installed = utils_item.get_upgrades_installed(obj, nil, true)
-- Show upgrade tree
for row,v in pairs(self.upgr_tree) do
for col,info in pairs(v) do
local ii = row .. col .. ( info.solo and "b" or "" )
self.upx[ii].section = info.section
self.upx[ii].ico:InitTexture(info.icon)
self.upx[ii].ico:SetStretchTexture(true)
self.upx[ii].base:Show(true)
end
end
self:RMode_EvaluateUpgrAll()
end
function UIInventory:RMode_InitItemIcon(obj)
self:Print(nil, "RMode_InitItemIcon | %s", obj and obj:name())
if (not obj) then
self.npc_up_item:Show(false)
return
end
local sec = obj:section()
local ratio = (utils_xml.is_widescreen() and 0.8 or 1)
local x = SYS_GetParam(2,sec,"upgr_icon_x")
local y = SYS_GetParam(2,sec,"upgr_icon_y")
local w = SYS_GetParam(2,sec,"upgr_icon_width")
local h = SYS_GetParam(2,sec,"upgr_icon_height")
if not (x and y and w and h) then
self.npc_up_item:Show(false)
return
end
-- Get upgrade dds
local path = SYS_GetParam(0,sec,"upgr_icon_path") or (IsWeapon(obj) and "ui\\ui_actor_weapons") or "ui\\ui_actor_armor"
self.npc_up_item:InitTexture(path)
self.npc_up_item:SetTextureRect(Frect():set(x, y, x + w, y + h))
self.npc_up_item:SetWndSize(vector2():set( w * ratio , h ))
self.npc_up_item:SetStretchTexture(true)
self.npc_up_item:Show(true)
end
function UIInventory:RMode_OnUpgrade(row, col, ii)
self:Print(nil, "RMode_OnUpgrade | row: %s - col: %s - ii: %s", row, col, ii)
local btn = self.upx[ii].btn
if (not btn) then
return
end
-- You cannot uninstall
if (not btn:GetCheck()) then
btn:SetCheck(true)
return
end
btn:SetCheck(false)
self.upgr_last_row = row
self.upgr_last_col = col
self.upgr_last_ii = ii
local str = game.translate_string("st_upgrade_install") .. " " .. game.translate_string(self.upgr_tree[row][col].name or "") .. "?"
self.message_box_up:InitMessageBox("message_box_yes_no")
self.message_box_up:SetText(str)
self.message_box_up:ShowDialog(true)
end
function UIInventory:RMode_UpgradeYes()
local row = self.upgr_last_row
local col = self.upgr_last_col
local ii = self.upgr_last_ii
self.upx[ii].btn:SetCheck(true)
self:Print(nil, "RMode_UpgradeYes | row: %s - col: %s - ii: %s", row, col, ii)
-- Install new upgrade
local obj = self.upgr.id and level.object_by_id(self.upgr.id)
if (not obj) then
return
end
-- For weapons, unload mag and clear ammo cache in case of ammo type upgrades
if IsWeapon(obj) and (not IsItem("fake_ammo_wpn",obj:section())) then
obj:force_unload_magazine(true)
item_weapon.clear_cache(obj)
end
-- Install upgrade
local upgr_section = self.upgr_tree[row][col].section
if (not upgr_section) then
return
end
obj:install_upgrade(upgr_section)
self.upgr_installed[upgr_section] = true
--[[ -- Effect on upgrading (not needed because it's called by install_upgrade)
local section_states = self.upgr_tree[row][col].stats
inventory_upgrades.effect_functor_a( nil, section_states, 0 )
--]]
inventory_upgrades.effect_upgrade_item(obj)
-- Evaluate all other upgrades
self:RMode_EvaluateUpgrAll()
self:On_Item_Update()
end
function UIInventory:RMode_EvaluateUpgr(row, col, ii, info)
self:Print(nil, "RMode_EvaluateUpgr | row: %s - col: %s - ii: %s", row, col, ii)
local btn = self.upx[ii].btn
-- We don't evalute installed upgrades
if btn:GetCheck() or self.upgr_installed[info.section] then
btn:SetCheck(true)
self.upx[ii].prereq = game.translate_string("st_upgr_installed")
return
end
-- Check if upgrade group is installed
if (not self.upgr_tree[row][col].solo) then
local col_g = odd(col) and col+1 or col-1
local section_g = self.upgr_tree[row][col_g].section
if self.upgr_installed[section_g] then
btn:Enable(false)
self.upx[ii].prereq = game.translate_string("st_upgr_disable")
return
end
end
-- Check price + mechanic info portion + parsed profile
local ret = inventory_upgrades.precondition_functor_a(nil, info.stats)
local prereq = parse_func(info.section, "prereq_functor", nil, info.stats) or ""
-- Check if parent upgrades is not installed
local prev_installed = col <= 2 and true or false
local section = self.upgr_tree[row][col].section
if (not prev_installed) then
for c, v in pairs(self.upgr_tree[row]) do
if v.effect and v.effect[section] and self.upgr_installed[v.section] then
prev_installed = true
end
end
end
if (not prev_installed) then
ret = 2
-- Edited by Sota - "\\n - "
prereq = prereq .. "\\n " .. game.translate_string("st_upgr_parents")
end
-- Finale
if prereq and prereq ~= "" then
prereq = game.translate_string("st_upgr_disable") .. " \\n" .. prereq
end
self.upx[ii].prereq = prereq
btn:Enable( (ret == 0) )
end
function UIInventory:RMode_EvaluateUpgrAll()
self:Print(nil, "RMode_EvaluateUpgrAll")
for row,v in pairs(self.upgr_tree) do
for col,info in pairs(v) do
local ii = row .. col .. (info.solo and "b" or "")
self:RMode_EvaluateUpgr(row, col, ii, info)
end
end
end
function UIInventory:RMode_OnRepair()
self:Print(nil, "RMode_OnRepair")
if (not self.upgr.id) then
return
end
local obj = level.object_by_id(self.upgr.id)
if (not obj) then
return
end
local sec = obj:section()
local cond = obj:condition()
local can_afford = inventory_upgrades.can_afford_repair_item(sec , cond)
local str = inventory_upgrades.question_repair_item( sec, cond, true )
if (str == nil) then
str = game.translate_string("st_upgr_cant_do")
end
if can_afford then
self.message_box:InitMessageBox("message_box_yes_no")
else
self.message_box:InitMessageBox("message_box_ok")
end
self.message_box:SetText(str)
self.message_box:ShowDialog(true)
end
function UIInventory:RMode_RepairYes()
self:Print(nil, "RMode_RepairYes")
if (not self.upgr.id) then
return
end
local obj = level.object_by_id(self.upgr.id)
if (not obj) then
return
end
inventory_upgrades.effect_repair_item( obj:section(), obj:condition())
obj:set_condition(0.99999)
self:On_Item_Update()
-- Repair button state goes off (cause full repaired)
self.npc_up_repair:Enable(false)
end
-- Callbacks - object
function UIInventory:actor_item_to_ruck(obj)
if self:IsShown() then
self:Print(nil, "Callback actor_item_to_ruck - %s", obj and obj:name())
self:On_Item_Update()
end
-- Unequip artefacts if player unequipped outfit
if IsOutfit(obj) and (not db.actor:item_in_slot(7)) then
db.actor:iterate_belt( function(owner, arty)
db.actor:move_to_ruck(arty)
end)
end
end
function UIInventory:actor_item_to_slot(obj)
if self:IsShown() then
self:Print(nil, "Callback actor_item_to_slot - %s", obj and obj:name())
self:On_Item_Update()
end
-- Unequip helmet/backpack if equipped outfit prevent them
if IsOutfit(obj) then
local c_outfit = obj:cast_CustomOutfit()
local helm = db.actor:item_in_slot(12)
if (not c_outfit.bIsHelmetAvaliable) and helm then
db.actor:move_to_ruck(helm)
end
local bkpk = db.actor:item_in_slot(13)
if (not c_outfit.bIsBackpackAvaliable) and bkpk then
db.actor:move_to_ruck(bkpk)
end
end
end
function UIInventory:actor_item_to_belt(obj)
if self:IsShown() then
self:Print(nil, "Callback actor_item_to_belt - %s", obj and obj:name())
self:On_Item_Update()
end
end
function UIInventory:actor_on_item_drop(obj)
if self:IsShown() then
self:Print(nil, "Callback actor_on_item_drop - %s", obj and obj:name())
self:On_Item_Update()
end
-- Unequip artefacts if player unequipped outfit
if IsOutfit(obj) and (not db.actor:item_in_slot(7)) then
db.actor:iterate_belt( function(owner, arty)
db.actor:move_to_ruck(arty)
end)
end
end
function UIInventory:actor_on_item_use(obj)
if self:IsShown() then
self:Print(nil, "Callback actor_on_item_use - %s", obj and obj:name())
self:On_Item_Update()
end
end
function UIInventory:actor_on_item_put_in_box(npc, obj)
if self:IsShown() and (self.npc_id == npc:id()) then
self:Print(nil, "Callback actor_on_item_put_in_box - %s", obj and obj:name())
self:On_Item_Update()
itms_manager.play_item_sound(obj, 0.75)
end
end
function UIInventory:actor_on_item_take_from_box(npc, obj)
if self:IsShown() and (self.npc_id == npc:id()) then
self:Print(nil, "Callback actor_on_item_take_from_box - %s", obj and obj:name())
self:On_Item_Update()
end
end
function UIInventory:npc_on_item_take(npc, obj)
if self:IsShown() and (self.npc_id == npc:id()) then
self:Print(nil, "Callback npc_on_item_take - %s", obj and obj:name())
-- Companions exchange mode: don't show non-assigned items
if (self.mode == "loot") and self.npc_is_companion and (not axr_companions.is_assigned_item(npc:id(), obj:id())) then
return
end
self:On_Item_Update()
itms_manager.play_item_sound(obj, 0.75)
end
end
function UIInventory:npc_on_item_drop(npc, obj)
if self:IsShown() and (self.npc_id == npc:id()) then
self:Print(nil, "Callback npc_on_item_drop - %s", obj and obj:name())
self:On_Item_Update()
end
end
function UIInventory:npc_on_use(obj, who)
if (who:id() == AC_ID) and (not self:IsShown()) and IsStalker(obj) and (not obj:alive()) then
start("loot", obj)
end
end
function UIInventory:physic_object_on_use_callback(obj, who)
-- sometimes who isn't passed!
if who and (who:id() == AC_ID) and (not self:IsShown()) and IsInvbox(obj) then
start("loot", obj)
end
end
function UIInventory:actor_on_net_destroy()
if self:IsShown() then
self:Close()
end
GUI = nil
end
-- Callbacks - UI
function UIInventory:On_CC_DragDrop(bag_from, idx_from)
local obj_from = self.CC[bag_from]:GetObj(idx_from)
if (not obj_from) then
return
end
if self.mode == "trade" then return end
-- When interacting with item picker, get parent cell bag and index
bag_from, idx_from = self:Picker_Ownership(bag_from, idx_from, obj_from)
self:Print(nil, "Callback On_CC_DragDrop | bag: %s - idx: %s", bag_from, idx_from)
-- Throw items outside
if self.trash:IsShown() and self.trash:IsCursorOverWindow() then
if self:Item_On_Mode("drop", bag_from) and self:Cond_NotQuest(obj_from, bag_from) then
self:Action_Drop(obj_from, bag_from)
return
end
-- Drag Drop item on other item
else
-- Get hovered container and cell
local bag_to, idx_to, obj_to
for name,cc in pairs(self.CC) do
bag_to, idx_to, obj_to = cc:GetCell_Focused()
if bag_to then
break
end
end
-- When interacting with item picker, get parent cell bag and index
if obj_to then
bag_to, idx_to = self:Picker_Ownership(bag_to, idx_to, obj_to)
end
self:Print(nil, "Callback On_CC_DragDrop | obj_f: %s - bag_f: %s - idx_f: %s | obj_t: %s - bag_t: %s - idx_t: %s", obj_from:name(), bag_from, idx_from, obj_to and obj_to:name(), bag_to, idx_to)
-- Ruck/Slot to Slot
if (bag_to == "actor_equ") and (self:Cond_Equip(obj_from, bag_from) or bag_from == "actor_equ") and (not IsArtefact(obj_from)) then
local slot = (SYS_GetParam(2,obj_from:section(),"slot") or -1) + 1
local cslots = self.slot_cell[slot] or {}
for i=1,#cslots do
if (cslots[i] == idx_to) then
self:Print(nil, "Callback On_CC_DragDrop | Ruck to Slot | obj_from: %s - obj_to: %s - base slot: %s - new slot: %s", obj_from:name(), obj_to and obj_to:name(), slot, idx_to)
if obj_to then
db.actor:move_to_ruck(obj_to)
end
db.actor:move_to_slot(obj_from, idx_to)
self:PlaySND(snd_item_to_slot)
break
end
end
-- Ruck to Belt
elseif (bag_to == "actor_belt" and bag_from == "actor_bag") and IsArtefact(obj_from) then
-- Edited by HarukaSai - replacing artefact in slot instead of doing nothing
if obj_to then
db.actor:move_to_ruck(obj_to)
CreateTimeEvent("haru_to_belt", "haru_to_belt", 0, function(self, obj_from, bag_from)
self:Action_Equip(obj_from, bag_from)
return true
end,
self, obj_from, bag_from)
elseif self:Cond_Equip(obj_from, bag_from) then
self:Action_Equip(obj_from, bag_from)
end
-- end of edit
-- To Quick access
elseif (bag_to == "actor_quick") and IsItem("consumable",obj_from:section()) then
quick_item = exec_console_cmd("slot_" .. (idx_to - 1) .. " " .. obj_from:section())
self.update_info = true
return
-- Case object to drop on
elseif obj_to then
-- Attachment
if ((bag_to == "actor_bag") or (bag_to == "actor_equ")) and self:Cond_Attach(obj_from, "actor_bag", nil, nil, obj_to) then
self:Action_Attach(obj_from, "actor_bag", nil, nil, obj_to)
-- Callback
else
SendScriptCallback("ActorMenu_on_item_drag_drop", obj_from, obj_to, self.bag_id[bag_from], self.bag_id[bag_to])
end
-- No object to drop on
else
if (not bag_to) then
for bag,cc in pairs(self.CC) do
if (bag ~= "picker") and cc:IsCursorOverWindow() then
bag_to = bag
break
end
end
end
-- Case bag to drop on
if bag_to then
-- Move to other suitable bag
if self:Item_On_Mode("move", bag_from) and self:Cond_Move(obj_from, bag_from, nil, bag_to) then
if self.holding_ctrl and self:Cond_Childs(obj_from, bag_from) then
self:Action_Move_All(obj_from, bag_from)
else
self:Action_Move(obj_from, bag_from)
end
-- Unequip
elseif self:Item_On_Mode("to_ruck", bag_from) and (bag_to == "actor_bag" or bag_to == "actor_trade_bag") then
self:Action_UnEquip(obj_from, bag_from)
end
end
end
self:On_Item_Update()
end
end
function UIInventory:On_CC_Hover(bag, idx)
-- self:Print(nil, "Callback On_CC_Hover | bag: %s - idx: %s", bag, idx)
local prev_idx = self.hover.idx
local prev_bag = self.hover.bag
self.hover.bag = bag
self.hover.idx = idx
self.hover.tg = time_global()
-- Unhighlight all on hover changes
if (bag ~= prev_bag) or (idx ~= prev_idx) then
self:UnHighlight_All()
end
-- Highlight hovered cell
if bag and idx then
local ci = self.CC[bag].cell[idx]
if ci and ci:IsShown() then
-- Edited by HarukaSai to display color based on settings
local use_main_clr = (bag == "actor_equ") or (bag == "actor_belt") or (bag == "actor_quick")
ci:Highlight(true, "def", use_main_clr)
if use_main_clr then
local color = color_settings.slot_colors and self.faction_color or (
(bag == "actor_belt") and slot_colors.belt or
(bag == "actor_quick") and slot_colors.quick or
slot_colors[idx]
)
ci.hl:SetTextureColor(color)
end
-- end of edit
end
end
-- On Item focus lost
if prev_idx and prev_bag and (prev_idx ~= idx) then
local obj = self.CC[prev_bag]:GetObj(prev_idx)
if obj then
SendScriptCallback("ActorMenu_on_item_focus_lost", obj)
end
end
-- On Item focus receive
if idx and bag and (prev_idx ~= idx) then
local obj = self.CC[bag]:GetObj(idx)
if obj then
SendScriptCallback("ActorMenu_on_item_focus_receive", obj)
end
end
-- Highlight slots for equippable items
if ((self.slot_hl.idx ~= idx) or (self.slot_hl.bag ~= bag)) then
local force = (self.slot_hl.bag ~= bag) -- force unhighlight when switching bags to avoid stucking highlighting
-- Less hooks
self.slot_hl.idx = idx
self.slot_hl.bag = bag
-- Obviously we don't want to highlight compatible slots when hovered item is in a slot
local can_highlight = (bag ~= "actor_equ") and (bag ~= "actor_belt") and (bag ~= "actor_quick")
-- Unhighlight all first
if force or can_highlight then
local cc1 = self.CC["actor_equ"]
for i=1,#cc1.cell do
cc1.cell[i]:Highlight(false)
end
local cc2 = self.CC["actor_belt"]
for i=1,#cc2.cell do
cc2.cell[i]:Highlight(false)
end
local cc3 = self.CC["actor_quick"]
for i=1,#cc3.cell do
cc3.cell[i]:Highlight(false)
end
end
-- Highlight compatible items
if can_highlight and bag and idx then
local obj = self.CC[bag]:GetObj(idx)
if obj then
-- For slots, we higlight when item is equippable
if self:Cond_Equip(obj, bag) then
local slot = (SYS_GetParam(2,obj:section(),"slot") or -1) + 1
local slot_cells = self.slot_cell[slot]
-- For belt, we higlight when item is an artefact
if IsArtefact(obj) then
local cc = self.CC["actor_belt"]
for i=1,#cc.cell do
-- Edited by HarukaSai - removal of highlights when there's blocker in that cell
if not (self.blocker_arty[i]:IsShown()) then
cc.cell[i]:Highlight(true, "def", true)
local color = color_settings.slot_colors and self.faction_color or slot_colors.belt
cc.cell[i].hl:SetTextureColor(color)
end
end
elseif slot_cells then
local cc = self.CC["actor_equ"]
for i=1,#slot_cells do
local ci = cc.cell[ slot_cells[i] ]
if ci then
ci:Highlight(true, "def", true)
-- Edited by HarukaSai to add slot recolors
local color = color_settings.slot_colors and self.faction_color or slot_colors[slot_cells[i]]
ci.hl:SetTextureColor(color)
end
end
end
-- For quick slots, we higlight when item is consumable
elseif IsItem("consumable", obj:section()) then
local cc = self.CC["actor_quick"]
for i=1,#cc.cell do
cc.cell[i]:Highlight(true, "def", true)
-- Edited by HarukaSai to add slot recolors
local color = color_settings.slot_colors and self.faction_color or slot_colors.quick
cc.cell[i].hl:SetTextureColor(color)
end
end
end
end
end
end
function UIInventory:On_CC_Mouse1(bag, idx)
-- Start or Hide picker
self:Picker_Toggle(bag, idx)
local obj = self.CC[bag]:GetObj(idx)
if (not obj) then
self:Print(nil, "Callback On_CC_Mouse1 | no object recieved!", bag, idx)
return
end
-- When interacting with item picker, get parent cell bag and index
bag, idx = self:Picker_Ownership(bag, idx, obj)
self:Print(nil, "Callback On_CC_Mouse1 | bag: %s - idx: %s", bag, idx)
-- Upgrade tree
if self:IsMode(bag,"repair","actor_bag","actor_equ") then
self:RMode_InitItem(obj, bag, idx)
end
end
function UIInventory:On_CC_Mouse1_DB(bag, idx)
-- Fix for quick-slot double clicking crash the game
if (bag == "actor_quick") then
--self.CC["actor_quick"]:AddItemManual(nil, nil, idx)
--exec_console_cmd("slot_"..(idx - 1).." (NULL)")
return
end
local obj = self.CC[bag]:GetObj(idx)
if (not obj) then
self:Print(nil, "Callback On_CC_Mouse1_DB | no object recieved!", bag, idx)
return
end
-- When interacting with item picker, get parent cell bag and index
bag, idx = self:Picker_Ownership(bag, idx, obj)
self:Print(nil, "Callback On_CC_Mouse1_DB | bag: %s - idx: %s", bag, idx)
-- Eat consumable
if self:Item_On_Mode("use", bag) and self:Cond_Use(obj, bag) then
self:Action_Use(obj, bag)
-- Equip item
elseif self:Item_On_Mode("to_slot", bag) and self:Cond_Equip(obj, bag) then
self:Action_Equip(obj, bag)
-- Unequip item
elseif self:Item_On_Mode("to_ruck", bag) then
self:Action_UnEquip(obj, bag)
-- Move items between bags
elseif self:Item_On_Mode("move", bag) and self:Cond_Move(obj, bag) then
if self.holding_ctrl and self:Cond_Childs(obj, bag) then
self:Action_Move_All(obj, bag)
else
self:Action_Move(obj, bag)
end
return true -- continue double clicking!
-- Execute first custom property that support double-click
else
local i = 1
local mode = self.mode
while (self.properties["custom_" .. i] ~= nil) do
-- Check if double-click is enabled
if self:DB_Custom(obj, bag, nil, i) then
local props = self.properties["custom_" .. i]
-- Check if prop is aimed for active container
local bag_allowed = true
if props.cont then
bag_allowed = props.cont[bag] and true or false
end
if props.cont_func and props.cont_func[1] and self[props.cont_func[1]] then
bag_allowed = self[props.cont_func[1]](self, obj, bag, unpack(props.cont_func)) and true or false
end
-- Check if prop is aimed for active mode
local mode_allowed = true
if props.mode then
mode_allowed = props.mode[mode] and true or false
end
if props.mode_func and props.mode_func[1] and self[props.mode_func[1]] then
mode_allowed = self[props.mode_func[1]](self, obj, bag, unpack(props.mode_func)) and true or false
end
if mode_allowed and bag_allowed then
-- Evaluate preconditions
local cond = true
local k = 1
while cond and props["precondition" .. k] do
local precond = props["precondition" .. k]
if precond[1] and self[precond[1]] then
cond = self[precond[1]](self, obj, bag, unpack(precond)) and true or false
else
cond = false
end
k = k + 1
end
if cond then
local id = obj:id()
-- Get prop name
local name = props.name
local func_name = props.name_func
if func_name and func_name[1] and self[func_name[1]] then
name = self[func_name[1]](self, id, bag, unpack(func_name)) or name
end
if name then
-- Execute action
local func_action = props.action
if func_action and func_action[1] and self[func_action[1]] then
self[func_action[1]](self, id, bag, unpack(func_action))
break
end
end
end
end
end
i = i + 1
end
end
end
function UIInventory:On_CC_Mouse2(bag, idx)
-- Start or Hide picker
self:Picker_Toggle(bag, idx)
local obj = self.CC[bag]:GetObj(idx)
if (not obj) then
self:Print(nil, "Callback On_CC_Mouse2 | no object recieved!", bag, idx)
return
end
-- When interacting with item picker, get parent cell bag and index
bag, idx = self:Picker_Ownership(bag, idx, obj)
self:Print(nil, "Callback On_CC_Mouse2 | bag: %s - idx: %s", bag, idx)
if (not self.CC[bag].showcase) then
self:InitProperties(obj, bag)
end
end
function UIInventory:On_CC_Add(bag, idx, on_area)
self:Print(nil, "Callback On_CC_Add | bag: %s - idx: %s - on_area", bag, idx, on_area)
-- Update info
self.update_info = true
end
function UIInventory:On_CC_Remove(bag, idx, on_area) -- after cell removal!
self:Print(nil, "Callback On_CC_Remove | bag: %s - idx: %s - on_area", bag, idx, on_area)
-- Update info
self.update_info = true
end
function UIInventory:On_CC_Trasfer(bag_from, bag_to, idx_from, idx_to, obj)
self:Print(nil, "Callback On_CC_Trasfer | bag_from: %s - bag_to: %s - idx_from: %s - idx_to: %s", bag_from, bag_to, idx_from, idx_to)
-- Special case for item picker
local cc = self.CC["picker"]
if cc:IsShown() and (cc.parent.bag == bag_from) then
cc:RemoveItem(obj)
end
-- Update info
self.update_info = true
end
-- Cell management
function UIInventory:On_Item_Exchange(npc_from, npc_to, obj)
npc_from:transfer_item(obj, npc_to)
self:On_Item_Update()
end
function UIInventory:On_Item_Update()
self:Print(nil, "On_Item_Update")
-- Update info
self.tg_inv = time_global() - 30
self.update_info = true
end
-- Technical
function UIInventory:PlaySND(snd, vol)
self:Print(nil, "PlaySND")
-- Anti sound spam
local tg = time_global()
if self.tg_play and (tg - self.tg_play < 500) then
return
end
self.tg_play = tg
snd:play(db.actor,0,sound_object.s2d)
snd.volume = vol or 1
end
function UIInventory:SetHint(text, pos)
if (not text) then
self.tg_hint = time_global()
self.hint_wnd:Show(false)
return
end
if (time_global() < self.tg_hint + self.tg_hint_step) then
return
end
self.hint_wnd:Show(true)
self.hint_wnd_text:SetText(text)
self.hint_wnd_text:AdjustHeightToText()
-- Edited by Sota
local w = self.hint_wnd:GetWidth()
--w = w >= 150 and w or 150
--local h = self.hint_wnd_text:GetHeight()+44
local h = self.hint_wnd_text:GetHeight() + self.hint_wnd_text:GetWndPos().y * 3
--h = h >= 265 and h or 265
self.hint_wnd:SetWndSize(vector2():set(w,h))
pos = pos or GetCursorPosition()
pos.y = pos.y - self.hint_wnd:GetHeight()
pos.x = pos.x - self.hint_wnd:GetWidth()
self.hint_wnd:SetWndPos(pos)
FitInRect(self.hint_wnd,Frect():set(0,0,1024,768),0,100)
end
function UIInventory:Update()
CUIScriptWnd.Update(self)
-- Update all info: weight/prices/slots/bags/stats
self:UpdateInfo()
-- Update stats cycle
if (time_global() > self.tg_stats) then
self.tg_stats = time_global() + self.tg_stats_step
self:UpdateStats()
end
-- Reinit loot mode (special case for boxes because they spawn items after opening inventory)
if self.box_init_update.state and (time_global() > self.box_init_update.tg) then
self:LMode_Init( self:GetPartner() )
end
-- More GUI are opened at once, distable inventory showcase elements
if Overlapped_UI() then
self:Picker_Toggle()
self.item_info:Update()
self.upgr_info:Update()
self:SetHint(false)
return
end
-- Update upgrades info box
local hide_upgr_info = true
if (self.mode == "repair") and self.upgr.id then
for ii,ele in pairs(self.upx) do
if ele.base:IsShown() and ele.btn:IsCursorOverWindow() then
self.upgr_info:Update(ele.section, ele.prereq, ele.btn:GetCheck())
hide_upgr_info = false
break
end
end
end
if hide_upgr_info then
self.upgr_info:Update()
end
-- Updating item info box and item cell containers
self.found_cell = false
local no_info = self.item_props:IsShown() or (self.item_in_hold and true or false)
for name,cc in pairs(self.CC) do
if cc:IsShown() then
-- We don't want to trigger info box for cells belong to bag below picker area
self.found_cell = cc:Update(self.item_info, no_info) or self.found_cell
end
end
-- Unhighlight all cells if no cell is focused on
if (self.found_cell) then
self:SetHint(false)
self:Picker_Update()
return
else
self.item_info:Update()
self:UnHighlight_All()
end
local show_hint = not self:Picker_Update()
-- Edited by Sota - show HTS bar tooltip when hovering over a bar
-- Hint
for name,v in pairs(self.stat) do
if show_hint and v and v.bar and v.bar:IsCursorOverWindow() then
local str = self.stat_list[name].hint
-- if str then
if str and (not self.hts_tooltips[name]) then
self:SetHint( game.translate_string(str) )
else
self.hts_tooltips[name].tooltip:TextControl():SetText( math.ceil( str() * 100 ) .. " %" )
self.hts_tooltips[name].tooltip:Show(true)
end
return
end
end
self:SetHint(false)
self:HideTooltips()
end
-- Added by Sota - hide HTS bars tooltips
function UIInventory:HideTooltips()
for name,_ in pairs(self.hts_tooltips) do
self.hts_tooltips[name].tooltip:Show(false)
end
end
function UIInventory:OnKeyboard(dik, keyboard_action)
local res = CUIScriptWnd.OnKeyboard(self,dik,keyboard_action)
if (res == false) then
for bag, cc in pairs(self.CC) do
if cc:IsShown() then
cc:OnKeyboard(dik, keyboard_action)
end
end
if keyboard_action == E_RELEASE then
-- This is needed to close the picker when player press mouse 1 elsewhere
if dik == K_M1 or dik == K_M2 then
if (not self:Picker_IsFocused()) and (self.tg_m1 + 25 < time_global()) then
self:Picker_Toggle(self.hover.bag, self.hover.idx)
end
-- Take/Put all (SHIFT + T/P)
elseif (self.mode == "loot") and self.holding_shift then
if (dik == DIK_keys.DIK_P) then
self:LMode_PutAll()
elseif (dik == DIK_keys.DIK_T) then
self:LMode_TakeAll()
end
-- Refresh
elseif dik == DIK_keys.DIK_F5 then
if self.mode == "inventory" then
self:IMode_Init()
elseif self.mode == "loot" then
self:LMode_Init(self:GetPartner())
elseif self.mode == "trade" then
self:TMode_Init(self:GetPartner())
elseif self.mode == "repair" then
self:RMode_Init(self:GetPartner())
end
------------------------------
elseif dik == K_CTRL then
self.holding_ctrl = false
elseif dik == K_SHFT then
self.holding_shift = false
end
------------------------------
elseif keyboard_action == E_PRESS then
local bind = dik_to_bind(dik)
------------------------------
if dik == K_CTRL then
self.holding_ctrl = true
elseif dik == K_SHFT then
self.holding_shift = true
------------------------------
-- Exit
elseif (bind == key_bindings.kINVENTORY) or (bind == key_bindings.kUSE) then
if keybind_pass() then
self:Close()
end
-- Exit
elseif dik == DIK_keys.DIK_ESCAPE then
self:Close()
-- PDA
elseif bind == key_bindings.kACTIVE_JOBS then
if (db.actor:item_in_slot(8)) then
self:Close()
if (get_console_cmd(1,"g_3d_pda")) then
db.actor:activate_slot(8)
else
ActorMenu.get_pda_menu():ShowDialog(true)
end
end
-- Sort tabs
else
for i=1,#self.sort_btn do
if (dik == DIK_keys["DIK_" .. i]) or (dik == DIK_keys["DIK_NUMPAD" .. i]) then
self:On_Sort(i,true)
self:On_Sort(i)
break
end
end
end
end
end
return res
end
function UIInventory:Close()
self:Print(nil, "Close")
-- Sound effect
self:PlaySND(snd_close)
self:HideDialog()
self:Show(false)
change_last_mode(0)
Unregister_UI("UIInventory")
end
function UIInventory:Print(mark,fmt,...)
--printf( (mark or "/") .. " UIInventory | " .. fmt, ...)
end
-------------------------------------------------------------------
-- Utilities
-------------------------------------------------------------------
function func_index(t,a,b)
return (t[a].index) < (t[b].index)
end
function overrides()
_G.hide_hud_inventory = ui_inventory.hide_actor_menu
actor_menu_inventory.CUIActorMenu_OnHideActorMenu = ui_inventory.hide_inventory
-- Get inventory menu
_G.GetActorMenu = function()
if (not GUI) then
GUI = UIInventory()
end
return GUI
end
ui_companion_inv.start = function(npc)
start("loot", npc)
end
end
function hide_actor_menu()
if GUI and GUI:IsShown() then
GUI:Close()
return true
end
local hud = get_hud()
if (hud) then
hud:HideActorMenu()
return true
end
return false
end
function hide_inventory()
if GUI and GUI:IsShown() then
GUI:Close()
end
end
function change_last_mode(mode)
actor_menu.actor_menu_mode(mode)
end
function is_enabled()
return enable_feature
end