Initial commit
This commit is contained in:
3
engines/darkseed/POTFILES
Normal file
3
engines/darkseed/POTFILES
Normal file
@@ -0,0 +1,3 @@
|
||||
engines/darkseed/darkseed.cpp
|
||||
engines/darkseed/dialogs.cpp
|
||||
engines/darkseed/metaengine.cpp
|
||||
232
engines/darkseed/adlib_dsf.cpp
Normal file
232
engines/darkseed/adlib_dsf.cpp
Normal file
@@ -0,0 +1,232 @@
|
||||
/* 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 "darkseed/adlib_dsf.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
// F-num values used for the 12 octave notes.
|
||||
const uint16 MidiDriver_DarkSeedFloppy_AdLib::OPL_NOTE_FREQUENCIES[12] = {
|
||||
0x157, 0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287
|
||||
};
|
||||
|
||||
MidiDriver_DarkSeedFloppy_AdLib::MidiDriver_DarkSeedFloppy_AdLib(OPL::Config::OplType oplType, int timerFrequency) :
|
||||
MidiDriver_ADLIB_Multisource::MidiDriver_ADLIB_Multisource(oplType, timerFrequency) {
|
||||
|
||||
_dsfInstrumentBank = new OplInstrumentDefinition[128];
|
||||
_instrumentBank = _dsfInstrumentBank;
|
||||
Common::fill(_sourcePriority, _sourcePriority + sizeof(_sourcePriority), 0);
|
||||
|
||||
_defaultChannelVolume = 0x7F;
|
||||
// Dark Seed uses rhythm instrument definitions with instrument numbers 0x0 - 0xE
|
||||
_rhythmInstrumentMode = RHYTHM_INSTRUMENT_MODE_RHYTHM_TYPE;
|
||||
_instrumentWriteMode = INSTRUMENT_WRITE_MODE_FIRST_NOTE_ON;
|
||||
}
|
||||
|
||||
MidiDriver_DarkSeedFloppy_AdLib::~MidiDriver_DarkSeedFloppy_AdLib() {
|
||||
delete[] _dsfInstrumentBank;
|
||||
}
|
||||
|
||||
int MidiDriver_DarkSeedFloppy_AdLib::open() {
|
||||
int result = MidiDriver_ADLIB_Multisource::open();
|
||||
if (result == 0)
|
||||
// Dark Seed has the OPL rhythm mode always on
|
||||
setRhythmMode(true);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void MidiDriver_DarkSeedFloppy_AdLib::deinitSource(uint8 source) {
|
||||
MidiDriver_ADLIB_Multisource::deinitSource(source);
|
||||
|
||||
_sourcePriority[source] = 0;
|
||||
}
|
||||
|
||||
void MidiDriver_DarkSeedFloppy_AdLib::setSourcePriority(uint8 source, uint8 priority) {
|
||||
assert(source < MAXIMUM_SOURCES);
|
||||
_sourcePriority[source] = priority;
|
||||
}
|
||||
|
||||
void MidiDriver_DarkSeedFloppy_AdLib::loadInstrumentBank(uint8 *instrumentBankData) {
|
||||
// Dark Seed stores instruments in SIT files. Most music tracks have their
|
||||
// own instrument bank, but there are only 2 significantly different banks.
|
||||
// START loads the instrument bank for each of the 8 tracks it plays, but
|
||||
// each bank is effectively the same. TOS only loads the TOS1.SIT
|
||||
// instrument bank; the SIT files from the music tracks it plays are
|
||||
// ignored.
|
||||
//
|
||||
// All SIT files contain 256 instruments in the 16 byte AdLib BNK format.
|
||||
// Only the first 128 instruments are actually loaded; the rest is usually
|
||||
// empty.
|
||||
for (int i = 0; i < 128; i++) {
|
||||
AdLibIbkInstrumentDefinition _ibkInstrument;
|
||||
_ibkInstrument.o0FreqMultMisc = *instrumentBankData++;
|
||||
_ibkInstrument.o1FreqMultMisc = *instrumentBankData++;
|
||||
_ibkInstrument.o0Level = *instrumentBankData++;
|
||||
_ibkInstrument.o1Level = *instrumentBankData++;
|
||||
_ibkInstrument.o0DecayAttack = *instrumentBankData++;
|
||||
_ibkInstrument.o1DecayAttack = *instrumentBankData++;
|
||||
_ibkInstrument.o0ReleaseSustain = *instrumentBankData++;
|
||||
_ibkInstrument.o1ReleaseSustain = *instrumentBankData++;
|
||||
_ibkInstrument.o0WaveformSelect = *instrumentBankData++;
|
||||
_ibkInstrument.o1WaveformSelect = *instrumentBankData++;
|
||||
_ibkInstrument.connectionFeedback = *instrumentBankData++;
|
||||
|
||||
// The first 15 instruments are rhythm instrument definitions, meant
|
||||
// for the 5 OPL rhythm mode instruments. 0-2 are bass drum instruments,
|
||||
// 3-5 are snare drum instruments, etc.
|
||||
uint8 rhythmType = 0;
|
||||
if (i < 15) {
|
||||
rhythmType = 6 + (i / 3);
|
||||
}
|
||||
_ibkInstrument.rhythmType = rhythmType;
|
||||
_ibkInstrument.rhythmNote = 0;
|
||||
_ibkInstrument.transpose = 0;
|
||||
|
||||
_ibkInstrument.toOplInstrumentDefinition(_dsfInstrumentBank[i]);
|
||||
|
||||
// Skip padding bytes
|
||||
instrumentBankData += 5;
|
||||
}
|
||||
}
|
||||
|
||||
uint8 MidiDriver_DarkSeedFloppy_AdLib::allocateOplChannel(uint8 channel, uint8 source, InstrumentInfo &instrumentInfo) {
|
||||
uint8 allocatedChannel = 0xFF;
|
||||
|
||||
_allocationMutex.lock();
|
||||
_activeNotesMutex.lock();
|
||||
|
||||
if (instrumentInfo.instrumentId <= 0xE) {
|
||||
// The first 15 instruments are rhythm instruments. These get assigned
|
||||
// to the corresponding OPL rhythm instruments.
|
||||
// Note: original code also processes instrument 0xF, leading to
|
||||
// undefined behavior.
|
||||
|
||||
// The order of the rhythm instruments is flipped compared to the order
|
||||
// in the _activeRhythmNotes array.
|
||||
uint8 rhythmInstType = 4 - (instrumentInfo.instrumentId / 3);
|
||||
allocatedChannel = OPL_RHYTHM_INSTRUMENT_CHANNELS[rhythmInstType];
|
||||
if (_activeRhythmNotes[rhythmInstType].channelAllocated && _activeRhythmNotes[rhythmInstType].source != source) {
|
||||
// OPL rhythm instrument is already allocated
|
||||
if (_sourcePriority[_activeRhythmNotes[rhythmInstType].source] >= _sourcePriority[source]) {
|
||||
// Current source priority is equal to or higher than the new
|
||||
// source priority. Do not re-allocate this rhythm instrument.
|
||||
allocatedChannel = 0xFF;
|
||||
} else {
|
||||
// Current source priority is lower than the new source
|
||||
// priority. Deallocate the channel from the current source.
|
||||
if (_activeRhythmNotes[rhythmInstType].noteActive)
|
||||
writeKeyOff(allocatedChannel, static_cast<OplInstrumentRhythmType>(rhythmInstType + 1));
|
||||
_channelAllocations[_activeRhythmNotes[rhythmInstType].source][_activeRhythmNotes[rhythmInstType].channel] = 0xFF;
|
||||
}
|
||||
}
|
||||
|
||||
if (allocatedChannel != 0xFF) {
|
||||
// Allocate the OPL channel to the source and rhythm instrument.
|
||||
_activeRhythmNotes[rhythmInstType].channelAllocated = true;
|
||||
_activeRhythmNotes[rhythmInstType].source = source;
|
||||
_activeRhythmNotes[rhythmInstType].channel = channel;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// For melodic instruments, the following OPL channel is allocated:
|
||||
// - The OPL channel already allocated to this data channel.
|
||||
// - The OPL channel with the lowest priority, if it is lower than the
|
||||
// priority of the new source.
|
||||
uint8 lowestPriority = 0x64;
|
||||
for (int i = 0; i < _numMelodicChannels; i++) {
|
||||
uint8 oplChannel = _melodicChannels[i];
|
||||
if (_activeNotes[oplChannel].channelAllocated && _activeNotes[oplChannel].source == source && _activeNotes[oplChannel].channel == channel) {
|
||||
// This OPL channel is already allocated to this source and
|
||||
// data channel. Use this OPL channel.
|
||||
allocatedChannel = oplChannel;
|
||||
lowestPriority = 0;
|
||||
break;
|
||||
}
|
||||
// Unallocated channels are treated as having priority 0, the
|
||||
// lowest priority.
|
||||
uint8 currentChannelPriority = !_activeNotes[oplChannel].channelAllocated ? 0 : _sourcePriority[_activeNotes[oplChannel].source];
|
||||
if (currentChannelPriority < lowestPriority) {
|
||||
// Found an OPL channel with a lower priority than the
|
||||
// previously found OPL channel.
|
||||
allocatedChannel = i;
|
||||
lowestPriority = currentChannelPriority;
|
||||
}
|
||||
}
|
||||
|
||||
if (_sourcePriority[source] <= lowestPriority) {
|
||||
// New source priority is lower than the lowest found OPL channel
|
||||
// priority. Do not re-allocate this OPL channel.
|
||||
allocatedChannel = 0xFF;
|
||||
}
|
||||
|
||||
if (allocatedChannel != 0xFF) {
|
||||
if (_activeNotes[allocatedChannel].channelAllocated && _activeNotes[allocatedChannel].source != source) {
|
||||
// OPL channel is already allocated. De-allocate it.
|
||||
if (_activeNotes[allocatedChannel].noteActive)
|
||||
writeKeyOff(allocatedChannel);
|
||||
_channelAllocations[_activeRhythmNotes[allocatedChannel].source][_activeRhythmNotes[allocatedChannel].channel] = 0xFF;
|
||||
}
|
||||
|
||||
// Allocate the OPL channel to the source and data channel.
|
||||
_activeNotes[allocatedChannel].channelAllocated = true;
|
||||
_activeNotes[allocatedChannel].source = source;
|
||||
_activeNotes[allocatedChannel].channel = channel;
|
||||
}
|
||||
}
|
||||
|
||||
if (allocatedChannel != 0xFF) {
|
||||
_channelAllocations[source][channel] = allocatedChannel;
|
||||
}
|
||||
|
||||
_allocationMutex.unlock();
|
||||
_activeNotesMutex.unlock();
|
||||
|
||||
return allocatedChannel;
|
||||
}
|
||||
|
||||
uint16 MidiDriver_DarkSeedFloppy_AdLib::calculateFrequency(uint8 channel, uint8 source, uint8 note) {
|
||||
uint8 octaveNote = ((note >= 120) ? 11 : (note % 12));
|
||||
uint8 block;
|
||||
if (note < 12) {
|
||||
block = 0;
|
||||
} else if (note >= 108) {
|
||||
block = 7;
|
||||
} else {
|
||||
block = (note / 12) - 1;
|
||||
}
|
||||
uint16 fnum = OPL_NOTE_FREQUENCIES[octaveNote];
|
||||
|
||||
return fnum | (block << 10);
|
||||
}
|
||||
|
||||
uint8 MidiDriver_DarkSeedFloppy_AdLib::calculateUnscaledVolume(uint8 channel, uint8 source, uint8 velocity, const OplInstrumentDefinition &instrumentDef, uint8 operatorNum) {
|
||||
uint8 instrumentLevel = instrumentDef.getOperatorDefinition(operatorNum).level & 0x3F;
|
||||
if (instrumentDef.getNumberOfOperators() >= 2 && operatorNum == 0) {
|
||||
// For operator 0 of a 2 operator instrument, the level from the
|
||||
// instrument definition is used without scaling, even if the
|
||||
// connection type is additive.
|
||||
return instrumentLevel;
|
||||
}
|
||||
return 0x3F - (((velocity + 0x80) * (0x3F - instrumentLevel)) >> 8);
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
61
engines/darkseed/adlib_dsf.h
Normal file
61
engines/darkseed/adlib_dsf.h
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_ADLIB_DSF_H
|
||||
#define DARKSEED_ADLIB_DSF_H
|
||||
|
||||
#include "audio/adlib_ms.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
/**
|
||||
* Implementation of the AdLib code used by Dark Seed (floppy version).
|
||||
* The game uses a combination of the Creative FM-Music Functions library and
|
||||
* its own sound code.
|
||||
*/
|
||||
class MidiDriver_DarkSeedFloppy_AdLib : public MidiDriver_ADLIB_Multisource {
|
||||
protected:
|
||||
static const uint16 OPL_NOTE_FREQUENCIES[12];
|
||||
|
||||
public:
|
||||
MidiDriver_DarkSeedFloppy_AdLib(OPL::Config::OplType oplType, int timerFrequency = OPL::OPL::kDefaultCallbackFrequency);
|
||||
~MidiDriver_DarkSeedFloppy_AdLib();
|
||||
|
||||
int open() override;
|
||||
|
||||
void deinitSource(uint8 source) override;
|
||||
|
||||
void setSourcePriority(uint8 source, uint8 priority);
|
||||
|
||||
void loadInstrumentBank(uint8 *instrumentBankData);
|
||||
|
||||
protected:
|
||||
uint8 allocateOplChannel(uint8 channel, uint8 source, InstrumentInfo &instrumentInfo) override;
|
||||
uint16 calculateFrequency(uint8 channel, uint8 source, uint8 note) override;
|
||||
uint8 calculateUnscaledVolume(uint8 channel, uint8 source, uint8 velocity, const OplInstrumentDefinition &instrumentDef, uint8 operatorNum) override;
|
||||
|
||||
uint8 _sourcePriority[MAXIMUM_SOURCES];
|
||||
OplInstrumentDefinition *_dsfInstrumentBank;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_ADLIB_DSF_H
|
||||
292
engines/darkseed/adlib_worx.cpp
Normal file
292
engines/darkseed/adlib_worx.cpp
Normal file
@@ -0,0 +1,292 @@
|
||||
/* 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 "darkseed/adlib_worx.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
const AdLibIbkInstrumentDefinition MidiDriver_Worx_AdLib::WORX_INSTRUMENT_BANK[128] = {
|
||||
// 0x00
|
||||
{ 0x01, 0x01, 0x4f, 0x12, 0xf1, 0xd3, 0x50, 0x7c, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x02, 0x01, 0x50, 0x12, 0xf1, 0xd2, 0x50, 0x76, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x01, 0x4b, 0x17, 0xf1, 0xd2, 0x50, 0x76, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x13, 0x01, 0x50, 0x11, 0xf1, 0xd2, 0x50, 0x76, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x32, 0x01, 0x92, 0x8f, 0xff, 0xff, 0x11, 0x13, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x34, 0x03, 0x92, 0x0f, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x34, 0x03, 0x92, 0x14, 0xff, 0xff, 0x10, 0x04, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x53, 0x51, 0x4e, 0x00, 0xf1, 0xd2, 0x00, 0x86, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x08
|
||||
{ 0x28, 0x21, 0xcf, 0x0d, 0xf8, 0xc0, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xe2, 0xe1, 0xca, 0x15, 0xf8, 0xc0, 0xe5, 0x0e, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x2c, 0xa1, 0xd4, 0x1c, 0xf9, 0xc0, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x2b, 0x21, 0xca, 0x13, 0xf8, 0xc0, 0xe5, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x29, 0x21, 0xcd, 0x14, 0xf0, 0xe0, 0x91, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x24, 0x21, 0xd0, 0x14, 0xf0, 0xe0, 0x01, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x23, 0x21, 0xc8, 0x10, 0xf0, 0xe0, 0x01, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x64, 0x61, 0xc9, 0x14, 0xb0, 0xf0, 0x01, 0x86, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x10
|
||||
{ 0x33, 0x15, 0x85, 0x94, 0xa1, 0x72, 0x10, 0x23, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x15, 0x85, 0x94, 0xa1, 0x73, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x16, 0x81, 0x94, 0xa1, 0xc2, 0x30, 0x74, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x03, 0x02, 0x8a, 0x94, 0xf0, 0xf4, 0x7b, 0x7b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x03, 0x01, 0x8a, 0x99, 0xf0, 0xf4, 0x7b, 0x7b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x23, 0x01, 0x8a, 0x94, 0xf2, 0xf4, 0x7b, 0x7b, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x32, 0x12, 0x80, 0x95, 0x01, 0x72, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x32, 0x14, 0x80, 0x90, 0x01, 0x73, 0x10, 0x33, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x18
|
||||
{ 0x31, 0x21, 0x16, 0x14, 0x73, 0x80, 0x8e, 0x9e, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x30, 0x21, 0x16, 0x10, 0x73, 0x80, 0x7e, 0x9e, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x21, 0x94, 0x15, 0x33, 0xa0, 0x73, 0x97, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x21, 0x94, 0x13, 0xd3, 0xa0, 0x73, 0x97, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x32, 0x45, 0x11, 0xf1, 0xf2, 0x53, 0x27, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x13, 0x15, 0x0c, 0x1a, 0xf2, 0xf2, 0x01, 0xb6, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x11, 0x11, 0x0c, 0x15, 0xf2, 0xf2, 0x01, 0xb6, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x11, 0x11, 0x0a, 0x10, 0xfe, 0xf2, 0x04, 0xbd, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x20
|
||||
{ 0x16, 0xe1, 0x4d, 0x11, 0xfa, 0xf1, 0x11, 0xf1, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x16, 0xf1, 0x40, 0x17, 0xba, 0x24, 0x11, 0x31, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x61, 0xe1, 0xa7, 0x8e, 0x72, 0x50, 0x8e, 0x1a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x18, 0xe1, 0x4d, 0x13, 0x32, 0x51, 0x13, 0xe3, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x17, 0x31, 0xc0, 0x92, 0x12, 0x13, 0x41, 0x31, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x03, 0x21, 0x8f, 0x90, 0xf5, 0xf3, 0x55, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x13, 0xe1, 0x4d, 0x12, 0xfa, 0xf1, 0x11, 0xf1, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x11, 0xf1, 0x43, 0x10, 0x20, 0x31, 0x15, 0xf8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x28
|
||||
{ 0x11, 0xe4, 0x03, 0x52, 0x82, 0xf0, 0x97, 0xf2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x05, 0x14, 0x40, 0x0f, 0xd1, 0x51, 0x53, 0x71, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xf1, 0x21, 0x01, 0x12, 0x77, 0x81, 0x17, 0x18, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xf1, 0xe1, 0x18, 0x17, 0x32, 0xf1, 0x11, 0x13, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x73, 0x71, 0x48, 0x13, 0xf1, 0xf1, 0x53, 0x06, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x71, 0x61, 0x8d, 0x53, 0x71, 0x72, 0x11, 0x15, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xd7, 0xd2, 0x4f, 0x14, 0xf2, 0xf1, 0x61, 0xb2, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x01, 0x11, 0x13, 0xf0, 0xf0, 0xff, 0xf8, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x30
|
||||
{ 0x31, 0x61, 0x8b, 0x10, 0x41, 0x22, 0x11, 0x13, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x61, 0x8b, 0x10, 0xff, 0x44, 0x21, 0x15, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x61, 0x8b, 0x10, 0x41, 0x32, 0x11, 0x15, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x71, 0x21, 0x1c, 0x10, 0xfd, 0xe7, 0x13, 0xd6, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x71, 0x21, 0x1c, 0x10, 0x51, 0x54, 0x03, 0x67, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x71, 0x21, 0x1c, 0x10, 0x51, 0x54, 0x03, 0x17, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x71, 0x21, 0x1c, 0x10, 0x54, 0x53, 0x15, 0x49, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x71, 0x61, 0x56, 0x10, 0x51, 0x54, 0x03, 0x17, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x38
|
||||
{ 0x71, 0x21, 0x1c, 0x10, 0x51, 0x54, 0x03, 0x17, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x02, 0x01, 0x29, 0x90, 0xf5, 0xf2, 0x75, 0xf3, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x02, 0x01, 0x29, 0x90, 0xf0, 0xf4, 0x75, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x11, 0x49, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x11, 0x89, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x02, 0x11, 0x89, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x02, 0x11, 0x80, 0x10, 0xf1, 0xf1, 0x53, 0x74, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x08, 0x40, 0x50, 0xf1, 0xf1, 0x53, 0x53, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x40
|
||||
{ 0x21, 0x21, 0x15, 0x90, 0xd3, 0xc3, 0x2c, 0x2c, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x21, 0x18, 0x90, 0xd4, 0xc4, 0xf2, 0x8a, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x11, 0x4e, 0x10, 0xf0, 0xf4, 0x7b, 0xc8, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x01, 0x11, 0x44, 0x10, 0xf0, 0xf3, 0xab, 0xab, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x53, 0x11, 0x0e, 0x10, 0xf4, 0xf1, 0xc8, 0xbb, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x53, 0x11, 0x0b, 0x10, 0xf2, 0xf2, 0xc8, 0xc5, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x21, 0x15, 0x10, 0xb4, 0x94, 0x4c, 0xac, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x21, 0x15, 0x10, 0x94, 0x64, 0x1c, 0xac, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x48
|
||||
{ 0x21, 0xa1, 0x16, 0x90, 0x77, 0x60, 0x8f, 0x2a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0xa1, 0x19, 0x90, 0x77, 0x60, 0xbf, 0x2a, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xa1, 0xe2, 0x13, 0x90, 0xd6, 0x60, 0xaf, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xa2, 0xe2, 0x1d, 0x90, 0x95, 0x60, 0x24, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x32, 0x61, 0x9a, 0x90, 0x51, 0x60, 0x19, 0x39, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xa4, 0xe2, 0x12, 0x90, 0xf4, 0x60, 0x30, 0x2a, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x21, 0x16, 0x10, 0x63, 0x63, 0x0e, 0x0e, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x21, 0x16, 0x10, 0x63, 0x63, 0x0a, 0x0b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x50
|
||||
{ 0x21, 0x21, 0x1b, 0x10, 0x63, 0x63, 0x0a, 0x0b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x20, 0x21, 0x1b, 0x10, 0x63, 0x63, 0x0a, 0x0b, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x32, 0x61, 0x1c, 0x90, 0x82, 0x60, 0x18, 0x07, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x32, 0xe1, 0x18, 0x90, 0x51, 0x62, 0x14, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x22, 0xc3, 0x10, 0x87, 0x8b, 0x17, 0x0e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x71, 0x22, 0xc3, 0x14, 0x8e, 0x8b, 0x17, 0x0e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x70, 0x22, 0x8d, 0x10, 0x6e, 0x6b, 0x17, 0x0e, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x24, 0x31, 0x4f, 0x10, 0xf2, 0x52, 0x06, 0x06, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x58
|
||||
{ 0x31, 0x61, 0x1b, 0x10, 0x64, 0xd0, 0x07, 0x67, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x61, 0x1b, 0x10, 0x61, 0xd2, 0x06, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x61, 0x1f, 0x10, 0x31, 0x50, 0x06, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x61, 0x1f, 0x10, 0x41, 0xa0, 0x06, 0x36, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x21, 0x9a, 0x90, 0x53, 0xa0, 0x56, 0x16, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x21, 0x21, 0x9a, 0x90, 0x53, 0xa0, 0x56, 0x16, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x61, 0x21, 0x19, 0x10, 0x53, 0xa0, 0x58, 0x18, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x61, 0x21, 0x19, 0x10, 0x73, 0xa0, 0x57, 0x17, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x60
|
||||
{ 0x21, 0x21, 0x1b, 0x10, 0x71, 0xa1, 0xa6, 0x96, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x85, 0xa1, 0x91, 0x10, 0xf5, 0xf0, 0x44, 0x45, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x07, 0x61, 0x51, 0x10, 0xf5, 0xf0, 0x33, 0x25, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x13, 0x11, 0x8c, 0x90, 0xff, 0xff, 0x21, 0x03, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x38, 0xb1, 0x8c, 0x50, 0xf3, 0xf5, 0x0d, 0x33, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x87, 0x22, 0x91, 0x10, 0xf5, 0xf0, 0x55, 0x54, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xb3, 0x90, 0x4a, 0x10, 0xb6, 0xd1, 0x32, 0x31, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x04, 0xc2, 0x00, 0x10, 0xfe, 0xf6, 0xf0, 0xb5, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x68
|
||||
{ 0x05, 0x01, 0x4e, 0x90, 0xda, 0xf0, 0x15, 0x13, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x32, 0x44, 0x10, 0xf2, 0xf0, 0x9a, 0x27, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xb0, 0xd7, 0xc4, 0x90, 0xa4, 0x40, 0x02, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xca, 0xcc, 0x84, 0x10, 0xf0, 0x59, 0xf0, 0x62, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x30, 0x35, 0x35, 0x10, 0xf5, 0xf0, 0xf0, 0x9b, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xb4, 0xd7, 0x87, 0x90, 0xa4, 0x40, 0x02, 0x42, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x07, 0x05, 0x40, 0x00, 0x09, 0xf6, 0x53, 0x96, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x09, 0x01, 0x4e, 0x10, 0xda, 0xf1, 0x25, 0x15, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x70
|
||||
{ 0x06, 0x00, 0x09, 0x10, 0xf4, 0xf6, 0xa0, 0x46, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x07, 0x00, 0x00, 0x10, 0xf0, 0x5c, 0xf0, 0xdc, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x1c, 0x0c, 0x1e, 0x10, 0xe5, 0x5d, 0x5b, 0xfa, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x11, 0x01, 0x8a, 0x50, 0xf1, 0xf1, 0x11, 0xb3, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x40, 0x10, 0xd1, 0xf2, 0x53, 0x56, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x32, 0x11, 0x44, 0x10, 0xf8, 0xf5, 0xff, 0x7f, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x02, 0x40, 0x10, 0x09, 0xf7, 0x53, 0x94, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x11, 0x01, 0x86, 0x90, 0xf2, 0xa0, 0xa8, 0xa8, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
// 0x78
|
||||
{ 0x00, 0x13, 0x50, 0x10, 0xf2, 0xf2, 0x70, 0x72, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0xf0, 0xe0, 0x00, 0xd0, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x07, 0x12, 0x4f, 0x10, 0xf2, 0xf2, 0x60, 0x72, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x0b, 0x10, 0xa8, 0xd6, 0x4c, 0x4f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x00, 0x00, 0x0d, 0x10, 0xe8, 0xa5, 0xef, 0xff, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x31, 0x16, 0x87, 0x90, 0xa1, 0x7d, 0x11, 0x46, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x30, 0x10, 0x90, 0x10, 0xf4, 0xf4, 0x49, 0x33, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00 },
|
||||
{ 0x24, 0x31, 0x54, 0x10, 0x55, 0x50, 0xfd, 0x2d, 0x00, 0x00, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x00 }
|
||||
};
|
||||
|
||||
const uint16 MidiDriver_Worx_AdLib::OPL_NOTE_FREQUENCIES[12] = {
|
||||
0x16B, 0x181, 0x198, 0x1B0, 0x1CA, 0x1E5, 0x202, 0x220, 0x241, 0x263, 0x287, 0x2AE
|
||||
};
|
||||
|
||||
MidiDriver_Worx_AdLib::MidiDriver_Worx_AdLib(OPL::Config::OplType oplType, int timerFrequency) :
|
||||
MidiDriver_ADLIB_Multisource::MidiDriver_ADLIB_Multisource(oplType, timerFrequency) {
|
||||
|
||||
OplInstrumentDefinition *instrumentBank = new OplInstrumentDefinition[128];
|
||||
|
||||
for (int i = 0; i < 128; i++) {
|
||||
WORX_INSTRUMENT_BANK[i].toOplInstrumentDefinition(instrumentBank[i]);
|
||||
|
||||
// The original code does not add the key scale level bits (bits 6 and 7)
|
||||
// from the instrument definition to the level before it writes the 0x4x
|
||||
// register value, so effectively, KSL is always disabled for operator 1.
|
||||
// This is probably an oversight, but this behavior is implemented here
|
||||
// by clearing the KSL bits of operator 1 in the instrument definition.
|
||||
instrumentBank[i].operator1.level &= 0x3F;
|
||||
}
|
||||
|
||||
// Set the const class variable with our just allocated bank
|
||||
_instrumentBank = instrumentBank;
|
||||
|
||||
_defaultChannelVolume = 0x7F;
|
||||
_rhythmInstrumentMode = RHYTHM_INSTRUMENT_MODE_RHYTHM_TYPE;
|
||||
_instrumentWriteMode = INSTRUMENT_WRITE_MODE_FIRST_NOTE_ON;
|
||||
}
|
||||
|
||||
MidiDriver_Worx_AdLib::~MidiDriver_Worx_AdLib() {
|
||||
delete[] _instrumentBank;
|
||||
}
|
||||
|
||||
uint8 MidiDriver_Worx_AdLib::allocateOplChannel(uint8 channel, uint8 source, InstrumentInfo &instrumentInfo) {
|
||||
uint8 allocatedChannel = 0xFF;
|
||||
|
||||
_allocationMutex.lock();
|
||||
|
||||
uint8 unusedChannel = 0xFF, unallocatedChannel = 0xFF, unusedAllocatedChannel = 0xFF;
|
||||
for (int i = 0; i < _numMelodicChannels; i++) {
|
||||
uint8 oplChannel = _melodicChannels[i];
|
||||
if (_activeNotes[oplChannel].channelAllocated && _activeNotes[oplChannel].source == source && _activeNotes[oplChannel].channel == channel &&
|
||||
!_activeNotes[oplChannel].noteActive && unusedChannel == 0xFF) {
|
||||
// This OPL channel is already allocated to this source and MIDI
|
||||
// channel, but it is not playing a note. Use this channel.
|
||||
unusedChannel = oplChannel;
|
||||
break;
|
||||
}
|
||||
if (!_activeNotes[oplChannel].channelAllocated && unallocatedChannel == 0xFF) {
|
||||
// This channel is unallocated. If no unallocated channel has been
|
||||
// found yet, register this channel.
|
||||
unallocatedChannel = oplChannel;
|
||||
}
|
||||
if (_activeNotes[oplChannel].channelAllocated && !(_activeNotes[oplChannel].source == source && _activeNotes[oplChannel].channel == channel) &&
|
||||
!_activeNotes[oplChannel].noteActive && unusedAllocatedChannel == 0xFF) {
|
||||
// This channel is allocated to a different source and/or MIDI
|
||||
// channel, but it is not playing a note. If a channel of this
|
||||
// type has not yet been found, register it.
|
||||
unusedAllocatedChannel = oplChannel;
|
||||
}
|
||||
}
|
||||
|
||||
if (unusedChannel != 0xFF) {
|
||||
// Found an allocated but unused channel.
|
||||
allocatedChannel = unusedChannel;
|
||||
}
|
||||
else if (unallocatedChannel != 0xFF) {
|
||||
// Found an unallocated channel.
|
||||
allocatedChannel = unallocatedChannel;
|
||||
}
|
||||
else if (unusedAllocatedChannel != 0xFF) {
|
||||
// Found an unused channel allocated to a different source / MIDI channel.
|
||||
allocatedChannel = unusedAllocatedChannel;
|
||||
}
|
||||
else {
|
||||
// All channels are playing notes. No channel is freed, so this will
|
||||
// result in the note not being played. Return 0xFF.
|
||||
_allocationMutex.unlock();
|
||||
return allocatedChannel;
|
||||
}
|
||||
|
||||
// Allocate the OPL channel to the source / MIDI channel.
|
||||
_activeNotes[allocatedChannel].channelAllocated = true;
|
||||
_activeNotes[allocatedChannel].source = source;
|
||||
_activeNotes[allocatedChannel].channel = channel;
|
||||
|
||||
_allocationMutex.unlock();
|
||||
|
||||
return allocatedChannel;
|
||||
}
|
||||
|
||||
uint16 MidiDriver_Worx_AdLib::calculateFrequency(uint8 channel, uint8 source, uint8 note) {
|
||||
// Notes for melodic instruments are transposed down by 13 semitones.
|
||||
uint8 transposedNote = MAX(note - 12 - 1, 0);
|
||||
|
||||
// TODO Implement transpose based on transpose controllers
|
||||
|
||||
// Get F-num based on octave note. Note: Worx does not support pitch bend.
|
||||
uint8 octaveNote = transposedNote % 12;
|
||||
uint16 oplFrequency = OPL_NOTE_FREQUENCIES[octaveNote];
|
||||
|
||||
// Get block (octave).
|
||||
uint8 block = transposedNote / 12;
|
||||
block = MIN(block, (uint8) 7);
|
||||
|
||||
// Combine the block and frequency in the OPL Ax and Bx register format.
|
||||
return oplFrequency | (block << 10);
|
||||
}
|
||||
|
||||
uint8 MidiDriver_Worx_AdLib::calculateUnscaledVolume(uint8 channel, uint8 source, uint8 velocity, const OplInstrumentDefinition &instrumentDef, uint8 operatorNum) {
|
||||
// Worx calculates volume by scaling the instrument operator volume by the
|
||||
// channel volume. Note velocity is not used.
|
||||
uint8 operatorVolume = 0x3F - (instrumentDef.getOperatorDefinition(operatorNum).level & 0x3F);
|
||||
uint8 channelVolume = _controlData[source][channel].volume;
|
||||
// Note: the original code loses 1 bit of precision here (bit 0 is always 0).
|
||||
uint8 unscaledVolume = (operatorVolume * channelVolume) >> 7;
|
||||
|
||||
return 0x3F - unscaledVolume;
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
65
engines/darkseed/adlib_worx.h
Normal file
65
engines/darkseed/adlib_worx.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_ADLIB_WORX_H
|
||||
#define DARKSEED_ADLIB_WORX_H
|
||||
|
||||
#include "audio/adlib_ms.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
/**
|
||||
* Implementation of the AdLib code from the Worx Toolkit library,
|
||||
* based on version 2.1, as used by Dark Seed (CD version).
|
||||
* Implements the OPL channel allocation algorithm and note frequency
|
||||
* and volume calculation.
|
||||
*
|
||||
* TODO Implementation is incomplete, because Dark Seed does not use
|
||||
* some functionality of the library:
|
||||
* - OPL rhythm mode
|
||||
* - Transpose controllers 0x68 and 0x69 (seems to be buggy)
|
||||
*/
|
||||
class MidiDriver_Worx_AdLib : public MidiDriver_ADLIB_Multisource {
|
||||
private:
|
||||
/**
|
||||
* The OPL instrument bank of the Worx Toolkit.
|
||||
* This was taken from the Dark Seed executable and might have been
|
||||
* customized for the game.
|
||||
*/
|
||||
static const AdLibIbkInstrumentDefinition WORX_INSTRUMENT_BANK[];
|
||||
/**
|
||||
* The OPL frequency (F-num) for each octave note.
|
||||
*/
|
||||
static const uint16 OPL_NOTE_FREQUENCIES[];
|
||||
|
||||
public:
|
||||
MidiDriver_Worx_AdLib(OPL::Config::OplType oplType, int timerFrequency = OPL::OPL::kDefaultCallbackFrequency);
|
||||
~MidiDriver_Worx_AdLib();
|
||||
|
||||
protected:
|
||||
uint8 allocateOplChannel(uint8 channel, uint8 source, InstrumentInfo &instrumentInfo) override;
|
||||
uint16 calculateFrequency(uint8 channel, uint8 source, uint8 note) override;
|
||||
uint8 calculateUnscaledVolume(uint8 channel, uint8 source, uint8 velocity, const OplInstrumentDefinition &instrumentDef, uint8 operatorNum) override;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_ADLIB_WORX_H
|
||||
1411
engines/darkseed/animation.cpp
Normal file
1411
engines/darkseed/animation.cpp
Normal file
File diff suppressed because it is too large
Load Diff
68
engines/darkseed/animation.h
Normal file
68
engines/darkseed/animation.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
#ifndef DARKSEED_ANIMATION_H
|
||||
#define DARKSEED_ANIMATION_H
|
||||
|
||||
#include "darkseed/objects.h"
|
||||
#include "darkseed/player.h"
|
||||
namespace Darkseed {
|
||||
|
||||
class Animation {
|
||||
Player *_player = nullptr;
|
||||
Objects &_objectVar;
|
||||
|
||||
public:
|
||||
int _animIndexTbl[30];
|
||||
int _spriteAnimCountdownTimer[30];
|
||||
|
||||
bool _isPlayingAnimation_maybe = false;
|
||||
uint16 _otherNspAnimationType_maybe = 0;
|
||||
|
||||
bool _scaleSequence = false;
|
||||
bool _objRestarted = false;
|
||||
bool _frameAdvanced = false;
|
||||
|
||||
int _nsp_sprite_scaling_y_position = 0;
|
||||
|
||||
public:
|
||||
explicit Animation(Player *player, Objects &objectVar) : _player(player), _objectVar(objectVar) {}
|
||||
|
||||
void updateAnimation();
|
||||
|
||||
void advanceAnimationFrame(int nspAminIdx);
|
||||
|
||||
void dCopAnim();
|
||||
void sargoAnim();
|
||||
void keeperAdmin();
|
||||
void gancAnim();
|
||||
void stuffPlayer();
|
||||
void runDrekethSequence();
|
||||
void libAnim(bool pickingUpReservedBook);
|
||||
|
||||
void setupOtherNspAnimation(int nspAnimIdx, int animId);
|
||||
private:
|
||||
void adddrekbutt();
|
||||
void wonGame();
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_ANIMATION_H
|
||||
61
engines/darkseed/anm.cpp
Normal file
61
engines/darkseed/anm.cpp
Normal file
@@ -0,0 +1,61 @@
|
||||
/* 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 "common/debug.h"
|
||||
#include "darkseed/anm.h"
|
||||
|
||||
namespace Darkseed {
|
||||
bool Anm::load(const Common::Path &filename, int deltaOffset) {
|
||||
close();
|
||||
if (!_file.open(filename)) {
|
||||
return false;
|
||||
}
|
||||
_numRecords = _file.readUint16LE();
|
||||
_assetFileId = _file.readUint16LE();
|
||||
_deltaOffset = deltaOffset;
|
||||
return true;
|
||||
}
|
||||
|
||||
void Anm::close() {
|
||||
if (_file.isOpen()) {
|
||||
_file.close();
|
||||
}
|
||||
}
|
||||
|
||||
bool Anm::getImg(uint16 index, Img &img, bool includesPosition) {
|
||||
_file.seek(4 + index * 2);
|
||||
int offset = _file.readUint16LE() + _deltaOffset;
|
||||
_file.seek((offset * 16) + (4 + _numRecords * 2));
|
||||
if (includesPosition) {
|
||||
img.load(_file);
|
||||
} else {
|
||||
img.loadWithoutPosition(_file);
|
||||
}
|
||||
debug("Loaded %d (%d,%d) (%d,%d) %x", index, img.getX(), img.getY(), img.getWidth(), img.getHeight(), 0);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int Anm::numImages() const {
|
||||
return _numRecords;
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
46
engines/darkseed/anm.h
Normal file
46
engines/darkseed/anm.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_ANM_H
|
||||
#define DARKSEED_ANM_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "darkseed/img.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Anm {
|
||||
private:
|
||||
Common::File _file;
|
||||
uint16 _numRecords = 0;
|
||||
uint16 _assetFileId = 0;
|
||||
int _deltaOffset = 0;
|
||||
|
||||
public:
|
||||
bool load(const Common::Path &filename, int deltaOffset = 0);
|
||||
void close();
|
||||
bool getImg(uint16 index, Img &img, bool includesPosition = true);
|
||||
int numImages() const;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_ANM_H
|
||||
82
engines/darkseed/big5font.cpp
Normal file
82
engines/darkseed/big5font.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/big5font.h"
|
||||
|
||||
#include "graphics/fonts/dosfont.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
Big5Font::Big5Font() {
|
||||
Common::File fontData;
|
||||
if (!fontData.open("big5font_game.dat")) {
|
||||
error("Error: failed to open big5font_game.dat");
|
||||
}
|
||||
_big5.loadPrefixedRaw(fontData, 15);
|
||||
fontData.close();
|
||||
}
|
||||
|
||||
int Big5Font::getFontHeight() const {
|
||||
return 15;
|
||||
}
|
||||
|
||||
int Big5Font::getMaxCharWidth() const {
|
||||
return 17;
|
||||
}
|
||||
|
||||
int Big5Font::getCharWidth(uint32 chr) const {
|
||||
if (_big5.hasGlyphForBig5Char(chr)) {
|
||||
return getMaxCharWidth();
|
||||
}
|
||||
return 9;
|
||||
}
|
||||
|
||||
void Big5Font::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
|
||||
Common::Point charPos = {(int16)x, (int16)y};
|
||||
if (_big5.drawBig5Char(g_engine->_screen->surfacePtr(), chr, charPos, 0xf)) {
|
||||
charPos.x++;
|
||||
_big5.drawBig5Char(g_engine->_screen->surfacePtr(), chr, charPos, 0xc);
|
||||
charPos.x += Graphics::Big5Font::kChineseTraditionalWidth + 1;
|
||||
} else if (chr < 128) {
|
||||
drawBiosFontGlyph(chr, x, y, 0xf);
|
||||
drawBiosFontGlyph(chr, x+1, y, 0xc);
|
||||
}
|
||||
}
|
||||
|
||||
void Big5Font::drawBiosFontGlyph(uint8 chr, int x, int y, uint8 color) const {
|
||||
byte *ptr = (byte *)g_engine->_screen->getBasePtr(x, y);
|
||||
int srcPixel = chr * 8;
|
||||
for (int sy = 0; sy < 8; sy++) {
|
||||
for (int sx = 0; sx < 8; sx++) {
|
||||
if (Graphics::DosFont::fontData_PCBIOS[srcPixel] & 1 << (7 - sx)) {
|
||||
*ptr = color;
|
||||
ptr[g_engine->_screen->pitch] = color;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
srcPixel++;
|
||||
ptr -= 8;
|
||||
ptr += (g_engine->_screen->pitch * 2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
48
engines/darkseed/big5font.h
Normal file
48
engines/darkseed/big5font.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_BIG5FONT_H
|
||||
#define DARKSEED_BIG5FONT_H
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/big5.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Big5Font : public Graphics::Font {
|
||||
private:
|
||||
Graphics::Big5Font _big5;
|
||||
|
||||
public:
|
||||
Big5Font();
|
||||
|
||||
int getFontHeight() const override;
|
||||
int getMaxCharWidth() const override;
|
||||
int getCharWidth(uint32 chr) const override;
|
||||
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
|
||||
private:
|
||||
void drawBiosFontGlyph(uint8 chr, int x, int y, uint8 color) const;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_BIG5FONT_H
|
||||
3
engines/darkseed/configure.engine
Normal file
3
engines/darkseed/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine darkseed "Darkseed" yes "" "" "highres" "midi"
|
||||
139
engines/darkseed/console.cpp
Normal file
139
engines/darkseed/console.cpp
Normal file
@@ -0,0 +1,139 @@
|
||||
/* 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 "common/debug.h"
|
||||
#include "darkseed/big5font.h"
|
||||
#include "darkseed/kofont.h"
|
||||
#include "darkseed/console.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
static constexpr Common::Rect consoleArea = {{0x70, 277}, 416, 51};
|
||||
|
||||
Console::Console(TosText *tosText, Sound *sound) : _tosText(tosText), _sound(sound) {
|
||||
switch (g_engine->getLanguage()) {
|
||||
case Common::ZH_ANY :
|
||||
_font = new Big5Font();
|
||||
_lineHeight = 17;
|
||||
_numLines = 3;
|
||||
_isCJKLanguage = true;
|
||||
break;
|
||||
case Common::KO_KOR :
|
||||
_font = new KoFont();
|
||||
_lineHeight = 18;
|
||||
_numLines = 3;
|
||||
_isCJKLanguage = true;
|
||||
break;
|
||||
default:
|
||||
_font = new GameFont();
|
||||
_lineHeight = 11;
|
||||
_numLines = 4;
|
||||
break;
|
||||
}
|
||||
|
||||
_text.resize(10);
|
||||
}
|
||||
|
||||
Console::~Console() {
|
||||
delete _font;
|
||||
}
|
||||
|
||||
void Console::clear() {
|
||||
_text.clear();
|
||||
_text.resize(10);
|
||||
_startIdx = 0;
|
||||
_redrawRequired = true;
|
||||
}
|
||||
|
||||
void Console::printTosText(int tosIndex, bool shouldAddToCurrentLine) {
|
||||
if (g_engine->isDosDemo()) {
|
||||
debug("TosIndex: %d", tosIndex);
|
||||
}
|
||||
const Common::U32String &text = _tosText->getText(tosIndex);
|
||||
|
||||
if (!_isCJKLanguage) {
|
||||
debug("%s", text.encode().c_str());
|
||||
} else {
|
||||
debugN("tos %d: ", tosIndex);
|
||||
for (uint i = 0; i < text.size(); i++) {
|
||||
debugN("%02x,", (unsigned char)text[i]);
|
||||
}
|
||||
debug("%s", "");
|
||||
}
|
||||
if (shouldAddToCurrentLine) {
|
||||
addToCurrentLine(text);
|
||||
} else {
|
||||
addTextLine(text);
|
||||
}
|
||||
_sound->playTosSpeech(tosIndex);
|
||||
}
|
||||
|
||||
void Console::addToCurrentLine(const Common::String &text) {
|
||||
addToCurrentLineU32(Common::U32String(text));
|
||||
}
|
||||
|
||||
void Console::addTextLine(const Common::U32String &text) {
|
||||
Common::U32StringArray lines;
|
||||
_font->wordWrapText(text, consoleArea.width(), lines);
|
||||
for (auto &line : lines) {
|
||||
addLine(line);
|
||||
}
|
||||
}
|
||||
|
||||
void Console::addToCurrentLineU32(const Common::U32String &text) {
|
||||
int curIdx = _startIdx == 0 ? _text.size() - 1 : _startIdx - 1;
|
||||
_startIdx = curIdx;
|
||||
addTextLine(_text[_startIdx] + text);
|
||||
}
|
||||
|
||||
void Console::addI18NText(const I18nText &text) {
|
||||
addTextLine(getI18NText(text));
|
||||
}
|
||||
|
||||
void Console::draw(bool forceRedraw) {
|
||||
if (!_redrawRequired && !forceRedraw) {
|
||||
return;
|
||||
}
|
||||
|
||||
g_engine->_screen->fillRect(consoleArea, 0);
|
||||
int curIdx = _startIdx == 0 ? _text.size() - 1 : _startIdx - 1;
|
||||
int y = 0x139;
|
||||
for (int i = 0; i < _numLines && curIdx != _startIdx && !_text[curIdx].empty(); i++) {
|
||||
drawStringAt(0x70, y, _text[curIdx]);
|
||||
y -= _lineHeight;
|
||||
curIdx = curIdx == 0 ? _text.size() - 1 : curIdx - 1;
|
||||
}
|
||||
_redrawRequired = false;
|
||||
g_engine->_screen->addDirtyRect(consoleArea);
|
||||
}
|
||||
|
||||
void Console::drawStringAt(const int x, const int y, const Common::U32String &text) const {
|
||||
_font->drawString(g_engine->_screen, text, x, y, consoleArea.width(), 0);
|
||||
}
|
||||
|
||||
void Console::addLine(const Common::U32String &line) {
|
||||
_text[_startIdx] = line;
|
||||
_startIdx = (_startIdx + 1) % _text.size();
|
||||
_redrawRequired = true;
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
67
engines/darkseed/console.h
Normal file
67
engines/darkseed/console.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_CONSOLE_H
|
||||
#define DARKSEED_CONSOLE_H
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "darkseed/sound.h"
|
||||
#include "darkseed/tostext.h"
|
||||
#include "darkseed/langtext.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Console {
|
||||
private:
|
||||
TosText *_tosText;
|
||||
Graphics::Font *_font;
|
||||
Sound *_sound;
|
||||
|
||||
Common::U32StringArray _text;
|
||||
int _startIdx = 0;
|
||||
bool _redrawRequired = false;
|
||||
int _numLines = 4;
|
||||
int _lineHeight = 11;
|
||||
bool _isCJKLanguage = false;
|
||||
|
||||
public:
|
||||
Console(TosText *tostext, Sound *sound);
|
||||
~Console();
|
||||
|
||||
void clear();
|
||||
|
||||
void printTosText(int tosIndex, bool shouldAddToCurrentLine = false);
|
||||
void addTextLine(const Common::U32String &text);
|
||||
void addToCurrentLine(const Common::String &text);
|
||||
void addToCurrentLineU32(const Common::U32String &text);
|
||||
|
||||
void addI18NText(const I18nText &text);
|
||||
|
||||
void draw(bool forceRedraw = false);
|
||||
void drawStringAt(int x, int y, const Common::U32String &text) const;
|
||||
|
||||
private:
|
||||
void addLine(const Common::U32String &line);
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_CONSOLE_H
|
||||
3
engines/darkseed/credits.pl
Normal file
3
engines/darkseed/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("Darkseed");
|
||||
add_person("Eric Fry", "Yuv422", "");
|
||||
end_section();
|
||||
68
engines/darkseed/cursor.cpp
Normal file
68
engines/darkseed/cursor.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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 "graphics/cursorman.h"
|
||||
#include "darkseed/cursor.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
void Cursor::setCursorType(enum CursorType newType) {
|
||||
bool loadCursor = !_hasLoadedCursor || _currentCursorType != newType;
|
||||
_currentCursorType = newType;
|
||||
|
||||
if (loadCursor) {
|
||||
const Sprite cursorSprite = g_engine->_baseSprites.getSpriteAt(_currentCursorType);
|
||||
Graphics::Surface surf;
|
||||
surf.create(cursorSprite._width, cursorSprite._height, Graphics::PixelFormat::createFormatCLUT8());
|
||||
surf.copyRectToSurface(cursorSprite._pixels.data(), cursorSprite._pitch, 0, 0, cursorSprite._width, cursorSprite._height);
|
||||
CursorMan.replaceCursor(surf, 0, 0, 0xf);
|
||||
surf.free();
|
||||
}
|
||||
}
|
||||
|
||||
void Cursor::updatePosition(int16 x, int16 y) {
|
||||
_position.x = x;
|
||||
_position.y = y;
|
||||
// debug("mouse at (%d,%d)", _x, _y);
|
||||
}
|
||||
|
||||
int Cursor::getWidth() const {
|
||||
return g_engine->_baseSprites.getSpriteAt(_currentCursorType)._width;
|
||||
}
|
||||
|
||||
int Cursor::getHeight() const {
|
||||
return g_engine->_baseSprites.getSpriteAt(_currentCursorType)._height;
|
||||
}
|
||||
|
||||
const Sprite &Darkseed::Cursor::getSprite() const {
|
||||
return g_engine->_baseSprites.getSpriteAt(_currentCursorType);
|
||||
}
|
||||
|
||||
const Sprite &Darkseed::Cursor::getSpriteForType(Darkseed::CursorType cursorType) const {
|
||||
return g_engine->_baseSprites.getSpriteAt(cursorType);
|
||||
}
|
||||
|
||||
void Cursor::showCursor(bool showCursor) {
|
||||
CursorMan.showMouse(showCursor);
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
81
engines/darkseed/cursor.h
Normal file
81
engines/darkseed/cursor.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_CURSOR_H
|
||||
#define DARKSEED_CURSOR_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "darkseed/nsp.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
enum CursorType {
|
||||
Pointer = 0,
|
||||
Hand = 2,
|
||||
Look = 3,
|
||||
HourGlass = 91,
|
||||
ConnectorEntrance = 92,
|
||||
HandPointing = 93,
|
||||
ExclamationMark = 94,
|
||||
};
|
||||
|
||||
class Cursor {
|
||||
private:
|
||||
Common::Point _position;
|
||||
enum CursorType _currentCursorType = Pointer;
|
||||
bool _hasLoadedCursor = false;
|
||||
|
||||
public:
|
||||
|
||||
void showCursor(bool showCursor);
|
||||
void setCursorType(enum CursorType newType);
|
||||
CursorType getCursorType() const {
|
||||
return _currentCursorType;
|
||||
}
|
||||
|
||||
Common::Point &getPosition() {
|
||||
return _position;
|
||||
}
|
||||
void setPosition(Common::Point &position) {
|
||||
_position = position;
|
||||
}
|
||||
|
||||
int16 getX() const {
|
||||
return _position.x;
|
||||
}
|
||||
int16 getY() const {
|
||||
return _position.y;
|
||||
}
|
||||
|
||||
Common::Rect getRect() const {
|
||||
return Common::Rect(_position, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
int getWidth() const;
|
||||
int getHeight() const;
|
||||
const Sprite &getSprite() const;
|
||||
const Sprite &getSpriteForType(CursorType cursorType) const;
|
||||
void updatePosition(int16 x, int16 y);
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_CURSOR_H
|
||||
1477
engines/darkseed/cutscene.cpp
Normal file
1477
engines/darkseed/cutscene.cpp
Normal file
File diff suppressed because it is too large
Load Diff
87
engines/darkseed/cutscene.h
Normal file
87
engines/darkseed/cutscene.h
Normal file
@@ -0,0 +1,87 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_CUTSCENE_H
|
||||
#define DARKSEED_CUTSCENE_H
|
||||
|
||||
#include "darkseed/morph.h"
|
||||
#include "darkseed/pal.h"
|
||||
#include "darkseed/titlefont.h"
|
||||
#include "zhmenufont.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
struct I18NTextWithPosition;
|
||||
|
||||
class Cutscene {
|
||||
char _cutsceneId = 0;
|
||||
uint16 _movieStep = 9999;
|
||||
TitleFont *_titleFont = nullptr;
|
||||
ZhMenuFont *_zhFont = nullptr;
|
||||
Pal _palette;
|
||||
Anm _animation;
|
||||
int _animIdx = 0;
|
||||
int _animCount = 0;
|
||||
int _animDelayCount = 0;
|
||||
int _animDirection = 0;
|
||||
uint32 _startTime = 0;
|
||||
Morph *_morph = nullptr;
|
||||
int _valvesIdx = 0;
|
||||
int _faceIdx = 0;
|
||||
|
||||
public:
|
||||
Cutscene() {}
|
||||
virtual ~Cutscene();
|
||||
void play(char cutsceneId);
|
||||
bool isPlaying() const {
|
||||
return _movieStep != 9999;
|
||||
}
|
||||
void update();
|
||||
|
||||
private:
|
||||
bool introScene();
|
||||
bool embryoInsertedScene();
|
||||
bool shipLaunchScene();
|
||||
bool alienBornScene();
|
||||
bool babyDollScene();
|
||||
bool bookScene();
|
||||
bool nightmare2Scene();
|
||||
bool nightmare3Scene();
|
||||
|
||||
void runAnim(int direction = 1);
|
||||
bool stepAnim(int drawMode = 1);
|
||||
|
||||
bool stepValveAnim(bool doFaceAnim);
|
||||
|
||||
void putHouse();
|
||||
|
||||
void registTime();
|
||||
bool waitTime(int16 duration) const;
|
||||
|
||||
void freeMorph();
|
||||
|
||||
void displayTitleText(const I18NTextWithPosition &text);
|
||||
void displayZhString(const char *text, int y);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_CUTSCENE_H
|
||||
2816
engines/darkseed/darkseed.cpp
Normal file
2816
engines/darkseed/darkseed.cpp
Normal file
File diff suppressed because it is too large
Load Diff
298
engines/darkseed/darkseed.h
Normal file
298
engines/darkseed/darkseed.h
Normal file
@@ -0,0 +1,298 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_H
|
||||
#define DARKSEED_H
|
||||
|
||||
#include "common/error.h"
|
||||
#include "common/fs.h"
|
||||
#include "common/keyboard.h"
|
||||
#include "common/random.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/system.h"
|
||||
#include "common/util.h"
|
||||
#include "engines/engine.h"
|
||||
#include "graphics/screen.h"
|
||||
|
||||
#include "darkseed/animation.h"
|
||||
#include "darkseed/console.h"
|
||||
#include "darkseed/cursor.h"
|
||||
#include "darkseed/cutscene.h"
|
||||
#include "darkseed/detection.h"
|
||||
#include "darkseed/inventory.h"
|
||||
#include "darkseed/menu.h"
|
||||
#include "darkseed/nsp.h"
|
||||
#include "darkseed/objects.h"
|
||||
#include "darkseed/player.h"
|
||||
#include "darkseed/room.h"
|
||||
#include "darkseed/sound.h"
|
||||
#include "darkseed/sprites.h"
|
||||
#include "darkseed/tostext.h"
|
||||
#include "darkseed/usecode.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
struct DarkseedGameDescription;
|
||||
|
||||
enum DarkseedAction {
|
||||
kDarkseedActionNone,
|
||||
kDarkseedActionSelect,
|
||||
kDarkseedActionChangeCommand,
|
||||
kDarkseedActionTimeAdvance,
|
||||
kDarkseedActionQuit,
|
||||
kDarkseedActionSkipCutscene
|
||||
};
|
||||
|
||||
enum ActionMode : uint8 {
|
||||
kPointerAction = 0,
|
||||
kHandAction = 2,
|
||||
kLookAction = 3,
|
||||
kUseStickAction = 19,
|
||||
kUseHammerAction = 27,
|
||||
};
|
||||
|
||||
enum class FadeDirection : uint8 {
|
||||
NONE,
|
||||
IN,
|
||||
OUT
|
||||
};
|
||||
|
||||
class DarkseedEngine : public Engine {
|
||||
const ADGameDescription *_gameDescription;
|
||||
Common::RandomSource _randomSource;
|
||||
Pic *_fullscreenPic = nullptr;
|
||||
bool _timeAdvanceEventSelected = false;
|
||||
uint8 _delbertspeech = 0;
|
||||
int16 _yvec = 0; //delbert throw stick related.
|
||||
bool _normalWorldSpritesLoaded = true;
|
||||
bool _redrawFrame = true;
|
||||
bool _restartGame = false;
|
||||
bool _canSaveGame = false;
|
||||
|
||||
FadeDirection _fadeDirection = FadeDirection::NONE;
|
||||
uint8 _fadeStepCounter = 0;
|
||||
Pal _fadeTempPalette;
|
||||
Pal _fadeTargetPalette;
|
||||
|
||||
protected:
|
||||
// Engine APIs
|
||||
Common::Error run() override;
|
||||
public:
|
||||
Pic _frame;
|
||||
|
||||
bool _ct_voice_status = false;
|
||||
bool _isRightMouseClicked = false;
|
||||
bool _isLeftMouseClicked = false;
|
||||
Common::KeyCode _lastKeyPressed = Common::KeyCode::KEYCODE_INVALID;
|
||||
|
||||
Sound *_sound = nullptr;
|
||||
Nsp _baseSprites;
|
||||
Cursor _cursor;
|
||||
Graphics::Screen *_screen = nullptr;
|
||||
TosText *_tosText = nullptr;
|
||||
Console *_console = nullptr;
|
||||
Room *_room = nullptr;
|
||||
int _actionMode = kPointerAction;
|
||||
Player *_player = nullptr;
|
||||
Sprites _sprites;
|
||||
Objects _objectVar;
|
||||
Inventory _inventory;
|
||||
UseCode *_useCode = nullptr;
|
||||
Cutscene _cutscene;
|
||||
Animation *_animation = nullptr;
|
||||
Menu *_menu = nullptr;
|
||||
|
||||
uint8 _currentDay = 1;
|
||||
int _currentTimeInSeconds = 0x7e8e;
|
||||
int _fttime = 0;
|
||||
|
||||
uint8 _previousRoomNumber = 0;
|
||||
uint16 _targetRoomNumber = 0;
|
||||
|
||||
uint16 _headAcheMessageCounter = 0;
|
||||
uint8 _headacheMessageIdx = 0;
|
||||
|
||||
int _sprite_y_scaling_threshold_maybe = 0xf0;
|
||||
int _scaledWalkSpeed_maybe = 0;
|
||||
uint16 _scaledSpriteWidth = 0;
|
||||
uint16 _scaledSpriteHeight = 0;
|
||||
|
||||
int _frameBottom = 0;
|
||||
|
||||
// Unknown variables
|
||||
bool _doorEnabled = false;
|
||||
bool _useDoorTarget = false;
|
||||
|
||||
int16 _counter_2c85_888b = 0;
|
||||
|
||||
uint8 _targetPlayerDirection = 0; // related to changing rooms.
|
||||
|
||||
uint8 _systemTimerCounter = 0;
|
||||
|
||||
bool _debugShowWalkPath = false;
|
||||
int _phoneStatus = 0;
|
||||
|
||||
int16 _soundTimer = 0;
|
||||
bool _printedcomeheredawson = false;
|
||||
void zeroMouseButtons();
|
||||
void updateEvents();
|
||||
|
||||
void gotoNextMorning();
|
||||
|
||||
void playDayChangeCutscene();
|
||||
|
||||
void removeFullscreenPic();
|
||||
|
||||
void wait();
|
||||
|
||||
void waitForSpeech();
|
||||
void waitForSpeechOrSfx();
|
||||
|
||||
void syncSoundSettings() override;
|
||||
void pauseEngineIntern(bool pause) override;
|
||||
|
||||
DarkseedEngine(OSystem *syst, const ADGameDescription *gameDesc);
|
||||
~DarkseedEngine() override;
|
||||
|
||||
uint32 getFeatures() const;
|
||||
|
||||
Common::Language getLanguage() const {
|
||||
return _gameDescription->language;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the game Id
|
||||
*/
|
||||
Common::String getGameId() const;
|
||||
|
||||
/**
|
||||
* Gets a random number
|
||||
*/
|
||||
uint32 getRandomNumber(uint maxNum) {
|
||||
return _randomSource.getRandomNumber(maxNum);
|
||||
}
|
||||
|
||||
bool isDosVersion() const {
|
||||
return _gameDescription->platform == Common::kPlatformDOS;
|
||||
}
|
||||
|
||||
bool isCdVersion() const {
|
||||
return getFeatures() & ADGF_CD;
|
||||
}
|
||||
|
||||
bool isDosFloppy() const {
|
||||
return isDosVersion() && !isCdVersion();
|
||||
}
|
||||
|
||||
bool isDosDemo() const {
|
||||
return isDosVersion() && getFeatures() & ADGF_DEMO;
|
||||
}
|
||||
|
||||
bool hasFeature(EngineFeature f) const override {
|
||||
return
|
||||
(f == kSupportsLoadingDuringRuntime) ||
|
||||
(f == kSupportsSavingDuringRuntime) ||
|
||||
(f == kSupportsReturnToLauncher);
|
||||
};
|
||||
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg) override {
|
||||
return !isDosDemo() && !_animation->_isPlayingAnimation_maybe && !_player->_isAutoWalkingToBed && !_player->_heroWaiting && !_cutscene.isPlaying();
|
||||
}
|
||||
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg) override {
|
||||
return _canSaveGame && !_animation->_isPlayingAnimation_maybe && !_player->_isAutoWalkingToBed && !_player->_heroWaiting && !_cutscene.isPlaying() && !_menu->isOpen();
|
||||
}
|
||||
|
||||
/**
|
||||
* Uses a serializer to allow implementing savegame
|
||||
* loading and saving using a single method
|
||||
*/
|
||||
Common::Error syncGame(Common::Serializer &s);
|
||||
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override {
|
||||
Common::Serializer s(nullptr, stream);
|
||||
return syncGame(s);
|
||||
}
|
||||
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override {
|
||||
Common::Serializer s(stream, nullptr);
|
||||
Common::Error syncResult = syncGame(s);
|
||||
if (syncResult.getCode() == Common::kNoError) {
|
||||
changeToRoom(_room->_roomNumber);
|
||||
}
|
||||
_canSaveGame = true;
|
||||
return syncResult;
|
||||
}
|
||||
|
||||
Common::Path getRoomFilePath(const Common::Path &filename) const;
|
||||
Common::Path getPictureFilePath(const Common::Path &filename) const;
|
||||
|
||||
void fadeIn(const Pal &palette);
|
||||
void fadeOut();
|
||||
bool fadeStep();
|
||||
|
||||
void restartGame();
|
||||
void newGame();
|
||||
|
||||
void updateDisplay();
|
||||
void debugTeleportToRoom(int newRoomNumber, int entranceNumber);
|
||||
void showFullscreenPic(const Common::Path &filename);
|
||||
void drawFullscreenPic();
|
||||
void lookCode(int objNum);
|
||||
void handleObjCollision(int targetObjNum);
|
||||
void playSound(uint8 sfxId, uint8 priority, int16 unk2);
|
||||
void nextFrame(int nspAminIdx);
|
||||
|
||||
void throwmikeinjail();
|
||||
void runObjects();
|
||||
void getPackageObj(int packageType);
|
||||
void printTime();
|
||||
void changeToRoom(int newRoomNumber, bool placeDirectly = false);
|
||||
void waitxticks(int ticks);
|
||||
|
||||
void doCircles();
|
||||
|
||||
private:
|
||||
void updateBaseSprites();
|
||||
void gameLoop();
|
||||
|
||||
void handleInput();
|
||||
void handlePointerAction();
|
||||
void loadRoom(int roomNumber);
|
||||
|
||||
void gotoSleepInJail();
|
||||
|
||||
void updateHeadache();
|
||||
void closeShops();
|
||||
void initDelbertAtSide();
|
||||
void movePlayerToDelbert();
|
||||
void delbertThrowStick(int16 spriteNum);
|
||||
void leavePackage();
|
||||
void copyLine(const Graphics::Surface &surface, int16 x1, int16 x2, int16 y);
|
||||
};
|
||||
|
||||
extern DarkseedEngine *g_engine;
|
||||
#define SHOULD_QUIT ::Darkseed::g_engine->shouldQuit()
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_H
|
||||
291
engines/darkseed/debugconsole.cpp
Normal file
291
engines/darkseed/debugconsole.cpp
Normal file
@@ -0,0 +1,291 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/debugconsole.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
DebugConsole::DebugConsole(TosText *tosText) : _tosText(tosText) {
|
||||
registerCmd("tostext", WRAP_METHOD(DebugConsole, Cmd_tostext));
|
||||
registerCmd("dt", WRAP_METHOD(DebugConsole, Cmd_dt));
|
||||
registerCmd("getvar", WRAP_METHOD(DebugConsole, Cmd_getvar));
|
||||
registerCmd("setvar", WRAP_METHOD(DebugConsole, Cmd_setvar));
|
||||
registerCmd("enablePathfinderOverlay", WRAP_METHOD(DebugConsole, Cmd_enablePathfinderOverlay));
|
||||
registerCmd("info", WRAP_METHOD(DebugConsole, Cmd_info));
|
||||
registerCmd("gotoRoom", WRAP_METHOD(DebugConsole, Cmd_gotoRoom));
|
||||
registerCmd("invAdd", WRAP_METHOD(DebugConsole, Cmd_invAdd));
|
||||
registerCmd("invRemove", WRAP_METHOD(DebugConsole, Cmd_invRemove));
|
||||
registerCmd("changeDay", WRAP_METHOD(DebugConsole, Cmd_changeDay));
|
||||
registerCmd("searchTos", WRAP_METHOD(DebugConsole, Cmd_searchTos));
|
||||
registerCmd("playMusic", WRAP_METHOD(DebugConsole, Cmd_playMusic));
|
||||
registerCmd("stopMusic", WRAP_METHOD(DebugConsole, Cmd_stopMusic));
|
||||
registerCmd("playSfx", WRAP_METHOD(DebugConsole, Cmd_playSfx));
|
||||
registerCmd("playFloppySfx", WRAP_METHOD(DebugConsole, Cmd_playFloppySfx));
|
||||
registerCmd("playSpeech", WRAP_METHOD(DebugConsole, Cmd_playSpeech));
|
||||
}
|
||||
|
||||
DebugConsole::~DebugConsole() {
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_tostext(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: tostext <index>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint16 textIdx = atoi(argv[1]);
|
||||
if (textIdx < _tosText->getNumEntries()) {
|
||||
debugPrintf("%s\n", _tosText->getText(textIdx).encode().c_str());
|
||||
} else {
|
||||
debugPrintf("index too large!\n");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_dt(int argc, const char **argv) {
|
||||
printDayAndTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_getvar(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: getvar <index>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int16 varIdx = (int16)atoi(argv[1]);
|
||||
|
||||
if (validateObjVarIndex(varIdx)) {
|
||||
debugPrintf("Object Var: %d\n", g_engine->_objectVar.getVar(varIdx));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_setvar(int argc, const char **argv) {
|
||||
if (argc != 3) {
|
||||
debugPrintf("Usage: setvar <index> <newValue>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int16 varIdx = (int16)atoi(argv[1]);
|
||||
int16 newValue = (int16)atoi(argv[2]);
|
||||
|
||||
if (validateObjVarIndex(varIdx)) {
|
||||
g_engine->_objectVar[varIdx] = newValue;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_enablePathfinderOverlay(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: enablePathfinderOverlay <true | t | false | f>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!strcmp(argv[1], "true") || !strcmp(argv[1], "t")) {
|
||||
g_engine->_debugShowWalkPath = true;
|
||||
} else if (!strcmp(argv[1], "false") || !strcmp(argv[1], "f")) {
|
||||
g_engine->_debugShowWalkPath = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::validateObjVarIndex(int16 varIdx) {
|
||||
if (varIdx >= Objects::MAX_OBJECTS) {
|
||||
debugPrintf("Index must be less than %d\n", Objects::MAX_OBJECTS);
|
||||
return false;
|
||||
}
|
||||
if (varIdx < 0) {
|
||||
debugPrintf("Index cannot be negative\n");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_info(int argc, const char **argv) {
|
||||
printDayAndTime();
|
||||
debugPrintf("\nRoom info:\n");
|
||||
debugPrintf("Room number: %d\n", g_engine->_room->_roomNumber);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_gotoRoom(int argc, const char **argv) {
|
||||
if (argc < 2 || argc > 3) {
|
||||
debugPrintf("Usage: gotoRoom <roomNumber> <entranceNumber>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int16 roomNumber = (int16)atoi(argv[1]);
|
||||
int entranceNumber = 0;
|
||||
if (argc == 3) {
|
||||
entranceNumber = (int16)atoi(argv[2]);
|
||||
}
|
||||
|
||||
g_engine->debugTeleportToRoom(roomNumber, entranceNumber);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_invAdd(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: invAdd <objNum>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 objNum = (uint8)atoi(argv[1]);
|
||||
|
||||
g_engine->_inventory.addItem(objNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_invRemove(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: invRemove <objNum>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 objNum = (uint8)atoi(argv[1]);
|
||||
|
||||
g_engine->_inventory.removeItem(objNum);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_changeDay(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: changeDay <newDay>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 newDay = (uint8)atoi(argv[1]);
|
||||
if (newDay < 1 || newDay > 3) {
|
||||
debugPrintf("Error: Day must be in range of 1 .. 3\n");
|
||||
return true;
|
||||
}
|
||||
g_engine->_currentDay = newDay;
|
||||
debugPrintf("Current day changed.\n");
|
||||
printDayAndTime();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_searchTos(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: searchTos \"search string\"\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::String searchString = Common::String(argv[1]);
|
||||
searchString.toLowercase();
|
||||
|
||||
for (int i = 0; i < g_engine->_tosText->getNumEntries(); i++) {
|
||||
Common::String entry = g_engine->_tosText->getText(i);
|
||||
entry.toLowercase();
|
||||
if (entry.contains(searchString)) {
|
||||
debugPrintf("% 3d: %s\n", i, entry.c_str());
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_playMusic(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: playMusic <trackNumber>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 trackNumber = (uint8)atoi(argv[1]);
|
||||
if (trackNumber > 19) {
|
||||
debugPrintf("Error: track number must be in range of 0 .. 19\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
if (trackNumber < 8) {
|
||||
g_engine->_sound->playMusic(static_cast<StartMusicId>(trackNumber));
|
||||
}
|
||||
else {
|
||||
g_engine->_sound->playMusic(static_cast<MusicId>(trackNumber - 7), false);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_stopMusic(int argc, const char** argv) {
|
||||
g_engine->_sound->stopMusic();
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_playSfx(int argc, const char** argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: playSfx <sfxNumber>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 sfxId = (uint8)atoi(argv[1]);
|
||||
if (sfxId > 59) {
|
||||
debugPrintf("Error: SFX number must be in range of 0 .. 59\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_engine->_sound->playSfx(sfxId, 1, -1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_playFloppySfx(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: playFloppySfx <sfxNumber>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
uint8 sfxId = (uint8)atoi(argv[1]);
|
||||
if (sfxId < 10 || sfxId > 119) {
|
||||
debugPrintf("Error: SFX number must be in range of 10 .. 119\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_engine->_sound->playDosFloppySfx(sfxId, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DebugConsole::Cmd_playSpeech(int argc, const char **argv) {
|
||||
if (argc != 2) {
|
||||
debugPrintf("Usage: playSpeech <speechNumber>\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
int speechId = atoi(argv[1]);
|
||||
if (speechId < 0 || speechId > 998) {
|
||||
debugPrintf("Error: speech number must be in range of 0 .. 998\n");
|
||||
return true;
|
||||
}
|
||||
|
||||
g_engine->_sound->playTosSpeech(speechId);
|
||||
return true;
|
||||
}
|
||||
|
||||
void DebugConsole::printDayAndTime() {
|
||||
int hour = g_engine->_currentTimeInSeconds / 3600;
|
||||
debugPrintf("Day %d at %d:%02d%s (%d seconds)\n",
|
||||
g_engine->_currentDay,
|
||||
hour > 12 ? hour - 12 : hour,
|
||||
(g_engine->_currentTimeInSeconds / 60) % 60,
|
||||
hour < 12 ? "AM" : "PM", g_engine->_currentTimeInSeconds);
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
59
engines/darkseed/debugconsole.h
Normal file
59
engines/darkseed/debugconsole.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_DEBUGCONSOLE_H
|
||||
#define DARKSEED_DEBUGCONSOLE_H
|
||||
|
||||
#include "gui/debugger.h"
|
||||
#include "darkseed/tostext.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class DebugConsole : public GUI::Debugger {
|
||||
TosText *_tosText;
|
||||
|
||||
bool Cmd_tostext(int argc, const char **argv);
|
||||
bool Cmd_dt(int argc, const char **argv);
|
||||
bool Cmd_getvar(int argc, const char **argv);
|
||||
bool Cmd_setvar(int argc, const char **argv);
|
||||
bool Cmd_enablePathfinderOverlay(int argc, const char **argv);
|
||||
bool Cmd_info(int argc, const char **argv);
|
||||
bool Cmd_gotoRoom(int argc, const char **argv);
|
||||
bool Cmd_invAdd(int argc, const char **argv);
|
||||
bool Cmd_invRemove(int argc, const char **argv);
|
||||
bool Cmd_changeDay(int argc, const char **argv);
|
||||
bool Cmd_searchTos(int argc, const char **argv);
|
||||
bool Cmd_playMusic(int argc, const char **argv);
|
||||
bool Cmd_stopMusic(int argc, const char **argv);
|
||||
bool Cmd_playSfx(int argc, const char **argv);
|
||||
bool Cmd_playFloppySfx(int argc, const char **argv);
|
||||
bool Cmd_playSpeech(int argc, const char **argv);
|
||||
bool validateObjVarIndex(int16 varIdx);
|
||||
void printDayAndTime();
|
||||
|
||||
public:
|
||||
DebugConsole(TosText *tostext);
|
||||
~DebugConsole() override;
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_DEBUGCONSOLE_H
|
||||
39
engines/darkseed/detection.cpp
Normal file
39
engines/darkseed/detection.cpp
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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 "base/plugins.h"
|
||||
#include "common/file.h"
|
||||
#include "darkseed/detection.h"
|
||||
#include "darkseed/detection_tables.h"
|
||||
|
||||
const DebugChannelDef DarkseedMetaEngineDetection::debugFlagList[] = {
|
||||
{ Darkseed::kDebugGraphics, "Graphics", "Graphics debug level" },
|
||||
{ Darkseed::kDebugPath, "Path", "Pathfinding debug level" },
|
||||
{ Darkseed::kDebugFilePath, "FilePath", "File path debug level" },
|
||||
{ Darkseed::kDebugScan, "Scan", "Scan for unrecognised games" },
|
||||
{ Darkseed::kDebugScript, "Script", "Enable debug script dump" },
|
||||
DEBUG_CHANNEL_END
|
||||
};
|
||||
|
||||
DarkseedMetaEngineDetection::DarkseedMetaEngineDetection() : AdvancedMetaEngineDetection(Darkseed::gameDescriptions, Darkseed::darkseedGames) {
|
||||
}
|
||||
|
||||
REGISTER_PLUGIN_STATIC(DARKSEED_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, DarkseedMetaEngineDetection);
|
||||
77
engines/darkseed/detection.h
Normal file
77
engines/darkseed/detection.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_DETECTION_H
|
||||
#define DARKSEED_DETECTION_H
|
||||
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
enum DarkseedDebugChannels {
|
||||
kDebugGraphics = 1,
|
||||
kDebugPath,
|
||||
kDebugScan,
|
||||
kDebugFilePath,
|
||||
kDebugScript,
|
||||
};
|
||||
|
||||
extern const PlainGameDescriptor darkseedGames[];
|
||||
|
||||
extern const ADGameDescription gameDescriptions[];
|
||||
|
||||
#define GAMEOPTION_ORIGINAL_SAVELOAD GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_FLOPPY_MUSIC GUIO_GAMEOPTIONS2
|
||||
#define GAMEOPTION_SFX_MODE GUIO_GAMEOPTIONS3
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
class DarkseedMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
static const DebugChannelDef debugFlagList[];
|
||||
|
||||
public:
|
||||
DarkseedMetaEngineDetection();
|
||||
~DarkseedMetaEngineDetection() override {}
|
||||
|
||||
const char *getName() const override {
|
||||
return "darkseed";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Darkseed";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "(C) 1992 CYBERDREAMS, INC.";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
enum DarkseedSfxMode {
|
||||
SFX_MODE_CD_ONLY,
|
||||
SFX_MODE_CD_PLUS_FLOPPY,
|
||||
SFX_MODE_FLOPPY_ONLY
|
||||
};
|
||||
|
||||
#endif // DARKSEED_DETECTION_H
|
||||
150
engines/darkseed/detection_tables.h
Normal file
150
engines/darkseed/detection_tables.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
const PlainGameDescriptor darkseedGames[] = {
|
||||
{ "darkseed", "Darkseed" },
|
||||
{ 0, 0 }
|
||||
};
|
||||
|
||||
const ADGameDescription gameDescriptions[] = {
|
||||
{
|
||||
"darkseed",
|
||||
nullptr,
|
||||
AD_ENTRY1s("TOS.EXE", "e20ca609f2acb623e0076ef2288673b2", 147016),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
{ // version 1.2
|
||||
"darkseed",
|
||||
nullptr,
|
||||
AD_ENTRY1s("TOS.EXE", "9fad9d0a4b5e7d0657172593750c7b81", 214784),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
nullptr,
|
||||
AD_ENTRY1s("TOS.EXE", "73854f950819beb0eb0d73bd52cc9030", 149412),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
nullptr,
|
||||
AD_ENTRY1s("TOS.EXE", "ba87f00c3a51ca3e3bb218fc58f128eb", 121662),
|
||||
Common::ZH_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
{ // unpacked exe
|
||||
"darkseed",
|
||||
"unpacked",
|
||||
AD_ENTRY1s("TOS.EXE", "0fc2751aa16cac26ad3aa9d1cbbb5c7b", 209208),
|
||||
Common::ZH_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
nullptr,
|
||||
AD_ENTRY1s("TOS.EXE", "62a636d3d6b19336d059cd2f8b1a365f", 154450),
|
||||
Common::KO_KOR,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
"CD",
|
||||
AD_ENTRY1s("TOS.EXE", "679abf5829b2453d30b17caabafea168", 168432),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
|
||||
},
|
||||
{ // 1.51 according to DS.BAT, 1.5P according to intro
|
||||
"darkseed",
|
||||
"CD",
|
||||
AD_ENTRY1s("TOS.EXE", "afaeb490ef8e7625008867aa8f20c703", 168480),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
"CD",
|
||||
AD_ENTRY1s("TOS.EXE", "57581682c29fc7d242b463210b6e54b4", 144422),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
"CD",
|
||||
AD_ENTRY1s("TOS.EXE", "9b8cdd3b4268d18babf7629fca6a271e", 143534),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
"CD",
|
||||
AD_ENTRY1s("TOS.EXE", "3c00f3e80fa2c40641278243f96b8398", 170944),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_CD,
|
||||
GUIO2(GAMEOPTION_FLOPPY_MUSIC, GAMEOPTION_SFX_MODE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
"CD",
|
||||
AD_ENTRY1s("DARKSEED.EXE", "27321d178a553c4dc17d1a2a601a9a6f", 1432140),
|
||||
Common::JA_JPN,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE | ADGF_CD,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
{
|
||||
"darkseed",
|
||||
"DEMO",
|
||||
AD_ENTRY1s("TOS.EXE", "43014b73a2cc549bd13d65b18a6aefe4", 161184),
|
||||
Common::EN_ANY,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NONE)
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
144
engines/darkseed/dialogs.cpp
Normal file
144
engines/darkseed/dialogs.cpp
Normal file
@@ -0,0 +1,144 @@
|
||||
/* 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 "base/plugins.h"
|
||||
#include "common/file.h"
|
||||
#include "common/hashmap.h"
|
||||
#include "common/ptr.h"
|
||||
#include "common/translation.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
#include "darkseed/detection.h"
|
||||
#include "darkseed/dialogs.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
OptionsWidget::OptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain) : OptionsContainerWidget(boss, name, "DarkseedGameOptionsDialog", domain) {
|
||||
_guiOptions = ConfMan.get("guioptions", domain);
|
||||
|
||||
for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
|
||||
if (checkGameGUIOption(entry->guioFlag, _guiOptions))
|
||||
_checkboxes[entry->option.configOption] = new GUI::CheckboxWidget(widgetsBoss(), _dialogLayout + "." + entry->option.configOption, _(entry->option.label), _(entry->option.tooltip));
|
||||
|
||||
for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry)
|
||||
if (checkGameGUIOption(entry->guioFlag, _guiOptions)) {
|
||||
GUI::StaticTextWidget *textWidget = new GUI::StaticTextWidget(widgetsBoss(), _dialogLayout + "." + entry->configOption + "_desc", _(entry->label), _(entry->tooltip));
|
||||
textWidget->setAlign(Graphics::kTextAlignRight);
|
||||
|
||||
_popUps[entry->configOption] = new GUI::PopUpWidget(widgetsBoss(), _dialogLayout + "." + entry->configOption);
|
||||
|
||||
for (uint i = 0; entry->items[i].label; ++i)
|
||||
_popUps[entry->configOption]->appendEntry(_(entry->items[i].label), entry->items[i].configValue);
|
||||
}
|
||||
}
|
||||
|
||||
void OptionsWidget::defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const {
|
||||
layouts.addDialog(layoutName, overlayedLayout);
|
||||
layouts.addLayout(GUI::ThemeLayout::kLayoutVertical).addPadding(0, 0, 0, 0);
|
||||
|
||||
for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
|
||||
layouts.addWidget(entry->option.configOption, "Checkbox");
|
||||
|
||||
for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry) {
|
||||
layouts.addLayout(GUI::ThemeLayout::kLayoutHorizontal).addPadding(0, 0, 0, 0);
|
||||
layouts.addWidget(Common::String(entry->configOption) + "_desc", "OptionsLabel");
|
||||
layouts.addWidget(entry->configOption, "PopUp").closeLayout();
|
||||
}
|
||||
|
||||
layouts.closeLayout().closeDialog();
|
||||
}
|
||||
|
||||
void OptionsWidget::load() {
|
||||
for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
|
||||
if (checkGameGUIOption(entry->guioFlag, _guiOptions))
|
||||
_checkboxes[entry->option.configOption]->setState(ConfMan.getBool(entry->option.configOption, _domain));
|
||||
|
||||
for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry)
|
||||
if (checkGameGUIOption(entry->guioFlag, _guiOptions))
|
||||
_popUps[entry->configOption]->setSelectedTag(ConfMan.getInt(entry->configOption, _domain));
|
||||
}
|
||||
|
||||
bool OptionsWidget::save() {
|
||||
for (const ADExtraGuiOptionsMap *entry = optionsList; entry->guioFlag; ++entry)
|
||||
if (checkGameGUIOption(entry->guioFlag, _guiOptions))
|
||||
ConfMan.setBool(entry->option.configOption, _checkboxes[entry->option.configOption]->getState(), _domain);
|
||||
|
||||
for (const PopUpOptionsMap *entry = popUpOptionsList; entry->guioFlag; ++entry)
|
||||
if (checkGameGUIOption(entry->guioFlag, _guiOptions))
|
||||
ConfMan.setInt(entry->configOption, _popUps[entry->configOption]->getSelectedTag(), _domain);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_ORIGINAL_SAVELOAD,
|
||||
{
|
||||
_s("Use original save/load screens"),
|
||||
_s("Use the original save/load screens instead of the ScummVM ones"),
|
||||
"original_menus",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_FLOPPY_MUSIC,
|
||||
{
|
||||
_s("Use floppy version music"),
|
||||
_s("Use the music from the floppy version. The floppy version's music files must be copied to the SOUND directory."),
|
||||
"use_floppy_music",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
|
||||
const PopUpOptionsMap popUpOptionsList[] = {
|
||||
{
|
||||
GAMEOPTION_SFX_MODE,
|
||||
_s("SFX mode:"),
|
||||
_s("Determines if the game should use CD version SFX only, CD SFX with additional floppy SFX, or floppy SFX only. Floppy SFX are only available if floppy music is used."),
|
||||
"sfx_mode",
|
||||
SFX_MODE_CD_ONLY,
|
||||
{
|
||||
{
|
||||
_s("CD version SFX only"),
|
||||
SFX_MODE_CD_ONLY
|
||||
},
|
||||
{
|
||||
_s("CD + extra floppy SFX"),
|
||||
SFX_MODE_CD_PLUS_FLOPPY
|
||||
},
|
||||
{
|
||||
_s("Floppy version SFX only"),
|
||||
SFX_MODE_FLOPPY_ONLY
|
||||
},
|
||||
POPUP_OPTIONS_ITEMS_TERMINATOR
|
||||
}
|
||||
},
|
||||
POPUP_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
74
engines/darkseed/dialogs.h
Normal file
74
engines/darkseed/dialogs.h
Normal file
@@ -0,0 +1,74 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_DIALOGS_H
|
||||
#define DARKSEED_DIALOGS_H
|
||||
|
||||
#include "gui/ThemeEval.h"
|
||||
#include "gui/widget.h"
|
||||
#include "gui/widgets/popup.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
struct PopUpOptionsItem {
|
||||
const char *label;
|
||||
int configValue;
|
||||
};
|
||||
|
||||
#define POPUP_OPTIONS_ITEMS_TERMINATOR {nullptr, 0}
|
||||
|
||||
struct PopUpOptionsMap {
|
||||
const char *guioFlag;
|
||||
const char *label;
|
||||
const char *tooltip;
|
||||
const char *configOption;
|
||||
int defaultState;
|
||||
PopUpOptionsItem items[10];
|
||||
};
|
||||
|
||||
#define POPUP_OPTIONS_TERMINATOR \
|
||||
{ \
|
||||
nullptr, nullptr, nullptr, nullptr, 0, { POPUP_OPTIONS_ITEMS_TERMINATOR } \
|
||||
}
|
||||
|
||||
class OptionsWidget : public GUI::OptionsContainerWidget {
|
||||
public:
|
||||
explicit OptionsWidget(GuiObject *boss, const Common::String &name, const Common::String &domain);
|
||||
|
||||
// OptionsContainerWidget API
|
||||
void load() override;
|
||||
bool save() override;
|
||||
|
||||
private:
|
||||
// OptionsContainerWidget API
|
||||
void defineLayout(GUI::ThemeEval &layouts, const Common::String &layoutName, const Common::String &overlayedLayout) const override;
|
||||
|
||||
Common::String _guiOptions;
|
||||
Common::HashMap<Common::String, GUI::CheckboxWidget *> _checkboxes;
|
||||
Common::HashMap<Common::String, GUI::PopUpWidget *> _popUps;
|
||||
};
|
||||
|
||||
extern const ADExtraGuiOptionsMap optionsList[];
|
||||
extern const PopUpOptionsMap popUpOptionsList[];
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_DIALOGS_H
|
||||
118
engines/darkseed/gamefont.cpp
Normal file
118
engines/darkseed/gamefont.cpp
Normal file
@@ -0,0 +1,118 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/gamefont.h"
|
||||
|
||||
namespace Darkseed {
|
||||
extern DarkseedEngine *g_engine;
|
||||
|
||||
GameFont::GameFont() {
|
||||
if (_letters.load("tosfont.nsp")) {
|
||||
_maxWidth = _letters.getMaxSpriteWidth() + 1;
|
||||
} else {
|
||||
error("Error loading tosfont.nsp");
|
||||
}
|
||||
}
|
||||
|
||||
const Sprite *GameFont::getCharacterSprite(char c) const {
|
||||
int letterIdx = 1000;
|
||||
switch (c) {
|
||||
case 0x20 :
|
||||
case 0x2d :
|
||||
letterIdx = 0x46;
|
||||
break;
|
||||
case 0x21 :
|
||||
letterIdx = 0x36;
|
||||
break;
|
||||
case 0x22 :
|
||||
case 0x5e :
|
||||
letterIdx = 0x3a;
|
||||
break;
|
||||
case 0x27 :
|
||||
letterIdx = 0x45;
|
||||
break;
|
||||
case 0x28 :
|
||||
letterIdx = 0x37;
|
||||
break;
|
||||
case 0x29 :
|
||||
letterIdx = 0x38;
|
||||
break;
|
||||
case 0x2b :
|
||||
letterIdx = 0xa;
|
||||
break;
|
||||
case 0x2c :
|
||||
letterIdx = 0x34;
|
||||
break;
|
||||
case 0x2e :
|
||||
letterIdx = 0x35;
|
||||
break;
|
||||
case 0x3a :
|
||||
letterIdx = 0x47;
|
||||
break;
|
||||
case 0x3f :
|
||||
letterIdx = 0x39;
|
||||
break;
|
||||
|
||||
default: {
|
||||
if (c < 0x41 || c > 0x5a) {
|
||||
if (c < 0x61 || c > 0x7a) {
|
||||
if (c > 0x2f && c < 0x3a) {
|
||||
letterIdx = c + 0xb;
|
||||
}
|
||||
} else {
|
||||
letterIdx = c - 0x61;
|
||||
}
|
||||
} else {
|
||||
letterIdx = c - 0x27;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (letterIdx != 1000) {
|
||||
return &_letters.getSpriteAt(letterIdx);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int GameFont::getFontHeight() const {
|
||||
return 10;
|
||||
}
|
||||
|
||||
int GameFont::getMaxCharWidth() const {
|
||||
return _maxWidth;
|
||||
}
|
||||
|
||||
int GameFont::getCharWidth(uint32 chr) const {
|
||||
auto letter = getCharacterSprite((char)chr);
|
||||
return letter ? letter->_width + 1 : 0;
|
||||
}
|
||||
|
||||
void GameFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
|
||||
auto letter = getCharacterSprite((char)chr);
|
||||
if (letter) {
|
||||
letter->draw(dst, x, y);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
50
engines/darkseed/gamefont.h
Normal file
50
engines/darkseed/gamefont.h
Normal file
@@ -0,0 +1,50 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_GAMEFONT_H
|
||||
#define DARKSEED_GAMEFONT_H
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "darkseed/nsp.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class GameFont : public Graphics::Font {
|
||||
private:
|
||||
Nsp _letters;
|
||||
int _maxWidth = 0;
|
||||
|
||||
public:
|
||||
GameFont();
|
||||
|
||||
int getFontHeight() const override;
|
||||
int getMaxCharWidth() const override;
|
||||
int getCharWidth(uint32 chr) const override;
|
||||
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
|
||||
|
||||
private:
|
||||
const Sprite *getCharacterSprite(char c) const;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_GAMEFONT_H
|
||||
137
engines/darkseed/img.cpp
Normal file
137
engines/darkseed/img.cpp
Normal file
@@ -0,0 +1,137 @@
|
||||
/* 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 "common/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
#include "darkseed/img.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
bool Img::load(const Common::Path &filename) {
|
||||
Common::File file;
|
||||
if (!file.open(filename)) {
|
||||
return false;
|
||||
}
|
||||
bool ret = load(file);
|
||||
file.close();
|
||||
if (ret) {
|
||||
debug("Loaded %s (%d,%d) (%d,%d) %x", filename.toString().c_str(), _x, _y, _width, _height, _mode);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Img::load(Common::SeekableReadStream &readStream) {
|
||||
Common::Array<uint8> unpackedData;
|
||||
unpackRLE(readStream, unpackedData);
|
||||
_x = (uint16)READ_LE_INT16(&unpackedData.data()[0]);
|
||||
_y = (uint16)READ_LE_INT16(&unpackedData.data()[2]);
|
||||
unpackPlanarData(unpackedData, 4);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Img::loadWithoutPosition(Common::SeekableReadStream &readStream) {
|
||||
Common::Array<uint8> unpackedData;
|
||||
unpackRLE(readStream, unpackedData);
|
||||
_x = 0;
|
||||
_y = 0;
|
||||
unpackPlanarData(unpackedData, 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Img::unpackRLE(Common::SeekableReadStream &readStream, Common::Array<byte> &buf) {
|
||||
uint16 size = readStream.readUint16LE();
|
||||
uint16 idx = 0;
|
||||
buf.resize(size + 1);
|
||||
|
||||
while (idx <= size) {
|
||||
uint8 byte = readStream.readByte();
|
||||
assert(!readStream.err());
|
||||
if (byte & 0x80) {
|
||||
uint8 count = byte & 0x7f;
|
||||
count++;
|
||||
byte = readStream.readByte();
|
||||
for (int i = 0; i < count && idx + i < size; i++) {
|
||||
buf[idx + i] = byte;
|
||||
}
|
||||
idx += count;
|
||||
} else {
|
||||
uint8 count = byte + 1;
|
||||
for (int i = 0; i < count && idx + i < size; i++) {
|
||||
buf[idx + i] = readStream.readByte();
|
||||
}
|
||||
idx += count;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Img::unpackPlanarData(Common::Array<uint8> &planarData, uint16 headerOffset) {
|
||||
_height = (uint16)READ_LE_INT16(&planarData.data()[headerOffset]);
|
||||
_width = (uint16)READ_LE_INT16(&planarData.data()[headerOffset + 2]) * 8;
|
||||
_mode = planarData.data()[headerOffset + 4];
|
||||
// assert(mode == 0xff);
|
||||
_pixels.resize(_width * _height, 0);
|
||||
for (int py = 0; py < _height; py++) {
|
||||
for (int plane = 0; plane < 4; plane++) {
|
||||
for (int px = 0; px < _width; px++) {
|
||||
int bitPos = (7 - (px % 8));
|
||||
int planeBit = (planarData[(headerOffset + 5) + (px / 8) + (_width / 8) * plane + py * (_width / 8) * 4] & (1 << bitPos)) >> bitPos;
|
||||
_pixels[px + py * _width] |= planeBit << (3 - plane);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Common::Array<uint8> &Img::getPixels() {
|
||||
return _pixels;
|
||||
}
|
||||
|
||||
void Img::draw(int drawMode, int drawWidth) {
|
||||
drawAt(_x, _y, drawMode, drawWidth);
|
||||
}
|
||||
|
||||
void Img::drawAt(uint16 xPos, uint16 yPos, int drawMode, int drawWidth) {
|
||||
int w = drawWidth != 0 ? drawWidth : _width;
|
||||
if (drawMode != 0) {
|
||||
uint8 *screen = (uint8 *)g_engine->_screen->getBasePtr(xPos, yPos);
|
||||
uint8 *imgPixels = _pixels.data();
|
||||
for (int sy = 0; sy < _height; sy++) {
|
||||
for (int sx = 0; sx < w; sx++) {
|
||||
if (drawMode == 1 && imgPixels[sx] != 0) {
|
||||
screen[sx] ^= imgPixels[sx];
|
||||
} else if (drawMode == 2 && imgPixels[sx] != 15) {
|
||||
screen[sx] &= imgPixels[sx];
|
||||
} else if (drawMode == 3 && imgPixels[sx] != 0) {
|
||||
screen[sx] |= imgPixels[sx];
|
||||
}
|
||||
}
|
||||
imgPixels += _width;
|
||||
screen += g_engine->_screen->pitch;
|
||||
}
|
||||
} else {
|
||||
g_engine->_screen->copyRectToSurface(_pixels.data(), _width, xPos, yPos, w, _height);
|
||||
}
|
||||
g_engine->_screen->addDirtyRect({{(int16)xPos, (int16)yPos}, (int16)w, (int16)_height});
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
67
engines/darkseed/img.h
Normal file
67
engines/darkseed/img.h
Normal file
@@ -0,0 +1,67 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_IMG_H
|
||||
#define DARKSEED_IMG_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Img {
|
||||
uint16 _x = 0;
|
||||
uint16 _y = 0;
|
||||
uint16 _width = 0;
|
||||
uint16 _height = 0;
|
||||
byte _mode = 0;
|
||||
Common::Array<uint8> _pixels;
|
||||
|
||||
public:
|
||||
bool load(const Common::Path &filename);
|
||||
bool load(Common::SeekableReadStream &readStream);
|
||||
bool loadWithoutPosition(Common::SeekableReadStream &readStream);
|
||||
void draw(int drawMode = 0, int drawWidth = 0);
|
||||
void drawAt(uint16 xPos, uint16 yPos, int drawMode = 0, int drawWidth = 0);
|
||||
|
||||
Common::Array<uint8> &getPixels();
|
||||
uint16 getX() const {
|
||||
return _x;
|
||||
}
|
||||
uint16 getY() const {
|
||||
return _y;
|
||||
}
|
||||
uint16 getWidth() const {
|
||||
return _width;
|
||||
}
|
||||
uint16 getHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
private:
|
||||
bool unpackRLE(Common::SeekableReadStream &readStream, Common::Array<uint8> &buf);
|
||||
void unpackPlanarData(Common::Array<uint8> &planarData, uint16 headerOffset);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_IMG_H
|
||||
227
engines/darkseed/inventory.cpp
Normal file
227
engines/darkseed/inventory.cpp
Normal file
@@ -0,0 +1,227 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/inventory.h"
|
||||
#include "darkseed/menu.h"
|
||||
#include "darkseed/kofont.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
constexpr uint16 MAX_INVENTORY = 42;
|
||||
constexpr uint16 MAX_ICONS = 9;
|
||||
static constexpr Common::Rect drawArea = {{139, 0}, 334, 40};
|
||||
|
||||
Inventory::Inventory() {
|
||||
_iconList.resize(MAX_ICONS);
|
||||
_inventory.resize(MAX_INVENTORY);
|
||||
reset();
|
||||
}
|
||||
|
||||
void Inventory::reset() {
|
||||
_viewOffset = 0;
|
||||
_inventory[0] = 8;
|
||||
_inventoryLength = 1;
|
||||
update();
|
||||
}
|
||||
|
||||
void Inventory::addItem(uint8 item) {
|
||||
_inventory[_inventoryLength] = item;
|
||||
_inventoryLength++;
|
||||
g_engine->playSound(6, 5, -1);
|
||||
update();
|
||||
}
|
||||
|
||||
void Inventory::removeItem(uint8 item) {
|
||||
for (int i = 0; i < _inventoryLength; i++) {
|
||||
if (_inventory[i] == item) {
|
||||
for (int j = i; j < _inventoryLength - 1; j++) {
|
||||
_inventory[j] = _inventory[j + 1];
|
||||
}
|
||||
_inventoryLength--;
|
||||
update();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::update() {
|
||||
if (_viewOffset != 0) {
|
||||
if (_inventoryLength <= _viewOffset + (MAX_ICONS - 1)) {
|
||||
_viewOffset = _inventoryLength - (MAX_ICONS - 1);
|
||||
}
|
||||
if (_viewOffset > 50) {
|
||||
_viewOffset = 0;
|
||||
}
|
||||
}
|
||||
_iconList[0] = 4;
|
||||
if (_inventoryLength + 1 < MAX_ICONS) {
|
||||
_viewOffset = 0;
|
||||
for (int i = 0; i < _inventoryLength; i++) {
|
||||
_iconList[i + 1] = _inventory[i];
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < MAX_ICONS - 1; i++) {
|
||||
_iconList[i + 1] = _inventory[_viewOffset + i];
|
||||
}
|
||||
if (_viewOffset + 8 < _inventoryLength) {
|
||||
_iconList[8] = 43;
|
||||
}
|
||||
if (_viewOffset != 0) {
|
||||
_iconList[1] = 42;
|
||||
}
|
||||
}
|
||||
_numIcons = MIN(_inventoryLength + 1, 9);
|
||||
_redraw = true;
|
||||
}
|
||||
|
||||
void Inventory::restoreFrame() {
|
||||
g_engine->_frame.drawRect(drawArea);
|
||||
g_engine->_screen->addDirtyRect(drawArea);
|
||||
}
|
||||
|
||||
void Inventory::draw() {
|
||||
if ((g_engine->_actionMode <= 4 && g_engine->_cursor.getY() > 40) || g_engine->_animation->_isPlayingAnimation_maybe || (g_engine->_objectVar[141] >= 1 && g_engine->_objectVar[141] <= 3)) {
|
||||
if (_isVisible) {
|
||||
restoreFrame();
|
||||
_isVisible = false;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (_redraw) {
|
||||
restoreFrame();
|
||||
_redraw = false;
|
||||
}
|
||||
|
||||
_isVisible = true;
|
||||
for (int i = 0; i < _numIcons; i++) {
|
||||
int icon = _iconList[i];
|
||||
if (icon != 42 && icon != 43) {
|
||||
icon += g_engine->isDosDemo() ? 36 : 42;
|
||||
}
|
||||
|
||||
if (g_engine->_actionMode == _iconList[i] && g_engine->_actionMode > 4) {
|
||||
const Sprite &selectedSprite = g_engine->_baseSprites.getSpriteAt(95);
|
||||
g_engine->_sprites.addSpriteToDrawList(139 + i * 37, 20 - selectedSprite._height / 2, &selectedSprite, 255, selectedSprite._width, selectedSprite._height, false);
|
||||
}
|
||||
const Sprite &iconSprite = g_engine->_baseSprites.getSpriteAt(icon);
|
||||
g_engine->_sprites.addSpriteToDrawList(140 + i * 37, 20 - iconSprite._height / 2, &iconSprite, 255, iconSprite._width, iconSprite._height, false);
|
||||
}
|
||||
g_engine->_screen->addDirtyRect(drawArea);
|
||||
}
|
||||
|
||||
void Inventory::handleClick() {
|
||||
Common::Point clickPos = g_engine->_cursor.getPosition();
|
||||
if (clickPos.x < 140 || clickPos.x > 140 + _numIcons * 37) {
|
||||
return;
|
||||
}
|
||||
int iconIdx = (clickPos.x - 140) / 37;
|
||||
int icon = _iconList[iconIdx];
|
||||
g_engine->playSound(5, 4, -1);
|
||||
if (icon == 42) {
|
||||
leftArrowClicked();
|
||||
} else if (icon == 43) {
|
||||
rightArrowClicked();
|
||||
} else if (icon == 4) {
|
||||
if (g_engine->isDosDemo()) {
|
||||
g_engine->_console->addTextLine(Common::U32String("You can't load or save games in demo mode, press 'q' to exit."));
|
||||
} else {
|
||||
g_engine->_menu->loadMenu();
|
||||
}
|
||||
} else if (icon == 21) {
|
||||
g_engine->_console->printTosText(935);
|
||||
g_engine->_objectVar[21] = 1;
|
||||
g_engine->_room->_collisionType = 1;
|
||||
g_engine->_room->removeObjectFromRoom(21);
|
||||
removeItem(21);
|
||||
} else if ((g_engine->_actionMode == 25 && icon == 20) ||
|
||||
(g_engine->_actionMode == 20 && icon == 25)
|
||||
) {
|
||||
g_engine->handleObjCollision(icon);
|
||||
} else if (g_engine->_actionMode == kHandAction && icon == 35) {
|
||||
g_engine->_objectVar[35] = 28800; // wind watch
|
||||
g_engine->_console->printTosText(669);
|
||||
} else if (g_engine->_actionMode == kLookAction) {
|
||||
g_engine->lookCode(icon);
|
||||
} else {
|
||||
g_engine->_actionMode = icon;
|
||||
if (g_engine->getLanguage() == Common::KO_KOR) {
|
||||
g_engine->_console->addTextLine(KoFont::getObjectString(g_engine->_objectVar.getObjectName(icon)));
|
||||
g_engine->_console->printTosText(972, true);
|
||||
} else {
|
||||
g_engine->_console->printTosText(972);
|
||||
g_engine->_console->addToCurrentLine(formatInjectStrings(Common::U32String("%s.").c_str(), g_engine->_objectVar.getObjectName(icon).c_str()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::leftArrowClicked() {
|
||||
if (_viewOffset > 0) {
|
||||
_viewOffset--;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
void Inventory::rightArrowClicked() {
|
||||
_viewOffset++;
|
||||
update();
|
||||
}
|
||||
|
||||
Common::Error Inventory::sync(Common::Serializer &s) {
|
||||
s.syncAsSint16LE(_inventoryLength);
|
||||
for (int i = 0; i < _inventoryLength; i++) {
|
||||
s.syncAsByte(_inventory[i]);
|
||||
}
|
||||
_viewOffset = 0;
|
||||
update();
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void Inventory::endOfDayOutsideLogic() {
|
||||
for (int i = 0; i < _inventoryLength; i++) {
|
||||
g_engine->_objectVar.setMoveObjectRoom(_inventory[i], _inventory[i] == 28 ? 255 : 252);
|
||||
}
|
||||
_inventoryLength = 0;
|
||||
_viewOffset = 0;
|
||||
g_engine->_objectVar[53] = 2;
|
||||
}
|
||||
|
||||
void Inventory::gotoJailLogic() {
|
||||
for (int i = 0; i < _inventoryLength; i++) {
|
||||
g_engine->_objectVar.setMoveObjectRoom(_inventory[i], 100);
|
||||
}
|
||||
g_engine->_objectVar.setMoveObjectRoom(28, 255);
|
||||
_inventoryLength = 0;
|
||||
_viewOffset = 0;
|
||||
update();
|
||||
}
|
||||
|
||||
bool Inventory::hasObject(uint8 objNum) {
|
||||
for (int i = 0; i < _inventoryLength; i++) {
|
||||
if (_inventory[i] == objNum) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
59
engines/darkseed/inventory.h
Normal file
59
engines/darkseed/inventory.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_INVENTORY_H
|
||||
#define DARKSEED_INVENTORY_H
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Inventory {
|
||||
Common::Array<uint8> _inventory;
|
||||
int16 _inventoryLength = 0;
|
||||
Common::Array<uint8> _iconList;
|
||||
int _viewOffset = 0;
|
||||
int _numIcons = 0;
|
||||
bool _isVisible = false;
|
||||
bool _redraw = false;
|
||||
|
||||
public:
|
||||
Inventory();
|
||||
void reset();
|
||||
void addItem(uint8 item);
|
||||
void removeItem(uint8 item);
|
||||
void draw();
|
||||
void handleClick();
|
||||
void endOfDayOutsideLogic();
|
||||
void gotoJailLogic();
|
||||
bool hasObject(uint8 objNum);
|
||||
|
||||
Common::Error sync(Common::Serializer &s);
|
||||
|
||||
private:
|
||||
void update();
|
||||
void leftArrowClicked();
|
||||
void rightArrowClicked();
|
||||
void restoreFrame();
|
||||
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_INVENTORY_H
|
||||
96
engines/darkseed/kidpic.cpp
Normal file
96
engines/darkseed/kidpic.cpp
Normal file
@@ -0,0 +1,96 @@
|
||||
/* 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 "common/debug.h"
|
||||
#include "common/file.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
#include "darkseed/kidpic.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
static constexpr int BYTES_PER_LINE = 320;
|
||||
static constexpr int BYTES_PER_PLANE = 80;
|
||||
|
||||
static constexpr int KID_WIDTH = 640;
|
||||
static constexpr int KID_HEIGHT = 350;
|
||||
|
||||
KidPic::KidPic() {
|
||||
_pixels.resize(KID_WIDTH * KID_HEIGHT);
|
||||
Common::File file;
|
||||
if (!file.open("kid.pic")) {
|
||||
error("Failed to open kid.pic");
|
||||
}
|
||||
|
||||
file.seek(0x10);
|
||||
Pal pal;
|
||||
pal.loadFromStream(file, false);
|
||||
pal.swapEntries(14, 4); // not sure why we need to swap these palette entries. All the other entries line up correctly.
|
||||
pal.installPalette();
|
||||
unpackRLE(file);
|
||||
}
|
||||
|
||||
bool KidPic::unpackRLE(Common::SeekableReadStream &readStream) {
|
||||
uint idx = 0;
|
||||
uint unpackedSize = _pixels.size() / 2;
|
||||
|
||||
readStream.seek(0x80);
|
||||
|
||||
while (idx < unpackedSize && !readStream.eos()) {
|
||||
uint8 byte = readStream.readByte();
|
||||
assert(!readStream.err());
|
||||
|
||||
uint repeat = 1;
|
||||
if ((byte & 192) == 192) {
|
||||
repeat = (byte & 63);
|
||||
byte = readStream.readByte();
|
||||
assert(!readStream.err());
|
||||
}
|
||||
|
||||
for (uint j = 0; j < repeat; j++) {
|
||||
unpackByte(byte);
|
||||
}
|
||||
idx += repeat;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// image is stored as 4 x 1-bit planes per line.
|
||||
void KidPic::unpackByte(uint8 byte) {
|
||||
int planeOffset = _lineByteIdx / BYTES_PER_PLANE;
|
||||
int x = _lineByteIdx % BYTES_PER_PLANE;
|
||||
for (int i = 0; i < 8; i++) {
|
||||
if (byte & 1 << (7 - i)) {
|
||||
_pixels[_lineNum * KID_WIDTH + (x * 8) + i] |= 1 << planeOffset;
|
||||
}
|
||||
}
|
||||
_lineByteIdx++;
|
||||
if (_lineByteIdx == BYTES_PER_LINE) {
|
||||
_lineByteIdx = 0;
|
||||
_lineNum++;
|
||||
}
|
||||
}
|
||||
|
||||
void KidPic::draw() {
|
||||
g_engine->_screen->copyRectToSurface(_pixels.data(), KID_WIDTH, 0, 0, KID_WIDTH, KID_HEIGHT);
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
47
engines/darkseed/kidpic.h
Normal file
47
engines/darkseed/kidpic.h
Normal file
@@ -0,0 +1,47 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_KIDPIC_H
|
||||
#define DARKSEED_KIDPIC_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "common/file.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class KidPic {
|
||||
Common::Array<uint8> _pixels;
|
||||
int _lineNum = 0;
|
||||
int _lineByteIdx = 0;
|
||||
|
||||
public:
|
||||
KidPic();
|
||||
void draw();
|
||||
|
||||
private:
|
||||
bool unpackRLE(Common::SeekableReadStream &readStream);
|
||||
void unpackByte(uint8 byte);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_KIDPIC_H
|
||||
311
engines/darkseed/kofont.cpp
Normal file
311
engines/darkseed/kofont.cpp
Normal file
@@ -0,0 +1,311 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/kofont.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
KoFont::KoFont() {
|
||||
Common::File fontData;
|
||||
if (!fontData.open("k16.bin")) {
|
||||
error("Error: failed to open k16.bin");
|
||||
}
|
||||
|
||||
loadFontDataSet(_fontDataSet1, 191, 64, fontData);
|
||||
loadFontDataSet(_fontDataSet2, 85, 64, fontData);
|
||||
loadFontDataSet(_fontDataSet3, 109, 64, fontData);
|
||||
|
||||
Common::File fontOthersData;
|
||||
if (!fontOthersData.open("others.bin")) {
|
||||
error("Error: failed to open others.bin");
|
||||
}
|
||||
|
||||
loadFontDataSet(_fontDataSetOther, 20, 32, fontOthersData);
|
||||
|
||||
fontOthersData.close();
|
||||
fontData.close();
|
||||
|
||||
_gameFont = new GameFont();
|
||||
}
|
||||
|
||||
KoFont::~KoFont() {
|
||||
delete _gameFont;
|
||||
}
|
||||
|
||||
void KoFont::loadFontDataSet(Common::Array<Common::Array<uint8> > &dataSet, int size, int packedGlyphSize, Common::File &file) {
|
||||
dataSet.resize(size);
|
||||
|
||||
for (int i = 0; i < size; i++) {
|
||||
dataSet[i].resize(packedGlyphSize * 4, 0);
|
||||
loadFontGlyph(dataSet[i], packedGlyphSize, file);
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint8 kFontPal[4] = {0, 2, 4, 11};
|
||||
|
||||
void KoFont::loadFontGlyph(Common::Array<uint8> &pixels, int packedGlyphSize, Common::File &file) {
|
||||
// Unpack 2bpp font data into 8bpp
|
||||
for (int i = 0; i < packedGlyphSize; i++) {
|
||||
uint8 byte = file.readByte();
|
||||
for (int j = 0; j < 4; j++) {
|
||||
pixels[i * 4 + j] = kFontPal[(byte >> (3 - j) * 2) & 3];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int KoFont::getFontHeight() const {
|
||||
return 16;
|
||||
}
|
||||
|
||||
int KoFont::getMaxCharWidth() const {
|
||||
return 16;
|
||||
}
|
||||
|
||||
int KoFont::getCharWidth(uint32 chr) const {
|
||||
if (chr < 128) {
|
||||
if (getOtherCharIdx(chr) != -1) {
|
||||
return 10;
|
||||
}
|
||||
return _gameFont->getCharWidth(chr);
|
||||
}
|
||||
return getMaxCharWidth();
|
||||
}
|
||||
|
||||
void KoFont::createGlyph(uint8 *pixels, uint32 chr) const {
|
||||
uint16 param1, param2, param3;
|
||||
extractKoIndexComponents(chr, ¶m1, ¶m2, ¶m3);
|
||||
if (param1 < 191) {
|
||||
addToGlyph(pixels, param1);
|
||||
}
|
||||
if (param2 < 85) {
|
||||
addToGlyph(pixels, param2 + 191);
|
||||
}
|
||||
if (param3 < 109) {
|
||||
addToGlyph(pixels, param3 + 276);
|
||||
}
|
||||
}
|
||||
|
||||
void KoFont::addToGlyph(uint8 *destPixels, int16 index) const {
|
||||
if (index < 192) {
|
||||
addPixels(destPixels, _fontDataSet1[index]);
|
||||
} else if (index < 277) {
|
||||
addPixels(destPixels, _fontDataSet2[index - 191]);
|
||||
} else {
|
||||
addPixels(destPixels, _fontDataSet3[index - 276]);
|
||||
}
|
||||
}
|
||||
|
||||
void KoFont::addPixels(uint8 *destPixels, const Common::Array<uint8> &pixels) const {
|
||||
for (uint i = 0; i < pixels.size(); i++) {
|
||||
if (pixels[i] != 0) {
|
||||
destPixels[i] = pixels[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int16 SHORT_ARRAY_1000_01ca[32] = {
|
||||
-1, 0, 32, 352,
|
||||
672, 992, 1312, 1632,
|
||||
1952, 2272, 2592, 2912,
|
||||
3232, 3552, 3872, 4192,
|
||||
4512, 4832, 5152, 5472,
|
||||
5792, -1, -1, -1,
|
||||
-1, -1, -1, -1,
|
||||
-1, -1, -1, -1};
|
||||
|
||||
int16 SHORT_ARRAY_1000_020a[32] = {
|
||||
-1, -1, 0, 128,
|
||||
256, 384, 512, 640,
|
||||
-1, -1, 768, 896,
|
||||
1024, 1152, 1280, 1408,
|
||||
-1, -1, 1536, 1664,
|
||||
1792, 1920, 2048, 2176,
|
||||
-1, -1, 2304, 2432,
|
||||
2560, 2688, -1, -1};
|
||||
|
||||
int16 SHORT_ARRAY_1000_024a[32] = {
|
||||
-1, 0, 128, 256,
|
||||
384, 512, 640, 768,
|
||||
896, 1024, 1152, 1280,
|
||||
1408, 1536, 1664, 1792,
|
||||
1920, 2048, -1, 2176,
|
||||
2304, 2432, 2560, 2688,
|
||||
2816, 2944, 3072, 3200,
|
||||
3328, 3456, -1, -1};
|
||||
|
||||
int16 SHORT_ARRAY_1000_028a[32] = {
|
||||
-1, 0, 0, 64,
|
||||
64, 64, 64, 64,
|
||||
64, 64, 64, 64,
|
||||
64, 64, 64, 64,
|
||||
64, 0, 64, 64,
|
||||
64, -1, -1, -1,
|
||||
-1, -1, -1, -1,
|
||||
-1, -1, -1, -1};
|
||||
|
||||
int16 SHORT_ARRAY_1000_02ca[32] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 64, 192, 192,
|
||||
0, 0, 192, 64,
|
||||
128, 256, 256, 256,
|
||||
0, 0, 128, 64,
|
||||
192, 0, 0, 0};
|
||||
|
||||
int16 SHORT_ARRAY_1000_030a[32] = {
|
||||
0, 0, 0, 0,
|
||||
64, 0, 64, 32,
|
||||
0, 0, 64, 32,
|
||||
64, 96, 0, 64,
|
||||
0, 0, 32, 96,
|
||||
96, 32, 64, 32,
|
||||
0, 0, 96, 96,
|
||||
32, 32, 0, 0};
|
||||
|
||||
int16 SHORT_ARRAY_1000_034a[32] = {
|
||||
-1, 0, 32, 32,
|
||||
32, 32, 32, 32,
|
||||
32, 32, 32, 32,
|
||||
32, 32, 32, 32,
|
||||
32, 32, -1, 32,
|
||||
32, 32, 32, 32,
|
||||
32, 32, 32, 32,
|
||||
32, 32, -1, -1};
|
||||
|
||||
void KoFont::extractKoIndexComponents(uint32 charIdx, uint16 *param_2, uint16 *param_3, uint16 *param_4) {
|
||||
int uVar1;
|
||||
int iVar2;
|
||||
int uVar3;
|
||||
int uVar4;
|
||||
int uVar5;
|
||||
|
||||
iVar2 = (charIdx & 31) * 2;
|
||||
uVar5 = (charIdx << 1) >> 5 & 62;
|
||||
uVar4 = (charIdx << 1) >> 10 & 62;
|
||||
uVar1 = SHORT_ARRAY_1000_020a[uVar5 / 2];
|
||||
if (uVar1 > 0) {
|
||||
uVar1 += SHORT_ARRAY_1000_028a[uVar4 / 2] + SHORT_ARRAY_1000_034a[iVar2 / 2] - 3;
|
||||
}
|
||||
uVar4 = SHORT_ARRAY_1000_01ca[uVar4 / 2];
|
||||
if (uVar4 > 0) {
|
||||
uVar4 += SHORT_ARRAY_1000_02ca[uVar5 / 2] + SHORT_ARRAY_1000_034a[iVar2 / 2];
|
||||
}
|
||||
uVar3 = SHORT_ARRAY_1000_024a[iVar2 / 2];
|
||||
if (uVar3 > 0) {
|
||||
uVar3 += SHORT_ARRAY_1000_030a[uVar5 / 2] - 3;
|
||||
}
|
||||
*param_2 = uVar4 >> 5;
|
||||
*param_3 = (uVar1 >> 5) - 2;
|
||||
*param_4 = (uVar3 >> 5) - 2;
|
||||
}
|
||||
|
||||
bool KoFont::isConsonant(uint32 charIdx) {
|
||||
uint16 param1, param2, param3;
|
||||
extractKoIndexComponents(charIdx, ¶m1, ¶m2, ¶m3);
|
||||
return param3 < 109;
|
||||
}
|
||||
|
||||
Common::U32String KoFont::getObjectString(const Common::U32String &object) {
|
||||
if (object.size() == 0) {
|
||||
return Common::U32String("");
|
||||
}
|
||||
if (isConsonant(object[object.size() - 1])) {
|
||||
return object + convertToU32String("\xb7\x69", Common::KO_KOR); // -eul
|
||||
}
|
||||
return object + convertToU32String("\x9f\x69", Common::KO_KOR); // -reul
|
||||
}
|
||||
|
||||
Common::U32String KoFont::getTopicString(const Common::U32String &object) {
|
||||
if (object.size() == 0) {
|
||||
return Common::U32String("");
|
||||
}
|
||||
if (isConsonant(object[object.size() - 1])) {
|
||||
return object + convertToU32String("\xb7\x65", Common::KO_KOR); // -eun
|
||||
}
|
||||
return object + convertToU32String("\x93\x65", Common::KO_KOR); // -neun
|
||||
}
|
||||
|
||||
Common::U32String KoFont::getLinkingString(const Common::U32String &object) {
|
||||
if (object.size() == 0) {
|
||||
return Common::U32String("");
|
||||
}
|
||||
if (isConsonant(object[object.size() - 1])) {
|
||||
return object + convertToU32String("\x89\xc1", Common::KO_KOR); // -gwa
|
||||
}
|
||||
return object + convertToU32String("\xb5\xc1", Common::KO_KOR); // -wa
|
||||
}
|
||||
|
||||
Common::U32String KoFont::getLocationString(const Common::U32String &object) {
|
||||
if (object.size() == 0) {
|
||||
return Common::U32String("");
|
||||
}
|
||||
if (isConsonant(object[object.size() - 1])) {
|
||||
return object + convertToU32String("\xb7\x61", Common::KO_KOR); // -eu
|
||||
}
|
||||
return object;
|
||||
}
|
||||
|
||||
int KoFont::getOtherCharIdx(uint32 chr) const {
|
||||
switch (chr) {
|
||||
case '!':
|
||||
return 2;
|
||||
case '"':
|
||||
return 6;
|
||||
case '(':
|
||||
return 3;
|
||||
case ')':
|
||||
return 4;
|
||||
case ',':
|
||||
return 0;
|
||||
case '.':
|
||||
return 1;
|
||||
case '?':
|
||||
return 5;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void KoFont::drawOtherGlyph(Graphics::Surface *dst, uint8 chr, int x, int y) const {
|
||||
g_engine->_screen->copyRectToSurfaceWithKey(_fontDataSetOther[chr].data(), 8, x, y, 8, 16,0xf);
|
||||
}
|
||||
|
||||
void KoFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
|
||||
if (chr < 128) {
|
||||
int otherCharIdx = getOtherCharIdx(chr);
|
||||
if (otherCharIdx != -1) {
|
||||
drawOtherGlyph(dst, (uint8)otherCharIdx, x, y);
|
||||
} else {
|
||||
_gameFont->drawChar(dst, chr, x, y, color);
|
||||
}
|
||||
return;
|
||||
}
|
||||
uint8 pixels[256];
|
||||
memset(pixels, 0, 256);
|
||||
createGlyph(pixels, chr);
|
||||
g_engine->_screen->copyRectToSurfaceWithKey(pixels, 16, x, y - 2, 16, 16,0xf);
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
68
engines/darkseed/kofont.h
Normal file
68
engines/darkseed/kofont.h
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_KOFONT_H
|
||||
#define DARKSEED_KOFONT_H
|
||||
|
||||
#include "graphics/font.h"
|
||||
#include "common/file.h"
|
||||
#include "darkseed/gamefont.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class KoFont : public Graphics::Font {
|
||||
private:
|
||||
Common::Array<Common::Array<uint8>> _fontDataSet1;
|
||||
Common::Array<Common::Array<uint8>> _fontDataSet2;
|
||||
Common::Array<Common::Array<uint8>> _fontDataSet3;
|
||||
Common::Array<Common::Array<uint8>> _fontDataSetOther;
|
||||
|
||||
GameFont *_gameFont;
|
||||
|
||||
public:
|
||||
KoFont();
|
||||
~KoFont();
|
||||
|
||||
int getFontHeight() const override;
|
||||
int getMaxCharWidth() const override;
|
||||
int getCharWidth(uint32 chr) const override;
|
||||
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
|
||||
|
||||
static void extractKoIndexComponents(uint32 charIdx, uint16 *param_2, uint16 *param_3, uint16 *param_4);
|
||||
static bool isConsonant(uint32 charIdx);
|
||||
static Common::U32String getObjectString(const Common::U32String &object);
|
||||
static Common::U32String getTopicString(const Common::U32String &object);
|
||||
static Common::U32String getLinkingString(const Common::U32String &object);
|
||||
static Common::U32String getLocationString(const Common::U32String &object);
|
||||
private:
|
||||
void loadFontDataSet(Common::Array<Common::Array<uint8>> &dataSet, int size, int packedGlyphSize, Common::File &file);
|
||||
void loadFontGlyph(Common::Array<uint8> &pixels, int packedGlyphSize, Common::File &file);
|
||||
|
||||
void createGlyph(uint8 *pixels, uint32 chr) const;
|
||||
void addToGlyph(uint8 *destPixels, int16 index) const;
|
||||
void addPixels(uint8 *destPixels, const Common::Array<uint8> &pixels) const;
|
||||
int getOtherCharIdx(uint32 chr) const;
|
||||
void drawOtherGlyph(Graphics::Surface *dst, uint8 chr, int x, int y) const;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_KOFONT_H
|
||||
100
engines/darkseed/langtext.cpp
Normal file
100
engines/darkseed/langtext.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/langtext.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
Common::U32String getI18NText(const I18nText &text) {
|
||||
switch (g_engine->getLanguage()) {
|
||||
case Common::ES_ESP : return Common::U32String(text.es);
|
||||
case Common::FR_FRA : return Common::U32String(text.fr);
|
||||
case Common::DE_DEU : return Common::U32String(text.de);
|
||||
case Common::KO_KOR : return text.ko ? convertToU32String(text.ko, Common::KO_KOR) : Common::U32String(text.en);
|
||||
case Common::ZH_ANY : return text.zh ? convertToU32String(text.zh, Common::ZH_ANY) : Common::U32String(text.en);
|
||||
default : return Common::U32String(text.en);
|
||||
}
|
||||
}
|
||||
|
||||
const TextWithPosition &getI18NTextWithPosition(const I18NTextWithPosition &i18nTextWithPosition) {
|
||||
switch (g_engine->getLanguage()) {
|
||||
case Common::ES_ESP : return i18nTextWithPosition.es;
|
||||
case Common::FR_FRA : return i18nTextWithPosition.fr;
|
||||
case Common::DE_DEU : return i18nTextWithPosition.de;
|
||||
case Common::KO_KOR : return i18nTextWithPosition.ko;
|
||||
case Common::ZH_ANY : return i18nTextWithPosition.zh;
|
||||
default : return i18nTextWithPosition.en;
|
||||
}
|
||||
}
|
||||
|
||||
Common::U32String convertToU32String(const char *text, Common::Language language) {
|
||||
size_t len = strlen(text);
|
||||
switch (language) {
|
||||
case Common::ZH_ANY:
|
||||
case Common::KO_KOR: {
|
||||
Common::U32String str;
|
||||
for (uint i = 0; i < len; i++) {
|
||||
uint8 byte = text[i];
|
||||
if (byte & 0x80) {
|
||||
if (i < len - 1) {
|
||||
uint8 byte2 = text[i + 1];
|
||||
str += (int)byte << 8 | byte2;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
str += byte;
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
default : break;
|
||||
}
|
||||
return Common::U32String(text);
|
||||
}
|
||||
|
||||
Common::U32String formatInjectStrings(const Common::u32char_type_t *format, ...) {
|
||||
Common::U32String outString;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
for (const Common::u32char_type_t *itr = format; *itr; itr++) {
|
||||
if (*itr == '%') {
|
||||
itr++;
|
||||
if (!*itr) {
|
||||
outString += '%';
|
||||
break;
|
||||
}
|
||||
if (*itr == 's') {
|
||||
auto text = va_arg(args, char32_t *);
|
||||
outString += text;
|
||||
} else {
|
||||
outString += *itr;
|
||||
}
|
||||
} else {
|
||||
outString += *itr;
|
||||
}
|
||||
}
|
||||
va_end(args);
|
||||
return outString;
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
447
engines/darkseed/langtext.h
Normal file
447
engines/darkseed/langtext.h
Normal file
@@ -0,0 +1,447 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_LANGTEXT_H
|
||||
#define DARKSEED_LANGTEXT_H
|
||||
|
||||
#include "common/language.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
enum class KoreanObjectSuffixType {
|
||||
None,
|
||||
Object,
|
||||
Topic,
|
||||
Linking,
|
||||
Location
|
||||
};
|
||||
|
||||
struct I18nText {
|
||||
const char *en;
|
||||
const char *es;
|
||||
const char *fr;
|
||||
const char *de;
|
||||
const char *ko;
|
||||
const char *zh;
|
||||
};
|
||||
|
||||
struct TextWithPosition {
|
||||
int x;
|
||||
int y;
|
||||
const char *text;
|
||||
};
|
||||
|
||||
struct I18NTextWithPosition {
|
||||
const TextWithPosition en;
|
||||
const TextWithPosition es;
|
||||
const TextWithPosition fr;
|
||||
const TextWithPosition de;
|
||||
const TextWithPosition ko;
|
||||
const TextWithPosition zh;
|
||||
};
|
||||
|
||||
Common::U32String getI18NText(const I18nText &text);
|
||||
const TextWithPosition &getI18NTextWithPosition(const I18NTextWithPosition &i18nTextWithPosition);
|
||||
|
||||
Common::U32String convertToU32String(const char *text, Common::Language language);
|
||||
|
||||
Common::U32String formatInjectStrings(const Common::u32char_type_t *format, ...);
|
||||
|
||||
constexpr I18nText kI18N_CarKeysIgnitionText = {
|
||||
"You see the car keys in the ignition.",
|
||||
"VES LAS LLAVES DEL COCHE EN EL CONTACTO.",
|
||||
"VOUS VOYEZ LES CLEFS DE LA VOTTURE DAUS LE STARTER.",
|
||||
"DU SIEHSTDIE AUTOSCHLUSSEL IM ANLASSER.",
|
||||
"\xb8\x61\x95\xb7\xc0\x61\x20\xb5\x69\xae\x41\x88\x61\x20\xb7\xa1\x8b\x61\x93\xa1\xad\x65\xb5\x41\x20\x8d\xb9\xd1\x61\xb7\xb6\x93\x65\x88\xf5\xb7\xa1\x20\xa5\xa1\xb7\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xac\xdd\xa8\xec\xa4\x46\xa8\xae\xc6\x5f\xb0\xcd\xa6\x62\xc2\x49\xa4\xf5\xb6\x7d\xc3\xf6\xa4\x57\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouSeeIronBarsText = {
|
||||
"You see the iron bars of your cell.",
|
||||
"VES LAS BARRAS DE HIERRO DE TU CELDA.",
|
||||
"VOUS VOYEZ LES BARREAUX DE FER DE VOTRE CELLULE.",
|
||||
"DU SIEHST DIE EISENSTANGEN IN DER ZELLE.",
|
||||
"\x88\x71\xa4\x77\xb7\x81\x20\xb8\x61\xa2\x89\xae\x41\xc9\xb7\x20\xb7\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xac\xdd\xa8\xec\xa4\x46\xba\xbb\xc5\xa2\xb8\xcc\xaa\xba\xc5\x4b\xb1\xf8\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouSeeDelbertText = {
|
||||
"You see Delbert, not much to look at.",
|
||||
"VES A DELBERT, NO HAY MUCHO QUE VER.",
|
||||
"VOUS VOYEZ DELBERT, PAS GRAND CHOSE A VOIR.",
|
||||
"DU SIEHST DELBERT, NICHT VIEL ZU SEHEN",
|
||||
"\xd0\x65\x88\x61\x9d\xb3\x89\x41\x20\xb4\x81\x89\x65\x89\xc1\xb7\x81\x20\x91\xa9\xb7\xa1\xb5\x41\x20\xb5\x69\xba\x97\xd0\x61\x89\xa1\xb7\xb6\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xac\xdd\xa8\xec\xa4\x46\xc0\xb9\xba\xb8\xa7\x42\xa1\x41\xa5\x4c\xa6\xfc\xa5\x47\xa6\xa3\xb5\xdb\xb3\x72\xaa\xaf\xaa\xb1\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouSeeTheClerkText = {
|
||||
"You see the clerk.",
|
||||
"VES AL EMPLEADO.",
|
||||
"VOUS VOYEZ L'HOMME.",
|
||||
"DU SIEHST DEN MANN.",
|
||||
"\xb7\xa1\x20\x88\x61\x89\x41\xb7\x81\x20\xb8\xf1\xb6\xa5\xb7\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xac\xdd\xa8\xec\xa4\x46\xa9\xb1\xad\xfb\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouSeeTheOpenGloveBoxText = {
|
||||
"You see the open glove box.",
|
||||
"VES LA CAJA DE LOS GUANTES ABIERTA.",
|
||||
"VOUS VOYEZ LA BOITE DE GANT OUVERTE.",
|
||||
"DU SIEHST DAS OFFENE HANDSCHUHFACH.",
|
||||
"\xb8\x77\x88\x73\xc9\xb7\xb7\xa1\x20\xb5\x69\x9d\x61\xb7\xb6\x93\x65\x88\xf5\xb7\xa1\x20\xa5\xa1\xb7\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xac\xdd\xa8\xec\xa5\xb4\xb6\x7d\xa4\x46\xaa\xba\xa4\xe2\xae\x4d\xb2\xb0\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_youSeeTheText = {
|
||||
"You see the %s.",
|
||||
"VES %s.",
|
||||
"VOUS VOYEZ %s.",
|
||||
"DU SIEHST %s.",
|
||||
"%s \xac\x69\xcd\x61\xa5\xb3\x93\xa1\x94\x61",
|
||||
"\xa7\x41\xac\xdd\xa8\xec\xa4\x46%s\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_TheCopsIgnoreYourDemandsText = {
|
||||
"The cops ignore your demands for attention.",
|
||||
"LOS POLICIAS IGNORAN TUS LLAMADAS DE ATENCION.",
|
||||
"LES FLICS IGNORENT VOTRE DEMANDE D'ATTENTION.",
|
||||
"DIE POLIZISTEN BEACHTEN NICHT DEINE FORDERUNGEN.",
|
||||
"\xb4\x61\xa2\x81\x9f\xa1\x20\xaf\xa5\xd1\xa1\x9f\x69\x20\xa5\xa1\x90\x81\x95\xa1\x20\x89\x77\xc0\x69\x97\x69\xb7\x65\x20\xc1\x61\x94\x61\xa5\xa9\x20\xac\x97\x88\x62\x95\xa1\x20\xd0\x61\xbb\xa1\x20\xb4\x67\x93\x65\x8a\x85\xb6\x61\x2e",
|
||||
nullptr // Untranslated in this version
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_ThePhoneIsRingingText = {
|
||||
"The phone is ringing.",
|
||||
"EL TELEFONO ESTA SONANDO.",
|
||||
"LE TELEPHONE SONNE.",
|
||||
"DAS TELEFON KLINGELT.",
|
||||
"\xb8\xe5\xd1\xc1\xa5\x49\xb7\xa1\x20\xb6\x89\x9f\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xb9\x71\xb8\xdc\xc1\x6e\xc5\x54\xb0\x5f\x2e\x0a"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_TheDoorbellIsRingingText = {
|
||||
"The doorbell is ringing.",
|
||||
"EL TIMBRE DE LA PUERTA ESTA SONANDO.",
|
||||
"LA SONETTE DE LA PORTE SONNE.",
|
||||
"DIE TUERKLINGEL LAEUTET.",
|
||||
"\xd1\x65\x89\xc5\x20\xc1\xa1\xb7\xa5\xb9\xb7\xb7\xa1\x20\xb6\x89\x9f\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xaa\xf9\xb9\x61\xc1\x6e\xc5\x54\xb0\x5f\x2e\x0a"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_ChooseAnItemBeforeText = {
|
||||
"Choose an item before giving clerk more money.",
|
||||
"ELIGE UN OBJETO ANTES DE DARLE AL EMPLEADO MAS DINERO.",
|
||||
"CHOISISSEZ QUELQUE CHOSE AVANT DE REMETTRE L'ARGENT A VENDEUR.",
|
||||
"SUCHE ETWAS AUS BEVOR DU DEN MANN BEZAHLST.",
|
||||
"\xb8\xf1\xb6\xa5\xb5\x41\x89\x41\x20\x95\xa5\xb7\x69\x20\x94\xe1\x20\xba\x81\x8b\xa1\xb8\xe5\xb5\x41\x20\xa0\xe5\xb8\xe1\x20\x8a\x81\xb7\xb3\xd0\x69\x20\xa2\x89\x88\xe5\xb7\x69\x20\x89\xa1\x9f\x61\xad\x41\xb6\x61\x2e",
|
||||
"\xad\x6e\xae\xb3\xb3\x66\xab\x7e\xab\x65\xa1\x41\xb0\x4f\xb1\x6f\xbd\xd0\xa5\xfd\xa5\x49\xbf\xfa\xb5\xb9\xa9\xb1\xad\xfb\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouTouchDelbertText = {
|
||||
"You touch Delbert...",
|
||||
"TOCAS A DELBERT...",
|
||||
"VOUS TOUCHEZ DELBERT.",
|
||||
"GREIFE DELBERT AN...",
|
||||
"\xae\x89\xb7\x69\x20\xd0\x65\xa4\xe5\x20\x8a\xa5\xd0\x81\x20\xa5\xa1\x93\x65\x88\xf5\xb7\xa1\x20\xb4\xe1\x98\xe9\x8c\x61\xb6\x61\x3f",
|
||||
"\xa7\x41\xb8\x49\xc4\xb2\xc0\xb9\xba\xb8\xa7\x42\xa4\x40\xa4\x55\xa1\x44\xa1\x44"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouTouchTheColdIronBarsText = {
|
||||
"You touch the cold iron bars.",
|
||||
"TOCAS LAS FRIAS BARRAS DE HIERRO.",
|
||||
"VOUS TOUCHEZ LES BARREAUX DE FER.",
|
||||
"GREIFE DIE KALTEN EISEN STANGEN AN.",
|
||||
"\xc0\x77\xac\x69\xb7\x81\x20\x88\x71\xc1\xa2\xb7\x65\x20\xb5\x62\xaf\xa1\x20\xc0\x61\x88\x73\x8a\x85\xb6\x61\x21",
|
||||
"\xa7\x41\xba\x4e\xb5\xdb\xa6\x42\xa7\x4e\xaa\xba\xc5\x4b\xb1\xf8\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_TheSergeantSaysNiceGunText = {
|
||||
"The sergeant says 'Nice gun eh? It's a Browning'",
|
||||
"EL SARGENTO DICE: 'BUENA PISTOLA, EH? ES UNA BROWNING.'",
|
||||
"LE SERGENT DIT: BEAU REVOLVER HEIN, C'EST UN BROWNING.",
|
||||
"DER SEARGENT SAGT 'SCHOENE PISTOLE, EH? ES IST EIN BROWNING.'",
|
||||
"\xc1\xb7\x20\x8b\x65\xc0\xe1\xb5\x41\xac\xe1\x20\x98\xe9\xb4\xe1\xbb\xa1\xaf\xa1\xb6\x61\x21",
|
||||
"\xc4\xb5\xa9\x78\xbb\xa1\xa1\x47\xac\x4f\xa7\xe2\xa6\x6e\xba\x6a\xa7\x63\xa1\x48\xb3\x6f\xac\x4f\xa5\xd5\xae\xd4\xb9\xe7\xa4\xe2\xba\x6a\xa9\x4f\xa1\x49"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouTurnOnTheMusicText = {
|
||||
"You turn on the music.",
|
||||
"PONES MUSICA.",
|
||||
"VOUS METTEZ LA MUSIQUE.",
|
||||
"SCHALTE DIE MUSIK AN.",
|
||||
"\xc0\x61\x20\x20\x9c\x61\x97\xa1\xb5\xa1\x9f\x69\x20\xc5\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xa5\xb4\xb6\x7d\xad\xb5\xbc\xd6\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouTurnOffTheMusicText = {
|
||||
"You turn off the music.",
|
||||
"QUITAS LA MUSICA.",
|
||||
"VOUS ARRETEZ LA MUSIQUE.",
|
||||
"SCHALTE DIE MUSIK AB.",
|
||||
"\xc0\x61\x20\x9c\x61\x97\xa1\xb5\xa1\x9f\x69\x20\x8f\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xc3\xf6\xb1\xbc\xad\xb5\xbc\xd6\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouTouchTheOrnateSignalText = {
|
||||
"You touch the surface of the ornate sigil.",
|
||||
"TOCAS LA SUPERFICIE DE LA FIGURA ADORNADA.",
|
||||
"VOUS TOUCHEZ LA SURFACE DE LA PIERRE MAGIQUE.",
|
||||
"GREIFE DIE VERZAUBERTEN STEINE AN.",
|
||||
"\xac\xe2\xa2\x61\xb7\x81\x20\xa5\xb7\xb7\xa5\xb7\x69\x20\xa0\x65\xb9\x61\xa5\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xc4\xb2\xba\x4e\xb5\xdb\xc0\x4a\xb9\xa2\xba\xeb\xac\xfc\xaa\xba\xab\xca\xa6\x4c\xaa\xed\xad\xb1\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_ThisSentryCannotBeStoppedWithText = {
|
||||
"This sentry cannot be stopped with a %s.",
|
||||
"NO PUEDES PARAR A ESTE CENTINELA CON %s.",
|
||||
"VOUS N'ARRETEREZ PAS LA SENTINELLE AVEC %s.",
|
||||
"DIESE WACHE KANN NICHT AUFGEHALTEN WERDEN MIT %s.",
|
||||
"%s\x9d\xa1\x93\x65\x20\x88\x65\xae\x81\x9f\x69\x20\xb8\xe1\xbb\xa1\xd0\x69\x20\xae\x81\x20\xb4\xf4\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
nullptr // not translated
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_HasNoEffectOnTheAlienTubesText = {
|
||||
"The %s has no effect on the alien tubes.",
|
||||
"%s NO TIENE EFECTO SOBRE LOS TUBOS ALIENIGENAS.",
|
||||
"%s RESTE SANS EFFET SUR LES TUBES EXTRA-TERRESTRES.",
|
||||
"%s BEWIRKT NICHTS AN AUSSERIRDISCHEN TUNNELS.",
|
||||
"%s \x95\xb7\x9d\x62\xac\xe5\xb5\x41\x20\xb4\x61\xa2\x81\x9c\xe5\x20\xb5\x77\xd0\xb7\xb7\x69\x20\xa3\xa1\xc3\xa1\xbb\xa1\x20\xa1\xb5\xd0\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa5\xce\x25\x73\xa6\x62\xb3\x6f\xa8\xc7\xb2\xa7\xa7\xce\xb8\xd5\xba\xde\xa4\x57\xa1\x41\xa4\x40\xc2\x49\xae\xc4\xaa\x47\xa4\x5d\xa8\x53\xa6\xb3\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouIncinerateTheText = {
|
||||
"You incinerate the %s inside the power nexus!.",
|
||||
"INCINERAS %s DENTRO DE LA FUENTA DE ENERGIA.",
|
||||
"VOUS INCINEREZ %s A L'INTERIEUR DU LIEN DE PUISSANCE.",
|
||||
"DU VERNICHTEST %s MIT DER STROMVERSORGUNG!",
|
||||
"%s \xb5\xc5\xb8\xe5\xd3\xa1\x20\xcc\x61\x8a\x41\xaf\xa1\xc5\x76\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xb1\x4e\x25\x73\xa1\x41\xa9\xf1\xa6\x62\xaf\xe0\xb6\x71\xc1\x70\xb5\xb2\xa8\x74\xb2\xce\xa4\xa4\xa4\xdf\xa4\xba\xbf\x4e\xa6\xa8\xa6\xc7\xc2\x75\xa1\x49"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_HasNoEffectOnTheAlienMonstrosityText = {
|
||||
"The %s has no effect on this alien monstrosity.",
|
||||
"%s NO TIENE EFECTO SOBRE ESTA MONSTRUOSIDAD ALIENIGENA.",
|
||||
"%s RESTE SANS EFFET SUR CETTE MONSTRUOSITE EXTRA-TERRESTRE.",
|
||||
"%s BEWIRKT NICHTS AM AUSSERIRDISCHEN MONSTRUM.",
|
||||
"%s \xb7\x41\x8b\xa1\xc1\x41\x20\xc4\xf1\xcf\x41\xc8\xe1\xb5\x41\x20\xb5\x77\xd0\xb7\xb7\x69\x20\xa3\xa1\xc3\xa9\xae\x85\x20\xb4\xf4\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa5\xce%s\xb9\xef\xa5\x49\xb3\x6f\xa8\xc7\xb2\xa7\xa7\xce\xa9\xc7\xaa\xab\xa1\x41\xae\xda\xa5\xbb\xa8\x53\xa6\xb3\xa5\xce\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_cutTheWiresText = {
|
||||
"The %s is not strong enough to cut the cables.\nPerhaps if you had some wire cutters?",
|
||||
"%s NO ES LO BASTANTE RESISTENTE COMO PARA CORTAR LOS CABLES.\nY SI TUVIERAS UN CORTACABLES?",
|
||||
"%s NE POURRA PAS COUPER LES CABLES.\nET SI VOUS AVIEZ DES PINCES COUPANTES?",
|
||||
"%s IST NICHT STARK GENUG, UM DIE KABEL ABZUSCHNEIDEN.\nHAST DU VIELLEICHT EINEN KABELSCHNEIDER?",
|
||||
"%s \xc5\x41\xb7\xa1\xa7\x69\xb7\x69\x20\xb8\xe9\x94\x65\xd0\x69\x20\xae\x81\x20\xb7\xb6\xb7\x69\x20\xb8\xf7\x95\xa1\x9d\xa1\x20\x88\x77\xd0\x61\xbb\xa5\x20\xa1\xb5\xd0\x73\x93\xa1\x94\x61\x2e\x20\x89\xc1\xb5\x65\x20\xc5\x41\xb7\xa1\xa7\x69\xb7\x69\x20\xb8\xe9\x94\x65\xd0\x69\x20\xae\x81\x20\xb7\xb6\xb7\x69\x8c\x61\xb6\x61\x3f",
|
||||
"%s\xae\xda\xa5\xbb\xa8\x53\xbf\xec\xaa\x6b\xa4\xc1\xc2\x5f\xb3\x6f\xa8\xc7\xb9\x71\xc6\x6c\xbd\x75\xa1\x43 \xa9\xce\xb3\xa7\x41\xa6\xb3\xaa\xf7\xc4\xdd\xa4\xc1\xb3\xce\xbe\xb9\xb6\xdc\xa1\x48"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_NoEffectOnTheProtectedAncientText = {
|
||||
"The %s has no effect on the protected ancient.",
|
||||
"%s NO TIENE EFECTO SOBRE EL ANTEPASADO PROTEGIDO.",
|
||||
"%s N'A AUCUN EFFET SUR L'ANCIEN PROTEGE.",
|
||||
"%s BEWIRKT NICHTS BEI DEM GESCHUETZTEN ALTEN.",
|
||||
"%s \xc4\x93\xaf\x49\xad\xa2\xb7\x81\x20\xa3\xa1\xb7\xa1\x9c\x61\xb5\x41\x89\x41\x20\xb5\x77\xd0\xb7\xb7\x69\x20\xa3\xa1\xc3\xa1\xbb\xa1\x20\xa1\xb5\xd0\x73\x93\xa1\x94\x61\x2e",
|
||||
"\x25\x73\xb9\xef\xb3\x6f\xa8\xc7\xa8\xfc\xa8\xec\xab\x4f\xc5\x40\xaa\xba\xa5\x6a\xa5\x4e\xa4\x48\xa1\x41\xa8\xc3\xa8\x53\xa6\xb3\xa5\xf4\xa6\xf3\xae\xc4\xa5\xce\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_YouHideTheObjectUnderThePillowText = {
|
||||
"You hide the %s under the pillow.",
|
||||
"OCULTAS %s BAJO LA ALMOHADA.",
|
||||
"VOUS CACHEZ %s SOUS L'OREILLER.",
|
||||
"DU VERSTECKST %s UNTER DEM KISSEN.",
|
||||
"%s \xa5\x41\x88\x81\xa3\xbb\xb5\x41\x20\xae\x91\x8b\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xa7\xe2%s\xc2\xc3\xa6\x62\xaa\x45\xc0\x59\xa9\xb3\xa4\x55\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_DontPutTheObjectInTheTrunkText = {
|
||||
"Don't put the %s in the trunk, you'll forget it.",
|
||||
"NO PONGAS %s EN EL BAUL, TE OLVIDARAS.",
|
||||
"NE METTEZ PAS %s DANS LE COFFRE, VOUS L'OUBLIEREZ.",
|
||||
"WENN DU %s IN DEN TRUHE LEGST, VERGISST DU ES.", // TODO check this is correct.
|
||||
"%s \xcb\x61\x9c\xf7\xc7\x61\xb5\x41\x20\x90\xfd\xbb\xa1\x20\xa0\x61\xaf\xb3\xaf\xa1\xb6\x61\x2e",
|
||||
"\xa4\xa3\xad\x6e\xb1\x4e\x25\x73\xa9\xf1\xa6\x62\xa8\x54\xa8\xae\xa6\xe6\xa7\xf5\xbd\x63\xa4\xa4\xa1\x41\xa7\x41\xb1\x4e\xab\xdc\xae\x65\xa9\xf6\xa7\xd1\xb0\x4f\xa5\xa6\xb4\xbf\xb8\x67\xa9\xf1\xa6\x62\xa6\xf3\xb3\x42\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_TheCarWontStartWithTheText = {
|
||||
"The car won't start with the %s.",
|
||||
"EL COCHE NO SE PONDRA EN MARCHA CON %s.",
|
||||
"LA VOITURE NE DEMARRERA PAS AVEC %s.",
|
||||
"DAS AUTO SPRINGT NICHT AN MIT %s.",
|
||||
"%s\x9d\xa1\x93\x65\x20\xb8\x61\x95\xb7\xc0\x61\xb7\x81\x20\xaf\xa1\x95\xb7\xb7\x69\x20\x88\xe9\x20\xae\x81\x20\xb4\xf4\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa8\xcf\xa5\xce%s\xa8\xc3\xa4\xa3\xaf\xe0\xc5\xfd\xa8\x54\xa8\xae\xb5\x6f\xb0\xca\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_IfYouPutTheObjectInTheTrunkText = {
|
||||
"If you put the %s in the trunk, you'll forget it.",
|
||||
"SI PONES %s EN EL BAUL, TE OLVIDARAS.",
|
||||
"SI VOUS METTEZ %s DANS LE COFFRE, VOUS L'OUBLIEREZ.",
|
||||
"WENN DU %s IN DEN TRUHE LEGST, VERGISST DU ES.",
|
||||
"%s \xb7\xb0\xb4\xe1\xa4\xe1\x9f\xa1\x89\xa1\x20\xaf\xbc\xb7\x61\xaf\xb3\x93\xa1\x8c\x61\x3f",
|
||||
"\xad\x59\xac\x4f\xa7\x41\xb1\x4e\x25\x73\xa9\xf1\xa6\x62\xa8\x54\xa8\xae\xa6\xe6\xa7\xf5\xbd\x63\xa4\xa4\xa1\x41\xa7\x41\xb1\x4e\xab\xdc\xae\x65\xa9\xf6\xa7\xd1\xb0\x4f\xa5\xa6\xb4\xbf\xb8\x67\xa9\xf1\xa6\x62\xa6\xf3\xb3\x42\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_TheObjectIsYoursYouHaventLostItText = {
|
||||
"The %s is yours, you haven't lost it.",
|
||||
"%s ES TUYA, NO LA HASA PERDIDO.",
|
||||
"%s EST A VOUS, VOUS NE L'AVEZ PAS PERDUE.",
|
||||
"%s GEHOERT DIR, DU HAST ES NICHT VERLOREN.",
|
||||
"%s \xb7\xa1\xa3\xa1\x20\x94\x77\xaf\xa5\xb7\x81\x20\x88\xf5\xb7\xb3\x93\xa1\x94\x61\x2e",
|
||||
"%s\xa4\x77\xb8\x67\xac\x4f\xa7\x41\xaa\xba\xa4\x46\xa1\x41\xa7\x41\xa8\xc3\xa8\x53\xa6\xb3\xbf\xf2\xa5\xa2\xb1\xbc\xb0\xda\xa1\x48"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_notAGoodPlaceToHideTheText = {
|
||||
"Not a good place to hide the %s.",
|
||||
"NO ES UN BUEN SITIO PARA OCULTAR %S.",
|
||||
"VOUS NE POURREZ PAS CACHER %S.",
|
||||
"KEIN GUTES VERSTECK FUER %S.",
|
||||
"%s \x91\xbd\xb4\x61\x96\x89\xa0\x65\xd0\x65\x20\xb8\x77\xad\xa1\x93\x65\x20\xb4\x61\x93\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xb3\x6f\xa4\xa3\xac\x4f\xa4\x40\xad\xd3\xc2\xc3%s\xaa\xba\xa6\x6e\xa6\x61\xa4\xe8\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_youTryToPutTheObjectInsideButTheDoorWontOpenText = {
|
||||
"You try to put the %s inside, but the door won't open",
|
||||
"INTENTAS PONER %s DENTRO, PERO LA PUERTA NO SE ABRIRA.",
|
||||
"VOUS ESSAYEZ DE METTRE %s A L'INTERIEUR, MAIS LA PORTE NE S'OUVRIRA PAS.",
|
||||
"DU VERSUCHST, %s HINEINZUSTELLEN, ABER DIE TUER OEFFNET SICH NICHT.",
|
||||
"%s \x8b\x61\x89\xb5\xb5\x41\x20\xac\x61\xb6\x77\xd0\x69\x20\xcf\xa9\xb6\x61\x88\x61\x20\xb7\xb6\xb7\x69\x8c\x61\xb6\x61\x3f",
|
||||
"\xa7\x41\xb9\xc1\xb8\xd5\xb1\x4e\x25\x73\xa9\xf1\xb8\x6d\xa6\x62\xb8\xcc\xad\xb1\xa1\x41\xa6\xfd\xac\x4f\xaa\xf9\xa8\xc3\xa8\x53\xa6\xb3\xa5\xb4\xb6\x7d\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_theKitchenIsNoPlaceToKeepTheText = {
|
||||
"The kitchen is no place to keep the %s.",
|
||||
"LA COCINA NO ES LUGAR PARA GUARDAR %s.",
|
||||
"LA CUISINE NE CONVIENT PAS A %s.",
|
||||
"DIE KUECHE IST KEIN PLATZ FUER %s.",
|
||||
"\xa6\x81\xb4\xfa\xb5\x41\x93\x65 %s \x91\xbd\xb4\x61\x96\x89\xa0\x65\xd0\x65\x20\xb8\x77\xad\xa1\x88\x61\x20\xb4\x61\x93\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xbc\x70\xa9\xd0\xa8\xc3\xa8\x53\xa6\xb3\xa6\x68\xa4\xd6\xaa\xc5\xb6\xa1\xa8\xd3\xa6\x73\xa9\xf1%s"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_youllForgetTheObjectHereText = {
|
||||
"You'll forget the %s here.",
|
||||
"OLIVIDARAS %s AQUI.",
|
||||
"VOUS OUBLIEREZ %s ICI.",
|
||||
"DU WIRST NOCH %s HIER VERGESSEN.",
|
||||
"\xb5\x61\x8b\xa1\x94\x61 %s \x91\xbd\xb4\x61\x96\x81\xa1\x65\x20\xb7\xb0\xb4\xe1\xa4\xe1\x9f\xa9\x20\x88\xf5\xb7\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xb1\x4e\xb7\x7c\xa7\xd1\xa4\x46\xa7\xe2\x25\x73\xa9\xf1\xa6\x62\xb3\x6f\xb8\xcc\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_youdRatherHaveTheObjectWithYouText = {
|
||||
"You'd rather have the %s with you.",
|
||||
"SERIA MEJOR TENER %s CONTIGO.",
|
||||
"IL VAUDRAIT MIEUX AVOIR %s SUR VOUS.",
|
||||
"DU HAETTEST LIEBER %s BEI DIR.",
|
||||
"\xc0\x61\x9c\x61\x9f\xa1 %s \x88\x61\xbb\xa1\x93\x65\x89\x41\x20\xb9\xbd\xb7\x69\x88\xf5\x20\xb7\xb3\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xb9\xe7\xc4\x40\xb1\x4e\x25\x73\xaf\x64\xa6\x62\xa8\xad\xa4\x57\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_theObjectHasNoEffectText = {
|
||||
"The %s has no effect.",
|
||||
"%s NO TIENE EFECTO.",
|
||||
"%s N'A AUCUN EFFET.",
|
||||
"%s BEWIRKT NICHTS.",
|
||||
"%s \xb5\x77\xd0\xb7\xb7\x69\x20\xa3\xa1\xc3\xa1\xbb\xa1\x20\xa1\xb5\xd0\x73\x93\xa1\x94\x61\x2e",
|
||||
"%s\xa8\x53\xa6\xb3\xae\xc4\xaa\x47\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_thisIsNotAGoodPlaceForTheText = {
|
||||
"This is not a good place for the %s.",
|
||||
"NO ES UN BUEN SITIO PARA %s.",
|
||||
"CE N'EST PAS UN BON ENDROIT POUR %s.",
|
||||
"DAS IST KEIN GUTER PLATZ FUER %s.",
|
||||
"%s \x91\xbd\xb4\x61\x96\x89\x20\xb8\x77\xad\xa1\x9d\xa1\xac\xe1\x93\x65\x20\xb8\xe2\xd0\x73\xd0\x61\xbb\xa1\x20\xb4\x67\xb7\x65\x88\xf5\x20\x88\x7b\x8a\x85\xb6\x61\x2e",
|
||||
"\xb3\x6f\xb8\xcc\xa4\xa3\xac\x4f\xa9\xf1\xb8\x6d\x25\x73\xaa\xba\xa6\x6e\xa6\x61\xa4\xe8\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_youSeeAReflectionOfTheText = {
|
||||
"You see a reflection of the %s.",
|
||||
"VES UN REFLEJO DE %s.",
|
||||
"VOUS VOYEZ UN REFLET REPRESENTANT %s.",
|
||||
"DU SIEHST EIN SPIEGELBILD VON %s.",
|
||||
"%s \x88\xe1\xb6\x89\xb9\xa1\x88\x62\xb5\x41\x20\xa7\xa1\xc2\xa1\x95\xa1\x20\xb4\x61\xa2\x81\x9c\xe5\x20\xa4\x65\xb7\x77\xb7\xa1\x20\xb4\xf4\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xac\xdd\xa8\xec\xa4\x46\x25\x73\xaa\xba\xa4\xcf\xae\x67\xac\x4d\xb9\xb3\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_youDontWantToLeaveTheObjectUnderTheBedText = {
|
||||
"You don't want to leave the %s under the bed.",
|
||||
"NO QUIERES DEJAR %s DEBAJO DE LA CAMA.",
|
||||
"POURQUOI LAISSERIEZ-VOUS %s SOUS LE LIT?",
|
||||
"DU WILLST %s NICHT UNTER DEM BETT LASSEN.",
|
||||
"%s \xc3\xb1\x94\x81\xa3\xbb\xb5\x41\x20\x90\xfd\x93\x65\x88\xf5\xb7\x65\x20\xa5\x69\x9d\xa1\x20\xb9\xbd\xb7\x65\x20\xac\x97\x88\x62\xb7\xa1\x20\xb4\x61\x93\xa5\x88\xf5\x20\x88\x7b\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\x41\xa4\xa3\xad\x6e\xb1\x4e\x25\x73\xaf\x64\xa6\x62\xa7\xc9\xa9\xb3\xa4\x55\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_genResponse0_usingTheObjectOnTheObjectItMustBeYourHeadachesText = {
|
||||
"Using the %s on the %s doesn't make any sense, it must be your headaches!",
|
||||
"UTILIZAR %s EN %s NO TIENE SENTIDO, TE PRODUCIRA DOLOR DE CABEZA",
|
||||
"POURQUOI UTILISER %s SUR %s PRENEZ DONC DE L'ASPIRINE!",
|
||||
"GEBRAUCHEN VON %s AUF %s MACHT KEINEN SINN, DAS MUSS AN DEINEN KOPFSCHMERZEN LIEGEN!",
|
||||
"%s %s\xb5\x41\x20\xac\x61\xb6\x77\xd0\x61\x93\x65\x88\xf5\xb7\x65\x20\xa0\x69\x95\xa1\x96\x41\xbb\xa1\x20\xb4\x67\xaf\x73\x93\xa1\x94\x61\x2e\x20\x8b\x61\x20\xaf\xb1\xd0\x65\x20\x96\x81\xc9\xb7\x98\x81\xa2\x85\xb5\x41\x20\x8b\x61\x9c\xe1\x93\x65\x88\xf5\xb7\xa1\x20\xb4\x61\x93\xa9\x8c\x61\xb6\x61\x3f",
|
||||
"\xa8\xcf\xa5\xce\x25\x73\xa9\xf3\x25\x73\xb2\x40\xb5\x4c\xb7\x4e\xb8\x71\xa1\x41\xa8\xba\xa4\x40\xa9\x77\xa5\xd1\xa9\xf3\xa7\x41\xaa\xba\xc0\x59\xb5\x68\xa1\x49"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_genResponse1_theObjectWillDoNothingToTheText = {
|
||||
"The %s will do nothing to the %s.",
|
||||
"%s NO TIENE NADA QUE VER CON %s.",
|
||||
"%s NE FERONT RIEN A %s.",
|
||||
"%s HAT NICHTS ZU TUN MIT %s",
|
||||
"%s %s\xb5\x41\x20\xac\x61\xb6\x77\xd0\x61\x93\x65\x88\xf5\xb7\x65\x20\xb4\x61\xa2\x81\x9c\xe5\x20\xad\xa1\xb6\x77\xb7\xa1\x20\xb4\xf4\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\xe2\x25\x73\xa5\xce\xa6\x62\x25\x73\xa4\x57\xa8\x53\xa6\xb3\xa5\xce\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_genResponse2_theObjectDoesntHaveAnyEffectOnTheText = {
|
||||
"The %s doesn't have any effect on the %s.",
|
||||
"%s NO LE CAUSARA EFECTO A %s.",
|
||||
"%s N'AURA AUCUN EFFET SUR %s.",
|
||||
"%s BEWIRKT NICHTS MIT %s.",
|
||||
"%s %s\xb5\x41\x20\xb4\x61\xa2\x81\xb5\x77\xd0\xb7\x95\xa1\x20\xa3\xa1\xc3\xa1\xbb\xa1\xa1\xb5\xd0\x73\x93\xa1\x94\x61\x2e",
|
||||
"\xa7\xe2\x25\x73\xa5\xce\xa6\x62\x25\x73\xa4\x57\xb2\x40\xb5\x4c\xae\xc4\xaa\x47\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_genResponse3_theObjectHasNothingToDoWithTheText = {
|
||||
"The %s has nothing to do with %s.",
|
||||
"%s NO TIENE NADA QUE VER CON %s.",
|
||||
"%s N'A AUCUN RAPPORT AVEC %s.",
|
||||
"%s HAT NICHTS ZU TUN MIT %s.",
|
||||
"%s %s \xb8\xe5\xd1\x61\x20\x89\xc5\x89\x81\x88\x61\x20\xb4\xf4\xaf\x73\x93\xa1\x94\x61\x2e",
|
||||
"\x25\x73\xb9\xef\x25\x73\xb0\x5f\xa4\xa3\xa4\x46\xa4\xb0\xbb\xf2\xa7\x40\xa5\xce\xa1\x43"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_genResponse4_areYouFeelingAlrightText = {
|
||||
"Are you feeling alright?",
|
||||
"TE ENCUENTRAS BIEN?",
|
||||
"VOUS ETES SUR QUE CA VA BIEN?",
|
||||
"FUEHLST DU DICH GUT?",
|
||||
"\xbb\xa1\x8b\x71\x20\xb8\xf7\xaf\xa5\xb7\xa1\x20\xb5\xa5\xb8\xe5\xd0\x73\x93\xa1\x8c\x61\x3f\x0a",
|
||||
"\xa7\x41\xc1\xd9\xa6\x6e\xa7\x61\xa1\x48"
|
||||
};
|
||||
|
||||
constexpr I18nText kI18N_blankText = {
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
""
|
||||
};
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif //DARKSEED_LANGTEXT_H
|
||||
245
engines/darkseed/menu.cpp
Normal file
245
engines/darkseed/menu.cpp
Normal file
@@ -0,0 +1,245 @@
|
||||
/* 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 "common/keyboard.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "darkseed/menu.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
#include "darkseed/langtext.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
constexpr I18NTextWithPosition kMenu_load = {
|
||||
{127, 62, "Load"},
|
||||
{119, 62, "CARGAR"},
|
||||
{118, 62, "CHARGER"},
|
||||
{121, 62, "LADEN"},
|
||||
{120, 62, "\xA6\x89\x9C\xE1\x90\x91"},
|
||||
{118, 55, "\xa8\xfa\x20\xc0\xc9"}
|
||||
};
|
||||
|
||||
constexpr I18NTextWithPosition kMenu_silent = {
|
||||
{123, 136, "Silent"},
|
||||
{115, 136, "SIN SON"},
|
||||
{118, 136, "SILENCE"},
|
||||
{129, 136, "RUHE"},
|
||||
{121, 136, "\xB7q\xAD\xA1\x88\xE1"},
|
||||
{118, 129, "\xc0\x52\x20\xad\xb5"}
|
||||
|
||||
};
|
||||
|
||||
constexpr I18NTextWithPosition kMenu_sounds = {
|
||||
{117, 136, "Sounds"},
|
||||
{121, 136, "SONIDO"},
|
||||
{126, 136, "SONS"},
|
||||
{123, 136, "SOUND"},
|
||||
{128, 136, "\xB7q\xD0\xB7"},
|
||||
{118, 129, "\xad\xb5\x20\xae\xc4"}
|
||||
};
|
||||
|
||||
constexpr I18NTextWithPosition kMenu_save = {
|
||||
{127, 99, "Save"},
|
||||
{119, 99, "GRABAR"},
|
||||
{121, 99, "SAUVER"},
|
||||
{115, 99, "SICHERN"},
|
||||
{128, 99, "\xB8\xE1\xB8w"},
|
||||
{118, 92, "\xa6\x73\x20\xc0\xc9"}
|
||||
};
|
||||
|
||||
constexpr I18NTextWithPosition kMenu_resume = {
|
||||
{118, 173, "Resume"},
|
||||
{122, 173, "SEQUIR"},
|
||||
{124, 173, "JOUER"},
|
||||
{118, 173, "WEITER"},
|
||||
{128, 173, "\xA5\xA2\x8A\xE1"},
|
||||
{118, 166, "\xc4\x7e\x20\xc4\xf2"}
|
||||
};
|
||||
|
||||
constexpr I18NTextWithPosition kMenu_quit = {
|
||||
{129, 210, "Quit"},
|
||||
{125, 210, "SALIR"},
|
||||
{117, 210, "QUITTER"},
|
||||
{129, 210, "ENDE"},
|
||||
{119, 210, "\x8F{\xA0""a\xC3\xB1"},
|
||||
{118, 203, "\xb5\xb2\x20\xa7\xf4"}
|
||||
};
|
||||
|
||||
void Menu::drawMenuItem(const I18NTextWithPosition &menuText) {
|
||||
const TextWithPosition &textWithPosition = getI18NTextWithPosition(menuText);
|
||||
if (_zhFont) {
|
||||
_zhFont->drawString(g_engine->_screen, convertToU32String(textWithPosition.text, g_engine->getLanguage()), textWithPosition.x, textWithPosition.y, 640, 14);
|
||||
} else {
|
||||
g_engine->_console->drawStringAt(textWithPosition.x, textWithPosition.y, convertToU32String(textWithPosition.text, g_engine->getLanguage()));
|
||||
}
|
||||
}
|
||||
|
||||
void Menu::drawSoundMenuItem() {
|
||||
if (g_engine->getLanguage() == Common::ZH_ANY) {
|
||||
g_engine->_screen->fillRect({{115, 129}, 62, 20}, 0);
|
||||
} else {
|
||||
g_engine->_screen->fillRect({{115, 136}, 62, 13}, 0);
|
||||
}
|
||||
if (g_engine->_sound->isMuted()) {
|
||||
drawMenuItem(kMenu_silent);
|
||||
} else {
|
||||
drawMenuItem(kMenu_sounds);
|
||||
}
|
||||
}
|
||||
|
||||
Common::KeyCode Menu::getLocalisedConfirmToQuitKeycode() {
|
||||
switch (g_engine->getLanguage()) {
|
||||
case Common::ES_ESP : return Common::KeyCode::KEYCODE_s;
|
||||
case Common::FR_FRA : return Common::KeyCode::KEYCODE_o;
|
||||
case Common::DE_DEU : return Common::KeyCode::KEYCODE_j;
|
||||
default : return Common::KeyCode::KEYCODE_y;
|
||||
}
|
||||
}
|
||||
|
||||
Menu::Menu() {
|
||||
if (g_engine->getLanguage() == Common::ZH_ANY) {
|
||||
_zhFont = new ZhMenuFont("zhmenufont_game.dat", ZhLargeFontType::InGame);
|
||||
}
|
||||
}
|
||||
|
||||
Menu::~Menu() {
|
||||
delete _zhFont;
|
||||
}
|
||||
|
||||
void Menu::loadMenu() {
|
||||
g_engine->_sound->stopSpeech();
|
||||
if (g_engine->_sound->isPlayingMusic()) {
|
||||
g_engine->_sound->startFadeOut();
|
||||
while (g_engine->_sound->isFading()) {
|
||||
g_engine->wait();
|
||||
}
|
||||
g_engine->_sound->stopMusic();
|
||||
}
|
||||
g_engine->_sound->stopSfx();
|
||||
|
||||
_open = true;
|
||||
Graphics::Surface screenCopy;
|
||||
screenCopy.copyFrom(*g_engine->_screen);
|
||||
|
||||
g_engine->showFullscreenPic(g_engine->_room->isGiger() ? "glady.pic" : "clady.pic");
|
||||
g_engine->_frame.draw();
|
||||
g_engine->drawFullscreenPic();
|
||||
g_engine->_console->draw(true);
|
||||
|
||||
drawMenuItem(kMenu_load);
|
||||
drawMenuItem(kMenu_save);
|
||||
drawSoundMenuItem();
|
||||
drawMenuItem(kMenu_resume);
|
||||
drawMenuItem(kMenu_quit);
|
||||
|
||||
g_engine->_screen->makeAllDirty();
|
||||
g_engine->_screen->update();
|
||||
|
||||
g_engine->zeroMouseButtons();
|
||||
|
||||
g_engine->_lastKeyPressed = Common::KeyCode::KEYCODE_INVALID;
|
||||
|
||||
while (!g_engine->shouldQuit()) {
|
||||
g_engine->updateEvents();
|
||||
int menuItemIdx = -1;
|
||||
|
||||
if (g_engine->_isLeftMouseClicked) {
|
||||
g_engine->zeroMouseButtons();
|
||||
|
||||
Common::Point cursorPos = g_engine->_cursor.getPosition();
|
||||
|
||||
if (cursorPos.x > 111 && cursorPos.x < 178 && cursorPos.y > 50 && cursorPos.y < 235) {
|
||||
menuItemIdx = (cursorPos.y - 50) / 37;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_engine->_lastKeyPressed != Common::KeyCode::KEYCODE_INVALID) {
|
||||
switch (g_engine->_lastKeyPressed) {
|
||||
case Common::KeyCode::KEYCODE_l: menuItemIdx = 0; break;
|
||||
case Common::KeyCode::KEYCODE_s: menuItemIdx = 1; break;
|
||||
case Common::KeyCode::KEYCODE_r: menuItemIdx = 3; break;
|
||||
case Common::KeyCode::KEYCODE_q: menuItemIdx = 4; break;
|
||||
default: break;
|
||||
}
|
||||
g_engine->_lastKeyPressed = Common::KeyCode::KEYCODE_INVALID;
|
||||
}
|
||||
|
||||
if (menuItemIdx > -1) {
|
||||
g_engine->_sound->playSfx(5, 0, -1);
|
||||
g_engine->waitForSpeechOrSfx();
|
||||
}
|
||||
|
||||
if (menuItemIdx == 0) {
|
||||
g_engine->loadGameDialog();
|
||||
break;
|
||||
}
|
||||
if (menuItemIdx == 1) {
|
||||
// restore game screen back for the save game thumbnail
|
||||
g_engine->_screen->copyRectToSurface(screenCopy, 0, 0, {screenCopy.w, screenCopy.h});
|
||||
g_engine->_room->installPalette(); // restore room working palette
|
||||
g_engine->_screen->update();
|
||||
_open = false; // mark menu as closed to allow saving.
|
||||
g_engine->saveGameDialog();
|
||||
break;
|
||||
}
|
||||
if (menuItemIdx == 2) { // sound settings
|
||||
g_engine->flipMute();
|
||||
ConfMan.flushToDisk();
|
||||
drawSoundMenuItem();
|
||||
}
|
||||
if (menuItemIdx == 3) { // Resume
|
||||
break;
|
||||
}
|
||||
if (menuItemIdx == 4) {
|
||||
g_engine->_console->printTosText(16);
|
||||
g_engine->_console->draw();
|
||||
g_engine->_screen->update();
|
||||
g_engine->_lastKeyPressed = Common::KeyCode::KEYCODE_INVALID;
|
||||
while (!g_engine->shouldQuit()) {
|
||||
g_engine->updateEvents();
|
||||
if (g_engine->_lastKeyPressed == getLocalisedConfirmToQuitKeycode() || g_engine->_isLeftMouseClicked) {
|
||||
g_engine->quitGame();
|
||||
break;
|
||||
}
|
||||
if (g_engine->_lastKeyPressed == Common::KeyCode::KEYCODE_n ||
|
||||
g_engine->_lastKeyPressed == Common::KeyCode::KEYCODE_ESCAPE ||
|
||||
g_engine->_isRightMouseClicked) {
|
||||
g_engine->_console->printTosText(17);
|
||||
g_engine->_console->draw();
|
||||
g_engine->_screen->update();
|
||||
break;
|
||||
}
|
||||
g_engine->_screen->update();
|
||||
g_engine->wait();
|
||||
}
|
||||
}
|
||||
|
||||
g_engine->_screen->update();
|
||||
g_engine->wait();
|
||||
}
|
||||
|
||||
g_engine->_room->loadRoomMusic();
|
||||
|
||||
g_engine->removeFullscreenPic();
|
||||
screenCopy.free();
|
||||
_open = false;
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
49
engines/darkseed/menu.h
Normal file
49
engines/darkseed/menu.h
Normal file
@@ -0,0 +1,49 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_MENU_H
|
||||
#define DARKSEED_MENU_H
|
||||
|
||||
#include "darkseed/zhmenufont.h"
|
||||
#include "darkseed/langtext.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Menu {
|
||||
private:
|
||||
bool _open = false;
|
||||
ZhMenuFont *_zhFont = nullptr;
|
||||
|
||||
public:
|
||||
Menu();
|
||||
~Menu();
|
||||
bool isOpen() const { return _open; }
|
||||
|
||||
void loadMenu();
|
||||
private:
|
||||
void drawSoundMenuItem();
|
||||
Common::KeyCode getLocalisedConfirmToQuitKeycode();
|
||||
void drawMenuItem(const I18NTextWithPosition &menuText);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif //DARKSEED_MENU_H
|
||||
99
engines/darkseed/metaengine.cpp
Normal file
99
engines/darkseed/metaengine.cpp
Normal file
@@ -0,0 +1,99 @@
|
||||
/* 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 "common/translation.h"
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
#include "darkseed/metaengine.h"
|
||||
#include "darkseed/detection.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
#include "darkseed/dialogs.h"
|
||||
|
||||
const char *DarkseedMetaEngine::getName() const {
|
||||
return "darkseed";
|
||||
}
|
||||
|
||||
Common::KeymapArray DarkseedMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
|
||||
Keymap *engineKeyMap = new Keymap(Keymap::kKeymapTypeGame, "darkseed", "Darkseed");
|
||||
|
||||
Action *act;
|
||||
|
||||
act = new Action(kStandardActionLeftClick, _("Action"));
|
||||
act->setCustomEngineActionEvent(Darkseed::kDarkseedActionSelect);
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("CHANGECOMMAND", _("Change command"));
|
||||
act->setCustomEngineActionEvent(Darkseed::kDarkseedActionChangeCommand);
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("TIMEADVANCE", _("Time advance"));
|
||||
act->setCustomEngineActionEvent(Darkseed::kDarkseedActionTimeAdvance);
|
||||
act->addDefaultInputMapping("t");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("QUIT", _("Quit game"));
|
||||
act->setCustomEngineActionEvent(Darkseed::kDarkseedActionQuit);
|
||||
act->addDefaultInputMapping("C+q");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
act = new Action("SKIPCUTSCENE", _("Skip cutscene"));
|
||||
act->setCustomEngineActionEvent(Darkseed::kDarkseedActionSkipCutscene);
|
||||
act->addDefaultInputMapping("SPACE");
|
||||
engineKeyMap->addAction(act);
|
||||
|
||||
return Keymap::arrayOf(engineKeyMap);
|
||||
}
|
||||
|
||||
Common::Error DarkseedMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
|
||||
*engine = new Darkseed::DarkseedEngine(syst, desc);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool DarkseedMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||
return checkExtendedSaves(f) ||
|
||||
(f == kSupportsLoadingDuringStartup);
|
||||
}
|
||||
|
||||
void DarkseedMetaEngine::registerDefaultSettings(const Common::String &target) const {
|
||||
for (const ADExtraGuiOptionsMap *entry = Darkseed::optionsList; entry->guioFlag; ++entry)
|
||||
ConfMan.registerDefault(entry->option.configOption, entry->option.defaultState);
|
||||
|
||||
for (const Darkseed::PopUpOptionsMap *entry = Darkseed::popUpOptionsList; entry->guioFlag; ++entry)
|
||||
ConfMan.registerDefault(entry->configOption, entry->defaultState);
|
||||
}
|
||||
|
||||
GUI::OptionsContainerWidget *DarkseedMetaEngine::buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const {
|
||||
return new Darkseed::OptionsWidget(boss, name, target);
|
||||
}
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(DARKSEED)
|
||||
REGISTER_PLUGIN_DYNAMIC(DARKSEED, PLUGIN_TYPE_ENGINE, DarkseedMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(DARKSEED, PLUGIN_TYPE_ENGINE, DarkseedMetaEngine);
|
||||
#endif
|
||||
46
engines/darkseed/metaengine.h
Normal file
46
engines/darkseed/metaengine.h
Normal file
@@ -0,0 +1,46 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_METAENGINE_H
|
||||
#define DARKSEED_METAENGINE_H
|
||||
|
||||
#include "backends/keymapper/keymap.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
|
||||
class DarkseedMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override;
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
|
||||
|
||||
/**
|
||||
* Determine whether the engine supports the specified MetaEngine feature.
|
||||
*
|
||||
* Used by e.g. the launcher to determine whether to enable the Load button.
|
||||
*/
|
||||
bool hasFeature(MetaEngineFeature f) const override;
|
||||
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
void registerDefaultSettings(const Common::String &target) const override;
|
||||
GUI::OptionsContainerWidget *buildEngineOptionsWidget(GUI::GuiObject *boss, const Common::String &name, const Common::String &target) const override;
|
||||
};
|
||||
|
||||
#endif // DARKSEED_METAENGINE_H
|
||||
303
engines/darkseed/midiparser_sbr.cpp
Normal file
303
engines/darkseed/midiparser_sbr.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/* 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 "darkseed/midiparser_sbr.h"
|
||||
|
||||
#include "audio/mididrv.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
MidiParser_SBR::MidiParser_SBR(int8 source, bool sfx) : MidiParser_SMF(source), _sfx(sfx) {
|
||||
Common::fill(_trackDeltas, _trackDeltas + ARRAYSIZE(_trackDeltas), 0);
|
||||
Common::fill(_trackInstruments, _trackInstruments + ARRAYSIZE(_trackInstruments), 0xFF);
|
||||
Common::fill(_trackNoteActive, _trackNoteActive + ARRAYSIZE(_trackNoteActive), 0xFF);
|
||||
Common::fill(_trackLoopCounter, _trackLoopCounter + ARRAYSIZE(_trackLoopCounter), 0);
|
||||
|
||||
// SBR uses a fixed tempo.
|
||||
_ppqn = 96;
|
||||
setTempo(1318214);
|
||||
}
|
||||
|
||||
void MidiParser_SBR::parseNextEvent(EventInfo &info) {
|
||||
uint8 subtrack = info.subtrack;
|
||||
const byte *parsePos = _position._subtracks[subtrack]._playPos;
|
||||
const uint8 *start = parsePos;
|
||||
|
||||
/**
|
||||
* SBR uses 6 byte structures to represent events:
|
||||
* - Event type / note
|
||||
* - Note velocity
|
||||
* - (unused)
|
||||
* - Delta (word, little-endian)
|
||||
* - Instrument
|
||||
* Delta is ticks to the next event, not preceding this event like SMF.
|
||||
*
|
||||
* The following event types are used:
|
||||
* - 0x00: End of track. This is the only byte in this event.
|
||||
* - 0x01: Subtrack list. See loadMusic.
|
||||
* - 0x02: Rest. Effectively a note off and a delta to the next event.
|
||||
* - 0x03: Sample. Indicates the sample filename shoud be read from the
|
||||
* corresponding DIG file entry. See Sound class.
|
||||
* - 0x05: Restart playback from the beginning of the subtrack.
|
||||
* - 0x06: Loop. Velocity specifies the number of events to jump back.
|
||||
* Delta specifies the number of times to repeat this section.
|
||||
* - 0x24+: Note on.
|
||||
*/
|
||||
info.start = start;
|
||||
info.length = 0;
|
||||
info.noop = false;
|
||||
info.loop = false;
|
||||
info.delta = _trackDeltas[subtrack];
|
||||
_trackDeltas[subtrack] = 0;
|
||||
|
||||
// Any event will turn off the active note on this subtrack.
|
||||
if (_trackNoteActive[subtrack] != 0xFF) {
|
||||
info.event = 0x80 | subtrack;
|
||||
info.basic.param1 = _trackNoteActive[subtrack];
|
||||
info.basic.param2 = 0x00;
|
||||
_trackNoteActive[subtrack] = 0xFF;
|
||||
return;
|
||||
}
|
||||
|
||||
if (parsePos == nullptr || parsePos[0] == 0) {
|
||||
// Reached the end of the track. Generate an end-of-track event.
|
||||
info.event = 0xFF;
|
||||
info.ext.type = MidiDriver::MIDI_META_END_OF_TRACK;
|
||||
info.ext.data = parsePos;
|
||||
return;
|
||||
}
|
||||
|
||||
// There are more MIDI events in this track.
|
||||
uint8 noteType = parsePos[0];
|
||||
if (noteType == 5) {
|
||||
// Subtrack needs to be restarted. Generate a custom meta event.
|
||||
info.event = 0xFF;
|
||||
info.ext.type = 5;
|
||||
info.loop = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (noteType == 6) {
|
||||
// Subtrack needs to be looped. Generate a custom meta event.
|
||||
info.event = 0xFF;
|
||||
info.ext.type = 6;
|
||||
info.ext.data = parsePos;
|
||||
info.loop = true;
|
||||
// Delta needs to be one more than specified due to differences in the
|
||||
// way this event is processed compared to the original code.
|
||||
info.delta++;
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if the instrument specified in this event is different from the
|
||||
// current instrument for this track. Typically, all events in a subtrack
|
||||
// have the same instrument.
|
||||
uint8 instrument = parsePos[5];
|
||||
if (_trackInstruments[subtrack] != instrument) {
|
||||
if (_trackInstruments[subtrack] <= 0xF && (_trackInstruments[subtrack] / 3) != (instrument / 3)) {
|
||||
// WORKAROUND The current instrument for this subtrack is a rhythm
|
||||
// instrument, and the instrument specified in this event is for a
|
||||
// different rhythm instrument type. This occurs a few times in
|
||||
// the Dark Seed SBR files. The instrument for the offending events
|
||||
// is 0, probably by mistake. The original code will allocate a
|
||||
// subtrack to an OPL rhythm instrument based on the first event
|
||||
// and then never change it, even when an event with an instrument
|
||||
// with a different rhythm type is encountered. Instead, it will
|
||||
// write the new instrument definition to the originally allocated
|
||||
// OPL rhythm instrument, even if it has the wrong rhythm type.
|
||||
// The ScummVM code will change the allocation to the rhythm
|
||||
// instrument indicated by the instrument on the new event, which
|
||||
// causes incorrect playback, because typically there already is
|
||||
// a subtrack allocated to this instrument.
|
||||
// To fix this, the incorrect instrument on this event is simply
|
||||
// ignored.
|
||||
}
|
||||
else {
|
||||
// The instrument on this event is different from the current
|
||||
// instrument. Generate a program change event.
|
||||
_trackInstruments[subtrack] = instrument;
|
||||
info.event = 0xC0 | subtrack;
|
||||
info.basic.param1 = instrument;
|
||||
info.basic.param2 = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (noteType >= 24) {
|
||||
// Note on.
|
||||
info.event = 0x90 | subtrack;
|
||||
info.basic.param1 = noteType;
|
||||
info.basic.param2 = parsePos[1];
|
||||
_trackNoteActive[subtrack] = noteType;
|
||||
}
|
||||
else {
|
||||
// For rest events, nothing needs to be done other than turning off
|
||||
// the current note (already done above) and process the delta.
|
||||
// Subtrack list and sample events are not processed here.
|
||||
info.noop = true;
|
||||
}
|
||||
if (noteType == 2 || noteType >= 24) {
|
||||
// Delta to the next event is only processed for
|
||||
// note on and rest events.
|
||||
_trackDeltas[subtrack] = READ_LE_UINT16(parsePos + 3);
|
||||
}
|
||||
|
||||
// Set play position to the start of the next event.
|
||||
_position._subtracks[subtrack]._playPos += 6;
|
||||
}
|
||||
|
||||
bool MidiParser_SBR::processEvent(const EventInfo &info, bool fireEvents) {
|
||||
// Handle custom meta events here.
|
||||
if (info.event == 0xFF) {
|
||||
uint8 subtrack = info.subtrack;
|
||||
if (info.ext.type == 5) {
|
||||
// Restart. Set play position to the beginning of the subtrack.
|
||||
_position._subtracks[subtrack]._playPos = _tracks[_activeTrack][subtrack];
|
||||
return true;
|
||||
}
|
||||
else if (info.ext.type == 6) {
|
||||
// Loop.
|
||||
bool loop = false;
|
||||
if (_trackLoopCounter[subtrack] > 0) {
|
||||
// A loop iteration has completed.
|
||||
_trackLoopCounter[subtrack]--;
|
||||
if (_trackLoopCounter[subtrack] > 0) {
|
||||
// There are more iterations remaining.
|
||||
loop = true;
|
||||
}
|
||||
else {
|
||||
// Loop has finished. Playback will resume at the event
|
||||
// after the loop event.
|
||||
_position._subtracks[subtrack]._playPos += 6;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// Initialize the loop. Read number of iterations from the
|
||||
// event delta.
|
||||
_trackLoopCounter[subtrack] = READ_LE_UINT16(info.ext.data + 3);
|
||||
loop = true;
|
||||
}
|
||||
if (loop) {
|
||||
// Set the play position back by the number of events indicated
|
||||
// by the event velocity.
|
||||
_position._subtracks[subtrack]._playPos -= ((info.ext.data[1]) * 6);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// All other events are handled like SMF events.
|
||||
return MidiParser::processEvent(info, fireEvents);
|
||||
}
|
||||
|
||||
void MidiParser_SBR::onTrackStart(uint8 track) {
|
||||
Common::fill(_trackDeltas, _trackDeltas + ARRAYSIZE(_trackDeltas), 0);
|
||||
Common::fill(_trackInstruments, _trackInstruments + ARRAYSIZE(_trackInstruments), 0xFF);
|
||||
Common::fill(_trackNoteActive, _trackNoteActive + ARRAYSIZE(_trackNoteActive), 0xFF);
|
||||
Common::fill(_trackLoopCounter, _trackLoopCounter + ARRAYSIZE(_trackLoopCounter), 0);
|
||||
}
|
||||
|
||||
bool MidiParser_SBR::loadMusic(const byte *data, uint32 size) {
|
||||
assert(size > 0);
|
||||
|
||||
unloadMusic();
|
||||
|
||||
// SBR files typically contain 120 tracks; some have 100.
|
||||
// Music files only use the first 10. SFX files use the remaining 110.
|
||||
uint8 startTrack = _sfx ? 10 : 0;
|
||||
uint8 endTrack = _sfx ? 120 : 10;
|
||||
|
||||
// Read all the tracks. These consist of 0 or more 6 byte events,
|
||||
// terminated by a 00 byte.
|
||||
uint16 bytesRead = 0;
|
||||
for (int i = 0; i < endTrack; i++) {
|
||||
const byte *startOfTrack = data;
|
||||
uint16 trackSize = 0;
|
||||
|
||||
bool foundEndOfTrack = false;
|
||||
while (bytesRead < size) {
|
||||
uint8 eventType = data[0];
|
||||
if (eventType == 0) {
|
||||
foundEndOfTrack = true;
|
||||
data++;
|
||||
trackSize++;
|
||||
bytesRead++;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
data += 6;
|
||||
trackSize += 6;
|
||||
bytesRead += 6;
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundEndOfTrack) {
|
||||
// Some files have less than 120 tracks
|
||||
endTrack = i;
|
||||
break;
|
||||
}
|
||||
else if (i < startTrack) {
|
||||
_tracks[i][0] = nullptr;
|
||||
}
|
||||
else {
|
||||
_tracks[i][0] = startOfTrack;
|
||||
}
|
||||
}
|
||||
_numTracks = endTrack;
|
||||
|
||||
// Look for tracks starting with a subtrack list event (type 01).
|
||||
// These are tracks consisting of multiple parallel subtracks.
|
||||
// Music files typically have a subtrack list in track 0. Some SFX use
|
||||
// multiple subtracks as well.
|
||||
for (int i = 0; i < _numTracks; i++) {
|
||||
if (_tracks[i][0] != nullptr && _tracks[i][0][0] == 0x01) {
|
||||
// Read the subtrack list. This is a variable-length list of
|
||||
// subtrack indices, terminated by a 00 byte.
|
||||
// (The track is padded with garbage and terminated by another
|
||||
// 00 byte to match the x * 6 byte event format used by all tracks.)
|
||||
const uint8 *tracklist = _tracks[i][0] + 1;
|
||||
uint8 subtrackIndex = 0;
|
||||
while (*tracklist != 0) {
|
||||
_tracks[i][subtrackIndex++] = _tracks[*tracklist][0];
|
||||
tracklist++;
|
||||
}
|
||||
_numSubtracks[i] = subtrackIndex;
|
||||
}
|
||||
else {
|
||||
// This is a track containing just a single subtrack.
|
||||
_numSubtracks[i] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
_disableAutoStartPlayback = true;
|
||||
resetTracking();
|
||||
|
||||
setTrack(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool MidiParser_SBR::isSampleSfx(uint8 sfxId) {
|
||||
if (!_sfx || sfxId >= _numTracks)
|
||||
return false;
|
||||
return _tracks[sfxId][0] != nullptr && _tracks[sfxId][0][0] == 0x03;
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
53
engines/darkseed/midiparser_sbr.h
Normal file
53
engines/darkseed/midiparser_sbr.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_MIDIPARSER_SBR_H
|
||||
#define DARKSEED_MIDIPARSER_SBR_H
|
||||
|
||||
#include "audio/midiparser_smf.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
/**
|
||||
* MIDI parser for the SBR format used by Dark Seed floppy version.
|
||||
*/
|
||||
class MidiParser_SBR : public MidiParser_SMF {
|
||||
public:
|
||||
MidiParser_SBR(int8 source = -1, bool sfx = false);
|
||||
|
||||
bool loadMusic(const byte *data, uint32 size) override;
|
||||
bool isSampleSfx(uint8 sfxId);
|
||||
|
||||
protected:
|
||||
void parseNextEvent(EventInfo &info) override;
|
||||
bool processEvent(const EventInfo &info, bool fireEvents = true) override;
|
||||
void onTrackStart(uint8 track) override;
|
||||
|
||||
bool _sfx = false;
|
||||
uint8 _trackInstruments[10];
|
||||
uint16 _trackDeltas[10];
|
||||
uint8 _trackNoteActive[10];
|
||||
uint16 _trackLoopCounter[10];
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif
|
||||
48
engines/darkseed/module.mk
Normal file
48
engines/darkseed/module.mk
Normal file
@@ -0,0 +1,48 @@
|
||||
MODULE := engines/darkseed
|
||||
|
||||
MODULE_OBJS = \
|
||||
adlib_dsf.o \
|
||||
adlib_worx.o \
|
||||
animation.o \
|
||||
anm.o \
|
||||
big5font.o \
|
||||
console.o \
|
||||
cursor.o \
|
||||
cutscene.o \
|
||||
darkseed.o \
|
||||
debugconsole.o \
|
||||
dialogs.o \
|
||||
gamefont.o \
|
||||
img.o \
|
||||
inventory.o \
|
||||
kidpic.o \
|
||||
kofont.o \
|
||||
langtext.o \
|
||||
menu.o \
|
||||
metaengine.o \
|
||||
midiparser_sbr.o \
|
||||
morph.o \
|
||||
music.o \
|
||||
nsp.o \
|
||||
objects.o \
|
||||
pal.o \
|
||||
pic.o \
|
||||
player.o \
|
||||
room.o \
|
||||
sound.o \
|
||||
sprites.o \
|
||||
titlefont.o \
|
||||
tostext.o \
|
||||
usecode.o \
|
||||
zhmenufont.o
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_DARKSEED), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
68
engines/darkseed/morph.cpp
Normal file
68
engines/darkseed/morph.cpp
Normal file
@@ -0,0 +1,68 @@
|
||||
/* 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 "darkseed/morph.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
Morph::Morph(const Common::Rect &area) : _area(area) {}
|
||||
void Morph::loadSrcFromScreen() {
|
||||
_src.copyFrom(*(Graphics::ManagedSurface *)g_engine->_screen);
|
||||
}
|
||||
|
||||
void Morph::loadDestFromScreen() {
|
||||
_dest.copyFrom(*(Graphics::ManagedSurface *)g_engine->_screen);
|
||||
}
|
||||
|
||||
void Morph::start(MorphDirection direction) {
|
||||
_stepCount = 0;
|
||||
_direction = direction;
|
||||
}
|
||||
|
||||
bool Morph::morphStep() {
|
||||
if (_stepCount > 16) {
|
||||
return false;
|
||||
}
|
||||
draw(_direction == MorphDirection::Forward ? _stepCount : 16 - _stepCount);
|
||||
_stepCount += 1;
|
||||
return _stepCount < 17;
|
||||
}
|
||||
|
||||
void Morph::draw(int16 drawIdx) {
|
||||
uint8 *screen = (uint8 *)g_engine->_screen->getBasePtr(_area.left, _area.top);
|
||||
uint8 *src = (uint8 *)_src.getBasePtr(_area.left, _area.top);
|
||||
uint8 *dest = (uint8 *)_dest.getBasePtr(_area.left, _area.top);
|
||||
|
||||
for (int y = 0; y < _area.height(); y++) {
|
||||
for (int x = 0; x < _area.width(); x++) {
|
||||
if (src[x] != dest[x]) {
|
||||
screen[x] = (src[x] * (16 - drawIdx) + dest[x] * drawIdx) >> 4;
|
||||
}
|
||||
}
|
||||
screen += g_engine->_screen->pitch;
|
||||
src += _src.pitch;
|
||||
dest += _dest.pitch;
|
||||
}
|
||||
g_engine->_screen->addDirtyRect(_area);
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
57
engines/darkseed/morph.h
Normal file
57
engines/darkseed/morph.h
Normal file
@@ -0,0 +1,57 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
#ifndef DARKSEED_MORPH_H
|
||||
#define DARKSEED_MORPH_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "graphics/managed_surface.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
enum class MorphDirection : uint8 {
|
||||
Forward,
|
||||
Backward
|
||||
};
|
||||
|
||||
class Morph {
|
||||
Common::Rect _area;
|
||||
Graphics::ManagedSurface _src;
|
||||
Graphics::ManagedSurface _dest;
|
||||
MorphDirection _direction = MorphDirection::Forward;
|
||||
int16 _stepCount = 0;
|
||||
|
||||
public:
|
||||
explicit Morph(const Common::Rect &area);
|
||||
|
||||
void loadSrcFromScreen();
|
||||
void loadDestFromScreen();
|
||||
|
||||
void start(MorphDirection direction);
|
||||
|
||||
bool morphStep();
|
||||
|
||||
private:
|
||||
void draw(int16 drawIdx);
|
||||
};
|
||||
|
||||
} // End of namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_MORPH_H
|
||||
449
engines/darkseed/music.cpp
Normal file
449
engines/darkseed/music.cpp
Normal file
@@ -0,0 +1,449 @@
|
||||
/* 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 "darkseed/music.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
MusicPlayer::MusicPlayer(DarkseedEngine* vm, bool useFloppyMusic, bool useFloppySfx) :
|
||||
_vm(vm),
|
||||
_driver(nullptr),
|
||||
_floppyAdLibDriver(nullptr),
|
||||
_paused(false),
|
||||
_deviceType(MT_NULL),
|
||||
_musicParser(nullptr),
|
||||
_musicData(nullptr),
|
||||
_sfxParserSbr(nullptr),
|
||||
_sfxData(nullptr),
|
||||
_tosInstrumentBankData(nullptr),
|
||||
_tosInstrumentBankLoaded(false),
|
||||
_useFloppyMusic(useFloppyMusic),
|
||||
_useFloppySfx(useFloppySfx) {
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
_sfxParsers[i] = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
MusicPlayer::~MusicPlayer() {
|
||||
stopMusic();
|
||||
stopAllSfx();
|
||||
if (_driver != nullptr) {
|
||||
_driver->setTimerCallback(nullptr, nullptr);
|
||||
_driver->close();
|
||||
}
|
||||
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
if (_musicParser != nullptr)
|
||||
delete _musicParser;
|
||||
if (_musicData != nullptr)
|
||||
delete[] _musicData;
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr)
|
||||
delete _sfxParsers[i];
|
||||
}
|
||||
if (_sfxData != nullptr)
|
||||
delete _sfxData;
|
||||
if (_tosInstrumentBankData != nullptr)
|
||||
delete[] _tosInstrumentBankData;
|
||||
if (_driver != nullptr) {
|
||||
delete _driver;
|
||||
_driver = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
int MusicPlayer::open() {
|
||||
assert(!_driver);
|
||||
|
||||
int devFlags = MDT_ADLIB; // | MDT_PCSPK;
|
||||
MidiDriver::DeviceHandle dev = MidiDriver::detectDevice(devFlags);
|
||||
_deviceType = MidiDriver::getMusicType(dev);
|
||||
|
||||
if (_useFloppyMusic) {
|
||||
switch (_deviceType) {
|
||||
case MT_ADLIB:
|
||||
_floppyAdLibDriver = new MidiDriver_DarkSeedFloppy_AdLib(OPL::Config::kOpl2);
|
||||
_driver = _floppyAdLibDriver;
|
||||
break;
|
||||
case MT_PCSPK:
|
||||
// TODO Implement PC speaker driver
|
||||
default:
|
||||
_driver = new MidiDriver_NULL_Multisource();
|
||||
break;
|
||||
}
|
||||
|
||||
_musicParser = new MidiParser_SBR(0);
|
||||
if (_useFloppySfx) {
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParserSbr == nullptr) {
|
||||
_sfxParserSbr = new MidiParser_SBR(i + 1, true);
|
||||
_sfxParsers[i] = _sfxParserSbr;
|
||||
}
|
||||
else {
|
||||
_sfxParsers[i] = new MidiParser_SBR(i + 1, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
switch (_deviceType) {
|
||||
case MT_ADLIB:
|
||||
_driver = new MidiDriver_Worx_AdLib(OPL::Config::kOpl2);
|
||||
// Some tracks do not set instruments and expect instrument 0
|
||||
// to be set on each channel. Make sure this is done every time
|
||||
// a track starts.
|
||||
_driver->setControllerDefault(MidiDriver_Multisource::CONTROLLER_DEFAULT_PROGRAM);
|
||||
break;
|
||||
case MT_PCSPK:
|
||||
// TODO Implement PC speaker driver
|
||||
default:
|
||||
_driver = new MidiDriver_NULL_Multisource();
|
||||
break;
|
||||
}
|
||||
|
||||
// CD version uses SMF data
|
||||
_musicParser = MidiParser::createParser_SMF(0);
|
||||
}
|
||||
|
||||
_driver->property(MidiDriver::PROP_USER_VOLUME_SCALING, true);
|
||||
if (_musicParser != nullptr)
|
||||
_musicParser->property(MidiParser::mpDisableAutoStartPlayback, true);
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr) {
|
||||
_sfxParsers[i]->property(MidiParser::mpDisableAutoStartPlayback, true);
|
||||
}
|
||||
}
|
||||
|
||||
int returnCode = _driver->open();
|
||||
if (returnCode != 0) {
|
||||
error("MusicPlayer::open - Failed to open MIDI driver - error code %d.", returnCode);
|
||||
return 1;
|
||||
}
|
||||
|
||||
syncSoundSettings();
|
||||
|
||||
if (_musicParser != nullptr) {
|
||||
_musicParser->setMidiDriver(_driver);
|
||||
_musicParser->setTimerRate(_driver->getBaseTempo());
|
||||
}
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr) {
|
||||
_sfxParsers[i]->setMidiDriver(_driver);
|
||||
_sfxParsers[i]->setTimerRate(_driver->getBaseTempo());
|
||||
}
|
||||
}
|
||||
_driver->setTimerCallback(this, &onTimer);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void MusicPlayer::onTimer(void *data) {
|
||||
MusicPlayer *p = (MusicPlayer *)data;
|
||||
|
||||
Common::StackLock lock(p->_mutex);
|
||||
|
||||
if (p->_musicParser != nullptr)
|
||||
p->_musicParser->onTimer();
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (p->_sfxParsers[i] != nullptr) {
|
||||
p->_sfxParsers[i]->onTimer();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MusicPlayer::isPlayingMusic() {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
return _musicParser != nullptr && _musicParser->isPlaying();
|
||||
}
|
||||
|
||||
void MusicPlayer::stopMusic() {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
if (_musicParser != nullptr) {
|
||||
_musicParser->stopPlaying();
|
||||
if (_driver != nullptr) {
|
||||
_driver->deinitSource(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MusicPlayer::pauseMusic(bool pause) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
if (_paused == pause || _musicParser == nullptr)
|
||||
return;
|
||||
|
||||
_paused = pause;
|
||||
|
||||
if (_paused) {
|
||||
_musicParser->pausePlaying();
|
||||
} else {
|
||||
_musicParser->resumePlaying();
|
||||
}
|
||||
}
|
||||
|
||||
bool MusicPlayer::isPlayingSfx() {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr && _sfxParsers[i]->isPlaying()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool MusicPlayer::isPlayingSfx(uint8 sfxId) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr && _sfxParsers[i]->isPlaying() && _sfxParsers[i]->getActiveTrack() == sfxId) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void MusicPlayer::playSfx(uint8 sfxId, uint8 priority) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
if (_sfxParsers[0] == nullptr)
|
||||
return;
|
||||
|
||||
if (!_tosInstrumentBankLoaded) {
|
||||
warning("Attempt to play floppy sound effect %i while TOS instrument bank is not loaded", sfxId);
|
||||
return;
|
||||
}
|
||||
|
||||
uint8 sfxParserIdx = assignSfxParser();
|
||||
if (sfxParserIdx == 0xFF) {
|
||||
warning("All SFX parsers in use when trying to play SFX %i", sfxId);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_driver != nullptr) {
|
||||
_driver->resetSourceVolume(sfxParserIdx + 1);
|
||||
}
|
||||
if (_floppyAdLibDriver != nullptr)
|
||||
_floppyAdLibDriver->setSourcePriority(sfxParserIdx + 1, priority);
|
||||
|
||||
_sfxParsers[sfxParserIdx]->setTrack(sfxId);
|
||||
_sfxParsers[sfxParserIdx]->startPlaying();
|
||||
}
|
||||
|
||||
uint8 MusicPlayer::assignSfxParser() {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
int parserIdx = 0xFF;
|
||||
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr && !_sfxParsers[i]->isPlaying()) {
|
||||
// Make sure all inactive SFX parsers have released their resources
|
||||
if (_driver != nullptr)
|
||||
_driver->deinitSource(i + 1);
|
||||
|
||||
if (parserIdx == 0xFF)
|
||||
parserIdx = i;
|
||||
}
|
||||
}
|
||||
// If all SFX parsers are already playing, parserIdx is still 0xFF
|
||||
|
||||
return parserIdx;
|
||||
}
|
||||
|
||||
void MusicPlayer::stopAllSfx() {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr) {
|
||||
_sfxParsers[i]->stopPlaying();
|
||||
if (_driver != nullptr) {
|
||||
_driver->deinitSource(i + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool MusicPlayer::stopSfx(uint8 sfxId) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
bool stoppedSfx = false;
|
||||
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
if (_sfxParsers[i] != nullptr && _sfxParsers[i]->getActiveTrack() == sfxId) {
|
||||
_sfxParsers[i]->stopPlaying();
|
||||
if (_driver != nullptr) {
|
||||
_driver->deinitSource(i + 1);
|
||||
}
|
||||
stoppedSfx = true;
|
||||
}
|
||||
}
|
||||
|
||||
return stoppedSfx;
|
||||
}
|
||||
|
||||
void MusicPlayer::syncSoundSettings() {
|
||||
if (_driver)
|
||||
_driver->syncSoundSettings();
|
||||
}
|
||||
|
||||
void MusicPlayer::setLoopMusic(bool loop) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
if (_musicParser)
|
||||
_musicParser->property(MidiParser::mpAutoLoop, loop);
|
||||
}
|
||||
|
||||
void MusicPlayer::load(Common::SeekableReadStream *in, int32 size, bool sfx) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
MidiParser *parser = sfx ? _sfxParsers[0] : _musicParser;
|
||||
byte **dataPtr = sfx ? &_sfxData : &_musicData;
|
||||
|
||||
if (parser == nullptr)
|
||||
return;
|
||||
|
||||
if (size < 0) {
|
||||
// Use the parser to determine the size of the MIDI data.
|
||||
int64 startPos = in->pos();
|
||||
size = parser->determineDataSize(in);
|
||||
if (size < 0) {
|
||||
warning("MusicPlayer::load - Could not determine size of music data");
|
||||
return;
|
||||
}
|
||||
// determineDataSize might move the stream position, so return it to
|
||||
// the original position.
|
||||
in->seek(startPos);
|
||||
}
|
||||
|
||||
if (!sfx && isPlayingMusic()) {
|
||||
stopMusic();
|
||||
_musicParser->unloadMusic();
|
||||
}
|
||||
if (sfx && isPlayingSfx()) {
|
||||
stopAllSfx();
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
_sfxParsers[i]->unloadMusic();
|
||||
}
|
||||
}
|
||||
if (*dataPtr != nullptr) {
|
||||
delete[] *dataPtr;
|
||||
}
|
||||
|
||||
*dataPtr = new byte[size];
|
||||
in->read(*dataPtr, size);
|
||||
|
||||
if (!sfx) {
|
||||
_musicParser->loadMusic(*dataPtr, size);
|
||||
}
|
||||
else {
|
||||
for (int i = 0; i < NUM_SFX_PARSERS; i++) {
|
||||
_sfxParsers[i]->loadMusic(*dataPtr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MusicPlayer::loadTosInstrumentBankData(Common::SeekableReadStream* in, int32 size) {
|
||||
if (size != 4096) {
|
||||
warning("MusicPlayer::loadTosInstrumentBankData - Specified instrument bank has unexpected size %d", size);
|
||||
return;
|
||||
}
|
||||
|
||||
if (_tosInstrumentBankData != nullptr)
|
||||
delete[] _tosInstrumentBankData;
|
||||
|
||||
_tosInstrumentBankData = new byte[size];
|
||||
in->read(_tosInstrumentBankData, size);
|
||||
}
|
||||
|
||||
void MusicPlayer::loadTosInstrumentBank() {
|
||||
if (_floppyAdLibDriver == nullptr) {
|
||||
warning("MusicPlayer::loadTosInstrumentBank - Driver does not support instrument banks");
|
||||
return;
|
||||
}
|
||||
if (_tosInstrumentBankData == nullptr) {
|
||||
warning("MusicPlayer::loadTosInstrumentBank - TOS instrument bank data has not been loaded");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_tosInstrumentBankLoaded) {
|
||||
if (isPlayingMusic())
|
||||
stopMusic();
|
||||
_floppyAdLibDriver->loadInstrumentBank(_tosInstrumentBankData);
|
||||
_tosInstrumentBankLoaded = true;
|
||||
}
|
||||
}
|
||||
|
||||
void MusicPlayer::loadInstrumentBank(Common::SeekableReadStream *in, int32 size) {
|
||||
if (_floppyAdLibDriver == nullptr) {
|
||||
warning("MusicPlayer::loadInstrumentBank - Driver does not support instrument banks");
|
||||
return;
|
||||
}
|
||||
if (size != 4096) {
|
||||
warning("MusicPlayer::loadInstrumentBank - Specified instrument bank has unexpected size %d", size);
|
||||
return;
|
||||
}
|
||||
|
||||
byte *instrumentBankData = new byte[size];
|
||||
in->read(instrumentBankData, size);
|
||||
|
||||
if (isPlayingMusic())
|
||||
stopMusic();
|
||||
_floppyAdLibDriver->loadInstrumentBank(instrumentBankData);
|
||||
_tosInstrumentBankLoaded = false;
|
||||
}
|
||||
|
||||
bool MusicPlayer::isSampleSfx(uint8 sfxId) {
|
||||
if (_sfxParserSbr == nullptr)
|
||||
return false;
|
||||
return _sfxParserSbr->isSampleSfx(sfxId);
|
||||
}
|
||||
|
||||
void MusicPlayer::playMusic(uint8 priority, bool loop) {
|
||||
Common::StackLock lock(_mutex);
|
||||
|
||||
if (_musicParser == nullptr || _driver == nullptr)
|
||||
return;
|
||||
|
||||
if (!_useFloppyMusic)
|
||||
_musicParser->property(MidiParser::mpAutoLoop, loop);
|
||||
if (_floppyAdLibDriver != nullptr)
|
||||
_floppyAdLibDriver->setSourcePriority(0, priority);
|
||||
|
||||
if (_driver->isFading())
|
||||
_driver->abortFade();
|
||||
_driver->resetSourceVolume(0);
|
||||
|
||||
_musicParser->startPlaying();
|
||||
}
|
||||
|
||||
void MusicPlayer::startFadeOutMusic() {
|
||||
_driver->startFade(0, 1100, 0);
|
||||
}
|
||||
|
||||
bool MusicPlayer::isFadingMusic() {
|
||||
return _driver->isFading();
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
97
engines/darkseed/music.h
Normal file
97
engines/darkseed/music.h
Normal file
@@ -0,0 +1,97 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_MUSIC_H
|
||||
#define DARKSEED_MUSIC_H
|
||||
|
||||
#include "darkseed/adlib_dsf.h"
|
||||
#include "darkseed/adlib_worx.h"
|
||||
#include "darkseed/midiparser_sbr.h"
|
||||
|
||||
#include "audio/mididrv_ms.h"
|
||||
#include "audio/midiparser.h"
|
||||
#include "common/mutex.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class DarkseedEngine;
|
||||
|
||||
class MusicPlayer {
|
||||
protected:
|
||||
static const uint8 NUM_SFX_PARSERS = 5;
|
||||
|
||||
DarkseedEngine *_vm;
|
||||
|
||||
Common::Mutex _mutex;
|
||||
MidiDriver_Multisource *_driver;
|
||||
MidiDriver_DarkSeedFloppy_AdLib *_floppyAdLibDriver;
|
||||
|
||||
MidiParser *_musicParser;
|
||||
MidiParser *_sfxParsers[NUM_SFX_PARSERS];
|
||||
MidiParser_SBR *_sfxParserSbr;
|
||||
// The type of the music device selected for playback.
|
||||
MusicType _deviceType;
|
||||
byte *_musicData;
|
||||
byte *_sfxData;
|
||||
byte *_tosInstrumentBankData;
|
||||
bool _tosInstrumentBankLoaded;
|
||||
bool _useFloppyMusic;
|
||||
bool _useFloppySfx;
|
||||
|
||||
bool _paused;
|
||||
|
||||
static void onTimer(void *data);
|
||||
|
||||
public:
|
||||
MusicPlayer(DarkseedEngine *vm, bool useFloppyMusic, bool useFloppySfx);
|
||||
~MusicPlayer();
|
||||
|
||||
int open();
|
||||
|
||||
void load(Common::SeekableReadStream *in, int32 size = -1, bool sfx = false);
|
||||
void loadTosInstrumentBankData(Common::SeekableReadStream *in, int32 size = -1);
|
||||
void loadTosInstrumentBank();
|
||||
void loadInstrumentBank(Common::SeekableReadStream *in, int32 size = -1);
|
||||
bool isSampleSfx(uint8 sfxId);
|
||||
|
||||
void playMusic(uint8 priority = 0xFF, bool loop = false);
|
||||
void setLoopMusic(bool loop);
|
||||
bool isPlayingMusic();
|
||||
void stopMusic();
|
||||
void pauseMusic(bool pause);
|
||||
void playSfx(uint8 sfxId, uint8 priority = 0xFF);
|
||||
bool isPlayingSfx();
|
||||
bool isPlayingSfx(uint8 sfxId);
|
||||
void stopAllSfx();
|
||||
bool stopSfx(uint8 sfxId);
|
||||
|
||||
void startFadeOutMusic();
|
||||
bool isFadingMusic();
|
||||
|
||||
void syncSoundSettings();
|
||||
|
||||
protected:
|
||||
uint8 assignSfxParser();
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_MUSIC_H
|
||||
272
engines/darkseed/nsp.cpp
Normal file
272
engines/darkseed/nsp.cpp
Normal file
@@ -0,0 +1,272 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/nsp.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
Sprite::Sprite(uint16 width, uint16 height, uint16 pitch) : _width(width), _height(height), _pitch(pitch) {
|
||||
_pixels.resize(pitch * height, 0);
|
||||
}
|
||||
|
||||
bool Sprite::loadData(Common::SeekableReadStream &readStream) {
|
||||
g_engine->waitForSpeech();
|
||||
if (_width == 1 && _height == 1) {
|
||||
byte b = readStream.readByte();
|
||||
_pixels[0] = b >> 4;
|
||||
} else {
|
||||
bool hasReadByte = false;
|
||||
int currentDataByte = 0;
|
||||
for (int i = 0; i < _pitch * _height; i++) {
|
||||
if (!hasReadByte) {
|
||||
currentDataByte = readStream.readByte();
|
||||
if (readStream.eos()) {
|
||||
debug("Argh!");
|
||||
return false;
|
||||
}
|
||||
hasReadByte = true;
|
||||
_pixels[i] = currentDataByte >> 4;
|
||||
} else {
|
||||
hasReadByte = false;
|
||||
_pixels[i] = currentDataByte & 0xf;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void Sprite::clipToScreen(int x, int y, uint16 frameBottom, uint16 *clippedWidth, uint16 *clippedHeight) const {
|
||||
*clippedWidth = _width;
|
||||
*clippedHeight = _height;
|
||||
if (x + _width > g_engine->_screen->w) {
|
||||
*clippedWidth = g_engine->_screen->w - x;
|
||||
}
|
||||
if (x + _width > 570) {
|
||||
*clippedWidth = 570 - x;
|
||||
}
|
||||
if (frameBottom != 0 && y + _height > g_engine->_frameBottom) {
|
||||
if (y >= frameBottom) {
|
||||
return;
|
||||
}
|
||||
*clippedHeight = frameBottom - y;
|
||||
}
|
||||
}
|
||||
|
||||
void Sprite::draw(int x, int y, uint16 frameBottom) const {
|
||||
uint16 clippedWidth = _width;
|
||||
uint16 clippedHeight = _height;
|
||||
clipToScreen(x, y, frameBottom, &clippedWidth, &clippedHeight);
|
||||
|
||||
// clip to left side of frame.
|
||||
if (x + _width <= 70) {
|
||||
return;
|
||||
}
|
||||
int dX = 0;
|
||||
if (x < 70) {
|
||||
dX = 70 - x;
|
||||
x = 70;
|
||||
clippedWidth -= dX;
|
||||
}
|
||||
const uint8 *pixels = _pixels.data() + dX;
|
||||
g_engine->_screen->copyRectToSurfaceWithKey(pixels, _pitch, x, y, clippedWidth, clippedHeight, 0xf);
|
||||
}
|
||||
|
||||
void Sprite::draw(Graphics::Surface *dst, int x, int y, uint16 frameBottom) const {
|
||||
uint16 clippedWidth = _width;
|
||||
uint16 clippedHeight = _height;
|
||||
clipToScreen(x, y, frameBottom, &clippedWidth, &clippedHeight);
|
||||
dst->copyRectToSurfaceWithKey(_pixels.data(), _pitch, x, y, clippedWidth, clippedHeight, 0xf);
|
||||
}
|
||||
|
||||
void Sprite::drawScaled(int destX, int destY, int destWidth, int destHeight, bool flipX) const {
|
||||
//TODO image isn't exactly the same when not scaling. It seems larger by about a pixel.
|
||||
//TODO this logic is pretty messy. It should probably be re-written. It is trying to scale, clip and flip at once.
|
||||
Graphics::ManagedSurface * destSurface = g_engine->_screen;
|
||||
// Based on the GNAP engine scaling code
|
||||
if (destWidth == 0 || destHeight == 0) {
|
||||
return;
|
||||
}
|
||||
const byte *source = _pixels.data();
|
||||
const int xs = ((_width - 1) << 16) / destWidth;
|
||||
const int ys = ((_height - 1) << 16) / destHeight;
|
||||
int clipX = 0, clipY = 0;
|
||||
const int destPitch = destSurface->pitch;
|
||||
if (destX < 0) {
|
||||
clipX = -destX;
|
||||
destX = 0;
|
||||
destWidth -= clipX;
|
||||
}
|
||||
|
||||
if (destY < 0) {
|
||||
clipY = -destY;
|
||||
destY = 0;
|
||||
destHeight -= clipY;
|
||||
}
|
||||
if (destY + destHeight >= destSurface->h) {
|
||||
destHeight = destSurface->h - destY;
|
||||
}
|
||||
if (destWidth < 0 || destHeight < 0)
|
||||
return;
|
||||
byte *dst = (byte *)destSurface->getBasePtr(destX, destY);
|
||||
int yi = ys * clipY;
|
||||
const byte *hsrc = source + _pitch * ((yi + 0x8000) >> 16);
|
||||
int16 currY = destY;
|
||||
for (int yc = 0; yc < destHeight && currY < g_engine->_frameBottom; ++yc) {
|
||||
byte *wdst = flipX ? dst + (destWidth - 1) : dst;
|
||||
int16 currX = flipX ? destX + (destWidth - 1) : destX;
|
||||
int xi = flipX ? xs : xs * clipX;
|
||||
const byte *wsrc = hsrc + ((xi + 0x8000) >> 16);
|
||||
for (int xc = 0; xc < destWidth; ++xc) {
|
||||
if (currX > 69 && currX < 570 && currX < destSurface->w) { // clip to game window. TODO pass clip rect into method.
|
||||
byte colorIndex = *wsrc;
|
||||
// uint16 c = READ_LE_UINT16(&palette[colorIndex * 2]);
|
||||
if (colorIndex != 0xf) {
|
||||
*wdst = colorIndex;
|
||||
// if (!(c & 0x8000u) || alpha == NONE) {
|
||||
// // only copy opaque pixels
|
||||
// WRITE_SCREEN(wdst, c & ~0x8000);
|
||||
// } else {
|
||||
// WRITE_SCREEN(wdst, alphaBlendRGB555(c & 0x7fffu, READ_SCREEN(wdst) & 0x7fffu, 128));
|
||||
// // semi-transparent pixels.
|
||||
// }
|
||||
}
|
||||
}
|
||||
currX += (flipX ? -1 : 1);
|
||||
wdst += (flipX ? -1 : 1);
|
||||
xi += xs;
|
||||
wsrc = hsrc + ((xi + 0x8000) >> 16);
|
||||
}
|
||||
dst += destPitch;
|
||||
yi += ys;
|
||||
hsrc = source + _pitch * ((yi + 0x8000) >> 16);
|
||||
currY++;
|
||||
}
|
||||
}
|
||||
|
||||
bool Nsp::load(const Common::Path &filename) {
|
||||
Common::File file;
|
||||
Common::Path filePath = g_engine->getRoomFilePath(filename);
|
||||
if (!file.open(filePath)) {
|
||||
return false;
|
||||
}
|
||||
bool ret = load(file);
|
||||
file.close();
|
||||
if (ret) {
|
||||
Common::String filePathStr = filePath.toString();
|
||||
debug("Loaded %s", filePathStr.c_str());
|
||||
Common::Path obtFilename = Common::Path(filePathStr.substr(0, filePathStr.size() - 4) + ".obt");
|
||||
if (!loadObt(obtFilename)) {
|
||||
debug("failed to load %s", obtFilename.toString().c_str());
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Nsp::load(Common::SeekableReadStream &readStream) {
|
||||
_frames.clear();
|
||||
for (int i = 0; i < 96; i++) {
|
||||
int w = readStream.readByte();
|
||||
int h = readStream.readByte();
|
||||
int p = w + (w & 1);
|
||||
_frames.push_back(Sprite(w, h, p));
|
||||
}
|
||||
|
||||
for (int i = 0; i < 96; i++) {
|
||||
if (!_frames[i].loadData(readStream)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const Sprite &Nsp::getSpriteAt(int index) const {
|
||||
if (index >= (int)_frames.size()) {
|
||||
error("getSpriteAt: Invalid sprite index. %d", index);
|
||||
}
|
||||
return _frames[index];
|
||||
}
|
||||
|
||||
bool Nsp::loadObt(const Common::Path &filename) {
|
||||
Common::File file;
|
||||
if (!file.open(filename)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_animations.clear();
|
||||
_animations.resize(20);
|
||||
for (int i = 0; i < 20; i++) {
|
||||
_animations[i]._numFrames = file.readByte();
|
||||
|
||||
for (int j = 0; j < 20; j++) {
|
||||
if (file.readByte()) {
|
||||
_animations[i]._deltaX.push_back(-(file.readUint16LE() / 100));
|
||||
} else {
|
||||
_animations[i]._deltaX.push_back(file.readUint16LE() / 100);
|
||||
}
|
||||
if (file.readByte()) {
|
||||
_animations[i]._deltaY.push_back(-(file.readUint16LE() / 100));
|
||||
} else {
|
||||
_animations[i]._deltaY.push_back(file.readUint16LE() / 100);
|
||||
}
|
||||
_animations[i]._frameNo.push_back(file.readByte());
|
||||
_animations[i]._frameDuration.push_back(file.readByte());
|
||||
}
|
||||
}
|
||||
|
||||
file.close();
|
||||
|
||||
debug("Loaded %s", filename.toString().c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
const Obt &Nsp::getAnimAt(int index) {
|
||||
return _animations[index];
|
||||
}
|
||||
|
||||
int16 Nsp::getMaxSpriteWidth() {
|
||||
int maxWidth = 0;
|
||||
for (auto &frame : _frames) {
|
||||
if (frame._width > maxWidth) {
|
||||
maxWidth = frame._width;
|
||||
}
|
||||
}
|
||||
return maxWidth;
|
||||
}
|
||||
|
||||
Obt::Obt() {
|
||||
_numFrames = 0;
|
||||
_deltaX.reserve(20);
|
||||
_deltaY.reserve(20);
|
||||
_frameNo.reserve(20);
|
||||
_frameDuration.reserve(20);
|
||||
}
|
||||
|
||||
Obt::~Obt() {
|
||||
_deltaX.clear();
|
||||
_deltaY.clear();
|
||||
_frameNo.clear();
|
||||
_frameDuration.clear();
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
84
engines/darkseed/nsp.h
Normal file
84
engines/darkseed/nsp.h
Normal file
@@ -0,0 +1,84 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_NSP_H
|
||||
#define DARKSEED_NSP_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/path.h"
|
||||
#include "common/stream.h"
|
||||
#include "common/scummsys.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Sprite {
|
||||
public:
|
||||
uint16 _width;
|
||||
uint16 _height;
|
||||
uint16 _pitch;
|
||||
Common::Array<uint8> _pixels;
|
||||
|
||||
Sprite(uint16 width, uint16 height, uint16 pitch);
|
||||
bool loadData(Common::SeekableReadStream &readStream);
|
||||
void draw(int x, int y, uint16 frameBottom = 0) const;
|
||||
void draw(Graphics::Surface *dst, int x, int y, uint16 frameBottom = 0) const;
|
||||
void drawScaled(int x, int y, int destWidth, int destHeight, bool flipX) const;
|
||||
|
||||
private:
|
||||
void clipToScreen(int x, int y, uint16 frameBottom, uint16 *clippedWidth, uint16 *clippedHeight) const;
|
||||
};
|
||||
|
||||
class Obt {
|
||||
public:
|
||||
uint8 _numFrames;
|
||||
Common::Array<int32> _deltaX;
|
||||
Common::Array<int32> _deltaY;
|
||||
Common::Array<uint8> _frameNo;
|
||||
Common::Array<uint8> _frameDuration;
|
||||
Obt();
|
||||
virtual ~Obt();
|
||||
};
|
||||
|
||||
class Nsp {
|
||||
Common::Array<Sprite> _frames;
|
||||
Common::Array<Obt> _animations;
|
||||
|
||||
public:
|
||||
bool load(const Common::Path &filename);
|
||||
bool containsSpriteAt(int index) const {
|
||||
return (int)_frames.size() > index;
|
||||
}
|
||||
const Sprite &getSpriteAt(int index) const;
|
||||
const Obt &getAnimAt(int index);
|
||||
int16 getTotalAnim() const {
|
||||
return (int16)_animations.size();
|
||||
}
|
||||
int16 getMaxSpriteWidth();
|
||||
|
||||
private:
|
||||
bool load(Common::SeekableReadStream &readStream);
|
||||
bool loadObt(const Common::Path &filename);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_NSP_H
|
||||
836
engines/darkseed/object_name_tables.h
Normal file
836
engines/darkseed/object_name_tables.h
Normal file
@@ -0,0 +1,836 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_OBJECT_NAME_TABLES_H
|
||||
#define DARKSEED_OBJECT_NAME_TABLES_H
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
static constexpr char objectNameTbl_en[199][21] = {
|
||||
"Nothing.",
|
||||
"Box",
|
||||
"hand",
|
||||
"eye",
|
||||
"Ctrl",
|
||||
"crowbar",
|
||||
"journal",
|
||||
"scotch",
|
||||
"money",
|
||||
"newspaper",
|
||||
"library card",
|
||||
"bobby pin",
|
||||
"journal scrap",
|
||||
"clock key",
|
||||
"gloves",
|
||||
"mirror shard",
|
||||
"binoculars",
|
||||
"shovel",
|
||||
"business card",
|
||||
"stick",
|
||||
"axe handle",
|
||||
"head band",
|
||||
"trunk",
|
||||
"rope",
|
||||
"microfiche card",
|
||||
"loose rock",
|
||||
"car keys",
|
||||
"hammer",
|
||||
"gun",
|
||||
"grave journal scrap",
|
||||
"note from movers",
|
||||
"package",
|
||||
"package",
|
||||
"package",
|
||||
"blue print",
|
||||
"watch",
|
||||
"crackers",
|
||||
"sardines",
|
||||
"insecticide",
|
||||
"soysauce",
|
||||
"olives",
|
||||
"tin cup",
|
||||
"trunk lock",
|
||||
"book 'Alien'",
|
||||
"gas cap",
|
||||
"Fido",
|
||||
"librarian",
|
||||
"telephone",
|
||||
"bone bars",
|
||||
"stairs",
|
||||
"brass urn",
|
||||
"viewscreen",
|
||||
"shower",
|
||||
"sergeant",
|
||||
"guard",
|
||||
"evil plans",
|
||||
"evil sergeant",
|
||||
"starship lever",
|
||||
"Dreketh guards",
|
||||
"secret door",
|
||||
"turbo door",
|
||||
"post",
|
||||
"radio dial",
|
||||
"exit in car",
|
||||
"guard",
|
||||
"prisoner lock",
|
||||
"tomb left",
|
||||
"tomb up",
|
||||
"tomb right",
|
||||
"front door",
|
||||
"top of stairs",
|
||||
"car ignition",
|
||||
"police at door",
|
||||
"evil mike",
|
||||
"Gcell lock",
|
||||
"tombstone",
|
||||
"ladder down",
|
||||
"ladder",
|
||||
"secret door 2",
|
||||
"evil fido",
|
||||
"microfiche",
|
||||
"box behind desk",
|
||||
"button",
|
||||
"library floor",
|
||||
"book",
|
||||
"store",
|
||||
"glove compartment",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tombstone",
|
||||
"tomb door",
|
||||
"coat",
|
||||
"car trunk",
|
||||
"rope tied to house",
|
||||
"clock",
|
||||
"cupboard",
|
||||
"cupboard",
|
||||
"cupboard",
|
||||
"cupboard",
|
||||
"stove",
|
||||
"drawer",
|
||||
"kitchen tap",
|
||||
"bathroom tap",
|
||||
"medicine chest",
|
||||
"pillow",
|
||||
"Ancient",
|
||||
"power nexus",
|
||||
"abyss",
|
||||
"observatory lever",
|
||||
"horizon",
|
||||
"force field",
|
||||
"leech victims",
|
||||
"shrubs",
|
||||
"railing",
|
||||
"bed",
|
||||
"artwork",
|
||||
"carpet",
|
||||
"chair",
|
||||
"spittoon",
|
||||
"bed",
|
||||
"bed bottom",
|
||||
"fridge",
|
||||
"books",
|
||||
"globe",
|
||||
"mug shots",
|
||||
"map",
|
||||
"desk",
|
||||
"xxx",
|
||||
"mirror",
|
||||
"clerk",
|
||||
"ladder",
|
||||
"postman",
|
||||
"Delbert",
|
||||
"cement rock",
|
||||
"towels",
|
||||
"water heater",
|
||||
"bathtub",
|
||||
"xxx",
|
||||
"couch",
|
||||
"window",
|
||||
"art",
|
||||
"art",
|
||||
"clock",
|
||||
"counter",
|
||||
"books",
|
||||
"desk",
|
||||
"xxx",
|
||||
"desk",
|
||||
"books",
|
||||
"arch",
|
||||
"ground",
|
||||
"pillars",
|
||||
"caskets",
|
||||
"horizon",
|
||||
"urn",
|
||||
"urn",
|
||||
"urn",
|
||||
"urn",
|
||||
"urn",
|
||||
"urn",
|
||||
"xxx",
|
||||
"soccer ball",
|
||||
"skis",
|
||||
"trunk",
|
||||
"bottles",
|
||||
"barrels",
|
||||
"wheel",
|
||||
"car",
|
||||
"furniture",
|
||||
"xxx",
|
||||
"cocoons",
|
||||
"wall of skulls",
|
||||
"creature",
|
||||
"glass case",
|
||||
"power cables",
|
||||
"tubes",
|
||||
"brain nexus",
|
||||
"xxx",
|
||||
"control panel",
|
||||
"desk",
|
||||
"cell bars",
|
||||
"cell bars",
|
||||
"console",
|
||||
"viewer",
|
||||
"building",
|
||||
"box",
|
||||
"tools",
|
||||
"newspaper",
|
||||
"table",
|
||||
"bed bottom",
|
||||
};
|
||||
|
||||
static constexpr char objectNameTbl_fr[199][22] = {
|
||||
"RIEN",
|
||||
"LA BOITE",
|
||||
"LA MAIN",
|
||||
"LA QUESTION",
|
||||
"CTRL",
|
||||
"LE MANIVELLE",
|
||||
"LE JOURNAL",
|
||||
"LE WHISKY",
|
||||
"DE L'ARGENT",
|
||||
"LE JOURNAL",
|
||||
"LA CARTE DE PRET",
|
||||
"LA PINCE",
|
||||
"LE BOUT DE JOURNAL",
|
||||
"LA CLEF DE L'HORLOGE",
|
||||
"LES GANTS",
|
||||
"UN FRAGMENT DU MIROIR",
|
||||
"LES JUMELLES",
|
||||
"LA PELLE",
|
||||
"CARTE PROFESSIONNELLE",
|
||||
"LE BATON",
|
||||
"LA COGNEE",
|
||||
"LE BANDEAU",
|
||||
"LE COFFRE",
|
||||
"LA CORDE",
|
||||
"CARTE A MICROFICHES",
|
||||
"PIERRE DESCELLEE",
|
||||
"CLEFS DE LA VOITURE",
|
||||
"MARTEAU",
|
||||
"L'ARME",
|
||||
"JOURNAL DU CIMETIERE",
|
||||
"NOTE DES DEMENAGEURS",
|
||||
"LE PAQUET",
|
||||
"LE PAQUET",
|
||||
"LE PAQUET",
|
||||
"LE PLAN",
|
||||
"LA MONTRE",
|
||||
"DES CRACKERS",
|
||||
"DES SARDINES",
|
||||
"UN INSECTICIDE",
|
||||
"UNE SAUCE AU SOJA",
|
||||
"LES OLIVES",
|
||||
"TIMBALE EN ETAIN",
|
||||
"SERRURE DU COFFRE",
|
||||
"LIVRE 'ALIEN'",
|
||||
"LE BOUCHON",
|
||||
"FIDO",
|
||||
"LE BIBLIOTHECAIRE",
|
||||
"LE TELEPHONE",
|
||||
"UNE BARRE EN OS",
|
||||
"LES ESCALIERS",
|
||||
"L'URNE EN CUIVRE",
|
||||
"L'ECRAN",
|
||||
"LA DOUCHE",
|
||||
"LE SERGENT",
|
||||
"XXX",
|
||||
"DES PLANS MAUDITS",
|
||||
"LE SERGENT MALEFIQUE",
|
||||
"MANETTE DU VAISSEAU",
|
||||
"LES GARDES DE DREKETH",
|
||||
"LA PORTE DEROBEE",
|
||||
"LA PORTE TURBO",
|
||||
"POSTE",
|
||||
"SELECTEUR RADIO",
|
||||
"SORTIE EN VOITURE",
|
||||
"DELBERT",
|
||||
"LE VERROU",
|
||||
"LA TOMBE A GAUCHE",
|
||||
"LA TOMBE EN HAUT",
|
||||
"LA TOMBE A DROITE",
|
||||
"LA PORTE DE DEVANT",
|
||||
"LE HAUT DES ESCALIERS",
|
||||
"LE CONTACT",
|
||||
"POLICE CHEZ VOUS",
|
||||
"MALFAISANT MIKE",
|
||||
"VERROU CELL. G",
|
||||
"LA PIERRE TOMBALE",
|
||||
"L'ECHELLE",
|
||||
"L'ECHELLE",
|
||||
"LA PORTE DEROBEE",
|
||||
"MAUVAIS FIDO",
|
||||
"LA MICROFICHE",
|
||||
"BOITE APRES LE BUREAU",
|
||||
"LE BOUTON",
|
||||
"ETAGE BIBLIOTHEQUE",
|
||||
"LE LIVRE",
|
||||
"LE MAGASIN",
|
||||
"LE LIVRE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PIERRE TOMBALE",
|
||||
"LA PORTE DU CAVEAU",
|
||||
"LE MANTEAU",
|
||||
"COFFRE DE L'AUTO",
|
||||
"CORDE LIEE AU LOGIS",
|
||||
"L'HORLOGE",
|
||||
"LE PLACARD",
|
||||
"LE PLACARD",
|
||||
"LE PLACARD",
|
||||
"LE PLACARD",
|
||||
"LE FOUR",
|
||||
"LE TIROIR",
|
||||
"ROBINET DE LA CUISINE",
|
||||
"ROBINET",
|
||||
"BOITE A PHARMACIE",
|
||||
"L'OREILLER",
|
||||
"L'ANCIEN",
|
||||
"LIEN DE PUISSANCE",
|
||||
"L'ABYSSE",
|
||||
"POIGNER",
|
||||
"L'HORIZON",
|
||||
"LE CHAMPS DE FORCE",
|
||||
"VICTIME DE SANGSUES",
|
||||
"DES ARBUSTES",
|
||||
"LES RAMPES",
|
||||
"LE LIT",
|
||||
"LE DECORUM",
|
||||
"LE TAPIS",
|
||||
"LA CHAISE",
|
||||
"LE CRACHOIR",
|
||||
"LE LIT",
|
||||
"LE PIED DU LIT",
|
||||
"LE REFRIGERATEUR",
|
||||
"LES LIVRES",
|
||||
"LE GLOBE",
|
||||
"PHOTOS D'IDENTITE",
|
||||
"LA CARTE",
|
||||
"LE BUREAU",
|
||||
"XXX",
|
||||
"LE MIROIR",
|
||||
"L'EMPLOYE",
|
||||
"LE CORDON",
|
||||
"LE POSTIER",
|
||||
"DELBERT",
|
||||
"LE BLOC DE CIMENT",
|
||||
"LES SERVIETTES",
|
||||
"LE CHAUFFE-EAU",
|
||||
"LA BAIGNOIRE",
|
||||
"XXX",
|
||||
"LE DIVAN",
|
||||
"LA FENETRE",
|
||||
"L'ART",
|
||||
"L'ART",
|
||||
"L'HORLOGE",
|
||||
"LE COMPTOIR",
|
||||
"LES LIVRES",
|
||||
"LE BUREAU",
|
||||
"XXX",
|
||||
"LE BUREAU",
|
||||
"LES LIVRES",
|
||||
"L'ARCHE",
|
||||
"LE SOL",
|
||||
"LES COLONNES",
|
||||
"LES BOITES",
|
||||
"L'HORIZON",
|
||||
"L'URNE",
|
||||
"L'URNE",
|
||||
"L'URNE",
|
||||
"L'URNE",
|
||||
"L'URNE",
|
||||
"L'URNE",
|
||||
"XXX",
|
||||
"BALLON DE FOOT",
|
||||
"LES SKIS",
|
||||
"LE COFFRE",
|
||||
"LES BOUTEILLES",
|
||||
"LES TONNEAUX",
|
||||
"LE VOLANT",
|
||||
"LA VOITURE",
|
||||
"LES MEUBLES",
|
||||
"XXX",
|
||||
"LES COCONS",
|
||||
"LE MUR DE CRANES",
|
||||
"LA CREATURE",
|
||||
"LE GLOBE",
|
||||
"CABLES D'ALIMENTATION",
|
||||
"LES TUBES",
|
||||
"LIEN DU CERVEAU",
|
||||
"XXX",
|
||||
"LE TABLEAU DE BORD",
|
||||
"LE BUREAU",
|
||||
"LE BARREAU",
|
||||
"LE BARREAU",
|
||||
"LA CONSOLE",
|
||||
"LA VISIONNEUSE",
|
||||
"LE BATIMENT",
|
||||
"LA BOITE",
|
||||
"LES OUTILS",
|
||||
"LE JOURNAL",
|
||||
"LA TABLE",
|
||||
"PIED DU LIT"
|
||||
};
|
||||
|
||||
static constexpr char objectNameTbl_de[199][27] = {
|
||||
"NICHTS",
|
||||
"DER KASTEN",
|
||||
"DIE HAND",
|
||||
"DIE FRAGE",
|
||||
"CTRL",
|
||||
"DAS BRECHEISEN",
|
||||
"DAS TAGEBUCH",
|
||||
"DIE FLASCHE SCOTCH",
|
||||
"DAS GELD",
|
||||
"DIE ZEITUNG",
|
||||
"DIE BUECHEREIKARTE",
|
||||
"DIE HAARNADEL",
|
||||
"DIE TAGEBUCHSCHNIPSEL",
|
||||
"DER UHRENSCHLUESSEL",
|
||||
"DIE HANDSCHUHE",
|
||||
"DIE SPIEGELSCHERBE",
|
||||
"DAS FERNGLAS",
|
||||
"DIE SCHAUFEL",
|
||||
"DIE VISITENKARTE",
|
||||
"DER STOCK",
|
||||
"DER AXTGRIFF",
|
||||
"DAS STIRNBAND",
|
||||
"DIE TRUHE",
|
||||
"DAS SEIL",
|
||||
"DIE MIKROFILMKARTE",
|
||||
"DER LOSER STEIN",
|
||||
"DIE AUTOSCHLUESSEL",
|
||||
"DER HAMMER",
|
||||
"DIE PISTOLE",
|
||||
"DIE TAGEBUCHSEITEN",
|
||||
"DIE NOTIZ DER MOEBELPACKER",
|
||||
"DAS PAKET",
|
||||
"DAS PAKET",
|
||||
"DAS PAKET",
|
||||
"DIE BLAUPAUSE",
|
||||
"DIE UHR",
|
||||
"DIE KEKSE",
|
||||
"DIE SARDINEN",
|
||||
"DAS INSEKTENSPRAY",
|
||||
"DIE SOJASAUCE",
|
||||
"DIE OLIVEN",
|
||||
"DER ZINNBECHER",
|
||||
"DAS TRUHENSCHLOSS",
|
||||
"DAS BUCH 'AUSSERIRDISCHER'",
|
||||
"DER GASHAHN",
|
||||
"DER FIDO",
|
||||
"DIE BIBLIOTHEKARIN",
|
||||
"DAS TELEFON",
|
||||
"DIE KNOCHENGITTER",
|
||||
"DIE STUFEN",
|
||||
"DIE MESSING-URNE",
|
||||
"DER BILDSCHIRM",
|
||||
"DIE DUSCHE",
|
||||
"DER POLIZIST",
|
||||
"xxx",
|
||||
"DIE PLAENE DER BOESEN",
|
||||
"DER BOESER POLIZIST",
|
||||
"DER HEBEL FUER RAUMSCHIFF",
|
||||
"DIE DREKETH-WACHEN",
|
||||
"DIE GEHEIMTUER",
|
||||
"DIE AUFZUGTUER",
|
||||
"DIE POST",
|
||||
"DIE FREQUENZANZEIGE",
|
||||
"DER AUSGANG IM AUTO",
|
||||
"DER DELBERT",
|
||||
"DAS GEFAENGNISSCHLOSS",
|
||||
"DIE LINKE STEINPLATTE",
|
||||
"DIE OBERE STEINPLATTE",
|
||||
"DIE RECHTE STEINPLATTE",
|
||||
"DIE HAUSTUER",
|
||||
"DIE OBERSTE STUFE",
|
||||
"DAS ZUENDSCHLOSS",
|
||||
"DIE POLIZEI AN DER TUER",
|
||||
"DER BOESER MIKE",
|
||||
"DAS ZELLENSCHLOSS",
|
||||
"DER GRABSTEIN",
|
||||
"DIE LEITER",
|
||||
"DIE LEITER",
|
||||
"DIE GEHEIMTUER",
|
||||
"DER BOESER FIDO",
|
||||
"DER MIKROFILM",
|
||||
"DER KASTEN HINTER PULT",
|
||||
"DER KNOPF",
|
||||
"DER BUECHERGANG",
|
||||
"DAS BUCH",
|
||||
"DER LADEN",
|
||||
"DAS BUCH",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DER GRABSTEIN",
|
||||
"DIE TUER DER GRUFT",
|
||||
"DER MANTEL",
|
||||
"DER KOFFERRAUM",
|
||||
"DAS ANGEBUNDENES SEIL",
|
||||
"DIE UHR",
|
||||
"DER SCHRANK",
|
||||
"DER SCHRANK",
|
||||
"DER SCHRANK",
|
||||
"DER SCHRANK",
|
||||
"DER HERD",
|
||||
"DIE SCHUBLADE",
|
||||
"DER KUECHEN-WASSERHAHN",
|
||||
"DER BAD-WASSERHAHN",
|
||||
"DER MEDIZINSCHRANK",
|
||||
"DIE KISSEN",
|
||||
"DIE ALTER",
|
||||
"DIE STROMVERSORGUNG",
|
||||
"DER ABGRUND",
|
||||
"DER OBSERVATORIUMSHEBEL",
|
||||
"DER HORIZONT",
|
||||
"DAS KRAFTFELD",
|
||||
"DER OPFER DES BLUTSAUGERS",
|
||||
"DIE BUESCHE",
|
||||
"DAS GELAENDER",
|
||||
"DAS BETT",
|
||||
"DAS KUNSTWERK",
|
||||
"DER TEPPICH",
|
||||
"DER STUHL",
|
||||
"DER SPUCKNAPF",
|
||||
"DAS BETT",
|
||||
"DER FUSS DES BETTES",
|
||||
"DER KUEHLSCHRANK",
|
||||
"DIE BUECHER",
|
||||
"DER GLOBUS",
|
||||
"DIE PHANTOMBILDER",
|
||||
"DIE KARTE",
|
||||
"DER SCHREIBTISCH",
|
||||
"xxx",
|
||||
"DER SPIEGEL",
|
||||
"DER ANGESTELLTER",
|
||||
"DAS SEIL",
|
||||
"DER POSTBOTE",
|
||||
"DER DELBERT",
|
||||
"DAS ZEMENTGESTEIN",
|
||||
"DIE HANDTUECHER",
|
||||
"DER BOILER",
|
||||
"DIE BADEWANNE",
|
||||
"xxx",
|
||||
"DIE COUCH",
|
||||
"DIE FENSTER",
|
||||
"DIE KUNST",
|
||||
"DIE KUNST",
|
||||
"DIE UHR",
|
||||
"DIE TRESEN",
|
||||
"DIE BUECHER",
|
||||
"DER SCHREIBTISCH",
|
||||
"xxx",
|
||||
"DER SCHREIBTISCH",
|
||||
"DIE BUECHER",
|
||||
"DER BOGEN",
|
||||
"DER BODEN",
|
||||
"DIE SAEULEN",
|
||||
"DIE URNEN",
|
||||
"DER HORIZONT",
|
||||
"DIE URNE",
|
||||
"DIE URNE",
|
||||
"DIE URNE",
|
||||
"DIE URNE",
|
||||
"DIE URNE",
|
||||
"DIE URNE",
|
||||
"xxx",
|
||||
"DER FUSSBALL",
|
||||
"DIE SKIER",
|
||||
"DIE TRUHE",
|
||||
"DIE FLASCHEN",
|
||||
"DIE FAESSER",
|
||||
"DAS RAD",
|
||||
"DAS AUTO",
|
||||
"DIE MOEBEL",
|
||||
"xxx",
|
||||
"DIE KOKONS",
|
||||
"DIE WAND VOLLER SCHAEDELN",
|
||||
"DIE KREATUR",
|
||||
"DER GLASKAEFIG",
|
||||
"DIE STROMKABEL",
|
||||
"DIE ROHRE",
|
||||
"DIE GEHIRNVERSORGUNG",
|
||||
"xxx",
|
||||
"DER KONTROLLPULT",
|
||||
"DER SCHREIBTISCH",
|
||||
"DIE ZELLENGITTER",
|
||||
"DIE ZELLENGITTER",
|
||||
"DIE KONSOLE",
|
||||
"DIE SUCHER",
|
||||
"DIE GEBAEUDE",
|
||||
"DIE KASTEN",
|
||||
"DAS WERKZEUG",
|
||||
"DIE ZEITUNG",
|
||||
"DER TISCH",
|
||||
"DAS FUSSENDE DES BETTES"
|
||||
};
|
||||
|
||||
static constexpr char objectNameTbl_es[199][35] = {
|
||||
"NADA",
|
||||
"LA CAJA",
|
||||
"LA MANO",
|
||||
"LA PREGUNTA",
|
||||
"CTRL",
|
||||
"LA BALLESTA",
|
||||
"EL DIARIO",
|
||||
"EL WHISKY",
|
||||
"EL DINERO",
|
||||
"EL PERIODICO",
|
||||
"LA FICHA DE LIBRERIA",
|
||||
"LA HORQUILLA",
|
||||
"EL PAPEL DE PERIODICO",
|
||||
"LA LLAVE DEL RELOJ",
|
||||
"LOS GUANTES",
|
||||
"EL TROZO DE ESPEJO",
|
||||
"LOS PRISMATICOS",
|
||||
"LA PALA",
|
||||
"LA TARJETA DE VISITA",
|
||||
"LA VARA",
|
||||
"EL MANGO DEL HACHA",
|
||||
"LA CINTA DE LA CABEZA",
|
||||
"EL BAUL",
|
||||
"LA CUERDA",
|
||||
"LA TARJETA MICROFICHA",
|
||||
"LA PIEDRA SUELTA",
|
||||
"LAS LLAVES DEL COCHE",
|
||||
"EL MARTILLO",
|
||||
"LA PISTOLA",
|
||||
"UNA NECROLOGIA",
|
||||
"LA NOTA DE LA MUDANZA",
|
||||
"EL PAQUETE",
|
||||
"EL PAQUETE",
|
||||
"EL PAQUETE",
|
||||
"EL PLANO",
|
||||
"EL RELOJ",
|
||||
"LAS GALLETAS",
|
||||
"LAS SARDINAS",
|
||||
"EL INSECTICIDA",
|
||||
"LA SALSA DE SOJA",
|
||||
"LAS ACEITUNAS",
|
||||
"LA TAZA DE HOJALATA",
|
||||
"LA CERRADURA DEL BAUL",
|
||||
"EL LIBRO 'ALIEN'",
|
||||
"EL TAPON DE GASOLINA",
|
||||
"FIDO",
|
||||
"LA BIBLIOTECARIA",
|
||||
"EL TELEFONO",
|
||||
"LAS BARRAS DE HUESO",
|
||||
"LAS ESCALERAS",
|
||||
"LA URNA DE BRONCE",
|
||||
"LA PANTALLA DE VISION",
|
||||
"LA DUCHA",
|
||||
"EL SARGENTO",
|
||||
"xxx",
|
||||
"LOS PLANOS DIABOLICOS",
|
||||
"EL SARGENTO DIABOLICO",
|
||||
"LA PALANCA",
|
||||
"LOS GUARDIANES DE DREKETH",
|
||||
"LA PUERTA SECRETA",
|
||||
"LA TURBO PUERTA",
|
||||
"EL CORREO",
|
||||
"EL DIAL DE LA RADIO",
|
||||
"LA SALIDA EN COCHE",
|
||||
"DELBERT",
|
||||
"LA CERRADURA DEL PRISIONERO",
|
||||
"LA TUMBA DE LA IZQUIERDA",
|
||||
"LA TUMBA DE ARRIBA",
|
||||
"LA TUMBA DE LA DERECHA",
|
||||
"LA PUERTA DELANTERA",
|
||||
"LA PARTA SUPERIOR DE LAS ESCALERAS",
|
||||
"EL ARRANQUE DEL COCHE",
|
||||
"EL POLICIA EN LA PUERTA",
|
||||
"MIKE DIABOLICO",
|
||||
"LA CERRADURA DE LA CELDA",
|
||||
"LA LAPIDA",
|
||||
"LA ESCALERA",
|
||||
"LA ESCALERA",
|
||||
"LA PUERTA SECRETA",
|
||||
"FIDO DIABOLICO",
|
||||
"LA MICROFICHA",
|
||||
"LA CAJA DETRAS DEL ESCRITORIO",
|
||||
"EL BOTON",
|
||||
"EL SUELO DE LA BIBLIOTECA",
|
||||
"EL LIBRO",
|
||||
"LA TIENDA",
|
||||
"EL LIBRO",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA LAPIDA",
|
||||
"LA PUERTA DE LA TUMBA",
|
||||
"EL ABRIGO",
|
||||
"EL PORTAEQUIPAJES",
|
||||
"LA CUERDA ATADA A LA CASA",
|
||||
"EL RELOJ",
|
||||
"EL ARMARIO",
|
||||
"EL ARMARIO",
|
||||
"EL ARMARIO",
|
||||
"EL ARMARIO",
|
||||
"LA ESTUFA",
|
||||
"EL COJON",
|
||||
"LA LLAVE DE LA COCINA",
|
||||
"LA LLAVE DEL CUARTO DE ASEO",
|
||||
"EL BOTIQUIN",
|
||||
"LA ALMOHADA",
|
||||
"EL ANTEPASADO",
|
||||
"LA FUENTA DE ENERGIA",
|
||||
"EL ABISMO",
|
||||
"LA PALANCA DEL OBSERVATORIO",
|
||||
"EL HORIZONTE",
|
||||
"EL CAMPO DE FUERZA",
|
||||
"LAS VICTIMAS DE LA SANGUIJUELA",
|
||||
"LOS ARBUSTOS",
|
||||
"LA BARANDILLA",
|
||||
"LA CAMA",
|
||||
"LA OBRA DE ARTE",
|
||||
"LA ALFOMBRA",
|
||||
"LA SILLA",
|
||||
"LA ESCUPIDERA",
|
||||
"LA CAMA",
|
||||
"EL FONDO DE LA CAMA",
|
||||
"EL FRIGORIFICO",
|
||||
"LOS LIBROS",
|
||||
"EL GLOBO TERRAQUEO",
|
||||
"LAS FOTOGRAFIAS DE RUFIANES",
|
||||
"EL MAPA",
|
||||
"EL ESCRITORIO",
|
||||
"xxx",
|
||||
"EL ESPEJO",
|
||||
"EL EMPLEADO",
|
||||
"EL CORDON",
|
||||
"EL CARTERO",
|
||||
"DELBERT",
|
||||
"LA PIEDRA DE CEMENTO",
|
||||
"LAS TOALLAS",
|
||||
"EL CALENTADOR DE AGUA",
|
||||
"LA BANERA",
|
||||
"xxx",
|
||||
"EL SOFA",
|
||||
"LA VENTANA",
|
||||
"EL ARTE",
|
||||
"EL ARTE",
|
||||
"EL RELOJ",
|
||||
"EL MOSTRADOR",
|
||||
"LOS LIBROS",
|
||||
"EL ESCRITORIO",
|
||||
"xxx",
|
||||
"EL ESCRITORIO",
|
||||
"LOS LIBROS",
|
||||
"EL ARCO",
|
||||
"EL SUELO",
|
||||
"LOS PILARES",
|
||||
"LOS ATAUDES",
|
||||
"EL HORIZONTE",
|
||||
"LA URNA",
|
||||
"LA URNA",
|
||||
"LA URNA",
|
||||
"LA URNA",
|
||||
"LA URNA",
|
||||
"LA URNA",
|
||||
"xxx",
|
||||
"EL BALON DE FUTBOL",
|
||||
"LOS ESQUIS",
|
||||
"EL BAUL",
|
||||
"LAS BOTELLAS",
|
||||
"LOS BARRILES",
|
||||
"LA RUEDA",
|
||||
"EL COCHE",
|
||||
"LOS MUEBLES",
|
||||
"xxx",
|
||||
"LOS CAPULLOS",
|
||||
"LA PARED DE CALAVERAS",
|
||||
"LA CRIATURA",
|
||||
"LA CAJA DE CRISTAL",
|
||||
"LOS CABLES DE ENERGIA",
|
||||
"LOS TUBOS",
|
||||
"EL NEXO CEREBRAL",
|
||||
"xxx",
|
||||
"EL PANEL DE CONTROL",
|
||||
"EL ESCRITORIO",
|
||||
"LAS BARRAS DE LA CELDA",
|
||||
"LAS BARRAS DE LA CELDA",
|
||||
"LA CONSOLA",
|
||||
"EL VISOR",
|
||||
"EL EDIFICIO",
|
||||
"LA CAJA",
|
||||
"LAS HERRAMIENTAS",
|
||||
"EL PERIODICO",
|
||||
"LA MESA",
|
||||
"EL FONDO DE LA CAMA"
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
#endif //DARKSEED_OBJECT_NAME_TABLES_H
|
||||
276
engines/darkseed/objects.cpp
Normal file
276
engines/darkseed/objects.cpp
Normal file
@@ -0,0 +1,276 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/objects.h"
|
||||
|
||||
#include "darkseed/object_name_tables.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
Objects::Objects() {
|
||||
_objectVar.resize(MAX_OBJECTS);
|
||||
_objectRunningCode.resize(MAX_OBJECTS);
|
||||
_moveObjectXY.resize(MAX_OBJECTS);
|
||||
_moveObjectRoom.resize(MAX_OBJECTS); // The original only allocates 42 entries here but writes 199 in the save file!
|
||||
_objectNames.resize(MAX_OBJECTS);
|
||||
reset();
|
||||
}
|
||||
|
||||
void Objects::reset() {
|
||||
for (int i = 0; i < MAX_OBJECTS; i++) {
|
||||
_objectVar[i] = 0;
|
||||
_objectRunningCode[i] = 0;
|
||||
_moveObjectXY[i].x = 0; // TODO verify this is the correct reset state for these XY vars.
|
||||
_moveObjectXY[i].y = 0;
|
||||
_moveObjectRoom[i] = i < 42 ? 0xff : 0; // Hack for weird behaviour in original engine.
|
||||
}
|
||||
// Initial object state.
|
||||
setVar(52, 1);
|
||||
setVar(112, 0);
|
||||
setVar(62, 0);
|
||||
}
|
||||
|
||||
void Objects::setVar(uint16 varIdx, int16 newValue) {
|
||||
if (varIdx >= MAX_OBJECTS) {
|
||||
error("setVar: Object Index out of range! %d", varIdx);
|
||||
}
|
||||
_objectVar[varIdx] = newValue;
|
||||
}
|
||||
|
||||
int16 Objects::getVar(uint16 varIdx) {
|
||||
if (varIdx >= MAX_OBJECTS) {
|
||||
error("getVar: Object Index out of range! %d", varIdx);
|
||||
}
|
||||
return _objectVar[varIdx];
|
||||
}
|
||||
|
||||
Common::Point Objects::getMoveObjectPosition(uint8 objIdx) {
|
||||
if (objIdx >= MAX_OBJECTS) {
|
||||
error("getMoveObjectPosition: Object Index out of range! %d", objIdx);
|
||||
}
|
||||
return _moveObjectXY[objIdx];
|
||||
}
|
||||
|
||||
void Objects::setMoveObjectPosition(uint8 objIdx, const Common::Point &newPoint) {
|
||||
if (objIdx >= MAX_OBJECTS) {
|
||||
error("setMoveObjectPosition: Object Index out of range! %d", objIdx);
|
||||
}
|
||||
_moveObjectXY[objIdx] = newPoint;
|
||||
}
|
||||
|
||||
void Objects::setMoveObjectX(uint8 objIdx, int16 xPos) {
|
||||
if (objIdx >= MAX_OBJECTS) {
|
||||
error("setMoveObjectX: Object Index out of range! %d", objIdx);
|
||||
}
|
||||
_moveObjectXY[objIdx].x = xPos;
|
||||
}
|
||||
|
||||
int16 &Objects::operator[](uint16 varIdx) {
|
||||
if (varIdx >= MAX_OBJECTS) {
|
||||
error("getVar: Object Index out of range! %d", varIdx);
|
||||
}
|
||||
return _objectVar[varIdx];
|
||||
}
|
||||
const int16 &Objects::operator[](uint16 varIdx) const {
|
||||
if (varIdx >= MAX_OBJECTS) {
|
||||
error("getVar: Object Index out of range! %d", varIdx);
|
||||
}
|
||||
return _objectVar[varIdx];
|
||||
}
|
||||
|
||||
void Objects::loadObjectNames() {
|
||||
auto lang = g_engine->getLanguage();
|
||||
if (lang == Common::KO_KOR) {
|
||||
loadKoreanObjectNames();
|
||||
} else if (lang == Common::ZH_ANY) {
|
||||
loadChineseObjectNames();
|
||||
} else {
|
||||
for (int i = 0; i < MAX_OBJECTS; i++) {
|
||||
switch (lang) {
|
||||
case Common::FR_FRA: _objectNames[i] = Common::U32String(objectNameTbl_fr[i]); break;
|
||||
case Common::DE_DEU: _objectNames[i] = Common::U32String(objectNameTbl_de[i]); break;
|
||||
case Common::ES_ESP: _objectNames[i] = Common::U32String(objectNameTbl_es[i]); break;
|
||||
default: _objectNames[i] = Common::U32String(objectNameTbl_en[i]); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Objects::loadKoreanObjectNames() {
|
||||
Common::File file;
|
||||
if (!file.open("tos.exe")) {
|
||||
error("Failed to open TOS.EXE");
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_OBJECTS; i++) {
|
||||
file.seek(0x22f62 + i * 4);
|
||||
uint16 offset = file.readUint16LE();
|
||||
file.seek(0x20990 + offset);
|
||||
_objectNames[i] = readU32String(file);
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
void Objects::loadChineseObjectNames() {
|
||||
Common::File file;
|
||||
if (!file.open("zh_objectnames.dat")) {
|
||||
error("Failed to open zh_objectnames.dat");
|
||||
}
|
||||
|
||||
for (int i = 0; i < MAX_OBJECTS; i++) {
|
||||
file.seek(i * 21);
|
||||
_objectNames[i] = readU32String(file);
|
||||
}
|
||||
|
||||
file.close();
|
||||
}
|
||||
|
||||
Common::U32String Objects::readU32String(Common::SeekableReadStream &readStream) {
|
||||
Common::U32String str;
|
||||
uint8 byte = readStream.readByte();
|
||||
while (byte != 0) {
|
||||
if (byte & 0x80) {
|
||||
uint8 byte2 = readStream.readByte();
|
||||
if (readStream.err()) {
|
||||
error("Failed to read byte from stream!");
|
||||
}
|
||||
str += (int)byte << 8 | byte2;
|
||||
} else {
|
||||
str += byte;
|
||||
}
|
||||
byte = readStream.readByte();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static constexpr uint16 eyeDescriptionsTbl[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 513,
|
||||
0, 421, 0, 521,
|
||||
0, 0, 713, 0,
|
||||
791, 812, 0, 743,
|
||||
0, 0, 661, 166,
|
||||
0, 0, 0, 0,
|
||||
500, 0, 0, 423,
|
||||
425, 427, 418, 667,
|
||||
503, 505, 507, 509,
|
||||
511, 755, 652, 0,
|
||||
728, 0, 0, 43,
|
||||
0, 0, 0, 0,
|
||||
192, 0, 0, 0,
|
||||
0, 893, 845, 0,
|
||||
0, 452, 721, 0,
|
||||
483, 0, 466, 466,
|
||||
466, 0, 0, 705,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 829,
|
||||
552, 0, 0, 0,
|
||||
0, 0, 711, 608,
|
||||
610, 606, 604, 602,
|
||||
600, 598, 596, 594,
|
||||
592, 590, 588, 0,
|
||||
0, 732, 166, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 241,
|
||||
231, 750, 815, 826,
|
||||
838, 794, 797, 806,
|
||||
802, 440, 448, 117,
|
||||
259, 271, 305, 90,
|
||||
161, 136, 376, 398,
|
||||
414, 474, 477, 480,
|
||||
0, 0, 999, 252,
|
||||
0, 0, 170, 182,
|
||||
212, 219, 284, 315,
|
||||
328, 337, 346, 356,
|
||||
515, 526, 533, 0,
|
||||
547, 561, 570, 575,
|
||||
613, 615, 620, 624,
|
||||
636, 638, 641, 643,
|
||||
645, 0, 673, 677,
|
||||
680, 683, 688, 717,
|
||||
726, 746, 0, 759,
|
||||
765, 780, 787, 818,
|
||||
822, 824, 0, 855,
|
||||
862, 0, 880, 887,
|
||||
891, 900, 0, 724,
|
||||
671, 321, 163
|
||||
};
|
||||
|
||||
int Objects::getEyeDescriptionTosIdx(uint16 objNum) {
|
||||
if (objNum >= MAX_OBJECTS) {
|
||||
error("getEyeDescriptionTosIdx: Object Index out of range! %d", objNum);
|
||||
}
|
||||
return eyeDescriptionsTbl[objNum];
|
||||
}
|
||||
|
||||
int Objects::getMoveObjectRoom(uint16 idx) {
|
||||
if (idx >= MAX_OBJECTS) {
|
||||
error("getMoveObjectRoom: index out of range.");
|
||||
}
|
||||
return _moveObjectRoom[idx];
|
||||
}
|
||||
|
||||
void Objects::setMoveObjectRoom(uint16 idx, uint8 value) {
|
||||
if (idx >= MAX_OBJECTS) {
|
||||
error("setMoveObjectRoom: index out of range.");
|
||||
}
|
||||
_moveObjectRoom[idx] = value;
|
||||
}
|
||||
|
||||
int16 Objects::getObjectRunningCode(int idx) {
|
||||
if (idx >= MAX_OBJECTS) {
|
||||
error("getObjectRunningCode: index out of range.");
|
||||
}
|
||||
return _objectRunningCode[idx];
|
||||
}
|
||||
|
||||
void Objects::setObjectRunningCode(int idx, int16 value) {
|
||||
if (idx >= MAX_OBJECTS) {
|
||||
error("setObjectRunningCode: index out of range.");
|
||||
}
|
||||
_objectRunningCode[idx] = value;
|
||||
}
|
||||
|
||||
const Common::U32String &Objects::getObjectName(int idx) {
|
||||
if (idx < 0 || idx >= MAX_OBJECTS) {
|
||||
error("getObjectName: index out of range.");
|
||||
}
|
||||
|
||||
return _objectNames[idx];
|
||||
}
|
||||
|
||||
static inline void syncPoint(Common::Serializer &s, Common::Point &value) {
|
||||
s.syncAsSint16LE(value.x);
|
||||
s.syncAsSint16LE(value.y);
|
||||
}
|
||||
|
||||
Common::Error Objects::sync(Common::Serializer &s) {
|
||||
s.syncArray(_objectVar.data(), _objectVar.size(), Common::Serializer::Sint16LE);
|
||||
s.syncArray(_objectRunningCode.data(), _objectRunningCode.size(), Common::Serializer::Sint16LE);
|
||||
s.syncArray(_objectRunningCode.data(), _objectRunningCode.size(), Common::Serializer::Sint16LE);
|
||||
s.syncArray(_moveObjectXY.data(), _moveObjectXY.size(), syncPoint);
|
||||
s.syncArray(_moveObjectRoom.data(), _moveObjectRoom.size(), Common::Serializer::Byte);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
81
engines/darkseed/objects.h
Normal file
81
engines/darkseed/objects.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_OBJECTS_H
|
||||
#define DARKSEED_OBJECTS_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/error.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/serializer.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
enum ObjType {
|
||||
OBJ_21_HEADBAND = 21
|
||||
};
|
||||
|
||||
class Objects {
|
||||
Common::Array<int16> _objectVar;
|
||||
Common::Array<Common::Point> _moveObjectXY;
|
||||
Common::Array<uint8> _moveObjectRoom;
|
||||
Common::U32StringArray _objectNames;
|
||||
|
||||
public:
|
||||
Common::Array<int16> _objectRunningCode;
|
||||
|
||||
static constexpr int MAX_MOVED_OBJECTS = 42;
|
||||
static constexpr int MAX_OBJECTS = 199;
|
||||
Objects();
|
||||
void reset();
|
||||
void loadObjectNames();
|
||||
|
||||
Common::Error sync(Common::Serializer &s);
|
||||
|
||||
void setVar(uint16 varIdx, int16 newValue);
|
||||
int16 getVar(uint16 varIdx);
|
||||
|
||||
int16 getObjectRunningCode(int idx);
|
||||
void setObjectRunningCode(int idx, int16 value);
|
||||
|
||||
Common::Point getMoveObjectPosition(uint8 objIdx);
|
||||
void setMoveObjectPosition(uint8 objIdx, const Common::Point &newPoint);
|
||||
void setMoveObjectX(uint8 objIdx, int16 xPos);
|
||||
int getEyeDescriptionTosIdx(uint16 objNum);
|
||||
|
||||
int getMoveObjectRoom(uint16 idx);
|
||||
void setMoveObjectRoom(uint16 idx, uint8 value);
|
||||
|
||||
const Common::U32String &getObjectName(int idx);
|
||||
|
||||
int16 &operator[](uint16 varIdx);
|
||||
const int16 &operator[](uint16 varIdx) const;
|
||||
|
||||
private:
|
||||
void loadKoreanObjectNames();
|
||||
void loadChineseObjectNames();
|
||||
|
||||
Common::U32String readU32String(Common::SeekableReadStream &readStream);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_OBJECTS_H
|
||||
112
engines/darkseed/pal.cpp
Normal file
112
engines/darkseed/pal.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
/* 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 "graphics/paletteman.h"
|
||||
#include "darkseed/pal.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
#define DARKSEED_NUM_PAL_ENTRIES 16
|
||||
#define DARKSEED_PAL_SIZE (DARKSEED_NUM_PAL_ENTRIES * 3)
|
||||
|
||||
Pal::Pal(const Pal &pal) {
|
||||
load(pal);
|
||||
}
|
||||
|
||||
Pal &Pal::operator=(const Pal &pal) {
|
||||
if (this != &pal) {
|
||||
load(pal);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
void Pal::load(const Pal &pal) {
|
||||
memcpy(_palData, pal._palData, DARKSEED_PAL_SIZE);
|
||||
}
|
||||
|
||||
bool Pal::load(const Common::Path &filename, bool shouldInstallPalette) {
|
||||
Common::File file;
|
||||
if (!file.open(filename)) {
|
||||
loadFromScreen();
|
||||
return false;
|
||||
}
|
||||
|
||||
return loadFromStream(file, shouldInstallPalette);
|
||||
}
|
||||
|
||||
bool Pal::loadFromStream(Common::SeekableReadStream &readStream, bool shouldInstallPalette) {
|
||||
uint32 bytesRead = readStream.read(_palData, DARKSEED_PAL_SIZE);
|
||||
assert(bytesRead == DARKSEED_PAL_SIZE);
|
||||
|
||||
for (int i = 0; i < DARKSEED_PAL_SIZE; i++) {
|
||||
_palData[i] = _palData[i] << 2;
|
||||
}
|
||||
if (shouldInstallPalette) {
|
||||
installPalette();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Pal::loadFromScreen() {
|
||||
g_system->getPaletteManager()->grabPalette(_palData, 0, DARKSEED_NUM_PAL_ENTRIES);
|
||||
}
|
||||
|
||||
void Pal::clear() {
|
||||
memset(_palData, 0, DARKSEED_PAL_SIZE);
|
||||
}
|
||||
|
||||
void Pal::swapEntries(int idx1, int idx2) {
|
||||
uint8 tmpEntry[3];
|
||||
tmpEntry[0] = _palData[idx1 * 3];
|
||||
tmpEntry[1] = _palData[idx1 * 3 + 1];
|
||||
tmpEntry[2] = _palData[idx1 * 3 + 2];
|
||||
|
||||
_palData[idx1 * 3] = _palData[idx2 * 3];
|
||||
_palData[idx1 * 3 + 1] = _palData[idx2 * 3 + 1];
|
||||
_palData[idx1 * 3 + 2] = _palData[idx2 * 3 + 2];
|
||||
|
||||
_palData[idx2 * 3] = tmpEntry[0];
|
||||
_palData[idx2 * 3 + 1] = tmpEntry[1];
|
||||
_palData[idx2 * 3 + 2] = tmpEntry[2];
|
||||
}
|
||||
|
||||
void Pal::updatePalette(int delta, const Pal &targetPal, bool shouldInstallPalette) {
|
||||
for (int i = 0; i < DARKSEED_PAL_SIZE; i++) {
|
||||
int c = _palData[i] + delta;
|
||||
if (c < 0) {
|
||||
c = 0;
|
||||
} else if (delta > 0 && c > targetPal._palData[i]) {
|
||||
c = targetPal._palData[i];
|
||||
}
|
||||
_palData[i] = (uint8)c;
|
||||
}
|
||||
if (shouldInstallPalette) {
|
||||
installPalette();
|
||||
}
|
||||
}
|
||||
|
||||
void Pal::installPalette() const {
|
||||
g_system->getPaletteManager()->setPalette(_palData, 0, DARKSEED_NUM_PAL_ENTRIES);
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
53
engines/darkseed/pal.h
Normal file
53
engines/darkseed/pal.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_PAL_H
|
||||
#define DARKSEED_PAL_H
|
||||
|
||||
#include "common/path.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
#define DARKSEED_NUM_PAL_ENTRIES 16
|
||||
#define DARKSEED_PAL_SIZE (DARKSEED_NUM_PAL_ENTRIES * 3)
|
||||
|
||||
|
||||
class Pal {
|
||||
public:
|
||||
byte _palData[DARKSEED_PAL_SIZE];
|
||||
|
||||
Pal() {};
|
||||
Pal(const Pal &pal);
|
||||
Pal & operator=(const Pal &pal);
|
||||
void loadFromScreen();
|
||||
void load(const Pal &pal);
|
||||
bool load(const Common::Path &filename, bool shouldInstallPalette = true);
|
||||
bool loadFromStream(Common::SeekableReadStream &readStream, bool shouldInstallPalette = true);
|
||||
void clear();
|
||||
void swapEntries(int idx1, int idx2);
|
||||
void updatePalette(int delta, const Pal &targetPal, bool shouldInstallPalette = true);
|
||||
void installPalette() const;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_PAL_H
|
||||
108
engines/darkseed/pic.cpp
Normal file
108
engines/darkseed/pic.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
/* 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 "darkseed/pic.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
#include "common/debug.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
bool Pic::load(const Common::Path &filename) {
|
||||
g_engine->waitForSpeech();
|
||||
Common::File file;
|
||||
Common::Path fullPath = g_engine->getPictureFilePath(filename);
|
||||
if (!file.open(fullPath)) {
|
||||
debug("Failed to load %s", fullPath.toString().c_str());
|
||||
return false;
|
||||
}
|
||||
bool ret = load(file);
|
||||
file.close();
|
||||
if (ret) {
|
||||
debug("Loaded %s (%d,%d)", fullPath.toString().c_str(), _width, _height);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool Pic::load(Common::SeekableReadStream &readStream) {
|
||||
_width = readStream.readUint16BE();
|
||||
_height = readStream.readUint16BE();
|
||||
_pixels.resize(_width * (_height + 1), 0);
|
||||
|
||||
int curX = 0;
|
||||
int curY = 0;
|
||||
while (curY < _height) {
|
||||
int rleCommand = readNextNibble(readStream);
|
||||
|
||||
if (rleCommand < 8) {
|
||||
// read nibble count of nibbles pixels
|
||||
for (int i = 0; i < rleCommand + 1; i++) {
|
||||
byte pixel = readNextNibble(readStream);
|
||||
_pixels[curX + curY * _width] = pixel;
|
||||
curX++;
|
||||
if (curX == _width) {
|
||||
curX = 0;
|
||||
curY++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// fetch next nibble and repeat if n times.
|
||||
byte pixel = readNextNibble(readStream);
|
||||
for (int i = 16; i >= rleCommand; i--) {
|
||||
_pixels[curX + curY * _width] = pixel;
|
||||
curX++;
|
||||
if (curX == _width) {
|
||||
curX = 0;
|
||||
curY++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
byte Pic::readNextNibble(Common::SeekableReadStream &readStream) {
|
||||
if (!_hasReadByte) {
|
||||
_currentDataByte = readStream.readByte();
|
||||
if (readStream.eos()) {
|
||||
debug("Argh!");
|
||||
}
|
||||
_hasReadByte = true;
|
||||
return _currentDataByte >> 4;
|
||||
} else {
|
||||
_hasReadByte = false;
|
||||
return _currentDataByte & 0xf;
|
||||
}
|
||||
}
|
||||
|
||||
void Pic::draw() {
|
||||
draw(0, 0);
|
||||
}
|
||||
|
||||
void Pic::draw(int xOffset, int yOffset) {
|
||||
g_engine->_screen->copyRectToSurface(getPixels().data(), getWidth(), xOffset, yOffset, getWidth(), getHeight());
|
||||
}
|
||||
|
||||
void Pic::drawRect(const Common::Rect &rect) {
|
||||
void *ptr = getPixels().data() + rect.left + (rect.top * getWidth());
|
||||
g_engine->_screen->copyRectToSurface(ptr, getWidth(), rect.left, rect.top, rect.width(), rect.height());
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
65
engines/darkseed/pic.h
Normal file
65
engines/darkseed/pic.h
Normal file
@@ -0,0 +1,65 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_PIC_H
|
||||
#define DARKSEED_PIC_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/file.h"
|
||||
#include "common/rect.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Pic {
|
||||
uint16 _width = 0;
|
||||
uint16 _height = 0;
|
||||
Common::Array<uint8> _pixels;
|
||||
|
||||
bool _hasReadByte = false;
|
||||
byte _currentDataByte = 0;
|
||||
|
||||
public:
|
||||
Pic() {}
|
||||
bool load(const Common::Path &filename);
|
||||
Common::Array<uint8> &getPixels() {
|
||||
return _pixels;
|
||||
}
|
||||
|
||||
uint16 getWidth() const {
|
||||
return _width;
|
||||
}
|
||||
uint16 getHeight() const {
|
||||
return _height;
|
||||
}
|
||||
|
||||
void draw();
|
||||
void draw(int xOffset, int yOffset);
|
||||
void drawRect(const Common::Rect &rect);
|
||||
|
||||
private:
|
||||
bool load(Common::SeekableReadStream &readStream);
|
||||
|
||||
byte readNextNibble(Common::SeekableReadStream &readStream);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_PIC_H
|
||||
470
engines/darkseed/player.cpp
Normal file
470
engines/darkseed/player.cpp
Normal file
@@ -0,0 +1,470 @@
|
||||
/* 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 "math/utils.h"
|
||||
#include "darkseed/player.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
Player::Player() {
|
||||
_cPlayerSprites.load("cplayer.nsp");
|
||||
_gPlayerSprites.load("gplayer.nsp");
|
||||
_connectorList.resize(Room::MAX_CONNECTORS);
|
||||
}
|
||||
|
||||
const Sprite &Player::getSprite(int frameNo) const {
|
||||
if (g_engine->_room->isGiger()) {
|
||||
return _gPlayerSprites.getSpriteAt(frameNo);
|
||||
} else {
|
||||
return _cPlayerSprites.getSpriteAt(frameNo);
|
||||
}
|
||||
}
|
||||
|
||||
bool Player::loadAnimations(const Common::Path &filename) {
|
||||
return _animations.load(filename);
|
||||
}
|
||||
|
||||
uint8 playerSpriteIndexDirectionTbl[] = { 24, 26, 28, 26 };
|
||||
static constexpr bool DIRECTION_FLIP_SPRITE_TBL[] = { false, false, false, true };
|
||||
uint16 walkFrameOffsetTbl[] = { 0, 8, 16, 8 };
|
||||
|
||||
void Player::updateSprite() {
|
||||
if (!_playerIsChangingDirection) {
|
||||
if ((_direction == 3) || (_direction == 1)) {
|
||||
_flipSprite = DIRECTION_FLIP_SPRITE_TBL[_direction];
|
||||
}
|
||||
if (_position.x == _walkTarget.x && _position.y == _walkTarget.y && !_heroMoving) {
|
||||
_frameIdx = playerSpriteIndexDirectionTbl[_direction];
|
||||
} else {
|
||||
_frameIdx = _playerWalkFrameIdx + walkFrameOffsetTbl[_direction];
|
||||
}
|
||||
if (_direction == 2) {
|
||||
if (_position.x < _walkTarget.x) {
|
||||
_flipSprite = true;
|
||||
} else if (_walkTarget.x < _position.x) {
|
||||
_flipSprite = false;
|
||||
}
|
||||
}
|
||||
if (_direction == 0) {
|
||||
if (_walkTarget.x < _position.x) {
|
||||
_flipSprite = true;
|
||||
} else if (_position.x < _walkTarget.x) {
|
||||
_flipSprite = false;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
_flipSprite = (4 < _playerSpriteWalkIndex_maybe);
|
||||
if (_flipSprite) {
|
||||
_frameIdx = 0x20 - _playerSpriteWalkIndex_maybe;
|
||||
} else {
|
||||
_frameIdx = _playerSpriteWalkIndex_maybe + 0x18;
|
||||
}
|
||||
}
|
||||
}
|
||||
bool Player::isAtPosition(int x, int y) const {
|
||||
return _position.x == x && _position.y == y;
|
||||
}
|
||||
|
||||
bool Player::isAtWalkTarget() const {
|
||||
return _position == _walkTarget;
|
||||
}
|
||||
|
||||
void Player::changeDirection(int16 oldDir, int16 newDir) {
|
||||
if (oldDir != newDir) {
|
||||
_playerIsChangingDirection = true;
|
||||
_playerSpriteWalkIndex_maybe = (int16)(oldDir * 2);
|
||||
_playerNewFacingDirection_maybe = (int16)(newDir * 2);
|
||||
_playerWalkFrameDeltaOffset = 1;
|
||||
if (oldDir < 4) {
|
||||
switch (oldDir) {
|
||||
case 0:
|
||||
if (newDir == 3) {
|
||||
_playerWalkFrameDeltaOffset = -1;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if (newDir == 0) {
|
||||
_playerWalkFrameDeltaOffset = -1;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if (newDir == 1) {
|
||||
_playerWalkFrameDeltaOffset = -1;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (newDir == 2) {
|
||||
_playerWalkFrameDeltaOffset = -1;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::playerFaceWalkTarget() {
|
||||
int previousDirection;
|
||||
int xDelta;
|
||||
int yDelta;
|
||||
|
||||
previousDirection = _direction;
|
||||
if (_position.x < _walkTarget.x) {
|
||||
xDelta = _walkTarget.x - _position.x;
|
||||
} else {
|
||||
xDelta = _position.x - _walkTarget.x;
|
||||
}
|
||||
if (_position.y < _walkTarget.y) {
|
||||
yDelta = _walkTarget.y - _position.y;
|
||||
} else {
|
||||
yDelta = _position.y - _walkTarget.y;
|
||||
}
|
||||
if (yDelta * 2 <= xDelta) {
|
||||
if (_position.x < _walkTarget.x) {
|
||||
_direction = 1;
|
||||
} else if (_walkTarget.x < _position.x) {
|
||||
_direction = 3;
|
||||
}
|
||||
} else if (_position.y < _walkTarget.y) {
|
||||
_direction = 2;
|
||||
} else {
|
||||
_direction = 0;
|
||||
}
|
||||
changeDirection(previousDirection, _direction);
|
||||
updateSprite();
|
||||
_positionLong = _position;
|
||||
}
|
||||
|
||||
void Player::calculateWalkTarget() {
|
||||
_heroMoving = true;
|
||||
_playerWalkFrameIdx = 0;
|
||||
_walkPathIndex = -1;
|
||||
_numConnectorsInWalkPath = 0;
|
||||
int selectedObjNum = 0;
|
||||
if (g_engine->_actionMode == kPointerAction) {
|
||||
selectedObjNum = g_engine->_room->getRoomExitAtCursor();
|
||||
}
|
||||
|
||||
if (selectedObjNum == 0) {
|
||||
_walkTarget.x = g_engine->_cursor.getX();
|
||||
_walkTarget.y = g_engine->_cursor.getY();
|
||||
} else {
|
||||
int currentRoomNumber = g_engine->_room->_roomNumber;
|
||||
if (currentRoomNumber == 34 || (currentRoomNumber > 18 && currentRoomNumber < 24)) {
|
||||
g_engine->_previousRoomNumber = currentRoomNumber;
|
||||
if (currentRoomNumber == 34) {
|
||||
g_engine->changeToRoom(33);
|
||||
} else {
|
||||
g_engine->changeToRoom(28);
|
||||
}
|
||||
return;
|
||||
}
|
||||
g_engine->_room->getWalkTargetForObjectType_maybe(selectedObjNum);
|
||||
}
|
||||
|
||||
if (_walkTarget.y > 237) {
|
||||
_walkTarget.y = 238;
|
||||
}
|
||||
|
||||
if (!g_engine->_room->canWalkAtLocation(_walkTarget.x, _walkTarget.y)) {
|
||||
int ty = _walkTarget.y;
|
||||
while (!g_engine->_room->canWalkAtLocation(_walkTarget.x, ty) && ty <= 233) {
|
||||
ty += 4;
|
||||
}
|
||||
if (ty < 235) {
|
||||
_walkTarget.y = ty;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_engine->_room->canWalkInLineToTarget(_position.x, _position.y, _walkTarget.x, _walkTarget.y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_engine->_room->canWalkAtLocation(_walkTarget.x, _walkTarget.y)) {
|
||||
Common::Point connector = getClosestUnusedConnector(_walkTarget.x, _walkTarget.y);
|
||||
if (connector.x == -1 && connector.y == -1) {
|
||||
return;
|
||||
}
|
||||
int connectorToTargetDist = Math::hypotenuse(connector.x - _walkTarget.x, connector.y - _walkTarget.y);
|
||||
int playerToTargetDist = Math::hypotenuse(_position.x - _walkTarget.x, _position.y - _walkTarget.y);
|
||||
if (connectorToTargetDist < playerToTargetDist) {
|
||||
if (g_engine->_room->canWalkInLineToTarget(_position.x, _position.y, connector.x, connector.y)) {
|
||||
_finalTarget = _walkTarget;
|
||||
_walkTarget = connector;
|
||||
} else {
|
||||
Common::Point tmpDest = _walkTarget;
|
||||
_walkTarget = connector;
|
||||
if (_numConnectorsInWalkPath > 0 && _numConnectorsInWalkPath < Room::MAX_CONNECTORS - 1 && _connectorList[_numConnectorsInWalkPath - 1] != connector) {
|
||||
_connectorList[_numConnectorsInWalkPath] = connector;
|
||||
_numConnectorsInWalkPath++;
|
||||
}
|
||||
_finalTarget = tmpDest;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
createConnectorPathToDest();
|
||||
}
|
||||
}
|
||||
|
||||
int Player::getWidth() {
|
||||
return getSprite(_frameIdx)._width;
|
||||
}
|
||||
|
||||
int Player::getHeight() {
|
||||
return getSprite(_frameIdx)._height;
|
||||
}
|
||||
|
||||
void Player::updatePlayerPositionAfterRoomChange() {
|
||||
int currentRoomNumber = g_engine->_room->_roomNumber;
|
||||
g_engine->_room->calculateScaledSpriteDimensions(getWidth(), getHeight(), _position.y);
|
||||
if (currentRoomNumber == 0x29 && g_engine->_previousRoomNumber == 0x2c) {
|
||||
_position = Common::Point(0x13d, 0xa9);
|
||||
} else if (currentRoomNumber == 0x2c && g_engine->_previousRoomNumber == 0x29) {
|
||||
_position = Common::Point(0x16e, 0xb8);
|
||||
} else if (_direction == 0 || ((currentRoomNumber == 0x29 || currentRoomNumber == 0x2c) && _direction == 2)) {
|
||||
_position.y = 0xec;
|
||||
g_engine->_room->calculateScaledSpriteDimensions(getWidth(), getHeight(), _position.y);
|
||||
while (!g_engine->_room->canWalkAtLocation(_position.x, _position.y + 3) && _position.y > 100) {
|
||||
_position.y--;
|
||||
}
|
||||
} else if (_direction == 2) {
|
||||
while (!g_engine->_room->canWalkAtLocation(_position.x, _position.y - 5) && _position.y < 0xee && currentRoomNumber != 0x29 && currentRoomNumber != 0x2c) {
|
||||
_position.y++;
|
||||
}
|
||||
} else if (_direction == 3) {
|
||||
if (currentRoomNumber == 0x20 || currentRoomNumber == 0x1a) {
|
||||
g_engine->_scaledSpriteHeight = 5;
|
||||
} else {
|
||||
g_engine->_room->calculateScaledSpriteDimensions(getWidth(), getHeight(), _position.y + g_engine->_scaledSpriteHeight);
|
||||
}
|
||||
_position.y += g_engine->_scaledSpriteHeight;
|
||||
if (_position.y > 0xee) {
|
||||
_position.y = 0xee;
|
||||
}
|
||||
if (_position.x > 0x27b) {
|
||||
_position.x = 0x27b;
|
||||
}
|
||||
|
||||
int yUp = _position.y;
|
||||
int yDown = _position.y;
|
||||
while (!g_engine->_room->canWalkAtLocation(_position.x, yUp) && yUp < 0xee) {
|
||||
yUp++;
|
||||
}
|
||||
while (!g_engine->_room->canWalkAtLocation(_position.x, yDown) && yDown > 0x28) {
|
||||
yDown--;
|
||||
}
|
||||
if (yUp - _position.y < _position.y - yDown) {
|
||||
_position.y = yUp;
|
||||
} else {
|
||||
_position.y = yDown;
|
||||
}
|
||||
} else {
|
||||
g_engine->_room->calculateScaledSpriteDimensions(getWidth(), getHeight(), _position.y + g_engine->_scaledSpriteHeight);
|
||||
_position.y += g_engine->_scaledSpriteHeight;
|
||||
if (_position.y > 0xee) {
|
||||
_position.y = 0xee;
|
||||
}
|
||||
|
||||
int yUp = _position.y;
|
||||
int yDown = _position.y;
|
||||
while (!g_engine->_room->canWalkAtLocation(_position.x, yUp) && yUp < 0xee) {
|
||||
yUp++;
|
||||
}
|
||||
while (!g_engine->_room->canWalkAtLocation(_position.x, yDown) && yDown > 0x28) {
|
||||
yDown--;
|
||||
}
|
||||
if (yUp - _position.y < _position.y - yDown) {
|
||||
_position.y = yUp;
|
||||
} else {
|
||||
_position.y = yDown;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::createConnectorPathToDest() {
|
||||
constexpr Common::Point noConnectorFound(-1, -1);
|
||||
Common::Point origWalkTarget = _walkTarget;
|
||||
Common::Point startPoint = _position;
|
||||
if (g_engine->_room->_roomNumber != 5 || _position.x > 320) {
|
||||
startPoint = _walkTarget;
|
||||
_walkTarget = _position;
|
||||
}
|
||||
_numConnectorsInWalkPath = 0;
|
||||
Common::Point connector;
|
||||
if (!g_engine->_room->canWalkAtLocation(startPoint.x, startPoint.y)) {
|
||||
connector = getClosestUnusedConnector(startPoint.x, startPoint.y);
|
||||
} else {
|
||||
connector = getClosestUnusedConnector(startPoint.x, startPoint.y, true);
|
||||
}
|
||||
if (connector == noConnectorFound) {
|
||||
if (g_engine->_room->_roomNumber != 5 || _position.x > 320) {
|
||||
_walkTarget = origWalkTarget;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
_walkPathIndex = 0;
|
||||
_connectorList[_numConnectorsInWalkPath] = connector;
|
||||
_numConnectorsInWalkPath++;
|
||||
|
||||
while (_numConnectorsInWalkPath < Room::MAX_CONNECTORS && connector != noConnectorFound) {
|
||||
if (g_engine->_room->canWalkInLineToTarget(connector.x, connector.y, _walkTarget.x, _walkTarget.y)) {
|
||||
break;
|
||||
}
|
||||
connector = getClosestUnusedConnector(connector.x, connector.y, true);
|
||||
if (connector == _walkTarget) {
|
||||
break;
|
||||
}
|
||||
if (connector != noConnectorFound) {
|
||||
_connectorList[_numConnectorsInWalkPath] = connector;
|
||||
_numConnectorsInWalkPath++;
|
||||
}
|
||||
}
|
||||
|
||||
if (g_engine->_room->_roomNumber != 5 || _position.x > 320) {
|
||||
reverseConnectorList();
|
||||
_walkTarget = origWalkTarget;
|
||||
}
|
||||
optimisePath();
|
||||
if (g_engine->_room->_roomNumber == 5 && _position.x < 321) {
|
||||
_finalTarget = _walkTarget;
|
||||
} else {
|
||||
_finalTarget = origWalkTarget;
|
||||
}
|
||||
_walkTarget = _connectorList[0];
|
||||
}
|
||||
|
||||
Common::Point Player::getClosestUnusedConnector(int16 x, int16 y, bool mustHaveCleanLine) {
|
||||
Common::Point closestPoint = {-1, -1};
|
||||
int closestDist = 5000;
|
||||
for (auto &roomConnector : g_engine->_room->_connectors) {
|
||||
bool containsPoint = false;
|
||||
for (int i = 0; i < _numConnectorsInWalkPath; i++) {
|
||||
if (_connectorList[i] == roomConnector) {
|
||||
containsPoint = true;
|
||||
}
|
||||
}
|
||||
if (!containsPoint) {
|
||||
int dist = Math::hypotenuse((roomConnector.x - x), (roomConnector.y - y));
|
||||
if (dist < closestDist) {
|
||||
if (!mustHaveCleanLine || g_engine->_room->canWalkInLineToTarget(x, y, roomConnector.x, roomConnector.y)) {
|
||||
closestPoint = roomConnector;
|
||||
closestDist = dist;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return closestPoint;
|
||||
}
|
||||
|
||||
void Player::walkToNextConnector() {
|
||||
if (_walkPathIndex == -1) {
|
||||
return;
|
||||
}
|
||||
if (_walkPathIndex + 1 < _numConnectorsInWalkPath) {
|
||||
_walkPathIndex++;
|
||||
_walkTarget = _connectorList[_walkPathIndex];
|
||||
} else {
|
||||
_walkTarget = _finalTarget;
|
||||
_walkPathIndex = -1;
|
||||
}
|
||||
playerFaceWalkTarget();
|
||||
}
|
||||
|
||||
void Player::draw() {
|
||||
if (g_engine->_debugShowWalkPath) {
|
||||
if (_walkPathIndex != -1) {
|
||||
for (int i = _walkPathIndex; i < _numConnectorsInWalkPath; i++) {
|
||||
if (i == _walkPathIndex) {
|
||||
g_engine->_screen->drawLine(_position.x, _position.y, _connectorList[i].x, _connectorList[i].y, 2);
|
||||
} else {
|
||||
g_engine->_screen->drawLine(_connectorList[i].x, _connectorList[i].y, _connectorList[i - 1].x, _connectorList[i - 1].y, 2);
|
||||
}
|
||||
}
|
||||
g_engine->_screen->drawLine(_connectorList[_numConnectorsInWalkPath - 1].x, _connectorList[_numConnectorsInWalkPath - 1].y, _finalTarget.x, _finalTarget.y, 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Player::reverseConnectorList() {
|
||||
for (int i = 0; i < _numConnectorsInWalkPath / 2; i++) {
|
||||
SWAP(_connectorList[i], _connectorList[_numConnectorsInWalkPath - 1 - i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Player::optimisePath() {
|
||||
if (g_engine->_room->_roomNumber != 7 && g_engine->_room->_roomNumber != 32) {
|
||||
while (_numConnectorsInWalkPath > 1) {
|
||||
if (g_engine->_room->canWalkInLineToTarget(_connectorList[_numConnectorsInWalkPath - 2].x, _connectorList[_numConnectorsInWalkPath - 2].y, _walkTarget.x, _walkTarget.y)) {
|
||||
_numConnectorsInWalkPath--;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr uint8 _closerroom[10] = {
|
||||
0, 5, 0, 9,
|
||||
0, 0, 5, 6,
|
||||
7, 6
|
||||
};
|
||||
|
||||
void Player::setPlayerTowardsBedroom() {
|
||||
if (g_engine->_animation->_isPlayingAnimation_maybe) {
|
||||
return;
|
||||
}
|
||||
Common::Point currentCursor = g_engine->_cursor.getPosition();
|
||||
uint8 currentRoomNumber = g_engine->_room->_roomNumber;
|
||||
if (currentRoomNumber == 0) {
|
||||
Common::Point target = {223, 190};
|
||||
g_engine->_cursor.setPosition(target);
|
||||
} else {
|
||||
uint8 local_a = 0;
|
||||
if (currentRoomNumber < 10) {
|
||||
local_a = _closerroom[currentRoomNumber];
|
||||
} else if (currentRoomNumber == 13) {
|
||||
local_a = 61;
|
||||
} else if (currentRoomNumber == 61) {
|
||||
local_a = 5;
|
||||
} else if (currentRoomNumber == 62) {
|
||||
local_a = 8;
|
||||
}
|
||||
if (currentRoomNumber == 6 && g_engine->_objectVar[137] == 2) {
|
||||
local_a = 10;
|
||||
}
|
||||
|
||||
Common::Point exitPosition = g_engine->_room->getExitPointForRoom(local_a);
|
||||
g_engine->_cursor.setPosition(exitPosition);
|
||||
uint16 exitObjNum = g_engine->_room->getRoomExitAtCursor();
|
||||
g_engine->_room->getWalkTargetForObjectType_maybe(exitObjNum);
|
||||
|
||||
g_engine->_cursor.setPosition(_walkTarget);
|
||||
}
|
||||
|
||||
calculateWalkTarget();
|
||||
playerFaceWalkTarget();
|
||||
g_engine->_cursor.setPosition(currentCursor);
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
88
engines/darkseed/player.h
Normal file
88
engines/darkseed/player.h
Normal file
@@ -0,0 +1,88 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_PLAYER_H
|
||||
#define DARKSEED_PLAYER_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "common/path.h"
|
||||
#include "darkseed/nsp.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class Player {
|
||||
Nsp _cPlayerSprites;
|
||||
Nsp _gPlayerSprites;
|
||||
|
||||
public:
|
||||
Nsp _animations;
|
||||
int _frameIdx = 0;
|
||||
int _direction = 0;
|
||||
Common::Point _position;
|
||||
Common::Point _positionLong; // the original sometimes seems to use a long (4 byte) version of the location
|
||||
Common::Point _walkTarget;
|
||||
Common::Point _finalTarget;
|
||||
|
||||
int16 _playerSpriteWalkIndex_maybe = 0;
|
||||
int16 _playerWalkFrameDeltaOffset = 0;
|
||||
int16 _playerNewFacingDirection_maybe = 0;
|
||||
uint16 _playerWalkFrameIdx = 0;
|
||||
bool _actionToPerform = false; // player is pathfinding to some destination?
|
||||
bool _playerIsChangingDirection = false; // AKA _Rotating
|
||||
bool _isAutoWalkingToBed = false;
|
||||
bool _heroMoving = false; // maybe set to true while player is walking around the room.
|
||||
bool _heroWaiting = false;
|
||||
int _walkPathIndex = -1;
|
||||
uint16 _numConnectorsInWalkPath = 0;
|
||||
Common::Array<Common::Point> _connectorList;
|
||||
int16 _sequenceRotation = -1;
|
||||
bool _walkToSequence = false;
|
||||
Common::Point _walkToSequencePoint;
|
||||
bool _flipSprite = false;
|
||||
|
||||
Player();
|
||||
bool loadAnimations(const Common::Path &filename);
|
||||
const Sprite &getSprite(int frameNo) const;
|
||||
void updateSprite();
|
||||
void draw();
|
||||
|
||||
bool isAtPosition(int x, int y) const;
|
||||
bool isAtWalkTarget() const;
|
||||
void calculateWalkTarget();
|
||||
|
||||
void changeDirection(int16 oldDir, int16 newDir);
|
||||
void playerFaceWalkTarget();
|
||||
int getWidth();
|
||||
int getHeight();
|
||||
void updatePlayerPositionAfterRoomChange();
|
||||
void setPlayerTowardsBedroom();
|
||||
void walkToNextConnector();
|
||||
|
||||
private:
|
||||
void createConnectorPathToDest();
|
||||
Common::Point getClosestUnusedConnector(int16 x, int16 y, bool mustHaveCleanLine = false);
|
||||
void reverseConnectorList();
|
||||
void optimisePath();
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_PLAYER_H
|
||||
1514
engines/darkseed/room.cpp
Normal file
1514
engines/darkseed/room.cpp
Normal file
File diff suppressed because it is too large
Load Diff
125
engines/darkseed/room.h
Normal file
125
engines/darkseed/room.h
Normal file
@@ -0,0 +1,125 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_ROOM_H
|
||||
#define DARKSEED_ROOM_H
|
||||
|
||||
#include "common/rect.h"
|
||||
#include "darkseed/nsp.h"
|
||||
#include "darkseed/pal.h"
|
||||
#include "darkseed/pic.h"
|
||||
#include "sound.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
struct RoomExit {
|
||||
uint16 x = 0;
|
||||
uint16 y = 0;
|
||||
uint16 width = 0;
|
||||
uint16 height = 0;
|
||||
uint16 roomNumber = 0;
|
||||
uint8 direction = 0;
|
||||
};
|
||||
|
||||
struct RoomStruct2 {
|
||||
uint8 strip[40];
|
||||
};
|
||||
|
||||
struct RoomObjElement {
|
||||
uint16 type = 0;
|
||||
uint16 objNum = 0;
|
||||
uint16 xOffset = 0;
|
||||
uint16 yOffset = 0;
|
||||
uint16 width = 0;
|
||||
uint16 height = 0;
|
||||
uint8 depth = 0;
|
||||
uint8 spriteNum = 0;
|
||||
};
|
||||
|
||||
class Room {
|
||||
bool _palLoaded = false;
|
||||
|
||||
public:
|
||||
static constexpr int MAX_CONNECTORS = 12;
|
||||
uint8 _roomNumber;
|
||||
Pic _pic;
|
||||
Pal _pal;
|
||||
Pal _workPal; // used to darken the sky.
|
||||
Nsp _locationSprites;
|
||||
Common::Array<int16> _locObjFrame;
|
||||
Common::Array<int16> _locObjFrameTimer;
|
||||
|
||||
Common::Array<RoomExit> _room1;
|
||||
Common::Array<RoomStruct2> _walkableLocationsMap;
|
||||
Common::Array<RoomObjElement> _roomObj;
|
||||
Common::Array<Common::Point> _connectors;
|
||||
|
||||
uint16 _selectedObjIndex = 0;
|
||||
int16 _collisionType = 0;
|
||||
|
||||
explicit Room(int roomNumber);
|
||||
|
||||
void initRoom();
|
||||
void draw();
|
||||
|
||||
void update();
|
||||
|
||||
int checkCursorAndMoveableObjects();
|
||||
int checkCursorAndStaticObjects(int x, int y);
|
||||
int CheckCursorAndMovedObjects();
|
||||
int getRoomExitAtCursor();
|
||||
void getWalkTargetForObjectType_maybe(int objId);
|
||||
int getObjectUnderCursor();
|
||||
uint16 getDoorTargetRoom(int objId);
|
||||
int getExitRoomNumberAtPoint(int x, int y);
|
||||
bool exitRoom();
|
||||
Common::String getRoomFilenameBase(int roomNumber);
|
||||
bool canWalkAtLocation(int x, int y);
|
||||
bool canWalkInLineToTarget(int x, int y, int targetX, int targetY);
|
||||
void printRoomDescriptionText() const;
|
||||
void calculateScaledSpriteDimensions(int width, int height, int curYPosition);
|
||||
bool isOutside() const;
|
||||
bool isGiger();
|
||||
void runRoomObjects();
|
||||
void removeObjectFromRoom(int16 objNum);
|
||||
void updateRoomObj(int16 objNum, int16 x, int16 width, int16 y, int16 height);
|
||||
bool advanceFrame(int animIdx);
|
||||
void mikeStickThrowAnim();
|
||||
void loadRoom61AWalkableLocations();
|
||||
void restorePalette();
|
||||
void installPalette();
|
||||
void darkenSky();
|
||||
void loadLocationSprites(const Common::Path &path);
|
||||
Common::Point getExitPointForRoom(uint8 roomNumber);
|
||||
static MusicId getMusicIdForRoom(uint8 roomNumber);
|
||||
void loadRoomMusic();
|
||||
|
||||
private:
|
||||
bool load();
|
||||
static Common::String stripSpaces(const Common::String &source);
|
||||
void drawTrunk();
|
||||
void advanceLocAnimFrame(int roomObjIdx);
|
||||
void dosDemoFixupRoomObjects();
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_ROOM_H
|
||||
587
engines/darkseed/sound.cpp
Normal file
587
engines/darkseed/sound.cpp
Normal file
@@ -0,0 +1,587 @@
|
||||
/* 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 "audio/audiostream.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "audio/decoders/voc.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/util.h"
|
||||
#include "darkseed/sound.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
static constexpr char musicDosFloppyFilenameTbl[][14] = {
|
||||
"lab1",
|
||||
"victory1",
|
||||
"cemetry1",
|
||||
"leech1",
|
||||
"ext1",
|
||||
"quiet",
|
||||
"package",
|
||||
"dth",
|
||||
"library",
|
||||
"radio",
|
||||
"outdoor",
|
||||
"town"
|
||||
};
|
||||
|
||||
static constexpr char musicDosCDFilenameTbl[][14] = {
|
||||
"lab.mid",
|
||||
"victory.mid",
|
||||
"cemetery.mid",
|
||||
"leech.mid",
|
||||
"exterior.mid",
|
||||
"passtime.mid",
|
||||
"mirrorst.mid",
|
||||
"dth.mid",
|
||||
"lib_moz.mid",
|
||||
"carradio.mid",
|
||||
"greenwal.mid",
|
||||
"walktown.mid"
|
||||
};
|
||||
|
||||
static constexpr char startMusicDosFloppyFilenameTbl[][14] = {
|
||||
"credits",
|
||||
"alien",
|
||||
"implant",
|
||||
"launch",
|
||||
"night2",
|
||||
"night3",
|
||||
"book",
|
||||
"doll"
|
||||
};
|
||||
|
||||
static constexpr char startMusicDosCDFilenameTbl[][14] = {
|
||||
"openingt.mid",
|
||||
"alienmou.mid",
|
||||
"mindfuck.mid",
|
||||
"spaceshi.mid",
|
||||
"mindfuck.mid",
|
||||
"zombie.mid",
|
||||
"booktran.mid",
|
||||
"babydoll.mid"
|
||||
};
|
||||
|
||||
static constexpr char sfxCDFilenameTbl[][14] = {
|
||||
"",
|
||||
"opendoor.sfx",
|
||||
"showers2.sfx",
|
||||
"razzsysb.sfx",
|
||||
"medicine.sfx",
|
||||
"pop.sfx",
|
||||
"pickupit.sfx",
|
||||
"rockener.sfx",
|
||||
"pullleve.sfx",
|
||||
"starship.sfx",
|
||||
"podwrith.sfx",
|
||||
"starterc.sfx",
|
||||
"sigils.sfx",
|
||||
"tombdoor.sfx",
|
||||
"digging.sfx",
|
||||
"opendoor.sfx",
|
||||
"carstart.sfx",
|
||||
"makehamm.sfx",
|
||||
"picklock.sfx",
|
||||
"impaled.sfx",
|
||||
"evilbeas.sfx",
|
||||
"laser.sfx",
|
||||
"knock.sfx",
|
||||
"bubblesi.sfx",
|
||||
"phone.sfx",
|
||||
"softphon.sfx",
|
||||
"pulsar.sfx",
|
||||
"doorbell.sfx",
|
||||
"mirrorsm.sfx",
|
||||
"softdoor.sfx",
|
||||
"electroc.sfx",
|
||||
"medicine.sfx",
|
||||
"pourings.sfx",
|
||||
"tuneinra.sfx",
|
||||
"opendoor.sfx",
|
||||
"showers1.sfx",
|
||||
"yo.sfx",
|
||||
"showers2.sfx",
|
||||
"popii.sfx",
|
||||
"carhorn.sfx",
|
||||
"yo.sfx",
|
||||
"secretdo.sfx",
|
||||
"opendoor.sfx",
|
||||
"tick.sfx",
|
||||
"tock.sfx",
|
||||
"chime.sfx",
|
||||
"softchim.sfx",
|
||||
"shakeurn.sfx",
|
||||
"beaming.sfx"
|
||||
};
|
||||
|
||||
// Maps CD SFX IDs to floppy SFX IDs
|
||||
static constexpr int sfxCdFloppyMapping[60] = {
|
||||
// 0
|
||||
-1, // Unused
|
||||
10, // House front door
|
||||
11, // Shower
|
||||
-1, // Delbert's dog (not present in floppy version)
|
||||
13, // Stairs
|
||||
14, // Press button
|
||||
15, // Pick up item
|
||||
16, // Unused (energizing hammer head?)
|
||||
17, // Lever
|
||||
18, // Spaceship
|
||||
// 10
|
||||
19, // Leech
|
||||
20, // Car engine start
|
||||
21, // Mausoleum sigils (only used by floppy version)
|
||||
22, // Mausoleum door (only used by CD version)
|
||||
23, // Shovel
|
||||
24, // Car door
|
||||
25, // Car engine start failure
|
||||
26, // Assembling hammer
|
||||
27, // Lock picking
|
||||
28, // Guardian
|
||||
// 20
|
||||
29, // Alien dog
|
||||
30, // Alien cop gun
|
||||
12, // Cup
|
||||
32, // Cocoon
|
||||
90, // Phone (loud)
|
||||
91, // Phone (quiet)
|
||||
118, // Fixing mirror
|
||||
93, // Doorbell (loud)
|
||||
94, // Destroying mirror
|
||||
95, // Doorbell (quiet)
|
||||
// 30
|
||||
96, // Electricity
|
||||
97, // Car trunk / trunk (attic)
|
||||
98, // Drinking / pouring
|
||||
99, // Unused (tuning radio?)
|
||||
100, // Bathroom cabinet
|
||||
101, // Bathroom faucet
|
||||
-1, // Unused
|
||||
-1, // Unused (running water?)
|
||||
-1, // Unused (press button alternate?)
|
||||
111, // Car horn
|
||||
// 40
|
||||
-1, // Unused
|
||||
116, // Secret door
|
||||
115, // Kitchen doors
|
||||
107, // Clock tick (only used by floppy version)
|
||||
108, // Clock tock (only used by floppy version)
|
||||
104, // Clock chime (loud)
|
||||
106, // Clock chime (quiet)
|
||||
113, // Urn
|
||||
114, // Teleporter
|
||||
-1, // Unused
|
||||
// 50 Floppy-only sound effects
|
||||
35, // Recruitment center
|
||||
51, // Car engine running (original code uses 50 here, which sounds wrong)
|
||||
92, // Footstep
|
||||
105, // Mosquito (upstairs hallway)
|
||||
109, // Book stamp
|
||||
110, // Kitchen faucet / fountain
|
||||
112, // Phone dial tone
|
||||
-1,
|
||||
-1,
|
||||
-1
|
||||
};
|
||||
|
||||
// Maps DOS CD speech IDs to DOS floppy SFX IDs
|
||||
static Common::Pair<int, int> speechCdFloppyMapping[] = {
|
||||
// 59: ralph1 (unused & invalid)
|
||||
{ 904, 60 }, // m1-1 Librarian (phone): "Hello?" "Hello Mike. This is Sue at the library. ..."
|
||||
{ 927, 61 }, // cl1 Store clerk: "Serve yourself, Mr. Dawson."
|
||||
{ 905, 62 }, // cl2 Store clerk: "That's the last bottle of Scotch. ..."
|
||||
{ 907, 63 }, // d4a-1 Delbert: "Hi you must be Mike. ..."
|
||||
{ 908, 64 }, // d6c-2 Delbert: "You're a writer, huh? ..."
|
||||
{ 909, 65 }, // d5a-1 Delbert: "Good to see you, Dawson. ..."
|
||||
{ 910, 66 }, // d6a-2 Delbert: "Boy, that's smooth. ..."
|
||||
{ 906, 67 }, // cl3 Store clerk: "I'm sorry, Mr. Dawson, ..."
|
||||
// CD ID 925 includes both this line and the next. These are 2 separate IDs in the floppy version. CD ID 926 is unused.
|
||||
{ 925, 68 }, // gl0a Librarian: "I'm not really sure why I'm here, ..."
|
||||
{ 926, 69 }, // gl1b Librarian: "I know it sounds strange, ..."
|
||||
{ 924, 70 }, // gl2a Librarian: "This card really should be kept with the book. ..."
|
||||
// 71: s7a-1 (invalid)
|
||||
{ 912, 72 }, // s8a-2 Cop: "You're under arrest, Dawson. ..."
|
||||
{ 913, 73 }, // k9a-3 Keeper: "Greetings Michael. ..."
|
||||
{ 914, 74 }, // k9c-3 Keeper: "If born, this creature will destroy you..."
|
||||
{ 915, 75 }, // k9e-3 Keeper: "Also, the Police in your world..."
|
||||
{ 928, 76 }, // gl3a Librarian: "Hi Mike. Here's the book that was put on hold for you."
|
||||
// 77: k9e-3 (duplicate of 75)
|
||||
// 78: k9f-3 (invalid)
|
||||
{ 916, 79 }, // g10a-1 Sargo: "Greetings, human. ..."
|
||||
{ 917, 80 }, // g10b-1 Sargo: "I am prepared to give you the gift..."
|
||||
{ 918, 81 }, // m11a-1 Mike: "I'm just beginning to understand."
|
||||
{ 919, 82 }, // o12a-1 Keeper (radio): "Steal from those who protect you..."
|
||||
{ 920, 83 }, // o13a-1 Keeper (radio): "What you do in the light..."
|
||||
// 84: o13b-1 (invalid)
|
||||
{ 921, 85 }, // o14a-1 Keeper (radio): "Turn yourself in and leave behind the key..."
|
||||
{ 922, 86 }, // k15a-1 Keeper (phone): "Remember, anything seen in the mirror..."
|
||||
{ 923, 87 }, // s16a-1 Alien cop: "So that's where my gun went! ..."
|
||||
// 88: l17a-1 (invalid)
|
||||
// 89: l18a-1 (invalid)
|
||||
{ -1, -1 }
|
||||
};
|
||||
|
||||
Sound::Sound(Audio::Mixer *mixer) : _mixer(mixer), _lastPlayedDigitalSfx(0) {
|
||||
memset(_sfxFloppyDigFilenameTbl, 0, 120 * 14);
|
||||
|
||||
bool floppyMusicSetting = ConfMan.hasKey("use_floppy_music") ? ConfMan.getBool("use_floppy_music") : false;
|
||||
_useFloppyMusic = g_engine->isDosFloppy() || floppyMusicSetting;
|
||||
|
||||
// SFX mode 0: CD SFX only
|
||||
// SFX mode 1: CD SFX + additional floppy SFX
|
||||
// SFX mode 2: floppy SFX only
|
||||
// CD SFX are only available when using the CD version
|
||||
// Floppy SFX are only available when using floppy music
|
||||
int sfxMode = ConfMan.hasKey("sfx_mode") ? ConfMan.getInt("sfx_mode") : -1;
|
||||
_useCdSfx = g_engine->isCdVersion() && (!_useFloppyMusic || sfxMode != 2);
|
||||
_useFloppySfx = _useFloppyMusic && (g_engine->isDosFloppy() || sfxMode == 1 || sfxMode == 2);
|
||||
|
||||
_musicPlayer = new MusicPlayer(g_engine, _useFloppyMusic, _useFloppySfx);
|
||||
|
||||
_didSpeech.resize(978);
|
||||
resetSpeech();
|
||||
}
|
||||
|
||||
Sound::~Sound() {
|
||||
delete _musicPlayer;
|
||||
}
|
||||
|
||||
int Sound::init() {
|
||||
int returnCode = _musicPlayer->open();
|
||||
if (returnCode != 0)
|
||||
return returnCode;
|
||||
|
||||
if (_useFloppyMusic || _useFloppySfx) {
|
||||
Common::File file;
|
||||
Common::Path path = g_engine->isCdVersion() ? Common::Path("sound").join("tos1.sit") : Common::Path("tos1.sit");
|
||||
if (file.open(path)) {
|
||||
_musicPlayer->loadTosInstrumentBankData(&file, (int32)file.size());
|
||||
} else {
|
||||
warning("Failed to load TOS floppy instrument bank data %s", path.toString().c_str());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
if (_useFloppySfx) {
|
||||
Common::File file;
|
||||
Common::Path path = g_engine->isCdVersion() ? Common::Path("sound").join("tos1.sbr") : Common::Path("tos1.sbr");
|
||||
if (file.open(path)) {
|
||||
_musicPlayer->load(&file, (int32)file.size(), true);
|
||||
} else {
|
||||
warning("Failed to load TOS floppy sound effects data %s", path.toString().c_str());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
if (g_engine->isDosFloppy()) {
|
||||
Common::File file;
|
||||
Common::Path path = Common::Path("tos1.dig");
|
||||
if (file.open(path)) {
|
||||
loadTosDigData(&file, (int32)file.size());
|
||||
} else {
|
||||
warning("Failed to load TOS floppy speech data %s", path.toString().c_str());
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Sound::loadTosDigData(Common::SeekableReadStream* in, int32 size) {
|
||||
int32 bytesRead = 0;
|
||||
int entriesRead = 0;
|
||||
while (bytesRead < size && entriesRead < 120) {
|
||||
byte type = in->readByte();
|
||||
if (type == 3) {
|
||||
// VOC filename entry
|
||||
uint32 entryBytesRead = in->read(_sfxFloppyDigFilenameTbl[entriesRead], 14);
|
||||
if (entryBytesRead != 14) {
|
||||
warning("Failed to read all bytes from DIG filename entry %i", entriesRead);
|
||||
return;
|
||||
}
|
||||
bytesRead += 15;
|
||||
}
|
||||
else if (type == 0) {
|
||||
// Unknown what this entry type contains. It is ignored by the original code.
|
||||
uint16 entrySize = in->readUint16LE();
|
||||
if (!in->skip(entrySize - 3)) {
|
||||
warning("Failed to read all bytes from DIG type 0 entry %i", entriesRead);
|
||||
return;
|
||||
}
|
||||
bytesRead += entrySize;
|
||||
}
|
||||
else {
|
||||
// Unknown entry type.
|
||||
warning("Unknown DIG entry type %X in entry %i", type, entriesRead);
|
||||
return;
|
||||
}
|
||||
entriesRead++;
|
||||
}
|
||||
if (entriesRead < 100) {
|
||||
// DIG files typically contain at least 100 entries
|
||||
warning("DIG file only contained %i entries", entriesRead);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::playTosSpeech(int tosIdx) {
|
||||
if (g_engine->isDosFloppy()) {
|
||||
int floppySfxId = convertCdSpeechToFloppySfxId(tosIdx);
|
||||
if (floppySfxId == -1)
|
||||
return;
|
||||
|
||||
playDosFloppySfx(floppySfxId, 5);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!g_engine->isCdVersion() || _didSpeech[tosIdx] == 1) {
|
||||
return;
|
||||
}
|
||||
Common::String filename = Common::String::format("%d.voc", tosIdx + 1);
|
||||
Common::Path path = Common::Path("speech").join(filename);
|
||||
Common::File f;
|
||||
if (!f.open(path)) {
|
||||
return;
|
||||
}
|
||||
Common::SeekableReadStream *srcStream = f.readStream((uint32)f.size());
|
||||
Audio::SeekableAudioStream *stream = Audio::makeVOCStream(srcStream,
|
||||
Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
|
||||
_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream);
|
||||
_didSpeech[tosIdx] = 1;
|
||||
}
|
||||
|
||||
void Sound::stopSpeech() {
|
||||
_mixer->stopHandle(_speechHandle);
|
||||
}
|
||||
|
||||
bool Sound::isPlayingSpeech() const {
|
||||
return _mixer->isSoundHandleActive(_speechHandle);
|
||||
}
|
||||
|
||||
bool Sound::isPlayingSfx() const {
|
||||
return _mixer->isSoundHandleActive(_sfxHandle) || _musicPlayer->isPlayingSfx();
|
||||
}
|
||||
|
||||
bool Sound::isPlayingSfx(uint8 sfxId) const {
|
||||
if (_useFloppySfx) {
|
||||
int floppySfxId = sfxCdFloppyMapping[sfxId];
|
||||
if (floppySfxId == -1)
|
||||
return false;
|
||||
|
||||
return _musicPlayer->isPlayingSfx(floppySfxId);
|
||||
}
|
||||
|
||||
return _lastPlayedDigitalSfx == sfxId && _mixer->isSoundHandleActive(_sfxHandle);
|
||||
}
|
||||
|
||||
bool Sound::isPlayingMusic() {
|
||||
return _musicPlayer->isPlayingMusic();
|
||||
}
|
||||
|
||||
void Sound::resetSpeech() {
|
||||
for (int i = 0; i < (int)_didSpeech.size(); i++) {
|
||||
_didSpeech[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::playMusic(MusicId musicId, bool loop) {
|
||||
if (musicId == MusicId::kNone) {
|
||||
return;
|
||||
}
|
||||
int filenameIdx = static_cast<uint8>(musicId) - 1;
|
||||
playMusic(_useFloppyMusic ?
|
||||
Common::String(musicDosFloppyFilenameTbl[filenameIdx]) + ".sbr" : musicDosCDFilenameTbl[filenameIdx],
|
||||
nullptr, 6, loop);
|
||||
}
|
||||
|
||||
void Sound::playMusic(StartMusicId musicId) {
|
||||
int filenameIdx = static_cast<uint8>(musicId);
|
||||
if (_useFloppyMusic) {
|
||||
Common::String const &filenameBase = startMusicDosFloppyFilenameTbl[filenameIdx];
|
||||
Common::String const &filenameSbr = filenameBase + ".sbr";
|
||||
Common::String const &filenameSit = filenameBase + ".sit";
|
||||
|
||||
playMusic(filenameSbr, &filenameSit, 5);
|
||||
}
|
||||
else {
|
||||
playMusic(startMusicDosCDFilenameTbl[filenameIdx]);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::playMusic(Common::String const &musicFilename, Common::String const *instrBankFilename, uint8 priority, bool loop) {
|
||||
Common::File file;
|
||||
Common::Path path;
|
||||
if (_useFloppyMusic) {
|
||||
if (instrBankFilename != nullptr) {
|
||||
path = g_engine->isCdVersion() ? Common::Path("sound").join(instrBankFilename->c_str()) : Common::Path(instrBankFilename->c_str());
|
||||
debug("Loading instrument bank: %s", path.toString().c_str());
|
||||
if (!file.open(path)) {
|
||||
debug("Failed to load %s", path.toString().c_str());
|
||||
return;
|
||||
}
|
||||
_musicPlayer->loadInstrumentBank(&file, (int32)file.size());
|
||||
file.close();
|
||||
}
|
||||
else {
|
||||
debug("Loading TOS instrument bank");
|
||||
_musicPlayer->loadTosInstrumentBank();
|
||||
}
|
||||
}
|
||||
path = g_engine->isCdVersion() ? Common::Path("sound").join(musicFilename) : Common::Path(musicFilename);
|
||||
debug("Loading music: %s", path.toString().c_str());
|
||||
if (!file.open(path)) {
|
||||
debug("Failed to load %s", path.toString().c_str());
|
||||
return;
|
||||
}
|
||||
_musicPlayer->load(&file, (int32)file.size());
|
||||
file.close();
|
||||
|
||||
_musicPlayer->playMusic(priority, loop);
|
||||
}
|
||||
|
||||
void Sound::stopMusic() {
|
||||
_musicPlayer->stopMusic();
|
||||
}
|
||||
|
||||
void Sound::pauseMusic(bool pause) {
|
||||
_musicPlayer->pauseMusic(pause);
|
||||
}
|
||||
|
||||
void Sound::killAllSound() {
|
||||
stopMusic();
|
||||
stopSfx();
|
||||
stopSpeech();
|
||||
}
|
||||
|
||||
void Sound::syncSoundSettings() {
|
||||
_musicPlayer->syncSoundSettings();
|
||||
}
|
||||
|
||||
Common::Error Sound::sync(Common::Serializer &s) {
|
||||
s.syncArray(_didSpeech.data(), _didSpeech.size(), Common::Serializer::Byte);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
bool Sound::isMuted() const {
|
||||
bool soundIsMuted = false;
|
||||
if (ConfMan.hasKey("mute")) {
|
||||
soundIsMuted = ConfMan.getBool("mute");
|
||||
}
|
||||
return soundIsMuted;
|
||||
}
|
||||
|
||||
void Sound::playSfx(uint8 sfxId, uint8 priority, int unk2) {
|
||||
// Do not play floppy-only SFX using the CD SFX playing code
|
||||
if (_useCdSfx && sfxId <= 48 && sfxId != 43 && sfxId != 44) {
|
||||
playDosCDSfx(sfxId);
|
||||
}
|
||||
else if (_useFloppySfx && sfxId < 60) {
|
||||
int floppySfxId = sfxCdFloppyMapping[sfxId];
|
||||
if (floppySfxId == -1)
|
||||
return;
|
||||
|
||||
playDosFloppySfx(floppySfxId, priority);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::stopSfx() {
|
||||
_mixer->stopHandle(_sfxHandle);
|
||||
_musicPlayer->stopAllSfx();
|
||||
}
|
||||
|
||||
void Sound::playDosCDSfx(int sfxId) {
|
||||
if (sfxId == 0 || sfxId > 48) {
|
||||
return;
|
||||
}
|
||||
if (isPlayingSfx()) {
|
||||
return;
|
||||
}
|
||||
Common::Path path = Common::Path("sound").join(sfxCDFilenameTbl[sfxId]);
|
||||
Common::File f;
|
||||
if (!f.open(path)) {
|
||||
debug("Failed to load sfx. %s", path.toString().c_str());
|
||||
return;
|
||||
}
|
||||
Common::SeekableReadStream *srcStream = f.readStream((uint32)f.size());
|
||||
Audio::SeekableAudioStream *stream = Audio::makeVOCStream(srcStream,
|
||||
Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_sfxHandle, stream);
|
||||
_lastPlayedDigitalSfx = sfxId;
|
||||
}
|
||||
|
||||
void Sound::playDosFloppySfx(byte floppySfxId, uint8 priority) {
|
||||
if (_musicPlayer->isSampleSfx(floppySfxId)) {
|
||||
playFloppySpeech(floppySfxId);
|
||||
} else if (floppySfxId >= 10 && floppySfxId < 120) {
|
||||
_musicPlayer->playSfx(floppySfxId, priority);
|
||||
}
|
||||
}
|
||||
|
||||
void Sound::playFloppySpeech(int floppySfxId) {
|
||||
Common::String filename = _sfxFloppyDigFilenameTbl[floppySfxId];
|
||||
if (filename.size() == 0)
|
||||
return;
|
||||
|
||||
Common::Path path = Common::Path(filename + ".voc");
|
||||
Common::File f;
|
||||
if (!f.open(path)) {
|
||||
warning("Failed to load speech file %s", path.toString().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *srcStream = f.readStream((uint32)f.size());
|
||||
Audio::SeekableAudioStream *stream = Audio::makeVOCStream(srcStream,
|
||||
Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
|
||||
_mixer->playStream(Audio::Mixer::kSpeechSoundType, &_speechHandle, stream);
|
||||
}
|
||||
|
||||
void Sound::startFadeOut() {
|
||||
_musicPlayer->startFadeOutMusic();
|
||||
}
|
||||
|
||||
bool Sound::isFading() {
|
||||
return _musicPlayer->isFadingMusic();
|
||||
}
|
||||
|
||||
int Sound::convertCdSpeechToFloppySfxId(int cdSfxId) {
|
||||
int i = 0;
|
||||
while (true) {
|
||||
int entryCdSfxId = speechCdFloppyMapping[i].first;
|
||||
if (entryCdSfxId == -1)
|
||||
return -1;
|
||||
if (entryCdSfxId == cdSfxId)
|
||||
return speechCdFloppyMapping[i].second;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
bool Sound::isUsingCdSfx() const {
|
||||
return _useCdSfx;
|
||||
}
|
||||
|
||||
bool Sound::isUsingFloppySfx() const {
|
||||
return _useFloppySfx;
|
||||
}
|
||||
void Sound::resetIndividualSpeech(int tosIdx) {
|
||||
_didSpeech[tosIdx] = 0;
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
115
engines/darkseed/sound.h
Normal file
115
engines/darkseed/sound.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_SOUND_H
|
||||
#define DARKSEED_SOUND_H
|
||||
|
||||
#include "darkseed/music.h"
|
||||
|
||||
#include "audio/mixer.h"
|
||||
#include "common/array.h"
|
||||
#include "common/error.h"
|
||||
#include "common/serializer.h"
|
||||
|
||||
namespace Darkseed {
|
||||
enum class MusicId : uint8 {
|
||||
kNone = 0,
|
||||
kLab,
|
||||
kVictory,
|
||||
kCemetry,
|
||||
kLeech,
|
||||
kExt,
|
||||
kQuiet,
|
||||
kPackage,
|
||||
kDth,
|
||||
kLibrary,
|
||||
kRadio,
|
||||
kOutdoor,
|
||||
kTown,
|
||||
};
|
||||
|
||||
enum class StartMusicId : uint8 {
|
||||
kCredits = 0,
|
||||
kAlien,
|
||||
kImplant,
|
||||
kLaunch,
|
||||
kNight2,
|
||||
kNight3,
|
||||
kBook,
|
||||
kDoll
|
||||
};
|
||||
|
||||
class Sound {
|
||||
// Floppy speech filenames from TOS1.DIG
|
||||
char _sfxFloppyDigFilenameTbl[120][14];
|
||||
|
||||
Audio::Mixer *_mixer;
|
||||
Audio::SoundHandle _speechHandle;
|
||||
Audio::SoundHandle _sfxHandle;
|
||||
MusicPlayer *_musicPlayer;
|
||||
Common::Array<uint8> _didSpeech;
|
||||
bool _useFloppyMusic;
|
||||
bool _useCdSfx;
|
||||
bool _useFloppySfx;
|
||||
uint8 _lastPlayedDigitalSfx;
|
||||
|
||||
public:
|
||||
explicit Sound(Audio::Mixer *mixer);
|
||||
~Sound();
|
||||
|
||||
int init();
|
||||
|
||||
Common::Error sync(Common::Serializer &s);
|
||||
|
||||
bool isMuted() const;
|
||||
void playTosSpeech(int tosIdx);
|
||||
void stopSpeech();
|
||||
bool isPlayingSpeech() const;
|
||||
bool isPlayingSfx() const;
|
||||
bool isPlayingSfx(uint8 sfxId) const;
|
||||
bool isPlayingMusic();
|
||||
void resetSpeech();
|
||||
void resetIndividualSpeech(int tosIdx);
|
||||
void playMusic(MusicId musicId, bool loop = true);
|
||||
void playMusic(StartMusicId musicId);
|
||||
void playMusic(Common::String const &filename, Common::String const *instrBankFilename = nullptr, uint8 priority = 0xFF, bool loop = false);
|
||||
void stopMusic();
|
||||
void pauseMusic(bool pause);
|
||||
void playSfx(uint8 sfxId, uint8 priority, int unk2);
|
||||
void playDosFloppySfx(byte sfxId, uint8 priority);
|
||||
void stopSfx();
|
||||
bool isUsingCdSfx() const;
|
||||
bool isUsingFloppySfx() const;
|
||||
void syncSoundSettings();
|
||||
void killAllSound();
|
||||
void startFadeOut();
|
||||
bool isFading();
|
||||
|
||||
private:
|
||||
void loadTosDigData(Common::SeekableReadStream *in, int32 size);
|
||||
void playDosCDSfx(int sfxId);
|
||||
void playFloppySpeech(int tosIdx);
|
||||
int convertCdSpeechToFloppySfxId(int cdSfxId);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_SOUND_H
|
||||
78
engines/darkseed/sprites.cpp
Normal file
78
engines/darkseed/sprites.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 "darkseed/sprites.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
#define DARKSEED_MAX_SPRITES_ON_SCREEN 30
|
||||
|
||||
Sprites::Sprites() {
|
||||
_spriteDrawList.reserve(DARKSEED_MAX_SPRITES_ON_SCREEN);
|
||||
}
|
||||
|
||||
void Sprites::addSpriteToDrawList(uint16 destX, uint16 destY, const Sprite *sprite, uint8 order, uint16 destW, uint16 destH, bool flip) {
|
||||
if (_spriteDrawList.size() == DARKSEED_MAX_SPRITES_ON_SCREEN || destX >= 570) {
|
||||
return;
|
||||
}
|
||||
|
||||
SpriteDrawInstruction drawInstruction;
|
||||
drawInstruction.destX = destX;
|
||||
drawInstruction.destY = destY;
|
||||
drawInstruction.sprite = sprite;
|
||||
drawInstruction.order = order;
|
||||
drawInstruction.destW = destW;
|
||||
drawInstruction.destH = destH;
|
||||
drawInstruction.flip = flip;
|
||||
|
||||
if (!_spriteDrawList.empty()) {
|
||||
uint insertLocation = 0;
|
||||
for (; insertLocation < _spriteDrawList.size(); insertLocation++) {
|
||||
if (order < _spriteDrawList[insertLocation].order) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
_spriteDrawList.insert_at(insertLocation, drawInstruction);
|
||||
} else {
|
||||
_spriteDrawList.push_back(drawInstruction);
|
||||
}
|
||||
}
|
||||
|
||||
void Sprites::clearSpriteDrawList() {
|
||||
// not using clear() here to avoid freeing array storage memory.
|
||||
while (!_spriteDrawList.empty()) {
|
||||
_spriteDrawList.pop_back();
|
||||
}
|
||||
}
|
||||
|
||||
void Sprites::drawSprites() {
|
||||
for (int i = _spriteDrawList.size() - 1; i >= 0; i--) {
|
||||
SpriteDrawInstruction &drawInstruction = _spriteDrawList[i];
|
||||
if (drawInstruction.sprite->_width == drawInstruction.destW && drawInstruction.sprite->_height == drawInstruction.destH && !drawInstruction.flip) {
|
||||
drawInstruction.sprite->draw(drawInstruction.destX, drawInstruction.destY, g_engine->_frameBottom); // TODO add support for flipping sprite.
|
||||
} else {
|
||||
drawInstruction.sprite->drawScaled(drawInstruction.destX, drawInstruction.destY, drawInstruction.destW, drawInstruction.destH, drawInstruction.flip);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} // End of namespace Darkseed
|
||||
54
engines/darkseed/sprites.h
Normal file
54
engines/darkseed/sprites.h
Normal file
@@ -0,0 +1,54 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_SPRITES_H
|
||||
#define DARKSEED_SPRITES_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "darkseed/nsp.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
struct SpriteDrawInstruction {
|
||||
uint16 destX = 0;
|
||||
uint16 destY = 0;
|
||||
uint16 srcW = 0;
|
||||
uint16 srcH = 0;
|
||||
const Sprite *sprite = nullptr;
|
||||
uint8 order = 0;
|
||||
uint16 destW = 0;
|
||||
uint16 destH = 0;
|
||||
bool flip = false;
|
||||
};
|
||||
|
||||
class Sprites {
|
||||
Common::Array<SpriteDrawInstruction> _spriteDrawList;
|
||||
|
||||
public:
|
||||
Sprites();
|
||||
void addSpriteToDrawList(uint16 destX, uint16 destY, const Sprite *sprite, uint8 order, uint16 destW, uint16 destH, bool flip);
|
||||
void clearSpriteDrawList();
|
||||
|
||||
void drawSprites();
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
#endif // DARKSEED_SPRITES_H
|
||||
78
engines/darkseed/titlefont.cpp
Normal file
78
engines/darkseed/titlefont.cpp
Normal file
@@ -0,0 +1,78 @@
|
||||
/* 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 "graphics/screen.h"
|
||||
#include "darkseed/titlefont.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
|
||||
namespace Darkseed {
|
||||
extern DarkseedEngine *g_engine;
|
||||
|
||||
TitleFont::TitleFont() {
|
||||
_letters.load("art/letters.anm");
|
||||
}
|
||||
|
||||
uint8 letterIndexLookupTbl[] = {
|
||||
50, 52, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 2, 4, 6,
|
||||
8, 10, 12, 14,
|
||||
16, 18, 20, 22,
|
||||
24, 26, 28, 30,
|
||||
0, 32, 34, 36,
|
||||
38, 40, 42, 44,
|
||||
46, 48
|
||||
};
|
||||
|
||||
int16 letterWidthLookupTbl[] = {
|
||||
18, 18, 18, 18,
|
||||
18, 18, 18, 18,
|
||||
10, 12, 16, 18,
|
||||
20, 20, 18, 18,
|
||||
18, 18, 18, 18,
|
||||
18, 20, 20, 18,
|
||||
20, 18, 10
|
||||
};
|
||||
|
||||
void TitleFont::displayString(uint16 x, uint16 y, const Common::String &text) {
|
||||
for (unsigned int i = 0; i < text.size(); i++) {
|
||||
if (text[i] == ' ') {
|
||||
x += 0x12;
|
||||
continue;
|
||||
}
|
||||
Img letterShadow;
|
||||
Img letter;
|
||||
int letterId = letterIndexLookupTbl[text[i] - 45];
|
||||
_letters.getImg(letterId, letterShadow, false);
|
||||
_letters.getImg(letterId + 1, letter, false);
|
||||
|
||||
int w = letterWidthLookupTbl[letterId / 2];
|
||||
letterShadow.drawAt(x, y, 2, w - 1); // TODO the original doesn't seem to need to override the width here.
|
||||
letter.drawAt(x, y + 1, 3);
|
||||
debug("%c %d %d %d", text[i], w, letter.getWidth(), letterShadow.getWidth());
|
||||
x += w;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
39
engines/darkseed/titlefont.h
Normal file
39
engines/darkseed/titlefont.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_TITLEFONT_H
|
||||
#define DARKSEED_TITLEFONT_H
|
||||
|
||||
#include "darkseed/anm.h"
|
||||
namespace Darkseed {
|
||||
|
||||
class TitleFont {
|
||||
Anm _letters;
|
||||
|
||||
public:
|
||||
TitleFont();
|
||||
void displayString(uint16 x, uint16 y, const Common::String &text);
|
||||
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_TITLEFONT_H
|
||||
100
engines/darkseed/tostext.cpp
Normal file
100
engines/darkseed/tostext.cpp
Normal file
@@ -0,0 +1,100 @@
|
||||
/* 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 "common/file.h"
|
||||
#include "darkseed/darkseed.h"
|
||||
#include "darkseed/tostext.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
bool TosText::load() {
|
||||
if (g_engine->isDosDemo()) {
|
||||
loadDemoTosEntries();
|
||||
return true;
|
||||
}
|
||||
Common::File tostextFile;
|
||||
if (!tostextFile.open("tostext.bin")) {
|
||||
return false;
|
||||
}
|
||||
_numEntries = tostextFile.readUint16LE() / 2;
|
||||
_textArray.resize(_numEntries);
|
||||
|
||||
for (int i = 0; i < _numEntries; i++) {
|
||||
_textArray[i] = loadString(tostextFile, i);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void TosText::loadDemoTosEntries() {
|
||||
_numEntries = 973;
|
||||
_textArray.resize(_numEntries);
|
||||
_textArray[10] = "My head is killing me.";
|
||||
_textArray[11] = "My head feels like it is going to explode.";
|
||||
_textArray[12] = "It seems like I've had this headache since I moved here.";
|
||||
_textArray[13] = "I need an asprin or something.";
|
||||
|
||||
_textArray[798] = "You can't touch the horizon!";
|
||||
|
||||
_textArray[802] = "You see the unfortunate victims of the life leech.";
|
||||
|
||||
_textArray[972] = "Holding ";
|
||||
}
|
||||
|
||||
const Common::U32String &TosText::getText(uint16 textIndex) {
|
||||
assert(textIndex < _numEntries);
|
||||
return _textArray[textIndex];
|
||||
}
|
||||
|
||||
Common::U32String TosText::loadString(Common::File &file, uint16 index) const {
|
||||
Common::U32String str;
|
||||
file.seek(index * 2, SEEK_SET);
|
||||
auto startOffset = file.readUint16LE();
|
||||
uint16 strLen = index == _numEntries - 1
|
||||
? (uint16)file.size() - startOffset
|
||||
: file.readUint16LE() - startOffset;
|
||||
file.seek(startOffset, SEEK_SET);
|
||||
if (g_engine->getLanguage() == Common::KO_KOR || g_engine->getLanguage() == Common::ZH_ANY) {
|
||||
// handle multi-byte languages
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
uint8 byte = (char)file.readByte();
|
||||
if (byte & 0x80) {
|
||||
if (i < strLen - 1) {
|
||||
uint8 byte2 = (char)file.readByte();
|
||||
str += (int)byte << 8 | byte2;
|
||||
i++;
|
||||
}
|
||||
} else {
|
||||
str += byte;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (int i = 0; i < strLen; i++) {
|
||||
str += (char)file.readByte();
|
||||
}
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
uint16 TosText::getNumEntries() const {
|
||||
return _numEntries;
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
48
engines/darkseed/tostext.h
Normal file
48
engines/darkseed/tostext.h
Normal file
@@ -0,0 +1,48 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_TOSTEXT_H
|
||||
#define DARKSEED_TOSTEXT_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/file.h"
|
||||
#include "common/str.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class TosText {
|
||||
Common::U32StringArray _textArray;
|
||||
uint16 _numEntries = 0;
|
||||
|
||||
public:
|
||||
bool load();
|
||||
|
||||
uint16 getNumEntries() const;
|
||||
const Common::U32String &getText(uint16 textIndex);
|
||||
|
||||
private:
|
||||
Common::U32String loadString(Common::File &file, uint16 index) const;
|
||||
void loadDemoTosEntries();
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_TOSTEXT_H
|
||||
1763
engines/darkseed/usecode.cpp
Normal file
1763
engines/darkseed/usecode.cpp
Normal file
File diff suppressed because it is too large
Load Diff
98
engines/darkseed/usecode.h
Normal file
98
engines/darkseed/usecode.h
Normal file
@@ -0,0 +1,98 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_USECODE_H
|
||||
#define DARKSEED_USECODE_H
|
||||
|
||||
#include "common/scummsys.h"
|
||||
#include "darkseed/console.h"
|
||||
#include "darkseed/inventory.h"
|
||||
#include "darkseed/objects.h"
|
||||
#include "darkseed/player.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
class UseCode {
|
||||
Console *_console = nullptr;
|
||||
Player *_player = nullptr;
|
||||
Objects &_objectVar;
|
||||
Inventory &_inventory;
|
||||
uint8 _genericResponseCounter = 0;
|
||||
|
||||
public:
|
||||
UseCode(Console *console, Player *player, Objects &objectVar, Inventory &inventory);
|
||||
|
||||
void useCode(int objNum);
|
||||
void useCodeGloves(int16 targetObjNum);
|
||||
void useCodeMoney(int16 targetObjNum);
|
||||
void useCodeJournal(int16 actionObjNum, int16 targetObjNum);
|
||||
void useCodeShopItems(int16 actionObjNum, int16 targetObjNum);
|
||||
void useCrowBar(int16 targetObjNum);
|
||||
void useCodeNewspaper(int16 targetObjNum);
|
||||
void useCodeLibraryCard(int16 targetObjNum);
|
||||
void useCodeBobbyPin(int16 targetObjNum);
|
||||
void useCodeKeys(int16 actionObjNum, int16 targetObjNum);
|
||||
void useCodeMirrorShard(int16 targetObjNum);
|
||||
void useCodeBinoculars(int16 targetObjNum);
|
||||
void useCodeShovel(int16 targetObjNum);
|
||||
void useCodeDelbertsCard(int16 targetObjNum);
|
||||
void useCodeStick(int16 targetObjNum);
|
||||
void useCodeAxeHandle(int16 targetObjNum);
|
||||
void useCodeRope(int16 targetObjNum);
|
||||
void useCodeMicroFilm(int16 targetObjNum);
|
||||
void useCodeSpecialHammer(int16 actionObjNum, int16 targetObjNum);
|
||||
void useCodeGun(int16 targetObjNum);
|
||||
void useCodeMoversNote(int16 targetObjNum);
|
||||
void useCodeBluePrints(int16 targetObjNum);
|
||||
void useCodeWatch(int16 targetObjNum);
|
||||
void useCodeTinCup(int16 targetObjNum);
|
||||
void useCodeEmptyUrn(int16 targetObjNum);
|
||||
void genericResponse(int16 useObjNum, int16 targetObjNum, int16 tosIdx);
|
||||
|
||||
private:
|
||||
int getHandDescriptionTosIdx(uint16 objNum);
|
||||
int16 getUseGlovesTosIdx(uint16 objNum);
|
||||
int16 getUseMoneyTosIdx(uint16 objNum);
|
||||
int16 getUseCrowbarTosIdx(uint16 objNum);
|
||||
int16 getUseJournalTosIdx(uint16 objNum);
|
||||
int16 getUseLibraryCardTosIdx(uint16 objNum);
|
||||
int16 getUseBobbyPinTosIdx(uint16 objNum);
|
||||
int16 getUseKeysTosIdx(uint16 objNum);
|
||||
int16 getUseBinocularsTosIdx(uint16 objNum);
|
||||
int16 getUseShovelTosIdx(uint16 objNum);
|
||||
int16 getUseDelbertsCardTosIdx(uint16 objNum);
|
||||
int16 getUseStickTosIdx(uint16 objNum);
|
||||
int16 getUseAxeHandleTosIdx(uint16 objNum);
|
||||
int16 getUseRopeTosIdx(uint16 objNum);
|
||||
int16 getUseMicroFilmTosIdx(uint16 objNum);
|
||||
int16 getUseSpecialHammerTosIdx(uint16 objNum);
|
||||
int16 getUseGunTosIdx(uint16 objNum);
|
||||
int16 getUseWatchTosIdx(uint16 objNum);
|
||||
|
||||
void putObjUnderPillow(int objNum);
|
||||
|
||||
void startDigging(int16 targetObjNum);
|
||||
void genericSingleObjectResponse(const I18nText &text, int16 useObjNum, KoreanObjectSuffixType krObjSuffixType=KoreanObjectSuffixType::None);
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_USECODE_H
|
||||
982
engines/darkseed/usecode_tos_tables.h
Normal file
982
engines/darkseed/usecode_tos_tables.h
Normal file
@@ -0,0 +1,982 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_USECODE_TOS_TABLES_H
|
||||
#define DARKSEED_USECODE_TOS_TABLES_H
|
||||
|
||||
namespace Darkseed {
|
||||
static constexpr uint16 handDescriptionsTbl[] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
791, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 652, 0,
|
||||
729, 0, 0, 0,
|
||||
0, 0, 0, 852,
|
||||
0, 0, 0, 772,
|
||||
0, 0, 846, 0,
|
||||
0, 453, 0, 0,
|
||||
484, 0, 0, 0,
|
||||
0, 0, 0, 706,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 609,
|
||||
611, 607, 605, 603,
|
||||
601, 599, 597, 595,
|
||||
593, 591, 589, 0,
|
||||
0, 0, 0, 355,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 827,
|
||||
839, 0, 798, 807,
|
||||
803, 441, 449, 118,
|
||||
260, 272, 306, 91,
|
||||
162, 137, 377, 399,
|
||||
415, 475, 478, 481,
|
||||
0, 0, 999, 253,
|
||||
0, 0, 171, 183,
|
||||
213, 220, 285, 316,
|
||||
329, 338, 338, 357,
|
||||
516, 527, 534, 0,
|
||||
548, 562, 571, 576,
|
||||
614, 616, 621, 625,
|
||||
637, 0, 642, 644,
|
||||
646, 0, 674, 678,
|
||||
681, 684, 689, 0,
|
||||
726, 747, 0, 760,
|
||||
766, 781, 788, 819,
|
||||
823, 825, 0, 0,
|
||||
863, 0, 881, 888,
|
||||
892, 901, 0, 0,
|
||||
672, 322, 164
|
||||
};
|
||||
|
||||
static constexpr int16 glovesTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 525,
|
||||
999, 999, 999, 999,
|
||||
999, 84, 999, 745,
|
||||
999, 999, 84, 999,
|
||||
999, 84, 84, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 84,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 84, 999,
|
||||
84, 999, 84, 49,
|
||||
999, 84, 999, 999,
|
||||
198, 487, 999, 773,
|
||||
999, 0, 999, 84,
|
||||
999, 84, 84, 999,
|
||||
999, 999, 84, 84,
|
||||
84, 999, 999, 84,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 35, 999,
|
||||
84, 999, 999, 999,
|
||||
84, 84, 84, 84,
|
||||
84, 84, 84, 84,
|
||||
84, 84, 84, 84,
|
||||
84, 84, 84, 999,
|
||||
84, 84, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 84, 392, 84,
|
||||
996, 84, 999, 981,
|
||||
999, 796, 999, 808,
|
||||
804, 84, 84, 84,
|
||||
999, 84, 84, 84,
|
||||
999, 998, 991, 84,
|
||||
84, 999, 84, 84,
|
||||
999, 84, 999, 84,
|
||||
999, 999, 84, 185,
|
||||
84, 84, 84, 84,
|
||||
84, 84, 84, 999,
|
||||
999, 84, 84, 999,
|
||||
84, 999, 84, 84,
|
||||
84, 84, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 84, 84,
|
||||
84, 84, 84, 84,
|
||||
84, 84, 999, 999,
|
||||
768, 999, 999, 820,
|
||||
84, 84, 999, 999,
|
||||
999, 999, 999, 84,
|
||||
84, 999, 84, 84,
|
||||
84, 84, 999
|
||||
};
|
||||
|
||||
static constexpr int16 moneyTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 169,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
961, 961, 961, 961,
|
||||
961, 999, 999, 999,
|
||||
999, 999, 543, 58,
|
||||
872, 999, 999, 999,
|
||||
206, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 461, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
560, 999, 999, 999,
|
||||
999, 436, 999, 586,
|
||||
586, 586, 586, 586,
|
||||
586, 586, 586, 586,
|
||||
586, 586, 586, 999,
|
||||
156, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 0, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
804, 990, 999, 132,
|
||||
999, 281, 86, 111,
|
||||
999, 998, 991, 402,
|
||||
417, 999, 999, 999,
|
||||
999, 303, 0, 999,
|
||||
999, 999, 999, 190,
|
||||
217, 227, 290, 999,
|
||||
999, 999, 999, 999,
|
||||
906, 531, 999, 999,
|
||||
550, 999, 573, 577,
|
||||
999, 999, 999, 633,
|
||||
633, 633, 633, 633,
|
||||
633, 999, 999, 999,
|
||||
988, 687, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 785, 999, 999,
|
||||
980, 982, 999, 999,
|
||||
865, 999, 885, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 326, 999
|
||||
};
|
||||
|
||||
static constexpr int16 crowBarTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 518,
|
||||
999, 999, 999, 524,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
518, 518, 518, 518,
|
||||
518, 757, 0, 999,
|
||||
999, 999, 999, 51,
|
||||
999, 249, 999, 999,
|
||||
999, 485, 999, 999,
|
||||
999, 999, 979, 411,
|
||||
999, 456, 999, 999,
|
||||
999, 999, 470, 470,
|
||||
470, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 36, 832,
|
||||
999, 999, 999, 999,
|
||||
999, 433, 999, 583,
|
||||
583, 583, 583, 583,
|
||||
583, 583, 583, 583,
|
||||
583, 583, 583, 999,
|
||||
999, 986, 999, 360,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 753, 984, 981,
|
||||
999, 999, 999, 808,
|
||||
804, 990, 999, 999,
|
||||
22, 67, 85, 100,
|
||||
999, 998, 379, 999,
|
||||
999, 999, 479, 479,
|
||||
999, 995, 999, 999,
|
||||
999, 999, 173, 999,
|
||||
215, 224, 286, 999,
|
||||
330, 342, 349, 360,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 999, 579,
|
||||
999, 999, 999, 628,
|
||||
628, 628, 628, 628,
|
||||
628, 999, 999, 999,
|
||||
988, 686, 999, 999,
|
||||
999, 999, 999, 762,
|
||||
999, 782, 999, 983,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 324, 999
|
||||
};
|
||||
|
||||
static constexpr int16 journalTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 486, 999,
|
||||
868, 999, 999, 999,
|
||||
196, 486, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 455, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 999, 999, 981,
|
||||
999, 999, 999, 999,
|
||||
804, 999, 999, 999,
|
||||
999, 999, 82, 93,
|
||||
999, 998, 991, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 299, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 222, 146, 309,
|
||||
999, 999, 999, 999,
|
||||
486, 999, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
980, 982, 999, 864,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 994, 999
|
||||
};
|
||||
|
||||
static constexpr int16 libraryCardTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 0, 56,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
559, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
154, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 0, 999, 981,
|
||||
999, 999, 999, 999,
|
||||
804, 443, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 998, 991, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 177, 999,
|
||||
999, 222, 288, 309,
|
||||
999, 999, 999, 999,
|
||||
519, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 499, 999,
|
||||
999, 993, 999
|
||||
};
|
||||
|
||||
static constexpr int16 bobbyPinTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 50,
|
||||
0, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 457, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
555, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 0, 999, 981,
|
||||
999, 999, 999, 808,
|
||||
804, 990, 999, 125,
|
||||
999, 66, 999, 99,
|
||||
999, 998, 991, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 223, 999, 999,
|
||||
332, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 676, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 0, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 993, 999
|
||||
};
|
||||
|
||||
static constexpr int16 keysTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
871, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 413,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 472, 472,
|
||||
472, 999, 999, 0,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 435, 716, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 986, 999, 365,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 999, 999, 981,
|
||||
999, 999, 999, 808,
|
||||
804, 990, 999, 999,
|
||||
25, 999, 999, 108,
|
||||
999, 998, 381, 999,
|
||||
416, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
336, 999, 999, 365,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 784, 784, 999,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 884, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 993, 999
|
||||
};
|
||||
|
||||
static constexpr int16 binocularsTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 53,
|
||||
999, 999, 999, 999,
|
||||
200, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 459, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 38, 999,
|
||||
556, 999, 999, 999,
|
||||
999, 999, 999, 584,
|
||||
584, 584, 584, 584,
|
||||
584, 584, 584, 584,
|
||||
584, 584, 584, 999,
|
||||
150, 986, 999, 361,
|
||||
999, 999, 999, 999,
|
||||
386, 192, 392, 999,
|
||||
996, 753, 999, 999,
|
||||
999, 999, 799, 999,
|
||||
804, 990, 999, 127,
|
||||
23, 69, 999, 103,
|
||||
127, 998, 991, 401,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 174, 187,
|
||||
999, 225, 287, 999,
|
||||
334, 343, 343, 999,
|
||||
999, 530, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 623, 630,
|
||||
630, 630, 630, 630,
|
||||
630, 999, 999, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 763,
|
||||
999, 999, 999, 999,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 498, 999,
|
||||
999, 993, 998
|
||||
};
|
||||
|
||||
static constexpr int16 shovelTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 524,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 48,
|
||||
999, 999, 627, 999,
|
||||
999, 485, 999, 999,
|
||||
999, 999, 979, 411,
|
||||
999, 456, 999, 999,
|
||||
999, 999, 470, 470,
|
||||
470, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 34, 832,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 999,
|
||||
147, 986, 999, 359,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 753, 999, 981,
|
||||
841, 999, 999, 808,
|
||||
804, 990, 999, 123,
|
||||
21, 65, 310, 97,
|
||||
999, 998, 991, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 995, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 286, 999,
|
||||
330, 341, 348, 359,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 572, 578,
|
||||
999, 999, 999, 627,
|
||||
627, 627, 627, 627,
|
||||
627, 999, 999, 999,
|
||||
988, 686, 999, 999,
|
||||
999, 999, 999, 762,
|
||||
999, 999, 999, 983,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 498, 999,
|
||||
999, 323, 999
|
||||
};
|
||||
|
||||
static constexpr int16 delbertsCardTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 168,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 541, 52,
|
||||
999, 999, 999, 999,
|
||||
999, 0, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 455, 999, 999,
|
||||
0, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 37, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
149, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 754, 999, 981,
|
||||
999, 999, 999, 999,
|
||||
805, 990, 999, 999,
|
||||
999, 999, 999, 101,
|
||||
999, 998, 991, 999,
|
||||
999, 999, 999, 482,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 222, 999, 309,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 783, 999, 999,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 993, 999
|
||||
};
|
||||
|
||||
static constexpr int16 stickTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 524,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 0, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
201, 489, 999, 999,
|
||||
999, 999, 979, 411,
|
||||
999, 456, 999, 999,
|
||||
999, 999, 470, 470,
|
||||
470, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 39, 832,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
147, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 753, 984, 981,
|
||||
843, 999, 999, 808,
|
||||
804, 990, 999, 128,
|
||||
999, 70, 999, 104,
|
||||
999, 998, 991, 999,
|
||||
999, 999, 479, 479,
|
||||
999, 999, 999, 995,
|
||||
999, 999, 175, 188,
|
||||
216, 999, 999, 999,
|
||||
330, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 631,
|
||||
631, 631, 631, 631,
|
||||
631, 999, 999, 999,
|
||||
988, 686, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 983,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 325, 999
|
||||
};
|
||||
|
||||
static constexpr int16 axeHandleTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 984, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
199, 489, 999, 999,
|
||||
999, 999, 979, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 832,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 753, 999, 981,
|
||||
832, 999, 999, 808,
|
||||
804, 990, 999, 126,
|
||||
999, 68, 999, 102,
|
||||
999, 998, 380, 999,
|
||||
999, 999, 479, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 186,
|
||||
999, 999, 999, 999,
|
||||
333, 999, 999, 999,
|
||||
999, 529, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 629,
|
||||
629, 629, 629, 629,
|
||||
629, 999, 999, 999,
|
||||
988, 686, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 983,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 993, 999
|
||||
};
|
||||
|
||||
static constexpr int16 ropeTextTbl[199] = {
|
||||
0, 0, 0, 0,
|
||||
0, 0, 0, 999,
|
||||
0, 999, 0, 523,
|
||||
0, 0, 999, 0,
|
||||
793, 999, 0, 999,
|
||||
0, 0, 999, 0,
|
||||
0, 999, 699, 0,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 0, 0, 0,
|
||||
999, 0, 999, 45,
|
||||
0, 0, 0, 0,
|
||||
195, 485, 0, 999,
|
||||
0, 999, 847, 410,
|
||||
0, 454, 999, 0,
|
||||
0, 0, 469, 469,
|
||||
469, 0, 0, 987,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 999, 831,
|
||||
999, 0, 0, 0,
|
||||
0, 0, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 0,
|
||||
144, 986, 0, 358,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 990,
|
||||
996, 753, 999, 981,
|
||||
840, 999, 0, 808,
|
||||
804, 990, 450, 121,
|
||||
261, 63, 81, 92,
|
||||
121, 998, 378, 400,
|
||||
999, 999, 999, 999,
|
||||
0, 297, 0, 999,
|
||||
999, 0, 999, 184,
|
||||
214, 221, 999, 999,
|
||||
999, 339, 339, 358,
|
||||
999, 528, 999, 0,
|
||||
549, 0, 999, 577,
|
||||
999, 617, 999, 626,
|
||||
0, 0, 0, 0,
|
||||
0, 0, 675, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 0, 761,
|
||||
767, 999, 999, 999,
|
||||
980, 982, 0, 0,
|
||||
0, 0, 0, 999,
|
||||
999, 0, 989, 999,
|
||||
999, 999, 0
|
||||
};
|
||||
|
||||
static constexpr int16 microFilmTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
870, 999, 999, 999,
|
||||
999, 999, 999, 774,
|
||||
999, 999, 999, 999,
|
||||
999, 455, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
0, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
152, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 0, 999, 981,
|
||||
999, 999, 999, 999,
|
||||
804, 990, 999, 999,
|
||||
999, 71, 999, 999,
|
||||
105, 998, 991, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
335, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
980, 982, 999, 999,
|
||||
864, 999, 999, 999,
|
||||
999, 999, 989, 999,
|
||||
999, 993, 999
|
||||
};
|
||||
|
||||
static constexpr int16 specialHammerTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 757, 999, 999,
|
||||
999, 999, 999, 55,
|
||||
999, 999, 999, 999,
|
||||
203, 489, 999, 999,
|
||||
999, 999, 979, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 987,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 832,
|
||||
558, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 986, 999, 363,
|
||||
999, 999, 999, 999,
|
||||
387, 992, 392, 999,
|
||||
996, 753, 984, 904,
|
||||
999, 999, 999, 808,
|
||||
805, 990, 999, 130,
|
||||
999, 72, 999, 107,
|
||||
999, 998, 991, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 0, 999, 999,
|
||||
999, 999, 176, 999,
|
||||
216, 999, 999, 999,
|
||||
330, 344, 351, 999,
|
||||
999, 999, 999, 999,
|
||||
550, 999, 999, 577,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 762,
|
||||
999, 999, 999, 983,
|
||||
980, 982, 999, 999,
|
||||
999, 999, 999, 889,
|
||||
999, 999, 989, 999,
|
||||
999, 324, 999
|
||||
};
|
||||
|
||||
static constexpr int16 gunTextTbl[199] = {
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
999, 999, 19, 999,
|
||||
19, 19, 999, 19,
|
||||
19, 999, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 999,
|
||||
19, 19, 19, 19,
|
||||
19, 757, 19, 19,
|
||||
999, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 485, 19, 999,
|
||||
540, 999, 848, 19,
|
||||
19, 19, 999, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 987,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 999, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 986, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
350, 992, 392, 999,
|
||||
996, 753, 19, 19,
|
||||
19, 999, 999, 19,
|
||||
19, 990, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 998, 991, 19,
|
||||
19, 999, 999, 19,
|
||||
19, 19, 19, 999,
|
||||
19, 19, 19, 19,
|
||||
19, 999, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 577,
|
||||
19, 618, 622, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 999,
|
||||
19, 685, 999, 999,
|
||||
999, 999, 19, 19,
|
||||
19, 19, 999, 19,
|
||||
19, 19, 19, 19,
|
||||
19, 19, 19, 999,
|
||||
999, 19, 497, 999,
|
||||
999, 19, 19
|
||||
};
|
||||
|
||||
static constexpr int16 watchTextTbl[199] = {
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 59,
|
||||
873, 999, 999, 999,
|
||||
210, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
160, 986, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
386, 992, 392, 999,
|
||||
996, 999, 999, 981,
|
||||
999, 999, 999, 999,
|
||||
804, 990, 999, 134,
|
||||
27, 75, 87, 115,
|
||||
134, 998, 991, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 191,
|
||||
999, 228, 932, 318,
|
||||
999, 999, 999, 368,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 577,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
988, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
980, 982, 999, 999,
|
||||
866, 999, 999, 999,
|
||||
999, 999, 999, 999,
|
||||
999, 993, 998
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_USECODE_TOS_TABLES_H
|
||||
133
engines/darkseed/zhmenufont.cpp
Normal file
133
engines/darkseed/zhmenufont.cpp
Normal file
@@ -0,0 +1,133 @@
|
||||
/* 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 "darkseed/darkseed.h"
|
||||
#include "darkseed/zhmenufont.h"
|
||||
|
||||
#include "graphics/fonts/dosfont.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
ZhMenuFont::ZhMenuFont(const Common::Path &filename, ZhLargeFontType type) : _type(type) {
|
||||
load(filename);
|
||||
}
|
||||
|
||||
void ZhMenuFont::load(const Common::Path &filename) {
|
||||
Common::File fontData;
|
||||
if (!fontData.open(filename)) {
|
||||
error("Error: failed to open zhmenufont_game.dat");
|
||||
}
|
||||
int numGlyphs = fontData.size()/74;
|
||||
_glyphs.resize(numGlyphs);
|
||||
|
||||
for (int i = 0; i < numGlyphs; i++) {
|
||||
_glyphs[i].charIdx = fontData.readUint16BE();
|
||||
fontData.read(_glyphs[i].pixels, 72);
|
||||
}
|
||||
|
||||
fontData.close();
|
||||
}
|
||||
|
||||
const ZhLargeFontGlyph *ZhMenuFont::getGlyph(uint32 chr) const {
|
||||
for (auto &glyph : _glyphs) {
|
||||
if (glyph.charIdx == chr) {
|
||||
return &glyph;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
int ZhMenuFont::getFontHeight() const {
|
||||
return 24;
|
||||
}
|
||||
|
||||
int ZhMenuFont::getMaxCharWidth() const {
|
||||
return 24;
|
||||
}
|
||||
|
||||
int ZhMenuFont::getCharWidth(uint32 chr) const {
|
||||
auto glyph = getGlyph(chr);
|
||||
return glyph ? getMaxCharWidth() : 8;
|
||||
}
|
||||
|
||||
void ZhMenuFont::drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const {
|
||||
auto glyph = getGlyph(chr);
|
||||
if (glyph) {
|
||||
if (_type == ZhLargeFontType::InGame) {
|
||||
drawGlyph(glyph, x, y, color);
|
||||
} else {
|
||||
drawGlyph(glyph, x-1, y, 0);
|
||||
drawGlyph(glyph, x, y+1, 0);
|
||||
drawGlyph(glyph, x-1, y+1, 0);
|
||||
drawGlyph(glyph, x, y, 0xd);
|
||||
}
|
||||
} else if (chr < 128) {
|
||||
drawBiosFontGlyph(chr, x, y, 0);
|
||||
drawBiosFontGlyph(chr, x+1, y, 0xd);
|
||||
}
|
||||
}
|
||||
|
||||
void ZhMenuFont::drawBiosFontGlyph(uint8 chr, int x, int y, uint8 color) const {
|
||||
byte *ptr = (byte *)g_engine->_screen->getBasePtr(x, y);
|
||||
int srcPixel = chr * 8;
|
||||
int colorOffset = 1;
|
||||
for (int sy = 0; sy < 8; sy++) {
|
||||
for (int sx = 0; sx < 8; sx++) {
|
||||
if (Graphics::DosFont::fontData_PCBIOS[srcPixel] & 1 << (7 - sx)) {
|
||||
*ptr = color;
|
||||
ptr[g_engine->_screen->pitch] = color;
|
||||
ptr[g_engine->_screen->pitch * 2] = color;
|
||||
color += colorOffset;
|
||||
colorOffset = -colorOffset;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
srcPixel++;
|
||||
ptr -= 8;
|
||||
ptr += (g_engine->_screen->pitch * 3);
|
||||
}
|
||||
}
|
||||
|
||||
void ZhMenuFont::drawGlyph(const ZhLargeFontGlyph *glyph, int x, int y, uint8 color) const {
|
||||
byte *ptr = (byte *)g_engine->_screen->getBasePtr(x, y);
|
||||
int srcPixel = 0;
|
||||
int sByteOffset = 0;
|
||||
int colorOffset = _type == ZhLargeFontType::InGame ? 0 : 1;
|
||||
for (int sy = 0; sy < getFontHeight(); sy++) {
|
||||
for (int sx = 0; sx < getMaxCharWidth(); sx++) {
|
||||
if (glyph->pixels[srcPixel] & 1 << (7 - sByteOffset)) {
|
||||
*ptr = (uint8)color;
|
||||
color += colorOffset;
|
||||
colorOffset = -colorOffset;
|
||||
}
|
||||
sByteOffset++;
|
||||
if (sByteOffset == 8) {
|
||||
sByteOffset = 0;
|
||||
srcPixel++;
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
ptr -= getMaxCharWidth();
|
||||
ptr += g_engine->_screen->pitch;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace Darkseed
|
||||
63
engines/darkseed/zhmenufont.h
Normal file
63
engines/darkseed/zhmenufont.h
Normal file
@@ -0,0 +1,63 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef DARKSEED_ZHMENUFONT_H
|
||||
#define DARKSEED_ZHMENUFONT_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/surface.h"
|
||||
|
||||
namespace Darkseed {
|
||||
|
||||
struct ZhLargeFontGlyph {
|
||||
uint16 charIdx;
|
||||
uint8 pixels[72]; // 24x24 pixels @ 1bpp
|
||||
};
|
||||
|
||||
enum class ZhLargeFontType {
|
||||
InGame,
|
||||
Titles
|
||||
};
|
||||
|
||||
class ZhMenuFont : public Graphics::Font {
|
||||
private:
|
||||
ZhLargeFontType _type = ZhLargeFontType::InGame;
|
||||
Common::Array<ZhLargeFontGlyph> _glyphs;
|
||||
|
||||
public:
|
||||
ZhMenuFont(const Common::Path &filename, ZhLargeFontType type);
|
||||
|
||||
int getFontHeight() const override;
|
||||
int getMaxCharWidth() const override;
|
||||
int getCharWidth(uint32 chr) const override;
|
||||
void drawChar(Graphics::Surface *dst, uint32 chr, int x, int y, uint32 color) const override;
|
||||
|
||||
private:
|
||||
void load(const Common::Path &filename);
|
||||
const ZhLargeFontGlyph *getGlyph(uint32 chr) const;
|
||||
void drawBiosFontGlyph(uint8 chr, int x, int y, uint8 color) const;
|
||||
void drawGlyph(const ZhLargeFontGlyph *glyph, int x, int y, uint8 color) const;
|
||||
};
|
||||
|
||||
} // namespace Darkseed
|
||||
|
||||
#endif // DARKSEED_ZHMENUFONT_H
|
||||
Reference in New Issue
Block a user