added page compression to remove redundant page states; implemented state resolver
This commit is contained in:
parent
bd99018ed1
commit
a0c9ce5d8c
|
@ -1,10 +1,6 @@
|
||||||
namespace Ficdown.Parser.Tests
|
namespace Ficdown.Parser.Tests
|
||||||
{
|
{
|
||||||
using System;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Player;
|
|
||||||
using ServiceStack.Text;
|
|
||||||
using TestStories;
|
using TestStories;
|
||||||
using Xunit;
|
using Xunit;
|
||||||
|
|
||||||
|
@ -16,13 +12,6 @@
|
||||||
var parser = new FicdownParser();
|
var parser = new FicdownParser();
|
||||||
var storyText = Encoding.UTF8.GetString(Resources.TheRobotKing);
|
var storyText = Encoding.UTF8.GetString(Resources.TheRobotKing);
|
||||||
var story = parser.ParseStory(storyText);
|
var story = parser.ParseStory(storyText);
|
||||||
Assert.NotNull(story);
|
|
||||||
Assert.Equal("The Robot King", story.Name);
|
|
||||||
Assert.Equal("Robot Cave", story.Scenes[story.FirstScene].First().Name);
|
|
||||||
|
|
||||||
var traverser = new GameTraverser(story);
|
|
||||||
var test = traverser.Enumerate();
|
|
||||||
Console.WriteLine(test.Take(10).Dump());
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,32 +1,43 @@
|
||||||
namespace Ficdown.Parser
|
using System.Runtime.CompilerServices;
|
||||||
|
[assembly: InternalsVisibleTo("Ficdown.Parser.Tests")]
|
||||||
|
|
||||||
|
namespace Ficdown.Parser
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using Model.Story;
|
using System.Collections.Generic;
|
||||||
|
using Model.Parser;
|
||||||
using Parser;
|
using Parser;
|
||||||
|
using Player;
|
||||||
|
|
||||||
public class FicdownParser
|
public class FicdownParser
|
||||||
{
|
{
|
||||||
private IBlockHandler _blockHandler;
|
private IBlockHandler _blockHandler;
|
||||||
public IBlockHandler BlockHandler
|
internal IBlockHandler BlockHandler
|
||||||
{
|
{
|
||||||
get { return _blockHandler ?? (_blockHandler = new BlockHandler()); }
|
get { return _blockHandler ?? (_blockHandler = new BlockHandler()); }
|
||||||
set { _blockHandler = value; }
|
set { _blockHandler = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
private IStateResolver _stateResolver;
|
private IGameTraverser _gameTraverser;
|
||||||
|
internal IGameTraverser GameTraverser
|
||||||
|
{
|
||||||
|
get { return _gameTraverser ?? (_gameTraverser = new GameTraverser()); }
|
||||||
|
set { _gameTraverser = value; }
|
||||||
|
}
|
||||||
|
|
||||||
public IStateResolver StateResolver
|
private IStateResolver _stateResolver;
|
||||||
|
internal IStateResolver StateResolver
|
||||||
{
|
{
|
||||||
get { return _stateResolver ?? (_stateResolver = new StateResolver()); }
|
get { return _stateResolver ?? (_stateResolver = new StateResolver()); }
|
||||||
set { _stateResolver = value; }
|
set { _stateResolver = value; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public Story ParseStory(string storyText)
|
public IEnumerable<ResolvedPage> ParseStory(string storyText)
|
||||||
{
|
{
|
||||||
var lines = storyText.Split(new[] {"\n", "\r\n"}, StringSplitOptions.None);
|
var lines = storyText.Split(new[] {"\n", "\r\n"}, StringSplitOptions.None);
|
||||||
var blocks = BlockHandler.ExtractBlocks(lines);
|
var blocks = BlockHandler.ExtractBlocks(lines);
|
||||||
var story = BlockHandler.ParseBlocks(blocks);
|
GameTraverser.Story = BlockHandler.ParseBlocks(blocks);
|
||||||
return story;
|
return StateResolver.Resolve(GameTraverser.Enumerate());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,11 +42,10 @@
|
||||||
<Reference Include="System.Xml" />
|
<Reference Include="System.Xml" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
<Compile Include="Model\Parser\ResolvedPage.cs" />
|
||||||
<Compile Include="Model\Traverser\PageState.cs" />
|
<Compile Include="Model\Traverser\PageState.cs" />
|
||||||
<Compile Include="Model\Traverser\State.cs" />
|
<Compile Include="Model\Traverser\State.cs" />
|
||||||
<Compile Include="Model\Traverser\StateQueueItem.cs" />
|
<Compile Include="Model\Traverser\StateQueueItem.cs" />
|
||||||
<Compile Include="Player\IRenderer.cs" />
|
|
||||||
<Compile Include="Player\HtmlRenderer.cs" />
|
|
||||||
<Compile Include="Parser\BlockHandler.cs" />
|
<Compile Include="Parser\BlockHandler.cs" />
|
||||||
<Compile Include="Parser\IBlockHandler.cs" />
|
<Compile Include="Parser\IBlockHandler.cs" />
|
||||||
<Compile Include="Parser\RegexLib.cs" />
|
<Compile Include="Parser\RegexLib.cs" />
|
||||||
|
@ -61,6 +60,7 @@
|
||||||
<Compile Include="Model\Player\PlayerState.cs" />
|
<Compile Include="Model\Player\PlayerState.cs" />
|
||||||
<Compile Include="Model\Story\Extensions\SceneExtensions.cs" />
|
<Compile Include="Model\Story\Extensions\SceneExtensions.cs" />
|
||||||
<Compile Include="Player\GameTraverser.cs" />
|
<Compile Include="Player\GameTraverser.cs" />
|
||||||
|
<Compile Include="Player\IGameTraverser.cs" />
|
||||||
<Compile Include="Player\StateManager.cs" />
|
<Compile Include="Player\StateManager.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
<Compile Include="Model\Story\Action.cs" />
|
<Compile Include="Model\Story\Action.cs" />
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
namespace Ficdown.Parser.Model.Parser
|
||||||
|
{
|
||||||
|
public class ResolvedPage
|
||||||
|
{
|
||||||
|
public string Name { get; set; }
|
||||||
|
public string Content { get; set; }
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,8 @@
|
||||||
namespace Ficdown.Parser.Model.Traverser
|
namespace Ficdown.Parser.Model.Traverser
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
using System.Collections;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Ficdown.Parser.Player;
|
||||||
using Story;
|
using Story;
|
||||||
|
|
||||||
internal class PageState
|
internal class PageState
|
||||||
|
@ -12,29 +12,22 @@
|
||||||
public State State { get; set; }
|
public State State { get; set; }
|
||||||
public State AffectedState { get; set; }
|
public State AffectedState { get; set; }
|
||||||
|
|
||||||
|
public IDictionary<string, int> StateMatrix { get; set; }
|
||||||
|
|
||||||
public string Resolved { get; set; }
|
public string Resolved { get; set; }
|
||||||
public IDictionary<string, string> Links { get; set; }
|
public IDictionary<string, string> Links { get; set; }
|
||||||
|
|
||||||
private string _uniqueHash;
|
private string _uniqueHash;
|
||||||
|
private string _compressedHash;
|
||||||
|
|
||||||
public string UniqueHash
|
public string UniqueHash
|
||||||
{
|
{
|
||||||
get
|
get { return _uniqueHash ?? (_uniqueHash = StateManager.GetUniqueHash(State, Scene.Key)); }
|
||||||
|
}
|
||||||
|
|
||||||
|
public string CompressedHash
|
||||||
{
|
{
|
||||||
if (_uniqueHash == null)
|
get { return _compressedHash ?? (_compressedHash = StateManager.GetCompressedHash(this)); }
|
||||||
{
|
|
||||||
var combined =
|
|
||||||
new bool[State.PlayerState.Count + State.ScenesSeen.Count + State.ActionsToShow.Count];
|
|
||||||
State.PlayerState.CopyTo(combined, 0);
|
|
||||||
State.ScenesSeen.CopyTo(combined, State.PlayerState.Count);
|
|
||||||
State.ActionsToShow.CopyTo(combined, State.PlayerState.Count + State.ScenesSeen.Count);
|
|
||||||
var ba = new BitArray(combined);
|
|
||||||
var byteSize = (int) Math.Ceiling(combined.Length/8.0);
|
|
||||||
var encoded = new byte[byteSize];
|
|
||||||
ba.CopyTo(encoded, 0);
|
|
||||||
_uniqueHash = string.Format("{0}=={1}", Scene.Key, Convert.ToBase64String(encoded));
|
|
||||||
}
|
|
||||||
return _uniqueHash;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -8,7 +8,7 @@
|
||||||
using Model.Story;
|
using Model.Story;
|
||||||
using Action = Model.Story.Action;
|
using Action = Model.Story.Action;
|
||||||
|
|
||||||
public class BlockHandler : IBlockHandler
|
internal class BlockHandler : IBlockHandler
|
||||||
{
|
{
|
||||||
public IEnumerable<Block> ExtractBlocks(IEnumerable<string> lines)
|
public IEnumerable<Block> ExtractBlocks(IEnumerable<string> lines)
|
||||||
{
|
{
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
using Model.Parser;
|
using Model.Parser;
|
||||||
using Model.Story;
|
using Model.Story;
|
||||||
|
|
||||||
public interface IBlockHandler
|
internal interface IBlockHandler
|
||||||
{
|
{
|
||||||
IEnumerable<Block> ExtractBlocks(IEnumerable<string> lines);
|
IEnumerable<Block> ExtractBlocks(IEnumerable<string> lines);
|
||||||
Story ParseBlocks(IEnumerable<Block> blocks);
|
Story ParseBlocks(IEnumerable<Block> blocks);
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
namespace Ficdown.Parser.Parser
|
namespace Ficdown.Parser.Parser
|
||||||
{
|
{
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using Model.Parser;
|
||||||
|
using Model.Traverser;
|
||||||
|
|
||||||
public interface IStateResolver
|
internal interface IStateResolver
|
||||||
{
|
{
|
||||||
string Resolve(string description, IDictionary<string, bool> playState, bool firstSeen);
|
IEnumerable<ResolvedPage> Resolve(IEnumerable<PageState> pages);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,36 +1,102 @@
|
||||||
namespace Ficdown.Parser.Parser
|
namespace Ficdown.Parser.Parser
|
||||||
{
|
{
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using Model.Parser;
|
||||||
|
using Model.Traverser;
|
||||||
|
|
||||||
public class StateResolver : IStateResolver
|
internal class StateResolver : IStateResolver
|
||||||
{
|
{
|
||||||
public string Resolve(string description, IDictionary<string, bool> playerState, bool firstSeen)
|
private static readonly Random _random = new Random((int) DateTime.Now.Ticks);
|
||||||
|
private readonly IDictionary<string, string> _pageNames;
|
||||||
|
private readonly HashSet<string> _usedNames;
|
||||||
|
|
||||||
|
public StateResolver()
|
||||||
{
|
{
|
||||||
foreach (var anchor in Utilities.ParseAnchors(description))
|
_pageNames = new Dictionary<string, string>();
|
||||||
|
_usedNames = new HashSet<string>();
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<ResolvedPage> Resolve(IEnumerable<PageState> pages)
|
||||||
{
|
{
|
||||||
|
return
|
||||||
|
pages.Select(
|
||||||
|
page =>
|
||||||
|
new ResolvedPage
|
||||||
|
{
|
||||||
|
Name = GetPageNameForHash(page.CompressedHash),
|
||||||
|
Content = ResolveDescription(page)
|
||||||
|
}).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ResolveAnchor(Anchor anchor, IDictionary<string, bool> playerState, string targetHash)
|
||||||
|
{
|
||||||
|
var text = anchor.Text;
|
||||||
if (anchor.Href.Conditions != null)
|
if (anchor.Href.Conditions != null)
|
||||||
{
|
{
|
||||||
var satisfied = Utilities.ConditionsMet(playerState, anchor.Href.Conditions);
|
var satisfied = Utilities.ConditionsMet(playerState, anchor.Href.Conditions);
|
||||||
var alts = Utilities.ParseConditionalText(anchor.Text);
|
var alts = Utilities.ParseConditionalText(text);
|
||||||
var replace = alts[satisfied];
|
var replace = alts[satisfied];
|
||||||
replace = RegexLib.EscapeChar.Replace(replace, string.Empty);
|
text = RegexLib.EscapeChar.Replace(replace, string.Empty);
|
||||||
if (!replace.Equals(string.Empty) || (anchor.Href.Toggles == null && anchor.Href.Target == null))
|
}
|
||||||
|
return !string.IsNullOrEmpty(text) && !string.IsNullOrEmpty(targetHash)
|
||||||
|
? string.Format("[{0}](/{1})", text, GetPageNameForHash(targetHash))
|
||||||
|
: text;
|
||||||
|
}
|
||||||
|
|
||||||
|
private string ResolveDescription(PageState page)
|
||||||
{
|
{
|
||||||
description = description.Replace(anchor.Original, replace);
|
var resolved = page.Scene.Description;
|
||||||
description = RegexLib.EmptyListItem.Replace(description, string.Empty);
|
|
||||||
|
var anchors = Utilities.ParseAnchors(resolved);
|
||||||
|
|
||||||
|
resolved = RegexLib.EmptyListItem.Replace(anchors.Aggregate(resolved,
|
||||||
|
(current, anchor) =>
|
||||||
|
current.Replace(anchor.Original,
|
||||||
|
ResolveAnchor(anchor, GetStateDictionary(page),
|
||||||
|
page.Links.ContainsKey(anchor.Original) ? page.Links[anchor.Original] : null))),
|
||||||
|
string.Empty);
|
||||||
|
|
||||||
|
var seen = page.State.ScenesSeen[page.Scene.Id - 1];
|
||||||
|
resolved = !seen
|
||||||
|
? RegexLib.BlockQuoteToken.Replace(resolved, string.Empty)
|
||||||
|
: RegexLib.BlockQuotes.Replace(resolved, string.Empty);
|
||||||
|
return resolved;
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
private IDictionary<string, bool> GetStateDictionary(PageState page)
|
||||||
{
|
{
|
||||||
var newAnchor = string.Format(@"[{0}]({1}{2})", replace,
|
return page.StateMatrix.Where(matrix => page.State.PlayerState[matrix.Value])
|
||||||
(anchor.Href.Target != null ? string.Format(@"/{0}", anchor.Href.Target) : null),
|
.ToDictionary(m => m.Key, m => true);
|
||||||
anchor.Href.Toggles.ToHrefString("+"));
|
}
|
||||||
description = description.Replace(anchor.Original, newAnchor);
|
|
||||||
}
|
private string GetPageNameForHash(string hash)
|
||||||
}
|
{
|
||||||
}
|
if (!_pageNames.ContainsKey(hash))
|
||||||
return firstSeen
|
{
|
||||||
? RegexLib.BlockQuoteToken.Replace(description, string.Empty)
|
string name;
|
||||||
: RegexLib.BlockQuotes.Replace(description, string.Empty);
|
do
|
||||||
|
{
|
||||||
|
name = RandomString(8);
|
||||||
|
} while (_usedNames.Contains(name));
|
||||||
|
_pageNames.Add(hash, name);
|
||||||
|
_usedNames.Add(name);
|
||||||
|
}
|
||||||
|
return _pageNames[hash];
|
||||||
|
}
|
||||||
|
|
||||||
|
private string RandomString(int size)
|
||||||
|
{
|
||||||
|
var builder = new StringBuilder();
|
||||||
|
for (int i = 0; i < size; i++)
|
||||||
|
{
|
||||||
|
char ch = Convert.ToChar(Convert.ToInt32(Math.Floor(26*_random.NextDouble() + 65)));
|
||||||
|
builder.Append(ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -1,7 +1,4 @@
|
||||||
using System.Runtime.CompilerServices;
|
|
||||||
|
|
||||||
[assembly: InternalsVisibleTo("Ficdown.Parser.Tests")]
|
|
||||||
|
|
||||||
namespace Ficdown.Parser.Parser
|
namespace Ficdown.Parser.Parser
|
||||||
{
|
{
|
||||||
using System;
|
using System;
|
||||||
|
|
|
@ -6,17 +6,25 @@
|
||||||
using Model.Traverser;
|
using Model.Traverser;
|
||||||
using Parser;
|
using Parser;
|
||||||
|
|
||||||
internal class GameTraverser
|
internal class GameTraverser : IGameTraverser
|
||||||
{
|
{
|
||||||
private readonly StateManager _manager;
|
private StateManager _manager;
|
||||||
private readonly Queue<StateQueueItem> _processingQueue;
|
private Queue<StateQueueItem> _processingQueue;
|
||||||
private readonly IDictionary<string, PageState> _processed;
|
private IDictionary<string, PageState> _processed;
|
||||||
|
private IDictionary<string, PageState> _compressed;
|
||||||
|
|
||||||
public GameTraverser(Story story)
|
private Story _story;
|
||||||
|
public Story Story
|
||||||
{
|
{
|
||||||
_manager = new StateManager(story);
|
get { return _story; }
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_story = value;
|
||||||
|
_manager = new StateManager(_story);
|
||||||
_processingQueue = new Queue<StateQueueItem>();
|
_processingQueue = new Queue<StateQueueItem>();
|
||||||
_processed = new Dictionary<string, PageState>();
|
_processed = new Dictionary<string, PageState>();
|
||||||
|
_compressed = new Dictionary<string, PageState>();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public IEnumerable<PageState> Enumerate()
|
public IEnumerable<PageState> Enumerate()
|
||||||
|
@ -40,9 +48,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
// compress redundancies
|
// compress redundancies
|
||||||
|
foreach (var row in _processed)
|
||||||
|
{
|
||||||
|
if (!_compressed.ContainsKey(row.Value.CompressedHash))
|
||||||
|
{
|
||||||
|
var scene = row.Value;
|
||||||
|
var links = scene.Links.Keys.ToArray();
|
||||||
|
foreach (var link in links)
|
||||||
|
{
|
||||||
|
scene.Links[link] = _processed[scene.Links[link]].CompressedHash;
|
||||||
|
}
|
||||||
|
_compressed.Add(row.Value.CompressedHash, row.Value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return _compressed.Values;
|
||||||
return _processed.Values;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessState(StateQueueItem currentState)
|
private void ProcessState(StateQueueItem currentState)
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
namespace Ficdown.Parser.Player
|
|
||||||
{
|
|
||||||
using System.IO;
|
|
||||||
using MarkdownSharp;
|
|
||||||
|
|
||||||
public class HtmlRenderer : IRenderer
|
|
||||||
{
|
|
||||||
public string Template { get; set; }
|
|
||||||
public void Render(string text, string outFile)
|
|
||||||
{
|
|
||||||
File.WriteAllText(outFile, new Markdown().Transform(text));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
namespace Ficdown.Parser.Player
|
||||||
|
{
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Model.Story;
|
||||||
|
using Model.Traverser;
|
||||||
|
|
||||||
|
internal interface IGameTraverser
|
||||||
|
{
|
||||||
|
Story Story { get; set; }
|
||||||
|
IEnumerable<PageState> Enumerate();
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,7 +0,0 @@
|
||||||
namespace Ficdown.Parser.Player
|
|
||||||
{
|
|
||||||
public interface IRenderer
|
|
||||||
{
|
|
||||||
void Render(string text, string outFile);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -59,7 +59,8 @@
|
||||||
ScenesSeen = new BitArray(_sceneCount),
|
ScenesSeen = new BitArray(_sceneCount),
|
||||||
ActionsToShow = new BitArray(_actionCount)
|
ActionsToShow = new BitArray(_actionCount)
|
||||||
},
|
},
|
||||||
Scene = _story.Scenes[_story.FirstScene].Single(s => s.Conditions == null)
|
Scene = _story.Scenes[_story.FirstScene].Single(s => s.Conditions == null),
|
||||||
|
StateMatrix = _stateMatrix
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,6 +96,30 @@
|
||||||
state.ScenesSeen[sceneId - 1] = true;
|
state.ScenesSeen[sceneId - 1] = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static string GetUniqueHash(State state, string sceneKey)
|
||||||
|
{
|
||||||
|
var combined = new bool[state.PlayerState.Count + state.ScenesSeen.Count + state.ActionsToShow.Count];
|
||||||
|
state.PlayerState.CopyTo(combined, 0);
|
||||||
|
state.ScenesSeen.CopyTo(combined, state.PlayerState.Count);
|
||||||
|
state.ActionsToShow.CopyTo(combined, state.PlayerState.Count + state.ScenesSeen.Count);
|
||||||
|
var ba = new BitArray(combined);
|
||||||
|
var byteSize = (int)Math.Ceiling(combined.Length / 8.0);
|
||||||
|
var encoded = new byte[byteSize];
|
||||||
|
ba.CopyTo(encoded, 0);
|
||||||
|
return string.Format("{0}=={1}", sceneKey, Convert.ToBase64String(encoded));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetCompressedHash(PageState page)
|
||||||
|
{
|
||||||
|
var compressed = new State
|
||||||
|
{
|
||||||
|
PlayerState = page.State.PlayerState.And(page.AffectedState.PlayerState),
|
||||||
|
ScenesSeen = page.State.ScenesSeen.And(page.AffectedState.ScenesSeen),
|
||||||
|
ActionsToShow = page.State.ActionsToShow
|
||||||
|
};
|
||||||
|
return GetUniqueHash(compressed, page.Scene.Key);
|
||||||
|
}
|
||||||
|
|
||||||
private Scene GetScene(string target, BitArray playerState)
|
private Scene GetScene(string target, BitArray playerState)
|
||||||
{
|
{
|
||||||
if (!_story.Scenes.ContainsKey(target))
|
if (!_story.Scenes.ContainsKey(target))
|
||||||
|
@ -138,7 +163,8 @@
|
||||||
PlayerState = new BitArray(_stateMatrix.Keys.Count),
|
PlayerState = new BitArray(_stateMatrix.Keys.Count),
|
||||||
ScenesSeen = new BitArray(_sceneCount),
|
ScenesSeen = new BitArray(_sceneCount),
|
||||||
ActionsToShow = new BitArray(_actionCount)
|
ActionsToShow = new BitArray(_actionCount)
|
||||||
}
|
},
|
||||||
|
StateMatrix = _stateMatrix
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue