quake2ts 0.0.68 → 0.0.71

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 (54) hide show
  1. package/package.json +1 -1
  2. package/packages/client/dist/browser/index.global.js +1 -1
  3. package/packages/client/dist/browser/index.global.js.map +1 -1
  4. package/packages/client/dist/cjs/index.cjs.map +1 -1
  5. package/packages/client/dist/esm/index.js.map +1 -1
  6. package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
  7. package/packages/engine/dist/browser/index.global.js +14 -14
  8. package/packages/engine/dist/browser/index.global.js.map +1 -1
  9. package/packages/engine/dist/cjs/index.cjs +84 -0
  10. package/packages/engine/dist/cjs/index.cjs.map +1 -1
  11. package/packages/engine/dist/esm/index.js +81 -0
  12. package/packages/engine/dist/esm/index.js.map +1 -1
  13. package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
  14. package/packages/engine/dist/types/assets/manager.d.ts +4 -1
  15. package/packages/engine/dist/types/assets/manager.d.ts.map +1 -1
  16. package/packages/engine/dist/types/assets/sprite.d.ts +23 -0
  17. package/packages/engine/dist/types/assets/sprite.d.ts.map +1 -0
  18. package/packages/engine/dist/types/index.d.ts +1 -0
  19. package/packages/engine/dist/types/index.d.ts.map +1 -1
  20. package/packages/game/dist/browser/index.global.js +1 -1
  21. package/packages/game/dist/browser/index.global.js.map +1 -1
  22. package/packages/game/dist/cjs/index.cjs +318 -40
  23. package/packages/game/dist/cjs/index.cjs.map +1 -1
  24. package/packages/game/dist/esm/index.js +318 -40
  25. package/packages/game/dist/esm/index.js.map +1 -1
  26. package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
  27. package/packages/game/dist/types/combat/weapons/firing.d.ts.map +1 -1
  28. package/packages/game/dist/types/entities/entity.d.ts +9 -1
  29. package/packages/game/dist/types/entities/entity.d.ts.map +1 -1
  30. package/packages/game/dist/types/entities/funcs.d.ts +9 -0
  31. package/packages/game/dist/types/entities/funcs.d.ts.map +1 -0
  32. package/packages/game/dist/types/entities/projectiles.d.ts +2 -0
  33. package/packages/game/dist/types/entities/projectiles.d.ts.map +1 -1
  34. package/packages/game/dist/types/entities/spawn.d.ts.map +1 -1
  35. package/packages/game/dist/types/entities/system.d.ts +2 -0
  36. package/packages/game/dist/types/entities/system.d.ts.map +1 -1
  37. package/packages/game/dist/types/entities/thinkScheduler.d.ts +1 -1
  38. package/packages/game/dist/types/entities/thinkScheduler.d.ts.map +1 -1
  39. package/packages/game/dist/types/imports.d.ts +1 -0
  40. package/packages/game/dist/types/imports.d.ts.map +1 -1
  41. package/packages/game/dist/types/index.d.ts +4 -1
  42. package/packages/game/dist/types/index.d.ts.map +1 -1
  43. package/packages/game/dist/types/physics/movement.d.ts +2 -0
  44. package/packages/game/dist/types/physics/movement.d.ts.map +1 -1
  45. package/packages/shared/dist/browser/index.global.js +1 -1
  46. package/packages/shared/dist/browser/index.global.js.map +1 -1
  47. package/packages/shared/dist/cjs/index.cjs +18 -8
  48. package/packages/shared/dist/cjs/index.cjs.map +1 -1
  49. package/packages/shared/dist/esm/index.js +16 -8
  50. package/packages/shared/dist/esm/index.js.map +1 -1
  51. package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
  52. package/packages/shared/dist/types/math/vec3.d.ts +2 -0
  53. package/packages/shared/dist/types/math/vec3.d.ts.map +1 -1
  54. package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
