quake2ts 0.0.215 → 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.
@@ -1723,6 +1723,7 @@ var MoveType = /* @__PURE__ */ ((MoveType3) => {
1723
1723
  MoveType3[MoveType3["Toss"] = 7] = "Toss";
1724
1724
  MoveType3[MoveType3["FlyMissile"] = 8] = "FlyMissile";
1725
1725
  MoveType3[MoveType3["Bounce"] = 9] = "Bounce";
1726
+ MoveType3[MoveType3["WallBounce"] = 10] = "WallBounce";
1726
1727
  return MoveType3;
1727
1728
  })(MoveType || {});
1728
1729
  var Solid = /* @__PURE__ */ ((Solid3) => {
@@ -2600,7 +2601,7 @@ function checkTriggers(ent, system) {
2600
2601
 
2601
2602
  // src/physics/movement.ts
2602
2603
  function runGravity(ent, gravity, frametime) {
2603
- if (ent.movetype === 7 /* Toss */) {
2604
+ if (ent.movetype === 7 /* Toss */ || ent.movetype === 9 /* Bounce */ || ent.movetype === 10 /* WallBounce */) {
2604
2605
  if (!ent.velocity) ent.velocity = { x: 0, y: 0, z: 0 };
2605
2606
  if (!ent.origin) ent.origin = { x: 0, y: 0, z: 0 };
2606
2607
  if (ent.waterlevel > 1) {
@@ -2623,7 +2624,7 @@ function runGravity(ent, gravity, frametime) {
2623
2624
  }
2624
2625
  }
2625
2626
  function runBouncing(ent, imports, frametime) {
2626
- if (ent.movetype !== 9 /* Bounce */) {
2627
+ if (ent.movetype !== 9 /* Bounce */ && ent.movetype !== 10 /* WallBounce */) {
2627
2628
  return;
2628
2629
  }
2629
2630
  if (!ent.velocity) ent.velocity = { x: 0, y: 0, z: 0 };
@@ -2634,8 +2635,17 @@ function runBouncing(ent, imports, frametime) {
2634
2635
  ent.origin = traceResult.endpos;
2635
2636
  }
2636
2637
  if (traceResult.fraction > 0 && traceResult.fraction < 1 && traceResult.plane) {
2637
- const clipped = clipVelocityVec3(ent.velocity, traceResult.plane.normal, 1.01);
2638
- ent.velocity = scaleVec3(clipped, ent.bounce);
2638
+ let overbounce = 1.01;
2639
+ if (ent.movetype === 10 /* WallBounce */) {
2640
+ overbounce = 2;
2641
+ } else {
2642
+ overbounce = 1.6;
2643
+ }
2644
+ const clipped = clipVelocityVec3(ent.velocity, traceResult.plane.normal, overbounce);
2645
+ ent.velocity = clipped;
2646
+ if (ent.movetype === 10 /* WallBounce */) {
2647
+ ent.angles = vectorToAngles(ent.velocity);
2648
+ }
2639
2649
  }
2640
2650
  }
2641
2651
  function runStep(ent, system, imports, gravity, frametime) {
@@ -6047,7 +6057,15 @@ function createGrenade(sys, owner, start, dir, damage, speed) {
6047
6057
  }
6048
6058
  function createBlasterBolt(sys, owner, start, dir, damage, speed, mod) {
6049
6059
  const bolt = sys.spawn();
6050
- bolt.classname = mod === 10 /* HYPERBLASTER */ ? "hyperblaster_bolt" : "blaster_bolt";
6060
+ if (mod === 10 /* HYPERBLASTER */) {
6061
+ bolt.classname = "hyperblaster_bolt";
6062
+ } else if (mod === 58 /* BLUEBLASTER */) {
6063
+ bolt.classname = "blueblaster_bolt";
6064
+ bolt.modelindex = sys.modelIndex("models/objects/laser/tris.md2");
6065
+ bolt.skin = 1;
6066
+ } else {
6067
+ bolt.classname = "blaster_bolt";
6068
+ }
6051
6069
  bolt.owner = owner;
6052
6070
  bolt.origin = { ...start };
6053
6071
  bolt.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
@@ -6077,13 +6095,61 @@ function createBlasterBolt(sys, owner, start, dir, damage, speed, mod) {
6077
6095
  );
6078
6096
  } else {
6079
6097
  if (plane) {
6080
- sys.multicast(self.origin, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.BLASTER, self.origin, plane.normal);
6098
+ let impactEffect = TempEntity.BLASTER;
6099
+ if (mod === 58 /* BLUEBLASTER */) {
6100
+ impactEffect = TempEntity.BLUEHYPERBLASTER;
6101
+ }
6102
+ sys.multicast(self.origin, 1 /* Pvs */, ServerCommand.temp_entity, impactEffect, self.origin, plane.normal);
6081
6103
  }
6082
6104
  }
6083
6105
  sys.free(self);
6084
6106
  };
6085
6107
  sys.finalizeSpawn(bolt);
6086
6108
  }
6109
+ function createIonRipper(sys, owner, start, dir, damage, speed) {
6110
+ const ion = sys.spawn();
6111
+ ion.classname = "ionripper";
6112
+ ion.owner = owner;
6113
+ ion.origin = { ...start };
6114
+ ion.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
6115
+ ion.movetype = 10 /* WallBounce */;
6116
+ ion.solid = 2 /* BoundingBox */;
6117
+ ion.modelindex = sys.modelIndex("models/objects/boomrang/tris.md2");
6118
+ ion.mins = { x: -2, y: -2, z: -2 };
6119
+ ion.maxs = { x: 2, y: 2, z: 2 };
6120
+ ion.touch = (self, other, plane, surf) => {
6121
+ if (other === self.owner) {
6122
+ return;
6123
+ }
6124
+ if (other && other.takedamage) {
6125
+ T_Damage(
6126
+ other,
6127
+ self,
6128
+ self.owner,
6129
+ self.velocity,
6130
+ self.origin,
6131
+ plane ? plane.normal : ZERO_VEC3,
6132
+ damage,
6133
+ 1,
6134
+ 4 /* ENERGY */,
6135
+ 35 /* RIPPER */,
6136
+ sys.timeSeconds,
6137
+ sys.multicast.bind(sys)
6138
+ );
6139
+ sys.free(self);
6140
+ return;
6141
+ }
6142
+ };
6143
+ ion.think = (self) => {
6144
+ sys.multicast(self.origin, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.WELDING_SPARKS, self.origin, ZERO_VEC3, 228);
6145
+ sys.free(self);
6146
+ };
6147
+ sys.scheduleThink(ion, sys.timeSeconds + 3);
6148
+ sys.finalizeSpawn(ion);
6149
+ }
6150
+ function createBlueBlaster(sys, owner, start, dir, damage, speed) {
6151
+ createBlasterBolt(sys, owner, start, dir, damage, speed, 58 /* BLUEBLASTER */);
6152
+ }
6087
6153
  function fireBfgPiercingLaser(sys, bfg, target, damage) {
6088
6154
  const start = { ...bfg.origin };
6089
6155
  const targetCenter2 = {
@@ -6342,6 +6408,12 @@ function monster_fire_shotgun(self, start, aimdir, damage, kick, hspread, vsprea
6342
6408
  function monster_fire_blaster(self, start, dir, damage, speed, flashtype, effect, context, mod = 1 /* BLASTER */) {
6343
6409
  createBlasterBolt(context, self, start, dir, damage, speed, mod);
6344
6410
  }
6411
+ function monster_fire_blueblaster(self, start, dir, damage, speed, flashtype, effect, context) {
6412
+ createBlueBlaster(context, self, start, dir, damage, speed);
6413
+ }
6414
+ function monster_fire_ionripper(self, start, dir, damage, speed, flashtype, effect, context) {
6415
+ createIonRipper(context, self, start, dir, damage, speed);
6416
+ }
6345
6417
  function monster_fire_grenade(self, start, aim, damage, speed, flashtype, context) {
6346
6418
  createGrenade(context, self, start, aim, damage, speed);
6347
6419
  }
@@ -6404,12 +6476,36 @@ function monster_fire_heat(self, start, dir, damage, speed, flashtype, turn_frac
6404
6476
  function dabeam_update(self, context) {
6405
6477
  const start = { ...self.origin };
6406
6478
  const end = addVec3(start, scaleVec3(self.movedir, 2048));
6407
- const tr = context.trace(start, end, ZERO_VEC3, ZERO_VEC3, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_DEADMONSTER);
6408
- if (self.dmg > 0 && tr.ent && tr.ent.takedamage && tr.ent !== self.owner) {
6409
- T_Damage(tr.ent, self, self.owner, self.movedir, tr.endpos, ZERO_VEC3, self.dmg, 0, 4 /* ENERGY */, 31 /* TARGET_LASER */, context.timeSeconds);
6410
- }
6411
- if (tr.ent && tr.ent.solid === 3 /* Bsp */) {
6412
- context.multicast(tr.endpos, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.LASER_SPARKS, 10, tr.endpos, tr.plane?.normal || ZERO_VEC3, self.skin);
6479
+ let currentStart = { ...start };
6480
+ const MAX_PIERCE = 16;
6481
+ const pierced = [];
6482
+ const piercedSolidities = [];
6483
+ try {
6484
+ for (let i = 0; i < MAX_PIERCE; i++) {
6485
+ const tr = context.trace(currentStart, end, ZERO_VEC3, ZERO_VEC3, self, CONTENTS_SOLID | CONTENTS_MONSTER | CONTENTS_PLAYER | CONTENTS_DEADMONSTER);
6486
+ if (!tr.ent || tr.fraction >= 1) {
6487
+ break;
6488
+ }
6489
+ if (self.dmg > 0 && tr.ent.takedamage && tr.ent !== self.owner) {
6490
+ T_Damage(tr.ent, self, self.owner, self.movedir, tr.endpos, ZERO_VEC3, self.dmg, 0, 4 /* ENERGY */, 31 /* TARGET_LASER */, context.timeSeconds);
6491
+ }
6492
+ if (tr.ent && tr.ent.solid === 3 /* Bsp */) {
6493
+ context.multicast(tr.endpos, 1 /* Pvs */, ServerCommand.temp_entity, TempEntity.LASER_SPARKS, 10, tr.endpos, tr.plane?.normal || ZERO_VEC3, self.skin);
6494
+ break;
6495
+ }
6496
+ if (tr.ent && (tr.ent.takedamage || tr.ent.client)) {
6497
+ pierced.push(tr.ent);
6498
+ piercedSolidities.push(tr.ent.solid);
6499
+ tr.ent.solid = 0 /* Not */;
6500
+ currentStart = { ...tr.endpos };
6501
+ continue;
6502
+ }
6503
+ break;
6504
+ }
6505
+ } finally {
6506
+ for (let i = 0; i < pierced.length; i++) {
6507
+ pierced[i].solid = piercedSolidities[i];
6508
+ }
6413
6509
  }
6414
6510
  context.linkentity(self);
6415
6511
  }
@@ -6432,11 +6528,7 @@ function monster_fire_dabeam(self, damage, secondary, update_func, context) {
6432
6528
  beam.owner = self;
6433
6529
  beam.dmg = damage;
6434
6530
  beam.frame = 2;
6435
- if (self.monsterinfo.aiflags & 64) {
6436
- beam.skin = 4092850673;
6437
- } else {
6438
- beam.skin = 4076007664;
6439
- }
6531
+ beam.skin = 4076007664;
6440
6532
  beam.think = (ent, ctx) => {
6441
6533
  if (ent.postthink) {
6442
6534
  ent.postthink(ent, ctx);
@@ -10634,6 +10726,8 @@ function soldier_run(self) {
10634
10726
  function soldier_attack(self) {
10635
10727
  if (self.spawnflags & SOLDIER_MACHINEGUN) {
10636
10728
  self.monsterinfo.current_move = attack_move_mg;
10729
+ } else if (self.style === 1 && self.count >= 4) {
10730
+ self.monsterinfo.current_move = attack_move_mg;
10637
10731
  } else {
10638
10732
  self.monsterinfo.current_move = attack_move8;
10639
10733
  }
@@ -10692,9 +10786,59 @@ function soldier_fire_machinegun(self, context) {
10692
10786
  context.engine.sound?.(self, 0, "soldier/solatck3.wav", 1, 1, 0);
10693
10787
  monster_fire_bullet(self, start, forward, damage, kick, hspread, vspread, 0, context, 4 /* MACHINEGUN */);
10694
10788
  }
10789
+ function soldierh_laser_update(beam, context) {
10790
+ const self = beam.owner;
10791
+ if (!self || !self.enemy) return;
10792
+ const { forward, right, up } = angleVectors(self.angles);
10793
+ let start = { ...self.origin };
10794
+ start = addVec3(start, scaleVec3(forward, 16));
10795
+ start.z += self.viewheight;
10796
+ const enemyCenter = { ...self.enemy.origin };
10797
+ enemyCenter.z += self.enemy.viewheight || 0;
10798
+ const dir = normalizeVec3(subtractVec3(enemyCenter, start));
10799
+ beam.origin = start;
10800
+ beam.movedir = dir;
10801
+ context.linkentity(beam);
10802
+ }
10803
+ function soldier_fire_ripper(self, context) {
10804
+ if (!self.enemy) return;
10805
+ const start = get_fire_start(self);
10806
+ const forward = get_fire_dir(self, start);
10807
+ const damage = 5;
10808
+ const speed = 600;
10809
+ monster_fire_ionripper(self, start, forward, damage, speed, 0, 0, context);
10810
+ }
10811
+ function soldier_fire_hypergun(self, context) {
10812
+ if (!self.enemy) return;
10813
+ const start = get_fire_start(self);
10814
+ const forward = get_fire_dir(self, start);
10815
+ const damage = 1;
10816
+ const speed = 600;
10817
+ context.engine.sound?.(self, 0, "weapons/hyprbl1a.wav", 1, 1, 0);
10818
+ monster_fire_blueblaster(self, start, forward, damage, speed, 0, 0, context);
10819
+ }
10820
+ function soldier_fire_laser(self, context) {
10821
+ if (!self.enemy) return;
10822
+ monster_fire_dabeam(self, 1, false, soldierh_laser_update, context);
10823
+ }
10824
+ function soldier_fire_xatrix(self, context) {
10825
+ if (self.count < 2) {
10826
+ soldier_fire_ripper(self, context);
10827
+ } else if (self.count < 4) {
10828
+ soldier_fire_hypergun(self, context);
10829
+ } else {
10830
+ soldier_fire_laser(self, context);
10831
+ }
10832
+ }
10695
10833
  function soldier_fire(self, context) {
10834
+ if (self.style === 1) {
10835
+ soldier_fire_xatrix(self, context);
10836
+ return;
10837
+ }
10696
10838
  if (self.spawnflags & SOLDIER_SSG) {
10697
10839
  soldier_fire_ssg(self, context);
10840
+ } else if (self.spawnflags & SOLDIER_MACHINEGUN) {
10841
+ soldier_fire_machinegun(self, context);
10698
10842
  } else {
10699
10843
  soldier_fire_blaster(self, context);
10700
10844
  }
@@ -10744,7 +10888,10 @@ var attack_frames_mg = Array.from({ length: 10 }, (_, i) => ({
10744
10888
  ai: monster_ai_charge18,
10745
10889
  dist: 0,
10746
10890
  // Fire on frames 4, 5, 6, 7, 8
10747
- think: i >= 4 && i <= 8 ? soldier_fire_machinegun : null
10891
+ // Note: Laser soldier fires continuously?
10892
+ // C++: soldierh_hyperripper8 called on frames 11, 13, 18?
10893
+ // Actually laser soldier (machinegun equivalent) fires on frames 4-8.
10894
+ think: i >= 4 && i <= 8 ? soldier_fire : null
10748
10895
  }));
10749
10896
  attack_move_mg = {
10750
10897
  firstframe: 90,
@@ -10845,10 +10992,33 @@ function SP_monster_soldier_ssg(self, context) {
10845
10992
  self.spawnflags |= SOLDIER_SSG;
10846
10993
  SP_monster_soldier(self, context);
10847
10994
  }
10995
+ function SP_monster_soldier_x(self, context, skin, health) {
10996
+ SP_monster_soldier(self, context);
10997
+ self.style = 1;
10998
+ self.skin = skin;
10999
+ self.count = skin - 6;
11000
+ self.health = health;
11001
+ self.max_health = health;
11002
+ }
11003
+ function SP_monster_soldier_ripper(self, context) {
11004
+ SP_monster_soldier_x(self, context, 6, 50);
11005
+ self.model = "models/monsters/soldier/tris.md2";
11006
+ }
11007
+ function SP_monster_soldier_hypergun(self, context) {
11008
+ SP_monster_soldier_x(self, context, 8, 60);
11009
+ self.model = "models/monsters/soldier/tris.md2";
11010
+ }
11011
+ function SP_monster_soldier_lasergun(self, context) {
11012
+ SP_monster_soldier_x(self, context, 10, 70);
11013
+ self.model = "models/monsters/soldier/tris.md2";
11014
+ }
10848
11015
  function registerMonsterSpawns(registry) {
10849
11016
  registry.register("monster_soldier", SP_monster_soldier);
10850
11017
  registry.register("monster_soldier_light", SP_monster_soldier_light);
10851
11018
  registry.register("monster_soldier_ssg", SP_monster_soldier_ssg);
11019
+ registry.register("monster_soldier_ripper", SP_monster_soldier_ripper);
11020
+ registry.register("monster_soldier_hypergun", SP_monster_soldier_hypergun);
11021
+ registry.register("monster_soldier_lasergun", SP_monster_soldier_lasergun);
10852
11022
  }
10853
11023
 
10854
11024
  // src/entities/monsters/supertank.ts