PWADà~/* Ceiling Run version 1.1.0 by Lach modified by Kaldrum A modification of Lach's ArcadePhysics ceiling running script from Chrispy's Arcade. Should allow for implementation of loops. Requires landing on a slope to start ceiling running, and depending on player orientation when entering a slope will flip movement when upside down. Wouldn't recommend using flipcam with this active. */ if CeilingRun return end rawset(_G, "CeilingRun", true) local CEILING_SPEED_THRESHOLD = 16*FRACUNIT local function FixedSquare(n) return FixedMul(n, n) end //Will swap the current gravity state, allowing for ceiling running in existing reverse gravity. local function FlipGravity(mo) mo.flags2 = $ ^^ MF2_OBJECTFLIP mo.eflags = $ ^^ MFE_VERTICALFLIP end //Cool slope math (that I don't understand) local function FV3_Rotate(rotVecX, rotVecY, rotVecZ, axisVecX, axisVecY, axisVecZ, angle) local ux, uy, uz = FixedMul(axisVecX, rotVecX), FixedMul(axisVecX, rotVecY), FixedMul(axisVecX, rotVecZ) local vx, vy, vz = FixedMul(axisVecY, rotVecX), FixedMul(axisVecY, rotVecY), FixedMul(axisVecY, rotVecZ) local wx, wy, wz = FixedMul(axisVecZ, rotVecX), FixedMul(axisVecZ, rotVecY), FixedMul(axisVecZ, rotVecZ) local sa, ca = sin(angle), cos(angle) local ua = ux + vy + wz local ax, ay, az = FixedMul(axisVecX, ua), FixedMul(axisVecY, ua), FixedMul(axisVecZ, ua) local xs, ys, zs = FixedSquare(axisVecX), FixedSquare(axisVecY), FixedSquare(axisVecZ) local bx, by, bz = FixedMul(rotVecX, ys + zs), FixedMul(rotVecY, xs + zs), FixedMul(rotVecZ, xs + ys) local cx, cy, cz = FixedMul(axisVecX, vy + wz), FixedMul(axisVecY, ux + wz), FixedMul(axisVecZ, ux + vy) local dx, dy, dz = FixedMul(bx - cx, ca), FixedMul(by - cy, ca), FixedMul(bz - cz, ca) local ex, ey, ez = FixedMul(vz - wy, sa), FixedMul(wx - uz, sa), FixedMul(uy - vx, sa) return ax + dx + ex, ay + dy + ey, az + dz + ez end local function GetSlopeLandingMomentum(mo, slope) if not slope or slope.flags & SL_NOPHYSICS or slope.zangle == 0 return mo.momx, mo.momy end return FV3_Rotate(mo.momx, mo.momy, 2 * mo.momz, -slope.d.y, slope.d.x, 0, InvAngle(slope.zangle)) end //Gets the slope of the floor above the player. local function GetFloorSlope(mo) if not (mo.eflags & MFE_VERTICALFLIP) == not true local fof = mo.floorrover if fof return fof.t_slope end return mo.subsector.sector.f_slope else local fof = mo.ceilingrover if fof return fof.b_slope end return mo.subsector.sector.c_slope end end //Determines if the object will touch the floor based on their height and momentum local function MobjWillTouchFloor(mo) if not (mo.eflags & MFE_VERTICALFLIP) == not true return mo.z + mo.momz < mo.floorz else return mo.z + mo.height + mo.momz > mo.ceilingz end end local function P_QuantizeMomentumToSlope(vx, vy, vz, slope, slopeangle) local ax = 0 local ay = 0 local az = 0 if (slope.flags & SL_NOPHYSICS) return end ax = -slope.d.y ay = slope.d.x az = 0 return FV3_Rotate(vx, vy, vz, ax, ay, az, slopeangle) end local function P_ShouldResetConveyorMomentum(player) if player.onconveyor == 1 return false elseif player.onconveyor == 2 return not(player.mo.eflags & (MFE_UNDERWATER|MFE_TOUCHWATER)) elseif player.onconveyor == 3 return true elseif player.onconveyor == 4 return not P_IsObjectOnGround(player.mo) else return true end end //undoes the slope physics local function P_ReverseButteredSlope(mo, momx, momy) local thrust = 0 if not mo.standingslope return end if mo.standingslope.flags & SL_NOPHYSICS return end if mo.flags & (MF_NOCLIPHEIGHT|MF_NOGRAVITY) return end if mo.player if (abs(mo.standingslope.zdelta) < FRACUNIT/4 and not(mo.player.pflags & PF_SPINNING)) return end if (abs(mo.standingslope.zdelta) < FRACUNIT/2 and not(mo.player.rmomx or mo.player.rmomy)) return end end thrust = sin(mo.standingslope.zangle) * 3/2 * -P_MobjFlip(mo) if mo.player and (mo.player.pflags & PF_SPINNING) local mult = 0 if momx or momy local angle = R_PointToAngle2(0,0,momx, momy) - mo.standingslope.xydirection if (P_MobjFlip(mo) * mo.standingslope.zdelta < 0) angle = $+ANGLE_180 end mult = cos(angle) end thrust = FixedMul(thrust, FRACUNIT*2/3 + mult/8) end if momx or momy thrust = FixedMul(thrust, FRACUNIT + P_AproxDistance(momx, momy)/16) end thrust = FixedMul(thrust, abs(P_GetMobjGravity(mo))) thrust = FixedMul(thrust, FixedDiv(mo.friction, 29*FRACUNIT/32)) P_Thrust(mo, mo.standingslope.xydirection, -2 * thrust) end //slightly modified movement code local function P_3dMovement(player, momx, momy) local movepushangle, movepushsideangle = 0, 0 local topspeed, acceleration, thrustfactor = 0, 0, 0 local movepushforward, movepushside = 0, 0 local mforward, mbackward = 0, 0 local dangle = 0 local normalspeed = FixedMul(player.normalspeed, player.mo.scale) local spin = (P_IsObjectOnGround(player.mo) and (player.pflags & (PF_SPINNING|PF_THOKKED)) == PF_SPINNING and (player.rmomx or player.rmomy) and not(player.pflags & PF_STARTDASH)) local oldmagnitude, newmagnitude = 0, 0 local totalthrustx, totalthrusty, totalthrustz = 0, 0, 0 local momx, momy = player.mo.momx, player.mo.momy local cmomx, cmomy = player.cmomx, player.cmomy local rmomx, rmomy = 0, 0 local speed = 0 local aiming = 0 totalthrustz = FRACUNIT*P_MobjFlip(player.mo)/3 oldmagnitude = R_PointToDist2(momx - cmomx, momy - cmomy, 0, 0) if player.pflags & PF_ANALOGMODE movepushangle = player.cmd.angleturn << 16 else movepushangle = player.mo.angle end movepushsideangle = movepushangle - ANGLE_90 if P_ShouldResetConveyorMomentum(player) cmomx = 0 cmomy = 0 end rmomx = momx - cmomx rmomy = momy - cmomy speed = P_AproxDistance(rmomx, rmomy) dangle = R_PointToAngle2(0, 0, player.rmomx, player.rmomy) - player.mo.angle if dangle > ANGLE_180 dangle = InvAngle(dangle) end if dangle <= ANGLE_45 mforward = 1 elseif dangle >= ANGLE_135 mbackward = 1 end if player.pflags & PF_SLIDING player.cmd.forwardmove = 0 elseif P_IsObjectOnGround(player.mo) and player.mo.state == S_PLAY_PAIN player.mo.state = S_PLAY_WALK end aiming = player.cmd.aiming << 16 if player.pflags & PF_SLIDING normalspeed = FixedMul(36<<16, player.mo.scale) thrustfactor = 5 acceleration = 96 + (FixedDiv(speed, player.mo.scale)>>16) * 40 topspeed = normalspeed else if player.powers[pw_super] or player.powers[pw_sneakers] topspeed = 5 * normalspeed/3 thrustfactor = player.thrustfactor * 2 acceleration = player.accelstart/2 + (FixedDiv(speed, player.mo.scale)>>16) * player.acceleration/2 else topspeed = normalspeed thrustfactor = player.thrustfactor acceleration = player.accelstart + (FixedDiv(speed, player.mo.scale)>>16) * player.acceleration end if player.powers[pw_tailsfly] topspeed = $>>1 elseif player.mo.eflags & (MFE_UNDERWATER|MFE_GOOWATER) topspeed = $>>1 acceleration = 2*acceleration/3 end end if spin local ns = FixedDiv(549*29*FRACUNIT/32, 500* FRACUNIT) topspeed = FixedMul(oldmagnitude, ns) end if not player.powers[pw_tailsfly] if player.pflags & PF_BOUNCING if player.mo.state == S_PLAY_BOUNCE_LANDING thrustfactor = player.thrustfactor * 8 acceleration = player.accelstart/8 + (FixedDiv(speed, player.mo.scale)>>16) * player.acceleration/8 else thrustfactor = (3*player.thrustfactor)/4 acceleration = player.accelstart + (FixedDiv(speed, player. mo.scale)>>16) * player.acceleration end end if player.mo.movefactor ~= FRACUNIT acceleration = FixedMul(acceleration<<16, player.mo.movefactor)>>16 end end if player.climbing elseif not (player.pflags & PF_ANALOGMODE) and player.cmd.forwardmove ~= 0 and not(player.pflags & PF_GLIDING or player.exiting or P_PlayerInPain(player) and not P_IsObjectOnGround(player.mo)) movepushforward = player.cmd.forwardmove * (thrustfactor * acceleration) if (player.pflags & (PF_SPINNING|PF_THOKKED)) == PF_SPINNING if (mforward and player.cmd.forwardmove > 0) or (mbackward and player.cmd.forwardmove < 0) or (player.pflags & PF_STARTDASH) movepushforward = 0 elseif P_IsObjectOnGround(player.mo) movepushforward = $ / 16 else movepushforward = $ /8 end elseif not P_IsObjectOnGround(player.mo) movepushforward = $ / 4 end movepushforward = FixedMul(movepushforward, player.mo.scale) totalthrustx = $ + P_ReturnThrustX(player.mo, movepushangle, movepushforward) totalthrusty = $ + P_ReturnThrustY(player.mo, movepushangle, movepushforward) end if player.climbing elseif (player.pflags & PF_ANALOGMODE) if not(player.pflags & PF_GLIDING or player.exiting or P_PlayerInPain(player)) local controldirection = R_PointToAngle2(0, 0, player.cmd.forwardmove * FRACUNIT, -player.cmd.sidemove * FRACUNIT) + movepushangle movepushforward = FixedHypot(player.cmd.sidemove, player.cmd.forwardmove) * (thrustfactor * acceleration) if (player.pflags & (PF_SPINNING|PF_THOKKED)) == PF_SPINNING if (mforward and player.cmd.forwardmove > 0) or (mbackward and player.cmd.forwardmove < 0) or (player.pflags & PF_STARTDASH) movepushforward = 0 elseif P_IsObjectOnGround(player.mo) movepushforward = $ >> 4 else movepushforward = $ >> 3 end elseif not P_IsObjectOnGround(player.mo) movepushforward = $ >> 2 end movepushsideangle = controldirection movepushforward = FixedMul(movepushforward, player.mo.scale) totalthrustx = $ + P_ReturnThrustX(player.mo, controldirection, movepushforward) totalthrusty = $ + P_ReturnThrustY(player.mo, controldirection, movepushforward) end elseif player.cmd.sidemove and not (player.pflags & PF_GLIDING) and not player.exiting and not P_PlayerInPain(player) movepushside = player.cmd.sidemove * (thrustfactor * acceleration) if not P_IsObjectOnGround(player.mo) movepushside = $ / 4 if ((player.pflags & (PF_SPINNING|PF_THOKKED)) == PF_SPINNING) or (player.powers[pw_tailsfly] and speed > topspeed) movepushside = $ / 4 end elseif (player.pflags & (PF_SPINNING|PF_THOKKED)) == PF_SPINNING if player.pflags & PF_STARTDASH movepushside = 0 elseif P_IsObjectOnGround(player.mo) movepushside = $ / 16 else movepushside = $ / 8 end end movepushside = FixedMul(movepushside, player.mo.scale) totalthrustx = $ + P_ReturnThrustX(player.mo, movepushsideangle, movepushside) totalthrusty = $ + P_ReturnThrustY(player.mo, movepushsideangle, movepushside) end if (totalthrustx or totalthrusty) and player.mo.standingslope and (not(player.mo.standingslope.flags & SL_NOPHYSICS)) and abs(player.mo.standingslope.zdelta) > FRACUNIT/2 local thrustangle = R_PointToAngle2(0, 0, totalthrustx, totalthrusty)-player.mo.standingslope.xydirection //this is different in order to reduce movement on downwards slopes instead of on upwards ones as it would normally do if player.mo.standingslope.zdelta > 0 if (thrustangle < ANGLE_90) or (thrustangle > ANGLE_270) local momentum = {P_QuantizeMomentumToSlope(totalthrustx, totalthrusty, totalthrustz, player.mo.standingslope, player.mo.standingslope.zangle)} totalthrustx = momentum[1] totalthrusty = momentum[2] end else if (thrustangle > ANGLE_90) and (thrustangle < ANGLE_270) local momentum = {P_QuantizeMomentumToSlope(totalthrustx, totalthrusty, totalthrustz, player.mo.standingslope, player.mo.standingslope.zangle)} totalthrustx = momentum[1] totalthrusty = momentum[2] end end end if totalthrustx or totalthrusty momx = $ + totalthrustx momy = $ + totalthrusty else return nil end newmagnitude = R_PointToDist2(momx - cmomx, momy - cmomy, 0, 0) if newmagnitude > topspeed local tempmomx, tempmomy = 0, 0 if (oldmagnitude > topspeed) and (not spin) if newmagnitude > oldmagnitude tempmomx = FixedMul(FixedDiv(momx - cmomx, newmagnitude), oldmagnitude) tempmomy = FixedMul(FixedDiv(momy - cmomy, newmagnitude), oldmagnitude) momx = tempmomx + cmomx momy = tempmomy + cmomy end else tempmomx = FixedMul(FixedDiv(momx - cmomx, newmagnitude), topspeed) tempmomy = FixedMul(FixedDiv(momy - cmomy, newmagnitude), topspeed) momx = tempmomx + cmomx momy = tempmomy + cmomy end end return momx, momy, rmomx, rmomy, cmomx, cmomy, speed end //Sets variables relating to modified movement physics local function Set3DMoveVars(player) local movevars = {P_3dMovement(player)} if movevars[1] ~= nil player.nmomx = movevars[1] player.nmomy = movevars[2] player.nrmomx = movevars[3] player.nrmomy = movevars[4] player.ncmomx = movevars[5] player.ncmomy = movevars[6] player.nspeed = movevars[7] else player.nmomx = nil player.nmomy = nil player.nrmomx = nil player.nrmomy = nil player.ncmomx = nil player.ncmomy = nil player.nspeed = nil end end addHook("PreThinkFrame", function() for player in players.iterate do local mo = player.mo if not mo continue end if player.inputFlip == true if not(twodlevel or mo.flags2 & MF2_TWOD) player.cmd.forwardmove = -$ else player.cmd.sidemove = -$ end end if player.ceilingRun and not(twodlevel or mo.flags2 & MF2_TWOD) Set3DMoveVars(player) end //Cannot run on the ceiling if clipping through ceilings or floors, or carrying something. if (mo.flags & MF_NOCLIPHEIGHT)or (player.powers[pw_carry] ~= CR_NONE) if player.ceilingRun FlipGravity(mo) player.ceilingRun = false end continue end if P_IsObjectOnGround(mo) if not player.ceilingRun continue end if FixedHypot(mo.momx - player.cmomx , mo.momy - player.cmomy) < FixedMul(10*FRACUNIT, mo.scale) FlipGravity(mo) player.ceilingRun = false end continue end //Flips gravity if the player will touch a slope with enough momentum. Reverses forward and backward input if the player is flipped around by the slope. if MobjWillTouchFloor(mo) local speed = FixedHypot(GetSlopeLandingMomentum(mo, GetFloorSlope(mo))) local threshold = FixedMul(CEILING_SPEED_THRESHOLD, mo.scale) local slope = GetFloorSlope(mo) if not ((slope==nil) or (slope.flags & SL_NOPHYSICS) or (slope.zangle == 0)) if (abs(slope.xydirection - mo.player.drawangle) < ANG30) player.inputFlip = true end if speed >= threshold FlipGravity(mo) player.ceilingRun = true if not (twodlevel or mo.flags2 & MF2_TWOD) Set3DMoveVars(player) end end if player.inputFlip and player.ceilingRun if not(twodlevel or mo.flags2 & MF2_TWOD) player.cmd.forwardmove = -$ else player.cmd.sidemove = -$ end end end elseif player.ceilingRun player.falltimer = $+1 if (player.pflags & PF_JUMPED) or (mo.state == S_PLAY_ROLL) player.falltimer = 2 if mo.state == S_PLAY_ROLL if mo.eflags & MFE_VERTICALFLIP and not (twodlevel or mo.flags2 & MF2_TWOD) mo.momz = $ * 9/4//z-momentum boost when leaving a wall from rolling to compensate for weird slope transfer when upside down else mo.momz = $ * 3/2 //slope launch physics work a lot better when leaving the floor, if your ceilingrun state //is floor running (reverse sector/global gravity), multiply by less to avoid weird momentum glitches end end end if player.falltimer == 2 if player.powers[pw_justlaunched] == 2 P_Thrust(mo, player.drawangle, FRACUNIT) end FlipGravity(mo) player.ceilingRun = false end end if not player.ceilingRun player.inputFlip = false player.falltimer = 0 end end end) //applies modified movement physics while in ceilingrun state addHook("PlayerThink", function(player) local mo = player.mo if player.nmomx ~= nil and player.ceilingRun == true mo.momx = player.nmomx mo.momy = player.nmomy player.rmomx = player.nrmomx player.rmomy = player.nrmomy player.cmomx = player.ncmomx player.cmomy = player.ncmomy player.speed = player.nspeed end end) addHook("ThinkFrame", function() for player in players.iterate do if player.ceilingRun == true //changes slope physics if in ceilingrun state so upside down downward slopes have an upwards slope effect and vice versa P_ReverseButteredSlope(player.mo, player.nmomx, player.nmomy) end end end)/* Wall Run version 1.1.0 by Kaldrum This script adds wall running functionality when a player leaves a halfpipe, giving them either a wallrunning or wallrolling state. When in either state, the player can walljump to gain a burst of horizontal momentum away from the wall, and can use their ability following this jump. In the running state, the player is able to freely run on the wall, with inputs down increasing downwards momentum and inputs upwards partially counteracting gravity, allowing for extended time on the wall. The player is able to transition into their wallrolling state at any time as long as they are currently touching the wall. */ if WallRun return end rawset(_G, "WallRun", true) freeslot( "S_PLAY_WALLRUN", "S_PLAY_WALLROLL" ) local DASHMODE_THRESHOLD = TICRATE * 3 local DASHMODE_MAX = TICRATE * 3 + 3 local multiwallrun = false //Needs different animations than default ones. states[S_PLAY_WALLRUN] = { sprite = SPR_PLAY, frame = SPR2_RUN, tics = 3, nextstate = S_PLAY_RUN } states[S_PLAY_WALLROLL] = { sprite = SPR_PLAY, frame = SPR2_ROLL, tics = 3, nextstate = S_PLAY_ROLL } //Obtains the object's angle required to face directly towards a wall. Accounts for both front and back sidedefs. local function GetWallAngle(mo, line) local mobjAngle = R_PointToAngle2(line.v1.x, line.v1.y , line.v2.x, line.v2.y) if(#line.frontsector == #mo.subsector.sector) mobjAngle = $ + ANGLE_90 mo.lineside = 0 elseif (line.backsector ~= nil) and (#line.backsector == #mo.subsector.sector) mobjAngle = $ - ANGLE_90 mo.lineside = 1 else //just in case mobjAngle = $ + ANGLE_90 mo.lineside = 0 end return mobjAngle end //source code but wallrun also allows a jetfume to appear. slightly offset when rollangle makes the player face upside down local function P_DoMetalJetFume(player, fume) local FUME_SKINCOLORS = { SKINCOLOR_ICY, SKINCOLOR_SKY, SKINCOLOR_CYAN, SKINCOLOR_WAVE, SKINCOLOR_TEAL, SKINCOLOR_AQUA, SKINCOLOR_SEAFOAM, SKINCOLOR_MINT, SKINCOLOR_PERIDOT, SKINCOLOR_LIME, SKINCOLOR_YELLOW, SKINCOLOR_SANDY, SKINCOLOR_GOLD, SKINCOLOR_APRICOT, SKINCOLOR_SUNSET } local mo = player.mo local angle = player.drawangle local rollangle = mo.rollangle local dist = 0 local heightoffset = 0 if (mo.eflags & MFE_VERTICALFLIP) heightoffset = mo.height - (P_GetPlayerHeight(player)>>1) else heightoffset = (P_GetPlayerHeight(player)>>1) end local dashmode = min(player.dashmode, DASHMODE_MAX) local underwater = mo.eflags & MFE_UNDERWATER if (mo.state ~= S_PLAY_WALLRUN and player.panim ~= PA_WALK and player.panim ~= PA_RUN and player.panim ~= PA_DASH) if fume.state ~= fume.info.spawnstate fume.state = fume.info.spawnstate end return end if underwater fume.movedir = $ + FixedAngle(FixedDiv(2*player.speed, 3 * mo.scale)) fume.movefactor = $ + player.speed if fume.movefactor > FixedDiv(2*player.normalspeed, 3 *mo.scale) local i = 0 local radiusv = 4*FRACUNIT local radiusx = P_ReturnThrustX(mo, angle, -mo.radius) local radiusy = P_ReturnThrustY(mo, angle, -mo.radius) local factorx = P_ReturnThrustX(mo, angle + ANGLE_90, mo.scale) local factory = P_ReturnThrustY(mo, angle + ANGLE_90, mo.scale) local offseth = 0 local offsetv = 0 local x = 0 local y = 0 local z = 0 for i = -1, 1, 2 do offseth = i*P_ReturnThrustX(fume, fume.movedir, radiusv) offsetv = i*P_ReturnThrustY(fume, fume.movedir, radiusv) x = mo.x + radiusx + FixedMul(offseth, factorx) y = mo.y + radiusy + FixedMul(offseth, factory) z = mo.z + heightoffset + offsetv P_SpawnMobj(x, y, z, MT_SMALLBUBBLE).scale = mo.scale>>1 end fume.movefactor = 0 end if player.panim == PA_WALK if fume.state ~= fume.info.spawnstate fume.threshold = 0 fume.state = fume.info.spawnstate end return end end if(fume.state == fume.info.spawnstate) fume.state = fume.info.seestate end if (dashmode > DASHMODE_THRESHOLD) and (fume.state ~= fume.info.seestate) fume.destscale = mo.scale fume.flags2 = $ & ~ MF2_DONTDRAW fume.flags2 = $ | (mo.flags2 & MF2_DONTDRAW) else if dashmode == DASHMODE_THRESHOLD and dashmode > fume.movecount fume.state = fume.info.seestate P_SetScale(fume, mo.scale << 1) end fume.flags2 = (fume.flags2 & ~ MF2_DONTDRAW) | (mo.flags2 & MF2_DONTDRAW) fume.destscale = mo.scale + FixedDiv(player.speed, player.normalspeed) if underwater fume.destscale = $/6 else fume.destscale = $/3 end fume.color = FUME_SKINCOLORS[(dashmode * table.maxn(FUME_SKINCOLORS) / (DASHMODE_MAX + 1))+1] if underwater fume.frame = fume.frame & FF_FRAMEMASK | FF_ANIMATE | (P_RandomRange(0,9) * FF_TRANS10) fume.threshold = 1 elseif fume.threshold fume.frame = (fume.frame & FF_FRAMEMASK) | fume.state.frame fume.threshold = 0 end end fume.movecount = dashmode fume.flags2 = (fume.flags2 & ~ MF2_OBJECTFLIP) | (mo.flags2 & MF2_OBJECTFLIP) fume.eflags = (fume.eflags & ~ MFE_VERTICALFLIP) | (mo.eflags & MFE_VERTICALFLIP) dist = -mo.radius - FixedMul(fume.info.radius, fume.destscale - mo.scale/3) //gets offset from the player sprite when rolled fume.rollangle = rollangle local x = mo.x + P_ReturnThrustX(fume, angle, dist) local y = mo.y + P_ReturnThrustY(fume, angle, dist) local z = mo.z + heightoffset - (fume.height>>1) P_TeleportMove(fume, x, y, z) if player.normalspeed >= player.normalspeed * 2 P_SpawnGhostMobj(fume) end end addHook("FollowMobj", function(player, fume) if not player.mo.skin == "metalsonic" return end P_DoMetalJetFume(player, fume) return true end, MT_METALJETFUME) /* If touching a wall following a halfpipe launch: Gets the player angle of the wall the player is touching. Checks if the "wall" is a thok barrier showing a skybox instead of wall texture. If so, the player cannot enter a wallrun state. Checks the difference between the previous wall angle and the current one. If this difference is 45 degrees or under, sets the wallangle to the new one. If not, ignores it. This prevents the sides of sectors from rotating the player 90 degrees when they move between them. If there is no angle stored, stores the current wall angle. Sets the proper state depending on how the player launches from the slope. Resets the wallrun state loss timer. */ addHook("MobjMoveBlocked", function(mo, object, line) if not mo.player return end if mo.player.wallruntype ~= 0 local lineAngle = GetWallAngle(mo, line) if mo.lineside == 0 if line.backsector ~= nil if(mo.z > line.backsector.ceilingheight) and ((line.frontside.toptexture == 0) or (line.backsector.ceilingpic == "F_SKY1")) return elseif(mo.z < line.backsector.floorheight) and ((line.frontside.bottomtexture == 0) or (line.backsector.floorpic == "F_SKY1")) return elseif (line.flags & ML_IMPASSIBLE) and (mo.z>line.backsector.floorheight) and (mo.z line.frontsector.ceilingheight) and (line.backside.toptexture == 0) return elseif(mo.z < line.frontsector.floorheight) and ((line.backside.bottomtexture == 0) or (line.frontsector.floorpic == "F_SKY1")) return elseif (line.flags & ML_IMPASSIBLE) and (mo.z>line.frontsector.floorheight) and (mo.z 0 mo.rollangle = FixedAngle(FRACUNIT * player.turninput * -90 / 50) elseif player.forwardinput < 0 mo.rollangle = ANGLE_180 + FixedAngle(FRACUNIT * player.turninput * 90 / 50) end else if player.forwardinput > 0 mo.rollangle = 0 player.drawangle = player.wallangle //this is meant to correct sprites facing the incorrect direction when reversed, however looks weird with models for some reason elseif player.forwardinput < 0 mo.rollangle = ANGLE_180 player.drawangle = player.wallangle + ANGLE_180 end end end //Wall spin, should add more character exclusions at some point to increase compatibility with other mods if (player.cmd.buttons & BT_SPIN) and (player.wallrun == 1) and not (mo.skin == "fang" or mo.skin == "amy") mo.state = S_PLAY_WALLROLL player.wallruntype = 2 player.pflags = $ | PF_SPINNING S_StartSound(mo, 17) mo.rollangle = 0 end end // Not entirely sure if this is the best way to keep a rolling player on the wall, the slight forward movement prevents them from landing back onto the slope without extra input. if mo.state == S_PLAY_WALLROLL P_Thrust(mo, player.wallangle, FRACUNIT/128) player.drawangle = player.wallangle end //Walljump button handling if (player.cmd.buttons & BT_JUMP) and player.wjready == true player.wjready = false player.walljump = true elseif (player.cmd.buttons & BT_JUMP) player.wjready = false player.walljump = false elseif mo.state == S_PLAY_WALLRUN player.wjready = true player.walljump = false elseif mo.state == S_PLAY_WALLROLL player.wjready = true player.walljump = false else player.wjready = false player.walljump = false end //Walljump action, ends wallrun and ability to enter wallrun. Allows secondary jump actions. if player.walljump == true P_InstaThrust(mo, player.wallangle + ANGLE_180, 20*FRACUNIT) mo.state = S_PLAY_JUMP S_StartSound(mo, 14) player.pflags = $ | PF_JUMPED player.pflags = $ & ~ PF_THOKKED //multiwallrun: if enabled, prevents the immediate wall run state loss from wall jumping. also rotates the player. if multiwallrun == true mo.angle = player.wallangle + ANGLE_180 player.stoptimer = true if (twodlevel or mo.flags2 & MF2_TWOD) player.wrinputdir = -$ end player.wallruntype = 1 else player.wallruntype = 0 end end //If the player is off of the wall for 15 tics, then they cannot reenter a wallrunning state. if (player.wallrun == 0) and (player.exitwallrun < 15) and (player.stoptimer ~= true) player.exitwallrun = $ + 1 end if player.wallrun == 1 player.wallrun = 2 end if player.exitwallrun == 15 player.wallruntype = 0 player.exitwallrun = 16 end //kinda lame implementation of this, will actually fix it later if player.charflags & SF_DASHMODE if player.dashmode > DASHMODE_THRESHOLD player.wasdashmode = true elseif player.dashmode < 84 player.wasdashmode = false end end end) //Saves the players inputs for use in wall movement, but prevents them from acutally changing the player's direction. addHook("PreThinkFrame", function() for player in players.iterate do local mo = player.mo if mo.state == S_PLAY_WALLRUN if not(twodlevel or mo.flags2 & MF2_TWOD) player.forwardinput = player.cmd.forwardmove * player.wrinputdir player.turninput = player.cmd.sidemove * player.wrinputdir if (player.cmd.forwardmove ~= 0) and (player.forwardinput < 0) and (player.inputFlip == false) player.cmd.forwardmove = 0 end player.cmd.sidemove = 0 else //uses sidemove instead of forwardmove in 2d mode. disables sideways wall running player.forwardinput = player.cmd.sidemove * player.wrinputdir if (player.cmd.sidemove ~= 0) and (player.forwardinput < 0) and (player.inputFlip == false) player.cmd.sidemove = 0 end end elseif mo.state == S_PLAY_WALLROLL if not(twodlevel or mo.flags2 & MF2_TWOD) player.cmd.forwardmove = 0 else player.cmd.sidemove = 0 end end end end) addHook("MapChange", function(map) //add "Lua.multiwallrun" to a level header to enable subsequent wall runs following a walljump if mapheaderinfo[map].multiwallrun == "active" multiwallrun = true else multiwallrun = false end end) addHook("NetVars", function(net) multiwallrun = net(multiwallrun) end) /*TO DO: *add actual animations for wall running *model support would be easier, just rotation of existing running ones, but new spriting would also be necessary *animation speed should also be based on z momentum *maybe figure out a way to keep wallroll touching the wall without adding extra forward momentum so manual adjustment isn't required to land back in the same place when launching straight up *probably more stuff idk */ óALUA_CLRNÿAá<LUA_WLRN