1528 lines
43 KiB
Plaintext
1528 lines
43 KiB
Plaintext
|
|
--[[
|
|
itms_manager
|
|
by Alundaio
|
|
|
|
Copyright (C) 2012 Alundaio
|
|
This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
|
|
|
|
Modified by Tronex:
|
|
2018/7/18 - Added support for new usable items (maps,craft)
|
|
2018/7/21 - Added the ability to gather/separate muti-use items
|
|
2018/7/26 - Added the ability to disassemble misc items
|
|
2018/7/26 - Rewrote a lot of function with better codes
|
|
2018/7/31 - Added new items, battery consumption for geiger counter and gps tracker
|
|
2018/8/2 - Drag artefacts on containers to put them in, container tool is no longer used
|
|
2019/2/16 - Organized the items in tables for global use
|
|
2019/9/19 - Bolt count manager
|
|
2020/3/18 - Cleaning
|
|
--]]
|
|
|
|
-- local uses = obj:get_remaining_uses()
|
|
-- local max_uses = obj:get_max_uses()
|
|
-- obj:set_remaining_uses(num)
|
|
|
|
|
|
-- Prepare ini files
|
|
ini_manager = ini_file("items\\settings\\itms_manager.ltx")
|
|
ini_container = ini_file("items\\settings\\arty_container.ltx")
|
|
ini_parts = ini_file("items\\settings\\parts.ltx")
|
|
ini_craft = ini_file("items\\settings\\craft.ltx")
|
|
ini_death = ini_file("items\\settings\\death_generic.ltx")
|
|
ini_reward = ini_file("items\\settings\\item_rewards.ltx")
|
|
|
|
local n = 0
|
|
local result,id,value = "","",""
|
|
local string_find = string.find
|
|
local string_gsub = string.gsub
|
|
|
|
-- Collect item sections of main tools
|
|
itms_arty_container = utils_data.collect_section(ini_container,"containers",true) or {}
|
|
|
|
local empty_syringe_items = {}
|
|
n = ini_manager:line_count("empty_syringe_items")
|
|
for i=0,n-1 do
|
|
result, id, value = ini_manager:r_line_ex("empty_syringe_items",i,"","")
|
|
if ini_sys:section_exist(id) then
|
|
empty_syringe_items[id] = true
|
|
end
|
|
end
|
|
|
|
item_rewards = {}
|
|
ini_reward:section_for_each(function(section)
|
|
if (not item_rewards[section]) then
|
|
item_rewards[section] = {}
|
|
end
|
|
|
|
n = ini_reward:line_count(section)
|
|
for i=0,n-1 do
|
|
result, id, value = ini_reward:r_line_ex(section,i,"","")
|
|
if ini_sys:section_exist(id) then
|
|
item_rewards[section][id] = ini_sys:r_float_ex(id,"tier") or 1
|
|
end
|
|
end
|
|
end)
|
|
|
|
item_combine = {}
|
|
n = ini_craft:line_count("item_combination")
|
|
for i=0,n-1 do
|
|
result, id, value = ini_craft:r_line_ex("item_combination",i,"","")
|
|
if id and value then
|
|
local str = str_explode(id,":")
|
|
if str[1] and str[2] and ini_sys:section_exist(str[1]) and ini_sys:section_exist(str[2]) and ini_sys:section_exist(value) then
|
|
if (not item_combine[str[1]]) then
|
|
item_combine[str[1]] = {}
|
|
end
|
|
item_combine[str[1]][str[2]] = value
|
|
else
|
|
printe("!ERROR item_combination | wrong section names")
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-------------------------------
|
|
-- CALLBACKS
|
|
-------------------------------
|
|
function on_game_start()
|
|
RegisterScriptCallback("actor_on_item_before_use",actor_on_item_before_use)
|
|
RegisterScriptCallback("actor_on_first_update",actor_on_first_update)
|
|
RegisterScriptCallback("actor_on_item_drop",actor_on_item_drop)
|
|
RegisterScriptCallback("actor_on_item_use",actor_on_item_use)
|
|
RegisterScriptCallback("actor_on_item_take",actor_on_item_take)
|
|
RegisterScriptCallback("ActorMenu_on_item_drag_drop",ActorMenu_on_item_drag_drop)
|
|
RegisterScriptCallback("ActorMenu_on_item_focus_receive",ActorMenu_on_item_focus_receive)
|
|
RegisterScriptCallback("save_state",save_state)
|
|
end
|
|
|
|
local old_booster = {}
|
|
local boost_min = 0.00005
|
|
local booster_string = {
|
|
["pwr"] = "ui_inv_power",
|
|
["psy"] = "ui_inv_outfit_telepatic_protection",
|
|
["bld"] = "ui_inv_bleeding",
|
|
["hp"] = "ui_inv_health",
|
|
["rad"] = "ui_inv_radiation",
|
|
}
|
|
function actor_on_item_before_use(obj,flags)
|
|
local sec = obj:section()
|
|
|
|
-- no need to check for tools
|
|
if IsItem("tool",sec) then
|
|
--printf("- actor_on_item_before_use [%s] | ignore utility item", sec)
|
|
flags.ret_value = true
|
|
return
|
|
end
|
|
|
|
local curr_booster = {}
|
|
local time_g = time_global()
|
|
local str = ""
|
|
local pass = true
|
|
|
|
-- read important boosts
|
|
local period = ini_sys:r_float_ex(sec, "boost_time") or 0
|
|
local rad_boost = ini_sys:r_float_ex(sec, "boost_radiation_restore") or 0
|
|
local psy_boost = ini_sys:r_float_ex(sec, "boost_telepat_protection") or 0
|
|
local bld_boost = ini_sys:r_float_ex(sec, "boost_bleeding_restore") or 0
|
|
local hp_boost = ini_sys:r_float_ex(sec, "boost_health_restore") or 0
|
|
local pwr_boost = ini_sys:r_float_ex(sec, "boost_power_restore") or 0
|
|
|
|
-- if an item is required
|
|
local require_tool = ini_sys:r_string_ex(sec, "required_tool")
|
|
local obj_tool = require_tool and ini_sys:section_exist(require_tool) and db.actor:object(require_tool)
|
|
|
|
-- store boosts in a table
|
|
curr_booster["section"] = sec
|
|
curr_booster["period"] = (period > 0) and (time_g + period*1000) or time_g
|
|
curr_booster["pwr"] = (pwr_boost > boost_min) and pwr_boost or 0
|
|
curr_booster["psy"] = (psy_boost > boost_min) and psy_boost or 0
|
|
curr_booster["bld"] = (bld_boost > boost_min) and bld_boost or 0
|
|
curr_booster["hp"] = (hp_boost > boost_min) and hp_boost or 0
|
|
curr_booster["rad"] = (rad_boost > boost_min) and rad_boost or 0
|
|
|
|
-- A required tool is missing -> no eat
|
|
if require_tool and (not obj_tool) then
|
|
--printf("~ actor_on_item_before_use [%s] | require_tool [%s] is missing", sec, require_tool)
|
|
str = strformat(game.translate_string("st_itm_manager_missing_requirements"), ui_item.get_sec_name(require_tool))
|
|
pass = false
|
|
|
|
-- older booster is still active
|
|
-- elseif old_booster["period"] and (old_booster["period"] > time_g) then
|
|
--printf("~ on_before_item_use [%s] | older booster [%s] is still active", sec, old_booster['section'])
|
|
-- local weaker_effect
|
|
-- local stronger_effect
|
|
-- for k,v in pairs(curr_booster) do
|
|
-- if (k ~= "section") and (k ~= "period") then
|
|
-- local v2 = old_booster[k]
|
|
-- if v2 and (v > boost_min) and (v2 > boost_min) then
|
|
-- if (v <= v2) then
|
|
-- weaker_effect = k
|
|
-- else
|
|
-- stronger_effect = k
|
|
-- end
|
|
-- elseif (v2 == 0) and (v > boost_min) then
|
|
-- stronger_effect = k
|
|
-- end
|
|
-- end
|
|
-- end
|
|
|
|
-- older booster has some stronger effect, while new one doesn't have any stronger effect
|
|
-- if weaker_effect and (not stronger_effect) then
|
|
--printf("~ on_before_item_use [%s] | older booster [%s] has stronger effect: %s", sec, old_booster['section'], weaker_effect)
|
|
-- local boost_str = game.translate_string(booster_string[weaker_effect])
|
|
-- str = strformat(game.translate_string("st_itm_manager_greater_effect"),boost_str)
|
|
-- pass = false
|
|
-- end
|
|
end
|
|
|
|
-- to eat or not to eat
|
|
if pass then
|
|
--printf("- on_before_item_use [%s] | pass = true", sec)
|
|
flags.ret_value = true
|
|
copy_table(old_booster, curr_booster)
|
|
if obj_tool then
|
|
utils_item.discharge(obj_tool)
|
|
end
|
|
else
|
|
--printf("! actor_on_item_before_use [%s] | pass = false", sec)
|
|
flags.ret_value = false
|
|
--alife_release(obj)
|
|
--alife_create_item(sec,db.actor)
|
|
|
|
utils_xml.hide_menu()
|
|
actor_menu.set_msg(1, str,3)
|
|
end
|
|
end
|
|
|
|
function actor_on_first_update()
|
|
|
|
-- Delete base pda
|
|
local sim = alife()
|
|
local obj, se_obj
|
|
--[[
|
|
for i=1,65534 do
|
|
se_obj = sim:object(i)
|
|
if se_obj and (se_obj:section_name() == "device_pda") then
|
|
sim:release(se_obj,true)
|
|
end
|
|
end
|
|
--]]
|
|
|
|
-- Delete animation items on actor
|
|
for sec,_ in pairs(GetItemList("release")) do
|
|
obj = db.actor:object(sec)
|
|
if obj then
|
|
alife_release(obj)
|
|
end
|
|
end
|
|
|
|
-- Spawn bolts
|
|
local m_data = alife_storage_manager.get_state()
|
|
local bolt_first = m_data.bolt_first
|
|
if bolt_first then
|
|
alife_create_item(bolt_first, db.actor)
|
|
m_data.bolt_first = nil
|
|
end
|
|
|
|
local bolt_slot = m_data.bolt_slot
|
|
if bolt_slot then
|
|
alife_create_item(bolt_slot, db.actor)
|
|
end
|
|
|
|
local bolts = m_data.bolts
|
|
if bolts then
|
|
for sec,cnt in pairs(bolts) do
|
|
for i=1,cnt do
|
|
alife_create_item(sec, db.actor)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Damage equipment
|
|
if (not has_alife_info("start_equippment_handled")) and (not IsTestMode()) then
|
|
CreateTimeEvent(0,"delay_new_game_autosave",4,new_game_equippment)
|
|
end
|
|
|
|
-- Bolt manager
|
|
CreateTimeEvent("cycle","bolt_manager",60,bolt_manager)
|
|
end
|
|
|
|
function actor_on_item_drop(obj)
|
|
if not (obj) then
|
|
return
|
|
end
|
|
|
|
if (db.actor:has_info("actor_made_wish_for_riches")) then
|
|
db.actor:transfer_item(obj,db.actor)
|
|
elseif IsWeapon(obj) then
|
|
se_save_var(obj:id(), nil, "strapped_item", obj:condition())
|
|
end
|
|
end
|
|
|
|
function actor_on_item_use(obj)
|
|
if (db.actor:has_info("actor_made_wish_for_riches")) then
|
|
return
|
|
end
|
|
|
|
local sec = obj:section()
|
|
|
|
|
|
-- Strelok Notes
|
|
if (sec == "mlr_strelok_item_01") then
|
|
txr_routes.open_route("val","x18")
|
|
return
|
|
|
|
-- Deployable mgun
|
|
elseif (sec == "itm_deployable_mgun") then
|
|
use_deployable_mgun(obj)
|
|
return
|
|
|
|
-- Watch
|
|
elseif (sec == "hand_watch") then
|
|
use_watch(obj)
|
|
return
|
|
|
|
-- Chocolate Bar
|
|
elseif (sec == "chocolate") then
|
|
alife_create_item("chocolate_p", db.actor)
|
|
return
|
|
|
|
-- Bolts pack
|
|
elseif (sec == "bolts_pack") then
|
|
local bolts = {}
|
|
local n = math.random(20,30)
|
|
for i=1,n do
|
|
local actor = db.actor
|
|
if math.random(1,100) > 50 then
|
|
bolts[#bolts + 1] = "bolt"
|
|
else
|
|
bolts[#bolts + 1] = "bolt_bullet"
|
|
end
|
|
end
|
|
utils_item.delay_event(bolts, nil, "bolts_pack", false, 5)
|
|
return
|
|
|
|
-- give empty syringe on using some medical items
|
|
elseif empty_syringe_items[sec] then
|
|
alife_create_item("e_syringe", db.actor)
|
|
|
|
-- weather radar
|
|
elseif (sec == "device_weather_radar") then
|
|
ui_debug_weather.activate()
|
|
return
|
|
end
|
|
|
|
-- don't discharge items with no removal
|
|
if IsItem("multiuse_r",sec) then
|
|
local uses = obj:get_remaining_uses()
|
|
local max_uses = obj:get_max_uses()
|
|
if uses and max_uses and (uses < max_uses) then
|
|
obj:set_remaining_uses(uses + 1)
|
|
end
|
|
end
|
|
end
|
|
|
|
local str_itm_taken = game.translate_string("st_item_taken")
|
|
function actor_on_item_take(obj)
|
|
local sec = obj:section()
|
|
|
|
-- Play sound effect for item taking
|
|
play_item_sound(obj)
|
|
|
|
if IsWeapon(obj) and se_load_var(item_id, nil, "strapped_item") then
|
|
se_save_var(obj:id(), nil, "strapped_item", nil)
|
|
|
|
-- Explosive barrels
|
|
elseif (sec == "explosive_mobiltank") or (sec == "explosive_tank") then
|
|
local se_obj = alife_object(obj:id())
|
|
local fuel = tostring(math.random(6,8))
|
|
if se_obj then
|
|
alife_release(se_obj)
|
|
alife_create_item("explo_jerrycan_fuel", db.actor, {uses = 2})
|
|
end
|
|
|
|
-- Story special
|
|
elseif (sec == "main_story_1_quest_case") and (not has_alife_info("agr_u_bloodsucker_on_case")) then
|
|
db.actor:give_info_portion("agr_u_bloodsucker_on_case")
|
|
xr_effects.create_squad(nil,nil,{"agr_u_bloodsucker_3_squad","agr_u_bloodsucker"})
|
|
end
|
|
|
|
-- Show notification
|
|
--local str = strformat(str_itm_taken, ui_item.get_sec_name(sec))
|
|
--actor_menu.set_msg(2, str)
|
|
end
|
|
|
|
function dropdrop_ArtyContainer(obj_1, obj_2, sec_1, sec_2) -- Put artefact in container
|
|
local cont = sec_2
|
|
local arty = sec_1
|
|
if ini_sys:section_exist(arty .. "_" .. cont) then
|
|
local cond = obj_1 and obj_1:condition()
|
|
|
|
actor_effects.play_item_fx("container_tool_" .. cont .. "_dummy")
|
|
|
|
alife_create_item(arty .. "_" .. cont, db.actor, { cond = cond } )
|
|
alife_release(obj_1)
|
|
alife_release(obj_2)
|
|
end
|
|
end
|
|
function dropdrop_Basic_Combination(obj_1, obj_2, sec_1, sec_2) -- Combine basic items
|
|
local sec_new = item_combine[sec_1][sec_2]
|
|
actor_effects.play_item_fx("item_combination")
|
|
alife_create_item(sec_new, db.actor)
|
|
alife_release(obj_1)
|
|
alife_release(obj_2)
|
|
end
|
|
function ActorMenu_on_item_drag_drop(obj_1, obj_2, slot_from, slot_to)
|
|
|
|
-- Check capability
|
|
if not (slot_from == EDDListType.iActorBag and slot_to == EDDListType.iActorBag) then
|
|
return
|
|
end
|
|
|
|
local sec_1 = obj_1:section()
|
|
local sec_2 = obj_2:section()
|
|
|
|
if itms_arty_container[sec_2] then
|
|
if (ini_sys:r_string_ex(sec_1,"class") == "ARTEFACT") or (ini_sys:r_string_ex(sec_1,"class") == "SCRPTART") then
|
|
dropdrop_ArtyContainer(obj_1, obj_2, sec_1, sec_2)
|
|
end
|
|
|
|
elseif item_combine[sec_1] and item_combine[sec_1][sec_2] then
|
|
dropdrop_Basic_Combination(obj_1, obj_2, sec_1, sec_2)
|
|
end
|
|
end
|
|
|
|
local focus_last_sec
|
|
local focus_tbl = {}
|
|
local focus_upgr = {}
|
|
function ActorMenu_on_item_focus_receive(obj) -- highlight compatible items
|
|
--[[
|
|
local parent = obj:parent()
|
|
if not (parent and parent:id() == AC_ID) then
|
|
return
|
|
end
|
|
--]]
|
|
|
|
local sec_focus = obj:section()
|
|
if (focus_last_sec ~= sec_focus) then
|
|
local id = obj:id()
|
|
focus_last_sec = sec_focus
|
|
empty_table(focus_tbl)
|
|
|
|
local parent_sec = ini_sys:r_string_ex(sec_focus,"parent_section") or sec_focus
|
|
|
|
-- For weapons
|
|
if IsWeapon(obj) then
|
|
|
|
-- Ammo
|
|
local ammo = utils_item.get_ammo(sec_focus, id)
|
|
for i=1,#ammo do
|
|
focus_tbl[#focus_tbl + 1] = ammo[i]
|
|
end
|
|
|
|
-- Scopes
|
|
local scopes = parse_list(ini_sys, parent_sec, "scopes")
|
|
for i=1,#scopes do
|
|
focus_tbl[#focus_tbl + 1] = scopes[i]
|
|
end
|
|
|
|
local scope = utils_item.get_wpn_param(obj, sec_focus, "scopes_sect")
|
|
if scope and (obj:weapon_scope_status() == 2) then
|
|
focus_tbl[#focus_tbl + 1] = scope
|
|
end
|
|
|
|
-- Silencer
|
|
local sil = utils_item.get_wpn_param(obj, sec_focus, "silencer_name")
|
|
if sil and (obj:weapon_silencer_status() == 2) then
|
|
focus_tbl[#focus_tbl + 1] = sil
|
|
end
|
|
|
|
-- Grenade Launcher
|
|
local gl = utils_item.get_wpn_param(obj, sec_focus, "grenade_launcher_name")
|
|
if gl and (obj:weapon_grenadelauncher_status() == 2) then
|
|
focus_tbl[#focus_tbl + 1] = gl
|
|
end
|
|
end
|
|
|
|
-- Parts
|
|
local parts_str = ini_parts:r_string_ex("con_parts_list",parent_sec)
|
|
local parts = parts_str and (parts_str ~= "") and str_explode(parts_str,",")
|
|
if parts then
|
|
for i=1,#parts do
|
|
focus_tbl[#focus_tbl + 1] = parts[i]
|
|
end
|
|
end
|
|
|
|
-- Repair kits
|
|
local repair_type = ini_sys:r_string_ex(parent_sec,"repair_type")
|
|
if repair_type and repair_type ~= "" then
|
|
for kit,v in pairs(GetItemList("repair")) do
|
|
if v[repair_type] then
|
|
focus_tbl[#focus_tbl + 1] = kit
|
|
end
|
|
end
|
|
--[[
|
|
for kit,v in pairs(GetItemList("workshop")) do
|
|
if v[repair_type] then
|
|
focus_tbl[#focus_tbl + 1] = kit
|
|
end
|
|
end
|
|
--]]
|
|
end
|
|
|
|
-- Upgrade parts
|
|
local upgr_str = ini_sys:r_string_ex(parent_sec,"upgrades")
|
|
if upgr_str and upgr_str ~= "" then
|
|
if (not focus_upgr[parent_sec]) then
|
|
local upgr = parse_list(ini_sys,parent_sec,"upgrades")
|
|
focus_upgr[parent_sec] = {}
|
|
for i=1,#upgr do
|
|
extract_upgr_tools(focus_upgr[parent_sec], upgr[i])
|
|
end
|
|
end
|
|
for tool,_ in pairs(focus_upgr[parent_sec]) do
|
|
--printf("- upgrade part for [%s] -> [%s]", parent_sec, tool)
|
|
focus_tbl[#focus_tbl + 1] = tool
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
local inventory = GetActorMenu()
|
|
if not ((#focus_tbl > 0) or (inventory and inventory:IsShown())) then
|
|
return
|
|
end
|
|
|
|
for i=1,#focus_tbl do
|
|
inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iActorBag)
|
|
inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iPartnerTradeBag)
|
|
inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iDeadBodyBag)
|
|
inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iActorTrade)
|
|
inventory:highlight_section_in_slot(focus_tbl[i],EDDListType.iPartnerTrade)
|
|
end
|
|
end
|
|
|
|
function save_state(m_data) --// NOTE: bolts aren't saved in alife, so this is a temp solution
|
|
local bolts = {}
|
|
local function itr(obj)
|
|
local sec = obj:section()
|
|
if (sec == "bolt") or (sec == "bolt_bullet") then
|
|
if (not bolts[sec]) then
|
|
bolts[sec] = 0
|
|
end
|
|
bolts[sec] = bolts[sec] + 1
|
|
end
|
|
return false
|
|
end
|
|
db.actor:inventory_for_each(itr)
|
|
|
|
m_data.bolts = bolts
|
|
m_data.bolt_slot = db.actor:item_in_slot(6) and db.actor:item_in_slot(6):section() or nil
|
|
end
|
|
|
|
|
|
-------------------------------
|
|
-- ITEM OPTIONS (MENU)
|
|
-------------------------------
|
|
function menu_open(itm) -- return "open" name
|
|
local p = itm:parent()
|
|
if not (p and p:id() == AC_ID) then return end
|
|
if itms_arty_container[itm:section()] then return end -- default containers
|
|
|
|
return game.translate_string("st_item_open")
|
|
end
|
|
|
|
function menu_unpack(itm) -- return "unpack" name
|
|
local p = itm:parent()
|
|
if not (p and p:id() == AC_ID) then return end
|
|
|
|
return game.translate_string("st_item_unpack")
|
|
end
|
|
|
|
function menu_play(itm) -- return "Play" name
|
|
local p = itm:parent()
|
|
if not (p and p:id() == AC_ID) then return end
|
|
|
|
return game.translate_string("st_item_play")
|
|
end
|
|
|
|
function menu_place(obj) -- return "Place" name
|
|
return game.translate_string("st_item_place")
|
|
end
|
|
|
|
|
|
-------------------------------
|
|
-- ITEM OPTIONS (FUNCTOR)
|
|
-------------------------------
|
|
function use_package(obj)
|
|
local sec = obj:section()
|
|
local content = parse_list(ini_manager, "package_content", sec)
|
|
if #content > 0 then
|
|
utils_item.delay_event(content, {obj:id()}, "package_content", false, 5)
|
|
end
|
|
end
|
|
|
|
function use_package_random(obj)
|
|
local sec = obj:section()
|
|
local content = ini_manager:r_string_ex("package_content",sec)
|
|
if not content then return end
|
|
|
|
local t = str_explode(content,",")
|
|
local pick = {}
|
|
for i=1,#t do
|
|
if (#pick < 6) and (math.random(100) < 50) then
|
|
pick[#pick+1] = t[i]
|
|
end
|
|
end
|
|
pick = #pick > 1 and pick or {t[1],t[2],t[3],t[4]}
|
|
|
|
utils_item.delay_event(pick, {obj:id()}, "package_content", true, 5)
|
|
end
|
|
|
|
function use_deployable_mgun(obj)
|
|
local pos = vector():set(device().cam_pos)
|
|
pos:add(device().cam_dir:mul(3))
|
|
alife_create("deployable_mgun",pos,level.vertex_id(pos),db.actor:game_vertex_id())
|
|
end
|
|
|
|
function use_guitar(obj)
|
|
local n = math.random(28)
|
|
local snd = sound_object("music\\guitar_" .. tostring(n))
|
|
if (not snd) then return end
|
|
local period = snd:length()
|
|
snd:play_no_feedback(db.actor, 0, 0, db.actor:position(), 1.0, 1.0)
|
|
actor_effects.play_continuous_effect(period)
|
|
end
|
|
|
|
function use_harmonica(obj)
|
|
local n = math.random(5)
|
|
local snd = sound_object("music\\harmonica_" .. tostring(n))
|
|
if (not snd) then return end
|
|
local period = snd:length()
|
|
snd:play_no_feedback(db.actor, 0, 0, db.actor:position(), 1.0, 1.0)
|
|
actor_effects.play_continuous_effect(period)
|
|
end
|
|
|
|
function use_arty_container(obj)
|
|
local break_con
|
|
local break_arty
|
|
local sec = obj:section()
|
|
|
|
if (string.find(sec, "(lead.-_box)",3)) then
|
|
break_con = "lead_box"
|
|
break_arty = sec:gsub("_lead_box", "")
|
|
elseif (string.find(sec, "(af.-_iam)",3)) then
|
|
break_con = "af_iam"
|
|
break_arty = sec:gsub("_af_iam", "")
|
|
elseif (string.find(sec, "(af.-_aac)",3)) then
|
|
break_con = "af_aac"
|
|
break_arty = sec:gsub("_af_aac", "")
|
|
elseif (string.find(sec, "(af.-_aam)",3)) then
|
|
break_con = "af_aam"
|
|
break_arty = sec:gsub("_af_aam", "")
|
|
end
|
|
|
|
if break_con and break_arty and ini_sys:section_exist(break_con) and ini_sys:section_exist(break_arty) then
|
|
local cond = obj:condition()
|
|
|
|
_G.ARTY_FROM_CONT = true -- Hack to prevent player from exploting Artefacts Containers (gaining rank by recieving artefacts)
|
|
actor_effects.play_item_fx(break_con .. "_dummy")
|
|
alife_create_item(break_con, db.actor)
|
|
alife_create_item(break_arty, db.actor, { cond = cond } )
|
|
alife_release(obj)
|
|
end
|
|
end
|
|
|
|
function use_watch(obj)
|
|
local Y, M, D, h, mint, sec, ms = game.get_game_time():get()
|
|
local pharse = game.translate_string("st_dyn_news_day_part_am")
|
|
local mints = tostring(mint)
|
|
if (h > 12) then
|
|
h = h - 12
|
|
pharse = game.translate_string("st_dyn_news_day_part_pm")
|
|
elseif (h == 12) then
|
|
pharse = game.translate_string("st_dyn_news_day_part_pm")
|
|
elseif (h == 0) then
|
|
h = 12
|
|
end
|
|
if (mint < 10) then
|
|
mints = "0" .. tostring(mint)
|
|
end
|
|
utils_xml.hide_menu()
|
|
actor_menu.set_msg(1, tostring(h) .. ":" .. mints .. " " .. pharse , 3)
|
|
end
|
|
|
|
function use_place(obj)
|
|
local p = obj:parent()
|
|
if not (p and p:id() == AC_ID) then
|
|
return
|
|
end
|
|
|
|
local section = obj:section()
|
|
alife_release_id(obj:id())
|
|
|
|
local pos = db.actor:position()
|
|
pos:add(device().cam_dir:mul(1.2))
|
|
pos.y = db.actor:position().y + 1
|
|
local lvid = db.actor:level_vertex_id()
|
|
local gvid = db.actor:game_vertex_id()
|
|
local se_obj = alife_create(section,pos,lvid,gvid)
|
|
|
|
local rot = device().cam_dir:getH()
|
|
se_obj.angle = vector():set(0,rot,0)
|
|
end
|
|
|
|
|
|
-------------------------------
|
|
-- OTHERS
|
|
-------------------------------
|
|
function actor_on_trade(obj,sell_bye,money) -- bind_stalker on_trade
|
|
|
|
end
|
|
|
|
function actor_item_take(obj) -- bind_stalker on_item_take
|
|
|
|
end
|
|
|
|
function npc_on_item_take_from_box(npc,box,item)
|
|
|
|
end
|
|
|
|
function new_game_equippment()
|
|
-- Damage equipment
|
|
local function damage_items(actor,itm)
|
|
local sec = itm:section()
|
|
if (IsWeapon(itm) and (sec ~= "wpn_binoc_inv")) or IsOutfit(itm) or IsHeadgear(itm) or IsItem("device",sec) then
|
|
itm:set_condition(math.random(75,85)/100)
|
|
end
|
|
end
|
|
db.actor:iterate_inventory(damage_items,db.actor)
|
|
|
|
give_info("start_equippment_handled")
|
|
|
|
-- Override autosave
|
|
exec_console_cmd("save " .. user_name() .. " - autosave")
|
|
printf("- Autosaved new game")
|
|
|
|
-- Override ammo type if required
|
|
local start_wpn_tbl = alife_storage_manager.get_state().start_wpn_ammo
|
|
if start_wpn_tbl then
|
|
for id, ammo_sec in pairs(start_wpn_tbl) do
|
|
local wpn = level.object_by_id(id)
|
|
if wpn then
|
|
local ammo_list = utils_item.get_ammo(wpn:section(), wpn:id())
|
|
local ammo_type
|
|
for i=1,#ammo_list do
|
|
if (ammo_list[i] == ammo_sec) then
|
|
ammo_type = i-1
|
|
break
|
|
end
|
|
end
|
|
if ammo_type then
|
|
local wpn_ammo_mag_size = ini_sys:r_u32(wpn:section(), "ammo_mag_size")
|
|
if wpn_ammo_mag_size then
|
|
wpn:unload_magazine()
|
|
wpn:set_ammo_type(ammo_type)
|
|
wpn:set_ammo_elapsed(wpn_ammo_mag_size )
|
|
printdbg("- New game weapon | [%s] - ammo type used: %s", wpn:section(), ammo_type)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return true
|
|
end
|
|
|
|
function bolt_manager() -- limit bolt count in actor inventory
|
|
ResetTimeEvent("cycle","bolt_manager",60)
|
|
|
|
local sim = alife()
|
|
local bolt_max_num = ini_manager:r_float_ex("settings","bolt_max_num") or 99
|
|
local cnt = 0
|
|
local id, sec, se_obj
|
|
|
|
local function itr(temp, obj)
|
|
sec = obj:section()
|
|
if (sec == "bolt") or (sec == "bolt_bullet") then
|
|
cnt = cnt + 1
|
|
if (cnt > bolt_max_num) then
|
|
local se_obj = alife_object(obj:id())
|
|
if se_obj then
|
|
alife_release(se_obj)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
db.actor:iterate_ruck(itr, nil)
|
|
|
|
return false
|
|
end
|
|
|
|
function give_item_reward(num_of_items)
|
|
num_of_items = num_of_items or 1
|
|
local prior = {
|
|
["health"] = 2,
|
|
["rad"] = 2,
|
|
["drink"] = 2,
|
|
["food"] = 2,
|
|
["ammo"] = 2,
|
|
["battery"] = 0,
|
|
}
|
|
|
|
local tot_power,tot_devices = 0,0
|
|
local ammo_suitable = {}
|
|
local ammo_avail = {}
|
|
local function itr(obj)
|
|
local sec = obj:section()
|
|
|
|
-- Evaluate medkits
|
|
if item_rewards["items_health"][sec] then
|
|
prior["health"] = prior["health"] - 1
|
|
end
|
|
|
|
-- Evaluate anti-rads
|
|
if item_rewards["items_rad"][sec] then
|
|
prior["rad"] = prior["rad"] - 1
|
|
end
|
|
|
|
-- Evaluate drink
|
|
if item_rewards["items_drink"][sec] then
|
|
prior["drink"] = prior["drink"] - 1
|
|
end
|
|
|
|
-- Evaluate food
|
|
if item_rewards["items_food"][sec] then
|
|
prior["food"] = prior["food"] - 1
|
|
end
|
|
|
|
-- Evaluate devices power
|
|
if IsItem("device",sec) then
|
|
tot_devices = tot_devices + 1
|
|
tot_power = tot_power + (obj:condition() * 100)
|
|
end
|
|
|
|
-- Evaluate weapons and ammo
|
|
if (sec ~= "wpn_binoc") and IsWeapon(obj) and (not IsMelee(obj)) then
|
|
local ammo = utils_item.get_ammo(obj:section(), obj:id())
|
|
if ammo and #ammo > 1 then
|
|
for i=1,#ammo do
|
|
local sec_ammo = ammo[i]
|
|
if item_rewards["items_ammo"][sec_ammo] then
|
|
ammo_suitable[sec_ammo] = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if IsItem("ammo",sec) then
|
|
ammo_avail[sec] = { cnt = obj:ammo_get_count() , box = IsItem("ammo",sec) }
|
|
--printf("ammo_avail[%s] = { cnt = %s | box = %s", sec, ammo_avail[sec].cnt, ammo_avail[sec].box)
|
|
end
|
|
|
|
return false
|
|
end
|
|
db.actor:inventory_for_each(itr)
|
|
|
|
-- Total power of devices is less than %50 -> need battery
|
|
if (tot_power < (50 * tot_devices)) then
|
|
prior["battery"] = 1
|
|
end
|
|
|
|
-- No enough ammo found for existing weapons -> need ammo
|
|
for sec,_ in pairs(ammo_suitable) do
|
|
local ammo = ammo_avail[sec]
|
|
if ammo and (ammo.cnt >= ammo.box) then
|
|
prior["ammo"] = prior["ammo"] - 1
|
|
end
|
|
end
|
|
|
|
--[[
|
|
for k,p in pairs(prior) do
|
|
printf("- Prior[%s] = %s",k,p)
|
|
end
|
|
--]]
|
|
|
|
-- Give actor items
|
|
for i=1,num_of_items do
|
|
|
|
-- Search from higher to lower priority
|
|
local picker = {}
|
|
local pick_prior
|
|
local functor = function(t,a,b) return t[a] > t[b] end
|
|
for k,p in spairs(prior,functor) do
|
|
if (p > 0) then
|
|
if (not pick_prior) or (pick_prior == p) then
|
|
pick_prior = p
|
|
picker[#picker + 1] = k
|
|
end
|
|
end
|
|
end
|
|
|
|
if pick_prior and (#picker > 0) then
|
|
|
|
-- Pick random type of this priority
|
|
local item_reward
|
|
local k = picker[math.random(#picker)]
|
|
|
|
-- Pick random item
|
|
if k == "health" then
|
|
item_reward = random_key_table(item_rewards["items_health"])
|
|
elseif k == "rad" then
|
|
item_reward = random_key_table(item_rewards["items_rad"])
|
|
elseif k == "drink" then
|
|
item_reward = random_key_table(item_rewards["items_drink"])
|
|
elseif k == "food" then
|
|
item_reward = random_key_table(item_rewards["items_food"])
|
|
elseif k == "battery" then
|
|
item_reward = item_device.device_battery
|
|
elseif k == "ammo" then
|
|
item_reward = random_key_table(ammo_suitable)
|
|
end
|
|
|
|
if item_reward then
|
|
|
|
-- Reduce priority
|
|
prior[k] = prior[k] - 1
|
|
local amount = 1
|
|
|
|
-- Give items
|
|
local box_size = IsItem("ammo",item_reward)
|
|
local max_uses = IsItem("multiuse",item_reward)
|
|
local uses = max_uses and (max_uses >= 2) and 2 or 1
|
|
if uses then
|
|
amount = math.random(1,uses)
|
|
end
|
|
alife_create_item(item_reward, db.actor, {uses = amount , ammo = box_size})
|
|
|
|
-- Send news
|
|
news_manager.relocate_item(db.actor, "in", item_reward, amount)
|
|
end
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
function send_itm_msg(sec)
|
|
local str = strformat(game.translate_string("st_item_taken"), ui_item.get_sec_name(sec))
|
|
actor_menu.set_msg(2, str)
|
|
end
|
|
|
|
local upg_gr = {
|
|
["first"] = 1,
|
|
["secon"] = 2,
|
|
["third"] = 3,
|
|
["fourt"] = 4,
|
|
["fifth"] = 5,
|
|
}
|
|
local upg_ind = {
|
|
["a"] = 1,
|
|
["b"] = 2,
|
|
["c"] = 3,
|
|
["d"] = 4,
|
|
["e"] = 5,
|
|
["f"] = 6,
|
|
}
|
|
function extract_upgr_tools(t1, current_grp)
|
|
|
|
local elements = parse_list(ini_sys, current_grp, "elements")
|
|
|
|
-- Gather groups and indexes
|
|
for i=1,#elements do -- search in upgrade group elements
|
|
for k,v in pairs(upg_gr) do
|
|
if string_find(elements[i],k) then -- if we found a legit element
|
|
local indx = elements[i]:sub(9,9) -- get the index
|
|
local upg_idx = indx and upg_ind[indx]
|
|
if upg_idx then
|
|
local prop = ini_sys:r_string_ex(elements[i],"property")
|
|
if prop then
|
|
local pr = str_explode(prop,",")
|
|
local tool = utils_item.get_upgrade_prop_tool(pr[1])
|
|
local num = ((upg_idx <= 2) and 1) or ((upg_idx <= 4) and 2) or 3
|
|
local sec_tool = tool and tool:gsub("%^d", tostring(num)) or nil
|
|
if sec_tool then
|
|
t1[sec_tool] = true
|
|
else
|
|
local sec = ini_sys:r_string_ex(elements[i],"section")
|
|
printdbg("! extract_upgr | can't generate tool for upgrade [%s], property: %s", sec, pr[1])
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Repeat
|
|
for i=1,#elements do
|
|
local next_grp = ini_sys:r_string_ex(elements[i],"effects")
|
|
if next_grp and (next_grp ~= "") then
|
|
extract_upgr_tools(t1,next_grp)
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
-------------------------------
|
|
-- MULTI-USE ITEMS
|
|
-------------------------------
|
|
function relocate_item_to_actor(actor, npc, section, amount)
|
|
if (not actor) then
|
|
return
|
|
end
|
|
|
|
amount = amount or 1
|
|
local npc_inv = npc and (not IsItem("anim",section)) and utils_item.collect_amount(npc, section, 1) or {}
|
|
local sim = alife()
|
|
local cnt = amount
|
|
local max_uses = IsItem("multiuse",section) or 1
|
|
|
|
while cnt > 0 do
|
|
-- Create or transfer object from npc
|
|
local id
|
|
if not is_empty(npc_inv) then
|
|
local id_pick = random_key_table(npc_inv)
|
|
local obj = id_pick and level.object_by_id(id_pick)
|
|
if obj then
|
|
npc:transfer_item(obj, actor)
|
|
npc_inv[id_pick] = nil
|
|
id = id_pick
|
|
end
|
|
else
|
|
local se_obj = alife_create_item(section, db.actor)
|
|
id = se_obj and se_obj.id
|
|
|
|
-- Register PDA if found
|
|
if npc and id and item_device.device_npc_pda[section] then
|
|
ui_pda_npc_tab.register_pda(npc, section, id)
|
|
end
|
|
end
|
|
|
|
-- Set remaining uses if needed
|
|
if id then
|
|
cnt = cnt - max_uses
|
|
if cnt < 0 then
|
|
local uses = (max_uses - (-cnt))
|
|
process_item(section , id, {uses = uses} )
|
|
end
|
|
else
|
|
printe("!ERROR: relocate_item_to_actor | object for section [%s] is bugged!", section)
|
|
break
|
|
end
|
|
end
|
|
|
|
local box_size = IsItem("ammo",section)
|
|
if box_size then
|
|
amount = amount * box_size
|
|
end
|
|
news_manager.relocate_item(actor, "in", section, amount)
|
|
end
|
|
|
|
function relocate_item_from_actor(actor, npc, section, amount)
|
|
if (not actor) then
|
|
return
|
|
end
|
|
|
|
if (npc == nil) then
|
|
--printe("!ERROR: Couldn't relocate_item_from_actor | no npc found!")
|
|
end
|
|
|
|
amount = amount or 1
|
|
local cnt = amount
|
|
local max_uses = IsItem("multiuse",section)
|
|
local keep_itr = true
|
|
local function itr(temp, obj)
|
|
--printf("~relocate_item_from_actor | checked [%s]", obj:section())
|
|
if keep_itr and (obj and obj:section() == section) then
|
|
--printf("-relocate_item_from_actor | found needed section [%s]", section)
|
|
local uses = max_uses and obj:get_remaining_uses() or 1
|
|
cnt = cnt - uses
|
|
if (cnt >= 0) then
|
|
if npc then
|
|
actor:transfer_item(obj, npc)
|
|
else
|
|
alife_release_id(obj:id())
|
|
end
|
|
|
|
if (cnt == 0) then
|
|
keep_itr = false
|
|
end
|
|
else
|
|
local remain_1 = -cnt
|
|
local remain_2 = max_uses - remain_1
|
|
process_item(section, obj:id(), {uses = remain_1})
|
|
if npc then
|
|
alife_create_item(section, npc, {uses = remain_2})
|
|
end
|
|
keep_itr = false
|
|
end
|
|
end
|
|
end
|
|
actor:iterate_inventory(itr, nil)
|
|
|
|
if cnt > 0 then
|
|
printe("! ERROR: Couldn't relocate_item_from_actor | not enough item [%s] recolated! need %s more", section, cnt)
|
|
end
|
|
|
|
local box_size = IsItem("ammo",section)
|
|
if box_size then
|
|
amount = amount * box_size
|
|
end
|
|
news_manager.relocate_item(actor, "out", section, amount)
|
|
end
|
|
|
|
|
|
-------------------------------
|
|
-- Sound Effects
|
|
-------------------------------
|
|
local time_snd_prev = 0
|
|
local snd_on_take = {
|
|
["coin"] = {"interface\\items\\inv_items_money_coin_2"},
|
|
["bolt"] = {"interface\\items\\inv_items_ammo_1"},
|
|
["paper"] = {"interface\\items\\inv_items_money_paper"},
|
|
["bottle"] = {"interface\\items\\inv_items_bottle_",1,2},
|
|
["pills"] = {"interface\\items\\inv_items_pills_2"},
|
|
["part"] = {"interface\\items\\inv_items_parts_",1,2},
|
|
["outfit"] = {"interface\\items\\inv_items_cloth_",1,3},
|
|
["ammo"] = {"interface\\items\\inv_items_ammo_",4,7},
|
|
["grenade"] = {"interface\\items\\inv_items_grenade_",1,2},
|
|
["knife"] = {"interface\\items\\inv_items_knife_",1,2},
|
|
["weapon"] = {"interface\\items\\inv_items_wpn_",1,2},
|
|
["other"] = {"interface\\items\\inv_items_generic_",2,5},
|
|
}
|
|
|
|
function play_item_sound(item, vol)
|
|
if (not item) then
|
|
printe("!ERROR itms_manager | play_item_sound | no object recieved!")
|
|
end
|
|
|
|
local snd_type = SYS_GetParam(0,item:section(),"snd_on_take")
|
|
if not (snd_type and snd_type ~= "") then
|
|
return
|
|
end
|
|
|
|
local snd = snd_on_take[snd_type]
|
|
if (not snd) then
|
|
return
|
|
end
|
|
|
|
local snd_obj
|
|
if (#snd == 1) then
|
|
snd_obj = sound_object(snd[1])
|
|
else
|
|
snd_obj = sound_object(snd[1] .. tostring(math.random(snd[2],snd[3])))
|
|
end
|
|
|
|
local time_g = time_global()
|
|
if snd_obj and (time_g > time_snd_prev + 25) then
|
|
snd_obj:play(db.actor,0,sound_object.s2d)
|
|
snd_obj.volume = vol or 1
|
|
end
|
|
time_snd_prev = time_g
|
|
end
|
|
|
|
|
|
|
|
-------------------------------
|
|
-- Item Processor
|
|
-------------------------------
|
|
local c_instance
|
|
function get_item_processor()
|
|
if c_instance == nil then
|
|
c_instance = ItemProcessor()
|
|
end
|
|
return c_instance
|
|
end
|
|
|
|
function process_item(...)
|
|
if c_instance == nil then
|
|
c_instance = ItemProcessor()
|
|
end
|
|
return c_instance:Process_Item(...)
|
|
end
|
|
|
|
function create_item(...)
|
|
if c_instance == nil then
|
|
c_instance = ItemProcessor()
|
|
end
|
|
return c_instance:Create_Item(...)
|
|
end
|
|
|
|
class "ItemProcessor"
|
|
function ItemProcessor:__init()
|
|
self.Remove = {}
|
|
self.Cond = {}
|
|
self.Uses = {}
|
|
self.Ammo = {}
|
|
|
|
self.Debug = false -- true to debug
|
|
self.Cycles = 10
|
|
end
|
|
|
|
function ItemProcessor:update()
|
|
-- Process Condition
|
|
for id,con in pairs(self.Cond) do
|
|
local obj = level.object_by_id(id)
|
|
if obj then
|
|
if self.Debug then
|
|
printf("* ItemProcessor | processing condition | id: %s - con: %s", id, con)
|
|
end
|
|
|
|
obj:set_condition(con)
|
|
local new_con = obj:condition()
|
|
|
|
if (new_con < con + 0.02) and (new_con > con - 0.02) then -- range check
|
|
self.Cond[id] = nil
|
|
|
|
if self.Debug then
|
|
printf("# ItemProcessor | processing condition done | id: %s - con: %s", id, new_con)
|
|
end
|
|
else
|
|
self:Remove_Process(id,"!","can't set condition!")
|
|
end
|
|
|
|
elseif alife_object(id) then
|
|
self:Remove_Process(id,"~","server object exists, no game object yet")
|
|
|
|
else
|
|
self:Remove_Process(id,"!","no game object!")
|
|
end
|
|
end
|
|
|
|
-- Process Uses
|
|
for id,uses in pairs(self.Uses) do
|
|
local obj = level.object_by_id(id)
|
|
if obj then
|
|
if self.Debug then
|
|
printf("* ItemProcessor | processing uses | id: %s - uses: %s", id, uses)
|
|
end
|
|
|
|
obj:set_remaining_uses(uses)
|
|
|
|
if (obj:get_remaining_uses() == uses) then
|
|
self.Uses[id] = nil
|
|
|
|
if self.Debug then
|
|
printf("# ItemProcessor | processing uses done | id: %s - con: %s", id, uses)
|
|
end
|
|
else
|
|
self:Remove_Process(id,"!","can't set uses!")
|
|
end
|
|
|
|
elseif alife_object(id) then
|
|
self:Remove_Process(id,"~","server object exists, no game object yet")
|
|
|
|
else
|
|
self:Remove_Process(id,"!","no game object!")
|
|
end
|
|
end
|
|
|
|
-- Process Ammo
|
|
for id,ammo in pairs(self.Ammo) do
|
|
local obj = level.object_by_id(id)
|
|
if obj then
|
|
if self.Debug then
|
|
printf("* ItemProcessor | processing ammo | id: %s - ammo: %s", id, ammo)
|
|
end
|
|
|
|
obj:ammo_set_count(ammo)
|
|
|
|
if (obj:ammo_get_count() == ammo) then -- range
|
|
self.Ammo[id] = nil
|
|
|
|
if self.Debug then
|
|
printf("# ItemProcessor | processing ammo done | id: %s - con: %s", id, new_con)
|
|
end
|
|
else
|
|
self:Remove_Process(id,"!","can't set ammo!")
|
|
end
|
|
|
|
elseif alife_object(id) then
|
|
self:Remove_Process(id,"~","server object exists, no game object yet")
|
|
|
|
else
|
|
self:Remove_Process(id,"!","no game object!")
|
|
end
|
|
end
|
|
end
|
|
|
|
function ItemProcessor:Create_Item(section, owner, t)
|
|
|
|
t = t or {}
|
|
|
|
if section then
|
|
local uses
|
|
section, uses = self:Extract_Uses(section)
|
|
|
|
if (ini_sys:section_exist(section)) then
|
|
|
|
-- Spawn object
|
|
local se_itm
|
|
if owner then
|
|
|
|
-- Collect spawn data
|
|
local pos, lvi, gvi, pid, spawn_typ
|
|
if (type(owner) == "table") then
|
|
pos, lvi, gvi, pid = owner[1], owner[2], owner[3], owner[4]
|
|
if pid then
|
|
spawn_typ = "on custom object"
|
|
else
|
|
spawn_typ = "in world"
|
|
end
|
|
elseif (type(owner.id) == "function") then
|
|
pos, lvi, gvi, pid = owner:position(), owner:level_vertex_id(), owner:game_vertex_id(), owner:id()
|
|
spawn_typ = "on game object"
|
|
elseif owner.id then
|
|
pos, lvi, gvi, pid = owner.position, owner.m_level_vertex_id, owner.m_game_vertex_id, owner.id
|
|
spawn_typ = "on server object"
|
|
end
|
|
|
|
-- Validate
|
|
if not (pos and lvi and gvi) then
|
|
callstack()
|
|
printe("! ItemProcessor | Missing spawn properties for [%s] | Spawn type: %s | pos: %s, lvi: %s, gvi: %s", section, spawn_typ, pos , lvi , gvi)
|
|
return nil
|
|
end
|
|
if self.Debug then
|
|
local obj_p = pid and alife_object(pid)
|
|
local name_p = obj_p and (obj_p.id == AC_ID and "actor" or obj_p:name()) or ""
|
|
spawn_typ = spawn_typ .. (obj_p and (" (".. name_p .. ")") or "")
|
|
end
|
|
|
|
-- Ammo need unique process to spawn multi-objects, return result from here
|
|
if t.ammo and t.ammo > 0 and IsItem("ammo",section) then
|
|
|
|
-- Replace damaged items with old if _NO_DAMAGED_AMMO allows it
|
|
if _NO_DAMAGED_AMMO and string_find(section,"verybad") then
|
|
local new_section = string_gsub(section,"verybad","bad")
|
|
if ini_sys:section_exist(new_section) then
|
|
section = new_section
|
|
end
|
|
end
|
|
|
|
|
|
local num_in_box = ini_sys:r_u32(section, "box_size")
|
|
local num = t.ammo
|
|
local se_tbl = {}
|
|
local sim = alife()
|
|
|
|
local p_id = pid or 65535 -- because xray
|
|
while (num > num_in_box) do
|
|
se_tbl[#se_tbl+1] = sim:create_ammo(section, pos, lvi, gvi, p_id, num_in_box)
|
|
alife_record( se_tbl[#se_tbl] , true )
|
|
num = num - num_in_box
|
|
|
|
if self.Debug then
|
|
local se_ammo = se_tbl[#se_tbl]
|
|
printf("/ alife_create [%s] (%s) x%s ammo %s", section, se_ammo and se_ammo.id, num_in_box, spawn_typ)
|
|
end
|
|
end
|
|
|
|
se_tbl[#se_tbl+1] = sim:create_ammo(section, pos, lvi, gvi, p_id, num)
|
|
alife_record( se_tbl[#se_tbl] , true )
|
|
|
|
if self.Debug then
|
|
local se_ammo = se_tbl[#se_tbl]
|
|
printf("/ alife_create [%s] (%s) x%s ammo %s", section, se_ammo and se_ammo.id, num, spawn_typ)
|
|
end
|
|
|
|
return se_tbl
|
|
|
|
-- Other items
|
|
else
|
|
|
|
if pid then
|
|
se_itm = alife():create(section, pos, lvi, gvi, pid)
|
|
else
|
|
se_itm = alife():create(section, pos, lvi, gvi)
|
|
end
|
|
|
|
if self.Debug then
|
|
printf("/ alife_create [%s] (%s) on %s", section, se_itm and se_itm.id, spawn_typ)
|
|
end
|
|
end
|
|
else
|
|
printe("! ItemProcessor | Missing spawn owner for [%s]!", section)
|
|
end
|
|
|
|
-- Process
|
|
if se_itm then
|
|
alife_record(se_itm,true)
|
|
|
|
-- Multiuse items
|
|
if IsItem("multiuse",section) then
|
|
uses = uses or t.uses
|
|
|
|
-- Send to process
|
|
if uses then
|
|
self.Uses[se_itm.id] = uses --self:Process_Item(section, se_itm.id, { uses = uses })
|
|
end
|
|
|
|
-- Degradable items
|
|
elseif utils_item.is_degradable(nil, section) then
|
|
local cond = t.cond
|
|
|
|
-- Parts
|
|
if t.cond_cr and t.cond_ct and IsItem(cond_ct,section) then
|
|
cond = (#t.cond_cr > 2) and self:Random_Choice(t.cond_cr) or self:Random_Condition(t.cond_cr)
|
|
|
|
-- others
|
|
elseif t.cond_r then
|
|
cond = (#t.cond_r > 2) and self:Random_Choice(t.cond_r) or self:Random_Condition(t.cond_r)
|
|
|
|
end
|
|
|
|
-- Send to process
|
|
if cond then
|
|
self.Cond[se_itm.id] = cond --self:Process_Item(section, se_itm.id, { cond = cond })
|
|
end
|
|
end
|
|
|
|
return se_itm
|
|
|
|
else
|
|
printe("!ERROR [%s] is not spawned by ItemProcessor",section)
|
|
end
|
|
|
|
else
|
|
printe("! ItemProcessor | section [%s] doesn't exist!", section)
|
|
end
|
|
|
|
else
|
|
printf("~ ItemProcessor | nothing is passed to process!")
|
|
end
|
|
|
|
return nil
|
|
end
|
|
|
|
function ItemProcessor:Process_Item(section, id, t)
|
|
if t then
|
|
if t.uses then
|
|
self.Uses[id] = t.uses
|
|
|
|
elseif t.cond then
|
|
self.Cond[id] = t.cond
|
|
|
|
elseif t.ammo then
|
|
self.Ammo[id] = t.ammo
|
|
|
|
elseif self.Debug then
|
|
--printf("* ItemProcessor | no process done for [%s] (%s)", section, id)
|
|
end
|
|
end
|
|
end
|
|
|
|
function ItemProcessor:Remove_Process(id, mark, str)
|
|
mark = mark or "~"
|
|
self.Remove[id] = self.Remove[id] and (self.Remove[id] + 1) or 0
|
|
if (self.Remove[id] > self.Cycles) then
|
|
self.Cond[id] = nil
|
|
self.Uses[id] = nil
|
|
self.Ammo[id] = nil
|
|
self.Remove[id] = nil
|
|
|
|
if self.Debug then
|
|
local obj = level.object_by_id(id)
|
|
local p = obj and obj:parent()
|
|
printf("%s ItemProcessor | %s: (%s) [%s] - owner: (%s) [%s]", mark, str, id, obj and obj:section(), p and p:id() or "-", p and p:section())
|
|
end
|
|
end
|
|
end
|
|
|
|
function ItemProcessor:Random_Choice(arg)
|
|
if arg and (#arg > 0) then
|
|
local r = math.random(1, #arg)
|
|
return arg[r]
|
|
end
|
|
end
|
|
|
|
function ItemProcessor:Random_Condition(arg)
|
|
if arg and (#arg > 0) then
|
|
return (math.random(arg[1], arg[2])/100)
|
|
end
|
|
end
|
|
|
|
function ItemProcessor:Extract_Uses(sec_d)
|
|
local _, __, sec_u, uses = string_find(sec_d,"(.*)__(%d)")
|
|
if sec_u and uses and tonumber(uses) and ini_sys:section_exist(sec_u) then
|
|
return sec_u, tonumber(uses)
|
|
end
|
|
return sec_d
|
|
end
|
|
|
|
--------------------------------------------------------------------------------
|
|
|
|
|
|
-------------------------------
|
|
-- DEBUG
|
|
-------------------------------
|
|
function generate_boosters_list()
|
|
local config = ini_file_ex("booster_stats.ltx",true)
|
|
|
|
ini_sys:section_for_each(function(section)
|
|
local cls = ini_sys:r_string_ex(section,"class")
|
|
if (cls == "II_FOOD") and (ini_sys:r_float_ex(section,"boost_time") > 0) then
|
|
local str = ""
|
|
str = str .. ("cost:" .. ini_sys:r_float_ex(section,"cost") .. "|")
|
|
str = str .. (ini_sys:r_float_ex(section,"max_uses") and ("uses:" .. ini_sys:r_float_ex(section,"max_uses") .. "|") or ("uses:1|"))
|
|
str = str .. ("boost_time:" .. ini_sys:r_float_ex(section,"boost_time") .. "|")
|
|
|
|
if ini_sys:r_float_ex(section,"boost_max_weight") ~= 0 then
|
|
str = str .. ("boost_max_weight:" .. ini_sys:r_float_ex(section,"boost_max_weight") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_health_restore") ~= 0 then
|
|
str = str .. ("boost_health_restore:" .. ini_sys:r_float_ex(section,"boost_health_restore") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_power_restore") ~= 0 then
|
|
str = str .. ("boost_power_restore:" .. ini_sys:r_float_ex(section,"boost_power_restore") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_radiation_restore") ~= 0 then
|
|
str = str .. ("boost_radiation_restore:" .. ini_sys:r_float_ex(section,"boost_radiation_restore") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_bleeding_restore") ~= 0 then
|
|
str = str .. ("boost_bleeding_restore:" .. ini_sys:r_float_ex(section,"boost_bleeding_restore") .. "|")
|
|
end
|
|
|
|
if ini_sys:r_float_ex(section,"boost_radiation_protection") ~= 0 then
|
|
str = str .. ("boost_radiation_protection:" .. ini_sys:r_float_ex(section,"boost_radiation_protection") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_telepat_protection") ~= 0 then
|
|
str = str .. ("boost_telepat_protection:" .. ini_sys:r_float_ex(section,"boost_telepat_protection") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_chemburn_protection") ~= 0 then
|
|
str = str .. ("boost_chemburn_protection:" .. ini_sys:r_float_ex(section,"boost_chemburn_protection") .. "|")
|
|
end
|
|
|
|
if ini_sys:r_float_ex(section,"boost_burn_immunity") ~= 0 then
|
|
str = str .. ("boost_burn_immunity:" .. ini_sys:r_float_ex(section,"boost_burn_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_shock_immunity") ~= 0 then
|
|
str = str .. ("boost_shock_immunity:" .. ini_sys:r_float_ex(section,"boost_shock_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_radiation_immunity") ~= 0 then
|
|
str = str .. ("boost_radiation_immunity:" .. ini_sys:r_float_ex(section,"boost_radiation_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_telepat_immunity") ~= 0 then
|
|
str = str .. ("boost_telepat_immunity:" .. ini_sys:r_float_ex(section,"boost_telepat_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_chemburn_immunity") ~= 0 then
|
|
str = str .. ("boost_chemburn_immunity:" .. ini_sys:r_float_ex(section,"boost_chemburn_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_strike_immunity") ~= 0 then
|
|
str = str .. ("boost_strike_immunity:" .. ini_sys:r_float_ex(section,"boost_strike_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_wound_immunity") ~= 0 then
|
|
str = str .. ("boost_wound_immunity:" .. ini_sys:r_float_ex(section,"boost_wound_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_explosion_immunity") ~= 0 then
|
|
str = str .. ("boost_explosion_immunity:" .. ini_sys:r_float_ex(section,"boost_explosion_immunity") .. "|")
|
|
end
|
|
if ini_sys:r_float_ex(section,"boost_fire_wound_immunity") ~= 0 then
|
|
str = str .. ("boost_fire_wound_immunity:" .. ini_sys:r_float_ex(section,"boost_fire_wound_immunity") .. "|")
|
|
end
|
|
|
|
config:w_value("temp", section, str)
|
|
end
|
|
end)
|
|
|
|
config:save()
|
|
end |