quake2ts 0.0.216 → 0.0.217

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.
@@ -1557,6 +1557,7 @@ var MoveType = /* @__PURE__ */ ((MoveType3) => {
1557
1557
  MoveType3[MoveType3["Toss"] = 7] = "Toss";
1558
1558
  MoveType3[MoveType3["FlyMissile"] = 8] = "FlyMissile";
1559
1559
  MoveType3[MoveType3["Bounce"] = 9] = "Bounce";
1560
+ MoveType3[MoveType3["WallBounce"] = 10] = "WallBounce";
1560
1561
  return MoveType3;
1561
1562
  })(MoveType || {});
1562
1563
  var Solid = /* @__PURE__ */ ((Solid3) => {
@@ -2434,7 +2435,7 @@ function checkTriggers(ent, system) {
2434
2435
 
2435
2436
  // src/physics/movement.ts
2436
2437
  function runGravity(ent, gravity, frametime) {
2437
- if (ent.movetype === 7 /* Toss */) {
2438
+ if (ent.movetype === 7 /* Toss */ || ent.movetype === 9 /* Bounce */ || ent.movetype === 10 /* WallBounce */) {
2438
2439
  if (!ent.velocity) ent.velocity = { x: 0, y: 0, z: 0 };
2439
2440
  if (!ent.origin) ent.origin = { x: 0, y: 0, z: 0 };
2440
2441
  if (ent.waterlevel > 1) {
@@ -2457,7 +2458,7 @@ function runGravity(ent, gravity, frametime) {
2457
2458
  }
2458
2459
  }
2459
2460
  function runBouncing(ent, imports, frametime) {
2460
- if (ent.movetype !== 9 /* Bounce */) {
2461
+ if (ent.movetype !== 9 /* Bounce */ && ent.movetype !== 10 /* WallBounce */) {
2461
2462
  return;
2462
2463
  }
2463
2464
  if (!ent.velocity) ent.velocity = { x: 0, y: 0, z: 0 };
@@ -2468,8 +2469,17 @@ function runBouncing(ent, imports, frametime) {
2468
2469
  ent.origin = traceResult.endpos;
2469
2470
  }
2470
2471
  if (traceResult.fraction > 0 && traceResult.fraction < 1 && traceResult.plane) {
2471
- const clipped = clipVelocityVec3(ent.velocity, traceResult.plane.normal, 1.01);
2472
- ent.velocity = scaleVec3(clipped, ent.bounce);
2472
+ let overbounce = 1.01;
2473
+ if (ent.movetype === 10 /* WallBounce */) {
2474
+ overbounce = 2;
2475
+ } else {
2476
+ overbounce = 1.6;
2477
+ }
2478
+ const clipped = clipVelocityVec3(ent.velocity, traceResult.plane.normal, overbounce);
2479
+ ent.velocity = clipped;
2480
+ if (ent.movetype === 10 /* WallBounce */) {
2481
+ ent.angles = vectorToAngles(ent.velocity);
2482
+ }
2473
2483
  }
2474
2484
  }
2475
2485
  function runStep(ent, system, imports, gravity, frametime) {
@@ -5881,7 +5891,15 @@ function createGrenade(sys, owner, start, dir, damage, speed) {
5881
5891
  }
5882
5892
  function createBlasterBolt(sys, owner, start, dir, damage, speed, mod) {
5883
5893
  const bolt = sys.spawn();
5884
- bolt.classname = mod === 10 /* HYPERBLASTER */ ? "hyperblaster_bolt" : "blaster_bolt";
5894
+ if (mod === 10 /* HYPERBLASTER */) {
5895
+ bolt.classname = "hyperblaster_bolt";
5896
+ } else if (mod === 58 /* BLUEBLASTER */) {
5897
+ bolt.classname = "blueblaster_bolt";
5898
+ bolt.modelindex = sys.modelIndex("models/objects/laser/tris.md2");
5899
+ bolt.skin = 1;
5900
+ } else {
5901
+ bolt.classname = "blaster_bolt";
5902
+ }
5885
5903
  bolt.owner = owner;
5886
5904
  bolt.origin = { ...start };
5887
5905
  bolt.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
@@ -5911,13 +5929,61 @@ function createBlasterBolt(sys, owner, start, dir, damage, speed, mod) {
5911
5929
  );
5912
5930
  } else {
5913
5931
  if (plane) {
5914
- sys.multicast(self.origin, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.BLASTER, self.origin, plane.normal);
5932
+ let impactEffect = TempEntity.BLASTER;
5933
+ if (mod === 58 /* BLUEBLASTER */) {
5934
+ impactEffect = TempEntity.BLUEHYPERBLASTER;
5935
+ }
5936
+ sys.multicast(self.origin, 1 /* Pvs */, ServerCommand.temp_entity, impactEffect, self.origin, plane.normal);
5915
5937
  }
5916
5938
  }
5917
5939
  sys.free(self);
5918
5940
  };
5919
5941
  sys.finalizeSpawn(bolt);
5920
5942
  }
5943
+ function createIonRipper(sys, owner, start, dir, damage, speed) {
5944
+ const ion = sys.spawn();
5945
+ ion.classname = "ionripper";
5946
+ ion.owner = owner;
5947
+ ion.origin = { ...start };
5948
+ ion.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
5949
+ ion.movetype = 10 /* WallBounce */;
5950
+ ion.solid = 2 /* BoundingBox */;
5951
+ ion.modelindex = sys.modelIndex("models/objects/boomrang/tris.md2");
5952
+ ion.mins = { x: -2, y: -2, z: -2 };
5953
+ ion.maxs = { x: 2, y: 2, z: 2 };
5954
+ ion.touch = (self, other, plane, surf) => {
5955
+ if (other === self.owner) {
5956
+ return;
5957
+ }
5958
+ if (other && other.takedamage) {
5959
+ T_Damage(
5960
+ other,
5961
+ self,
5962
+ self.owner,
5963
+ self.velocity,
5964
+ self.origin,
5965
+ plane ? plane.normal : ZERO_VEC3,
5966
+ damage,
5967
+ 1,
5968
+ 4 /* ENERGY */,
5969
+ 35 /* RIPPER */,
5970
+ sys.timeSeconds,
5971
+ sys.multicast.bind(sys)
5972
+ );
5973
+ sys.free(self);
5974
+ return;
5975
+ }
5976
+ };
5977
+ ion.think = (self) => {
5978
+ sys.multicast(self.origin, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.WELDING_SPARKS, self.origin, ZERO_VEC3, 228);
5979
+ sys.free(self);
5980
+ };
5981
+ sys.scheduleThink(ion, sys.timeSeconds + 3);
5982
+ sys.finalizeSpawn(ion);
5983
+ }
5984
+ function createBlueBlaster(sys, owner, start, dir, damage, speed) {
5985
+ createBlasterBolt(sys, owner, start, dir, damage, speed, 58 /* BLUEBLASTER */);
5986
+ }
5921
5987
  function fireBfgPiercingLaser(sys, bfg, target, damage) {
5922
5988
  const start = { ...bfg.origin };
5923
5989
  const targetCenter2 = {
@@ -6176,6 +6242,12 @@ function monster_fire_shotgun(self, start, aimdir, damage, kick, hspread, vsprea
6176
6242
  function monster_fire_blaster(self, start, dir, damage, speed, flashtype, effect, context, mod = 1 /* BLASTER */) {
6177
6243
  createBlasterBolt(context, self, start, dir, damage, speed, mod);
6178
6244
  }
6245
+ function monster_fire_blueblaster(self, start, dir, damage, speed, flashtype, effect, context) {
6246
+ createBlueBlaster(context, self, start, dir, damage, speed);
6247
+ }
6248
+ function monster_fire_ionripper(self, start, dir, damage, speed, flashtype, effect, context) {
6249
+ createIonRipper(context, self, start, dir, damage, speed);
6250
+ }
6179
6251
  function monster_fire_grenade(self, start, aim, damage, speed, flashtype, context) {
6180
6252
  createGrenade(context, self, start, aim, damage, speed);
6181
6253
  }
@@ -6238,12 +6310,36 @@ function monster_fire_heat(self, start, dir, damage, speed, flashtype, turn_frac
6238
6310
  function dabeam_update(self, context) {
6239
6311
  const start = { ...self.origin };
6240
6312
  const end = addVec3(start, scaleVec3(self.movedir, 2048));
6241
- const tr = context.trace(start, end, ZERO_VEC3, ZERO_VEC3, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_DEADMONSTER);
6242
- if (self.dmg > 0 && tr.ent && tr.ent.takedamage && tr.ent !== self.owner) {
6243
- T_Damage(tr.ent, self, self.owner, self.movedir, tr.endpos, ZERO_VEC3, self.dmg, 0, 4 /* ENERGY */, 31 /* TARGET_LASER */, context.timeSeconds);
6244
- }
6245
- if (tr.ent && tr.ent.solid === 3 /* Bsp */) {
6246
- context.multicast(tr.endpos, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.LASER_SPARKS, 10, tr.endpos, tr.plane?.normal || ZERO_VEC3, self.skin);
6313
+ let currentStart = { ...start };
6314
+ const MAX_PIERCE = 16;
6315
+ const pierced = [];
6316
+ const piercedSolidities = [];
6317
+ try {
6318
+ for (let i = 0; i < MAX_PIERCE; i++) {
6319
+ const tr = context.trace(currentStart, end, ZERO_VEC3, ZERO_VEC3, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_DEADMONSTER);
6320
+ if (!tr.ent || tr.fraction >= 1) {
6321
+ break;
6322
+ }
6323
+ if (self.dmg > 0 && tr.ent.takedamage && tr.ent !== self.owner) {
6324
+ T_Damage(tr.ent, self, self.owner, self.movedir, tr.endpos, ZERO_VEC3, self.dmg, 0, 4 /* ENERGY */, 31 /* TARGET_LASER */, context.timeSeconds);
6325
+ }
6326
+ if (tr.ent && tr.ent.solid === 3 /* Bsp */) {
6327
+ context.multicast(tr.endpos, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.LASER_SPARKS, 10, tr.endpos, tr.plane?.normal || ZERO_VEC3, self.skin);
6328
+ break;
6329
+ }
6330
+ if (tr.ent && (tr.ent.takedamage || tr.ent.client)) {
6331
+ pierced.push(tr.ent);
6332
+ piercedSolidities.push(tr.ent.solid);
6333
+ tr.ent.solid = 0 /* Not */;
6334
+ currentStart = { ...tr.endpos };
6335
+ continue;
6336
+ }
6337
+ break;
6338
+ }
6339
+ } finally {
6340
+ for (let i = 0; i < pierced.length; i++) {
6341
+ pierced[i].solid = piercedSolidities[i];
6342
+ }
6247
6343
  }
6248
6344
  context.linkentity(self);
6249
6345
  }
@@ -6266,11 +6362,7 @@ function monster_fire_dabeam(self, damage, secondary, update_func, context) {
6266
6362
  beam.owner = self;
6267
6363
  beam.dmg = damage;
6268
6364
  beam.frame = 2;
6269
- if (self.monsterinfo.aiflags & 64) {
6270
- beam.skin = 4092850673;
6271
- } else {
6272
- beam.skin = 4076007664;
6273
- }
6365
+ beam.skin = 4076007664;
6274
6366
  beam.think = (ent, ctx) => {
6275
6367
  if (ent.postthink) {
6276
6368
  ent.postthink(ent, ctx);
@@ -10468,6 +10560,8 @@ function soldier_run(self) {
10468
10560
  function soldier_attack(self) {
10469
10561
  if (self.spawnflags & SOLDIER_MACHINEGUN) {
10470
10562
  self.monsterinfo.current_move = attack_move_mg;
10563
+ } else if (self.style === 1 && self.count >= 4) {
10564
+ self.monsterinfo.current_move = attack_move_mg;
10471
10565
  } else {
10472
10566
  self.monsterinfo.current_move = attack_move8;
10473
10567
  }
@@ -10526,9 +10620,59 @@ function soldier_fire_machinegun(self, context) {
10526
10620
  context.engine.sound?.(self, 0, "soldier/solatck3.wav", 1, 1, 0);
10527
10621
  monster_fire_bullet(self, start, forward, damage, kick, hspread, vspread, 0, context, 4 /* MACHINEGUN */);
10528
10622
  }
10623
+ function soldierh_laser_update(beam, context) {
10624
+ const self = beam.owner;
10625
+ if (!self || !self.enemy) return;
10626
+ const { forward, right, up } = angleVectors(self.angles);
10627
+ let start = { ...self.origin };
10628
+ start = addVec3(start, scaleVec3(forward, 16));
10629
+ start.z += self.viewheight;
10630
+ const enemyCenter = { ...self.enemy.origin };
10631
+ enemyCenter.z += self.enemy.viewheight || 0;
10632
+ const dir = normalizeVec3(subtractVec3(enemyCenter, start));
10633
+ beam.origin = start;
10634
+ beam.movedir = dir;
10635
+ context.linkentity(beam);
10636
+ }
10637
+ function soldier_fire_ripper(self, context) {
10638
+ if (!self.enemy) return;
10639
+ const start = get_fire_start(self);
10640
+ const forward = get_fire_dir(self, start);
10641
+ const damage = 5;
10642
+ const speed = 600;
10643
+ monster_fire_ionripper(self, start, forward, damage, speed, 0, 0, context);
10644
+ }
10645
+ function soldier_fire_hypergun(self, context) {
10646
+ if (!self.enemy) return;
10647
+ const start = get_fire_start(self);
10648
+ const forward = get_fire_dir(self, start);
10649
+ const damage = 1;
10650
+ const speed = 600;
10651
+ context.engine.sound?.(self, 0, "weapons/hyprbl1a.wav", 1, 1, 0);
10652
+ monster_fire_blueblaster(self, start, forward, damage, speed, 0, 0, context);
10653
+ }
10654
+ function soldier_fire_laser(self, context) {
10655
+ if (!self.enemy) return;
10656
+ monster_fire_dabeam(self, 1, false, soldierh_laser_update, context);
10657
+ }
10658
+ function soldier_fire_xatrix(self, context) {
10659
+ if (self.count < 2) {
10660
+ soldier_fire_ripper(self, context);
10661
+ } else if (self.count < 4) {
10662
+ soldier_fire_hypergun(self, context);
10663
+ } else {
10664
+ soldier_fire_laser(self, context);
10665
+ }
10666
+ }
10529
10667
  function soldier_fire(self, context) {
10668
+ if (self.style === 1) {
10669
+ soldier_fire_xatrix(self, context);
10670
+ return;
10671
+ }
10530
10672
  if (self.spawnflags & SOLDIER_SSG) {
10531
10673
  soldier_fire_ssg(self, context);
10674
+ } else if (self.spawnflags & SOLDIER_MACHINEGUN) {
10675
+ soldier_fire_machinegun(self, context);
10532
10676
  } else {
10533
10677
  soldier_fire_blaster(self, context);
10534
10678
  }
@@ -10578,7 +10722,10 @@ var attack_frames_mg = Array.from({ length: 10 }, (_, i) => ({
10578
10722
  ai: monster_ai_charge18,
10579
10723
  dist: 0,
10580
10724
  // Fire on frames 4, 5, 6, 7, 8
10581
- think: i >= 4 && i <= 8 ? soldier_fire_machinegun : null
10725
+ // Note: Laser soldier fires continuously?
10726
+ // C++: soldierh_hyperripper8 called on frames 11, 13, 18?
10727
+ // Actually laser soldier (machinegun equivalent) fires on frames 4-8.
10728
+ think: i >= 4 && i <= 8 ? soldier_fire : null
10582
10729
  }));
10583
10730
  attack_move_mg = {
10584
10731
  firstframe: 90,
@@ -10679,10 +10826,33 @@ function SP_monster_soldier_ssg(self, context) {
10679
10826
  self.spawnflags |= SOLDIER_SSG;
10680
10827
  SP_monster_soldier(self, context);
10681
10828
  }
10829
+ function SP_monster_soldier_x(self, context, skin, health) {
10830
+ SP_monster_soldier(self, context);
10831
+ self.style = 1;
10832
+ self.skin = skin;
10833
+ self.count = skin - 6;
10834
+ self.health = health;
10835
+ self.max_health = health;
10836
+ }
10837
+ function SP_monster_soldier_ripper(self, context) {
10838
+ SP_monster_soldier_x(self, context, 6, 50);
10839
+ self.model = "models/monsters/soldier/tris.md2";
10840
+ }
10841
+ function SP_monster_soldier_hypergun(self, context) {
10842
+ SP_monster_soldier_x(self, context, 8, 60);
10843
+ self.model = "models/monsters/soldier/tris.md2";
10844
+ }
10845
+ function SP_monster_soldier_lasergun(self, context) {
10846
+ SP_monster_soldier_x(self, context, 10, 70);
10847
+ self.model = "models/monsters/soldier/tris.md2";
10848
+ }
10682
10849
  function registerMonsterSpawns(registry) {
10683
10850
  registry.register("monster_soldier", SP_monster_soldier);
10684
10851
  registry.register("monster_soldier_light", SP_monster_soldier_light);
10685
10852
  registry.register("monster_soldier_ssg", SP_monster_soldier_ssg);
10853
+ registry.register("monster_soldier_ripper", SP_monster_soldier_ripper);
10854
+ registry.register("monster_soldier_hypergun", SP_monster_soldier_hypergun);
10855
+ registry.register("monster_soldier_lasergun", SP_monster_soldier_lasergun);
10686
10856
  }
10687
10857
 
10688
10858
  // src/entities/monsters/supertank.ts