MUTATIONOFJB: Load object frames and implement special handling for map scenes.

This commit is contained in:
Ľubomír Remák 2018-04-02 14:03:40 +02:00 committed by Eugene Sandulenko
parent 2b94873694
commit 99d9055e20
11 changed files with 296 additions and 64 deletions

View File

@ -159,7 +159,7 @@ void AnimationDecoder::loadDiffFrame(EncryptedFile &file, uint32) {
const uint16 numLines = file.readUint16LE();
for (uint16 line = firstLine; line < firstLine + numLines; ++line) {
uint8 *imageData = reinterpret_cast<uint8 *>(_surface.getBasePtr(0, firstLine));
uint8 *imageData = reinterpret_cast<uint8 *>(_surface.getBasePtr(0, line));
uint8 runs = file.readByte();
while (runs--) {

View File

@ -65,6 +65,7 @@ Console::Console(MutationOfJBEngine *vm) : _vm(vm) {
registerCmd("showstartup", WRAP_METHOD(Console, cmd_showstartup));
registerCmd("changescene", WRAP_METHOD(Console, cmd_changescene));
registerCmd("dumpsceneinfo", WRAP_METHOD(Console, cmd_dumpsceneinfo));
registerCmd("dumpdoorinfo", WRAP_METHOD(Console, cmd_dumpdoorinfo));
registerCmd("dumpobjectinfo", WRAP_METHOD(Console, cmd_dumpobjectinfo));
registerCmd("dumpstaticinfo", WRAP_METHOD(Console, cmd_dumpstaticinfo));
}
@ -324,6 +325,38 @@ bool Console::cmd_dumpsceneinfo(int argc, const char **argv) {
return true;
}
bool Console::cmd_dumpdoorinfo(int argc, const char **argv) {
if (argc == 3) {
const uint8 sceneId = atoi(argv[1]);
const uint8 doorId = atoi(argv[2]);
Scene *const scene = _vm->getGame().getGameData().getScene(sceneId);
if (scene) {
Door *const door = scene->getDoor(doorId);
if (door) {
debugPrintf("Name: '%s'\n", convertToASCII(door->_name).c_str());
debugPrintf("DestSceneId: %u\n", (unsigned int) door->_destSceneId);
debugPrintf("DestX: %u\n", (unsigned int) door->_destX);
debugPrintf("DestY: %u\n", (unsigned int) door->_destY);
debugPrintf("X: %u\n", (unsigned int) door->_x);
debugPrintf("Y: %u\n", (unsigned int) door->_y);
debugPrintf("Width: %u\n", (unsigned int) door->_width);
debugPrintf("Height: %u\n", (unsigned int) door->_height);
debugPrintf("WalkToX: %u\n", (unsigned int) door->_walkToX);
debugPrintf("WalkToY: %u\n", (unsigned int) door->_walkToY);
debugPrintf("SP: %u\n", (unsigned int) door->_SP);
} else {
debugPrintf(_("Door %u not found.\n"), (unsigned int) doorId);
}
} else {
debugPrintf(_("Scene %u not found.\n"), (unsigned int) sceneId);
}
} else {
debugPrintf(_("dumpdoorinfo <sceneid> <doorid>\n"));
}
return true;
}
bool Console::cmd_dumpobjectinfo(int argc, const char **argv) {
if (argc == 3) {
const uint8 sceneId = atoi(argv[1]);

View File

@ -45,6 +45,7 @@ private:
bool cmd_showstartup(int argc, const char **argv);
bool cmd_changescene(int argc, const char **argv);
bool cmd_dumpsceneinfo(int argc, const char **argv);
bool cmd_dumpdoorinfo(int argc, const char **argv);
bool cmd_dumpobjectinfo(int argc, const char **argv);
bool cmd_dumpstaticinfo(int argc, const char **argv);

View File

@ -46,7 +46,7 @@ Game::Game(MutationOfJBEngine *vm)
globalScriptFile.close();
_localScript = nullptr;
_room = new Room(_vm->getScreen());
_room = new Room(this, _vm->getScreen());
changeScene(13, false); // Initial scene.
}
@ -55,6 +55,10 @@ GameData &Game::getGameData() {
return *_gameData;
}
Room &Game::getRoom() {
return *_room;
}
Script *Game::getGlobalScript() const {
return _globalScript;
}
@ -122,36 +126,6 @@ Script *Game::changeSceneDelayScript(uint8 sceneId, bool partB) {
return _delayedLocalScript;
}
Door *Game::findDoor(int16 x, int16 y) {
Scene *scene = _gameData->getCurrentScene();
if (!scene)
return nullptr;
for (int i = 0; i < MIN(ARRAYSIZE(scene->_doors), (int) scene->_noDoors); ++i) {
Door &door = scene->_doors[i];
if ((x >= door._x) && (x < door._x + door._width) && (y >= door._y) && (y < door._y + door._height)) {
return &door;
}
}
return nullptr;
}
Static *Game::findStatic(int16 x, int16 y) {
Scene *scene = _gameData->getCurrentScene();
if (!scene)
return nullptr;
for (int i = 0; i < MIN(ARRAYSIZE(scene->_statics), (int) scene->_noStatics); ++i) {
Static &stat = scene->_statics[i];
if ((x >= stat._x) && (x < stat._x + stat._width) && (y >= stat._y) && (y < stat._y + stat._height)) {
return &stat;
}
}
return nullptr;
}
static Command *findActionInfoCommand(const ActionInfos &infos, const Common::String &entity1Name, const Common::String &entity2Name = Common::String()) {
for (ActionInfos::const_iterator it = infos.begin(); it != infos.end(); ++it) {
if (it->_entity1Name == entity1Name && it->_entity2Name == entity2Name) {
@ -180,6 +154,10 @@ bool Game::startActionSection(ActionInfo::Action action, const Common::String &e
return false;
}
bool Game::isCurrentSceneMap() const {
return _gameData->_currentScene == 12;
}
void Game::update() {
Command::ExecuteResult res = _scriptExecCtx.runActiveCommand();
if (res == Command::Finished && _delayedLocalScript) {

View File

@ -39,22 +39,23 @@ class Script;
class Room;
class Door;
class Static;
class Bitmap;
class Game {
public:
Game(MutationOfJBEngine *vm);
GameData &getGameData();
Room &getRoom();
Script *getGlobalScript() const;
Script *getLocalScript() const;
void changeScene(uint8 sceneId, bool partB);
Script *changeSceneDelayScript(uint8 sceneId, bool partB);
Door *findDoor(int16 x, int16 y);
Static *findStatic(int16 x, int16 y);
bool startActionSection(ActionInfo::Action action, const Common::String &entity1Name, const Common::String &entity2Name = Common::String());
bool isCurrentSceneMap() const;
void update();
private:

View File

@ -151,7 +151,7 @@ Door *Scene::getDoor(uint8 doorId) {
}
Object *Scene::getObject(uint8 objectId, bool ignoreNo) {
if (objectId == 0 || objectId > (!ignoreNo ? MIN(_noObjects, (uint8) ARRAYSIZE(_objects)) : ARRAYSIZE(_objects))) {
if (objectId == 0 || objectId > getNoObjects(ignoreNo)) {
warning(_("Object %d does not exist"), objectId);
return nullptr;
}
@ -168,6 +168,60 @@ Static *Scene::getStatic(uint8 staticId, bool ignoreNo) {
return &_statics[staticId - 1];
}
uint8 Scene::getNoDoors(bool ignoreNo) const {
return (!ignoreNo ? MIN(_noDoors, (uint8) ARRAYSIZE(_doors)) : ARRAYSIZE(_doors));
}
uint8 Scene::getNoObjects(bool ignoreNo) const {
return (!ignoreNo ? MIN(_noObjects, (uint8) ARRAYSIZE(_objects)) : ARRAYSIZE(_objects));
}
uint8 Scene::getNoStatics(bool ignoreNo) const {
return (!ignoreNo ? MIN(_noStatics, (uint8) ARRAYSIZE(_statics)) : ARRAYSIZE(_statics));
}
Door *Scene::findDoor(int16 x, int16 y, int *index) {
for (int i = 0; i < getNoDoors(); ++i) {
Door &door = _doors[i];
if ((x >= door._x) && (x < door._x + door._width) && (y >= door._y) && (y < door._y + door._height)) {
if (index) {
*index = i + 1;
}
return &door;
}
}
return nullptr;
}
Static *Scene::findStatic(int16 x, int16 y, int *index) {
for (int i = 0; i < getNoStatics(); ++i) {
Static &stat = _statics[i];
if ((x >= stat._x) && (x < stat._x + stat._width) && (y >= stat._y) && (y < stat._y + stat._height)) {
if (index) {
*index = i + 1;
}
return &stat;
}
}
return nullptr;
}
Bitmap *Scene::findBitmap(int16 x, int16 y, int *index) {
for (int i = 0; i < ARRAYSIZE(_bitmaps); ++i) {
Bitmap &bitmap = _bitmaps[i];
if ((x >= bitmap._x1) && (x <= bitmap._x2) && (y >= bitmap._y1) && (y <= bitmap._y2)) {
if (index) {
*index = i + 1;
}
return &bitmap;
}
}
return nullptr;
}
GameData::GameData()
: _currentScene(0),

View File

@ -121,11 +121,18 @@ struct Bitmap {
struct Scene {
Door *getDoor(uint8 objectId);
Object *getObject(uint8 objectId, bool ignoreNo = false);
Static *getStatic(uint8 staticId, bool ignoreNo = false);
uint8 getNoDoors(bool ignoreNo = false) const;
uint8 getNoObjects(bool ignoreNo = false) const;
uint8 getNoStatics(bool ignoreNo = false) const;
Door *findDoor(int16 x, int16 y, int *index = nullptr);
Static *findStatic(int16 x, int16 y, int *index = nullptr);
Bitmap *findBitmap(int16 x, int16 y, int *index = nullptr);
uint8 _startup;
uint8 _unknown001;
uint8 _unknown002;

View File

@ -35,13 +35,16 @@
#include "mutationofjb/game.h"
#include "mutationofjb/gamedata.h"
#include "mutationofjb/debug.h"
#include "mutationofjb/room.h"
namespace MutationOfJB {
MutationOfJBEngine::MutationOfJBEngine(OSystem *syst)
: Engine(syst),
_console(nullptr),
_screen(nullptr) {
_screen(nullptr),
_currentAction(ActionInfo::Walk),
_mapObjectId(0) {
debug("MutationOfJBEngine::MutationOfJBEngine");
}
@ -69,6 +72,94 @@ Game &MutationOfJBEngine::getGame() {
return *_game;
}
void MutationOfJBEngine::handleNormalScene(const Common::Event &event) {
Scene *const scene = _game->getGameData().getCurrentScene();
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
{
const int16 x = event.mouse.x;
const int16 y = event.mouse.y;
if (Door *const door = scene->findDoor(x, y)) {
if (!_game->startActionSection(_currentAction, door->_name) && _currentAction == ActionInfo::Walk && door->_destSceneId != 0) {
_game->changeScene(door->_destSceneId, _game->getGameData()._partB);
}
} else if (Static *const stat = scene->findStatic(x, y)) {
if (stat->_active == 1) {
_game->startActionSection(_currentAction, stat->_name);
}
}
break;
}
default:
break;
}
}
/*
Special handling for map scenes.
Bitmaps define mouse clickable areas.
Statics are used to start actions.
Objects are used for showing labels.
*/
void MutationOfJBEngine::handleMapScene(const Common::Event &event) {
Scene *const scene = _game->getGameData().getCurrentScene();
switch (event.type) {
case Common::EVENT_LBUTTONDOWN:
{
const int16 x = event.mouse.x;
const int16 y = event.mouse.y;
int index = 0;
if (Bitmap *const bitmap = scene->findBitmap(x, y, &index)) {
Static *const stat = scene->getStatic(index);
if (stat && stat->_active == 1) {
_game->startActionSection(ActionInfo::Walk, stat->_name);
}
}
break;
}
case Common::EVENT_MOUSEMOVE:
{
const int16 x = event.mouse.x;
const int16 y = event.mouse.y;
int index = 0;
bool found = false;
if (Bitmap *const bitmap = scene->findBitmap(x, y, &index)) {
Static *const stat = scene->getStatic(index);
if (stat && stat->_active == 1) {
Object *const object = scene->getObject(index);
if (object) {
found = true;
if (index != _mapObjectId) {
if (_mapObjectId) {
_game->getRoom().drawObjectAnimation(_mapObjectId, 1);
_mapObjectId = 0;
}
_mapObjectId = index;
_game->getRoom().drawObjectAnimation(_mapObjectId, 0);
}
}
}
}
if (!found && _mapObjectId != 0) {
_game->getRoom().drawObjectAnimation(_mapObjectId, 1);
_mapObjectId = 0;
}
break;
}
default:
break;
}
}
Common::Error MutationOfJBEngine::run() {
debug("MutationOfJBEngine::run");
@ -77,11 +168,10 @@ Common::Error MutationOfJBEngine::run() {
_console = new Console(this);
_screen = new Graphics::Screen();
_game = new Game(this);
ActionInfo::Action currentAction = ActionInfo::Walk;
setupCursor();
while(!shouldQuit()) {
while (!shouldQuit()) {
Common::Event event;
while (_eventMan->pollEvent(event)) {
switch (event.type) {
@ -93,45 +183,40 @@ Common::Error MutationOfJBEngine::run() {
}
break;
}
case Common::EVENT_LBUTTONDOWN:
{
if (Door *const door = _game->findDoor(event.mouse.x, event.mouse.y)) {
if (!_game->startActionSection(currentAction, door->_name) && currentAction == ActionInfo::Walk && door->_destSceneId != 0) {
_game->changeScene(door->_destSceneId, _game->getGameData()._partB);
}
} else if (Static *const stat = _game->findStatic(event.mouse.x, event.mouse.y)) {
_game->startActionSection(currentAction, stat->_name);
}
break;
}
case Common::EVENT_KEYUP:
{
switch (event.kbd.ascii) {
case 'g':
currentAction = ActionInfo::Walk;
_currentAction = ActionInfo::Walk;
break;
case 'r':
currentAction = ActionInfo::Talk;
_currentAction = ActionInfo::Talk;
break;
case 's':
currentAction = ActionInfo::Look;
_currentAction = ActionInfo::Look;
break;
case 'b':
currentAction = ActionInfo::Use;
_currentAction = ActionInfo::Use;
break;
case 'n':
currentAction = ActionInfo::PickUp;
_currentAction = ActionInfo::PickUp;
break;
}
}
default:
break;
}
if (!_game->isCurrentSceneMap()) {
handleNormalScene(event);
} else {
handleMapScene(event);
}
}
_console->onFrame();
_game->update();
_system->delayMillis(40);
_system->delayMillis(10);
_screen->update();
}

View File

@ -24,9 +24,14 @@
#define MUTATIONOFJB_MUTATIONOFJB_H
#include "engines/engine.h"
#include "mutationofjb/script.h"
namespace Common {
class Event;
}
namespace Graphics {
class Screen;
class Screen;
}
namespace MutationOfJB {
@ -46,10 +51,14 @@ public:
private:
bool loadGameData(bool partB);
void setupCursor();
void handleNormalScene(const Common::Event &event);
void handleMapScene(const Common::Event &event);
Console *_console;
Graphics::Screen *_screen;
Game *_game;
ActionInfo::Action _currentAction;
uint8 _mapObjectId;
};

View File

@ -23,6 +23,8 @@
#include "mutationofjb/room.h"
#include "mutationofjb/animationdecoder.h"
#include "mutationofjb/encryptedfile.h"
#include "mutationofjb/game.h"
#include "mutationofjb/gamedata.h"
#include "mutationofjb/util.h"
#include "common/str.h"
#include "common/translation.h"
@ -44,20 +46,75 @@ void RoomAnimationDecoderCallback::onPaletteUpdated(byte palette[PALETTE_SIZE])
}
void RoomAnimationDecoderCallback::onFrame(int frameNo, Graphics::Surface &surface) {
if (frameNo != 0) {
return;
if (frameNo == 0) {
_room._screen->blitFrom(surface);
}
_room._screen->blitFrom(surface);
const int frameNo1 = frameNo + 1;
Scene *scene = _room._game->getGameData().getCurrentScene();
if (scene) {
const uint8 noObjects = scene->getNoObjects();
for (int i = 0; i < noObjects; ++i) {
Object &object = scene->_objects[i];
const uint16 startFrame = (object._WY << 8) + object._FS;
if (frameNo1 >= startFrame && frameNo1 < startFrame + object._NA) {
const int x = object._x;
const int y = object._y;
const int w = object._XL / 4 * 4;
const int h = object._YL / 4 * 4;
Common::Rect rect(x, y, x + w, y + h);
const Graphics::Surface sharedSurface = surface.getSubArea(rect);
Graphics::Surface outSurface;
outSurface.copyFrom(sharedSurface);
_room._surfaces[_room._objectsStart[i] + frameNo1 - startFrame] = outSurface;
}
}
}
}
Room::Room(Graphics::Screen *screen) : _screen(screen) {}
Room::Room(Game *game, Graphics::Screen *screen) : _game(game), _screen(screen) {}
bool Room::load(uint8 roomNumber, bool roomB) {
_objectsStart.clear();
Scene *const scene = _game->getGameData().getCurrentScene();
if (scene) {
const uint8 noObjects = scene->getNoObjects();
for (int i = 0; i < noObjects; ++i) {
uint8 firstIndex = 0;
if (i != 0) {
firstIndex = _objectsStart[i - 1] + scene->_objects[i - 1]._NA;
}
_objectsStart.push_back(firstIndex);
uint8 numAnims = scene->_objects[i]._NA;
while (numAnims--) {
_surfaces.push_back(Graphics::Surface());
}
}
}
const Common::String fileName = Common::String::format("room%d%s.dat", roomNumber, roomB ? "b" : "");
AnimationDecoder decoder(fileName);
RoomAnimationDecoderCallback callback(*this);
return decoder.decode(&callback);
}
void Room::drawObjectAnimation(uint8 objectId, int animOffset) {
Scene *const scene = _game->getGameData().getCurrentScene();
if (!scene) {
return;
}
Object *const object = scene->getObject(objectId);
if (!object) {
return;
}
const int startFrame = _objectsStart[objectId - 1];
const int animFrame = startFrame + animOffset;
_screen->blitFrom(_surfaces[animFrame], Common::Point(object->_x, object->_y));
}
}

View File

@ -24,23 +24,30 @@
#define MUTATIONOFJB_ROOM_H
#include "common/scummsys.h"
#include "common/array.h"
#include "graphics/surface.h"
namespace Graphics {
class Screen;
class Screen;
}
namespace MutationOfJB {
class EncryptedFile;
class Game;
class Room {
public:
friend class RoomAnimationDecoderCallback;
Room(Graphics::Screen *screen);
Room(Game *game, Graphics::Screen *screen);
bool load(uint8 roomNumber, bool roomB);
void drawObjectAnimation(uint8 objectId, int animOffset);
private:
Game *_game;
Graphics::Screen *_screen;
Common::Array<Graphics::Surface> _surfaces;
Common::Array<int> _objectsStart;
};
}