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