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 configurations for game compilation, deployment and also default configurations.
12 */
13 module novelate.scripting.config;
14 
15 import std.conv : to;
16 import std.array : split;
17 import std..string : isNumeric;
18 
19 /// A value that may contain two different type values. Similar to a union except they're not combined data.
20 struct AltValue(T1,T2)
21 {
22   /// The first value.
23   T1 value1;
24   /// The second value.
25   T2 value2;
26 }
27 
28 /// The compiled config for the game.
29 final class NovelateConfig
30 {
31   private:
32   /// The data folder.
33   string _dataFolder;
34   /// The save folder.
35   string _saveFolder;
36   /// The title of the game.
37   string _gameTitle;
38   /// The slogan of the game.
39   string _gameSlogan;
40   /// The description of the game.
41   string _gameDescription;
42   /// The about text of the game.
43   string[] _gameAbout;
44   /// The x coordinate for the menubox under the 800 resolution.
45   AltValue!(ptrdiff_t, string) _menuBox_X800;
46   /// The y coordinate for the menubox under the 800 resolution.
47   AltValue!(ptrdiff_t, string) _menuBox_Y800;
48   /// The x coordinate for the menubox under the 1024 resolution.
49   AltValue!(ptrdiff_t, string) _menuBox_X1024;
50   /// The y coordinate for the menubox under the 1024 resolution.
51   AltValue!(ptrdiff_t, string) _menuBox_Y1024;
52   /// The x coordinate for the menubox under the 1280 resolution.
53   AltValue!(ptrdiff_t, string) _menuBox_X1280;
54   /// The y coordinate for the menubox under the 1280 resolution.
55   AltValue!(ptrdiff_t, string) _menuBox_Y1280;
56   /// The menu text for the menu item: Play
57   NovelateMenuText _menuItem_Play;
58   /// The menu text for the menu item: Load
59   NovelateMenuText _menuItem_Load;
60   /// The menu text for the menu item: Save
61   NovelateMenuText _menuItem_Save;
62   /// The menu text for the menu item: About
63   NovelateMenuText _menuItem_About;
64   /// The menu text for the menu item: Characters
65   NovelateMenuText _menuItem_Characters;
66   /// The menu text for the menu item: Exit
67   NovelateMenuText _menuItem_Exit;
68 
69   /// The menu title text.
70   NovelateMenuText _menuTitleText;
71   /// The menu title slogan.
72   NovelateMenuText _menuTitleSlogan;
73 
74   /// The menu logo animation/image.
75   NovelateImageAnimation _menuLogoImage;
76 
77   /// The x coordinate for the menu logo under the 800 resolution.
78   ptrdiff_t _menuLogoImageX800;
79   /// The y coordinate for the menu logo under the 800 resolution.
80   ptrdiff_t _menuLogoImageY800;
81   /// The x coordinate for the menu logo under the 1024 resolution.
82   ptrdiff_t _menuLogoImageX1024;
83   /// The y coordinate for the menu logo under the 1024 resolution.
84   ptrdiff_t _menuLogoImageY1024;
85   /// The x coordinate for the menu logo under the 1280 resolution.
86   ptrdiff_t _menuLogoImageX1280;
87   /// The y coordinate for the menu logo under the 1280 resolution.
88   ptrdiff_t _menuLogoImageY1280;
89 
90   /// The menu music.
91   string _menuMusic;
92 
93   /// The menu background animation/image.
94   NovelateImageAnimation _menuBackground;
95 
96   /// The default font.
97   string _defaultFont;
98   /// The default font size.
99   uint _defaultFontSize;
100   /// The default dialogue color.
101   string _defaultDialogueColor;
102   /// The default dialogue background color.
103   string _defaultDialogueBackground;
104   /// The default dialogue border color.
105   string _defaultDialogueBorder;
106   /// The default dialogue background image/animation.
107   NovelateImageAnimation _defaultDialogueBackgroundImage;
108   /// The default dialogue padding.
109   size_t _defaultDialoguePadding;
110   /// The default dialogue margin.
111   size_t _defaultDialogueMargin;
112   /// The default dialogue height under the 800 resolution.
113   size_t _defaultDialogueHeight800;
114   /// The default dialogue height under the 1024 resolution.
115   size_t _defaultDialogueHeight1024;
116   /// The default dialogue height under the 1280 resolution.
117   size_t _defaultDialogueHeight1280;
118   /// The default dialogue name font size.
119   size_t _defaultDialogueNameFontSize;
120   /// The default dialogue text font size.
121   size_t _defaultDialogueTextFontSize;
122   /// The default dialogue name font.
123   string _defaultDialogueNameFont;
124   /// The default dialogue text font.
125   string _defaultDialogueTextFont;
126 
127   /// The start scene.
128   string _startScene;
129   /// The credits video.
130   string _creditsVideo;
131 
132   public:
133   final:
134   this()
135   {
136     _gameAbout = [];
137 
138     _menuItem_Play = new NovelateMenuText("Play");
139     _menuItem_Load = new NovelateMenuText("Load");
140     _menuItem_Save = new NovelateMenuText("Save");
141     _menuItem_About = new NovelateMenuText("About");
142     _menuItem_Characters = new NovelateMenuText("Characters");
143     _menuItem_Exit = new NovelateMenuText("Exit");
144 
145     _menuTitleText = new NovelateMenuText("Game Title");
146     _menuTitleSlogan = new NovelateMenuText("Game Slogan");
147 
148     _defaultDialoguePadding = 8;
149     _defaultDialogueMargin = 8;
150 
151     _defaultFontSize = 16;
152   }
153 
154   @property
155   {
156     /// Gets the data folder.
157     string dataFolder() { return _dataFolder; }
158     /// Gets the save folder.
159     string saveFolder() { return _saveFolder; }
160     /// Gets the game title.
161     string gameTitle() { return _gameTitle; }
162     /// Gets the game slogan.
163     string gameSlogan() { return _gameSlogan; }
164     /// Gets the game description.
165     string gameDescription() { return _gameDescription; }
166     /// Gets the about text of the game.
167     string[] gameAbout() { return _gameAbout; }
168     /// Gets the x coordinate for the menubox under the 800 resolution.
169     AltValue!(ptrdiff_t, string) menuBox_X800() { return _menuBox_X800; }
170     /// Gets the y coordinate for the menubox under the 800 resolution.
171     AltValue!(ptrdiff_t, string) menuBox_Y800() { return _menuBox_Y800; }
172     /// Gets the x coordinate for the menubox under the 1024 resolution.
173     AltValue!(ptrdiff_t, string) menuBox_X1024() { return _menuBox_X1024; }
174     /// Gets the y coordinate for the menubox under the 1024 resolution.
175     AltValue!(ptrdiff_t, string) menuBox_Y1024() { return _menuBox_Y1024; }
176     /// Gets the x coordinate for the menubox under the 1280 resolution.
177     AltValue!(ptrdiff_t, string) menuBox_X1280() { return _menuBox_X1280; }
178     /// Gets the y coordinate for the menubox under the 1280 resolution.
179     AltValue!(ptrdiff_t, string) menuBox_Y1280() { return _menuBox_Y1280; }
180     /// Gets the menu text for the menu item: Play
181     NovelateMenuText menuItem_Play() { return _menuItem_Play; }
182     /// Gets the menu text for the menu item: Load
183     NovelateMenuText menuItem_Load() { return _menuItem_Load; }
184     /// Gets the menu text for the menu item: Save
185     NovelateMenuText menuItem_Save() { return _menuItem_Save; }
186     /// Gets the menu text for the menu item: About
187     NovelateMenuText menuItem_About() { return _menuItem_About; }
188     /// Gets the menu text for the menu item: Characters
189     NovelateMenuText menuItem_Characters() { return _menuItem_Characters; }
190     /// Gets the menu text for the menu item: Exit
191     NovelateMenuText menuItem_Exit() { return _menuItem_Exit; }
192     /// Gets the menu title text.
193     NovelateMenuText menuTitleText() { return _menuTitleText; }
194     /// Gets the menu title slogan.
195     NovelateMenuText menuTitleSlogan() { return _menuTitleSlogan; }
196     /// Gets the menu logo animation/image.
197     NovelateImageAnimation menuLogoImage() { return _menuLogoImage; }
198     /// Gets the x coordinate for the menu logo under the 800 resolution.
199     ptrdiff_t menuLogoImageX800() { return _menuLogoImageX800; }
200     /// Gets the y coordinate for the menu logo under the 800 resolution.
201     ptrdiff_t menuLogoImageY800() { return _menuLogoImageY800; }
202     /// Gets the x coordinate for the menu logo under the 1024 resolution.
203     ptrdiff_t menuLogoImageX1024() { return _menuLogoImageX1024; }
204     /// Gets the y coordinate for the menu logo under the 1024 resolution.
205     ptrdiff_t menuLogoImageY1024() { return _menuLogoImageY1024; }
206     /// Gets the x coordinate for the menu logo under the 1280 resolution.
207     ptrdiff_t menuLogoImageX1280() { return _menuLogoImageX1280; }
208     /// Gets the y coordinate for the menu logo under the 1280 resolution.
209     ptrdiff_t menuLogoImageY1280() { return _menuLogoImageY1280; }
210     /// Gets the menu music.
211     string menuMusic() { return _menuMusic; }
212     /// Gets the menu background animation/image.
213     NovelateImageAnimation menuBackground() { return _menuBackground; }
214     /// Gets the default font.
215     string defaultFont() { return _defaultFont; }
216     /// Gets the default font size.
217     uint defaultFontSize() { return _defaultFontSize; }
218     /// Gets the default dialogue color.
219     string defaultDialogueColor() { return _defaultDialogueColor; }
220     /// Gets the default dialogue background.
221     string defaultDialogueBackground() { return _defaultDialogueBackground; }
222     /// Gets the default dialogue border.
223     string defaultDialogueBorder() { return _defaultDialogueBorder; }
224     /// Gets the default dialogue background image/animation.
225     NovelateImageAnimation defaultDialogueBackgroundImage() { return _defaultDialogueBackgroundImage; }
226     /// Gets the default dialogue padding.
227     size_t defaultDialoguePadding() { return _defaultDialoguePadding; }
228     /// Gets the default dialogue margin.
229     size_t defaultDialogueMargin() { return _defaultDialogueMargin; }
230     /// Gets the default dialogue height under the 800 resolution.
231     size_t defaultDialogueHeight800() { return _defaultDialogueHeight800; }
232     /// Gets the default dialogue height under the 1024 resolution.
233     size_t defaultDialogueHeight1024() { return _defaultDialogueHeight1024; }
234     /// Gets the default dialogue height under the 1280 resolution.
235     size_t defaultDialogueHeight1280() { return _defaultDialogueHeight1280; }
236     /// Gets the default dialogue name font size.
237     size_t defaultDialogueNameFontSize() { return _defaultDialogueNameFontSize; }
238     /// Gets the default dialogue text font size.
239     size_t defaultDialogueTextFontSize() { return _defaultDialogueTextFontSize; }
240     /// Gets the default dialogue name font.
241     string defaultDialogueNameFont() { return _defaultDialogueNameFont; }
242     /// Gets the default dialogue text font.
243     string defaultDialogueTextFont() { return _defaultDialogueTextFont; }
244     /// Gets the start scene.
245     string startScene() { return _startScene; }
246     /// Gets the credits video.
247     string creditsVideo() { return _creditsVideo; }
248   }
249 
250   package(novelate):
251   /**
252   * Sets a parsed configuration. Some configurations can be set to multiple values by setting them multiple times.
253   * Params:
254   *   name = The name of the configuration to set.
255   *   value = The value of the configuration to set.
256   */
257   void setConfig(string name, string value)
258   {
259     switch (name)
260     {
261       case "DataFolder": _dataFolder = value; break;
262       case "SaveFolder": _saveFolder = value; break;
263       case "GameTitle": _gameTitle = value; break;
264       case "GameSlogan": _gameSlogan = value; break;
265       case "GameDescription": _gameDescription = value; break;
266       case "GameAbout": _gameAbout ~= value; break;
267       case "MenuItem_Play": _menuItem_Play = parseMenuItem(value, _menuItem_Play); break;
268       case "MenuItem_Load": _menuItem_Load = parseMenuItem(value, _menuItem_Load); break;
269       case "MenuItem_Save": _menuItem_Save = parseMenuItem(value, _menuItem_Save); break;
270       case "MenuItem_About": _menuItem_About = parseMenuItem(value, _menuItem_About); break;
271       case "MenuItem_Characters": _menuItem_Characters = parseMenuItem(value, _menuItem_Characters); break;
272       case "MenuItem_Exit": _menuItem_Exit = parseMenuItem(value, _menuItem_Exit); break;
273       case "MenuTitleText": _menuTitleText = parseMenuItem(value, _menuTitleText); break;
274       case "MenuTitleSlogan": _menuTitleSlogan = parseMenuItem(value, _menuTitleSlogan); break;
275 
276       case "MenuBoxPosition_800":
277       {
278         auto pos = value.split(",");
279 
280         if (pos[0].isNumeric) _menuBox_X800.value1 = to!ptrdiff_t(pos[0]);
281         else _menuBox_X800.value2 = pos[0];
282 
283         if (pos[1].isNumeric) _menuBox_Y800.value1 = to!ptrdiff_t(pos[1]);
284         else _menuBox_Y800.value2 = pos[1];
285         break;
286       }
287 
288       case "MenuBoxPosition_1024":
289       {
290         auto pos = value.split(",");
291 
292         if (pos[0].isNumeric) _menuBox_X1024.value1 = to!ptrdiff_t(pos[0]);
293         else _menuBox_X1024.value2 = pos[0];
294 
295         if (pos[1].isNumeric) _menuBox_Y1024.value1 = to!ptrdiff_t(pos[1]);
296         else _menuBox_Y1024.value2 = pos[1];
297         break;
298       }
299 
300       case "MenuBoxPosition_1280":
301       {
302         auto pos = value.split(",");
303 
304         if (pos[0].isNumeric) _menuBox_X1280.value1 = to!ptrdiff_t(pos[0]);
305         else _menuBox_X1280.value2 = pos[0];
306 
307         if (pos[1].isNumeric) _menuBox_Y1280.value1 = to!ptrdiff_t(pos[1]);
308         else _menuBox_Y1280.value2 = pos[1];
309         break;
310       }
311 
312       case "MenuLogoImageLocation_800":
313       {
314         auto pos = value.split(",");
315 
316         _menuLogoImageX800 = to!ptrdiff_t(pos[0]);
317         _menuLogoImageY800 = to!ptrdiff_t(pos[1]);
318         break;
319       }
320 
321       case "MenuLogoImageLocation_1024":
322       {
323         auto pos = value.split(",");
324 
325         _menuLogoImageX1024 = to!ptrdiff_t(pos[0]);
326         _menuLogoImageY1024 = to!ptrdiff_t(pos[1]);
327         break;
328       }
329 
330       case "MenuLogoImageLocation_1280":
331       {
332         auto pos = value.split(",");
333 
334         _menuLogoImageX1280 = to!ptrdiff_t(pos[0]);
335         _menuLogoImageY1280 = to!ptrdiff_t(pos[1]);
336         break;
337       }
338 
339       case "MenuMusic": _menuMusic = value; break;
340 
341       case "MenuBackground":
342       {
343         if (!_menuBackground)
344         {
345           _menuBackground = new NovelateImageAnimation;
346         }
347 
348         parseImageAnimationFrame(_menuBackground, value);
349         break;
350       }
351 
352       case "MenuLogoImage":
353       {
354         if (!_menuLogoImage)
355         {
356           _menuLogoImage = new NovelateImageAnimation;
357         }
358 
359         parseImageAnimationFrame(_menuLogoImage, value);
360         break;
361       }
362 
363       case "DefaultFont": _defaultFont = value; break;
364       case "DefaultFontSize": _defaultFontSize = to!uint(value); break;
365       case "DefaultDialogueColor": _defaultDialogueColor = value; break;
366       case "DefaultDialogueBackground": _defaultDialogueBackground = value; break;
367       case "DefaultDialogueBorder": _defaultDialogueBorder = value; break;
368       case "DefaultDialogueBackgroundImage":
369       {
370         if (!_defaultDialogueBackgroundImage)
371         {
372           _defaultDialogueBackgroundImage = new NovelateImageAnimation;
373         }
374 
375         parseImageAnimationFrame(_defaultDialogueBackgroundImage, value);
376         break;
377       }
378       case "DefaultDialoguePadding": _defaultDialoguePadding = to!size_t(value); break;
379       case "DefaultDialogueMargin": _defaultDialogueMargin = to!size_t(value); break;
380       case "DefaultDialogueHeight_800": _defaultDialogueHeight800 = to!size_t(value); break;
381       case "DefaultDialogueHeight_1024": _defaultDialogueHeight1024 = to!size_t(value); break;
382       case "DefaultDialogueHeight_1280": _defaultDialogueHeight1280 = to!size_t(value); break;
383       case "DefaultDialogueNameFontSize": _defaultDialogueNameFontSize = to!size_t(value); break;
384       case "DefaultDialogueTextFontSize": _defaultDialogueTextFontSize = to!size_t(value); break;
385       case "DefaultDialogueNameFont": _defaultDialogueNameFont = value; break;
386       case "DefaultDialogueTextFont": _defaultDialogueTextFont = value; break;
387 
388       case "StartScene": _startScene = value; break;
389       case "CreditsVideo": _creditsVideo = value; break;
390 
391       default: break;
392     }
393   }
394 }
395 
396 /**
397 * Parses an image animation frame configuration.
398 * Params:
399 *   animation = The animation object to add the frame to.
400 *   value = The value of the frame configuration.
401 */
402 private void parseImageAnimationFrame(NovelateImageAnimation animation, string value)
403 {
404   auto entryData = value.split("|");
405   auto image = entryData[0];
406   auto time = to!size_t(entryData[1]);
407 
408   animation.add(new NovelateImageAnimationFrame(image, time));
409 }
410 
411 /**
412 * Parses a menu item configuration.
413 * Params:
414 *   value = The value of the menu item configuration.
415 *   refItem = The referenced menu item. Usually the old state of the menu item.
416 * Returns:
417 *   Returns the parsed menu item configuration.
418 */
419 private NovelateMenuText parseMenuItem(string value, NovelateMenuText refItem)
420 {
421   auto entryData = value.split("|");
422   auto text = entryData[0];
423   auto color = refItem.color;
424   auto font = refItem.font;
425 
426   if (entryData.length >= 2)
427   {
428     color = entryData[1];
429   }
430 
431   if (entryData.length >= 3)
432   {
433     font = entryData[2];
434   }
435 
436   return new NovelateMenuText(text, color, font);
437 }
438 
439 /// A menu text configuration.
440 final class NovelateMenuText
441 {
442   private:
443   /// The text.
444   string _text;
445   /// The color.
446   string _color;
447   /// The font.
448   string _font;
449 
450   public:
451   /**
452   * Creates a new menu item text configuration.
453   * Params:
454   *   text = The text.
455   *   color = The color.
456   *   font = The font.
457   */
458   this(string text, string color = "255,255,255", string font = null)
459   {
460     _text = text;
461     _color = color;
462     _font = font;
463   }
464 
465   @property
466   {
467     /// Gets the text.
468     string text() { return _text; }
469     /// Gets the color.
470     string color() { return _color; }
471     /// Gets the font.
472     string font() { return _font; }
473   }
474 }
475 
476 /// An image animation configuration.
477 final class NovelateImageAnimation
478 {
479   private:
480   /// The frames of the image animation.
481   NovelateImageAnimationFrame[] _frames;
482 
483   public:
484   /// Creates a new image animation configuration.
485   this()
486   {
487     _frames = [];
488   }
489 
490   @property
491   {
492     /// Gets the frames.
493     NovelateImageAnimationFrame[] frames() { return _frames; }
494   }
495 
496   /// Clears the frames of the image animation.
497   void clear()
498   {
499     _frames = [];
500   }
501 
502   /**
503   * Adds an image animation frame.
504   * Params:
505   *   frame = The frame to add.
506   */
507   void add(NovelateImageAnimationFrame frame)
508   {
509     _frames ~= frame;
510   }
511 }
512 
513 /// An image animation frame.
514 final class NovelateImageAnimationFrame
515 {
516   private:
517   /// The image.
518   string _image;
519   /// The next frame time. Generally only the first frame's time is used to be consistent.
520   size_t _nextFrameTime;
521 
522   public:
523   final:
524   /**
525   * Creates an image animation frame.
526   * Params:
527   *   image = The image of the animation frame.
528   *   nextFrameTime = The next frame time. Generally only the first frame's time is used to be consistent.
529   */
530   this(string image, size_t nextFrameTime)
531   {
532     _image = image;
533     _nextFrameTime = nextFrameTime;
534   }
535 
536   @property
537   {
538     /// Gets the image.
539     string image() { return _image; }
540 
541     /// Gets the next frame time. Generally only the first frame's time is used to be consistent.
542     size_t nextFrameTime() { return _nextFrameTime; }
543   }
544 }
545 
546 /// The configuration.
547 private NovelateConfig _config;
548 
549 public:
550 @property
551 {
552   /// Gets the configuration.
553   NovelateConfig config()
554   {
555     if (!_config)
556     {
557       _config = new NovelateConfig();
558     }
559 
560     return _config;
561   }
562 }