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 // Verb and hitarea handling
24
25 #include "common/system.h"
26
27 #include "graphics/surface.h"
28
29 #include "agos/agos.h"
30 #include "agos/intern.h"
31
32 namespace AGOS {
33
34 static const char *const russian_verb_names[] = {
35 "Ietj _",
36 "Qnotrft< pa",
37 "Nt_r[t<",
38 "Ecjdat<",
39 "Q=fst<",
40 "C^]t<",
41 "Ha_r[t<",
42 "Isqom<^ocat<",
43 "Docorjt<",
44 "Qp]t<",
45 "Neft<",
46 "Eat<"
47 };
48
49 static const char *const hebrew_verb_names[] = {
50 "LJ @L",
51 "DQZKL RL",
52 "TZG",
53 "DFF",
54 "@KEL",
55 "DXM",
56 "QBEX",
57 "DYZNY",
58 "CAX @L",
59 "DQX",
60 "LAY",
61 "ZO"
62 };
63
64 static const char *const spanish_verb_names[] = {
65 "Caminar",
66 "Mirar",
67 "Abrir",
68 "Mover",
69 "Consumir",
70 "Coger",
71 "Cerrar",
72 "Usar",
73 "Hablar",
74 "Quitar",
75 "Llevar",
76 "Dar"
77 };
78
79 static const char *const italian_verb_names[] = {
80 "Vai verso",
81 "Osserva",
82 "Apri",
83 "Sposta",
84 "Mangia",
85 "Raccogli",
86 "Chiudi",
87 "Usa",
88 "Parla a",
89 "Togli",
90 "Indossa",
91 "Dai"
92 };
93
94 static const char *const french_verb_names[] = {
95 "Aller vers",
96 "Regarder",
97 "Ouvrir",
98 "D/placer",
99 "Consommer",
100 "Prendre",
101 "Fermer",
102 "Utiliser",
103 "Parler ;",
104 "Enlever",
105 "Mettre",
106 "Donner"
107 };
108
109 static const char *const german_verb_names[] = {
110 "Gehe zu",
111 "Schau an",
112 ";ffne",
113 "Bewege",
114 "Verzehre",
115 "Nimm",
116 "Schlie+e",
117 "Benutze",
118 "Rede mit",
119 "Entferne",
120 "Trage",
121 "Gib"
122 };
123
124 static const char *const english_verb_names[] = {
125 "Walk to",
126 "Look at",
127 "Open",
128 "Move",
129 "Consume",
130 "Pick up",
131 "Close",
132 "Use",
133 "Talk to",
134 "Remove",
135 "Wear",
136 "Give"
137 };
138
139 static const char *const czech_verb_names[] = {
140 "Jit",
141 "Podivat se",
142 "Otevrit",
143 "Pohnout s",
144 "Snist",
145 "Sebrat",
146 "Zavrit",
147 "Pouzit",
148 "Mluvit s",
149 "Odstranit",
150 "Oblect",
151 "Dat"
152 };
153
154 static const char *const russian_verb_prep_names[] = {
155 "", "", "", "",
156 "", "", "", "s yfn?",
157 "", "", "", "_onu ?"
158 };
159
160 static const char *const hebrew_verb_prep_names[] = {
161 "", "", "", "",
162 "", "", "", "RM ND ?",
163 "", "", "", "LNI ?"
164 };
165
166 static const char *const spanish_verb_prep_names[] = {
167 "", "", "", "",
168 "", "", "", "^con qu/?",
169 "", "", "", "^a qui/n?"
170 };
171
172 static const char *const italian_verb_prep_names[] = {
173 "", "", "", "",
174 "", "", "", "con cosa ?",
175 "", "", "", "a chi ?"
176 };
177
178 static const char *const french_verb_prep_names[] = {
179 "", "", "", "",
180 "", "", "", "avec quoi ?",
181 "", "", "", "; qui ?"
182 };
183
184 static const char *const german_verb_prep_names[] = {
185 "", "", "", "",
186 "", "", "", "mit was ?",
187 "", "", "", "zu wem ?"
188 };
189
190 static const char *const english_verb_prep_names[] = {
191 "", "", "", "",
192 "", "", "", "with what ?",
193 "", "", "", "to whom ?"
194 };
195
196 static const char *const czech_verb_prep_names[] = {
197 "", "", "", "",
198 "", "", "", "s cim ?",
199 "", "", "", "komu ?"
200 };
201
202 #ifdef ENABLE_AGOS2
clearName()203 void AGOSEngine_Feeble::clearName() {
204 stopAnimateSimon2(2, 6);
205 _lastNameOn = NULL;
206 _animatePointer = false;
207 _mouseAnim = 1;
208 return;
209 }
210 #endif
211
clearName()212 void AGOSEngine_Simon2::clearName() {
213 if (getBitFlag(79)) {
214 sendSync(202);
215 _lastNameOn = NULL;
216 return;
217 }
218
219 if (_currentVerbBox == _lastVerbOn)
220 return;
221
222 resetNameWindow();
223 _lastVerbOn = _currentVerbBox;
224
225 if (_currentVerbBox != NULL && !(_currentVerbBox->flags & kBFBoxDead))
226 printVerbOf(_currentVerbBox->id);
227 }
228
clearName()229 void AGOSEngine_Simon1::clearName() {
230 HitArea *ha;
231
232 if (_currentVerbBox == _lastVerbOn)
233 return;
234
235 resetNameWindow();
236 _lastVerbOn = _currentVerbBox;
237
238 if (_currentVerbBox != NULL && (ha = findBox(200)) && (ha->flags & kBFBoxDead) && !(_currentVerbBox->flags & kBFBoxDead))
239 printVerbOf(_currentVerbBox->id);
240 }
241
clearName()242 void AGOSEngine::clearName() {
243 if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2)
244 return;
245
246 if (_nameLocked || !_lastNameOn)
247 return;
248
249 resetNameWindow();
250 }
251
252 static const byte convertVerbID[9] = {
253 0, 1, 5, 11, 8, 7, 10, 3, 2
254 };
255
printVerbOf(uint hitarea_id)256 void AGOSEngine::printVerbOf(uint hitarea_id) {
257 const char *txt;
258 const char * const *verb_names;
259 const char * const *verb_prep_names;
260
261 hitarea_id -= 101;
262 if (getGameType() == GType_SIMON2)
263 hitarea_id = convertVerbID[hitarea_id];
264
265 if (_showPreposition) {
266 switch (_language) {
267 case Common::RU_RUS:
268 verb_prep_names = russian_verb_prep_names;
269 break;
270 case Common::HE_ISR:
271 verb_prep_names = hebrew_verb_prep_names;
272 break;
273 case Common::ES_ESP:
274 verb_prep_names = spanish_verb_prep_names;
275 break;
276 case Common::IT_ITA:
277 verb_prep_names = italian_verb_prep_names;
278 break;
279 case Common::FR_FRA:
280 verb_prep_names = french_verb_prep_names;
281 break;
282 case Common::DE_DEU:
283 verb_prep_names = german_verb_prep_names;
284 break;
285 case Common::CZ_CZE:
286 verb_prep_names = czech_verb_prep_names;
287 break;
288 default:
289 verb_prep_names = english_verb_prep_names;
290 break;
291 }
292 CHECK_BOUNDS(hitarea_id, english_verb_prep_names);
293 txt = verb_prep_names[hitarea_id];
294 } else {
295 switch (_language) {
296 case Common::RU_RUS:
297 verb_names = russian_verb_names;
298 break;
299 case Common::HE_ISR:
300 verb_names = hebrew_verb_names;
301 break;
302 case Common::ES_ESP:
303 verb_names = spanish_verb_names;
304 break;
305 case Common::IT_ITA:
306 verb_names = italian_verb_names;
307 break;
308 case Common::FR_FRA:
309 verb_names = french_verb_names;
310 break;
311 case Common::DE_DEU:
312 verb_names = german_verb_names;
313 break;
314 case Common::CZ_CZE:
315 verb_names = czech_verb_names;
316 break;
317 default:
318 verb_names = english_verb_names;
319 break;
320 }
321 CHECK_BOUNDS(hitarea_id, english_verb_names);
322 txt = verb_names[hitarea_id];
323 }
324 showActionString((const byte *)txt);
325 }
326
showActionString(const byte * string)327 void AGOSEngine::showActionString(const byte *string) {
328 WindowBlock *window;
329 uint x;
330 const uint len = (getGameType() == GType_WW) ? 29 : 53;
331
332 window = _windowArray[1];
333 if (window == NULL || window->textColor == 0)
334 return;
335
336 // Arisme : hack for long strings in the French version
337 if ((strlen((const char*)string) - 1) <= len)
338 x = (len - (strlen((const char *)string) - 1)) * 3;
339 else
340 x = 0;
341
342 window->textColumn = x / 8;
343 window->textColumnOffset = x & 7;
344 if (_language == Common::HE_ISR && window->textColumnOffset != 0) {
345 window->textColumnOffset = 8 - window->textColumnOffset;
346 window->textColumn++;
347 }
348
349 for (; *string; string++)
350 windowPutChar(window, *string);
351 }
352
handleVerbClicked(uint verb)353 void AGOSEngine::handleVerbClicked(uint verb) {
354 Subroutine *sub;
355 int result;
356
357 if (shouldQuit())
358 return;
359
360 _objectItem = _hitAreaObjectItem;
361 if (_objectItem == _dummyItem2) {
362 _objectItem = me();
363 }
364 if (_objectItem == _dummyItem3) {
365 _objectItem = derefItem(me()->parent);
366 }
367
368 _subjectItem = _hitAreaSubjectItem;
369 if (_subjectItem == _dummyItem2) {
370 _subjectItem = me();
371 }
372 if (_subjectItem == _dummyItem3) {
373 _subjectItem = derefItem(me()->parent);
374 }
375
376 if (_subjectItem) {
377 _scriptNoun1 = _subjectItem->noun;
378 _scriptAdj1 = _subjectItem->adjective;
379 } else {
380 _scriptNoun1 = -1;
381 _scriptAdj1 = -1;
382 }
383
384 if (_objectItem) {
385 _scriptNoun2 = _objectItem->noun;
386 _scriptAdj2 = _objectItem->adjective;
387 } else {
388 _scriptNoun2 = -1;
389 _scriptAdj2 = -1;
390 }
391
392 _scriptVerb = _verbHitArea;
393
394 sub = getSubroutineByID(0);
395 if (sub == NULL)
396 return;
397
398 result = startSubroutine(sub);
399 if (result == -1)
400 showMessageFormat("I don't understand");
401
402 _runScriptReturn1 = false;
403
404 sub = getSubroutineByID(100);
405 if (sub)
406 startSubroutine(sub);
407
408 if (getGameType() == GType_SIMON2 || getGameType() == GType_FF || getGameType() == GType_PP)
409 _runScriptReturn1 = false;
410
411 permitInput();
412 }
413
resetNameWindow()414 void AGOSEngine::resetNameWindow() {
415 WindowBlock *window;
416
417 if (getGameType() == GType_SIMON2 && getBitFlag(79))
418 return;
419
420 window = _windowArray[1];
421 if (window != NULL && window->textColor != 0)
422 clearWindow(window);
423
424 _lastNameOn = NULL;
425 _lastVerbOn = NULL;
426 }
427
findBox(uint hitarea_id)428 HitArea *AGOSEngine::findBox(uint hitarea_id) {
429 HitArea *ha = _hitAreas;
430 uint count = ARRAYSIZE(_hitAreas);
431
432 do {
433 if (getGameType() == GType_FF || getGameType() == GType_PP) {
434 if (ha->id == hitarea_id && ha->flags != 0)
435 return ha;
436 } else {
437 if (ha->id == hitarea_id)
438 return ha;
439 }
440 } while (ha++, --count);
441 return NULL;
442 }
443
findEmptyHitArea()444 HitArea *AGOSEngine::findEmptyHitArea() {
445 HitArea *ha = _hitAreas;
446 uint count = ARRAYSIZE(_hitAreas) - 1;
447
448 do {
449 if (ha->flags == 0)
450 return ha;
451 } while (ha++, --count);
452
453 // The last box is overwritten, if too many boxes are allocated.
454 return ha;
455 }
456
freeBox(uint index)457 void AGOSEngine::freeBox(uint index) {
458 CHECK_BOUNDS(index, _hitAreas);
459 _hitAreas[index].flags = 0;
460 }
461
enableBox(uint hitarea)462 void AGOSEngine::enableBox(uint hitarea) {
463 HitArea *ha = findBox(hitarea);
464 if (ha != NULL)
465 ha->flags &= ~kBFBoxDead;
466 }
467
disableBox(uint hitarea)468 void AGOSEngine::disableBox(uint hitarea) {
469 HitArea *ha = findBox(hitarea);
470 if (ha != NULL) {
471 ha->flags |= kBFBoxDead;
472 ha->flags &= ~kBFBoxSelected;
473 if ((getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) &&
474 hitarea == 102) {
475 resetVerbs();
476 }
477 }
478 }
479
moveBox(uint hitarea,int x,int y)480 void AGOSEngine::moveBox(uint hitarea, int x, int y) {
481 HitArea *ha = findBox(hitarea);
482 if (ha != NULL) {
483 if (getGameType() == GType_FF || getGameType() == GType_PP) {
484 ha->x += x;
485 ha->y += y;
486 } else {
487 ha->x = x;
488 ha->y = y;
489 }
490 }
491 }
492
undefineBox(uint hitarea)493 void AGOSEngine::undefineBox(uint hitarea) {
494 HitArea *ha = findBox(hitarea);
495 if (ha != NULL) {
496 ha->flags = 0;
497 if (ha == _lastNameOn)
498 clearName();
499 _needHitAreaRecalc++;
500 }
501 }
502
isBoxDead(uint hitarea)503 bool AGOSEngine::isBoxDead(uint hitarea) {
504 HitArea *ha = findBox(hitarea);
505 if (ha == NULL)
506 return false;
507 return (ha->flags & kBFBoxDead) == 0;
508 }
509
defineBox(uint16 id,uint16 x,uint16 y,uint16 height,uint16 width,uint16 msg1,uint16 msg2,uint16 flags)510 void AGOSEngine::defineBox(uint16 id, uint16 x, uint16 y, uint16 height, uint16 width, uint16 msg1, uint16 msg2, uint16 flags) {
511 HitArea *ha = _hitAreaList + id;
512 ha->x = x;
513 ha->y = y;
514 ha->width = width;
515 ha->height = height;
516 ha->msg1 = msg1;
517 ha->msg2 = msg2;
518 ha->flags = flags;
519 ha->id = ha->priority = id;
520 }
521
defineBox(int id,int x,int y,int width,int height,int flags,int verb,Item * itemPtr)522 void AGOSEngine::defineBox(int id, int x, int y, int width, int height, int flags, int verb, Item *itemPtr) {
523 HitArea *ha;
524 undefineBox(id);
525
526 ha = findEmptyHitArea();
527 ha->x = x;
528 ha->y = y;
529 ha->width = width;
530 ha->height = height;
531 ha->flags = flags | kBFBoxInUse;
532 ha->id = ha->priority = id;
533 ha->verb = verb;
534 ha->itemPtr = itemPtr;
535
536 if (getGameType() == GType_FF && (ha->flags & kBFHyperBox)) {
537 ha->data = _hyperLink;
538 ha->priority = 50;
539 }
540
541 _needHitAreaRecalc++;
542 }
543
544 #ifdef ENABLE_AGOS2
resetVerbs()545 void AGOSEngine_PuzzlePack::resetVerbs() {
546 _verbHitArea = 300;
547 }
548
resetVerbs()549 void AGOSEngine_Feeble::resetVerbs() {
550 _verbHitArea = 300;
551 int cursor = 0;
552 int animMax = 16;
553
554 if (getBitFlag(203)) {
555 cursor = 14;
556 animMax = 9;
557 } else if (getBitFlag(204)) {
558 cursor = 15;
559 animMax = 9;
560 } else if (getBitFlag(207)) {
561 cursor = 26;
562 animMax = 2;
563 }
564
565 _mouseCursor = cursor;
566 _mouseAnimMax = animMax;
567 _mouseAnim = 1;
568 _needHitAreaRecalc++;
569
570 if (getBitFlag(99)) {
571 setVerb(NULL);
572 }
573 }
574 #endif
575
resetVerbs()576 void AGOSEngine::resetVerbs() {
577 if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2)
578 return;
579
580 uint id;
581 HitArea *ha;
582
583 if (getGameType() == GType_SIMON2) {
584 id = 2;
585 if (!getBitFlag(79))
586 id = (_mouse.y >= 136) ? 102 : 101;
587 } else {
588 id = (_mouse.y >= 136) ? 102 : 101;
589 }
590
591 _defaultVerb = id;
592
593 ha = findBox(id);
594 if (ha == NULL)
595 return;
596
597 if (ha->flags & kBFBoxDead) {
598 _defaultVerb = 999;
599 _currentVerbBox = NULL;
600 } else {
601 _verbHitArea = ha->verb;
602 setVerb(ha);
603 }
604 }
605
606 #ifdef ENABLE_AGOS2
setVerb(HitArea * ha)607 void AGOSEngine_Feeble::setVerb(HitArea *ha) {
608 int cursor = _mouseCursor;
609 if (_noRightClick)
610 return;
611
612 if (cursor > 13)
613 cursor = 0;
614 cursor++;
615 if (cursor == 5)
616 cursor = 1;
617 if (cursor == 4) {
618 if (getBitFlag(72)) {
619 cursor = 1;
620 }
621 } else if (cursor == 2) {
622 if (getBitFlag(99)) {
623 cursor = 3;
624 }
625 }
626
627 _mouseCursor = cursor;
628 _mouseAnimMax = (cursor == 4) ? 14: 16;
629 _mouseAnim = 1;
630 _needHitAreaRecalc++;
631 _verbHitArea = cursor + 300;
632 }
633 #endif
634
setVerb(HitArea * ha)635 void AGOSEngine::setVerb(HitArea *ha) {
636 HitArea *tmp = _currentVerbBox;
637
638 if (ha == tmp)
639 return;
640
641 if (getGameType() == GType_SIMON1) {
642 if (tmp != NULL) {
643 tmp->flags |= kBFInvertTouch;
644 if (getFeatures() & GF_32COLOR)
645 invertBox(tmp, 212, 208, 212, 8);
646 else
647 invertBox(tmp, 213, 208, 213, 10);
648 }
649
650 if (ha->flags & kBFBoxSelected) {
651 if (getFeatures() & GF_32COLOR)
652 invertBox(ha, 216, 212, 212, 4);
653 else
654 invertBox(ha, 218, 213, 213, 5);
655 } else {
656 if (getFeatures() & GF_32COLOR)
657 invertBox(ha, 220, 216, 216, 8);
658 else
659 invertBox(ha, 223, 218, 218, 10);
660 }
661
662 ha->flags &= ~(kBFBoxSelected + kBFInvertTouch);
663 } else {
664 if (ha->id < 101)
665 return;
666 _mouseCursor = ha->id - 101;
667 _needHitAreaRecalc++;
668 }
669 _currentVerbBox = ha;
670 }
671
672 #ifdef ENABLE_AGOS2
hitarea_leave(HitArea * ha,bool state)673 void AGOSEngine_Feeble::hitarea_leave(HitArea *ha, bool state) {
674 invertBox(ha, state);
675 }
676 #endif
677
hitarea_leave(HitArea * ha,bool state)678 void AGOSEngine::hitarea_leave(HitArea *ha, bool state) {
679 if (getGameType() == GType_SIMON2) {
680 invertBox(ha, 231, 229, 230, 1);
681 } else {
682 if (getFeatures() & GF_32COLOR)
683 invertBox(ha, 220, 212, 216, 4);
684 else
685 invertBox(ha, 223, 213, 218, 5);
686 }
687 }
688
leaveHitAreaById(uint hitarea_id)689 void AGOSEngine::leaveHitAreaById(uint hitarea_id) {
690 HitArea *ha = findBox(hitarea_id);
691 if (ha)
692 hitarea_leave(ha);
693 }
694
inventoryUp(WindowBlock * window)695 void AGOSEngine::inventoryUp(WindowBlock *window) {
696 if (window->iconPtr->line == 0)
697 return;
698
699 mouseOff();
700 uint index = getWindowNum(window);
701 drawIconArray(index, window->iconPtr->itemRef, window->iconPtr->line - 1, window->iconPtr->classMask);
702 mouseOn();
703 }
704
inventoryDown(WindowBlock * window)705 void AGOSEngine::inventoryDown(WindowBlock *window) {
706 mouseOff();
707 uint index = getWindowNum(window);
708 drawIconArray(index, window->iconPtr->itemRef, window->iconPtr->line + 1, window->iconPtr->classMask);
709 mouseOn();
710 }
711
boxController(uint x,uint y,uint mode)712 void AGOSEngine::boxController(uint x, uint y, uint mode) {
713 HitArea *best_ha;
714 HitArea *ha = _hitAreas;
715 uint count = ARRAYSIZE(_hitAreas);
716 uint16 priority = 0;
717
718 best_ha = NULL;
719
720 do {
721 if (ha->flags & kBFBoxInUse) {
722 if (!(ha->flags & kBFBoxDead)) {
723 if (x >= ha->x && y >= ha->y &&
724 x - ha->x < ha->width && y - ha->y < ha->height && priority <= ha->priority) {
725 priority = ha->priority;
726 best_ha = ha;
727 } else {
728 if (ha->flags & kBFBoxSelected) {
729 hitarea_leave(ha , true);
730 ha->flags &= ~kBFBoxSelected;
731 }
732 }
733 } else {
734 ha->flags &= ~kBFBoxSelected;
735 }
736 }
737 } while (ha++, --count);
738
739 _currentBoxNum = 0;
740 _currentBox = best_ha;
741
742 if (best_ha == NULL)
743 return;
744
745 _currentBoxNum = best_ha->id;
746
747 if (mode != 0) {
748 if (mode == 3) {
749 if (best_ha->verb & 0x4000) {
750 if (getGameType() == GType_ELVIRA1 && _variableArray[500] == 0) {
751 _variableArray[500] = best_ha->verb & 0xBFFF;
752 }
753
754 if (_clickOnly && best_ha->id < 8) {
755 uint id = best_ha->id;
756 if (id >= 4)
757 id -= 4;
758
759 invertBox(findBox(id), 0, 0, 0, 0);
760 _clickOnly = false;
761 return;
762 }
763 }
764
765 if (best_ha->flags & kBFDragBox)
766 _lastClickRem = best_ha;
767 } else {
768 _lastHitArea = best_ha;
769 }
770 }
771
772 if (_clickOnly)
773 return;
774
775 if (best_ha->flags & kBFInvertTouch) {
776 if (!(best_ha->flags & kBFBoxSelected)) {
777 hitarea_leave(best_ha, false);
778 best_ha->flags |= kBFBoxSelected;
779 }
780 } else {
781 if (mode == 0)
782 return;
783
784 if (!(best_ha->flags & kBFInvertSelect))
785 return;
786
787 if (best_ha->flags & kBFToggleBox) {
788 hitarea_leave(best_ha, false);
789 best_ha->flags ^= kBFInvertSelect;
790 } else if (!(best_ha->flags & kBFBoxSelected)) {
791 hitarea_leave(best_ha, false);
792 best_ha->flags |= kBFBoxSelected;
793 }
794 }
795 }
796
boxController(uint x,uint y,uint mode)797 void AGOSEngine_Waxworks::boxController(uint x, uint y, uint mode) {
798 HitArea *best_ha;
799 HitArea *ha = _hitAreas;
800 uint count = ARRAYSIZE(_hitAreas);
801 uint16 priority = 0;
802 uint16 x_ = x;
803 uint16 y_ = y;
804
805 if (getGameType() == GType_FF || getGameType() == GType_PP) {
806 x_ += _scrollX;
807 y_ += _scrollY;
808 } else if (getGameType() == GType_SIMON2) {
809 if (getBitFlag(79) || y < 134) {
810 x_ += _scrollX * 8;
811 }
812 }
813
814 best_ha = NULL;
815
816 do {
817 if (ha->flags & kBFBoxInUse) {
818 if (!(ha->flags & kBFBoxDead)) {
819 if (x_ >= ha->x && y_ >= ha->y &&
820 x_ - ha->x < ha->width && y_ - ha->y < ha->height && priority <= ha->priority) {
821 priority = ha->priority;
822 best_ha = ha;
823 } else {
824 if (ha->flags & kBFBoxSelected) {
825 hitarea_leave(ha , true);
826 ha->flags &= ~kBFBoxSelected;
827 }
828 }
829 } else {
830 ha->flags &= ~kBFBoxSelected;
831 }
832 }
833 } while (ha++, --count);
834
835 _currentBoxNum = 0;
836 _currentBox = best_ha;
837
838 if (best_ha == NULL) {
839 clearName();
840 if (getGameType() == GType_WW && _mouseCursor >= 4) {
841 _mouseCursor = 0;
842 _needHitAreaRecalc++;
843 }
844 return;
845 }
846
847 _currentBoxNum = best_ha->id;
848
849 if (mode != 0) {
850 if (mode == 3) {
851 if (best_ha->flags & kBFDragBox) {
852 _lastClickRem = best_ha;
853 }
854 } else {
855 _lastHitArea = best_ha;
856 if (getGameType() == GType_PP) {
857 _variableArray[400] = x;
858 _variableArray[401] = y;
859 } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2 ||
860 getGameType() == GType_FF) {
861 _variableArray[1] = x;
862 _variableArray[2] = y;
863 }
864 }
865 }
866
867 if ((getGameType() == GType_WW) && (_mouseCursor == 0 || _mouseCursor >= 4)) {
868 uint verb = best_ha->verb & 0x3FFF;
869 if (verb >= 239 && verb <= 242) {
870 uint cursor = verb - 235;
871 if (_mouseCursor != cursor) {
872 _mouseCursor = cursor;
873 _needHitAreaRecalc++;
874 }
875 }
876 }
877
878 if (getGameType() != GType_WW || !_nameLocked) {
879 if (best_ha->flags & kBFNoTouchName) {
880 clearName();
881 } else if (best_ha != _lastNameOn) {
882 displayName(best_ha);
883 }
884 }
885
886 if (best_ha->flags & kBFInvertTouch && !(best_ha->flags & kBFBoxSelected)) {
887 hitarea_leave(best_ha, false);
888 best_ha->flags |= kBFBoxSelected;
889 }
890 }
891
displayName(HitArea * ha)892 void AGOSEngine::displayName(HitArea *ha) {
893 if (getGameType() == GType_ELVIRA1 || getGameType() == GType_ELVIRA2 || getGameType() == GType_PP)
894 return;
895
896 bool result;
897 int x = 0, y = 0;
898
899 if (getGameType() == GType_FF) {
900 if (ha->flags & kBFHyperBox) {
901 _lastNameOn = ha;
902 return;
903 }
904 if (findBox(50))
905 return;
906
907 if (getBitFlag(99))
908 _animatePointer = ((ha->flags & kBFTextBox) == 0);
909 else
910 _animatePointer = true;
911
912 if (!getBitFlag(73))
913 return;
914
915 y = ha->y;
916 if (getBitFlag(99) && y > 288)
917 y = 288;
918 y -= 17;
919 if (y < 0)
920 y = 0;
921 y += 2;
922 x = ha->width / 2 + ha->x;
923 } else {
924 resetNameWindow();
925 }
926
927 if (ha->flags & kBFTextBox) {
928 result = printTextOf(ha->flags / 256, x, y);
929 } else {
930 result = printNameOf(ha->itemPtr, x, y);
931 }
932
933 if (result)
934 _lastNameOn = ha;
935 }
936
937 #ifdef ENABLE_AGOS2
invertBox(HitArea * ha,bool state)938 void AGOSEngine_Feeble::invertBox(HitArea *ha, bool state) {
939 if (getBitFlag(205) || getBitFlag(206)) {
940 if (state != 0) {
941 _mouseAnimMax = _oldMouseAnimMax;
942 _mouseCursor = _oldMouseCursor;
943 } else if (_mouseCursor != 18) {
944 _oldMouseCursor = _mouseCursor;
945 _animatePointer = false;
946 _oldMouseAnimMax = _mouseAnimMax;
947 _mouseAnimMax = 2;
948 _mouseCursor = 18;
949 }
950 } else {
951 if (getBitFlag(207)) {
952 if (state != 0) {
953 _noRightClick = 0;
954 resetVerbs();
955 } else {
956 int cursor = ha->id + 9;
957 if (cursor >= 23)
958 cursor = 21;
959 _mouseCursor = cursor;
960 _mouseAnimMax = 8;
961 _noRightClick = 1;
962 }
963 } else {
964 VgaSprite *vsp = _vgaSprites;
965
966 int id = ha->id - 43;
967 while (vsp->id) {
968 if (vsp->id == id && vsp->zoneNum == 2) {
969 if (state == 0)
970 vsp->flags |= kDFShaded;
971 else
972 vsp->flags &= ~kDFShaded;
973 break;
974 }
975 vsp++;
976 }
977 }
978 }
979 }
980 #endif
981
invertBox(HitArea * ha,byte a,byte b,byte c,byte d)982 void AGOSEngine::invertBox(HitArea *ha, byte a, byte b, byte c, byte d) {
983 byte *src, color;
984 int w, h, i;
985
986 _videoLockOut |= 0x8000;
987
988 Graphics::Surface *screen = _system->lockScreen();
989 src = (byte *)screen->getBasePtr(ha->x, ha->y);
990
991 // WORKAROUND: Hitareas for saved game names aren't adjusted for scrolling locations
992 if (getGameType() == GType_SIMON2 && ha->id >= 208 && ha->id <= 213) {
993 src -= _scrollX * 8;
994 }
995
996 _litBoxFlag = true;
997
998 w = ha->width;
999 h = ha->height;
1000
1001 do {
1002 for (i = 0; i != w; ++i) {
1003 color = src[i];
1004 if (getGameType() == GType_WW) {
1005 if (!(color & 0xF) || (color & 0xF) == 10) {
1006 color ^= 10;
1007 src[i] = color;
1008 }
1009 } else if (getGameType() == GType_ELVIRA2) {
1010 if (!(color & 1)) {
1011 color ^= 2;
1012 src[i] = color;
1013 }
1014 } else if (getGameType() == GType_ELVIRA1) {
1015 if (color & 1) {
1016 color ^= 2;
1017 src[i] = color;
1018 }
1019 } else if (getGameType() == GType_PN) {
1020 if (getPlatform() == Common::kPlatformDOS) {
1021 if (color != 15) {
1022 color ^= 7;
1023 src[i] = color;
1024 }
1025 } else {
1026 if (color != 14) {
1027 color ^= 15;
1028 src[i] = color;
1029 }
1030 }
1031 } else {
1032 if (a >= color && b < color) {
1033 if (c >= color)
1034 color += d;
1035 else
1036 color -= d;
1037 src[i] = color;
1038 }
1039 }
1040 }
1041 src += screen->pitch;
1042 } while (--h);
1043
1044 _system->unlockScreen();
1045
1046 _videoLockOut &= ~0x8000;
1047 }
1048
1049 } // End of namespace AGOS
1050