class AttackSkillLogic extends SkillLogic { willBeExecuted ( data ) { let hasTarget = data . skill . range . hasValidTarget ( data . executor ) ; return super . willBeExecuted ( data ) && hasTarget ; } execute ( data ) { let skill = data . skill ; skill . getReady ( data . executor ) ; let targets = skill . range . targets ; if ( RangeFactory . isEnemyScaledRange ( skill . skillRange ) ) { data . scaledRatio = RangeFactory . getScaledRatio ( skill . skillRange , targets . length ) ; } if ( ! RangeFactory . isEnemyRandomRange ( data . skill . skillRange ) && data . skill . isIndirectSkill ( ) ) { this . executeAoeAttack ( data , targets ) ; } else { this . executeNonAoeAttack ( data ) ; } } /**
     * Execute a fork/sweeping/random attack
     * Multiple protection is possible
     */ executeNonAoeAttack ( data ) { let target ; let attackCount = 0 ; while ( ( target = data . skill . getTarget ( data . executor ) ) && ! data . executor . isDead && data . executor . canAttack ( ) ) { if ( RangeFactory . isEnemyVaryingRange ( data . skill . skillRange ) ) { var varyingRatio = RangeFactory . getVaryingRatio ( data . skill . skillRange , attackCount ) ; } this . processAttackAgainstSingleTarget ( data . executor , target , data . skill , data . scaledRatio , varyingRatio ) ; attackCount ++ ; } } /**
     * Execute an AoE attack
     */ executeAoeAttack ( data , targets ) { let skill = data . skill ; let executor = data . executor ; if ( skill . isIndirectSkill ( ) ) { shuffle ( targets ) ; let aoeReactiveSkillActivated = false ; let targetsAttacked = [ ] ; for ( let i = 0 ; i < targets . length ; i ++ ) { let targetCard = targets [ i ] ; if ( targetCard . isDead ) { continue ; } let protectSkillActivated = false ; if ( ! aoeReactiveSkillActivated && ! targetsAttacked [ targetCard . id ] ) { let protectData = this . battleModel . processProtect ( executor , targetCard , skill , targetsAttacked , data . scaledRatio ) ; protectSkillActivated = protectData . activated ; if ( protectSkillActivated ) { aoeReactiveSkillActivated = true ; } } if ( ! protectSkillActivated && ! targetsAttacked [ targetCard . id ] ) { let defenseSkill = targetCard . getRandomDefenseSkill ( ) ; let defenseData = { executor : targetCard , skill : defenseSkill , attacker : executor , } ; this . battleModel . processDamagePhase ( { attacker : executor , target : targetCard , skill : skill , scaledRatio : data . scaledRatio } ) ; targetsAttacked [ targetCard . id ] = true ; if ( ! executor . justMissed && ! targetCard . justEvaded && ! targetCard . isDead ) { if ( Skill . isDebuffAttackSkill ( skill . id ) ) { if ( Math . random ( ) <= skill . skillFuncArg3 ) { DebuffSkillLogic . processDebuff ( executor , targetCard , skill ) ; } } else if ( skill . skillFunc === ENUM . SkillFunc . ATTACK || skill . skillFunc === ENUM . SkillFunc . MAGIC ) { AfflictionSkillLogic . processAffliction ( executor , targetCard , skill ) ; } } if ( defenseSkill && defenseSkill . willBeExecuted ( defenseData ) && ! aoeReactiveSkillActivated ) { defenseSkill . execute ( defenseData ) ; aoeReactiveSkillActivated = true ; } } if ( skill . skillFunc === ENUM . SkillFunc . DRAIN_ATTACK || skill . skillFunc === ENUM . SkillFunc . DRAIN_MAGIC ) { this . processDrainPhase ( executor , skill ) ; } if ( skill . skillFunc === ENUM . SkillFunc . ABSORB_ATTACK || skill . skillFunc === ENUM . SkillFunc . ABSORB_MAGIC ) { new AbsorbSkillLogic ( ) . absorbTarget ( executor , targetCard , skill ) ; } this . clearAllCardsDamagePhaseData ( ) ; } } } processAttackAgainstSingleTarget ( executor , target , skill , scaledRatio , varyingRatio ? ) { let protectData = this . battleModel . processProtect ( executor , target , skill , null , scaledRatio , varyingRatio ) ; if ( ! protectData . activated ) { let defenseSkill = target . getRandomDefenseSkill ( ) ; let defenseData = { executor : target , skill : defenseSkill , attacker : executor , } ; this . battleModel . processDamagePhase ( { attacker : executor , target : target , skill : skill , scaledRatio : scaledRatio , varyingRatio : varyingRatio } ) ; if ( ! executor . justMissed && ! target . justEvaded && ! target . isDead ) { if ( Skill . isDebuffAttackSkill ( skill . id ) ) { if ( Math . random ( ) <= skill . skillFuncArg3 ) { DebuffSkillLogic . processDebuff ( executor , target , skill ) ; } } else if ( skill . skillFunc === ENUM . SkillFunc . ATTACK || skill . skillFunc === ENUM . SkillFunc . MAGIC ) { AfflictionSkillLogic . processAffliction ( executor , target , skill ) ; } } if ( defenseSkill && defenseSkill . willBeExecuted ( defenseData ) ) { defenseSkill . execute ( defenseData ) ; } } if ( skill . skillFunc === ENUM . SkillFunc . DRAIN_ATTACK || skill . skillFunc === ENUM . SkillFunc . DRAIN_MAGIC ) { this . processDrainPhase ( executor , skill ) ; } if ( skill . skillFunc === ENUM . SkillFunc . ABSORB_ATTACK || skill . skillFunc === ENUM . SkillFunc . ABSORB_MAGIC ) { new AbsorbSkillLogic ( ) . absorbTarget ( executor , target , skill ) ; } this . clearAllCardsDamagePhaseData ( ) ; } /**
     * Process the drain phase for drain attacks
     */ processDrainPhase ( executor , skill ) { let healRange = RangeFactory . getRange ( skill . skillFuncArg4 ) ; healRange . getReady ( executor , ( card ) => ! card . isFullHealth ( ) ) ; assert ( ! ( healRange instanceof RandomRange ) , "can't do this with random ranges!" ) ; if ( healRange . targets . length === 0 ) { return ; } let healAmount = Math . floor ( ( executor . lastBattleDamageDealt * skill . skillFuncArg2 ) / healRange . targets . length ) ; let target ; while ( target = healRange . getTarget ( executor ) ) { this . battleModel . damageToTargetDirectly ( target , - 1 * healAmount , " healing" ) ; } } }