refactor: rename "rupture" to "wound" and "sanctify" to "cleanse"

- Renamed skill name from rupture → wound throughout data/skills.json and data/cards.json (120+ occurrences)
- Updated all related logic in CombatEngine.js and SkillProcessor.js:
  * Phase renamed _rupturePhase → _woundPhase, event types updated
  * Tracker renamed ruptureTracker → woundTracker
  * Card property ruptureStacks → woundStacks
- Renamed skill name from sanctify → cleanse, changed trigger to postBattle and removed all-target support (now always cleanses all allies)
- Updated visual assets: badge text, sound keys (sfx_rupture → sfx_wound, sfx_sanctify → sfx_cleanse), status messages
- Adjusted strike skill values in cards.json (5→8, 7→14, 10→20, 15→30)
This commit is contained in:
Brian Fertig 2026-03-28 09:41:49 -06:00
parent 2ea8857f91
commit 2cfba2a893
8 changed files with 282 additions and 301 deletions

View File

@ -2233,7 +2233,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 2,
"trigger": "on_attack"
}
@ -2252,7 +2252,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 4,
"trigger": "on_attack"
}
@ -2271,7 +2271,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 6,
"trigger": "on_attack"
}
@ -2290,7 +2290,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 9,
"trigger": "on_attack"
}
@ -2309,7 +2309,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 13,
"trigger": "on_attack"
}
@ -3072,7 +3072,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 1,
"trigger": "on_attack"
}
@ -3090,7 +3090,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 2,
"trigger": "on_attack"
}
@ -3108,7 +3108,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 2,
"trigger": "on_attack"
}
@ -3126,7 +3126,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 3,
"trigger": "on_attack"
}
@ -3144,7 +3144,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 5,
"trigger": "on_attack"
}
@ -3456,7 +3456,7 @@
"trigger": "passive"
},
{
"name": "rupture",
"name": "wound",
"value": 2,
"trigger": "on_attack"
}
@ -3474,7 +3474,7 @@
"trigger": "passive"
},
{
"name": "rupture",
"name": "wound",
"value": 3,
"trigger": "on_attack"
}
@ -3492,7 +3492,7 @@
"trigger": "passive"
},
{
"name": "rupture",
"name": "wound",
"value": 5,
"trigger": "on_attack"
}
@ -3510,7 +3510,7 @@
"trigger": "passive"
},
{
"name": "rupture",
"name": "wound",
"value": 7,
"trigger": "on_attack"
}
@ -3528,7 +3528,7 @@
"trigger": "passive"
},
{
"name": "rupture",
"name": "wound",
"value": 10,
"trigger": "on_attack"
}
@ -3658,7 +3658,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 3,
"trigger": "on_attack"
}
@ -3676,7 +3676,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 5,
"trigger": "on_attack"
}
@ -3694,7 +3694,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 8,
"trigger": "on_attack"
}
@ -3712,7 +3712,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 11,
"trigger": "on_attack"
}
@ -3730,7 +3730,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 15,
"trigger": "on_attack"
}
@ -4583,7 +4583,7 @@
"delay": 0,
"skills": [
{
"name": "rupture",
"name": "wound",
"value": 1,
"trigger": "on_attack"
}
@ -4596,7 +4596,7 @@
"delay": 0,
"skills": [
{
"name": "rupture",
"name": "wound",
"value": 2,
"trigger": "on_attack"
}
@ -4609,7 +4609,7 @@
"delay": 0,
"skills": [
{
"name": "rupture",
"name": "wound",
"value": 3,
"trigger": "on_attack"
}
@ -4622,7 +4622,7 @@
"delay": 0,
"skills": [
{
"name": "rupture",
"name": "wound",
"value": 4,
"trigger": "on_attack"
}
@ -4635,7 +4635,7 @@
"delay": 0,
"skills": [
{
"name": "rupture",
"name": "wound",
"value": 5,
"trigger": "on_attack"
}
@ -5068,7 +5068,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 2,
"trigger": "on_attack"
}
@ -5086,7 +5086,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 3,
"trigger": "on_attack"
}
@ -5104,7 +5104,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 6,
"trigger": "on_attack"
}
@ -5122,7 +5122,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 10,
"trigger": "on_attack"
}
@ -5140,7 +5140,7 @@
"trigger": "preBattle"
},
{
"name": "rupture",
"name": "wound",
"value": 15,
"trigger": "on_attack"
}
@ -5472,7 +5472,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 2,
"trigger": "on_attack"
}
@ -5490,7 +5490,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 3,
"trigger": "on_attack"
}
@ -5508,7 +5508,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 5,
"trigger": "on_attack"
}
@ -5526,7 +5526,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 7,
"trigger": "on_attack"
}
@ -5544,7 +5544,7 @@
"trigger": "preAttack"
},
{
"name": "rupture",
"name": "wound",
"value": 10,
"trigger": "on_attack"
}
@ -7831,10 +7831,9 @@
"delay": 0,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 1,
"all": true,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -7845,10 +7844,9 @@
"delay": 0,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 2,
"all": true,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -7859,10 +7857,9 @@
"delay": 0,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 3,
"all": true,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -7873,10 +7870,9 @@
"delay": 0,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 5,
"all": true,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -7887,10 +7883,9 @@
"delay": 0,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 7,
"all": true,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
}
@ -9030,9 +9025,9 @@
"delay": 2,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 1,
"trigger": "preBattle"
"trigger": "postBattle"
},
{
"name": "strike",
@ -9048,9 +9043,9 @@
"delay": 2,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 2,
"trigger": "preBattle"
"trigger": "postBattle"
},
{
"name": "strike",
@ -9066,9 +9061,9 @@
"delay": 2,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 3,
"trigger": "preBattle"
"trigger": "postBattle"
},
{
"name": "strike",
@ -9084,9 +9079,9 @@
"delay": 2,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 5,
"trigger": "preBattle"
"trigger": "postBattle"
},
{
"name": "strike",
@ -9102,9 +9097,9 @@
"delay": 2,
"skills": [
{
"name": "sanctify",
"name": "cleanse",
"value": 7,
"trigger": "preBattle"
"trigger": "postBattle"
},
{
"name": "strike",
@ -9343,9 +9338,9 @@
"trigger": "on_attack"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 1,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9366,9 +9361,9 @@
"trigger": "on_attack"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 2,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9389,9 +9384,9 @@
"trigger": "on_attack"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 3,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9412,9 +9407,9 @@
"trigger": "on_attack"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 5,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9435,9 +9430,9 @@
"trigger": "on_attack"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 7,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
}
@ -9493,7 +9488,7 @@
},
{
"name": "strike",
"value": 5,
"value": 8,
"trigger": "preAttack"
}
]
@ -9516,7 +9511,7 @@
},
{
"name": "strike",
"value": 7,
"value": 14,
"trigger": "preAttack"
}
]
@ -9539,7 +9534,7 @@
},
{
"name": "strike",
"value": 10,
"value": 20,
"trigger": "preAttack"
}
]
@ -9562,7 +9557,7 @@
},
{
"name": "strike",
"value": 15,
"value": 30,
"trigger": "preAttack"
}
]
@ -9596,9 +9591,9 @@
"trigger": "preBattle"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 1,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9620,9 +9615,9 @@
"trigger": "preBattle"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 2,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9644,9 +9639,9 @@
"trigger": "preBattle"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 3,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9668,9 +9663,9 @@
"trigger": "preBattle"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 5,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
},
@ -9692,9 +9687,9 @@
"trigger": "preBattle"
},
{
"name": "sanctify",
"name": "cleanse",
"value": 7,
"trigger": "preBattle"
"trigger": "postBattle"
}
]
}

