diff --git a/17 Bullfight/csharp/Bullfight.sln b/17 Bullfight/csharp/Bullfight.sln new file mode 100644 index 00000000..29f5276f --- /dev/null +++ b/17 Bullfight/csharp/Bullfight.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.31321.278 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Game", "Game.csproj", "{8F7C450E-5F3A-45BA-9DB9-329744214931}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {8F7C450E-5F3A-45BA-9DB9-329744214931}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {8F7C450E-5F3A-45BA-9DB9-329744214931}.Debug|Any CPU.Build.0 = Debug|Any CPU + {8F7C450E-5F3A-45BA-9DB9-329744214931}.Release|Any CPU.ActiveCfg = Release|Any CPU + {8F7C450E-5F3A-45BA-9DB9-329744214931}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {C5BFC749-C7D8-4981-A7D4-1D401901A890} + EndGlobalSection +EndGlobal diff --git a/17 Bullfight/csharp/Game.csproj b/17 Bullfight/csharp/Game.csproj new file mode 100644 index 00000000..36c64642 --- /dev/null +++ b/17 Bullfight/csharp/Game.csproj @@ -0,0 +1,7 @@ + + + Exe + net5.0 + enable + + diff --git a/17 Bullfight/csharp/src/Action.cs b/17 Bullfight/csharp/src/Action.cs new file mode 100644 index 00000000..2a148683 --- /dev/null +++ b/17 Bullfight/csharp/src/Action.cs @@ -0,0 +1,24 @@ +namespace Game +{ + /// + /// Enumerates the different actions that the player can take on each round + /// of the fight. + /// + public enum Action + { + /// + /// Dodge the bull. + /// + Dodge, + + /// + /// Kill the bull. + /// + Kill, + + /// + /// Freeze in place and don't do anything. + /// + Panic + } +} diff --git a/17 Bullfight/csharp/src/ActionResult.cs b/17 Bullfight/csharp/src/ActionResult.cs new file mode 100644 index 00000000..baa74f2e --- /dev/null +++ b/17 Bullfight/csharp/src/ActionResult.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Game +{ + /// + /// Enumerates the different possible outcomes of the player's action. + /// + public enum ActionResult + { + /// + /// The fight continues. + /// + FightContinues, + + /// + /// The player fled from the ring. + /// + PlayerFlees, + + /// + /// The bull has gored the player. + /// + BullGoresPlayer, + + /// + /// The bull killed the player. + /// + BullKillsPlayer, + + /// + /// The player killed the bull. + /// + PlayerKillsBull, + + /// + /// The player attempted to kill the bull and both survived. + /// + Draw + } +} diff --git a/17 Bullfight/csharp/src/BullFight.cs b/17 Bullfight/csharp/src/BullFight.cs new file mode 100644 index 00000000..8df6ff8c --- /dev/null +++ b/17 Bullfight/csharp/src/BullFight.cs @@ -0,0 +1,220 @@ +using System; +using System.Collections.Generic; + +namespace Game +{ + /// + /// Provides a method for simulating a bull fight. + /// + public static class BullFight + { + /// + /// Begins a new fight. + /// + /// + /// Object used to communicate with the player. + /// + /// + /// The sequence of events that take place during the fight. + /// + /// + /// After receiving each event, the caller must invoke the appropriate + /// mediator method to inform this coroutine what to do next. Failure + /// to do so will result in an exception. + /// + public static IEnumerable Begin(Mediator mediator) + { + var random = new Random(); + var result = ActionResult.FightContinues; + + var bullQuality = GetBullQuality(); + var toreadorePerformance = GetHelpQuality(bullQuality); + var picadorePerformance = GetHelpQuality(bullQuality); + + var bullStrength = 6 - (int)bullQuality; + var assistanceLevel = (12 - (int)toreadorePerformance - (int)picadorePerformance) * 0.1; + var bravery = 1.0; + var style = 1.0; + var passNumber = 0; + + yield return new Events.MatchStarted( + bullQuality, + toreadorePerformance, + picadorePerformance, + GetHumanCasualties(toreadorePerformance), + GetHumanCasualties(picadorePerformance), + GetHorseCasualties(picadorePerformance)); + + while (result == ActionResult.FightContinues) + { + yield return new Events.BullCharging(++passNumber); + + var (action, riskLevel) = mediator.GetInput<(Action, RiskLevel)>(); + result = action switch + { + Action.Dodge => TryDodge(riskLevel), + Action.Kill => TryKill(riskLevel), + _ => Panic() + }; + + var first = true; + while (result == ActionResult.BullGoresPlayer) + { + yield return new Events.PlayerGored(action == Action.Panic, first); + first = false; + + result = TrySurvive(); + if (result == ActionResult.FightContinues) + { + yield return new Events.PlayerSurvived(); + + var runFromRing = mediator.GetInput(); + if (runFromRing) + result = Flee(); + else + result = IgnoreInjury(action); + } + } + } + + yield return new Events.MatchCompleted( + result, + bravery == 2, + GetReward()); + + Quality GetBullQuality() => + (Quality)random.Next(1, 6); + + Quality GetHelpQuality(Quality bullQuality) => + ((3.0 / (int)bullQuality) * random.NextDouble()) switch + { + < 0.37 => Quality.Superb, + < 0.50 => Quality.Good, + < 0.63 => Quality.Fair, + < 0.87 => Quality.Poor, + _ => Quality.Awful + }; + + int GetHumanCasualties(Quality performance) => + performance switch + { + Quality.Poor => random.Next(0, 2), + Quality.Awful => random.Next(1, 3), + _ => 0 + }; + + int GetHorseCasualties(Quality performance) => + performance switch + { + // NOTE: The code for displaying a single horse casuality + // following a poor picadore peformance was unreachable + // in the original BASIC version. I've assumed this was + // a bug. + Quality.Poor => 1, + Quality.Awful => random.Next(1, 3), + _ => 0 + }; + + ActionResult TryDodge(RiskLevel riskLevel) + { + var difficultyModifier = riskLevel switch + { + RiskLevel.High => 3.0, + RiskLevel.Medium => 2.0, + _ => 0.5 + }; + + var outcome = (bullStrength + (difficultyModifier / 10)) * random.NextDouble() / + ((assistanceLevel + (passNumber / 10.0)) * 5); + + if (outcome < 0.51) + { + style += difficultyModifier; + return ActionResult.FightContinues; + } + else + return ActionResult.BullGoresPlayer; + } + + ActionResult TryKill(RiskLevel riskLevel) + { + var luck = bullStrength * 10 * random.NextDouble() / (assistanceLevel * 5 * passNumber); + + return ((riskLevel == RiskLevel.High && luck > 0.2) || luck > 0.8) ? + ActionResult.BullGoresPlayer : ActionResult.PlayerKillsBull; + } + + ActionResult Panic() => + ActionResult.BullGoresPlayer; + + ActionResult TrySurvive() + { + if (random.Next(2) == 0) + { + bravery = 1.5; + return ActionResult.BullKillsPlayer; + } + else + return ActionResult.FightContinues; + } + + ActionResult Flee() + { + bravery = 0.0; + return ActionResult.PlayerFlees; + } + + ActionResult IgnoreInjury(Action action) + { + if (random.Next(2) == 0) + { + bravery = 2.0; + return action == Action.Dodge ? ActionResult.FightContinues : ActionResult.Draw; + } + else + return ActionResult.BullGoresPlayer; + } + + Reward GetReward() + { + var score = CalculateScore(); + + if (score * random.NextDouble() < 2.4) + return Reward.Nothing; + else + if (score * random.NextDouble() < 4.9) + return Reward.OneEar; + else + if (score * random.NextDouble() < 7.4) + return Reward.TwoEars; + else + return Reward.CarriedFromRing; + } + + double CalculateScore() + { + var score = 4.5; + + // Style + score += style / 6; + + // Assisstance + score -= assistanceLevel * 2.5; + + // Courage + score += 4 * bravery; + + // Kill bonus + score += (result == ActionResult.PlayerKillsBull) ? 4 : 2; + + // Match length + score -= Math.Pow(passNumber, 2) / 120; + + // Difficulty + score -= (int)bullQuality; + + return score; + } + } + } +} diff --git a/17 Bullfight/csharp/src/Controller.cs b/17 Bullfight/csharp/src/Controller.cs new file mode 100644 index 00000000..c1441f9a --- /dev/null +++ b/17 Bullfight/csharp/src/Controller.cs @@ -0,0 +1,134 @@ +using System; + +namespace Game +{ + /// + /// Contains functions for getting input from the user. + /// + public static class Controller + { + /// + /// Handles the initial interaction with the player. + /// + public static void StartGame() + { + View.ShowBanner(); + View.PromptShowInstructions(); + + var input = Console.ReadLine(); + if (input is null) + Environment.Exit(0); + + if (input.ToUpperInvariant() != "NO") + View.ShowInstructions(); + + View.ShowSeparator(); + } + + /// + /// Gets the player's action for the current round. + /// + /// + /// The current pass number. + /// + public static (Action action, RiskLevel riskLevel) GetPlayerIntention(int passNumber) + { + if (passNumber < 3) + View.PromptKillBull(); + else + View.PromptKillBullBrief(); + + var attemptToKill = GetYesOrNo(); + + if (attemptToKill) + { + View.PromptKillMethod(); + + var input = Console.ReadLine(); + if (input is null) + Environment.Exit(0); + + return input switch + { + "4" => (Action.Kill, RiskLevel.High), + "5" => (Action.Kill, RiskLevel.Low), + _ => (Action.Panic, default(RiskLevel)) + }; + } + else + { + if (passNumber < 2) + View.PromptCapeMove(); + else + View.PromptCapeMoveBrief(); + + var action = Action.Panic; + var riskLevel = default(RiskLevel); + + while (action == Action.Panic) + { + var input = Console.ReadLine(); + if (input is null) + Environment.Exit(0); + + (action, riskLevel) = input switch + { + "0" => (Action.Dodge, RiskLevel.High), + "1" => (Action.Dodge, RiskLevel.Medium), + "2" => (Action.Dodge, RiskLevel.Low), + _ => (Action.Panic, default(RiskLevel)) + }; + + if (action == Action.Panic) + View.PromptDontPanic(); + } + + return (action, riskLevel); + } + } + + /// + /// Gets the player's intention to flee (or not). + /// + /// + /// True if the player flees; otherwise, false. + /// + public static bool GetPlayerRunsFromRing() + { + View.PromptRunFromRing(); + + var playerFlees = GetYesOrNo(); + if (!playerFlees) + View.ShowPlayerFoolhardy(); + + return playerFlees; + } + + /// + /// Gets a yes or no response from the player. + /// + /// + /// True if the user answered yes; otherwise, false. + /// + public static bool GetYesOrNo() + { + while (true) + { + var input = Console.ReadLine(); + if (input is null) + Environment.Exit(0); + + switch (input.ToUpperInvariant()) + { + case "YES": + return true; + case "NO": + return false; + default: + Console.WriteLine("INCORRECT ANSWER - - PLEASE TYPE 'YES' OR 'NO'."); + break; + } + } + } + } +} diff --git a/17 Bullfight/csharp/src/Events/BullCharging.cs b/17 Bullfight/csharp/src/Events/BullCharging.cs new file mode 100644 index 00000000..bc041c64 --- /dev/null +++ b/17 Bullfight/csharp/src/Events/BullCharging.cs @@ -0,0 +1,7 @@ +namespace Game.Events +{ + /// + /// Indicates that the bull is charing the player. + /// + public sealed record BullCharging(int PassNumber) : Event; +} diff --git a/17 Bullfight/csharp/src/Events/Event.cs b/17 Bullfight/csharp/src/Events/Event.cs new file mode 100644 index 00000000..e9a8a646 --- /dev/null +++ b/17 Bullfight/csharp/src/Events/Event.cs @@ -0,0 +1,7 @@ +namespace Game.Events +{ + /// + /// Common base class for all events in the game. + /// + public abstract record Event(); +} diff --git a/17 Bullfight/csharp/src/Events/MatchCompleted.cs b/17 Bullfight/csharp/src/Events/MatchCompleted.cs new file mode 100644 index 00000000..94c67d06 --- /dev/null +++ b/17 Bullfight/csharp/src/Events/MatchCompleted.cs @@ -0,0 +1,7 @@ +namespace Game.Events +{ + /// + /// Indicates that the fight has completed. + /// + public sealed record MatchCompleted(ActionResult Result, bool ExtremeBravery, Reward Reward) : Event; +} diff --git a/17 Bullfight/csharp/src/Events/MatchStarted.cs b/17 Bullfight/csharp/src/Events/MatchStarted.cs new file mode 100644 index 00000000..8141b617 --- /dev/null +++ b/17 Bullfight/csharp/src/Events/MatchStarted.cs @@ -0,0 +1,13 @@ +namespace Game.Events +{ + /// + /// Indicates that a new match has started. + /// + public sealed record MatchStarted( + Quality BullQuality, + Quality ToreadorePerformance, + Quality PicadorePerformance, + int ToreadoresKilled, + int PicadoresKilled, + int HorsesKilled) : Event; +} diff --git a/17 Bullfight/csharp/src/Events/PlayerGored.cs b/17 Bullfight/csharp/src/Events/PlayerGored.cs new file mode 100644 index 00000000..f55ae20d --- /dev/null +++ b/17 Bullfight/csharp/src/Events/PlayerGored.cs @@ -0,0 +1,7 @@ +namespace Game.Events +{ + /// + /// Indicates that the player has been gored by the bull. + /// + public sealed record PlayerGored(bool Panicked, bool FirstGoring) : Event; +} diff --git a/17 Bullfight/csharp/src/Events/PlayerSurvived.cs b/17 Bullfight/csharp/src/Events/PlayerSurvived.cs new file mode 100644 index 00000000..135a9a09 --- /dev/null +++ b/17 Bullfight/csharp/src/Events/PlayerSurvived.cs @@ -0,0 +1,7 @@ +namespace Game.Events +{ + /// + /// Indicates that the player has survived being gored by the bull. + /// + public sealed record PlayerSurvived() : Event; +} diff --git a/17 Bullfight/csharp/src/Mediator.cs b/17 Bullfight/csharp/src/Mediator.cs new file mode 100644 index 00000000..c9d4e298 --- /dev/null +++ b/17 Bullfight/csharp/src/Mediator.cs @@ -0,0 +1,48 @@ +using System.Diagnostics; + +namespace Game +{ + /// + /// Facilitates sending messages between the two game loops. + /// + /// + /// This class serves as a little piece of glue in between the main program + /// loop and the bull fight coroutine. When the main program calls one of + /// its methods, the mediator creates the appropriate input data that the + /// bull fight coroutine later retrieves with . + /// + public class Mediator + { + private object? m_input; + + public void Dodge(RiskLevel riskLevel) => + m_input = (Action.Dodge, riskLevel); + + public void Kill(RiskLevel riskLevel) => + m_input = (Action.Kill, riskLevel); + + public void Panic() => + m_input = (Action.Panic, default(RiskLevel)); + + public void RunFromRing() => + m_input = true; + + public void ContinueFighting() => + m_input = false; + + /// + /// Gets the next input from the user. + /// + /// + /// The type of input to receive. + /// + public T GetInput() + { + Debug.Assert(m_input is not null, "No input received"); + Debug.Assert(m_input.GetType() == typeof(T), "Invalid input received"); + var result = (T)m_input; + m_input = null; + return result; + } + } +} diff --git a/17 Bullfight/csharp/src/Program.cs b/17 Bullfight/csharp/src/Program.cs new file mode 100644 index 00000000..d3f3760b --- /dev/null +++ b/17 Bullfight/csharp/src/Program.cs @@ -0,0 +1,54 @@ +namespace Game +{ + class Program + { + static void Main() + { + Controller.StartGame(); + + var mediator = new Mediator(); + foreach (var evt in BullFight.Begin(mediator)) + { + switch (evt) + { + case Events.MatchStarted matchStarted: + View.ShowStartingConditions(matchStarted); + break; + + case Events.BullCharging bullCharging: + View.ShowStartOfPass(bullCharging.PassNumber); + var (action, riskLevel) = Controller.GetPlayerIntention(bullCharging.PassNumber); + switch (action) + { + case Action.Dodge: + mediator.Dodge(riskLevel); + break; + case Action.Kill: + mediator.Kill(riskLevel); + break; + case Action.Panic: + mediator.Panic(); + break; + } + break; + + case Events.PlayerGored playerGored: + View.ShowPlayerGored(playerGored.Panicked, playerGored.FirstGoring); + break; + + case Events.PlayerSurvived: + View.ShowPlayerSurvives(); + if (Controller.GetPlayerRunsFromRing()) + mediator.RunFromRing(); + else + mediator.ContinueFighting(); + break; + + case Events.MatchCompleted matchCompleted: + View.ShowFinalResult(matchCompleted.Result, matchCompleted.ExtremeBravery, matchCompleted.Reward); + break; + } + } + } + } +} diff --git a/17 Bullfight/csharp/src/Quality.cs b/17 Bullfight/csharp/src/Quality.cs new file mode 100644 index 00000000..ee7bf6d9 --- /dev/null +++ b/17 Bullfight/csharp/src/Quality.cs @@ -0,0 +1,19 @@ +namespace Game +{ + /// + /// Enumerates the different levels of quality in the game. + /// + /// + /// Quality applies both to the bull and to the help received from the + /// toreadores and picadores. Note that the ordinal values are significant + /// (these are used in various calculations). + /// + public enum Quality + { + Superb = 1, + Good = 2, + Fair = 3, + Poor = 4, + Awful = 5 + } +} diff --git a/17 Bullfight/csharp/src/Reward.cs b/17 Bullfight/csharp/src/Reward.cs new file mode 100644 index 00000000..295789be --- /dev/null +++ b/17 Bullfight/csharp/src/Reward.cs @@ -0,0 +1,13 @@ +namespace Game +{ + /// + /// Enumerates the different things the player can be awarded. + /// + public enum Reward + { + Nothing, + OneEar, + TwoEars, + CarriedFromRing + } +} diff --git a/17 Bullfight/csharp/src/RiskLevel.cs b/17 Bullfight/csharp/src/RiskLevel.cs new file mode 100644 index 00000000..8048f663 --- /dev/null +++ b/17 Bullfight/csharp/src/RiskLevel.cs @@ -0,0 +1,12 @@ +namespace Game +{ + /// + /// Enumerates the different levels of risk for manoeuvres in the game. + /// + public enum RiskLevel + { + Low, + Medium, + High + } +} diff --git a/17 Bullfight/csharp/src/View.cs b/17 Bullfight/csharp/src/View.cs new file mode 100644 index 00000000..0cc627b8 --- /dev/null +++ b/17 Bullfight/csharp/src/View.cs @@ -0,0 +1,242 @@ +using System; + +namespace Game +{ + /// + /// Contains functions for displaying information to the user. + /// + public static class View + { + private static readonly string[] QualityString = { "SUPERB", "GOOD", "FAIR", "POOR", "AWFUL" }; + + public static void ShowBanner() + { + Console.WriteLine(" BULL"); + Console.WriteLine(" CREATIVE COMPUTING MORRISTOWN, NEW JERSEY"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + } + + public static void ShowInstructions() + { + Console.WriteLine("HELLO, ALL YOU BLOODLOVERS AND AFICIONADOS."); + Console.WriteLine("HERE IS YOUR BIG CHANCE TO KILL A BULL."); + Console.WriteLine(); + Console.WriteLine("ON EACH PASS OF THE BULL, YOU MAY TRY"); + Console.WriteLine("0 - VERONICA (DANGEROUS INSIDE MOVE OF THE CAPE)"); + Console.WriteLine("1 - LESS DANGEROUS OUTSIDE MOVE OF THE CAPE"); + Console.WriteLine("2 - ORDINARY SWIRL OF THE CAPE."); + Console.WriteLine(); + Console.WriteLine("INSTEAD OF THE ABOVE, YOU MAY TRY TO KILL THE BULL"); + Console.WriteLine("ON ANY TURN: 4 (OVER THE HORNS), 5 (IN THE CHEST)."); + Console.WriteLine("BUT IF I WERE YOU,"); + Console.WriteLine("I WOULDN'T TRY IT BEFORE THE SEVENTH PASS."); + Console.WriteLine(); + Console.WriteLine("THE CROWD WILL DETERMINE WHAT AWARD YOU DESERVE"); + Console.WriteLine("(POSTHUMOUSLY IF NECESSARY)."); + Console.WriteLine("THE BRAVER YOU ARE, THE BETTER THE AWARD YOU RECEIVE."); + Console.WriteLine(); + Console.WriteLine("THE BETTER THE JOB THE PICADORES AND TOREADORES DO,"); + Console.WriteLine("THE BETTER YOUR CHANCES ARE."); + } + + public static void ShowSeparator() + { + Console.WriteLine(); + Console.WriteLine(); + } + + public static void ShowStartingConditions(Events.MatchStarted matchStarted) + { + ShowBullQuality(); + ShowHelpQuality("TOREADORES", matchStarted.ToreadorePerformance, matchStarted.ToreadoresKilled, 0); + ShowHelpQuality("PICADORES", matchStarted.PicadorePerformance, matchStarted.PicadoresKilled, matchStarted.HorsesKilled); + + void ShowBullQuality() + { + Console.WriteLine($"YOU HAVE DRAWN A {QualityString[(int)matchStarted.BullQuality - 1]} BULL."); + + if (matchStarted.BullQuality > Quality.Poor) + { + Console.WriteLine("YOU'RE LUCKY"); + } + else + if (matchStarted.BullQuality < Quality.Good) + { + Console.WriteLine("GOOD LUCK. YOU'LL NEED IT."); + Console.WriteLine(); + } + + Console.WriteLine(); + } + + static void ShowHelpQuality(string helperName, Quality helpQuality, int helpersKilled, int horsesKilled) + { + Console.WriteLine($"THE {helperName} DID A {QualityString[(int)helpQuality - 1]} JOB."); + + // NOTE: The code below makes some *strong* assumptions about + // how the casualty numbers were generated. It is written + // this way to preserve the behaviour of the original BASIC + // version, but it would make more sense ignore the helpQuality + // parameter and just use the provided numbers to decide what + // to display. + switch (helpQuality) + { + case Quality.Poor: + if (horsesKilled > 0) + Console.WriteLine($"ONE OF THE HORSES OF THE {helperName} WAS KILLED."); + + if (helpersKilled > 0) + Console.WriteLine($"ONE OF THE {helperName} WAS KILLED."); + else + Console.WriteLine($"NO {helperName} WERE KILLED."); + break; + + case Quality.Awful: + if (horsesKilled > 0) + Console.WriteLine($" {horsesKilled} OF THE HORSES OF THE {helperName} KILLED."); + + Console.WriteLine($" {helpersKilled} OF THE {helperName} KILLED."); + break; + } + } + } + + public static void ShowStartOfPass(int passNumber) + { + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine($"PASS NUMBER {passNumber}"); + } + + public static void ShowPlayerGored(bool playerPanicked, bool firstGoring) + { + Console.WriteLine((playerPanicked, firstGoring) switch + { + (true, true) => "YOU PANICKED. THE BULL GORED YOU.", + (false, true) => "THE BULL HAS GORED YOU!", + (_, false) => "YOU ARE GORED AGAIN!" + }); + } + + public static void ShowPlayerSurvives() + { + Console.WriteLine("YOU ARE STILL ALIVE."); + Console.WriteLine(); + } + + public static void ShowPlayerFoolhardy() + { + Console.WriteLine("YOU ARE BRAVE. STUPID, BUT BRAVE."); + } + + public static void ShowFinalResult(ActionResult result, bool extremeBravery, Reward reward) + { + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + + switch (result) + { + case ActionResult.PlayerFlees: + Console.WriteLine("COWARD"); + break; + case ActionResult.BullKillsPlayer: + Console.WriteLine("YOU ARE DEAD."); + break; + case ActionResult.PlayerKillsBull: + Console.WriteLine("YOU KILLED THE BULL!"); + break; + } + + if (result == ActionResult.PlayerFlees) + { + Console.WriteLine("THE CROWD BOOS FOR TEN MINUTES. IF YOU EVER DARE TO SHOW"); + Console.WriteLine("YOUR FACE IN A RING AGAIN, THEY SWEAR THEY WILL KILL YOU--"); + Console.WriteLine("UNLESS THE BULL DOES FIRST."); + } + else + { + if (extremeBravery) + Console.WriteLine("THE CROWD CHEERS WILDLY!"); + else + if (result == ActionResult.PlayerKillsBull) + { + Console.WriteLine("THE CROWD CHEERS!"); + Console.WriteLine(); + } + + Console.WriteLine("THE CROWD AWARDS YOU"); + switch (reward) + { + case Reward.Nothing: + Console.WriteLine("NOTHING AT ALL."); + break; + case Reward.OneEar: + Console.WriteLine("ONE EAR OF THE BULL."); + break; + case Reward.TwoEars: + Console.WriteLine("BOTH EARS OF THE BULL!"); + Console.WriteLine("OLE!"); + break; + default: + Console.WriteLine("OLE! YOU ARE 'MUY HOMBRE'!! OLE! OLE!"); + break; + } + } + + Console.WriteLine(); + Console.WriteLine("ADIOS"); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine(); + } + + public static void PromptShowInstructions() + { + Console.Write("DO YOU WANT INSTRUCTIONS? "); + } + + public static void PromptKillBull() + { + Console.WriteLine("THE BULL IS CHARGING AT YOU! YOU ARE THE MATADOR--"); + Console.Write("DO YOU WANT TO KILL THE BULL? "); + } + + public static void PromptKillBullBrief() + { + Console.Write("HERE COMES THE BULL. TRY FOR A KILL? "); + } + + public static void PromptKillMethod() + { + Console.WriteLine(); + Console.WriteLine("IT IS THE MOMENT OF TRUTH."); + Console.WriteLine(); + + Console.Write("HOW DO YOU TRY TO KILL THE BULL? "); + } + + public static void PromptCapeMove() + { + Console.Write("WHAT MOVE DO YOU MAKE WITH THE CAPE? "); + } + + public static void PromptCapeMoveBrief() + { + Console.Write("CAPE MOVE? "); + } + + public static void PromptDontPanic() + { + Console.WriteLine("DON'T PANIC, YOU IDIOT! PUT DOWN A CORRECT NUMBER"); + Console.Write("? "); + } + + public static void PromptRunFromRing() + { + Console.Write("DO YOU RUN FROM THE RING? "); + } + } +}