Divergent/mods/Anomaly Magazines Redux/gamedata/scripts/magazines_loot.script

236 lines
9.6 KiB
Plaintext
Raw Permalink Normal View History

2024-03-17 20:18:03 -04:00
----------------------------------------------------------------
-- Deal with loot injection in stalkers and traders
----------------------------------------------------------------
gc = game.translate_string
get_data = magazine_binder.get_data
set_data = magazine_binder.set_data
get_mag_loaded = magazine_binder.get_mag_loaded
prep_weapon = magazines.prep_weapon
is_supported_weapon = magazine_binder.is_supported_weapon
get_magazine_caliber = magazine_binder.get_magazine_caliber
is_magazine = magazine_binder.is_magazine
weapon_default_magazine = magazine_binder.weapon_default_magazine
weapon_improved_magazine = magazine_binder.weapon_improved_magazine
create_mag_data = magazine_binder.create_mag_data
print_dbg = magazines.print_dbg
get_weapon_base_type = magazine_binder.get_weapon_base_type
get_mags_for_basetype = magazine_binder.get_mags_for_basetype
valid_mag_data = magazine_binder.valid_mag_data
get_config = magazines_mcm.get_config
validate_mag = magazine_binder.validate_mag
validate_wep = magazine_binder.validate_wep
local math_random = math.random
local math_floor = math.floor
local string_format = string.format
local print_table = utils_data.print_table
local ini_loadouts = ini_file("items\\settings\\npc_mag_loadouts.ltx")
local mag_timer_global = nil
local tm = {}
-- trader management
TraderAuto = trader_autoinject.update
function trader_autoinject.update(npc)
TraderAuto(npc)
CreateTimeEvent("restock_mags" .. npc:id(), "restock_mags" .. npc:id(), 0.01, function()
stock_mags(npc)
return true
end)
end
-- function to resupply mags based on what weapons are in stock
-- formula is: 3 mags for 1st weapon, and 1 extra for each subsequent
function stock_mags(npc)
local id = npc:id()
if trader_autoinject.get_trader_type(npc) ~= trader_autoinject.SUPPLIER then return end
print_dbg("Restocking mags for %s", npc:name())
local to_spawn = {}
-- collect num. of mags to spawn
local function itr_inv(temp, item)
local sec = item:section()
if not IsAmmo(item) and IsWeapon(item) and is_supported_weapon(item) then
local default_mag = weapon_default_magazine(item)
local default_capacity = SYS_GetParam(2, default_mag, "max_mag_size")
local default_load_delay = SYS_GetParam(2, default_mag, "load_delay")
local mags = get_mags_for_basetype(get_weapon_base_type(item))
if mags then
print_dbg("Mags [%s]", sec)
for _, mag in pairs(mags) do
local load_delay = SYS_GetParam(2, mag, "load_delay")
local capacity = SYS_GetParam(2, mag, "max_mag_size")
if mag ~= default_mag and (capacity > default_capacity or load_delay < default_load_delay) then
print_dbg("Mag %s is improved", mag)
to_spawn[mag] = to_spawn[mag] and to_spawn[mag] + math_random(0, 1) or math_random(1, 2)
else
print_dbg("Mag %s is normal", mag)
to_spawn[mag] = to_spawn[mag] and to_spawn[mag] + 1 or 3
end
end
else
print_dbg("Weapon has broken basetype [%s]", sec)
end
end
end
npc:iterate_inventory(itr_inv, npc)
-- spawn them empty
trader_autoinject.spawn_items(npc, to_spawn, true)
end
-- death management
local function get_mag_prop(rank, prop)
rank = rank or "novice"
return ini_loadouts:r_float_ex(rank.."_mag_loadout", prop)
end
-- called on each created magazine, autofill with the appropriate crap
function random_pop_mag(mag_id, mag_sec, ammo_table, rank)
local quality = get_config("deathquality") or 1
local amount = math_random(0, get_mag_prop(rank, "mag_fill_max"))
amount = clamp(amount * (get_config("deathammo") or 1), 0, 100)/100
local mag_data = get_mag_loaded(mag_id) or create_mag_data(mag_id, mag_sec)
empty_table(mag_data.loaded)
local to_fill = math_floor(amount * SYS_GetParam(2, mag_sec, "max_mag_size"))
-- also pick the appropriate ammo
local good_chance = get_mag_prop(rank, "mag_good_chance") * quality
-- add validation for existence of a single ammo type (e.g. 9x21 sp10)
-- This should really be refactored to categorize bad ammo in the ammo table instead of relying on the index
local ammo_to_pick = math_random(#ammo_table)
if #ammo_table > 1 then
ammo_to_pick = 3*math_floor(math_random(#ammo_table - 1) / 3) + 1 + (math_random(100) < good_chance and 0 or 1)
else
to_fill = math_floor(to_fill/2)
end
local ammo_to_use = determine_ammo(ammo_table[ammo_to_pick], mag_sec, rank)
print_dbg("Filling mag %s to %s with %s (num %s)", mag_sec, to_fill, ammo_to_use, ammo_to_pick)
for i=1,to_fill do
stack.push(mag_data.loaded, ammo_to_use)
end
set_data(mag_id, mag_data)
return true
end
function determine_ammo(ammo_to_pick, mag_sec, rank)
return ammo_to_pick
end
function npc_on_death(npc, who)
local rank = ranks.get_obj_rank_name(npc)
local found_primary = false
local found_secondary = false
function itr_inv(temp, item)
local sec = item:section()
if IsWeapon(nil,item:clsid()) and not npc:marked_dropped(item) and is_supported_weapon(item) then
-- spawn mags for one primary, one secondary
local is_sidearm = IsPistol(item)
if (found_primary and not is_sidearm) or (found_secondary and is_sidearm) then return end
-- reduce ammo in loaded weapon
local id = item:id()
local mag_data = get_data(id)
local mags_to_spawn = math_random(0, get_mag_prop(rank, "max_mags"))
local mag_sec = weapon_default_magazine(sec)
local improved_mag_sec = weapon_improved_magazine(sec)
local mag_good_chance = get_mag_prop(rank, "mag_good_chance")
local ammo_table = get_magazine_caliber(mag_sec)
local quality = get_config("deathquality") or 1
print_dbg("Spawning %s mags for %s", mags_to_spawn, sec)
for i=1,mags_to_spawn do
local to_create = math_floor(quality * math_random(100)) <= mag_good_chance and improved_mag_sec or mag_sec
print_dbg("Creating magazine %s", to_create)
local new_mag = alife_create_item(to_create, npc)
if new_mag then
random_pop_mag(new_mag.id, to_create, ammo_table, rank)
end
end
if is_sidearm then
found_secondary = true
else
found_primary = true
end
end
end
npc:iterate_inventory(itr_inv, npc)
end
SetWepCondition = death_manager.set_weapon_drop_condition
function death_manager.set_weapon_drop_condition(npc, itm)
SetWepCondition(npc, itm)
local death_dropped = se_load_var(npc:id(), npc:name(), "death_dropped")
if (death_dropped) then
return
end
local id = itm:id()
if not is_supported_weapon(itm) then
set_data(id, nil)
return
end
if (is_supported_weapon(itm) and not npc:marked_dropped(itm)) then
local id = itm:id()
local sec = itm:section()
local mag_sec = weapon_default_magazine(sec)
local ammo_table = get_magazine_caliber(mag_sec)
local rank = ranks.get_obj_rank_name(npc)
print_dbg("Resetting mag data for weapon %s (%s)", id, itm:section())
itm:unload_magazine()
random_pop_mag(id, mag_sec, ammo_table, rank)
prep_weapon(itm, false)
end
end
-- 1.5.2 feature - determine mag cost based on contents
function on_get_item_cost(kind, obj, profile, calculated_cost, ret)
local id = obj:id()
local sec = obj:section()
local mag_data = get_mag_loaded(id)
local calculated_cost = ret.new_cost or calculated_cost -- in case someone adjusted the price of the weapon
if mag_data == nil then return end
-- we have mag data - but it can potentially be corrupt. perform validation if needed
-- print_dbg("Item %s has mag data", sec)
if is_magazine(obj) then
validate_mag(id, sec)
local cost_base = obj:cost()
-- non stalkers, reduce mag cost
if profile.mode == 1 then
cost_base = cost_base * 0.1
end
local info = mags_patches.collect_mag_data(mag_data)
for k,v in pairs(info) do
local cost_frac = math_floor(SYS_GetParam(2, k, "cost") / SYS_GetParam(2, k, "box_size")) * v
-- print_dbg("Mag %s, cost %s, add cost %s from %s of %s", sec, cost_base, cost_frac, v, k)
cost_base = cost_base + cost_frac
end
ret.new_cost = cost_base * profile.discount
print_dbg("Final cost of %s is %s, discount %s", sec, ret.new_cost, profile.discount)
elseif is_supported_weapon(obj) and mag_data then
validate_wep(id, sec)
local mag_cost = SYS_GetParam(2, mag_data.section, "cost") * profile.discount
if profile.mode == 1 then
mag_cost = mag_cost * 0.1
end
-- print_dbg("Weapon %s, adding mag %s cost %s", sec, mag_data.section, mag_cost)
ret.new_cost = calculated_cost + mag_cost
else
printf("!!! FRAUD DETECTED !!! Item %s should not have mag data!", sec)
set_data(id, nil)
end
end
function on_game_start()
if utils_item.on_get_item_cost then
RegisterScriptCallback("on_get_item_cost", on_get_item_cost)
end
RegisterScriptCallback("npc_on_death_callback", npc_on_death)
end