quake2ts 0.0.432 → 0.0.434

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 (51) hide show
  1. package/package.json +1 -1
  2. package/packages/cgame/dist/index.cjs +27 -17
  3. package/packages/cgame/dist/index.cjs.map +1 -1
  4. package/packages/cgame/dist/index.d.cts +2 -0
  5. package/packages/cgame/dist/index.d.ts +2 -0
  6. package/packages/cgame/dist/index.js +27 -17
  7. package/packages/cgame/dist/index.js.map +1 -1
  8. package/packages/client/dist/browser/index.global.js +16 -16
  9. package/packages/client/dist/browser/index.global.js.map +1 -1
  10. package/packages/client/dist/cjs/index.cjs +9 -0
  11. package/packages/client/dist/cjs/index.cjs.map +1 -1
  12. package/packages/client/dist/esm/index.js +9 -0
  13. package/packages/client/dist/esm/index.js.map +1 -1
  14. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  15. package/packages/client/dist/types/index.d.ts.map +1 -1
  16. package/packages/client/dist/types/net/serverBrowser.d.ts +6 -0
  17. package/packages/client/dist/types/net/serverBrowser.d.ts.map +1 -1
  18. package/packages/game/dist/browser/index.global.js +4 -4
  19. package/packages/game/dist/browser/index.global.js.map +1 -1
  20. package/packages/game/dist/cjs/index.cjs +248 -77
  21. package/packages/game/dist/cjs/index.cjs.map +1 -1
  22. package/packages/game/dist/esm/index.js +248 -77
  23. package/packages/game/dist/esm/index.js.map +1 -1
  24. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  25. package/packages/game/dist/types/combat/weapons/chaingun.d.ts.map +1 -1
  26. package/packages/game/dist/types/combat/weapons/firing.d.ts +9 -0
  27. package/packages/game/dist/types/combat/weapons/firing.d.ts.map +1 -1
  28. package/packages/game/dist/types/combat/weapons/supershotgun.d.ts.map +1 -1
  29. package/packages/game/dist/types/entities/player.d.ts.map +1 -1
  30. package/packages/game/dist/types/entities/system.d.ts.map +1 -1
  31. package/packages/game/dist/types/imports.d.ts +2 -0
  32. package/packages/game/dist/types/imports.d.ts.map +1 -1
  33. package/packages/game/dist/types/index.d.ts +1 -0
  34. package/packages/game/dist/types/index.d.ts.map +1 -1
  35. package/packages/game/dist/types/inventory/playerInventory.d.ts +1 -0
  36. package/packages/game/dist/types/inventory/playerInventory.d.ts.map +1 -1
  37. package/packages/game/dist/types/modes/ctf/capture.d.ts +7 -0
  38. package/packages/game/dist/types/modes/ctf/capture.d.ts.map +1 -0
  39. package/packages/game/dist/types/modes/ctf/drop.d.ts +8 -0
  40. package/packages/game/dist/types/modes/ctf/drop.d.ts.map +1 -0
  41. package/packages/game/dist/types/modes/ctf/flag.d.ts.map +1 -1
  42. package/packages/game/dist/types/modes/ctf/integration.d.ts +4 -0
  43. package/packages/game/dist/types/modes/ctf/integration.d.ts.map +1 -0
  44. package/packages/game/dist/types/modes/ctf/pickup.d.ts +6 -0
  45. package/packages/game/dist/types/modes/ctf/pickup.d.ts.map +1 -0
  46. package/packages/game/dist/types/modes/ctf/state.d.ts +15 -0
  47. package/packages/game/dist/types/modes/ctf/state.d.ts.map +1 -0
  48. package/packages/server/dist/index.cjs +122 -1
  49. package/packages/server/dist/index.d.cts +4 -0
  50. package/packages/server/dist/index.d.ts +4 -0
  51. package/packages/server/dist/index.js +122 -1
@@ -4652,6 +4652,8 @@ var EntitySystem = class {
4652
4652
  configstring: () => {
4653
4653
  },
4654
4654
  serverCommand: () => {
4655
+ },
4656
+ setLagCompensation: () => {
4655
4657
  }
4656
4658
  };
