Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- Tronex
- 2020/3/10
- Artefact binder
- Inventory radiation:
- Non-contained radioactive artefacts in ruck will irrediate the actor by half of their rad speed value
- This is a Misery feature, reworked and moved to this script
- Belt HUD:
- Show icons of belt artefacts on main HUD
- This is a CoC feature, reworked and moved to this script
- Port of lattest CoC version, fixed by xQd and Alundaio
- --]]
- local rad_factor = 0.5 -- multiplier to artefact rad effect in ruck
- local rad_tg_step = 300 --[ms]
- local dgr_tg_step = 2000 --[ms]
- local belted_arts = {}
- local imm_mul, mul, _tmr
- artefact_degradation_feature = false
- backpack_degradation_feature = false
- art_weight_add = 0
- local in_actor_ruck = utils_item.in_actor_ruck
- function utils_item.is_degradable(obj, sec)
- local section = obj and obj:section() or sec
- return section and ((ini_sys:r_bool_ex(section,"use_condition") and (not IsItem("multiuse",section))) or (ini_sys:r_string_ex(section,"kind") == "i_arty" )or (ini_sys:r_string_ex(section,"kind") == "i_arty_cont" ))
- end
- local function main_loop()
- local tg = time_global()
- if (_tmr and tg < _tmr) then
- return false
- end
- _tmr = tg + 2000 -- if you change this value timed artefact multipliers will need changes
- if not (db.actor) then
- return false
- end
- 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)
- art_weight_add = 0
- local cond_loss, val = 0, 0
- for art_id,active in pairs(belted_arts) do
- if (active) then
- local arte = level.object_by_id(art_id)
- if not (arte and db.actor:is_on_belt(arte)) then
- belted_arts[art_id] = nil
- else
- cond_loss = 0
- if (db.actor.health < 1.0) then
- val = ini_sys:r_float_ex(arte:section(),"health_restore_speed") or 0
- if (val > 0) then
- cond_loss = cond_loss + (val * mul["health"])
- end
- end
- if (db.actor.radiation > 0) then
- val = ini_sys:r_float_ex(arte:section(),"radiation_restore_speed") or 0
- if (val < 0) then
- cond_loss = cond_loss + (math.abs(val) * mul["radiation"])
- end
- end
- if (db.actor.satiety < 1.0) then
- val = ini_sys:r_float_ex(arte:section(),"satiety_restore_speed") or 0
- if (val > 0) then
- cond_loss = cond_loss + (val * mul["satiety"])
- end
- end
- if (db.actor.power < 1.0) then
- val = ini_sys:r_float_ex(arte:section(),"power_restore_speed") or 0
- if (val > 0) then
- cond_loss = cond_loss + (val * mul["power"])
- end
- end
- if (db.actor.bleeding > 0) then
- val = ini_sys:r_float_ex(arte:section(),"bleeding_restore_speed") or 0
- if (val > 0) then
- cond_loss = cond_loss + (val * mul["bleeding"])
- end
- end
- if (db.actor.psy_health < 1.0) then
- val = ini_sys:r_float_ex(arte:section(),"psy_health_restore_speed") or 0
- if (val > 0) then
- cond_loss = cond_loss + (val * mul["psy_health"])
- end
- end
- val = ini_sys:r_float_ex(arte:section(),"additional_inventory_weight") or 0
- art_weight_add = art_weight_add + val
- if (val > 0) then
- -- Which part of current carrying capacity comes from this belt item.
- -- Other items play their part as well. Multiple items will degrade
- -- slower than one item would, since they all share the load.
- local effect = val / max_weight
- -- Just how loaded the actor is.
- local actor_load = db.actor:get_total_weight() / max_weight
- -- This way items will not degrade when the actor is completely overloaded,
- -- otherwise the player will be trying to reduce carryweight in a race against degrading carrying capacity.
- -- Just imagine that all items automatically shut down when the actor is loaded over capacity.
- if actor_load <= 1 then
- cond_loss = cond_loss + (actor_load * effect * mul["weight"])
- end
- end
- if (cond_loss > 0) then
- --printf("%s Degradation: cond_loss=%s",arte:name(),cond_loss)
- local degrade_rate = (cond_loss*ini_sys:r_float_ex(arte:section(),"degrade_rate",1))
- if (arte:condition() - degrade_rate >= 0.01) then
- arte:set_condition(arte:condition() - degrade_rate)
- else
- arte:set_condition(0.01)
- end
- end
- end
- end
- end
- return false
- end
- function activate_feature()
- _g.printf("-Artefact/Backpack degradation started")
- imm_mul = imm_mul or { -- correction factors for hit events
- ["light_burn_immunity"] = 1.2,
- ["burn_immunity"] = 1.2,
- ["strike_immunity"] = 1.2,
- ["shock_immunity"] = 1.2,
- ["wound_immunity"] = 1.2,
- ["radiation_immunity"] = 1.2,
- ["telepatic_immunity"] = 1.2,
- ["chemical_burn_immunity"] = 1.2,
- ["explosion_immunity"] = 1.2,
- ["fire_wound_immunity"] = 1.2,
- }
- mul = mul or { -- correction factors for timed checks
- ["health"] = 0.4, -- updated often while slotted so don't set too high
- ["radiation"] = 0.4,
- ["satiety"] = 0.4,
- ["power"] = 0.4, -- updated often while slotted so don't set too high
- ["bleeding"] = 0.4,
- ["psy_health"] = 0.4,
- ["weight"] = 0.0002, -- updated often while slotted so don't set too high
- }
- RegisterScriptCallback("actor_on_item_drop",actor_on_item_drop)
- RegisterScriptCallback("actor_on_before_hit",actor_on_before_hit)
- RegisterScriptCallback("actor_item_to_belt",actor_item_to_belt)
- AddUniqueCall(main_loop)
- end
- function deactivate_feature()
- _g.printf("-Artefact/Backpack degradation stopped")
- RemoveUniqueCall(main_loop)
- UnregisterScriptCallback("actor_on_item_drop",actor_on_item_drop)
- UnregisterScriptCallback("actor_on_before_hit",actor_on_before_hit)
- UnregisterScriptCallback("actor_item_to_belt",actor_item_to_belt)
- end
- function toggle_feature_arty_degradation()
- end
- function set_feature_arty_degradation()
- if (artefact_degradation_feature) then
- activate_feature()
- else
- deactivate_feature()
- end
- end
- --------------------------------------------------------------------------
- -- Belt HUD
- --------------------------------------------------------------------------
- HUD = nil
- function activate_hud()
- RegisterScriptCallback("actor_item_to_belt",actor_on_item_change)
- RegisterScriptCallback("actor_item_to_ruck",actor_on_item_change)
- RegisterScriptCallback("actor_on_item_drop",actor_on_item_change)
- RegisterScriptCallback("on_console_execute",on_console_execute)
- RegisterScriptCallback("actor_on_net_destroy",actor_on_net_destroy)
- RegisterScriptCallback("GUI_on_show",update_hud)
- RegisterScriptCallback("GUI_on_hide",update_hud)
- if HUD == nil then
- HUD = UIBelt()
- get_hud():AddDialogToRender(HUD)
- end
- HUD:Refresh()
- end
- function deactivate_hud()
- if HUD ~= nil then
- get_hud():RemoveDialogToRender(HUD)
- HUD = nil
- end
- UnregisterScriptCallback("actor_item_to_belt",actor_on_item_change)
- UnregisterScriptCallback("actor_item_to_ruck", actor_on_item_change)
- UnregisterScriptCallback("actor_on_item_drop",actor_on_item_change)
- UnregisterScriptCallback("on_console_execute",on_console_execute)
- UnregisterScriptCallback("actor_on_net_destroy",actor_on_net_destroy)
- UnregisterScriptCallback("GUI_on_show",update_hud)
- UnregisterScriptCallback("GUI_on_hide",update_hud)
- end
- function update_hud()
- if HUD ~= nil then
- HUD:Refresh()
- end
- end
- function actor_on_net_destroy()
- if HUD ~= nil then
- get_hud():RemoveDialogToRender(HUD)
- HUD = nil
- end
- end
- function actor_on_item_change(item)
- if HUD and IsArtefact(item) then
- HUD:Refresh()
- end
- end
- function on_option_change()
- local state = ui_options.get("video/hud/show_slots")
- if state and (not HUD) then
- activate_hud()
- elseif (not state) and HUD then
- deactivate_hud()
- end
- end
- function on_console_execute(name)
- if name == "hud_draw" and HUD then
- HUD:Refresh()
- end
- end
- function on_game_start()
- RegisterScriptCallback("on_option_change",on_option_change)
- if (ui_options.get("video/hud/show_slots") == false) then
- return
- end
- local function actor_on_first_update()
- set_feature_arty_degradation()
- activate_hud()
- RegisterScriptCallback("on_console_execute",on_console_execute)
- end
- RegisterScriptCallback("actor_on_first_update",actor_on_first_update)
- end
- ----------------------------------------------------
- class "UIBelt" (CUIScriptWnd)
- function UIBelt:__init() super()
- self.slot = {}
- self.mirrored = true
- self.W = 25
- self.offset = 10
- self._tmr = time_global()
- self:InitControls()
- end
- function UIBelt:__finalize()
- end
- function UIBelt:InitControls()
- local xml = utils_xml.get_hud_xml()
- self.dialog = xml:InitStatic("belt", self)
- --utils_xml.correct_ratio(self.dialog)
- self.dialog:Show(false)
- for i=1, 5 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].ico = xml:InitStatic("belt:slot", self.dialog)
- self.slot[i].layer = xml:InitStatic("belt:slot", self.dialog)
- for k, ele in pairs(self.slot[i]) do
- ele:SetWndPos( vector2():set( x , 0 ) )
- utils_xml.correct_ratio(ele)
- end
- end
- end
- function UIBelt:Clear()
- for i=1,5 do
- self.slot[i].ico:Show(false)
- self.slot[i].layer:Show(false)
- end
- end
- function UIBelt:Refresh()
- local cnt = 0
- self:Clear()
- if not main_hud_shown() then
- return
- end
- db.actor:iterate_belt( function(owner, obj)
- local sec = obj:section()
- cnt = cnt + 1
- self.slot[cnt].ico:InitTexture( utils_xml.get_icons_texture(sec) )
- self.slot[cnt].ico:SetTextureRect(Frect():set( utils_xml.get_item_axis(sec, nil, true) ))
- self.slot[cnt].ico:Show(true)
- -- Set up indicator icon if found
- local ico_layer = ini_sys:r_string_ex(sec,"1icon_layer")
- if ico_layer then
- local ico_layer_x = ini_sys:r_float_ex(sec,"1icon_layer_x")
- local ico_layer_y = ini_sys:r_float_ex(sec,"1icon_layer_y")
- local ico_layer_scale = ini_sys:r_float_ex(sec,"1icon_layer_scale")
- local pos = self.slot[cnt].ico:GetWndPos()
- local w = self.slot[cnt].ico:GetWidth()
- local h = self.slot[cnt].ico:GetHeight()
- local ratio = w/50
- --print_dbg("UIBelt: icon [%s](%s) | x = %s / y = %s / w = %s / h = %s", sec, cnt, pos.x , pos.y , w , h )
- local x_i = pos.x + math.ceil(ico_layer_x * ico_layer_scale * ratio)
- local y_i = pos.y + math.ceil(ico_layer_y * ico_layer_scale * ratio)
- local w_i = math.ceil(w * ico_layer_scale)
- local h_i = math.ceil(h * ico_layer_scale)
- self.slot[cnt].layer:InitTexture( utils_xml.get_icons_texture(ico_layer) )
- self.slot[cnt].layer:SetWndPos(vector2():set( x_i , y_i ))
- self.slot[cnt].layer:SetWndSize(vector2():set( w_i , h_i ))
- --print_dbg("UIBelt: indicator [%s](%s) | scale: %s / x = %s / y = %s / w = %s / h = %s", sec, cnt, ico_layer_scale, x_i , y_i , w_i , h_i )
- self.slot[cnt].layer:SetTextureRect(Frect():set( utils_xml.get_item_axis(ico_layer, nil, true) ))
- self.slot[cnt].layer:Show(true)
- end
- end)
- self.dialog:Show(cnt > 0)
- end
- function UIBelt:Update()
- local tg = time_global()
- if self._tmr >= tg then
- return
- else
- self._tmr = tg + 10000
- end
- self:Refresh()
- CUIScriptWnd.Update(self)
- end
- --------------------------------------------------------------------------
- -- Callbacks
- --------------------------------------------------------------------------
- function actor_on_item_drop(art)
- if not IsArtefact(art) then
- return
- end
- local art_id = art:id()
- for k,v in pairs(belted_arts) do
- if k == art_id then
- belted_arts[k] = nil
- return
- end
- end
- end
- function actor_item_to_belt(item)
- if IsArtefact(item) then
- belted_arts[item:id()] = true
- end
- end
- --//----------- On hit immunities checks
- local hit_to_section = {
- [hit.light_burn] = "light_burn_immunity",
- [hit.burn] = "burn_immunity",
- [hit.strike] = "strike_immunity",
- [hit.shock] = "shock_immunity",
- [hit.wound] = "wound_immunity",
- [hit.radiation] = "radiation_immunity",
- [hit.telepatic] = "telepatic_immunity",
- [hit.chemical_burn] = "chemical_burn_immunity",
- [hit.explosion] = "explosion_immunity",
- [hit.fire_wound] = "fire_wound_immunity",
- }
- local equipement_damaging = {
- ["light_burn_immunity"] = true,
- ["burn_immunity"] = true,
- ["strike_immunity"] = true,
- ["wound_immunity"] = true,
- ["chemical_burn_immunity"] = true,
- ["explosion_immunity"] = true,
- ["fire_wound_immunity"] = true,
- }
- function actor_on_before_hit(s_hit)
- if (s_hit.power <= 0) then
- return
- end
- local cond_loss = 0
- local hit_absorbation_sect, imm_sect
- if (artefact_degradation_feature) then
- for art_id,active in pairs(belted_arts) do
- if (active) then
- local arte = level.object_by_id(art_id)
- if not (arte and db.actor:is_on_belt(arte)) then
- belted_arts[art_id] = nil
- else
- cond_loss = 0
- hit_absorbation_sect = ini_sys:r_string_ex(arte:section(),"hit_absorbation_sect")
- if (hit_absorbation_sect) then
- imm_sect = hit_to_section[s_hit.type]
- cond_loss = imm_sect and ini_sys:r_float_ex(hit_absorbation_sect,imm_sect) or 0
- if (cond_loss > 0) then
- cond_loss = (s_hit.power * imm_mul[imm_sect] * cond_loss)
- printf("%s Degradation: hit_power=%s cond_loss=%s",arte:name(),s_hit.power,cond_loss)
- local temp_cond = arte:condition() - (cond_loss*ini_sys:r_float_ex(arte:section(),"degrade_rate",1))
- temp_cond = temp_cond > 0.01 and temp_cond or 0.01
- arte:set_condition(temp_cond)
- end
- end
- end
- end
- end
- end
- local backpack = db.actor:item_in_slot(13)
- if (backpack) and (backpack_degradation_feature) then
- cond_loss = 0
- hit_absorbation_sect = ini_sys:r_string_ex("stalker_outfit","immunities_sect")
- if (hit_absorbation_sect) and (equipement_damaging[hit_to_section[s_hit.type]]) then
- imm_sect = hit_to_section[s_hit.type]
- cond_loss = imm_sect and ini_sys:r_float_ex(hit_absorbation_sect,imm_sect)*0.5 or 0
- cond_loss = cond_loss * s_hit.power
- if (cond_loss > 0) then
- --printf("%s Degradation: hit_power=%s cond_loss=%s",backpack:name(),s_hit.power,cond_loss)
- local temp_cond = backpack:condition() - (cond_loss*ini_sys:r_float_ex(backpack:section(),"degrade_rate",1))
- temp_cond = temp_cond > 0.01 and temp_cond or 0.01
- backpack:set_condition(temp_cond)
- end
- end
- end
- end
- --------------------------------------------------------------------------------
- -- Class "artefact_binder"
- --------------------------------------------------------------------------------
- function printf()
- end
- function bind(obj)
- obj:bind_object(artefact_binder(obj))
- end
- class "artefact_binder" (object_binder)
- function artefact_binder:__init(obj) super(obj)
- db.storage[self.object:id()] = { }
- end
- function artefact_binder:net_spawn(se_abstract)
- if not object_binder.net_spawn(self, se_abstract) then
- return false
- end
- db.add_obj(self.object)
- local artefact = self.object:get_artefact()
- local id = self.object:id()
- if bind_anomaly_zone.artefact_ways_by_id[id] ~= nil then
- local anomal_zone = bind_anomaly_zone.parent_zones_by_artefact_id[id]
- local force_xz = anomal_zone.applying_force_xz
- local force_y = anomal_zone.applying_force_y
- artefact:FollowByPath(bind_anomaly_zone.artefact_ways_by_id[id],bind_anomaly_zone.artefact_points_by_id[id],vector():set(force_xz,force_y,force_xz))
- -- artefact:FollowByPath(bind_anomaly_zone.artefact_ways_by_id[id],0,vector():set(force_xz,force_y,force_xz))
- end
- self.first_call = true
- local tg = time_global()
- self._tmr_rad = tg
- self._tmr_dgr = tg
- return true
- end
- function artefact_binder:update(delta)
- object_binder.update(self, delta)
- printf("pl:art [%s] pos %s", self.object:name(), vec_to_str(self.object:position()))
- if self.first_call == true then
- local se_obj = alife_object(self.object:id())
- if (se_obj) then
- local m_data = alife_storage_manager.get_se_obj_state(se_obj)
- if (m_data and m_data.offline_condition) then
- printf("loaded condition "..tonumber(m_data.offline_condition))
- self.object:set_condition(tonumber(m_data.offline_condition) or 0.9999999)
- m_data.offline_condition = nil
- end
- end
- local ini = self.object:spawn_ini()
- if not (ini and ini:section_exist("fixed_bone")) then
- self.first_call = false
- return
- end
- local bone_name = ini:r_string_ex("fixed_bone", "name")
- local ph_shell = self.object:get_physics_shell()
- if not ph_shell then
- --printf("no ph shell")
- return
- end
- local ph_element = ph_shell:get_element_by_bone_name(bone_name)
- if ph_element:is_fixed() then
- --printf("OBJECT FIXED")
- else
- --printf("FIXING OBJECT")
- ph_element:fix()
- end
- self.first_call = false
- end
- local obj = self.object
- local cobj = obj:cast_Artefact()
- if (not cobj) then
- return
- end
- local tg = time_global()
- local val = 0
- if (tg > self._tmr_rad) and (not self.no_rad) and in_actor_ruck(obj) then
- self._tmr_rad = tg + rad_tg_step
- -- Get radiation restore speed
- local rad_val = cobj.m_fRadiationRestoreSpeed or 0
- -- No process for artefacts with no / healing rad effect
- if (self.no_rad == nil) then
- self.no_rad = (rad_val <= 0)
- if self.no_rad then
- --print_dbg("Inventory radiation | artefact [%s] is not harmful -> exclude!", obj:name())
- return
- end
- end
- -- Apply radiation on actor
- local rad_delta = rad_val * rad_factor
- db.actor:change_radiation(rad_delta)
- --print_dbg("Inventory radiation | artefact: %s - radiation effect: %s", obj:name(), rad_delta)
- end
- end
- function artefact_binder:net_destroy(se_abstract)
- db.del_obj(self.object)
- object_binder.net_destroy(self)
- end
- function artefact_binder:load(stpk)
- object_binder.load(self,stpk)
- end
- function artefact_binder:save(stpk)
- object_binder.save(self,stpk)
- local se_obj = alife_object(self.object:id())
- if (se_obj) then
- local m_data = alife_storage_manager.get_se_obj_state(se_obj)
- if (m_data) then
- m_data.offline_condition = self.object:condition()
- printf("saved condition "..tonumber(m_data.offline_condition))
- end
- end
- end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement