var AttackFlowMode = { NONE: 0, STARTFLOW: 1, ATTACK: 2, ENDFLOW: 3, COMPLETE: 4 }; var AttackFlowResult = { DEATH: 0, CONTINUE: 1, NONE: 2 }; // RealBattleもEasyBattleも、 // どのユニットから攻撃するかなどの順番は同一である。 // こうした順番は、AttackOrder内のAttackEntryで構成されており、 // それを確認するのがAttackFlowになる。 var AttackFlow = defineObject(BaseObject, { _parentCoreAttack: null, _order: null, _attackInfo: null, _startStraightFlow: null, _endStraightFlow: null, setAttackInfoAndOrder: function(attackInfo, order, parentCoreAttack) { this._parentCoreAttack = parentCoreAttack; this._order = order; this._attackInfo = attackInfo; this._startStraightFlow = createObject(StraightFlow); this._startStraightFlow.setStraightFlowData(this._parentCoreAttack); this._pushFlowEntriesStart(this._startStraightFlow); this._endStraightFlow = createObject(StraightFlow); this._endStraightFlow.setStraightFlowData(this._parentCoreAttack); this._pushFlowEntriesEnd(this._endStraightFlow); }, startAttackFlow: function() { this._changeFirstMode(); return EnterResult.NOTENTER; }, moveStartFlow: function() { var mode = this.getCycleMode(); var result = MoveResult.CONTINUE; if (mode === AttackFlowMode.STARTFLOW) { if (this._startStraightFlow.moveStraightFlow() !== MoveResult.CONTINUE) { this.changeCycleMode(AttackFlowMode.ATTACK); result = MoveResult.END; } } else if (mode === AttackFlowMode.ATTACK) { result = MoveResult.END; } return result; }, moveEndFlow: function() { var mode = this.getCycleMode(); var result = MoveResult.CONTINUE; if (mode === AttackFlowMode.ENDFLOW) { if (this._endStraightFlow.moveStraightFlow() !== MoveResult.CONTINUE) { this.changeCycleMode(AttackFlowMode.COMPLETE); } } else if (mode === AttackFlowMode.COMPLETE) { result = MoveResult.END; } return result; }, drawStartFlow: function() { var mode = this.getCycleMode(); if (mode === AttackFlowMode.STARTFLOW) { this._startStraightFlow.drawStraightFlow(); } }, drawEndFlow: function() { var mode = this.getCycleMode(); if (mode === AttackFlowMode.ENDFLOW) { this._endStraightFlow.drawStraightFlow(); } }, checkNextAttack : function() { var result = AttackFlowResult.NONE; if (this.isBattleUnitLosted()) { this._changeLastMode(); result = AttackFlowResult.DEATH; } else if (this._isBattleContinue()) { // trueを返した場合はまだAttackEntryが存在することを意味する。 // 呼び出し元はこれを検出して戦闘を続ける。 result = AttackFlowResult.CONTINUE; } else { // AttackEntryが存在しなくなり、戦闘に決着がつかなかった場合に実行される this._changeLastMode(); } return result; }, getPlayerUnit: function() { var unit = this._order.getActiveUnit(); if (unit.getUnitType() === UnitType.PLAYER) { return unit; } unit = this._order.getPassiveUnit(); if (unit.getUnitType() === UnitType.PLAYER) { return unit; } return null; }, isBattleUnitLosted: function() { var active = this._order.getActiveUnit(); var passive = this._order.getPassiveUnit(); return DamageControl.isLosted(active) || DamageControl.isLosted(passive); }, getAttackOrder: function() { return this._order; }, getAttackInfo: function() { return this._attackInfo; }, validBattle: function() { var result = this._order.isNextOrder(); if (!result) { this._changeLastMode(); } return result; }, // 戦闘をカットしたい場合に呼び出される。 // オーダーの中身を一気に実行する。 finalizeAttack: function() { if (!this._startStraightFlow.isFlowLast()) { this._startStraightFlow.enterStraightFlow(); } while (this._order.isNextOrder()) { this.executeAttackPocess(); } if (!this._endStraightFlow.isFlowLast()) { this._endStraightFlow.enterStraightFlow(); } }, executeAttackPocess: function() { this._doAttackAction(); this._order.nextOrder(); }, _doAttackAction: function() { var i, count; var order = this._order; var active = order.getActiveUnit(); var passive = order.getPassiveUnit(); var activeStateArray = order.getActiveStateArray(); var passiveStateArray = order.getPassiveStateArray(); var isItemDecrement = order.isCurrentItemDecrement(); DamageControl.reduceHp(active, order.getActiveDamage()); DamageControl.reduceHp(passive, order.getPassiveDamage()); DamageControl.checkHp(active, passive); count = activeStateArray.length; for (i = 0; i < count; i++) { StateControl.arrangeState(active, activeStateArray[i], IncreaseType.INCREASE); } count = passiveStateArray.length; for (i = 0; i < count; i++) { StateControl.arrangeState(passive, passiveStateArray[i], IncreaseType.INCREASE); } if (isItemDecrement) { // 攻撃する側の武器を減らす。 // ここで、アイテムが破棄されるようなことはない。 ItemControl.decreaseLimit(active, ItemControl.getEquippedWeapon(active)); } }, _isBattleContinue: function() { return this._order.isNextOrder(); }, _changeFirstMode: function() { if (this._startStraightFlow.enterStraightFlow() === EnterResult.OK) { this.changeCycleMode(AttackFlowMode.STARTFLOW); } else { this.changeCycleMode(AttackFlowMode.ATTACK); } }, _changeLastMode: function() { if (this._endStraightFlow.enterStraightFlow() === EnterResult.OK) { this.changeCycleMode(AttackFlowMode.ENDFLOW); } else { this.changeCycleMode(AttackFlowMode.COMPLETE); } }, _pushFlowEntriesStart: function(straightFlow) { straightFlow.pushFlowEntry(UnitDeclarationFlowEntry); }, _pushFlowEntriesEnd: function(straightFlow) { straightFlow.pushFlowEntry(UnitDeathFlowEntry); straightFlow.pushFlowEntry(UnitSyncopeFlowEntry); // リアル戦闘用の経験値取得と、簡易戦闘用の経験値取得を追加しているが、 // 実際に処理が実行されるのはどちらか片方である。 straightFlow.pushFlowEntry(RealExperienceFlowEntry); straightFlow.pushFlowEntry(EasyExperienceFlowEntry); straightFlow.pushFlowEntry(WeaponBrokenFlowEntry); } } ); var UnitDeclarationFlowEntry = defineObject(BaseFlowEntry, { _capsuleEvent: null, enterFlowEntry: function(coreAttack) { this._prepareMemberData(coreAttack); return this._completeMemberData(coreAttack); }, moveFlowEntry: function() { var result = MoveResult.CONTINUE; if (this._capsuleEvent.moveCapsuleEvent() !== MoveResult.CONTINUE) { return MoveResult.END; } return result; }, _prepareMemberData: function(coreAttack) { this._capsuleEvent = createObject(CapsuleEvent); }, _completeMemberData: function(coreAttack) { var order = coreAttack.getAttackFlow().getAttackOrder(); var battleEventData = UnitEventChecker.getUnitBattleEventData(order.getActiveUnit(), order.getPassiveUnit()); if (battleEventData === null) { return EnterResult.NOTENTER; } this._capsuleEvent.setBattleUnit(battleEventData.unit); if (this.isFlowSkip() || coreAttack.isBattleCut()) { root.setEventSkipMode(true); } return this._capsuleEvent.enterCapsuleEvent(battleEventData.event, true); } } ); var UnitDeathMode = { EVENT: 0, ERASE: 1 }; var UnitDeathFlowEntry = defineObject(BaseFlowEntry, { _coreAttack: null, _eraseCounter: null, _activeUnit: null, _passiveUnit: null, _capsuleEvent: null, enterFlowEntry: function(coreAttack) { this._prepareMemberData(coreAttack); return this._completeMemberData(coreAttack); }, moveFlowEntry: function() { var mode = this.getCycleMode(); var result = MoveResult.CONTINUE; if (mode === UnitDeathMode.EVENT) { result = this._moveEvent(); } else if (mode === UnitDeathMode.ERASE) { result = this._moveErase(); } return result; }, _prepareMemberData: function(coreAttack) { var order = coreAttack.getAttackFlow().getAttackOrder(); this._coreAttack = coreAttack; this._eraseCounter = createObject(EraseCounter); this._activeUnit = order.getActiveUnit(); this._passiveUnit = order.getPassiveUnit(); this._capsuleEvent = createObject(CapsuleEvent); }, _completeMemberData: function(coreAttack) { root.getSceneController().notifyBattleEnd(this._activeUnit, this._passiveUnit); // どちらのユニットも倒れていない場合は、処理を続行しない if (!coreAttack.getAttackFlow().isBattleUnitLosted()) { return EnterResult.NOTENTER; } if (DamageControl.isSyncope(this._passiveUnit)) { return EnterResult.NOTENTER; } // UnitDeathFlowEntryはCoreAttackから使用されるが、 // CoreAttackにおけるスキップは必ず成功しなければならないため、 // 現在がスキップ状態の場合は無条件にスキップする。 if (this.isFlowSkip() || this._coreAttack.isBattleCut()) { this._doEndAction(); return EnterResult.NOTENTER; } // 死亡時イベントを処理することを記録する coreAttack.recordUnitLostEvent(true); // イベントが存在しない、または終了できたかどうか if (this._capsuleEvent.enterCapsuleEvent(UnitEventChecker.getUnitLostEvent(this._passiveUnit), false) === EnterResult.NOTENTER) { if (this.isFlowSkip() || this._coreAttack.isBattleCut()) { this._doEndAction(); return EnterResult.NOTENTER; } else { this.changeCycleMode(UnitDeathMode.ERASE); return EnterResult.OK; } } this._playUnitDeathMusic(); this.changeCycleMode(UnitDeathMode.EVENT); return EnterResult.OK; }, _moveEvent: function() { if (this._capsuleEvent.moveCapsuleEvent() !== MoveResult.CONTINUE) { // ユニットイベントで表示されたかもしれないメッセージを消去する。 // 簡易の強制戦闘でマップユニットがメッセージの上に描画されるのを防ぐ。 EventCommandManager.eraseMessage(MessageEraseFlag.ALL); this.changeCycleMode(UnitDeathMode.ERASE); } return MoveResult.CONTINUE; }, _moveErase: function() { if (this._eraseCounter.moveEraseCounter() !== MoveResult.CONTINUE) { this._coreAttack.getBattleObject().eraseRoutine(0); this._doEndAction(); return MoveResult.END; } else { this._coreAttack.getBattleObject().eraseRoutine(this._eraseCounter.getEraseAlpha()); } return MoveResult.CONTINUE; }, _doEndAction: function() { }, _playUnitDeathMusic: function() { var handle; if (this._passiveUnit.getUnitType() === UnitType.PLAYER && !this._passiveUnit.isGuest()) { handle = root.querySoundHandle('playerdeathmusic'); if (!handle.isNullHandle()) { MediaControl.musicPlay(handle); this._coreAttack.getBattleObject().getBattleTable().setMusicPlayFlag(true); } } } } ); var UnitSyncopeFlowEntry = defineObject(BaseFlowEntry, { _coreAttack: null, _eraseCounter: null, _activeUnit: null, _passiveUnit: null, enterFlowEntry: function(coreAttack) { this._prepareMemberData(coreAttack); return this._completeMemberData(coreAttack); }, moveFlowEntry: function() { if (this._eraseCounter.moveEraseCounter() !== MoveResult.CONTINUE) { this._coreAttack.getBattleObject().eraseRoutine(0); this._doEndAction(); return MoveResult.END; } else { this._coreAttack.getBattleObject().eraseRoutine(this._eraseCounter.getEraseAlpha()); } return MoveResult.CONTINUE; }, _prepareMemberData: function(coreAttack) { var order = coreAttack.getAttackFlow().getAttackOrder(); this._coreAttack = coreAttack; this._eraseCounter = createObject(EraseCounter); this._activeUnit = order.getActiveUnit(); this._passiveUnit = order.getPassiveUnit(); }, _completeMemberData: function(coreAttack) { if (!DamageControl.isSyncope(this._passiveUnit)) { return EnterResult.NOTENTER; } if (this.isFlowSkip() || this._coreAttack.isBattleCut()) { this._doEndAction(); return EnterResult.NOTENTER; } if (!this._coreAttack.getBattleObject().isSyncopeErasing()) { this._doEndAction(); return EnterResult.NOTENTER; } return EnterResult.OK; }, _doEndAction: function() { } } ); var RealExperienceMode = { WINDOW: 0, SCROLL: 1, ANIME: 2, LEVEL: 3 }; var RealExperienceFlowEntry = defineObject(BaseFlowEntry, { _coreAttack: null, _unit: null, _getExp: 0, _growthArray: null, _experienceNumberView: null, _levelupView: null, _effect: null, enterFlowEntry: function(coreAttack) { if (this._checkLevelup()) { // 経験値処理の途中でスキップが発生した場合、AttackFlow.finalizeAttack経由で再度enterFlowEntryが呼ばれる return EnterResult.NOTENTER; } this._prepareMemberData(coreAttack); return this._completeMemberData(coreAttack); }, moveFlowEntry: function() { var mode = this.getCycleMode(); var result = MoveResult.CONTINUE; if (mode === RealExperienceMode.WINDOW) { result = this._moveWindow(); } else if (mode === RealExperienceMode.SCROLL) { result = this._moveScroll(); } else if (mode === RealExperienceMode.ANIME) { result = this._moveAnime(); } else if (mode === RealExperienceMode.LEVEL) { result = this._moveLevel(); } return result; }, drawFlowEntry: function() { var mode = this.getCycleMode(); if (mode === RealExperienceMode.WINDOW) { this._drawWindow(); } else if (mode === RealExperienceMode.LEVEL) { this._drawLevel(); } }, _prepareMemberData: function(coreAttack) { var attackFlow = coreAttack.getAttackFlow(); var order = attackFlow.getAttackOrder(); this._coreAttack = coreAttack; this._unit = attackFlow.getPlayerUnit(); this._getExp = order.getExp(); this._growthArray = null; this._experienceNumberView = createWindowObject(ExperienceNumberView, this); this._levelupView = createObject(LevelupView); }, _completeMemberData: function(coreAttack) { // 戦闘がリアル形式でない場合は続行しない if (!coreAttack.isRealBattle()) { return EnterResult.NOTENTER; } if (!Miscellaneous.isExperienceEnabled(this._unit, this._getExp)) { return EnterResult.NOTENTER; } this._growthArray = ExperienceControl.obtainExperience(this._unit, this._getExp); if (this.isFlowSkip() || this._coreAttack.isBattleCut()) { // スキップ時は、直ちに経験値を与える this._doEndAction(); return EnterResult.NOTENTER; } this._experienceNumberView.setExperienceNumberData(this._unit, this._getExp); this.changeCycleMode(RealExperienceMode.WINDOW); return EnterResult.OK; }, _checkLevelup: function() { if (this._coreAttack === null) { return false; } this._doEndAction(); return true; }, _doEndAction: function() { if (this._growthArray !== null) { ExperienceControl.plusGrowth(this._unit, this._growthArray); ExperienceControl.obtainData(this._unit); } }, _moveWindow: function() { if (this._experienceNumberView.moveNumberView() !== MoveResult.CONTINUE) { if (this._growthArray !== null) { // レベルが上がる場合はスクロール this._coreAttack.getBattleObject().startExperienceScroll(this._unit); this.changeCycleMode(RealExperienceMode.SCROLL); } else { return MoveResult.END; } } return MoveResult.CONTINUE; }, _moveScroll: function() { if (this._coreAttack.getBattleObject().moveAutoScroll() !== MoveResult.CONTINUE) { this._changeLevelAnime(); } return MoveResult.CONTINUE; }, _moveAnime: function() { var levelupViewParam; if (this._effect.isEffectLast()) { levelupViewParam = this._createLevelupViewParam(); this._levelupView.enterLevelupViewCycle(levelupViewParam); this.changeCycleMode(RealExperienceMode.LEVEL); } return MoveResult.CONTINUE; }, _moveLevel: function() { var result = this._levelupView.moveLevelupViewCycle(); if (result !== MoveResult.CONTINUE) { this._doEndAction(); } return result; }, _drawWindow: function() { var x = LayoutControl.getCenterX(-1, this._experienceNumberView.getNumberViewWidth()); var y = this._coreAttack.getBattleObject().getBattleArea().y + 120; this._experienceNumberView.drawNumberView(x, y); }, _drawLevel: function() { this._levelupView.drawLevelupViewCycle(); }, _changeLevelAnime: function() { var pos; var animeData = root.queryAnime('reallevelup'); var isRight = true; var battleObject = this._coreAttack.getBattleObject(); var battler = battleObject.getBattler(isRight); if (battler.getUnit() !== this._unit) { isRight = false; battler = battleObject.getBattler(isRight); } pos = battler.getEffectPos(animeData); this._effect = battleObject.createEffect(animeData, pos.x, pos.y, isRight, false); this.changeCycleMode(RealExperienceMode.ANIME); }, _createLevelupViewParam: function() { var levelupViewParam = StructureBuilder.buildLevelupViewParam(); levelupViewParam.targetUnit = this._unit; levelupViewParam.getExp = this._getExp; levelupViewParam.xAnime = 0; levelupViewParam.yAnime = 0; levelupViewParam.anime = null; levelupViewParam.growthArray = this._growthArray; return levelupViewParam; } } ); var EasyExperienceMode = { WINDOW: 0, LEVEL: 1 }; var EasyExperienceFlowEntry = defineObject(BaseFlowEntry, { _coreAttack: null, _unit: null, _getExp: 0, _growthArray: null, _experienceNumberView: null, _levelupView: null, enterFlowEntry: function(coreAttack) { if (this._checkLevelup()) { return EnterResult.NOTENTER; } this._prepareMemberData(coreAttack); return this._completeMemberData(coreAttack); }, moveFlowEntry: function() { var mode = this.getCycleMode(); var result = MoveResult.CONTINUE; if (mode === EasyExperienceMode.WINDOW) { result = this._moveWindow(); } else if (mode === EasyExperienceMode.LEVEL) { result = this._moveLevel(); } return result; }, drawFlowEntry: function() { var mode = this.getCycleMode(); if (mode === EasyExperienceMode.WINDOW) { this._drawWindow(); } else if (mode === EasyExperienceMode.LEVEL) { this._drawLevel(); } }, _prepareMemberData: function(coreAttack) { var attackFlow = coreAttack.getAttackFlow(); var order = attackFlow.getAttackOrder(); this._coreAttack = coreAttack; this._unit = attackFlow.getPlayerUnit(); this._getExp = order.getExp(); this._growthArray = null; this._experienceNumberView = createWindowObject(ExperienceNumberView, this); this._levelupView = createObject(LevelupView); }, _completeMemberData: function(coreAttack) { if (coreAttack.isRealBattle()) { return EnterResult.NOTENTER; } if (!Miscellaneous.isExperienceEnabled(this._unit, this._getExp)) { return EnterResult.NOTENTER; } this._growthArray = ExperienceControl.obtainExperience(this._unit, this._getExp); if (this.isFlowSkip() || this._coreAttack.isBattleCut()) { // スキップ時は、直ちに経験値を与える this._doEndAction(); return EnterResult.NOTENTER; } this._experienceNumberView.setExperienceNumberData(this._unit, this._getExp); this.changeCycleMode(EasyExperienceMode.WINDOW); return EnterResult.OK; }, _checkLevelup: function() { if (this._coreAttack === null) { return false; } this._doEndAction(); return true; }, _doEndAction: function() { if (this._growthArray !== null) { ExperienceControl.plusGrowth(this._unit, this._growthArray); ExperienceControl.obtainData(this._unit); } }, _moveWindow: function() { var levelupViewParam; if (this._experienceNumberView.moveNumberView() !== MoveResult.CONTINUE) { if (this._growthArray !== null) { levelupViewParam = this._createLevelupViewParam(); this._levelupView.enterLevelupViewCycle(levelupViewParam); this.changeCycleMode(EasyExperienceMode.LEVEL); } else { return MoveResult.END; } } return MoveResult.CONTINUE; }, _moveLevel: function() { var result = this._levelupView.moveLevelupViewCycle(); if (result !== MoveResult.CONTINUE) { this._doEndAction(); } return result; }, _drawWindow: function() { var x = LayoutControl.getCenterX(-1, this._experienceNumberView.getNumberViewWidth()); var y = LayoutControl.getNotifyY(); this._experienceNumberView.drawNumberView(x, y); }, _drawLevel: function() { this._levelupView.drawLevelupViewCycle(); }, _createLevelupViewParam: function() { var levelupViewParam = StructureBuilder.buildLevelupViewParam(); var x = LayoutControl.getPixelX(this._unit.getMapX()); var y = LayoutControl.getPixelY(this._unit.getMapY()); var anime = root.queryAnime('easylevelup'); var pos = LayoutControl.getMapAnimationPos(x, y, anime); levelupViewParam.targetUnit = this._unit; levelupViewParam.getExp = this._getExp; levelupViewParam.xAnime = pos.x; levelupViewParam.yAnime = pos.y; levelupViewParam.anime = anime; levelupViewParam.growthArray = this._growthArray; return levelupViewParam; } } ); var WeaponBrokenFlowEntry = defineObject(BaseFlowEntry, { _dynamicEvent: null, enterFlowEntry: function(coreAttack) { var generator; var attackFlow = coreAttack.getAttackFlow(); var order = attackFlow.getAttackOrder(); if (this.isFlowSkip() || coreAttack.isBattleCut()) { return EnterResult.NOTENTER; } this._dynamicEvent = createObject(DynamicEvent); generator = this._dynamicEvent.acquireEventGenerator(); this._checkDelete(order.getActiveUnit(), generator); this._checkDelete(order.getPassiveUnit(), generator); return this._dynamicEvent.executeDynamicEvent(); }, moveFlowEntry: function() { return this._dynamicEvent.moveDynamicEvent(); }, _checkDelete: function(unit, generator) { var weapon; var isCenterShow = true; weapon = ItemControl.getEquippedWeapon(unit); if (weapon === null) { return; } if (ItemControl.isItemBroken(weapon)) { if (unit.getUnitType() === UnitType.PLAYER && DataConfig.isWeaponLostDisplayable()) { generator.soundPlay(this._getLostSoundHandle(), 1); generator.messageTitle(weapon.getName() + StringTable.ItemLost, 0, 0, isCenterShow); } } }, _getLostSoundHandle: function() { return root.querySoundHandle('itemlost'); } } );