quake2ts 0.0.296 → 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.
Files changed (44) hide show
  1. package/package.json +1 -1
  2. package/packages/cgame/dist/index.cjs +3 -1
  3. package/packages/cgame/dist/index.cjs.map +1 -1
  4. package/packages/cgame/dist/index.js +3 -1
  5. package/packages/cgame/dist/index.js.map +1 -1
  6. package/packages/client/dist/browser/index.global.js +13 -13
  7. package/packages/client/dist/browser/index.global.js.map +1 -1
  8. package/packages/client/dist/cjs/index.cjs +20 -11
  9. package/packages/client/dist/cjs/index.cjs.map +1 -1
  10. package/packages/client/dist/esm/index.js +20 -11
  11. package/packages/client/dist/esm/index.js.map +1 -1
  12. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  13. package/packages/engine/dist/browser/index.global.js +8 -8
  14. package/packages/engine/dist/browser/index.global.js.map +1 -1
  15. package/packages/engine/dist/cjs/index.cjs +11 -2
  16. package/packages/engine/dist/cjs/index.cjs.map +1 -1
  17. package/packages/engine/dist/esm/index.js +11 -2
  18. package/packages/engine/dist/esm/index.js.map +1 -1
  19. package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
  20. package/packages/engine/dist/types/demo/parser.d.ts.map +1 -1
  21. package/packages/game/dist/browser/index.global.js +4 -4
  22. package/packages/game/dist/browser/index.global.js.map +1 -1
  23. package/packages/game/dist/cjs/index.cjs +67 -20
  24. package/packages/game/dist/cjs/index.cjs.map +1 -1
  25. package/packages/game/dist/esm/index.js +67 -20
  26. package/packages/game/dist/esm/index.js.map +1 -1
  27. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  28. package/packages/game/dist/types/ai/movement.d.ts.map +1 -1
  29. package/packages/shared/dist/browser/index.global.js +1 -1
  30. package/packages/shared/dist/browser/index.global.js.map +1 -1
  31. package/packages/shared/dist/cjs/index.cjs +1342 -1038
  32. package/packages/shared/dist/cjs/index.cjs.map +1 -1
  33. package/packages/shared/dist/esm/index.js +1340 -1038
  34. package/packages/shared/dist/esm/index.js.map +1 -1
  35. package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
  36. package/packages/shared/dist/types/pmove/jump.d.ts +2 -0
  37. package/packages/shared/dist/types/pmove/jump.d.ts.map +1 -1
  38. package/packages/shared/dist/types/pmove/move.d.ts +20 -0
  39. package/packages/shared/dist/types/pmove/move.d.ts.map +1 -1
  40. package/packages/shared/dist/types/pmove/pmove.d.ts +5 -1
  41. package/packages/shared/dist/types/pmove/pmove.d.ts.map +1 -1
  42. package/packages/shared/dist/types/pmove/types.d.ts +25 -1
  43. package/packages/shared/dist/types/pmove/types.d.ts.map +1 -1
  44. 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__ */ ((PlayerButton2) => {
2136
- PlayerButton2[PlayerButton2["None"] = 0] = "None";
2137
- PlayerButton2[PlayerButton2["Attack"] = 1] = "Attack";
2138
- PlayerButton2[PlayerButton2["Use"] = 2] = "Use";
2139
- PlayerButton2[PlayerButton2["Holster"] = 4] = "Holster";
2140
- PlayerButton2[PlayerButton2["Jump"] = 8] = "Jump";
2141
- PlayerButton2[PlayerButton2["Crouch"] = 16] = "Crouch";
2142
- PlayerButton2[PlayerButton2["Any"] = 128] = "Any";
2143
- return PlayerButton2;
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/pmove.ts
2147
- function applyPmoveFriction(params) {
2148
- const {
2149
- velocity,
2150
- frametime,
2151
- onGround,
2152
- groundIsSlick,
2153
- onLadder,
2154
- waterlevel,
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
- let drop = 0;
2164
- if (onGround && !groundIsSlick || onLadder) {
2165
- const control = speed < pmStopSpeed ? pmStopSpeed : speed;
2166
- const friction = pmFriction;
2167
- drop += control * friction * frametime;
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 (waterlevel > 0 && !onLadder) {
2170
- drop += speed * pmWaterFriction * waterlevel * frametime;
2169
+ if (hasPmJumpHold(nextFlags)) {
2170
+ return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
2171
2171
  }
2172
- let newspeed = speed - drop;
2173
- if (newspeed < 0) {
2174
- newspeed = 0;
2172
+ if (pmType === 4 /* Dead */) {
2173
+ return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
2175
2174
  }
2176
- if (newspeed === speed) {
2177
- return velocity;
2175
+ if (waterlevel >= 2 /* Waist */) {
2176
+ nextOnGround = false;
2177
+ return { pmFlags: nextFlags, onGround: nextOnGround, velocity: nextVelocity, origin: nextOrigin, jumpSound, jumped };
2178
2178
  }
2179
- const scale = newspeed / speed;
2180
- return scaleVec3(velocity, scale);
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 applyPmoveAccelerate(params) {
2183
- const { velocity, wishdir, wishspeed, accel, frametime } = params;
2184
- const currentSpeed = dotVec3(velocity, wishdir);
2185
- const addSpeed = wishspeed - currentSpeed;
2186
- if (addSpeed <= 0) {
2187
- return velocity;
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
- let accelSpeed = accel * frametime * wishspeed;
2190
- if (accelSpeed > addSpeed) {
2191
- accelSpeed = addSpeed;
2218
+ if (contents & CONTENTS_CURRENT_90) {
2219
+ y += 1;
2192
2220
  }
2193
- return {
2194
- x: velocity.x + wishdir.x * accelSpeed,
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
- let accelSpeed = accel * wishspeed * frametime;
2208
- if (accelSpeed > addSpeed) {
2209
- accelSpeed = addSpeed;
2224
+ if (contents & CONTENTS_CURRENT_270) {
2225
+ y -= 1;
2210
2226
  }
2211
- return {
2212
- x: velocity.x + wishdir.x * accelSpeed,
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
- const total = Math.sqrt(cmd.forwardmove * cmd.forwardmove + cmd.sidemove * cmd.sidemove + cmd.upmove * cmd.upmove);
2226
- return maxSpeed * max / (127 * total);
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
- return {
2242
- wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
2243
- wishspeed
2244
- };
2233
+ if (x === 0 && y === 0 && z === 0) {
2234
+ return ZERO_VEC3;
2235
+ }
2236
+ return { x, y, z };
2245
2237
  }
2246
- function buildWaterWish(params) {
2247
- const { forward, right, cmd, maxSpeed } = params;
2248
- let wishvel = {
2249
- x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
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
- let wishspeed = lengthVec3(wishvel);
2263
- if (wishspeed > maxSpeed) {
2264
- const scale = maxSpeed / wishspeed;
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
- wishspeed *= 0.5;
2269
- return {
2270
- wishdir: wishspeed === 0 ? wishvel : normalizeVec3(wishvel),
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
- const planes = [];
2287
- let velocity = initialVelocity;
2288
- for (const plane of planesEncountered) {
2289
- if (planes.length >= maxClipPlanes) {
2290
- return { velocity: ZERO_VEC3, planes, stopped: true };
2291
- }
2292
- const duplicate = planes.find((existing) => dotVec3(existing, plane) > 0.99);
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
- const stopped = velocity.x === 0 && velocity.y === 0 && velocity.z === 0;
2326
- return { velocity, planes, stopped };
2259
+ return scaleVec3(direction, scale);
2327
2260
  }
2328
- function slideMove(params) {
2261
+ function applyPmoveAddCurrents(params) {
2329
2262
  const {
2330
- origin: initialOrigin,
2331
- velocity: initialVelocity,
2332
- frametime,
2333
- overbounce,
2334
- trace,
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/stuck.ts
2434
- var AXES = ["x", "y", "z"];
2435
- var SIDE_CHECKS = [
2436
- { normal: [0, 0, 1], mins: [-1, -1, 0], maxs: [1, 1, 0] },
2437
- { normal: [0, 0, -1], mins: [-1, -1, 0], maxs: [1, 1, 0] },
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
- wishVelocity,
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 = DEFAULT_TRACE
2692
- } = params;
2693
- let adjusted = wishVelocity;
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
- adjusted = applyLadderAdjustments({
2696
- wishVelocity: adjusted,
2697
- cmd,
2698
- waterlevel,
2699
- viewPitch,
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
- const groundVelocity = groundCurrentVelocity({ groundContents });
2716
- if (groundVelocity !== ZERO_VEC3) {
2717
- adjusted = addVec3(adjusted, groundVelocity);
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
- return adjusted;
2721
- }
2722
- function applyLadderAdjustments(params) {
2723
- const { wishVelocity, cmd, waterlevel, viewPitch, maxSpeed, ladderMod, onGround, forward, origin, mins, maxs, trace } = params;
2724
- const buttons = cmd.buttons ?? 0;
2725
- let adjusted = { ...wishVelocity };
2726
- if ((buttons & (8 /* Jump */ | 16 /* Crouch */)) !== 0) {
2727
- const ladderSpeed = isAtLeastWaistDeep(waterlevel) ? maxSpeed : DEFAULT_FORWARD_LADDER_CLAMP;
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
- return adjusted;
2771
- }
2772
- function clamp(value, min, max) {
2773
- return Math.max(min, Math.min(max, value));
2774
- }
2775
- function clampHorizontal(value) {
2776
- if (value < -LADDER_HORIZONTAL_CAP) {
2777
- return -LADDER_HORIZONTAL_CAP;
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 (value > LADDER_HORIZONTAL_CAP) {
2780
- return LADDER_HORIZONTAL_CAP;
2663
+ if (pmType !== 1 /* Grapple */) {
2664
+ velocity = { ...velocity, z: velocity.z - gravity * frametime };
2781
2665
  }
2782
- return value;
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 = DEFAULT_OVERBOUNCE,
2687
+ overbounce = DEFAULT_STEP_OVERBOUNCE,
2806
2688
  stepSize,
2807
2689
  maxBumps,
2808
- maxClipPlanes
2809
- } = params;
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
- pmWaterSpeed
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
- if (wishdirVelocity.wishspeed > 0) {
2819
- velocity = applyPmoveAccelerate({
2820
- velocity,
2821
- wishdir: wishdirVelocity.wishdir,
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 (!doclip) {
2828
- const originDelta = scaleVec3(velocity, frametime);
2829
- const nextOrigin = addVec3(origin, originDelta);
2830
- return {
2831
- origin: nextOrigin,
2832
- velocity,
2833
- planes: [],
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
- if (!trace || !mins || !maxs) {
2841
- throw new Error("applyPmoveFlyMove: doclip=true requires trace/mins/maxs");
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
- return stepSlideMove({
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 applyFlyFriction(params) {
2857
- const { velocity, pmFriction, pmStopSpeed, frametime } = params;
2858
- const speed = lengthVec3(velocity);
2859
- if (speed < 1) {
2860
- return { x: 0, y: 0, z: 0 };
2861
- }
2862
- const friction = pmFriction * FLY_FRICTION_MULTIPLIER;
2863
- const control = speed < pmStopSpeed ? pmStopSpeed : speed;
2864
- const drop = control * friction * frametime;
2865
- let newspeed = speed - drop;
2866
- if (newspeed < 0) {
2867
- newspeed = 0;
2868
- }
2869
- if (newspeed === speed) {
2870
- return velocity;
2871
- }
2872
- return scaleVec3(velocity, newspeed / speed);
2873
- }
2874
- function buildFlyWishVelocity(params) {
2875
- const { cmd, forward, right, pmMaxSpeed, pmWaterSpeed } = params;
2876
- const forwardNorm = normalizeVec3(forward);
2877
- const rightNorm = normalizeVec3(right);
2878
- const wishvel = {
2879
- x: forwardNorm.x * cmd.forwardmove + rightNorm.x * cmd.sidemove,
2880
- y: forwardNorm.y * cmd.forwardmove + rightNorm.y * cmd.sidemove,
2881
- z: forwardNorm.z * cmd.forwardmove + rightNorm.z * cmd.sidemove
2882
- };
2883
- let adjusted = wishvel;
2884
- const buttons = cmd.buttons ?? 0;
2885
- if (buttons & 8 /* Jump */) {
2886
- adjusted = addVec3(adjusted, { x: 0, y: 0, z: pmWaterSpeed * BUTTON_VERTICAL_SCALE });
2887
- }
2888
- if (buttons & 16 /* Crouch */) {
2889
- adjusted = addVec3(adjusted, { x: 0, y: 0, z: -pmWaterSpeed * BUTTON_VERTICAL_SCALE });
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
- let wishspeed = lengthVec3(adjusted);
2892
- let wishdir = wishspeed === 0 ? { x: 0, y: 0, z: 0 } : normalizeVec3(adjusted);
2893
- if (wishspeed > pmMaxSpeed) {
2894
- const scale = pmMaxSpeed / wishspeed;
2895
- adjusted = scaleVec3(adjusted, scale);
2896
- wishspeed = pmMaxSpeed;
2897
- wishdir = wishspeed === 0 ? { x: 0, y: 0, z: 0 } : normalizeVec3(adjusted);
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
- const accelSpeed = wishspeed * 2;
2900
- return { wishdir, wishspeed, accelSpeed };
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/jump.ts
2933
- var DEFAULT_JUMP_HEIGHT = 270;
2934
- function hasButton(buttons, button) {
2935
- return (buttons & button) !== 0;
2936
- }
2937
- function checkJump(params) {
2938
- const { pmFlags, pmType, buttons, waterlevel, onGround, velocity, jumpHeight = DEFAULT_JUMP_HEIGHT } = params;
2939
- if (pmFlags & 16 /* TimeLand */) {
2940
- return { pmFlags, onGround, velocity, jumpSound: false, jumped: false };
2941
- }
2942
- const holdingJump = hasButton(buttons, 8 /* Jump */);
2943
- let nextFlags = pmFlags;
2944
- let nextOnGround = onGround;
2945
- let jumpSound = false;
2946
- let jumped = false;
2947
- let nextVelocity = velocity;
2948
- if (!holdingJump) {
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/move.ts
3184
- var DEFAULT_AIR_ACCELERATE = 1;
3185
- var WATER_DRIFT_SPEED = 60;
3186
- var DEFAULT_STEP_OVERBOUNCE = 1.01;
3187
- function applyPmoveAirMove(params) {
3188
- const {
3189
- origin,
3190
- frametime,
3191
- mins,
3192
- maxs,
3193
- trace,
3194
- overbounce = DEFAULT_STEP_OVERBOUNCE,
3195
- stepSize,
3196
- maxBumps,
3197
- maxClipPlanes,
3198
- hasTime,
3199
- forward,
3200
- right,
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
- trace
3237
- });
3238
- const ducked = hasPmFlag(pmFlags, 1 /* Ducked */);
3239
- const maxSpeed = ducked ? pmDuckSpeed : pmMaxSpeed;
3240
- let wishdir = wishvel;
3241
- let wishspeed = lengthVec3(wishdir);
3242
- if (wishspeed !== 0) {
3243
- wishdir = normalizeVec3(wishdir);
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
- if (wishspeed > maxSpeed) {
3246
- const scale = maxSpeed / wishspeed;
3247
- wishvel = scaleVec3(wishvel, scale);
3248
- wishspeed = maxSpeed;
3249
- if (wishspeed !== 0) {
3250
- wishdir = normalizeVec3(wishvel);
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
- if (onLadder) {
3254
- velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: pmAccelerate, frametime });
3255
- if (Math.abs(wishvel.z) < Number.EPSILON) {
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
- return runStepSlideMove({
3259
- origin,
3260
- velocity,
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
- if (onGround) {
3273
- velocity = { ...velocity, z: 0 };
3274
- velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: pmAccelerate, frametime });
3275
- if (gravity > 0) {
3276
- velocity = { ...velocity, z: 0 };
3277
- } else {
3278
- velocity = { ...velocity, z: velocity.z - gravity * frametime };
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 (pmAirAccelerate > 0) {
3306
- velocity = applyPmoveAirAccelerate({
3307
- velocity,
3308
- wishdir,
3309
- wishspeed,
3310
- accel: pmAirAccelerate,
3311
- frametime
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
- velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: DEFAULT_AIR_ACCELERATE, frametime });
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 (pmType !== 1 /* Grapple */) {
3317
- velocity = { ...velocity, z: velocity.z - gravity * frametime };
3660
+ if (candidates.length === 0) {
3661
+ return { result: "no-good-position", origin: { ...origin } };
3318
3662
  }
3319
- return runStepSlideMove({
3320
- origin,
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
- function applyPmoveWaterMove(params) {
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 = DEFAULT_STEP_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 = { ...params.velocity };
3362
- let wishvel = buildFullWishVelocity(forward, right, cmd);
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
- origin,
3386
- mins,
3387
- maxs,
3388
- trace
3696
+ right,
3697
+ pmMaxSpeed,
3698
+ pmWaterSpeed
3389
3699
  });
3390
- let wishdir = wishvel;
3391
- let wishspeed = lengthVec3(wishdir);
3392
- if (wishspeed !== 0) {
3393
- wishdir = normalizeVec3(wishdir);
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 (wishspeed > pmMaxSpeed) {
3396
- const scale = pmMaxSpeed / wishspeed;
3397
- wishvel = scaleVec3(wishvel, scale);
3398
- wishspeed = pmMaxSpeed;
3399
- if (wishspeed !== 0) {
3400
- wishdir = normalizeVec3(wishvel);
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
- wishspeed *= 0.5;
3404
- const ducked = hasPmFlag(pmFlags, 1 /* Ducked */);
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
- velocity = applyPmoveAccelerate({ velocity, wishdir, wishspeed, accel: pmWaterAccelerate, frametime });
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 buildPlanarWishVelocity(forward, right, cmd) {
3429
- return {
3430
- x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
3431
- y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
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 buildFullWishVelocity(forward, right, cmd) {
3436
- return {
3437
- x: forward.x * cmd.forwardmove + right.x * cmd.sidemove,
3438
- y: forward.y * cmd.forwardmove + right.y * cmd.sidemove,
3439
- z: forward.z * cmd.forwardmove + right.z * cmd.sidemove
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
- function hasButton2(cmd, button) {
3443
- return (cmd.buttons ?? 0) & button ? true : false;
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
- return { ...velocity, z };
3465
- }
3466
- function runStepSlideMove(params) {
3467
- const { origin, velocity, frametime, mins, maxs, trace, overbounce = DEFAULT_STEP_OVERBOUNCE, stepSize, maxBumps, maxClipPlanes, hasTime } = params;
3468
- return stepSlideMove({
3469
- origin,
3470
- velocity,
3471
- frametime,
3472
- trace,
3473
- mins,
3474
- maxs,
3475
- overbounce,
3476
- stepSize,
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 FRAMETIME = 0.025;
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: 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: FRAMETIME
4806
+ frametime: FRAMETIME2
4505
4807
  });
4506
4808
  const traceResult = trace(origin, {
4507
- x: origin.x + finalVelocity.x * FRAMETIME,
4508
- y: origin.y + finalVelocity.y * FRAMETIME,
4509
- z: origin.z + finalVelocity.z * FRAMETIME
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,