math_random = math.random math_floor = math.floor gc = game.translate_string ini_ammo = ballistics_utils.ini_ammo get_ammo_data = arti_handlers.get_ammo_data print_dbg = ballistics_mcm.print_dbg local modes = { ["inventory"] = true, } local bags = { ["actor_bag"] = true, ["actor_equ"] = true, ["actor_belt"] = true, } function try_mg_link(obj, bag, mode) if obj and bags[bag] and modes[mode] then if obj:section() == "ammo_7.62x54_7h1" then return gc("st_link") elseif obj:section() == "ammo_pkm_100" then return gc("st_unlink") end end end function mg_link(obj) -- grab up to 5 and try to link them together if obj:section() == "ammo_7.62x54_7h1" then local to_link = {} local count = 0 db.actor:iterate_inventory(function(npc, item) if item:section() == "ammo_7.62x54_7h1" and count < 5 then to_link[item:id()] = item count = count + 1 end end) local total = 0 for k,v in pairs(to_link) do total = total + v:ammo_get_count() alife_release_id(k) end if total > 0 then alife_create_item("ammo_pkm_100", db.actor, {ammo = total}) end elseif obj:section() == "ammo_pkm_100" then local count = obj:ammo_get_count() create_ammo("ammo_7.62x54_7h1", db.actor:position(), db.actor:level_vertex_id(), db.actor:game_vertex_id(), AC_ID, count) alife_release(obj) end end function downgrade_ammo(sec, bypass, mult) mult = mult or 1 local dg_ammo = ini_ammo:r_string_ex(sec, "dg_ammo") local dg_chance = ini_ammo:r_float_ex(sec, "dg_chance") or 0 dg_chance = dg_chance * mult -- print_dbg("Attempt downgrade ammo %s to %s", sec, dg_ammo) if dg_ammo and (math_random() < (dg_chance) or bypass) then -- print_dbg("Downgrading ammo %s to %s", sec, dg_ammo) return dg_ammo else return sec end end function process_wpn(wpn, bypass) local ammo_data = utils_item.get_ammo(wpn:section(), wpn:id()) local ammo_data_inv = invert_table(ammo_data) if is_empty(ammo_data) then return end local ammo_type = ammo_data[wpn:get_ammo_type() + 1] local dg_ammo = ini_ammo:r_string_ex(ammo_type, "dg_ammo") or "" local dg_chance = ini_ammo:r_float_ex(ammo_type, "dg_chance") or 0 if ammo_data_inv[dg_ammo] and (bypass or math_random() < dg_chance) then -- print_dbg("Downgrading ammo for weapon %s", wpn:section()) local cnt = wpn:get_ammo_in_magazine() wpn:unload_magazine(true) wpn:set_ammo_type(ammo_data_inv[dg_ammo] - 1) wpn:set_ammo_elapsed(cnt) end end local recipe_trader = { killer = { "recipe_ammo_nato", "recipe_ammo_pistol", "recipe_ammo_powder", "recipe_ammo_bullet" }, army = { "recipe_ammo_ru1", "recipe_ammo_ru2", "recipe_ammo_powder", "recipe_ammo_bullet" }, ecolog = { "recipe_ammo_arty2", "recipe_ammo_arty1", "recipe_ammo_powder", "recipe_ammo_bullet" }, monolith = { "recipe_ammo_ru2", "recipe_ammo_fire", "recipe_ammo_powder", "recipe_ammo_bullet" }, dolg = { "recipe_ammo_ru1", "recipe_ammo_shotgun", "recipe_ammo_powder", "recipe_ammo_bullet" }, freedom = { "recipe_ammo_nato", "recipe_ammo_fire", "recipe_ammo_powder", "recipe_ammo_bullet" }, csky = { "recipe_ammo_shotgun", "recipe_ammo_arty1", "recipe_ammo_powder", "recipe_ammo_bullet" }, stalker = { "recipe_ammo_pistol", "recipe_ammo_shotgun", "recipe_ammo_powder", "recipe_ammo_bullet" }, bandit = { "recipe_ammo_ru1", "recipe_ammo_pistol", "recipe_ammo_powder", "recipe_ammo_bullet" }, greh = { "recipe_ammo_arty2", "recipe_ammo_nato", "recipe_ammo_powder", "recipe_ammo_bullet" }, isg = { "recipe_ammo_ru1", "recipe_ammo_ru2", "recipe_ammo_pistol", "recipe_ammo_shotgun", "recipe_ammo_nato", "recipe_ammo_arty1", "recipe_ammo_arty2", "recipe_ammo_fire", "recipe_ammo_powder", "recipe_ammo_bullet" }, } function trader_on_restock(npc) if trader_autoinject.get_trader_type(npc) == 1 then trader_autoinject.spawn_items(npc, { powder_fire = 10 }, true) end to_create = {} npc:iterate_inventory(function(npc, item) if not IsAmmo(item) then return end local sec = item:section() dg = downgrade_ammo(sec) if sec ~= dg then to_create[item:id()] = { sec = dg, cnt = item:ammo_get_count() } end end) for k,v in pairs(to_create) do alife_release_id(k) alife_create_item(v.sec, npc, {ammo = v.cnt}) end local level = trader_autoinject.supply_level(npc, true) or 1 local chance = clamp(30 * (level - 1), 0, 100) local comm = trader_autoinject.get_real_community(npc, "stalker") if not recipe_trader[comm] then return end for k,v in pairs(recipe_trader[comm]) do if math.random(100) <= chance then alife_create_item(v, npc) end end end local downgrade = false SpawnAmmo = death_manager.try_spawn_ammo function death_manager.try_spawn_ammo(npc) downgrade = true SpawnAmmo(npc) downgrade = false end -- catch the guys that already exist SetDrop = death_manager.set_weapon_drop_condition function death_manager.set_weapon_drop_condition(npc,itm) downgrade = true SetDrop(npc,itm) -- process_wpn(itm) downgrade = false end AlifeCreate = _G.alife_create_item function _G.alife_create_item(section, obj, t) if downgrade and IsItem("ammo",section) and obj:id() ~= AC_ID then section = downgrade_ammo(section, true) end return AlifeCreate(section, obj, t) end -- this happens whenever npc comes online, currently guarantees that the npc will never have access to better ammo in the wapon function npc_on_net_spawn(npc) CreateTimeEvent("downgrade_ammos",npc:id(), 0,function() npc:iterate_inventory(function(t, item) if IsWeapon(item) then process_wpn(item, true) end end) return true end) end -- spawn recipes with random weights local recipe_weights = { recipe_ammo_ru1 = 20, recipe_ammo_ru2 = 10, recipe_ammo_pistol = 20, recipe_ammo_shotgun = 15, recipe_ammo_nato = 10, recipe_ammo_arty1 = 5, recipe_ammo_arty2 = 5, recipe_ammo_fire = 5, } SpawnTreasure = treasure_manager.try_spawn_treasure function treasure_manager.try_spawn_treasure(box) local id = box:id() -- no spawn if the cache is already looted if not (treasure_manager.caches[id]) then return end SpawnTreasure(box) local k = random_key_table(recipe_weights) if math.random(100) <= recipe_weights[k] then alife_create_item(k, box) end end if magazines then RollAmmo = magazines_loot.determine_ammo -- subject the ammo pop in mags to downgrade function magazines_loot.determine_ammo(ammo_to_pick, mag_sec, rank) if RollAmmo then print_dbg("Roll to downgrade %s in %s", ammo_to_pick, mag_sec) ammo_to_pick = RollAmmo(ammo_to_pick, mag_sec, rank) ammo_to_pick = downgrade_ammo(ammo_to_pick) end return ammo_to_pick end end function on_get_item_cost(kind, obj, profile, calculated_cost, ret) local sec = obj:section() if SYS_GetParam(1, sec, "is_component") and profile.mode == 1 then local calculated_cost = ret.new_cost or calculated_cost -- in case someone adjusted the price of the weapon calculated_cost = calculated_cost * 0.1 ret.new_cost = calculated_cost end end function on_game_start() custom_functor_autoinject.add_functor("mg_link", try_mg_link, try_mg_link, nil, mg_link, true) RegisterScriptCallback("npc_on_net_spawn",npc_on_net_spawn) RegisterScriptCallback("on_get_item_cost",on_get_item_cost) RegisterScriptCallback("trader_on_restock",trader_on_restock) end