feat(combat): add hack support for new skills and fix sound playback
- Extend `CombatEngine` to support hacking `strike`, `jam`, `venom`, `smite`, and `molt` skills, including single and area-of-effect variants. - Add logic to process deaths and carapace gain for hacked `strikeAll` attacks. - Update `BattleScene` to handle animation sequences for the new hacked skills (`strikeAll`, `jam`, `venom`, `venomAll`, `smite`, `smiteAll`, `molt`). - Fix sound effect playback by removing redundant existence checks (`if (this.sound.get(...))`), ensuring sounds play reliably.
This commit is contained in:
parent
69df7c5793
commit
82f871abfb
|
|
@ -889,6 +889,36 @@ export class CombatEngine {
|
||||||
if (copied.name === 'drain' && ctx2.drainTarget) {
|
if (copied.name === 'drain' && ctx2.drainTarget) {
|
||||||
hackFires.push({ skill: 'drain', source: pending.attacker, target: ctx2.drainTarget, damage: ctx2.drainDamage, heal: ctx2.drainHeal, isHacked: true });
|
hackFires.push({ skill: 'drain', source: pending.attacker, target: ctx2.drainTarget, damage: ctx2.drainDamage, heal: ctx2.drainHeal, isHacked: true });
|
||||||
}
|
}
|
||||||
|
if (copied.name === 'strike' && copied.all && ctx2.strikeAllTargets) {
|
||||||
|
for (const t of ctx2.strikeAllTargets) {
|
||||||
|
const targetIsCommander = t.target === pending.enemyCommander;
|
||||||
|
const fire = { skill: 'strikeAll', target: t.target, damage: t.damage, hpBefore: t.hpBefore, targetIsCommander, isHacked: true };
|
||||||
|
if (!targetIsCommander && t.target.currentHP <= 0) {
|
||||||
|
this.events.push({ type: 'death', card: t.target, side: _enemySide });
|
||||||
|
this._processOnDeath(t.target, pending.enemyLanes, _enemySide);
|
||||||
|
}
|
||||||
|
fire.carapaceGain = !targetIsCommander ? this._tryCarapace(t.target, t.damage, false) : 0;
|
||||||
|
hackFires.push(fire);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (copied.name === 'jam' && ctx2.jamTargets?.length) {
|
||||||
|
hackFires.push({ skill: 'jam', source: pending.attacker, targets: ctx2.jamTargets, isHacked: true });
|
||||||
|
}
|
||||||
|
if (copied.name === 'venom' && !copied.all && ctx2.venomTarget) {
|
||||||
|
hackFires.push({ skill: 'venom', attacker: pending.attacker, target: ctx2.venomTarget, stacks: ctx2.venomStacks, isHacked: true });
|
||||||
|
}
|
||||||
|
if (copied.name === 'venom' && copied.all && ctx2.venomAllTargets?.length) {
|
||||||
|
hackFires.push({ skill: 'venomAll', attacker: pending.attacker, targets: ctx2.venomAllTargets, isHacked: true });
|
||||||
|
}
|
||||||
|
if (copied.name === 'smite' && !copied.all && ctx2.smiteTarget) {
|
||||||
|
hackFires.push({ skill: 'smite', attacker: pending.attacker, target: ctx2.smiteTarget, stacks: ctx2.smiteStacks, isHacked: true });
|
||||||
|
}
|
||||||
|
if (copied.name === 'smite' && copied.all && ctx2.smiteAllTargets?.length) {
|
||||||
|
hackFires.push({ skill: 'smiteAll', attacker: pending.attacker, targets: ctx2.smiteAllTargets, isHacked: true });
|
||||||
|
}
|
||||||
|
if (copied.name === 'molt' && ctx2.moltHeal > 0) {
|
||||||
|
hackFires.push({ skill: 'molt', card: pending.attacker, heal: ctx2.moltHeal, armorLost: ctx2.moltArmorLost, isHacked: true });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (hackFires.length > 0) {
|
if (hackFires.length > 0) {
|
||||||
preAttackFires.push({ skill: 'hack', source: pending.attacker, copiedFrom: pending.target, fires: hackFires });
|
preAttackFires.push({ skill: 'hack', source: pending.attacker, copiedFrom: pending.target, fires: hackFires });
|
||||||
|
|
|
||||||
|
|
@ -3947,7 +3947,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
if (!sourceObj?.scene || !targetObj?.scene) { onComplete(); return; }
|
if (!sourceObj?.scene || !targetObj?.scene) { onComplete(); return; }
|
||||||
|
|
||||||
this.statusText.setText(`${event.attacker.name} smites ${event.target.name}! [${event.stacks} stacks]`);
|
this.statusText.setText(`${event.attacker.name} smites ${event.target.name}! [${event.stacks} stacks]`);
|
||||||
if (this.sound.get('sfx_smite_cast')) this.sound.play('sfx_smite_cast', { volume: 0.8 });
|
this.sound.play('sfx_smite_cast', { volume: 0.8 });
|
||||||
|
|
||||||
this._doSmiteCastTo(sourceObj, targetObj, () => {
|
this._doSmiteCastTo(sourceObj, targetObj, () => {
|
||||||
if (targetObj.scene) targetObj.refresh();
|
if (targetObj.scene) targetObj.refresh();
|
||||||
|
|
@ -3958,7 +3958,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
_animateSmiteApplyAll(event, onComplete) {
|
_animateSmiteApplyAll(event, onComplete) {
|
||||||
if (!event.targets?.length) { onComplete(); return; }
|
if (!event.targets?.length) { onComplete(); return; }
|
||||||
this.statusText.setText(`${event.attacker.name} smites all enemies!`);
|
this.statusText.setText(`${event.attacker.name} smites all enemies!`);
|
||||||
if (this.sound.get('sfx_smite_cast')) this.sound.play('sfx_smite_cast', { volume: 0.8 });
|
this.sound.play('sfx_smite_cast', { volume: 0.8 });
|
||||||
|
|
||||||
const sourceObj = this.cardObjects.get(event.attacker.instanceId) || this.commanderObjects?.get(event.attacker.instanceId);
|
const sourceObj = this.cardObjects.get(event.attacker.instanceId) || this.commanderObjects?.get(event.attacker.instanceId);
|
||||||
let remaining = event.targets.length;
|
let remaining = event.targets.length;
|
||||||
|
|
@ -3979,7 +3979,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
if (!obj?.scene) { onComplete(); return; }
|
if (!obj?.scene) { onComplete(); return; }
|
||||||
|
|
||||||
this.statusText.setText(`${event.card.name} suffers ${event.damage} smite damage!`);
|
this.statusText.setText(`${event.card.name} suffers ${event.damage} smite damage!`);
|
||||||
if (this.sound.get('sfx_smite_damage')) this.sound.play('sfx_smite_damage', { volume: 0.8 });
|
this.sound.play('sfx_smite_damage', { volume: 0.8 });
|
||||||
|
|
||||||
const effectSprite = this.add.sprite(obj.x, obj.y, 'attacks', 39)
|
const effectSprite = this.add.sprite(obj.x, obj.y, 'attacks', 39)
|
||||||
.setDisplaySize(140, 140)
|
.setDisplaySize(140, 140)
|
||||||
|
|
@ -4039,7 +4039,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
|
|
||||||
const effects = fire.cleansed.map(c => c.effect).join(', ');
|
const effects = fire.cleansed.map(c => c.effect).join(', ');
|
||||||
this.statusText.setText(`${fire.source.name} sanctifies self! Cleansed: ${effects}`);
|
this.statusText.setText(`${fire.source.name} sanctifies self! Cleansed: ${effects}`);
|
||||||
if (this.sound.get('sfx_sanctify')) this.sound.play('sfx_sanctify', { volume: 0.8 });
|
this.sound.play('sfx_sanctify', { volume: 0.8 });
|
||||||
|
|
||||||
const startX = sourceObj?.scene ? sourceObj.x : targetObj.x;
|
const startX = sourceObj?.scene ? sourceObj.x : targetObj.x;
|
||||||
const startY = sourceObj?.scene ? sourceObj.y : targetObj.y;
|
const startY = sourceObj?.scene ? sourceObj.y : targetObj.y;
|
||||||
|
|
@ -4052,7 +4052,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
_animateSanctifyAll(fire, onComplete) {
|
_animateSanctifyAll(fire, onComplete) {
|
||||||
if (!fire.targets?.length) { onComplete(); return; }
|
if (!fire.targets?.length) { onComplete(); return; }
|
||||||
this.statusText.setText(`${fire.source.name} sanctifies all allies!`);
|
this.statusText.setText(`${fire.source.name} sanctifies all allies!`);
|
||||||
if (this.sound.get('sfx_sanctify')) this.sound.play('sfx_sanctify', { volume: 0.8 });
|
this.sound.play('sfx_sanctify', { volume: 0.8 });
|
||||||
|
|
||||||
const sourceObj = this.cardObjects.get(fire.source.instanceId) || this.commanderObjects?.get(fire.source.instanceId);
|
const sourceObj = this.cardObjects.get(fire.source.instanceId) || this.commanderObjects?.get(fire.source.instanceId);
|
||||||
const startX = sourceObj?.scene ? sourceObj.x : 0;
|
const startX = sourceObj?.scene ? sourceObj.x : 0;
|
||||||
|
|
@ -4142,7 +4142,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
if (!sourceObj?.scene) { onComplete(); return; }
|
if (!sourceObj?.scene) { onComplete(); return; }
|
||||||
|
|
||||||
this.statusText.setText(`${fire.source.name} overcharges! -${fire.selfDamage} HP, +${fire.selfDamage} ATK to allies`);
|
this.statusText.setText(`${fire.source.name} overcharges! -${fire.selfDamage} HP, +${fire.selfDamage} ATK to allies`);
|
||||||
if (this.sound.get('sfx_overcharge')) this.sound.play('sfx_overcharge', { volume: 0.8 });
|
this.sound.play('sfx_overcharge', { volume: 0.8 });
|
||||||
|
|
||||||
// Sprite 40 pulses over source while HP loss animates
|
// Sprite 40 pulses over source while HP loss animates
|
||||||
const pulseSprite = this.add.sprite(sourceObj.x, sourceObj.y, 'attacks', 40)
|
const pulseSprite = this.add.sprite(sourceObj.x, sourceObj.y, 'attacks', 40)
|
||||||
|
|
@ -4227,7 +4227,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
if (!obj?.scene) { onComplete(); return; }
|
if (!obj?.scene) { onComplete(); return; }
|
||||||
|
|
||||||
this.statusText.setText(`${fire.source.name} fortifies! +${fire.amount} armor`);
|
this.statusText.setText(`${fire.source.name} fortifies! +${fire.amount} armor`);
|
||||||
if (this.sound.get('sfx_fortify')) this.sound.play('sfx_fortify', { volume: 0.8 });
|
this.sound.play('sfx_fortify', { volume: 0.8 });
|
||||||
|
|
||||||
this._doFortifyPulse(obj, fire.amount, onComplete);
|
this._doFortifyPulse(obj, fire.amount, onComplete);
|
||||||
}
|
}
|
||||||
|
|
@ -4237,7 +4237,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
|
|
||||||
const amount = fire.targets[0]?.amount || 0;
|
const amount = fire.targets[0]?.amount || 0;
|
||||||
this.statusText.setText(`${fire.source.name} fortifies all allies! +${amount} armor`);
|
this.statusText.setText(`${fire.source.name} fortifies all allies! +${amount} armor`);
|
||||||
if (this.sound.get('sfx_fortify')) this.sound.play('sfx_fortify', { volume: 0.8 });
|
this.sound.play('sfx_fortify', { volume: 0.8 });
|
||||||
|
|
||||||
const sourceObj = this.cardObjects.get(fire.source.instanceId) || this.commanderObjects?.get(fire.source.instanceId);
|
const sourceObj = this.cardObjects.get(fire.source.instanceId) || this.commanderObjects?.get(fire.source.instanceId);
|
||||||
const startX = sourceObj?.scene ? sourceObj.x : 0;
|
const startX = sourceObj?.scene ? sourceObj.x : 0;
|
||||||
|
|
@ -4311,7 +4311,7 @@ export class BattleScene extends Phaser.Scene {
|
||||||
const sourceObj = this.cardObjects.get(attacker.instanceId) || this.commanderObjects?.get(attacker.instanceId);
|
const sourceObj = this.cardObjects.get(attacker.instanceId) || this.commanderObjects?.get(attacker.instanceId);
|
||||||
|
|
||||||
this.statusText.setText(`${attacker.name} hacks ${hackGroup.copiedFrom?.name || 'enemy'}!`);
|
this.statusText.setText(`${attacker.name} hacks ${hackGroup.copiedFrom?.name || 'enemy'}!`);
|
||||||
if (this.sound.get('sfx_hack')) this.sound.play('sfx_hack', { volume: 0.8 });
|
this.sound.play('sfx_hack', { volume: 0.8 });
|
||||||
|
|
||||||
// Sprite 42 pulses on source for 1.5s before copied skills fire
|
// Sprite 42 pulses on source for 1.5s before copied skills fire
|
||||||
const runFires = () => {
|
const runFires = () => {
|
||||||
|
|
@ -4321,10 +4321,17 @@ export class BattleScene extends Phaser.Scene {
|
||||||
const fire = fires[idx];
|
const fire = fires[idx];
|
||||||
const cb = () => nextFire(idx + 1);
|
const cb = () => nextFire(idx + 1);
|
||||||
if (fire.skill === 'strike') this._animateStrikeFire(attacker, fire, cb);
|
if (fire.skill === 'strike') this._animateStrikeFire(attacker, fire, cb);
|
||||||
|
else if (fire.skill === 'strikeAll') this._animateStrikeFire(attacker, fire, cb);
|
||||||
else if (fire.skill === 'mortar') this._animateMortarFire(attacker, fire, cb);
|
else if (fire.skill === 'mortar') this._animateMortarFire(attacker, fire, cb);
|
||||||
else if (fire.skill === 'pierce') this._animatePierceFire(attacker, fire, cb);
|
else if (fire.skill === 'pierce') this._animatePierceFire(attacker, fire, cb);
|
||||||
else if (fire.skill === 'swipe') this._animateSwipeSequence(attacker, [fire], cb);
|
else if (fire.skill === 'swipe') this._animateSwipeSequence(attacker, [fire], cb);
|
||||||
else if (fire.skill === 'drain') this._animateDrainFire(fire, cb);
|
else if (fire.skill === 'drain') this._animateDrainFire(fire, cb);
|
||||||
|
else if (fire.skill === 'jam') this._animateJamFire(fire, cb);
|
||||||
|
else if (fire.skill === 'venom') this._animateVenomApply(fire, cb);
|
||||||
|
else if (fire.skill === 'venomAll') this._animateVenomApplyAll(fire, cb);
|
||||||
|
else if (fire.skill === 'smite') this._animateSmiteApply(fire, cb);
|
||||||
|
else if (fire.skill === 'smiteAll') this._animateSmiteApplyAll(fire, cb);
|
||||||
|
else if (fire.skill === 'molt') this._animateMolt(fire, cb);
|
||||||
else cb();
|
else cb();
|
||||||
};
|
};
|
||||||
nextFire(0);
|
nextFire(0);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue