import * as _ from "lodash" ; import { Ability , IAbilityNode } from "../ability" ; import { Encounter } from "../combat" ; import { DamageType } from "../damagetype" ; import { Entity } from "../entity" ; import { Party } from "../party" ; import { StatusEffect } from "../statuseffect" ; import { IParse , Text } from "../text" ; export namespace AbilityNode { export function DefaultParser ( caster , target ? ) { let parse = { } ; if ( caster ) { parse = caster . ParserPronouns ( parse ) ; parse . name = caster . nameDesc ( ) ; parse . Name = caster . NameDesc ( ) ; parse . poss = caster . possessive ( ) ; parse . Poss = caster . Possessive ( ) ; parse . y = caster . plural ( ) ? "y" : "ies" ; parse . s = caster . plural ( ) ? "s" : "" ; parse . es = caster . plural ( ) ? "es" : "" ; parse . notS = caster . plural ( ) ? "" : "s" ; parse . notEs = caster . plural ( ) ? "" : "es" ; parse . is = caster . is ( ) ; parse . has = caster . has ( ) ; parse . hand = ( ) => caster . HandDesc ( ) ; } if ( target ) { parse = target . ParserPronouns ( parse , "t" ) ; parse . tname = target . nameDesc ( ) ; parse . tName = target . NameDesc ( ) ; parse . tposs = target . possessive ( ) ; parse . tPoss = target . Possessive ( ) ; parse . ty = target . plural ( ) ? "y" : "ies" ; parse . ts = target . plural ( ) ? "s" : "" ; parse . tes = target . plural ( ) ? "es" : "" ; parse . tnotS = target . plural ( ) ? "" : "s" ; parse . tnotEs = target . plural ( ) ? "" : "es" ; parse . tis = target . is ( ) ; parse . thas = target . has ( ) ; } return parse ; } export namespace Template { export function Blank ( node = { } ) { node . damageTypeNode = node . damageType ? new DamageType ( node . damageType ) : undefined ; node . cost = node . cost || { hp : undefined , sp : undefined , lp : undefined } ; node . toHit = _ . has ( node , "toHit" ) ? node . toHit : AbilityNode . ToHit . Regular ; node . toDamage = _ . has ( node , "toDamage" ) ? node . toDamage : AbilityNode . ToDamage . Regular ; node . damagePool = node . damagePool || [ ] ; node . hitFunc = node . hitFunc || AbilityNode . HitFunc . Physical ; node . evadeFunc = node . evadeFunc || AbilityNode . EvadeFunc . Physical ; node . atkFunc = node . atkFunc || AbilityNode . AtkFunc . Physical ; node . defFunc = node . defFunc || AbilityNode . DefFunc . Physical ; node . damageFunc = node . damageFunc || AbilityNode . DamageFunc . Physical ; return _ . bind ( AbilityNode . Run , node ) ; } export function Physical ( node = { } ) { node . damageTypeNode = node . damageType ? new DamageType ( node . damageType ) : undefined ; node . toHit = _ . has ( node , "toHit" ) ? node . toHit : AbilityNode . ToHit . Regular ; node . toDamage = _ . has ( node , "toDamage" ) ? node . toDamage : AbilityNode . ToDamage . Regular ; node . hitFunc = node . hitFunc || AbilityNode . HitFunc . Physical ; node . evadeFunc = node . evadeFunc || AbilityNode . EvadeFunc . Physical ; node . atkFunc = node . atkFunc || AbilityNode . AtkFunc . Physical ; node . defFunc = node . defFunc || AbilityNode . DefFunc . Physical ; node . damageFunc = node . damageFunc || AbilityNode . DamageFunc . Physical ; node . damagePool = node . damagePool || [ AbilityNode . DamagePool . Physical ] ; return _ . bind ( AbilityNode . Run , node ) ; } export function Magical ( node = { } ) { node . damageTypeNode = node . damageType ? new DamageType ( node . damageType ) : undefined ; node . toHit = _ . has ( node , "toHit" ) ? node . toHit : AbilityNode . ToHit . Regular ; node . toDamage = _ . has ( node , "toDamage" ) ? node . toDamage : AbilityNode . ToDamage . Regular ; node . hitFunc = node . hitFunc || AbilityNode . HitFunc . Magical ; node . evadeFunc = node . evadeFunc || AbilityNode . EvadeFunc . Magical ; node . atkFunc = node . atkFunc || AbilityNode . AtkFunc . Magical ; node . defFunc = node . defFunc || AbilityNode . DefFunc . Magical ; node . damageFunc = node . damageFunc || AbilityNode . DamageFunc . Magical ; node . damagePool = node . damagePool || [ AbilityNode . DamagePool . Physical ] ; return _ . bind ( AbilityNode . Run , node ) ; } export function Lust ( node = { } ) { node . damageTypeNode = node . damageType ? new DamageType ( node . damageType ) : undefined ; node . toHit = _ . has ( node , "toHit" ) ? node . toHit : AbilityNode . ToHit . Regular ; node . toDamage = _ . has ( node , "toDamage" ) ? node . toDamage : AbilityNode . ToDamage . Regular ; node . hitFunc = node . hitFunc || AbilityNode . HitFunc . Lust ; node . evadeFunc = node . evadeFunc || AbilityNode . EvadeFunc . Lust ; node . atkFunc = node . atkFunc || AbilityNode . AtkFunc . Lust ; node . defFunc = node . defFunc || AbilityNode . DefFunc . Lust ; node . damageFunc = node . damageFunc || AbilityNode . DamageFunc . Lust ; node . damagePool = node . damagePool || [ AbilityNode . DamagePool . Lust ] ; return _ . bind ( AbilityNode . Run , node ) ; } export function Heal ( node = { } ) { node . toHit = _ . has ( node , "toHit" ) ? node . toHit : undefined ; node . toDamage = _ . has ( node , "toDamage" ) ? node . toDamage : AbilityNode . ToDamage . Heal ; node . atkFunc = node . atkFunc || AbilityNode . AtkFunc . Magical ; node . damageFunc = node . damageFunc || AbilityNode . DamageFunc . Magical ; node . damagePool = node . damagePool || [ AbilityNode . DamagePool . Physical ] ; return _ . bind ( AbilityNode . Run , node ) ; } export function Fallthrough ( node = { } ) { node . onDamage = node . onDamage || [ ] ; node . onAbsorb = node . onAbsorb || [ ] ; node . fraction = node . fraction || 1 ; node . damageFunc = node . damageFunc || AbilityNode . DamageFunc . Physical ; node . damagePool = node . damagePool || [ AbilityNode . DamagePool . Physical ] ; return _ . bind ( RunFallthrough , node ) ; } function RunFallthrough ( ability , encounter , caster , target , result ) { const that = this ; const fraction = that . fraction || 1 ; const dmg = fraction * result ; const onattack = that . damageFunc ( caster , target , dmg ) ; if ( onattack ) { if ( dmg <= 0 ) { _ . each ( that . onDamage , ( node ) => { node ( ability , encounter , caster , target , dmg ) ; } ) ; } else { _ . each ( that . onAbsorb , ( node ) => { node ( ability , encounter , caster , target , dmg ) ; } ) ; } } } export function AddSpellstack ( node = { } ) { return _ . bind ( RunAddSpellstack , node ) ; } function RunAddSpellstack ( ability , encounter , caster , target , result ) { const that = this ; const value = _ . isFunction ( that . value ) ? that . value ( ) : that . value ; const entry = target . GetCombatEntry ( encounter ) ; entry . spellstack = entry . spellstack || [ ] ; entry . spellstack . push ( value ) ; } export function MatchSpellstack ( node = { } ) { node . stack = node . stack || [ ] ; node . onHit = node . onHit || [ ] ; node . onMiss = node . onMiss || [ ] ; return _ . bind ( RunMatchSpellstack , node ) ; } function RunMatchSpellstack ( ability , encounter , caster , target , result ) { const that = this ; const consume = that . consume ; const entry = target . GetCombatEntry ( encounter ) ; const spellstack = entry . spellstack || [ ] ; const stack = that . stack ; let match = true ; if ( spellstack . length >= stack . length ) { let first = 0 ; _ . each ( stack , ( spell ) => { first = _ . indexOf ( spellstack , spell , first ) ; if ( first === - 1 ) { match = false ; return false ; } else { first ++ ; } } ) ; } else { match = false ; } if ( match ) { if ( consume ) { entry . spellstack = [ ] ; } _ . each ( that . onHit , ( node ) => { node ( ability , encounter , caster , target , result ) ; } ) ; } else { _ . each ( that . onMiss , ( node ) => { node ( ability , encounter , caster , target , result ) ; } ) ; } } export function Cancel ( node = { } ) { node . onHit = node . onHit || [ ] ; node . onMiss = node . onMiss || [ ] ; return _ . bind ( RunCancel , node ) ; } function RunCancel ( ability , encounter , caster , target , result ) { const that = this ; const entry = target . GetCombatEntry ( encounter ) ; if ( entry && entry . casting ) { result = that . result || result ; let cancellable = entry . casting . ability . cancellable ; if ( _ . isFunction ( cancellable ) ) { cancellable = cancellable ( ability , encounter , caster , target , result ) ; } if ( cancellable && target . CanBeInterrupted ( ability , encounter , caster , result ) ) { const parse = AbilityNode . DefaultParser ( caster , target ) ; Text . NL ( ) ; Text . Add ( "[tPoss] concentration is broken!" , parse , "bold" ) ; Text . NL ( ) ; entry . casting = undefined ; _ . each ( that . onHit , ( node ) => { node ( ability , encounter , caster , target , result ) ; } ) ; } else { _ . each ( that . onMiss , ( node ) => { node ( ability , encounter , caster , target ) ; } ) ; } } } } export namespace ToHit { export function StrikeThrough ( caster , target ) { return true ; } export function Regular ( caster , target ) { const that = this ; const hitMod = that . hitMod || 1 ; const hit = hitMod * that . hitFunc ( caster , target ) ; const evade = that . evadeFunc ( caster , target ) ; return Ability . ToHit ( hit , evade ) ; } } export namespace HitFunc { export function Physical ( caster , target ) { return caster . PHit ( ) ; } export function Magical ( caster , target ) { return caster . MHit ( ) ; } export function Lust ( caster , target ) { return caster . LHit ( ) ; } } export namespace EvadeFunc { export function Physical ( caster , target ) { return target . PEvade ( ) ; } export function Magical ( caster , target ) { return target . MEvade ( ) ; } export function Lust ( caster , target ) { return target . LEvade ( ) ; } } export namespace ToDamage { export function Regular ( caster , target ) { const that = this ; const damageType = that . damageTypeNode ? that . damageTypeNode : caster . elementAtk ; const atkMod = that . atkMod || 1 ; const defMod = that . defMod || 1 ; const atkDmg = atkMod * that . atkFunc ( caster , target ) ; const def = defMod * that . defFunc ( caster , target ) ; let dmg = Ability . Damage ( atkDmg , def , caster . level , target . level ) ; if ( dmg < 0 ) { dmg = 0 ; } dmg = damageType . ApplyDmgType ( target . elementDef , dmg ) ; dmg = Math . floor ( dmg ) ; return - dmg ; } export function Heal ( caster , target ) { const that = this ; const atkMod = that . atkMod || 1 ; let healing = atkMod * that . atkFunc ( caster , target ) ; if ( healing < 0 ) { healing = 0 ; } healing = Math . floor ( healing ) ; return healing ; } } export namespace AtkFunc { export function Physical ( caster , target ) { return caster . PAttack ( ) ; } export function Magical ( caster , target ) { return caster . MAttack ( ) ; } export function Lust ( caster , target ) { return caster . LAttack ( ) ; } } export namespace DefFunc { export function Physical ( caster , target ) { return target . PDefense ( ) ; } export function Magical ( caster , target ) { return target . MDefense ( ) ; } export function Lust ( caster , target ) { return target . LDefense ( ) ; } } export namespace DamageFunc { export function Physical ( encounter , caster , target , dmg ) { if ( target . PhysDmgHP ( encounter , caster , dmg ) ) { const weakness = target . combatStatus . stats [ StatusEffect . Weakness ] ; if ( weakness ) { const reduction = target . LustLevel ( ) * weakness . str ; dmg += dmg * reduction ; dmg = Math . floor ( dmg ) ; } return dmg ; } else { return undefined ; } } export function Magical ( encounter , caster , target , dmg ) { return dmg ; } export function Lust ( encounter , caster , target , dmg ) { return dmg ; } } export namespace DamagePool { export function Physical ( ability , encounter , caster , target , dmg ) { target . AddHPAbs ( dmg ) ; } export function Magical ( ability , encounter , caster , target , dmg ) { target . AddSPAbs ( dmg ) ; } export function Lust ( ability , encounter , caster , target , dmg ) { target . AddLustAbs ( - dmg ) ; } } export function Run ( ability , encounter , caster , target , result ) { const that = this ; _ . each ( that . onCast , ( node ) => { node ( ability , encounter , caster , target ) ; } ) ; if ( ! Ability . EnabledCost ( that , caster ) ) { return ; } Ability . ApplyCost ( that , caster ) ; const targets = _ . has ( target , "members" ) ? target . members : [ target ] ; let nrAttacks = that . nrAttacks ; if ( _ . isFunction ( nrAttacks ) ) { nrAttacks = nrAttacks ( ability , encounter , caster , target , result ) ; } else if ( ! _ . isNumber ( nrAttacks ) ) { nrAttacks = 1 ; } _ . each ( targets , ( e ) => { if ( ! that . hitFallen && e . Incapacitated ( ) ) { return ; } _ . times ( nrAttacks , ( ) => { const hit = that . toHit ? Math . random ( ) < that . toHit ( caster , e ) : true ; if ( hit ) { if ( that . toDamage ) { let dmg = that . toDamage ( caster , e ) ; if ( that . damageFunc ) { dmg = that . damageFunc ( encounter , caster , e , dmg ) ; } if ( _ . isNumber ( dmg ) ) { _ . each ( that . damagePool , ( node ) => { node ( ability , encounter , caster , e , dmg ) ; } ) ; if ( dmg <= 0 ) { _ . each ( that . onDamage , ( node ) => { node ( ability , encounter , caster , e , dmg ) ; } ) ; } else { _ . each ( that . onAbsorb , ( node ) => { node ( ability , encounter , caster , e , dmg ) ; } ) ; } } } _ . each ( that . onHit , ( node ) => { node ( ability , encounter , caster , e , result ) ; } ) ; } else { _ . each ( that . onMiss , ( node ) => { node ( ability , encounter , caster , e ) ; } ) ; } } ) ; } ) ; } }