quake2ts 0.0.270 → 0.0.275

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 (50) hide show
  1. package/package.json +1 -1
  2. package/packages/cgame/dist/index.cjs +29 -5
  3. package/packages/cgame/dist/index.cjs.map +1 -1
  4. package/packages/cgame/dist/index.js +30 -6
  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.map +1 -1
  9. package/packages/client/dist/esm/index.js.map +1 -1
  10. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  11. package/packages/engine/dist/browser/index.global.js +6 -6
  12. package/packages/engine/dist/browser/index.global.js.map +1 -1
  13. package/packages/engine/dist/cjs/index.cjs.map +1 -1
  14. package/packages/engine/dist/esm/index.js.map +1 -1
  15. package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
  16. package/packages/game/dist/browser/index.global.js +3 -3
  17. package/packages/game/dist/browser/index.global.js.map +1 -1
  18. package/packages/game/dist/cjs/index.cjs +1170 -120
  19. package/packages/game/dist/cjs/index.cjs.map +1 -1
  20. package/packages/game/dist/esm/index.js +1170 -120
  21. package/packages/game/dist/esm/index.js.map +1 -1
  22. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  23. package/packages/game/dist/types/entities/entity.d.ts +2 -0
  24. package/packages/game/dist/types/entities/entity.d.ts.map +1 -1
  25. package/packages/game/dist/types/entities/monsters/fixbot.d.ts +5 -0
  26. package/packages/game/dist/types/entities/monsters/fixbot.d.ts.map +1 -0
  27. package/packages/game/dist/types/entities/monsters/gekk.d.ts +5 -0
  28. package/packages/game/dist/types/entities/monsters/gekk.d.ts.map +1 -0
  29. package/packages/game/dist/types/entities/monsters/index.d.ts.map +1 -1
  30. package/packages/game/dist/types/entities/playerStats.d.ts.map +1 -1
  31. package/packages/game/dist/types/entities/system.d.ts.map +1 -1
  32. package/packages/game/dist/types/entities/targets.d.ts.map +1 -1
  33. package/packages/game/dist/types/inventory/playerInventory.d.ts +5 -48
  34. package/packages/game/dist/types/inventory/playerInventory.d.ts.map +1 -1
  35. package/packages/server/dist/index.cjs +73 -5
  36. package/packages/server/dist/index.js +73 -5
  37. package/packages/shared/dist/browser/index.global.js +1 -1
  38. package/packages/shared/dist/browser/index.global.js.map +1 -1
  39. package/packages/shared/dist/cjs/index.cjs +47 -4
  40. package/packages/shared/dist/cjs/index.cjs.map +1 -1
  41. package/packages/shared/dist/esm/index.js +45 -4
  42. package/packages/shared/dist/esm/index.js.map +1 -1
  43. package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
  44. package/packages/shared/dist/types/items/index.d.ts +1 -0
  45. package/packages/shared/dist/types/items/index.d.ts.map +1 -1
  46. package/packages/shared/dist/types/items/weaponInfo.d.ts +5 -0
  47. package/packages/shared/dist/types/items/weaponInfo.d.ts.map +1 -0
  48. package/packages/shared/dist/types/items/weapons.d.ts +8 -7
  49. package/packages/shared/dist/types/items/weapons.d.ts.map +1 -1
  50. package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
@@ -933,6 +933,33 @@ function setCompressedInteger(stats, startIndex, id, count, bitsPerValue) {
933
933
  const valueToWrite = base & ~mask | count << bitShift & mask;
934
934
  writeUint16LE(stats, startIndex, byteOffset, valueToWrite & 65535);
935
935
  }
