diff --git a/Enemy.cs b/Enemy.cs index 83685ae..70bfe91 100644 --- a/Enemy.cs +++ b/Enemy.cs @@ -11,8 +11,8 @@ public partial class Enemy : StaticBody2D public delegate void ClickedEventHandler(Enemy THIS); [Signal] public delegate void RightClickedEventHandler(Enemy THIS); - public bool _hovered = false, _track = false; - public int _damage = 1, _health = 2, _speed, _speedRemaining, _visibilityRange = 4, _hitRange; + public bool _hovered = false, _track = false, _warp = false; + public int _damage = 1, _health = 2, _stamina, _staminaRemaining, _visibilityRange = 4, _hitRange, _priority = 1; public Vector2I _address = -Vector2I.One, _range = Vector2I.Up; public List _path = new(); public float _movement = 0; @@ -48,44 +48,52 @@ public partial class Enemy : StaticBody2D PLAYER.ChangeHealth(-1, this); } + public bool CanAttack() + { + return _address.Y <= _hitRange; + } + public void CounterAttack(Commander COMMANDER) { } + public virtual List GetGoals(Map MAP) + { + List firstOpenRow = [.. MAP._cells.Where(c => c.Y == MAP.GetFirstOpenRow() && !MAP._astar.IsPointSolid(c))]; + return firstOpenRow; + } + public virtual List GetBestPath(Map MAP) { - Vector2I goal = Vector2I.One * -1000; + List goals = GetGoals(MAP); + List> paths = new(); - goal.Y = MAP.GetFirstOpenRow(); - List openCells = [.. MAP._cells.Where(c => c.Y == goal.Y && !MAP._astar.IsPointSolid(c))]; - List testPath, bestPath = []; - - int bestLength = 999999; - - for (int i = 0; i < openCells.Count; i++) + for (int i = 0; i < goals.Count; i++) { - testPath = MAP.GetPath(_address, openCells[i]); - int testLength = testPath.Count; - if (testLength < bestLength) - { - bestPath = testPath; - bestLength = testLength; - goal = openCells[i]; - } - else if (testLength == bestLength) - { - if (Math.Abs(openCells[i].X - _address.X) < Math.Abs(goal.X - _address.X)) - { - bestPath = testPath; - bestLength = testLength; - goal = openCells[i]; - } - } + paths.Add(MAP.GetPath(_address, goals[i])); } + List bestPath = paths.OrderBy(p => p.Count).ThenBy(p => p.Last().X % 2).ToList()[0]; return bestPath; } + public void GetRemainingStamina(Map MAP) + { + _staminaRemaining = _address.Y <= MAP.GetFirstOpenRow() ? 0 : _stamina; + } + + public void RemainInPlace() + { + if (_path.Count <= 0) + { + _path.Add(_address); + } + else + { + _path.Add(_path.LastOrDefault()); + } + } + public void TakeDamage(int DAMAGE, Commander ATTACKER) { _health -= DAMAGE; diff --git a/EnemyController.cs b/EnemyController.cs index 6ff3a83..5098515 100644 --- a/EnemyController.cs +++ b/EnemyController.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; +using System.Threading.Tasks; public partial class EnemyController : TurnController { @@ -11,6 +12,8 @@ public partial class EnemyController : TurnController public List _enemies = new(); public PlayerController _playerController; + public Tween _movementTween; + public void AddEnemies(int ENEMY_COUNT = 1) { for (int i = 0; i < ENEMY_COUNT; i++) @@ -20,8 +23,8 @@ public partial class EnemyController : TurnController newEnemy.Clicked += HandleEnemyClick; newEnemy.RightClicked += HandleEnemyRightClick; - newEnemy._speed = Globals._rng.Next(2,4+1); - newEnemy.Modulate = new Color(newEnemy._speed == 2 ? "#FF0000" : newEnemy._speed == 3 ? "#00FF00" : "#0000FF"); + newEnemy._stamina = Globals._rng.Next(2,4+1); + newEnemy.Modulate = new Color(newEnemy._stamina == 2 ? "#FF0000" : newEnemy._stamina == 3 ? "#00FF00" : "#0000FF"); newEnemy._enemyController = this; List unoccupied = [.. _playArea._map._bottomRow.Where(c => _enemies.All(e => e._address != c))]; Vector2I randomCell = unoccupied[Globals._rng.Next(unoccupied.Count)]; @@ -39,9 +42,9 @@ public partial class EnemyController : TurnController newEnemy.Clicked += HandleEnemyClick; newEnemy.RightClicked += HandleEnemyRightClick; - newEnemy._speed = Globals._rng.Next(2,4+1); + newEnemy._stamina = Globals._rng.Next(2,4+1); newEnemy._hitRange = Globals._rng.Next(1,2+1); - newEnemy.Modulate = new Color(newEnemy._speed == 2 ? "#FF0000" : newEnemy._speed == 3 ? "#00FF00" : "#0000FF"); + newEnemy.Modulate = new Color(newEnemy._stamina == 2 ? "#FF0000" : newEnemy._stamina == 3 ? "#00FF00" : "#0000FF"); newEnemy._enemyController = this; SetEnemy(newEnemy, POSITIONS[i]); @@ -51,25 +54,78 @@ public partial class EnemyController : TurnController } - public List EnemyAttacks() + public void EnemyAttacks() { - List attackingEnemies = [.. _enemies.Where(e => e._address.Y <= e._hitRange)]; + List attackingEnemies = [.. _enemies.Where(e => e.CanAttack())]; for (int i = 0; i < attackingEnemies.Count; i++) { Enemy enemy = attackingEnemies[i]; enemy.Attack(_playerController); + enemy._staminaRemaining = Math.Max(enemy._staminaRemaining - 2, 0); } - return attackingEnemies; } - public void GetRemainingSpeed(Enemy ENEMY) + public async Task BuildEnemyPaths() { - ENEMY._speedRemaining = ENEMY._address.Y <= _playArea._map.GetFirstOpenRow() || ENEMY._address.Y <= ENEMY._hitRange ? 0 : ENEMY._speed; + Map map = _playArea._map; + + for (int i = 0; i < _enemies.Count; i++) + { + Enemy enemy = _enemies[i]; + enemy.GetRemainingStamina(map); + } + + _enemies.ForEach(e => e._path.Clear()); + + if (_enemies.All(e => e._staminaRemaining <= 0)) + { + return; + } + + while (_enemies.Any(e => e._staminaRemaining > 0)) + { + for (int i = 0; i < _enemies.Count; i++) + { + Enemy enemy = _enemies[i]; + if (enemy._staminaRemaining <= 0) + { + enemy.RemainInPlace(); + continue; + } + if (enemy._address.Y <= map.GetFirstOpenRow()) + { + enemy.RemainInPlace(); + enemy._staminaRemaining = 0; + continue; + } + + List path = enemy.GetBestPath(map); + + if (path.Count == 0) + { + enemy.RemainInPlace(); + continue; + } + + Vector2I cell = path[0]; + if (cell.Y <= enemy._address.Y) // if path would move enemy forward + { + map.SetCellEnemy(cell, enemy); + enemy._path.Add(cell); + } + else + { + enemy.RemainInPlace(); + } + + enemy._staminaRemaining--; + } + } } public void HandleEnemyClick(Enemy ENEMY) { - if (ENEMY._speedRemaining <= 0){ + if (ENEMY._staminaRemaining <= 0){ return; } TileMapLayer pathLayer = _playArea.GetNode("PathLayer"); @@ -95,92 +151,29 @@ public partial class EnemyController : TurnController AddEnemies(positions); } - public void MoveEnemies(List EXCLUDE_ENEMIES) + public void StepEnemies(int STEP) { Map map = _playArea._map; - List movingEnmies = [.. _enemies.Where(e => !EXCLUDE_ENEMIES.Contains(e))]; - for (int i = 0; i < movingEnmies.Count; i++) + if (_movementTween != null) { - Enemy enemy = movingEnmies[i]; - GetRemainingSpeed(enemy); - - if (enemy._speedRemaining > 0) - { - enemy._path = enemy.GetBestPath(map); - - if (enemy._path.Count <= 0) - { - enemy._speedRemaining = 0; - } - } + _movementTween.Kill(); } + _movementTween = CreateTween(); + _movementTween.TweenInterval(0.5f); - List remainingEnemies = GetRemainingEnemies(movingEnmies); - _enemies.ForEach(e => e._path.Clear()); - if (remainingEnemies.Count == 0) + for (int i= 0; i < _enemies.Count; i++) { - return; + Enemy enemy = _enemies[i]; + _movementTween.Parallel().TweenProperty(enemy, "global_position", map.GetCellPositionFromAddress(enemy._path[STEP]), 0.25f); } - while (remainingEnemies.Count > 0) + if (STEP < _enemies[0]._path.Count - 1) { - remainingEnemies = GetRemainingEnemies(remainingEnemies); - for (int i = 0; i < remainingEnemies.Count; i++) - { - Enemy enemy = remainingEnemies[i]; - if (enemy._speedRemaining <= 0) - { - continue; - } - if (enemy._address.Y <= map.GetFirstOpenRow()) - { - enemy._speedRemaining = 0; - continue; - } - List path = enemy.GetBestPath(map); - - if (path.Count == 0) - { - continue; - } - Vector2I cell = path[0]; - if (cell.Y <= enemy._address.Y) - { - map.SetCellEnemy(cell, enemy); - enemy._path.Add(cell); - } - - enemy._speedRemaining--; - } + _movementTween.TweenCallback(Callable.From(() => StepEnemies(STEP + 1))); } - - Tween tween = CreateTween(); - tween.SetParallel(); - - List movingEnemies = [.. _enemies.Where(e => e._path.Count > 0)]; - int maxSteps = movingEnemies.Max(e => e._path.Count); - for (int i = 0; i < maxSteps; i++) + else { - for (int j = 0; j < movingEnemies.Count; j++) - { - Enemy mEnemy = movingEnemies[j]; - if (mEnemy._path.Count <= i) - { - continue; - } - if (j == 0) - { - tween.Chain(); - } - else - { - tween.Parallel(); - } - tween.TweenProperty(mEnemy, "global_position", map.GetCellPositionFromAddress(mEnemy._path[i]), .25f); - } + _movementTween.TweenCallback(Callable.From(() => EndTurn())); } - - tween.TweenCallback(Callable.From(() => EmitSignal(SignalName.TurnDone))); - _playArea.HighlightCells(); } public void RemoveEnemy(Enemy ENEMY_TO_REMOVE) @@ -190,18 +183,22 @@ public partial class EnemyController : TurnController ENEMY_TO_REMOVE.QueueFree(); } - public List GetRemainingEnemies(List ENEMIES) + public void SortEnemies() { - return [.. ENEMIES.Where(e => e._speedRemaining > 0).OrderByDescending(e => e.GetBestPath(_playArea._map).Count).ThenBy(e => e._address.Y).ThenBy(e => Math.Abs(e._address.X - _playArea._map._maxX / 2))]; + _enemies = [.. _enemies.OrderByDescending(e => e._priority).ThenBy(e => e._address.Y).ThenBy(e => e._path.Count).ThenBy(e => Math.Abs(e._address.X - _playArea._map._maxX / 2))]; } - public override void StartTurn() + public override async Task StartTurn() { AddEnemies(1); + + SortEnemies(); - List attackingEnemies = EnemyAttacks(); + EnemyAttacks(); + + await BuildEnemyPaths(); - MoveEnemies(attackingEnemies); + StepEnemies(0); } public void SetEnemy(Enemy ENEMY, Vector2I CELL) diff --git a/Main.cs b/Main.cs index 247942f..c6f521a 100644 --- a/Main.cs +++ b/Main.cs @@ -37,7 +37,7 @@ public partial class Main : Node base._Process(delta); if (Input.IsActionJustPressed("escape")) { - + EndGame(_playerController); } if (Input.IsActionJustPressed("changeTurn")) { @@ -48,18 +48,18 @@ public partial class Main : Node } } - public void ChangeTurn() + public async void ChangeTurn() { if (_turnController != _playerController) { _turnController = _playerController; - _playerController.StartTurn(); + await _playerController.StartTurn(); } else { _turnController = _enemyController; - _enemyController.StartTurn(); + await _enemyController.StartTurn(); } } diff --git a/Map.cs b/Map.cs index 3c8199d..51e252c 100644 --- a/Map.cs +++ b/Map.cs @@ -119,10 +119,10 @@ public partial class Map : TileMapLayer _astar.DefaultComputeHeuristic = AStarGrid2D.Heuristic.Manhattan; _astar.DiagonalMode = AStarGrid2D.DiagonalModeEnum.Never; _astar.Update(); - // for (int i = 0; i < _cells.Count; i++) - // { - // _astar.SetPointWeightScale(_cells[i], _cells[i].Y * 5); - // } + for (int i = 0; i < _cells.Count; i++) + { + _astar.SetPointWeightScale(_cells[i], _cells[i].Y * 2); + } EvaluateSolidCells(); } diff --git a/PlayerController.cs b/PlayerController.cs index def6101..8f1f636 100644 --- a/PlayerController.cs +++ b/PlayerController.cs @@ -2,11 +2,13 @@ using Godot; using System; using System.Collections.Generic; using System.Linq; +using System.Threading.Tasks; public partial class PlayerController : TurnController { [Signal] public delegate void DeathEventHandler(PlayerController THIS); + public bool _dead = false; public int _health, _healthMax = 100; public EnemyController _enemyController; public PackedScene _commanderScene = GD.Load("res://Commander.tscn"); @@ -22,9 +24,10 @@ public partial class PlayerController : TurnController { _health += DAMAGE; _health = Math.Clamp(_health, 0, _healthMax); - GD.Print(_health); - if (_health == 0) + if (_health == 0 && !_dead) { + _dead = !_dead; + GD.Print("YOU DIED"); EmitSignal(SignalName.Death, this); } } @@ -60,7 +63,7 @@ public partial class PlayerController : TurnController _towers[3].AddChild(newCommander); } - public override void StartTurn() + public override async Task StartTurn() { _towers.ForEach(t => t.StartTurn()); } diff --git a/TurnController.cs b/TurnController.cs index f360519..9a55a7b 100644 --- a/TurnController.cs +++ b/TurnController.cs @@ -1,5 +1,6 @@ using Godot; using System; +using System.Threading.Tasks; public partial class TurnController : Node2D { @@ -7,7 +8,11 @@ public partial class TurnController : Node2D public delegate void TurnDoneEventHandler(); public PlayArea _playArea; - public virtual void StartTurn() + public virtual async Task StartTurn() { } + public virtual void EndTurn() + { + EmitSignal(SignalName.TurnDone); + } }