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