scummvm/engines/lure/game.cpp
Torbjörn Andersson 21b91adcdf Changed "it's" to "its" in a few comments.
svn-id: r22408
2006-05-11 08:04:41 +00:00

474 lines
12 KiB
C++

/* ScummVM - Scumm Interpreter
* Copyright (C) 2005-2006 The ScummVM project
*
* 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 "lure/game.h"
#include "lure/strings.h"
#include "lure/room.h"
#include "lure/system.h"
#include "lure/debug-input.h"
#include "lure/debug-methods.h"
#include "lure/scripts.h"
#include "lure/res_struct.h"
namespace Lure {
static Game *int_game = NULL;
Game &Game::getReference() {
return *int_game;
}
Game::Game() {
int_game = this;
_slowSpeedFlag = true;
_soundFlag = true;
}
void Game::nextFrame() {
Resources &res = Resources::getReference();
Room &room = Room::getReference();
HotspotList::iterator i;
room.checkCursor();
room.update();
// Call the tick method for each hotspot - this is somewaht complicated
// by the fact that a tick proc can unload both itself and/or others,
// so we first get a list of the Ids, and call the tick proc for each
// id in sequence if it's still active
uint16 *idList = new uint16[res.activeHotspots().size()];
int idSize = 0;
for (i = res.activeHotspots().begin(); i != res.activeHotspots().end(); ++i) {
Hotspot *hotspot = *i;
idList[idSize++] = hotspot->hotspotId();
}
for (int idCtr = 0; idCtr < idSize; ++idCtr) {
Hotspot *hotspot = res.getActiveHotspot(idList[idCtr]);
if (hotspot)
hotspot->tick();
}
delete[] idList;
Screen::getReference().update();
}
void Game::execute() {
OSystem &system = System::getReference();
Room &r = Room::getReference();
Resources &res = Resources::getReference();
Events &events = Events::getReference();
Mouse &mouse = Mouse::getReference();
Screen &screen = Screen::getReference();
//Menu &menu = Menu::getReference();
ValueTableData &fields = res.fieldList();
uint32 timerVal = system.getMillis();
screen.empty();
//_screen.resetPalette();
screen.setPaletteEmpty();
Script::execute(STARTUP_SCRIPT);
// Load the first room
r.setRoomNumber(1);
// Set the player direction
res.getActiveHotspot(PLAYER_ID)->setDirection(UP);
r.update();
mouse.setCursorNum(CURSOR_ARROW);
mouse.cursorOn();
while (!events.quitFlag) {
// If time for next frame, allow everything to update
if (system.getMillis() > timerVal + GAME_FRAME_DELAY) {
timerVal = system.getMillis();
nextFrame();
}
res.delayList().tick();
while (events.pollEvent()) {
if (events.type() == OSystem::EVENT_KEYDOWN) {
uint16 roomNum = r.roomNumber();
#ifdef LURE_DEBUG
if (events.event().kbd.keycode == 282) {
doDebugMenu();
continue;
}
#endif
switch (events.event().kbd.ascii) {
case 27:
events.quitFlag = true;
break;
#ifdef LURE_DEBUG
case '+':
while (++roomNum <= 51)
if (res.getRoom(roomNum) != NULL) break;
if (roomNum == 52) roomNum = 1;
r.leaveRoom();
r.setRoomNumber(roomNum);
break;
case '-':
if (roomNum == 1) roomNum = 55;
while (res.getRoom(--roomNum) == NULL) ;
r.leaveRoom();
r.setRoomNumber(roomNum);
break;
case '*':
res.getActiveHotspot(PLAYER_ID)->setRoomNumber(
r.roomNumber());
break;
#endif
default:
break;
}
}
if ((events.type() == OSystem::EVENT_LBUTTONDOWN) ||
(events.type() == OSystem::EVENT_RBUTTONDOWN))
handleClick();
}
uint16 destRoom;
destRoom = fields.getField(NEW_ROOM_NUMBER);
if (destRoom != 0) {
// Need to change the current room
bool remoteFlag = fields.getField(OLD_ROOM_NUMBER) != 0;
r.setRoomNumber(destRoom, remoteFlag);
fields.setField(NEW_ROOM_NUMBER, 0);
}
destRoom = fields.playerNewPos().roomNumber;
if (destRoom != 0) {
playerChangeRoom();
}
system.updateScreen();
system.delayMillis(10);
}
r.leaveRoom();
}
#ifdef LURE_DEBUG
#define NUM_DEBUG_ITEMS 4
const char *debugItems[NUM_DEBUG_ITEMS] =
{"Toggle Info", "Set Room", "Show Active HS", "Show Room HS"};
void Game::doDebugMenu() {
uint16 index = PopupMenu::Show(NUM_DEBUG_ITEMS, debugItems);
Room &r = Room::getReference();
Resources &res = Resources::getReference();
switch (index) {
case 0:
// Toggle co-ordinates
r.setShowInfo(!r.showInfo());
break;
case 1:
// Set room number:
uint32 roomNumber;
if (!input_integer("Enter room number:", roomNumber)) return;
if (res.getRoom(roomNumber))
r.setRoomNumber(roomNumber);
else
Dialog::show("The room does not exist");
break;
case 2:
// Show active hotspots
showActiveHotspots();
break;
case 3:
// Show hotspots in room
showRoomHotspots();
break;
default:
break;
}
}
#endif
void Game::handleMenuResponse(uint8 selection) {
switch (selection) {
case MENUITEM_CREDITS:
doShowCredits();
break;
case MENUITEM_RESTART_GAME:
case MENUITEM_SAVE_GAME:
case MENUITEM_RESTORE_GAME:
break;
case MENUITEM_QUIT:
doQuit();
break;
case MENUITEM_TEXT_SPEED:
doTextSpeed();
break;
case MENUITEM_SOUND:
doSound();
}
}
void Game::playerChangeRoom() {
Resources &res = Resources::getReference();
Room &room = Room::getReference();
ValueTableData &fields = res.fieldList();
uint16 roomNum = fields.playerNewPos().roomNumber;
fields.playerNewPos().roomNumber = 0;
Point &newPos = fields.playerNewPos().position;
Hotspot *player = res.getActiveHotspot(PLAYER_ID);
player->currentActions().clear();
player->setRoomNumber(roomNum);
//player->setPosition((newPos.x & 0xfff8) || 5, newPos.y & 0xfff8);
player->setPosition(newPos.x, newPos.y);
room.setRoomNumber(roomNum, false);
}
void Game::handleClick() {
Resources &res = Resources::getReference();
Room &room = Room::getReference();
ValueTableData &fields = res.fieldList();
Mouse &mouse = Mouse::getReference();
uint16 oldRoomNumber = fields.getField(OLD_ROOM_NUMBER);
if (room.checkInTalkDialog()) {
// Close the active talk dialog
room.setTalkDialog(0, 0);
} else if (oldRoomNumber != 0) {
// Viewing a room remotely - handle returning to prior room
if ((room.roomNumber() != 35) || (fields.getField(87) == 0)) {
// Reset player tick proc and signal to change back to the old room
res.getActiveHotspot(PLAYER_ID)->setTickProc(PLAYER_TICK_PROC_ID);
fields.setField(NEW_ROOM_NUMBER, oldRoomNumber);
fields.setField(OLD_ROOM_NUMBER, 0);
}
} else if ((room.cursorState() == CS_TALKING) ||
(res.getTalkState() != TALK_NONE)) {
// Currently talking, so let its tick proc handle it
} else if (mouse.y() < MENUBAR_Y_SIZE) {
uint8 response = Menu::getReference().execute();
if (response != MENUITEM_NONE)
handleMenuResponse(response);
} else if ((room.cursorState() == CS_SEQUENCE) ||
(room.cursorState() == CS_UNKNOWN)) {
// No action necessary
} else {
if (mouse.lButton())
handleLeftClick();
else
handleRightClickMenu();
}
}
void Game::handleRightClickMenu() {
Room &room = Room::getReference();
Resources &res = Resources::getReference();
ValueTableData &fields = res.fieldList();
Hotspot *player = res.getActiveHotspot(PLAYER_ID);
HotspotData *hotspot;
Action action;
uint32 actions;
uint16 itemId = 0xffff;
if (room.hotspotId() != 0) {
// Get hotspot actions
actions = room.hotspotActions();
} else {
// Standard actions - drink, examine, look, status
actions = 0x1184000;
}
// If no inventory items remove entries that require them
if (res.numInventoryItems() == 0)
actions &= 0xFEF3F9FD;
// If the player hasn't any money, remove any bribe entry
if (res.fieldList().numGroats() == 0)
actions &= 0xFF7FFFFF;
action = NONE;
hotspot = NULL;
bool breakFlag = false;
while (!breakFlag) {
action = PopupMenu::Show(actions);
switch (action) {
case LOOK:
case STATUS:
breakFlag = true;
break;
case GIVE:
case USE:
case EXAMINE:
case DRINK:
if (action != DRINK)
hotspot = res.getHotspot(room.hotspotId());
itemId = PopupMenu::ShowInventory();
breakFlag = (itemId != 0xffff);
if (breakFlag)
fields.setField(USE_HOTSPOT_ID, itemId);
break;
default:
hotspot = res.getHotspot(room.hotspotId());
breakFlag = true;
break;
}
}
if (action != NONE) {
player->stopWalking();
doAction(action, (hotspot != NULL) ? hotspot->hotspotId : 0, itemId);
}
}
void Game::handleLeftClick() {
Room &room = Room::getReference();
Mouse &mouse = Mouse::getReference();
Resources &res = Resources::getReference();
Hotspot *player = res.getActiveHotspot(PLAYER_ID);
room.setCursorState(CS_NONE);
player->stopWalking();
player->setDestHotspot(0);
player->setActionCtr(0);
if ((room.destRoomNumber() == 0) && (room.hotspotId() != 0)) {
// Handle look at hotspot
doAction(LOOK_AT, room.hotspotId(), 0xffff);
} else if (room.destRoomNumber() != 0) {
// Walk to another room
RoomExitCoordinateData &exitData =
res.coordinateList().getEntry(room.roomNumber()).getData(room.destRoomNumber());
player->walkTo((exitData.x & 0xfff8) | 5, (exitData.y & 0xfff8),
room.hotspotId() == 0 ? 0xffff : room.hotspotId());
} else {
// Walking within room
player->walkTo(mouse.x(), mouse.y(), 0);
}
}
void Game::doAction(Action action, uint16 hotspotId, uint16 usedId) {
Resources &res = Resources::getReference();
Room &room = Room::getReference();
ValueTableData &fields = res.fieldList();
Hotspot *player = res.getActiveHotspot(PLAYER_ID);
fields.setField(CHARACTER_HOTSPOT_ID, PLAYER_ID);
fields.setField(ACTIVE_HOTSPOT_ID, hotspotId);
fields.setField(USE_HOTSPOT_ID, usedId);
res.setCurrentAction(action);
room.setCursorState(CS_ACTION);
player->setCurrentAction(DISPATCH_ACTION, action, hotspotId, usedId);
}
void Game::doShowCredits() {
Events &events = Events::getReference();
Mouse &mouse = Mouse::getReference();
Screen &screen = Screen::getReference();
mouse.cursorOff();
Palette p(CREDITS_RESOURCE_ID - 1);
Surface *s = Surface::getScreen(CREDITS_RESOURCE_ID);
screen.setPalette(&p);
s->copyToScreen(0, 0);
delete s;
events.waitForPress();
screen.resetPalette();
screen.update();
mouse.cursorOn();
}
void Game::doQuit() {
Mouse &mouse = Mouse::getReference();
Events &events = Events::getReference();
Screen &screen = Screen::getReference();
mouse.cursorOff();
Surface *s = Surface::newDialog(190, "Are you sure (y/n)?");
s->centerOnScreen();
delete s;
char key = '\0';
do {
if (events.pollEvent()) {
if (events.event().type == OSystem::EVENT_KEYDOWN) {
key = events.event().kbd.ascii;
if ((key >= 'A') && (key <= 'Z')) key += 'a' - 'A';
}
}
} while (((uint8) key != 27) && (key != 'y') && (key != 'n'));
events.quitFlag = key == 'y';
if (!events.quitFlag) {
screen.update();
mouse.cursorOn();
}
}
void Game::doTextSpeed() {
Menu &menu = Menu::getReference();
_slowSpeedFlag = !_slowSpeedFlag;
const char *pSrc = _slowSpeedFlag ? "Slow" : "Fast";
char *pDest = menu.getMenu(2).getEntry(1);
memcpy(pDest, pSrc, 4);
}
void Game::doSound() {
Menu &menu = Menu::getReference();
_soundFlag = !_soundFlag;
const char *pSrc = _soundFlag ? "on " : "off";
char *pDest = menu.getMenu(2).getEntry(2) + 6;
memcpy(pDest, pSrc, 3);
}
} // end of namespace Lure