mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-23 20:51:14 +00:00
1681 lines
45 KiB
C++
1681 lines
45 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/resources/encounters.h"
|
|
|
|
#include "asylum/resources/actor.h"
|
|
#include "asylum/resources/object.h"
|
|
#include "asylum/resources/script.h"
|
|
#include "asylum/resources/worldstats.h"
|
|
|
|
#include "asylum/system/cursor.h"
|
|
#include "asylum/system/graphics.h"
|
|
#include "asylum/system/screen.h"
|
|
#include "asylum/system/speech.h"
|
|
#include "asylum/system/text.h"
|
|
|
|
#include "asylum/views/scene.h"
|
|
#include "asylum/views/video.h"
|
|
|
|
#include "asylum/asylum.h"
|
|
#include "asylum/respack.h"
|
|
#include "asylum/staticres.h"
|
|
|
|
namespace Asylum {
|
|
|
|
#define KEYWORD_MASK 0xFFF
|
|
|
|
#define OPCODE_NAME(index) (index > 25 ? "INVALID" : opcodeNames[index])
|
|
const char *opcodeNames[] = {
|
|
"Return",
|
|
"SetScriptVariable",
|
|
"SetCounterFromVars",
|
|
"SetOffset",
|
|
"SetOffsetIfCounterNegative",
|
|
"SetOffsetIfCounterNegativeOrNull",
|
|
"SetOffsetIfCounterIsNull",
|
|
"SetOffsetIfCounterIsNotNull",
|
|
"SetOffsetIfCounterPositiveOrNull",
|
|
"SetOffsetIfCounterPositive",
|
|
"SetCurrentItemOptions",
|
|
"ClearCurrentItemOptions",
|
|
"SetItemOptions",
|
|
"CloseDialog",
|
|
"ResetSpeech",
|
|
"SetVariable",
|
|
"IncrementScriptVariable",
|
|
"ProcessVariable3",
|
|
"AddRemoveInventoryItem",
|
|
"UNUSED (19)",
|
|
"UNUSED (20)",
|
|
"SetCounterIfInventoryOmits",
|
|
"UNUSED (22)",
|
|
"PrepareMovie",
|
|
"SetClearGameFlag",
|
|
"SetCounterFromGameFlag"
|
|
};
|
|
|
|
Common::String Encounter::ScriptEntry::toString() {
|
|
return Common::String::format("0x%02X: %s (%d, %d)", opcode, OPCODE_NAME(opcode), param1, param2);
|
|
}
|
|
|
|
Encounter::Encounter(AsylumEngine *engine) : _vm(engine),
|
|
_index(0), _speechResourceId(0), _soundResourceId(kResourceNone), _item(NULL), _objectId1(kObjectNone), _objectId2(kObjectNone), _objectId3(kObjectNone),
|
|
_actorIndex(kActorInvalid), _shouldEnablePlayer(false), _wasPlayerDisabled(false), _isClosing(false), _isScriptRunning(false) {
|
|
|
|
memset(&_keywordIndexes, 0, sizeof(_keywordIndexes));
|
|
_rectIndex = -1;
|
|
|
|
_value1 = 0;
|
|
_tick = 0;
|
|
_data_455B14 = 0;
|
|
_data_455B3C = 0;
|
|
_data_455B70 = 0;
|
|
_data_455BCC = false;
|
|
_isDialogOpen = false;
|
|
_shouldCloseDialog = false;
|
|
_data_455BD8 = false;
|
|
_data_455BDC = false;
|
|
_data_455BE0 = false;
|
|
_shouldCloseBackground = false;
|
|
_data_455BE8 = false;
|
|
_data_455BF0 = 0;
|
|
_data_455BF4 = 0;
|
|
_keywordStartIndex = 0;
|
|
|
|
load();
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Data
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Encounter::load() {
|
|
Common::File file;
|
|
|
|
if (!file.open("sntrm.dat"))
|
|
error("[Encounter::load] Could not open encounter data!");
|
|
|
|
// Load the variables
|
|
uint16 count = file.readUint16LE();
|
|
for (uint i = 0; i < count; i++)
|
|
_variables.push_back(file.readSint16LE());
|
|
|
|
// Read anvil flag
|
|
if (file.readSint16LE())
|
|
error("[Encounter::load] Data file not supported!");
|
|
|
|
// Read encounter data
|
|
int16 dataCount = file.readSint16LE();
|
|
for (uint8 i = 0; i < dataCount; i++) {
|
|
EncounterItem item;
|
|
|
|
item.speechResourceId = file.readSint32LE();
|
|
item.scriptResourceId = (ResourceId)file.readSint32LE();
|
|
|
|
for (uint j = 0; j < ARRAYSIZE(item.keywords); j++)
|
|
item.keywords[j] = file.readSint16LE();
|
|
|
|
item.variable2 = file.readByte();
|
|
|
|
_items.push_back(item);
|
|
}
|
|
|
|
file.close();
|
|
}
|
|
|
|
void Encounter::initData() {
|
|
memset(&_keywordIndexes, -1, sizeof(_keywordIndexes));
|
|
|
|
uint32 currentIndex = 0;
|
|
|
|
for (uint i = 0; i < 50; i++) {
|
|
if (_item->keywords[i] & KEYWORD_MASK) {
|
|
if (!isKeywordDisabled(_item->keywords[i])) {
|
|
_keywordIndexes[currentIndex] = i;
|
|
currentIndex++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (uint i = 0; i < 50; i++) {
|
|
if (_item->keywords[i] & KEYWORD_MASK) {
|
|
if (isKeywordDisabled(_item->keywords[i])) {
|
|
_keywordIndexes[currentIndex] = i;
|
|
currentIndex++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void Encounter::initBackground() {
|
|
_background.resourceId = getWorld()->encounterFrameBg;
|
|
_background.frameIndex = 0;
|
|
_background.frameCount = GraphicResource::getFrameCount(_vm, _background.resourceId);
|
|
_background.rect = GraphicResource::getFrameRect(_vm, _background.resourceId, _background.frameCount - 1);
|
|
|
|
Common::Point point;
|
|
Actor *player = getScene()->getActor();
|
|
player->adjustCoordinates(&point);
|
|
_point = Common::Point(15, (point.y < 240) ? 464 - _background.rect.height() : 15);
|
|
|
|
_background.transTableNum = 1;
|
|
}
|
|
|
|
void Encounter::initPortraits() {
|
|
// Portrait 1
|
|
if (_index == 18)
|
|
_portrait1.resourceId = getWorld()->graphicResourceIds[51];
|
|
else
|
|
_portrait1.resourceId = getWorld()->graphicResourceIds[encounterPortrait1Index[getWorld()->chapter == kChapter9 ? getWorld()->actorType + 9 : getWorld()->chapter]];
|
|
|
|
if (_portrait1.resourceId == kResourceInvalid && getWorld()->chapter == kChapter1)
|
|
_portrait1.resourceId = getWorld()->graphicResourceIds[36];
|
|
|
|
if (_portrait1.resourceId == kResourceInvalid)
|
|
error("[Encounter::initPortraits] No portrait 1 for this encounter!");
|
|
|
|
_portrait1.frameIndex = 0;
|
|
_portrait1.frameCount = GraphicResource::getFrameCount(_vm, _portrait1.resourceId);
|
|
_portrait1.rect = GraphicResource::getFrameRect(_vm, _portrait1.resourceId, 0);
|
|
_portrait1.transTableNum = 0;
|
|
_portrait1.transTableMax = 3;
|
|
_portrait1.speech0 = 0;
|
|
|
|
// Portrait 2
|
|
if (_index != 59)
|
|
_portrait2.resourceId = getWorld()->graphicResourceIds[encounterPortrait2Index[_index]];
|
|
else if (_vm->isGameFlagSet(kGameFlag353))
|
|
_portrait2.resourceId = getWorld()->graphicResourceIds[16];
|
|
else if (_vm->isGameFlagSet(kGameFlag354))
|
|
_portrait2.resourceId = getWorld()->graphicResourceIds[23];
|
|
else if (_vm->isGameFlagSet(kGameFlag355))
|
|
_portrait2.resourceId = getWorld()->graphicResourceIds[24];
|
|
|
|
if (_portrait2.resourceId == kResourceInvalid && getWorld()->chapter == kChapter1)
|
|
_portrait2.resourceId = getWorld()->graphicResourceIds[36];
|
|
|
|
if (_portrait2.resourceId == kResourceInvalid)
|
|
error("[Encounter::initPortraits] No portrait 2 for this encounter!");
|
|
|
|
_portrait2.frameIndex = 0;
|
|
_portrait2.frameCount = GraphicResource::getFrameCount(_vm, _portrait2.resourceId);
|
|
_portrait2.rect = GraphicResource::getFrameRect(_vm, _portrait2.resourceId, 0);
|
|
_portrait2.transTableNum = 0;
|
|
_portrait2.transTableMax = 0;
|
|
_portrait2.speech0 = 0;
|
|
}
|
|
|
|
void Encounter::initDrawStructs() {
|
|
for (uint i = 0; i < ARRAYSIZE(_drawingStructs); i++) {
|
|
_drawingStructs[i].resourceId = (i == 0) ? getWorld()->smallCurUp : getWorld()->smallCurDown;
|
|
_drawingStructs[i].frameIndex = 0;
|
|
_drawingStructs[i].status = 0;
|
|
_drawingStructs[i].transTableNum = -1;
|
|
|
|
Common::Rect frameRect = GraphicResource::getFrameRect(_vm, _drawingStructs[i].resourceId, 0);
|
|
_drawingStructs[i].point1 = Common::Point(frameRect.height(), frameRect.width());
|
|
_drawingStructs[i].point2 = Common::Point(_point.x + _background.rect.width() + 10,
|
|
_point.y + (i == 0 ? 5 : _point.x + _background.rect.height() - 6));
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Run
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Encounter::run(int32 encounterIndex, ObjectId objectId1, ObjectId objectId2, ActorIndex actorIndex) {
|
|
debugC(kDebugLevelEncounter, "[Encounter] Running Encounter %d: object1 = %d object2 = %d actor = %d",
|
|
encounterIndex, objectId1, objectId2, actorIndex);
|
|
|
|
if (!_speechResourceId) {
|
|
_item = &_items[0];
|
|
_speechResourceId = _item->speechResourceId;
|
|
}
|
|
|
|
if (encounterIndex < 0)
|
|
return;
|
|
|
|
// Original engine saves the event handler passed as first parameter (to be restored later)
|
|
// Since it always passes the current scene instance, we restore it at the end and skip
|
|
// saving it here
|
|
_index = encounterIndex;
|
|
_item = &_items[_index];
|
|
_objectId1 = objectId1;
|
|
_objectId2 = objectId2;
|
|
_actorIndex = actorIndex;
|
|
|
|
if (getWorld()->getObjectById(objectId2))
|
|
getWorld()->getObjectById(objectId2)->stopSound();
|
|
|
|
getScene()->getActor(actorIndex)->stopSound();
|
|
|
|
setVariable(1, 0);
|
|
setVariable(2, _item->variable2);
|
|
|
|
// Disable the player and store the previous state as a flag
|
|
Actor *player = getScene()->getActor();
|
|
if (player->getStatus() == kActorStatusDisabled) {
|
|
_wasPlayerDisabled = true;
|
|
} else {
|
|
_wasPlayerDisabled = false;
|
|
player->updateStatus(kActorStatusDisabled);
|
|
}
|
|
|
|
_shouldEnablePlayer = false;
|
|
|
|
// Setup encounter event handler
|
|
_vm->switchEventHandler(this);
|
|
}
|
|
|
|
void Encounter::exitEncounter() {
|
|
setVariable(1, 32767);
|
|
initScript(_item->scriptResourceId);
|
|
_isClosing = true;
|
|
runScript();
|
|
|
|
setupEntities(true);
|
|
|
|
++_item->variable2;
|
|
// Original saves the modified item back here (we are using a reference to it all along)
|
|
|
|
// Update flags
|
|
getSharedData()->setFlag(kFlagIsEncounterRunning, false);
|
|
getSharedData()->setFlag(kFlag3, true);
|
|
|
|
// Check if we need to re-enable the player
|
|
if (_wasPlayerDisabled)
|
|
_wasPlayerDisabled = false;
|
|
else
|
|
_shouldEnablePlayer = true;
|
|
|
|
if (getSharedData()->getFlag(kFlagEncounterDisablePlayerOnExit))
|
|
getScene()->getActor()->updateStatus(kActorStatusDisabled);
|
|
|
|
getSharedData()->setFlag(kFlagEncounterDisablePlayerOnExit, false);
|
|
|
|
if (getSound()->getMusicVolume() != Config.musicVolume)
|
|
getSound()->setMusicVolume(Config.musicVolume);
|
|
|
|
// Restore scene event handler
|
|
_vm->switchEventHandler(getScene());
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Message handler
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool Encounter::handleEvent(const AsylumEvent &evt) {
|
|
switch ((int32)evt.type) {
|
|
default:
|
|
break;
|
|
|
|
case EVENT_ASYLUM_INIT:
|
|
return init();
|
|
|
|
case EVENT_ASYLUM_UPDATE:
|
|
return update();
|
|
|
|
case Common::EVENT_KEYDOWN:
|
|
return key(evt);
|
|
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
case Common::EVENT_LBUTTONUP:
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
case Common::EVENT_RBUTTONUP:
|
|
return mouse(evt);
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Encounter::init() {
|
|
// Lower music volume while we are in the encounter
|
|
if (getSound()->getMusicVolume() != Config.musicVolume - 500)
|
|
getSound()->setMusicVolume(Config.musicVolume - 500);
|
|
|
|
if (!getSharedData()->getMatteBarHeight()) {
|
|
getSharedData()->setFlag(kFlagIsEncounterRunning, true);
|
|
_shouldCloseDialog = false;
|
|
_data_455BD8 = false;
|
|
_data_455BDC = false;
|
|
_data_455BE0 = false;
|
|
_shouldCloseBackground = false;
|
|
_data_455BCC = false;
|
|
_data_455B3C = 1;
|
|
_rectIndex = -1;
|
|
_value1 = 0;
|
|
_data_455BF4 = 0;
|
|
_keywordStartIndex = 0;
|
|
_data_455B14 = -1;
|
|
|
|
getSpeech()->resetTextData();
|
|
|
|
initData();
|
|
|
|
getText()->loadFont(getWorld()->font1);
|
|
|
|
initBackground();
|
|
initPortraits();
|
|
initDrawStructs();
|
|
}
|
|
|
|
_isDialogOpen = false;
|
|
getCursor()->set(getWorld()->cursorResources[kCursorResourceTalkNPC], -1, kCursorAnimationMirror);
|
|
|
|
if (!getSharedData()->getMatteBarHeight())
|
|
initScript(_item->scriptResourceId);
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Encounter::update() {
|
|
// Check that the music volume is lowered
|
|
if (getSound()->getMusicVolume() != Config.musicVolume - 500)
|
|
getSound()->setMusicVolume(Config.musicVolume - 500);
|
|
|
|
uint32 tick = _vm->getTick();
|
|
ResourceId id = kResourceNone;
|
|
|
|
if (_objectId3) {
|
|
_isDialogOpen = false;
|
|
|
|
Object *object = getWorld()->getObjectById(_objectId3);
|
|
id = object->getResourceId();
|
|
|
|
if (object->getFrameIndex() == object->getFrameCount() - 1) {
|
|
switch (getVariable(3)) {
|
|
default:
|
|
break;
|
|
|
|
case 13:
|
|
if (_actorIndex)
|
|
getScene()->getActor(_actorIndex)->show();
|
|
else
|
|
setupEntities(true);
|
|
break;
|
|
|
|
case 14:
|
|
getScene()->getActor()->show();
|
|
break;
|
|
|
|
case 15:
|
|
if (_actorIndex)
|
|
getScene()->getActor(_actorIndex)->show();
|
|
else
|
|
setupEntities(true);
|
|
|
|
getScene()->getActor()->show();
|
|
break;
|
|
}
|
|
|
|
object->disable();
|
|
_objectId3 = kObjectNone;
|
|
_data_455BF4 = 0;
|
|
getCursor()->show();
|
|
}
|
|
}
|
|
|
|
if (_data_455BE8) {
|
|
if (getSharedData()->getMatteBarHeight()) {
|
|
_isDialogOpen = false;
|
|
} else {
|
|
getCursor()->show();
|
|
_data_455BE8 = false;
|
|
_data_455BF4 = 0;
|
|
}
|
|
}
|
|
|
|
if (_isDialogOpen) {
|
|
if (_data_455BF4 == 1) {
|
|
_data_455BF4 = 2;
|
|
runScript();
|
|
}
|
|
|
|
bool doScript = false;
|
|
if ((_soundResourceId/*getSpeech()->getSoundResourceId()*/ && !getSound()->isPlaying(_soundResourceId/*getSpeech()->getSoundResourceId()*/) && !_data_455BE0) // TODO replace with speech
|
|
/*|| (getSpeech()->getTick() && tick >= getSpeech()->getTick())*/)
|
|
doScript = true;
|
|
|
|
if (doScript
|
|
&& !getSharedData()->getMatteBarHeight()
|
|
&& _isScriptRunning
|
|
&& !setupSpeechTest(id))
|
|
runScript();
|
|
}
|
|
|
|
// Redraw screen
|
|
if (!getSharedData()->getFlag(kFlagRedraw)) {
|
|
if (updateScreen())
|
|
return true;
|
|
|
|
getSharedData()->setFlag(kFlagRedraw, true);
|
|
}
|
|
|
|
if (tick >= getSharedData()->getNextScreenUpdate() && getSharedData()->getFlag(kFlagRedraw)) {
|
|
if (getSharedData()->getMatteBarHeight() <= 0) {
|
|
getScreen()->copyBackBufferToScreen();
|
|
} else {
|
|
drawScreen();
|
|
}
|
|
|
|
getSharedData()->setFlag(kFlagRedraw, false);
|
|
getSharedData()->setNextScreenUpdate(tick + 55);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Encounter::key(const AsylumEvent &evt) {
|
|
switch (evt.kbd.keycode) {
|
|
default:
|
|
break;
|
|
|
|
case Common::KEYCODE_TAB:
|
|
getScreen()->takeScreenshot();
|
|
break;
|
|
|
|
case Common::KEYCODE_ESCAPE:
|
|
if (!isSpeaking()
|
|
&& _isDialogOpen
|
|
&& !getSpeech()->getTextData()
|
|
&& !getSpeech()->getTextDataPos())
|
|
_shouldCloseDialog = true;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Encounter::mouse(const AsylumEvent &evt) {
|
|
switch (evt.type) {
|
|
default:
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
if (!_data_455BD8) {
|
|
_data_455BD8 = true;
|
|
_rectIndex = findRect();
|
|
|
|
if (_rectIndex != -1)
|
|
updateDrawingStatus2(_rectIndex);
|
|
}
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONUP:
|
|
if (_rectIndex == -1) {
|
|
if (!isSpeaking())
|
|
choose(getKeywordIndex());
|
|
|
|
_data_455BD8 = false;
|
|
} else {
|
|
_rectIndex = -1;
|
|
updateDrawingStatus1(_rectIndex);
|
|
_data_455BD8 = false;
|
|
}
|
|
break;
|
|
|
|
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
if (!isSpeaking()
|
|
&& _isDialogOpen
|
|
&& !getSpeech()->getTextData()
|
|
&& !getSpeech()->getTextDataPos())
|
|
_shouldCloseDialog = true;
|
|
break;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Variables
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Encounter::setVariable(uint32 index, int16 val) {
|
|
if (index >= _variables.size())
|
|
error("[Encounter::setVariable] Invalid index (was: %d, max: %d)", index, _variables.size() - 1);
|
|
|
|
_variables[index] = val;
|
|
}
|
|
|
|
int16 Encounter::getVariable(uint32 index) {
|
|
if (index >= _variables.size())
|
|
error("[Encounter::getVariable] Invalid index (was: %d, max: %d)", index, _variables.size() - 1);
|
|
|
|
return _variables[index];
|
|
}
|
|
|
|
int16 Encounter::getVariableInv(int16 index) {
|
|
if (index >= 0)
|
|
return index;
|
|
|
|
return getVariable((uint16)-index);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Actions
|
|
//////////////////////////////////////////////////////////////////////////
|
|
uint32 Encounter::findKeyword(EncounterItem *item, int16 keyword) const {
|
|
for (uint i = 0; i < ARRAYSIZE(item->keywords); i++) {
|
|
if ((item->keywords[i] & KEYWORD_MASK) == keyword)
|
|
return i;
|
|
}
|
|
|
|
error("[Encounter::findKeyword] Could not find a valid keyword!");
|
|
}
|
|
|
|
int32 Encounter::getKeywordIndex() {
|
|
Common::Point mousePos = getCursor()->position();
|
|
|
|
int16 counter = 0;
|
|
for (uint i = _keywordStartIndex; i < ARRAYSIZE(_keywordIndexes); i++) {
|
|
int32 index = _keywordIndexes[i];
|
|
|
|
if (counter / 3 >= 8)
|
|
break;
|
|
|
|
if ((_item->keywords[index] & KEYWORD_MASK) > 0 && isKeywordVisible(_item->keywords[index])) {
|
|
int32 x = _drawingStructs[0].point1.y + 145 * (counter % 3) + _point.x + _portrait1.rect.width() + 15;
|
|
int32 y = 16 * (counter / 3) + _point.y + 5;
|
|
|
|
if (mousePos.x >= x && mousePos.x <= (x + getText()->getWidth(MAKE_RESOURCE(kResourcePackText, 3681 + (_item->keywords[index] & KEYWORD_MASK))))
|
|
&& mousePos.y >= y && mousePos.y <= (y + 16))
|
|
return index;
|
|
|
|
++counter;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void Encounter::choose(int32 index) {
|
|
if (_isScriptRunning || index == -1)
|
|
return;
|
|
|
|
if ((_item->keywords[index] & KEYWORD_MASK) && isKeywordVisible(_item->keywords[index])) {
|
|
|
|
_value1 = (_item->keywords[index] & KEYWORD_MASK);
|
|
setVariable(1, _value1);
|
|
|
|
if (strcmp("Goodbye", getText()->get(MAKE_RESOURCE(kResourcePackText, 3681 + _value1))))
|
|
if (_index != 79)
|
|
BYTE1(_item->keywords[index]) |= kKeywordOptionsDisabled;
|
|
|
|
initScript(_item->scriptResourceId);
|
|
runScript();
|
|
}
|
|
}
|
|
|
|
bool Encounter::checkKeywords() const {
|
|
if (_data_455B14 == -1 || _data_455B14 + 1 >= 50)
|
|
return false;
|
|
|
|
for (int32 i = _data_455B14 + 1; i < ARRAYSIZE(_keywordIndexes); i++) {
|
|
int32 index = _keywordIndexes[i];
|
|
|
|
if (index < 0)
|
|
continue;
|
|
|
|
if ((_item->keywords[index] & KEYWORD_MASK) && isKeywordVisible(_item->keywords[index]))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool Encounter::checkKeywords2() const {
|
|
for (uint32 i = 0; i < _keywordStartIndex; i++) {
|
|
int32 index = _keywordIndexes[i];
|
|
|
|
if (index < 0)
|
|
continue;
|
|
|
|
if ((_item->keywords[index] & KEYWORD_MASK) && isKeywordVisible(_item->keywords[index]))
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
void Encounter::updateFromRect(int32 rectIndex) {
|
|
if (rectIndex) {
|
|
if (rectIndex == 1 && (_data_455B14 + 1) < 50) {
|
|
bool cont = false;
|
|
|
|
for (int32 i = _data_455B14 + 1; i < ARRAYSIZE(_keywordIndexes); i++) {
|
|
int32 index = _keywordIndexes[i];
|
|
|
|
if (index < 0)
|
|
continue;
|
|
|
|
if ((_item->keywords[index] & KEYWORD_MASK) && isKeywordVisible(_item->keywords[index])) {
|
|
cont = true;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!cont)
|
|
return;
|
|
|
|
uint32 counter = 0;
|
|
for (uint32 i = _keywordStartIndex + 1; i < ARRAYSIZE(_keywordIndexes); i++) {
|
|
int32 index = _keywordIndexes[i];
|
|
|
|
if (counter == 3)
|
|
break;
|
|
|
|
if (index < 0)
|
|
continue;
|
|
|
|
if ((_item->keywords[index] & KEYWORD_MASK) && isKeywordVisible(_item->keywords[index])) {
|
|
_keywordStartIndex = i;
|
|
++counter;
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
uint32 counter = 0;
|
|
for (int32 i = (int32)_keywordStartIndex - 1; i > -1; i--) {
|
|
int32 index = _keywordIndexes[i];
|
|
|
|
if (counter == 3)
|
|
break;
|
|
|
|
if (index < 0)
|
|
continue;
|
|
|
|
if ((_item->keywords[index] & KEYWORD_MASK) && isKeywordVisible(_item->keywords[index])) {
|
|
_keywordStartIndex = (uint32)i;
|
|
++counter;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Speech
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Encounter::resetSpeech(int16 keywordIndex, int16 a2) {
|
|
getSpeech()->resetTextData();
|
|
setupPortraits();
|
|
|
|
_data_455BCC = false;
|
|
_data_455B3C = 1;
|
|
|
|
if (keywordIndex) {
|
|
getSpeech()->setTextResourceId(keywordIndex + a2);
|
|
setupSpeechText();
|
|
}
|
|
}
|
|
|
|
void Encounter::setupPortraits() {
|
|
_portrait1.transTableMax = 3;
|
|
_portrait2.transTableMax = 0;
|
|
setupSpeechData('N', &_portrait1);
|
|
setupSpeechData('N', &_portrait2);
|
|
}
|
|
|
|
void Encounter::setupSpeechData(char val, EncounterGraphic *encounterGraphic) const {
|
|
switch (val) {
|
|
default:
|
|
break;
|
|
|
|
case 'N':
|
|
encounterGraphic->frameIndex = 0;
|
|
break;
|
|
|
|
case 'H':
|
|
encounterGraphic->frameIndex = 1;
|
|
break;
|
|
|
|
case 'E':
|
|
encounterGraphic->frameIndex = 2;
|
|
break;
|
|
|
|
case 'S':
|
|
encounterGraphic->frameIndex = 3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Encounter::setupSpeechText() {
|
|
setupSpeechData('N', &_portrait1);
|
|
setupSpeechData('N', &_portrait2);
|
|
|
|
char *text = getText()->get(getSpeech()->getTextResourceId());
|
|
|
|
if (*text == '{') {
|
|
_portrait1.transTableMax = 3;
|
|
_portrait2.transTableMax = 0;
|
|
|
|
getSpeech()->setTextData(text + 3);
|
|
getSpeech()->setTextDataPos(NULL);
|
|
|
|
setupSpeech(getSpeech()->getTextResourceId(), getWorld()->font1);
|
|
} else {
|
|
_portrait1.transTableMax = 0;
|
|
_portrait2.transTableMax = 3;
|
|
|
|
getSpeech()->setTextData(NULL);
|
|
getSpeech()->setTextDataPos(text);
|
|
if (*text == '/')
|
|
getSpeech()->setTextDataPos(text + 2);
|
|
|
|
setupSpeech(getSpeech()->getTextResourceId(), getWorld()->font3);
|
|
}
|
|
|
|
_data_455BCC = false;
|
|
_data_455B3C = 1;
|
|
}
|
|
|
|
void Encounter::setupSpeech(ResourceId textResourceId, ResourceId fontResourceId) {
|
|
getText()->loadFont(fontResourceId);
|
|
|
|
char *text = getText()->get(textResourceId);
|
|
|
|
if (*text == '{') {
|
|
_data_455BDC = true;
|
|
setupEntities(true);
|
|
setupSpeechData(text[1], &_portrait1);
|
|
} else {
|
|
_data_455BDC = false;
|
|
setupEntities(false);
|
|
if (*text == '/') {
|
|
char *c = text + 1;
|
|
while (*c != ' ') {
|
|
setupSpeechData(*(c + 1), &_portrait2);
|
|
c++;
|
|
}
|
|
}
|
|
}
|
|
|
|
_data_455BE0 = true;
|
|
_soundResourceId = MAKE_RESOURCE(kResourcePackSharedSound, textResourceId - _speechResourceId);
|
|
//_soundResourceId = MAKE_RESOURCE(kResourcePackSpeech, textResourceId - _speechResourceId); // todo replace with speech (this is being override by the actor speechs)
|
|
//getSpeech()->setSoundResourceId(MAKE_RESOURCE(kResourcePackSpeech, textResourceId - _speechResourceId));
|
|
}
|
|
|
|
bool Encounter::setupSpeechTest(ResourceId id) {
|
|
getSpeech()->setTick(0);
|
|
_soundResourceId = kResourceNone; // TODO replace with speech (this is being override by the actor speechs)
|
|
//getSpeech()->setSoundResourceId(kResourceNone);
|
|
|
|
setupEntities(false);
|
|
|
|
if (id == kResourceNone)
|
|
id = getSpeech()->getTextResourceId();
|
|
|
|
char *text = getText()->get(id);
|
|
if (text[strlen(text) - 1] == 1) {
|
|
setupEntities(true);
|
|
getSpeech()->setTextResourceId(kResourceNone);
|
|
getSpeech()->setTextData(NULL);
|
|
getSpeech()->setTextDataPos(NULL);
|
|
|
|
_data_455BCC = false;
|
|
_data_455B3C = 1;
|
|
|
|
setupPortraits();
|
|
|
|
return false;
|
|
}
|
|
|
|
getSpeech()->setTextResourceId(getSpeech()->getTextResourceId() + 1);
|
|
setupSpeechText();
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Encounter::isSpeaking() {
|
|
if (!_isScriptRunning)
|
|
return false;
|
|
|
|
if (_soundResourceId/*getSpeech()->getSoundResourceId()*/ != kResourceNone && getSound()->isPlaying(_soundResourceId/*getSpeech()->getSoundResourceId()*/)) { // TODO replace with speech
|
|
getSound()->stopAll(_soundResourceId);
|
|
return true;
|
|
}
|
|
|
|
if (getSpeech()->getTick()) {
|
|
getSpeech()->setTick(_vm->getTick());
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Drawing
|
|
//////////////////////////////////////////////////////////////////////////
|
|
bool Encounter::drawBackground() {
|
|
if (Config.performance > 1) {
|
|
if (_vm->isGameFlagSet(kGameFlag528)) {
|
|
Common::Point origin;
|
|
|
|
getScreen()->addGraphicToQueueCrossfade(_background.resourceId,
|
|
_background.frameIndex,
|
|
_point,
|
|
getWorld()->getObjectById(kObjectCave)->getResourceId(),
|
|
origin,
|
|
(uint32)_background.transTableNum);
|
|
} else {
|
|
Common::Point origin(getWorld()->xLeft, getWorld()->yTop);
|
|
|
|
getScreen()->addGraphicToQueueCrossfade(_background.resourceId,
|
|
_background.frameIndex,
|
|
_point,
|
|
getWorld()->backgroundImage,
|
|
origin,
|
|
(uint32)_background.transTableNum);
|
|
}
|
|
} else {
|
|
getScreen()->draw(_background.resourceId, _background.frameIndex, _point);
|
|
}
|
|
|
|
if (_shouldCloseBackground) {
|
|
if (_background.frameIndex == 0)
|
|
exitEncounter();
|
|
else
|
|
--_background.frameIndex;
|
|
|
|
return false;
|
|
}
|
|
|
|
if (_background.frameIndex < _background.frameCount - 1) {
|
|
++_background.frameIndex;
|
|
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
bool Encounter::drawPortraits() {
|
|
bool ret = true;
|
|
|
|
if (_shouldCloseDialog) {
|
|
_portrait1.transTableMax = 0;
|
|
_portrait2.transTableMax = 0;
|
|
}
|
|
|
|
// Portrait 1
|
|
if (_portrait1.transTableNum == 3)
|
|
getScreen()->draw(_portrait1.resourceId,
|
|
_portrait1.frameIndex,
|
|
_point + Common::Point(5, 5));
|
|
else
|
|
getScreen()->drawTransparent(_portrait1.resourceId,
|
|
_portrait1.frameIndex,
|
|
_point + Common::Point(5, 5),
|
|
kDrawFlagNone,
|
|
(uint32)_portrait1.transTableNum);
|
|
|
|
if (_portrait1.transTableNum != _portrait1.transTableMax) {
|
|
if (_portrait1.transTableNum <= _portrait1.transTableMax)
|
|
++_portrait1.transTableNum;
|
|
else
|
|
--_portrait1.transTableNum;
|
|
|
|
ret = false;
|
|
}
|
|
|
|
if (_portrait1.speech0) {
|
|
if (_portrait1.speech0 == 1)
|
|
++_portrait1.frameIndex;
|
|
else
|
|
--_portrait1.frameIndex;
|
|
|
|
_portrait1.frameIndex %= _portrait1.frameCount;
|
|
}
|
|
|
|
// Portrait 2
|
|
Common::Rect frameRect = GraphicResource::getFrameRect(_vm, _portrait2.resourceId, _portrait2.frameIndex);
|
|
|
|
if (_portrait2.transTableNum == 3)
|
|
getScreen()->draw(_portrait2.resourceId,
|
|
_portrait2.frameIndex,
|
|
Common::Point(_point.x + _background.rect.width() - (frameRect.width() + 6), _point.y + 5));
|
|
else
|
|
getScreen()->drawTransparent(_portrait2.resourceId,
|
|
_portrait2.frameIndex,
|
|
Common::Point(_point.x + _background.rect.width() - (frameRect.width() + 6), _point.y + 5),
|
|
kDrawFlagNone,
|
|
(uint32)_portrait2.transTableNum);
|
|
|
|
if (_portrait2.transTableNum != _portrait2.transTableMax) {
|
|
if (_portrait2.transTableNum <= _portrait2.transTableMax)
|
|
++_portrait2.transTableNum;
|
|
else
|
|
--_portrait2.transTableNum;
|
|
|
|
ret = false;
|
|
}
|
|
|
|
if (_portrait2.speech0) {
|
|
if (_portrait2.speech0 == 1)
|
|
++_portrait2.frameIndex;
|
|
else
|
|
--_portrait2.frameIndex;
|
|
|
|
_portrait2.frameIndex %= _portrait2.frameCount;
|
|
}
|
|
|
|
if (_shouldCloseDialog)
|
|
if (_portrait1.transTableNum == _portrait1.transTableMax
|
|
&& _portrait2.transTableNum == _portrait2.transTableMax)
|
|
_shouldCloseBackground = true;
|
|
|
|
return ret;
|
|
}
|
|
|
|
void Encounter::drawStructs() {
|
|
// Drawing structure 1
|
|
if (_drawingStructs[0].transTableNum < -1 || _drawingStructs[0].transTableNum > 3)
|
|
error("[Encounter::drawStructs] Something got <redacted> wrong!");
|
|
|
|
if (checkKeywords2() || _drawingStructs[0].transTableNum > -1) {
|
|
int32 val = _drawingStructs[0].transTableNum;
|
|
|
|
if (_shouldCloseDialog
|
|
&& _drawingStructs[0].status != 2
|
|
&& _drawingStructs[0].transTableNum > -1) {
|
|
val = _drawingStructs[0].transTableNum - 1;
|
|
_drawingStructs[0].status = 2;
|
|
--_drawingStructs[0].transTableNum;
|
|
}
|
|
|
|
switch (val) {
|
|
default:
|
|
break;
|
|
|
|
case -1:
|
|
getScreen()->drawTransparent(_drawingStructs[0].resourceId,
|
|
_drawingStructs[0].frameIndex,
|
|
_drawingStructs[0].point2,
|
|
kDrawFlagNone,
|
|
0);
|
|
|
|
_drawingStructs[0].status = 0;
|
|
break;
|
|
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
getScreen()->drawTransparent(_drawingStructs[0].resourceId,
|
|
_drawingStructs[0].frameIndex,
|
|
_drawingStructs[0].point2,
|
|
kDrawFlagNone,
|
|
(uint32)val);
|
|
|
|
if (_drawingStructs[0].status == 1)
|
|
++_drawingStructs[0].transTableNum;
|
|
else if (_drawingStructs[0].status == 2)
|
|
--_drawingStructs[0].transTableNum;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
getScreen()->draw(_drawingStructs[0].resourceId,
|
|
_drawingStructs[0].frameIndex,
|
|
_drawingStructs[0].point2);
|
|
|
|
_drawingStructs[0].status = 0;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Drawing structure 2
|
|
if (_drawingStructs[1].transTableNum < -1 || _drawingStructs[1].transTableNum > 3)
|
|
error("[Encounter::drawStructs] Something got <redacted> wrong!");
|
|
|
|
if (checkKeywords() || _drawingStructs[1].transTableNum > -1) {
|
|
int32 val = _drawingStructs[1].transTableNum;
|
|
|
|
if (_shouldCloseDialog
|
|
&& _drawingStructs[1].status != 2
|
|
&& _drawingStructs[1].transTableNum > -1) {
|
|
val = _drawingStructs[1].transTableNum - 1;
|
|
_drawingStructs[1].status = 2;
|
|
--_drawingStructs[1].transTableNum;
|
|
}
|
|
|
|
switch (val) {
|
|
default:
|
|
break;
|
|
|
|
case -1:
|
|
getScreen()->drawTransparent(_drawingStructs[1].resourceId,
|
|
_drawingStructs[1].frameIndex,
|
|
_drawingStructs[1].point2,
|
|
kDrawFlagNone,
|
|
0);
|
|
|
|
_drawingStructs[1].status = 0;
|
|
break;
|
|
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
getScreen()->drawTransparent(_drawingStructs[1].resourceId,
|
|
_drawingStructs[1].frameIndex,
|
|
_drawingStructs[1].point2,
|
|
kDrawFlagNone,
|
|
(uint32)val);
|
|
|
|
if (_drawingStructs[1].status == 1)
|
|
++_drawingStructs[1].transTableNum;
|
|
else if (_drawingStructs[1].status == 2)
|
|
--_drawingStructs[1].transTableNum;
|
|
|
|
break;
|
|
|
|
case 3:
|
|
getScreen()->draw(_drawingStructs[1].resourceId,
|
|
_drawingStructs[1].frameIndex,
|
|
_drawingStructs[1].point2);
|
|
|
|
_drawingStructs[1].status = 0;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Encounter::drawDialogOptions() {
|
|
getText()->loadFont(getWorld()->font1);
|
|
|
|
int16 counter = 0;
|
|
|
|
for (uint32 i = _keywordStartIndex; i < ARRAYSIZE(_keywordIndexes); i++) {
|
|
if (counter / 3 >= 8)
|
|
return;
|
|
|
|
int32 keywordIndex = _keywordIndexes[i];
|
|
if (keywordIndex < 0)
|
|
continue;
|
|
|
|
int16 keyword = _item->keywords[keywordIndex];
|
|
if ((keyword & KEYWORD_MASK) > 0 && isKeywordVisible(keyword)) {
|
|
|
|
if (isKeywordDisabled(keyword))
|
|
getText()->loadFont(getWorld()->font2);
|
|
else
|
|
getText()->loadFont(getWorld()->font1);
|
|
|
|
Common::Point coords(_drawingStructs[0].point1.y + 145 * (counter % 3) + _point.x + (counter % 3) + _portrait1.rect.width() + 15,
|
|
_point.y + (int16)(16 * (counter / 3)));
|
|
|
|
if (getKeywordIndex() == keywordIndex)
|
|
getScreen()->fillRect(coords.x - 1, coords.y + 5, getText()->getWidth(MAKE_RESOURCE(kResourcePackText, 3681 + (keyword & KEYWORD_MASK))) + 2, 18, 0);
|
|
|
|
getText()->setPosition(coords);
|
|
getText()->draw(MAKE_RESOURCE(kResourcePackText, 3681 + (keyword & KEYWORD_MASK)));
|
|
|
|
++counter;
|
|
_data_455B14 = i;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Encounter::drawSubtitle(char *text, ResourceId font, int16 y) {
|
|
if (!text)
|
|
return;
|
|
|
|
int16 width = _background.rect.width() - (_portrait1.rect.width() + _portrait2.rect.width() + 20);
|
|
int16 x = _point.x + _portrait1.rect.width() + 10;
|
|
|
|
getText()->loadFont(font);
|
|
|
|
if (_data_455BCC) {
|
|
if (_data_455B3C != 1 && _tick < _vm->getTick()) {
|
|
_tick = _vm->getTick() + 1000 * (getResource()->get(_soundResourceId/*getSpeech()->getSoundResourceId()*/)->size / 11025) / (uint16)_data_455B3C; // TODO replace with speech
|
|
|
|
if ((_data_455BF0 + 8) < _data_455B70)
|
|
_data_455BF0 += 8;
|
|
}
|
|
} else {
|
|
_data_455BCC = true;
|
|
_data_455B70 = getText()->draw(kTextCalculate, Common::Point(x, y), 16, width, text);
|
|
_data_455B3C = _data_455B70 / 8 + 1;
|
|
_data_455BF0 = 0;
|
|
_tick = _vm->getTick() + 1000 * (getResource()->get(_soundResourceId/*getSpeech()->getSoundResourceId()*/)->size / 11025) / (uint16)_data_455B3C; // TODO replace with speech
|
|
}
|
|
|
|
getText()->draw(_data_455BF0, 7, kTextCenter, Common::Point(x, y), 16, width, text);
|
|
}
|
|
|
|
void Encounter::drawScreen() {
|
|
getScene()->getActor()->setLastScreenUpdate(_vm->screenUpdateCount);
|
|
|
|
if (!getSharedData()->getMatteInitialized())
|
|
getSharedData()->setMatteBarHeight(85);
|
|
|
|
if (getSharedData()->getMatteBarHeight() >= 84) {
|
|
if (getSharedData()->getMatteBarHeight() == 85) {
|
|
if (getSharedData()->getMatteInitialized()) {
|
|
getScreen()->drawWideScreenBars(82);
|
|
|
|
getScreen()->updatePalette();
|
|
getScreen()->setupPalette(NULL, 0, 0);
|
|
getScreen()->paletteFade(0, 25, 10);
|
|
} else {
|
|
getSharedData()->setMatteInitialized(true);
|
|
getScreen()->clear();
|
|
}
|
|
|
|
if (getSharedData()->getMatteVar1()) {
|
|
if (!getSharedData()->getMatteVar2())
|
|
getSound()->playMusic(kResourceNone, 0);
|
|
|
|
// Play movie
|
|
getScreen()->clear();
|
|
getVideo()->play(getSharedData()->movieIndex, getSharedData()->getFlag(kFlagIsEncounterRunning) ? (EventHandler*)this : getScene());
|
|
getScreen()->clearGraphicsInQueue();
|
|
getScreen()->clear();
|
|
getCursor()->hide();
|
|
|
|
if (getSharedData()->getMattePlaySound()) {
|
|
getScreen()->paletteFade(0, 2, 1);
|
|
getScene()->updateScreen();
|
|
getScreen()->drawWideScreenBars(82);
|
|
|
|
getScreen()->updatePalette(0);
|
|
getScreen()->setupPalette(NULL, 0, 0);
|
|
|
|
if (getSharedData()->getMattePlaySound() /* Scene::updateScreen() does script processing, so the value might have changed */
|
|
&& !getSharedData()->getMatteVar2()
|
|
&& getWorld()->musicCurrentResourceIndex != kMusicStopped)
|
|
getSound()->playMusic(MAKE_RESOURCE(kResourcePackMusic, getWorld()->musicCurrentResourceIndex));
|
|
}
|
|
|
|
getSharedData()->setMatteBarHeight(getSharedData()->getMattePlaySound() ? 346 : 170);
|
|
} else {
|
|
getSharedData()->setMatteBarHeight(170);
|
|
}
|
|
} else if (getSharedData()->getMatteBarHeight() >= 170) {
|
|
if (getSharedData()->getFlag(kFlagIsEncounterRunning)) {
|
|
getSharedData()->setMatteBarHeight(0);
|
|
getCursor()->show();
|
|
}
|
|
} else {
|
|
getScreen()->drawWideScreenBars(172 - getSharedData()->getMatteBarHeight());
|
|
getSharedData()->setMatteBarHeight(getSharedData()->getMatteBarHeight() + 4);
|
|
|
|
ResourceId paletteId = getWorld()->actions[getScene()->getActor()->getActionIndex3()]->paletteResourceId;
|
|
getScreen()->setPaletteGamma(paletteId ? paletteId : getWorld()->currentPaletteId);
|
|
|
|
updatePalette1();
|
|
getScreen()->setupPalette(NULL, 0, 0);
|
|
}
|
|
} else {
|
|
getScreen()->drawWideScreenBars(getSharedData()->getMatteBarHeight());
|
|
getSharedData()->setMatteBarHeight(getSharedData()->getMatteBarHeight() + 4);
|
|
|
|
getScreen()->setPaletteGamma(getWorld()->currentPaletteId);
|
|
|
|
updatePalette2();
|
|
getScreen()->setupPalette(NULL, 0, 0);
|
|
}
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Misc
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Encounter::setupEntities(bool type4) {
|
|
// Actor
|
|
if (_actorIndex) {
|
|
Actor *actor = getScene()->getActor(_actorIndex);
|
|
|
|
if (actor->isDefaultDirection(20))
|
|
actor->updateStatus(type4 ? kActorStatusDisabled : kActorStatus8);
|
|
|
|
return;
|
|
}
|
|
|
|
// Objects
|
|
if (_objectId1 == _objectId2)
|
|
return;
|
|
|
|
if (_index == 37) {
|
|
if (getVariable(3)) {
|
|
if (getVariable(3) == 1 && _vm->isGameFlagNotSet(kGameFlag470)) {
|
|
getWorld()->getObjectById(type4 ? kObjectNPC026Talking : kObjectNPC026TalkStatusQuo)->disable();
|
|
getWorld()->getObjectById(type4 ? kObjectNPC026TalkStatusQuo : kObjectNPC026Talking)->setNextFrame(getWorld()->getObjectById(type4 ? kObjectNPC026TalkStatusQuo : kObjectNPC026Talking)->flags);
|
|
}
|
|
} else {
|
|
getWorld()->getObjectById(type4 ? _objectId1 : _objectId2)->disable();
|
|
getWorld()->getObjectById(type4 ? _objectId2 : _objectId1)->setNextFrame(getWorld()->getObjectById(type4 ? _objectId2 : _objectId1)->flags);
|
|
}
|
|
} else {
|
|
if (type4) {
|
|
getWorld()->getObjectById(_objectId1)->disable();
|
|
getWorld()->getObjectById(_objectId2)->setNextFrame(getWorld()->getObjectById(_objectId2)->flags);
|
|
} else {
|
|
if (_index == 5) {
|
|
if (!_vm->isGameFlagSet(kGameFlag262)) {
|
|
getWorld()->getObjectById(kObjectMariaPointsLeft)->disable();
|
|
getWorld()->getObjectById(_objectId2)->disable();
|
|
|
|
_objectId1 = kObjectMariaPointsRight;
|
|
getWorld()->getObjectById(_objectId1)->setNextFrame(getWorld()->getObjectById(_objectId1)->flags);
|
|
} else {
|
|
getWorld()->getObjectById(_objectId1)->disable();
|
|
getWorld()->getObjectById(_objectId2)->disable();
|
|
|
|
_objectId1 = kObjectMariaPointsLeft;
|
|
getWorld()->getObjectById(_objectId1)->setNextFrame(getWorld()->getObjectById(_objectId1)->flags);
|
|
}
|
|
} else {
|
|
getWorld()->getObjectById(_objectId2)->disable();
|
|
getWorld()->getObjectById(_objectId1)->setNextFrame(getWorld()->getObjectById(_objectId1)->flags);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int32 Encounter::findRect() {
|
|
Common::Point mousePos = getCursor()->position();
|
|
|
|
for (uint32 i = 0; i < ARRAYSIZE(_drawingStructs); i++) {
|
|
EncounterDrawingStruct *drawStruct = &_drawingStructs[i];
|
|
|
|
if (mousePos.x >= drawStruct->point2.x
|
|
&& mousePos.x < (drawStruct->point2.x + drawStruct->point1.y)
|
|
&& mousePos.y >= drawStruct->point2.y
|
|
&& mousePos.y < (drawStruct->point2.y + drawStruct->point1.x))
|
|
return i;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
void Encounter::updateDrawingStatus() {
|
|
if (checkKeywords2()) {
|
|
if (_rectIndex) {
|
|
if (_drawingStructs[0].transTableNum == -1) {
|
|
_drawingStructs[0].status = 1;
|
|
_drawingStructs[0].transTableNum = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (_drawingStructs[0].transTableNum == 3) {
|
|
_drawingStructs[0].status = 2;
|
|
_drawingStructs[0].transTableNum = 2;
|
|
}
|
|
}
|
|
|
|
if (checkKeywords()) {
|
|
if (_rectIndex != 1) {
|
|
if (_drawingStructs[1].transTableNum == -1) {
|
|
_drawingStructs[1].status = 1;
|
|
_drawingStructs[1].transTableNum = 0;
|
|
}
|
|
}
|
|
} else {
|
|
if (_drawingStructs[1].transTableNum == 3) {
|
|
_drawingStructs[1].status = 2;
|
|
_drawingStructs[1].transTableNum = 2;
|
|
}
|
|
}
|
|
}
|
|
|
|
void Encounter::updateDrawingStatus1(int32 rectIndex) {
|
|
switch (rectIndex) {
|
|
default:
|
|
error("[Encounter::updateDrawingStatus1] Invalid rect index (%d)", rectIndex);
|
|
break;
|
|
|
|
case 0:
|
|
if (checkKeywords2()) {
|
|
_drawingStructs[rectIndex].status = 1;
|
|
++_drawingStructs[rectIndex].transTableNum;
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (checkKeywords()) {
|
|
_drawingStructs[rectIndex].status = 1;
|
|
++_drawingStructs[rectIndex].transTableNum;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void Encounter::updateDrawingStatus2(int32 rectIndex) {
|
|
switch (rectIndex) {
|
|
default:
|
|
error("[Encounter::updateDrawingStatus1] Invalid rect index (%d)", rectIndex);
|
|
break;
|
|
|
|
case 0:
|
|
if (checkKeywords2()) {
|
|
_drawingStructs[rectIndex].status = 2;
|
|
--_drawingStructs[rectIndex].transTableNum;
|
|
updateFromRect(rectIndex);
|
|
}
|
|
break;
|
|
|
|
case 1:
|
|
if (checkKeywords()) {
|
|
_drawingStructs[rectIndex].status = 2;
|
|
--_drawingStructs[rectIndex].transTableNum;
|
|
updateFromRect(rectIndex);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
bool Encounter::updateScreen() {
|
|
if (getScene()->updateScreen())
|
|
return true;
|
|
|
|
getText()->loadFont(getWorld()->font1);
|
|
|
|
if (!drawBackground()) {
|
|
_isDialogOpen = false;
|
|
return false;
|
|
}
|
|
|
|
if (!drawPortraits()) {
|
|
_isDialogOpen = false;
|
|
|
|
if (_shouldCloseDialog)
|
|
drawStructs();
|
|
|
|
return false;
|
|
}
|
|
|
|
if (_isDialogOpen) {
|
|
|
|
if (!getSpeech()->getTextDataPos() && !getSpeech()->getTextData()) {
|
|
|
|
drawDialogOptions();
|
|
updateDrawingStatus();
|
|
drawStructs();
|
|
|
|
if (_rectIndex != -1 && findRect() == _rectIndex)
|
|
updateFromRect(_rectIndex);
|
|
|
|
return false;
|
|
}
|
|
|
|
if (Config.showEncounterSubtitles) {
|
|
drawSubtitle(getSpeech()->getTextDataPos(), getWorld()->font3, _point.y);
|
|
drawSubtitle(getSpeech()->getTextData(), getWorld()->font1, _point.y);
|
|
}
|
|
|
|
if (_data_455BE0) {
|
|
_data_455BE0 = false;
|
|
|
|
// Check resources
|
|
if (!_data_455BDC && !_objectId1 && !_objectId2 && !_actorIndex)
|
|
error("[Encounter::updateScreen] Invalid encounter resources!");
|
|
|
|
getSound()->playSound(_soundResourceId/*getSpeech()->getSoundResourceId()*/, false, Config.voiceVolume); // TODO replace with speech
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
if (_objectId3 || _data_455BE8)
|
|
return false;
|
|
|
|
if (!_data_455BF4)
|
|
_data_455BF4 = 1;
|
|
|
|
_isDialogOpen = true;
|
|
|
|
return false;
|
|
}
|
|
|
|
void Encounter::updatePalette1() {
|
|
debugC(kDebugLevelEncounter, "[Encounter::updatePalette1] Not implemented!");
|
|
}
|
|
|
|
void Encounter::updatePalette2() {
|
|
debugC(kDebugLevelEncounter, "[Encounter::updatePalette2] Not implemented!");
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// Scripts
|
|
//////////////////////////////////////////////////////////////////////////
|
|
void Encounter::initScript(ResourceId resourceId) {
|
|
_scriptData.reset(resourceId);
|
|
_isClosing = false;
|
|
}
|
|
|
|
Encounter::ScriptEntry Encounter::getScriptEntry(ResourceId resourceId, uint32 offset) {
|
|
ResourceEntry *entry = getResource()->get(resourceId);
|
|
return ScriptEntry(entry->data + offset * 4);
|
|
}
|
|
|
|
void Encounter::runScript() {
|
|
_isScriptRunning = true;
|
|
bool done = false;
|
|
|
|
do {
|
|
ScriptEntry entry = getScriptEntry(_scriptData.resourceId, _scriptData.offset);
|
|
|
|
debugC(kDebugLevelEncounter, "[Encounter] %s", entry.toString().c_str());
|
|
|
|
switch (entry.opcode) {
|
|
default:
|
|
break;
|
|
|
|
case kOpcodeEncounterReturn:
|
|
_isScriptRunning = false;
|
|
done = true;
|
|
_value1 = 0;
|
|
break;
|
|
|
|
case kOpcodeSetScriptVariable:
|
|
_scriptData.vars[entry.param1] = getVariableInv(entry.param2);
|
|
break;
|
|
|
|
case kOpcodeSetCounterFromVars:
|
|
_scriptData.counter = _scriptData.vars[entry.param1] - getVariableInv(entry.param2);
|
|
break;
|
|
|
|
case kOpcodeSetOffset:
|
|
_scriptData.offset = entry.param2 - 1;
|
|
break;
|
|
|
|
case kOpcodeSetOffsetIfCounterNegative:
|
|
if (_scriptData.counter >= 0)
|
|
break;
|
|
|
|
_scriptData.offset = entry.param2 - 1;
|
|
break;
|
|
|
|
case kOpcodeSetOffsetIfCounterNegativeOrNull:
|
|
if (_scriptData.counter > 0)
|
|
break;
|
|
|
|
_scriptData.offset = entry.param2 - 1;
|
|
break;
|
|
|
|
case kOpcodeSetOffsetIfCounterIsNull:
|
|
if (_scriptData.counter)
|
|
break;
|
|
|
|
_scriptData.offset = entry.param2 - 1;
|
|
break;
|
|
|
|
case kOpcodeSetOffsetIfCounterIsNotNull:
|
|
if (!_scriptData.counter)
|
|
break;
|
|
|
|
_scriptData.offset = entry.param2 - 1;
|
|
break;
|
|
|
|
case kOpcodeSetOffsetIfCounterPositiveOrNull:
|
|
if (_scriptData.counter < 0)
|
|
break;
|
|
|
|
_scriptData.offset = entry.param2 - 1;
|
|
break;
|
|
|
|
case kOpcodeSetOffsetIfCounterPositive:
|
|
if (_scriptData.counter <= 0)
|
|
break;
|
|
|
|
_scriptData.offset = entry.param2 - 1;
|
|
break;
|
|
|
|
case kOpcodeSetCurrentItemOptions:
|
|
if (entry.param1)
|
|
_item->keywords[findKeyword(_item, entry.param2)] &= -((kKeywordOptionsDisabled << 8) + 1);
|
|
else
|
|
_item->keywords[findKeyword(_item, entry.param2)] |= (kKeywordOptionsVisible << 8);
|
|
break;
|
|
|
|
case kOpcodeClearCurrentItemOptions:
|
|
if (entry.param1)
|
|
_item->keywords[findKeyword(_item, entry.param2)] |= (kKeywordOptionsDisabled << 8);
|
|
else
|
|
_item->keywords[findKeyword(_item, entry.param2)] &= -((kKeywordOptionsVisible << 8) + 1);
|
|
break;
|
|
|
|
case kOpcodeSetItemOptions:
|
|
_items[entry.param1].keywords[findKeyword(&_items[entry.param1], entry.param2)] |= (kKeywordOptionsUnknown << 8);
|
|
_items[entry.param1].keywords[findKeyword(&_items[entry.param1], entry.param2)] |= (kKeywordOptionsVisible << 8);
|
|
|
|
// Original saves the item back here
|
|
break;
|
|
|
|
case kOpcodeCloseDialog:
|
|
if (!_isClosing)
|
|
_shouldCloseDialog = true;
|
|
|
|
done = true;
|
|
break;
|
|
|
|
case kOpcodeResetSpeech:
|
|
resetSpeech(_item->speechResourceId, getVariableInv(entry.param2));
|
|
|
|
done = true;
|
|
break;
|
|
|
|
case kOpcodeSetVariable:
|
|
setVariable(entry.param2, (int16)_scriptData.vars[entry.param1]);
|
|
break;
|
|
|
|
case kOpcodeIncrementScriptVariable:
|
|
_scriptData.vars[entry.param1] += entry.param2;
|
|
break;
|
|
|
|
case kOpcodeProcessVariable3:
|
|
switch (getVariable(3)) {
|
|
default:
|
|
break;
|
|
|
|
case 13:
|
|
case 15:
|
|
if (_actorIndex) {
|
|
getScene()->getActor(_actorIndex)->hide();
|
|
} else {
|
|
getWorld()->getObjectById(_objectId1)->disable();
|
|
getWorld()->getObjectById(_objectId2)->disable();
|
|
}
|
|
|
|
if (getVariable(3) == 13)
|
|
break;
|
|
// fallthrough
|
|
|
|
case 14:
|
|
getScene()->getActor()->hide(); // Hide player
|
|
break;
|
|
|
|
case 16: {
|
|
Object *obj = getWorld()->getObjectById((ObjectId)getVariableInv(entry.param2));
|
|
obj->setNextFrame(obj->flags);
|
|
_data_455BF4 = 1;
|
|
done = true;
|
|
}
|
|
break;
|
|
|
|
case 17:
|
|
getWorld()->getObjectById((ObjectId)getVariableInv(entry.param2))->setNextFrame(32);
|
|
_data_455BF4 = 1;
|
|
done = true;
|
|
break;
|
|
|
|
case 18:
|
|
getWorld()->getObjectById((ObjectId)getVariableInv(entry.param2))->setNextFrame(512);
|
|
_data_455BF4 = 1;
|
|
done = true;
|
|
break;
|
|
}
|
|
|
|
if (!done) {
|
|
_objectId3 = (ObjectId)getVariableInv(entry.param2);
|
|
getWorld()->getObjectById(_objectId3)->setNextFrame(8);
|
|
getCursor()->hide();
|
|
done = true;
|
|
}
|
|
break;
|
|
|
|
case kOpcodeAddRemoveInventoryItem:
|
|
if (entry.param1)
|
|
getScene()->getActor()->inventory.remove(getVariableInv(entry.param2), _scriptData.vars[1]);
|
|
else
|
|
getScene()->getActor()->inventory.add(getVariableInv(entry.param2), _scriptData.vars[1]);
|
|
break;
|
|
|
|
case kOpcodeSetCounterIfInventoryOmits:
|
|
_scriptData.counter = getScene()->getActor()->inventory.contains(getVariableInv(entry.param2), _scriptData.vars[1]) ? 0 : 1;
|
|
break;
|
|
|
|
case kOpcodePrepareMovie:
|
|
if (!getSharedData()->getMatteBarHeight()) {
|
|
getScreen()->loadGrayPalette();
|
|
getSharedData()->setMatteBarHeight(1);
|
|
getSharedData()->movieIndex = (uint16)getVariableInv(entry.param2);
|
|
getSharedData()->setMatteVar1(1);
|
|
getSharedData()->setMattePlaySound(true);
|
|
getSharedData()->setMatteInitialized(true);
|
|
getSharedData()->setMatteVar2(0);
|
|
done = true;
|
|
}
|
|
|
|
if (!_data_455BE8) {
|
|
_data_455BE8 = true;
|
|
getCursor()->hide();
|
|
}
|
|
break;
|
|
|
|
case kOpcodeSetClearGameFlag:
|
|
if (entry.param1)
|
|
_vm->setGameFlag((GameFlag)getVariableInv(entry.param2));
|
|
else
|
|
_vm->clearGameFlag((GameFlag)getVariableInv(entry.param2));
|
|
break;
|
|
|
|
case kOpcodeSetCounterFromGameFlag:
|
|
_scriptData.counter = _vm->isGameFlagSet((GameFlag)getVariableInv(entry.param2)) ? 1 : 0;
|
|
break;
|
|
}
|
|
|
|
++_scriptData.offset;
|
|
|
|
} while (!done);
|
|
}
|
|
|
|
}
|