1 /**
2 * Copyright © Novelate 2020
3 * License: MIT (https://github.com/Novelate/NovelateEngine/blob/master/LICENSE)
4 * Author: Jacob Jensen (bausshf)
5 * Website: https://novelate.com/
6 * ------
7 * Novelate is a free and open-source visual novel engine and framework written in the D programming language.
8 * It can be used freely for both personal and commercial projects.
9 * ------
10 * Module Description:
11 * This module handles scenes.
12 */
13 module novelate.scripting.scene;
14 
15 import std.conv : to;
16 import std.algorithm : countUntil, endsWith;
17 
18 /// Wrapper around a scene configuration.
19 final class NovelateScene
20 {
21   private:
22   /// The name.
23   string _name;
24   /// The music.
25   string _music;
26   /// The background.
27   string _background;
28   /// The animation.
29   string _animation;
30   /// The animation direction.
31   string _animationDirection;
32   /// The animation start position.
33   string _animationStartPosition;
34   /// Boolean determining whether the scene name should be displayed or not.
35   bool _displaySceneName;
36   /// Boolean determining whether the configuration is parsing actions.
37   bool _parseActions;
38   /// The actions.
39   NovelateSceneAction[] _actions;
40 
41   public:
42   final:
43   package(novelate)
44   {
45     this(string name)
46     {
47       _name = name;
48 
49       _actions = [];
50     }
51 
52     /**
53     * Updates the scene with a line to parse from the parsed Novelate content.
54     * Params:
55     *   line = The line to parse.
56     */
57     void updateScene(string line)
58     {
59       if (line == "---")
60       {
61         _parseActions = true;
62       }
63       else
64       {
65         if (_parseActions)
66         {
67           if (line == "===")
68           {
69             _actions ~= new NovelateSceneAction(NovelateSceneActionType.actionChange, line);
70           }
71           else
72           {
73             auto valueIndex = line.countUntil("=");
74 
75             if (valueIndex < 1)
76             {
77               if (line.endsWith(";"))
78               {
79                 _actions ~= new NovelateSceneAction(NovelateSceneActionType.action, line[0 .. $-1]);
80               }
81               else
82               {
83                 _actions ~= new NovelateSceneAction(NovelateSceneActionType.characterChange, line);
84               }
85             }
86             else
87             {
88               import std.array : replace;
89 
90               auto name = line[0 .. valueIndex];
91               auto value = line[valueIndex + 1 .. $];
92 
93               _actions ~= new NovelateSceneAction(NovelateSceneActionType.option, name, value.replace("\\n", "\n"));
94             }
95           }
96         }
97         else
98         {
99           auto valueIndex = line.countUntil("=");
100 
101           if (valueIndex < 1)
102           {
103             return;
104           }
105 
106           auto name = line[0 .. valueIndex];
107           auto value = line[valueIndex + 1 .. $];
108 
109           switch (name)
110           {
111             case "Music": _music = value; break;
112             case "Background": _background = value; break;
113             case "Animation": _animation = value; break;
114             case "AnimationDirection": _animationDirection = value; break;
115             case "AnimationStartPosition": _animationStartPosition = value; break;
116             case "DisplaySceneName": _displaySceneName = to!bool(value); break;
117 
118             default: break;
119           }
120         }
121       }
122     }
123   }
124 
125   @property
126   {
127     /// Gets the name of the scene.
128     string name() { return _name; }
129 
130     /// Gets the music of the scene.
131     string music() { return _music; }
132 
133     /// Gets the background of the scene.
134     string background() { return _background; }
135 
136     /// Gets the animation of the scene.
137     string animation() { return _animation; }
138 
139     /// Gets the animation direction of the scene.
140     string animationDirection() { return _animationDirection; }
141 
142     /// Gets the animation start position of the scene.
143     string animationStartPosition() { return _animationStartPosition; }
144 
145     /// Gets a boolean determining whether the scene name should be displayed or not.
146     bool displaySceneName() { return _displaySceneName; }
147 
148     /// Gets the actions of the scene.
149     NovelateSceneAction[] actions() { return _actions; }
150   }
151 }
152 
153 /// Enumeration of scene action types.
154 enum NovelateSceneActionType
155 {
156   /// A character change.
157   characterChange,
158   /// An option. This means an optiion for inputting configurations, setting data etc.
159   option,
160   /// An action to execute.
161   action,
162   /// An action change. This forces a wait for the next set of actions.
163   actionChange
164 }
165 
166 /// Wrapper around a scene action.
167 final class NovelateSceneAction
168 {
169   private:
170   /// The type.
171   NovelateSceneActionType _type;
172   /// The name.
173   string _name;
174   /// The value.
175   string _value;
176 
177   public:
178   final:
179   /**
180   * Creates a new scene action.
181   * Params:
182   *   type = The type of the scene action.
183   *   name = The name of the scene action.
184   */
185   this(NovelateSceneActionType type, string name)
186   {
187     _type = type;
188     _name = name;
189   }
190 
191   /**
192   * Creates a new scene action.
193   * Params:
194   *   type = The type of the scene action.
195   *   name = The name of the scene action.
196   *   value = The value of the scene action.
197   */
198   this(NovelateSceneActionType type, string name, string value)
199   {
200     this(type, name);
201 
202     _value = value;
203   }
204 
205   @property
206   {
207     /// Gets the type.
208     NovelateSceneActionType type() { return _type; }
209 
210     /// Gets the name.
211     string name() { return _name; }
212 
213     /// Gets the value.
214     string value() { return _value; }
215   }
216 }
217 
218 /// The scene collection.
219 private NovelateScene[string] _scenes;
220 
221 public:
222 /**
223 * Gets a scene.
224 * Params:
225 *   name = The name of the scene to get.
226 * Returns:
227 *   The scene.
228 */
229 NovelateScene getScene(string name)
230 {
231   if (!_scenes)
232   {
233     return null;
234   }
235 
236   return _scenes.get(name, null);
237 }
238 
239 package(novelate):
240 /**
241 * Creates a scene base.
242 * Params:
243 *   name = The name of the scene to create a base for.
244 * Returns:
245 *   The scene base created.
246 */
247 NovelateScene createSceneBase(string name)
248 {
249   auto scene = new NovelateScene(name);
250 
251   _scenes[scene.name] = scene;
252 
253   return scene;
254 }