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/inventory.h"
32 #include "tony/game.h"
33 #include "tony/tony.h"
34
35 namespace Tony {
36
37 /****************************************************************************\
38 * RMInventory Methods
39 \****************************************************************************/
40
RMInventory()41 RMInventory::RMInventory() {
42 _items = NULL;
43 _state = CLOSED;
44 _bCombining = false;
45 _csModifyInterface = g_system->createMutex();
46 _nItems = 0;
47
48 Common::fill(_inv, _inv + 256, 0);
49 _nInv = 0;
50 _curPutY = 0;
51 _curPutTime = 0;
52 _curPos = 0;
53 _bHasFocus = false;
54 _nSelectObj = 0;
55 _nCombine = 0;
56 _bBlinkingRight = false;
57 _bBlinkingLeft = false;
58 _miniAction = 0;
59 }
60
~RMInventory()61 RMInventory::~RMInventory() {
62 close();
63 g_system->deleteMutex(_csModifyInterface);
64 }
65
checkPointInside(const RMPoint & pt)66 bool RMInventory::checkPointInside(const RMPoint &pt) {
67 if (!GLOBALS._bCfgInvUp)
68 return pt._y > RM_SY - 70;
69 else
70 return pt._y < 70;
71 }
72
init()73 void RMInventory::init() {
74 // Create the main buffer
75 create(RM_SX, 68);
76 setPriority(185);
77
78 // Setup the inventory
79 _nInv = 0;
80 _curPos = 0;
81 _bCombining = false;
82
83 // New items
84 _nItems = 78; // @@@ Number of takeable items
85 _items = new RMInventoryItem[_nItems + 1];
86
87 int curres = 10500;
88
89 // Loop through the items
90 for (int i = 0; i <= _nItems; i++) {
91 // Load the items from the resource
92 RMRes res(curres);
93 assert(res.isValid());
94 Common::SeekableReadStream *ds = res.getReadStream();
95
96 // Initialize the MPAL inventory item by reading it in.
97 _items[i]._icon.setInitCurPattern(false);
98 _items[i]._icon.readFromStream(*ds);
99 delete ds;
100
101 // Puts in the default pattern 1
102 _items[i]._pointer = NULL;
103 _items[i]._status = 1;
104 _items[i]._icon.setPattern(1);
105 _items[i]._icon.doFrame(this, false);
106
107 curres++;
108 if (i == 0 || i == 28 || i == 29)
109 continue;
110
111 _items[i]._pointer = new RMGfxSourceBuffer8RLEByteAA[_items[i]._icon.numPattern()];
112
113 for (int j = 0; j < _items[i]._icon.numPattern(); j++) {
114 RMResRaw raw(curres);
115
116 assert(raw.isValid());
117
118 _items[i]._pointer[j].init((const byte *)raw, raw.width(), raw.height(), true);
119 curres++;
120 }
121 }
122
123 _items[28]._icon.setPattern(1);
124 _items[29]._icon.setPattern(1);
125
126 // Download interface
127 RMRes res(RES_I_MINIINTER);
128 assert(res.isValid());
129 Common::SeekableReadStream *ds = res.getReadStream();
130 _miniInterface.readFromStream(*ds);
131 _miniInterface.setPattern(1);
132 delete ds;
133
134 // Create the text for hints on the mini interface
135 _hints[0].setAlignType(RMText::HCENTER, RMText::VTOP);
136 _hints[1].setAlignType(RMText::HCENTER, RMText::VTOP);
137 _hints[2].setAlignType(RMText::HCENTER, RMText::VTOP);
138
139 // The text is taken from MPAL for translation
140 RMMessage msg1(15);
141 RMMessage msg2(13);
142 RMMessage msg3(14);
143
144 _hints[0].writeText(msg1[0], 1); // Examine
145 _hints[1].writeText(msg2[0], 1); // Take
146 _hints[2].writeText(msg3[0], 1); // Use
147
148 // Prepare initial inventory
149 prepare();
150 drawOT(Common::nullContext);
151 clearOT();
152 }
153
close()154 void RMInventory::close() {
155 // Has memory
156 if (_items != NULL) {
157 // Delete the item pointers
158 for (int i = 0; i <= _nItems; i++)
159 delete[] _items[i]._pointer;
160
161 // Delete the items array
162 delete[] _items;
163 _items = NULL;
164 }
165
166 destroy();
167 }
168
reset()169 void RMInventory::reset() {
170 _state = CLOSED;
171 endCombine();
172 }
173
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim)174 void RMInventory::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
175 CORO_BEGIN_CONTEXT;
176 RMPoint pos;
177 RMPoint pos2;
178 RMGfxPrimitive *p;
179 RMGfxPrimitive *p2;
180 CORO_END_CONTEXT(_ctx);
181
182 CORO_BEGIN_CODE(_ctx);
183
184 prim->setDst(RMPoint(0, _curPutY));
185 g_system->lockMutex(_csModifyInterface);
186 CORO_INVOKE_2(RMGfxWoodyBuffer::draw, bigBuf, prim);
187 g_system->unlockMutex(_csModifyInterface);
188
189 if (_state == SELECTING) {
190
191 if (!GLOBALS._bCfgInvUp) {
192 _ctx->pos.set((_nSelectObj + 1) * 64 - 20, RM_SY - 113);
193 _ctx->pos2.set((_nSelectObj + 1) * 64 + 34, RM_SY - 150);
194 } else {
195 _ctx->pos.set((_nSelectObj + 1) * 64 - 20, 72 - 4); // The brown part is at the top :(
196 _ctx->pos2.set((_nSelectObj + 1) * 64 + 34, 119 - 4);
197 }
198
199 _ctx->p = new RMGfxPrimitive(prim->_task, _ctx->pos);
200 _ctx->p2 = new RMGfxPrimitive(prim->_task, _ctx->pos2);
201
202 // Draw the mini interface
203 CORO_INVOKE_2(_miniInterface.draw, bigBuf, _ctx->p);
204
205 if (GLOBALS._bCfgInterTips) {
206 if (_miniAction == 1) // Examine
207 CORO_INVOKE_2(_hints[0].draw, bigBuf, _ctx->p2);
208 else if (_miniAction == 2) // Talk
209 CORO_INVOKE_2(_hints[1].draw, bigBuf, _ctx->p2);
210 else if (_miniAction == 3) // Use
211 CORO_INVOKE_2(_hints[2].draw, bigBuf, _ctx->p2);
212 }
213
214 delete _ctx->p;
215 delete _ctx->p2;
216 }
217
218 CORO_END_CODE;
219 }
220
removeThis(CORO_PARAM,bool & result)221 void RMInventory::removeThis(CORO_PARAM, bool &result) {
222 if (_state == CLOSED)
223 result = true;
224 else
225 result = false;
226 }
227
removeItem(int code)228 void RMInventory::removeItem(int code) {
229 for (int i = 0; i < _nInv; i++) {
230 if (_inv[i] == code - 10000) {
231 g_system->lockMutex(_csModifyInterface);
232
233 Common::copy(&_inv[i + 1], &_inv[i + 1] + (_nInv - i), &_inv[i]);
234 _nInv--;
235
236 prepare();
237 drawOT(Common::nullContext);
238 clearOT();
239 g_system->unlockMutex(_csModifyInterface);
240 return;
241 }
242 }
243 }
244
addItem(int code)245 void RMInventory::addItem(int code) {
246 if (code <= 10000 || code >= 10101) {
247 // If we are here, it means that we are adding an item that should not be in the inventory
248 warning("RMInventory::addItem(%d) - Cannot find a valid icon for this item, and then it will not be added to the inventory", code);
249 } else {
250 g_system->lockMutex(_csModifyInterface);
251 if (_curPos + 8 == _nInv) {
252 // Break through the inventory! On the flashing pattern
253 _items[28]._icon.setPattern(2);
254 }
255
256 _inv[_nInv++] = code - 10000;
257
258 prepare();
259 drawOT(Common::nullContext);
260 clearOT();
261 g_system->unlockMutex(_csModifyInterface);
262 }
263 }
264
changeItemStatus(uint32 code,uint32 dwStatus)265 void RMInventory::changeItemStatus(uint32 code, uint32 dwStatus) {
266 if (code <= 10000 || code >= 10101) {
267 error("RMInventory::changeItemStatus(%d) - Specified object code is not valid", code);
268 } else {
269 g_system->lockMutex(_csModifyInterface);
270 _items[code - 10000]._icon.setPattern(dwStatus);
271 _items[code - 10000]._status = dwStatus;
272
273 prepare();
274 drawOT(Common::nullContext);
275 clearOT();
276 g_system->unlockMutex(_csModifyInterface);
277 }
278 }
279
prepare()280 void RMInventory::prepare() {
281 for (int i = 1; i < RM_SX / 64 - 1; i++) {
282 if (i - 1 + _curPos < _nInv)
283 addPrim(new RMGfxPrimitive(&_items[_inv[i - 1 + _curPos]]._icon, RMPoint(i * 64, 0)));
284 else
285 addPrim(new RMGfxPrimitive(&_items[0]._icon, RMPoint(i * 64, 0)));
286 }
287
288 // Frecce
289 addPrim(new RMGfxPrimitive(&_items[29]._icon, RMPoint(0, 0)));
290 addPrim(new RMGfxPrimitive(&_items[28]._icon, RMPoint(640 - 64, 0)));
291 }
292
miniActive()293 bool RMInventory::miniActive() {
294 return _state == SELECTING;
295 }
296
haveFocus(const RMPoint & mpos)297 bool RMInventory::haveFocus(const RMPoint &mpos) {
298 // When we combine, have the focus only if we are on an arrow (to scroll)
299 if (_state == OPENED && _bCombining && checkPointInside(mpos) && (mpos._x < 64 || mpos._x > RM_SX - 64))
300 return true;
301
302 // If the inventory is open, focus we we go over it
303 if (_state == OPENED && !_bCombining && checkPointInside(mpos))
304 return true;
305
306 // If we are selecting a verb (and then right down), we always focus
307 if (_state == SELECTING)
308 return true;
309
310 return false;
311 }
312
endCombine()313 void RMInventory::endCombine() {
314 _bCombining = false;
315 }
316
leftClick(const RMPoint & mpos,int & nCombineObj)317 bool RMInventory::leftClick(const RMPoint &mpos, int &nCombineObj) {
318 // The left click picks an item from your inventory to use it with the background
319 int n = mpos._x / 64;
320
321 if (_state == OPENED) {
322 if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0) {
323 _bCombining = true; //m_state = COMBINING;
324 _nCombine = _inv[n - 1 + _curPos];
325 nCombineObj = _nCombine + 10000;
326
327 g_vm->playUtilSFX(1);
328 return true;
329 }
330 }
331
332 // Click the right arrow
333 if ((_state == OPENED) && _bBlinkingRight) {
334 g_system->lockMutex(_csModifyInterface);
335 _curPos++;
336
337 if (_curPos + 8 >= _nInv) {
338 _bBlinkingRight = false;
339 _items[28]._icon.setPattern(1);
340 }
341
342 if (_curPos > 0) {
343 _bBlinkingLeft = true;
344 _items[29]._icon.setPattern(2);
345 }
346
347 prepare();
348 drawOT(Common::nullContext);
349 clearOT();
350 g_system->unlockMutex(_csModifyInterface);
351 }
352
353 // Click the left arrow
354 else if ((_state == OPENED) && _bBlinkingLeft) {
355 assert(_curPos > 0);
356 g_system->lockMutex(_csModifyInterface);
357 _curPos--;
358
359 if (_curPos == 0) {
360 _bBlinkingLeft = false;
361 _items[29]._icon.setPattern(1);
362 }
363
364 if (_curPos + 8 < _nInv) {
365 _bBlinkingRight = true;
366 _items[28]._icon.setPattern(2);
367 }
368
369 prepare();
370 drawOT(Common::nullContext);
371 clearOT();
372 g_system->unlockMutex(_csModifyInterface);
373 }
374
375 return false;
376 }
377
rightClick(const RMPoint & mpos)378 void RMInventory::rightClick(const RMPoint &mpos) {
379 assert(checkPointInside(mpos));
380
381 if (_state == OPENED && !_bCombining) {
382 // Open the context interface
383 int n = mpos._x / 64;
384
385 if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0) {
386 _state = SELECTING;
387 _miniAction = 0;
388 _nSelectObj = n - 1;
389
390 g_vm->playUtilSFX(0);
391 }
392 }
393
394 if ((_state == OPENED) && _bBlinkingRight) {
395 g_system->lockMutex(_csModifyInterface);
396 _curPos += 7;
397 if (_curPos + 8 > _nInv)
398 _curPos = _nInv - 8;
399
400 if (_curPos + 8 <= _nInv) {
401 _bBlinkingRight = false;
402 _items[28]._icon.setPattern(1);
403 }
404
405 if (_curPos > 0) {
406 _bBlinkingLeft = true;
407 _items[29]._icon.setPattern(2);
408 }
409
410 prepare();
411 drawOT(Common::nullContext);
412 clearOT();
413 g_system->unlockMutex(_csModifyInterface);
414 } else if ((_state == OPENED) && _bBlinkingLeft) {
415 assert(_curPos > 0);
416 g_system->lockMutex(_csModifyInterface);
417 _curPos -= 7;
418 if (_curPos < 0)
419 _curPos = 0;
420
421 if (_curPos == 0) {
422 _bBlinkingLeft = false;
423 _items[29]._icon.setPattern(1);
424 }
425
426 if (_curPos + 8 < _nInv) {
427 _bBlinkingRight = true;
428 _items[28]._icon.setPattern(2);
429 }
430
431 prepare();
432 drawOT(Common::nullContext);
433 clearOT();
434 g_system->unlockMutex(_csModifyInterface);
435 }
436 }
437
rightRelease(const RMPoint & mpos,RMTonyAction & curAction)438 bool RMInventory::rightRelease(const RMPoint &mpos, RMTonyAction &curAction) {
439 if (_state == SELECTING) {
440 _state = OPENED;
441
442 if (_miniAction == 1) { // Examine
443 curAction = TA_EXAMINE;
444 return true;
445 } else if (_miniAction == 2) { // Talk
446 curAction = TA_TALK;
447 return true;
448 } else if (_miniAction == 3) { // Use
449 curAction = TA_USE;
450 return true;
451 }
452 }
453
454 return false;
455 }
456
457 #define INVSPEED 20
458
doFrame(RMGfxTargetBuffer & bigBuf,RMPointer & ptr,RMPoint mpos,bool bCanOpen)459 void RMInventory::doFrame(RMGfxTargetBuffer &bigBuf, RMPointer &ptr, RMPoint mpos, bool bCanOpen) {
460 if (_state != CLOSED) {
461 // Clean up the OT list
462 g_system->lockMutex(_csModifyInterface);
463 clearOT();
464
465 // DoFrame makes all the objects currently in the inventory be displayed
466 // @@@ Maybe we should do all takeable objects? Please does not help
467 bool bNeedRedraw = false;
468
469 for (int i = 0; i < _nInv; i++) {
470 if (_items[_inv[i]]._icon.doFrame(this, false) && (i >= _curPos && i <= _curPos + 7))
471 bNeedRedraw = true;
472 }
473
474 if ((_state == CLOSING || _state == OPENING || _state == OPENED) && checkPointInside(mpos)) {
475 if (mpos._x > RM_SX - 64) {
476 if (_curPos + 8 < _nInv && !_bBlinkingRight) {
477 _items[28]._icon.setPattern(3);
478 _bBlinkingRight = true;
479 bNeedRedraw = true;
480 }
481 } else if (_bBlinkingRight) {
482 _items[28]._icon.setPattern(2);
483 _bBlinkingRight = false;
484 bNeedRedraw = true;
485 }
486
487 if (mpos._x < 64) {
488 if (_curPos > 0 && !_bBlinkingLeft) {
489 _items[29]._icon.setPattern(3);
490 _bBlinkingLeft = true;
491 bNeedRedraw = true;
492 }
493 } else if (_bBlinkingLeft) {
494 _items[29]._icon.setPattern(2);
495 _bBlinkingLeft = false;
496 bNeedRedraw = true;
497 }
498 }
499
500 if (_items[28]._icon.doFrame(this, false))
501 bNeedRedraw = true;
502
503 if (_items[29]._icon.doFrame(this, false))
504 bNeedRedraw = true;
505
506 if (bNeedRedraw)
507 prepare();
508
509 g_system->unlockMutex(_csModifyInterface);
510 }
511
512 if (g_vm->getEngine()->getInput().getAsyncKeyState(Common::KEYCODE_i)) {
513 GLOBALS._bCfgInvLocked = !GLOBALS._bCfgInvLocked;
514 }
515
516 if (_bCombining) { // m_state == COMBINING)
517 ptr.setCustomPointer(&_items[_nCombine]._pointer[_items[_nCombine]._status - 1]);
518 ptr.setSpecialPointer(RMPointer::PTR_CUSTOM);
519 }
520
521 if (!GLOBALS._bCfgInvUp) {
522 if ((_state == CLOSED) && (mpos._y > RM_SY - 10 || GLOBALS._bCfgInvLocked) && bCanOpen) {
523 if (!GLOBALS._bCfgInvNoScroll) {
524 _state = OPENING;
525 _curPutY = RM_SY - 1;
526 _curPutTime = g_vm->getTime();
527 } else {
528 _state = OPENED;
529 _curPutY = RM_SY - 68;
530 }
531 } else if (_state == OPENED) {
532 if ((mpos._y < RM_SY - 70 && !GLOBALS._bCfgInvLocked) || !bCanOpen) {
533 if (!GLOBALS._bCfgInvNoScroll) {
534 _state = CLOSING;
535 _curPutY = RM_SY - 68;
536 _curPutTime = g_vm->getTime();
537 } else {
538 _state = CLOSED;
539 }
540 }
541 } else if (_state == OPENING) {
542 while (_curPutTime + INVSPEED < g_vm->getTime()) {
543 _curPutY -= 3;
544 _curPutTime += INVSPEED;
545 }
546
547 if (_curPutY <= RM_SY - 68) {
548 _state = OPENED;
549 _curPutY = RM_SY - 68;
550 }
551
552 } else if (_state == CLOSING) {
553 while (_curPutTime + INVSPEED < g_vm->getTime()) {
554 _curPutY += 3;
555 _curPutTime += INVSPEED;
556 }
557
558 if (_curPutY > 480)
559 _state = CLOSED;
560 }
561 } else {
562 if ((_state == CLOSED) && (mpos._y < 10 || GLOBALS._bCfgInvLocked) && bCanOpen) {
563 if (!GLOBALS._bCfgInvNoScroll) {
564 _state = OPENING;
565 _curPutY = - 68;
566 _curPutTime = g_vm->getTime();
567 } else {
568 _state = OPENED;
569 _curPutY = 0;
570 }
571 } else if (_state == OPENED) {
572 if ((mpos._y > 70 && !GLOBALS._bCfgInvLocked) || !bCanOpen) {
573 if (!GLOBALS._bCfgInvNoScroll) {
574 _state = CLOSING;
575 _curPutY = -2;
576 _curPutTime = g_vm->getTime();
577 } else {
578 _state = CLOSED;
579 }
580 }
581 } else if (_state == OPENING) {
582 while (_curPutTime + INVSPEED < g_vm->getTime()) {
583 _curPutY += 3;
584 _curPutTime += INVSPEED;
585 }
586
587 if (_curPutY >= 0) {
588 _state = OPENED;
589 _curPutY = 0;
590 }
591 } else if (_state == CLOSING) {
592 while (_curPutTime + INVSPEED < g_vm->getTime()) {
593 _curPutY -= 3;
594 _curPutTime += INVSPEED;
595 }
596
597 if (_curPutY < -68)
598 _state = CLOSED;
599 }
600 }
601
602 if (_state == SELECTING) {
603 int startx = (_nSelectObj + 1) * 64 - 20;
604 int starty;
605
606 if (!GLOBALS._bCfgInvUp)
607 starty = RM_SY - 109;
608 else
609 starty = 70;
610
611 // Make sure it is on one of the verbs
612 if (mpos._y > starty && mpos._y < starty + 45) {
613 if (mpos._x > startx && mpos._x < startx + 40) {
614 if (_miniAction != 1) {
615 _miniInterface.setPattern(2);
616 _miniAction = 1;
617 g_vm->playUtilSFX(1);
618 }
619 } else if (mpos._x >= startx + 40 && mpos._x < startx + 80) {
620 if (_miniAction != 2) {
621 _miniInterface.setPattern(3);
622 _miniAction = 2;
623 g_vm->playUtilSFX(1);
624 }
625 } else if (mpos._x >= startx + 80 && mpos._x < startx + 108) {
626 if (_miniAction != 3) {
627 _miniInterface.setPattern(4);
628 _miniAction = 3;
629 g_vm->playUtilSFX(1);
630 }
631 } else {
632 _miniInterface.setPattern(1);
633 _miniAction = 0;
634 }
635 } else {
636 _miniInterface.setPattern(1);
637 _miniAction = 0;
638 }
639
640 // Update the mini-interface
641 _miniInterface.doFrame(&bigBuf, false);
642 }
643
644 if ((_state != CLOSED) && !_nInList) {
645 bigBuf.addPrim(new RMGfxPrimitive(this));
646 }
647 }
648
itemInFocus(const RMPoint & mpt)649 bool RMInventory::itemInFocus(const RMPoint &mpt) {
650 if ((_state == OPENED || _state == OPENING) && checkPointInside(mpt))
651 return true;
652 else
653 return false;
654 }
655
whichItemIsIn(const RMPoint & mpt)656 RMItem *RMInventory::whichItemIsIn(const RMPoint &mpt) {
657 if (_state == OPENED) {
658 if (checkPointInside(mpt)) {
659 int n = mpt._x / 64;
660 if (n > 0 && n < RM_SX / 64 - 1 && _inv[n - 1 + _curPos] != 0 && (!_bCombining || _inv[n - 1 + _curPos] != _nCombine))
661 return &_items[_inv[n - 1 + _curPos]]._icon;
662 }
663 }
664
665 return NULL;
666 }
667
getSaveStateSize()668 int RMInventory::getSaveStateSize() {
669 // m_inv pattern m_nInv
670 return 256 * 4 + 256 * 4 + 4;
671 }
672
saveState(byte * state)673 void RMInventory::saveState(byte *state) {
674 WRITE_LE_UINT32(state, _nInv);
675 state += 4;
676 for (int i = 0; i < 256; ++i) {
677 WRITE_LE_UINT32(state, _inv[i]);
678 state += 4;
679 }
680
681 int x;
682 for (int i = 0; i < 256; i++) {
683 if (i < _nItems)
684 x = _items[i]._status;
685 else
686 x = 0;
687
688 WRITE_LE_UINT32(state, x);
689 state += 4;
690 }
691 }
692
loadState(byte * state)693 int RMInventory::loadState(byte *state) {
694 _nInv = READ_LE_UINT32(state);
695 state += 4;
696 for (int i = 0; i < 256; ++i) {
697 _inv[i] = READ_LE_UINT32(state);
698 state += 4;
699 }
700
701 for (int i = 0; i < 256; i++) {
702 int x = READ_LE_UINT32(state);
703 state += 4;
704
705 if (i < _nItems) {
706 _items[i]._status = x;
707 _items[i]._icon.setPattern(x);
708 }
709 }
710
711 _curPos = 0;
712 _bCombining = false;
713
714 _items[29]._icon.setPattern(1);
715
716 if (_nInv > 8)
717 _items[28]._icon.setPattern(2);
718 else
719 _items[28]._icon.setPattern(1);
720
721 prepare();
722 drawOT(Common::nullContext);
723 clearOT();
724
725 return getSaveStateSize();
726 }
727
operator +=(RMItem * item)728 RMInventory &RMInventory::operator+=(RMItem *item) {
729 addItem(item->mpalCode());
730 return *this;
731 }
732
operator +=(RMItem & item)733 RMInventory &RMInventory::operator+=(RMItem &item) {
734 addItem(item.mpalCode());
735 return *this;
736 }
737
operator +=(int code)738 RMInventory &RMInventory::operator+=(int code) {
739 addItem(code);
740 return *this;
741 }
742
743 /****************************************************************************\
744 * RMInterface methods
745 \****************************************************************************/
746
RMInterface()747 RMInterface::RMInterface() : RMGfxSourceBuffer8RLEByte() {
748 _bActive = _bPerorate = false;
749 _lastHotZone = -1;
750 }
751
~RMInterface()752 RMInterface::~RMInterface() {
753 }
754
active()755 bool RMInterface::active() {
756 return _bActive;
757 }
758
onWhichBox(RMPoint pt)759 int RMInterface::onWhichBox(RMPoint pt) {
760 pt -= _openStart;
761
762 // Check how many verbs you have to consider
763 int max = 4;
764 if (_bPerorate)
765 max = 5;
766
767 // Find the verb
768 for (int i = 0; i < max; i++) {
769 if (_hotbbox[i].ptInRect(pt))
770 return i;
771 }
772
773 // Found no verb
774 return -1;
775 }
776
draw(CORO_PARAM,RMGfxTargetBuffer & bigBuf,RMGfxPrimitive * prim)777 void RMInterface::draw(CORO_PARAM, RMGfxTargetBuffer &bigBuf, RMGfxPrimitive *prim) {
778 CORO_BEGIN_CONTEXT;
779 int h;
780 CORO_END_CONTEXT(_ctx);
781
782 CORO_BEGIN_CODE(_ctx);
783
784 prim->getDst().topLeft() = _openStart;
785 CORO_INVOKE_2(RMGfxSourceBuffer8RLEByte::draw, bigBuf, prim);
786
787 // Check if there is a draw hot zone
788 _ctx->h = onWhichBox(_mpos);
789 if (_ctx->h != -1) {
790 prim->getDst().topLeft() = _openStart;
791 CORO_INVOKE_2(_hotzone[_ctx->h].draw, bigBuf, prim);
792
793 if (_lastHotZone != _ctx->h) {
794 _lastHotZone = _ctx->h;
795 g_vm->playUtilSFX(1);
796 }
797
798 if (GLOBALS._bCfgInterTips) {
799 prim->getDst().topLeft() = _openStart + RMPoint(70, 177);
800 CORO_INVOKE_2(_hints[_ctx->h].draw, bigBuf, prim);
801 }
802 } else
803 _lastHotZone = -1;
804
805 CORO_END_CODE;
806 }
807
doFrame(RMGfxTargetBuffer & bigBuf,RMPoint mousepos)808 void RMInterface::doFrame(RMGfxTargetBuffer &bigBuf, RMPoint mousepos) {
809 // If needed, add to the OT schedule list
810 if (!_nInList && _bActive)
811 bigBuf.addPrim(new RMGfxPrimitive(this));
812
813 _mpos = mousepos;
814 }
815
clicked(const RMPoint & mousepos)816 void RMInterface::clicked(const RMPoint &mousepos) {
817 _bActive = true;
818 _openPos = mousepos;
819
820 // Calculate the top left corner of the interface
821 _openStart = _openPos - RMPoint(_dimx / 2, _dimy / 2);
822 _lastHotZone = -1;
823
824 // Keep it inside the screen
825 if (_openStart._x < 0)
826 _openStart._x = 0;
827 if (_openStart._y < 0)
828 _openStart._y = 0;
829 if (_openStart._x + _dimx > RM_SX)
830 _openStart._x = RM_SX - _dimx;
831 if (_openStart._y + _dimy > RM_SY)
832 _openStart._y = RM_SY - _dimy;
833
834 // Play the sound effect
835 g_vm->playUtilSFX(0);
836 }
837
released(const RMPoint & mousepos,RMTonyAction & action)838 bool RMInterface::released(const RMPoint &mousepos, RMTonyAction &action) {
839 if (!_bActive)
840 return false;
841
842 _bActive = false;
843
844 switch (onWhichBox(mousepos)) {
845 case 0:
846 action = TA_TAKE;
847 break;
848
849 case 1:
850 action = TA_TALK;
851 break;
852
853 case 2:
854 action = TA_USE;
855 break;
856
857 case 3:
858 action = TA_EXAMINE;
859 break;
860
861 case 4:
862 action = TA_PERORATE;
863 break;
864
865 default: // No verb
866 return false;
867 }
868
869 return true;
870 }
871
reset()872 void RMInterface::reset() {
873 _bActive = false;
874 }
875
setPerorate(bool bOn)876 void RMInterface::setPerorate(bool bOn) {
877 _bPerorate = bOn;
878 }
879
getPerorate()880 bool RMInterface::getPerorate() {
881 return _bPerorate;
882 }
883
init()884 void RMInterface::init() {
885 RMResRaw inter(RES_I_INTERFACE);
886 RMRes pal(RES_I_INTERPPAL);
887
888 setPriority(191);
889
890 RMGfxSourceBuffer::init(inter, inter.width(), inter.height());
891 loadPaletteWA(RES_I_INTERPAL);
892
893 for (int i = 0; i < 5; i++) {
894 RMResRaw part(RES_I_INTERP1 + i);
895
896 _hotzone[i].init(part, part.width(), part.height());
897 _hotzone[i].loadPaletteWA(pal);
898 }
899
900 _hotbbox[0].setRect(126, 123, 159, 208); // Take
901 _hotbbox[1].setRect(90, 130, 125, 186); // About
902 _hotbbox[2].setRect(110, 60, 152, 125);
903 _hotbbox[3].setRect(56, 51, 93, 99);
904 _hotbbox[4].setRect(51, 105, 82, 172);
905
906 _hints[0].setAlignType(RMText::HRIGHT, RMText::VTOP);
907 _hints[1].setAlignType(RMText::HRIGHT, RMText::VTOP);
908 _hints[2].setAlignType(RMText::HRIGHT, RMText::VTOP);
909 _hints[3].setAlignType(RMText::HRIGHT, RMText::VTOP);
910 _hints[4].setAlignType(RMText::HRIGHT, RMText::VTOP);
911
912 // The text is taken from MPAL for translation
913 RMMessage msg0(12);
914 RMMessage msg1(13);
915 RMMessage msg2(14);
916 RMMessage msg3(15);
917 RMMessage msg4(16);
918
919 _hints[0].writeText(msg0[0], 1); // Take
920 _hints[1].writeText(msg1[0], 1); // Talk
921 _hints[2].writeText(msg2[0], 1); // Use
922 _hints[3].writeText(msg3[0], 1); // Examine
923 _hints[4].writeText(msg4[0], 1); // Show Yourself
924
925 _bActive = false;
926 _bPerorate = false;
927 _lastHotZone = 0;
928 }
929
close()930 void RMInterface::close() {
931 destroy();
932
933 for (int i = 0; i < 5; i++)
934 _hotzone[i].destroy();
935 }
936
937 } // End of namespace Tony
938