// 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; } }
// Update is called once per frame async void Update() { switch (battleStage) { case BattleLoopStage.Initial: if (!cutscene.inProgress) { advanceBattleStage(); } break; case BattleLoopStage.Pick: //TODO This is temp just for testing until pick phase gets built. addUnit(UnitType.Knight, level.characters[0], 0, 0); addUnit(UnitType.Knight, level.characters[0], 1, 0); addUnit(UnitType.Knight, level.characters[0], 0, 1); addUnit(UnitType.Knight, level.characters[1], 3, 7); addUnit(UnitType.Knight, level.characters[1], 4, 7); foreach (Unit unit in battlefield.charactersUnits[level.characters[1]]) { Renderer rend = unit.gameObject.GetComponent <Renderer>(); rend.material.shader = Shader.Find("_Color"); rend.material.SetColor("_Color", Color.green); rend.material.shader = Shader.Find("Specular"); rend.material.SetColor("_SpecColor", Color.green); } advanceBattleStage(); break; case BattleLoopStage.BattleLoopStart: advanceBattleStage(); break; case BattleLoopStage.TurnChange: //There's probably a less fragile way of doing this. It's just to make sure this call only happens once per turn loop. if (!turnPlayerText.enabled) { currentCharacter = (currentCharacter + 1) % level.characters.Length; turnPlayerText.text = level.characters[currentCharacter].name + "'s turn"; 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: //Player input. LMB if (Input.GetButtonDown("Select")) { RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, 1000.0f)) { Vector3Int tileCoords = Util.WorldToGrid(hit.transform.position); IBattlefieldItem selectedItem = battlefield.battlefieldItemAt(tileCoords.x, tileCoords.y, tileCoords.z); if (selectedItem is Tile) { //Selected a tile, show info abt that tile //TODO: Show info about tile if a tile is clicked Tile selectedTile = selectedItem as Tile; highlightSingleObject(selectedTile.gameObject); } else if (selectedItem is Unit) { Unit selectedUnit = selectedItem as Unit; if (selectedUnit.getCharacter(battlefield) == level.characters[currentCharacter] && !selectedUnit.hasMovedThisTurn) { //Selected friendly unit. show move options. highlightSingleObject(selectedUnit.gameObject, 1); this.highlightedFriendlyUnit = selectedUnit; moveOptions = selectedUnit.getValidMoves(tileCoords.x, tileCoords.y, battlefield); foreach (Coord moveOption in moveOptions) { highlightMultipleObjects(battlefield.map[moveOption.x, moveOption.y].Peek().gameObject); } this.highlightedEnemyUnits = selectedUnit.getTargets(tileCoords.x, tileCoords.y, battlefield, level.characters[currentCharacter]); foreach (Unit targetableUnit in highlightedEnemyUnits) { highlightMultipleObjects(targetableUnit.gameObject, 2); } advanceBattleStage(); } else { //Selected enemy unit. Show unit and its move options. //TODO: highlight enemy's valid move tiles. } } else if (selectedItem == null) { //Clicked on empty space! Nbd, don't do anything. Debug.Log("Clicked on empty space"); } else { Debug.LogWarning("Item of unrecognized type clicked on."); } } } //If player has selected a move: //TODO play the animation break; case BattleLoopStage.ActionSelection: if (Input.GetButtonDown("Select")) { RaycastHit hit; Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); if (Physics.Raycast(ray, out hit, 1000.0f)) { Vector3Int tileCoords = Util.WorldToGrid(hit.transform.position); IBattlefieldItem selectedItem = battlefield.battlefieldItemAt(tileCoords.x, tileCoords.y, tileCoords.z); if (selectedItem is Tile) { //We selected a tile! lets move to it if (moveOptions.Any(move => (move.x == tileCoords.x && move.y == tileCoords.y))) { moveUnit(highlightedFriendlyUnit, tileCoords); deselectMoveOptions(); highlightedFriendlyUnit.hasMovedThisTurn = true; if (battlefield.charactersUnits[level.characters[currentCharacter]].All(unit => unit.hasMovedThisTurn)) { advanceBattleStage(); } else { this.battleStage = BattleLoopStage.UnitSelection; } } } else if (selectedItem == null) { //Clicked on empty space, deselect deselectMoveOptions(); battleStage = BattleLoopStage.UnitSelection; } else if (selectedItem is Unit) { Unit selectedUnit = selectedItem as Unit; if (highlightedFriendlyUnit == selectedUnit) { //clicked on the same unit, deselect deselectMoveOptions(); battleStage = BattleLoopStage.UnitSelection; } else if (selectedUnit.getCharacter(battlefield) == level.characters[currentCharacter]) { //Clicked on a friendly unit. Deselect the current one. deselectMoveOptions(); battleStage = BattleLoopStage.UnitSelection; } else { //Clicked on a hostile unit! fight! if (highlightedEnemyUnits.Contains(selectedUnit)) { bool defenderDefeated = highlightedFriendlyUnit.doBattleWith( selectedUnit, battlefield.map[tileCoords.x, tileCoords.y].Peek(), battlefield); await Task.Delay(TimeSpan.FromMilliseconds(250)); if (defenderDefeated) { highlightedEnemyUnits.RemoveAll(units => units == null); } else { //Counterattack Coord unitCoords = battlefield.getUnitCoords(highlightedFriendlyUnit); selectedUnit.doBattleWith( highlightedFriendlyUnit, battlefield.map[unitCoords.x, unitCoords.y].Peek(), battlefield); } checkWinAndLose(); highlightedFriendlyUnit.hasMovedThisTurn = true; await Task.Delay(TimeSpan.FromMilliseconds(250)); deselectMoveOptions(); //If all of our units have moved advance. Otherwise, go back to unit selection. if (battlefield.charactersUnits[level.characters[currentCharacter]].All(unit => unit.hasMovedThisTurn)) { advanceBattleStage(); } else { this.battleStage = BattleLoopStage.UnitSelection; } } } } else { Debug.LogWarning("Item of unrecognized type clicked on."); } } } break; case BattleLoopStage.EndTurn: foreach (Unit unit in battlefield.charactersUnits[level.characters[currentCharacter]]) { unit.hasMovedThisTurn = false; } checkWinAndLose(); advanceBattleStage(); 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; } }
// Update is called once per frame async void Update() { switch (battleStage) { case BattleLoopStage.Initial: if (!cutscene.inProgress) { advanceBattleStage(); } break; case BattleLoopStage.Pick: //TODO This is temp just for testing until pick phase gets built. addUnit(UnitType.Knight, level.characters[0], 0, 0); addUnit(UnitType.Knight, level.characters[0], 1, 0); addUnit(UnitType.Knight, level.characters[0], 0, 1); addUnit(UnitType.Knight, level.characters[1], 3, 7); addUnit(UnitType.Knight, level.characters[1], 4, 7); foreach (Unit unit in battlefield.charactersUnits[level.characters[1]]) { Renderer rend = unit.gameObject.GetComponent <Renderer>(); rend.material.shader = Shader.Find("_Color"); rend.material.SetColor("_Color", Color.green); rend.material.shader = Shader.Find("Specular"); rend.material.SetColor("_SpecColor", Color.green); } advanceBattleStage(); break; case BattleLoopStage.BattleLoopStart: advanceBattleStage(); break; case BattleLoopStage.TurnChange: //There's probably a less fragile way of doing this. It's just to make sure this call only happens once per turn loop. if (!turnPlayerText.enabled) { currentCharacter = (currentCharacter + 1) % level.characters.Length; turnPlayerText.text = level.characters[currentCharacter].name + "'s turn"; 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 this 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.fromX, move.fromY]; IBattlefieldItem selectedItem = battlefield.battlefieldItemAt(move.toX, move.toY); if (selectedItem is Tile) { //We selected a tile! lets move to it moveUnit(ourUnit, move.toX, move.toY); } else if (selectedItem is Unit) { //Targeted a hostile unit! fight! Unit selectedUnit = selectedItem as Unit; bool defenderDefeated = ourUnit.doBattleWith( selectedUnit, battlefield.map[move.toX, move.toY].Peek(), battlefield); await Task.Delay(TimeSpan.FromMilliseconds(250)); if (!defenderDefeated) { //Counterattack selectedUnit.doBattleWith( ourUnit, battlefield.map[move.fromX, move.fromY].Peek(), battlefield); } 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 => unit.hasMovedThisTurn)) { advanceBattleStage(); } else { setBattleLoopStage(BattleLoopStage.UnitSelection); } break; case BattleLoopStage.EndTurn: foreach (Unit unit in battlefield.charactersUnits[level.characters[currentCharacter]]) { unit.hasMovedThisTurn = false; } checkWinAndLose(); advanceBattleStage(); break; } }