@@ -20,6 +20,12 @@ function lengthSquaredVec3(a) {
20
20
  function lengthVec3(a) {
21
21
  return Math.sqrt(lengthSquaredVec3(a));
22
22
  }
23
+ function distance(a, b) {
24
+ return lengthVec3(subtractVec3(a, b));
25
+ }
26
+ function vec3Equals(a, b) {
27
+ return a.x === b.x && a.y === b.y && a.z === b.z;
28
+ }
23
29
  function normalizeVec3(a) {
24
30
  const len = lengthVec3(a);
25
31
  return len === 0 ? a : scaleVec3(a, 1 / len);
@@ -605,9 +611,13 @@ var Entity = class {
605
611
  this.velocity = copyVec3();
606
612
  this.avelocity = copyVec3();
607
613
  this.angles = copyVec3();
614
+ this.pos1 = copyVec3();
615
+ this.pos2 = copyVec3();
608
616
  this.viewheight = 0;
609
617
  this.mins = copyVec3();
610
618
  this.maxs = copyVec3();
619
+ this.absmin = copyVec3();
620
+ this.absmax = copyVec3();
611
621
  this.size = copyVec3();
612
622
  this.mass = 0;
613
623
  this.gravity = 1;
@@ -629,6 +639,8 @@ var Entity = class {
629
639
  this.wait = 0;
630
640
  this.delay = 0;
631
641
  this.timestamp = 0;
642
+ this.lip = 0;
643
+ this.state = 0;
632
644
  this.sounds = 0;
633
645
  this.noise_index = 0;
634
646
  this.fly_sound_debounce_time = 0;
@@ -679,9 +691,13 @@ var Entity = class {
679
691
  this.velocity = copyVec3();
680
692
  this.avelocity = copyVec3();
681
693
  this.angles = copyVec3();
694
+ this.pos1 = copyVec3();
695
+ this.pos2 = copyVec3();
682
696
  this.viewheight = 0;
683
697
  this.mins = copyVec3();
684
698
  this.maxs = copyVec3();
699
+ this.absmin = copyVec3();
700
+ this.absmax = copyVec3();
685
701
  this.size = copyVec3();
686
702
  this.mass = 0;
687
703
  this.gravity = 1;
@@ -703,6 +719,8 @@ var Entity = class {
703
719
  this.wait = 0;
704
720
  this.delay = 0;
705
721
  this.timestamp = 0;
722
+ this.lip = 0;
723
+ this.state = 0;
706
724
  this.sounds = 0;
707
725
  this.noise_index = 0;
708
726
  this.fly_sound_debounce_time = 0;
@@ -724,6 +742,7 @@ var Entity = class {
724
742
  this.think = void 0;
725
743
  this.touch = void 0;
726
744
  this.use = void 0;
745
+ this.blocked = void 0;
727
746
  this.pain = void 0;
728
747
  this.die = void 0;
729
748
  this.activator = null;
@@ -754,9 +773,13 @@ var ENTITY_FIELD_METADATA = [
754
773
  { name: "velocity", type: "vec3", save: true },
755
774
  { name: "avelocity", type: "vec3", save: true },
756
775
  { name: "angles", type: "vec3", save: true },
776
+ { name: "pos1", type: "vec3", save: true },
777
+ { name: "pos2", type: "vec3", save: true },
757
778
  { name: "viewheight", type: "int", save: true },
758
779
  { name: "mins", type: "vec3", save: true },
759
780
  { name: "maxs", type: "vec3", save: true },
781
+ { name: "absmin", type: "vec3", save: true },
782
+ { name: "absmax", type: "vec3", save: true },
760
783
  { name: "size", type: "vec3", save: true },
761
784
  { name: "mass", type: "int", save: true },
762
785
  { name: "gravity", type: "float", save: true },
@@ -777,6 +800,8 @@ var ENTITY_FIELD_METADATA = [
777
800
  { name: "wait", type: "float", save: true },
778
801
  { name: "delay", type: "float", save: true },
779
802
  { name: "timestamp", type: "float", save: true },
803
+ { name: "lip", type: "int", save: true },
804
+ { name: "state", type: "int", save: true },
780
805
  { name: "sounds", type: "int", save: true },
781
806
  { name: "noise_index", type: "int", save: true },
782
807
  { name: "fly_sound_debounce_time", type: "float", save: true },
@@ -801,6 +826,7 @@ var ENTITY_FIELD_METADATA = [
801
826
  { name: "think", type: "callback", save: false },
802
827
  { name: "touch", type: "callback", save: false },
803
828
  { name: "use", type: "callback", save: false },
829
+ { name: "blocked", type: "callback", save: false },
804
830
  { name: "pain", type: "callback", save: false },
805
831
  { name: "die", type: "callback", save: false }
806
832
  ];
@@ -834,6 +860,108 @@ function runProjectileMovement(ent, imports, frametime) {
834
860
  const traceResult = imports.trace(ent.origin, ent.mins, ent.maxs, end, ent, ent.clipmask);
835
861
  ent.origin = traceResult.endpos;
836
862
  }
863
+ function testEntityPosition(ent, imports) {
864
+ const trace = imports.trace(ent.origin, ent.mins, ent.maxs, ent.origin, ent, ent.clipmask);
865
+ if (trace.startsolid || trace.allsolid) {
866
+ return false;
867
+ }
868
+ return true;
869
+ }
870
+ function runPush(pusher, system, imports, frametime) {
871
+ const move = {
872
+ x: pusher.velocity.x * frametime,
873
+ y: pusher.velocity.y * frametime,
874
+ z: pusher.velocity.z * frametime
875
+ };
876
+ const amove = {
877
+ x: pusher.avelocity.x * frametime,
878
+ y: pusher.avelocity.y * frametime,
879
+ z: pusher.avelocity.z * frametime
880
+ };
881
+ const mins = {
882
+ x: Math.min(pusher.absmin.x, pusher.absmin.x + move.x) - 2,
883
+ // Expand slightly? Quake2 does 'mins - move - 2' logic implicitly via box check
884
+ y: Math.min(pusher.absmin.y, pusher.absmin.y + move.y) - 2,
885
+ z: Math.min(pusher.absmin.z, pusher.absmin.z + move.z) - 2
886
+ };
887
+ const maxs = {
888
+ x: Math.max(pusher.absmax.x, pusher.absmax.x + move.x) + 2,
889
+ y: Math.max(pusher.absmax.y, pusher.absmax.y + move.y) + 2,
890
+ z: Math.max(pusher.absmax.z, pusher.absmax.z + move.z) + 2
891
+ };
892
+ const pushed = [];
893
+ pushed.push({
894
+ ent: pusher,
895
+ origin: { ...pusher.origin },
896
+ angles: { ...pusher.angles },
897
+ ground: pusher.groundentity
898
+ });
899
+ pusher.origin = {
900
+ x: pusher.origin.x + move.x,
901
+ y: pusher.origin.y + move.y,
902
+ z: pusher.origin.z + move.z
903
+ };
904
+ pusher.angles = {
905
+ x: pusher.angles.x + amove.x,
906
+ y: pusher.angles.y + amove.y,
907
+ z: pusher.angles.z + amove.z
908
+ };
909
+ imports.linkentity(pusher);
910
+ if (!testEntityPosition(pusher, imports)) {
911
+ pusher.origin = pushed[0].origin;
912
+ pusher.angles = pushed[0].angles;
913
+ imports.linkentity(pusher);
914
+ return false;
915
+ }
916
+ const candidates = [];
917
+ system.forEachEntity((check) => {
918
+ if (check === pusher) return;
919
+ if (check.solid === 0 /* Not */ || check.solid === 1 /* Trigger */) return;
920
+ if (check.absmin.x >= maxs.x || check.absmax.x <= mins.x || check.absmin.y >= maxs.y || check.absmax.y <= mins.y || check.absmin.z >= maxs.z || check.absmax.z <= mins.z) {
921
+ return;
922
+ }
923
+ candidates.push(check);
924
+ });
925
+ for (const ent of candidates) {
926
+ let moveEntity = false;
927
+ if (ent.groundentity === pusher) {
928
+ moveEntity = true;
929
+ } else {
930
+ if (ent.absmin.x < pusher.absmax.x && ent.absmax.x > pusher.absmin.x && ent.absmin.y < pusher.absmax.y && ent.absmax.y > pusher.absmin.y && ent.absmin.z < pusher.absmax.z && ent.absmax.z > pusher.absmin.z) {
931
+ moveEntity = true;
932
+ }
933
+ }
934
+ if (moveEntity) {
935
+ pushed.push({
936
+ ent,
937
+ origin: { ...ent.origin },
938
+ angles: { ...ent.angles },
939
+ ground: ent.groundentity
940
+ });
941
+ ent.origin = {
942
+ x: ent.origin.x + move.x,
943
+ y: ent.origin.y + move.y,
944
+ z: ent.origin.z + move.z
945
+ };
946
+ imports.linkentity(ent);
947
+ if (!testEntityPosition(ent, imports)) {
948
+ if (pusher.blocked) {
949
+ pusher.blocked(pusher, ent);
950
+ }
951
+ if (ent.solid !== 0 /* Not */ && (!ent.health || ent.health > 0)) {
952
+ for (let i = pushed.length - 1; i >= 0; i--) {
953
+ const p = pushed[i];
954
+ p.ent.origin = p.origin;
955
+ p.ent.angles = p.angles;
956
+ p.ent.groundentity = p.ground, imports.linkentity(p.ent);
957
+ }
958
+ return false;
959
+ }
960
+ }
961
+ }
962
+ }
963
+ return true;
964
+ }
837
965
 
838
966
  // src/entities/pool.ts
839
967
  var MAX_EDICTS = 2048;
@@ -1048,7 +1176,7 @@ var ThinkScheduler = class {
1048
1176
  this.schedule(entity, entry.time);
1049
1177
  }
1050
1178
  }
1051
- runDueThinks(currentTimeSeconds) {
1179
+ runDueThinks(currentTimeSeconds, context) {
1052
1180
  while (this.queue.length > 0) {
1053
1181
  const next = this.queue[0];
1054
1182
  if (next.time > currentTimeSeconds) {
@@ -1065,7 +1193,7 @@ var ThinkScheduler = class {
1065
1193
  if (entity.nextthink !== time) {
1066
1194
  continue;
1067
1195
  }
1068
- entity.think(entity);
1196
+ entity.think(entity, context);
1069
1197
  }
1070
1198
  }
1071
1199
  };
@@ -1138,7 +1266,19 @@ var EntitySystem = class {
1138
1266
  contents: 0,
1139
1267
  ent: null
1140
1268
  }),
1141
- pointcontents: () => 0
1269
+ pointcontents: () => 0,
1270
+ linkentity: (ent) => {
1271
+ ent.absmin = {
1272
+ x: ent.origin.x + ent.mins.x,
1273
+ y: ent.origin.y + ent.mins.y,
1274
+ z: ent.origin.z + ent.mins.z
1275
+ };
1276
+ ent.absmax = {
1277
+ x: ent.origin.x + ent.maxs.x,
1278
+ y: ent.origin.y + ent.maxs.y,
1279
+ z: ent.origin.z + ent.maxs.z
1280
+ };
1281
+ }
1142
1282
  };
1143
1283
  this.gravity = gravity || { x: 0, y: 0, z: 0 };
1144
1284
  this.callbackToName = /* @__PURE__ */ new Map();
@@ -1188,6 +1328,9 @@ var EntitySystem = class {
1188
1328
  sound(entity, channel, sound, volume, attenuation, timeofs) {
1189
1329
  this.engine.sound?.(entity, channel, sound, volume, attenuation, timeofs);
1190
1330
  }
1331
+ modelIndex(model) {
1332
+ return this.engine.modelIndex?.(model) || 0;
1333
+ }
1191
1334
  scheduleThink(entity, nextThinkSeconds) {
1192
1335
  this.thinkScheduler.schedule(entity, nextThinkSeconds);
1193
1336
  }
@@ -1216,6 +1359,18 @@ var EntitySystem = class {
1216
1359
  }
1217
1360
  return Array.from(matches).filter((entity) => entity.inUse && !entity.freePending);
1218
1361
  }
1362
+ findByRadius(origin, radius) {
1363
+ const matches = [];
1364
+ for (const entity of this.pool) {
1365
+ if (entity.inUse && !entity.freePending) {
1366
+ const distance2 = lengthVec3(subtractVec3(origin, entity.origin));
1367
+ if (distance2 <= radius) {
1368
+ matches.push(entity);
1369
+ }
1370
+ }
1371
+ }
1372
+ return matches;
1373
+ }
1219
1374
  pickTarget(targetname) {
1220
1375
  if (!targetname) {
1221
1376
  return null;
@@ -1264,7 +1419,7 @@ var EntitySystem = class {
1264
1419
  this.useTargetsImmediate(entity, activator ?? entity);
1265
1420
  }
1266
1421
  runFrame() {
1267
- this.thinkScheduler.runDueThinks(this.currentTimeSeconds);
1422
+ this.thinkScheduler.runDueThinks(this.currentTimeSeconds, this);
1268
1423
  for (const ent of this.pool) {
1269
1424
  if (!ent.inUse || ent.freePending) {
1270
1425
  continue;
@@ -1284,6 +1439,9 @@ var EntitySystem = class {
1284
1439
  runProjectileMovement(ent, this.imports, frametime);
1285
1440
  ent.timestamp = this.currentTimeSeconds;
1286
1441
  break;
1442
+ case 2 /* Push */:
1443
+ runPush(ent, this, this.imports, frametime);
1444
+ break;
1287
1445
  }
1288
1446
  }
1289
1447
  this.runTouches();
@@ -2852,6 +3010,112 @@ function registerItemSpawns(game, registry) {
2852
3010
  }
2853
3011
  }
2854
3012
 
3013
+ // src/entities/funcs.ts
3014
+ function door_blocked(self, other) {
3015
+ if (other && other.takedamage) {
3016
+ const damage = self.dmg || 2;
3017
+ other.health -= damage;
3018
+ }
3019
+ if (self.state === 1 /* Opening */) {
3020
+ self.state = 3 /* Closing */;
3021
+ self.think = door_go_down;
3022
+ } else if (self.state === 3 /* Closing */) {
3023
+ self.state = 1 /* Opening */;
3024
+ self.think = door_go_up;
3025
+ }
3026
+ }
3027
+ function door_go_down(door, context) {
3028
+ if (vec3Equals(door.origin, door.pos1)) {
3029
+ door.state = 2 /* Closed */;
3030
+ door.velocity = { x: 0, y: 0, z: 0 };
3031
+ return;
3032
+ }
3033
+ const move = distance(door.origin, door.pos1);
3034
+ const speed = Math.min(door.speed, move);
3035
+ door.velocity = {
3036
+ x: (door.pos1.x - door.origin.x) / distance(door.pos1, door.origin) * door.speed,
3037
+ y: (door.pos1.y - door.origin.y) / distance(door.pos1, door.origin) * door.speed,
3038
+ z: (door.pos1.z - door.origin.z) / distance(door.pos1, door.origin) * door.speed
3039
+ };
3040
+ if (move <= door.speed * 0.1) {
3041
+ door.velocity = {
3042
+ x: (door.pos1.x - door.origin.x) / 0.1,
3043
+ y: (door.pos1.y - door.origin.y) / 0.1,
3044
+ z: (door.pos1.z - door.origin.z) / 0.1
3045
+ };
3046
+ }
3047
+ context?.scheduleThink(door, context.timeSeconds + 0.1);
3048
+ }
3049
+ function door_go_up(door, context) {
3050
+ if (vec3Equals(door.origin, door.pos2)) {
3051
+ door.state = 0 /* Open */;
3052
+ door.velocity = { x: 0, y: 0, z: 0 };
3053
+ context?.scheduleThink(door, context.timeSeconds + door.wait);
3054
+ door.think = door_go_down;
3055
+ return;
3056
+ }
3057
+ const move = distance(door.origin, door.pos2);
3058
+ door.velocity = {
3059
+ x: (door.pos2.x - door.origin.x) / distance(door.pos2, door.origin) * door.speed,
3060
+ y: (door.pos2.y - door.origin.y) / distance(door.pos2, door.origin) * door.speed,
3061
+ z: (door.pos2.z - door.origin.z) / distance(door.pos2, door.origin) * door.speed
3062
+ };
3063
+ if (move <= door.speed * 0.1) {
3064
+ door.velocity = {
3065
+ x: (door.pos2.x - door.origin.x) / 0.1,
3066
+ y: (door.pos2.y - door.origin.y) / 0.1,
3067
+ z: (door.pos2.z - door.origin.z) / 0.1
3068
+ };
3069
+ }
3070
+ context?.scheduleThink(door, context.timeSeconds + 0.1);
3071
+ }
3072
+ var func_door = (entity, context) => {
3073
+ entity.movedir = setMovedir(entity.angles);
3074
+ if (!entity.speed) {
3075
+ entity.speed = 100;
3076
+ }
3077
+ if (!entity.wait) {
3078
+ entity.wait = 3;
3079
+ }
3080
+ if (!entity.lip) {
3081
+ entity.lip = 8;
3082
+ }
3083
+ if (!entity.dmg) {
3084
+ entity.dmg = 2;
3085
+ }
3086
+ if (!entity.health) {
3087
+ entity.health = 0;
3088
+ }
3089
+ entity.solid = 3 /* Bsp */;
3090
+ entity.movetype = 2 /* Push */;
3091
+ entity.blocked = door_blocked;
3092
+ entity.state = 2 /* Closed */;
3093
+ entity.pos1 = { ...entity.origin };
3094
+ const move = entity.movedir.x * (Math.abs(entity.maxs.x - entity.mins.x) - entity.lip) + entity.movedir.y * (Math.abs(entity.maxs.y - entity.mins.y) - entity.lip) + entity.movedir.z * (Math.abs(entity.maxs.z - entity.mins.z) - entity.lip);
3095
+ entity.pos2 = {
3096
+ x: entity.pos1.x + entity.movedir.x * move,
3097
+ y: entity.pos1.y + entity.movedir.y * move,
3098
+ z: entity.pos1.z + entity.movedir.z * move
3099
+ };
3100
+ entity.use = (self) => {
3101
+ if (self.state !== 2 /* Closed */) return;
3102
+ self.state = 1 /* Opening */;
3103
+ self.think = door_go_up;
3104
+ context.entities.scheduleThink(self, context.entities.timeSeconds + 0.1);
3105
+ };
3106
+ };
3107
+ var func_button = (entity, context) => {
3108
+ entity.solid = 3 /* Bsp */;
3109
+ entity.movetype = 2 /* Push */;
3110
+ entity.use = (self) => {
3111
+ context.entities.useTargets(self, self);
3112
+ };
3113
+ };
3114
+ function registerFuncSpawns(registry) {
3115
+ registry.register("func_door", func_door);
3116
+ registry.register("func_button", func_button);
3117
+ }
3118
+
2855
3119
  // src/entities/spawn.ts
2856
3120
  var FIELD_LOOKUP = new Map(
2857
3121
  ENTITY_FIELD_METADATA.map((field) => [field.name, field])
@@ -3063,6 +3327,7 @@ function registerDefaultSpawns(game, registry) {
3063
3327
  registerTargetSpawns(registry);
3064
3328
  registerMiscSpawns(registry);
3065
3329
  registerItemSpawns(game, registry);
3330
+ registerFuncSpawns(registry);
3066
3331
  }
3067
3332
  function createDefaultSpawnRegistry(game) {
3068
3333
  const registry = new SpawnRegistry();
@@ -3254,19 +3519,19 @@ var TraceMask = /* @__PURE__ */ ((TraceMask2) => {
3254
3519
  })(TraceMask || {});
3255
3520
 
3256
3521
  // src/ai/movement.ts
3257
- function yawVector(yawDegrees, distance) {
3258
- if (distance === 0) {
3522
+ function yawVector(yawDegrees, distance2) {
3523
+ if (distance2 === 0) {
3259
3524
  return { x: 0, y: 0, z: 0 };
3260
3525
  }
3261
3526
  const radians = degToRad(yawDegrees);
3262
3527
  return {
3263
- x: Math.cos(radians) * distance,
3264
- y: Math.sin(radians) * distance,
3528
+ x: Math.cos(radians) * distance2,
3529
+ y: Math.sin(radians) * distance2,
3265
3530
  z: 0
3266
3531
  };
3267
3532
  }
3268
- function walkMove(self, yawDegrees, distance) {
3269
- const delta = yawVector(yawDegrees, distance);
3533
+ function walkMove(self, yawDegrees, distance2) {
3534
+ const delta = yawVector(yawDegrees, distance2);
3270
3535
  const origin = self.origin;
3271
3536
  origin.x += delta.x;
3272
3537
  origin.y += delta.y;
@@ -3299,8 +3564,8 @@ function facingIdeal(self) {
3299
3564
  }
3300
3565
  return !(delta > 45 && delta < 315);
3301
3566
  }
3302
- function ai_move(self, distance) {
3303
- walkMove(self, self.angles.y, distance);
3567
+ function ai_move(self, distance2) {
3568
+ walkMove(self, self.angles.y, distance2);
3304
3569
  }
3305
3570
  function setIdealYawTowards(self, target) {
3306
3571
  if (!target) return;
@@ -3314,40 +3579,40 @@ function setIdealYawTowards(self, target) {
3314
3579
  function ai_stand(self, deltaSeconds) {
3315
3580
  changeYaw(self, deltaSeconds);
3316
3581
  }
3317
- function ai_walk(self, distance, deltaSeconds) {
3582
+ function ai_walk(self, distance2, deltaSeconds) {
3318
3583
  setIdealYawTowards(self, self.goalentity);
3319
3584
  changeYaw(self, deltaSeconds);
3320
- if (distance !== 0) {
3321
- walkMove(self, self.angles.y, distance);
3585
+ if (distance2 !== 0) {
3586
+ walkMove(self, self.angles.y, distance2);
3322
3587
  }
3323
3588
  }
3324
- function ai_turn(self, distance, deltaSeconds) {
3325
- if (distance !== 0) {
3326
- walkMove(self, self.angles.y, distance);
3589
+ function ai_turn(self, distance2, deltaSeconds) {
3590
+ if (distance2 !== 0) {
3591
+ walkMove(self, self.angles.y, distance2);
3327
3592
  }
3328
3593
  changeYaw(self, deltaSeconds);
3329
3594
  }
3330
- function ai_run(self, distance, deltaSeconds) {
3595
+ function ai_run(self, distance2, deltaSeconds) {
3331
3596
  setIdealYawTowards(self, self.enemy ?? self.goalentity);
3332
3597
  changeYaw(self, deltaSeconds);
3333
- if (distance !== 0) {
3334
- walkMove(self, self.angles.y, distance);
3598
+ if (distance2 !== 0) {
3599
+ walkMove(self, self.angles.y, distance2);
3335
3600
  }
3336
3601
  }
3337
- function ai_face(self, enemy, distance, deltaSeconds) {
3602
+ function ai_face(self, enemy, distance2, deltaSeconds) {
3338
3603
  if (enemy) {
3339
3604
  setIdealYawTowards(self, enemy);
3340
3605
  }
3341
3606
  changeYaw(self, deltaSeconds);
3342
- if (distance !== 0) {
3343
- walkMove(self, self.angles.y, distance);
3607
+ if (distance2 !== 0) {
3608
+ walkMove(self, self.angles.y, distance2);
3344
3609
  }
3345
3610
  }
3346
- function ai_charge(self, distance, deltaSeconds) {
3611
+ function ai_charge(self, distance2, deltaSeconds) {
3347
3612
  setIdealYawTowards(self, self.enemy);
3348
3613
  changeYaw(self, deltaSeconds);
3349
- if (distance !== 0) {
3350
- walkMove(self, self.angles.y, distance);
3614
+ if (distance2 !== 0) {
3615
+ walkMove(self, self.angles.y, distance2);
3351
3616
  }
3352
3617
  }
3353
3618
 
@@ -3379,14 +3644,14 @@ function rangeTo(self, other) {
3379
3644
  const distanceSquared = distanceBetweenBoxesSquared(a.mins, a.maxs, b.mins, b.maxs);
3380
3645
  return Math.sqrt(distanceSquared);
3381
3646
  }
3382
- function classifyRange(distance) {
3383
- if (distance <= RANGE_MELEE) {
3647
+ function classifyRange(distance2) {
3648
+ if (distance2 <= RANGE_MELEE) {
3384
3649
  return "melee" /* Melee */;
3385
3650
  }
3386
- if (distance <= RANGE_NEAR) {
3651
+ if (distance2 <= RANGE_NEAR) {
3387
3652
  return "near" /* Near */;
3388
3653
  }
3389
- if (distance <= RANGE_MID) {
3654
+ if (distance2 <= RANGE_MID) {
3390
3655
  return "mid" /* Mid */;
3391
3656
  }
3392
3657
  return "far" /* Far */;
@@ -3466,8 +3731,8 @@ function foundTarget(self, level, options) {
3466
3731
  self.monsterinfo.run?.(self);
3467
3732
  }
3468
3733
  function classifyClientVisibility(self, other, level, trace) {
3469
- const distance = rangeTo(self, other);
3470
- const range = classifyRange(distance);
3734
+ const distance2 = rangeTo(self, other);
3735
+ const range = classifyRange(distance2);
3471
3736
  if (range === "far" /* Far */) return false;
3472
3737
  if (other.light_level <= 5) return false;
3473
3738
  if (!visible(self, other, trace, { throughGlass: false })) return false;
@@ -4354,11 +4619,11 @@ function T_RadiusDamage(entities, inflictor, attacker, damage, ignore, radius, d
4354
4619
  }
4355
4620
  const entCenter = ent.mins && ent.maxs ? closestPointToBox(inflictorCenter, addVec3(ent.origin, ent.mins), addVec3(ent.origin, ent.maxs)) : targetCenter(ent);
4356
4621
  const toTarget = subtractVec3(inflictorCenter, entCenter);
4357
- const distance = lengthVec3(toTarget);
4358
- if (radius > 0 && distance > radius) {
4622
+ const distance2 = lengthVec3(toTarget);
4623
+ if (radius > 0 && distance2 > radius) {
4359
4624
  continue;
4360
4625
  }
4361
- const points = damage - 0.5 * distance;
4626
+ const points = damage - 0.5 * distance2;
4362
4627
  if (points <= 0) {
4363
4628
  continue;
4364
4629
  }
@@ -4782,11 +5047,23 @@ function getWeaponState(playerStates, weaponId) {
4782
5047
 
4783
5048
  // src/index.ts
4784
5049
  var ZERO_VEC32 = { x: 0, y: 0, z: 0 };
4785
- function createGame(imports, engine, options) {
5050
+ function createGame({ trace, pointcontents }, engine, options) {
4786
5051
  const gravity = options.gravity;
4787
5052
  const levelClock = new LevelClock();
4788
5053
  const frameLoop = new GameFrameLoop();
4789
- const entities = new EntitySystem(engine, imports, gravity);
5054
+ const linkentity = (ent) => {
5055
+ ent.absmin = {
5056
+ x: ent.origin.x + ent.mins.x,
5057
+ y: ent.origin.y + ent.mins.y,
5058
+ z: ent.origin.z + ent.mins.z
5059
+ };
5060
+ ent.absmax = {
5061
+ x: ent.origin.x + ent.maxs.x,
5062
+ y: ent.origin.y + ent.maxs.y,
5063
+ z: ent.origin.z + ent.maxs.z
5064
+ };
5065
+ };
5066
+ const entities = new EntitySystem(engine, { trace, pointcontents, linkentity }, gravity);
4790
5067
  frameLoop.addStage("prep", (context) => {
4791
5068
  levelClock.tick(context);
4792
5069
  entities.beginFrame(levelClock.current.timeSeconds);
@@ -4864,7 +5141,7 @@ function createGame(imports, engine, options) {
4864
5141
  };
4865
5142
  const playerState = { origin: player.origin, velocity: player.velocity, onGround: false, waterLevel: 0, mins: player.mins, maxs: player.maxs, damageAlpha: 0, damageIndicators: [], viewAngles: player.angles };
4866
5143
  const traceAdapter = (start, end) => {
4867
- const result = imports.trace(start, player.mins, player.maxs, end, player, 268435457);
5144
+ const result = trace(start, player.mins, player.maxs, end, player, 268435457);
4868
5145
  return {
4869
5146
  fraction: result.fraction,
4870
5147
  endpos: result.endpos,
@@ -4873,7 +5150,7 @@ function createGame(imports, engine, options) {
4873
5150
  planeNormal: result.plane?.normal
4874
5151
  };
4875
5152
  };
4876
- const pointContentsAdapter = (point) => imports.pointcontents(point);
5153
+ const pointContentsAdapter = (point) => pointcontents(point);
4877
5154
  const newState = applyPmove(playerState, pcmd, traceAdapter, pointContentsAdapter);
4878
5155
  player.origin = newState.origin;
4879
5156
  player.velocity = newState.velocity;
@@ -4887,6 +5164,7 @@ function createGame(imports, engine, options) {
4887
5164
  centerprintf(entity, message) {
4888
5165
  engine.centerprintf?.(entity, message);
4889
5166
  },
5167
+ trace,
4890
5168
  get time() {
4891
5169
  return levelClock.current.timeSeconds;
4892
5170
  }