-------------------- -- Console variables -------------------- local ir_mode = CV_RegisterVar({ name = "ir_mode", defaultvalue = "Race", flags = CV_NETVAR, possiblevalue = {None = 0, Race = 1, Battle = 2, Both = 3} }) local ir_traps = CV_RegisterVar({ name = "ir_traps", defaultvalue = "Off", flags = CV_NETVAR, possiblevalue = CV_OnOff }) local ir_limit = CV_RegisterVar({ name = "ir_limit", defaultvalue = "90", flags = CV_NETVAR, possiblevalue = CV_Natural }) local ir_limit_spb = CV_RegisterVar({ name = "ir_limit_spb", defaultvalue = "2", flags = CV_NETVAR, possiblevalue = CV_Natural }) local ir_lifetime = CV_RegisterVar({ name = "ir_lifetime", defaultvalue = "1400", flags = CV_NETVAR, possiblevalue = CV_Natural }) local ir_delay = CV_RegisterVar({ name = "ir_delay", defaultvalue = "13", flags = CV_NETVAR, possiblevalue = CV_Natural }) local ir_rarity = CV_RegisterVar({ name = "ir_rarity", defaultvalue = "On", flags = CV_NETVAR, possiblevalue = CV_OnOff }) local ir_startup = CV_RegisterVar({ name = "ir_startup", defaultvalue = "70", flags = CV_NETVAR, possiblevalue = CV_Natural }) local ir_pickups = CV_RegisterVar({ name = "ir_pickups", defaultvalue = "Vanilla", flags = CV_NETVAR, possiblevalue = {Off = 0, Vanilla = 1, Stack = 2} }) //turns elim on or off local ir_enabled = CV_RegisterVar({ name = "ir_enabled", defaultvalue = "On", flags = CV_NETVAR|CV_SHOWMODIF, possiblevalue = CV_OnOff}) -------------------------- -- Defining custom objects -------------------------- freeslot("MT_SINKTRAP", "S_SINKTRAP") -- yes this is intended to kill you even if you're invincible, don't drive into sinks mobjinfo[MT_SINKTRAP] = { spawnstate = S_SINKTRAP, -- spawnstate speed = 0, -- speed radius = 16*FRACUNIT, -- radius height = 24*FRACUNIT, -- height displayoffset = 0, -- display offset mass = 100, -- mass damage = 1, -- damage flags = MF_BOUNCE|MF_SHOOTABLE|MF_DONTENCOREMAP, -- flags } states[S_SINKTRAP] = { sprite = SPR_SINK, frame = 0, tics = -1, nextstate = S_SINKTRAP } ------------------------------------------------ -- Globals to let other mods mess with item rain ------------------------------------------------ rawset(_G, "itemraindefs", { -- item form, trap form, min/max stacks from rain drops, rain rarity (lower = better), min/max stacks from boxstacking, boxstack rarity (lower = better) -- modify this from your script if you want to add new presets none = {}, vanilla = { {held = KITEM_SNEAKER, trap = nil, rainmin = 1, rainmax = 3, rainchance = 1, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_ROCKETSNEAKER, trap = nil, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_INVINCIBILITY, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_BANANA, trap = MT_BANANA, rainmin = 1, rainmax = 10, rainchance = 1, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_EGGMAN, trap = MT_EGGMANITEM, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_ORBINAUT, trap = MT_ORBINAUT, rainmin = 1, rainmax = 4, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 2}, {held = KITEM_JAWZ, trap = MT_JAWZ_DUD, rainmin = 1, rainmax = 2, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 2}, {held = KITEM_MINE, trap = MT_SSMINE, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_BALLHOG, trap = MT_BALLHOG, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_SPB, trap = MT_SPB, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_GROW, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_SHRINK, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_POGOSPRING, trap = nil, rainmin = 1, rainmax = 1, rainchance = 8, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_THUNDERSHIELD, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_HYUDORO, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_KITCHENSINK, trap = nil, rainmin = 1, rainmax = 1, rainchance = 8, boxmin = 1, boxmax = 1, boxchance = 16} }, mint = { {held = KITEM_SNEAKER, trap = nil, rainmin = 1, rainmax = 3, rainchance = 1, boxmin = 1, boxmax = 3, boxchance = 1}, {held = KITEM_ROCKETSNEAKER, trap = nil, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 2}, {held = KITEM_INVINCIBILITY, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_BANANA, trap = MT_BANANA, rainmin = 1, rainmax = 10, rainchance = 1, boxmin = 1, boxmax = 10, boxchance = 1}, {held = KITEM_EGGMAN, trap = MT_EGGMANITEM, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 2}, {held = KITEM_ORBINAUT, trap = MT_ORBINAUT, rainmin = 1, rainmax = 4, rainchance = 2, boxmin = 1, boxmax = 4, boxchance = 2}, {held = KITEM_JAWZ, trap = MT_JAWZ_DUD, rainmin = 1, rainmax = 2, rainchance = 2, boxmin = 1, boxmax = 2, boxchance = 2}, {held = KITEM_MINE, trap = MT_SSMINE, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_BALLHOG, trap = MT_BALLHOG, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_SPB, trap = MT_SPB, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_GROW, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_SHRINK, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_POGOSPRING, trap = MT_YELLOWSPRING, rainmin = 1, rainmax = 1, rainchance = 8, boxmin = 1, boxmax = 1, boxchance = 8}, {held = KITEM_THUNDERSHIELD, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_HYUDORO, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_KITCHENSINK, trap = MT_SINKTRAP, rainmin = 1, rainmax = 1, rainchance = 8, boxmin = 1, boxmax = 1, boxchance = 8} }, neapolitan = { {held = KITEM_SNEAKER, trap = nil, rainmin = 3, rainmax = 3, rainchance = 1, boxmin = 3, boxmax = 3, boxchance = 1}, {held = KITEM_ROCKETSNEAKER, trap = nil, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_INVINCIBILITY, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_BANANA, trap = MT_BANANA, rainmin = 10, rainmax = 10, rainchance = 1, boxmin = 10, boxmax = 10, boxchance = 1}, {held = KITEM_EGGMAN, trap = MT_EGGMANITEM, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_ORBINAUT, trap = MT_ORBINAUT, rainmin = 4, rainmax = 4, rainchance = 2, boxmin = 4, boxmax = 4, boxchance = 1}, {held = KITEM_JAWZ, trap = MT_JAWZ_DUD, rainmin = 2, rainmax = 2, rainchance = 2, boxmin = 2, boxmax = 2, boxchance = 1}, {held = KITEM_MINE, trap = MT_SSMINE, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_BALLHOG, trap = MT_BALLHOG, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_SPB, trap = MT_SPB, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_GROW, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_SHRINK, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_POGOSPRING, trap = MT_YELLOWSPRING, rainmin = 1, rainmax = 1, rainchance = 8, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_THUNDERSHIELD, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_HYUDORO, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_KITCHENSINK, trap = MT_SINKTRAP, rainmin = 1, rainmax = 1, rainchance = 8, boxmin = 1, boxmax = 1, boxchance = 1} }, strawberry = { {held = KITEM_SNEAKER, trap = nil, rainmin = 1, rainmax = 3, rainchance = 1, boxmin = 1, boxmax = 3, boxchance = 1}, {held = KITEM_ROCKETSNEAKER, trap = nil, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 2}, {held = KITEM_INVINCIBILITY, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_GROW, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, }, chocolate = { {held = KITEM_BANANA, trap = MT_BANANA, rainmin = 1, rainmax = 10, rainchance = 1, boxmin = 1, boxmax = 10, boxchance = 1}, {held = KITEM_EGGMAN, trap = MT_EGGMANITEM, rainmin = 1, rainmax = 1, rainchance = 2, boxmin = 1, boxmax = 1, boxchance = 2}, {held = KITEM_ORBINAUT, trap = MT_ORBINAUT, rainmin = 1, rainmax = 4, rainchance = 2, boxmin = 1, boxmax = 4, boxchance = 2}, {held = KITEM_JAWZ, trap = MT_JAWZ_DUD, rainmin = 1, rainmax = 2, rainchance = 2, boxmin = 1, boxmax = 2, boxchance = 2}, {held = KITEM_MINE, trap = MT_ORBINAUT, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_BALLHOG, trap = MT_BALLHOG, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_SPB, trap = MT_SPB, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_THUNDERSHIELD, trap = nil, rainmin = 1, rainmax = 1, rainchance = 4, boxmin = 1, boxmax = 1, boxchance = 4}, {held = KITEM_KITCHENSINK, trap = nil, rainmin = 1, rainmax = 1, rainchance = 8, boxmin = 1, boxmax = 1, boxchance = 8} }, banana = { {held = KITEM_BANANA, trap = MT_BANANA, rainmin = 10, rainmax = 10, rainchance = 1, boxmin = 4, boxmax = 4, boxchance = 1} }, rockyroad = { {held = KITEM_ORBINAUT, trap = MT_BLUEFRUIT, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_ORBINAUT, trap = MT_ORANGEFRUIT, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_ORBINAUT, trap = MT_REDFRUIT, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 1, boxmax = 1, boxchance = 1}, {held = KITEM_ORBINAUT, trap = MT_PINKFRUIT, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 1, boxmax = 1, boxchance = 1} }, superman = { {held = KITEM_POGOSPRING, trap = MT_BLUESPRING, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 0, boxmax = 0, boxchance = 1}, {held = KITEM_POGOSPRING, trap = MT_YELLOWSPRING, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 0, boxmax = 0, boxchance = 1}, {held = KITEM_POGOSPRING, trap = MT_REDSPRING, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 0, boxmax = 0, boxchance = 1} }, soap = { {held = KITEM_KITCHENSINK, trap = MT_SINKTRAP, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 0, boxmax = 0, boxchance = 1} } }) rawset(_G, "itemrainadd", {}) -- or modify THIS from your script to add item definitions that are active regardless of preset. as an example of how you might add items to this table in your own mods: -- table.insert(_G.itemrainadd, {held = KITEM_SAD,trap = MT_ARIDTOAD,rainmin = 10,rainmax = 10,rainchance = 1,boxmin = 4,boxmax = 4,boxchance = 1}) ---------------------------------- -- Private functions for Item Rain ---------------------------------- local function GetRainableTable() local racers = {} -- count number of active players for player in players.iterate if not player.spectator then table.insert(racers, player) end end if #racers == 1 and not G_BattleGametype() then -- free play hack return {{held = KITEM_SNEAKER, trap = nil, rainmin = 1, rainmax = 1, rainchance = 1, boxmin = 1, boxmax = 1, boxchance = 1}} end local mergedTable = {} for k,v in pairs(_G.itemrain) do table.insert(mergedTable, v) end for k,v in pairs(_G.itemrainadd) do table.insert(mergedTable, v) end return mergedTable end local function GetFirstItemEntry(item) local tempitemrain = GetRainableTable() for key = 1, #tempitemrain do if tempitemrain[key].held == item then return tempitemrain[key] end end return {held = KITEM_NONE, trap = nil, rainmin = 0, rainmax = 0, rainchance = 1, boxmin = 0, boxmax = 0, boxchance = 1} end local function GetFirstTrapEntry(item) local tempitemrain = GetRainableTable() for key = 1, #tempitemrain do if tempitemrain[key].trap == item then return tempitemrain[key] end end return {held = KITEM_NONE, trap = nil, rainmin = 0, rainmax = 0, rainchance = 1, boxmin = 0, boxmax = 0, boxchance = 1} end local function RainAllowed() if ir_mode.value == 0 then return false end if not ir_enabled.value then return end if ir_mode.value == 1 and G_BattleGametype() then return false end if ir_mode.value == 2 and not G_BattleGametype() then return false end return true end local function SetRainableTable(input) rawset(_G, "itemrain", _G.itemraindefs[string.lower(input)]) end ----------------------------------------- -- variable declarations for Item Rain -- ----------------------------------------- SetRainableTable("vanilla") local nuked = false local rainedMobjs = {} -- track objects created by item rain ---------------------- -- console commands -- ---------------------- COM_AddCommand("ir_additem", function (player, h, t, rmin, rmax, rc, bmin, bmax, bc) if not IsPlayerAdmin(player) and player != server then CONS_Printf(player, "You think you can control the weather? Hah.") return end table.insert(_G.itemrain, {held = tonumber(h), trap = tonumber(t), rainmin = tonumber(rmin), rainmax = tonumber(rmax), rainchance = tonumber(rc), boxmin = tonumber(bmin), boxmax = tonumber(bmax), boxchance = tonumber(bc)}) end) COM_AddCommand("ir_preset", function (player, str) if not IsPlayerAdmin(player) and player != server then CONS_Printf(player, "You think you can control the weather? Hah.") return end SetRainableTable(str) end) ------------------------------------------- -- hud elements for announcing Item Rain -- ------------------------------------------- hud.add(function(weatherAlert, p, t, e) if ir_pickups.value == 1 and not RainAllowed() then return end local raintext1 = "Item rain incoming!" local raintext2 = "Watch your head!" if RainAllowed() then if (leveltime == ir_startup.value - TICRATE*3) or (leveltime == 5 and leveltime >= ir_startup.value - TICRATE*2) then S_StartSound(nil, sfx_trpowr, p) elseif (leveltime >= ir_startup.value - TICRATE*4) and (leveltime < ir_startup.value + TICRATE) then if ir_pickups.value == 0 then raintext2 = "Item boxes are allergic to rain." elseif ir_pickups.value == 2 then raintext2 = "Box stacking enabled!" end weatherAlert.drawString(160, 32, raintext1, V_YELLOWMAP, "center") weatherAlert.drawString(160 - (weatherAlert.stringWidth(raintext2, 0, "small") / 2), 40, raintext2, 0, "small") return end else if ir_pickups.value == 0 raintext1 = "No items, karts only," raintext2 = "Daytona Speedway Zone." elseif ir_pickups.value == 2 raintext1 = "Box stacking enabled!" raintext2 = "Drive into item sets while holding an item!" end if (leveltime == 5) then S_StartSound(nil, sfx_itemup, p) weatherAlert.drawString(160, 32, raintext1, V_YELLOWMAP, "center") weatherAlert.drawString(160 - (weatherAlert.stringWidth(raintext2, 0, "small") / 2), 40, raintext2, 0, "small") elseif (leveltime < TICRATE*4) then weatherAlert.drawString(160, 32, raintext1, V_YELLOWMAP, "center") weatherAlert.drawString(160 - (weatherAlert.stringWidth(raintext2, 0, "small") / 2), 40, raintext2, 0, "small") end end end, "game") ----------- -- hooks -- ----------- addHook("ThinkFrame", function() if not RainAllowed() then return end if leveltime == 0 then nuked = false end -- reset nuked between maps if not nuked and ir_pickups.value == 0 then -- server has just disabled pickups, or changed maps after doing so for mobj in thinkers.iterate("mobj") do if mobj.type == MT_RANDOMITEM then P_RemoveMobj(mobj) end end nuked = true end local racers = {} -- count number of active players, re-evaluate every tick to catch leavers/spectators for player in players.iterate if not player.spectator then table.insert(racers, player) end end local randomPlayer = racers[P_RandomRange(1, #racers)] local activeSPBs = 0 for i, v in ipairs(rainedMobjs) do -- recount the mobjs that have been created by this script, as well as active SPBs if v.valid and (v.type == MT_SPB or v.threshold == KITEM_SPB) then activeSPBs = $+1 end if not v.valid then table.remove(rainedMobjs, i) end -- clear out items that have disappeared. end if (leveltime % (ir_delay.value) == 0) and leveltime >= ir_startup.value and #rainedMobjs < ir_limit.value then -- time to spawn an item local floatOptions = {} -- For determining which items are OK to rain. local tempitemrain = GetRainableTable() for key = 1, #tempitemrain do if (tempitemrain[key].rainmax > 0) and (P_RandomChance(FRACUNIT/tempitemrain[key].rainchance)) then -- roll item rarity if (tempitemrain[key].held == KITEM_SPB or tempitemrain[key].trap == MT_SPB) and activeSPBs < ir_limit_spb.value and not G_BattleGametype() then -- this town is exactly big enough for the two of you table.insert(floatOptions, tempitemrain[key]) elseif (tempitemrain[key].held == KITEM_SPB or tempitemrain[key].trap == MT_SPB) then -- to the shadow realm with you else -- everything else table.insert(floatOptions, tempitemrain[key]) end end end if floatOptions != nil and #floatOptions > 0 then -- At least one item option, at least one player. local rainResult = floatOptions[P_RandomRange(1, #floatOptions)] local rainStack = rainResult.held local rainState = MT_FLOATINGITEM if (ir_traps.value or rainResult.held == KITEM_NONE) and rainResult.trap != nil then rainState = rainResult.trap end -- Transform items into their active versions when appropriate. local ipos = {x = randomPlayer.mo.x + P_SignedRandom()*P_RandomRange(20,40)*FRACUNIT, -- Item spawn has a random horizontal offset. y = randomPlayer.mo.y + P_SignedRandom()*P_RandomRange(20,40)*FRACUNIT, z = randomPlayer.mo.z + randomPlayer.mo.scale*1024} if G_BattleGametype() or rainState == MT_SPB then -- Battle maps can be a lot smaller, items are super important there, and we want SPBs reasonably close to the race. ipos.x = randomPlayer.mo.x + P_SignedRandom()*P_RandomRange(5,10)*FRACUNIT ipos.y = randomPlayer.mo.y + P_SignedRandom()*P_RandomRange(5,10)*FRACUNIT end local newItem = P_SpawnMobj(ipos.x, ipos.y, ipos.z, rainState) if not (ir_traps.value and newItem.type == MT_SPB) then newItem.fuse = ir_lifetime.value -- Items disappear after a while to cycle out ones that may be in bad spots, but not if they're active SPBs. end if newItem.type == MT_FLOATINGITEM then -- Making floating items behave normally. newItem.threshold = rainResult.held newItem.destscale = 3*newItem.destscale/2 newItem.flags = $|MF_NOCLIPTHING newItem.movecount = P_RandomRange(rainResult.rainmin, rainResult.rainmax) end newItem.angle = FRACUNIT*P_RandomRange(1, 360) table.insert(rainedMobjs, newItem) -- Shove the new item into the rainedMobjs table for the purpose of counting it later. end end end) addHook("MobjThinker", function(pmo) if not pmo.player.itemstacktimer then pmo.player.itemstacktimer = 0 end if pmo.player.itemstacktimer > 0 then pmo.player.itemstacktimer = pmo.player.itemstacktimer - 1 end end, MT_PLAYER) addHook("MobjMoveCollide", function(pmo, box) if box and box.valid and box.type == MT_SINKTRAP and pmo.z + pmo.height*2 >= box.z and pmo.z <= box.z + box.height and box.health then -- test collision vs. sink traps S_StartSound(pmo, sfx_gloop) S_StartSound(NULL, sfx_lose, pmo.player) P_DamageMobj(pmo, box, box, 10000) P_KillMobj(box, pmo, pmo) return end if ir_pickups.value < 2 then return end if box and box.valid and box.type == MT_RANDOMITEM and pmo.z + pmo.height*2 >= box.z and pmo.z <= box.z + box.height and box.health then -- test collision vs. item boxes local temptype = pmo.player.kartstuff[k_itemtype] local tempcount = pmo.player.kartstuff[k_itemamount] local tempstackentry = GetFirstItemEntry(temptype) if temptype != KITEM_NONE and pmo.player.itemstacktimer == 0 and tempstackentry.boxmax > 0 then P_KillMobj(box, pmo, pmo) -- have to do this to get the box to respawn if box and box.valid -- hack for single-player box.fuse = CV_FindVar("respawnitemtime").value*TICRATE + 2 end pmo.player.itemstacktimer = CV_FindVar("respawnitemtime").value*TICRATE + 2 pmo.player.kartstuff[k_itemroulette] = 0 if not P_RandomChance(FRACUNIT/tempstackentry.boxchance) then return false end pmo.player.kartstuff[k_itemamount] = min(tempcount + P_RandomRange(tempstackentry.boxmin, tempstackentry.boxmax), 255) S_StartSound(NULL, sfx_itemup, pmo.player) return false end end end, MT_PLAYER) addHook("NetVars", function(net) rawset(_G, "itemraindefs", net(_G.itemraindefs)) rawset(_G, "itemrainadd", net(_G.itemrainadd)) rawset(_G, "itemrain", net(_G.itemrain)) end)