1
0
Fork 0

Multiple healths as shields

This commit is contained in:
Pabloader 2026-05-09 18:27:35 +00:00
parent e1ba738ea0
commit 9a1fb9b655
2 changed files with 38 additions and 6 deletions

View File

@ -65,7 +65,10 @@ export class Stat<T = {}> extends Component<StatState & T> {
}
@component
export class Health extends Stat {
export class Health extends Stat<{ damageTypes?: string[]; priority?: number }> {
get damageTypes(): readonly string[] { return this.state.damageTypes ?? []; }
get priority(): number { return this.state.priority ?? 0; }
@action
kill() {
this.set(0);

View File

@ -18,8 +18,8 @@ export class CombatSystem extends System {
let random: Random | undefined;
for (const [target] of world.query(Attacked)) {
const health = target.get(Health);
if (!health) {
const healths = target.getAll(Health).sort((a, b) => b.priority - a.priority);
if (healths.length === 0) {
console.warn(`[CombatSystem] Target ${target.id} has no Health component`);
for (const attack of target.getAll(Attacked)) target.remove(attack);
continue;
@ -116,14 +116,43 @@ export class CombatSystem extends System {
if (damageSum === 0) continue;
const wasAlive = health.value > 0;
health.update(-damageSum);
let totalBefore = 0;
for (const pool of healths) totalBefore += pool.value;
for (const hit of hitEvents) {
let remaining = hit.amount;
if (hit.damageType) {
for (const pool of healths) {
if (remaining <= 0) break;
if (pool.value <= 0) continue;
if (!pool.damageTypes.includes(hit.damageType)) continue;
const take = Math.min(pool.value, remaining);
pool.update(-take);
remaining -= take;
}
}
if (remaining > 0) {
for (const pool of healths) {
if (remaining <= 0) break;
if (pool.value <= 0) continue;
if (pool.damageTypes.length > 0) continue;
const take = Math.min(pool.value, remaining);
pool.update(-take);
remaining -= take;
}
}
}
for (const info of hitEvents) {
target.emit('Combat.hit', info);
}
if (wasAlive && health.value <= 0 && lastHit) {
let totalAfter = 0;
for (const pool of healths) totalAfter += pool.value;
if (totalBefore > 0 && totalAfter <= 0 && lastHit) {
target.emit('Combat.killed', lastHit);
}
}