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]));
156 debugC(3, kDebugLevelScript
, "opcode 0x41: say %s", +a
[0]);
158 if (Log
.protagonist()->isSpeaking()) {
159 Log
.protagonist()->callMeWhenSilent(current
);
163 if (Log
.protagonist()->isMoving()) {
164 Log
.protagonist()->callMeWhenStill(current
);
168 Log
.protagonist()->say(a
[0]);
173 debugC(3, kDebugLevelScript
, "opcode 0x54: ask about '%s' at %s:%s %sx%s", +a
[4], +a
[0], +a
[1], +a
[2], +a
[3]);
176 unless ((result
= _graphics
->ask(a
[0], a
[1], a
[2], a
[3], a
[4])) == 0xffff)
177 return CodePointer(result
, this);
183 // args: left, top, colour, text
184 debugC(3, kDebugLevelScript
, "opcode 0x55: paint '%s' with colour %s at %s:%s", +a
[3], +a
[2], +a
[0], +a
[1]);
185 _graphics
->paintText(a
[0], a
[1], a
[2], a
[3]);
191 debugC(3, kDebugLevelScript
, "opcode 0x86: say %s for %s frames", +a
[1], +a
[0]);
192 Graf
.say(a
[1], a
[1], a
[0]);
198 debugC(3, kDebugLevelScript
, "opcode 0x57: wait until text is said");
199 Graf
.runWhenSaid(next
);
205 // takes a list (1st)
207 // a field (as offset from structure start) (3rd)
208 // first word on the list is entry length in words (minus one for index)
209 // then are entries, first word being index
210 // finds entry matching index == value in the list and
211 // saves value of specified field in 4th argument
212 uint16 offset
= static_cast<CodePointer
&>(a
[0]).offset();
215 byte
*pos
= _base
+ offset
;
216 uint16 width
= READ_LE_UINT16(pos
);
219 uint16 index
= READ_LE_UINT16(pos
);
220 if (index
== 0xffff) {
226 value
= READ_LE_UINT16(pos
+ a
[2]);
232 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]);
238 // get actor property
239 Actor
*actor
= _logic
->getActor(a
[0]);
242 switch (uint16(a
[1]) & 0xff) {
243 case Actor::kOffsetRoom
:
245 a
[2] = actor
->room();
247 /* case Actor::kOffsetOffset:
249 a[2] = actor->offset();
251 case Actor::kOffsetLeft:
253 a[2] = actor->left();
255 case Actor::kOffsetTop:
259 case Actor::kOffsetMainSprite:
261 a[2] = actor->mainSprite();
263 case Actor::kOffsetTicksLeft:
265 a[2] = actor->ticksLeft();
267 case Actor::kOffsetCode:
269 a[2] = actor->code();
271 case Actor::kOffsetInterval:
273 a[2] = actor->interval();
276 error("unhandled actor property %s", +a
[1]);
279 debugC(3, kDebugLevelScript
, "opcode 0x63: %s = get %s of actor %s", +a
[2], desc
, +a
[0]);
285 debugC(3, kDebugLevelScript
, "opcode 0x6d: %s++", +a
[0]);
292 debugC(3, kDebugLevelScript
, "opcode 0x6d: %s--", +a
[0]);
299 debugC(3, kDebugLevelScript
, "opcode 0x70: %s = %s", +a
[0], +a
[1]);
306 debugC(3, kDebugLevelScript
, "opcode 0x72: %s = 1", +a
[0]);
313 debugC(3, kDebugLevelScript
, "opcode 0x73: %s = 0", +a
[0]);
319 // initialize protagonist
320 debugC(3, kDebugLevelScript
, "opcode 0x77: go to room %s facing %s", +a
[0], +a
[1]);
321 _logic
->protagonist()->setRoom(a
[0], a
[1]);
322 _logic
->changeRoom(a
[0]);
327 // move actor to another room
328 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]);
329 _logic
->getActor(a
[0])->setRoom(a
[1]);
335 Exit
*exit
= _logic
->blockProgram()->getExit(a
[0]);
336 debugC(3, kDebugLevelScript
, "opcode 0x7c: toggling exit %s to %s", +a
[0], exit
->isEnabled() ? "disabled" : "enabled");
337 exit
->setEnabled(!exit
->isEnabled());
342 // disallow user interaction
343 debugC(1, kDebugLevelScript
, "opcode 0x96: lock control STUB");
348 // wait for protagonist to exit
349 debugC(3, kDebugLevelScript
, "opcoe 0x99: wait for protagonist to exit");
351 Actor
*ac
= _logic
->protagonist();
352 if (ac
->room() != _logic
->currentRoom())
360 // wait for actor to exit
361 debugC(3, kDebugLevelScript
, "opcode 0x9a: wait for actor %s to exit", +a
[0]);
363 Actor
*ac
= _logic
->getActor(a
[0]);
364 if (ac
->room() != _logic
->currentRoom())
373 debugC(3, kDebugLevelScript
, "opcode 0x9b: delay %s frames", +a
[0]);
374 _logic
->runLater(next
, a
[0]);
379 // wait until another room
380 debugC(3, kDebugLevelScript
, "opcode 0x9a: wait until actor %s enters or %s ticks", +a
[0], +a
[1]);
382 Actor
*ac
= _logic
->getActor(a
[0]);
383 if (ac
->room() != _logic
->currentRoom()) {
384 ac
->tellMe(next
, a
[1]);
392 debugC(3, kDebugLevelScript
, "opcode 0x9d: set protagonist(%s)", +a
[0]);
393 _logic
->setProtagonist(a
[0]);
398 // set protagonist frame
399 debugC(3, kDebugLevelScript
, "opcode 0xab: set protagonist frame to %s", +a
[0]);
401 Actor
*ac
= Log
.protagonist();
413 debugC(3, kDebugLevelScript
, "opcode 0xad: move actor %s to frame %s next", +a
[0], +a
[1]);
415 Actor
*ac
= _logic
->getActor(a
[0]);
421 // TODO: special handling for protagonist
429 debugC(3, kDebugLevelScript
, "opcode 0xbc: hide actor %s", +a
[0]);
430 _logic
->getActor(a
[0])->hide();
435 // set protagonist animation
436 debugC(3, kDebugLevelScript
, "opcode 0xbd: set protagonist animation to %s", +a
[0]);
438 Actor
*ac
= Log
.protagonist();
444 CodePointer
p(static_cast<CodePointer
&>(a
[0]).offset(), Log
.mainInterpreter());
450 // add animation at cursor
451 debugC(3, kDebugLevelScript
, "opcode 0xc2: add animation %s at cursor partial STUB", +a
[0]);
452 _logic
->addAnimation(new Animation(static_cast<CodePointer
&>(a
[0]), _graphics
->cursorPosition()));
457 // suspend execution until an animation's ip points to 0xff
458 debugC(3, kDebugLevelScript
, "opcode 0xc6: wait on animation %s", +a
[0]);
459 _logic
->animation(a
[0])->runOnNextFrame(next
);
465 debugC(3, kDebugLevelScript
, "opcode 0xc7: play movie %s with slowness %s", +a
[0], +a
[1]);
466 Movie
*m
= Movie::fromFile(reinterpret_cast<char *>((byte
*)(a
[0])));
467 m
->setFrameDelay(a
[1]);
474 // (not sure what's the difference to c9)
475 debugC(3, kDebugLevelScript
, "opcode 0xc8: set backdrop(%s)", +a
[0]);
476 _graphics
->setBackdrop(a
[0]);
482 // does it set the default one?
483 debugC(3, kDebugLevelScript
, "opcode 0xc9: set backdrop(%s)", +a
[0]);
484 _graphics
->setBackdrop(a
[0]);
490 debugC(1, kDebugLevelScript
, "opcode 0xcc: go fullscreen STUB");
496 debugC(2, kDebugLevelScript
, "opcode 0xce: start cutscene partial STUB");
499 // set game area height to 200
505 debugC(1, kDebugLevelScript
, "opcode 0xcf: fadeout");
506 _graphics
->fadeOut();
511 debugC(1, kDebugLevelScript
, "opcode 0xd0: partial fadeout");
512 Graf
.fadeOut(Graphics::kPartialFade
);
517 debugC(3, kDebugLevelScript
, "opcode 0xd1: fadein next paint");
518 _graphics
->willFadein();
523 // prepare interface palette
524 debugC(3, kDebugLevelScript
, "opcode 0xd2: will fadein partially");
525 Graf
.willFadein(Graphics::kPartialFade
);
530 kCopyProtectionRoom
= 81,
531 kIntroOffset
= 0x33a3
536 debugC(1, kDebugLevelScript
, "opcode 0xd6: change room(%s)", +a
[0]);
538 if (room
== kCopyProtectionRoom
) {
539 if (_engine
->_startRoom
)
540 room
= Eng
._startRoom
;
542 _logic
->changeRoom(room
);
543 if (room
== kCopyProtectionRoom
&& !Eng
._copyProtection
) {
544 Log
.runLater(CodePointer(kIntroOffset
, Log
.blockInterpreter()));
552 debugC(3, kDebugLevelScript
, "opcode 0xdb: add rect %s at %s %s %s %s", +a
[0], +a
[1], +a
[2], +a
[3], +a
[4]);
553 Log
.room()->addRect(Room::Rect(a
[0].signd(), Common::Rect(a
[1].signd(), a
[4].signd(), a
[2].signd(), a
[3].signd())));
559 std::vector
<byte
> nexts(8);
560 for (int i
= 0; i
< 4; i
++) {
562 nexts
[2*i
] = val
& 0xff;
563 nexts
[2*i
+1] = val
>> 8;
565 const int16 left
= a
[0].signd();
566 const int16 top
= a
[1].signd();
567 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]);
568 Log
.room()->addActorFrame(Common::Point(left
, top
), nexts
);
573 // hide all exits from the map
574 debugC(1, kDebugLevelScript
, "opcode 0xe5: hide exits from map STUB");
579 // set room loop code
580 debugC(3, kDebugLevelScript
, "opcode 0xe6: set room loop to %s", +a
[0]);
581 assert(a
[0].holdsCode());
582 _logic
->setRoomLoop(static_cast<CodePointer
&>(a
[0]));
588 uint16 value
= _engine
->getRandom(a
[0]);
589 debugC(3, kDebugLevelScript
, "opcode 0xef: %s = %d == random(%s)", +a
[1], value
, +a
[0]);
596 debugC(1, kDebugLevelScript
, "opcode 0xf0: load sfx set %s STUB", +a
[0]);
602 debugC(1, kDebugLevelScript
, "opcode 0xf4: play music script at %s", +a
[0]);
603 Music
.loadMusic(static_cast<CodePointer
&>(a
[0]).offset() + Log
.mainInterpreter()->_base
);
609 debugC(1, kDebugLevelScript
, "opcode 0xf7: stop music STUB");
616 debugC(1, kDebugLevelScript
, "opcode 0xf9: set %s to %s STUB", a
[0] == 1 ? "music" : "sfx", +a
[1]);
622 debugC(3, kDebugLevelScript
, "opcode 0xfc: quit%s", a
[0] == 0 ? "" : " unconditionally");
624 error("asking for quitting not implemented");
630 // #define ANIMCODE(n) template<> void Animation::handle<n>()
634 // uint16 left = READ_LE_UINT16(_code + 2);
635 // uint16 top = READ_LE_UINT16(_code + 4);
636 // setPosition(Common::Point(left, top));
641 // // get sprite id from main variable
642 // const uint16 offset = READ_LE_UINT16(_code + 2);
643 // const byte *var = _resources->getGlobalWordVariable(offset/2);
644 // const uint16 sprite = READ_LE_UINT16(var);
645 // setSprite(sprite);
650 // setZIndex(_code[1]);
651 // // TODO set field 16 to 0
655 } // End of namespace Innocent