protected List <Coord> findNearestEnemies(Coord start) { int[,] moveDirs = new int[, ] { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; HashSet <Coord> visited = new HashSet <Coord>(); Queue <Coord> moveQueue = new Queue <Coord>(); moveQueue.Enqueue(start); visited.Add(start); List <Coord> enemies = new List <Coord>(); int minDist = Int32.MaxValue; while (moveQueue.Count() > 0) { Coord curCoord = moveQueue.Dequeue(); if (manhattanDistance(start, curCoord) > minDist) { return(enemies); } IBattlefieldItem item = battlefield.battlefieldItemAt(curCoord.x, curCoord.y, 0); if (item is Unit) { Unit unit = item as Unit; if (!battlefield.charactersUnits[character].Contains(unit)) { enemies.Add(curCoord); if (minDist == Int32.MaxValue) { minDist = manhattanDistance(start, curCoord); } } } for (int x = 0; x < moveDirs.GetLength(0); x++) { Coord nextCoord = new Coord(curCoord.x + moveDirs[x, 0], curCoord.y + moveDirs[x, 1]); if (nextCoord.x >= 0 && nextCoord.y >= 0 && nextCoord.x < battlefield.map.GetLength(0) && nextCoord.y < battlefield.map.GetLength(1)) { if (!visited.Contains(nextCoord)) { visited.Add(nextCoord); moveQueue.Enqueue(nextCoord); } } } } return(enemies); }
protected Unit coordToUnit(Coord coord) { IBattlefieldItem item = battlefield.battlefieldItemAt(coord.x, coord.y, 0); if (item is Unit) { return(item as Unit); } else { return(null); } }
// Replaced findEnemiesWithinDistance. Use with filterEnemies to achieve the same result. protected List <Coord> findUnitsWithinDistance(Coord start, int minDist) { int[,] moveDirs = new int[, ] { { 0, 1 }, { 0, -1 }, { 1, 0 }, { -1, 0 } }; HashSet <Coord> visited = new HashSet <Coord>(); Queue <Coord> moveQueue = new Queue <Coord>(); moveQueue.Enqueue(start); visited.Add(start); List <Coord> units = new List <Coord> (); while (moveQueue.Count() > 0) { Coord curCoord = moveQueue.Dequeue(); if (manhattanDistance(start, curCoord) > minDist) { return(units); } IBattlefieldItem item = battlefield.battlefieldItemAt(curCoord.x, curCoord.y, 0); if (item is Unit) { Unit unit = item as Unit; units.Add(curCoord); } for (int x = 0; x < moveDirs.GetLength(0); x++) { Coord nextCoord = new Coord(curCoord.x + moveDirs[x, 0], curCoord.y + moveDirs[x, 1]); if (nextCoord.x >= 0 && nextCoord.y >= 0 && nextCoord.x < battlefield.map.GetLength(0) && nextCoord.y < battlefield.map.GetLength(1)) { if (!visited.Contains(nextCoord)) { visited.Add(nextCoord); moveQueue.Enqueue(nextCoord); } } } } return(units); }
// 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; } }
public void getSelectionPhase(Move currentMove) { 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; unhighlightAll(); highlight(selectedTile.gameObject); //This method will get called again because we didn't find a valid selection } else if (selectedItem is Unit) { Unit selectedUnit = selectedItem as Unit; if (selectedUnit.getCharacter(battlefield) == this.character && (!selectedUnit.hasMovedThisTurn || (!selectedUnit.getHasAttackedThisTurn() && selectedUnit.getTargets(tileCoords.x, tileCoords.y, battlefield, character).Count != 0))) { //Selected friendly unit. Valid selection, store selection coords. currentMove.from = new Coord(tileCoords.x, tileCoords.y); //show move options unhighlightAll(); highlight(selectedUnit, 1); this.highlightedFriendlyUnit = selectedUnit; moveOptions = selectedUnit.getValidMoves(tileCoords.x, tileCoords.y, battlefield); foreach (Coord moveOption in moveOptions) { highlight(battlefield.map[moveOption.x, moveOption.y].Peek().gameObject, 1); } this.targetableUnits = selectedUnit.getTargets(tileCoords.x, tileCoords.y, battlefield, this.character); foreach (Coord targetableUnit in targetableUnits) { int colorIndex = selectedUnit is Cleric ? 3 : 2; highlight(battlefield.units[targetableUnit.x, targetableUnit.y], colorIndex); highlight(battlefield.map[targetableUnit.x, targetableUnit.y].Peek().gameObject, colorIndex); } } else { //Selected enemy unit. Show unit and its move options. unhighlightAll(); highlight(selectedUnit, 2); moveOptions = selectedUnit.getValidMoves(tileCoords.x, tileCoords.y, battlefield); foreach (Coord moveOption in moveOptions) { highlight(battlefield.map[moveOption.x, moveOption.y].Peek().gameObject, 2); } this.targetableUnits = selectedUnit.getTargets(tileCoords.x, tileCoords.y, battlefield, selectedUnit.getCharacter(battlefield)); foreach (Coord targetableUnit in targetableUnits) { int colorIndex = selectedUnit is Cleric ? 3 : 2; highlight(battlefield.units[targetableUnit.x, targetableUnit.y], colorIndex); highlight(battlefield.map[targetableUnit.x, targetableUnit.y].Peek().gameObject, colorIndex); } } } 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."); } } }
public void getMovePhase(Move currentMove) { 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))) { currentMove.to = new Coord(tileCoords.x, tileCoords.y); } else { //Clicked on invalid tile, restart. currentMove.from = null; } unhighlightAll(); } else if (selectedItem == null) { //Clicked on empty space, deselect unhighlightAll(); currentMove.from = null; } else if (selectedItem is Unit) { Unit selectedUnit = selectedItem as Unit; if (highlightedFriendlyUnit == selectedUnit) { //clicked on the same unit, return the "do nothing" move unhighlightAll(); currentMove.to = new Coord(tileCoords.x, tileCoords.y); } else if (selectedUnit.getCharacter(battlefield) == this.character && !(highlightedFriendlyUnit is Cleric)) { //Clicked on a friendly unit. Deselect the current one. unhighlightAll(); currentMove.from = null; } else { //Clicked on a hostile unit! fight! if (targetableUnits.Any(coord => coord.x == tileCoords.x && coord.y == tileCoords.y)) { currentMove.to = new Coord(tileCoords.x, tileCoords.y); } else { //Clicked on invalid enemy unit, restart. currentMove.from = null; } unhighlightAll(); } } else { Debug.LogWarning("Item of unrecognized type clicked on."); } } }
// 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; } }
public async Task <Move> getSelectionPhase(Move currentMove) { //Await player input. But. Unity doesn't really support async await. //I'm feeling kinda dumb for not just learning coroutines. Next time! while (!Input.GetButtonDown("Select")) { await Task.Delay(1); } 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); //This method will get called again because we didn't find a valid selection } else if (selectedItem is Unit) { Unit selectedUnit = selectedItem as Unit; if (selectedUnit.getCharacter(battlefield) == this.character && !selectedUnit.hasMovedThisTurn) { //Selected friendly unit. Valid selection, store selection coords. currentMove.fromX = tileCoords.x; currentMove.fromY = tileCoords.y; //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, this.character); foreach (Unit targetableUnit in highlightedEnemyUnits) { highlightMultipleObjects(targetableUnit.gameObject, 2); } } else { //Selected enemy unit. Show unit and its move options. //TODO: highlight enemy's valid move tiles. don't assign currentMove.fromX or fromY, bc not valid advancement criteria } } 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."); } } return(currentMove); }
public async Task <Move> getMovePhase(Move currentMove) { //Await player input. while (!Input.GetButtonDown("Select")) { await Task.Delay(1); } 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))) { currentMove.toX = tileCoords.x; currentMove.toY = tileCoords.y; deselectMoveOptions(); } } else if (selectedItem == null) { //Clicked on empty space, deselect deselectMoveOptions(); currentMove = goBackToSelectionPhase(); } else if (selectedItem is Unit) { Unit selectedUnit = selectedItem as Unit; if (highlightedFriendlyUnit == selectedUnit) { //clicked on the same unit, deselect deselectMoveOptions(); currentMove = goBackToSelectionPhase(); } else if (selectedUnit.getCharacter(battlefield) == this.character) { //Clicked on a friendly unit. Deselect the current one. deselectMoveOptions(); currentMove = goBackToSelectionPhase(); } else { //Clicked on a hostile unit! fight! deselectMoveOptions(); currentMove.toX = tileCoords.x; currentMove.toY = tileCoords.y; } } else { Debug.LogWarning("Item of unrecognized type clicked on."); } } return(currentMove); }
// 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; } }
// 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; } }
public async Task getMovePhase(Move currentMove) { //Await player input. while (!Input.GetButtonDown("Select")) { await Task.Delay(1); } 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))) { currentMove.to = new Coord(tileCoords.x, tileCoords.y); } else { //Clicked on invalid tile, restart. currentMove.from = null; } unhighlightAll(); } else if (selectedItem == null) { //Clicked on empty space, deselect unhighlightAll(); currentMove.from = null; } else if (selectedItem is Unit) { Unit selectedUnit = selectedItem as Unit; if (highlightedFriendlyUnit == selectedUnit) { //clicked on the same unit, deselect unhighlightAll(); currentMove.from = null; } else if (selectedUnit.getCharacter(battlefield) == this.character) { //Clicked on a friendly unit. Deselect the current one. unhighlightAll(); currentMove.from = null; } else { //Clicked on a hostile unit! fight! if (highlightedEnemyUnits.Any(coord => coord.x == tileCoords.x && coord.y == tileCoords.y)) { currentMove.to = new Coord(tileCoords.x, tileCoords.y); } else { //Clicked on invalid enemy unit, restart. currentMove.from = null; } unhighlightAll(); } } else { Debug.LogWarning("Item of unrecognized type clicked on."); } } //Wait for the mouse down event to un-fire. This avoids an infinite loop in the next condition. while (!Input.GetButtonUp("Select")) { await Task.Delay(1); } }