quake2ts 0.0.297 → 0.0.298
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/packages/cgame/dist/index.cjs +3 -1
- package/packages/cgame/dist/index.cjs.map +1 -1
- package/packages/cgame/dist/index.js +3 -1
- package/packages/cgame/dist/index.js.map +1 -1
- package/packages/client/dist/browser/index.global.js +13 -13
- package/packages/client/dist/browser/index.global.js.map +1 -1
- package/packages/client/dist/cjs/index.cjs +9 -9
- package/packages/client/dist/cjs/index.cjs.map +1 -1
- package/packages/client/dist/esm/index.js +9 -9
- package/packages/client/dist/esm/index.js.map +1 -1
- package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/engine/dist/browser/index.global.js +8 -8
- package/packages/engine/dist/browser/index.global.js.map +1 -1
- package/packages/engine/dist/cjs/index.cjs.map +1 -1
- package/packages/engine/dist/esm/index.js.map +1 -1
- package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/game/dist/browser/index.global.js +4 -4
- package/packages/game/dist/browser/index.global.js.map +1 -1
- package/packages/game/dist/cjs/index.cjs +67 -20
- package/packages/game/dist/cjs/index.cjs.map +1 -1
- package/packages/game/dist/esm/index.js +67 -20
- package/packages/game/dist/esm/index.js.map +1 -1
- package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/game/dist/types/ai/movement.d.ts.map +1 -1
- package/packages/shared/dist/browser/index.global.js +1 -1
- package/packages/shared/dist/browser/index.global.js.map +1 -1
- package/packages/shared/dist/cjs/index.cjs +1342 -1038
- package/packages/shared/dist/cjs/index.cjs.map +1 -1
- package/packages/shared/dist/esm/index.js +1340 -1038
- package/packages/shared/dist/esm/index.js.map +1 -1
- package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/shared/dist/types/pmove/jump.d.ts +2 -0
- package/packages/shared/dist/types/pmove/jump.d.ts.map +1 -1
- package/packages/shared/dist/types/pmove/move.d.ts +20 -0
- package/packages/shared/dist/types/pmove/move.d.ts.map +1 -1
- package/packages/shared/dist/types/pmove/pmove.d.ts +5 -1
- package/packages/shared/dist/types/pmove/pmove.d.ts.map +1 -1
- package/packages/shared/dist/types/pmove/types.d.ts +25 -1
- package/packages/shared/dist/types/pmove/types.d.ts.map +1 -1
- package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
|
@@ -199,6 +199,7 @@ __export(index_exports, {
|
|
|
199
199
|
applyPmoveAirMove: () => applyPmoveAirMove,
|
|
200
200
|
applyPmoveFlyMove: () => applyPmoveFlyMove,
|
|
201
201
|
applyPmoveFriction: () => applyPmoveFriction,
|
|
202
|
+
applyPmoveWalkMove: () => applyPmoveWalkMove,
|
|
202
203
|
applyPmoveWaterMove: () => applyPmoveWaterMove,
|
|
203
204
|
assertContract: () => assertContract,
|
|
204
205
|
attenuationToDistanceMultiplier: () => attenuationToDistanceMultiplier,
|
|
@@ -274,6 +275,7 @@ __export(index_exports, {
|
|
|
274
275
|
removePmFlag: () => removePmFlag,
|
|
275
276
|
resolveSlideMove: () => resolveSlideMove,
|
|
276
277
|
rotatePointAroundVector: () => rotatePointAroundVector,
|
|
278
|
+
runPmove: () => runPmove,
|
|
277
279
|
scaleVec3: () => scaleVec3,
|
|
278
280
|
slerpVec3: () => slerpVec3,
|
|
279
281
|
slideClipVelocityVec3: () => slideClipVelocityVec3,
|
|
@@ -2132,206 +2134,301 @@ var PmType = /* @__PURE__ */ ((PmType2) => {
|
|
|
2132
2134
|
PmType2[PmType2["Freeze"] = 6] = "Freeze";
|
|
2133
2135
|
return PmType2;
|
|
2134
2136
|
})(PmType || {});
|
|
2135
|
-
var PlayerButton = /* @__PURE__ */ ((
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
return
|
|
2137
|
+
var PlayerButton = /* @__PURE__ */ ((PlayerButton3) => {
|
|
2138
|
+
PlayerButton3[PlayerButton3["None"] = 0] = "None";
|
|
2139
|
+
PlayerButton3[PlayerButton3["Attack"] = 1] = "Attack";
|
|
2140
|
+
PlayerButton3[PlayerButton3["Use"] = 2] = "Use";
|
|
2141
|
+
PlayerButton3[PlayerButton3["Holster"] = 4] = "Holster";
|
|
2142
|
+
PlayerButton3[PlayerButton3["Jump"] = 8] = "Jump";
|
|
2143
|
+
PlayerButton3[PlayerButton3["Crouch"] = 16] = "Crouch";
|
|
2144
|
+
PlayerButton3[PlayerButton3["Any"] = 128] = "Any";
|
|
2145
|
+
return PlayerButton3;
|
|
2144
2146
|
})(PlayerButton || {});
|
|
2145
2147
|
|
|
2146
|
-
// src/pmove/
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
pmFriction,
|
|
2156
|
-
pmStopSpeed,
|
|
2157
|
-
pmWaterFriction
|
|
2158
|
-
} = params;
|
|
2159
|
-
const speed = lengthVec3(velocity);
|
|
2160
|
-
if (speed < 1) {
|
|
2161
|
-
return { x: 0, y: 0, z: velocity.z };
|
|
2148
|
+
// src/pmove/jump.ts
|
|
2149
|
+
var DEFAULT_JUMP_HEIGHT = 270;
|
|
2150
|
+
function hasButton(buttons, button) {
|
|
2151
|
+
return (buttons & button) !== 0;
|
|
2152
|
+
}
|
|
2153
|
+
function checkJump(params) {
|
|
2154
|
+
const { pmFlags, pmType, buttons, waterlevel, onGround, velocity, origin, jumpHeight = DEFAULT_JUMP_HEIGHT } = params;
|
|
2155
|
+
if (pmFlags & 16 /* TimeLand */) {
|
|
2156
|
+
return { pmFlags, onGround, velocity, origin, jumpSound: false, jumped: false };
|
|
2162
2157
|
}
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2158
|
+
const holdingJump = hasButton(buttons, 8 /* Jump */);
|
|
2159
|
+
let nextFlags = pmFlags;
|
|
2160
|
+
let nextOnGround = onGround;
|
|
2161
|
+
let jumpSound = false;
|
|
2162
|
+
let jumped = false;
|
|
2163
|
+
let nextVelocity = velocity;
|
|
2164
|
+
let nextOrigin = origin;
|
|
2165
|
+
if (!holdingJump) {
|
|
2166
|
+
nextFlags = removePmFlag(nextFlags, 2 /* JumpHeld */);
|
|
2167
|
+
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
|
|
2168
2168
|
}
|
|
2169
|
-
if (
|
|
2170
|
-
|
|
2169
|
+
if (hasPmJumpHold(nextFlags)) {
|
|
2170
|
+
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
|
|
2171
2171
|
}
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
newspeed = 0;
|
|
2172
|
+
if (pmType === 4 /* Dead */) {
|
|
2173
|
+
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
|
|
2175
2174
|
}
|
|
2176
|
-
if (
|
|
2177
|
-
|
|
2175
|
+
if (waterlevel >= 2 /* Waist */) {
|
|
2176
|
+
nextOnGround = false;
|
|
2177
|
+
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
|
|
2178
2178
|
}
|
|
2179
|
-
|
|
2180
|
-
|
|
2179
|
+
if (!nextOnGround) {
|
|
2180
|
+
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
|
|
2181
|
+
}
|
|
2182
|
+
nextFlags = addPmFlag(nextFlags, 2 /* JumpHeld */);
|
|
2183
|
+
nextFlags = removePmFlag(nextFlags, 4 /* OnGround */);
|
|
2184
|
+
nextOnGround = false;
|
|
2185
|
+
jumpSound = true;
|
|
2186
|
+
jumped = true;
|
|
2187
|
+
const z = velocity.z + jumpHeight;
|
|
2188
|
+
const finalZ = z < jumpHeight ? jumpHeight : z;
|
|
2189
|
+
nextVelocity = { ...velocity, z: finalZ };
|
|
2190
|
+
nextOrigin = { ...origin, z: origin.z + 1 };
|
|
2191
|
+
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
|
|
2181
2192
|
}
|
|
2182
|
-
function
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2193
|
+
function hasPmJumpHold(flags) {
|
|
2194
|
+
return (flags & 2 /* JumpHeld */) !== 0;
|
|
2195
|
+
}
|
|
2196
|
+
|
|
2197
|
+
// src/pmove/currents.ts
|
|
2198
|
+
var DEFAULT_GROUND_CURRENT_SCALE = 100;
|
|
2199
|
+
var DEFAULT_FORWARD_LADDER_CLAMP = 200;
|
|
2200
|
+
var DEFAULT_SIDE_LADDER_CLAMP = 150;
|
|
2201
|
+
var LADDER_HORIZONTAL_CAP = 25;
|
|
2202
|
+
var LADDER_ASCEND_PITCH_THRESHOLD = 15;
|
|
2203
|
+
var LADDER_TRACE_DISTANCE = 1;
|
|
2204
|
+
var UP_VECTOR = { x: 0, y: 0, z: 1 };
|
|
2205
|
+
var DEFAULT_TRACE = (_, end) => ({
|
|
2206
|
+
fraction: 1,
|
|
2207
|
+
endpos: end,
|
|
2208
|
+
allsolid: false,
|
|
2209
|
+
startsolid: false
|
|
2210
|
+
});
|
|
2211
|
+
function currentVectorFromContents(contents) {
|
|
2212
|
+
let x = 0;
|
|
2213
|
+
let y = 0;
|
|
2214
|
+
let z = 0;
|
|
2215
|
+
if (contents & CONTENTS_CURRENT_0) {
|
|
2216
|
+
x += 1;
|
|
2188
2217
|
}
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
accelSpeed = addSpeed;
|
|
2218
|
+
if (contents & CONTENTS_CURRENT_90) {
|
|
2219
|
+
y += 1;
|
|
2192
2220
|
}
|
|
2193
|
-
|
|
2194
|
-
x
|
|
2195
|
-
y: velocity.y + wishdir.y * accelSpeed,
|
|
2196
|
-
z: velocity.z + wishdir.z * accelSpeed
|
|
2197
|
-
};
|
|
2198
|
-
}
|
|
2199
|
-
function applyPmoveAirAccelerate(params) {
|
|
2200
|
-
const { velocity, wishdir, wishspeed, accel, frametime } = params;
|
|
2201
|
-
const wishspd = Math.min(wishspeed, 30);
|
|
2202
|
-
const currentSpeed = dotVec3(velocity, wishdir);
|
|
2203
|
-
const addSpeed = wishspd - currentSpeed;
|
|
2204
|
-
if (addSpeed <= 0) {
|
|
2205
|
-
return velocity;
|
|
2221
|
+
if (contents & CONTENTS_CURRENT_180) {
|
|
2222
|
+
x -= 1;
|
|
2206
2223
|
}
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
accelSpeed = addSpeed;
|
|
2224
|
+
if (contents & CONTENTS_CURRENT_270) {
|
|
2225
|
+
y -= 1;
|
|
2210
2226
|
}
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
y: velocity.y + wishdir.y * accelSpeed,
|
|
2214
|
-
z: velocity.z + wishdir.z * accelSpeed
|
|
2215
|
-
};
|
|
2216
|
-
}
|
|
2217
|
-
function pmoveCmdScale(cmd, maxSpeed) {
|
|
2218
|
-
const forward = Math.abs(cmd.forwardmove);
|
|
2219
|
-
const side = Math.abs(cmd.sidemove);
|
|
2220
|
-
const up = Math.abs(cmd.upmove);
|
|
2221
|
-
const max = Math.max(forward, side, up);
|
|
2222
|
-
if (max === 0) {
|
|
2223
|
-
return 0;
|
|
2227
|
+
if (contents & CONTENTS_CURRENT_UP) {
|
|
2228
|
+
z += 1;
|
|
2224
2229
|
}
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
}
|
|
2228
|
-
function buildAirGroundWish(params) {
|
|
2229
|
-
const { forward, right, cmd, maxSpeed } = params;
|
|
2230
|
-
let wishvel = {
|
|
2231
|
-
x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
|
|
2232
|
-
y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
|
|
2233
|
-
z: 0
|
|
2234
|
-
};
|
|
2235
|
-
let wishspeed = lengthVec3(wishvel);
|
|
2236
|
-
if (wishspeed > maxSpeed) {
|
|
2237
|
-
const scale = maxSpeed / wishspeed;
|
|
2238
|
-
wishvel = scaleVec3(wishvel, scale);
|
|
2239
|
-
wishspeed = maxSpeed;
|
|
2230
|
+
if (contents & CONTENTS_CURRENT_DOWN) {
|
|
2231
|
+
z -= 1;
|
|
2240
2232
|
}
|
|
2241
|
-
|
|
2242
|
-
|
|
2243
|
-
|
|
2244
|
-
};
|
|
2233
|
+
if (x === 0 && y === 0 && z === 0) {
|
|
2234
|
+
return ZERO_VEC3;
|
|
2235
|
+
}
|
|
2236
|
+
return { x, y, z };
|
|
2245
2237
|
}
|
|
2246
|
-
function
|
|
2247
|
-
const {
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
|
|
2251
|
-
z: forward.z * cmd.forwardmove + right.z * cmd.sidemove
|
|
2252
|
-
};
|
|
2253
|
-
if (cmd.upmove > 10) {
|
|
2254
|
-
wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
|
|
2255
|
-
} else if (cmd.upmove < -10) {
|
|
2256
|
-
wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
|
|
2257
|
-
} else if (Math.abs(cmd.forwardmove) < 10 && Math.abs(cmd.sidemove) < 10) {
|
|
2258
|
-
wishvel = addVec3(wishvel, { x: 0, y: 0, z: -60 });
|
|
2259
|
-
} else {
|
|
2260
|
-
wishvel = addVec3(wishvel, { x: 0, y: 0, z: 10 });
|
|
2238
|
+
function waterCurrentVelocity(params) {
|
|
2239
|
+
const { watertype, waterlevel, onGround, waterSpeed } = params;
|
|
2240
|
+
if ((watertype & MASK_CURRENT) === 0) {
|
|
2241
|
+
return ZERO_VEC3;
|
|
2261
2242
|
}
|
|
2262
|
-
|
|
2263
|
-
if (
|
|
2264
|
-
|
|
2265
|
-
wishvel = scaleVec3(wishvel, scale);
|
|
2266
|
-
wishspeed = maxSpeed;
|
|
2243
|
+
const direction = currentVectorFromContents(watertype);
|
|
2244
|
+
if (direction === ZERO_VEC3) {
|
|
2245
|
+
return ZERO_VEC3;
|
|
2267
2246
|
}
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
|
|
2271
|
-
wishspeed
|
|
2272
|
-
};
|
|
2273
|
-
}
|
|
2274
|
-
|
|
2275
|
-
// src/pmove/slide.ts
|
|
2276
|
-
var DEFAULT_MAX_CLIP_PLANES = 5;
|
|
2277
|
-
var DEFAULT_MAX_BUMPS = 4;
|
|
2278
|
-
var DEFAULT_STEP_SIZE = 18;
|
|
2279
|
-
var MIN_STEP_NORMAL = 0.7;
|
|
2280
|
-
var SLIDEMOVE_BLOCKED_FLOOR = 1;
|
|
2281
|
-
var SLIDEMOVE_BLOCKED_WALL = 2;
|
|
2282
|
-
function resolveSlideMove(initialVelocity, planesEncountered, overbounce, maxClipPlanes = DEFAULT_MAX_CLIP_PLANES, primalVelocity = initialVelocity) {
|
|
2283
|
-
if (planesEncountered.length === 0) {
|
|
2284
|
-
return { velocity: initialVelocity, planes: [], stopped: false };
|
|
2247
|
+
let scale = waterSpeed;
|
|
2248
|
+
if (waterlevel === 1 /* Feet */ && onGround) {
|
|
2249
|
+
scale *= 0.5;
|
|
2285
2250
|
}
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
if (duplicate) {
|
|
2294
|
-
continue;
|
|
2295
|
-
}
|
|
2296
|
-
planes.push(plane);
|
|
2297
|
-
let clipped;
|
|
2298
|
-
let i = 0;
|
|
2299
|
-
for (; i < planes.length; i++) {
|
|
2300
|
-
const candidate = clipVelocityVec3(velocity, planes[i], overbounce);
|
|
2301
|
-
let j = 0;
|
|
2302
|
-
for (; j < planes.length; j++) {
|
|
2303
|
-
if (j === i) continue;
|
|
2304
|
-
if (dotVec3(candidate, planes[j]) < 0) break;
|
|
2305
|
-
}
|
|
2306
|
-
if (j === planes.length) {
|
|
2307
|
-
clipped = candidate;
|
|
2308
|
-
break;
|
|
2309
|
-
}
|
|
2310
|
-
}
|
|
2311
|
-
if (clipped) {
|
|
2312
|
-
velocity = clipped;
|
|
2313
|
-
} else {
|
|
2314
|
-
if (planes.length !== 2) {
|
|
2315
|
-
return { velocity: ZERO_VEC3, planes, stopped: true };
|
|
2316
|
-
}
|
|
2317
|
-
const dir = crossVec3(planes[0], planes[1]);
|
|
2318
|
-
const d = dotVec3(dir, velocity);
|
|
2319
|
-
velocity = scaleVec3(dir, d);
|
|
2320
|
-
}
|
|
2321
|
-
if (dotVec3(velocity, primalVelocity) <= 0) {
|
|
2322
|
-
return { velocity: ZERO_VEC3, planes, stopped: true };
|
|
2323
|
-
}
|
|
2251
|
+
return scaleVec3(direction, scale);
|
|
2252
|
+
}
|
|
2253
|
+
function groundCurrentVelocity(params) {
|
|
2254
|
+
const { groundContents, scale = DEFAULT_GROUND_CURRENT_SCALE } = params;
|
|
2255
|
+
const direction = currentVectorFromContents(groundContents);
|
|
2256
|
+
if (direction === ZERO_VEC3) {
|
|
2257
|
+
return ZERO_VEC3;
|
|
2324
2258
|
}
|
|
2325
|
-
|
|
2326
|
-
return { velocity, planes, stopped };
|
|
2259
|
+
return scaleVec3(direction, scale);
|
|
2327
2260
|
}
|
|
2328
|
-
function
|
|
2261
|
+
function applyPmoveAddCurrents(params) {
|
|
2329
2262
|
const {
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2263
|
+
wishVelocity,
|
|
2264
|
+
onLadder,
|
|
2265
|
+
onGround,
|
|
2266
|
+
waterlevel,
|
|
2267
|
+
watertype,
|
|
2268
|
+
groundContents,
|
|
2269
|
+
cmd,
|
|
2270
|
+
viewPitch,
|
|
2271
|
+
maxSpeed,
|
|
2272
|
+
ladderMod,
|
|
2273
|
+
waterSpeed,
|
|
2274
|
+
forward,
|
|
2275
|
+
origin,
|
|
2276
|
+
mins,
|
|
2277
|
+
maxs,
|
|
2278
|
+
trace = DEFAULT_TRACE
|
|
2279
|
+
} = params;
|
|
2280
|
+
let adjusted = wishVelocity;
|
|
2281
|
+
if (onLadder) {
|
|
2282
|
+
adjusted = applyLadderAdjustments({
|
|
2283
|
+
wishVelocity: adjusted,
|
|
2284
|
+
cmd,
|
|
2285
|
+
waterlevel,
|
|
2286
|
+
viewPitch,
|
|
2287
|
+
maxSpeed,
|
|
2288
|
+
ladderMod,
|
|
2289
|
+
onGround,
|
|
2290
|
+
forward,
|
|
2291
|
+
origin,
|
|
2292
|
+
mins,
|
|
2293
|
+
maxs,
|
|
2294
|
+
trace
|
|
2295
|
+
});
|
|
2296
|
+
}
|
|
2297
|
+
const waterVelocity = waterCurrentVelocity({ watertype, waterlevel, onGround, waterSpeed });
|
|
2298
|
+
if (waterVelocity !== ZERO_VEC3) {
|
|
2299
|
+
adjusted = addVec3(adjusted, waterVelocity);
|
|
2300
|
+
}
|
|
2301
|
+
if (onGround) {
|
|
2302
|
+
const groundVelocity = groundCurrentVelocity({ groundContents });
|
|
2303
|
+
if (groundVelocity !== ZERO_VEC3) {
|
|
2304
|
+
adjusted = addVec3(adjusted, groundVelocity);
|
|
2305
|
+
}
|
|
2306
|
+
}
|
|
2307
|
+
return adjusted;
|
|
2308
|
+
}
|
|
2309
|
+
function applyLadderAdjustments(params) {
|
|
2310
|
+
const { wishVelocity, cmd, waterlevel, viewPitch, maxSpeed, ladderMod, onGround, forward, origin, mins, maxs, trace } = params;
|
|
2311
|
+
const buttons = cmd.buttons ?? 0;
|
|
2312
|
+
let adjusted = { ...wishVelocity };
|
|
2313
|
+
if ((buttons & (8 /* Jump */ | 16 /* Crouch */)) !== 0) {
|
|
2314
|
+
const ladderSpeed = isAtLeastWaistDeep(waterlevel) ? maxSpeed : DEFAULT_FORWARD_LADDER_CLAMP;
|
|
2315
|
+
adjusted = {
|
|
2316
|
+
...adjusted,
|
|
2317
|
+
z: buttons & 8 /* Jump */ ? ladderSpeed : -ladderSpeed
|
|
2318
|
+
};
|
|
2319
|
+
} else if (cmd.forwardmove) {
|
|
2320
|
+
const clamped = clamp(cmd.forwardmove, -DEFAULT_FORWARD_LADDER_CLAMP, DEFAULT_FORWARD_LADDER_CLAMP);
|
|
2321
|
+
if (cmd.forwardmove > 0) {
|
|
2322
|
+
const climb = viewPitch < LADDER_ASCEND_PITCH_THRESHOLD ? clamped : -clamped;
|
|
2323
|
+
adjusted = { ...adjusted, z: climb };
|
|
2324
|
+
} else {
|
|
2325
|
+
if (!onGround) {
|
|
2326
|
+
adjusted = { ...adjusted, x: 0, y: 0 };
|
|
2327
|
+
}
|
|
2328
|
+
adjusted = { ...adjusted, z: clamped };
|
|
2329
|
+
}
|
|
2330
|
+
} else {
|
|
2331
|
+
adjusted = { ...adjusted, z: 0 };
|
|
2332
|
+
}
|
|
2333
|
+
if (!onGround) {
|
|
2334
|
+
if (cmd.sidemove) {
|
|
2335
|
+
let sideSpeed = clamp(cmd.sidemove, -DEFAULT_SIDE_LADDER_CLAMP, DEFAULT_SIDE_LADDER_CLAMP);
|
|
2336
|
+
if (waterlevel < 2 /* Waist */) {
|
|
2337
|
+
sideSpeed *= ladderMod;
|
|
2338
|
+
}
|
|
2339
|
+
const flatForward = normalizeVec3({ x: forward.x, y: forward.y, z: 0 });
|
|
2340
|
+
if (flatForward.x !== 0 || flatForward.y !== 0) {
|
|
2341
|
+
const spot = addVec3(origin, scaleVec3(flatForward, LADDER_TRACE_DISTANCE));
|
|
2342
|
+
const tr = trace(origin, spot, mins, maxs);
|
|
2343
|
+
if (tr.fraction !== 1 && !tr.allsolid && tr.contents !== void 0 && (tr.contents & CONTENTS_LADDER) !== 0 && tr.planeNormal) {
|
|
2344
|
+
const right = crossVec3(tr.planeNormal, UP_VECTOR);
|
|
2345
|
+
adjusted = { ...adjusted, x: 0, y: 0 };
|
|
2346
|
+
adjusted = addVec3(adjusted, scaleVec3(right, -sideSpeed));
|
|
2347
|
+
}
|
|
2348
|
+
}
|
|
2349
|
+
} else {
|
|
2350
|
+
adjusted = {
|
|
2351
|
+
...adjusted,
|
|
2352
|
+
x: clampHorizontal(adjusted.x),
|
|
2353
|
+
y: clampHorizontal(adjusted.y)
|
|
2354
|
+
};
|
|
2355
|
+
}
|
|
2356
|
+
}
|
|
2357
|
+
return adjusted;
|
|
2358
|
+
}
|
|
2359
|
+
function clamp(value, min, max) {
|
|
2360
|
+
return Math.max(min, Math.min(max, value));
|
|
2361
|
+
}
|
|
2362
|
+
function clampHorizontal(value) {
|
|
2363
|
+
if (value < -LADDER_HORIZONTAL_CAP) {
|
|
2364
|
+
return -LADDER_HORIZONTAL_CAP;
|
|
2365
|
+
}
|
|
2366
|
+
if (value > LADDER_HORIZONTAL_CAP) {
|
|
2367
|
+
return LADDER_HORIZONTAL_CAP;
|
|
2368
|
+
}
|
|
2369
|
+
return value;
|
|
2370
|
+
}
|
|
2371
|
+
|
|
2372
|
+
// src/pmove/slide.ts
|
|
2373
|
+
var DEFAULT_MAX_CLIP_PLANES = 5;
|
|
2374
|
+
var DEFAULT_MAX_BUMPS = 4;
|
|
2375
|
+
var DEFAULT_STEP_SIZE = 18;
|
|
2376
|
+
var MIN_STEP_NORMAL = 0.7;
|
|
2377
|
+
var SLIDEMOVE_BLOCKED_FLOOR = 1;
|
|
2378
|
+
var SLIDEMOVE_BLOCKED_WALL = 2;
|
|
2379
|
+
function resolveSlideMove(initialVelocity, planesEncountered, overbounce, maxClipPlanes = DEFAULT_MAX_CLIP_PLANES, primalVelocity = initialVelocity) {
|
|
2380
|
+
if (planesEncountered.length === 0) {
|
|
2381
|
+
return { velocity: initialVelocity, planes: [], stopped: false };
|
|
2382
|
+
}
|
|
2383
|
+
const planes = [];
|
|
2384
|
+
let velocity = initialVelocity;
|
|
2385
|
+
for (const plane of planesEncountered) {
|
|
2386
|
+
if (planes.length >= maxClipPlanes) {
|
|
2387
|
+
return { velocity: ZERO_VEC3, planes, stopped: true };
|
|
2388
|
+
}
|
|
2389
|
+
const duplicate = planes.find((existing) => dotVec3(existing, plane) > 0.99);
|
|
2390
|
+
if (duplicate) {
|
|
2391
|
+
continue;
|
|
2392
|
+
}
|
|
2393
|
+
planes.push(plane);
|
|
2394
|
+
let clipped;
|
|
2395
|
+
let i = 0;
|
|
2396
|
+
for (; i < planes.length; i++) {
|
|
2397
|
+
const candidate = clipVelocityVec3(velocity, planes[i], overbounce);
|
|
2398
|
+
let j = 0;
|
|
2399
|
+
for (; j < planes.length; j++) {
|
|
2400
|
+
if (j === i) continue;
|
|
2401
|
+
if (dotVec3(candidate, planes[j]) < 0) break;
|
|
2402
|
+
}
|
|
2403
|
+
if (j === planes.length) {
|
|
2404
|
+
clipped = candidate;
|
|
2405
|
+
break;
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
if (clipped) {
|
|
2409
|
+
velocity = clipped;
|
|
2410
|
+
} else {
|
|
2411
|
+
if (planes.length !== 2) {
|
|
2412
|
+
return { velocity: ZERO_VEC3, planes, stopped: true };
|
|
2413
|
+
}
|
|
2414
|
+
const dir = crossVec3(planes[0], planes[1]);
|
|
2415
|
+
const d = dotVec3(dir, velocity);
|
|
2416
|
+
velocity = scaleVec3(dir, d);
|
|
2417
|
+
}
|
|
2418
|
+
if (dotVec3(velocity, primalVelocity) <= 0) {
|
|
2419
|
+
return { velocity: ZERO_VEC3, planes, stopped: true };
|
|
2420
|
+
}
|
|
2421
|
+
}
|
|
2422
|
+
const stopped = velocity.x === 0 && velocity.y === 0 && velocity.z === 0;
|
|
2423
|
+
return { velocity, planes, stopped };
|
|
2424
|
+
}
|
|
2425
|
+
function slideMove(params) {
|
|
2426
|
+
const {
|
|
2427
|
+
origin: initialOrigin,
|
|
2428
|
+
velocity: initialVelocity,
|
|
2429
|
+
frametime,
|
|
2430
|
+
overbounce,
|
|
2431
|
+
trace,
|
|
2335
2432
|
maxBumps = DEFAULT_MAX_BUMPS,
|
|
2336
2433
|
maxClipPlanes = DEFAULT_MAX_CLIP_PLANES,
|
|
2337
2434
|
mins,
|
|
@@ -2430,250 +2527,45 @@ function stepSlideMove(params) {
|
|
|
2430
2527
|
};
|
|
2431
2528
|
}
|
|
2432
2529
|
|
|
2433
|
-
// src/pmove/
|
|
2434
|
-
var
|
|
2435
|
-
var
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
{ normal: [1, 0, 0], mins: [0, -1, -1], maxs: [0, 1, 1] },
|
|
2439
|
-
{ normal: [-1, 0, 0], mins: [0, -1, -1], maxs: [0, 1, 1] },
|
|
2440
|
-
{ normal: [0, 1, 0], mins: [-1, 0, -1], maxs: [1, 0, 1] },
|
|
2441
|
-
{ normal: [0, -1, 0], mins: [-1, 0, -1], maxs: [1, 0, 1] }
|
|
2442
|
-
];
|
|
2443
|
-
var ZERO_VEC = { x: 0, y: 0, z: 0 };
|
|
2444
|
-
function cloneMutable(vec) {
|
|
2445
|
-
return { x: vec.x, y: vec.y, z: vec.z };
|
|
2446
|
-
}
|
|
2447
|
-
function tupleToVec3(tuple) {
|
|
2448
|
-
return { x: tuple[0], y: tuple[1], z: tuple[2] };
|
|
2449
|
-
}
|
|
2450
|
-
function adjustAxis(vec, axis, delta) {
|
|
2451
|
-
if (delta === 0) return;
|
|
2452
|
-
switch (axis) {
|
|
2453
|
-
case "x":
|
|
2454
|
-
vec.x += delta;
|
|
2455
|
-
break;
|
|
2456
|
-
case "y":
|
|
2457
|
-
vec.y += delta;
|
|
2458
|
-
break;
|
|
2459
|
-
case "z":
|
|
2460
|
-
vec.z += delta;
|
|
2461
|
-
break;
|
|
2462
|
-
}
|
|
2463
|
-
}
|
|
2464
|
-
function setAxis(vec, axis, value) {
|
|
2465
|
-
switch (axis) {
|
|
2466
|
-
case "x":
|
|
2467
|
-
vec.x = value;
|
|
2468
|
-
break;
|
|
2469
|
-
case "y":
|
|
2470
|
-
vec.y = value;
|
|
2471
|
-
break;
|
|
2472
|
-
case "z":
|
|
2473
|
-
vec.z = value;
|
|
2474
|
-
break;
|
|
2475
|
-
}
|
|
2476
|
-
}
|
|
2477
|
-
function axisValue(vec, axis) {
|
|
2478
|
-
switch (axis) {
|
|
2479
|
-
case "x":
|
|
2480
|
-
return vec.x;
|
|
2481
|
-
case "y":
|
|
2482
|
-
return vec.y;
|
|
2483
|
-
case "z":
|
|
2484
|
-
default:
|
|
2485
|
-
return vec.z;
|
|
2486
|
-
}
|
|
2487
|
-
}
|
|
2488
|
-
function boundValue(code, axis, mins, maxs) {
|
|
2489
|
-
if (code === -1) {
|
|
2490
|
-
return axisValue(mins, axis);
|
|
2491
|
-
}
|
|
2492
|
-
if (code === 1) {
|
|
2493
|
-
return axisValue(maxs, axis);
|
|
2494
|
-
}
|
|
2495
|
-
return 0;
|
|
2496
|
-
}
|
|
2497
|
-
function applySideOffset(base, side, mins, maxs) {
|
|
2498
|
-
const result = cloneMutable(base);
|
|
2499
|
-
for (let i = 0; i < AXES.length; i++) {
|
|
2500
|
-
const axis = AXES[i];
|
|
2501
|
-
const normal = side.normal[i];
|
|
2502
|
-
if (normal < 0) {
|
|
2503
|
-
adjustAxis(result, axis, axisValue(mins, axis));
|
|
2504
|
-
} else if (normal > 0) {
|
|
2505
|
-
adjustAxis(result, axis, axisValue(maxs, axis));
|
|
2506
|
-
}
|
|
2507
|
-
}
|
|
2508
|
-
return result;
|
|
2509
|
-
}
|
|
2510
|
-
function buildSideBounds(side, mins, maxs) {
|
|
2511
|
-
const localMins = cloneMutable(ZERO_VEC);
|
|
2512
|
-
const localMaxs = cloneMutable(ZERO_VEC);
|
|
2513
|
-
for (let i = 0; i < AXES.length; i++) {
|
|
2514
|
-
const axis = AXES[i];
|
|
2515
|
-
setAxis(localMins, axis, boundValue(side.mins[i], axis, mins, maxs));
|
|
2516
|
-
setAxis(localMaxs, axis, boundValue(side.maxs[i], axis, mins, maxs));
|
|
2517
|
-
}
|
|
2518
|
-
return { mins: localMins, maxs: localMaxs };
|
|
2519
|
-
}
|
|
2520
|
-
function addEpsilon(source, axis, direction) {
|
|
2521
|
-
if (!axis || direction === 0) {
|
|
2522
|
-
return source;
|
|
2523
|
-
}
|
|
2524
|
-
const clone = cloneMutable(source);
|
|
2525
|
-
adjustAxis(clone, axis, direction);
|
|
2526
|
-
return clone;
|
|
2527
|
-
}
|
|
2528
|
-
function addEpsilonImmutable(vec, axis, direction) {
|
|
2529
|
-
if (!axis || direction === 0) {
|
|
2530
|
-
return vec;
|
|
2531
|
-
}
|
|
2532
|
-
switch (axis) {
|
|
2533
|
-
case "x":
|
|
2534
|
-
return { ...vec, x: vec.x + direction };
|
|
2535
|
-
case "y":
|
|
2536
|
-
return { ...vec, y: vec.y + direction };
|
|
2537
|
-
case "z":
|
|
2538
|
-
default:
|
|
2539
|
-
return { ...vec, z: vec.z + direction };
|
|
2540
|
-
}
|
|
2541
|
-
}
|
|
2542
|
-
function fixStuckObjectGeneric(params) {
|
|
2543
|
-
const { origin, mins, maxs, trace } = params;
|
|
2544
|
-
const initial = trace(origin, mins, maxs, origin);
|
|
2545
|
-
if (!initial.startsolid) {
|
|
2546
|
-
return { result: "good-position", origin: { ...origin } };
|
|
2547
|
-
}
|
|
2548
|
-
const candidates = [];
|
|
2549
|
-
for (let i = 0; i < SIDE_CHECKS.length; i++) {
|
|
2550
|
-
const side = SIDE_CHECKS[i];
|
|
2551
|
-
const { mins: localMins, maxs: localMaxs } = buildSideBounds(side, mins, maxs);
|
|
2552
|
-
let start = applySideOffset(origin, side, mins, maxs);
|
|
2553
|
-
let tr = trace(start, localMins, localMaxs, start);
|
|
2554
|
-
let epsilonAxis;
|
|
2555
|
-
let epsilonDir = 0;
|
|
2556
|
-
if (tr.startsolid) {
|
|
2557
|
-
for (let axisIndex = 0; axisIndex < AXES.length; axisIndex++) {
|
|
2558
|
-
if (side.normal[axisIndex] !== 0) {
|
|
2559
|
-
continue;
|
|
2560
|
-
}
|
|
2561
|
-
const axis = AXES[axisIndex];
|
|
2562
|
-
let epsilonStart = cloneMutable(start);
|
|
2563
|
-
adjustAxis(epsilonStart, axis, 1);
|
|
2564
|
-
tr = trace(epsilonStart, localMins, localMaxs, epsilonStart);
|
|
2565
|
-
if (!tr.startsolid) {
|
|
2566
|
-
start = epsilonStart;
|
|
2567
|
-
epsilonAxis = axis;
|
|
2568
|
-
epsilonDir = 1;
|
|
2569
|
-
break;
|
|
2570
|
-
}
|
|
2571
|
-
epsilonStart = cloneMutable(start);
|
|
2572
|
-
adjustAxis(epsilonStart, axis, -1);
|
|
2573
|
-
tr = trace(epsilonStart, localMins, localMaxs, epsilonStart);
|
|
2574
|
-
if (!tr.startsolid) {
|
|
2575
|
-
start = epsilonStart;
|
|
2576
|
-
epsilonAxis = axis;
|
|
2577
|
-
epsilonDir = -1;
|
|
2578
|
-
break;
|
|
2579
|
-
}
|
|
2580
|
-
}
|
|
2581
|
-
}
|
|
2582
|
-
if (tr.startsolid) {
|
|
2583
|
-
continue;
|
|
2584
|
-
}
|
|
2585
|
-
const otherSide = SIDE_CHECKS[i ^ 1];
|
|
2586
|
-
let oppositeStart = applySideOffset(origin, otherSide, mins, maxs);
|
|
2587
|
-
oppositeStart = addEpsilon(oppositeStart, epsilonAxis, epsilonDir);
|
|
2588
|
-
tr = trace(start, localMins, localMaxs, oppositeStart);
|
|
2589
|
-
if (tr.startsolid) {
|
|
2590
|
-
continue;
|
|
2591
|
-
}
|
|
2592
|
-
const normal = tupleToVec3(side.normal);
|
|
2593
|
-
const end = addVec3(tr.endpos ?? oppositeStart, scaleVec3(normal, 0.125));
|
|
2594
|
-
const delta = subtractVec3(end, oppositeStart);
|
|
2595
|
-
let newOrigin = addVec3(origin, delta);
|
|
2596
|
-
newOrigin = addEpsilonImmutable(newOrigin, epsilonAxis, epsilonDir);
|
|
2597
|
-
const validation = trace(newOrigin, mins, maxs, newOrigin);
|
|
2598
|
-
if (validation.startsolid) {
|
|
2599
|
-
continue;
|
|
2600
|
-
}
|
|
2601
|
-
candidates.push({ origin: newOrigin, distance: lengthSquaredVec3(delta) });
|
|
2602
|
-
}
|
|
2603
|
-
if (candidates.length === 0) {
|
|
2604
|
-
return { result: "no-good-position", origin: { ...origin } };
|
|
2605
|
-
}
|
|
2606
|
-
candidates.sort((a, b) => a.distance - b.distance);
|
|
2607
|
-
return { result: "fixed", origin: { ...candidates[0].origin } };
|
|
2608
|
-
}
|
|
2609
|
-
|
|
2610
|
-
// src/pmove/currents.ts
|
|
2611
|
-
var DEFAULT_GROUND_CURRENT_SCALE = 100;
|
|
2612
|
-
var DEFAULT_FORWARD_LADDER_CLAMP = 200;
|
|
2613
|
-
var DEFAULT_SIDE_LADDER_CLAMP = 150;
|
|
2614
|
-
var LADDER_HORIZONTAL_CAP = 25;
|
|
2615
|
-
var LADDER_ASCEND_PITCH_THRESHOLD = 15;
|
|
2616
|
-
var LADDER_TRACE_DISTANCE = 1;
|
|
2617
|
-
var UP_VECTOR = { x: 0, y: 0, z: 1 };
|
|
2618
|
-
var DEFAULT_TRACE = (_, end) => ({
|
|
2619
|
-
fraction: 1,
|
|
2620
|
-
endpos: end,
|
|
2621
|
-
allsolid: false,
|
|
2622
|
-
startsolid: false
|
|
2623
|
-
});
|
|
2624
|
-
function currentVectorFromContents(contents) {
|
|
2625
|
-
let x = 0;
|
|
2626
|
-
let y = 0;
|
|
2627
|
-
let z = 0;
|
|
2628
|
-
if (contents & CONTENTS_CURRENT_0) {
|
|
2629
|
-
x += 1;
|
|
2630
|
-
}
|
|
2631
|
-
if (contents & CONTENTS_CURRENT_90) {
|
|
2632
|
-
y += 1;
|
|
2633
|
-
}
|
|
2634
|
-
if (contents & CONTENTS_CURRENT_180) {
|
|
2635
|
-
x -= 1;
|
|
2636
|
-
}
|
|
2637
|
-
if (contents & CONTENTS_CURRENT_270) {
|
|
2638
|
-
y -= 1;
|
|
2639
|
-
}
|
|
2640
|
-
if (contents & CONTENTS_CURRENT_UP) {
|
|
2641
|
-
z += 1;
|
|
2642
|
-
}
|
|
2643
|
-
if (contents & CONTENTS_CURRENT_DOWN) {
|
|
2644
|
-
z -= 1;
|
|
2645
|
-
}
|
|
2646
|
-
if (x === 0 && y === 0 && z === 0) {
|
|
2647
|
-
return ZERO_VEC3;
|
|
2648
|
-
}
|
|
2649
|
-
return { x, y, z };
|
|
2650
|
-
}
|
|
2651
|
-
function waterCurrentVelocity(params) {
|
|
2652
|
-
const { watertype, waterlevel, onGround, waterSpeed } = params;
|
|
2653
|
-
if ((watertype & MASK_CURRENT) === 0) {
|
|
2654
|
-
return ZERO_VEC3;
|
|
2655
|
-
}
|
|
2656
|
-
const direction = currentVectorFromContents(watertype);
|
|
2657
|
-
if (direction === ZERO_VEC3) {
|
|
2658
|
-
return ZERO_VEC3;
|
|
2659
|
-
}
|
|
2660
|
-
let scale = waterSpeed;
|
|
2661
|
-
if (waterlevel === 1 /* Feet */ && onGround) {
|
|
2662
|
-
scale *= 0.5;
|
|
2663
|
-
}
|
|
2664
|
-
return scaleVec3(direction, scale);
|
|
2665
|
-
}
|
|
2666
|
-
function groundCurrentVelocity(params) {
|
|
2667
|
-
const { groundContents, scale = DEFAULT_GROUND_CURRENT_SCALE } = params;
|
|
2668
|
-
const direction = currentVectorFromContents(groundContents);
|
|
2669
|
-
if (direction === ZERO_VEC3) {
|
|
2670
|
-
return ZERO_VEC3;
|
|
2671
|
-
}
|
|
2672
|
-
return scaleVec3(direction, scale);
|
|
2673
|
-
}
|
|
2674
|
-
function applyPmoveAddCurrents(params) {
|
|
2530
|
+
// src/pmove/move.ts
|
|
2531
|
+
var DEFAULT_AIR_ACCELERATE = 1;
|
|
2532
|
+
var WATER_DRIFT_SPEED = 60;
|
|
2533
|
+
var DEFAULT_STEP_OVERBOUNCE = 1.01;
|
|
2534
|
+
function applyPmoveAirMove(params) {
|
|
2675
2535
|
const {
|
|
2676
|
-
|
|
2536
|
+
origin,
|
|
2537
|
+
frametime,
|
|
2538
|
+
mins,
|
|
2539
|
+
maxs,
|
|
2540
|
+
trace,
|
|
2541
|
+
overbounce = DEFAULT_STEP_OVERBOUNCE,
|
|
2542
|
+
stepSize,
|
|
2543
|
+
maxBumps,
|
|
2544
|
+
maxClipPlanes,
|
|
2545
|
+
hasTime,
|
|
2546
|
+
forward,
|
|
2547
|
+
right,
|
|
2548
|
+
cmd,
|
|
2549
|
+
pmFlags,
|
|
2550
|
+
onGround,
|
|
2551
|
+
gravity,
|
|
2552
|
+
pmType,
|
|
2553
|
+
pmAccelerate,
|
|
2554
|
+
pmAirAccelerate = DEFAULT_AIR_ACCELERATE,
|
|
2555
|
+
pmMaxSpeed,
|
|
2556
|
+
pmDuckSpeed,
|
|
2557
|
+
onLadder,
|
|
2558
|
+
waterlevel,
|
|
2559
|
+
watertype,
|
|
2560
|
+
groundContents,
|
|
2561
|
+
viewPitch,
|
|
2562
|
+
ladderMod,
|
|
2563
|
+
pmWaterSpeed
|
|
2564
|
+
} = params;
|
|
2565
|
+
let velocity = { ...params.velocity };
|
|
2566
|
+
let wishvel = buildPlanarWishVelocity(forward, right, cmd);
|
|
2567
|
+
wishvel = applyPmoveAddCurrents({
|
|
2568
|
+
wishVelocity: wishvel,
|
|
2677
2569
|
onLadder,
|
|
2678
2570
|
onGround,
|
|
2679
2571
|
waterlevel,
|
|
@@ -2681,223 +2573,354 @@ function applyPmoveAddCurrents(params) {
|
|
|
2681
2573
|
groundContents,
|
|
2682
2574
|
cmd,
|
|
2683
2575
|
viewPitch,
|
|
2684
|
-
maxSpeed,
|
|
2576
|
+
maxSpeed: hasPmFlag(pmFlags, 1 /* Ducked */) ? pmDuckSpeed : pmMaxSpeed,
|
|
2685
2577
|
ladderMod,
|
|
2686
|
-
waterSpeed,
|
|
2578
|
+
waterSpeed: pmWaterSpeed,
|
|
2687
2579
|
forward,
|
|
2688
2580
|
origin,
|
|
2689
2581
|
mins,
|
|
2690
2582
|
maxs,
|
|
2691
|
-
trace
|
|
2692
|
-
}
|
|
2693
|
-
|
|
2583
|
+
trace
|
|
2584
|
+
});
|
|
2585
|
+
const ducked = hasPmFlag(pmFlags, 1 /* Ducked */);
|
|
2586
|
+
const maxSpeed = ducked ? pmDuckSpeed : pmMaxSpeed;
|
|
2587
|
+
let wishdir = wishvel;
|
|
2588
|
+
let wishspeed = lengthVec3(wishdir);
|
|
2589
|
+
if (wishspeed !== 0) {
|
|
2590
|
+
wishdir = normalizeVec3(wishdir);
|
|
2591
|
+
}
|
|
2592
|
+
if (wishspeed > maxSpeed) {
|
|
2593
|
+
const scale = maxSpeed / wishspeed;
|
|
2594
|
+
wishvel = scaleVec3(wishvel, scale);
|
|
2595
|
+
wishspeed = maxSpeed;
|
|
2596
|
+
if (wishspeed !== 0) {
|
|
2597
|
+
wishdir = normalizeVec3(wishvel);
|
|
2598
|
+
}
|
|
2599
|
+
}
|
|
2694
2600
|
if (onLadder) {
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
maxSpeed,
|
|
2701
|
-
ladderMod,
|
|
2702
|
-
onGround,
|
|
2703
|
-
forward,
|
|
2601
|
+
velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: pmAccelerate, frametime });
|
|
2602
|
+
if (Math.abs(wishvel.z) < Number.EPSILON) {
|
|
2603
|
+
velocity = dampVerticalVelocity(velocity, gravity, frametime);
|
|
2604
|
+
}
|
|
2605
|
+
return runStepSlideMove({
|
|
2704
2606
|
origin,
|
|
2607
|
+
velocity,
|
|
2608
|
+
frametime,
|
|
2705
2609
|
mins,
|
|
2706
2610
|
maxs,
|
|
2707
|
-
trace
|
|
2611
|
+
trace,
|
|
2612
|
+
overbounce,
|
|
2613
|
+
stepSize,
|
|
2614
|
+
maxBumps,
|
|
2615
|
+
maxClipPlanes,
|
|
2616
|
+
hasTime
|
|
2708
2617
|
});
|
|
2709
2618
|
}
|
|
2710
|
-
const waterVelocity = waterCurrentVelocity({ watertype, waterlevel, onGround, waterSpeed });
|
|
2711
|
-
if (waterVelocity !== ZERO_VEC3) {
|
|
2712
|
-
adjusted = addVec3(adjusted, waterVelocity);
|
|
2713
|
-
}
|
|
2714
2619
|
if (onGround) {
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2620
|
+
velocity = { ...velocity, z: 0 };
|
|
2621
|
+
velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: pmAccelerate, frametime });
|
|
2622
|
+
if (gravity > 0) {
|
|
2623
|
+
velocity = { ...velocity, z: 0 };
|
|
2624
|
+
} else {
|
|
2625
|
+
velocity = { ...velocity, z: velocity.z - gravity * frametime };
|
|
2718
2626
|
}
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2722
|
-
|
|
2723
|
-
|
|
2724
|
-
|
|
2725
|
-
|
|
2726
|
-
|
|
2727
|
-
|
|
2728
|
-
adjusted = {
|
|
2729
|
-
...adjusted,
|
|
2730
|
-
z: buttons & 8 /* Jump */ ? ladderSpeed : -ladderSpeed
|
|
2731
|
-
};
|
|
2732
|
-
} else if (cmd.forwardmove) {
|
|
2733
|
-
const clamped = clamp(cmd.forwardmove, -DEFAULT_FORWARD_LADDER_CLAMP, DEFAULT_FORWARD_LADDER_CLAMP);
|
|
2734
|
-
if (cmd.forwardmove > 0) {
|
|
2735
|
-
const climb = viewPitch < LADDER_ASCEND_PITCH_THRESHOLD ? clamped : -clamped;
|
|
2736
|
-
adjusted = { ...adjusted, z: climb };
|
|
2737
|
-
} else {
|
|
2738
|
-
if (!onGround) {
|
|
2739
|
-
adjusted = { ...adjusted, x: 0, y: 0 };
|
|
2740
|
-
}
|
|
2741
|
-
adjusted = { ...adjusted, z: clamped };
|
|
2742
|
-
}
|
|
2743
|
-
} else {
|
|
2744
|
-
adjusted = { ...adjusted, z: 0 };
|
|
2745
|
-
}
|
|
2746
|
-
if (!onGround) {
|
|
2747
|
-
if (cmd.sidemove) {
|
|
2748
|
-
let sideSpeed = clamp(cmd.sidemove, -DEFAULT_SIDE_LADDER_CLAMP, DEFAULT_SIDE_LADDER_CLAMP);
|
|
2749
|
-
if (waterlevel < 2 /* Waist */) {
|
|
2750
|
-
sideSpeed *= ladderMod;
|
|
2751
|
-
}
|
|
2752
|
-
const flatForward = normalizeVec3({ x: forward.x, y: forward.y, z: 0 });
|
|
2753
|
-
if (flatForward.x !== 0 || flatForward.y !== 0) {
|
|
2754
|
-
const spot = addVec3(origin, scaleVec3(flatForward, LADDER_TRACE_DISTANCE));
|
|
2755
|
-
const tr = trace(origin, spot, mins, maxs);
|
|
2756
|
-
if (tr.fraction !== 1 && !tr.allsolid && tr.contents !== void 0 && (tr.contents & CONTENTS_LADDER) !== 0 && tr.planeNormal) {
|
|
2757
|
-
const right = crossVec3(tr.planeNormal, UP_VECTOR);
|
|
2758
|
-
adjusted = { ...adjusted, x: 0, y: 0 };
|
|
2759
|
-
adjusted = addVec3(adjusted, scaleVec3(right, -sideSpeed));
|
|
2760
|
-
}
|
|
2761
|
-
}
|
|
2762
|
-
} else {
|
|
2763
|
-
adjusted = {
|
|
2764
|
-
...adjusted,
|
|
2765
|
-
x: clampHorizontal(adjusted.x),
|
|
2766
|
-
y: clampHorizontal(adjusted.y)
|
|
2627
|
+
if (velocity.x === 0 && velocity.y === 0) {
|
|
2628
|
+
return {
|
|
2629
|
+
origin,
|
|
2630
|
+
velocity,
|
|
2631
|
+
planes: [],
|
|
2632
|
+
blocked: 0,
|
|
2633
|
+
stopped: true,
|
|
2634
|
+
stepped: false,
|
|
2635
|
+
stepHeight: 0
|
|
2767
2636
|
};
|
|
2768
2637
|
}
|
|
2638
|
+
return runStepSlideMove({
|
|
2639
|
+
origin,
|
|
2640
|
+
velocity,
|
|
2641
|
+
frametime,
|
|
2642
|
+
mins,
|
|
2643
|
+
maxs,
|
|
2644
|
+
trace,
|
|
2645
|
+
overbounce,
|
|
2646
|
+
stepSize,
|
|
2647
|
+
maxBumps,
|
|
2648
|
+
maxClipPlanes,
|
|
2649
|
+
hasTime
|
|
2650
|
+
});
|
|
2769
2651
|
}
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2652
|
+
if (pmAirAccelerate > 0) {
|
|
2653
|
+
velocity = applyPmoveAirAccelerate({
|
|
2654
|
+
velocity,
|
|
2655
|
+
wishdir,
|
|
2656
|
+
wishspeed,
|
|
2657
|
+
accel: pmAirAccelerate,
|
|
2658
|
+
frametime
|
|
2659
|
+
});
|
|
2660
|
+
} else {
|
|
2661
|
+
velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: DEFAULT_AIR_ACCELERATE, frametime });
|
|
2778
2662
|
}
|
|
2779
|
-
if (
|
|
2780
|
-
|
|
2663
|
+
if (pmType !== 1 /* Grapple */) {
|
|
2664
|
+
velocity = { ...velocity, z: velocity.z - gravity * frametime };
|
|
2781
2665
|
}
|
|
2782
|
-
return
|
|
2666
|
+
return runStepSlideMove({
|
|
2667
|
+
origin,
|
|
2668
|
+
velocity,
|
|
2669
|
+
frametime,
|
|
2670
|
+
mins,
|
|
2671
|
+
maxs,
|
|
2672
|
+
trace,
|
|
2673
|
+
overbounce,
|
|
2674
|
+
stepSize,
|
|
2675
|
+
maxBumps,
|
|
2676
|
+
maxClipPlanes,
|
|
2677
|
+
hasTime
|
|
2678
|
+
});
|
|
2783
2679
|
}
|
|
2784
|
-
|
|
2785
|
-
// src/pmove/fly.ts
|
|
2786
|
-
var FLY_FRICTION_MULTIPLIER = 1.5;
|
|
2787
|
-
var BUTTON_VERTICAL_SCALE = 0.5;
|
|
2788
|
-
var DEFAULT_OVERBOUNCE = 1.01;
|
|
2789
|
-
function applyPmoveFlyMove(params) {
|
|
2680
|
+
function applyPmoveWaterMove(params) {
|
|
2790
2681
|
const {
|
|
2791
2682
|
origin,
|
|
2792
|
-
cmd,
|
|
2793
2683
|
frametime,
|
|
2794
|
-
pmFriction,
|
|
2795
|
-
pmStopSpeed,
|
|
2796
|
-
pmMaxSpeed,
|
|
2797
|
-
pmAccelerate,
|
|
2798
|
-
pmWaterSpeed,
|
|
2799
|
-
doclip,
|
|
2800
|
-
forward,
|
|
2801
|
-
right,
|
|
2802
2684
|
mins,
|
|
2803
2685
|
maxs,
|
|
2804
2686
|
trace,
|
|
2805
|
-
overbounce =
|
|
2687
|
+
overbounce = DEFAULT_STEP_OVERBOUNCE,
|
|
2806
2688
|
stepSize,
|
|
2807
2689
|
maxBumps,
|
|
2808
|
-
maxClipPlanes
|
|
2809
|
-
|
|
2810
|
-
let velocity = applyFlyFriction({ velocity: params.velocity, pmFriction, pmStopSpeed, frametime });
|
|
2811
|
-
const wishdirVelocity = buildFlyWishVelocity({
|
|
2812
|
-
cmd,
|
|
2690
|
+
maxClipPlanes,
|
|
2691
|
+
hasTime,
|
|
2813
2692
|
forward,
|
|
2814
2693
|
right,
|
|
2694
|
+
cmd,
|
|
2695
|
+
pmFlags,
|
|
2696
|
+
onGround,
|
|
2815
2697
|
pmMaxSpeed,
|
|
2816
|
-
|
|
2698
|
+
pmDuckSpeed,
|
|
2699
|
+
pmWaterAccelerate,
|
|
2700
|
+
pmWaterSpeed,
|
|
2701
|
+
onLadder,
|
|
2702
|
+
watertype,
|
|
2703
|
+
groundContents,
|
|
2704
|
+
waterlevel,
|
|
2705
|
+
viewPitch,
|
|
2706
|
+
ladderMod
|
|
2707
|
+
} = params;
|
|
2708
|
+
let velocity = { ...params.velocity };
|
|
2709
|
+
let wishvel = buildFullWishVelocity(forward, right, cmd);
|
|
2710
|
+
if (isIdleInWater(cmd, onGround)) {
|
|
2711
|
+
wishvel = { ...wishvel, z: wishvel.z - WATER_DRIFT_SPEED };
|
|
2712
|
+
} else {
|
|
2713
|
+
if (hasButton2(cmd, 16 /* Crouch */)) {
|
|
2714
|
+
wishvel = addVec3(wishvel, { x: 0, y: 0, z: -pmWaterSpeed * 0.5 });
|
|
2715
|
+
} else if (hasButton2(cmd, 8 /* Jump */)) {
|
|
2716
|
+
wishvel = addVec3(wishvel, { x: 0, y: 0, z: pmWaterSpeed * 0.5 });
|
|
2717
|
+
}
|
|
2718
|
+
}
|
|
2719
|
+
wishvel = applyPmoveAddCurrents({
|
|
2720
|
+
wishVelocity: wishvel,
|
|
2721
|
+
onLadder,
|
|
2722
|
+
onGround,
|
|
2723
|
+
waterlevel,
|
|
2724
|
+
watertype,
|
|
2725
|
+
groundContents,
|
|
2726
|
+
cmd,
|
|
2727
|
+
viewPitch,
|
|
2728
|
+
maxSpeed: hasPmFlag(pmFlags, 1 /* Ducked */) ? pmDuckSpeed : pmMaxSpeed,
|
|
2729
|
+
ladderMod,
|
|
2730
|
+
waterSpeed: pmWaterSpeed,
|
|
2731
|
+
forward,
|
|
2732
|
+
origin,
|
|
2733
|
+
mins,
|
|
2734
|
+
maxs,
|
|
2735
|
+
trace
|
|
2817
2736
|
});
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
wishspeed: wishdirVelocity.accelSpeed,
|
|
2823
|
-
accel: pmAccelerate,
|
|
2824
|
-
frametime
|
|
2825
|
-
});
|
|
2737
|
+
let wishdir = wishvel;
|
|
2738
|
+
let wishspeed = lengthVec3(wishdir);
|
|
2739
|
+
if (wishspeed !== 0) {
|
|
2740
|
+
wishdir = normalizeVec3(wishdir);
|
|
2826
2741
|
}
|
|
2827
|
-
if (
|
|
2828
|
-
const
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
blocked: 0,
|
|
2835
|
-
stopped: velocity.x === 0 && velocity.y === 0 && velocity.z === 0,
|
|
2836
|
-
stepped: false,
|
|
2837
|
-
stepHeight: 0
|
|
2838
|
-
};
|
|
2742
|
+
if (wishspeed > pmMaxSpeed) {
|
|
2743
|
+
const scale = pmMaxSpeed / wishspeed;
|
|
2744
|
+
wishvel = scaleVec3(wishvel, scale);
|
|
2745
|
+
wishspeed = pmMaxSpeed;
|
|
2746
|
+
if (wishspeed !== 0) {
|
|
2747
|
+
wishdir = normalizeVec3(wishvel);
|
|
2748
|
+
}
|
|
2839
2749
|
}
|
|
2840
|
-
|
|
2841
|
-
|
|
2750
|
+
wishspeed *= 0.5;
|
|
2751
|
+
const ducked = hasPmFlag(pmFlags, 1 /* Ducked */);
|
|
2752
|
+
if (ducked && wishspeed > pmDuckSpeed) {
|
|
2753
|
+
const scale = pmDuckSpeed / wishspeed;
|
|
2754
|
+
wishvel = scaleVec3(wishvel, scale);
|
|
2755
|
+
wishspeed = pmDuckSpeed;
|
|
2756
|
+
if (wishspeed !== 0) {
|
|
2757
|
+
wishdir = normalizeVec3(wishvel);
|
|
2758
|
+
}
|
|
2842
2759
|
}
|
|
2843
|
-
|
|
2760
|
+
velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: pmWaterAccelerate, frametime });
|
|
2761
|
+
return runStepSlideMove({
|
|
2844
2762
|
origin,
|
|
2845
2763
|
velocity,
|
|
2846
2764
|
frametime,
|
|
2847
|
-
overbounce,
|
|
2848
|
-
trace,
|
|
2849
2765
|
mins,
|
|
2850
2766
|
maxs,
|
|
2767
|
+
trace,
|
|
2768
|
+
overbounce,
|
|
2851
2769
|
stepSize,
|
|
2852
2770
|
maxBumps,
|
|
2853
|
-
maxClipPlanes
|
|
2771
|
+
maxClipPlanes,
|
|
2772
|
+
hasTime
|
|
2854
2773
|
});
|
|
2855
2774
|
}
|
|
2856
|
-
function
|
|
2857
|
-
const {
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
|
|
2867
|
-
|
|
2868
|
-
|
|
2869
|
-
|
|
2870
|
-
|
|
2871
|
-
|
|
2872
|
-
|
|
2873
|
-
|
|
2874
|
-
|
|
2875
|
-
|
|
2876
|
-
|
|
2877
|
-
|
|
2878
|
-
|
|
2879
|
-
|
|
2880
|
-
|
|
2881
|
-
|
|
2882
|
-
|
|
2883
|
-
|
|
2884
|
-
|
|
2885
|
-
|
|
2886
|
-
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2775
|
+
function applyPmoveWalkMove(params) {
|
|
2776
|
+
const {
|
|
2777
|
+
origin,
|
|
2778
|
+
frametime,
|
|
2779
|
+
mins,
|
|
2780
|
+
maxs,
|
|
2781
|
+
trace,
|
|
2782
|
+
overbounce = DEFAULT_STEP_OVERBOUNCE,
|
|
2783
|
+
stepSize,
|
|
2784
|
+
maxBumps,
|
|
2785
|
+
maxClipPlanes,
|
|
2786
|
+
hasTime,
|
|
2787
|
+
forward,
|
|
2788
|
+
right,
|
|
2789
|
+
cmd,
|
|
2790
|
+
pmFlags,
|
|
2791
|
+
onGround,
|
|
2792
|
+
gravity,
|
|
2793
|
+
pmAccelerate,
|
|
2794
|
+
pmMaxSpeed,
|
|
2795
|
+
pmDuckSpeed,
|
|
2796
|
+
onLadder,
|
|
2797
|
+
waterlevel,
|
|
2798
|
+
watertype,
|
|
2799
|
+
groundContents,
|
|
2800
|
+
viewPitch,
|
|
2801
|
+
ladderMod,
|
|
2802
|
+
pmWaterSpeed
|
|
2803
|
+
} = params;
|
|
2804
|
+
let velocity = { ...params.velocity };
|
|
2805
|
+
let wishvel = buildPlanarWishVelocity(forward, right, cmd);
|
|
2806
|
+
wishvel = applyPmoveAddCurrents({
|
|
2807
|
+
wishVelocity: wishvel,
|
|
2808
|
+
onLadder,
|
|
2809
|
+
onGround,
|
|
2810
|
+
waterlevel,
|
|
2811
|
+
watertype,
|
|
2812
|
+
groundContents,
|
|
2813
|
+
cmd,
|
|
2814
|
+
viewPitch,
|
|
2815
|
+
maxSpeed: hasPmFlag(pmFlags, 1 /* Ducked */) ? pmDuckSpeed : pmMaxSpeed,
|
|
2816
|
+
ladderMod,
|
|
2817
|
+
waterSpeed: pmWaterSpeed,
|
|
2818
|
+
forward,
|
|
2819
|
+
origin,
|
|
2820
|
+
mins,
|
|
2821
|
+
maxs,
|
|
2822
|
+
trace
|
|
2823
|
+
});
|
|
2824
|
+
const ducked = hasPmFlag(pmFlags, 1 /* Ducked */);
|
|
2825
|
+
const maxSpeed = ducked ? pmDuckSpeed : pmMaxSpeed;
|
|
2826
|
+
let wishdir = wishvel;
|
|
2827
|
+
let wishspeed = lengthVec3(wishdir);
|
|
2828
|
+
if (wishspeed !== 0) {
|
|
2829
|
+
wishdir = normalizeVec3(wishdir);
|
|
2890
2830
|
}
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
|
|
2896
|
-
|
|
2897
|
-
|
|
2831
|
+
if (wishspeed > maxSpeed) {
|
|
2832
|
+
const scale = maxSpeed / wishspeed;
|
|
2833
|
+
wishvel = scaleVec3(wishvel, scale);
|
|
2834
|
+
wishspeed = maxSpeed;
|
|
2835
|
+
if (wishspeed !== 0) {
|
|
2836
|
+
wishdir = normalizeVec3(wishvel);
|
|
2837
|
+
}
|
|
2898
2838
|
}
|
|
2899
|
-
|
|
2900
|
-
|
|
2839
|
+
velocity = { ...velocity, z: 0 };
|
|
2840
|
+
velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: pmAccelerate, frametime });
|
|
2841
|
+
if (gravity > 0) {
|
|
2842
|
+
velocity = { ...velocity, z: 0 };
|
|
2843
|
+
} else {
|
|
2844
|
+
velocity = { ...velocity, z: velocity.z - gravity * frametime };
|
|
2845
|
+
}
|
|
2846
|
+
if (velocity.x === 0 && velocity.y === 0) {
|
|
2847
|
+
return {
|
|
2848
|
+
origin,
|
|
2849
|
+
velocity,
|
|
2850
|
+
planes: [],
|
|
2851
|
+
blocked: 0,
|
|
2852
|
+
stopped: true,
|
|
2853
|
+
stepped: false,
|
|
2854
|
+
stepHeight: 0
|
|
2855
|
+
};
|
|
2856
|
+
}
|
|
2857
|
+
return runStepSlideMove({
|
|
2858
|
+
origin,
|
|
2859
|
+
velocity,
|
|
2860
|
+
frametime,
|
|
2861
|
+
mins,
|
|
2862
|
+
maxs,
|
|
2863
|
+
trace,
|
|
2864
|
+
overbounce,
|
|
2865
|
+
stepSize,
|
|
2866
|
+
maxBumps,
|
|
2867
|
+
maxClipPlanes,
|
|
2868
|
+
hasTime
|
|
2869
|
+
});
|
|
2870
|
+
}
|
|
2871
|
+
function buildPlanarWishVelocity(forward, right, cmd) {
|
|
2872
|
+
return {
|
|
2873
|
+
x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
|
|
2874
|
+
y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
|
|
2875
|
+
z: 0
|
|
2876
|
+
};
|
|
2877
|
+
}
|
|
2878
|
+
function buildFullWishVelocity(forward, right, cmd) {
|
|
2879
|
+
return {
|
|
2880
|
+
x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
|
|
2881
|
+
y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
|
|
2882
|
+
z: forward.z * cmd.forwardmove + right.z * cmd.sidemove
|
|
2883
|
+
};
|
|
2884
|
+
}
|
|
2885
|
+
function hasButton2(cmd, button) {
|
|
2886
|
+
return (cmd.buttons ?? 0) & button ? true : false;
|
|
2887
|
+
}
|
|
2888
|
+
function isIdleInWater(cmd, onGround) {
|
|
2889
|
+
const noMove = cmd.forwardmove === 0 && cmd.sidemove === 0;
|
|
2890
|
+
const noButtons = (cmd.buttons ?? 0) & (8 /* Jump */ | 16 /* Crouch */) ? false : true;
|
|
2891
|
+
return noMove && noButtons && !onGround;
|
|
2892
|
+
}
|
|
2893
|
+
function dampVerticalVelocity(velocity, gravity, frametime) {
|
|
2894
|
+
let z = velocity.z;
|
|
2895
|
+
const delta = gravity * frametime;
|
|
2896
|
+
if (z > 0) {
|
|
2897
|
+
z -= delta;
|
|
2898
|
+
if (z < 0) {
|
|
2899
|
+
z = 0;
|
|
2900
|
+
}
|
|
2901
|
+
} else {
|
|
2902
|
+
z += delta;
|
|
2903
|
+
if (z > 0) {
|
|
2904
|
+
z = 0;
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
return { ...velocity, z };
|
|
2908
|
+
}
|
|
2909
|
+
function runStepSlideMove(params) {
|
|
2910
|
+
const { origin, velocity, frametime, mins, maxs, trace, overbounce = DEFAULT_STEP_OVERBOUNCE, stepSize, maxBumps, maxClipPlanes, hasTime } = params;
|
|
2911
|
+
return stepSlideMove({
|
|
2912
|
+
origin,
|
|
2913
|
+
velocity,
|
|
2914
|
+
frametime,
|
|
2915
|
+
trace,
|
|
2916
|
+
mins,
|
|
2917
|
+
maxs,
|
|
2918
|
+
overbounce,
|
|
2919
|
+
stepSize,
|
|
2920
|
+
maxBumps,
|
|
2921
|
+
maxClipPlanes,
|
|
2922
|
+
hasTime
|
|
2923
|
+
});
|
|
2901
2924
|
}
|
|
2902
2925
|
|
|
2903
2926
|
// src/pmove/water.ts
|
|
@@ -2929,184 +2952,23 @@ function getWaterLevel(params) {
|
|
|
2929
2952
|
return { waterlevel, watertype };
|
|
2930
2953
|
}
|
|
2931
2954
|
|
|
2932
|
-
// src/pmove/
|
|
2933
|
-
var
|
|
2934
|
-
|
|
2935
|
-
|
|
2936
|
-
|
|
2937
|
-
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
|
|
2947
|
-
|
|
2948
|
-
|
|
2949
|
-
nextFlags = removePmFlag(nextFlags, 2 /* JumpHeld */);
|
|
2950
|
-
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, jumpSound, jumped };
|
|
2951
|
-
}
|
|
2952
|
-
if (hasPmJumpHold(nextFlags)) {
|
|
2953
|
-
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, jumpSound, jumped };
|
|
2954
|
-
}
|
|
2955
|
-
if (pmType === 4 /* Dead */) {
|
|
2956
|
-
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, jumpSound, jumped };
|
|
2957
|
-
}
|
|
2958
|
-
if (waterlevel >= 2 /* Waist */) {
|
|
2959
|
-
nextOnGround = false;
|
|
2960
|
-
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, jumpSound, jumped };
|
|
2961
|
-
}
|
|
2962
|
-
if (!nextOnGround) {
|
|
2963
|
-
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, jumpSound, jumped };
|
|
2964
|
-
}
|
|
2965
|
-
nextFlags = addPmFlag(nextFlags, 2 /* JumpHeld */);
|
|
2966
|
-
nextFlags = removePmFlag(nextFlags, 4 /* OnGround */);
|
|
2967
|
-
nextOnGround = false;
|
|
2968
|
-
jumpSound = true;
|
|
2969
|
-
jumped = true;
|
|
2970
|
-
const z = velocity.z + jumpHeight;
|
|
2971
|
-
const finalZ = z < jumpHeight ? jumpHeight : z;
|
|
2972
|
-
nextVelocity = { ...velocity, z: finalZ };
|
|
2973
|
-
return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, jumpSound, jumped };
|
|
2974
|
-
}
|
|
2975
|
-
function hasPmJumpHold(flags) {
|
|
2976
|
-
return (flags & 2 /* JumpHeld */) !== 0;
|
|
2977
|
-
}
|
|
2978
|
-
|
|
2979
|
-
// src/pmove/dimensions.ts
|
|
2980
|
-
function createVec3(x, y, z) {
|
|
2981
|
-
return { x, y, z };
|
|
2982
|
-
}
|
|
2983
|
-
function computePlayerDimensions(pmType, pmFlags) {
|
|
2984
|
-
const minsBase = createVec3(-16, -16, 0);
|
|
2985
|
-
const maxsBase = createVec3(16, 16, 16);
|
|
2986
|
-
if (pmType === 5 /* Gib */) {
|
|
2987
|
-
return {
|
|
2988
|
-
mins: minsBase,
|
|
2989
|
-
maxs: maxsBase,
|
|
2990
|
-
viewheight: 8
|
|
2991
|
-
};
|
|
2992
|
-
}
|
|
2993
|
-
const ducked = pmType === 4 /* Dead */ || (pmFlags & 1 /* Ducked */) !== 0;
|
|
2994
|
-
const mins = createVec3(minsBase.x, minsBase.y, -24);
|
|
2995
|
-
const maxs = createVec3(maxsBase.x, maxsBase.y, ducked ? 4 : 32);
|
|
2996
|
-
return {
|
|
2997
|
-
mins,
|
|
2998
|
-
maxs,
|
|
2999
|
-
viewheight: ducked ? -2 : 22
|
|
3000
|
-
};
|
|
3001
|
-
}
|
|
3002
|
-
|
|
3003
|
-
// src/pmove/duck.ts
|
|
3004
|
-
var CROUCH_MAX_Z = 4;
|
|
3005
|
-
var STAND_MAX_Z = 32;
|
|
3006
|
-
var ABOVE_WATER_OFFSET = 8;
|
|
3007
|
-
function checkDuckState(params) {
|
|
3008
|
-
const { pmType } = params;
|
|
3009
|
-
if (pmType === 5 /* Gib */) {
|
|
3010
|
-
const dims2 = computePlayerDimensions(pmType, params.pmFlags);
|
|
3011
|
-
return { pmFlags: params.pmFlags, ducked: hasPmFlag(params.pmFlags, 1 /* Ducked */), changed: false, ...dims2 };
|
|
3012
|
-
}
|
|
3013
|
-
let flags = params.pmFlags;
|
|
3014
|
-
let changed = false;
|
|
3015
|
-
if (pmType === 4 /* Dead */) {
|
|
3016
|
-
if (!hasPmFlag(flags, 1 /* Ducked */)) {
|
|
3017
|
-
flags = addPmFlag(flags, 1 /* Ducked */);
|
|
3018
|
-
changed = true;
|
|
3019
|
-
}
|
|
3020
|
-
} else if (shouldDuck(params)) {
|
|
3021
|
-
if (!hasPmFlag(flags, 1 /* Ducked */) && !isDuckBlocked(params)) {
|
|
3022
|
-
flags = addPmFlag(flags, 1 /* Ducked */);
|
|
3023
|
-
changed = true;
|
|
3024
|
-
}
|
|
3025
|
-
} else if (hasPmFlag(flags, 1 /* Ducked */) && !isStandBlocked(params)) {
|
|
3026
|
-
flags = removePmFlag(flags, 1 /* Ducked */);
|
|
3027
|
-
changed = true;
|
|
3028
|
-
}
|
|
3029
|
-
const dims = computePlayerDimensions(pmType, flags);
|
|
3030
|
-
const ducked = pmType === 4 /* Dead */ || hasPmFlag(flags, 1 /* Ducked */);
|
|
3031
|
-
return { pmFlags: flags, ducked, changed, ...dims };
|
|
3032
|
-
}
|
|
3033
|
-
function shouldDuck(params) {
|
|
3034
|
-
if ((params.buttons & 16 /* Crouch */) === 0) {
|
|
3035
|
-
return false;
|
|
3036
|
-
}
|
|
3037
|
-
if (params.onLadder || params.n64Physics) {
|
|
3038
|
-
return false;
|
|
3039
|
-
}
|
|
3040
|
-
if (params.hasGroundEntity) {
|
|
3041
|
-
return true;
|
|
3042
|
-
}
|
|
3043
|
-
if (params.waterlevel <= 1 /* Feet */ && !isAboveWater(params)) {
|
|
3044
|
-
return true;
|
|
3045
|
-
}
|
|
3046
|
-
return false;
|
|
3047
|
-
}
|
|
3048
|
-
function isDuckBlocked(params) {
|
|
3049
|
-
const trace = params.trace({
|
|
3050
|
-
start: params.origin,
|
|
3051
|
-
end: params.origin,
|
|
3052
|
-
mins: params.mins,
|
|
3053
|
-
maxs: withZ(params.maxs, CROUCH_MAX_Z),
|
|
3054
|
-
mask: MASK_SOLID
|
|
3055
|
-
});
|
|
3056
|
-
return trace.allsolid;
|
|
3057
|
-
}
|
|
3058
|
-
function isStandBlocked(params) {
|
|
3059
|
-
const trace = params.trace({
|
|
3060
|
-
start: params.origin,
|
|
3061
|
-
end: params.origin,
|
|
3062
|
-
mins: params.mins,
|
|
3063
|
-
maxs: withZ(params.maxs, STAND_MAX_Z),
|
|
3064
|
-
mask: MASK_SOLID
|
|
3065
|
-
});
|
|
3066
|
-
return trace.allsolid;
|
|
3067
|
-
}
|
|
3068
|
-
function isAboveWater(params) {
|
|
3069
|
-
const below = { x: params.origin.x, y: params.origin.y, z: params.origin.z - ABOVE_WATER_OFFSET };
|
|
3070
|
-
const solidTrace = params.trace({
|
|
3071
|
-
start: params.origin,
|
|
3072
|
-
end: below,
|
|
3073
|
-
mins: params.mins,
|
|
3074
|
-
maxs: params.maxs,
|
|
3075
|
-
mask: MASK_SOLID
|
|
3076
|
-
});
|
|
3077
|
-
if (solidTrace.fraction < 1) {
|
|
3078
|
-
return false;
|
|
3079
|
-
}
|
|
3080
|
-
const waterTrace = params.trace({
|
|
3081
|
-
start: params.origin,
|
|
3082
|
-
end: below,
|
|
3083
|
-
mins: params.mins,
|
|
3084
|
-
maxs: params.maxs,
|
|
3085
|
-
mask: MASK_WATER
|
|
3086
|
-
});
|
|
3087
|
-
return waterTrace.fraction < 1;
|
|
3088
|
-
}
|
|
3089
|
-
function withZ(vec, z) {
|
|
3090
|
-
return { x: vec.x, y: vec.y, z };
|
|
3091
|
-
}
|
|
3092
|
-
|
|
3093
|
-
// src/pmove/categorize.ts
|
|
3094
|
-
var GROUND_PROBE_DISTANCE = 0.25;
|
|
3095
|
-
var LADDER_BYPASS_VELOCITY = 180;
|
|
3096
|
-
var TRICK_VELOCITY_THRESHOLD = 100;
|
|
3097
|
-
var SLANTED_NORMAL_THRESHOLD = 0.7;
|
|
3098
|
-
var TRICK_NORMAL_THRESHOLD = 0.9;
|
|
3099
|
-
var TRICK_PM_TIME = 64;
|
|
3100
|
-
var LAND_PM_TIME = 128;
|
|
3101
|
-
var IMPACT_CLIP_OVERBOUNCE = 1.01;
|
|
3102
|
-
var WATERJUMP_CLEAR = 8 /* TimeWaterJump */ | 16 /* TimeLand */ | 32 /* TimeTeleport */ | 1024 /* TimeTrick */;
|
|
3103
|
-
function categorizePosition(params) {
|
|
3104
|
-
const {
|
|
3105
|
-
pmType,
|
|
3106
|
-
n64Physics,
|
|
3107
|
-
velocity,
|
|
3108
|
-
startVelocity,
|
|
3109
|
-
origin,
|
|
2955
|
+
// src/pmove/categorize.ts
|
|
2956
|
+
var GROUND_PROBE_DISTANCE = 0.25;
|
|
2957
|
+
var LADDER_BYPASS_VELOCITY = 180;
|
|
2958
|
+
var TRICK_VELOCITY_THRESHOLD = 100;
|
|
2959
|
+
var SLANTED_NORMAL_THRESHOLD = 0.7;
|
|
2960
|
+
var TRICK_NORMAL_THRESHOLD = 0.9;
|
|
2961
|
+
var TRICK_PM_TIME = 64;
|
|
2962
|
+
var LAND_PM_TIME = 128;
|
|
2963
|
+
var IMPACT_CLIP_OVERBOUNCE = 1.01;
|
|
2964
|
+
var WATERJUMP_CLEAR = 8 /* TimeWaterJump */ | 16 /* TimeLand */ | 32 /* TimeTeleport */ | 1024 /* TimeTrick */;
|
|
2965
|
+
function categorizePosition(params) {
|
|
2966
|
+
const {
|
|
2967
|
+
pmType,
|
|
2968
|
+
n64Physics,
|
|
2969
|
+
velocity,
|
|
2970
|
+
startVelocity,
|
|
2971
|
+
origin,
|
|
3110
2972
|
mins,
|
|
3111
2973
|
maxs,
|
|
3112
2974
|
viewheight,
|
|
@@ -3180,304 +3042,744 @@ function categorizePosition(params) {
|
|
|
3180
3042
|
};
|
|
3181
3043
|
}
|
|
3182
3044
|
|
|
3183
|
-
// src/pmove/
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
function
|
|
3188
|
-
const
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3193
|
-
|
|
3194
|
-
|
|
3195
|
-
|
|
3196
|
-
|
|
3197
|
-
|
|
3198
|
-
|
|
3199
|
-
|
|
3200
|
-
|
|
3201
|
-
cmd,
|
|
3202
|
-
pmFlags,
|
|
3203
|
-
onGround,
|
|
3204
|
-
gravity,
|
|
3205
|
-
pmType,
|
|
3206
|
-
pmAccelerate,
|
|
3207
|
-
pmAirAccelerate = DEFAULT_AIR_ACCELERATE,
|
|
3208
|
-
pmMaxSpeed,
|
|
3209
|
-
pmDuckSpeed,
|
|
3210
|
-
onLadder,
|
|
3211
|
-
waterlevel,
|
|
3212
|
-
watertype,
|
|
3213
|
-
groundContents,
|
|
3214
|
-
viewPitch,
|
|
3215
|
-
ladderMod,
|
|
3216
|
-
pmWaterSpeed
|
|
3217
|
-
} = params;
|
|
3218
|
-
let velocity = { ...params.velocity };
|
|
3219
|
-
let wishvel = buildPlanarWishVelocity(forward, right, cmd);
|
|
3220
|
-
wishvel = applyPmoveAddCurrents({
|
|
3221
|
-
wishVelocity: wishvel,
|
|
3222
|
-
onLadder,
|
|
3223
|
-
onGround,
|
|
3224
|
-
waterlevel,
|
|
3225
|
-
watertype,
|
|
3226
|
-
groundContents,
|
|
3227
|
-
cmd,
|
|
3228
|
-
viewPitch,
|
|
3229
|
-
maxSpeed: hasPmFlag(pmFlags, 1 /* Ducked */) ? pmDuckSpeed : pmMaxSpeed,
|
|
3230
|
-
ladderMod,
|
|
3231
|
-
waterSpeed: pmWaterSpeed,
|
|
3232
|
-
forward,
|
|
3233
|
-
origin,
|
|
3045
|
+
// src/pmove/dimensions.ts
|
|
3046
|
+
function createVec3(x, y, z) {
|
|
3047
|
+
return { x, y, z };
|
|
3048
|
+
}
|
|
3049
|
+
function computePlayerDimensions(pmType, pmFlags) {
|
|
3050
|
+
const minsBase = createVec3(-16, -16, 0);
|
|
3051
|
+
const maxsBase = createVec3(16, 16, 16);
|
|
3052
|
+
if (pmType === 5 /* Gib */) {
|
|
3053
|
+
return {
|
|
3054
|
+
mins: minsBase,
|
|
3055
|
+
maxs: maxsBase,
|
|
3056
|
+
viewheight: 8
|
|
3057
|
+
};
|
|
3058
|
+
}
|
|
3059
|
+
const ducked = pmType === 4 /* Dead */ || (pmFlags & 1 /* Ducked */) !== 0;
|
|
3060
|
+
const mins = createVec3(minsBase.x, minsBase.y, -24);
|
|
3061
|
+
const maxs = createVec3(maxsBase.x, maxsBase.y, ducked ? 4 : 32);
|
|
3062
|
+
return {
|
|
3234
3063
|
mins,
|
|
3235
3064
|
maxs,
|
|
3236
|
-
|
|
3237
|
-
}
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3242
|
-
|
|
3243
|
-
|
|
3065
|
+
viewheight: ducked ? -2 : 22
|
|
3066
|
+
};
|
|
3067
|
+
}
|
|
3068
|
+
|
|
3069
|
+
// src/pmove/duck.ts
|
|
3070
|
+
var CROUCH_MAX_Z = 4;
|
|
3071
|
+
var STAND_MAX_Z = 32;
|
|
3072
|
+
var ABOVE_WATER_OFFSET = 8;
|
|
3073
|
+
function checkDuckState(params) {
|
|
3074
|
+
const { pmType } = params;
|
|
3075
|
+
if (pmType === 5 /* Gib */) {
|
|
3076
|
+
const dims2 = computePlayerDimensions(pmType, params.pmFlags);
|
|
3077
|
+
return { pmFlags: params.pmFlags, ducked: hasPmFlag(params.pmFlags, 1 /* Ducked */), changed: false, ...dims2 };
|
|
3244
3078
|
}
|
|
3245
|
-
|
|
3246
|
-
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3079
|
+
let flags = params.pmFlags;
|
|
3080
|
+
let changed = false;
|
|
3081
|
+
if (pmType === 4 /* Dead */) {
|
|
3082
|
+
if (!hasPmFlag(flags, 1 /* Ducked */)) {
|
|
3083
|
+
flags = addPmFlag(flags, 1 /* Ducked */);
|
|
3084
|
+
changed = true;
|
|
3251
3085
|
}
|
|
3252
|
-
}
|
|
3253
|
-
|
|
3254
|
-
|
|
3255
|
-
|
|
3256
|
-
velocity = dampVerticalVelocity(velocity, gravity, frametime);
|
|
3086
|
+
} else if (shouldDuck(params)) {
|
|
3087
|
+
if (!hasPmFlag(flags, 1 /* Ducked */) && !isDuckBlocked(params)) {
|
|
3088
|
+
flags = addPmFlag(flags, 1 /* Ducked */);
|
|
3089
|
+
changed = true;
|
|
3257
3090
|
}
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
frametime,
|
|
3262
|
-
mins,
|
|
3263
|
-
maxs,
|
|
3264
|
-
trace,
|
|
3265
|
-
overbounce,
|
|
3266
|
-
stepSize,
|
|
3267
|
-
maxBumps,
|
|
3268
|
-
maxClipPlanes,
|
|
3269
|
-
hasTime
|
|
3270
|
-
});
|
|
3091
|
+
} else if (hasPmFlag(flags, 1 /* Ducked */) && !isStandBlocked(params)) {
|
|
3092
|
+
flags = removePmFlag(flags, 1 /* Ducked */);
|
|
3093
|
+
changed = true;
|
|
3271
3094
|
}
|
|
3272
|
-
|
|
3273
|
-
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
|
|
3279
|
-
}
|
|
3280
|
-
if (velocity.x === 0 && velocity.y === 0) {
|
|
3281
|
-
return {
|
|
3282
|
-
origin,
|
|
3283
|
-
velocity,
|
|
3284
|
-
planes: [],
|
|
3285
|
-
blocked: 0,
|
|
3286
|
-
stopped: true,
|
|
3287
|
-
stepped: false,
|
|
3288
|
-
stepHeight: 0
|
|
3289
|
-
};
|
|
3290
|
-
}
|
|
3291
|
-
return runStepSlideMove({
|
|
3292
|
-
origin,
|
|
3293
|
-
velocity,
|
|
3294
|
-
frametime,
|
|
3295
|
-
mins,
|
|
3296
|
-
maxs,
|
|
3297
|
-
trace,
|
|
3298
|
-
overbounce,
|
|
3299
|
-
stepSize,
|
|
3300
|
-
maxBumps,
|
|
3301
|
-
maxClipPlanes,
|
|
3302
|
-
hasTime
|
|
3303
|
-
});
|
|
3095
|
+
const dims = computePlayerDimensions(pmType, flags);
|
|
3096
|
+
const ducked = pmType === 4 /* Dead */ || hasPmFlag(flags, 1 /* Ducked */);
|
|
3097
|
+
return { pmFlags: flags, ducked, changed, ...dims };
|
|
3098
|
+
}
|
|
3099
|
+
function shouldDuck(params) {
|
|
3100
|
+
if ((params.buttons & 16 /* Crouch */) === 0) {
|
|
3101
|
+
return false;
|
|
3304
3102
|
}
|
|
3305
|
-
if (
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3103
|
+
if (params.onLadder || params.n64Physics) {
|
|
3104
|
+
return false;
|
|
3105
|
+
}
|
|
3106
|
+
if (params.hasGroundEntity) {
|
|
3107
|
+
return true;
|
|
3108
|
+
}
|
|
3109
|
+
if (params.waterlevel <= 1 /* Feet */ && !isAboveWater(params)) {
|
|
3110
|
+
return true;
|
|
3111
|
+
}
|
|
3112
|
+
return false;
|
|
3113
|
+
}
|
|
3114
|
+
function isDuckBlocked(params) {
|
|
3115
|
+
const trace = params.trace({
|
|
3116
|
+
start: params.origin,
|
|
3117
|
+
end: params.origin,
|
|
3118
|
+
mins: params.mins,
|
|
3119
|
+
maxs: withZ(params.maxs, CROUCH_MAX_Z),
|
|
3120
|
+
mask: MASK_SOLID
|
|
3121
|
+
});
|
|
3122
|
+
return trace.allsolid;
|
|
3123
|
+
}
|
|
3124
|
+
function isStandBlocked(params) {
|
|
3125
|
+
const trace = params.trace({
|
|
3126
|
+
start: params.origin,
|
|
3127
|
+
end: params.origin,
|
|
3128
|
+
mins: params.mins,
|
|
3129
|
+
maxs: withZ(params.maxs, STAND_MAX_Z),
|
|
3130
|
+
mask: MASK_SOLID
|
|
3131
|
+
});
|
|
3132
|
+
return trace.allsolid;
|
|
3133
|
+
}
|
|
3134
|
+
function isAboveWater(params) {
|
|
3135
|
+
const below = { x: params.origin.x, y: params.origin.y, z: params.origin.z - ABOVE_WATER_OFFSET };
|
|
3136
|
+
const solidTrace = params.trace({
|
|
3137
|
+
start: params.origin,
|
|
3138
|
+
end: below,
|
|
3139
|
+
mins: params.mins,
|
|
3140
|
+
maxs: params.maxs,
|
|
3141
|
+
mask: MASK_SOLID
|
|
3142
|
+
});
|
|
3143
|
+
if (solidTrace.fraction < 1) {
|
|
3144
|
+
return false;
|
|
3145
|
+
}
|
|
3146
|
+
const waterTrace = params.trace({
|
|
3147
|
+
start: params.origin,
|
|
3148
|
+
end: below,
|
|
3149
|
+
mins: params.mins,
|
|
3150
|
+
maxs: params.maxs,
|
|
3151
|
+
mask: MASK_WATER
|
|
3152
|
+
});
|
|
3153
|
+
return waterTrace.fraction < 1;
|
|
3154
|
+
}
|
|
3155
|
+
function withZ(vec, z) {
|
|
3156
|
+
return { x: vec.x, y: vec.y, z };
|
|
3157
|
+
}
|
|
3158
|
+
|
|
3159
|
+
// src/pmove/pmove.ts
|
|
3160
|
+
var FRAMETIME = 0.025;
|
|
3161
|
+
function applyPmoveFriction(params) {
|
|
3162
|
+
const {
|
|
3163
|
+
velocity,
|
|
3164
|
+
frametime,
|
|
3165
|
+
onGround,
|
|
3166
|
+
groundIsSlick,
|
|
3167
|
+
onLadder,
|
|
3168
|
+
waterlevel,
|
|
3169
|
+
pmFriction,
|
|
3170
|
+
pmStopSpeed,
|
|
3171
|
+
pmWaterFriction
|
|
3172
|
+
} = params;
|
|
3173
|
+
const speed = lengthVec3(velocity);
|
|
3174
|
+
if (speed < 1) {
|
|
3175
|
+
return { x: 0, y: 0, z: velocity.z };
|
|
3176
|
+
}
|
|
3177
|
+
let drop = 0;
|
|
3178
|
+
if (onGround && !groundIsSlick || onLadder) {
|
|
3179
|
+
const control = speed < pmStopSpeed ? pmStopSpeed : speed;
|
|
3180
|
+
const friction = pmFriction;
|
|
3181
|
+
drop += control * friction * frametime;
|
|
3182
|
+
}
|
|
3183
|
+
if (waterlevel > 0 && !onLadder) {
|
|
3184
|
+
drop += speed * pmWaterFriction * waterlevel * frametime;
|
|
3185
|
+
}
|
|
3186
|
+
let newspeed = speed - drop;
|
|
3187
|
+
if (newspeed < 0) {
|
|
3188
|
+
newspeed = 0;
|
|
3189
|
+
}
|
|
3190
|
+
if (newspeed === speed) {
|
|
3191
|
+
return velocity;
|
|
3192
|
+
}
|
|
3193
|
+
const scale = newspeed / speed;
|
|
3194
|
+
return scaleVec3(velocity, scale);
|
|
3195
|
+
}
|
|
3196
|
+
function applyPmoveAccelerate(params) {
|
|
3197
|
+
const { velocity, wishdir, wishspeed, accel, frametime } = params;
|
|
3198
|
+
const currentSpeed = dotVec3(velocity, wishdir);
|
|
3199
|
+
const addSpeed = wishspeed - currentSpeed;
|
|
3200
|
+
if (addSpeed <= 0) {
|
|
3201
|
+
return velocity;
|
|
3202
|
+
}
|
|
3203
|
+
let accelSpeed = accel * frametime * wishspeed;
|
|
3204
|
+
if (accelSpeed > addSpeed) {
|
|
3205
|
+
accelSpeed = addSpeed;
|
|
3206
|
+
}
|
|
3207
|
+
return {
|
|
3208
|
+
x: velocity.x + wishdir.x * accelSpeed,
|
|
3209
|
+
y: velocity.y + wishdir.y * accelSpeed,
|
|
3210
|
+
z: velocity.z + wishdir.z * accelSpeed
|
|
3211
|
+
};
|
|
3212
|
+
}
|
|
3213
|
+
function applyPmoveAirAccelerate(params) {
|
|
3214
|
+
const { velocity, wishdir, wishspeed, accel, frametime } = params;
|
|
3215
|
+
const wishspd = Math.min(wishspeed, 30);
|
|
3216
|
+
const currentSpeed = dotVec3(velocity, wishdir);
|
|
3217
|
+
const addSpeed = wishspd - currentSpeed;
|
|
3218
|
+
if (addSpeed <= 0) {
|
|
3219
|
+
return velocity;
|
|
3220
|
+
}
|
|
3221
|
+
let accelSpeed = accel * wishspeed * frametime;
|
|
3222
|
+
if (accelSpeed > addSpeed) {
|
|
3223
|
+
accelSpeed = addSpeed;
|
|
3224
|
+
}
|
|
3225
|
+
return {
|
|
3226
|
+
x: velocity.x + wishdir.x * accelSpeed,
|
|
3227
|
+
y: velocity.y + wishdir.y * accelSpeed,
|
|
3228
|
+
z: velocity.z + wishdir.z * accelSpeed
|
|
3229
|
+
};
|
|
3230
|
+
}
|
|
3231
|
+
function pmoveCmdScale(cmd, maxSpeed) {
|
|
3232
|
+
const forward = Math.abs(cmd.forwardmove);
|
|
3233
|
+
const side = Math.abs(cmd.sidemove);
|
|
3234
|
+
const up = Math.abs(cmd.upmove);
|
|
3235
|
+
const max = Math.max(forward, side, up);
|
|
3236
|
+
if (max === 0) {
|
|
3237
|
+
return 0;
|
|
3238
|
+
}
|
|
3239
|
+
const total = Math.sqrt(cmd.forwardmove * cmd.forwardmove + cmd.sidemove * cmd.sidemove + cmd.upmove * cmd.upmove);
|
|
3240
|
+
return maxSpeed * max / (127 * total);
|
|
3241
|
+
}
|
|
3242
|
+
function buildAirGroundWish(params) {
|
|
3243
|
+
const { forward, right, cmd, maxSpeed } = params;
|
|
3244
|
+
let wishvel = {
|
|
3245
|
+
x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
|
|
3246
|
+
y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
|
|
3247
|
+
z: 0
|
|
3248
|
+
};
|
|
3249
|
+
let wishspeed = lengthVec3(wishvel);
|
|
3250
|
+
if (wishspeed > maxSpeed) {
|
|
3251
|
+
const scale = maxSpeed / wishspeed;
|
|
3252
|
+
wishvel = scaleVec3(wishvel, scale);
|
|
3253
|
+
wishspeed = maxSpeed;
|
|
3254
|
+
}
|
|
3255
|
+
return {
|
|
3256
|
+
wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
|
|
3257
|
+
wishspeed
|
|
3258
|
+
};
|
|
3259
|
+
}
|
|
3260
|
+
function buildWaterWish(params) {
|
|
3261
|
+
const { forward, right, cmd, maxSpeed } = params;
|
|
3262
|
+
let wishvel = {
|
|
3263
|
+
x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
|
|
3264
|
+
y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
|
|
3265
|
+
z: forward.z * cmd.forwardmove + right.z * cmd.sidemove
|
|
3266
|
+
};
|
|
3267
|
+
if (cmd.upmove > 10) {
|
|
3268
|
+
wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
|
|
3269
|
+
} else if (cmd.upmove < -10) {
|
|
3270
|
+
wishvel = addVec3(wishvel, { x: 0, y: 0, z: cmd.upmove });
|
|
3271
|
+
} else if (Math.abs(cmd.forwardmove) < 10 && Math.abs(cmd.sidemove) < 10) {
|
|
3272
|
+
wishvel = addVec3(wishvel, { x: 0, y: 0, z: -60 });
|
|
3313
3273
|
} else {
|
|
3314
|
-
|
|
3274
|
+
wishvel = addVec3(wishvel, { x: 0, y: 0, z: 10 });
|
|
3275
|
+
}
|
|
3276
|
+
let wishspeed = lengthVec3(wishvel);
|
|
3277
|
+
if (wishspeed > maxSpeed) {
|
|
3278
|
+
const scale = maxSpeed / wishspeed;
|
|
3279
|
+
wishvel = scaleVec3(wishvel, scale);
|
|
3280
|
+
wishspeed = maxSpeed;
|
|
3281
|
+
}
|
|
3282
|
+
wishspeed *= 0.5;
|
|
3283
|
+
return {
|
|
3284
|
+
wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
|
|
3285
|
+
wishspeed
|
|
3286
|
+
};
|
|
3287
|
+
}
|
|
3288
|
+
function runPmove(state, imports) {
|
|
3289
|
+
if (state.pmType === 4 /* Dead */) {
|
|
3290
|
+
return state;
|
|
3291
|
+
}
|
|
3292
|
+
let nextState = { ...state };
|
|
3293
|
+
const catResult = categorizePosition({
|
|
3294
|
+
pmType: nextState.pmType,
|
|
3295
|
+
pmFlags: nextState.pmFlags,
|
|
3296
|
+
pmTime: 0,
|
|
3297
|
+
n64Physics: false,
|
|
3298
|
+
velocity: nextState.velocity,
|
|
3299
|
+
startVelocity: nextState.velocity,
|
|
3300
|
+
origin: nextState.origin,
|
|
3301
|
+
mins: nextState.mins,
|
|
3302
|
+
maxs: nextState.maxs,
|
|
3303
|
+
viewheight: nextState.viewHeight,
|
|
3304
|
+
trace: imports.trace,
|
|
3305
|
+
pointContents: imports.pointcontents
|
|
3306
|
+
});
|
|
3307
|
+
nextState.pmFlags = catResult.pmFlags;
|
|
3308
|
+
nextState.waterlevel = catResult.waterlevel;
|
|
3309
|
+
nextState.watertype = catResult.watertype;
|
|
3310
|
+
const duckResult = checkDuckState({
|
|
3311
|
+
pmType: nextState.pmType,
|
|
3312
|
+
pmFlags: nextState.pmFlags,
|
|
3313
|
+
buttons: nextState.cmd.buttons,
|
|
3314
|
+
waterlevel: nextState.waterlevel,
|
|
3315
|
+
hasGroundEntity: (nextState.pmFlags & 4 /* OnGround */) !== 0,
|
|
3316
|
+
onLadder: false,
|
|
3317
|
+
n64Physics: false,
|
|
3318
|
+
origin: nextState.origin,
|
|
3319
|
+
mins: nextState.mins,
|
|
3320
|
+
maxs: nextState.maxs,
|
|
3321
|
+
trace: (params) => {
|
|
3322
|
+
return imports.trace(params.start, params.end, params.mins, params.maxs);
|
|
3323
|
+
}
|
|
3324
|
+
});
|
|
3325
|
+
nextState.pmFlags = duckResult.pmFlags;
|
|
3326
|
+
nextState.mins = duckResult.mins;
|
|
3327
|
+
nextState.maxs = duckResult.maxs;
|
|
3328
|
+
nextState.viewHeight = duckResult.viewheight;
|
|
3329
|
+
const jumpResult = checkJump({
|
|
3330
|
+
pmFlags: nextState.pmFlags,
|
|
3331
|
+
pmType: nextState.pmType,
|
|
3332
|
+
buttons: nextState.cmd.buttons,
|
|
3333
|
+
waterlevel: nextState.waterlevel,
|
|
3334
|
+
onGround: (nextState.pmFlags & 4 /* OnGround */) !== 0,
|
|
3335
|
+
velocity: nextState.velocity,
|
|
3336
|
+
origin: nextState.origin
|
|
3337
|
+
});
|
|
3338
|
+
nextState.pmFlags = jumpResult.pmFlags;
|
|
3339
|
+
nextState.velocity = jumpResult.velocity;
|
|
3340
|
+
nextState.origin = jumpResult.origin;
|
|
3341
|
+
if (jumpResult.onGround !== ((nextState.pmFlags & 4 /* OnGround */) !== 0)) {
|
|
3342
|
+
if (jumpResult.onGround) {
|
|
3343
|
+
nextState.pmFlags = addPmFlag(nextState.pmFlags, 4 /* OnGround */);
|
|
3344
|
+
} else {
|
|
3345
|
+
nextState.pmFlags = removePmFlag(nextState.pmFlags, 4 /* OnGround */);
|
|
3346
|
+
}
|
|
3347
|
+
}
|
|
3348
|
+
const onGround = (nextState.pmFlags & 4 /* OnGround */) !== 0;
|
|
3349
|
+
const velocityBeforeFriction = nextState.velocity;
|
|
3350
|
+
nextState.velocity = applyPmoveFriction({
|
|
3351
|
+
velocity: nextState.velocity,
|
|
3352
|
+
frametime: FRAMETIME,
|
|
3353
|
+
onGround,
|
|
3354
|
+
groundIsSlick: false,
|
|
3355
|
+
onLadder: false,
|
|
3356
|
+
// Defaulting to false for now as ladder logic is complex
|
|
3357
|
+
waterlevel: nextState.waterlevel,
|
|
3358
|
+
pmFriction: 6,
|
|
3359
|
+
// Default
|
|
3360
|
+
pmStopSpeed: 100,
|
|
3361
|
+
// Default
|
|
3362
|
+
pmWaterFriction: 1
|
|
3363
|
+
// Default
|
|
3364
|
+
});
|
|
3365
|
+
const { forward, right } = angleVectors(nextState.viewAngles);
|
|
3366
|
+
if (nextState.pmType === 2 /* NoClip */) {
|
|
3367
|
+
const wishvel = {
|
|
3368
|
+
x: forward.x * nextState.cmd.forwardmove + right.x * nextState.cmd.sidemove,
|
|
3369
|
+
y: forward.y * nextState.cmd.forwardmove + right.y * nextState.cmd.sidemove,
|
|
3370
|
+
z: nextState.cmd.upmove
|
|
3371
|
+
};
|
|
3372
|
+
const scale = FRAMETIME;
|
|
3373
|
+
nextState.velocity = wishvel;
|
|
3374
|
+
nextState.origin = {
|
|
3375
|
+
x: nextState.origin.x + wishvel.x * scale,
|
|
3376
|
+
y: nextState.origin.y + wishvel.y * scale,
|
|
3377
|
+
z: nextState.origin.z + wishvel.z * scale
|
|
3378
|
+
};
|
|
3379
|
+
} else if (nextState.waterlevel >= 2) {
|
|
3380
|
+
const outcome = applyPmoveWaterMove({
|
|
3381
|
+
origin: nextState.origin,
|
|
3382
|
+
velocity: nextState.velocity,
|
|
3383
|
+
frametime: FRAMETIME,
|
|
3384
|
+
mins: nextState.mins,
|
|
3385
|
+
maxs: nextState.maxs,
|
|
3386
|
+
trace: imports.trace,
|
|
3387
|
+
cmd: nextState.cmd,
|
|
3388
|
+
forward,
|
|
3389
|
+
right,
|
|
3390
|
+
pmFlags: nextState.pmFlags,
|
|
3391
|
+
onGround,
|
|
3392
|
+
pmMaxSpeed: 300,
|
|
3393
|
+
pmDuckSpeed: 100,
|
|
3394
|
+
pmWaterAccelerate: 4,
|
|
3395
|
+
pmWaterSpeed: 400,
|
|
3396
|
+
onLadder: false,
|
|
3397
|
+
watertype: nextState.watertype,
|
|
3398
|
+
groundContents: 0,
|
|
3399
|
+
// Should be passed in?
|
|
3400
|
+
waterlevel: nextState.waterlevel,
|
|
3401
|
+
viewPitch: nextState.viewAngles.x,
|
|
3402
|
+
ladderMod: 1,
|
|
3403
|
+
stepSize: 18
|
|
3404
|
+
// Added stepSize for consistency, though water move might not use it heavily
|
|
3405
|
+
});
|
|
3406
|
+
nextState.origin = outcome.origin;
|
|
3407
|
+
nextState.velocity = outcome.velocity;
|
|
3408
|
+
} else if ((nextState.pmFlags & 4 /* OnGround */) === 0) {
|
|
3409
|
+
const outcome = applyPmoveAirMove({
|
|
3410
|
+
origin: nextState.origin,
|
|
3411
|
+
velocity: nextState.velocity,
|
|
3412
|
+
frametime: FRAMETIME,
|
|
3413
|
+
mins: nextState.mins,
|
|
3414
|
+
maxs: nextState.maxs,
|
|
3415
|
+
trace: imports.trace,
|
|
3416
|
+
cmd: nextState.cmd,
|
|
3417
|
+
forward,
|
|
3418
|
+
right,
|
|
3419
|
+
pmFlags: nextState.pmFlags,
|
|
3420
|
+
onGround,
|
|
3421
|
+
gravity: nextState.gravity,
|
|
3422
|
+
pmType: nextState.pmType,
|
|
3423
|
+
pmAccelerate: 10,
|
|
3424
|
+
pmAirAccelerate: 1,
|
|
3425
|
+
pmMaxSpeed: 300,
|
|
3426
|
+
pmDuckSpeed: 100,
|
|
3427
|
+
onLadder: false,
|
|
3428
|
+
waterlevel: nextState.waterlevel,
|
|
3429
|
+
watertype: nextState.watertype,
|
|
3430
|
+
groundContents: 0,
|
|
3431
|
+
viewPitch: nextState.viewAngles.x,
|
|
3432
|
+
ladderMod: 1,
|
|
3433
|
+
pmWaterSpeed: 400,
|
|
3434
|
+
stepSize: 18
|
|
3435
|
+
// Added stepSize
|
|
3436
|
+
});
|
|
3437
|
+
nextState.origin = outcome.origin;
|
|
3438
|
+
nextState.velocity = outcome.velocity;
|
|
3439
|
+
} else {
|
|
3440
|
+
const outcome = applyPmoveWalkMove({
|
|
3441
|
+
origin: nextState.origin,
|
|
3442
|
+
velocity: nextState.velocity,
|
|
3443
|
+
frametime: FRAMETIME,
|
|
3444
|
+
mins: nextState.mins,
|
|
3445
|
+
maxs: nextState.maxs,
|
|
3446
|
+
trace: imports.trace,
|
|
3447
|
+
cmd: nextState.cmd,
|
|
3448
|
+
forward,
|
|
3449
|
+
right,
|
|
3450
|
+
pmFlags: nextState.pmFlags,
|
|
3451
|
+
onGround,
|
|
3452
|
+
gravity: nextState.gravity,
|
|
3453
|
+
pmType: nextState.pmType,
|
|
3454
|
+
pmAccelerate: 10,
|
|
3455
|
+
pmMaxSpeed: 300,
|
|
3456
|
+
pmDuckSpeed: 100,
|
|
3457
|
+
onLadder: false,
|
|
3458
|
+
waterlevel: nextState.waterlevel,
|
|
3459
|
+
watertype: nextState.watertype,
|
|
3460
|
+
groundContents: 0,
|
|
3461
|
+
viewPitch: nextState.viewAngles.x,
|
|
3462
|
+
ladderMod: 1,
|
|
3463
|
+
pmWaterSpeed: 400,
|
|
3464
|
+
stepSize: 18
|
|
3465
|
+
// Added stepSize
|
|
3466
|
+
});
|
|
3467
|
+
nextState.origin = outcome.origin;
|
|
3468
|
+
nextState.velocity = outcome.velocity;
|
|
3469
|
+
}
|
|
3470
|
+
const catResultEnd = categorizePosition({
|
|
3471
|
+
pmType: nextState.pmType,
|
|
3472
|
+
pmFlags: nextState.pmFlags,
|
|
3473
|
+
pmTime: 0,
|
|
3474
|
+
n64Physics: false,
|
|
3475
|
+
velocity: nextState.velocity,
|
|
3476
|
+
startVelocity: nextState.velocity,
|
|
3477
|
+
origin: nextState.origin,
|
|
3478
|
+
mins: nextState.mins,
|
|
3479
|
+
maxs: nextState.maxs,
|
|
3480
|
+
viewheight: nextState.viewHeight,
|
|
3481
|
+
trace: imports.trace,
|
|
3482
|
+
pointContents: imports.pointcontents
|
|
3483
|
+
});
|
|
3484
|
+
nextState.pmFlags = catResultEnd.pmFlags;
|
|
3485
|
+
nextState.waterlevel = catResultEnd.waterlevel;
|
|
3486
|
+
nextState.watertype = catResultEnd.watertype;
|
|
3487
|
+
return nextState;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
// src/pmove/stuck.ts
|
|
3491
|
+
var AXES = ["x", "y", "z"];
|
|
3492
|
+
var SIDE_CHECKS = [
|
|
3493
|
+
{ normal: [0, 0, 1], mins: [-1, -1, 0], maxs: [1, 1, 0] },
|
|
3494
|
+
{ normal: [0, 0, -1], mins: [-1, -1, 0], maxs: [1, 1, 0] },
|
|
3495
|
+
{ normal: [1, 0, 0], mins: [0, -1, -1], maxs: [0, 1, 1] },
|
|
3496
|
+
{ normal: [-1, 0, 0], mins: [0, -1, -1], maxs: [0, 1, 1] },
|
|
3497
|
+
{ normal: [0, 1, 0], mins: [-1, 0, -1], maxs: [1, 0, 1] },
|
|
3498
|
+
{ normal: [0, -1, 0], mins: [-1, 0, -1], maxs: [1, 0, 1] }
|
|
3499
|
+
];
|
|
3500
|
+
var ZERO_VEC = { x: 0, y: 0, z: 0 };
|
|
3501
|
+
function cloneMutable(vec) {
|
|
3502
|
+
return { x: vec.x, y: vec.y, z: vec.z };
|
|
3503
|
+
}
|
|
3504
|
+
function tupleToVec3(tuple) {
|
|
3505
|
+
return { x: tuple[0], y: tuple[1], z: tuple[2] };
|
|
3506
|
+
}
|
|
3507
|
+
function adjustAxis(vec, axis, delta) {
|
|
3508
|
+
if (delta === 0) return;
|
|
3509
|
+
switch (axis) {
|
|
3510
|
+
case "x":
|
|
3511
|
+
vec.x += delta;
|
|
3512
|
+
break;
|
|
3513
|
+
case "y":
|
|
3514
|
+
vec.y += delta;
|
|
3515
|
+
break;
|
|
3516
|
+
case "z":
|
|
3517
|
+
vec.z += delta;
|
|
3518
|
+
break;
|
|
3519
|
+
}
|
|
3520
|
+
}
|
|
3521
|
+
function setAxis(vec, axis, value) {
|
|
3522
|
+
switch (axis) {
|
|
3523
|
+
case "x":
|
|
3524
|
+
vec.x = value;
|
|
3525
|
+
break;
|
|
3526
|
+
case "y":
|
|
3527
|
+
vec.y = value;
|
|
3528
|
+
break;
|
|
3529
|
+
case "z":
|
|
3530
|
+
vec.z = value;
|
|
3531
|
+
break;
|
|
3532
|
+
}
|
|
3533
|
+
}
|
|
3534
|
+
function axisValue(vec, axis) {
|
|
3535
|
+
switch (axis) {
|
|
3536
|
+
case "x":
|
|
3537
|
+
return vec.x;
|
|
3538
|
+
case "y":
|
|
3539
|
+
return vec.y;
|
|
3540
|
+
case "z":
|
|
3541
|
+
default:
|
|
3542
|
+
return vec.z;
|
|
3543
|
+
}
|
|
3544
|
+
}
|
|
3545
|
+
function boundValue(code, axis, mins, maxs) {
|
|
3546
|
+
if (code === -1) {
|
|
3547
|
+
return axisValue(mins, axis);
|
|
3548
|
+
}
|
|
3549
|
+
if (code === 1) {
|
|
3550
|
+
return axisValue(maxs, axis);
|
|
3551
|
+
}
|
|
3552
|
+
return 0;
|
|
3553
|
+
}
|
|
3554
|
+
function applySideOffset(base, side, mins, maxs) {
|
|
3555
|
+
const result = cloneMutable(base);
|
|
3556
|
+
for (let i = 0; i < AXES.length; i++) {
|
|
3557
|
+
const axis = AXES[i];
|
|
3558
|
+
const normal = side.normal[i];
|
|
3559
|
+
if (normal < 0) {
|
|
3560
|
+
adjustAxis(result, axis, axisValue(mins, axis));
|
|
3561
|
+
} else if (normal > 0) {
|
|
3562
|
+
adjustAxis(result, axis, axisValue(maxs, axis));
|
|
3563
|
+
}
|
|
3564
|
+
}
|
|
3565
|
+
return result;
|
|
3566
|
+
}
|
|
3567
|
+
function buildSideBounds(side, mins, maxs) {
|
|
3568
|
+
const localMins = cloneMutable(ZERO_VEC);
|
|
3569
|
+
const localMaxs = cloneMutable(ZERO_VEC);
|
|
3570
|
+
for (let i = 0; i < AXES.length; i++) {
|
|
3571
|
+
const axis = AXES[i];
|
|
3572
|
+
setAxis(localMins, axis, boundValue(side.mins[i], axis, mins, maxs));
|
|
3573
|
+
setAxis(localMaxs, axis, boundValue(side.maxs[i], axis, mins, maxs));
|
|
3574
|
+
}
|
|
3575
|
+
return { mins: localMins, maxs: localMaxs };
|
|
3576
|
+
}
|
|
3577
|
+
function addEpsilon(source, axis, direction) {
|
|
3578
|
+
if (!axis || direction === 0) {
|
|
3579
|
+
return source;
|
|
3580
|
+
}
|
|
3581
|
+
const clone = cloneMutable(source);
|
|
3582
|
+
adjustAxis(clone, axis, direction);
|
|
3583
|
+
return clone;
|
|
3584
|
+
}
|
|
3585
|
+
function addEpsilonImmutable(vec, axis, direction) {
|
|
3586
|
+
if (!axis || direction === 0) {
|
|
3587
|
+
return vec;
|
|
3588
|
+
}
|
|
3589
|
+
switch (axis) {
|
|
3590
|
+
case "x":
|
|
3591
|
+
return { ...vec, x: vec.x + direction };
|
|
3592
|
+
case "y":
|
|
3593
|
+
return { ...vec, y: vec.y + direction };
|
|
3594
|
+
case "z":
|
|
3595
|
+
default:
|
|
3596
|
+
return { ...vec, z: vec.z + direction };
|
|
3597
|
+
}
|
|
3598
|
+
}
|
|
3599
|
+
function fixStuckObjectGeneric(params) {
|
|
3600
|
+
const { origin, mins, maxs, trace } = params;
|
|
3601
|
+
const initial = trace(origin, mins, maxs, origin);
|
|
3602
|
+
if (!initial.startsolid) {
|
|
3603
|
+
return { result: "good-position", origin: { ...origin } };
|
|
3604
|
+
}
|
|
3605
|
+
const candidates = [];
|
|
3606
|
+
for (let i = 0; i < SIDE_CHECKS.length; i++) {
|
|
3607
|
+
const side = SIDE_CHECKS[i];
|
|
3608
|
+
const { mins: localMins, maxs: localMaxs } = buildSideBounds(side, mins, maxs);
|
|
3609
|
+
let start = applySideOffset(origin, side, mins, maxs);
|
|
3610
|
+
let tr = trace(start, localMins, localMaxs, start);
|
|
3611
|
+
let epsilonAxis;
|
|
3612
|
+
let epsilonDir = 0;
|
|
3613
|
+
if (tr.startsolid) {
|
|
3614
|
+
for (let axisIndex = 0; axisIndex < AXES.length; axisIndex++) {
|
|
3615
|
+
if (side.normal[axisIndex] !== 0) {
|
|
3616
|
+
continue;
|
|
3617
|
+
}
|
|
3618
|
+
const axis = AXES[axisIndex];
|
|
3619
|
+
let epsilonStart = cloneMutable(start);
|
|
3620
|
+
adjustAxis(epsilonStart, axis, 1);
|
|
3621
|
+
tr = trace(epsilonStart, localMins, localMaxs, epsilonStart);
|
|
3622
|
+
if (!tr.startsolid) {
|
|
3623
|
+
start = epsilonStart;
|
|
3624
|
+
epsilonAxis = axis;
|
|
3625
|
+
epsilonDir = 1;
|
|
3626
|
+
break;
|
|
3627
|
+
}
|
|
3628
|
+
epsilonStart = cloneMutable(start);
|
|
3629
|
+
adjustAxis(epsilonStart, axis, -1);
|
|
3630
|
+
tr = trace(epsilonStart, localMins, localMaxs, epsilonStart);
|
|
3631
|
+
if (!tr.startsolid) {
|
|
3632
|
+
start = epsilonStart;
|
|
3633
|
+
epsilonAxis = axis;
|
|
3634
|
+
epsilonDir = -1;
|
|
3635
|
+
break;
|
|
3636
|
+
}
|
|
3637
|
+
}
|
|
3638
|
+
}
|
|
3639
|
+
if (tr.startsolid) {
|
|
3640
|
+
continue;
|
|
3641
|
+
}
|
|
3642
|
+
const otherSide = SIDE_CHECKS[i ^ 1];
|
|
3643
|
+
let oppositeStart = applySideOffset(origin, otherSide, mins, maxs);
|
|
3644
|
+
oppositeStart = addEpsilon(oppositeStart, epsilonAxis, epsilonDir);
|
|
3645
|
+
tr = trace(start, localMins, localMaxs, oppositeStart);
|
|
3646
|
+
if (tr.startsolid) {
|
|
3647
|
+
continue;
|
|
3648
|
+
}
|
|
3649
|
+
const normal = tupleToVec3(side.normal);
|
|
3650
|
+
const end = addVec3(tr.endpos ?? oppositeStart, scaleVec3(normal, 0.125));
|
|
3651
|
+
const delta = subtractVec3(end, oppositeStart);
|
|
3652
|
+
let newOrigin = addVec3(origin, delta);
|
|
3653
|
+
newOrigin = addEpsilonImmutable(newOrigin, epsilonAxis, epsilonDir);
|
|
3654
|
+
const validation = trace(newOrigin, mins, maxs, newOrigin);
|
|
3655
|
+
if (validation.startsolid) {
|
|
3656
|
+
continue;
|
|
3657
|
+
}
|
|
3658
|
+
candidates.push({ origin: newOrigin, distance: lengthSquaredVec3(delta) });
|
|
3315
3659
|
}
|
|
3316
|
-
if (
|
|
3317
|
-
|
|
3660
|
+
if (candidates.length === 0) {
|
|
3661
|
+
return { result: "no-good-position", origin: { ...origin } };
|
|
3318
3662
|
}
|
|
3319
|
-
|
|
3320
|
-
|
|
3321
|
-
velocity,
|
|
3322
|
-
frametime,
|
|
3323
|
-
mins,
|
|
3324
|
-
maxs,
|
|
3325
|
-
trace,
|
|
3326
|
-
overbounce,
|
|
3327
|
-
stepSize,
|
|
3328
|
-
maxBumps,
|
|
3329
|
-
maxClipPlanes,
|
|
3330
|
-
hasTime
|
|
3331
|
-
});
|
|
3663
|
+
candidates.sort((a, b) => a.distance - b.distance);
|
|
3664
|
+
return { result: "fixed", origin: { ...candidates[0].origin } };
|
|
3332
3665
|
}
|
|
3333
|
-
|
|
3666
|
+
|
|
3667
|
+
// src/pmove/fly.ts
|
|
3668
|
+
var FLY_FRICTION_MULTIPLIER = 1.5;
|
|
3669
|
+
var BUTTON_VERTICAL_SCALE = 0.5;
|
|
3670
|
+
var DEFAULT_OVERBOUNCE = 1.01;
|
|
3671
|
+
function applyPmoveFlyMove(params) {
|
|
3334
3672
|
const {
|
|
3335
3673
|
origin,
|
|
3674
|
+
cmd,
|
|
3336
3675
|
frametime,
|
|
3676
|
+
pmFriction,
|
|
3677
|
+
pmStopSpeed,
|
|
3678
|
+
pmMaxSpeed,
|
|
3679
|
+
pmAccelerate,
|
|
3680
|
+
pmWaterSpeed,
|
|
3681
|
+
doclip,
|
|
3682
|
+
forward,
|
|
3683
|
+
right,
|
|
3337
3684
|
mins,
|
|
3338
3685
|
maxs,
|
|
3339
3686
|
trace,
|
|
3340
|
-
overbounce =
|
|
3687
|
+
overbounce = DEFAULT_OVERBOUNCE,
|
|
3341
3688
|
stepSize,
|
|
3342
3689
|
maxBumps,
|
|
3343
|
-
maxClipPlanes
|
|
3344
|
-
hasTime,
|
|
3345
|
-
forward,
|
|
3346
|
-
right,
|
|
3347
|
-
cmd,
|
|
3348
|
-
pmFlags,
|
|
3349
|
-
onGround,
|
|
3350
|
-
pmMaxSpeed,
|
|
3351
|
-
pmDuckSpeed,
|
|
3352
|
-
pmWaterAccelerate,
|
|
3353
|
-
pmWaterSpeed,
|
|
3354
|
-
onLadder,
|
|
3355
|
-
watertype,
|
|
3356
|
-
groundContents,
|
|
3357
|
-
waterlevel,
|
|
3358
|
-
viewPitch,
|
|
3359
|
-
ladderMod
|
|
3690
|
+
maxClipPlanes
|
|
3360
3691
|
} = params;
|
|
3361
|
-
let velocity = {
|
|
3362
|
-
|
|
3363
|
-
if (isIdleInWater(cmd, onGround)) {
|
|
3364
|
-
wishvel = { ...wishvel, z: wishvel.z - WATER_DRIFT_SPEED };
|
|
3365
|
-
} else {
|
|
3366
|
-
if (hasButton2(cmd, 16 /* Crouch */)) {
|
|
3367
|
-
wishvel = addVec3(wishvel, { x: 0, y: 0, z: -pmWaterSpeed * 0.5 });
|
|
3368
|
-
} else if (hasButton2(cmd, 8 /* Jump */)) {
|
|
3369
|
-
wishvel = addVec3(wishvel, { x: 0, y: 0, z: pmWaterSpeed * 0.5 });
|
|
3370
|
-
}
|
|
3371
|
-
}
|
|
3372
|
-
wishvel = applyPmoveAddCurrents({
|
|
3373
|
-
wishVelocity: wishvel,
|
|
3374
|
-
onLadder,
|
|
3375
|
-
onGround,
|
|
3376
|
-
waterlevel,
|
|
3377
|
-
watertype,
|
|
3378
|
-
groundContents,
|
|
3692
|
+
let velocity = applyFlyFriction({ velocity: params.velocity, pmFriction, pmStopSpeed, frametime });
|
|
3693
|
+
const wishdirVelocity = buildFlyWishVelocity({
|
|
3379
3694
|
cmd,
|
|
3380
|
-
viewPitch,
|
|
3381
|
-
maxSpeed: hasPmFlag(pmFlags, 1 /* Ducked */) ? pmDuckSpeed : pmMaxSpeed,
|
|
3382
|
-
ladderMod,
|
|
3383
|
-
waterSpeed: pmWaterSpeed,
|
|
3384
3695
|
forward,
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
trace
|
|
3696
|
+
right,
|
|
3697
|
+
pmMaxSpeed,
|
|
3698
|
+
pmWaterSpeed
|
|
3389
3699
|
});
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3700
|
+
if (wishdirVelocity.wishspeed > 0) {
|
|
3701
|
+
velocity = applyPmoveAccelerate({
|
|
3702
|
+
velocity,
|
|
3703
|
+
wishdir: wishdirVelocity.wishdir,
|
|
3704
|
+
wishspeed: wishdirVelocity.accelSpeed,
|
|
3705
|
+
accel: pmAccelerate,
|
|
3706
|
+
frametime
|
|
3707
|
+
});
|
|
3394
3708
|
}
|
|
3395
|
-
if (
|
|
3396
|
-
const
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3400
|
-
|
|
3401
|
-
|
|
3709
|
+
if (!doclip) {
|
|
3710
|
+
const originDelta = scaleVec3(velocity, frametime);
|
|
3711
|
+
const nextOrigin = addVec3(origin, originDelta);
|
|
3712
|
+
return {
|
|
3713
|
+
origin: nextOrigin,
|
|
3714
|
+
velocity,
|
|
3715
|
+
planes: [],
|
|
3716
|
+
blocked: 0,
|
|
3717
|
+
stopped: velocity.x === 0 && velocity.y === 0 && velocity.z === 0,
|
|
3718
|
+
stepped: false,
|
|
3719
|
+
stepHeight: 0
|
|
3720
|
+
};
|
|
3402
3721
|
}
|
|
3403
|
-
|
|
3404
|
-
|
|
3405
|
-
if (ducked && wishspeed > pmDuckSpeed) {
|
|
3406
|
-
const scale = pmDuckSpeed / wishspeed;
|
|
3407
|
-
wishvel = scaleVec3(wishvel, scale);
|
|
3408
|
-
wishspeed = pmDuckSpeed;
|
|
3409
|
-
if (wishspeed !== 0) {
|
|
3410
|
-
wishdir = normalizeVec3(wishvel);
|
|
3411
|
-
}
|
|
3722
|
+
if (!trace || !mins || !maxs) {
|
|
3723
|
+
throw new Error("applyPmoveFlyMove: doclip=true requires trace/mins/maxs");
|
|
3412
3724
|
}
|
|
3413
|
-
|
|
3414
|
-
return runStepSlideMove({
|
|
3725
|
+
return stepSlideMove({
|
|
3415
3726
|
origin,
|
|
3416
3727
|
velocity,
|
|
3417
3728
|
frametime,
|
|
3729
|
+
overbounce,
|
|
3730
|
+
trace,
|
|
3418
3731
|
mins,
|
|
3419
3732
|
maxs,
|
|
3420
|
-
trace,
|
|
3421
|
-
overbounce,
|
|
3422
3733
|
stepSize,
|
|
3423
3734
|
maxBumps,
|
|
3424
|
-
maxClipPlanes
|
|
3425
|
-
hasTime
|
|
3735
|
+
maxClipPlanes
|
|
3426
3736
|
});
|
|
3427
3737
|
}
|
|
3428
|
-
function
|
|
3429
|
-
|
|
3430
|
-
|
|
3431
|
-
|
|
3432
|
-
z: 0
|
|
3433
|
-
}
|
|
3738
|
+
function applyFlyFriction(params) {
|
|
3739
|
+
const { velocity, pmFriction, pmStopSpeed, frametime } = params;
|
|
3740
|
+
const speed = lengthVec3(velocity);
|
|
3741
|
+
if (speed < 1) {
|
|
3742
|
+
return { x: 0, y: 0, z: 0 };
|
|
3743
|
+
}
|
|
3744
|
+
const friction = pmFriction * FLY_FRICTION_MULTIPLIER;
|
|
3745
|
+
const control = speed < pmStopSpeed ? pmStopSpeed : speed;
|
|
3746
|
+
const drop = control * friction * frametime;
|
|
3747
|
+
let newspeed = speed - drop;
|
|
3748
|
+
if (newspeed < 0) {
|
|
3749
|
+
newspeed = 0;
|
|
3750
|
+
}
|
|
3751
|
+
if (newspeed === speed) {
|
|
3752
|
+
return velocity;
|
|
3753
|
+
}
|
|
3754
|
+
return scaleVec3(velocity, newspeed / speed);
|
|
3434
3755
|
}
|
|
3435
|
-
function
|
|
3436
|
-
|
|
3437
|
-
|
|
3438
|
-
|
|
3439
|
-
|
|
3756
|
+
function buildFlyWishVelocity(params) {
|
|
3757
|
+
const { cmd, forward, right, pmMaxSpeed, pmWaterSpeed } = params;
|
|
3758
|
+
const forwardNorm = normalizeVec3(forward);
|
|
3759
|
+
const rightNorm = normalizeVec3(right);
|
|
3760
|
+
const wishvel = {
|
|
3761
|
+
x: forwardNorm.x * cmd.forwardmove + rightNorm.x * cmd.sidemove,
|
|
3762
|
+
y: forwardNorm.y * cmd.forwardmove + rightNorm.y * cmd.sidemove,
|
|
3763
|
+
z: forwardNorm.z * cmd.forwardmove + rightNorm.z * cmd.sidemove
|
|
3440
3764
|
};
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
}
|
|
3445
|
-
function isIdleInWater(cmd, onGround) {
|
|
3446
|
-
const noMove = cmd.forwardmove === 0 && cmd.sidemove === 0;
|
|
3447
|
-
const noButtons = (cmd.buttons ?? 0) & (8 /* Jump */ | 16 /* Crouch */) ? false : true;
|
|
3448
|
-
return noMove && noButtons && !onGround;
|
|
3449
|
-
}
|
|
3450
|
-
function dampVerticalVelocity(velocity, gravity, frametime) {
|
|
3451
|
-
let z = velocity.z;
|
|
3452
|
-
const delta = gravity * frametime;
|
|
3453
|
-
if (z > 0) {
|
|
3454
|
-
z -= delta;
|
|
3455
|
-
if (z < 0) {
|
|
3456
|
-
z = 0;
|
|
3457
|
-
}
|
|
3458
|
-
} else {
|
|
3459
|
-
z += delta;
|
|
3460
|
-
if (z > 0) {
|
|
3461
|
-
z = 0;
|
|
3462
|
-
}
|
|
3765
|
+
let adjusted = wishvel;
|
|
3766
|
+
const buttons = cmd.buttons ?? 0;
|
|
3767
|
+
if (buttons & 8 /* Jump */) {
|
|
3768
|
+
adjusted = addVec3(adjusted, { x: 0, y: 0, z: pmWaterSpeed * BUTTON_VERTICAL_SCALE });
|
|
3463
3769
|
}
|
|
3464
|
-
|
|
3465
|
-
}
|
|
3466
|
-
|
|
3467
|
-
|
|
3468
|
-
|
|
3469
|
-
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
maxBumps,
|
|
3478
|
-
maxClipPlanes,
|
|
3479
|
-
hasTime
|
|
3480
|
-
});
|
|
3770
|
+
if (buttons & 16 /* Crouch */) {
|
|
3771
|
+
adjusted = addVec3(adjusted, { x: 0, y: 0, z: -pmWaterSpeed * BUTTON_VERTICAL_SCALE });
|
|
3772
|
+
}
|
|
3773
|
+
let wishspeed = lengthVec3(adjusted);
|
|
3774
|
+
let wishdir = wishspeed === 0 ? { x: 0, y: 0, z: 0 } : normalizeVec3(adjusted);
|
|
3775
|
+
if (wishspeed > pmMaxSpeed) {
|
|
3776
|
+
const scale = pmMaxSpeed / wishspeed;
|
|
3777
|
+
adjusted = scaleVec3(adjusted, scale);
|
|
3778
|
+
wishspeed = pmMaxSpeed;
|
|
3779
|
+
wishdir = wishspeed === 0 ? { x: 0, y: 0, z: 0 } : normalizeVec3(adjusted);
|
|
3780
|
+
}
|
|
3781
|
+
const accelSpeed = wishspeed * 2;
|
|
3782
|
+
return { wishdir, wishspeed, accelSpeed };
|
|
3481
3783
|
}
|
|
3482
3784
|
|
|
3483
3785
|
// src/pmove/special.ts
|
|
@@ -4421,7 +4723,7 @@ var U_MODEL4 = 1 << 2;
|
|
|
4421
4723
|
var U_REMOVE = 32768;
|
|
4422
4724
|
|
|
4423
4725
|
// src/pmove/apply.ts
|
|
4424
|
-
var
|
|
4726
|
+
var FRAMETIME2 = 0.025;
|
|
4425
4727
|
var MASK_WATER2 = 33554432;
|
|
4426
4728
|
var WaterLevel3 = {
|
|
4427
4729
|
None: 0,
|
|
@@ -4475,7 +4777,7 @@ var applyPmove = (state, cmd, trace, pointContents2) => {
|
|
|
4475
4777
|
const { forward, right } = angleVectors(adjustedAngles);
|
|
4476
4778
|
const frictionedVelocity = applyPmoveFriction({
|
|
4477
4779
|
velocity,
|
|
4478
|
-
frametime:
|
|
4780
|
+
frametime: FRAMETIME2,
|
|
4479
4781
|
onGround,
|
|
4480
4782
|
groundIsSlick: false,
|
|
4481
4783
|
onLadder: false,
|
|
@@ -4501,12 +4803,12 @@ var applyPmove = (state, cmd, trace, pointContents2) => {
|
|
|
4501
4803
|
wishspeed: wish.wishspeed,
|
|
4502
4804
|
// Water movement uses ground acceleration (10), not air acceleration (1)
|
|
4503
4805
|
accel: onGround || waterLevel >= 2 ? 10 : 1,
|
|
4504
|
-
frametime:
|
|
4806
|
+
frametime: FRAMETIME2
|
|
4505
4807
|
});
|
|
4506
4808
|
const traceResult = trace(origin, {
|
|
4507
|
-
x: origin.x + finalVelocity.x *
|
|
4508
|
-
y: origin.y + finalVelocity.y *
|
|
4509
|
-
z: origin.z + finalVelocity.z *
|
|
4809
|
+
x: origin.x + finalVelocity.x * FRAMETIME2,
|
|
4810
|
+
y: origin.y + finalVelocity.y * FRAMETIME2,
|
|
4811
|
+
z: origin.z + finalVelocity.z * FRAMETIME2
|
|
4510
4812
|
});
|
|
4511
4813
|
return {
|
|
4512
4814
|
...newState,
|
|
@@ -5375,6 +5677,7 @@ function calculateMaxAudibleDistance(attenuation) {
|
|
|
5375
5677
|
applyPmoveAirMove,
|
|
5376
5678
|
applyPmoveFlyMove,
|
|
5377
5679
|
applyPmoveFriction,
|
|
5680
|
+
applyPmoveWalkMove,
|
|
5378
5681
|
applyPmoveWaterMove,
|
|
5379
5682
|
assertContract,
|
|
5380
5683
|
attenuationToDistanceMultiplier,
|
|
@@ -5450,6 +5753,7 @@ function calculateMaxAudibleDistance(attenuation) {
|
|
|
5450
5753
|
removePmFlag,
|
|
5451
5754
|
resolveSlideMove,
|
|
5452
5755
|
rotatePointAroundVector,
|
|
5756
|
+
runPmove,
|
|
5453
5757
|
scaleVec3,
|
|
5454
5758
|
slerpVec3,
|
|
5455
5759
|
slideClipVelocityVec3,
|