mirror of
https://github.com/libretro/scummvm.git
synced 2024-12-15 22:28:10 +00:00
2878 lines
76 KiB
C++
2878 lines
76 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 "asylum/views/scene.h"
|
|
|
|
#include "asylum/resources/actor.h"
|
|
#include "asylum/resources/encounters.h"
|
|
#include "asylum/resources/object.h"
|
|
#include "asylum/resources/polygons.h"
|
|
#include "asylum/resources/script.h"
|
|
#include "asylum/resources/special.h"
|
|
#include "asylum/resources/worldstats.h"
|
|
|
|
#include "asylum/system/cursor.h"
|
|
#include "asylum/system/graphics.h"
|
|
#include "asylum/system/savegame.h"
|
|
#include "asylum/system/screen.h"
|
|
#include "asylum/system/speech.h"
|
|
#include "asylum/system/text.h"
|
|
|
|
#include "asylum/views/menu.h"
|
|
#include "asylum/views/scenetitle.h"
|
|
|
|
#include "asylum/asylum.h"
|
|
#include "asylum/respack.h"
|
|
#include "asylum/staticres.h"
|
|
|
|
namespace Asylum {
|
|
|
|
#define SCREEN_EDGES 40
|
|
#define SCROLL_STEP 10
|
|
|
|
int g_debugActors;
|
|
int g_debugObjects;
|
|
int g_debugPolygons;
|
|
int g_debugSceneRects;
|
|
int g_debugScrolling;
|
|
|
|
Scene::Scene(AsylumEngine *engine): _vm(engine),
|
|
_polygons(NULL), _ws(NULL) {
|
|
|
|
// Initialize data
|
|
_packId = kResourcePackInvalid;
|
|
|
|
_hitAreaChapter7Counter = 0;
|
|
_isCTRLPressed = false;
|
|
_chapter5RainFrameIndex = 0;
|
|
|
|
_musicVolume = 0;
|
|
|
|
g_debugActors = 0;
|
|
g_debugObjects = 0;
|
|
g_debugPolygons = 0;
|
|
g_debugSceneRects = 0;
|
|
g_debugScrolling = 0;
|
|
}
|
|
|
|
Scene::~Scene() {
|
|
// Unload the associated resources
|
|
getResource()->unload(_packId);
|
|
|
|
// Clear script queue
|
|
getScript()->reset();
|
|
|
|
delete _polygons;
|
|
delete _ws;
|
|
|
|
// Zero passed pointers
|
|
_vm = NULL;
|
|
}
|
|
|
|
void Scene::enter(ResourcePackId packId) {
|
|
_vm->setGameFlag(kGameFlagScriptProcessing);
|
|
|
|
getCursor()->hide();
|
|
|
|
getSharedData()->setPlayerIndex(0);
|
|
|
|
// Load the scene data
|
|
load(packId);
|
|
|
|
// Set wheel indices
|
|
_ws->setWheelObjects();
|
|
|
|
// Adjust object priority
|
|
if (_ws->objects.size() > 0) {
|
|
int32 priority = 4091;
|
|
|
|
for (uint32 i = 0; i < _ws->objects.size(); i++) {
|
|
Object *object = _ws->objects[i];
|
|
object->setPriority(priority);
|
|
object->flags &= ~kObjectFlagC000;
|
|
priority -= 4;
|
|
}
|
|
}
|
|
|
|
// Set the cursor to magnifying glass
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceMagnifyingGlass], 0, kCursorAnimationNone);
|
|
getCursor()->show();
|
|
|
|
// Clear the graphic queue
|
|
getScreen()->clearGraphicsInQueue();
|
|
|
|
_ws->sceneRectIdx = 0;
|
|
_ws->motionStatus = 1;
|
|
|
|
// Update current player bounding rectangle
|
|
Actor *player = getActor();
|
|
Common::Rect *boundingRect = player->getBoundingRect();
|
|
boundingRect->bottom = (int16)player->getPoint2()->y;
|
|
boundingRect->right = (int16)(player->getPoint2()->x * 2);
|
|
|
|
// Adjust scene bounding rect
|
|
_ws->boundingRect = Common::Rect(195, 115, 445 - boundingRect->right, 345 - boundingRect->bottom);
|
|
|
|
player->show(); // flag |= 1 (show actor)
|
|
player->enable();
|
|
|
|
// Update current player coordinates
|
|
player->getPoint1()->x -= player->getPoint2()->x;
|
|
player->getPoint1()->y -= player->getPoint2()->y;
|
|
|
|
// Update all other actors
|
|
if (_ws->actors.size() > 1) {
|
|
for (uint32 i = 1; i < _ws->actors.size(); i++) {
|
|
Actor *actor = _ws->actors[i];
|
|
|
|
actor->hide();
|
|
actor->setDirection(kDirectionNW);
|
|
actor->enable();
|
|
|
|
actor->getPoint1()->x -= actor->getPoint2()->x;
|
|
actor->getPoint1()->y -= actor->getPoint2()->y;
|
|
|
|
actor->getBoundingRect()->bottom = (int16)actor->getPoint2()->y;
|
|
actor->getBoundingRect()->right = (int16)(2 * actor->getPoint2()->x);
|
|
}
|
|
}
|
|
|
|
// Queue scene script
|
|
if (_ws->scriptIndex)
|
|
getScript()->queueScript(_ws->scriptIndex, 0);
|
|
|
|
// Clear the graphic queue (FIXME: not sure why we need to do this again)
|
|
getScreen()->clearGraphicsInQueue();
|
|
|
|
// Load transparency tables
|
|
getScreen()->setupTransTables(3, _ws->cellShadeMask1, _ws->cellShadeMask2, _ws->cellShadeMask3);
|
|
getScreen()->selectTransTable(1);
|
|
|
|
// Setup font
|
|
getText()->loadFont(_ws->font1);
|
|
|
|
// Preload graphics (we are just showing the loading screen
|
|
preload();
|
|
|
|
// Play scene intro dialog
|
|
playIntroSpeech();
|
|
|
|
// Set actor type
|
|
_ws->actorType = actorType[_ws->chapter];
|
|
|
|
// Play intro music
|
|
if (_ws->musicCurrentResourceIndex != kMusicStopped && _ws->chapter != kChapter1)
|
|
getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, _ws->musicCurrentResourceIndex));
|
|
else
|
|
getSound()->playMusic(kResourceNone, 0);
|
|
|
|
// Update global values
|
|
_vm->lastScreenUpdate = 1;
|
|
getSharedData()->setFlag(kFlagScene1, true);
|
|
|
|
player->setLastScreenUpdate(_vm->screenUpdateCount);
|
|
player->enable();
|
|
|
|
if (_ws->chapter == kChapter9) {
|
|
changePlayer(1);
|
|
_ws->nextPlayer = kActorInvalid;
|
|
}
|
|
}
|
|
|
|
void Scene::enterLoad() {
|
|
if (!_ws)
|
|
error("[Scene::enterLoad] WorldStats not initialized properly");
|
|
|
|
_vm->setGameFlag(kGameFlagScriptProcessing);
|
|
getScreen()->clearGraphicsInQueue();
|
|
|
|
// Setup scene bounding rect
|
|
_ws->boundingRect.left = 195;
|
|
_ws->boundingRect.top = 115;
|
|
_ws->boundingRect.right = 445 - getActor()->getBoundingRect()->right;
|
|
_ws->boundingRect.bottom = 345 - getActor()->getBoundingRect()->bottom;
|
|
|
|
// Setup transparency table
|
|
getScreen()->setupTransTables(3, _ws->cellShadeMask1, _ws->cellShadeMask2, _ws->cellShadeMask3);
|
|
getScreen()->selectTransTable(1);
|
|
getText()->loadFont(_ws->font1);
|
|
|
|
preload();
|
|
|
|
// Adjust object priority
|
|
if (_ws->objects.size() > 0) {
|
|
int32 priority = 4091;
|
|
|
|
for (uint32 i = 0; i < _ws->objects.size(); i++) {
|
|
Object *object = _ws->objects[i];
|
|
object->setPriority(priority);
|
|
object->flags &= ~kObjectFlagC000;
|
|
priority -= 4;
|
|
}
|
|
}
|
|
|
|
// Play intro music
|
|
if (_ws->musicCurrentResourceIndex != kMusicStopped)
|
|
getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, _ws->musicCurrentResourceIndex));
|
|
else
|
|
getSound()->playMusic(kResourceNone, 0);
|
|
|
|
// Palette fade
|
|
getScreen()->paletteFade(0, 75, 8);
|
|
getScreen()->clear();
|
|
|
|
getSharedData()->setFlag(kFlagScene1, true);
|
|
_vm->lastScreenUpdate = 1;
|
|
getActor()->setLastScreenUpdate(_vm->screenUpdateCount);
|
|
}
|
|
|
|
void Scene::load(ResourcePackId packId) {
|
|
// Setup resource manager
|
|
_packId = packId;
|
|
getResource()->setMusicPackId(packId);
|
|
|
|
char filename[10];
|
|
sprintf(filename, SCENE_FILE_MASK, _packId);
|
|
|
|
char sceneTag[6];
|
|
Common::File* fd = new Common::File;
|
|
|
|
if (!Common::File::exists(filename))
|
|
error("Scene file doesn't exist %s", filename);
|
|
|
|
fd->open(filename);
|
|
|
|
if (!fd->isOpen())
|
|
error("Failed to load scene file %s", filename);
|
|
|
|
fd->read(sceneTag, 6);
|
|
|
|
if (Common::String(sceneTag, 6) != "DFISCN")
|
|
error("The file isn't recognized as scene %s", filename);
|
|
|
|
_ws = new WorldStats(_vm);
|
|
_ws->load(fd);
|
|
|
|
_polygons = new Polygons(fd);
|
|
|
|
ScriptManager *script = getScript();
|
|
script->resetAll();
|
|
script->load(fd);
|
|
|
|
fd->close();
|
|
delete fd;
|
|
|
|
getSharedData()->resetAmbientFlags();
|
|
_ws->field_120 = -1;
|
|
|
|
int32 tick = _vm->getTick();
|
|
for (uint32 a = 0; a < _ws->actors.size(); a++)
|
|
_ws->actors[a]->setLastScreenUpdate(tick);
|
|
|
|
getCursor()->show();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Event handling
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool Scene::handleEvent(const AsylumEvent &evt) {
|
|
switch ((int32)evt.type) {
|
|
default:
|
|
break;
|
|
|
|
case EVENT_ASYLUM_INIT:
|
|
return init();
|
|
|
|
case EVENT_ASYLUM_ACTIVATE:
|
|
case Common::EVENT_RBUTTONUP:
|
|
activate();
|
|
break;
|
|
|
|
case EVENT_ASYLUM_UPDATE:
|
|
return update();
|
|
|
|
case Common::EVENT_KEYDOWN:
|
|
if (evt.kbd.flags & Common::KBD_CTRL)
|
|
_isCTRLPressed = true;
|
|
|
|
return key(evt);
|
|
|
|
case Common::EVENT_KEYUP:
|
|
if (!(evt.kbd.flags & Common::KBD_CTRL))
|
|
_isCTRLPressed = false;
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
case Common::EVENT_MBUTTONDOWN:
|
|
return clickDown(evt);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Scene::activate() {
|
|
Actor *player = getActor();
|
|
|
|
if (player->getStatus() == kActorStatusWalking)
|
|
player->updateStatus(kActorStatusEnabled);
|
|
|
|
if (player->getStatus() == kActorStatus12)
|
|
player->updateStatus(kActorStatus14);
|
|
}
|
|
|
|
bool Scene::init() {
|
|
if (!_ws)
|
|
error("[Scene::init] WorldStats not initialized properly");
|
|
|
|
if (getSharedData()->getFlag((kFlag3))) { // this flag is set during an encounter
|
|
getSharedData()->setFlag(kFlag3, false);
|
|
|
|
// The original test for flag 1001 but doesn't use the result
|
|
return true;
|
|
}
|
|
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceScrollUp], 0, kCursorAnimationNone);
|
|
_ws->coordinates[0] = -1;
|
|
getScreen()->clear();
|
|
getText()->loadFont(_ws->font1);
|
|
|
|
ResourceId paletteResource = _ws->actions[getActor()->getActionIndex3()]->paletteResourceId;
|
|
if (!paletteResource)
|
|
paletteResource = _ws->currentPaletteId;
|
|
|
|
getScreen()->setPalette(paletteResource);
|
|
getScreen()->setGammaLevel(paletteResource);
|
|
getScreen()->loadPalette();
|
|
getScreen()->setupTransTables(3, _ws->cellShadeMask1, _ws->cellShadeMask2, _ws->cellShadeMask3);
|
|
getScreen()->selectTransTable(1);
|
|
|
|
getCursor()->show();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Scene::update() {
|
|
if (getEncounter()->shouldEnablePlayer()) {
|
|
getEncounter()->setShouldEnablePlayer(false);
|
|
|
|
// Enable player
|
|
getActor()->updateStatus(kActorStatusEnabled);
|
|
}
|
|
|
|
uint32 ticks = _vm->getTick();
|
|
|
|
if (!getSharedData()->getFlag(kFlagRedraw)) {
|
|
if (updateScreen())
|
|
return true;
|
|
|
|
getSharedData()->setFlag(kFlagRedraw, true);
|
|
}
|
|
|
|
if (ticks > getSharedData()->getNextScreenUpdate()) {
|
|
if (getSharedData()->getFlag(kFlagRedraw)) {
|
|
if (getSharedData()->getMatteBarHeight() <= 0)
|
|
getScreen()->copyBackBufferToScreen();
|
|
else
|
|
getEncounter()->drawScreen();
|
|
|
|
// Original also sets an unused value to 0
|
|
getSharedData()->setEventUpdate(getSharedData()->getEventUpdate() ^ 1);
|
|
|
|
getSharedData()->setFlag(kFlagRedraw, false);
|
|
getSharedData()->setNextScreenUpdate(ticks + 55);
|
|
++_vm->screenUpdateCount;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Scene::key(const AsylumEvent &evt) {
|
|
if (!_ws)
|
|
error("[Scene::key] WorldStats not initialized properly");
|
|
|
|
// TODO add support for debug commands
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Check for keyboard shortcuts
|
|
if (evt.kbd.ascii == Config.keyShowVersion) {
|
|
// TODO show version!
|
|
|
|
return true;
|
|
}
|
|
|
|
if (evt.kbd.ascii == Config.keyQuickLoad) {
|
|
getSaveLoad()->quickLoad();
|
|
|
|
return true;
|
|
}
|
|
|
|
if (evt.kbd.ascii == Config.keyQuickSave) {
|
|
getSaveLoad()->quickSave();
|
|
|
|
return true;
|
|
}
|
|
|
|
if (evt.kbd.ascii == Config.keySwitchToSara) {
|
|
if (getCursor()->isHidden() || _ws->chapter != kChapter9)
|
|
return true;
|
|
|
|
getScript()->queueScript(_ws->actions[_ws->getActionAreaIndexById(2206)]->scriptIndex, getSharedData()->getPlayerIndex());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (evt.kbd.ascii == Config.keySwitchToGrimwall) {
|
|
if (getCursor()->isHidden() || _ws->chapter != kChapter9)
|
|
return true;
|
|
|
|
getScript()->queueScript(_ws->actions[_ws->getActionAreaIndexById(2207)]->scriptIndex, getSharedData()->getPlayerIndex());
|
|
|
|
return true;
|
|
}
|
|
|
|
if (evt.kbd.ascii == Config.keySwitchToOlmec) {
|
|
if (getCursor()->isHidden() || _ws->chapter != kChapter9)
|
|
return true;
|
|
|
|
getScript()->queueScript(_ws->actions[_ws->getActionAreaIndexById(2208)]->scriptIndex, getSharedData()->getPlayerIndex());
|
|
|
|
return true;
|
|
}
|
|
|
|
switch (evt.kbd.keycode) {
|
|
default:
|
|
break;
|
|
|
|
case Common::KEYCODE_BACKSPACE:
|
|
// TODO add support for debug commands
|
|
warning("[Scene::key] debug command handling not implemented!");
|
|
break;
|
|
|
|
case Common::KEYCODE_RETURN:
|
|
// TODO add support for debug commands
|
|
warning("[Scene::key] debug command handling not implemented!");
|
|
break;
|
|
|
|
case Common::KEYCODE_ESCAPE:
|
|
// TODO add support for debug commands
|
|
|
|
if (getSpeech()->getSoundResourceId()) {
|
|
getScene()->stopSpeech();
|
|
} else {
|
|
if (getCursor()->isHidden())
|
|
break;
|
|
|
|
_vm->switchEventHandler(_vm->menu());
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_LEFTBRACKET:
|
|
if (evt.kbd.ascii != 123)
|
|
break;
|
|
// Fallback to next case (we got a left brace)
|
|
|
|
case Common::KEYCODE_p:
|
|
case Common::KEYCODE_q:
|
|
case Common::KEYCODE_r:
|
|
case Common::KEYCODE_s:
|
|
case Common::KEYCODE_t:
|
|
case Common::KEYCODE_u:
|
|
case Common::KEYCODE_v:
|
|
case Common::KEYCODE_w:
|
|
case Common::KEYCODE_x:
|
|
case Common::KEYCODE_y:
|
|
case Common::KEYCODE_z:
|
|
if (speak(evt.kbd.keycode)) {
|
|
_vm->lastScreenUpdate = _vm->screenUpdateCount;
|
|
getActor()->setLastScreenUpdate(_vm->screenUpdateCount);
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_TAB:
|
|
getScreen()->takeScreenshot();
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Scene::clickDown(const AsylumEvent &evt) {
|
|
_vm->lastScreenUpdate = 0;
|
|
|
|
if (getSharedData()->getFlag(kFlag2)) {
|
|
stopSpeech();
|
|
|
|
return true;
|
|
}
|
|
|
|
Actor *player = getActor();
|
|
switch (evt.type) {
|
|
default:
|
|
break;
|
|
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
if (getSpeech()->getSoundResourceId())
|
|
stopSpeech();
|
|
|
|
if (player->getStatus() == kActorStatus6 || player->getStatus() == kActorStatus10) {
|
|
player->updateStatus(kActorStatusEnabled);
|
|
getSound()->playSound(MAKE_RESOURCE(kResourcePackSound, 5));
|
|
} else if (player->getStatus() != kActorStatusDisabled) {
|
|
player->updateStatus(kActorStatusWalking);
|
|
}
|
|
break;
|
|
|
|
case Common::EVENT_MBUTTONDOWN:
|
|
if (player->getStatus() != kActorStatusDisabled) {
|
|
if (player->getStatus() == kActorStatus6 || player->getStatus() == kActorStatus10)
|
|
player->updateStatus(kActorStatusEnabled);
|
|
else
|
|
player->updateStatus(kActorStatus6);
|
|
}
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
if (getCursor()->getState() & kCursorStateRight)
|
|
break;
|
|
|
|
if (getSpeech()->getSoundResourceId())
|
|
stopSpeech();
|
|
|
|
if (player->getStatus() == kActorStatusDisabled)
|
|
break;
|
|
|
|
if (player->getField638()) {
|
|
if (hitTestPlayer()) {
|
|
player->setField638(0);
|
|
return true;
|
|
}
|
|
|
|
HitType type = kHitNone;
|
|
int32 res = hitTestScene(type);
|
|
|
|
if (res == -1)
|
|
getSpeech()->playIndexed(2);
|
|
else
|
|
handleHit(res, type);
|
|
|
|
return true;
|
|
}
|
|
|
|
if (!hitTestPlayer() || player->getStatus() >= kActorStatus11 || !player->getReactionValue(0)) {
|
|
if (player->getStatus() == kActorStatus6 || player->getStatus() == kActorStatus10) {
|
|
playerReaction();
|
|
} else {
|
|
HitType type = kHitNone;
|
|
int32 res = hitTest(type);
|
|
if (res != -1)
|
|
handleHit(res, type);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
if (player->getStatus() == kActorStatus6 || player->getStatus() == kActorStatus10) {
|
|
getSound()->playSound(MAKE_RESOURCE(kResourcePackSound, 5));
|
|
player->updateStatus(kActorStatusEnabled);
|
|
} else {
|
|
getSound()->playSound(MAKE_RESOURCE(kResourcePackSound, 2));
|
|
player->updateStatus(kActorStatus6);
|
|
}
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Scene update
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool Scene::updateScreen() {
|
|
// Original has a frame counter (for showing fps)
|
|
|
|
if (updateScene())
|
|
return true;
|
|
|
|
if (Config.performance <= 4) {
|
|
// TODO when Config.performance <= 4, we need to skip drawing frames to screen
|
|
|
|
if (drawScene())
|
|
return true;
|
|
|
|
} else {
|
|
if (drawScene())
|
|
return true;
|
|
}
|
|
|
|
getActor()->drawNumber();
|
|
|
|
// Original handle all debug commands here (we do it as part of each update command)
|
|
|
|
if (getSharedData()->getFlag(kFlagScene1)) {
|
|
getScreen()->clear();
|
|
|
|
getScreen()->stopPaletteFade(0, 0, 0);
|
|
updateScene();
|
|
drawScene();
|
|
getScreen()->copyBackBufferToScreen();
|
|
|
|
getScreen()->stopPaletteFadeAndSet(getWorld()->currentPaletteId, 100, 10);
|
|
drawScene();
|
|
getScreen()->copyBackBufferToScreen();
|
|
|
|
getSharedData()->setFlag(kFlagScene1, false);
|
|
}
|
|
|
|
if (getSpeech()->getSoundResourceId() != 0) {
|
|
if (getSound()->isPlaying(getSpeech()->getSoundResourceId())) {
|
|
getSpeech()->prepareSpeech();
|
|
} else {
|
|
getSpeech()->resetResourceIds();
|
|
_vm->clearGameFlag(kGameFlag219);
|
|
}
|
|
}
|
|
|
|
if (getWorld()->chapter == kChapter5) {
|
|
if (_vm->isGameFlagSet(kGameFlag249))
|
|
drawRain();
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
bool Scene::updateScene() {
|
|
#ifdef DEBUG_SCENE_TIMES
|
|
#define MESURE_TICKS(func) { \
|
|
int32 startTick =_vm->getTick(); \
|
|
func(); \
|
|
debugC(kDebugLevelScene, "[Scene] " #func " - Time: %d", _vm->getTick() - startTick); \
|
|
}
|
|
#else
|
|
#define MESURE_TICKS(func) func();
|
|
#endif
|
|
|
|
// Update each part of the scene
|
|
if (getSharedData()->getMatteBarHeight() != 170 || getSharedData()->getMattePlaySound()) {
|
|
MESURE_TICKS(updateMouse);
|
|
MESURE_TICKS(updateActors);
|
|
MESURE_TICKS(updateObjects);
|
|
MESURE_TICKS(updateAmbientSounds);
|
|
MESURE_TICKS(updateMusic);
|
|
MESURE_TICKS(updateAdjustScreen);
|
|
}
|
|
|
|
return getScript()->process();
|
|
}
|
|
|
|
void Scene::updateMouse() {
|
|
Actor *player = getActor();
|
|
Common::Point mouse = getCursor()->position();
|
|
|
|
Common::Point pt;
|
|
player->adjustCoordinates(&pt);
|
|
|
|
Common::Rect actorRect;
|
|
if (_ws->chapter != kChapter2 || getSharedData()->getPlayerIndex() != 10) {
|
|
actorRect.left = pt.x + 20;
|
|
actorRect.top = pt.y;
|
|
actorRect.right = (int16)(pt.x + 2 * player->getPoint2()->x);
|
|
actorRect.bottom = (int16)(pt.y + player->getPoint2()->y);
|
|
} else {
|
|
actorRect.left = pt.x + 50;
|
|
actorRect.top = pt.y + 60;
|
|
actorRect.right = (int16)(pt.x + getActor(10)->getPoint2()->x + 10);
|
|
actorRect.bottom = (int16)(pt.y + getActor(10)->getPoint2()->y - 20);
|
|
}
|
|
|
|
ActorDirection newDirection = kDirectionInvalid;
|
|
|
|
if (mouse.x < actorRect.left) {
|
|
if (mouse.y >= actorRect.top) {
|
|
if (mouse.y > actorRect.bottom) {
|
|
if (player->getDirection() == kDirectionW) {
|
|
if ((mouse.y - actorRect.bottom) > 10)
|
|
newDirection = kDirectionSW;
|
|
} else {
|
|
if (player->getDirection() == kDirectionS) {
|
|
if ((actorRect.left - mouse.x) > 10)
|
|
newDirection = kDirectionSW;
|
|
} else {
|
|
newDirection = kDirectionSW;
|
|
}
|
|
}
|
|
} else {
|
|
if (player->getDirection() == kDirectionNW) {
|
|
if ((mouse.y - actorRect.top) > 10)
|
|
newDirection = kDirectionW;
|
|
} else {
|
|
if (player->getDirection() == kDirectionSW) {
|
|
if ((actorRect.bottom - mouse.y) > 10)
|
|
newDirection = kDirectionW;
|
|
} else {
|
|
newDirection = kDirectionW;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (player->getDirection() != kDirectionN) {
|
|
if (player->getDirection() == kDirectionW) {
|
|
if ((actorRect.top - mouse.y) > 10)
|
|
newDirection = kDirectionNW;
|
|
} else {
|
|
newDirection = kDirectionNW;
|
|
}
|
|
} else {
|
|
if ((actorRect.left - mouse.x) > 10)
|
|
newDirection = kDirectionNW;
|
|
}
|
|
}
|
|
|
|
} else if (mouse.x <= actorRect.right) {
|
|
if (mouse.y >= actorRect.top) {
|
|
if (mouse.y > actorRect.bottom) {
|
|
if (player->getDirection() == kDirectionSW) {
|
|
if ((mouse.x - actorRect.left) > 10)
|
|
newDirection = kDirectionS;
|
|
} else {
|
|
if (player->getDirection() == kDirectionSE) {
|
|
if ((actorRect.right - mouse.x) > 10)
|
|
newDirection = kDirectionS;
|
|
} else {
|
|
newDirection = kDirectionS;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (player->getDirection() == kDirectionNW) {
|
|
if ((mouse.x - actorRect.left) > 10)
|
|
newDirection = kDirectionN;
|
|
} else {
|
|
if (player->getDirection() == kDirectionNE) {
|
|
if ((actorRect.right - mouse.x) > 10)
|
|
newDirection = kDirectionN;
|
|
} else {
|
|
newDirection = kDirectionN;
|
|
}
|
|
}
|
|
}
|
|
} else if (mouse.y < actorRect.top) {
|
|
if (player->getDirection() != kDirectionN) {
|
|
if (player->getDirection() == kDirectionE) {
|
|
if ((actorRect.top - mouse.y) > 10)
|
|
newDirection = kDirectionNE;
|
|
} else {
|
|
newDirection = kDirectionNE;
|
|
}
|
|
} else {
|
|
if ((mouse.x - actorRect.right) > 10)
|
|
newDirection = kDirectionNE;
|
|
}
|
|
} else if (mouse.y <= actorRect.bottom) {
|
|
if (player->getDirection() == kDirectionSE) {
|
|
if ((actorRect.bottom - mouse.y) > 10)
|
|
newDirection = kDirectionE;
|
|
} else {
|
|
if (player->getDirection() == kDirectionNE) {
|
|
if ((mouse.y - actorRect.top) > 10)
|
|
newDirection = kDirectionE;
|
|
} else {
|
|
newDirection = kDirectionE;
|
|
}
|
|
}
|
|
} else if ( player->getDirection() == kDirectionS) {
|
|
if ((mouse.x - actorRect.right) > 10)
|
|
newDirection = kDirectionSE;
|
|
} else if ((player->getDirection() != kDirectionE || (mouse.y - actorRect.bottom) > 10)) {
|
|
newDirection = kDirectionSE;
|
|
}
|
|
|
|
updateCursor(newDirection, actorRect);
|
|
|
|
if (newDirection >= kDirectionN)
|
|
if (player->getStatus() == kActorStatusWalking || player->getStatus() == kActorStatus12)
|
|
player->updateFromDirection(newDirection);
|
|
}
|
|
|
|
|
|
void Scene::updateActors() {
|
|
if (!_ws)
|
|
error("[Scene::updateActors] WorldStats not initialized properly!");
|
|
|
|
for (uint32 i = 0; i < _ws->actors.size(); i++)
|
|
_ws->actors[i]->update();
|
|
}
|
|
|
|
void Scene::updateObjects() {
|
|
if (!_ws)
|
|
error("[Scene::updateObjects] WorldStats not initialized properly!");
|
|
|
|
for (uint32 i = 0; i < _ws->objects.size(); i++)
|
|
_ws->objects[i]->update();
|
|
}
|
|
|
|
void Scene::updateAmbientSounds() {
|
|
if (!_ws)
|
|
error("[Scene::updateAmbientSounds] WorldStats not initialized properly!");
|
|
|
|
if (Config.performance <= 3)
|
|
return;
|
|
|
|
// The original loops for each actor, but the volume calculation is always the same
|
|
|
|
for (uint32 i = 0; i < _ws->numAmbientSounds; i++) {
|
|
bool processSound = true;
|
|
AmbientSoundItem *snd = &_ws->ambientSounds[i];
|
|
uint32 ambientTick = getSharedData()->getAmbientTick(i);
|
|
|
|
for (int32 f = 0; f < 6; f++) {
|
|
int32 gameFlag = snd->flagNum[f];
|
|
if (gameFlag >= 0) {
|
|
if (_vm->isGameFlagNotSet((GameFlag)gameFlag)) {
|
|
processSound = false;
|
|
break;
|
|
}
|
|
} else {
|
|
if (_vm->isGameFlagSet((GameFlag)-gameFlag)) {
|
|
processSound = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (processSound) {
|
|
if (_vm->sound()->isPlaying(snd->resourceId)) {
|
|
|
|
if (snd->field_0) {
|
|
int32 volume = Config.ambientVolume + getSound()->calculateVolumeAdjustement(snd->point, snd->attenuation, snd->delta);
|
|
|
|
if (volume <= 0) {
|
|
if (volume < -10000)
|
|
volume = -10000;
|
|
|
|
getSound()->setVolume(snd->resourceId, volume);
|
|
} else {
|
|
getSound()->setVolume(snd->resourceId, 0);
|
|
}
|
|
}
|
|
|
|
} else {
|
|
int32 panning = (snd->field_0) ? getSound()->calculatePanningAtPoint(snd->point) : 0;
|
|
|
|
int32 volume = 0;
|
|
if (snd->field_0)
|
|
volume = getSound()->calculateVolumeAdjustement(snd->point, snd->attenuation, snd->delta);
|
|
else
|
|
volume = -(int32)pow((double)snd->delta, 2);
|
|
|
|
volume += Config.ambientVolume;
|
|
|
|
|
|
if (LOBYTE(snd->flags) & 1) {
|
|
|
|
getSound()->playSound(snd->resourceId, true, volume, panning);
|
|
|
|
} else if (LOBYTE(snd->flags) & 2) {
|
|
if (_vm->getRandom(10000) < 10) {
|
|
if (snd->field_0) {
|
|
getSound()->playSound(snd->resourceId, false, volume, panning);
|
|
} else {
|
|
int32 tmpVol = volume + (int32)_vm->getRandom(500) * ((_vm->getRandom(100) >= 50) ? -1 : 1);
|
|
|
|
if (tmpVol <= -10000)
|
|
tmpVol = -10000;
|
|
|
|
if (tmpVol >= 0)
|
|
tmpVol = 0;
|
|
else if (tmpVol <= -10000)
|
|
tmpVol = -10000;
|
|
|
|
getSound()->playSound(snd->resourceId, false, tmpVol, _vm->getRandom(20001) - 10000);
|
|
}
|
|
}
|
|
} else if (LOBYTE(snd->flags) & 4) {
|
|
if (ambientTick > _vm->getTick()) {
|
|
if (snd->nextTick >= 0)
|
|
getSharedData()->setAmbientTick(i, (uint32)((int32)_vm->getTick() + snd->nextTick * 60000));
|
|
else
|
|
getSharedData()->setAmbientTick(i, (uint32)((int32)_vm->getTick() - snd->nextTick * 1000));
|
|
|
|
getSound()->playSound(snd->resourceId, false, volume, panning);
|
|
}
|
|
} else if (LOBYTE(snd->flags) & 8) {
|
|
if (!getSharedData()->getAmbientFlag(i)) {
|
|
getSound()->playSound(snd->resourceId, false, volume, panning);
|
|
getSharedData()->setAmbientFlag(i, 1);
|
|
}
|
|
|
|
}
|
|
}
|
|
} else {
|
|
if (_vm->sound()->isPlaying(snd->resourceId))
|
|
_vm->sound()->stop(snd->resourceId);
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scene::updateMusic() {
|
|
if (!getWorld()->musicFlag)
|
|
return;
|
|
|
|
if (getWorld()->musicCurrentResourceIndex != kMusicStopped) {
|
|
switch (getWorld()->musicStatus) {
|
|
default:
|
|
break;
|
|
|
|
case 1:
|
|
getWorld()->musicCurrentResourceIndex = getWorld()->musicResourceIndex;
|
|
|
|
if (getWorld()->musicResourceIndex == kMusicStopped) {
|
|
getWorld()->musicStatus = 0;
|
|
getSound()->playMusic(kResourceNone, 0);
|
|
} else {
|
|
getWorld()->musicStatus = getWorld()->musicStatusExt;
|
|
getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, getWorld()->musicResourceIndex));
|
|
}
|
|
break;
|
|
|
|
case 2:
|
|
_musicVolume = getSound()->getMusicVolume();
|
|
getWorld()->musicStatus = 4;
|
|
break;
|
|
|
|
case 4:
|
|
_musicVolume -= 150;
|
|
if (_musicVolume >= -2500) {
|
|
getSound()->setMusicVolume(_musicVolume);
|
|
break;
|
|
}
|
|
|
|
_musicVolume = -10000;
|
|
getWorld()->musicCurrentResourceIndex = kMusicStopped;
|
|
|
|
if (getWorld()->musicResourceIndex == kMusicStopped) {
|
|
getWorld()->musicStatus = 0;
|
|
getSound()->playMusic(kResourceNone, 0);
|
|
} else {
|
|
getWorld()->musicStatus = 8;
|
|
getSound()->playMusic(kResourceNone, 0);
|
|
getWorld()->musicCurrentResourceIndex = getWorld()->musicResourceIndex;
|
|
_musicVolume = -2500;
|
|
getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, getWorld()->musicResourceIndex), _musicVolume);
|
|
}
|
|
break;
|
|
|
|
case 8:
|
|
_musicVolume += 150;
|
|
if (_musicVolume < 150) {
|
|
getSound()->setMusicVolume(_musicVolume);
|
|
break;
|
|
}
|
|
|
|
getSound()->setMusicVolume(Config.musicVolume);
|
|
getWorld()->musicStatus = getWorld()->musicStatusExt;
|
|
getWorld()->musicResourceIndex = (int32)kMusicStopped;
|
|
getWorld()->musicStatusExt = 0;
|
|
break;
|
|
}
|
|
} if (getWorld()->musicResourceIndex != kMusicStopped) {
|
|
switch (getWorld()->musicStatusExt) {
|
|
default:
|
|
break;
|
|
|
|
case 1:
|
|
getWorld()->musicCurrentResourceIndex = getWorld()->musicResourceIndex;
|
|
getWorld()->musicStatus = 1;
|
|
getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, getWorld()->musicResourceIndex));
|
|
getWorld()->musicResourceIndex = kMusicStopped;
|
|
getWorld()->musicStatusExt = 0;
|
|
getWorld()->musicFlag = 0;
|
|
break;
|
|
|
|
case 2:
|
|
_musicVolume = -10000;
|
|
getSound()->setMusicVolume(_musicVolume);
|
|
getWorld()->musicCurrentResourceIndex = getWorld()->musicResourceIndex;
|
|
getWorld()->musicStatus = 8;
|
|
getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, getWorld()->musicResourceIndex), _musicVolume);
|
|
break;
|
|
}
|
|
} else {
|
|
getWorld()->musicFlag = 0;
|
|
}
|
|
}
|
|
|
|
void Scene::updateAdjustScreen() {
|
|
if (g_debugScrolling) {
|
|
debugScreenScrolling();
|
|
} else {
|
|
updateCoordinates();
|
|
}
|
|
}
|
|
|
|
void Scene::updateCoordinates() {
|
|
Actor *act = getActor();
|
|
int16 xLeft = _ws->xLeft;
|
|
int16 yTop = _ws->yTop;
|
|
int16 posX = act->getPoint1()->x - _ws->xLeft;
|
|
int16 posY = act->getPoint1()->y - _ws->yTop;
|
|
Common::Rect boundingRect = _ws->boundingRect;
|
|
|
|
switch (_ws->motionStatus) {
|
|
default:
|
|
break;
|
|
|
|
case 1:
|
|
if (posX < boundingRect.left) {
|
|
xLeft = (posX - boundingRect.left) + _ws->xLeft;
|
|
_ws->xLeft += posX - boundingRect.left;
|
|
} else if (posX > boundingRect.right) {
|
|
xLeft = (posX - boundingRect.right) + _ws->xLeft;
|
|
_ws->xLeft += posX - boundingRect.right;
|
|
}
|
|
|
|
if (posY < boundingRect.top) {
|
|
yTop = (posY - boundingRect.top) + _ws->yTop;
|
|
_ws->yTop += posY - boundingRect.top;
|
|
} else if (posY > boundingRect.bottom) {
|
|
yTop = (posY - boundingRect.bottom) + _ws->yTop;
|
|
_ws->yTop += posY - boundingRect.bottom;
|
|
}
|
|
|
|
if (xLeft < 0)
|
|
xLeft = _ws->xLeft = 0;
|
|
|
|
if (xLeft > (_ws->width - 640))
|
|
xLeft = _ws->xLeft = _ws->width - 640;
|
|
|
|
if (yTop < 0)
|
|
yTop = _ws->yTop = 0;
|
|
|
|
if (yTop > (_ws->height - 480))
|
|
yTop = _ws->yTop = _ws->height - 480;
|
|
|
|
break;
|
|
|
|
case 2:
|
|
case 5: {
|
|
getSharedData()->setSceneOffset(getSharedData()->getSceneOffset() + getSharedData()->getSceneOffsetAdd());
|
|
|
|
int32 coord1 = 0;
|
|
int32 coord2 = 0;
|
|
|
|
if (abs(getSharedData()->getSceneCoords().x - _ws->coordinates[0]) <= abs(getSharedData()->getSceneCoords().y - _ws->coordinates[1])) {
|
|
coord1 = _ws->coordinates[1];
|
|
coord2 = yTop;
|
|
|
|
if (_ws->coordinates[1] != _ws->yTop)
|
|
xLeft = _ws->xLeft = getSharedData()->getSceneOffset() + getSharedData()->getSceneCoords().x;
|
|
|
|
xLeft = _ws->coordinates[2] + _ws->xLeft;
|
|
_ws->xLeft += _ws->coordinates[2];
|
|
|
|
} else {
|
|
coord1 = _ws->coordinates[0];
|
|
coord2 = xLeft;
|
|
|
|
if (_ws->coordinates[0] != _ws->xLeft)
|
|
yTop = _ws->yTop = getSharedData()->getSceneOffset() + getSharedData()->getSceneCoords().y;
|
|
|
|
yTop = _ws->coordinates[2] + _ws->yTop;
|
|
_ws->yTop += _ws->coordinates[2];
|
|
}
|
|
|
|
if (abs(coord2 - coord1) <= abs(_ws->coordinates[2])) {
|
|
_ws->motionStatus = 3;
|
|
_ws->coordinates[0] = -1;
|
|
}
|
|
|
|
}
|
|
break;
|
|
}
|
|
|
|
// Update scene coordinates
|
|
Common::Rect sceneRect = _ws->sceneRects[_ws->sceneRectIdx];
|
|
|
|
if (xLeft < sceneRect.left)
|
|
xLeft =_ws->xLeft =sceneRect.left;
|
|
|
|
if (yTop < sceneRect.top)
|
|
yTop = _ws->yTop = sceneRect.top;
|
|
|
|
if ((xLeft + 639) > sceneRect.right)
|
|
xLeft = _ws->xLeft = sceneRect.right - 639;
|
|
|
|
if ((yTop + 479) > sceneRect.bottom)
|
|
yTop = _ws->yTop = sceneRect.bottom - 479;
|
|
|
|
// XXX dword_44E1EC is set to 2 at this point if the scene coordinates
|
|
// have changed, but that variable is never used anywhere else
|
|
}
|
|
|
|
void Scene::updateCursor(ActorDirection direction, const Common::Rect &rect) {
|
|
HitType type = kHitNone;
|
|
Actor *player = getActor();
|
|
int16 rightLimit = rect.right - 10;
|
|
Common::Point mouse = getCursor()->position();
|
|
|
|
if (getSharedData()->getFlag(kFlagIsEncounterRunning)) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceTalkNPC])
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceTalkNPC]);
|
|
|
|
return;
|
|
}
|
|
|
|
if (getCursor()->getState() & kCursorStateRight) {
|
|
if (player->getStatus() == kActorStatusWalking || player->getStatus() == kActorStatus12) {
|
|
|
|
ResourceId resourceId =_ws->cursorResources[direction];
|
|
|
|
if (direction >= kDirectionN && getCursor()->getResourceId() != resourceId)
|
|
getCursor()->set(resourceId);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (player->getStatus() == kActorStatus6 || player->getStatus() == kActorStatus10) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceHand])
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceHand]);
|
|
|
|
return;
|
|
}
|
|
|
|
if (player->getField638()) {
|
|
if (mouse.x >= rect.left && mouse.x <= rightLimit && mouse.y >= rect.top && mouse.y <= rect.bottom && hitTestPlayer()) {
|
|
|
|
ResourceId id = _ws->cursorResourcesAlternate[player->getField638() + 31];
|
|
if (getCursor()->getResourceId() != id)
|
|
getCursor()->set(id, 0, kCursorAnimationNone);
|
|
|
|
} else {
|
|
if (hitTestScene(type) == -1) {
|
|
ResourceId id = _ws->cursorResourcesAlternate[player->getField638() + 31];
|
|
if (getCursor()->getResourceId() != id)
|
|
getCursor()->set(id, 0, kCursorAnimationNone);
|
|
} else {
|
|
ResourceId id = _ws->cursorResourcesAlternate[player->getField638() + 47];
|
|
uint32 frameCount = GraphicResource::getFrameCount(_vm, id);
|
|
if (getCursor()->getResourceId() != id)
|
|
getCursor()->set(id, 0, (frameCount <= 1) ? kCursorAnimationNone : kCursorAnimationMirror);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
if (mouse.x >= rect.left && mouse.x <= rightLimit && mouse.y >= rect.top && mouse.y <= rect.bottom && hitTestPlayer()) {
|
|
if (player->getReactionValue(0)) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceGrabPointer])
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceGrabPointer]);
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
int32 index = hitTest(type);
|
|
if (index == -1) {
|
|
if (_ws->chapter != kChapter2 || getSharedData()->getPlayerIndex() != 10) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceMagnifyingGlass] || getCursor()->getAnimation())
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceMagnifyingGlass]);
|
|
} else {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceTalkNPC2] || getCursor()->getAnimation())
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceTalkNPC2]);
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
int32 actionType = 0;
|
|
switch (type) {
|
|
default:
|
|
error("[Scene::updateCursor] Invalid hit type!");
|
|
break;
|
|
|
|
case kHitActionArea:
|
|
actionType = _ws->actions[index]->actionType;
|
|
break;
|
|
|
|
case kHitObject:
|
|
actionType = _ws->objects[index]->actionType;
|
|
break;
|
|
|
|
case kHitActor:
|
|
actionType = getActor(index)->actionType;
|
|
break;
|
|
}
|
|
|
|
if (actionType & kActionTypeFind) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceMagnifyingGlass] || getCursor()->getAnimation() != kCursorAnimationMirror)
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceMagnifyingGlass]);
|
|
} else if (actionType & kActionTypeTalk) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceTalkNPC])
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceTalkNPC]);
|
|
} else if (actionType & kActionTypeGrab) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceHand])
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceHand]);
|
|
} else if (actionType & kActionType16) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceTalkNPC2] || getCursor()->getAnimation() != kCursorAnimationMirror)
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceTalkNPC2]);
|
|
} else if (_ws->chapter != kChapter2 && getSharedData()->getPlayerIndex() != 10) {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceMagnifyingGlass] || getCursor()->getAnimation())
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceMagnifyingGlass]);
|
|
} else {
|
|
if (getCursor()->getResourceId() != _ws->cursorResources[kCursorResourceTalkNPC2] || getCursor()->getAnimation())
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceTalkNPC2]);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// HitTest
|
|
//////////////////////////////////////////////////////////////////////////
|
|
int32 Scene::hitTest(HitType &type) {
|
|
type = kHitNone;
|
|
|
|
int32 targetIdx = hitTestObject();
|
|
if (targetIdx == -1) {
|
|
|
|
targetIdx = hitTestActionArea();
|
|
if (targetIdx == -1) {
|
|
|
|
targetIdx = hitTestActor();
|
|
type = kHitActor;
|
|
|
|
} else {
|
|
type = kHitActionArea;
|
|
}
|
|
} else {
|
|
type = kHitObject;
|
|
}
|
|
|
|
return targetIdx;
|
|
}
|
|
|
|
int32 Scene::hitTestScene(HitType &type) {
|
|
if (!_ws)
|
|
error("[Scene::hitTestScene] WorldStats not initialized properly!");
|
|
|
|
const Common::Point pt = getCursor()->position();
|
|
|
|
int16 top = pt.x + _ws->xLeft;
|
|
int16 left = pt.y + _ws->yTop;
|
|
type = kHitNone;
|
|
|
|
int32 index = findActionArea(kActionAreaType2, Common::Point(top, left));
|
|
if (index != -1) {
|
|
if (_ws->actions[index]->actionType & kActionType8) {
|
|
type = kHitActionArea;
|
|
return index;
|
|
}
|
|
}
|
|
|
|
// Check objects
|
|
for (uint i = 0; i < _ws->objects.size(); i++) {
|
|
Object *object = _ws->objects[i];
|
|
|
|
if (object->isOnScreen() && (object->actionType & kActionType8)) {
|
|
if (hitTestPixel(object->getResourceId(),
|
|
object->getFrameIndex(),
|
|
top - object->x,
|
|
left - object->y,
|
|
(bool)(object->flags & kObjectFlag1000))) {
|
|
type = kHitObject;
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Check actors
|
|
for (uint i = 0; i < _ws->actors.size(); i++) {
|
|
Actor *actor = _ws->actors[i];
|
|
|
|
if (actor->actionType & kActionType8) {
|
|
uint32 frameIndex = (actor->getFrameIndex() >= actor->getFrameCount() ? 2 * actor->getFrameCount() - (actor->getFrameIndex() + 1) : actor->getFrameIndex());
|
|
|
|
if (hitTestPixel(actor->getResourceId(),
|
|
frameIndex,
|
|
top - (actor->getPoint()->x + actor->getPoint1()->x),
|
|
left - (actor->getPoint()->y + actor->getPoint1()->y),
|
|
actor->getDirection() >= kDirectionSE)) {
|
|
type = kHitActor;
|
|
return i;
|
|
}
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
int32 Scene::hitTestActionArea() {
|
|
const Common::Point pt = getCursor()->position();
|
|
|
|
int32 targetIdx = findActionArea(kActionAreaType2, Common::Point(_ws->xLeft + pt.x, _ws->yTop + pt.y));
|
|
|
|
if ( targetIdx == -1 || !(_ws->actions[targetIdx]->actionType & (kActionTypeFind | kActionTypeTalk | kActionTypeGrab | kActionType16)))
|
|
return -1;
|
|
|
|
return targetIdx;
|
|
}
|
|
|
|
ActorIndex Scene::hitTestActor() {
|
|
if (!_ws)
|
|
error("[Scene::hitTestActor] WorldStats not initialized properly!");
|
|
|
|
const Common::Point mouse = getCursor()->position();
|
|
|
|
if (_ws->actors.size() == 0)
|
|
return -1;
|
|
|
|
// Check actors 13 to 20
|
|
if (_ws->actors.size() >= 20) {
|
|
for (uint i = 13; i < 21; i++) {
|
|
Actor *actor = getActor(i);
|
|
|
|
if (!actor->isOnScreen() || !actor->actionType)
|
|
continue;
|
|
|
|
Common::Rect rect = GraphicResource::getFrameRect(_vm, getActor(12)->getResourceId(), 0);
|
|
|
|
int32 x = _ws->xLeft + mouse.x - (actor->getPoint1()->x + actor->getPoint()->x);
|
|
int32 y = _ws->yTop + mouse.y - (actor->getPoint1()->y + actor->getPoint()->y);
|
|
|
|
if (x > (rect.left - 20)
|
|
&& x < (rect.width() + rect.left + 20)
|
|
&& y > (rect.top - 20)
|
|
&& y < (rect.height() + rect.top + 20))
|
|
return i;
|
|
}
|
|
}
|
|
|
|
// Check Actor 11
|
|
if (_ws->actors.size() >= 11) {
|
|
Actor *actor11 = getActor(11);
|
|
if (actor11->isOnScreen() && actor11->actionType) {
|
|
Common::Point pt = mouse + Common::Point(_ws->xLeft, _ws->yTop) - *actor11->getPoint1();
|
|
|
|
if (actor11->getBoundingRect()->contains(pt))
|
|
return 11;
|
|
}
|
|
}
|
|
|
|
switch (_ws->chapter) {
|
|
default:
|
|
break;
|
|
|
|
case kChapter8:
|
|
if (_ws->actors.size() <= 7)
|
|
error("[Scene::hitTestActor] Not enough actors to check (chapter 8 - checking actors 1-7)!");
|
|
|
|
for (uint i = 1; i < 7; i++) {
|
|
Actor *actor = getActor(i);
|
|
|
|
if (!actor->isVisible() || !actor->actionType)
|
|
continue;
|
|
|
|
int32 x = _ws->xLeft + mouse.x - (actor->getPoint1()->x + actor->getPoint()->x);
|
|
int32 y = _ws->yTop + mouse.y - (actor->getPoint1()->y + actor->getPoint()->y);
|
|
|
|
if (x > 300 && x < 340 && y > 220 && y < 260)
|
|
return i;
|
|
}
|
|
break;
|
|
|
|
case kChapter11:
|
|
if (_ws->actors.size() <= 1)
|
|
error("[Scene::hitTestActor] Not enough actors to check (chapter 11 - checking actor 1)!");
|
|
|
|
if (getActor(1)->isOnScreen() && getActor(1)->actionType) {
|
|
Actor *actor = getActor(1);
|
|
|
|
int32 x = _ws->xLeft + mouse.x - (actor->getPoint1()->x + actor->getPoint()->x);
|
|
int32 y = _ws->yTop + mouse.y - (actor->getPoint1()->y + actor->getPoint()->y);
|
|
|
|
Common::Rect rect = GraphicResource::getFrameRect(_vm, actor->getResourceId(), 0);
|
|
|
|
if (x > (rect.left - 10)
|
|
&& x < (rect.width() + rect.left + 10)
|
|
&& y > (rect.top - 10)
|
|
&& y < (rect.height() + rect.top + 10))
|
|
return 1;
|
|
}
|
|
|
|
if (_ws->actors.size() <= 15)
|
|
error("[Scene::hitTestActor] Not enough actors to check (chapter 11 - checking actors 10-15)!");
|
|
|
|
for (uint i = 10; i < 15; i++) {
|
|
Actor *actor = getActor(i);
|
|
|
|
if (!actor->isOnScreen() || !actor->actionType)
|
|
continue;
|
|
|
|
Common::Rect rect = GraphicResource::getFrameRect(_vm, actor->getResourceId(), 0);
|
|
|
|
int32 x = _ws->xLeft + mouse.x - (actor->getPoint1()->x + actor->getPoint()->x);
|
|
int32 y = _ws->yTop + mouse.y - (actor->getPoint1()->y + actor->getPoint()->y);
|
|
|
|
if (x > (rect.left - 10)
|
|
&& x < (rect.width() + rect.left + 10)
|
|
&& y > (rect.top - 10)
|
|
&& y < (rect.height() + rect.top + 10))
|
|
return i;
|
|
}
|
|
break;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Default check
|
|
for (int i = _ws->actors.size() - 1; i >= 0 ; i--) {
|
|
Actor *actor = getActor(i);
|
|
|
|
uint32 hitFrame;
|
|
if (actor->getFrameIndex() >= actor->getFrameCount())
|
|
hitFrame = 2 * actor->getFrameIndex() - (actor->getFrameCount() + 1);
|
|
else
|
|
hitFrame = actor->getFrameIndex();
|
|
|
|
if (hitTestPixel(actor->getResourceId(),
|
|
hitFrame,
|
|
_ws->xLeft - (actor->getPoint()->x + actor->getPoint1()->x),
|
|
_ws->yTop - (actor->getPoint()->y + actor->getPoint1()->y),
|
|
actor->getDirection() >= kDirectionSE))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool Scene::hitTestPlayer() {
|
|
const Common::Point pt = getCursor()->position();
|
|
|
|
Actor *player = getActor();
|
|
Common::Point point;
|
|
|
|
player->adjustCoordinates(&point);
|
|
|
|
uint32 frameIndex = (player->getFrameIndex() >= player->getFrameCount() ? 2 * player->getFrameCount() - (player->getFrameIndex() + 1) : player->getFrameIndex());
|
|
|
|
return hitTestPixel(player->getResourceId(),
|
|
frameIndex,
|
|
pt.x - (player->getPoint()->x + point.x),
|
|
pt.y - (player->getPoint()->y + point.y),
|
|
player->getDirection() >= kDirectionSE);
|
|
}
|
|
|
|
int32 Scene::hitTestObject() {
|
|
if (!_ws)
|
|
error("[Scene::hitTestObject] WorldStats not initialized properly!");
|
|
|
|
const Common::Point pt = getCursor()->position();
|
|
|
|
for (uint32 i = 0; i < _ws->objects.size(); i++) {
|
|
Object *object = _ws->objects[i];
|
|
if (object->isOnScreen() && object->actionType)
|
|
if (hitTestPixel(object->getResourceId(),
|
|
object->getFrameIndex(),
|
|
_ws->xLeft + pt.x - object->x,
|
|
_ws->yTop + pt.y - object->y,
|
|
(bool)(object->flags & kObjectFlag1000)))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
bool Scene::hitTestPixel(ResourceId resourceId, uint32 frameIndex, int16 x, int16 y, bool flipped) {
|
|
if (x < 0 || y < 0)
|
|
return false;
|
|
|
|
GraphicResource *resource = new GraphicResource(_vm, resourceId);
|
|
GraphicFrame *frame = resource->getFrame(frameIndex);
|
|
Common::Rect frameRect = frame->getRect();
|
|
|
|
// Check y coordinates
|
|
if (y < frameRect.top || y >= frameRect.bottom)
|
|
goto cleanup;
|
|
|
|
// Compute left/right x coordinates, using flipped value
|
|
int32 left, right;
|
|
if (flipped) {
|
|
if (getScreen()->getFlag() == -1) {
|
|
left = resource->getData().maxWidth - frameRect.right;
|
|
right = resource->getData().maxWidth - frameRect.left;
|
|
} else {
|
|
left = frameRect.left + 2 * (getScreen()->getFlag() - (frameRect.right / 2));
|
|
right = x;
|
|
}
|
|
} else {
|
|
left = frameRect.left;
|
|
right = frameRect.right;
|
|
}
|
|
|
|
// Check x coordinates
|
|
if (x < left || x >= right)
|
|
goto cleanup;
|
|
|
|
// Check pixel value
|
|
byte *pixel;
|
|
if (flipped) {
|
|
pixel = (byte *)frame->surface.getBasePtr((left - x) + frame->getWidth() - 1, y - frame->y);
|
|
} else {
|
|
pixel = (byte *)frame->surface.getBasePtr(x - left, y - frame->y);
|
|
}
|
|
|
|
if (pixel == 0)
|
|
goto cleanup;
|
|
|
|
delete resource;
|
|
|
|
return true;
|
|
|
|
cleanup:
|
|
delete resource;
|
|
|
|
return false;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Hit actions
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Scene::handleHit(int32 index, HitType type) {
|
|
if (!_ws)
|
|
error("[Scene::handleHit] WorldStats not initialized properly!");
|
|
|
|
switch (type) {
|
|
default:
|
|
break;
|
|
|
|
case kHitActionArea:
|
|
if (!getScript()->isInQueue(_ws->actions[index]->scriptIndex)) {
|
|
debugC(kDebugLevelScripts, "[Script] Queuing Script idx: %d from kHitActionArea (idx: %d, name: '%s')",
|
|
_ws->actions[index]->scriptIndex, index, _ws->actions[index]->name);
|
|
getScript()->queueScript(_ws->actions[index]->scriptIndex, getSharedData()->getPlayerIndex());
|
|
}
|
|
|
|
switch (_ws->chapter) {
|
|
default:
|
|
break;
|
|
|
|
case kChapter2:
|
|
hitAreaChapter2(_ws->actions[index]->id);
|
|
break;
|
|
|
|
case kChapter7:
|
|
hitAreaChapter7(_ws->actions[index]->id);
|
|
break;
|
|
|
|
case kChapter11:
|
|
hitAreaChapter11(_ws->actions[index]->id);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case kHitObject: {
|
|
Object *object = _ws->objects[index];
|
|
|
|
if (object->getSoundResourceId()) {
|
|
if (getSound()->isPlaying(object->getSoundResourceId())) {
|
|
getSound()->stop(object->getSoundResourceId());
|
|
object->setSoundResourceId(kResourceNone);
|
|
}
|
|
}
|
|
|
|
if (!getScript()->isInQueue(object->getScriptIndex())) {
|
|
debugC(kDebugLevelScripts, "[Script] Queuing Script idx: %d from kHitObject (id: %d, name: '%s')",
|
|
object->getScriptIndex(), object->getId(), object->getName());
|
|
|
|
getScript()->queueScript(object->getScriptIndex(), getSharedData()->getPlayerIndex());
|
|
}
|
|
|
|
// Original executes special script hit functions, but since there is none defined, we can skip this part
|
|
}
|
|
break;
|
|
|
|
case kHitActor: {
|
|
Actor *actor = _ws->actors[index];
|
|
|
|
if (actor->actionType & (kActionTypeFind | kActionType16)) {
|
|
|
|
if (getScript()->isInQueue(actor->getScriptIndex())) {
|
|
debugC(kDebugLevelScripts, "[Script] Queuing Script idx: %d from kHitActor (id: %d, name: '%s')",
|
|
actor->getScriptIndex(), index, actor->getName());
|
|
getScript()->queueScript(actor->getScriptIndex(), getSharedData()->getPlayerIndex());
|
|
}
|
|
|
|
} else if (actor->actionType & kActionTypeTalk) {
|
|
|
|
if (getSound()->isPlaying(actor->getSoundResourceId())) {
|
|
if (actor->getStatus() != kActorStatusEnabled)
|
|
actor->updateStatus(kActorStatusEnabled);
|
|
|
|
getSound()->stop(actor->getSoundResourceId());
|
|
actor->setSoundResourceId(kResourceNone);
|
|
}
|
|
|
|
if (getScript()->isInQueue(actor->getScriptIndex())) {
|
|
debugC(kDebugLevelScripts, "[Script] Queuing Script idx: %d from kActionTypeTalk (actor idx: %d)",
|
|
actor->getScriptIndex(), getSharedData()->getPlayerIndex());
|
|
getScript()->queueScript(actor->getScriptIndex(), getSharedData()->getPlayerIndex());
|
|
}
|
|
}
|
|
|
|
switch (_ws->chapter) {
|
|
default:
|
|
break;
|
|
|
|
case kChapter2:
|
|
hitActorChapter2(index);
|
|
break;
|
|
|
|
case kChapter11:
|
|
hitActorChapter11(index);
|
|
break;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Scene::playerReaction() {
|
|
const Common::Point mouse = getCursor()->position();
|
|
Common::Point point;
|
|
Actor *player = getActor();
|
|
|
|
player->adjustCoordinates(&point);
|
|
|
|
uint32 count;
|
|
for (count = 0; count < 8; count++) {
|
|
if (!player->getReactionValue(count))
|
|
break;
|
|
}
|
|
|
|
player->setField638(0);
|
|
|
|
if (count > 0) {
|
|
for (uint32 i = 0; i < count; i++) {
|
|
Common::Point ret = _vm->getSinCosValues(count, i);
|
|
int32 x = point.x + player->getPoint2()->x + ret.x;
|
|
int32 y = point.y + player->getPoint2()->y / 2 - ret.y;
|
|
|
|
if (mouse.x >= x && mouse.x <= (x + 40) && mouse.y >= y && mouse.y <= (y + 40)) {
|
|
// Handle reaction
|
|
getSound()->playSound(MAKE_RESOURCE(kResourcePackSound, 4));
|
|
|
|
if (_ws->chapter == kChapter9) {
|
|
switch (i) {
|
|
default:
|
|
player->setField638(player->getReactionValue(i));
|
|
break;
|
|
|
|
case 0:
|
|
getScript()->queueScript(_ws->actions[_ws->getActionAreaIndexById(2206)]->scriptIndex, getSharedData()->getPlayerIndex());
|
|
break;
|
|
|
|
case 1:
|
|
getScript()->queueScript(_ws->actions[_ws->getActionAreaIndexById(2207)]->scriptIndex, getSharedData()->getPlayerIndex());
|
|
break;
|
|
|
|
case 2:
|
|
getScript()->queueScript(_ws->actions[_ws->getActionAreaIndexById(2208)]->scriptIndex, getSharedData()->getPlayerIndex());
|
|
break;
|
|
}
|
|
} else {
|
|
player->setField638(player->getReactionValue(i));
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
player->updateStatus(kActorStatusEnabled);
|
|
getSound()->playSound(MAKE_RESOURCE(kResourcePackSound, 5));
|
|
}
|
|
|
|
void Scene::hitAreaChapter2(int32 id) {
|
|
if (id == 783)
|
|
getActor()->setField638(6);
|
|
}
|
|
|
|
void Scene::hitAreaChapter7(int32 id) {
|
|
switch (id) {
|
|
default:
|
|
break;
|
|
|
|
case 1088:
|
|
if (_isCTRLPressed)
|
|
_vm->setGameFlag(kGameFlag1144);
|
|
break;
|
|
|
|
case 2504:
|
|
if (++_hitAreaChapter7Counter > 20) {
|
|
_vm->setGameFlag(kGameFlag1108);
|
|
getActor(1)->setPosition(570, 225, kDirectionN, 0);
|
|
getActor(1)->show();
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Scene::hitAreaChapter11(int32 id) {
|
|
if (!_ws)
|
|
error("[Scene::hitAreaChapter11] WorldStats not initialized properly!");
|
|
|
|
if (id == 1670)
|
|
_ws->field_E849C = 666;
|
|
}
|
|
|
|
|
|
void Scene::hitActorChapter2(ActorIndex index) {
|
|
if (!_ws)
|
|
error("[Scene::hitActorChapter2] WorldStats not initialized properly!");
|
|
|
|
Actor *player = getActor();
|
|
|
|
if (player->getStatus() != kActorStatus14 && player->getStatus() != kActorStatus12)
|
|
return;
|
|
|
|
if (index == 11) {
|
|
player->faceTarget((uint32)(index + 9), kDirectionFromActor);
|
|
player->updateStatus(kActorStatus15);
|
|
|
|
Actor *actor11 = getActor(index);
|
|
|
|
Common::Point pointPlayer(player->getPoint1()->x + player->getPoint2()->x, player->getPoint1()->y + player->getPoint2()->y);
|
|
Common::Point pointActor11(actor11->getPoint1()->x + actor11->getPoint2()->x, actor11->getPoint1()->y + actor11->getPoint2()->y);
|
|
|
|
if (Actor::euclidianDistance(pointPlayer, pointActor11) < 150) {
|
|
if (actor11->getStatus() == kActorStatus12)
|
|
actor11->updateStatus(kActorStatus18);
|
|
|
|
if (actor11->getStatus() == kActorStatusEnabled)
|
|
actor11->updateStatus(kActorStatus14);
|
|
}
|
|
|
|
getSharedData()->setChapter2ActorIndex(index);
|
|
|
|
} else if (index > 12) {
|
|
player->faceTarget((uint32)(index + 9), kDirectionFromActor);
|
|
player->updateStatus(kActorStatus15);
|
|
getSharedData()->setChapter2ActorIndex(index);
|
|
}
|
|
}
|
|
|
|
void Scene::hitActorChapter11(ActorIndex index) {
|
|
if (!_ws)
|
|
error("[Scene::hitActorChapter11] WorldStats not initialized properly!");
|
|
|
|
if (_ws->field_E848C < 3)
|
|
_ws->field_E849C = index;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Helpers
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Scene::playIntroSpeech() {
|
|
ResourceId resourceId;
|
|
|
|
switch (_packId) {
|
|
default:
|
|
resourceId = (ResourceId)_packId;
|
|
break;
|
|
|
|
case kResourcePackCourtyardAndChapel:
|
|
resourceId = getSpeech()->playScene(4, 3);
|
|
break;
|
|
|
|
case kResourcePackCave:
|
|
resourceId = getSpeech()->playScene(4, 6);
|
|
break;
|
|
|
|
case kResourcePackLaboratory:
|
|
resourceId = getSpeech()->playScene(4, 7);
|
|
break;
|
|
}
|
|
|
|
getScreen()->clear();
|
|
getScreen()->stopPaletteFade(0, 0, 0);
|
|
|
|
do {
|
|
// Poll events (this ensure we don't freeze the screen)
|
|
Common::Event ev;
|
|
_vm->getEventManager()->pollEvent(ev);
|
|
|
|
g_system->delayMillis(100);
|
|
|
|
} while (getSound()->isPlaying(resourceId));
|
|
}
|
|
|
|
void Scene::stopSpeech() {
|
|
if (_vm->isGameFlagSet(kGameFlag219)) {
|
|
if (getSpeech()->getSoundResourceId() != kResourceNone && getSound()->isPlaying(getSpeech()->getSoundResourceId()))
|
|
getSound()->stopAll(getSpeech()->getSoundResourceId());
|
|
else if (getSpeech()->getTick())
|
|
getSpeech()->setTick(_vm->getTick());
|
|
}
|
|
}
|
|
|
|
bool Scene::speak(Common::KeyCode code) {
|
|
if (!_ws)
|
|
error("[Scene::speak] WorldStats not initialized properly!");
|
|
|
|
#define GET_INDEX() ((int)abs((double)_vm->getRandom(RAND_MAX)) & 1)
|
|
|
|
int32 index = -1;
|
|
|
|
switch (code) {
|
|
default:
|
|
break;
|
|
|
|
case Common::KEYCODE_p:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = GET_INDEX();
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
index = 1;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_q:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 3 - GET_INDEX();
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
index = 2;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_r:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 2;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
index = 4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_s:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 5;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
index = 3;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_t:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 6;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
case 3:
|
|
index = 4;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_u:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 7;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
index = 5;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_v:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 8;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
index = 6;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_w:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 9;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
index = 7;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_x:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 10;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
index = 8;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_y:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 11;
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
index = 9;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_z:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 13 - GET_INDEX();
|
|
break;
|
|
|
|
case 1:
|
|
case 2:
|
|
index = 10;
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case Common::KEYCODE_LEFTBRACKET:
|
|
switch (_ws->actorType) {
|
|
default:
|
|
break;
|
|
|
|
case 0:
|
|
index = 15 - GET_INDEX();
|
|
break;
|
|
|
|
case 2:
|
|
index = 12 - GET_INDEX();
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (getSpeech()->getSoundResourceId() && getSound()->isPlaying(getSpeech()->getSoundResourceId()))
|
|
return false;
|
|
|
|
if (index == -1)
|
|
return false;
|
|
|
|
getSpeech()->playPlayer(index);
|
|
|
|
return true;
|
|
|
|
#undef GET_INDEX
|
|
}
|
|
|
|
bool Scene::pointIntersectsRect(const Common::Point &point, const Common::Rect &rect) const {
|
|
if (rect.top || rect.left || rect.bottom || rect.right) {
|
|
Common::Rational res(rect.height() * (point.x - rect.left), rect.width());
|
|
|
|
return (bool)(point.y > (rect.top + res.toInt()));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Scene::rectIntersect(int32 x, int32 y, int32 x1, int32 y1, int32 x2, int32 y2, int32 x3, int32 y3) const {
|
|
return (x <= x3 && x1 >= x2) && (y <= y3 && y1 >= y2);
|
|
}
|
|
|
|
void Scene::adjustCoordinates(Common::Point *point) {
|
|
if (!_ws)
|
|
error("[Scene::adjustCoordinates] WorldStats not initialized properly!");
|
|
|
|
point->x = _ws->xLeft + getCursor()->position().x;
|
|
point->y = _ws->yTop + getCursor()->position().y;
|
|
}
|
|
|
|
Actor* Scene::getActor(ActorIndex index) {
|
|
if (!_ws)
|
|
error("[Scene::getActor] WorldStats not initialized properly!");
|
|
|
|
ActorIndex computedIndex = (index != kActorInvalid) ? index : getSharedData()->getPlayerIndex();
|
|
|
|
if (computedIndex < 0 || computedIndex >= (int16)_ws->actors.size())
|
|
error("[Scene::getActor] Invalid actor index: %d ([0-%d] allowed)", computedIndex, _ws->actors.size() - 1);
|
|
|
|
return _ws->actors[computedIndex];
|
|
}
|
|
|
|
bool Scene::updateSceneCoordinates(int32 tX, int32 tY, int32 A0, bool checkSceneCoords, int32 *param) {
|
|
if (!_ws)
|
|
error("[Scene::updateSceneCoordinates] WorldStats not initialized properly!");
|
|
|
|
Common::Rect *sr = &_ws->sceneRects[_ws->sceneRectIdx];
|
|
|
|
int16 *targetX = &_ws->coordinates[0];
|
|
int16 *targetY = &_ws->coordinates[1];
|
|
int16 *coord3 = &_ws->coordinates[2];
|
|
|
|
*targetX = (int16)tX;
|
|
*targetY = (int16)tY;
|
|
|
|
*coord3 = (int16)A0;
|
|
|
|
// Adjust coordinates
|
|
if (checkSceneCoords)
|
|
if (*targetX + 640 > _ws->width)
|
|
*targetX = _ws->width - 640;
|
|
|
|
if (*targetX < sr->left)
|
|
*targetX = sr->left;
|
|
|
|
if (*targetY < sr->top)
|
|
*targetY = sr->top;
|
|
|
|
if (*targetX + 640 > sr->right)
|
|
*targetX = sr->right - 640;
|
|
|
|
if (*targetY + 480 < sr->bottom)
|
|
*targetY = sr->bottom - 480;
|
|
|
|
if (checkSceneCoords)
|
|
if (*targetY + 480 > _ws->height)
|
|
*targetY = _ws->height - 480;
|
|
|
|
// Adjust scene offsets & coordinates
|
|
getSharedData()->setSceneOffset(0);
|
|
getSharedData()->setSceneCoords(Common::Point(_ws->xLeft, _ws->yTop));
|
|
|
|
int32 diffX = *targetX - _ws->xLeft;
|
|
int32 diffY = *targetY - _ws->yTop;
|
|
|
|
if (abs(diffX) <= abs(diffY)) {
|
|
if (_ws->yTop > *targetY)
|
|
*coord3 = -*coord3;
|
|
|
|
getSharedData()->setSceneOffsetAdd((int16)Common::Rational(*coord3 * diffX, diffY).toInt());
|
|
|
|
if (param != NULL && abs(diffY) <= abs(*coord3)) {
|
|
*targetX = -1;
|
|
*param = 0;
|
|
return true;
|
|
}
|
|
} else {
|
|
if (_ws->xLeft > *targetX)
|
|
*coord3 = -*coord3;
|
|
|
|
getSharedData()->setSceneOffsetAdd((int16)Common::Rational(*coord3 * diffY, diffX).toInt());
|
|
|
|
if (param != NULL && abs(diffX) <= abs(*coord3)) {
|
|
*targetX = -1;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
int32 Scene::findActionArea(ActionAreaType type, const Common::Point &pt, bool highlight) {
|
|
if (!_ws)
|
|
error("[Scene::findActionArea] WorldStats not initialized properly!");
|
|
|
|
if (!_polygons)
|
|
error("[Scene::findActionArea] Polygons not initialized properly!");
|
|
|
|
Common::Array<int32> areaIds;
|
|
|
|
switch (type) {
|
|
default:
|
|
return type - 2;
|
|
|
|
case kActionAreaType1:
|
|
if (_ws->actions.size() < 1)
|
|
return -1;
|
|
|
|
for (int32 i = _ws->actions.size() - 1; i >= 0; i--) {
|
|
ActionArea *area = _ws->actions[i];
|
|
|
|
if (g_debugPolygons && highlight) {
|
|
#ifdef DEBUG
|
|
// Highlight each polygon as it gets checked for action
|
|
debugHighlightPolygon(area->polygonIndex);
|
|
#endif
|
|
}
|
|
|
|
bool found = false;
|
|
|
|
// Iterate over flagNum
|
|
for (uint32 j = 0; j < 10; j++) {
|
|
if (!area->flagNums[j])
|
|
break; // We stop as soon as a flag is 0
|
|
|
|
bool flagSet = false;
|
|
if (area->flagNums[j] <= 0)
|
|
flagSet = _vm->isGameFlagNotSet((GameFlag)-area->flagNums[j]);
|
|
else
|
|
flagSet = _vm->isGameFlagSet((GameFlag)area->flagNums[j]);
|
|
|
|
if (!flagSet) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found && _polygons->get(area->polygonIndex).contains(pt))
|
|
areaIds.push_back(i);
|
|
}
|
|
break;
|
|
|
|
case kActionAreaType2:
|
|
if (_ws->actions.size() < 1)
|
|
return -1;
|
|
|
|
for (int32 i = _ws->actions.size() - 1; i >= 0; i--) {
|
|
ActionArea *area = _ws->actions[i];
|
|
|
|
bool found = false;
|
|
|
|
// Iterate over flagNum
|
|
for (uint32 j = 0; j < 10; j++) {
|
|
if (!area->flagNums[j])
|
|
continue; // We skip over null flags
|
|
|
|
bool flagSet = false;
|
|
if (area->flagNums[j] <= 0)
|
|
flagSet = _vm->isGameFlagNotSet((GameFlag)-area->flagNums[j]);
|
|
else
|
|
flagSet = _vm->isGameFlagSet((GameFlag)area->flagNums[j]);
|
|
|
|
if (!flagSet) {
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!found && _polygons->get(area->polygonIndex).contains(pt))
|
|
areaIds.push_back(i);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (areaIds.empty()) {
|
|
return -1;
|
|
} else {
|
|
int32 i;
|
|
for (i = 0; i < areaIds.size(); i++)
|
|
if (_ws->actions[i]->flags)
|
|
break;
|
|
|
|
return (i == areaIds.size()) ? areaIds[0] : areaIds[i];
|
|
}
|
|
}
|
|
|
|
void Scene::changePlayer(ActorIndex index) {
|
|
if (!_ws)
|
|
error("[Scene::changePlayer] WorldStats not initialized properly!");
|
|
|
|
switch (index) {
|
|
default:
|
|
if (_ws->chapter == kChapter9) {
|
|
changePlayerUpdate(index);
|
|
|
|
getActor(index)->show();
|
|
}
|
|
|
|
getSharedData()->setPlayerIndex(index);
|
|
break;
|
|
|
|
case 1:
|
|
if (_ws->chapter == kChapter9) {
|
|
changePlayerUpdate(index);
|
|
|
|
getScreen()->setPalette(_ws->graphicResourceIds[0]);
|
|
_ws->currentPaletteId = _ws->graphicResourceIds[0];
|
|
getScreen()->setGammaLevel(_ws->graphicResourceIds[0]);
|
|
_vm->setGameFlag(kGameFlag635);
|
|
_vm->clearGameFlag(kGameFlag636);
|
|
_vm->clearGameFlag(kGameFlag637);
|
|
|
|
getActor(index)->show();
|
|
}
|
|
|
|
getSharedData()->setPlayerIndex(index);
|
|
break;
|
|
|
|
case 2:
|
|
if (_ws->chapter == kChapter9) {
|
|
changePlayerUpdate(index);
|
|
|
|
getScreen()->setPalette(_ws->graphicResourceIds[1]);
|
|
_ws->currentPaletteId = _ws->graphicResourceIds[1];
|
|
getScreen()->setGammaLevel(_ws->graphicResourceIds[1]);
|
|
_vm->setGameFlag(kGameFlag636);
|
|
_vm->clearGameFlag(kGameFlag635);
|
|
_vm->clearGameFlag(kGameFlag637);
|
|
|
|
getActor(index)->show();
|
|
}
|
|
|
|
getSharedData()->setPlayerIndex(index);
|
|
break;
|
|
|
|
case 3:
|
|
if (_ws->chapter == kChapter9) {
|
|
changePlayerUpdate(index);
|
|
|
|
getScreen()->setPalette(_ws->graphicResourceIds[2]);
|
|
_ws->currentPaletteId = _ws->graphicResourceIds[2];
|
|
getScreen()->setGammaLevel(_ws->graphicResourceIds[2]);
|
|
_vm->setGameFlag(kGameFlag637);
|
|
_vm->clearGameFlag(kGameFlag635);
|
|
_vm->clearGameFlag(kGameFlag636);
|
|
|
|
getActor(index)->show();
|
|
}
|
|
|
|
getActor(index)->show();
|
|
getSharedData()->setPlayerIndex(index);
|
|
break;
|
|
|
|
case 666:
|
|
getScreen()->setupTransTables(3, _ws->graphicResourceIds[50], _ws->graphicResourceIds[49], _ws->graphicResourceIds[48]);
|
|
|
|
// Save scene data
|
|
getSharedData()->saveCursorResources((ResourceId *)&_ws->cursorResources, sizeof(_ws->cursorResources));
|
|
getSharedData()->saveSceneFonts(_ws->font1, _ws->font2, _ws->font3);
|
|
getSharedData()->saveSmallCursor(_ws->smallCurDown, _ws->smallCurUp);
|
|
getSharedData()->saveEncounterFrameBackground(_ws->encounterFrameBg);
|
|
|
|
// Setup new values
|
|
for (uint32 i = 0; i < 11; i++)
|
|
_ws->cursorResources[i] = _ws->graphicResourceIds[40 + i];
|
|
|
|
_ws->font1 = _ws->graphicResourceIds[35];
|
|
_ws->font2 = _ws->graphicResourceIds[37];
|
|
_ws->font3 = _ws->graphicResourceIds[36];
|
|
|
|
_ws->smallCurUp = _ws->graphicResourceIds[33];
|
|
_ws->smallCurDown = _ws->graphicResourceIds[34];
|
|
_ws->encounterFrameBg = _ws->graphicResourceIds[32];
|
|
break;
|
|
|
|
case 667:
|
|
getScreen()->setupTransTables(3, _ws->cellShadeMask1, _ws->cellShadeMask2, _ws->cellShadeMask3);
|
|
|
|
// Load scene data
|
|
getSharedData()->loadCursorResources((ResourceId *)&_ws->cursorResources, sizeof(_ws->cursorResources));
|
|
getSharedData()->loadSceneFonts(&_ws->font1, &_ws->font2, &_ws->font3);
|
|
getSharedData()->loadSmallCursor(&_ws->smallCurDown, &_ws->smallCurUp);
|
|
getSharedData()->loadEncounterFrameBackground(&_ws->encounterFrameBg);
|
|
|
|
// Reset cursor
|
|
getCursor()->set(_ws->cursorResources[kCursorResourceMagnifyingGlass], 0, kCursorAnimationNone);
|
|
break;
|
|
|
|
case 668:
|
|
getActor(11)->setPosition(2300, 100, kDirectionN, 0);
|
|
getSharedData()->setChapter2Counter(6, 0);
|
|
getSharedData()->setFlag(kFlag1, false);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Scene::changePlayerUpdate(ActorIndex index) {
|
|
Actor *actor = getActor(index);
|
|
Actor *player = getActor();
|
|
|
|
actor->setPosition(player->getPoint1()->x + player->getPoint2()->x, player->getPoint1()->y + player->getPoint2()->y, player->getDirection(), 0);
|
|
player->hide();
|
|
|
|
for (uint i = 0; i < 8; i++)
|
|
actor->setReaction(i, player->getReactionValue(i));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Scene drawing
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Scene::preload() {
|
|
if (!Config.showSceneLoading)
|
|
return;
|
|
|
|
SceneTitle *title = new SceneTitle(_vm);
|
|
title->load();
|
|
|
|
do {
|
|
title->update(_vm->getTick());
|
|
|
|
getScreen()->copyBackBufferToScreen();
|
|
g_system->updateScreen();
|
|
|
|
g_system->delayMillis(10);
|
|
|
|
// Poll events (this ensure we don't freeze the screen)
|
|
Common::Event ev;
|
|
_vm->getEventManager()->pollEvent(ev);
|
|
|
|
} while (!title->loadingComplete());
|
|
|
|
delete title;
|
|
}
|
|
|
|
bool Scene::drawScene() {
|
|
if (!_ws)
|
|
error("[Scene::drawScene] WorldStats not initialized properly!");
|
|
|
|
_vm->screen()->clearGraphicsInQueue();
|
|
|
|
if (getSharedData()->getFlag(kFlagRedraw)) {
|
|
_vm->screen()->clear();
|
|
return false;
|
|
}
|
|
|
|
// Draw scene background
|
|
getScreen()->draw(_ws->backgroundImage, 0, Common::Point(-_ws->xLeft, -_ws->yTop), kDrawFlagNone, false);
|
|
|
|
// Draw actors on the update list
|
|
buildUpdateList();
|
|
processUpdateList();
|
|
|
|
if (_ws->chapter == kChapter11)
|
|
checkVisibleActorsPriority();
|
|
|
|
// Queue updates
|
|
for (uint32 i = 0; i < _ws->actors.size(); i++)
|
|
_ws->actors[i]->draw();
|
|
|
|
for (uint32 i = 0; i < _ws->objects.size(); i++)
|
|
_ws->objects[i]->draw();
|
|
|
|
Actor *player = getActor();
|
|
if (player->getStatus() == kActorStatus6 || player->getStatus() == kActorStatus10)
|
|
player->updateAndDraw();
|
|
else
|
|
player->setNumberFlag01(0);
|
|
|
|
_vm->screen()->drawGraphicsInQueue();
|
|
|
|
// Show debug information
|
|
if (g_debugScrolling)
|
|
debugScreenScrolling();
|
|
if (g_debugActors)
|
|
debugShowActors();
|
|
if (g_debugPolygons)
|
|
debugShowPolygons();
|
|
if (g_debugObjects)
|
|
debugShowObjects();
|
|
if (g_debugSceneRects)
|
|
debugShowSceneRects();
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Scene::updateListCompare(const UpdateItem &item1, const UpdateItem &item2) {
|
|
return (item1.priority - item2.priority < 0) ? false : true;
|
|
}
|
|
|
|
void Scene::buildUpdateList() {
|
|
if (!_ws)
|
|
error("[Scene::buildUpdateList] WorldStats not initialized properly!");
|
|
|
|
_updateList.clear();
|
|
|
|
for (uint32 i = 0; i < _ws->actors.size(); i++) {
|
|
Actor *actor = _ws->actors[i];
|
|
|
|
if (actor->isVisible()) {
|
|
UpdateItem item;
|
|
item.index = i;
|
|
item.priority = actor->getPoint1()->y + actor->getPoint2()->y;
|
|
|
|
_updateList.push_back(item);
|
|
}
|
|
}
|
|
|
|
// Sort the list (the original uses qsort, so we may have to revert to that if our sort isn't behaving the same)
|
|
Common::sort(_updateList.begin(), _updateList.end(), &Scene::updateListCompare);
|
|
}
|
|
|
|
void Scene::processUpdateList() {
|
|
if (!_ws)
|
|
error("[Scene::processUpdateList] WorldStats not initialized properly!");
|
|
|
|
for (uint32 i = 0; i < _updateList.size(); i++) {
|
|
Actor *actor = getActor(_updateList[i].index);
|
|
int32 priority = _updateList[i].priority;
|
|
|
|
// Check priority
|
|
if (priority < 0) {
|
|
actor->setPriority(abs(priority));
|
|
continue;
|
|
}
|
|
|
|
actor->setPriority(3);
|
|
|
|
if (actor->getField944() == 1 || actor->getField944() == 4) {
|
|
actor->setPriority(1);
|
|
} else {
|
|
actor->setField938(1);
|
|
actor->setField934(0);
|
|
Common::Point sum = *actor->getPoint1() + *actor->getPoint2();
|
|
|
|
int16 bottomRight = actor->getPoint1()->y + actor->getBoundingRect()->bottom + 4;
|
|
|
|
if (_ws->chapter == kChapter11 && _updateList[i].index != getSharedData()->getPlayerIndex())
|
|
bottomRight += 20;
|
|
|
|
// Our actor rect
|
|
Common::Rect actorRect(actor->getPoint1()->x, actor->getPoint1()->y, actor->getPoint1()->x + actor->getBoundingRect()->right, bottomRight);
|
|
|
|
// Process objects
|
|
for (uint32 j = 0; j < _ws->objects.size(); j++) {
|
|
Object *object = _ws->objects[j];
|
|
|
|
// Skip hidden objects
|
|
if (!object->isOnScreen())
|
|
continue;
|
|
|
|
// Check that the rects are contained
|
|
if (!rectIntersect(object->x,
|
|
object->y,
|
|
object->x + object->getBoundingRect()->right,
|
|
object->y + object->getBoundingRect()->bottom,
|
|
actor->getPoint1()->x,
|
|
actor->getPoint1()->y,
|
|
actor->getPoint1()->x + actor->getBoundingRect()->right,
|
|
bottomRight)) {
|
|
|
|
if ((BYTE1(object->flags) & kObjectFlag20) && !(BYTE1(object->flags) & kObjectFlag80))
|
|
BYTE1(object->flags) = BYTE1(object->flags) | kObjectFlag40;
|
|
|
|
continue;
|
|
}
|
|
|
|
// Check if it intersects with either the object rect or the related polygon
|
|
bool isMasked = false;
|
|
if (object->flags & kObjectFlag2) {
|
|
isMasked = !pointIntersectsRect(sum, *object->getRect());
|
|
} else if (object->flags & kObjectFlag40) {
|
|
Polygon poly = _polygons->get(object->getPolygonIndex());
|
|
isMasked = poly.contains(sum);
|
|
}
|
|
|
|
// Adjust object flags
|
|
if ((BYTE1(object->flags) & kObjectFlag80) || isMasked) {
|
|
if (BYTE1(object->flags) & kObjectFlag20)
|
|
BYTE1(object->flags) = (BYTE1(object->flags) & kObjectFlagBF) | kObjectFlag80;
|
|
} else {
|
|
if (BYTE1(object->flags) & kObjectFlag20) {
|
|
BYTE1(object->flags) = BYTE1(object->flags) | kObjectFlag40;
|
|
}
|
|
}
|
|
|
|
if (LOBYTE(object->flags) & kObjectFlag4) {
|
|
if (isMasked) {
|
|
if (actor->flags & kActorFlagMasked)
|
|
error("[Scene::processUpdateList] Assigning mask to masked character (%s)", actor->getName());
|
|
|
|
// We are masked by the object!
|
|
actor->setObjectIndex(j);
|
|
actor->flags |= kActorFlagMasked;
|
|
}
|
|
} else {
|
|
if (isMasked) {
|
|
if (actor->getPriority() < object->getPriority()) {
|
|
actor->setField934(1);
|
|
actor->setPriority(object->getPriority() + 3);
|
|
|
|
if (i > 0) {
|
|
// Update actor priority up to current index
|
|
for (uint32 k = 0; k < i; k++) {
|
|
Actor *previousActor = getWorld()->actors[_updateList[k].index];
|
|
|
|
if (getWorld()->chapter != kChapter2 || previousActor->getField944() != 1) {
|
|
if (previousActor->getPriority() == actor->getPriority())
|
|
actor->setPriority(actor->getPriority() - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (actor->getPriority() > object->getPriority() || actor->getPriority() == 1) {
|
|
actor->setField934(1);
|
|
actor->setPriority(object->getPriority() - 1);
|
|
|
|
if (i > 0) {
|
|
|
|
// Update actor priority up to current index
|
|
for (uint32 k = 0; k < i; k++) {
|
|
Actor *previousActor = getWorld()->actors[_updateList[k].index];
|
|
|
|
if (previousActor->getField944() != 1 && previousActor->getField944() != 4) {
|
|
Actor *actorCheck = getWorld()->actors[k];
|
|
|
|
if (rectIntersect(actorCheck->getPoint1()->x,
|
|
actorCheck->getPoint1()->y,
|
|
actorCheck->getPoint1()->x + actorCheck->getBoundingRect()->bottom,
|
|
actorCheck->getPoint1()->y + actorCheck->getBoundingRect()->right,
|
|
actor->getPoint1()->x,
|
|
actor->getPoint1()->y,
|
|
actor->getPoint1()->x + actor->getBoundingRect()->right,
|
|
bottomRight)) {
|
|
if (previousActor->getPriority() == actor->getPriority())
|
|
actor->setPriority(actor->getPriority() - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} // end processing objects
|
|
|
|
// Update all other actors
|
|
for (uint32 k = 0; k < _updateList.size(); k++) {
|
|
Actor *actor2 = getActor(_updateList[k].index);
|
|
|
|
if (actor2->isVisible() && actor2->getField944() != 1 && actor2->getField944() != 4 && _updateList[k].index != _updateList[i].index) {
|
|
|
|
Common::Rect actor2Rect(actor2->getPoint1()->x, actor2->getPoint1()->y, actor2->getPoint1()->x + actor2->getBoundingRect()->right, actor2->getPoint1()->y + actor2->getBoundingRect()->bottom);
|
|
|
|
if (actor2Rect.contains(actorRect)) {
|
|
|
|
// Inferior
|
|
if ((actor2->getPoint1()->y + actor2->getPoint2()->y) > (actor->getPoint1()->y + actor->getPoint2()->y)) {
|
|
if (actor->getPriority() <= actor2->getPriority()) {
|
|
if (actor->getField934() || actor2->getNumberValue01()) {
|
|
if (!actor2->getNumberValue01())
|
|
actor2->setPriority(actor->getPriority() - 1);
|
|
} else {
|
|
actor->setPriority(actor2->getPriority() + 1);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Superior
|
|
if ((actor2->getPoint1()->y + actor2->getPoint2()->y) < (actor->getPoint1()->y + actor->getPoint2()->y)) {
|
|
if (actor->getPriority() >= actor2->getPriority()) {
|
|
if (actor->getField934() || actor2->getNumberValue01()) {
|
|
if (!actor2->getNumberValue01())
|
|
actor2->setPriority(actor->getPriority() + 1);
|
|
} else {
|
|
actor->setPriority(actor2->getPriority() - 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (actor->shouldInvertPriority())
|
|
getActor(actor->getNextActorIndex())->setPriority(-actor->getPriority());
|
|
}
|
|
} // end processing actors
|
|
|
|
|
|
// Go through the list from the end
|
|
if (_updateList.size() > 1) {
|
|
for (int i = _updateList.size() - 1; i >= 0; --i) {
|
|
// Get the actor
|
|
Actor *actor1 = getActor(_updateList[i].index);
|
|
|
|
// Skip hidden actors
|
|
if (!actor1->isVisible())
|
|
continue;
|
|
|
|
if (actor1->getField944() != 1 && actor1->getField944() != 4) {
|
|
// Process all previous actors
|
|
if (i > 0) {
|
|
for (int j = i - 1; j >= 0; --j) {
|
|
Actor *actor2 = getActor(_updateList[j].index);
|
|
|
|
if (actor2->getField944() != 1 && actor2->getField944() != 4) {
|
|
|
|
// Process priorities
|
|
if (actor2->getPriority() <= actor1->getPriority()) {
|
|
if (rectIntersect(actor1->getPoint1()->x,
|
|
actor1->getPoint1()->y,
|
|
actor1->getPoint1()->x + actor1->getBoundingRect()->right,
|
|
actor1->getPoint1()->y + actor1->getBoundingRect()->bottom,
|
|
actor2->getPoint1()->x,
|
|
actor2->getPoint1()->y,
|
|
actor2->getPoint1()->x + actor2->getBoundingRect()->right,
|
|
actor2->getPoint1()->y + actor2->getBoundingRect()->bottom)) {
|
|
actor2->setPriority(actor1->getPriority() + 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Scene::checkVisibleActorsPriority() {
|
|
for (uint i = 2; i < 9; i++)
|
|
if (getActor(i)->isVisible())
|
|
adjustActorPriority(i);
|
|
|
|
for (uint i = 16; i < 18; i++)
|
|
if (getActor(i)->isVisible())
|
|
adjustActorPriority(i);
|
|
}
|
|
|
|
void Scene::adjustActorPriority(ActorIndex index) {
|
|
Actor* actor0 = getActor(0);
|
|
Actor* actor = getActor(index);
|
|
|
|
if (rectIntersect(actor0->getPoint1()->x,
|
|
actor0->getPoint1()->y,
|
|
actor0->getPoint1()->x + actor0->getBoundingRect()->right,
|
|
actor0->getPoint1()->y + actor0->getBoundingRect()->bottom + 4,
|
|
actor->getPoint1()->x,
|
|
actor->getPoint1()->y,
|
|
actor->getPoint1()->x + actor0->getBoundingRect()->right,
|
|
actor->getPoint1()->y + actor0->getBoundingRect()->bottom)) {
|
|
if (actor->getPriority() < actor0->getPriority())
|
|
actor0->setPriority(actor->getPriority());
|
|
}
|
|
}
|
|
|
|
void Scene::drawRain() {
|
|
if (!_ws)
|
|
error("[Scene::drawRain] WorldStats not initialized properly!");
|
|
|
|
if (getSharedData()->getFlag(kFlagSkipDrawScene))
|
|
return;
|
|
|
|
for (int16 y = 0; y < 512; y = y + 64) {
|
|
for (int16 x = 0; x < 704; x = x + 64) {
|
|
getScreen()->draw(MAKE_RESOURCE(kResourcePackShared, 58), (uint32)_chapter5RainFrameIndex, Common::Point(x + (_ws->xLeft % 64) / 8, y + (_ws->yTop % 64) / 8));
|
|
}
|
|
}
|
|
|
|
_chapter5RainFrameIndex = (_chapter5RainFrameIndex + 1) % (int32)GraphicResource::getFrameCount(_vm, MAKE_RESOURCE(kResourcePackShared, 58));
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Debug
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Scene::debugScreenScrolling() {
|
|
if (!_ws)
|
|
error("[Scene::debugScreenScrolling] WorldStats not initialized properly!");
|
|
|
|
Common::Rect rect = GraphicResource::getFrameRect(_vm, _ws->backgroundImage, 0);
|
|
|
|
// Horizontal scrolling
|
|
if (getCursor()->position().x < SCREEN_EDGES && _ws->xLeft >= SCROLL_STEP)
|
|
_ws->xLeft -= SCROLL_STEP;
|
|
else if (getCursor()->position().x > (640 - SCREEN_EDGES) && _ws->xLeft <= (rect.width() - (640 + SCROLL_STEP)))
|
|
_ws->xLeft += SCROLL_STEP;
|
|
|
|
// Vertical scrolling
|
|
if (getCursor()->position().y < SCREEN_EDGES && _ws->yTop >= SCROLL_STEP)
|
|
_ws->yTop -= SCROLL_STEP;
|
|
else if (getCursor()->position().y > (480 - SCREEN_EDGES) && _ws->yTop <= (rect.height() - (480 + SCROLL_STEP)))
|
|
_ws->yTop += SCROLL_STEP;
|
|
}
|
|
|
|
// WALK REGION DEBUG
|
|
void Scene::debugShowWalkRegion(Polygon *poly) {
|
|
Graphics::Surface surface;
|
|
surface.create((uint16)poly->boundingRect.width() + 1,
|
|
(uint16)poly->boundingRect.height() + 1,
|
|
Graphics::PixelFormat::createFormatCLUT8());
|
|
|
|
// Draw all lines in Polygon
|
|
for (uint32 i = 0; i < poly->count(); i++) {
|
|
surface.drawLine(
|
|
poly->points[i].x - poly->boundingRect.left,
|
|
poly->points[i].y - poly->boundingRect.top,
|
|
poly->points[(i+1) % poly->count()].x - poly->boundingRect.left,
|
|
poly->points[(i+1) % poly->count()].y - poly->boundingRect.top, 0x3A);
|
|
}
|
|
|
|
getScreen()->copyToBackBufferClipped(&surface, poly->boundingRect.left, poly->boundingRect.top);
|
|
|
|
surface.free();
|
|
}
|
|
|
|
// POLYGONS DEBUG
|
|
void Scene::debugShowPolygons() {
|
|
if (!_polygons)
|
|
error("[Scene::debugShowPolygons] Polygons not initialized properly!");
|
|
|
|
for (uint32 p = 0; p < _polygons->size(); p++)
|
|
debugShowPolygon(p);
|
|
}
|
|
|
|
void Scene::debugShowPolygon(uint32 index, uint32 color) {
|
|
if (!_polygons)
|
|
error("[Scene::debugShowPolygon] Polygons not initialized properly");
|
|
|
|
if (index >= _polygons->size() - 1)
|
|
return;
|
|
|
|
Graphics::Surface surface;
|
|
Polygon poly = _polygons->get(index);
|
|
surface.create((uint16)poly.boundingRect.width() + 1,
|
|
(uint16)poly.boundingRect.height() + 1,
|
|
Graphics::PixelFormat::createFormatCLUT8());
|
|
|
|
// Draw all lines in Polygon
|
|
for (uint32 i = 0; i < poly.count(); i++) {
|
|
surface.drawLine(poly.points[i].x - poly.boundingRect.left,
|
|
poly.points[i].y - poly.boundingRect.top,
|
|
poly.points[(i+1) % poly.count()].x - poly.boundingRect.left,
|
|
poly.points[(i+1) % poly.count()].y - poly.boundingRect.top,
|
|
color);
|
|
}
|
|
|
|
getScreen()->copyToBackBufferClipped(&surface, poly.boundingRect.left, poly.boundingRect.top);
|
|
|
|
surface.free();
|
|
}
|
|
|
|
void Scene::debugHighlightPolygon(uint32 index) {
|
|
debugShowPolygon(index, 0x12);
|
|
getScreen()->copyBackBufferToScreen();
|
|
g_system->updateScreen();
|
|
}
|
|
|
|
// SCENE RECTS DEBUG
|
|
void Scene::debugShowSceneRects() {
|
|
if (!_ws)
|
|
error("[Scene::debugShowObjects] WorldStats not initialized properly!");
|
|
|
|
for (uint32 i = 0; i < ARRAYSIZE(_ws->sceneRects); i++)
|
|
getScreen()->drawRect(_ws->sceneRects[i]);
|
|
}
|
|
|
|
// OBJECT DEBUGGING
|
|
void Scene::debugShowObjects() {
|
|
if (!_ws)
|
|
error("[Scene::debugShowObjects] WorldStats not initialized properly!");
|
|
|
|
for (uint32 p = 0; p < _ws->objects.size(); p++) {
|
|
Graphics::Surface surface;
|
|
Object *object = _ws->objects[p];
|
|
|
|
if (object->isOnScreen()) {
|
|
surface.create((uint16)object->getBoundingRect()->width() + 1,
|
|
(uint16)object->getBoundingRect()->height() + 1,
|
|
Graphics::PixelFormat::createFormatCLUT8());
|
|
surface.frameRect(*object->getBoundingRect(), 0x22);
|
|
getScreen()->copyToBackBufferClipped(&surface, object->x, object->y);
|
|
}
|
|
|
|
surface.free();
|
|
}
|
|
}
|
|
|
|
// ACTOR DEBUGGING
|
|
void Scene::debugShowActors() {
|
|
if (!_ws)
|
|
error("[Scene::debugShowActors] WorldStats not initialized properly!");
|
|
|
|
for (uint32 p = 0; p < _ws->actors.size(); p++) {
|
|
Graphics::Surface surface;
|
|
Actor *a = _ws->actors[p];
|
|
|
|
if (a->isOnScreen()) {
|
|
surface.create((uint16)a->getBoundingRect()->width() + 1,
|
|
(uint16)a->getBoundingRect()->height() + 1,
|
|
Graphics::PixelFormat::createFormatCLUT8());
|
|
surface.frameRect(*a->getBoundingRect(), 0x128);
|
|
getScreen()->copyToBackBufferClipped(&surface, a->getPoint1()->x, a->getPoint1()->y);
|
|
}
|
|
|
|
surface.free();
|
|
}
|
|
}
|
|
|
|
} // end of namespace Asylum
|