505 lines
15 KiB
Plaintext
505 lines
15 KiB
Plaintext
|
|
||
|
--[[
|
||
|
|
||
|
Tronex
|
||
|
2020/4/9
|
||
|
|
||
|
Actor status / info - Handly for checking actor related info like current safe cover by other scripts
|
||
|
Custom HUD indicators
|
||
|
|
||
|
--]]
|
||
|
|
||
|
-- Update rate
|
||
|
local tg_update = 0
|
||
|
local tg_update_step = 1000 --[ms]
|
||
|
|
||
|
----------------------------------
|
||
|
-- Current Boosters and states
|
||
|
----------------------------------
|
||
|
local active_boosters = {}
|
||
|
local boost_name = {}
|
||
|
function prepare_boosters_effect()
|
||
|
boost_name = invert_table(BoosterID)
|
||
|
end
|
||
|
function scan_boosters_effect()
|
||
|
for name,t in pairs(active_boosters) do
|
||
|
t.value = nil
|
||
|
t.period = nil
|
||
|
end
|
||
|
db.actor:cast_Actor():conditions():BoosterForEach( scan_current_booster_effect )
|
||
|
end
|
||
|
function scan_current_booster_effect(typ, period, value)
|
||
|
active_boosters[ boost_name[typ] ] = { value=value , period=period }
|
||
|
end
|
||
|
|
||
|
function get_boost(name, time_only)
|
||
|
if time_only then
|
||
|
return active_boosters[name] and active_boosters[name].period
|
||
|
end
|
||
|
return active_boosters[name] and active_boosters[name].value
|
||
|
end
|
||
|
|
||
|
function get_satienty(visual)
|
||
|
local conditions = db.actor:cast_Actor():conditions()
|
||
|
local satienty = conditions:GetSatiety()
|
||
|
if (not visual) then
|
||
|
return satienty
|
||
|
end
|
||
|
|
||
|
local satiety_critical = conditions:SatietyCritical()
|
||
|
local satiety_koef = (satienty - satiety_critical) / (satienty >= satiety_critical and (1 - satiety_critical) or satiety_critical)
|
||
|
if (satiety_koef > 0.5) then
|
||
|
return 0
|
||
|
else
|
||
|
if (satiety_koef > 0.0) then
|
||
|
return 1
|
||
|
elseif (satiety_koef > -0.5) then
|
||
|
return 2
|
||
|
else
|
||
|
return 4
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function get_radiation(visual)
|
||
|
local radiation = db.actor.radiation
|
||
|
if (not visual) then
|
||
|
return radiation
|
||
|
end
|
||
|
|
||
|
-- for indicator
|
||
|
if radiation and radiation > 0 then
|
||
|
return math.ceil(radiation * 4)
|
||
|
end
|
||
|
return 0
|
||
|
end
|
||
|
|
||
|
function get_overweight(visual)
|
||
|
local actor = db.actor
|
||
|
local tot_weight = actor:get_total_weight()
|
||
|
local max_weight = actor:get_actor_max_walk_weight()
|
||
|
|
||
|
local outfit = actor:item_in_slot(7)
|
||
|
local backpack = actor:item_in_slot(13)
|
||
|
max_weight = max_weight + (outfit and outfit:get_additional_max_weight() or 0)
|
||
|
max_weight = max_weight + (backpack and backpack:get_additional_max_weight() or 0)
|
||
|
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)
|
||
|
--max_weight = max_weight + actor:cast_Actor():conditions().eBoostMaxWeight
|
||
|
|
||
|
if (not visual) then
|
||
|
return (tot_weight > max_weight), tot_weight, max_weight
|
||
|
end
|
||
|
|
||
|
-- for indicator
|
||
|
if (tot_weight > max_weight) then
|
||
|
return 4
|
||
|
elseif (tot_weight + 10 > max_weight) then
|
||
|
return 2
|
||
|
end
|
||
|
return 0
|
||
|
end
|
||
|
|
||
|
|
||
|
----------------------------------
|
||
|
-- Current safe cover
|
||
|
----------------------------------
|
||
|
local safe_covers = {}
|
||
|
local near_cover_dist
|
||
|
local last_cover, last_cover_2, near_cover
|
||
|
local last_cover_o, near_cover_o
|
||
|
|
||
|
function prepare_safe_zone()
|
||
|
local sur_ini = ini_file("misc\\surge_manager.ltx")
|
||
|
local safe_covers_list = utils_data.collect_section(sur_ini,"list",true)
|
||
|
|
||
|
-- Only collect safe covers in the same level
|
||
|
local sim = alife()
|
||
|
local is_on_the_actor_level = simulation_objects.is_on_the_actor_level
|
||
|
for i=1, 65534 do
|
||
|
local se_obj = sim:object(i)
|
||
|
if se_obj and safe_covers_list[se_obj:name()] and is_on_the_actor_level(se_obj) then
|
||
|
safe_covers[se_obj:name()] = se_obj.id
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
function scan_safe_zone()
|
||
|
--printf("Safe cover: %s", GetEvent("current_safe_cover"))
|
||
|
if GetEvent("underground") then
|
||
|
return true, false, 0
|
||
|
|
||
|
elseif last_cover and db.actor_inside_zones[last_cover] then
|
||
|
return db.actor_inside_zones[last_cover]:id(), false, 1
|
||
|
|
||
|
elseif last_cover_2 and db.zone_by_name[last_cover_2] and db.zone_by_name[last_cover_2]:inside(db.actor:position()) then
|
||
|
return safe_covers[last_cover_2], false, 2
|
||
|
|
||
|
elseif (size_table(db.actor_inside_zones) > 1) then
|
||
|
for name, obj in pairs(db.actor_inside_zones) do
|
||
|
last_cover = name
|
||
|
return obj:id(), false, 3
|
||
|
end
|
||
|
|
||
|
else
|
||
|
|
||
|
local pos = db.actor:position()
|
||
|
last_cover = nil
|
||
|
last_cover_2 = nil
|
||
|
near_cover = nil
|
||
|
near_cover_dist = nil
|
||
|
|
||
|
for name,id in pairs(safe_covers) do
|
||
|
local zone = db.zone_by_name[name]
|
||
|
if (zone) then
|
||
|
local dist = zone:position():distance_to_sqr(pos)
|
||
|
if (near_cover_dist == nil or dist < near_cover_dist) then
|
||
|
near_cover = name
|
||
|
near_cover_dist = dist
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if near_cover then
|
||
|
local zone = db.zone_by_name[near_cover]
|
||
|
if (zone) and zone:inside(pos) then
|
||
|
last_cover_2 = near_cover
|
||
|
return zone:id(), false, 4
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Tents are considered as save covers
|
||
|
if item_tent and item_tent.get_nearby_tent(1.5) then
|
||
|
return true, near_cover and safe_covers[near_cover] or false, 5
|
||
|
end
|
||
|
|
||
|
return false, near_cover and safe_covers[near_cover] or false, 6
|
||
|
end
|
||
|
end
|
||
|
function scan_safe_zone_old()
|
||
|
--printf("Safe cover: %s", GetEvent("current_safe_cover"))
|
||
|
if GetEvent("underground") then
|
||
|
return true, false, 0
|
||
|
|
||
|
elseif last_cover_o and db.zone_by_name[last_cover_o] and db.zone_by_name[last_cover_o]:inside(db.actor:position()) then
|
||
|
return safe_covers[last_cover_o], false, 2
|
||
|
|
||
|
else
|
||
|
|
||
|
local pos = db.actor:position()
|
||
|
last_cover_o = nil
|
||
|
near_cover_o = nil
|
||
|
near_cover_dist = nil
|
||
|
|
||
|
for name,id in pairs(safe_covers) do
|
||
|
local zone = db.zone_by_name[name]
|
||
|
if (zone) then
|
||
|
local dist = zone:position():distance_to_sqr(pos)
|
||
|
if (near_cover_dist == nil or dist < near_cover_dist) then
|
||
|
near_cover_o = name
|
||
|
near_cover_dist = dist
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
if near_cover_o then
|
||
|
local zone = db.zone_by_name[near_cover_o]
|
||
|
if (zone) and zone:inside(pos) then
|
||
|
last_cover_o = near_cover_o
|
||
|
return zone:id(), false, 4
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- Tents are considered as save covers
|
||
|
if item_tent and item_tent.get_nearby_tent(1.5) then
|
||
|
return true, near_cover_o and safe_covers[near_cover_o] or false, 5
|
||
|
end
|
||
|
|
||
|
return false, near_cover_o and safe_covers[near_cover_o] or false, 6
|
||
|
end
|
||
|
end
|
||
|
|
||
|
----------------------------------
|
||
|
-- HUD (Indicators)
|
||
|
----------------------------------
|
||
|
|
||
|
HUD = nil
|
||
|
indicators = {}
|
||
|
|
||
|
function prepare_indictors_list()
|
||
|
-- functor must return number [1-4] if it's a state (to indicate the color), boosters will always use one color
|
||
|
|
||
|
if is_not_empty(indicators) then return end
|
||
|
indicators["Radiation"] = { index= 1 ,typ= "state" ,functor= {"actor_status","get_radiation",true} ,icon= "ui_inGame2_booster_rad" ,background= "ui_inGame2_indicator_slot" ,anim_icon= true ,anim_bk= false }
|
||
|
indicators["Hunger"] = { index= 2 ,typ= "state" ,functor= {"actor_status","get_satienty",true} ,icon= "ui_inGame2_indicator_hunger" ,background= "ui_inGame2_indicator_slot" ,anim_icon= false ,anim_bk= false }
|
||
|
indicators["Overweight"] = { index= 5 ,typ= "state" ,functor= {"actor_status","get_overweight",true} ,icon= "ui_inGame2_indicator_overweight" ,background= "ui_inGame2_indicator_slot" ,anim_icon= false ,anim_bk= false }
|
||
|
|
||
|
indicators["HpRestore"] = { index= 6 ,typ= "booster" ,functor= {"actor_status","get_boost","HpRestore",true} ,icon= "ui_inGame2_booster_health" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
indicators["BleedingRestore"] = { index= 7 ,typ= "booster" ,functor= {"actor_status","get_boost","BleedingRestore",true} ,icon= "ui_inGame2_booster_bleed" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
indicators["RadiationRestore"] = { index= 8 ,typ= "booster" ,functor= {"actor_status","get_boost","RadiationRestore",true} ,icon= "ui_inGame2_booster_rad" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
indicators["MaxWeight"] = { index= 9 ,typ= "booster" ,functor= {"actor_status","get_boost","MaxWeight",true} ,icon= "ui_inGame2_booster_carry_weight" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
indicators["PowerRestore"] = { index= 10 ,typ= "booster" ,functor= {"actor_status","get_boost","PowerRestore",true} ,icon= "ui_inGame2_booster_power" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
indicators["RadiationProtection"] = { index= 11 ,typ= "booster" ,functor= {"actor_status","get_boost","RadiationProtection",true} ,icon= "ui_inGame2_booster_ext_rad" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
indicators["TelepaticProtection"] = { index= 12 ,typ= "booster" ,functor= {"actor_status","get_boost","TelepaticProtection",true} ,icon= "ui_inGame2_booster_psi" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
indicators["ChemicalBurnProtection"] = { index= 13 ,typ= "booster" ,functor= {"actor_status","get_boost","ChemicalBurnProtection",true} ,icon= "ui_inGame2_booster_chem" ,background= "ui_inGame2_booster_slot" ,anim_icon= false ,anim_bk= false ,anim_period= 5 }
|
||
|
end
|
||
|
|
||
|
function add_indicator(k,v)
|
||
|
prepare_indictors_list()
|
||
|
indicators[k] = v
|
||
|
end
|
||
|
|
||
|
function func_index(t,a,b)
|
||
|
return (t[a].index) < (t[b].index)
|
||
|
end
|
||
|
|
||
|
-------
|
||
|
function activate_hud()
|
||
|
RegisterScriptCallback("actor_on_net_destroy",actor_on_net_destroy)
|
||
|
RegisterScriptCallback("on_console_execute",on_console_execute)
|
||
|
RegisterScriptCallback("GUI_on_show",update_hud)
|
||
|
RegisterScriptCallback("GUI_on_hide",update_hud)
|
||
|
|
||
|
if HUD == nil then
|
||
|
HUD = UIIndicators()
|
||
|
get_hud():AddDialogToRender(HUD)
|
||
|
end
|
||
|
HUD:Update(true)
|
||
|
end
|
||
|
|
||
|
function deactivate_hud()
|
||
|
if HUD ~= nil then
|
||
|
get_hud():RemoveDialogToRender(HUD)
|
||
|
HUD = nil
|
||
|
end
|
||
|
|
||
|
UnregisterScriptCallback("actor_on_net_destroy",actor_on_net_destroy)
|
||
|
UnregisterScriptCallback("on_console_execute",on_console_execute)
|
||
|
UnregisterScriptCallback("GUI_on_show",update_hud)
|
||
|
UnregisterScriptCallback("GUI_on_hide",update_hud)
|
||
|
end
|
||
|
|
||
|
function update_hud()
|
||
|
if HUD ~= nil then
|
||
|
HUD:Update(true)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function actor_on_net_destroy()
|
||
|
if HUD ~= nil then
|
||
|
get_hud():RemoveDialogToRender(HUD)
|
||
|
HUD = nil
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function on_console_execute(name)
|
||
|
if name == "hud_draw" and HUD then
|
||
|
HUD:Update(true)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-------
|
||
|
class "UIIndicators" (CUIScriptWnd)
|
||
|
|
||
|
function UIIndicators:__init() super()
|
||
|
|
||
|
self.mirrored = false
|
||
|
self.slot = {}
|
||
|
self.clr_list = {
|
||
|
[0] = GetARGB(255,255,255,255), -- white
|
||
|
[1] = GetARGB(255,200,200,200), -- grey
|
||
|
[2] = GetARGB(255,255,255,50), -- yellow
|
||
|
[3] = GetARGB(255,255,125,50), -- orange
|
||
|
[4] = GetARGB(255,255,50,50), -- red
|
||
|
}
|
||
|
|
||
|
self.ratio = utils_xml.screen_ratio()
|
||
|
self._tmr = time_global()
|
||
|
self.index = 0
|
||
|
self.W = 40
|
||
|
self.offset = 10
|
||
|
|
||
|
prepare_indictors_list()
|
||
|
|
||
|
self:InitControls()
|
||
|
end
|
||
|
|
||
|
function UIIndicators:__finalize()
|
||
|
end
|
||
|
|
||
|
function UIIndicators:InitControls()
|
||
|
local xml = utils_xml.get_hud_xml()
|
||
|
local time_xml = CScriptXmlInit()
|
||
|
time_xml:ParseFile("actor_menu.xml")
|
||
|
|
||
|
self.dialog = xml:InitStatic("indicators", self)
|
||
|
--utils_xml.correct_ratio(self.dialog)
|
||
|
self.dialog:Show(false)
|
||
|
|
||
|
local t_size = size_table(indicators)
|
||
|
for i=1,t_size do
|
||
|
local x = (i-1)*(self.W + self.offset)
|
||
|
if self.mirrored then
|
||
|
x = (1-i)*(self.W + self.offset)
|
||
|
end
|
||
|
|
||
|
self.slot[i] = {}
|
||
|
self.slot[i].back_s = xml:InitStatic("indicators:static", self.dialog)
|
||
|
self.slot[i].back_f = xml:InitStatic("indicators:flashing", self.dialog)
|
||
|
self.slot[i].icon_s = xml:InitStatic("indicators:static", self.dialog)
|
||
|
self.slot[i].icon_f = xml:InitStatic("indicators:flashing", self.dialog)
|
||
|
|
||
|
-- xcvb boost time
|
||
|
self.slot[i].xcvb_time = time_xml:InitTextWnd("quick_slot3_text", self)
|
||
|
local dialog_pos = self.dialog:GetWndPos()
|
||
|
--------------------
|
||
|
|
||
|
for k, ele in pairs(self.slot[i]) do
|
||
|
ele:SetWndPos( vector2():set( x , 0 ) )
|
||
|
utils_xml.correct_ratio(ele)
|
||
|
end
|
||
|
|
||
|
-- xcvb boost time
|
||
|
local icon_pos = self.slot[i].icon_f:GetWndPos()
|
||
|
local text_x_pos = dialog_pos.x + icon_pos.x
|
||
|
local text_y_pos = dialog_pos.y + icon_pos.y - 15
|
||
|
self.slot[i].xcvb_time:SetWndPos(vector2():set( text_x_pos, text_y_pos ))
|
||
|
|
||
|
local icon_width = self.slot[i].icon_f:GetWidth()
|
||
|
local self_height = self.slot[i].xcvb_time:GetHeight()
|
||
|
self.slot[i].xcvb_time:SetWndSize(vector2():set(icon_width, self_height))
|
||
|
self.slot[i].xcvb_time:SetText("")
|
||
|
---------------------
|
||
|
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function UIIndicators:Clear()
|
||
|
for i=1,size_table(indicators) do
|
||
|
if self.slot[i] then
|
||
|
for k, ele in pairs(self.slot[i]) do
|
||
|
ele:Show(false)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
self.index = 0
|
||
|
end
|
||
|
|
||
|
function UIIndicators:Update(force)
|
||
|
CUIScriptWnd.Update(self)
|
||
|
|
||
|
local tg = time_global()
|
||
|
if force then
|
||
|
self._tmr = tg - 1
|
||
|
end
|
||
|
if self._tmr >= tg then
|
||
|
return
|
||
|
else
|
||
|
self._tmr = tg + 1000
|
||
|
end
|
||
|
|
||
|
-- Clear all
|
||
|
self:Clear()
|
||
|
|
||
|
-- Hide HUD when it's occupied by a GUI class
|
||
|
if not main_hud_shown() then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
-- Gather info
|
||
|
for name,t in spairs(indicators, func_index) do
|
||
|
local value = t.functor and execute_func(unpack(t.functor))
|
||
|
|
||
|
-- Determine if we should show the indicator on HUD according to type and value
|
||
|
local pass = false
|
||
|
if t.typ == "state" then
|
||
|
pass = value and value <= 4 and value >= 1
|
||
|
elseif t.typ == "booster" then
|
||
|
pass = value and true or false
|
||
|
end
|
||
|
|
||
|
if pass then
|
||
|
local i = self.index + 1
|
||
|
|
||
|
if t.icon then
|
||
|
local ico
|
||
|
if t.anim_period and (t.typ == "booster") and (value < t.anim_period) then
|
||
|
ico = self.slot[i].icon_f
|
||
|
else
|
||
|
ico = t.anim_icon and self.slot[i].icon_f or self.slot[i].icon_s
|
||
|
end
|
||
|
|
||
|
ico:InitTexture( t.icon )
|
||
|
ico:Show(true)
|
||
|
|
||
|
-- xcvb boost time
|
||
|
local show_time
|
||
|
db.actor:cast_Actor():conditions():BoosterForEach( function(boost_typ, boost_time, boost_val)
|
||
|
if name == boost_name[boost_typ] then
|
||
|
show_time = math.ceil(boost_time)
|
||
|
end
|
||
|
end)
|
||
|
|
||
|
if self.slot[i].xcvb_time then
|
||
|
self.slot[i].xcvb_time:Show(show_time and true or false)
|
||
|
self.slot[i].xcvb_time:SetText(show_time or "")
|
||
|
end
|
||
|
-----------------------
|
||
|
end
|
||
|
|
||
|
if t.background then
|
||
|
local bk
|
||
|
if t.anim_period and (t.typ == "booster") and (value < t.anim_period) then
|
||
|
bk = self.slot[i].back_f
|
||
|
else
|
||
|
bk = t.anim_bk and self.slot[i].back_f or self.slot[i].back_s
|
||
|
end
|
||
|
|
||
|
bk:InitTexture( t.background )
|
||
|
bk:SetTextureColor( t.typ == "state" and self.clr_list[value] or self.clr_list[0] )
|
||
|
bk:Show(true)
|
||
|
end
|
||
|
|
||
|
self.index = i
|
||
|
end
|
||
|
end
|
||
|
|
||
|
self.dialog:Show(self.index > 0)
|
||
|
end
|
||
|
|
||
|
|
||
|
----------------------------------
|
||
|
-- Callbacks
|
||
|
----------------------------------
|
||
|
|
||
|
local function actor_on_first_update()
|
||
|
prepare_boosters_effect()
|
||
|
prepare_safe_zone()
|
||
|
|
||
|
activate_hud()
|
||
|
end
|
||
|
|
||
|
local function actor_on_update()
|
||
|
|
||
|
local tg = time_global()
|
||
|
if tg < tg_update then
|
||
|
return
|
||
|
end
|
||
|
tg_update = tg + tg_update_step
|
||
|
|
||
|
--local cover_curr, cover_near, num = scan_safe_zone()
|
||
|
local cover_curr, cover_near, num = scan_safe_zone_old()
|
||
|
--actor_menu.set_msg(nil, strformat("cover_curr: %s | cover_near: %s | num: %s", cover_curr, cover_near, num))
|
||
|
--printf("cover_curr: %s | cover_near: %s | num: %s", cover_curr, cover_near, num)
|
||
|
SetEvent("current_safe_cover", cover_curr)
|
||
|
SetEvent("nearest_safe_cover", cover_near)
|
||
|
|
||
|
scan_boosters_effect()
|
||
|
end
|
||
|
|
||
|
function on_game_start()
|
||
|
RegisterScriptCallback("actor_on_first_update",actor_on_first_update)
|
||
|
RegisterScriptCallback("actor_on_update",actor_on_update)
|
||
|
end
|