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 #include "common/endian.h"
24 #include "common/str.h"
25 #include "graphics/cursorman.h"
26
27 #include "gob/gob.h"
28 #include "gob/draw.h"
29 #include "gob/global.h"
30 #include "gob/util.h"
31 #include "gob/game.h"
32 #include "gob/script.h"
33 #include "gob/resources.h"
34 #include "gob/hotspots.h"
35 #include "gob/scenery.h"
36 #include "gob/inter.h"
37 #include "gob/video.h"
38
39 namespace Gob {
40
Draw_v2(GobEngine * vm)41 Draw_v2::Draw_v2(GobEngine *vm) : Draw_v1(vm) {
42 _mayorWorkaroundStatus = 0;
43 }
44
initScreen()45 void Draw_v2::initScreen() {
46 _vm->_game->_preventScroll = false;
47
48 _scrollOffsetX = 0;
49 _scrollOffsetY = 0;
50
51 initSpriteSurf(kBackSurface, _vm->_video->_surfWidth, _vm->_video->_surfHeight, 0);
52 _backSurface = _spritesArray[kBackSurface];
53 _backSurface->clear();
54
55 if (!_spritesArray[kCursorSurface]) {
56 initSpriteSurf(kCursorSurface, 32, 16, 2);
57 _cursorSpritesBack = _spritesArray[kCursorSurface];
58 _cursorSprites = _cursorSpritesBack;
59 _scummvmCursor = _vm->_video->initSurfDesc(16, 16, SCUMMVM_CURSOR);
60 }
61
62 _spritesArray[kFrontSurface] = _frontSurface;
63 _spritesArray[kBackSurface ] = _backSurface;
64
65 _vm->_video->dirtyRectsAll();
66 }
67
closeScreen()68 void Draw_v2::closeScreen() {
69 //freeSprite(kCursorSurface);
70 //_cursorSprites = 0;
71 //_cursorSpritesBack = 0;
72 //_scummvmCursor = 0;
73 freeSprite(kBackSurface);
74 }
75
blitCursor()76 void Draw_v2::blitCursor() {
77 if (!_cursorSprites || (_cursorIndex == -1))
78 return;
79
80 _showCursor = (_showCursor & ~2) | ((_showCursor & 1) << 1);
81 }
82
animateCursor(int16 cursor)83 void Draw_v2::animateCursor(int16 cursor) {
84 if (!_cursorSprites)
85 return;
86
87 int16 cursorIndex = cursor;
88 int16 newX = 0, newY = 0;
89 uint16 hotspotX, hotspotY;
90
91 _showCursor |= 1;
92
93 // .-- _draw_animateCursorSUB1 ---
94 if (cursorIndex == -1) {
95 cursorIndex =
96 _vm->_game->_hotspots->findCursor(_vm->_global->_inter_mouseX,
97 _vm->_global->_inter_mouseY);
98
99 if (_cursorAnimLow[cursorIndex] == -1)
100 cursorIndex = 1;
101 }
102 // '------
103
104 if (_cursorAnimLow[cursorIndex] != -1) {
105 // .-- _draw_animateCursorSUB2 ---
106 if (cursorIndex == _cursorIndex) {
107 if ((_cursorAnimDelays[_cursorIndex] != 0) &&
108 ((_cursorTimeKey + (_cursorAnimDelays[_cursorIndex] * 10)) <=
109 _vm->_util->getTimeKey())) {
110 _cursorAnim++;
111 if ((_cursorAnimHigh[_cursorIndex] < _cursorAnim) ||
112 (_cursorAnimLow[_cursorIndex] > _cursorAnim))
113 _cursorAnim = _cursorAnimLow[_cursorIndex];
114 _cursorTimeKey = _vm->_util->getTimeKey();
115 } else {
116 if (_noInvalidated && (_vm->_global->_inter_mouseX == _cursorX) &&
117 (_vm->_global->_inter_mouseY == _cursorY)) {
118 _vm->_video->waitRetrace();
119 return;
120 }
121 }
122 } else {
123 _cursorIndex = cursorIndex;
124 if (_cursorAnimDelays[cursorIndex] != 0) {
125 _cursorAnim = _cursorAnimLow[cursorIndex];
126 _cursorTimeKey = _vm->_util->getTimeKey();
127 }
128 }
129
130 if (_cursorAnimDelays[_cursorIndex] != 0) {
131 if ((_cursorAnimHigh[_cursorIndex] < _cursorAnim) ||
132 (_cursorAnimLow[_cursorIndex] > _cursorAnim))
133 _cursorAnim = _cursorAnimLow[_cursorIndex];
134
135 cursorIndex = _cursorAnim;
136 }
137 // '------
138
139 hotspotX = 0;
140 hotspotY = 0;
141
142 if (_cursorHotspotXVar != -1) {
143 hotspotX = (uint16) VAR(_cursorIndex + _cursorHotspotXVar);
144 hotspotY = (uint16) VAR(_cursorIndex + _cursorHotspotYVar);
145 } else if (_cursorHotspotX != -1) {
146 hotspotX = _cursorHotspotX;
147 hotspotY = _cursorHotspotY;
148 } else if (_cursorHotspotsX != 0) {
149 hotspotX = _cursorHotspotsX[_cursorIndex];
150 hotspotY = _cursorHotspotsY[_cursorIndex];
151 }
152
153 newX = _vm->_global->_inter_mouseX - hotspotX;
154 newY = _vm->_global->_inter_mouseY - hotspotY;
155
156 _scummvmCursor->clear();
157 _scummvmCursor->blit(*_cursorSprites,
158 cursorIndex * _cursorWidth, 0,
159 (cursorIndex + 1) * _cursorWidth - 1,
160 _cursorHeight - 1, 0, 0);
161
162 uint32 keyColor = 0;
163 if (_doCursorPalettes && _cursorKeyColors && _doCursorPalettes[cursorIndex])
164 keyColor = _cursorKeyColors[cursorIndex];
165
166 CursorMan.replaceCursor(_scummvmCursor->getData(),
167 _cursorWidth, _cursorHeight, hotspotX, hotspotY, keyColor, false, &_vm->getPixelFormat());
168
169 if (_doCursorPalettes && _doCursorPalettes[cursorIndex]) {
170 CursorMan.replaceCursorPalette(_cursorPalettes + (cursorIndex * 256 * 3),
171 _cursorPaletteStarts[cursorIndex], _cursorPaletteCounts[cursorIndex]);
172 CursorMan.disableCursorPalette(false);
173 } else
174 CursorMan.disableCursorPalette(true);
175
176 if (_frontSurface != _backSurface) {
177 if (!_noInvalidated) {
178 int16 tmp = _cursorIndex;
179 _cursorIndex = -1;
180 blitInvalidated();
181 _cursorIndex = tmp;
182 } else {
183 _showCursor = 3;
184 _vm->_video->waitRetrace();
185 if (MIN(newY, _cursorY) < 50)
186 _vm->_util->delay(5);
187 }
188 }
189 } else {
190 blitCursor();
191 _cursorX = newX;
192 _cursorY = newY;
193 }
194
195 _showCursor &= ~1;
196 }
197
printTotText(int16 id)198 void Draw_v2::printTotText(int16 id) {
199 byte *dataPtr;
200 byte *ptr, *ptrEnd;
201 byte cmd;
202 int16 savedFlags;
203 int16 destX, destY;
204 int16 spriteRight, spriteBottom;
205 int16 val;
206 int16 rectLeft, rectTop, rectRight, rectBottom;
207 int16 size;
208
209 id &= 0xFFF;
210
211 _vm->validateLanguage();
212
213 // WORKAROUND: In the scripts of some Gobliins 2 versions, the dialog text IDs
214 // for Fingus and the mayor are swapped.
215 if ((_vm->getGameType() == kGameTypeGob2) && !_vm->isCD() &&
216 _vm->isCurrentTot("gob07.tot")) {
217
218 if (id == 24) {
219 if (_mayorWorkaroundStatus == 1) {
220 _mayorWorkaroundStatus = 0;
221 id = 31;
222 } else
223 _mayorWorkaroundStatus = 2;
224 } else if (id == 31) {
225 if (_mayorWorkaroundStatus == 0) {
226 _mayorWorkaroundStatus = 1;
227 id = 24;
228 } else
229 _mayorWorkaroundStatus = 0;
230 }
231
232 }
233
234 TextItem *textItem = _vm->_game->_resources->getTextItem(id);
235 if (!textItem)
236 return;
237
238 size = textItem->getSize();
239 dataPtr = textItem->getData();
240 ptr = dataPtr;
241 _pattern = 0;
242
243 bool isSubtitle = (ptr[1] & 0x80) != 0;
244
245 if (isSubtitle && !_vm->_global->_doSubtitles) {
246 delete textItem;
247 return;
248 }
249
250 if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
251 destX = (READ_LE_UINT16(ptr) & 0x7FFF) * 2;
252 spriteRight = READ_LE_UINT16(ptr + 4) * 2 + 1;
253 } else {
254 // No mask used for Fascination
255 destX = READ_LE_UINT16(ptr);
256 if (_vm->getGameType() != kGameTypeFascination)
257 destX &= 0x7FFF;
258 spriteRight = READ_LE_UINT16(ptr + 4);
259 }
260
261 if (_renderFlags & RENDERFLAG_FROMSPLIT) {
262 int16 start;
263
264 start = _vm->_video->_splitStart;
265
266 destY = start;
267 spriteBottom = READ_LE_UINT16(ptr + 6) - READ_LE_UINT16(ptr + 2);
268
269 if (_renderFlags & RENDERFLAG_DOUBLECOORDS)
270 spriteBottom *= 3;
271
272 spriteBottom += start;
273
274 if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
275 spriteBottom += _backDeltaY;
276 destY += _backDeltaY;
277 }
278 } else {
279 destY = READ_LE_UINT16(ptr + 2);
280 spriteBottom = READ_LE_UINT16(ptr + 6);
281
282 if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
283 destY *= 2;
284 spriteBottom *= 2;
285 }
286 }
287
288 ptr += 8;
289
290 if (_renderFlags & RENDERFLAG_CAPTUREPUSH) {
291 _vm->_game->capturePush(destX, destY,
292 spriteRight - destX + 1, spriteBottom - destY + 1);
293 (*_vm->_scenery->_pCaptureCounter)++;
294 }
295
296 _destSpriteX = destX;
297 _destSpriteY = destY;
298 _spriteRight = spriteRight;
299 _spriteBottom = spriteBottom;
300 _destSurface = kBackSurface;
301
302 _backColor = *ptr++;
303 _transparency = 1;
304
305 spriteOperation(DRAW_CLEARRECT);
306
307 _backColor = 0;
308 savedFlags = _renderFlags;
309 _renderFlags &= ~RENDERFLAG_NOINVALIDATE;
310
311 while ((_destSpriteX = READ_LE_UINT16(ptr)) != -1) {
312 _destSpriteX += destX;
313 _destSpriteY = READ_LE_UINT16(ptr + 2) + destY;
314 _spriteRight = READ_LE_UINT16(ptr + 4) + destX;
315 _spriteBottom = READ_LE_UINT16(ptr + 6) + destY;
316 ptr += 8;
317
318 cmd = *ptr++;
319 switch ((cmd & 0xF0) >> 4) {
320 case 0:
321 _frontColor = cmd & 0xF;
322 spriteOperation(DRAW_DRAWLINE);
323 break;
324 case 1:
325 _frontColor = cmd & 0xF;
326 spriteOperation(DRAW_DRAWBAR);
327 break;
328 case 2:
329 _backColor = cmd & 0xF;
330 spriteOperation(DRAW_FILLRECTABS);
331 break;
332 default:
333 break;
334 }
335 }
336 ptr += 2;
337
338 ptrEnd = ptr;
339 while (((ptrEnd - dataPtr) < size) && (*ptrEnd != 1)) {
340 // Converting to unknown commands/characters to spaces
341 if ((_vm->_game->_script->getVersionMinor() < 2) && (*ptrEnd > 3) && (*ptrEnd < 32))
342 *ptrEnd = 32;
343
344 switch (*ptrEnd) {
345 case 1:
346 break;
347
348 case 2:
349 case 5:
350 ptrEnd += 5;
351 break;
352
353 case 3:
354 case 4:
355 ptrEnd += 2;
356 break;
357
358 case 6:
359 ptrEnd++;
360 switch (*ptrEnd & 0xC0) {
361 case 0x40:
362 ptrEnd += 9;
363 break;
364 case 0x80:
365 ptrEnd += 3;
366 break;
367 case 0xC0:
368 ptrEnd += 11;
369 break;
370 default:
371 ptrEnd++;
372 break;
373 }
374 break;
375
376 case 10:
377 ptrEnd += (ptrEnd[1] * 2) + 2;
378 break;
379
380 default:
381 ptrEnd++;
382 break;
383 }
384 }
385 ptrEnd++;
386
387 int16 fontIndex = 0, frontColor = 0;
388 int16 strPos = 0, strPos2 = -1, strPosBak;
389 int16 offX = 0, offY = 0;
390 int16 colId = 0;
391 int16 colCmd = 0;
392 int16 width;
393 int16 maskChar = 0;
394 char mask[80], str[80], buf[50];
395
396 memset(mask, 0, 80);
397 memset(str, ' ', 80);
398 _backColor = 0;
399 _transparency = 1;
400
401 while (true) {
402 if ((((*ptr >= 1) && (*ptr <= 7)) || (*ptr == 10)) && (strPos != 0)) {
403 str[MAX(strPos, strPos2)] = 0;
404 strPosBak = strPos;
405 width = strlen(str) * _fonts[fontIndex]->getCharWidth();
406 adjustCoords(1, &width, 0);
407
408 if (colCmd & 0x0F) {
409 rectLeft = offX - 2;
410 rectTop = offY - 2;
411 rectRight = offX + width + 1;
412 rectBottom = _fonts[fontIndex]->getCharHeight();
413 adjustCoords(1, &rectBottom, 0);
414 rectBottom += offY + 1;
415 adjustCoords(0, &rectLeft, &rectTop);
416 adjustCoords(2, &rectRight, &rectBottom);
417
418 if (colId != -1)
419 _vm->_game->_hotspots->add(colId + 0xD000, rectLeft, rectTop,
420 rectRight, rectBottom, (uint16) Hotspots::kTypeClick, 0, 0, 0, 0);
421
422 if (_needAdjust != 2)
423 printTextCentered(colCmd & 0x0F, rectLeft + 4, rectTop + 4,
424 rectRight - 4, rectBottom - 4, str, fontIndex, frontColor);
425 else
426 printTextCentered(colCmd & 0x0F, rectLeft + 2, rectTop + 2,
427 rectRight - 2, rectBottom - 2, str, fontIndex, frontColor);
428
429 } else {
430 _destSpriteX = offX;
431 _destSpriteY = offY;
432 _fontIndex = fontIndex;
433 _frontColor = frontColor;
434 _textToPrint = str;
435
436 if (isSubtitle) {
437 _fontIndex = _subtitleFont;
438 _frontColor = _subtitleColor;
439 }
440
441 if (_needAdjust != 2) {
442 if ((_destSpriteX >= destX) && (_destSpriteY >= destY) &&
443 (((_fonts[_fontIndex]->getCharHeight() / 2) + _destSpriteY - 1) <= spriteBottom)) {
444 while (((_destSpriteX + width - 1) > spriteRight) && (width > 0)) {
445 width -= _fonts[_fontIndex]->getCharWidth() / 2;
446 str[strlen(str) - 1] = '\0';
447 }
448 spriteOperation(DRAW_PRINTTEXT);
449 }
450 } else
451 spriteOperation(DRAW_PRINTTEXT);
452
453 width = strlen(str);
454 for (strPos = 0; strPos < width; strPos++) {
455 if (mask[strPos] == '\0')
456 continue;
457
458 rectLeft = _fonts[fontIndex]->getCharWidth();
459 rectTop = _fonts[fontIndex]->getCharHeight();
460 adjustCoords(1, &rectLeft, &rectTop);
461 _destSpriteX = strPos * rectLeft + offX;
462 _spriteRight = _destSpriteX + rectLeft - 1;
463 _spriteBottom = offY + rectTop;
464 _destSpriteY = _spriteBottom;
465 spriteOperation(DRAW_DRAWLINE);
466 }
467 }
468
469 rectLeft = 0;
470 for (int i = 0; i < strPosBak; i++)
471 rectLeft += _fonts[_fontIndex]->getCharWidth(str[i]);
472
473 adjustCoords(1, &rectLeft, 0);
474 offX += rectLeft;
475 strPos = 0;
476 strPos2 = -1;
477 memset(mask, 0, 80);
478 memset(str, ' ', 80);
479 }
480
481 if (*ptr == 1)
482 break;
483
484 cmd = *ptr;
485 switch ((uint8) cmd) {
486 case 2:
487 case 5:
488 ptr++;
489 offX = destX + (int16)READ_LE_UINT16(ptr);
490 offY = destY + (int16)READ_LE_UINT16(ptr + 2);
491 if (_renderFlags & RENDERFLAG_DOUBLECOORDS) {
492 offX += (int16)READ_LE_UINT16(ptr);
493 offY += (int16)READ_LE_UINT16(ptr + 2);
494 }
495 ptr += 4;
496 break;
497
498 case 3:
499 ptr++;
500 fontIndex = ((*ptr & 0xF0) >> 4) & 7;
501 frontColor = *ptr & 0x0F;
502 ptr++;
503
504 if (isSubtitle) {
505 _subtitleFont = fontIndex;
506 _subtitleColor = frontColor;
507 }
508 break;
509
510 case 4:
511 ptr++;
512 frontColor = *ptr++;
513
514 if (isSubtitle)
515 _subtitleColor = frontColor;
516 break;
517
518 case 6:
519 ptr++;
520 colCmd = *ptr++;
521 colId = -1;
522 if (colCmd & 0x80) {
523 colId = (int16)READ_LE_UINT16(ptr);
524 ptr += 2;
525 }
526 if (colCmd & 0x40) {
527 rectLeft = destX + (int16)READ_LE_UINT16(ptr);
528 rectRight = destX + (int16)READ_LE_UINT16(ptr + 2);
529 rectTop = destY + (int16)READ_LE_UINT16(ptr + 4);
530 rectBottom = destY + (int16)READ_LE_UINT16(ptr + 6);
531 adjustCoords(2, &rectLeft, &rectTop);
532 adjustCoords(2, &rectRight, &rectBottom);
533 _vm->_game->_hotspots->add(colId + 0x0D000, rectLeft, rectTop,
534 rectRight, rectBottom, (uint16) Hotspots::kTypeClick, 0, 0, 0, 0);
535 ptr += 8;
536 }
537 break;
538
539 case 7:
540 ptr++;
541 colCmd = 0;
542 break;
543
544 case 8:
545 ptr++;
546 maskChar = 1;
547 break;
548
549 case 9:
550 ptr++;
551 maskChar = 0;
552 break;
553
554 case 10:
555 str[0] = (char) 255;
556 WRITE_LE_UINT16(str + 1, ptr - _vm->_game->_resources->getTexts());
557 str[3] = 0;
558 ptr++;
559 for (int i = *ptr++; i > 0; i--) {
560 mask[strPos++] = maskChar;
561 ptr += 2;
562 }
563 break;
564
565 default:
566 str[strPos] = (char) cmd;
567 // fall through
568 case 32:
569 mask[strPos++] = maskChar;
570 ptr++;
571 break;
572
573 case 186:
574 cmd = ptrEnd[17] & 0x7F;
575 if (cmd == 0) {
576 val = READ_LE_UINT16(ptrEnd + 18) * 4;
577 sprintf(buf, "%d", (int32)VAR_OFFSET(val));
578 } else if (cmd == 1) {
579 val = READ_LE_UINT16(ptrEnd + 18) * 4;
580 Common::strlcpy(buf, GET_VARO_STR(val), 20);
581 } else {
582 val = READ_LE_UINT16(ptrEnd + 18) * 4;
583 sprintf(buf, "%d", (int32)VAR_OFFSET(val));
584 if (buf[0] == '-') {
585 while (strlen(buf) - 1 < (uint32)ptrEnd[17]) {
586 _vm->_util->insertStr("0", buf, 1);
587 }
588 } else {
589 while (strlen(buf) - 1 < (uint32)ptrEnd[17]) {
590 _vm->_util->insertStr("0", buf, 0);
591 }
592 }
593 if (_vm->_global->_language == 2)
594 _vm->_util->insertStr(".", buf, strlen(buf) + 1 - ptrEnd[17]);
595 else
596 _vm->_util->insertStr(",", buf, strlen(buf) + 1 - ptrEnd[17]);
597 }
598 memcpy(str + strPos, buf, strlen(buf));
599 memset(mask, maskChar, strlen(buf));
600 if (ptrEnd[17] & 0x80) {
601 strPos2 = strPos + strlen(buf);
602 strPos++;
603 ptrEnd += 23;
604 ptr++;
605 } else {
606 strPos += strlen(buf);
607 if (ptr[1] != ' ') {
608 if ((ptr[1] == 2) &&
609 (((int16)READ_LE_UINT16(ptr + 4)) == _destSpriteY)) {
610 ptr += 5;
611 str[strPos] = ' ';
612 mask[strPos++] = maskChar;
613 }
614 } else {
615 str[strPos] = ' ';
616 mask[strPos++] = maskChar;
617 while (ptr[1] == ' ')
618 ptr++;
619 if ((ptr[1] == 2) &&
620 (((int16)READ_LE_UINT16(ptr + 4)) == _destSpriteY))
621 ptr += 5;
622 }
623 ptrEnd += 23;
624 ptr++;
625 }
626 break;
627 }
628 }
629
630 delete textItem;
631 _renderFlags = savedFlags;
632
633 if (!(_renderFlags & RENDERFLAG_COLLISIONS))
634 return;
635
636 _vm->_game->_hotspots->check(0, 0);
637
638 if (*_vm->_scenery->_pCaptureCounter != 0) {
639 (*_vm->_scenery->_pCaptureCounter)--;
640 _vm->_game->capturePop(1);
641 }
642 }
643
spriteOperation(int16 operation)644 void Draw_v2::spriteOperation(int16 operation) {
645 int16 len;
646 int16 x, y;
647 SurfacePtr sourceSurf, destSurf;
648 bool deltaVeto;
649 int16 left;
650 int16 ratio;
651 Resource *resource;
652
653 deltaVeto = (operation & 0x10) != 0;
654 operation &= 0x0F;
655
656 if (_sourceSurface >= 100)
657 _sourceSurface -= 80;
658 if (_destSurface >= 100)
659 _destSurface -= 80;
660
661 if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) {
662 if ((_sourceSurface == kBackSurface) && (operation != DRAW_LOADSPRITE)) {
663 _spriteLeft += _backDeltaX;
664 _spriteTop += _backDeltaY;
665 }
666
667 if (_destSurface == kBackSurface) {
668 _destSpriteX += _backDeltaX;
669 _destSpriteY += _backDeltaY;
670 if ((operation == DRAW_DRAWLINE) ||
671 ((operation >= DRAW_DRAWBAR) && (operation <= DRAW_FILLRECTABS))) {
672 _spriteRight += _backDeltaX;
673 _spriteBottom += _backDeltaY;
674 }
675 }
676 }
677
678 int16 spriteLeft = _spriteLeft;
679 int16 spriteTop = _spriteTop;
680 int16 spriteRight = _spriteRight;
681 int16 spriteBottom = _spriteBottom;
682 int16 destSpriteX = _destSpriteX;
683 int16 destSpriteY = _destSpriteY;
684 int16 destSurface = _destSurface;
685 int16 sourceSurface = _sourceSurface;
686
687 if (_vm->_video->_splitSurf && ((_destSurface == kFrontSurface) || (_destSurface == kBackSurface))) {
688 if ((_destSpriteY >= _vm->_video->_splitStart)) {
689 _destSpriteY -= _vm->_video->_splitStart;
690 if ((operation == DRAW_DRAWLINE) ||
691 ((operation >= DRAW_DRAWBAR) && (operation <= DRAW_FILLRECTABS)))
692 _spriteBottom -= _vm->_video->_splitStart;
693
694 _destSurface += 4;
695 }
696
697 if ((_spriteTop >= _vm->_video->_splitStart) && (operation == DRAW_BLITSURF)) {
698 _spriteTop -= _vm->_video->_splitStart;
699 if (_destSurface < 24)
700 _destSurface += 4;
701 }
702
703 }
704
705 adjustCoords(0, &_destSpriteX, &_destSpriteY);
706 if ((operation != DRAW_LOADSPRITE) && (_needAdjust != 2)) {
707 adjustCoords(0, &_spriteRight, &_spriteBottom);
708 adjustCoords(0, &_spriteLeft, &_spriteTop);
709
710 if (operation == DRAW_DRAWLINE) {
711 if ((_spriteRight == _destSpriteX) || (_spriteBottom == _destSpriteY)) {
712 operation = DRAW_FILLRECTABS;
713 _backColor = _frontColor;
714 }
715 } else if (operation == DRAW_DRAWLETTER)
716 operation = DRAW_BLITSURF;
717
718 if (operation == DRAW_DRAWLINE) {
719 if (_spriteBottom < _destSpriteY) {
720 SWAP(_spriteBottom, _destSpriteY);
721 SWAP(_spriteRight, _destSpriteX);
722 }
723 } else if ((operation == DRAW_LOADSPRITE) ||
724 (operation > DRAW_PRINTTEXT)) {
725 if (_spriteBottom < _destSpriteY)
726 SWAP(_spriteBottom, _destSpriteY);
727 if (_spriteRight < _destSpriteX)
728 SWAP(_spriteRight, _destSpriteX);
729 _spriteRight++;
730 _spriteBottom++;
731 }
732 }
733
734 sourceSurf = _spritesArray[_sourceSurface];
735 destSurf = _spritesArray[_destSurface];
736
737 if (!destSurf) {
738 warning("Can't do operation %d on surface %d: nonexistent", operation, _destSurface);
739 return;
740 }
741
742 switch (operation) {
743 case DRAW_BLITSURF:
744 case DRAW_DRAWLETTER:
745 if (!sourceSurf || !destSurf)
746 break;
747
748 _spritesArray[_destSurface]->blit(*_spritesArray[_sourceSurface],
749 _spriteLeft, spriteTop,
750 _spriteLeft + _spriteRight - 1,
751 _spriteTop + _spriteBottom - 1,
752 _destSpriteX, _destSpriteY, (_transparency == 0) ? -1 : 0);
753
754 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
755 _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
756 break;
757
758 case DRAW_PUTPIXEL:
759 _spritesArray[_destSurface]->putPixel(_destSpriteX, _destSpriteY, _frontColor);
760
761 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _destSpriteX, _destSpriteY);
762 break;
763
764 case DRAW_FILLRECT:
765 if (!(_backColor & 0xFF00) || !(_backColor & 0x0100)) {
766 _spritesArray[_destSurface]->fillRect(destSpriteX,
767 _destSpriteY, _destSpriteX + _spriteRight - 1,
768 _destSpriteY + _spriteBottom - 1, getColor(_backColor));
769 } else {
770 uint8 strength = 16 - (((uint16) _backColor) >> 12);
771
772 _spritesArray[_destSurface]->shadeRect(destSpriteX,
773 _destSpriteY, _destSpriteX + _spriteRight - 1,
774 _destSpriteY + _spriteBottom - 1, getColor(_backColor), strength);
775 }
776
777 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
778 _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
779 break;
780
781 case DRAW_DRAWLINE:
782 _spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
783 _spriteRight, _spriteBottom, _frontColor);
784
785 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
786 break;
787
788 case DRAW_INVALIDATE:
789 _spritesArray[_destSurface]->drawCircle(_destSpriteX,
790 _destSpriteY, _spriteRight, _frontColor);
791
792 dirtiedRect(_destSurface, _destSpriteX - _spriteRight, _destSpriteY - _spriteBottom,
793 _destSpriteX + _spriteRight, _destSpriteY + _spriteBottom);
794 break;
795
796 case DRAW_LOADSPRITE:
797 resource = _vm->_game->_resources->getResource((uint16) _spriteLeft,
798 &_spriteRight, &_spriteBottom);
799
800 if (!resource)
801 break;
802
803 _vm->_video->drawPackedSprite(resource->getData(),
804 _spriteRight, _spriteBottom, _destSpriteX, _destSpriteY,
805 _transparency, *_spritesArray[_destSurface]);
806
807 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY,
808 _destSpriteX + _spriteRight - 1, _destSpriteY + _spriteBottom - 1);
809
810 delete resource;
811 break;
812
813 case DRAW_PRINTTEXT:
814 // WORKAROUND: There's mistakes in Little Red's animal names.
815 // See this function for details.
816 fixLittleRedStrings();
817
818 len = strlen(_textToPrint);
819 left = _destSpriteX;
820
821 if ((_fontIndex >= 4) || (_fontToSprite[_fontIndex].sprite == -1)) {
822 if ((_fontIndex >= kFontCount) || !_fonts[_fontIndex]) {
823 warning("Trying to print \"%s\" with undefined font %d", _textToPrint, _fontIndex);
824 break;
825 }
826
827 Font *font = _fonts[_fontIndex];
828 if (font->isMonospaced()) {
829 if (((int8) _textToPrint[0]) == -1) {
830 _vm->validateLanguage();
831
832 byte *dataBuf = _vm->_game->_resources->getTexts() + _textToPrint[1] + 1;
833 len = *dataBuf++;
834 for (int i = 0; i < len; i++, dataBuf += 2) {
835 font->drawLetter(*_spritesArray[_destSurface], READ_LE_UINT16(dataBuf),
836 _destSpriteX, _destSpriteY, getColor(_frontColor),
837 getColor(_backColor), _transparency);
838 }
839 } else {
840 font->drawString(_textToPrint, _destSpriteX, _destSpriteY, getColor(_frontColor),
841 getColor(_backColor), _transparency, *_spritesArray[_destSurface]);
842 _destSpriteX += len * font->getCharWidth();
843 }
844 } else {
845 for (int i = 0; i < len; i++) {
846 font->drawLetter(*_spritesArray[_destSurface], _textToPrint[i],
847 _destSpriteX, _destSpriteY, getColor(_frontColor),
848 getColor(_backColor), _transparency);
849 _destSpriteX += font->getCharWidth(_textToPrint[i]);
850 }
851 }
852
853 } else {
854 sourceSurf = _spritesArray[_fontToSprite[_fontIndex].sprite];
855 ratio = ((sourceSurf == _frontSurface) || (sourceSurf == _backSurface)) ?
856 320 : sourceSurf->getWidth();
857 ratio /= _fontToSprite[_fontIndex].width;
858 for (int i = 0; i < len; i++) {
859 y = ((_textToPrint[i] - _fontToSprite[_fontIndex].base) / ratio)
860 * _fontToSprite[_fontIndex].height;
861 x = ((_textToPrint[i] - _fontToSprite[_fontIndex].base) % ratio)
862 * _fontToSprite[_fontIndex].width;
863 _spritesArray[_destSurface]->blit(*_spritesArray[_fontToSprite[_fontIndex].sprite], x, y,
864 x + _fontToSprite[_fontIndex].width - 1,
865 y + _fontToSprite[_fontIndex].height - 1,
866 _destSpriteX, _destSpriteY, (_transparency == 0) ? -1 : 0);
867 _destSpriteX += _fontToSprite[_fontIndex].width;
868 }
869 }
870
871 dirtiedRect(_destSurface, left, _destSpriteY,
872 _destSpriteX - 1, _destSpriteY + _fonts[_fontIndex]->getCharHeight() - 1);
873 break;
874
875 case DRAW_DRAWBAR:
876 if (_needAdjust != 2) {
877 _spritesArray[_destSurface]->fillRect(_destSpriteX, _spriteBottom - 1,
878 _spriteRight, _spriteBottom, _frontColor);
879
880 _spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
881 _destSpriteX + 1, _spriteBottom, _frontColor);
882
883 _spritesArray[_destSurface]->fillRect(_spriteRight - 1, _destSpriteY,
884 _spriteRight, _spriteBottom, _frontColor);
885
886 _spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
887 _spriteRight, _destSpriteY + 1, _frontColor);
888 } else {
889 _spritesArray[_destSurface]->drawLine(_destSpriteX, _spriteBottom,
890 _spriteRight, _spriteBottom, _frontColor);
891
892 _spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
893 _destSpriteX, _spriteBottom, _frontColor);
894
895 _spritesArray[_destSurface]->drawLine(_spriteRight, _destSpriteY,
896 _spriteRight, _spriteBottom, _frontColor);
897
898 _spritesArray[_destSurface]->drawLine(_destSpriteX, _destSpriteY,
899 _spriteRight, _destSpriteY, _frontColor);
900 }
901
902 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
903 break;
904
905 case DRAW_CLEARRECT:
906 if ((_backColor != 16) && (_backColor != 144)) {
907 _spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
908 _spriteRight, _spriteBottom,
909 getColor(_backColor));
910 }
911
912 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
913 break;
914
915 case DRAW_FILLRECTABS:
916 _spritesArray[_destSurface]->fillRect(_destSpriteX, _destSpriteY,
917 _spriteRight, _spriteBottom, getColor(_backColor));
918
919 dirtiedRect(_destSurface, _destSpriteX, _destSpriteY, _spriteRight, _spriteBottom);
920 break;
921
922 default:
923 break;
924 }
925
926 _spriteLeft = spriteLeft;
927 _spriteTop = spriteTop;
928 _spriteRight = spriteRight;
929 _spriteBottom = spriteBottom;
930 if (operation != DRAW_PRINTTEXT)
931 _destSpriteX = destSpriteX;
932 _destSpriteY = destSpriteY;
933 _destSurface = destSurface;
934 _sourceSurface = sourceSurface;
935
936 if ((_renderFlags & RENDERFLAG_USEDELTAS) && !deltaVeto) {
937 if (_sourceSurface == kBackSurface) {
938 _spriteLeft -= _backDeltaX;
939 _spriteTop -= _backDeltaY;
940 }
941
942 if (_destSurface == kBackSurface) {
943 _destSpriteX -= _backDeltaX;
944 _destSpriteY -= _backDeltaY;
945 }
946 }
947 }
948
949 /* WORKAROUND: Fix wrong German animal names in Once Upon A Time: Little Red Riding Hood.
950 *
951 * The DOS, Amiga and Atari version of Little Red come with a small screen, accessible
952 * through the main menu, that lets children read and listen to animal names in 5
953 * languages: French, German, English, Spanish and Italian.
954 * Unfortunately, the German names are partially wrong. This is especially tragic
955 * because this is a game for small children and they're supposed to learn something
956 * here. We fix this.
957 *
958 * However, there's also problems with the recorded spoken German names:
959 * - "Der Rabe" has a far too short "a", sounding more like "Rabbe"
960 * - The wrong article for "Schmetterling" is very audible
961 * - In general, the words are way too overpronounced
962 * These are, of course, way harder to fix.
963 */
964
965 static const char *kLittleRedStrings[][2] = {
966 {"die Heule" , "die Eule"},
967 {"das Schmetterling" , "der Schmetterling"},
968 {"die Vespe" , "die Wespe"},
969 {"das Eich\224rnchen" , "das Eichh\224rnchen"}
970 };
971
fixLittleRedStrings()972 void Draw_v2::fixLittleRedStrings() {
973 if (!_textToPrint || (_vm->getGameType() != kGameTypeLittleRed))
974 return;
975
976 for (int i = 0; i < ARRAYSIZE(kLittleRedStrings); i++) {
977 if (!strcmp(_textToPrint, kLittleRedStrings[i][0])) {
978 _textToPrint = kLittleRedStrings[i][1];
979 return;
980 }
981 }
982 }
983
984 } // End of namespace Gob
985