View File

@ -22,9 +22,9 @@
"supportsAll": true
},
{
"name": "rupture",
"description": "Apply rupture stacks to target. Each stack deals value damage at the start of the turn.",
"allDescription": "Apply rupture stacks to ALL enemy cards. Each stack deals value damage at the start of the turn.",
"name": "wound",
"description": "Apply wound stacks to target. Each stack deals value damage at the start of the turn.",
"allDescription": "Apply wound stacks to ALL enemy cards. Each stack deals value damage at the start of the turn.",
"trigger": "on_attack",
"category": "offense",
"supportsAll": true
@ -210,8 +210,8 @@
"category": "offense"
},
{
"name": "sanctify",
"description": "Before battle: cleanse all negative effects (venom, smite, enfeeble, jam, rupture) from self.",
"name": "cleanse",
"description": "Before battle: cleanse all negative effects (venom, smite, enfeeble, jam, wound) from self.",
"allDescription": "Before battle: cleanse all negative effects from ALL allied cards.",
"trigger": "preBattle",
"category": "support",

View File

@ -71,28 +71,28 @@ export class CombatEngine {
tick(this.opponentLanes);
}
// Apply rupture damage to all cards, emitting ruptureTick events (mirrors venomPhase)
_rupturePhase() {
const applyRupture = (cards, alliedLanes, side) => {
// Apply wound damage to all cards, emitting woundTick events (mirrors venomPhase)
_woundPhase() {
const applyWound = (cards, alliedLanes, side) => {
for (const c of cards) {
if (c.ruptureStacks > 0) {
const dmg = c.ruptureStacks;
if (c.woundStacks > 0) {
const dmg = c.woundStacks;
c.currentHP -= dmg;
this._log(`${c.name} takes ${dmg} rupture damage`);
this._log(`${c.name} takes ${dmg} wound damage`);
const killed = c.currentHP <= 0;
if (killed) {
this._log(`${c.name} is destroyed by rupture`);
this._log(`${c.name} is destroyed by wound`);
this.events.push({ type: 'death', card: c, side });
this._processOnDeath(c, alliedLanes, side);
}
this.events.push({ type: 'ruptureTick', card: c, damage: dmg, killed });
this.events.push({ type: 'woundTick', card: c, damage: dmg, killed });
this._tryCarapace(c, dmg);
c.ruptureStacks--;
c.woundStacks--;
}
}
};
applyRupture(this.playerLanes, this.playerLanes, 'player');
applyRupture(this.opponentLanes, this.opponentLanes, 'opponent');
applyWound(this.playerLanes, this.playerLanes, 'player');
applyWound(this.opponentLanes, this.opponentLanes, 'opponent');
}
// If the card has carapace and just took damage, apply armor gain (with cap).
@ -292,8 +292,8 @@ export class CombatEngine {
}
const extraAttacks = (context.extraAttacks || 0) + 1;
// Track rupture stacks applied this attack sequence so flurry can't stack beyond skill.value
context.ruptureTracker = { applied: 0 };
// Track wound stacks applied this attack sequence so flurry can't stack beyond skill.value
context.woundTracker = { applied: 0 };
for (let a = 0; a < extraAttacks; a++) {
// Skip a target that was already killed (e.g. by mortar during preAttack)
const currentTarget = (target && target.currentHP > 0) ? target : null;
@ -318,11 +318,11 @@ export class CombatEngine {
alliedLanes.filter(c => c.currentHP > 0),
enemyLanes.filter(c => c.currentHP > 0),
onAtkCtx);
if (onAtkCtx.ruptureAllTargets) {
this.events.push({ type: 'ruptureAll', attacker, targets: onAtkCtx.ruptureAllTargets, side });
if (onAtkCtx.woundAllTargets) {
this.events.push({ type: 'woundAll', attacker, targets: onAtkCtx.woundAllTargets, side });
}
if (onAtkCtx.ruptureTarget) {
this.events.push({ type: 'ruptureApply', attacker, target: onAtkCtx.ruptureTarget, stacks: onAtkCtx.ruptureStacks, side });
if (onAtkCtx.woundTarget) {
this.events.push({ type: 'woundApply', attacker, target: onAtkCtx.woundTarget, stacks: onAtkCtx.woundStacks, side });
}
if (onAtkCtx.weakenAllTargets) {
this.events.push({ type: 'weakenAll', attacker, targets: onAtkCtx.weakenAllTargets, side });
@ -479,7 +479,7 @@ export class CombatEngine {
for (const c of this.ai.hand) { if (c.currentDelay > 0) c.currentDelay--; }
this._commanderSkillPhase();
this._cardOnTurnStartPhase();
this._rupturePhase();
this._woundPhase();
this._venomPhase();
this._smitePhase();
this._moltPhase();
@ -526,7 +526,7 @@ export class CombatEngine {
this._commanderSkillPhase();
this._cardOnTurnStartPhase();
this._jamPhase();
this._preBattlePhase(); // _rupturePhase() and _venomPhase() are called first inside _preBattlePhase
this._preBattlePhase(); // _woundPhase() and _venomPhase() are called first inside _preBattlePhase
// NOTE: No _deathCheck() here — dead cards stay in lanes so the scene can
// animate their death during preBattle (e.g. drain kills). _buildPendingAttacks
// already skips dead cards via currentHP <= 0 checks. finalizeCommit() calls
@ -546,7 +546,6 @@ export class CombatEngine {
const weakenFires = [];
const drainFires = [];
const healFires = [];
const sanctifyFires = [];
const overchargeFires = [];
const fortifyFires = [];
const strikeFires = [];
@ -652,13 +651,6 @@ export class CombatEngine {
healFires.push({ skill: 'heal', source: card, target: ctx.healTarget, healAmount: ctx.healAmount, hpBefore: ctx.healHpBefore });
this._log(`${card.name} heal: restored ${ctx.healAmount} HP to ${ctx.healTarget.name}`);
}
if (s.name === 'sanctify' && ctx.sanctifyAllTargets) {
sanctifyFires.push({ skill: 'sanctify', source: card, isAll: true, targets: ctx.sanctifyAllTargets });
this._log(`${card.name} sanctify all: cleansed ${ctx.sanctifyAllTargets.length} allies`);
} else if (s.name === 'sanctify' && ctx.sanctifyCleansed?.length) {
sanctifyFires.push({ skill: 'sanctify', source: card, target: ctx.sanctifyTarget, cleansed: ctx.sanctifyCleansed });
this._log(`${card.name} sanctify: cleansed self`);
}
if (s.name === 'overcharge' && ctx.overchargeSource) {
const selfKilled = ctx.overchargeSelfKilled;
overchargeFires.push({
@ -711,13 +703,13 @@ export class CombatEngine {
}
}
}
return { buffs, siegeFires, protectFires, enfeebeFires, jamFires, weakenFires, drainFires, healFires, sanctifyFires, overchargeFires, fortifyFires, strikeFires };
return { buffs, siegeFires, protectFires, enfeebeFires, jamFires, weakenFires, drainFires, healFires, overchargeFires, fortifyFires, strikeFires };
}
// Emit the 8-step pre-battle sequence and process preBattle skills.
_preBattlePhase() {
// Rupture/venom/smite ticks first, then molt heals (both before buff skills).
this._rupturePhase();
// Wound/venom/smite ticks first, then molt heals (both before buff skills).
this._woundPhase();
this._venomPhase();
this._smitePhase();
this._moltPhase();
@ -732,8 +724,8 @@ export class CombatEngine {
const otherAllies = [otherCmd, ...otherLanes];
// Steps 12: commander defensive buffs (placeholder — no defensive skills yet)
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: firstSide, card: firstCmd, buffs: [], siegeFires: [], protectFires: [], sanctifyFires: [], overchargeFires: [], fortifyFires: [] });
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: otherSide, card: otherCmd, buffs: [], siegeFires: [], protectFires: [], sanctifyFires: [], overchargeFires: [], fortifyFires: [] });
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: firstSide, card: firstCmd, buffs: [], siegeFires: [], protectFires: [], overchargeFires: [], fortifyFires: [] });
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: otherSide, card: otherCmd, buffs: [], siegeFires: [], protectFires: [], overchargeFires: [], fortifyFires: [] });
// Steps 34: commander offensive buffs (pass actual enemy lanes so all-targeting skills work)
const firstCmdFires = this._collectPreBattleFires([firstCmd], firstAllies, otherAllies, otherCmd, otherLanes);
@ -742,8 +734,8 @@ export class CombatEngine {
this.events.push({ type: 'preBattle', phase: 'offensive', target: 'commander', side: otherSide, card: otherCmd, ...otherCmdFires });
// Steps 56: lane defensive buffs (placeholder)
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: firstSide, cards: firstLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], sanctifyFires: [], overchargeFires: [], fortifyFires: [] });
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: otherSide, cards: otherLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], sanctifyFires: [], overchargeFires: [], fortifyFires: [] });
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: firstSide, cards: firstLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], overchargeFires: [], fortifyFires: [] });
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: otherSide, cards: otherLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], overchargeFires: [], fortifyFires: [] });
// Steps 78: lane offensive buffs + all skill fires
const firstLaneFires = this._collectPreBattleFires(firstLanes, firstAllies, otherAllies, otherCmd, otherLanes);
@ -1110,6 +1102,26 @@ export class CombatEngine {
return debuffs;
}
// Collect cleanse fires from all live cards on a side for the postBattle phase.
_collectPostBattleCleanseFires(allSideCards) {
const cleanseFires = [];
const liveCards = allSideCards.filter(c => c && c.currentHP > 0);
for (const card of liveCards) {
for (const s of card.skills) {
if (s.name === 'cleanse' && s.trigger === 'postBattle') {
const ctx = { rng: this.rng };
const otherAllies = liveCards.filter(c => c !== card);
this.skillProcessor.process(s, card, null, otherAllies, [], ctx);
if (ctx.cleanseTargets?.length) {
cleanseFires.push({ skill: 'cleanse', source: card, targets: ctx.cleanseTargets });
this._log(`${card.name} cleanse: cleansed ${ctx.cleanseTargets.length} cards`);
}
}
}
}
return cleanseFires;
}
// Emit the 8-step post-battle sequence and remove all temp buffs.
// playerGoesFirst was already flipped in beginCommit, so !playerGoesFirst = who went first this turn.
_postBattlePhase() {
@ -1135,11 +1147,13 @@ export class CombatEngine {
this.events.push({ type: 'postBattle', phase: 'defensive', target: 'lanes', side: firstSide, cards: firstLanes, debuffs: [] });
this.events.push({ type: 'postBattle', phase: 'defensive', target: 'lanes', side: otherSide, cards: otherLanes, debuffs: [] });
// Steps 78: lane offensive debuffs
// Steps 78: lane offensive debuffs + cleanse
const firstLaneDebuffs = this._removeAndCollectDebuffs(firstLanes);
const otherLaneDebuffs = this._removeAndCollectDebuffs(otherLanes);
this.events.push({ type: 'postBattle', phase: 'offensive', target: 'lanes', side: firstSide, cards: firstLanes, debuffs: firstLaneDebuffs });
this.events.push({ type: 'postBattle', phase: 'offensive', target: 'lanes', side: otherSide, cards: otherLanes, debuffs: otherLaneDebuffs });
const firstCleanseFires = this._collectPostBattleCleanseFires([...firstLanes, firstCmd]);
const otherCleanseFires = this._collectPostBattleCleanseFires([...otherLanes, otherCmd]);
this.events.push({ type: 'postBattle', phase: 'offensive', target: 'lanes', side: firstSide, cards: firstLanes, debuffs: firstLaneDebuffs, cleanseFires: firstCleanseFires });
this.events.push({ type: 'postBattle', phase: 'offensive', target: 'lanes', side: otherSide, cards: otherLanes, debuffs: otherLaneDebuffs, cleanseFires: otherCleanseFires });
// Decrement burrow stacks now that the full combat round has resolved.
this._burrowPhase();
@ -1156,7 +1170,7 @@ export class CombatEngine {
this._activationPhase();
this._commanderSkillPhase();
this._cardOnTurnStartPhase();
this._rupturePhase();
this._woundPhase();
this._jamPhase();
this._venomPhase();
this._smitePhase();

View File

@ -73,8 +73,8 @@ export class SkillProcessor {
}
}
rupture(skill, attacker, defender, allies, enemies, context) {
const tracker = context?.ruptureTracker;
wound(skill, attacker, defender, allies, enemies, context) {
const tracker = context?.woundTracker;
const alreadyApplied = tracker?.applied || 0;
const canApply = Math.max(0, skill.value - alreadyApplied);
if (canApply <= 0) return;
@ -84,18 +84,18 @@ export class SkillProcessor {
if (targets.length === 0) return;
const allTargets = [];
for (const t of targets) {
t.ruptureStacks = (t.ruptureStacks || 0) + canApply;
t.woundStacks = (t.woundStacks || 0) + canApply;
allTargets.push({ target: t, stacks: canApply });
}
if (tracker) tracker.applied += canApply;
if (context) context.ruptureAllTargets = allTargets;
if (context) context.woundAllTargets = allTargets;
return;
}
if (!defender || defender.currentHP <= 0) return;
if (defender.burrowTurns > 0) return;
defender.ruptureStacks = (defender.ruptureStacks || 0) + canApply;
defender.woundStacks = (defender.woundStacks || 0) + canApply;
if (tracker) tracker.applied += canApply;
if (context) { context.ruptureTarget = defender; context.ruptureStacks = canApply; }
if (context) { context.woundTarget = defender; context.woundStacks = canApply; }
}
berserk(skill, attacker, defender, allies, enemies, context) {
@ -577,8 +577,11 @@ export class SkillProcessor {
if (context) { context.smiteTarget = defender; context.smiteStacks = skill.value; }
}
sanctify(skill, attacker, defender, allies, enemies, context) {
const cleanse = (card) => {
cleanse(skill, attacker, defender, allies, enemies, context) {
// Always cleanses all friendly cards including self
const allAllies = [attacker, ...allies].filter(c => c.currentHP > 0);
const targets = [];
for (const card of allAllies) {
const cleansed = [];
if (card.venomStacks > 0) {
const removed = Math.min(skill.value, card.venomStacks);
@ -590,29 +593,14 @@ export class SkillProcessor {
card.smiteStacks = Math.max(0, card.smiteStacks - removed);
cleansed.push({ effect: 'smite', removed });
}
if (card.ruptureStacks > 0) {
const removed = Math.min(skill.value, card.ruptureStacks);
card.ruptureStacks = Math.max(0, card.ruptureStacks - removed);
cleansed.push({ effect: 'rupture', removed });
if (card.woundStacks > 0) {
const removed = Math.min(skill.value, card.woundStacks);
card.woundStacks = Math.max(0, card.woundStacks - removed);
cleansed.push({ effect: 'wound', removed });
}
return cleansed;
};
if (skill.all) {
const allTargets = [];
for (const a of allies) {
if (a.currentHP <= 0) continue;
const cleansed = cleanse(a);
if (cleansed.length > 0) allTargets.push({ target: a, cleansed });
}
if (context && allTargets.length > 0) context.sanctifyAllTargets = allTargets;
return;
}
const cleansed = cleanse(attacker);
if (context && cleansed.length > 0) {
context.sanctifyTarget = attacker;
context.sanctifyCleansed = cleansed;
if (cleansed.length > 0) targets.push({ target: card, cleansed });
}
if (context && targets.length > 0) context.cleanseTargets = targets;
}
hack(skill, attacker, defender, allies, enemies, context) {

View File

@ -48,7 +48,7 @@ export class CardManager {
currentArmor: stats.armor,
baseArmor: stats.armor || 0,
currentDelay: stats.delay,
ruptureStacks: 0,
woundStacks: 0,
venomStacks: 0,
smiteStacks: 0,
burrowTurns: (() => { const bs = stats.skills.find(s => s.name === 'burrow'); return bs ? bs.value : 0; })(),

View File

@ -154,8 +154,8 @@ export class CardObject extends Phaser.GameObjects.Container {
this.add(this.burrowBadge);
this._updateBurrowBadge();
// Rupture stack indicator (below burrow badge, red)
this.ruptureBadge = this.scene.add.text(
// Wound stack indicator (below burrow badge, red)
this.woundBadge = this.scene.add.text(
w / 2 - Math.round(4 * scale),
-h / 2 + bannerH + Math.round(45 * scale),
'',
@ -166,9 +166,9 @@ export class CardObject extends Phaser.GameObjects.Container {
fontFamily: 'Audiowide'
}
).setOrigin(1, 0);
this.ruptureBadge.setVisible(false);
this.add(this.ruptureBadge);
this._updateRuptureBadge();
this.woundBadge.setVisible(false);
this.add(this.woundBadge);
this._updateWoundBadge();
// Flash overlay — transparent red rect; .bg is targeted by _animateAttack
this.bg = this.scene.add.rectangle(0, imageCY, w, imageH, 0xff2200, 0);
@ -288,14 +288,14 @@ export class CardObject extends Phaser.GameObjects.Container {
}
}
_updateRuptureBadge() {
if (!this.ruptureBadge) return;
const stacks = this.cardData.ruptureStacks || 0;
_updateWoundBadge() {
if (!this.woundBadge) return;
const stacks = this.cardData.woundStacks || 0;
if (stacks > 0) {
this.ruptureBadge.setText(`${stacks}`);
this.ruptureBadge.setVisible(true);
this.woundBadge.setText(`${stacks}`);
this.woundBadge.setVisible(true);
} else {
this.ruptureBadge.setVisible(false);
this.woundBadge.setVisible(false);
}
}
@ -321,7 +321,7 @@ export class CardObject extends Phaser.GameObjects.Container {
this._updateVenomBadge();
this._updateSmiteBadge();
this._updateBurrowBadge();
this._updateRuptureBadge();
this._updateWoundBadge();
if (this.skillText && this.cardData.skills?.length) {
const skillStr = this.cardData.skills
.map(s => {

View File

@ -809,7 +809,7 @@ export class BattleScene extends Phaser.Scene {
// Deploy + pre-attack phases (NO damage applied yet)
// On player-first turns, beginCommit also deploys the AI card
const commitEvents = this.engine.beginCommit(chosenCard);
const preBattleEvents = commitEvents.filter(e => e.type === 'preBattle' || e.type === 'ruptureTick' || e.type === 'venomTick' || e.type === 'smiteTick' || e.type === 'carapace' || e.type === 'molt' || e.type === 'hive_link');
const preBattleEvents = commitEvents.filter(e => e.type === 'preBattle' || e.type === 'woundTick' || e.type === 'venomTick' || e.type === 'smiteTick' || e.type === 'carapace' || e.type === 'molt' || e.type === 'hive_link');
// Build preBattle hive_link map for venom kills: dead card instanceId → hive_link event
this._preBattleHiveLinks = {};
@ -826,7 +826,6 @@ export class BattleScene extends Phaser.Scene {
this._restoreDrainForDisplay(preBattleEvents);
this._restoreMoltForDisplay(preBattleEvents);
this._restoreHealForDisplay(preBattleEvents);
this._restoreSanctifyForDisplay(preBattleEvents);
this._restoreOverchargeForDisplay(preBattleEvents);
this._restoreFortifyForDisplay(preBattleEvents);
// Render the field with all newly deployed cards but pre-combat stats
@ -837,7 +836,6 @@ export class BattleScene extends Phaser.Scene {
this._reapplyDrainDamage(preBattleEvents);
this._reapplyMolt(preBattleEvents);
this._reapplyHeal(preBattleEvents);
this._reapplySanctify(preBattleEvents);
this._reapplyOvercharge(preBattleEvents);
this._reapplyFortify(preBattleEvents);
@ -918,7 +916,7 @@ export class BattleScene extends Phaser.Scene {
} else if (currentRound) {
if (e.type === 'berserk') currentRound.berserkEvent = e;
else if (e.type === 'counter') currentRound.counterEvent = e;
else if (['ruptureAll', 'ruptureApply', 'weakenAll', 'venomApply', 'venomApplyAll', 'smiteApply', 'smiteApplyAll', 'carapace'].includes(e.type))
else if (['woundAll', 'woundApply', 'weakenAll', 'venomApply', 'venomApplyAll', 'smiteApply', 'smiteApplyAll', 'carapace'].includes(e.type))
currentRound.onAttackAllEvents.push(e);
}
}
@ -1000,7 +998,7 @@ export class BattleScene extends Phaser.Scene {
?? this.commanderObjects?.get(cardData.instanceId);
if (!obj) return;
obj.refresh();
// Fallback death path for cards killed by counter/rupture without an HP loss animation
// Fallback death path for cards killed by counter/wound without an HP loss animation
if (cardData.currentHP <= 0 && !obj.isCommander) {
this._playCardDeath(obj, cardData);
}
@ -1013,8 +1011,8 @@ export class BattleScene extends Phaser.Scene {
if (idx >= events.length) { onComplete(); return; }
const event = events[idx];
const cb = () => next(idx + 1);
if (event.type === 'ruptureAll') this._animateRuptureAll(event, cb);
else if (event.type === 'ruptureApply') this._animateRuptureApply(event, cb);
if (event.type === 'woundAll') this._animateWoundAll(event, cb);
else if (event.type === 'woundApply') this._animateWoundApply(event, cb);
else if (event.type === 'weakenAll') this._animateWeakenAll(event, cb);
else if (event.type === 'venomApply') this._animateVenomApply(event, cb);
else if (event.type === 'venomApplyAll') this._animateVenomApplyAll(event, cb);
@ -1027,12 +1025,12 @@ export class BattleScene extends Phaser.Scene {
next(0);
}
_animateRuptureAll(event, onComplete) {
_animateWoundAll(event, onComplete) {
if (!event.targets?.length) { onComplete(); return; }
const _lookup = id => id && (this.cardObjects.get(id) || this.commanderObjects?.get(id));
const sourceObj = _lookup(event.attacker.instanceId);
this.statusText.setText(`${event.attacker.name} ruptures all enemies!`);
this.sound.play('sfx_rupture', { volume: 0.8 });
this.statusText.setText(`${event.attacker.name} wounds all enemies!`);
this.sound.play('sfx_wound', { volume: 0.8 });
let remaining = event.targets.length;
const done = () => { if (--remaining <= 0) onComplete(); };
@ -1043,7 +1041,7 @@ export class BattleScene extends Phaser.Scene {
if (!sourceObj?.scene) {
targetObj.refresh();
this._showRuptureStackGain(targetObj, t.stacks);
this._showWoundStackGain(targetObj, t.stacks);
this.time.delayedCall(400, done);
continue;
}
@ -1064,7 +1062,7 @@ export class BattleScene extends Phaser.Scene {
if (knife.scene) knife.destroy();
if (targetObj.scene) {
targetObj.refresh();
this._showRuptureStackGain(targetObj, t.stacks);
this._showWoundStackGain(targetObj, t.stacks);
}
done();
}
@ -1072,18 +1070,18 @@ export class BattleScene extends Phaser.Scene {
}
}
_animateRuptureApply(event, onComplete) {
_animateWoundApply(event, onComplete) {
const _lookup = id => id && (this.cardObjects.get(id) || this.commanderObjects?.get(id));
const sourceObj = _lookup(event.attacker.instanceId);
const targetObj = _lookup(event.target.instanceId);
if (!targetObj?.scene) { onComplete(); return; }
this.statusText.setText(`${event.attacker.name} ruptures ${event.target.name}! [${event.stacks} stacks]`);
this.sound.play('sfx_rupture', { volume: 0.8 });
this.statusText.setText(`${event.attacker.name} wounds ${event.target.name}! [${event.stacks} stacks]`);
this.sound.play('sfx_wound', { volume: 0.8 });
if (!sourceObj?.scene) {
targetObj.refresh();
this._showRuptureStackGain(targetObj, event.stacks);
this._showWoundStackGain(targetObj, event.stacks);
this.time.delayedCall(400, onComplete);
return;
}
@ -1104,18 +1102,18 @@ export class BattleScene extends Phaser.Scene {
if (knife.scene) knife.destroy();
if (!targetObj.scene) { onComplete(); return; }
targetObj.refresh();
this._showRuptureStackGain(targetObj, event.stacks);
this._showWoundStackGain(targetObj, event.stacks);
this.time.delayedCall(400, onComplete);
}
});
}
_animateRuptureTick(event, onComplete) {
_animateWoundTick(event, onComplete) {
const obj = this.cardObjects.get(event.card.instanceId) || this.commanderObjects?.get(event.card.instanceId);
if (!obj?.scene) { onComplete(); return; }
this.statusText.setText(`${event.card.name} suffers ${event.damage} rupture damage!`);
this.sound.play('sfx_rupture_effect', { volume: 0.8 });
this.statusText.setText(`${event.card.name} suffers ${event.damage} wound damage!`);
this.sound.play('sfx_wound_effect', { volume: 0.8 });
// Sprite 45 (heart) pulses larger/smaller over the card for ~2 seconds
const effectSprite = this.add.sprite(obj.x, obj.y, 'attacks', 45)
@ -1152,9 +1150,9 @@ export class BattleScene extends Phaser.Scene {
});
}
_showRuptureStackGain(targetObj, stacks) {
_showWoundStackGain(targetObj, stacks) {
if (!targetObj?.scene || stacks <= 0) return;
const gainText = this.add.text(targetObj.x, targetObj.y - 20, `+${stacks} rupture`, {
const gainText = this.add.text(targetObj.x, targetObj.y - 20, `+${stacks} wound`, {
fontSize: '12px', color: '#ff4444', fontStyle: 'bold',
stroke: '#000000', strokeThickness: 3, fontFamily: 'Audiowide'
}).setOrigin(0.5).setDepth(35);
@ -2711,8 +2709,8 @@ export class BattleScene extends Phaser.Scene {
_processPreBattle(events, onComplete) {
const processStep = (idx) => {
if (idx >= events.length) { onComplete(); return; }
if (events[idx].type === 'ruptureTick') {
this._animateRuptureTick(events[idx], () => processStep(idx + 1));
if (events[idx].type === 'woundTick') {
this._animateWoundTick(events[idx], () => processStep(idx + 1));
return;
}
if (events[idx].type === 'venomTick') {
@ -2751,13 +2749,11 @@ export class BattleScene extends Phaser.Scene {
const hasWeaken = event.weakenFires?.length > 0;
const hasDrain = event.drainFires?.length > 0;
const hasHeal = event.healFires?.length > 0;
const hasSanctify = event.sanctifyFires?.length > 0;
const hasOvercharge = event.overchargeFires?.length > 0;
const hasFortify = event.fortifyFires?.length > 0;
const hasStrike = event.strikeFires?.length > 0;
if (hasBuffs || hasSiege || hasProtect || hasEnfeeble || hasJam || hasWeaken || hasDrain || hasHeal || hasSanctify || hasOvercharge || hasFortify || hasStrike) {
this._processSanctifyFires(event.sanctifyFires || [], () => {
if (hasBuffs || hasSiege || hasProtect || hasEnfeeble || hasJam || hasWeaken || hasDrain || hasHeal || hasOvercharge || hasFortify || hasStrike) {
this._processDrainFires(event.drainFires || [], () => {
this._processOverchargeFires(event.overchargeFires || [], () => {
this._processBuffAnimations(event.buffs || [], () => {
@ -2779,7 +2775,6 @@ export class BattleScene extends Phaser.Scene {
});
});
});
});
} else {
onComplete();
}
@ -4365,7 +4360,7 @@ export class BattleScene extends Phaser.Scene {
processStep(0);
}
// Called once per postBattle step. Refreshes cards whose temp buffs were removed.
// Called once per postBattle step. Refreshes cards whose temp buffs were removed, then plays cleanse.
_onPostBattleStep(event, onComplete) {
if (event.debuffs?.length > 0) {
for (const debuff of event.debuffs) {
@ -4374,6 +4369,10 @@ export class BattleScene extends Phaser.Scene {
obj?.refresh();
}
}
if (event.cleanseFires?.length > 0) {
this._processPostBattleCleanseFires(event.cleanseFires, onComplete);
return;
}
onComplete();
}
@ -4841,64 +4840,61 @@ export class BattleScene extends Phaser.Scene {
}
}
// ── Sanctify animations ──────────────────────────────────────────────────
// ── Cleanse animations ───────────────────────────────────────────────────
_processSanctifyFires(fires, onComplete) {
if (!fires || fires.length === 0) { onComplete(); return; }
_processPostBattleCleanseFires(cleanseFires, onComplete) {
if (!cleanseFires?.length) { onComplete(); return; }
const next = (idx) => {
if (idx >= fires.length) { onComplete(); return; }
const fire = fires[idx];
if (fire.isAll) {
this._animateSanctifyAll(fire, () => next(idx + 1));
} else {
this._animateSanctifySingle(fire, () => next(idx + 1));
}
if (idx >= cleanseFires.length) { onComplete(); return; }
this._animatePostBattleCleanseFireSet(cleanseFires[idx], () => next(idx + 1));
};
next(0);
}
_animateSanctifySingle(fire, onComplete) {
const sourceObj = this.cardObjects.get(fire.source.instanceId) || this.commanderObjects?.get(fire.source.instanceId);
const targetObj = this.cardObjects.get(fire.target.instanceId) || this.commanderObjects?.get(fire.target.instanceId);
if (!targetObj?.scene) { onComplete(); return; }
const effects = fire.cleansed.map(c => c.effect).join(', ');
this.statusText.setText(`${fire.source.name} sanctifies self! Cleansed: ${effects}`);
this.sound.play('sfx_sanctify', { volume: 0.8 });
const startX = sourceObj?.scene ? sourceObj.x : targetObj.x;
const startY = sourceObj?.scene ? sourceObj.y : targetObj.y;
this._doSanctifySpriteTo(startX, startY, targetObj, () => {
if (targetObj.scene) targetObj.refresh();
onComplete();
});
}
_animateSanctifyAll(fire, onComplete) {
_animatePostBattleCleanseFireSet(fire, onComplete) {
if (!fire.targets?.length) { onComplete(); return; }
this.statusText.setText(`${fire.source.name} sanctifies all allies!`);
this.sound.play('sfx_sanctify', { volume: 0.8 });
const sourceObj = this.cardObjects.get(fire.source.instanceId) || this.commanderObjects?.get(fire.source.instanceId);
const startX = sourceObj?.scene ? sourceObj.x : 0;
const startY = sourceObj?.scene ? sourceObj.y : 0;
this.statusText.setText(`${fire.source.name} cleanses the team!`);
this.sound.play('sfx_cleanse', { volume: 0.8 });
const startX = sourceObj?.scene ? sourceObj.x : this.cameras.main.centerX;
const startY = sourceObj?.scene ? sourceObj.y : this.cameras.main.centerY;
let remaining = fire.targets.length;
const done = () => { if (--remaining <= 0) onComplete(); };
for (const t of fire.targets) {
const targetObj = this.cardObjects.get(t.target.instanceId) || this.commanderObjects?.get(t.target.instanceId);
if (!targetObj?.scene) { done(); continue; }
const obj = this.cardObjects.get(t.target.instanceId) || this.commanderObjects?.get(t.target.instanceId);
if (!obj?.scene) { done(); continue; }
this._doSanctifySpriteTo(startX, startY, targetObj, () => {
if (targetObj.scene) targetObj.refresh();
this._doCleanseSpriteTo(startX, startY, obj, () => {
for (const c of t.cleansed) {
this._showCleanseReduction(obj, c.effect, c.removed);
}
if (obj.scene) obj.refresh();
done();
});
}
}
_showCleanseReduction(targetObj, effect, removed) {
if (!targetObj?.scene || removed <= 0) return;
const colors = { venom: '#88ff44', smite: '#ffcc00', wound: '#ff4444' };
const color = colors[effect] || '#44ffff';
const gainText = this.add.text(targetObj.x, targetObj.y - 20, `-${removed} ${effect}`, {
fontSize: '12px', color, fontStyle: 'bold',
stroke: '#000000', strokeThickness: 3, fontFamily: 'Audiowide'
}).setOrigin(0.5).setDepth(35);
this.tweens.add({
targets: gainText,
alpha: 0, y: targetObj.y - 55,
duration: 800, ease: 'Power2',
onComplete: () => { if (gainText.scene) gainText.destroy(); }
});
}
// Fly sprite 35 from (startX, startY) to targetObj, shake it, swap to sprite 36, fade out.
_doSanctifySpriteTo(startX, startY, targetObj, onComplete) {
_doCleanseSpriteTo(startX, startY, targetObj, onComplete) {
const sprite = this.add.sprite(startX, startY, 'attacks', 35)
.setDisplaySize(100, 100)
.setDepth(30)
@ -5002,22 +4998,51 @@ export class BattleScene extends Phaser.Scene {
_animateOverchargeBuffs(fire, onComplete) {
if (!fire.targets?.length) { onComplete(); return; }
const sourceObj = this.cardObjects.get(fire.source.instanceId) || this.commanderObjects?.get(fire.source.instanceId);
let remaining = fire.targets.length;
const done = () => { if (--remaining <= 0) onComplete(); };
for (const t of fire.targets) {
const obj = this.cardObjects.get(t.target.instanceId) || this.commanderObjects?.get(t.target.instanceId);
for (const tgt of fire.targets) {
const obj = this.cardObjects.get(tgt.target.instanceId) || this.commanderObjects?.get(tgt.target.instanceId);
if (!obj?.scene) { done(); continue; }
// Sprite 41 pulses over each buffed ally while ATK gain animates
const buffSprite = this.add.sprite(obj.x, obj.y, 'attacks', 41)
const startX = sourceObj ? sourceObj.x : obj.x;
const startY = sourceObj ? sourceObj.y : obj.y;
const endX = obj.x;
const endY = obj.y;
// Control point arches upward above the midpoint
const ctrlX = (startX + endX) / 2;
const ctrlY = Math.min(startY, endY) - 120;
// Sprite 41 originates at source and arches to each buffed ally
const buffSprite = this.add.sprite(startX, startY, 'attacks', 41)
.setDisplaySize(130, 130)
.setDepth(30)
.setAlpha(0.9);
const progress = { t: 0 };
this.tweens.add({
targets: progress,
t: 1,
duration: 380,
scaleX: 1.5,
scaleY: 1.5,
ease: 'Sine.easeIn',
onUpdate: () => {
const p = progress.t;
const bx = (1 - p) * (1 - p) * startX + 2 * (1 - p) * p * ctrlX + p * p * endX;
const by = (1 - p) * (1 - p) * startY + 2 * (1 - p) * p * ctrlY + p * p * endY;
if (buffSprite.scene) { buffSprite.x = bx; buffSprite.y = by; }
},
onComplete: () => {
if (!buffSprite.scene) { done(); return; }
// Arrived — pulse at target then destroy
this.tweens.add({
targets: buffSprite,
scaleX: { from: 0.8, to: 1.5 },
scaleY: { from: 0.8, to: 1.5 },
scaleX: { from: 0.8, to: 1.2 },
scaleY: { from: 0.8, to: 1.2 },
duration: 220,
yoyo: true,
repeat: 1,
@ -5029,6 +5054,8 @@ export class BattleScene extends Phaser.Scene {
done();
});
}
});
}
}
// ── Fortify animations ───────────────────────────────────────────────────
@ -5105,7 +5132,7 @@ export class BattleScene extends Phaser.Scene {
if (obj.armText) obj.armText.setText(`${(obj.cardData.currentArmor || 0) - amount}`);
const sprite = this.add.sprite(obj.x, obj.y, 'attacks', 37)
.setDisplaySize(110, 110)
.setDisplaySize(90, 90)
.setDepth(30)
.setAlpha(0.9);
@ -5198,49 +5225,6 @@ export class BattleScene extends Phaser.Scene {
// ── Restore/reapply for new preBattle skills ─────────────────────────────
_restoreSanctifyForDisplay(preBattleEvents) {
for (const event of preBattleEvents) {
for (const fire of event.sanctifyFires || []) {
if (fire.isAll) {
for (const t of fire.targets || []) {
for (const c of t.cleansed) {
if (c.effect === 'venom') t.target.venomStacks += c.removed;
if (c.effect === 'smite') t.target.smiteStacks += c.removed;
if (c.effect === 'rupture') t.target.ruptureStacks += c.removed;
}
}
} else if (fire.cleansed?.length) {
for (const c of fire.cleansed) {
if (c.effect === 'venom') fire.target.venomStacks += c.removed;
if (c.effect === 'smite') fire.target.smiteStacks += c.removed;
if (c.effect === 'rupture') fire.target.ruptureStacks += c.removed;
}
}
}
}
}
_reapplySanctify(preBattleEvents) {
for (const event of preBattleEvents) {
for (const fire of event.sanctifyFires || []) {
if (fire.isAll) {
for (const t of fire.targets || []) {
for (const c of t.cleansed) {
if (c.effect === 'venom') t.target.venomStacks -= c.removed;
if (c.effect === 'smite') t.target.smiteStacks -= c.removed;
if (c.effect === 'rupture') t.target.ruptureStacks -= c.removed;
}
}
} else if (fire.cleansed?.length) {
for (const c of fire.cleansed) {
if (c.effect === 'venom') fire.target.venomStacks -= c.removed;
if (c.effect === 'smite') fire.target.smiteStacks -= c.removed;
if (c.effect === 'rupture') fire.target.ruptureStacks -= c.removed;
}
}
}
}
}
_restoreOverchargeForDisplay(preBattleEvents) {
for (const event of preBattleEvents) {

View File

@ -57,14 +57,14 @@ export class BootScene extends Phaser.Scene {
this.load.audio('sfx_hive_link', 'assets/audio/fx/hive_link.mp3');
this.load.audio('sfx_swarm', 'assets/audio/fx/swarm.mp3');
this.load.audio('sfx_heal', 'assets/audio/fx/heal.mp3');
this.load.audio('sfx_sanctify', 'assets/audio/fx/sanctify.mp3');
this.load.audio('sfx_cleanse', 'assets/audio/fx/sanctify.mp3');
this.load.audio('sfx_hack', 'assets/audio/fx/hack.mp3');
this.load.audio('sfx_smite_cast', 'assets/audio/fx/smite-cast.mp3');
this.load.audio('sfx_smite_damage', 'assets/audio/fx/smite-damage.mp3');
this.load.audio('sfx_overcharge', 'assets/audio/fx/overcharge.mp3');
this.load.audio('sfx_weaken', 'assets/audio/fx/weaken.mp3');
this.load.audio('sfx_rupture', 'assets/audio/fx/rupture.mp3');
this.load.audio('sfx_rupture_effect', 'assets/audio/fx/rupture-effect.mp3');
this.load.audio('sfx_wound', 'assets/audio/fx/rupture.mp3');
this.load.audio('sfx_wound_effect', 'assets/audio/fx/rupture-effect.mp3');
this.load.audio('sfx_fortify', 'assets/audio/fx/fortify.mp3');
this.load.audio('sfx_store_buy', 'assets/audio/fx/buy.mp3');
this.load.audio('sfx_store_card', 'assets/audio/fx/card.mp3');