4657
4659
  this.imports = { ...defaultImports, ...imports };
@@ -8328,6 +8330,7 @@ var FRAME_CHAINGUN_ACTIVATE_LAST = 4;
8328
8330
  var FRAME_CHAINGUN_FIRE_LAST = 21;
8329
8331
  var FRAME_CHAINGUN_IDLE_LAST = 52;
8330
8332
  var FRAME_CHAINGUN_DEACTIVATE_LAST = 61;
8333
+ var FRAME_CHAINGUN_SPINUP = 5;
8331
8334
  var FRAME_RAILGUN_ACTIVATE_LAST = 3;
8332
8335
  var FRAME_RAILGUN_FIRE_LAST = 18;
8333
8336
  var FRAME_RAILGUN_IDLE_LAST = 51;
@@ -8381,6 +8384,14 @@ var ANIM_DEATH = 3;
8381
8384
 
8382
8385
  // src/combat/weapons/firing.ts
8383
8386
  var random3 = createRandomGenerator();
8387
+ var DEFAULT_SHOTGUN_HSPREAD = 500;
8388
+ var DEFAULT_SHOTGUN_VSPREAD = 500;
8389
+ var DEFAULT_SSHOTGUN_HSPREAD = 1e3;
8390
+ var DEFAULT_SSHOTGUN_VSPREAD = 500;
8391
+ var DEFAULT_DEATHMATCH_SHOTGUN_COUNT = 12;
8392
+ var DEFAULT_SHOTGUN_COUNT = 12;
8393
+ var DEFAULT_SSHOTGUN_COUNT = 20;
8394
+ var BUTTON_ATTACK2 = 32;
8384
8395
  function applyKick(player, pitch, yaw = 0, kickOrigin = 0) {
8385
8396
  if (player.client) {
8386
8397
  player.client.kick_angles = { x: pitch, y: yaw, z: 0 };
@@ -8401,14 +8412,24 @@ function setPlayerAttackAnim(player) {
8401
8412
  }
8402
8413
  function fireHitscan(game, player, start, forward, damage, knockback, mod) {
8403
8414
  const end = { x: start.x + forward.x * 8192, y: start.y + forward.y * 8192, z: start.z + forward.z * 8192 };
8404
- const trace = game.trace(
8405
- start,
8406
- null,
8407
- null,
8408
- end,
8409
- player,
8410
- 0
8411
- );
8415
+ if (game.setLagCompensation && player.client) {
8416
+ game.setLagCompensation(true, player, player.client.ping);
8417
+ }
8418
+ let trace;
8419
+ try {
8420
+ trace = game.trace(
8421
+ start,
8422
+ null,
8423
+ null,
8424
+ end,
8425
+ player,
8426
+ 0
8427
+ );
8428
+ } finally {
8429
+ if (game.setLagCompensation) {
8430
+ game.setLagCompensation(false);
8431
+ }
8432
+ }
8412
8433
  if (trace.ent && trace.ent.takedamage) {
8413
8434
  T_Damage(
8414
8435
  trace.ent,
@@ -8431,31 +8452,40 @@ function fireHitscan(game, player, start, forward, damage, knockback, mod) {
8431
8452
  }
8432
8453
  }
8433
8454
  function fireMultiplePellets(game, player, start, forward, right, up, count, damage, knockback, hspread, vspread, mod) {
8434
- for (let i = 0; i < count; i++) {
8435
- const spread = addVec3(scaleVec3(right, random3.crandom() * hspread), scaleVec3(up, random3.crandom() * vspread));
8436
- const dir = addVec3(forward, spread);
8437
- const end = { x: start.x + dir.x * 8192, y: start.y + dir.y * 8192, z: start.z + dir.z * 8192 };
8438
- const trace = game.trace(start, null, null, end, player, 0);
8439
- if (trace.ent && trace.ent.takedamage) {
8440
- T_Damage(
8441
- trace.ent,
8442
- player,
8443
- player,
8444
- ZERO_VEC3,
8445
- trace.endpos,
8446
- trace.plane ? trace.plane.normal : ZERO_VEC3,
8447
- damage,
8448
- knockback,
8449
- 16 /* BULLET */,
8450
- mod,
8451
- game.time,
8452
- game.multicast
8453
- );
8454
- } else if (trace.plane) {
8455
- if (random3.frandom() > 0.9) {
8456
- game.multicast(trace.endpos, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.GUNSHOT, trace.endpos, trace.plane.normal);
8455
+ if (game.setLagCompensation && player.client) {
8456
+ game.setLagCompensation(true, player, player.client.ping);
8457
+ }
8458
+ try {
8459
+ for (let i = 0; i < count; i++) {
8460
+ const spread = addVec3(scaleVec3(right, random3.crandom() * hspread), scaleVec3(up, random3.crandom() * vspread));
8461
+ const dir = addVec3(forward, spread);
8462
+ const end = { x: start.x + dir.x * 8192, y: start.y + dir.y * 8192, z: start.z + dir.z * 8192 };
8463
+ const trace = game.trace(start, null, null, end, player, 0);
8464
+ if (trace.ent && trace.ent.takedamage) {
8465
+ T_Damage(
8466
+ trace.ent,
8467
+ player,
8468
+ player,
8469
+ ZERO_VEC3,
8470
+ trace.endpos,
8471
+ trace.plane ? trace.plane.normal : ZERO_VEC3,
8472
+ damage,
8473
+ knockback,
8474
+ 16 /* BULLET */,
8475
+ mod,
8476
+ game.time,
8477
+ game.multicast
8478
+ );
8479
+ } else if (trace.plane) {
8480
+ if (random3.frandom() > 0.9) {
8481
+ game.multicast(trace.endpos, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.GUNSHOT, trace.endpos, trace.plane.normal);
8482
+ }
8457
8483
  }
8458
8484
  }
8485
+ } finally {
8486
+ if (game.setLagCompensation) {
8487
+ game.setLagCompensation(false);
8488
+ }
8459
8489
  }
8460
8490
  }
8461
8491
  function fireRailgun(game, player, start, forward, damage, knockback) {
@@ -8465,33 +8495,42 @@ function fireRailgun(game, player, start, forward, damage, knockback) {
8465
8495
  let ignore = player;
8466
8496
  let count = 0;
8467
8497
  let finalEnd = end;
8468
- while (count < 16) {
8469
- count++;
8470
- const trace = game.trace(currentStart, null, null, end, ignore, 0);
8471
- finalEnd = trace.endpos;
8472
- if (trace.fraction >= 1) {
8473
- break;
8474
- }
8475
- if (trace.ent && trace.ent.takedamage) {
8476
- T_Damage(
8477
- trace.ent,
8478
- player,
8479
- player,
8480
- ZERO_VEC3,
8481
- trace.endpos,
8482
- trace.plane ? trace.plane.normal : ZERO_VEC3,
8483
- damage,
8484
- knockback,
8485
- 4 /* ENERGY */,
8486
- 11 /* RAILGUN */,
8487
- game.time,
8488
- game.multicast
8489
- );
8498
+ if (game.setLagCompensation && player.client) {
8499
+ game.setLagCompensation(true, player, player.client.ping);
8500
+ }
8501
+ try {
8502
+ while (count < 16) {
8503
+ count++;
8504
+ const trace = game.trace(currentStart, null, null, end, ignore, 0);
8505
+ finalEnd = trace.endpos;
8506
+ if (trace.fraction >= 1) {
8507
+ break;
8508
+ }
8509
+ if (trace.ent && trace.ent.takedamage) {
8510
+ T_Damage(
8511
+ trace.ent,
8512
+ player,
8513
+ player,
8514
+ ZERO_VEC3,
8515
+ trace.endpos,
8516
+ trace.plane ? trace.plane.normal : ZERO_VEC3,
8517
+ damage,
8518
+ knockback,
8519
+ 4 /* ENERGY */,
8520
+ 11 /* RAILGUN */,
8521
+ game.time,
8522
+ game.multicast
8523
+ );
8524
+ }
8525
+ ignore = trace.ent;
8526
+ currentStart = trace.endpos;
8527
+ if (!trace.ent || trace.ent === game.entities.world) {
8528
+ break;
8529
+ }
8490
8530
  }
8491
- ignore = trace.ent;
8492
- currentStart = trace.endpos;
8493
- if (!trace.ent || trace.ent === game.entities.world) {
8494
- break;
8531
+ } finally {
8532
+ if (game.setLagCompensation) {
8533
+ game.setLagCompensation(false);
8495
8534
  }
8496
8535
  }
8497
8536
  game.multicast(originalStart, 2 /* Phs */, ServerCommand.temp_entity, TempEntity.RAILTRAIL, originalStart, finalEnd);
@@ -8508,7 +8547,8 @@ function fireShotgun(game, player) {
8508
8547
  setPlayerAttackAnim(player);
8509
8548
  const { forward, right, up } = angleVectors(player.angles);
8510
8549
  const source = P_ProjectSource(game, player, { x: 8, y: 8, z: -8 }, forward, right, up);
8511
- fireMultiplePellets(game, player, source, forward, right, up, 12, 4, 1, 500, 500, 2 /* SHOTGUN */);
8550
+ const count = game.deathmatch ? DEFAULT_DEATHMATCH_SHOTGUN_COUNT : DEFAULT_SHOTGUN_COUNT;
8551
+ fireMultiplePellets(game, player, source, forward, right, up, count, 4, 1, DEFAULT_SHOTGUN_HSPREAD, DEFAULT_SHOTGUN_VSPREAD, 2 /* SHOTGUN */);
8512
8552
  }
8513
8553
  function fireSuperShotgun(game, player) {
8514
8554
  if (!player.client) return;
@@ -8516,16 +8556,26 @@ function fireSuperShotgun(game, player) {
8516
8556
  if (inventory.ammo.counts[AmmoType.Shells] < 2) {
8517
8557
  return;
8518
8558
  }
8559
+ const isPrecision = (player.client.buttons & BUTTON_ATTACK2) !== 0;
8519
8560
  inventory.ammo.counts[AmmoType.Shells] -= 2;
8520
8561
  game.multicast(player.origin, 1 /* Pvs */, ServerCommand.muzzleflash, player.index, MZ_SSHOTGUN);
8521
8562
  applyKick(player, -4, 0, -4);
8522
8563
  setPlayerAttackAnim(player);
8523
8564
  const { forward, right, up } = angleVectors(player.angles);
8524
8565
  const source = P_ProjectSource(game, player, { x: 8, y: 8, z: -8 }, forward, right, up);
8566
+ const count = DEFAULT_SSHOTGUN_COUNT / 2;
8567
+ let hspread = DEFAULT_SSHOTGUN_HSPREAD;
8568
+ let vspread = DEFAULT_SSHOTGUN_VSPREAD;
8569
+ let damage = 6;
8570
+ if (isPrecision) {
8571
+ hspread = 300;
8572
+ vspread = 150;
8573
+ damage = 4;
8574
+ }
8525
8575
  const { forward: forward1, right: right1, up: up1 } = angleVectors({ ...player.angles, y: player.angles.y - 5 });
8526
- fireMultiplePellets(game, player, source, forward1, right1, up1, 10, 6, 1, 700, 700, 3 /* SSHOTGUN */);
8576
+ fireMultiplePellets(game, player, source, forward1, right1, up1, count, damage, 1, hspread, vspread, 3 /* SSHOTGUN */);
8527
8577
  const { forward: forward2, right: right2, up: up2 } = angleVectors({ ...player.angles, y: player.angles.y + 5 });
8528
- fireMultiplePellets(game, player, source, forward2, right2, up2, 10, 6, 1, 700, 700, 3 /* SSHOTGUN */);
8578
+ fireMultiplePellets(game, player, source, forward2, right2, up2, count, damage, 1, hspread, vspread, 3 /* SSHOTGUN */);
8529
8579
  }
8530
8580
  function fireMachinegun(game, player) {
8531
8581
  if (!player.client) return;
@@ -8914,12 +8964,36 @@ function Throw_Generic(ent, FRAME_FIRE_LAST, FRAME_IDLE_LAST, FRAME_THROW_FIRST,
8914
8964
 
8915
8965
  // src/combat/weapons/chaingun.ts
8916
8966
  var CHAINGUN_PAUSE_FRAMES = [38, 43, 51, 61];
8967
+ var BUTTON_ATTACK22 = 32;
8917
8968
  function chaingunThink(player, sys) {
8918
8969
  const weaponState = getWeaponState(player.client.weaponStates, WeaponId.Chaingun);
8919
- if (!(player.client.buttons & BUTTON_ATTACK) && weaponState.spinupCount && weaponState.spinupCount > 0) {
8970
+ const client = player.client;
8971
+ if (!(client.buttons & BUTTON_ATTACK) && !(client.buttons & BUTTON_ATTACK22) && weaponState.spinupCount && weaponState.spinupCount > 0) {
8920
8972
  sys.sound(player, 0, "weapons/chngnd1a.wav", 1, 0, 0);
8921
8973
  weaponState.spinupCount = 0;
8922
8974
  }
8975
+ if (client.buttons & BUTTON_ATTACK22 && !(client.buttons & BUTTON_ATTACK)) {
8976
+ const spinupCount = (weaponState.spinupCount || 0) + 1;
8977
+ weaponState.spinupCount = spinupCount;
8978
+ const currentTime = sys.game ? sys.game.time : sys.timeSeconds * 1e3;
8979
+ weaponState.lastFireTime = currentTime;
8980
+ if (spinupCount > FRAME_CHAINGUN_SPINUP) {
8981
+ sys.sound(player, 0, "weapons/chngnl1a.wav", 1, 0, 0);
8982
+ } else {
8983
+ if (spinupCount === 1) {
8984
+ sys.sound(player, 0, "weapons/chngnu1a.wav", 1, 0, 0);
8985
+ }
8986
+ }
8987
+ if (client.gun_frame < FRAME_CHAINGUN_SPINUP || client.gun_frame > FRAME_CHAINGUN_FIRE_LAST) {
8988
+ client.gun_frame = FRAME_CHAINGUN_SPINUP;
8989
+ } else {
8990
+ client.gun_frame++;
8991
+ if (client.gun_frame > FRAME_CHAINGUN_FIRE_LAST) {
8992
+ client.gun_frame = FRAME_CHAINGUN_SPINUP;
8993
+ }
8994
+ }
8995
+ return;
8996
+ }
8923
8997
  Weapon_Repeating(
8924
8998
  player,
8925
8999
  FRAME_CHAINGUN_ACTIVATE_LAST,
@@ -8950,9 +9024,13 @@ function shotgunThink(player, sys) {
8950
9024
  }
8951
9025
 
8952
9026
  // src/combat/weapons/supershotgun.ts
9027
+ init_state();
9028
+ init_playerInventory();
8953
9029
  var SSHOTGUN_PAUSE_FRAMES = [29, 42, 57];
8954
9030
  var SSHOTGUN_FIRE_FRAMES = [22, 28];
8955
9031
  function superShotgunThink(player, sys) {
9032
+ const client = player.client;
9033
+ const weaponState = getWeaponState(client.weaponStates, WeaponId.SuperShotgun);
8956
9034
  Weapon_Generic(
8957
9035
  player,
8958
9036
  FRAME_SSHOTGUN_ACTIVATE_LAST,
@@ -9311,9 +9389,9 @@ function Weapon_ChainFist(player, sys) {
9311
9389
  fireChainfist(game, ent, inventory, weaponState, start, forward);
9312
9390
  if (ent.client) {
9313
9391
  const client = ent.client;
9314
- const BUTTON_ATTACK2 = 1;
9392
+ const BUTTON_ATTACK3 = 1;
9315
9393
  const buttons = client.buttons;
9316
- if (buttons & BUTTON_ATTACK2) {
9394
+ if (buttons & BUTTON_ATTACK3) {
9317
9395
  if (client.gun_frame === 12) client.gun_frame = 14;
9318
9396
  else if (client.gun_frame === 22) client.gun_frame = 24;
9319
9397
  else if (client.gun_frame >= 32) client.gun_frame = 7;
@@ -9932,32 +10010,68 @@ function createPowerArmorPickupEntity(game, item) {
9932
10010
 
9933
10011
  // src/modes/ctf/flag.ts
9934
10012
  init_playerInventory();
10013
+
10014
+ // src/modes/ctf/state.ts
10015
+ function setFlagState(flag, newState, context) {
10016
+ flag.flagState = newState;
10017
+ }
10018
+
10019
+ // src/modes/ctf/flag.ts
9935
10020
  function createFlagPickupEntity(game, flagItem) {
9936
- const drop = (self, context) => {
9937
- };
10021
+ const isRed = flagItem.team === "red";
9938
10022
  const respawn = (self) => {
10023
+ setFlagState(self, 0 /* AT_BASE */, game.entities);
9939
10024
  self.solid = 1 /* Trigger */;
10025
+ self.model = isRed ? "players/male/flag1.md2" : "players/male/flag2.md2";
10026
+ self.origin = { ...self.baseOrigin };
10027
+ self.svflags &= ~1;
9940
10028
  };
9941
10029
  return {
9942
10030
  classname: flagItem.id,
9943
10031
  solid: 1 /* Trigger */,
9944
- model: flagItem.team === "red" ? "players/male/flag1.md2" : "players/male/flag2.md2",
9945
- // Note: Models might need adjustment based on how Q2 handles skins for flags
9946
- // Original: "players/male/flag1.md2" (red) "players/male/flag2.md2" (blue)
9947
- // Usually it's just one model with skin change, but Q2 uses separate models for dropped flags often?
9948
- // Checking g_ctf.c: SP_item_flag_team1 sets ent->s.modelindex = gi.modelindex ("players/male/flag1.md2");
9949
- touch: (self, other) => {
10032
+ model: isRed ? "players/male/flag1.md2" : "players/male/flag2.md2",
10033
+ movetype: 0 /* None */,
10034
+ // Base flag is stationary
10035
+ // Initialize extended properties
10036
+ // We cast this object to Partial<Entity> which includes FlagEntity props if we extend definition
10037
+ // or we just assign them dynamically.
10038
+ // For type safety, we might need to cast to any here or define these props on Entity.
10039
+ // Since we can't easily modify Entity definition right now without a big refactor,
10040
+ // we assume runtime extensions are allowed or these are custom fields.
10041
+ flagState: 0 /* AT_BASE */,
10042
+ flagTeam: flagItem.team,
10043
+ baseOrigin: { x: 0, y: 0, z: 0 },
10044
+ touch: (selfEntity, other) => {
10045
+ const self = selfEntity;
9950
10046
  if (!other || !other.client) {
9951
10047
  return;
9952
10048
  }
9953
- if (pickupFlag(other.client, flagItem, game.time * 1e3)) {
9954
- game.sound?.(other, 0, "ctf/flagpk.wav", 1, 1, 0);
9955
- game.centerprintf?.(other, `You got the ${flagItem.name}`);
9956
- self.solid = 0 /* Not */;
9957
- self.model = void 0;
10049
+ const playerTeam = other.client.team || "red";
10050
+ const sameTeam = self.flagTeam === playerTeam;
10051
+ if (sameTeam) {
10052
+ if (self.flagState === 0 /* AT_BASE */) {
10053
+ return;
10054
+ }
10055
+ if (self.flagState === 2 /* DROPPED */) {
10056
+ game.sound?.(other, 0, "ctf/flagret.wav", 1, 1, 0);
10057
+ game.centerprintf?.(other, `You returned the ${flagItem.name}!`);
10058
+ respawn(self);
10059
+ }
10060
+ } else {
10061
+ if (pickupFlag(other.client, flagItem, game.time * 1e3)) {
10062
+ game.sound?.(other, 0, "ctf/flagpk.wav", 1, 1, 0);
10063
+ game.centerprintf?.(other, `You got the ${flagItem.name}!`);
10064
+ setFlagState(self, 1 /* CARRIED */, game.entities);
10065
+ self.solid = 0 /* Not */;
10066
+ self.model = void 0;
10067
+ self.owner = other;
10068
+ }
9958
10069
  }
9959
10070
  },
9960
- think: (self, context) => {
10071
+ think: (selfEntity, context) => {
10072
+ const self = selfEntity;
10073
+ if (self.flagState === 2 /* DROPPED */) {
10074
+ }
9961
10075
  }
9962
10076
  };
9963
10077
  }
@@ -24923,6 +25037,55 @@ function ClientObituary(self, inflictor, attacker, mod, sys) {
24923
25037
  }
24924
25038
  }
24925
25039
 
25040
+ // src/modes/ctf/integration.ts
25041
+ init_playerInventory();
25042
+
25043
+ // src/modes/ctf/drop.ts
25044
+ function dropFlag(flag, origin, game, context) {
25045
+ if (flag.flagState !== 1 /* CARRIED */) {
25046
+ return;
25047
+ }
25048
+ setFlagState(flag, 2 /* DROPPED */, context);
25049
+ flag.origin = { x: origin.x, y: origin.y, z: origin.z + 24 };
25050
+ flag.owner = null;
25051
+ flag.solid = 1 /* Trigger */;
25052
+ flag.model = flag.flagTeam === "red" ? "players/male/flag1.md2" : "players/male/flag2.md2";
25053
+ const time = context.timeSeconds ?? game.time;
25054
+ flag.nextthink = time + 30;
25055
+ game.centerprintf?.(flag, `The ${flag.flagTeam} flag was dropped!`);
25056
+ flag.think = (selfEntity, ctx) => flagThink(selfEntity, ctx, game);
25057
+ }
25058
+ function flagThink(self, context, game) {
25059
+ const flag = self;
25060
+ if (flag.flagState === 2 /* DROPPED */) {
25061
+ game.sound?.(flag, 0, "ctf/flagret.wav", 1, 1, 0);
25062
+ game.centerprintf?.(flag, `The ${flag.flagTeam} flag returned to base!`);
25063
+ setFlagState(flag, 0 /* AT_BASE */, context);
25064
+ flag.origin = { ...flag.baseOrigin };
25065
+ flag.solid = 1 /* Trigger */;
25066
+ flag.nextthink = -1;
25067
+ }
25068
+ }
25069
+
25070
+ // src/modes/ctf/integration.ts
25071
+ function checkPlayerFlagDrop(player, sys) {
25072
+ if (!player.client) return;
25073
+ const hasRedFlag = hasKey(player.client.inventory, "key_red_flag" /* RedFlag */);
25074
+ const hasBlueFlag = hasKey(player.client.inventory, "key_blue_flag" /* BlueFlag */);
25075
+ if (!hasRedFlag && !hasBlueFlag) return;
25076
+ sys.forEachEntity((ent) => {
25077
+ const flag = ent;
25078
+ if ((flag.classname === "item_flag_team1" || flag.classname === "item_flag_team2") && flag.owner === player) {
25079
+ const game = sys._game;
25080
+ if (game) {
25081
+ dropFlag(flag, player.origin, game, sys);
25082
+ player.client.inventory.keys.delete("key_red_flag" /* RedFlag */);
25083
+ player.client.inventory.keys.delete("key_blue_flag" /* BlueFlag */);
25084
+ }
25085
+ }
25086
+ });
25087
+ }
25088
+
24926
25089
  // src/entities/player.ts
24927
25090
  function P_PlayerThink(ent, sys) {
24928
25091
  if (!ent.client) return;
@@ -25003,6 +25166,9 @@ function player_die(self, inflictor, attacker, damage, point, mod, sys) {
25003
25166
  self.solid = 0 /* Not */;
25004
25167
  self.movetype = 7 /* Toss */;
25005
25168
  self.takedamage = false;
25169
+ if (sys) {
25170
+ checkPlayerFlagDrop(self, sys);
25171
+ }
25006
25172
  if (self.health < -40 && sys) {
25007
25173
  throwGibs(sys, self.origin, damage);
25008
25174
  return;
@@ -25769,6 +25935,11 @@ function createGame(imports, engine, options) {
25769
25935
  serverCommand(cmd) {
25770
25936
  serverCommand(cmd);
25771
25937
  },
25938
+ setLagCompensation(active, client, lagMs) {
25939
+ if (engine.setLagCompensation) {
25940
+ engine.setLagCompensation(active, client, lagMs);
25941
+ }
25942
+ },
25772
25943
  get time() {
25773
25944
  return levelClock.current.timeSeconds;
25774
25945
  },