quake2ts 0.0.496 → 0.0.498

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 (29) hide show
  1. package/package.json +1 -1
  2. package/packages/client/dist/browser/index.global.js +17 -16
  3. package/packages/client/dist/browser/index.global.js.map +1 -1
  4. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  5. package/packages/game/dist/browser/index.global.js +5 -4
  6. package/packages/game/dist/browser/index.global.js.map +1 -1
  7. package/packages/game/dist/cjs/index.cjs +339 -35
  8. package/packages/game/dist/cjs/index.cjs.map +1 -1
  9. package/packages/game/dist/esm/index.js +339 -35
  10. package/packages/game/dist/esm/index.js.map +1 -1
  11. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  12. package/packages/game/dist/types/entities/monsters/rogue/common.d.ts.map +1 -1
  13. package/packages/game/dist/types/entities/monsters/rogue/widow.d.ts.map +1 -1
  14. package/packages/game/dist/types/entities/player.d.ts.map +1 -1
  15. package/packages/game/dist/types/entities/playerStats.d.ts.map +1 -1
  16. package/packages/game/dist/types/entities/projectiles.d.ts +5 -0
  17. package/packages/game/dist/types/entities/projectiles.d.ts.map +1 -1
  18. package/packages/game/dist/types/entities/system.d.ts +1 -0
  19. package/packages/game/dist/types/entities/system.d.ts.map +1 -1
  20. package/packages/game/dist/types/entities/targets.d.ts.map +1 -1
  21. package/packages/game/dist/types/inventory/items.d.ts.map +1 -1
  22. package/packages/game/dist/types/inventory/playerInventory.d.ts +1 -0
  23. package/packages/game/dist/types/inventory/playerInventory.d.ts.map +1 -1
  24. package/packages/game/dist/types/modes/ctf/capture.d.ts.map +1 -1
  25. package/packages/game/dist/types/modes/ctf/grapple.d.ts +13 -0
  26. package/packages/game/dist/types/modes/ctf/grapple.d.ts.map +1 -0
  27. package/packages/game/dist/types/modes/ctf/pickup.d.ts.map +1 -1
  28. package/packages/game/dist/types/modes/ctf/scoreboard.d.ts +34 -0
  29. package/packages/game/dist/types/modes/ctf/scoreboard.d.ts.map +1 -0
@@ -811,36 +811,36 @@ var MAX_ITEMS = 256;
811
811
  var MAX_GENERAL = MAX_CLIENTS * 2;
812
812
  var MAX_SHADOW_LIGHTS = 256;
813
813
  var MAX_WHEEL_ITEMS = 32;
