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
|
@@ -1385,6 +1385,12 @@ var EntitySystem = class {
|
|
|
1385
1385
|
}
|
|
1386
1386
|
}
|
|
1387
1387
|
}
|
|
1388
|
+
get trace() {
|
|
1389
|
+
return this.imports.trace;
|
|
1390
|
+
}
|
|
1391
|
+
get pointcontents() {
|
|
1392
|
+
return this.imports.pointcontents;
|
|
1393
|
+
}
|
|
1388
1394
|
get world() {
|
|
1389
1395
|
return this.pool.world;
|
|
1390
1396
|
}
|
|
@@ -2336,14 +2342,14 @@ var AmmoType = /* @__PURE__ */ ((AmmoType3) => {
|
|
|
2336
2342
|
return AmmoType3;
|
|
2337
2343
|
})(AmmoType || {});
|
|
2338
2344
|
var AMMO_TYPE_COUNT = Object.keys(AmmoType).length / 2;
|
|
2339
|
-
var AmmoItemId = /* @__PURE__ */ ((
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
2346
|
-
return
|
|
2345
|
+
var AmmoItemId = /* @__PURE__ */ ((AmmoItemId4) => {
|
|
2346
|
+
AmmoItemId4["Shells"] = "ammo_shells";
|
|
2347
|
+
AmmoItemId4["Bullets"] = "ammo_bullets";
|
|
2348
|
+
AmmoItemId4["Rockets"] = "ammo_rockets";
|
|
2349
|
+
AmmoItemId4["Grenades"] = "ammo_grenades";
|
|
2350
|
+
AmmoItemId4["Cells"] = "ammo_cells";
|
|
2351
|
+
AmmoItemId4["Slugs"] = "ammo_slugs";
|
|
2352
|
+
return AmmoItemId4;
|
|
2347
2353
|
})(AmmoItemId || {});
|
|
2348
2354
|
var AMMO_ITEM_DEFINITIONS = {
|
|
2349
2355
|
["ammo_shells" /* Shells */]: { id: "ammo_shells" /* Shells */, ammoType: 1 /* Shells */, quantity: 10, weaponAmmo: false },
|
|
@@ -3078,6 +3084,32 @@ function createKeyPickupEntity(game, keyItem) {
|
|
|
3078
3084
|
};
|
|
3079
3085
|
}
|
|
3080
3086
|
|
|
3087
|
+
// src/entities/items/ammo.ts
|
|
3088
|
+
function createAmmoPickupEntity(game, itemId) {
|
|
3089
|
+
const def = getAmmoItemDefinition(itemId);
|
|
3090
|
+
const respawn = (self) => {
|
|
3091
|
+
self.solid = 1 /* Trigger */;
|
|
3092
|
+
};
|
|
3093
|
+
return {
|
|
3094
|
+
classname: itemId,
|
|
3095
|
+
solid: 1 /* Trigger */,
|
|
3096
|
+
touch: (self, other) => {
|
|
3097
|
+
if (!other || !other.client) {
|
|
3098
|
+
return;
|
|
3099
|
+
}
|
|
3100
|
+
const result = pickupAmmo(other.client.inventory.ammo, itemId);
|
|
3101
|
+
if (result.pickedUp) {
|
|
3102
|
+
game.sound?.(other, 0, "items/pkup.wav", 1, 1, 0);
|
|
3103
|
+
game.centerprintf?.(other, `You got ${def.quantity} ${itemId.replace("ammo_", "")}`);
|
|
3104
|
+
self.solid = 0 /* Not */;
|
|
3105
|
+
self.nextthink = game.time + 30;
|
|
3106
|
+
game.entities.scheduleThink(self, self.nextthink);
|
|
3107
|
+
}
|
|
3108
|
+
},
|
|
3109
|
+
think: respawn
|
|
3110
|
+
};
|
|
3111
|
+
}
|
|
3112
|
+
|
|
3081
3113
|
// src/entities/items.ts
|
|
3082
3114
|
function registerItemSpawns(game, registry) {
|
|
3083
3115
|
for (const weaponItem of Object.values(WEAPON_ITEMS)) {
|
|
@@ -3105,6 +3137,11 @@ function registerItemSpawns(game, registry) {
|
|
|
3105
3137
|
Object.assign(entity, createKeyPickupEntity(game, keyItem));
|
|
3106
3138
|
});
|
|
3107
3139
|
}
|
|
3140
|
+
for (const ammoId of Object.values(AmmoItemId)) {
|
|
3141
|
+
registry.register(ammoId, (entity) => {
|
|
3142
|
+
Object.assign(entity, createAmmoPickupEntity(game, ammoId));
|
|
3143
|
+
});
|
|
3144
|
+
}
|
|
3108
3145
|
}
|
|
3109
3146
|
|
|
3110
3147
|
// src/entities/funcs.ts
|
|
@@ -3169,6 +3206,7 @@ var func_door = (entity, context) => {
|
|
|
3169
3206
|
self.state = 1 /* Opening */;
|
|
3170
3207
|
self.think = door_go_up;
|
|
3171
3208
|
context.entities.scheduleThink(self, context.entities.timeSeconds + 0.1);
|
|
3209
|
+
context.entities.sound(self, 0, "doors/dr1_strt.wav", 1, 1, 0);
|
|
3172
3210
|
};
|
|
3173
3211
|
};
|
|
3174
3212
|
var func_button = (entity, context) => {
|
|
@@ -3176,6 +3214,7 @@ var func_button = (entity, context) => {
|
|
|
3176
3214
|
entity.movetype = 2 /* Push */;
|
|
3177
3215
|
entity.use = (self) => {
|
|
3178
3216
|
context.entities.useTargets(self, self);
|
|
3217
|
+
context.entities.sound(self, 0, "switches/butn2.wav", 1, 1, 0);
|
|
3179
3218
|
};
|
|
3180
3219
|
};
|
|
3181
3220
|
var TRAIN_START_ON = 1;
|
|
@@ -3453,6 +3492,66 @@ var TraceMask = /* @__PURE__ */ ((TraceMask2) => {
|
|
|
3453
3492
|
return TraceMask2;
|
|
3454
3493
|
})(TraceMask || {});
|
|
3455
3494
|
|
|
3495
|
+
// src/ai/perception.ts
|
|
3496
|
+
var RangeCategory = /* @__PURE__ */ ((RangeCategory2) => {
|
|
3497
|
+
RangeCategory2["Melee"] = "melee";
|
|
3498
|
+
RangeCategory2["Near"] = "near";
|
|
3499
|
+
RangeCategory2["Mid"] = "mid";
|
|
3500
|
+
RangeCategory2["Far"] = "far";
|
|
3501
|
+
return RangeCategory2;
|
|
3502
|
+
})(RangeCategory || {});
|
|
3503
|
+
function absBounds(entity) {
|
|
3504
|
+
return {
|
|
3505
|
+
mins: {
|
|
3506
|
+
x: entity.origin.x + entity.mins.x,
|
|
3507
|
+
y: entity.origin.y + entity.mins.y,
|
|
3508
|
+
z: entity.origin.z + entity.mins.z
|
|
3509
|
+
},
|
|
3510
|
+
maxs: {
|
|
3511
|
+
x: entity.origin.x + entity.maxs.x,
|
|
3512
|
+
y: entity.origin.y + entity.maxs.y,
|
|
3513
|
+
z: entity.origin.z + entity.maxs.z
|
|
3514
|
+
}
|
|
3515
|
+
};
|
|
3516
|
+
}
|
|
3517
|
+
function rangeTo(self, other) {
|
|
3518
|
+
const a = absBounds(self);
|
|
3519
|
+
const b = absBounds(other);
|
|
3520
|
+
const distanceSquared = distanceBetweenBoxesSquared(a.mins, a.maxs, b.mins, b.maxs);
|
|
3521
|
+
return Math.sqrt(distanceSquared);
|
|
3522
|
+
}
|
|
3523
|
+
function classifyRange(distance2) {
|
|
3524
|
+
if (distance2 <= RANGE_MELEE) {
|
|
3525
|
+
return "melee" /* Melee */;
|
|
3526
|
+
}
|
|
3527
|
+
if (distance2 <= RANGE_NEAR) {
|
|
3528
|
+
return "near" /* Near */;
|
|
3529
|
+
}
|
|
3530
|
+
if (distance2 <= RANGE_MID) {
|
|
3531
|
+
return "mid" /* Mid */;
|
|
3532
|
+
}
|
|
3533
|
+
return "far" /* Far */;
|
|
3534
|
+
}
|
|
3535
|
+
function infront(self, other) {
|
|
3536
|
+
const { forward } = angleVectors(self.angles);
|
|
3537
|
+
const direction = normalizeVec3(subtractVec3(other.origin, self.origin));
|
|
3538
|
+
const dot = dotVec3(direction, forward);
|
|
3539
|
+
if ((self.spawnflags & SPAWNFLAG_MONSTER_AMBUSH) !== 0 && self.trail_time === 0 && self.enemy === null) {
|
|
3540
|
+
return dot > 0.15;
|
|
3541
|
+
}
|
|
3542
|
+
return dot > -0.3;
|
|
3543
|
+
}
|
|
3544
|
+
function visible(self, other, trace, options) {
|
|
3545
|
+
if ((other.flags & FL_NOVISIBLE) !== 0) {
|
|
3546
|
+
return false;
|
|
3547
|
+
}
|
|
3548
|
+
const start = { x: self.origin.x, y: self.origin.y, z: self.origin.z + self.viewheight };
|
|
3549
|
+
const end = { x: other.origin.x, y: other.origin.y, z: other.origin.z + other.viewheight };
|
|
3550
|
+
const mask = options?.throughGlass ? 1 /* Opaque */ : 1 /* Opaque */ | 2 /* Window */;
|
|
3551
|
+
const result = trace(start, end, self, mask);
|
|
3552
|
+
return result.fraction === 1 || result.entity === other;
|
|
3553
|
+
}
|
|
3554
|
+
|
|
3456
3555
|
// src/ai/movement.ts
|
|
3457
3556
|
function yawVector(yawDegrees, distance2) {
|
|
3458
3557
|
if (distance2 === 0) {
|
|
@@ -3514,12 +3613,24 @@ function setIdealYawTowards(self, target) {
|
|
|
3514
3613
|
function ai_stand(self, deltaSeconds) {
|
|
3515
3614
|
changeYaw(self, deltaSeconds);
|
|
3516
3615
|
}
|
|
3517
|
-
function ai_walk(self, distance2, deltaSeconds) {
|
|
3616
|
+
function ai_walk(self, distance2, deltaSeconds, context) {
|
|
3518
3617
|
setIdealYawTowards(self, self.goalentity);
|
|
3519
3618
|
changeYaw(self, deltaSeconds);
|
|
3520
3619
|
if (distance2 !== 0) {
|
|
3521
3620
|
walkMove(self, self.angles.y, distance2);
|
|
3522
3621
|
}
|
|
3622
|
+
if (self.goalentity && self.goalentity.classname === "path_corner") {
|
|
3623
|
+
const dist = rangeTo(self, self.goalentity);
|
|
3624
|
+
if (dist < 64) {
|
|
3625
|
+
if (self.goalentity.target) {
|
|
3626
|
+
const next = context.pickTarget(self.goalentity.target);
|
|
3627
|
+
if (next) {
|
|
3628
|
+
self.goalentity = next;
|
|
3629
|
+
self.ideal_yaw = self.angles.y;
|
|
3630
|
+
}
|
|
3631
|
+
}
|
|
3632
|
+
}
|
|
3633
|
+
}
|
|
3523
3634
|
}
|
|
3524
3635
|
function ai_turn(self, distance2, deltaSeconds) {
|
|
3525
3636
|
if (distance2 !== 0) {
|
|
@@ -3551,66 +3662,6 @@ function ai_charge(self, distance2, deltaSeconds) {
|
|
|
3551
3662
|
}
|
|
3552
3663
|
}
|
|
3553
3664
|
|
|
3554
|
-
// src/ai/perception.ts
|
|
3555
|
-
var RangeCategory = /* @__PURE__ */ ((RangeCategory2) => {
|
|
3556
|
-
RangeCategory2["Melee"] = "melee";
|
|
3557
|
-
RangeCategory2["Near"] = "near";
|
|
3558
|
-
RangeCategory2["Mid"] = "mid";
|
|
3559
|
-
RangeCategory2["Far"] = "far";
|
|
3560
|
-
return RangeCategory2;
|
|
3561
|
-
})(RangeCategory || {});
|
|
3562
|
-
function absBounds(entity) {
|
|
3563
|
-
return {
|
|
3564
|
-
mins: {
|
|
3565
|
-
x: entity.origin.x + entity.mins.x,
|
|
3566
|
-
y: entity.origin.y + entity.mins.y,
|
|
3567
|
-
z: entity.origin.z + entity.mins.z
|
|
3568
|
-
},
|
|
3569
|
-
maxs: {
|
|
3570
|
-
x: entity.origin.x + entity.maxs.x,
|
|
3571
|
-
y: entity.origin.y + entity.maxs.y,
|
|
3572
|
-
z: entity.origin.z + entity.maxs.z
|
|
3573
|
-
}
|
|
3574
|
-
};
|
|
3575
|
-
}
|
|
3576
|
-
function rangeTo(self, other) {
|
|
3577
|
-
const a = absBounds(self);
|
|
3578
|
-
const b = absBounds(other);
|
|
3579
|
-
const distanceSquared = distanceBetweenBoxesSquared(a.mins, a.maxs, b.mins, b.maxs);
|
|
3580
|
-
return Math.sqrt(distanceSquared);
|
|
3581
|
-
}
|
|
3582
|
-
function classifyRange(distance2) {
|
|
3583
|
-
if (distance2 <= RANGE_MELEE) {
|
|
3584
|
-
return "melee" /* Melee */;
|
|
3585
|
-
}
|
|
3586
|
-
if (distance2 <= RANGE_NEAR) {
|
|
3587
|
-
return "near" /* Near */;
|
|
3588
|
-
}
|
|
3589
|
-
if (distance2 <= RANGE_MID) {
|
|
3590
|
-
return "mid" /* Mid */;
|
|
3591
|
-
}
|
|
3592
|
-
return "far" /* Far */;
|
|
3593
|
-
}
|
|
3594
|
-
function infront(self, other) {
|
|
3595
|
-
const { forward } = angleVectors(self.angles);
|
|
3596
|
-
const direction = normalizeVec3(subtractVec3(other.origin, self.origin));
|
|
3597
|
-
const dot = dotVec3(direction, forward);
|
|
3598
|
-
if ((self.spawnflags & SPAWNFLAG_MONSTER_AMBUSH) !== 0 && self.trail_time === 0 && self.enemy === null) {
|
|
3599
|
-
return dot > 0.15;
|
|
3600
|
-
}
|
|
3601
|
-
return dot > -0.3;
|
|
3602
|
-
}
|
|
3603
|
-
function visible(self, other, trace, options) {
|
|
3604
|
-
if ((other.flags & FL_NOVISIBLE) !== 0) {
|
|
3605
|
-
return false;
|
|
3606
|
-
}
|
|
3607
|
-
const start = { x: self.origin.x, y: self.origin.y, z: self.origin.z + self.viewheight };
|
|
3608
|
-
const end = { x: other.origin.x, y: other.origin.y, z: other.origin.z + other.viewheight };
|
|
3609
|
-
const mask = options?.throughGlass ? 1 /* Opaque */ : 1 /* Opaque */ | 2 /* Window */;
|
|
3610
|
-
const result = trace(start, end, self, mask);
|
|
3611
|
-
return result.fraction === 1 || result.entity === other;
|
|
3612
|
-
}
|
|
3613
|
-
|
|
3614
3665
|
// src/ai/targeting.ts
|
|
3615
3666
|
function setIdealYawTowards2(self, other) {
|
|
3616
3667
|
const delta = {
|
|
@@ -3623,19 +3674,19 @@ function setIdealYawTowards2(self, other) {
|
|
|
3623
3674
|
function faceYawInstantly(self) {
|
|
3624
3675
|
self.angles.y = angleMod(self.ideal_yaw);
|
|
3625
3676
|
}
|
|
3626
|
-
function huntTarget(self, level) {
|
|
3677
|
+
function huntTarget(self, level, context) {
|
|
3627
3678
|
if (!self.enemy) return;
|
|
3628
3679
|
self.goalentity = self.enemy;
|
|
3629
3680
|
setIdealYawTowards2(self, self.enemy);
|
|
3630
3681
|
faceYawInstantly(self);
|
|
3631
3682
|
if ((self.monsterinfo.aiflags & 1 /* StandGround */) !== 0) {
|
|
3632
|
-
self.monsterinfo.stand?.(self);
|
|
3683
|
+
self.monsterinfo.stand?.(self, context);
|
|
3633
3684
|
} else {
|
|
3634
|
-
self.monsterinfo.run?.(self);
|
|
3685
|
+
self.monsterinfo.run?.(self, context);
|
|
3635
3686
|
self.attack_finished_time = level.timeSeconds + 1;
|
|
3636
3687
|
}
|
|
3637
3688
|
}
|
|
3638
|
-
function foundTarget(self, level, options) {
|
|
3689
|
+
function foundTarget(self, level, context, options) {
|
|
3639
3690
|
if (!self.enemy) return;
|
|
3640
3691
|
if ((self.enemy.svflags & 8 /* Player */) !== 0) {
|
|
3641
3692
|
level.sightEntity = self;
|
|
@@ -3650,7 +3701,7 @@ function foundTarget(self, level, options) {
|
|
|
3650
3701
|
self.trail_time = level.timeSeconds;
|
|
3651
3702
|
self.monsterinfo.trail_time = level.timeSeconds;
|
|
3652
3703
|
if (!self.combattarget) {
|
|
3653
|
-
huntTarget(self, level);
|
|
3704
|
+
huntTarget(self, level, context);
|
|
3654
3705
|
return;
|
|
3655
3706
|
}
|
|
3656
3707
|
const pickTarget = options?.pickTarget;
|
|
@@ -3663,7 +3714,7 @@ function foundTarget(self, level, options) {
|
|
|
3663
3714
|
self.movetarget.targetname = void 0;
|
|
3664
3715
|
}
|
|
3665
3716
|
self.monsterinfo.pausetime = 0;
|
|
3666
|
-
self.monsterinfo.run?.(self);
|
|
3717
|
+
self.monsterinfo.run?.(self, context);
|
|
3667
3718
|
}
|
|
3668
3719
|
function classifyClientVisibility(self, other, level, trace) {
|
|
3669
3720
|
const distance2 = rangeTo(self, other);
|
|
@@ -3720,7 +3771,7 @@ function rejectNotargetEntity(client) {
|
|
|
3720
3771
|
if (client.enemy && (client.enemy.flags & FL_NOTARGET) !== 0) return true;
|
|
3721
3772
|
return false;
|
|
3722
3773
|
}
|
|
3723
|
-
function findTarget(self, level, trace, hearability = {}) {
|
|
3774
|
+
function findTarget(self, level, context, trace, hearability = {}) {
|
|
3724
3775
|
if ((self.monsterinfo.aiflags & 256 /* GoodGuy */) !== 0) {
|
|
3725
3776
|
if (self.goalentity?.classname === "target_actor") {
|
|
3726
3777
|
return false;
|
|
@@ -3741,7 +3792,7 @@ function findTarget(self, level, trace, hearability = {}) {
|
|
|
3741
3792
|
} else if (!updateSoundChase(self, candidate, level, hearability, trace)) {
|
|
3742
3793
|
return false;
|
|
3743
3794
|
}
|
|
3744
|
-
foundTarget(self, level);
|
|
3795
|
+
foundTarget(self, level, context);
|
|
3745
3796
|
if ((self.monsterinfo.aiflags & 4 /* SoundTarget */) === 0) {
|
|
3746
3797
|
self.monsterinfo.sight?.(self, self.enemy);
|
|
3747
3798
|
}
|
|
@@ -3749,7 +3800,7 @@ function findTarget(self, level, trace, hearability = {}) {
|
|
|
3749
3800
|
}
|
|
3750
3801
|
|
|
3751
3802
|
// src/ai/monster.ts
|
|
3752
|
-
function M_MoveFrame(self) {
|
|
3803
|
+
function M_MoveFrame(self, context) {
|
|
3753
3804
|
const move = self.monsterinfo.current_move;
|
|
3754
3805
|
if (!move) {
|
|
3755
3806
|
return;
|
|
@@ -3764,10 +3815,10 @@ function M_MoveFrame(self) {
|
|
|
3764
3815
|
const index = self.frame - move.firstframe;
|
|
3765
3816
|
const frame = move.frames[index];
|
|
3766
3817
|
if (frame.ai) {
|
|
3767
|
-
frame.ai(self, frame.dist);
|
|
3818
|
+
frame.ai(self, frame.dist, context);
|
|
3768
3819
|
}
|
|
3769
3820
|
if (frame.think) {
|
|
3770
|
-
frame.think(self);
|
|
3821
|
+
frame.think(self, context);
|
|
3771
3822
|
}
|
|
3772
3823
|
if (!self.inUse) {
|
|
3773
3824
|
return;
|
|
@@ -3775,7 +3826,7 @@ function M_MoveFrame(self) {
|
|
|
3775
3826
|
self.frame++;
|
|
3776
3827
|
if (self.frame > move.lastframe) {
|
|
3777
3828
|
if (move.endfunc) {
|
|
3778
|
-
move.endfunc(self);
|
|
3829
|
+
move.endfunc(self, context);
|
|
3779
3830
|
if (self.monsterinfo.current_move !== move) {
|
|
3780
3831
|
return;
|
|
3781
3832
|
}
|
|
@@ -3783,125 +3834,589 @@ function M_MoveFrame(self) {
|
|
|
3783
3834
|
}
|
|
3784
3835
|
}
|
|
3785
3836
|
function monster_think(self, context) {
|
|
3786
|
-
M_MoveFrame(self);
|
|
3787
|
-
|
|
3788
|
-
self.nextthink = time + 0.1;
|
|
3789
|
-
}
|
|
3790
|
-
|
|
3791
|
-
// src/entities/monsters/soldier.ts
|
|
3792
|
-
var MONSTER_TICK = 0.1;
|
|
3793
|
-
function monster_ai_stand(self, dist) {
|
|
3794
|
-
ai_stand(self, MONSTER_TICK);
|
|
3795
|
-
}
|
|
3796
|
-
function monster_ai_walk(self, dist) {
|
|
3797
|
-
ai_walk(self, dist, MONSTER_TICK);
|
|
3798
|
-
}
|
|
3799
|
-
function monster_ai_run(self, dist) {
|
|
3800
|
-
ai_run(self, dist, MONSTER_TICK);
|
|
3801
|
-
}
|
|
3802
|
-
function monster_ai_charge(self, dist) {
|
|
3803
|
-
ai_charge(self, dist, MONSTER_TICK);
|
|
3804
|
-
}
|
|
3805
|
-
var stand_move;
|
|
3806
|
-
var walk_move;
|
|
3807
|
-
var run_move;
|
|
3808
|
-
var attack_move;
|
|
3809
|
-
function soldier_stand(self) {
|
|
3810
|
-
self.monsterinfo.current_move = stand_move;
|
|
3811
|
-
}
|
|
3812
|
-
function soldier_walk(self) {
|
|
3813
|
-
self.monsterinfo.current_move = walk_move;
|
|
3814
|
-
}
|
|
3815
|
-
function soldier_run(self) {
|
|
3816
|
-
if (self.enemy && self.enemy.health > 0) {
|
|
3817
|
-
self.monsterinfo.current_move = run_move;
|
|
3818
|
-
} else {
|
|
3819
|
-
self.monsterinfo.current_move = stand_move;
|
|
3820
|
-
}
|
|
3821
|
-
}
|
|
3822
|
-
function soldier_attack(self) {
|
|
3823
|
-
self.monsterinfo.current_move = attack_move;
|
|
3824
|
-
}
|
|
3825
|
-
function soldier_fire(self) {
|
|
3826
|
-
}
|
|
3827
|
-
var stand_frames = Array.from({ length: 30 }, () => ({
|
|
3828
|
-
ai: monster_ai_stand,
|
|
3829
|
-
dist: 0
|
|
3830
|
-
}));
|
|
3831
|
-
stand_move = {
|
|
3832
|
-
firstframe: 0,
|
|
3833
|
-
lastframe: 29,
|
|
3834
|
-
frames: stand_frames,
|
|
3835
|
-
endfunc: soldier_stand
|
|
3836
|
-
};
|
|
3837
|
-
var walk_frames = Array.from({ length: 40 }, () => ({
|
|
3838
|
-
ai: monster_ai_walk,
|
|
3839
|
-
dist: 2
|
|
3840
|
-
}));
|
|
3841
|
-
walk_move = {
|
|
3842
|
-
firstframe: 30,
|
|
3843
|
-
lastframe: 69,
|
|
3844
|
-
frames: walk_frames,
|
|
3845
|
-
endfunc: soldier_walk
|
|
3846
|
-
};
|
|
3847
|
-
var run_frames = Array.from({ length: 20 }, () => ({
|
|
3848
|
-
ai: monster_ai_run,
|
|
3849
|
-
dist: 10
|
|
3850
|
-
}));
|
|
3851
|
-
run_move = {
|
|
3852
|
-
firstframe: 70,
|
|
3853
|
-
lastframe: 89,
|
|
3854
|
-
frames: run_frames,
|
|
3855
|
-
endfunc: soldier_run
|
|
3856
|
-
};
|
|
3857
|
-
var attack_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
3858
|
-
ai: monster_ai_charge,
|
|
3859
|
-
dist: 0,
|
|
3860
|
-
think: i === 5 ? soldier_fire : null
|
|
3861
|
-
}));
|
|
3862
|
-
attack_move = {
|
|
3863
|
-
firstframe: 90,
|
|
3864
|
-
lastframe: 99,
|
|
3865
|
-
frames: attack_frames,
|
|
3866
|
-
endfunc: soldier_run
|
|
3867
|
-
};
|
|
3868
|
-
function SP_monster_soldier(self, context) {
|
|
3869
|
-
self.model = "models/monsters/soldier/tris.md2";
|
|
3870
|
-
self.mins = { x: -16, y: -16, z: -24 };
|
|
3871
|
-
self.maxs = { x: 16, y: 16, z: 32 };
|
|
3872
|
-
self.movetype = 5 /* Step */;
|
|
3873
|
-
self.solid = 2 /* BoundingBox */;
|
|
3874
|
-
self.health = 20;
|
|
3875
|
-
self.max_health = 20;
|
|
3876
|
-
self.mass = 100;
|
|
3877
|
-
self.pain = (self2, other, kick, damage) => {
|
|
3878
|
-
};
|
|
3879
|
-
self.die = (self2, inflictor, attacker, damage, point) => {
|
|
3880
|
-
self2.deadflag = 2 /* Dead */;
|
|
3881
|
-
self2.solid = 0 /* Not */;
|
|
3882
|
-
};
|
|
3883
|
-
self.monsterinfo.stand = soldier_stand;
|
|
3884
|
-
self.monsterinfo.walk = soldier_walk;
|
|
3885
|
-
self.monsterinfo.run = soldier_run;
|
|
3886
|
-
self.monsterinfo.attack = soldier_attack;
|
|
3887
|
-
self.think = monster_think;
|
|
3888
|
-
soldier_stand(self);
|
|
3889
|
-
self.nextthink = self.timestamp + MONSTER_TICK;
|
|
3890
|
-
}
|
|
3891
|
-
function registerMonsterSpawns(registry) {
|
|
3892
|
-
registry.register("monster_soldier", SP_monster_soldier);
|
|
3837
|
+
M_MoveFrame(self, context);
|
|
3838
|
+
self.nextthink = context.timeSeconds + 0.1;
|
|
3893
3839
|
}
|
|
3894
3840
|
|
|
3895
|
-
// src/
|
|
3896
|
-
var
|
|
3897
|
-
|
|
3898
|
-
|
|
3899
|
-
|
|
3900
|
-
|
|
3901
|
-
|
|
3902
|
-
|
|
3903
|
-
|
|
3904
|
-
|
|
3841
|
+
// src/combat/damageMods.ts
|
|
3842
|
+
var DamageMod = /* @__PURE__ */ ((DamageMod2) => {
|
|
3843
|
+
DamageMod2[DamageMod2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
3844
|
+
DamageMod2[DamageMod2["BLASTER"] = 1] = "BLASTER";
|
|
3845
|
+
DamageMod2[DamageMod2["SHOTGUN"] = 2] = "SHOTGUN";
|
|
3846
|
+
DamageMod2[DamageMod2["SSHOTGUN"] = 3] = "SSHOTGUN";
|
|
3847
|
+
DamageMod2[DamageMod2["MACHINEGUN"] = 4] = "MACHINEGUN";
|
|
3848
|
+
DamageMod2[DamageMod2["CHAINGUN"] = 5] = "CHAINGUN";
|
|
3849
|
+
DamageMod2[DamageMod2["GRENADE"] = 6] = "GRENADE";
|
|
3850
|
+
DamageMod2[DamageMod2["G_SPLASH"] = 7] = "G_SPLASH";
|
|
3851
|
+
DamageMod2[DamageMod2["ROCKET"] = 8] = "ROCKET";
|
|
3852
|
+
DamageMod2[DamageMod2["R_SPLASH"] = 9] = "R_SPLASH";
|
|
3853
|
+
DamageMod2[DamageMod2["HYPERBLASTER"] = 10] = "HYPERBLASTER";
|
|
3854
|
+
DamageMod2[DamageMod2["RAILGUN"] = 11] = "RAILGUN";
|
|
3855
|
+
DamageMod2[DamageMod2["BFG_LASER"] = 12] = "BFG_LASER";
|
|
3856
|
+
DamageMod2[DamageMod2["BFG_BLAST"] = 13] = "BFG_BLAST";
|
|
3857
|
+
DamageMod2[DamageMod2["BFG_EFFECT"] = 14] = "BFG_EFFECT";
|
|
3858
|
+
DamageMod2[DamageMod2["HANDGRENADE"] = 15] = "HANDGRENADE";
|
|
3859
|
+
DamageMod2[DamageMod2["HG_SPLASH"] = 16] = "HG_SPLASH";
|
|
3860
|
+
DamageMod2[DamageMod2["WATER"] = 17] = "WATER";
|
|
3861
|
+
DamageMod2[DamageMod2["SLIME"] = 18] = "SLIME";
|
|
3862
|
+
DamageMod2[DamageMod2["LAVA"] = 19] = "LAVA";
|
|
3863
|
+
DamageMod2[DamageMod2["CRUSH"] = 20] = "CRUSH";
|
|
3864
|
+
DamageMod2[DamageMod2["TELEFRAG"] = 21] = "TELEFRAG";
|
|
3865
|
+
DamageMod2[DamageMod2["TELEFRAG_SPAWN"] = 22] = "TELEFRAG_SPAWN";
|
|
3866
|
+
DamageMod2[DamageMod2["FALLING"] = 23] = "FALLING";
|
|
3867
|
+
DamageMod2[DamageMod2["SUICIDE"] = 24] = "SUICIDE";
|
|
3868
|
+
DamageMod2[DamageMod2["HELD_GRENADE"] = 25] = "HELD_GRENADE";
|
|
3869
|
+
DamageMod2[DamageMod2["EXPLOSIVE"] = 26] = "EXPLOSIVE";
|
|
3870
|
+
DamageMod2[DamageMod2["BARREL"] = 27] = "BARREL";
|
|
3871
|
+
DamageMod2[DamageMod2["BOMB"] = 28] = "BOMB";
|
|
3872
|
+
DamageMod2[DamageMod2["EXIT"] = 29] = "EXIT";
|
|
3873
|
+
DamageMod2[DamageMod2["SPLASH"] = 30] = "SPLASH";
|
|
3874
|
+
DamageMod2[DamageMod2["TARGET_LASER"] = 31] = "TARGET_LASER";
|
|
3875
|
+
DamageMod2[DamageMod2["TRIGGER_HURT"] = 32] = "TRIGGER_HURT";
|
|
3876
|
+
DamageMod2[DamageMod2["HIT"] = 33] = "HIT";
|
|
3877
|
+
DamageMod2[DamageMod2["TARGET_BLASTER"] = 34] = "TARGET_BLASTER";
|
|
3878
|
+
DamageMod2[DamageMod2["RIPPER"] = 35] = "RIPPER";
|
|
3879
|
+
DamageMod2[DamageMod2["PHALANX"] = 36] = "PHALANX";
|
|
3880
|
+
DamageMod2[DamageMod2["BRAINTENTACLE"] = 37] = "BRAINTENTACLE";
|
|
3881
|
+
DamageMod2[DamageMod2["BLASTOFF"] = 38] = "BLASTOFF";
|
|
3882
|
+
DamageMod2[DamageMod2["GEKK"] = 39] = "GEKK";
|
|
3883
|
+
DamageMod2[DamageMod2["TRAP"] = 40] = "TRAP";
|
|
3884
|
+
DamageMod2[DamageMod2["CHAINFIST"] = 41] = "CHAINFIST";
|
|
3885
|
+
DamageMod2[DamageMod2["DISINTEGRATOR"] = 42] = "DISINTEGRATOR";
|
|
3886
|
+
DamageMod2[DamageMod2["ETF_RIFLE"] = 43] = "ETF_RIFLE";
|
|
3887
|
+
DamageMod2[DamageMod2["BLASTER2"] = 44] = "BLASTER2";
|
|
3888
|
+
DamageMod2[DamageMod2["HEATBEAM"] = 45] = "HEATBEAM";
|
|
3889
|
+
DamageMod2[DamageMod2["TESLA"] = 46] = "TESLA";
|
|
3890
|
+
DamageMod2[DamageMod2["PROX"] = 47] = "PROX";
|
|
3891
|
+
DamageMod2[DamageMod2["NUKE"] = 48] = "NUKE";
|
|
3892
|
+
DamageMod2[DamageMod2["VENGEANCE_SPHERE"] = 49] = "VENGEANCE_SPHERE";
|
|
3893
|
+
DamageMod2[DamageMod2["HUNTER_SPHERE"] = 50] = "HUNTER_SPHERE";
|
|
3894
|
+
DamageMod2[DamageMod2["DEFENDER_SPHERE"] = 51] = "DEFENDER_SPHERE";
|
|
3895
|
+
DamageMod2[DamageMod2["TRACKER"] = 52] = "TRACKER";
|
|
3896
|
+
DamageMod2[DamageMod2["DBALL_CRUSH"] = 53] = "DBALL_CRUSH";
|
|
3897
|
+
DamageMod2[DamageMod2["DOPPLE_EXPLODE"] = 54] = "DOPPLE_EXPLODE";
|
|
3898
|
+
DamageMod2[DamageMod2["DOPPLE_VENGEANCE"] = 55] = "DOPPLE_VENGEANCE";
|
|
3899
|
+
DamageMod2[DamageMod2["DOPPLE_HUNTER"] = 56] = "DOPPLE_HUNTER";
|
|
3900
|
+
DamageMod2[DamageMod2["GRAPPLE"] = 57] = "GRAPPLE";
|
|
3901
|
+
DamageMod2[DamageMod2["BLUEBLASTER"] = 58] = "BLUEBLASTER";
|
|
3902
|
+
return DamageMod2;
|
|
3903
|
+
})(DamageMod || {});
|
|
3904
|
+
var ORDERED_DAMAGE_MODS = [
|
|
3905
|
+
0 /* UNKNOWN */,
|
|
3906
|
+
1 /* BLASTER */,
|
|
3907
|
+
2 /* SHOTGUN */,
|
|
3908
|
+
3 /* SSHOTGUN */,
|
|
3909
|
+
4 /* MACHINEGUN */,
|
|
3910
|
+
5 /* CHAINGUN */,
|
|
3911
|
+
6 /* GRENADE */,
|
|
3912
|
+
7 /* G_SPLASH */,
|
|
3913
|
+
8 /* ROCKET */,
|
|
3914
|
+
9 /* R_SPLASH */,
|
|
3915
|
+
10 /* HYPERBLASTER */,
|
|
3916
|
+
11 /* RAILGUN */,
|
|
3917
|
+
12 /* BFG_LASER */,
|
|
3918
|
+
13 /* BFG_BLAST */,
|
|
3919
|
+
14 /* BFG_EFFECT */,
|
|
3920
|
+
15 /* HANDGRENADE */,
|
|
3921
|
+
16 /* HG_SPLASH */,
|
|
3922
|
+
17 /* WATER */,
|
|
3923
|
+
18 /* SLIME */,
|
|
3924
|
+
19 /* LAVA */,
|
|
3925
|
+
20 /* CRUSH */,
|
|
3926
|
+
21 /* TELEFRAG */,
|
|
3927
|
+
22 /* TELEFRAG_SPAWN */,
|
|
3928
|
+
23 /* FALLING */,
|
|
3929
|
+
24 /* SUICIDE */,
|
|
3930
|
+
25 /* HELD_GRENADE */,
|
|
3931
|
+
26 /* EXPLOSIVE */,
|
|
3932
|
+
27 /* BARREL */,
|
|
3933
|
+
28 /* BOMB */,
|
|
3934
|
+
29 /* EXIT */,
|
|
3935
|
+
30 /* SPLASH */,
|
|
3936
|
+
31 /* TARGET_LASER */,
|
|
3937
|
+
32 /* TRIGGER_HURT */,
|
|
3938
|
+
33 /* HIT */,
|
|
3939
|
+
34 /* TARGET_BLASTER */,
|
|
3940
|
+
35 /* RIPPER */,
|
|
3941
|
+
36 /* PHALANX */,
|
|
3942
|
+
37 /* BRAINTENTACLE */,
|
|
3943
|
+
38 /* BLASTOFF */,
|
|
3944
|
+
39 /* GEKK */,
|
|
3945
|
+
40 /* TRAP */,
|
|
3946
|
+
41 /* CHAINFIST */,
|
|
3947
|
+
42 /* DISINTEGRATOR */,
|
|
3948
|
+
43 /* ETF_RIFLE */,
|
|
3949
|
+
44 /* BLASTER2 */,
|
|
3950
|
+
45 /* HEATBEAM */,
|
|
3951
|
+
46 /* TESLA */,
|
|
3952
|
+
47 /* PROX */,
|
|
3953
|
+
48 /* NUKE */,
|
|
3954
|
+
49 /* VENGEANCE_SPHERE */,
|
|
3955
|
+
50 /* HUNTER_SPHERE */,
|
|
3956
|
+
51 /* DEFENDER_SPHERE */,
|
|
3957
|
+
52 /* TRACKER */,
|
|
3958
|
+
53 /* DBALL_CRUSH */,
|
|
3959
|
+
54 /* DOPPLE_EXPLODE */,
|
|
3960
|
+
55 /* DOPPLE_VENGEANCE */,
|
|
3961
|
+
56 /* DOPPLE_HUNTER */,
|
|
3962
|
+
57 /* GRAPPLE */,
|
|
3963
|
+
58 /* BLUEBLASTER */
|
|
3964
|
+
];
|
|
3965
|
+
function damageModName(mod) {
|
|
3966
|
+
return `MOD_${DamageMod[mod]}`;
|
|
3967
|
+
}
|
|
3968
|
+
|
|
3969
|
+
// src/combat/damage.ts
|
|
3970
|
+
var EntityDamageFlags = /* @__PURE__ */ ((EntityDamageFlags2) => {
|
|
3971
|
+
EntityDamageFlags2[EntityDamageFlags2["GODMODE"] = 1] = "GODMODE";
|
|
3972
|
+
EntityDamageFlags2[EntityDamageFlags2["IMMORTAL"] = 2] = "IMMORTAL";
|
|
3973
|
+
EntityDamageFlags2[EntityDamageFlags2["NO_KNOCKBACK"] = 4] = "NO_KNOCKBACK";
|
|
3974
|
+
EntityDamageFlags2[EntityDamageFlags2["NO_DAMAGE_EFFECTS"] = 8] = "NO_DAMAGE_EFFECTS";
|
|
3975
|
+
return EntityDamageFlags2;
|
|
3976
|
+
})(EntityDamageFlags || {});
|
|
3977
|
+
function applyKnockback(targ, attacker, dir, knockback, dflags) {
|
|
3978
|
+
const hasNoKnockback = hasAnyDamageFlag(dflags, 8 /* NO_KNOCKBACK */) || ((targ.flags ?? 0) & 4 /* NO_KNOCKBACK */) !== 0;
|
|
3979
|
+
if (hasNoKnockback || knockback === 0) {
|
|
3980
|
+
return { x: 0, y: 0, z: 0 };
|
|
3981
|
+
}
|
|
3982
|
+
const mass = Math.max(50, targ.mass ?? 200);
|
|
3983
|
+
const normalized = normalizeVec3(dir);
|
|
3984
|
+
const scale = attacker === targ ? 1600 : 500;
|
|
3985
|
+
const delta = scaleVec3(normalized, scale * knockback / mass);
|
|
3986
|
+
targ.velocity = addVec3(targ.velocity, delta);
|
|
3987
|
+
return delta;
|
|
3988
|
+
}
|
|
3989
|
+
function applyProtection(targ, point, normal, damage, dflags) {
|
|
3990
|
+
let take = damage;
|
|
3991
|
+
let psave = 0;
|
|
3992
|
+
let asave = 0;
|
|
3993
|
+
let remainingCells;
|
|
3994
|
+
let remainingArmor;
|
|
3995
|
+
if (targ.powerArmor) {
|
|
3996
|
+
const result = applyPowerArmor(damage, dflags, point, normal, targ.powerArmor);
|
|
3997
|
+
psave = result.saved;
|
|
3998
|
+
remainingCells = result.remainingCells;
|
|
3999
|
+
take -= psave;
|
|
4000
|
+
}
|
|
4001
|
+
if (targ.regularArmor) {
|
|
4002
|
+
const result = applyRegularArmor(take, dflags, targ.regularArmor);
|
|
4003
|
+
asave = result.saved;
|
|
4004
|
+
remainingArmor = result.remainingArmor;
|
|
4005
|
+
take -= asave;
|
|
4006
|
+
}
|
|
4007
|
+
return [Math.max(0, take), psave, asave, remainingCells, remainingArmor];
|
|
4008
|
+
}
|
|
4009
|
+
function targetCenter(ent) {
|
|
4010
|
+
if (ent.mins && ent.maxs) {
|
|
4011
|
+
return {
|
|
4012
|
+
x: ent.origin.x + (ent.mins.x + ent.maxs.x) * 0.5,
|
|
4013
|
+
y: ent.origin.y + (ent.mins.y + ent.maxs.y) * 0.5,
|
|
4014
|
+
z: ent.origin.z + (ent.mins.z + ent.maxs.z) * 0.5
|
|
4015
|
+
};
|
|
4016
|
+
}
|
|
4017
|
+
return ent.origin;
|
|
4018
|
+
}
|
|
4019
|
+
function T_Damage(targ, inflictor, attacker, dir, point, normal, damage, knockback, dflags, mod) {
|
|
4020
|
+
if (!targ.takedamage || damage <= 0) {
|
|
4021
|
+
return null;
|
|
4022
|
+
}
|
|
4023
|
+
const protectedByGod = !hasAnyDamageFlag(dflags, 32 /* NO_PROTECTION */) && ((targ.flags ?? 0) & 1 /* GODMODE */) !== 0;
|
|
4024
|
+
if (protectedByGod) {
|
|
4025
|
+
return {
|
|
4026
|
+
take: 0,
|
|
4027
|
+
psave: 0,
|
|
4028
|
+
asave: damage,
|
|
4029
|
+
knocked: { x: 0, y: 0, z: 0 },
|
|
4030
|
+
killed: false
|
|
4031
|
+
};
|
|
4032
|
+
}
|
|
4033
|
+
const knocked = applyKnockback(targ, attacker, dir, knockback, dflags);
|
|
4034
|
+
const [take, psave, asave, remainingCells, remainingArmor] = applyProtection(targ, point, normal, damage, dflags);
|
|
4035
|
+
if (targ.powerArmor && remainingCells !== void 0) {
|
|
4036
|
+
targ.powerArmor.cellCount = remainingCells;
|
|
4037
|
+
}
|
|
4038
|
+
if (targ.regularArmor) {
|
|
4039
|
+
targ.regularArmor.armorCount = remainingArmor ?? targ.regularArmor.armorCount;
|
|
4040
|
+
}
|
|
4041
|
+
let actualTake = take;
|
|
4042
|
+
if (actualTake > 0) {
|
|
4043
|
+
targ.health -= actualTake;
|
|
4044
|
+
}
|
|
4045
|
+
const killed = targ.health <= 0;
|
|
4046
|
+
if (killed) {
|
|
4047
|
+
if (targ.flags && targ.flags & 2 /* IMMORTAL */) {
|
|
4048
|
+
targ.health = Math.max(1, targ.health);
|
|
4049
|
+
} else if (targ.die) {
|
|
4050
|
+
targ.die(targ, inflictor, attacker, actualTake, point, mod);
|
|
4051
|
+
}
|
|
4052
|
+
} else if (actualTake > 0 && targ.pain) {
|
|
4053
|
+
targ.pain(targ, attacker, knockback, actualTake, mod);
|
|
4054
|
+
}
|
|
4055
|
+
return { take: actualTake, psave, asave, knocked, killed, remainingCells, remainingArmor };
|
|
4056
|
+
}
|
|
4057
|
+
function T_RadiusDamage(entities, inflictor, attacker, damage, ignore, radius, dflags, mod, options = {}) {
|
|
4058
|
+
const hits = [];
|
|
4059
|
+
const inflictorCenter = targetCenter(inflictor);
|
|
4060
|
+
const canDamage = options.canDamage ?? (() => true);
|
|
4061
|
+
for (const ent of entities) {
|
|
4062
|
+
if (ent === ignore || !ent.takedamage || !canDamage(ent, inflictor)) {
|
|
4063
|
+
continue;
|
|
4064
|
+
}
|
|
4065
|
+
const entCenter = ent.mins && ent.maxs ? closestPointToBox(inflictorCenter, addVec3(ent.origin, ent.mins), addVec3(ent.origin, ent.maxs)) : targetCenter(ent);
|
|
4066
|
+
const toTarget = subtractVec3(inflictorCenter, entCenter);
|
|
4067
|
+
const distance2 = lengthVec3(toTarget);
|
|
4068
|
+
if (radius > 0 && distance2 > radius) {
|
|
4069
|
+
continue;
|
|
4070
|
+
}
|
|
4071
|
+
const points = damage - 0.5 * distance2;
|
|
4072
|
+
if (points <= 0) {
|
|
4073
|
+
continue;
|
|
4074
|
+
}
|
|
4075
|
+
const adjustedDamage = ent === attacker ? points * 0.5 : points;
|
|
4076
|
+
const dir = normalizeVec3(subtractVec3(ent.origin, inflictorCenter));
|
|
4077
|
+
const result = T_Damage(ent, inflictor, attacker, dir, entCenter, dir, adjustedDamage, adjustedDamage, dflags | 1 /* RADIUS */, mod);
|
|
4078
|
+
hits.push({ target: ent, result, appliedDamage: adjustedDamage });
|
|
4079
|
+
}
|
|
4080
|
+
return hits;
|
|
4081
|
+
}
|
|
4082
|
+
|
|
4083
|
+
// src/entities/monsters/attack.ts
|
|
4084
|
+
function monster_fire_bullet(self, start, dir, damage, kick, hspread, vspread, flashtype, context, mod = 0 /* UNKNOWN */) {
|
|
4085
|
+
const end = addVec3(start, scaleVec3(dir, 8192));
|
|
4086
|
+
const tr = context.trace(start, null, null, end, self, 1 | 536870912);
|
|
4087
|
+
if (!tr.ent || tr.fraction === 1) {
|
|
4088
|
+
return;
|
|
4089
|
+
}
|
|
4090
|
+
T_Damage(
|
|
4091
|
+
tr.ent,
|
|
4092
|
+
self,
|
|
4093
|
+
self,
|
|
4094
|
+
dir,
|
|
4095
|
+
tr.endpos,
|
|
4096
|
+
tr.plane?.normal || ZERO_VEC3,
|
|
4097
|
+
damage,
|
|
4098
|
+
kick,
|
|
4099
|
+
16 /* BULLET */ | 2 /* NO_ARMOR */,
|
|
4100
|
+
// Usually monsters ignore armor? Or maybe not.
|
|
4101
|
+
mod
|
|
4102
|
+
);
|
|
4103
|
+
}
|
|
4104
|
+
|
|
4105
|
+
// src/entities/projectiles.ts
|
|
4106
|
+
function createGrenade(sys, owner, start, dir, damage, speed) {
|
|
4107
|
+
const grenade = sys.spawn();
|
|
4108
|
+
grenade.classname = "grenade";
|
|
4109
|
+
grenade.owner = owner;
|
|
4110
|
+
grenade.origin = { ...start };
|
|
4111
|
+
grenade.velocity = { x: dir.x * speed, y: dir.y * speed, z: dir.z * speed };
|
|
4112
|
+
grenade.movetype = 9 /* Bounce */;
|
|
4113
|
+
grenade.clipmask = 268566530;
|
|
4114
|
+
grenade.solid = 2 /* BoundingBox */;
|
|
4115
|
+
grenade.modelindex = sys.modelIndex("models/objects/grenade/tris.md2");
|
|
4116
|
+
grenade.mins = { x: -4, y: -4, z: -4 };
|
|
4117
|
+
grenade.maxs = { x: 4, y: 4, z: 4 };
|
|
4118
|
+
grenade.touch = (self, other, plane, surf) => {
|
|
4119
|
+
if (other === self.owner) {
|
|
4120
|
+
return;
|
|
4121
|
+
}
|
|
4122
|
+
if (other && other.takedamage) {
|
|
4123
|
+
T_Damage(
|
|
4124
|
+
other,
|
|
4125
|
+
self,
|
|
4126
|
+
self.owner,
|
|
4127
|
+
self.velocity,
|
|
4128
|
+
self.origin,
|
|
4129
|
+
plane ? plane.normal : ZERO_VEC3,
|
|
4130
|
+
damage,
|
|
4131
|
+
// Direct impact damage? Usually separate but let's assume it's part of it or handled by radius.
|
|
4132
|
+
// Actually G_Weapon.c Grenade_Touch calls Grenade_Explode which calls T_RadiusDamage.
|
|
4133
|
+
// It doesn't seem to do T_Damage separately?
|
|
4134
|
+
// Wait, if it hits a monster, it stops and explodes.
|
|
4135
|
+
0,
|
|
4136
|
+
0 /* NONE */,
|
|
4137
|
+
6 /* GRENADE */
|
|
4138
|
+
);
|
|
4139
|
+
const entities = sys.findByRadius(self.origin, 120);
|
|
4140
|
+
T_RadiusDamage(entities, self, self.owner, damage, self.owner, 120, 0 /* NONE */, 6 /* GRENADE */);
|
|
4141
|
+
sys.free(self);
|
|
4142
|
+
return;
|
|
4143
|
+
}
|
|
4144
|
+
};
|
|
4145
|
+
grenade.think = (self) => {
|
|
4146
|
+
const entities = sys.findByRadius(self.origin, 120);
|
|
4147
|
+
T_RadiusDamage(entities, self, self.owner, damage, self.owner, 120, 0 /* NONE */, 6 /* GRENADE */);
|
|
4148
|
+
sys.free(self);
|
|
4149
|
+
};
|
|
4150
|
+
sys.scheduleThink(grenade, sys.timeSeconds + 2.5);
|
|
4151
|
+
sys.finalizeSpawn(grenade);
|
|
4152
|
+
}
|
|
4153
|
+
|
|
4154
|
+
// src/entities/monsters/gunner.ts
|
|
4155
|
+
var MONSTER_TICK = 0.1;
|
|
4156
|
+
function monster_ai_stand(self, dist, context) {
|
|
4157
|
+
ai_stand(self, MONSTER_TICK);
|
|
4158
|
+
}
|
|
4159
|
+
function monster_ai_walk(self, dist, context) {
|
|
4160
|
+
ai_walk(self, dist, MONSTER_TICK, context);
|
|
4161
|
+
}
|
|
4162
|
+
function monster_ai_run(self, dist, context) {
|
|
4163
|
+
ai_run(self, dist, MONSTER_TICK);
|
|
4164
|
+
}
|
|
4165
|
+
function monster_ai_charge(self, dist, context) {
|
|
4166
|
+
ai_charge(self, dist, MONSTER_TICK);
|
|
4167
|
+
}
|
|
4168
|
+
var stand_move;
|
|
4169
|
+
var walk_move;
|
|
4170
|
+
var run_move;
|
|
4171
|
+
var attack_chain_move;
|
|
4172
|
+
var attack_grenade_move;
|
|
4173
|
+
function gunner_stand(self) {
|
|
4174
|
+
self.monsterinfo.current_move = stand_move;
|
|
4175
|
+
}
|
|
4176
|
+
function gunner_walk(self) {
|
|
4177
|
+
self.monsterinfo.current_move = walk_move;
|
|
4178
|
+
}
|
|
4179
|
+
function gunner_run(self) {
|
|
4180
|
+
if (self.enemy && self.enemy.health > 0) {
|
|
4181
|
+
self.monsterinfo.current_move = run_move;
|
|
4182
|
+
} else {
|
|
4183
|
+
self.monsterinfo.current_move = stand_move;
|
|
4184
|
+
}
|
|
4185
|
+
}
|
|
4186
|
+
function gunner_attack(self) {
|
|
4187
|
+
if (Math.random() > 0.5) {
|
|
4188
|
+
self.monsterinfo.current_move = attack_chain_move;
|
|
4189
|
+
} else {
|
|
4190
|
+
self.monsterinfo.current_move = attack_grenade_move;
|
|
4191
|
+
}
|
|
4192
|
+
}
|
|
4193
|
+
function gunner_fire_chain(self, context) {
|
|
4194
|
+
if (!self.enemy) return;
|
|
4195
|
+
const start = {
|
|
4196
|
+
x: self.origin.x,
|
|
4197
|
+
y: self.origin.y,
|
|
4198
|
+
z: self.origin.z + self.viewheight - 8
|
|
4199
|
+
};
|
|
4200
|
+
const forward = normalizeVec3(subtractVec3(self.enemy.origin, start));
|
|
4201
|
+
const damage = 10;
|
|
4202
|
+
const kick = 2;
|
|
4203
|
+
monster_fire_bullet(self, start, forward, damage, kick, 0, 0, 0, context, 5 /* CHAINGUN */);
|
|
4204
|
+
}
|
|
4205
|
+
function gunner_fire_grenade(self, context) {
|
|
4206
|
+
if (!self.enemy) return;
|
|
4207
|
+
const start = {
|
|
4208
|
+
x: self.origin.x,
|
|
4209
|
+
y: self.origin.y,
|
|
4210
|
+
z: self.origin.z + self.viewheight
|
|
4211
|
+
};
|
|
4212
|
+
const forward = normalizeVec3(subtractVec3(self.enemy.origin, start));
|
|
4213
|
+
const damage = 50;
|
|
4214
|
+
const speed = 600;
|
|
4215
|
+
createGrenade(context, self, start, forward, damage, speed);
|
|
4216
|
+
}
|
|
4217
|
+
var stand_frames = Array.from({ length: 30 }, () => ({
|
|
4218
|
+
ai: monster_ai_stand,
|
|
4219
|
+
dist: 0
|
|
4220
|
+
}));
|
|
4221
|
+
stand_move = {
|
|
4222
|
+
firstframe: 0,
|
|
4223
|
+
lastframe: 29,
|
|
4224
|
+
frames: stand_frames,
|
|
4225
|
+
endfunc: gunner_stand
|
|
4226
|
+
};
|
|
4227
|
+
var walk_frames = Array.from({ length: 40 }, () => ({
|
|
4228
|
+
ai: monster_ai_walk,
|
|
4229
|
+
dist: 2
|
|
4230
|
+
}));
|
|
4231
|
+
walk_move = {
|
|
4232
|
+
firstframe: 30,
|
|
4233
|
+
lastframe: 69,
|
|
4234
|
+
frames: walk_frames,
|
|
4235
|
+
endfunc: gunner_walk
|
|
4236
|
+
};
|
|
4237
|
+
var run_frames = Array.from({ length: 20 }, () => ({
|
|
4238
|
+
ai: monster_ai_run,
|
|
4239
|
+
dist: 10
|
|
4240
|
+
}));
|
|
4241
|
+
run_move = {
|
|
4242
|
+
firstframe: 70,
|
|
4243
|
+
lastframe: 89,
|
|
4244
|
+
frames: run_frames,
|
|
4245
|
+
endfunc: gunner_run
|
|
4246
|
+
};
|
|
4247
|
+
var attack_chain_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
4248
|
+
ai: monster_ai_charge,
|
|
4249
|
+
dist: 0,
|
|
4250
|
+
think: i >= 2 && i <= 8 ? gunner_fire_chain : null
|
|
4251
|
+
}));
|
|
4252
|
+
attack_chain_move = {
|
|
4253
|
+
firstframe: 90,
|
|
4254
|
+
lastframe: 99,
|
|
4255
|
+
frames: attack_chain_frames,
|
|
4256
|
+
endfunc: gunner_run
|
|
4257
|
+
};
|
|
4258
|
+
var attack_grenade_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
4259
|
+
ai: monster_ai_charge,
|
|
4260
|
+
dist: 0,
|
|
4261
|
+
think: i === 5 ? gunner_fire_grenade : null
|
|
4262
|
+
}));
|
|
4263
|
+
attack_grenade_move = {
|
|
4264
|
+
firstframe: 100,
|
|
4265
|
+
lastframe: 109,
|
|
4266
|
+
frames: attack_grenade_frames,
|
|
4267
|
+
endfunc: gunner_run
|
|
4268
|
+
};
|
|
4269
|
+
function SP_monster_gunner(self, context) {
|
|
4270
|
+
self.model = "models/monsters/gunner/tris.md2";
|
|
4271
|
+
self.mins = { x: -16, y: -16, z: -24 };
|
|
4272
|
+
self.maxs = { x: 16, y: 16, z: 32 };
|
|
4273
|
+
self.movetype = 5 /* Step */;
|
|
4274
|
+
self.solid = 2 /* BoundingBox */;
|
|
4275
|
+
self.health = 175;
|
|
4276
|
+
self.max_health = 175;
|
|
4277
|
+
self.mass = 200;
|
|
4278
|
+
self.pain = (self2, other, kick, damage) => {
|
|
4279
|
+
};
|
|
4280
|
+
self.die = (self2, inflictor, attacker, damage, point) => {
|
|
4281
|
+
self2.deadflag = 2 /* Dead */;
|
|
4282
|
+
self2.solid = 0 /* Not */;
|
|
4283
|
+
};
|
|
4284
|
+
self.monsterinfo.stand = gunner_stand;
|
|
4285
|
+
self.monsterinfo.walk = gunner_walk;
|
|
4286
|
+
self.monsterinfo.run = gunner_run;
|
|
4287
|
+
self.monsterinfo.attack = gunner_attack;
|
|
4288
|
+
self.think = monster_think;
|
|
4289
|
+
gunner_stand(self);
|
|
4290
|
+
self.nextthink = self.timestamp + MONSTER_TICK;
|
|
4291
|
+
}
|
|
4292
|
+
function registerGunnerSpawns(registry) {
|
|
4293
|
+
registry.register("monster_gunner", SP_monster_gunner);
|
|
4294
|
+
}
|
|
4295
|
+
|
|
4296
|
+
// src/entities/monsters/soldier.ts
|
|
4297
|
+
var MONSTER_TICK2 = 0.1;
|
|
4298
|
+
function monster_ai_stand2(self, dist, context) {
|
|
4299
|
+
ai_stand(self, MONSTER_TICK2);
|
|
4300
|
+
}
|
|
4301
|
+
function monster_ai_walk2(self, dist, context) {
|
|
4302
|
+
ai_walk(self, dist, MONSTER_TICK2, context);
|
|
4303
|
+
}
|
|
4304
|
+
function monster_ai_run2(self, dist, context) {
|
|
4305
|
+
ai_run(self, dist, MONSTER_TICK2);
|
|
4306
|
+
}
|
|
4307
|
+
function monster_ai_charge2(self, dist, context) {
|
|
4308
|
+
ai_charge(self, dist, MONSTER_TICK2);
|
|
4309
|
+
}
|
|
4310
|
+
var stand_move2;
|
|
4311
|
+
var walk_move2;
|
|
4312
|
+
var run_move2;
|
|
4313
|
+
var attack_move;
|
|
4314
|
+
function soldier_stand(self) {
|
|
4315
|
+
self.monsterinfo.current_move = stand_move2;
|
|
4316
|
+
}
|
|
4317
|
+
function soldier_walk(self) {
|
|
4318
|
+
self.monsterinfo.current_move = walk_move2;
|
|
4319
|
+
}
|
|
4320
|
+
function soldier_run(self) {
|
|
4321
|
+
if (self.enemy && self.enemy.health > 0) {
|
|
4322
|
+
self.monsterinfo.current_move = run_move2;
|
|
4323
|
+
} else {
|
|
4324
|
+
self.monsterinfo.current_move = stand_move2;
|
|
4325
|
+
}
|
|
4326
|
+
}
|
|
4327
|
+
function soldier_attack(self) {
|
|
4328
|
+
self.monsterinfo.current_move = attack_move;
|
|
4329
|
+
}
|
|
4330
|
+
function soldier_fire(self, context) {
|
|
4331
|
+
if (!self.enemy) return;
|
|
4332
|
+
const start = {
|
|
4333
|
+
x: self.origin.x,
|
|
4334
|
+
y: self.origin.y,
|
|
4335
|
+
z: self.origin.z + self.viewheight
|
|
4336
|
+
};
|
|
4337
|
+
const forward = normalizeVec3(subtractVec3(self.enemy.origin, start));
|
|
4338
|
+
const damage = 4;
|
|
4339
|
+
const kick = 4;
|
|
4340
|
+
monster_fire_bullet(self, start, forward, damage, kick, 0, 0, 0, context, 4 /* MACHINEGUN */);
|
|
4341
|
+
}
|
|
4342
|
+
var stand_frames2 = Array.from({ length: 30 }, () => ({
|
|
4343
|
+
ai: monster_ai_stand2,
|
|
4344
|
+
dist: 0
|
|
4345
|
+
}));
|
|
4346
|
+
stand_move2 = {
|
|
4347
|
+
firstframe: 0,
|
|
4348
|
+
lastframe: 29,
|
|
4349
|
+
frames: stand_frames2,
|
|
4350
|
+
endfunc: soldier_stand
|
|
4351
|
+
};
|
|
4352
|
+
var walk_frames2 = Array.from({ length: 40 }, () => ({
|
|
4353
|
+
ai: monster_ai_walk2,
|
|
4354
|
+
dist: 2
|
|
4355
|
+
}));
|
|
4356
|
+
walk_move2 = {
|
|
4357
|
+
firstframe: 30,
|
|
4358
|
+
lastframe: 69,
|
|
4359
|
+
frames: walk_frames2,
|
|
4360
|
+
endfunc: soldier_walk
|
|
4361
|
+
};
|
|
4362
|
+
var run_frames2 = Array.from({ length: 20 }, () => ({
|
|
4363
|
+
ai: monster_ai_run2,
|
|
4364
|
+
dist: 10
|
|
4365
|
+
}));
|
|
4366
|
+
run_move2 = {
|
|
4367
|
+
firstframe: 70,
|
|
4368
|
+
lastframe: 89,
|
|
4369
|
+
frames: run_frames2,
|
|
4370
|
+
endfunc: soldier_run
|
|
4371
|
+
};
|
|
4372
|
+
var attack_frames = Array.from({ length: 10 }, (_, i) => ({
|
|
4373
|
+
ai: monster_ai_charge2,
|
|
4374
|
+
dist: 0,
|
|
4375
|
+
think: i === 5 ? soldier_fire : null
|
|
4376
|
+
}));
|
|
4377
|
+
attack_move = {
|
|
4378
|
+
firstframe: 90,
|
|
4379
|
+
lastframe: 99,
|
|
4380
|
+
frames: attack_frames,
|
|
4381
|
+
endfunc: soldier_run
|
|
4382
|
+
};
|
|
4383
|
+
function SP_monster_soldier(self, context) {
|
|
4384
|
+
self.model = "models/monsters/soldier/tris.md2";
|
|
4385
|
+
self.mins = { x: -16, y: -16, z: -24 };
|
|
4386
|
+
self.maxs = { x: 16, y: 16, z: 32 };
|
|
4387
|
+
self.movetype = 5 /* Step */;
|
|
4388
|
+
self.solid = 2 /* BoundingBox */;
|
|
4389
|
+
self.health = 20;
|
|
4390
|
+
self.max_health = 20;
|
|
4391
|
+
self.mass = 100;
|
|
4392
|
+
self.pain = (self2, other, kick, damage) => {
|
|
4393
|
+
};
|
|
4394
|
+
self.die = (self2, inflictor, attacker, damage, point) => {
|
|
4395
|
+
self2.deadflag = 2 /* Dead */;
|
|
4396
|
+
self2.solid = 0 /* Not */;
|
|
4397
|
+
};
|
|
4398
|
+
self.monsterinfo.stand = soldier_stand;
|
|
4399
|
+
self.monsterinfo.walk = soldier_walk;
|
|
4400
|
+
self.monsterinfo.run = soldier_run;
|
|
4401
|
+
self.monsterinfo.attack = soldier_attack;
|
|
4402
|
+
self.think = monster_think;
|
|
4403
|
+
soldier_stand(self);
|
|
4404
|
+
self.nextthink = self.timestamp + MONSTER_TICK2;
|
|
4405
|
+
}
|
|
4406
|
+
function registerMonsterSpawns(registry) {
|
|
4407
|
+
registry.register("monster_soldier", SP_monster_soldier);
|
|
4408
|
+
}
|
|
4409
|
+
|
|
4410
|
+
// src/entities/spawn.ts
|
|
4411
|
+
var FIELD_LOOKUP = new Map(
|
|
4412
|
+
ENTITY_FIELD_METADATA.map((field) => [field.name, field])
|
|
4413
|
+
);
|
|
4414
|
+
function parseVec3(text) {
|
|
4415
|
+
const parts = text.trim().split(/\s+/);
|
|
4416
|
+
const [x = 0, y = 0, z = 0] = parts.map((part) => Number.parseFloat(part)).map((value) => Number.isNaN(value) ? 0 : value);
|
|
4417
|
+
return { x, y, z };
|
|
4418
|
+
}
|
|
4419
|
+
function parseBoolean(text) {
|
|
3905
4420
|
const normalized = text.trim().toLowerCase();
|
|
3906
4421
|
return normalized === "1" || normalized === "true" || normalized === "yes";
|
|
3907
4422
|
}
|
|
@@ -4107,6 +4622,7 @@ function registerDefaultSpawns(game, registry) {
|
|
|
4107
4622
|
registerPathSpawns(registry);
|
|
4108
4623
|
registerLightSpawns(registry);
|
|
4109
4624
|
registerMonsterSpawns(registry);
|
|
4625
|
+
registerGunnerSpawns(registry);
|
|
4110
4626
|
}
|
|
4111
4627
|
function createDefaultSpawnRegistry(game) {
|
|
4112
4628
|
const registry = new SpawnRegistry();
|
|
@@ -4973,248 +5489,6 @@ _SaveStorage.DEFAULT_STORE = "saves";
|
|
|
4973
5489
|
_SaveStorage.QUICK_SLOT = "quicksave";
|
|
4974
5490
|
var SaveStorage = _SaveStorage;
|
|
4975
5491
|
|
|
4976
|
-
// src/combat/damage.ts
|
|
4977
|
-
var EntityDamageFlags = /* @__PURE__ */ ((EntityDamageFlags2) => {
|
|
4978
|
-
EntityDamageFlags2[EntityDamageFlags2["GODMODE"] = 1] = "GODMODE";
|
|
4979
|
-
EntityDamageFlags2[EntityDamageFlags2["IMMORTAL"] = 2] = "IMMORTAL";
|
|
4980
|
-
EntityDamageFlags2[EntityDamageFlags2["NO_KNOCKBACK"] = 4] = "NO_KNOCKBACK";
|
|
4981
|
-
EntityDamageFlags2[EntityDamageFlags2["NO_DAMAGE_EFFECTS"] = 8] = "NO_DAMAGE_EFFECTS";
|
|
4982
|
-
return EntityDamageFlags2;
|
|
4983
|
-
})(EntityDamageFlags || {});
|
|
4984
|
-
function applyKnockback(targ, attacker, dir, knockback, dflags) {
|
|
4985
|
-
const hasNoKnockback = hasAnyDamageFlag(dflags, 8 /* NO_KNOCKBACK */) || ((targ.flags ?? 0) & 4 /* NO_KNOCKBACK */) !== 0;
|
|
4986
|
-
if (hasNoKnockback || knockback === 0) {
|
|
4987
|
-
return { x: 0, y: 0, z: 0 };
|
|
4988
|
-
}
|
|
4989
|
-
const mass = Math.max(50, targ.mass ?? 200);
|
|
4990
|
-
const normalized = normalizeVec3(dir);
|
|
4991
|
-
const scale = attacker === targ ? 1600 : 500;
|
|
4992
|
-
const delta = scaleVec3(normalized, scale * knockback / mass);
|
|
4993
|
-
targ.velocity = addVec3(targ.velocity, delta);
|
|
4994
|
-
return delta;
|
|
4995
|
-
}
|
|
4996
|
-
function applyProtection(targ, point, normal, damage, dflags) {
|
|
4997
|
-
let take = damage;
|
|
4998
|
-
let psave = 0;
|
|
4999
|
-
let asave = 0;
|
|
5000
|
-
let remainingCells;
|
|
5001
|
-
let remainingArmor;
|
|
5002
|
-
if (targ.powerArmor) {
|
|
5003
|
-
const result = applyPowerArmor(damage, dflags, point, normal, targ.powerArmor);
|
|
5004
|
-
psave = result.saved;
|
|
5005
|
-
remainingCells = result.remainingCells;
|
|
5006
|
-
take -= psave;
|
|
5007
|
-
}
|
|
5008
|
-
if (targ.regularArmor) {
|
|
5009
|
-
const result = applyRegularArmor(take, dflags, targ.regularArmor);
|
|
5010
|
-
asave = result.saved;
|
|
5011
|
-
remainingArmor = result.remainingArmor;
|
|
5012
|
-
take -= asave;
|
|
5013
|
-
}
|
|
5014
|
-
return [Math.max(0, take), psave, asave, remainingCells, remainingArmor];
|
|
5015
|
-
}
|
|
5016
|
-
function targetCenter(ent) {
|
|
5017
|
-
if (ent.mins && ent.maxs) {
|
|
5018
|
-
return {
|
|
5019
|
-
x: ent.origin.x + (ent.mins.x + ent.maxs.x) * 0.5,
|
|
5020
|
-
y: ent.origin.y + (ent.mins.y + ent.maxs.y) * 0.5,
|
|
5021
|
-
z: ent.origin.z + (ent.mins.z + ent.maxs.z) * 0.5
|
|
5022
|
-
};
|
|
5023
|
-
}
|
|
5024
|
-
return ent.origin;
|
|
5025
|
-
}
|
|
5026
|
-
function T_Damage(targ, inflictor, attacker, dir, point, normal, damage, knockback, dflags, mod) {
|
|
5027
|
-
if (!targ.takedamage || damage <= 0) {
|
|
5028
|
-
return null;
|
|
5029
|
-
}
|
|
5030
|
-
const protectedByGod = !hasAnyDamageFlag(dflags, 32 /* NO_PROTECTION */) && ((targ.flags ?? 0) & 1 /* GODMODE */) !== 0;
|
|
5031
|
-
if (protectedByGod) {
|
|
5032
|
-
return {
|
|
5033
|
-
take: 0,
|
|
5034
|
-
psave: 0,
|
|
5035
|
-
asave: damage,
|
|
5036
|
-
knocked: { x: 0, y: 0, z: 0 },
|
|
5037
|
-
killed: false
|
|
5038
|
-
};
|
|
5039
|
-
}
|
|
5040
|
-
const knocked = applyKnockback(targ, attacker, dir, knockback, dflags);
|
|
5041
|
-
const [take, psave, asave, remainingCells, remainingArmor] = applyProtection(targ, point, normal, damage, dflags);
|
|
5042
|
-
if (targ.powerArmor && remainingCells !== void 0) {
|
|
5043
|
-
targ.powerArmor.cellCount = remainingCells;
|
|
5044
|
-
}
|
|
5045
|
-
if (targ.regularArmor) {
|
|
5046
|
-
targ.regularArmor.armorCount = remainingArmor ?? targ.regularArmor.armorCount;
|
|
5047
|
-
}
|
|
5048
|
-
let actualTake = take;
|
|
5049
|
-
if (actualTake > 0) {
|
|
5050
|
-
targ.health -= actualTake;
|
|
5051
|
-
}
|
|
5052
|
-
const killed = targ.health <= 0;
|
|
5053
|
-
if (killed) {
|
|
5054
|
-
if (targ.flags && targ.flags & 2 /* IMMORTAL */) {
|
|
5055
|
-
targ.health = Math.max(1, targ.health);
|
|
5056
|
-
} else if (targ.die) {
|
|
5057
|
-
targ.die(targ, inflictor, attacker, actualTake, point, mod);
|
|
5058
|
-
}
|
|
5059
|
-
} else if (actualTake > 0 && targ.pain) {
|
|
5060
|
-
targ.pain(targ, attacker, knockback, actualTake, mod);
|
|
5061
|
-
}
|
|
5062
|
-
return { take: actualTake, psave, asave, knocked, killed, remainingCells, remainingArmor };
|
|
5063
|
-
}
|
|
5064
|
-
function T_RadiusDamage(entities, inflictor, attacker, damage, ignore, radius, dflags, mod, options = {}) {
|
|
5065
|
-
const hits = [];
|
|
5066
|
-
const inflictorCenter = targetCenter(inflictor);
|
|
5067
|
-
const canDamage = options.canDamage ?? (() => true);
|
|
5068
|
-
for (const ent of entities) {
|
|
5069
|
-
if (ent === ignore || !ent.takedamage || !canDamage(ent, inflictor)) {
|
|
5070
|
-
continue;
|
|
5071
|
-
}
|
|
5072
|
-
const entCenter = ent.mins && ent.maxs ? closestPointToBox(inflictorCenter, addVec3(ent.origin, ent.mins), addVec3(ent.origin, ent.maxs)) : targetCenter(ent);
|
|
5073
|
-
const toTarget = subtractVec3(inflictorCenter, entCenter);
|
|
5074
|
-
const distance2 = lengthVec3(toTarget);
|
|
5075
|
-
if (radius > 0 && distance2 > radius) {
|
|
5076
|
-
continue;
|
|
5077
|
-
}
|
|
5078
|
-
const points = damage - 0.5 * distance2;
|
|
5079
|
-
if (points <= 0) {
|
|
5080
|
-
continue;
|
|
5081
|
-
}
|
|
5082
|
-
const adjustedDamage = ent === attacker ? points * 0.5 : points;
|
|
5083
|
-
const dir = normalizeVec3(subtractVec3(ent.origin, inflictorCenter));
|
|
5084
|
-
const result = T_Damage(ent, inflictor, attacker, dir, entCenter, dir, adjustedDamage, adjustedDamage, dflags | 1 /* RADIUS */, mod);
|
|
5085
|
-
hits.push({ target: ent, result, appliedDamage: adjustedDamage });
|
|
5086
|
-
}
|
|
5087
|
-
return hits;
|
|
5088
|
-
}
|
|
5089
|
-
|
|
5090
|
-
// src/combat/damageMods.ts
|
|
5091
|
-
var DamageMod = /* @__PURE__ */ ((DamageMod2) => {
|
|
5092
|
-
DamageMod2[DamageMod2["UNKNOWN"] = 0] = "UNKNOWN";
|
|
5093
|
-
DamageMod2[DamageMod2["BLASTER"] = 1] = "BLASTER";
|
|
5094
|
-
DamageMod2[DamageMod2["SHOTGUN"] = 2] = "SHOTGUN";
|
|
5095
|
-
DamageMod2[DamageMod2["SSHOTGUN"] = 3] = "SSHOTGUN";
|
|
5096
|
-
DamageMod2[DamageMod2["MACHINEGUN"] = 4] = "MACHINEGUN";
|
|
5097
|
-
DamageMod2[DamageMod2["CHAINGUN"] = 5] = "CHAINGUN";
|
|
5098
|
-
DamageMod2[DamageMod2["GRENADE"] = 6] = "GRENADE";
|
|
5099
|
-
DamageMod2[DamageMod2["G_SPLASH"] = 7] = "G_SPLASH";
|
|
5100
|
-
DamageMod2[DamageMod2["ROCKET"] = 8] = "ROCKET";
|
|
5101
|
-
DamageMod2[DamageMod2["R_SPLASH"] = 9] = "R_SPLASH";
|
|
5102
|
-
DamageMod2[DamageMod2["HYPERBLASTER"] = 10] = "HYPERBLASTER";
|
|
5103
|
-
DamageMod2[DamageMod2["RAILGUN"] = 11] = "RAILGUN";
|
|
5104
|
-
DamageMod2[DamageMod2["BFG_LASER"] = 12] = "BFG_LASER";
|
|
5105
|
-
DamageMod2[DamageMod2["BFG_BLAST"] = 13] = "BFG_BLAST";
|
|
5106
|
-
DamageMod2[DamageMod2["BFG_EFFECT"] = 14] = "BFG_EFFECT";
|
|
5107
|
-
DamageMod2[DamageMod2["HANDGRENADE"] = 15] = "HANDGRENADE";
|
|
5108
|
-
DamageMod2[DamageMod2["HG_SPLASH"] = 16] = "HG_SPLASH";
|
|
5109
|
-
DamageMod2[DamageMod2["WATER"] = 17] = "WATER";
|
|
5110
|
-
DamageMod2[DamageMod2["SLIME"] = 18] = "SLIME";
|
|
5111
|
-
DamageMod2[DamageMod2["LAVA"] = 19] = "LAVA";
|
|
5112
|
-
DamageMod2[DamageMod2["CRUSH"] = 20] = "CRUSH";
|
|
5113
|
-
DamageMod2[DamageMod2["TELEFRAG"] = 21] = "TELEFRAG";
|
|
5114
|
-
DamageMod2[DamageMod2["TELEFRAG_SPAWN"] = 22] = "TELEFRAG_SPAWN";
|
|
5115
|
-
DamageMod2[DamageMod2["FALLING"] = 23] = "FALLING";
|
|
5116
|
-
DamageMod2[DamageMod2["SUICIDE"] = 24] = "SUICIDE";
|
|
5117
|
-
DamageMod2[DamageMod2["HELD_GRENADE"] = 25] = "HELD_GRENADE";
|
|
5118
|
-
DamageMod2[DamageMod2["EXPLOSIVE"] = 26] = "EXPLOSIVE";
|
|
5119
|
-
DamageMod2[DamageMod2["BARREL"] = 27] = "BARREL";
|
|
5120
|
-
DamageMod2[DamageMod2["BOMB"] = 28] = "BOMB";
|
|
5121
|
-
DamageMod2[DamageMod2["EXIT"] = 29] = "EXIT";
|
|
5122
|
-
DamageMod2[DamageMod2["SPLASH"] = 30] = "SPLASH";
|
|
5123
|
-
DamageMod2[DamageMod2["TARGET_LASER"] = 31] = "TARGET_LASER";
|
|
5124
|
-
DamageMod2[DamageMod2["TRIGGER_HURT"] = 32] = "TRIGGER_HURT";
|
|
5125
|
-
DamageMod2[DamageMod2["HIT"] = 33] = "HIT";
|
|
5126
|
-
DamageMod2[DamageMod2["TARGET_BLASTER"] = 34] = "TARGET_BLASTER";
|
|
5127
|
-
DamageMod2[DamageMod2["RIPPER"] = 35] = "RIPPER";
|
|
5128
|
-
DamageMod2[DamageMod2["PHALANX"] = 36] = "PHALANX";
|
|
5129
|
-
DamageMod2[DamageMod2["BRAINTENTACLE"] = 37] = "BRAINTENTACLE";
|
|
5130
|
-
DamageMod2[DamageMod2["BLASTOFF"] = 38] = "BLASTOFF";
|
|
5131
|
-
DamageMod2[DamageMod2["GEKK"] = 39] = "GEKK";
|
|
5132
|
-
DamageMod2[DamageMod2["TRAP"] = 40] = "TRAP";
|
|
5133
|
-
DamageMod2[DamageMod2["CHAINFIST"] = 41] = "CHAINFIST";
|
|
5134
|
-
DamageMod2[DamageMod2["DISINTEGRATOR"] = 42] = "DISINTEGRATOR";
|
|
5135
|
-
DamageMod2[DamageMod2["ETF_RIFLE"] = 43] = "ETF_RIFLE";
|
|
5136
|
-
DamageMod2[DamageMod2["BLASTER2"] = 44] = "BLASTER2";
|
|
5137
|
-
DamageMod2[DamageMod2["HEATBEAM"] = 45] = "HEATBEAM";
|
|
5138
|
-
DamageMod2[DamageMod2["TESLA"] = 46] = "TESLA";
|
|
5139
|
-
DamageMod2[DamageMod2["PROX"] = 47] = "PROX";
|
|
5140
|
-
DamageMod2[DamageMod2["NUKE"] = 48] = "NUKE";
|
|
5141
|
-
DamageMod2[DamageMod2["VENGEANCE_SPHERE"] = 49] = "VENGEANCE_SPHERE";
|
|
5142
|
-
DamageMod2[DamageMod2["HUNTER_SPHERE"] = 50] = "HUNTER_SPHERE";
|
|
5143
|
-
DamageMod2[DamageMod2["DEFENDER_SPHERE"] = 51] = "DEFENDER_SPHERE";
|
|
5144
|
-
DamageMod2[DamageMod2["TRACKER"] = 52] = "TRACKER";
|
|
5145
|
-
DamageMod2[DamageMod2["DBALL_CRUSH"] = 53] = "DBALL_CRUSH";
|
|
5146
|
-
DamageMod2[DamageMod2["DOPPLE_EXPLODE"] = 54] = "DOPPLE_EXPLODE";
|
|
5147
|
-
DamageMod2[DamageMod2["DOPPLE_VENGEANCE"] = 55] = "DOPPLE_VENGEANCE";
|
|
5148
|
-
DamageMod2[DamageMod2["DOPPLE_HUNTER"] = 56] = "DOPPLE_HUNTER";
|
|
5149
|
-
DamageMod2[DamageMod2["GRAPPLE"] = 57] = "GRAPPLE";
|
|
5150
|
-
DamageMod2[DamageMod2["BLUEBLASTER"] = 58] = "BLUEBLASTER";
|
|
5151
|
-
return DamageMod2;
|
|
5152
|
-
})(DamageMod || {});
|
|
5153
|
-
var ORDERED_DAMAGE_MODS = [
|
|
5154
|
-
0 /* UNKNOWN */,
|
|
5155
|
-
1 /* BLASTER */,
|
|
5156
|
-
2 /* SHOTGUN */,
|
|
5157
|
-
3 /* SSHOTGUN */,
|
|
5158
|
-
4 /* MACHINEGUN */,
|
|
5159
|
-
5 /* CHAINGUN */,
|
|
5160
|
-
6 /* GRENADE */,
|
|
5161
|
-
7 /* G_SPLASH */,
|
|
5162
|
-
8 /* ROCKET */,
|
|
5163
|
-
9 /* R_SPLASH */,
|
|
5164
|
-
10 /* HYPERBLASTER */,
|
|
5165
|
-
11 /* RAILGUN */,
|
|
5166
|
-
12 /* BFG_LASER */,
|
|
5167
|
-
13 /* BFG_BLAST */,
|
|
5168
|
-
14 /* BFG_EFFECT */,
|
|
5169
|
-
15 /* HANDGRENADE */,
|
|
5170
|
-
16 /* HG_SPLASH */,
|
|
5171
|
-
17 /* WATER */,
|
|
5172
|
-
18 /* SLIME */,
|
|
5173
|
-
19 /* LAVA */,
|
|
5174
|
-
20 /* CRUSH */,
|
|
5175
|
-
21 /* TELEFRAG */,
|
|
5176
|
-
22 /* TELEFRAG_SPAWN */,
|
|
5177
|
-
23 /* FALLING */,
|
|
5178
|
-
24 /* SUICIDE */,
|
|
5179
|
-
25 /* HELD_GRENADE */,
|
|
5180
|
-
26 /* EXPLOSIVE */,
|
|
5181
|
-
27 /* BARREL */,
|
|
5182
|
-
28 /* BOMB */,
|
|
5183
|
-
29 /* EXIT */,
|
|
5184
|
-
30 /* SPLASH */,
|
|
5185
|
-
31 /* TARGET_LASER */,
|
|
5186
|
-
32 /* TRIGGER_HURT */,
|
|
5187
|
-
33 /* HIT */,
|
|
5188
|
-
34 /* TARGET_BLASTER */,
|
|
5189
|
-
35 /* RIPPER */,
|
|
5190
|
-
36 /* PHALANX */,
|
|
5191
|
-
37 /* BRAINTENTACLE */,
|
|
5192
|
-
38 /* BLASTOFF */,
|
|
5193
|
-
39 /* GEKK */,
|
|
5194
|
-
40 /* TRAP */,
|
|
5195
|
-
41 /* CHAINFIST */,
|
|
5196
|
-
42 /* DISINTEGRATOR */,
|
|
5197
|
-
43 /* ETF_RIFLE */,
|
|
5198
|
-
44 /* BLASTER2 */,
|
|
5199
|
-
45 /* HEATBEAM */,
|
|
5200
|
-
46 /* TESLA */,
|
|
5201
|
-
47 /* PROX */,
|
|
5202
|
-
48 /* NUKE */,
|
|
5203
|
-
49 /* VENGEANCE_SPHERE */,
|
|
5204
|
-
50 /* HUNTER_SPHERE */,
|
|
5205
|
-
51 /* DEFENDER_SPHERE */,
|
|
5206
|
-
52 /* TRACKER */,
|
|
5207
|
-
53 /* DBALL_CRUSH */,
|
|
5208
|
-
54 /* DOPPLE_EXPLODE */,
|
|
5209
|
-
55 /* DOPPLE_VENGEANCE */,
|
|
5210
|
-
56 /* DOPPLE_HUNTER */,
|
|
5211
|
-
57 /* GRAPPLE */,
|
|
5212
|
-
58 /* BLUEBLASTER */
|
|
5213
|
-
];
|
|
5214
|
-
function damageModName(mod) {
|
|
5215
|
-
return `MOD_${DamageMod[mod]}`;
|
|
5216
|
-
}
|
|
5217
|
-
|
|
5218
5492
|
// src/combat/specialDamage.ts
|
|
5219
5493
|
var ZERO2 = { x: 0, y: 0, z: 0 };
|
|
5220
5494
|
var EnvironmentalFlags = /* @__PURE__ */ ((EnvironmentalFlags2) => {
|
|
@@ -5692,12 +5966,17 @@ export {
|
|
|
5692
5966
|
convertRereleaseLevelToGameSave,
|
|
5693
5967
|
convertRereleaseSaveToGameSave,
|
|
5694
5968
|
createAmmoInventory,
|
|
5969
|
+
createAmmoPickupEntity,
|
|
5970
|
+
createArmorPickupEntity,
|
|
5695
5971
|
createBaseAmmoCaps,
|
|
5696
5972
|
createCallbackRegistry,
|
|
5697
5973
|
createDefaultSpawnRegistry,
|
|
5698
5974
|
createGame,
|
|
5975
|
+
createHealthPickupEntity,
|
|
5976
|
+
createKeyPickupEntity,
|
|
5699
5977
|
createPlayerInventory,
|
|
5700
5978
|
createPlayerWeaponStates,
|
|
5979
|
+
createPowerupPickupEntity,
|
|
5701
5980
|
createSaveFile,
|
|
5702
5981
|
createWeaponPickupEntity,
|
|
5703
5982
|
damageModName,
|