Initial commit
This commit is contained in:
433
engines/dgds/scene_op.cpp
Normal file
433
engines/dgds/scene_op.cpp
Normal file
@@ -0,0 +1,433 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "dgds/scene_op.h"
|
||||
#include "dgds/dgds.h"
|
||||
#include "dgds/debug_util.h"
|
||||
#include "dgds/globals.h"
|
||||
#include "dgds/inventory.h"
|
||||
#include "dgds/scene.h"
|
||||
#include "dgds/dragon_native.h"
|
||||
#include "dgds/hoc_intro.h"
|
||||
#include "dgds/minigames/dragon_arcade.h"
|
||||
#include "dgds/minigames/china_train.h"
|
||||
#include "dgds/minigames/china_tank.h"
|
||||
|
||||
namespace Dgds {
|
||||
|
||||
static Common::String _sceneOpCodeName(SceneOpCode code) {
|
||||
code = static_cast<SceneOpCode>(code & ~kSceneOpHasConditionalOpsFlag);
|
||||
switch (code) {
|
||||
case kSceneOpNone: return "none";
|
||||
case kSceneOpChangeScene: return "changeScene";
|
||||
case kSceneOpNoop: return "noop";
|
||||
case kSceneOpGlobal: return "global";
|
||||
case kSceneOpSegmentStateOps: return "sceneOpSegmentStateOps";
|
||||
case kSceneOpSetItemAttr: return "setItemAttr";
|
||||
case kSceneOpSetDragItem: return "setDragItem";
|
||||
case kSceneOpOpenInventory: return "openInventory";
|
||||
case kSceneOpShowDlg: return "showdlg";
|
||||
case kSceneOpShowInvButton: return "showInvButton";
|
||||
case kSceneOpHideInvButton: return "hideInvButton";
|
||||
case kSceneOpEnableTrigger: return "enabletrigger";
|
||||
case kSceneOpChangeSceneToStored: return "changeSceneToStored";
|
||||
case kSceneOpAddFlagToDragItem: return "addFlagToDragItem";
|
||||
case kSceneOpMoveItemsBetweenScenes: return "moveItemsBetweenScenes";
|
||||
case kSceneOpOpenInventoryZoom: return "openInventoryZoom";
|
||||
case kSceneOpShowClock: return "showClock";
|
||||
case kSceneOpHideClock: return "hideClock";
|
||||
case kSceneOpShowMouse: return "showMouse";
|
||||
case kSceneOpHideMouse: return "hideMouse";
|
||||
case kSceneOpLoadTalkDataAndSetFlags: return "loadTalkDataAndSetFlags";
|
||||
case kSceneOpClearVisibleTalkHeads: return "clearVisibleTalksHeads";
|
||||
case kSceneOpLoadTalkData: return "loadTalkData";
|
||||
case kSceneOpLoadDDSData: return "loadDDSData";
|
||||
case kSceneOpFreeDDSData: return "freeDDSData";
|
||||
case kSceneOpFreeTalkData: return "freeTalkData";
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (DgdsEngine::getInstance()->getGameId() == GID_DRAGON) {
|
||||
switch (code) {
|
||||
case kSceneOpPasscode: return "passcode";
|
||||
case kSceneOpMeanwhile: return "meanwhile";
|
||||
case kSceneOpOpenGameOverMenu: return "openGameOverMenu";
|
||||
case kSceneOpTiredDialog: return "openTiredDialog";
|
||||
case kSceneOpArcadeTick: return "sceneOpArcadeTick";
|
||||
case kSceneOpDrawDragonCountdown1: return "drawDragonCountdown1";
|
||||
case kSceneOpDrawDragonCountdown2: return "drawDragonCountdown2";
|
||||
case kSceneOpOpenPlaySkipIntroMenu: return "openPlaySkipIntroMovie";
|
||||
case kSceneOpOpenBetterSaveGameMenu: return "openBetterSaveGameMenu";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (DgdsEngine::getInstance()->getGameId() == GID_HOC) {
|
||||
switch (code) {
|
||||
case kSceneOpChinaTankInit: return "tankInit";
|
||||
case kSceneOpChinaTankEnd: return "tankEnd";
|
||||
case kSceneOpChinaTankTick: return "tankTick";
|
||||
case kSceneOpChinaScrollLeft: return "scrollLeft";
|
||||
case kSceneOpChinaScrollRight: return "scrollRight";
|
||||
case kSceneOpShellGameInit: return "shellGameInit";
|
||||
case kSceneOpShellGameEnd: return "shellGameEnd";
|
||||
case kSceneOpShellGameTick: return "shellGameTick";
|
||||
case kSceneOpChinaTrainInit: return "trainInit";
|
||||
case kSceneOpChinaTrainEnd: return "trainEnd";
|
||||
case kSceneOpChinaTrainTick: return "trainTick";
|
||||
case kSceneOpChinaOpenGameOverMenu: return "gameOverMenu";
|
||||
case kSceneOpChinaOpenSkipCreditsMenu: return "skipCreditsMenu";
|
||||
case kSceneOpChinaOnIntroInit: return "chinaOnIntroInit";
|
||||
case kSceneOpChinaOnIntroTick: return "chinaOnIntroTick";
|
||||
case kSceneOpChinaOnIntroEnd: return "chinaOnIntroEnd";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
} else if (DgdsEngine::getInstance()->getGameId() == GID_WILLY) {
|
||||
switch (code) {
|
||||
case kSceneOpOpenBeamishGameOverMenu: return "openGameOverMenu";
|
||||
case kSceneOpOpenBeamishOpenSkipCreditsMenu: return "skipCreditsMenu";
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return Common::String::format("sceneOp%d", (int)code);
|
||||
}
|
||||
|
||||
|
||||
Common::String SceneOp::dump(const Common::String &indent) const {
|
||||
Common::String argsStr;
|
||||
if (_args.empty()) {
|
||||
argsStr = "[]";
|
||||
} else {
|
||||
argsStr = "[";
|
||||
for (uint i : _args)
|
||||
argsStr += Common::String::format("%d ", i);
|
||||
argsStr.setChar(']', argsStr.size() - 1);
|
||||
}
|
||||
|
||||
const Common::String opName = _sceneOpCodeName(_opCode);
|
||||
const char *isConditional = (_opCode & kSceneOpHasConditionalOpsFlag) ? "(cond)": "";
|
||||
Common::String str = Common::String::format("%sSceneOp<op: %s%s args: %s", indent.c_str(), opName.c_str(), isConditional, argsStr.c_str());
|
||||
|
||||
str += DebugUtil::dumpStructList(indent, "conditionList", _conditionList);
|
||||
if (!_conditionList.empty()) {
|
||||
str += "\n";
|
||||
str += indent;
|
||||
}
|
||||
str += ">";
|
||||
return str;
|
||||
}
|
||||
|
||||
bool SceneOp::runOp() const {
|
||||
bool sceneChanged;
|
||||
|
||||
if (_opCode < 100) {
|
||||
sceneChanged = runCommonOp();
|
||||
} else {
|
||||
// Game-specific opcode
|
||||
switch (DgdsEngine::getInstance()->getGameId()) {
|
||||
case GID_DRAGON:
|
||||
sceneChanged = runDragonOp();
|
||||
break;
|
||||
case GID_HOC:
|
||||
sceneChanged = runChinaOp();
|
||||
break;
|
||||
case GID_WILLY:
|
||||
sceneChanged = runBeamishOp();
|
||||
break;
|
||||
default:
|
||||
error("TODO: Implement game-specific scene op for this game");
|
||||
}
|
||||
}
|
||||
return sceneChanged;
|
||||
}
|
||||
|
||||
bool SceneOp::runCommonOp() const {
|
||||
DgdsEngine *engine = DgdsEngine::getInstance();
|
||||
switch (_opCode) {
|
||||
case kSceneOpChangeScene:
|
||||
if (engine->changeScene(_args[0]))
|
||||
return true;
|
||||
break;
|
||||
case kSceneOpNoop:
|
||||
//
|
||||
// This is run when the "quit willy beamish help" dialog item is called.
|
||||
// There may be a nicer way to do this?
|
||||
//
|
||||
if (engine->getScene()->getNum() == 80 && engine->getGameId() == GID_WILLY) {
|
||||
int16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
|
||||
if (engine->changeScene(sceneNo))
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case kSceneOpGlobal:
|
||||
// The globals are held by the GDS scene
|
||||
engine->getGDSScene()->globalOps(_args);
|
||||
break;
|
||||
case kSceneOpSegmentStateOps:
|
||||
SDSScene::segmentStateOps(_args);
|
||||
break;
|
||||
case kSceneOpSetItemAttr:
|
||||
SDSScene::setItemAttrOp(_args);
|
||||
break;
|
||||
case kSceneOpSetDragItem:
|
||||
SDSScene::setDragItemOp(_args);
|
||||
break;
|
||||
case kSceneOpOpenInventory:
|
||||
engine->getInventory()->open();
|
||||
// This implicitly changes scene num
|
||||
break;
|
||||
case kSceneOpShowDlg:
|
||||
if (_args.size() == 1)
|
||||
engine->getScene()->showDialog(0, _args[0]);
|
||||
else if (_args.size() > 1)
|
||||
engine->getScene()->showDialog(_args[0], _args[1]);
|
||||
break;
|
||||
case kSceneOpShowInvButton:
|
||||
engine->getScene()->addInvButtonToHotAreaList();
|
||||
break;
|
||||
case kSceneOpHideInvButton:
|
||||
engine->getScene()->removeInvButtonFromHotAreaList();
|
||||
break;
|
||||
case kSceneOpEnableTrigger:
|
||||
if (_args.size() == 1)
|
||||
engine->getScene()->enableTrigger(0, _args[0]);
|
||||
else if (_args.size() > 1)
|
||||
engine->getScene()->enableTrigger(_args[1], _args[0]);
|
||||
break;
|
||||
case kSceneOpChangeSceneToStored: {
|
||||
int16 sceneNo = engine->getGameGlobals()->getGlobal(0x61);
|
||||
if (engine->changeScene(sceneNo))
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
case kSceneOpAddFlagToDragItem: {
|
||||
GameItem *item = engine->getScene()->getDragItem();
|
||||
if (item) {
|
||||
item->_flags |= kItemStateDragging;
|
||||
// TODO: Use hot x/y or just position?
|
||||
Common::Point lastMouse = engine->getLastMouseMinusHot();
|
||||
item->_rect.x = lastMouse.x;
|
||||
item->_rect.y = lastMouse.y;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSceneOpOpenInventoryZoom:
|
||||
engine->getInventory()->setShowZoomBox(true);
|
||||
engine->getInventory()->open();
|
||||
return true;
|
||||
case kSceneOpMoveItemsBetweenScenes: {
|
||||
int16 fromScene = engine->getGameGlobals()->getGlobal(0x55);
|
||||
int16 toScene = engine->getGameGlobals()->getGlobal(0x54);
|
||||
for (auto &item : engine->getGDSScene()->getGameItems()) {
|
||||
if (item._inSceneNum == fromScene)
|
||||
item._inSceneNum = toScene;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case kSceneOpShowClock:
|
||||
engine->setShowClock(true);
|
||||
break;
|
||||
case kSceneOpHideClock:
|
||||
engine->setShowClock(false);
|
||||
break;
|
||||
case kSceneOpShowMouse:
|
||||
CursorMan.showMouse(true);
|
||||
break;
|
||||
case kSceneOpHideMouse:
|
||||
CursorMan.showMouse(false);
|
||||
break;
|
||||
case kSceneOpLoadTalkDataAndSetFlags: // args: tdsnum to load, headnum
|
||||
engine->getScene()->loadTalkDataAndSetFlags(_args[0], _args[1]);
|
||||
break;
|
||||
case kSceneOpClearVisibleTalkHeads: // args: none
|
||||
engine->getScene()->clearVisibleTalkers();
|
||||
break;
|
||||
case kSceneOpLoadTalkData: // args: tds num to load
|
||||
engine->getScene()->loadTalkData(_args[0]);
|
||||
break;
|
||||
case kSceneOpLoadDDSData: // args: dds num to load
|
||||
if (_args[0])
|
||||
engine->getScene()->loadDialogData(_args[0]);
|
||||
break;
|
||||
case kSceneOpFreeDDSData: // args: dds num to free
|
||||
engine->getScene()->freeDialogData(_args[0]);
|
||||
break;
|
||||
case kSceneOpFreeTalkData: // args: tds num to free
|
||||
engine->getScene()->freeTalkData(_args[0]);
|
||||
break;
|
||||
|
||||
default:
|
||||
warning("TODO: Implement generic scene op %d", _opCode);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SceneOp::runDragonOp() const {
|
||||
DgdsEngine *engine = DgdsEngine::getInstance();
|
||||
switch (_opCode) {
|
||||
case kSceneOpPasscode:
|
||||
DragonNative::updatePasscodeGlobal();
|
||||
break;
|
||||
case kSceneOpMeanwhile:
|
||||
// TODO: Should we draw "meanwhile" like the original? it just gets overwritten with the image anyway.
|
||||
// Probably need to do something here to avoid flashing..
|
||||
//engine->_compositionBuffer.fillRect(Common::Rect(SCREEN_WIDTH, SCREEN_HEIGHT), 0);
|
||||
break;
|
||||
case kSceneOpOpenGameOverMenu:
|
||||
engine->setMenuToTrigger(kMenuGameOver);
|
||||
break;
|
||||
case kSceneOpTiredDialog:
|
||||
engine->getInventory()->close();
|
||||
engine->getScene()->addAndShowTiredDialog();
|
||||
break;
|
||||
case kSceneOpArcadeTick:
|
||||
// TODO: Add a configuration option to skip arcade sequence?
|
||||
// g_system->displayMessageOnOSD(_("Skipping DGDS arcade sequence"));
|
||||
// engine->getGameGlobals()->setGlobal(0x21, 6);
|
||||
engine->getDragonArcade()->arcadeTick();
|
||||
break;
|
||||
case kSceneOpDrawDragonCountdown1:
|
||||
DragonNative::drawCountdown(FontManager::k4x5Font, 141, 56);
|
||||
break;
|
||||
case kSceneOpDrawDragonCountdown2:
|
||||
DragonNative::drawCountdown(FontManager::k8x8Font, 250, 42);
|
||||
break;
|
||||
case kSceneOpOpenPlaySkipIntroMenu:
|
||||
engine->setMenuToTrigger(kMenuSkipPlayIntro);
|
||||
break;
|
||||
case kSceneOpOpenBetterSaveGameMenu:
|
||||
engine->setMenuToTrigger(kMenuSaveBeforeArcade);
|
||||
break;
|
||||
default:
|
||||
error("Unexpected Dragon scene opcode %d", _opCode);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SceneOp::runChinaOp() const {
|
||||
DgdsEngine *engine = DgdsEngine::getInstance();
|
||||
switch (_opCode) {
|
||||
case kSceneOpChinaTankInit:
|
||||
engine->getChinaTank()->init();
|
||||
break;
|
||||
case kSceneOpChinaTankEnd:
|
||||
engine->getChinaTank()->end();
|
||||
break;
|
||||
case kSceneOpChinaTankTick:
|
||||
engine->getChinaTank()->tick();
|
||||
break;
|
||||
case kSceneOpShellGameTick:
|
||||
engine->getShellGame()->shellGameTick();
|
||||
break;
|
||||
case kSceneOpShellGameEnd:
|
||||
engine->getShellGame()->shellGameEnd();
|
||||
break;
|
||||
case kSceneOpChinaTrainInit:
|
||||
engine->getChinaTrain()->init();
|
||||
break;
|
||||
case kSceneOpChinaTrainEnd:
|
||||
engine->getChinaTrain()->end();
|
||||
break;
|
||||
case kSceneOpChinaTrainTick:
|
||||
engine->getChinaTrain()->tick();
|
||||
break;
|
||||
case kSceneOpChinaOpenGameOverMenu:
|
||||
engine->setMenuToTrigger(kMenuGameOver);
|
||||
break;
|
||||
case kSceneOpChinaOpenSkipCreditsMenu:
|
||||
engine->setMenuToTrigger(kMenuSkipPlayIntro);
|
||||
break;
|
||||
case kSceneOpChinaOnIntroInit:
|
||||
engine->getHocIntro()->init();
|
||||
break;
|
||||
case kSceneOpChinaOnIntroTick:
|
||||
engine->getHocIntro()->tick();
|
||||
break;
|
||||
case kSceneOpChinaOnIntroEnd:
|
||||
engine->getHocIntro()->end();
|
||||
break;
|
||||
case kSceneOpChinaScrollIntro:
|
||||
case kSceneOpChinaScrollLeft:
|
||||
case kSceneOpChinaScrollRight:
|
||||
// These map to null functions.
|
||||
break;
|
||||
default:
|
||||
warning("TODO: Implement china-specific scene opcode: (%s)", dump("").c_str());
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SceneOp::runBeamishOp() const {
|
||||
DgdsEngine *engine = DgdsEngine::getInstance();
|
||||
|
||||
if (_opCode & kSceneOpHasConditionalOpsFlag) {
|
||||
uint16 opcode = _opCode & ~kSceneOpHasConditionalOpsFlag;
|
||||
for (const ConditionalSceneOp &cop : engine->getScene()->getConditionalOps()) {
|
||||
if (cop._opCode == opcode && SceneConditions::check(cop._conditionList)) {
|
||||
if (!Scene::runOps(cop._opList))
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (_opCode) {
|
||||
case kSceneOpOpenBeamishGameOverMenu:
|
||||
engine->setMenuToTrigger(kMenuGameOver);
|
||||
break;
|
||||
case kSceneOpOpenBeamishOpenSkipCreditsMenu:
|
||||
engine->setMenuToTrigger(kMenuSkipPlayIntro);
|
||||
break;
|
||||
default:
|
||||
warning("TODO: Implement beamish-specific scene opcode %d", _opCode);
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
Common::String ConditionalSceneOp::dump(const Common::String &indent) const {
|
||||
const Common::String opName = _sceneOpCodeName(static_cast<SceneOpCode>(_opCode));
|
||||
Common::String str = Common::String::format("%sConditionalSceneOp<op: %s", indent.c_str(), opName.c_str());
|
||||
|
||||
str += DebugUtil::dumpStructList(indent, "conditionList", _conditionList);
|
||||
if (!_conditionList.empty()) {
|
||||
str += indent;
|
||||
}
|
||||
str += DebugUtil::dumpStructList(indent, "opList", _opList);
|
||||
if (!_opList.empty()) {
|
||||
str += "\n";
|
||||
str += indent;
|
||||
}
|
||||
str += ">";
|
||||
return str;
|
||||
}
|
||||
|
||||
} // end namespace Dgds
|
||||
Reference in New Issue
Block a user