814
- var ConfigStringIndex = ((ConfigStringIndex2) => {
815
- ConfigStringIndex2[ConfigStringIndex2["Name"] = 0] = "Name";
816
- ConfigStringIndex2[ConfigStringIndex2["CdTrack"] = 1] = "CdTrack";
817
- ConfigStringIndex2[ConfigStringIndex2["Sky"] = 2] = "Sky";
818
- ConfigStringIndex2[ConfigStringIndex2["SkyAxis"] = 3] = "SkyAxis";
819
- ConfigStringIndex2[ConfigStringIndex2["SkyRotate"] = 4] = "SkyRotate";
820
- ConfigStringIndex2[ConfigStringIndex2["StatusBar"] = 5] = "StatusBar";
821
- ConfigStringIndex2[ConfigStringIndex2["HealthBarName"] = 55] = "HealthBarName";
822
- ConfigStringIndex2[ConfigStringIndex2["CONFIG_N64_PHYSICS"] = 56] = "CONFIG_N64_PHYSICS";
823
- ConfigStringIndex2[ConfigStringIndex2["CONFIG_CTF_TEAMS"] = 57] = "CONFIG_CTF_TEAMS";
824
- ConfigStringIndex2[ConfigStringIndex2["CONFIG_COOP_RESPAWN_STRING"] = 58] = "CONFIG_COOP_RESPAWN_STRING";
825
- ConfigStringIndex2[ConfigStringIndex2["Story"] = 54] = "Story";
826
- ConfigStringIndex2[ConfigStringIndex2["AirAccel"] = 59] = "AirAccel";
827
- ConfigStringIndex2[ConfigStringIndex2["MaxClients"] = 60] = "MaxClients";
828
- ConfigStringIndex2[ConfigStringIndex2["MapChecksum"] = 61] = "MapChecksum";
829
- ConfigStringIndex2[ConfigStringIndex2["Models"] = 62] = "Models";
830
- ConfigStringIndex2[ConfigStringIndex2["Sounds"] = 62 + MAX_MODELS] = "Sounds";
831
- ConfigStringIndex2[ConfigStringIndex2["Images"] = ConfigStringIndex2.Sounds + MAX_SOUNDS] = "Images";
832
- ConfigStringIndex2[ConfigStringIndex2["Lights"] = ConfigStringIndex2.Images + MAX_IMAGES] = "Lights";
833
- ConfigStringIndex2[ConfigStringIndex2["ShadowLights"] = ConfigStringIndex2.Lights + MAX_LIGHTSTYLES] = "ShadowLights";
834
- ConfigStringIndex2[ConfigStringIndex2["Items"] = ConfigStringIndex2.ShadowLights + MAX_SHADOW_LIGHTS] = "Items";
835
- ConfigStringIndex2[ConfigStringIndex2["PlayerSkins"] = ConfigStringIndex2.Items + MAX_ITEMS] = "PlayerSkins";
836
- ConfigStringIndex2[ConfigStringIndex2["General"] = ConfigStringIndex2.PlayerSkins + MAX_CLIENTS] = "General";
837
- ConfigStringIndex2[ConfigStringIndex2["WheelWeapons"] = ConfigStringIndex2.General + MAX_GENERAL] = "WheelWeapons";
838
- ConfigStringIndex2[ConfigStringIndex2["WheelAmmo"] = ConfigStringIndex2.WheelWeapons + MAX_WHEEL_ITEMS] = "WheelAmmo";
839
- ConfigStringIndex2[ConfigStringIndex2["WheelPowerups"] = ConfigStringIndex2.WheelAmmo + MAX_WHEEL_ITEMS] = "WheelPowerups";
840
- ConfigStringIndex2[ConfigStringIndex2["CdLoopCount"] = ConfigStringIndex2.WheelPowerups + MAX_WHEEL_ITEMS] = "CdLoopCount";
841
- ConfigStringIndex2[ConfigStringIndex2["GameStyle"] = ConfigStringIndex2.CdLoopCount + 1] = "GameStyle";
842
- ConfigStringIndex2[ConfigStringIndex2["MaxConfigStrings"] = ConfigStringIndex2.GameStyle + 1] = "MaxConfigStrings";
843
- return ConfigStringIndex2;
814
+ var ConfigStringIndex = ((ConfigStringIndex22) => {
815
+ ConfigStringIndex22[ConfigStringIndex22["Name"] = 0] = "Name";
816
+ ConfigStringIndex22[ConfigStringIndex22["CdTrack"] = 1] = "CdTrack";
817
+ ConfigStringIndex22[ConfigStringIndex22["Sky"] = 2] = "Sky";
818
+ ConfigStringIndex22[ConfigStringIndex22["SkyAxis"] = 3] = "SkyAxis";
819
+ ConfigStringIndex22[ConfigStringIndex22["SkyRotate"] = 4] = "SkyRotate";
820
+ ConfigStringIndex22[ConfigStringIndex22["StatusBar"] = 5] = "StatusBar";
821
+ ConfigStringIndex22[ConfigStringIndex22["HealthBarName"] = 55] = "HealthBarName";
822
+ ConfigStringIndex22[ConfigStringIndex22["CONFIG_N64_PHYSICS"] = 56] = "CONFIG_N64_PHYSICS";
823
+ ConfigStringIndex22[ConfigStringIndex22["CONFIG_CTF_TEAMS"] = 57] = "CONFIG_CTF_TEAMS";
824
+ ConfigStringIndex22[ConfigStringIndex22["CONFIG_COOP_RESPAWN_STRING"] = 58] = "CONFIG_COOP_RESPAWN_STRING";
825
+ ConfigStringIndex22[ConfigStringIndex22["Story"] = 54] = "Story";
826
+ ConfigStringIndex22[ConfigStringIndex22["AirAccel"] = 59] = "AirAccel";
827
+ ConfigStringIndex22[ConfigStringIndex22["MaxClients"] = 60] = "MaxClients";
828
+ ConfigStringIndex22[ConfigStringIndex22["MapChecksum"] = 61] = "MapChecksum";
829
+ ConfigStringIndex22[ConfigStringIndex22["Models"] = 62] = "Models";
830
+ ConfigStringIndex22[ConfigStringIndex22["Sounds"] = 62 + MAX_MODELS] = "Sounds";
831
+ ConfigStringIndex22[ConfigStringIndex22["Images"] = ConfigStringIndex22.Sounds + MAX_SOUNDS] = "Images";
832
+ ConfigStringIndex22[ConfigStringIndex22["Lights"] = ConfigStringIndex22.Images + MAX_IMAGES] = "Lights";
833
+ ConfigStringIndex22[ConfigStringIndex22["ShadowLights"] = ConfigStringIndex22.Lights + MAX_LIGHTSTYLES] = "ShadowLights";
834
+ ConfigStringIndex22[ConfigStringIndex22["Items"] = ConfigStringIndex22.ShadowLights + MAX_SHADOW_LIGHTS] = "Items";
835
+ ConfigStringIndex22[ConfigStringIndex22["PlayerSkins"] = ConfigStringIndex22.Items + MAX_ITEMS] = "PlayerSkins";
836
+ ConfigStringIndex22[ConfigStringIndex22["General"] = ConfigStringIndex22.PlayerSkins + MAX_CLIENTS] = "General";
837
+ ConfigStringIndex22[ConfigStringIndex22["WheelWeapons"] = ConfigStringIndex22.General + MAX_GENERAL] = "WheelWeapons";
838
+ ConfigStringIndex22[ConfigStringIndex22["WheelAmmo"] = ConfigStringIndex22.WheelWeapons + MAX_WHEEL_ITEMS] = "WheelAmmo";
839
+ ConfigStringIndex22[ConfigStringIndex22["WheelPowerups"] = ConfigStringIndex22.WheelAmmo + MAX_WHEEL_ITEMS] = "WheelPowerups";
840
+ ConfigStringIndex22[ConfigStringIndex22["CdLoopCount"] = ConfigStringIndex22.WheelPowerups + MAX_WHEEL_ITEMS] = "CdLoopCount";
841
+ ConfigStringIndex22[ConfigStringIndex22["GameStyle"] = ConfigStringIndex22.CdLoopCount + 1] = "GameStyle";
842
+ ConfigStringIndex22[ConfigStringIndex22["MaxConfigStrings"] = ConfigStringIndex22.GameStyle + 1] = "MaxConfigStrings";
843
+ return ConfigStringIndex22;
844
844
  })(ConfigStringIndex || {});
845
845
  var MAX_CONFIGSTRINGS = ConfigStringIndex.MaxConfigStrings;
846
846
  var replay_exports = {};
@@ -5327,6 +5327,9 @@ var EntitySystem = class {
5327
5327
  soundIndex(sound) {
5328
5328
  return this.engine.soundIndex?.(sound) || 0;
5329
5329
  }
5330
+ configStringIndex(str) {
5331
+ return this.engine.configStringIndex?.(str) || 0;
5332
+ }
5330
5333
  modelIndex(model) {
5331
5334
  return this.engine.modelIndex?.(model) || 0;
5332
5335
  }
@@ -5339,8 +5342,8 @@ var EntitySystem = class {
5339
5342
  unlink(ent) {
5340
5343
  this.spatialGrid.remove(ent);
5341
5344
  }
5342
- multicast(origin, type, ServerCommand6, ...args) {
5343
- this.imports.multicast(origin, type, ServerCommand6, ...args);
5345
+ multicast(origin, type, ServerCommand7, ...args) {
5346
+ this.imports.multicast(origin, type, ServerCommand7, ...args);
5344
5347
  }
5345
5348
  unicast(ent, reliable, event, ...args) {
5346
5349
  this.imports.unicast(ent, reliable, event, ...args);
@@ -6081,6 +6084,19 @@ function createTrap(context, owner, start, dir, speed) {
6081
6084
  // src/entities/projectiles.ts
6082
6085
  var BFG_LASER_RADIUS = 256;
6083
6086
  var BFG_LASER_RANGE = 2048;
6087
+ function createProjectile(sys, start, dir, speed, mod, damage, radiusDamage) {
6088
+ const proj = sys.spawn();
6089
+ proj.movetype = 8 /* FlyMissile */;
6090
+ proj.solid = 2 /* BoundingBox */;
6091
+ proj.origin = { ...start };
6092
+ proj.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
6093
+ proj.mins = { x: -4, y: -4, z: -4 };
6094
+ proj.maxs = { x: 4, y: 4, z: 4 };
6095
+ proj.angles = vectorToAngles(dir);
6096
+ proj.takedamage = false;
6097
+ sys.finalizeSpawn(proj);
6098
+ return proj;
6099
+ }
6084
6100
  function createRocket(sys, owner, start, dir, damage, radiusDamage, speed, flashtype = 0) {
6085
6101
  const rocket = sys.spawn();
6086
6102
  rocket.classname = "rocket";
@@ -7193,8 +7209,10 @@ var SPEAKER_SPAWNFLAGS = {
7193
7209
  LoopedOff: 1 << 1,
7194
7210
  Reliable: 1 << 2
7195
7211
  };
7196
- function useChangeLevel(self) {
7212
+ function useChangeLevel(self, other, activator, context) {
7197
7213
  if (self.map) {
7214
+ context.entities.imports.serverCommand(`changelevel ${self.map}
7215
+ `);
7198
7216
  }
7199
7217
  }
7200
7218
  function targetSpeakerUse(self, other, activator, context) {
@@ -7654,13 +7672,14 @@ function registerTargetSpawns(registry) {
7654
7672
  entities.useTargets(self, self.activator ?? null);
7655
7673
  };
7656
7674
  });
7657
- registry.register("target_changelevel", (entity, { keyValues, free }) => {
7675
+ registry.register("target_changelevel", (entity, context) => {
7676
+ const { keyValues, free } = context;
7658
7677
  if (!keyValues.map) {
7659
7678
  free(entity);
7660
7679
  return;
7661
7680
  }
7662
7681
  entity.map = keyValues.map;
7663
- entity.use = useChangeLevel;
7682
+ entity.use = (self, other, activator) => useChangeLevel(self, other, activator ?? null, context);
7664
7683
  entity.solid = 1 /* Trigger */;
7665
7684
  });
7666
7685
  registry.register("target_spawner", (entity, context) => {
@@ -10120,6 +10139,95 @@ function Trap_Think(player, sys) {
10120
10139
  );
10121
10140
  }
10122
10141
 
10142
+ // src/modes/ctf/grapple.ts
10143
+ var GRAPPLE_SPEED = 1200;
10144
+ var GRAPPLE_PULL_SPEED = 800;
10145
+ var GRAPPLE_DAMAGE = 20;
10146
+ function Grapple_Think(player, sys) {
10147
+ if (player.client?.inventory.currentWeapon !== WeaponId.Grapple) {
10148
+ ResetGrapple(player, sys);
10149
+ }
10150
+ Weapon_Generic(
10151
+ player,
10152
+ 0,
10153
+ 10,
10154
+ // ready
10155
+ 11,
10156
+ 20,
10157
+ // fire
10158
+ [],
10159
+ // pause frames
10160
+ [11],
10161
+ // fire frames
10162
+ (ent) => fire_grapple(ent, sys),
10163
+ sys
10164
+ );
10165
+ if (player.client && !(player.client.buttons & 1)) {
10166
+ ResetGrapple(player, sys);
10167
+ }
10168
+ if (player.grapple && player.grapple.grappleState === "attached") {
10169
+ Grapple_Pull(player, player.grapple, sys);
10170
+ }
10171
+ }
10172
+ function fire_grapple(player, sys) {
10173
+ if (player.grapple) return;
10174
+ const angles = player.client.v_angle || player.angles;
10175
+ const vectors = angleVectors(angles);
10176
+ const forward = vectors.forward;
10177
+ const right = vectors.right;
10178
+ const up = vectors.up;
10179
+ const game = sys.game;
10180
+ const start = P_ProjectSource(game, player, { x: 8, y: 8, z: 8 }, forward, right, up);
10181
+ const dir = { ...forward };
10182
+ const grapple = createProjectile(sys, start, dir, GRAPPLE_SPEED, 57 /* GRAPPLE */, 0);
10183
+ grapple.classname = "grapple";
10184
+ grapple.owner = player;
10185
+ grapple.movetype = 8 /* FlyMissile */;
10186
+ grapple.solid = 2 /* BoundingBox */;
10187
+ grapple.mins = { x: -4, y: -4, z: -4 };
10188
+ grapple.maxs = { x: 4, y: 4, z: 4 };
10189
+ grapple.model = "models/weapons/grapple/hook/tris.md2";
10190
+ grapple.grappleState = "fly";
10191
+ grapple.touch = (self, other, plane, surface) => {
10192
+ if (!other) return;
10193
+ Grapple_Touch(self, other, plane, surface, sys);
10194
+ };
10195
+ player.grapple = grapple;
10196
+ sys.sound(player, 0, "weapons/grapple/throw.wav", 1, 1, 0);
10197
+ }
10198
+ function Grapple_Touch(self, other, plane, surface, sys) {
10199
+ if (other === self.owner) return;
10200
+ if (self.grappleState === "attached") return;
10201
+ if (other.takedamage) {
10202
+ T_Damage(other, self, self.owner, self.velocity, self.origin, ZERO_VEC3, GRAPPLE_DAMAGE, 0, 0, 57 /* GRAPPLE */, sys.timeSeconds, sys.multicast.bind(sys));
10203
+ sys.free(self);
10204
+ if (self.owner) self.owner.grapple = void 0;
10205
+ return;
10206
+ }
10207
+ if (other.solid === 3 /* Bsp */ || other.solid === 2 /* BoundingBox */) {
10208
+ self.velocity = { x: 0, y: 0, z: 0 };
10209
+ self.movetype = 0 /* None */;
10210
+ self.grappleState = "attached";
10211
+ sys.sound(self, 0, "weapons/grapple/hit.wav", 1, 1, 0);
10212
+ if (plane) {
10213
+ }
10214
+ }
10215
+ }
10216
+ function Grapple_Pull(player, grapple, sys) {
10217
+ const dir = subtractVec3(grapple.origin, player.origin);
10218
+ const dist = lengthVec3(dir);
10219
+ if (dist < 32) return;
10220
+ const normalizedDir = normalizeVec3(dir);
10221
+ const pull = scaleVec3(normalizedDir, GRAPPLE_PULL_SPEED);
10222
+ player.velocity = pull;
10223
+ }
10224
+ function ResetGrapple(player, sys) {
10225
+ if (player.grapple) {
10226
+ sys.free(player.grapple);
10227
+ player.grapple = void 0;
10228
+ }
10229
+ }
10230
+
10123
10231
  // src/inventory/items.ts
10124
10232
  var WEAPON_ITEMS = {
10125
10233
  "weapon_blaster": {
@@ -10317,6 +10425,18 @@ var WEAPON_ITEMS = {
10317
10425
  pickupAmmo: 5,
10318
10426
  fireRate: 1,
10319
10427
  think: Trap_Think
10428
+ },
10429
+ "weapon_grapple": {
10430
+ type: "weapon",
10431
+ id: "weapon_grapple",
10432
+ name: "Grapple",
10433
+ weaponId: WeaponId.Grapple,
10434
+ ammoType: null,
10435
+ // Grapple uses no ammo in standard Q2 CTF? Or maybe just internal timer.
10436
+ initialAmmo: 0,
10437
+ pickupAmmo: 0,
10438
+ fireRate: 0.5,
10439
+ think: Grapple_Think
10320
10440
  }
10321
10441
  };
10322
10442
  var HEALTH_ITEMS = {
@@ -10718,6 +10838,34 @@ function setFlagState(flag, newState, context) {
10718
10838
  flag.flagState = newState;
10719
10839
  }
10720
10840
 
10841
+ // src/modes/ctf/scoreboard.ts
10842
+ var teamScores = {
10843
+ [1 /* RED */]: 0,
10844
+ [2 /* BLUE */]: 0
10845
+ };
10846
+ function addTeamScore(team, points) {
10847
+ if (team === 1 /* RED */ || team === 2 /* BLUE */) {
10848
+ teamScores[team] += points;
10849
+ }
10850
+ }
10851
+ function updateCtfScoreboard(ent, sys) {
10852
+ if (!ent.client || !ent.client.stats) return;
10853
+ const stats = ent.client.stats;
10854
+ stats[PlayerStat.STAT_CTF_TEAM1_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_r.pcx") : 0;
10855
+ stats[PlayerStat.STAT_CTF_TEAM1_CAPS] = teamScores[1 /* RED */];
10856
+ stats[PlayerStat.STAT_CTF_TEAM2_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_b.pcx") : 0;
10857
+ stats[PlayerStat.STAT_CTF_TEAM2_CAPS] = teamScores[2 /* BLUE */];
10858
+ const clientTeam = ent.client.ctfTeam;
10859
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM1_PIC] = 0;
10860
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM2_PIC] = 0;
10861
+ if (clientTeam === 1 /* RED */) {
10862
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM1_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_r.pcx") : 0;
10863
+ } else if (clientTeam === 2 /* BLUE */) {
10864
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM2_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_b.pcx") : 0;
10865
+ }
10866
+ stats[PlayerStat.STAT_CTF_TEAMINFO] = 1;
10867
+ }
10868
+
10721
10869
  // src/modes/ctf/capture.ts
10722
10870
  function checkCapture(flag, player, game, context) {
10723
10871
  if (!player.client) return false;
@@ -10738,11 +10886,17 @@ function captureFlag(ownFlag, player, game, context) {
10738
10886
  if (!player.client) return false;
10739
10887
  const playerTeam = player.client.team || "red";
10740
10888
  const enemyTeam = playerTeam === "red" ? "blue" : "red";
10889
+ const ctfStats = player.client.ctfStats;
10890
+ if (ctfStats) {
10891
+ ctfStats.captures++;
10892
+ }
10741
10893
  if (player.client.score !== void 0) {
10742
10894
  player.client.score += 5;
10743
10895
  } else {
10744
10896
  player.client.score = 5;
10745
10897
  }
10898
+ const teamEnum = playerTeam === "red" ? 1 /* RED */ : 2 /* BLUE */;
10899
+ addTeamScore(teamEnum, 1);
10746
10900
  game.sound?.(player, 0, "ctf/flagcap.wav", 1, 1, 0);
10747
10901
  game.centerprintf?.(player, "You captured the flag!");
10748
10902
  const enemyFlagKey = playerTeam === "red" ? "key_blue_flag" /* BlueFlag */ : "key_red_flag" /* RedFlag */;
@@ -12341,14 +12495,81 @@ var generic_stand_frames = Array.from({ length: 1 }, () => ({
12341
12495
  ai: generic_ai_stand,
12342
12496
  dist: 0
12343
12497
  }));
12498
+ var generic_stand_move = {
12499
+ firstframe: 0,
12500
+ lastframe: 0,
12501
+ frames: generic_stand_frames,
12502
+ endfunc: (self) => {
12503
+ self.monsterinfo.current_move = generic_stand_move;
12504
+ }
12505
+ };
12344
12506
  var generic_walk_frames = Array.from({ length: 1 }, () => ({
12345
12507
  ai: generic_ai_walk,
12346
12508
  dist: 5
12347
12509
  }));
12510
+ var generic_walk_move = {
12511
+ firstframe: 0,
12512
+ lastframe: 0,
12513
+ frames: generic_walk_frames,
12514
+ endfunc: (self) => {
12515
+ self.monsterinfo.current_move = generic_walk_move;
12516
+ }
12517
+ };
12348
12518
  var generic_run_frames = Array.from({ length: 1 }, () => ({
12349
12519
  ai: generic_ai_run,
12350
12520
  dist: 10
12351
12521
  }));
12522
+ var generic_run_move = {
12523
+ firstframe: 0,
12524
+ lastframe: 0,
12525
+ frames: generic_run_frames,
12526
+ endfunc: (self) => {
12527
+ self.monsterinfo.current_move = generic_run_move;
12528
+ }
12529
+ };
12530
+ function createMonsterSpawn(config) {
12531
+ return function(self, context) {
12532
+ self.model = config.model;
12533
+ self.mins = config.mins || { x: -16, y: -16, z: -24 };
12534
+ self.maxs = config.maxs || { x: 16, y: 16, z: 32 };
12535
+ self.movetype = config.fly ? 5 /* Step */ : 5 /* Step */;
12536
+ self.solid = 2 /* BoundingBox */;
12537
+ self.health = config.health * context.health_multiplier;
12538
+ self.max_health = self.health;
12539
+ self.mass = config.mass;
12540
+ self.takedamage = true;
12541
+ self.pain = (self2, other, kick, damage) => {
12542
+ };
12543
+ self.die = (self2, inflictor, attacker, damage, point, mod = 0 /* UNKNOWN */) => {
12544
+ self2.deadflag = 2 /* Dead */;
12545
+ self2.solid = 0 /* Not */;
12546
+ if (self2.health < -40) {
12547
+ throwGibs(context.entities, self2.origin, damage, GIB_ORGANIC, mod);
12548
+ context.entities.free(self2);
12549
+ return;
12550
+ }
12551
+ self2.think = (self3) => {
12552
+ context.entities.free(self3);
12553
+ };
12554
+ self2.nextthink = context.entities.timeSeconds + 5;
12555
+ };
12556
+ self.monsterinfo.stand = (self2, context2) => {
12557
+ self2.monsterinfo.current_move = generic_stand_move;
12558
+ };
12559
+ self.monsterinfo.walk = (self2, context2) => {
12560
+ self2.monsterinfo.current_move = generic_walk_move;
12561
+ };
12562
+ self.monsterinfo.run = (self2, context2) => {
12563
+ self2.monsterinfo.current_move = generic_run_move;
12564
+ };
12565
+ self.monsterinfo.attack = (self2, context2) => {
12566
+ self2.monsterinfo.current_move = generic_run_move;
12567
+ };
12568
+ self.think = monster_think;
12569
+ self.monsterinfo.stand(self, context.entities);
12570
+ self.nextthink = self.timestamp + MONSTER_TICK2;
12571
+ };
12572
+ }
12352
12573
  function M_SetAnimation(self, move, context) {
12353
12574
  self.monsterinfo.current_move = move;
12354
12575
  }
@@ -24073,6 +24294,39 @@ function registerShamblerSpawns(registry) {
24073
24294
  registry.register("monster_shambler", SP_monster_shambler);
24074
24295
  }
24075
24296
 
24297
+ // src/entities/monsters/rogue/common.ts
24298
+ var MAX_REINFORCEMENTS2 = 5;
24299
+ var INVERSE_LOG_SLOTS = Math.pow(2, MAX_REINFORCEMENTS2);
24300
+ function M_PickValidReinforcements(self, space, output) {
24301
+ output.length = 0;
24302
+ if (!self.monsterinfo.reinforcements) return;
24303
+ for (let i = 0; i < self.monsterinfo.reinforcements.length; i++) {
24304
+ if (self.monsterinfo.reinforcements[i].strength <= space) {
24305
+ output.push(i);
24306
+ }
24307
+ }
24308
+ }
24309
+ function M_PickReinforcements(self, rng, countRef, max_slots = 0) {
24310
+ const output = [];
24311
+ const chosen = new Array(MAX_REINFORCEMENTS2).fill(255);
24312
+ let num_chosen = 0;
24313
+ let num_slots = Math.max(1, Math.floor(Math.log2(rng.frandomRange(0, INVERSE_LOG_SLOTS))));
24314
+ let remaining = (self.monsterinfo.monster_slots || 0) - (self.monsterinfo.monster_used || 0);
24315
+ for (num_chosen = 0; num_chosen < num_slots; num_chosen++) {
24316
+ if (max_slots && num_chosen === max_slots || !remaining) {
24317
+ break;
24318
+ }
24319
+ M_PickValidReinforcements(self, remaining, output);
24320
+ if (output.length === 0) {
24321
+ break;
24322
+ }
24323
+ const randIndex = rng.irandomRange(0, output.length);
24324
+ chosen[num_chosen] = output[randIndex];
24325
+ remaining -= self.monsterinfo.reinforcements[chosen[num_chosen]].strength;
24326
+ }
24327
+ return { chosen, count: num_chosen };
24328
+ }
24329
+
24076
24330
  // src/entities/monsters/rogue/widow.ts
24077
24331
  var MODEL_SCALE3 = 1;
24078
24332
  var RANGE_MELEE3 = 100;
@@ -24184,6 +24438,43 @@ function widow_kick(self, context) {
24184
24438
  }
24185
24439
  function widow_spawn_check(self, context) {
24186
24440
  if (M_SlotsLeft(self) > 0) {
24441
+ const result = M_PickReinforcements(self, context.rng, 1);
24442
+ self.monsterinfo.chosen_reinforcements = result.chosen;
24443
+ if (result.count > 0) {
24444
+ const reinforcement = self.monsterinfo.reinforcements[self.monsterinfo.chosen_reinforcements[0]];
24445
+ WidowSpawn(self, context);
24446
+ }
24447
+ }
24448
+ }
24449
+ function WidowSpawn(self, context) {
24450
+ const { forward, right } = angleVectors(self.angles);
24451
+ const offset = { x: 50, y: 0, z: 0 };
24452
+ const start = M_ProjectFlashSource(self, offset, forward, right);
24453
+ if (!self.monsterinfo.chosen_reinforcements) {
24454
+ const result = M_PickReinforcements(self, context.rng, 1);
24455
+ self.monsterinfo.chosen_reinforcements = result.chosen;
24456
+ }
24457
+ if (self.monsterinfo.chosen_reinforcements && self.monsterinfo.chosen_reinforcements[0] !== 255) {
24458
+ const rIndex = self.monsterinfo.chosen_reinforcements[0];
24459
+ const reinforcement = self.monsterinfo.reinforcements[rIndex];
24460
+ const ent = context.spawn();
24461
+ ent.origin = { ...start };
24462
+ ent.angles = { ...self.angles };
24463
+ if (reinforcement.classname === "monster_stalker") {
24464
+ SP_monster_stalker(ent, { entities: context });
24465
+ } else if (reinforcement.classname === "monster_flyer") {
24466
+ SP_monster_flyer(ent, { entities: context });
24467
+ } else {
24468
+ createMonsterSpawn({
24469
+ model: "models/monsters/stalker/tris.md2",
24470
+ health: 100,
24471
+ mass: 100
24472
+ })(ent, { entities: context });
24473
+ }
24474
+ if (ent.inUse) {
24475
+ if (!self.monsterinfo.monster_used) self.monsterinfo.monster_used = 0;
24476
+ self.monsterinfo.monster_used += reinforcement.strength;
24477
+ }
24187
24478
  }
24188
24479
  }
24189
24480
  var widow_frames_stand = Array(20).fill({ ai: widow_ai_stand, dist: 0 });
@@ -26372,6 +26663,9 @@ function player_think(self, sys) {
26372
26663
  }
26373
26664
  }
26374
26665
  P_PlayerThink(self, sys);
26666
+ if (sys.deathmatch && (sys.configStringIndex ? sys.configStringIndex("pics/ctf_r.pcx") > 0 : true)) {
26667
+ updateCtfScoreboard(self, sys);
26668
+ }
26375
26669
  self.nextthink = sys.timeSeconds + 0.1;
26376
26670
  sys.scheduleThink(self, self.nextthink);
26377
26671
  }
@@ -26439,6 +26733,16 @@ function populatePlayerStats(player, timeSeconds) {
26439
26733
  const remainingSeconds = Math.ceil((bestTime - nowMs) / 1e3);
26440
26734
  statArray[PlayerStat.STAT_TIMER] = remainingSeconds;
26441
26735
  }
26736
+ if (player.client.score !== void 0) {
26737
+ statArray[PlayerStat.STAT_FRAGS] = player.client.score;
26738
+ }
26739
+ if (player.client.stats) {
26740
+ for (let i = 0; i < player.client.stats.length; i++) {
26741
+ if (player.client.stats[i] !== 0) {
26742
+ statArray[i] = player.client.stats[i];
26743
+ }
26744
+ }
26745
+ }
26442
26746
  return statArray;
26443
26747
  }
26444
26748