Merge branch 'master' into zvision

This commit is contained in:
RichieSams 2013-09-29 18:04:53 -05:00
commit 49d67caa31
176 changed files with 6909 additions and 5963 deletions

3
NEWS
View File

@ -2,6 +2,9 @@ For a more comprehensive changelog of the latest experimental code, see:
https://github.com/scummvm/scummvm/commits/
1.7.0 (????-??-??)
General:
- Updated MT-32 emulation code to version 1.3.0.
Gob:
- Improved video quality in Urban Runner

View File

@ -44,7 +44,8 @@ _centerPitchWheelOnUnload(false),
_sendSustainOffOnNotesOff(false),
_numTracks(0),
_activeTrack(255),
_abortParse(0) {
_abortParse(false),
_jumpingToTick(false) {
memset(_activeNotes, 0, sizeof(_activeNotes));
memset(_tracks, 0, sizeof(_tracks));
_nextEvent.start = NULL;
@ -204,49 +205,22 @@ void MidiParser::onTimer() {
return;
}
if (info.event == 0xF0) {
// SysEx event
// Check for trailing 0xF7 -- if present, remove it.
if (info.ext.data[info.length-1] == 0xF7)
_driver->sysEx(info.ext.data, (uint16)info.length-1);
if (info.command() == 0x8) {
activeNote(info.channel(), info.basic.param1, false);
} else if (info.command() == 0x9) {
if (info.length > 0)
hangingNote(info.channel(), info.basic.param1, info.length * _psecPerTick - (endTime - eventTime));
else
_driver->sysEx(info.ext.data, (uint16)info.length);
} else if (info.event == 0xFF) {
// META event
if (info.ext.type == 0x2F) {
// End of Track must be processed by us,
// as well as sending it to the output device.
if (_autoLoop) {
jumpToTick(0);
parseNextEvent(_nextEvent);
} else {
stopPlaying();
_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
}
return;
} else if (info.ext.type == 0x51) {
if (info.length >= 3) {
setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
}
}
_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
} else {
if (info.command() == 0x8) {
activeNote(info.channel(), info.basic.param1, false);
} else if (info.command() == 0x9) {
if (info.length > 0)
hangingNote(info.channel(), info.basic.param1, info.length * _psecPerTick - (endTime - eventTime));
else
activeNote(info.channel(), info.basic.param1, true);
}
sendToDriver(info.event, info.basic.param1, info.basic.param2);
activeNote(info.channel(), info.basic.param1, true);
}
processEvent(info);
if (!_abortParse) {
_position._lastEventTime = eventTime;
parseNextEvent(_nextEvent);
}
if (_abortParse)
break;
_position._lastEventTime = eventTime;
parseNextEvent(_nextEvent);
}
if (!_abortParse) {
@ -255,6 +229,45 @@ void MidiParser::onTimer() {
}
}
void MidiParser::processEvent(const EventInfo &info, bool fireEvents) {
if (info.event == 0xF0) {
// SysEx event
// Check for trailing 0xF7 -- if present, remove it.
if (fireEvents) {
if (info.ext.data[info.length-1] == 0xF7)
_driver->sysEx(info.ext.data, (uint16)info.length-1);
else
_driver->sysEx(info.ext.data, (uint16)info.length);
}
} else if (info.event == 0xFF) {
// META event
if (info.ext.type == 0x2F) {
// End of Track must be processed by us,
// as well as sending it to the output device.
if (_autoLoop) {
jumpToTick(0);
parseNextEvent(_nextEvent);
} else {
stopPlaying();
if (fireEvents)
_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
}
_abortParse = true;
return;
} else if (info.ext.type == 0x51) {
if (info.length >= 3) {
setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
}
}
if (fireEvents)
_driver->metaEvent(info.ext.type, info.ext.data, (uint16)info.length);
} else {
if (fireEvents)
sendToDriver(info.event, info.basic.param1, info.basic.param2);
}
}
void MidiParser::allNotesOff() {
if (!_driver)
return;
@ -370,6 +383,9 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d
if (_activeTrack >= _numTracks)
return false;
assert(!_jumpingToTick); // This function is not re-entrant
_jumpingToTick = true;
Tracker currentPos(_position);
EventInfo currentEvent(_nextEvent);
@ -390,34 +406,19 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d
_position._playTick = _position._lastEventTick;
_position._playTime = _position._lastEventTime;
if (info.event == 0xFF) {
if (info.ext.type == 0x2F) { // End of track
_position = currentPos;
_nextEvent = currentEvent;
return false;
} else {
if (info.ext.type == 0x51 && info.length >= 3) // Tempo
setTempo(info.ext.data[0] << 16 | info.ext.data[1] << 8 | info.ext.data[2]);
if (fireEvents)
_driver->metaEvent(info.ext.type, info.ext.data, (uint16) info.length);
}
} else if (fireEvents) {
if (info.event == 0xF0) {
if (info.ext.data[info.length-1] == 0xF7)
_driver->sysEx(info.ext.data, (uint16)info.length-1);
else
_driver->sysEx(info.ext.data, (uint16)info.length);
} else {
// The note on sending code is used by the SCUMM engine. Other engine using this code
// (such as SCI) have issues with this, as all the notes sent can be heard when a song
// is fast-forwarded. Thus, if the engine requests it, don't send note on events.
if (info.command() == 0x9 && dontSendNoteOn) {
// Don't send note on; doing so creates a "warble" with some instruments on the MT-32.
// Refer to patch #3117577
} else {
sendToDriver(info.event, info.basic.param1, info.basic.param2);
}
}
// Some special processing for the fast-forward case
if (info.command() == 0x9 && dontSendNoteOn) {
// Don't send note on; doing so creates a "warble" with
// some instruments on the MT-32. Refer to patch #3117577
} else if (info.event == 0xFF && info.ext.type == 0x2F) {
// End of track
// This means that we failed to find the right tick.
_position = currentPos;
_nextEvent = currentEvent;
_jumpingToTick = false;
return false;
} else {
processEvent(info, fireEvents);
}
parseNextEvent(_nextEvent);
@ -441,6 +442,7 @@ bool MidiParser::jumpToTick(uint32 tick, bool fireEvents, bool stopNotes, bool d
}
_abortParse = true;
_jumpingToTick = false;
return true;
}

View File

@ -105,8 +105,8 @@ struct EventInfo {
///< will occur, and the MidiParser will have to generate one itself.
///< For all other events, this value should always be zero.
byte channel() { return event & 0x0F; } ///< Separates the MIDI channel from the event.
byte command() { return event >> 4; } ///< Separates the command code from the event.
byte channel() const { return event & 0x0F; } ///< Separates the MIDI channel from the event.
byte command() const { return event >> 4; } ///< Separates the command code from the event.
};
/**
@ -287,12 +287,14 @@ protected:
///< so each event is parsed only once; this permits
///< simulated events in certain formats.
bool _abortParse; ///< If a jump or other operation interrupts parsing, flag to abort.
bool _jumpingToTick; ///< True if currently inside jumpToTick
protected:
static uint32 readVLQ(byte * &data);
virtual void resetTracking();
virtual void allNotesOff();
virtual void parseNextEvent(EventInfo &info) = 0;
virtual void processEvent(const EventInfo &info, bool fireEvents = true);
void activeNote(byte channel, byte note, bool active);
void hangingNote(byte channel, byte note, uint32 ticksLeft, bool recycle = true);

View File

@ -315,15 +315,29 @@ void LA32PartialPair::generateNextSample(const PairType useMaster, const Bit32u
}
}
float LA32PartialPair::nextOutSample() {
float outputSample;
if (ringModulated) {
float ringModulatedSample = masterOutputSample * slaveOutputSample;
outputSample = mixed ? masterOutputSample + ringModulatedSample : ringModulatedSample;
} else {
outputSample = masterOutputSample + slaveOutputSample;
static inline float produceDistortedSample(float sample) {
if (sample < -1.0f) {
return sample + 2.0f;
} else if (1.0f < sample) {
return sample - 2.0f;
}
return outputSample;
return sample;
}
float LA32PartialPair::nextOutSample() {
if (!ringModulated) {
return masterOutputSample + slaveOutputSample;
}
/*
* SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion.
* LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191.
* This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case.
* As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space,
* it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication.
* Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning.
*/
float ringModulatedSample = produceDistortedSample(masterOutputSample) * produceDistortedSample(slaveOutputSample);
return mixed ? masterOutputSample + ringModulatedSample : ringModulatedSample;
}
void LA32PartialPair::deactivate(const PairType useMaster) {

View File

@ -370,18 +370,12 @@ void LA32PartialPair::generateNextSample(const PairType useMaster, const Bit32u
}
}
Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg, const LogSample * const ringModulatingLogSample) {
if (!wg.isActive() || ((ringModulatingLogSample != NULL) && (ringModulatingLogSample->logValue == SILENCE.logValue))) {
Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg) {
if (!wg.isActive()) {
return 0;
}
LogSample firstLogSample = wg.getOutputLogSample(true);
LogSample secondLogSample = wg.getOutputLogSample(false);
if (ringModulatingLogSample != NULL) {
LA32Utilites::addLogSamples(firstLogSample, *ringModulatingLogSample);
LA32Utilites::addLogSamples(secondLogSample, *ringModulatingLogSample);
}
Bit16s firstSample = LA32Utilites::unlog(firstLogSample);
Bit16s secondSample = LA32Utilites::unlog(secondLogSample);
Bit16s firstSample = LA32Utilites::unlog(wg.getOutputLogSample(true));
Bit16s secondSample = LA32Utilites::unlog(wg.getOutputLogSample(false));
if (wg.isPCMWave()) {
return Bit16s(firstSample + ((Bit32s(secondSample - firstSample) * wg.getPCMInterpolationFactor()) >> 7));
}
@ -389,19 +383,32 @@ Bit16s LA32PartialPair::unlogAndMixWGOutput(const LA32WaveGenerator &wg, const L
}
Bit16s LA32PartialPair::nextOutSample() {
if (ringModulated) {
LogSample slaveFirstLogSample = slave.getOutputLogSample(true);
LogSample slaveSecondLogSample = slave.getOutputLogSample(false);
Bit16s sample = unlogAndMixWGOutput(master, &slaveFirstLogSample);
if (!slave.isPCMWave()) {
sample += unlogAndMixWGOutput(master, &slaveSecondLogSample);
}
if (mixed) {
sample += unlogAndMixWGOutput(master, NULL);
}
return sample;
if (!ringModulated) {
return unlogAndMixWGOutput(master) + unlogAndMixWGOutput(slave);
}
return unlogAndMixWGOutput(master, NULL) + unlogAndMixWGOutput(slave, NULL);
/*
* SEMI-CONFIRMED: Ring modulation model derived from sample analysis of specially constructed patches which exploit distortion.
* LA32 ring modulator found to produce distorted output in case if the absolute value of maximal amplitude of one of the input partials exceeds 8191.
* This is easy to reproduce using synth partials with resonance values close to the maximum. It looks like an integer overflow happens in this case.
* As the distortion is strictly bound to the amplitude of the complete mixed square + resonance wave in the linear space,
* it is reasonable to assume the ring modulation is performed also in the linear space by sample multiplication.
* Most probably the overflow is caused by limited precision of the multiplication circuit as the very similar distortion occurs with panning.
*/
Bit16s nonOverdrivenMasterSample = unlogAndMixWGOutput(master); // Store master partial sample for further mixing
Bit16s masterSample = nonOverdrivenMasterSample << 2;
masterSample >>= 2;
/* SEMI-CONFIRMED from sample analysis:
* We observe that for partial structures with ring modulation the interpolation is not applied to the slave PCM partial.
* It's assumed that the multiplication circuitry intended to perform the interpolation on the slave PCM partial
* is borrowed by the ring modulation circuit (or the LA32 chip has a similar lack of resources assigned to each partial pair).
*/
Bit16s slaveSample = slave.isPCMWave() ? LA32Utilites::unlog(slave.getOutputLogSample(true)) : unlogAndMixWGOutput(slave);
slaveSample <<= 2;
slaveSample >>= 2;
Bit16s ringModulatedSample = Bit16s(((Bit32s)masterSample * (Bit32s)slaveSample) >> 13);
return mixed ? nonOverdrivenMasterSample + ringModulatedSample : ringModulatedSample;
}
void LA32PartialPair::deactivate(const PairType useMaster) {

View File

@ -209,7 +209,7 @@ class LA32PartialPair {
bool ringModulated;
bool mixed;
static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg, const LogSample * const ringModulatingLogSample);
static Bit16s unlogAndMixWGOutput(const LA32WaveGenerator &wg);
public:
enum PairType {

View File

@ -24,15 +24,10 @@
namespace MT32Emu {
#ifdef INACCURATE_SMOOTH_PAN
// Mok wanted an option for smoother panning, and we love Mok.
static const float PAN_NUMERATOR_NORMAL[] = {0.0f, 0.5f, 1.0f, 1.5f, 2.0f, 2.5f, 3.0f, 3.5f, 4.0f, 4.5f, 5.0f, 5.5f, 6.0f, 6.5f, 7.0f};
#else
// CONFIRMED by Mok: These NUMERATOR values (as bytes, not floats, obviously) are sent exactly like this to the LA32.
static const float PAN_NUMERATOR_NORMAL[] = {0.0f, 0.0f, 1.0f, 1.0f, 2.0f, 2.0f, 3.0f, 3.0f, 4.0f, 4.0f, 5.0f, 5.0f, 6.0f, 6.0f, 7.0f};
#endif
static const float PAN_NUMERATOR_MASTER[] = {0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f};
static const float PAN_NUMERATOR_SLAVE[] = {0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f, 7.0f};
static const Bit8u PAN_NUMERATOR_MASTER[] = {0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7};
static const Bit8u PAN_NUMERATOR_SLAVE[] = {0, 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7, 7};
static const Bit32s PAN_FACTORS[] = {0, 18, 37, 55, 73, 91, 110, 128, 146, 165, 183, 201, 219, 238, 256};
Partial::Partial(Synth *useSynth, int useDebugPartialNum) :
synth(useSynth), debugPartialNum(useDebugPartialNum), sampleNum(0) {
@ -116,24 +111,30 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
structurePosition = patchCache->structurePosition;
Bit8u panSetting = rhythmTemp != NULL ? rhythmTemp->panpot : part->getPatchTemp()->panpot;
float panVal;
if (mixType == 3) {
if (structurePosition == 0) {
panVal = PAN_NUMERATOR_MASTER[panSetting];
panSetting = PAN_NUMERATOR_MASTER[panSetting] << 1;
} else {
panVal = PAN_NUMERATOR_SLAVE[panSetting];
panSetting = PAN_NUMERATOR_SLAVE[panSetting] << 1;
}
// Do a normal mix independent of any pair partial.
mixType = 0;
pairPartial = NULL;
} else {
panVal = PAN_NUMERATOR_NORMAL[panSetting];
// Mok wanted an option for smoother panning, and we love Mok.
#ifndef INACCURATE_SMOOTH_PAN
// CONFIRMED by Mok: exactly bytes like this (right shifted?) are sent to the LA32.
panSetting &= 0x0E;
#endif
}
// FIXME: Sample analysis suggests that the use of panVal is linear, but there are some some quirks that still need to be resolved.
// FIXME: I suppose this should be panVal / 8 and undoubtly integer, clarify ASAP
stereoVolume.leftVol = panVal / 7.0f;
stereoVolume.rightVol = 1.0f - stereoVolume.leftVol;
leftPanValue = synth->reversedStereoEnabled ? 14 - panSetting : panSetting;
rightPanValue = 14 - leftPanValue;
#if !MT32EMU_USE_FLOAT_SAMPLES
leftPanValue = PAN_FACTORS[leftPanValue];
rightPanValue = PAN_FACTORS[rightPanValue];
#endif
// SEMI-CONFIRMED: From sample analysis:
// Found that timbres with 3 or 4 partials (i.e. one using two partial pairs) are mixed in two different ways.
@ -150,8 +151,8 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us
// For my personal taste, this behaviour rather enriches the sounding and should be emulated.
// Also, the current partial allocator model probably needs to be refined.
if (debugPartialNum & 8) {
stereoVolume.leftVol = -stereoVolume.leftVol;
stereoVolume.rightVol = -stereoVolume.rightVol;
leftPanValue = -leftPanValue;
rightPanValue = -rightPanValue;
}
if (patchCache->PCMPartial) {
@ -230,39 +231,6 @@ Bit32u Partial::getCutoffValue() {
return (tvf->getBaseCutoff() << 18) + cutoffModifierRampVal;
}
unsigned long Partial::generateSamples(Sample *partialBuf, unsigned long length) {
if (!isActive() || alreadyOutputed) {
return 0;
}
if (poly == NULL) {
synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::generateSamples()!", debugPartialNum);
return 0;
}
alreadyOutputed = true;
for (sampleNum = 0; sampleNum < length; sampleNum++) {
if (!tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::MASTER)) {
deactivate();
break;
}
la32Pair.generateNextSample(LA32PartialPair::MASTER, getAmpValue(), tvp->nextPitch(), getCutoffValue());
if (hasRingModulatingSlave()) {
la32Pair.generateNextSample(LA32PartialPair::SLAVE, pair->getAmpValue(), pair->tvp->nextPitch(), pair->getCutoffValue());
if (!pair->tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::SLAVE)) {
pair->deactivate();
if (mixType == 2) {
deactivate();
break;
}
}
}
*(partialBuf++) = la32Pair.nextOutSample();
}
unsigned long renderedSamples = sampleNum;
sampleNum = 0;
return renderedSamples;
}
bool Partial::hasRingModulatingSlave() const {
return pair != NULL && structurePosition == 0 && (mixType == 1 || mixType == 2);
}
@ -305,19 +273,52 @@ bool Partial::produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long len
synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", debugPartialNum);
return false;
}
Sample buffer[MAX_SAMPLES_PER_RUN];
unsigned long numGenerated = generateSamples(buffer, length);
for (unsigned int i = 0; i < numGenerated; i++) {
alreadyOutputed = true;
for (sampleNum = 0; sampleNum < length; sampleNum++) {
if (!tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::MASTER)) {
deactivate();
break;
}
la32Pair.generateNextSample(LA32PartialPair::MASTER, getAmpValue(), tvp->nextPitch(), getCutoffValue());
if (hasRingModulatingSlave()) {
la32Pair.generateNextSample(LA32PartialPair::SLAVE, pair->getAmpValue(), pair->tvp->nextPitch(), pair->getCutoffValue());
if (!pair->tva->isPlaying() || !la32Pair.isActive(LA32PartialPair::SLAVE)) {
pair->deactivate();
if (mixType == 2) {
deactivate();
break;
}
}
}
// Although, LA32 applies panning itself, we assume here it is applied in the mixer, not within a pair.
// Applying the pan value in the log-space looks like a waste of unlog resources. Though, it needs clarification.
Sample sample = la32Pair.nextOutSample();
// FIXME: Sample analysis suggests that the use of panVal is linear, but there are some quirks that still need to be resolved.
#if MT32EMU_USE_FLOAT_SAMPLES
*(leftBuf++) += buffer[i] * stereoVolume.leftVol;
*(rightBuf++) += buffer[i] * stereoVolume.rightVol;
Sample leftOut = (sample * (float)leftPanValue) / 14.0f;
Sample rightOut = (sample * (float)rightPanValue) / 14.0f;
*(leftBuf++) += leftOut;
*(rightBuf++) += rightOut;
#else
*leftBuf = Synth::clipBit16s((Bit32s)*leftBuf + Bit32s(buffer[i] * stereoVolume.leftVol));
*rightBuf = Synth::clipBit16s((Bit32s)*rightBuf + Bit32s(buffer[i] * stereoVolume.rightVol));
// FIXME: Dividing by 7 (or by 14 in a Mok-friendly way) looks of course pointless. Need clarification.
// FIXME2: LA32 may produce distorted sound in case if the absolute value of maximal amplitude of the input exceeds 8191
// when the panning value is non-zero. Most probably the distortion occurs in the same way it does with ring modulation,
// and it seems to be caused by limited precision of the common multiplication circuit.
// From analysis of this overflow, it is obvious that the right channel output is actually found
// by subtraction of the left channel output from the input.
// Though, it is unknown whether this overflow is exploited somewhere.
Sample leftOut = Sample((sample * leftPanValue) >> 8);
Sample rightOut = Sample((sample * rightPanValue) >> 8);
*leftBuf = Synth::clipBit16s((Bit32s)*leftBuf + (Bit32s)leftOut);
*rightBuf = Synth::clipBit16s((Bit32s)*rightBuf + (Bit32s)rightOut);
leftBuf++;
rightBuf++;
#endif
}
sampleNum = 0;
return true;
}

View File

@ -25,24 +25,22 @@ class Part;
class TVA;
struct ControlROMPCMStruct;
struct StereoVolume {
float leftVol;
float rightVol;
};
// A partial represents one of up to four waveform generators currently playing within a poly.
class Partial {
private:
Synth *synth;
const int debugPartialNum; // Only used for debugging
// Number of the sample currently being rendered by generateSamples(), or 0 if no run is in progress
// Number of the sample currently being rendered by produceOutput(), or 0 if no run is in progress
// This is only kept available for debugging purposes.
unsigned long sampleNum;
// Actually, this is a 4-bit register but we abuse this to emulate inverted mixing.
// Also we double the value to enable INACCURATE_SMOOTH_PAN, with respect to MoK.
Bit32s leftPanValue, rightPanValue;
int ownerPart; // -1 if unassigned
int mixType;
int structurePosition; // 0 or 1 of a structure pair
StereoVolume stereoVolume;
// Only used for PCM partials
int pcmNum;
@ -103,9 +101,6 @@ public:
// This function (unlike the one below it) returns processed stereo samples
// made from combining this single partial with its pair, if it has one.
bool produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long length);
// This function writes mono sample output to the provided buffer, and returns the number of samples written
unsigned long generateSamples(Sample *partialBuf, unsigned long length);
};
}

View File

@ -76,6 +76,7 @@ Synth::Synth(ReportHandler *useReportHandler) {
isOpen = false;
reverbEnabled = true;
reverbOverridden = false;
partialCount = DEFAULT_MAX_PARTIALS;
if (useReportHandler == NULL) {
reportHandler = new ReportHandler;
@ -95,6 +96,7 @@ Synth::Synth(ReportHandler *useReportHandler) {
setMIDIDelayMode(MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY);
setOutputGain(1.0f);
setReverbOutputGain(1.0f);
setReversedStereoEnabled(false);
partialManager = NULL;
midiQueue = NULL;
lastReceivedMIDIEventTimestamp = 0;
@ -172,6 +174,8 @@ MIDIDelayMode Synth::getMIDIDelayMode() const {
return midiDelayMode;
}
#if MT32EMU_USE_FLOAT_SAMPLES
void Synth::setOutputGain(float newOutputGain) {
outputGain = newOutputGain;
}
@ -188,6 +192,39 @@ float Synth::getReverbOutputGain() const {
return reverbOutputGain;
}
#else // #if MT32EMU_USE_FLOAT_SAMPLES
void Synth::setOutputGain(float newOutputGain) {
if (newOutputGain < 0.0f) newOutputGain = -newOutputGain;
if (256.0f < newOutputGain) newOutputGain = 256.0f;
outputGain = int(newOutputGain * 256.0f);
}
float Synth::getOutputGain() const {
return outputGain / 256.0f;
}
void Synth::setReverbOutputGain(float newReverbOutputGain) {
if (newReverbOutputGain < 0.0f) newReverbOutputGain = -newReverbOutputGain;
float maxValue = 256.0f / CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR;
if (maxValue < newReverbOutputGain) newReverbOutputGain = maxValue;
reverbOutputGain = int(newReverbOutputGain * 256.0f);
}
float Synth::getReverbOutputGain() const {
return reverbOutputGain / 256.0f;
}
#endif // #if MT32EMU_USE_FLOAT_SAMPLES
void Synth::setReversedStereoEnabled(bool enabled) {
reversedStereoEnabled = enabled;
}
bool Synth::isReversedStereoEnabled() {
return reversedStereoEnabled;
}
bool Synth::loadControlROM(const ROMImage &controlROMImage) {
if (&controlROMImage == NULL) return false;
Common::File *file = controlROMImage.getFile();
@ -1445,16 +1482,19 @@ void Synth::convertSamplesToOutput(Sample *target, const Sample *source, Bit32u
*(target++) = *(source++) * gain;
}
#else
float gain = reverb ? reverbOutputGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR : outputGain;
if (!reverb) {
int gain;
if (reverb) {
gain = int(reverbOutputGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR);
} else {
gain = outputGain;
switch (dacInputMode) {
case DACInputMode_NICE:
// Since we're not shooting for accuracy here, don't worry about the rounding mode.
gain *= 2.0f;
gain <<= 1;
break;
case DACInputMode_GENERATION1:
while (len--) {
*target = clipBit16s(Bit32s(*source * gain));
*target = clipBit16s(Bit32s((*source * gain) >> 8));
*target = (*target & 0x8000) | ((*target << 1) & 0x7FFE);
source++;
target++;
@ -1462,7 +1502,7 @@ void Synth::convertSamplesToOutput(Sample *target, const Sample *source, Bit32u
return;
case DACInputMode_GENERATION2:
while (len--) {
*target = clipBit16s(Bit32s(*source * gain));
*target = clipBit16s(Bit32s((*source * gain) >> 8));
*target = (*target & 0x8000) | ((*target << 1) & 0x7FFE) | ((*target >> 14) & 0x0001);
source++;
target++;
@ -1473,7 +1513,7 @@ void Synth::convertSamplesToOutput(Sample *target, const Sample *source, Bit32u
}
}
while (len--) {
*(target++) = clipBit16s(Bit32s(*(source++) * gain));
*(target++) = clipBit16s(Bit32s((*(source++) * gain) >> 8));
}
#endif
}

View File

@ -343,8 +343,16 @@ private:
MIDIDelayMode midiDelayMode;
DACInputMode dacInputMode;
#if MT32EMU_USE_FLOAT_SAMPLES
float outputGain;
float reverbOutputGain;
#else
int outputGain;
int reverbOutputGain;
#endif
bool reversedStereoEnabled;
bool isOpen;
@ -477,6 +485,9 @@ public:
void setReverbOutputGain(float);
float getReverbOutputGain() const;
void setReversedStereoEnabled(bool enabled);
bool isReversedStereoEnabled();
// Renders samples to the specified output stream.
// The length is in frames, not bytes (in 16-bit stereo,
// one frame is 4 bytes).

View File

@ -54,6 +54,8 @@ DefaultEventManager::DefaultEventManager(Common::EventSource *boss) :
_currentKeyDown.ascii = 0;
_currentKeyDown.flags = 0;
_keyRepeatTime = 0;
#ifdef ENABLE_VKEYBD
_vk = new Common::VirtualKeyboard();
#endif

View File

@ -129,4 +129,12 @@ const char *gScummVMFeatures = ""
#ifdef USE_FREETYPE2
"FreeType2 "
#endif
#ifdef USE_JPEG
"JPEG "
#endif
#ifdef USE_PNG
"PNG "
#endif
;

View File

@ -128,7 +128,7 @@ public:
*/
#define CORO_BEGIN_CONTEXT \
struct CoroContextTag : Common::CoroBaseContext { \
CoroContextTag() : CoroBaseContext(SCUMMVM_CURRENT_FUNCTION) {} \
CoroContextTag() : CoroBaseContext(SCUMMVM_CURRENT_FUNCTION) { DUMMY = 0; } \
int DUMMY
/**
@ -146,6 +146,7 @@ public:
#define CORO_BEGIN_CODE(x) \
if (&coroParam == &Common::nullContext) assert(!Common::nullContext); \
if (!x) { coroParam = x = new CoroContextTag(); } \
x->DUMMY = 0; \
Common::CoroContextHolder tmpHolder(coroParam); \
switch (coroParam->_line) { case 0:;

View File

@ -371,12 +371,14 @@ bool DecompressorDCL::unpack(ReadStream *src, byte *dest, uint32 nPacked, uint32
debug(8, "\nCOPY(%d from %d)\n", val_length, val_distance);
if (val_length + _dwWrote > _szUnpacked) {
warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes", val_length);
warning("DCL-INFLATE Error: Write out of bounds while copying %d bytes (declared unpacked size is %d bytes, current is %d + %d bytes)",
val_length, _szUnpacked, _dwWrote, val_length);
return false;
}
if (_dwWrote < val_distance) {
warning("DCL-INFLATE Error: Attempt to copy from before beginning of input stream");
warning("DCL-INFLATE Error: Attempt to copy from before beginning of input stream (declared unpacked size is %d bytes, current is %d bytes)",
_szUnpacked, _dwWrote);
return false;
}

View File

@ -23,6 +23,10 @@
#ifndef COMMON_SCUMMSYS_H
#define COMMON_SCUMMSYS_H
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
// This is a convenience macro to test whether the compiler used is a GCC
// version, which is at least major.minor.
#define GCC_ATLEAST(major, minor) (defined(__GNUC__) && (__GNUC__ > (major) || (__GNUC__ == (major) && __GNUC_MINOR__ >= (minor))))

62
configure vendored
View File

@ -115,6 +115,7 @@ _timidity=auto
_zlib=auto
_mpeg2=auto
_sparkle=auto
_jpeg=auto
_png=auto
_theoradec=auto
_faad=auto
@ -166,7 +167,7 @@ _windres=windres
_stagingpath="staging"
_win32path="c:/scummvm"
_aos4path="Games:ScummVM"
_staticlibpath=/sw
_staticlibpath=
_sdlconfig=sdl-config
_freetypeconfig=freetype-config
_sdlpath="$PATH"
@ -188,6 +189,7 @@ add_feature faad "libfaad" "_faad"
add_feature flac "FLAC" "_flac"
add_feature freetype2 "FreeType2" "_freetype2"
add_feature mad "MAD" "_mad"
add_feature jpeg "JPEG" "_jpeg"
add_feature png "PNG" "_png"
add_feature theoradec "libtheoradec" "_theoradec"
add_feature vorbis "Vorbis file support" "_vorbis _tremor"
@ -936,6 +938,9 @@ Optional Libraries:
--with-opengl-prefix=DIR Prefix where OpenGL (ES) is installed (optional)
--disable-opengl disable OpenGL (ES) support [autodetect]
--with-jpeg-prefix=DIR Prefix where libjpeg is installed (optional)
--disable-jpeg disable JPEG decoder [autodetect]
--with-png-prefix=DIR Prefix where libpng is installed (optional)
--disable-png disable PNG decoder [autodetect]
@ -1015,6 +1020,8 @@ for ac_option in $@; do
--disable-nasm) _nasm=no ;;
--enable-mpeg2) _mpeg2=yes ;;
--disable-mpeg2) _mpeg2=no ;;
--disable-jpeg) _jpeg=no ;;
--enable-jpeg) _jpeg=yes ;;
--disable-png) _png=no ;;
--enable-png) _png=yes ;;
--disable-theoradec) _theoradec=no ;;
@ -1096,6 +1103,11 @@ for ac_option in $@; do
MAD_CFLAGS="-I$arg/include"
MAD_LIBS="-L$arg/lib"
;;
--with-jpeg-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
JPEG_CFLAGS="-I$arg/include"
JPEG_LIBS="-L$arg/lib"
;;
--with-png-prefix=*)
arg=`echo $ac_option | cut -d '=' -f 2`
PNG_CFLAGS="-I$arg/include"
@ -2103,6 +2115,24 @@ case $_host_os in
LDFLAGS="-L${macport_prefix}/lib $LDFLAGS"
CXXFLAGS="-I${macport_prefix}/include $CXXFLAGS"
if test -z "$_staticlibpath"; then
_staticlibpath=${macport_prefix}
echo "Set staticlib-prefix to ${_staticlibpath}"
fi
fi
# If _staticlibpath is not set yet try first /sw (fink) then /usr/local
# (the macports case is handled above).
if test -z "$_staticlibpath"; then
if test -d "/sw"; then
_staticlibpath=/sw
echo "Set staticlib-prefix to ${_staticlibpath}"
elif test -d "/usr/local"; then
_staticlibpath=/usr/local
echo "Set staticlib-prefix to ${_staticlibpath}"
else
echo "Could not determine prefix for static libraries"
fi
fi
;;
dreamcast)
@ -3338,6 +3368,32 @@ fi
define_in_config_h_if_yes "$_alsa" 'USE_ALSA'
echo "$_alsa"
#
# Check for libjpeg
#
echocheck "libjpeg >= v6b"
if test "$_jpeg" = auto ; then
_jpeg=no
cat > $TMPC << EOF
#include <stdio.h>
#include <jpeglib.h>
int main(void) {
#if JPEG_LIB_VERSION >= 62
#else
syntax error
#endif
return 0;
}
EOF
cc_check $JPEG_CFLAGS $JPEG_LIBS -ljpeg && _jpeg=yes
fi
if test "$_jpeg" = yes ; then
LIBS="$LIBS $JPEG_LIBS -ljpeg"
INCLUDES="$INCLUDES $JPEG_CFLAGS"
fi
define_in_config_if_yes "$_jpeg" 'USE_JPEG'
echo "$_jpeg"
#
# Check for PNG
#
@ -3354,10 +3410,10 @@ int main(void) {
return 0;
}
EOF
cc_check $PNG_CFLAGS $PNG_LIBS -lpng && _png=yes
cc_check $PNG_CFLAGS $PNG_LIBS -lpng -lz && _png=yes
fi
if test "$_png" = yes ; then
LIBS="$LIBS $PNG_LIBS -lpng"
LIBS="$LIBS $PNG_LIBS -lpng -lz"
INCLUDES="$INCLUDES $PNG_CFLAGS"
fi
define_in_config_if_yes "$_png" 'USE_PNG'

View File

@ -20,6 +20,10 @@
*
*/
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#include <fstream>
#include <string>
#include <stdio.h>

View File

@ -33,10 +33,6 @@
#undef main
#endif // main
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "common/endian.h"
#include "create_mortdat.h"
#include "enginetext.h"

View File

@ -30,8 +30,8 @@
#undef main
#endif // main
#include <vector>
#include "create_neverhood.h"
#include <vector>
#include "md5.h"
#include "tables.h"

View File

@ -64,6 +64,11 @@ std::string processLibraryName(std::string name) {
if (pos != std::string::npos)
return name.replace(pos, 7, "");
// Remove "-static" in lib name
pos = name.find("-static");
if (pos != std::string::npos)
return name.replace(pos, 7, "");
// Replace "zlib" by "libz"
if (name == "zlib")
return "libz";

View File

@ -845,6 +845,7 @@ const Feature s_features[] = {
{ "mpeg2", "USE_MPEG2", "libmpeg2", false, "MPEG-2 support" },
{ "theora", "USE_THEORADEC", "libtheora_static", true, "Theora decoding support" },
{"freetype", "USE_FREETYPE2", "freetype", true, "FreeType support" },
{ "jpeg", "USE_JPEG", "jpeg-static", true, "libjpeg support" },
// Feature flags
{ "bink", "USE_BINK", "", true, "Bink video support" },

View File

@ -23,6 +23,10 @@
#ifndef TOOLS_CREATE_PROJECT_H
#define TOOLS_CREATE_PROJECT_H
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#include <map>
#include <list>
#include <string>

View File

@ -22,6 +22,8 @@
* The generated files is used by ScummVM to propose translation of its GUI.
*/
#include "create_translations.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@ -34,7 +36,6 @@
#undef main
#endif // main
#include "create_translations.h"
#include "po_parser.h"
#include "cp_parser.h"

View File

@ -28,4 +28,8 @@ typedef unsigned short uint16;
typedef unsigned int uint32;
typedef signed short int16;
#ifndef __has_feature // Optional of course.
#define __has_feature(x) 0 // Compatibility with non-clang compilers.
#endif
#endif /* CREATE_TRANSLATIONS_H */

View File

@ -598,6 +598,7 @@ catalog Humongous Interactive Catalog
a56e8d9d4281c53c3f63c9bd22a59e21 10978342 en All HE CUP Preview George Kormendi
74da3494fbe1a7d20213b0afe0954755 10841544 fr All HE CUP Preview - George Kormendi
4c4820518e16e1a0e3616a3b021a04f3 10927456 de All HE CUP Preview - Kirben
288fb75b24389733c29fa107fe8d44e8 10795148 us All HE CUP Preview - Kirben
airport Let's Explore the Airport with Buzzy
d6334a5a9b61afe18c368540fdf522ca -1 en Mac - - - Joachim Eberhard

View File

@ -13,10 +13,10 @@ add_engine cruise "Cinematique evo 2" yes
add_engine draci "Dragon History" yes
add_engine drascula "Drascula: The Vampire Strikes Back" yes
add_engine dreamweb "Dreamweb" yes
add_engine fullpipe "Full Pipe" yes
add_engine fullpipe "Full Pipe" no
add_engine gob "Gobli*ns" yes
add_engine groovie "Groovie" yes "groovie2" "7th Guest"
add_engine groovie2 "Groovie 2 games" no
add_engine groovie2 "Groovie 2 games" no "" "" "jpeg"
add_engine hopkins "Hopkins FBI" yes "" "" "16bit"
add_engine hugo "Hugo Trilogy" yes
add_engine kyra "Kyra" yes "lol eob" "Legend of Kyrandia 1-3"
@ -52,5 +52,5 @@ add_engine touche "Touche: The Adventures of the Fifth Musketeer" yes
add_engine tony "Tony Tough and the Night of Roasted Moths" yes "" "" "16bit"
add_engine tsage "TsAGE" yes
add_engine tucker "Bud Tucker in Double Trouble" yes
add_engine wintermute "Wintermute" no "" "" "png zlib vorbis 16bit"
add_engine wintermute "Wintermute" no "" "" "jpeg png zlib vorbis 16bit"
add_engine zvision "ZVision" no

View File

@ -48,17 +48,17 @@ void BehaviorManager::clear() {
_behaviors.clear();
}
void BehaviorManager::initBehavior(Scene *sc, CGameVar *var) {
void BehaviorManager::initBehavior(Scene *sc, GameVar *var) {
clear();
_scene = sc;
BehaviorInfo *behinfo;
CGameVar *behvar = var->getSubVarByName("BEHAVIOR");
GameVar *behvar = var->getSubVarByName("BEHAVIOR");
if (!behvar)
return;
for (CGameVar *subvar = behvar->_subVars; subvar; subvar = subvar->_nextVarObj) {
for (GameVar *subvar = behvar->_subVars; subvar; subvar = subvar->_nextVarObj) {
if (!strcmp(subvar->_varName, "AMBIENT")) {
behinfo = new BehaviorInfo;
behinfo->initAmbientBehavior(subvar, sc);
@ -191,7 +191,7 @@ void BehaviorInfo::clear() {
_bheItems.clear();
}
void BehaviorInfo::initAmbientBehavior(CGameVar *var, Scene *sc) {
void BehaviorInfo::initAmbientBehavior(GameVar *var, Scene *sc) {
debug(0, "BehaviorInfo::initAmbientBehavior(%s)", transCyrillic((byte *)var->_varName));
clear();
@ -215,7 +215,7 @@ void BehaviorInfo::initAmbientBehavior(CGameVar *var, Scene *sc) {
}
}
void BehaviorInfo::initObjectBehavior(CGameVar *var, Scene *sc, StaticANIObject *ani) {
void BehaviorInfo::initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject *ani) {
debug(0, "BehaviorInfo::initObjectBehavior(%s)", transCyrillic((byte *)var->_varName));
clear();
@ -227,7 +227,7 @@ void BehaviorInfo::initObjectBehavior(CGameVar *var, Scene *sc, StaticANIObject
if (strcmp(var->_value.stringValue, "ROOT"))
break;
CGameVar *v1 = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("BEHAVIOR")->getSubVarByName(ani->getName());
GameVar *v1 = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("BEHAVIOR")->getSubVarByName(ani->getName());
if (v1 == var)
return;
@ -255,7 +255,7 @@ BehaviorEntry::BehaviorEntry() {
_items = 0;
}
BehaviorEntry::BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay) {
BehaviorEntry::BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay) {
_staticsId = 0;
_itemsCount = 0;
@ -274,7 +274,7 @@ BehaviorEntry::BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int
_items = (BehaviorEntryInfo**)calloc(_itemsCount, sizeof(BehaviorEntryInfo *));
for (int i = 0; i < _itemsCount; i++) {
CGameVar *subvar = var->getSubVarByIndex(i);
GameVar *subvar = var->getSubVarByIndex(i);
int delay;
_items[i] = new BehaviorEntryInfo(subvar, sc, &delay);
@ -289,14 +289,14 @@ BehaviorEntry::BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int
}
}
BehaviorEntryInfo::BehaviorEntryInfo(CGameVar *subvar, Scene *sc, int *delay) {
BehaviorEntryInfo::BehaviorEntryInfo(GameVar *subvar, Scene *sc, int *delay) {
_messageQueue = 0;
_delay = 0;
_percent = 0;
_flags = 0;
_messageQueue = sc->getMessageQueueByName(subvar->_varName);
CGameVar *vart = subvar->getSubVarByName("dwDelay");
GameVar *vart = subvar->getSubVarByName("dwDelay");
if (vart)
_delay = vart->_value.intValue;

View File

@ -31,7 +31,7 @@ struct BehaviorEntryInfo {
uint32 _percent;
int _flags;
BehaviorEntryInfo(CGameVar *subvar, Scene *sc, int *delay);
BehaviorEntryInfo(GameVar *subvar, Scene *sc, int *delay);
};
struct BehaviorEntry {
@ -41,7 +41,7 @@ struct BehaviorEntry {
BehaviorEntryInfo **_items;
BehaviorEntry();
BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay);
BehaviorEntry(GameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay);
};
struct BehaviorInfo {
@ -57,8 +57,8 @@ struct BehaviorInfo {
BehaviorInfo() { clear(); }
void clear();
void initAmbientBehavior(CGameVar *var, Scene *sc);
void initObjectBehavior(CGameVar *var, Scene *sc, StaticANIObject *ani);
void initAmbientBehavior(GameVar *var, Scene *sc);
void initObjectBehavior(GameVar *var, Scene *sc, StaticANIObject *ani);
};
class BehaviorManager : public CObject {
@ -72,7 +72,7 @@ class BehaviorManager : public CObject {
void clear();
void initBehavior(Scene *scene, CGameVar *var);
void initBehavior(Scene *scene, GameVar *var);
void updateBehaviors();
void updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry);

View File

@ -236,7 +236,7 @@ void FullpipeEngine::updateEvents() {
_modalObject->update();
} else {
_modalObject->saveload();
CBaseModalObject *obj = _modalObject->_parentObj;
BaseModalObject *obj = _modalObject->_parentObj;
if (obj)
delete _modalObject;
_modalObject = obj;
@ -260,7 +260,7 @@ void FullpipeEngine::updateEvents() {
}
ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0);
ex->_keyCode = 83;
ex->_keyCode = event.kbd.keycode;
ex->_excFlags |= 3;
ex->handle();
break;
@ -360,7 +360,7 @@ void FullpipeEngine::updateScreen() {
_modalObject->update();
} else {
_modalObject->saveload();
CBaseModalObject *tmp = _modalObject->_parentObj;
BaseModalObject *tmp = _modalObject->_parentObj;
delete _modalObject;
@ -389,7 +389,7 @@ void FullpipeEngine::updateScreen() {
}
int FullpipeEngine::getObjectEnumState(const char *name, const char *state) {
CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
if (!var) {
var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0);
@ -406,7 +406,7 @@ int FullpipeEngine::getObjectEnumState(const char *name, const char *state) {
}
int FullpipeEngine::getObjectState(const char *objname) {
CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
if (var)
return var->getSubVarAsInt(objname);
@ -415,7 +415,7 @@ int FullpipeEngine::getObjectState(const char *objname) {
}
void FullpipeEngine::setObjectState(const char *name, int state) {
CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
GameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES");
if (!var) {
var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0);

View File

@ -44,11 +44,11 @@ enum FullpipeGameFeatures {
};
class BehaviorManager;
class CBaseModalObject;
class CGameLoader;
class CGameVar;
class CInputController;
class CInventory2;
class BaseModalObject;
class GameLoader;
class GameVar;
class InputController;
class Inventory2;
struct CursorInfo;
struct EntranceInfo;
class ExCommand;
@ -98,12 +98,12 @@ public:
Graphics::Surface _backgroundSurface;
CGameLoader *_gameLoader;
GameLoader *_gameLoader;
GameProject *_gameProject;
bool loadGam(const char *fname, int scene = 0);
CGameVar *getGameLoaderGameVar();
CInputController *getGameLoaderInputController();
GameVar *getGameLoaderGameVar();
InputController *getGameLoaderInputController();
int _gameProjectVersion;
int _pictureScale;
@ -124,7 +124,7 @@ public:
StaticANIObject *_aniMan2;
byte *_globalPalette;
CInputController *_inputController;
InputController *_inputController;
bool _inputDisabled;
int _currentCheat;
@ -190,14 +190,14 @@ public:
int32 _mapTable[200];
Scene *_inventoryScene;
CInventory2 *_inventory;
Inventory2 *_inventory;
int _currSelectedInventoryItemId;
int32 _updateTicks;
int32 _lastInputTicks;
int32 _lastButtonUpTicks;
CBaseModalObject *_modalObject;
BaseModalObject *_modalObject;
int (*_updateScreenCallback)();
int (*_updateCursorCallback)();
@ -218,7 +218,7 @@ public:
bool sceneSwitcher(EntranceInfo *entrance);
Scene *accessScene(int sceneId);
void setSceneMusicParameters(CGameVar *var);
void setSceneMusicParameters(GameVar *var);
NGIArchive *_currArchive;

View File

@ -31,25 +31,25 @@
namespace Fullpipe {
CInventory2 *getGameLoaderInventory() {
Inventory2 *getGameLoaderInventory() {
return &g_fullpipe->_gameLoader->_inventory;
}
CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId) {
MctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId) {
for (uint i = 0; i < g_fullpipe->_gameLoader->_sc2array.size(); i++)
if (g_fullpipe->_gameLoader->_sc2array[i]._sceneId == sceneId)
return (CMctlCompound *)g_fullpipe->_gameLoader->_sc2array[i]._motionController;
return (MctlCompound *)g_fullpipe->_gameLoader->_sc2array[i]._motionController;
return 0;
}
CInteractionController *getGameLoaderInteractionController() {
InteractionController *getGameLoaderInteractionController() {
return g_fullpipe->_gameLoader->_interactionController;
}
CGameLoader::CGameLoader() {
_interactionController = new CInteractionController();
_inputController = new CInputController();
GameLoader::GameLoader() {
_interactionController = new InteractionController();
_inputController = new InputController();
_gameProject = 0;
_gameName = 0;
@ -74,15 +74,15 @@ CGameLoader::CGameLoader() {
g_fullpipe->_msgId = 0;
}
CGameLoader::~CGameLoader() {
GameLoader::~GameLoader() {
free(_gameName);
delete _gameProject;
delete _interactionController;
delete _inputController;
}
bool CGameLoader::load(MfcArchive &file) {
debug(5, "CGameLoader::load()");
bool GameLoader::load(MfcArchive &file) {
debug(5, "GameLoader::load()");
_gameName = file.readPascalString();
debug(6, "_gameName: %s", _gameName);
@ -124,12 +124,12 @@ bool CGameLoader::load(MfcArchive &file) {
_field_FA = file.readUint16LE();
_field_F8 = file.readUint16LE();
_gameVar = (CGameVar *)file.readClass();
_gameVar = (GameVar *)file.readClass();
return true;
}
bool CGameLoader::loadScene(int sceneId) {
bool GameLoader::loadScene(int sceneId) {
SceneTag *st;
int idx = getSceneTagBySceneId(sceneId, &st);
@ -155,7 +155,7 @@ bool CGameLoader::loadScene(int sceneId) {
return false;
}
bool CGameLoader::gotoScene(int sceneId, int entranceId) {
bool GameLoader::gotoScene(int sceneId, int entranceId) {
SceneTag *st;
int sc2idx = getSceneTagBySceneId(sceneId, &st);
@ -181,7 +181,7 @@ bool CGameLoader::gotoScene(int sceneId, int entranceId) {
return false;
}
CGameVar *sg = _gameVar->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME");
GameVar *sg = _gameVar->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME");
if (sg || (sg = _gameVar->getSubVarByName("OBJSTATES")->addSubVarAsInt("SAVEGAME", 0)) != 0)
sg->setSubVarAsInt("Entrance", entranceId);
@ -234,7 +234,7 @@ bool preloadCallback(const PreloadItem &pre, int flag) {
return true;
}
bool CGameLoader::preloadScene(int sceneId, int entranceId) {
bool GameLoader::preloadScene(int sceneId, int entranceId) {
debug(0, "preloadScene(%d, %d), ", sceneId, entranceId);
if (_preloadSceneId != sceneId || _preloadEntranceId != entranceId) {
@ -289,7 +289,7 @@ bool CGameLoader::preloadScene(int sceneId, int entranceId) {
return true;
}
bool CGameLoader::unloadScene(int sceneId) {
bool GameLoader::unloadScene(int sceneId) {
SceneTag *tag;
int sceneTag = getSceneTagBySceneId(sceneId, &tag);
@ -310,7 +310,7 @@ bool CGameLoader::unloadScene(int sceneId) {
return true;
}
int CGameLoader::getSceneTagBySceneId(int sceneId, SceneTag **st) {
int GameLoader::getSceneTagBySceneId(int sceneId, SceneTag **st) {
if (_sc2array.size() > 0 && _gameProject->_sceneTagList->size() > 0) {
for (uint i = 0; i < _sc2array.size(); i++) {
if (_sc2array[i]._sceneId == sceneId) {
@ -329,11 +329,11 @@ int CGameLoader::getSceneTagBySceneId(int sceneId, SceneTag **st) {
return -1;
}
void CGameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount) {
void GameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount) {
if (picAniInfoCount <= 0)
return;
debug(0, "CGameLoader::applyPicAniInfos(sc, ptr, %d)", picAniInfoCount);
debug(0, "GameLoader::applyPicAniInfos(sc, ptr, %d)", picAniInfoCount);
PictureObject *pict;
StaticANIObject *ani;
@ -381,11 +381,11 @@ void CGameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAn
}
}
void CGameLoader::saveScenePicAniInfos(int sceneId) {
warning("STUB: CGameLoader::saveScenePicAniInfos(%d)", sceneId);
void GameLoader::saveScenePicAniInfos(int sceneId) {
warning("STUB: GameLoader::saveScenePicAniInfos(%d)", sceneId);
}
void CGameLoader::updateSystems(int counterdiff) {
void GameLoader::updateSystems(int counterdiff) {
if (g_fullpipe->_currentScene) {
g_fullpipe->_currentScene->update(counterdiff);
@ -425,7 +425,7 @@ bool Sc2::load(MfcArchive &file) {
_sceneId = file.readUint16LE();
_motionController = (CMotionController *)file.readClass();
_motionController = (MotionController *)file.readClass();
_count1 = file.readUint32LE();
debug(4, "count1: %d", _count1);
@ -496,14 +496,14 @@ bool PreloadItems::load(MfcArchive &file) {
return true;
}
CGameVar *FullpipeEngine::getGameLoaderGameVar() {
GameVar *FullpipeEngine::getGameLoaderGameVar() {
if (_gameLoader)
return _gameLoader->_gameVar;
else
return 0;
}
CInputController *FullpipeEngine::getGameLoaderInputController() {
InputController *FullpipeEngine::getGameLoaderInputController() {
if (_gameLoader)
return _gameLoader->_inputController;
else

View File

@ -30,17 +30,17 @@
namespace Fullpipe {
class SceneTag;
class CMctlCompound;
class CInputController;
class CInteractionController;
class CMotionController;
class MctlCompound;
class InputController;
class InteractionController;
class MotionController;
class Sc2 : public CObject {
public:
int16 _sceneId;
int16 _field_2;
Scene *_scene;
CMotionController *_motionController;
MotionController *_motionController;
int32 *_data1; // FIXME, could be a struct
int _count1;
PicAniInfo **_defPicAniInfos;
@ -72,10 +72,10 @@ class PreloadItems : public Common::Array<PreloadItem *>, public CObject {
virtual bool load(MfcArchive &file);
};
class CGameLoader : public CObject {
class GameLoader : public CObject {
public:
CGameLoader();
virtual ~CGameLoader();
GameLoader();
virtual ~GameLoader();
virtual bool load(MfcArchive &file);
bool loadScene(int sceneId);
@ -90,9 +90,9 @@ class CGameLoader : public CObject {
void saveScenePicAniInfos(int sceneId);
GameProject *_gameProject;
CInteractionController *_interactionController;
CInputController *_inputController;
CInventory2 _inventory;
InteractionController *_interactionController;
InputController *_inputController;
Inventory2 _inventory;
Sc2Array _sc2array;
void *_sceneSwitcher;
bool (*_preloadCallback)(const PreloadItem &pre, int flag);
@ -100,7 +100,7 @@ class CGameLoader : public CObject {
int16 _field_F8;
int16 _field_FA;
PreloadItems _preloadItems;
CGameVar *_gameVar;
GameVar *_gameVar;
char *_gameName;
ExCommand _exCommand;
int _updateCounter;
@ -108,9 +108,9 @@ class CGameLoader : public CObject {
int _preloadEntranceId;
};
CInventory2 *getGameLoaderInventory();
CInteractionController *getGameLoaderInteractionController();
CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId);
Inventory2 *getGameLoaderInventory();
InteractionController *getGameLoaderInteractionController();
MctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId);
} // End of namespace Fullpipe

View File

@ -171,7 +171,7 @@ bool PictureObject::load(MfcArchive &file, bool bigPicture) {
_picture->load(file);
_pictureObject2List = new CPtrList();
_pictureObject2List = new PtrList();
int count = file.readUint16LE();
@ -325,7 +325,7 @@ void GameObject::setOXY(int x, int y) {
_oy = y;
}
void GameObject::renumPictures(CPtrList *lst) {
void GameObject::renumPictures(PtrList *lst) {
int *buf = (int *)calloc(lst->size() + 2, sizeof(int));
for (uint i = 0; i < lst->size(); i++) {

View File

@ -137,7 +137,7 @@ class GameObject : public CObject {
virtual bool load(MfcArchive &file);
void setOXY(int x, int y);
void renumPictures(CPtrList *lst);
void renumPictures(PtrList *lst);
void setFlags(int16 flags) { _flags = flags; }
void clearFlags() { _flags = 0; }
const char *getName() { return _objectName; }
@ -149,7 +149,7 @@ class GameObject : public CObject {
class PictureObject : public GameObject {
public:
Picture *_picture;
CPtrList *_pictureObject2List;
PtrList *_pictureObject2List;
int _ox2;
int _oy2;
@ -169,7 +169,7 @@ class PictureObject : public GameObject {
class Background : public CObject {
public:
CPtrList _picObjList;
PtrList _picObjList;
char *_bgname;
int _x;

View File

@ -123,7 +123,7 @@ void FullpipeEngine::initObjectStates() {
}
void FullpipeEngine::setLevelStates() {
CGameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons);
GameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons);
if (v) {
v->setSubVarAsInt(sO_Level0, 2833);

View File

@ -33,7 +33,7 @@
namespace Fullpipe {
CInputController::CInputController() {
InputController::InputController() {
g_fullpipe->_inputController = this;
_flag = 0;
@ -52,13 +52,13 @@ CInputController::CInputController() {
_cursorItemPicture = 0;
}
CInputController::~CInputController() {
InputController::~InputController() {
removeMessageHandler(126, -1);
g_fullpipe->_inputController = 0;
}
void CInputController::setInputDisabled(bool state) {
void InputController::setInputDisabled(bool state) {
_flag = state;
g_fullpipe->_inputDisabled = state;
}
@ -67,7 +67,7 @@ void setInputDisabled(bool state) {
g_fullpipe->_inputController->setInputDisabled(state);
}
void CInputController::addCursor(CursorInfo *cursor) {
void InputController::addCursor(CursorInfo *cursor) {
CursorInfo *newc = new CursorInfo(cursor);
Common::Point p;
@ -82,14 +82,14 @@ void CInputController::addCursor(CursorInfo *cursor) {
_cursorsArray.push_back(newc);
}
void CInputController::setCursorMode(bool enabled) {
void InputController::setCursorMode(bool enabled) {
if (enabled)
_inputFlags |= 1;
else
_inputFlags &= ~1;
}
void CInputController::drawCursor(int x, int y) {
void InputController::drawCursor(int x, int y) {
if (_cursorIndex == -1)
return;
@ -105,7 +105,7 @@ void CInputController::drawCursor(int x, int y) {
_cursorBounds.top + _cursorsArray[_cursorIndex]->itemPictureOffsY, 0, 0);
}
void CInputController::setCursor(int cursorId) {
void InputController::setCursor(int cursorId) {
if (_cursorIndex == -1 || _cursorsArray[_cursorIndex]->pictureId != cursorId) {
_cursorIndex = -1;
@ -165,7 +165,6 @@ void FullpipeEngine::defHandleKeyDown(int key) {
return;
}
warning("%d %d", _currentCheat, _currentCheatPos);
if (toupper(key) != input_cheats[_currentCheat][_currentCheatPos]) {
_currentCheat = -1;
@ -173,7 +172,6 @@ void FullpipeEngine::defHandleKeyDown(int key) {
}
_currentCheatPos++;
warning("%d %d", _currentCheat, _currentCheatPos);
if (!input_cheats[_currentCheat][_currentCheatPos]) {
switch (_currentCheat) {

View File

@ -45,7 +45,7 @@ struct CursorInfo {
typedef Common::Array<CursorInfo *> CursorsArray;
class CInputController {
class InputController {
//CObject obj;
int _flag;
int _inputFlags;
@ -59,8 +59,8 @@ class CInputController {
Picture *_cursorItemPicture;
public:
CInputController();
~CInputController();
InputController();
~InputController();
void setInputDisabled(bool state);
void addCursor(CursorInfo *cursor);

View File

@ -39,9 +39,9 @@ bool canInteractAny(GameObject *obj1, GameObject *obj2, int invId) {
if (g_fullpipe->_currentScene)
sceneId = g_fullpipe->_currentScene->_sceneId;
CInteractionController *intC = getGameLoaderInteractionController();
for (CObList::iterator i = intC->_interactions.begin(); i != intC->_interactions.end(); ++i) {
CInteraction *intr = (CInteraction *)*i;
InteractionController *intC = getGameLoaderInteractionController();
for (ObList::iterator i = intC->_interactions.begin(); i != intC->_interactions.end(); ++i) {
Interaction *intr = (Interaction *)*i;
if (intr->_sceneId > 0 && intr->_sceneId != sceneId)
break;
@ -55,17 +55,17 @@ bool canInteractAny(GameObject *obj1, GameObject *obj2, int invId) {
return false;
}
bool CInteractionController::load(MfcArchive &file) {
debug(5, "CInteractionController::load()");
bool InteractionController::load(MfcArchive &file) {
debug(5, "InteractionController::load()");
return _interactions.load(file);
}
int static_compSceneId = 0;
bool CInteractionController::compareInteractions(const void *p1, const void *p2) {
const CInteraction *i1 = (const CInteraction *)p1;
const CInteraction *i2 = (const CInteraction *)p2;
bool InteractionController::compareInteractions(const void *p1, const void *p2) {
const Interaction *i1 = (const Interaction *)p1;
const Interaction *i2 = (const Interaction *)p2;
if (i2->_sceneId < i1->_sceneId) {
if (i1->_sceneId != static_compSceneId)
@ -89,13 +89,13 @@ bool CInteractionController::compareInteractions(const void *p1, const void *p2)
return true;
}
void CInteractionController::sortInteractions(int sceneId) {
void InteractionController::sortInteractions(int sceneId) {
static_compSceneId = sceneId;
Common::sort(_interactions.begin(), _interactions.end(), CInteractionController::compareInteractions);
Common::sort(_interactions.begin(), _interactions.end(), InteractionController::compareInteractions);
}
bool CInteractionController::handleInteraction(StaticANIObject *subj, GameObject *obj, int invId) {
bool InteractionController::handleInteraction(StaticANIObject *subj, GameObject *obj, int invId) {
if (subj) {
if (!subj->isIdle() || (subj->_flags & 0x100))
return false;
@ -104,16 +104,16 @@ bool CInteractionController::handleInteraction(StaticANIObject *subj, GameObject
if (!_interactions.size())
return false;
CInteraction *inter = 0;
CInteraction *previnter = 0;
Interaction *inter = 0;
Interaction *previnter = 0;
int dur = 0;
int mindur = 0xFFFF;
MessageQueue *mq;
ExCommand *ex;
for (CObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) {
CInteraction *cinter = (CInteraction *)*i;
for (ObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) {
Interaction *cinter = (Interaction *)*i;
if (!cinter->canInteract(subj, obj, invId))
continue;
@ -394,7 +394,7 @@ LABEL_38:
return true;
}
CInteraction::CInteraction() {
Interaction::Interaction() {
_objectId1 = 0;
_objectId2 = 0;
_staticsId1 = 0;
@ -411,8 +411,8 @@ CInteraction::CInteraction() {
_actionName = 0;
}
bool CInteraction::load(MfcArchive &file) {
debug(5, "CInteraction::load()");
bool Interaction::load(MfcArchive &file) {
debug(5, "Interaction::load()");
_objectId1 = file.readUint16LE();
_objectId2 = file.readUint16LE();
@ -432,7 +432,7 @@ bool CInteraction::load(MfcArchive &file) {
return true;
}
bool CInteraction::canInteract(GameObject *obj1, GameObject *obj2, int invId) {
bool Interaction::canInteract(GameObject *obj1, GameObject *obj2, int invId) {
if (_sceneId > 0 && g_fullpipe->_currentScene && g_fullpipe->_currentScene->_sceneId != _sceneId)
return false;
@ -489,7 +489,7 @@ bool CInteraction::canInteract(GameObject *obj1, GameObject *obj2, int invId) {
return true;
}
bool CInteraction::isOverlapping(StaticANIObject *subj, GameObject *obj) {
bool Interaction::isOverlapping(StaticANIObject *subj, GameObject *obj) {
StaticANIObject *ani = (StaticANIObject *)obj;
if (abs(_xOffs + obj->_ox - subj->_ox) <= 1

View File

@ -35,7 +35,7 @@ int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int in
bool canInteractAny(GameObject *obj1, GameObject *obj2, int invId);
class CInteraction : public CObject {
class Interaction : public CObject {
public:
int16 _objectId1;
int16 _objectId2;
@ -53,15 +53,15 @@ class CInteraction : public CObject {
char *_actionName;
public:
CInteraction();
Interaction();
virtual bool load(MfcArchive &file);
bool canInteract(GameObject *obj1, GameObject *obj2, int invId);
bool isOverlapping(StaticANIObject *subj, GameObject *obj);
};
class CInteractionController : public CObject {
class InteractionController : public CObject {
public:
CObList _interactions;
ObList _interactions;
int16 _field_20;
bool _flag24;
@ -69,7 +69,7 @@ class CInteractionController : public CObject {
static bool compareInteractions(const void *p1, const void *p2);
public:
CInteractionController() : _field_20(0), _flag24(true) {}
InteractionController() : _field_20(0), _flag24(true) {}
virtual bool load(MfcArchive &file);

View File

@ -30,8 +30,8 @@
namespace Fullpipe {
bool CInventory::load(MfcArchive &file) {
debug(5, "CInventory::load()");
bool Inventory::load(MfcArchive &file) {
debug(5, "Inventory::load()");
_sceneId = file.readUint16LE();
int numInvs = file.readUint32LE();
@ -52,7 +52,7 @@ bool CInventory::load(MfcArchive &file) {
return true;
}
int CInventory::getInventoryPoolItemIndexById(int itemId) {
int Inventory::getInventoryPoolItemIndexById(int itemId) {
if (_itemsPool.size() <= 0)
return -1;
@ -64,7 +64,7 @@ int CInventory::getInventoryPoolItemIndexById(int itemId) {
return 0;
}
bool CInventory::setItemFlags(int itemId, int flags) {
bool Inventory::setItemFlags(int itemId, int flags) {
int idx = getInventoryPoolItemIndexById(itemId);
if (idx < 0)
@ -75,7 +75,7 @@ bool CInventory::setItemFlags(int itemId, int flags) {
return true;
}
CInventory2::CInventory2() {
Inventory2::Inventory2() {
_selectedId = -1;
_field_48 = -1;
_scene = 0;
@ -85,7 +85,7 @@ CInventory2::CInventory2() {
_topOffset = -65;
}
bool CInventory2::loadPartial(MfcArchive &file) { // CInventory2_SerializePartially
bool Inventory2::loadPartial(MfcArchive &file) { // Inventory2_SerializePartially
int numInvs = file.readUint32LE();
for (int i = 0; i < numInvs; i++) {
@ -98,27 +98,27 @@ bool CInventory2::loadPartial(MfcArchive &file) { // CInventory2_SerializePartia
return true;
}
void CInventory2::addItem(int itemId, int count) {
void Inventory2::addItem(int itemId, int count) {
if (getInventoryPoolItemIndexById(itemId) >= 0)
_inventoryItems.push_back(new InventoryItem(itemId, count));
}
void CInventory2::addItem2(StaticANIObject *obj) {
void Inventory2::addItem2(StaticANIObject *obj) {
if (getInventoryPoolItemIndexById(obj->_id) >= 0 && getInventoryPoolItemFieldCById(obj->_id) != 2) {
addItem(obj->_id, 1);
obj->hide();
}
}
void CInventory2::removeItem(int itemId, int count) {
warning("STUB: CInventory2::removeItem(%d, %d)", itemId, count);
void Inventory2::removeItem(int itemId, int count) {
warning("STUB: Inventory2::removeItem(%d, %d)", itemId, count);
}
void CInventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority) {
void Inventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority) {
warning("STUB: void removeItem2(sc, %d, %d, %d, %d)", itemId, x, y, priority);
}
int CInventory2::getCountItemsWithId(int itemId) {
int Inventory2::getCountItemsWithId(int itemId) {
int res = 0;
for (uint i = 0; i < _inventoryItems.size(); i++) {
@ -129,7 +129,7 @@ int CInventory2::getCountItemsWithId(int itemId) {
return res;
}
int CInventory2::getInventoryItemIndexById(int itemId) {
int Inventory2::getInventoryItemIndexById(int itemId) {
for (uint i = 0; i < _inventoryItems.size(); i++) {
if (_inventoryItems[i]->itemId == itemId)
return i;
@ -138,11 +138,11 @@ int CInventory2::getInventoryItemIndexById(int itemId) {
return -1;
}
int CInventory2::getInventoryPoolItemIdAtIndex(int itemId) {
int Inventory2::getInventoryPoolItemIdAtIndex(int itemId) {
return _itemsPool[itemId]->id;
}
int CInventory2::getInventoryPoolItemFieldCById(int itemId) {
int Inventory2::getInventoryPoolItemFieldCById(int itemId) {
for (uint i = 0; i < _itemsPool.size(); i++) {
if (_itemsPool[i]->id == itemId)
return _itemsPool[i]->field_C;
@ -151,7 +151,7 @@ int CInventory2::getInventoryPoolItemFieldCById(int itemId) {
return 0;
}
int CInventory2::getItemFlags(int itemId) {
int Inventory2::getItemFlags(int itemId) {
int idx = getInventoryPoolItemIndexById(itemId);
if (idx < 0)
@ -160,7 +160,7 @@ int CInventory2::getItemFlags(int itemId) {
return _itemsPool[idx]->flags;
}
void CInventory2::rebuildItemRects() {
void Inventory2::rebuildItemRects() {
_scene = g_fullpipe->accessScene(_sceneId);
if (!_scene)
@ -222,7 +222,7 @@ void CInventory2::rebuildItemRects() {
}
}
void CInventory2::draw() {
void Inventory2::draw() {
if (!_scene)
return;
@ -295,7 +295,7 @@ reset:
}
void CInventory2::slideIn() {
void Inventory2::slideIn() {
_isInventoryOut = false;
ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0);
@ -307,7 +307,7 @@ void CInventory2::slideIn() {
ex->postMessage();
}
void CInventory2::slideOut() {
void Inventory2::slideOut() {
_isInventoryOut = true;
ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0);
@ -319,7 +319,7 @@ void CInventory2::slideOut() {
ex->postMessage();
}
bool CInventory2::handleLeftClick(ExCommand *cmd) {
bool Inventory2::handleLeftClick(ExCommand *cmd) {
if (!_isInventoryOut)
return false;
@ -353,7 +353,7 @@ bool CInventory2::handleLeftClick(ExCommand *cmd) {
return res;
}
int CInventory2::selectItem(int itemId) {
int Inventory2::selectItem(int itemId) {
if (getInventoryItemIndexById(itemId) < 0)
return -1;
@ -371,7 +371,7 @@ int CInventory2::selectItem(int itemId) {
return _selectedId;
}
bool CInventory2::unselectItem(bool flag) {
bool Inventory2::unselectItem(bool flag) {
if (_selectedId < 0)
return false;
@ -387,7 +387,7 @@ bool CInventory2::unselectItem(bool flag) {
return true;
}
int CInventory2::getHoveredItem(Common::Point *point) {
int Inventory2::getHoveredItem(Common::Point *point) {
int selId = getSelectedItemId();
if (point->y <= 20 && !_isInventoryOut && !_isLocked)
@ -422,7 +422,7 @@ int CInventory2::getHoveredItem(Common::Point *point) {
}
void FullpipeEngine::getAllInventory() {
CInventory2 *inv = getGameLoaderInventory();
Inventory2 *inv = getGameLoaderInventory();
for (uint i = 0; i < inv->getItemsPoolCount(); ++i ) {
int id = inv->getInventoryPoolItemIdAtIndex(i);

View File

@ -42,13 +42,13 @@ struct InventoryPoolItem {
typedef Common::Array<InventoryPoolItem *> InventoryPoolItems;
class CInventory : public CObject {
class Inventory : public CObject {
protected:
int16 _sceneId;
InventoryPoolItems _itemsPool;
public:
CInventory() { _sceneId = 0; }
Inventory() { _sceneId = 0; }
virtual bool load(MfcArchive &file);
int getInventoryPoolItemIndexById(int itemId);
@ -83,7 +83,7 @@ struct InventoryIcon {
typedef Common::Array<InventoryIcon *> InventoryIcons;
class CInventory2 : public CInventory {
class Inventory2 : public Inventory {
InventoryItems _inventoryItems;
InventoryIcons _inventoryIcons;
int _selectedId;
@ -95,7 +95,7 @@ class CInventory2 : public CInventory {
BigPicture *_picture;
public:
CInventory2();
Inventory2();
bool loadPartial(MfcArchive &file);
void addItem(int itemId, int count);
void addItem2(StaticANIObject *obj);

View File

@ -169,13 +169,13 @@ Message::Message(int16 parentId, int messageKind, int x, int y, int a6, int a7,
_field_34 = 0;
}
CObjstateCommand::CObjstateCommand() {
ObjstateCommand::ObjstateCommand() {
_value = 0;
_objCommandName = 0;
}
bool CObjstateCommand::load(MfcArchive &file) {
debug(5, "CObjStateCommand::load()");
bool ObjstateCommand::load(MfcArchive &file) {
debug(5, "ObjStateCommand::load()");
_objtype = kObjTypeObjstateCommand;
@ -196,6 +196,9 @@ MessageQueue::MessageQueue() {
_isFinished = 0;
_flags = 0;
_queueName = 0;
_counter = 0;
_field_38 = 0;
_flag1 = 0;
}
MessageQueue::MessageQueue(MessageQueue *src, int parId, int field_38) {
@ -222,6 +225,7 @@ MessageQueue::MessageQueue(MessageQueue *src, int parId, int field_38) {
g_fullpipe->_globalMessageQueueList->addMessageQueue(this);
_isFinished = 0;
_flag1 = 0;
}
MessageQueue::~MessageQueue() {

View File

@ -82,14 +82,14 @@ class ExCommand2 : public ExCommand {
int _pointsSize;
};
class CObjstateCommand : public CObject {
class ObjstateCommand : public CObject {
public:
ExCommand _cmd;
char *_objCommandName;
int _value;
public:
CObjstateCommand();
ObjstateCommand();
virtual bool load(MfcArchive &file);
};
@ -99,7 +99,6 @@ class MessageQueue : public CObject {
int _flags;
char *_queueName;
int16 _dataId;
int16 _field_12;
CObject *_field_14;
Common::List<ExCommand *> _exCommands;
int _counter;

View File

@ -28,30 +28,30 @@
namespace Fullpipe {
bool CBaseModalObject::handleMessage(ExCommand *message) {
warning("STUB: CBaseModalObject::handleMessage()");
bool BaseModalObject::handleMessage(ExCommand *message) {
warning("STUB: BaseModalObject::handleMessage()");
return true;
}
bool CBaseModalObject::init(int counterdiff) {
warning("STUB: CBaseModalObject::init(%d)", counterdiff);
bool BaseModalObject::init(int counterdiff) {
warning("STUB: BaseModalObject::init(%d)", counterdiff);
return true;
}
bool CBaseModalObject::update() {
warning("STUB: CBaseModalObject::update()");
bool BaseModalObject::update() {
warning("STUB: BaseModalObject::update()");
return true;
}
void CBaseModalObject::saveload() {
warning("STUB: CBaseModalObject::saveload()");
void BaseModalObject::saveload() {
warning("STUB: BaseModalObject::saveload()");
}
CModalIntro::CModalIntro() {
ModalIntro::ModalIntro() {
_field_8 = 0;
_countDown = 0;
_needRedraw = 0;
@ -68,7 +68,7 @@ CModalIntro::CModalIntro() {
_sfxVolume = g_fullpipe->_sfxVolume;
}
bool CModalIntro::handleMessage(ExCommand *message) {
bool ModalIntro::handleMessage(ExCommand *message) {
if (message->_messageKind != 17)
return false;

View File

@ -25,14 +25,14 @@
namespace Fullpipe {
class CBaseModalObject {
class BaseModalObject {
public:
CBaseModalObject *_parentObj;
BaseModalObject *_parentObj;
public:
CBaseModalObject() : _parentObj(0) {}
virtual ~CBaseModalObject() {}
BaseModalObject() : _parentObj(0) {}
virtual ~BaseModalObject() {}
virtual bool handleMessage(ExCommand *message);
virtual bool init(int counterdiff);
@ -41,7 +41,7 @@ class CBaseModalObject {
void saveload();
};
class CModalIntro : public CBaseModalObject {
class ModalIntro : public BaseModalObject {
int _field_8;
int _introFlags;
int _countDown;
@ -49,7 +49,7 @@ class CModalIntro : public CBaseModalObject {
int _sfxVolume;
public:
CModalIntro();
ModalIntro();
virtual bool handleMessage(ExCommand *message);
};

View File

@ -27,35 +27,40 @@
#include "common/list.h"
#include "fullpipe/objects.h"
#include "fullpipe/statics.h"
#include "fullpipe/motion.h"
#include "fullpipe/messages.h"
#include "fullpipe/gameloader.h"
namespace Fullpipe {
bool CMotionController::load(MfcArchive &file) {
bool MotionController::load(MfcArchive &file) {
// Is originally empty file.readClass();
debug(5, "CMotionController::load()");
debug(5, "MotionController::load()");
return true;
}
bool CMctlCompound::load(MfcArchive &file) {
debug(5, "CMctlCompound::load()");
bool MctlCompound::load(MfcArchive &file) {
debug(5, "MctlCompound::load()");
int count = file.readUint32LE();
debug(6, "CMctlCompound::count = %d", count);
debug(6, "MctlCompound::count = %d", count);
for (int i = 0; i < count; i++) {
debug(6, "CompoundArray[%d]", i);
CMctlCompoundArrayItem *obj = (CMctlCompoundArrayItem *)file.readClass();
MctlCompoundArrayItem *obj = new MctlCompoundArrayItem();
obj->_motionControllerObj = (MotionController *)file.readClass();
int count1 = file.readUint32LE();
debug(6, "ConnectionPoint::count: %d", count1);
for (int j = 0; j < count1; j++) {
debug(6, "ConnectionPoint[%d]", j);
CMctlConnectionPoint *obj1 = (CMctlConnectionPoint *)file.readClass();
MctlConnectionPoint *obj1 = (MctlConnectionPoint *)file.readClass();
obj->_connectionPoints.push_back(*obj1);
}
@ -64,57 +69,97 @@ bool CMctlCompound::load(MfcArchive &file) {
obj->_field_24 = file.readUint32LE();
debug(6, "graphReact");
obj->_movGraphReactObj = (CMovGraphReact *)file.readClass();
obj->_movGraphReactObj = (MovGraphReact *)file.readClass();
_motionControllers.push_back(*obj);
_motionControllers.push_back(obj);
}
return true;
}
void CMctlCompound::addObject(StaticANIObject *obj) {
warning("STUB: CMctlCompound::addObject()");
void MctlCompound::addObject(StaticANIObject *obj) {
for (uint i = 0; i < _motionControllers.size(); i++)
_motionControllers[i]->_motionControllerObj->addObject(obj);
}
void CMctlCompound::initMovGraph2() {
warning("STUB: CMctlCompound::initMovGraph2()");
}
MessageQueue *CMctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: CMctlCompound::method34()");
int MctlCompound::removeObject(StaticANIObject *obj) {
warning("STUB: MctlCompound::removeObject()");
return 0;
}
MessageQueue *CMctlCompound::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: CMctlCompound::method4C()");
void MctlCompound::initMovGraph2() {
if (_objtype != kObjTypeMctlCompound)
return;
for (uint i = 0; i < _motionControllers.size(); i++) {
if (_motionControllers[i]->_motionControllerObj->_objtype != kObjTypeMovGraph)
continue;
MovGraph *gr = (MovGraph *)_motionControllers[i]->_motionControllerObj;
MovGraph2 *newgr = new MovGraph2();
newgr->_links = gr->_links;
newgr->_nodes = gr->_nodes;
gr->_links.clear();
gr->_nodes.clear();
delete gr;
_motionControllers[i]->_motionControllerObj = newgr;
}
}
void MctlCompound::freeItems() {
warning("STUB: MctlCompound::freeItems()");
}
MessageQueue *MctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: MctlCompound::method34()");
return 0;
}
bool CMctlCompoundArray::load(MfcArchive &file) {
debug(5, "CMctlCompoundArray::load()");
MessageQueue *MctlCompound::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: MctlCompound::method4C()");
return 0;
}
bool MctlCompoundArray::load(MfcArchive &file) {
debug(5, "MctlCompoundArray::load()");
int count = file.readUint32LE();
debug(0, "CMctlCompoundArray::count = %d", count);
debug(0, "MctlCompoundArray::count = %d", count);
assert(0);
return true;
}
CMovGraph::CMovGraph() {
warning("STUB: CMovGraph::CMovGraph()");
_itemsCount = 0;
_items = 0;
//_callback1 = CMovGraphCallback1; // TODO
_field_44 = 0;
// insertMessageHandler(CMovGraph_messageHandler, getMessageHandlersCount() - 1, 129);
int MovGraph_messageHandler(ExCommand *cmd);
int MovGraphCallback(int a1, int a2, int a3) {
warning("STUB: MovgraphCallback");
return 0;
}
bool CMovGraph::load(MfcArchive &file) {
debug(5, "CMovGraph::load()");
MovGraph::MovGraph() {
_itemsCount = 0;
_items = 0;
_callback1 = MovGraphCallback;
_field_44 = 0;
insertMessageHandler(MovGraph_messageHandler, getMessageHandlersCount() - 1, 129);
_objtype = kObjTypeMovGraph;
}
bool MovGraph::load(MfcArchive &file) {
debug(5, "MovGraph::load()");
_links.load(file);
_nodes.load(file);
@ -122,11 +167,288 @@ bool CMovGraph::load(MfcArchive &file) {
return true;
}
void CMovGraph::addObject(StaticANIObject *obj) {
warning("STUB: CMovGraph::addObject()");
void MovGraph::addObject(StaticANIObject *obj) {
warning("STUB: MovGraph::addObject()");
}
CMovGraphLink::CMovGraphLink() {
int MovGraph::removeObject(StaticANIObject *obj) {
warning("STUB: MovGraph::removeObject()");
return 0;
}
void MovGraph::freeItems() {
warning("STUB: MovGraph::freeItems()");
}
int MovGraph::method28() {
warning("STUB: MovGraph::method28()");
return 0;
}
int MovGraph::method2C() {
warning("STUB: MovGraph::method2C()");
return 0;
}
MessageQueue *MovGraph::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: MovGraph::method34()");
return 0;
}
int MovGraph::changeCallback() {
warning("STUB: MovGraph::changeCallback()");
return 0;
}
int MovGraph::method3C() {
warning("STUB: MovGraph::method3C()");
return 0;
}
int MovGraph::method44() {
warning("STUB: MovGraph::method44()");
return 0;
}
MessageQueue *MovGraph::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: MovGraph::method4C()");
return 0;
}
int MovGraph::method50() {
warning("STUB: MovGraph::method50()");
return 0;
}
double MovGraph::calcDistance(Common::Point *point, MovGraphLink *link, int flag) {
int n1x = link->_movGraphNode1->_x;
int n1y = link->_movGraphNode1->_y;
int n2x = link->_movGraphNode2->_x;
int n2y = link->_movGraphNode2->_y;
double dist1x = (double)(point->x - n1x);
double dist1y = (double)(n1y - point->y);
double dist2x = (double)(n2x - n1x);
double dist2y = (double)(n2y - n1y);
double dist1 = sqrt(dist1y * dist1y + dist1x * dist1x);
double dist2 = ((double)(n1y - n2y) * dist1y + dist2x * dist1x) / link->_distance / dist1;
double distm = dist2 * dist1;
double res = sqrt(1.0 - dist2 * dist2) * dist1;
if (dist2 <= 0.0 || distm >= link->_distance) {
if (flag) {
if (dist2 > 0.0) {
if (distm >= link->_distance) {
point->x = n2x;
point->y = n2y;
}
} else {
point->x = n1x;
point->y = n1y;
}
} else {
return -1.0;
}
} else {
point->x = n1x + (dist2x * distm / link->_distance);
point->y = n1y + (dist2y * distm / link->_distance);
}
return res;
}
int MovGraph2::getItemIndexByGameObjectId(int objectId) {
for (uint i = 0; i < _items.size(); i++)
if (_items[i]->_objectId == objectId)
return i;
return -1;
}
bool MovGraph2::initDirections(StaticANIObject *obj, MovGraph2Item *item) {
item->_obj = obj;
item->_objectId = obj->_id;
GameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(obj->_objectName);
if (!var)
return false;
var = var->getSubVarByName("Test_walk");
if (!var)
return false;
GameVar *varD = 0;
Common::Point point;
for (int dir = 0; dir < 4; dir++) {
switch (dir) {
case 0:
varD = var->getSubVarByName("Right");
break;
case 1:
varD = var->getSubVarByName("Left");
break;
case 2:
varD = var->getSubVarByName("Up");
break;
case 3:
varD = var->getSubVarByName("Down");
break;
}
if (!varD)
return false;
for (int act = 0; act < 3; act++) {
int idx;
switch(act) {
case 0:
idx = varD->getSubVarAsInt("Start");
break;
case 1:
idx = varD->getSubVarAsInt("Go");
break;
case 2:
idx = varD->getSubVarAsInt("Stop");
break;
}
item->_subItems[dir]._walk[act]._movementId = idx;
Movement *mov = obj->getMovementById(idx);
item->_subItems[dir]._walk[act]._mov = mov;
if (mov) {
mov->calcSomeXY(point, 0);
item->_subItems[dir]._walk[act]._mx = point.x;
item->_subItems[dir]._walk[act]._my = point.y;
}
}
for (int act = 0; act < 4; act++) {
int idx;
switch(act) {
case 0:
idx = varD->getSubVarAsInt("TurnR");
break;
case 1:
idx = varD->getSubVarAsInt("TurnL");
break;
case 2:
idx = varD->getSubVarAsInt("TurnU");
break;
case 3:
idx = varD->getSubVarAsInt("TurnD");
break;
}
item->_subItems[dir]._turn[act]._movementId = idx;
Movement *mov = obj->getMovementById(idx);
item->_subItems[dir]._turn[act]._mov = mov;
if (mov) {
mov->calcSomeXY(point, 0);
item->_subItems[dir]._turn[act]._mx = point.x;
item->_subItems[dir]._turn[act]._my = point.y;
}
}
for (int act = 0; act < 4; act++) {
int idx;
switch(act) {
case 0:
idx = varD->getSubVarAsInt("TurnSR");
break;
case 1:
idx = varD->getSubVarAsInt("TurnSL");
break;
case 2:
idx = varD->getSubVarAsInt("TurnSU");
break;
case 3:
idx = varD->getSubVarAsInt("TurnSD");
break;
}
item->_subItems[dir]._turnS[act]._movementId = idx;
Movement *mov = obj->getMovementById(idx);
item->_subItems[dir]._turnS[act]._mov = mov;
if (mov) {
mov->calcSomeXY(point, 0);
item->_subItems[dir]._turnS[act]._mx = point.x;
item->_subItems[dir]._turnS[act]._my = point.y;
}
}
item->_subItems[dir]._staticsId1 = item->_subItems[dir]._walk[0]._mov->_staticsObj1->_staticsId;
item->_subItems[dir]._staticsId2 = item->_subItems[dir]._walk[0]._mov->_staticsObj2->_staticsId;
}
return true;
}
void MovGraph2::addObject(StaticANIObject *obj) {
MovGraph::addObject(obj);
int id = getItemIndexByGameObjectId(obj->_id);
if (id >= 0) {
_items[id]->_obj = obj;
} else {
MovGraph2Item *item = new MovGraph2Item;
if (initDirections(obj, item)) {
_items.push_back(item);
} else {
delete item;
}
}
}
int MovGraph2::removeObject(StaticANIObject *obj) {
warning("STUB: MovGraph2::removeObject()");
return 0;
}
void MovGraph2::freeItems() {
warning("STUB: MovGraph2::freeItems()");
}
MessageQueue *MovGraph2::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: MovGraph2::method34()");
return 0;
}
MessageQueue *MovGraph2::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) {
warning("STUB: MovGraph2::method4C()");
return 0;
}
MovGraphNode *MovGraph::calcOffset(int ox, int oy) {
warning("STUB: MovGraph::calcOffset()");
return 0;
}
MovGraphLink::MovGraphLink() {
_distance = 0;
_angle = 0;
_flags = 0x10000000;
@ -138,8 +460,8 @@ CMovGraphLink::CMovGraphLink() {
_name = 0;
}
bool CMovGraphLink::load(MfcArchive &file) {
debug(5, "CMovGraphLink::load()");
bool MovGraphLink::load(MfcArchive &file) {
debug(5, "MovGraphLink::load()");
_dwordArray1.load(file);
_dwordArray2.load(file);
@ -147,23 +469,23 @@ bool CMovGraphLink::load(MfcArchive &file) {
_flags = file.readUint32LE();
debug(8, "GraphNode1");
_movGraphNode1 = (CMovGraphNode *)file.readClass();
_movGraphNode1 = (MovGraphNode *)file.readClass();
debug(8, "GraphNode2");
_movGraphNode2 = (CMovGraphNode *)file.readClass();
_movGraphNode2 = (MovGraphNode *)file.readClass();
_distance = file.readDouble();
_angle = file.readDouble();
debug(8, "distance: %g, angle: %g", _distance, _angle);
_movGraphReact = (CMovGraphReact *)file.readClass();
_movGraphReact = (MovGraphReact *)file.readClass();
_name = file.readPascalString();
return true;
}
bool CMovGraphNode::load(MfcArchive &file) {
debug(5, "CMovGraphNode::load()");
bool MovGraphNode::load(MfcArchive &file) {
debug(5, "MovGraphNode::load()");
_field_14 = file.readUint32LE();
_x = file.readUint32LE();
@ -173,7 +495,7 @@ bool CMovGraphNode::load(MfcArchive &file) {
return true;
}
CReactParallel::CReactParallel() {
ReactParallel::ReactParallel() {
_x1 = 0;
_x2 = 0;
_dy = 0;
@ -183,8 +505,8 @@ CReactParallel::CReactParallel() {
_y2 = 0;
}
bool CReactParallel::load(MfcArchive &file) {
debug(5, "CReactParallel::load()");
bool ReactParallel::load(MfcArchive &file) {
debug(5, "ReactParallel::load()");
_x1 = file.readUint32LE();
_y1 = file.readUint32LE();
@ -198,7 +520,7 @@ bool CReactParallel::load(MfcArchive &file) {
return true;
}
void CReactParallel::createRegion() {
void ReactParallel::createRegion() {
_points = (Common::Point **)malloc(sizeof(Common::Point *) * 4);
for (int i = 0; i < 4; i++)
@ -223,15 +545,15 @@ void CReactParallel::createRegion() {
// GdiObject::Attach(_rgn, CreatePolygonRgn(_points, 4, 2);
}
CReactPolygonal::CReactPolygonal() {
ReactPolygonal::ReactPolygonal() {
_field_C = 0;
_points = 0;
_pointCount = 0;
_field_10 = 0;
}
bool CReactPolygonal::load(MfcArchive &file) {
debug(5, "CReactPolygonal::load()");
bool ReactPolygonal::load(MfcArchive &file) {
debug(5, "ReactPolygonal::load()");
_field_C = file.readUint32LE();
_field_10 = file.readUint32LE();
@ -254,7 +576,7 @@ bool CReactPolygonal::load(MfcArchive &file) {
return true;
}
void CReactPolygonal::createRegion() {
void ReactPolygonal::createRegion() {
if (_points) {
// GdiObject::Attach(_rgn, CreatePolygonRgn(_points, _pointCount, 2);
@ -262,7 +584,10 @@ void CReactPolygonal::createRegion() {
}
int startWalkTo(int objId, int objKey, int x, int y, int a5) {
warning("STUB: startWalkTo(%d, %d, %d, %d, %d)", objId, objKey, x, y, a5);
MctlCompound *mc = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId);
if (mc)
return (mc->method34(g_fullpipe->_currentScene->getStaticANIObject1ById(objId, objKey), x, y, a5, 0) != 0);
return 0;
}

View File

@ -29,54 +29,88 @@ int startWalkTo(int objId, int objKey, int x, int y, int a5);
int doSomeAnimation(int objId, int objKey, int a3);
int doSomeAnimation2(int objId, int objKey);
class CMotionController : public CObject {
public:
class MotionController : public CObject {
public:
int _field_4;
bool _isEnabled;
public:
CMotionController() : _isEnabled(true) {}
public:
MotionController() : _isEnabled(true), _field_4(0) {}
virtual ~MotionController() {}
virtual bool load(MfcArchive &file);
void setEnabled() { _isEnabled = true; }
void clearEnabled() { _isEnabled = false; }
virtual void methodC() {}
virtual void method10() {}
virtual void clearEnabled() { _isEnabled = false; }
virtual void setEnabled() { _isEnabled = true; }
virtual void addObject(StaticANIObject *obj) {}
virtual int removeObject(StaticANIObject *obj) { return 0; }
virtual void freeItems() {}
virtual int method28() { return 0; }
virtual int method2C() { return 0; }
virtual int method30() { return 0; }
virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { return 0; }
virtual int changeCallback() { return 0; }
virtual int method3C() { return 0; }
virtual int method40() { return 0; }
virtual int method44() { return 0; }
virtual int method48() { return -1; }
virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { return 0; }
};
class CMctlCompoundArray : public Common::Array<CObject>, public CObject {
class MovGraphReact : public CObject {
// Empty
};
typedef Common::Array<CObject> MctlConnectionPointsArray;
class MctlCompoundArrayItem : public CObject {
friend class MctlCompound;
protected:
MotionController *_motionControllerObj;
MovGraphReact *_movGraphReactObj;
MctlConnectionPointsArray _connectionPoints;
int _field_20;
int _field_24;
int _field_28;
public:
MctlCompoundArrayItem() : _movGraphReactObj(0) {}
};
class MctlCompoundArray : public Common::Array<MctlCompoundArrayItem *>, public CObject {
public:
virtual bool load(MfcArchive &file);
};
class CMctlConnectionPointsArray : public Common::Array<CObject>, public CObject {
public:
virtual bool load(MfcArchive &file);
};
class CMctlCompound : public CMotionController {
CMctlCompoundArray _motionControllers;
class MctlCompound : public MotionController {
MctlCompoundArray _motionControllers;
public:
MctlCompound() { _objtype = kObjTypeMctlCompound; }
virtual bool load(MfcArchive &file);
virtual void addObject(StaticANIObject *obj);
void initMovGraph2();
virtual int removeObject(StaticANIObject *obj);
virtual void freeItems();
virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
void initMovGraph2();
};
class Unk2 : public CObject {
public:
int _items;
int _count;
public:
public:
Unk2() : _items(0), _count(0) {}
};
class CMovGraphNode : public CObject {
class MovGraphNode : public CObject {
public:
int _x;
int _y;
int _distance;
@ -84,30 +118,11 @@ class CMovGraphNode : public CObject {
int _field_14;
public:
CMovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) {}
MovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) {}
virtual bool load(MfcArchive &file);
};
class CMovGraphReact : public CObject {
// Empty
};
class CMctlCompoundArrayItem : public CObject {
friend class CMctlCompound;
protected:
CMotionController *_motionControllerObj;
CMovGraphReact *_movGraphReactObj;
CMctlConnectionPointsArray _connectionPoints;
int _field_20;
int _field_24;
int _field_28;
public:
CMctlCompoundArrayItem() : _movGraphReactObj(0) {}
};
class CReactParallel : public CMovGraphReact {
class ReactParallel : public MovGraphReact {
//CRgn _rgn;
int _x1;
int _y1;
@ -118,12 +133,12 @@ class CReactParallel : public CMovGraphReact {
Common::Point **_points;
public:
CReactParallel();
ReactParallel();
virtual bool load(MfcArchive &file);
void createRegion();
};
class CReactPolygonal : public CMovGraphReact {
class ReactPolygonal : public MovGraphReact {
//CRgn _rgn;
int _field_C;
int _field_10;
@ -131,32 +146,34 @@ class CReactPolygonal : public CMovGraphReact {
Common::Point **_points;
public:
CReactPolygonal();
ReactPolygonal();
virtual bool load(MfcArchive &file);
void createRegion();
};
class CMovGraphLink : public CObject {
CMovGraphNode *_movGraphNode1;
CMovGraphNode *_movGraphNode2;
CDWordArray _dwordArray1;
CDWordArray _dwordArray2;
class MovGraphLink : public CObject {
public:
MovGraphNode *_movGraphNode1;
MovGraphNode *_movGraphNode2;
DWordArray _dwordArray1;
DWordArray _dwordArray2;
int _flags;
int _field_38;
int _field_3C;
double _distance;
double _angle;
CMovGraphReact *_movGraphReact;
MovGraphReact *_movGraphReact;
char *_name;
public:
CMovGraphLink();
MovGraphLink();
virtual bool load(MfcArchive &file);
};
class CMovGraph : public CMotionController {
CObList _nodes;
CObList _links;
class MovGraph : public MotionController {
public:
ObList _nodes;
ObList _links;
int _field_44;
int _items;
int _itemsCount;
@ -164,13 +181,65 @@ class CMovGraph : public CMotionController {
Unk2 _unk2;
public:
CMovGraph();
MovGraph();
virtual bool load(MfcArchive &file);
virtual void addObject(StaticANIObject *obj);
virtual int removeObject(StaticANIObject *obj);
virtual void freeItems();
virtual int method28();
virtual int method2C();
virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
virtual int changeCallback();
virtual int method3C();
virtual int method44();
virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
virtual int method50();
double calcDistance(Common::Point *point, MovGraphLink *link, int flag);
MovGraphNode *calcOffset(int ox, int oy);
};
class CMctlConnectionPoint : public CObject {
class Movement;
struct MG2I {
int _movementId;
Movement *_mov;
int _mx;
int _my;
};
struct MovGraph2ItemSub {
int _staticsId2;
int _staticsId1;
MG2I _walk[3];
MG2I _turn[4];
MG2I _turnS[4];
};
struct MovGraph2Item {
int _objectId;
StaticANIObject *_obj;
MovGraph2ItemSub _subItems[4];
};
class MovGraph2 : public MovGraph {
public:
Common::Array<MovGraph2Item *> _items;
public:
virtual void addObject(StaticANIObject *obj);
virtual int removeObject(StaticANIObject *obj);
virtual void freeItems();
virtual MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
virtual MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId);
int getItemIndexByGameObjectId(int objectId);
bool initDirections(StaticANIObject *obj, MovGraph2Item *item);
};
class MctlConnectionPoint : public CObject {
public:
int _connectionX;
int _connectionY;
int _field_C;

View File

@ -69,27 +69,27 @@ union VarValue {
char *stringValue;
};
class CGameVar : public CObject {
class GameVar : public CObject {
public:
CGameVar *_nextVarObj;
CGameVar *_prevVarObj;
CGameVar *_parentVarObj;
CGameVar *_subVars;
CGameVar *_field_14;
GameVar *_nextVarObj;
GameVar *_prevVarObj;
GameVar *_parentVarObj;
GameVar *_subVars;
GameVar *_field_14;
char *_varName;
VarValue _value;
int _varType;
public:
CGameVar();
GameVar();
virtual bool load(MfcArchive &file);
CGameVar *getSubVarByName(const char *name);
GameVar *getSubVarByName(const char *name);
bool setSubVarAsInt(const char *name, int value);
int getSubVarAsInt(const char *name);
CGameVar *addSubVarAsInt(const char *name, int value);
bool addSubVar(CGameVar *subvar);
GameVar *addSubVarAsInt(const char *name, int value);
bool addSubVar(GameVar *subvar);
int getSubVarsCount();
CGameVar *getSubVarByIndex(int idx);
GameVar *getSubVarByIndex(int idx);
};
} // End of namespace Fullpipe

View File

@ -72,6 +72,7 @@ SceneTag::SceneTag() {
_field_4 = 0;
_scene = 0;
_tag = 0;
_sceneId = 0;
}
bool SceneTag::load(MfcArchive &file) {
@ -259,7 +260,7 @@ void Scene::init() {
if (_staticANIObjectList2.size() != _staticANIObjectList1.size()) {
_staticANIObjectList2.clear();
for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s)
for (PtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s)
_staticANIObjectList2.push_back(*s);
}
}
@ -273,7 +274,7 @@ StaticANIObject *Scene::getAniMan() {
}
StaticANIObject *Scene::getStaticANIObject1ById(int obj, int a3) {
for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) {
for (PtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) {
StaticANIObject *o = (StaticANIObject *)*s;
if (o->_id == obj && (a3 == -1 || o->_okeyCode == a3))
return o;
@ -327,7 +328,7 @@ void Scene::setPictureObjectsFlag4() {
}
PictureObject *Scene::getPictureObjectById(int objId, int flags) {
for (uint i = 0; i < _picObjList.size(); i++) {
for (uint i = 1; i < _picObjList.size(); i++) {
if (((PictureObject *)_picObjList[i])->_id == objId && ((PictureObject *)_picObjList[i])->_okeyCode == flags)
return (PictureObject *)_picObjList[i];
}
@ -371,16 +372,16 @@ MessageQueue *Scene::getMessageQueueByName(char *name) {
return 0;
}
void Scene::preloadMovements(CGameVar *var) {
CGameVar *preload = var->getSubVarByName("PRELOAD");
void Scene::preloadMovements(GameVar *var) {
GameVar *preload = var->getSubVarByName("PRELOAD");
if (!preload)
return;
for (CGameVar *i = preload->_subVars; i; i = i->_nextVarObj) {
for (GameVar *i = preload->_subVars; i; i = i->_nextVarObj) {
StaticANIObject *ani = getStaticANIObject1ByName(i->_varName, -1);
if (ani) {
CGameVar *subVars = i->_subVars;
GameVar *subVars = i->_subVars;
if (subVars) {
for (;subVars; subVars = subVars->_nextVarObj) {
@ -397,7 +398,7 @@ void Scene::preloadMovements(CGameVar *var) {
}
void Scene::initObjectCursors(const char *varname) {
CGameVar *cursorsVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(varname)->getSubVarByName("CURSORS");
GameVar *cursorsVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(varname)->getSubVarByName("CURSORS");
if (!cursorsVar || !cursorsVar->_subVars)
return;
@ -405,7 +406,7 @@ void Scene::initObjectCursors(const char *varname) {
int maxId = 0;
int minId = 0xffff;
for (CGameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) {
for (GameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) {
GameObject *obj = getPictureObjectByName(sub->_varName, -1);
if (obj || (obj = getStaticANIObject1ByName(sub->_varName, -1)) != 0) {
@ -421,7 +422,7 @@ void Scene::initObjectCursors(const char *varname) {
g_fullpipe->_objectIdCursors.resize(maxId - minId + 1);
for (CGameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) {
for (GameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) {
GameObject *obj = getPictureObjectByName(sub->_varName, -1);
if (!obj)
@ -441,7 +442,7 @@ bool Scene::compareObjPriority(const void *p1, const void *p2) {
return false;
}
void Scene::objectList_sortByPriority(CPtrList &list) {
void Scene::objectList_sortByPriority(PtrList &list) {
Common::sort(list.begin(), list.end(), Scene::compareObjPriority);
}
@ -453,12 +454,12 @@ void Scene::draw() {
objectList_sortByPriority(_staticANIObjectList2);
for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) {
for (PtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) {
((StaticANIObject *)*s)->draw2();
}
int priority = -1;
for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) {
for (PtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) {
drawContent(((StaticANIObject *)*s)->_priority, priority, false);
((StaticANIObject *)*s)->draw();
@ -526,7 +527,7 @@ int Scene::getPictureObjectIdAtPos(int x, int y) {
void Scene::update(int counterdiff) {
debug(0, "Scene::update(%d)", counterdiff);
for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s)
for (PtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s)
((StaticANIObject *)*s)->update(counterdiff);
}

View File

@ -31,10 +31,10 @@ class MessageQueue;
class Scene : public Background {
public:
CPtrList _staticANIObjectList1;
CPtrList _staticANIObjectList2;
CPtrList _messageQueueList;
CPtrList _faObjectList;
PtrList _staticANIObjectList1;
PtrList _staticANIObjectList2;
PtrList _messageQueueList;
PtrList _faObjectList;
Shadows *_shadows;
SoundList *_soundList;
int16 _sceneId;
@ -69,7 +69,7 @@ class Scene : public Background {
PictureObject *getPictureObjectById(int objId, int flags);
PictureObject *getPictureObjectByName(const char *name, int keyCode);
void deletePictureObject(PictureObject *obj);
void preloadMovements(CGameVar *var);
void preloadMovements(GameVar *var);
StaticANIObject *getStaticANIObjectAtPos(int x, int y);
PictureObject *getPictureObjectAtPos(int x, int y);
@ -79,7 +79,7 @@ class Scene : public Background {
private:
static bool compareObjPriority(const void *p1, const void *p2);
void objectList_sortByPriority(CPtrList &list);
void objectList_sortByPriority(PtrList &list);
};
class SceneTag : public CObject {
@ -88,7 +88,6 @@ class SceneTag : public CObject {
char *_tag;
Scene *_scene;
int16 _sceneId;
int16 _field_12;
public:
SceneTag();

View File

@ -75,7 +75,7 @@ Vars::Vars() {
}
bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) {
CGameVar *sceneVar;
GameVar *sceneVar;
Common::Point sceneDim;
Scene *scene = accessScene(entrance->_sceneId);
@ -137,21 +137,17 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) {
_aniMan->_statics = _aniMan->getStaticsById(ST_MAN_EMPTY);
_aniMan->setOXY(0, 0);
if (_aniMan) {
_aniMan2 = _aniMan;
CMctlCompound *cmp = getSc2MctlCompoundBySceneId(entrance->_sceneId);
cmp->initMovGraph2();
cmp->addObject(_aniMan);
cmp->setEnabled();
getGameLoaderInteractionController()->enableFlag24();
setInputDisabled(0);
} else {
_aniMan2 = 0;
}
_aniMan2 = _aniMan;
MctlCompound *cmp = getSc2MctlCompoundBySceneId(entrance->_sceneId);
cmp->initMovGraph2();
cmp->addObject(_aniMan);
cmp->setEnabled();
getGameLoaderInteractionController()->enableFlag24();
setInputDisabled(0);
scene->setPictureObjectsFlag4();
for (CPtrList::iterator s = scene->_staticANIObjectList1.begin(); s != scene->_staticANIObjectList1.end(); ++s) {
for (PtrList::iterator s = scene->_staticANIObjectList1.begin(); s != scene->_staticANIObjectList1.end(); ++s) {
StaticANIObject *o = (StaticANIObject *)*s;
o->setFlags(o->_flags & 0xFE7F);
}
@ -657,7 +653,7 @@ bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) {
}
void setElevatorButton(const char *name, int state) {
CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons);
GameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons);
if (var)
var->setSubVarAsInt(name, state);
@ -731,6 +727,8 @@ int global_messageHandler1(ExCommand *cmd) {
}
break;
case 36: // keydown
g_fullpipe->defHandleKeyDown(cmd->_keyCode);
switch (cmd->_keyCode) {
case '\x1B': // ESC
if (g_fullpipe->_currentScene) {
@ -768,7 +766,6 @@ int global_messageHandler1(ExCommand *cmd) {
cmd->_messageKind = 0;
break;
default:
g_fullpipe->defHandleKeyDown(cmd->_keyCode);
break;
}
break;
@ -1075,7 +1072,7 @@ int global_messageHandler3(ExCommand *cmd) {
return doSomeAnimation2(cmd->_parentId, cmd->_keyCode);
case 63:
if (cmd->_objtype == kObjTypeObjstateCommand) {
CObjstateCommand *c = (CObjstateCommand *)cmd;
ObjstateCommand *c = (ObjstateCommand *)cmd;
result = 1;
g_fullpipe->setObjectState(c->_objCommandName, c->_value);
}
@ -1312,6 +1309,63 @@ int global_messageHandler4(ExCommand *cmd) {
return 1;
}
int MovGraph_messageHandler(ExCommand *cmd) {
if (cmd->_messageKind != 17)
return 0;
if (cmd->_messageNum != 33)
return 0;
StaticANIObject *ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1);
if (!getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId))
return 0;
if (getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->_objtype != kObjTypeMovGraph || !ani)
return 0;
MovGraph *gr = (MovGraph *)getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId);
MovGraphLink *link = 0;
double mindistance = 1.0e10;
Common::Point point;
for (ObList::iterator i = gr->_links.begin(); i != gr->_links.end(); ++i) {
point.x = ani->_ox;
point.y = ani->_oy;
double dst = gr->calcDistance(&point, (MovGraphLink *)(*i), 0);
if (dst >= 0.0 && dst < mindistance) {
mindistance = dst;
link = (MovGraphLink *)(*i);
}
}
int top;
if (link) {
MovGraphNode *node = link->_movGraphNode1;
double sq = (ani->_oy - node->_y) * (ani->_oy - node->_y) + (ani->_ox - node->_x) * (ani->_ox - node->_x);
int off = (node->_field_14 >> 16) & 0xFF;
double off2 = ((link->_movGraphNode2->_field_14 >> 8) & 0xff) - off;
top = off + (int)(sqrt(sq) * off2 / link->_distance);
} else {
top = (gr->calcOffset(ani->_ox, ani->_oy)->_field_14 >> 8) & 0xff;
}
if (ani->_movement) {
ani->_movement->_currDynamicPhase->_rect->top = 255 - top;
return 0;
}
if (ani->_statics)
ani->_statics->_rect->top = 255 - top;
return 0;
}
int defaultUpdateCursor() {
g_fullpipe->updateCursorsCommon();
@ -1325,7 +1379,7 @@ int sceneIntro_updateCursor() {
}
void FullpipeEngine::setSwallowedEggsState() {
CGameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs);
GameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs);
g_vars->swallowedEgg1 = v->getSubVarByName(sO_Egg1);
g_vars->swallowedEgg2 = v->getSubVarByName(sO_Egg2);
@ -1348,7 +1402,7 @@ void sceneIntro_initScene(Scene *sc) {
if (g_fullpipe->_recordEvents || g_fullpipe->_inputArFlag)
g_vars->sceneIntro_skipIntro = false;
g_fullpipe->_modalObject = new CModalIntro;
g_fullpipe->_modalObject = new ModalIntro;
}
int sceneHandlerIntro(ExCommand *cmd) {
@ -1358,7 +1412,7 @@ int sceneHandlerIntro(ExCommand *cmd) {
}
void scene01_fixEntrance() {
CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME");
GameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME");
if (var->getSubVarAsInt("Entrance") == TrubaLeft)
var->setSubVarAsInt("Entrance", TrubaRight);
}

View File

@ -31,9 +31,9 @@ class Vars {
public:
Vars();
CGameVar *swallowedEgg1;
CGameVar *swallowedEgg2;
CGameVar *swallowedEgg3;
GameVar *swallowedEgg1;
GameVar *swallowedEgg2;
GameVar *swallowedEgg3;
StaticANIObject *sceneIntro_aniin1man;
bool sceneIntro_needSleep;

View File

@ -111,7 +111,7 @@ void Sound::setPanAndVolumeByStaticAni() {
debug(3, "STUB Sound::setPanAndVolumeByStaticAni()");
}
void FullpipeEngine::setSceneMusicParameters(CGameVar *var) {
void FullpipeEngine::setSceneMusicParameters(GameVar *var) {
warning("STUB: FullpipeEngine::setSceneMusicParameters()");
}

View File

@ -29,7 +29,6 @@ class Sound : public MemoryObject {
int _id;
char *_description;
int16 _objectId;
int16 _field_32;
int _directSoundBuffer;
int _directSoundBuffers[7];
byte *_soundData;

View File

@ -37,7 +37,7 @@
namespace Fullpipe {
bool FullpipeEngine::loadGam(const char *fname, int scene) {
_gameLoader = new CGameLoader();
_gameLoader = new GameLoader();
if (!_gameLoader->loadFile(fname))
return false;
@ -54,7 +54,7 @@ bool FullpipeEngine::loadGam(const char *fname, int scene) {
_inventory->rebuildItemRects();
for (CPtrList::iterator p = _inventory->getScene()->_picObjList.begin(); p != _inventory->getScene()->_picObjList.end(); ++p) {
for (PtrList::iterator p = _inventory->getScene()->_picObjList.begin(); p != _inventory->getScene()->_picObjList.end(); ++p) {
((MemoryObject *)((PictureObject *)*p)->_picture)->load();
}
@ -145,7 +145,7 @@ GameProject::~GameProject() {
free(_headerFilename);
}
CGameVar::CGameVar() {
GameVar::GameVar() {
_subVars = 0;
_parentVarObj = 0;
_nextVarObj = 0;
@ -156,7 +156,7 @@ CGameVar::CGameVar() {
_varName = 0;
}
bool CGameVar::load(MfcArchive &file) {
bool GameVar::load(MfcArchive &file) {
_varName = file.readPascalString();
_varType = file.readUint32LE();
@ -184,18 +184,18 @@ bool CGameVar::load(MfcArchive &file) {
}
file.incLevel();
_parentVarObj = (CGameVar *)file.readClass();
_prevVarObj = (CGameVar *)file.readClass();
_nextVarObj = (CGameVar *)file.readClass();
_field_14 = (CGameVar *)file.readClass();
_subVars = (CGameVar *)file.readClass();
_parentVarObj = (GameVar *)file.readClass();
_prevVarObj = (GameVar *)file.readClass();
_nextVarObj = (GameVar *)file.readClass();
_field_14 = (GameVar *)file.readClass();
_subVars = (GameVar *)file.readClass();
file.decLevel();
return true;
}
CGameVar *CGameVar::getSubVarByName(const char *name) {
CGameVar *sv = 0;
GameVar *GameVar::getSubVarByName(const char *name) {
GameVar *sv = 0;
if (_subVars != 0) {
sv = _subVars;
@ -205,8 +205,8 @@ CGameVar *CGameVar::getSubVarByName(const char *name) {
return sv;
}
bool CGameVar::setSubVarAsInt(const char *name, int value) {
CGameVar *var = getSubVarByName(name);
bool GameVar::setSubVarAsInt(const char *name, int value) {
GameVar *var = getSubVarByName(name);
if (var) {
if (var->_varType == 0) {
@ -217,7 +217,7 @@ bool CGameVar::setSubVarAsInt(const char *name, int value) {
return false;
}
var = new CGameVar();
var = new GameVar();
var->_varType = 0;
var->_value.intValue = value;
var->_varName = (char *)calloc(strlen(name) + 1, 1);
@ -226,8 +226,8 @@ bool CGameVar::setSubVarAsInt(const char *name, int value) {
return addSubVar(var);
}
int CGameVar::getSubVarAsInt(const char *name) {
CGameVar *var = getSubVarByName(name);
int GameVar::getSubVarAsInt(const char *name) {
GameVar *var = getSubVarByName(name);
if (var)
return var->_value.intValue;
@ -235,11 +235,11 @@ int CGameVar::getSubVarAsInt(const char *name) {
return 0;
}
CGameVar *CGameVar::addSubVarAsInt(const char *name, int value) {
GameVar *GameVar::addSubVarAsInt(const char *name, int value) {
if (getSubVarByName(name)) {
return 0;
} else {
CGameVar *var = new CGameVar();
GameVar *var = new GameVar();
var->_varType = 0;
var->_value.intValue = value;
@ -251,11 +251,11 @@ CGameVar *CGameVar::addSubVarAsInt(const char *name, int value) {
}
}
bool CGameVar::addSubVar(CGameVar *subvar) {
CGameVar *var = _subVars;
bool GameVar::addSubVar(GameVar *subvar) {
GameVar *var = _subVars;
if (var) {
for (CGameVar *i = var->_nextVarObj; i; i = i->_nextVarObj)
for (GameVar *i = var->_nextVarObj; i; i = i->_nextVarObj)
var = i;
var->_nextVarObj = subvar;
@ -273,9 +273,9 @@ bool CGameVar::addSubVar(CGameVar *subvar) {
return false;
}
int CGameVar::getSubVarsCount() {
int GameVar::getSubVarsCount() {
int res;
CGameVar *sub = _subVars;
GameVar *sub = _subVars;
for (res = 0; sub; res++)
sub = sub->_nextVarObj;
@ -283,8 +283,8 @@ int CGameVar::getSubVarsCount() {
return res;
}
CGameVar *CGameVar::getSubVarByIndex(int idx) {
CGameVar *sub = _subVars;
GameVar *GameVar::getSubVarByIndex(int idx) {
GameVar *sub = _subVars;
while (idx--) {
sub = sub->_nextVarObj;

View File

@ -33,7 +33,7 @@
namespace Fullpipe {
CStepArray::CStepArray() {
StepArray::StepArray() {
_points = 0;
_maxPointIndex = 0;
_currPointIndex = 0;
@ -41,7 +41,7 @@ CStepArray::CStepArray() {
_isEos = 0;
}
CStepArray::~CStepArray() {
StepArray::~StepArray() {
if (_pointsCount) {
for (int i = 0; i < _pointsCount; i++)
delete _points[i];
@ -52,7 +52,7 @@ CStepArray::~CStepArray() {
}
}
void CStepArray::clear() {
void StepArray::clear() {
_currPointIndex = 0;
_maxPointIndex = 0;
_isEos = 0;
@ -63,7 +63,7 @@ void CStepArray::clear() {
}
}
Common::Point *CStepArray::getCurrPoint(Common::Point *point) {
Common::Point *StepArray::getCurrPoint(Common::Point *point) {
if (_isEos || _points == 0) {
point->x = 0;
point->y = 0;
@ -73,7 +73,7 @@ Common::Point *CStepArray::getCurrPoint(Common::Point *point) {
return point;
}
bool CStepArray::gotoNextPoint() {
bool StepArray::gotoNextPoint() {
if (_currPointIndex < _maxPointIndex) {
_currPointIndex++;
return true;
@ -547,7 +547,7 @@ void StaticANIObject::draw2() {
}
MovTable *StaticANIObject::countMovements() {
CGameVar *preloadSubVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("PRELOAD");
GameVar *preloadSubVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("PRELOAD");
if (!preloadSubVar || preloadSubVar->getSubVarsCount() == 0)
return 0;
@ -561,7 +561,7 @@ MovTable *StaticANIObject::countMovements() {
GameObject *obj = (GameObject *)_movements[i];
movTable->movs[i] = 2;
for (CGameVar *sub = preloadSubVar->_subVars; sub; sub = sub->_nextVarObj) {
for (GameVar *sub = preloadSubVar->_subVars; sub; sub = sub->_nextVarObj) {
if (scumm_stricmp(obj->getName(), sub->_varName) == 0) {
movTable->movs[i] = 1;
break;
@ -573,7 +573,7 @@ MovTable *StaticANIObject::countMovements() {
}
void StaticANIObject::setSpeed(int speed) {
CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("SpeedUp");
GameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("SpeedUp");
if (!var)
return;
@ -1131,6 +1131,9 @@ Movement::Movement(Movement *src, StaticANIObject *ani) {
_currDynamicPhaseIndex = src->_currDynamicPhaseIndex;
_field_94 = 0;
_field_24 = 0;
_field_28 = 0;
_currMovement = src;
_ox = src->_ox;
_oy = src->_oy;
@ -1242,6 +1245,41 @@ Common::Point *Movement::getCurrDynamicPhaseXY(Common::Point &p) {
return &p;
}
Common::Point *Movement::calcSomeXY(Common::Point &p, int idx) {
int oldox = _ox;
int oldoy = _oy;
int oldidx = _currDynamicPhaseIndex;
int x = 0;
int y = 0;
if (!idx) {
Common::Point point;
_staticsObj1->getSomeXY(point);
int y1 = _my - point.y;
int x1 = _mx - point.x;
setDynamicPhaseIndex(0);
x = _currDynamicPhase->_someX + x1;
y = _currDynamicPhase->_someY + y1;
}
setOXY(x, y);
while (_currDynamicPhaseIndex != idx)
gotoNextFrame(0, 0);
p.x = _ox;
p.y = _oy;
setDynamicPhaseIndex(oldidx);
setOXY(oldox, oldoy);
return &p;
}
void Movement::setAlpha(int alpha) {
if (_currMovement)
for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) {
@ -1553,7 +1591,7 @@ bool Movement::gotoPrevFrame() {
_currDynamicPhaseIndex--;
if (_currDynamicPhaseIndex < 0)
_currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1;
_currDynamicPhaseIndex = _dynamicPhases.size() - 1;
}
updateCurrDynamicPhase();

View File

@ -29,7 +29,7 @@ namespace Fullpipe {
class ExCommand;
class CStepArray : public CObject {
class StepArray : public CObject {
int _currPointIndex;
Common::Point **_points;
int _maxPointIndex;
@ -37,8 +37,8 @@ class CStepArray : public CObject {
int _isEos;
public:
CStepArray();
~CStepArray();
StepArray();
~StepArray();
void clear();
int getCurrPointIndex() { return _currPointIndex; }
@ -118,7 +118,7 @@ class Movement : public GameObject {
int _field_50;
int _counterMax;
int _counter;
CPtrList _dynamicPhases;
PtrList _dynamicPhases;
int _field_78;
Common::Point **_framePosOffsets;
Movement *_currMovement;
@ -140,6 +140,8 @@ class Movement : public GameObject {
Common::Point *getCenter(Common::Point *p);
Common::Point *getDimensionsOfPhase(Common::Point *p, int phaseIndex);
Common::Point *calcSomeXY(Common::Point &p, int idx);
void initStatics(StaticANIObject *ani);
void updateCurrDynamicPhase();
@ -172,9 +174,9 @@ class StaticANIObject : public GameObject {
int _initialCounter;
int _callback1;
void (*_callback2)(int *);
CPtrList _movements;
CPtrList _staticsList;
CStepArray _stepArray;
PtrList _movements;
PtrList _staticsList;
StepArray _stepArray;
int16 _field_96;
int _messageQueueId;
int _messageNum;

View File

@ -44,14 +44,14 @@ bool CObject::loadFile(const char *fname) {
return load(archive);
}
bool CObList::load(MfcArchive &file) {
debug(5, "CObList::load()");
bool ObList::load(MfcArchive &file) {
debug(5, "ObList::load()");
int count = file.readCount();
debug(9, "CObList::count: %d:", count);
debug(9, "ObList::count: %d:", count);
for (int i = 0; i < count; i++) {
debug(9, "CObList::[%d]", i);
debug(9, "ObList::[%d]", i);
CObject *t = file.readClass();
push_back(t);
@ -60,8 +60,8 @@ bool CObList::load(MfcArchive &file) {
return true;
}
bool CObArray::load(MfcArchive &file) {
debug(5, "CObArray::load()");
bool ObArray::load(MfcArchive &file) {
debug(5, "ObArray::load()");
int count = file.readCount();
resize(count);
@ -75,11 +75,11 @@ bool CObArray::load(MfcArchive &file) {
return true;
}
bool CDWordArray::load(MfcArchive &file) {
debug(5, "CWordArray::load()");
bool DWordArray::load(MfcArchive &file) {
debug(5, "DWordArray::load()");
int count = file.readCount();
debug(9, "CDWordArray::count: %d", count);
debug(9, "DWordArray::count: %d", count);
resize(count);
@ -262,34 +262,34 @@ double MfcArchive::readDouble() {
enum {
kNullObject,
kCInteraction,
kInteraction,
kMessageQueue,
kExCommand,
kCObjstateCommand,
kCGameVar,
kCMctlCompound,
kCMovGraph,
kCMovGraphLink,
kCMovGraphNode,
kCReactParallel,
kCReactPolygonal
kObjstateCommand,
kGameVar,
kMctlCompound,
kMovGraph,
kMovGraphLink,
kMovGraphNode,
kReactParallel,
kReactPolygonal
};
const struct {
const char *name;
int id;
} classMap[] = {
{ "CInteraction", kCInteraction },
{ "CInteraction", kInteraction },
{ "MessageQueue", kMessageQueue },
{ "ExCommand", kExCommand },
{ "CObjstateCommand", kCObjstateCommand },
{ "CGameVar", kCGameVar },
{ "CMctlCompound", kCMctlCompound },
{ "CMovGraph", kCMovGraph },
{ "CMovGraphLink", kCMovGraphLink },
{ "CMovGraphNode", kCMovGraphNode },
{ "CReactParallel", kCReactParallel },
{ "CReactPolygonal", kCReactPolygonal },
{ "CObjstateCommand", kObjstateCommand },
{ "CGameVar", kGameVar },
{ "CMctlCompound", kMctlCompound },
{ "CMovGraph", kMovGraph },
{ "CMovGraphLink", kMovGraphLink },
{ "CMovGraphNode", kMovGraphNode },
{ "CReactParallel", kReactParallel },
{ "CReactPolygonal", kReactPolygonal },
{ 0, 0 }
};
@ -306,28 +306,28 @@ static CObject *createObject(int objectId) {
switch (objectId) {
case kNullObject:
return 0;
case kCInteraction:
return new CInteraction();
case kInteraction:
return new Interaction();
case kMessageQueue:
return new MessageQueue();
case kExCommand:
return new ExCommand();
case kCObjstateCommand:
return new CObjstateCommand();
case kCGameVar:
return new CGameVar();
case kCMctlCompound:
return new CMctlCompound();
case kCMovGraph:
return new CMovGraph();
case kCMovGraphLink:
return new CMovGraphLink();
case kCMovGraphNode:
return new CMovGraphNode();
case kCReactParallel:
return new CReactParallel();
case kCReactPolygonal:
return new CReactPolygonal();
case kObjstateCommand:
return new ObjstateCommand();
case kGameVar:
return new GameVar();
case kMctlCompound:
return new MctlCompound();
case kMovGraph:
return new MovGraph();
case kMovGraphLink:
return new MovGraphLink();
case kMovGraphNode:
return new MovGraphNode();
case kReactParallel:
return new ReactParallel();
case kReactPolygonal:
return new ReactPolygonal();
default:
error("Unknown objectId: %d", objectId);
}
@ -396,6 +396,8 @@ CObject *MfcArchive::parseClass(bool *isCopyReturned) {
if (_objectMap.size() < obTag) {
error("Object index too big: %d at 0x%08x", obTag, pos() - 2);
}
debug(7, "parseClass::obTag <%s>", lookupObjectId(_objectIdMap[obTag]));
res = _objectMap[obTag];
*isCopyReturned = true;

View File

@ -68,7 +68,9 @@ enum ObjType {
kObjTypeDefault,
kObjTypeObjstateCommand,
kObjTypeStaticANIObject,
kObjTypePictureObject
kObjTypePictureObject,
kObjTypeMovGraph,
kObjTypeMctlCompound
};
class CObject {
@ -82,7 +84,7 @@ class CObject {
bool loadFile(const char *fname);
};
class CObList : public Common::List<CObject *>, public CObject {
class ObList : public Common::List<CObject *>, public CObject {
public:
virtual bool load(MfcArchive &file);
};
@ -97,9 +99,6 @@ class MemoryObject : CObject {
int _mfield_C;
int _mfield_10;
char _mfield_14;
char _mfield_15;
char _mfield_16;
char _mfield_17;
byte *_data;
int _dataSize;
int _mflags;
@ -134,17 +133,17 @@ class MemoryObject2 : public MemoryObject {
void copyData(byte *src, int dataSize);
};
class CObArray : public Common::Array<CObject>, public CObject {
class ObArray : public Common::Array<CObject>, public CObject {
public:
virtual bool load(MfcArchive &file);
};
class CDWordArray : public Common::Array<int32>, public CObject {
class DWordArray : public Common::Array<int32>, public CObject {
public:
virtual bool load(MfcArchive &file);
};
typedef Common::Array<void *> CPtrList;
typedef Common::Array<void *> PtrList;
char *genFileName(int superId, int sceneId, const char *ext);
byte *transCyrillic(byte *s);

View File

@ -28,6 +28,7 @@
#include "groovie/groovie.h"
#include "common/debug.h"
#include "common/substream.h"
#include "common/textconsole.h"
#include "graphics/palette.h"
@ -435,19 +436,20 @@ bool ROQPlayer::processBlockStill(ROQBlockHeader &blockHeader) {
warning("Groovie::ROQ: JPEG frame (unfinished)");
Graphics::JPEGDecoder *jpg = new Graphics::JPEGDecoder();
jpg->loadStream(*_file);
const byte *y = (const byte *)jpg->getComponent(1)->getPixels();
const byte *u = (const byte *)jpg->getComponent(2)->getPixels();
const byte *v = (const byte *)jpg->getComponent(3)->getPixels();
jpg->setOutputColorSpace(Graphics::JPEGDecoder::kColorSpaceYUV);
uint32 startPos = _file->pos();
Common::SeekableSubReadStream subStream(_file, startPos, startPos + blockHeader.size, DisposeAfterUse::NO);
jpg->loadStream(subStream);
const Graphics::Surface *srcSurf = jpg->getSurface();
const byte *src = (const byte *)srcSurf->getPixels();
byte *ptr = (byte *)_currBuf->getPixels();
for (int i = 0; i < _currBuf->w * _currBuf->h; i++) {
*ptr++ = *y++;
*ptr++ = *u++;
*ptr++ = *v++;
}
memcpy(ptr, src, _currBuf->w * _currBuf->h * srcSurf->format.bytesPerPixel);
delete jpg;
_file->seek(startPos + blockHeader.size);
return true;
}

View File

@ -131,7 +131,8 @@ void BlbArchive::load(BlbArchiveEntry *entry, byte *buffer, uint32 size) {
break;
case 3: // DCL-compressed
if (!Common::decompressDCL(&_fd, buffer, entry->diskSize, entry->size))
error("BlbArchive::load() Error during decompression of %08X", entry->fileHash);
error("BlbArchive::load() Error during decompression of %08X (offset: %d, disk size: %d, size: %d)",
entry->fileHash, entry->offset, entry->diskSize, entry->size);
break;
default:
error("BlbArchive::load() Unknown compression type %d", entry->comprType);

View File

@ -252,7 +252,7 @@ bool Console::Cmd_DumpResource(int argc, const char **argv) {
if (!handle.isValid()) {
DebugPrintf("Invalid resource hash\n");
} else {
_vm->_res->loadResource(handle);
_vm->_res->loadResource(handle, _vm->applyResourceFixes());
Common::DumpFile outFile;
outFile.open(outFileName);
outFile.write(handle.data(), handle.size());

View File

@ -52,6 +52,10 @@ Common::Platform NeverhoodEngine::getPlatform() const {
return _gameDescription->desc.platform;
}
Common::Language NeverhoodEngine::getLanguage() const {
return _gameDescription->desc.language;
}
uint16 NeverhoodEngine::getVersion() const {
return _gameDescription->version;
}
@ -60,6 +64,10 @@ bool NeverhoodEngine::isDemo() const {
return _gameDescription->desc.flags & ADGF_DEMO;
}
bool NeverhoodEngine::applyResourceFixes() const {
return getLanguage() == Common::RU_RUS;
}
}
static const PlainGameDescriptor neverhoodGames[] = {

View File

@ -411,7 +411,9 @@ void GameModule::checkRequests() {
}
if (_restoreGameRequested) {
_restoreGameRequested = false;
_vm->_audioResourceMan->stopAllMusic();
_vm->_audioResourceMan->stopAllSounds();
_vm->_soundMan->stopAllMusic();
_vm->_soundMan->stopAllSounds();
delete _childObject;
delete _prevChildObject;

View File

@ -160,7 +160,8 @@ void MenuModule::updateScene() {
createScene(MAKING_OF, -1);
break;
case kMainMenuToggleMusic:
// TODO Toggle music 0048A367
_vm->toggleMusic(!_vm->musicIsEnabled());
_vm->_mixer->muteSoundType(Audio::Mixer::kMusicSoundType, !_vm->musicIsEnabled());
createScene(MAIN_MENU, -1);
break;
case kMainMenuDeleteGame:
@ -353,11 +354,11 @@ MainMenu::MainMenu(NeverhoodEngine *vm, Module *parentModule)
setPalette(0x08C0020C);
insertScreenMouse(0x00208084);
insertStaticSprite(0x41137051, 100);
insertStaticSprite(0xC10B2015, 100);
insertStaticSprite(0x41137051, 100); // "Options" header text
insertStaticSprite(0xC10B2015, 100); // Button texts
// TODO Only if music is enabled
_musicOnButton = insertStaticSprite(0x0C24C0EE, 100);
if (!_vm->musicIsEnabled())
insertStaticSprite(0x0C24C0EE, 100); // "Music is off" button
for (uint buttonIndex = 0; buttonIndex < 9; ++buttonIndex) {
Sprite *menuButton = insertSprite<MenuButton>(this, buttonIndex,
@ -573,6 +574,7 @@ TextEditWidget::TextEditWidget(NeverhoodEngine *vm, int16 x, int16 y, GameStateM
_maxVisibleChars = (_rect.x2 - _rect.x1) / _fontSurface->getCharWidth();
_cursorPos = 0;
_textLabelWidget = NULL;
SetUpdateHandler(&TextEditWidget::update);
SetMessageHandler(&TextEditWidget::handleMessage);

View File

@ -79,7 +79,6 @@ class MainMenu : public Scene {
public:
MainMenu(NeverhoodEngine *vm, Module *parentModule);
protected:
Sprite *_musicOnButton;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};

View File

@ -33,6 +33,7 @@ MODULE_OBJS = \
modules/module2600.o \
modules/module2700.o \
modules/module2800.o \
modules/module2800_sprites.o \
modules/module2900.o \
modules/module3000.o \
mouse.o \

View File

@ -1012,7 +1012,7 @@ void AsScene1002VenusFlyTrap::swallowKlaymen() {
}
AsScene1002OutsideDoorBackground::AsScene1002OutsideDoorBackground(NeverhoodEngine *vm)
: AnimatedSprite(vm, 1200), _countdown(0) {
: AnimatedSprite(vm, 1200), _countdown(0), _isDoorClosed(true) {
createSurface(850, 186, 212);
_x = 320;

View File

@ -155,8 +155,6 @@ protected:
class SsScene1201Tnt : public StaticSprite {
public:
SsScene1201Tnt(NeverhoodEngine *vm, uint32 elemIndex, uint32 pointIndex, int16 clipY2);
protected:
uint32 _elemIndex;
};
class Scene1201 : public Scene {

View File

@ -630,7 +630,7 @@ void AsScene1303Balloon::stPopBalloon() {
}
Scene1303::Scene1303(NeverhoodEngine *vm, Module *parentModule)
: Scene(vm, parentModule) {
: Scene(vm, parentModule), _asBalloon(NULL) {
SetMessageHandler(&Scene1303::handleMessage);

View File

@ -33,6 +33,7 @@
#include "neverhood/modules/module2100.h"
#include "neverhood/modules/module2200.h"
#include "neverhood/modules/module2800.h"
#include "neverhood/modules/module2800_sprites.h"
#include "neverhood/diskplayerscene.h"
namespace Neverhood {

File diff suppressed because it is too large Load Diff

View File

@ -70,38 +70,7 @@ protected:
void changeTuneStatus(int prevTuneStatus, int newTuneStatus);
};
class AsScene2803LightCord : public AnimatedSprite {
public:
AsScene2803LightCord(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int16 x, int16 y);
void stPulled();
void stIdle();
void setFileHashes(uint32 fileHash1, uint32 fileHash2);
protected:
Scene *_parentScene;
uint32 _fileHash1, _fileHash2;
bool _isPulled, _isBusy;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmPulled(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2803TestTubeOne : public AnimatedSprite {
public:
AsScene2803TestTubeOne(NeverhoodEngine *vm, uint32 fileHash1, uint32 fileHash2);
protected:
uint32 _fileHash1, _fileHash2;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2803Rope : public AnimatedSprite {
public:
AsScene2803Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x);
protected:
Scene *_parentScene;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmReleased(int messageNum, const MessageParam &param, Entity *sender);
void stReleased();
void stHide();
};
class AsScene2803LightCord;
class Scene2803 : public Scene {
public:
@ -158,101 +127,8 @@ protected:
void updatePaletteArea(bool instantly);
};
class Scene2804;
class SsScene2804RedButton : public StaticSprite {
public:
SsScene2804RedButton(NeverhoodEngine *vm, Scene2804 *parentScene);
protected:
Scene2804 *_parentScene;
int _countdown;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2804LightCoil : public StaticSprite {
public:
SsScene2804LightCoil(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2804BeamCoilBody : public StaticSprite {
public:
SsScene2804BeamCoilBody(NeverhoodEngine *vm);
};
class SsScene2804LightTarget : public StaticSprite {
public:
SsScene2804LightTarget(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2804Flash : public StaticSprite {
public:
SsScene2804Flash(NeverhoodEngine *vm);
void show();
};
class AsScene2804CrystalWaves : public AnimatedSprite {
public:
AsScene2804CrystalWaves(NeverhoodEngine *vm, uint crystalIndex);
void show();
void hide();
protected:
uint _crystalIndex;
};
class AsScene2804Crystal : public AnimatedSprite {
public:
AsScene2804Crystal(NeverhoodEngine *vm, AsScene2804CrystalWaves *asCrystalWaves, uint crystalIndex);
void show();
void hide();
void activate();
int16 getColorNum() const { return _colorNum; }
protected:
AsScene2804CrystalWaves *_asCrystalWaves;
uint _crystalIndex;
int16 _colorNum;
bool _isLightOn;
bool _isShowing;
};
class SsScene2804CrystalButton : public StaticSprite {
public:
SsScene2804CrystalButton(NeverhoodEngine *vm, Scene2804 *parentScene, AsScene2804Crystal *asCrystal, uint crystalIndex);
protected:
Scene2804 *_parentScene;
AsScene2804Crystal *_asCrystal;
uint _crystalIndex;
int _countdown;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2804BeamCoil : public AnimatedSprite {
public:
AsScene2804BeamCoil(NeverhoodEngine *vm, Scene *parentScene, SsScene2804BeamCoilBody *ssBeamCoilBody);
virtual ~AsScene2804BeamCoil();
protected:
Scene *_parentScene;
SsScene2804BeamCoilBody *_ssBeamCoilBody;
int _countdown;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
void show();
void hide();
void stBeaming();
uint32 hmBeaming(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2804BeamTarget : public AnimatedSprite {
public:
AsScene2804BeamTarget(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2804Flash;
class AsScene2804Crystal;
class Scene2804 : public Scene {
public:
@ -284,13 +160,6 @@ protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2806Spew : public AnimatedSprite {
public:
AsScene2806Spew(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class Scene2806 : public Scene {
public:
Scene2806(NeverhoodEngine *vm, Module *parentModule, int which);
@ -315,63 +184,8 @@ protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2808Dispenser : public StaticSprite {
public:
SsScene2808Dispenser(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum, int testTubeIndex);
void startCountdown(int index);
protected:
Scene *_parentScene;
int _countdown;
int _testTubeSetNum, _testTubeIndex;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808TestTube : public AnimatedSprite {
public:
AsScene2808TestTube(NeverhoodEngine *vm, int testTubeSetNum, int testTubeIndex, SsScene2808Dispenser *ssDispenser);
void fill();
void flush();
uint32 getFillLevel() const { return _fillLevel; }
protected:
SsScene2808Dispenser *_ssDispenser;
int _testTubeSetNum;
uint32 _fillLevel;
int _testTubeIndex;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808Handle : public AnimatedSprite {
public:
AsScene2808Handle(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum);
void activate();
void stActivated();
protected:
Scene *_parentScene;
int _testTubeSetNum;
bool _isActivated;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmActivating(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808Flow : public AnimatedSprite {
public:
AsScene2808Flow(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum);
void start();
void stKeepFlowing();
protected:
Scene *_parentScene;
int _testTubeSetNum;
uint32 hmFlowing(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808LightEffect : public AnimatedSprite {
public:
AsScene2808LightEffect(NeverhoodEngine *vm, int which);
protected:
int _countdown;
void update();
};
class AsScene2808Flow;
class AsScene2808TestTube;
class Scene2808 : public Scene {
public:
@ -389,13 +203,6 @@ protected:
bool isAnyTestTubeFilled();
};
class AsScene2809Spew : public AnimatedSprite {
public:
AsScene2809Spew(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class Scene2809 : public Scene {
public:
Scene2809(NeverhoodEngine *vm, Module *parentModule, int which);
@ -413,14 +220,6 @@ protected:
void findClosestPoint();
};
class AsScene2810Rope : public AnimatedSprite {
public:
AsScene2810Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x);
protected:
Scene *_parentScene;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class Scene2810 : public Scene {
public:
Scene2810(NeverhoodEngine *vm, Module *parentModule, int which);
@ -440,31 +239,6 @@ protected:
void insertKlaymenLadder();
};
class AsScene2812Winch : public AnimatedSprite {
public:
AsScene2812Winch(NeverhoodEngine *vm);
virtual ~AsScene2812Winch();
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2812Rope : public AnimatedSprite {
public:
AsScene2812Rope(NeverhoodEngine *vm, Scene *parentScene);
protected:
Scene *_parentScene;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmRopingDown(int messageNum, const MessageParam &param, Entity *sender);
void stRopingDown();
};
class AsScene2812TrapDoor : public AnimatedSprite {
public:
AsScene2812TrapDoor(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class Scene2812 : public Scene {
public:
Scene2812(NeverhoodEngine *vm, Module *parentModule, int which);

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,268 @@
/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#ifndef NEVERHOOD_MODULES_MODULE2800_SPRITES_H
#define NEVERHOOD_MODULES_MODULE2800_SPRITES_H
#include "neverhood/neverhood.h"
#include "neverhood/module.h"
#include "neverhood/scene.h"
namespace Neverhood {
class AsScene2803LightCord : public AnimatedSprite {
public:
AsScene2803LightCord(NeverhoodEngine *vm, Scene *parentScene, uint32 fileHash1, uint32 fileHash2, int16 x, int16 y);
void stPulled();
void stIdle();
void setFileHashes(uint32 fileHash1, uint32 fileHash2);
protected:
Scene *_parentScene;
uint32 _fileHash1, _fileHash2;
bool _isPulled, _isBusy;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmPulled(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2803TestTubeOne : public AnimatedSprite {
public:
AsScene2803TestTubeOne(NeverhoodEngine *vm, uint32 fileHash1, uint32 fileHash2);
protected:
uint32 _fileHash1, _fileHash2;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2803Rope : public AnimatedSprite {
public:
AsScene2803Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x);
protected:
Scene *_parentScene;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmReleased(int messageNum, const MessageParam &param, Entity *sender);
void stReleased();
void stHide();
};
class Scene2804;
class SsScene2804RedButton : public StaticSprite {
public:
SsScene2804RedButton(NeverhoodEngine *vm, Scene2804 *parentScene);
protected:
Scene2804 *_parentScene;
int _countdown;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2804LightCoil : public StaticSprite {
public:
SsScene2804LightCoil(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2804BeamCoilBody : public StaticSprite {
public:
SsScene2804BeamCoilBody(NeverhoodEngine *vm);
};
class SsScene2804LightTarget : public StaticSprite {
public:
SsScene2804LightTarget(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2804Flash : public StaticSprite {
public:
SsScene2804Flash(NeverhoodEngine *vm);
void show();
};
class AsScene2804CrystalWaves : public AnimatedSprite {
public:
AsScene2804CrystalWaves(NeverhoodEngine *vm, uint crystalIndex);
void show();
void hide();
protected:
uint _crystalIndex;
};
class AsScene2804Crystal : public AnimatedSprite {
public:
AsScene2804Crystal(NeverhoodEngine *vm, AsScene2804CrystalWaves *asCrystalWaves, uint crystalIndex);
void show();
void hide();
void activate();
int16 getColorNum() const { return _colorNum; }
protected:
AsScene2804CrystalWaves *_asCrystalWaves;
uint _crystalIndex;
int16 _colorNum;
bool _isLightOn;
bool _isShowing;
};
class SsScene2804CrystalButton : public StaticSprite {
public:
SsScene2804CrystalButton(NeverhoodEngine *vm, Scene2804 *parentScene, AsScene2804Crystal *asCrystal, uint crystalIndex);
protected:
Scene2804 *_parentScene;
AsScene2804Crystal *_asCrystal;
uint _crystalIndex;
int _countdown;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2804BeamCoil : public AnimatedSprite {
public:
AsScene2804BeamCoil(NeverhoodEngine *vm, Scene *parentScene, SsScene2804BeamCoilBody *ssBeamCoilBody);
virtual ~AsScene2804BeamCoil();
protected:
Scene *_parentScene;
SsScene2804BeamCoilBody *_ssBeamCoilBody;
int _countdown;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
void show();
void hide();
void stBeaming();
uint32 hmBeaming(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2804BeamTarget : public AnimatedSprite {
public:
AsScene2804BeamTarget(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2806Spew : public AnimatedSprite {
public:
AsScene2806Spew(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class SsScene2808Dispenser : public StaticSprite {
public:
SsScene2808Dispenser(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum, int testTubeIndex);
void startCountdown(int index);
protected:
Scene *_parentScene;
int _countdown;
int _testTubeSetNum, _testTubeIndex;
void update();
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808TestTube : public AnimatedSprite {
public:
AsScene2808TestTube(NeverhoodEngine *vm, int testTubeSetNum, int testTubeIndex, SsScene2808Dispenser *ssDispenser);
void fill();
void flush();
uint32 getFillLevel() const { return _fillLevel; }
protected:
SsScene2808Dispenser *_ssDispenser;
int _testTubeSetNum;
uint32 _fillLevel;
int _testTubeIndex;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808Handle : public AnimatedSprite {
public:
AsScene2808Handle(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum);
void activate();
void stActivated();
protected:
Scene *_parentScene;
int _testTubeSetNum;
bool _isActivated;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmActivating(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808Flow : public AnimatedSprite {
public:
AsScene2808Flow(NeverhoodEngine *vm, Scene *parentScene, int testTubeSetNum);
void start();
void stKeepFlowing();
protected:
Scene *_parentScene;
int _testTubeSetNum;
uint32 hmFlowing(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2808LightEffect : public AnimatedSprite {
public:
AsScene2808LightEffect(NeverhoodEngine *vm, int which);
protected:
int _countdown;
void update();
};
class AsScene2809Spew : public AnimatedSprite {
public:
AsScene2809Spew(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2810Rope : public AnimatedSprite {
public:
AsScene2810Rope(NeverhoodEngine *vm, Scene *parentScene, int16 x);
protected:
Scene *_parentScene;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2812Winch : public AnimatedSprite {
public:
AsScene2812Winch(NeverhoodEngine *vm);
virtual ~AsScene2812Winch();
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
class AsScene2812Rope : public AnimatedSprite {
public:
AsScene2812Rope(NeverhoodEngine *vm, Scene *parentScene);
protected:
Scene *_parentScene;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
uint32 hmRopingDown(int messageNum, const MessageParam &param, Entity *sender);
void stRopingDown();
};
class AsScene2812TrapDoor : public AnimatedSprite {
public:
AsScene2812TrapDoor(NeverhoodEngine *vm);
protected:
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
};
} // End of namespace Neverhood
#endif /* NEVERHOOD_MODULES_MODULE2800_SPRITES_H */

View File

@ -109,6 +109,7 @@ Common::Error NeverhoodEngine::run() {
_isSaveAllowed = true;
_updateSound = true;
_enableMusic = !_mixer->isSoundTypeMuted(Audio::Mixer::kMusicSoundType);
if (isDemo()) {
// Adjust this navigation list for the demo version

View File

@ -72,8 +72,10 @@ public:
uint32 getFeatures() const;
uint16 getVersion() const;
Common::Platform getPlatform() const;
Common::Language getLanguage() const;
bool hasFeature(EngineFeature f) const;
bool isDemo() const;
bool applyResourceFixes() const;
Common::String getTargetName() { return _targetName; };
Common::RandomSource *_rnd;
@ -135,9 +137,12 @@ public:
NPoint getMousePos();
void toggleSoundUpdate(bool state) { _updateSound = state; }
void toggleMusic(bool state) { _enableMusic = state; }
bool musicIsEnabled() { return _enableMusic; }
private:
bool _updateSound;
bool _enableMusic;
};

View File

@ -66,6 +66,11 @@ void Palette::init() {
_status = 0;
_palette = new byte[1024];
_basePalette = new byte[1024];
_palCounter = 0;
_fadeToR = 0;
_fadeToG = 0;
_fadeToB = 0;
_fadeStep = 0;
}
void Palette::usePalette() {

View File

@ -53,7 +53,7 @@ bool SpriteResource::load(uint32 fileHash, bool doLoadPosition) {
unload();
_vm->_res->queryResource(fileHash, _resourceHandle);
if (_resourceHandle.isValid() && _resourceHandle.type() == kResTypeBitmap) {
_vm->_res->loadResource(_resourceHandle);
_vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
const byte *spriteData = _resourceHandle.data();
NPoint *position = doLoadPosition ? &_position : NULL;
parseBitmapResource(spriteData, &_rle, &_dimensions, position, NULL, &_pixels);
@ -83,7 +83,7 @@ bool PaletteResource::load(uint32 fileHash) {
_vm->_res->queryResource(fileHash, _resourceHandle);
if (_resourceHandle.isValid() &&
(_resourceHandle.type() == kResTypeBitmap || _resourceHandle.type() == kResTypePalette)) {
_vm->_res->loadResource(_resourceHandle);
_vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
_palette = _resourceHandle.data();
// Check if the palette is stored in a bitmap
if (_resourceHandle.type() == kResTypeBitmap)
@ -144,7 +144,7 @@ bool AnimResource::load(uint32 fileHash) {
uint16 frameListStartOfs, frameCount;
uint32 spriteDataOfs, paletteDataOfs;
_vm->_res->loadResource(_resourceHandle);
_vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
resourceData = _resourceHandle.data();
animListCount = READ_LE_UINT16(resourceData);
@ -323,7 +323,7 @@ void TextResource::load(uint32 fileHash) {
unload();
_vm->_res->queryResource(fileHash, _resourceHandle);
if (_resourceHandle.isValid() && _resourceHandle.type() == kResTypeText) {
_vm->_res->loadResource(_resourceHandle);
_vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
_textData = _resourceHandle.data();
_count = READ_LE_UINT32(_textData);
}
@ -359,7 +359,7 @@ void DataResource::load(uint32 fileHash) {
unload();
_vm->_res->queryResource(fileHash, _resourceHandle);
if (_resourceHandle.isValid() && _resourceHandle.type() == kResTypeData) {
_vm->_res->loadResource(_resourceHandle);
_vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
data = _resourceHandle.data();
dataSize = _resourceHandle.size();
}

View File

@ -85,7 +85,25 @@ void ResourceMan::queryResource(uint32 fileHash, ResourceHandle &resourceHandle)
resourceHandle._extData = firstEntry ? firstEntry->archiveEntry->extData : NULL;
}
void ResourceMan::loadResource(ResourceHandle &resourceHandle) {
struct EntrySizeFix {
uint32 fileHash;
uint32 offset;
uint32 diskSize;
uint32 size;
uint32 fixedSize;
};
static const EntrySizeFix entrySizeFixes[] = {
// fileHash offset diskSize size fixedSize
// Fixes for the Russian "Dyadyushka Risech" version
// TODO
// Fixes for the Russian "Fargus" version
// TODO
//
{ 0, 0, 0, 0, 0 }
};
void ResourceMan::loadResource(ResourceHandle &resourceHandle, bool applyResourceFixes) {
resourceHandle._data = NULL;
if (resourceHandle.isValid()) {
const uint32 fileHash = resourceHandle.fileHash();
@ -97,8 +115,19 @@ void ResourceMan::loadResource(ResourceHandle &resourceHandle) {
if (resourceData->data != NULL) {
resourceData->dataRefCount++;
} else {
resourceData->data = new byte[resourceHandle._resourceFileEntry->archiveEntry->size];
resourceHandle._resourceFileEntry->archive->load(resourceHandle._resourceFileEntry->archiveEntry, resourceData->data, 0);
BlbArchiveEntry *entry = resourceHandle._resourceFileEntry->archiveEntry;
// Apply fixes for broken resources in Russian versions
if (applyResourceFixes) {
for (const EntrySizeFix *cur = entrySizeFixes; cur->fileHash > 0; ++cur) {
if (entry->fileHash == cur->fileHash && entry->offset == cur->offset &&
entry->diskSize == cur->diskSize && entry->size == cur->size)
entry->size = cur->fixedSize;
}
}
resourceData->data = new byte[entry->size];
resourceHandle._resourceFileEntry->archive->load(entry, resourceData->data, 0);
resourceData->dataRefCount = 1;
}
resourceHandle._data = resourceData->data;

View File

@ -78,7 +78,7 @@ public:
const ResourceFileEntry& getEntry(uint index) { return _entries[index]; }
uint getEntryCount() { return _entries.size(); }
void queryResource(uint32 fileHash, ResourceHandle &resourceHandle);
void loadResource(ResourceHandle &resourceHandle);
void loadResource(ResourceHandle &resourceHandle, bool applyResourceFixes);
void unloadResource(ResourceHandle &resourceHandle);
void purgeResources();
protected:

View File

@ -50,6 +50,9 @@ Scene::Scene(NeverhoodEngine *vm, Module *parentModule)
_smackerPlayer = NULL;
_isMessageListBusy = false;
_messageValue = -1;
_messageListStatus = 0;
_messageListCount = 0;
_messageListIndex = 0;
_backgroundFileHash = _cursorFileHash = 0;

View File

@ -204,8 +204,6 @@ protected:
// Used for debugging
uint32 _backgroundFileHash, _cursorFileHash; // for StaticScene and all Scene* classes
void (Entity::*_savedUpdateHandlerCb)();
uint32 (Entity::*_savedMessageHandlerCb)(int messageNum, const MessageParam &param, Entity *sender);
int _messageValue;
uint32 handleMessage(int messageNum, const MessageParam &param, Entity *sender);
bool queryPositionSprite(int16 mouseX, int16 mouseY);

View File

@ -27,7 +27,8 @@ namespace Neverhood {
Screen::Screen(NeverhoodEngine *vm)
: _vm(vm), _paletteData(NULL), _paletteChanged(false), _smackerDecoder(NULL),
_yOffset(0), _fullRefresh(false) {
_yOffset(0), _fullRefresh(false), _frameDelay(0), _savedSmackerDecoder(NULL),
_savedFrameDelay(0), _savedYOffset(0) {
_ticks = _vm->_system->getMillis();

View File

@ -250,13 +250,26 @@ void SoundItem::update() {
// SoundMan
SoundMan::SoundMan(NeverhoodEngine *vm)
: _vm(vm), _soundIndex1(-1), _soundIndex2(-1), _soundIndex3(-1) {
: _vm(vm), _soundIndex1(-1), _soundIndex2(-1), _soundIndex3(-1),
_initialCountdown(0), _playOnceAfterCountdown(false),
_initialCountdown3(0), _playOnceAfterCountdown3(false) {
}
SoundMan::~SoundMan() {
stopAllMusic();
stopAllSounds();
}
void SoundMan::stopAllMusic() {
for (uint i = 0; i < _musicItems.size(); ++i) {
if (_musicItems[i]) {
_musicItems[i]->stopMusic(0, 0);
delete _musicItems[i];
_musicItems[i] = NULL;
}
}
}
void SoundMan::stopAllSounds() {
for (uint i = 0; i < _soundItems.size(); ++i) {
if (_soundItems[i]) {
@ -265,13 +278,6 @@ void SoundMan::stopAllSounds() {
_soundItems[i] = NULL;
}
}
for (uint i = 0; i < _musicItems.size(); ++i) {
if (_musicItems[i]) {
_musicItems[i]->stopMusic(0, 0);
delete _musicItems[i];
_musicItems[i] = NULL;
}
}
_soundIndex1 = _soundIndex2 = _soundIndex3 = -1;
}
@ -573,7 +579,7 @@ AudioResourceManSoundItem::AudioResourceManSoundItem(NeverhoodEngine *vm, uint32
void AudioResourceManSoundItem::loadSound() {
if (!_data && _resourceHandle.isValid() &&
(_resourceHandle.type() == kResTypeSound || _resourceHandle.type() == kResTypeMusic)) {
_vm->_res->loadResource(_resourceHandle);
_vm->_res->loadResource(_resourceHandle, _vm->applyResourceFixes());
_data = _resourceHandle.data();
}
}
@ -623,7 +629,8 @@ bool AudioResourceManSoundItem::isPlaying() {
AudioResourceManMusicItem::AudioResourceManMusicItem(NeverhoodEngine *vm, uint32 fileHash)
: _vm(vm), _fileHash(fileHash), _terminate(false), _canRestart(false),
_volume(100), _panning(50), _start(false), _isFadingIn(false), _isFadingOut(false), _isPlaying(false) {
_volume(100), _panning(50), _start(false), _isFadingIn(false), _isFadingOut(false), _isPlaying(false),
_fadeVolume(0), _fadeVolumeStep(0) {
}
@ -724,14 +731,7 @@ AudioResourceMan::AudioResourceMan(NeverhoodEngine *vm)
: _vm(vm) {
}
void AudioResourceMan::stopAllSounds() {
for (uint i = 0; i < _soundItems.size(); ++i) {
if (_soundItems[i]) {
_soundItems[i]->stopSound();
delete _soundItems[i];
_soundItems[i] = NULL;
}
}
void AudioResourceMan::stopAllMusic() {
for (uint i = 0; i < _musicItems.size(); ++i) {
if (_musicItems[i]) {
_musicItems[i]->stopMusic(0);
@ -741,7 +741,18 @@ void AudioResourceMan::stopAllSounds() {
}
}
void AudioResourceMan::stopAllSounds() {
for (uint i = 0; i < _soundItems.size(); ++i) {
if (_soundItems[i]) {
_soundItems[i]->stopSound();
delete _soundItems[i];
_soundItems[i] = NULL;
}
}
}
AudioResourceMan::~AudioResourceMan() {
stopAllMusic();
stopAllSounds();
}

View File

@ -129,6 +129,7 @@ public:
SoundMan(NeverhoodEngine *vm);
~SoundMan();
void stopAllMusic();
void stopAllSounds();
// Music
@ -264,6 +265,7 @@ public:
AudioResourceMan(NeverhoodEngine *vm);
~AudioResourceMan();
void stopAllMusic();
void stopAllSounds();
int16 addSound(uint32 fileHash);

View File

@ -211,6 +211,12 @@ void AnimatedSprite::init() {
_replNewColor = 0;
_animResource.setReplEnabled(false);
_playBackwards = false;
_currAnimFileHash = 0;
_lastFrameIndex = 0;
_plLastFrameIndex = 0;
_plFirstFrameHash = 0;
_plLastFrameHash = 0;
_animStatus = 0;
}
void AnimatedSprite::update() {

View File

@ -3297,6 +3297,17 @@ static const struct ADGameDescription SciGameDescriptions[] = {
AD_LISTEND},
Common::EN_ANY, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// RAMA - German Windows CD (from farmboy0, in pull request 397)
{"rama", "", {
{"resmap.001", 0, "f68cd73308c46977a9632dfc618e1e38", 8338},
{"ressci.001", 0, "2a68edd064e5e4937b5e9c74b38f2082", 70595521},
{"resmap.002", 0, "891fc2f5d9e23e7d9a9454acc7aaae52", 12082},
{"ressci.002", 0, "2a68edd064e5e4937b5e9c74b38f2082", 128508558},
{"resmap.003", 0, "222096000bd83a1d56577114a452cccf", 1636},
{"ressci.003", 0, "2a68edd064e5e4937b5e9c74b38f2082", 6954219},
AD_LISTEND},
Common::DE_DEU, Common::kPlatformWindows, ADGF_UNSTABLE, GUIO4(GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) },
// RAMA - Italian Windows CD (from glorifindel)
// SCI interpreter version 3.000.000 (a guess?)
{"rama", "", {

View File

@ -600,7 +600,10 @@ void MusicEntry::saveLoadWithSerializer(Common::Serializer &s) {
s.syncAsSint16LE(dataInc);
s.syncAsSint16LE(ticker);
s.syncAsSint16LE(signal, VER(17));
s.syncAsByte(priority);
if (s.getVersion() >= 31) // FE sound/music.h -> priority
s.syncAsSint16LE(priority);
else
s.syncAsByte(priority);
s.syncAsSint16LE(loop, VER(17));
s.syncAsByte(volume);
s.syncAsByte(hold, VER(17));

View File

@ -37,6 +37,7 @@ struct EngineState;
*
* Version - new/changed feature
* =============================
* 31 - priority for sound effects/music is now a signed int16, instead of a byte
* 30 - synonyms
* 29 - system strings
* 28 - heap
@ -55,7 +56,7 @@ struct EngineState;
*/
enum {
CURRENT_SAVEGAME_VERSION = 30,
CURRENT_SAVEGAME_VERSION = 31,
MINIMUM_SAVEGAME_VERSION = 14
};

View File

@ -58,6 +58,58 @@ struct SciScriptSignature {
// - if not EOS, an adjust offset and the actual bytes
// - rinse and repeat
// ===========================================================================
// Conquests of Camelot
// At the bazaar in Jerusalem, it's possible to see a girl taking a shower.
// If you get too close, you get warned by the father - if you don't get away,
// he will kill you.
// Instead of walking there manually, it's also possible to enter "look window"
// and ego will automatically walk to the window. It seems that this is something
// that wasn't properly implemented, because instead of getting killed, you will
// get an "Oops" message in Sierra SCI.
//
// This is caused by peepingTom in script 169 not getting properly initialized.
// peepingTom calls the object behind global b9h. This global variable is
// properly initialized, when walking there manually (method fawaz::doit).
// When you instead walk there automatically (method fawaz::handleEvent), that
// global isn't initialized, which then results in the Oops-message in Sierra SCI
// and an error message in ScummVM/SCI.
//
// We fix the script by patching in a jump to the proper code inside fawaz::doit.
// Responsible method: fawaz::handleEvent
// Fixes bug #3614969
const byte camelotSignaturePeepingTom[] = {
5,
0x72, 0x7e, 0x07, // lofsa fawaz <-- start of proper initializion code
0xa1, 0xb9, // sag b9h
+255, 0,
+255, 0,
+61, 19, // skip 571 bytes
0x39, 0x7a, // pushi 7a <-- initialization code when walking automatically
0x78, // push1
0x7a, // push2
0x38, 0xa9, 0x00, // pushi 00a9 - script 169
0x78, // push1
0x43, 0x02, 0x04, // call kScriptID
0x36, // push
0x81, 0x00, // lag 00
0x4a, 0x06, // send 06
0x32, 0x20, 0x05, // jmp [end of fawaz::handleEvent]
0
};
const uint16 camelotPatchPeepingTom[] = {
PATCH_ADDTOOFFSET | +576,
0x32, 0xbd, 0xfd, // jmp to fawaz::doit / properly init peepingTom code
PATCH_END
};
// script, description, magic DWORD, adjust
const SciScriptSignature camelotSignatures[] = {
{ 62, "fix peepingTom Sierra bug", 1, PATCH_MAGICDWORD(0x7e, 0x07, 0xa1, 0xb9), -1, camelotSignaturePeepingTom, camelotPatchPeepingTom },
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// stayAndHelp::changeState (0) is called when ego swims to the left or right
// boundaries of room 660. Normally a textbox is supposed to get on screen
@ -741,6 +793,48 @@ const SciScriptSignature longbowSignatures[] = {
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// Leisure Suit Larry 2
// On the plane, Larry is able to wear the parachute. This grants 4 points.
// In early versions of LSL2, it was possible to get "unlimited" points by
// simply wearing it multiple times.
// They fixed it in later versions by remembering, if the parachute was already
// used before.
// But instead of adding it properly, it seems they hacked the script / forgot
// to replace script 0 as well, which holds information about how many global
// variables are allocated at the start of the game.
// The script tries to read an out-of-bounds global variable, which somewhat
// "worked" in SSCI, but ScummVM/SCI doesn't allow that.
// That's why those points weren't granted here at all.
// We patch the script to use global 90, which seems to be unused in the whole game.
// Responsible method: rm63Script::handleEvent
// Fixes bug #3614419
const byte larry2SignatureWearParachutePoints[] = {
16,
0x35, 0x01, // ldi 01
0xa1, 0x8e, // sag 8e
0x80, 0xe0, 0x01, // lag 1e0
0x18, // not
0x30, 0x0f, 0x00, // bnt [don't give points]
0x35, 0x01, // ldi 01
0xa0, 0xe0, 0x01, // sag 1e0
0
};
const uint16 larry2PatchWearParachutePoints[] = {
PATCH_ADDTOOFFSET | +4,
0x80, 0x5a, 0x00, // lag 5a (global 90)
PATCH_ADDTOOFFSET | +6,
0xa0, 0x5a, 0x00, // sag 5a (global 90)
PATCH_END
};
// script, description, magic DWORD, adjust
const SciScriptSignature larry2Signatures[] = {
{ 63, "plane: no points for wearing plane", 1, PATCH_MAGICDWORD(0x8e, 0x80, 0xe0, 0x01), -3, larry2SignatureWearParachutePoints, larry2PatchWearParachutePoints },
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// this is called on every death dialog. Problem is at least the german
// version of lsl6 gets title text that is far too long for the
@ -867,6 +961,68 @@ const SciScriptSignature mothergoose256Signatures[] = {
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// Police Quest 1 VGA
// When at the police station, you can put or get your gun from your locker.
// The script, that handles this, is buggy. It disposes the gun as soon as
// you click, but then waits 2 seconds before it also closes the locker.
// Problem is that it's possible to click again, which then results in a
// disposed object getting accessed. This happened to work by pure luck in
// SSCI.
// This patch changes the code, so that the gun is actually given away
// when the 2 seconds have passed and the locker got closed.
// Responsible method: putGun::changeState (script 341)
// Fixes bug #3036933 / #3303802
const byte pq1vgaSignaturePutGunInLockerBug[] = {
5,
0x35, 0x00, // ldi 00
0x1a, // eq?
0x31, 0x25, // bnt [next state check]
+22, 29, // [skip 22 bytes]
0x38, 0x5f, 0x01, // pushi 15fh
0x78, // push1
0x76, // push0
0x81, 0x00, // lag 00
0x4a, 0x06, // send 06 - ego::put(0)
0x35, 0x02, // ldi 02
0x65, 0x1c, // aTop 1c (set timer to 2 seconds)
0x33, 0x0e, // jmp [end of method]
0x3c, // dup --- next state check target
0x35, 0x01, // ldi 01
0x1a, // eq?
0x31, 0x08, // bnt [end of method]
0x39, 0x6f, // pushi 6fh
0x76, // push0
0x72, 0x88, 0x00, // lofsa 0088
0x4a, 0x04, // send 04 - locker::dispose
0
};
const uint16 pq1vgaPatchPutGunInLockerBug[] = {
PATCH_ADDTOOFFSET | +3,
0x31, 0x1c, // bnt [next state check]
PATCH_ADDTOOFFSET | +22,
0x35, 0x02, // ldi 02
0x65, 0x1c, // aTop 1c (set timer to 2 seconds)
0x33, 0x17, // jmp [end of method]
0x3c, // dup --- next state check target
0x35, 0x01, // ldi 01
0x1a, // eq?
0x31, 0x11, // bnt [end of method]
0x38, 0x5f, 0x01, // pushi 15fh
0x78, // push1
0x76, // push0
0x81, 0x00, // lag 00
0x4a, 0x06, // send 06 - ego::put(0)
PATCH_END
};
// script, description, magic DWORD, adjust
const SciScriptSignature pq1vgaSignatures[] = {
{ 341, "put gun in locker bug", 1, PATCH_MAGICDWORD(0x38, 0x5f, 0x01, 0x78), -27, pq1vgaSignaturePutGunInLockerBug, pq1vgaPatchPutGunInLockerBug },
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// script 215 of qfg1vga pointBox::doit actually processes button-presses
// during fighting with monsters. It strangely also calls kGetEvent. Because
@ -995,14 +1151,75 @@ const uint16 qfg1vgaPatchMoveToCastleGate[] = {
PATCH_END
};
// Typo in the original Sierra scripts
// Looking at a cheetaur resulted in a text about a Saurus Rex
// The code treats both monster types the same.
// Responsible method: smallMonster::doVerb
// Fixes bug #3604943.
const byte qfg1vgaSignatureCheetaurDescription[] = {
16,
0x34, 0xb8, 0x01, // ldi 01b8
0x1a, // eq?
0x31, 0x16, // bnt 16
0x38, 0x27, 0x01, // pushi 0127
0x39, 0x06, // pushi 06
0x39, 0x03, // pushi 03
0x78, // push1
0x39, 0x12, // pushi 12 -> monster type Saurus Rex
0
};
const uint16 qfg1vgaPatchCheetaurDescription[] = {
PATCH_ADDTOOFFSET | +14,
0x39, 0x11, // pushi 11 -> monster type cheetaur
PATCH_END
};
// In the "funny" room (Yorick's room) in QfG1 VGA, pulling the chain and
// then pressing the button on the right side of the room results in
// a broken game. This also happens in SSCI.
// Problem is that the Sierra programmers forgot to disable the door, that
// gets opened by pulling the chain. So when ego falls down and then
// rolls through the door, one method thinks that the player walks through
// it and acts that way and the other method is still doing the roll animation.
// Local 5 of that room is a timer, that closes the door (object door11).
// Setting it to 1 during happyFace::changeState(0) stops door11::doit from
// calling goTo6::init, so the whole issue is stopped from happening.
// Responsible method: happyFace::changeState, door11::doit
// Fixes bug #3585793
const byte qfg1vgaSignatureFunnyRoomFix[] = {
14,
0x65, 0x14, // aTop 14 (state)
0x36, // push
0x3c, // dup
0x35, 0x00, // ldi 00
0x1a, // eq?
0x30, 0x25, 0x00, // bnt 0025 [-> next state]
0x35, 0x01, // ldi 01
0xa3, 0x4e, // sal 4e
0
};
const uint16 qfg1vgaPatchFunnyRoomFix[] = {
PATCH_ADDTOOFFSET | +3,
0x2e, 0x29, 0x00, // bt 0029 [-> next state] - saves 4 bytes
0x35, 0x01, // ldi 01
0xa3, 0x4e, // sal 4e
0xa3, 0x05, // sal 05 (sets local 5 to 1)
0xa3, 0x05, // and again to make absolutely sure (actually to waste 2 bytes)
PATCH_END
};
// script, description, magic DWORD, adjust
const SciScriptSignature qfg1vgaSignatures[] = {
{ 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
{ 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
{ 814, "window text temp space", 1, PATCH_MAGICDWORD(0x3f, 0xba, 0x87, 0x00), 0, qfg1vgaSignatureTempSpace, qfg1vgaPatchTempSpace },
{ 814, "dialog header offset", 3, PATCH_MAGICDWORD(0x5b, 0x04, 0x80, 0x36), 0, qfg1vgaSignatureDialogHeader, qfg1vgaPatchDialogHeader },
{ 331, "moving to crusher", 1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39), 0, qfg1vgaSignatureMoveToCrusher, qfg1vgaPatchMoveToCrusher },
{ 41, "moving to castle gate", 1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39), 0, qfg1vgaSignatureMoveToCastleGate, qfg1vgaPatchMoveToCastleGate },
{ 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
{ 216, "weapon master event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents },
{ 814, "window text temp space", 1, PATCH_MAGICDWORD(0x3f, 0xba, 0x87, 0x00), 0, qfg1vgaSignatureTempSpace, qfg1vgaPatchTempSpace },
{ 814, "dialog header offset", 3, PATCH_MAGICDWORD(0x5b, 0x04, 0x80, 0x36), 0, qfg1vgaSignatureDialogHeader, qfg1vgaPatchDialogHeader },
{ 331, "moving to crusher", 1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39), 0, qfg1vgaSignatureMoveToCrusher, qfg1vgaPatchMoveToCrusher },
{ 41, "moving to castle gate", 1, PATCH_MAGICDWORD(0x51, 0x1f, 0x36, 0x39), 0, qfg1vgaSignatureMoveToCastleGate, qfg1vgaPatchMoveToCastleGate },
{ 210, "cheetaur description fixed", 1, PATCH_MAGICDWORD(0x34, 0xb8, 0x01, 0x1a), 0, qfg1vgaSignatureCheetaurDescription, qfg1vgaPatchCheetaurDescription },
{ 96, "funny room script bug fixed", 1, PATCH_MAGICDWORD(0x35, 0x01, 0xa3, 0x4e), -10, qfg1vgaSignatureFunnyRoomFix, qfg1vgaPatchFunnyRoomFix },
SCI_SIGNATUREENTRY_TERMINATOR
};
@ -1250,6 +1467,32 @@ const SciScriptSignature sq4Signatures[] = {
SCI_SIGNATUREENTRY_TERMINATOR
};
// ===========================================================================
// When you leave Ulence Flats, another timepod is supposed to appear.
// On fast machines, that timepod appears fully immediately and then
// starts to appear like it should be. That first appearance is caused
// by the scripts setting an invalid cel number and the machine being
// so fast that there is no time for another script to actually fix
// the cel number. On slower machines, the cel number gets fixed
// by the cycler and that's why only fast machines are affected.
// The same issue happens in Sierra SCI.
// We simply set the correct starting cel number to fix the bug.
// Responsible method: robotIntoShip::changeState(9)
const byte sq1vgaSignatureUlenceFlatsTimepodGfxGlitch[] = {
8,
0x39, 0x07, // pushi 07 (ship::cel)
0x78, // push1
0x39, 0x0a, // pushi 0x0a (set ship::cel to 10)
0x38, 0xa0, 0x00, // pushi 0x00a0 (ship::setLoop)
0
};
const uint16 sq1vgaPatchUlenceFlatsTimepodGfxGlitch[] = {
PATCH_ADDTOOFFSET | +3,
0x39, 0x09, // pushi 0x09 (set ship::cel to 9)
PATCH_END
};
const byte sq1vgaSignatureEgoShowsCard[] = {
25,
0x38, 0x46, 0x02, // push 0x246 (set up send frame to set timesShownID)
@ -1267,7 +1510,8 @@ const byte sq1vgaSignatureEgoShowsCard[] = {
0x36, // push (wrong, acc clobbered by class, above)
0x35, 0x03, // ldi 0x03
0x22, // lt?
0};
0
};
// Note that this script patch is merely a reordering of the
// instructions in the original script.
@ -1287,13 +1531,14 @@ const uint16 sq1vgaPatchEgoShowsCard[] = {
0x4a, 0x06, // send 0x06 (set timesShownID)
0x35, 0x03, // ldi 0x03
0x22, // lt?
PATCH_END};
PATCH_END
};
// script, description, magic DWORD, adjust
const SciScriptSignature sq1vgaSignatures[] = {
{ 58, "Sarien armory droid zapping ego first time", 1, PATCH_MAGICDWORD( 0x72, 0x88, 0x15, 0x36 ), -70,
sq1vgaSignatureEgoShowsCard, sq1vgaPatchEgoShowsCard },
{ 45, "Ulence Flats: timepod graphic glitch", 1, PATCH_MAGICDWORD( 0x07, 0x78, 0x39, 0x0a ), -1, sq1vgaSignatureUlenceFlatsTimepodGfxGlitch, sq1vgaPatchUlenceFlatsTimepodGfxGlitch },
{ 58, "Sarien armory droid zapping ego first time", 1, PATCH_MAGICDWORD( 0x72, 0x88, 0x15, 0x36 ), -70, sq1vgaSignatureEgoShowsCard, sq1vgaPatchEgoShowsCard },
SCI_SIGNATUREENTRY_TERMINATOR};
@ -1389,6 +1634,9 @@ int32 Script::findSignature(const SciScriptSignature *signature, const byte *scr
void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uint32 scriptSize) {
const SciScriptSignature *signatureTable = NULL;
switch (g_sci->getGameId()) {
case GID_CAMELOT:
signatureTable = camelotSignatures;
break;
case GID_ECOQUEST:
signatureTable = ecoquest1Signatures;
break;
@ -1420,12 +1668,18 @@ void Script::matchSignatureAndPatch(uint16 scriptNr, byte *scriptData, const uin
case GID_LONGBOW:
signatureTable = longbowSignatures;
break;
case GID_LSL2:
signatureTable = larry2Signatures;
break;
case GID_LSL6:
signatureTable = larry6Signatures;
break;
case GID_MOTHERGOOSE256:
signatureTable = mothergoose256Signatures;
break;
case GID_PQ1:
signatureTable = pq1vgaSignatures;
break;
case GID_QFG1VGA:
signatureTable = qfg1vgaSignatures;
break;

View File

@ -286,11 +286,15 @@ void GfxScreen::putPixelOnDisplay(int x, int y, byte color) {
* with flood fill, due to small difference in the Bresenham logic.
*/
void GfxScreen::drawLine(Common::Point startPoint, Common::Point endPoint, byte color, byte priority, byte control) {
int16 left = startPoint.x;
int16 top = startPoint.y;
int16 right = endPoint.x;
int16 bottom = endPoint.y;
int16 maxWidth = _width - 1;
int16 maxHeight = _height - 1;
// we need to clip values here, lsl3 room 620 background picture draws a line from 0, 199 t 320, 199
// otherwise we would get heap corruption.
int16 left = CLIP<int16>(startPoint.x, 0, maxWidth);
int16 top = CLIP<int16>(startPoint.y, 0, maxHeight);
int16 right = CLIP<int16>(endPoint.x, 0, maxWidth);
int16 bottom = CLIP<int16>(endPoint.y, 0, maxHeight);
//set_drawing_flag
byte drawMask = getDrawingMask(color, priority, control);

View File

@ -20,6 +20,9 @@
*
*/
#include "sci/sci.h"
#include "sci/engine/state.h"
#include "sci/engine/kernel.h"
#include "sci/engine/state.h"
#include "sci/sound/midiparser_sci.h"
@ -53,11 +56,6 @@ MidiParser_SCI::MidiParser_SCI(SciVersion soundVersion, SciMusic *music) :
_masterVolume = 15;
_volume = 127;
_signalSet = false;
_signalToSet = 0;
_dataincAdd = false;
_dataincToAdd = 0;
_jumpToHoldTick = false;
_resetOnPause = false;
_pSnd = 0;
}
@ -440,26 +438,6 @@ void MidiParser_SCI::sendToDriver(uint32 midi) {
}
void MidiParser_SCI::parseNextEvent(EventInfo &info) {
// Set signal AFTER waiting for delta, otherwise we would set signal too soon resulting in all sorts of bugs
if (_dataincAdd) {
_dataincAdd = false;
_pSnd->dataInc += _dataincToAdd;
_pSnd->signal = 0x7f + _pSnd->dataInc;
debugC(4, kDebugLevelSound, "datainc %04x", _dataincToAdd);
}
if (_signalSet) {
_signalSet = false;
_pSnd->setSignal(_signalToSet);
debugC(4, kDebugLevelSound, "signal %04x", _signalToSet);
}
if (_jumpToHoldTick) {
_jumpToHoldTick = false;
_pSnd->inFastForward = true;
jumpToTick(_loopTick, false, false);
_pSnd->inFastForward = false;
}
info.start = _position._playPos;
info.delta = 0;
while (*_position._playPos == 0xF8) {
@ -481,33 +459,6 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
case 0xC:
info.basic.param1 = *(_position._playPos++);
info.basic.param2 = 0;
if (info.channel() == 0xF) {// SCI special case
if (info.basic.param1 != kSetSignalLoop) {
// At least in kq5/french&mac the first scene in the intro has
// a song that sets signal to 4 immediately on tick 0. Signal
// isn't set at that point by sierra sci and it would cause the
// castle daventry text to get immediately removed, so we
// currently filter it. Sierra SCI ignores them as well at that
// time. However, this filtering should only be performed for
// SCI1 and newer games. Signalling is done differently in SCI0
// though, so ignoring these signals in SCI0 games will result
// in glitches (e.g. the intro of LB1 Amiga gets stuck - bug
// #3297883). Refer to MusicEntry::setSignal() in sound/music.cpp.
// FIXME: SSCI doesn't start playing at the very beginning
// of the stream, but at a fixed location a few commands later.
// That is probably why this signal isn't triggered
// immediately there.
if (_soundVersion <= SCI_VERSION_0_LATE ||
_position._playTick || info.delta) {
if (!_pSnd->inFastForward) {
_signalSet = true;
_signalToSet = info.basic.param1;
}
}
} else {
_loopTick = _position._playTick + info.delta;
}
}
break;
case 0xD:
info.basic.param1 = *(_position._playPos++);
@ -517,92 +468,6 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
case 0xB:
info.basic.param1 = *(_position._playPos++);
info.basic.param2 = *(_position._playPos++);
// Reference for some events:
// http://wiki.scummvm.org/index.php/SCI/Specifications/Sound/SCI0_Resource_Format#Status_Reference
// Handle common special events
switch (info.basic.param1) {
case kSetReverb:
if (info.basic.param2 == 127) // Set global reverb instead
_pSnd->reverb = _music->getGlobalReverb();
else
_pSnd->reverb = info.basic.param2;
((MidiPlayer *)_driver)->setReverb(_pSnd->reverb);
break;
default:
break;
}
// Handle events sent to the SCI special channel (15)
if (info.channel() == 0xF) {
switch (info.basic.param1) {
case kSetReverb:
// Already handled above
break;
case kMidiHold:
// Check if the hold ID marker is the same as the hold ID
// marker set for that song by cmdSetSoundHold.
// If it is, loop back, but don't stop notes when jumping.
// We need to wait for the delta of the current event before
// jumping, thus the jump will be performed on the next
// parseNextEvent() call, like with the signal set events.
// In LSL6, room 360, song 381, this ends up jumping forward
// one tick (the hold marker occurs at playtick 27, with
// _loopTick being 15 and the event itself having a delta of
// 13, total = 28) - bug #3614566.
if (info.basic.param2 == _pSnd->hold) {
_jumpToHoldTick = true;
}
break;
case kUpdateCue:
if (!_pSnd->inFastForward) {
_dataincAdd = true;
switch (_soundVersion) {
case SCI_VERSION_0_EARLY:
case SCI_VERSION_0_LATE:
_dataincToAdd = info.basic.param2;
break;
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
case SCI_VERSION_2_1:
_dataincToAdd = 1;
break;
default:
error("unsupported _soundVersion");
}
}
break;
case kResetOnPause:
_resetOnPause = info.basic.param2;
break;
// Unhandled SCI commands
case 0x46: // LSL3 - binoculars
case 0x61: // Iceman (AdLib?)
case 0x73: // Hoyle
case 0xD1: // KQ4, when riding the unicorn
// Obscure SCI commands - ignored
break;
// Standard MIDI commands
case 0x01: // mod wheel
case 0x04: // foot controller
case 0x07: // channel volume
case 0x0A: // pan
case 0x0B: // expression
case 0x40: // sustain
case 0x79: // reset all
case 0x7B: // notes off
// These are all handled by the music driver, so ignore them
break;
case 0x4B: // voice mapping
// TODO: is any support for this needed at the MIDI parser level?
warning("Unhanded SCI MIDI command 0x%x - voice mapping (parameter %d)", info.basic.param1, info.basic.param2);
break;
default:
warning("Unhandled SCI MIDI command 0x%x (parameter %d)", info.basic.param1, info.basic.param2);
break;
}
}
info.length = 0;
break;
@ -649,34 +514,6 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
info.length = readVLQ(_position._playPos);
info.ext.data = _position._playPos;
_position._playPos += info.length;
if (info.ext.type == 0x2F) {// end of track reached
if (_pSnd->loop)
_pSnd->loop--;
// QFG3 abuses the hold flag. Its scripts call kDoSoundSetHold,
// but sometimes there's no hold marker in the associated songs
// (e.g. song 110, during the intro). The original interpreter
// treats this case as an infinite loop (bug #3311911).
if (_pSnd->loop || _pSnd->hold > 0) {
// TODO: this jump is also vulnerable to the same lockup as
// the MIDI hold one above. However, we can't perform the
// jump on the next tick like with the MIDI hold jump above,
// as there aren't any subsequent MIDI events after this one.
// This assert is here to detect cases where the song ends
// up jumping forward, like with bug #3614566 (see above).
assert(_loopTick + info.delta < _position._playTick);
uint32 extraDelta = info.delta;
_pSnd->inFastForward = true;
jumpToTick(_loopTick);
_pSnd->inFastForward = false;
_nextEvent.delta += extraDelta;
} else {
_pSnd->status = kSoundStopped;
_pSnd->setSignal(SIGNAL_OFFSET);
debugC(4, kDebugLevelSound, "signal EOT");
}
}
break;
default:
warning(
@ -686,6 +523,190 @@ void MidiParser_SCI::parseNextEvent(EventInfo &info) {
}// switch (info.command())
}
void MidiParser_SCI::processEvent(const EventInfo &info, bool fireEvents) {
if (!fireEvents) {
// We don't do any processing that should be done while skipping events
MidiParser::processEvent(info, fireEvents);
return;
}
switch (info.command()) {
case 0xC:
if (info.channel() == 0xF) {// SCI special case
if (info.basic.param1 != kSetSignalLoop) {
// At least in kq5/french&mac the first scene in the intro has
// a song that sets signal to 4 immediately on tick 0. Signal
// isn't set at that point by sierra sci and it would cause the
// castle daventry text to get immediately removed, so we
// currently filter it. Sierra SCI ignores them as well at that
// time. However, this filtering should only be performed for
// SCI1 and newer games. Signalling is done differently in SCI0
// though, so ignoring these signals in SCI0 games will result
// in glitches (e.g. the intro of LB1 Amiga gets stuck - bug
// #3297883). Refer to MusicEntry::setSignal() in sound/music.cpp.
// FIXME: SSCI doesn't start playing at the very beginning
// of the stream, but at a fixed location a few commands later.
// That is probably why this signal isn't triggered
// immediately there.
bool skipSignal = false;
if (_soundVersion >= SCI_VERSION_1_EARLY) {
if (!_position._playTick) {
skipSignal = true;
switch (g_sci->getGameId()) {
case GID_ECOQUEST2:
// In Eco Quest 2 room 530 - gonzales is supposed to dance
// WORKAROUND: we need to signal in this case on tick 0
// this whole issue is complicated and can only be properly fixed by
// changing the whole parser to a per-channel parser. SSCI seems to
// start each channel at offset 13 (may be 10 for us) and only
// starting at offset 0 when the music loops to the initial position.
if (g_sci->getEngineState()->currentRoomNumber() == 530)
skipSignal = false;
break;
default:
break;
}
}
}
if (!skipSignal) {
if (!_jumpingToTick) {
_pSnd->setSignal(info.basic.param1);
debugC(4, kDebugLevelSound, "signal %04x", info.basic.param1);
}
}
} else {
_loopTick = _position._playTick;
}
// Done with this event.
return;
}
// Break to let parent handle the rest.
break;
case 0xB:
// Reference for some events:
// http://wiki.scummvm.org/index.php/SCI/Specifications/Sound/SCI0_Resource_Format#Status_Reference
// Handle common special events
switch (info.basic.param1) {
case kSetReverb:
if (info.basic.param2 == 127) // Set global reverb instead
_pSnd->reverb = _music->getGlobalReverb();
else
_pSnd->reverb = info.basic.param2;
((MidiPlayer *)_driver)->setReverb(_pSnd->reverb);
break;
default:
break;
}
// Handle events sent to the SCI special channel (15)
if (info.channel() == 0xF) {
switch (info.basic.param1) {
case kSetReverb:
// Already handled above
return;
case kMidiHold:
// Check if the hold ID marker is the same as the hold ID
// marker set for that song by cmdSetSoundHold.
// If it is, loop back, but don't stop notes when jumping.
if (info.basic.param2 == _pSnd->hold) {
jumpToTick(_loopTick, false, false);
// Done with this event.
return;
}
return;
case kUpdateCue:
if (!_jumpingToTick) {
int inc;
switch (_soundVersion) {
case SCI_VERSION_0_EARLY:
case SCI_VERSION_0_LATE:
inc = info.basic.param2;
break;
case SCI_VERSION_1_EARLY:
case SCI_VERSION_1_LATE:
case SCI_VERSION_2_1:
inc = 1;
break;
default:
error("unsupported _soundVersion");
}
_pSnd->dataInc += inc;
debugC(4, kDebugLevelSound, "datainc %04x", inc);
}
return;
case kResetOnPause:
_resetOnPause = info.basic.param2;
return;
// Unhandled SCI commands
case 0x46: // LSL3 - binoculars
case 0x61: // Iceman (AdLib?)
case 0x73: // Hoyle
case 0xD1: // KQ4, when riding the unicorn
// Obscure SCI commands - ignored
return;
// Standard MIDI commands
case 0x01: // mod wheel
case 0x04: // foot controller
case 0x07: // channel volume
case 0x0A: // pan
case 0x0B: // expression
case 0x40: // sustain
case 0x79: // reset all
case 0x7B: // notes off
// These are all handled by the music driver, so ignore them
break;
case 0x4B: // voice mapping
// TODO: is any support for this needed at the MIDI parser level?
warning("Unhanded SCI MIDI command 0x%x - voice mapping (parameter %d)", info.basic.param1, info.basic.param2);
return;
default:
warning("Unhandled SCI MIDI command 0x%x (parameter %d)", info.basic.param1, info.basic.param2);
return;
}
}
// Break to let parent handle the rest.
break;
case 0xF: // META event
if (info.ext.type == 0x2F) {// end of track reached
if (_pSnd->loop)
_pSnd->loop--;
// QFG3 abuses the hold flag. Its scripts call kDoSoundSetHold,
// but sometimes there's no hold marker in the associated songs
// (e.g. song 110, during the intro). The original interpreter
// treats this case as an infinite loop (bug #3311911).
if (_pSnd->loop || _pSnd->hold > 0) {
jumpToTick(_loopTick);
// Done with this event.
return;
} else {
_pSnd->status = kSoundStopped;
_pSnd->setSignal(SIGNAL_OFFSET);
debugC(4, kDebugLevelSound, "signal EOT");
}
}
// Break to let parent handle the rest.
break;
default:
// Break to let parent handle the rest.
break;
}
// Let parent handle the rest
MidiParser::processEvent(info, fireEvents);
}
byte MidiParser_SCI::getSongReverb() {
assert(_track);

View File

@ -89,6 +89,7 @@ public:
protected:
void parseNextEvent(EventInfo &info);
void processEvent(const EventInfo &info, bool fireEvents = true);
byte *midiMixChannels();
byte *midiFilterChannels(int channelMask);
byte midiGetNextChannel(long ticker);
@ -106,11 +107,6 @@ protected:
byte _masterVolume; // the overall master volume (same for all tracks)
byte _volume; // the global volume of the current track
bool _signalSet;
int16 _signalToSet;
bool _dataincAdd;
int16 _dataincToAdd;
bool _jumpToHoldTick;
bool _resetOnPause;
bool _channelUsed[16];

View File

@ -521,11 +521,7 @@ void SciMusic::soundPlay(MusicEntry *pSnd) {
pSnd->pMidiParser->jumpToTick(0);
else {
// Fast forward to the last position and perform associated events when loading
pSnd->inFastForward = true;
// we set this flag, so that the midiparser doesn't set any signals for scripts
// if we don't do this, at least accessing the debugger will reset previously set signals
pSnd->pMidiParser->jumpToTick(pSnd->ticker, true, true, true);
pSnd->inFastForward = false;
}
// Restore looping and hold
@ -765,7 +761,6 @@ MusicEntry::MusicEntry() {
resourceId = 0;
isQueued = false;
inFastForward = false;
dataInc = 0;
ticker = 0;

View File

@ -65,12 +65,11 @@ public:
uint16 resourceId;
bool isQueued; // for SCI0 only!
bool inFastForward; // if we are currently fast-forwarding (disables any signals to scripts)
uint16 dataInc;
uint16 ticker;
uint16 signal;
byte priority;
int16 priority; // must be int16, at least in Laura Bow 1, main music (object conMusic) uses priority -1
uint16 loop;
int16 volume;
int16 hold;

View File

@ -116,7 +116,10 @@ void SoundCommandParser::processInitSound(reg_t obj) {
newSound->resourceId = resourceId;
newSound->soundObj = obj;
newSound->loop = readSelectorValue(_segMan, obj, SELECTOR(loop));
newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)) & 0xFF;
if (_soundVersion <= SCI_VERSION_0_LATE)
newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(priority));
else
newSound->priority = readSelectorValue(_segMan, obj, SELECTOR(priority)) & 0xFF;
if (_soundVersion >= SCI_VERSION_1_EARLY)
newSound->volume = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, MUSIC_VOLUME_MAX);
newSound->reverb = -1; // initialize to SCI invalid, it'll be set correctly in soundInitSnd() below
@ -428,7 +431,7 @@ reg_t SoundCommandParser::kDoSoundUpdate(int argc, reg_t *argv, reg_t acc) {
int16 objVol = CLIP<int>(readSelectorValue(_segMan, obj, SELECTOR(vol)), 0, 255);
if (objVol != musicSlot->volume)
_music->soundSetVolume(musicSlot, objVol);
uint32 objPrio = readSelectorValue(_segMan, obj, SELECTOR(priority));
int16 objPrio = readSelectorValue(_segMan, obj, SELECTOR(priority));
if (objPrio != musicSlot->priority)
_music->soundSetPriority(musicSlot, objPrio);
return acc;

View File

@ -1,5 +1,5 @@
/*
This file was generated by the md5table tool on Thu Aug 15 12:47:39 2013
This file was generated by the md5table tool on Fri Sep 27 05:44:12 2013
DO NOT EDIT MANUALLY!
*/
@ -121,6 +121,7 @@ static const MD5Table md5table[] = {
{ "2723fea3dae0cb47768c424b145ae0e7", "tentacle", "Floppy", "Floppy", 7932, Common::EN_ANY, Common::kPlatformDOS },
{ "27b2ef1653089fe5b897d9cc89ce784f", "balloon", "HE 80", "", -1, Common::RU_RUS, Common::kPlatformWindows },
{ "27b3a4224ad63d5b04627595c1c1a025", "zak", "V2", "V2", -1, Common::IT_ITA, Common::kPlatformAmiga },
{ "288fb75b24389733c29fa107fe8d44e8", "catalog", "HE CUP", "Preview", 10795148, Common::EN_USA, Common::kPlatformUnknown },
{ "28d24a33448fab6795850bc9f159a4a2", "atlantis", "FM-TOWNS", "Demo", 11170, Common::JA_JPN, Common::kPlatformFMTowns },
{ "28ef68ee3ed76d7e2ee8ee13c15fbd5b", "loom", "EGA", "EGA", 5748, Common::EN_ANY, Common::kPlatformDOS },
{ "28f07458f1b6c24e118a1ea056827701", "lost", "HE 99", "", -1, Common::NL_NLD, Common::kPlatformUnknown },

View File

@ -553,15 +553,15 @@ bool Animation::persist(OutputPersistenceBlock &writer) {
writer.write(_currentFrameTime);
writer.write(_running);
writer.write(_finished);
writer.write(static_cast<uint>(_direction));
writer.write(static_cast<uint32>(_direction));
// Je nach Animationstyp entweder das Template oder die Ressource speichern.
if (_animationResourcePtr) {
uint marker = 0;
uint32 marker = 0;
writer.write(marker);
writer.writeString(_animationResourcePtr->getFileName());
} else if (_animationTemplateHandle) {
uint marker = 1;
uint32 marker = 1;
writer.write(marker);
writer.write(_animationTemplateHandle);
} else {
@ -574,13 +574,13 @@ bool Animation::persist(OutputPersistenceBlock &writer) {
// The following is only there to for compatibility with older saves
// resp. the original engine.
writer.write((uint)1);
writer.write((uint32)1);
writer.writeString("LuaLoopPointCB");
writer.write(getHandle());
writer.write((uint)1);
writer.write((uint32)1);
writer.writeString("LuaActionCB");
writer.write(getHandle());
writer.write((uint)1);
writer.write((uint32)1);
writer.writeString("LuaDeleteCB");
writer.write(getHandle());
@ -605,12 +605,12 @@ bool Animation::unpersist(InputPersistenceBlock &reader) {
reader.read(_currentFrameTime);
reader.read(_running);
reader.read(_finished);
uint direction;
uint32 direction;
reader.read(direction);
_direction = static_cast<Direction>(direction);
// Animationstyp einlesen.
uint marker;
uint32 marker;
reader.read(marker);
if (marker == 0) {
Common::String resourceFilename;
@ -629,9 +629,9 @@ bool Animation::unpersist(InputPersistenceBlock &reader) {
// The following is only there to for compatibility with older saves
// resp. the original engine.
uint callbackCount;
uint32 callbackCount;
Common::String callbackFunctionName;
uint callbackData;
uint32 callbackData;
// loop point callback
reader.read(callbackCount);

View File

@ -159,18 +159,18 @@ private:
BACKWARD
};
int _relX;
int _relY;
int32 _relX;
int32 _relY;
float _scaleFactorX;
float _scaleFactorY;
uint _modulationColor;
uint _currentFrame;
int _currentFrameTime;
uint32 _modulationColor;
uint32 _currentFrame;
int32 _currentFrameTime;
bool _running;
bool _finished;
Direction _direction;
AnimationResource *_animationResourcePtr;
uint _animationTemplateHandle;
uint32 _animationTemplateHandle;
bool _framesLocked;
ANIMATION_CALLBACK _loopPointCallback;

Some files were not shown because too many files have changed in this diff Show More