1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 /*
24 * This code is based on original Mortville Manor DOS source code
25 * Copyright (c) 1987-1989 Lankhor
26 */
27
28 #include "mortevielle/mortevielle.h"
29 #include "mortevielle/mouse.h"
30 #include "mortevielle/outtext.h"
31 #include "mortevielle/graphics.h"
32
33 #include "common/file.h"
34 #include "common/str.h"
35
36 namespace Mortevielle {
37
TextHandler(MortevielleEngine * vm)38 TextHandler::TextHandler(MortevielleEngine *vm) {
39 _vm = vm;
40 }
41
42 /**
43 * Next word
44 * @remarks Originally called 'l_motsuiv'
45 */
nextWord(int p,const char * ch,int & tab)46 int TextHandler::nextWord(int p, const char *ch, int &tab) {
47 int c = p;
48
49 while ((ch[p] != ' ') && (ch[p] != '$') && (ch[p] != '@'))
50 ++p;
51
52 return tab * (p - c);
53 }
54
55 /**
56 * Engine function - Display Text
57 * @remarks Originally called 'afftex'
58 */
displayStr(Common::String inputStr,int x,int y,int dx,int dy,int typ)59 void TextHandler::displayStr(Common::String inputStr, int x, int y, int dx, int dy, int typ) {
60 Common::String s;
61 int i, j;
62
63 // Safeguard: add $ just in case
64 inputStr += '$';
65
66 _vm->_screenSurface->putxy(x, y);
67 int tab = 6;
68 dx *= 6;
69 dy *= 6;
70 int xc = x;
71 int yc = y;
72 int xf = x + dx;
73 int yf = y + dy;
74 int p = 0;
75 bool stringParsed = (inputStr[p] == '$');
76 s = "";
77 while (!stringParsed) {
78 switch (inputStr[p]) {
79 case '@':
80 _vm->_screenSurface->drawString(s, typ);
81 s = "";
82 ++p;
83 xc = x;
84 yc += 6;
85 _vm->_screenSurface->putxy(xc, yc);
86 break;
87 case ' ':
88 s += ' ';
89 xc += tab;
90 ++p;
91 if (nextWord(p, inputStr.c_str(), tab) + xc > xf) {
92 _vm->_screenSurface->drawString(s, typ);
93 s = "";
94 xc = x;
95 yc += 6;
96 if (yc > yf) {
97 while (!_vm->keyPressed())
98 ;
99 i = y;
100 do {
101 j = x;
102 do {
103 _vm->_screenSurface->putxy(j, i);
104 _vm->_screenSurface->drawString(" ", 0);
105 j += 6;
106 } while (j <= xf);
107 i += 6;
108 } while (i <= yf);
109 yc = y;
110 }
111 _vm->_screenSurface->putxy(xc, yc);
112 }
113 break;
114 case '$':
115 stringParsed = true;
116 _vm->_screenSurface->drawString(s, typ);
117 break;
118 default:
119 s += inputStr[p];
120 ++p;
121 xc += tab;
122 break;
123 }
124 }
125 }
126
127 /**
128 * Load DES (picture container) file
129 * @remarks Originally called 'chardes'
130 */
loadPictureFile(Common::String filename,Common::String altFilename,int32 skipSize,int length)131 void TextHandler::loadPictureFile(Common::String filename, Common::String altFilename, int32 skipSize, int length) {
132 Common::File f;
133 if (!f.open(filename)) {
134 if (!f.open(altFilename))
135 error("Missing file: Either %s or %s", filename.c_str(), altFilename.c_str());
136 }
137 // HACK: The original game contains a bug in the 2nd intro screen, in German DOS version.
138 // The size specified in the fxx array is wrong (too short). In order to fix it, we are using
139 // the value -1 to force a variable read length.
140 if (length == -1)
141 length = f.size() - skipSize;
142
143 assert(skipSize + length <= f.size());
144
145 free(_vm->_curPict);
146 _vm->_curPict = (byte *)malloc(sizeof(byte) * length);
147 f.seek(skipSize);
148 f.read(_vm->_curPict, length);
149 f.close();
150 }
151
152 /**
153 * Load ANI file
154 * @remarks Originally called 'charani'
155 */
loadAniFile(Common::String filename,int32 skipSize,int length)156 void TextHandler::loadAniFile(Common::String filename, int32 skipSize, int length) {
157 Common::File f;
158 if (!f.open(filename))
159 error("Missing file - %s", filename.c_str());
160
161 assert(skipSize + length <= f.size());
162
163 free(_vm->_curAnim);
164 _vm->_curAnim = (byte *)malloc(sizeof(byte) * length);
165 f.seek(skipSize);
166 f.read(_vm->_curAnim, length);
167 f.close();
168 }
169
taffich()170 void TextHandler::taffich() {
171 static const byte tran1[] = { 121, 121, 138, 139, 120 };
172 static const byte tran2[] = { 150, 150, 152, 152, 100, 110, 159, 100, 100 };
173
174 int cx, drawingSize, npal;
175 int32 drawingStartPos;
176
177 int a = _vm->_caff;
178 if ((a >= 153) && (a <= 161))
179 a = tran2[a - 153];
180 else if ((a >= 136) && (a <= 140))
181 a = tran1[a - 136];
182 int b = a;
183 if (_vm->_maff == a)
184 return;
185
186 switch (a) {
187 case 16:
188 _vm->_coreVar._pctHintFound[9] = '*';
189 _vm->_coreVar._availableQuestion[42] = '*';
190 break;
191 case 20:
192 _vm->_coreVar._availableQuestion[39] = '*';
193 if (_vm->_coreVar._availableQuestion[36] == '*') {
194 _vm->_coreVar._pctHintFound[3] = '*';
195 _vm->_coreVar._availableQuestion[38] = '*';
196 }
197 break;
198 case 24:
199 _vm->_coreVar._availableQuestion[37] = '*';
200 break;
201 case 30:
202 _vm->_coreVar._availableQuestion[9] = '*';
203 break;
204 case 31: // Coat of arms
205 _vm->_coreVar._pctHintFound[4] = '*';
206 _vm->_coreVar._availableQuestion[35] = '*';
207 break;
208 case 118:
209 _vm->_coreVar._availableQuestion[41] = '*';
210 break;
211 case 143:
212 _vm->_coreVar._pctHintFound[1] = '*';
213 break;
214 case 150:
215 _vm->_coreVar._availableQuestion[34] = '*';
216 break;
217 case 151:
218 _vm->_coreVar._pctHintFound[2] = '*';
219 break;
220 default:
221 break;
222 }
223
224 _vm->_destinationOk = true;
225 _vm->_mouse->hideMouse();
226 drawingStartPos = 0;
227 Common::String filename, altFilename;
228
229 if ((a != 50) && (a != 51)) {
230 int m = a + 2000;
231
232 if ((m > 2001) && (m < 2010))
233 m = 2001;
234 else if (m == 2011)
235 m = 2010;
236 if (a == 32)
237 m = 2034;
238 else if ((a == 17) && (_vm->_maff == 14))
239 m = 2018;
240 else if (a > 99) {
241 if ((_vm->_is == 1) || (_vm->_is == 0))
242 m = 2031;
243 else
244 m = 2032;
245 }
246
247 if ( ((a > 69) && (a < 80)) || (a == 30) || (a == 31) || (a == 144) || (a == 147) || (a == 149) )
248 m = 2030;
249 else if ( ((a < 27) && ( ((_vm->_maff > 69) && (!_vm->_coreVar._alreadyEnteredManor)) || (_vm->_maff > 99) )) || ((_vm->_maff > 29) && (_vm->_maff < 33)) )
250 m = 2033;
251
252 _vm->displayInterScreenMessage(m);
253 _vm->_maff = a;
254
255 if (a == 159)
256 a = 86;
257 else if (a > 140)
258 a -= 67;
259 else if (a > 137)
260 a -= 66;
261 else if (a > 99)
262 a -= 64;
263 else if (a > 69)
264 a -= 42;
265 else if (a > 29)
266 a -= 5;
267 else if (a == 26)
268 a = 24;
269 else if (a > 18)
270 --a;
271 npal = a;
272
273 for (cx = 0; cx <= (a - 1); ++cx)
274 drawingStartPos += _vm->_drawingSizeArr[cx];
275 drawingSize = _vm->_drawingSizeArr[a];
276
277 altFilename = filename = "DXX.mor";
278 } else {
279 filename = "DZZ.mor";
280 altFilename = "DZZALL";
281
282 if (a == 50) {
283 // First intro screen
284 drawingStartPos = 0;
285 drawingSize = _vm->_drawingSizeArr[87];
286 } else { // a == 51
287 // Second intro screen
288 drawingStartPos = _vm->_drawingSizeArr[87];
289 // HACK: Force a variable size in order to fix the wrong size used by the German version
290 drawingSize = -1;
291 }
292 _vm->_maff = a;
293 npal = a + 37;
294 }
295 loadPictureFile(filename, altFilename, drawingStartPos, drawingSize);
296 _vm->_numpal = npal;
297 _vm->setPal(npal);
298
299 if ((b < 15) || (b == 16) || (b == 17) || (b == 24) || (b == 26) || (b == 50)) {
300 drawingStartPos = 0;
301 if ((b < 15) || (b == 16) || (b == 17) || (b == 24) || (b == 26)) {
302 if (b == 26)
303 b = 18;
304 else if (b == 24)
305 b = 17;
306 else if (b > 15)
307 --b;
308 for (cx = 0; cx <= (b - 1); ++cx)
309 drawingStartPos += _vm->_drawingSizeArr[cx + 89];
310 drawingSize = _vm->_drawingSizeArr[b + 89];
311 filename = "AXX.mor";
312 } else { // b == 50
313 // CHECKME: the size of AZZ.mor is 1280 for the DOS version
314 // and 1260 for the Amiga version. Maybe the 20 bytes
315 // are a filler (to get 10 blocks of 128 bytes),
316 // or the size should be variable.
317 drawingSize = 1260;
318 filename = "AZZ.mor";
319 }
320 loadAniFile(filename, drawingStartPos, drawingSize);
321 }
322 _vm->_mouse->showMouse();
323 if ((a < COAT_ARMS) && ((_vm->_maff < COAT_ARMS) || (_vm->_coreVar._currPlace == LANDING)) && (_vm->_currAction != _vm->_menu->_opcodeEnter)) {
324 if ((a == ATTIC) || (a == CELLAR))
325 _vm->displayAloneText();
326 else if (!_vm->_outsideOnlyFl)
327 _vm->getPresence(_vm->_coreVar._currPlace);
328 _vm->_savedBitIndex = 0;
329 }
330 }
331
332 } // End of namespace Mortevielle
333