void AgiEngine::motionMoveObj(VtEntry *v) { v->direction = getDirection(v->xPos, v->yPos, v->parm1, v->parm2, v->stepSize); // Update V6 if ego if (isEgoView(v)) _game.vars[vEgoDir] = v->direction; if (v->direction == 0) inDestination(v); }
/** * Update position of objects * This function updates the position of all animated, updating view * table entries according to its motion type, step size, etc. The * new position must be valid according to the sprite positioning * rules, otherwise the previous position will be kept. */ void AgiEngine::updatePosition() { VtEntry *v; int x, y, oldX, oldY, border; _game.vars[vBorderCode] = 0; _game.vars[vBorderTouchEgo] = 0; _game.vars[vBorderTouchObj] = 0; for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) { if ((v->flags & (ANIMATED | UPDATE | DRAWN)) != (ANIMATED | UPDATE | DRAWN)) { continue; } if (v->stepTimeCount != 0) { if (--v->stepTimeCount != 0) continue; } v->stepTimeCount = v->stepTime; x = oldX = v->xPos; y = oldY = v->yPos; // If object has moved, update its position if (~v->flags & UPDATE_POS) { int dx[9] = { 0, 0, 1, 1, 1, 0, -1, -1, -1 }; int dy[9] = { 0, -1, -1, 0, 1, 1, 1, 0, -1 }; x += v->stepSize * dx[v->direction]; y += v->stepSize * dy[v->direction]; } // Now check if it touched the borders border = 0; // Check left/right borders if (x < 0) { x = 0; border = 4; } else if (x <= 0 && getVersion() == 0x3086) { // KQ4 x = 0; // See Sarien bug #590462 border = 4; } else if (v->entry == 0 && x == 0 && v->flags & ADJ_EGO_XY) { // Extra test to walk west clicking the mouse x = 0; border = 4; } else if (x + v->xSize > _WIDTH) { x = _WIDTH - v->xSize; border = 2; } // Check top/bottom borders. if (y - v->ySize + 1 < 0) { y = v->ySize - 1; border = 1; } else if (y > _HEIGHT - 1) { y = _HEIGHT - 1; border = 3; } else if ((~v->flags & IGNORE_HORIZON) && y <= _game.horizon) { debugC(4, kDebugLevelSprites, "y = %d, horizon = %d", y, _game.horizon); y = _game.horizon + 1; border = 1; } // Test new position. rollback if test fails v->xPos = x; v->yPos = y; if (checkCollision(v) || !checkPriority(v)) { v->xPos = oldX; v->yPos = oldY; border = 0; fixPosition(v->entry); } if (border != 0) { if (isEgoView(v)) { _game.vars[vBorderTouchEgo] = border; } else { _game.vars[vBorderCode] = v->entry; _game.vars[vBorderTouchObj] = border; } if (v->motion == MOTION_MOVE_OBJ) { inDestination(v); } } v->flags &= ~UPDATE_POS; } }
// If main_cycle returns false, don't process more events! int AgiEngine::mainCycle() { unsigned int key, kascii; VtEntry *v = &_game.viewTable[0]; pollTimer(); updateTimer(); key = doPollKeyboard(); // In AGI Mouse emulation mode we must update the mouse-related // vars in every interpreter cycle. // // We run AGIMOUSE always as a side effect if (getFeatures() & GF_AGIMOUSE || true) { _game.vars[28] = _mouse.x / 2; _game.vars[29] = _mouse.y; } if (key == KEY_PRIORITY) { _sprites->eraseBoth(); _debug.priority = !_debug.priority; _picture->showPic(); _sprites->blitBoth(); _sprites->commitBoth(); key = 0; } if (key == KEY_STATUSLN) { _debug.statusline = !_debug.statusline; writeStatus(); key = 0; } // Click-to-walk mouse interface if (_game.playerControl && v->flags & ADJ_EGO_XY) { int toX = v->parm1; int toY = v->parm2; // AGI Mouse games use ego's sprite's bottom left corner for mouse walking target. // Amiga games use ego's sprite's bottom center for mouse walking target. // TODO: Check what Atari ST AGI and Apple IIGS AGI use for mouse walking target. if (getPlatform() == Common::kPlatformAmiga) toX -= (v->xSize / 2); // Center ego's sprite horizontally // Adjust ego's sprite's mouse walking target position (These parameters are // controlled with the adj.ego.move.to.x.y-command). Note that these values rely // on the horizontal centering of the ego's sprite at least on the Amiga platform. toX += _game.adjMouseX; toY += _game.adjMouseY; v->direction = getDirection(v->xPos, v->yPos, toX, toY, v->stepSize); if (v->direction == 0) inDestination(v); } kascii = KEY_ASCII(key); if (kascii) setvar(vKey, kascii); process_key: switch (_game.inputMode) { case INPUT_NORMAL: if (!handleController(key)) { if (key == 0 || !_game.inputEnabled) break; handleKeys(key); // if ESC pressed, activate menu before // accept.input from the interpreter cycle // sets the input mode to normal again // (closes: #540856) if (key == KEY_ESCAPE) { key = 0; goto process_key; } // commented out to close Sarien bug #438872 //if (key) // _game.keypress = key; } break; case INPUT_GETSTRING: handleController(key); handleGetstring(key); setvar(vKey, 0); // clear ENTER key break; case INPUT_MENU: _menu->keyhandler(key); _gfx->doUpdate(); return false; case INPUT_NONE: handleController(key); if (key) _game.keypress = key; break; } _gfx->doUpdate(); if (_game.msgBoxTicks > 0) _game.msgBoxTicks--; return true; }
// We return the current key, or 0 if no key was pressed uint16 AgiEngine::processAGIEvents() { uint16 key; ScreenObjEntry *screenObjEgo = &_game.screenObjTable[SCREENOBJECTS_EGO_ENTRY]; wait(10); key = doPollKeyboard(); // In AGI Mouse emulation mode we must update the mouse-related // vars in every interpreter cycle. // // We run AGIMOUSE always as a side effect setVar(VM_VAR_MOUSE_X, _mouse.pos.x / 2); setVar(VM_VAR_MOUSE_Y, _mouse.pos.y); if (!cycleInnerLoopIsActive()) { // Click-to-walk mouse interface if (_game.playerControl && (screenObjEgo->flags & fAdjEgoXY)) { int toX = screenObjEgo->move_x; int toY = screenObjEgo->move_y; // AGI Mouse games use ego's sprite's bottom left corner for mouse walking target. // Amiga games use ego's sprite's bottom center for mouse walking target. // Atari ST and Apple II GS seem to use the bottom left if (getPlatform() == Common::kPlatformAmiga) toX -= (screenObjEgo->xSize / 2); // Center ego's sprite horizontally // Adjust ego's sprite's mouse walking target position (These parameters are // controlled with the adj.ego.move.to.x.y-command). Note that these values rely // on the horizontal centering of the ego's sprite at least on the Amiga platform. toX += _game.adjMouseX; toY += _game.adjMouseY; screenObjEgo->direction = getDirection(screenObjEgo->xPos, screenObjEgo->yPos, toX, toY, screenObjEgo->stepSize); if (screenObjEgo->direction == 0) inDestination(screenObjEgo); } } handleMouseClicks(key); if (!cycleInnerLoopIsActive()) { // no inner loop active at the moment, regular processing if (key) { if (!handleController(key)) { if (key) { // Only set VAR_KEY, when no controller/direction was detected setVar(VM_VAR_KEY, key & 0xFF); if (_text->promptIsEnabled()) { _text->promptKeyPress(key); } } } } if (_menu->delayedExecuteActive()) { _menu->execute(); } } else { // inner loop active // call specific workers switch (_game.cycleInnerLoopType) { case CYCLE_INNERLOOP_GETSTRING: // loop called from TextMgr::stringEdit() case CYCLE_INNERLOOP_GETNUMBER: if (key) { _text->stringKeyPress(key); } break; case CYCLE_INNERLOOP_INVENTORY: // loop called from InventoryMgr::show() if (key) { _inventory->keyPress(key); } break; case CYCLE_INNERLOOP_MENU_VIA_KEYBOARD: if (key) { _menu->keyPress(key); } break; case CYCLE_INNERLOOP_MENU_VIA_MOUSE: _menu->mouseEvent(key); break; case CYCLE_INNERLOOP_SYSTEMUI_SELECTSAVEDGAMESLOT: if (key) { _systemUI->savedGameSlot_KeyPress(key); } break; case CYCLE_INNERLOOP_SYSTEMUI_VERIFICATION: _systemUI->askForVerificationKeyPress(key); break; case CYCLE_INNERLOOP_MESSAGEBOX: if (key) { _text->messageBox_KeyPress(key); } break; default: break; } } _gfx->updateScreen(); return key; }