public static bool RunAway(Unit runner, List <Monster> monster_list) { Random rng = new Random(); Console.WriteLine($"{runner.Name} is making a move!\n"); Console.WriteLine($"Your party tries to make a run for it..."); CMethods.SmartSleep(750); int chance; // Running has a 30% chance of success if the runner is paralyzed, regardless of if (runner.HasStatus(CEnums.Status.paralyzation)) { chance = 30; } // Running has a 70% chance of success if the runner: // 1. Has a higher speed than the fastest monster, but a lower evasion than the most evasive monster // 2. Has a higher evasion than the most evasive monster, but a lower speed than the fastest monster else if ((runner.Speed > monster_list.Select(x => x.Speed).Max()) != (runner.Evasion > monster_list.Select(x => x.Evasion).Max())) { chance = 70; } // Running has an 90% chance of success if the runner is both: // 1. Faster than the fastest monster // 2. More evasive than the most evasive monster else if ((runner.Speed > monster_list.Select(x => x.Speed).Max()) && (runner.Evasion > monster_list.Select(x => x.Evasion).Max())) { chance = 90; } // In all other scenarios, running has a 50% chance to succeed else { chance = 50; } if (rng.Next(0, 100) < chance) { SoundManager.buff_spell.SmartPlay(); Console.WriteLine("Your party managed to escape!"); CMethods.PressAnyKeyToContinue(); return(true); } else { SoundManager.debuff.SmartPlay(); Console.WriteLine("Your party's escape attempt failed!"); return(false); } }
public override void UseMagic(PlayableCharacter user, bool is_battle) { SpendMana(user); Unit target = user.CurrentTarget; int total_heal; if (HealthIncreaseFlat < target.MaxHP * HealthIncreasePercent) { total_heal = (int)((target.MaxHP * HealthIncreasePercent) + user.Attributes[CEnums.PlayerAttribute.wisdom]); } else { total_heal = HealthIncreaseFlat + user.Attributes[CEnums.PlayerAttribute.wisdom]; } target.HP += total_heal; target.FixAllStats(); if (is_battle) { Console.WriteLine($"{user.Name} is making a move!\n"); Console.WriteLine($"{user.Name} is preparing to cast {SpellName}..."); SoundManager.ability_cast.SmartPlay(); CMethods.SmartSleep(750); Console.WriteLine($"Using {SpellName}, {target.Name} is healed by {total_heal} HP!"); SoundManager.magic_healing.SmartPlay(); } else { CMethods.PrintDivider(); Console.WriteLine($"Using {SpellName}, {target.Name} is healed by {total_heal} HP!"); SoundManager.magic_healing.SmartPlay(); CMethods.PressAnyKeyToContinue(); CMethods.PrintDivider(); } }
public static void WouldYouLikeToSave() { while (true) { string yes_no = CMethods.SingleCharInput("Do you wish to save your progress? | [Y]es or [N]o: ").ToLower(); if (CMethods.IsYesString(yes_no)) { Console.WriteLine("Saving..."); CMethods.SmartSleep(100); SaveTheGame(); Console.WriteLine("Game has been saved!"); CMethods.PressAnyKeyToContinue(); return; } else if (CMethods.IsNoString(yes_no)) { return; } } }
public static void AfterBattle(List <PlayableCharacter> active_pcus, List <Monster> monster_list, bool is_bossfight) { CMethods.PrintDivider(); foreach (PlayableCharacter pcu in active_pcus) { pcu.FixAllStats(); } foreach (Monster monster in monster_list) { monster.FixAllStats(); } if (active_pcus.Any(x => x.IsAlive())) { SoundManager.victory_music.PlayLooping(); if (is_bossfight) { Console.WriteLine($"The mighty {monster_list[0].Name} has been slain!"); CInfo.DefeatedBosses.Add(monster_list[0].UnitID); monster_list[0].UponDefeating(); } else { Console.WriteLine($"The {monster_list[0].Name} falls to the ground dead as a stone."); } int gold_drops = 0; foreach (Monster monster in monster_list) { gold_drops += Math.Max(Math.Max(1, monster.DroppedGold), (int)(2 * monster.Level)); } int expr_drops = 0; foreach (Monster monster in monster_list) { expr_drops += Math.Max(Math.Max(1, monster.DroppedXP), (int)Math.Pow(1.5, monster.Level)); } Dictionary <string, string> item_drops = new Dictionary <string, string>(); foreach (Monster monster in monster_list) { if (monster.DroppedItem != null || monster.SetDroppedItem()) { item_drops.Add(monster.Name, monster.DroppedItem); } } CInfo.GP += gold_drops; CMethods.PressAnyKeyToContinue(prompt: $"Your party got {gold_drops} GP"); foreach (PlayableCharacter pcu in active_pcus) { pcu.CurrentXP += expr_drops; CMethods.PressAnyKeyToContinue(prompt: $"{pcu.Name} gained {expr_drops} XP"); } foreach (KeyValuePair <string, string> drop in item_drops) { CMethods.PressAnyKeyToContinue(prompt: $"The {drop.Key} dropped a {ItemManager.FindItemWithID(drop.Value).ItemName}"); InventoryManager.AddItemToInventory(drop.Value); } foreach (PlayableCharacter pcu in active_pcus) { pcu.PlayerLevelUp(); } SoundManager.PlayCellMusic(); } else { SoundManager.gameover_music.PlayLooping(); Console.WriteLine($"Despite your best efforts, the {monster_list[0].Name} has killed your party."); CMethods.PrintDivider(); bool auto_yes = false; while (true) { string y_n; if (auto_yes) { y_n = "y"; } else { y_n = CMethods.SingleCharInput("Do you wish to continue playing? | [Y]es or [N]o: "); } if (CMethods.IsYesString(y_n)) { CInfo.CurrentTile = CInfo.RespawnTile; UnitManager.HealAllPCUs(true, true, true); SoundManager.PlayCellMusic(); return; } else if (CMethods.IsNoString(y_n)) { while (true) { string y_n2 = CMethods.SingleCharInput("Are you sure you want to quit? | [Y]es or [N]o: "); if (CMethods.IsYesString(y_n2)) { auto_yes = true; break; } else if (CMethods.IsNoString(y_n2)) { Environment.Exit(0); } } } } } }
public static void BattleSystem(bool is_bossfight) { Random rng = new Random(); TileManager.GetCellList(); List <Monster> monster_list = new List <Monster>() { UnitManager.GenerateMonster() }; List <PlayableCharacter> active_pcus = UnitManager.GetActivePCUs(); turn_counter = 0; // 67% chance to add a second monster if (rng.Next(0, 100) > 33) { monster_list.Add(UnitManager.GenerateMonster()); // 34% chance to add a third monster if a second monster was already added if (rng.Next(0, 100) > 66) { monster_list.Add(UnitManager.GenerateMonster()); } } if (is_bossfight) { Console.WriteLine($"The legendary {monster_list[0].Name} has awoken!"); SoundManager.battle_music.PlayLooping(); } else { if (monster_list.Count == 1) { Console.WriteLine($"A {monster_list[0].Name} suddenly appeared out of nowhere!"); } else if (monster_list.Count == 2) { Console.WriteLine($"A {monster_list[0].Name} and 1 other monster suddenly appeared out of nowhere!"); } else if (monster_list.Count > 2) { Console.WriteLine($"A {monster_list[0].Name} and {monster_list.Count - 1} other monsters suddenly appeared out of nowhere!"); } SoundManager.battle_music.PlayLooping(); } CMethods.SmartSleep(1000); // Create a temporary copy of all of the player's stats. These copies are what will be modified in-battle by // spells, abilities, etc. so that they will return to normal after battle (although they in fact were never // touched to begin with) active_pcus.ForEach(x => x.SetTempStats()); // While all active party members are alive, continue the battle while (monster_list.Any(x => x.HP > 0) && active_pcus.Any(x => x.HP > 0)) { turn_counter++; List <Unit> speed_list = new List <Unit>(); active_pcus.ForEach(x => speed_list.Add(x)); monster_list.ForEach(x => speed_list.Add(x)); // Display the stats for every battle participant DisplayBattleStats(active_pcus, monster_list); // Iterate through each active players foreach (PlayableCharacter character in UnitManager.GetAliveActivePCUs()) { if (0 < character.HP && character.HP <= character.MaxHP * 0.20) { Console.WriteLine($"Warning: {character.Name}'s HP is low, heal as soon as possible!"); SoundManager.health_low.SmartPlay(); CMethods.SmartSleep(1333); } character.PlayerChoice(monster_list); if (character != UnitManager.GetAliveActivePCUs().Last()) { CMethods.PrintDivider(); } } // Iterate through each unit in the battle from fastest to slowest foreach (Unit unit in speed_list) { if (unit.IsAlive()) { if (monster_list.All(x => x.HP <= 0) || active_pcus.All(x => x.HP <= 0)) { break; } CMethods.PrintDivider(); // Leave the battle if the player runs away if (unit is PlayableCharacter) { PlayableCharacter pcu = unit as PlayableCharacter; if (pcu.PlayerExecuteMove(monster_list) == "ran") { return; } } else if (unit is Monster) { Monster monster = unit as Monster; monster.MonsterExecuteMove(); } } // If any unit died on this turn, set their health to 0 and set their status as 'dead' foreach (Unit other_unit in speed_list) { if (other_unit is PlayableCharacter && other_unit.HP <= 0 && other_unit.IsAlive()) { other_unit.FixAllStats(); CMethods.SmartSleep(250); SoundManager.ally_death.SmartPlay(); Console.WriteLine($"\n{other_unit.Name} has fallen to the monsters!"); } else if (other_unit is Monster && other_unit.HP <= 0 && other_unit.IsAlive()) { other_unit.FixAllStats(); CMethods.SmartSleep(250); SoundManager.enemy_death.SmartPlay(); Console.WriteLine($"\nThe {other_unit.Name} was defeated by your party!"); } } if (monster_list.Any(x => x.HP > 0) && unit.HP > 0) { CMethods.PressAnyKeyToContinue(); } } } // Determine the results of the battle and react accordingly AfterBattle(active_pcus, monster_list, is_bossfight); }
public static void SetAdventureName() { // This function asks the player for an "adventure name". This is the // name of the directory in which his/her save files will be stored. while (true) { // Certain OSes don't allow certain characters, so this removes those characters // and replaces them with whitespace. The player is then asked if this is okay. string adventure = CMethods.MultiCharInput("Finally, what do you want to name this adventure? "); // This line removes all characters that are not alphanumeric, spaces, dashes, or underscores // We also remove repeated spaces like "Hello world" => "Hello world" // Finally we .Trim() to remove leading or ending whitespace like " Hello world " => "Hello world" adventure = Regex.Replace(Regex.Replace(adventure, @"[^\w\s\-]*", ""), @"\s+", " ").Trim(); // Make sure the adventure name isn't blank if (string.IsNullOrEmpty(adventure)) { continue; } // You also can't use "temp", because this is reserved for other features else if (adventure == "temp") { Console.WriteLine("Please choose a different name, that one definitely won't do!"); CMethods.PressAnyKeyToContinue(); continue; } // Make sure that the folder doesn't already exist else if (Directory.Exists(adventure)) { Console.WriteLine("I've already read about adventures with that name; be original!"); CMethods.PressAnyKeyToContinue(); continue; } // Max adventure name length is 35 else if (adventure.Length > 35) { Console.WriteLine("That adventure name is far too long, it would never catch on!"); CMethods.PressAnyKeyToContinue(); continue; } while (true) { string yes_no = CMethods.SingleCharInput($"You want your adventure to be remembered as '{adventure}'? | [Y]es or [N]o: ").ToLower(); if (CMethods.IsYesString(yes_no)) { adventure_name = adventure; return; } else if (CMethods.IsNoString(yes_no)) { CMethods.PrintDivider(); break; } } } }
public static bool PickSpell(CEnums.SpellCategory category, PlayableCharacter user, List <Monster> monster_list, bool is_battle) { List <Spell> chosen_spellbook = GetSpellbook(category).Where(x => x.RequiredLevel <= user.Level).ToList(); int padding; CMethods.PrintDivider(); while (true) { padding = chosen_spellbook.Max(x => x.SpellName.Length); Console.WriteLine($"{user.Name}'s {category.EnumToString()} Spells | {user.MP}/{user.MaxMP} MP remaining"); int counter = 0; foreach (Spell spell in chosen_spellbook) { Console.WriteLine($" [{counter + 1}] {spell.SpellName} {new string('-', padding - spell.SpellName.Length)}-> {spell.ManaCost} MP"); counter++; } while (true) { string chosen_spell = CMethods.FlexibleInput("Input [#] (or type 'exit'): ", chosen_spellbook.Count); try { user.CurrentSpell = chosen_spellbook[int.Parse(chosen_spell) - 1]; } catch (Exception ex) when(ex is FormatException || ex is ArgumentOutOfRangeException) { if (CMethods.IsExitString(chosen_spell)) { CMethods.PrintDivider(); return(false); } continue; } // Of course, you can't cast spells without the required amount of MP if (user.CurrentSpell.ManaCost > user.MP) { CMethods.PrintDivider(); Console.WriteLine($"{user.Name} doesn't have enough MP to cast {user.CurrentSpell.SpellName}!"); CMethods.PressAnyKeyToContinue(); break; } if (is_battle) { if (user.CurrentSpell is HealingSpell || user.CurrentSpell is BuffSpell) { if (user.PlayerGetTarget(monster_list, $"Who should {user.Name} cast {user.CurrentSpell.SpellName} on?", true, false, false, false)) { return(true); } else { break; } } else { if (user.PlayerGetTarget(monster_list, $"Who should {user.Name} cast {user.CurrentSpell.SpellName} on?", false, true, false, false)) { return(true); } else { break; } } } else { user.PlayerGetTarget(monster_list, $"Who should {user.Name} cast {user.CurrentSpell.SpellName} on?", true, false, false, false); user.CurrentSpell.UseMagic(user, is_battle); break; } } } }
public static void PickInventoryAction(string item_id) { Item this_item = ItemManager.FindItemWithID(item_id); CMethods.PrintDivider(); // Loop while the item is in the inventory while (true) { string action; if (this_item is Equipment) { // You equip weapons/armor/accessories action = "Equip"; } else { // You use other items action = "Use"; } Console.WriteLine($"What should your party do with the {this_item.ItemName}? "); Console.WriteLine($" [1] {action}"); Console.WriteLine(" [2] Read Description"); Console.WriteLine(" [3] Drop"); while (true) { string chosen = CMethods.SingleCharInput("Input [#] (or type 'exit'): ").ToLower(); if (CMethods.IsExitString(chosen)) { return; } else if (chosen == "1") { // Items of these classes require a target to be used, so we have to acquire a target first if (this_item is Equipment || this_item is HealthManaPotion || this_item is StatusPotion) { if (UnitManager.player.PlayerGetTarget(new List <Monster>(), $"Who should {action} the {this_item.ItemName}?", true, false, true, false)) { CMethods.PrintDivider(); this_item.UseItem(UnitManager.player.CurrentTarget as PlayableCharacter); return; } break; } // Other items can just be used normally else { CMethods.PrintDivider(); this_item.UseItem(UnitManager.player); } return; } else if (chosen == "2") { // Display the item description CMethods.PrintDivider(); Console.WriteLine($"Description for '{this_item.ItemName}': \n"); Console.WriteLine(this_item.Description); CMethods.PressAnyKeyToContinue(); CMethods.PrintDivider(); break; } else if (chosen == "3") { CMethods.PrintDivider(); // You can't throw away important/essential items, such as tools and quest items. // This is to prevent the game from becoming unwinnable. if (this_item.IsImportant) { Console.WriteLine("Essential Items cannot be thrown away."); CMethods.PressAnyKeyToContinue(); } else { while (true) { string yes_or_no = CMethods.SingleCharInput($"Throw away the {this_item.ItemName}? | [Y]es or [N]o: ").ToLower(); if (CMethods.IsYesString(yes_or_no)) { RemoveItemFromInventory(this_item.ItemID); Console.WriteLine($"You toss the {this_item.ItemName} aside and continue on your journey."); CMethods.PressAnyKeyToContinue(); return; } else if (CMethods.IsNoString(yes_or_no)) { Console.WriteLine($"You decide to keep the {this_item.ItemName}."); CMethods.PressAnyKeyToContinue(); return; } } } } } } }
public static void PickInventoryCategory() { while (true) { Console.WriteLine("Your Inventory: "); Console.WriteLine(" [1] Armor"); Console.WriteLine(" [2] Weapons"); Console.WriteLine(" [3] Accessories"); Console.WriteLine(" [4] Consumables"); Console.WriteLine(" [5] Tools"); Console.WriteLine(" [6] Quest Items"); Console.WriteLine(" [7] Miscellaneous"); Console.WriteLine(" [8] View Equipment"); Console.WriteLine(" [9] View Quests"); while (true) { string chosen = CMethods.SingleCharInput("Input [#] (or type 'exit'): ").ToLower(); CEnums.InvCategory category; if (CMethods.IsExitString(chosen)) { return; } else if (chosen == "1") { category = CEnums.InvCategory.armor; } else if (chosen == "2") { category = CEnums.InvCategory.weapons; } else if (chosen == "3") { category = CEnums.InvCategory.accessories; } else if (chosen == "4") { category = CEnums.InvCategory.consumables; } else if (chosen == "5") { category = CEnums.InvCategory.tools; } else if (chosen == "6") { category = CEnums.InvCategory.quest; } else if (chosen == "7") { category = CEnums.InvCategory.misc; } else if (chosen == "8") { // Equipped items aren't actually stored in the inventory, so they need their own function to handle them PickEquipmentItem(); break; } else if (chosen == "9") { // Quests have their own function, because they aren't actually instances of the Item class ViewQuests(); break; } else { continue; } if (GetInventory()[category].Count > 0) { PickInventoryItem(category, false); break; } else { CMethods.PrintDivider(); Console.WriteLine($"Your part has no {category.EnumToString()}."); CMethods.PressAnyKeyToContinue(); CMethods.PrintDivider(); break; } } } }