936
+ var PowerupId = /* @__PURE__ */ ((PowerupId22) => {
937
+ PowerupId22["QuadDamage"] = "quad";
938
+ PowerupId22["Invulnerability"] = "invulnerability";
939
+ PowerupId22["EnviroSuit"] = "enviro_suit";
940
+ PowerupId22["Rebreather"] = "rebreather";
941
+ PowerupId22["Silencer"] = "silencer";
942
+ PowerupId22["PowerScreen"] = "power_screen";
943
+ PowerupId22["PowerShield"] = "power_shield";
944
+ PowerupId22["QuadFire"] = "quad_fire";
945
+ PowerupId22["Invisibility"] = "invisibility";
946
+ PowerupId22["Bandolier"] = "bandolier";
947
+ PowerupId22["AmmoPack"] = "ammo_pack";
948
+ PowerupId22["IRGoggles"] = "ir_goggles";
949
+ PowerupId22["DoubleDamage"] = "double_damage";
950
+ PowerupId22["SphereVengeance"] = "sphere_vengeance";
951
+ PowerupId22["SphereHunter"] = "sphere_hunter";
952
+ PowerupId22["SphereDefender"] = "sphere_defender";
953
+ PowerupId22["Doppelganger"] = "doppelganger";
954
+ PowerupId22["TagToken"] = "tag_token";
955
+ PowerupId22["TechResistance"] = "tech_resistance";
956
+ PowerupId22["TechStrength"] = "tech_strength";
957
+ PowerupId22["TechHaste"] = "tech_haste";
958
+ PowerupId22["TechRegeneration"] = "tech_regeneration";
959
+ PowerupId22["Flashlight"] = "flashlight";
960
+ PowerupId22["Compass"] = "compass";
961
+ return PowerupId22;
962
+ })(PowerupId || {});
936
963
  var PlayerStat = /* @__PURE__ */ ((PlayerStat2) => {
937
964
  PlayerStat2[PlayerStat2["STAT_HEALTH_ICON"] = 0] = "STAT_HEALTH_ICON";
938
965
  PlayerStat2[PlayerStat2["STAT_HEALTH"] = 1] = "STAT_HEALTH";
@@ -1247,6 +1274,29 @@ var applyPmove = (state, cmd, trace, pointContents2) => {
1247
1274
  velocity: finalVelocity
1248
1275
  };
1249
1276
  };
1277
+ var WeaponId = /* @__PURE__ */ ((WeaponId22) => {
1278
+ WeaponId22["Blaster"] = "blaster";
1279
+ WeaponId22["Shotgun"] = "shotgun";
1280
+ WeaponId22["SuperShotgun"] = "supershotgun";
1281
+ WeaponId22["Machinegun"] = "machinegun";
1282
+ WeaponId22["Chaingun"] = "chaingun";
1283
+ WeaponId22["HandGrenade"] = "grenades";
1284
+ WeaponId22["GrenadeLauncher"] = "grenadelauncher";
1285
+ WeaponId22["RocketLauncher"] = "rocketlauncher";
1286
+ WeaponId22["HyperBlaster"] = "hyperblaster";
1287
+ WeaponId22["Railgun"] = "railgun";
1288
+ WeaponId22["BFG10K"] = "bfg10k";
1289
+ WeaponId22["Grapple"] = "grapple";
1290
+ WeaponId22["ChainFist"] = "chainfist";
1291
+ WeaponId22["EtfRifle"] = "etf_rifle";
1292
+ WeaponId22["ProxLauncher"] = "prox_launcher";
1293
+ WeaponId22["IonRipper"] = "ionripper";
1294
+ WeaponId22["PlasmaBeam"] = "plasmabeam";
1295
+ WeaponId22["Phalanx"] = "phalanx";
1296
+ WeaponId22["Disruptor"] = "disruptor";
1297
+ WeaponId22["Trap"] = "trap";
1298
+ return WeaponId22;
1299
+ })(WeaponId || {});
1250
1300
  var AmmoType = /* @__PURE__ */ ((AmmoType22) => {
1251
1301
  AmmoType22[AmmoType22["Bullets"] = 0] = "Bullets";
1252
1302
  AmmoType22[AmmoType22["Shells"] = 1] = "Shells";
@@ -1280,6 +1330,20 @@ var AmmoItemId = /* @__PURE__ */ ((AmmoItemId22) => {
1280
1330
  AmmoItemId22["Prox"] = "ammo_prox";
1281
1331
  return AmmoItemId22;
1282
1332
  })(AmmoItemId || {});
1333
+ var WEAPON_WHEEL_ORDER = [
1334
+ "blaster",
1335
+ "shotgun",
1336
+ "supershotgun",
1337
+ "machinegun",
1338
+ "chaingun",
1339
+ "grenadelauncher",
1340
+ "rocketlauncher",
1341
+ "grenades",
1342
+ "hyperblaster",
1343
+ "railgun",
1344
+ "bfg10k"
1345
+ /* BFG10K */
1346
+ ];
1283
1347
 
1284
1348
  // src/inventory/ammo.ts
1285
1349
  var AMMO_ITEM_DEFINITIONS = {
@@ -1462,54 +1526,6 @@ function applyPowerArmor(damage, flags, hitPoint, _hitNormal, state, options = {
1462
1526
  }
1463
1527
 
1464
1528
  // src/inventory/playerInventory.ts
1465
- var WeaponId = /* @__PURE__ */ ((WeaponId3) => {
1466
- WeaponId3["Blaster"] = "blaster";
1467
- WeaponId3["Shotgun"] = "shotgun";
1468
- WeaponId3["SuperShotgun"] = "supershotgun";
1469
- WeaponId3["Machinegun"] = "machinegun";
1470
- WeaponId3["Chaingun"] = "chaingun";
1471
- WeaponId3["GrenadeLauncher"] = "grenadelauncher";
1472
- WeaponId3["RocketLauncher"] = "rocketlauncher";
1473
- WeaponId3["HyperBlaster"] = "hyperblaster";
1474
- WeaponId3["Railgun"] = "railgun";
1475
- WeaponId3["BFG10K"] = "bfg10k";
1476
- WeaponId3["HandGrenade"] = "grenades";
1477
- WeaponId3["Grapple"] = "grapple";
1478
- WeaponId3["IonRipper"] = "ionripper";
1479
- WeaponId3["Phalanx"] = "phalanx";
1480
- WeaponId3["Trap"] = "trap";
1481
- WeaponId3["PlasmaBeam"] = "plasmabeam";
1482
- WeaponId3["EtfRifle"] = "etfrifle";
1483
- WeaponId3["ProxLauncher"] = "proxlauncher";
1484
- WeaponId3["ChainFist"] = "chainfist";
1485
- WeaponId3["Disruptor"] = "disruptor";
1486
- return WeaponId3;
1487
- })(WeaponId || {});
1488
- var PowerupId = /* @__PURE__ */ ((PowerupId3) => {
1489
- PowerupId3["QuadDamage"] = "quad";
1490
- PowerupId3["Invulnerability"] = "invulnerability";
1491
- PowerupId3["Silencer"] = "silencer";
1492
- PowerupId3["Rebreather"] = "rebreather";
1493
- PowerupId3["EnviroSuit"] = "enviro";
1494
- PowerupId3["DoubleDamage"] = "double";
1495
- PowerupId3["QuadFire"] = "quadfire";
1496
- PowerupId3["Invisibility"] = "invisibility";
1497
- PowerupId3["Bandolier"] = "bandolier";
1498
- PowerupId3["AmmoPack"] = "pack";
1499
- PowerupId3["IRGoggles"] = "goggles";
1500
- PowerupId3["SphereVengeance"] = "vengeance";
1501
- PowerupId3["SphereHunter"] = "hunter";
1502
- PowerupId3["SphereDefender"] = "defender";
1503
- PowerupId3["Doppelganger"] = "doppelganger";
1504
- PowerupId3["TagToken"] = "tagtoken";
1505
- PowerupId3["TechResistance"] = "tech_resistance";
1506
- PowerupId3["TechStrength"] = "tech_strength";
1507
- PowerupId3["TechHaste"] = "tech_haste";
1508
- PowerupId3["TechRegeneration"] = "tech_regeneration";
1509
- PowerupId3["Flashlight"] = "flashlight";
1510
- PowerupId3["Compass"] = "compass";
1511
- return PowerupId3;
1512
- })(PowerupId || {});
1513
1529
  var KeyId = /* @__PURE__ */ ((KeyId2) => {
1514
1530
  KeyId2["Blue"] = "key_blue";
1515
1531
  KeyId2["Red"] = "key_red";
@@ -1534,7 +1550,7 @@ function createPlayerInventory(init = {}) {
1534
1550
  const ammoCaps = init.ammoCaps;
1535
1551
  const inv = {
1536
1552
  ammo: createAmmoInventory(ammoCaps),
1537
- ownedWeapons: new Set(init.weapons ?? ["blaster" /* Blaster */]),
1553
+ ownedWeapons: new Set(init.weapons ?? [WeaponId.Blaster]),
1538
1554
  armor: null,
1539
1555
  powerups: /* @__PURE__ */ new Map(),
1540
1556
  keys: /* @__PURE__ */ new Set(),
@@ -1548,8 +1564,8 @@ function createPlayerInventory(init = {}) {
1548
1564
  if (init.currentWeapon) {
1549
1565
  inv.currentWeapon = init.currentWeapon;
1550
1566
  } else if (inv.ownedWeapons.size > 0) {
1551
- if (inv.ownedWeapons.has("blaster" /* Blaster */)) inv.currentWeapon = "blaster" /* Blaster */;
1552
- else if (inv.ownedWeapons.has("shotgun" /* Shotgun */)) inv.currentWeapon = "shotgun" /* Shotgun */;
1567
+ if (inv.ownedWeapons.has(WeaponId.Blaster)) inv.currentWeapon = WeaponId.Blaster;
1568
+ else if (inv.ownedWeapons.has(WeaponId.Shotgun)) inv.currentWeapon = WeaponId.Shotgun;
1553
1569
  else inv.currentWeapon = [...inv.ownedWeapons][0];
1554
1570
  }
1555
1571
  return inv;
@@ -1678,27 +1694,27 @@ function pickupPowerup(client, item, time) {
1678
1694
  let icon = "";
1679
1695
  switch (item.id) {
1680
1696
  case "item_quad":
1681
- powerupId = "quad" /* QuadDamage */;
1697
+ powerupId = PowerupId.QuadDamage;
1682
1698
  icon = "p_quad";
1683
1699
  break;
1684
1700
  case "item_invulnerability":
1685
- powerupId = "invulnerability" /* Invulnerability */;
1701
+ powerupId = PowerupId.Invulnerability;
1686
1702
  icon = "p_invulnerability";
1687
1703
  break;
1688
1704
  case "item_silencer":
1689
- powerupId = "silencer" /* Silencer */;
1705
+ powerupId = PowerupId.Silencer;
1690
1706
  icon = "p_silencer";
1691
1707
  break;
1692
1708
  case "item_rebreather":
1693
- powerupId = "rebreather" /* Rebreather */;
1709
+ powerupId = PowerupId.Rebreather;
1694
1710
  icon = "p_rebreather";
1695
1711
  break;
1696
1712
  case "item_enviro":
1697
- powerupId = "enviro" /* EnviroSuit */;
1713
+ powerupId = PowerupId.EnviroSuit;
1698
1714
  icon = "p_envirosuit";
1699
1715
  break;
1700
1716
  case "item_double":
1701
- powerupId = "double" /* DoubleDamage */;
1717
+ powerupId = PowerupId.DoubleDamage;
1702
1718
  icon = "p_double";
1703
1719
  break;
1704
1720
  }
@@ -1706,9 +1722,9 @@ function pickupPowerup(client, item, time) {
1706
1722
  const expiresAt = inventory.powerups.get(powerupId);
1707
1723
  const newExpiresAt = expiresAt && expiresAt > time ? expiresAt + item.timer * 1e3 : time + item.timer * 1e3;
1708
1724
  inventory.powerups.set(powerupId, newExpiresAt);
1709
- if (powerupId === "quad" /* QuadDamage */) {
1725
+ if (powerupId === PowerupId.QuadDamage) {
1710
1726
  client.quad_time = newExpiresAt / 1e3;
1711
- } else if (powerupId === "double" /* DoubleDamage */) {
1727
+ } else if (powerupId === PowerupId.DoubleDamage) {
1712
1728
  client.double_time = newExpiresAt / 1e3;
1713
1729
  }
1714
1730
  setPickup(inventory, icon, time);
@@ -1916,6 +1932,8 @@ var Entity = class {
1916
1932
  this.attenuation = 0;
1917
1933
  this.volume = 0;
1918
1934
  this.fly_sound_debounce_time = 0;
1935
+ this.last_move_time = 0;
1936
+ this.damage_debounce_time = 0;
1919
1937
  this.enemy = null;
1920
1938
  this.movetarget = null;
1921
1939
  this.target_ent = null;
@@ -2055,6 +2073,8 @@ var Entity = class {
2055
2073
  this.sounds = 0;
2056
2074
  this.noise_index = 0;
2057
2075
  this.fly_sound_debounce_time = 0;
2076
+ this.last_move_time = 0;
2077
+ this.damage_debounce_time = 0;
2058
2078
  this.enemy = null;
2059
2079
  this.movetarget = null;
2060
2080
  this.target_ent = null;
@@ -2150,6 +2170,8 @@ var ENTITY_FIELD_METADATA = [
2150
2170
  { name: "attenuation", type: "float", save: true },
2151
2171
  { name: "volume", type: "float", save: true },
2152
2172
  { name: "fly_sound_debounce_time", type: "float", save: true },
2173
+ { name: "last_move_time", type: "float", save: true },
2174
+ { name: "damage_debounce_time", type: "float", save: true },
2153
2175
  { name: "enemy", type: "entity", save: true },
2154
2176
  { name: "movetarget", type: "entity", save: true },
2155
2177
  { name: "target_ent", type: "entity", save: true },
@@ -3388,7 +3410,9 @@ var EntitySystem = class {
3388
3410
  }
3389
3411
  forEachEntity(callback) {
3390
3412
  for (const entity of this.pool) {
3391
- callback(entity);
3413
+ if (entity.inUse && !entity.freePending) {
3414
+ callback(entity);
3415
+ }
3392
3416
  }
3393
3417
  }
3394
3418
  find(predicate) {
@@ -4539,6 +4563,7 @@ function createBfgBall(sys, owner, start, dir, damage, speed, damageRadius) {
4539
4563
  }
4540
4564
 
4541
4565
  // src/entities/targets.ts
4566
+ var ATTN_NONE = 0;
4542
4567
  var ATTN_NORM = 1;
4543
4568
  var SPEAKER_SPAWNFLAGS = {
4544
4569
  LoopedOn: 1 << 0,
@@ -4631,6 +4656,88 @@ function useTargetBlaster(self, other, activator, context) {
4631
4656
  }
4632
4657
  context.entities.sound(self, 2, "weapons/laser2.wav", 1, ATTN_NORM, 0);
4633
4658
  }
4659
+ var SPAWNFLAG_EARTHQUAKE_SILENT = 1;
4660
+ var SPAWNFLAG_EARTHQUAKE_TOGGLE = 2;
4661
+ var SPAWNFLAG_EARTHQUAKE_ONE_SHOT = 8;
4662
+ function target_earthquake_think(self, context) {
4663
+ if (!(self.spawnflags & SPAWNFLAG_EARTHQUAKE_SILENT)) {
4664
+ if (self.last_move_time < context.entities.timeSeconds) {
4665
+ context.entities.sound(self, 2, "world/quake.wav", 1, ATTN_NONE, 0);
4666
+ self.last_move_time = context.entities.timeSeconds + 0.5;
4667
+ }
4668
+ }
4669
+ context.entities.forEachEntity((ent) => {
4670
+ if (!ent.client) return;
4671
+ ent.client.quake_time = context.entities.timeSeconds + 0.2;
4672
+ });
4673
+ if (context.entities.timeSeconds < self.timestamp) {
4674
+ self.nextthink = context.entities.timeSeconds + 0.1;
4675
+ }
4676
+ }
4677
+ function useTargetEarthquake(self, other, activator, context) {
4678
+ if (self.spawnflags & SPAWNFLAG_EARTHQUAKE_ONE_SHOT) {
4679
+ context.entities.forEachEntity((ent) => {
4680
+ if (!ent.client) return;
4681
+ if (ent.client) {
4682
+ if (!ent.client.kick_angles) ent.client.kick_angles = { x: 0, y: 0, z: 0 };
4683
+ ent.client.kick_angles = { ...ent.client.kick_angles, x: -self.speed * 0.1 };
4684
+ }
4685
+ });
4686
+ return;
4687
+ }
4688
+ self.timestamp = context.entities.timeSeconds + self.count;
4689
+ if (self.spawnflags & SPAWNFLAG_EARTHQUAKE_TOGGLE) {
4690
+ if (self.style) {
4691
+ self.nextthink = 0;
4692
+ } else {
4693
+ self.nextthink = context.entities.timeSeconds + 0.1;
4694
+ }
4695
+ self.style = !self.style ? 1 : 0;
4696
+ } else {
4697
+ self.nextthink = context.entities.timeSeconds + 0.1;
4698
+ self.last_move_time = 0;
4699
+ }
4700
+ self.activator = activator;
4701
+ }
4702
+ var SPAWNFLAG_LIGHTRAMP_TOGGLE = 1;
4703
+ function target_lightramp_think(self, context) {
4704
+ const timeDelta = context.entities.timeSeconds - self.timestamp;
4705
+ const val = self.movedir.x + timeDelta / 0.1 * self.movedir.z;
4706
+ let charCode = Math.floor("a".charCodeAt(0) + val);
4707
+ const styleStr = String.fromCharCode(charCode);
4708
+ const CS_LIGHTS = 32;
4709
+ if (self.enemy && self.enemy.style !== void 0) {
4710
+ context.entities.configstring(CS_LIGHTS + self.enemy.style, styleStr);
4711
+ }
4712
+ if (timeDelta < self.speed) {
4713
+ self.nextthink = context.entities.timeSeconds + 0.1;
4714
+ } else if (self.spawnflags & SPAWNFLAG_LIGHTRAMP_TOGGLE) {
4715
+ const temp = self.movedir.x;
4716
+ self.movedir = { ...self.movedir, x: self.movedir.y, y: temp, z: self.movedir.z * -1 };
4717
+ }
4718
+ }
4719
+ function useTargetLightramp(self, other, activator, context) {
4720
+ if (!self.enemy) {
4721
+ let e = null;
4722
+ let found = false;
4723
+ context.entities.forEachEntity((ent) => {
4724
+ if (ent.targetname === self.target) {
4725
+ if (ent.classname === "light") {
4726
+ self.enemy = ent;
4727
+ found = true;
4728
+ } else {
4729
+ context.warn(`${self.classname} target ${self.target} is not a light`);
4730
+ }
4731
+ }
4732
+ });
4733
+ if (!found) {
4734
+ context.warn(`${self.classname} target ${self.target} not found`);
4735
+ return;
4736
+ }
4737
+ }
4738
+ self.timestamp = context.entities.timeSeconds;
4739
+ target_lightramp_think(self, context);
4740
+ }
4634
4741
  var TARGET_LASER_START_ON = 1;
4635
4742
  var TARGET_LASER_RED = 2;
4636
4743
  var TARGET_LASER_GREEN = 4;
@@ -4887,6 +4994,26 @@ function registerTargetSpawns(registry) {
4887
4994
  };
4888
4995
  context.entities.scheduleThink(entity, context.entities.timeSeconds + entity.delay);
4889
4996
  });
4997
+ registry.register("target_earthquake", (entity, context) => {
4998
+ if (!entity.count) entity.count = 5;
4999
+ if (!entity.speed) entity.speed = 200;
5000
+ entity.svflags |= 1 /* NoClient */;
5001
+ entity.think = (self) => target_earthquake_think(self, context);
5002
+ entity.use = (self, other, activator) => useTargetEarthquake(self, other, activator ?? null, context);
5003
+ if (!(entity.spawnflags & SPAWNFLAG_EARTHQUAKE_SILENT)) {
5004
+ }
5005
+ });
5006
+ registry.register("target_lightramp", (entity, context) => {
5007
+ entity.svflags |= 1 /* NoClient */;
5008
+ entity.use = (self, other, activator) => useTargetLightramp(self, other, activator ?? null, context);
5009
+ entity.think = (self) => target_lightramp_think(self, context);
5010
+ if (entity.message && entity.message.length === 2 && entity.speed) {
5011
+ const start = entity.message.charCodeAt(0) - "a".charCodeAt(0);
5012
+ const end = entity.message.charCodeAt(1) - "a".charCodeAt(0);
5013
+ const slope = (end - start) / (entity.speed / 0.1);
5014
+ entity.movedir = { x: start, y: end, z: slope };
5015
+ }
5016
+ });
4890
5017
  }
4891
5018
 
4892
5019
  // src/entities/triggers.ts
@@ -5472,7 +5599,7 @@ function chaingunThink(player, sys) {
5472
5599
  if (!player.client) {
5473
5600
  return;
5474
5601
  }
5475
- const weaponState = getWeaponState(player.client.weaponStates, "chaingun" /* Chaingun */);
5602
+ const weaponState = getWeaponState(player.client.weaponStates, WeaponId.Chaingun);
5476
5603
  if (!(player.client.buttons & BUTTON_ATTACK) && weaponState.spinupCount && weaponState.spinupCount > 0) {
5477
5604
  sys.sound(player, 0, "weapons/chngnd1a.wav", 1, 0, 0);
5478
5605
  weaponState.spinupCount = 0;
@@ -5485,7 +5612,7 @@ var WEAPON_ITEMS = {
5485
5612
  type: "weapon",
5486
5613
  id: "weapon_blaster",
5487
5614
  name: "Blaster",
5488
- weaponId: "blaster" /* Blaster */,
5615
+ weaponId: WeaponId.Blaster,
5489
5616
  ammoType: null,
5490
5617
  initialAmmo: 0,
5491
5618
  pickupAmmo: 0,
@@ -5495,7 +5622,7 @@ var WEAPON_ITEMS = {
5495
5622
  type: "weapon",
5496
5623
  id: "weapon_shotgun",
5497
5624
  name: "Shotgun",
5498
- weaponId: "shotgun" /* Shotgun */,
5625
+ weaponId: WeaponId.Shotgun,
5499
5626
  ammoType: AmmoType.Shells,
5500
5627
  initialAmmo: 10,
5501
5628
  pickupAmmo: 10,
@@ -5505,7 +5632,7 @@ var WEAPON_ITEMS = {
5505
5632
  type: "weapon",
5506
5633
  id: "weapon_supershotgun",
5507
5634
  name: "Super Shotgun",
5508
- weaponId: "supershotgun" /* SuperShotgun */,
5635
+ weaponId: WeaponId.SuperShotgun,
5509
5636
  ammoType: AmmoType.Shells,
5510
5637
  initialAmmo: 10,
5511
5638
  pickupAmmo: 10,
@@ -5515,7 +5642,7 @@ var WEAPON_ITEMS = {
5515
5642
  type: "weapon",
5516
5643
  id: "weapon_machinegun",
5517
5644
  name: "Machinegun",
5518
- weaponId: "machinegun" /* Machinegun */,
5645
+ weaponId: WeaponId.Machinegun,
5519
5646
  ammoType: AmmoType.Bullets,
5520
5647
  initialAmmo: 50,
5521
5648
  pickupAmmo: 50,
@@ -5526,7 +5653,7 @@ var WEAPON_ITEMS = {
5526
5653
  type: "weapon",
5527
5654
  id: "weapon_chaingun",
5528
5655
  name: "Chaingun",
5529
- weaponId: "chaingun" /* Chaingun */,
5656
+ weaponId: WeaponId.Chaingun,
5530
5657
  ammoType: AmmoType.Bullets,
5531
5658
  initialAmmo: 50,
5532
5659
  pickupAmmo: 50,
@@ -5536,7 +5663,7 @@ var WEAPON_ITEMS = {
5536
5663
  type: "weapon",
5537
5664
  id: "weapon_grenades",
5538
5665
  name: "Hand Grenade",
5539
- weaponId: "grenades" /* HandGrenade */,
5666
+ weaponId: WeaponId.HandGrenade,
5540
5667
  ammoType: AmmoType.Grenades,
5541
5668
  initialAmmo: 5,
5542
5669
  pickupAmmo: 5,
@@ -5546,7 +5673,7 @@ var WEAPON_ITEMS = {
5546
5673
  type: "weapon",
5547
5674
  id: "weapon_grenadelauncher",
5548
5675
  name: "Grenade Launcher",
5549
- weaponId: "grenadelauncher" /* GrenadeLauncher */,
5676
+ weaponId: WeaponId.GrenadeLauncher,
5550
5677
  ammoType: AmmoType.Grenades,
5551
5678
  initialAmmo: 10,
5552
5679
  pickupAmmo: 10,
@@ -5556,7 +5683,7 @@ var WEAPON_ITEMS = {
5556
5683
  type: "weapon",
5557
5684
  id: "weapon_rocketlauncher",
5558
5685
  name: "Rocket Launcher",
5559
- weaponId: "rocketlauncher" /* RocketLauncher */,
5686
+ weaponId: WeaponId.RocketLauncher,
5560
5687
  ammoType: AmmoType.Rockets,
5561
5688
  initialAmmo: 5,
5562
5689
  pickupAmmo: 5,
@@ -5566,7 +5693,7 @@ var WEAPON_ITEMS = {
5566
5693
  type: "weapon",
5567
5694
  id: "weapon_hyperblaster",
5568
5695
  name: "HyperBlaster",
5569
- weaponId: "hyperblaster" /* HyperBlaster */,
5696
+ weaponId: WeaponId.HyperBlaster,
5570
5697
  ammoType: AmmoType.Cells,
5571
5698
  initialAmmo: 50,
5572
5699
  pickupAmmo: 50,
@@ -5576,7 +5703,7 @@ var WEAPON_ITEMS = {
5576
5703
  type: "weapon",
5577
5704
  id: "weapon_railgun",
5578
5705
  name: "Railgun",
5579
- weaponId: "railgun" /* Railgun */,
5706
+ weaponId: WeaponId.Railgun,
5580
5707
  ammoType: AmmoType.Slugs,
5581
5708
  initialAmmo: 10,
5582
5709
  pickupAmmo: 10,
@@ -5586,7 +5713,7 @@ var WEAPON_ITEMS = {
5586
5713
  type: "weapon",
5587
5714
  id: "weapon_bfg",
5588
5715
  name: "BFG10K",
5589
- weaponId: "bfg10k" /* BFG10K */,
5716
+ weaponId: WeaponId.BFG10K,
5590
5717
  ammoType: AmmoType.Cells,
5591
5718
  initialAmmo: 50,
5592
5719
  pickupAmmo: 50,
@@ -5598,7 +5725,7 @@ var WEAPON_ITEMS = {
5598
5725
  id: "weapon_boomer",
5599
5726
  // Ion Ripper
5600
5727
  name: "Ion Ripper",
5601
- weaponId: "ionripper" /* IonRipper */,
5728
+ weaponId: WeaponId.IonRipper,
5602
5729
  ammoType: AmmoType.Cells,
5603
5730
  initialAmmo: 50,
5604
5731
  pickupAmmo: 50,
@@ -5608,7 +5735,7 @@ var WEAPON_ITEMS = {
5608
5735
  type: "weapon",
5609
5736
  id: "weapon_phalanx",
5610
5737
  name: "Phalanx",
5611
- weaponId: "phalanx" /* Phalanx */,
5738
+ weaponId: WeaponId.Phalanx,
5612
5739
  ammoType: AmmoType.MagSlugs,
5613
5740
  initialAmmo: 50,
5614
5741
  pickupAmmo: 50,
@@ -5618,7 +5745,7 @@ var WEAPON_ITEMS = {
5618
5745
  type: "weapon",
5619
5746
  id: "weapon_beam",
5620
5747
  name: "Plasma Beam",
5621
- weaponId: "plasmabeam" /* PlasmaBeam */,
5748
+ weaponId: WeaponId.PlasmaBeam,
5622
5749
  ammoType: AmmoType.Cells,
5623
5750
  initialAmmo: 50,
5624
5751
  pickupAmmo: 50,
@@ -5628,7 +5755,7 @@ var WEAPON_ITEMS = {
5628
5755
  type: "weapon",
5629
5756
  id: "weapon_etf_rifle",
5630
5757
  name: "ETF Rifle",
5631
- weaponId: "etfrifle" /* EtfRifle */,
5758
+ weaponId: WeaponId.EtfRifle,
5632
5759
  ammoType: AmmoType.Flechettes,
5633
5760
  initialAmmo: 50,
5634
5761
  pickupAmmo: 50,
@@ -5638,7 +5765,7 @@ var WEAPON_ITEMS = {
5638
5765
  type: "weapon",
5639
5766
  id: "weapon_proxlauncher",
5640
5767
  name: "Prox Launcher",
5641
- weaponId: "proxlauncher" /* ProxLauncher */,
5768
+ weaponId: WeaponId.ProxLauncher,
5642
5769
  ammoType: AmmoType.Prox,
5643
5770
  initialAmmo: 5,
5644
5771
  pickupAmmo: 5,
@@ -11547,8 +11674,8 @@ function actor_pain(self, other, kick, damage) {
11547
11674
  if (context.timeSeconds < self.pain_debounce_time)
11548
11675
  return;
11549
11676
  self.pain_debounce_time = context.timeSeconds + 3;
11550
- const random10 = Math.random();
11551
- if (other && other.client && random10 < 0.4) {
11677
+ const random12 = Math.random();
11678
+ if (other && other.client && random12 < 0.4) {
11552
11679
  const v = subtractVec3(other.origin, self.origin);
11553
11680
  self.ideal_yaw = vectorToYaw(v);
11554
11681
  if (Math.random() < 0.5)
@@ -14244,6 +14371,934 @@ function registerTurretSpawns(registry) {
14244
14371
  registry.register("monster_turret", SP_monster_turret);
14245
14372
  }
14246
14373
 
14374
+ // src/entities/monsters/gekk.ts
14375
+ var MONSTER_TICK24 = 0.1;
14376
+ var random8 = () => Math.random();
14377
+ var frandom2 = () => Math.random();
14378
+ var irandom2 = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
14379
+ function monster_ai_stand22(self, dist, context) {
14380
+ ai_stand(self, MONSTER_TICK24, context);
14381
+ }
14382
+ function monster_ai_walk20(self, dist, context) {
14383
+ ai_walk(self, dist, MONSTER_TICK24, context);
14384
+ }
14385
+ function monster_ai_run21(self, dist, context) {
14386
+ ai_run(self, dist, MONSTER_TICK24, context);
14387
+ }
14388
+ function monster_ai_charge22(self, dist, context) {
14389
+ ai_charge(self, dist, MONSTER_TICK24, context);
14390
+ }
14391
+ function monster_ai_move21(self, dist, context) {
14392
+ ai_move(self, dist);
14393
+ }
14394
+ var gekk_move_stand;
14395
+ var gekk_move_standunderwater;
14396
+ var gekk_move_swim_loop;
14397
+ var gekk_move_swim_start;
14398
+ var gekk_move_chant;
14399
+ var gekk_move_idle;
14400
+ var gekk_move_idle2;
14401
+ var gekk_move_walk;
14402
+ var gekk_move_run;
14403
+ var gekk_move_run_start;
14404
+ var gekk_move_attack1;
14405
+ var gekk_move_attack2;
14406
+ var gekk_move_spit;
14407
+ var gekk_move_leapatk;
14408
+ var gekk_move_leapatk2;
14409
+ var gekk_move_attack;
14410
+ var gekk_move_pain;
14411
+ var gekk_move_pain1;
14412
+ var gekk_move_pain2;
14413
+ var gekk_move_death1;
14414
+ var gekk_move_death3;
14415
+ var gekk_move_death4;
14416
+ var gekk_move_wdeath;
14417
+ var WATER_WAIST = 2;
14418
+ var RANGE_MELEE2 = 80;
14419
+ var RANGE_NEAR2 = 100;
14420
+ var RANGE_MID2 = 400;
14421
+ var SPAWNFLAG_GEKK_CHANT = 8;
14422
+ var SPAWNFLAG_GEKK_NOJUMPING = 16;
14423
+ var SPAWNFLAG_GEKK_NOSWIM = 32;
14424
+ var GIB_HEALTH = -30;
14425
+ function gekk_check_underwater(self, context) {
14426
+ if (!(self.spawnflags & SPAWNFLAG_GEKK_NOSWIM) && self.waterlevel >= WATER_WAIST) {
14427
+ land_to_water(self);
14428
+ }
14429
+ }
14430
+ function gekk_stand(self) {
14431
+ if (self.waterlevel >= WATER_WAIST) {
14432
+ self.flags |= 2 /* Swim */;
14433
+ self.monsterinfo.current_move = gekk_move_standunderwater;
14434
+ } else {
14435
+ if (self.monsterinfo.current_move !== gekk_move_chant) {
14436
+ self.monsterinfo.current_move = gekk_move_stand;
14437
+ }
14438
+ }
14439
+ }
14440
+ function gekk_swim_loop_func(self) {
14441
+ self.flags |= 2 /* Swim */;
14442
+ self.monsterinfo.current_move = gekk_move_swim_loop;
14443
+ }
14444
+ function gekk_hit_left(self, context) {
14445
+ if (!self.enemy) return;
14446
+ const damage = irandom2(5, 10);
14447
+ const range = 100;
14448
+ const dir = subtractVec3(self.enemy.origin, self.origin);
14449
+ const dist = lengthVec3(dir);
14450
+ if (dist <= range) {
14451
+ context.engine.sound?.(self, 0, "gek/gk_atck2.wav", 1, 1, 0);
14452
+ T_Damage(self.enemy, self, self, normalizeVec3(dir), self.enemy.origin, ZERO_VEC3, damage, damage, 0, 0 /* UNKNOWN */, context.timeSeconds);
14453
+ } else {
14454
+ context.engine.sound?.(self, 0, "gek/gk_atck1.wav", 1, 1, 0);
14455
+ }
14456
+ }
14457
+ function gekk_hit_right(self, context) {
14458
+ if (!self.enemy) return;
14459
+ const damage = irandom2(5, 10);
14460
+ const range = 100;
14461
+ const dir = subtractVec3(self.enemy.origin, self.origin);
14462
+ const dist = lengthVec3(dir);
14463
+ if (dist <= range) {
14464
+ context.engine.sound?.(self, 0, "gek/gk_atck3.wav", 1, 1, 0);
14465
+ T_Damage(self.enemy, self, self, normalizeVec3(dir), self.enemy.origin, ZERO_VEC3, damage, damage, 0, 0 /* UNKNOWN */, context.timeSeconds);
14466
+ } else {
14467
+ context.engine.sound?.(self, 0, "gek/gk_atck1.wav", 1, 1, 0);
14468
+ }
14469
+ }
14470
+ function gekk_bite(self, context) {
14471
+ if (!self.enemy) return;
14472
+ const damage = 5;
14473
+ const range = RANGE_MELEE2;
14474
+ const dir = subtractVec3(self.enemy.origin, self.origin);
14475
+ const dist = lengthVec3(dir);
14476
+ if (dist <= range) {
14477
+ T_Damage(self.enemy, self, self, normalizeVec3(dir), self.enemy.origin, ZERO_VEC3, damage, 0, 0, 0 /* UNKNOWN */, context.timeSeconds);
14478
+ }
14479
+ }
14480
+ function gekk_check_melee(self, context) {
14481
+ if (!self.enemy || self.enemy.health <= 0 || self.monsterinfo.melee_debounce_time && self.monsterinfo.melee_debounce_time > context.timeSeconds)
14482
+ return false;
14483
+ const dist = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14484
+ return dist <= RANGE_MELEE2;
14485
+ }
14486
+ function gekk_check_jump(self, context) {
14487
+ if (!self.enemy) return false;
14488
+ if (self.absmin.z + 125 < self.enemy.absmin.z)
14489
+ return false;
14490
+ const v = subtractVec3(self.origin, self.enemy.origin);
14491
+ v.z = 0;
14492
+ const distance2 = lengthVec3(v);
14493
+ if (distance2 < 100) return false;
14494
+ if (distance2 > 100) {
14495
+ if (frandom2() < (self.waterlevel >= WATER_WAIST ? 0.2 : 0.9))
14496
+ return false;
14497
+ }
14498
+ return true;
14499
+ }
14500
+ function gekk_check_jump_close(self, context) {
14501
+ if (!self.enemy) return false;
14502
+ const v = subtractVec3(self.origin, self.enemy.origin);
14503
+ v.z = 0;
14504
+ const distance2 = lengthVec3(v);
14505
+ if (distance2 < 100) {
14506
+ if (self.absmax.z <= self.enemy.absmin.z) return false;
14507
+ }
14508
+ return true;
14509
+ }
14510
+ function gekk_checkattack(self, context) {
14511
+ if (!self.enemy || self.enemy.health <= 0) return false;
14512
+ if (gekk_check_melee(self, context)) {
14513
+ return true;
14514
+ }
14515
+ if (gekk_check_jump(self, context)) {
14516
+ return true;
14517
+ }
14518
+ if (gekk_check_jump_close(self, context) && !(self.flags & 2 /* Swim */)) {
14519
+ return true;
14520
+ }
14521
+ return false;
14522
+ }
14523
+ function gekk_chant(self) {
14524
+ self.monsterinfo.current_move = gekk_move_chant;
14525
+ }
14526
+ function gekk_idle_loop(self) {
14527
+ if (frandom2() > 0.75 && self.health < self.max_health) {
14528
+ self.monsterinfo.nextframe = 0;
14529
+ }
14530
+ }
14531
+ function gekk_step(self, context) {
14532
+ const n = irandom2(0, 2);
14533
+ const sounds = ["gek/gk_step1.wav", "gek/gk_step2.wav", "gek/gk_step3.wav"];
14534
+ context.engine.sound?.(self, 0, sounds[n], 1, 1, 0);
14535
+ }
14536
+ function gekk_search(self, context) {
14537
+ if (self.spawnflags & SPAWNFLAG_GEKK_CHANT) {
14538
+ const r = frandom2();
14539
+ if (r < 0.33) context.engine.sound?.(self, 0, "gek/gek_low.wav", 1, 1, 0);
14540
+ else if (r < 0.66) context.engine.sound?.(self, 0, "gek/gek_mid.wav", 1, 1, 0);
14541
+ else context.engine.sound?.(self, 0, "gek/gek_high.wav", 1, 1, 0);
14542
+ } else {
14543
+ context.engine.sound?.(self, 0, "gek/gk_idle1.wav", 1, 1, 0);
14544
+ }
14545
+ self.health += irandom2(10, 20);
14546
+ if (self.health > self.max_health) self.health = self.max_health;
14547
+ if (self.health < self.max_health / 4) self.skin = 2;
14548
+ else if (self.health < self.max_health / 2) self.skin = 1;
14549
+ else self.skin = 0;
14550
+ }
14551
+ function gekk_run_start(self) {
14552
+ if (!(self.spawnflags & SPAWNFLAG_GEKK_NOSWIM) && self.waterlevel >= WATER_WAIST) {
14553
+ self.monsterinfo.current_move = gekk_move_swim_start;
14554
+ } else {
14555
+ self.monsterinfo.current_move = gekk_move_run_start;
14556
+ }
14557
+ }
14558
+ function gekk_run(self) {
14559
+ if (!(self.spawnflags & SPAWNFLAG_GEKK_NOSWIM) && self.waterlevel >= WATER_WAIST) {
14560
+ self.monsterinfo.current_move = gekk_move_swim_start;
14561
+ } else {
14562
+ self.monsterinfo.current_move = gekk_move_run;
14563
+ }
14564
+ }
14565
+ function gekk_check_refire(self) {
14566
+ if (!self.enemy || self.enemy.health <= 0) return;
14567
+ const dist = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14568
+ if (dist <= RANGE_MELEE2) {
14569
+ if (self.frame === 114) {
14570
+ self.monsterinfo.current_move = gekk_move_attack2;
14571
+ } else if (self.frame === 123) {
14572
+ self.monsterinfo.current_move = gekk_move_attack1;
14573
+ }
14574
+ }
14575
+ }
14576
+ function fire_loogie(self, start, dir, damage, speed, context) {
14577
+ const bolt = createBlasterBolt(context, self, start, dir, damage, speed, 0 /* UNKNOWN */);
14578
+ bolt.model = "models/objects/loogy/tris.md2";
14579
+ }
14580
+ function loogie_fire(self, context) {
14581
+ if (!self.enemy || self.enemy.health <= 0) return;
14582
+ const vectors = angleVectors(self.angles);
14583
+ const forward = vectors.forward;
14584
+ const right = vectors.right;
14585
+ const up = vectors.up;
14586
+ const offset = { x: -18, y: -0.8, z: 24 };
14587
+ const start = addVec3(self.origin, addVec3(scaleVec3(forward, offset.x), addVec3(scaleVec3(right, offset.y), scaleVec3(up, offset.z))));
14588
+ start.z += 2;
14589
+ const end = copyVec3(self.enemy.origin);
14590
+ end.z += self.enemy.viewheight || 0;
14591
+ const dir = normalizeVec3(subtractVec3(end, start));
14592
+ fire_loogie(self, start, dir, 5, 550, context);
14593
+ context.engine.sound?.(self, 0, "gek/gk_atck4.wav", 1, 1, 0);
14594
+ }
14595
+ function reloogie(self) {
14596
+ if (frandom2() > 0.8 && self.health < self.max_health) {
14597
+ self.monsterinfo.current_move = gekk_move_idle2;
14598
+ return;
14599
+ }
14600
+ if (self.enemy && self.enemy.health > 0) {
14601
+ const dist = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14602
+ if (frandom2() > 0.7 && dist <= RANGE_NEAR2) {
14603
+ self.monsterinfo.current_move = gekk_move_spit;
14604
+ }
14605
+ }
14606
+ }
14607
+ function gekk_jump_touch(self, other, plane, surf) {
14608
+ if (self.health <= 0) {
14609
+ self.touch = void 0;
14610
+ return;
14611
+ }
14612
+ self.touch = void 0;
14613
+ }
14614
+ function gekk_jump_takeoff(self, context) {
14615
+ const vectors = angleVectors(self.angles);
14616
+ const forward = vectors.forward;
14617
+ context.engine.sound?.(self, 0, "gek/gk_sght1.wav", 1, 1, 0);
14618
+ self.origin.z += 1;
14619
+ self.velocity = addVec3(scaleVec3(forward, 700), { x: 0, y: 0, z: 250 });
14620
+ self.groundentity = null;
14621
+ self.touch = gekk_jump_touch;
14622
+ }
14623
+ function gekk_check_landing(self, context) {
14624
+ if (self.groundentity) {
14625
+ context.engine.sound?.(self, 0, "mutant/thud1.wav", 1, 1, 0);
14626
+ self.velocity = ZERO_VEC3;
14627
+ return;
14628
+ }
14629
+ }
14630
+ function gekk_stop_skid(self) {
14631
+ if (self.groundentity) self.velocity = ZERO_VEC3;
14632
+ }
14633
+ function gekk_preattack(self, context) {
14634
+ }
14635
+ function gekk_dead(self) {
14636
+ self.mins = { x: -16, y: -16, z: -24 };
14637
+ self.maxs = { x: 16, y: 16, z: -8 };
14638
+ self.nextthink = -1;
14639
+ }
14640
+ function gekk_gibfest(self, context) {
14641
+ throwGibs(context, self.origin, 20);
14642
+ self.deadflag = 2 /* Dead */;
14643
+ }
14644
+ function isgibfest(self, context) {
14645
+ if (frandom2() > 0.9) gekk_gibfest(self, context);
14646
+ }
14647
+ function gekk_shrink(self) {
14648
+ self.maxs.z = 0;
14649
+ }
14650
+ function land_to_water(self) {
14651
+ self.flags |= 2 /* Swim */;
14652
+ self.yaw_speed = 10;
14653
+ self.viewheight = 10;
14654
+ self.monsterinfo.current_move = gekk_move_swim_start;
14655
+ self.mins = { x: -18, y: -18, z: -24 };
14656
+ self.maxs = { x: 18, y: 18, z: 16 };
14657
+ }
14658
+ var frames_stand2 = Array(38).fill({ ai: monster_ai_stand22, dist: 0 });
14659
+ frames_stand2[38] = { ai: monster_ai_stand22, dist: 0, think: gekk_check_underwater };
14660
+ gekk_move_stand = {
14661
+ firstframe: 0,
14662
+ lastframe: 38,
14663
+ frames: frames_stand2,
14664
+ endfunc: null
14665
+ };
14666
+ var frames_standunderwater = Array(32).fill({ ai: monster_ai_stand22, dist: 14 });
14667
+ gekk_move_standunderwater = {
14668
+ firstframe: 39,
14669
+ lastframe: 70,
14670
+ frames: frames_standunderwater,
14671
+ endfunc: null
14672
+ };
14673
+ var frames_swim = Array(32).fill({ ai: monster_ai_run21, dist: 14 });
14674
+ gekk_move_swim_loop = {
14675
+ firstframe: 39,
14676
+ lastframe: 70,
14677
+ frames: frames_swim,
14678
+ endfunc: gekk_swim_loop_func
14679
+ };
14680
+ var frames_swim_start = Array(32).fill({ ai: monster_ai_run21, dist: 14 });
14681
+ frames_swim_start[8] = { ai: monster_ai_run21, dist: 18, think: gekk_hit_left };
14682
+ frames_swim_start[14] = { ai: monster_ai_run21, dist: 24, think: gekk_hit_right };
14683
+ frames_swim_start[20] = { ai: monster_ai_run21, dist: 22, think: gekk_bite };
14684
+ gekk_move_swim_start = {
14685
+ firstframe: 39,
14686
+ lastframe: 70,
14687
+ frames: frames_swim_start,
14688
+ endfunc: gekk_swim_loop_func
14689
+ };
14690
+ var frames_idle = Array(32).fill({ ai: monster_ai_stand22, dist: 0 });
14691
+ frames_idle[0] = { ai: monster_ai_stand22, dist: 0, think: gekk_search };
14692
+ frames_idle[31] = { ai: monster_ai_stand22, dist: 0, think: gekk_idle_loop };
14693
+ gekk_move_idle = {
14694
+ firstframe: 71,
14695
+ lastframe: 102,
14696
+ frames: frames_idle,
14697
+ endfunc: gekk_stand
14698
+ };
14699
+ var frames_idle2 = Array(32).fill({ ai: monster_ai_move21, dist: 0 });
14700
+ frames_idle2[0] = { ai: monster_ai_move21, dist: 0, think: gekk_search };
14701
+ frames_idle2[31] = { ai: monster_ai_move21, dist: 0, think: gekk_idle_loop };
14702
+ gekk_move_idle2 = {
14703
+ firstframe: 71,
14704
+ lastframe: 102,
14705
+ frames: frames_idle2,
14706
+ endfunc: (s) => M_SetAnimation2(s, gekk_move_stand)
14707
+ // or face
14708
+ };
14709
+ gekk_move_chant = {
14710
+ firstframe: 71,
14711
+ lastframe: 102,
14712
+ frames: frames_idle2,
14713
+ endfunc: gekk_chant
14714
+ };
14715
+ var frames_walk2 = [
14716
+ { ai: monster_ai_walk20, dist: 3.8, think: gekk_check_underwater },
14717
+ { ai: monster_ai_walk20, dist: 19.6 },
14718
+ { ai: monster_ai_walk20, dist: 25.5 },
14719
+ { ai: monster_ai_walk20, dist: 34.6, think: gekk_step },
14720
+ { ai: monster_ai_walk20, dist: 27.3 },
14721
+ { ai: monster_ai_walk20, dist: 28.4 }
14722
+ ];
14723
+ gekk_move_walk = {
14724
+ firstframe: 103,
14725
+ lastframe: 108,
14726
+ frames: frames_walk2,
14727
+ endfunc: null
14728
+ };
14729
+ var frames_run2 = [
14730
+ { ai: monster_ai_run21, dist: 3.8, think: gekk_check_underwater },
14731
+ { ai: monster_ai_run21, dist: 19.6 },
14732
+ { ai: monster_ai_run21, dist: 25.5 },
14733
+ { ai: monster_ai_run21, dist: 34.6, think: gekk_step },
14734
+ { ai: monster_ai_run21, dist: 27.3 },
14735
+ { ai: monster_ai_run21, dist: 28.4 }
14736
+ ];
14737
+ gekk_move_run = {
14738
+ firstframe: 103,
14739
+ lastframe: 108,
14740
+ frames: frames_run2,
14741
+ endfunc: null
14742
+ };
14743
+ var frames_run_st = [
14744
+ { ai: monster_ai_run21, dist: 0.2 },
14745
+ { ai: monster_ai_run21, dist: 19.7 }
14746
+ ];
14747
+ gekk_move_run_start = {
14748
+ firstframe: 0,
14749
+ lastframe: 1,
14750
+ // Frames 0 and 1 reuse stand start? C says FRAME_stand_01, FRAME_stand_02
14751
+ frames: frames_run_st,
14752
+ endfunc: gekk_run
14753
+ };
14754
+ var frames_spit = [
14755
+ { ai: monster_ai_charge22, dist: 0 },
14756
+ { ai: monster_ai_charge22, dist: 0 },
14757
+ { ai: monster_ai_charge22, dist: 0 },
14758
+ { ai: monster_ai_charge22, dist: 0 },
14759
+ { ai: monster_ai_charge22, dist: 0 },
14760
+ { ai: monster_ai_charge22, dist: 0, think: loogie_fire },
14761
+ { ai: monster_ai_charge22, dist: 0, think: reloogie }
14762
+ ];
14763
+ gekk_move_spit = {
14764
+ firstframe: 133,
14765
+ // FRAME_spit_01
14766
+ lastframe: 139,
14767
+ frames: frames_spit,
14768
+ endfunc: gekk_run_start
14769
+ };
14770
+ var frames_attack1 = [
14771
+ { ai: monster_ai_charge22, dist: 0 },
14772
+ { ai: monster_ai_charge22, dist: 0 },
14773
+ { ai: monster_ai_charge22, dist: 0 },
14774
+ { ai: monster_ai_charge22, dist: 0, think: gekk_hit_left },
14775
+ { ai: monster_ai_charge22, dist: 0 },
14776
+ { ai: monster_ai_charge22, dist: 0 },
14777
+ { ai: monster_ai_charge22, dist: 0 },
14778
+ { ai: monster_ai_charge22, dist: 0 },
14779
+ { ai: monster_ai_charge22, dist: 0, think: gekk_check_refire }
14780
+ ];
14781
+ gekk_move_attack1 = {
14782
+ firstframe: 109,
14783
+ lastframe: 117,
14784
+ frames: frames_attack1,
14785
+ endfunc: gekk_run_start
14786
+ };
14787
+ var frames_attack2 = [
14788
+ { ai: monster_ai_charge22, dist: 0 },
14789
+ { ai: monster_ai_charge22, dist: 0 },
14790
+ { ai: monster_ai_charge22, dist: 0, think: gekk_hit_left },
14791
+ { ai: monster_ai_charge22, dist: 0 },
14792
+ { ai: monster_ai_charge22, dist: 0 },
14793
+ { ai: monster_ai_charge22, dist: 0, think: gekk_hit_right },
14794
+ { ai: monster_ai_charge22, dist: 0 },
14795
+ { ai: monster_ai_charge22, dist: 0 },
14796
+ { ai: monster_ai_charge22, dist: 0, think: gekk_check_refire }
14797
+ ];
14798
+ gekk_move_attack2 = {
14799
+ firstframe: 118,
14800
+ lastframe: 126,
14801
+ frames: frames_attack2,
14802
+ endfunc: gekk_run_start
14803
+ };
14804
+ var frames_leapatk = [
14805
+ { ai: monster_ai_charge22, dist: 0 },
14806
+ { ai: monster_ai_charge22, dist: -0.3 },
14807
+ { ai: monster_ai_charge22, dist: -1.1 },
14808
+ { ai: monster_ai_charge22, dist: -0.2 },
14809
+ { ai: monster_ai_charge22, dist: 6.7, think: gekk_jump_takeoff },
14810
+ { ai: monster_ai_charge22, dist: 6.4 },
14811
+ { ai: monster_ai_charge22, dist: 0.1 },
14812
+ { ai: monster_ai_charge22, dist: 28.3 },
14813
+ { ai: monster_ai_charge22, dist: 24.1 },
14814
+ { ai: monster_ai_charge22, dist: 31.7 },
14815
+ { ai: monster_ai_charge22, dist: 35.9, think: gekk_check_landing },
14816
+ { ai: monster_ai_charge22, dist: 12.3, think: gekk_stop_skid },
14817
+ { ai: monster_ai_charge22, dist: 20.1, think: gekk_stop_skid },
14818
+ { ai: monster_ai_charge22, dist: -1, think: gekk_stop_skid },
14819
+ { ai: monster_ai_charge22, dist: 2.5, think: gekk_stop_skid },
14820
+ { ai: monster_ai_charge22, dist: 0.5, think: gekk_stop_skid },
14821
+ { ai: monster_ai_charge22, dist: 1.8, think: gekk_stop_skid },
14822
+ { ai: monster_ai_charge22, dist: 1.2, think: gekk_stop_skid },
14823
+ { ai: monster_ai_charge22, dist: -0.4, think: gekk_check_underwater }
14824
+ ];
14825
+ gekk_move_leapatk = {
14826
+ firstframe: 140,
14827
+ lastframe: 158,
14828
+ frames: frames_leapatk,
14829
+ endfunc: gekk_run_start
14830
+ };
14831
+ gekk_move_leapatk2 = {
14832
+ firstframe: 140,
14833
+ lastframe: 158,
14834
+ frames: frames_leapatk,
14835
+ // reusing frames
14836
+ endfunc: gekk_run_start
14837
+ };
14838
+ var frames_attack3 = Array(21).fill({ ai: monster_ai_charge22, dist: 16 });
14839
+ frames_attack3[0] = { ai: monster_ai_charge22, dist: 16, think: gekk_preattack };
14840
+ frames_attack3[4] = { ai: monster_ai_charge22, dist: 16, think: gekk_bite };
14841
+ frames_attack3[9] = { ai: monster_ai_charge22, dist: 16, think: gekk_bite };
14842
+ frames_attack3[13] = { ai: monster_ai_charge22, dist: 16, think: gekk_hit_left };
14843
+ frames_attack3[18] = { ai: monster_ai_charge22, dist: 16, think: gekk_hit_right };
14844
+ gekk_move_attack = {
14845
+ firstframe: 159,
14846
+ lastframe: 179,
14847
+ frames: frames_attack3,
14848
+ endfunc: gekk_run_start
14849
+ };
14850
+ var frames_pain = Array(6).fill({ ai: monster_ai_move21, dist: 0 });
14851
+ gekk_move_pain = {
14852
+ firstframe: 180,
14853
+ lastframe: 185,
14854
+ frames: frames_pain,
14855
+ endfunc: gekk_run_start
14856
+ };
14857
+ var frames_pain12 = Array(11).fill({ ai: monster_ai_move21, dist: 0 });
14858
+ frames_pain12[10] = { ai: monster_ai_move21, dist: 0, think: gekk_check_underwater };
14859
+ gekk_move_pain1 = {
14860
+ firstframe: 186,
14861
+ lastframe: 196,
14862
+ frames: frames_pain12,
14863
+ endfunc: gekk_run_start
14864
+ };
14865
+ var frames_pain22 = Array(13).fill({ ai: monster_ai_move21, dist: 0 });
14866
+ frames_pain22[12] = { ai: monster_ai_move21, dist: 0, think: gekk_check_underwater };
14867
+ gekk_move_pain2 = {
14868
+ firstframe: 197,
14869
+ lastframe: 209,
14870
+ frames: frames_pain22,
14871
+ endfunc: gekk_run_start
14872
+ };
14873
+ function gekk_pain(self, other, kick, damage, context) {
14874
+ if (self.spawnflags & SPAWNFLAG_GEKK_CHANT) {
14875
+ self.spawnflags &= ~SPAWNFLAG_GEKK_CHANT;
14876
+ return;
14877
+ }
14878
+ context.engine.sound?.(self, 0, "gek/gk_pain1.wav", 1, 1, 0);
14879
+ if (self.waterlevel >= WATER_WAIST) {
14880
+ if (!(self.flags & 2 /* Swim */)) {
14881
+ self.flags |= 2 /* Swim */;
14882
+ }
14883
+ self.monsterinfo.current_move = gekk_move_pain;
14884
+ } else {
14885
+ if (random8() > 0.5) self.monsterinfo.current_move = gekk_move_pain1;
14886
+ else self.monsterinfo.current_move = gekk_move_pain2;
14887
+ }
14888
+ }
14889
+ var frames_death12 = Array(10).fill({ ai: monster_ai_move21, dist: 0 });
14890
+ frames_death12[5] = { ai: monster_ai_move21, dist: -7, think: gekk_shrink };
14891
+ gekk_move_death1 = {
14892
+ firstframe: 210,
14893
+ lastframe: 219,
14894
+ frames: frames_death12,
14895
+ endfunc: gekk_dead
14896
+ };
14897
+ var frames_death3 = Array(7).fill({ ai: monster_ai_move21, dist: 0 });
14898
+ frames_death3[5] = { ai: monster_ai_move21, dist: -7, think: isgibfest };
14899
+ gekk_move_death3 = {
14900
+ firstframe: 220,
14901
+ lastframe: 226,
14902
+ frames: frames_death3,
14903
+ endfunc: gekk_dead
14904
+ };
14905
+ var frames_death4 = Array(35).fill({ ai: monster_ai_move21, dist: 0 });
14906
+ frames_death4[34] = { ai: monster_ai_move21, dist: 0, think: gekk_gibfest };
14907
+ gekk_move_death4 = {
14908
+ firstframe: 227,
14909
+ lastframe: 261,
14910
+ frames: frames_death4,
14911
+ endfunc: gekk_dead
14912
+ };
14913
+ var frames_wdeath = Array(45).fill({ ai: monster_ai_move21, dist: 0 });
14914
+ gekk_move_wdeath = {
14915
+ firstframe: 262,
14916
+ lastframe: 306,
14917
+ frames: frames_wdeath,
14918
+ endfunc: gekk_dead
14919
+ };
14920
+ function gekk_die(self, inflictor, attacker, damage, point, mod, context) {
14921
+ if (self.health <= GIB_HEALTH) {
14922
+ throwGibs(context, self.origin, damage);
14923
+ return;
14924
+ }
14925
+ if (self.deadflag === 2 /* Dead */) return;
14926
+ context.engine.sound?.(self, 0, "gek/gk_deth1.wav", 1, 1, 0);
14927
+ self.deadflag = 2 /* Dead */;
14928
+ self.takedamage = true;
14929
+ if (self.waterlevel >= WATER_WAIST) {
14930
+ gekk_shrink(self);
14931
+ self.monsterinfo.current_move = gekk_move_wdeath;
14932
+ } else {
14933
+ const r = frandom2();
14934
+ if (r > 0.66) self.monsterinfo.current_move = gekk_move_death1;
14935
+ else if (r > 0.33) self.monsterinfo.current_move = gekk_move_death3;
14936
+ else self.monsterinfo.current_move = gekk_move_death4;
14937
+ }
14938
+ }
14939
+ function SP_monster_gekk(self, context) {
14940
+ self.classname = "monster_gekk";
14941
+ self.model = "models/monsters/gekk/tris.md2";
14942
+ self.movetype = 5 /* Step */;
14943
+ self.solid = 2 /* BoundingBox */;
14944
+ self.mins = { x: -18, y: -18, z: -24 };
14945
+ self.maxs = { x: 18, y: 18, z: 24 };
14946
+ self.health = 125;
14947
+ self.max_health = 125;
14948
+ self.mass = 300;
14949
+ self.pain = (e, o, k, d) => gekk_pain(e, o, k, d, context.entities);
14950
+ self.die = (e, i, a, d, p, m3) => gekk_die(e, i, a, d, p, m3, context.entities);
14951
+ self.monsterinfo.stand = gekk_stand;
14952
+ self.monsterinfo.walk = (s) => M_SetAnimation2(s, gekk_move_walk);
14953
+ self.monsterinfo.run = gekk_run_start;
14954
+ self.monsterinfo.attack = (s) => gekk_attack(s, context.entities);
14955
+ self.monsterinfo.melee = gekk_melee;
14956
+ self.monsterinfo.sight = (s, o) => context.entities.sound?.(s, 0, "gek/gk_sght1.wav", 1, 1, 0);
14957
+ self.monsterinfo.search = (s) => gekk_search(s, context.entities);
14958
+ self.monsterinfo.idle = (s) => {
14959
+ if (s.spawnflags & SPAWNFLAG_GEKK_NOSWIM || s.waterlevel < WATER_WAIST) {
14960
+ M_SetAnimation2(s, gekk_move_idle);
14961
+ } else {
14962
+ M_SetAnimation2(s, gekk_move_swim_start);
14963
+ }
14964
+ };
14965
+ self.monsterinfo.checkattack = (s) => gekk_checkattack(s, context.entities);
14966
+ context.entities.linkentity(self);
14967
+ M_SetAnimation2(self, gekk_move_stand);
14968
+ self.think = monster_think;
14969
+ self.nextthink = context.entities.timeSeconds + MONSTER_TICK24;
14970
+ if (self.spawnflags & SPAWNFLAG_GEKK_CHANT) {
14971
+ M_SetAnimation2(self, gekk_move_chant);
14972
+ }
14973
+ }
14974
+ function M_SetAnimation2(self, move) {
14975
+ self.monsterinfo.current_move = move;
14976
+ }
14977
+ function gekk_attack(self, context) {
14978
+ if (!self.enemy) return;
14979
+ const r = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14980
+ if (self.flags & 2 /* Swim */) {
14981
+ if (self.enemy && self.enemy.waterlevel >= WATER_WAIST && r <= RANGE_NEAR2)
14982
+ return;
14983
+ self.flags &= ~2 /* Swim */;
14984
+ M_SetAnimation2(self, gekk_move_leapatk);
14985
+ self.frame = 144;
14986
+ } else {
14987
+ if (r >= RANGE_MID2) {
14988
+ if (frandom2() > 0.5) {
14989
+ M_SetAnimation2(self, gekk_move_spit);
14990
+ } else {
14991
+ M_SetAnimation2(self, gekk_move_run_start);
14992
+ }
14993
+ } else if (frandom2() > 0.7) {
14994
+ M_SetAnimation2(self, gekk_move_spit);
14995
+ } else {
14996
+ if (self.spawnflags & SPAWNFLAG_GEKK_NOJUMPING || frandom2() > 0.7) {
14997
+ M_SetAnimation2(self, gekk_move_run_start);
14998
+ } else {
14999
+ M_SetAnimation2(self, gekk_move_leapatk);
15000
+ }
15001
+ }
15002
+ }
15003
+ }
15004
+ function gekk_melee(self) {
15005
+ if (self.waterlevel >= WATER_WAIST) {
15006
+ M_SetAnimation2(self, gekk_move_attack);
15007
+ } else {
15008
+ if (frandom2() > 0.66) M_SetAnimation2(self, gekk_move_attack1);
15009
+ else M_SetAnimation2(self, gekk_move_attack2);
15010
+ }
15011
+ }
15012
+ function registerGekkSpawns(registry) {
15013
+ registry.register("monster_gekk", SP_monster_gekk);
15014
+ }
15015
+
15016
+ // src/entities/monsters/fixbot.ts
15017
+ var MONSTER_TICK25 = 0.1;
15018
+ var random9 = () => Math.random();
15019
+ var frandom3 = () => Math.random();
15020
+ function monster_ai_walk21(self, dist, context) {
15021
+ ai_walk(self, dist, MONSTER_TICK25, context);
15022
+ }
15023
+ function monster_ai_run22(self, dist, context) {
15024
+ ai_run(self, dist, MONSTER_TICK25, context);
15025
+ }
15026
+ function monster_ai_charge23(self, dist, context) {
15027
+ ai_charge(self, dist, MONSTER_TICK25, context);
15028
+ }
15029
+ function monster_ai_move22(self, dist, context) {
15030
+ ai_move(self, dist);
15031
+ }
15032
+ var fixbot_move_stand;
15033
+ var fixbot_move_walk;
15034
+ var fixbot_move_run;
15035
+ var fixbot_move_attack2;
15036
+ var fixbot_move_laserattack;
15037
+ var fixbot_move_weld_start;
15038
+ var fixbot_move_weld;
15039
+ var fixbot_move_weld_end;
15040
+ var fixbot_move_start_attack;
15041
+ var fixbot_move_pain3;
15042
+ var fixbot_move_painb;
15043
+ var fixbot_move_paina;
15044
+ var MZ2_HOVER_BLASTER_1 = 1;
15045
+ function fixbot_set_fly_parameters(self, heal, weld) {
15046
+ if (heal) {
15047
+ } else if (weld) {
15048
+ } else {
15049
+ }
15050
+ }
15051
+ function fixbot_FindDeadMonster(self, context) {
15052
+ const radius = 1024;
15053
+ const candidates = context.findByRadius(self.origin, radius);
15054
+ let best = null;
15055
+ for (const ent of candidates) {
15056
+ if (ent === self) continue;
15057
+ if (!ent.monsterinfo) continue;
15058
+ if (ent.monsterinfo.aiflags & 256 /* GoodGuy */) continue;
15059
+ if (ent.health > 0) continue;
15060
+ if (ent.nextthink && ent.think === context.free) continue;
15061
+ if (ent.health <= -40) continue;
15062
+ if (!visible(self, ent, context.trace)) continue;
15063
+ if (!best) {
15064
+ best = ent;
15065
+ continue;
15066
+ }
15067
+ if (ent.max_health <= best.max_health) continue;
15068
+ best = ent;
15069
+ }
15070
+ return best;
15071
+ }
15072
+ function fixbot_search(self, context) {
15073
+ if (self.enemy) return;
15074
+ const ent = fixbot_FindDeadMonster(self, context);
15075
+ if (ent) {
15076
+ self.enemy = ent;
15077
+ self.monsterinfo.aiflags |= 8192 /* Medic */;
15078
+ fixbot_run(self);
15079
+ fixbot_set_fly_parameters(self, true, false);
15080
+ } else {
15081
+ if (random9() < 0.1) {
15082
+ context.engine.sound?.(self, 0, "flyer/flysght1.wav", 1, 1, 0);
15083
+ }
15084
+ }
15085
+ }
15086
+ function fixbot_die(self, inflictor, attacker, damage, point, mod, context) {
15087
+ context.engine.sound?.(self, 0, "flyer/flydeth1.wav", 1, 1, 0);
15088
+ throwGibs(context, self.origin, damage);
15089
+ self.deadflag = 2 /* Dead */;
15090
+ self.takedamage = false;
15091
+ context.free(self);
15092
+ }
15093
+ function fixbot_fire_blaster_func(self, context) {
15094
+ if (!self.enemy || !self.enemy.inUse) {
15095
+ self.monsterinfo.current_move = fixbot_move_run;
15096
+ return;
15097
+ }
15098
+ const vectors = angleVectors(self.angles);
15099
+ const start = addVec3(self.origin, addVec3(scaleVec3(vectors.forward, 0), addVec3(scaleVec3(vectors.right, 0), scaleVec3(vectors.up, 0))));
15100
+ const end = copyVec3(self.enemy.origin);
15101
+ end.z += self.enemy.viewheight || 0;
15102
+ const dir = normalizeVec3(subtractVec3(end, start));
15103
+ monster_fire_blaster(self, start, dir, 15, 1e3, MZ2_HOVER_BLASTER_1, 0, context);
15104
+ }
15105
+ function fixbot_fire_laser(self, context) {
15106
+ if (!self.enemy || !self.enemy.inUse || self.enemy.health <= -40) {
15107
+ self.monsterinfo.current_move = fixbot_move_stand;
15108
+ self.monsterinfo.aiflags &= ~8192 /* Medic */;
15109
+ return;
15110
+ }
15111
+ if (self.enemy.health < self.enemy.max_health) {
15112
+ self.enemy.health += 5;
15113
+ if (self.enemy.health > self.enemy.max_health) self.enemy.health = self.enemy.max_health;
15114
+ } else {
15115
+ if (self.enemy.deadflag === 2 /* Dead */) {
15116
+ self.enemy.deadflag = 0 /* Alive */;
15117
+ self.enemy.solid = 2 /* BoundingBox */;
15118
+ self.enemy.takedamage = true;
15119
+ self.enemy.health = self.enemy.max_health;
15120
+ self.enemy.monsterinfo.aiflags &= ~128 /* HoldFrame */;
15121
+ }
15122
+ self.monsterinfo.current_move = fixbot_move_stand;
15123
+ self.monsterinfo.aiflags &= ~8192 /* Medic */;
15124
+ self.enemy = null;
15125
+ }
15126
+ }
15127
+ function fixbot_fire_welder(self, context) {
15128
+ if (frandom3() > 0.8) {
15129
+ const r = frandom3();
15130
+ if (r < 0.33) context.engine.sound?.(self, 0, "misc/welder1.wav", 1, 1, 0);
15131
+ else if (r < 0.66) context.engine.sound?.(self, 0, "misc/welder2.wav", 1, 1, 0);
15132
+ else context.engine.sound?.(self, 0, "misc/welder3.wav", 1, 1, 0);
15133
+ }
15134
+ }
15135
+ function fixbot_pain(self, other, kick, damage, context) {
15136
+ if (self.timestamp < (self.pain_debounce_time || 0)) return;
15137
+ self.pain_debounce_time = self.timestamp + 3;
15138
+ context.engine.sound?.(self, 0, "flyer/flypain1.wav", 1, 1, 0);
15139
+ if (damage <= 10) self.monsterinfo.current_move = fixbot_move_pain3;
15140
+ else if (damage <= 25) self.monsterinfo.current_move = fixbot_move_painb;
15141
+ else self.monsterinfo.current_move = fixbot_move_paina;
15142
+ }
15143
+ function fixbot_stand(self) {
15144
+ self.monsterinfo.current_move = fixbot_move_stand;
15145
+ }
15146
+ function fixbot_walk(self) {
15147
+ self.monsterinfo.current_move = fixbot_move_walk;
15148
+ }
15149
+ function fixbot_run(self) {
15150
+ if (self.monsterinfo.aiflags & 1 /* StandGround */)
15151
+ self.monsterinfo.current_move = fixbot_move_stand;
15152
+ else
15153
+ self.monsterinfo.current_move = fixbot_move_run;
15154
+ }
15155
+ function fixbot_start_attack(self) {
15156
+ self.monsterinfo.current_move = fixbot_move_start_attack;
15157
+ }
15158
+ function fixbot_attack(self) {
15159
+ if (self.monsterinfo.aiflags & 8192 /* Medic */) {
15160
+ self.monsterinfo.current_move = fixbot_move_laserattack;
15161
+ } else {
15162
+ self.monsterinfo.current_move = fixbot_move_attack2;
15163
+ }
15164
+ }
15165
+ function weldstate(self) {
15166
+ if (self.goalentity && self.goalentity.health > 0) {
15167
+ } else {
15168
+ self.monsterinfo.current_move = fixbot_move_stand;
15169
+ }
15170
+ }
15171
+ var frames_stand3 = Array(19).fill({ ai: monster_ai_move22, dist: 0 });
15172
+ frames_stand3[18] = { ai: monster_ai_move22, dist: 0, think: fixbot_search };
15173
+ fixbot_move_stand = {
15174
+ firstframe: 58,
15175
+ // FRAME_ambient_01
15176
+ lastframe: 76,
15177
+ frames: frames_stand3,
15178
+ endfunc: null
15179
+ };
15180
+ var frames_walk3 = [
15181
+ { ai: monster_ai_walk21, dist: 5 }
15182
+ ];
15183
+ fixbot_move_walk = {
15184
+ firstframe: 0,
15185
+ lastframe: 0,
15186
+ frames: frames_walk3,
15187
+ endfunc: null
15188
+ };
15189
+ var frames_run3 = [
15190
+ { ai: monster_ai_run22, dist: 10 }
15191
+ ];
15192
+ fixbot_move_run = {
15193
+ firstframe: 0,
15194
+ lastframe: 0,
15195
+ frames: frames_run3,
15196
+ endfunc: null
15197
+ };
15198
+ var frames_attack22 = Array(31).fill({ ai: monster_ai_charge23, dist: 0 });
15199
+ frames_attack22[20] = { ai: monster_ai_charge23, dist: 0, think: fixbot_fire_blaster_func };
15200
+ fixbot_move_attack2 = {
15201
+ firstframe: 121,
15202
+ // FRAME_charging_01
15203
+ lastframe: 151,
15204
+ frames: frames_attack22,
15205
+ endfunc: fixbot_run
15206
+ };
15207
+ var frames_laserattack = Array(6).fill({ ai: monster_ai_charge23, dist: 0, think: fixbot_fire_laser });
15208
+ fixbot_move_laserattack = {
15209
+ firstframe: 115,
15210
+ // FRAME_shoot_01
15211
+ lastframe: 120,
15212
+ frames: frames_laserattack,
15213
+ endfunc: null
15214
+ // Loops or handled by AI?
15215
+ };
15216
+ var frames_weld_start = Array(10).fill({ ai: monster_ai_move22, dist: 0 });
15217
+ frames_weld_start[9] = { ai: monster_ai_move22, dist: 0, think: weldstate };
15218
+ fixbot_move_weld_start = {
15219
+ firstframe: 77,
15220
+ // FRAME_weldstart_01
15221
+ lastframe: 86,
15222
+ frames: frames_weld_start,
15223
+ endfunc: null
15224
+ };
15225
+ var frames_weld = Array(7).fill({ ai: monster_ai_move22, dist: 0, think: fixbot_fire_welder });
15226
+ frames_weld[6] = { ai: monster_ai_move22, dist: 0, think: weldstate };
15227
+ fixbot_move_weld = {
15228
+ firstframe: 87,
15229
+ // FRAME_weldmiddle_01
15230
+ lastframe: 93,
15231
+ frames: frames_weld,
15232
+ endfunc: null
15233
+ };
15234
+ var frames_weld_end = Array(7).fill({ ai: monster_ai_move22, dist: -2 });
15235
+ frames_weld_end[6] = { ai: monster_ai_move22, dist: -2, think: weldstate };
15236
+ fixbot_move_weld_end = {
15237
+ firstframe: 94,
15238
+ // FRAME_weldend_01
15239
+ lastframe: 100,
15240
+ frames: frames_weld_end,
15241
+ endfunc: null
15242
+ };
15243
+ var frames_start_attack = [
15244
+ { ai: monster_ai_charge23, dist: 0 }
15245
+ ];
15246
+ fixbot_move_start_attack = {
15247
+ firstframe: 0,
15248
+ lastframe: 0,
15249
+ frames: frames_start_attack,
15250
+ endfunc: fixbot_attack
15251
+ };
15252
+ var frames_pain32 = [
15253
+ { ai: monster_ai_move22, dist: -1 }
15254
+ ];
15255
+ fixbot_move_pain3 = {
15256
+ firstframe: 0,
15257
+ lastframe: 0,
15258
+ frames: frames_pain32,
15259
+ endfunc: fixbot_run
15260
+ };
15261
+ var frames_painb = Array(8).fill({ ai: monster_ai_move22, dist: 0 });
15262
+ fixbot_move_painb = {
15263
+ firstframe: 107,
15264
+ // FRAME_painb_01
15265
+ lastframe: 114,
15266
+ frames: frames_painb,
15267
+ endfunc: fixbot_run
15268
+ };
15269
+ var frames_paina = Array(6).fill({ ai: monster_ai_move22, dist: 0 });
15270
+ fixbot_move_paina = {
15271
+ firstframe: 101,
15272
+ // FRAME_paina_01
15273
+ lastframe: 106,
15274
+ frames: frames_paina,
15275
+ endfunc: fixbot_run
15276
+ };
15277
+ function SP_monster_fixbot(self, context) {
15278
+ self.classname = "monster_fixbot";
15279
+ self.model = "models/monsters/fixbot/tris.md2";
15280
+ self.mins = { x: -32, y: -32, z: -24 };
15281
+ self.maxs = { x: 32, y: 32, z: 24 };
15282
+ self.movetype = 5 /* Step */;
15283
+ self.solid = 2 /* BoundingBox */;
15284
+ self.health = 150;
15285
+ self.mass = 150;
15286
+ self.pain = (e, o, k, d) => fixbot_pain(e, o, k, d, context.entities);
15287
+ self.die = (e, i, a, d, p, m3) => fixbot_die(e, i, a, d, p, m3, context.entities);
15288
+ self.monsterinfo.stand = fixbot_stand;
15289
+ self.monsterinfo.walk = fixbot_walk;
15290
+ self.monsterinfo.run = fixbot_run;
15291
+ self.monsterinfo.attack = fixbot_start_attack;
15292
+ context.entities.linkentity(self);
15293
+ self.monsterinfo.current_move = fixbot_move_stand;
15294
+ self.think = monster_think;
15295
+ self.nextthink = context.entities.timeSeconds + MONSTER_TICK25;
15296
+ self.flags |= 1 /* Fly */;
15297
+ }
15298
+ function registerFixbotSpawns(registry) {
15299
+ registry.register("monster_fixbot", SP_monster_fixbot);
15300
+ }
15301
+
14247
15302
  // src/entities/monsters/index.ts
14248
15303
  function registerMonsterSpawns2(registry) {
14249
15304
  registerMonsterSpawns(registry);
@@ -14270,6 +15325,8 @@ function registerMonsterSpawns2(registry) {
14270
15325
  registerMakronSpawns(registry);
14271
15326
  registerInsaneSpawns(registry);
14272
15327
  registerActorSpawns(registry);
15328
+ registerGekkSpawns(registry);
15329
+ registerFixbotSpawns(registry);
14273
15330
  }
14274
15331
 
14275
15332
  // src/entities/worldspawn.ts
@@ -15580,7 +16637,7 @@ function PlayerNoise(who, where, type, context) {
15580
16637
  }
15581
16638
 
15582
16639
  // src/combat/obituary.ts
15583
- var random8 = createRandomGenerator();
16640
+ var random10 = createRandomGenerator();
15584
16641
  var PRINT_MEDIUM = 1;
15585
16642
  function getGender(ent) {
15586
16643
  return "male";
@@ -15743,7 +16800,7 @@ var ANIM_PAIN = 2;
15743
16800
  var ANIM_DEATH = 3;
15744
16801
 
15745
16802
  // src/combat/weapons/firing.ts
15746
- var random9 = createRandomGenerator();
16803
+ var random11 = createRandomGenerator();
15747
16804
 
15748
16805
  // src/entities/player.ts
15749
16806
  function P_PlayerThink(ent, sys) {
@@ -15800,7 +16857,7 @@ function player_pain(self, damage) {
15800
16857
  return;
15801
16858
  }
15802
16859
  self.client.anim_priority = ANIM_PAIN;
15803
- const r = random9.frandom();
16860
+ const r = random11.frandom();
15804
16861
  if (r < 0.33) {
15805
16862
  self.frame = FRAME_pain1012;
15806
16863
  self.client.anim_end = FRAME_pain104;
@@ -15823,7 +16880,7 @@ function player_die(self, inflictor, attacker, damage, point, mod, sys) {
15823
16880
  }
15824
16881
  if (self.client) {
15825
16882
  self.client.anim_priority = ANIM_DEATH;
15826
- const r = random9.frandom();
16883
+ const r = random11.frandom();
15827
16884
  if (r < 0.33) {
15828
16885
  self.frame = FRAME_death1012;
15829
16886
  self.client.anim_end = FRAME_death106;
@@ -15876,25 +16933,12 @@ function player_think(self, sys) {
15876
16933
  }
15877
16934
 
15878
16935
  // src/entities/playerStats.ts
15879
- var WEAPON_WHEEL_ORDER = [
15880
- "blaster" /* Blaster */,
15881
- "shotgun" /* Shotgun */,
15882
- "supershotgun" /* SuperShotgun */,
15883
- "machinegun" /* Machinegun */,
15884
- "chaingun" /* Chaingun */,
15885
- "grenadelauncher" /* GrenadeLauncher */,
15886
- "rocketlauncher" /* RocketLauncher */,
15887
- "grenades" /* HandGrenade */,
15888
- "hyperblaster" /* HyperBlaster */,
15889
- "railgun" /* Railgun */,
15890
- "bfg10k" /* BFG10K */
15891
- ];
15892
16936
  var POWERUP_TIMERS = [
15893
- { id: "quad" /* QuadDamage */, priority: 1 },
15894
- { id: "invulnerability" /* Invulnerability */, priority: 2 },
15895
- { id: "enviro" /* EnviroSuit */, priority: 3 },
15896
- { id: "rebreather" /* Rebreather */, priority: 4 },
15897
- { id: "silencer" /* Silencer */, priority: 5 }
16937
+ { id: PowerupId.QuadDamage, priority: 1 },
16938
+ { id: PowerupId.Invulnerability, priority: 2 },
16939
+ { id: PowerupId.EnviroSuit, priority: 3 },
16940
+ { id: PowerupId.Rebreather, priority: 4 },
16941
+ { id: PowerupId.Silencer, priority: 5 }
15898
16942
  ];
15899
16943
  function populatePlayerStats(player, timeSeconds) {
15900
16944
  if (!player.client) return [];
@@ -15913,6 +16957,12 @@ function populatePlayerStats(player, timeSeconds) {
15913
16957
  }
15914
16958
  statArray[PlayerStat.STAT_WEAPONS_OWNED_1] = weaponBits & 65535;
15915
16959
  statArray[PlayerStat.STAT_WEAPONS_OWNED_2] = weaponBits >> 16 & 65535;
16960
+ if (inventory.currentWeapon) {
16961
+ const index = WEAPON_WHEEL_ORDER.indexOf(inventory.currentWeapon);
16962
+ if (index !== -1) {
16963
+ statArray[PlayerStat.STAT_ACTIVE_WHEEL_WEAPON] = index;
16964
+ }
16965
+ }
15916
16966
  statArray[PlayerStat.STAT_AMMO] = 0;
15917
16967
  if (inventory.currentWeapon) {
15918
16968
  const weaponItem = Object.values(WEAPON_ITEMS).find((item) => item.weaponId === inventory.currentWeapon);
@@ -16217,7 +17267,7 @@ var WEAPONS = {
16217
17267
  };
16218
17268
 
16219
17269
  // src/index.ts
16220
- var ZERO_VEC36 = { x: 0, y: 0, z: 0 };
17270
+ var ZERO_VEC37 = { x: 0, y: 0, z: 0 };
16221
17271
  function createGame(imports, engine, options) {
16222
17272
  const gravity = options.gravity;
16223
17273
  const deathmatch = options.deathmatch ?? false;
@@ -16286,26 +17336,26 @@ function createGame(imports, engine, options) {
16286
17336
  };
16287
17337
  entities.runFrame();
16288
17338
  });
16289
- let origin = { ...ZERO_VEC36 };
16290
- let velocity = { ...ZERO_VEC36 };
17339
+ let origin = { ...ZERO_VEC37 };
17340
+ let velocity = { ...ZERO_VEC37 };
16291
17341
  const calculateBlend = (player, time) => {
16292
17342
  const blend = [0, 0, 0, 0];
16293
17343
  if (!player || !player.client) return blend;
16294
17344
  const inventory = player.client.inventory;
16295
- if (inventory.powerups.has("quad" /* QuadDamage */)) {
17345
+ if (inventory.powerups.has(PowerupId.QuadDamage)) {
16296
17346
  blend[2] = 1;
16297
17347
  blend[3] = 0.08;
16298
17348
  }
16299
- if (inventory.powerups.has("invulnerability" /* Invulnerability */)) {
17349
+ if (inventory.powerups.has(PowerupId.Invulnerability)) {
16300
17350
  blend[0] = 1;
16301
17351
  blend[1] = 1;
16302
17352
  blend[3] = 0.08;
16303
17353
  }
16304
- if (inventory.powerups.has("enviro" /* EnviroSuit */)) {
17354
+ if (inventory.powerups.has(PowerupId.EnviroSuit)) {
16305
17355
  blend[1] = 1;
16306
17356
  blend[3] = 0.08;
16307
17357
  }
16308
- if (inventory.powerups.has("rebreather" /* Rebreather */)) {
17358
+ if (inventory.powerups.has(PowerupId.Rebreather)) {
16309
17359
  blend[0] = 0.4;
16310
17360
  blend[1] = 1;
16311
17361
  blend[2] = 0.4;
@@ -16369,10 +17419,10 @@ function createGame(imports, engine, options) {
16369
17419
  // TODO
16370
17420
  damageIndicators: [],
16371
17421
  stats: player ? populatePlayerStats(player, levelClock.current.timeSeconds) : [],
16372
- kick_angles: player?.client?.kick_angles ?? ZERO_VEC36,
16373
- kick_origin: player?.client?.kick_origin ?? ZERO_VEC36,
16374
- gunoffset: ZERO_VEC36,
16375
- gunangles: ZERO_VEC36,
17422
+ kick_angles: player?.client?.kick_angles ?? ZERO_VEC37,
17423
+ kick_origin: player?.client?.kick_origin ?? ZERO_VEC37,
17424
+ gunoffset: ZERO_VEC37,
17425
+ gunangles: ZERO_VEC37,
16376
17426
  gunindex: 0,
16377
17427
  gun_frame: player?.client?.gun_frame ?? 0,
16378
17428
  rdflags: player?.client?.rdflags ?? 0,
@@ -16386,8 +17436,8 @@ function createGame(imports, engine, options) {
16386
17436
  const resetState = (startTimeMs) => {
16387
17437
  frameLoop.reset(startTimeMs);
16388
17438
  levelClock.start(startTimeMs);
16389
- origin = { ...ZERO_VEC36 };
16390
- velocity = { ...ZERO_VEC36 };
17439
+ origin = { ...ZERO_VEC37 };
17440
+ velocity = { ...ZERO_VEC37 };
16391
17441
  entities.beginFrame(startTimeMs / 1e3);
16392
17442
  entities.runFrame();
16393
17443
  };
@@ -16415,10 +17465,10 @@ function createGame(imports, engine, options) {
16415
17465
  blend: [0, 0, 0, 0],
16416
17466
  // Stubs
16417
17467
  stats: populatePlayerStats(player, levelClock.current.timeSeconds),
16418
- kick_angles: ZERO_VEC36,
16419
- kick_origin: ZERO_VEC36,
16420
- gunoffset: ZERO_VEC36,
16421
- gunangles: ZERO_VEC36,
17468
+ kick_angles: ZERO_VEC37,
17469
+ kick_origin: ZERO_VEC37,
17470
+ gunoffset: ZERO_VEC37,
17471
+ gunangles: ZERO_VEC37,
16422
17472
  gunindex: 0,
16423
17473
  pm_type: 0,
16424
17474
  pm_time: 0,
@@ -16548,8 +17598,8 @@ function createGame(imports, engine, options) {
16548
17598
  rng,
16549
17599
  player: player?.client?.inventory
16550
17600
  });
16551
- origin = player ? { ...player.origin } : { ...ZERO_VEC36 };
16552
- velocity = player ? { ...player.velocity } : { ...ZERO_VEC36 };
17601
+ origin = player ? { ...player.origin } : { ...ZERO_VEC37 };
17602
+ velocity = player ? { ...player.velocity } : { ...ZERO_VEC37 };
16553
17603
  frameLoop.reset(save.level.timeSeconds * 1e3);
16554
17604
  }
16555
17605
  };