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 Tony Tough source code
25 *
26 * Copyright (c) 1997-2003 Nayma Software
27 */
28
29 #include "common/textconsole.h"
30 #include "tony/mpal/mpalutils.h"
31 #include "tony/font.h"
32 #include "tony/input.h"
33 #include "tony/inventory.h"
34 #include "tony/loc.h"
35 #include "tony/tony.h"
36
37 namespace Tony {
38
39 /****************************************************************************\
40 * RMFont Methods
41 \****************************************************************************/
42
RMFont()43 RMFont::RMFont() {
44 _letter = NULL;
45 _nLetters = _fontDimx = _fontDimy = _dimx = _dimy = 0;
46 }
47
~RMFont()48 RMFont::~RMFont() {
49 unload();
50 }
51
load(const byte * buf,int nChars,int dimx,int dimy,uint32 palResID)52 void RMFont::load(const byte *buf, int nChars, int dimx, int dimy, uint32 palResID) {
53 _letter = new RMGfxSourceBuffer8RLEByte[nChars];
54
55 // Initialize the fonts
56 for (int i = 0; i < nChars; i++) {
57 // Initialize the buffer with the letters
58 _letter[i].init(buf + i * (dimx * dimy + 8) + 8, dimx, dimy);
59 _letter[i].loadPaletteWA(palResID);
60 }
61
62 _fontDimx = dimx;
63 _fontDimy = dimy;
64
65 _nLetters = nChars;
66 }
67
load(uint32 resID,int nChars,int dimx,int dimy,uint32 palResID)68 void RMFont::load(uint32 resID, int nChars, int dimx, int dimy, uint32 palResID) {
69 RMRes res(resID);
70
71 if ((int)res.size() < nChars * (dimy * dimx + 8))
72 nChars = res.size() / (dimy * dimx + 8);
73
74 load(res, nChars, dimx, dimy, palResID);
75 }
76
unload()77 void RMFont::unload() {
78 if (_letter != NULL) {
79 delete[] _letter;
80 _letter = NULL;
81 }
82 }
83
makeLetterPrimitive(byte bChar,int & nLength)84 RMGfxPrimitive *RMFont::makeLetterPrimitive(byte bChar, int &nLength) {
85 RMFontPrimitive *prim;
86
87 // Convert from character to glyph index
88 int nLett = convertToLetter(bChar);
89 assert(nLett < _nLetters);
90
91 // Create primitive font
92 prim = new RMFontPrimitive(this);
93 prim->_nChar = nLett;
94
95 // Get the length of the character in pixels
96 nLength = letterLength(bChar);
97
98 return prim;
99 }
100
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim2)101 void RMFont::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim2) {
102 CORO_BEGIN_CONTEXT;
103 CORO_END_CONTEXT(_ctx);
104
105 RMFontPrimitive *prim = (RMFontPrimitive *)prim2;
106
107 CORO_BEGIN_CODE(_ctx);
108
109 // Call the draw method of the letter assigned to the primitive
110 if (prim->_nChar != -1)
111 CORO_INVOKE_2(_letter[prim->_nChar].draw, bigBuf, prim);
112
113 CORO_END_CODE;
114 }
115
close()116 void RMFont::close() {
117 unload();
118 }
119
stringLen(const Common::String & text)120 int RMFont::stringLen(const Common::String &text) {
121 if (text.empty())
122 return letterLength('\0');
123
124 uint len = 0;
125 uint i;
126 for (i = 0; i < text.size() - 1; i++)
127 len += letterLength(text[i], text[i + 1]);
128 len += letterLength(text[i]);
129
130 return len;
131 }
132
stringLen(char bChar,char bNext)133 int RMFont::stringLen(char bChar, char bNext) {
134 return letterLength(bChar, bNext);
135 }
136
137 /****************************************************************************\
138 * RMFontColor Methods
139 \****************************************************************************/
140
RMFontColor()141 RMFontColor::RMFontColor() {
142 _fontR = _fontG = _fontB = 255;
143 }
144
~RMFontColor()145 RMFontColor::~RMFontColor() {
146 }
147
setBaseColor(byte r1,byte g1,byte b1)148 void RMFontColor::setBaseColor(byte r1, byte g1, byte b1) {
149 int r = (int)r1 << 16;
150 int g = (int)g1 << 16;
151 int b = (int)b1 << 16;
152
153 int rstep = r / 14;
154 int gstep = g / 14;
155 int bstep = b / 14;
156
157 byte pal[768 * 3];
158
159 // Check if we are already on the right color
160 if (_fontR == r1 && _fontG == g1 && _fontB == b1)
161 return;
162
163 _fontR = r1;
164 _fontG = g1;
165 _fontB = b1;
166
167 // Constructs a new palette for the font
168 for (int i = 1; i < 16; i++) {
169 pal[i * 3 + 0] = r >> 16;
170 pal[i * 3 + 1] = g >> 16;
171 pal[i * 3 + 2] = b >> 16;
172
173 r -= rstep;
174 g -= gstep;
175 b -= bstep;
176 }
177
178 pal[15 * 3 + 0] += 8;
179 pal[15 * 3 + 1] += 8;
180 pal[15 * 3 + 2] += 8;
181
182 // Puts in all the letters
183 for (int i = 0; i < _nLetters; i++)
184 _letter[i].loadPaletteWA(pal);
185 }
186
187 /***************************************************************************\
188 * RMFontWithTables Methods
189 \****************************************************************************/
convertToLetter(byte nChar)190 int RMFontWithTables::convertToLetter(byte nChar) {
191 return _cTable[nChar];
192 }
193
letterLength(int nChar,int nNext)194 int RMFontWithTables::letterLength(int nChar, int nNext) {
195 return (nChar != -1 ? _lTable[(byte)nChar] + _l2Table[(byte)nChar][(byte)nNext] : _lDefault);
196 }
197
198 /***************************************************************************\
199 * RMFontDialog Methods
200 \****************************************************************************/
201
init()202 void RMFontDialog::init() {
203 // bernie: Number of characters in the font
204 int nchars =
205 112 // base
206 + 18 // polish
207 + 66 // russian
208 + 30 // czech
209 + 8 // french
210 + 5; // deutsch
211
212 load(RES_F_PARL, nchars, 20, 20);
213
214 // Initialize the font table
215 _lDefault = 13;
216 _hDefault = 18;
217 Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
218
219 for (int i = 0; i < 256; i++) {
220 _cTable[i] = g_vm->_cTableDialog[i];
221 _lTable[i] = g_vm->_lTableDialog[i];
222 }
223 }
224
225 /***************************************************************************\
226 * RMFontMacc Methods
227 \****************************************************************************/
228
init()229 void RMFontMacc::init() {
230 // bernie: Number of characters in the font
231 int nchars =
232 102 // base
233 + 18 // polish
234 + 66 // russian
235 + 30 // czech
236 + 8 // francais
237 + 5; // deutsch
238
239 load(RES_F_MACC, nchars, 11, 16);
240
241 // Default
242 _lDefault = 10;
243 _hDefault = 17;
244 Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
245
246 for (int i = 0; i < 256; i++) {
247 _cTable[i] = g_vm->_cTableMacc[i];
248 _lTable[i] = g_vm->_lTableMacc[i];
249 }
250 }
251
252 /***************************************************************************\
253 * RMFontCredits Methods
254 \****************************************************************************/
255
init()256 void RMFontCredits::init() {
257 // bernie: Number of characters in the font
258 int nchars =
259 112 // base
260 + 18 // polish
261 + 66 // russian
262 + 30 // czech
263 + 8 // french
264 + 2; // deutsch
265
266 load(RES_F_CREDITS, nchars, 27, 28, RES_F_CPAL);
267
268 // Default
269 _lDefault = 10;
270 _hDefault = 28;
271 Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
272
273 for (int i = 0; i < 256; i++) {
274 _cTable[i] = g_vm->_cTableCred[i];
275 _lTable[i] = g_vm->_lTableCred[i];
276 }
277 }
278
279 /***************************************************************************\
280 * RMFontObj Methods
281 \****************************************************************************/
282
283 #define TOUPPER(a) ((a) >= 'a' && (a) <= 'z' ? (a) + 'A' - 'a' : (a))
284 #define TOLOWER(a) ((a) >= 'A' && (a) <= 'Z' ? (a) + 'a' - 'A' : (a))
285
setBothCase(int nChar,int nNext,signed char spiazz)286 void RMFontObj::setBothCase(int nChar, int nNext, signed char spiazz) {
287 _l2Table[TOUPPER(nChar)][TOUPPER(nNext)] = spiazz;
288 _l2Table[TOUPPER(nChar)][TOLOWER(nNext)] = spiazz;
289 _l2Table[TOLOWER(nChar)][TOUPPER(nNext)] = spiazz;
290 _l2Table[TOLOWER(nChar)][TOLOWER(nNext)] = spiazz;
291 }
292
init()293 void RMFontObj::init() {
294 //bernie: Number of characters in the font (solo maiuscolo)
295 int nchars =
296 85 // base
297 + 9 // polish
298 + 33 // russian
299 + 15 // czech
300 + 0 // francais (no uppercase chars)
301 + 1; // deutsch
302
303 load(RES_F_OBJ, nchars, 25, 30);
304
305 // Initialize the font table
306 _lDefault = 26;
307 _hDefault = 30;
308 Common::fill(&_l2Table[0][0], &_l2Table[0][0] + (256 * 256), '\0');
309
310 for (int i = 0; i < 256; i++) {
311 _cTable[i] = g_vm->_cTableObj[i];
312 _lTable[i] = g_vm->_lTableObj[i];
313 }
314
315 // Special case
316 setBothCase('C', 'C', 2);
317 setBothCase('A', 'T', -2);
318 setBothCase('R', 'S', 2);
319 setBothCase('H', 'I', -2);
320 setBothCase('T', 'S', 2);
321 setBothCase('O', 'R', 2);
322 setBothCase('O', 'L', 2);
323 setBothCase('O', 'G', 2);
324 setBothCase('Z', 'A', -1);
325 setBothCase('R', 'R', 1);
326 setBothCase('R', 'U', 3);
327 }
328
329 /****************************************************************************\
330 * RMText Methods
331 \****************************************************************************/
332
333 RMFontColor *RMText::_fonts[4] = { NULL, NULL, NULL, NULL };
334
initStatics()335 void RMText::initStatics() {
336 Common::fill(&_fonts[0], &_fonts[4], (RMFontColor *)NULL);
337 }
338
RMText()339 RMText::RMText() {
340 // Default color: white
341 _textR = _textG = _textB = 255;
342
343 // Default length
344 _maxLineLength = 350;
345
346 _bTrasp0 = true;
347 _aHorType = HCENTER;
348 _aVerType = VTOP;
349 setPriority(150);
350 }
351
~RMText()352 RMText::~RMText() {
353 }
354
unload()355 void RMText::unload() {
356 if (_fonts[0] != NULL) {
357 delete _fonts[0];
358 delete _fonts[1];
359 delete _fonts[2];
360 delete _fonts[3];
361 _fonts[0] = _fonts[1] = _fonts[2] = _fonts[3] = 0;
362 }
363 }
364
setMaxLineLength(int max)365 void RMText::setMaxLineLength(int max) {
366 _maxLineLength = max;
367 }
368
removeThis(CORO_PARAM,bool & result)369 void RMText::removeThis(CORO_PARAM, bool &result) {
370 // Here we can do checks on the number of frames, time spent, etc.
371 result = true;
372 }
373
writeText(const Common::String & text,int nFont,int * time)374 void RMText::writeText(const Common::String &text, int nFont, int *time) {
375 // Initializes the font (only once)
376 if (_fonts[0] == NULL) {
377 _fonts[0] = new RMFontDialog;
378 _fonts[0]->init();
379 _fonts[1] = new RMFontObj;
380 _fonts[1]->init();
381 _fonts[2] = new RMFontMacc;
382 _fonts[2]->init();
383 _fonts[3] = new RMFontCredits;
384 _fonts[3]->init();
385 }
386
387 writeText(text, _fonts[nFont], time);
388 }
389
writeText(Common::String text,RMFontColor * font,int * time)390 void RMText::writeText(Common::String text, RMFontColor *font, int *time) {
391 RMGfxPrimitive *prim;
392
393 // Set the base color
394 font->setBaseColor(_textR, _textG, _textB);
395
396 // Destroy the buffer before starting
397 destroy();
398
399 // If the string is empty, do nothing
400 if (text.empty())
401 return;
402
403 // Divide the words into lines. In this cycle, X contains the maximum length reached by a line,
404 // and the number of lines
405 Common::Array<Common::String> lines;
406 uint p = 0;
407 int j = 0;
408 int x = 0;
409 while (p < text.size()) {
410 j += font->stringLen(text[p]);
411 if (j > (((_aHorType == HLEFTPAR) && (lines.size() > 0)) ? _maxLineLength - 25 : _maxLineLength)) {
412 j -= font->stringLen(text[p], (p + 1 == text.size()) ? '\0' : text[p + 1]);
413 if (j > x)
414 x = j;
415
416 // Back to the first usable space
417 //
418 // BERNIE: In the original, sentences containing words that exceed the
419 // width of a line caused discontinuation of the whole sentence.
420 // This workaround has the partial word broken up so it will still display
421 //
422 uint old_p = p;
423 while (text[p] != ' ' && text[p] != '-' && p > 0)
424 p--;
425
426 if (p == 0)
427 p = old_p;
428
429 // Check if there are any blanks to end
430 while ((text[p] == ' ' || text[p] == '-') && p + 1 < text.size())
431 p++;
432 if (p == text.size())
433 break;
434 lines.push_back(Common::String(text.c_str(), p));
435 if (text[p] == ' ')
436 p++;
437 text = text.c_str() + p;
438 p = 0;
439 j = 0;
440 continue;
441 }
442 p++;
443 }
444
445 if (j > x)
446 x = j;
447
448 // Add the last line of text.
449 lines.push_back(text);
450
451 x += 8;
452
453 // Starting position for the surface: X1, Y
454 int width = x;
455 int height = (lines.size() - 1) * font->letterHeight() + font->_fontDimy;
456
457 // Create the surface
458 create(width, height);
459 Common::fill(_buf, _buf + width * height * 2, 0);
460
461 p = 0;
462
463 int y = 0;
464 int numchar = 0;
465 for (uint i = 0; i < lines.size(); ++i) {
466 const Common::String &line = lines[i];
467
468 // Measure the length of the line
469 x = 0;
470 j = font->stringLen(line);
471
472 switch (_aHorType) {
473 case HLEFT:
474 default:
475 x = 0;
476 break;
477
478 case HLEFTPAR:
479 if (i == 0)
480 x = 0;
481 else
482 x = 25;
483 break;
484
485 case HCENTER:
486 x = width / 2 - j / 2;
487 break;
488
489 case HRIGHT:
490 x = width - j - 1;
491 break;
492 }
493
494 p = 0;
495 while (p < line.size()) {
496 if (line[p] == ' ') {
497 x += font->stringLen(line[p]);
498 p++;
499 continue;
500 }
501
502 int len;
503 prim = font->makeLetterPrimitive(line[p], len);
504 prim->getDst()._x1 = x;
505 prim->getDst()._y1 = y;
506 addPrim(prim);
507
508 numchar++;
509
510 x += font->stringLen(line[p], (p + 1 == line.size()) ? '\0' : line[p + 1]);
511 p++;
512 }
513 p++;
514 y += font->letterHeight();
515 }
516
517 if (time != NULL)
518 *time = 1000 + numchar * (11 - GLOBALS._nCfgTextSpeed) * 14;
519 }
520
clipOnScreen(RMGfxPrimitive * prim)521 void RMText::clipOnScreen(RMGfxPrimitive *prim) {
522 // Don't let it go outside the screen
523 if (prim->getDst()._x1 < 5)
524 prim->getDst()._x1 = 5;
525 if (prim->getDst()._y1 < 5)
526 prim->getDst()._y1 = 5;
527 if (prim->getDst()._x1 + _dimx > 635)
528 prim->getDst()._x1 = 635 - _dimx;
529 if (prim->getDst()._y1 + _dimy > 475)
530 prim->getDst()._y1 = 475 - _dimy;
531 }
532
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim)533 void RMText::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
534 CORO_BEGIN_CONTEXT;
535 CORO_END_CONTEXT(_ctx);
536
537 CORO_BEGIN_CODE(_ctx);
538 // Horizontally
539 if (_aHorType == HCENTER)
540 prim->getDst().topLeft() -= RMPoint(_dimx / 2, 0);
541 else if (_aHorType == HRIGHT)
542 prim->getDst().topLeft() -= RMPoint(_dimx, 0);
543
544 // Vertically
545 if (_aVerType == VTOP) {
546
547 } else if (_aVerType == VCENTER) {
548 prim->getDst()._y1 -= _dimy / 2;
549
550 } else if (_aVerType == VBOTTOM) {
551 prim->getDst()._y1 -= _dimy;
552 }
553
554 clipOnScreen(prim);
555
556 CORO_INVOKE_2(RMGfxWoodyBuffer::draw, bigBuf, prim);
557
558 CORO_END_CODE;
559 }
560
561 /**
562 * Set the alignment type
563 */
setAlignType(HorAlign aHor,VerAlign aVer)564 void RMText::setAlignType(HorAlign aHor, VerAlign aVer) {
565 _aHorType = aHor;
566 _aVerType = aVer;
567 }
568
569 /**
570 * Set the base color
571 */
setColor(byte r,byte g,byte b)572 void RMText::setColor(byte r, byte g, byte b) {
573 _textR = r;
574 _textG = g;
575 _textB = b;
576 }
577
578 /****************************************************************************\
579 * RMTextDialog Methods
580 \****************************************************************************/
581
RMTextDialog()582 RMTextDialog::RMTextDialog() : RMText() {
583 _time = _startTime = 0;
584 _dst = RMPoint(0, 0);
585
586 _bSkipStatus = true;
587 _bShowed = true;
588 _bForceTime = false;
589 _bForceNoTime = false;
590 _bAlwaysDisplay = false;
591 _bNoTab = false;
592 _hCustomSkip = CORO_INVALID_PID_VALUE;
593 _hCustomSkip2 = CORO_INVALID_PID_VALUE;
594 _input = NULL;
595
596 // Create the event for displaying the end
597 _hEndDisplay = CoroScheduler.createEvent(false, false);
598 }
599
~RMTextDialog()600 RMTextDialog::~RMTextDialog() {
601 CoroScheduler.closeEvent(_hEndDisplay);
602 }
603
show()604 void RMTextDialog::show() {
605 _bShowed = true;
606 }
607
hide(CORO_PARAM)608 void RMTextDialog::hide(CORO_PARAM) {
609 _bShowed = false;
610 }
611
writeText(const Common::String & text,int font,int * time)612 void RMTextDialog::writeText(const Common::String &text, int font, int *time) {
613 RMText::writeText(text, font, &_time);
614
615 if (time != NULL)
616 *time = _time;
617 }
618
writeText(const Common::String & text,RMFontColor * font,int * time)619 void RMTextDialog::writeText(const Common::String &text, RMFontColor *font, int *time) {
620 RMText::writeText(text, font, &_time);
621
622 if (time != NULL)
623 *time = _time;
624 }
625
setSkipStatus(bool bEnabled)626 void RMTextDialog::setSkipStatus(bool bEnabled) {
627 _bSkipStatus = bEnabled;
628 }
629
forceTime()630 void RMTextDialog::forceTime() {
631 _bForceTime = true;
632 }
633
forceNoTime()634 void RMTextDialog::forceNoTime() {
635 _bForceNoTime = true;
636 }
637
setNoTab()638 void RMTextDialog::setNoTab() {
639 _bNoTab = true;
640 }
641
setForcedTime(uint32 dwTime)642 void RMTextDialog::setForcedTime(uint32 dwTime) {
643 _time = dwTime;
644 }
645
setAlwaysDisplay()646 void RMTextDialog::setAlwaysDisplay() {
647 _bAlwaysDisplay = true;
648 }
649
removeThis(CORO_PARAM,bool & result)650 void RMTextDialog::removeThis(CORO_PARAM, bool &result) {
651 CORO_BEGIN_CONTEXT;
652 bool expired;
653 CORO_END_CONTEXT(_ctx);
654
655 CORO_BEGIN_CODE(_ctx);
656
657 // Presume successful result
658 result = true;
659
660 // Don't erase the background
661 if (_bSkipStatus) {
662 if (!(GLOBALS._bCfgDubbing && _hCustomSkip2 != CORO_INVALID_PID_VALUE)) {
663 if (GLOBALS._bCfgTimerizedText) {
664 if (!_bForceNoTime) {
665 if (g_vm->getTime() > (uint32)_time + _startTime)
666 return;
667 }
668 }
669 }
670
671 if (!_bNoTab) {
672 if (g_vm->getEngine()->getInput().getAsyncKeyState(Common::KEYCODE_TAB))
673 return;
674 }
675
676 if (!_bNoTab) {
677 if (_input) {
678 if (_input->mouseLeftClicked() || _input->mouseRightClicked())
679 return;
680 }
681 }
682 }
683
684 // Erase the background
685 else if (!(GLOBALS._bCfgDubbing && _hCustomSkip2 != CORO_INVALID_PID_VALUE)) {
686 if (!_bForceNoTime) {
687 if (g_vm->getTime() > (uint32)_time + _startTime)
688 return;
689 }
690 }
691
692 // If time is forced
693 if (_bForceTime) {
694 if (g_vm->getTime() > (uint32)_time + _startTime)
695 return;
696 }
697
698 if (_hCustomSkip != CORO_INVALID_PID_VALUE) {
699 CORO_INVOKE_3(CoroScheduler.waitForSingleObject, _hCustomSkip, 0, &_ctx->expired);
700 // == WAIT_OBJECT_0
701 if (!_ctx->expired)
702 return;
703 }
704
705 if (GLOBALS._bCfgDubbing && _hCustomSkip2 != CORO_INVALID_PID_VALUE) {
706 CORO_INVOKE_3(CoroScheduler.waitForSingleObject, _hCustomSkip2, 0, &_ctx->expired);
707 // == WAIT_OBJECT_0
708 if (!_ctx->expired)
709 return;
710 }
711
712 result = false;
713
714 CORO_END_CODE;
715 }
716
unregister()717 void RMTextDialog::unregister() {
718 RMGfxTask::unregister();
719 assert(_nInList == 0);
720 CoroScheduler.setEvent(_hEndDisplay);
721 }
722
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim)723 void RMTextDialog::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
724 CORO_BEGIN_CONTEXT;
725 CORO_END_CONTEXT(_ctx);
726
727 CORO_BEGIN_CODE(_ctx);
728
729 if (_startTime == 0)
730 _startTime = g_vm->getTime();
731
732 if (_bShowed) {
733 if (GLOBALS._bShowSubtitles || _bAlwaysDisplay) {
734 prim->getDst().topLeft() = _dst;
735 CORO_INVOKE_2(RMText::draw, bigBuf, prim);
736 }
737 }
738
739 CORO_END_CODE;
740 }
741
setCustomSkipHandle(uint32 hCustom)742 void RMTextDialog::setCustomSkipHandle(uint32 hCustom) {
743 _hCustomSkip = hCustom;
744 }
745
setCustomSkipHandle2(uint32 hCustom)746 void RMTextDialog::setCustomSkipHandle2(uint32 hCustom) {
747 _hCustomSkip2 = hCustom;
748 }
749
waitForEndDisplay(CORO_PARAM)750 void RMTextDialog::waitForEndDisplay(CORO_PARAM) {
751 CoroScheduler.waitForSingleObject(coroParam, _hEndDisplay, CORO_INFINITE);
752 }
753
setInput(RMInput * input)754 void RMTextDialog::setInput(RMInput *input) {
755 _input = input;
756 }
757
758 /**
759 * Set the position
760 */
setPosition(const RMPoint & pt)761 void RMTextDialog::setPosition(const RMPoint &pt) {
762 _dst = pt;
763 }
764
765 /****************************************************************************\
766 * RMTextDialogScrolling Methods
767 \****************************************************************************/
768
RMTextDialogScrolling()769 RMTextDialogScrolling::RMTextDialogScrolling() {
770 _curLoc = NULL;
771 }
772
RMTextDialogScrolling(RMLocation * loc)773 RMTextDialogScrolling::RMTextDialogScrolling(RMLocation *loc) {
774 _curLoc = loc;
775 _startScroll = loc->scrollPosition();
776 }
777
~RMTextDialogScrolling()778 RMTextDialogScrolling::~RMTextDialogScrolling() {
779 }
780
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim)781 void RMTextDialogScrolling::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
782 CORO_BEGIN_CONTEXT;
783 RMPoint curDst;
784 CORO_END_CONTEXT(_ctx);
785
786 CORO_BEGIN_CODE(_ctx);
787
788 _ctx->curDst = _dst;
789
790 if (_curLoc != NULL)
791 _dst -= _curLoc->scrollPosition() - _startScroll;
792
793 CORO_INVOKE_2(RMTextDialog::draw, bigBuf, prim);
794
795 _dst = _ctx->curDst;
796
797 CORO_END_CODE;
798 }
799
clipOnScreen(RMGfxPrimitive * prim)800 void RMTextDialogScrolling::clipOnScreen(RMGfxPrimitive *prim) {
801 // We must not do anything!
802 }
803
804 /****************************************************************************\
805 * RMTextItemName Methods
806 \****************************************************************************/
807
RMTextItemName()808 RMTextItemName::RMTextItemName() : RMText() {
809 _item = NULL;
810 setPriority(220);
811 }
812
~RMTextItemName()813 RMTextItemName::~RMTextItemName() {
814 }
815
doFrame(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMLocation & loc,RMPointer & ptr,RMInventory & inv)816 void RMTextItemName::doFrame(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMLocation &loc, RMPointer &ptr, RMInventory &inv) {
817 CORO_BEGIN_CONTEXT;
818 RMItem *lastItem;
819 uint32 hThread;
820 CORO_END_CONTEXT(_ctx);
821
822 Common::String itemName;
823
824 CORO_BEGIN_CODE(_ctx);
825
826 _ctx->lastItem = _item;
827
828 // Adds to the list if there is need
829 if (!_nInList)
830 bigBuf.addPrim(new RMGfxPrimitive(this));
831
832 // Update the scrolling co-ordinates
833 _curscroll = loc.scrollPosition();
834
835 // Check if we are on the inventory
836 if (inv.itemInFocus(_mpos))
837 _item = inv.whichItemIsIn(_mpos);
838 else
839 _item = loc.whichItemIsIn(_mpos);
840
841 // If there an item, get its name
842 if (_item != NULL)
843 _item->getName(itemName);
844
845 // Write it
846 writeText(itemName, 1);
847
848 // Handle the change If the selected item is different from the previous one
849 if (_ctx->lastItem != _item) {
850 if (_item == NULL)
851 ptr.setSpecialPointer(RMPointer::PTR_NONE);
852 else {
853 _ctx->hThread = mpalQueryDoAction(20, _item->mpalCode(), 0);
854 if (_ctx->hThread == CORO_INVALID_PID_VALUE)
855 ptr.setSpecialPointer(RMPointer::PTR_NONE);
856 else
857 CORO_INVOKE_2(CoroScheduler.waitForSingleObject, _ctx->hThread, CORO_INFINITE);
858 }
859 }
860
861 CORO_END_CODE;
862 }
863
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim)864 void RMTextItemName::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
865 CORO_BEGIN_CONTEXT;
866 CORO_END_CONTEXT(_ctx);
867
868 CORO_BEGIN_CODE(_ctx);
869
870 // If there is no text, it's pointless to continue
871 if (_buf == NULL)
872 return;
873
874 // Set the destination coordinates of the mouse
875 prim->getDst().topLeft() = _mpos - RMPoint(0, 30);
876
877 CORO_INVOKE_2(RMText::draw, bigBuf, prim);
878
879 CORO_END_CODE;
880 }
881
getHotspot()882 RMPoint RMTextItemName::getHotspot() {
883 if (_item == NULL)
884 return _mpos + _curscroll;
885 else
886 return _item->getHotspot();
887 }
888
getSelectedItem()889 RMItem *RMTextItemName::getSelectedItem() {
890 return _item;
891 }
892
isItemSelected()893 bool RMTextItemName::isItemSelected() {
894 return _item != NULL;
895 }
896
setMouseCoord(const RMPoint & m)897 void RMTextItemName::setMouseCoord(const RMPoint &m) {
898 _mpos = m;
899 }
900
removeThis(CORO_PARAM,bool & result)901 void RMTextItemName::removeThis(CORO_PARAM, bool &result) {
902 result = true;
903 }
904
905 /****************************************************************************\
906 * RMDialogChoice Methods
907 \****************************************************************************/
908
RMDialogChoice()909 RMDialogChoice::RMDialogChoice() {
910 RMResRaw dlg1(RES_I_DLGTEXT);
911 RMResRaw dlg2(RES_I_DLGTEXTLINE);
912 RMRes dlgpal(RES_I_DLGTEXTPAL);
913
914 _dlgText.init(dlg1, dlg1.width(), dlg1.height());
915 _dlgTextLine.init(dlg2, dlg2.width(), dlg2.height());
916
917 _dlgText.loadPaletteWA(dlgpal);
918 _dlgTextLine.loadPaletteWA(dlgpal);
919
920 _hUnreg = CoroScheduler.createEvent(false, false);
921 _bRemoveFromOT = false;
922
923 _curAdded = 0;
924 _bShow = false;
925
926 _curSelection = 0;
927 _numChoices = 0;
928
929 _drawedStrings = NULL;
930 _ptDrawStrings = NULL;
931 }
932
~RMDialogChoice()933 RMDialogChoice::~RMDialogChoice() {
934 CoroScheduler.closeEvent(_hUnreg);
935 }
936
unregister()937 void RMDialogChoice::unregister() {
938 RMGfxWoodyBuffer::unregister();
939 assert(!_nInList);
940 CoroScheduler.pulseEvent(_hUnreg);
941
942 _bRemoveFromOT = false;
943 }
944
init()945 void RMDialogChoice::init() {
946 _numChoices = 0;
947 _drawedStrings = NULL;
948 _ptDrawStrings = NULL;
949 _curSelection = -1;
950
951 create(640, 477);
952 setPriority(140);
953 }
954
close()955 void RMDialogChoice::close() {
956 if (_drawedStrings != NULL) {
957 delete[] _drawedStrings;
958 _drawedStrings = NULL;
959 }
960
961 if (_ptDrawStrings != NULL) {
962 delete[] _ptDrawStrings;
963 _ptDrawStrings = NULL;
964 }
965
966 destroy();
967 }
968
setNumChoices(int num)969 void RMDialogChoice::setNumChoices(int num) {
970 _numChoices = num;
971 _curAdded = 0;
972
973 // Allocate space for drawn strings
974 _drawedStrings = new RMText[num];
975 _ptDrawStrings = new RMPoint[num];
976
977 // Initialization
978 for (int i = 0; i < _numChoices; i++) {
979 _drawedStrings[i].setColor(0, 255, 0);
980 _drawedStrings[i].setAlignType(RMText::HLEFTPAR, RMText::VTOP);
981 _drawedStrings[i].setMaxLineLength(600);
982 _drawedStrings[i].setPriority(10);
983 }
984 }
985
addChoice(const Common::String & string)986 void RMDialogChoice::addChoice(const Common::String &string) {
987 // Draw the string
988 assert(_curAdded < _numChoices);
989 _drawedStrings[_curAdded++].writeText(string, 0);
990 }
991
prepare(CORO_PARAM)992 void RMDialogChoice::prepare(CORO_PARAM) {
993 CORO_BEGIN_CONTEXT;
994 int i;
995 RMPoint ptPos;
996 CORO_END_CONTEXT(_ctx);
997
998 CORO_BEGIN_CODE(_ctx);
999
1000 addPrim(new RMGfxPrimitive(&_dlgText, RMPoint(0, 0)));
1001 addPrim(new RMGfxPrimitive(&_dlgTextLine, RMPoint(0, 155)));
1002 addPrim(new RMGfxPrimitive(&_dlgTextLine, RMPoint(0, 155 + 83)));
1003 addPrim(new RMGfxPrimitive(&_dlgTextLine, RMPoint(0, 155 + 83 + 83)));
1004 addPrim(new RMGfxPrimitive(&_dlgTextLine, RMPoint(0, 155 + 83 + 83 + 83)));
1005
1006 _ctx->ptPos.set(20, 90);
1007
1008 for (_ctx->i = 0; _ctx->i < _numChoices; _ctx->i++) {
1009 addPrim(new RMGfxPrimitive(&_drawedStrings[_ctx->i], _ctx->ptPos));
1010 _ptDrawStrings[_ctx->i] = _ctx->ptPos;
1011 _ctx->ptPos.offset(0, _drawedStrings[_ctx->i].getDimy() + 15);
1012 }
1013
1014 CORO_INVOKE_0(drawOT);
1015 clearOT();
1016
1017 _ptDrawPos.set(0, 480 - _ctx->ptPos._y);
1018
1019 CORO_END_CODE;
1020 }
1021
setSelected(CORO_PARAM,int pos)1022 void RMDialogChoice::setSelected(CORO_PARAM, int pos) {
1023 CORO_BEGIN_CONTEXT;
1024 RMGfxBox box;
1025 RMRect rc;
1026 CORO_END_CONTEXT(_ctx);
1027
1028 CORO_BEGIN_CODE(_ctx);
1029
1030 if (pos == _curSelection)
1031 return;
1032
1033 _ctx->box.setPriority(5);
1034
1035 if (_curSelection != -1) {
1036 _ctx->box.setColor(0xCC, 0xCC, 0xFF);
1037 _ctx->rc.topLeft() = RMPoint(18, _ptDrawStrings[_curSelection]._y);
1038 _ctx->rc.bottomRight() = _ctx->rc.topLeft() + RMPoint(597, _drawedStrings[_curSelection].getDimy());
1039 addPrim(new RMGfxPrimitive(&_ctx->box, _ctx->rc));
1040
1041 addPrim(new RMGfxPrimitive(&_drawedStrings[_curSelection], _ptDrawStrings[_curSelection]));
1042 CORO_INVOKE_0(drawOT);
1043 clearOT();
1044 }
1045
1046 if (pos != -1) {
1047 _ctx->box.setColor(100, 100, 100);
1048 _ctx->rc.topLeft() = RMPoint(18, _ptDrawStrings[pos]._y);
1049 _ctx->rc.bottomRight() = _ctx->rc.topLeft() + RMPoint(597, _drawedStrings[pos].getDimy());
1050 addPrim(new RMGfxPrimitive(&_ctx->box, _ctx->rc));
1051 addPrim(new RMGfxPrimitive(&_drawedStrings[pos], _ptDrawStrings[pos]));
1052 }
1053
1054 CORO_INVOKE_0(drawOT);
1055 clearOT();
1056
1057 _curSelection = pos;
1058
1059 CORO_END_CODE;
1060 }
1061
show(CORO_PARAM,RMGfxTargetBuffer * bigBuf)1062 void RMDialogChoice::show(CORO_PARAM, RMGfxTargetBuffer *bigBuf) {
1063 CORO_BEGIN_CONTEXT;
1064 RMPoint destpt;
1065 int deltay;
1066 int starttime;
1067 int elaps;
1068 CORO_END_CONTEXT(_ctx);
1069
1070 CORO_BEGIN_CODE(_ctx);
1071
1072 CORO_INVOKE_0(prepare);
1073 _bShow = false;
1074
1075 if (!_nInList && bigBuf != NULL)
1076 bigBuf->addPrim(new RMGfxPrimitive(this));
1077
1078 if (0) {
1079 _bShow = true;
1080 } else {
1081 _ctx->starttime = g_vm->getTime();
1082 _ctx->deltay = 480 - _ptDrawPos._y;
1083 _ctx->destpt = _ptDrawPos;
1084 _ptDrawPos.set(0, 480);
1085
1086 if (!_nInList && bigBuf != NULL)
1087 bigBuf->addPrim(new RMGfxPrimitive(this));
1088 _bShow = true;
1089
1090 _ctx->elaps = 0;
1091 while (_ctx->elaps < 700) {
1092 CORO_INVOKE_2(CoroScheduler.waitForSingleObject, g_vm->_hEndOfFrame, CORO_INFINITE);
1093 _ctx->elaps = g_vm->getTime() - _ctx->starttime;
1094 _ptDrawPos._y = 480 - ((_ctx->deltay * 100) / 700 * _ctx->elaps) / 100;
1095 }
1096
1097 _ptDrawPos._y = _ctx->destpt._y;
1098 }
1099
1100 CORO_END_CODE;
1101 }
1102
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim)1103 void RMDialogChoice::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
1104 CORO_BEGIN_CONTEXT;
1105 CORO_END_CONTEXT(_ctx);
1106
1107 CORO_BEGIN_CODE(_ctx);
1108
1109 if (_bShow == false)
1110 return;
1111
1112 prim->setDst(_ptDrawPos);
1113 CORO_INVOKE_2(RMGfxSourceBuffer16::draw, bigBuf, prim);
1114
1115 CORO_END_CODE;
1116 }
1117
hide(CORO_PARAM)1118 void RMDialogChoice::hide(CORO_PARAM) {
1119 CORO_BEGIN_CONTEXT;
1120 int deltay;
1121 int starttime;
1122 int elaps;
1123 CORO_END_CONTEXT(_ctx);
1124
1125 CORO_BEGIN_CODE(_ctx);
1126
1127 if (1) {
1128 _ctx->starttime = g_vm->getTime();
1129
1130 _ctx->deltay = 480 - _ptDrawPos._y;
1131 _ctx->elaps = 0;
1132 while (_ctx->elaps < 700) {
1133 CORO_INVOKE_2(CoroScheduler.waitForSingleObject, g_vm->_hEndOfFrame, CORO_INFINITE);
1134 _ctx->elaps = g_vm->getTime() - _ctx->starttime;
1135 _ptDrawPos._y = 480 - ((_ctx->deltay * 100) / 700 * (700 - _ctx->elaps)) / 100;
1136 }
1137 }
1138
1139 _bShow = false;
1140 _bRemoveFromOT = true;
1141 CORO_INVOKE_2(CoroScheduler.waitForSingleObject, _hUnreg, CORO_INFINITE);
1142
1143 CORO_END_CODE;
1144 }
1145
removeThis(CORO_PARAM,bool & result)1146 void RMDialogChoice::removeThis(CORO_PARAM, bool &result) {
1147 result = _bRemoveFromOT;
1148 }
1149
doFrame(CORO_PARAM,RMPoint ptMousePos)1150 void RMDialogChoice::doFrame(CORO_PARAM, RMPoint ptMousePos) {
1151 CORO_BEGIN_CONTEXT;
1152 int i;
1153 CORO_END_CONTEXT(_ctx);
1154
1155 CORO_BEGIN_CODE(_ctx);
1156
1157 if (ptMousePos._y > _ptDrawPos._y) {
1158 for (_ctx->i = 0; _ctx->i < _numChoices; _ctx->i++) {
1159 if ((ptMousePos._y >= _ptDrawPos._y + _ptDrawStrings[_ctx->i]._y) && (ptMousePos._y < _ptDrawPos._y + _ptDrawStrings[_ctx->i]._y + _drawedStrings[_ctx->i].getDimy())) {
1160 CORO_INVOKE_1(setSelected, _ctx->i);
1161 break;
1162 }
1163 }
1164
1165 if (_ctx->i == _numChoices)
1166 CORO_INVOKE_1(setSelected, -1);
1167 }
1168
1169 CORO_END_CODE;
1170 }
1171
getSelection()1172 int RMDialogChoice::getSelection() {
1173 return _curSelection;
1174 }
1175
1176 } // End of namespace Tony
1177