diff --git a/assets/scripts/core/game-scene.js b/assets/scripts/core/game-scene.js
index 98b31055..679aee0e 100644
--- a/assets/scripts/core/game-scene.js
+++ b/assets/scripts/core/game-scene.js
@@ -6162,6 +6162,9 @@ _buildSettingsPopup() {
*/
const updateEntries = [
{ text: "Update Log", scale: 1, font: "goldFont" },
+ { text: "Slopes OVERHAULED", scale: 0.75, color: 0xff9944 },
+ { text: "Bug reports are appreciated", scale: 0.75, },
+ { text: "-Bari", scale: 0.75, },
{ text: "Credits menu fixed :3", scale: 0.75, },
{ text: "Small Icon Kit changes", scale: 0.75, },
{ text: "Low Detail Mode", scale: 0.75, },
@@ -6178,9 +6181,6 @@ _buildSettingsPopup() {
{ text: "Breakable blocks break now.", scale: 0.75, },
{ text: "Fixed objects not showing in editor", scale: 0.65, },
{ text: "^ I, Amethyst, did all this btw. ^", scale: 0.6, color: 0x9966cc},
- { text: "Slopes (very buggy)", scale: 0.75, color: 0xff9944 },
- { text: "THEY WILL BE FIXED-", scale: 0.75, },
- { text: "OVER TIME.", scale: 0.75, },
{ text: "Slopes work in imported-", scale: 0.75, },
{ text: "levels now (thanks lasokadadyy)", scale: 0.7, },
{ text: "Fixed SOME objects", scale: 0.75 },
diff --git a/assets/scripts/core/level.js b/assets/scripts/core/level.js
index 8e41777c..5485ff83 100644
--- a/assets/scripts/core/level.js
+++ b/assets/scripts/core/level.js
@@ -11,29 +11,31 @@ class Collider {
this.slopeDir = 1;
this.slopeIsFilled = false;
this.slopeFlipY = false;
+ this.hypoAx = 0; this.hypoAy = 0;
+ this.hypoBx = 0; this.hypoBy = 0;
+ this.rightAx = 0; this.rightAy = 0;
+ this.slopeSolidBelow = true;
}
getSlopeSurfaceY(worldX) {
if (this.type !== slopeType) return null;
- const halfW = this.w / 2;
- const left = this.x - halfW;
- const right = this.x + halfW;
- if (worldX < left || worldX > right) return null;
- const frac = (worldX - left) / (right - left);
- let surfaceFrac = this.slopeDir > 0 ? frac : (1 - frac);
- if (this.slopeFlipY) surfaceFrac = 1 - surfaceFrac;
- return (this.y - this.h / 2) + surfaceFrac * this.h;
+ const ax = this.x + this.hypoAx, ay = this.y + this.hypoAy;
+ const bx = this.x + this.hypoBx, by = this.y + this.hypoBy;
+ const lo = ax <= bx ? { x: ax, y: ay } : { x: bx, y: by };
+ const hi = ax <= bx ? { x: bx, y: by } : { x: ax, y: ay };
+ if (hi.x - lo.x < 0.01) return null;
+ if (worldX < lo.x || worldX > hi.x) return null;
+ const t = (worldX - lo.x) / (hi.x - lo.x);
+ return lo.y + t * (hi.y - lo.y);
}
getSlopeAngleRad() {
- let angleDeg = this.slopeAngleDeg;
- if (this.slopeDir < 0) angleDeg = -angleDeg;
- if (this.slopeFlipY) angleDeg = -angleDeg;
- return angleDeg * Math.PI / 180;
+ if (this.type !== slopeType) return 0;
+ return Math.atan2(this.hypoBy - this.hypoAy, this.hypoBx - this.hypoAx);
}
usesFloorLanding(gravityFlipped) {
return this.isSolidBelowSurface(gravityFlipped);
}
isSolidBelowSurface(gravityFlipped) {
- return this.slopeFlipY === gravityFlipped;
+ return this.slopeSolidBelow !== gravityFlipped;
}
isSlopeSolidAt(worldX, worldY, gravityFlipped = false) {
if (this.type !== slopeType) return false;
@@ -209,6 +211,9 @@ const _SLOPE_DATA = {
294:{gw:1,gh:1,angle:45,sq:false},295:{gw:2,gh:1,angle:22.5,sq:false},
296:{gw:0.367,gh:0.433,angle:45,sq:true},297:{gw:0.967,gh:0.45,angle:45,sq:true},
299:{gw:1,gh:1,angle:45,sq:false},301:{gw:2,gh:1,angle:22.5,sq:false},
+ 305:{gw:1,gh:1,angle:45,sq:false},307:{gw:2,gh:1,angle:22.5,sq:false},
+ 349:{gw:1,gh:1,angle:45,sq:false},351:{gw:2,gh:1,angle:22.5,sq:false},
+ 673:{gw:1,gh:1,angle:45,sq:false},674:{gw:2,gh:1,angle:22.5,sq:false},
309:{gw:1,gh:1,angle:45,sq:false},311:{gw:2,gh:1,angle:22.5,sq:false},
315:{gw:1,gh:1,angle:45,sq:false},317:{gw:2,gh:1,angle:22.5,sq:false},
321:{gw:1,gh:1,angle:45,sq:false},323:{gw:2,gh:1,angle:22.5,sq:false},
@@ -355,20 +360,91 @@ function _resolveSlopeOrientation(objectDef, levelObj) {
return { dir, flipY };
}
+function _gdSlopeType(flipX, flipY, rotationDegrees) {
+ const rot = (parseInt(rotationDegrees, 10) || 0) % 360;
+ const fx = !!flipX, fy = !!flipY;
+ const r0 = rot === 0;
+ const r180 = Math.abs(rot) === 180;
+ const r90 = rot === 90 || rot === -270;
+ const r270 = rot === -90 || rot === 270;
+ if (!fx && !fy) return r0 ? 0 : r90 ? 4 : r180 ? 3 : r270 ? 5 : null;
+ if (!fx && fy) return r0 ? 1 : r90 ? 7 : r180 ? 2 : r270 ? 6 : null;
+ if (fx && !fy) return r0 ? 2 : r90 ? 6 : r180 ? 1 : r270 ? 7 : null;
+ return r0 ? 3 : r90 ? 5 : r180 ? 0 : r270 ? 4 : null;
+}
+
+function _gdSlopeSolidAbove(type) {
+ return type !== null && type < 7 && ((0x6a >> type) & 1) !== 0;
+}
+function _gdSlopeWallOnLeft(type) {
+ return type !== null && ((type - 2) >>> 0 < 3 || type === 6);
+}
+
+const _SLOPE_DECO_RANGES = [
+ [681, 708], [713, 716], [730, 763], [771, 772], [826, 829], [877, 878],
+ [888, 961], [969, 970], [1014, 1015], [1033, 1034], [1037, 1038],
+ [1041, 1092], [1108, 1188], [1198, 1199], [1256, 1306], [1316, 1317],
+ [1758, 1900]
+];
+
+function _isDecorationSlopeId(id) {
+ const n = parseInt(id, 10);
+ if (!Number.isFinite(n)) return false;
+ for (const [lo, hi] of _SLOPE_DECO_RANGES) {
+ if (n >= lo && n <= hi) return true;
+ }
+ return false;
+}
+
+function rotateSlopePoint(localX, localY, rotDeg) {
+ const theta = -rotDeg * Math.PI / 180;
+ const cosT = Math.cos(theta), sinT = Math.sin(theta);
+ return { x: localX * cosT - localY * sinT, y: localX * sinT + localY * cosT };
+}
+
function _createSlopeCollider(levelObj, objectDef, worldX, worldY) {
const slopeData = _SLOPE_DATA[levelObj.id];
if (!slopeData) return null;
- const rot90 = Math.round((((levelObj.rot || 0) % 360) + 360) % 360 / 90) % 4;
- const steep = rot90 === 1 || rot90 === 3;
- const w = (steep ? slopeData.gh : slopeData.gw) * a;
- const h = (steep ? slopeData.gw : slopeData.gh) * a;
+ if (slopeData.sq) return null;
+ if (_isDecorationSlopeId(levelObj.id)) return null;
+ const _scaleRaw = Number(levelObj.scale);
+ const _scale = Number.isFinite(_scaleRaw) && _scaleRaw > 0 ? _scaleRaw : 1;
+ const hw0 = (slopeData.gw * a * _scale) / 2;
+ const hh0 = (slopeData.gh * a * _scale) / 2;
+ let vRight = { x: hw0, y: -hh0 };
+ let vLo = { x: -hw0, y: -hh0 };
+ let vHi = { x: hw0, y: hh0 };
+ const fx = levelObj.flipX ? -1 : 1;
+ const fy = levelObj.flipY ? -1 : 1;
+ const flip = pt => ({ x: pt.x * fx, y: pt.y * fy });
+ vRight = flip(vRight); vLo = flip(vLo); vHi = flip(vHi);
+ const rotDeg = levelObj.rot || 0;
+ vRight = rotateSlopePoint(vRight.x, vRight.y, rotDeg);
+ vLo = rotateSlopePoint(vLo.x, vLo.y, rotDeg);
+ vHi = rotateSlopePoint(vHi.x, vHi.y, rotDeg);
+ const xs = [vRight.x, vLo.x, vHi.x];
+ const ys = [vRight.y, vLo.y, vHi.y];
+ const w = Math.max(...xs) - Math.min(...xs);
+ const h = Math.max(...ys) - Math.min(...ys);
const collider = new Collider(slopeType, worldX, worldY, w, h, 0);
collider.objid = levelObj.id;
+ collider.hypoAx = vLo.x; collider.hypoAy = vLo.y;
+ collider.hypoBx = vHi.x; collider.hypoBy = vHi.y;
+ collider.rightAx = vRight.x; collider.rightAy = vRight.y;
+ const hypoDx = vHi.x - vLo.x;
+ collider.slopeSolidBelow = Math.abs(hypoDx) < 0.01
+ ? vRight.x < vLo.x
+ : vRight.y < (vLo.y + ((vRight.x - vLo.x) / hypoDx) * (vHi.y - vLo.y));
+ const rot90 = Math.round(((rotDeg % 360) + 360) % 360 / 90) % 4;
+ const steep = rot90 === 1 || rot90 === 3;
collider.slopeAngleDeg = steep ? (90 - slopeData.angle) : slopeData.angle;
- const { dir, flipY } = _resolveSlopeOrientation(objectDef, levelObj);
+ const { dir } = _resolveSlopeOrientation(objectDef, levelObj);
collider.slopeDir = dir;
- collider.slopeFlipY = flipY;
+ collider.slopeFlipY = !collider.slopeSolidBelow;
collider.slopeIsFilled = slopeData.sq;
+ collider.slopeType = _gdSlopeType(levelObj.flipX, levelObj.flipY, levelObj.rot);
+ collider.gdSolidAbove = _gdSlopeSolidAbove(collider.slopeType);
+ collider.gdWallOnLeft = _gdSlopeWallOnLeft(collider.slopeType);
return collider;
}
diff --git a/assets/scripts/core/loading-screen.js b/assets/scripts/core/loading-screen.js
index c28c1e53..6b931f18 100644
--- a/assets/scripts/core/loading-screen.js
+++ b/assets/scripts/core/loading-screen.js
@@ -187,7 +187,9 @@ class BootScene extends Phaser.Scene {
"It is only game...",
"Unlock new icons and colors by completing achievements",
"y=mx+b",
- "Nicest game ever!"
+ "Nicest game ever!",
+ "S-slopes!~",
+ "Anything but slopes"
];
const sliderOriginX = cx - 105;
const sliderOriginY = cy + 110;
diff --git a/assets/scripts/core/player.js b/assets/scripts/core/player.js
index a3b54228..dcec6032 100644
--- a/assets/scripts/core/player.js
+++ b/assets/scripts/core/player.js
@@ -408,6 +408,12 @@ class PlayerObject {
this._prevSlopeObj = null;
this._prevSlopeAngle = null;
this._slopeEntryX = null;
+ this._slopeRiding = false;
+ this._slopeContactFrames = 0;
+ this._slopeExitVel = null;
+ this._slopeExitGrace = 0;
+ this._slopeRidePush = false;
+ this._skipSlopeExit = false;
this.rotateActionActive = false;
this.rotateActionTime = 0;
this.rotateActionDuration = 0;
@@ -2283,8 +2289,8 @@ if (this.p.isFlying || this.p.isUfo) {
}
this._setGamemodeFlyBounds(false, 0);
}
- hitGround() {
- const _0x4a38a5 = !this.p.onGround;
+ hitGround(skipBurst = false) {
+ const _0x4a38a5 = !skipBurst && !this.p.onGround;
if (!this.p.isFlying && !this.p.isWave && !this.p.isUfo) {
this.p.lastGroundY = this.p.y;
}
@@ -2913,194 +2919,249 @@ if (this.p.isFlying || this.p.isUfo) {
_getSlopeHitSize(playerSize, waveHitSize) {
return this.p.isWave ? waveHitSize : playerSize;
}
- _isOnSlopeSurface(surfaceY, footProbe, headProbe, hitSize, useFloorLanding) {
- const tolerance = Math.max(14, hitSize * 0.45);
- if (useFloorLanding) {
- return Math.abs(footProbe - surfaceY) < tolerance && footProbe >= surfaceY - 2;
- }
- return Math.abs(headProbe - surfaceY) < tolerance && headProbe <= surfaceY + 2;
- }
- _landOnSlopeFloor(gameObj, surfaceY, hitSize, footProbe, lastFootProbe, playersY) {
- const margin = Math.max(8, Math.abs(footProbe - lastFootProbe) + 4);
- if (!this.p.gravityFlipped &&
- (footProbe >= surfaceY || lastFootProbe >= surfaceY) &&
- (this.p.yVelocity <= 0 || this.p.onGround) &&
- playersY <= surfaceY + hitSize + margin) {
- return { y: surfaceY + hitSize, onCeiling: false, collideBottom: surfaceY, collideTop: null, slopeAngle: gameObj.getSlopeAngleRad() };
- }
- return null;
- }
- _landOnSlopeCeiling(gameObj, surfaceY, hitSize, headProbe, lastHeadProbe, playersY) {
- const margin = Math.max(8, Math.abs(headProbe - lastHeadProbe) + 4);
- if ((headProbe <= surfaceY || lastHeadProbe <= surfaceY) &&
- (this.p.yVelocity >= 0 || this.p.onGround) &&
- playersY >= surfaceY - hitSize - margin) {
- return { y: surfaceY - hitSize, onCeiling: true, collideBottom: null, collideTop: surfaceY, slopeAngle: gameObj.getSlopeAngleRad() };
- }
- return null;
- }
- _landOnSlopeCeilingFlipped(gameObj, surfaceY, hitSize, footProbe, lastFootProbe, playersY) {
- const margin = Math.max(8, Math.abs(footProbe - lastFootProbe) + 4);
- if (this.p.gravityFlipped &&
- (footProbe >= surfaceY || lastFootProbe >= surfaceY) &&
- (this.p.yVelocity <= 0 || this.p.onGround) &&
- playersY <= surfaceY + hitSize + margin) {
- return { y: surfaceY + hitSize, onCeiling: true, collideBottom: null, collideTop: surfaceY, slopeAngle: gameObj.getSlopeAngleRad() };
- }
- return null;
- }
- _trySnapToSlopeSurface(gameObj, pieceWidth, playersY, hitSize, gamemodeAddition, useFloorLanding) {
- const surfaceY = gameObj.getSlopeSurfaceY(pieceWidth);
- if (surfaceY === null) return null;
- const isFlyMode = this.p.isFlying || this.p.isUfo;
- const pad = isFlyMode ? Math.max(10, hitSize * 0.4) : 9;
- const footProbe = playersY - hitSize + gamemodeAddition;
- const headProbe = playersY + hitSize - gamemodeAddition;
- if (useFloorLanding) {
- if (footProbe < surfaceY - pad) return null;
- if (footProbe > surfaceY + pad) return null;
- return { y: surfaceY + hitSize, onCeiling: false, collideBottom: surfaceY, collideTop: null, slopeAngle: gameObj.getSlopeAngleRad() };
- }
- if (headProbe < surfaceY - pad) return null;
- if (headProbe > surfaceY + pad) return null;
- return { y: surfaceY - hitSize, onCeiling: true, collideBottom: null, collideTop: surfaceY, slopeAngle: gameObj.getSlopeAngleRad() };
- }
- _trySlopeVelocityLanding(gameObj, surfaceY, hitSize, footProbe, lastFootProbe, headProbe, lastHeadProbe, playersY, useFloorLanding) {
- if (useFloorLanding) {
- if (this.p.gravityFlipped) {
- return this._landOnSlopeCeilingFlipped(gameObj, surfaceY, hitSize, footProbe, lastFootProbe, playersY);
- }
- return this._landOnSlopeFloor(gameObj, surfaceY, hitSize, footProbe, lastFootProbe, playersY);
- }
- return this._landOnSlopeCeiling(gameObj, surfaceY, hitSize, headProbe, lastHeadProbe, playersY);
- }
- _handleSlopeCollision(gameObj, pieceWidth, playersY, playersLastY, left, right, top, bottom, playerSize, waveHitSize, gamemodeAddition) {
+ _slopeRideY(gameObj, surfaceY, angle, playerSize, above) {
+ return above ? surfaceY + playerSize : surfaceY - playerSize;
+ }
+ _slopeReached(pEdge, surfaceY, gamemodeAddition, above) {
+ if (window.slopeReachGuard === false) return true;
+ if (this.p.onGround) return true;
+ return above ? pEdge <= surfaceY + gamemodeAddition
+ : pEdge >= surfaceY - gamemodeAddition;
+ }
+ _slopeBackWallHit(gameObj, pieceWidth, playersY, surfaceY) {
+ if (window.slopeBackWall === false) return false;
+ const ty = gameObj.slopeType;
+ if (ty === null || ty === undefined) return false;
+ const halfW = (gameObj.w || 0) / 2;
+ const halfH = (gameObj.h || 0) / 2;
+ if (!(halfW > 0) || !(halfH > 0)) return false;
+ if (surfaceY !== null && surfaceY !== undefined) {
+ const insideSolid = gameObj.slopeSolidBelow
+ ? (playersY < surfaceY)
+ : (playersY > surfaceY);
+ if (!insideSolid) return false;
+ }
+ const wallW = 2;
+ const wallLeft = gameObj.gdWallOnLeft
+ ? (gameObj.x - halfW)
+ : (gameObj.x + halfW - wallW);
+ const wallRight = wallLeft + wallW;
+ const boxBot = gameObj.y - halfH;
+ const boxTop = gameObj.y + halfH;
+ const inner = 9;
+ return (pieceWidth + inner > wallLeft) && (pieceWidth - inner < wallRight)
+ && (playersY + inner > boxBot) && (playersY - inner < boxTop);
+ }
+ _slopeFlatCapLand(gameObj, pieceWidth, playersY, playersLastY, playerSize, gamemodeAddition) {
+ if (window.slopeFlatCap === false) return null;
+ const ty = gameObj.slopeType;
+ if (ty === null || ty === undefined) return null;
+ if (this.p.isWave) return null;
+ const halfW = (gameObj.w || 0) / 2;
+ const halfH = (gameObj.h || 0) / 2;
+ if (!(halfW > 0) || !(halfH > 0)) return null;
+ if (pieceWidth <= gameObj.x - halfW || pieceWidth >= gameObj.x + halfW) return null;
+ const boxTop = gameObj.y + halfH;
+ const boxBot = gameObj.y - halfH;
+ const capAtTop = !!gameObj.gdSolidAbove;
+ const gFlip = this.p.gravityFlipped;
+ if (capAtTop === gFlip) return null;
+ const face = capAtTop ? boxTop : boxBot;
+ const feet = capAtTop
+ ? playersY - playerSize + gamemodeAddition
+ : playersY + playerSize - gamemodeAddition;
+ const lastFeet = capAtTop
+ ? playersLastY - playerSize + gamemodeAddition
+ : playersLastY + playerSize - gamemodeAddition;
+ const falling = capAtTop ? (this.p.yVelocity <= 0) : (this.p.yVelocity >= 0);
+ if (!falling && !this.p.onGround) return null;
+ const crossed = capAtTop
+ ? (feet <= face && (lastFeet >= face || this.p.onGround))
+ : (feet >= face && (lastFeet <= face || this.p.onGround));
+ if (!crossed) return null;
+ if (Math.abs(face - feet) > playerSize) return null;
+ return { landed: true, died: false, candidate: {
+ y: capAtTop ? face + playerSize : face - playerSize,
+ onCeiling: !capAtTop,
+ collideBottom: capAtTop ? face : null,
+ collideTop: capAtTop ? null : face,
+ slopeAngle: 0, blocked: true } };
+ }
+ _handleSlopeCollision(gameObj, pieceWidth, playersY, playersLastY, left, right, top, bottom, playerSize, waveHitSize, gamemodeAddition, previousWorldX) {
const surfaceY = gameObj.getSlopeSurfaceY(pieceWidth);
if (surfaceY === null) return { landed: false, died: false };
- const hitSize = this._getSlopeHitSize(playerSize, waveHitSize);
- const footProbe = playersY - hitSize + gamemodeAddition;
- const lastFootProbe = playersLastY - hitSize + gamemodeAddition;
- const headProbe = playersY + hitSize - gamemodeAddition;
- const lastHeadProbe = playersLastY + hitSize - gamemodeAddition;
- const tightPad = this.p.isWave ? 5 : 9;
- const inXRange = pieceWidth + hitSize - 5 > left && pieceWidth - hitSize + 5 < right;
- const useFloorLanding = gameObj.usesFloorLanding(this.p.gravityFlipped);
- const onSlopeSurface = this._isOnSlopeSurface(surfaceY, footProbe, headProbe, hitSize, useFloorLanding);
-
- let candidate = null;
- if (inXRange) {
- candidate = this._trySlopeVelocityLanding(gameObj, surfaceY, hitSize, footProbe, lastFootProbe, headProbe, lastHeadProbe, playersY, useFloorLanding);
- if (!candidate) {
- candidate = this._trySnapToSlopeSurface(gameObj, pieceWidth, playersY, hitSize, gamemodeAddition, useFloorLanding);
+ const lastSurfaceY = previousWorldX === undefined
+ ? surfaceY
+ : (gameObj.getSlopeSurfaceY(previousWorldX) ?? surfaceY);
+ if (this._slopeBackWallHit(gameObj, pieceWidth, playersY, surfaceY)) {
+ return { landed: false, died: true, immediate: true, reason: 'slope-backwall' };
+ }
+ const capLand = this._slopeFlatCapLand(
+ gameObj, pieceWidth, playersY, playersLastY, playerSize, gamemodeAddition);
+ if (capLand) return capLand;
+ const angle = gameObj.getSlopeAngleRad();
+ const isCeilSlope = !gameObj.slopeSolidBelow;
+
+ if (this.p.isWave) {
+ const waveHalf = this.p.isMini ? 6 : 9;
+ const insideSolid = gameObj.slopeSolidBelow
+ ? (playersY - waveHalf < surfaceY)
+ : (playersY + waveHalf > surfaceY);
+ if (insideSolid) return { landed: false, died: true, immediate: true };
+ return { landed: false, died: false };
+ }
+
+ const pLow = playersY - playerSize + gamemodeAddition;
+ const pHigh = playersY + playerSize - gamemodeAddition;
+ const pLastLow = playersLastY - playerSize + gamemodeAddition;
+ const pLastHigh = playersLastY + playerSize - gamemodeAddition;
+ const _tanSpeed = playerSpeed * (window.slopeTangentD !== undefined ? window.slopeTangentD : d);
+ const tangent = Math.tan(angle) * _tanSpeed;
+
+ if (this.p.isFlying && !this.p.isUfo) {
+ const gFlip = this.p.gravityFlipped;
+ const actsAsFloor = (!isCeilSlope && !gFlip) || (isCeilSlope && gFlip);
+ const snapAbove = actsAsFloor !== gFlip;
+ const stickRest = this.p.onGround && !this.p.upKeyDown;
+ const stickPush = this.p.onGround && this.p.upKeyDown;
+ if (snapAbove) {
+ const crossedDown = pLastLow >= surfaceY - gamemodeAddition && pLow < surfaceY;
+ if ((this.p.yVelocity <= 0 || (gFlip ? stickPush : stickRest) || crossedDown) &&
+ pLow >= surfaceY - playerSize && pLow <= surfaceY + gamemodeAddition) {
+ if (this._slopeRiding && this._slopeExitVel > 0 && tangent < 0) {
+ return { landed: false, died: false };
+ }
+ return { landed: true, died: false, candidate: {
+ y: this._slopeRideY(gameObj, surfaceY, angle, playerSize, true),
+ onCeiling: false, collideBottom: surfaceY, collideTop: null,
+ slopeAngle: angle, tangent: tangent, ride: true, ridePush: gFlip } };
+ }
+ return { landed: false, died: false };
}
- if (!candidate && onSlopeSurface) {
- if (useFloorLanding) {
- candidate = {
- y: surfaceY + hitSize,
- onCeiling: this.p.gravityFlipped,
- collideBottom: this.p.gravityFlipped ? null : surfaceY,
- collideTop: this.p.gravityFlipped ? surfaceY : null,
- slopeAngle: gameObj.getSlopeAngleRad()
- };
- } else {
- candidate = {
- y: surfaceY - hitSize,
- onCeiling: true,
- collideBottom: null,
- collideTop: surfaceY,
- slopeAngle: gameObj.getSlopeAngleRad()
- };
+ const crossedUp = pLastHigh <= surfaceY + gamemodeAddition && pHigh > surfaceY;
+ if ((this.p.yVelocity >= 0 || (gFlip ? stickRest : stickPush) || crossedUp) &&
+ pHigh >= surfaceY - playerSize * 1.5 && pHigh <= surfaceY + playerSize) {
+ if (this._slopeRiding && this._slopeExitVel < 0 && tangent > 0) {
+ return { landed: false, died: false };
}
+ return { landed: true, died: false, candidate: {
+ y: this._slopeRideY(gameObj, surfaceY, angle, playerSize, false),
+ onCeiling: true, collideBottom: null, collideTop: surfaceY,
+ slopeAngle: angle, tangent: tangent, ride: true, ridePush: !gFlip } };
}
+ return { landed: false, died: false };
}
- if (candidate) {
- candidate.gameObj = gameObj;
- return { landed: true, died: false, candidate };
- }
+ const rideable = isCeilSlope === this.p.gravityFlipped;
- const overlapping = pieceWidth + tightPad > left && pieceWidth - tightPad < right &&
- playersY + tightPad > top && playersY - tightPad < bottom;
- if (this.p.isWave && overlapping) {
- return { landed: false, died: true };
- }
- if (overlapping && !onSlopeSurface) {
- if (!gameObj.slopeIsFilled && gameObj.isSlopeSolidAt(pieceWidth, playersY, this.p.gravityFlipped)) {
- if (window.noClip) this.p.diedThisFrame = true;
- else return { landed: false, died: true };
- } else {
- const backSide = gameObj.getSlopeBackWallSide(this.p.gravityFlipped);
- const wallX = backSide === "left" ? left : right;
- const wallSurface = gameObj.getSlopeSurfaceY(wallX);
- let hitBackWall = false;
- if (useFloorLanding) {
- if (backSide === "left") {
- hitBackWall = pieceWidth < wallX + tightPad && pieceWidth + hitSize > wallX &&
- footProbe < wallSurface - 2 && headProbe > top + 2;
- } else {
- hitBackWall = pieceWidth > wallX - tightPad && pieceWidth - hitSize < wallX &&
- footProbe < wallSurface - 2 && headProbe > top + 2;
- }
- } else if (backSide === "left") {
- hitBackWall = pieceWidth < wallX + tightPad && pieceWidth + hitSize > wallX &&
- headProbe > wallSurface + 2 && footProbe < bottom - 2;
- } else {
- hitBackWall = pieceWidth > wallX - tightPad && pieceWidth - hitSize < wallX &&
- headProbe > wallSurface + 2 && footProbe < bottom - 2;
+ if (!isCeilSlope) {
+ if (!rideable) {
+ if (pLow < surfaceY && pLow >= surfaceY - playerSize) {
+ return { landed: true, died: false, candidate: {
+ y: this._slopeRideY(gameObj, surfaceY, angle, playerSize, true),
+ onCeiling: false, collideBottom: surfaceY, collideTop: null,
+ slopeAngle: angle, blocked: true } };
}
- if (hitBackWall || gameObj.slopeIsFilled) {
- if (window.noClip) this.p.diedThisFrame = true;
- else return { landed: false, died: true };
+ if (pLow < surfaceY - playerSize && pLastLow < surfaceY - playerSize) {
+ return { landed: false, died: true };
}
+ return { landed: false, died: false };
+ }
+ if ((pLastLow >= lastSurfaceY || this.p.onGround) && (this.p.yVelocity <= 0 || this.p.onGround)) {
+ if (pLow >= surfaceY - playerSize && this._slopeReached(pLow, surfaceY, gamemodeAddition, true)) {
+ if (this._slopeRiding && this._slopeExitVel > 0 && tangent < 0) {
+ return { landed: false, died: false };
+ }
+ return { landed: true, died: false, candidate: {
+ y: this._slopeRideY(gameObj, surfaceY, angle, playerSize, true),
+ onCeiling: false, collideBottom: surfaceY, collideTop: null,
+ slopeAngle: angle, tangent: tangent, ride: true } };
+ }
+ return { landed: false, died: false };
+ }
+ if (pLow < surfaceY - playerSize && pLastLow < surfaceY - playerSize) {
+ return { landed: false, died: true };
}
+ return { landed: false, died: false };
}
+ if (!rideable) {
+ if (pHigh > surfaceY && pHigh <= surfaceY + playerSize) {
+ return { landed: true, died: false, candidate: {
+ y: this._slopeRideY(gameObj, surfaceY, angle, playerSize, false),
+ onCeiling: true, collideBottom: null, collideTop: surfaceY,
+ slopeAngle: angle, blocked: true } };
+ }
+ if (pHigh > surfaceY + playerSize && pLastHigh > surfaceY + playerSize) {
+ return { landed: false, died: true };
+ }
+ return { landed: false, died: false };
+ }
+ if ((pLastHigh <= lastSurfaceY || this.p.onGround) && (this.p.yVelocity >= 0 || this.p.onGround)) {
+ if (pHigh <= surfaceY + playerSize && this._slopeReached(pHigh, surfaceY, gamemodeAddition, false)) {
+ if (this._slopeRiding && this._slopeExitVel < 0 && tangent > 0) {
+ return { landed: false, died: false };
+ }
+ return { landed: true, died: false, candidate: {
+ y: this._slopeRideY(gameObj, surfaceY, angle, playerSize, false),
+ onCeiling: true, collideBottom: null, collideTop: surfaceY,
+ slopeAngle: angle, tangent: tangent, ride: true } };
+ }
+ return { landed: false, died: false };
+ }
+ if (pHigh > surfaceY + playerSize && pLastHigh > surfaceY + playerSize) {
+ return { landed: false, died: true };
+ }
return { landed: false, died: false };
}
- static SLOPE_BOUNCE_SCALE = {
- 291: 1,
- };
- _applySlopeExitBounce(slopeObj, slopeAngle, pieceWidth) {
- if (!slopeObj || slopeAngle === null || slopeAngle === undefined) return;
- if (this.p.isJumping && !this.p.onGround) return;
- const angleRad = Math.abs(slopeAngle);
- if (angleRad < 0.05) return;
- const halfW = slopeObj.w / 2;
- const left = slopeObj.x - halfW;
- const right = slopeObj.x + halfW;
- const exitMargin = 14;
- let exitHighEnd = slopeObj.slopeDir > 0
- ? pieceWidth >= right - exitMargin
- : pieceWidth <= left + exitMargin;
- if (slopeObj.slopeFlipY) exitHighEnd = !exitHighEnd;
- if (!exitHighEnd) return;
- let highEndIsRight = slopeObj.slopeDir > 0;
- if (slopeObj.slopeFlipY) highEndIsRight = !highEndIsRight;
- const highEndX = highEndIsRight ? right : left;
- const lowEndX = highEndIsRight ? left : right;
- const slopeSpan = Math.abs(right - left) || 1;
- const entryX = Number.isFinite(this._slopeEntryX) ? this._slopeEntryX : lowEndX;
- const traveledFraction = Math.min(1, Math.max(0, Math.abs(highEndX - entryX) / slopeSpan));
- let bounceVel = Math.tan(angleRad) * playerSpeed * this.flipMod();
- const idScale = PlayerObject.SLOPE_BOUNCE_SCALE[slopeObj.objid];
- if (idScale !== undefined) bounceVel *= idScale;
- bounceVel *= traveledFraction;
- if (slopeObj.slopeFlipY) bounceVel = -bounceVel;
- if (this.p.isWave) bounceVel *= 0.85;
- else if (this.p.isMini) bounceVel *= 0.8;
- if (Math.abs(bounceVel) < 0.5) return;
- this.p.yVelocity = bounceVel;
+ _slopeLaunchMultiplier(angleRad) {
+ const num = window.slopeLaunchNum !== undefined ? window.slopeLaunchNum : 0.8;
+ const cap = window.slopeLaunchCap !== undefined ? window.slopeLaunchCap : 1.1;
+ const gain = window.slopeLaunchGain !== undefined ? window.slopeLaunchGain : 1.4;
+ const acute = Math.atan(Math.abs(Math.tan(angleRad || 0)));
+ if (!(acute > 1e-6)) return cap * gain;
+ return Math.min(num / acute, cap) * gain;
+ }
+ _slopeExitScale() {
+ const rampTime = window.slopeRampTime !== undefined ? window.slopeRampTime : 0.1;
+ const rampFloor = window.slopeRampFloor !== undefined ? window.slopeRampFloor : 0.4;
+ const held = (this._slopeContactFrames || 0) / 240;
+ const ramp = held < rampTime ? Math.max(held / rampTime, rampFloor) : 1;
+ const modeScale = (this.p.isFlying || this.p.isUfo || this.p.isWave
+ || this.p.isSwing || this.p.isBall) ? 0.75 : 1;
+ return this._slopeLaunchMultiplier(this._prevSlopeAngle) * modeScale * ramp;
+ }
+ _applySlopeExitVelocity() {
+ if (this._slopeExitVel === null) return;
+ if (this._skipSlopeExit) return;
+ if (this.p.isFlying && !this.p.isUfo) {
+ if (!this.p.upKeyDown || this._slopeRidePush) {
+ const shipCap = window.slopeShipCap !== undefined ? window.slopeShipCap : 16;
+ const shipVel = this._slopeExitVel * this._slopeExitScale();
+ const shipDir = shipVel >= 0 ? 1 : -1;
+ if (shipVel * shipDir <= this.p.yVelocity * shipDir) return;
+ this.p.yVelocity = Math.max(-shipCap, Math.min(shipCap, Math.round(shipVel * 1000) / 1000));
+ }
+ return;
+ }
+ if (this.p.isJumping) return;
+ const exitScale = this._slopeExitScale();
+ const exitCap = this.p.isSwing
+ ? (window.slopeSwingCap !== undefined ? window.slopeSwingCap : 13)
+ : (window.slopeExitCap !== undefined ? window.slopeExitCap : 30);
+ const exitVel = this._slopeExitVel * exitScale;
+ const dir = exitVel >= 0 ? 1 : -1;
+ if (exitVel * dir <= this.p.yVelocity * dir) return;
+ this.p.yVelocity = Math.max(-exitCap, Math.min(exitCap, Math.round(exitVel * 1000) / 1000));
this.p.onGround = false;
this.p.canJump = false;
- if (this.p.isFlying) {
- this.p._slopeBounceActive = true;
- }
- if (!this.p.isFlying && !this.p.isWave && !this.p.isUfo && !this.p.isSpider && !this.p.isRobot) {
- this.p.isJumping = true;
- this._rotation = slopeAngle;
- this.stopRotation();
+ const rising = this.p.gravityFlipped ? this.p.yVelocity < 0 : this.p.yVelocity > 0;
+ const launchedClear = Math.abs(this.p.yVelocity) > p * 2;
+ if (rising && launchedClear && !this.p.isWave && !this.p.isUfo && !this.p.isSpider && !this.p.isRobot && !this.rotateActionActive) {
+ this.runRotateAction();
}
}
+
_checkSnapJump(_0x1f801b) {
const _0x483058 = [{
dx: 240,
@@ -3281,6 +3342,29 @@ if (this.p.isFlying || this.p.isUfo) {
return this.p.yVelocity < p;
}
}
+ _gravBaseForSpeed() {
+ if (window.speedGravity === false) return p;
+ if (typeof SpeedPortal === 'undefined' || typeof playerSpeed !== 'number') return p;
+ const sp = playerSpeed;
+ if (sp <= (SpeedPortal.HALF + SpeedPortal.ONE_TIMES) / 2) return 1.880398;
+ if (sp <= (SpeedPortal.ONE_TIMES + SpeedPortal.TWO_TIMES) / 2) return p;
+ if (sp <= (SpeedPortal.TWO_TIMES + SpeedPortal.THREE_TIMES) / 2) return 1.914398;
+ return 1.922398;
+ }
+ _applySlopeJumpBoost() {
+ if (window.slopeJumpBoost === false) return;
+ if (this._slopeExitVel === null || this._slopeExitVel === undefined) return;
+ const base = this.p.yVelocity;
+ if (!base) return;
+ const dir = base >= 0 ? 1 : -1;
+ const contact = this._slopeExitVel * this._slopeExitScale();
+ if (contact * dir <= 0) return;
+ const cap = base * 1.4;
+ let v = base + contact * 0.25;
+ if (dir > 0) { if (v > cap) v = cap; }
+ else { if (v < cap) v = cap; }
+ this.p.yVelocity = v;
+ }
updateJump(_0x3d1c6f) {
if (this.p.pendingVelocity !== null) {
this.p.yVelocity = this.p.pendingVelocity;
@@ -3314,9 +3398,10 @@ if (this.p.isFlying || this.p.isUfo) {
this.p.upKeyPressed = false;
this.p.queuedHold = false;
this.p.yVelocity = this.flipMod() * 22.360064 * (this.p.isMini ? 0.8 : 1);
+ this._applySlopeJumpBoost();
this.runRotateAction();
} else if (this.p.isJumping) {
- this.p.yVelocity -= p * _0x3d1c6f * this.flipMod();
+ this.p.yVelocity -= this._gravBaseForSpeed() * _0x3d1c6f * this.flipMod();
if (this.playerIsFalling()) {
this.p.isJumping = false;
this.p.onGround = false;
@@ -3325,7 +3410,7 @@ if (this.p.isFlying || this.p.isUfo) {
if (this.playerIsFalling()) {
this.p.canJump = false;
}
- this.p.yVelocity -= p * _0x3d1c6f * this.flipMod();
+ this.p.yVelocity -= this._gravBaseForSpeed() * _0x3d1c6f * this.flipMod();
if (this.p.gravityFlipped) {
this.p.yVelocity = Math.min(this.p.yVelocity, 30);
} else {
@@ -3444,9 +3529,10 @@ if (this.p.isFlying || this.p.isUfo) {
this.p.onGround = false;
this.p.canJump = false;
this.p.yVelocity *= 0.6;
+ this._skipSlopeExit = true;
return;
}
-
+
if (this.playerIsFalling()) {
this.p.canJump = false;
}
@@ -3503,8 +3589,8 @@ if (this.p.isFlying || this.p.isUfo) {
const robotJumpInit = 10.25 * robotMiniJumpScale;
const robotHoldMax = 15.5;
const robotHoldForce = p * 0.2 * robotMiniJumpScale;
- const robotGravityHold = p * 0.15;
- const robotGravityFall = p * 0.81;
+ const robotGravityHold = this._gravBaseForSpeed() * (window.robotGravHold !== undefined ? window.robotGravHold : 0.15);
+ const robotGravityFall = this._gravBaseForSpeed() * (window.robotGravMult !== undefined ? window.robotGravMult : 0.9);
const robotReleaseCut = 0.9;
const robotReleaseMinTime = 0;
const robotMaxFall = 28;
@@ -3517,6 +3603,7 @@ if (this.p.isFlying || this.p.isUfo) {
this.p.canJump = false;
this.p.queuedHold = false;
this.p.yVelocity = this.flipMod() * robotJumpInit;
+ this._applySlopeJumpBoost();
this.p._robotHold = true;
this.p._robotHoldTimer = 0;
this._robotJumpFlameActive = true;
@@ -3574,9 +3661,12 @@ if (this.p.isFlying || this.p.isUfo) {
}
_updateUfoJump(_dt) {
const _ufoJump = this.p.isMini ? 13.296 : 13.742;
+ const _ufoMini = window.ufoMiniDiv !== undefined ? window.ufoMiniDiv : 0.85;
+ const _ufoFastBase = window.ufoFastGrav !== undefined ? window.ufoFastGrav : 0.6;
+ const _ufoSlowBase = window.ufoSlowGrav !== undefined ? window.ufoSlowGrav : 0.5;
const _ufoThreshold = 3.832796;
- const _ufoFastGrav = this.p.isMini ? 0.634524 : 0.540121;
- const _ufoSlowGrav = this.p.isMini ? 0.421624 : 0.359973;
+ const _ufoFastGrav = this.p.isMini ? _ufoFastBase / _ufoMini : _ufoFastBase;
+ const _ufoSlowGrav = this.p.isMini ? _ufoSlowBase / _ufoMini : _ufoSlowBase;
const _ufoUpVel = this.p.yVelocity * this.flipMod();
const _ufoGrav = _ufoUpVel > _ufoThreshold ? _ufoFastGrav : _ufoSlowGrav;
this.p.yVelocity -= p * _ufoGrav * _dt * this.flipMod();
@@ -3968,6 +4058,10 @@ if (this.p.isFlying || this.p.isUfo) {
let bestSlopeCandidate = null;
let bestSlopeGameObj = null;
const preferHighestSlopeSurface = !this.p.gravityFlipped;
+ let _slopeKillPending = false;
+ let _snappedSlopeThisFrame = false;
+ let _slopeTangentThisFrame = 0;
+ let _slopeBlockedThisStep = false;
const _0x198534 = this._gameLayer.getNearbySectionObjects(pieceWidth);
for (let gameObj of _0x198534) {
let left = gameObj.x - gameObj.w / 2;
@@ -4522,11 +4616,19 @@ if (this.p.isFlying || this.p.isUfo) {
return;
} else if (_colType === slopeType) {
const slopeResult = this._handleSlopeCollision(
- gameObj, pieceWidth, playersY, playersLastY, left, right, top, bottom, playerSize, waveHitSize, gamemodeAddition
+ gameObj, pieceWidth, playersY, playersLastY, left, right, top, bottom, playerSize, waveHitSize, gamemodeAddition, previousWorldX
);
if (slopeResult.died) {
- this.killPlayer();
- return;
+ if (slopeResult.immediate) {
+ if (window.noClip) {
+ this.p.diedThisFrame = true;
+ continue;
+ }
+ this.killPlayer();
+ return;
+ }
+ _slopeKillPending = true;
+ continue;
}
if (slopeResult.landed && slopeResult.candidate) {
const cand = slopeResult.candidate;
@@ -4562,7 +4664,10 @@ if (this.p.isFlying || this.p.isUfo) {
const _0xLandBot = (this.p.yVelocity <= 0 || this.p.onGround) && (_0x146a97 >= bottom || _0x869e42 >= bottom);
const _0xLandTop = (this.p.yVelocity >= 0 || this.p.onGround) && (_0x3e7199 <= top || _0x135a9d <= top);
const isstandingOnAPlatform = this.p.gravityFlipped ? _0xLandTop : _0xLandBot;
- if (iscolliding && !isstandingOnAPlatform) {
+ const _slopeLeadIn = this._slopeRiding && (this.p.gravityFlipped
+ ? _0x3e7199 <= top + playerSize
+ : _0x146a97 >= bottom - playerSize);
+ if (iscolliding && !isstandingOnAPlatform && !_slopeLeadIn) {
if (window.noClip) {
continue;
@@ -4573,8 +4678,17 @@ if (this.p.isFlying || this.p.isUfo) {
this.killPlayer();
return;
}
+ const _sDist = Math.abs(playersY - playersLastY);
+ const _normalLandBot = _0x146a97 >= bottom && _0x146a97 - bottom <= _sDist + gamemodeAddition;
+ const _coyoteBot = this.p.onGround && !this._slopeRiding && this._slopeExitGrace === 0 && _0x146a97 >= bottom && _0x146a97 - bottom < playerSize + gamemodeAddition;
+ const _skipBot = _0x146a97 < bottom && _0x869e42 >= bottom;
+ const _landBot = _normalLandBot || _coyoteBot || _skipBot;
+ const _normalLandTop = _0x3e7199 <= top && top - _0x3e7199 <= _sDist + gamemodeAddition;
+ const _coyoteTop = this.p.onGround && !this._slopeRiding && this._slopeExitGrace === 0 && _0x3e7199 <= top && top - _0x3e7199 < playerSize + gamemodeAddition;
+ const _skipTop = _0x3e7199 > top && _0x135a9d <= top;
+ const _landTop = _normalLandTop || _coyoteTop || _skipTop;
if (pieceWidth + playerSize - 5 > left && pieceWidth - playerSize + 5 < right) {
- if (!this.p.gravityFlipped && (_0x146a97 >= bottom || _0x869e42 >= bottom) && (this.p.yVelocity <= 0 || this.p.onGround)) {
+ if (!this.p.gravityFlipped && _landBot && (this.p.yVelocity <= 0 || this.p.onGround)) {
this.p.y = bottom + playerSize;
this.hitGround();
_0x30410f = true;
@@ -4584,7 +4698,7 @@ if (this.p.isFlying || this.p.isUfo) {
}
continue;
}
- if (this.p.gravityFlipped && !this.p.isFlying && (_0x3e7199 <= top || _0x135a9d <= top) && (this.p.yVelocity >= 0 || this.p.onGround)) {
+ if (this.p.gravityFlipped && !this.p.isFlying && _landTop && (this.p.yVelocity >= 0 || this.p.onGround)) {
this.p.y = top - playerSize;
this.hitGround();
_0x30410f = true;
@@ -4596,14 +4710,14 @@ if (this.p.isFlying || this.p.isUfo) {
continue;
}
if (this.p.isUfo) {
- if (!this.p.gravityFlipped && (_0x3e7199 <= top || _0x135a9d <= top) && (this.p.yVelocity >= 0 || this.p.onGround)) {
+ if (!this.p.gravityFlipped && _landTop && (this.p.yVelocity >= 0 || this.p.onGround)) {
this.p.y = top - playerSize;
this.hitGround();
this.p.onCeiling = true;
this.p.collideTop = top;
continue;
}
- if (this.p.gravityFlipped && (_0x146a97 >= bottom || _0x869e42 >= bottom) && (this.p.yVelocity <= 0 || this.p.onGround)) {
+ if (this.p.gravityFlipped && _landBot && (this.p.yVelocity <= 0 || this.p.onGround)) {
this.p.y = bottom + playerSize;
this.hitGround();
_0x30410f = true;
@@ -4613,7 +4727,7 @@ if (this.p.isFlying || this.p.isUfo) {
}
continue;
}
- if ((_0x3e7199 <= top || _0x135a9d <= top) && (this.p.yVelocity >= 0 || this.p.onGround) && this.p.isFlying) {
+ if (_landTop && (this.p.yVelocity >= 0 || this.p.onGround) && this.p.isFlying) {
this.p.y = top - playerSize;
this.hitGround();
this.p.onCeiling = true;
@@ -4630,7 +4744,7 @@ if (this.p.isFlying || this.p.isUfo) {
}
continue;
}
- if (this.p.gravityFlipped && (_0x146a97 >= bottom || _0x869e42 >= bottom) && (this.p.yVelocity <= 0 || this.p.onGround) && this.p.isFlying) {
+ if (this.p.gravityFlipped && _landBot && (this.p.yVelocity <= 0 || this.p.onGround) && this.p.isFlying) {
this.p.y = bottom + playerSize;
this.hitGround();
_0x30410f = true;
@@ -4642,9 +4756,14 @@ if (this.p.isFlying || this.p.isUfo) {
}
}
}
+ if (bestSlopeCandidate && _boostedThisStep && window.slopeBoostSkipSnap !== false) {
+ this._skipSlopeExit = true;
+ bestSlopeCandidate = null;
+ }
if (bestSlopeCandidate) {
+ const _wasJumpingSlope = this.p.isJumping;
this.p.y = bestSlopeCandidate.y;
- this.hitGround();
+ this.hitGround(true);
this.p.onCeiling = !!bestSlopeCandidate.onCeiling;
if (bestSlopeCandidate.collideBottom !== null) this.p.collideBottom = bestSlopeCandidate.collideBottom;
if (bestSlopeCandidate.collideTop !== null) this.p.collideTop = bestSlopeCandidate.collideTop;
@@ -4655,10 +4774,27 @@ if (this.p.isFlying || this.p.isUfo) {
this._activeSlopeObj = bestSlopeGameObj;
this._activeSlopeAngle = bestSlopeCandidate.slopeAngle;
_0x30410f = true;
+ if (bestSlopeCandidate.blocked) {
+ _slopeBlockedThisStep = true;
+ } else if (!_wasJumpingSlope) {
+ _snappedSlopeThisFrame = true;
+ _slopeTangentThisFrame = bestSlopeCandidate.tangent;
+ if (bestSlopeCandidate.ridePush !== undefined) {
+ this._slopeRidePush = bestSlopeCandidate.ridePush;
+ }
+ }
if (!this.p.isFlying && !this.p.isWave) {
this._checkSnapJump(bestSlopeGameObj);
}
}
+ if (_slopeKillPending && !bestSlopeCandidate && !_0x30410f) {
+ if (window.noClip) {
+ this.p.diedThisFrame = true;
+ } else {
+ this.killPlayer();
+ return;
+ }
+ }
if (this.p.collideTop !== 0 && this.p.collideBottom !== 0) {
if (Math.abs(this.p.collideTop - this.p.collideBottom) < 48) {
if (window.noClip) this.p.diedThisFrame = true;
@@ -4735,25 +4871,21 @@ if (this.p.isFlying || this.p.isUfo) {
if (this._ignoreTeleportUntilClear && !_touchingTeleportDuringRespawnIgnore) {
this._ignoreTeleportUntilClear = false;
}
- if (bestSlopeCandidate) {
- this.p.y = bestSlopeCandidate.y;
- this.hitGround();
- this.p.onCeiling = !!bestSlopeCandidate.onCeiling;
- if (bestSlopeCandidate.collideBottom !== null) this.p.collideBottom = bestSlopeCandidate.collideBottom;
- if (bestSlopeCandidate.collideTop !== null) this.p.collideTop = bestSlopeCandidate.collideTop;
- this._onSlopeAngle = bestSlopeCandidate.slopeAngle;
- if (this._prevSlopeObj !== bestSlopeGameObj) {
- this._slopeEntryX = pieceWidth;
- }
- this._activeSlopeObj = bestSlopeGameObj;
- this._activeSlopeAngle = bestSlopeCandidate.slopeAngle;
- _0x30410f = true;
- if (!this.p.isFlying && !this.p.isWave) {
- this._checkSnapJump(bestSlopeGameObj);
- }
- }
- if (this._prevSlopeObj && !this._activeSlopeObj) {
- this._applySlopeExitBounce(this._prevSlopeObj, this._prevSlopeAngle, pieceWidth);
+ if (_snappedSlopeThisFrame) {
+ this._slopeContactFrames = this._slopeRiding ? (this._slopeContactFrames || 0) + 1 : 0;
+ this._slopeRiding = true;
+ this._slopeExitVel = _slopeTangentThisFrame;
+ this._slopeExitGrace = 20;
+ } else if (this._slopeRiding) {
+ this._slopeRiding = false;
+ if (!_slopeBlockedThisStep) {
+ this._applySlopeExitVelocity();
+ }
+ this._slopeExitVel = null;
+ }
+ this._skipSlopeExit = false;
+ if (this._slopeExitGrace > 0 && !this._slopeRiding) {
+ this._slopeExitGrace--;
}
if (this.p.isFlying || this.p.isWave || this.p.isUfo || this.p.isSpider) {
const _0x354b7c = this.p.y <= _0x3020c8 + _effectiveSize;
diff --git a/index.html b/index.html
index b099db67..8d033615 100644
--- a/index.html
+++ b/index.html
@@ -45,7 +45,7 @@
-
+