Created
May 22, 2015 01:47
-
-
Save AIBrain/37fa4ba3a18b5de6cbcb to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
namespace RPG { | |
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
internal class Program { | |
/// <summary> | |
/// Puts your comments in here, instead of near the end brackets. | |
/// In Visual Studio, the shortcut is three "/" (press slash 3 times) | |
/// </summary> | |
/// <param name="args"></param> | |
private static void Main( string[] args ) { | |
var game = new GameClass(); | |
game.Run(); | |
} | |
private class GameClass { | |
internal static readonly Random RNG = new Random(); | |
internal Player HumanPlayer; | |
internal readonly List<Player> EnemyPlayers = new List<Player>(); | |
/// <summary> | |
/// SELECTING CHARACTER CLASS (MAGE OR WARRIOR) | |
/// </summary> | |
/// <returns></returns> | |
private static PossiblePath ChoosePath( String name ) { | |
Console.WriteLine(); | |
Console.Write( "Do you walk the Path of The Mage (1) or the Path of The Warrior (2), {0}? ", name ); | |
var classChoice = Console.ReadLine(); | |
switch ( classChoice ) { | |
case "1": | |
return PossiblePath.Mage; | |
default: | |
return PossiblePath.Warrior; //choose a warrior by default | |
} | |
} | |
private void SetUpCharacter() { | |
Console.WriteLine( "Hello, human." ); | |
TryAgain: | |
Console.Write( "What is your name? " ); | |
var name = Console.ReadLine(); | |
if ( String.IsNullOrWhiteSpace( name ) ) { | |
Console.WriteLine( "I'm sorry..?" ); | |
goto TryAgain; | |
} | |
var choice = ChoosePath( name ); | |
this.HumanPlayer = new Player( name: name, choosenPath: choice ); | |
this.HumanPlayer.Display(); | |
} | |
public void Run() { | |
SetUpCharacter(); | |
ShowTutorial(); | |
PlayGame(); | |
} | |
private void ShowTutorial() { | |
Console.WriteLine(); | |
Console.WriteLine( "Welcome to the tutorial, {0}. You will face a basic enemy Kobold in this room.", this.HumanPlayer.Name ); | |
var kobold = new Kobold( name: "Kobold" ); | |
this.EnemyPlayers.Add( kobold ); | |
} | |
private static PossibleAction GetPlayerAction() { | |
do { | |
Console.WriteLine(); | |
Console.Write( "Attempt to (F)ight or (R)un?" ); | |
var key = Console.ReadKey().Key; | |
Console.WriteLine(); | |
switch ( key ) { | |
case ConsoleKey.F: | |
return PossibleAction.Fight; | |
case ConsoleKey.R: | |
return PossibleAction.Run; | |
} | |
} while ( true ); | |
} | |
/// <summary> | |
/// //TODO I'm not sure the ref are needed here... | |
/// </summary> | |
/// <param name="player1"></param> | |
/// <param name="player2"></param> | |
private void Attacks( ref Player player1, ref Player player2 ) { | |
if ( player1 == null ) { | |
throw new ArgumentNullException( nameof( player1 ) ); | |
} | |
if ( player2 == null ) { | |
throw new ArgumentNullException( nameof( player2 ) ); | |
} | |
var player1AttacksFor = RNG.Next( ( int )( player1.Attack * 0.5f ), ( int )( player1.Attack * 1.5f ) ); | |
Console.WriteLine( "{0} attacks {1} for {2} points.", player1.Name, player2.Name, player1AttacksFor ); | |
player2.HitPoints -= player1AttacksFor; | |
player1.Display(); | |
player2.Display(); | |
} | |
private void PlayGame() { | |
if ( null == this.HumanPlayer ) { | |
throw new InvalidOperationException( "The human player has not been set up yet." ); | |
} | |
while ( this.EnemyPlayers.Count < RNG.Next( 1, 10 ) ) { | |
Player enemy; | |
if ( RNG.Next( 0, 2 ) == 0 ) { | |
enemy = new Kobold(); | |
} | |
else { | |
enemy = new Goblin(); | |
} | |
this.EnemyPlayers.Add( enemy ); | |
} | |
if ( !this.EnemyPlayers.Any() ) { | |
throw new InvalidOperationException( "No enemies to fight!" ); | |
} | |
Console.WriteLine(); | |
Console.WriteLine( "You encounter {0} enemies. {1} kobolds and {2} goblins.", this.EnemyPlayers.Count, this.EnemyPlayers.OfType<Kobold>().Count(), this.EnemyPlayers.OfType<Goblin>().Count() ); | |
while ( this.HumanPlayer.IsAlive() && this.EnemyPlayers.Any() ) { | |
var action = GetPlayerAction(); | |
var fastestEnemy = EnemyPlayers.OrderByDescending( player => player.Speed ).First(); | |
if ( fastestEnemy.Speed > this.HumanPlayer.Speed ) { | |
Attacks( ref fastestEnemy, ref this.HumanPlayer ); | |
if ( fastestEnemy.IsDead() ) { | |
this.EnemyPlayers.Remove( fastestEnemy ); | |
} | |
} | |
else { | |
switch ( action ) { | |
case PossibleAction.Fight: | |
Attacks( ref this.HumanPlayer, ref fastestEnemy ); | |
break; | |
case PossibleAction.Run: | |
if ( RNG.Next( 1, 100 ) > 50 ) { | |
Console.WriteLine( "{0} runs away in fright!" ); | |
goto GameOver; | |
} | |
Console.WriteLine( "You decide to move faster.." ); | |
this.HumanPlayer.Speed += ( Single )RNG.NextDouble(); //increase the player's speed. //cheat? :P | |
break; | |
default: | |
throw new ArgumentOutOfRangeException(); | |
} | |
} | |
} | |
GameOver: | |
Console.WriteLine(); | |
Console.Write( "Game over.." ); | |
Console.WriteLine( this.HumanPlayer.IsAlive() ? "You survived! Good job!" : "..you died. Better luck next time." ); | |
Console.WriteLine( "Press enter." ); | |
Console.ReadLine(); | |
} | |
} | |
} | |
internal enum PossiblePath { | |
Mage, Warrior | |
} | |
internal enum PossibleAction { | |
Fight, Run | |
} | |
/// <summary> | |
/// Define a basic CHARACTER class | |
/// </summary> | |
internal class Player { | |
public const int MinimumHitPoints = 100; | |
public const int MaximumHitPoints = 500; | |
public const int MinimumAttack = 100; | |
public const int MaximumAttack = 500; | |
internal static readonly Random RNG = new Random(); //this is only created once, no matter how many Player() we instantiate | |
private float _speed; | |
public string Name { get; } | |
public int HitPoints { get; protected internal set; } //go ahead and use longer descriptive names. | |
public int Attack { get; protected set; } | |
/// <summary> | |
/// Determines who gets to go first. | |
/// </summary> | |
public Single Speed { | |
get { return this._speed; } | |
set { | |
if ( value < 0 ) { | |
value = 0; | |
} | |
else if ( value > 1 ) { | |
value = 1; | |
} | |
this._speed = value; | |
} | |
} | |
public PossiblePath ChoosenPath { get; } | |
public Player( string name, PossiblePath choosenPath ) { | |
this.Name = name; | |
this.HitPoints = RNG.Next( MinimumHitPoints, MaximumHitPoints ); | |
this.Attack = RNG.Next( MinimumAttack, MaximumAttack ); | |
this.ChoosenPath = choosenPath; | |
this.Speed = ( Single )RNG.NextDouble(); //pick a random speed for this player. | |
} | |
/// <summary> | |
/// Don't let a player be created without a name and other parameters | |
/// </summary> | |
private Player() { | |
} | |
public void Display() { | |
Console.WriteLine( "{0} has {1} hp and can attack from {2}-{3} points.", this.Name, this.HitPoints, ( int )( this.Attack * 0.5f ), ( int )( this.Attack * 1.5f ) ); | |
} | |
public Boolean IsAlive() { | |
return this.HitPoints > 0; | |
} | |
public Boolean IsDead() { | |
return this.HitPoints <= 0; | |
} | |
} | |
internal class Kobold : Player { | |
public new const int MinimumHitPoints = 200; //you can redefine different values here using the new keyword. | |
public new const int MaximumHitPoints = 600; | |
public new const int MinimumAttack = 90; | |
public new const int MaximumAttack = 400; | |
public Kobold( String name = "Kobold" ) : base( name: name, choosenPath: PossiblePath.Warrior ) { | |
this.HitPoints = RNG.Next( MinimumHitPoints, MaximumHitPoints ); | |
this.Attack = RNG.Next( MinimumAttack, MaximumAttack ); | |
} | |
} | |
internal class Goblin : Player { | |
public new const int MinimumHitPoints = 300; //you can redefine different values here using the new keyword. | |
public new const int MaximumHitPoints = 700; | |
public new const int MinimumAttack = 110; | |
public new const int MaximumAttack = 600; | |
public Goblin( String name = "Goblin" ) : base( name: name, choosenPath: PossiblePath.Warrior ) { | |
this.HitPoints = RNG.Next( MinimumHitPoints, MaximumHitPoints ); | |
this.Attack = RNG.Next( MinimumAttack, MaximumAttack ); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment