// Totally terrible emerald stage switch tactic /*function A_EmeraldCheck(actor,var1,var2) local emeraldType = mapheaderinfo[gamemap].badzemerald //If this is an emerald stage, replace this with the emerald you want. //Otherwise, set it to nil and it'll be a non-functional wireframe replacement. if emeraldType != nil A_SpawnObjectRelative(actor,0,emeraldType) P_KillMobj(actor) end end*/ local won = false // Salt: Actually, let me do something different so I can force people out of the level without giving them an emblem via sugoi.FailLevel() freeslot("MT_REPLACEMENTEMERALD") local function emeraldLookalike(mo) if (mapheaderinfo[gamemap].badzemerald) mo.frame = (states[mobjinfo[_G[mapheaderinfo[gamemap].badzemerald]].spawnstate].frame)|FF_FULLBRIGHT end end local function gibeEmerald(mo, pmo) if not (pmo.player and pmo.player.valid) return end if (mapheaderinfo[gamemap].badzemerald) P_SpawnMobj(pmo.x, pmo.y, pmo.z, _G[mapheaderinfo[gamemap].badzemerald]) end won = true for player in players.iterate P_DoPlayerExit(player) end end local function exitThink() if not (mapheaderinfo[gamemap].badzss) return end local allexiting = true for player in players.iterate if not (player and player.valid) continue end if (player.bot) continue end if not (player.exiting) allexiting = false end end if not (allexiting) return end if not (won) sugoi.FailLevel() if (modeattacking) // Salt: kill RA replays for player in players.iterate if (player.mo and player.mo.valid) player.exiting = 0 P_DamageMobj(player.mo, nil, nil, 10000) end end end end end local function loadGarbage() // Salt again: aaaaaaaaa i forgot thisss won = false end local function netGarbage(net) won = net(won) end addHook("MobjSpawn", emeraldLookalike, MT_REPLACEMENTEMERALD) addHook("TouchSpecial", gibeEmerald, MT_REPLACEMENTEMERALD) addHook("ThinkFrame", exitThink) addHook("MapChange", loadGarbage) addHook("NetVars", netGarbage) // ------------------- The glider -------------------- freeslot("MT_GREENGLIDER", "MT_BOOSTSMOKE") local function GliderCatch (glider, collider) if collider.player and (collider.player.bot == 0) if collider.airglider return true end collider.airglider = glider glider.gliderhelpdisplaytime = 0 glider.target = collider glider.draintimer = 0 glider.boost = 0 glider.exploded = false glider.state = glider.info.seestate A_SpawnObjectRelative(glider,0,MT_GREENGLIDER) //This is hilariously stupid, but guess what? I don't care. return true end end local function GliderFly(actor) local owner = actor.target if owner != nil if owner.valid and owner.health > 1 and not owner.player.exiting and not actor.exploded actor.gliderhelpdisplaytime = $1 + 1 if (owner.player.cmd.forwardmove > 0) actor.momz = $1 + FRACUNIT/2 end if (owner.player.cmd.forwardmove < 0) actor.momz = $1 - FRACUNIT/2 end actor.momz = FixedDiv($1,FRACUNIT+FRACUNIT/40) actor.angle = owner.angle A_Thrust(owner.airglider, owner.airglider.info.speed + actor.boost/FRACUNIT, 1) owner.momx = actor.momx owner.momy = actor.momy owner.momz = actor.momz owner.state = S_PLAY_CARRY owner.player.panim = PA_FALL A_CapeChase(actor, 44*FRACUNIT, -3) if(owner.player.cmd.buttons & BT_JUMP) actor.boost = 6*FRACUNIT if(leveltime % 3 == 0) A_GliderFX(actor,MT_BOOSTSMOKE,24) end else actor.boost = max(0,$1-FRACUNIT/5) end actor.draintimer = $1 + 1 if(actor.draintimer >= actor.info.raisestate) actor.draintimer = 0 owner.health = max(1, $1 - actor.info.mass) owner.player.health = owner.health A_GliderFX(actor,MT_SPARK,32) end else if not actor.exploded P_KillMobj(actor) actor.exploded = true owner.airglider = nil if not owner.player.exiting A_PlaySound(owner,sfx_s3kb2,1) P_DoPlayerExit(owner.player) end end end end end addHook("TouchSpecial", GliderCatch, MT_GREENGLIDER) addHook("MobjThinker", GliderFly, MT_GREENGLIDER) local function PressJumpToAccelerate(v,pl) if(mapheaderinfo[gamemap].badzss) and (pl.mo and pl.mo.valid) and (pl.mo.airglider and pl.mo.airglider.valid) and (pl.mo.airglider.gliderhelpdisplaytime != nil) and (pl.mo.airglider.gliderhelpdisplaytime < 80) v.drawString(150,60,"Hold \130JUMP\128 to accelerate!",V_30TRANS|V_ALLOWLOWERCASE,"center") end end hud.add(PressJumpToAccelerate,"game") function A_GliderFX(actor,var1,var2) local dist = (sin(actor.angle+ANGLE_90)*var2)/FRACUNIT + ((cos(actor.angle+ANGLE_90)*var2)/FRACUNIT)*FRACUNIT //oh my god this is a terrible way to handle this A_SpawnObjectRelative(actor,dist,var1+12*FRACUNIT) A_SpawnObjectRelative(actor,-dist,var1+12*FRACUNIT) end // ------------------- The mines -------------------- freeslot("MT_TDMINE", "MT_HSPINMINE", "MT_VSPINMINE", "MT_FATMINE", "MT_MINIMINE") local function MineBlaster (mine, exploded) if exploded.player if(exploded.health > 10 and not exploded.player.powers[pw_flashing] and not exploded.player.powers[pw_invulnerability]) P_DoPlayerPain(exploded.player,mine,mine) exploded.health = $1 - 10 exploded.player.health = exploded.health A_PlaySound(exploded,sfx_s3kb9,1) P_PlayerRingBurst(exploded.player,10) else P_DamageMobj(exploded,mine,mine) end else P_DamageMobj(exploded,mine,mine) end P_KillMobj (mine) end addHook("TouchSpecial", MineBlaster, MT_TDMINE) addHook("TouchSpecial", MineBlaster, MT_HSPINMINE) addHook("TouchSpecial", MineBlaster, MT_VSPINMINE) addHook("TouchSpecial", MineBlaster, MT_FATMINE) addHook("TouchSpecial", MineBlaster, MT_MINIMINE) function A_ClearTarget (actor, var1, var2) actor.target = nil end // -------------------- The giant ring -------------------- freeslot("MT_RINGRING") addHook("MobjSpawn",function(mobj) mobj.fxPos = 0 end,MT_RINGRING) function A_RingRingFX(actor,var1,var2) actor.fxPos = $1 + ANG20 local position = (sin(actor.fxPos)*96)/FRACUNIT local dist = (sin(actor.angle+ANGLE_90)*position)/FRACUNIT + ((cos(actor.angle+ANGLE_90)*position)/FRACUNIT)*FRACUNIT //oh my god this is a really terrible way to handle this local height = (cos(actor.fxPos)*96)/FRACUNIT A_SpawnObjectRelative(actor,dist,var1+(height+96)*FRACUNIT) A_SpawnObjectRelative(actor,-dist,var1-(height-96)*FRACUNIT) end function A_GlobalRingBox(actor,var1,var2) for player in players.iterate if (player.bot == 0) actor.target = player.mo A_RingBox(actor,var1,var2) end end end // ------------------- The sparkly crystal things -------------------- //Directly copied from the original thokker version of this map, which is why they're in lua-SOC instead of normal SOC. function A_SpawnRandom(actor, var1, var2) A_SpawnObjectRelative(actor,((P_RandomRange(-var2,var2)*FRACUNIT)+P_RandomRange(-var2,var2)),(P_RandomRange(0,var2)*FRACUNIT)+var1) end freeslot("MT_SPARKLECRYSTALR","MT_SPARKLECRYSTALB","MT_SPARKLERED","MT_SPARKLEBLUE","S_SPARKLECRYSTALR","S_SPARKLECRYSTALB","S_SPARKLYRED","S_SPARKLYBLUE") mobjinfo[MT_SPARKLECRYSTALR] = { doomednum = 2160, spawnstate = S_SPARKLECRYSTALR, spawnhealth = 1, radius = 8*FRACUNIT, height = 16*FRACUNIT, flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY } mobjinfo[MT_SPARKLECRYSTALB] = { doomednum = 2161, spawnstate = S_SPARKLECRYSTALB, spawnhealth = 1, radius = 8*FRACUNIT, height = 16*FRACUNIT, flags = MF_NOBLOCKMAP|MF_NOCLIP|MF_SCENERY } mobjinfo[MT_SPARKLERED] = { spawnstate = S_SPARKLYRED, spawnhealth = 1, height = 1, radius = 1, flags = MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY } mobjinfo[MT_SPARKLEBLUE] = { spawnstate = S_SPARKLYBLUE, spawnhealth = 1, height = 1, radius = 1, flags = MF_NOCLIPHEIGHT|MF_NOGRAVITY|MF_SCENERY } states[S_SPARKLECRYSTALR] = { sprite = SPR_BCRY, frame = TR_TRANS30|FF_FULLBRIGHT|A, tics = 20, action = A_SpawnRandom, var1 = MT_SPARKLERED, var2 = 28, nextstate = S_SPARKLECRYSTALR } states[S_SPARKLECRYSTALB] = { sprite = SPR_BCRY, frame = A|FF_FULLBRIGHT|TR_TRANS30, tics = 20, action = A_SpawnRandom, var1 = MT_SPARKLEBLUE, var2 = 28, nextstate = S_SPARKLECRYSTALB } states[S_SPARKLYBLUE] = { sprite = SPR_NSPK, frame = A, tics = 4, nextstate = S_NIGHTSPARKLE2 } states[S_SPARKLYRED] = { sprite = SPR_NSPK, frame = E, tics = 4, nextstate = S_NIGHTSPARKLESUPER2 }