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
@@ -611,36 +611,36 @@ var MAX_ITEMS = 256;
611
611
  var MAX_GENERAL = MAX_CLIENTS * 2;
612
612
  var MAX_SHADOW_LIGHTS = 256;
613
613
  var MAX_WHEEL_ITEMS = 32;
614
- var ConfigStringIndex = ((ConfigStringIndex2) => {
615
- ConfigStringIndex2[ConfigStringIndex2["Name"] = 0] = "Name";
616
- ConfigStringIndex2[ConfigStringIndex2["CdTrack"] = 1] = "CdTrack";
617
- ConfigStringIndex2[ConfigStringIndex2["Sky"] = 2] = "Sky";
618
- ConfigStringIndex2[ConfigStringIndex2["SkyAxis"] = 3] = "SkyAxis";
619
- ConfigStringIndex2[ConfigStringIndex2["SkyRotate"] = 4] = "SkyRotate";
620
- ConfigStringIndex2[ConfigStringIndex2["StatusBar"] = 5] = "StatusBar";
621
- ConfigStringIndex2[ConfigStringIndex2["HealthBarName"] = 55] = "HealthBarName";
622
- ConfigStringIndex2[ConfigStringIndex2["CONFIG_N64_PHYSICS"] = 56] = "CONFIG_N64_PHYSICS";
623
- ConfigStringIndex2[ConfigStringIndex2["CONFIG_CTF_TEAMS"] = 57] = "CONFIG_CTF_TEAMS";
624
- ConfigStringIndex2[ConfigStringIndex2["CONFIG_COOP_RESPAWN_STRING"] = 58] = "CONFIG_COOP_RESPAWN_STRING";
625
- ConfigStringIndex2[ConfigStringIndex2["Story"] = 54] = "Story";
626
- ConfigStringIndex2[ConfigStringIndex2["AirAccel"] = 59] = "AirAccel";
627
- ConfigStringIndex2[ConfigStringIndex2["MaxClients"] = 60] = "MaxClients";
628
- ConfigStringIndex2[ConfigStringIndex2["MapChecksum"] = 61] = "MapChecksum";
629
- ConfigStringIndex2[ConfigStringIndex2["Models"] = 62] = "Models";
630
- ConfigStringIndex2[ConfigStringIndex2["Sounds"] = 62 + MAX_MODELS] = "Sounds";
631
- ConfigStringIndex2[ConfigStringIndex2["Images"] = ConfigStringIndex2.Sounds + MAX_SOUNDS] = "Images";
632
- ConfigStringIndex2[ConfigStringIndex2["Lights"] = ConfigStringIndex2.Images + MAX_IMAGES] = "Lights";
633
- ConfigStringIndex2[ConfigStringIndex2["ShadowLights"] = ConfigStringIndex2.Lights + MAX_LIGHTSTYLES] = "ShadowLights";
634
- ConfigStringIndex2[ConfigStringIndex2["Items"] = ConfigStringIndex2.ShadowLights + MAX_SHADOW_LIGHTS] = "Items";
635
- ConfigStringIndex2[ConfigStringIndex2["PlayerSkins"] = ConfigStringIndex2.Items + MAX_ITEMS] = "PlayerSkins";
636
- ConfigStringIndex2[ConfigStringIndex2["General"] = ConfigStringIndex2.PlayerSkins + MAX_CLIENTS] = "General";
637
- ConfigStringIndex2[ConfigStringIndex2["WheelWeapons"] = ConfigStringIndex2.General + MAX_GENERAL] = "WheelWeapons";
638
- ConfigStringIndex2[ConfigStringIndex2["WheelAmmo"] = ConfigStringIndex2.WheelWeapons + MAX_WHEEL_ITEMS] = "WheelAmmo";
639
- ConfigStringIndex2[ConfigStringIndex2["WheelPowerups"] = ConfigStringIndex2.WheelAmmo + MAX_WHEEL_ITEMS] = "WheelPowerups";
640
- ConfigStringIndex2[ConfigStringIndex2["CdLoopCount"] = ConfigStringIndex2.WheelPowerups + MAX_WHEEL_ITEMS] = "CdLoopCount";
641
- ConfigStringIndex2[ConfigStringIndex2["GameStyle"] = ConfigStringIndex2.CdLoopCount + 1] = "GameStyle";
642
- ConfigStringIndex2[ConfigStringIndex2["MaxConfigStrings"] = ConfigStringIndex2.GameStyle + 1] = "MaxConfigStrings";
643
- return ConfigStringIndex2;
614
+ var ConfigStringIndex = ((ConfigStringIndex22) => {
615
+ ConfigStringIndex22[ConfigStringIndex22["Name"] = 0] = "Name";
616
+ ConfigStringIndex22[ConfigStringIndex22["CdTrack"] = 1] = "CdTrack";
617
+ ConfigStringIndex22[ConfigStringIndex22["Sky"] = 2] = "Sky";
618
+ ConfigStringIndex22[ConfigStringIndex22["SkyAxis"] = 3] = "SkyAxis";
619
+ ConfigStringIndex22[ConfigStringIndex22["SkyRotate"] = 4] = "SkyRotate";
620
+ ConfigStringIndex22[ConfigStringIndex22["StatusBar"] = 5] = "StatusBar";
621
+ ConfigStringIndex22[ConfigStringIndex22["HealthBarName"] = 55] = "HealthBarName";
622
+ ConfigStringIndex22[ConfigStringIndex22["CONFIG_N64_PHYSICS"] = 56] = "CONFIG_N64_PHYSICS";
623
+ ConfigStringIndex22[ConfigStringIndex22["CONFIG_CTF_TEAMS"] = 57] = "CONFIG_CTF_TEAMS";
624
+ ConfigStringIndex22[ConfigStringIndex22["CONFIG_COOP_RESPAWN_STRING"] = 58] = "CONFIG_COOP_RESPAWN_STRING";
625
+ ConfigStringIndex22[ConfigStringIndex22["Story"] = 54] = "Story";
626
+ ConfigStringIndex22[ConfigStringIndex22["AirAccel"] = 59] = "AirAccel";
627
+ ConfigStringIndex22[ConfigStringIndex22["MaxClients"] = 60] = "MaxClients";
628
+ ConfigStringIndex22[ConfigStringIndex22["MapChecksum"] = 61] = "MapChecksum";
629
+ ConfigStringIndex22[ConfigStringIndex22["Models"] = 62] = "Models";
630
+ ConfigStringIndex22[ConfigStringIndex22["Sounds"] = 62 + MAX_MODELS] = "Sounds";
631
+ ConfigStringIndex22[ConfigStringIndex22["Images"] = ConfigStringIndex22.Sounds + MAX_SOUNDS] = "Images";
632
+ ConfigStringIndex22[ConfigStringIndex22["Lights"] = ConfigStringIndex22.Images + MAX_IMAGES] = "Lights";
633
+ ConfigStringIndex22[ConfigStringIndex22["ShadowLights"] = ConfigStringIndex22.Lights + MAX_LIGHTSTYLES] = "ShadowLights";
634
+ ConfigStringIndex22[ConfigStringIndex22["Items"] = ConfigStringIndex22.ShadowLights + MAX_SHADOW_LIGHTS] = "Items";
635
+ ConfigStringIndex22[ConfigStringIndex22["PlayerSkins"] = ConfigStringIndex22.Items + MAX_ITEMS] = "PlayerSkins";
636
+ ConfigStringIndex22[ConfigStringIndex22["General"] = ConfigStringIndex22.PlayerSkins + MAX_CLIENTS] = "General";
637
+ ConfigStringIndex22[ConfigStringIndex22["WheelWeapons"] = ConfigStringIndex22.General + MAX_GENERAL] = "WheelWeapons";
638
+ ConfigStringIndex22[ConfigStringIndex22["WheelAmmo"] = ConfigStringIndex22.WheelWeapons + MAX_WHEEL_ITEMS] = "WheelAmmo";
639
+ ConfigStringIndex22[ConfigStringIndex22["WheelPowerups"] = ConfigStringIndex22.WheelAmmo + MAX_WHEEL_ITEMS] = "WheelPowerups";
640
+ ConfigStringIndex22[ConfigStringIndex22["CdLoopCount"] = ConfigStringIndex22.WheelPowerups + MAX_WHEEL_ITEMS] = "CdLoopCount";
641
+ ConfigStringIndex22[ConfigStringIndex22["GameStyle"] = ConfigStringIndex22.CdLoopCount + 1] = "GameStyle";
642
+ ConfigStringIndex22[ConfigStringIndex22["MaxConfigStrings"] = ConfigStringIndex22.GameStyle + 1] = "MaxConfigStrings";
643
+ return ConfigStringIndex22;
644
644
  })(ConfigStringIndex || {});
645
645
  var MAX_CONFIGSTRINGS = ConfigStringIndex.MaxConfigStrings;
646
646
  var replay_exports = {};
@@ -5127,6 +5127,9 @@ var EntitySystem = class {
5127
5127
  soundIndex(sound) {
5128
5128
  return this.engine.soundIndex?.(sound) || 0;
5129
5129
  }
5130
+ configStringIndex(str) {
5131
+ return this.engine.configStringIndex?.(str) || 0;
5132
+ }
5130
5133
  modelIndex(model) {
5131
5134
  return this.engine.modelIndex?.(model) || 0;
5132
5135
  }
@@ -5139,8 +5142,8 @@ var EntitySystem = class {
5139
5142
  unlink(ent) {
5140
5143
  this.spatialGrid.remove(ent);
5141
5144
  }
5142
- multicast(origin, type, ServerCommand6, ...args) {
5143
- this.imports.multicast(origin, type, ServerCommand6, ...args);
5145
+ multicast(origin, type, ServerCommand7, ...args) {
5146
+ this.imports.multicast(origin, type, ServerCommand7, ...args);
5144
5147
  }
5145
5148
  unicast(ent, reliable, event, ...args) {
5146
5149
  this.imports.unicast(ent, reliable, event, ...args);
@@ -5881,6 +5884,19 @@ function createTrap(context, owner, start, dir, speed) {
5881
5884
  // src/entities/projectiles.ts
5882
5885
  var BFG_LASER_RADIUS = 256;
5883
5886
  var BFG_LASER_RANGE = 2048;
5887
+ function createProjectile(sys, start, dir, speed, mod, damage, radiusDamage) {
5888
+ const proj = sys.spawn();
5889
+ proj.movetype = 8 /* FlyMissile */;
5890
+ proj.solid = 2 /* BoundingBox */;
5891
+ proj.origin = { ...start };
5892
+ proj.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
5893
+ proj.mins = { x: -4, y: -4, z: -4 };
5894
+ proj.maxs = { x: 4, y: 4, z: 4 };
5895
+ proj.angles = vectorToAngles(dir);
5896
+ proj.takedamage = false;
5897
+ sys.finalizeSpawn(proj);
5898
+ return proj;
5899
+ }
5884
5900
  function createRocket(sys, owner, start, dir, damage, radiusDamage, speed, flashtype = 0) {
5885
5901
  const rocket = sys.spawn();
5886
5902
  rocket.classname = "rocket";
@@ -6993,8 +7009,10 @@ var SPEAKER_SPAWNFLAGS = {
6993
7009
  LoopedOff: 1 << 1,
6994
7010
  Reliable: 1 << 2
6995
7011
  };
6996
- function useChangeLevel(self) {
7012
+ function useChangeLevel(self, other, activator, context) {
6997
7013
  if (self.map) {
7014
+ context.entities.imports.serverCommand(`changelevel ${self.map}
7015
+ `);
6998
7016
  }
6999
7017
  }
7000
7018
  function targetSpeakerUse(self, other, activator, context) {
@@ -7454,13 +7472,14 @@ function registerTargetSpawns(registry) {
7454
7472
  entities.useTargets(self, self.activator ?? null);
7455
7473
  };
7456
7474
  });
7457
- registry.register("target_changelevel", (entity, { keyValues, free }) => {
7475
+ registry.register("target_changelevel", (entity, context) => {
7476
+ const { keyValues, free } = context;
7458
7477
  if (!keyValues.map) {
7459
7478
  free(entity);
7460
7479
  return;
7461
7480
  }
7462
7481
  entity.map = keyValues.map;
7463
- entity.use = useChangeLevel;
7482
+ entity.use = (self, other, activator) => useChangeLevel(self, other, activator ?? null, context);
7464
7483
  entity.solid = 1 /* Trigger */;
7465
7484
  });
7466
7485
  registry.register("target_spawner", (entity, context) => {
@@ -9920,6 +9939,95 @@ function Trap_Think(player, sys) {
9920
9939
  );
9921
9940
  }
9922
9941
 
9942
+ // src/modes/ctf/grapple.ts
9943
+ var GRAPPLE_SPEED = 1200;
9944
+ var GRAPPLE_PULL_SPEED = 800;
9945
+ var GRAPPLE_DAMAGE = 20;
9946
+ function Grapple_Think(player, sys) {
9947
+ if (player.client?.inventory.currentWeapon !== WeaponId.Grapple) {
9948
+ ResetGrapple(player, sys);
9949
+ }
9950
+ Weapon_Generic(
9951
+ player,
9952
+ 0,
9953
+ 10,
9954
+ // ready
9955
+ 11,
9956
+ 20,
9957
+ // fire
9958
+ [],
9959
+ // pause frames
9960
+ [11],
9961
+ // fire frames
9962
+ (ent) => fire_grapple(ent, sys),
9963
+ sys
9964
+ );
9965
+ if (player.client && !(player.client.buttons & 1)) {
9966
+ ResetGrapple(player, sys);
9967
+ }
9968
+ if (player.grapple && player.grapple.grappleState === "attached") {
9969
+ Grapple_Pull(player, player.grapple, sys);
9970
+ }
9971
+ }
9972
+ function fire_grapple(player, sys) {
9973
+ if (player.grapple) return;
9974
+ const angles = player.client.v_angle || player.angles;
9975
+ const vectors = angleVectors(angles);
9976
+ const forward = vectors.forward;
9977
+ const right = vectors.right;
9978
+ const up = vectors.up;
9979
+ const game = sys.game;
9980
+ const start = P_ProjectSource(game, player, { x: 8, y: 8, z: 8 }, forward, right, up);
9981
+ const dir = { ...forward };
9982
+ const grapple = createProjectile(sys, start, dir, GRAPPLE_SPEED, 57 /* GRAPPLE */, 0);
9983
+ grapple.classname = "grapple";
9984
+ grapple.owner = player;
9985
+ grapple.movetype = 8 /* FlyMissile */;
9986
+ grapple.solid = 2 /* BoundingBox */;
9987
+ grapple.mins = { x: -4, y: -4, z: -4 };
9988
+ grapple.maxs = { x: 4, y: 4, z: 4 };
9989
+ grapple.model = "models/weapons/grapple/hook/tris.md2";
9990
+ grapple.grappleState = "fly";
9991
+ grapple.touch = (self, other, plane, surface) => {
9992
+ if (!other) return;
9993
+ Grapple_Touch(self, other, plane, surface, sys);
9994
+ };
9995
+ player.grapple = grapple;
9996
+ sys.sound(player, 0, "weapons/grapple/throw.wav", 1, 1, 0);
9997
+ }
9998
+ function Grapple_Touch(self, other, plane, surface, sys) {
9999
+ if (other === self.owner) return;
10000
+ if (self.grappleState === "attached") return;
10001
+ if (other.takedamage) {
10002
+ T_Damage(other, self, self.owner, self.velocity, self.origin, ZERO_VEC3, GRAPPLE_DAMAGE, 0, 0, 57 /* GRAPPLE */, sys.timeSeconds, sys.multicast.bind(sys));
10003
+ sys.free(self);
10004
+ if (self.owner) self.owner.grapple = void 0;
10005
+ return;
10006
+ }
10007
+ if (other.solid === 3 /* Bsp */ || other.solid === 2 /* BoundingBox */) {
10008
+ self.velocity = { x: 0, y: 0, z: 0 };
10009
+ self.movetype = 0 /* None */;
10010
+ self.grappleState = "attached";
10011
+ sys.sound(self, 0, "weapons/grapple/hit.wav", 1, 1, 0);
10012
+ if (plane) {
10013
+ }
10014
+ }
10015
+ }
10016
+ function Grapple_Pull(player, grapple, sys) {
10017
+ const dir = subtractVec3(grapple.origin, player.origin);
10018
+ const dist = lengthVec3(dir);
10019
+ if (dist < 32) return;
10020
+ const normalizedDir = normalizeVec3(dir);
10021
+ const pull = scaleVec3(normalizedDir, GRAPPLE_PULL_SPEED);
10022
+ player.velocity = pull;
10023
+ }
10024
+ function ResetGrapple(player, sys) {
10025
+ if (player.grapple) {
10026
+ sys.free(player.grapple);
10027
+ player.grapple = void 0;
10028
+ }
10029
+ }
10030
+
9923
10031
  // src/inventory/items.ts
9924
10032
  var WEAPON_ITEMS = {
9925
10033
  "weapon_blaster": {
@@ -10117,6 +10225,18 @@ var WEAPON_ITEMS = {
10117
10225
  pickupAmmo: 5,
10118
10226
  fireRate: 1,
10119
10227
  think: Trap_Think
10228
+ },
10229
+ "weapon_grapple": {
10230
+ type: "weapon",
10231
+ id: "weapon_grapple",
10232
+ name: "Grapple",
10233
+ weaponId: WeaponId.Grapple,
10234
+ ammoType: null,
10235
+ // Grapple uses no ammo in standard Q2 CTF? Or maybe just internal timer.
10236
+ initialAmmo: 0,
10237
+ pickupAmmo: 0,
10238
+ fireRate: 0.5,
10239
+ think: Grapple_Think
10120
10240
  }
10121
10241
  };
10122
10242
  var HEALTH_ITEMS = {
@@ -10518,6 +10638,34 @@ function setFlagState(flag, newState, context) {
10518
10638
  flag.flagState = newState;
10519
10639
  }
10520
10640
 
10641
+ // src/modes/ctf/scoreboard.ts
10642
+ var teamScores = {
10643
+ [1 /* RED */]: 0,
10644
+ [2 /* BLUE */]: 0
10645
+ };
10646
+ function addTeamScore(team, points) {
10647
+ if (team === 1 /* RED */ || team === 2 /* BLUE */) {
10648
+ teamScores[team] += points;
10649
+ }
10650
+ }
10651
+ function updateCtfScoreboard(ent, sys) {
10652
+ if (!ent.client || !ent.client.stats) return;
10653
+ const stats = ent.client.stats;
10654
+ stats[PlayerStat.STAT_CTF_TEAM1_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_r.pcx") : 0;
10655
+ stats[PlayerStat.STAT_CTF_TEAM1_CAPS] = teamScores[1 /* RED */];
10656
+ stats[PlayerStat.STAT_CTF_TEAM2_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_b.pcx") : 0;
10657
+ stats[PlayerStat.STAT_CTF_TEAM2_CAPS] = teamScores[2 /* BLUE */];
10658
+ const clientTeam = ent.client.ctfTeam;
10659
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM1_PIC] = 0;
10660
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM2_PIC] = 0;
10661
+ if (clientTeam === 1 /* RED */) {
10662
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM1_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_r.pcx") : 0;
10663
+ } else if (clientTeam === 2 /* BLUE */) {
10664
+ stats[PlayerStat.STAT_CTF_JOINED_TEAM2_PIC] = sys.configStringIndex ? sys.configStringIndex("pics/ctf_b.pcx") : 0;
10665
+ }
10666
+ stats[PlayerStat.STAT_CTF_TEAMINFO] = 1;
10667
+ }
10668
+
10521
10669
  // src/modes/ctf/capture.ts
10522
10670
  function checkCapture(flag, player, game, context) {
10523
10671
  if (!player.client) return false;
@@ -10538,11 +10686,17 @@ function captureFlag(ownFlag, player, game, context) {
10538
10686
  if (!player.client) return false;
10539
10687
  const playerTeam = player.client.team || "red";
10540
10688
  const enemyTeam = playerTeam === "red" ? "blue" : "red";
10689
+ const ctfStats = player.client.ctfStats;
10690
+ if (ctfStats) {
10691
+ ctfStats.captures++;
10692
+ }
10541
10693
  if (player.client.score !== void 0) {
10542
10694
  player.client.score += 5;
10543
10695
  } else {
10544
10696
  player.client.score = 5;
10545
10697
  }
10698
+ const teamEnum = playerTeam === "red" ? 1 /* RED */ : 2 /* BLUE */;
10699
+ addTeamScore(teamEnum, 1);
10546
10700
  game.sound?.(player, 0, "ctf/flagcap.wav", 1, 1, 0);
10547
10701
  game.centerprintf?.(player, "You captured the flag!");
10548
10702
  const enemyFlagKey = playerTeam === "red" ? "key_blue_flag" /* BlueFlag */ : "key_red_flag" /* RedFlag */;
@@ -12141,14 +12295,81 @@ var generic_stand_frames = Array.from({ length: 1 }, () => ({
12141
12295
  ai: generic_ai_stand,
12142
12296
  dist: 0
12143
12297
  }));
12298
+ var generic_stand_move = {
12299
+ firstframe: 0,
12300
+ lastframe: 0,
12301
+ frames: generic_stand_frames,
12302
+ endfunc: (self) => {
12303
+ self.monsterinfo.current_move = generic_stand_move;
12304
+ }
12305
+ };
12144
12306
  var generic_walk_frames = Array.from({ length: 1 }, () => ({
12145
12307
  ai: generic_ai_walk,
12146
12308
  dist: 5
12147
12309
  }));
12310
+ var generic_walk_move = {
12311
+ firstframe: 0,
12312
+ lastframe: 0,
12313
+ frames: generic_walk_frames,
12314
+ endfunc: (self) => {
12315
+ self.monsterinfo.current_move = generic_walk_move;
12316
+ }
12317
+ };
12148
12318
  var generic_run_frames = Array.from({ length: 1 }, () => ({
12149
12319
  ai: generic_ai_run,
12150
12320
  dist: 10
12151
12321
  }));
12322
+ var generic_run_move = {
12323
+ firstframe: 0,
12324
+ lastframe: 0,
12325
+ frames: generic_run_frames,
12326
+ endfunc: (self) => {
12327
+ self.monsterinfo.current_move = generic_run_move;
12328
+ }
12329
+ };
12330
+ function createMonsterSpawn(config) {
12331
+ return function(self, context) {
12332
+ self.model = config.model;
12333
+ self.mins = config.mins || { x: -16, y: -16, z: -24 };
12334
+ self.maxs = config.maxs || { x: 16, y: 16, z: 32 };
12335
+ self.movetype = config.fly ? 5 /* Step */ : 5 /* Step */;
12336
+ self.solid = 2 /* BoundingBox */;
12337
+ self.health = config.health * context.health_multiplier;
12338
+ self.max_health = self.health;
12339
+ self.mass = config.mass;
12340
+ self.takedamage = true;
12341
+ self.pain = (self2, other, kick, damage) => {
12342
+ };
12343
+ self.die = (self2, inflictor, attacker, damage, point, mod = 0 /* UNKNOWN */) => {
12344
+ self2.deadflag = 2 /* Dead */;
12345
+ self2.solid = 0 /* Not */;
12346
+ if (self2.health < -40) {
12347
+ throwGibs(context.entities, self2.origin, damage, GIB_ORGANIC, mod);
12348
+ context.entities.free(self2);
12349
+ return;
12350
+ }
12351
+ self2.think = (self3) => {
12352
+ context.entities.free(self3);
12353
+ };
12354
+ self2.nextthink = context.entities.timeSeconds + 5;
12355
+ };
12356
+ self.monsterinfo.stand = (self2, context2) => {
12357
+ self2.monsterinfo.current_move = generic_stand_move;
12358
+ };
12359
+ self.monsterinfo.walk = (self2, context2) => {
12360
+ self2.monsterinfo.current_move = generic_walk_move;
12361
+ };
12362
+ self.monsterinfo.run = (self2, context2) => {
12363
+ self2.monsterinfo.current_move = generic_run_move;
12364
+ };
12365
+ self.monsterinfo.attack = (self2, context2) => {
12366
+ self2.monsterinfo.current_move = generic_run_move;
12367
+ };
12368
+ self.think = monster_think;
12369
+ self.monsterinfo.stand(self, context.entities);
12370
+ self.nextthink = self.timestamp + MONSTER_TICK2;
12371
+ };
12372
+ }
12152
12373
  function M_SetAnimation(self, move, context) {
12153
12374
  self.monsterinfo.current_move = move;
12154
12375
  }
@@ -23873,6 +24094,39 @@ function registerShamblerSpawns(registry) {
23873
24094
  registry.register("monster_shambler", SP_monster_shambler);
23874
24095
  }
23875
24096
 
24097
+ // src/entities/monsters/rogue/common.ts
24098
+ var MAX_REINFORCEMENTS2 = 5;
24099
+ var INVERSE_LOG_SLOTS = Math.pow(2, MAX_REINFORCEMENTS2);
24100
+ function M_PickValidReinforcements(self, space, output) {
24101
+ output.length = 0;
24102
+ if (!self.monsterinfo.reinforcements) return;
24103
+ for (let i = 0; i < self.monsterinfo.reinforcements.length; i++) {
24104
+ if (self.monsterinfo.reinforcements[i].strength <= space) {
24105
+ output.push(i);
24106
+ }
24107
+ }
24108
+ }
24109
+ function M_PickReinforcements(self, rng, countRef, max_slots = 0) {
24110
+ const output = [];
24111
+ const chosen = new Array(MAX_REINFORCEMENTS2).fill(255);
24112
+ let num_chosen = 0;
24113
+ let num_slots = Math.max(1, Math.floor(Math.log2(rng.frandomRange(0, INVERSE_LOG_SLOTS))));
24114
+ let remaining = (self.monsterinfo.monster_slots || 0) - (self.monsterinfo.monster_used || 0);
24115
+ for (num_chosen = 0; num_chosen < num_slots; num_chosen++) {
24116
+ if (max_slots && num_chosen === max_slots || !remaining) {
24117
+ break;
24118
+ }
24119
+ M_PickValidReinforcements(self, remaining, output);
24120
+ if (output.length === 0) {
24121
+ break;
24122
+ }
24123
+ const randIndex = rng.irandomRange(0, output.length);
24124
+ chosen[num_chosen] = output[randIndex];
24125
+ remaining -= self.monsterinfo.reinforcements[chosen[num_chosen]].strength;
24126
+ }
24127
+ return { chosen, count: num_chosen };
24128
+ }
24129
+
23876
24130
  // src/entities/monsters/rogue/widow.ts
23877
24131
  var MODEL_SCALE3 = 1;
23878
24132
  var RANGE_MELEE3 = 100;
@@ -23984,6 +24238,43 @@ function widow_kick(self, context) {
23984
24238
  }
23985
24239
  function widow_spawn_check(self, context) {
23986
24240
  if (M_SlotsLeft(self) > 0) {
24241
+ const result = M_PickReinforcements(self, context.rng, 1);
24242
+ self.monsterinfo.chosen_reinforcements = result.chosen;
24243
+ if (result.count > 0) {
24244
+ const reinforcement = self.monsterinfo.reinforcements[self.monsterinfo.chosen_reinforcements[0]];
24245
+ WidowSpawn(self, context);
24246
+ }
24247
+ }
24248
+ }
24249
+ function WidowSpawn(self, context) {
24250
+ const { forward, right } = angleVectors(self.angles);
24251
+ const offset = { x: 50, y: 0, z: 0 };
24252
+ const start = M_ProjectFlashSource(self, offset, forward, right);
24253
+ if (!self.monsterinfo.chosen_reinforcements) {
24254
+ const result = M_PickReinforcements(self, context.rng, 1);
24255
+ self.monsterinfo.chosen_reinforcements = result.chosen;
24256
+ }
24257
+ if (self.monsterinfo.chosen_reinforcements && self.monsterinfo.chosen_reinforcements[0] !== 255) {
24258
+ const rIndex = self.monsterinfo.chosen_reinforcements[0];
24259
+ const reinforcement = self.monsterinfo.reinforcements[rIndex];
24260
+ const ent = context.spawn();
24261
+ ent.origin = { ...start };
24262
+ ent.angles = { ...self.angles };
24263
+ if (reinforcement.classname === "monster_stalker") {
24264
+ SP_monster_stalker(ent, { entities: context });
24265
+ } else if (reinforcement.classname === "monster_flyer") {
24266
+ SP_monster_flyer(ent, { entities: context });
24267
+ } else {
24268
+ createMonsterSpawn({
24269
+ model: "models/monsters/stalker/tris.md2",
24270
+ health: 100,
24271
+ mass: 100
24272
+ })(ent, { entities: context });
24273
+ }
24274
+ if (ent.inUse) {
24275
+ if (!self.monsterinfo.monster_used) self.monsterinfo.monster_used = 0;
24276
+ self.monsterinfo.monster_used += reinforcement.strength;
24277
+ }
23987
24278
  }
23988
24279
  }
23989
24280
  var widow_frames_stand = Array(20).fill({ ai: widow_ai_stand, dist: 0 });
@@ -26172,6 +26463,9 @@ function player_think(self, sys) {
26172
26463
  }
26173
26464
  }
26174
26465
  P_PlayerThink(self, sys);
26466
+ if (sys.deathmatch && (sys.configStringIndex ? sys.configStringIndex("pics/ctf_r.pcx") > 0 : true)) {
26467
+ updateCtfScoreboard(self, sys);
26468
+ }
26175
26469
  self.nextthink = sys.timeSeconds + 0.1;
26176
26470
  sys.scheduleThink(self, self.nextthink);
26177
26471
  }
@@ -26239,6 +26533,16 @@ function populatePlayerStats(player, timeSeconds) {
26239
26533
  const remainingSeconds = Math.ceil((bestTime - nowMs) / 1e3);
26240
26534
  statArray[PlayerStat.STAT_TIMER] = remainingSeconds;
26241
26535
  }
26536
+ if (player.client.score !== void 0) {
26537
+ statArray[PlayerStat.STAT_FRAGS] = player.client.score;
26538
+ }
26539
+ if (player.client.stats) {
26540
+ for (let i = 0; i < player.client.stats.length; i++) {
26541
+ if (player.client.stats[i] !== 0) {
26542
+ statArray[i] = player.client.stats[i];
26543
+ }
26544
+ }
26545
+ }
26242
26546
  return statArray;
26243
26547
  }
26244
26548