1 // -*- Mode: C++; tab-width:2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 // vi:tw=80:et:ts=2:sts=2
3 //
4 // -----------------------------------------------------------------------
5 //
6 // This file is part of RLVM, a RealLive virtual machine clone.
7 //
8 // -----------------------------------------------------------------------
9 //
10 // Copyright (C) 2006, 2007 Elliot Glaysher
11 //
12 // This program is free software; you can redistribute it and/or modify
13 // it under the terms of the GNU General Public License as published by
14 // the Free Software Foundation; either version 3 of the License, or
15 // (at your option) any later version.
16 //
17 // This program is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 // GNU General Public License for more details.
21 //
22 // You should have received a copy of the GNU General Public License
23 // along with this program; if not, write to the Free Software
24 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
25 //
26 // -----------------------------------------------------------------------
27 
28 #ifndef SRC_SYSTEMS_BASE_SYSTEM_H_
29 #define SRC_SYSTEMS_BASE_SYSTEM_H_
30 
31 #include <boost/serialization/access.hpp>
32 #include <boost/serialization/version.hpp>
33 #include <boost/filesystem/path.hpp>
34 
35 #include <map>
36 #include <sstream>
37 #include <string>
38 #include <utility>
39 #include <vector>
40 
41 class GraphicsSystem;
42 class EventSystem;
43 class TextSystem;
44 class SoundSystem;
45 class RLMachine;
46 class Gameexe;
47 class GameexeInterpretObject;
48 class Platform;
49 
50 // Syscom Constants
51 //
52 // Associations between syscom integer values and their names.
53 const int NUM_SYSCOM_ENTRIES = 32;
54 const int SYSCOM_INVISIBLE = 0;
55 const int SYSCOM_VISIBLE = 1;
56 const int SYSCOM_GREYED_OUT = 2;
57 
58 const int SYSCOM_SAVE = 0;
59 const int SYSCOM_LOAD = 1;
60 const int SYSCOM_MESSAGE_SPEED = 2;
61 const int SYSCOM_WINDOW_ATTRIBUTES = 3;
62 const int SYSCOM_VOLUME_SETTINGS = 4;
63 const int SYSCOM_SCREEN_MODE = 5;
64 const int SYSCOM_MISCELLANEOUS_SETTINGS = 6;
65 // No 7?
66 const int SYSCOM_VOICE_SETTINGS = 8;
67 const int SYSCOM_FONT_SELECTION = 9;
68 const int SYSCOM_BGM_FADE = 10;
69 const int SYSCOM_BGM_SETTINGS = 11;
70 const int SYSCOM_WINDOW_DECORATION_STYLE = 12;
71 const int SYSCOM_AUTO_MODE_SETTINGS = 13;
72 const int SYSCOM_RETURN_TO_PREVIOUS_SELECTION = 14;
73 const int SYSCOM_USE_KOE = 15;
74 const int SYSCOM_DISPLAY_VERSION = 16;
75 const int SYSCOM_SHOW_WEATHER = 17;
76 const int SYSCOM_SHOW_OBJECT_1 = 18;
77 const int SYSCOM_SHOW_OBJECT_2 = 19;
78 const int SYSCOM_CLASSIFY_TEXT = 20;  // ??????? Unknown function.
79 const int SYSCOM_GENERIC_1 = 21;
80 const int SYSCOM_GENERIC_2 = 22;
81 // No 23?
82 const int SYSCOM_OPEN_MANUAL_PATH = 24;
83 const int SYSCOM_SET_SKIP_MODE = 25;
84 const int SYSCOM_AUTO_MODE = 26;
85 // No 27?
86 const int SYSCOM_MENU_RETURN = 28;
87 const int SYSCOM_EXIT_GAME = 29;
88 const int SYSCOM_HIDE_MENU = 30;
89 const int SYSCOM_SHOW_BACKGROUND = 31;
90 
91 // File type constants.
92 //
93 // These constant, externed vectors are passed as parameters to
94 // FindFile to control which file types are searched for. Defaults to
95 // all.
96 extern const std::vector<std::string> OBJ_FILETYPES;
97 extern const std::vector<std::string> IMAGE_FILETYPES;
98 extern const std::vector<std::string> PDT_IMAGE_FILETYPES;
99 extern const std::vector<std::string> GAN_FILETYPES;
100 extern const std::vector<std::string> ANM_FILETYPES;
101 extern const std::vector<std::string> HIK_FILETYPES;
102 extern const std::vector<std::string> SOUND_FILETYPES;
103 extern const std::vector<std::string> KOE_ARCHIVE_FILETYPES;
104 extern const std::vector<std::string> KOE_LOOSE_FILETYPES;
105 
106 // Struct containing the global memory to get serialized to disk with
107 // global memory.
108 struct SystemGlobals {
109   SystemGlobals();
110 
111   // Whether we should put up a yes/no dialog box when saving/loading.
112   bool confirm_save_load_;
113 
114   // I suspect that this is a placebo. I'll track the value, but I don't think
115   // it's relevant to anything.
116   bool low_priority_;
117 
118   // boost::serialization support
119   template <class Archive>
serializeSystemGlobals120   void serialize(Archive& ar, const unsigned int version) {
121     ar& confirm_save_load_;
122 
123     if (version > 0)
124       ar& low_priority_;
125   }
126 };
127 
128 BOOST_CLASS_VERSION(SystemGlobals, 1)
129 
130 // The system class provides a generalized interface to all the
131 // components that make up a local system that may need to be
132 // implemented differently on different systems, i.e., sound,
133 // graphics, filesystem etc.
134 //
135 // The base System class is an abstract base class that is meant to be
136 // specialized.
137 class System {
138  public:
139   System();
140   virtual ~System();
141 
confirm_save_load()142   bool confirm_save_load() const { return globals_.confirm_save_load_; }
set_confirm_save_load(const int in)143   void set_confirm_save_load(const int in) { globals_.confirm_save_load_ = in; }
144 
low_priority()145   bool low_priority() const { return globals_.low_priority_; }
set_low_priority(const int in)146   void set_low_priority(const int in) { globals_.low_priority_ = in; }
147 
platform()148   std::shared_ptr<Platform> platform() { return platform_; }
149   void SetPlatform(const std::shared_ptr<Platform>& platform);
150 
151   // Whether we're currently forcing fast forward (only used during game tests
152   // to zoom through).
force_fast_forward()153   bool force_fast_forward() { return force_fast_forward_; }
154   // Set in lua_rlvm, to speed through the game with maximum speed!
set_force_fast_forward()155   void set_force_fast_forward() { force_fast_forward_ = true; }
156 
force_wait()157   bool force_wait() { return force_wait_; }
set_force_wait(bool in)158   void set_force_wait(bool in) { force_wait_ = in; }
159 
160   // We record what the text encoding response was during the first scene, and
161   // then during every scene change, if it was western, we flip this bit to
162   // true. We do this as a big hack because we only have System access while
163   // we're loading fonts.
use_western_font()164   bool use_western_font() { return use_western_font_; }
set_use_western_font()165   void set_use_western_font() { use_western_font_ = true; }
166 
167   // Takes and restores the previous selection snapshot; a special emphemeral
168   // save game slot that autosaves on selections and is restored through a
169   // special kepago method/syscom call.
170   void TakeSelectionSnapshot(RLMachine& machine);
171   void RestoreSelectionSnapshot(RLMachine& machine);
172 
173   // Syscom related functions
174   //
175   // RealLive provides a context menu system to handle most actions
176   // and configuration settings. The system command menu is configured
177   // with the \#SYSCOM variables in gameexe.ini. It can be disabled by
178   // setting \#SYSCOM_USE to 0, and if a \#CANCELCALL hook is defined it
179   // will never be used at all (Clannad does this, although it uses
180   // the internal flags associated with the system command menu to
181   // control its own menu system).
182   //
183   // These functions are used to manipulate the visibility, change the
184   // values of, and invoke standard dialogs for various SYSCOM elements.
185 
186   // Checks the visibility of a single syscom command. Returns 0 if the given
187   // system command is invisible, 1 if it is visible, and 2 if it is visible
188   // but disabled (greyed out).
189   int IsSyscomEnabled(int syscom);
190 
191   // Hides all syscom entries
192   void HideSyscom();
193 
194   // Hides the syscom entry |syscom|
195   void HideSyscomEntry(int syscom);
196 
197   // Enables all syscom entries
198   void EnableSyscom();
199 
200   // Enables the syscom entry |syscom|
201   void EnableSyscomEntry(int syscom);
202 
203   // Disables all syscom entries
204   void DisableSyscom();
205 
206   // Disables the syscom entry |syscom|
207   void DisableSyscomEntry(int syscom);
208 
209   // Reads the corresponding value for syscom number |syscom|
210   int ReadSyscom(int syscom);
211 
212   // Called by various LongOperations to show the right click menu.
213   void ShowSyscomMenu(RLMachine& machine);
214 
215   // If there is a standard dialog box associated with syscom, it is
216   // displayed; if there is a standard action, it is performed. The list of
217   // menu commands in section 4.5 has details of which menu commands have
218   // standard dialogs. The optional value is used for the setting where
219   // relevant (for example, InvokeSyscom(5, val) is exactly equivalent to
220   // SetScreenMode(val)).
221   void InvokeSyscom(RLMachine& machine, int syscom);
222 
223   // Shows a screen with certain information about the current state of the
224   // interpreter.
225   void ShowSystemInfo(RLMachine& machine);
226 
227   // Finds a file on disk based on its basename with a list of possible
228   // extensions, or empty() if file not found.
229   boost::filesystem::path FindFile(const std::string& fileName,
230                                    const std::vector<std::string>& extensions);
231 
232   // Resets the present values of the system; this doesn't clear user settings,
233   // but clears things like the current graphics state and the status of all
234   // the text windows. This method is called when the user loads a game or
235   // resets the machine. The System implementation of reset() will call
236   // reset() on all systems.
237   void Reset();
238 
239   // Returns the global state for saving/restoring
globals()240   SystemGlobals& globals() { return globals_; }
241 
242   // Cleans the regname entry from the gameexe and makes it filesystem
243   // safe. This translates it to UTF-8, as Gameexe files are written in
244   // Shift-JIS.
245   std::string Regname();
246 
247   // Returns a boost::filesystem object which points to the directory
248   // where saved game data, preferences, etc should be stored
249   // for this game.
250   //
251   // The default implementation returns "~/.rlvm/#{REGNAME}/". A Mac
252   // specific override could return "~/Library/Application
253   // Support/rlvm/#{REGNAME}/"
254   boost::filesystem::path GameSaveDirectory();
255 
256   // Testing and Debugging Tools
257 
258   // Whether we are zooming through text and events quickly. Currently can be
259   // triggered by holding down the control key, or using skip previously read
260   // text.
261   bool ShouldFastForward();
262 
263   // Renders the screen and dumps a textual representation of the screen.
264   void DumpRenderTree(RLMachine& machine);
265 
266   // Called once per gameloop.
267   virtual void Run(RLMachine& machine) = 0;
268 
269   // Returns the specific subclasses.
270   virtual GraphicsSystem& graphics() = 0;
271   virtual EventSystem& event() = 0;
272   virtual Gameexe& gameexe() = 0;
273   virtual TextSystem& text() = 0;
274   virtual SoundSystem& sound() = 0;
275 
276  protected:
277   // Native widget drawer. Can be NULL. This field is protected instead of
278   // private because we need to be destroy the Platform before we destroy SDL.
279   std::shared_ptr<Platform> platform_;
280 
281  private:
282   typedef std::multimap<std::string,
283                         std::pair<std::string, boost::filesystem::path>>
284       FileSystemCache;
285 
286   boost::filesystem::path GetHomeDirectory();
287 
288   // Invokes a custom dialog or the standard one if none present.
289   void InvokeSaveOrLoad(RLMachine& machine,
290                         int syscom,
291                         const std::string& mod_key,
292                         const std::string& location);
293 
294   // Verify that |index| is valid and throw if it isn't.
295   void CheckSyscomIndex(int index, const char* function);
296 
297   // Builds a list of all files that are in a directory specified in the
298   // #FOLDNAME part of the Gameexe.ini file.
299   void BuildFileSystemCache();
300 
301   // Recurses on |directory| and adds all filetypes that we can read to our
302   // FileSystemCache.
303   void AddDirectoryToCache(const boost::filesystem::path& directory);
304 
305   // The visibility status for all syscom entries
306   int syscom_status_[NUM_SYSCOM_ENTRIES];
307 
308   // Whether the SYSCOM menu is currently being displayed.
309   bool in_menu_;
310 
311   // Whether we are being forced to fast forward through the game for testing
312   // reasons.
313   bool force_fast_forward_;
314 
315   // Forces a 10ms sleep at the end of the System::run function. Used to lower
316   // CPU usage during manual redrawing.
317   bool force_wait_;
318 
319   // Whether we should be trying to find a western font.
320   bool use_western_font_;
321 
322   // Cached view of the filesystem, mapping a lowercase filename to an
323   // extension and the local file path for that file.
324   FileSystemCache filesystem_cache_;
325 
326   SystemGlobals globals_;
327 
328   // A stream with the save game data at the time of the last selection. Used
329   // for the Return to Previous Selection feature.
330   std::shared_ptr<std::stringstream> previous_selection_;
331 
332   // Implementation detail which resets in_menu_;
333   friend class MenuReseter;
334 
335   friend class boost::serialization::access;
336 
337   // boost::serialization
338   template <class Archive>
serialize(Archive & ar,unsigned int version)339   void serialize(Archive& ar, unsigned int version) {
340     // For now, does nothing
341   }
342 };
343 
344 // -----------------------------------------------------------------------
345 
346 // Returns a version string suitable for printing. Used on the command line
347 // interface and on the info screen.
348 std::string GetRlvmVersionString();
349 
350 #endif  // SRC_SYSTEMS_BASE_SYSTEM_H_
351