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
@@ -767,6 +767,33 @@ function setCompressedInteger(stats, startIndex, id, count, bitsPerValue) {
767
767
  const valueToWrite = base & ~mask | count << bitShift & mask;
768
768
  writeUint16LE(stats, startIndex, byteOffset, valueToWrite & 65535);
769
769
  }
770
+ var PowerupId = /* @__PURE__ */ ((PowerupId22) => {
771
+ PowerupId22["QuadDamage"] = "quad";
772
+ PowerupId22["Invulnerability"] = "invulnerability";
773
+ PowerupId22["EnviroSuit"] = "enviro_suit";
774
+ PowerupId22["Rebreather"] = "rebreather";
775
+ PowerupId22["Silencer"] = "silencer";
776
+ PowerupId22["PowerScreen"] = "power_screen";
777
+ PowerupId22["PowerShield"] = "power_shield";
778
+ PowerupId22["QuadFire"] = "quad_fire";
779
+ PowerupId22["Invisibility"] = "invisibility";
780
+ PowerupId22["Bandolier"] = "bandolier";
781
+ PowerupId22["AmmoPack"] = "ammo_pack";
782
+ PowerupId22["IRGoggles"] = "ir_goggles";
783
+ PowerupId22["DoubleDamage"] = "double_damage";
784
+ PowerupId22["SphereVengeance"] = "sphere_vengeance";
785
+ PowerupId22["SphereHunter"] = "sphere_hunter";
786
+ PowerupId22["SphereDefender"] = "sphere_defender";
787
+ PowerupId22["Doppelganger"] = "doppelganger";
788
+ PowerupId22["TagToken"] = "tag_token";
789
+ PowerupId22["TechResistance"] = "tech_resistance";
790
+ PowerupId22["TechStrength"] = "tech_strength";
791
+ PowerupId22["TechHaste"] = "tech_haste";
792
+ PowerupId22["TechRegeneration"] = "tech_regeneration";
793
+ PowerupId22["Flashlight"] = "flashlight";
794
+ PowerupId22["Compass"] = "compass";
795
+ return PowerupId22;
796
+ })(PowerupId || {});
770
797
  var PlayerStat = /* @__PURE__ */ ((PlayerStat2) => {
771
798
  PlayerStat2[PlayerStat2["STAT_HEALTH_ICON"] = 0] = "STAT_HEALTH_ICON";
772
799
  PlayerStat2[PlayerStat2["STAT_HEALTH"] = 1] = "STAT_HEALTH";
@@ -1081,6 +1108,29 @@ var applyPmove = (state, cmd, trace, pointContents2) => {
1081
1108
  velocity: finalVelocity
1082
1109
  };
1083
1110
  };
1111
+ var WeaponId = /* @__PURE__ */ ((WeaponId22) => {
1112
+ WeaponId22["Blaster"] = "blaster";
1113
+ WeaponId22["Shotgun"] = "shotgun";
1114
+ WeaponId22["SuperShotgun"] = "supershotgun";
1115
+ WeaponId22["Machinegun"] = "machinegun";
1116
+ WeaponId22["Chaingun"] = "chaingun";
1117
+ WeaponId22["HandGrenade"] = "grenades";
1118
+ WeaponId22["GrenadeLauncher"] = "grenadelauncher";
1119
+ WeaponId22["RocketLauncher"] = "rocketlauncher";
1120
+ WeaponId22["HyperBlaster"] = "hyperblaster";
1121
+ WeaponId22["Railgun"] = "railgun";
1122
+ WeaponId22["BFG10K"] = "bfg10k";
1123
+ WeaponId22["Grapple"] = "grapple";
1124
+ WeaponId22["ChainFist"] = "chainfist";
1125
+ WeaponId22["EtfRifle"] = "etf_rifle";
1126
+ WeaponId22["ProxLauncher"] = "prox_launcher";
1127
+ WeaponId22["IonRipper"] = "ionripper";
1128
+ WeaponId22["PlasmaBeam"] = "plasmabeam";
1129
+ WeaponId22["Phalanx"] = "phalanx";
1130
+ WeaponId22["Disruptor"] = "disruptor";
1131
+ WeaponId22["Trap"] = "trap";
1132
+ return WeaponId22;
1133
+ })(WeaponId || {});
1084
1134
  var AmmoType = /* @__PURE__ */ ((AmmoType22) => {
1085
1135
  AmmoType22[AmmoType22["Bullets"] = 0] = "Bullets";
1086
1136
  AmmoType22[AmmoType22["Shells"] = 1] = "Shells";
@@ -1114,6 +1164,20 @@ var AmmoItemId = /* @__PURE__ */ ((AmmoItemId22) => {
1114
1164
  AmmoItemId22["Prox"] = "ammo_prox";
1115
1165
  return AmmoItemId22;
1116
1166
  })(AmmoItemId || {});
1167
+ var WEAPON_WHEEL_ORDER = [
1168
+ "blaster",
1169
+ "shotgun",
1170
+ "supershotgun",
1171
+ "machinegun",
1172
+ "chaingun",
1173
+ "grenadelauncher",
1174
+ "rocketlauncher",
1175
+ "grenades",
1176
+ "hyperblaster",
1177
+ "railgun",
1178
+ "bfg10k"
1179
+ /* BFG10K */
1180
+ ];
1117
1181
 
1118
1182
  // src/inventory/ammo.ts
1119
1183
  var AMMO_ITEM_DEFINITIONS = {
@@ -1296,54 +1360,6 @@ function applyPowerArmor(damage, flags, hitPoint, _hitNormal, state, options = {
1296
1360
  }
1297
1361
 
1298
1362
  // src/inventory/playerInventory.ts
1299
- var WeaponId = /* @__PURE__ */ ((WeaponId3) => {
1300
- WeaponId3["Blaster"] = "blaster";
1301
- WeaponId3["Shotgun"] = "shotgun";
1302
- WeaponId3["SuperShotgun"] = "supershotgun";
1303
- WeaponId3["Machinegun"] = "machinegun";
1304
- WeaponId3["Chaingun"] = "chaingun";
1305
- WeaponId3["GrenadeLauncher"] = "grenadelauncher";
1306
- WeaponId3["RocketLauncher"] = "rocketlauncher";
1307
- WeaponId3["HyperBlaster"] = "hyperblaster";
1308
- WeaponId3["Railgun"] = "railgun";
1309
- WeaponId3["BFG10K"] = "bfg10k";
1310
- WeaponId3["HandGrenade"] = "grenades";
1311
- WeaponId3["Grapple"] = "grapple";
1312
- WeaponId3["IonRipper"] = "ionripper";
1313
- WeaponId3["Phalanx"] = "phalanx";
1314
- WeaponId3["Trap"] = "trap";
1315
- WeaponId3["PlasmaBeam"] = "plasmabeam";
1316
- WeaponId3["EtfRifle"] = "etfrifle";
1317
- WeaponId3["ProxLauncher"] = "proxlauncher";
1318
- WeaponId3["ChainFist"] = "chainfist";
1319
- WeaponId3["Disruptor"] = "disruptor";
1320
- return WeaponId3;
1321
- })(WeaponId || {});
1322
- var PowerupId = /* @__PURE__ */ ((PowerupId3) => {
1323
- PowerupId3["QuadDamage"] = "quad";
1324
- PowerupId3["Invulnerability"] = "invulnerability";
1325
- PowerupId3["Silencer"] = "silencer";
1326
- PowerupId3["Rebreather"] = "rebreather";
1327
- PowerupId3["EnviroSuit"] = "enviro";
1328
- PowerupId3["DoubleDamage"] = "double";
1329
- PowerupId3["QuadFire"] = "quadfire";
1330
- PowerupId3["Invisibility"] = "invisibility";
1331
- PowerupId3["Bandolier"] = "bandolier";
1332
- PowerupId3["AmmoPack"] = "pack";
1333
- PowerupId3["IRGoggles"] = "goggles";
1334
- PowerupId3["SphereVengeance"] = "vengeance";
1335
- PowerupId3["SphereHunter"] = "hunter";
1336
- PowerupId3["SphereDefender"] = "defender";
1337
- PowerupId3["Doppelganger"] = "doppelganger";
1338
- PowerupId3["TagToken"] = "tagtoken";
1339
- PowerupId3["TechResistance"] = "tech_resistance";
1340
- PowerupId3["TechStrength"] = "tech_strength";
1341
- PowerupId3["TechHaste"] = "tech_haste";
1342
- PowerupId3["TechRegeneration"] = "tech_regeneration";
1343
- PowerupId3["Flashlight"] = "flashlight";
1344
- PowerupId3["Compass"] = "compass";
1345
- return PowerupId3;
1346
- })(PowerupId || {});
1347
1363
  var KeyId = /* @__PURE__ */ ((KeyId2) => {
1348
1364
  KeyId2["Blue"] = "key_blue";
1349
1365
  KeyId2["Red"] = "key_red";
@@ -1368,7 +1384,7 @@ function createPlayerInventory(init = {}) {
1368
1384
  const ammoCaps = init.ammoCaps;
1369
1385
  const inv = {
1370
1386
  ammo: createAmmoInventory(ammoCaps),
1371
- ownedWeapons: new Set(init.weapons ?? ["blaster" /* Blaster */]),
1387
+ ownedWeapons: new Set(init.weapons ?? [WeaponId.Blaster]),
1372
1388
  armor: null,
1373
1389
  powerups: /* @__PURE__ */ new Map(),
1374
1390
  keys: /* @__PURE__ */ new Set(),
@@ -1382,8 +1398,8 @@ function createPlayerInventory(init = {}) {
1382
1398
  if (init.currentWeapon) {
1383
1399
  inv.currentWeapon = init.currentWeapon;
1384
1400
  } else if (inv.ownedWeapons.size > 0) {
1385
- if (inv.ownedWeapons.has("blaster" /* Blaster */)) inv.currentWeapon = "blaster" /* Blaster */;
1386
- else if (inv.ownedWeapons.has("shotgun" /* Shotgun */)) inv.currentWeapon = "shotgun" /* Shotgun */;
1401
+ if (inv.ownedWeapons.has(WeaponId.Blaster)) inv.currentWeapon = WeaponId.Blaster;
1402
+ else if (inv.ownedWeapons.has(WeaponId.Shotgun)) inv.currentWeapon = WeaponId.Shotgun;
1387
1403
  else inv.currentWeapon = [...inv.ownedWeapons][0];
1388
1404
  }
1389
1405
  return inv;
@@ -1512,27 +1528,27 @@ function pickupPowerup(client, item, time) {
1512
1528
  let icon = "";
1513
1529
  switch (item.id) {
1514
1530
  case "item_quad":
1515
- powerupId = "quad" /* QuadDamage */;
1531
+ powerupId = PowerupId.QuadDamage;
1516
1532
  icon = "p_quad";
1517
1533
  break;
1518
1534
  case "item_invulnerability":
1519
- powerupId = "invulnerability" /* Invulnerability */;
1535
+ powerupId = PowerupId.Invulnerability;
1520
1536
  icon = "p_invulnerability";
1521
1537
  break;
1522
1538
  case "item_silencer":
1523
- powerupId = "silencer" /* Silencer */;
1539
+ powerupId = PowerupId.Silencer;
1524
1540
  icon = "p_silencer";
1525
1541
  break;
1526
1542
  case "item_rebreather":
1527
- powerupId = "rebreather" /* Rebreather */;
1543
+ powerupId = PowerupId.Rebreather;
1528
1544
  icon = "p_rebreather";
1529
1545
  break;
1530
1546
  case "item_enviro":
1531
- powerupId = "enviro" /* EnviroSuit */;
1547
+ powerupId = PowerupId.EnviroSuit;
1532
1548
  icon = "p_envirosuit";
1533
1549
  break;
1534
1550
  case "item_double":
1535
- powerupId = "double" /* DoubleDamage */;
1551
+ powerupId = PowerupId.DoubleDamage;
1536
1552
  icon = "p_double";
1537
1553
  break;
1538
1554
  }
@@ -1540,9 +1556,9 @@ function pickupPowerup(client, item, time) {
1540
1556
  const expiresAt = inventory.powerups.get(powerupId);
1541
1557
  const newExpiresAt = expiresAt && expiresAt > time ? expiresAt + item.timer * 1e3 : time + item.timer * 1e3;
1542
1558
  inventory.powerups.set(powerupId, newExpiresAt);
1543
- if (powerupId === "quad" /* QuadDamage */) {
1559
+ if (powerupId === PowerupId.QuadDamage) {
1544
1560
  client.quad_time = newExpiresAt / 1e3;
1545
- } else if (powerupId === "double" /* DoubleDamage */) {
1561
+ } else if (powerupId === PowerupId.DoubleDamage) {
1546
1562
  client.double_time = newExpiresAt / 1e3;
1547
1563
  }
1548
1564
  setPickup(inventory, icon, time);
@@ -1750,6 +1766,8 @@ var Entity = class {
1750
1766
  this.attenuation = 0;
1751
1767
  this.volume = 0;
1752
1768
  this.fly_sound_debounce_time = 0;
1769
+ this.last_move_time = 0;
1770
+ this.damage_debounce_time = 0;
1753
1771
  this.enemy = null;
1754
1772
  this.movetarget = null;
1755
1773
  this.target_ent = null;
@@ -1889,6 +1907,8 @@ var Entity = class {
1889
1907
  this.sounds = 0;
1890
1908
  this.noise_index = 0;
1891
1909
  this.fly_sound_debounce_time = 0;
1910
+ this.last_move_time = 0;
1911
+ this.damage_debounce_time = 0;
1892
1912
  this.enemy = null;
1893
1913
  this.movetarget = null;
1894
1914
  this.target_ent = null;
@@ -1984,6 +2004,8 @@ var ENTITY_FIELD_METADATA = [
1984
2004
  { name: "attenuation", type: "float", save: true },
1985
2005
  { name: "volume", type: "float", save: true },
1986
2006
  { name: "fly_sound_debounce_time", type: "float", save: true },
2007
+ { name: "last_move_time", type: "float", save: true },
2008
+ { name: "damage_debounce_time", type: "float", save: true },
1987
2009
  { name: "enemy", type: "entity", save: true },
1988
2010
  { name: "movetarget", type: "entity", save: true },
1989
2011
  { name: "target_ent", type: "entity", save: true },
@@ -3222,7 +3244,9 @@ var EntitySystem = class {
3222
3244
  }
3223
3245
  forEachEntity(callback) {
3224
3246
  for (const entity of this.pool) {
3225
- callback(entity);
3247
+ if (entity.inUse && !entity.freePending) {
3248
+ callback(entity);
3249
+ }
3226
3250
  }
3227
3251
  }
3228
3252
  find(predicate) {
@@ -4373,6 +4397,7 @@ function createBfgBall(sys, owner, start, dir, damage, speed, damageRadius) {
4373
4397
  }
4374
4398
 
4375
4399
  // src/entities/targets.ts
4400
+ var ATTN_NONE = 0;
4376
4401
  var ATTN_NORM = 1;
4377
4402
  var SPEAKER_SPAWNFLAGS = {
4378
4403
  LoopedOn: 1 << 0,
@@ -4465,6 +4490,88 @@ function useTargetBlaster(self, other, activator, context) {
4465
4490
  }
4466
4491
  context.entities.sound(self, 2, "weapons/laser2.wav", 1, ATTN_NORM, 0);
4467
4492
  }
4493
+ var SPAWNFLAG_EARTHQUAKE_SILENT = 1;
4494
+ var SPAWNFLAG_EARTHQUAKE_TOGGLE = 2;
4495
+ var SPAWNFLAG_EARTHQUAKE_ONE_SHOT = 8;
4496
+ function target_earthquake_think(self, context) {
4497
+ if (!(self.spawnflags & SPAWNFLAG_EARTHQUAKE_SILENT)) {
4498
+ if (self.last_move_time < context.entities.timeSeconds) {
4499
+ context.entities.sound(self, 2, "world/quake.wav", 1, ATTN_NONE, 0);
4500
+ self.last_move_time = context.entities.timeSeconds + 0.5;
4501
+ }
4502
+ }
4503
+ context.entities.forEachEntity((ent) => {
4504
+ if (!ent.client) return;
4505
+ ent.client.quake_time = context.entities.timeSeconds + 0.2;
4506
+ });
4507
+ if (context.entities.timeSeconds < self.timestamp) {
4508
+ self.nextthink = context.entities.timeSeconds + 0.1;
4509
+ }
4510
+ }
4511
+ function useTargetEarthquake(self, other, activator, context) {
4512
+ if (self.spawnflags & SPAWNFLAG_EARTHQUAKE_ONE_SHOT) {
4513
+ context.entities.forEachEntity((ent) => {
4514
+ if (!ent.client) return;
4515
+ if (ent.client) {
4516
+ if (!ent.client.kick_angles) ent.client.kick_angles = { x: 0, y: 0, z: 0 };
4517
+ ent.client.kick_angles = { ...ent.client.kick_angles, x: -self.speed * 0.1 };
4518
+ }
4519
+ });
4520
+ return;
4521
+ }
4522
+ self.timestamp = context.entities.timeSeconds + self.count;
4523
+ if (self.spawnflags & SPAWNFLAG_EARTHQUAKE_TOGGLE) {
4524
+ if (self.style) {
4525
+ self.nextthink = 0;
4526
+ } else {
4527
+ self.nextthink = context.entities.timeSeconds + 0.1;
4528
+ }
4529
+ self.style = !self.style ? 1 : 0;
4530
+ } else {
4531
+ self.nextthink = context.entities.timeSeconds + 0.1;
4532
+ self.last_move_time = 0;
4533
+ }
4534
+ self.activator = activator;
4535
+ }
4536
+ var SPAWNFLAG_LIGHTRAMP_TOGGLE = 1;
4537
+ function target_lightramp_think(self, context) {
4538
+ const timeDelta = context.entities.timeSeconds - self.timestamp;
4539
+ const val = self.movedir.x + timeDelta / 0.1 * self.movedir.z;
4540
+ let charCode = Math.floor("a".charCodeAt(0) + val);
4541
+ const styleStr = String.fromCharCode(charCode);
4542
+ const CS_LIGHTS = 32;
4543
+ if (self.enemy && self.enemy.style !== void 0) {
4544
+ context.entities.configstring(CS_LIGHTS + self.enemy.style, styleStr);
4545
+ }
4546
+ if (timeDelta < self.speed) {
4547
+ self.nextthink = context.entities.timeSeconds + 0.1;
4548
+ } else if (self.spawnflags & SPAWNFLAG_LIGHTRAMP_TOGGLE) {
4549
+ const temp = self.movedir.x;
4550
+ self.movedir = { ...self.movedir, x: self.movedir.y, y: temp, z: self.movedir.z * -1 };
4551
+ }
4552
+ }
4553
+ function useTargetLightramp(self, other, activator, context) {
4554
+ if (!self.enemy) {
4555
+ let e = null;
4556
+ let found = false;
4557
+ context.entities.forEachEntity((ent) => {
4558
+ if (ent.targetname === self.target) {
4559
+ if (ent.classname === "light") {
4560
+ self.enemy = ent;
4561
+ found = true;
4562
+ } else {
4563
+ context.warn(`${self.classname} target ${self.target} is not a light`);
4564
+ }
4565
+ }
4566
+ });
4567
+ if (!found) {
4568
+ context.warn(`${self.classname} target ${self.target} not found`);
4569
+ return;
4570
+ }
4571
+ }
4572
+ self.timestamp = context.entities.timeSeconds;
4573
+ target_lightramp_think(self, context);
4574
+ }
4468
4575
  var TARGET_LASER_START_ON = 1;
4469
4576
  var TARGET_LASER_RED = 2;
4470
4577
  var TARGET_LASER_GREEN = 4;
@@ -4721,6 +4828,26 @@ function registerTargetSpawns(registry) {
4721
4828
  };
4722
4829
  context.entities.scheduleThink(entity, context.entities.timeSeconds + entity.delay);
4723
4830
  });
4831
+ registry.register("target_earthquake", (entity, context) => {
4832
+ if (!entity.count) entity.count = 5;
4833
+ if (!entity.speed) entity.speed = 200;
4834
+ entity.svflags |= 1 /* NoClient */;
4835
+ entity.think = (self) => target_earthquake_think(self, context);
4836
+ entity.use = (self, other, activator) => useTargetEarthquake(self, other, activator ?? null, context);
4837
+ if (!(entity.spawnflags & SPAWNFLAG_EARTHQUAKE_SILENT)) {
4838
+ }
4839
+ });
4840
+ registry.register("target_lightramp", (entity, context) => {
4841
+ entity.svflags |= 1 /* NoClient */;
4842
+ entity.use = (self, other, activator) => useTargetLightramp(self, other, activator ?? null, context);
4843
+ entity.think = (self) => target_lightramp_think(self, context);
4844
+ if (entity.message && entity.message.length === 2 && entity.speed) {
4845
+ const start = entity.message.charCodeAt(0) - "a".charCodeAt(0);
4846
+ const end = entity.message.charCodeAt(1) - "a".charCodeAt(0);
4847
+ const slope = (end - start) / (entity.speed / 0.1);
4848
+ entity.movedir = { x: start, y: end, z: slope };
4849
+ }
4850
+ });
4724
4851
  }
4725
4852
 
4726
4853
  // src/entities/triggers.ts
@@ -5306,7 +5433,7 @@ function chaingunThink(player, sys) {
5306
5433
  if (!player.client) {
5307
5434
  return;
5308
5435
  }
5309
- const weaponState = getWeaponState(player.client.weaponStates, "chaingun" /* Chaingun */);
5436
+ const weaponState = getWeaponState(player.client.weaponStates, WeaponId.Chaingun);
5310
5437
  if (!(player.client.buttons & BUTTON_ATTACK) && weaponState.spinupCount && weaponState.spinupCount > 0) {
5311
5438
  sys.sound(player, 0, "weapons/chngnd1a.wav", 1, 0, 0);
5312
5439
  weaponState.spinupCount = 0;
@@ -5319,7 +5446,7 @@ var WEAPON_ITEMS = {
5319
5446
  type: "weapon",
5320
5447
  id: "weapon_blaster",
5321
5448
  name: "Blaster",
5322
- weaponId: "blaster" /* Blaster */,
5449
+ weaponId: WeaponId.Blaster,
5323
5450
  ammoType: null,
5324
5451
  initialAmmo: 0,
5325
5452
  pickupAmmo: 0,
@@ -5329,7 +5456,7 @@ var WEAPON_ITEMS = {
5329
5456
  type: "weapon",
5330
5457
  id: "weapon_shotgun",
5331
5458
  name: "Shotgun",
5332
- weaponId: "shotgun" /* Shotgun */,
5459
+ weaponId: WeaponId.Shotgun,
5333
5460
  ammoType: AmmoType.Shells,
5334
5461
  initialAmmo: 10,
5335
5462
  pickupAmmo: 10,
@@ -5339,7 +5466,7 @@ var WEAPON_ITEMS = {
5339
5466
  type: "weapon",
5340
5467
  id: "weapon_supershotgun",
5341
5468
  name: "Super Shotgun",
5342
- weaponId: "supershotgun" /* SuperShotgun */,
5469
+ weaponId: WeaponId.SuperShotgun,
5343
5470
  ammoType: AmmoType.Shells,
5344
5471
  initialAmmo: 10,
5345
5472
  pickupAmmo: 10,
@@ -5349,7 +5476,7 @@ var WEAPON_ITEMS = {
5349
5476
  type: "weapon",
5350
5477
  id: "weapon_machinegun",
5351
5478
  name: "Machinegun",
5352
- weaponId: "machinegun" /* Machinegun */,
5479
+ weaponId: WeaponId.Machinegun,
5353
5480
  ammoType: AmmoType.Bullets,
5354
5481
  initialAmmo: 50,
5355
5482
  pickupAmmo: 50,
@@ -5360,7 +5487,7 @@ var WEAPON_ITEMS = {
5360
5487
  type: "weapon",
5361
5488
  id: "weapon_chaingun",
5362
5489
  name: "Chaingun",
5363
- weaponId: "chaingun" /* Chaingun */,
5490
+ weaponId: WeaponId.Chaingun,
5364
5491
  ammoType: AmmoType.Bullets,
5365
5492
  initialAmmo: 50,
5366
5493
  pickupAmmo: 50,
@@ -5370,7 +5497,7 @@ var WEAPON_ITEMS = {
5370
5497
  type: "weapon",
5371
5498
  id: "weapon_grenades",
5372
5499
  name: "Hand Grenade",
5373
- weaponId: "grenades" /* HandGrenade */,
5500
+ weaponId: WeaponId.HandGrenade,
5374
5501
  ammoType: AmmoType.Grenades,
5375
5502
  initialAmmo: 5,
5376
5503
  pickupAmmo: 5,
@@ -5380,7 +5507,7 @@ var WEAPON_ITEMS = {
5380
5507
  type: "weapon",
5381
5508
  id: "weapon_grenadelauncher",
5382
5509
  name: "Grenade Launcher",
5383
- weaponId: "grenadelauncher" /* GrenadeLauncher */,
5510
+ weaponId: WeaponId.GrenadeLauncher,
5384
5511
  ammoType: AmmoType.Grenades,
5385
5512
  initialAmmo: 10,
5386
5513
  pickupAmmo: 10,
@@ -5390,7 +5517,7 @@ var WEAPON_ITEMS = {
5390
5517
  type: "weapon",
5391
5518
  id: "weapon_rocketlauncher",
5392
5519
  name: "Rocket Launcher",
5393
- weaponId: "rocketlauncher" /* RocketLauncher */,
5520
+ weaponId: WeaponId.RocketLauncher,
5394
5521
  ammoType: AmmoType.Rockets,
5395
5522
  initialAmmo: 5,
5396
5523
  pickupAmmo: 5,
@@ -5400,7 +5527,7 @@ var WEAPON_ITEMS = {
5400
5527
  type: "weapon",
5401
5528
  id: "weapon_hyperblaster",
5402
5529
  name: "HyperBlaster",
5403
- weaponId: "hyperblaster" /* HyperBlaster */,
5530
+ weaponId: WeaponId.HyperBlaster,
5404
5531
  ammoType: AmmoType.Cells,
5405
5532
  initialAmmo: 50,
5406
5533
  pickupAmmo: 50,
@@ -5410,7 +5537,7 @@ var WEAPON_ITEMS = {
5410
5537
  type: "weapon",
5411
5538
  id: "weapon_railgun",
5412
5539
  name: "Railgun",
5413
- weaponId: "railgun" /* Railgun */,
5540
+ weaponId: WeaponId.Railgun,
5414
5541
  ammoType: AmmoType.Slugs,
5415
5542
  initialAmmo: 10,
5416
5543
  pickupAmmo: 10,
@@ -5420,7 +5547,7 @@ var WEAPON_ITEMS = {
5420
5547
  type: "weapon",
5421
5548
  id: "weapon_bfg",
5422
5549
  name: "BFG10K",
5423
- weaponId: "bfg10k" /* BFG10K */,
5550
+ weaponId: WeaponId.BFG10K,
5424
5551
  ammoType: AmmoType.Cells,
5425
5552
  initialAmmo: 50,
5426
5553
  pickupAmmo: 50,
@@ -5432,7 +5559,7 @@ var WEAPON_ITEMS = {
5432
5559
  id: "weapon_boomer",
5433
5560
  // Ion Ripper
5434
5561
  name: "Ion Ripper",
5435
- weaponId: "ionripper" /* IonRipper */,
5562
+ weaponId: WeaponId.IonRipper,
5436
5563
  ammoType: AmmoType.Cells,
5437
5564
  initialAmmo: 50,
5438
5565
  pickupAmmo: 50,
@@ -5442,7 +5569,7 @@ var WEAPON_ITEMS = {
5442
5569
  type: "weapon",
5443
5570
  id: "weapon_phalanx",
5444
5571
  name: "Phalanx",
5445
- weaponId: "phalanx" /* Phalanx */,
5572
+ weaponId: WeaponId.Phalanx,
5446
5573
  ammoType: AmmoType.MagSlugs,
5447
5574
  initialAmmo: 50,
5448
5575
  pickupAmmo: 50,
@@ -5452,7 +5579,7 @@ var WEAPON_ITEMS = {
5452
5579
  type: "weapon",
5453
5580
  id: "weapon_beam",
5454
5581
  name: "Plasma Beam",
5455
- weaponId: "plasmabeam" /* PlasmaBeam */,
5582
+ weaponId: WeaponId.PlasmaBeam,
5456
5583
  ammoType: AmmoType.Cells,
5457
5584
  initialAmmo: 50,
5458
5585
  pickupAmmo: 50,
@@ -5462,7 +5589,7 @@ var WEAPON_ITEMS = {
5462
5589
  type: "weapon",
5463
5590
  id: "weapon_etf_rifle",
5464
5591
  name: "ETF Rifle",
5465
- weaponId: "etfrifle" /* EtfRifle */,
5592
+ weaponId: WeaponId.EtfRifle,
5466
5593
  ammoType: AmmoType.Flechettes,
5467
5594
  initialAmmo: 50,
5468
5595
  pickupAmmo: 50,
@@ -5472,7 +5599,7 @@ var WEAPON_ITEMS = {
5472
5599
  type: "weapon",
5473
5600
  id: "weapon_proxlauncher",
5474
5601
  name: "Prox Launcher",
5475
- weaponId: "proxlauncher" /* ProxLauncher */,
5602
+ weaponId: WeaponId.ProxLauncher,
5476
5603
  ammoType: AmmoType.Prox,
5477
5604
  initialAmmo: 5,
5478
5605
  pickupAmmo: 5,
@@ -11381,8 +11508,8 @@ function actor_pain(self, other, kick, damage) {
11381
11508
  if (context.timeSeconds < self.pain_debounce_time)
11382
11509
  return;
11383
11510
  self.pain_debounce_time = context.timeSeconds + 3;
11384
- const random10 = Math.random();
11385
- if (other && other.client && random10 < 0.4) {
11511
+ const random12 = Math.random();
11512
+ if (other && other.client && random12 < 0.4) {
11386
11513
  const v = subtractVec3(other.origin, self.origin);
11387
11514
  self.ideal_yaw = vectorToYaw(v);
11388
11515
  if (Math.random() < 0.5)
@@ -14078,6 +14205,934 @@ function registerTurretSpawns(registry) {
14078
14205
  registry.register("monster_turret", SP_monster_turret);
14079
14206
  }
14080
14207
 
14208
+ // src/entities/monsters/gekk.ts
14209
+ var MONSTER_TICK24 = 0.1;
14210
+ var random8 = () => Math.random();
14211
+ var frandom2 = () => Math.random();
14212
+ var irandom2 = (min, max) => Math.floor(Math.random() * (max - min + 1)) + min;
14213
+ function monster_ai_stand22(self, dist, context) {
14214
+ ai_stand(self, MONSTER_TICK24, context);
14215
+ }
14216
+ function monster_ai_walk20(self, dist, context) {
14217
+ ai_walk(self, dist, MONSTER_TICK24, context);
14218
+ }
14219
+ function monster_ai_run21(self, dist, context) {
14220
+ ai_run(self, dist, MONSTER_TICK24, context);
14221
+ }
14222
+ function monster_ai_charge22(self, dist, context) {
14223
+ ai_charge(self, dist, MONSTER_TICK24, context);
14224
+ }
14225
+ function monster_ai_move21(self, dist, context) {
14226
+ ai_move(self, dist);
14227
+ }
14228
+ var gekk_move_stand;
14229
+ var gekk_move_standunderwater;
14230
+ var gekk_move_swim_loop;
14231
+ var gekk_move_swim_start;
14232
+ var gekk_move_chant;
14233
+ var gekk_move_idle;
14234
+ var gekk_move_idle2;
14235
+ var gekk_move_walk;
14236
+ var gekk_move_run;
14237
+ var gekk_move_run_start;
14238
+ var gekk_move_attack1;
14239
+ var gekk_move_attack2;
14240
+ var gekk_move_spit;
14241
+ var gekk_move_leapatk;
14242
+ var gekk_move_leapatk2;
14243
+ var gekk_move_attack;
14244
+ var gekk_move_pain;
14245
+ var gekk_move_pain1;
14246
+ var gekk_move_pain2;
14247
+ var gekk_move_death1;
14248
+ var gekk_move_death3;
14249
+ var gekk_move_death4;
14250
+ var gekk_move_wdeath;
14251
+ var WATER_WAIST = 2;
14252
+ var RANGE_MELEE2 = 80;
14253
+ var RANGE_NEAR2 = 100;
14254
+ var RANGE_MID2 = 400;
14255
+ var SPAWNFLAG_GEKK_CHANT = 8;
14256
+ var SPAWNFLAG_GEKK_NOJUMPING = 16;
14257
+ var SPAWNFLAG_GEKK_NOSWIM = 32;
14258
+ var GIB_HEALTH = -30;
14259
+ function gekk_check_underwater(self, context) {
14260
+ if (!(self.spawnflags & SPAWNFLAG_GEKK_NOSWIM) && self.waterlevel >= WATER_WAIST) {
14261
+ land_to_water(self);
14262
+ }
14263
+ }
14264
+ function gekk_stand(self) {
14265
+ if (self.waterlevel >= WATER_WAIST) {
14266
+ self.flags |= 2 /* Swim */;
14267
+ self.monsterinfo.current_move = gekk_move_standunderwater;
14268
+ } else {
14269
+ if (self.monsterinfo.current_move !== gekk_move_chant) {
14270
+ self.monsterinfo.current_move = gekk_move_stand;
14271
+ }
14272
+ }
14273
+ }
14274
+ function gekk_swim_loop_func(self) {
14275
+ self.flags |= 2 /* Swim */;
14276
+ self.monsterinfo.current_move = gekk_move_swim_loop;
14277
+ }
14278
+ function gekk_hit_left(self, context) {
14279
+ if (!self.enemy) return;
14280
+ const damage = irandom2(5, 10);
14281
+ const range = 100;
14282
+ const dir = subtractVec3(self.enemy.origin, self.origin);
14283
+ const dist = lengthVec3(dir);
14284
+ if (dist <= range) {
14285
+ context.engine.sound?.(self, 0, "gek/gk_atck2.wav", 1, 1, 0);
14286
+ T_Damage(self.enemy, self, self, normalizeVec3(dir), self.enemy.origin, ZERO_VEC3, damage, damage, 0, 0 /* UNKNOWN */, context.timeSeconds);
14287
+ } else {
14288
+ context.engine.sound?.(self, 0, "gek/gk_atck1.wav", 1, 1, 0);
14289
+ }
14290
+ }
14291
+ function gekk_hit_right(self, context) {
14292
+ if (!self.enemy) return;
14293
+ const damage = irandom2(5, 10);
14294
+ const range = 100;
14295
+ const dir = subtractVec3(self.enemy.origin, self.origin);
14296
+ const dist = lengthVec3(dir);
14297
+ if (dist <= range) {
14298
+ context.engine.sound?.(self, 0, "gek/gk_atck3.wav", 1, 1, 0);
14299
+ T_Damage(self.enemy, self, self, normalizeVec3(dir), self.enemy.origin, ZERO_VEC3, damage, damage, 0, 0 /* UNKNOWN */, context.timeSeconds);
14300
+ } else {
14301
+ context.engine.sound?.(self, 0, "gek/gk_atck1.wav", 1, 1, 0);
14302
+ }
14303
+ }
14304
+ function gekk_bite(self, context) {
14305
+ if (!self.enemy) return;
14306
+ const damage = 5;
14307
+ const range = RANGE_MELEE2;
14308
+ const dir = subtractVec3(self.enemy.origin, self.origin);
14309
+ const dist = lengthVec3(dir);
14310
+ if (dist <= range) {
14311
+ T_Damage(self.enemy, self, self, normalizeVec3(dir), self.enemy.origin, ZERO_VEC3, damage, 0, 0, 0 /* UNKNOWN */, context.timeSeconds);
14312
+ }
14313
+ }
14314
+ function gekk_check_melee(self, context) {
14315
+ if (!self.enemy || self.enemy.health <= 0 || self.monsterinfo.melee_debounce_time && self.monsterinfo.melee_debounce_time > context.timeSeconds)
14316
+ return false;
14317
+ const dist = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14318
+ return dist <= RANGE_MELEE2;
14319
+ }
14320
+ function gekk_check_jump(self, context) {
14321
+ if (!self.enemy) return false;
14322
+ if (self.absmin.z + 125 < self.enemy.absmin.z)
14323
+ return false;
14324
+ const v = subtractVec3(self.origin, self.enemy.origin);
14325
+ v.z = 0;
14326
+ const distance2 = lengthVec3(v);
14327
+ if (distance2 < 100) return false;
14328
+ if (distance2 > 100) {
14329
+ if (frandom2() < (self.waterlevel >= WATER_WAIST ? 0.2 : 0.9))
14330
+ return false;
14331
+ }
14332
+ return true;
14333
+ }
14334
+ function gekk_check_jump_close(self, context) {
14335
+ if (!self.enemy) return false;
14336
+ const v = subtractVec3(self.origin, self.enemy.origin);
14337
+ v.z = 0;
14338
+ const distance2 = lengthVec3(v);
14339
+ if (distance2 < 100) {
14340
+ if (self.absmax.z <= self.enemy.absmin.z) return false;
14341
+ }
14342
+ return true;
14343
+ }
14344
+ function gekk_checkattack(self, context) {
14345
+ if (!self.enemy || self.enemy.health <= 0) return false;
14346
+ if (gekk_check_melee(self, context)) {
14347
+ return true;
14348
+ }
14349
+ if (gekk_check_jump(self, context)) {
14350
+ return true;
14351
+ }
14352
+ if (gekk_check_jump_close(self, context) && !(self.flags & 2 /* Swim */)) {
14353
+ return true;
14354
+ }
14355
+ return false;
14356
+ }
14357
+ function gekk_chant(self) {
14358
+ self.monsterinfo.current_move = gekk_move_chant;
14359
+ }
14360
+ function gekk_idle_loop(self) {
14361
+ if (frandom2() > 0.75 && self.health < self.max_health) {
14362
+ self.monsterinfo.nextframe = 0;
14363
+ }
14364
+ }
14365
+ function gekk_step(self, context) {
14366
+ const n = irandom2(0, 2);
14367
+ const sounds = ["gek/gk_step1.wav", "gek/gk_step2.wav", "gek/gk_step3.wav"];
14368
+ context.engine.sound?.(self, 0, sounds[n], 1, 1, 0);
14369
+ }
14370
+ function gekk_search(self, context) {
14371
+ if (self.spawnflags & SPAWNFLAG_GEKK_CHANT) {
14372
+ const r = frandom2();
14373
+ if (r < 0.33) context.engine.sound?.(self, 0, "gek/gek_low.wav", 1, 1, 0);
14374
+ else if (r < 0.66) context.engine.sound?.(self, 0, "gek/gek_mid.wav", 1, 1, 0);
14375
+ else context.engine.sound?.(self, 0, "gek/gek_high.wav", 1, 1, 0);
14376
+ } else {
14377
+ context.engine.sound?.(self, 0, "gek/gk_idle1.wav", 1, 1, 0);
14378
+ }
14379
+ self.health += irandom2(10, 20);
14380
+ if (self.health > self.max_health) self.health = self.max_health;
14381
+ if (self.health < self.max_health / 4) self.skin = 2;
14382
+ else if (self.health < self.max_health / 2) self.skin = 1;
14383
+ else self.skin = 0;
14384
+ }
14385
+ function gekk_run_start(self) {
14386
+ if (!(self.spawnflags & SPAWNFLAG_GEKK_NOSWIM) && self.waterlevel >= WATER_WAIST) {
14387
+ self.monsterinfo.current_move = gekk_move_swim_start;
14388
+ } else {
14389
+ self.monsterinfo.current_move = gekk_move_run_start;
14390
+ }
14391
+ }
14392
+ function gekk_run(self) {
14393
+ if (!(self.spawnflags & SPAWNFLAG_GEKK_NOSWIM) && self.waterlevel >= WATER_WAIST) {
14394
+ self.monsterinfo.current_move = gekk_move_swim_start;
14395
+ } else {
14396
+ self.monsterinfo.current_move = gekk_move_run;
14397
+ }
14398
+ }
14399
+ function gekk_check_refire(self) {
14400
+ if (!self.enemy || self.enemy.health <= 0) return;
14401
+ const dist = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14402
+ if (dist <= RANGE_MELEE2) {
14403
+ if (self.frame === 114) {
14404
+ self.monsterinfo.current_move = gekk_move_attack2;
14405
+ } else if (self.frame === 123) {
14406
+ self.monsterinfo.current_move = gekk_move_attack1;
14407
+ }
14408
+ }
14409
+ }
14410
+ function fire_loogie(self, start, dir, damage, speed, context) {
14411
+ const bolt = createBlasterBolt(context, self, start, dir, damage, speed, 0 /* UNKNOWN */);
14412
+ bolt.model = "models/objects/loogy/tris.md2";
14413
+ }
14414
+ function loogie_fire(self, context) {
14415
+ if (!self.enemy || self.enemy.health <= 0) return;
14416
+ const vectors = angleVectors(self.angles);
14417
+ const forward = vectors.forward;
14418
+ const right = vectors.right;
14419
+ const up = vectors.up;
14420
+ const offset = { x: -18, y: -0.8, z: 24 };
14421
+ const start = addVec3(self.origin, addVec3(scaleVec3(forward, offset.x), addVec3(scaleVec3(right, offset.y), scaleVec3(up, offset.z))));
14422
+ start.z += 2;
14423
+ const end = copyVec3(self.enemy.origin);
14424
+ end.z += self.enemy.viewheight || 0;
14425
+ const dir = normalizeVec3(subtractVec3(end, start));
14426
+ fire_loogie(self, start, dir, 5, 550, context);
14427
+ context.engine.sound?.(self, 0, "gek/gk_atck4.wav", 1, 1, 0);
14428
+ }
14429
+ function reloogie(self) {
14430
+ if (frandom2() > 0.8 && self.health < self.max_health) {
14431
+ self.monsterinfo.current_move = gekk_move_idle2;
14432
+ return;
14433
+ }
14434
+ if (self.enemy && self.enemy.health > 0) {
14435
+ const dist = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14436
+ if (frandom2() > 0.7 && dist <= RANGE_NEAR2) {
14437
+ self.monsterinfo.current_move = gekk_move_spit;
14438
+ }
14439
+ }
14440
+ }
14441
+ function gekk_jump_touch(self, other, plane, surf) {
14442
+ if (self.health <= 0) {
14443
+ self.touch = void 0;
14444
+ return;
14445
+ }
14446
+ self.touch = void 0;
14447
+ }
14448
+ function gekk_jump_takeoff(self, context) {
14449
+ const vectors = angleVectors(self.angles);
14450
+ const forward = vectors.forward;
14451
+ context.engine.sound?.(self, 0, "gek/gk_sght1.wav", 1, 1, 0);
14452
+ self.origin.z += 1;
14453
+ self.velocity = addVec3(scaleVec3(forward, 700), { x: 0, y: 0, z: 250 });
14454
+ self.groundentity = null;
14455
+ self.touch = gekk_jump_touch;
14456
+ }
14457
+ function gekk_check_landing(self, context) {
14458
+ if (self.groundentity) {
14459
+ context.engine.sound?.(self, 0, "mutant/thud1.wav", 1, 1, 0);
14460
+ self.velocity = ZERO_VEC3;
14461
+ return;
14462
+ }
14463
+ }
14464
+ function gekk_stop_skid(self) {
14465
+ if (self.groundentity) self.velocity = ZERO_VEC3;
14466
+ }
14467
+ function gekk_preattack(self, context) {
14468
+ }
14469
+ function gekk_dead(self) {
14470
+ self.mins = { x: -16, y: -16, z: -24 };
14471
+ self.maxs = { x: 16, y: 16, z: -8 };
14472
+ self.nextthink = -1;
14473
+ }
14474
+ function gekk_gibfest(self, context) {
14475
+ throwGibs(context, self.origin, 20);
14476
+ self.deadflag = 2 /* Dead */;
14477
+ }
14478
+ function isgibfest(self, context) {
14479
+ if (frandom2() > 0.9) gekk_gibfest(self, context);
14480
+ }
14481
+ function gekk_shrink(self) {
14482
+ self.maxs.z = 0;
14483
+ }
14484
+ function land_to_water(self) {
14485
+ self.flags |= 2 /* Swim */;
14486
+ self.yaw_speed = 10;
14487
+ self.viewheight = 10;
14488
+ self.monsterinfo.current_move = gekk_move_swim_start;
14489
+ self.mins = { x: -18, y: -18, z: -24 };
14490
+ self.maxs = { x: 18, y: 18, z: 16 };
14491
+ }
14492
+ var frames_stand2 = Array(38).fill({ ai: monster_ai_stand22, dist: 0 });
14493
+ frames_stand2[38] = { ai: monster_ai_stand22, dist: 0, think: gekk_check_underwater };
14494
+ gekk_move_stand = {
14495
+ firstframe: 0,
14496
+ lastframe: 38,
14497
+ frames: frames_stand2,
14498
+ endfunc: null
14499
+ };
14500
+ var frames_standunderwater = Array(32).fill({ ai: monster_ai_stand22, dist: 14 });
14501
+ gekk_move_standunderwater = {
14502
+ firstframe: 39,
14503
+ lastframe: 70,
14504
+ frames: frames_standunderwater,
14505
+ endfunc: null
14506
+ };
14507
+ var frames_swim = Array(32).fill({ ai: monster_ai_run21, dist: 14 });
14508
+ gekk_move_swim_loop = {
14509
+ firstframe: 39,
14510
+ lastframe: 70,
14511
+ frames: frames_swim,
14512
+ endfunc: gekk_swim_loop_func
14513
+ };
14514
+ var frames_swim_start = Array(32).fill({ ai: monster_ai_run21, dist: 14 });
14515
+ frames_swim_start[8] = { ai: monster_ai_run21, dist: 18, think: gekk_hit_left };
14516
+ frames_swim_start[14] = { ai: monster_ai_run21, dist: 24, think: gekk_hit_right };
14517
+ frames_swim_start[20] = { ai: monster_ai_run21, dist: 22, think: gekk_bite };
14518
+ gekk_move_swim_start = {
14519
+ firstframe: 39,
14520
+ lastframe: 70,
14521
+ frames: frames_swim_start,
14522
+ endfunc: gekk_swim_loop_func
14523
+ };
14524
+ var frames_idle = Array(32).fill({ ai: monster_ai_stand22, dist: 0 });
14525
+ frames_idle[0] = { ai: monster_ai_stand22, dist: 0, think: gekk_search };
14526
+ frames_idle[31] = { ai: monster_ai_stand22, dist: 0, think: gekk_idle_loop };
14527
+ gekk_move_idle = {
14528
+ firstframe: 71,
14529
+ lastframe: 102,
14530
+ frames: frames_idle,
14531
+ endfunc: gekk_stand
14532
+ };
14533
+ var frames_idle2 = Array(32).fill({ ai: monster_ai_move21, dist: 0 });
14534
+ frames_idle2[0] = { ai: monster_ai_move21, dist: 0, think: gekk_search };
14535
+ frames_idle2[31] = { ai: monster_ai_move21, dist: 0, think: gekk_idle_loop };
14536
+ gekk_move_idle2 = {
14537
+ firstframe: 71,
14538
+ lastframe: 102,
14539
+ frames: frames_idle2,
14540
+ endfunc: (s) => M_SetAnimation2(s, gekk_move_stand)
14541
+ // or face
14542
+ };
14543
+ gekk_move_chant = {
14544
+ firstframe: 71,
14545
+ lastframe: 102,
14546
+ frames: frames_idle2,
14547
+ endfunc: gekk_chant
14548
+ };
14549
+ var frames_walk2 = [
14550
+ { ai: monster_ai_walk20, dist: 3.8, think: gekk_check_underwater },
14551
+ { ai: monster_ai_walk20, dist: 19.6 },
14552
+ { ai: monster_ai_walk20, dist: 25.5 },
14553
+ { ai: monster_ai_walk20, dist: 34.6, think: gekk_step },
14554
+ { ai: monster_ai_walk20, dist: 27.3 },
14555
+ { ai: monster_ai_walk20, dist: 28.4 }
14556
+ ];
14557
+ gekk_move_walk = {
14558
+ firstframe: 103,
14559
+ lastframe: 108,
14560
+ frames: frames_walk2,
14561
+ endfunc: null
14562
+ };
14563
+ var frames_run2 = [
14564
+ { ai: monster_ai_run21, dist: 3.8, think: gekk_check_underwater },
14565
+ { ai: monster_ai_run21, dist: 19.6 },
14566
+ { ai: monster_ai_run21, dist: 25.5 },
14567
+ { ai: monster_ai_run21, dist: 34.6, think: gekk_step },
14568
+ { ai: monster_ai_run21, dist: 27.3 },
14569
+ { ai: monster_ai_run21, dist: 28.4 }
14570
+ ];
14571
+ gekk_move_run = {
14572
+ firstframe: 103,
14573
+ lastframe: 108,
14574
+ frames: frames_run2,
14575
+ endfunc: null
14576
+ };
14577
+ var frames_run_st = [
14578
+ { ai: monster_ai_run21, dist: 0.2 },
14579
+ { ai: monster_ai_run21, dist: 19.7 }
14580
+ ];
14581
+ gekk_move_run_start = {
14582
+ firstframe: 0,
14583
+ lastframe: 1,
14584
+ // Frames 0 and 1 reuse stand start? C says FRAME_stand_01, FRAME_stand_02
14585
+ frames: frames_run_st,
14586
+ endfunc: gekk_run
14587
+ };
14588
+ var frames_spit = [
14589
+ { ai: monster_ai_charge22, dist: 0 },
14590
+ { ai: monster_ai_charge22, dist: 0 },
14591
+ { ai: monster_ai_charge22, dist: 0 },
14592
+ { ai: monster_ai_charge22, dist: 0 },
14593
+ { ai: monster_ai_charge22, dist: 0 },
14594
+ { ai: monster_ai_charge22, dist: 0, think: loogie_fire },
14595
+ { ai: monster_ai_charge22, dist: 0, think: reloogie }
14596
+ ];
14597
+ gekk_move_spit = {
14598
+ firstframe: 133,
14599
+ // FRAME_spit_01
14600
+ lastframe: 139,
14601
+ frames: frames_spit,
14602
+ endfunc: gekk_run_start
14603
+ };
14604
+ var frames_attack1 = [
14605
+ { ai: monster_ai_charge22, dist: 0 },
14606
+ { ai: monster_ai_charge22, dist: 0 },
14607
+ { ai: monster_ai_charge22, dist: 0 },
14608
+ { ai: monster_ai_charge22, dist: 0, think: gekk_hit_left },
14609
+ { ai: monster_ai_charge22, dist: 0 },
14610
+ { ai: monster_ai_charge22, dist: 0 },
14611
+ { ai: monster_ai_charge22, dist: 0 },
14612
+ { ai: monster_ai_charge22, dist: 0 },
14613
+ { ai: monster_ai_charge22, dist: 0, think: gekk_check_refire }
14614
+ ];
14615
+ gekk_move_attack1 = {
14616
+ firstframe: 109,
14617
+ lastframe: 117,
14618
+ frames: frames_attack1,
14619
+ endfunc: gekk_run_start
14620
+ };
14621
+ var frames_attack2 = [
14622
+ { ai: monster_ai_charge22, dist: 0 },
14623
+ { ai: monster_ai_charge22, dist: 0 },
14624
+ { ai: monster_ai_charge22, dist: 0, think: gekk_hit_left },
14625
+ { ai: monster_ai_charge22, dist: 0 },
14626
+ { ai: monster_ai_charge22, dist: 0 },
14627
+ { ai: monster_ai_charge22, dist: 0, think: gekk_hit_right },
14628
+ { ai: monster_ai_charge22, dist: 0 },
14629
+ { ai: monster_ai_charge22, dist: 0 },
14630
+ { ai: monster_ai_charge22, dist: 0, think: gekk_check_refire }
14631
+ ];
14632
+ gekk_move_attack2 = {
14633
+ firstframe: 118,
14634
+ lastframe: 126,
14635
+ frames: frames_attack2,
14636
+ endfunc: gekk_run_start
14637
+ };
14638
+ var frames_leapatk = [
14639
+ { ai: monster_ai_charge22, dist: 0 },
14640
+ { ai: monster_ai_charge22, dist: -0.3 },
14641
+ { ai: monster_ai_charge22, dist: -1.1 },
14642
+ { ai: monster_ai_charge22, dist: -0.2 },
14643
+ { ai: monster_ai_charge22, dist: 6.7, think: gekk_jump_takeoff },
14644
+ { ai: monster_ai_charge22, dist: 6.4 },
14645
+ { ai: monster_ai_charge22, dist: 0.1 },
14646
+ { ai: monster_ai_charge22, dist: 28.3 },
14647
+ { ai: monster_ai_charge22, dist: 24.1 },
14648
+ { ai: monster_ai_charge22, dist: 31.7 },
14649
+ { ai: monster_ai_charge22, dist: 35.9, think: gekk_check_landing },
14650
+ { ai: monster_ai_charge22, dist: 12.3, think: gekk_stop_skid },
14651
+ { ai: monster_ai_charge22, dist: 20.1, think: gekk_stop_skid },
14652
+ { ai: monster_ai_charge22, dist: -1, think: gekk_stop_skid },
14653
+ { ai: monster_ai_charge22, dist: 2.5, think: gekk_stop_skid },
14654
+ { ai: monster_ai_charge22, dist: 0.5, think: gekk_stop_skid },
14655
+ { ai: monster_ai_charge22, dist: 1.8, think: gekk_stop_skid },
14656
+ { ai: monster_ai_charge22, dist: 1.2, think: gekk_stop_skid },
14657
+ { ai: monster_ai_charge22, dist: -0.4, think: gekk_check_underwater }
14658
+ ];
14659
+ gekk_move_leapatk = {
14660
+ firstframe: 140,
14661
+ lastframe: 158,
14662
+ frames: frames_leapatk,
14663
+ endfunc: gekk_run_start
14664
+ };
14665
+ gekk_move_leapatk2 = {
14666
+ firstframe: 140,
14667
+ lastframe: 158,
14668
+ frames: frames_leapatk,
14669
+ // reusing frames
14670
+ endfunc: gekk_run_start
14671
+ };
14672
+ var frames_attack3 = Array(21).fill({ ai: monster_ai_charge22, dist: 16 });
14673
+ frames_attack3[0] = { ai: monster_ai_charge22, dist: 16, think: gekk_preattack };
14674
+ frames_attack3[4] = { ai: monster_ai_charge22, dist: 16, think: gekk_bite };
14675
+ frames_attack3[9] = { ai: monster_ai_charge22, dist: 16, think: gekk_bite };
14676
+ frames_attack3[13] = { ai: monster_ai_charge22, dist: 16, think: gekk_hit_left };
14677
+ frames_attack3[18] = { ai: monster_ai_charge22, dist: 16, think: gekk_hit_right };
14678
+ gekk_move_attack = {
14679
+ firstframe: 159,
14680
+ lastframe: 179,
14681
+ frames: frames_attack3,
14682
+ endfunc: gekk_run_start
14683
+ };
14684
+ var frames_pain = Array(6).fill({ ai: monster_ai_move21, dist: 0 });
14685
+ gekk_move_pain = {
14686
+ firstframe: 180,
14687
+ lastframe: 185,
14688
+ frames: frames_pain,
14689
+ endfunc: gekk_run_start
14690
+ };
14691
+ var frames_pain12 = Array(11).fill({ ai: monster_ai_move21, dist: 0 });
14692
+ frames_pain12[10] = { ai: monster_ai_move21, dist: 0, think: gekk_check_underwater };
14693
+ gekk_move_pain1 = {
14694
+ firstframe: 186,
14695
+ lastframe: 196,
14696
+ frames: frames_pain12,
14697
+ endfunc: gekk_run_start
14698
+ };
14699
+ var frames_pain22 = Array(13).fill({ ai: monster_ai_move21, dist: 0 });
14700
+ frames_pain22[12] = { ai: monster_ai_move21, dist: 0, think: gekk_check_underwater };
14701
+ gekk_move_pain2 = {
14702
+ firstframe: 197,
14703
+ lastframe: 209,
14704
+ frames: frames_pain22,
14705
+ endfunc: gekk_run_start
14706
+ };
14707
+ function gekk_pain(self, other, kick, damage, context) {
14708
+ if (self.spawnflags & SPAWNFLAG_GEKK_CHANT) {
14709
+ self.spawnflags &= ~SPAWNFLAG_GEKK_CHANT;
14710
+ return;
14711
+ }
14712
+ context.engine.sound?.(self, 0, "gek/gk_pain1.wav", 1, 1, 0);
14713
+ if (self.waterlevel >= WATER_WAIST) {
14714
+ if (!(self.flags & 2 /* Swim */)) {
14715
+ self.flags |= 2 /* Swim */;
14716
+ }
14717
+ self.monsterinfo.current_move = gekk_move_pain;
14718
+ } else {
14719
+ if (random8() > 0.5) self.monsterinfo.current_move = gekk_move_pain1;
14720
+ else self.monsterinfo.current_move = gekk_move_pain2;
14721
+ }
14722
+ }
14723
+ var frames_death12 = Array(10).fill({ ai: monster_ai_move21, dist: 0 });
14724
+ frames_death12[5] = { ai: monster_ai_move21, dist: -7, think: gekk_shrink };
14725
+ gekk_move_death1 = {
14726
+ firstframe: 210,
14727
+ lastframe: 219,
14728
+ frames: frames_death12,
14729
+ endfunc: gekk_dead
14730
+ };
14731
+ var frames_death3 = Array(7).fill({ ai: monster_ai_move21, dist: 0 });
14732
+ frames_death3[5] = { ai: monster_ai_move21, dist: -7, think: isgibfest };
14733
+ gekk_move_death3 = {
14734
+ firstframe: 220,
14735
+ lastframe: 226,
14736
+ frames: frames_death3,
14737
+ endfunc: gekk_dead
14738
+ };
14739
+ var frames_death4 = Array(35).fill({ ai: monster_ai_move21, dist: 0 });
14740
+ frames_death4[34] = { ai: monster_ai_move21, dist: 0, think: gekk_gibfest };
14741
+ gekk_move_death4 = {
14742
+ firstframe: 227,
14743
+ lastframe: 261,
14744
+ frames: frames_death4,
14745
+ endfunc: gekk_dead
14746
+ };
14747
+ var frames_wdeath = Array(45).fill({ ai: monster_ai_move21, dist: 0 });
14748
+ gekk_move_wdeath = {
14749
+ firstframe: 262,
14750
+ lastframe: 306,
14751
+ frames: frames_wdeath,
14752
+ endfunc: gekk_dead
14753
+ };
14754
+ function gekk_die(self, inflictor, attacker, damage, point, mod, context) {
14755
+ if (self.health <= GIB_HEALTH) {
14756
+ throwGibs(context, self.origin, damage);
14757
+ return;
14758
+ }
14759
+ if (self.deadflag === 2 /* Dead */) return;
14760
+ context.engine.sound?.(self, 0, "gek/gk_deth1.wav", 1, 1, 0);
14761
+ self.deadflag = 2 /* Dead */;
14762
+ self.takedamage = true;
14763
+ if (self.waterlevel >= WATER_WAIST) {
14764
+ gekk_shrink(self);
14765
+ self.monsterinfo.current_move = gekk_move_wdeath;
14766
+ } else {
14767
+ const r = frandom2();
14768
+ if (r > 0.66) self.monsterinfo.current_move = gekk_move_death1;
14769
+ else if (r > 0.33) self.monsterinfo.current_move = gekk_move_death3;
14770
+ else self.monsterinfo.current_move = gekk_move_death4;
14771
+ }
14772
+ }
14773
+ function SP_monster_gekk(self, context) {
14774
+ self.classname = "monster_gekk";
14775
+ self.model = "models/monsters/gekk/tris.md2";
14776
+ self.movetype = 5 /* Step */;
14777
+ self.solid = 2 /* BoundingBox */;
14778
+ self.mins = { x: -18, y: -18, z: -24 };
14779
+ self.maxs = { x: 18, y: 18, z: 24 };
14780
+ self.health = 125;
14781
+ self.max_health = 125;
14782
+ self.mass = 300;
14783
+ self.pain = (e, o, k, d) => gekk_pain(e, o, k, d, context.entities);
14784
+ self.die = (e, i, a, d, p, m3) => gekk_die(e, i, a, d, p, m3, context.entities);
14785
+ self.monsterinfo.stand = gekk_stand;
14786
+ self.monsterinfo.walk = (s) => M_SetAnimation2(s, gekk_move_walk);
14787
+ self.monsterinfo.run = gekk_run_start;
14788
+ self.monsterinfo.attack = (s) => gekk_attack(s, context.entities);
14789
+ self.monsterinfo.melee = gekk_melee;
14790
+ self.monsterinfo.sight = (s, o) => context.entities.sound?.(s, 0, "gek/gk_sght1.wav", 1, 1, 0);
14791
+ self.monsterinfo.search = (s) => gekk_search(s, context.entities);
14792
+ self.monsterinfo.idle = (s) => {
14793
+ if (s.spawnflags & SPAWNFLAG_GEKK_NOSWIM || s.waterlevel < WATER_WAIST) {
14794
+ M_SetAnimation2(s, gekk_move_idle);
14795
+ } else {
14796
+ M_SetAnimation2(s, gekk_move_swim_start);
14797
+ }
14798
+ };
14799
+ self.monsterinfo.checkattack = (s) => gekk_checkattack(s, context.entities);
14800
+ context.entities.linkentity(self);
14801
+ M_SetAnimation2(self, gekk_move_stand);
14802
+ self.think = monster_think;
14803
+ self.nextthink = context.entities.timeSeconds + MONSTER_TICK24;
14804
+ if (self.spawnflags & SPAWNFLAG_GEKK_CHANT) {
14805
+ M_SetAnimation2(self, gekk_move_chant);
14806
+ }
14807
+ }
14808
+ function M_SetAnimation2(self, move) {
14809
+ self.monsterinfo.current_move = move;
14810
+ }
14811
+ function gekk_attack(self, context) {
14812
+ if (!self.enemy) return;
14813
+ const r = lengthVec3(subtractVec3(self.enemy.origin, self.origin));
14814
+ if (self.flags & 2 /* Swim */) {
14815
+ if (self.enemy && self.enemy.waterlevel >= WATER_WAIST && r <= RANGE_NEAR2)
14816
+ return;
14817
+ self.flags &= ~2 /* Swim */;
14818
+ M_SetAnimation2(self, gekk_move_leapatk);
14819
+ self.frame = 144;
14820
+ } else {
14821
+ if (r >= RANGE_MID2) {
14822
+ if (frandom2() > 0.5) {
14823
+ M_SetAnimation2(self, gekk_move_spit);
14824
+ } else {
14825
+ M_SetAnimation2(self, gekk_move_run_start);
14826
+ }
14827
+ } else if (frandom2() > 0.7) {
14828
+ M_SetAnimation2(self, gekk_move_spit);
14829
+ } else {
14830
+ if (self.spawnflags & SPAWNFLAG_GEKK_NOJUMPING || frandom2() > 0.7) {
14831
+ M_SetAnimation2(self, gekk_move_run_start);
14832
+ } else {
14833
+ M_SetAnimation2(self, gekk_move_leapatk);
14834
+ }
14835
+ }
14836
+ }
14837
+ }
14838
+ function gekk_melee(self) {
14839
+ if (self.waterlevel >= WATER_WAIST) {
14840
+ M_SetAnimation2(self, gekk_move_attack);
14841
+ } else {
14842
+ if (frandom2() > 0.66) M_SetAnimation2(self, gekk_move_attack1);
14843
+ else M_SetAnimation2(self, gekk_move_attack2);
14844
+ }
14845
+ }
14846
+ function registerGekkSpawns(registry) {
14847
+ registry.register("monster_gekk", SP_monster_gekk);
14848
+ }
14849
+
14850
+ // src/entities/monsters/fixbot.ts
14851
+ var MONSTER_TICK25 = 0.1;
14852
+ var random9 = () => Math.random();
14853
+ var frandom3 = () => Math.random();
14854
+ function monster_ai_walk21(self, dist, context) {
14855
+ ai_walk(self, dist, MONSTER_TICK25, context);
14856
+ }
14857
+ function monster_ai_run22(self, dist, context) {
14858
+ ai_run(self, dist, MONSTER_TICK25, context);
14859
+ }
14860
+ function monster_ai_charge23(self, dist, context) {
14861
+ ai_charge(self, dist, MONSTER_TICK25, context);
14862
+ }
14863
+ function monster_ai_move22(self, dist, context) {
14864
+ ai_move(self, dist);
14865
+ }
14866
+ var fixbot_move_stand;
14867
+ var fixbot_move_walk;
14868
+ var fixbot_move_run;
14869
+ var fixbot_move_attack2;
14870
+ var fixbot_move_laserattack;
14871
+ var fixbot_move_weld_start;
14872
+ var fixbot_move_weld;
14873
+ var fixbot_move_weld_end;
14874
+ var fixbot_move_start_attack;
14875
+ var fixbot_move_pain3;
14876
+ var fixbot_move_painb;
14877
+ var fixbot_move_paina;
14878
+ var MZ2_HOVER_BLASTER_1 = 1;
14879
+ function fixbot_set_fly_parameters(self, heal, weld) {
14880
+ if (heal) {
14881
+ } else if (weld) {
14882
+ } else {
14883
+ }
14884
+ }
14885
+ function fixbot_FindDeadMonster(self, context) {
14886
+ const radius = 1024;
14887
+ const candidates = context.findByRadius(self.origin, radius);
14888
+ let best = null;
14889
+ for (const ent of candidates) {
14890
+ if (ent === self) continue;
14891
+ if (!ent.monsterinfo) continue;
14892
+ if (ent.monsterinfo.aiflags & 256 /* GoodGuy */) continue;
14893
+ if (ent.health > 0) continue;
14894
+ if (ent.nextthink && ent.think === context.free) continue;
14895
+ if (ent.health <= -40) continue;
14896
+ if (!visible(self, ent, context.trace)) continue;
14897
+ if (!best) {
14898
+ best = ent;
14899
+ continue;
14900
+ }
14901
+ if (ent.max_health <= best.max_health) continue;
14902
+ best = ent;
14903
+ }
14904
+ return best;
14905
+ }
14906
+ function fixbot_search(self, context) {
14907
+ if (self.enemy) return;
14908
+ const ent = fixbot_FindDeadMonster(self, context);
14909
+ if (ent) {
14910
+ self.enemy = ent;
14911
+ self.monsterinfo.aiflags |= 8192 /* Medic */;
14912
+ fixbot_run(self);
14913
+ fixbot_set_fly_parameters(self, true, false);
14914
+ } else {
14915
+ if (random9() < 0.1) {
14916
+ context.engine.sound?.(self, 0, "flyer/flysght1.wav", 1, 1, 0);
14917
+ }
14918
+ }
14919
+ }
14920
+ function fixbot_die(self, inflictor, attacker, damage, point, mod, context) {
14921
+ context.engine.sound?.(self, 0, "flyer/flydeth1.wav", 1, 1, 0);
14922
+ throwGibs(context, self.origin, damage);
14923
+ self.deadflag = 2 /* Dead */;
14924
+ self.takedamage = false;
14925
+ context.free(self);
14926
+ }
14927
+ function fixbot_fire_blaster_func(self, context) {
14928
+ if (!self.enemy || !self.enemy.inUse) {
14929
+ self.monsterinfo.current_move = fixbot_move_run;
14930
+ return;
14931
+ }
14932
+ const vectors = angleVectors(self.angles);
14933
+ const start = addVec3(self.origin, addVec3(scaleVec3(vectors.forward, 0), addVec3(scaleVec3(vectors.right, 0), scaleVec3(vectors.up, 0))));
14934
+ const end = copyVec3(self.enemy.origin);
14935
+ end.z += self.enemy.viewheight || 0;
14936
+ const dir = normalizeVec3(subtractVec3(end, start));
14937
+ monster_fire_blaster(self, start, dir, 15, 1e3, MZ2_HOVER_BLASTER_1, 0, context);
14938
+ }
14939
+ function fixbot_fire_laser(self, context) {
14940
+ if (!self.enemy || !self.enemy.inUse || self.enemy.health <= -40) {
14941
+ self.monsterinfo.current_move = fixbot_move_stand;
14942
+ self.monsterinfo.aiflags &= ~8192 /* Medic */;
14943
+ return;
14944
+ }
14945
+ if (self.enemy.health < self.enemy.max_health) {
14946
+ self.enemy.health += 5;
14947
+ if (self.enemy.health > self.enemy.max_health) self.enemy.health = self.enemy.max_health;
14948
+ } else {
14949
+ if (self.enemy.deadflag === 2 /* Dead */) {
14950
+ self.enemy.deadflag = 0 /* Alive */;
14951
+ self.enemy.solid = 2 /* BoundingBox */;
14952
+ self.enemy.takedamage = true;
14953
+ self.enemy.health = self.enemy.max_health;
14954
+ self.enemy.monsterinfo.aiflags &= ~128 /* HoldFrame */;
14955
+ }
14956
+ self.monsterinfo.current_move = fixbot_move_stand;
14957
+ self.monsterinfo.aiflags &= ~8192 /* Medic */;
14958
+ self.enemy = null;
14959
+ }
14960
+ }
14961
+ function fixbot_fire_welder(self, context) {
14962
+ if (frandom3() > 0.8) {
14963
+ const r = frandom3();
14964
+ if (r < 0.33) context.engine.sound?.(self, 0, "misc/welder1.wav", 1, 1, 0);
14965
+ else if (r < 0.66) context.engine.sound?.(self, 0, "misc/welder2.wav", 1, 1, 0);
14966
+ else context.engine.sound?.(self, 0, "misc/welder3.wav", 1, 1, 0);
14967
+ }
14968
+ }
14969
+ function fixbot_pain(self, other, kick, damage, context) {
14970
+ if (self.timestamp < (self.pain_debounce_time || 0)) return;
14971
+ self.pain_debounce_time = self.timestamp + 3;
14972
+ context.engine.sound?.(self, 0, "flyer/flypain1.wav", 1, 1, 0);
14973
+ if (damage <= 10) self.monsterinfo.current_move = fixbot_move_pain3;
14974
+ else if (damage <= 25) self.monsterinfo.current_move = fixbot_move_painb;
14975
+ else self.monsterinfo.current_move = fixbot_move_paina;
14976
+ }
14977
+ function fixbot_stand(self) {
14978
+ self.monsterinfo.current_move = fixbot_move_stand;
14979
+ }
14980
+ function fixbot_walk(self) {
14981
+ self.monsterinfo.current_move = fixbot_move_walk;
14982
+ }
14983
+ function fixbot_run(self) {
14984
+ if (self.monsterinfo.aiflags & 1 /* StandGround */)
14985
+ self.monsterinfo.current_move = fixbot_move_stand;
14986
+ else
14987
+ self.monsterinfo.current_move = fixbot_move_run;
14988
+ }
14989
+ function fixbot_start_attack(self) {
14990
+ self.monsterinfo.current_move = fixbot_move_start_attack;
14991
+ }
14992
+ function fixbot_attack(self) {
14993
+ if (self.monsterinfo.aiflags & 8192 /* Medic */) {
14994
+ self.monsterinfo.current_move = fixbot_move_laserattack;
14995
+ } else {
14996
+ self.monsterinfo.current_move = fixbot_move_attack2;
14997
+ }
14998
+ }
14999
+ function weldstate(self) {
15000
+ if (self.goalentity && self.goalentity.health > 0) {
15001
+ } else {
15002
+ self.monsterinfo.current_move = fixbot_move_stand;
15003
+ }
15004
+ }
15005
+ var frames_stand3 = Array(19).fill({ ai: monster_ai_move22, dist: 0 });
15006
+ frames_stand3[18] = { ai: monster_ai_move22, dist: 0, think: fixbot_search };
15007
+ fixbot_move_stand = {
15008
+ firstframe: 58,
15009
+ // FRAME_ambient_01
15010
+ lastframe: 76,
15011
+ frames: frames_stand3,
15012
+ endfunc: null
15013
+ };
15014
+ var frames_walk3 = [
15015
+ { ai: monster_ai_walk21, dist: 5 }
15016
+ ];
15017
+ fixbot_move_walk = {
15018
+ firstframe: 0,
15019
+ lastframe: 0,
15020
+ frames: frames_walk3,
15021
+ endfunc: null
15022
+ };
15023
+ var frames_run3 = [
15024
+ { ai: monster_ai_run22, dist: 10 }
15025
+ ];
15026
+ fixbot_move_run = {
15027
+ firstframe: 0,
15028
+ lastframe: 0,
15029
+ frames: frames_run3,
15030
+ endfunc: null
15031
+ };
15032
+ var frames_attack22 = Array(31).fill({ ai: monster_ai_charge23, dist: 0 });
15033
+ frames_attack22[20] = { ai: monster_ai_charge23, dist: 0, think: fixbot_fire_blaster_func };
15034
+ fixbot_move_attack2 = {
15035
+ firstframe: 121,
15036
+ // FRAME_charging_01
15037
+ lastframe: 151,
15038
+ frames: frames_attack22,
15039
+ endfunc: fixbot_run
15040
+ };
15041
+ var frames_laserattack = Array(6).fill({ ai: monster_ai_charge23, dist: 0, think: fixbot_fire_laser });
15042
+ fixbot_move_laserattack = {
15043
+ firstframe: 115,
15044
+ // FRAME_shoot_01
15045
+ lastframe: 120,
15046
+ frames: frames_laserattack,
15047
+ endfunc: null
15048
+ // Loops or handled by AI?
15049
+ };
15050
+ var frames_weld_start = Array(10).fill({ ai: monster_ai_move22, dist: 0 });
15051
+ frames_weld_start[9] = { ai: monster_ai_move22, dist: 0, think: weldstate };
15052
+ fixbot_move_weld_start = {
15053
+ firstframe: 77,
15054
+ // FRAME_weldstart_01
15055
+ lastframe: 86,
15056
+ frames: frames_weld_start,
15057
+ endfunc: null
15058
+ };
15059
+ var frames_weld = Array(7).fill({ ai: monster_ai_move22, dist: 0, think: fixbot_fire_welder });
15060
+ frames_weld[6] = { ai: monster_ai_move22, dist: 0, think: weldstate };
15061
+ fixbot_move_weld = {
15062
+ firstframe: 87,
15063
+ // FRAME_weldmiddle_01
15064
+ lastframe: 93,
15065
+ frames: frames_weld,
15066
+ endfunc: null
15067
+ };
15068
+ var frames_weld_end = Array(7).fill({ ai: monster_ai_move22, dist: -2 });
15069
+ frames_weld_end[6] = { ai: monster_ai_move22, dist: -2, think: weldstate };
15070
+ fixbot_move_weld_end = {
15071
+ firstframe: 94,
15072
+ // FRAME_weldend_01
15073
+ lastframe: 100,
15074
+ frames: frames_weld_end,
15075
+ endfunc: null
15076
+ };
15077
+ var frames_start_attack = [
15078
+ { ai: monster_ai_charge23, dist: 0 }
15079
+ ];
15080
+ fixbot_move_start_attack = {
15081
+ firstframe: 0,
15082
+ lastframe: 0,
15083
+ frames: frames_start_attack,
15084
+ endfunc: fixbot_attack
15085
+ };
15086
+ var frames_pain32 = [
15087
+ { ai: monster_ai_move22, dist: -1 }
15088
+ ];
15089
+ fixbot_move_pain3 = {
15090
+ firstframe: 0,
15091
+ lastframe: 0,
15092
+ frames: frames_pain32,
15093
+ endfunc: fixbot_run
15094
+ };
15095
+ var frames_painb = Array(8).fill({ ai: monster_ai_move22, dist: 0 });
15096
+ fixbot_move_painb = {
15097
+ firstframe: 107,
15098
+ // FRAME_painb_01
15099
+ lastframe: 114,
15100
+ frames: frames_painb,
15101
+ endfunc: fixbot_run
15102
+ };
15103
+ var frames_paina = Array(6).fill({ ai: monster_ai_move22, dist: 0 });
15104
+ fixbot_move_paina = {
15105
+ firstframe: 101,
15106
+ // FRAME_paina_01
15107
+ lastframe: 106,
15108
+ frames: frames_paina,
15109
+ endfunc: fixbot_run
15110
+ };
15111
+ function SP_monster_fixbot(self, context) {
15112
+ self.classname = "monster_fixbot";
15113
+ self.model = "models/monsters/fixbot/tris.md2";
15114
+ self.mins = { x: -32, y: -32, z: -24 };
15115
+ self.maxs = { x: 32, y: 32, z: 24 };
15116
+ self.movetype = 5 /* Step */;
15117
+ self.solid = 2 /* BoundingBox */;
15118
+ self.health = 150;
15119
+ self.mass = 150;
15120
+ self.pain = (e, o, k, d) => fixbot_pain(e, o, k, d, context.entities);
15121
+ self.die = (e, i, a, d, p, m3) => fixbot_die(e, i, a, d, p, m3, context.entities);
15122
+ self.monsterinfo.stand = fixbot_stand;
15123
+ self.monsterinfo.walk = fixbot_walk;
15124
+ self.monsterinfo.run = fixbot_run;
15125
+ self.monsterinfo.attack = fixbot_start_attack;
15126
+ context.entities.linkentity(self);
15127
+ self.monsterinfo.current_move = fixbot_move_stand;
15128
+ self.think = monster_think;
15129
+ self.nextthink = context.entities.timeSeconds + MONSTER_TICK25;
15130
+ self.flags |= 1 /* Fly */;
15131
+ }
15132
+ function registerFixbotSpawns(registry) {
15133
+ registry.register("monster_fixbot", SP_monster_fixbot);
15134
+ }
15135
+
14081
15136
  // src/entities/monsters/index.ts
14082
15137
  function registerMonsterSpawns2(registry) {
14083
15138
  registerMonsterSpawns(registry);
@@ -14104,6 +15159,8 @@ function registerMonsterSpawns2(registry) {
14104
15159
  registerMakronSpawns(registry);
14105
15160
  registerInsaneSpawns(registry);
14106
15161
  registerActorSpawns(registry);
15162
+ registerGekkSpawns(registry);
15163
+ registerFixbotSpawns(registry);
14107
15164
  }
14108
15165
 
14109
15166
  // src/entities/worldspawn.ts
@@ -15414,7 +16471,7 @@ function PlayerNoise(who, where, type, context) {
15414
16471
  }
15415
16472
 
15416
16473
  // src/combat/obituary.ts
15417
- var random8 = createRandomGenerator();
16474
+ var random10 = createRandomGenerator();
15418
16475
  var PRINT_MEDIUM = 1;
15419
16476
  function getGender(ent) {
15420
16477
  return "male";
@@ -15577,7 +16634,7 @@ var ANIM_PAIN = 2;
15577
16634
  var ANIM_DEATH = 3;
15578
16635
 
15579
16636
  // src/combat/weapons/firing.ts
15580
- var random9 = createRandomGenerator();
16637
+ var random11 = createRandomGenerator();
15581
16638
 
15582
16639
  // src/entities/player.ts
15583
16640
  function P_PlayerThink(ent, sys) {
@@ -15634,7 +16691,7 @@ function player_pain(self, damage) {
15634
16691
  return;
15635
16692
  }
15636
16693
  self.client.anim_priority = ANIM_PAIN;
15637
- const r = random9.frandom();
16694
+ const r = random11.frandom();
15638
16695
  if (r < 0.33) {
15639
16696
  self.frame = FRAME_pain1012;
15640
16697
  self.client.anim_end = FRAME_pain104;
@@ -15657,7 +16714,7 @@ function player_die(self, inflictor, attacker, damage, point, mod, sys) {
15657
16714
  }
15658
16715
  if (self.client) {
15659
16716
  self.client.anim_priority = ANIM_DEATH;
15660
- const r = random9.frandom();
16717
+ const r = random11.frandom();
15661
16718
  if (r < 0.33) {
15662
16719
  self.frame = FRAME_death1012;
15663
16720
  self.client.anim_end = FRAME_death106;
@@ -15710,25 +16767,12 @@ function player_think(self, sys) {
15710
16767
  }
15711
16768
 
15712
16769
  // src/entities/playerStats.ts
15713
- var WEAPON_WHEEL_ORDER = [
15714
- "blaster" /* Blaster */,
15715
- "shotgun" /* Shotgun */,
15716
- "supershotgun" /* SuperShotgun */,
15717
- "machinegun" /* Machinegun */,
15718
- "chaingun" /* Chaingun */,
15719
- "grenadelauncher" /* GrenadeLauncher */,
15720
- "rocketlauncher" /* RocketLauncher */,
15721
- "grenades" /* HandGrenade */,
15722
- "hyperblaster" /* HyperBlaster */,
15723
- "railgun" /* Railgun */,
15724
- "bfg10k" /* BFG10K */
15725
- ];
15726
16770
  var POWERUP_TIMERS = [
15727
- { id: "quad" /* QuadDamage */, priority: 1 },
15728
- { id: "invulnerability" /* Invulnerability */, priority: 2 },
15729
- { id: "enviro" /* EnviroSuit */, priority: 3 },
15730
- { id: "rebreather" /* Rebreather */, priority: 4 },
15731
- { id: "silencer" /* Silencer */, priority: 5 }
16771
+ { id: PowerupId.QuadDamage, priority: 1 },
16772
+ { id: PowerupId.Invulnerability, priority: 2 },
16773
+ { id: PowerupId.EnviroSuit, priority: 3 },
16774
+ { id: PowerupId.Rebreather, priority: 4 },
16775
+ { id: PowerupId.Silencer, priority: 5 }
15732
16776
  ];
15733
16777
  function populatePlayerStats(player, timeSeconds) {
15734
16778
  if (!player.client) return [];
@@ -15747,6 +16791,12 @@ function populatePlayerStats(player, timeSeconds) {
15747
16791
  }
15748
16792
  statArray[PlayerStat.STAT_WEAPONS_OWNED_1] = weaponBits & 65535;
15749
16793
  statArray[PlayerStat.STAT_WEAPONS_OWNED_2] = weaponBits >> 16 & 65535;
16794
+ if (inventory.currentWeapon) {
16795
+ const index = WEAPON_WHEEL_ORDER.indexOf(inventory.currentWeapon);
16796
+ if (index !== -1) {
16797
+ statArray[PlayerStat.STAT_ACTIVE_WHEEL_WEAPON] = index;
16798
+ }
16799
+ }
15750
16800
  statArray[PlayerStat.STAT_AMMO] = 0;
15751
16801
  if (inventory.currentWeapon) {
15752
16802
  const weaponItem = Object.values(WEAPON_ITEMS).find((item) => item.weaponId === inventory.currentWeapon);
@@ -16051,7 +17101,7 @@ var WEAPONS = {
16051
17101
  };
16052
17102
 
16053
17103
  // src/index.ts
16054
- var ZERO_VEC36 = { x: 0, y: 0, z: 0 };
17104
+ var ZERO_VEC37 = { x: 0, y: 0, z: 0 };
16055
17105
  function createGame(imports, engine, options) {
16056
17106
  const gravity = options.gravity;
16057
17107
  const deathmatch = options.deathmatch ?? false;
@@ -16120,26 +17170,26 @@ function createGame(imports, engine, options) {
16120
17170
  };
16121
17171
  entities.runFrame();
16122
17172
  });
16123
- let origin = { ...ZERO_VEC36 };
16124
- let velocity = { ...ZERO_VEC36 };
17173
+ let origin = { ...ZERO_VEC37 };
17174
+ let velocity = { ...ZERO_VEC37 };
16125
17175
  const calculateBlend = (player, time) => {
16126
17176
  const blend = [0, 0, 0, 0];
16127
17177
  if (!player || !player.client) return blend;
16128
17178
  const inventory = player.client.inventory;
16129
- if (inventory.powerups.has("quad" /* QuadDamage */)) {
17179
+ if (inventory.powerups.has(PowerupId.QuadDamage)) {
16130
17180
  blend[2] = 1;
16131
17181
  blend[3] = 0.08;
16132
17182
  }
16133
- if (inventory.powerups.has("invulnerability" /* Invulnerability */)) {
17183
+ if (inventory.powerups.has(PowerupId.Invulnerability)) {
16134
17184
  blend[0] = 1;
16135
17185
  blend[1] = 1;
16136
17186
  blend[3] = 0.08;
16137
17187
  }
16138
- if (inventory.powerups.has("enviro" /* EnviroSuit */)) {
17188
+ if (inventory.powerups.has(PowerupId.EnviroSuit)) {
16139
17189
  blend[1] = 1;
16140
17190
  blend[3] = 0.08;
16141
17191
  }
16142
- if (inventory.powerups.has("rebreather" /* Rebreather */)) {
17192
+ if (inventory.powerups.has(PowerupId.Rebreather)) {
16143
17193
  blend[0] = 0.4;
16144
17194
  blend[1] = 1;
16145
17195
  blend[2] = 0.4;
@@ -16203,10 +17253,10 @@ function createGame(imports, engine, options) {
16203
17253
  // TODO
16204
17254
  damageIndicators: [],
16205
17255
  stats: player ? populatePlayerStats(player, levelClock.current.timeSeconds) : [],
16206
- kick_angles: player?.client?.kick_angles ?? ZERO_VEC36,
16207
- kick_origin: player?.client?.kick_origin ?? ZERO_VEC36,
16208
- gunoffset: ZERO_VEC36,
16209
- gunangles: ZERO_VEC36,
17256
+ kick_angles: player?.client?.kick_angles ?? ZERO_VEC37,
17257
+ kick_origin: player?.client?.kick_origin ?? ZERO_VEC37,
17258
+ gunoffset: ZERO_VEC37,
17259
+ gunangles: ZERO_VEC37,
16210
17260
  gunindex: 0,
16211
17261
  gun_frame: player?.client?.gun_frame ?? 0,
16212
17262
  rdflags: player?.client?.rdflags ?? 0,
@@ -16220,8 +17270,8 @@ function createGame(imports, engine, options) {
16220
17270
  const resetState = (startTimeMs) => {
16221
17271
  frameLoop.reset(startTimeMs);
16222
17272
  levelClock.start(startTimeMs);
16223
- origin = { ...ZERO_VEC36 };
16224
- velocity = { ...ZERO_VEC36 };
17273
+ origin = { ...ZERO_VEC37 };
17274
+ velocity = { ...ZERO_VEC37 };
16225
17275
  entities.beginFrame(startTimeMs / 1e3);
16226
17276
  entities.runFrame();
16227
17277
  };
@@ -16249,10 +17299,10 @@ function createGame(imports, engine, options) {
16249
17299
  blend: [0, 0, 0, 0],
16250
17300
  // Stubs
16251
17301
  stats: populatePlayerStats(player, levelClock.current.timeSeconds),
16252
- kick_angles: ZERO_VEC36,
16253
- kick_origin: ZERO_VEC36,
16254
- gunoffset: ZERO_VEC36,
16255
- gunangles: ZERO_VEC36,
17302
+ kick_angles: ZERO_VEC37,
17303
+ kick_origin: ZERO_VEC37,
17304
+ gunoffset: ZERO_VEC37,
17305
+ gunangles: ZERO_VEC37,
16256
17306
  gunindex: 0,
16257
17307
  pm_type: 0,
16258
17308
  pm_time: 0,
@@ -16382,8 +17432,8 @@ function createGame(imports, engine, options) {
16382
17432
  rng,
16383
17433
  player: player?.client?.inventory
16384
17434
  });
16385
- origin = player ? { ...player.origin } : { ...ZERO_VEC36 };
16386
- velocity = player ? { ...player.velocity } : { ...ZERO_VEC36 };
17435
+ origin = player ? { ...player.origin } : { ...ZERO_VEC37 };
17436
+ velocity = player ? { ...player.velocity } : { ...ZERO_VEC37 };
16387
17437
  frameLoop.reset(save.level.timeSeconds * 1e3);
16388
17438
  }
16389
17439
  };