@@ -6,6 +6,7 @@
using Lain.Utils;
using Lain.Geometry;
using RnR.Systems.D20.FloorElements;
using RnR.Systems.D20;

namespace RnR.Consoles
{
@@ -22,6 +23,8 @@ public class DungeonFloorConsole : SadConsole.Consoles.Console
/// <value>The floor.</value>
public DungeonFloor Floor { get; set; }

public Party Party { get; set; }

/// <summary>
/// The width of the view.
/// </summary>
@@ -45,18 +48,18 @@ public class DungeonFloorConsole : SadConsole.Consoles.Console
/// <summary>
/// The center.
/// </summary>
private Point2D center;
//private Point2D center;

/// <summary>
/// Gets or sets the center.
/// </summary>
/// <value>The center.</value>
public Point2D Center {
set {
center = value;
Party.Leader.Position = value;
UpdateMapData (value);
}
get { return center; }
get { return Party.Leader.Position; }
}

/// <summary>
@@ -65,20 +68,21 @@ public class DungeonFloorConsole : SadConsole.Consoles.Console
/// <param name="floor">Floor.</param>
/// <param name="w">The width.</param>
/// <param name="h">The height.</param>
public DungeonFloorConsole (DungeonFloor floor, int w, int h)
public DungeonFloorConsole (DungeonFloor floor, Party party, int w, int h)
: base (Math.Max (floor.Width, w), Math.Max (floor.Height, h))
{
viewWidth = w;
viewHeight = h;
Floor = floor;
Party = party;

drawData = new CellAppearance [w, h];

TextSurface.RenderArea = new Microsoft.Xna.Framework.Rectangle (0, 0, viewWidth, viewHeight);

foreach (RogueSharp.Cell cell in Floor.GetAllCells ()) {
if (cell.IsWalkable) {
center = new Point2D (cell.X, cell.Y);
Party.Leader.Position = new Point2D (cell.X, cell.Y);
break;
}
}
@@ -155,8 +159,8 @@ bool StairIsAtCell (RogueSharp.Cell cell, Stair stair)
/// <param name="cell">Cell.</param>
CellAppearance GetAppearanceFromCell (RogueSharp.Cell cell)
{
if (center.X == cell.X && center.Y == cell.Y)
return CenterAppearance;
if (Center.X == cell.X && Center.Y == cell.Y)
return Party.Leader.Appearance(true);

if (cell.IsExplored) {
if (Floor.UpStair != null && StairIsAtCell (cell, Floor.UpStair))
@@ -230,7 +234,7 @@ bool CellHasWalkableNeighbour (RogueSharp.Cell cell)
public override void Update ()
{
base.Update ();
UpdateMapData (center);
UpdateMapData (Party.Leader.Position);
}
}
}
@@ -9,11 +9,11 @@ namespace RnR.Consoles
/// </summary>
public class GameLogConsole : SadConsole.Consoles.Console
{
private int STARTX = 1;
private int STARTY = 1;
int STARTX = 1;
int STARTY = 1;

private List<string> log;
private int lines;
readonly List<string> log;
readonly int lines;

/// <summary>
/// Initializes a new instance of the <see cref="T:RnR.Consoles.GameLogConsole"/> class.
@@ -33,7 +33,7 @@ public GameLogConsole (List<string> log, int lines, int w, int h)
/// Writes a line.
/// </summary>
/// <param name="s">String.</param>
private void WriteLine(string s)
void WriteLine (string s)
{
VirtualCursor.Print (s);
VirtualCursor.Position = new Point (STARTX, VirtualCursor.Position.Y + 1);
@@ -44,14 +44,14 @@ private void WriteLine(string s)
/// </summary>
public override void Update ()
{
Clear();
VirtualCursor.Position = new Point(STARTX, STARTY);
Clear ();
VirtualCursor.Position = new Point (STARTX, STARTY);

int start = Math.Max(0, log.Count - lines);
int start = Math.Max (0, log.Count - lines);
for (int i = start; i < log.Count; i++) {
WriteLine(log[i]);
WriteLine (log [i]);
}

base.Update ();
}
}
@@ -0,0 +1,42 @@
using System;
using Lain.Utils;
using Microsoft.Xna.Framework;
using RnR.Systems.D20;
using SadConsole;

namespace RnR.Consoles
{
public class LeftCombatStatusConsole : AbstractCombatStatusConsole
{
public LeftCombatStatusConsole (GameCharacter character, int w, int h)
: base (character, w, h)
{
}

protected override void RenderStatus ()
{
Clear ();

VirtualCursor.Position = new Point (4, STARTY);
VirtualCursor.Print (Character.Name);

if (IsSelected)
(new CellAppearance (Color.White, Color.Transparent, 17)).CopyAppearanceTo (this [(int)Math.Floor(Width * 0.6), STARTY]);

// Draw health bar
VirtualCursor.Position = new Point (4, STARTY + 2);
var hitPointsPerc = (int)Math.Floor (((float)Character.HitPoints / (float)Character.MaxHitPoints) * 10.0);

var g = new CellAppearance (Color.Transparent, Color.Green, 0);
var dg = new CellAppearance (Color.Transparent, MaterialColors.Green900, 0);

for (int i = 0; i < hitPointsPerc; i++)
g.CopyAppearanceTo (this [i + 4, STARTY + 2]);
for (int i = hitPointsPerc; i < 10; i++)
dg.CopyAppearanceTo (this [i + 4, STARTY + 2]);

VirtualCursor.Position = new Point (15, STARTY + 2);
VirtualCursor.Print (string.Format ("{0}/{1}", Character.HitPoints, Character.MaxHitPoints));
}
}
}
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Runtime.Serialization;
using Microsoft.Xna.Framework;
using SadConsole;

namespace RnR.Consoles
{
[DataContract]
public class MenuConsole : SadConsole.Consoles.Console
{
[DataMember]
List<MenuItem> items;
const int STARTX = 1;
const int STARTY = 1;

[DataMember]
CellAppearance selectedCellAppearance;

public MenuConsole (List<MenuItem> items, int w, int h)
: base (w, h)
{
this.items = items;

selectedCellAppearance = new CellAppearance (Color.White, Color.Transparent, 16);
}

public override void Render ()
{
base.Render ();

Clear ();

int i = STARTY;
foreach (MenuItem item in items) {
if (item.Selected) {
selectedCellAppearance.CopyAppearanceTo (this [STARTX, i]);
}

VirtualCursor.Position = new Point (STARTX + 2, i);
VirtualCursor.Print (item.Entry);

i += 2;
}
}
}
}
@@ -0,0 +1,17 @@
using System;
namespace RnR.Consoles
{
public class MenuItem
{
public MenuItem (int id, string entry, bool selected)
{
Id = id;
Entry = entry;
Selected = selected;
}

public int Id { get; set; }
public string Entry { get; set; }
public bool Selected { get; set; }
}
}
@@ -0,0 +1,53 @@
using System;
using Lain.Utils;
using Microsoft.Xna.Framework;
using RnR.Systems.D20;
using SadConsole;
using SadConsole.Consoles;

namespace RnR.Consoles
{
public class PartyStatusConsole : SadConsole.Consoles.Console
{
Party party;

public PartyStatusConsole (Party party, int w, int h)
: base (w, h)
{
this.party = party;
}

public override void Render ()
{
base.Render ();

Clear ();

int i = 1;
foreach (GameCharacter c in party) {
VirtualCursor.Position = new Point (1, i);
VirtualCursor.Print (c.Name);

//VirtualCursor.Position = new Point (1, i + 2);

var hitPointsPerc = (int)Math.Floor (c.HitPoints / (float)c.MaxHitPoints * Math.Min(20, (Width - 2)));

var g = new CellAppearance (Color.Transparent, Color.Green, 0);
var dg = new CellAppearance (Color.Transparent, MaterialColors.Green900, 0);

for (int j = 0; j < hitPointsPerc; j++)
g.CopyAppearanceTo (this [j + 1, i + 2]);
for (int j = hitPointsPerc; j < Math.Min (20, (Width - 2)); j++)
dg.CopyAppearanceTo (this [j + 1, i + 2]);

if (c == party.Leader) {
VirtualCursor.Position = new Point (3, i + 4);
VirtualCursor.Print ("Leader");
}

i += 6;
//break;
}
}
}
}
@@ -0,0 +1,46 @@
using System;
using Lain.Utils;
using Microsoft.Xna.Framework;
using RnR.Systems.D20;
using SadConsole;

namespace RnR.Consoles
{
public class RightCombatStatusConsole : AbstractCombatStatusConsole
{
public RightCombatStatusConsole (GameCharacter character, int w, int h)
: base (character, w,h)
{
}

protected override void RenderStatus ()
{
Clear ();
VirtualCursor.Position = new Point (STARTX, STARTY);

// Draw cursor if selected
if (IsSelected)
(new CellAppearance (Color.White, Color.Transparent, 16)).CopyAppearanceTo (
this [VirtualCursor.Position.X, VirtualCursor.Position.Y]);

// Draw name
VirtualCursor.Position = new Point (4, STARTY);
VirtualCursor.Print (Character.Name);

// Draw health bar
VirtualCursor.Position = new Point (4, STARTY + 2);
var hitPointsPerc = (int)Math.Floor (((float)Character.HitPoints / (float)Character.MaxHitPoints) * 10.0);

var g = new CellAppearance (Color.Transparent, Color.Green, 0);
var dg = new CellAppearance (Color.Transparent, MaterialColors.Green900, 0);

for (int i = 0; i < hitPointsPerc; i++)
g.CopyAppearanceTo (this [i + 4, STARTY + 2]);
for (int i = hitPointsPerc; i < 10; i++)
dg.CopyAppearanceTo (this [i + 4, STARTY + 2]);

VirtualCursor.Position = new Point (15, STARTY + 2);
VirtualCursor.Print (string.Format ("{0}/{1}", Character.HitPoints, Character.MaxHitPoints));
}
}
}
@@ -1,16 +1,60 @@
using System;
using System.Collections.Generic;
using RnR.Systems.D20;
using RnR.Systems.D20.Base.Actors;
using RnR.World;
using RnR.World.Generators;

namespace RnR
{
public class GameState
{
#region Singleton
/// <summary>
/// The singleton instance.
/// </summary>
private static GameState instance = null;

/// <summary>
/// Gets the instance.
/// </summary>
/// <value>The instance.</value>
public static GameState Instance {
get {
if (instance == null) instance = new GameState ();
return instance;
}
}
#endregion

public Dungeon Dungeon { get; private set; }
public Party Party { get; private set; }

readonly string [] names = {
"Thomas", "Leonard", "Andre", "Dalton"
};

public GameState ()
{
Dungeon = new Dungeon (new SimpleFloorGenerationStrategy());
Dungeon = new Dungeon (new SimpleFloorGenerationStrategy ());
var cs = new List<GameCharacter> ();
for (int i = 0; i < 4; i++) {
var gc = new GameCharacterBuilder ()
.SetAttribute (Attributes.STR)
.SetAttribute (Attributes.DEX)
.SetAttribute (Attributes.CON)
.SetAttribute (Attributes.INT)
.SetAttribute (Attributes.WIS)
.SetAttribute (Attributes.CHA)
.SetSkill (SkillType.COMBAT)
.SetSkill (SkillType.DETECT_MAGIC)
.SetSkill (SkillType.DODGE_TRAP)
.SetSkill (SkillType.PINLOCK)
.SetName (names [i])
.Build ();
cs.Add (gc);
}
Party = new Party (cs);
}
}
}
@@ -41,6 +41,7 @@
<Folder Include="Systems\D20\Objects\" />
<Folder Include="Systems\D20\Objects\Foods\" />
<Folder Include="Actions\" />
<Folder Include="Systems\D20\Util\" />
</ItemGroup>
<ItemGroup>
<Compile Include="Application.cs" />
@@ -138,9 +139,25 @@
<Compile Include="Actions\MoveAction.cs" />
<Compile Include="Systems\D20\Base\FloorElements\Stepable.cs" />
<Compile Include="Scenes\CombatScene.cs" />
<Compile Include="Consoles\CombatConsole.cs" />
<Compile Include="Systems\D20\Combat.cs" />
<Compile Include="Systems\D20\Party.cs" />
<Compile Include="Systems\D20\Util\PartyMembersIterator.cs" />
<Compile Include="Systems\D20\Util\InitiativeOrderPartyMembersIterator.cs" />
<Compile Include="Consoles\AvailableActionsConsole.cs" />
<Compile Include="Consoles\AbstractCombatStatusConsole.cs" />
<Compile Include="Consoles\RightCombatStatusConsole.cs" />
<Compile Include="Consoles\LeftCombatStatusConsole.cs" />
<Compile Include="Systems\D20\GameCharacterBuilder.cs" />
<Compile Include="Scenes\CombatSceneState.cs" />
<Compile Include="Scenes\AskingForActionState.cs" />
<Compile Include="Scenes\AskingForTargetState.cs" />
<Compile Include="Scenes\DoTurnState.cs" />
<Compile Include="Actions\AttackAction.cs" />
<Compile Include="Scenes\CombatSceneContext.cs" />
<Compile Include="Consoles\PartyStatusConsole.cs" />
<Compile Include="Scenes\MainMenuScene.cs" />
<Compile Include="Consoles\MenuConsole.cs" />
<Compile Include="Consoles\MenuItem.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Microsoft.CSharp" />
@@ -167,6 +184,7 @@
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
</Reference>
<Reference Include="System" />
<Reference Include="System.Runtime.Serialization" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
@@ -0,0 +1,51 @@
using Lain;
using Microsoft.Xna.Framework.Input;
using RnR.Actions;

namespace RnR.Scenes
{
public class AskingForActionState : CombatSceneState
{
bool actionSelected;
IAction selectedAction;

CombatSceneContext context;

public AskingForActionState (CombatSceneContext context)
{
this.context = context;

context.AvailableActions.Clear ();
context.AvailableActions.Add ("(a) Attack");

actionSelected = false;
}

public void HandleInput ()
{
KeyboardState s = Keyboard.GetState ();

if (s.IsKeyDown (Keys.A)) {
actionSelected = true;
selectedAction = new AttackAction (context.Log);
}
}

public void Update ()
{
var gc = context.It.Current;

context.PlayerPartyStatusConsoles.ForEach ((statusConsole) => {
statusConsole.IsSelected = statusConsole.Character == gc;
});

if (actionSelected) {
context.Actions [gc] = selectedAction;
if (selectedAction is AttackAction) {
(selectedAction as AttackAction).Attacker = gc;
}
context.State = new AskingForTargetState (context);
}
}
}
}
@@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using Lain;
using Microsoft.Xna.Framework.Input;
using RnR.Actions;
using RnR.Systems.D20;

namespace RnR.Scenes
{
public class AskingForTargetState : CombatSceneState
{
CombatSceneContext context;
int selectedTargetIdx;

KeyboardState lastKbState;

bool targetSelected;

public AskingForTargetState (CombatSceneContext context)
{
this.context = context;
selectedTargetIdx = 0;

context.AvailableActions.Clear ();
context.AvailableActions.Add ("(Up) Move up");
context.AvailableActions.Add ("(Down) Move down");
context.AvailableActions.Add ("(Enter) Select");

targetSelected = false;
}

public void HandleInput ()
{
KeyboardState ks = Keyboard.GetState ();

if (ks.IsKeyDown (Keys.Down) &&
!lastKbState.IsKeyDown (Keys.Down)) {
// Go down
selectedTargetIdx++;
if (selectedTargetIdx >= context.EnemyPartyStatusConsoles.Count)
selectedTargetIdx = context.EnemyPartyStatusConsoles.Count - 1;
} else if (ks.IsKeyDown (Keys.Up) &&
!lastKbState.IsKeyDown (Keys.Up)) {
// Go up
selectedTargetIdx--;
if (selectedTargetIdx < 0)
selectedTargetIdx = 0;
} else targetSelected |= ks.IsKeyDown (Keys.Enter);

lastKbState = ks;
}

public void Update ()
{
System.Console.WriteLine ("AskingForTargetState::Update");
for (int i = 0; i < context.EnemyPartyStatusConsoles.Count; i++) {
context.EnemyPartyStatusConsoles [i].IsSelected = i == selectedTargetIdx;
}

if (targetSelected) {
for (int i = 0; i < context.EnemyPartyStatusConsoles.Count; i++) {
context.EnemyPartyStatusConsoles [i].IsSelected = false;
}

IAction action = context.Actions [context.It.Current];
if (action is AttackAction) {
(action as AttackAction).Target = context.Combat.EnemyParty.Members [selectedTargetIdx];
}

if (context.It.MoveNext ()) {
context.State = new AskingForActionState (context);
} else {
context.State = new DoTurnState (context);
}
}
}
}

}
@@ -3,46 +3,104 @@
using Lain;
using Lain.Views;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using RnR.Actions;
using RnR.Consoles;
using RnR.Systems.D20;

namespace RnR.Scenes
{
public class CombatScene : Scene
{
List<string> log;
CombatSceneContext context;

GameLogConsole logConsole;
AvailableActionsConsole actionsConsole;

public override void OnCreate ()
{
var combatConsoleWidth = (int)Math.Floor (Configuration.GridWidth * 1.0);
var combatConsoleHeight = (int)Math.Floor (Configuration.GridHeight * 0.8);
var gameLogConsoleWidht = (int)Math.Floor (Configuration.GridWidth * 1.0);
base.OnCreate ();

context = new CombatSceneContext ();

context.Combat = new Combat (GameState.Instance.Party, GameState.Instance.Party);
context.Actions = new Dictionary<GameCharacter, IAction> ();

var gameLogConsoleWidth = (int)Math.Floor (Configuration.GridWidth * 1.0);
var gameLogConsoleHeight = (int)Math.Floor (Configuration.GridHeight * 0.2);
var statusConsoleWidth = (int)Math.Floor (Configuration.GridWidth * 0.5);
var statusConsoleHeight = (int)Math.Floor ((Configuration.GridHeight - gameLogConsoleHeight - 3) / 4.0);

log = new List<string> ();
context.Log = new List<string> ();
context.PlayerPartyStatusConsoles = new List<AbstractCombatStatusConsole> ();
context.EnemyPartyStatusConsoles = new List<AbstractCombatStatusConsole> ();

logConsole = new GameLogConsole(log, Math.Min (gameLogConsoleHeight - 2, 11), gameLogConsoleWidht, gameLogConsoleHeight);
logConsole = new GameLogConsole (context.Log, Math.Min (gameLogConsoleHeight - 2, 11), gameLogConsoleWidth, gameLogConsoleHeight);
logConsole.Position = new Point (0, (int)Math.Floor (Configuration.GridHeight * 0.8) + 1);
Add (logConsole);

int i = 0;
foreach (GameCharacter c in context.Combat.PlayerParty) {

AbstractCombatStatusConsole status = new RightCombatStatusConsole (c, statusConsoleWidth, statusConsoleHeight);
status.Position = new Point (statusConsoleWidth, i);
i += statusConsoleHeight;

context.PlayerPartyStatusConsoles.Add (status);
Add (status);
}

i = 0;
foreach (GameCharacter c in context.Combat.EnemyParty) {
AbstractCombatStatusConsole status = new LeftCombatStatusConsole (c, statusConsoleWidth, statusConsoleHeight);
status.Position = new Point (0, i);
i += statusConsoleHeight;

context.EnemyPartyStatusConsoles.Add (status);
Add (status);
}

actionsConsole = new AvailableActionsConsole (gameLogConsoleWidth);
context.AvailableActions = new List<string> ();
actionsConsole.availableActions = context.AvailableActions;
actionsConsole.Position = new Point (0, statusConsoleHeight * 4);
Add (actionsConsole);

context.It = context.Combat.PlayerParty.GetEnumerator ();
context.It.MoveNext ();
context.State = new AskingForActionState (context);

SetBackground (new Color (new Vector3 (0x12, 0x13, 0x14)));
}

public override void OnDestroy ()
{
base.OnDestroy ();
}

public override void OnPause ()
{
base.OnPause ();
}

public override void OnResume ()
{
base.OnResume ();
}

public override void Update (GameTime delta)
{
KeyboardState state = Keyboard.GetState ();
IAction action = new FalseAction ();

if (state.IsKeyDown (Keys.Escape)) {
(new ExitAction (0)).Execute();
}

base.Update (delta);

context.State.HandleInput ();
context.State.Update ();
}
}
}
@@ -0,0 +1,25 @@
using System;
using System.Collections.Generic;
using Lain;
using RnR.Consoles;
using RnR.Systems.D20;

namespace RnR.Scenes
{
public class CombatSceneContext
{
public List<string> Log { get; set; }
public List<string> AvailableActions { get; set; }

public Combat Combat { get; set; }

public CombatSceneState State { get; set; }

public IEnumerator<GameCharacter> It { get; set; }

public List<AbstractCombatStatusConsole> EnemyPartyStatusConsoles { get; set; }
public List<AbstractCombatStatusConsole> PlayerPartyStatusConsoles { get; set; }

public Dictionary<GameCharacter, IAction> Actions { get; set; }
}
}
@@ -0,0 +1,9 @@
using System;
namespace RnR.Scenes
{
public interface CombatSceneState
{
void HandleInput ();
void Update ();
}
}
@@ -0,0 +1,27 @@
using System;
namespace RnR.Scenes
{
public class DoTurnState : CombatSceneState
{
CombatSceneContext context;

public DoTurnState (CombatSceneContext context)
{
this.context = context;
}

public void HandleInput ()
{
/* Do nothing */
}

public void Update ()
{
context.Combat.DoTurn (context.Actions);
context.Actions.Clear ();
context.It.Reset ();
context.It.MoveNext ();
context.State = new AskingForActionState (context);
}
}
}
@@ -18,6 +18,7 @@ public class MainGameScene : Scene

DungeonFloorConsole dungeonFloorConsole;
GameLogConsole gameLogConsole;
PartyStatusConsole statusConsole;

#endregion

@@ -37,24 +38,32 @@ public class MainGameScene : Scene
/// </summary>
public override void OnCreate ()
{
int dungeonConsoleWidth = (int)Math.Floor (Configuration.GridWidth * 0.8);
int dungeonConsoleHeight = (int)Math.Floor (Configuration.GridHeight * 0.8);
int gameLogConsoleWidht = dungeonConsoleWidth;
int gameLogConsoleHeight = (int)Math.Floor (Configuration.GridHeight * 0.2);
base.OnCreate ();

gameState = new GameState ();
var dungeonConsoleWidth = (int)Math.Floor (Configuration.GridWidth * 0.8);
var dungeonConsoleHeight = (int)Math.Floor (Configuration.GridHeight * 0.8);
var gameLogConsoleWidht = dungeonConsoleWidth;
var gameLogConsoleHeight = (int)Math.Floor (Configuration.GridHeight * 0.2);
var statusConsoleWidth = (int)Math.Floor (Configuration.GridWidth * 0.2);
var statusConsoleHeight = (int)Math.Floor (Configuration.GridHeight * 1.0);

gameState = GameState.Instance;
log = new List<string> ();
(new LogCurrentFloor (gameState, log)).Execute ();

dungeonFloorConsole = new DungeonFloorConsole (gameState.Dungeon.CurrentFloor, dungeonConsoleWidth, dungeonConsoleHeight);
dungeonFloorConsole = new DungeonFloorConsole (gameState.Dungeon.CurrentFloor, gameState.Party, dungeonConsoleWidth, dungeonConsoleHeight);
gameLogConsole = new GameLogConsole (log, Math.Min (gameLogConsoleHeight - 2, 11), gameLogConsoleWidht, gameLogConsoleHeight);
gameLogConsole.Position = new Point (0, dungeonConsoleHeight + 1);
statusConsole = new PartyStatusConsole (gameState.Party, statusConsoleWidth, statusConsoleHeight);
statusConsole.Position = new Point (dungeonConsoleWidth + 1, 0);

Add (dungeonFloorConsole);
Add (gameLogConsole);
Add (statusConsole);

SetBackground (new Color (new Vector3 (0x12, 0x13, 0x14)));

gameState.Dungeon.Update (dungeonFloorConsole.Center);
gameState.Dungeon.Update (gameState.Party, log);
dungeonFloorConsole.Update ();
}

@@ -63,20 +72,23 @@ public override void OnCreate ()
/// </summary>
public override void OnPause ()
{
base.OnPause ();
}

/// <summary>
/// Called when the scene is resumed.
/// </summary>
public override void OnResume ()
{
base.OnResume ();
}

/// <summary>
/// Called when the scene is destroyed.
/// </summary>
public override void OnDestroy ()
{
base.OnDestroy ();
}

/// <summary>
@@ -89,7 +101,9 @@ private IAction HandleInput ()
IAction action = new FalseAction ();

if (state.IsKeyDown (Keys.Escape)) {
return new ExitAction (0);
//return new ExitAction (0);
Director.Instance.PopScene ();
return action;
}

if (delay == 0) {
@@ -116,16 +130,16 @@ private IAction HandleInput ()
/// <param name="delta">Delta.</param>
public override void Update (GameTime delta)
{
base.Update (delta);

KeyboardState state = Keyboard.GetState ();
IAction action = HandleInput ();

if (action.Execute () && action is MoveAction)
(new AndChain (new TryUseStairs (gameState, dungeonFloorConsole),
new LogCurrentFloor (gameState, log))).Execute ();

gameState.Dungeon.Update (dungeonFloorConsole.Center);

base.Update (delta);
gameState.Dungeon.Update (gameState.Party, log);
}
}
}
@@ -0,0 +1,97 @@
using System;
using System.Collections.Generic;
using Lain;
using Lain.Views;
using Microsoft.Xna.Framework.Input;
using RnR.Actions;
using RnR.Consoles;

namespace RnR.Scenes
{
public class MainMenuScene : Scene
{
MenuConsole mainMenuConsole;

int selectedItemIdx;
bool itemSelected;
KeyboardState lastKbState;
List<MenuItem> menuItems;

public override void OnCreate ()
{
base.OnCreate ();
menuItems = new List<MenuItem>(new MenuItem [] {
new MenuItem(0, "New game", true),
new MenuItem(1, "Exit", false)
});

mainMenuConsole = new MenuConsole (menuItems, Configuration.GridWidth, Configuration.GridHeight);
Add (mainMenuConsole);

selectedItemIdx = 0;
}

public override void OnDestroy ()
{
base.OnDestroy ();
}

public override void OnPause ()
{
base.OnPause ();
}

public override void OnResume ()
{
base.OnResume ();
}

public void HandleInput ()
{
KeyboardState ks = Keyboard.GetState ();

if (ks.IsKeyDown (Keys.Down) &&
!lastKbState.IsKeyDown (Keys.Down)) {
// Go down
selectedItemIdx++;
if (selectedItemIdx >= menuItems.Count)
selectedItemIdx = menuItems.Count - 1;
} else if (ks.IsKeyDown (Keys.Up) &&
!lastKbState.IsKeyDown (Keys.Up)) {
// Go up
selectedItemIdx--;
if (selectedItemIdx < 0)
selectedItemIdx = 0;
} else itemSelected |= ks.IsKeyDown (Keys.Enter);

lastKbState = ks;
}

public override void Update (Microsoft.Xna.Framework.GameTime delta)
{
base.Update (delta);

HandleInput ();

for (int i = 0; i < menuItems.Count; i++)
menuItems [i].Selected = i == selectedItemIdx;

if (itemSelected) {
switch (selectedItemIdx) {
case 0:
LoadNewGame ();
break;
case 1:
(new ExitAction (0)).Execute ();
break;
}
}
}

void LoadNewGame ()
{
itemSelected = false;
Director.Instance.PushScene (new MainGameScene ());
}
}
}
@@ -4,15 +4,14 @@

namespace RnR.Systems.D20.Base.Actors
{
public abstract class GameActor : IGameActor
public class GameActor : IGameActor
{
#region Class attributes

protected readonly string name;
protected int money;
protected int hitPoints;
protected int maxHitPoints;
protected Dictionary<SkillType, Skill> skills;
public Dictionary<SkillType, Skill> Skills { get; private set; }
protected int hunger;

protected Attribute _STR, _DEX, _CON, _INT, _WIS, _CHA;
@@ -27,12 +26,14 @@ public abstract class GameActor : IGameActor

public GameActor ()
{
skills = new Dictionary<SkillType, Skill> ();
Skills = new Dictionary<SkillType, Skill> ();
equipedRing = null;
equipedArmor = null;
equipedWeapon = null;
equipedEarring = null;
equipedNecklace = null;


}

/// <summary>
@@ -52,6 +53,9 @@ public GameActor (int str, int dex, int con, int _int, int wis, int cha) : this(
_INT = new Attribute (_int, Attributes.INT);
_WIS = new Attribute (wis, Attributes.WIS);
_CHA = new Attribute (cha, Attributes.CHA);

hitPoints = MaxHitPoints;
hunger = MaxHunger;
}

#region Getter & Setters
@@ -71,7 +75,7 @@ public GameActor (int str, int dex, int con, int _int, int wis, int cha) : this(
hitPoints = Math.Max (0, Math.Min (value, MaxHitPoints));
}
}
public int MaxHitPoints { get { return maxHitPoints; } }
public int MaxHitPoints { get { return CON ().Value + CON ().Mod; } }


public AbstractWeapon EquipedWeapon {
@@ -145,7 +149,7 @@ public bool IsDead

public Skill GetSkill (SkillType type)
{
if (skills.ContainsKey (type)) return skills [type];
if (Skills.ContainsKey (type)) return Skills [type];
throw new CantParticipateInContestException (this);
}

@@ -161,7 +165,7 @@ public int GetChallengeRate ()

public SkillType GetSkillType ()
{
throw new NotImplementedException ();
return SkillType.COMBAT;
}

public void ContestFinished (Challenger challenger, bool challengerWon)
@@ -171,7 +175,7 @@ public void ContestFinished (Challenger challenger, bool challengerWon)

public bool CanParticipate (Challenger challenger)
{
throw new NotImplementedException ();
return true;
}

public int CA
@@ -5,8 +5,8 @@ namespace RnR.Systems.D20.Base.FloorElements
{
public abstract class AbstractDamageTrap : AbstractTrap
{
int dices;
int damage;
protected int dices;
protected int damage;

public AbstractDamageTrap (SkillType skill, int dices, int damage, int rate) : base (skill, rate)
{
@@ -14,25 +14,26 @@ public AbstractGrass ()
picked = false;
}

public IGameActor OnStep (IGameActor target)
public string OnStep (Party target)
{
if (!picked && target is GameCharacter) {
ApplyAction (target);
if (!picked) {
picked = true;
return ApplyAction (target);
}
return target;

return null;
}

protected abstract void ApplyAction (IGameActor target);
protected abstract string ApplyAction (Party target);

#region implemented abstract members of AbstractFloorElement

public override SadConsole.CellAppearance Appearance (bool inFov)
public override CellAppearance Appearance (bool inFov)
{
if (inFov)
return new CellAppearance (Color.Green, Color.Transparent, 34);
else
return new CellAppearance (Color.DarkGreen, Color.Transparent, 34);
int glyph = picked ? 96 : 34;
if (inFov)
return new CellAppearance (Color.Green, Color.Transparent, glyph);
return new CellAppearance (Color.DarkGreen, Color.Transparent, glyph);
}

#endregion
@@ -9,7 +9,7 @@ public abstract class AbstractTrap : AbstractFloorElement, Stepable, Challenge
private int challengeRate;
private bool applied;
private SkillType skill;
private IGameActor victim;
private Actors.IGameActor victim;

public AbstractTrap (SkillType skill, int challengeRate)
{
@@ -29,33 +29,33 @@ public void Disarm ()
armed = false;
}

public IGameActor OnStep (IGameActor target)
public string OnStep (Party target)
{
if (armed) {
Contest contest = new Contest (this, target);
var contest = new Contest (this, target.Leader);
contest.Resolve ();
Disarm ();
if (applied) {
return victim;
}
return resultMsg;
}
return target;
return null;
}

string resultMsg;

public bool Armed { get { return armed; } }

public void ContestFinished (Challenger challenger, bool challengerWon)
{
IGameActor aga = (IGameActor)challenger;
if (!challengerWon) {
victim = ApplyEffect (aga);
applied = true;
resultMsg = ApplyEffect (challenger as GameCharacter);
} else {
resultMsg = "You find a trap before it can harm you.";
}
}

public bool CanParticipate (Challenger challenger)
{
return challenger is IGameActor;
return challenger is GameCharacter;
}

public int GetChallengeRate () { return challengeRate; }
@@ -64,6 +64,6 @@ public SkillType GetSkillType ()
return skill;
}

protected abstract IGameActor ApplyEffect (IGameActor target);
protected abstract string ApplyEffect (GameCharacter target);
}
}
@@ -5,6 +5,6 @@ namespace RnR.Systems.D20.Base.FloorElements
{
public interface Stepable
{
IGameActor OnStep (IGameActor target);
string OnStep (Party target);
}
}
@@ -31,7 +31,7 @@ public int MaxDex

}

public IGameActor OnEquip (IGameActor target)
public IGameActor OnEquip (Actors.IGameActor target)
{
target.EquipedArmor = this;
return target;
@@ -12,7 +12,7 @@ public AbstractEarring(string name, string description, int weight, int price, G
{
}

public override IGameActor OnEquip (IGameActor target)
public override IGameActor OnEquip (Actors.IGameActor target)
{
// Remove previously equiped earring effect
if (target.EquipedEarring != null) {
@@ -13,7 +13,7 @@ public AbstractFood(string name, string description, int weight, int price, int
energyGain = eneryGain;
}

public IGameActor OnEat (IGameActor target)
public IGameActor OnEat (Actors.IGameActor target)
{
if (target is GameCharacter){
(target as GameCharacter).Hunger += energyGain;
@@ -17,7 +17,7 @@ public GameActorDecorator Effect
}
}

public abstract IGameActor OnEquip (IGameActor target);
public abstract IGameActor OnEquip (Actors.IGameActor target);

public AbstractJewel(string name, string description, int weight, int price, GameActorDecorator effect)
: base(name, description, weight, price)
@@ -12,7 +12,7 @@ public abstract class AbstractNecklace : AbstractJewel
{
}

public override IGameActor OnEquip (IGameActor target)
public override IGameActor OnEquip (Actors.IGameActor target)
{
// Remove previously equiped earring effect
if (target.EquipedNecklace != null) {
@@ -14,7 +14,7 @@ public AbstractPotion(string name, string description, int weight, int price, Ga
this.effect = effect;
}

public IGameActor OnEat (IGameActor target)
public IGameActor OnEat (Actors.IGameActor target)
{
effect.Target = target;
return effect;
@@ -12,7 +12,7 @@ public AbstractRing(string name, string description, int weight, int price, Game
{
}

public override IGameActor OnEquip (IGameActor target)
public override IGameActor OnEquip (Actors.IGameActor target)
{
// Remove previously equiped earring effect
if (target.EquipedRing != null) {
@@ -23,7 +23,7 @@ public AbstractTrapSetup(string name, string description, int weight, int price,
this.trap = trap;
}

public IGameActor OnUse (IGameActor target)
public Party OnUse (Actors.IGameActor target)
{
throw new NotImplementedException ();
}
@@ -53,7 +53,7 @@ public int CriticMultiplier
}
}

public virtual IGameActor OnEquip (IGameActor target)
public virtual IGameActor OnEquip (Actors.IGameActor target)
{
target.EquipedWeapon = this;
return target;
@@ -6,6 +6,6 @@ namespace RnR.Systems.D20.Base.Objects
{
public interface EdibleObject
{
IGameActor OnEat(IGameActor target);
IGameActor OnEat(Actors.IGameActor target);
}
}
@@ -6,6 +6,6 @@ namespace RnR.Systems.D20.Base.Objects
{
public interface EquipableObject
{
IGameActor OnEquip(IGameActor target);
IGameActor OnEquip(Actors.IGameActor target);
}
}
@@ -6,6 +6,6 @@ namespace RnR.Systems.D20.Base.Objects
{
public interface UsableObject
{
IGameActor OnUse(IGameActor target);
Party OnUse(Actors.IGameActor target);
}
}
@@ -1,15 +1,45 @@
using System;
using System.Collections;
using System.Collections.Generic;
using Lain;
using RnR.Systems.D20.Util;

namespace RnR.Systems.D20
{
public class Combat
public class Combat : IEnumerable<GameCharacter>
{
public Party PlayerParty { get; private set; }
public Party EnemyParty { get; private set; }

readonly InitiativeOrderPartyMembersIterator turnOrderIterator;

public Combat (Party playerParty, Party enemyParty)
{
PlayerParty = playerParty;
EnemyParty = enemyParty;

turnOrderIterator =
new InitiativeOrderPartyMembersIterator (playerParty.Members ?? new List<GameCharacter>())
.AddCharacters (enemyParty.Members ?? new List<GameCharacter>());
}

public void DoTurn (Dictionary<GameCharacter, IAction> actions)
{
foreach (var character in this) {
if (actions.ContainsKey (character)) {
actions [character].Execute ();
}
}
}

public IEnumerator<GameCharacter> GetEnumerator ()
{
return turnOrderIterator;
}

IEnumerator IEnumerable.GetEnumerator ()
{
return turnOrderIterator;
}
}
}
@@ -5,7 +5,7 @@ namespace RnR.Systems.D20.Effects
{
public class PoisonEffect : GameActorDecorator
{
public PoisonEffect (IGameActor target)
public PoisonEffect (Base.Actors.IGameActor target)
: base(target)
{
}
@@ -5,7 +5,7 @@ namespace RnR.Systems.D20.Effects
{
public class StuntEffect : GameActorDecorator
{
public StuntEffect (IGameActor target)
public StuntEffect (Base.Actors.IGameActor target)
: base(target)
{
}
@@ -15,28 +15,25 @@ public ExhaustionTrap (int dices, int damage, int rate)
{
}

protected override IGameActor ApplyEffect (IGameActor target)
protected override string ApplyEffect (GameCharacter target)
{
if (target is GameCharacter) {
var player = (GameCharacter)target;
player.Hunger -= CalculateDamage();
}
return target;
var dmg = CalculateDamage ();
target.Hunger -= dmg;
return $"The famine invades you and you gain {dmg} ({dices}d{damage}) point of hunger";
}

#region implemented abstract members of AbstractFloorElement

public override SadConsole.CellAppearance Appearance (bool inFov)
public override CellAppearance Appearance (bool inFov)
{
if (inFov) {
if (this.Armed)
if (Armed)
return new FloorInFovAppearance ();
return new CellAppearance (Color.YellowGreen, Color.Transparent, 116);
} else {
if (this.Armed)
return new FloorAppearance ();
return new CellAppearance (Color.YellowGreen, Color.Transparent, 116);
}
if (Armed)
return new FloorAppearance ();
return new CellAppearance (Color.YellowGreen, Color.Transparent, 116);
}

#endregion
@@ -13,9 +13,10 @@ public FoodGrass (AbstractFood food)
this.food = food;
}

protected override void ApplyAction (IGameActor target)
protected override string ApplyAction (Party target)
{
//target.Inventory.Add (food);
target.Inventory.Add (food);
return $"Found: {food.Name}";
}
}
}
@@ -8,22 +8,41 @@ namespace RnR.Systems.D20.FloorElements
{
public class Fountain : AbstractFloorElement, Stepable
{
public IGameActor OnStep (IGameActor target)
bool exhausted;

public Fountain ()
{
exhausted = false;
}

public string OnStep (Party target)
{
if (target is GameCharacter) {
/*if (target is GameCharacter) {
target.HitPoints = target.MaxHitPoints;
}
return target;
return target;*/
if (!exhausted) {
foreach (GameCharacter c in target) {
c.HitPoints = c.MaxHitPoints;
}
exhausted = true;
return "Your party recovers all its health";
}
return null;
}

#region implemented abstract members of AbstractFloorElement

public override SadConsole.CellAppearance Appearance (bool inFov)
{
if (inFov) {
if (exhausted) {
if (inFov)
return new CellAppearance (Color.Beige, Color.Transparent, 102);
return new CellAppearance (Color.Brown, Color.Transparent, 102);
}
if (inFov)
return new CellAppearance (Color.CornflowerBlue, Color.Transparent, 102);
} else
return new CellAppearance (Color.DarkBlue, Color.Transparent, 102);
return new CellAppearance (Color.DarkBlue, Color.Transparent, 102);
}

#endregion
@@ -13,9 +13,10 @@ public MoneyGrass (int amount)
this.amount = amount;
}

protected override void ApplyAction (IGameActor target)
protected override string ApplyAction (Party target)
{
target.Money += amount;
target.Leader.Money += amount;
return $"Found {amount} pieces of gold";
}
}
}
@@ -15,10 +15,10 @@ public PoisonTrap (int rate)
{
}

protected override IGameActor ApplyEffect (IGameActor target)
protected override string ApplyEffect (GameCharacter target)
{
Effect.Target = target;
return Effect;
target.AddEffect (Effect);
return "You have been poisoned";
}

#region implemented abstract members of AbstractFloorElement
@@ -13,14 +13,23 @@ public class RandomFloorElementFactory : FloorElementFactory

Random r;

ChestFactory chestFactory;
RandomTrapFactory randomTrapFactory;
RandomGrassFactory randomGrassFactory;
FountainFactory fountainFactory;

public RandomFloorElementFactory ()
{
r = new Random ();
chestFactory = null;
randomTrapFactory = null;
randomGrassFactory = null;
fountainFactory = null;
}

#region FloorElementFactory implementation

public RnR.Systems.D20.Base.FloorElements.AbstractFloorElement CreateFloorElement ()
public AbstractFloorElement CreateFloorElement ()
{
FloorElementFactory realFactory;

@@ -30,14 +39,23 @@ public RnR.Systems.D20.Base.FloorElements.AbstractFloorElement CreateFloorElemen

double random = r.NextDouble ();

if (random < accChestProb)
realFactory = new ChestFactory ();
else if (random < accTrapProb)
realFactory = new RandomTrapFactory ();
else if (random < accGrassProb)
realFactory = new RandomGrassFactory ();
else
realFactory = new FountainFactory ();
if (random < accChestProb) {
if (chestFactory == null)
chestFactory = new ChestFactory ();
realFactory = chestFactory;
} else if (random < accTrapProb) {
if (randomTrapFactory == null)
randomTrapFactory = new RandomTrapFactory ();
realFactory = randomTrapFactory;
} else if (random < accGrassProb) {
if (randomGrassFactory == null)
randomGrassFactory = new RandomGrassFactory ();
realFactory = randomGrassFactory;
} else {
if (fountainFactory == null)
fountainFactory = new FountainFactory ();
realFactory = fountainFactory;
}

return realFactory.CreateFloorElement ();
}
@@ -18,7 +18,7 @@ public RandomGrassFactory ()

#region FloorElementFactory implementation

public RnR.Systems.D20.Base.FloorElements.AbstractFloorElement CreateFloorElement ()
public AbstractFloorElement CreateFloorElement ()
{
AbstractGrass newGrass = null;

@@ -15,25 +15,25 @@ public SpikeTrap (int dices, int damage, int rate)
{
}

protected override IGameActor ApplyEffect (IGameActor target)
protected override string ApplyEffect (GameCharacter target)
{
target.HitPoints -= CalculateDamage();
return target;
var dmg = CalculateDamage ();
target.HitPoints -= dmg;
return $"The spikes hurt you. You receive {dmg} ({dices}d{damage}) point of damage";
}

#region implemented abstract members of AbstractFloorElement

public override SadConsole.CellAppearance Appearance (bool inFov)
public override CellAppearance Appearance (bool inFov)
{
if (inFov) {
if (this.Armed)
if (Armed)
return new FloorInFovAppearance ();
return new CellAppearance (Color.Red, Color.Transparent, 116);
} else {
if (this.Armed)
return new FloorAppearance ();
return new CellAppearance (Color.Red, Color.Transparent, 116);
}
if (Armed)
return new FloorAppearance ();
return new CellAppearance (Color.Red, Color.Transparent, 116);
}

#endregion
@@ -6,7 +6,7 @@

namespace RnR.Systems.D20.FloorElements
{
public class Stair : Stepable, Drawable, Positionable
public class Stair : Drawable, Positionable
{
public StairDirection Direction { get; private set; }

@@ -15,25 +15,24 @@ public StuntTrap (int rate)
{
}

protected override IGameActor ApplyEffect (IGameActor target)
protected override string ApplyEffect (GameCharacter target)
{
Effect.Target = target;
return Effect;
target.AddEffect (Effect);
return "You have been stunned by some magic";
}

#region implemented abstract members of AbstractFloorElement

public override SadConsole.CellAppearance Appearance (bool inFov)
public override CellAppearance Appearance (bool inFov)
{
if (inFov) {
if (this.Armed)
if (Armed)
return new FloorInFovAppearance ();
return new CellAppearance (Color.LightBlue, Color.Transparent, 116);
} else {
if (this.Armed)
return new FloorAppearance ();
return new CellAppearance (Color.LightBlue, Color.Transparent, 116);
}
if (Armed)
return new FloorAppearance ();
return new CellAppearance (Color.LightBlue, Color.Transparent, 116);
}

#endregion
@@ -1,173 +1,162 @@
using System;
using Lain;
using Lain.Geometry;
using Lain.Utils;
using Microsoft.Xna.Framework;
using RnR.Systems.D20.Base.Actors;
using RnR.Systems.D20.Base.Objects;
using SadConsole;

namespace RnR.Systems.D20
{
// XXX: Put here delegation instead of inheritance?
public class GameCharacter : IGameActor
public class GameCharacter : IGameActor, Positionable, Drawable
{
private IGameActor innerActor;
IGameActor innerActor;
Point2D position;
Color color;

public GameCharacter(GameActor gameActor)
public GameCharacter (string name, GameActor gameActor)
{
this.innerActor = gameActor;
Name = name;
innerActor = gameActor;
color = MaterialColors.RandomMaterialColor ();
}

public string Name { get; private set; }

public AbstractArmor EquipedArmor
{
get
{
public AbstractArmor EquipedArmor {
get {
return innerActor.EquipedArmor;
}

set
{
set {
innerActor.EquipedArmor = value;
}
}

public AbstractEarring EquipedEarring
{
get
{
public AbstractEarring EquipedEarring {
get {
return innerActor.EquipedEarring;
}

set
{
set {
innerActor.EquipedEarring = value;
}
}

public AbstractNecklace EquipedNecklace
{
get
{
public AbstractNecklace EquipedNecklace {
get {
return innerActor.EquipedNecklace;
}

set
{
set {
innerActor.EquipedNecklace = value;
}
}

public AbstractRing EquipedRing
{
get
{
public AbstractRing EquipedRing {
get {
return innerActor.EquipedRing;
}

set
{
set {
innerActor.EquipedRing = value;
}
}

public AbstractWeapon EquipedWeapon
{
get
{
public AbstractWeapon EquipedWeapon {
get {
return innerActor.EquipedWeapon;
}

set
{
set {
innerActor.EquipedWeapon = value;
}
}

public int HitPoints
{
get
{
public int HitPoints {
get {
return innerActor.HitPoints;
}

set
{
set {
innerActor.HitPoints = value;
}
}

public int MaxHunger
{
get
{
return innerActor.MaxHunger;
public int MaxHunger {
get {
return innerActor.MaxHunger;
}
}

public int Hunger
{
get
{
public int Hunger {
get {
return innerActor.Hunger;
}

set
{
set {
innerActor.Hunger = value;
}
}

public int MaxHitPoints
{
get
{
public int MaxHitPoints {
get {
return innerActor.MaxHitPoints;
}
}

public int Money
{
get
{
public int Money {
get {
return innerActor.Money;
}

set
{
set {
innerActor.Money = value;
}
}

public bool IsDead
{
get
{
public bool IsDead {
get {
return innerActor.IsDead;
}
}

public int CA {
get
{
get {
return innerActor.CA;
}
}

public Point2D Position {
get {
return position;
}

set {
position = value;
}
}

public bool CanParticipate (Challenger challenger)
{
return innerActor.CanParticipate (challenger);
}

public Base.Actors.Attribute CHA ()
{
return innerActor.CHA();
return innerActor.CHA ();
}

public Base.Actors.Attribute CON ()
{
return innerActor.CON();
return innerActor.CON ();
}

public void ContestFinished (Challenger challenger, bool challengerWon)
{
innerActor.ContestFinished(challenger, challengerWon);
innerActor.ContestFinished (challenger, challengerWon);
}

public Base.Actors.Attribute DEX ()
@@ -177,12 +166,12 @@ public Base.Actors.Attribute DEX ()

public GameActor Equip (EquipableObject obj)
{
return this.Equip(obj); // CHECK
return this.Equip (obj); // CHECK
}

public int GetChallengeRate ()
{
return innerActor.GetChallengeRate();
return innerActor.GetChallengeRate ();
}

public SkillType GetSkillType ()
@@ -192,7 +181,7 @@ public SkillType GetSkillType ()

public Skill GetSkill (SkillType type)
{
return innerActor.GetSkill(type);
return innerActor.GetSkill (type);
}

public Base.Actors.Attribute INT ()
@@ -225,8 +214,11 @@ public void AddEffect (GameActorDecorator effect)
public void RemoveEffect (GameActorDecorator effect)
{
GameActorDecorator.Remove (innerActor, effect);

}

public CellAppearance Appearance (bool inFov)
{
return new CellAppearance (color, Color.Transparent, Name [0]);
}
}
}
@@ -0,0 +1,96 @@
using System.Collections.Generic;
using RnR.Systems.D20.Base.Actors;
using RnR.Systems.Dice;

namespace RnR.Systems.D20
{
public class GameCharacterBuilder
{
Attribute _STR, _DEX, _CON, _INT, _WIS, _CHA;
Dictionary<SkillType, Skill> skills;
string name;

public GameCharacterBuilder ()
{
skills = new Dictionary<SkillType, Skill> ();
}

public GameCharacterBuilder SetAttribute (Attributes attr)
{
DiceRoll attrRoll = Dice.Dice.Roll (4, 6);
attrRoll.DiscardLower ();
var a = new Attribute (attrRoll.Sum, attr);

switch (attr) {
case Attributes.CHA:
_CHA = a;
break;
case Attributes.CON:
_CON = a;
break;
case Attributes.DEX:
_DEX = a;
break;
case Attributes.INT:
_INT = a;
break;
case Attributes.STR:
_STR = a;
break;
case Attributes.WIS:
_WIS = a;
break;
}

return this;
}

public GameCharacterBuilder SetSkill (SkillType type)
{
var val = Dice.Dice.Roll (1, 6).Sum;

switch (type) {
case SkillType.COMBAT:
skills.Add (type, new Skill (type, "Combat", val, _STR));
break;
case SkillType.DETECT_MAGIC:
skills.Add (type, new Skill (type, "Detect magic", val, _INT));
break;
case SkillType.DODGE_TRAP:
skills.Add (type, new Skill (type, "Dodge traps", val, _DEX));
break;
case SkillType.PINLOCK:
skills.Add (type, new Skill (type, "Pinlock", val, _WIS));
break;
}

return this;
}

public GameCharacterBuilder SetName (string name)
{
this.name = name;

return this;
}

public GameCharacter Build ()
{
var ga = new GameActor (_STR.Value,
_DEX.Value,
_CON.Value,
_INT.Value,
_WIS.Value,
_CHA.Value);

var gc = new GameCharacter (name,
ga);

foreach (var skill in skills) {
ga.Skills.Add (skill.Key, skill.Value);
}

return gc;
}
}
}
@@ -1,12 +1,16 @@
using System;
using System.Collections;
using System.Collections.Generic;
using RnR.Systems.D20.Base.Objects;

namespace RnR.Systems.D20
{
public class Party
public class Party : IEnumerable<GameCharacter>
{
int leaderPos;

public List<GameObject> Inventory { get; private set; }

public Party ()
: this (new List<GameCharacter>())
{
@@ -15,6 +19,7 @@ public Party ()
public Party (List<GameCharacter> members)
{
Members = members;
Inventory = new List<GameObject> ();
leaderPos = 0;
}

@@ -29,5 +34,15 @@ public Party (List<GameCharacter> members)
}

public List<GameCharacter> Members { get; private set; }

public IEnumerator<GameCharacter> GetEnumerator ()
{
return Members.GetEnumerator ();
}

IEnumerator IEnumerable.GetEnumerator ()
{
return Members.GetEnumerator ();
}
}
}
@@ -0,0 +1,112 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace RnR.Systems.D20.Util
{
public class InitiativeOrderPartyMembersIterator : IEnumerator<GameCharacter>
{
struct MemberWrapper
{
GameCharacter character;
int rolledInitiative;

public GameCharacter Character {
get {
return character;
}

set {
character = value;
}
}

public int RolledInitiative {
get {
return rolledInitiative;
}

set {
rolledInitiative = value;
}
}
}

private class InitiativeComparer<K> : IComparer<K> where K : IComparable
{
public int Compare (K x, K y)
{
int result = x.CompareTo (y);
if (result == 0)
return 1;
else
return result;
}
}

SortedList<int, GameCharacter> membersByInitiative;

public InitiativeOrderPartyMembersIterator (List<GameCharacter> members)
{
membersByInitiative = new SortedList<int, GameCharacter> (new InitiativeComparer<int>());
AddCharacters (members);
}

public InitiativeOrderPartyMembersIterator AddCharacters (List<GameCharacter> characters)
{
characters.ConvertAll ((character) => {
var mw = new MemberWrapper ();
mw.Character = character;
mw.RolledInitiative = Dice.Dice.Roll (1, 20).Sum + character.DEX ().Mod;
return mw;
}).ForEach ((mw) => {
membersByInitiative.Add (mw.RolledInitiative, mw.Character);
});

return this;
}

bool loaded;
IEnumerator<KeyValuePair<int, GameCharacter>> e;

void LazyLoadEnumerator ()
{
if (!loaded) {
e = membersByInitiative.GetEnumerator ();
loaded = true;
}
}

public GameCharacter Current {
get {
LazyLoadEnumerator ();
return e.Current.Value;
}
}

object IEnumerator.Current {
get {
LazyLoadEnumerator ();
return e.Current.Value;
}
}

public void Dispose ()
{
LazyLoadEnumerator ();
e.Dispose ();
}

public bool MoveNext ()
{
LazyLoadEnumerator ();
return e.MoveNext ();
}

public void Reset ()
{
LazyLoadEnumerator ();
e.Reset ();
}
}
}
@@ -0,0 +1,45 @@
using System;
using System.Collections;
using System.Collections.Generic;

namespace RnR.Systems.D20.Util
{
public class PartyMembersIterator : IEnumerator<GameCharacter>
{
List<GameCharacter> members;
int p;

public PartyMembersIterator (List<GameCharacter> members)
{
this.members = members;
p = 0;
}

public GameCharacter Current {
get {
return members [p];
}
}

object IEnumerator.Current {
get {
return members [p];
}
}

public void Dispose ()
{
}

public bool MoveNext ()
{
p++;
return p < members.Count;
}

public void Reset ()
{
p = 0;
}
}
}
@@ -63,5 +63,26 @@ private void CalculateSum ()
public List<int> Dices {
get { return dices; }
}

/// <summary>
/// Discards the lower value of the roll.
/// </summary>
public void DiscardLower ()
{
int idx = -1;
int val = int.MaxValue;
int i = 0;
dices.ForEach ((diceVal) => {
if (diceVal < val) {
val = diceVal;
idx = i;
}

i++;
});

if (idx >= 0)
dices.RemoveAt (idx);
}
}
}
@@ -4,6 +4,7 @@
using Lain.Geometry;
using RogueSharp;
using RnR.Systems.D20.Base.FloorElements;
using RnR.Systems.D20;

namespace RnR.World
{
@@ -31,19 +32,22 @@ public Dungeon (FloorGenerationStrategy strategy)
CurrentFloor.SetCellProperties (c.X, c.Y, c.IsTransparent, c.IsWalkable, true);
}

private void CheckIfActorSteped(Point2D p) {
if (CurrentFloor.FloorElements.ContainsKey (p)) {
var e = CurrentFloor.FloorElements [p];
private void CheckIfActorSteped(Party p, List<string> log) {
if (CurrentFloor.FloorElements.ContainsKey (p.Leader.Position)) {
var e = CurrentFloor.FloorElements [p.Leader.Position];
if (e is Stepable) {
string msg = (e as Stepable).OnStep (p);
if (msg != null)
log.Add (msg);
//System.Console.WriteLine ($"Steped over a {e.GetType().Name}");
//(e as OnStepListener).OnStep (null);
}
}
}

public void Update(Point2D center) {
SetFovAsVisible (center);
CheckIfActorSteped (center);
public void Update(Party party, List<string> log) {
SetFovAsVisible (party.Leader.Position);
CheckIfActorSteped (party, log);
}

void AddNewFloor ()