local OFHotBrassPatch = { patched = false, } local function isPatchToggleEnabled() local vars = SandboxVars and SandboxVars.OpinionatedFirearms if vars and vars.HBVCEFAmmoMakerPatch ~= nil then return vars.HBVCEFAmmoMakerPatch == true end return true end local function isSessionEligible() return isPatchToggleEnabled() end local function getAmmoMakerFiredCasing(ammoType) if type(ammoType) ~= "string" or ammoType == "" then return nil end local function partDataToFiredType(partData) if type(partData) ~= "table" then return nil end local firedType = partData.partFired or partData.partOld if type(firedType) ~= "string" or firedType == "" then return nil end return firedType end if type(ammoMakerAmmoParts) ~= "table" then return nil end if type(ammoMakerGetCasingType) == "function" then local ok, casingType = pcall(ammoMakerGetCasingType, ammoType) if ok and type(casingType) == "string" then local firedType = partDataToFiredType(ammoMakerAmmoParts[casingType]) if firedType then return firedType end end end -- Fallback path that doesn't depend on Ammo Maker active-mod resolution. if type(ammoMakerAmmoTypes) == "table" and type(ammoMakerAmmoData) == "table" then local ammoDef = ammoMakerAmmoTypes[ammoType] if type(ammoDef) == "table" and type(ammoDef.ammoTypes) == "table" then for i = 1, #ammoDef.ammoTypes do local ammoKey = ammoDef.ammoTypes[i] local ammoData = ammoMakerAmmoData[ammoKey] if type(ammoData) == "table" and type(ammoData.casingType) == "string" then local firedType = partDataToFiredType(ammoMakerAmmoParts[ammoData.casingType]) if firedType then return firedType end end end end end return nil end local function applyPatch() if OFHotBrassPatch.patched then return true end if not isSessionEligible() then return false end if type(SpentCasingPhysics) ~= "table" then return false end if type(SpentCasingPhysics.getItemToEject) ~= "function" then return false end if type(SpentCasingPhysics.doSpawnCasing) ~= "function" then return false end local originalGetItemToEject = SpentCasingPhysics.getItemToEject local originalDoSpawnCasing = SpentCasingPhysics.doSpawnCasing SpentCasingPhysics.getItemToEject = function(ammoType) local mappedType = getAmmoMakerFiredCasing(ammoType) if mappedType then return mappedType end return originalGetItemToEject(ammoType) end SpentCasingPhysics.doSpawnCasing = function(player, weapon, params, racking, optionalItem) if not optionalItem and weapon and weapon.getAmmoType then local ammoType = weapon:getAmmoType() if ammoType then local mappedType = getAmmoMakerFiredCasing(tostring(ammoType)) if mappedType then optionalItem = mappedType if racking then -- Force rack ejects to stay as empties for this patch. racking = false end end end end return originalDoSpawnCasing(player, weapon, params, racking, optionalItem) end OFHotBrassPatch.patched = true return true end local function tryPatchOnTick() if OFHotBrassPatch.patched then Events.OnTick.Remove(tryPatchOnTick) return end applyPatch() end Events.OnTick.Add(tryPatchOnTick)