mirror of
https://github.com/scummvm/scummvm.git
synced 2025-04-02 10:52:32 -04:00
405 lines
12 KiB
C++
405 lines
12 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 3 of the License, or
|
|
* (at your option) any later version.
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
*
|
|
*/
|
|
|
|
#include "illusions/duckman/illusions_duckman.h"
|
|
#include "illusions/duckman/duckman_credits.h"
|
|
#include "illusions/duckman/duckman_screenshakereffects.h"
|
|
#include "illusions/duckman/duckman_specialcode.h"
|
|
#include "illusions/duckman/duckman_inventory.h"
|
|
#include "illusions/duckman/propertytimers.h"
|
|
#include "illusions/duckman/scriptopcodes_duckman.h"
|
|
#include "illusions/actor.h"
|
|
#include "illusions/dictionary.h"
|
|
#include "illusions/resources/fontresource.h"
|
|
#include "illusions/resources/scriptresource.h"
|
|
#include "illusions/sound.h"
|
|
#include "illusions/specialcode.h"
|
|
#include "illusions/textdrawer.h"
|
|
#include "illusions/time.h"
|
|
#include "illusions/updatefunctions.h"
|
|
|
|
#include "engines/util.h"
|
|
|
|
namespace Illusions {
|
|
|
|
// Duckman_SpecialCode
|
|
|
|
DuckmanSpecialCode::DuckmanSpecialCode(IllusionsEngine_Duckman *vm)
|
|
: _vm(vm) {
|
|
|
|
_propertyTimers = new PropertyTimers(_vm);
|
|
_inventory = new DuckmanInventory(_vm);
|
|
_credits = new DuckmanCredits(_vm);
|
|
|
|
_wasCursorHoldingElvisPoster = false;
|
|
_counter = 0;
|
|
_savedTempMasterSfxVolume = 16;
|
|
_lastRandomSoundIndex = 6;
|
|
}
|
|
|
|
DuckmanSpecialCode::~DuckmanSpecialCode() {
|
|
delete _propertyTimers;
|
|
delete _inventory;
|
|
delete _credits;
|
|
|
|
for (auto &it : _specialCodeMap) {
|
|
delete it._value;
|
|
}
|
|
}
|
|
|
|
typedef Common::Functor1Mem<OpCall&, void, DuckmanSpecialCode> SpecialCodeFunctionDM;
|
|
#define SPECIAL(id, func) _specialCodeMap[id] = new SpecialCodeFunctionDM(this, &DuckmanSpecialCode::func);
|
|
|
|
void DuckmanSpecialCode::init() {
|
|
SPECIAL(0x00160001, spcStartScreenShaker);
|
|
SPECIAL(0x00160002, spcSetCursorHandMode);
|
|
SPECIAL(0x00160003, spcResetChinesePuzzle);
|
|
SPECIAL(0x00160004, spcAddChinesePuzzleAnswer);
|
|
SPECIAL(0x00160005, spcOpenInventory);
|
|
|
|
SPECIAL(0x00160007, spcPutBackInventoryItem);
|
|
SPECIAL(0x00160008, spcClearInventorySlot);
|
|
|
|
SPECIAL(0x0016000A, spcAddPropertyTimer);
|
|
SPECIAL(0x0016000B, spcSetPropertyTimer);
|
|
SPECIAL(0x0016000C, spcRemovePropertyTimer);
|
|
SPECIAL(0x0016000E, spcInitTeleporterPosition);
|
|
SPECIAL(0x0016000F, spcUpdateTeleporterPosition);
|
|
SPECIAL(0x00160010, spcCenterNewspaper);
|
|
SPECIAL(0x00160012, spcStopScreenShaker);
|
|
SPECIAL(0x00160013, spcIncrCounter);
|
|
SPECIAL(0x00160014, spcUpdateObject272Sequence);
|
|
SPECIAL(0x00160017, spcPlayRandomSound);
|
|
SPECIAL(0x0016001A, spcHoldGlowingElvisPoster);
|
|
SPECIAL(0x0016001B, spcStartCredits);
|
|
SPECIAL(0x0016001C, spcSetCursorInventoryMode);
|
|
SPECIAL(0x0016001D, spcCenterCurrentScreenText);
|
|
SPECIAL(0x0016001E, spcSetDefaultTextCoords);
|
|
SPECIAL(0x0016001F, spcSetTextDuration);
|
|
SPECIAL(0x00160020, spcSetTempMasterSfxVolume);
|
|
SPECIAL(0x00160021, spcRestoreTempMasterSfxVolume);
|
|
}
|
|
|
|
#undef SPECIAL
|
|
|
|
void DuckmanSpecialCode::run(uint32 specialCodeId, OpCall &opCall) {
|
|
SpecialCodeMapIterator it = _specialCodeMap.find(specialCodeId);
|
|
if (it != _specialCodeMap.end()) {
|
|
(*(*it)._value)(opCall);
|
|
} else {
|
|
debug("DuckmanSpecialCode::run() Unimplemented special code %08X", specialCodeId);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
error("DuckmanSpecialCode::run() Unimplemented special code");
|
|
}
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcStartScreenShaker(OpCall &opCall) {
|
|
ARG_BYTE(effect);
|
|
const ScreenShakeEffect *shakerEffect = getScreenShakeEffect(effect);
|
|
_vm->startScreenShaker(shakerEffect->_pointsCount, shakerEffect->_duration, shakerEffect->_points, opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcSetCursorHandMode(OpCall &opCall) {
|
|
ARG_BYTE(mode);
|
|
_vm->setCursorHandMode(mode);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcResetChinesePuzzle(OpCall &opCall) {
|
|
_vm->_scriptResource->_properties.set(0x000E0018, false);
|
|
_vm->_scriptResource->_properties.set(0x000E0019, false);
|
|
_chinesePuzzleIndex = 0;
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcAddChinesePuzzleAnswer(OpCall &opCall) {
|
|
ARG_BYTE(answer);
|
|
_chinesePuzzleAnswers[_chinesePuzzleIndex++] = answer;
|
|
if (_chinesePuzzleIndex == 3) {
|
|
_vm->_scriptResource->_properties.set(0x000E0018, true);
|
|
if ((_chinesePuzzleAnswers[0] == 7 && _chinesePuzzleAnswers[1] == 2 && _chinesePuzzleAnswers[2] == 5) ||
|
|
(_chinesePuzzleAnswers[0] == 5 && _chinesePuzzleAnswers[1] == 2 && _chinesePuzzleAnswers[2] == 7))
|
|
_vm->_scriptResource->_properties.set(0x000E0019, true);
|
|
else if ((_chinesePuzzleAnswers[0] == 7 && _chinesePuzzleAnswers[1] == 2 && _chinesePuzzleAnswers[2] == 1) ||
|
|
(_chinesePuzzleAnswers[0] == 1 && _chinesePuzzleAnswers[1] == 2 && _chinesePuzzleAnswers[2] == 7))
|
|
_vm->_scriptResource->_properties.set(0x000E00A0, true);
|
|
}
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcOpenInventory(OpCall &opCall) {
|
|
_inventory->openInventory();
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcPutBackInventoryItem(OpCall &opCall) {
|
|
_inventory->putBackInventoryItem();
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcClearInventorySlot(OpCall &opCall) {
|
|
ARG_UINT32(objectId);
|
|
_inventory->clearInventorySlot(objectId);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcAddPropertyTimer(OpCall &opCall) {
|
|
ARG_UINT32(propertyId);
|
|
_propertyTimers->addPropertyTimer(propertyId);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcSetPropertyTimer(OpCall &opCall) {
|
|
ARG_INT16(propertyNum);
|
|
ARG_INT16(duration);
|
|
_propertyTimers->setPropertyTimer(propertyNum | 0xE0000, duration);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcRemovePropertyTimer(OpCall &opCall) {
|
|
ARG_UINT32(propertyId);
|
|
_propertyTimers->removePropertyTimer(propertyId);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcInitTeleporterPosition(OpCall &opCall) {
|
|
_teleporterPosition.x = 4;
|
|
_teleporterPosition.y = 3;
|
|
updateTeleporterProperties();
|
|
_vm->_scriptResource->_properties.set(0x000E007A, false);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcUpdateTeleporterPosition(OpCall &opCall) {
|
|
ARG_BYTE(direction);
|
|
int16 deltaX = 0;
|
|
int16 deltaY = 0;
|
|
uint32 sequenceId = 0;
|
|
|
|
Control *control = _vm->getObjectControl(0x400C0);
|
|
switch (direction) {
|
|
case 1:
|
|
if (_teleporterPosition.y > 1) {
|
|
deltaY = -1;
|
|
sequenceId = 0x60386;
|
|
}
|
|
break;
|
|
case 4:
|
|
if (_teleporterPosition.x < 4) {
|
|
deltaX = 1;
|
|
sequenceId = 0x60387;
|
|
}
|
|
break;
|
|
case 0x10:
|
|
if (_teleporterPosition.y < 3) {
|
|
deltaY = 1;
|
|
sequenceId = 0x60385;
|
|
}
|
|
break;
|
|
case 0x40:
|
|
if (_teleporterPosition.x > 1) {
|
|
deltaX = -1;
|
|
sequenceId = 0x60388;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
|
|
if (sequenceId) {
|
|
control->startSequenceActor(sequenceId, 2, opCall._threadId);
|
|
_teleporterPosition.x += deltaX;
|
|
_teleporterPosition.y += deltaY;
|
|
updateTeleporterProperties();
|
|
_vm->_scriptResource->_properties.set(0x000E007A, false);
|
|
} else {
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcCenterNewspaper(OpCall &opCall) {
|
|
Control *control = _vm->getObjectControl(0x40017);
|
|
control->_flags |= 8;
|
|
control->_actor->_position.x = 160;
|
|
control->_actor->_position.y = 100;
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcStopScreenShaker(OpCall &opCall) {
|
|
_vm->stopScreenShaker();
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcIncrCounter(OpCall &opCall) {
|
|
ARG_BYTE(maxCount);
|
|
ARG_BYTE(incr);
|
|
_vm->_scriptResource->_properties.set(0x000E0088, false);
|
|
if (incr) {
|
|
_counter += incr;
|
|
if (_counter >= maxCount)
|
|
_vm->_scriptResource->_properties.set(0x000E0088, true);
|
|
} else {
|
|
_counter = 0;
|
|
}
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcUpdateObject272Sequence(OpCall &opCall) {
|
|
byte flags = 0;
|
|
uint32 sequenceId;
|
|
if (_vm->_scriptResource->_properties.get(0x000E0085))
|
|
flags |= 1;
|
|
if (_vm->_scriptResource->_properties.get(0x000E0083))
|
|
flags |= 2;
|
|
if (_vm->_scriptResource->_properties.get(0x000E0084))
|
|
flags |= 4;
|
|
switch (flags) {
|
|
case 0:
|
|
sequenceId = 0x603C1;
|
|
break;
|
|
case 1:
|
|
sequenceId = 0x603BF;
|
|
break;
|
|
case 2:
|
|
sequenceId = 0x603C2;
|
|
break;
|
|
case 3:
|
|
sequenceId = 0x603C0;
|
|
break;
|
|
case 4:
|
|
sequenceId = 0x603C3;
|
|
break;
|
|
case 5:
|
|
sequenceId = 0x603C5;
|
|
break;
|
|
case 6:
|
|
sequenceId = 0x603C4;
|
|
break;
|
|
case 7:
|
|
sequenceId = 0x603C6;
|
|
break;
|
|
default:
|
|
sequenceId = 0x603C1;
|
|
break;
|
|
}
|
|
Control *control = _vm->getObjectControl(0x40110);
|
|
control->startSequenceActor(sequenceId, 2, opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcPlayRandomSound(OpCall &opCall) {
|
|
static const uint32 kRandomSoundIds[] = {
|
|
0x00090084, 0x00090085, 0x00090086, 0x00090087, 0x00090088, 0x00090089
|
|
};
|
|
int16 soundIndex;
|
|
do {
|
|
soundIndex = _vm->getRandom(ARRAYSIZE(kRandomSoundIds));
|
|
} while (soundIndex == _lastRandomSoundIndex);
|
|
_vm->_soundMan->playSound(kRandomSoundIds[soundIndex], 255, 0);
|
|
_lastRandomSoundIndex = soundIndex;
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcHoldGlowingElvisPoster(OpCall &opCall) {
|
|
const uint32 kPosterObjectId = 0x40072;
|
|
const uint32 kPosterSequenceId = 0x60034;
|
|
ARG_BYTE(mode);
|
|
switch (mode) {
|
|
case 0:
|
|
if (_vm->_cursor._objectId == kPosterObjectId) {
|
|
_wasCursorHoldingElvisPoster = true;
|
|
_inventory->addInventoryItem(_vm->_cursor._objectId);
|
|
_vm->stopCursorHoldingObject();
|
|
} else {
|
|
_wasCursorHoldingElvisPoster = false;
|
|
}
|
|
break;
|
|
case 1:
|
|
if (_wasCursorHoldingElvisPoster) {
|
|
_inventory->clearInventorySlot(kPosterObjectId);
|
|
_vm->_cursor._objectId = kPosterObjectId;
|
|
_vm->_cursor._sequenceId2 = kPosterSequenceId;
|
|
_vm->_cursor._field14[_vm->_cursor._actorIndex - 1] = true;
|
|
}
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcStartCredits(OpCall &opCall) {
|
|
ARG_BYTE(mode);
|
|
if (mode == 0)
|
|
_credits->start();
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcSetCursorInventoryMode(OpCall &opCall) {
|
|
ARG_BYTE(mode);
|
|
ARG_BYTE(value);
|
|
_vm->setCursorInventoryMode(mode, value);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcCenterCurrentScreenText(OpCall &opCall) {
|
|
WidthHeight dimensions;
|
|
_vm->getDefaultTextDimensions(dimensions);
|
|
Common::Point pt(160, dimensions._height / 2 + 8);
|
|
_vm->setDefaultTextPosition(pt);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcSetDefaultTextCoords(OpCall &opCall) {
|
|
_vm->setDefaultTextCoords();
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcSetTextDuration(OpCall &opCall) {
|
|
ARG_INT16(kind);
|
|
ARG_INT16(duration);
|
|
_vm->setTextDuration(kind, duration);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcSetTempMasterSfxVolume(OpCall &opCall) {
|
|
ARG_INT16(sfxVolume);
|
|
// TODO _savedTempMasterSfxVolume = _vm->getMasterSfxVolume();
|
|
// TODO _vm->setMasterSfxVolume(sfxVolume);
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::spcRestoreTempMasterSfxVolume(OpCall &opCall) {
|
|
// TODO _vm->setMasterSfxVolume(_savedTempMasterSfxVolume);
|
|
_savedTempMasterSfxVolume = 16;
|
|
_vm->notifyThreadId(opCall._threadId);
|
|
}
|
|
|
|
void DuckmanSpecialCode::updateTeleporterProperties() {
|
|
_vm->_scriptResource->_properties.set(0x000E0074, _teleporterPosition.x == 4 && _teleporterPosition.y == 2);
|
|
_vm->_scriptResource->_properties.set(0x000E0075, _teleporterPosition.x == 4 && _teleporterPosition.y == 3);
|
|
_vm->_scriptResource->_properties.set(0x000E0076, _teleporterPosition.x == 3 && _teleporterPosition.y == 3);
|
|
_vm->_scriptResource->_properties.set(0x000E0077, _teleporterPosition.x == 2 && _teleporterPosition.y == 2);
|
|
_vm->_scriptResource->_properties.set(0x000E0078, _teleporterPosition.x == 1 && _teleporterPosition.y == 1);
|
|
}
|
|
|
|
} // End of namespace Illusions
|