Apply treasure equipment battle effects
This commit is contained in:
@@ -43,14 +43,15 @@ Build a small complete tactical RPG loop that can grow into a longer Romance of
|
||||
- Camp progress timeline tab that summarizes Liu Bei's long campaign arc, completed battles, current chapter, latest battle, and next major chapter
|
||||
- Tactical sortie preparation panel with battle-specific sortie limits, recommended officers with reasons, class role, named equipment, core stats, bond partner, next-map terrain suitability, deployment preview, formation roles, active bond count, recruited-officer count, reserve roster summary, and readiness advice for each deployable officer
|
||||
- Officer collection support in camp, including full roster status, selected/reserve/recommended markers, and post-battle reserve training growth for benched officers
|
||||
- Treasure equipment effects wired into battle previews and resolution, including named weapon damage bonuses, defensive treasure mitigation, support recovery bonuses, turn-start charm recovery, and equipment-specific growth bonuses
|
||||
- Flow verification script from title through the eighteenth battle victory, recruit sortie selection, Liu Biao visit rewards, Zhuge Liang recruitment, Bowang camp state, campaign timeline state, and camp save state
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. Continue the Red Cliffs preparation chapter into Changban and the Jiangdong envoy route
|
||||
2. Apply treasure equipment effects to damage, defense, recovery, and command rules
|
||||
3. Add more recruitable officers as the campaign moves toward Red Cliffs, Jing Province, Yi Province, and Shu Han
|
||||
4. Expand reserve training into explicit drill choices, class practice, and bond-focused camp assignments
|
||||
2. Add more recruitable officers as the campaign moves toward Red Cliffs, Jing Province, Yi Province, and Shu Han
|
||||
3. Expand reserve training into explicit drill choices, class practice, and bond-focused camp assignments
|
||||
4. Add a dedicated treasure/equipment management view so players can compare special effects and growth
|
||||
5. Keep expanding scenarios through the long campaign instead of treating the current slice as an ending
|
||||
|
||||
## Content Direction
|
||||
|
||||
@@ -1814,6 +1814,9 @@ try {
|
||||
const eighteenthEnemies = eighteenthBattleState.units.filter((unit) => unit.faction === 'enemy');
|
||||
const eighteenthAllies = eighteenthBattleState.units.filter((unit) => unit.faction === 'ally');
|
||||
const eighteenthEnemyBehaviors = new Set(eighteenthEnemies.map((unit) => unit.ai));
|
||||
const treasureLabels = new Set(
|
||||
eighteenthBattleState.treasureEffectPreviews?.flatMap((preview) => preview.equipmentEffectLabels ?? []) ?? []
|
||||
);
|
||||
if (
|
||||
eighteenthBattleState.camera?.mapWidth !== 36 ||
|
||||
eighteenthBattleState.camera?.mapHeight !== 26 ||
|
||||
@@ -1823,9 +1826,13 @@ try {
|
||||
!eighteenthEnemyBehaviors.has('guard') ||
|
||||
!eighteenthEnemyBehaviors.has('hold') ||
|
||||
!eighteenthEnemies.some((unit) => unit.id === 'bowang-leader-xiahou-dun') ||
|
||||
!eighteenthAllies.some((unit) => unit.id === 'zhuge-liang')
|
||||
!eighteenthAllies.some((unit) => unit.id === 'zhuge-liang') ||
|
||||
!treasureLabels.has('자웅일대검 공명') ||
|
||||
(!treasureLabels.has('청룡언월도 무력 우위') && !treasureLabels.has('청룡언월도 대도')) ||
|
||||
!treasureLabels.has('장팔사모 치명') ||
|
||||
!treasureLabels.has('백우선 책략')
|
||||
) {
|
||||
throw new Error(`Expected eighteenth battle to use Bowang map, Xiahou Dun objective, mixed AI, and deployed Zhuge Liang: ${JSON.stringify(eighteenthBattleState)}`);
|
||||
throw new Error(`Expected eighteenth battle to use Bowang map, Xiahou Dun objective, mixed AI, deployed Zhuge Liang, and treasure equipment effects: ${JSON.stringify(eighteenthBattleState)}`);
|
||||
}
|
||||
|
||||
await page.evaluate(() => window.__HEROS_DEBUG__?.forceBattleOutcome('victory'));
|
||||
|
||||
@@ -404,6 +404,11 @@ type CombatPreview = {
|
||||
damage: number;
|
||||
bondDamageBonus: number;
|
||||
bondLabel?: string;
|
||||
equipmentDamageBonus: number;
|
||||
equipmentDamageReduction: number;
|
||||
equipmentHitBonus: number;
|
||||
equipmentCriticalBonus: number;
|
||||
equipmentEffectLabels: string[];
|
||||
hitRate: number;
|
||||
criticalRate: number;
|
||||
counterAvailable: boolean;
|
||||
@@ -2244,9 +2249,12 @@ export class BattleScene extends Phaser.Scene {
|
||||
private renderAttackPreview(preview: CombatPreview) {
|
||||
const counter = preview.counterAvailable ? ' / 반격 가능' : '';
|
||||
const bond = preview.bondDamageBonus > 0 && preview.bondLabel ? `\n공명 ${preview.bondLabel} 피해 +${preview.bondDamageBonus}%` : '';
|
||||
const equipment = preview.equipmentEffectLabels.length > 0
|
||||
? `\n보물 ${preview.equipmentEffectLabels.join(', ')} (${this.equipmentPreviewBonusText(preview)})`
|
||||
: '';
|
||||
this.renderUnitDetail(
|
||||
preview.defender,
|
||||
`${preview.attacker.name} ${commandLabels[preview.action]} 예측\n피해 ${preview.damage} / 명중 ${preview.hitRate}% / 치명 ${preview.criticalRate}%\n지형 ${preview.terrainLabel}${counter}${bond}`
|
||||
`${preview.attacker.name} ${commandLabels[preview.action]} 예측\n피해 ${preview.damage} / 명중 ${preview.hitRate}% / 치명 ${preview.criticalRate}%\n지형 ${preview.terrainLabel}${counter}${bond}${equipment}`
|
||||
);
|
||||
}
|
||||
|
||||
@@ -2263,6 +2271,16 @@ export class BattleScene extends Phaser.Scene {
|
||||
);
|
||||
}
|
||||
|
||||
private equipmentPreviewBonusText(preview: CombatPreview) {
|
||||
const parts = [
|
||||
preview.equipmentDamageBonus > 0 ? `피해 +${preview.equipmentDamageBonus}%` : '',
|
||||
preview.equipmentDamageReduction > 0 ? `피해 -${preview.equipmentDamageReduction}%` : '',
|
||||
preview.equipmentHitBonus > 0 ? `명중 +${preview.equipmentHitBonus}` : '',
|
||||
preview.equipmentCriticalBonus > 0 ? `치명 +${preview.equipmentCriticalBonus}` : ''
|
||||
].filter(Boolean);
|
||||
return parts.join(' / ') || '보정 없음';
|
||||
}
|
||||
|
||||
private finishUnitAction(unit: UnitData, message: string) {
|
||||
this.actedUnitIds.add(unit.id);
|
||||
this.phase = 'idle';
|
||||
@@ -3198,7 +3216,9 @@ export class BattleScene extends Phaser.Scene {
|
||||
const attackPower = this.actionPower(attacker, action, usable);
|
||||
const defensePower = this.actionDefense(defender, action, terrainRule.defenseBonus);
|
||||
const bondBonus = attacker.faction === 'ally' ? this.strongestBondBonus(attacker.id) : { damageBonus: 0, chainRate: 0 };
|
||||
const damage = Phaser.Math.Clamp(Math.round((attackPower - defensePower) * (1 + bondBonus.damageBonus / 100)), 3, defender.maxHp);
|
||||
const equipmentEffect = this.combatEquipmentEffect(attacker, defender, action, usable);
|
||||
const totalDamageBonus = bondBonus.damageBonus + equipmentEffect.damageBonus - equipmentEffect.damageReduction;
|
||||
const damage = Phaser.Math.Clamp(Math.round((attackPower - defensePower) * (1 + totalDamageBonus / 100)), 3, defender.maxHp);
|
||||
const defenderTerrainRating = getUnitClass(defender.classKey).terrainRatings[terrain] ?? 100;
|
||||
const terrainHitPenalty = Math.floor(terrainRule.defenseBonus / 2) + Math.max(0, Math.floor((defenderTerrainRating - 100) / 4));
|
||||
const hitRate = Phaser.Math.Clamp(
|
||||
@@ -3207,6 +3227,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
Math.floor((attacker.stats.luck - defender.stats.luck) / 8) -
|
||||
terrainHitPenalty +
|
||||
(usable?.accuracyBonus ?? 0) +
|
||||
equipmentEffect.hitBonus +
|
||||
this.hitBuff(attacker),
|
||||
45,
|
||||
98
|
||||
@@ -3217,6 +3238,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
Math.floor((attacker.stats.might - defender.stats.leadership) / 12) +
|
||||
(action === 'attack' && getItem(attacker.equipment.weapon.itemId).rank === 'treasure' ? 2 : 0) +
|
||||
(usable?.criticalBonus ?? 0) +
|
||||
equipmentEffect.criticalBonus +
|
||||
this.criticalBuff(attacker),
|
||||
2,
|
||||
28
|
||||
@@ -3230,6 +3252,11 @@ export class BattleScene extends Phaser.Scene {
|
||||
damage,
|
||||
bondDamageBonus: bondBonus.damageBonus,
|
||||
bondLabel: bondBonus.label,
|
||||
equipmentDamageBonus: equipmentEffect.damageBonus,
|
||||
equipmentDamageReduction: equipmentEffect.damageReduction,
|
||||
equipmentHitBonus: equipmentEffect.hitBonus,
|
||||
equipmentCriticalBonus: equipmentEffect.criticalBonus,
|
||||
equipmentEffectLabels: equipmentEffect.labels,
|
||||
hitRate,
|
||||
criticalRate,
|
||||
counterAvailable: this.canCounterAttack(defender, attacker, action),
|
||||
@@ -3277,7 +3304,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
const critical = hit && this.rollPercent(preview.criticalRate);
|
||||
const damage = hit ? Phaser.Math.Clamp(Math.round(preview.damage * (critical ? 1.5 : 1)), 1, defender.hp) : 0;
|
||||
const attackerGrowth = this.awardEquipmentExp(attacker, action === 'attack' ? 'weapon' : 'accessory', this.attackerEquipmentExpGain(attacker, action));
|
||||
const armorGrowth = this.awardEquipmentExp(defender, 'armor', hit ? 6 : 3);
|
||||
const armorGrowth = this.awardEquipmentExp(defender, 'armor', this.defenderArmorExpGain(defender, hit, preview));
|
||||
const characterGrowth = this.awardCharacterExp(attacker, this.characterExpGain(preview, damage, hit, critical));
|
||||
const bondGrowth = attacker.faction === 'ally' && !isCounter ? this.recordBondAttackIntent(attacker, defender) : [];
|
||||
const bondExp = bondGrowth.reduce((total, growth) => total + growth.amount, 0);
|
||||
@@ -3367,7 +3394,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
this.flashSupport(target, usable.name, '#ffdf7b');
|
||||
}
|
||||
|
||||
const equipmentGrowth = this.awardEquipmentExp(user, 'accessory', usable.command === 'strategy' ? 7 : 5);
|
||||
const equipmentGrowth = this.awardEquipmentExp(user, 'accessory', this.supportEquipmentExpGain(user, usable));
|
||||
const characterGrowth = this.awardCharacterExp(user, usable.effect === 'heal' ? 8 : 6);
|
||||
this.recordSupportStats(user, healAmount);
|
||||
|
||||
@@ -3385,7 +3412,89 @@ export class BattleScene extends Phaser.Scene {
|
||||
|
||||
private supportHealAmount(user: UnitData, target: UnitData, usable: BattleUsable) {
|
||||
const bonus = usable.command === 'strategy' ? Math.floor(user.stats.intelligence / 12) : Math.floor(user.stats.luck / 14);
|
||||
return Math.min(target.maxHp - target.hp, Math.max(1, usable.power + bonus));
|
||||
const equipmentBonus =
|
||||
getItem(user.equipment.weapon.itemId).id === 'white-feather-fan' && usable.command === 'strategy'
|
||||
? 3
|
||||
: getItem(user.equipment.accessory.itemId).id === 'peach-charm'
|
||||
? 2
|
||||
: 0;
|
||||
return Math.min(target.maxHp - target.hp, Math.max(1, usable.power + bonus + equipmentBonus));
|
||||
}
|
||||
|
||||
private combatEquipmentEffect(attacker: UnitData, defender: UnitData, action: DamageCommand, usable?: BattleUsable) {
|
||||
const labels: string[] = [];
|
||||
let damageBonus = 0;
|
||||
let damageReduction = 0;
|
||||
let hitBonus = 0;
|
||||
let criticalBonus = 0;
|
||||
|
||||
const weapon = getItem(attacker.equipment.weapon.itemId);
|
||||
const armor = getItem(defender.equipment.armor.itemId);
|
||||
const accessory = getItem(attacker.equipment.accessory.itemId);
|
||||
const defenderAccessory = getItem(defender.equipment.accessory.itemId);
|
||||
const bondBonus = attacker.faction === 'ally' ? this.strongestBondBonus(attacker.id) : { damageBonus: 0, chainRate: 0 };
|
||||
|
||||
if (action === 'attack' && weapon.id === 'twin-oath-blades' && bondBonus.chainRate > 0) {
|
||||
damageBonus += 6;
|
||||
hitBonus += 4;
|
||||
labels.push('자웅일대검 공명');
|
||||
}
|
||||
|
||||
if (action === 'attack' && weapon.id === 'green-dragon-glaive') {
|
||||
damageBonus += attacker.stats.might > defender.stats.might ? 8 : 4;
|
||||
labels.push(attacker.stats.might > defender.stats.might ? '청룡언월도 무력 우위' : '청룡언월도 대도');
|
||||
}
|
||||
|
||||
if (action === 'attack' && weapon.id === 'serpent-spear') {
|
||||
criticalBonus += 8;
|
||||
if (attacker.hp <= Math.ceil(attacker.maxHp * 0.55)) {
|
||||
damageBonus += 5;
|
||||
labels.push('장팔사모 투지');
|
||||
} else {
|
||||
labels.push('장팔사모 치명');
|
||||
}
|
||||
}
|
||||
|
||||
if ((action === 'strategy' || usable?.command === 'strategy') && weapon.id === 'white-feather-fan') {
|
||||
damageBonus += usable?.effect === 'damage' || action === 'strategy' ? 7 : 0;
|
||||
hitBonus += 6;
|
||||
labels.push('백우선 책략');
|
||||
}
|
||||
|
||||
if (accessory.id === 'war-manual' && attacker.faction === 'ally' && bondBonus.damageBonus > 0) {
|
||||
damageBonus += 3;
|
||||
hitBonus += 3;
|
||||
labels.push('병법서 공명 보정');
|
||||
}
|
||||
|
||||
if (accessory.id === 'bravery-token' && attacker.hp <= Math.ceil(attacker.maxHp * 0.45)) {
|
||||
damageBonus += 6;
|
||||
criticalBonus += 4;
|
||||
labels.push('호담패 저력');
|
||||
}
|
||||
|
||||
if (accessory.id === 'wind-quiver' && (attacker.classKey === 'archer' || weapon.id === 'short-bow')) {
|
||||
hitBonus += 8;
|
||||
criticalBonus += 3;
|
||||
labels.push('바람 화살통 명중');
|
||||
}
|
||||
|
||||
if (armor.id === 'reinforced-lamellar' && action === 'attack') {
|
||||
damageReduction += 8;
|
||||
labels.push('철린갑 피해 감소');
|
||||
}
|
||||
|
||||
if (armor.id === 'oath-robe' && defender.faction === 'ally' && this.strongestBondBonus(defender.id).damageBonus > 0) {
|
||||
damageReduction += 4;
|
||||
labels.push('도원포 공명 방호');
|
||||
}
|
||||
|
||||
if (defenderAccessory.id === 'peach-charm' && defender.hp <= Math.ceil(defender.maxHp * 0.4)) {
|
||||
damageReduction += 4;
|
||||
labels.push('복숭아 부적 가호');
|
||||
}
|
||||
|
||||
return { damageBonus, damageReduction, hitBonus, criticalBonus, labels };
|
||||
}
|
||||
|
||||
private actionPower(unit: UnitData, action: DamageCommand, usable?: BattleUsable) {
|
||||
@@ -3436,9 +3545,10 @@ export class BattleScene extends Phaser.Scene {
|
||||
const outcome = this.formatCombatOutcome(result);
|
||||
const defeated = result.defeated ? `\n${result.defender.name} 퇴각!` : `\n${result.defender.name} HP ${result.defender.hp}/${result.defender.maxHp}`;
|
||||
const bondBonus = result.bondDamageBonus > 0 && result.bondLabel ? `\n공명 효과 ${result.bondLabel}: 피해 +${result.bondDamageBonus}%` : '';
|
||||
const equipment = result.equipmentEffectLabels.length > 0 ? `\n보물 효과: ${result.equipmentEffectLabels.join(', ')}` : '';
|
||||
const bond = result.bondExp > 0 ? `\n공명 경험치 +${result.bondExp}` : '';
|
||||
const counter = result.counter ? `\n${this.formatCounterLine(result.counter)}` : '';
|
||||
return `${result.attacker.name} ${result.usable?.name ?? commandLabels[result.action]}\n${outcome}${defeated}${bondBonus}\n장수 경험치 +${result.characterGrowth.amount}\n${this.formatEquipmentGrowth(result.attackerGrowth)}\n${this.formatEquipmentGrowth(result.defenderGrowth)}${bond}${counter}`;
|
||||
return `${result.attacker.name} ${result.usable?.name ?? commandLabels[result.action]}\n${outcome}${defeated}${bondBonus}${equipment}\n장수 경험치 +${result.characterGrowth.amount}\n${this.formatEquipmentGrowth(result.attackerGrowth)}\n${this.formatEquipmentGrowth(result.defenderGrowth)}${bond}${counter}`;
|
||||
}
|
||||
|
||||
private formatCombatOutcome(result: CombatResult) {
|
||||
@@ -3469,6 +3579,9 @@ export class BattleScene extends Phaser.Scene {
|
||||
if (result.bondExp > 0) {
|
||||
lines.push(`공명 경험치 +${result.bondExp}`);
|
||||
}
|
||||
if (result.equipmentEffectLabels.length > 0) {
|
||||
lines.push(`보물 효과: ${result.equipmentEffectLabels.join(', ')}`);
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
@@ -5409,7 +5522,8 @@ export class BattleScene extends Phaser.Scene {
|
||||
.forEach((unit) => {
|
||||
const terrain = battleMap.terrain[unit.y][unit.x];
|
||||
const terrainRule = getTerrainRule(terrain);
|
||||
const hpGain = Math.min(terrainRule.recoveryHp ?? 0, unit.maxHp - unit.hp);
|
||||
const itemRecovery = this.turnStartEquipmentRecovery(unit);
|
||||
const hpGain = Math.min((terrainRule.recoveryHp ?? 0) + itemRecovery.amount, unit.maxHp - unit.hp);
|
||||
const moraleBonus = terrainRule.moraleBonus ?? 0;
|
||||
if (hpGain <= 0 && moraleBonus <= 0) {
|
||||
return;
|
||||
@@ -5423,7 +5537,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
const parts = [
|
||||
hpGain > 0 ? `병력 +${hpGain}` : '',
|
||||
hpGain > 0 ? `병력 +${hpGain}${itemRecovery.label ? ` (${itemRecovery.label})` : ''}` : '',
|
||||
moraleBonus > 0 ? `사기 +${moraleBonus}` : ''
|
||||
].filter(Boolean);
|
||||
messages.push(`${unit.name} ${terrainRule.label}: ${parts.join(' / ')}`);
|
||||
@@ -5440,6 +5554,24 @@ export class BattleScene extends Phaser.Scene {
|
||||
return message;
|
||||
}
|
||||
|
||||
private turnStartEquipmentRecovery(unit: UnitData) {
|
||||
let amount = 0;
|
||||
const labels: string[] = [];
|
||||
const accessory = getItem(unit.equipment.accessory.itemId);
|
||||
const armor = getItem(unit.equipment.armor.itemId);
|
||||
|
||||
if (accessory.id === 'peach-charm' && unit.hp <= Math.ceil(unit.maxHp * 0.55)) {
|
||||
amount += 4;
|
||||
labels.push('복숭아 부적');
|
||||
}
|
||||
if (armor.id === 'oath-robe' && this.strongestBondBonus(unit.id).damageBonus > 0) {
|
||||
amount += 2;
|
||||
labels.push('도원포');
|
||||
}
|
||||
|
||||
return { amount, label: labels.join('/') };
|
||||
}
|
||||
|
||||
private applyTerrainMorale(unit: UnitData, moraleBonus: number) {
|
||||
const existing = this.battleBuffs.get(unit.id);
|
||||
this.battleBuffs.set(unit.id, {
|
||||
@@ -5611,7 +5743,25 @@ export class BattleScene extends Phaser.Scene {
|
||||
private weaponExpGain(unit: UnitData) {
|
||||
const weapon = getItem(unit.equipment.weapon.itemId);
|
||||
const bonus = this.strongestBondBonus(unit.id);
|
||||
return 8 + (weapon.rank === 'treasure' ? 2 : 0) + (bonus.chainRate > 0 ? 2 : 0);
|
||||
const oathBonus = weapon.id === 'twin-oath-blades' && bonus.chainRate > 0 ? 2 : 0;
|
||||
const strategyWeaponBonus = weapon.id === 'white-feather-fan' ? 2 : 0;
|
||||
return 8 + (weapon.rank === 'treasure' ? 2 : 0) + (bonus.chainRate > 0 ? 2 : 0) + oathBonus + strategyWeaponBonus;
|
||||
}
|
||||
|
||||
private defenderArmorExpGain(unit: UnitData, hit: boolean, preview: CombatPreview) {
|
||||
const armor = getItem(unit.equipment.armor.itemId);
|
||||
const bondGuardBonus = armor.id === 'oath-robe' && preview.equipmentEffectLabels.includes('도원포 공명 방호') ? 2 : 0;
|
||||
const treasureGuardBonus = armor.id === 'reinforced-lamellar' && hit ? 2 : 0;
|
||||
return (hit ? 6 : 3) + bondGuardBonus + treasureGuardBonus;
|
||||
}
|
||||
|
||||
private supportEquipmentExpGain(user: UnitData, usable: BattleUsable) {
|
||||
const accessory = getItem(user.equipment.accessory.itemId);
|
||||
const weapon = getItem(user.equipment.weapon.itemId);
|
||||
const strategyBonus = usable.command === 'strategy' ? 2 : 0;
|
||||
const manualBonus = accessory.id === 'war-manual' ? 2 : 0;
|
||||
const featherBonus = weapon.id === 'white-feather-fan' && usable.command === 'strategy' ? 2 : 0;
|
||||
return (usable.command === 'strategy' ? 7 : 5) + strategyBonus + manualBonus + featherBonus;
|
||||
}
|
||||
|
||||
private awardEquipmentExp(unit: UnitData, slot: EquipmentSlot, amount: number): EquipmentGrowthResult {
|
||||
@@ -6846,6 +6996,7 @@ export class BattleScene extends Phaser.Scene {
|
||||
selectedUsable: this.selectedUsable?.id ?? null,
|
||||
itemStocks: this.serializeItemStocks(),
|
||||
battleBuffs: Array.from(this.battleBuffs.values()).map((buff) => ({ ...buff })),
|
||||
treasureEffectPreviews: this.debugTreasureEffectPreviews(),
|
||||
units: battleUnits.map((unit) => ({
|
||||
id: unit.id,
|
||||
name: unit.name,
|
||||
@@ -6873,6 +7024,34 @@ export class BattleScene extends Phaser.Scene {
|
||||
};
|
||||
}
|
||||
|
||||
private debugTreasureEffectPreviews() {
|
||||
return ['liu-bei', 'guan-yu', 'zhang-fei', 'zhuge-liang']
|
||||
.map((unitId) => battleUnits.find((unit) => unit.id === unitId && unit.hp > 0))
|
||||
.filter((unit): unit is UnitData => Boolean(unit))
|
||||
.map((unit) => {
|
||||
const target = this.findNearestEnemy(unit);
|
||||
if (!target) {
|
||||
return undefined;
|
||||
}
|
||||
const action: DamageCommand = unit.id === 'zhuge-liang' ? 'strategy' : 'attack';
|
||||
const preview = this.combatPreview(unit, target, action);
|
||||
return {
|
||||
attackerId: unit.id,
|
||||
defenderId: target.id,
|
||||
action,
|
||||
damage: preview.damage,
|
||||
hitRate: preview.hitRate,
|
||||
criticalRate: preview.criticalRate,
|
||||
equipmentDamageBonus: preview.equipmentDamageBonus,
|
||||
equipmentDamageReduction: preview.equipmentDamageReduction,
|
||||
equipmentHitBonus: preview.equipmentHitBonus,
|
||||
equipmentCriticalBonus: preview.equipmentCriticalBonus,
|
||||
equipmentEffectLabels: preview.equipmentEffectLabels
|
||||
};
|
||||
})
|
||||
.filter((preview): preview is NonNullable<typeof preview> => Boolean(preview));
|
||||
}
|
||||
|
||||
debugForceBattleOutcome(outcome: BattleOutcome = 'victory') {
|
||||
if (!import.meta.env.DEV || this.battleOutcome) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user