/// <summary> /// Have the damage taken be reflected in the Character or Monster List /// </summary> /// <param name="Target"></param> /// <param name="damage"></param> /// <returns></returns> public bool TakeDamage(BattleEntityModel Target, int damage) { if (Target == null) { return(false); } Target.TakeDamage(damage); switch (Target.EntityType) { case (EntityTypeEnum.Character): var character = CharacterList.First(a => a.Id == Target.Id); character.TakeDamage(damage); // Hackathon scenario 9 - Miracle Max if (!character.Alive && character.MiracleMax) { EntityList.First(a => a.Id == Target.Id).CurrentHealth = character.MaxHealth; // it's a miracle! character.CurrentHealth = character.MaxHealth; character.MiracleMax = false; EntityList.First(a => a.Id == Target.Id).Alive = true; EntityList.First(a => a.Id == Target.Id).CurrentHealth = character.MaxHealth; character.Alive = true; BattleMessages.TurnMessageSpecial = character.Name + " has been miraculously revived by Miracle Max!\nSee Miracle Max for all of your miraculous needs~"; Debug.WriteLine(BattleMessages.TurnMessageSpecial); } return(true); case (EntityTypeEnum.Monster): default: MonsterList.First(a => a.Id == Target.Id).TakeDamage(damage); return(true); } }
// Turn consists of a Move or Attack // // Move: // Move to an empty space on the Map // Turn Over // // Attack: // Allowed only if in range of target // Roll To Hit // Decide Hit or Miss // Decide Damage // Death // Drop Items // Turn Over #endregion Algorithm /// <summary> /// The current attacker takes their turn. /// </summary> /// <param name="attacker"></param> /// <returns></returns> public bool TakeTurn(BattleEntityModel Attacker) { CurrentAttacker = Attacker; Score.TurnCount++; // Assume Move if nothing else happens CurrentAction = ActionEnum.Move; // See if Desired Target is within Range, and if so attack away if (MapModel.IsTargetInRange(Attacker, AttackChoice(Attacker))) { CurrentAction = ActionEnum.Attack; } // Perform the action switch (CurrentAction) { case ActionEnum.Attack: return(Attack(Attacker)); case ActionEnum.Move: case ActionEnum.Unknown: default: return(MoveAsTurn(Attacker)); } }
/// <summary> /// Put the Player into a Display Box /// </summary> /// <param name="data"></param> /// <returns></returns> public StackLayout PlayerInfoDisplayBox(BattleEntityModel data) { if (data == null) { data = new BattleEntityModel { ImageURI = "" }; } // Hookup the image var PlayerImage = new Image { Style = (Style)Application.Current.Resources["PlayerBattleMediumStyle"], Source = data.ImageURI }; // Put the Image Button and Text inside a layout var PlayerStack = new StackLayout { Style = (Style)Application.Current.Resources["PlayerBattleDisplayBox"], Children = { PlayerImage, }, }; return(PlayerStack); }
public void TurnEngine_RemoveIfDead_Dead_true_Should_Return_true() { // Arrange var Monster = new MonsterModel { CurrentHealth = 0, Alive = false, Id = "me" }; var BattleMonster = new BattleEntityModel(Monster); Engine.MonsterList.Clear(); Engine.MonsterList.Add(Monster); // Engine.MakeEntityList(); Engine.EntityList.Add(BattleMonster); // Act var result = Engine.RemoveIfDead(BattleMonster); // Reset Engine.StartBattle(false); // Assert Assert.AreEqual(true, result); }
public void BattleEntityTests_Format_Output_Valid() { // Arrange var BattleEntity = new BattleEntityModel(); // Assert Assert.AreEqual(BattleEntity.Name, BattleEntity.FormatOutput()); }
/// <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(BattleEntityModel Attacker) { /* * Move Logic * Find the desired target based on MoveChoice: * Character goes for lowest current health, then highest level * Monster goes for highest current health, then highest level * Find an empty square near the target that is reachable based on Attacker's range * Jump/teleport to the empty square * * If no open spaces, return false * */ // For Attack, Choose Who CurrentDefender = MoveChoice(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 - preference to first found spot that is in Range distance var openSquare = MapModel.ReturnClosestEmptyLocation(locationDefender, Attacker.Range); // No empty square found if (openSquare == null) { Debug.WriteLine(string.Format("{0} waits", locationAttacker.Player.Name)); BattleMessages.TurnMessage = Attacker.Name + " waits"; return(false); } Debug.WriteLine(string.Format("{0} moves from {1},{2} to {3},{4}", locationAttacker.Player.Name, locationAttacker.Column, locationAttacker.Row, openSquare.Column, openSquare.Row)); BattleMessages.TurnMessage = Attacker.Name + " moves closer to " + CurrentDefender.Name; return(MapModel.MovePlayerOnMap(locationAttacker, openSquare)); }
/// <summary> /// If Dead process Target Died /// </summary> /// <param name="Target"></param> public bool RemoveIfDead(BattleEntityModel Target) { // Check for alive if (Target.Alive == false) { return(TargetDied(Target)); } return(false); }
/// <summary> /// Decide which to attack /// </summary> /// <param name="data"></param> /// <returns></returns> public BattleEntityModel AttackChoice(BattleEntityModel data) { switch (data.EntityType) { case EntityTypeEnum.Monster: return(SelectCharacterToAttack()); case EntityTypeEnum.Character: default: return(SelectMonsterToAttack()); } }
/// <summary> /// Have the character or monster drop all their items and returns the list of item models /// </summary> /// <param name="target"></param> /// <returns></returns> public List <ItemModel> RemoveItems(BattleEntityModel target) { switch (target.EntityType) { case (EntityTypeEnum.Character): return(CharacterList.Where(a => a.Id == target.Id).FirstOrDefault().DropAllItems()); case (EntityTypeEnum.Monster): default: return(MonsterList.Where(a => a.Id == target.Id).FirstOrDefault().DropItems()); } }
/// <summary> /// Decide who to move toward /// </summary> /// <param name="data"></param> /// <returns></returns> public BattleEntityModel MoveChoice(BattleEntityModel data) { switch (data.EntityType) { case EntityTypeEnum.Monster: return(SelectCharacterToMoveToward()); case EntityTypeEnum.Character: default: return(SelectMonsterToMoveToward()); } }
/// <summary> /// Gets the roll of the damage value (including any stat boosts) of the character or monster /// </summary> /// <param name="attacker"></param> /// <returns></returns> public int GetDamage(BattleEntityModel attacker) { switch (attacker.EntityType) { case (EntityTypeEnum.Character): return(CharacterList.Where(a => a.Id == attacker.Id).FirstOrDefault().RollDamageDice()); case (EntityTypeEnum.Monster): default: return(MonsterList.Where(a => a.Id == attacker.Id).FirstOrDefault().RollDamageDice()); } }
/// <summary> /// Gets the defense value (including any stat boosts) of the character of monster /// </summary> /// <param name="target"></param> /// <returns></returns> public int GetDefense(BattleEntityModel target) { switch (target.EntityType) { case (EntityTypeEnum.Character): var character = CharacterList.Where(a => a.Id == target.Id).FirstOrDefault(); return(character.Defense + character.Level + character.GetItemBonus(AttributeEnum.Defense)); case (EntityTypeEnum.Monster): default: return(target.Defense + target.Level); } }
public void BattleEntityModelTests_Constructor_New_Monster_Should_Copy() { // Arrange var Monster = new MonsterModel(); Monster.ExperienceGiven = 500; // Act var BattleEntity = new BattleEntityModel(Monster); // Assert Assert.AreEqual(Monster.ExperienceGiven, BattleEntity.ExperiencePoints); }
public void BattleEntityModel_Constructor_Default_Should_Pass() { // Arrange // Act var result = new BattleEntityModel(); // reset // Assert Assert.AreEqual(result.EntityType, EntityTypeEnum.Unknown); Assert.AreEqual(result.ExperiencePoints, 0); Assert.AreEqual(result.ListOrder, 0); }
public void BattleEntityModelTests_Change_Level_Should_Pass() { // Arrange var BattleEntity = new BattleEntityModel(); // Act - do this until method implemented try { BattleEntity.ChangeLevel(1); } catch (NotImplementedException) { } }
/// <summary> /// Handle the Critical Miss event (if enabled) /// </summary> /// <param name="attacker"></param> /// <returns></returns> public bool CriticalMiss(BattleEntityModel attacker) { switch (attacker.EntityType) { case EntityTypeEnum.Monster: return(MonsterCriticalMiss(MonsterList.First(a => a.Id == attacker.Id))); case EntityTypeEnum.Character: return(CharacterCriticalMiss(CharacterList.First(a => a.Id == attacker.Id))); default: return(false); } }
public void BattleEntityModelTests_Constructor_New_Character_Should_Copy() { // Arrange var Character = new CharacterModel(); Character.TotalExperience = 500; var battleEntity = new BattleEntityModel(Character); // Act // reset // Assert Assert.AreEqual(Character.TotalExperience, battleEntity.ExperiencePoints); }
/// <summary> /// Attack as a turn. /// /// Pick who to go after /// /// Determine Attack Score /// Determine DefenseScore /// /// Do the Attack /// </summary> /// <param name="Attacker"></param> /// <returns></returns> public bool Attack(BattleEntityModel Attacker) { // If no defender, should return null regardless of autobattle or regular battle // For Attack, Choose Who CurrentDefender = AttackChoice(Attacker); if (CurrentDefender == null) { return(false); } // Do Attack TurnAsAttack(Attacker, CurrentDefender); return(true); }
/// <summary> /// Process an entity's death. /// </summary> /// <param name="target"></param> /// <returns></returns> public bool TargetDied(BattleEntityModel target) { // Mark Status in output BattleMessages.TurnMessageSpecial = target.Name + " has perished."; // Remove target from Map MapModel.RemovePlayerFromMap(target); // Using a switch so in the future additional PlayerTypes can be added (Boss...) switch (target.EntityType) { case EntityTypeEnum.Character: DropItems(target); var character = CharacterList.Where(a => a.Id == target.Id).FirstOrDefault(); CharacterList.Remove(character); EntityList.Remove(EntityList.Find(m => m.Id.Equals(target.Id))); // Add the MonsterModel to the killed list Score.CharacterAtDeathList += character.FormatOutput() + "\n"; Debug.WriteLine(BattleMessages.TurnMessageSpecial); return(true); case EntityTypeEnum.Monster: default: DropItems(target); var monster = MonsterList.Where(a => a.Id == target.Id).FirstOrDefault(); MonsterList.Remove(monster); EntityList.Remove(EntityList.Find(m => m.Id.Equals(target.Id))); // Add one to the monsters killed count... Score.MonsterSlainNumber++; // Add the MonsterModel to the killed list Score.MonstersKilledList += monster.FormatOutput() + "\n"; Debug.WriteLine(BattleMessages.TurnMessageSpecial); return(true); } }
public void BattleEntityModelTests_Constructor_New_BattleEntity_Should_Copy() { // Arrange var battleEntity = new BattleEntityModel(); battleEntity.EntityType = EntityTypeEnum.Character; battleEntity.ExperiencePoints = 500; //battleEntity.ListOrder = 1; // Act var newBattleEntity = new BattleEntityModel(battleEntity); // reset // Assert Assert.AreEqual(battleEntity.EntityType, newBattleEntity.EntityType); Assert.AreEqual(battleEntity.ExperiencePoints, newBattleEntity.ExperiencePoints); //Assert.AreEqual(battleEntity.ListOrder, newBattleEntity.ListOrder); }
/// <summary> /// Process Experience Points gained from killing a monster. /// Add to battle score and to the attacking character's experience. /// </summary> /// <param name="character"></param> /// <returns></returns> public bool AddExperience(BattleEntityModel entity, int experience) { if (entity == null) { return(false); } if (entity.EntityType == EntityTypeEnum.Monster) { return(false); } // character should gain experience var character = CharacterList.Where(a => a.Id == entity.Id).FirstOrDefault(); int level = character.Level; character.AddExperience(experience); EntityList.Where(a => a.Id == character.Id).FirstOrDefault().Update(character); // update battle messages BattleMessages.ExperienceEarned = "Won " + experience + " beats!"; Debug.WriteLine(BattleMessages.ExperienceEarned); // did character level up? if (level != character.Level) { BattleMessages.LevelUpMessage = entity.Name + " is now Level " + entity.Level + " with max health of " + entity.MaxHealth; Debug.WriteLine(BattleMessages.LevelUpMessage); } // update score - both Experience and Total Score Score.ScoreTotal += experience; Score.ExperienceGainedTotal += experience; return(true); }
/// <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> /// Have the target drop all their items /// </summary> /// <param name="target"></param> /// <returns></returns> public int DropItems(BattleEntityModel target) { // Reset item drop message BattleMessages.ItemDropMessage = string.Empty; // Drop Items to ItemModel Pool var myItemList = RemoveItems(target); // Add monster drop items if (target.EntityType == EntityTypeEnum.Monster) { myItemList.AddRange(GetRandomMonsterItemDrops(myItemList)); if (CloudItemDropEnabled) { var cloudItem = Task.Run(async() => await GetExternalItem(target.Level)).Result; if (cloudItem != null) { myItemList.Add(cloudItem); } } //// Hackathon Scenario 10 //if (myItemList.Count == 1) //{ // var diceroll = DiceHelper.RollDice(1, 10); // if (diceroll == 1) // { // var damageroll = DiceHelper.RollDice(1, 4); // var damage = Score.RoundCount * damageroll; // BattleMessages.ItemDropMessage += "GRENADE dropped!"; // Debug.WriteLine(BattleMessages.TurnMessageSpecial); // foreach (var monster in MonsterList) // { // // monsters take damage // TakeDamage(EntityList.First(a => a.Id == monster.Id), damage); // // remove monsters if dead // var dead = RemoveIfDead(EntityList.First(a => a.Id == monster.Id)); // // add dead monsters' items to myItemList // if (dead) // { // var monsterItemList = RemoveItems(EntityList.First(a => a.Id == monster.Id)); // myItemList.AddRange(GetRandomMonsterItemDrops(monsterItemList)); // } // } // } //} } var itemsForPool = new List <ItemModel>(); // Add to ScoreModel foreach (var ItemModel in myItemList) { if (ItemModel != null) { Score.ItemsDroppedList += ItemModel.FormatOutput() + "\n"; BattleMessages.ItemDropMessage += "\n" + ItemModel.Name + " dropped"; itemsForPool.Add(ItemModel); } } Debug.WriteLine(BattleMessages.ItemDropMessage); ItemPool.AddRange(itemsForPool); return(myItemList.Count()); }
/// <summary> /// Process the attack. Use BattleMessagesModel to communicate actions. /// </summary> /// <param name="attacker"></param> /// <param name="target"></param> /// <returns></returns> public bool TurnAsAttack(BattleEntityModel attacker, BattleEntityModel target) { if (attacker == null) { return(false); } if (target == null) { return(false); } // refresh battle messages for turn BattleMessages.ClearMessages(); // Hackathon // Hackathon Scenario 2, Bob alwasys misses if (attacker.Name.Equals("Bob")) { BattleMessages.HitStatus = HitStatusEnum.Miss; BattleMessages.TurnMessage = "Bob always Misses"; Debug.WriteLine(BattleMessages.TurnMessage); return(true); } BattleMessages.PlayerType = EntityTypeEnum.Monster; var AttackScore = GetAttack(attacker); var DefenseScore = GetDefense(target); // Choose who to attack BattleMessages.TargetName = target.Name; BattleMessages.AttackerName = attacker.Name; BattleMessages.HitStatus = RollToHitTarget(AttackScore, DefenseScore); Debug.WriteLine(BattleMessages.GetTurnMessage()); // It's a Miss if (BattleMessages.HitStatus == HitStatusEnum.Miss) { BattleMessages.TurnMessage = attacker.Name + " blunders and misses " + target.Name; // Check if Critical Miss is enabled (hackathon rule) if (CriticalMissEnabled) { if (BattleMessages.CriticalMiss) { CriticalMiss(attacker); BattleMessages.TurnMessage += BattleMessages.CriticalMissMessage; // toggle flag BattleMessages.CriticalMiss = false; } } Debug.WriteLine(BattleMessages.TurnMessage); return(true); } // It's a Hit if (BattleMessages.HitStatus == HitStatusEnum.Hit) { //Calculate Damage BattleMessages.DamageAmount = GetDamage(attacker); // Calculate Critical Hit if enabled if (CriticalHitsEnabled) { if (BattleMessages.CriticalHit) { BattleMessages.DamageAmount *= 2; } } if (target.EntityType == EntityTypeEnum.Monster) { double FractionalExperience = (double)BattleMessages.DamageAmount / (double)target.MaxHealth; int ExperienceGained = (int)Math.Ceiling(FractionalExperience * (double)target.ExperiencePoints); TakeDamage(target, BattleMessages.DamageAmount); // If monster takes damage he loses proportional amount of remaining experience points to attacker AddExperience(attacker, ExperienceGained); target.ExperiencePoints -= ExperienceGained; } else { TakeDamage(target, BattleMessages.DamageAmount); } } // update battle messages BattleMessages.CurrentHealth = target.CurrentHealth; BattleMessages.AttackStatus = " strikes "; BattleMessages.TurnMessage = attacker.Name + BattleMessages.AttackStatus + target.Name + BattleMessages.GetCurrentHealthMessage(); if (CriticalHitsEnabled) { if (BattleMessages.CriticalHit) { BattleMessages.TurnMessage += "\nCritical Hit!!!"; BattleMessages.CriticalHit = false; // toggle flag } } Debug.WriteLine(BattleMessages.TurnMessage); RemoveIfDead(target); return(true); }