scummvm/engines/illusions/duckman/duckman_specialcode.cpp
2021-12-26 18:48:43 +01:00

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 (SpecialCodeMap::iterator it = _specialCodeMap.begin(); it != _specialCodeMap.end(); ++it) {
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