Logo Search packages:      
Sourcecode: scummvm version File versions  Download package

game.cpp

/* 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: https://svn.sourceforge.net/svnroot/scummvm/scummvm/tags/release-0-9-1/engines/lure/game.cpp $
 * $Id: game.cpp 22800 2006-05-31 13:36:01Z eriktorbjorn $
 *
 */

#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"
#include "lure/animseq.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();
      ValueTableData &fields = res.fieldList();
      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) {
                  fields.setField(CHARACTER_HOTSPOT_ID, hotspot->hotspotId());
                  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();

      setState(0);

      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) {
            while (!events.quitFlag && (_state == 0)) {
                  // 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);
            }

            // If Skorl catches player, show the catching animation
            if ((_state & GS_CAUGHT) != 0) {
                  Palette palette(SKORL_CATCH_PALETTE_ID);
                  AnimationSequence *anim = new AnimationSequence(screen, system, 
                        SKORL_CATCH_ANIM_ID, palette, false);
                  mouse.cursorOff();
                  anim->show();
                  mouse.cursorOn();
            }

            // If the Restart/Restore dialog is needed, show it
            if ((_state & GS_RESTORE_RESTART) != 0) {
                  // TODO: Restore/Restart dialog - for now, simply flag for exit
                  events.quitFlag = true;
            }
      }

      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_BUMPED)) { 
            // 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);

      // Set the action
      CharacterScheduleEntry *rec = res.playerSupportRecord();
      rec->setDetails(action, hotspotId, usedId);
      player->currentActions().addFront(DISPATCH_ACTION, rec, player->roomNumber());
}

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

Generated by  Doxygen 1.6.0   Back to index