/// <summary> /// If the user clicks a battle square when it's a Character's turn, call the battle engine to /// perform an action on that square /// </summary> /// <param name="data"></param> /// <returns></returns> public bool CharacterManualTurn(MapModelLocation data) { if (!IsCharacterTurn) { return(false); } // no one is taking a turn - do nothing if (EngineViewModel.Engine.CurrentEntity == null) { return(false); } // only take a turn if we're waiting on a character if (EngineViewModel.Engine.CurrentEntity.EntityType != EntityTypeEnum.Character) { return(false); } // toggle flag to prevent this character from performing multiple actions if user keeps clicking IsCharacterTurn = false; var result = EngineViewModel.Engine.CharacterManualTurn(EngineViewModel.Engine.CurrentEntity, data); DisplayTurnResult(); AttackButton.IsVisible = true; CharacterTurnMessage.IsVisible = false; return(result); }
/// <summary> /// Make the Game Map Frame /// Place the Character or Monster on the frame /// If empty, place Empty /// </summary> /// <param name="mapLocationModel"></param> /// <returns></returns> public Frame MakeMapGridBox(MapModelLocation mapLocationModel) { if (mapLocationModel.Player == null) { mapLocationModel.Player = BattleEngineViewModel.Instance.Engine.EngineSettings.MapModel.EmptySquare; } var PlayerImageButton = DetermineMapImageButton(mapLocationModel); var PlayerStack = new StackLayout { Padding = 0, Style = (Style)Application.Current.Resources["BattleMapImageBox"], HorizontalOptions = LayoutOptions.Center, VerticalOptions = LayoutOptions.Center, BackgroundColor = DetermineMapBackgroundColor(mapLocationModel), Children = { PlayerImageButton }, }; MapGridObjectAddImage(PlayerImageButton, mapLocationModel); MapGridObjectAddStack(PlayerStack, mapLocationModel); var MapFrame = new Frame { Style = (Style)Application.Current.Resources["BattleMapFrame"], Content = PlayerStack, AutomationId = GetDictionaryFrameName(mapLocationModel) }; return(MapFrame); }
/// <summary> /// Set the Image onto the map /// The Image represents the player /// /// So a character is the character Image for that character /// /// The Automation ID equals the guid for the player /// This makes it easier to identify when checking the map to update thigns /// /// The button action is set per the type, so Characters events are differnt than monster events /// </summary> /// <param name="MapModel"></param> /// <returns></returns> public ImageButton DetermineMapImageButton(MapModelLocation MapLocationModel) { ImageButton data; if (MapLocationModel.Player.EntityType == EntityTypeEnum.Character) { data = new ImageButton { Style = (Style)Application.Current.Resources["ImageBattleSmallSpriteStyle"], Source = MapLocationModel.Player.ImageURI, // Store the guid to identify this button AutomationId = MapLocationModel.Player.Guid }; } else { data = new ImageButton { Style = (Style)Application.Current.Resources["ImageBattleSmallIconStyle"], Source = MapLocationModel.Player.ImageURI, // Store the guid to identify this button AutomationId = MapLocationModel.Player.Guid }; } // add a click event to handle character manual turn data.Clicked += (sender, args) => CharacterManualTurn(MapLocationModel); return(data); }
/// <summary> /// Set the Image onto the map /// The Image represents the player /// /// So a charcter is the character Image for that character /// /// The Automation ID equals the guid for the player /// This makes it easier to identify when checking the map to update thigns /// /// The button action is set per the type, so Characters events are differnt than monster events /// </summary> /// <param name="MapLocationModel"></param> /// <returns></returns> public ImageButton DetermineMapImageButton(MapModelLocation MapLocationModel) { var data = new ImageButton { Style = (Style)Application.Current.Resources["BattleMapPlayerSmallStyle"], Source = MapLocationModel.Player.ImageURI, // Store the guid to identify this button AutomationId = MapLocationModel.Player.Guid }; switch (MapLocationModel.Player.PlayerType) { case PlayerTypeEnum.Character: data.Clicked += (sender, args) => SetSelectedCharacter(MapLocationModel); break; case PlayerTypeEnum.Monster: data.Clicked += (sender, args) => SetSelectedMonster(MapLocationModel); break; case PlayerTypeEnum.Unknown: default: data.Clicked += (sender, args) => SetSelectedEmpty(MapLocationModel); // Use the blank cell data.Source = BattleEngineViewModel.Instance.Engine.EngineSettings.MapModel.EmptySquare.ImageURI; break; } return(data); }
/// <summary> /// Event when a Monster is clicked on /// </summary> /// <param name="data"></param> /// <returns></returns> public bool SetSelectedMonster(MapModelLocation data) { // Click on a monster if within range if (data.Player.PlayerType == PlayerTypeEnum.Monster) { // the ImageButton serves to disable Monsters out of reach object MapObject = GetMapGridObject(GetDictionaryImageButtonName(data)); if (MapObject != null) { var imageObject = (ImageButton)MapObject; imageObject.IsEnabled = false; // check range if (Math.Abs(selectedCharacterLocation.Row - data.Row) + Math.Abs(selectedCharacterLocation.Column - data.Column) <= selectedCharacterRange) { // Choose the attack action and choose this monster as current defender selectedMonster = data.Player; BattleEngineViewModel.Instance.Engine.EngineSettings.CurrentAction = ActionEnum.Attack; BattleEngineViewModel.Instance.Engine.Round.SetCurrentDefender(selectedMonster); data.IsSelectedTarget = true; // setting the current action to move if a monster is selected monsterIsSelected = true; imageObject.IsEnabled = true; return(true); } } } return(false); }
/// <summary> /// Event when a Character is clicked on /// </summary> /// <param name="data"></param> /// <returns></returns> public bool SetSelectedCharacter(MapModelLocation data) { // Only for characters if (data.Player.PlayerType == PlayerTypeEnum.Character) { // flags that help with turns in the SetAttackerAndDefender method selectedCharacter = data.Player; selectedCharacterRange = data.Player.Range; selectedCharacterLocation = data; characterIsSelected = true; foreach (var cell in BattleEngineViewModel.Instance.Engine.EngineSettings.MapModel.MapGridLocation) { // disable out-of-reach cells object MapObject = GetMapGridObject(GetDictionaryImageButtonName(cell)); if (MapObject != null & cell.Player.PlayerType != PlayerTypeEnum.Character) { var imageObject = (ImageButton)MapObject; imageObject.IsEnabled = true; // check range if (Math.Abs(selectedCharacterLocation.Row - cell.Row) + Math.Abs(selectedCharacterLocation.Column - cell.Column) > selectedCharacterRange) { imageObject.IsEnabled = false; } } } return(true); } return(false); }
/// <summary> /// Event when a Character is clicked on /// </summary> /// <param name="data"></param> /// <returns></returns> public bool SetSelectedCharacter(MapModelLocation data) { // TODO: Info /* * This gets called when the characters is clicked on * Usefull if you want to select the character and then set state or do something * * For Mike's simple battle grammar there is no selection of action so I just return true */ return(true); }
/// <summary> /// Event when an empty location is clicked on /// </summary> /// <param name="data"></param> /// <returns></returns> public bool SetSelectedEmpty(MapModelLocation data) { // TODO: Info /* * This gets called when the characters is clicked on * Usefull if you want to select the location to move to etc. * * For Mike's simple battle grammar there is no selection of action so I just return true */ return(true); }
/// <summary> /// Event when a Monster is clicked on /// </summary> /// <param name="data"></param> /// <returns></returns> public bool SetSelectedMonster(MapModelLocation data) { // TODO: Info /* * This gets called when the Monster is clicked on * Usefull if you want to select the monster to attack etc. * * For Mike's simple battle grammar there is no selection of action so I just return true */ data.IsSelectedTarget = true; return(true); }
public void BattleSettingsPage_MakeMapGridBox_InValid_Should_Fail() { // Arrange var data = new MapModelLocation { Player = null, Column = 0, Row = 0 }; // Act var result = page.MakeMapGridBox(data); // Reset // Assert Assert.AreEqual(HitStatusEnum.Default, BattleEngineViewModel.Instance.Engine.EngineSettings.BattleSettingsModel.CharacterHitEnum); }
/// <summary> /// This adds the Stack into the Dictionary to keep track of /// </summary> /// <param name="data"></param> /// <param name="MapModel"></param> /// <returns></returns> public bool MapGridObjectAddStack(StackLayout data, MapModelLocation MapModel) { var name = GetDictionaryStackName(MapModel); // First check to see if it has data, if so update rather than add if (MapLocationObject.ContainsKey(name)) { // Update it MapLocationObject[name] = data; return(true); } MapLocationObject.Add(name, data); return(true); }
/// <summary> /// Set the Background color for the tile. /// Monsters and Characters have different colors /// Empty cells are transparent /// </summary> /// <param name="MapModel"></param> /// <returns></returns> public Color DetermineMapBackgroundColor(MapModelLocation MapModel) { if (EngineViewModel.Engine.CurrentAttacker == MapModel.Player) { return((Color)Application.Current.Resources["BattleMapCurrentAttacker"]); } if (EngineViewModel.Engine.CurrentEntity == MapModel.Player) { return((Color)Application.Current.Resources["BattleMapCurrentEntity"]); } if (EngineViewModel.Engine.CurrentDefender == MapModel.Player) { return((Color)Application.Current.Resources["BattleMapCurrentDefender"]); } return(Color.Transparent); }
/// <summary> /// Event when an empty location is clicked on /// </summary> /// <param name="data"></param> /// <returns></returns> public bool SetSelectedEmpty(MapModelLocation data) { // pick empty sells and move if within range if (BattleEngineViewModel.Instance.Engine.EngineSettings.CurrentAttacker.PlayerType == PlayerTypeEnum.Character & data.Player.PlayerType == PlayerTypeEnum.Unknown) { BattleEngineViewModel.Instance.Engine.EngineSettings.CurrentAction = ActionEnum.Move; // if within range, pick empty cell and move the character on map if (Math.Abs(selectedCharacterLocation.Row - data.Row) + Math.Abs(selectedCharacterLocation.Column - data.Column) <= selectedCharacterRange) { emptyIsSelected = true; BattleEngineViewModel.Instance.Engine.EngineSettings.MapModel.MovePlayerOnMap(selectedCharacterLocation, data); } UpdateMapGrid(); // If the player moves, then ability cannot be applied AbilityButton.IsEnabled = false; } return(true); }
/// <summary> /// Event when player is clicked. To swap position. /// </summary> /// <param name="sender"></param> /// <param name="e"></param> public void OnPlayerClicked(object sender, EventArgs e) { var imgButton = (ImageButton)sender; var player_clicked = (EntityInfoModel)imgButton.BindingContext; if (player_clicked.PlayerType != PlayerTypeEnum.Character) { return; // validate the player is a character } if (From == null) { From = EngineViewModel.Engine.MapModel.GetLocationForPlayer(player_clicked); Selected = imgButton; Selected.IsEnabled = false; } else { if (player_clicked != From.Player) { var to = EngineViewModel.Engine.MapModel.GetLocationForPlayer(player_clicked); var temp = From.Player; From.Player = to.Player; to.Player = temp; } From = null; Selected.IsEnabled = true; // redraw game board DrawBattleBoard(); } }
/// <summary> /// Set the Background color for the tile. /// Monsters and Characters have different colors /// Empty cells are transparent /// </summary> /// <param name="MapModel"></param> /// <returns></returns> public Color DetermineMapBackgroundColor(MapModelLocation MapModel) { string BattleMapBackgroundColor; switch (MapModel.Player.PlayerType) { case PlayerTypeEnum.Character: BattleMapBackgroundColor = "BattleMapCharacterColor"; break; case PlayerTypeEnum.Monster: BattleMapBackgroundColor = "BattleMapMonsterColor"; break; case PlayerTypeEnum.Unknown: default: BattleMapBackgroundColor = "BattleMapTransparentColor"; break; } var result = (Color)Application.Current.Resources[BattleMapBackgroundColor]; return(result); }
/// <summary> /// Character takes a turn by performing an action on the specified MapModelLocation. /// Possible actions are: /// Attack: if location has a monster in range /// Move: if location has a monster out of range, or location is empty /// Swap: if location has a character, the characters swap places /// Wait: if character's own square was clicked, do nothing /// </summary> /// <param name="Attacker"></param> /// <param name="location"></param> /// <returns></returns> public bool CharacterManualTurn(BattleEntityModel Attacker, MapModelLocation Location) { Score.TurnCount++; CurrentAttacker = Attacker; // only characters are allowed to do manual attacks if (Attacker.EntityType == EntityTypeEnum.Monster) { return(false); } // is there a monster at the location? if (Location.Player.EntityType == EntityTypeEnum.Monster) { CurrentDefender = Location.Player; // is it in range? attack... if (MapModel.IsTargetInRange(Attacker, Location.Player)) { return(TurnAsAttack(Attacker, Location.Player)); } // otherwise move to the closest found space var openSquare = MapModel.ReturnClosestEmptyLocation(Location); var current = MapModel.GetLocationForPlayer(Attacker); Debug.WriteLine(string.Format("{0} moves from {1},{2} to {3},{4}", Attacker.Name, current.Column, current.Row, openSquare.Column, openSquare.Row)); BattleMessages.TurnMessage = Attacker.Name + " moves closer to " + CurrentDefender.Name; return(MapModel.MovePlayerOnMap(current, openSquare)); } // is the location empty? if (Location.Player.EntityType == EntityTypeEnum.Unknown) { CurrentDefender = null; // move to empty space var current = MapModel.GetLocationForPlayer(Attacker); Debug.WriteLine(string.Format("{0} moves from {1},{2} to {3},{4}", Attacker.Name, current.Column, current.Row, Location.Column, Location.Row)); BattleMessages.TurnMessage = Attacker.Name + " moves to an empty space"; return(MapModel.MovePlayerOnMap(current, Location)); } // is there a character at the location? if (Location.Player.EntityType == EntityTypeEnum.Character) { CurrentDefender = null; // is this my own space? if (Location.Player.Id.Equals(Attacker.Id)) { Debug.WriteLine(string.Format("{0} hums a song and does nothing", Attacker.Name)); BattleMessages.TurnMessage = Attacker.Name + " hums a song and does nothing"; return(true); } // characters swap locations var current = MapModel.GetLocationForPlayer(Attacker); Debug.WriteLine(string.Format("{0} moves and swaps places with {1} ", Attacker.Name, Location.Player.Name)); BattleMessages.TurnMessage = Attacker.Name + " moves and swaps places with " + Location.Player.Name; return(MapModel.SwapPlayersOnMap(current, Location)); } // did not perform action return(false); }
/// <summary> /// Find a Desired Target /// Move close to them /// Get to move the number of Speed /// </summary> /// <param name="Attacker"></param> /// <returns></returns> public bool MoveAsTurn(EntityInfoModel Attacker, MapModelLocation targetLocation = null) { /* * TODO: TEAMS Work out your own move logic if you are implementing move * * Mike's Logic * The monster or charcter will move to a different square if one is open * Find the Desired Target * Jump to the closest space near the target that is open * * If no open spaces, return false * */ if (Attacker.PlayerType == PlayerTypeEnum.Monster) { // For Attack, Choose Who CurrentDefender = AttackChoice(Attacker); if (CurrentDefender == null) { return(false); } // Get X, Y for Defender var locationDefender = MapModel.GetLocationForPlayer(CurrentDefender); if (locationDefender == null) { return(false); } var locationAttacker = MapModel.GetLocationForPlayer(Attacker); if (locationAttacker == null) { return(false); } // Find Location Nearest to Defender that is Open. // Get the Open Locations var openSquare = MapModel.ReturnClosestEmptyLocation(locationDefender); Debug.WriteLine(string.Format("{0} moves from {1},{2} to {3},{4}", locationAttacker.Player.Name, locationAttacker.Column, locationAttacker.Row, openSquare.Column, openSquare.Row)); BattleMessageModel.TurnMessage = Attacker.Name + " moves closer to " + CurrentDefender.Name; return(MapModel.MovePlayerOnMap(locationAttacker, openSquare)); } else if (Attacker.PlayerType == PlayerTypeEnum.Character) { var locationAttacker = MapModel.GetLocationForPlayer(Attacker); if (locationAttacker == null) { return(false); } var openSquare = TargetLocation; Debug.WriteLine(string.Format("{0} moves from {1},{2} to {3},{4}", locationAttacker.Player.Name, locationAttacker.Column, locationAttacker.Row, openSquare.Column, openSquare.Row)); BattleMessageModel.TurnMessage = Attacker.Name + " moves to row: " + openSquare.Row + 1 + " column: " + openSquare.Column; return(MapModel.MovePlayerOnMap(locationAttacker, openSquare)); } return(true); }
/// <summary> /// Covert the player map location to a name for the dictionary to lookup /// </summary> /// <param name="data"></param> /// <returns></returns> public string GetDictionaryImageButtonName(MapModelLocation data) { // Look up the Frame in the Dictionary return(string.Format("MapR{0}C{1}ImageButton", data.Row, data.Column)); }
/// <summary> /// Convert the Stack to a name for the dictionary to lookup /// </summary> /// <param name="data"></param> /// <returns></returns> public string GetDictionaryStackName(MapModelLocation data) { return(string.Format("MapR{0}C{1}Stack", data.Row, data.Column)); }