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) 2008 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_RLBABEL_DLL_H_ 29 #define SRC_SYSTEMS_BASE_RLBABEL_DLL_H_ 30 31 #include <cstdint> 32 #include <memory> 33 #include <string> 34 #include <vector> 35 36 #include "machine/reallive_dll.h" 37 #include "machine/reference.h" 38 #include "systems/base/rect.h" 39 40 class TextWindow; 41 42 // Possible commands sent to the rlBabel DLL from the code. These will be 43 // passed in as the first integer argument (func) to RlBabelDLL::callDLL(). 44 enum dllFunction { 45 dllInitialise = 0, 46 dllTextoutStart = 10, 47 dllTextoutAppend = 11, 48 dllTextoutGetChar = 12, 49 dllTextoutNewScreen = 13, 50 dllClearGlosses = 20, 51 dllNewGloss = 21, 52 dllAddGloss = 22, 53 dllTestGlosses = 23, 54 endSetWindowName = 98, 55 endGetCharWinNam = 99, 56 dllSetNameMod = 100, 57 dllGetNameMod = 101, 58 dllSetWindowName = 102, 59 dllGetTextWindow = 103, 60 dllGetRCommandMod = 104, 61 dllMessageBox = 105, 62 dllSelectAdd = 200 63 }; 64 65 // Return codes from the above functions sent back to the RealLive bytecode. 66 enum getcReturn { 67 getcError = 0, 68 getcEndOfString = 1, 69 getcPrintChar = 2, 70 getcNewLine = 3, 71 getcNewScreen = 4, 72 getcSetIndent = 5, 73 getcClearIndent = 6, 74 getcBeginGloss = 7 75 }; 76 77 // Clickable on screen areas that display a message. 78 class Gloss { 79 public: 80 Gloss(const std::shared_ptr<TextWindow>& window, 81 const std::string& cp932_src, 82 int x1, 83 int y1, 84 int x2, 85 int y2); 86 ~Gloss(); 87 88 // Whether the passed in point intersects with 89 bool Contains(const Point& point); 90 text()91 const std::string& text() const { return text_; } 92 93 private: 94 // Text displayed in the gloss. 95 std::string text_; 96 97 // Clickable areas which trigger this gloss. 98 std::vector<Rect> link_areas_; 99 }; // end of class Gloss 100 101 // rlvm's implementation of the rlBabel "DLL". Handles calls from 102 // specially compiled RealLive bytecode to implement the following 103 // extra features on top of normal RL bytecode: 104 // 105 // - Text in codepages other than cp932. 106 // - Western text lineation. 107 // - "Glosses," a system of simple hyperlinks. 108 // 109 // How rlBabel works internally: 110 // 111 // Games are disassembled with kprl, their resources are translated, 112 // and are recompiled with rlBabel.kh with a special compiler flag and 113 // the line "#load 'rlBabel'" at the top of the file. rlBabel.kh 114 // redefines several normal functions to be rerouted through a 115 // CallDll() call, along with special casing for textout. 116 // 117 // rlc will compile the disassembled source differently. Instead of 118 // the normal textout method, it will add calls which will put the 119 // text in a buffer (dllTextoutStart, dllTextoutAppend). 120 // 121 // Once everything is placed in the buffer, dllTextoutGetChar will be 122 // called for a list of actions to take (getcNewLine, getcNewScreen, 123 // getcSetIndent, getcPrintChar, etc.) Each character will be pulled 124 // out of the buffer (getcPrintChar) and displayed, moving the text 125 // insertion point to a location provided by the DLL. 126 class RlBabelDLL : public RealLiveDLL { 127 public: 128 explicit RlBabelDLL(RLMachine& machine); 129 virtual ~RlBabelDLL(); 130 131 // Overridden from RealLiveDLL: 132 133 // Main entrypoint to the "DLL". It's a giant switch function that handles 134 // all the commands that Haeleth added with rlBabel. 135 virtual int CallDLL(RLMachine& machine, 136 int func, 137 int arg1, 138 int arg2, 139 int arg3, 140 int arg4) override; 141 142 virtual const std::string& GetDLLName() const override; 143 144 private: 145 // Initializes the DLL. 146 int Initialize(int dllno, int windname); 147 148 // Takes an input string and copies it to our internal buffer. 149 int TextoutAdd(const std::string& str); 150 151 // Adds characters to the internal buffer, italicizing text as it comes in. 152 void AppendChar(const char*& ch); 153 154 // Clears our internal text buffer. 155 void TextoutClear(); 156 157 // Checks if there's room on this page, and either line breaks (returns 158 // getcNewLine) or page breaks (returns getcNewScreen). 159 int TextoutLineBreak(StringReferenceIterator buf); 160 161 // Retrieves an action specified in getcReturn, which directs the side of 162 // rlBabel implemented in RealLive code. Uses buffer and xmod as output 163 // variables for the command given. 164 int TextoutGetChar(StringReferenceIterator buffer, IntReferenceIterator xmod); 165 166 // (rlBabel function not entirely understood...) 167 int StartNewScreen(const std::string& cnam); 168 169 // Sets the window name internally. This does not display the name in the 170 // case of NAME_MOD being 0 (name displayed inline), but will display it in 171 // case of NAME_MOD being 1 (name being displayed in a different window 172 // where it won't mess with our indentation rules.) 173 int SetCurrentWindowName(StringReferenceIterator buffer); 174 175 // Clears all on screen glosses. 176 int ClearGlosses(); 177 178 // Mark where this gloss begins. 179 int NewGloss(); 180 181 // Create a gloss of the text since newGloss() with the glosstext of 182 // |cp932_gloss_text|. 183 int AddGloss(const std::string& cp932_gloss_text); 184 185 // Tests if (x, y) is inside any defined glosses. If so, return true and put 186 // the glosstext in |text|. 187 int TestGlosses(int x, int y, StringReferenceIterator text, int globalwaku); 188 189 // Helper functions: 190 191 int GetCharWidth(uint16_t full_char, bool as_xmod); 192 193 bool LineBreakRequired(); 194 195 uint16_t ConsumeNextCharacter(std::string::size_type& index); 196 197 inline char& cur_pos(int offset = 0) { 198 return cp932_text_buffer[text_index + offset]; 199 } 200 inline const char& cur_pos(int offset = 0) const { 201 return cp932_text_buffer[text_index + offset]; 202 } 203 inline char& end_token(int offset = 0) { 204 return cp932_text_buffer[end_token_index + offset]; 205 } 206 inline const char& end_token(int offset = 0) const { 207 return cp932_text_buffer[end_token_index + offset]; 208 } 209 210 // Transform one of rlBabel's integer addresses into an iterator to the 211 // corresponding piece of integer memory. 212 IntReferenceIterator GetIvar(int addr); 213 214 // Transform one of rlBabel's integer addresses into an iterator to the 215 // corresponding piece of integer memory. 216 StringReferenceIterator GetSvar(int addr); 217 218 std::shared_ptr<TextWindow> GetWindow(int id); 219 220 // Whether text being added is italicized. 221 bool add_is_italic; 222 223 // Internal text buffer to which text is added by dllTextoutStart and 224 // dllTextoutAppend. Neither |text_index| or |cp932_text_buffer| are 225 // iterators or pointers into this strings character backing since I'm 226 // worried about invalidation. 227 std::string cp932_text_buffer; 228 229 // Current position in |cp932_text_buffer|. 230 std::string::size_type text_index; 231 232 // End of the current token being processed in |cp932_text_buffer|. 233 std::string::size_type end_token_index; 234 235 // Clickable on screen areas that display a message. 236 std::vector<Gloss> glosses_; 237 238 // Marker set at the start of a gloss. 239 int gloss_start_x_, gloss_start_y_; 240 241 // Reference to our enclosing system. 242 RLMachine& machine_; 243 }; // end of class RlBabelDll 244 245 #endif // SRC_SYSTEMS_BASE_RLBABEL_DLL_H_ 246