scummvm/engines/agi/cycle.cpp

390 lines
8.4 KiB
C++
Raw Normal View History

2006-05-23 23:43:52 +00:00
/* ScummVM - Scumm Interpreter
* Copyright (C) 2006 The ScummVM project
*
* Copyright (C) 1999-2003 Sarien Team
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* $URL$
* $Id$
*
*/
#include "common/stdafx.h"
#include "agi/agi.h"
#include "agi/sprite.h"
#include "agi/graphics.h"
#include "agi/keyboard.h"
#include "agi/menu.h"
namespace Agi {
/**
* Set up new room.
* This function is called when ego enters a new room.
* @param n room number
*/
void AgiEngine::newRoom(int n) {
VtEntry *v;
2006-05-23 23:43:52 +00:00
int i;
debugC(4, kDebugLevelMain, "*** room %d ***", n);
_sound->stopSound();
2006-05-23 23:43:52 +00:00
i = 0;
for (v = _game.viewTable; v < &_game.viewTable[MAX_VIEWTABLE]; v++) {
2006-05-23 23:43:52 +00:00
v->entry = i++;
v->flags &= ~(ANIMATED | DRAWN);
v->flags |= UPDATE;
v->stepTime = 1;
v->stepTimeCount = 1;
v->cycleTime = 1;
v->cycleTimeCount = 1;
v->stepSize = 1;
2006-05-23 23:43:52 +00:00
}
agiUnloadResources();
2006-05-23 23:43:52 +00:00
_game.playerControl = true;
_game.block.active = false;
_game.horizon = 36;
_game.vars[vPrevRoom] = _game.vars[vCurRoom];
_game.vars[vCurRoom] = n;
_game.vars[vBorderTouchObj] = 0;
_game.vars[vBorderCode] = 0;
_game.vars[vEgoViewResource] = _game.viewTable[0].currentView;
2006-05-23 23:43:52 +00:00
agiLoadResource(rLOGIC, n);
2006-05-23 23:43:52 +00:00
/* Reposition ego in the new room */
switch (_game.vars[vBorderTouchEgo]) {
2006-05-23 23:43:52 +00:00
case 1:
_game.viewTable[0].yPos = _HEIGHT - 1;
2006-05-23 23:43:52 +00:00
break;
case 2:
_game.viewTable[0].xPos = 0;
2006-05-23 23:43:52 +00:00
break;
case 3:
_game.viewTable[0].yPos = HORIZON + 1;
2006-05-23 23:43:52 +00:00
break;
case 4:
_game.viewTable[0].xPos = _WIDTH - _game.viewTable[0].xSize;
2006-05-23 23:43:52 +00:00
break;
}
_game.vars[vBorderTouchEgo] = 0;
setflag(fNewRoomExec, true);
2006-05-23 23:43:52 +00:00
_game.exitAllLogics = true;
2006-05-23 23:43:52 +00:00
writeStatus();
writePrompt();
2006-05-23 23:43:52 +00:00
}
void AgiEngine::resetControllers() {
2006-05-23 23:43:52 +00:00
int i;
for (i = 0; i < MAX_DIRS; i++) {
_game.evKeyp[i].occured = false;
2006-05-23 23:43:52 +00:00
}
}
void AgiEngine::interpretCycle() {
int oldSound, oldScore;
2006-05-23 23:43:52 +00:00
if (_game.playerControl)
_game.vars[vEgoDir] = _game.viewTable[0].direction;
2006-05-23 23:43:52 +00:00
else
_game.viewTable[0].direction = _game.vars[vEgoDir];
checkAllMotions();
oldScore = _game.vars[vScore];
oldSound = getflag(fSoundOn);
_game.exitAllLogics = false;
while (runLogic(0) == 0 && !_game.quitProgNow) {
_game.vars[vWordNotFound] = 0;
_game.vars[vBorderTouchObj] = 0;
_game.vars[vBorderCode] = 0;
oldScore = _game.vars[vScore];
setflag(fEnteredCli, false);
_game.exitAllLogics = false;
resetControllers();
2006-05-23 23:43:52 +00:00
}
resetControllers();
2006-05-23 23:43:52 +00:00
_game.viewTable[0].direction = _game.vars[vEgoDir];
2006-05-23 23:43:52 +00:00
if (_game.vars[vScore] != oldScore || getflag(fSoundOn) != oldSound)
writeStatus();
2006-05-23 23:43:52 +00:00
_game.vars[vBorderTouchObj] = 0;
_game.vars[vBorderCode] = 0;
setflag(fNewRoomExec, false);
setflag(fRestartGame, false);
setflag(fRestoreJustRan, false);
2006-05-23 23:43:52 +00:00
if (_game.gfxMode) {
updateViewtable();
_gfx->doUpdate();
2006-05-23 23:43:52 +00:00
}
}
/**
* Update AGI interpreter timer.
*/
void AgiEngine::updateTimer() {
_clockCount++;
if (_clockCount <= TICK_SECONDS)
2006-05-23 23:43:52 +00:00
return;
_clockCount -= TICK_SECONDS;
2006-05-23 23:43:52 +00:00
if (!_game.clockEnabled)
2006-05-23 23:43:52 +00:00
return;
setvar(vSeconds, getvar(vSeconds) + 1);
if (getvar(vSeconds) < 60)
2006-05-23 23:43:52 +00:00
return;
setvar(vSeconds, 0);
setvar(vMinutes, getvar(vMinutes) + 1);
if (getvar(vMinutes) < 60)
2006-05-23 23:43:52 +00:00
return;
setvar(vMinutes, 0);
setvar(vHours, getvar(vHours) + 1);
if (getvar(vHours) < 24)
2006-05-23 23:43:52 +00:00
return;
setvar(vHours, 0);
setvar(vDays, getvar(vDays) + 1);
2006-05-23 23:43:52 +00:00
}
void AgiEngine::newInputMode(int i) {
_oldMode = _game.inputMode;
_game.inputMode = i;
2006-05-23 23:43:52 +00:00
}
void AgiEngine::oldInputMode() {
_game.inputMode = _oldMode;
2006-05-23 23:43:52 +00:00
}
/* If main_cycle returns false, don't process more events! */
int AgiEngine::mainCycle() {
2006-05-23 23:43:52 +00:00
unsigned int key, kascii;
VtEntry *v = &_game.viewTable[0];
2006-05-23 23:43:52 +00:00
_gfx->pollTimer(); /* msdos driver -> does nothing */
updateTimer();
2006-05-23 23:43:52 +00:00
if (_game.ver == 0) {
messageBox("Warning: game CRC not listed, assuming AGI version 2.917.");
_game.ver = -1;
2006-05-23 23:43:52 +00:00
}
key = doPollKeyboard();
2006-05-23 23:43:52 +00:00
/* In AGI Mouse emulation mode we must update the mouse-related
* vars in every interpreter cycle.
*/
if (getFeatures() & GF_AGIMOUSE) {
_game.vars[28] = g_mouse.x / 2;
_game.vars[29] = g_mouse.y;
2006-05-23 23:43:52 +00:00
}
if (key == KEY_PRIORITY) {
_sprites->eraseBoth();
_debug.priority = !_debug.priority;
_picture->showPic();
_sprites->blitBoth();
_sprites->commitBoth();
2006-05-23 23:43:52 +00:00
key = 0;
}
if (key == KEY_STATUSLN) {
_debug.statusline = !_debug.statusline;
writeStatus();
2006-05-23 23:43:52 +00:00
key = 0;
}
/* Click-to-walk mouse interface */
if (_game.playerControl && v->flags & ADJ_EGO_XY) {
v->direction = getDirection(v->xPos, v->yPos, v->parm1, v->parm2, v->stepSize);
2006-05-23 23:43:52 +00:00
if (v->direction == 0)
inDestination(v);
2006-05-23 23:43:52 +00:00
}
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;
2006-05-23 23:43:52 +00:00
}
2007-05-07 05:06:22 +00:00
/* commented out to close Sarien bug #438872
* if (key) game.keypress = key;
*/
2006-05-23 23:43:52 +00:00
}
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;
2006-05-23 23:43:52 +00:00
}
_gfx->doUpdate();
if (_game.msgBoxTicks > 0)
_game.msgBoxTicks--;
2006-05-23 23:43:52 +00:00
return true;
}
int AgiEngine::playGame() {
int ec = errOK;
2006-05-23 23:43:52 +00:00
debugC(2, kDebugLevelMain, "initializing...");
debugC(2, kDebugLevelMain, "game.ver = 0x%x", _game.ver);
2006-05-23 23:43:52 +00:00
_sound->stopSound();
_gfx->clearScreen(0);
2006-05-23 23:43:52 +00:00
_game.horizon = HORIZON;
_game.playerControl = false;
2006-05-23 23:43:52 +00:00
setflag(fLogicZeroFirsttime, true); /* not in 2.917 */
setflag(fNewRoomExec, true); /* needed for MUMG and SQ2! */
setflag(fSoundOn, true); /* enable sound */
setvar(vTimeDelay, 2); /* "normal" speed */
2006-05-23 23:43:52 +00:00
_game.gfxMode = true;
_game.quitProgNow = false;
_game.clockEnabled = true;
_game.lineUserInput = 22;
2006-05-23 23:43:52 +00:00
if (getFeatures() & GF_AGIMOUSE)
2006-05-23 23:43:52 +00:00
report("Using AGI Mouse 1.0 protocol\n");
if (getFeatures() & GF_AGIPAL)
debug(1, "Running AGIPAL game");
2006-05-23 23:43:52 +00:00
report("Running AGI script.\n");
setflag(fEnteredCli, false);
setflag(fSaidAcceptedInput, false);
_game.vars[vWordNotFound] = 0;
_game.vars[vKey] = 0;
2006-05-23 23:43:52 +00:00
debugC(2, kDebugLevelMain, "Entering main loop");
do {
if (!mainCycle())
2006-05-23 23:43:52 +00:00
continue;
if (getvar(vTimeDelay) == 0 || (1 + _clockCount) % getvar(vTimeDelay) == 0) {
if (!_game.hasPrompt && _game.inputMode == INPUT_NORMAL) {
writePrompt();
_game.hasPrompt = 1;
} else if (_game.hasPrompt && _game.inputMode == INPUT_NONE) {
writePrompt();
_game.hasPrompt = 0;
2006-05-23 23:43:52 +00:00
}
interpretCycle();
2006-05-23 23:43:52 +00:00
setflag(fEnteredCli, false);
setflag(fSaidAcceptedInput, false);
_game.vars[vWordNotFound] = 0;
_game.vars[vKey] = 0;
2006-05-23 23:43:52 +00:00
}
if (_game.quitProgNow == 0xff)
ec = errRestartGame;
2006-05-23 23:43:52 +00:00
} while (_game.quitProgNow == 0);
2006-05-23 23:43:52 +00:00
_sound->stopSound();
2006-05-23 23:43:52 +00:00
return ec;
}
int AgiEngine::runGame() {
int i, ec = errOK;
2006-05-23 23:43:52 +00:00
for (i = 0; i < MAX_DIRS; i++)
memset(&_game.evKeyp[i], 0, sizeof(struct AgiEvent));
2006-05-23 23:43:52 +00:00
/* Execute the game */
do {
debugC(2, kDebugLevelMain, "game loop");
debugC(2, kDebugLevelMain, "game.ver = 0x%x", _game.ver);
2006-05-23 23:43:52 +00:00
if (agiInit() != errOK)
2006-05-23 23:43:52 +00:00
break;
if (ec == errRestartGame)
setflag(fRestartGame, true);
setvar(vComputer, 0); /* IBM PC (4 = Atari ST) */
setvar(vSoundgen, 1); /* IBM PC SOUND */
setvar(vMonitor, 0x3); /* EGA monitor */
setvar(vMaxInputChars, 38);
_game.inputMode = INPUT_NONE;
_game.inputEnabled = 0;
_game.hasPrompt = 0;
_game.state = STATE_RUNNING;
ec = playGame();
_game.state = STATE_LOADED;
agiDeinit();
} while (ec == errRestartGame);
2006-05-23 23:43:52 +00:00
delete _menu;
_menu = NULL;
2006-05-23 23:43:52 +00:00
releaseImageStack();
2006-05-23 23:43:52 +00:00
return ec;
}
} // End of namespace Agi