quake2ts 0.0.46 → 0.0.48
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.
- package/apps/viewer/dist/browser/index.global.js +1 -1
- package/apps/viewer/dist/browser/index.global.js.map +1 -1
- package/apps/viewer/dist/cjs/index.cjs +14 -3
- package/apps/viewer/dist/cjs/index.cjs.map +1 -1
- package/apps/viewer/dist/esm/index.js +14 -3
- package/apps/viewer/dist/esm/index.js.map +1 -1
- package/apps/viewer/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/packages/engine/dist/browser/index.global.js +7 -7
- package/packages/engine/dist/browser/index.global.js.map +1 -1
- package/packages/engine/dist/cjs/index.cjs +3 -1
- package/packages/engine/dist/cjs/index.cjs.map +1 -1
- package/packages/engine/dist/esm/index.js +3 -1
- package/packages/engine/dist/esm/index.js.map +1 -1
- package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/engine/dist/types/render/md3Pipeline.d.ts.map +1 -1
- package/packages/game/dist/browser/index.global.js +1 -1
- package/packages/game/dist/browser/index.global.js.map +1 -1
- package/packages/game/dist/cjs/index.cjs +176 -3
- package/packages/game/dist/cjs/index.cjs.map +1 -1
- package/packages/game/dist/esm/index.js +172 -3
- package/packages/game/dist/esm/index.js.map +1 -1
- package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/game/dist/types/ai/constants.d.ts +16 -0
- package/packages/game/dist/types/ai/constants.d.ts.map +1 -1
- package/packages/game/dist/types/ai/index.d.ts +1 -0
- package/packages/game/dist/types/ai/index.d.ts.map +1 -1
- package/packages/game/dist/types/ai/targeting.d.ts +25 -0
- package/packages/game/dist/types/ai/targeting.d.ts.map +1 -0
- package/packages/game/dist/types/entities/entity.d.ts +11 -0
- package/packages/game/dist/types/entities/entity.d.ts.map +1 -1
|
@@ -34,6 +34,7 @@ __export(index_exports, {
|
|
|
34
34
|
EntityDamageFlags: () => EntityDamageFlags,
|
|
35
35
|
EntitySystem: () => EntitySystem,
|
|
36
36
|
EnvironmentalFlags: () => EnvironmentalFlags,
|
|
37
|
+
FL_NOTARGET: () => FL_NOTARGET,
|
|
37
38
|
FL_NOVISIBLE: () => FL_NOVISIBLE,
|
|
38
39
|
KeyId: () => KeyId,
|
|
39
40
|
MoveType: () => MoveType,
|
|
@@ -87,6 +88,8 @@ __export(index_exports, {
|
|
|
87
88
|
damageModName: () => damageModName,
|
|
88
89
|
equipArmor: () => equipArmor,
|
|
89
90
|
facingIdeal: () => facingIdeal,
|
|
91
|
+
findTarget: () => findTarget,
|
|
92
|
+
foundTarget: () => foundTarget,
|
|
90
93
|
getAmmoItemDefinition: () => getAmmoItemDefinition,
|
|
91
94
|
giveAmmo: () => giveAmmo,
|
|
92
95
|
giveAmmoItem: () => giveAmmoItem,
|
|
@@ -96,6 +99,7 @@ __export(index_exports, {
|
|
|
96
99
|
hasPowerup: () => hasPowerup,
|
|
97
100
|
hasWeapon: () => hasWeapon,
|
|
98
101
|
hashGameState: () => hashGameState,
|
|
102
|
+
huntTarget: () => huntTarget,
|
|
99
103
|
infront: () => infront,
|
|
100
104
|
isZeroVector: () => isZeroVector,
|
|
101
105
|
killBox: () => killBox,
|
|
@@ -526,7 +530,12 @@ var ZERO = { ...ZERO_VEC3 };
|
|
|
526
530
|
function copyVec3() {
|
|
527
531
|
return { ...ZERO };
|
|
528
532
|
}
|
|
529
|
-
var DEFAULT_MONSTER_INFO = Object.freeze({
|
|
533
|
+
var DEFAULT_MONSTER_INFO = Object.freeze({
|
|
534
|
+
aiflags: 0,
|
|
535
|
+
last_sighting: ZERO,
|
|
536
|
+
trail_time: 0,
|
|
537
|
+
pausetime: 0
|
|
538
|
+
});
|
|
530
539
|
var Entity = class {
|
|
531
540
|
constructor(index) {
|
|
532
541
|
this.inUse = false;
|
|
@@ -586,7 +595,9 @@ var Entity = class {
|
|
|
586
595
|
this.solid = 0 /* Not */;
|
|
587
596
|
this.flags = 0;
|
|
588
597
|
this.svflags = 0;
|
|
589
|
-
this.monsterinfo = { ...DEFAULT_MONSTER_INFO };
|
|
598
|
+
this.monsterinfo = { ...DEFAULT_MONSTER_INFO, last_sighting: copyVec3() };
|
|
599
|
+
this.show_hostile = 0;
|
|
600
|
+
this.light_level = 0;
|
|
590
601
|
this.index = index;
|
|
591
602
|
}
|
|
592
603
|
reset() {
|
|
@@ -660,7 +671,10 @@ var Entity = class {
|
|
|
660
671
|
this.solid = 0 /* Not */;
|
|
661
672
|
this.flags = 0;
|
|
662
673
|
this.svflags = 0;
|
|
663
|
-
this.monsterinfo = { ...DEFAULT_MONSTER_INFO };
|
|
674
|
+
this.monsterinfo = { ...DEFAULT_MONSTER_INFO, last_sighting: copyVec3() };
|
|
675
|
+
this.combattarget = void 0;
|
|
676
|
+
this.show_hostile = 0;
|
|
677
|
+
this.light_level = 0;
|
|
664
678
|
}
|
|
665
679
|
};
|
|
666
680
|
var ENTITY_FIELD_METADATA = [
|
|
@@ -2183,9 +2197,25 @@ var LevelClock = class {
|
|
|
2183
2197
|
var RANGE_MELEE = 20;
|
|
2184
2198
|
var RANGE_NEAR = 440;
|
|
2185
2199
|
var RANGE_MID = 940;
|
|
2200
|
+
var FL_NOTARGET = 1 << 5;
|
|
2186
2201
|
var FL_NOVISIBLE = 1 << 24;
|
|
2187
2202
|
var SPAWNFLAG_MONSTER_AMBUSH = 1 << 0;
|
|
2188
2203
|
var AIFlags = /* @__PURE__ */ ((AIFlags2) => {
|
|
2204
|
+
AIFlags2[AIFlags2["StandGround"] = 1] = "StandGround";
|
|
2205
|
+
AIFlags2[AIFlags2["TempStandGround"] = 2] = "TempStandGround";
|
|
2206
|
+
AIFlags2[AIFlags2["SoundTarget"] = 4] = "SoundTarget";
|
|
2207
|
+
AIFlags2[AIFlags2["LostSight"] = 8] = "LostSight";
|
|
2208
|
+
AIFlags2[AIFlags2["PursuitLastSeen"] = 16] = "PursuitLastSeen";
|
|
2209
|
+
AIFlags2[AIFlags2["PursueNext"] = 32] = "PursueNext";
|
|
2210
|
+
AIFlags2[AIFlags2["PursueTemp"] = 64] = "PursueTemp";
|
|
2211
|
+
AIFlags2[AIFlags2["HoldFrame"] = 128] = "HoldFrame";
|
|
2212
|
+
AIFlags2[AIFlags2["GoodGuy"] = 256] = "GoodGuy";
|
|
2213
|
+
AIFlags2[AIFlags2["Brutal"] = 512] = "Brutal";
|
|
2214
|
+
AIFlags2[AIFlags2["NoStep"] = 1024] = "NoStep";
|
|
2215
|
+
AIFlags2[AIFlags2["Ducked"] = 2048] = "Ducked";
|
|
2216
|
+
AIFlags2[AIFlags2["CombatPoint"] = 4096] = "CombatPoint";
|
|
2217
|
+
AIFlags2[AIFlags2["Medic"] = 8192] = "Medic";
|
|
2218
|
+
AIFlags2[AIFlags2["Resurrecting"] = 16384] = "Resurrecting";
|
|
2189
2219
|
AIFlags2[AIFlags2["Pathing"] = 1073741824] = "Pathing";
|
|
2190
2220
|
return AIFlags2;
|
|
2191
2221
|
})(AIFlags || {});
|
|
@@ -2353,6 +2383,145 @@ function visible(self, other, trace, options) {
|
|
|
2353
2383
|
return result.fraction === 1 || result.entity === other;
|
|
2354
2384
|
}
|
|
2355
2385
|
|
|
2386
|
+
// src/ai/targeting.ts
|
|
2387
|
+
function setIdealYawTowards2(self, other) {
|
|
2388
|
+
const delta = {
|
|
2389
|
+
x: other.origin.x - self.origin.x,
|
|
2390
|
+
y: other.origin.y - self.origin.y,
|
|
2391
|
+
z: other.origin.z - self.origin.z
|
|
2392
|
+
};
|
|
2393
|
+
self.ideal_yaw = vectorToYaw(delta);
|
|
2394
|
+
}
|
|
2395
|
+
function faceYawInstantly(self) {
|
|
2396
|
+
self.angles.y = angleMod(self.ideal_yaw);
|
|
2397
|
+
}
|
|
2398
|
+
function huntTarget(self, level) {
|
|
2399
|
+
if (!self.enemy) return;
|
|
2400
|
+
self.goalentity = self.enemy;
|
|
2401
|
+
setIdealYawTowards2(self, self.enemy);
|
|
2402
|
+
faceYawInstantly(self);
|
|
2403
|
+
if ((self.monsterinfo.aiflags & 1 /* StandGround */) !== 0) {
|
|
2404
|
+
self.monsterinfo.stand?.(self);
|
|
2405
|
+
} else {
|
|
2406
|
+
self.monsterinfo.run?.(self);
|
|
2407
|
+
self.attack_finished_time = level.timeSeconds + 1;
|
|
2408
|
+
}
|
|
2409
|
+
}
|
|
2410
|
+
function foundTarget(self, level, options) {
|
|
2411
|
+
if (!self.enemy) return;
|
|
2412
|
+
if ((self.enemy.svflags & 8 /* Player */) !== 0) {
|
|
2413
|
+
level.sightEntity = self;
|
|
2414
|
+
level.sightEntityFrame = level.frameNumber;
|
|
2415
|
+
self.light_level = 128;
|
|
2416
|
+
}
|
|
2417
|
+
self.show_hostile = level.timeSeconds + 1;
|
|
2418
|
+
const lastSighting = self.monsterinfo.last_sighting;
|
|
2419
|
+
lastSighting.x = self.enemy.origin.x;
|
|
2420
|
+
lastSighting.y = self.enemy.origin.y;
|
|
2421
|
+
lastSighting.z = self.enemy.origin.z;
|
|
2422
|
+
self.trail_time = level.timeSeconds;
|
|
2423
|
+
self.monsterinfo.trail_time = level.timeSeconds;
|
|
2424
|
+
if (!self.combattarget) {
|
|
2425
|
+
huntTarget(self, level);
|
|
2426
|
+
return;
|
|
2427
|
+
}
|
|
2428
|
+
const pickTarget = options?.pickTarget;
|
|
2429
|
+
const movetarget = pickTarget?.(self.combattarget) ?? self.enemy;
|
|
2430
|
+
self.goalentity = movetarget;
|
|
2431
|
+
self.movetarget = movetarget;
|
|
2432
|
+
self.combattarget = void 0;
|
|
2433
|
+
self.monsterinfo.aiflags |= 4096 /* CombatPoint */;
|
|
2434
|
+
if (self.movetarget) {
|
|
2435
|
+
self.movetarget.targetname = void 0;
|
|
2436
|
+
}
|
|
2437
|
+
self.monsterinfo.pausetime = 0;
|
|
2438
|
+
self.monsterinfo.run?.(self);
|
|
2439
|
+
}
|
|
2440
|
+
function classifyClientVisibility(self, other, level) {
|
|
2441
|
+
const distance = rangeTo(self, other);
|
|
2442
|
+
const range = classifyRange(distance);
|
|
2443
|
+
const passthrough = (_start, _end, _ignore, _mask) => ({ fraction: 1, entity: other });
|
|
2444
|
+
if (range === "far" /* Far */) return false;
|
|
2445
|
+
if (other.light_level <= 5) return false;
|
|
2446
|
+
if (!visible(self, other, passthrough, { throughGlass: false })) return false;
|
|
2447
|
+
if (range === "near" /* Near */) {
|
|
2448
|
+
return level.timeSeconds <= other.show_hostile || infront(self, other);
|
|
2449
|
+
}
|
|
2450
|
+
if (range === "mid" /* Mid */) {
|
|
2451
|
+
return infront(self, other);
|
|
2452
|
+
}
|
|
2453
|
+
return true;
|
|
2454
|
+
}
|
|
2455
|
+
function updateSoundChase(self, client, level, hearability) {
|
|
2456
|
+
const passthrough = (_start, _end, _ignore, _mask) => ({ fraction: 1, entity: client });
|
|
2457
|
+
if ((self.spawnflags & SPAWNFLAG_MONSTER_AMBUSH) !== 0) {
|
|
2458
|
+
if (!visible(self, client, passthrough)) return false;
|
|
2459
|
+
} else if (hearability.canHear && !hearability.canHear(self, client)) {
|
|
2460
|
+
return false;
|
|
2461
|
+
}
|
|
2462
|
+
const delta = subtractVec3(client.origin, self.origin);
|
|
2463
|
+
if (lengthVec3(delta) > 1e3) return false;
|
|
2464
|
+
if (hearability.areasConnected && !hearability.areasConnected(self, client)) return false;
|
|
2465
|
+
self.ideal_yaw = vectorToYaw(delta);
|
|
2466
|
+
faceYawInstantly(self);
|
|
2467
|
+
self.monsterinfo.aiflags |= 4 /* SoundTarget */;
|
|
2468
|
+
self.enemy = client;
|
|
2469
|
+
return true;
|
|
2470
|
+
}
|
|
2471
|
+
function chooseCandidate(self, level) {
|
|
2472
|
+
if (level.sightEntity && level.sightEntityFrame >= level.frameNumber - 1 && (self.spawnflags & SPAWNFLAG_MONSTER_AMBUSH) === 0) {
|
|
2473
|
+
if (level.sightEntity.enemy !== self.enemy) {
|
|
2474
|
+
return { candidate: level.sightEntity, heardit: false };
|
|
2475
|
+
}
|
|
2476
|
+
return { candidate: null, heardit: false };
|
|
2477
|
+
}
|
|
2478
|
+
if (level.soundEntity && level.soundEntityFrame >= level.frameNumber - 1) {
|
|
2479
|
+
return { candidate: level.soundEntity, heardit: true };
|
|
2480
|
+
}
|
|
2481
|
+
if (!self.enemy && level.sound2Entity && level.sound2EntityFrame >= level.frameNumber - 1 && (self.spawnflags & SPAWNFLAG_MONSTER_AMBUSH) === 0) {
|
|
2482
|
+
return { candidate: level.sound2Entity, heardit: true };
|
|
2483
|
+
}
|
|
2484
|
+
if (level.sightClient) {
|
|
2485
|
+
return { candidate: level.sightClient, heardit: false };
|
|
2486
|
+
}
|
|
2487
|
+
return { candidate: null, heardit: false };
|
|
2488
|
+
}
|
|
2489
|
+
function rejectNotargetEntity(client) {
|
|
2490
|
+
if ((client.flags & FL_NOTARGET) !== 0) return true;
|
|
2491
|
+
if ((client.svflags & 4 /* Monster */) !== 0 && client.enemy) {
|
|
2492
|
+
return (client.enemy.flags & FL_NOTARGET) !== 0;
|
|
2493
|
+
}
|
|
2494
|
+
if (client.enemy && (client.enemy.flags & FL_NOTARGET) !== 0) return true;
|
|
2495
|
+
return false;
|
|
2496
|
+
}
|
|
2497
|
+
function findTarget(self, level, hearability = {}) {
|
|
2498
|
+
if ((self.monsterinfo.aiflags & 256 /* GoodGuy */) !== 0) {
|
|
2499
|
+
if (self.goalentity?.classname === "target_actor") {
|
|
2500
|
+
return false;
|
|
2501
|
+
}
|
|
2502
|
+
return false;
|
|
2503
|
+
}
|
|
2504
|
+
if ((self.monsterinfo.aiflags & 4096 /* CombatPoint */) !== 0) {
|
|
2505
|
+
return false;
|
|
2506
|
+
}
|
|
2507
|
+
const { candidate, heardit } = chooseCandidate(self, level);
|
|
2508
|
+
if (!candidate || !candidate.inUse) return false;
|
|
2509
|
+
if (candidate === self.enemy) return true;
|
|
2510
|
+
if (rejectNotargetEntity(candidate)) return false;
|
|
2511
|
+
if (!heardit) {
|
|
2512
|
+
if (!classifyClientVisibility(self, candidate, level)) return false;
|
|
2513
|
+
self.monsterinfo.aiflags &= ~4 /* SoundTarget */;
|
|
2514
|
+
self.enemy = candidate;
|
|
2515
|
+
} else if (!updateSoundChase(self, candidate, level, hearability)) {
|
|
2516
|
+
return false;
|
|
2517
|
+
}
|
|
2518
|
+
foundTarget(self, level);
|
|
2519
|
+
if ((self.monsterinfo.aiflags & 4 /* SoundTarget */) === 0) {
|
|
2520
|
+
self.monsterinfo.sight?.(self, self.enemy);
|
|
2521
|
+
}
|
|
2522
|
+
return true;
|
|
2523
|
+
}
|
|
2524
|
+
|
|
2356
2525
|
// src/checksum.ts
|
|
2357
2526
|
var FNV_OFFSET_BASIS = 2166136261;
|
|
2358
2527
|
var FNV_PRIME = 16777619;
|
|
@@ -3816,6 +3985,7 @@ function createGame(engine, options) {
|
|
|
3816
3985
|
EntityDamageFlags,
|
|
3817
3986
|
EntitySystem,
|
|
3818
3987
|
EnvironmentalFlags,
|
|
3988
|
+
FL_NOTARGET,
|
|
3819
3989
|
FL_NOVISIBLE,
|
|
3820
3990
|
KeyId,
|
|
3821
3991
|
MoveType,
|
|
@@ -3869,6 +4039,8 @@ function createGame(engine, options) {
|
|
|
3869
4039
|
damageModName,
|
|
3870
4040
|
equipArmor,
|
|
3871
4041
|
facingIdeal,
|
|
4042
|
+
findTarget,
|
|
4043
|
+
foundTarget,
|
|
3872
4044
|
getAmmoItemDefinition,
|
|
3873
4045
|
giveAmmo,
|
|
3874
4046
|
giveAmmoItem,
|
|
@@ -3878,6 +4050,7 @@ function createGame(engine, options) {
|
|
|
3878
4050
|
hasPowerup,
|
|
3879
4051
|
hasWeapon,
|
|
3880
4052
|
hashGameState,
|
|
4053
|
+
huntTarget,
|
|
3881
4054
|
infront,
|
|
3882
4055
|
isZeroVector,
|
|
3883
4056
|
killBox,
|