/**
 * Responsible for stuffs in the debugger mode
 */ class BattleDebugger { static IS_DEBUG_MODE = true ; private static _instance : BattleDebugger = null ; constructor ( ) { if ( BattleDebugger . _instance ) { throw new Error ( "Error: Instantiation failed: Use getInstance() instead of new." ) ; } BattleDebugger . _instance = this ; } public static getInstance ( ) { if ( BattleDebugger . _instance === null ) { BattleDebugger . _instance = new BattleDebugger ( ) ; } return BattleDebugger . _instance ; } /**
     * Create the debugger: display all events in the left side event log, and bound onlick callback to them.
     */ public displayDebugger ( ) { this . displayEventLogAtIndex ( 0 ) ; let minorLog = BattleLogger . getInstance ( ) . minorEventLog ; let majorLog = BattleLogger . getInstance ( ) . majorEventLog ; let currentTurn = - 10 ; for ( let i = 0 ; i < majorLog . length ; i ++ ) { if ( majorLog [ i ] . turn !== currentTurn ) { currentTurn = majorLog [ i ] . turn ; this . displayTurn ( currentTurn ) ; } this . displayMajorEvent ( i ) ; for ( let j = 0 ; minorLog [ i ] && j < minorLog [ i ] . length ; j ++ ) { this . displayMinorEvent ( i , j ) ; } } } /**
     * Display a major event on screen (the left side list)
     */ displayMajorEvent ( index ) { if ( ! BattleDebugger . IS_DEBUG_MODE ) { return ; } let data = BattleLogger . getInstance ( ) . majorEventLog [ index ] ; let id = `turn${ data . turn }events` ; let battleEventDiv = document . getElementById ( "battleEventDiv" ) ; let turnEventList = document . getElementById ( id ) ; if ( ! turnEventList ) { turnEventList = document . createElement ( "ul" ) ; turnEventList . setAttribute ( "id" , id ) ; battleEventDiv . appendChild ( turnEventList ) ; } let newEvent = document . createElement ( "li" ) ; newEvent . innerHTML = `<a>${ data . description }</a>` ; newEvent . setAttribute ( "tabindex" , index + "" ) ; newEvent . setAttribute ( "id" , index + "" ) ; newEvent . onclick = function ( ) { BattleDebugger . getInstance ( ) . displayEventLogAtIndex ( + ( < HTMLLIElement > this ) . id ) ; } ; turnEventList . appendChild ( newEvent ) ; } /**
     * Display a minor event on screen
     */ displayMinorEvent ( majorIndex , minorIndex ) { if ( BattleModel . IS_MASS_SIMULATION || ! BattleDebugger . IS_DEBUG_MODE ) { return ; } let currentTurn = BattleLogger . getInstance ( ) . majorEventLog [ majorIndex ] . turn ; let id = `turn${ currentTurn }events` ; let description = BattleLogger . getInstance ( ) . minorEventLog [ majorIndex ] [ minorIndex ] . description ; let turnEventList = document . getElementById ( id ) ; let lastEvent = turnEventList . lastChild ; let subEventList = lastEvent . getElementsByTagName ( "ul" ) [ 0 ] ; if ( ! subEventList ) { subEventList = document . createElement ( "ul" ) ; lastEvent . appendChild ( subEventList ) ; } let newEvent = document . createElement ( "li" ) ; newEvent . innerHTML = description ; subEventList . appendChild ( newEvent ) ; } /**
     * Log a new turn
     */ displayTurn ( turnNum ) { if ( BattleModel . IS_MASS_SIMULATION || ! BattleDebugger . IS_DEBUG_MODE ) { return ; } let battleEventDiv = document . getElementById ( "battleEventDiv" ) ; let newEvent = document . createElement ( "p" ) ; newEvent . innerHTML = `Turn ${ turnNum }` ; battleEventDiv . appendChild ( newEvent ) ; } /**
     * This is called when you click on an event in the event list. It updates the field on the right side
     * of the screen with information after the event that you clicked on has been processed. That event
     * is represented by the index argument supplied into this function.
     */ displayEventLogAtIndex ( majorIndex ) { if ( ! BattleDebugger . IS_DEBUG_MODE ) { return ; } let graphic = BattleGraphic . getInstance ( ) ; let logger = BattleLogger . getInstance ( ) ; let lastEventIndex = ( majorIndex === 0 ) ? 0 : majorIndex - 1 ; let lastEventField = logger . getFieldAtMajorIndex ( lastEventIndex ) ; let field = logger . getFieldAtMajorIndex ( majorIndex ) ; for ( let p = 1 ; p <= 2 ; p ++ ) { let playerCards = field [ `player${ p }Cards` ] ; let lastPlayerCards = lastEventField [ `player${ p }Cards` ] ; for ( let f = 0 ; f < 5 ; f ++ ) { let stats = playerCards [ f ] . stats ; let originalStats = playerCards [ f ] . originalStats ; let status = playerCards [ f ] . status ; let afflict = playerCards [ f ] . affliction ; let hpRatio = stats . hp / originalStats . hp ; let finalAtk = this . getFinalStat ( originalStats . atk , status . atk , status . isNewLogic [ ENUM . StatusType . ATK ] , status . remainHpAtkUp , hpRatio ) ; let finalDef = this . getFinalStat ( originalStats . def , status . def , status . isNewLogic [ ENUM . StatusType . DEF ] , status . remainHpDefUp , hpRatio ) ; let finalWis = this . getFinalStat ( originalStats . wis , status . wis , status . isNewLogic [ ENUM . StatusType . WIS ] , status . remainHpWisUp , hpRatio ) ; let finalAgi = this . getFinalStat ( originalStats . agi , status . agi , status . isNewLogic [ ENUM . StatusType . AGI ] , status . remainHpAgiUp , hpRatio ) ; let lastStats = lastPlayerCards [ f ] . stats ; let lastOriginalStats = lastPlayerCards [ f ] . originalStats ; let lastStatus = lastPlayerCards [ f ] . status ; let lastHpRatio = lastStats . hp / lastOriginalStats . hp ; let lastFinalAtk = this . getFinalStat ( lastOriginalStats . atk , lastStatus . atk , lastStatus . isNewLogic [ ENUM . StatusType . ATK ] , lastStatus . remainHpAtkUp , lastHpRatio ) ; let lastFinalDef = this . getFinalStat ( lastOriginalStats . def , lastStatus . def , lastStatus . isNewLogic [ ENUM . StatusType . DEF ] , lastStatus . remainHpDefUp , lastHpRatio ) ; let lastFinalWis = this . getFinalStat ( lastOriginalStats . wis , lastStatus . wis , lastStatus . isNewLogic [ ENUM . StatusType . WIS ] , lastStatus . remainHpWisUp , lastHpRatio ) ; let lastFinalAgi = this . getFinalStat ( lastOriginalStats . agi , lastStatus . agi , lastStatus . isNewLogic [ ENUM . StatusType . AGI ] , lastStatus . remainHpAgiUp , lastHpRatio ) ; let infoText = { name : playerCards [ f ] . name , hp : `HP: ${ stats . hp }` , atk : `ATK: ${ finalAtk }` , def : `DEF: ${ finalDef }` , wis : `WIS: ${ finalWis }` , agi : `AGI: ${ finalAgi }` , } ; if ( status . attackResistance !== 0 ) infoText . physicalResist = `PW: ${ status . attackResistance }` ; if ( status . magicResistance !== 0 ) infoText . magicalResist = `MW: ${ status . magicResistance }` ; if ( status . breathResistance !== 0 ) infoText . breathResist = `BW: ${ status . breathResistance }` ; if ( status . willAttackAgain !== 0 ) infoText . willAttackAgain = "Extra action: Yes" ; if ( status . skillProbability !== 0 ) infoText . skillProbability = `Extra prob.: ${ status . skillProbability }` ; if ( status . hpShield !== 0 ) infoText . hpShield = `HP Shld.: ${ status . hpShield }` ; if ( afflict ) { infoText . affliction = `Affliction: ${ Affliction . getAfflictionAdjective ( afflict . type ) }` ; if ( afflict . type === ENUM . AfflictionType . SILENT ) { infoText . affliction += ` (${ afflict . validTurnNum } turn)` ; } else if ( afflict . type === ENUM . AfflictionType . POISON ) { infoText . affliction += ` (${ afflict . percent } %)` ; } else if ( afflict . type === ENUM . AfflictionType . BURN ) { infoText . affliction += ` (${ afflict . damage })` ; } else { infoText . affliction += " (1 turn)" ; } } if ( stats . hp !== lastStats . hp ) infoText . hp = this . decorateText ( infoText . hp , stats . hp < lastStats . hp ) ; if ( finalAtk !== lastFinalAtk ) infoText . atk = this . decorateText ( infoText . atk , finalAtk < lastFinalAtk ) ; if ( finalDef !== lastFinalDef ) infoText . def = this . decorateText ( infoText . def , finalDef < lastFinalDef ) ; if ( finalWis !== lastFinalWis ) infoText . wis = this . decorateText ( infoText . wis , finalWis < lastFinalWis ) ; if ( finalAgi !== lastFinalAgi ) infoText . agi = this . decorateText ( infoText . agi , finalAgi < lastFinalAgi ) ; for ( let j = 0 ; logger . minorEventLog [ majorIndex ] && j < logger . minorEventLog [ majorIndex ] . length ; j ++ ) { let tempEvent = logger . minorEventLog [ majorIndex ] [ j ] ; if ( tempEvent . targetId === playerCards [ f ] . id ) { if ( tempEvent . type === ENUM . MinorEventType . STATUS ) { if ( tempEvent . status . type === ENUM . StatusType . ATTACK_RESISTANCE ) { infoText . physicalResist = this . decorateText ( infoText . physicalResist , false ) ; } else if ( tempEvent . status . type === ENUM . StatusType . MAGIC_RESISTANCE ) { infoText . magicalResist = this . decorateText ( infoText . magicalResist , false ) ; } else if ( tempEvent . status . type === ENUM . StatusType . BREATH_RESISTANCE ) { infoText . breathResist = this . decorateText ( infoText . breathResist , false ) ; } else if ( tempEvent . status . type === ENUM . StatusType . WILL_ATTACK_AGAIN ) { infoText . willAttackAgain = this . decorateText ( infoText . willAttackAgain , false ) ; } else if ( tempEvent . status . type === ENUM . StatusType . SKILL_PROBABILITY ) { infoText . skillProbability = this . decorateText ( infoText . skillProbability , false ) ; } else if ( tempEvent . status . type === ENUM . StatusType . HP_SHIELD ) { infoText . hpShield = this . decorateText ( infoText . hpShield , false ) ; } } else if ( tempEvent . type === ENUM . MinorEventType . AFFLICTION ) { if ( ! tempEvent . affliction . isFinished ) { infoText . affliction = this . decorateText ( infoText . affliction , false ) ; } } } } if ( logger . minorEventLog [ majorIndex ] && logger . minorEventLog [ majorIndex ] [ 0 ] . executorId === playerCards [ f ] . id ) { infoText . name = `<b>${ infoText . name }</b>` ; } let htmlelem = document . getElementById ( `player${ p }Fam${ f }` ) ; htmlelem . innerHTML = infoText . name + "<br>" + infoText . hp + "<br>" + infoText . atk + "<br>" + infoText . def + "<br>" + infoText . wis + "<br>" + infoText . agi + ( infoText . physicalResist ? `<br>${ infoText . physicalResist }` : "" ) + ( infoText . magicalResist ? `<br>${ infoText . magicalResist }` : "" ) + ( infoText . breathResist ? `<br>${ infoText . breathResist }` : "" ) + ( infoText . willAttackAgain ? `<br>${ infoText . willAttackAgain }` : "" ) + ( infoText . skillProbability ? `<br>${ infoText . skillProbability }` : "" ) + ( infoText . hpShield ? `<br>${ infoText . hpShield }` : "" ) + ( infoText . affliction ? `<br>${ infoText . affliction }` : "" ) ; let lastEventCard = lastEventField [ `player${ p }Cards` ] [ f ] ; graphic . displayHP ( lastEventCard . stats . hp / lastEventCard . originalStats . hp * 100 , p , f , 0 ) ; } } graphic . displayAllCardImages ( majorIndex ) ; graphic . displayAllAfflictionText ( lastEventIndex ) ; graphic . displayMajorEventAnimation ( majorIndex ) ; } /**
     * Get the final stat after all adjustments (buff/debuff status,
     * new debuff logic adjustment, remain hp power up)
     */ getFinalStat ( original , statusAmount , isNewLogic , remainHpPwrUp , hpRatio ) { let value = original ; if ( remainHpPwrUp > 1 ) { value += Math . round ( value * ( 1 - hpRatio ) * ( remainHpPwrUp - 1 ) ) ; } value += statusAmount ; if ( value < 0 ) { value = 0 ; } if ( isNewLogic ) { let lowerLimit = original * Card . NEW_DEBUFF_LOW_LIMIT_FACTOR ; value = ( value > lowerLimit ) ? value : lowerLimit ; } return value ; } param text param isNegative decorateText ( text , isNegative ) { let openTag ; if ( isNegative ) { openTag = "<span style='color:red'><b>" ; } else { openTag = "<span style='color:green'><b>" ; } return openTag + text + "</b></span>" ; } }