//MAP FILE: A PRIMER //Map files are plaintext files encoded with data from which we can load maps //The format for the map file is as follows (omit the <> when writing): //[Start of File] //<x size> //<y size> //<tile set number> //<music number> //<x coordinate>,<y coordinate>,<height>,<unit number (see below)>,<player number[0 or 1]>,<impassible[0 or 1]>,<move cost>,<type> //[repeat for each tile] //[end of file] public static Map LoadMap(string filename) { StreamReader sr = new StreamReader(filename); string file = sr.ReadToEnd(); string[] lines = file.Split(new string[]{Environment.NewLine}, StringSplitOptions.RemoveEmptyEntries); int sizeX = Int32.Parse(lines[0]); int sizeY = Int32.Parse(lines[1]); int tileSet = Int32.Parse(lines[2]); int music = Int32.Parse(lines[3]); int linecount = 4; Map finalMap = new Map(new int[]{sizeX, sizeY}, tileSet, music); for (int i = 4; i < lines.Length; i++) { linecount++; Tile newTile = new Tile(); string[] tileData = lines[i].Split(','); int X = Int32.Parse(tileData[0]); int y = Int32.Parse(tileData[1]); int height = Int32.Parse(tileData[2]); int unit = Int32.Parse(tileData[3]); int PlayerUnit = Int32.Parse(tileData[4]); int impassible = Int32.Parse(tileData[5]); int moveCost = Int32.Parse(tileData[6]); newTile.MoveCost = moveCost; string type = tileData[7]; newTile.type = type; newTile.X = X; newTile.Y = y; newTile.Height = height; if (impassible == 0) { newTile.IsImpassible = false; } else { newTile.IsImpassible = true; } Unit tileUnit; newTile.hasUnit = true; //the following is a list of unit codes, use -1 for no unit switch (unit) { case 0: tileUnit = new Soldier(); break; case 1: tileUnit = new Defender(); break; case 2: tileUnit = new Cavalry(); break; case 3: tileUnit = new Ranger(); break; case 4: tileUnit = new Mage(); break; case 5: tileUnit = new Artillery(); break; case 6: tileUnit = new Scout(); break; case 7: tileUnit = new Bomber(); break; case 8: tileUnit = new Fighter(); break; default: tileUnit = null; newTile.hasUnit = false; break; } if (newTile.hasUnit) { newTile.IsImpassible = true; if (PlayerUnit == 0) { tileUnit.isPlayerUnit = true; } else { tileUnit.isPlayerUnit = false; } newTile.TileUnit = tileUnit; newTile.IsImpassible = true; tileUnit.Location[0] = newTile.X; tileUnit.Location[1] = newTile.Y; } else { newTile.TileUnit = null; } newTile.AssignFileName(); finalMap.map[X][y] = newTile; if (newTile.type == "water") { newTile.IsImpassible = true; } } sr.Close(); return finalMap; }
public static void MakeAIMove(Battle battle, Unit active) { Map map = battle.BattleMap; Tile location = map.GetTileAt(active.Location[0], active.Location[1]); //the AI favors nearby units with low health, preferrably out of range of enemies List<Unit> enemies = new List<Unit>(); foreach (Unit unit in battle.BattleQueue) { if (unit.isPlayerUnit) enemies.Add(unit); } Unit nearestEnemy = new Soldier(); int nearestEnemyDistance = 30000; Tile nearestLocation = new Tile(); //calculate the closest enemy foreach (Unit enemy in enemies) { Tile enemyTile = map.GetTileAt(enemy.Location[0], enemy.Location[1]); List<Tile> enemyAdjTiles = GetAdjacentLegalTiles(map, enemyTile); foreach (Tile adj in enemyAdjTiles) { List<Tile> path = GetPath(location, adj, map); foreach (Tile p in path) { int pathTotal = 0; p.FScore = 0; p.GScore = 0; p.HScore = 0; p.parentTile = null; pathTotal += p.MoveCost; if (pathTotal < nearestEnemyDistance) { nearestEnemyDistance = pathTotal; nearestEnemy = enemy; nearestLocation = adj; } } } } //calculate the best unit, if any, in range Unit attackEnemy; int range = active.Range; int x = active.Location[0]; int y = active.Location[1]; List<int[]> rangeSquare = new List<int[]>() ; for (int i = (range * -1); i <= range; i++) { for (int j = (range * -1); j <= range; j++) { if ((i + x) < map.Size[0] && (j + y) < map.Size[1] && (i + x) >= 0 & (j + y) >= 0) { rangeSquare.Add(new int[] { i + x, j + y }); } } } List<Tile> actualRange = new List<Tile>(); foreach (int[] tile in rangeSquare) { if ((Math.Abs(tile[0] - x) + Math.Abs(tile[1] - y)) <= range) { actualRange.Add(map.GetTileAt(tile[0], tile[1])); } } List<Unit> attackableUnits = new List<Unit>(); foreach (Tile tile in actualRange) { if (tile.hasUnit) { if (tile.TileUnit.isPlayerUnit) { attackableUnits.Add(tile.TileUnit); } } } //look for the enemy with the highest HP that can be killed in one or two hits if (attackableUnits.Count > 0) { int highestKillableHP = 0; Unit highestKillableUnit = new Soldier(); foreach (Unit enemy in attackableUnits) { if (AttackResolver.Attack(active, enemy, active.AttackModifiers) * active.AP > enemy.HP && enemy.HP > highestKillableHP) { highestKillableHP = enemy.HP; highestKillableUnit = enemy; } } int highestDamage = 0; Unit highestDamageUnit = new Soldier() ; //if no enemy is killable, find the one we can do the greatest damage to if (highestKillableHP == 0) { foreach (Unit enemy in attackableUnits) { int damage = AttackResolver.Attack(active, enemy, active.AttackModifiers); if (damage * active.AP > highestDamage) { highestDamage = damage * active.AP; highestDamageUnit = enemy; } } attackEnemy = highestDamageUnit; } else { attackEnemy = highestKillableUnit; } battle.GameUI.unitDamage = battle.Attack(attackEnemy); battle.GameUI.attackedUnitTrueX = attackEnemy.Location[0] * 55 - 13; battle.GameUI.attackedUnitTrueY = attackEnemy.Location[1] * 55 - 20; battle.GameUI.displayDamage = true; return; } //if the unit is weak, defend if(active.HP < active.MaxHP / 4 && active.AP == 1) { battle.SelectDefend(); return; } //now we check on which tile to move to List<int[]> reachableTilesAsInt = map.GetLegalMoveCoordinates(active); List<Tile> reachableTiles = new List<Tile>(); foreach (int[] coords in reachableTilesAsInt) { reachableTiles.Add(map.GetTileAt(coords[0], coords[1])); } Tile closest = map.GetTileAt(active.Location[0], active.Location[1]); int nearestTileToEnemy = 30000; foreach (Tile test in reachableTiles) { if (!test.hasUnit) { int pathCost = 0; List<Tile> path = GetPath(nearestLocation, test, map); foreach (Tile p in path) { pathCost += p.MoveCost; } if (pathCost < nearestTileToEnemy) { nearestTileToEnemy = pathCost; closest = test; } } } if (closest != map.GetTileAt(active.Location[0], active.Location[1])) { battle.StartMove(closest); return; } else { active.AP = 0; } }