// Update is called once per frame async void Update() { switch (battleStage) { case BattleLoopStage.Initial: if (!cutscene.isRunning) { CameraController.inputEnabled = true; cutsceneCamera.enabled = false; mainCamera.enabled = true; advanceBattleStage(); } break; case BattleLoopStage.Pick: advanceBattleStage(); break; case BattleLoopStage.BattleLoopStart: advanceBattleStage(); break; case BattleLoopStage.TurnChange: //If we've already entered this we're awaiting. Don't call it again every frame. if (!battleStageChanged) { break; } battleStageChanged = false; currentCharacter = (currentCharacter + 1) % level.characters.Length; turnPlayerText.text = level.characters[currentCharacter].name + "'s turn\n" + "Turns remaining: " + (objective.maxHalfTurns - ((halfTurnsElapsed / 2) + 1)); turnPlayerText.enabled = true; turnChangeBackground.enabled = true; Util.setTimeout(advanceBattleStage, 1000); break; case BattleLoopStage.TurnChangeEnd: turnPlayerText.enabled = false; turnChangeBackground.enabled = false; advanceBattleStage(); break; case BattleLoopStage.UnitSelection: advanceBattleStage(); break; case BattleLoopStage.ActionSelection: //If we've already entered this we're awaiting. Don't call it again every frame. if (!battleStageChanged) { break; } battleStageChanged = false; //Character.getMove() is responsible for validation so we assume the move to be legal Move move = await level.characters[currentCharacter].getMove(); Unit ourUnit = battlefield.units[move.from.x, move.from.y]; IBattlefieldItem selectedItem = battlefield.battlefieldItemAt(move.to.x, move.to.y); if (selectedItem is Tile) { //We selected a tile! lets move to it moveUnit(ourUnit, move.to.x, move.to.y); if (ourUnit.getTargets(move.to.x, move.to.y, battlefield, level.characters[currentCharacter]).Count == 0) { ourUnit.greyOut(); } } else if (selectedItem is Unit) { //Targeted a hostile unit! fight! Unit selectedUnit = selectedItem as Unit; bool defenderDefeated = ourUnit.doBattleWith( selectedUnit, battlefield.map[move.to.x, move.to.y].Peek(), battlefield); await Task.Delay(TimeSpan.FromMilliseconds(250)); if (!defenderDefeated && (selectedItem is MeleeUnit) && (ourUnit is MeleeUnit)) { //Counterattack applied only when both units are Melee selectedUnit.doBattleWith( ourUnit, battlefield.map[move.from.x, move.from.y].Peek(), battlefield); } ourUnit.setHasAttackedThisTurn(true); await Task.Delay(TimeSpan.FromMilliseconds(250)); } else { Debug.LogWarning("Item of unrecognized type clicked on."); } checkWinAndLose(); //If all of our units have moved advance. Otherwise, go back to unit selection. ourUnit.hasMovedThisTurn = true; if (battlefield.charactersUnits[level.characters[currentCharacter]].All(unit => { //I know this looks inelegant but it avoid calling getUnitCoords if necessary if (!unit.hasMovedThisTurn) { return(false); } else if (unit.getHasAttackedThisTurn()) { return(true); } else { Coord coord = battlefield.getUnitCoords(unit); return(unit.getTargets(coord.x, coord.y, battlefield, level.characters[currentCharacter]).Count == 0); } })) { advanceBattleStage(); } else { setBattleLoopStage(BattleLoopStage.UnitSelection); } break; case BattleLoopStage.EndTurn: //If we've already entered this we're awaiting. Don't call it again every frame. if (!battleStageChanged) { break; } battleStageChanged = false; foreach (Unit unit in battlefield.charactersUnits[level.characters[currentCharacter]]) { unit.hasMovedThisTurn = false; unit.setHasAttackedThisTurn(false); } bool endGame = checkWinAndLose(); if (!endGame) { advanceBattleStage(); } halfTurnsElapsed++; break; } }
// Poor man's state machine. in retrospect i have no idea why i didn't use a proper one. oh well, next game. async void Update() { switch (battleStage) { case BattleLoopStage.Initial: if (!battleStageChanged) { break; } battleStageChanged = false; playBgm(); turnPlayerText.text = "Battle objective:\n" + objective.getName(); turnPlayerText.enabled = true; turnChangeBackground.enabled = true; await Task.Delay(3000); advanceBattleStage(); break; case BattleLoopStage.Pick: advanceBattleStage(); turnPlayerText.enabled = false; turnChangeBackground.enabled = false; break; case BattleLoopStage.BattleLoopStart: if (!battleStageChanged) { break; } battleStageChanged = false; //Check for cutscenes every start phase await runAppropriateCutscenes(); advanceBattleStage(); break; case BattleLoopStage.TurnChange: //If we've already entered this we're awaiting. Don't call it again every frame. if (!battleStageChanged) { break; } battleStageChanged = false; currentCharacter = (currentCharacter + 1) % level.characters.Length; turnPlayerText.text = level.characters[currentCharacter].name + "'s turn\n" + "Turns remaining: " + (objective.maxHalfTurns - halfTurnsElapsed); turnPlayerText.enabled = true; turnChangeBackground.enabled = true; await Task.Delay(1000); advanceBattleStage(); break; case BattleLoopStage.TurnChangeEnd: turnPlayerText.enabled = false; turnChangeBackground.enabled = false; advanceBattleStage(); break; case BattleLoopStage.UnitSelection: advanceBattleStage(); break; case BattleLoopStage.ActionSelection: //If we've already entered this we're awaiting. Don't call it again every frame. if (!battleStageChanged) { break; } battleStageChanged = false; //The getMove function returns null if no move should be made, //possibly in the event of the selection loop being interrupted by a manually ended turn Move move = await level.characters[currentCharacter].getMove(); //Since no move occurs, nothing else needs to be done this turn (since nothing changed). if (move == null) { break; } Unit ourUnit = battlefield.units[move.from.x, move.from.y]; if (ourUnit == null) { Debug.LogWarning("In BattleControl.update(), a move originated from a nonexistent unit, probably due to an ended turn."); break; } IBattlefieldItem selectedItem = battlefield.battlefieldItemAt(move.to.x, move.to.y); if (move.from.Equals(move.to)) { //This is the null move. just do nothing! ourUnit.hasMovedThisTurn = true; ourUnit.setHasAttackedThisTurn(true); ourUnit.greyOut(); } else if (selectedItem is Tile) { //We selected a tile! lets move to it await moveUnit(ourUnit, move.to); if (ourUnit.getTargets(move.to.x, move.to.y, battlefield, level.characters[currentCharacter]).Count == 0) { ourUnit.greyOut(); ourUnit.setHasAttackedThisTurn(true); } } else if (selectedItem is Unit) { //Targeted a hostile unit! fight! Unit selectedUnit = selectedItem as Unit; await rotateUnit(ourUnit, battlefield.getUnitCoords(selectedUnit)); bool defenderDefeated = await ourUnit.doBattleWith( selectedUnit, battlefield.map[move.to.x, move.to.y].Peek(), battlefield); if (!defenderDefeated && (selectedItem is MeleeUnit) && (ourUnit is MeleeUnit)) { await rotateUnit(selectedUnit, battlefield.getUnitCoords(ourUnit)); //Counterattack applied only when both units are Melee await selectedUnit.doBattleWith( ourUnit, battlefield.map[move.from.x, move.from.y].Peek(), battlefield); } //Re-grey model if needed... I'm regretting my desire to make the health ui manager stateless :p if (ourUnit is HealerUnit) { if ((selectedUnit.hasMovedThisTurn && selectedUnit.getTargets(move.to.x, move.to.y, battlefield, level.characters[currentCharacter]).Count == 0) || selectedUnit.getHasAttackedThisTurn()) { selectedUnit.greyOut(); } } ourUnit.setHasAttackedThisTurn(true); // await Task.Delay(TimeSpan.FromMilliseconds(turnDelayMs)); } else { Debug.LogWarning("Item of unrecognized type clicked on."); } ourUnit.hasMovedThisTurn = true; await runAppropriateCutscenes(); //Check if we eliminated the last unit. await checkWinAndLose(); // Update AI capture point if Intercept mission if (objective is InterceptObjective) { foreach (Character c in level.characters) { if (c.agent is DefendAgent) { (c.agent as DefendAgent).capturePoint = battlefield.getUnitCoords((objective as InterceptObjective).vips[0]); } } } //If all of our units have moved advance. Otherwise, go back to unit selection. if (battlefield.charactersUnits[level.characters[currentCharacter]].All(unit => { //I know this looks inelegant but it avoid calling getUnitCoords if necessary if (!unit.hasMovedThisTurn) { return(false); } else if (unit.getHasAttackedThisTurn()) { return(true); } else { Coord coord = battlefield.getUnitCoords(unit); return(unit.getTargets(coord.x, coord.y, battlefield, level.characters[currentCharacter]).Count == 0); } })) { advanceBattleStage(); } else { setBattleLoopStage(BattleLoopStage.UnitSelection); } break; case BattleLoopStage.EndTurn: //If we've already entered this we're awaiting. Don't call it again every frame. if (!battleStageChanged) { break; } battleStageChanged = false; //Check cutscenes every end phase await runAppropriateCutscenes(); foreach (Unit unit in battlefield.charactersUnits[level.characters[currentCharacter]]) { Coord coord = battlefield.getUnitCoords(unit); Tile tile = battlefield.map[coord.x, coord.y].Peek(); await checkTile(tile, unit); unit.hasMovedThisTurn = false; unit.setHasAttackedThisTurn(false); } bool endGame = await checkWinAndLose(); if (!endGame) { advanceBattleStage(); } halfTurnsElapsed++; break; } }