diff options
Diffstat (limited to 'engines/sci')
-rw-r--r-- | engines/sci/engine/kernel_tables.h | 2 | ||||
-rw-r--r-- | engines/sci/engine/kmovement.cpp | 115 |
2 files changed, 116 insertions, 1 deletions
diff --git a/engines/sci/engine/kernel_tables.h b/engines/sci/engine/kernel_tables.h index a9b38efeef..29e2a38ad4 100644 --- a/engines/sci/engine/kernel_tables.h +++ b/engines/sci/engine/kernel_tables.h @@ -329,7 +329,7 @@ static SciKernelMapEntry s_kernelMap[] = { { MAP_CALL(DisposeScript), SIG_EVERYWHERE, "i(i*)", NULL, kDisposeScript_workarounds }, { MAP_CALL(DisposeWindow), SIG_EVERYWHERE, "i(i)", NULL, NULL }, { MAP_CALL(DoAudio), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop - { MAP_CALL(DoAvoider), SIG_EVERYWHERE, "o", NULL, NULL }, + { MAP_CALL(DoAvoider), SIG_EVERYWHERE, "o(i)", NULL, NULL }, { MAP_CALL(DoBresen), SIG_EVERYWHERE, "o", NULL, NULL }, { MAP_CALL(DoSound), SIG_EVERYWHERE, "i(.*)", kDoSound_subops, NULL }, { MAP_CALL(DoSync), SIG_EVERYWHERE, "i(.*)", NULL, NULL }, // subop diff --git a/engines/sci/engine/kmovement.cpp b/engines/sci/engine/kmovement.cpp index 7d26d10961..bc02edc1dd 100644 --- a/engines/sci/engine/kmovement.cpp +++ b/engines/sci/engine/kmovement.cpp @@ -401,6 +401,120 @@ int getAngle(int xrel, int yrel) { reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) { SegManager *segMan = s->_segMan; reg_t avoider = argv[0]; + int16 timesStep = argc > 1 ? argv[1].toUint16() : 1; + + if (!s->_segMan->isHeapObject(avoider)) { + error("DoAvoider() where avoider %04x:%04x is not an object", PRINT_REG(avoider)); + return SIGNAL_REG; + } + + reg_t client = readSelector(segMan, avoider, SELECTOR(client)); + reg_t mover = readSelector(segMan, client, SELECTOR(mover)); + if (mover.isNull()) + return SIGNAL_REG; + + // call mover::doit + invokeSelector(s, mover, SELECTOR(doit), argc, argv); + + // Read mover again + mover = readSelector(segMan, client, SELECTOR(mover)); + if (mover.isNull()) + return SIGNAL_REG; + + int16 clientX = readSelectorValue(segMan, client, SELECTOR(x)); + int16 clientY = readSelectorValue(segMan, client, SELECTOR(y)); + int16 moverX = readSelectorValue(segMan, mover, SELECTOR(x)); + int16 moverY = readSelectorValue(segMan, mover, SELECTOR(y)); + int16 avoiderHeading = readSelectorValue(segMan, avoider, SELECTOR(heading)); + + // call client::isBlocked + invokeSelector(s, client, SELECTOR(isBlocked), argc, argv); + + if (s->r_acc.isNull()) { + // not blocked + if (avoiderHeading == -1) + return SIGNAL_REG; + avoiderHeading = -1; + + // TODO: reverse this + uint16 angle = getAngle(moverX - clientX, moverY - clientY); + + reg_t clientLooper = readSelector(segMan, client, SELECTOR(looper)); + if (clientLooper.isNull()) { + kDirLoopWorker(client, angle, s, argc, argv); + } else { + // call looper::doit + reg_t params[2] = { make_reg(0, angle), client }; + invokeSelector(s, clientLooper, SELECTOR(doit), argc, argv, 2, params); + } + s->r_acc = SIGNAL_REG; + + } else { + // is blocked + if (avoiderHeading == -1) + avoiderHeading = g_sci->getRNG().getRandomBit() ? 45 : -45; + int16 clientHeading = readSelectorValue(segMan, client, SELECTOR(heading)); + clientHeading = (clientHeading / 45) * 45; + + int16 clientXstep = readSelectorValue(segMan, client, SELECTOR(xStep)) * timesStep; + int16 clientYstep = readSelectorValue(segMan, client, SELECTOR(yStep)) * timesStep; + int16 newHeading = clientHeading; + + while (1) { + int16 newX = clientX; + int16 newY = clientY; + switch (newHeading) { + case 45: + case 90: + case 135: + newX += clientXstep; + break; + case 225: + case 270: + case 315: + newX -= clientXstep; + } + + switch (newHeading) { + case 0: + case 45: + case 315: + newY -= clientYstep; + break; + case 135: + case 180: + case 225: + newY += clientYstep; + } + writeSelectorValue(segMan, client, SELECTOR(x), newX); + writeSelectorValue(segMan, client, SELECTOR(y), newY); + + // call client::canBeHere + invokeSelector(s, client, SELECTOR(canBeHere), argc, argv); + + if (!s->r_acc.isNull()) { + s->r_acc = make_reg(0, newHeading); + break; // break out + } + + clientHeading += avoiderHeading; + if (newHeading >= 360) + newHeading -= 360; + if (newHeading < 0) + newHeading += 360; + if (newHeading == clientHeading) { + // tried everything + writeSelectorValue(segMan, client, SELECTOR(x), clientX); + writeSelectorValue(segMan, client, SELECTOR(y), clientY); + s->r_acc = SIGNAL_REG; + break; // break out + } + } + } + writeSelectorValue(segMan, avoider, SELECTOR(heading), avoiderHeading); + return s->r_acc; + +#if 0 reg_t client, looper, mover; int angle; int dx, dy; @@ -508,6 +622,7 @@ reg_t kDoAvoider(EngineState *s, int argc, reg_t *argv) { } return s->r_acc; +#endif } } // End of namespace Sci |