SCI: properly reversed kDoAvoider

getAngle()-code is missing though. Still fixes lsl2early hang on airport (bug #3037036), fixes kq4early unicorn doing moonwalk (kq4late still works as well)

svn-id: r52512
This commit is contained in:
Martin Kiewitz 2010-09-04 07:29:27 +00:00
parent 976458058d
commit acc294c7a8
2 changed files with 116 additions and 1 deletions

View File

@ -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

View File

@ -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