Description:
Actually render dialog from Ink.
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r384:23e132ba3fe0 -

@@ -0,0 +1,62
1
2
3 using System;
4 using System.Collections.Generic;
5 using System.Text.RegularExpressions;
6 using System.Linq;
7
8 using Microsoft.Xna.Framework;
9
10 using isometricparkfna.Messages;
11 using isometricparkfna.Components;
12 using static isometricparkfna.CellMap;
13 using isometricparkfna.UI;
14
15 using Encompass;
16 using TraceryNet;
17 using Ink.Runtime;
18
19
20 namespace isometricparkfna.Spawners {
21
22 [Receives(typeof(SpawnDialogMessage))]
23 class DialogSpawner : Spawner<SpawnDialogMessage>
24
25 {
26 Story Story;
27 Grammar Grammar;
28
29 public DialogSpawner(Story story, Grammar grammar)
30 {
31 this.Story = story;
32 this.Grammar = grammar;
33 }
34
35 protected override void Spawn(in SpawnDialogMessage message)
36 {
37 //Jump to the specified part of the story:
38 Story.ChoosePathString(message.Path);
39
40 var newDialog = CreateEntity();
41 var continuation = this.Story.ContinueMaximally();
42
43 var parts = Regex.Split(continuation, ":", 0);
44 var speaker = (parts.Length == 2) ? parts[0] : "";
45 var dialog = (parts.Length == 2) ? parts[1] : continuation;
46
47 AddComponent(newDialog, new DialogComponent {
48 CurrentDialog = dialog,
49 CurrentSpeaker = speaker,
50 Options = this.Story.currentChoices
51 .Select(option => option.text)
52 .ToList()});
53
54 AddComponent(newDialog, new WindowTypeComponent {
55 type = Window.Dialog});
56 AddComponent(newDialog,
57 new VisibilityComponent{ visible = true});
58
59 Logging.Success("Spawned new dialog.");
60 }
61 }
62 }
@@ -0,0 +1,17
1
2 using Encompass;
3
4 using isometricparkfna.Utils;
5 using isometricparkfna.UI;
6
7 namespace isometricparkfna.Messages
8 {
9
10 //You must specify both or you get 0 for a window, which is the default window :(
11 public struct DialogChoiceMessage : IMessage, IHasEntity
12 {
13
14 public Entity Entity { set; get; }
15 public int Choice;
16 }
17 }
@@ -0,0 +1,15
1
2
3 using Microsoft.Xna.Framework;
4 using Encompass;
5
6 using isometricparkfna.Spawners;
7
8 #nullable enable
9
10 namespace isometricparkfna.Messages {
11 public struct SpawnDialogMessage : IMessage
12 {
13 public string Path;
14 }
15 }
@@ -33,4 +33,8
33 33 <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
34 34 <PackageReference Include="LinqFaster" Version="1.0.0" />
35 35 </ItemGroup>
36
37 <ItemGroup>
38 <PackageReference Include="Ink.Engine.Runtime-Unofficial" Version="1.0.0-nightly-21061600" />
39 </ItemGroup>
36 40 </Project>
@@ -1,4 +1,4
1
1 using System.Collections.Generic;
2 2
3 3 using Microsoft.Xna.Framework;
4 4
@@ -9,7 +9,11
9 9
10 10 namespace isometricparkfna.Components {
11 11
12 public struct DialogComponent : IComponent {
12 public struct DialogComponent : IComponent/*, IHasEntity*/ {
13 13 public Node<DialogOption> Dialog;
14 public string CurrentDialog;
15 // public Entity Entity {get; set;}
16 public string CurrentSpeaker;
17 public List<string> Options;
14 18 }
15 19 }
@@ -1,1 +1,1
1 {"inkVersion":20,"root":[[{"->":"IntroGovernor"},["done",{"#f":5,"#n":"g-0"}],null],"done",{"Once":[["^Once upon a time...","\n",["ev",{"^->":"Once.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^There were two choices.",{"->":"$r","var":true},null]}],["ev",{"^->":"Once.0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^There were four lines of content.",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"Once.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"Once.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^They lived happily ever after.","\n","end",{"#f":5}]}],{"#f":1}],"IntroGovernor":[["^Governor: Welcome to your new park, director! You can use the mouse or arrow keys to move around, and the plus and minus keys to zoom in and out. B opens the budget and F lets you adjust Forest Policy.","\n","ev","str","^Okay","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","^Governor: Make sure that you keep visitors happy and the budget in the black! You're currently getting an annual grant out of my budgetβ€”it'd sure be nice if you park were self-sufficient so we could drop that expense!","\n",["ev","str","^And I need to keep the forest healthy, too, right?","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Sounds good!","/str","/ev",{"*":".^.c-1","flg":20},{"c-0":["^ ","\n","ev",{"VAR?":"GovernorOpinion"},1,"-","/ev",{"VAR=":"GovernorOpinion","re":true},"^Governor: Ummm, yeah","\n",[["ev",{"^->":"IntroGovernor.0.c-0.3.c-0.10.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^...",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"IntroGovernor.0.c-0.3.c-0.10.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","end",{"#f":5}]}],{"#f":5}],"c-1":["\n","^Governor: I'll check in soon.","\n","end",{"#f":5}]}],{"#f":5}]}],{"#f":1}],"global decl":["ev",0,{"VAR=":"GovernorOpinion"},"/ev","end",null],"#f":1}],"listDefs":{}} No newline at end of file
1 {"inkVersion":20,"root":[[{"->":"IntroGovernor"},["done",{"#f":5,"#n":"g-0"}],null],"done",{"Once":[["^Once upon a time...","\n",["ev",{"^->":"Once.0.2.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^There were two choices.",{"->":"$r","var":true},null]}],["ev",{"^->":"Once.0.3.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-1","flg":18},{"s":["^There were four lines of content.",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"Once.0.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.2.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"c-1":["ev",{"^->":"Once.0.c-1.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.3.s"},[{"#n":"$r2"}],"\n",{"->":".^.^.g-0"},{"#f":5}],"g-0":["^They lived happily ever after.","\n","end",{"#f":5}]}],{"#f":1}],"IntroGovernor":[["^Governor: Welcome to your new park, director! You can use the mouse or arrow keys to move around, and the plus and minus keys to zoom in and out. B opens the budget and F lets you adjust Forest Policy.","\n","ev","str","^Okay","/str","/ev",{"*":".^.c-0","flg":20},{"c-0":["\n","^Governor: Make sure that you keep visitors happy and the budget in the black! You're currently getting an annual grant out of my budgetβ€”it'd sure be nice if you park were self-sufficient so we could drop that expense!","\n",["ev","str","^And I need to keep the forest healthy, too, right?","/str","/ev",{"*":".^.c-0","flg":20},"ev","str","^Sounds good!","/str","/ev",{"*":".^.c-1","flg":20},{"c-0":["^ ","\n","ev",{"VAR?":"GovernorOpinion"},1,"-","/ev",{"VAR=":"GovernorOpinion","re":true},"^Governor: Ummm, yeah","\n",[["ev",{"^->":"IntroGovernor.0.c-0.3.c-0.10.0.$r1"},{"temp=":"$r"},"str",{"->":".^.s"},[{"#n":"$r1"}],"/str","/ev",{"*":".^.^.c-0","flg":18},{"s":["^...",{"->":"$r","var":true},null]}],{"c-0":["ev",{"^->":"IntroGovernor.0.c-0.3.c-0.10.c-0.$r2"},"/ev",{"temp=":"$r"},{"->":".^.^.0.s"},[{"#n":"$r2"}],"\n","end",{"#f":5}]}],{"#f":5}],"c-1":["\n","ev",{"VAR?":"GovernorOpinion"},1,"+","/ev",{"VAR=":"GovernorOpinion","re":true},"^Governor: I'll check in soon.","\n","end",{"#f":5}]}],{"#f":5}]}],{"#f":1}],"global decl":["ev",0,{"VAR=":"GovernorOpinion"},"/ev","end",null],"#f":1}],"listDefs":{}} No newline at end of file
@@ -22,7 +22,8
22 22 typeof(SetTrespassingPolicyMessage),
23 23 typeof(SpawnGameMessage),
24 24 typeof(SetTextVariableMessage),
25 typeof(SetDialogMessage))]
25 typeof(SetDialogMessage),
26 typeof(DialogChoiceMessage))]
26 27 [Reads(typeof(VisibilityComponent),
27 28 typeof(WindowTypeComponent),
28 29 typeof(TrespassingPolicyComponent)
@@ -44,6 +45,7
44 45 public List<SpawnGameMessage> spawnGameMessages;
45 46 public List<SetTextVariableMessage> setTextVariableMessages;
46 47 public List<SetDialogMessage> setDialogMessages;
48 public List<DialogChoiceMessage> dialogChoiceMessages;
47 49
48 50 bool showBudget {get;}
49 51 bool showForest {get;}
@@ -73,6 +75,7
73 75 this.spawnGameMessages = new List<SpawnGameMessage>();
74 76 this.setTextVariableMessages = new List<SetTextVariableMessage>();
75 77 this.setDialogMessages = new List<SetDialogMessage>();
78 this.dialogChoiceMessages = new List<DialogChoiceMessage>();
76 79 this.windowStatuses = new Dictionary<Window, bool>();
77 80
78 81
@@ -157,6 +160,10
157 160 {
158 161 SendMessage(message);
159 162 }
163 foreach (var message in this.dialogChoiceMessages)
164 {
165 SendMessage(message);
166 }
160 167
161 168
162 169
@@ -183,6 +190,7
183 190 this.spawnGameMessages.Clear();
184 191 this.setTextVariableMessages.Clear();
185 192 this.setDialogMessages.Clear();
193 this.dialogChoiceMessages.Clear();
186 194 }
187 195 }
188 196 }
@@ -17,10 +17,9
17 17 [Receives(typeof(SpawnGameMessage))]
18 18 [Sends(typeof(SpawnContractMessage),
19 19 typeof(SpawnOrganizationtMessage),
20 typeof(ToggleWindowMessage))]
21 [Writes(typeof(WindowTypeComponent)
22 //, typeof(DialogComponent)
23 )]
20 typeof(ToggleWindowMessage),
21 typeof(SpawnDialogMessage))]
22 [Writes(typeof(WindowTypeComponent))]
24 23 class GameSpawner : Spawner<SpawnGameMessage>
25 24
26 25 {
@@ -110,6 +109,7
110 109 type = OrganizationType.Cooperative });
111 110 #endregion
112 111 #region dialog
112 /*
113 113
114 114 // this.game.enqueueDialog(DialogTrees.flatten(DialogTrees.testTree, this.grammar));
115 115 //
@@ -139,6 +139,9
139 139 new VisibilityComponent{ visible = true});
140 140
141 141
142 */
143 SendMessage(new SpawnDialogMessage { Path = "IntroGovernor"});
144 // SendMessage(new SpawnDialogMessage { Path = "Once"});
142 145 #endregion
143 146 this.simulation.Subsidy = message.Difficulty switch {
144 147 DifficultyLevel.Hard => 0M,
@@ -1,6 +1,10
1 using System.Text.RegularExpressions;
2 using System.Linq;
3
1 4 using Microsoft.Xna.Framework.Input;
2 5
3 6 using Encompass;
7 using Ink.Runtime;
4 8
5 9 using isometricparkfna.Messages;
6 10 using isometricparkfna.Components;
@@ -13,7 +17,8
13 17 typeof(ToggleVisibilityMessage),
14 18 typeof(SetWindowVisibilityMessage),
15 19 typeof(SelectMessage),
16 typeof(SetDialogMessage))]
20 typeof(SetDialogMessage),
21 typeof(DialogChoiceMessage))]
17 22 [Reads(typeof(WindowTypeComponent),
18 23 typeof(VisibilityComponent),
19 24 typeof(SelectedComponent))]
@@ -22,6 +27,12
22 27 typeof(DialogComponent))]
23 28 class UIEngine : Engine
24 29 {
30 public Story Story;
31
32 public UIEngine(Story story)
33 {
34 this.Story = story;
35 }
25 36
26 37 public override void Update(double dt)
27 38 {
@@ -99,6 +110,34
99 110
100 111 }
101 112 }
113
114 foreach (ref readonly var choiceMessage in ReadMessages<DialogChoiceMessage>())
115 {
116
117 if (Story.currentChoices.Count > 0)
118 {
119 //Advance the story
120 Story.ChooseChoiceIndex(choiceMessage.Choice);
121
122 //Update the dialog component with the new speaker, dialog, and options:
123 var continuation = this.Story.ContinueMaximally();
124 var parts = Regex.Split(continuation, ":", 0);
125 var speaker = (parts.Length == 2) ? parts[0] : "";
126 var dialog = (parts.Length == 2) ? parts[1] : continuation;
127
128 SetComponent(choiceMessage.Entity, new DialogComponent {
129 CurrentDialog = dialog,
130 CurrentSpeaker = speaker,
131 Options = this.Story.currentChoices
132 .Select(option => option.text)
133 .ToList()});
134 }
135 else
136 {
137 Destroy(choiceMessage.Entity);
138 }
139
140 }
102 141 }
103 142 }
104 143 }
@@ -87,6 +87,8
87 87 private bool showInitial;
88 88 int messageIndex;
89 89
90 public Story Story;
91
90 92 //buggy
91 93 private static bool enableCulling = false;
92 94
@@ -242,12 +244,12
242 244 //Has to happen after Grammar initialization.
243 245 NewGameWindow.Initialize(this.grammar);
244 246
245 var _inkStory = new Story(File.ReadAllText(@"Content/dialog.json"));
247 this.Story = new Story(File.ReadAllText(@"Content/dialog.json"));
246 248
247 Logging.Debug(_inkStory.ContinueMaximally());
249 // Logging.Debug(this.Story.ContinueMaximally());
248 250
249 251 WorldBuilder.AddEngine(new InputEngine(Menu.MENU_BAR_HEIGHT, this.camera, gdm));
250 WorldBuilder.AddEngine(new UIEngine());
252 WorldBuilder.AddEngine(new UIEngine(this.Story));
251 253
252 254 var gameBridgeEngine = new GameBridgeEngine(this);
253 255
@@ -262,6 +264,7
262 264 WorldBuilder.AddEngine(new ContractSpawner(simulation.map.MapWidth, simulation.map.MapHeight, this.simulation, this.grammar));
263 265 WorldBuilder.AddEngine(new GameSpawner(this.simulation, this, this.grammar));
264 266 WorldBuilder.AddEngine(new OrganizationSpawner(this.simulation, this.grammar));
267 WorldBuilder.AddEngine(new DialogSpawner(this.Story, this.grammar));
265 268 WorldBuilder.AddEngine(new PolicyEngine());
266 269 WorldBuilder.AddEngine(new TraceryBridgeEngine(this.grammar));
267 270
@@ -69,7 +69,7
69 69 var width = gdm.PreferredBackBufferWidth;
70 70
71 71 Entity dialogEntity = default;
72 Node<DialogOption> dialogNode = default;
72 DialogComponent dialogNode = default;
73 73
74 74
75 75
@@ -119,7 +119,7
119 119 break;
120 120 case Window.Dialog:
121 121
122 var dialog = GetComponent<DialogComponent>(entity).Dialog;
122 var dialog = GetComponent<DialogComponent>(entity);
123 123
124 124 if ((dialogEntity == null)
125 125 || (dialogEntity.ID == 0)
@@ -136,7 +136,7
136 136
137 137 }
138 138 }
139 if (dialogNode != null)
139 if (dialogNode.CurrentDialog != null)
140 140 {
141 141 var show = true;
142 142 var paused = true;
@@ -8,6 +8,7
8 8 using Encompass;
9 9
10 10 using isometricparkfna.Engines;
11 using isometricparkfna.Components;
11 12 using isometricparkfna.Messages;
12 13
13 14 #nullable enable
@@ -112,9 +113,9
112 113
113 114 public static bool hadFocus = false;
114 115 public static Node<DialogOption> RenderDialog(Entity entity,
115 ImGuiWindowBridgeEngine bridgeEngine, ref bool show, ref bool paused, ImFontPtr font, Node<DialogOption> currentNode)
116 ImGuiWindowBridgeEngine bridgeEngine, ref bool show, ref bool paused, ImFontPtr font, DialogComponent dialogComponent)
116 117 {
117 Node<DialogOption> new_child = currentNode;
118 Node<DialogOption> new_child = default;
118 119 if (show)
119 120 {
120 121 ImGui.PushFont(font);
@@ -127,7 +128,8
127 128 {
128 129 ImGui.PushStyleColor(ImGuiCol.Text, StyleSets.white);
129 130 }
130 ImGui.Begin(currentNode.data.speaker, ref show, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoSavedSettings);
131
132 ImGui.Begin(dialogComponent.CurrentSpeaker, ref show, ImGuiWindowFlags.NoResize | ImGuiWindowFlags.NoCollapse | ImGuiWindowFlags.AlwaysAutoResize | ImGuiWindowFlags.NoSavedSettings);
131 133 if (DialogInterface.hadFocus)
132 134 {
133 135 ImGui.PopStyleColor();
@@ -135,21 +137,25
135 137 DialogInterface.hadFocus = ImGui.IsWindowFocused();
136 138
137 139
138 if (currentNode.data.response != null)
140 if (dialogComponent.CurrentDialog != null)
139 141 {
140 string messageText = currentNode.data.response;
142 string messageText = dialogComponent.CurrentDialog;
141 143 ImGui.TextWrapped(messageText);
142 144 }
143 145
144 if ((currentNode.children != null) && currentNode.children.Length > 0)
146 if ((dialogComponent.Options != null) && dialogComponent.Options.Count > 0)
145 147 {
146 //Filter out nulls
147 foreach ((Node<DialogOption> child, string choice) in currentNode.children.Select((child) => (child, child.data.choice)).Where( (pair, choice) => pair.choice != null))
148 // foreach (var choice in dialogComponent.Options)
149 for(int i = 0; i < dialogComponent.Options.Count; i++)
148 150 {
149 string buttonText = choice;
151 string buttonText = dialogComponent.Options[i];
150 152 if (ImGui.Button(buttonText))
151 153 {
152 new_child = child;
154 bridgeEngine.dialogChoiceMessages.Add(new DialogChoiceMessage {
155
156 Entity = entity,
157 Choice = i });
158
153 159 }
154 160 }
155 161 }
@@ -159,14 +165,14
159 165 {
160 166 show = false;
161 167 paused = false;
162 bridgeEngine.setDialogMessages.Add(new SetDialogMessage {
168 bridgeEngine.dialogChoiceMessages.Add(new DialogChoiceMessage {
163 169
164 170 Entity = entity,
165 newOption = null });
171 Choice = -1 });
166 172 }
167 173 }
168 174
169 if (currentNode.data.response == null)
175 if (dialogComponent.CurrentDialog == null)
170 176 {
171 177 show = false;
172 178 paused = false;
@@ -177,10 +183,11
177 183 StyleSets.defaultSet.pop();
178 184 ImGui.PopFont();
179 185 }
180 bridgeEngine.setDialogMessages.Add(new SetDialogMessage {
181
182 Entity = entity,
183 newOption = new_child });
186 // bridgeEngine.setDialogMessages.Add(new SetDialogMessage {
187 //
188 // Entity = entity,
189 // newOption = new_child });
190
184 191 return new_child;
185 192 }
186 193 }
You need to be logged in to leave comments. Login now