refactor: replace enfeeble with wound/skill rebalancing and add venom/burrow/hive_link support
- Replace enfeeble skill with wound (value adjusted per card) across multiple enemy cards in data/cards.json - Add venom preBattle skill to several enemy cards (3/6/12 stacks) - Add burrow all: true skill to multiple enemy cards (1–3 turns) - Add cleanse and hive_link skills to hive-related enemies with postBattle trigger - In CombatEngine.js: implement _applyCommanderBurrowBonus for deploying/spawned cards - Implement commander hive_link all: boost surviving allies' ATK when any card dies - In SkillProcessor.js: update all all-targeting skills (strike, pierce, mortar, jam, weaken) to skip targets with burrowTurns > 0 - Add venom skill support with stack handling and prevStacks tracking for display restoration - In BattleScene.js: extend preBattle event handling to include venomFires; fix hive_link deadCardId resolution
This commit is contained in:
parent
e6049b6985
commit
d98070915f
108
data/cards.json
108
data/cards.json
|
|
@ -4181,16 +4181,10 @@
|
|||
"delay": 0,
|
||||
"skills": [
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"name": "wound",
|
||||
"value": 1,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
},
|
||||
{
|
||||
"name": "weaken",
|
||||
"value": 2,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -4201,16 +4195,10 @@
|
|||
"delay": 0,
|
||||
"skills": [
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"name": "wound",
|
||||
"value": 2,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
},
|
||||
{
|
||||
"name": "weaken",
|
||||
"value": 3,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -4221,8 +4209,8 @@
|
|||
"delay": 0,
|
||||
"skills": [
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"value": 3,
|
||||
"name": "wound",
|
||||
"value": 5,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
},
|
||||
|
|
@ -4241,14 +4229,14 @@
|
|||
"delay": 0,
|
||||
"skills": [
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"value": 5,
|
||||
"name": "wound",
|
||||
"value": 8,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
},
|
||||
{
|
||||
"name": "weaken",
|
||||
"value": 7,
|
||||
"value": 8,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
}
|
||||
|
|
@ -4261,8 +4249,8 @@
|
|||
"delay": 0,
|
||||
"skills": [
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"value": 7,
|
||||
"name": "wound",
|
||||
"value": 10,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
},
|
||||
|
|
@ -6014,6 +6002,12 @@
|
|||
"name": "spawn",
|
||||
"value": 1,
|
||||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "venom",
|
||||
"value": 3,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -6027,6 +6021,12 @@
|
|||
"name": "spawn",
|
||||
"value": 1,
|
||||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "venom",
|
||||
"value": 6,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -6040,6 +6040,12 @@
|
|||
"name": "spawn",
|
||||
"value": 1,
|
||||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "venom",
|
||||
"value": 12,
|
||||
"all": true,
|
||||
"trigger": "preBattle"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -6093,6 +6099,11 @@
|
|||
"value": 3,
|
||||
"trigger": "preBattle",
|
||||
"all": true
|
||||
},
|
||||
{
|
||||
"name": "burrow",
|
||||
"value": 1,
|
||||
"all": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -6107,6 +6118,11 @@
|
|||
"value": 5,
|
||||
"trigger": "preBattle",
|
||||
"all": true
|
||||
},
|
||||
{
|
||||
"name": "burrow",
|
||||
"value": 2,
|
||||
"all": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -6121,6 +6137,11 @@
|
|||
"value": 7,
|
||||
"trigger": "preBattle",
|
||||
"all": true
|
||||
},
|
||||
{
|
||||
"name": "burrow",
|
||||
"value": 3,
|
||||
"all": true
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
@ -6145,12 +6166,6 @@
|
|||
"name": "spawn",
|
||||
"value": 1,
|
||||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"value": 1,
|
||||
"trigger": "preBattle",
|
||||
"all": true
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -6166,10 +6181,10 @@
|
|||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"name": "cleanse",
|
||||
"value": 2,
|
||||
"trigger": "preBattle",
|
||||
"all": true
|
||||
"all": true,
|
||||
"trigger": "postBattle"
|
||||
}
|
||||
]
|
||||
},
|
||||
|
|
@ -6185,9 +6200,14 @@
|
|||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"value": 3,
|
||||
"trigger": "preBattle",
|
||||
"name": "cleanse",
|
||||
"value": 4,
|
||||
"all": true,
|
||||
"trigger": "postBattle"
|
||||
},
|
||||
{
|
||||
"name": "hive_link",
|
||||
"value": 2,
|
||||
"all": true
|
||||
}
|
||||
]
|
||||
|
|
@ -6204,9 +6224,14 @@
|
|||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"value": 5,
|
||||
"trigger": "preBattle",
|
||||
"name": "cleanse",
|
||||
"value": 6,
|
||||
"all": true,
|
||||
"trigger": "postBattle"
|
||||
},
|
||||
{
|
||||
"name": "hive_link",
|
||||
"value": 4,
|
||||
"all": true
|
||||
}
|
||||
]
|
||||
|
|
@ -6223,9 +6248,14 @@
|
|||
"trigger": "on_turn_start"
|
||||
},
|
||||
{
|
||||
"name": "enfeeble",
|
||||
"value": 7,
|
||||
"trigger": "preBattle",
|
||||
"name": "cleanse",
|
||||
"value": 8,
|
||||
"all": true,
|
||||
"trigger": "postBattle"
|
||||
},
|
||||
{
|
||||
"name": "hive_link",
|
||||
"value": 6,
|
||||
"all": true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
|
|
@ -44,15 +44,23 @@ export class CombatEngine {
|
|||
}
|
||||
|
||||
// Deploy one card from hand into next open lane
|
||||
_applyCommanderBurrowBonus(card, commander) {
|
||||
const skill = commander?.skills?.find(s => s.name === 'burrow' && s.all);
|
||||
if (!skill) return;
|
||||
card.burrowTurns += skill.value;
|
||||
}
|
||||
|
||||
_deployPhase() {
|
||||
if (this.playerHand.length > 0 && this.playerLanes.length < MAX_LANES) {
|
||||
const card = this.playerHand.shift();
|
||||
this._applyCommanderBurrowBonus(card, this.playerCommander);
|
||||
this.playerLanes.push(card);
|
||||
this._log(`Player deploys ${card.name}`);
|
||||
this.events.push({ type: 'deploy', side: 'player', card });
|
||||
}
|
||||
const aiCard = this.ai.getNextCard();
|
||||
if (aiCard && this.opponentLanes.length < MAX_LANES) {
|
||||
this._applyCommanderBurrowBonus(aiCard, this.opponentCommander);
|
||||
this.opponentLanes.push(aiCard);
|
||||
this._log(`Opponent deploys ${aiCard.name}`);
|
||||
this.events.push({ type: 'deploy', side: 'opponent', card: aiCard });
|
||||
|
|
@ -203,6 +211,7 @@ export class CombatEngine {
|
|||
this.skillProcessor.process(s, commander, null,
|
||||
[commander, ...lanes], [enemyCommander, ...enemyLanes], ctx);
|
||||
if (ctx.spawnedDrone && lanes.length < MAX_LANES) {
|
||||
this._applyCommanderBurrowBonus(ctx.spawnedDrone, commander);
|
||||
lanes.push(ctx.spawnedDrone);
|
||||
const side = (commander === this.playerCommander) ? 'player' : 'opponent';
|
||||
this._log(`${commander.name} spawns a ${ctx.spawnedDrone.name}`);
|
||||
|
|
@ -420,6 +429,23 @@ export class CombatEngine {
|
|||
this.events.push({ type: 'hive_link', source: deadCard, targets: ctx.hiveLinkTargets, gain: s.value, side });
|
||||
}
|
||||
}
|
||||
|
||||
// Commander hive_link all: boost all surviving allies when any card dies
|
||||
const alliedCommander = side === 'player' ? this.playerCommander : this.opponentCommander;
|
||||
const hlAllSkill = alliedCommander?.skills?.find(s => s.name === 'hive_link' && s.all);
|
||||
if (hlAllSkill) {
|
||||
const remaining = alliedLanes.filter(a => a.currentHP > 0 && a !== deadCard);
|
||||
if (remaining.length > 0) {
|
||||
const targets = [];
|
||||
for (const ally of remaining) {
|
||||
ally.currentAttack += hlAllSkill.value;
|
||||
ally.attack += hlAllSkill.value;
|
||||
targets.push({ target: ally, gain: hlAllSkill.value });
|
||||
}
|
||||
this._log(`${alliedCommander.name} hive_link all: +${hlAllSkill.value} ATK to ${targets.length} allies on death of ${deadCard.name}`);
|
||||
this.events.push({ type: 'hive_link', source: alliedCommander, deadCardId: deadCard.instanceId, targets, gain: hlAllSkill.value, side });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove dead cards, compact lanes
|
||||
|
|
@ -464,6 +490,7 @@ export class CombatEngine {
|
|||
// and should not be ticked the same turn it enters the field (same rule as
|
||||
// player cards, which deploy after _activationPhase() runs in beginCommit).
|
||||
aiCard._justDeployed = true;
|
||||
this._applyCommanderBurrowBonus(aiCard, this.opponentCommander);
|
||||
this.opponentLanes.push(aiCard);
|
||||
this._log(`Opponent deploys ${aiCard.name}`);
|
||||
this.events.push({ type: 'deploy', side: 'opponent', card: aiCard });
|
||||
|
|
@ -480,6 +507,7 @@ export class CombatEngine {
|
|||
const idx = this.playerHand.findIndex(c => c.instanceId === chosenCard.instanceId);
|
||||
if (idx !== -1) {
|
||||
this.playerHand.splice(idx, 1);
|
||||
this._applyCommanderBurrowBonus(chosenCard, this.playerCommander);
|
||||
this.playerLanes.push(chosenCard);
|
||||
this._log(`Player deploys ${chosenCard.name}`);
|
||||
this.events.push({ type: 'deploy', side: 'player', card: chosenCard });
|
||||
|
|
@ -514,6 +542,7 @@ export class CombatEngine {
|
|||
const idx = this.playerHand.findIndex(c => c.instanceId === chosenCard.instanceId);
|
||||
if (idx !== -1) {
|
||||
this.playerHand.splice(idx, 1);
|
||||
this._applyCommanderBurrowBonus(chosenCard, this.playerCommander);
|
||||
this.playerLanes.push(chosenCard);
|
||||
this._log(`Player deploys ${chosenCard.name}`);
|
||||
this.events.push({ type: 'deploy', side: 'player', card: chosenCard });
|
||||
|
|
@ -526,6 +555,7 @@ export class CombatEngine {
|
|||
if (this.playerGoesFirst) {
|
||||
const aiCard = this.ai.getNextCard();
|
||||
if (aiCard && this.opponentLanes.length < MAX_LANES) {
|
||||
this._applyCommanderBurrowBonus(aiCard, this.opponentCommander);
|
||||
this.opponentLanes.push(aiCard);
|
||||
this._log(`Opponent deploys ${aiCard.name}`);
|
||||
this.events.push({ type: 'deploy', side: 'opponent', card: aiCard });
|
||||
|
|
@ -560,6 +590,7 @@ export class CombatEngine {
|
|||
const fortifyFires = [];
|
||||
const strikeFires = [];
|
||||
const woundFires = [];
|
||||
const venomFires = [];
|
||||
const liveAllies = allies.filter(c => c.currentHP > 0);
|
||||
const liveEnemies = enemies.filter(c => c.currentHP > 0);
|
||||
for (const card of cards) {
|
||||
|
|
@ -696,6 +727,13 @@ export class CombatEngine {
|
|||
woundFires.push({ skill: 'wound', source: card, target: ctx.woundTarget, stacks: ctx.woundStacks });
|
||||
this._log(`${card.name} wound: applied ${ctx.woundStacks} stacks to ${ctx.woundTarget.name}`);
|
||||
}
|
||||
if (s.name === 'venom' && ctx.venomAllTargets) {
|
||||
venomFires.push({ skill: 'venom', source: card, isAll: true, targets: ctx.venomAllTargets });
|
||||
this._log(`${card.name} venom all: applied stacks to ${ctx.venomAllTargets.length} enemies`);
|
||||
} else if (s.name === 'venom' && ctx.venomTarget) {
|
||||
venomFires.push({ skill: 'venom', source: card, target: ctx.venomTarget, stacks: ctx.venomStacks });
|
||||
this._log(`${card.name} venom: applied ${ctx.venomStacks} stacks to ${ctx.venomTarget.name}`);
|
||||
}
|
||||
if (s.name === 'strike' && ctx.strikeAllTargets) {
|
||||
const isPlayerCard = this.playerLanes.includes(card) || card === this.playerCommander;
|
||||
for (const t of ctx.strikeAllTargets) {
|
||||
|
|
@ -725,7 +763,7 @@ export class CombatEngine {
|
|||
}
|
||||
}
|
||||
}
|
||||
return { buffs, siegeFires, protectFires, enfeebeFires, jamFires, weakenFires, drainFires, healFires, overchargeFires, fortifyFires, strikeFires, woundFires };
|
||||
return { buffs, siegeFires, protectFires, enfeebeFires, jamFires, weakenFires, drainFires, healFires, overchargeFires, fortifyFires, strikeFires, woundFires, venomFires };
|
||||
}
|
||||
|
||||
// Emit the 8-step pre-battle sequence and process preBattle skills.
|
||||
|
|
@ -746,8 +784,8 @@ export class CombatEngine {
|
|||
const otherAllies = [otherCmd, ...otherLanes];
|
||||
|
||||
// Steps 1–2: commander defensive buffs (placeholder — no defensive skills yet)
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: firstSide, card: firstCmd, buffs: [], siegeFires: [], protectFires: [], overchargeFires: [], fortifyFires: [], woundFires: [] });
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: otherSide, card: otherCmd, buffs: [], siegeFires: [], protectFires: [], overchargeFires: [], fortifyFires: [], woundFires: [] });
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: firstSide, card: firstCmd, buffs: [], siegeFires: [], protectFires: [], overchargeFires: [], fortifyFires: [], woundFires: [], venomFires: [] });
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'commander', side: otherSide, card: otherCmd, buffs: [], siegeFires: [], protectFires: [], overchargeFires: [], fortifyFires: [], woundFires: [], venomFires: [] });
|
||||
|
||||
// Steps 3–4: commander offensive buffs (pass actual enemy lanes so all-targeting skills work)
|
||||
const firstCmdFires = this._collectPreBattleFires([firstCmd], firstAllies, otherAllies, otherCmd, otherLanes);
|
||||
|
|
@ -756,8 +794,8 @@ export class CombatEngine {
|
|||
this.events.push({ type: 'preBattle', phase: 'offensive', target: 'commander', side: otherSide, card: otherCmd, ...otherCmdFires });
|
||||
|
||||
// Steps 5–6: lane defensive buffs (placeholder)
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: firstSide, cards: firstLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], overchargeFires: [], fortifyFires: [], woundFires: [] });
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: otherSide, cards: otherLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], overchargeFires: [], fortifyFires: [], woundFires: [] });
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: firstSide, cards: firstLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], overchargeFires: [], fortifyFires: [], woundFires: [], venomFires: [] });
|
||||
this.events.push({ type: 'preBattle', phase: 'defensive', target: 'lanes', side: otherSide, cards: otherLanes, buffs: [], siegeFires: [], protectFires: [], enfeebeFires: [], jamFires: [], healFires: [], overchargeFires: [], fortifyFires: [], woundFires: [], venomFires: [] });
|
||||
|
||||
// Steps 7–8: lane offensive buffs + all skill fires
|
||||
const firstLaneFires = this._collectPreBattleFires(firstLanes, firstAllies, otherAllies, otherCmd, otherLanes);
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ export class SkillProcessor {
|
|||
strike(skill, attacker, defender, allies, enemies, context) {
|
||||
if (!skill.all && defender?.burrowTurns > 0) return;
|
||||
if (skill.all) {
|
||||
const targets = enemies.length > 0 ? enemies.filter(e => e.currentHP > 0) : (context?.enemyCommander ? [context.enemyCommander] : []);
|
||||
const targets = enemies.length > 0 ? enemies.filter(e => e.currentHP > 0 && !(e.burrowTurns > 0)) : (context?.enemyCommander ? [context.enemyCommander] : []);
|
||||
if (targets.length === 0) return;
|
||||
const allTargets = [];
|
||||
for (const t of targets) {
|
||||
|
|
@ -36,7 +36,7 @@ export class SkillProcessor {
|
|||
// Hits all enemy cards AND the enemy commander for skill.value damage, ignoring armor.
|
||||
const targets = [];
|
||||
for (const e of enemies) {
|
||||
if (e.currentHP > 0) targets.push(e);
|
||||
if (e.currentHP > 0 && !(e.burrowTurns > 0)) targets.push(e);
|
||||
}
|
||||
if (context?.enemyCommander?.currentHP > 0) targets.push(context.enemyCommander);
|
||||
if (targets.length === 0) return;
|
||||
|
|
@ -51,7 +51,7 @@ export class SkillProcessor {
|
|||
|
||||
pierce(skill, attacker, defender, allies, enemies, context) {
|
||||
if (skill.all) {
|
||||
const targets = enemies.length > 0 ? enemies.filter(e => e.currentHP > 0) : (context?.enemyCommander ? [context.enemyCommander] : []);
|
||||
const targets = enemies.length > 0 ? enemies.filter(e => e.currentHP > 0 && !(e.burrowTurns > 0)) : (context?.enemyCommander ? [context.enemyCommander] : []);
|
||||
if (targets.length === 0) return;
|
||||
const allTargets = [];
|
||||
for (const t of targets) {
|
||||
|
|
@ -64,6 +64,7 @@ export class SkillProcessor {
|
|||
}
|
||||
const target = defender || context?.enemyCommander;
|
||||
if (!target) return;
|
||||
if (target.burrowTurns > 0) return;
|
||||
// Reduce armor directly (floored at 0); track actual amount so it can be restored.
|
||||
const amount = Math.min(skill.value, Math.max(0, target.currentArmor));
|
||||
target.currentArmor -= amount;
|
||||
|
|
@ -236,7 +237,7 @@ export class SkillProcessor {
|
|||
const sIdx = idx + offset;
|
||||
if (sIdx < 0 || sIdx >= enemyLaneCards.length) continue;
|
||||
const secondary = enemyLaneCards[sIdx];
|
||||
if (!secondary?.currentHP > 0) continue;
|
||||
if (!secondary || secondary.currentHP <= 0 || secondary.burrowTurns > 0) continue;
|
||||
const reductions = this._applyJamReductions(secondary, secondaryAmount);
|
||||
if (reductions.length > 0) {
|
||||
secondary._tempBuffs = secondary._tempBuffs || [];
|
||||
|
|
@ -269,7 +270,7 @@ export class SkillProcessor {
|
|||
if (skill.all) {
|
||||
const allTargets = [];
|
||||
for (const t of enemyLaneCards) {
|
||||
if (!t || t.currentHP <= 0) continue;
|
||||
if (!t || t.currentHP <= 0 || t.burrowTurns > 0) continue;
|
||||
const amount = Math.min(skill.value, t.currentAttack);
|
||||
t.currentAttack = Math.max(0, t.currentAttack - amount);
|
||||
t._tempBuffs = t._tempBuffs || [];
|
||||
|
|
@ -366,7 +367,7 @@ export class SkillProcessor {
|
|||
mortar(skill, attacker, defender, allies, enemies, context) {
|
||||
if (enemies.length === 0) return;
|
||||
if (skill.all) {
|
||||
const targets = enemies.filter(e => e.currentHP > 0);
|
||||
const targets = enemies.filter(e => e.currentHP > 0 && !(e.burrowTurns > 0));
|
||||
if (targets.length === 0) return;
|
||||
const allTargets = [];
|
||||
for (const t of targets) {
|
||||
|
|
@ -435,6 +436,7 @@ export class SkillProcessor {
|
|||
drain(skill, attacker, defender, allies, enemies, context) {
|
||||
const target = defender || context?.enemyCommander;
|
||||
if (!target) return;
|
||||
if (target.burrowTurns > 0) return;
|
||||
const primaryDmg = Math.ceil(skill.value * 0.5);
|
||||
const secondaryDmg = Math.ceil(skill.value * 0.25);
|
||||
let totalDrained = 0;
|
||||
|
|
@ -452,7 +454,7 @@ export class SkillProcessor {
|
|||
const sIdx = idx + offset;
|
||||
if (sIdx < 0 || sIdx >= enemyLanes.length) continue;
|
||||
const sec = enemyLanes[sIdx];
|
||||
if (!sec || sec.currentHP <= 0) continue;
|
||||
if (!sec || sec.currentHP <= 0 || sec.burrowTurns > 0) continue;
|
||||
sec.currentHP -= secondaryDmg;
|
||||
totalDrained += secondaryDmg;
|
||||
secondaries.push({ target: sec, damage: secondaryDmg, laneOffset: offset });
|
||||
|
|
@ -529,8 +531,9 @@ export class SkillProcessor {
|
|||
const allTargets = [];
|
||||
for (const t of targets) {
|
||||
if (t.venomStacks < skill.value) {
|
||||
const prevStacks = t.venomStacks;
|
||||
t.venomStacks = skill.value;
|
||||
allTargets.push({ target: t, stacks: skill.value });
|
||||
allTargets.push({ target: t, stacks: skill.value, prevStacks });
|
||||
}
|
||||
}
|
||||
if (context && allTargets.length > 0) context.venomAllTargets = allTargets;
|
||||
|
|
@ -618,6 +621,7 @@ export class SkillProcessor {
|
|||
|
||||
hack(skill, attacker, defender, allies, enemies, context) {
|
||||
if (!defender || defender.currentHP <= 0) return;
|
||||
if (defender.burrowTurns > 0) return;
|
||||
const copiableSkills = defender.skills.filter(s =>
|
||||
(s.trigger === 'preAttack' || s.trigger === 'preBattle' || s.trigger === 'on_attack') &&
|
||||
s.name !== 'hack'
|
||||
|
|
|
|||
|
|
@ -828,7 +828,7 @@ export class BattleScene extends Phaser.Scene {
|
|||
// Build preBattle hive_link map for venom kills: dead card instanceId → hive_link event
|
||||
this._preBattleHiveLinks = {};
|
||||
for (const e of commitEvents) {
|
||||
if (e.type === 'hive_link') this._preBattleHiveLinks[e.source.instanceId] = e;
|
||||
if (e.type === 'hive_link') this._preBattleHiveLinks[e.deadCardId ?? e.source.instanceId] = e;
|
||||
}
|
||||
|
||||
// Temporarily restore all preBattle stat changes so _renderState() builds
|
||||
|
|
@ -843,6 +843,7 @@ export class BattleScene extends Phaser.Scene {
|
|||
this._restoreOverchargeForDisplay(preBattleEvents);
|
||||
this._restoreFortifyForDisplay(preBattleEvents);
|
||||
this._restorePreBattleWoundFires(preBattleEvents);
|
||||
this._restorePreBattleVenomFires(preBattleEvents);
|
||||
this._restoreSiegeFiresForDisplay(preBattleEvents);
|
||||
// Render the field with all newly deployed cards but pre-combat stats
|
||||
this._renderState();
|
||||
|
|
@ -855,6 +856,7 @@ export class BattleScene extends Phaser.Scene {
|
|||
this._reapplyOvercharge(preBattleEvents);
|
||||
this._reapplyFortify(preBattleEvents);
|
||||
this._reapplyPreBattleWoundFires(preBattleEvents);
|
||||
this._reapplyPreBattleVenomFires(preBattleEvents);
|
||||
this._reapplySiegeFires(preBattleEvents);
|
||||
|
||||
const newPlayerCard = chosenCard
|
||||
|
|
@ -946,12 +948,12 @@ export class BattleScene extends Phaser.Scene {
|
|||
this._pendingHiveLinks = {};
|
||||
for (const round of attackRounds) {
|
||||
for (const e of round.onAttackAllEvents) {
|
||||
if (e.type === 'hive_link') this._pendingHiveLinks[e.source.instanceId] = e;
|
||||
if (e.type === 'hive_link') this._pendingHiveLinks[e.deadCardId ?? e.source.instanceId] = e;
|
||||
}
|
||||
}
|
||||
// Also scan events not yet bucketed into rounds (e.g. from counter kills)
|
||||
for (const e of events) {
|
||||
if (e.type === 'hive_link') this._pendingHiveLinks[e.source.instanceId] = e;
|
||||
if (e.type === 'hive_link') this._pendingHiveLinks[e.deadCardId ?? e.source.instanceId] = e;
|
||||
}
|
||||
|
||||
if (attackRounds.length === 0) {
|
||||
|
|
@ -2767,8 +2769,10 @@ export class BattleScene extends Phaser.Scene {
|
|||
const hasFortify = event.fortifyFires?.length > 0;
|
||||
const hasStrike = event.strikeFires?.length > 0;
|
||||
const hasWound = event.woundFires?.length > 0;
|
||||
const hasVenom = event.venomFires?.length > 0;
|
||||
|
||||
if (hasBuffs || hasSiege || hasProtect || hasEnfeeble || hasJam || hasWeaken || hasDrain || hasHeal || hasOvercharge || hasFortify || hasStrike || hasWound) {
|
||||
if (hasBuffs || hasSiege || hasProtect || hasEnfeeble || hasJam || hasWeaken || hasDrain || hasHeal || hasOvercharge || hasFortify || hasStrike || hasWound || hasVenom) {
|
||||
this._processPreBattleVenomFires(event.venomFires || [], () => {
|
||||
this._processPreBattleWoundFires(event.woundFires || [], () => {
|
||||
this._processDrainFires(event.drainFires || [], () => {
|
||||
this._processOverchargeFires(event.overchargeFires || [], () => {
|
||||
|
|
@ -2792,11 +2796,51 @@ export class BattleScene extends Phaser.Scene {
|
|||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
} else {
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
_processPreBattleVenomFires(fires, onComplete) {
|
||||
if (!fires || fires.length === 0) { onComplete(); return; }
|
||||
const next = (idx) => {
|
||||
if (idx >= fires.length) { onComplete(); return; }
|
||||
const fire = fires[idx];
|
||||
const adapted = { ...fire, attacker: fire.source };
|
||||
if (fire.isAll) {
|
||||
this._animateVenomApplyAll(adapted, () => next(idx + 1));
|
||||
} else {
|
||||
this._animateVenomApply(adapted, () => next(idx + 1));
|
||||
}
|
||||
};
|
||||
next(0);
|
||||
}
|
||||
|
||||
_restorePreBattleVenomFires(preBattleEvents) {
|
||||
for (const event of preBattleEvents) {
|
||||
for (const fire of event.venomFires || []) {
|
||||
if (fire.isAll) {
|
||||
for (const t of fire.targets) t.target.venomStacks = t.prevStacks;
|
||||
} else if (fire.target) {
|
||||
fire.target.venomStacks = fire.prevStacks ?? 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_reapplyPreBattleVenomFires(preBattleEvents) {
|
||||
for (const event of preBattleEvents) {
|
||||
for (const fire of event.venomFires || []) {
|
||||
if (fire.isAll) {
|
||||
for (const t of fire.targets) t.target.venomStacks = t.stacks;
|
||||
} else if (fire.target) {
|
||||
fire.target.venomStacks = fire.stacks;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_processPreBattleWoundFires(fires, onComplete) {
|
||||
if (!fires || fires.length === 0) { onComplete(); return; }
|
||||
const next = (idx) => {
|
||||
|
|
|
|||
Loading…
Reference in New Issue