diff --git a/Ficdown.Parser.Tests/IntegrationTests.cs b/Ficdown.Parser.Tests/IntegrationTests.cs index 72af546..1451c0b 100644 --- a/Ficdown.Parser.Tests/IntegrationTests.cs +++ b/Ficdown.Parser.Tests/IntegrationTests.cs @@ -1,6 +1,9 @@ namespace Ficdown.Parser.Tests { + using System; + using System.IO; using System.Text; + using Render; using TestStories; using Xunit; @@ -12,6 +15,14 @@ var parser = new FicdownParser(); var storyText = Encoding.UTF8.GetString(Resources.TheRobotKing); var story = parser.ParseStory(storyText); + var path = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "itest_output"); + if (!Directory.Exists(path)) Directory.CreateDirectory(path); + foreach (var file in Directory.GetFiles(path)) + { + File.Delete(file); + } + var rend = new HtmlRenderer(); + rend.Render(story, path); } } } diff --git a/Ficdown.Parser/FicDownParser.cs b/Ficdown.Parser/FicDownParser.cs index e94b6d2..a88645a 100644 --- a/Ficdown.Parser/FicDownParser.cs +++ b/Ficdown.Parser/FicDownParser.cs @@ -36,8 +36,9 @@ namespace Ficdown.Parser { var lines = storyText.Split(new[] {"\n", "\r\n"}, StringSplitOptions.None); var blocks = BlockHandler.ExtractBlocks(lines); - GameTraverser.Story = BlockHandler.ParseBlocks(blocks); - return StateResolver.Resolve(GameTraverser.Enumerate()); + var story = BlockHandler.ParseBlocks(blocks); + GameTraverser.Story = story; + return StateResolver.Resolve(GameTraverser.Enumerate(), story); } } } diff --git a/Ficdown.Parser/Ficdown.Parser.csproj b/Ficdown.Parser/Ficdown.Parser.csproj index b34572a..de2e11f 100644 --- a/Ficdown.Parser/Ficdown.Parser.csproj +++ b/Ficdown.Parser/Ficdown.Parser.csproj @@ -43,9 +43,9 @@ - - - + + + @@ -66,6 +66,8 @@ + + diff --git a/Ficdown.Parser/Model/Traverser/PageState.cs b/Ficdown.Parser/Model/Player/PageState.cs similarity index 94% rename from Ficdown.Parser/Model/Traverser/PageState.cs rename to Ficdown.Parser/Model/Player/PageState.cs index 54f2a78..b71290f 100644 --- a/Ficdown.Parser/Model/Traverser/PageState.cs +++ b/Ficdown.Parser/Model/Player/PageState.cs @@ -1,4 +1,4 @@ -namespace Ficdown.Parser.Model.Traverser +namespace Ficdown.Parser.Model.Player { using System; using System.Collections.Generic; @@ -12,7 +12,7 @@ public State State { get; set; } public State AffectedState { get; set; } - public IDictionary StateMatrix { get; set; } + public IDictionary StateMatrix { get; set; } public string Resolved { get; set; } public IDictionary Links { get; set; } diff --git a/Ficdown.Parser/Model/Traverser/State.cs b/Ficdown.Parser/Model/Player/State.cs similarity index 83% rename from Ficdown.Parser/Model/Traverser/State.cs rename to Ficdown.Parser/Model/Player/State.cs index e2ef44b..8ae1f4c 100644 --- a/Ficdown.Parser/Model/Traverser/State.cs +++ b/Ficdown.Parser/Model/Player/State.cs @@ -1,4 +1,4 @@ -namespace Ficdown.Parser.Model.Traverser +namespace Ficdown.Parser.Model.Player { using System.Collections; diff --git a/Ficdown.Parser/Model/Traverser/StateQueueItem.cs b/Ficdown.Parser/Model/Player/StateQueueItem.cs similarity index 81% rename from Ficdown.Parser/Model/Traverser/StateQueueItem.cs rename to Ficdown.Parser/Model/Player/StateQueueItem.cs index 71afcd4..80d065b 100644 --- a/Ficdown.Parser/Model/Traverser/StateQueueItem.cs +++ b/Ficdown.Parser/Model/Player/StateQueueItem.cs @@ -1,4 +1,4 @@ -namespace Ficdown.Parser.Model.Traverser +namespace Ficdown.Parser.Model.Player { using System.Collections.Generic; diff --git a/Ficdown.Parser/Parser/IStateResolver.cs b/Ficdown.Parser/Parser/IStateResolver.cs index 6d935a2..b5a5b26 100644 --- a/Ficdown.Parser/Parser/IStateResolver.cs +++ b/Ficdown.Parser/Parser/IStateResolver.cs @@ -2,10 +2,11 @@ { using System.Collections.Generic; using Model.Parser; - using Model.Traverser; + using Model.Player; + using Model.Story; internal interface IStateResolver { - IEnumerable Resolve(IEnumerable pages); + IEnumerable Resolve(IEnumerable pages, Story story); } } diff --git a/Ficdown.Parser/Parser/StateResolver.cs b/Ficdown.Parser/Parser/StateResolver.cs index 66dc2ba..d7e21ff 100644 --- a/Ficdown.Parser/Parser/StateResolver.cs +++ b/Ficdown.Parser/Parser/StateResolver.cs @@ -5,13 +5,15 @@ using System.Linq; using System.Text; using Model.Parser; - using Model.Traverser; + using Model.Player; + using Model.Story; internal class StateResolver : IStateResolver { private static readonly Random _random = new Random((int) DateTime.Now.Ticks); private readonly IDictionary _pageNames; private readonly HashSet _usedNames; + private Story _story; public StateResolver() { @@ -19,8 +21,9 @@ _usedNames = new HashSet(); } - public IEnumerable Resolve(IEnumerable pages) + public IEnumerable Resolve(IEnumerable pages, Story story) { + _story = story; return pages.Select( page => @@ -48,11 +51,22 @@ private string ResolveDescription(PageState page) { - var resolved = page.Scene.Description; + var resolved = new StringBuilder(); + resolved.AppendFormat("## {0}\n\n", page.Scene.Name); - var anchors = Utilities.ParseAnchors(resolved); + for (var i = 0; i < page.State.ActionsToShow.Count; i++) + { + if (page.State.ActionsToShow[i]) + { + resolved.AppendFormat("{0}\n\n", _story.Actions.Single(a => a.Value.Id == i + 1).Value.Description); + } + } - resolved = RegexLib.EmptyListItem.Replace(anchors.Aggregate(resolved, + var text = resolved.Append(page.Scene.Description).ToString(); + + var anchors = Utilities.ParseAnchors(text); + + text = RegexLib.EmptyListItem.Replace(anchors.Aggregate(text, (current, anchor) => current.Replace(anchor.Original, ResolveAnchor(anchor, GetStateDictionary(page), @@ -60,10 +74,10 @@ 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; + text = !seen + ? RegexLib.BlockQuoteToken.Replace(text, string.Empty) + : RegexLib.BlockQuotes.Replace(text, string.Empty); + return text; } private IDictionary GetStateDictionary(PageState page) diff --git a/Ficdown.Parser/Player/GameTraverser.cs b/Ficdown.Parser/Player/GameTraverser.cs index 4f4d0af..557dc0d 100644 --- a/Ficdown.Parser/Player/GameTraverser.cs +++ b/Ficdown.Parser/Player/GameTraverser.cs @@ -2,8 +2,8 @@ { using System.Collections.Generic; using System.Linq; + using Model.Player; using Model.Story; - using Model.Traverser; using Parser; internal class GameTraverser : IGameTraverser @@ -12,6 +12,7 @@ private Queue _processingQueue; private IDictionary _processed; private IDictionary _compressed; + private IDictionary _actionMatrix; private Story _story; public Story Story @@ -20,6 +21,7 @@ set { _story = value; + _actionMatrix = _story.Actions.ToDictionary(a => a.Value.Id, a => a.Value); _manager = new StateManager(_story); _processingQueue = new Queue(); _processed = new Dictionary(); @@ -65,11 +67,23 @@ return _compressed.Values; } + private IEnumerable GetActionsForPage(PageState page) + { + var actions = new List(); + for (var i = 0; i < page.State.ActionsToShow.Count; i++) + { + if (page.State.ActionsToShow[i]) actions.Add(_actionMatrix[i + 1]); + } + return actions; + } + private void ProcessState(StateQueueItem currentState) { var states = new HashSet(); - var anchors = Utilities.ParseAnchors(currentState.Page.Scene.Description); + var anchors = Utilities.ParseAnchors(currentState.Page.Scene.Description).ToList(); + foreach (var action in GetActionsForPage(currentState.Page)) + anchors.AddRange(Utilities.ParseAnchors(action.Description)); var conditionals = anchors.SelectMany( a => a.Href.Conditions != null ? a.Href.Conditions.Select(c => c.Key) : new string[] {}) @@ -80,6 +94,9 @@ foreach (var affected in currentState.AffectedStates) { // signal to previous scenes that this scene's used conditionals are important + if(currentState.Page.Scene.Conditions != null) + foreach (var conditional in currentState.Page.Scene.Conditions) + _manager.ToggleStateOn(affected, conditional.Key); foreach (var conditional in conditionals) _manager.ToggleStateOn(affected, conditional); // signal to previous scenes if this scene has first-seen text diff --git a/Ficdown.Parser/Player/IGameTraverser.cs b/Ficdown.Parser/Player/IGameTraverser.cs index 22d2254..f390402 100644 --- a/Ficdown.Parser/Player/IGameTraverser.cs +++ b/Ficdown.Parser/Player/IGameTraverser.cs @@ -1,8 +1,8 @@ namespace Ficdown.Parser.Player { using System.Collections.Generic; + using Model.Player; using Model.Story; - using Model.Traverser; internal interface IGameTraverser { diff --git a/Ficdown.Parser/Player/StateManager.cs b/Ficdown.Parser/Player/StateManager.cs index ce1565e..dbf1a3a 100644 --- a/Ficdown.Parser/Player/StateManager.cs +++ b/Ficdown.Parser/Player/StateManager.cs @@ -5,8 +5,8 @@ using System.Collections.Generic; using System.Linq; using Model.Parser; + using Model.Player; using Model.Story; - using Model.Traverser; using Parser; internal class StateManager diff --git a/Ficdown.Parser/Render/HtmlRenderer.cs b/Ficdown.Parser/Render/HtmlRenderer.cs new file mode 100644 index 0000000..c9e4712 --- /dev/null +++ b/Ficdown.Parser/Render/HtmlRenderer.cs @@ -0,0 +1,33 @@ +namespace Ficdown.Parser.Render +{ + using System.Collections.Generic; + using System.IO; + using MarkdownSharp; + using Model.Parser; + using Model.Story; + using Parser; + + internal class HtmlRenderer : IRenderer + { + private readonly Markdown _md; + + public HtmlRenderer() + { + _md = new Markdown(); + } + + public void Render(IEnumerable pages, string outPath) + { + foreach (var page in pages) + { + var content = page.Content; + foreach (var anchor in Utilities.ParseAnchors(page.Content)) + { + var newAnchor = string.Format("[{0}]({1}.html)", anchor.Text, anchor.Href.Target); + content = content.Replace(anchor.Original, newAnchor); + } + File.WriteAllText(Path.Combine(outPath, string.Format("{0}.html", page.Name)), _md.Transform(content)); + } + } + } +} diff --git a/Ficdown.Parser/Render/IRenderer.cs b/Ficdown.Parser/Render/IRenderer.cs new file mode 100644 index 0000000..4a1c9db --- /dev/null +++ b/Ficdown.Parser/Render/IRenderer.cs @@ -0,0 +1,11 @@ +namespace Ficdown.Parser.Render +{ + using System.Collections.Generic; + using Model.Parser; + using Model.Story; + + internal interface IRenderer + { + void Render(IEnumerable pages, string outPath); + } +}