1 #include "innocent/inter.h"
5 #include "innocent/actor.h"
6 #include "innocent/animation.h"
7 #include "innocent/exit.h"
8 #include "innocent/graphics.h"
9 #include "innocent/innocent.h"
10 #include "innocent/logic.h"
11 #include "innocent/movie.h"
12 #include "innocent/musicparser.h"
13 #include "innocent/room.h"
14 #include "innocent/util.h"
16 #include "common/events.h"
17 #include "common/util.h"
20 #define OPCODE(num) template<> Interpreter::OpResult Interpreter::opcodeHandler<num>(ValueVector a, CodePointer current, CodePointer next)
24 debugC(3, kDebugLevelScript
, "opcode 0x00: nop");
30 // (some peculiarities in conj. with op 0x38, needs research TODO)
31 debugC(3, kDebugLevelScript
, "opcode 0x01: exit");
37 debugC(3, kDebugLevelScript
, "opcode 0x02: if %s == %s", +a
[0], +a
[1]);
45 debugC(3, kDebugLevelScript
, "opcode 0x03: if %s != %s", +a
[0], +a
[1]);
53 debugC(3, kDebugLevelScript
, "opcode 0x04: if %s < %s", +a
[0], +a
[1]);
61 debugC(3, kDebugLevelScript
, "opcode 0x05: if %s > %s", +a
[0], +a
[1]);
69 debugC(3, kDebugLevelScript
, "opcode 0x0f: if current room == %s then", +a
[0]);
70 unless (a
[0] == _logic
->currentRoom())
76 // if sound is on then
77 // (argument is a set of flags, 1 - adlib, 2 - sb, 4 - roland)
78 debugC(2, kDebugLevelScript
, "opcode 0x12: if sound is on then partial STUB");
79 // just say roland+sb for now
86 // if left button is up
87 // and current mode isn't null
88 debugC(1, kDebugLevelScript
, "opcode 0x13: if 1st button is up and mode isn't null partial STUB");
89 if (_engine
->_eventMan
->getButtonState() & Common::EventManager::LBUTTON
)
95 // if actor in current room then whatever
96 debugC(1, kDebugLevelScript, "opcode 0x1f: if actor %s in current room and STUB then", +a[1]);
97 if (_logic->getActor(a[1])->room() == _logic->currentRoom())
98 error("case with condition true unhandled");
106 debugC(3, kDebugLevelScript
, "opcode 0x24: if (%s)", +a
[0]);
114 debugC(3, kDebugLevelScript
, "opcode 0x2c: else");
121 debugC(3, kDebugLevelScript
, "opcode 0x2d: end if");
127 debugC(3, kDebugLevelScript
, "opcode 0x35: jump to %s", +a
[0]);
128 return static_cast<CodePointer
&>(a
[0]);
133 debugC(3, kDebugLevelScript
, ">>>opcode 0x36: call procedure %s", +a
[0]);
134 CodePointer
&p
= static_cast<CodePointer
&>(a
[0]);
136 debugC(3, kDebugLevelScript
, "<<<opcode 0x36: called procedure %s", +a
[0]);
142 debugC(3, kDebugLevelScript
, "opcode 0x39: execute main %s later", +a
[0]);
143 _logic
->runLater(CodePointer(static_cast<CodePointer
&>(a
[0]).offset(), _logic
->mainInterpreter()));
148 // save first arg -- instruction pointer -- for after skipping animation
149 debugC(3, kDebugLevelScript
, "opcode 0x3d: store position to continue if animation skipped to %s", +a
[0]);
150 Log
.setSkipPoint(static_cast<CodePointer
&>(a
[0]));
155 debugC(3, kDebugLevelScript
, "opcode 0x54: ask about '%s' at %s:%s %sx%s", +a
[4], +a
[0], +a
[1], +a
[2], +a
[3]);
158 unless ((result
= _graphics
->ask(a
[0], a
[1], a
[2], a
[3], a
[4])) == 0xffff)
159 return CodePointer(result
, this);
165 // args: left, top, colour, text
166 debugC(3, kDebugLevelScript
, "opcode 0x55: paint '%s' with colour %s at %s:%s", +a
[3], +a
[2], +a
[0], +a
[1]);
167 _graphics
->paintText(a
[0], a
[1], a
[2], a
[3]);
173 debugC(3, kDebugLevelScript
, "opcode 0x86: say %s for %s frames", +a
[1], +a
[0]);
174 Graf
.say(a
[1], a
[1], a
[0]);
180 debugC(3, kDebugLevelScript
, "opcode 0x57: wait until text is said");
181 Graf
.runWhenSaid(next
);
187 // takes a list (1st)
189 // a field (as offset from structure start) (3rd)
190 // first word on the list is entry length in words (minus one for index)
191 // then are entries, first word being index
192 // finds entry matching index == value in the list and
193 // saves value of specified field in 4th argument
194 uint16 offset
= static_cast<CodePointer
&>(a
[0]).offset();
197 byte
*pos
= _base
+ offset
;
198 uint16 width
= READ_LE_UINT16(pos
);
201 uint16 index
= READ_LE_UINT16(pos
);
202 if (index
== 0xffff) {
208 value
= READ_LE_UINT16(pos
+ a
[2]);
214 debugC(3, kDebugLevelScript
, "opcode 0x60: %s = %d == search list %s for %s and return field %s", +a
[3], value
, +a
[0], +a
[1], +a
[2]);
220 // get actor property
221 Actor
*actor
= _logic
->getActor(a
[0]);
224 switch (uint16(a
[1]) & 0xff) {
225 case Actor::kOffsetRoom
:
227 a
[2] = actor
->room();
229 /* case Actor::kOffsetOffset:
231 a[2] = actor->offset();
233 case Actor::kOffsetLeft:
235 a[2] = actor->left();
237 case Actor::kOffsetTop:
241 case Actor::kOffsetMainSprite:
243 a[2] = actor->mainSprite();
245 case Actor::kOffsetTicksLeft:
247 a[2] = actor->ticksLeft();
249 case Actor::kOffsetCode:
251 a[2] = actor->code();
253 case Actor::kOffsetInterval:
255 a[2] = actor->interval();
258 error("unhandled actor property %s", +a
[1]);
261 debugC(3, kDebugLevelScript
, "opcode 0x63: %s = get %s of actor %s", +a
[2], desc
, +a
[0]);
267 debugC(3, kDebugLevelScript
, "opcode 0x6d: %s++", +a
[0]);
274 debugC(3, kDebugLevelScript
, "opcode 0x6d: %s--", +a
[0]);
281 debugC(3, kDebugLevelScript
, "opcode 0x70: %s = %s", +a
[0], +a
[1]);
288 debugC(3, kDebugLevelScript
, "opcode 0x72: %s = 1", +a
[0]);
295 debugC(3, kDebugLevelScript
, "opcode 0x73: %s = 0", +a
[0]);
301 // initialize protagonist
302 debugC(3, kDebugLevelScript
, "opcode 0x77: go to room %s facing %s", +a
[0], +a
[1]);
303 _logic
->protagonist()->setRoom(a
[0], a
[1]);
304 _logic
->changeRoom(a
[0]);
309 // move actor to another room
310 debugC(1, kDebugLevelScript
, "opcode 0x79: move actor %s to room %s (and set current animation frame to %s STUB)", +a
[0], +a
[1], +a
[2]);
311 _logic
->getActor(a
[0])->setRoom(a
[1]);
317 Exit
*exit
= _logic
->blockProgram()->getExit(a
[0]);
318 debugC(3, kDebugLevelScript
, "opcode 0x7c: toggling exit %s to %s", +a
[0], exit
->isEnabled() ? "disabled" : "enabled");
319 exit
->setEnabled(!exit
->isEnabled());
324 // disallow user interaction
325 debugC(1, kDebugLevelScript
, "opcode 0x96: lock control STUB");
330 // wait for actor to exit
331 debugC(3, kDebugLevelScript
, "opcode 0x9a: wait for actor %s to exit", +a
[0]);
333 Actor
*ac
= _logic
->getActor(a
[0]);
334 if (ac
->room() != _logic
->currentRoom())
343 debugC(3, kDebugLevelScript
, "opcode 0x9b: delay %s frames", +a
[0]);
344 _logic
->runLater(next
, a
[0]);
349 // wait until another room
350 debugC(3, kDebugLevelScript
, "opcode 0x9a: wait until actor %s enters or %s ticks", +a
[0], +a
[1]);
352 Actor
*ac
= _logic
->getActor(a
[0]);
353 if (ac
->room() != _logic
->currentRoom()) {
354 ac
->tellMe(next
, a
[1]);
362 debugC(3, kDebugLevelScript
, "opcode 0x9d: set protagonist(%s)", +a
[0]);
363 _logic
->setProtagonist(a
[0]);
368 // // set protagonist frame
369 // debugC(3, kDebugLevelScript, "opcode 0xab: set protagonist frame to %s", +a[0]);
371 // Actor *ac = Log.protagonist();
372 // if (!ac->isVisible()) {
373 // ac->whenYouHideUpCall(current);
377 // ac->setFrame(a[0]);
383 debugC(3, kDebugLevelScript
, "opcode 0xad: move actor %s to frame %s next", +a
[0], +a
[1]);
385 Actor
*ac
= _logic
->getActor(a
[0]);
391 // TODO: special handling for protagonist
399 // debugC(3, kDebugLevelScript, "opcode 0xbc: hide actor %s", +a[0]);
400 // _logic->getActor(a[0])->hide();
405 // // set protagonist animation
406 // debugC(3, kDebugLevelScript, "opcode 0xbd: set protagonist animation to %s", +a[0]);
408 // Actor *ac = Log.protagonist();
409 // if (!ac->isVisible()) {
410 // ac->whenYouHideUpCall(current);
414 // CodePointer p(static_cast<CodePointer &>(a[0]).offset(), Log.mainInterpreter());
415 // ac->setAnimation(p);
420 // add animation at cursor
421 debugC(3, kDebugLevelScript
, "opcode 0xc2: add animation %s at cursor partial STUB", +a
[0]);
422 _logic
->addAnimation(new Animation(static_cast<CodePointer
&>(a
[0]), _graphics
->cursorPosition()));
427 // suspend execution until an animation's ip points to 0xff
428 debugC(3, kDebugLevelScript
, "opcode 0xc6: wait on animation %s", +a
[0]);
429 _logic
->animation(a
[0])->runOnNextFrame(next
);
435 debugC(3, kDebugLevelScript
, "opcode 0xc7: play movie %s with slowness %s", +a
[0], +a
[1]);
436 Movie
*m
= Movie::fromFile(reinterpret_cast<char *>((byte
*)(a
[0])));
437 m
->setFrameDelay(a
[1]);
444 // (not sure what's the difference to c9)
445 debugC(3, kDebugLevelScript
, "opcode 0xc8: set backdrop(%s)", +a
[0]);
446 _graphics
->setBackdrop(a
[0]);
452 // does it set the default one?
453 debugC(3, kDebugLevelScript
, "opcode 0xc9: set backdrop(%s)", +a
[0]);
454 _graphics
->setBackdrop(a
[0]);
460 debugC(1, kDebugLevelScript
, "opcode 0xcc: go fullscreen STUB");
466 debugC(2, kDebugLevelScript
, "opcode 0xce: start cutscene partial STUB");
469 // set game area height to 200
475 debugC(1, kDebugLevelScript
, "opcode 0xcf: fadeout");
476 _graphics
->fadeOut();
481 debugC(1, kDebugLevelScript
, "opcode 0xd0: partial fadeout");
482 Graf
.fadeOut(Graphics::kPartialFade
);
487 debugC(3, kDebugLevelScript
, "opcode 0xd1: fadein next paint");
488 _graphics
->willFadein();
493 // prepare interface palette
494 debugC(3, kDebugLevelScript
, "opcode 0xd2: will fadein partially");
495 Graf
.willFadein(Graphics::kPartialFade
);
500 kCopyProtectionRoom
= 81,
501 kIntroOffset
= 0x33a3
506 debugC(1, kDebugLevelScript
, "opcode 0xd6: change room(%s)", +a
[0]);
508 if (room
== kCopyProtectionRoom
) {
509 if (_engine
->_startRoom
)
510 room
= Eng
._startRoom
;
512 _logic
->changeRoom(room
);
513 if (room
== kCopyProtectionRoom
&& !Eng
._copyProtection
) {
514 Log
.runLater(CodePointer(kIntroOffset
, Log
.blockInterpreter()));
522 debugC(3, kDebugLevelScript
, "opcode 0xdb: add rect %s at %s %s %s %s", +a
[0], +a
[1], +a
[2], +a
[3], +a
[4]);
523 Log
.room()->addRect(Room::Rect(a
[0].signd(), Common::Rect(a
[1].signd(), a
[4].signd(), a
[2].signd(), a
[3].signd())));
529 std::vector
<byte
> nexts(8);
530 for (int i
= 0; i
< 4; i
++) {
532 nexts
[2*i
] = val
& 0xff;
533 nexts
[2*i
+1] = val
>> 8;
535 const int16 left
= a
[0].signd();
536 const int16 top
= a
[1].signd();
537 debugC(3, kDebugLevelScript
, "opcode 0xdf: add actor frame %d %d %d %d %d %d %d %d %d %d", left
, top
, nexts
[0], nexts
[1], nexts
[2], nexts
[3], nexts
[4], nexts
[5], nexts
[6], nexts
[7]);
538 Log
.room()->addActorFrame(Actor::Frame(left
, top
, nexts
));
543 // hide all exits from the map
544 debugC(1, kDebugLevelScript
, "opcode 0xe5: hide exits from map STUB");
549 // set room loop code
550 debugC(3, kDebugLevelScript
, "opcode 0xe6: set room loop to %s", +a
[0]);
551 assert(a
[0].holdsCode());
552 _logic
->setRoomLoop(static_cast<CodePointer
&>(a
[0]));
558 uint16 value
= _engine
->getRandom(a
[0]);
559 debugC(3, kDebugLevelScript
, "opcode 0xef: %s = %d == random(%s)", +a
[1], value
, +a
[0]);
566 debugC(1, kDebugLevelScript
, "opcode 0xf0: load sfx set %s STUB", +a
[0]);
572 debugC(1, kDebugLevelScript
, "opcode 0xf4: play music script at %s", +a
[0]);
573 Music
.loadMusic(static_cast<CodePointer
&>(a
[0]).offset() + Log
.mainInterpreter()->_base
);
579 debugC(1, kDebugLevelScript
, "opcode 0xf7: stop music STUB");
586 debugC(1, kDebugLevelScript
, "opcode 0xf9: set %s to %s STUB", a
[0] == 1 ? "music" : "sfx", +a
[1]);
592 debugC(3, kDebugLevelScript
, "opcode 0xfc: quit%s", a
[0] == 0 ? "" : " unconditionally");
594 error("asking for quitting not implemented");
600 // #define ANIMCODE(n) template<> void Animation::handle<n>()
604 // uint16 left = READ_LE_UINT16(_code + 2);
605 // uint16 top = READ_LE_UINT16(_code + 4);
606 // setPosition(Common::Point(left, top));
611 // // get sprite id from main variable
612 // const uint16 offset = READ_LE_UINT16(_code + 2);
613 // const byte *var = _resources->getGlobalWordVariable(offset/2);
614 // const uint16 sprite = READ_LE_UINT16(var);
615 // setSprite(sprite);
620 // setZIndex(_code[1]);
621 // // TODO set field 16 to 0
625 } // End of namespace Innocent