scummvm/engines/dragons/dragons.cpp

365 lines
9.5 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 "engines/util.h"
#include "graphics/thumbnail.h"
#include "graphics/surface.h"
#include "common/error.h"
#include "actor.h"
#include "actorresource.h"
#include "background.h"
#include "bigfile.h"
#include "dragonflg.h"
#include "dragonini.h"
#include "dragonobd.h"
#include "dragonrms.h"
#include "dragonvar.h"
#include "dragons.h"
#include "scene.h"
#include "screen.h"
#include "sequenceopcodes.h"
#include "scriptopcodes.h"
namespace Dragons {
#define DRAGONS_TICK_INTERVAL 17
static DragonsEngine *_engine = nullptr;
DragonsEngine *getEngine() {
return _engine;
}
DragonsEngine::DragonsEngine(OSystem *syst) : Engine(syst) {
_bigfileArchive = NULL;
_dragonRMS = NULL;
_backgroundResourceLoader = NULL;
_screen = NULL;
_nextUpdatetime = 0;
_flags = 0;
_unkFlags1 = 0;
_sequenceOpcodes = new SequenceOpcodes(this);
_scriptOpcodes = NULL;
_engine = this;
_cursorPosition = Common::Point();
}
DragonsEngine::~DragonsEngine() {
delete _sequenceOpcodes;
delete _scriptOpcodes;
}
void DragonsEngine::updateEvents() {
Common::Event event;
while (_eventMan->pollEvent(event)) {
// _input->processEvent(event);
switch (event.type) {
case Common::EVENT_QUIT:
quitGame();
break;
default:
break;
}
}
}
Common::Error DragonsEngine::run() {
_screen = new Screen();
_bigfileArchive = new BigfileArchive("bigfile.dat", Common::Language::EN_ANY);
_dragonFLG = new DragonFLG(_bigfileArchive);
_dragonOBD = new DragonOBD(_bigfileArchive);
_dragonRMS = new DragonRMS(_bigfileArchive, _dragonOBD);
_dragonVAR = new DragonVAR(_bigfileArchive);
_dragonINIResource = new DragonINIResource(_bigfileArchive);
ActorResourceLoader *actorResourceLoader = new ActorResourceLoader(_bigfileArchive);
_actorManager = new ActorManager(actorResourceLoader);
_scriptOpcodes = new ScriptOpcodes(this, _dragonFLG);
_scene = new Scene(this, _screen, _scriptOpcodes, _bigfileArchive, _actorManager, _dragonRMS, _dragonINIResource);
_flags = 0x1046;
Actor *cursor = _actorManager->loadActor(0, 0); //Load cursor
cursor->x_pos = _cursorPosition.x = 160;
cursor->y_pos = _cursorPosition.y = 100;
cursor->priorityLayer = 6;
cursor->flags = 0;
cursor->field_e = 0x100;
cursor->updateSequence(0);
cursor->flags |= (Dragons::ACTOR_FLAG_40 | Dragons::ACTOR_FLAG_80 | Dragons::ACTOR_FLAG_100 | Dragons::ACTOR_FLAG_200);
_dragonINIResource->getFlickerRecord()->actor = cursor; //TODO is this correct?
Actor *inventory = _actorManager->loadActor(1, 1); //Load inventory
inventory->x_pos = 2;
inventory->y_pos = 0;
inventory->priorityLayer = 6;
inventory->flags = 0;
inventory->field_e = 0x100;
inventory->updateSequence(0);
inventory->flags |= (Dragons::ACTOR_FLAG_40 | Dragons::ACTOR_FLAG_80 | Dragons::ACTOR_FLAG_100 | Dragons::ACTOR_FLAG_200);
_dragonINIResource->getFlickerRecord()->sceneId = 0x12; //TODO
_sceneId1 = 0x12;
_scene->loadScene(0x12, 0x1e);
_scene->draw();
_screen->updateScreen();
gameLoop();
delete _scene;
delete _actorManager;
delete _backgroundResourceLoader;
delete _dragonFLG;
delete _dragonRMS;
delete _dragonVAR;
delete _bigfileArchive;
delete _screen;
debug("Ok");
return Common::kNoError;
}
void DragonsEngine::gameLoop() {
_counter = 0;
bit_flags_8006fbd8 = 0;
while (!shouldQuit()) {
updateHandler();
updateEvents();
if (getCurrentSceneId() != 2) {
_sceneId1 = getCurrentSceneId();
}
_counter++;
DragonINI *flickerIni = _dragonINIResource->getFlickerRecord();
if (_counter >= 1200 && flickerIni->actor->resourceID == 0xe) { // 0xe == flicker.act
Actor *actor = flickerIni->actor;
actor->_sequenceID2 = 2;
flickerIni->field_20_actor_field_14 = 2;
actor->updateSequence(getINI(0xc2)->sceneId == 1 ? 0x30 : 2);
_counter = 0;
setFlags(Dragons::ENGINE_FLAG_80000000);
}
if (_flags & Dragons::ENGINE_FLAG_80000000) {
if (flickerIni->actor->flags & Dragons::ACTOR_FLAG_4) {
_counter = 0;
clearFlags(Dragons::ENGINE_FLAG_80000000);
}
}
if (bit_flags_8006fbd8 == 0) {
setFlags(Dragons::ENGINE_FLAG_8);
}
if (flickerIni->sceneId == getCurrentSceneId()) {
debug("get here");
}
_scene->draw();
_screen->updateScreen();
wait();
}
}
void DragonsEngine::updateHandler() {
updateActorSequences();
//TODO logic here
for (uint16 i = 0; i < 0x17; i++) {
Actor *actor = _actorManager->getActor(i);
if (actor->flags & Dragons::ACTOR_FLAG_40) {
if (!(actor->flags & Dragons::ACTOR_FLAG_100)) {
int16 priority = _scene->getPriorityAtPosition(Common::Point(actor->x_pos, actor->y_pos));
DragonINI *flicker = _dragonINIResource->getFlickerRecord();
if (flicker && _scene->contains(flicker) && flicker->actor->_actorID == i) {
if (priority < 8 || priority == 0x10) {
actor->priorityLayer = priority;
}
} else {
if (priority != -1) {
actor->priorityLayer = priority;
}
}
if (actor->priorityLayer >= 0x11) {
actor->priorityLayer = 0;
}
if (actor->priorityLayer >= 9) {
actor->priorityLayer -= 8;
}
}
if (actor->sequenceTimer != 0) {
actor->sequenceTimer--;
}
}
}
if (_flags & Dragons::ENGINE_FLAG_80) {
for (uint16 i = 0x17; i < DRAGONS_ENGINE_NUM_ACTORS; i++) {
Actor *actor = _actorManager->getActor(i);
if (actor->sequenceTimer != 0) {
actor->sequenceTimer--;
}
}
}
}
const char *DragonsEngine::getSavegameFilename(int num) {
static Common::String filename;
filename = getSavegameFilename(_targetName, num);
return filename.c_str();
}
Common::String DragonsEngine::getSavegameFilename(const Common::String &target, int num) {
assert(num >= 0 && num <= 999);
return Common::String::format("%s.%03d", target.c_str(), num);
}
#define DRAGONS_SAVEGAME_VERSION 0
kReadSaveHeaderError DragonsEngine::readSaveHeader(Common::SeekableReadStream *in, SaveHeader &header, bool skipThumbnail) {
header.version = in->readUint32LE();
if (header.version > DRAGONS_SAVEGAME_VERSION)
return kRSHEInvalidVersion;
byte descriptionLen = in->readByte();
header.description = "";
while (descriptionLen--) {
header.description += (char)in->readByte();
}
if (!Graphics::loadThumbnail(*in, header.thumbnail, skipThumbnail)) {
return kRSHEIoError;
}
header.flags = in->readUint32LE();
header.saveDate = in->readUint32LE();
header.saveTime = in->readUint32LE();
header.playTime = in->readUint32LE();
return ((in->eos() || in->err()) ? kRSHEIoError : kRSHENoError);
}
uint32 DragonsEngine::calulateTimeLeft() {
uint32 now;
now = _system->getMillis();
if ( _nextUpdatetime <= now ) {
_nextUpdatetime = now + DRAGONS_TICK_INTERVAL;
return(0);
}
uint32 delay = _nextUpdatetime - now;
_nextUpdatetime += DRAGONS_TICK_INTERVAL;
return(delay);
}
void DragonsEngine::wait() {
_system->delayMillis(calulateTimeLeft());
}
void DragonsEngine::updateActorSequences() {
if (!(_flags & Dragons::ENGINE_FLAG_4)) {
return;
}
//TODO ResetRCnt(0xf2000001);
int16 actorId = _flags & Dragons::ENGINE_FLAG_80 ? (int16)64 : (int16)23;
while (actorId > 0) {
actorId--;
Actor *actor = _actorManager->getActor((uint16)actorId);
if (actorId < 2 && _flags & Dragons::ENGINE_FLAG_40) {
continue;
}
if (actor->flags & Dragons::ACTOR_FLAG_40 &&
!(actor->flags & Dragons::ACTOR_FLAG_4) &&
!(actor->flags & Dragons::ACTOR_FLAG_400) &&
(actor->sequenceTimer == 0 || actor->flags & Dragons::ACTOR_FLAG_1)) {
debug("Actor[%d] execute sequenceOp", actorId);
if (actor->flags & Dragons::ACTOR_FLAG_1) {
actor->resetSequenceIP();
actor->flags &= 0xeff6; //TODO rewrite using ACTOR_FLAG_nnn
actor->field_7a = 0;
}
//TODO execute sequence Opcode here.
OpCall opCall;
opCall._result = 1;
while (opCall._result == 1) {
opCall._op = (byte) READ_LE_UINT16(actor->_seqCodeIp);
opCall._code = actor->_seqCodeIp + 2;
_sequenceOpcodes->execOpcode(actor, opCall);
actor->_seqCodeIp += opCall._deltaOfs;
}
}
}
}
void DragonsEngine::setFlags(uint32 flags) {
_flags |= flags;
}
void DragonsEngine::clearFlags(uint32 flags) {
_flags &= ~flags;
}
void DragonsEngine::setUnkFlags(uint32 flags) {
_unkFlags1 |= flags;
}
void DragonsEngine::clearUnkFlags(uint32 flags) {
_unkFlags1 &= ~flags;
}
byte *DragonsEngine::getBackgroundPalette() {
assert(_scene);
return _scene->getPalette();
}
bool DragonsEngine::isFlagSet(uint32 flag) {
return (bool)(_flags & flag);
}
DragonINI *DragonsEngine::getINI(uint32 index) {
return _dragonINIResource->getRecord(index);
}
uint16 DragonsEngine::getVar(uint16 offset) {
return _dragonVAR->getVar(offset);
}
uint16 DragonsEngine::getCurrentSceneId() {
return _scene->getSceneId();
}
void DragonsEngine::setVar(uint16 offset, uint16 value) {
return _dragonVAR->setVar(offset, value);
}
} // End of namespace Dragons