scummvm/engines/fullpipe/fullpipe.cpp
2017-12-08 23:57:48 +01:00

597 lines
14 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* 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.
*
*/
#include "base/plugins.h"
#include "common/archive.h"
#include "common/config-manager.h"
#include "common/debug-channels.h"
#include "audio/mixer.h"
#include "engines/util.h"
#include "graphics/surface.h"
#include "fullpipe/fullpipe.h"
#include "fullpipe/gameloader.h"
#include "fullpipe/messages.h"
#include "fullpipe/behavior.h"
#include "fullpipe/modal.h"
#include "fullpipe/input.h"
#include "fullpipe/motion.h"
#include "fullpipe/statics.h"
#include "fullpipe/scenes.h"
#include "fullpipe/floaters.h"
#include "fullpipe/console.h"
#include "fullpipe/constants.h"
namespace Fullpipe {
FullpipeEngine *g_fp = nullptr;
Vars *g_vars = nullptr;
FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc) :
Engine(syst),
_gameDescription(gameDesc),
_console(this),
_rnd("fullpipe"),
_gameProject(nullptr),
_modalObject(nullptr),
_currSoundList1(),
_mapTable() {
DebugMan.addDebugChannel(kDebugPathfinding, "path", "Pathfinding");
DebugMan.addDebugChannel(kDebugDrawing, "drawing", "Drawing");
DebugMan.addDebugChannel(kDebugLoading, "loading", "Scene loading");
DebugMan.addDebugChannel(kDebugAnimation, "animation", "Animation");
DebugMan.addDebugChannel(kDebugBehavior, "behavior", "Behavior");
DebugMan.addDebugChannel(kDebugMemory, "memory", "Memory management");
DebugMan.addDebugChannel(kDebugEvents, "events", "Event handling");
DebugMan.addDebugChannel(kDebugInventory, "inventory", "Inventory");
DebugMan.addDebugChannel(kDebugSceneLogic, "scenelogic", "Scene Logic");
DebugMan.addDebugChannel(kDebugInteractions, "interactions", "Interactions");
DebugMan.addDebugChannel(kDebugXML, "xml", "XML");
// Setup mixer
if (!_mixer->isReady()) {
warning("Sound initialization failed.");
}
syncSoundSettings();
_sfxVolume = ConfMan.getInt("sfx_volume") * 39 - 10000;
_musicVolume = ConfMan.getInt("music_volume");
_gameProjectVersion = 0;
_pictureScale = 8;
_scrollSpeed = 0;
_currSoundListCount = 0;
_updateTicks = 0;
_lastInputTicks = 0;
_lastButtonUpTicks = 0;
_currArchive = 0;
_soundEnabled = true;
_flgSoundList = true;
_inputController = 0;
_inputDisabled = false;
_normalSpeed = true;
_currentCheat = -1;
_currentCheatPos = 0;
_liftEnterMQ = 0;
_liftExitMQ = 0;
_lift = 0;
_lastLiftButton = nullptr;
_liftX = 0;
_liftY = 0;
_gameContinue = true;
_needRestart = false;
_flgPlayIntro = true;
_gamePaused = false;
_inputArFlag = false;
_recordEvents = false;
_mainMenu_debugEnabled = false;
_flgGameIsRunning = true;
_isProcessingMessages = false;
_musicAllowed = -1;
_musicGameVar = 0;
_musicMinDelay = 0;
_musicMaxDelay = 0;
_musicLocal = 0;
_trackStartDelay = 0;
_stream2playing = false;
_numSceneTracks = 0;
_sceneTrackHasSequence = false;
_sceneTrackIsPlaying = false;
_aniMan = nullptr;
_aniMan2 = nullptr;
_currentScene = nullptr;
_loaderScene = nullptr;
_scene2 = nullptr;
_scene3 = nullptr;
_messageHandlers = nullptr;
_updateScreenCallback = nullptr;
_updateCursorCallback = nullptr;
_msgX = 0;
_msgY = 0;
_msgObjectId2 = 0;
_msgId = 0;
_mouseVirtX = 0;
_mouseVirtY = 0;
_currSelectedInventoryItemId = 0;
_cursorId = 0;
_keyState = Common::KEYCODE_INVALID;
_buttonState = 0;
_updateFlag = true;
_flgCanOpenMap = true;
_sceneWidth = 1;
_sceneHeight = 1;
_inventoryScene = nullptr;
_inventory = nullptr;
_minCursorId = 0xffff;
_maxCursorId = 0;
_objectAtCursor = 0;
_objectIdAtCursor = 0;
_arcadeOverlay = nullptr;
_arcadeOverlayHelper = nullptr;
_arcadeOverlayX = 0;
_arcadeOverlayY = 0;
_arcadeOverlayMidX = 0;
_arcadeOverlayMidY = 0;
_isSaveAllowed = true;
g_fp = this;
g_vars = new Vars;
}
FullpipeEngine::~FullpipeEngine() {
g_fp = nullptr;
delete g_vars;
g_vars = nullptr;
}
void FullpipeEngine::restartGame() {
_floaters->stopAll();
clearGlobalMessageQueueList();
clearMessages();
initObjectStates();
if (_scene2) {
_scene2->getAniMan();
_scene2 = nullptr;
}
if (_currentScene) {
_gameLoader->unloadScene(_currentScene->_sceneId);
_currentScene = nullptr;
}
_gameLoader->restoreDefPicAniInfos();
getGameLoaderInventory()->clear();
getGameLoaderInventory()->addItem(ANI_INV_MAP, 1);
getGameLoaderInventory()->rebuildItemRects();
initMap();
if (_flgPlayIntro) {
_gameLoader->loadScene(SC_INTRO1);
_gameLoader->gotoScene(SC_INTRO1, TrubaUp);
} else {
_gameLoader->loadScene(SC_1);
_gameLoader->gotoScene(SC_1, TrubaLeft);
}
}
bool FullpipeEngine::shouldQuit() {
return !_gameContinue || Engine::shouldQuit();
}
Common::Error FullpipeEngine::loadGameState(int slot) {
deleteModalObject();
if (_gameLoader->readSavegame(getSavegameFile(slot)))
return Common::kNoError;
else
return Common::kUnknownError;
}
Common::Error FullpipeEngine::saveGameState(int slot, const Common::String &description) {
if (_gameLoader->writeSavegame(_currentScene, getSavegameFile(slot), description))
return Common::kNoError;
else
return Common::kUnknownError;
}
Common::Error FullpipeEngine::run() {
const Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0);
// Initialize backend
initGraphics(800, 600, &format);
_backgroundSurface.create(800, 600, format);
_origFormat = Graphics::PixelFormat(2, 5, 6, 5, 0, 11, 5, 0, 0);
_globalMessageQueueList.reset(new GlobalMessageQueueList);
_behaviorManager.reset(new BehaviorManager);
_sceneRect.left = 0;
_sceneRect.top = 0;
_sceneRect.right = 799;
_sceneRect.bottom = 599;
_floaters.reset(new Floaters);
_aniHandler.reset(new AniHandler);
_globalPalette = &_defaultPalette;
_isSaveAllowed = false;
if (debugChannelSet(-1, kDebugXML))
loadGameObjH();
int scene = 0;
if (ConfMan.hasKey("boot_param"))
scene = convertScene(ConfMan.getInt("boot_param"));
if (ConfMan.hasKey("save_slot"))
scene = -1;
if (!loadGam("fullpipe.gam", scene))
return Common::kNoGameDataFoundError;
if (ConfMan.hasKey("save_slot")) {
loadGameState(ConfMan.getInt("save_slot"));
}
#if 0
loadAllScenes();
#endif
int time1 = g_fp->_system->getMillis();
// Center mouse
_system->warpMouse(400, 300);
for (;;) {
updateEvents();
if (shouldQuit()) {
break;
}
int time2 = g_fp->_system->getMillis();
// 30fps
if (time2 - time1 >= 33 || !_normalSpeed) {
time1 = time2;
updateScreen();
}
if (_needRestart) {
delete _modalObject;
freeGameLoader();
_currentScene = nullptr;
_updateTicks = 0;
_globalPalette = &_defaultPalette;
loadGam("fullpipe.gam");
_needRestart = false;
}
_system->delayMillis(5);
_system->updateScreen();
}
freeGameLoader();
cleanup();
_backgroundSurface.free();
return Common::kNoError;
}
void FullpipeEngine::updateEvents() {
Common::Event event;
Common::EventManager *eventMan = _system->getEventManager();
ExCommand *ex;
while (eventMan->pollEvent(event)) {
switch (event.type) {
case Common::EVENT_KEYDOWN:
_keyState = event.kbd.keycode;
switch (event.kbd.keycode) {
case Common::KEYCODE_SPACE:
if (_gamePaused) {
if (_modalObject) {
if (_modalObject->init(42)) {
_modalObject->update();
} else {
deleteModalObject();
}
} else {
_gameLoader->updateSystems(42);
}
return;
}
ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0);
ex->_param = 32;
ex->_excFlags |= 3;
ex->handle();
break;
case Common::KEYCODE_s:
if (_gamePaused) {
_gamePaused = 0;
_flgGameIsRunning = true;
return;
}
ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0);
ex->_param = event.kbd.keycode;
ex->_excFlags |= 3;
ex->handle();
break;
case Common::KEYCODE_q:
return;
break;
default:
if (event.kbd.keycode == Common::KEYCODE_d && event.kbd.hasFlags(Common::KBD_CTRL)) {
// Start the debugger
getDebugger()->attach();
getDebugger()->onFrame();
}
ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0);
ex->_param = event.kbd.keycode;
ex->_excFlags |= 3;
ex->handle();
break;
}
break;
case Common::EVENT_KEYUP:
if (!_inputArFlag) {
ex = new ExCommand(0, 17, 37, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
ex->handle();
}
_keyState = Common::KEYCODE_INVALID;
break;
case Common::EVENT_MOUSEMOVE:
if (_recordEvents) {
ex = new ExCommand(0, 17, 31, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
ex->handle();
}
_mouseScreenPos = event.mouse;
break;
case Common::EVENT_QUIT:
return;
case Common::EVENT_RBUTTONDOWN:
if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) {
ex = new ExCommand(0, 17, 107, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
_lastInputTicks = _updateTicks;
ex->handle();
}
_mouseScreenPos = event.mouse;
break;
case Common::EVENT_LBUTTONDOWN:
if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) {
ex = new ExCommand(0, 17, 29, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0);
ex->_sceneClickX = _sceneRect.left + ex->_x;
ex->_sceneClickY = _sceneRect.top + ex->_y;
ex->_param = getGameLoaderInventory()->getSelectedItemId();
ex->_excFlags |= 3;
_lastInputTicks = _updateTicks;
ex->handle();
}
_mouseScreenPos = event.mouse;
break;
case Common::EVENT_LBUTTONUP:
if (!_inputArFlag && (_updateTicks - _lastButtonUpTicks) >= 2) {
ex = new ExCommand(0, 17, 30, 0, 0, 0, 1, 0, 0, 0);
ex->_excFlags |= 3;
_lastButtonUpTicks = _updateTicks;
ex->handle();
}
_mouseScreenPos = event.mouse;
break;
default:
break;
}
}
// pollEvent() is implemented only for video player. So skip it.
//if (event.kbd.keycode == MSG_SC11_SHOWSWING && _modalObject) {
// _modalObject->pollEvent();
//}
}
void FullpipeEngine::freeGameLoader() {
setCursor(0);
_floaters->stopAll();
_gameLoader.reset();
_currentScene = 0;
_scene2 = 0;
_loaderScene = 0;
}
void FullpipeEngine::cleanup() {
//cleanRecorder();
clearMessageHandlers();
clearMessages();
_globalMessageQueueList->compact();
for (uint i = 0; i < _globalMessageQueueList->size(); i++)
delete (*_globalMessageQueueList)[i];
stopAllSoundStreams();
}
void FullpipeEngine::deleteModalObject() {
if (!_modalObject)
return;
_modalObject->saveload();
BaseModalObject *tmp = _modalObject->_parentObj;
delete _modalObject;
_modalObject = tmp;
}
void FullpipeEngine::updateScreen() {
debugC(4, kDebugDrawing, "FullpipeEngine::updateScreen()");
_mouseVirtX = _mouseScreenPos.x + _sceneRect.left;
_mouseVirtY = _mouseScreenPos.y + _sceneRect.top;
//if (inputArFlag)
// updateGame_inputArFlag();
if (_modalObject || (_flgGameIsRunning && (_gameLoader->updateSystems(42), _modalObject != 0))) {
if (_flgGameIsRunning) {
if (_modalObject->init(42)) {
_modalObject->update();
} else {
deleteModalObject();
}
}
} else if (_currentScene) {
_currentScene->draw();
if (_inventoryScene)
_inventory->draw();
if (_updateScreenCallback)
_updateScreenCallback();
//if (inputArFlag && _currentScene) {
// vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "DEMO", 4, 380, 580);
// vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "Alt+F4 - exit", 14, 695, 580);
//}
} else {
//vrtRectangle(*(_DWORD *)g_vrtHandle, 0, 0, 0, 800, 600);
}
_inputController->drawCursor(_mouseScreenPos.x, _mouseScreenPos.y);
++_updateTicks;
}
int FullpipeEngine::getObjectEnumState(const Common::String &name, const char *state) {
GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
if (!var) {
var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0);
}
var = var->getSubVarByName(name);
if (var) {
var = var->getSubVarByName("ENUMSTATES");
if (var)
return var->getSubVarAsInt(state);
}
return 0;
}
int FullpipeEngine::getObjectState(const Common::String &objname) {
GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
if (var)
return var->getSubVarAsInt(objname);
return 0;
}
void FullpipeEngine::setObjectState(const Common::String &name, int state) {
GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
if (!var) {
var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0);
}
var->setSubVarAsInt(name, state);
}
void FullpipeEngine::disableSaves(ExCommand *ex) {
if (_isSaveAllowed) {
_isSaveAllowed = false;
if (_globalMessageQueueList->size() && (*_globalMessageQueueList)[0] != 0) {
for (uint i = 0; i < _globalMessageQueueList->size(); i++) {
if ((*_globalMessageQueueList)[i]->_flags & 1)
if ((*_globalMessageQueueList)[i]->_id != ex->_parId && !(*_globalMessageQueueList)[i]->_isFinished)
return;
}
}
// Original was makeing a save on every room entering
if (_currentScene) {
_gameLoader->saveScenePicAniInfos(_currentScene->_sceneId);
// _gameLoader->writeSavegame(_currentScene, "savetmp.sav");
}
}
}
bool FullpipeEngine::isSaveAllowed() {
if (!g_fp->_isSaveAllowed)
return false;
bool allowed = true;
for (Common::Array<MessageQueue *>::iterator s = g_fp->_globalMessageQueueList->begin(); s != g_fp->_globalMessageQueueList->end(); ++s) {
if (!(*s)->_isFinished && ((*s)->getFlags() & 1))
allowed = false;
}
return allowed;
}
} // End of namespace Fullpipe