public static float EvaluateAOEAttackState(GameState gameState, HexTileController htc) { //Data is going into a MinQ, smaller number is better float aiHealthLost = 0; float playerLost = 0; List <HexTile> attackRange = htc.FindRadius(gameState.selfTile, gameState.selfChar.stats.aoeRange); attackRange.Add(gameState.selfTile); foreach (HexTile hex in attackRange) { foreach (Character c in gameState.aiChars) { if (hex.Equals(htc.FindHex(c.gameCharacter.position))) { aiHealthLost += gameState.selfChar.stats.attackdmg; } } foreach (Character c in gameState.playerChars) { if (hex.Equals(htc.FindHex(c.gameCharacter.position))) { playerLost += gameState.selfChar.stats.attackdmg; } } } return(aiHealthLost - playerLost); }
public List <Character> GetAllInAOERange(HexTile tile, int tiles) { List <Character> inrange = new List <Character>(); int radius = tiles; GameObject[] tmp = Array.ConvertAll <HexTile, GameObject>(htc.FindRadius(tile, radius).ToArray(), t => t.HoldingObject); for (int i = 0; i < tmp.Length; i++) { if (tmp[i] == null) { continue; } Agent agent = tmp[i].GetComponent <Agent>(); if (agent != null) { inrange.Add(agent.character); } } return(inrange); }
public static MiniAction DecideAction(GameState gameState, HexTileController htc) { MoveDebug md = GameObject.FindGameObjectWithTag("MoveDebug").GetComponent <MoveDebug>(); int attackRadius = gameState.selfChar.stats.range; // **** Spencer Notes ****** /* If you can attack, do * Else evaluate all the locations you could possible move to, * then take the largest and move to it */ //If this character is the hacker, find best possible place to put the attack if (gameState.selfChar.characterclass == CharacterClass.HACKER) { List <HexTile> attackRange = htc.FindRadius(gameState.selfTile, attackRadius); PriorityQueue attackFringe = new PriorityQueue(); md.ClearAll(); foreach (HexTile hex in attackRange) { GameState gs = new GameState(gameState.aiChars, gameState.playerChars, hex, gameState.selfChar); float value = EvaluateAOEAttackState(gs, htc); md.SetText(hex, value); //If this attack will do more damage to yourself, don't add it to the list if (value < -1) { attackFringe.Push((hex, null), value); } } //If there is nothing in the list (No good attacks) Move intead if (attackFringe.HasNext()) { ((HexTile attackHex, List <int> a), float value) = attackFringe.PopWithVal(); //If this attack only did damage to 1 character (or 1 more than your own chars) /* *** Come back if you have more time **** * if (value <= gameState.selfChar.stats.attackdmg) * { * //Find see if there is a better place to attack and move to that spot * * }*/ return(new MiniAttack() { type = "AOEAttack", attackLocation = attackHex.Position }); } } else if (gameState.selfChar.characterclass == CharacterClass.PSYONIC) { Character needestChar = null; Character cantReachChar = null; float cantReachHealth = 1; float leastHealth = 1; foreach (Character character in gameState.aiChars) { if (character.CompareTo(gameState.selfChar) != 0) { int distance = htc.FindHexDistance(gameState.selfChar.gameCharacter.position, character.gameCharacter.position); float health = character.stats.health / character.stats.maxHealth; //If you can heal the character, and the health is less than 1 if (health < leastHealth) { if (distance <= attackRadius) { leastHealth = health; needestChar = character; } else { cantReachHealth = health; cantReachChar = character; } } } } if (leastHealth < 1) { return(new MiniAttack() { type = "Attack", toAttack = needestChar }); } else if (cantReachHealth < 1) { //If there is a character in need that you can't reach, move towards it Debug.Log("Healer Moving towards " + cantReachChar.name); HexTile toMovTo = MoveTowards(cantReachChar, gameState, htc, true); return(new MiniMove() { type = "Move", Dest = toMovTo }); } else { //Can't heal yourself******* //Move towards the Ranger Character target = GetCharacter(gameState.aiChars, CharacterClass.RANGED); if (target != null) { HexTile toMovTo = MoveTowards(target, gameState, htc, true); return(new MiniMove() { type = "Move", Dest = toMovTo }); } target = GetCharacter(gameState.aiChars, CharacterClass.HACKER); if (target != null) { HexTile toMovTo = MoveTowards(target, gameState, htc, true); return(new MiniMove() { type = "Move", Dest = toMovTo }); } target = GetCharacter(gameState.aiChars, CharacterClass.MELEE); if (target != null) { HexTile toMovTo = MoveTowards(target, gameState, htc, true); return(new MiniMove() { type = "Move", Dest = toMovTo }); } //No other characters but you exist, await the sweet release of death return(new MiniMove() { type = "Move", Dest = gameState.selfTile }); } } else { Character weakestChar = null; Character deadChar = null; float leastHealth = int.MaxValue; foreach (Character character in gameState.playerChars) { int distance = htc.FindHexDistance(gameState.selfChar.gameCharacter.position, character.gameCharacter.position); if (distance <= attackRadius) { //If your attack would kill this character, target this one above all else if ((Mathf.Max(0, character.stats.health - gameState.selfChar.stats.attackdmg) / character.stats.maxHealth) <= 0) { deadChar = character; } if ((character.stats.health / character.stats.maxHealth) < leastHealth) { leastHealth = (character.stats.health / character.stats.maxHealth); weakestChar = character; } } } //Attack the soon to be dead character if it can if (deadChar != null) { return(new MiniAttack() { type = "Attack", toAttack = deadChar }); } if (weakestChar != null) { return(new MiniAttack() { type = "Attack", toAttack = weakestChar }); } } // **** Spencer Notes ****** /* Could not find anything to attack so move to the best possible location */ List <HexTile> possibleMoves = htc.FindRadius(gameState.selfTile, gameState.selfChar.stats.speed); List <Character> allChars = gameState.aiChars.Concat(gameState.playerChars).ToList(); List <(HexTile, List <int>)> possibleMoves2 = ValidateRadius(gameState.selfTile, possibleMoves, gameState.selfChar.stats.speed, allChars, htc); //possibleMoves = ValidateRadius(gameState.selfTile, possibleMoves, gameState.selfChar.stats.speed, allChars, htc); possibleMoves = new List <HexTile>(); foreach ((HexTile hex, List <int> path) in possibleMoves2) { possibleMoves.Add(hex); } PriorityQueue fringe = new PriorityQueue(); foreach (HexTile hex in possibleMoves) { GameState gs = new GameState(gameState.aiChars, gameState.playerChars, hex, gameState.selfChar); fringe.Push((hex, null), EvaluateState(gs, htc)); } if (!fringe.HasNext()) { //No avialable moves, move to self return(new MiniMove() { type = "Move", Dest = gameState.selfTile }); } (HexTile state, List <int> actions) = fringe.Pop(); return(new MiniMove() { type = "Move", Dest = state }); }
public static HexTile MoveTowards(Character target, GameState gameState, HexTileController htc, bool runFromEnemy = false) { //choose the tile you want to move to, either the character directly, or a tile next to the character that is away from the enemy HexTile targetTile = htc.FindHex(target.gameCharacter.position); if (runFromEnemy) { List <HexTile> tilesAroundTarget = htc.FindRadius(targetTile, 1); int farthest = 0; foreach (HexTile hexTile in tilesAroundTarget) { if (!hexTile.IsObstacle && hexTile.HoldingObject == null) { //Find distance to all player characters int newDist = 0; foreach (Character c in gameState.playerChars) { newDist += htc.FindHexDistance(hexTile.Position, c.gameCharacter.position); } //You want the distance to the player to be largest if (newDist > farthest) { farthest = newDist; targetTile = hexTile; } } } } List <int> moves = GreedySearch(gameState.selfTile, targetTile, htc); //If run from enemy is false, your target in ON a character, so remove that last step if (!runFromEnemy) { //Remove the last step (the one on the distination character) if (moves.Count > 0) { moves.RemoveAt(moves.Count - 1); } } Debug.Log("Psyonic wants to move ..."); foreach (int i in moves) { Debug.Log(i); } Debug.Log("To get to " + target.name); //If you were already right next to the target, don't go anywhere if (moves.Count == 0) { return(gameState.selfTile); } //Only keep the number of steps that you are allowed to move //Starting hex is your own HexTile hex = gameState.selfTile; //Repet until you hit your step count, or you run out of moves for (int i = 0; i < Mathf.Min(gameState.selfChar.stats.speed, moves.Count); i++) { //Get the neighbor that the path tells you too hex = hex.nexts[moves[i]]; } return(hex); }