quake2ts 0.0.80 → 0.0.82
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/package.json +1 -1
- package/packages/client/dist/browser/index.global.js +1 -1
- package/packages/client/dist/browser/index.global.js.map +1 -1
- package/packages/client/dist/cjs/index.cjs +9 -1
- package/packages/client/dist/cjs/index.cjs.map +1 -1
- package/packages/client/dist/esm/index.js +9 -1
- package/packages/client/dist/esm/index.js.map +1 -1
- package/packages/client/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/client/dist/types/hud.d.ts.map +1 -1
- package/packages/client/dist/types/prediction.d.ts +2 -0
- package/packages/client/dist/types/prediction.d.ts.map +1 -1
- package/packages/engine/dist/browser/index.global.js +4 -2
- package/packages/engine/dist/browser/index.global.js.map +1 -1
- package/packages/engine/dist/cjs/index.cjs +6 -2
- package/packages/engine/dist/cjs/index.cjs.map +1 -1
- package/packages/engine/dist/esm/index.js +6 -2
- package/packages/engine/dist/esm/index.js.map +1 -1
- package/packages/engine/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/engine/dist/types/render/light.d.ts +10 -0
- package/packages/engine/dist/types/render/light.d.ts.map +1 -0
- package/packages/engine/dist/types/render/md2Pipeline.d.ts +3 -1
- package/packages/engine/dist/types/render/md2Pipeline.d.ts.map +1 -1
- package/packages/engine/dist/types/render/renderer.d.ts +1 -0
- package/packages/engine/dist/types/render/renderer.d.ts.map +1 -1
- package/packages/engine/dist/types/render/scene.d.ts +1 -0
- package/packages/engine/dist/types/render/scene.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 +724 -440
- package/packages/game/dist/cjs/index.cjs.map +1 -1
- package/packages/game/dist/esm/index.js +719 -440
- package/packages/game/dist/esm/index.js.map +1 -1
- package/packages/game/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/game/dist/types/ai/monster.d.ts +3 -2
- package/packages/game/dist/types/ai/monster.d.ts.map +1 -1
- package/packages/game/dist/types/ai/movement.d.ts +2 -1
- package/packages/game/dist/types/ai/movement.d.ts.map +1 -1
- package/packages/game/dist/types/ai/targeting.d.ts +4 -3
- package/packages/game/dist/types/ai/targeting.d.ts.map +1 -1
- package/packages/game/dist/types/entities/entity.d.ts +3 -2
- package/packages/game/dist/types/entities/entity.d.ts.map +1 -1
- package/packages/game/dist/types/entities/funcs.d.ts.map +1 -1
- package/packages/game/dist/types/entities/items/ammo.d.ts +5 -0
- package/packages/game/dist/types/entities/items/ammo.d.ts.map +1 -0
- package/packages/game/dist/types/entities/items/index.d.ts +5 -0
- package/packages/game/dist/types/entities/items/index.d.ts.map +1 -1
- package/packages/game/dist/types/entities/items.d.ts.map +1 -1
- package/packages/game/dist/types/entities/monsters/attack.d.ts +8 -0
- package/packages/game/dist/types/entities/monsters/attack.d.ts.map +1 -0
- package/packages/game/dist/types/entities/monsters/gunner.d.ts +3 -0
- package/packages/game/dist/types/entities/monsters/gunner.d.ts.map +1 -0
- package/packages/game/dist/types/entities/monsters/soldier.d.ts.map +1 -1
- package/packages/game/dist/types/entities/projectiles.d.ts +6 -5
- package/packages/game/dist/types/entities/projectiles.d.ts.map +1 -1
- package/packages/game/dist/types/entities/spawn.d.ts.map +1 -1
- package/packages/game/dist/types/entities/system.d.ts +3 -1
- package/packages/game/dist/types/entities/system.d.ts.map +1 -1
- package/packages/game/dist/types/imports.d.ts +4 -2
- package/packages/game/dist/types/imports.d.ts.map +1 -1
- package/packages/shared/dist/tsconfig.tsbuildinfo +1 -1
- package/packages/shared/dist/types/protocol/player-state.d.ts +2 -0
- package/packages/shared/dist/types/protocol/player-state.d.ts.map +1 -1
- package/packages/tools/dist/tsconfig.tsbuildinfo +1 -1
|
@@ -89,12 +89,17 @@ __export(index_exports, {
|
|
|
89
89
|
convertRereleaseLevelToGameSave: () => convertRereleaseLevelToGameSave,
|
|
90
90
|
convertRereleaseSaveToGameSave: () => convertRereleaseSaveToGameSave,
|
|
91
91
|
createAmmoInventory: () => createAmmoInventory,
|
|
92
|
+
createAmmoPickupEntity: () => createAmmoPickupEntity,
|
|
93
|
+
createArmorPickupEntity: () => createArmorPickupEntity,
|
|
92
94
|
createBaseAmmoCaps: () => createBaseAmmoCaps,
|
|
93
95
|
createCallbackRegistry: () => createCallbackRegistry,
|
|
94
96
|
createDefaultSpawnRegistry: () => createDefaultSpawnRegistry,
|
|
95
97
|
createGame: () => createGame,
|
|
98
|
+
createHealthPickupEntity: () => createHealthPickupEntity,
|
|
99
|
+
createKeyPickupEntity: () => createKeyPickupEntity,
|
|
96
100
|
createPlayerInventory: () => createPlayerInventory,
|
|
97
101
|
createPlayerWeaponStates: () => createPlayerWeaponStates,
|
|
102
|
+
createPowerupPickupEntity: () => createPowerupPickupEntity,
|
|
98
103
|
createSaveFile: () => createSaveFile,
|
|
99
104
|
createWeaponPickupEntity: () => createWeaponPickupEntity,
|
|
100
105
|
damageModName: () => damageModName,
|
|
@@ -1528,6 +1533,12 @@ var EntitySystem = class {
|
|
|
1528
1533
|
}
|
|
1529
1534
|
}
|
|
1530
1535
|
}
|
|
1536
|
+
get trace() {
|
|
1537
|
+
return this.imports.trace;
|
|
1538
|
+
}
|
|
1539
|
+
get pointcontents() {
|
|
1540
|
+
return this.imports.pointcontents;
|
|
1541
|
+
}
|
|
1531
1542
|
get world() {
|
|
1532
1543
|
return this.pool.world;
|
|
1533
1544
|
}
|
|
@@ -2479,14 +2490,14 @@ var AmmoType = /* @__PURE__ */ ((AmmoType3) => {
|
|
|
2479
2490
|
return AmmoType3;
|
|
2480
2491
|
})(AmmoType || {});
|
|
2481
2492
|
var AMMO_TYPE_COUNT = Object.keys(AmmoType).length / 2;
|
|
2482
|
-
var AmmoItemId = /* @__PURE__ */ ((
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
return
|
|
2493
|
+
var AmmoItemId = /* @__PURE__ */ ((AmmoItemId4) => {
|
|
2494
|
+
AmmoItemId4["Shells"] = "ammo_shells";
|
|
2495
|
+
AmmoItemId4["Bullets"] = "ammo_bullets";
|
|
2496
|
+
AmmoItemId4["Rockets"] = "ammo_rockets";
|
|
2497
|
+
AmmoItemId4["Grenades"] = "ammo_grenades";
|
|
2498
|
+
AmmoItemId4["Cells"] = "ammo_cells";
|
|
2499
|
+
AmmoItemId4["Slugs"] = "ammo_slugs";
|
|
2500
|
+
return AmmoItemId4;
|
|
2490
2501
|
})(AmmoItemId || {});
|
|
2491
2502
|
var AMMO_ITEM_DEFINITIONS = {
|
|
2492
2503
|
["ammo_shells" /* Shells */]: { id: "ammo_shells" /* Shells */, ammoType: 1 /* Shells */, quantity: 10, weaponAmmo: false },
|
|
@@ -3221,6 +3232,32 @@ function createKeyPickupEntity(game, keyItem) {
|
|
|
3221
3232
|
};
|
|
3222
3233
|
}
|
|
3223
3234
|
|
|
3235
|
+
// src/entities/items/ammo.ts
|
|
3236
|
+
function createAmmoPickupEntity(game, itemId) {
|
|
3237
|
+
const def = getAmmoItemDefinition(itemId);
|
|
3238
|
+
const respawn = (self) => {
|
|
3239
|
+
self.solid = 1 /* Trigger */;
|
|
3240
|
+
};
|
|
3241
|
+
return {
|
|
3242
|
+
classname: itemId,
|
|
3243
|
+
solid: 1 /* Trigger */,
|
|
3244
|
+
touch: (self, other) => {
|
|
3245
|
+
if (!other || !other.client) {
|
|
3246
|
+
return;
|
|
3247
|
+
}
|
|
3248
|
+
const result = pickupAmmo(other.client.inventory.ammo, itemId);
|
|
3249
|
+
if (result.pickedUp) {
|
|
3250
|
+
game.sound?.(other, 0, "items/pkup.wav", 1, 1, 0);
|
|
3251
|
+
game.centerprintf?.(other, `You got ${def.quantity} ${itemId.replace("ammo_", "")}`);
|
|
3252
|
+
self.solid = 0 /* Not */;
|
|
3253
|
+
self.nextthink = game.time + 30;
|
|
3254
|
+
game.entities.scheduleThink(self, self.nextthink);
|
|
3255
|
+
}
|
|
3256
|
+
},
|
|
3257
|
+
think: respawn
|
|
3258
|
+
};
|
|
3259
|
+
}
|
|
3260
|
+
|
|
3224
3261
|
// src/entities/items.ts
|
|
3225
3262
|
function registerItemSpawns(game, registry) {
|
|
3226
3263
|
for (const weaponItem of Object.values(WEAPON_ITEMS)) {
|
|
@@ -3248,6 +3285,11 @@ function registerItemSpawns(game, registry) {
|
|
|
3248
3285
|
Object.assign(entity, createKeyPickupEntity(game, keyItem));
|
|
3249
3286
|
});
|
|
3250
3287
|
}
|
|
3288
|
+
for (const ammoId of Object.values(AmmoItemId)) {
|
|
3289
|
+
registry.register(ammoId, (entity) => {
|
|
3290
|
+
Object.assign(entity, createAmmoPickupEntity(game, ammoId));
|
|
3291
|
+
});
|
|
3292
|
+
}
|
|
3251
3293
|
}
|
|
3252
3294
|
|
|
3253
3295
|
// src/entities/funcs.ts
|
|
@@ -3312,6 +3354,7 @@ var func_door = (entity, context) => {
|
|
|
3312
3354
|
self.state = 1 /* Opening */;
|
|
3313
3355
|
self.think = door_go_up;
|
|
3314
3356
|
context.entities.scheduleThink(self, context.entities.timeSeconds + 0.1);
|
|
3357
|
+
context.entities.sound(self, 0, "doors/dr1_strt.wav", 1, 1, 0);
|
|
3315
3358
|
};
|
|
3316
3359
|
};
|
|
3317
3360
|
var func_button = (entity, context) => {
|
|
@@ -3319,6 +3362,7 @@ var func_button = (entity, context) => {
|
|
|
3319
3362
|
entity.movetype = 2 /* Push */;
|
|
3320
3363
|
entity.use = (self) => {
|
|
3321
3364
|
context.entities.useTargets(self, self);
|
|
3365
|
+
context.entities.sound(self, 0, "switches/butn2.wav", 1, 1, 0);
|
|
3322
3366
|
};
|
|
3323
3367
|
};
|
|
3324
3368
|
var TRAIN_START_ON = 1;
|
|
@@ -3596,6 +3640,66 @@ var TraceMask = /* @__PURE__ */ ((TraceMask2) => {
|
|
|
3596
3640
|
return TraceMask2;
|
|
3597
3641
|
})(TraceMask || {});
|
|
3598
3642
|
|
|
3643
|
+
// src/ai/perception.ts
|
|
3644
|
+
var RangeCategory = /* @__PURE__ */ ((RangeCategory2) => {
|
|
3645
|
+
RangeCategory2["Melee"] = "melee";
|
|
3646
|
+
RangeCategory2["Near"] = "near";
|
|
3647
|
+
RangeCategory2["Mid"] = "mid";
|
|
3648
|
+
RangeCategory2["Far"] = "far";
|
|
3649
|
+
return RangeCategory2;
|
|
3650
|
+
})(RangeCategory || {});
|
|
3651
|
+
function absBounds(entity) {
|
|
3652
|
+
return {
|
|
3653
|
+
mins: {
|
|
3654
|
+
x: entity.origin.x + entity.mins.x,
|
|
3655
|
+
y: entity.origin.y + entity.mins.y,
|
|
3656
|
+
z: entity.origin.z + entity.mins.z
|
|
3657
|
+
},
|
|
3658
|
+
maxs: {
|
|
3659
|
+
x: entity.origin.x + entity.maxs.x,
|
|
3660
|
+
y: entity.origin.y + entity.maxs.y,
|
|
3661
|
+
z: entity.origin.z + entity.maxs.z
|
|
3662
|
+
}
|
|
3663
|
+
};
|
|
3664
|
+
}
|
|
3665
|
+
function rangeTo(self, other) {
|
|
3666
|
+
const a = absBounds(self);
|
|
3667
|
+
const b = absBounds(other);
|
|
3668
|
+
const distanceSquared = distanceBetweenBoxesSquared(a.mins, a.maxs, b.mins, b.maxs);
|
|
3669
|
+
return Math.sqrt(distanceSquared);
|
|
3670
|
+
}
|
|
3671
|
+
function classifyRange(distance2) {
|
|
3672
|
+
if (distance2 <= RANGE_MELEE) {
|
|
3673
|
+
return "melee" /* Melee */;
|
|
3674
|
+
}
|
|
3675
|
+
if (distance2 <= RANGE_NEAR) {
|
|
3676
|
+
return "near" /* Near */;
|
|
3677
|
+
}
|
|
3678
|
+
if (distance2 <= RANGE_MID) {
|
|
3679
|
+
return "mid" /* Mid */;
|
|
3680
|
+
}
|
|
3681
|
+
return "far" /* Far */;
|
|
3682
|
+
}
|
|
3683
|
+
function infront(self, other) {
|
|
3684
|
+
const { forward } = angleVectors(self.angles);
|
|
3685
|
+
const direction = normalizeVec3(subtractVec3(other.origin, self.origin));
|
|
3686
|
+
const dot = dotVec3(direction, forward);
|
|
3687
|
+
if ((self.spawnflags & SPAWNFLAG_MONSTER_AMBUSH) !== 0 && self.trail_time === 0 && self.enemy === null) {
|
|
3688
|
+
return dot > 0.15;
|
|
3689
|
+
}
|
|
3690
|
+
return dot > -0.3;
|
|
3691
|
+
}
|
|
3692
|
+
function visible(self, other, trace, options) {
|
|
3693
|
+
if ((other.flags & FL_NOVISIBLE) !== 0) {
|
|
3694
|
+
return false;
|
|
3695
|
+
}
|
|
3696
|
+
const start = { x: self.origin.x, y: self.origin.y, z: self.origin.z + self.viewheight };
|
|
3697
|
+
const end = { x: other.origin.x, y: other.origin.y, z: other.origin.z + other.viewheight };
|
|
3698
|
+
const mask = options?.throughGlass ? 1 /* Opaque */ : 1 /* Opaque */ | 2 /* Window */;
|
|
3699
|
+
const result = trace(start, end, self, mask);
|
|
3700
|
+
return result.fraction === 1 || result.entity === other;
|
|
3701
|
+
}
|
|
3702
|
+
|
|
3599
3703
|
// src/ai/movement.ts
|
|
3600
3704
|
function yawVector(yawDegrees, distance2) {
|
|
3601
3705
|
if (distance2 === 0) {
|
|
@@ -3657,12 +3761,24 @@ function setIdealYawTowards(self, target) {
|
|
|
3657
3761
|
function ai_stand(self, deltaSeconds) {
|
|
3658
3762
|
changeYaw(self, deltaSeconds);
|
|
3659
3763
|
}
|
|
3660
|
-
function ai_walk(self, distance2, deltaSeconds) {
|
|
3764
|
+
function ai_walk(self, distance2, deltaSeconds, context) {
|
|
3661
3765
|
setIdealYawTowards(self, self.goalentity);
|
|
3662
3766
|
changeYaw(self, deltaSeconds);
|
|
3663
3767
|
if (distance2 !== 0) {
|
|
3664
3768
|
walkMove(self, self.angles.y, distance2);
|
|
3665
3769
|
}
|
|
3770
|
+
if (self.goalentity && self.goalentity.classname === "path_corner") {
|
|
3771
|
+
const dist = rangeTo(self, self.goalentity);
|
|
3772
|
+
if (dist < 64) {
|
|
3773
|
+
if (self.goalentity.target) {
|
|
3774
|
+
const next = context.pickTarget(self.goalentity.target);
|
|
3775
|
+
if (next) {
|
|
3776
|
+
self.goalentity = next;
|
|
3777
|
+
self.ideal_yaw = self.angles.y;
|
|
3778
|
+
}
|
|
3779
|
+
}
|
|
3780
|
+
}
|
|
3781
|
+
}
|
|
3666
3782
|
}
|
|
3667
3783
|
function ai_turn(self, distance2, deltaSeconds) {
|
|
3668
3784
|
if (distance2 !== 0) {
|
|
@@ -3694,66 +3810,6 @@ function ai_charge(self, distance2, deltaSeconds) {
|
|
|
3694
3810
|
}
|
|
3695
3811
|
}
|
|
3696
3812
|
|
|
3697
|
-
// src/ai/perception.ts
|
|
3698
|
-
var RangeCategory = /* @__PURE__ */ ((RangeCategory2) => {
|
|
3699
|
-
RangeCategory2["Melee"] = "melee";
|
|
3700
|
-
RangeCategory2["Near"] = "near";
|
|
3701
|
-
RangeCategory2["Mid"] = "mid";
|
|
3702
|
-
RangeCategory2["Far"] = "far";
|
|
3703
|
-
return RangeCategory2;
|
|
3704
|
-
})(RangeCategory || {});
|
|
3705
|
-
function absBounds(entity) {
|
|
3706
|
-
return {
|
|
3707
|
-
mins: {
|
|
3708
|
-
x: entity.origin.x + entity.mins.x,
|
|
3709
|
-
y: entity.origin.y + entity.mins.y,
|
|
3710
|
-
z: entity.origin.z + entity.mins.z
|
|
3711
|
-
},
|
|
3712
|
-
maxs: {
|
|
3713
|
-
x: entity.origin.x + entity.maxs.x,
|
|
3714
|
-
y: entity.origin.y + entity.maxs.y,
|
|
3715
|
-
z: entity.origin.z + entity.maxs.z
|
|
3716
|
-
}
|
|
3717
|
-
};
|
|
3718
|
-
}
|
|
3719
|
-
function rangeTo(self, other) {
|
|
3720
|
-
const a = absBounds(self);
|
|
3721
|
-
const b = absBounds(other);
|
|
3722
|
-
const distanceSquared = distanceBetweenBoxesSquared(a.mins, a.maxs, b.mins, b.maxs);
|
|
3723
|
-
return Math.sqrt(distanceSquared);
|
|
3724
|
-
}
|
|
3725
|
-
function classifyRange(distance2) {
|
|
3726
|
-
if (distance2 <= RANGE_MELEE) {
|
|
3727
|
-
return "melee" /* Melee */;
|
|
3728
|
-
}
|
|
3729
|
-
if (distance2 <= RANGE_NEAR) {
|
|
3730
|
-
return "near" /* Near */;
|
|
3731
|
-
}
|
|
3732
|
-
if (distance2 <= RANGE_MID) {
|
|
3733
|
-
return "mid" /* Mid */;
|
|
3734
|
-
}
|
|
3735
|
-
return "far" /* Far */;
|
|
3736
|
-
}
|
|
3737
|
-
function infront(self, other) {
|
|
3738
|
-
const { forward } = angleVectors(self.angles);
|
|
3739
|
-
const direction = normalizeVec3(subtractVec3(other.origin, self.origin));
|
|
3740
|
-
const dot = dotVec3(direction, forward);
|
|
3741
|
-
if ((self.spawnflags & SPAWNFLAG_MONSTER_AMBUSH) !== 0 && self.trail_time === 0 && self.enemy === null) {
|
|
3742
|
-
return dot > 0.15;
|
|
3743
|
-
}
|
|
3744
|
-
return dot > -0.3;
|
|
3745
|
-
}
|
|
3746
|
-
function visible(self, other, trace, options) {
|
|
3747
|
-
if ((other.flags & FL_NOVISIBLE) !== 0) {
|
|
3748
|
-
return false;
|
|
3749
|
-
}
|
|
3750
|
-
const start = { x: self.origin.x, y: self.origin.y, z: self.origin.z + self.viewheight };
|
|
3751
|
-
const end = { x: other.origin.x, y: other.origin.y, z: other.origin.z + other.viewheight };
|
|
3752
|
-
const mask = options?.throughGlass ? 1 /* Opaque */ : 1 /* Opaque */ | 2 /* Window */;
|
|
3753
|
-
const result = trace(start, end, self, mask);
|
|
3754
|
-
return result.fraction === 1 || result.entity === other;
|
|
3755
|
-
}
|
|
3756
|
-
|
|
3757
3813
|
// src/ai/targeting.ts
|
|
3758
3814
|
function setIdealYawTowards2(self, other) {
|
|
3759
3815
|
const delta = {
|
|
@@ -3766,19 +3822,19 @@ function setIdealYawTowards2(self, other) {
|
|
|
3766
3822
|
function faceYawInstantly(self) {
|
|
3767
3823
|
self.angles.y = angleMod(self.ideal_yaw);
|
|
3768
3824
|
}
|
|
3769
|
-
function huntTarget(self, level) {
|
|
3825
|
+
function huntTarget(self, level, context) {
|
|
3770
3826
|
if (!self.enemy) return;
|
|
3771
3827
|
self.goalentity = self.enemy;
|
|
3772
3828
|
setIdealYawTowards2(self, self.enemy);
|
|
3773
3829
|
faceYawInstantly(self);
|
|
3774
3830
|
if ((self.monsterinfo.aiflags & 1 /* StandGround */) !== 0) {
|
|
3775
|
-
self.monsterinfo.stand?.(self);
|
|
3831
|
+
self.monsterinfo.stand?.(self, context);
|
|
3776
3832
|
} else {
|
|
3777
|
-
self.monsterinfo.run?.(self);
|
|
3833
|
+
self.monsterinfo.run?.(self, context);
|
|
3778
3834
|
self.attack_finished_time = level.timeSeconds + 1;
|
|
3779
3835
|
}
|
|
3780
3836
|
}
|
|
3781
|
-
function foundTarget(self, level, options) {
|
|
3837
|
+
function foundTarget(self, level, context, options) {
|
|
3782
3838
|
if (!self.enemy) return;
|
|
3783
3839
|
if ((self.enemy.svflags & 8 /* Player */) !== 0) {
|
|
3784
3840
|
level.sightEntity = self;
|
|
@@ -3793,7 +3849,7 @@ function foundTarget(self, level, options) {
|
|
|
3793
3849
|
self.trail_time = level.timeSeconds;
|
|
3794
3850
|
self.monsterinfo.trail_time = level.timeSeconds;
|
|
3795
3851
|
if (!self.combattarget) {
|
|
3796
|
-
huntTarget(self, level);
|
|
3852
|
+
huntTarget(self, level, context);
|
|
3797
3853
|
return;
|
|
3798
3854
|
}
|
|
3799
3855
|
const pickTarget = options?.pickTarget;
|
|
@@ -3806,7 +3862,7 @@ function foundTarget(self, level, options) {
|
|
|
3806
3862
|
self.movetarget.targetname = void 0;
|
|
3807
3863
|
}
|
|
3808
3864
|
self.monsterinfo.pausetime = 0;
|
|
3809
|
-
self.monsterinfo.run?.(self);
|
|
3865
|
+
self.monsterinfo.run?.(self, context);
|
|
3810
3866
|
}
|
|
3811
3867
|
function classifyClientVisibility(self, other, level, trace) {
|
|
3812
3868
|
const distance2 = rangeTo(self, other);
|
|
@@ -3863,7 +3919,7 @@ function rejectNotargetEntity(client) {
|
|
|
3863
3919
|
if (client.enemy && (client.enemy.flags & FL_NOTARGET) !== 0) return true;
|
|
3864
3920
|
return false;
|
|
3865
3921
|
}
|
|
3866
|
-
function findTarget(self, level, trace, hearability = {}) {
|
|
3922
|
+
function findTarget(self, level, context, trace, hearability = {}) {
|
|
3867
3923
|
if ((self.monsterinfo.aiflags & 256 /* GoodGuy */) !== 0) {
|
|
3868
3924
|
if (self.goalentity?.classname === "target_actor") {
|
|
3869
3925
|
return false;
|
|
@@ -3884,7 +3940,7 @@ function findTarget(self, level, trace, hearability = {}) {
|
|
|
3884
3940
|
} else if (!updateSoundChase(self, candidate, level, hearability, trace)) {
|
|
3885
3941
|
return false;
|
|
3886
3942
|
}
|
|
3887
|
-
foundTarget(self, level);
|
|
3943
|
+
foundTarget(self, level, context);
|
|
3888
3944
|
if ((self.monsterinfo.aiflags & 4 /* SoundTarget */) === 0) {
|
|
3889
3945
|
self.monsterinfo.sight?.(self, self.enemy);
|
|
3890
3946
|
}
|
|
@@ -3892,7 +3948,7 @@ function findTarget(self, level, trace, hearability = {}) {
|
|
|
3892
3948
|
}
|
|
3893
3949
|
|
|
3894
3950
|
// src/ai/monster.ts
|
|
3895
|
-
function M_MoveFrame(self) {
|
|
3951
|
+
function M_MoveFrame(self, context) {
|
|
3896
3952
|
const move = self.monsterinfo.current_move;
|
|
3897
3953
|
if (!move) {
|
|
3898
3954
|
return;
|
|
@@ -3907,10 +3963,10 @@ function M_MoveFrame(self) {
|
|
|
3907
3963
|
const index = self.frame - move.firstframe;
|
|
3908
3964
|
const frame = move.frames[index];
|
|
3909
3965
|
if (frame.ai) {
|
|
3910
|
-
frame.ai(self, frame.dist);
|
|
3966
|
+
frame.ai(self, frame.dist, context);
|
|
3911
3967
|
}
|
|
3912
3968
|
if (frame.think) {
|
|
3913
|
-
frame.think(self);
|
|
3969
|
+
frame.think(self, context);
|
|
3914
3970
|
}
|
|
3915
3971
|
if (!self.inUse) {
|
|
3916
3972
|
return;
|
|
@@ -3918,7 +3974,7 @@ function M_MoveFrame(self) {
|
|
|
3918
3974
|
self.frame++;
|
|
3919
3975
|
if (self.frame > move.lastframe) {
|
|
3920
3976
|
if (move.endfunc) {
|
|
3921
|
-
move.endfunc(self);
|
|
3977
|
+
move.endfunc(self, context);
|
|
3922
3978
|
if (self.monsterinfo.current_move !== move) {
|
|
3923
3979
|
return;
|
|
3924
3980
|
}
|
|
@@ -3926,125 +3982,589 @@ function M_MoveFrame(self) {
|
|
|
3926
3982
|
}
|
|
3927
3983
|
}
|
|
3928
3984
|
function monster_think(self, context) {
|
|
3929
|
-
M_MoveFrame(self);
|
|
3930
|
-
|
|
3931
|
-
self.nextthink = time + 0.1;
|
|
3932
|
-
}
|
|
3933
|
-
|
|
3934
|
-
// src/entities/monsters/soldier.ts
|
|
3935
|
-
var MONSTER_TICK = 0.1;
|
|
3936
|
-
function monster_ai_stand(self, dist) {
|
|
3937
|
-
ai_stand(self, MONSTER_TICK);
|
|
3938
|
-
}
|
|
3939
|
-
function monster_ai_walk(self, dist) {
|
|
3940
|
-
ai_walk(self, dist, MONSTER_TICK);
|
|
3941
|
-
}
|
|
3942
|
-
function monster_ai_run(self, dist) {
|
|
3943
|
-
ai_run(self, dist, MONSTER_TICK);
|
|
3944
|
-
}
|
|
3945
|
-
function monster_ai_charge(self, dist) {
|
|
3946
|
-
ai_charge(self, dist, MONSTER_TICK);
|
|
3947
|
-
}
|
|
3948
|
-
var stand_move;
|
|
3949
|
-
var walk_move;
|
|
3950
|
-
var run_move;
|
|
3951
|
-
var attack_move;
|
|
3952
|
-
function soldier_stand(self) {
|
|
3953
|
-
self.monsterinfo.current_move = stand_move;
|
|
3954
|
-
}
|
|
3955
|
-
function soldier_walk(self) {
|
|
3956
|
-
self.monsterinfo.current_move = walk_move;
|
|
3957
|
-
}
|
|
3958
|
-
function soldier_run(self) {
|
|
3959
|
-
if (self.enemy && self.enemy.health > 0) {
|
|
3960
|
-
self.monsterinfo.current_move = run_move;
|
|
3961
|
-
} else {
|
|
3962
|
-
self.monsterinfo.current_move = stand_move;
|
|
3963
|
-
}
|
|
3964
|
-
}
|
|
3965
|
-
function soldier_attack(self) {
|
|
3966
|
-
self.monsterinfo.current_move = attack_move;
|
|
3967
|
-
}
|
|
3968
|
-
function soldier_fire(self) {
|
|
3969
|
-
}
|
|
3970
|
-
var stand_frames = Array.from({ length: 30 }, () => ({
|
|
3971
|
-
ai: monster_ai_stand,
|
|
3972
|
-
dist: 0
|
|
3973
|
-
}));
|
|
3974
|
-
stand_move = {
|
|
3975
|
-
firstframe: 0,
|
|
3976
|
-
lastframe: 29,
|
|
3977
|
-
frames: stand_frames,
|
|
3978
|
-
endfunc: soldier_stand
|
|
3979
|
-
};
|
|
3980
|
-
var walk_frames = Array.from({ length: 40 }, () => ({
|
|
3981
|
-
ai: monster_ai_walk,
|
|
3982
|
-
dist: 2
|
|
3983
|
-
}));
|
|
3984
|
-
walk_move = {
|
|
3985
|
-
firstframe: 30,
|
|
3986
|
-
lastframe: 69,
|
|
3987
|
-
frames: walk_frames,
|
|
3988
|
-
endfunc: soldier_walk
|
|
3989
|
-
};
|
|
3990
|
-
var run_frames = Array.from({ length: 20 }, () => ({
|
|
3991
|
-
ai: monster_ai_run,
|
|
3992
|
-
dist: 10
|
|
3993
|
-
}));
|
|
3994
|
-
run_move = {
|
|
3995
|
-
firstframe: 70,
|
|
3996
|
-
lastframe: 89,
|
|
3997
|
-
frames: run_frames,
|
|
3998
|
-
endfunc: soldier_run
|
|
3999
|
-
};
|
|
4000
|
-
var attack_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
4001
|
-
ai: monster_ai_charge,
|
|
4002
|
-
dist: 0,
|
|
4003
|
-
think: i === 5 ? soldier_fire : null
|
|
4004
|
-
}));
|
|
4005
|
-
attack_move = {
|
|
4006
|
-
firstframe: 90,
|
|
4007
|
-
lastframe: 99,
|
|
4008
|
-
frames: attack_frames,
|
|
4009
|
-
endfunc: soldier_run
|
|
4010
|
-
};
|
|
4011
|
-
function SP_monster_soldier(self, context) {
|
|
4012
|
-
self.model = "models/monsters/soldier/tris.md2";
|
|
4013
|
-
self.mins = { x: -16, y: -16, z: -24 };
|
|
4014
|
-
self.maxs = { x: 16, y: 16, z: 32 };
|
|
4015
|
-
self.movetype = 5 /* Step */;
|
|
4016
|
-
self.solid = 2 /* BoundingBox */;
|
|
4017
|
-
self.health = 20;
|
|
4018
|
-
self.max_health = 20;
|
|
4019
|
-
self.mass = 100;
|
|
4020
|
-
self.pain = (self2, other, kick, damage) => {
|
|
4021
|
-
};
|
|
4022
|
-
self.die = (self2, inflictor, attacker, damage, point) => {
|
|
4023
|
-
self2.deadflag = 2 /* Dead */;
|
|
4024
|
-
self2.solid = 0 /* Not */;
|
|
4025
|
-
};
|
|
4026
|
-
self.monsterinfo.stand = soldier_stand;
|
|
4027
|
-
self.monsterinfo.walk = soldier_walk;
|
|
4028
|
-
self.monsterinfo.run = soldier_run;
|
|
4029
|
-
self.monsterinfo.attack = soldier_attack;
|
|
4030
|
-
self.think = monster_think;
|
|
4031
|
-
soldier_stand(self);
|
|
4032
|
-
self.nextthink = self.timestamp + MONSTER_TICK;
|
|
4033
|
-
}
|
|
4034
|
-
function registerMonsterSpawns(registry) {
|
|
4035
|
-
registry.register("monster_soldier", SP_monster_soldier);
|
|
3985
|
+
M_MoveFrame(self, context);
|
|
3986
|
+
self.nextthink = context.timeSeconds + 0.1;
|
|
4036
3987
|
}
|
|
4037
3988
|
|
|
4038
|
-
// src/
|
|
4039
|
-
var
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4047
|
-
|
|
3989
|
+
// src/combat/damageMods.ts
|
|
3990
|
+
var DamageMod = /* @__PURE__ */ ((DamageMod2) => {
|
|
3991
|
+
DamageMod2[DamageMod2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
3992
|
+
DamageMod2[DamageMod2["BLASTER"] = 1] = "BLASTER";
|
|
3993
|
+
DamageMod2[DamageMod2["SHOTGUN"] = 2] = "SHOTGUN";
|
|
3994
|
+
DamageMod2[DamageMod2["SSHOTGUN"] = 3] = "SSHOTGUN";
|
|
3995
|
+
DamageMod2[DamageMod2["MACHINEGUN"] = 4] = "MACHINEGUN";
|
|
3996
|
+
DamageMod2[DamageMod2["CHAINGUN"] = 5] = "CHAINGUN";
|
|
3997
|
+
DamageMod2[DamageMod2["GRENADE"] = 6] = "GRENADE";
|
|
3998
|
+
DamageMod2[DamageMod2["G_SPLASH"] = 7] = "G_SPLASH";
|
|
3999
|
+
DamageMod2[DamageMod2["ROCKET"] = 8] = "ROCKET";
|
|
4000
|
+
DamageMod2[DamageMod2["R_SPLASH"] = 9] = "R_SPLASH";
|
|
4001
|
+
DamageMod2[DamageMod2["HYPERBLASTER"] = 10] = "HYPERBLASTER";
|
|
4002
|
+
DamageMod2[DamageMod2["RAILGUN"] = 11] = "RAILGUN";
|
|
4003
|
+
DamageMod2[DamageMod2["BFG_LASER"] = 12] = "BFG_LASER";
|
|
4004
|
+
DamageMod2[DamageMod2["BFG_BLAST"] = 13] = "BFG_BLAST";
|
|
4005
|
+
DamageMod2[DamageMod2["BFG_EFFECT"] = 14] = "BFG_EFFECT";
|
|
4006
|
+
DamageMod2[DamageMod2["HANDGRENADE"] = 15] = "HANDGRENADE";
|
|
4007
|
+
DamageMod2[DamageMod2["HG_SPLASH"] = 16] = "HG_SPLASH";
|
|
4008
|
+
DamageMod2[DamageMod2["WATER"] = 17] = "WATER";
|
|
4009
|
+
DamageMod2[DamageMod2["SLIME"] = 18] = "SLIME";
|
|
4010
|
+
DamageMod2[DamageMod2["LAVA"] = 19] = "LAVA";
|
|
4011
|
+
DamageMod2[DamageMod2["CRUSH"] = 20] = "CRUSH";
|
|
4012
|
+
DamageMod2[DamageMod2["TELEFRAG"] = 21] = "TELEFRAG";
|
|
4013
|
+
DamageMod2[DamageMod2["TELEFRAG_SPAWN"] = 22] = "TELEFRAG_SPAWN";
|
|
4014
|
+
DamageMod2[DamageMod2["FALLING"] = 23] = "FALLING";
|
|
4015
|
+
DamageMod2[DamageMod2["SUICIDE"] = 24] = "SUICIDE";
|
|
4016
|
+
DamageMod2[DamageMod2["HELD_GRENADE"] = 25] = "HELD_GRENADE";
|
|
4017
|
+
DamageMod2[DamageMod2["EXPLOSIVE"] = 26] = "EXPLOSIVE";
|
|
4018
|
+
DamageMod2[DamageMod2["BARREL"] = 27] = "BARREL";
|
|
4019
|
+
DamageMod2[DamageMod2["BOMB"] = 28] = "BOMB";
|
|
4020
|
+
DamageMod2[DamageMod2["EXIT"] = 29] = "EXIT";
|
|
4021
|
+
DamageMod2[DamageMod2["SPLASH"] = 30] = "SPLASH";
|
|
4022
|
+
DamageMod2[DamageMod2["TARGET_LASER"] = 31] = "TARGET_LASER";
|
|
4023
|
+
DamageMod2[DamageMod2["TRIGGER_HURT"] = 32] = "TRIGGER_HURT";
|
|
4024
|
+
DamageMod2[DamageMod2["HIT"] = 33] = "HIT";
|
|
4025
|
+
DamageMod2[DamageMod2["TARGET_BLASTER"] = 34] = "TARGET_BLASTER";
|
|
4026
|
+
DamageMod2[DamageMod2["RIPPER"] = 35] = "RIPPER";
|
|
4027
|
+
DamageMod2[DamageMod2["PHALANX"] = 36] = "PHALANX";
|
|
4028
|
+
DamageMod2[DamageMod2["BRAINTENTACLE"] = 37] = "BRAINTENTACLE";
|
|
4029
|
+
DamageMod2[DamageMod2["BLASTOFF"] = 38] = "BLASTOFF";
|
|
4030
|
+
DamageMod2[DamageMod2["GEKK"] = 39] = "GEKK";
|
|
4031
|
+
DamageMod2[DamageMod2["TRAP"] = 40] = "TRAP";
|
|
4032
|
+
DamageMod2[DamageMod2["CHAINFIST"] = 41] = "CHAINFIST";
|
|
4033
|
+
DamageMod2[DamageMod2["DISINTEGRATOR"] = 42] = "DISINTEGRATOR";
|
|
4034
|
+
DamageMod2[DamageMod2["ETF_RIFLE"] = 43] = "ETF_RIFLE";
|
|
4035
|
+
DamageMod2[DamageMod2["BLASTER2"] = 44] = "BLASTER2";
|
|
4036
|
+
DamageMod2[DamageMod2["HEATBEAM"] = 45] = "HEATBEAM";
|
|
4037
|
+
DamageMod2[DamageMod2["TESLA"] = 46] = "TESLA";
|
|
4038
|
+
DamageMod2[DamageMod2["PROX"] = 47] = "PROX";
|
|
4039
|
+
DamageMod2[DamageMod2["NUKE"] = 48] = "NUKE";
|
|
4040
|
+
DamageMod2[DamageMod2["VENGEANCE_SPHERE"] = 49] = "VENGEANCE_SPHERE";
|
|
4041
|
+
DamageMod2[DamageMod2["HUNTER_SPHERE"] = 50] = "HUNTER_SPHERE";
|
|
4042
|
+
DamageMod2[DamageMod2["DEFENDER_SPHERE"] = 51] = "DEFENDER_SPHERE";
|
|
4043
|
+
DamageMod2[DamageMod2["TRACKER"] = 52] = "TRACKER";
|
|
4044
|
+
DamageMod2[DamageMod2["DBALL_CRUSH"] = 53] = "DBALL_CRUSH";
|
|
4045
|
+
DamageMod2[DamageMod2["DOPPLE_EXPLODE"] = 54] = "DOPPLE_EXPLODE";
|
|
4046
|
+
DamageMod2[DamageMod2["DOPPLE_VENGEANCE"] = 55] = "DOPPLE_VENGEANCE";
|
|
4047
|
+
DamageMod2[DamageMod2["DOPPLE_HUNTER"] = 56] = "DOPPLE_HUNTER";
|
|
4048
|
+
DamageMod2[DamageMod2["GRAPPLE"] = 57] = "GRAPPLE";
|
|
4049
|
+
DamageMod2[DamageMod2["BLUEBLASTER"] = 58] = "BLUEBLASTER";
|
|
4050
|
+
return DamageMod2;
|
|
4051
|
+
})(DamageMod || {});
|
|
4052
|
+
var ORDERED_DAMAGE_MODS = [
|
|
4053
|
+
0 /* UNKNOWN */,
|
|
4054
|
+
1 /* BLASTER */,
|
|
4055
|
+
2 /* SHOTGUN */,
|
|
4056
|
+
3 /* SSHOTGUN */,
|
|
4057
|
+
4 /* MACHINEGUN */,
|
|
4058
|
+
5 /* CHAINGUN */,
|
|
4059
|
+
6 /* GRENADE */,
|
|
4060
|
+
7 /* G_SPLASH */,
|
|
4061
|
+
8 /* ROCKET */,
|
|
4062
|
+
9 /* R_SPLASH */,
|
|
4063
|
+
10 /* HYPERBLASTER */,
|
|
4064
|
+
11 /* RAILGUN */,
|
|
4065
|
+
12 /* BFG_LASER */,
|
|
4066
|
+
13 /* BFG_BLAST */,
|
|
4067
|
+
14 /* BFG_EFFECT */,
|
|
4068
|
+
15 /* HANDGRENADE */,
|
|
4069
|
+
16 /* HG_SPLASH */,
|
|
4070
|
+
17 /* WATER */,
|
|
4071
|
+
18 /* SLIME */,
|
|
4072
|
+
19 /* LAVA */,
|
|
4073
|
+
20 /* CRUSH */,
|
|
4074
|
+
21 /* TELEFRAG */,
|
|
4075
|
+
22 /* TELEFRAG_SPAWN */,
|
|
4076
|
+
23 /* FALLING */,
|
|
4077
|
+
24 /* SUICIDE */,
|
|
4078
|
+
25 /* HELD_GRENADE */,
|
|
4079
|
+
26 /* EXPLOSIVE */,
|
|
4080
|
+
27 /* BARREL */,
|
|
4081
|
+
28 /* BOMB */,
|
|
4082
|
+
29 /* EXIT */,
|
|
4083
|
+
30 /* SPLASH */,
|
|
4084
|
+
31 /* TARGET_LASER */,
|
|
4085
|
+
32 /* TRIGGER_HURT */,
|
|
4086
|
+
33 /* HIT */,
|
|
4087
|
+
34 /* TARGET_BLASTER */,
|
|
4088
|
+
35 /* RIPPER */,
|
|
4089
|
+
36 /* PHALANX */,
|
|
4090
|
+
37 /* BRAINTENTACLE */,
|
|
4091
|
+
38 /* BLASTOFF */,
|
|
4092
|
+
39 /* GEKK */,
|
|
4093
|
+
40 /* TRAP */,
|
|
4094
|
+
41 /* CHAINFIST */,
|
|
4095
|
+
42 /* DISINTEGRATOR */,
|
|
4096
|
+
43 /* ETF_RIFLE */,
|
|
4097
|
+
44 /* BLASTER2 */,
|
|
4098
|
+
45 /* HEATBEAM */,
|
|
4099
|
+
46 /* TESLA */,
|
|
4100
|
+
47 /* PROX */,
|
|
4101
|
+
48 /* NUKE */,
|
|
4102
|
+
49 /* VENGEANCE_SPHERE */,
|
|
4103
|
+
50 /* HUNTER_SPHERE */,
|
|
4104
|
+
51 /* DEFENDER_SPHERE */,
|
|
4105
|
+
52 /* TRACKER */,
|
|
4106
|
+
53 /* DBALL_CRUSH */,
|
|
4107
|
+
54 /* DOPPLE_EXPLODE */,
|
|
4108
|
+
55 /* DOPPLE_VENGEANCE */,
|
|
4109
|
+
56 /* DOPPLE_HUNTER */,
|
|
4110
|
+
57 /* GRAPPLE */,
|
|
4111
|
+
58 /* BLUEBLASTER */
|
|
4112
|
+
];
|
|
4113
|
+
function damageModName(mod) {
|
|
4114
|
+
return `MOD_${DamageMod[mod]}`;
|
|
4115
|
+
}
|
|
4116
|
+
|
|
4117
|
+
// src/combat/damage.ts
|
|
4118
|
+
var EntityDamageFlags = /* @__PURE__ */ ((EntityDamageFlags2) => {
|
|
4119
|
+
EntityDamageFlags2[EntityDamageFlags2["GODMODE"] = 1] = "GODMODE";
|
|
4120
|
+
EntityDamageFlags2[EntityDamageFlags2["IMMORTAL"] = 2] = "IMMORTAL";
|
|
4121
|
+
EntityDamageFlags2[EntityDamageFlags2["NO_KNOCKBACK"] = 4] = "NO_KNOCKBACK";
|
|
4122
|
+
EntityDamageFlags2[EntityDamageFlags2["NO_DAMAGE_EFFECTS"] = 8] = "NO_DAMAGE_EFFECTS";
|
|
4123
|
+
return EntityDamageFlags2;
|
|
4124
|
+
})(EntityDamageFlags || {});
|
|
4125
|
+
function applyKnockback(targ, attacker, dir, knockback, dflags) {
|
|
4126
|
+
const hasNoKnockback = hasAnyDamageFlag(dflags, 8 /* NO_KNOCKBACK */) || ((targ.flags ?? 0) & 4 /* NO_KNOCKBACK */) !== 0;
|
|
4127
|
+
if (hasNoKnockback || knockback === 0) {
|
|
4128
|
+
return { x: 0, y: 0, z: 0 };
|
|
4129
|
+
}
|
|
4130
|
+
const mass = Math.max(50, targ.mass ?? 200);
|
|
4131
|
+
const normalized = normalizeVec3(dir);
|
|
4132
|
+
const scale = attacker === targ ? 1600 : 500;
|
|
4133
|
+
const delta = scaleVec3(normalized, scale * knockback / mass);
|
|
4134
|
+
targ.velocity = addVec3(targ.velocity, delta);
|
|
4135
|
+
return delta;
|
|
4136
|
+
}
|
|
4137
|
+
function applyProtection(targ, point, normal, damage, dflags) {
|
|
4138
|
+
let take = damage;
|
|
4139
|
+
let psave = 0;
|
|
4140
|
+
let asave = 0;
|
|
4141
|
+
let remainingCells;
|
|
4142
|
+
let remainingArmor;
|
|
4143
|
+
if (targ.powerArmor) {
|
|
4144
|
+
const result = applyPowerArmor(damage, dflags, point, normal, targ.powerArmor);
|
|
4145
|
+
psave = result.saved;
|
|
4146
|
+
remainingCells = result.remainingCells;
|
|
4147
|
+
take -= psave;
|
|
4148
|
+
}
|
|
4149
|
+
if (targ.regularArmor) {
|
|
4150
|
+
const result = applyRegularArmor(take, dflags, targ.regularArmor);
|
|
4151
|
+
asave = result.saved;
|
|
4152
|
+
remainingArmor = result.remainingArmor;
|
|
4153
|
+
take -= asave;
|
|
4154
|
+
}
|
|
4155
|
+
return [Math.max(0, take), psave, asave, remainingCells, remainingArmor];
|
|
4156
|
+
}
|
|
4157
|
+
function targetCenter(ent) {
|
|
4158
|
+
if (ent.mins && ent.maxs) {
|
|
4159
|
+
return {
|
|
4160
|
+
x: ent.origin.x + (ent.mins.x + ent.maxs.x) * 0.5,
|
|
4161
|
+
y: ent.origin.y + (ent.mins.y + ent.maxs.y) * 0.5,
|
|
4162
|
+
z: ent.origin.z + (ent.mins.z + ent.maxs.z) * 0.5
|
|
4163
|
+
};
|
|
4164
|
+
}
|
|
4165
|
+
return ent.origin;
|
|
4166
|
+
}
|
|
4167
|
+
function T_Damage(targ, inflictor, attacker, dir, point, normal, damage, knockback, dflags, mod) {
|
|
4168
|
+
if (!targ.takedamage || damage <= 0) {
|
|
4169
|
+
return null;
|
|
4170
|
+
}
|
|
4171
|
+
const protectedByGod = !hasAnyDamageFlag(dflags, 32 /* NO_PROTECTION */) && ((targ.flags ?? 0) & 1 /* GODMODE */) !== 0;
|
|
4172
|
+
if (protectedByGod) {
|
|
4173
|
+
return {
|
|
4174
|
+
take: 0,
|
|
4175
|
+
psave: 0,
|
|
4176
|
+
asave: damage,
|
|
4177
|
+
knocked: { x: 0, y: 0, z: 0 },
|
|
4178
|
+
killed: false
|
|
4179
|
+
};
|
|
4180
|
+
}
|
|
4181
|
+
const knocked = applyKnockback(targ, attacker, dir, knockback, dflags);
|
|
4182
|
+
const [take, psave, asave, remainingCells, remainingArmor] = applyProtection(targ, point, normal, damage, dflags);
|
|
4183
|
+
if (targ.powerArmor && remainingCells !== void 0) {
|
|
4184
|
+
targ.powerArmor.cellCount = remainingCells;
|
|
4185
|
+
}
|
|
4186
|
+
if (targ.regularArmor) {
|
|
4187
|
+
targ.regularArmor.armorCount = remainingArmor ?? targ.regularArmor.armorCount;
|
|
4188
|
+
}
|
|
4189
|
+
let actualTake = take;
|
|
4190
|
+
if (actualTake > 0) {
|
|
4191
|
+
targ.health -= actualTake;
|
|
4192
|
+
}
|
|
4193
|
+
const killed = targ.health <= 0;
|
|
4194
|
+
if (killed) {
|
|
4195
|
+
if (targ.flags && targ.flags & 2 /* IMMORTAL */) {
|
|
4196
|
+
targ.health = Math.max(1, targ.health);
|
|
4197
|
+
} else if (targ.die) {
|
|
4198
|
+
targ.die(targ, inflictor, attacker, actualTake, point, mod);
|
|
4199
|
+
}
|
|
4200
|
+
} else if (actualTake > 0 && targ.pain) {
|
|
4201
|
+
targ.pain(targ, attacker, knockback, actualTake, mod);
|
|
4202
|
+
}
|
|
4203
|
+
return { take: actualTake, psave, asave, knocked, killed, remainingCells, remainingArmor };
|
|
4204
|
+
}
|
|
4205
|
+
function T_RadiusDamage(entities, inflictor, attacker, damage, ignore, radius, dflags, mod, options = {}) {
|
|
4206
|
+
const hits = [];
|
|
4207
|
+
const inflictorCenter = targetCenter(inflictor);
|
|
4208
|
+
const canDamage = options.canDamage ?? (() => true);
|
|
4209
|
+
for (const ent of entities) {
|
|
4210
|
+
if (ent === ignore || !ent.takedamage || !canDamage(ent, inflictor)) {
|
|
4211
|
+
continue;
|
|
4212
|
+
}
|
|
4213
|
+
const entCenter = ent.mins && ent.maxs ? closestPointToBox(inflictorCenter, addVec3(ent.origin, ent.mins), addVec3(ent.origin, ent.maxs)) : targetCenter(ent);
|
|
4214
|
+
const toTarget = subtractVec3(inflictorCenter, entCenter);
|
|
4215
|
+
const distance2 = lengthVec3(toTarget);
|
|
4216
|
+
if (radius > 0 && distance2 > radius) {
|
|
4217
|
+
continue;
|
|
4218
|
+
}
|
|
4219
|
+
const points = damage - 0.5 * distance2;
|
|
4220
|
+
if (points <= 0) {
|
|
4221
|
+
continue;
|
|
4222
|
+
}
|
|
4223
|
+
const adjustedDamage = ent === attacker ? points * 0.5 : points;
|
|
4224
|
+
const dir = normalizeVec3(subtractVec3(ent.origin, inflictorCenter));
|
|
4225
|
+
const result = T_Damage(ent, inflictor, attacker, dir, entCenter, dir, adjustedDamage, adjustedDamage, dflags | 1 /* RADIUS */, mod);
|
|
4226
|
+
hits.push({ target: ent, result, appliedDamage: adjustedDamage });
|
|
4227
|
+
}
|
|
4228
|
+
return hits;
|
|
4229
|
+
}
|
|
4230
|
+
|
|
4231
|
+
// src/entities/monsters/attack.ts
|
|
4232
|
+
function monster_fire_bullet(self, start, dir, damage, kick, hspread, vspread, flashtype, context, mod = 0 /* UNKNOWN */) {
|
|
4233
|
+
const end = addVec3(start, scaleVec3(dir, 8192));
|
|
4234
|
+
const tr = context.trace(start, null, null, end, self, 1 | 536870912);
|
|
4235
|
+
if (!tr.ent || tr.fraction === 1) {
|
|
4236
|
+
return;
|
|
4237
|
+
}
|
|
4238
|
+
T_Damage(
|
|
4239
|
+
tr.ent,
|
|
4240
|
+
self,
|
|
4241
|
+
self,
|
|
4242
|
+
dir,
|
|
4243
|
+
tr.endpos,
|
|
4244
|
+
tr.plane?.normal || ZERO_VEC3,
|
|
4245
|
+
damage,
|
|
4246
|
+
kick,
|
|
4247
|
+
16 /* BULLET */ | 2 /* NO_ARMOR */,
|
|
4248
|
+
// Usually monsters ignore armor? Or maybe not.
|
|
4249
|
+
mod
|
|
4250
|
+
);
|
|
4251
|
+
}
|
|
4252
|
+
|
|
4253
|
+
// src/entities/projectiles.ts
|
|
4254
|
+
function createGrenade(sys, owner, start, dir, damage, speed) {
|
|
4255
|
+
const grenade = sys.spawn();
|
|
4256
|
+
grenade.classname = "grenade";
|
|
4257
|
+
grenade.owner = owner;
|
|
4258
|
+
grenade.origin = { ...start };
|
|
4259
|
+
grenade.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
|
|
4260
|
+
grenade.movetype = 9 /* Bounce */;
|
|
4261
|
+
grenade.clipmask = 268566530;
|
|
4262
|
+
grenade.solid = 2 /* BoundingBox */;
|
|
4263
|
+
grenade.modelindex = sys.modelIndex("models/objects/grenade/tris.md2");
|
|
4264
|
+
grenade.mins = { x: -4, y: -4, z: -4 };
|
|
4265
|
+
grenade.maxs = { x: 4, y: 4, z: 4 };
|
|
4266
|
+
grenade.touch = (self, other, plane, surf) => {
|
|
4267
|
+
if (other === self.owner) {
|
|
4268
|
+
return;
|
|
4269
|
+
}
|
|
4270
|
+
if (other && other.takedamage) {
|
|
4271
|
+
T_Damage(
|
|
4272
|
+
other,
|
|
4273
|
+
self,
|
|
4274
|
+
self.owner,
|
|
4275
|
+
self.velocity,
|
|
4276
|
+
self.origin,
|
|
4277
|
+
plane ? plane.normal : ZERO_VEC3,
|
|
4278
|
+
damage,
|
|
4279
|
+
// Direct impact damage? Usually separate but let's assume it's part of it or handled by radius.
|
|
4280
|
+
// Actually G_Weapon.c Grenade_Touch calls Grenade_Explode which calls T_RadiusDamage.
|
|
4281
|
+
// It doesn't seem to do T_Damage separately?
|
|
4282
|
+
// Wait, if it hits a monster, it stops and explodes.
|
|
4283
|
+
0,
|
|
4284
|
+
0 /* NONE */,
|
|
4285
|
+
6 /* GRENADE */
|
|
4286
|
+
);
|
|
4287
|
+
const entities = sys.findByRadius(self.origin, 120);
|
|
4288
|
+
T_RadiusDamage(entities, self, self.owner, damage, self.owner, 120, 0 /* NONE */, 6 /* GRENADE */);
|
|
4289
|
+
sys.free(self);
|
|
4290
|
+
return;
|
|
4291
|
+
}
|
|
4292
|
+
};
|
|
4293
|
+
grenade.think = (self) => {
|
|
4294
|
+
const entities = sys.findByRadius(self.origin, 120);
|
|
4295
|
+
T_RadiusDamage(entities, self, self.owner, damage, self.owner, 120, 0 /* NONE */, 6 /* GRENADE */);
|
|
4296
|
+
sys.free(self);
|
|
4297
|
+
};
|
|
4298
|
+
sys.scheduleThink(grenade, sys.timeSeconds + 2.5);
|
|
4299
|
+
sys.finalizeSpawn(grenade);
|
|
4300
|
+
}
|
|
4301
|
+
|
|
4302
|
+
// src/entities/monsters/gunner.ts
|
|
4303
|
+
var MONSTER_TICK = 0.1;
|
|
4304
|
+
function monster_ai_stand(self, dist, context) {
|
|
4305
|
+
ai_stand(self, MONSTER_TICK);
|
|
4306
|
+
}
|
|
4307
|
+
function monster_ai_walk(self, dist, context) {
|
|
4308
|
+
ai_walk(self, dist, MONSTER_TICK, context);
|
|
4309
|
+
}
|
|
4310
|
+
function monster_ai_run(self, dist, context) {
|
|
4311
|
+
ai_run(self, dist, MONSTER_TICK);
|
|
4312
|
+
}
|
|
4313
|
+
function monster_ai_charge(self, dist, context) {
|
|
4314
|
+
ai_charge(self, dist, MONSTER_TICK);
|
|
4315
|
+
}
|
|
4316
|
+
var stand_move;
|
|
4317
|
+
var walk_move;
|
|
4318
|
+
var run_move;
|
|
4319
|
+
var attack_chain_move;
|
|
4320
|
+
var attack_grenade_move;
|
|
4321
|
+
function gunner_stand(self) {
|
|
4322
|
+
self.monsterinfo.current_move = stand_move;
|
|
4323
|
+
}
|
|
4324
|
+
function gunner_walk(self) {
|
|
4325
|
+
self.monsterinfo.current_move = walk_move;
|
|
4326
|
+
}
|
|
4327
|
+
function gunner_run(self) {
|
|
4328
|
+
if (self.enemy && self.enemy.health > 0) {
|
|
4329
|
+
self.monsterinfo.current_move = run_move;
|
|
4330
|
+
} else {
|
|
4331
|
+
self.monsterinfo.current_move = stand_move;
|
|
4332
|
+
}
|
|
4333
|
+
}
|
|
4334
|
+
function gunner_attack(self) {
|
|
4335
|
+
if (Math.random() > 0.5) {
|
|
4336
|
+
self.monsterinfo.current_move = attack_chain_move;
|
|
4337
|
+
} else {
|
|
4338
|
+
self.monsterinfo.current_move = attack_grenade_move;
|
|
4339
|
+
}
|
|
4340
|
+
}
|
|
4341
|
+
function gunner_fire_chain(self, context) {
|
|
4342
|
+
if (!self.enemy) return;
|
|
4343
|
+
const start = {
|
|
4344
|
+
x: self.origin.x,
|
|
4345
|
+
y: self.origin.y,
|
|
4346
|
+
z: self.origin.z + self.viewheight - 8
|
|
4347
|
+
};
|
|
4348
|
+
const forward = normalizeVec3(subtractVec3(self.enemy.origin, start));
|
|
4349
|
+
const damage = 10;
|
|
4350
|
+
const kick = 2;
|
|
4351
|
+
monster_fire_bullet(self, start, forward, damage, kick, 0, 0, 0, context, 5 /* CHAINGUN */);
|
|
4352
|
+
}
|
|
4353
|
+
function gunner_fire_grenade(self, context) {
|
|
4354
|
+
if (!self.enemy) return;
|
|
4355
|
+
const start = {
|
|
4356
|
+
x: self.origin.x,
|
|
4357
|
+
y: self.origin.y,
|
|
4358
|
+
z: self.origin.z + self.viewheight
|
|
4359
|
+
};
|
|
4360
|
+
const forward = normalizeVec3(subtractVec3(self.enemy.origin, start));
|
|
4361
|
+
const damage = 50;
|
|
4362
|
+
const speed = 600;
|
|
4363
|
+
createGrenade(context, self, start, forward, damage, speed);
|
|
4364
|
+
}
|
|
4365
|
+
var stand_frames = Array.from({ length: 30 }, () => ({
|
|
4366
|
+
ai: monster_ai_stand,
|
|
4367
|
+
dist: 0
|
|
4368
|
+
}));
|
|
4369
|
+
stand_move = {
|
|
4370
|
+
firstframe: 0,
|
|
4371
|
+
lastframe: 29,
|
|
4372
|
+
frames: stand_frames,
|
|
4373
|
+
endfunc: gunner_stand
|
|
4374
|
+
};
|
|
4375
|
+
var walk_frames = Array.from({ length: 40 }, () => ({
|
|
4376
|
+
ai: monster_ai_walk,
|
|
4377
|
+
dist: 2
|
|
4378
|
+
}));
|
|
4379
|
+
walk_move = {
|
|
4380
|
+
firstframe: 30,
|
|
4381
|
+
lastframe: 69,
|
|
4382
|
+
frames: walk_frames,
|
|
4383
|
+
endfunc: gunner_walk
|
|
4384
|
+
};
|
|
4385
|
+
var run_frames = Array.from({ length: 20 }, () => ({
|
|
4386
|
+
ai: monster_ai_run,
|
|
4387
|
+
dist: 10
|
|
4388
|
+
}));
|
|
4389
|
+
run_move = {
|
|
4390
|
+
firstframe: 70,
|
|
4391
|
+
lastframe: 89,
|
|
4392
|
+
frames: run_frames,
|
|
4393
|
+
endfunc: gunner_run
|
|
4394
|
+
};
|
|
4395
|
+
var attack_chain_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
4396
|
+
ai: monster_ai_charge,
|
|
4397
|
+
dist: 0,
|
|
4398
|
+
think: i >= 2 && i <= 8 ? gunner_fire_chain : null
|
|
4399
|
+
}));
|
|
4400
|
+
attack_chain_move = {
|
|
4401
|
+
firstframe: 90,
|
|
4402
|
+
lastframe: 99,
|
|
4403
|
+
frames: attack_chain_frames,
|
|
4404
|
+
endfunc: gunner_run
|
|
4405
|
+
};
|
|
4406
|
+
var attack_grenade_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
4407
|
+
ai: monster_ai_charge,
|
|
4408
|
+
dist: 0,
|
|
4409
|
+
think: i === 5 ? gunner_fire_grenade : null
|
|
4410
|
+
}));
|
|
4411
|
+
attack_grenade_move = {
|
|
4412
|
+
firstframe: 100,
|
|
4413
|
+
lastframe: 109,
|
|
4414
|
+
frames: attack_grenade_frames,
|
|
4415
|
+
endfunc: gunner_run
|
|
4416
|
+
};
|
|
4417
|
+
function SP_monster_gunner(self, context) {
|
|
4418
|
+
self.model = "models/monsters/gunner/tris.md2";
|
|
4419
|
+
self.mins = { x: -16, y: -16, z: -24 };
|
|
4420
|
+
self.maxs = { x: 16, y: 16, z: 32 };
|
|
4421
|
+
self.movetype = 5 /* Step */;
|
|
4422
|
+
self.solid = 2 /* BoundingBox */;
|
|
4423
|
+
self.health = 175;
|
|
4424
|
+
self.max_health = 175;
|
|
4425
|
+
self.mass = 200;
|
|
4426
|
+
self.pain = (self2, other, kick, damage) => {
|
|
4427
|
+
};
|
|
4428
|
+
self.die = (self2, inflictor, attacker, damage, point) => {
|
|
4429
|
+
self2.deadflag = 2 /* Dead */;
|
|
4430
|
+
self2.solid = 0 /* Not */;
|
|
4431
|
+
};
|
|
4432
|
+
self.monsterinfo.stand = gunner_stand;
|
|
4433
|
+
self.monsterinfo.walk = gunner_walk;
|
|
4434
|
+
self.monsterinfo.run = gunner_run;
|
|
4435
|
+
self.monsterinfo.attack = gunner_attack;
|
|
4436
|
+
self.think = monster_think;
|
|
4437
|
+
gunner_stand(self);
|
|
4438
|
+
self.nextthink = self.timestamp + MONSTER_TICK;
|
|
4439
|
+
}
|
|
4440
|
+
function registerGunnerSpawns(registry) {
|
|
4441
|
+
registry.register("monster_gunner", SP_monster_gunner);
|
|
4442
|
+
}
|
|
4443
|
+
|
|
4444
|
+
// src/entities/monsters/soldier.ts
|
|
4445
|
+
var MONSTER_TICK2 = 0.1;
|
|
4446
|
+
function monster_ai_stand2(self, dist, context) {
|
|
4447
|
+
ai_stand(self, MONSTER_TICK2);
|
|
4448
|
+
}
|
|
4449
|
+
function monster_ai_walk2(self, dist, context) {
|
|
4450
|
+
ai_walk(self, dist, MONSTER_TICK2, context);
|
|
4451
|
+
}
|
|
4452
|
+
function monster_ai_run2(self, dist, context) {
|
|
4453
|
+
ai_run(self, dist, MONSTER_TICK2);
|
|
4454
|
+
}
|
|
4455
|
+
function monster_ai_charge2(self, dist, context) {
|
|
4456
|
+
ai_charge(self, dist, MONSTER_TICK2);
|
|
4457
|
+
}
|
|
4458
|
+
var stand_move2;
|
|
4459
|
+
var walk_move2;
|
|
4460
|
+
var run_move2;
|
|
4461
|
+
var attack_move;
|
|
4462
|
+
function soldier_stand(self) {
|
|
4463
|
+
self.monsterinfo.current_move = stand_move2;
|
|
4464
|
+
}
|
|
4465
|
+
function soldier_walk(self) {
|
|
4466
|
+
self.monsterinfo.current_move = walk_move2;
|
|
4467
|
+
}
|
|
4468
|
+
function soldier_run(self) {
|
|
4469
|
+
if (self.enemy && self.enemy.health > 0) {
|
|
4470
|
+
self.monsterinfo.current_move = run_move2;
|
|
4471
|
+
} else {
|
|
4472
|
+
self.monsterinfo.current_move = stand_move2;
|
|
4473
|
+
}
|
|
4474
|
+
}
|
|
4475
|
+
function soldier_attack(self) {
|
|
4476
|
+
self.monsterinfo.current_move = attack_move;
|
|
4477
|
+
}
|
|
4478
|
+
function soldier_fire(self, context) {
|
|
4479
|
+
if (!self.enemy) return;
|
|
4480
|
+
const start = {
|
|
4481
|
+
x: self.origin.x,
|
|
4482
|
+
y: self.origin.y,
|
|
4483
|
+
z: self.origin.z + self.viewheight
|
|
4484
|
+
};
|
|
4485
|
+
const forward = normalizeVec3(subtractVec3(self.enemy.origin, start));
|
|
4486
|
+
const damage = 4;
|
|
4487
|
+
const kick = 4;
|
|
4488
|
+
monster_fire_bullet(self, start, forward, damage, kick, 0, 0, 0, context, 4 /* MACHINEGUN */);
|
|
4489
|
+
}
|
|
4490
|
+
var stand_frames2 = Array.from({ length: 30 }, () => ({
|
|
4491
|
+
ai: monster_ai_stand2,
|
|
4492
|
+
dist: 0
|
|
4493
|
+
}));
|
|
4494
|
+
stand_move2 = {
|
|
4495
|
+
firstframe: 0,
|
|
4496
|
+
lastframe: 29,
|
|
4497
|
+
frames: stand_frames2,
|
|
4498
|
+
endfunc: soldier_stand
|
|
4499
|
+
};
|
|
4500
|
+
var walk_frames2 = Array.from({ length: 40 }, () => ({
|
|
4501
|
+
ai: monster_ai_walk2,
|
|
4502
|
+
dist: 2
|
|
4503
|
+
}));
|
|
4504
|
+
walk_move2 = {
|
|
4505
|
+
firstframe: 30,
|
|
4506
|
+
lastframe: 69,
|
|
4507
|
+
frames: walk_frames2,
|
|
4508
|
+
endfunc: soldier_walk
|
|
4509
|
+
};
|
|
4510
|
+
var run_frames2 = Array.from({ length: 20 }, () => ({
|
|
4511
|
+
ai: monster_ai_run2,
|
|
4512
|
+
dist: 10
|
|
4513
|
+
}));
|
|
4514
|
+
run_move2 = {
|
|
4515
|
+
firstframe: 70,
|
|
4516
|
+
lastframe: 89,
|
|
4517
|
+
frames: run_frames2,
|
|
4518
|
+
endfunc: soldier_run
|
|
4519
|
+
};
|
|
4520
|
+
var attack_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
4521
|
+
ai: monster_ai_charge2,
|
|
4522
|
+
dist: 0,
|
|
4523
|
+
think: i === 5 ? soldier_fire : null
|
|
4524
|
+
}));
|
|
4525
|
+
attack_move = {
|
|
4526
|
+
firstframe: 90,
|
|
4527
|
+
lastframe: 99,
|
|
4528
|
+
frames: attack_frames,
|
|
4529
|
+
endfunc: soldier_run
|
|
4530
|
+
};
|
|
4531
|
+
function SP_monster_soldier(self, context) {
|
|
4532
|
+
self.model = "models/monsters/soldier/tris.md2";
|
|
4533
|
+
self.mins = { x: -16, y: -16, z: -24 };
|
|
4534
|
+
self.maxs = { x: 16, y: 16, z: 32 };
|
|
4535
|
+
self.movetype = 5 /* Step */;
|
|
4536
|
+
self.solid = 2 /* BoundingBox */;
|
|
4537
|
+
self.health = 20;
|
|
4538
|
+
self.max_health = 20;
|
|
4539
|
+
self.mass = 100;
|
|
4540
|
+
self.pain = (self2, other, kick, damage) => {
|
|
4541
|
+
};
|
|
4542
|
+
self.die = (self2, inflictor, attacker, damage, point) => {
|
|
4543
|
+
self2.deadflag = 2 /* Dead */;
|
|
4544
|
+
self2.solid = 0 /* Not */;
|
|
4545
|
+
};
|
|
4546
|
+
self.monsterinfo.stand = soldier_stand;
|
|
4547
|
+
self.monsterinfo.walk = soldier_walk;
|
|
4548
|
+
self.monsterinfo.run = soldier_run;
|
|
4549
|
+
self.monsterinfo.attack = soldier_attack;
|
|
4550
|
+
self.think = monster_think;
|
|
4551
|
+
soldier_stand(self);
|
|
4552
|
+
self.nextthink = self.timestamp + MONSTER_TICK2;
|
|
4553
|
+
}
|
|
4554
|
+
function registerMonsterSpawns(registry) {
|
|
4555
|
+
registry.register("monster_soldier", SP_monster_soldier);
|
|
4556
|
+
}
|
|
4557
|
+
|
|
4558
|
+
// src/entities/spawn.ts
|
|
4559
|
+
var FIELD_LOOKUP = new Map(
|
|
4560
|
+
ENTITY_FIELD_METADATA.map((field) => [field.name, field])
|
|
4561
|
+
);
|
|
4562
|
+
function parseVec3(text) {
|
|
4563
|
+
const parts = text.trim().split(/\s+/);
|
|
4564
|
+
const [x = 0, y = 0, z = 0] = parts.map((part) => Number.parseFloat(part)).map((value) => Number.isNaN(value) ? 0 : value);
|
|
4565
|
+
return { x, y, z };
|
|
4566
|
+
}
|
|
4567
|
+
function parseBoolean(text) {
|
|
4048
4568
|
const normalized = text.trim().toLowerCase();
|
|
4049
4569
|
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
4050
4570
|
}
|
|
@@ -4250,6 +4770,7 @@ function registerDefaultSpawns(game, registry) {
|
|
|
4250
4770
|
registerPathSpawns(registry);
|
|
4251
4771
|
registerLightSpawns(registry);
|
|
4252
4772
|
registerMonsterSpawns(registry);
|
|
4773
|
+
registerGunnerSpawns(registry);
|
|
4253
4774
|
}
|
|
4254
4775
|
function createDefaultSpawnRegistry(game) {
|
|
4255
4776
|
const registry = new SpawnRegistry();
|
|
@@ -5116,248 +5637,6 @@ _SaveStorage.DEFAULT_STORE = "saves";
|
|
|
5116
5637
|
_SaveStorage.QUICK_SLOT = "quicksave";
|
|
5117
5638
|
var SaveStorage = _SaveStorage;
|
|
5118
5639
|
|
|
5119
|
-
// src/combat/damage.ts
|
|
5120
|
-
var EntityDamageFlags = /* @__PURE__ */ ((EntityDamageFlags2) => {
|
|
5121
|
-
EntityDamageFlags2[EntityDamageFlags2["GODMODE"] = 1] = "GODMODE";
|
|
5122
|
-
EntityDamageFlags2[EntityDamageFlags2["IMMORTAL"] = 2] = "IMMORTAL";
|
|
5123
|
-
EntityDamageFlags2[EntityDamageFlags2["NO_KNOCKBACK"] = 4] = "NO_KNOCKBACK";
|
|
5124
|
-
EntityDamageFlags2[EntityDamageFlags2["NO_DAMAGE_EFFECTS"] = 8] = "NO_DAMAGE_EFFECTS";
|
|
5125
|
-
return EntityDamageFlags2;
|
|
5126
|
-
})(EntityDamageFlags || {});
|
|
5127
|
-
function applyKnockback(targ, attacker, dir, knockback, dflags) {
|
|
5128
|
-
const hasNoKnockback = hasAnyDamageFlag(dflags, 8 /* NO_KNOCKBACK */) || ((targ.flags ?? 0) & 4 /* NO_KNOCKBACK */) !== 0;
|
|
5129
|
-
if (hasNoKnockback || knockback === 0) {
|
|
5130
|
-
return { x: 0, y: 0, z: 0 };
|
|
5131
|
-
}
|
|
5132
|
-
const mass = Math.max(50, targ.mass ?? 200);
|
|
5133
|
-
const normalized = normalizeVec3(dir);
|
|
5134
|
-
const scale = attacker === targ ? 1600 : 500;
|
|
5135
|
-
const delta = scaleVec3(normalized, scale * knockback / mass);
|
|
5136
|
-
targ.velocity = addVec3(targ.velocity, delta);
|
|
5137
|
-
return delta;
|
|
5138
|
-
}
|
|
5139
|
-
function applyProtection(targ, point, normal, damage, dflags) {
|
|
5140
|
-
let take = damage;
|
|
5141
|
-
let psave = 0;
|
|
5142
|
-
let asave = 0;
|
|
5143
|
-
let remainingCells;
|
|
5144
|
-
let remainingArmor;
|
|
5145
|
-
if (targ.powerArmor) {
|
|
5146
|
-
const result = applyPowerArmor(damage, dflags, point, normal, targ.powerArmor);
|
|
5147
|
-
psave = result.saved;
|
|
5148
|
-
remainingCells = result.remainingCells;
|
|
5149
|
-
take -= psave;
|
|
5150
|
-
}
|
|
5151
|
-
if (targ.regularArmor) {
|
|
5152
|
-
const result = applyRegularArmor(take, dflags, targ.regularArmor);
|
|
5153
|
-
asave = result.saved;
|
|
5154
|
-
remainingArmor = result.remainingArmor;
|
|
5155
|
-
take -= asave;
|
|
5156
|
-
}
|
|
5157
|
-
return [Math.max(0, take), psave, asave, remainingCells, remainingArmor];
|
|
5158
|
-
}
|
|
5159
|
-
function targetCenter(ent) {
|
|
5160
|
-
if (ent.mins && ent.maxs) {
|
|
5161
|
-
return {
|
|
5162
|
-
x: ent.origin.x + (ent.mins.x + ent.maxs.x) * 0.5,
|
|
5163
|
-
y: ent.origin.y + (ent.mins.y + ent.maxs.y) * 0.5,
|
|
5164
|
-
z: ent.origin.z + (ent.mins.z + ent.maxs.z) * 0.5
|
|
5165
|
-
};
|
|
5166
|
-
}
|
|
5167
|
-
return ent.origin;
|
|
5168
|
-
}
|
|
5169
|
-
function T_Damage(targ, inflictor, attacker, dir, point, normal, damage, knockback, dflags, mod) {
|
|
5170
|
-
if (!targ.takedamage || damage <= 0) {
|
|
5171
|
-
return null;
|
|
5172
|
-
}
|
|
5173
|
-
const protectedByGod = !hasAnyDamageFlag(dflags, 32 /* NO_PROTECTION */) && ((targ.flags ?? 0) & 1 /* GODMODE */) !== 0;
|
|
5174
|
-
if (protectedByGod) {
|
|
5175
|
-
return {
|
|
5176
|
-
take: 0,
|
|
5177
|
-
psave: 0,
|
|
5178
|
-
asave: damage,
|
|
5179
|
-
knocked: { x: 0, y: 0, z: 0 },
|
|
5180
|
-
killed: false
|
|
5181
|
-
};
|
|
5182
|
-
}
|
|
5183
|
-
const knocked = applyKnockback(targ, attacker, dir, knockback, dflags);
|
|
5184
|
-
const [take, psave, asave, remainingCells, remainingArmor] = applyProtection(targ, point, normal, damage, dflags);
|
|
5185
|
-
if (targ.powerArmor && remainingCells !== void 0) {
|
|
5186
|
-
targ.powerArmor.cellCount = remainingCells;
|
|
5187
|
-
}
|
|
5188
|
-
if (targ.regularArmor) {
|
|
5189
|
-
targ.regularArmor.armorCount = remainingArmor ?? targ.regularArmor.armorCount;
|
|
5190
|
-
}
|
|
5191
|
-
let actualTake = take;
|
|
5192
|
-
if (actualTake > 0) {
|
|
5193
|
-
targ.health -= actualTake;
|
|
5194
|
-
}
|
|
5195
|
-
const killed = targ.health <= 0;
|
|
5196
|
-
if (killed) {
|
|
5197
|
-
if (targ.flags && targ.flags & 2 /* IMMORTAL */) {
|
|
5198
|
-
targ.health = Math.max(1, targ.health);
|
|
5199
|
-
} else if (targ.die) {
|
|
5200
|
-
targ.die(targ, inflictor, attacker, actualTake, point, mod);
|
|
5201
|
-
}
|
|
5202
|
-
} else if (actualTake > 0 && targ.pain) {
|
|
5203
|
-
targ.pain(targ, attacker, knockback, actualTake, mod);
|
|
5204
|
-
}
|
|
5205
|
-
return { take: actualTake, psave, asave, knocked, killed, remainingCells, remainingArmor };
|
|
5206
|
-
}
|
|
5207
|
-
function T_RadiusDamage(entities, inflictor, attacker, damage, ignore, radius, dflags, mod, options = {}) {
|
|
5208
|
-
const hits = [];
|
|
5209
|
-
const inflictorCenter = targetCenter(inflictor);
|
|
5210
|
-
const canDamage = options.canDamage ?? (() => true);
|
|
5211
|
-
for (const ent of entities) {
|
|
5212
|
-
if (ent === ignore || !ent.takedamage || !canDamage(ent, inflictor)) {
|
|
5213
|
-
continue;
|
|
5214
|
-
}
|
|
5215
|
-
const entCenter = ent.mins && ent.maxs ? closestPointToBox(inflictorCenter, addVec3(ent.origin, ent.mins), addVec3(ent.origin, ent.maxs)) : targetCenter(ent);
|
|
5216
|
-
const toTarget = subtractVec3(inflictorCenter, entCenter);
|
|
5217
|
-
const distance2 = lengthVec3(toTarget);
|
|
5218
|
-
if (radius > 0 && distance2 > radius) {
|
|
5219
|
-
continue;
|
|
5220
|
-
}
|
|
5221
|
-
const points = damage - 0.5 * distance2;
|
|
5222
|
-
if (points <= 0) {
|
|
5223
|
-
continue;
|
|
5224
|
-
}
|
|
5225
|
-
const adjustedDamage = ent === attacker ? points * 0.5 : points;
|
|
5226
|
-
const dir = normalizeVec3(subtractVec3(ent.origin, inflictorCenter));
|
|
5227
|
-
const result = T_Damage(ent, inflictor, attacker, dir, entCenter, dir, adjustedDamage, adjustedDamage, dflags | 1 /* RADIUS */, mod);
|
|
5228
|
-
hits.push({ target: ent, result, appliedDamage: adjustedDamage });
|
|
5229
|
-
}
|
|
5230
|
-
return hits;
|
|
5231
|
-
}
|
|
5232
|
-
|
|
5233
|
-
// src/combat/damageMods.ts
|
|
5234
|
-
var DamageMod = /* @__PURE__ */ ((DamageMod2) => {
|
|
5235
|
-
DamageMod2[DamageMod2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
5236
|
-
DamageMod2[DamageMod2["BLASTER"] = 1] = "BLASTER";
|
|
5237
|
-
DamageMod2[DamageMod2["SHOTGUN"] = 2] = "SHOTGUN";
|
|
5238
|
-
DamageMod2[DamageMod2["SSHOTGUN"] = 3] = "SSHOTGUN";
|
|
5239
|
-
DamageMod2[DamageMod2["MACHINEGUN"] = 4] = "MACHINEGUN";
|
|
5240
|
-
DamageMod2[DamageMod2["CHAINGUN"] = 5] = "CHAINGUN";
|
|
5241
|
-
DamageMod2[DamageMod2["GRENADE"] = 6] = "GRENADE";
|
|
5242
|
-
DamageMod2[DamageMod2["G_SPLASH"] = 7] = "G_SPLASH";
|
|
5243
|
-
DamageMod2[DamageMod2["ROCKET"] = 8] = "ROCKET";
|
|
5244
|
-
DamageMod2[DamageMod2["R_SPLASH"] = 9] = "R_SPLASH";
|
|
5245
|
-
DamageMod2[DamageMod2["HYPERBLASTER"] = 10] = "HYPERBLASTER";
|
|
5246
|
-
DamageMod2[DamageMod2["RAILGUN"] = 11] = "RAILGUN";
|
|
5247
|
-
DamageMod2[DamageMod2["BFG_LASER"] = 12] = "BFG_LASER";
|
|
5248
|
-
DamageMod2[DamageMod2["BFG_BLAST"] = 13] = "BFG_BLAST";
|
|
5249
|
-
DamageMod2[DamageMod2["BFG_EFFECT"] = 14] = "BFG_EFFECT";
|
|
5250
|
-
DamageMod2[DamageMod2["HANDGRENADE"] = 15] = "HANDGRENADE";
|
|
5251
|
-
DamageMod2[DamageMod2["HG_SPLASH"] = 16] = "HG_SPLASH";
|
|
5252
|
-
DamageMod2[DamageMod2["WATER"] = 17] = "WATER";
|
|
5253
|
-
DamageMod2[DamageMod2["SLIME"] = 18] = "SLIME";
|
|
5254
|
-
DamageMod2[DamageMod2["LAVA"] = 19] = "LAVA";
|
|
5255
|
-
DamageMod2[DamageMod2["CRUSH"] = 20] = "CRUSH";
|
|
5256
|
-
DamageMod2[DamageMod2["TELEFRAG"] = 21] = "TELEFRAG";
|
|
5257
|
-
DamageMod2[DamageMod2["TELEFRAG_SPAWN"] = 22] = "TELEFRAG_SPAWN";
|
|
5258
|
-
DamageMod2[DamageMod2["FALLING"] = 23] = "FALLING";
|
|
5259
|
-
DamageMod2[DamageMod2["SUICIDE"] = 24] = "SUICIDE";
|
|
5260
|
-
DamageMod2[DamageMod2["HELD_GRENADE"] = 25] = "HELD_GRENADE";
|
|
5261
|
-
DamageMod2[DamageMod2["EXPLOSIVE"] = 26] = "EXPLOSIVE";
|
|
5262
|
-
DamageMod2[DamageMod2["BARREL"] = 27] = "BARREL";
|
|
5263
|
-
DamageMod2[DamageMod2["BOMB"] = 28] = "BOMB";
|
|
5264
|
-
DamageMod2[DamageMod2["EXIT"] = 29] = "EXIT";
|
|
5265
|
-
DamageMod2[DamageMod2["SPLASH"] = 30] = "SPLASH";
|
|
5266
|
-
DamageMod2[DamageMod2["TARGET_LASER"] = 31] = "TARGET_LASER";
|
|
5267
|
-
DamageMod2[DamageMod2["TRIGGER_HURT"] = 32] = "TRIGGER_HURT";
|
|
5268
|
-
DamageMod2[DamageMod2["HIT"] = 33] = "HIT";
|
|
5269
|
-
DamageMod2[DamageMod2["TARGET_BLASTER"] = 34] = "TARGET_BLASTER";
|
|
5270
|
-
DamageMod2[DamageMod2["RIPPER"] = 35] = "RIPPER";
|
|
5271
|
-
DamageMod2[DamageMod2["PHALANX"] = 36] = "PHALANX";
|
|
5272
|
-
DamageMod2[DamageMod2["BRAINTENTACLE"] = 37] = "BRAINTENTACLE";
|
|
5273
|
-
DamageMod2[DamageMod2["BLASTOFF"] = 38] = "BLASTOFF";
|
|
5274
|
-
DamageMod2[DamageMod2["GEKK"] = 39] = "GEKK";
|
|
5275
|
-
DamageMod2[DamageMod2["TRAP"] = 40] = "TRAP";
|
|
5276
|
-
DamageMod2[DamageMod2["CHAINFIST"] = 41] = "CHAINFIST";
|
|
5277
|
-
DamageMod2[DamageMod2["DISINTEGRATOR"] = 42] = "DISINTEGRATOR";
|
|
5278
|
-
DamageMod2[DamageMod2["ETF_RIFLE"] = 43] = "ETF_RIFLE";
|
|
5279
|
-
DamageMod2[DamageMod2["BLASTER2"] = 44] = "BLASTER2";
|
|
5280
|
-
DamageMod2[DamageMod2["HEATBEAM"] = 45] = "HEATBEAM";
|
|
5281
|
-
DamageMod2[DamageMod2["TESLA"] = 46] = "TESLA";
|
|
5282
|
-
DamageMod2[DamageMod2["PROX"] = 47] = "PROX";
|
|
5283
|
-
DamageMod2[DamageMod2["NUKE"] = 48] = "NUKE";
|
|
5284
|
-
DamageMod2[DamageMod2["VENGEANCE_SPHERE"] = 49] = "VENGEANCE_SPHERE";
|
|
5285
|
-
DamageMod2[DamageMod2["HUNTER_SPHERE"] = 50] = "HUNTER_SPHERE";
|
|
5286
|
-
DamageMod2[DamageMod2["DEFENDER_SPHERE"] = 51] = "DEFENDER_SPHERE";
|
|
5287
|
-
DamageMod2[DamageMod2["TRACKER"] = 52] = "TRACKER";
|
|
5288
|
-
DamageMod2[DamageMod2["DBALL_CRUSH"] = 53] = "DBALL_CRUSH";
|
|
5289
|
-
DamageMod2[DamageMod2["DOPPLE_EXPLODE"] = 54] = "DOPPLE_EXPLODE";
|
|
5290
|
-
DamageMod2[DamageMod2["DOPPLE_VENGEANCE"] = 55] = "DOPPLE_VENGEANCE";
|
|
5291
|
-
DamageMod2[DamageMod2["DOPPLE_HUNTER"] = 56] = "DOPPLE_HUNTER";
|
|
5292
|
-
DamageMod2[DamageMod2["GRAPPLE"] = 57] = "GRAPPLE";
|
|
5293
|
-
DamageMod2[DamageMod2["BLUEBLASTER"] = 58] = "BLUEBLASTER";
|
|
5294
|
-
return DamageMod2;
|
|
5295
|
-
})(DamageMod || {});
|
|
5296
|
-
var ORDERED_DAMAGE_MODS = [
|
|
5297
|
-
0 /* UNKNOWN */,
|
|
5298
|
-
1 /* BLASTER */,
|
|
5299
|
-
2 /* SHOTGUN */,
|
|
5300
|
-
3 /* SSHOTGUN */,
|
|
5301
|
-
4 /* MACHINEGUN */,
|
|
5302
|
-
5 /* CHAINGUN */,
|
|
5303
|
-
6 /* GRENADE */,
|
|
5304
|
-
7 /* G_SPLASH */,
|
|
5305
|
-
8 /* ROCKET */,
|
|
5306
|
-
9 /* R_SPLASH */,
|
|
5307
|
-
10 /* HYPERBLASTER */,
|
|
5308
|
-
11 /* RAILGUN */,
|
|
5309
|
-
12 /* BFG_LASER */,
|
|
5310
|
-
13 /* BFG_BLAST */,
|
|
5311
|
-
14 /* BFG_EFFECT */,
|
|
5312
|
-
15 /* HANDGRENADE */,
|
|
5313
|
-
16 /* HG_SPLASH */,
|
|
5314
|
-
17 /* WATER */,
|
|
5315
|
-
18 /* SLIME */,
|
|
5316
|
-
19 /* LAVA */,
|
|
5317
|
-
20 /* CRUSH */,
|
|
5318
|
-
21 /* TELEFRAG */,
|
|
5319
|
-
22 /* TELEFRAG_SPAWN */,
|
|
5320
|
-
23 /* FALLING */,
|
|
5321
|
-
24 /* SUICIDE */,
|
|
5322
|
-
25 /* HELD_GRENADE */,
|
|
5323
|
-
26 /* EXPLOSIVE */,
|
|
5324
|
-
27 /* BARREL */,
|
|
5325
|
-
28 /* BOMB */,
|
|
5326
|
-
29 /* EXIT */,
|
|
5327
|
-
30 /* SPLASH */,
|
|
5328
|
-
31 /* TARGET_LASER */,
|
|
5329
|
-
32 /* TRIGGER_HURT */,
|
|
5330
|
-
33 /* HIT */,
|
|
5331
|
-
34 /* TARGET_BLASTER */,
|
|
5332
|
-
35 /* RIPPER */,
|
|
5333
|
-
36 /* PHALANX */,
|
|
5334
|
-
37 /* BRAINTENTACLE */,
|
|
5335
|
-
38 /* BLASTOFF */,
|
|
5336
|
-
39 /* GEKK */,
|
|
5337
|
-
40 /* TRAP */,
|
|
5338
|
-
41 /* CHAINFIST */,
|
|
5339
|
-
42 /* DISINTEGRATOR */,
|
|
5340
|
-
43 /* ETF_RIFLE */,
|
|
5341
|
-
44 /* BLASTER2 */,
|
|
5342
|
-
45 /* HEATBEAM */,
|
|
5343
|
-
46 /* TESLA */,
|
|
5344
|
-
47 /* PROX */,
|
|
5345
|
-
48 /* NUKE */,
|
|
5346
|
-
49 /* VENGEANCE_SPHERE */,
|
|
5347
|
-
50 /* HUNTER_SPHERE */,
|
|
5348
|
-
51 /* DEFENDER_SPHERE */,
|
|
5349
|
-
52 /* TRACKER */,
|
|
5350
|
-
53 /* DBALL_CRUSH */,
|
|
5351
|
-
54 /* DOPPLE_EXPLODE */,
|
|
5352
|
-
55 /* DOPPLE_VENGEANCE */,
|
|
5353
|
-
56 /* DOPPLE_HUNTER */,
|
|
5354
|
-
57 /* GRAPPLE */,
|
|
5355
|
-
58 /* BLUEBLASTER */
|
|
5356
|
-
];
|
|
5357
|
-
function damageModName(mod) {
|
|
5358
|
-
return `MOD_${DamageMod[mod]}`;
|
|
5359
|
-
}
|
|
5360
|
-
|
|
5361
5640
|
// src/combat/specialDamage.ts
|
|
5362
5641
|
var ZERO2 = { x: 0, y: 0, z: 0 };
|
|
5363
5642
|
var EnvironmentalFlags = /* @__PURE__ */ ((EnvironmentalFlags2) => {
|
|
@@ -5836,12 +6115,17 @@ function createGame({ trace, pointcontents }, engine, options) {
|
|
|
5836
6115
|
convertRereleaseLevelToGameSave,
|
|
5837
6116
|
convertRereleaseSaveToGameSave,
|
|
5838
6117
|
createAmmoInventory,
|
|
6118
|
+
createAmmoPickupEntity,
|
|
6119
|
+
createArmorPickupEntity,
|
|
5839
6120
|
createBaseAmmoCaps,
|
|
5840
6121
|
createCallbackRegistry,
|
|
5841
6122
|
createDefaultSpawnRegistry,
|
|
5842
6123
|
createGame,
|
|
6124
|
+
createHealthPickupEntity,
|
|
6125
|
+
createKeyPickupEntity,
|
|
5843
6126
|
createPlayerInventory,
|
|
5844
6127
|
createPlayerWeaponStates,
|
|
6128
|
+
createPowerupPickupEntity,
|
|
5845
6129
|
createSaveFile,
|
|
5846
6130
|
createWeaponPickupEntity,
|
|
5847
6131
|
damageModName,
|