public Map(int[] size, int tileSet, int music) { Size = size; TileSet = tileSet; Music = music; map = new Tile[size[0]][]; for (int i = 0; i < map.Length; i++) { map[i] = new Tile[size[1]]; } }
public static List<Tile> GetAdjacentLegalTiles(Map map, Tile currentTile) { List<Tile> adjacentTiles = new List<Tile>(); int x = currentTile.X; int y = currentTile.Y; if (x - 1 >= 0) { Tile left = map.map[x - 1][y]; if (!left.IsImpassible) { adjacentTiles.Add(left); } } if (x + 1 < map.Size[0]) { Tile right = map.map[x + 1][y]; if(!right.IsImpassible) { adjacentTiles.Add(right); } } if(y - 1 >= 0) { Tile up = map.map[x][y - 1]; if(!up.IsImpassible) adjacentTiles.Add(up); } if(y + 1 < map.Size[1]) { Tile down = map.map[x][y + 1]; if(!down.IsImpassible) { adjacentTiles.Add(down); } } return adjacentTiles; }
public static int GetFCost(Map map, Tile tile, Tile destination) { int GCost = 0; bool root = false; Tile test = tile; while (!root) { GCost += test.MoveCost; if (test.IsRoot) { root = true; } else { test = test.parentTile; } } int HCost = (GetManhattanDistance(tile, destination)); return GCost + HCost; }
public static List<Tile> BuildPath(Tile endpoint) { List<Tile> path = new List<Tile>(); bool root = false; Tile current = endpoint; while (!root) { path.Add(current); if (current.IsRoot) { root = true; } else { current = current.parentTile; } } return path; }
/// <summary> /// Allows the game to run logic such as updating the world, /// checking for collisions, gathering input, and playing audio. /// </summary> /// <param name="gameTime">Provides a snapshot of timing values.</param> protected override void Update(GameTime gameTime) { MouseState mouseState = Mouse.GetState(); if (mainMenu) { if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed) this.Exit(); Rectangle quickClick = new Rectangle((Window.ClientBounds.Width / 2) - (quick_battle.Width / 2), (Window.ClientBounds.Height / 2) - (quick_battle.Height / 2), 141, 33); Rectangle campaignClick = new Rectangle((Window.ClientBounds.Width / 2) - (campaign.Width / 2), (Window.ClientBounds.Height / 2) - (quick_battle.Height - 55), 141, 33); Rectangle customClick = new Rectangle((Window.ClientBounds.Width / 2) - (custom_battle.Width / 2), (Window.ClientBounds.Height / 2) - (campaign.Height - 95), 175, 36); Rectangle optionsClick = new Rectangle((Window.ClientBounds.Width / 2) - (options.Width / 2), (Window.ClientBounds.Height / 2) - (custom_battle.Height - 140), 141, 33); Rectangle exitclickableArea = new Rectangle((Window.ClientBounds.Width / 2) - (exit.Width / 2), (Window.ClientBounds.Height - 70), 141, 33); // mousepos = new Point(); bool mousestuffs = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(exitclickableArea); bool mousequick = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(quickClick); bool mousecampaign = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(campaignClick); bool mousecustom = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(customClick); bool mouseoptions = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(optionsClick); if (mousestuffs && exit == exit_temp) { exit_temp = exit; exit = exit2; } else if (!mousestuffs && exit != exit_temp) { exit = exit_temp; } //campaign menu button logic if (mouseState.LeftButton == ButtonState.Pressed) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (campaignClick.Contains(mousePos)) { mainMenu = false; campaignmenu = true; LoadContent(); } } //options menu button logic if (mouseState.LeftButton == ButtonState.Pressed) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (optionsClick.Contains(mousePos) && !releaseWait) { releaseWait = true; mainMenu = false; optionsMenu = true; LoadContent(); } } if (mouseState.LeftButton == ButtonState.Pressed) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (exitclickableArea.Contains(mousePos)) { this.Exit(); } } if (mousecampaign && campaign == campaigntemp) { campaigntemp = campaign; campaign = campaign_invert; } else if (!mousecampaign && campaign != campaigntemp) { campaign = campaigntemp; } if (mousecustom && custom_battle == custom_battletemp) { custom_battletemp = custom_battle; custom_battle = custom_battle_invert; } else if (!mousecustom && custom_battle != custom_battletemp) { custom_battle = custom_battletemp; } if (mouseoptions && options == optionstemp) { optionstemp = options; options = options_invert; } else if (!mouseoptions && options != optionstemp) { options = optionstemp; } // TODO: Add your update logic here if (mousequick && quick_battle == quick_temp) { quick_temp = quick_battle; quick_battle = quick_battle_invert; } else if (!mousequick && quick_battle != quick_temp) { quick_battle = quick_temp; } if (mouseState.LeftButton == ButtonState.Pressed) { // We now know the left mouse button is down and it wasn't down last frame // so we've detected a click // Now find the position Point mousePos = new Point(mouseState.X, mouseState.Y); if (exitclickableArea.Contains(mousePos)) { this.Exit(); } } // TODO: Add your update logic here if (mousequick && quick_battle == quick_temp) { quick_temp = quick_battle; quick_battle = quick_battle_invert; } else if (!mousequick && quick_battle != quick_temp) { quick_battle = quick_temp; } if (mouseState.LeftButton == ButtonState.Pressed) { // We now know the left mouse button is down and it wasn't down last frame // so we've detected a click // Now find the position Point mousePos = new Point(mouseState.X, mouseState.Y); if (quickClick.Contains(mousePos)) { mainMenu = false; demo = true; MediaPlayer.Stop(); Map mainMap = MapLoader.LoadMap(@"Content\Demo.txt"); LoadContent(); } } } else if (campaignmenu) { Rectangle backClick = new Rectangle(15, 755, 141, 33); Rectangle newGameClick = new Rectangle(550, 300, 141, 33); Rectangle loadGameClick = new Rectangle(550, 343, 141, 33); bool mouseback = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(backClick); bool mousenew = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(newGameClick); bool mouseload = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(loadGameClick); if (mouseback && back == backtemp) { backtemp = back; back = back_invert; } else if (!mouseback && back != backtemp) { back = backtemp; } if (mousenew && newGame == newGametemp) { newGametemp = newGame; newGame = newGame_invert; } else if (!mousenew && newGame != newGametemp) { newGame = newGametemp; } if (mouseload && loadGame == loadGametemp) { loadGametemp = loadGame; loadGame = loadGame_invert; } else if (!mouseload && loadGame != loadGametemp) { loadGame = loadGametemp; } if (mouseState.LeftButton == ButtonState.Pressed) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (backClick.Contains(mousePos)) { mainMenu = true; campaignmenu = false; LoadContent(); } } } //logic or options buttons else if (optionsMenu) { Rectangle backClick = new Rectangle(15, 755, 141, 33); Rectangle textClick = new Rectangle(25, 433, 141, 33); Rectangle fullClick = new Rectangle(25, 337, 141, 33); Rectangle volumemuteclick = new Rectangle(206, 483, 141, 33); Rectangle volume1click = new Rectangle(360, 483, 141, 33); Rectangle volume2click = new Rectangle(514, 483, 141, 33); Rectangle volume3click = new Rectangle(669, 483, 141, 33); Rectangle volumemaxclick = new Rectangle(825, 483, 141, 33); Rectangle sfxmuteclick = new Rectangle(206, 533, 141, 33); Rectangle sfx1click = new Rectangle(360, 533, 141, 33); Rectangle sfx2click = new Rectangle(514, 533, 141, 33); Rectangle sfx3click = new Rectangle(669, 533, 141, 33); Rectangle sfxmaxclick = new Rectangle(825, 533, 141, 33); int count = 2; bool mouseback = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(backClick); bool mousefull = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(fullClick); //volume logic if (mouseState.LeftButton == ButtonState.Pressed) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (volumemuteclick.Contains(mousePos)) { volmute_unselected = volmute; vollevel1_unselected = vol1temp; vollevel2_unselected = vol2temp; vollevel3_unselected= vol3temp; vollevelMax_unselected= volmaxtemp; MediaPlayer.Volume = 0; } if (volume1click.Contains(mousePos)) { volmute_unselected = volmutetemp; vollevel1_unselected = vollevel1; vollevel2_unselected = vol2temp; vollevel3_unselected = vol3temp; vollevelMax_unselected= volmaxtemp; MediaPlayer.Volume = .25f; } if (volume2click.Contains(mousePos)) { volmute_unselected = volmutetemp; vollevel1_unselected = vol1temp; vollevel2_unselected = vollevel2; vollevel3_unselected = vol3temp; vollevelMax_unselected = volmaxtemp; MediaPlayer.Volume = .5f; } if (volume3click.Contains(mousePos)) { volmute_unselected = volmutetemp; vollevel1_unselected = vol1temp; vollevel2_unselected = vol2temp; vollevel3_unselected = vollevel3; vollevelMax_unselected = volmaxtemp; MediaPlayer.Volume = .75f; } if (volumemaxclick.Contains(mousePos)) { volmute_unselected = volmutetemp; vollevel1_unselected = vol1temp; vollevel2_unselected = vol2temp; vollevel3_unselected = vol3temp; vollevelMax_unselected = vollevelMax; MediaPlayer.Volume = 1f; } } //soundBank effects logic if (mouseState.LeftButton == ButtonState.Pressed&&!releaseWait) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (sfxmuteclick.Contains(mousePos)) { mute_unselected = mute; level1_unselected = level1temp; level2_unselected = level2temp; level3_unselected = level3temp; levelMax_unselected = maxtemp; sfx.setfxfvolume(0f); releaseWait = true; } if (sfx1click.Contains(mousePos)) { mute_unselected = mutetemp; level1_unselected = level1; level2_unselected = level2temp; level3_unselected = level3temp; levelMax_unselected = maxtemp; sfx.setfxfvolume(0.25f*6f); sfx.PlayBuzzer(); releaseWait = true; } if (sfx2click.Contains(mousePos)) { mute_unselected = mutetemp; level1_unselected = level1temp; level2_unselected = level2; level3_unselected = level3temp; levelMax_unselected = maxtemp; sfx.setfxfvolume(.5f * 6f); sfx.PlayBuzzer(); releaseWait = true; } if (sfx3click.Contains(mousePos)) { mute_unselected = mutetemp; level1_unselected = level1temp; level2_unselected = level2temp; level3_unselected = level3; levelMax_unselected = maxtemp; sfx.setfxfvolume(.75f * 6f); sfx.PlayBuzzer(); releaseWait = true; } if (sfxmaxclick.Contains(mousePos)) { mute_unselected = mutetemp; level1_unselected = level1temp; level2_unselected = level2temp; level3_unselected = level3temp; levelMax_unselected = levelMax; sfx.setfxfvolume(1f); sfx.PlayBuzzer(); releaseWait = true; } } //full screen logic if (mouseState.LeftButton == ButtonState.Pressed) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (fullClick.Contains(mousePos)) { if (isFullScreen) { graphics.ToggleFullScreen(); yes_invert = yestemp; no_invert = no; isFullScreen = false; } else if (!isFullScreen) { yes_invert = yes; no_invert =notemp; graphics.ToggleFullScreen(); isFullScreen = true; } } } //back inverter if (mouseback && back == backtemp) { backtemp = back; back = back_invert; } else if (!mouseback && back != backtemp) { back = backtemp; } //exits options menu if (mouseState.LeftButton == ButtonState.Pressed) { Point mousePos = new Point(mouseState.X, mouseState.Y); if (backClick.Contains(mousePos)) { mainMenu = true; optionsMenu = false; LoadContent(); } } } else if (demo && !(p1win || p2win)) { engine.Update(); sfx.Update(); if (!battle.AttackMode) { battle.BattleMap.ClearHighlights(); } battle.BattleMap.ClearHighlights(); //boxes for intersecion of buttons Rectangle moveclick = new Rectangle(680, 700, 116, 27); Rectangle passclick = new Rectangle(796, 700, 116, 27); Rectangle attackclick = new Rectangle(680, 727, 116, 27); Rectangle defendclick = new Rectangle(796, 727, 116, 27); Rectangle specialclick = new Rectangle(680, 754, 116, 27); Rectangle itemclick = new Rectangle(796, 754, 116, 27); mouseState = Mouse.GetState(); bool moveenabled = true; bool hilightenabled = true; //mouse state when on buttons bool mousemove = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(moveclick); bool mousepass = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(passclick); bool mouseattack = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(attackclick); bool mousedefend = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(defendclick); bool mousespecial = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(specialclick); bool mouseitems = new Rectangle(mouseState.X, mouseState.Y, 1, 1).Intersects(itemclick); Point mousePos = new Point(mouseState.X, mouseState.Y); //lock buttons during wait times if (tickWait) { LockButtons(); } //Move mode highlighting if (battle.MoveMode) { //THE ALL IMPORTANT MAP POSITION ESITMATION FUNCTION int X = (int)Math.Round(((double)mousePos.X - (double)offsetX - 20) / (double)55); int Y = (int)Math.Round(((double)mousePos.Y - (double)offsetY - 20) / (double)55); if (X >= 0 && X < battle.BattleMap.Size[0] && Y >= 0 && Y < battle.BattleMap.Size[1]) { battle.BattleMap.AddSpecificHighlight(X, Y); lastSelectedTile = battle.BattleMap.GetTileAt(X, Y); } else { battle.BattleMap.AddSpecificHighlight(lastSelectedTile.X, lastSelectedTile.Y); } } //AttackMode Highlighting else if(battle.AttackMode) { int X = (int)Math.Round(((double)mousePos.X - (double)offsetX - 20) / (double)55); int Y = (int)Math.Round(((double)mousePos.Y - (double)offsetY - 20) / (double)55); if (X >= 0 && X < battle.BattleMap.Size[0] && Y >= 0 && Y < battle.BattleMap.Size[1]) { battle.BattleMap.AddSpecificHighlight(X, Y); lastSelectedTile = battle.BattleMap.GetTileAt(X, Y); } } //Button clicks if (mouseState.LeftButton == ButtonState.Pressed && !releaseWait && !AILock) { //select move if (moveclick.Contains(mousePos) && move != move_invert && !moveWait && !tickWait && battle.SelectEnabled) { battle.BattleMap.ClearRedHighlights(); releaseWait = true; move = move_invert; attack = attack_grey; defend = defend_grey; item = item_grey; pass = pass_grey; special = special_grey; hilightenabled = false; battle.AttackMode = false; battle.SelectMove(); battle.BattleMap.ClearRedHighlights(); frameCount = 0; battle.SelectMove(); } //deselect move else if (moveclick.Contains(mousePos) && move == move_invert) { battle.BattleMap.ClearRedHighlights(); releaseWait = true; move = movetrue; attack = attacktrue; defend = defendtrue; item = itemtrue; pass = passtrue; special = specialtrue; hilightenabled = true; battle.DeselectMove(); } //select attack else if (attackclick.Contains(mousePos) && attack != attack_invert && !tickWait && !moveWait && battle.SelectEnabled) { releaseWait = true; move = move_grey; attack = attack_invert; defend = defend_grey; item = item_grey; pass = pass_grey; special = special_grey; hilightenabled = true; //deselect other modes before selecting attack battle.DeselectMove(); battle.SelectAttack(); //battle will get rid of attack mode if there are no valid targets if (!battle.AttackMode) { battle.SelectEnabled = true; move = movetrue; attack = attacktrue; defend = defendtrue; item = itemtrue; pass = passtrue; special = specialtrue; hilightenabled = true; sfx.PlayBuzzer(); } } //deselect attack else if (attackclick.Contains(mousePos) && attack == attack_invert) { releaseWait = true; move = movetrue; attack = attacktrue; defend = defendtrue; item = itemtrue; pass = passtrue; special = specialtrue; hilightenabled = true; battle.DeselectAttack(); } //select pass else if (passclick.Contains(mousePos) && !tickWait && !moveWait && battle.SelectEnabled) { sfx.PlayPassSound(battle.ActiveUnit); pass = pass_invert; timeSinceLastDamageFrame = 0; battle.ActiveUnit.AP = 0; releaseWait = true; move = movetrue; attack = attacktrue; defend = defendtrue; item = itemtrue; pass = passtrue; special = specialtrue; hilightenabled = true; } //select defend else if (defendclick.Contains(mousePos) && !wait && !tickWait && !moveWait && battle.SelectEnabled) { timeSinceLastDamageFrame = 0; wait = true; battle.MoveMode = false; battle.AttackMode = false; releaseWait = true; move = move_grey; attack = attack_grey; defend = defend_invert; item = item_grey; pass = pass_grey; special = special_grey; hilightenabled = true; battle.SelectDefend(); } //deselect if in move or attack mode and defend button clicked else if (defendclick.Contains(mousePos) && !wait && !tickWait && !moveWait && !battle.SelectEnabled) { battle.MoveMode = false; battle.AttackMode = false; battle.SelectEnabled = true; releaseWait = true; ResetButtons(); } //confirm move if (mouseState.LeftButton == ButtonState.Pressed && battle.MoveMode && !releaseWait && battle.BattleMap.GetTileAt(lastSelectedTile.X, lastSelectedTile.Y).IsRedHighlighted) { moveWait = true; move = movetrue; attack = attacktrue; defend = defendtrue; item = itemtrue; pass = passtrue; special = specialtrue; hilightenabled = true; releaseWait = true; battle.DeselectMove(); battle.StartMove(lastSelectedTile); battle.BattleMap.ClearRedHighlights(); if (battle.ActiveUnit.AP <= 1) { LockButtons(); } } else if (mouseState.LeftButton == ButtonState.Pressed && battle.MoveMode && !releaseWait && !battle.BattleMap.GetTileAt(lastSelectedTile.X, lastSelectedTile.Y).IsRedHighlighted) { releaseWait = true; sfx.PlayBuzzer(); } //Confirm attack if (mouseState.LeftButton == ButtonState.Pressed && battle.AttackMode && !releaseWait) { int X = (int)Math.Round(((double)mousePos.X - (double)offsetX - 20) / (double)55); int Y = (int)Math.Round(((double)mousePos.Y - (double)offsetY - 20) / (double)55); if (X >= 0 && X < battle.BattleMap.Size[0] && Y >= 0 && Y < battle.BattleMap.Size[1] && battle.BattleMap.GetTileAt(X, Y).IsHighlighted && battle.BattleMap.GetTileAt(X, Y).hasUnit && (battle.BattleMap.GetTileAt(X, Y).TileUnit.isPlayerUnit != battle.ActiveUnit.isPlayerUnit)) { battle.BattleMap.ClearRedHighlights(); wait = true; move = movetrue; attack = attacktrue; defend = defendtrue; item = itemtrue; pass = passtrue; special = specialtrue; hilightenabled = true; releaseWait = true; unitDamage = battle.Attack(battle.BattleMap.GetTileAt(X, Y).TileUnit); attackedUnitTrueX = X * 55 - 13; attackedUnitTrueY = Y * 55 - 20; unitAttacked = true; displayDamage = true; timeSinceLastDamageFrame = 0; } else if (!releaseWait) { releaseWait = true; sfx.PlayBuzzer(); } } } if (mouseState.LeftButton == ButtonState.Released) releaseWait = false; //move the view with WASD if (Keyboard.GetState().IsKeyDown(Keys.W) && offsetY < 500) { offsetY += 10; } if (Keyboard.GetState().IsKeyDown(Keys.S) && offsetY > -1000) { offsetY -= 10; } if (Keyboard.GetState().IsKeyDown(Keys.A) && offsetX < 750) { offsetX += 10; } if (Keyboard.GetState().IsKeyDown(Keys.D) && offsetX > -750) { offsetX -= 10; } //update the display with the active unit unit = battle.ActiveUnit.GetType(); hp = battle.ActiveUnit.HP.ToString(); range = battle.ActiveUnit.Range.ToString() ; defense = battle.ActiveUnit.Defense.ToString(); speed = battle.ActiveUnit.Speed.ToString() ; mp = battle.ActiveUnit.MP.ToString(); attackText = battle.ActiveUnit.Attack.ToString(); moveText = battle.ActiveUnit.AP.ToString(); nextUnits = new List<string>(); for (int i = battle.QueuePosition + 1; i < battle.QueuePosition + 6; i++) { if (i < battle.BattleQueue.Count) { string belongsTo; if (battle.BattleQueue.ElementAt(i).isPlayerUnit) { belongsTo = "Player 1"; } else { belongsTo = "Player 2"; } string unitText = belongsTo + ": " + battle.BattleQueue.ElementAt(i).GetType() + " " + battle.BattleQueue.ElementAt(i).HP.ToString() + " HP"; nextUnits.Add(unitText); } } timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds; //stuff that happens on the animation tick, about 60fps if (timeSinceLastFrame > millisecondsPerFrame) { timeSinceLastFrame = 0; } timeSinceLastDamageFrame += gameTime.ElapsedGameTime.Milliseconds; //stuff that happens on the damage tick, including end-of-turn checking //this tick is quite slow if (timeSinceLastDamageFrame > millisecondsPerDamageFrame) { timeSinceLastDamageFrame = 0; // Increment to next frame wait = false; displayDamage = false; if (battle.ActiveUnit.AP <= 0) { battle.NextPlayer(); } if (battle.gameOver) { endWait = false; } if (AILock && !moveWait) { battle.AIMove(); } } //stuff that happens on the move tick, a faster interval timeSinceLastMoveFrame += gameTime.ElapsedGameTime.Milliseconds; if (timeSinceLastMoveFrame > millisecondsPerMoveFrame) { timeSinceLastMoveFrame = 0; //if a move is ongoing, advance unit to the next tile if (moveWait) { battle.ContinueMove(); timeSinceLastDamageFrame = 0; } } //if the turn is over, lock everything for a beat if (battle.ActiveUnit.AP <= 0) { tickWait = true; } } timeSinceLastDamageFrame += gameTime.ElapsedGameTime.Milliseconds; if (timeSinceLastDamageFrame > millisecondsPerDamageFrame && battle != null) { timeSinceLastDamageFrame = 0; // Increment to next frame wait = false; displayDamage = false; if (battle.ActiveUnit.AP <= 0) { battle.NextPlayer(); } if (battle.gameOver) { endWait = false; } } if (MediaPlayer.State == MediaState.Stopped && (p1win || p2win)) { if (p1win) { cue.Stop(AudioStopOptions.Immediate); Song campaign = Content.Load<Song>(@"music\CampaignMode"); MediaPlayer.Play(campaign); } else if (p2win && !loseMusicStarted) { cue.Stop(AudioStopOptions.Immediate); cue = soundBank.GetCue("LoseBattle"); cue.Play(); loseMusicStarted = true; } } if (Keyboard.GetState().GetPressedKeys().Length > 0 && (p1win || p2win) && !endWait) { battle.gameOver = false; p1win = false; p2win = false; musicStarted = false; load.MainMenu(); demo = false; mainMenu = true; cue.Stop(AudioStopOptions.Immediate); } if (mouseState.LeftButton == ButtonState.Released) { releaseWait = false; } base.Update(gameTime); }
public Game1() { graphics = new GraphicsDeviceManager(this); this.graphics.PreferredBackBufferHeight = 800; this.graphics.PreferredBackBufferWidth = 1500; this.graphics.IsFullScreen = false; Content.RootDirectory = "Content"; this.IsMouseVisible = true; mainMenu = true; demo = false; offsetY = 0; offsetX = 0; startTurn = true; releaseWait = false; lastSelectedTile = new Tile(); unitAttacked = false; displayDamage = false; wait = false; p1win = false; p2win = false; musicStarted = false; MoveTiles = new List<Tile>(); moveWait = false; tickWait = false; endWait = false; timeSinceLastFrame = 0; millisecondsPerFrame = 100; draw = new Draw(this); load = new ContentLoader(this); }
//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 int GetGScore(Tile tile) { int GScore = 0; bool root = false; Tile test = tile; try { if (tile.parentTile == null) tile.IsRoot = true; } catch { tile.IsRoot = true; } while (!root) { GScore += test.MoveCost; if (test.IsRoot) { root = true; } else { test = test.parentTile; } } return GScore; }
//runs path algorithm and checks if there is //path between two points public static bool PathExists(Tile startTile, Tile endTile, Map map, List<Tile> rangeSet, int speed) { //HOLY SHIT, A WORKING A* ALGORITHM startTile.IsRoot = true; List<Tile> open = new List<Tile>(); List<Tile> closed = new List<Tile>(); open.Add(startTile); if (startTile == endTile) { return false; } Tile current = new Tile(); while (open.Count > 0) { int LowestFScore = 10000; for (int i = 0; i < open.Count; i++ ) { if (open.ElementAt(i).FScore < LowestFScore) { LowestFScore = open.ElementAt(i).FScore; current = open.ElementAt(i); } } open.Remove(current); closed.Add(current); List<Tile> adjacent = GetAdjacentLegalTiles(map, current); List<Tile> adjacentTemp = new List<Tile>(); foreach (Tile adj in adjacent) { //if(rangeSet.Contains(adj)) //{ adjacentTemp.Add(adj); //} if (closed.Contains(adj)) { adjacentTemp.Remove(adj); } } adjacent = adjacentTemp; foreach (Tile tile in adjacent) { if (!open.Contains(tile)) { open.Add(tile); } tile.parentTile = current; tile.GScore = GetGScore(tile); tile.HScore = GetManhattanDistance(current, endTile); tile.FScore = tile.GScore + tile.HScore; if (open.Contains(tile)) { Tile test = new Tile(); foreach (Tile o in open) { if (o == tile) { test = o; } } if (tile.GScore < test.GScore) { test.parentTile = current; test.GScore = GetGScore(test); test.FScore = test.GScore + test.HScore; } } } if(closed.Contains(endTile)) { List<Tile> path = BuildPath(endTile); if (Reachable(path, speed)) { return true; } else { return false; } } } return false; }
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; } }
//same as above, only returns the path public static List<Tile> GetPath(Tile startTile, Tile endTile, Map map) { //HOLY SHIT, ANOTHER WORKING A* ALGORITHM startTile.IsRoot = true; List<Tile> open = new List<Tile>(); List<Tile> closed = new List<Tile>(); open.Add(startTile); Tile current = new Tile(); while (open.Count > 0) { int LowestFScore = 10000; for (int i = 0; i < open.Count; i++ ) { if (open.ElementAt(i).FScore < LowestFScore) { LowestFScore = open.ElementAt(i).FScore; current = open.ElementAt(i); } } open.Remove(current); closed.Add(current); List<Tile> adjacent = GetAdjacentLegalTiles(map, current); List<Tile> adjacentTemp = new List<Tile>(); foreach (Tile adj in adjacent) { adjacentTemp.Add(adj); if (closed.Contains(adj)) { adjacentTemp.Remove(adj); } } adjacent = adjacentTemp; foreach (Tile tile in adjacent) { if (!open.Contains(tile)) { open.Add(tile); } tile.parentTile = current; tile.GScore = GetGScore(tile); tile.HScore = GetManhattanDistance(current, endTile); tile.FScore = tile.GScore + tile.HScore; if (open.Contains(tile)) { Tile test = new Tile(); foreach (Tile o in open) { if (o == tile) { test = o; } } if (tile.GScore < test.GScore) { test.parentTile = current; test.GScore = GetGScore(test); test.FScore = test.GScore + test.HScore; } } } if(closed.Contains(endTile)) { List<Tile> path = BuildPath(endTile); return path; } } return new List<Tile>(); }
/// <summary> /// Heuristic function for pathfinding. Returns the straight line distance between two tiles. /// </summary> /// <param name="testTile"></param> /// <param name="destination"></param> /// <returns></returns> public static int GetManhattanDistance(Tile testTile, Tile destination) { int mDistance = 0; if (testTile.X > destination.X) { mDistance += (testTile.X - destination.X); } if(testTile.X < destination.X) { mDistance += (destination.X - testTile.X); } if (testTile.Y > destination.Y) { mDistance += (testTile.Y - destination.Y); } if (testTile.Y < destination.Y) { mDistance += (destination.Y - testTile.Y); } return mDistance; }
//generate a list of moves between the unit and desired tile, for animation purposes public void StartMove(Tile move) { List<Tile> movePath = AI.GetPath(BattleMap.GetTileAt(ActiveUnit.Location[0], ActiveUnit.Location[1]), move, BattleMap); GameUI.moveWait = true; pendingMoves = movePath.ToArray(); pendingIndex = pendingMoves.Length - 1; GameUI.sfx.PlayMoveSound(ActiveUnit); }
//advance to the next tile in the move list //if at the end, the move is finished public void ContinueMove() { BattleMap.Move(ActiveUnit, pendingMoves[pendingIndex].X, pendingMoves[pendingIndex].Y); pendingIndex--; if (pendingIndex == -1) { GameUI.moveWait = false; ActiveUnit.AP--; BattleMap.ClearHighlights(); MoveMode = false; pendingIndex = 0; pendingMoves = new Tile[0]; } }