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 everything that has to do with the core of characters within a novel.
12 */
13 module novelate.character;
14 
15 import std.array : split;
16 import std.path : baseName;
17 import std.conv : to;
18 
19 /// A character.
20 final class NovelateCharacter
21 {
22   private:
23   /// The name.
24   string _name;
25   /// The alias name. Used internally if ex. display name has special characters, making it easier to retrieve/update etc. from code.
26   string _aliasName;
27   /// The name color.
28   string _nameColor;
29   /// The about information.
30   string _about;
31   /// The about image.
32   string _aboutImage;
33   /// The image collection of the character.
34   NovelateCharacterImageCollection[string] _graphics;
35 
36   public:
37   final:
38   /**
39   * Creates a new character.
40   * Params:
41   *   name = The name of the character.
42   */
43   this(string name)
44   {
45     _name = name;
46     _aliasName = _name;
47   }
48 
49   @property
50   {
51     /// Gets the name of the character.
52     string name() { return _name; }
53 
54     /// Gets the alias name of the character. Used internally if ex. display name has special characters, making it easier to retrieve/update etc. from code.
55     string aliasName() { return _aliasName; }
56 
57     /// Gets the name color of the character.
58     string nameColor() { return _nameColor; }
59 
60     /// Gets the about information of the character.
61     string about() { return _about; }
62 
63     /// Gets the about image of the character.
64     string aboutImage() { return _aboutImage; }
65   }
66 
67   /**
68   * Gets an image from the character's internal image collection.
69   * Params:
70   *   entry = The entry of the image ex. "Casual.Smiling"
71   *   width = The relative width to retrieve from. This can be 800, 1024 or 1280.
72   * Returns:
73   *   The path of the image retrieved.
74   */
75   string getImage(string entry, size_t width)
76   {
77     if (!_graphics)
78     {
79       return null;
80     }
81 
82     auto data = entry.split(".");
83 
84     if (data.length != 2)
85     {
86       return null;
87     }
88 
89     auto collection = _graphics.get(data[0], null);
90 
91     if (!collection)
92     {
93       return null;
94     }
95 
96     return collection.get(data[1] ~ "_" ~ to!string(width));
97   }
98 }
99 
100 /// A collection of character images.
101 final class NovelateCharacterImageCollection
102 {
103   private:
104   /// The images of the character.
105   string[string] _images;
106 
107   public:
108   final:
109   /**
110   * Creates a new collection of character images.
111   * Params:
112   *   path = The path of the image collection for the character.
113   */
114   this(string path)
115   {
116     import std.file : dirEntries, SpanMode;
117     import std.algorithm : filter, endsWith;
118 
119     auto images = dirEntries(to!string(path), SpanMode.shallow).filter!(f => f.name.endsWith(".png"));
120 
121     foreach (image; images)
122     {
123       auto name = baseName(image).split(".")[0];
124 
125       _images[name] = image;
126     }
127   }
128 
129   /**
130   * Gets an image from the collection.
131   * Params:
132   *   name = The name of the image.
133   * Returns:
134   *   The image retrieved from the collection.
135   */
136   string get(string name)
137   {
138     if (!_images)
139     {
140       return null;
141     }
142 
143     return _images.get(name, null);
144   }
145 }
146 
147 /// The collection of characters.
148 private NovelateCharacter[string] _characters;
149 
150 public:
151 /**
152 * Gets a character.
153 * Params:
154 *   name = The name of the character. This can also be the alias name.
155 * Returns:
156 *   The character from the character collection.
157 */
158 NovelateCharacter getCharacter(string name)
159 {
160   if (!_characters)
161   {
162     return null;
163   }
164 
165   return _characters.get(name, null);
166 }
167 
168 package(novelate):
169 /**
170 * Creates a character base and adds it to the character collection.
171 * Params:
172 *   name = The name of the character.
173 */
174 void createCharacterBase(string name)
175 {
176   if (_characters && (name in _characters))
177   {
178     return;
179   }
180 
181   auto character = new NovelateCharacter(name);
182 
183   _characters[character.name] = character;
184 }
185 
186 /**
187 * Updates a character with parsed configurations.
188 * Params:
189 *   characterName = The name of the character to update.
190 *   name = The name of the configuration.
191 *   value = The value of the configuration.
192 */
193 void updateCharacter(string characterName, string name, string value)
194 {
195   if (!_characters)
196   {
197     return;
198   }
199 
200   auto character = _characters.get(characterName, null);
201 
202   if (!character)
203   {
204     return;
205   }
206 
207   switch (name)
208   {
209     case "Alias":
210     {
211       character._aliasName = value;
212 
213       _characters[character._aliasName] = character;
214       break;
215     }
216     case "NameColor": character._nameColor = value; break;
217     case "About": character._about = value; break;
218     case "AboutImage": character._aboutImage = value; break;
219 
220     default:
221     {
222       character._graphics[name] = new NovelateCharacterImageCollection(value);
223       break;
224     }
225   }
226 }