Divergent/mods/Enhanced Graphical User Int.../gamedata/scripts/ui_inventory.script

3867 lines
114 KiB
Plaintext

--[[
- Tronex
- 2020/2/3 - 2020/4/3
- Inventory simulation
Modes:
1. Inventory
2. Loot
3. Trade
4. Repair/Upgrade
--]]
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),
}
-- 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)
--[[Bartoche70 for my addon Bart's New Sorting Tabs because "Keypad 0" toggle hud in inventory
--_GUIs_keyfree["UIInventory"] = true
--]]
_GUIs_keyfree["UIInventory"] = false
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")) },
["thirst"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_power_restore_speed")) },
["sleep"] = { min= 0 , max= (SYS_GetParam(2,"actor_condition","max_power_restore_speed")) },
}
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.player_dialog = xml:InitStatic("player", self)
self.player_background = xml:InitStatic("player:background", self.player_dialog)
self.player_community_overlay = xml:InitStatic("player:community_overlay", self.player_dialog)
self.player_name = xml:InitTextWnd("player:name", self.player_dialog)
self.player_community = xml:InitTextWnd("player:community", self.player_dialog)
self.player_rank = xml:InitTextWnd("player:rank", self.player_dialog)
self.player_rank_icon = xml:InitStatic("player:rank_icon", self.player_dialog)
self.player_icon = xml:InitStatic("player:icon", self.player_dialog)
self.player_money = xml:InitTextWnd("player:money", 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"
-- Community Player
self.player_community_icon = xml:InitStatic("player:community_icon", self.player_dialog)
-- Left side -- NPC
self.npc_dialog = xml:InitStatic("npc", self)
self.npc_background = xml:InitStatic("npc:background", self.npc_dialog)
self.npc_community_overlay = xml:InitStatic("player:community_overlay", self.npc_dialog)
self.npc_name = xml:InitTextWnd("npc:name", self.npc_dialog)
self.npc_community = xml:InitTextWnd("npc:community", self.npc_dialog)
self.npc_rank = xml:InitTextWnd("npc:rank", self.npc_dialog)
self.npc_rank_icon = xml:InitStatic("npc:rank_icon", self.npc_dialog)
self.npc_icon = xml:InitStatic("npc:icon", self.npc_dialog)
self.npc_money = xml:InitTextWnd("npc:money", 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_name = xml:InitTextWnd("upgrade:name", self.npc_up_dialog)
self.npc_up_community = xml:InitTextWnd("npc:community", self.npc_up_dialog)
self.npc_up_community_overlay = xml:InitStatic("player:community_overlay", self.npc_up_dialog)
self.npc_up_rank = xml:InitTextWnd("npc:rank", self.npc_up_dialog)
self.npc_up_rank_icon = xml:InitStatic("npc:rank_icon", self.npc_up_dialog)
self.npc_up_icon = xml:InitStatic("upgrade:icon", self.npc_up_dialog)
self.npc_up_money = xml:InitTextWnd("upgrade:money", 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")
-- Community NPC
self.npc_community_icon = xml:InitStatic("npc:community_icon", self.npc_dialog)
self.npc_up_community_icon = xml:InitStatic("upgrade:community_icon", self.npc_up_dialog)
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
-- Stats
self.stats_dialog = xml: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:InitStatic("equipment:actor_state_info:" .. name .. "_sensor", self.stats_dialog)
self.stat[name].bar = xml:InitProgressBar("equipment:actor_state_info:" .. name .. "_sensor:state_progress", self.stat[name].base)
self.stat[name].ico_base = xml:InitStatic("equipment:actor_state_info:icon", self.stat[name].base)
self.stat[name].ico_p = xml: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: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
-- Sorter
self.sort_dialog = xml:InitStatic("equipment:sorter", self.equ_dialog)
self.sort_btn = {}
self.sort_num = {}
--[[Bartoche70 for my addon Bart's New Sorting Tabs 30/10/2020
-------------------------------------------------------
--for i=1,8 do --> because tabs are now 10
--]]
for i=1,10 do
self.sort_btn[i] = xml: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)
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
self.CC["picker"].scroll:SetWndPos(vector2():set( 10 , 0 ))
-- self.CC["picker"].scroll:SetWndSize(vector2():set( self.CC["picker"].scroll:GetWidth() - 7.5 , self.CC["picker"].scroll:GetHeight() ))
-- 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)
printdbg("# UIInventory:Reset")
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"))
-- 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:ShowFaction("na", "npc")
self:ShowRank(0, "npc")
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.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_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_community_icon:InitTexture("ui_mm_faction_na")
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
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
function UIInventory:ShowFaction(v, view)
local arr = {'stalker', 'bandit', 'csky', 'dolg', 'freedom', 'killer', 'army','ecolog','monolith','greh','renegade','isg'}
local texture = v:gsub("actor_", "")
if not self:ArrayHasValue(arr, texture) then texture = "neutral" end
texture = "ui_inGame2_" .. texture
--printdbg("# UIInventory:ShowFaction | %s", texture)
if(view == "player") then
self.player_community_overlay:InitTexture(texture)
elseif (view == "npc") then
self.npc_community_overlay:InitTexture(texture)
self.npc_up_community_overlay:InitTexture(texture)
else
self.npc_community_overlay:InitTexture("ui_inGame2_na")
self.npc_up_community_overlay:InitTexture("ui_inGame2_na")
end
end
function UIInventory:ArrayHasValue (tab, val)
for index, value in ipairs(tab) do
if value == val then
return true
end
end
return false
end
-- Original ranks and rewards:
-- novice: 0, 5
-- trainee: 2000, 6
-- experienced: 4000, 7
-- professional: 7000, 8
-- veteran: 10000, 9
-- expert: 15000, 10
-- master: 21000, 15
-- legend: 28000, 20
-- Improved ranks and rewards:
-- novice: 0, 50
-- trainee: 4000, 100
-- experienced: 6000, 200
-- professional: 10000, 350
-- veteran: 16000, 550
-- expert: 24000, 800
-- master: 35000, 1100
-- legend: 50000, 1500
function UIInventory:ShowRank(v, view)
local texture = "ui_rank_0"
--printdbg("# UIInventory:ShowRank | Rank Number %s", v)
if v < 4000 then texture = "ui_rank_0" -- novice
elseif v < 6000 then texture = "ui_rank_1" -- trainee
elseif v < 10000 then texture = "ui_rank_2" -- experienced
elseif v < 16000 then texture = "ui_rank_3" -- professional
elseif v < 24000 then texture = "ui_rank_4" -- veteran
elseif v < 35000 then texture = "ui_rank_5" -- expert
elseif v < 50000 then texture = "ui_rank_6" -- master
elseif v >= 50000 then texture = "ui_rank_7" -- legend
end
--printdbg("# UIInventory:ShowRank | Rank Texture %s", texture)
if(view == "player") then
self.player_rank_icon:InitTexture(texture)
elseif (view == "npc") then
self.npc_rank_icon:InitTexture(texture)
self.npc_up_rank_icon:InitTexture(texture)
else
self.npc_rank_icon:InitTexture("ui_rank_0")
self.npc_up_rank_icon:InitTexture("ui_rank_0")
end
end
function UIInventory:UpdateCharacter()
local actor = db.actor
self:ShowFaction(actor:character_community(), "player")
self.player_name:SetText( alife():actor():character_name() )
self.player_community:SetText( game.translate_string(actor:character_community()) )
self.player_icon:InitTexture( actor:character_icon() )
self.player_money:SetText( actor:money() )
self:ShowRank(actor:character_rank(), "player")
-- self.player_rank:SetText(actor:character_rank())
-- NPC
local npc = self:GetPartner()
if npc and (not self.npc_is_box) then
-- in case of rich NPCs
local npc_money = npc:money()
npc_money = npc_money > 999999 and "..." or npc_money
if (self.mode == "repair") then
self:ShowFaction(npc:character_community(), "npc")
self.npc_up_name:SetText( npc:character_name() )
self.npc_up_community:SetText( game.translate_string(npc:character_community()) )
self.npc_up_icon:InitTexture( npc:character_icon() )
self.npc_up_money:SetText( npc_money )
self:ShowRank(npc:character_rank(), "npc")
else
self:ShowFaction(npc:character_community(), "npc")
self.npc_name:SetText( npc:character_name() )
self.npc_community:SetText( game.translate_string(npc:character_community()) )
self.npc_icon:InitTexture( npc:character_icon() )
self.npc_money:SetText( npc_money )
-- self.npc_rank:SetText(npc:character_rank())
self:ShowRank(npc:character_rank(), "npc")
end
end
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) )
-- 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) )
-- Satiety Bar
local satiety = actor:cast_Actor():conditions():GetSatiety()
satiety = (satiety - 0.1) / 5 -- 5.7
self.stat["power"].bar:SetProgressPos( clamp( satiety , 0, 0.2) )
-- Thirst Bar
local thirst = actor_status_thirst.get_last_drink()
local thirst_red_icon = actor_status_thirst.get_thirst_blur_4()
thirst = thirst_red_icon - thirst
thirst = (thirst / thirst_red_icon) / 5.65
self.stat["thirst"].bar:SetProgressPos( clamp( thirst, 0, 0.185))
-- Sleep bar
local sleep = actor_status_sleep.get_last_sleep()
local sleep_red_icon = actor_status_sleep.get_sleep_blur_4()
sleep = sleep_red_icon - sleep
sleep = (sleep / sleep_red_icon) / 5.65
self.stat["sleep"].bar:SetProgressPos( clamp( sleep, 0, 0.185))
-- 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
-- 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
--]]
-- 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)
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
-- 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
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
-- 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 self:Cond_Equip(obj_from, bag_from) and IsArtefact(obj_from) then
self:Action_Equip(obj_from, bag_from)
-- 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
ci:Highlight(true, "def", (bag == "actor_equ") or (bag == "actor_belt") or (bag == "actor_quick"))
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
cc.cell[i]:Highlight(true, "def", true)
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)
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)
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
-- 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()
local w = self.hint_wnd:GetWidth()
w = w >= 150 and w or 150
local h = self.hint_wnd_text:GetHeight()+44
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()
-- 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
self:SetHint( game.translate_string(str) )
end
return
end
end
self:SetHint(false)
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()
-- Sort tabs
else
for i=1,#self.sort_btn do
if (dik == DIK_keys["DIK_" .. i]) or (dik == DIK_keys["DIK_NUMPAD" .. i]) or i==10 and ((dik == DIK_keys["DIK_0" ]) or (dik == DIK_keys["DIK_NUMPAD0"])) then
--[[Bartoche70 for my addon Bart's New Sorting Tabs --> To add a quick access for the tenth tab, 0 or keypad 0
--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