Skip to content

Instantly share code, notes, and snippets.

@AIBrain
Created May 22, 2015 01:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save AIBrain/37fa4ba3a18b5de6cbcb to your computer and use it in GitHub Desktop.
Save AIBrain/37fa4ba3a18b5de6cbcb to your computer and use it in GitHub Desktop.
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