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_TEXT_SYSTEM_H_
29 #define SRC_SYSTEMS_BASE_TEXT_SYSTEM_H_
30 
31 #include <boost/serialization/split_member.hpp>
32 #include <boost/serialization/version.hpp>
33 
34 #include <cstdint>
35 #include <list>
36 #include <memory>
37 #include <string>
38 #include <vector>
39 #include <map>
40 
41 #include "machine/long_operation.h"
42 #include "systems/base/event_listener.h"
43 
44 class Gameexe;
45 class Memory;
46 class Point;
47 class RGBColour;
48 class RLMachine;
49 class Size;
50 class Surface;
51 class System;
52 class TextKeyCursor;
53 class TextPage;
54 class TextWindow;
55 
56 // Global variables written to disk.
57 struct TextSystemGlobals {
58   TextSystemGlobals();
59   explicit TextSystemGlobals(Gameexe& gexe);
60 
61   int auto_mode_base_time;
62   int auto_mode_char_time;
63 
64   // Message speed; range from 0 to 255
65   char message_speed;
66 
67   // Whether we should be bolded.
68   int font_weight;
69 
70   // Whether we should draw a shadow.
71   int font_shadow;
72 
73   // The default #WINDOW_ATTR. This is what is changed by the
74   std::vector<int> window_attr;
75 
76   // boost::serialization support
77   template <class Archive>
serializeTextSystemGlobals78   void serialize(Archive& ar, const unsigned int version) {
79     ar& auto_mode_base_time& auto_mode_char_time& message_speed& window_attr;
80 
81     if (version > 0)
82       ar& font_weight& font_shadow;
83   }
84 };
85 
86 BOOST_CLASS_VERSION(TextSystemGlobals, 1)
87 
88 // -----------------------------------------------------------------------
89 
90 class TextSystem : public EventListener {
91  public:
92   // Internal structure used to keep track of the state of
93   typedef std::map<int, TextPage> PageSet;
94 
95  public:
96   TextSystem(System& system, Gameexe& gexe);
97   virtual ~TextSystem();
98 
99   // Controls whether the text system is rendered at all.
system_visible()100   bool system_visible() const { return system_visible_; }
set_system_visible(bool in)101   void set_system_visible(bool in) { system_visible_ = in; }
102 
103   void ExecuteTextSystem();
104 
105   void Render(std::ostream* tree);
106   void HideTextWindow(int win_number);
107   void HideAllTextWindows();
108   void HideAllTextWindowsExcept(int i);
109   void ShowTextWindow(int win_number);
110   void ShowAllTextWindows();
111   void ClearAllTextWindows();
112   void SetVisualOverride(int win_number, bool show_window);
113   void SetVisualOverrideAll(bool show_window);
114   void ClearVisualOverrides();
115   virtual std::shared_ptr<TextWindow> GetTextWindow(int text_window_number) = 0;
116   std::shared_ptr<TextWindow> GetCurrentWindow();
117 
set_in_pause_state(bool in)118   void set_in_pause_state(bool in) { in_pause_state_ = in; }
119 
active_window()120   int active_window() const { return active_window_; }
set_active_window(int window)121   void set_active_window(int window) { active_window_ = window; }
122 
123   std::vector<int> GetActiveWindows();
124 
125   // Take a snapshot of the current window state, with their
126   // respective TextPages, and add it to the backlog.
127   void Snapshot();
128 
129   // Resets the text page in the current_set
130   void NewPageOnWindow(int window);
131 
132   // Get the active page. This function will return
133   // windows_[active_window_].page().
134   TextPage& GetCurrentPage();
135 
136   // Clears the screen, moves back one page and renders it.
137   void BackPage();
138   void ForwardPage();
139 
140   void ReplayPageSet(PageSet& set, bool is_current_page);
141 
142   bool IsReadingBacklog() const;
143   void StopReadingBacklog();
144 
145   // Performs #NAMAE replacement; used in the English Edition of Clannad.
146   std::string InterpretName(const std::string& utf8name);
147 
148   // A temporary version of |message_no_wait_| controllable by the script.
set_script_message_nowait(const int in)149   void set_script_message_nowait(const int in) { script_message_no_wait_ = in; }
script_message_nowait()150   int script_message_nowait() const { return script_message_no_wait_; }
151 
152   // It is possible to set the interpreter up to advance text
153   // automatically instead of waiting for player input after each
154   // screen is displayed; the `auto mode' controls permit this
155   // behavior to be customized.
auto_mode()156   int auto_mode() const { return (int)auto_mode_; }
157   void SetAutoMode(int i);
158 
auto_base_time()159   int auto_base_time() const { return globals_.auto_mode_base_time; }
set_auto_base_time(int i)160   void set_auto_base_time(int i) { globals_.auto_mode_base_time = i; }
161 
set_auto_char_time(int i)162   void set_auto_char_time(int i) { globals_.auto_mode_char_time = i; }
autoCharTime()163   int autoCharTime() const { return globals_.auto_mode_char_time; }
164 
165   int GetAutoTime(int num_chars);
166 
167   void SetKeyCursor(int new_cursor);
168 
169   // Returns the key cursor index. (or -1 if no key cursor).
170   int GetCursorNumber() const;
171 
ctrl_key_skip()172   int ctrl_key_skip() const { return ctrl_key_skip_; }
set_ctrl_key_skip(int i)173   void set_ctrl_key_skip(int i) { ctrl_key_skip_ = i; }
174 
fast_text_mode()175   int fast_text_mode() const { return fast_text_mode_; }
set_fast_text_mode(int i)176   void set_fast_text_mode(int i) { fast_text_mode_ = i; }
177 
message_no_wait()178   int message_no_wait() const { return message_no_wait_; }
set_message_no_wait(int i)179   void set_message_no_wait(int i) { message_no_wait_ = i; }
180 
message_speed()181   int message_speed() const { return globals_.message_speed; }
set_message_speed(int i)182   void set_message_speed(int i) { globals_.message_speed = i; }
183 
font_weight()184   int font_weight() const { return globals_.font_weight; }
set_font_weight(int i)185   void set_font_weight(int i) { globals_.font_weight = i; }
186 
font_shadow()187   int font_shadow() const { return globals_.font_shadow; }
set_font_shadow(int i)188   void set_font_shadow(int i) { globals_.font_shadow = i; }
189 
window_attr()190   const std::vector<int>& window_attr() const { return globals_.window_attr; }
191   void SetDefaultWindowAttr(const std::vector<int>& attr);
192 
window_attr_r()193   int window_attr_r() const { return globals_.window_attr.at(0); }
window_attr_g()194   int window_attr_g() const { return globals_.window_attr.at(1); }
window_attr_b()195   int window_attr_b() const { return globals_.window_attr.at(2); }
window_attr_a()196   int window_attr_a() const { return globals_.window_attr.at(3); }
window_attr_f()197   int window_attr_f() const { return globals_.window_attr.at(4); }
198 
199   void SetWindowAttrR(int i);
200   void SetWindowAttrG(int i);
201   void SetWindowAttrB(int i);
202   void SetWindowAttrA(int i);
203   void SetWindowAttrF(int i);
204 
window_move_use()205   bool window_move_use() const { return move_use_; }
window_clear_use()206   bool window_clear_use() const { return clear_use_; }
window_read_jump_use()207   bool window_read_jump_use() const { return read_jump_use_; }
window_automode_use()208   bool window_automode_use() const { return automode_use_; }
window_msgbk_use()209   bool window_msgbk_use() const { return msgbk_use_; }
window_msgbkleft_use()210   bool window_msgbkleft_use() const { return msgbkleft_use_; }
window_msgbkright_use()211   bool window_msgbkright_use() const { return msgbkright_use_; }
window_exbtn_use()212   bool window_exbtn_use() const { return exbtn_use_; }
213 
214   // Update the mouse cursor.
215   void SetMousePosition(const Point& pos);
216   bool HandleMouseClick(RLMachine& machine, const Point& pos, bool pressed);
217 
218   // Save pieces of state that would be saved to disk.
219   void TakeSavepointSnapshot();
220 
221   // Returns a surface with |utf8str| rendered with the other specified
222   // properties. Will search |utf8str| for object text syntax and will change
223   // various properties based on that syntax.
224   std::shared_ptr<Surface> RenderText(const std::string& utf8str,
225                                         int size,
226                                         int xspace,
227                                         int yspace,
228                                         const RGBColour& colour,
229                                         RGBColour* shadow_colour,
230                                         int max_chars_in_line);
231 
232   // Renders a glyph onto destination. Returns the size of the glyph blitted.
233   virtual Size RenderGlyphOnto(
234       const std::string& current,
235       int font_size,
236       bool italic,
237       const RGBColour& font_colour,
238       const RGBColour* shadow_colour,
239       int insertion_point_x,
240       int insertion_point_y,
241       const std::shared_ptr<Surface>& destination) = 0;
242 
243   virtual int GetCharWidth(int size, uint16_t codepoint) = 0;
244 
245   // Whether the current font has monospaced Roman letters.
246   virtual bool FontIsMonospaced() = 0;
247 
globals()248   TextSystemGlobals& globals() { return globals_; }
249 
250   // Resets non-configuration values (so we can load games).
251   virtual void Reset();
252 
kidoku_read()253   bool kidoku_read() const { return kidoku_read_; }
254   void SetKidokuRead(const int in);
255 
skip_mode()256   bool skip_mode() const { return skip_mode_; }
257   void SetSkipMode(int in);
258 
259   bool CurrentlySkipping() const;
260 
set_in_selection_mode(const bool in)261   void set_in_selection_mode(const bool in) { in_selection_mode_ = in; }
262 
263   // Overridden from EventListener
264   virtual bool MouseButtonStateChanged(MouseButton mouse_button,
265                                        bool pressed) override;
266   virtual bool KeyStateChanged(KeyCode key_code, bool pressed) override;
267 
system()268   System& system() { return system_; }
269 
270  protected:
271   void UpdateWindowsForChangeToWindowAttr();
272 
273   bool ShowWindow(int win_num) const;
274 
275   void CheckAndSetBool(Gameexe& gexe, const std::string& key, bool& out);
276 
277   // Reduces the number of page snapshots in previous_page_sets_ down to a
278   // manageable constant number.
279   void ExpireOldPages();
280 
281   // TextPage will call our internals since it actually does most of
282   // the work while we hold state.
283   friend class TextPage;
284 
285   // Whether Auto mode is enabled
286   bool auto_mode_;
287 
288   // Whether holding down the control key will skip text.
289   bool ctrl_key_skip_;
290 
291   // Fast text mode
292   bool fast_text_mode_;
293 
294   // Internal 'no wait' flag (user customization)
295   bool message_no_wait_;
296 
297   // 'No wait' flag under script control.
298   bool script_message_no_wait_;
299 
300   // Sets which window is the current active window.
301   int active_window_;
302 
303   // Type of the Window storage
304   typedef std::map<int, std::shared_ptr<TextWindow>> WindowMap;
305 
306   // Storage of active windows
307   WindowMap text_window_;
308 
309   // Whether we are reading the backlog
310   bool is_reading_backlog_;
311 
312   // The current page set. Represents what is on the screen right now.
313   PageSet current_pageset_;
314 
315   // Name mappings. Clannad English Edition maps name boxes from the key to the
316   // value.
317   std::map<std::string, std::string> namae_mapping_;
318 
319   // Previous Text Pages. The TextSystem owns the list of previous
320   // pages because multiple windows can be displayed in one text page.
321   std::list<PageSet> previous_page_sets_;
322 
323   // When previous_page_it_ == previous_pages_.end(), active_page_ is
324   // currently being rendered to the screen. When it is any valid
325   // iterator pointing into previous_pages_, that is the current page
326   // being rendered.
327   std::list<PageSet>::iterator previous_page_it_;
328 
329   // Whether we are in a state where the interpreter is pause()d.
330   bool in_pause_state_;
331 
332   std::shared_ptr<TextKeyCursor> text_key_cursor_;
333 
334   bool move_use_, clear_use_, read_jump_use_, automode_use_, msgbk_use_,
335       msgbkleft_use_, msgbkright_use_, exbtn_use_;
336 
337   TextSystemGlobals globals_;
338 
339   bool system_visible_;
340 
341   // Whether we skip text that we've already seen
342   bool skip_mode_;
343 
344   // Whether we are currently on a page of text that we've previously read.
345   bool kidoku_read_;
346 
347   // Whether we are currently paused at a user choice.
348   bool in_selection_mode_;
349 
350   // Contains overrides for showing or hiding the text windows.
351   std::map<int, bool> window_visual_override_;
352 
353   // Our parent system object.
354   System& system_;
355 
356   // This state can change after the last savepoint marker. These are the
357   // values that should be saved to disk.
358   int savepoint_active_window_;
359   int savepoint_cursor_number_;
360 
361   // boost::serialization support
362   friend class boost::serialization::access;
363 
364   template <class Archive>
365   void save(Archive& ar, const unsigned int file_version) const;
366 
367   template <class Archive>
368   void load(Archive& ar, const unsigned int file_version);
369 
370   BOOST_SERIALIZATION_SPLIT_MEMBER()
371 };
372 
373 // Name parser. Takes a raw, local machine encoded string and replaces name
374 // variable placeholders with the names from Memory. This function assumes that
375 // text is in CP932 encoding, and will need to be generalized when we try to
376 // support other hacks on top of cp932.
377 void parseNames(const Memory& memory,
378                 const std::string& input,
379                 std::string& output);
380 
381 // LongOperation which just calls text().set_system_visible(true) and removes
382 // itself from the callstack.
383 struct RestoreTextSystemVisibility : public LongOperation {
384   virtual bool operator()(RLMachine& machine);
385 };
386 
387 #endif  // SRC_SYSTEMS_BASE_TEXT_SYSTEM_H_
388