diff options
163 files changed, 6002 insertions, 5660 deletions
@@ -142,6 +142,14 @@ ScummVM Team Eugene Sandulenko David Turner + Mortevielle: + Arnaud Boutonne + Paul Gilbert + + Neverhood: + Benjamin Haisch + Filippos Karapetis + Parallaction: peres diff --git a/audio/softsynth/mt32/AReverbModel.cpp b/audio/softsynth/mt32/AReverbModel.cpp deleted file mode 100644 index 1d63832157..0000000000 --- a/audio/softsynth/mt32/AReverbModel.cpp +++ /dev/null @@ -1,277 +0,0 @@ -/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher - * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "mt32emu.h" - -#if MT32EMU_USE_REVERBMODEL == 1 - -#include "AReverbModel.h" - -// Analysing of state of reverb RAM address lines gives exact sizes of the buffers of filters used. This also indicates that -// the reverb model implemented in the real devices consists of three series allpass filters preceded by a non-feedback comb (or a delay with a LPF) -// and followed by three parallel comb filters - -namespace MT32Emu { - -// Because LA-32 chip makes it's output available to process by the Boss chip with a significant delay, -// the Boss chip puts to the buffer the LA32 dry output when it is ready and performs processing of the _previously_ latched data. -// Of course, the right way would be to use a dedicated variable for this, but our reverb model is way higher level, -// so we can simply increase the input buffer size. -static const Bit32u PROCESS_DELAY = 1; - -// Default reverb settings for modes 0-2. These correspond to CM-32L / LAPC-I "new" reverb settings. MT-32 reverb is a bit different. -// Found by tracing reverb RAM data lines (thanks go to Lord_Nightmare & balrog). - -static const Bit32u NUM_ALLPASSES = 3; -static const Bit32u NUM_COMBS = 4; // Well, actually there are 3 comb filters, but the entrance LPF + delay can be perfectly processed via a comb here. - -static const Bit32u MODE_0_ALLPASSES[] = {994, 729, 78}; -static const Bit32u MODE_0_COMBS[] = {705 + PROCESS_DELAY, 2349, 2839, 3632}; -static const Bit32u MODE_0_OUTL[] = {2349, 141, 1960}; -static const Bit32u MODE_0_OUTR[] = {1174, 1570, 145}; -static const Bit32u MODE_0_COMB_FACTOR[] = {0x3C, 0x60, 0x60, 0x60}; -static const Bit32u MODE_0_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; -static const Bit32u MODE_0_LEVELS[] = {10*1, 10*3, 10*5, 10*7, 11*9, 11*12, 11*15, 13*15}; -static const Bit32u MODE_0_LPF_AMP = 6; - -static const Bit32u MODE_1_ALLPASSES[] = {1324, 809, 176}; -static const Bit32u MODE_1_COMBS[] = {961 + PROCESS_DELAY, 2619, 3545, 4519}; -static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; -static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; -static const Bit32u MODE_1_COMB_FACTOR[] = {0x30, 0x60, 0x60, 0x60}; -static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; -static const Bit32u MODE_1_LEVELS[] = {10*1, 10*3, 11*5, 11*7, 11*9, 11*12, 11*15, 14*15}; -static const Bit32u MODE_1_LPF_AMP = 6; - -static const Bit32u MODE_2_ALLPASSES[] = {969, 644, 157}; -static const Bit32u MODE_2_COMBS[] = {116 + PROCESS_DELAY, 2259, 2839, 3539}; -static const Bit32u MODE_2_OUTL[] = {2259, 718, 1769}; -static const Bit32u MODE_2_OUTR[] = {1136, 2128, 1}; -static const Bit32u MODE_2_COMB_FACTOR[] = {0, 0x20, 0x20, 0x20}; -static const Bit32u MODE_2_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, - 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0, - 0x30, 0x58, 0x78, 0x88, 0xA0, 0xB8, 0xC0, 0xD0}; -static const Bit32u MODE_2_LEVELS[] = {10*1, 10*3, 11*5, 11*7, 11*9, 11*12, 12*15, 14*15}; -static const Bit32u MODE_2_LPF_AMP = 8; - -static const AReverbSettings REVERB_MODE_0_SETTINGS = {MODE_0_ALLPASSES, MODE_0_COMBS, MODE_0_OUTL, MODE_0_OUTR, MODE_0_COMB_FACTOR, MODE_0_COMB_FEEDBACK, MODE_0_LEVELS, MODE_0_LPF_AMP}; -static const AReverbSettings REVERB_MODE_1_SETTINGS = {MODE_1_ALLPASSES, MODE_1_COMBS, MODE_1_OUTL, MODE_1_OUTR, MODE_1_COMB_FACTOR, MODE_1_COMB_FEEDBACK, MODE_1_LEVELS, MODE_1_LPF_AMP}; -static const AReverbSettings REVERB_MODE_2_SETTINGS = {MODE_2_ALLPASSES, MODE_2_COMBS, MODE_2_OUTL, MODE_2_OUTR, MODE_2_COMB_FACTOR, MODE_2_COMB_FEEDBACK, MODE_2_LEVELS, MODE_2_LPF_AMP}; - -static const AReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTINGS, &REVERB_MODE_1_SETTINGS, &REVERB_MODE_2_SETTINGS, &REVERB_MODE_0_SETTINGS}; - -RingBuffer::RingBuffer(const Bit32u newsize) : size(newsize), index(0) { - buffer = new float[size]; -} - -RingBuffer::~RingBuffer() { - delete[] buffer; - buffer = NULL; -} - -float RingBuffer::next() { - if (++index >= size) { - index = 0; - } - return buffer[index]; -} - -bool RingBuffer::isEmpty() const { - if (buffer == NULL) return true; - - float *buf = buffer; - float max = 0.001f; - for (Bit32u i = 0; i < size; i++) { - if ((*buf < -max) || (*buf > max)) return false; - buf++; - } - return true; -} - -void RingBuffer::mute() { - float *buf = buffer; - for (Bit32u i = 0; i < size; i++) { - *buf++ = 0; - } -} - -AllpassFilter::AllpassFilter(const Bit32u useSize) : RingBuffer(useSize) {} - -float AllpassFilter::process(const float in) { - // This model corresponds to the allpass filter implementation of the real CM-32L device - // found from sample analysis - - const float bufferOut = next(); - - // store input - feedback / 2 - buffer[index] = in - 0.5f * bufferOut; - - // return buffer output + feedforward / 2 - return bufferOut + 0.5f * buffer[index]; -} - -CombFilter::CombFilter(const Bit32u useSize) : RingBuffer(useSize) {} - -void CombFilter::process(const float in) { - // This model corresponds to the comb filter implementation of the real CM-32L device - // found from sample analysis - - // the previously stored value - float last = buffer[index]; - - // prepare input + feedback - float filterIn = in + next() * feedbackFactor; - - // store input + feedback processed by a low-pass filter - buffer[index] = filterFactor * last - filterIn; -} - -float CombFilter::getOutputAt(const Bit32u outIndex) const { - return buffer[(size + index - outIndex) % size]; -} - -void CombFilter::setFeedbackFactor(const float useFeedbackFactor) { - feedbackFactor = useFeedbackFactor; -} - -void CombFilter::setFilterFactor(const float useFilterFactor) { - filterFactor = useFilterFactor; -} - -AReverbModel::AReverbModel(const ReverbMode mode) : allpasses(NULL), combs(NULL), currentSettings(*REVERB_SETTINGS[mode]) {} - -AReverbModel::~AReverbModel() { - close(); -} - -void AReverbModel::open() { - allpasses = new AllpassFilter*[NUM_ALLPASSES]; - for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { - allpasses[i] = new AllpassFilter(currentSettings.allpassSizes[i]); - } - combs = new CombFilter*[NUM_COMBS]; - for (Bit32u i = 0; i < NUM_COMBS; i++) { - combs[i] = new CombFilter(currentSettings.combSizes[i]); - combs[i]->setFilterFactor(currentSettings.filterFactor[i] / 256.0f); - } - lpfAmp = currentSettings.lpfAmp / 16.0f; - mute(); -} - -void AReverbModel::close() { - if (allpasses != NULL) { - for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { - if (allpasses[i] != NULL) { - delete allpasses[i]; - allpasses[i] = NULL; - } - } - delete[] allpasses; - allpasses = NULL; - } - if (combs != NULL) { - for (Bit32u i = 0; i < NUM_COMBS; i++) { - if (combs[i] != NULL) { - delete combs[i]; - combs[i] = NULL; - } - } - delete[] combs; - combs = NULL; - } -} - -void AReverbModel::mute() { - if (allpasses == NULL || combs == NULL) return; - for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { - allpasses[i]->mute(); - } - for (Bit32u i = 0; i < NUM_COMBS; i++) { - combs[i]->mute(); - } -} - -void AReverbModel::setParameters(Bit8u time, Bit8u level) { -// FIXME: wetLevel definitely needs ramping when changed -// Although, most games don't set reverb level during MIDI playback - if (combs == NULL) return; - level &= 7; - time &= 7; - for (Bit32u i = 0; i < NUM_COMBS; i++) { - combs[i]->setFeedbackFactor(currentSettings.decayTimes[(i << 3) + time] / 256.0f); - } - wetLevel = (level == 0 && time == 0) ? 0.0f : 0.5f * lpfAmp * currentSettings.wetLevels[level] / 256.0f; -} - -bool AReverbModel::isActive() const { - for (Bit32u i = 0; i < NUM_ALLPASSES; i++) { - if (!allpasses[i]->isEmpty()) return true; - } - for (Bit32u i = 0; i < NUM_COMBS; i++) { - if (!combs[i]->isEmpty()) return true; - } - return false; -} - -void AReverbModel::process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples) { - float dry, link, outL1; - - for (unsigned long i = 0; i < numSamples; i++) { - dry = wetLevel * (*inLeft + *inRight); - - // Get the last stored sample before processing in order not to loose it - link = combs[0]->getOutputAt(currentSettings.combSizes[0] - 1); - - combs[0]->process(-dry); - - link = allpasses[0]->process(link); - link = allpasses[1]->process(link); - link = allpasses[2]->process(link); - - // If the output position is equal to the comb size, get it now in order not to loose it - outL1 = 1.5f * combs[1]->getOutputAt(currentSettings.outLPositions[0] - 1); - - combs[1]->process(link); - combs[2]->process(link); - combs[3]->process(link); - - link = outL1 + 1.5f * combs[2]->getOutputAt(currentSettings.outLPositions[1]); - link += combs[3]->getOutputAt(currentSettings.outLPositions[2]); - *outLeft = link; - - link = 1.5f * combs[1]->getOutputAt(currentSettings.outRPositions[0]); - link += 1.5f * combs[2]->getOutputAt(currentSettings.outRPositions[1]); - link += combs[3]->getOutputAt(currentSettings.outRPositions[2]); - *outRight = link; - - inLeft++; - inRight++; - outLeft++; - outRight++; - } -} - -} - -#endif diff --git a/audio/softsynth/mt32/AReverbModel.h b/audio/softsynth/mt32/AReverbModel.h deleted file mode 100644 index c992478907..0000000000 --- a/audio/softsynth/mt32/AReverbModel.h +++ /dev/null @@ -1,87 +0,0 @@ -/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher - * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MT32EMU_A_REVERB_MODEL_H -#define MT32EMU_A_REVERB_MODEL_H - -namespace MT32Emu { - -struct AReverbSettings { - const Bit32u * const allpassSizes; - const Bit32u * const combSizes; - const Bit32u * const outLPositions; - const Bit32u * const outRPositions; - const Bit32u * const filterFactor; - const Bit32u * const decayTimes; - const Bit32u * const wetLevels; - const Bit32u lpfAmp; -}; - -class RingBuffer { -protected: - float *buffer; - const Bit32u size; - Bit32u index; - -public: - RingBuffer(const Bit32u size); - virtual ~RingBuffer(); - float next(); - bool isEmpty() const; - void mute(); -}; - -class AllpassFilter : public RingBuffer { -public: - AllpassFilter(const Bit32u size); - float process(const float in); -}; - -class CombFilter : public RingBuffer { - float feedbackFactor; - float filterFactor; - -public: - CombFilter(const Bit32u size); - void process(const float in); - float getOutputAt(const Bit32u outIndex) const; - void setFeedbackFactor(const float useFeedbackFactor); - void setFilterFactor(const float useFilterFactor); -}; - -class AReverbModel : public ReverbModel { - AllpassFilter **allpasses; - CombFilter **combs; - - const AReverbSettings ¤tSettings; - float lpfAmp; - float wetLevel; - void mute(); - -public: - AReverbModel(const ReverbMode mode); - ~AReverbModel(); - void open(); - void close(); - void setParameters(Bit8u time, Bit8u level); - void process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples); - bool isActive() const; -}; - -} - -#endif diff --git a/audio/softsynth/mt32/BReverbModel.cpp b/audio/softsynth/mt32/BReverbModel.cpp index cc0219b741..c16f7f17da 100644 --- a/audio/softsynth/mt32/BReverbModel.cpp +++ b/audio/softsynth/mt32/BReverbModel.cpp @@ -15,10 +15,8 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ +//#include <memory.h> #include "mt32emu.h" - -#if MT32EMU_USE_REVERBMODEL == 2 - #include "BReverbModel.h" // Analysing of state of reverb RAM address lines gives exact sizes of the buffers of filters used. This also indicates that @@ -62,9 +60,9 @@ static const Bit32u MODE_1_OUTL[] = {2618, 1760, 4518}; static const Bit32u MODE_1_OUTR[] = {1300, 3532, 2274}; static const Bit32u MODE_1_COMB_FACTOR[] = {0x80, 0x60, 0x60, 0x60}; static const Bit32u MODE_1_COMB_FEEDBACK[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, - 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, - 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; + 0x28, 0x48, 0x60, 0x70, 0x78, 0x80, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98, + 0x28, 0x48, 0x60, 0x78, 0x80, 0x88, 0x90, 0x98}; static const Bit32u MODE_1_DRY_AMP[] = {0xA0, 0xA0, 0xB0, 0xB0, 0xB0, 0xB0, 0xB0, 0xE0}; static const Bit32u MODE_1_WET_AMP[] = {0x10, 0x30, 0x50, 0x70, 0x90, 0xC0, 0xF0, 0xF0}; static const Bit32u MODE_1_LPF_AMP = 0x60; @@ -103,7 +101,11 @@ static const BReverbSettings * const REVERB_SETTINGS[] = {&REVERB_MODE_0_SETTING // This algorithm tries to emulate exactly Boss multiplication operation (at least this is what we see on reverb RAM data lines). // Also LA32 is suspected to use the similar one to perform PCM interpolation and ring modulation. -static Bit32s weirdMul(Bit32s a, Bit8u addMask, Bit8u carryMask) { +static Sample weirdMul(Sample a, Bit8u addMask, Bit8u carryMask) { + (void)carryMask; +#if MT32EMU_USE_FLOAT_SAMPLES + return a * addMask / 256.0f; +#elif MT32EMU_BOSS_REVERB_PRECISE_MODE Bit8u mask = 0x80; Bit32s res = 0; for (int i = 0; i < 8; i++) { @@ -113,10 +115,13 @@ static Bit32s weirdMul(Bit32s a, Bit8u addMask, Bit8u carryMask) { mask >>= 1; } return res; +#else + return Sample(((Bit32s)a * addMask) >> 8); +#endif } RingBuffer::RingBuffer(Bit32u newsize) : size(newsize), index(0) { - buffer = new Bit16s[size]; + buffer = new Sample[size]; } RingBuffer::~RingBuffer() { @@ -124,7 +129,7 @@ RingBuffer::~RingBuffer() { buffer = NULL; } -Bit32s RingBuffer::next() { +Sample RingBuffer::next() { if (++index >= size) { index = 0; } @@ -134,52 +139,69 @@ Bit32s RingBuffer::next() { bool RingBuffer::isEmpty() const { if (buffer == NULL) return true; - Bit16s *buf = buffer; +#if MT32EMU_USE_FLOAT_SAMPLES + Sample max = 0.001f; +#else + Sample max = 8; +#endif + Sample *buf = buffer; for (Bit32u i = 0; i < size; i++) { - if (*buf < -8 || *buf > 8) return false; + if (*buf < -max || *buf > max) return false; buf++; } return true; } void RingBuffer::mute() { - Bit16s *buf = buffer; +#if MT32EMU_USE_FLOAT_SAMPLES + Sample *buf = buffer; for (Bit32u i = 0; i < size; i++) { *buf++ = 0; } +#else + memset(buffer, 0, size * sizeof(Sample)); +#endif } AllpassFilter::AllpassFilter(const Bit32u useSize) : RingBuffer(useSize) {} -Bit32s AllpassFilter::process(const Bit32s in) { +Sample AllpassFilter::process(const Sample in) { // This model corresponds to the allpass filter implementation of the real CM-32L device // found from sample analysis - Bit16s bufferOut = next(); + const Sample bufferOut = next(); +#if MT32EMU_USE_FLOAT_SAMPLES + // store input - feedback / 2 + buffer[index] = in - 0.5f * bufferOut; + + // return buffer output + feedforward / 2 + return bufferOut + 0.5f * buffer[index]; +#else // store input - feedback / 2 buffer[index] = in - (bufferOut >> 1); // return buffer output + feedforward / 2 return bufferOut + (buffer[index] >> 1); +#endif } CombFilter::CombFilter(const Bit32u useSize, const Bit32u useFilterFactor) : RingBuffer(useSize), filterFactor(useFilterFactor) {} -void CombFilter::process(const Bit32s in) { +void CombFilter::process(const Sample in) { // This model corresponds to the comb filter implementation of the real CM-32L device // the previously stored value - Bit32s last = buffer[index]; + const Sample last = buffer[index]; // prepare input + feedback - Bit32s filterIn = in + weirdMul(next(), feedbackFactor, 0xF0 /* Maybe 0x80 ? */); + const Sample filterIn = in + weirdMul(next(), feedbackFactor, 0xF0 /* Maybe 0x80 ? */); // store input + feedback processed by a low-pass filter buffer[index] = weirdMul(last, filterFactor, 0x40) - filterIn; } -Bit32s CombFilter::getOutputAt(const Bit32u outIndex) const { +Sample CombFilter::getOutputAt(const Bit32u outIndex) const { return buffer[(size + index - outIndex) % size]; } @@ -190,15 +212,15 @@ void CombFilter::setFeedbackFactor(const Bit32u useFeedbackFactor) { DelayWithLowPassFilter::DelayWithLowPassFilter(const Bit32u useSize, const Bit32u useFilterFactor, const Bit32u useAmp) : CombFilter(useSize, useFilterFactor), amp(useAmp) {} -void DelayWithLowPassFilter::process(const Bit32s in) { +void DelayWithLowPassFilter::process(const Sample in) { // the previously stored value - Bit32s last = buffer[index]; + const Sample last = buffer[index]; // move to the next index next(); // low-pass filter process - Bit32s lpfOut = weirdMul(last, filterFactor, 0xFF) + in; + Sample lpfOut = weirdMul(last, filterFactor, 0xFF) + in; // store lpfOut multiplied by LPF amp factor buffer[index] = weirdMul(lpfOut, amp, 0xFF); @@ -206,26 +228,26 @@ void DelayWithLowPassFilter::process(const Bit32s in) { TapDelayCombFilter::TapDelayCombFilter(const Bit32u useSize, const Bit32u useFilterFactor) : CombFilter(useSize, useFilterFactor) {} -void TapDelayCombFilter::process(const Bit32s in) { +void TapDelayCombFilter::process(const Sample in) { // the previously stored value - Bit32s last = buffer[index]; + const Sample last = buffer[index]; // move to the next index next(); // prepare input + feedback // Actually, the size of the filter varies with the TIME parameter, the feedback sample is taken from the position just below the right output - Bit32s filterIn = in + weirdMul(getOutputAt(outR + MODE_3_FEEDBACK_DELAY), feedbackFactor, 0xF0); + const Sample filterIn = in + weirdMul(getOutputAt(outR + MODE_3_FEEDBACK_DELAY), feedbackFactor, 0xF0); // store input + feedback processed by a low-pass filter buffer[index] = weirdMul(last, filterFactor, 0xF0) - filterIn; } -Bit32s TapDelayCombFilter::getLeftOutput() const { +Sample TapDelayCombFilter::getLeftOutput() const { return getOutputAt(outL + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY); } -Bit32s TapDelayCombFilter::getRightOutput() const { +Sample TapDelayCombFilter::getRightOutput() const { return getOutputAt(outR + PROCESS_DELAY + MODE_3_ADDITIONAL_DELAY); } @@ -327,14 +349,14 @@ bool BReverbModel::isActive() const { return false; } -void BReverbModel::process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples) { - Bit32s dry, link, outL1, outR1; +void BReverbModel::process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, unsigned long numSamples) { + Sample dry; - for (unsigned long i = 0; i < numSamples; i++) { + while (numSamples > 0) { if (tapDelayMode) { - dry = Bit32s(*inLeft * 8192.0f) + Bit32s(*inRight * 8192.0f); + dry = *inLeft + *inRight; } else { - dry = Bit32s(*inLeft * 8192.0f) / 2 + Bit32s(*inRight * 8192.0f) / 2; + dry = *inLeft / 2 + *inRight / 2; } // Looks like dryAmp doesn't change in MT-32 but it does in CM-32L / LAPC-I @@ -343,44 +365,53 @@ void BReverbModel::process(const float *inLeft, const float *inRight, float *out if (tapDelayMode) { TapDelayCombFilter *comb = static_cast<TapDelayCombFilter *> (*combs); comb->process(dry); - *outLeft = weirdMul(comb->getLeftOutput(), wetLevel, 0xFF) / 8192.0f; - *outRight = weirdMul(comb->getRightOutput(), wetLevel, 0xFF) / 8192.0f; + *outLeft = weirdMul(comb->getLeftOutput(), wetLevel, 0xFF); + *outRight = weirdMul(comb->getRightOutput(), wetLevel, 0xFF); } else { - // Get the last stored sample before processing in order not to loose it - link = combs[0]->getOutputAt(currentSettings.combSizes[0] - 1); + // If the output position is equal to the comb size, get it now in order not to loose it + Sample link = combs[0]->getOutputAt(currentSettings.combSizes[0] - 1); // Entrance LPF. Note, comb.process() differs a bit here. combs[0]->process(dry); +#if !MT32EMU_USE_FLOAT_SAMPLES // This introduces reverb noise which actually makes output from the real Boss chip nondeterministic link = link - 1; +#endif link = allpasses[0]->process(link); link = allpasses[1]->process(link); link = allpasses[2]->process(link); // If the output position is equal to the comb size, get it now in order not to loose it - outL1 = combs[1]->getOutputAt(currentSettings.outLPositions[0] - 1); - outL1 += outL1 >> 1; + Sample outL1 = combs[1]->getOutputAt(currentSettings.outLPositions[0] - 1); combs[1]->process(link); combs[2]->process(link); combs[3]->process(link); - link = combs[2]->getOutputAt(currentSettings.outLPositions[1]); - link += link >> 1; - link += outL1; - link += combs[3]->getOutputAt(currentSettings.outLPositions[2]); - *outLeft = weirdMul(link, wetLevel, 0xFF) / 8192.0f; + Sample outL2 = combs[2]->getOutputAt(currentSettings.outLPositions[1]); + Sample outL3 = combs[3]->getOutputAt(currentSettings.outLPositions[2]); + Sample outR1 = combs[1]->getOutputAt(currentSettings.outRPositions[0]); + Sample outR2 = combs[2]->getOutputAt(currentSettings.outRPositions[1]); + Sample outR3 = combs[3]->getOutputAt(currentSettings.outRPositions[2]); + +#if MT32EMU_USE_FLOAT_SAMPLES + *outLeft = 1.5f * (outL1 + outL2) + outL3; + *outRight = 1.5f * (outR1 + outR2) + outR3; +#else + outL1 += outL1 >> 1; + outL2 += outL2 >> 1; + *outLeft = outL1 + outL2 + outL3; - outR1 = combs[1]->getOutputAt(currentSettings.outRPositions[0]); outR1 += outR1 >> 1; - link = combs[2]->getOutputAt(currentSettings.outRPositions[1]); - link += link >> 1; - link += outR1; - link += combs[3]->getOutputAt(currentSettings.outRPositions[2]); - *outRight = weirdMul(link, wetLevel, 0xFF) / 8192.0f; + outR2 += outR2 >> 1; + *outRight = outR1 + outR2 + outR3; +#endif + *outLeft = weirdMul(*outLeft, wetLevel, 0xFF); + *outRight = weirdMul(*outRight, wetLevel, 0xFF); } + numSamples--; inLeft++; inRight++; outLeft++; @@ -389,5 +420,3 @@ void BReverbModel::process(const float *inLeft, const float *inRight, float *out } } - -#endif diff --git a/audio/softsynth/mt32/BReverbModel.h b/audio/softsynth/mt32/BReverbModel.h index d6fcb73c13..7cf431db0d 100644 --- a/audio/softsynth/mt32/BReverbModel.h +++ b/audio/softsynth/mt32/BReverbModel.h @@ -36,14 +36,14 @@ struct BReverbSettings { class RingBuffer { protected: - Bit16s *buffer; + Sample *buffer; const Bit32u size; Bit32u index; public: RingBuffer(const Bit32u size); virtual ~RingBuffer(); - Bit32s next(); + Sample next(); bool isEmpty() const; void mute(); }; @@ -51,7 +51,7 @@ public: class AllpassFilter : public RingBuffer { public: AllpassFilter(const Bit32u size); - Bit32s process(const Bit32s in); + Sample process(const Sample in); }; class CombFilter : public RingBuffer { @@ -61,8 +61,8 @@ protected: public: CombFilter(const Bit32u size, const Bit32u useFilterFactor); - virtual void process(const Bit32s in); // Actually, no need to make it virtual, but for sure - Bit32s getOutputAt(const Bit32u outIndex) const; + virtual void process(const Sample in); + Sample getOutputAt(const Bit32u outIndex) const; void setFeedbackFactor(const Bit32u useFeedbackFactor); }; @@ -71,7 +71,7 @@ class DelayWithLowPassFilter : public CombFilter { public: DelayWithLowPassFilter(const Bit32u useSize, const Bit32u useFilterFactor, const Bit32u useAmp); - void process(const Bit32s in); + void process(const Sample in); void setFeedbackFactor(const Bit32u) {} }; @@ -81,13 +81,13 @@ class TapDelayCombFilter : public CombFilter { public: TapDelayCombFilter(const Bit32u useSize, const Bit32u useFilterFactor); - void process(const Bit32s in); - Bit32s getLeftOutput() const; - Bit32s getRightOutput() const; + void process(const Sample in); + Sample getLeftOutput() const; + Sample getRightOutput() const; void setOutputPositions(const Bit32u useOutL, const Bit32u useOutR); }; -class BReverbModel : public ReverbModel { +class BReverbModel { AllpassFilter **allpasses; CombFilter **combs; @@ -100,10 +100,12 @@ class BReverbModel : public ReverbModel { public: BReverbModel(const ReverbMode mode); ~BReverbModel(); + // After construction or a close(), open() must be called at least once before any other call (with the exception of close()). void open(); + // May be called multiple times without an open() in between. void close(); void setParameters(Bit8u time, Bit8u level); - void process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples); + void process(const Sample *inLeft, const Sample *inRight, Sample *outLeft, Sample *outRight, unsigned long numSamples); bool isActive() const; }; diff --git a/audio/softsynth/mt32/DelayReverb.cpp b/audio/softsynth/mt32/DelayReverb.cpp deleted file mode 100644 index d80c98acbc..0000000000 --- a/audio/softsynth/mt32/DelayReverb.cpp +++ /dev/null @@ -1,142 +0,0 @@ -/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher - * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -//#include <cmath> -//#include <cstring> -#include "mt32emu.h" -#include "DelayReverb.h" - -namespace MT32Emu { - -// CONFIRMED: The values below are found via analysis of digital samples and tracing reverb RAM address / data lines. Checked with all time and level combinations. -// Obviously: -// rightDelay = (leftDelay - 2) * 2 + 2 -// echoDelay = rightDelay - 1 -// Leaving these separate in case it's useful for work on other reverb modes... -static const Bit32u REVERB_TIMINGS[8][3]= { - // {leftDelay, rightDelay, feedbackDelay} - {402, 802, 801}, - {626, 1250, 1249}, - {962, 1922, 1921}, - {1490, 2978, 2977}, - {2258, 4514, 4513}, - {3474, 6946, 6945}, - {5282, 10562, 10561}, - {8002, 16002, 16001} -}; - -// Reverb amp is found as dryAmp * wetAmp -static const Bit32u REVERB_AMP[8] = {0x20*0x18, 0x50*0x18, 0x50*0x28, 0x50*0x40, 0x50*0x60, 0x50*0x80, 0x50*0xA8, 0x50*0xF8}; -static const Bit32u REVERB_FEEDBACK67 = 0x60; -static const Bit32u REVERB_FEEDBACK = 0x68; -static const float LPF_VALUE = 0x68 / 256.0f; - -static const Bit32u BUFFER_SIZE = 16384; - -DelayReverb::DelayReverb() { - buf = NULL; - setParameters(0, 0); -} - -DelayReverb::~DelayReverb() { - delete[] buf; -} - -void DelayReverb::open() { - if (buf == NULL) { - delete[] buf; - - buf = new float[BUFFER_SIZE]; - - recalcParameters(); - - // mute buffer - bufIx = 0; - if (buf != NULL) { - for (unsigned int i = 0; i < BUFFER_SIZE; i++) { - buf[i] = 0.0f; - } - } - } -} - -void DelayReverb::close() { - delete[] buf; - buf = NULL; -} - -// This method will always trigger a flush of the buffer -void DelayReverb::setParameters(Bit8u newTime, Bit8u newLevel) { - time = newTime; - level = newLevel; - recalcParameters(); -} - -void DelayReverb::recalcParameters() { - // Number of samples between impulse and eventual appearance on the left channel - delayLeft = REVERB_TIMINGS[time][0]; - // Number of samples between impulse and eventual appearance on the right channel - delayRight = REVERB_TIMINGS[time][1]; - // Number of samples between a response and that response feeding back/echoing - delayFeedback = REVERB_TIMINGS[time][2]; - - if (level < 3 || time < 6) { - feedback = REVERB_FEEDBACK / 256.0f; - } else { - feedback = REVERB_FEEDBACK67 / 256.0f; - } - - // Overall output amp - amp = (level == 0 && time == 0) ? 0.0f : REVERB_AMP[level] / 65536.0f; -} - -void DelayReverb::process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples) { - if (buf == NULL) return; - - for (unsigned int sampleIx = 0; sampleIx < numSamples; sampleIx++) { - // The ring buffer write index moves backwards; reads are all done with positive offsets. - Bit32u bufIxPrev = (bufIx + 1) % BUFFER_SIZE; - Bit32u bufIxLeft = (bufIx + delayLeft) % BUFFER_SIZE; - Bit32u bufIxRight = (bufIx + delayRight) % BUFFER_SIZE; - Bit32u bufIxFeedback = (bufIx + delayFeedback) % BUFFER_SIZE; - - // Attenuated input samples and feedback response are directly added to the current ring buffer location - float lpfIn = amp * (inLeft[sampleIx] + inRight[sampleIx]) + feedback * buf[bufIxFeedback]; - - // Single-pole IIR filter found on real devices - buf[bufIx] = buf[bufIxPrev] * LPF_VALUE - lpfIn; - - outLeft[sampleIx] = buf[bufIxLeft]; - outRight[sampleIx] = buf[bufIxRight]; - - bufIx = (BUFFER_SIZE + bufIx - 1) % BUFFER_SIZE; - } -} - -bool DelayReverb::isActive() const { - if (buf == NULL) return false; - - float *b = buf; - float max = 0.001f; - for (Bit32u i = 0; i < BUFFER_SIZE; i++) { - if ((*b < -max) || (*b > max)) return true; - b++; - } - return false; -} - -} diff --git a/audio/softsynth/mt32/DelayReverb.h b/audio/softsynth/mt32/DelayReverb.h deleted file mode 100644 index c8003832b5..0000000000 --- a/audio/softsynth/mt32/DelayReverb.h +++ /dev/null @@ -1,50 +0,0 @@ -/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher - * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MT32EMU_DELAYREVERB_H -#define MT32EMU_DELAYREVERB_H - -namespace MT32Emu { - -class DelayReverb : public ReverbModel { -private: - Bit8u time; - Bit8u level; - - Bit32u bufIx; - float *buf; - - Bit32u delayLeft; - Bit32u delayRight; - Bit32u delayFeedback; - - float amp; - float feedback; - - void recalcParameters(); - -public: - DelayReverb(); - ~DelayReverb(); - void open(); - void close(); - void setParameters(Bit8u time, Bit8u level); - void process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples); - bool isActive() const; -}; -} -#endif diff --git a/audio/softsynth/mt32/FreeverbModel.cpp b/audio/softsynth/mt32/FreeverbModel.cpp deleted file mode 100644 index bd9c70b6f4..0000000000 --- a/audio/softsynth/mt32/FreeverbModel.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher - * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#include "mt32emu.h" -#include "FreeverbModel.h" - -#include "freeverb.h" - -namespace MT32Emu { - -FreeverbModel::FreeverbModel(float useScaleTuning, float useFiltVal, float useWet, Bit8u useRoom, float useDamp) { - freeverb = NULL; - scaleTuning = useScaleTuning; - filtVal = useFiltVal; - wet = useWet; - room = useRoom; - damp = useDamp; -} - -FreeverbModel::~FreeverbModel() { - delete freeverb; -} - -void FreeverbModel::open() { - if (freeverb == NULL) { - freeverb = new revmodel(scaleTuning); - } - freeverb->mute(); - - // entrance Lowpass filter factor - freeverb->setfiltval(filtVal); - - // decay speed of high frequencies in the wet signal - freeverb->setdamp(damp); -} - -void FreeverbModel::close() { - delete freeverb; - freeverb = NULL; -} - -void FreeverbModel::process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples) { - freeverb->process(inLeft, inRight, outLeft, outRight, numSamples); -} - -void FreeverbModel::setParameters(Bit8u time, Bit8u level) { - // wet signal level - // FIXME: need to implement some sort of reverb level ramping - freeverb->setwet((float)level / 7.0f * wet); - - // wet signal decay speed - static float roomTable[] = { - 0.25f, 0.37f, 0.54f, 0.71f, 0.78f, 0.86f, 0.93f, 1.00f, - -1.00f, -0.50f, 0.00f, 0.30f, 0.51f, 0.64f, 0.77f, 0.90f, - 0.50f, 0.57f, 0.70f, 0.77f, 0.85f, 0.93f, 0.96f, 1.01f}; - freeverb->setroomsize(roomTable[8 * room + time]); -} - -bool FreeverbModel::isActive() const { - // FIXME: Not bothering to do this properly since we'll be replacing Freeverb soon... - return false; -} - -} diff --git a/audio/softsynth/mt32/FreeverbModel.h b/audio/softsynth/mt32/FreeverbModel.h deleted file mode 100644 index 5ea11f1f40..0000000000 --- a/audio/softsynth/mt32/FreeverbModel.h +++ /dev/null @@ -1,44 +0,0 @@ -/* Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 Dean Beeler, Jerome Fisher - * Copyright (C) 2011, 2012, 2013 Dean Beeler, Jerome Fisher, Sergey V. Mikayev - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License as published by - * the Free Software Foundation, either version 2.1 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 Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public License - * along with this program. If not, see <http://www.gnu.org/licenses/>. - */ - -#ifndef MT32EMU_FREEVERB_MODEL_H -#define MT32EMU_FREEVERB_MODEL_H - -class revmodel; - -namespace MT32Emu { - -class FreeverbModel : public ReverbModel { - revmodel *freeverb; - float scaleTuning; - float filtVal; - float wet; - Bit8u room; - float damp; -public: - FreeverbModel(float useScaleTuning, float useFiltVal, float useWet, Bit8u useRoom, float useDamp); - ~FreeverbModel(); - void open(); - void close(); - void setParameters(Bit8u time, Bit8u level); - void process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples); - bool isActive() const; -}; - -} - -#endif diff --git a/audio/softsynth/mt32/LegacyWaveGenerator.cpp b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp index 35ca975018..486942b75c 100644 --- a/audio/softsynth/mt32/LegacyWaveGenerator.cpp +++ b/audio/softsynth/mt32/LA32FloatWaveGenerator.cpp @@ -18,9 +18,7 @@ //#include <cmath> #include "mt32emu.h" #include "mmath.h" -#include "LegacyWaveGenerator.h" - -#if MT32EMU_ACCURATE_WG == 1 +#include "LA32FloatWaveGenerator.h" namespace MT32Emu { @@ -317,7 +315,7 @@ void LA32PartialPair::generateNextSample(const PairType useMaster, const Bit32u } } -Bit16s LA32PartialPair::nextOutSample() { +float LA32PartialPair::nextOutSample() { float outputSample; if (ringModulated) { float ringModulatedSample = masterOutputSample * slaveOutputSample; @@ -325,7 +323,7 @@ Bit16s LA32PartialPair::nextOutSample() { } else { outputSample = masterOutputSample + slaveOutputSample; } - return Bit16s(outputSample * 8192.0f); + return outputSample; } void LA32PartialPair::deactivate(const PairType useMaster) { @@ -343,5 +341,3 @@ bool LA32PartialPair::isActive(const PairType useMaster) const { } } - -#endif // #if MT32EMU_ACCURATE_WG == 1 diff --git a/audio/softsynth/mt32/LegacyWaveGenerator.h b/audio/softsynth/mt32/LA32FloatWaveGenerator.h index 81c1b9c713..9046160083 100644 --- a/audio/softsynth/mt32/LegacyWaveGenerator.h +++ b/audio/softsynth/mt32/LA32FloatWaveGenerator.h @@ -15,8 +15,6 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#if MT32EMU_ACCURATE_WG == 1 - #ifndef MT32EMU_LA32_WAVE_GENERATOR_H #define MT32EMU_LA32_WAVE_GENERATOR_H @@ -130,7 +128,7 @@ public: void generateNextSample(const PairType master, const Bit32u amp, const Bit16u pitch, const Bit32u cutoff); // Perform mixing / ring modulation and return the result - Bit16s nextOutSample(); + float nextOutSample(); // Deactivate the WG engine void deactivate(const PairType master); @@ -142,5 +140,3 @@ public: } // namespace MT32Emu #endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H - -#endif // #if MT32EMU_ACCURATE_WG == 1 diff --git a/audio/softsynth/mt32/LA32WaveGenerator.cpp b/audio/softsynth/mt32/LA32WaveGenerator.cpp index 80650699fb..9ffc2ca32e 100644 --- a/audio/softsynth/mt32/LA32WaveGenerator.cpp +++ b/audio/softsynth/mt32/LA32WaveGenerator.cpp @@ -20,7 +20,9 @@ #include "mmath.h" #include "LA32WaveGenerator.h" -#if MT32EMU_ACCURATE_WG == 0 +#if MT32EMU_USE_FLOAT_SAMPLES +#include "LA32FloatWaveGenerator.cpp" +#else namespace MT32Emu { @@ -129,7 +131,8 @@ void LA32WaveGenerator::advancePosition() { computePositions(highLinearLength, lowLinearLength, resonanceWaveLengthFactor); // resonancePhase computation hack - *(int*)&resonancePhase = ((resonanceSinePosition >> 18) + (phase > POSITIVE_FALLING_SINE_SEGMENT ? 2 : 0)) & 3; + int *resonancePhaseAlias = (int *)&resonancePhase; + *resonancePhaseAlias = ((resonanceSinePosition >> 18) + (phase > POSITIVE_FALLING_SINE_SEGMENT ? 2 : 0)) & 3; } void LA32WaveGenerator::generateNextSquareWaveLogSample() { @@ -415,4 +418,4 @@ bool LA32PartialPair::isActive(const PairType useMaster) const { } -#endif // #if MT32EMU_ACCURATE_WG == 0 +#endif // #if MT32EMU_USE_FLOAT_SAMPLES diff --git a/audio/softsynth/mt32/LA32WaveGenerator.h b/audio/softsynth/mt32/LA32WaveGenerator.h index 37a4aead85..4bc04c78d3 100644 --- a/audio/softsynth/mt32/LA32WaveGenerator.h +++ b/audio/softsynth/mt32/LA32WaveGenerator.h @@ -15,7 +15,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. */ -#if MT32EMU_ACCURATE_WG == 0 +#if MT32EMU_USE_FLOAT_SAMPLES +#include "LA32FloatWaveGenerator.h" +#else #ifndef MT32EMU_LA32_WAVE_GENERATOR_H #define MT32EMU_LA32_WAVE_GENERATOR_H @@ -243,4 +245,4 @@ public: #endif // #ifndef MT32EMU_LA32_WAVE_GENERATOR_H -#endif // #if MT32EMU_ACCURATE_WG == 0 +#endif // #if MT32EMU_USE_FLOAT_SAMPLES diff --git a/audio/softsynth/mt32/Part.cpp b/audio/softsynth/mt32/Part.cpp index 88404316eb..8a0daf3b38 100644 --- a/audio/softsynth/mt32/Part.cpp +++ b/audio/softsynth/mt32/Part.cpp @@ -67,18 +67,12 @@ Part::Part(Synth *useSynth, unsigned int usePartNum) { pitchBend = 0; activePartialCount = 0; memset(patchCache, 0, sizeof(patchCache)); - for (int i = 0; i < MT32EMU_MAX_POLY; i++) { - freePolys.prepend(new Poly(this)); - } } Part::~Part() { while (!activePolys.isEmpty()) { delete activePolys.takeFirst(); } - while (!freePolys.isEmpty()) { - delete freePolys.takeFirst(); - } } void Part::setDataEntryMSB(unsigned char midiDataEntryMSB) { @@ -431,23 +425,10 @@ void Part::noteOn(unsigned int midiKey, unsigned int velocity) { playPoly(patchCache, NULL, midiKey, key, velocity); } -void Part::abortPoly(Poly *poly) { - if (poly->startAbort()) { - while (poly->isActive()) { - if (!synth->prerender()) { - synth->printDebug("%s (%s): Ran out of prerender space to abort poly gracefully", name, currentInstr); - poly->terminate(); - break; - } - } - } -} - bool Part::abortFirstPoly(unsigned int key) { for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { if (poly->getKey() == key) { - abortPoly(poly); - return true; + return poly->startAbort(); } } return false; @@ -456,8 +437,7 @@ bool Part::abortFirstPoly(unsigned int key) { bool Part::abortFirstPoly(PolyState polyState) { for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { if (poly->getState() == polyState) { - abortPoly(poly); - return true; + return poly->startAbort(); } } return false; @@ -474,8 +454,7 @@ bool Part::abortFirstPoly() { if (activePolys.isEmpty()) { return false; } - abortPoly(activePolys.getFirst()); - return true; + return activePolys.getFirst()->startAbort(); } void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhythmTemp, unsigned int midiKey, unsigned int key, unsigned int velocity) { @@ -489,6 +468,7 @@ void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhyt if ((patchTemp->patch.assignMode & 2) == 0) { // Single-assign mode abortFirstPoly(key); + if (synth->isAbortingPoly()) return; } if (!synth->partialManager->freePartials(needPartials, partNum)) { @@ -498,12 +478,13 @@ void Part::playPoly(const PatchCache cache[4], const MemParams::RhythmTemp *rhyt #endif return; } + if (synth->isAbortingPoly()) return; - if (freePolys.isEmpty()) { + Poly *poly = synth->partialManager->assignPolyToPart(this); + if (poly == NULL) { synth->printDebug("%s (%s): No free poly to play key %d (velocity %d)", name, currentInstr, midiKey, velocity); return; } - Poly *poly = freePolys.takeFirst(); if (patchTemp->patch.assignMode & 1) { // Priority to data first received activePolys.prepend(poly); @@ -596,6 +577,10 @@ unsigned int Part::getActivePartialCount() const { return activePartialCount; } +const Poly *Part::getFirstActivePoly() const { + return activePolys.getFirst(); +} + unsigned int Part::getActiveNonReleasingPartialCount() const { unsigned int activeNonReleasingPartialCount = 0; for (Poly *poly = activePolys.getFirst(); poly != NULL; poly = poly->getNext()) { @@ -606,11 +591,15 @@ unsigned int Part::getActiveNonReleasingPartialCount() const { return activeNonReleasingPartialCount; } +Synth *Part::getSynth() const { + return synth; +} + void Part::partialDeactivated(Poly *poly) { activePartialCount--; if (!poly->isActive()) { activePolys.remove(poly); - freePolys.prepend(poly); + synth->partialManager->polyFreed(poly); synth->polyStateChanged(partNum); } } diff --git a/audio/softsynth/mt32/Part.h b/audio/softsynth/mt32/Part.h index b6585880fe..2aeeaf5bd7 100644 --- a/audio/softsynth/mt32/Part.h +++ b/audio/softsynth/mt32/Part.h @@ -51,13 +51,11 @@ private: unsigned int activePartialCount; PatchCache patchCache[4]; - PolyList freePolys; PolyList activePolys; void setPatch(const PatchParam *patch); unsigned int midiKeyToKey(unsigned int midiKey); - void abortPoly(Poly *poly); bool abortFirstPoly(unsigned int key); protected: @@ -110,8 +108,10 @@ public: virtual void setTimbre(TimbreParam *timbre); virtual unsigned int getAbsTimbreNum() const; const char *getCurrentInstr() const; + const Poly *getFirstActivePoly() const; unsigned int getActivePartialCount() const; unsigned int getActiveNonReleasingPartialCount() const; + Synth *getSynth() const; const MemParams::PatchTemp *getPatchTemp() const; diff --git a/audio/softsynth/mt32/Partial.cpp b/audio/softsynth/mt32/Partial.cpp index b80a028515..c7848f02d8 100644 --- a/audio/softsynth/mt32/Partial.cpp +++ b/audio/softsynth/mt32/Partial.cpp @@ -131,6 +131,7 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us } // 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; @@ -198,9 +199,6 @@ void Partial::startPartial(const Part *part, Poly *usePoly, const PatchCache *us if (!hasRingModulatingSlave()) { la32Pair.deactivate(LA32PartialPair::SLAVE); } - // Temporary integration hack - stereoVolume.leftVol /= 8192.0f; - stereoVolume.rightVol /= 8192.0f; } Bit32u Partial::getAmpValue() { @@ -232,7 +230,7 @@ Bit32u Partial::getCutoffValue() { return (tvf->getBaseCutoff() << 18) + cutoffModifierRampVal; } -unsigned long Partial::generateSamples(Bit16s *partialBuf, unsigned long length) { +unsigned long Partial::generateSamples(Sample *partialBuf, unsigned long length) { if (!isActive() || alreadyOutputed) { return 0; } @@ -258,7 +256,7 @@ unsigned long Partial::generateSamples(Bit16s *partialBuf, unsigned long length) } } } - *partialBuf++ = la32Pair.nextOutSample(); + *(partialBuf++) = la32Pair.nextOutSample(); } unsigned long renderedSamples = sampleNum; sampleNum = 0; @@ -288,7 +286,18 @@ Synth *Partial::getSynth() const { return synth; } -bool Partial::produceOutput(float *leftBuf, float *rightBuf, unsigned long length) { +TVA *Partial::getTVA() const { + return tva; +} + +void Partial::backupCache(const PatchCache &cache) { + if (patchCache == &cache) { + cachebackup = cache; + patchCache = &cachebackup; + } +} + +bool Partial::produceOutput(Sample *leftBuf, Sample *rightBuf, unsigned long length) { if (!isActive() || alreadyOutputed || isRingModulatingSlave()) { return false; } @@ -296,14 +305,18 @@ bool Partial::produceOutput(float *leftBuf, float *rightBuf, unsigned long lengt synth->printDebug("[Partial %d] *** ERROR: poly is NULL at Partial::produceOutput()!", debugPartialNum); return false; } - unsigned long numGenerated = generateSamples(myBuffer, length); + Sample buffer[MAX_SAMPLES_PER_RUN]; + unsigned long numGenerated = generateSamples(buffer, length); for (unsigned int i = 0; i < numGenerated; i++) { - *leftBuf++ = myBuffer[i] * stereoVolume.leftVol; - *rightBuf++ = myBuffer[i] * stereoVolume.rightVol; - } - for (; numGenerated < length; numGenerated++) { - *leftBuf++ = 0.0f; - *rightBuf++ = 0.0f; +#if MT32EMU_USE_FLOAT_SAMPLES + *(leftBuf++) += buffer[i] * stereoVolume.leftVol; + *(rightBuf++) += buffer[i] * stereoVolume.rightVol; +#else + *leftBuf = Synth::clipBit16s((Bit32s)*leftBuf + Bit32s(buffer[i] * stereoVolume.leftVol)); + *rightBuf = Synth::clipBit16s((Bit32s)*rightBuf + Bit32s(buffer[i] * stereoVolume.rightVol)); + leftBuf++; + rightBuf++; +#endif } return true; } diff --git a/audio/softsynth/mt32/Partial.h b/audio/softsynth/mt32/Partial.h index 21b1bfe376..358cb9d2d9 100644 --- a/audio/softsynth/mt32/Partial.h +++ b/audio/softsynth/mt32/Partial.h @@ -44,8 +44,6 @@ private: int structurePosition; // 0 or 1 of a structure pair StereoVolume stereoVolume; - Bit16s myBuffer[MAX_SAMPLES_PER_RUN]; - // Only used for PCM partials int pcmNum; // FIXME: Give this a better name (e.g. pcmWaveInfo) @@ -56,6 +54,11 @@ private: int pulseWidthVal; Poly *poly; + Partial *pair; + + TVA *tva; + TVP *tvp; + TVF *tvf; LA32Ramp ampRamp; LA32Ramp cutoffModifierRamp; @@ -63,18 +66,13 @@ private: // TODO: This should be owned by PartialPair LA32PartialPair la32Pair; + const PatchCache *patchCache; + PatchCache cachebackup; + Bit32u getAmpValue(); Bit32u getCutoffValue(); public: - const PatchCache *patchCache; - TVA *tva; - TVP *tvp; - TVF *tvf; - - PatchCache cachebackup; - - Partial *pair; bool alreadyOutputed; Partial(Synth *synth, int debugPartialNum); @@ -97,14 +95,17 @@ public: bool isPCM() const; const ControlROMPCMStruct *getControlROMPCMStruct() const; Synth *getSynth() const; + TVA *getTVA() const; + + void backupCache(const PatchCache &cache); // Returns true only if data written to buffer // 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(float *leftBuf, float *rightBuf, unsigned long length); + 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(Bit16s *partialBuf, unsigned long length); + unsigned long generateSamples(Sample *partialBuf, unsigned long length); }; } diff --git a/audio/softsynth/mt32/PartialManager.cpp b/audio/softsynth/mt32/PartialManager.cpp index 436e7a353e..905b5b8cf3 100644 --- a/audio/softsynth/mt32/PartialManager.cpp +++ b/audio/softsynth/mt32/PartialManager.cpp @@ -25,19 +25,26 @@ namespace MT32Emu { PartialManager::PartialManager(Synth *useSynth, Part **useParts) { synth = useSynth; parts = useParts; - for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { + partialTable = new Partial *[synth->getPartialCount()]; + freePolys = new Poly *[synth->getPartialCount()]; + firstFreePolyIndex = 0; + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { partialTable[i] = new Partial(synth, i); + freePolys[i] = new Poly(); } } PartialManager::~PartialManager(void) { - for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { delete partialTable[i]; + if (freePolys[i] != NULL) delete freePolys[i]; } + delete[] partialTable; + delete[] freePolys; } void PartialManager::clearAlreadyOutputed() { - for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { partialTable[i]->alreadyOutputed = false; } } @@ -46,12 +53,12 @@ bool PartialManager::shouldReverb(int i) { return partialTable[i]->shouldReverb(); } -bool PartialManager::produceOutput(int i, float *leftBuf, float *rightBuf, Bit32u bufferLength) { +bool PartialManager::produceOutput(int i, Sample *leftBuf, Sample *rightBuf, Bit32u bufferLength) { return partialTable[i]->produceOutput(leftBuf, rightBuf, bufferLength); } void PartialManager::deactivateAll() { - for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { partialTable[i]->deactivate(); } } @@ -69,7 +76,7 @@ Partial *PartialManager::allocPartial(int partNum) { Partial *outPartial = NULL; // Get the first inactive partial - for (int partialNum = 0; partialNum < MT32EMU_MAX_PARTIALS; partialNum++) { + for (unsigned int partialNum = 0; partialNum < synth->getPartialCount(); partialNum++) { if (!partialTable[partialNum]->isActive()) { outPartial = partialTable[partialNum]; break; @@ -83,7 +90,7 @@ Partial *PartialManager::allocPartial(int partNum) { unsigned int PartialManager::getFreePartialCount(void) { int count = 0; - for (int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { if (!partialTable[i]->isActive()) { count++; } @@ -94,7 +101,7 @@ unsigned int PartialManager::getFreePartialCount(void) { // This function is solely used to gather data for debug output at the moment. void PartialManager::getPerPartPartialUsage(unsigned int perPartPartialUsage[9]) { memset(perPartPartialUsage, 0, 9 * sizeof(unsigned int)); - for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { + for (unsigned int i = 0; i < synth->getPartialCount(); i++) { if (partialTable[i]->isActive()) { perPartPartialUsage[partialTable[i]->getOwnerPart()]++; } @@ -189,7 +196,7 @@ bool PartialManager::freePartials(unsigned int needed, int partNum) { break; } #endif - if (getFreePartialCount() >= needed) { + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { return true; } } @@ -206,7 +213,7 @@ bool PartialManager::freePartials(unsigned int needed, int partNum) { if (!abortFirstPolyPreferHeldWhereReserveExceeded(partNum)) { break; } - if (getFreePartialCount() >= needed) { + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { return true; } } @@ -222,7 +229,7 @@ bool PartialManager::freePartials(unsigned int needed, int partNum) { if (!abortFirstPolyPreferHeldWhereReserveExceeded(-1)) { break; } - if (getFreePartialCount() >= needed) { + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { return true; } } @@ -233,7 +240,7 @@ bool PartialManager::freePartials(unsigned int needed, int partNum) { if (!parts[partNum]->abortFirstPolyPreferHeld()) { break; } - if (getFreePartialCount() >= needed) { + if (synth->isAbortingPoly() || getFreePartialCount() >= needed) { return true; } } @@ -243,10 +250,39 @@ bool PartialManager::freePartials(unsigned int needed, int partNum) { } const Partial *PartialManager::getPartial(unsigned int partialNum) const { - if (partialNum > MT32EMU_MAX_PARTIALS - 1) { + if (partialNum > synth->getPartialCount() - 1) { return NULL; } return partialTable[partialNum]; } +Poly *PartialManager::assignPolyToPart(Part *part) { + if (firstFreePolyIndex < synth->getPartialCount()) { + Poly *poly = freePolys[firstFreePolyIndex]; + freePolys[firstFreePolyIndex] = NULL; + firstFreePolyIndex++; + poly->setPart(part); + return poly; + } + return NULL; +} + +void PartialManager::polyFreed(Poly *poly) { + if (0 == firstFreePolyIndex) { + synth->printDebug("Cannot return freed poly, currently active polys:\n"); + for (Bit32u partNum = 0; partNum < 9; partNum++) { + const Poly *activePoly = synth->getPart(partNum)->getFirstActivePoly(); + Bit32u polyCount = 0; + while (activePoly != NULL) { + activePoly->getNext(); + polyCount++; + } + synth->printDebug("Part: %i, active poly count: %i\n", partNum, polyCount); + } + } + poly->setPart(NULL); + firstFreePolyIndex--; + freePolys[firstFreePolyIndex] = poly; +} + } diff --git a/audio/softsynth/mt32/PartialManager.h b/audio/softsynth/mt32/PartialManager.h index a1c9266ea1..229b6e8121 100644 --- a/audio/softsynth/mt32/PartialManager.h +++ b/audio/softsynth/mt32/PartialManager.h @@ -24,17 +24,17 @@ class Synth; class PartialManager { private: - Synth *synth; // Only used for sending debug output + Synth *synth; Part **parts; - - Partial *partialTable[MT32EMU_MAX_PARTIALS]; + Poly **freePolys; + Partial **partialTable; Bit8u numReservedPartialsForPart[9]; + Bit32u firstFreePolyIndex; bool abortFirstReleasingPolyWhereReserveExceeded(int minPart); bool abortFirstPolyPreferHeldWhereReserveExceeded(int minPart); public: - PartialManager(Synth *synth, Part **parts); ~PartialManager(); Partial *allocPartial(int partNum); @@ -43,10 +43,12 @@ public: bool freePartials(unsigned int needed, int partNum); unsigned int setReserve(Bit8u *rset); void deactivateAll(); - bool produceOutput(int i, float *leftBuf, float *rightBuf, Bit32u bufferLength); + bool produceOutput(int i, Sample *leftBuf, Sample *rightBuf, Bit32u bufferLength); bool shouldReverb(int i); void clearAlreadyOutputed(); const Partial *getPartial(unsigned int partialNum) const; + Poly *assignPolyToPart(Part *part); + void polyFreed(Poly *poly); }; } diff --git a/audio/softsynth/mt32/Poly.cpp b/audio/softsynth/mt32/Poly.cpp index 46574f8967..1554881270 100644 --- a/audio/softsynth/mt32/Poly.cpp +++ b/audio/softsynth/mt32/Poly.cpp @@ -19,8 +19,8 @@ namespace MT32Emu { -Poly::Poly(Part *usePart) { - part = usePart; +Poly::Poly() { + part = NULL; key = 255; velocity = 255; sustain = false; @@ -32,10 +32,21 @@ Poly::Poly(Part *usePart) { next = NULL; } +void Poly::setPart(Part *usePart) { + part = usePart; +} + void Poly::reset(unsigned int newKey, unsigned int newVelocity, bool newSustain, Partial **newPartials) { if (isActive()) { - // FIXME: Throw out some big ugly debug output with a lot of exclamation marks - we should never get here - terminate(); + // This should never happen + part->getSynth()->printDebug("Resetting active poly. Active partial count: %i\n", activePartialCount); + for (int i = 0; i < 4; i++) { + if (partials[i] != NULL && partials[i]->isActive()) { + partials[i]->deactivate(); + activePartialCount--; + } + } + state = POLY_Inactive; } key = newKey; @@ -92,41 +103,24 @@ bool Poly::startDecay() { } bool Poly::startAbort() { - if (state == POLY_Inactive) { + if (state == POLY_Inactive || part->getSynth()->isAbortingPoly()) { return false; } for (int t = 0; t < 4; t++) { Partial *partial = partials[t]; if (partial != NULL) { partial->startAbort(); + part->getSynth()->abortingPoly = this; } } return true; } -void Poly::terminate() { - if (state == POLY_Inactive) { - return; - } - for (int t = 0; t < 4; t++) { - Partial *partial = partials[t]; - if (partial != NULL) { - partial->deactivate(); - } - } - if (state != POLY_Inactive) { - // FIXME: Throw out lots of debug output - this should never happen - // (Deactivating the partials above should've made them each call partialDeactivated(), ultimately changing the state to POLY_Inactive) - state = POLY_Inactive; - } -} - void Poly::backupCacheToPartials(PatchCache cache[4]) { for (int partialNum = 0; partialNum < 4; partialNum++) { Partial *partial = partials[partialNum]; - if (partial != NULL && partial->patchCache == &cache[partialNum]) { - partial->cachebackup = cache[partialNum]; - partial->patchCache = &partial->cachebackup; + if (partial != NULL) { + partial->backupCache(cache[partialNum]); } } } @@ -171,11 +165,14 @@ void Poly::partialDeactivated(Partial *partial) { } if (activePartialCount == 0) { state = POLY_Inactive; + if (part->getSynth()->abortingPoly == this) { + part->getSynth()->abortingPoly = NULL; + } } part->partialDeactivated(this); } -Poly *Poly::getNext() { +Poly *Poly::getNext() const { return next; } diff --git a/audio/softsynth/mt32/Poly.h b/audio/softsynth/mt32/Poly.h index 068cf73d35..33abc35fdf 100644 --- a/audio/softsynth/mt32/Poly.h +++ b/audio/softsynth/mt32/Poly.h @@ -44,13 +44,13 @@ private: Poly *next; public: - Poly(Part *part); + Poly(); + void setPart(Part *usePart); void reset(unsigned int key, unsigned int velocity, bool sustain, Partial **partials); bool noteOff(bool pedalHeld); bool stopPedalHold(); bool startDecay(); bool startAbort(); - void terminate(); void backupCacheToPartials(PatchCache cache[4]); @@ -63,7 +63,7 @@ public: void partialDeactivated(Partial *partial); - Poly *getNext(); + Poly *getNext() const; void setNext(Poly *poly); }; diff --git a/audio/softsynth/mt32/Structures.h b/audio/softsynth/mt32/Structures.h index 43d2d1f226..421e427fc0 100644 --- a/audio/softsynth/mt32/Structures.h +++ b/audio/softsynth/mt32/Structures.h @@ -38,6 +38,12 @@ typedef signed short int Bit16s; typedef unsigned char Bit8u; typedef signed char Bit8s; +#if MT32EMU_USE_FLOAT_SAMPLES +typedef float Sample; +#else +typedef Bit16s Sample; +#endif + // The following structures represent the MT-32's memory // Since sysex allows this memory to be written to in blocks of bytes, // we keep this packed so that we can copy data into the various diff --git a/audio/softsynth/mt32/Synth.cpp b/audio/softsynth/mt32/Synth.cpp index 1e1be06bc9..b76dc58b5f 100644 --- a/audio/softsynth/mt32/Synth.cpp +++ b/audio/softsynth/mt32/Synth.cpp @@ -26,15 +26,7 @@ #include "mt32emu.h" #include "mmath.h" #include "PartialManager.h" - -#if MT32EMU_USE_REVERBMODEL == 1 -#include "AReverbModel.h" -#elif MT32EMU_USE_REVERBMODEL == 2 #include "BReverbModel.h" -#else -#include "FreeverbModel.h" -#endif -#include "DelayReverb.h" namespace MT32Emu { @@ -50,84 +42,22 @@ static const ControlROMMap ControlROMMaps[7] = { // (Note that all but CM-32L ROM actually have 86 entries for rhythmTemp) }; -static inline Bit16s *streamOffset(Bit16s *stream, Bit32u pos) { - return stream == NULL ? NULL : stream + pos; -} +static inline void muteStream(Sample *stream, Bit32u len) { + if (stream == NULL) return; -static inline void clearIfNonNull(Bit16s *stream, Bit32u len) { - if (stream != NULL) { - memset(stream, 0, len * sizeof(Bit16s)); - } -} - -static inline void mix(float *target, const float *stream, Bit32u len) { - while (len--) { - *target += *stream; - stream++; - target++; - } -} - -static inline void clearFloats(float *leftBuf, float *rightBuf, Bit32u len) { +#if MT32EMU_USE_FLOAT_SAMPLES // FIXME: Use memset() where compatibility is guaranteed (if this turns out to be a win) while (len--) { - *leftBuf++ = 0.0f; - *rightBuf++ = 0.0f; - } -} - -static inline Bit16s clipBit16s(Bit32s a) { - // Clamp values above 32767 to 32767, and values below -32768 to -32768 - if ((a + 32768) & ~65535) { - return (a >> 31) ^ 32767; - } - return a; -} - -static void floatToBit16s_nice(Bit16s *target, const float *source, Bit32u len, float outputGain) { - float gain = outputGain * 16384.0f; - while (len--) { - // Since we're not shooting for accuracy here, don't worry about the rounding mode. - *target = clipBit16s((Bit32s)(*source * gain)); - source++; - target++; - } -} - -static void floatToBit16s_pure(Bit16s *target, const float *source, Bit32u len, float /*outputGain*/) { - while (len--) { - *target = clipBit16s((Bit32s)floor(*source * 8192.0f)); - source++; - target++; - } -} - -static void floatToBit16s_reverb(Bit16s *target, const float *source, Bit32u len, float outputGain) { - float gain = outputGain * 8192.0f; - while (len--) { - *target = clipBit16s((Bit32s)floor(*source * gain)); - source++; - target++; - } -} - -static void floatToBit16s_generation1(Bit16s *target, const float *source, Bit32u len, float outputGain) { - float gain = outputGain * 8192.0f; - while (len--) { - *target = clipBit16s((Bit32s)floor(*source * gain)); - *target = (*target & 0x8000) | ((*target << 1) & 0x7FFE); - source++; - target++; + *stream++ = 0.0f; } +#else + memset(stream, 0, len * sizeof(Sample)); +#endif } -static void floatToBit16s_generation2(Bit16s *target, const float *source, Bit32u len, float outputGain) { - float gain = outputGain * 8192.0f; - while (len--) { - *target = clipBit16s((Bit32s)floor(*source * gain)); - *target = (*target & 0x8000) | ((*target << 1) & 0x7FFE) | ((*target >> 14) & 0x0001); - source++; - target++; +static inline void advanceStreamPosition(Sample *&stream, Bit32u posDelta) { + if (stream != NULL) { + stream += posDelta; } } @@ -155,28 +85,19 @@ Synth::Synth(ReportHandler *useReportHandler) { isDefaultReportHandler = false; } -#if MT32EMU_USE_REVERBMODEL == 1 - reverbModels[REVERB_MODE_ROOM] = new AReverbModel(REVERB_MODE_ROOM); - reverbModels[REVERB_MODE_HALL] = new AReverbModel(REVERB_MODE_HALL); - reverbModels[REVERB_MODE_PLATE] = new AReverbModel(REVERB_MODE_PLATE); - reverbModels[REVERB_MODE_TAP_DELAY] = new DelayReverb(); -#elif MT32EMU_USE_REVERBMODEL == 2 reverbModels[REVERB_MODE_ROOM] = new BReverbModel(REVERB_MODE_ROOM); reverbModels[REVERB_MODE_HALL] = new BReverbModel(REVERB_MODE_HALL); reverbModels[REVERB_MODE_PLATE] = new BReverbModel(REVERB_MODE_PLATE); reverbModels[REVERB_MODE_TAP_DELAY] = new BReverbModel(REVERB_MODE_TAP_DELAY); -#else - reverbModels[REVERB_MODE_ROOM] = new FreeverbModel(0.76f, 0.687770909f, 0.63f, 0, 0.5f); - reverbModels[REVERB_MODE_HALL] = new FreeverbModel(2.0f, 0.712025098f, 0.86f, 1, 0.5f); - reverbModels[REVERB_MODE_PLATE] = new FreeverbModel(0.4f, 0.939522749f, 0.38f, 2, 0.05f); - reverbModels[REVERB_MODE_TAP_DELAY] = new DelayReverb(); -#endif reverbModel = NULL; setDACInputMode(DACInputMode_NICE); + setMIDIDelayMode(MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY); setOutputGain(1.0f); - setReverbOutputGain(0.68f); + setReverbOutputGain(1.0f); partialManager = NULL; + midiQueue = NULL; + lastReceivedMIDIEventTimestamp = 0; memset(parts, 0, sizeof(parts)); renderedSampleCount = 0; } @@ -197,8 +118,8 @@ void ReportHandler::showLCDMessage(const char *data) { } void ReportHandler::printDebug(const char *fmt, va_list list) { - vprintf(fmt, list); - printf("\n"); + vprintf(fmt, list); + printf("\n"); } void Synth::polyStateChanged(int partNum) { @@ -236,35 +157,37 @@ bool Synth::isReverbOverridden() const { } void Synth::setDACInputMode(DACInputMode mode) { - switch(mode) { - case DACInputMode_GENERATION1: - la32FloatToBit16sFunc = floatToBit16s_generation1; - reverbFloatToBit16sFunc = floatToBit16s_reverb; - break; - case DACInputMode_GENERATION2: - la32FloatToBit16sFunc = floatToBit16s_generation2; - reverbFloatToBit16sFunc = floatToBit16s_reverb; - break; - case DACInputMode_PURE: - la32FloatToBit16sFunc = floatToBit16s_pure; - reverbFloatToBit16sFunc = floatToBit16s_pure; - break; - case DACInputMode_NICE: - default: - la32FloatToBit16sFunc = floatToBit16s_nice; - reverbFloatToBit16sFunc = floatToBit16s_reverb; - break; - } + dacInputMode = mode; +} + +DACInputMode Synth::getDACInputMode() const { + return dacInputMode; +} + +void Synth::setMIDIDelayMode(MIDIDelayMode mode) { + midiDelayMode = mode; +} + +MIDIDelayMode Synth::getMIDIDelayMode() const { + return midiDelayMode; } void Synth::setOutputGain(float newOutputGain) { outputGain = newOutputGain; } +float Synth::getOutputGain() const { + return outputGain; +} + void Synth::setReverbOutputGain(float newReverbOutputGain) { reverbOutputGain = newReverbOutputGain; } +float Synth::getReverbOutputGain() const { + return reverbOutputGain; +} + bool Synth::loadControlROM(const ROMImage &controlROMImage) { if (&controlROMImage == NULL) return false; Common::File *file = controlROMImage.getFile(); @@ -343,9 +266,9 @@ bool Synth::loadPCMROM(const ROMImage &pcmROMImage) { bool Synth::initPCMList(Bit16u mapAddress, Bit16u count) { ControlROMPCMStruct *tps = (ControlROMPCMStruct *)&controlROMData[mapAddress]; for (int i = 0; i < count; i++) { - size_t rAddr = tps[i].pos * 0x800; - size_t rLenExp = (tps[i].len & 0x70) >> 4; - size_t rLen = 0x800 << rLenExp; + Bit32u rAddr = tps[i].pos * 0x800; + Bit32u rLenExp = (tps[i].len & 0x70) >> 4; + Bit32u rLen = 0x800 << rLenExp; if (rAddr + rLen > pcmROMSize) { printDebug("Control ROM error: Wave map entry %d points to invalid PCM address 0x%04X, length 0x%04X", i, rAddr, rLen); return false; @@ -407,17 +330,18 @@ bool Synth::initTimbres(Bit16u mapAddress, Bit16u offset, int count, int startTi return true; } -bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage) { +bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount) { if (isOpen) { return false; } - prerenderReadIx = prerenderWriteIx = 0; + partialCount = usePartialCount; + abortingPoly = NULL; #if MT32EMU_MONITOR_INIT printDebug("Initialising Constant Tables"); #endif #if !MT32EMU_REDUCE_REVERB_MEMORY - for (int i = 0; i < 4; i++) { - reverbModels[i]->open(useProp.sampleRate); + for (int i = REVERB_MODE_ROOM; i <= REVERB_MODE_TAP_DELAY; i++) { + reverbModels[i]->open(); } #endif @@ -554,6 +478,8 @@ bool Synth::open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage) { // For resetting mt32 mid-execution mt32default = mt32ram; + midiQueue = new MidiEventQueue(); + isOpen = true; isEnabled = false; @@ -568,6 +494,9 @@ void Synth::close() { return; } + delete midiQueue; + midiQueue = NULL; + delete partialManager; partialManager = NULL; @@ -588,12 +517,78 @@ void Synth::close() { isOpen = false; } -void Synth::playMsg(Bit32u msg) { +void Synth::flushMIDIQueue() { + if (midiQueue != NULL) { + for (;;) { + const MidiEvent *midiEvent = midiQueue->peekMidiEvent(); + if (midiEvent == NULL) break; + if (midiEvent->sysexData == NULL) { + playMsgNow(midiEvent->shortMessageData); + } else { + playSysexNow(midiEvent->sysexData, midiEvent->sysexLength); + } + midiQueue->dropMidiEvent(); + } + lastReceivedMIDIEventTimestamp = renderedSampleCount; + } +} + +void Synth::setMIDIEventQueueSize(Bit32u useSize) { + if (midiQueue != NULL) { + flushMIDIQueue(); + delete midiQueue; + midiQueue = new MidiEventQueue(useSize); + } +} + +Bit32u Synth::getShortMessageLength(Bit32u msg) { + if ((msg & 0xF0) == 0xF0) return 1; + // NOTE: This calculation isn't quite correct + // as it doesn't consider the running status byte + return ((msg & 0xE0) == 0xC0) ? 2 : 3; +} + +Bit32u Synth::addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp) { + Bit32u transferTime = Bit32u((double)len * MIDI_DATA_TRANSFER_RATE); + // Dealing with wrapping + if (Bit32s(timestamp - lastReceivedMIDIEventTimestamp) < 0) { + timestamp = lastReceivedMIDIEventTimestamp; + } + timestamp += transferTime; + lastReceivedMIDIEventTimestamp = timestamp; + return timestamp; +} + +bool Synth::playMsg(Bit32u msg) { + return playMsg(msg, renderedSampleCount); +} + +bool Synth::playMsg(Bit32u msg, Bit32u timestamp) { + if (midiQueue == NULL) return false; + if (midiDelayMode != MIDIDelayMode_IMMEDIATE) { + timestamp = addMIDIInterfaceDelay(getShortMessageLength(msg), timestamp); + } + return midiQueue->pushShortMessage(msg, timestamp); +} + +bool Synth::playSysex(const Bit8u *sysex, Bit32u len) { + return playSysex(sysex, len, renderedSampleCount); +} + +bool Synth::playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp) { + if (midiQueue == NULL) return false; + if (midiDelayMode == MIDIDelayMode_DELAY_ALL) { + timestamp = addMIDIInterfaceDelay(len, timestamp); + } + return midiQueue->pushSysex(sysex, len, timestamp); +} + +void Synth::playMsgNow(Bit32u msg) { // FIXME: Implement active sensing unsigned char code = (unsigned char)((msg & 0x0000F0) >> 4); unsigned char chan = (unsigned char)(msg & 0x00000F); - unsigned char note = (unsigned char)((msg & 0x00FF00) >> 8); - unsigned char velocity = (unsigned char)((msg & 0xFF0000) >> 16); + unsigned char note = (unsigned char)((msg & 0x007F00) >> 8); + unsigned char velocity = (unsigned char)((msg & 0x7F0000) >> 16); isEnabled = true; //printDebug("Playing chan %d, code 0x%01x note: 0x%02x", chan, code, note); @@ -606,11 +601,6 @@ void Synth::playMsg(Bit32u msg) { return; } playMsgOnPart(part, code, note, velocity); - - // This ensures minimum 1-sample delay between sequential MIDI events - // Without this, a sequence of NoteOn and immediately succeeding NoteOff messages is always silent - // Technically, it's also impossible to send events through the MIDI interface faster than about each millisecond - prerender(); } void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity) { @@ -692,7 +682,7 @@ void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char #if MT32EMU_MONITOR_MIDI > 0 printDebug("Unknown MIDI Control code: 0x%02x - vel 0x%02x", note, velocity); #endif - break; + return; } break; @@ -709,13 +699,12 @@ void Synth::playMsgOnPart(unsigned char part, unsigned char code, unsigned char #if MT32EMU_MONITOR_MIDI > 0 printDebug("Unknown Midi code: 0x%01x - %02x - %02x", code, note, velocity); #endif - break; + return; } - - //midiOutShortMsg(m_out, msg); + reportHandler->onMIDIMessagePlayed(); } -void Synth::playSysex(const Bit8u *sysex, Bit32u len) { +void Synth::playSysexNow(const Bit8u *sysex, Bit32u len) { if (len < 2) { printDebug("playSysex: Message is too short for sysex (%d bytes)", len); } @@ -810,6 +799,7 @@ void Synth::readSysex(unsigned char /*device*/, const Bit8u * /*sysex*/, Bit32u } void Synth::writeSysex(unsigned char device, const Bit8u *sysex, Bit32u len) { + reportHandler->onMIDIMessagePlayed(); Bit32u addr = (sysex[0] << 16) | (sysex[1] << 8) | (sysex[2]); addr = MT32EMU_MEMADDR(addr); sysex += 3; @@ -1232,7 +1222,7 @@ void Synth::refreshSystemReverbParameters() { reportHandler->onNewReverbTime(mt32ram.system.reverbTime); reportHandler->onNewReverbLevel(mt32ram.system.reverbLevel); - ReverbModel *newReverbModel = reverbModels[mt32ram.system.reverbMode]; + BReverbModel *newReverbModel = reverbModels[mt32ram.system.reverbMode]; #if MT32EMU_REDUCE_REVERB_MEMORY if (reverbModel != newReverbModel) { if (reverbModel != NULL) { @@ -1308,179 +1298,226 @@ void Synth::reset() { isEnabled = false; } -void Synth::render(Bit16s *stream, Bit32u len) { - if (!isEnabled) { - memset(stream, 0, len * sizeof(Bit16s) * 2); - return; +MidiEvent::~MidiEvent() { + if (sysexData != NULL) { + delete[] sysexData; } - while (len > 0) { - Bit32u thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; - renderStreams(tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisLen); - for (Bit32u i = 0; i < thisLen; i++) { - stream[0] = clipBit16s((Bit32s)tmpNonReverbLeft[i] + (Bit32s)tmpReverbDryLeft[i] + (Bit32s)tmpReverbWetLeft[i]); - stream[1] = clipBit16s((Bit32s)tmpNonReverbRight[i] + (Bit32s)tmpReverbDryRight[i] + (Bit32s)tmpReverbWetRight[i]); - stream += 2; - } - len -= thisLen; +} + +void MidiEvent::setShortMessage(Bit32u useShortMessageData, Bit32u useTimestamp) { + if (sysexData != NULL) { + delete[] sysexData; } + shortMessageData = useShortMessageData; + timestamp = useTimestamp; + sysexData = NULL; + sysexLength = 0; } -bool Synth::prerender() { - int newPrerenderWriteIx = (prerenderWriteIx + 1) % MAX_PRERENDER_SAMPLES; - if (newPrerenderWriteIx == prerenderReadIx) { - // The prerender buffer is full - return false; +void MidiEvent::setSysex(const Bit8u *useSysexData, Bit32u useSysexLength, Bit32u useTimestamp) { + if (sysexData != NULL) { + delete[] sysexData; } - doRenderStreams( - prerenderNonReverbLeft + prerenderWriteIx, - prerenderNonReverbRight + prerenderWriteIx, - prerenderReverbDryLeft + prerenderWriteIx, - prerenderReverbDryRight + prerenderWriteIx, - prerenderReverbWetLeft + prerenderWriteIx, - prerenderReverbWetRight + prerenderWriteIx, - 1); - prerenderWriteIx = newPrerenderWriteIx; + shortMessageData = 0; + timestamp = useTimestamp; + sysexLength = useSysexLength; + Bit8u *dstSysexData = new Bit8u[sysexLength]; + sysexData = dstSysexData; + memcpy(dstSysexData, useSysexData, sysexLength); +} + +MidiEventQueue::MidiEventQueue(Bit32u useRingBufferSize) : ringBufferSize(useRingBufferSize) { + ringBuffer = new MidiEvent[ringBufferSize]; + memset(ringBuffer, 0, ringBufferSize * sizeof(MidiEvent)); + reset(); +} + +MidiEventQueue::~MidiEventQueue() { + delete[] ringBuffer; +} + +void MidiEventQueue::reset() { + startPosition = 0; + endPosition = 0; +} + +bool MidiEventQueue::pushShortMessage(Bit32u shortMessageData, Bit32u timestamp) { + unsigned int newEndPosition = (endPosition + 1) % ringBufferSize; + // Is ring buffer full? + if (startPosition == newEndPosition) return false; + ringBuffer[endPosition].setShortMessage(shortMessageData, timestamp); + endPosition = newEndPosition; return true; } -static inline void maybeCopy(Bit16s *out, Bit32u outPos, Bit16s *in, Bit32u inPos, Bit32u len) { - if (out == NULL) { - return; - } - memcpy(out + outPos, in + inPos, len * sizeof(Bit16s)); +bool MidiEventQueue::pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp) { + unsigned int newEndPosition = (endPosition + 1) % ringBufferSize; + // Is ring buffer full? + if (startPosition == newEndPosition) return false; + ringBuffer[endPosition].setSysex(sysexData, sysexLength, timestamp); + endPosition = newEndPosition; + return true; } -void Synth::copyPrerender(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u pos, Bit32u len) { - maybeCopy(nonReverbLeft, pos, prerenderNonReverbLeft, prerenderReadIx, len); - maybeCopy(nonReverbRight, pos, prerenderNonReverbRight, prerenderReadIx, len); - maybeCopy(reverbDryLeft, pos, prerenderReverbDryLeft, prerenderReadIx, len); - maybeCopy(reverbDryRight, pos, prerenderReverbDryRight, prerenderReadIx, len); - maybeCopy(reverbWetLeft, pos, prerenderReverbWetLeft, prerenderReadIx, len); - maybeCopy(reverbWetRight, pos, prerenderReverbWetRight, prerenderReadIx, len); +const MidiEvent *MidiEventQueue::peekMidiEvent() { + return (startPosition == endPosition) ? NULL : &ringBuffer[startPosition]; } -void Synth::checkPrerender(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u &pos, Bit32u &len) { - if (prerenderReadIx > prerenderWriteIx) { - // There's data in the prerender buffer, and the write index has wrapped. - Bit32u prerenderCopyLen = MAX_PRERENDER_SAMPLES - prerenderReadIx; - if (prerenderCopyLen > len) { - prerenderCopyLen = len; - } - copyPrerender(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, pos, prerenderCopyLen); - len -= prerenderCopyLen; - pos += prerenderCopyLen; - prerenderReadIx = (prerenderReadIx + prerenderCopyLen) % MAX_PRERENDER_SAMPLES; - } - if (prerenderReadIx < prerenderWriteIx) { - // There's data in the prerender buffer, and the write index is ahead of the read index. - Bit32u prerenderCopyLen = prerenderWriteIx - prerenderReadIx; - if (prerenderCopyLen > len) { - prerenderCopyLen = len; - } - copyPrerender(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, pos, prerenderCopyLen); - len -= prerenderCopyLen; - pos += prerenderCopyLen; - prerenderReadIx += prerenderCopyLen; - } - if (prerenderReadIx == prerenderWriteIx) { - // If the ring buffer's empty, reset it to start at 0 to minimise wrapping, - // which requires two writes instead of one. - prerenderReadIx = prerenderWriteIx = 0; - } -} - -void Synth::renderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len) { - if (!isEnabled) { - clearIfNonNull(nonReverbLeft, len); - clearIfNonNull(nonReverbRight, len); - clearIfNonNull(reverbDryLeft, len); - clearIfNonNull(reverbDryRight, len); - clearIfNonNull(reverbWetLeft, len); - clearIfNonNull(reverbWetRight, len); - return; +void MidiEventQueue::dropMidiEvent() { + // Is ring buffer empty? + if (startPosition != endPosition) { + startPosition = (startPosition + 1) % ringBufferSize; } - Bit32u pos = 0; +} - // First, check for data in the prerender buffer and spit that out before generating anything new. - // Note that the prerender buffer is rarely used - see comments elsewhere for details. - checkPrerender(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, pos, len); +void Synth::render(Sample *stream, Bit32u len) { + Sample tmpNonReverbLeft[MAX_SAMPLES_PER_RUN]; + Sample tmpNonReverbRight[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbDryLeft[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbDryRight[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbWetLeft[MAX_SAMPLES_PER_RUN]; + Sample tmpReverbWetRight[MAX_SAMPLES_PER_RUN]; while (len > 0) { Bit32u thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; - doRenderStreams( - streamOffset(nonReverbLeft, pos), - streamOffset(nonReverbRight, pos), - streamOffset(reverbDryLeft, pos), - streamOffset(reverbDryRight, pos), - streamOffset(reverbWetLeft, pos), - streamOffset(reverbWetRight, pos), - thisLen); + renderStreams(tmpNonReverbLeft, tmpNonReverbRight, tmpReverbDryLeft, tmpReverbDryRight, tmpReverbWetLeft, tmpReverbWetRight, thisLen); + for (Bit32u i = 0; i < thisLen; i++) { +#if MT32EMU_USE_FLOAT_SAMPLES + *(stream++) = tmpNonReverbLeft[i] + tmpReverbDryLeft[i] + tmpReverbWetLeft[i]; + *(stream++) = tmpNonReverbRight[i] + tmpReverbDryRight[i] + tmpReverbWetRight[i]; +#else + *(stream++) = clipBit16s((Bit32s)tmpNonReverbLeft[i] + (Bit32s)tmpReverbDryLeft[i] + (Bit32s)tmpReverbWetLeft[i]); + *(stream++) = clipBit16s((Bit32s)tmpNonReverbRight[i] + (Bit32s)tmpReverbDryRight[i] + (Bit32s)tmpReverbWetRight[i]); +#endif + } len -= thisLen; - pos += thisLen; } } -// FIXME: Using more temporary buffers than we need to -void Synth::doRenderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len) { - clearFloats(&tmpBufMixLeft[0], &tmpBufMixRight[0], len); - if (!reverbEnabled) { - for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { - if (partialManager->produceOutput(i, &tmpBufPartialLeft[0], &tmpBufPartialRight[0], len)) { - mix(&tmpBufMixLeft[0], &tmpBufPartialLeft[0], len); - mix(&tmpBufMixRight[0], &tmpBufPartialRight[0], len); - } - } - if (nonReverbLeft != NULL) { - la32FloatToBit16sFunc(nonReverbLeft, &tmpBufMixLeft[0], len, outputGain); - } - if (nonReverbRight != NULL) { - la32FloatToBit16sFunc(nonReverbRight, &tmpBufMixRight[0], len, outputGain); - } - clearIfNonNull(reverbDryLeft, len); - clearIfNonNull(reverbDryRight, len); - clearIfNonNull(reverbWetLeft, len); - clearIfNonNull(reverbWetRight, len); - } else { - for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { - if (!partialManager->shouldReverb(i)) { - if (partialManager->produceOutput(i, &tmpBufPartialLeft[0], &tmpBufPartialRight[0], len)) { - mix(&tmpBufMixLeft[0], &tmpBufPartialLeft[0], len); - mix(&tmpBufMixRight[0], &tmpBufPartialRight[0], len); +void Synth::renderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len) { + while (len > 0) { + // We need to ensure zero-duration notes will play so add minimum 1-sample delay. + Bit32u thisLen = 1; + if (!isAbortingPoly()) { + const MidiEvent *nextEvent = midiQueue->peekMidiEvent(); + Bit32s samplesToNextEvent = (nextEvent != NULL) ? Bit32s(nextEvent->timestamp - renderedSampleCount) : MAX_SAMPLES_PER_RUN; + if (samplesToNextEvent > 0) { + thisLen = len > MAX_SAMPLES_PER_RUN ? MAX_SAMPLES_PER_RUN : len; + if (thisLen > (Bit32u)samplesToNextEvent) { + thisLen = samplesToNextEvent; + } + } else { + if (nextEvent->sysexData == NULL) { + playMsgNow(nextEvent->shortMessageData); + // If a poly is aborting we don't drop the event from the queue. + // Instead, we'll return to it again when the abortion is done. + if (!isAbortingPoly()) { + midiQueue->dropMidiEvent(); + } + } else { + playSysexNow(nextEvent->sysexData, nextEvent->sysexLength); + midiQueue->dropMidiEvent(); } } } - if (nonReverbLeft != NULL) { - la32FloatToBit16sFunc(nonReverbLeft, &tmpBufMixLeft[0], len, outputGain); + doRenderStreams(nonReverbLeft, nonReverbRight, reverbDryLeft, reverbDryRight, reverbWetLeft, reverbWetRight, thisLen); + advanceStreamPosition(nonReverbLeft, thisLen); + advanceStreamPosition(nonReverbRight, thisLen); + advanceStreamPosition(reverbDryLeft, thisLen); + advanceStreamPosition(reverbDryRight, thisLen); + advanceStreamPosition(reverbWetLeft, thisLen); + advanceStreamPosition(reverbWetRight, thisLen); + len -= thisLen; + } +} + +void Synth::convertSamplesToOutput(Sample *target, const Sample *source, Bit32u len, bool reverb) { + if (target == NULL) return; + + if (dacInputMode == DACInputMode_PURE) { + memcpy(target, source, len * sizeof(Sample)); + return; + } + +#if MT32EMU_USE_FLOAT_SAMPLES + float gain = reverb ? reverbOutputGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR : 2.0f * outputGain; + while (len--) { + *(target++) = *(source++) * gain; + } +#else + float gain = reverb ? reverbOutputGain * CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR : outputGain; + if (!reverb) { + switch (dacInputMode) { + case DACInputMode_NICE: + // Since we're not shooting for accuracy here, don't worry about the rounding mode. + gain *= 2.0f; + break; + case DACInputMode_GENERATION1: + while (len--) { + *target = clipBit16s(Bit32s(*source * gain)); + *target = (*target & 0x8000) | ((*target << 1) & 0x7FFE); + source++; + target++; + } + return; + case DACInputMode_GENERATION2: + while (len--) { + *target = clipBit16s(Bit32s(*source * gain)); + *target = (*target & 0x8000) | ((*target << 1) & 0x7FFE) | ((*target >> 14) & 0x0001); + source++; + target++; + } + return; + default: + break; } - if (nonReverbRight != NULL) { - la32FloatToBit16sFunc(nonReverbRight, &tmpBufMixRight[0], len, outputGain); + } + while (len--) { + *(target++) = clipBit16s(Bit32s(*(source++) * gain)); + } +#endif +} + +void Synth::doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len) { + if (isEnabled) { + Sample tmpBufMixLeft[MAX_SAMPLES_PER_RUN], tmpBufMixRight[MAX_SAMPLES_PER_RUN]; + muteStream(tmpBufMixLeft, len); + muteStream(tmpBufMixRight, len); + for (unsigned int i = 0; i < getPartialCount(); i++) { + if (!reverbEnabled || !partialManager->shouldReverb(i)) { + partialManager->produceOutput(i, tmpBufMixLeft, tmpBufMixRight, len); + } } + convertSamplesToOutput(nonReverbLeft, tmpBufMixLeft, len, false); + convertSamplesToOutput(nonReverbRight, tmpBufMixRight, len, false); + } else { + muteStream(nonReverbLeft, len); + muteStream(nonReverbRight, len); + } - clearFloats(&tmpBufMixLeft[0], &tmpBufMixRight[0], len); - for (unsigned int i = 0; i < MT32EMU_MAX_PARTIALS; i++) { + if (isEnabled && reverbEnabled) { + Sample tmpBufMixLeft[MAX_SAMPLES_PER_RUN], tmpBufMixRight[MAX_SAMPLES_PER_RUN]; + muteStream(tmpBufMixLeft, len); + muteStream(tmpBufMixRight, len); + for (unsigned int i = 0; i < getPartialCount(); i++) { if (partialManager->shouldReverb(i)) { - if (partialManager->produceOutput(i, &tmpBufPartialLeft[0], &tmpBufPartialRight[0], len)) { - mix(&tmpBufMixLeft[0], &tmpBufPartialLeft[0], len); - mix(&tmpBufMixRight[0], &tmpBufPartialRight[0], len); - } + partialManager->produceOutput(i, tmpBufMixLeft, tmpBufMixRight, len); } } - if (reverbDryLeft != NULL) { - la32FloatToBit16sFunc(reverbDryLeft, &tmpBufMixLeft[0], len, outputGain); - } - if (reverbDryRight != NULL) { - la32FloatToBit16sFunc(reverbDryRight, &tmpBufMixRight[0], len, outputGain); - } + convertSamplesToOutput(reverbDryLeft, tmpBufMixLeft, len, false); + convertSamplesToOutput(reverbDryRight, tmpBufMixRight, len, false); - // FIXME: Note that on the real devices, reverb input and output are signed linear 16-bit (well, kinda, there's some fudging) PCM, not float. - reverbModel->process(&tmpBufMixLeft[0], &tmpBufMixRight[0], &tmpBufReverbOutLeft[0], &tmpBufReverbOutRight[0], len); - if (reverbWetLeft != NULL) { - reverbFloatToBit16sFunc(reverbWetLeft, &tmpBufReverbOutLeft[0], len, reverbOutputGain); - } - if (reverbWetRight != NULL) { - reverbFloatToBit16sFunc(reverbWetRight, &tmpBufReverbOutRight[0], len, reverbOutputGain); - } + Sample tmpBufReverbOutLeft[MAX_SAMPLES_PER_RUN], tmpBufReverbOutRight[MAX_SAMPLES_PER_RUN]; + reverbModel->process(tmpBufMixLeft, tmpBufMixRight, tmpBufReverbOutLeft, tmpBufReverbOutRight, len); + convertSamplesToOutput(reverbWetLeft, tmpBufReverbOutLeft, len, true); + convertSamplesToOutput(reverbWetRight, tmpBufReverbOutRight, len, true); + } else { + muteStream(reverbDryLeft, len); + muteStream(reverbDryRight, len); + muteStream(reverbWetLeft, len); + muteStream(reverbWetRight, len); } + partialManager->clearAlreadyOutputed(); renderedSampleCount += len; } @@ -1489,19 +1526,14 @@ void Synth::printPartialUsage(unsigned long sampleOffset) { unsigned int partialUsage[9]; partialManager->getPerPartPartialUsage(partialUsage); if (sampleOffset > 0) { - printDebug("[+%lu] Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", sampleOffset, partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], MT32EMU_MAX_PARTIALS - partialManager->getFreePartialCount()); + printDebug("[+%lu] Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", sampleOffset, partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); } else { - printDebug("Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], MT32EMU_MAX_PARTIALS - partialManager->getFreePartialCount()); + printDebug("Partial Usage: 1:%02d 2:%02d 3:%02d 4:%02d 5:%02d 6:%02d 7:%02d 8:%02d R: %02d TOTAL: %02d", partialUsage[0], partialUsage[1], partialUsage[2], partialUsage[3], partialUsage[4], partialUsage[5], partialUsage[6], partialUsage[7], partialUsage[8], getPartialCount() - partialManager->getFreePartialCount()); } } bool Synth::hasActivePartials() const { - if (prerenderReadIx != prerenderWriteIx) { - // Data in the prerender buffer means that the current isActive() states are "in the future". - // It also means that partials are definitely active at this render point. - return true; - } - for (int partialNum = 0; partialNum < MT32EMU_MAX_PARTIALS; partialNum++) { + for (unsigned int partialNum = 0; partialNum < getPartialCount(); partialNum++) { if (partialManager->getPartial(partialNum)->isActive()) { return true; } @@ -1509,6 +1541,10 @@ bool Synth::hasActivePartials() const { return false; } +bool Synth::isAbortingPoly() const { + return abortingPoly != NULL; +} + bool Synth::isActive() const { if (hasActivePartials()) { return true; @@ -1523,6 +1559,10 @@ const Partial *Synth::getPartial(unsigned int partialNum) const { return partialManager->getPartial(partialNum); } +unsigned int Synth::getPartialCount() const { + return partialCount; +} + const Part *Synth::getPart(unsigned int partNum) const { if (partNum > 8) { return NULL; diff --git a/audio/softsynth/mt32/Synth.h b/audio/softsynth/mt32/Synth.h index b85e7ae507..783d6e2747 100644 --- a/audio/softsynth/mt32/Synth.h +++ b/audio/softsynth/mt32/Synth.h @@ -27,6 +27,7 @@ class Partial; class PartialManager; class Part; class ROMImage; +class BReverbModel; /** * Methods for emulating the connection between the LA32 and the DAC, which involves @@ -44,6 +45,7 @@ enum DACInputMode { // * Much less likely to overdrive than any other mode. // * Half the volume of any of the other modes, meaning its volume relative to the reverb // output when mixed together directly will sound wrong. + // * Output gain is ignored for both LA32 and reverb output. // * Perfect for developers while debugging :) DACInputMode_PURE, @@ -58,7 +60,17 @@ enum DACInputMode { DACInputMode_GENERATION2 }; -typedef void (*FloatToBit16sFunc)(Bit16s *target, const float *source, Bit32u len, float outputGain); +enum MIDIDelayMode { + // Process incoming MIDI events immediately. + MIDIDelayMode_IMMEDIATE, + + // Delay incoming short MIDI messages as if they where transferred via a MIDI cable to a real hardware unit and immediate sysex processing. + // This ensures more accurate timing of simultaneous NoteOn messages. + MIDIDelayMode_DELAY_SHORT_MESSAGES_ONLY, + + // Delay all incoming MIDI events as if they where transferred via a MIDI cable to a real hardware unit. + MIDIDelayMode_DELAY_ALL +}; const Bit8u SYSEX_MANUFACTURER_ROLAND = 0x41; @@ -217,18 +229,6 @@ public: ResetMemoryRegion(Synth *useSynth) : MemoryRegion(useSynth, NULL, NULL, MR_Reset, MT32EMU_MEMADDR(0x7F0000), 0x3FFF, 1) {} }; -class ReverbModel { -public: - virtual ~ReverbModel() {} - // After construction or a close(), open() will be called at least once before any other call (with the exception of close()). - virtual void open() = 0; - // May be called multiple times without an open() in between. - virtual void close() = 0; - virtual void setParameters(Bit8u time, Bit8u level) = 0; - virtual void process(const float *inLeft, const float *inRight, float *outLeft, float *outRight, unsigned long numSamples) = 0; - virtual bool isActive() const = 0; -}; - class ReportHandler { friend class Synth; @@ -244,22 +244,63 @@ protected: virtual void onErrorControlROM() {} virtual void onErrorPCMROM() {} virtual void showLCDMessage(const char *message); + virtual void onMIDIMessagePlayed() {} virtual void onDeviceReset() {} virtual void onDeviceReconfig() {} virtual void onNewReverbMode(Bit8u /* mode */) {} virtual void onNewReverbTime(Bit8u /* time */) {} virtual void onNewReverbLevel(Bit8u /* level */) {} - virtual void onPartStateChanged(int /* partNum */, bool /* hasActiveNonReleasingPolys */) {} virtual void onPolyStateChanged(int /* partNum */) {} - virtual void onPartialStateChanged(int /* partialNum */, int /* oldPartialPhase */, int /* newPartialPhase */) {} virtual void onProgramChanged(int /* partNum */, int /* bankNum */, const char * /* patchName */) {} }; +/** + * Used to safely store timestamped MIDI events in a local queue. + */ +struct MidiEvent { + Bit32u shortMessageData; + const Bit8u *sysexData; + Bit32u sysexLength; + Bit32u timestamp; + + ~MidiEvent(); + void setShortMessage(Bit32u shortMessageData, Bit32u timestamp); + void setSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp); +}; + +/** + * Simple queue implementation using a ring buffer to store incoming MIDI event before the synth actually processes it. + * It is intended to: + * - get rid of prerenderer while retaining graceful partial abortion + * - add fair emulation of the MIDI interface delays + * - extend the synth interface with the default implementation of a typical rendering loop. + * THREAD SAFETY: + * It is safe to use either in a single thread environment or when there are only two threads - one performs only reading + * and one performs only writing. More complicated usage requires external synchronisation. + */ +class MidiEventQueue { +private: + MidiEvent *ringBuffer; + Bit32u ringBufferSize; + volatile Bit32u startPosition; + volatile Bit32u endPosition; + +public: + MidiEventQueue(Bit32u ringBufferSize = DEFAULT_MIDI_EVENT_QUEUE_SIZE); + ~MidiEventQueue(); + void reset(); + bool pushShortMessage(Bit32u shortMessageData, Bit32u timestamp); + bool pushSysex(const Bit8u *sysexData, Bit32u sysexLength, Bit32u timestamp); + const MidiEvent *peekMidiEvent(); + void dropMidiEvent(); +}; + class Synth { friend class Part; friend class RhythmPart; friend class Poly; friend class Partial; +friend class PartialManager; friend class Tables; friend class MemoryRegion; friend class TVA; @@ -286,20 +327,22 @@ private: Bit16s *pcmROMData; size_t pcmROMSize; // This is in 16-bit samples, therefore half the number of bytes in the ROM - Bit8s chantable[32]; - - Bit32u renderedSampleCount; + unsigned int partialCount; + Bit8s chantable[32]; // FIXME: Need explanation why 32 is set, obviously it should be 16 + MidiEventQueue *midiQueue; + volatile Bit32u lastReceivedMIDIEventTimestamp; + volatile Bit32u renderedSampleCount; MemParams mt32ram, mt32default; - ReverbModel *reverbModels[4]; - ReverbModel *reverbModel; + BReverbModel *reverbModels[4]; + BReverbModel *reverbModel; bool reverbEnabled; bool reverbOverridden; - FloatToBit16sFunc la32FloatToBit16sFunc; - FloatToBit16sFunc reverbFloatToBit16sFunc; + MIDIDelayMode midiDelayMode; + DACInputMode dacInputMode; float outputGain; float reverbOutputGain; @@ -311,41 +354,18 @@ private: PartialManager *partialManager; Part *parts[9]; - // FIXME: We can reorganise things so that we don't need all these separate tmpBuf, tmp and prerender buffers. - // This should be rationalised when things have stabilised a bit (if prerender buffers don't die in the mean time). - - float tmpBufPartialLeft[MAX_SAMPLES_PER_RUN]; - float tmpBufPartialRight[MAX_SAMPLES_PER_RUN]; - float tmpBufMixLeft[MAX_SAMPLES_PER_RUN]; - float tmpBufMixRight[MAX_SAMPLES_PER_RUN]; - float tmpBufReverbOutLeft[MAX_SAMPLES_PER_RUN]; - float tmpBufReverbOutRight[MAX_SAMPLES_PER_RUN]; - - Bit16s tmpNonReverbLeft[MAX_SAMPLES_PER_RUN]; - Bit16s tmpNonReverbRight[MAX_SAMPLES_PER_RUN]; - Bit16s tmpReverbDryLeft[MAX_SAMPLES_PER_RUN]; - Bit16s tmpReverbDryRight[MAX_SAMPLES_PER_RUN]; - Bit16s tmpReverbWetLeft[MAX_SAMPLES_PER_RUN]; - Bit16s tmpReverbWetRight[MAX_SAMPLES_PER_RUN]; - - // These ring buffers are only used to simulate delays present on the real device. - // In particular, when a partial needs to be aborted to free it up for use by a new Poly, + // When a partial needs to be aborted to free it up for use by a new Poly, // the controller will busy-loop waiting for the sound to finish. - Bit16s prerenderNonReverbLeft[MAX_PRERENDER_SAMPLES]; - Bit16s prerenderNonReverbRight[MAX_PRERENDER_SAMPLES]; - Bit16s prerenderReverbDryLeft[MAX_PRERENDER_SAMPLES]; - Bit16s prerenderReverbDryRight[MAX_PRERENDER_SAMPLES]; - Bit16s prerenderReverbWetLeft[MAX_PRERENDER_SAMPLES]; - Bit16s prerenderReverbWetRight[MAX_PRERENDER_SAMPLES]; - int prerenderReadIx; - int prerenderWriteIx; - - bool prerender(); - void copyPrerender(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u pos, Bit32u len); - void checkPrerender(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u &pos, Bit32u &len); - void doRenderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len); - - void playAddressedSysex(unsigned char channel, const Bit8u *sysex, Bit32u len); + // We emulate this by delaying new MIDI events processing until abortion finishes. + Poly *abortingPoly; + + Bit32u getShortMessageLength(Bit32u msg); + Bit32u addMIDIInterfaceDelay(Bit32u len, Bit32u timestamp); + + void convertSamplesToOutput(Sample *target, const Sample *source, Bit32u len, bool reverb); + bool isAbortingPoly() const; + void doRenderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len); + void readSysex(unsigned char channel, const Bit8u *sysex, Bit32u len) const; void initMemoryRegions(); void deleteMemoryRegions(); @@ -375,6 +395,14 @@ private: void printDebug(const char *fmt, ...); public: + static inline Bit16s clipBit16s(Bit32s sample) { + // Clamp values above 32767 to 32767, and values below -32768 to -32768 + if ((sample + 32768) & ~65535) { + return (sample >> 31) ^ 32767; + } + return (Bit16s)sample; + } + static Bit8u calcSysexChecksum(const Bit8u *data, Bit32u len, Bit8u checksum); // Optionally sets callbacks for reporting various errors, information and debug messages @@ -384,18 +412,44 @@ public: // Used to initialise the MT-32. Must be called before any other function. // Returns true if initialization was sucessful, otherwise returns false. // controlROMImage and pcmROMImage represent Control and PCM ROM images for use by synth. - bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage); + // usePartialCount sets the maximum number of partials playing simultaneously for this session. + bool open(const ROMImage &controlROMImage, const ROMImage &pcmROMImage, unsigned int usePartialCount = DEFAULT_MAX_PARTIALS); // Closes the MT-32 and deallocates any memory used by the synthesizer void close(void); - // Sends a 4-byte MIDI message to the MT-32 for immediate playback - void playMsg(Bit32u msg); + // All the enqueued events are processed by the synth immediately. + void flushMIDIQueue(); + + // Sets size of the internal MIDI event queue. + // The queue is flushed before reallocation. + void setMIDIEventQueueSize(Bit32u); + + // Enqueues a MIDI event for subsequent playback. + // The minimum delay involves the delay introduced while the event is transferred via MIDI interface + // and emulation of the MCU busy-loop while it frees partials for use by a new Poly. + // Calls from multiple threads must be synchronised, although, + // no synchronisation is required with the rendering thread. + + // The MIDI event will be processed not before the specified timestamp. + // The timestamp is measured as the global rendered sample count since the synth was created. + bool playMsg(Bit32u msg, Bit32u timestamp); + bool playSysex(const Bit8u *sysex, Bit32u len, Bit32u timestamp); + // The MIDI event will be processed ASAP. + bool playMsg(Bit32u msg); + bool playSysex(const Bit8u *sysex, Bit32u len); + + // WARNING: + // The methods below don't ensure minimum 1-sample delay between sequential MIDI events, + // and a sequence of NoteOn and immediately succeeding NoteOff messages is always silent. + + // Sends a 4-byte MIDI message to the MT-32 for immediate playback. + void playMsgNow(Bit32u msg); void playMsgOnPart(unsigned char part, unsigned char code, unsigned char note, unsigned char velocity); // Sends a string of Sysex commands to the MT-32 for immediate interpretation // The length is in bytes - void playSysex(const Bit8u *sysex, Bit32u len); + void playSysexNow(const Bit8u *sysex, Bit32u len); void playSysexWithoutFraming(const Bit8u *sysex, Bit32u len); void playSysexWithoutHeader(unsigned char device, unsigned char command, const Bit8u *sysex, Bit32u len); void writeSysex(unsigned char channel, const Bit8u *sysex, Bit32u len); @@ -405,20 +459,31 @@ public: void setReverbOverridden(bool reverbOverridden); bool isReverbOverridden() const; void setDACInputMode(DACInputMode mode); + DACInputMode getDACInputMode() const; + void setMIDIDelayMode(MIDIDelayMode mode); + MIDIDelayMode getMIDIDelayMode() const; // Sets output gain factor. Applied to all output samples and unrelated with the synth's Master volume. + // Ignored in DACInputMode_PURE void setOutputGain(float); + float getOutputGain() const; // Sets output gain factor for the reverb wet output. setOutputGain() doesn't change reverb output gain. + // Note: We're currently emulate CM-32L/CM-64 reverb quite accurately and the reverb output level closely + // corresponds to the level of digital capture. Although, according to the CM-64 PCB schematic, + // there is a difference in the reverb analogue circuit, and the resulting output gain is 0.68 + // of that for LA32 analogue output. This factor is applied to the reverb output gain. + // Ignored in DACInputMode_PURE void setReverbOutputGain(float); + float getReverbOutputGain() const; // Renders samples to the specified output stream. // The length is in frames, not bytes (in 16-bit stereo, // one frame is 4 bytes). - void render(Bit16s *stream, Bit32u len); + void render(Sample *stream, Bit32u len); // Renders samples to the specified output streams (any or all of which may be NULL). - void renderStreams(Bit16s *nonReverbLeft, Bit16s *nonReverbRight, Bit16s *reverbDryLeft, Bit16s *reverbDryRight, Bit16s *reverbWetLeft, Bit16s *reverbWetRight, Bit32u len); + void renderStreams(Sample *nonReverbLeft, Sample *nonReverbRight, Sample *reverbDryLeft, Sample *reverbDryRight, Sample *reverbWetLeft, Sample *reverbWetRight, Bit32u len); // Returns true when there is at least one active partial, otherwise false. bool hasActivePartials() const; @@ -428,6 +493,9 @@ public: const Partial *getPartial(unsigned int partialNum) const; + // Returns the maximum number of partials playing simultaneously. + unsigned int getPartialCount() const; + void readMemory(Bit32u addr, Bit32u len, Bit8u *data); // partNum should be 0..7 for Part 1..8, or 8 for Rhythm diff --git a/audio/softsynth/mt32/TVP.cpp b/audio/softsynth/mt32/TVP.cpp index c3e64c18d0..8f68245753 100644 --- a/audio/softsynth/mt32/TVP.cpp +++ b/audio/softsynth/mt32/TVP.cpp @@ -181,7 +181,7 @@ void TVP::updatePitch() { pitch = (Bit16u)newPitch; // FIXME: We're doing this here because that's what the CM-32L does - we should probably move this somewhere more appropriate in future. - partial->tva->recalcSustain(); + partial->getTVA()->recalcSustain(); } void TVP::targetPitchOffsetReached() { diff --git a/audio/softsynth/mt32/Tables.h b/audio/softsynth/mt32/Tables.h index 8b4580df0e..bfb80e121e 100644 --- a/audio/softsynth/mt32/Tables.h +++ b/audio/softsynth/mt32/Tables.h @@ -25,6 +25,11 @@ namespace MT32Emu { // The output from the synth is supposed to be resampled to convert the sample rate. const unsigned int SAMPLE_RATE = 32000; +// MIDI interface data transfer rate in samples. Used to simulate the transfer delay. +const double MIDI_DATA_TRANSFER_RATE = (double)SAMPLE_RATE / 31250.0 * 8.0; + +const float CM32L_REVERB_TO_LA32_ANALOG_OUTPUT_GAIN_FACTOR = 0.68f; + const int MIDDLEC = 60; class Synth; diff --git a/audio/softsynth/mt32/freeverb.cpp b/audio/softsynth/mt32/freeverb.cpp deleted file mode 100644 index 181b878596..0000000000 --- a/audio/softsynth/mt32/freeverb.cpp +++ /dev/null @@ -1,324 +0,0 @@ -// Allpass filter implementation -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -#include "freeverb.h" - -allpass::allpass() -{ - bufidx = 0; -} - -void allpass::setbuffer(float *buf, int size) -{ - buffer = buf; - bufsize = size; -} - -void allpass::mute() -{ - for (int i=0; i<bufsize; i++) - buffer[i]=0; -} - -void allpass::setfeedback(float val) -{ - feedback = val; -} - -float allpass::getfeedback() -{ - return feedback; -} - -void allpass::deletebuffer() -{ - delete[] buffer; - buffer = 0; -} -// Comb filter implementation -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -comb::comb() -{ - filterstore = 0; - bufidx = 0; -} - -void comb::setbuffer(float *buf, int size) -{ - buffer = buf; - bufsize = size; -} - -void comb::mute() -{ - for (int i=0; i<bufsize; i++) - buffer[i]=0; -} - -void comb::setdamp(float val) -{ - damp1 = val; - damp2 = 1-val; -} - -float comb::getdamp() -{ - return damp1; -} - -void comb::setfeedback(float val) -{ - feedback = val; -} - -float comb::getfeedback() -{ - return feedback; -} - -void comb::deletebuffer() -{ - delete[] buffer; - buffer = 0; -} -// Reverb model implementation -// -// Written by Jezar at Dreampoint, June 2000 -// Modifications by Jerome Fisher, 2009, 2011 -// http://www.dreampoint.co.uk -// This code is public domain - -revmodel::revmodel(float scaletuning) -{ - int i; - int bufsize; - - // Allocate buffers for the components - for (i = 0; i < numcombs; i++) { - bufsize = int(scaletuning * combtuning[i]); - combL[i].setbuffer(new float[bufsize], bufsize); - bufsize += int(scaletuning * stereospread); - combR[i].setbuffer(new float[bufsize], bufsize); - } - for (i = 0; i < numallpasses; i++) { - bufsize = int(scaletuning * allpasstuning[i]); - allpassL[i].setbuffer(new float[bufsize], bufsize); - allpassL[i].setfeedback(0.5f); - bufsize += int(scaletuning * stereospread); - allpassR[i].setbuffer(new float[bufsize], bufsize); - allpassR[i].setfeedback(0.5f); - } - - // Set default values - dry = initialdry; - wet = initialwet*scalewet; - damp = initialdamp*scaledamp; - roomsize = (initialroom*scaleroom) + offsetroom; - width = initialwidth; - mode = initialmode; - update(); - - // Buffer will be full of rubbish - so we MUST mute them - mute(); -} - -revmodel::~revmodel() -{ - int i; - - for (i = 0; i < numcombs; i++) { - combL[i].deletebuffer(); - combR[i].deletebuffer(); - } - for (i = 0; i < numallpasses; i++) { - allpassL[i].deletebuffer(); - allpassR[i].deletebuffer(); - } -} - -void revmodel::mute() -{ - int i; - - if (getmode() >= freezemode) - return; - - for (i=0;i<numcombs;i++) - { - combL[i].mute(); - combR[i].mute(); - } - for (i=0;i<numallpasses;i++) - { - allpassL[i].mute(); - allpassR[i].mute(); - } - - // Init LPF history - filtprev1 = 0; - filtprev2 = 0; -} - -void revmodel::process(const float *inputL, const float *inputR, float *outputL, float *outputR, long numsamples) -{ - float outL,outR,input; - - while (numsamples-- > 0) - { - int i; - - outL = outR = 0; - input = (*inputL + *inputR) * gain; - - // Implementation of 2-stage IIR single-pole low-pass filter - // found at the entrance of reverb processing on real devices - filtprev1 += (input - filtprev1) * filtval; - filtprev2 += (filtprev1 - filtprev2) * filtval; - input = filtprev2; - - int s = -1; - // Accumulate comb filters in parallel - for (i=0; i<numcombs; i++) - { - outL += s * combL[i].process(input); - outR += s * combR[i].process(input); - s = -s; - } - - // Feed through allpasses in series - for (i=0; i<numallpasses; i++) - { - outL = allpassL[i].process(outL); - outR = allpassR[i].process(outR); - } - - // Calculate output REPLACING anything already there - *outputL = outL*wet1 + outR*wet2; - *outputR = outR*wet1 + outL*wet2; - - inputL++; - inputR++; - outputL++; - outputR++; - } -} - -void revmodel::update() -{ -// Recalculate internal values after parameter change - - int i; - - wet1 = wet*(width/2 + 0.5f); - wet2 = wet*((1-width)/2); - - if (mode >= freezemode) - { - roomsize1 = 1; - damp1 = 0; - gain = muted; - } - else - { - roomsize1 = roomsize; - damp1 = damp; - gain = fixedgain; - } - - for (i=0; i<numcombs; i++) - { - combL[i].setfeedback(roomsize1); - combR[i].setfeedback(roomsize1); - } - - for (i=0; i<numcombs; i++) - { - combL[i].setdamp(damp1); - combR[i].setdamp(damp1); - } -} - -// The following get/set functions are not inlined, because -// speed is never an issue when calling them, and also -// because as you develop the reverb model, you may -// wish to take dynamic action when they are called. - -void revmodel::setroomsize(float value) -{ - roomsize = (value*scaleroom) + offsetroom; - update(); -} - -float revmodel::getroomsize() -{ - return (roomsize-offsetroom)/scaleroom; -} - -void revmodel::setdamp(float value) -{ - damp = value*scaledamp; - update(); -} - -float revmodel::getdamp() -{ - return damp/scaledamp; -} - -void revmodel::setwet(float value) -{ - wet = value*scalewet; - update(); -} - -float revmodel::getwet() -{ - return wet/scalewet; -} - -void revmodel::setdry(float value) -{ - dry = value*scaledry; -} - -float revmodel::getdry() -{ - return dry/scaledry; -} - -void revmodel::setwidth(float value) -{ - width = value; - update(); -} - -float revmodel::getwidth() -{ - return width; -} - -void revmodel::setmode(float value) -{ - mode = value; - update(); -} - -float revmodel::getmode() -{ - if (mode >= freezemode) - return 1; - else - return 0; -} - -void revmodel::setfiltval(float value) -{ - filtval = value; -} diff --git a/audio/softsynth/mt32/freeverb.h b/audio/softsynth/mt32/freeverb.h deleted file mode 100644 index ae4d48169e..0000000000 --- a/audio/softsynth/mt32/freeverb.h +++ /dev/null @@ -1,189 +0,0 @@ -#ifndef _freeverb_ -#define _freeverb_ - -// Reverb model tuning values -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -const int numcombs = 8; -const int numallpasses = 4; -const float muted = 0; -const float fixedgain = 0.015f; -const float scalewet = 3; -const float scaledry = 2; -const float scaledamp = 0.4f; -const float scaleroom = 0.28f; -const float offsetroom = 0.7f; -const float initialroom = 0.5f; -const float initialdamp = 0.5f; -const float initialwet = 1/scalewet; -const float initialdry = 0; -const float initialwidth = 1; -const float initialmode = 0; -const float freezemode = 0.5f; -const int stereospread = 23; - -const int combtuning[] = {1116, 1188, 1277, 1356, 1422, 1491, 1557, 1617}; -const int allpasstuning[] = {556, 441, 341, 225}; - -// Macro for killing denormalled numbers -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// Based on IS_DENORMAL macro by Jon Watte -// This code is public domain - -static inline float undenormalise(float x) { - union { - float f; - unsigned int i; - } u; - u.f = x; - if ((u.i & 0x7f800000) == 0) { - return 0.0f; - } - return x; -} - -// Allpass filter declaration -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -class allpass -{ -public: - allpass(); - void setbuffer(float *buf, int size); - void deletebuffer(); - inline float process(float inp); - void mute(); - void setfeedback(float val); - float getfeedback(); -// private: - float feedback; - float *buffer; - int bufsize; - int bufidx; -}; - - -// Big to inline - but crucial for speed - -inline float allpass::process(float input) -{ - float output; - float bufout; - - bufout = undenormalise(buffer[bufidx]); - - output = -input + bufout; - buffer[bufidx] = input + (bufout*feedback); - - if (++bufidx>=bufsize) bufidx = 0; - - return output; -} - -// Comb filter class declaration -// -// Written by Jezar at Dreampoint, June 2000 -// http://www.dreampoint.co.uk -// This code is public domain - -class comb -{ -public: - comb(); - void setbuffer(float *buf, int size); - void deletebuffer(); - inline float process(float inp); - void mute(); - void setdamp(float val); - float getdamp(); - void setfeedback(float val); - float getfeedback(); -private: - float feedback; - float filterstore; - float damp1; - float damp2; - float *buffer; - int bufsize; - int bufidx; -}; - - -// Big to inline - but crucial for speed - -inline float comb::process(float input) -{ - float output; - - output = undenormalise(buffer[bufidx]); - - filterstore = undenormalise((output*damp2) + (filterstore*damp1)); - - buffer[bufidx] = input + (filterstore*feedback); - - if (++bufidx>=bufsize) bufidx = 0; - - return output; -} - -// Reverb model declaration -// -// Written by Jezar at Dreampoint, June 2000 -// Modifications by Jerome Fisher, 2009 -// http://www.dreampoint.co.uk -// This code is public domain - -class revmodel -{ -public: - revmodel(float scaletuning); - ~revmodel(); - void mute(); - void process(const float *inputL, const float *inputR, float *outputL, float *outputR, long numsamples); - void setroomsize(float value); - float getroomsize(); - void setdamp(float value); - float getdamp(); - void setwet(float value); - float getwet(); - void setdry(float value); - float getdry(); - void setwidth(float value); - float getwidth(); - void setmode(float value); - float getmode(); - void setfiltval(float value); -private: - void update(); -private: - float gain; - float roomsize,roomsize1; - float damp,damp1; - float wet,wet1,wet2; - float dry; - float width; - float mode; - - // LPF stuff - float filtval; - float filtprev1; - float filtprev2; - - // Comb filters - comb combL[numcombs]; - comb combR[numcombs]; - - // Allpass filters - allpass allpassL[numallpasses]; - allpass allpassR[numallpasses]; -}; - -#endif//_freeverb_ diff --git a/audio/softsynth/mt32/module.mk b/audio/softsynth/mt32/module.mk index e7afdfd2b4..1c8aa125ab 100644 --- a/audio/softsynth/mt32/module.mk +++ b/audio/softsynth/mt32/module.mk @@ -1,24 +1,19 @@ MODULE := audio/softsynth/mt32 MODULE_OBJS := \ - AReverbModel.o \ BReverbModel.o \ - DelayReverb.o \ - FreeverbModel.o \ LA32Ramp.o \ LA32WaveGenerator.o \ - LegacyWaveGenerator.o \ Part.o \ Partial.o \ PartialManager.o \ Poly.o \ ROMInfo.o \ Synth.o \ + Tables.o \ TVA.o \ TVF.o \ - TVP.o \ - Tables.o \ - freeverb.o + TVP.o # Include common rules include $(srcdir)/rules.mk diff --git a/audio/softsynth/mt32/mt32emu.h b/audio/softsynth/mt32/mt32emu.h index 971a0886d5..ab963886ac 100644 --- a/audio/softsynth/mt32/mt32emu.h +++ b/audio/softsynth/mt32/mt32emu.h @@ -60,27 +60,24 @@ #define MT32EMU_MONITOR_TVF 0 // Configuration -// The maximum number of partials playing simultaneously -#define MT32EMU_MAX_PARTIALS 32 -// The maximum number of notes playing simultaneously per part. -// No point making it more than MT32EMU_MAX_PARTIALS, since each note needs at least one partial. -#define MT32EMU_MAX_POLY 32 // If non-zero, deletes reverb buffers that are not in use to save memory. // If zero, keeps reverb buffers for all modes around all the time to avoid allocating/freeing in the critical path. #define MT32EMU_REDUCE_REVERB_MEMORY 1 -// 0: Use legacy Freeverb -// 1: Use Accurate Reverb model aka AReverb -// 2: Use Bit-perfect Boss Reverb model aka BReverb (for developers, not much practical use) -#define MT32EMU_USE_REVERBMODEL 1 +// 0: Maximum speed at the cost of a bit lower emulation accuracy. +// 1: Maximum achievable emulation accuracy. +#define MT32EMU_BOSS_REVERB_PRECISE_MODE 0 -// 0: Use refined wave generator based on logarithmic fixed-point computations and LUTs -// 1: Use legacy accurate wave generator based on float computations -#define MT32EMU_ACCURATE_WG 0 +// 0: Use 16-bit signed samples and refined wave generator based on logarithmic fixed-point computations and LUTs. Maximum emulation accuracy and speed. +// 1: Use float samples in the wave generator and renderer. Maximum output quality and minimum noise. +#define MT32EMU_USE_FLOAT_SAMPLES 0 namespace MT32Emu { +// The default value for the maximum number of partials playing simultaneously. +const unsigned int DEFAULT_MAX_PARTIALS = 32; + // The higher this number, the more memory will be used, but the more samples can be processed in one run - // various parts of sample generation can be processed more efficiently in a single run. // A run's maximum length is that given to Synth::render(), so giving a value here higher than render() is ever @@ -90,11 +87,14 @@ namespace MT32Emu // This value must be >= 1. const unsigned int MAX_SAMPLES_PER_RUN = 4096; -// This determines the amount of memory available for simulating delays. -// If set too low, partials aborted to allow other partials to play will not end gracefully, but will terminate -// abruptly and potentially cause a pop/crackle in the audio output. -// This value must be >= 1. -const unsigned int MAX_PRERENDER_SAMPLES = 1024; +// The default size of the internal MIDI event queue. +// It holds the incoming MIDI events before the rendering engine actually processes them. +// The main goal is to fairly emulate the real hardware behaviour which obviously +// uses an internal MIDI event queue to gather incoming data as well as the delays +// introduced by transferring data via the MIDI interface. +// This also facilitates building of an external rendering loop +// as the queue stores timestamped MIDI events. +const unsigned int DEFAULT_MIDI_EVENT_QUEUE_SIZE = 1024; } #include "Structures.h" @@ -103,7 +103,6 @@ const unsigned int MAX_PRERENDER_SAMPLES = 1024; #include "Poly.h" #include "LA32Ramp.h" #include "LA32WaveGenerator.h" -#include "LegacyWaveGenerator.h" #include "TVA.h" #include "TVP.h" #include "TVF.h" diff --git a/backends/platform/tizen/application.cpp b/backends/platform/tizen/application.cpp index 8236ebef67..a73efacf58 100644 --- a/backends/platform/tizen/application.cpp +++ b/backends/platform/tizen/application.cpp @@ -31,7 +31,7 @@ Application *TizenScummVM::createInstance() { return new TizenScummVM(); } -TizenScummVM::TizenScummVM() : _appForm(0) { +TizenScummVM::TizenScummVM() : _appForm(NULL) { logEntered(); } @@ -41,7 +41,7 @@ TizenScummVM::~TizenScummVM() { TizenSystem *system = (TizenSystem *)g_system; system->destroyBackend(); delete system; - g_system = 0; + g_system = NULL; } } @@ -68,17 +68,19 @@ bool TizenScummVM::OnAppTerminating(AppRegistry &appRegistry, bool forcedTermina } void TizenScummVM::OnUserEventReceivedN(RequestId requestId, IList *args) { + logEntered(); MessageBox messageBox; int modalResult; + String *message; - logEntered(); - - if (requestId == USER_MESSAGE_EXIT) { + switch (requestId) { + case USER_MESSAGE_EXIT: // normal program termination Terminate(); - } else if (requestId == USER_MESSAGE_EXIT_ERR) { + break; + + case USER_MESSAGE_EXIT_ERR: // assertion failure termination - String *message = NULL; if (args) { message = (String *)args->GetAt(0); } @@ -88,12 +90,15 @@ void TizenScummVM::OnUserEventReceivedN(RequestId requestId, IList *args) { messageBox.Construct(L"Oops...", *message, MSGBOX_STYLE_OK); messageBox.ShowAndWait(modalResult); Terminate(); - } else if (requestId == USER_MESSAGE_EXIT_ERR_CONFIG) { + break; + + case USER_MESSAGE_EXIT_ERR_CONFIG: // the config file was corrupted messageBox.Construct(L"Config file corrupted", L"Settings have been reverted, please restart.", MSGBOX_STYLE_OK); messageBox.ShowAndWait(modalResult); Terminate(); + break; } } @@ -132,7 +137,6 @@ void TizenScummVM::pauseGame(bool pause) { if (pause && g_engine && !g_engine->isPaused()) { _appForm->pushKey(Common::KEYCODE_SPACE); } - if (g_system) { ((TizenSystem *)g_system)->setMute(pause); } diff --git a/backends/platform/tizen/audio.cpp b/backends/platform/tizen/audio.cpp index 313a10eaa8..f9ac80a583 100644 --- a/backends/platform/tizen/audio.cpp +++ b/backends/platform/tizen/audio.cpp @@ -26,8 +26,9 @@ #include "backends/platform/tizen/audio.h" #include "backends/platform/tizen/system.h" -#define TIMER_INTERVAL 10 -#define VOLUME 99 +#define TIMER_INTERVAL 10 +#define VOLUME 96 +#define MIN_TIMER_INTERVAL 5 AudioThread::AudioThread() : _mixer(0), @@ -38,6 +39,7 @@ AudioThread::AudioThread() : _ready(0), _interval(TIMER_INTERVAL), _playing(-1), + _size(0), _muted(true) { } @@ -70,7 +72,7 @@ void AudioThread::setMute(bool on) { if (on) { _timer->Cancel(); } else { - _timer->StartAsRepeatable(_interval); + _timer->Start(_interval); } } } @@ -105,13 +107,14 @@ bool AudioThread::OnStart(void) { } } + _size = _audioBuffer[0].GetCapacity(); _timer = new Timer(); if (!_timer || IsFailed(_timer->Construct(*this))) { AppLog("Failed to create audio timer"); return false; } - if (IsFailed(_timer->StartAsRepeatable(_interval))) { + if (IsFailed(_timer->Start(_interval))) { AppLog("failed to start audio timer"); return false; } @@ -137,6 +140,7 @@ void AudioThread::OnStop(void) { if (_audioOut) { _audioOut->Reset(); + _audioOut->Unprepare(); delete _audioOut; } } @@ -161,21 +165,33 @@ void AudioThread::OnAudioOutBufferEndReached(Tizen::Media::AudioOut &src) { _tail = (_tail + 1) % NUM_AUDIO_BUFFERS; _ready--; } else { - // audio buffer empty: decrease timer inverval + // audio buffer empty: decrease timer interval _playing = -1; + _interval -= 1; + if (_interval < MIN_TIMER_INTERVAL) { + _interval = MIN_TIMER_INTERVAL; + } } + } void AudioThread::OnTimerExpired(Timer &timer) { if (_ready < NUM_AUDIO_BUFFERS) { - uint len = _audioBuffer[_head].GetCapacity(); - int samples = _mixer->mixCallback((byte *)_audioBuffer[_head].GetPointer(), len); - if (samples) { - _head = (_head + 1) % NUM_AUDIO_BUFFERS; - _ready++; + if (_playing != _head) { + if (_mixer->mixCallback((byte *)_audioBuffer[_head].GetPointer(), _size)) { + _head = (_head + 1) % NUM_AUDIO_BUFFERS; + _ready++; + } } + } else { + // audio buffer full: restore timer interval + _interval = TIMER_INTERVAL; } + if (_ready && _playing == -1) { OnAudioOutBufferEndReached(*_audioOut); } + + _timer->Start(_interval); } + diff --git a/backends/platform/tizen/audio.h b/backends/platform/tizen/audio.h index 8d7835042d..a304231578 100644 --- a/backends/platform/tizen/audio.h +++ b/backends/platform/tizen/audio.h @@ -54,6 +54,7 @@ public: bool isSilentMode(); void setMute(bool on); +private: bool OnStart(void); void OnStop(void); void OnAudioOutErrorOccurred(Tizen::Media::AudioOut &src, result r); @@ -62,12 +63,11 @@ public: void OnAudioOutBufferEndReached(Tizen::Media::AudioOut &src); void OnTimerExpired(Timer &timer); -private: Audio::MixerImpl *_mixer; Tizen::Base::Runtime::Timer *_timer; Tizen::Media::AudioOut *_audioOut; Tizen::Base::ByteBuffer _audioBuffer[NUM_AUDIO_BUFFERS]; - int _head, _tail, _ready, _interval, _playing; + int _head, _tail, _ready, _interval, _playing, _size; bool _muted; }; diff --git a/backends/platform/tizen/form.cpp b/backends/platform/tizen/form.cpp index 5050699ca9..10d51cc610 100644 --- a/backends/platform/tizen/form.cpp +++ b/backends/platform/tizen/form.cpp @@ -52,7 +52,7 @@ TizenAppForm::TizenAppForm() : _eventQueueLock(NULL), _state(kInitState), _buttonState(kLeftButton), - _shortcut(kShowKeypad) { + _shortcut(kEscapeKey) { } result TizenAppForm::Construct() { @@ -157,6 +157,8 @@ result TizenAppForm::OnInitializing(void) { AddOrientationEventListener(*this); AddTouchEventListener(*this); SetMultipointTouchEnabled(true); + SetFormBackEventListener(this); + SetFormMenuEventListener(this); // set focus to enable receiving key events SetEnabled(true); @@ -316,16 +318,16 @@ void TizenAppForm::invokeShortcut() { case kControlMouse: setButtonShortcut(); break; - + case kEscapeKey: pushKey(Common::KEYCODE_ESCAPE); break; - + case kGameMenu: _buttonState = kLeftButton; pushKey(Common::KEYCODE_F5); break; - + case kShowKeypad: showKeypad(); break; @@ -354,8 +356,6 @@ void TizenAppForm::OnTouchDoublePressed(const Control &source, if (_buttonState != kMoveOnly) { pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, currentPosition); - pushEvent(_buttonState == kLeftButton ? Common::EVENT_LBUTTONDOWN : Common::EVENT_RBUTTONDOWN, - currentPosition); } } @@ -417,3 +417,16 @@ void TizenAppForm::OnTouchReleased(const Control &source, } } +void TizenAppForm::OnFormBackRequested(Form &source) { + logEntered(); + if (_state == kActiveState) { + invokeShortcut(); + } +} + +void TizenAppForm::OnFormMenuRequested(Form &source) { + logEntered(); + if (_state == kActiveState) { + setShortcut(); + } +} diff --git a/backends/platform/tizen/form.h b/backends/platform/tizen/form.h index 64c447d409..e419c14d24 100644 --- a/backends/platform/tizen/form.h +++ b/backends/platform/tizen/form.h @@ -29,6 +29,8 @@ #include <FBase.h> #include <FUiITouchEventListener.h> #include <FUiITextEventListener.h> +#include <FUiCtrlIFormBackEventListener.h> +#include <FUiCtrlIFormMenuEventListener.h> #include "config.h" #include "common/scummsys.h" @@ -40,6 +42,7 @@ using namespace Tizen::Ui; using namespace Tizen::Graphics; using namespace Tizen::Base::Runtime; +using namespace Tizen::Ui::Controls; // // TizenAppForm @@ -48,7 +51,9 @@ class TizenAppForm : public Controls::Form, public IRunnable, public IOrientationEventListener, - public ITouchEventListener { + public ITouchEventListener, + public IFormBackEventListener, + public IFormMenuEventListener { public: TizenAppForm(); @@ -89,6 +94,8 @@ private: void OnTouchReleased(const Control &source, const Point ¤tPosition, const TouchEventInfo &touchInfo); + void OnFormBackRequested(Form &source); + void OnFormMenuRequested(Form &source); void pushEvent(Common::EventType type, const Point ¤tPosition); void terminate(); diff --git a/backends/platform/tizen/fs.cpp b/backends/platform/tizen/fs.cpp index f8b32f4239..8145cd5638 100644 --- a/backends/platform/tizen/fs.cpp +++ b/backends/platform/tizen/fs.cpp @@ -339,7 +339,6 @@ bool TizenFilesystemNode::getChildren(AbstractFSList &myList, ListMode mode, boo if (_isVirtualDir && mode != Common::FSNode::kListFilesOnly && _path == "/") { // present well known TIZEN file system areas myList.push_back(new TizenFilesystemNode(kData)); - myList.push_back(new TizenFilesystemNode(kResource)); myList.push_back(new TizenFilesystemNode(kSdCard)); myList.push_back(new TizenFilesystemNode(kMedia)); myList.push_back(new TizenFilesystemNode(kShared)); diff --git a/backends/platform/tizen/graphics.cpp b/backends/platform/tizen/graphics.cpp index bf255cd264..2cafb9f781 100644 --- a/backends/platform/tizen/graphics.cpp +++ b/backends/platform/tizen/graphics.cpp @@ -100,6 +100,8 @@ void TizenGraphicsManager::setFeatureState(OSystem::Feature f, bool enable) { } void TizenGraphicsManager::setReady() { + logEntered(); + _appForm->GetVisualElement()->SetShowState(true); _initState = false; } @@ -176,7 +178,9 @@ bool TizenGraphicsManager::loadEgl() { systemError("eglMakeCurrent() failed"); return false; } - + if (!_initState) { + _appForm->GetVisualElement()->SetShowState(true); + } logLeaving(); return true; } @@ -213,6 +217,7 @@ void TizenGraphicsManager::internUpdateScreen() { void TizenGraphicsManager::unloadGFXMode() { logEntered(); + _appForm->GetVisualElement()->SetShowState(false); if (_eglDisplay != EGL_NO_DISPLAY) { eglMakeCurrent(_eglDisplay, NULL, NULL, NULL); diff --git a/backends/platform/tizen/sscanf.cpp b/backends/platform/tizen/sscanf.cpp index aa846698f6..75f009cc61 100644 --- a/backends/platform/tizen/sscanf.cpp +++ b/backends/platform/tizen/sscanf.cpp @@ -93,7 +93,7 @@ bool scanStringUntil(const char **in, va_list *ap, char c_end) { char *arg = va_arg(*ap, char*); while (**in && **in != c_end) { *arg = **in; - *arg++; + arg++; (*in)++; } *arg = 0; diff --git a/backends/platform/tizen/system.cpp b/backends/platform/tizen/system.cpp index 54d92146e5..3448dc1421 100644 --- a/backends/platform/tizen/system.cpp +++ b/backends/platform/tizen/system.cpp @@ -513,13 +513,15 @@ TizenAppForm *systemStart(Tizen::App::Application *app) { } if (E_SUCCESS != appForm->Construct() || - E_SUCCESS != appFrame->AddControl(*appForm)) { + E_SUCCESS != appFrame->AddControl(appForm)) { delete appForm; AppLog("Failed to construct appForm"); return NULL; } appFrame->SetCurrentForm(appForm); + appForm->GetVisualElement()->SetShowState(false); + logLeaving(); return appForm; } @@ -531,7 +533,7 @@ void systemError(const char *message) { AppLog("Fatal system error: %s", message); if (strspn(message, "Config file buggy:") > 0) { - Tizen::Io::File::Remove(DEFAULT_CONFIG_FILE); + Tizen::Io::File::Remove(App::GetInstance()->GetAppDataPath() + DEFAULT_CONFIG_FILE); Application::GetInstance()->SendUserEvent(USER_MESSAGE_EXIT_ERR_CONFIG, NULL); } else { ArrayList *args = new ArrayList(); diff --git a/backends/vkeybd/virtual-keyboard-gui.cpp b/backends/vkeybd/virtual-keyboard-gui.cpp index 8bf9a54251..ec4cbf1de2 100644 --- a/backends/vkeybd/virtual-keyboard-gui.cpp +++ b/backends/vkeybd/virtual-keyboard-gui.cpp @@ -32,11 +32,9 @@ namespace Common { -static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 x, int16 y, OverlayColor transparent) { - if (surf_dst->format.bytesPerPixel != sizeof(OverlayColor) || surf_src->format.bytesPerPixel != sizeof(OverlayColor)) - return; - - const OverlayColor *src = (const OverlayColor *)surf_src->getPixels(); +template<typename ColorType> +static void blitImplementation(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 x, int16 y, ColorType transparent) { + const ColorType *src = (const ColorType *)surf_src->getPixels(); int blitW = surf_src->w; int blitH = surf_src->h; @@ -58,13 +56,13 @@ static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 if (blitW <= 0 || blitH <= 0) return; - OverlayColor *dst = (OverlayColor *)surf_dst->getBasePtr(x, y); + ColorType *dst = (ColorType *)surf_dst->getBasePtr(x, y); int dstAdd = surf_dst->w - blitW; int srcAdd = surf_src->w - blitW; for (int i = 0; i < blitH; ++i) { for (int j = 0; j < blitW; ++j, ++dst, ++src) { - OverlayColor col = *src; + ColorType col = *src; if (col != transparent) *dst = col; } @@ -73,6 +71,16 @@ static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 } } +static void blit(Graphics::Surface *surf_dst, Graphics::Surface *surf_src, int16 x, int16 y, uint32 transparent) { + if (surf_dst->format.bytesPerPixel != surf_src->format.bytesPerPixel) + return; + + if (surf_dst->format.bytesPerPixel == 2) + blitImplementation<uint16>(surf_dst, surf_src, x, y, transparent); + else if (surf_dst->format.bytesPerPixel == 4) + blitImplementation<uint32>(surf_dst, surf_src, x, y, transparent); +} + VirtualKeyboardGUI::VirtualKeyboardGUI(VirtualKeyboard *kbd) : _kbd(kbd), _displaying(false), _drag(false), _drawCaret(false), _displayEnabled(false), _firstRun(true), @@ -111,7 +119,7 @@ void VirtualKeyboardGUI::initMode(VirtualKeyboard::Mode *mode) { } } -void VirtualKeyboardGUI::setupDisplayArea(Rect &r, OverlayColor forecolor) { +void VirtualKeyboardGUI::setupDisplayArea(Rect &r, uint32 forecolor) { _dispFont = FontMan.getFontByUsage(Graphics::FontManager::kBigGUIFont); if (!fontIsSuitable(_dispFont, r)) { @@ -356,13 +364,13 @@ void VirtualKeyboardGUI::redraw() { Graphics::Surface surf; surf.create(w, h, _system->getOverlayFormat()); - OverlayColor *dst = (OverlayColor *)surf.getPixels(); - const OverlayColor *src = (OverlayColor *) _overlayBackup.getBasePtr(_dirtyRect.left, _dirtyRect.top); + byte *dst = (byte *)surf.getPixels(); + const byte *src = (const byte *)_overlayBackup.getBasePtr(_dirtyRect.left, _dirtyRect.top); while (h--) { - memcpy(dst, src, surf.w * sizeof(OverlayColor)); - dst += surf.w; - src += _overlayBackup.w; + memcpy(dst, src, surf.pitch); + dst += surf.pitch; + src += _overlayBackup.pitch; } blit(&surf, _kbdSurface, _kbdBound.left - _dirtyRect.left, diff --git a/backends/vkeybd/virtual-keyboard-gui.h b/backends/vkeybd/virtual-keyboard-gui.h index d0f9c884ed..a2000adea0 100644 --- a/backends/vkeybd/virtual-keyboard-gui.h +++ b/backends/vkeybd/virtual-keyboard-gui.h @@ -99,7 +99,7 @@ private: VirtualKeyboard *_kbd; Rect _kbdBound; Graphics::Surface *_kbdSurface; - OverlayColor _kbdTransparentColor; + uint32 _kbdTransparentColor; Point _dragPoint; bool _drag; @@ -113,7 +113,7 @@ private: const Graphics::Font *_dispFont; int16 _dispX, _dispY; uint _dispI; - OverlayColor _dispForeColor, _dispBackColor; + uint32 _dispForeColor, _dispBackColor; int _lastScreenChanged; int16 _screenW, _screenH; @@ -121,7 +121,7 @@ private: bool _displaying; bool _firstRun; - void setupDisplayArea(Rect &r, OverlayColor forecolor); + void setupDisplayArea(Rect &r, uint32 forecolor); void move(int16 x, int16 y); void moveToDefaultPosition(); void screenChanged(); diff --git a/backends/vkeybd/virtual-keyboard.h b/backends/vkeybd/virtual-keyboard.h index 4ab5ad446d..3b2b2196bd 100644 --- a/backends/vkeybd/virtual-keyboard.h +++ b/backends/vkeybd/virtual-keyboard.h @@ -112,11 +112,11 @@ protected: String resolution; String bitmapName; Graphics::Surface *image; - OverlayColor transparentColor; + uint32 transparentColor; ImageMap imageMap; VKEventMap events; Rect displayArea; - OverlayColor displayFontColor; + uint32 displayFontColor; Mode() : image(0) {} ~Mode() { diff --git a/devtools/create_mortdat/create_mortdat.cpp b/devtools/create_mortdat/create_mortdat.cpp index f12a69bd37..5a491eea2f 100644 --- a/devtools/create_mortdat/create_mortdat.cpp +++ b/devtools/create_mortdat/create_mortdat.cpp @@ -204,16 +204,19 @@ void writeGameStrings() { /** * Write out the data for the English menu */ -void writeMenuBlock() { - // Write out a section header to the output file and the font data +void writeMenuData(const char *menuData, int languageId) { + // Write out a section header to the output file and the menu data const char menuHeader[4] = { 'M', 'E', 'N', 'U' }; outputFile.write(menuHeader, 4); // Section Id - outputFile.writeWord(strlen(menuDataEn) / 8); // Section size + int size = strlen(menuData) / 8 + 1; // Language code + Menu data size + outputFile.writeWord(size); + + outputFile.writeByte(languageId); // Write each 8-characters block as a byte (one bit per character) // ' ' -> 0, anything else -> 1 byte value; int valueCpt = 0; - const char* str = menuDataEn; + const char* str = menuData; while (*str != 0) { if (*(str++) != ' ') value |= (1 << (7 - valueCpt)); @@ -226,10 +229,34 @@ void writeMenuBlock() { } } +void writeMenuBlock() { + writeMenuData(menuDataEn, 1); + writeMenuData(menuDataDe, 2); +} + +void writeVerbNums(const int *verbs, int languageId) { + // Write out a section header to the output file + const char menuHeader[4] = { 'V', 'E', 'R', 'B' }; + outputFile.write(menuHeader, 4); // Section Id + int size = 52 + 1; // Language code + 26 words + outputFile.writeWord(size); + + outputFile.writeByte(languageId); + for (int i = 0; i < 26; i++) + outputFile.writeWord(verbs[i]); +} + +void writeMenuVerbs() { + writeVerbNums(verbsEn, 1); + writeVerbNums(verbsFr, 0); + writeVerbNums(verbsDe, 2); +} + void process() { writeFontBlock(); writeGameStrings(); writeEngineStrings(); + writeMenuVerbs(); writeMenuBlock(); } diff --git a/devtools/create_mortdat/create_mortdat.h b/devtools/create_mortdat/create_mortdat.h index 8c210d32d9..e5007ae653 100644 --- a/devtools/create_mortdat/create_mortdat.h +++ b/devtools/create_mortdat/create_mortdat.h @@ -24,7 +24,7 @@ */ #define VERSION_MAJOR 1 -#define VERSION_MINOR 0 +#define VERSION_MINOR 2 enum AccessMode { kFileReadMode = 1, diff --git a/devtools/create_mortdat/gametext.h b/devtools/create_mortdat/gametext.h index b1809c614c..4f7b1f9776 100644 --- a/devtools/create_mortdat/gametext.h +++ b/devtools/create_mortdat/gametext.h @@ -505,31 +505,31 @@ const char *gameDataEn[] = { "$", "YOUR MOVE$", " attach$", - " wait$", - " force$", - " sleep$", - " listen$", - " enter$", " close$", - " search$", - " knock$", - " scratch$", - " read$", " eat$", - " place$", - " open$", - " take$", + " enter$", + " force$", + " knock$", + " leave$", + " lift$", + " listen$", " look$", + " open$", + " place$", + " read$", + " scratch$", + " search$", + " sleep$", " smell$", " sound$", - " leave$", - " lift$", + " take$", " turn$", + " wait$", " hide yourself$", - " search$", - " read$", - " put$", " look$", + " put$", + " read$", + " search$", " Leo$", " Pat$", " Guy$", diff --git a/devtools/create_mortdat/menudata.h b/devtools/create_mortdat/menudata.h index aa4557b336..ec8724135c 100644 --- a/devtools/create_mortdat/menudata.h +++ b/devtools/create_mortdat/menudata.h @@ -76,4 +76,68 @@ const char *menuDataEn = "@@@ @@@ @@@ @@@ " " "; +const char *menuDataDe = + " @@@ @@ " + " @ @ " + " @ @ @@ @ @@@@" + " @ @ @ @@@ @ @" + " @ @ @ @ @ @ @ " + " @ @ @ @ @ @ @ " + "@@@ @@@ @@ @@ @@ @@@@ " + " " + " @@@@@@ @ @@ " + " @ @ @ " + " @ @ @@ @@@@ @ " + " @@@@ @ @ @ @@@ " + " @ @ @ @ @ @ " + " @ @ @ @ @ @ @ " + "@@ @@ @@@ @@@ @@ @@" + " " + " @ @@ @ " + " @@@ @ @ " + " @ @ @ @@ @@@@ " + " @ @ @ @ @ " + " @@@@@ @@@ @ " + " @ @ @ @ @ " + "@@@ @@@ @@@ @@ @@ " + " " + " @@@ @@ " + " @ @ " + " @ @@@@ @ " + " @ @ @ @@@ " + " @ @ @ @ " + " @ @ @ @ @ " + " @@@ @@@ @@ @@ " + " " + " @@@@@@ " + " @ @ @@ " + " @ @ @@@ @ @@@ " + " @@@@ @ @ @@@@ @ @" + " @ @ @@@@@ @ @ @@@@ " + " @ @ @ @ @ @ " + "@@ @@ @@@ @@@ @@@ " + " " + " @@@@@ @ " + " @ @ @ " + " @ @ @@@@ @@@@ " + " @ @ @ @ @ " + " @ @ @ @ @ " + " @ @ @ @ @ " + "@@@@@ @@@@ @@ " + " "; + +const int verbsFr[26] = { 0x301, 0x302, 0x303, 0x304, 0x305, 0x306, 0x307, 0x308, + 0x309, 0x30a, 0x30b, 0x30c, 0x30d, 0x30e, 0x30f, 0x310, + 0x311, 0x312, 0x313, 0x314, 0x315, 0x401, 0x402, 0x403, + 0x404, 0x405 }; + +const int verbsEn[26] = { 0x301, 0x315, 0x305, 0x310, 0x309, 0x304, 0x302, 0x30f, + 0x306, 0x30d, 0x30e, 0x303, 0x30c, 0x30b, 0x313, 0x30a, + 0x311, 0x312, 0x307, 0x308, 0x314, 0x401, 0x405, 0x404, + 0x403, 0x402 }; + +const int verbsDe[26] = { 0x304, 0x314, 0x307, 0x310, 0x315, 0x308, 0x311, 0x306, + 0x30c, 0x301, 0x30d, 0x309, 0x312, 0x30f, 0x30e, 0x302, + 0x30a, 0x313, 0x303, 0x30b, 0x305, 0x405, 0x402, 0x404, + 0x403, 0x401 }; #endif diff --git a/devtools/create_project/msbuild.cpp b/devtools/create_project/msbuild.cpp index 23bf1bc28a..60aa35b739 100644 --- a/devtools/create_project/msbuild.cpp +++ b/devtools/create_project/msbuild.cpp @@ -405,7 +405,7 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b if (isRelease) { properties << "\t\t\t<IntrinsicFunctions>true</IntrinsicFunctions>\n" "\t\t\t<WholeProgramOptimization>true</WholeProgramOptimization>\n" - "\t\t\t<PreprocessorDefinitions>WIN32;DISABLE_GUI_BUILTIN_THEME;RELEASE_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" + "\t\t\t<PreprocessorDefinitions>WIN32;RELEASE_BUILD;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" "\t\t\t<StringPooling>true</StringPooling>\n" "\t\t\t<BufferSecurityCheck>false</BufferSecurityCheck>\n" "\t\t\t<DebugInformationFormat></DebugInformationFormat>\n" @@ -417,7 +417,7 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b "\t\t\t<SetChecksum>true</SetChecksum>\n"; } else { properties << "\t\t\t<Optimization>Disabled</Optimization>\n" - "\t\t\t<PreprocessorDefinitions>WIN32;DISABLE_GUI_BUILTIN_THEME;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" + "\t\t\t<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" "\t\t\t<MinimalRebuild>true</MinimalRebuild>\n" "\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n" "\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n" diff --git a/devtools/create_project/visualstudio.cpp b/devtools/create_project/visualstudio.cpp index 17e378fd0f..23225d3435 100644 --- a/devtools/create_project/visualstudio.cpp +++ b/devtools/create_project/visualstudio.cpp @@ -286,7 +286,7 @@ void VisualStudioProvider::createBuildProp(const BuildSetup &setup, bool isRelea if (isRelease) { properties << "\t\tEnableIntrinsicFunctions=\"true\"\n" "\t\tWholeProgramOptimization=\"true\"\n" - "\t\tPreprocessorDefinitions=\"WIN32;DISABLE_GUI_BUILTIN_THEME;RELEASE_BUILD\"\n" + "\t\tPreprocessorDefinitions=\"WIN32;RELEASE_BUILD\"\n" "\t\tStringPooling=\"true\"\n" "\t\tBufferSecurityCheck=\"false\"\n" "\t\tDebugInformationFormat=\"0\"\n" @@ -300,7 +300,7 @@ void VisualStudioProvider::createBuildProp(const BuildSetup &setup, bool isRelea "\t\tSetChecksum=\"true\"\n"; } else { properties << "\t\tOptimization=\"0\"\n" - "\t\tPreprocessorDefinitions=\"WIN32;DISABLE_GUI_BUILTIN_THEME\"\n" + "\t\tPreprocessorDefinitions=\"WIN32\"\n" "\t\tMinimalRebuild=\"true\"\n" "\t\tBasicRuntimeChecks=\"3\"\n" "\t\tRuntimeLibrary=\"1\"\n" diff --git a/devtools/credits.pl b/devtools/credits.pl index 7d39730c63..45018a5633 100755 --- a/devtools/credits.pl +++ b/devtools/credits.pl @@ -638,6 +638,16 @@ begin_credits("Credits"); add_person("David Turner", "digitall", ""); end_section(); + begin_section("Mortevielle"); + add_person("Arnaud Boutonné", "Strangerke", ""); + add_person("Paul Gilbert", "dreammaster", ""); + end_section(); + + begin_section("Neverhood"); + add_person("Benjamin Haisch", "john_doe", ""); + add_person("Filippos Karapetis", "[md5]", ""); + end_section(); + begin_section("Parallaction"); add_person("", "peres", ""); end_section(); diff --git a/devtools/scumm-md5.txt b/devtools/scumm-md5.txt index 76c12f57f4..0dbcbf4792 100644 --- a/devtools/scumm-md5.txt +++ b/devtools/scumm-md5.txt @@ -775,6 +775,7 @@ puttzoo Putt-Putt Saves the Zoo 3a3e592b074f595489f7f11e150c398d -1 us Windows HE 99 Updated - Adrian c5cc7cba02a2fbd539c4439e775b0536 43470 de Windows HE 99 Updated - Lightkey 5c9cecbd2952ccec14c9ecebf5822a34 -1 en iOS HE 100 - - clone2727 + 7b4ee071eecadc2d8cd0c3509110825c -1 en Windows HE 100 Remastered - Kirben 3486ede0f904789267d4bcc5537a46d4 14337 en Mac - Demo - khalek d220d154aafbfa12bd6f3ab1b2dae420 -1 de Mac - Demo - Joachim Eberhard diff --git a/dists/engine-data/mort.dat b/dists/engine-data/mort.dat Binary files differindex 8775b46c38..0d6a44206d 100644 --- a/dists/engine-data/mort.dat +++ b/dists/engine-data/mort.dat diff --git a/engines/agi/detection_tables.h b/engines/agi/detection_tables.h index 0c2c3ed3be..f1bb079ffc 100644 --- a/engines/agi/detection_tables.h +++ b/engines/agi/detection_tables.h @@ -642,6 +642,7 @@ static const AGIGameDescription gameDescriptions[] = { FANMADE("AGI Piano (v1.0)", "8778b3d89eb93c1d50a70ef06ef10310"), FANMADE("AGI Quest (v1.46-TJ0)", "1cf1a5307c1a0a405f5039354f679814"), GAME("tetris", "", "7a874e2db2162e7a4ce31c9130248d8a", 0x2917, GID_FANMADE), + FANMADE("AGI Tetris (1998)", "1afcbc25bfafded2d5fb82de9da0bd9a"), FANMADE_V("AGI Trek (Demo)", "c02882b8a8245b629c91caf7eb78eafe", 0x2440), FANMADE_F("AGI256 Demo", "79261ac143b2e2773b2753674733b0d5", GF_AGI256), FANMADE_F("AGI256-2 Demo", "3cad9b3aff1467cebf0c5c5b110985c5", GF_AGI256_2), diff --git a/engines/agos/agos.h b/engines/agos/agos.h index 65f8dd1420..87a1228c6a 100644 --- a/engines/agos/agos.h +++ b/engines/agos/agos.h @@ -1272,7 +1272,7 @@ protected: Item *getNextItemPtrStrange(); - virtual bool loadGame(const char *filename, bool restartMode = false); + virtual bool loadGame(const Common::String &filename, bool restartMode = false); virtual bool saveGame(uint slot, const char *caption); void openTextWindow(); @@ -1311,7 +1311,7 @@ protected: int countSaveGames(); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; }; class AGOSEngine_PN : public AGOSEngine { @@ -1517,8 +1517,8 @@ protected: virtual void windowPutChar(WindowBlock *window, byte c, byte b = 0); bool badload(int8 errorNum); - int loadFile(char *name); - int saveFile(char *name); + int loadFile(const Common::String &name); + int saveFile(const Common::String &name); void getFilename(); void sysftodb(); void dbtosysf(); @@ -1640,7 +1640,7 @@ protected: virtual void drawIcon(WindowBlock *window, uint icon, uint x, uint y); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; }; class AGOSEngine_Elvira2 : public AGOSEngine_Elvira1 { @@ -1709,7 +1709,7 @@ protected: virtual void readItemChildren(Common::SeekableReadStream *in, Item *item, uint tmp); - virtual bool loadGame(const char *filename, bool restartMode = false); + virtual bool loadGame(const Common::String &filename, bool restartMode = false); virtual bool saveGame(uint slot, const char *caption); virtual void addArrows(WindowBlock *window, uint8 num); @@ -1735,7 +1735,7 @@ protected: virtual void userGame(bool load); virtual int userGameGetKey(bool *b, char *buf, uint maxChar); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; }; class AGOSEngine_Waxworks : public AGOSEngine_Elvira2 { @@ -1802,7 +1802,7 @@ protected: virtual bool confirmOverWrite(WindowBlock *window); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; }; class AGOSEngine_Simon1 : public AGOSEngine_Waxworks { @@ -1873,7 +1873,7 @@ protected: virtual void vcStopAnimation(uint16 zone, uint16 sprite); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; }; class AGOSEngine_Simon2 : public AGOSEngine_Simon1 { @@ -1919,7 +1919,7 @@ protected: virtual void playSpeech(uint16 speechId, uint16 vgaSpriteId); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; }; #ifdef ENABLE_AGOS2 @@ -2059,7 +2059,7 @@ protected: void saveUserGame(int slot); void windowBackSpace(WindowBlock *window); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; virtual void quickLoadOrSave(); }; @@ -2139,7 +2139,7 @@ protected: void printInfoText(const char *itemText); - virtual char *genSaveName(int slot); + virtual Common::String genSaveName(int slot) const; }; diff --git a/engines/agos/saveload.cpp b/engines/agos/saveload.cpp index 48671390f0..8eb7f066b3 100644 --- a/engines/agos/saveload.cpp +++ b/engines/agos/saveload.cpp @@ -33,32 +33,35 @@ namespace AGOS { + +// FIXME: This code counts savegames, but callers in many cases assume +// that the return value + 1 indicates an empty slot. int AGOSEngine::countSaveGames() { Common::InSaveFile *f = NULL; Common::StringArray filenames; uint i = 1; - char slot[4]; int slotNum; bool marks[256]; - char *prefix = genSaveName(998); - prefix[strlen(prefix)-3] = '*'; - prefix[strlen(prefix)-2] = '\0'; + // Get the name of (possibly non-existent) savegame slot 998, and replace + // the extension by * to get a pattern. + Common::String tmp = genSaveName(998); + assert(tmp.size() >= 4 && tmp[tmp.size()-4] == '.'); + Common::String prefix = Common::String(tmp.c_str(), tmp.size()-3) + "*"; + memset(marks, false, 256 * sizeof(bool)); //assume no savegames for this title filenames = _saveFileMan->listSavefiles(prefix); for (Common::StringArray::const_iterator file = filenames.begin(); file != filenames.end(); ++file){ //Obtain the last 3 digits of the filename, since they correspond to the save slot - slot[0] = file->c_str()[file->size()-3]; - slot[1] = file->c_str()[file->size()-2]; - slot[2] = file->c_str()[file->size()-1]; - slot[3] = '\0'; - - slotNum = atoi(slot); + assert(file->size() >= 4); + slotNum = atoi(file->c_str() + file->size() - 3); if (slotNum >= 0 && slotNum < 256) marks[slotNum] = true; //mark this slot as valid } + // FIXME: Why does this already try to actually open the savegames? + // Historical accident? while (i < 256) { if (marks[i] && (f = _saveFileMan->openForLoading(genSaveName(i)))) { @@ -72,68 +75,46 @@ int AGOSEngine::countSaveGames() { } #ifdef ENABLE_AGOS2 -char *AGOSEngine_PuzzlePack::genSaveName(int slot) { - static char buf[20]; - +Common::String AGOSEngine_PuzzlePack::genSaveName(int slot) const { if (getGameId() == GID_DIMP) - sprintf(buf, "dimp.sav"); + return "dimp.sav"; else - sprintf(buf, "swampy.sav"); - - return buf; + return "swampy.sav"; } -char *AGOSEngine_Feeble::genSaveName(int slot) { - static char buf[20]; - sprintf(buf, "feeble.%.3d", slot); - return buf; +Common::String AGOSEngine_Feeble::genSaveName(int slot) const { + return Common::String::format("feeble.%.3d", slot); } #endif -char *AGOSEngine_Simon2::genSaveName(int slot) { - static char buf[20]; - sprintf(buf, "simon2.%.3d", slot); - return buf; +Common::String AGOSEngine_Simon2::genSaveName(int slot) const { + return Common::String::format("simon2.%.3d", slot); } -char *AGOSEngine_Simon1::genSaveName(int slot) { - static char buf[20]; - sprintf(buf, "simon1.%.3d", slot); - return buf; +Common::String AGOSEngine_Simon1::genSaveName(int slot) const { + return Common::String::format("simon1.%.3d", slot); } -char *AGOSEngine_Waxworks::genSaveName(int slot) { - static char buf[20]; - +Common::String AGOSEngine_Waxworks::genSaveName(int slot) const { if (getPlatform() == Common::kPlatformDOS) - sprintf(buf, "waxworks-pc.%.3d", slot); + return Common::String::format("waxworks-pc.%.3d", slot); else - sprintf(buf, "waxworks.%.3d", slot); - - return buf; + return Common::String::format("waxworks.%.3d", slot); } -char *AGOSEngine_Elvira2::genSaveName(int slot) { - static char buf[20]; - +Common::String AGOSEngine_Elvira2::genSaveName(int slot) const { if (getPlatform() == Common::kPlatformDOS) - sprintf(buf, "elvira2-pc.%.3d", slot); + return Common::String::format("elvira2-pc.%.3d", slot); else - sprintf(buf, "elvira2.%.3d", slot); - - return buf; + return Common::String::format("elvira2.%.3d", slot); } -char *AGOSEngine_Elvira1::genSaveName(int slot) { - static char buf[20]; - sprintf(buf, "elvira1.%.3d", slot); - return buf; +Common::String AGOSEngine_Elvira1::genSaveName(int slot) const { + return Common::String::format("elvira1.%.3d", slot); } -char *AGOSEngine::genSaveName(int slot) { - static char buf[20]; - sprintf(buf, "pn.%.3d", slot); - return buf; +Common::String AGOSEngine::genSaveName(int slot) const { + return Common::String::format("pn.%.3d", slot); } #ifdef ENABLE_AGOS2 @@ -177,12 +158,12 @@ void AGOSEngine::quickLoadOrSave() { waitForSync(1122); } - char *filename = genSaveName(_saveLoadSlot); + Common::String filename = genSaveName(_saveLoadSlot); if (_saveLoadType == 2) { Subroutine *sub; success = loadGame(genSaveName(_saveLoadSlot)); if (!success) { - buf = Common::String::format(_("Failed to load game state from file:\n\n%s"), filename); + buf = Common::String::format(_("Failed to load game state from file:\n\n%s"), filename.c_str()); } else if (getGameType() == GType_SIMON1 || getGameType() == GType_SIMON2) { drawIconArray(2, me(), 0, 0); setBitFlag(97, true); @@ -217,7 +198,7 @@ void AGOSEngine::quickLoadOrSave() { } else { success = saveGame(_saveLoadSlot, _saveLoadName); if (!success) - buf = Common::String::format(_("Failed to save game state to file:\n\n%s"), filename); + buf = Common::String::format(_("Failed to save game state to file:\n\n%s"), filename.c_str()); } if (!success) { @@ -225,7 +206,7 @@ void AGOSEngine::quickLoadOrSave() { dialog.runModal(); } else if (_saveLoadType == 1) { - buf = Common::String::format(_("Successfully saved game state in file:\n\n%s"), filename); + buf = Common::String::format(_("Successfully saved game state in file:\n\n%s"), filename.c_str()); GUI::TimedMessageDialog dialog(buf, 1500); dialog.runModal(); @@ -1041,7 +1022,7 @@ void writeItemID(Common::WriteStream *f, uint16 val) { f->writeUint32BE(val - 1); } -bool AGOSEngine::loadGame(const char *filename, bool restartMode) { +bool AGOSEngine::loadGame(const Common::String &filename, bool restartMode) { char ident[100]; Common::SeekableReadStream *f = NULL; uint num, item_index, i; @@ -1215,7 +1196,7 @@ bool AGOSEngine::saveGame(uint slot, const char *caption) { return result; } -bool AGOSEngine_Elvira2::loadGame(const char *filename, bool restartMode) { +bool AGOSEngine_Elvira2::loadGame(const Common::String &filename, bool restartMode) { char ident[100]; Common::SeekableReadStream *f = NULL; uint num, item_index, i, j; @@ -1633,7 +1614,7 @@ void AGOSEngine_PN::getFilename() { } } -int AGOSEngine_PN::loadFile(char *name) { +int AGOSEngine_PN::loadFile(const Common::String &name) { Common::InSaveFile *f; haltAnimation(); @@ -1666,7 +1647,7 @@ int AGOSEngine_PN::loadFile(char *name) { return 0; } -int AGOSEngine_PN::saveFile(char *name) { +int AGOSEngine_PN::saveFile(const Common::String &name) { Common::OutSaveFile *f; sysftodb(); haltAnimation(); diff --git a/engines/agos/script_pn.cpp b/engines/agos/script_pn.cpp index 60a1376f25..e98cd2795a 100644 --- a/engines/agos/script_pn.cpp +++ b/engines/agos/script_pn.cpp @@ -370,7 +370,7 @@ void AGOSEngine_PN::opn_opcode30() { void AGOSEngine_PN::opn_opcode31() { int a, slot = 0; - char bf[60]; + Common::String bf; if ((a = varval()) > 2) { setScriptReturn(false); @@ -381,10 +381,10 @@ void AGOSEngine_PN::opn_opcode31() { case 0: getFilename(); slot = matchSaveGame(_saveFile, countSaveGames()); - strcpy(bf, genSaveName(slot)); + bf = genSaveName(slot); break; case 1: - strcpy(bf, "pn.sav"); + bf = "pn.sav"; break; case 2: // NOTE: Is this case ever used? @@ -404,7 +404,7 @@ void AGOSEngine_PN::opn_opcode31() { } void AGOSEngine_PN::opn_opcode32() { - char bf[60]; + Common::String bf; int a, slot; a = varval(); @@ -419,12 +419,12 @@ void AGOSEngine_PN::opn_opcode32() { getFilename(); slot = matchSaveGame(_saveFile, curSlot); if (slot != -1) - strcpy(bf, genSaveName(slot)); + bf = genSaveName(slot); else - strcpy(bf, genSaveName(curSlot)); + bf = genSaveName(curSlot); break; case 1: - strcpy(bf, "pn.sav"); + bf = "pn.sav"; break; case 2: // NOTE: Is this case ever used? diff --git a/engines/drascula/actors.cpp b/engines/drascula/actors.cpp index 9d5d6550fa..e0983809fa 100644 --- a/engines/drascula/actors.cpp +++ b/engines/drascula/actors.cpp @@ -135,7 +135,7 @@ void DrasculaEngine::startWalking() { else characterMoved = 0; } - startTime = getTime(); + _startTime = getTime(); } void DrasculaEngine::moveCharacters() { @@ -239,7 +239,7 @@ void DrasculaEngine::moveCharacters() { factor_red[curY + curHeight], frontSurface, screenSurface); } } else if (characterMoved == 1) { - curPos[0] = _frameX[num_frame]; + curPos[0] = _frameX[_characterFrame]; curPos[1] = frame_y + DIF_MASK_HARE; curPos[2] = curX; curPos[3] = curY; @@ -369,13 +369,11 @@ void DrasculaEngine::quadrant_4() { } void DrasculaEngine::increaseFrameNum() { - timeDiff = getTime() - startTime; - - if (timeDiff >= 6) { - startTime = getTime(); - num_frame++; - if (num_frame == 6) - num_frame = 0; + if (getTime() - _startTime >= 6) { + _startTime = getTime(); + _characterFrame++; + if (_characterFrame == 6) + _characterFrame = 0; if (curDirection == kDirectionUp) { curX -= stepX; diff --git a/engines/drascula/animation.cpp b/engines/drascula/animation.cpp index 52cab6cd32..1145c8c3ff 100644 --- a/engines/drascula/animation.cpp +++ b/engines/drascula/animation.cpp @@ -426,7 +426,7 @@ void DrasculaEngine::animation_2_1() { if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit()) break; - roomNumber = 16; + _roomNumber = 16; if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit()) break; @@ -512,7 +512,7 @@ void DrasculaEngine::animation_2_1() { // room number to -1 for the same purpose // Also check animation_9_6(), where the same hack was used by // the original - roomNumber = -1; + _roomNumber = -1; if ((term_int == 1) || (getScan() == Common::KEYCODE_ESCAPE) || shouldQuit()) break; pause(8); @@ -734,7 +734,7 @@ void DrasculaEngine::animation_14_2() { void DrasculaEngine::asco() { loadPic(roomDisk, drawSurface3); - loadPic(roomNumber, bgSurface, HALF_PAL); + loadPic(_roomNumber, bgSurface, HALF_PAL); black(); updateRoom(); updateScreen(); @@ -1661,7 +1661,7 @@ void DrasculaEngine::animation_9_6() { // We set the room number to -1 for the same purpose. // Also check animation_2_1(), where the same hack was used // by the original - roomNumber = -2; + _roomNumber = -2; loadPic("nota2.alg", bgSurface, HALF_PAL); black(); trackProtagonist = 1; @@ -2176,9 +2176,9 @@ void DrasculaEngine::animation_5_4(){ void DrasculaEngine::animation_6_4() { debug(4, "animation_6_4()"); - int prevRoom = roomNumber; + int prevRoom = _roomNumber; - roomNumber = 26; + _roomNumber = 26; clearRoom(); loadPic(26, bgSurface, HALF_PAL); loadPic("aux26.alg", drawSurface3); @@ -2191,11 +2191,11 @@ void DrasculaEngine::animation_6_4() { updateScreen(); pause(40); talk_igor(26, kIgorFront); - roomNumber = prevRoom; + _roomNumber = prevRoom; clearRoom(); loadPic(96, frontSurface); loadPic(roomDisk, drawSurface3); - loadPic(roomNumber, bgSurface, HALF_PAL); + loadPic(_roomNumber, bgSurface, HALF_PAL); selectVerb(kVerbNone); updateRoom(); } @@ -2224,7 +2224,7 @@ void DrasculaEngine::activatePendulum() { flags[1] = 2; hare_se_ve = 0; - roomNumber = 102; + _roomNumber = 102; loadPic(102, bgSurface, HALF_PAL); loadPic("an_p1.alg", drawSurface3); loadPic("an_p2.alg", extraSurface); diff --git a/engines/drascula/console.cpp b/engines/drascula/console.cpp index 426b2ade67..c0d2748ec3 100644 --- a/engines/drascula/console.cpp +++ b/engines/drascula/console.cpp @@ -41,7 +41,7 @@ bool Console::Cmd_Room(int argc, const char **argv) { int roomNum = atoi(argv[1]); - _vm->loadedDifferentChapter = 0; + _vm->_loadedDifferentChapter = false; _vm->enterRoom(roomNum); _vm->selectVerb(kVerbNone); _vm->clearRoom(); diff --git a/engines/drascula/converse.cpp b/engines/drascula/converse.cpp index d045d683fc..95a5f7d87f 100644 --- a/engines/drascula/converse.cpp +++ b/engines/drascula/converse.cpp @@ -216,7 +216,7 @@ void DrasculaEngine::converse(int index) { phrase3_bottom = phrase2_bottom + 8 * print_abc_opc(phrase3, phrase2_bottom + 2, game3); phrase4_bottom = phrase3_bottom + 8 * print_abc_opc(phrase4, phrase3_bottom + 2, kDialogOptionUnselected); - if (mouseY > 0 && mouseY < phrase1_bottom) { + if (_mouseY > 0 && _mouseY < phrase1_bottom) { if (game1 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game1 != kDialogOptionClicked && _color != kColorLightGreen) @@ -224,13 +224,13 @@ void DrasculaEngine::converse(int index) { print_abc_opc(phrase1, 2, kDialogOptionSelected); - if (leftMouseButton == 1) { + if (_leftMouseButton == 1) { delay(100); game1 = kDialogOptionClicked; talk(phrase1, sound1); response(answer1); } - } else if (mouseY > phrase1_bottom && mouseY < phrase2_bottom) { + } else if (_mouseY > phrase1_bottom && _mouseY < phrase2_bottom) { if (game2 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game2 != kDialogOptionClicked && _color != kColorLightGreen) @@ -238,13 +238,13 @@ void DrasculaEngine::converse(int index) { print_abc_opc(phrase2, phrase1_bottom + 2, kDialogOptionSelected); - if (leftMouseButton == 1) { + if (_leftMouseButton == 1) { delay(100); game2 = kDialogOptionClicked; talk(phrase2, sound2); response(answer2); } - } else if (mouseY > phrase2_bottom && mouseY < phrase3_bottom) { + } else if (_mouseY > phrase2_bottom && _mouseY < phrase3_bottom) { if (game3 == kDialogOptionClicked && _color != kColorWhite) color_abc(kColorWhite); else if (game3 != kDialogOptionClicked && _color != kColorLightGreen) @@ -252,16 +252,16 @@ void DrasculaEngine::converse(int index) { print_abc_opc(phrase3, phrase2_bottom + 2, kDialogOptionSelected); - if (leftMouseButton == 1) { + if (_leftMouseButton == 1) { delay(100); game3 = kDialogOptionClicked; talk(phrase3, sound3); response(answer3); } - } else if (mouseY > phrase3_bottom && mouseY < phrase4_bottom) { + } else if (_mouseY > phrase3_bottom && _mouseY < phrase4_bottom) { print_abc_opc(phrase4, phrase3_bottom + 2, kDialogOptionSelected); - if (leftMouseButton == 1) { + if (_leftMouseButton == 1) { delay(100); talk(phrase4, sound4); breakOut = 1; diff --git a/engines/drascula/drascula.cpp b/engines/drascula/drascula.cpp index 804881cf9a..cde00baa32 100644 --- a/engines/drascula/drascula.cpp +++ b/engines/drascula/drascula.cpp @@ -91,10 +91,10 @@ DrasculaEngine::DrasculaEngine(OSystem *syst, const DrasculaGameDescription *gam _color = 0; blinking = 0; - mouseX = 0; - mouseY = 0; - leftMouseButton = 0; - rightMouseButton = 0; + _mouseX = 0; + _mouseY = 0; + _leftMouseButton = 0; + _rightMouseButton = 0; *textName = 0; _rnd = new Common::RandomSource("drascula"); @@ -197,7 +197,7 @@ Common::Error DrasculaEngine::run() { syncSoundSettings(); currentChapter = 1; // values from 1 to 6 will start each part of game - loadedDifferentChapter = 0; + _loadedDifferentChapter = false; setTotalPlayTime(0); // Check if a save is loaded from the launcher @@ -218,7 +218,7 @@ Common::Error DrasculaEngine::run() { curX = -1; characterMoved = 0; trackProtagonist = 3; - num_frame = 0; + _characterFrame = 0; hare_se_ve = 1; checkFlags = 1; doBreak = 0; @@ -231,9 +231,6 @@ Common::Error DrasculaEngine::run() { curWidth = CHARACTER_WIDTH; feetHeight = FEET_HEIGHT; - talkHeight = TALK_HEIGHT; - talkWidth = TALK_WIDTH; - hasAnswer = 0; savedTime = 0; breakOut = 0; @@ -246,7 +243,7 @@ Common::Error DrasculaEngine::run() { globalSpeed = 0; curExcuseLook = 0; curExcuseAction = 0; - roomNumber = 0; + _roomNumber = 0; for (i = 0; i < 8; i++) actorFrames[i] = 0; @@ -268,7 +265,7 @@ Common::Error DrasculaEngine::run() { loadPic("aux13.alg", bgSurface, COMPLETE_PAL); loadPic(96, frontSurface); } else if (currentChapter == 4) { - if (loadedDifferentChapter == 0) + if (!_loadedDifferentChapter) animation_castle(); loadPic(96, frontSurface); clearRoom(); @@ -330,7 +327,7 @@ void DrasculaEngine::endChapter() { bool DrasculaEngine::runCurrentChapter() { int n; - rightMouseButton = 0; + _rightMouseButton = 0; previousMusic = -1; @@ -360,14 +357,14 @@ bool DrasculaEngine::runCurrentChapter() { if (currentChapter == 1) { pickObject(28); - if (loadedDifferentChapter == 0) + if (!_loadedDifferentChapter) animation_1_1(); selectVerb(kVerbNone); loadPic("2aux62.alg", drawSurface2); trackProtagonist = 1; objExit = 104; - if (loadedDifferentChapter != 0) { + if (_loadedDifferentChapter) { if (!loadGame(_currentSaveSlot)) { return true; } @@ -383,7 +380,7 @@ bool DrasculaEngine::runCurrentChapter() { addObject(kItemPhone); trackProtagonist = 3; objExit = 162; - if (loadedDifferentChapter == 0) + if (!_loadedDifferentChapter) enterRoom(14); else { if (!loadGame(_currentSaveSlot)) { @@ -401,7 +398,7 @@ bool DrasculaEngine::runCurrentChapter() { flags[1] = 1; trackProtagonist = 1; objExit = 99; - if (loadedDifferentChapter == 0) + if (!_loadedDifferentChapter) enterRoom(20); else { if (!loadGame(_currentSaveSlot)) { @@ -415,7 +412,7 @@ bool DrasculaEngine::runCurrentChapter() { addObject(kItemReefer2); addObject(kItemOneCoin2); objExit = 100; - if (loadedDifferentChapter == 0) { + if (!_loadedDifferentChapter) { enterRoom(21); trackProtagonist = 0; curX = 235; @@ -437,7 +434,7 @@ bool DrasculaEngine::runCurrentChapter() { addObject(20); trackProtagonist = 1; objExit = 100; - if (loadedDifferentChapter == 0) { + if (!_loadedDifferentChapter) { enterRoom(45); } else { if (!loadGame(_currentSaveSlot)) { @@ -450,7 +447,7 @@ bool DrasculaEngine::runCurrentChapter() { trackProtagonist = 1; objExit = 104; - if (loadedDifferentChapter == 0) { + if (!_loadedDifferentChapter) { enterRoom(58); animation_1_6(); } else { @@ -480,13 +477,13 @@ bool DrasculaEngine::runCurrentChapter() { // lead to an incorrect setting of the protagonist's tracking flag (above). This // made the character start walking off screen, as his actual position was // different than the displayed one - if (roomNumber == 3 && (curX == 279) && (curY + curHeight == 101)) { + if (_roomNumber == 3 && (curX == 279) && (curY + curHeight == 101)) { gotoObject(178, 121); gotoObject(169, 135); - } else if (roomNumber == 14 && (curX == 214) && (curY + curHeight == 121)) { + } else if (_roomNumber == 14 && (curX == 214) && (curY + curHeight == 121)) { walkToObject = 1; gotoObject(190, 130); - } else if (roomNumber == 14 && (curX == 246) && (curY + curHeight == 112)) { + } else if (_roomNumber == 14 && (curX == 246) && (curY + curHeight == 112)) { walkToObject = 1; gotoObject(190, 130); } @@ -518,12 +515,12 @@ bool DrasculaEngine::runCurrentChapter() { checkObjects(); #ifdef _WIN32_WCE - if (rightMouseButton) { + if (_rightMouseButton) { if (_menuScreen) { #else - if (rightMouseButton == 1 && _menuScreen) { + if (_rightMouseButton == 1 && _menuScreen) { #endif - rightMouseButton = 0; + _rightMouseButton = 0; delay(100); if (currentChapter == 2) { loadPic(menuBackground, cursorSurface); @@ -549,10 +546,10 @@ bool DrasculaEngine::runCurrentChapter() { // Do not show the inventory screen in chapter 5, if the right mouse button is clicked // while the plug (object 16) is held // Fixes bug #2059621 - "DRASCULA: Plug bug" - if (rightMouseButton == 1 && !_menuScreen && + if (_rightMouseButton == 1 && !_menuScreen && !(currentChapter == 5 && pickedObject == 16)) { #endif - rightMouseButton = 0; + _rightMouseButton = 0; delay(100); characterMoved = 0; if (trackProtagonist == 2) @@ -580,19 +577,19 @@ bool DrasculaEngine::runCurrentChapter() { } #endif - if (leftMouseButton == 1 && _menuBar) { + if (_leftMouseButton == 1 && _menuBar) { delay(100); selectVerbFromBar(); - } else if (leftMouseButton == 1 && takeObject == 0) { + } else if (_leftMouseButton == 1 && takeObject == 0) { delay(100); if (verify1()) return true; - } else if (leftMouseButton == 1 && takeObject == 1) { + } else if (_leftMouseButton == 1 && takeObject == 1) { if (verify2()) return true; } - _menuBar = (mouseY < 24 && !_menuScreen) ? true : false; + _menuBar = (_mouseY < 24 && !_menuScreen) ? true : false; Common::KeyCode key = getScan(); if (key == Common::KEYCODE_F1 && !_menuScreen) { @@ -644,11 +641,11 @@ bool DrasculaEngine::runCurrentChapter() { } else if (key == Common::KEYCODE_TILDE || key == Common::KEYCODE_BACKQUOTE) { _console->attach(); _console->onFrame(); - } else if (currentChapter == 6 && key == Common::KEYCODE_0 && roomNumber == 61) { + } else if (currentChapter == 6 && key == Common::KEYCODE_0 && _roomNumber == 61) { loadPic("alcbar.alg", bgSurface, 255); } - if (leftMouseButton != 0 || rightMouseButton != 0 || key != 0) + if (_leftMouseButton != 0 || _rightMouseButton != 0 || key != 0) framesWithoutAction = 0; if (framesWithoutAction == 15000) { @@ -670,8 +667,8 @@ bool DrasculaEngine::verify1() { removeObject(); else { for (l = 0; l < numRoomObjs; l++) { - if (mouseX >= _objectX1[l] && mouseY >= _objectY1[l] - && mouseX <= _objectX2[l] && mouseY <= _objectY2[l] && doBreak == 0) { + if (_mouseX >= _objectX1[l] && _mouseY >= _objectY1[l] + && _mouseX <= _objectX2[l] && _mouseY <= _objectY2[l] && doBreak == 0) { if (exitRoom(l)) return true; if (doBreak == 1) @@ -679,13 +676,13 @@ bool DrasculaEngine::verify1() { } } - if (mouseX > curX && mouseY > curY - && mouseX < curX + curWidth && mouseY < curY + curHeight) + if (_mouseX > curX && _mouseY > curY + && _mouseX < curX + curWidth && _mouseY < curY + curHeight) doBreak = 1; for (l = 0; l < numRoomObjs; l++) { - if (mouseX > _objectX1[l] && mouseY > _objectY1[l] - && mouseX < _objectX2[l] && mouseY < _objectY2[l] && doBreak == 0) { + if (_mouseX > _objectX1[l] && _mouseY > _objectY1[l] + && _mouseX < _objectX2[l] && _mouseY < _objectY2[l] && doBreak == 0) { roomX = roomObjX[l]; roomY = roomObjY[l]; trackFinal = trackObj[l]; @@ -696,8 +693,8 @@ bool DrasculaEngine::verify1() { } if (doBreak == 0) { - roomX = CLIP(mouseX, floorX1, floorX2); - roomY = CLIP(mouseY, floorY1 + feetHeight, floorY2); + roomX = CLIP(_mouseX, floorX1, floorX2); + roomY = CLIP(_mouseY, floorY1 + feetHeight, floorY2); startWalking(); } doBreak = 0; @@ -718,8 +715,8 @@ bool DrasculaEngine::verify2() { return true; } else { for (l = 0; l < numRoomObjs; l++) { - if (mouseX > _objectX1[l] && mouseY > _objectY1[l] - && mouseX < _objectX2[l] && mouseY < _objectY2[l] && visible[l] == 1) { + if (_mouseX > _objectX1[l] && _mouseY > _objectY1[l] + && _mouseX < _objectX2[l] && _mouseY < _objectY2[l] && visible[l] == 1) { trackFinal = trackObj[l]; walkToObject = 1; gotoObject(roomObjX[l], roomObjY[l]); @@ -779,20 +776,20 @@ void DrasculaEngine::updateEvents() { case Common::EVENT_KEYUP: break; case Common::EVENT_MOUSEMOVE: - mouseX = event.mouse.x; - mouseY = event.mouse.y; + _mouseX = event.mouse.x; + _mouseY = event.mouse.y; break; case Common::EVENT_LBUTTONDOWN: - leftMouseButton = 1; + _leftMouseButton = 1; break; case Common::EVENT_LBUTTONUP: - leftMouseButton = 0; + _leftMouseButton = 0; break; case Common::EVENT_RBUTTONDOWN: // We changed semantic and react only on button up event break; case Common::EVENT_RBUTTONUP: - rightMouseButton = 1; + _rightMouseButton = 1; break; default: break; diff --git a/engines/drascula/drascula.h b/engines/drascula/drascula.h index c4d1c4c761..944191b5fb 100644 --- a/engines/drascula/drascula.h +++ b/engines/drascula/drascula.h @@ -403,7 +403,7 @@ public: int actorFrames[8]; int previousMusic, roomMusic; - int roomNumber; + int _roomNumber; char roomDisk[20]; char currentData[20]; int numRoomObjs; @@ -428,18 +428,17 @@ public: int flags[NUM_FLAGS]; int frame_y; - int curX, curY, characterMoved, curDirection, trackProtagonist, num_frame; + int curX, curY, characterMoved, curDirection, trackProtagonist, _characterFrame; int hare_se_ve; // TODO: what is this for? int roomX, roomY, checkFlags; int doBreak; int stepX, stepY; int curHeight, curWidth, feetHeight; - int talkHeight, talkWidth; int floorX1, floorY1, floorX2, floorY2; int lowerLimit, upperLimit; int trackFinal, walkToObject; int objExit; - int timeDiff, startTime; + int _startTime; int hasAnswer; int savedTime; int breakOut; @@ -454,14 +453,11 @@ public: int framesWithoutAction; int term_int; int currentChapter; - int loadedDifferentChapter; + bool _loadedDifferentChapter; int _currentSaveSlot; int _color; int musicStopped; - int mouseX; - int mouseY; - int leftMouseButton; - int rightMouseButton; + int _mouseX, _mouseY, _leftMouseButton, _rightMouseButton; Common::KeyState _keyBuffer[KEYBUFSIZE]; int _keyBufferHead; diff --git a/engines/drascula/graphics.cpp b/engines/drascula/graphics.cpp index 31d03a94a7..b28de669b6 100644 --- a/engines/drascula/graphics.cpp +++ b/engines/drascula/graphics.cpp @@ -82,7 +82,7 @@ void DrasculaEngine::moveCursor() { } else if (!_menuScreen && _color != kColorLightGreen) color_abc(kColorLightGreen); if (_hasName && !_menuScreen) - centerText(textName, mouseX, mouseY); + centerText(textName, _mouseX, _mouseY); if (_menuScreen) showMenu(); else if (_menuBar) @@ -417,8 +417,8 @@ void DrasculaEngine::screenSaver() { delete stream; updateEvents(); - xr = mouseX; - yr = mouseY; + xr = _mouseX; + yr = _mouseY; while (!shouldQuit()) { // efecto(bgSurface); @@ -480,18 +480,18 @@ void DrasculaEngine::screenSaver() { // end of efecto() updateEvents(); - if (rightMouseButton == 1 || leftMouseButton == 1) + if (_rightMouseButton == 1 || _leftMouseButton == 1) break; - if (mouseX != xr) + if (_mouseX != xr) break; - if (mouseY != yr) + if (_mouseY != yr) break; } // fin_ghost(); free(copia); free(ghost); - loadPic(roomNumber, bgSurface, HALF_PAL); + loadPic(_roomNumber, bgSurface, HALF_PAL); showCursor(); } diff --git a/engines/drascula/interface.cpp b/engines/drascula/interface.cpp index fca8040f59..f0b6d12027 100644 --- a/engines/drascula/interface.cpp +++ b/engines/drascula/interface.cpp @@ -51,7 +51,7 @@ bool DrasculaEngine::isCursorVisible() { void DrasculaEngine::selectVerbFromBar() { for (int n = 0; n < 7; n++) { - if (mouseX > _verbBarX[n] && mouseX < _verbBarX[n + 1] && n > 0) { + if (_mouseX > _verbBarX[n] && _mouseX < _verbBarX[n + 1] && n > 0) { selectVerb(n); return; } @@ -143,7 +143,7 @@ void DrasculaEngine::clearMenu() { int n, verbActivated = 1; for (n = 0; n < 7; n++) { - if (mouseX > _verbBarX[n] && mouseX < _verbBarX[n + 1]) + if (_mouseX > _verbBarX[n] && _mouseX < _verbBarX[n + 1]) verbActivated = 0; copyRect(OBJWIDTH * n, OBJHEIGHT * verbActivated, _verbBarX[n], 2, OBJWIDTH, OBJHEIGHT, cursorSurface, screenSurface); @@ -165,8 +165,8 @@ void DrasculaEngine::showMap() { _hasName = false; for (int l = 0; l < numRoomObjs; l++) { - if (mouseX > _objectX1[l] && mouseY > _objectY1[l] - && mouseX < _objectX2[l] && mouseY < _objectY2[l] + if (_mouseX > _objectX1[l] && _mouseY > _objectY1[l] + && _mouseX < _objectX2[l] && _mouseY < _objectY2[l] && visible[l] == 1) { strcpy(textName, objName[l]); _hasName = true; diff --git a/engines/drascula/objects.cpp b/engines/drascula/objects.cpp index f9f68c3317..35dfd3162a 100644 --- a/engines/drascula/objects.cpp +++ b/engines/drascula/objects.cpp @@ -91,8 +91,8 @@ void DrasculaEngine::gotoObject(int pointX, int pointY) { updateRoom(); updateScreen(); - // roomNumber -2 is end credits. Do not show cursor there - if (cursorVisible && roomNumber != -2) + // _roomNumber -2 is end credits. Do not show cursor there + if (cursorVisible && _roomNumber != -2) showCursor(); } @@ -100,8 +100,8 @@ void DrasculaEngine::checkObjects() { int l, veo = 0; for (l = 0; l < numRoomObjs; l++) { - if (mouseX > _objectX1[l] && mouseY > _objectY1[l] - && mouseX < _objectX2[l] && mouseY < _objectY2[l] + if (_mouseX > _objectX1[l] && _mouseY > _objectY1[l] + && _mouseX < _objectX2[l] && _mouseY < _objectY2[l] && visible[l] == 1 && isDoor[l] == 0) { strcpy(textName, objName[l]); _hasName = true; @@ -109,8 +109,8 @@ void DrasculaEngine::checkObjects() { } } - if (mouseX > curX + 2 && mouseY > curY + 2 - && mouseX < curX + curWidth - 2 && mouseY < curY + curHeight - 2) { + if (_mouseX > curX + 2 && _mouseY > curY + 2 + && _mouseX < curX + curWidth - 2 && _mouseY < curY + curHeight - 2) { if (currentChapter == 2 || veo == 0) { strcpy(textName, "hacker"); _hasName = true; @@ -223,9 +223,9 @@ int DrasculaEngine::whichObject() { int n; for (n = 1; n < ARRAYSIZE(inventoryObjects); n++) { - if (mouseX > _itemLocations[n].x && mouseY > _itemLocations[n].y && - mouseX < _itemLocations[n].x + OBJWIDTH && - mouseY < _itemLocations[n].y + OBJHEIGHT) { + if (_mouseX > _itemLocations[n].x && _mouseY > _itemLocations[n].y && + _mouseX < _itemLocations[n].x + OBJWIDTH && + _mouseY < _itemLocations[n].y + OBJHEIGHT) { return n; } } @@ -237,69 +237,69 @@ void DrasculaEngine::updateVisible() { if (currentChapter == 1) { // nothing } else if (currentChapter == 2) { - if (roomNumber == 2 && flags[40] == 0) + if (_roomNumber == 2 && flags[40] == 0) visible[3] = 0; - else if (roomNumber == 3 && flags[3] == 1) + else if (_roomNumber == 3 && flags[3] == 1) visible[8] = 0; - else if (roomNumber == 6 && flags[1] == 1 && flags[10] == 0) { + else if (_roomNumber == 6 && flags[1] == 1 && flags[10] == 0) { visible[2] = 0; visible[4] = 1; - } else if (roomNumber == 7 && flags[35] == 1) + } else if (_roomNumber == 7 && flags[35] == 1) visible[3] = 0; - else if (roomNumber == 14 && flags[5] == 1) + else if (_roomNumber == 14 && flags[5] == 1) visible[4] = 0; - else if (roomNumber == 18 && flags[28] == 1) + else if (_roomNumber == 18 && flags[28] == 1) visible[2] = 0; } else if (currentChapter == 3) { // nothing } else if (currentChapter == 4) { - if (roomNumber == 23 && flags[0] == 0 && flags[11] == 0) + if (_roomNumber == 23 && flags[0] == 0 && flags[11] == 0) visible[2] = 1; - if (roomNumber == 23 && flags[0] == 1 && flags[11] == 0) + if (_roomNumber == 23 && flags[0] == 1 && flags[11] == 0) visible[2] = 0; - if (roomNumber == 21 && flags[10] == 1) + if (_roomNumber == 21 && flags[10] == 1) visible[2] = 0; - if (roomNumber == 22 && flags[26] == 1) { + if (_roomNumber == 22 && flags[26] == 1) { visible[2] = 0; visible[1] = 1; } - if (roomNumber == 22 && flags[27] == 1) + if (_roomNumber == 22 && flags[27] == 1) visible[3] = 0; - if (roomNumber == 26 && flags[21] == 0) + if (_roomNumber == 26 && flags[21] == 0) strcpy(objName[2], _textmisc[0]); - if (roomNumber == 26 && flags[18] == 1) + if (_roomNumber == 26 && flags[18] == 1) visible[2] = 0; - if (roomNumber == 26 && flags[12] == 1) + if (_roomNumber == 26 && flags[12] == 1) visible[1] = 0; - if (roomNumber == 35 && flags[14] == 1) + if (_roomNumber == 35 && flags[14] == 1) visible[2] = 0; - if (roomNumber == 35 && flags[17] == 1) + if (_roomNumber == 35 && flags[17] == 1) visible[3] = 1; - if (roomNumber == 35 && flags[15] == 1) + if (_roomNumber == 35 && flags[15] == 1) visible[1] = 0; } else if (currentChapter == 5) { - if (roomNumber == 49 && flags[6] == 1) + if (_roomNumber == 49 && flags[6] == 1) visible[2] = 0; - if (roomNumber == 49 && flags[6] == 0) + if (_roomNumber == 49 && flags[6] == 0) visible[1] = 0; - if (roomNumber == 49 && flags[6] == 1) + if (_roomNumber == 49 && flags[6] == 1) visible[1] = 1; - if (roomNumber == 45 && flags[6] == 1) + if (_roomNumber == 45 && flags[6] == 1) visible[3] = 1; - if (roomNumber == 53 && flags[2] == 1) + if (_roomNumber == 53 && flags[2] == 1) visible[3] = 0; - if (roomNumber == 54 && flags[13] == 1) + if (_roomNumber == 54 && flags[13] == 1) visible[3] = 0; - if (roomNumber == 55 && flags[8] == 1) + if (_roomNumber == 55 && flags[8] == 1) visible[1] = 0; } else if (currentChapter == 6) { - if (roomNumber == 58 && flags[8] == 0) + if (_roomNumber == 58 && flags[8] == 0) isDoor[1] = 0; - if (roomNumber == 58 && flags[8] == 1) + if (_roomNumber == 58 && flags[8] == 1) isDoor[1] = 1; - if (roomNumber == 59) + if (_roomNumber == 59) isDoor[1] = 0; - if (roomNumber == 60) { + if (_roomNumber == 60) { trackDrascula = 0; drasculaX = 155; drasculaY = 69; diff --git a/engines/drascula/rooms.cpp b/engines/drascula/rooms.cpp index 9f707eaa07..25f3da0080 100644 --- a/engines/drascula/rooms.cpp +++ b/engines/drascula/rooms.cpp @@ -1087,7 +1087,7 @@ bool DrasculaEngine::room_102(int fl) { void DrasculaEngine::updateRefresh() { // Check generic updaters for (int i = 0; i < _roomUpdatesSize; i++) { - if (_roomUpdates[i].roomNum == roomNumber) { + if (_roomUpdates[i].roomNum == _roomNumber) { if (_roomUpdates[i].flag < 0 || flags[_roomUpdates[i].flag] == _roomUpdates[i].flagValue) { if (_roomUpdates[i].type == 0) { @@ -1107,25 +1107,25 @@ void DrasculaEngine::updateRefresh() { // Call room-specific updater char rm[20]; - sprintf(rm, "update_%d", roomNumber); + sprintf(rm, "update_%d", _roomNumber); for (uint i = 0; i < _roomHandlers->roomUpdaters.size(); i++) { if (!strcmp(rm, _roomHandlers->roomUpdaters[i]->desc)) { - debug(8, "Calling room updater %d", roomNumber); + debug(8, "Calling room updater %d", _roomNumber); (this->*(_roomHandlers->roomUpdaters[i]->proc))(); break; } } - if (roomNumber == 10) + if (_roomNumber == 10) showMap(); - else if (roomNumber == 45) + else if (_roomNumber == 45) showMap(); } void DrasculaEngine::updateRefresh_pre() { // Check generic preupdaters for (int i = 0; i < _roomPreUpdatesSize; i++) { - if (_roomPreUpdates[i].roomNum == roomNumber) { + if (_roomPreUpdates[i].roomNum == _roomNumber) { if (_roomPreUpdates[i].flag < 0 || flags[_roomPreUpdates[i].flag] == _roomPreUpdates[i].flagValue) { if (_roomPreUpdates[i].type == 0) { @@ -1145,16 +1145,16 @@ void DrasculaEngine::updateRefresh_pre() { // Call room-specific preupdater char rm[20]; - sprintf(rm, "update_%d_pre", roomNumber); + sprintf(rm, "update_%d_pre", _roomNumber); for (uint i = 0; i < _roomHandlers->roomPreupdaters.size(); i++) { if (!strcmp(rm, _roomHandlers->roomPreupdaters[i]->desc)) { - debug(8, "Calling room preupdater %d", roomNumber); + debug(8, "Calling room preupdater %d", _roomNumber); (this->*(_roomHandlers->roomPreupdaters[i]->proc))(); break; } } - if (currentChapter == 1 && roomNumber == 16) + if (currentChapter == 1 && _roomNumber == 16) placeBJ(); } @@ -1577,12 +1577,12 @@ bool DrasculaEngine::checkAction(int fl) { hasAnswer = 0; } else if (currentChapter == 2) { // Note: the original check was strcmp(num_room, "18.alg") - if (pickedObject == 11 && fl == 50 && flags[22] == 0 && roomNumber != 18) + if (pickedObject == 11 && fl == 50 && flags[22] == 0 && _roomNumber != 18) talk(315); else hasAnswer = 0; } else if (currentChapter == 3) { - if (roomNumber == 13) { + if (_roomNumber == 13) { if (room(13, fl)) { showCursor(); return true; @@ -1590,13 +1590,13 @@ bool DrasculaEngine::checkAction(int fl) { } else hasAnswer = 0; } else if (currentChapter == 4) { - if (roomNumber == 28) + if (_roomNumber == 28) talk(178); else if (pickedObject == 8 && fl == 50 && flags[18] == 0) talk(481); else if (pickedObject == 12 && fl == 50 && flags[18] == 0) talk(487); - else if (roomNumber == 21) { + else if (_roomNumber == 21) { if (room(21, fl)) { showCursor(); return true; @@ -1604,7 +1604,7 @@ bool DrasculaEngine::checkAction(int fl) { } else hasAnswer = 0; } else if (currentChapter == 5) { - if (roomNumber == 56) { + if (_roomNumber == 56) { if (room(56, fl)) { showCursor(); return true; @@ -1616,9 +1616,9 @@ bool DrasculaEngine::checkAction(int fl) { talk(308); else if (pickedObject == kVerbLook && fl == 50 && flags[0] == 0) talk(310); - else if (roomNumber == 102) + else if (_roomNumber == 102) room(102, fl); - else if (roomNumber == 60) { + else if (_roomNumber == 60) { if (room(60, fl)) { showCursor(); return true; @@ -1632,7 +1632,7 @@ bool DrasculaEngine::checkAction(int fl) { if (hasAnswer == 0) { hasAnswer = 1; - room(roomNumber, fl); + room(_roomNumber, fl); } if (hasAnswer == 0 && (_hasName || _menuScreen)) @@ -1684,7 +1684,7 @@ void DrasculaEngine::enterRoom(int roomIndex) { TextResourceParser p(stream, DisposeAfterUse::YES); - p.parseInt(roomNumber); + p.parseInt(_roomNumber); p.parseInt(roomMusic); p.parseString(roomDisk); p.parseInt(palLevel); @@ -1778,7 +1778,7 @@ void DrasculaEngine::enterRoom(int roomIndex) { } loadPic(roomDisk, drawSurface3); - loadPic(roomNumber, bgSurface, HALF_PAL); + loadPic(_roomNumber, bgSurface, HALF_PAL); copyBackground(0, 171, 0, 0, OBJWIDTH, OBJHEIGHT, backSurface, drawSurface3); @@ -1808,14 +1808,14 @@ void DrasculaEngine::enterRoom(int roomIndex) { } } - if (roomNumber == 24) { + if (_roomNumber == 24) { for (l = floorY1 - 1; l > 74; l--) { factor_red[l] = (int)(upperLimit - pequegnez); pequegnez = pequegnez + chiquez; } } - if (currentChapter == 5 && roomNumber == 54) { + if (currentChapter == 5 && _roomNumber == 54) { for (l = floorY1 - 1; l > 84; l--) { factor_red[l] = (int)(upperLimit - pequegnez); pequegnez = pequegnez + chiquez; @@ -1853,13 +1853,13 @@ void DrasculaEngine::enterRoom(int roomIndex) { isDoor[7] = 0; if (currentChapter == 2) { - if (roomNumber == 14 && flags[39] == 1) + if (_roomNumber == 14 && flags[39] == 1) roomMusic = 16; - else if (roomNumber == 15 && flags[39] == 1) + else if (_roomNumber == 15 && flags[39] == 1) roomMusic = 16; - if (roomNumber == 14 && flags[5] == 1) + if (_roomNumber == 14 && flags[5] == 1) roomMusic = 0; - else if (roomNumber == 15 && flags[5] == 1) + else if (_roomNumber == 15 && flags[5] == 1) roomMusic = 0; if (previousMusic != roomMusic && roomMusic != 0) @@ -1872,21 +1872,21 @@ void DrasculaEngine::enterRoom(int roomIndex) { } if (currentChapter == 2) { - if (roomNumber == 9 || roomNumber == 2 || roomNumber == 14 || roomNumber == 18) + if (_roomNumber == 9 || _roomNumber == 2 || _roomNumber == 14 || _roomNumber == 18) savedTime = getTime(); } if (currentChapter == 4) { - if (roomNumber == 26) + if (_roomNumber == 26) savedTime = getTime(); } - if (currentChapter == 4 && roomNumber == 24 && flags[29] == 1) + if (currentChapter == 4 && _roomNumber == 24 && flags[29] == 1) animation_7_4(); if (currentChapter == 5) { - if (roomNumber == 45) + if (_roomNumber == 45) hare_se_ve = 0; - if (roomNumber == 49 && flags[7] == 0) { + if (_roomNumber == 49 && flags[7] == 0) { playTalkSequence(4); // sequence 4, chapter 5 } } diff --git a/engines/drascula/saveload.cpp b/engines/drascula/saveload.cpp index 996c9d3f03..61d6f0b4af 100644 --- a/engines/drascula/saveload.cpp +++ b/engines/drascula/saveload.cpp @@ -263,7 +263,7 @@ bool DrasculaEngine::loadGame(int slot) { if (savedChapter != currentChapter) { _currentSaveSlot = slot; currentChapter = savedChapter - 1; - loadedDifferentChapter = 1; + _loadedDifferentChapter = true; delete in; return false; } @@ -283,7 +283,7 @@ bool DrasculaEngine::loadGame(int slot) { takeObject = in->readSint32LE(); pickedObject = in->readSint32LE(); - loadedDifferentChapter = 0; + _loadedDifferentChapter = false; if (!sscanf(currentData, "%d.ald", &roomNum)) { error("Bad save format"); } @@ -383,10 +383,10 @@ bool DrasculaEngine::saveLoadScreen() { updateScreen(); updateEvents(); - if (leftMouseButton == 1) { + if (_leftMouseButton == 1) { // Check if the user has clicked on a save slot for (n = 0; n < NUM_SAVES; n++) { - if (mouseX > 115 && mouseY > 27 + (9 * n) && mouseX < 115 + 175 && mouseY < 27 + 10 + (9 * n)) { + if (_mouseX > 115 && _mouseY > 27 + (9 * n) && _mouseX < 115 + 175 && _mouseY < 27 + 10 + (9 * n)) { selectedSlot = n; selectedName = _saveNames[selectedSlot]; if (selectedName.empty()) { @@ -399,14 +399,14 @@ bool DrasculaEngine::saveLoadScreen() { } // Check if the user has clicked in the text area above the save slots - if (mouseX > 117 && mouseY > 15 && mouseX < 295 && mouseY < 24 && !selectedName.empty()) { + if (_mouseX > 117 && _mouseY > 15 && _mouseX < 295 && _mouseY < 24 && !selectedName.empty()) { selectedName = enterName(selectedName); if (!selectedName.empty()) _saveNames[selectedSlot] = selectedName; // update save name } // Check if the user has clicked a button - if (mouseX > 208 && mouseY > 123 && mouseX < 282 && mouseY < 149) { + if (_mouseX > 208 && _mouseY > 123 && _mouseX < 282 && _mouseY < 149) { // "Save" button if (selectedName.empty()) { print_abc("Please select a slot", 117, 15); @@ -415,14 +415,14 @@ bool DrasculaEngine::saveLoadScreen() { } else { selectVerb(kVerbNone); clearRoom(); - loadPic(roomNumber, bgSurface, HALF_PAL); + loadPic(_roomNumber, bgSurface, HALF_PAL); updateRoom(); updateScreen(); saveGame(selectedSlot + 1, _saveNames[selectedSlot]); return true; } - } else if (mouseX > 125 && mouseY > 123 && mouseX < 199 && mouseY < 149) { + } else if (_mouseX > 125 && _mouseY > 123 && _mouseX < 199 && _mouseY < 149) { // "Load" button if (selectedName.empty()) { print_abc("Please select a slot", 117, 15); @@ -431,19 +431,19 @@ bool DrasculaEngine::saveLoadScreen() { } else { return loadGame(selectedSlot + 1); } - } else if (mouseX > 168 && mouseY > 154 && mouseX < 242 && mouseY < 180) { + } else if (_mouseX > 168 && _mouseY > 154 && _mouseX < 242 && _mouseY < 180) { // "Play" button break; } - } // if (leftMouseButton == 1) + } // if (_leftMouseButton == 1) - leftMouseButton = 0; + _leftMouseButton = 0; delay(10); } selectVerb(kVerbNone); clearRoom(); - loadPic(roomNumber, bgSurface, HALF_PAL); + loadPic(_roomNumber, bgSurface, HALF_PAL); return true; } diff --git a/engines/drascula/sound.cpp b/engines/drascula/sound.cpp index 112f6fd06c..59b5e1d237 100644 --- a/engines/drascula/sound.cpp +++ b/engines/drascula/sound.cpp @@ -36,9 +36,9 @@ namespace Drascula { void DrasculaEngine::updateVolume(Audio::Mixer::SoundType soundType, int prevVolume) { int vol = _mixer->getVolumeForSoundType(soundType) / 16; - if (mouseY < prevVolume && vol < 15) + if (_mouseY < prevVolume && vol < 15) vol++; - if (mouseY > prevVolume && vol > 0) + if (_mouseY > prevVolume && vol > 0) vol--; _mixer->setVolumeForSoundType(soundType, vol * 16); } @@ -78,23 +78,23 @@ void DrasculaEngine::volumeControls() { while (getScan()) ; - if (rightMouseButton == 1) { + if (_rightMouseButton == 1) { // Clear this to avoid going straight to the inventory - rightMouseButton = 0; + _rightMouseButton = 0; delay(100); break; } - if (leftMouseButton == 1) { + if (_leftMouseButton == 1) { delay(100); - if (mouseX > 80 && mouseX < 121) { + if (_mouseX > 80 && _mouseX < 121) { updateVolume(Audio::Mixer::kPlainSoundType, masterVolumeY); } - if (mouseX > 136 && mouseX < 178) { + if (_mouseX > 136 && _mouseX < 178) { updateVolume(Audio::Mixer::kSpeechSoundType, voiceVolumeY); } - if (mouseX > 192 && mouseX < 233) { + if (_mouseX > 192 && _mouseX < 233) { updateVolume(Audio::Mixer::kMusicSoundType, musicVolumeY); } } diff --git a/engines/drascula/talk.cpp b/engines/drascula/talk.cpp index a326852e96..6aabd91c6a 100644 --- a/engines/drascula/talk.cpp +++ b/engines/drascula/talk.cpp @@ -381,11 +381,11 @@ void DrasculaEngine::talk(const char *said, const char *filename) { int face; if (currentChapter == 6) { - if (flags[0] == 0 && roomNumber == 102) { + if (flags[0] == 0 && _roomNumber == 102) { talk_pen(said, filename, 0); return; } - if (flags[0] == 0 && roomNumber == 58) { + if (flags[0] == 0 && _roomNumber == 58) { talk_pen(said, filename, 1); return; } @@ -397,7 +397,7 @@ void DrasculaEngine::talk(const char *said, const char *filename) { } if (currentChapter == 4) { - if (roomNumber == 24 || flags[29] == 0) { + if (_roomNumber == 24 || flags[29] == 0) { color_abc(kColorYellow); } } else { @@ -413,59 +413,59 @@ void DrasculaEngine::talk(const char *said, const char *filename) { updateRefresh_pre(); if (currentChapter == 2) - copyBackground(curX, curY, OBJWIDTH + 1, 0, curWidth, talkHeight - 1, screenSurface, drawSurface3); + copyBackground(curX, curY, OBJWIDTH + 1, 0, curWidth, TALK_HEIGHT - 1, screenSurface, drawSurface3); else copyBackground(curX, curY, OBJWIDTH + 1, 0, (int)(((float)curWidth / 100) * factor_red[MIN(201, curY + curHeight)]), - (int)(((float)(talkHeight - 1) / 100) * factor_red[MIN(201, curY + curHeight)]), + (int)(((float)(TALK_HEIGHT - 1) / 100) * factor_red[MIN(201, curY + curHeight)]), screenSurface, drawSurface3); moveCharacters(); if (currentChapter == 2) { if (!strcmp(menuBackground, "99.alg") || !strcmp(menuBackground, "994.alg")) - copyBackground(OBJWIDTH + 1, 0, curX, curY, curWidth, talkHeight - 1, drawSurface3, screenSurface); + copyBackground(OBJWIDTH + 1, 0, curX, curY, curWidth, TALK_HEIGHT - 1, drawSurface3, screenSurface); } else { copyBackground(OBJWIDTH + 1, 0, curX, curY, (int)(((float)curWidth / 100) * factor_red[MIN(201, curY + curHeight)]), - (int)(((float)(talkHeight - 1) / 100) * factor_red[MIN(201, curY + curHeight)]), + (int)(((float)(TALK_HEIGHT - 1) / 100) * factor_red[MIN(201, curY + curHeight)]), drawSurface3, screenSurface); } if (trackProtagonist == 0) { if (currentChapter == 2) - copyRect(x_talk_izq[face], y_mask_talk, curX + 8, curY - 1, talkWidth, talkHeight, + copyRect(x_talk_izq[face], y_mask_talk, curX + 8, curY - 1, TALK_WIDTH, TALK_HEIGHT, extraSurface, screenSurface); else reduce_hare_chico(x_talk_izq[face], y_mask_talk, curX + (int)((8.0f / 100) * factor_red[MIN(201, curY + curHeight)]), - curY, talkWidth, talkHeight, factor_red[MIN(201, curY + curHeight)], + curY, TALK_WIDTH, TALK_HEIGHT, factor_red[MIN(201, curY + curHeight)], extraSurface, screenSurface); updateRefresh(); } else if (trackProtagonist == 1) { if (currentChapter == 2) - copyRect(x_talk_dch[face], y_mask_talk, curX + 12, curY, talkWidth, talkHeight, + copyRect(x_talk_dch[face], y_mask_talk, curX + 12, curY, TALK_WIDTH, TALK_HEIGHT, extraSurface, screenSurface); else reduce_hare_chico(x_talk_dch[face], y_mask_talk, curX + (int)((12.0f / 100) * factor_red[MIN(201, curY + curHeight)]), - curY, talkWidth, talkHeight, factor_red[MIN(201, curY + curHeight)], extraSurface, screenSurface); + curY, TALK_WIDTH, TALK_HEIGHT, factor_red[MIN(201, curY + curHeight)], extraSurface, screenSurface); updateRefresh(); } else if (trackProtagonist == 2) { if (currentChapter == 2) - copyRect(x_talk_izq[face], y_mask_talk, curX + 12, curY, talkWidth, talkHeight, + copyRect(x_talk_izq[face], y_mask_talk, curX + 12, curY, TALK_WIDTH, TALK_HEIGHT, frontSurface, screenSurface); else reduce_hare_chico(x_talk_izq[face], y_mask_talk, talkOffset + curX + (int)((12.0f / 100) * factor_red[MIN(201, curY + curHeight)]), - curY, talkWidth, talkHeight, factor_red[MIN(201, curY + curHeight)], + curY, TALK_WIDTH, TALK_HEIGHT, factor_red[MIN(201, curY + curHeight)], frontSurface, screenSurface); updateRefresh(); } else if (trackProtagonist == 3) { if (currentChapter == 2) - copyRect(x_talk_dch[face], y_mask_talk, curX + 8, curY, talkWidth, talkHeight, + copyRect(x_talk_dch[face], y_mask_talk, curX + 8, curY, TALK_WIDTH, TALK_HEIGHT, frontSurface, screenSurface); else reduce_hare_chico(x_talk_dch[face], y_mask_talk, talkOffset + curX + (int)((8.0f / 100) * factor_red[MIN(201, curY + curHeight)]), - curY, talkWidth,talkHeight, factor_red[MIN(201, curY + curHeight)], + curY, TALK_WIDTH,TALK_HEIGHT, factor_red[MIN(201, curY + curHeight)], frontSurface, screenSurface); updateRefresh(); } @@ -827,47 +827,47 @@ void DrasculaEngine::talk_sync(const char *said, const char *filename, const cha updateRefresh_pre(); if (currentChapter == 2) - copyBackground(curX, curY, OBJWIDTH + 1, 0, curWidth, talkHeight - 1, screenSurface, drawSurface3); + copyBackground(curX, curY, OBJWIDTH + 1, 0, curWidth, TALK_HEIGHT - 1, screenSurface, drawSurface3); else copyBackground(curX, curY, OBJWIDTH + 1, 0, (int)(((float)curWidth / 100) * factor_red[curY + curHeight]), - (int)(((float)(talkHeight - 1) / 100) * factor_red[curY + curHeight]), screenSurface, drawSurface3); + (int)(((float)(TALK_HEIGHT - 1) / 100) * factor_red[curY + curHeight]), screenSurface, drawSurface3); moveCharacters(); if (currentChapter == 2) { if (curHeight != 56) - copyBackground(OBJWIDTH + 1, 0, curX, curY, curWidth, talkHeight - 1, drawSurface3, screenSurface); + copyBackground(OBJWIDTH + 1, 0, curX, curY, curWidth, TALK_HEIGHT - 1, drawSurface3, screenSurface); } else copyBackground(OBJWIDTH + 1, 0, curX, curY, (int)(((float)curWidth / 100) * factor_red[curY + curHeight]), - (int)(((float)(talkHeight - 1) / 100) * factor_red[curY + curHeight]), drawSurface3, screenSurface); + (int)(((float)(TALK_HEIGHT - 1) / 100) * factor_red[curY + curHeight]), drawSurface3, screenSurface); if (trackProtagonist == 0) { if (currentChapter == 2) - copyRect(x_talk_izq[face], y_mask_talk, curX + 8, curY - 1, talkWidth, talkHeight, extraSurface, screenSurface); + copyRect(x_talk_izq[face], y_mask_talk, curX + 8, curY - 1, TALK_WIDTH, TALK_HEIGHT, extraSurface, screenSurface); else reduce_hare_chico(x_talk_izq[face], y_mask_talk, (int)(curX + (8.0f / 100) * factor_red[curY + curHeight]), - curY, talkWidth, talkHeight, factor_red[curY + curHeight], extraSurface, screenSurface); + curY, TALK_WIDTH, TALK_HEIGHT, factor_red[curY + curHeight], extraSurface, screenSurface); updateRefresh(); } else if (trackProtagonist == 1) { if (currentChapter == 2) - copyRect(x_talk_dch[face], y_mask_talk, curX + 12, curY, talkWidth, talkHeight, extraSurface, screenSurface); + copyRect(x_talk_dch[face], y_mask_talk, curX + 12, curY, TALK_WIDTH, TALK_HEIGHT, extraSurface, screenSurface); else reduce_hare_chico(x_talk_dch[face], y_mask_talk, (int)(curX + (12.0f / 100) * factor_red[curY + curHeight]), - curY, talkWidth, talkHeight, factor_red[curY + curHeight], extraSurface, screenSurface); + curY, TALK_WIDTH, TALK_HEIGHT, factor_red[curY + curHeight], extraSurface, screenSurface); updateRefresh(); } else if (trackProtagonist == 2) { if (currentChapter == 2) - copyRect(x_talk_izq[face], y_mask_talk, curX + 12, curY, talkWidth, talkHeight, frontSurface, screenSurface); + copyRect(x_talk_izq[face], y_mask_talk, curX + 12, curY, TALK_WIDTH, TALK_HEIGHT, frontSurface, screenSurface); else reduce_hare_chico(x_talk_izq[face], y_mask_talk, (int)(talkOffset + curX + (12.0f / 100) * factor_red[curY + curHeight]), curY, - talkWidth, talkHeight, factor_red[curY + curHeight], frontSurface, screenSurface); + TALK_WIDTH, TALK_HEIGHT, factor_red[curY + curHeight], frontSurface, screenSurface); updateRefresh(); } else if (trackProtagonist == 3) { if (currentChapter == 2) - copyRect(x_talk_dch[face], y_mask_talk, curX + 8, curY, talkWidth, talkHeight, frontSurface, screenSurface); + copyRect(x_talk_dch[face], y_mask_talk, curX + 8, curY, TALK_WIDTH, TALK_HEIGHT, frontSurface, screenSurface); else reduce_hare_chico(x_talk_dch[face], y_mask_talk, (int)(talkOffset + curX + (8.0f / 100) * factor_red[curY + curHeight]), curY, - talkWidth, talkHeight, factor_red[curY + curHeight], frontSurface, screenSurface); + TALK_WIDTH, TALK_HEIGHT, factor_red[curY + curHeight], frontSurface, screenSurface); updateRefresh(); } diff --git a/engines/mohawk/myst.cpp b/engines/mohawk/myst.cpp index 8140817eb3..975c6c2a21 100644 --- a/engines/mohawk/myst.cpp +++ b/engines/mohawk/myst.cpp @@ -418,6 +418,7 @@ void MohawkEngine_Myst::changeToStack(uint16 stack, uint16 card, uint16 linkSrcS _sound->stopSound(); _sound->stopBackgroundMyst(); + _video->stopVideos(); if (linkSrcSound) _sound->playSoundBlocking(linkSrcSound); diff --git a/engines/mohawk/myst_stacks/myst.cpp b/engines/mohawk/myst_stacks/myst.cpp index f17d765c99..dc5f433ce7 100644 --- a/engines/mohawk/myst_stacks/myst.cpp +++ b/engines/mohawk/myst_stacks/myst.cpp @@ -691,6 +691,7 @@ void Myst::toggleVar(uint16 var) { else _state.courtyardImageBoxes |= mask; } + break; case 41: // Vault white page if (_globals.ending != 4) { if (_dockVaultState == 1) { diff --git a/engines/mortevielle/actions.cpp b/engines/mortevielle/actions.cpp index 2a66100e17..b68dd48b0f 100644 --- a/engines/mortevielle/actions.cpp +++ b/engines/mortevielle/actions.cpp @@ -91,31 +91,41 @@ void MortevielleEngine::fctMove() { oldMenu = (_menu._moveMenu[menuChoice]._menuId << 8) | _menu._moveMenu[menuChoice]._actionId; } - if (_coreVar._currPlace == MOUNTAIN) { + switch (_coreVar._currPlace) { + case MOUNTAIN: if (menuChoice == 1) gotoManorFront(); else if (menuChoice == 2) checkManorDistance(); _menu.setDestinationText(_coreVar._currPlace); return; - } else if (_coreVar._currPlace == INSIDE_WELL) { + case INSIDE_WELL: if (menuChoice == 1) floodedInWell(); else if (menuChoice == 2) gotoManorBack(); _menu.setDestinationText(_coreVar._currPlace); return; - } else if ((_coreVar._currPlace == BUREAU) && (menuChoice == 1)) - menuChoice = 6; - else if (_coreVar._currPlace == KITCHEN) { + case BUREAU: + if (menuChoice == 1) + menuChoice = 6; + break; + case KITCHEN: if (menuChoice == 2) menuChoice = 6; else if (menuChoice == 5) menuChoice = 16; - } else if ((_coreVar._currPlace == CELLAR) && (menuChoice == 3)) - menuChoice = 6; - else if (((_coreVar._currPlace == LANDING) || (_coreVar._currPlace == ROOM26)) && (menuChoice == 4)) - menuChoice = 6; + break; + case CELLAR: + if (menuChoice == 3) + menuChoice = 6; + break; + case LANDING: + case ROOM26: + if (menuChoice == 4) + menuChoice = 6; + break; + } if ((_coreVar._currPlace > MOUNTAIN) && (_coreVar._currPlace != ROOM26)) menuChoice += 10; @@ -132,32 +142,40 @@ void MortevielleEngine::fctMove() { else if ((_coreVar._currPlace == WELL) && (menuChoice > 13) && (menuChoice != 17)) menuChoice = 15; - if (menuChoice == 1) + switch (menuChoice) { + case 1: _coreVar._currPlace = BUREAU; - else if (menuChoice == 2) + break; + case 2: _coreVar._currPlace = KITCHEN; - else if (menuChoice == 3) + break; + case 3: _coreVar._currPlace = CELLAR; - else if (menuChoice == 4) + break; + case 4: _coreVar._currPlace = LANDING; - else if (menuChoice == 5) - menuChoice = 12; - else if (menuChoice == 6) - menuChoice = 11; - - if (menuChoice == 11) - gotoDiningRoom(); - else if (menuChoice == 12) + break; + case 5: + case 12: gotoManorFront(); - else if (menuChoice == 13) + break; + case 6: + case 11: + gotoDiningRoom(); + break; + case 13: _coreVar._currPlace = CHAPEL; - else if (menuChoice == 14) + break; + case 14: _coreVar._currPlace = WELL; - else if (menuChoice == 15) + break; + case 15: checkManorDistance(); - else if (menuChoice == 16) + break; + case 16: gotoManorBack(); - else if (menuChoice == 17) { + break; + case 17: if ((_coreVar._wellObjectId != 120) && (_coreVar._wellObjectId != 140)) _crep = 997; else if (_coreVar._wellObjectId == 120) @@ -169,7 +187,9 @@ void MortevielleEngine::fctMove() { _coreVar._currPlace = INSIDE_WELL; prepareDisplayText(); } + break; } + if ((menuChoice < 5) || (menuChoice == 13) || (menuChoice == 14)) prepareDisplayText(); resetRoomVariables(_coreVar._currPlace); @@ -503,9 +523,12 @@ void MortevielleEngine::fctSearch() { setCoordinates(7); if (_num != 0) { int i; - for (i = 1; (i <= 6) && (_num != _openObjects[i]); i++) - ; - if (_num == _openObjects[i]) { + for (i = 1; i <= 6; i++) { + if (_num == _openObjects[i]) + break; + } + + if (i <= 6) { if (_currBitIndex > 0) _coreVar._faithScore += 3; @@ -584,7 +607,7 @@ void MortevielleEngine::fctOpen() { if (_caff == ROOM26) { if (_roomDoorId != OWN_ROOM) { - _currAction = OPCODE_ENTER; + _currAction = _menu._opcodeEnter; _syn = true; } else _crep = 997; @@ -606,9 +629,20 @@ void MortevielleEngine::fctOpen() { _coreVar._faithScore += 2; ++_openObjCount; int i; - for (i = 1; (i <= 6) && (_openObjects[i] != 0) && (_openObjects[i] != _num); i++) - ; - if (_openObjects[i] != _num) { + for (i = 1; (i <= 6); i++) { + if ((_openObjects[i] == 0) || (_openObjects[i] == _num)) + break; + } + + if (i > 6) { + warning("Unexpected action: Too many open objects"); + return; + } + + if (_openObjects[i] == _num) + // display "Already Opened" + _crep = 18; + else { if (!( ((_num == 3) && ((_coreVar._currPlace == OWN_ROOM) || (_coreVar._currPlace == JULIA_ROOM) || (_coreVar._currPlace == BLUE_ROOM) @@ -641,9 +675,7 @@ void MortevielleEngine::fctOpen() { _crep = _tabdon[kAouvr + (tmpPlace * 7) + _num - 1]; if (_crep == 254) _crep = 999; - } else - // display "Already Opened" - _crep = 18; + } } } @@ -702,10 +734,10 @@ void MortevielleEngine::fctPlace() { _soundManager.startSpeech(6, -9, 1); // Do you want to enter the hidden passage? - int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + int answer = _dialogManager.show(getEngineString(S_YES_NO)); if (answer == 1) { Common::String alertTxt = getString(582); - _dialogManager.show(alertTxt, 1); + _dialogManager.show(alertTxt); bool enterPassageFl = _dialogManager.showKnowledgeCheck(); _mouse.hideMouse(); @@ -732,7 +764,7 @@ void MortevielleEngine::fctPlace() { displayAnimFrame(1, 2); displayAnimFrame(1, 1); alertTxt = getString(577); - _dialogManager.show(alertTxt, 1); + _dialogManager.show(alertTxt); displayAnimFrame(2, 1); _crep = 166; } @@ -801,7 +833,7 @@ void MortevielleEngine::fctTurn() { if ((_coreVar._currPlace == ATTIC) && (_coreVar._atticRodHoleObjectId == 159) && (_coreVar._atticBallHoleObjectId == 141)) { handleDescriptionText(2, 167); _soundManager.startSpeech(7, 9, 1); - int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + int answer = _dialogManager.show(getEngineString(S_YES_NO)); if (answer == 1) _endGame = true; else @@ -811,7 +843,7 @@ void MortevielleEngine::fctTurn() { handleDescriptionText(2, 175); clearVerbBar(); _soundManager.startSpeech(6, -9, 1); - int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + int answer = _dialogManager.show(getEngineString(S_YES_NO)); if (answer == 1) { _coreVar._currPlace = CRYPT; prepareDisplayText(); @@ -884,9 +916,12 @@ void MortevielleEngine::fctClose() { setCoordinates(7); if (_num != 0) { int i; - for (i = 1; (i <= 6) && (_num != _openObjects[i]); ++i) - ; - if (_num == _openObjects[i]) { + for (i = 1; i <= 6; ++i) { + if (_num == _openObjects[i]) + break; + } + + if (i <= 6) { displayAnimFrame(2, _num); _crep = 998; _openObjects[i] = 0; @@ -914,7 +949,7 @@ void MortevielleEngine::fctKnock() { displayTextInVerbBar(getEngineString(S_HIT)); if (_coreVar._currPlace == LANDING) { - _dialogManager.show(getEngineString(S_BEFORE_USE_DEP_MENU), 1); + _dialogManager.show(getEngineString(S_BEFORE_USE_DEP_MENU)); return; } @@ -979,9 +1014,12 @@ void MortevielleEngine::fctSelfPut() { _crep = 997; else { int i; - for (i = 1; (i <= 6) && (_num != _openObjects[i]); i++) - ; - if (_num == _openObjects[i]) { + for (i = 1; i <= 6; i++) { + if (_num == _openObjects[i]) + break; + } + + if (i <= 6) { _curSearchObjId = objId; _crep = 999; } else @@ -1002,12 +1040,15 @@ void MortevielleEngine::fctSelfPut() { if (_num == 1) { if (_coreVar._atticBallHoleObjectId != 0) _crep = 188; - else + else { _coreVar._atticBallHoleObjectId = _coreVar._selectedObjectId; + displayAnimFrame(1, 7); + } } else if (_coreVar._atticRodHoleObjectId != 0) { _crep = 188; } else { _coreVar._atticRodHoleObjectId = _coreVar._selectedObjectId; + displayAnimFrame(1, 6); } } @@ -1220,7 +1261,7 @@ void MortevielleEngine::fctSleep() { if (hour > 23) hour = 0; prepareRoom(); - answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + answer = _dialogManager.show(getEngineString(S_YES_NO)); _anyone = false; } while (answer != 1); _crep = 998; @@ -1310,7 +1351,7 @@ void MortevielleEngine::fctWait() { return; } handleDescriptionText(2, 102); - answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + answer = _dialogManager.show(getEngineString(S_YES_NO)); } while (answer != 2); _crep = 998; if (!_anyone) @@ -1408,7 +1449,7 @@ void MortevielleEngine::fctDiscuss() { return; _mouse.getMousePosition(x, y, click); - x *= (3 - _resolutionScaler); + x *= (3 - kResolutionScaler); if (x > 319) cx = 41; else @@ -1626,7 +1667,7 @@ void MortevielleEngine::askRestart() { _day = 0; handleDescriptionText(2, 180); - int answer = _dialogManager.show(getEngineString(S_YES_NO), 1); + int answer = _dialogManager.show(getEngineString(S_YES_NO)); _quitGame = (answer != 1); } diff --git a/engines/mortevielle/detection.cpp b/engines/mortevielle/detection.cpp index 7d0f3c4d88..ee9cb40c99 100644 --- a/engines/mortevielle/detection.cpp +++ b/engines/mortevielle/detection.cpp @@ -30,12 +30,17 @@ namespace Mortevielle { struct MortevielleGameDescription { ADGameDescription desc; Common::Language originalLanguage; + uint8 dataFeature; }; uint32 MortevielleEngine::getGameFlags() const { return _gameDescription->desc.flags; } Common::Language MortevielleEngine::getLanguage() const { return _gameDescription->desc.language; } +Common::Language MortevielleEngine::getOriginalLanguage() const { return _gameDescription->originalLanguage; } + +bool MortevielleEngine::useOriginalData() const { return _gameDescription->dataFeature == kUseOriginalData; } + } static const PlainGameDescriptor MortevielleGame[] = { @@ -51,6 +56,9 @@ public: MortevielleGame) { _md5Bytes = 512; _singleid = "mortevielle"; + // Use kADFlagUseExtraAsHint to distinguish between original and improved versions + // (i.e. use or not of the game data file). + _flags = kADFlagUseExtraAsHint; } virtual const char *getName() const { return "Mortevielle"; diff --git a/engines/mortevielle/detection_tables.h b/engines/mortevielle/detection_tables.h index 9bb5fbea87..8d0cd5630c 100644 --- a/engines/mortevielle/detection_tables.h +++ b/engines/mortevielle/detection_tables.h @@ -37,7 +37,7 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = { Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0() - }, Common::FR_FRA + }, Common::FR_FRA, kUseOriginalData }, // German { @@ -53,7 +53,24 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = { Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0() - }, Common::DE_DEU + }, Common::DE_DEU, kUseOriginalData + }, + + // German, improved translation + { + { + "mortevielle", + "Improved Translation", + { + {"menual.mor", 0, "792aea282b07a1d74c4a4abeabc90c19", 144}, + {"dxx.mor", 0, "949e68e829ecd5ad29e36a00347a9e7e", 207744}, + AD_LISTEND + }, + Common::DE_DEU, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO0() + }, Common::DE_DEU, kUseEngineDataFile }, // DOS English version doesn't exist. Technically, they are French or German versions, @@ -73,7 +90,7 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = { Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0() - }, Common::FR_FRA + }, Common::FR_FRA, kUseEngineDataFile }, // English on top of German version @@ -90,10 +107,10 @@ static const MortevielleGameDescription MortevielleGameDescriptions[] = { Common::kPlatformDOS, ADGF_NO_FLAGS, GUIO0() - }, Common::DE_DEU + }, Common::DE_DEU, kUseEngineDataFile }, - { AD_TABLE_END_MARKER , Common::EN_ANY} + { AD_TABLE_END_MARKER , Common::EN_ANY, kUseEngineDataFile} }; } // End of namespace Mortevielle diff --git a/engines/mortevielle/dialogs.cpp b/engines/mortevielle/dialogs.cpp index abaf38c59b..9a2ade60ab 100644 --- a/engines/mortevielle/dialogs.cpp +++ b/engines/mortevielle/dialogs.cpp @@ -39,7 +39,7 @@ namespace Mortevielle { * Alert function - Show * @remarks Originally called 'do_alert' */ -int DialogManager::show(const Common::String &msg, int n) { +int DialogManager::show(const Common::String &msg) { // Make a copy of the current screen surface for later restore _vm->_backgroundSurface.copyFrom(_vm->_screenSurface); @@ -57,13 +57,12 @@ int DialogManager::show(const Common::String &msg, int n) { decodeAlertDetails(msg, caseNumb, lignNumb, colNumb, alertStr, caseStr); - int i = 0; Common::Point curPos; if (alertStr == "") { drawAlertBox(10, 5, colNumb); } else { drawAlertBox(8, 7, colNumb); - i = 0; + int i = 0; _vm->_screenSurface._textPos.y = 70; do { curPos.x = 320; @@ -71,10 +70,7 @@ int DialogManager::show(const Common::String &msg, int n) { while ((alertStr[i + 1] != '\174') && (alertStr[i + 1] != '\135')) { ++i; displayStr += alertStr[i]; - if (_vm->_resolutionScaler == 2) - curPos.x -= 3; - else - curPos.x -= 5; + curPos.x -= 3; } _vm->_screenSurface.putxy(curPos.x, _vm->_screenSurface._textPos.y); _vm->_screenSurface._textPos.y += 6; @@ -95,12 +91,12 @@ int DialogManager::show(const Common::String &msg, int n) { int limit[3][3]; memset(&limit[0][0], 0, sizeof(int) * 3 * 3); - limit[1][1] = ((uint)(coldep) / 2) * _vm->_resolutionScaler; + limit[1][1] = ((uint)(coldep) / 2) * kResolutionScaler; limit[1][2] = limit[1][1] + 40; if (caseNumb == 1) { limit[2][1] = limit[2][2]; } else { - limit[2][1] = ((uint)(320 + ((uint)esp >> 1)) / 2) * _vm->_resolutionScaler; + limit[2][1] = ((uint)(320 + ((uint)esp >> 1)) / 2) * kResolutionScaler; limit[2][2] = (limit[2][1]) + 40; } _vm->_mouse.showMouse(); @@ -168,10 +164,10 @@ int DialogManager::show(const Common::String &msg, int n) { _vm->setMouseClick(false); _vm->_mouse.hideMouse(); if (!test3) { - id = n; - setPosition(n, coldep, esp); + id = 1; + setPosition(1, coldep, esp); Common::String tmp4(" "); - tmp4 += buttonStr[n]; + tmp4 += buttonStr[1]; tmp4 += " "; _vm->_screenSurface.drawString(tmp4, 1); } @@ -221,10 +217,7 @@ void DialogManager::decodeAlertDetails(Common::String inputStr, int &choiceNumb, } choiceListStr = Common::String(inputStr.c_str() + i); - if (_vm->_resolutionScaler == 2) - col *= 6; - else - col *= 10; + col *= 6; } void DialogManager::setPosition(int ji, int coldep, int esp) { @@ -235,13 +228,13 @@ void DialogManager::setPosition(int ji, int coldep, int esp) { * Alert function - Draw Alert Box * @remarks Originally called 'fait_boite' */ -void DialogManager::drawAlertBox(int lidep, int nli, int tx) { - if (tx > 640) - tx = 640; - int x = 320 - ((uint)tx / 2); - int y = (lidep - 1) * 8; - int xx = x + tx; - int yy = y + (nli * 8); +void DialogManager::drawAlertBox(int firstLine, int lineNum, int width) { + if (width > 640) + width = 640; + int x = 320 - ((uint)width / 2); + int y = (firstLine - 1) * 8; + int xx = x + width; + int yy = y + (lineNum * 8); _vm->_screenSurface.fillRect(15, Common::Rect(x, y, xx, yy)); _vm->_screenSurface.fillRect(0, Common::Rect(x, y + 2, xx, y + 4)); _vm->_screenSurface.fillRect(0, Common::Rect(x, yy - 4, xx, yy - 2)); @@ -302,11 +295,7 @@ bool DialogManager::showKnowledgeCheck() { _vm->_mouse.hideMouse(); _vm->clearScreen(); _vm->_mouse.showMouse(); - int dialogHeight; - if (_vm->_resolutionScaler == 1) - dialogHeight = 29; - else - dialogHeight = 23; + int dialogHeight = 23; _vm->_screenSurface.fillRect(15, Common::Rect(0, 14, 630, dialogHeight)); Common::String tmpStr = _vm->getString(textIndexArr[indx]); _vm->_text.displayStr(tmpStr, 20, 15, 100, 2, 0); @@ -335,7 +324,7 @@ bool DialogManager::showKnowledgeCheck() { } for (int j = 1; j <= lastOption - firstOption + 1; ++j) { - coor[j]._rect = Common::Rect(45 * _vm->_resolutionScaler, 27 + j * 8, (maxLength * 3 + 55) * _vm->_resolutionScaler, 34 + j * 8); + coor[j]._rect = Common::Rect(45 * kResolutionScaler, 27 + j * 8, (maxLength * 3 + 55) * kResolutionScaler, 34 + j * 8); coor[j]._enabled = true; while ((int)choiceArray[j].size() < maxLength) { @@ -343,11 +332,7 @@ bool DialogManager::showKnowledgeCheck() { } } coor[lastOption - firstOption + 2]._enabled = false; - int rep; - if (_vm->_resolutionScaler == 1) - rep = 10; - else - rep = 6; + int rep = 6; _vm->_screenSurface.drawBox(80, 33, 40 + (maxLength * rep), (lastOption - firstOption) * 8 + 16, 15); rep = 0; @@ -431,12 +416,6 @@ void DialogManager::checkForF8(int SpeechNum, bool drawFrame2Fl) { _vm->_key = waitForF3F8(); if (_vm->shouldQuit()) return; - - if (_vm->_newGraphicalDevice != _vm->_currGraphicalDevice) { - _vm->_currGraphicalDevice = _vm->_newGraphicalDevice; - _vm->clearScreen(); - displayIntroScreen(drawFrame2Fl); - } } while (_vm->_key != 66); // keycode for F8 } @@ -483,7 +462,7 @@ void DialogManager::displayIntroFrame2() { _vm->displayPicture(&_vm->_curAnim[_vm->_crep], 63, 12); _vm->_crep = _vm->getAnimOffset(2, 1); _vm->displayPicture(&_vm->_curAnim[_vm->_crep], 63, 12); - _vm->_largestClearScreen = (_vm->_resolutionScaler == 1); + _vm->_largestClearScreen = false; _vm->handleDescriptionText(2, kDialogStringIndex + 143); } diff --git a/engines/mortevielle/dialogs.h b/engines/mortevielle/dialogs.h index af667e40c5..3f30851960 100644 --- a/engines/mortevielle/dialogs.h +++ b/engines/mortevielle/dialogs.h @@ -48,11 +48,11 @@ private: void decodeAlertDetails(Common::String inputStr, int &choiceNumb, int &lineNumb, int &col, Common::String &choiceStr, Common::String &choiceListStr); void setPosition(int ji, int coldep, int esp); - void drawAlertBox(int lidep, int nli, int tx); + void drawAlertBox(int firstLine, int lineNum, int width); void setButtonText(Common::String c, int coldep, int nbcase, Common::String *str, int esp); public: void setParent(MortevielleEngine *vm); - int show(const Common::String &msg, int n); + int show(const Common::String &msg); void drawF3F8(); void checkForF8(int SpeechNum, bool drawFrame2Fl); int waitForF3F8(); diff --git a/engines/mortevielle/graphics.cpp b/engines/mortevielle/graphics.cpp index 059f5a9be8..daf7926438 100644 --- a/engines/mortevielle/graphics.cpp +++ b/engines/mortevielle/graphics.cpp @@ -1015,11 +1015,6 @@ void ScreenSurface::writeCharacter(const Common::Point &pt, unsigned char ch, in * simulate the original 640x400 surface, all Y values have to be doubled */ void ScreenSurface::drawBox(int x, int y, int dx, int dy, int col) { - if (_vm->_resolutionScaler == 1) { - x = (uint)x >> 1; - dx = (uint)dx >> 1; - } - Graphics::Surface destSurface = lockArea(Common::Rect(x, y * 2, x + dx, (y + dy) * 2)); destSurface.hLine(0, 0, dx, col); @@ -1078,11 +1073,7 @@ void ScreenSurface::drawString(const Common::String &l, int command) { _vm->_mouse.hideMouse(); Common::Point pt = _textPos; - int charWidth; - if (_vm->_resolutionScaler == 2) - charWidth = 6; - else - charWidth = 10; + int charWidth = 6; int x = pt.x + charWidth * l.size(); int color = 0; @@ -1118,7 +1109,7 @@ void ScreenSurface::drawString(const Common::String &l, int command) { * Gets the width in pixels of the specified string */ int ScreenSurface::getStringWidth(const Common::String &s) { - int charWidth = (_vm->_resolutionScaler == 2) ? 6 : 10; + int charWidth = 6; return s.size() * charWidth; } @@ -1165,13 +1156,7 @@ void ScreenSurface::drawLine(int x, int y, int xx, int yy, int coul) { * @remarks Originally called 'paint_rect' */ void ScreenSurface::drawRectangle(int x, int y, int dx, int dy) { - int co; - - if (_vm->_currGraphicalDevice == MODE_CGA) - co = 3; - else - co = 11; - _vm->_screenSurface.fillRect(co, Common::Rect(x, y, x + dx, y + dy)); + _vm->_screenSurface.fillRect(11, Common::Rect(x, y, x + dx, y + dy)); } void ScreenSurface::setParent(MortevielleEngine *vm) { diff --git a/engines/mortevielle/menu.cpp b/engines/mortevielle/menu.cpp index f32c551ddb..641a527c98 100644 --- a/engines/mortevielle/menu.cpp +++ b/engines/mortevielle/menu.cpp @@ -48,34 +48,164 @@ const byte menuConstants[8][4] = { {62, 46, 13, 10} }; +Menu::Menu() { + _opcodeAttach = _opcodeWait = _opcodeForce = _opcodeSleep = OPCODE_NONE; + _opcodeListen = _opcodeEnter = _opcodeClose = _opcodeSearch = OPCODE_NONE; + _opcodeKnock = _opcodeScratch = _opcodeRead = _opcodeEat = OPCODE_NONE; + _opcodePlace = _opcodeOpen = _opcodeTake = _opcodeLook = OPCODE_NONE; + _opcodeSmell = _opcodeSound = _opcodeLeave = _opcodeLift = OPCODE_NONE; + _opcodeTurn = _opcodeSHide = _opcodeSSearch = _opcodeSRead = OPCODE_NONE; + _opcodeSPut = _opcodeSLook = OPCODE_NONE; +} + +void Menu::readVerbNums(Common::File &f, int dataSize) { + // Figure out what language Id is needed + byte desiredLanguageId; + switch(_vm->getLanguage()) { + case Common::EN_ANY: + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + case Common::FR_FRA: + desiredLanguageId = MORTDAT_LANG_FRENCH; + break; + case Common::DE_DEU: + desiredLanguageId = MORTDAT_LANG_GERMAN; + break; + default: + warning("Language not supported, switching to English"); + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + } + // Read in the language + byte languageId = f.readByte(); + --dataSize; + + // If the language isn't correct, then skip the entire block + if (languageId != desiredLanguageId) { + f.skip(dataSize); + return; + } + + assert(dataSize == 52); + _opcodeAttach = f.readUint16LE(); + _opcodeWait = f.readUint16LE(); + _opcodeForce = f.readUint16LE(); + _opcodeSleep = f.readUint16LE(); + _opcodeListen = f.readUint16LE(); + _opcodeEnter = f.readUint16LE(); + _opcodeClose = f.readUint16LE(); + _opcodeSearch = f.readUint16LE(); + _opcodeKnock = f.readUint16LE(); + _opcodeScratch = f.readUint16LE(); + _opcodeRead = f.readUint16LE(); + _opcodeEat = f.readUint16LE(); + _opcodePlace = f.readUint16LE(); + _opcodeOpen = f.readUint16LE(); + _opcodeTake = f.readUint16LE(); + _opcodeLook = f.readUint16LE(); + _opcodeSmell = f.readUint16LE(); + _opcodeSound = f.readUint16LE(); + _opcodeLeave = f.readUint16LE(); + _opcodeLift = f.readUint16LE(); + _opcodeTurn = f.readUint16LE(); + _opcodeSHide = f.readUint16LE(); + _opcodeSSearch = f.readUint16LE(); + _opcodeSRead = f.readUint16LE(); + _opcodeSPut = f.readUint16LE(); + _opcodeSLook = f.readUint16LE(); + + _actionMenu[0]._menuId = OPCODE_NONE >> 8; + _actionMenu[0]._actionId = OPCODE_NONE & 0xFF; + + _actionMenu[1]._menuId = _opcodeSHide >> 8; + _actionMenu[1]._actionId = _opcodeSHide & 0xFF; + + _actionMenu[2]._menuId = _opcodeAttach >> 8; + _actionMenu[2]._actionId = _opcodeAttach & 0xFF; + + _actionMenu[3]._menuId = _opcodeForce >> 8; + _actionMenu[3]._actionId = _opcodeForce & 0xFF; + + _actionMenu[4]._menuId = _opcodeSleep >> 8; + _actionMenu[4]._actionId = _opcodeSleep & 0xFF; + + _actionMenu[5]._menuId = _opcodeEnter >> 8; + _actionMenu[5]._actionId = _opcodeEnter & 0xFF; + + _actionMenu[6]._menuId = _opcodeClose >> 8; + _actionMenu[6]._actionId = _opcodeClose & 0xFF; + + _actionMenu[7]._menuId = _opcodeKnock >> 8; + _actionMenu[7]._actionId = _opcodeKnock & 0xFF; + + _actionMenu[8]._menuId = _opcodeEat >> 8; + _actionMenu[8]._actionId = _opcodeEat & 0xFF; + + _actionMenu[9]._menuId = _opcodePlace >> 8; + _actionMenu[9]._actionId = _opcodePlace & 0xFF; + + _actionMenu[10]._menuId = _opcodeOpen >> 8; + _actionMenu[10]._actionId = _opcodeOpen & 0xFF; + + _actionMenu[11]._menuId = _opcodeLeave >> 8; + _actionMenu[11]._actionId = _opcodeLeave & 0xFF; +} + /** * Setup a menu's contents * @remarks Originally called 'menut' */ -void Menu::setText(int menuId, int actionId, Common::String name) { +void Menu::setText(MenuItem item, Common::String name) { Common::String s = name; - while (s.size() < 22) - s += ' '; - - switch (menuId) { + switch (item._menuId) { case MENU_INVENTORY: - if (actionId != 7) { - _inventoryStringArray[actionId] = s; - _inventoryStringArray[actionId].insertChar(' ', 0); + if (item._actionId != 7) { + while (s.size() < 22) + s += ' '; + + _inventoryStringArray[item._actionId] = s; + _inventoryStringArray[item._actionId].insertChar(' ', 0); } break; - case MENU_MOVE: - _moveStringArray[actionId] = s; + case MENU_MOVE: { + // If the first character isn't '*' or ' ' then it's missing a heading space + char c = s[0]; + if (c != '*' && c != ' ') + s.insertChar(' ', 0); + + while (s.size() < 22) + s += ' '; + + _moveStringArray[item._actionId] = s; + } break; - case MENU_ACTION: - _actionStringArray[actionId] = s; + case MENU_ACTION: { + // If the first character isn't '*' or ' ' then it's missing a heading space + char c = s[0]; + if (c != '*' && c != ' ') + s.insertChar(' ', 0); + + while (s.size() < 10) + s += ' '; + + _actionStringArray[item._actionId] = s; + } break; - case MENU_SELF: - _selfStringArray[actionId] = s; + case MENU_SELF: { + // If the first character isn't '*' or ' ' then it's missing a heading space + char c = s[0]; + if (c != '*' && c != ' ') + s.insertChar(' ', 0); + + while (s.size() < 10) + s += ' '; + + _selfStringArray[item._actionId] = s; + } break; case MENU_DISCUSS: - _discussStringArray[actionId] = s; + _discussStringArray[item._actionId] = s; break; default: break; @@ -89,7 +219,7 @@ void Menu::setText(int menuId, int actionId, Common::String name) { void Menu::setDestinationText(int roomId) { Common::String nomp; - if (roomId == 26) + if (roomId == ROOM26) roomId = LANDING; int destinationId = 0; @@ -97,11 +227,11 @@ void Menu::setDestinationText(int roomId) { nomp = _vm->getString(_vm->_destinationArray[destinationId][roomId] + kMenuPlaceStringIndex); while (nomp.size() < 20) nomp += ' '; - setText(_moveMenu[destinationId + 1]._menuId, _moveMenu[destinationId + 1]._actionId, nomp); + setText(_moveMenu[destinationId + 1], nomp); } nomp = "* "; for (int i = 7; i >= destinationId + 1; --i) - setText(_moveMenu[i]._menuId, _moveMenu[i]._actionId, nomp); + setText(_moveMenu[i], nomp); } /** @@ -109,26 +239,26 @@ void Menu::setDestinationText(int roomId) { * @param menuId Menu number * @param actionId Item index */ -void Menu::disableMenuItem(int menuId, int actionId) { - switch (menuId) { +void Menu::disableMenuItem(MenuItem item) { + switch (item._menuId) { case MENU_INVENTORY: - if (actionId > 6) { - _inventoryStringArray[actionId].setChar('<', 0); - _inventoryStringArray[actionId].setChar('>', 21); + if (item._actionId > 6) { + _inventoryStringArray[item._actionId].setChar('<', 0); + _inventoryStringArray[item._actionId].setChar('>', 21); } else - _inventoryStringArray[actionId].setChar('*', 0); + _inventoryStringArray[item._actionId].setChar('*', 0); break; case MENU_MOVE: - _moveStringArray[actionId].setChar('*', 0); + _moveStringArray[item._actionId].setChar('*', 0); break; case MENU_ACTION: - _actionStringArray[actionId].setChar('*', 0); + _actionStringArray[item._actionId].setChar('*', 0); break; case MENU_SELF: - _selfStringArray[actionId].setChar('*', 0); + _selfStringArray[item._actionId].setChar('*', 0); break; case MENU_DISCUSS: - _discussStringArray[actionId].setChar('*', 0); + _discussStringArray[item._actionId].setChar('*', 0); break; default: break; @@ -141,25 +271,23 @@ void Menu::disableMenuItem(int menuId, int actionId) { * @param actionId Item index * @remarks Originally called menu_enable */ -void Menu::enableMenuItem(int menuId, int actionId) { - switch (menuId) { +void Menu::enableMenuItem(MenuItem item) { + switch (item._menuId) { case MENU_INVENTORY: - _inventoryStringArray[actionId].setChar(' ', 0); - _inventoryStringArray[actionId].setChar(' ', 21); + _inventoryStringArray[item._actionId].setChar(' ', 0); + _inventoryStringArray[item._actionId].setChar(' ', 21); break; case MENU_MOVE: - _moveStringArray[actionId].setChar(' ', 0); + _moveStringArray[item._actionId].setChar(' ', 0); break; case MENU_ACTION: - _actionStringArray[actionId].setChar(' ', 0); + _actionStringArray[item._actionId].setChar(' ', 0); break; case MENU_SELF: - _selfStringArray[actionId].setChar(' ', 0); - // The original sets two times the same value. Skipped - // _selfStringArray[l].setChar(' ', 0); + _selfStringArray[item._actionId].setChar(' ', 0); break; case MENU_DISCUSS: - _discussStringArray[actionId].setChar(' ', 0); + _discussStringArray[item._actionId].setChar(' ', 0); break; default: break; @@ -167,44 +295,33 @@ void Menu::enableMenuItem(int menuId, int actionId) { } void Menu::displayMenu() { - int ind_tabl, k, col; - - int pt, x, y, color, msk, num_letr; - _vm->_mouse.hideMouse(); - _vm->_screenSurface.fillRect(7, Common::Rect(0, 0, 639, 10)); - col = 28 * _vm->_resolutionScaler; - if (_vm->_currGraphicalDevice == MODE_CGA) - color = 1; - else - color = 9; - num_letr = 0; - do { // One character after the other - ++num_letr; - ind_tabl = 0; - y = 1; - do { // One column after the other - k = 0; - x = col; - do { // One line after the other - msk = 0x80; - for (pt = 0; pt <= 7; ++pt) { - if ((_charArr[num_letr - 1][ind_tabl] & msk) != 0) { + + int col = 28 * kResolutionScaler; + for (int charNum = 0; charNum < 6; charNum++) { + // One character after the other + int idx = 0; + for (int y = 1; y < 9; ++y) { + // One column after the other + int x = col; + for (int k = 0; k < 3; ++k) { + // One line after the other + uint msk = 0x80; + for (int pt = 0; pt <= 7; ++pt) { + if ((_charArr[charNum][idx] & msk) != 0) { _vm->_screenSurface.setPixel(Common::Point(x + 1, y + 1), 0); _vm->_screenSurface.setPixel(Common::Point(x, y + 1), 0); - _vm->_screenSurface.setPixel(Common::Point(x, y), color); + _vm->_screenSurface.setPixel(Common::Point(x, y), 9); } - msk = (uint)msk >> 1; + msk >>= 1; ++x; } - ++ind_tabl; - ++k; - } while (k != 3); - ++y; - } while (y != 9); - col += 48 * _vm->_resolutionScaler; - } while (num_letr != 6); + ++idx; + } + } + col += 48 * kResolutionScaler; + } _vm->_mouse.showMouse(); } @@ -280,16 +397,12 @@ void Menu::util(Common::Point pos) { int ymx = (menuConstants[_msg3 - 1][3] << 3) + 16; int dxcar = menuConstants[_msg3 - 1][2]; - int xmn = (menuConstants[_msg3 - 1][0] << 2) * _vm->_resolutionScaler; + int xmn = (menuConstants[_msg3 - 1][0] << 2) * kResolutionScaler; - int ix; - if (_vm->_resolutionScaler == 1) - ix = 5; - else - ix = 3; - int xmx = dxcar * ix * _vm->_resolutionScaler + xmn + 2; + int charWidth = 6; + int xmx = dxcar * charWidth + xmn + 2; if ((pos.x > xmn) && (pos.x < xmx) && (pos.y < ymx) && (pos.y > 15)) { - ix = (((uint)pos.y >> 3) - 1) + (_msg3 << 8); + int ix = (((uint)pos.y >> 3) - 1) + (_msg3 << 8); if (ix != _msg4) { invert(1); _msg4 = ix; @@ -305,79 +418,70 @@ void Menu::util(Common::Point pos) { * Draw a menu */ void Menu::menuDown(int ii) { - int cx, xcc, xco; - int lignNumb; - // Make a copy of the current screen surface for later restore _vm->_backgroundSurface.copyFrom(_vm->_screenSurface); // Draw the menu - xco = menuConstants[ii - 1][0]; - lignNumb = menuConstants[ii - 1][3]; + int minX = menuConstants[ii - 1][0] << 3; + int lineNum = menuConstants[ii - 1][3]; _vm->_mouse.hideMouse(); - xco = xco << 3; - if (_vm->_resolutionScaler == 1) - cx = 10; - else - cx = 6; - xcc = xco + (menuConstants[ii - 1][2] * cx) + 6; + int deltaX = 6; + int maxX = minX + (menuConstants[ii - 1][2] * deltaX) + 6; if ((ii == 4) && (_vm->getLanguage() == Common::EN_ANY)) // Extra width needed for Self menu in English version - xcc = 435; - - _vm->_screenSurface.fillRect(15, Common::Rect(xco, 12, xcc, 10 + (menuConstants[ii - 1][1] << 1))); - _vm->_screenSurface.fillRect(0, Common::Rect(xcc, 12, xcc + 4, 10 + (menuConstants[ii - 1][1] << 1))); - _vm->_screenSurface.fillRect(0, Common::Rect(xco, 8 + (menuConstants[ii - 1][1] << 1), xcc + 4, 12 + (menuConstants[ii - 1][1] << 1))); - _vm->_screenSurface.putxy(xco, 16); - cx = 0; - do { - ++cx; + maxX = 435; + + _vm->_screenSurface.fillRect(15, Common::Rect(minX, 12, maxX, 10 + (menuConstants[ii - 1][1] << 1))); + _vm->_screenSurface.fillRect(0, Common::Rect(maxX, 12, maxX + 4, 10 + (menuConstants[ii - 1][1] << 1))); + _vm->_screenSurface.fillRect(0, Common::Rect(minX, 8 + (menuConstants[ii - 1][1] << 1), maxX + 4, 12 + (menuConstants[ii - 1][1] << 1))); + _vm->_screenSurface.putxy(minX, 16); + for (int i = 1; i <= lineNum; i++) { switch (ii) { case 1: - if (_inventoryStringArray[cx][0] != '*') - _vm->_screenSurface.drawString(_inventoryStringArray[cx], 4); + if (_inventoryStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_inventoryStringArray[i], 4); break; case 2: - if (_moveStringArray[cx][0] != '*') - _vm->_screenSurface.drawString(_moveStringArray[cx], 4); + if (_moveStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_moveStringArray[i], 4); break; case 3: - if (_actionStringArray[cx][0] != '*') - _vm->_screenSurface.drawString(_actionStringArray[cx], 4); + if (_actionStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_actionStringArray[i], 4); break; case 4: - if (_selfStringArray[cx][0] != '*') - _vm->_screenSurface.drawString(_selfStringArray[cx], 4); + if (_selfStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_selfStringArray[i], 4); break; case 5: - if (_discussStringArray[cx][0] != '*') - _vm->_screenSurface.drawString(_discussStringArray[cx], 4); + if (_discussStringArray[i][0] != '*') + _vm->_screenSurface.drawString(_discussStringArray[i], 4); break; case 6: - _vm->_screenSurface.drawString(_vm->getEngineString(S_SAVE_LOAD + cx), 4); + _vm->_screenSurface.drawString(_vm->getEngineString(S_SAVE_LOAD + i), 4); break; case 7: { Common::String s = _vm->getEngineString(S_SAVE_LOAD + 1); s += ' '; - s += (char)(48 + cx); + s += (char)(48 + i); _vm->_screenSurface.drawString(s, 4); } break; case 8: - if (cx == 1) + if (i == 1) _vm->_screenSurface.drawString(_vm->getEngineString(S_RESTART), 4); else { Common::String s = _vm->getEngineString(S_SAVE_LOAD + 2); s += ' '; - s += (char)(47 + cx); + s += (char)(47 + i); _vm->_screenSurface.drawString(s, 4); } break; default: break; } - _vm->_screenSurface.putxy(xco, _vm->_screenSurface._textPos.y + 8); - } while (cx != lignNumb); + _vm->_screenSurface.putxy(minX, _vm->_screenSurface._textPos.y + 8); + } _multiTitle = true; _vm->_mouse.showMouse(); } @@ -427,24 +531,24 @@ void Menu::updateMenu() { _vm->_prevPos = curPos; bool tes = (curPos.y < 11) - && ((curPos.x >= (28 * _vm->_resolutionScaler) && curPos.x <= (28 * _vm->_resolutionScaler + 24)) - || (curPos.x >= (76 * _vm->_resolutionScaler) && curPos.x <= (76 * _vm->_resolutionScaler + 24)) - || ((curPos.x > 124 * _vm->_resolutionScaler) && (curPos.x < 124 * _vm->_resolutionScaler + 24)) - || ((curPos.x > 172 * _vm->_resolutionScaler) && (curPos.x < 172 * _vm->_resolutionScaler + 24)) - || ((curPos.x > 220 * _vm->_resolutionScaler) && (curPos.x < 220 * _vm->_resolutionScaler + 24)) - || ((curPos.x > 268 * _vm->_resolutionScaler) && (curPos.x < 268 * _vm->_resolutionScaler + 24))); + && ((curPos.x >= (28 * kResolutionScaler) && curPos.x <= (28 * kResolutionScaler + 24)) + || (curPos.x >= (76 * kResolutionScaler) && curPos.x <= (76 * kResolutionScaler + 24)) + || ((curPos.x > 124 * kResolutionScaler) && (curPos.x < 124 * kResolutionScaler + 24)) + || ((curPos.x > 172 * kResolutionScaler) && (curPos.x < 172 * kResolutionScaler + 24)) + || ((curPos.x > 220 * kResolutionScaler) && (curPos.x < 220 * kResolutionScaler + 24)) + || ((curPos.x > 268 * kResolutionScaler) && (curPos.x < 268 * kResolutionScaler + 24))); if (tes) { int ix; - if (curPos.x < 76 * _vm->_resolutionScaler) + if (curPos.x < 76 * kResolutionScaler) ix = MENU_INVENTORY; - else if (curPos.x < 124 * _vm->_resolutionScaler) + else if (curPos.x < 124 * kResolutionScaler) ix = MENU_MOVE; - else if (curPos.x < 172 * _vm->_resolutionScaler) + else if (curPos.x < 172 * kResolutionScaler) ix = MENU_ACTION; - else if (curPos.x < 220 * _vm->_resolutionScaler) + else if (curPos.x < 220 * kResolutionScaler) ix = MENU_SELF; - else if (curPos.x < 268 * _vm->_resolutionScaler) + else if (curPos.x < 268 * kResolutionScaler) ix = MENU_DISCUSS; else ix = MENU_FILE; @@ -486,18 +590,37 @@ void Menu::updateMenu() { } } -void Menu::initMenu(MortevielleEngine *vm) { +void Menu::setParent(MortevielleEngine *vm) { _vm = vm; +} - int i; +void Menu::initMenu() { Common::File f; - bool enMenuLoaded = false; - if (_vm->getLanguage() == Common::EN_ANY) { - // Open the mort.dat file + bool menuLoaded = false; + // First try to read it from mort.dat if useOriginalData() is false + if (!_vm->useOriginalData()) { if (!f.open(MORT_DAT)) warning("File %s not found. Using default menu from game data", MORT_DAT); else { + // Figure out what language Id is needed + byte desiredLanguageId; + switch(_vm->getLanguage()) { + case Common::EN_ANY: + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + case Common::FR_FRA: + desiredLanguageId = MORTDAT_LANG_FRENCH; + break; + case Common::DE_DEU: + desiredLanguageId = MORTDAT_LANG_GERMAN; + break; + default: + warning("Language not supported, switching to English"); + desiredLanguageId = MORTDAT_LANG_ENGLISH; + break; + } + // Validate the data file header char fileId[4]; f.read(fileId, 4); @@ -512,12 +635,20 @@ void Menu::initMenu(MortevielleEngine *vm) { f.read(dataType, 4); dataSize = f.readUint16LE(); if (!strncmp(dataType, "MENU", 4)) { - // MENU section - if (dataSize <= 7 * 24) { + // Read in the language + byte languageId = f.readByte(); + --dataSize; + + // If the language isn't correct, then skip the entire block + if (languageId != desiredLanguageId) { + f.skip(dataSize); + continue; + } + if (dataSize == 6 * 24) { f.read(_charArr, dataSize); - enMenuLoaded = true; + menuLoaded = true; } else - warning("Wrong size %d for menu data. Expected %d or less", dataSize, 7*24); + warning("Wrong size %d for menu data. Expected %d or less", dataSize, 6 * 24); break; } else { // Other sections @@ -527,46 +658,50 @@ void Menu::initMenu(MortevielleEngine *vm) { } // Close the file f.close(); - if (!enMenuLoaded) - warning("Failed to load English menu. Will use default menu from game data instead"); + if (!menuLoaded) + warning("Failed to load menu from mort.dat. Will use default menu from game data instead."); } } - if (!enMenuLoaded) { - if (!f.open("menufr.mor")) + if (!menuLoaded) { + // Load menu from game data using the original language + if (_vm->getOriginalLanguage() == Common::FR_FRA) { + if (!f.open("menufr.mor")) + error("Missing file - menufr.mor"); + } else { // Common::DE_DEU if (!f.open("menual.mor")) - if (!f.open("menu.mor")) - error("Missing file - menufr.mor or menual.mor or menu.mor"); - - f.read(_charArr, 7 * 24); + error("Missing file - menual.mor"); + } + f.read(_charArr, 6 * 24); f.close(); } // Skipped: dialog asking to swap floppy - for (i = 1; i <= 8; ++i) + for (int i = 1; i <= 8; ++i) _inventoryStringArray[i] = "* "; _inventoryStringArray[7] = "< -*-*-*-*-*-*-*-*-*- "; - for (i = 1; i <= 7; ++i) + for (int i = 1; i <= 7; ++i) _moveStringArray[i] = "* "; - i = 1; - do { + for (int i = 1; i < 22; i++) { _actionStringArray[i] = _vm->getString(i + kMenuActionStringIndex); - + if ((_actionStringArray[i][0] != '*') && (_actionStringArray[i][0] != ' ')) + _actionStringArray[i].insertChar(' ', 0); while (_actionStringArray[i].size() < 10) _actionStringArray[i] += ' '; if (i < 9) { if (i < 6) { _selfStringArray[i] = _vm->getString(i + kMenuSelfStringIndex); + if ((_selfStringArray[i][0] != '*') && (_selfStringArray[i][0] != ' ')) + _selfStringArray[i].insertChar(' ', 0); while (_selfStringArray[i].size() < 10) _selfStringArray[i] += ' '; } _discussStringArray[i] = _vm->getString(i + kMenuSayStringIndex) + ' '; } - ++i; - } while (i != 22); - for (i = 1; i <= 8; ++i) { + } + for (int i = 1; i <= 8; ++i) { _discussMenu[i]._menuId = MENU_DISCUSS; _discussMenu[i]._actionId = i; if (i < 8) { @@ -576,7 +711,7 @@ void Menu::initMenu(MortevielleEngine *vm) { _inventoryMenu[i]._menuId = MENU_INVENTORY; _inventoryMenu[i]._actionId = i; if (i > 6) - disableMenuItem(_inventoryMenu[i]._menuId, _inventoryMenu[i]._actionId); + disableMenuItem(_inventoryMenu[i]); } _msg3 = OPCODE_NONE; _msg4 = OPCODE_NONE; @@ -591,13 +726,21 @@ void Menu::initMenu(MortevielleEngine *vm) { */ void Menu::setSearchMenu() { for (int i = 1; i <= 7; ++i) - disableMenuItem(MENU_MOVE, _moveMenu[i]._actionId); + disableMenuItem(_moveMenu[i]); for (int i = 1; i <= 11; ++i) - disableMenuItem(_actionMenu[i]._menuId, _actionMenu[i]._actionId); + disableMenuItem(_actionMenu[i]); + + MenuItem miSound; + miSound._menuId = _opcodeSound >> 8; + miSound._actionId = _opcodeSound & 0xFF; - setText(OPCODE_SOUND >> 8, OPCODE_SOUND & 0xFF, _vm->getEngineString(S_SUITE)); - setText(OPCODE_LIFT >> 8, OPCODE_LIFT & 0xFF, _vm->getEngineString(S_STOP)); + MenuItem miLift; + miLift._menuId = _opcodeLift >> 8; + miLift._actionId = _opcodeLift & 0xFF; + + setText(miSound, _vm->getEngineString(S_SUITE)); + setText(miLift, _vm->getEngineString(S_STOP)); } /** @@ -607,10 +750,18 @@ void Menu::setSearchMenu() { void Menu::unsetSearchMenu() { setDestinationText(_vm->_coreVar._currPlace); for (int i = 1; i <= 11; ++i) - enableMenuItem(_actionMenu[i]._menuId, _actionMenu[i]._actionId); + enableMenuItem(_actionMenu[i]); + + MenuItem miSound; + miSound._menuId = _opcodeSound >> 8; + miSound._actionId = _opcodeSound & 0xFF; + + MenuItem miLift; + miLift._menuId = _opcodeLift >> 8; + miLift._actionId = _opcodeLift & 0xFF; - setText(OPCODE_SOUND >> 8, OPCODE_SOUND & 0xFF, _vm->getEngineString(S_PROBE)); - setText(OPCODE_LIFT >> 8, OPCODE_LIFT & 0xFF, _vm->getEngineString(S_RAISE)); + setText(miSound, _vm->getEngineString(S_PROBE)); + setText(miLift, _vm->getEngineString(S_RAISE)); } /** @@ -626,15 +777,15 @@ void Menu::setInventoryText() { ++cy; int r = _vm->_coreVar._inventory[i] + 400; nomp = _vm->getString(r - 501 + kInventoryStringIndex); - setText(_inventoryMenu[cy]._menuId, _inventoryMenu[cy]._actionId, nomp); - enableMenuItem(_inventoryMenu[i]._menuId, _inventoryMenu[i]._actionId); + setText(_inventoryMenu[cy], nomp); + enableMenuItem(_inventoryMenu[i]); } } if (cy < 6) { for (int i = cy + 1; i <= 6; ++i) { - setText(_inventoryMenu[i]._menuId, _inventoryMenu[i]._actionId, " "); - disableMenuItem(_inventoryMenu[i]._menuId, _inventoryMenu[i]._actionId); + setText(_inventoryMenu[i], " "); + disableMenuItem(_inventoryMenu[i]); } } } diff --git a/engines/mortevielle/menu.h b/engines/mortevielle/menu.h index 2428d8917b..debf5b09b6 100644 --- a/engines/mortevielle/menu.h +++ b/engines/mortevielle/menu.h @@ -40,45 +40,28 @@ enum { MENU_LOAD = 8 }; -enum verbs {OPCODE_NONE = 0, OPCODE_ATTACH = 0x301, OPCODE_WAIT = 0x302, OPCODE_FORCE = 0x303, OPCODE_SLEEP = 0x304, OPCODE_LISTEN = 0x305, -OPCODE_ENTER = 0x306, OPCODE_CLOSE = 0x307, OPCODE_SEARCH = 0x308, OPCODE_KNOCK = 0x309, OPCODE_SCRATCH = 0x30a, -OPCODE_READ = 0x30b, OPCODE_EAT = 0x30c, OPCODE_PLACE = 0x30d, OPCODE_OPEN = 0x30e, OPCODE_TAKE = 0x30f, -OPCODE_LOOK = 0x310, OPCODE_SMELL = 0x311, OPCODE_SOUND = 0x312, OPCODE_LEAVE = 0x313, OPCODE_LIFT = 0x314, -OPCODE_TURN = 0x315, OPCODE_SHIDE = 0x401, OPCODE_SSEARCH = 0x402, OPCODE_SREAD = 0x403, OPCODE_SPUT = 0x404, -OPCODE_SLOOK = 0x405}; - -struct menuItem { +const int OPCODE_NONE = 0; + +struct MenuItem { int _menuId; int _actionId; }; -static const menuItem _actionMenu[12] = { - {OPCODE_NONE >> 8, OPCODE_NONE & 0xFF}, - {OPCODE_SHIDE >> 8, OPCODE_SHIDE & 0xFF}, - {OPCODE_ATTACH >> 8, OPCODE_ATTACH & 0xFF}, - {OPCODE_FORCE >> 8, OPCODE_FORCE & 0xFF}, - {OPCODE_SLEEP >> 8, OPCODE_SLEEP & 0xFF}, - {OPCODE_ENTER >> 8, OPCODE_ENTER & 0xFF}, - {OPCODE_CLOSE >> 8, OPCODE_CLOSE & 0xFF}, - {OPCODE_KNOCK >> 8, OPCODE_KNOCK & 0xFF}, - {OPCODE_EAT >> 8, OPCODE_EAT & 0xFF}, - {OPCODE_PLACE >> 8, OPCODE_PLACE & 0xFF}, - {OPCODE_OPEN >> 8, OPCODE_OPEN & 0xFF}, - {OPCODE_LEAVE >> 8, OPCODE_LEAVE & 0xFF} -}; - class Menu { private: MortevielleEngine *_vm; - byte _charArr[7][24]; + byte _charArr[6][24]; int _msg3; int _msg4; void util(Common::Point pos); void invert(int indx); void menuDown(int ii); + public: + Menu(); + bool _menuActive; bool _menuSelected; bool _multiTitle; @@ -88,21 +71,51 @@ public: Common::String _actionStringArray[22]; Common::String _selfStringArray[7]; Common::String _discussStringArray[9]; - menuItem _discussMenu[9]; - menuItem _inventoryMenu[9]; - menuItem _moveMenu[8]; - - void setText(int menuId, int actionId, Common::String name); + MenuItem _discussMenu[9]; + MenuItem _inventoryMenu[9]; + MenuItem _moveMenu[8]; + + int _opcodeAttach; + int _opcodeWait; + int _opcodeForce; + int _opcodeSleep; + int _opcodeListen; + int _opcodeEnter; + int _opcodeClose; + int _opcodeSearch; + int _opcodeKnock; + int _opcodeScratch; + int _opcodeRead; + int _opcodeEat; + int _opcodePlace; + int _opcodeOpen; + int _opcodeTake; + int _opcodeLook; + int _opcodeSmell; + int _opcodeSound; + int _opcodeLeave; + int _opcodeLift; + int _opcodeTurn; + int _opcodeSHide; + int _opcodeSSearch; + int _opcodeSRead; + int _opcodeSPut; + int _opcodeSLook; + MenuItem _actionMenu[12]; + + void setParent(MortevielleEngine *vm); + void readVerbNums(Common::File &f, int dataSize); + void setText(MenuItem item, Common::String name); void setDestinationText(int roomId); void setInventoryText(); - void disableMenuItem(int menuId, int actionId); - void enableMenuItem(int menuId, int actionId); + void disableMenuItem(MenuItem item); + void enableMenuItem(MenuItem item); void displayMenu(); void drawMenu(); void menuUp(int msgId); void eraseMenu(); void updateMenu(); - void initMenu(MortevielleEngine *vm); + void initMenu(); void setSearchMenu(); void unsetSearchMenu(); diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp index 7b2a648221..f13f8cb65b 100644 --- a/engines/mortevielle/mortevielle.cpp +++ b/engines/mortevielle/mortevielle.cpp @@ -57,6 +57,7 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescr _text.setParent(this); _soundManager.setParent(this); _savegameManager.setParent(this); + _menu.setParent(this); _lastGameFrame = 0; _mouseClick = false; @@ -91,8 +92,6 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescr _uptodatePresence = false; _textColor = 0; - _currGraphicalDevice = -1; - _newGraphicalDevice = -1; _place = -1; _x26KeyCount = -1; @@ -179,10 +178,6 @@ Common::ErrorCode MortevielleEngine::initialize() { // Set up an intermediate screen surface _screenSurface.create(SCREEN_WIDTH, SCREEN_HEIGHT, Graphics::PixelFormat::createFormatCLUT8()); - // Set the screen mode - _currGraphicalDevice = MODE_EGA; - _resolutionScaler = 2; - _txxFileFl = false; // Load texts from TXX files loadTexts(); @@ -203,8 +198,6 @@ Common::ErrorCode MortevielleEngine::initialize() { // Setup the mouse cursor initMouse(); - _currGraphicalDevice = MODE_EGA; - _newGraphicalDevice = _currGraphicalDevice; loadPalette(); loadCFIPH(); loadCFIEC(); @@ -219,10 +212,7 @@ Common::ErrorCode MortevielleEngine::initialize() { testKeyboard(); showConfigScreen(); - _newGraphicalDevice = _currGraphicalDevice; testKeyboard(); - if (_newGraphicalDevice != _currGraphicalDevice) - _currGraphicalDevice = _newGraphicalDevice; clearScreen(); _soundManager.loadNoise(); @@ -273,6 +263,8 @@ Common::ErrorCode MortevielleEngine::loadMortDat() { readStaticStrings(f, dataSize, kStaticStrings); } else if ((!strncmp(dataType, "GSTR", 4)) && (!_txxFileFl)) { readStaticStrings(f, dataSize, kGameStrings); + } else if (!strncmp(dataType, "VERB", 4)) { + _menu.readVerbNums(f, dataSize); } else { // Unknown section f.skip(dataSize); @@ -286,6 +278,7 @@ Common::ErrorCode MortevielleEngine::loadMortDat() { return Common::kNoError; } + /** * Read in a static strings block, and if the language matches, load up the static strings */ @@ -354,10 +347,16 @@ Common::Error MortevielleEngine::run() { if (loadSlot == 0) // Show the game introduction showIntroduction(); + else { + _caff = 51; + _text.taffich(); + } // Either load the initial game state savegame, or the specified savegame number adzon(); - _savegameManager.loadSavegame(generateSaveFilename(loadSlot)); + resetVariables(); + if (loadSlot != 0) + _savegameManager.loadSavegame(generateSaveFilename(loadSlot)); // Run the main game loop mainGame(); @@ -400,7 +399,7 @@ void MortevielleEngine::mainGame() { for (_crep = 1; _crep <= _x26KeyCount; ++_crep) decodeNumber(&_cfiecBuffer[161 * 16], (_cfiecBufferSize - (161 * 16)) / 64); - _menu.initMenu(this); + _menu.initMenu(); charToHour(); initGame(); diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h index 27a3d5697a..4c096c1f71 100644 --- a/engines/mortevielle/mortevielle.h +++ b/engines/mortevielle/mortevielle.h @@ -62,6 +62,11 @@ enum { MORTDAT_LANG_GERMAN = 2 }; +enum { + kUseOriginalData = 0, + kUseEngineDataFile = 1 +}; + // Static string list enum { S_YES_NO = 0, S_GO_TO = 1, S_SOMEONE_ENTERS = 2, S_COOL = 3, S_LOURDE = 4, @@ -115,6 +120,7 @@ const int kMenuSelfStringIndex = 497; const int kMenuSayStringIndex = 502; const int kMaxPatt = 20; +const int kResolutionScaler = 2; /* 9 "A glance at the forbidden$", 18 "It's already open$", @@ -129,18 +135,6 @@ enum Places { DOOR = 25, ROOM26 = 26, COAT_ARMS = 27 }; -enum GraphicModes { MODE_AMSTRAD1512 = 0, MODE_CGA = 1, MODE_EGA = 2, MODE_HERCULES = 3, MODE_TANDY = 4 }; - -struct nhom { - byte _id; /* number between 0 and 32 */ - byte _hom[4]; -}; - -struct CgaPalette { - byte _p; - nhom _a[16]; -}; - struct Pattern { byte _tay, _tax; byte _des[kMaxPatt + 1][kMaxPatt + 1]; @@ -180,7 +174,6 @@ private: Common::StringArray _engineStrings; Common::StringArray _gameStrings; - Pattern _patternArr[15]; int _menuOpcode; bool _inMainGameLoop; // Flag when the main game loop is active @@ -224,7 +217,6 @@ private: int _startHour; int _endHour; Common::Point _stdPal[91][17]; - CgaPalette _cgaPal[91]; int _x26KeyCount; int _roomDoorId; @@ -257,7 +249,6 @@ private: void mainGame(); void playGame(); void handleAction(); - void displayCGAPattern(int n, Pattern *p, nhom *pal); void loadPalette(); void loadTexts(); void loadCFIEC(); @@ -278,7 +269,6 @@ private: void getReadDescription(int objId); void getSearchDescription(int objId); int checkLeaveSecretPassage(); - void changeGraphicalDevice(int newDevice); void startDialog(int16 rep); void endSearch(); int convertCharacterIndexToBitIndex(int characterIndex); @@ -419,8 +409,6 @@ public: bool _blo; bool _destinationOk; bool _largestClearScreen; - int _currGraphicalDevice; - int _newGraphicalDevice; float _addFix; int _savedBitIndex; int _numpal; @@ -432,7 +420,6 @@ public: int _caff; int _crep; - int _resolutionScaler; byte _destinationArray[7][25]; byte *_curPict; @@ -461,6 +448,8 @@ public: virtual Common::Error run(); uint32 getGameFlags() const; Common::Language getLanguage() const; + Common::Language getOriginalLanguage() const; + bool useOriginalData() const; static Common::String generateSaveFilename(const Common::String &target, int slot); Common::String generateSaveFilename(int slot) { return generateSaveFilename(_targetName, slot); } diff --git a/engines/mortevielle/mouse.cpp b/engines/mortevielle/mouse.cpp index dfc9ccd706..9eb4e129c0 100644 --- a/engines/mortevielle/mouse.cpp +++ b/engines/mortevielle/mouse.cpp @@ -65,8 +65,8 @@ void MouseHandler::showMouse() { * @remarks Originally called 'pos_mouse' */ void MouseHandler::setMousePosition(Common::Point newPos) { - if (newPos.x > 314 * _vm->_resolutionScaler) - newPos.x = 314 * _vm->_resolutionScaler; + if (newPos.x > 314 * kResolutionScaler) + newPos.x = 314 * kResolutionScaler; else if (newPos.x < 0) newPos.x = 0; if (newPos.y > 199) @@ -138,16 +138,16 @@ void MouseHandler::moveMouse(bool &funct, char &key) { cy = 190; break; case '9': - cx = 315 * _vm->_resolutionScaler; + cx = 315 * kResolutionScaler; cy = 1; break; case '3': cy = 190; - cx = 315 * _vm->_resolutionScaler; + cx = 315 * kResolutionScaler; break; case '5': cy = 100; - cx = 155 * _vm->_resolutionScaler; + cx = 155 * kResolutionScaler; break; case ' ': case '\15': @@ -201,27 +201,27 @@ void MouseHandler::moveMouse(bool &funct, char &key) { } break; case 'I': - cx = _vm->_resolutionScaler * 32; + cx = kResolutionScaler * 32; cy = 8; break; case 'D': - cx = 80 * _vm->_resolutionScaler; + cx = 80 * kResolutionScaler; cy = 8; break; case 'A': - cx = 126 * _vm->_resolutionScaler; + cx = 126 * kResolutionScaler; cy = 8; break; case 'S': - cx = 174 * _vm->_resolutionScaler; + cx = 174 * kResolutionScaler; cy = 8; break; case 'P': - cx = 222 * _vm->_resolutionScaler; + cx = 222 * kResolutionScaler; cy = 8; break; case 'F': - cx = _vm->_resolutionScaler * 270; + cx = kResolutionScaler * 270; cy = 8; break; case '\23': diff --git a/engines/mortevielle/outtext.cpp b/engines/mortevielle/outtext.cpp index 99c06c7c4c..d50f4005de 100644 --- a/engines/mortevielle/outtext.cpp +++ b/engines/mortevielle/outtext.cpp @@ -53,7 +53,6 @@ int TextHandler::nextWord(int p, const char *ch, int &tab) { * @remarks Originally called 'afftex' */ void TextHandler::displayStr(Common::String inputStr, int x, int y, int dx, int dy, int typ) { - int tab; Common::String s; int i, j; @@ -61,10 +60,7 @@ void TextHandler::displayStr(Common::String inputStr, int x, int y, int dx, int inputStr += '$'; _vm->_screenSurface.putxy(x, y); - if (_vm->_resolutionScaler == 1) - tab = 10; - else - tab = 6; + int tab = 6; dx *= 6; dy *= 6; int xc = x; @@ -168,14 +164,11 @@ void TextHandler::loadAniFile(Common::String filename, int32 skipSize, int lengt } void TextHandler::taffich() { - static const byte rang[16] = {15, 14, 11, 7, 13, 12, 10, 6, 9, 5, 3, 1, 2, 4, 8, 0}; - static const byte tran1[] = { 121, 121, 138, 139, 120 }; static const byte tran2[] = { 150, 150, 152, 152, 100, 110, 159, 100, 100 }; int cx, drawingSize, npal; int32 drawingStartPos; - int alllum[16]; int a = _vm->_caff; if ((a >= 153) && (a <= 161)) @@ -272,21 +265,6 @@ void TextHandler::taffich() { npal = a + 37; } loadPictureFile(filename, altFilename, drawingStartPos, drawingSize); - if (_vm->_currGraphicalDevice == MODE_HERCULES) { - for (int i = 0; i <= 15; ++i) { - int palh = READ_LE_UINT16(&_vm->_curPict[2 + (i << 1)]); - alllum[i] = (palh & 15) + (((uint)palh >> 12) & 15) + (((uint)palh >> 8) & 15); - } - for (int i = 0; i <= 15; ++i) { - int k = 0; - for (int j = 0; j <= 15; ++j) { - if (alllum[j] > alllum[k]) - k = j; - } - _vm->_curPict[2 + (k << 1)] = rang[i]; - alllum[k] = -1; - } - } _vm->_numpal = npal; _vm->setPal(npal); @@ -314,7 +292,7 @@ void TextHandler::taffich() { loadAniFile(filename, drawingStartPos, drawingSize); } _vm->_mouse.showMouse(); - if ((a < COAT_ARMS) && ((_vm->_maff < COAT_ARMS) || (_vm->_coreVar._currPlace == LANDING)) && (_vm->_currAction != OPCODE_ENTER)) { + if ((a < COAT_ARMS) && ((_vm->_maff < COAT_ARMS) || (_vm->_coreVar._currPlace == LANDING)) && (_vm->_currAction != _vm->_menu._opcodeEnter)) { if ((a == ATTIC) || (a == CELLAR)) _vm->displayAloneText(); else if (!_vm->_blo) diff --git a/engines/mortevielle/saveload.cpp b/engines/mortevielle/saveload.cpp index 651ed07b65..c14a03cd60 100644 --- a/engines/mortevielle/saveload.cpp +++ b/engines/mortevielle/saveload.cpp @@ -72,15 +72,16 @@ void SavegameManager::sync_save(Common::Serializer &sz) { * Inner code for loading a saved game * @remarks Originally called 'takesav' */ -void SavegameManager::loadSavegame(const Common::String &filename) { +bool SavegameManager::loadSavegame(const Common::String &filename) { // Try loading first from the save area Common::SeekableReadStream *stream = g_system->getSavefileManager()->openForLoading(filename); Common::File f; if (stream == NULL) { - if (!f.open(filename)) - error("Unable to open save file '%s'", filename.c_str()); - + if (!f.open(filename)) { + warning("Unable to open save file '%s'", filename.c_str()); + return false; + } stream = f.readStream(f.size()); f.close(); } @@ -107,6 +108,8 @@ void SavegameManager::loadSavegame(const Common::String &filename) { // Close the stream delete stream; + + return true; } /** @@ -115,14 +118,15 @@ void SavegameManager::loadSavegame(const Common::String &filename) { Common::Error SavegameManager::loadGame(const Common::String &filename) { g_vm->_mouse.hideMouse(); g_vm->displayEmptyHand(); - loadSavegame(filename); - - /* Initialization */ - g_vm->charToHour(); - g_vm->initGame(); - g_vm->gameLoaded(); - g_vm->_mouse.showMouse(); - return Common::kNoError; + if (loadSavegame(filename)) { + /* Initialization */ + g_vm->charToHour(); + g_vm->initGame(); + g_vm->gameLoaded(); + g_vm->_mouse.showMouse(); + return Common::kNoError; + } else + return Common::kUnknownError; } /** diff --git a/engines/mortevielle/saveload.h b/engines/mortevielle/saveload.h index 0121a04d8e..79747e6889 100644 --- a/engines/mortevielle/saveload.h +++ b/engines/mortevielle/saveload.h @@ -57,7 +57,7 @@ private: void sync_save(Common::Serializer &sz); public: void setParent(MortevielleEngine *vm); - void loadSavegame(const Common::String &filename); + bool loadSavegame(const Common::String &filename); Common::Error loadGame(const Common::String &filename); Common::Error saveGame(int n, const Common::String &saveName); Common::Error loadGame(int slot); diff --git a/engines/mortevielle/sound.cpp b/engines/mortevielle/sound.cpp index 3bea96b92f..b670246726 100644 --- a/engines/mortevielle/sound.cpp +++ b/engines/mortevielle/sound.cpp @@ -741,6 +741,10 @@ void SoundManager::startSpeech(int rep, int ht, int typ) { uint16 savph[501]; int tempo; + // Hack to avoid a crash in the ending version. To be removed when the speech are implemented + if ((rep == 141) && (typ == 0)) + return; + if (_vm->_soundOff) return; diff --git a/engines/mortevielle/utils.cpp b/engines/mortevielle/utils.cpp index fff53dbc30..5ca29d849c 100644 --- a/engines/mortevielle/utils.cpp +++ b/engines/mortevielle/utils.cpp @@ -67,9 +67,10 @@ bool MortevielleEngine::keyPressed() { * @remarks Originally called 'get_ch' */ int MortevielleEngine::getChar() { + bool end = false; // If there isn't any pending keypress, wait until there is - while (!shouldQuit() && _keypresses.empty()) { - keyPressed(); + while (!shouldQuit() && !end) { + end = keyPressed(); } // Return the top keypress @@ -283,10 +284,6 @@ void MortevielleEngine::handleAction() { _menu.eraseMenu(); _menu._menuDisplayed = false; - if ((inkey == '\1') || (inkey == '\3') || (inkey == '\5') || (inkey == '\7') || (inkey == '\11')) { - changeGraphicalDevice((uint)((int)inkey - 1) >> 1); - return; - } if (_menu._menuSelected && (_currMenu == MENU_SAVE)) { Common::String saveName = Common::String::format("Savegame #%d", _currAction & 15); _savegameManager.saveGame(_currAction & 15, saveName); @@ -294,7 +291,7 @@ void MortevielleEngine::handleAction() { if (_menu._menuSelected && (_currMenu == MENU_LOAD)) _savegameManager.loadGame((_currAction & 15) - 1); if (inkey == '\103') { /* F9 */ - temps = _dialogManager.show(_hintPctMessage, 1); + temps = _dialogManager.show(_hintPctMessage); return; } else if (inkey == '\77') { if ((_menuOpcode != OPCODE_NONE) && ((_currMenu == MENU_ACTION) || (_currMenu == MENU_SELF))) { @@ -327,9 +324,9 @@ void MortevielleEngine::handleAction() { if (_mouse._pos.y < 12) return; - if ((_currAction == OPCODE_SOUND) || (_currAction == OPCODE_LIFT)) { + if ((_currAction == _menu._opcodeSound) || (_currAction == _menu._opcodeLift)) { handledOpcodeFl = true; - if ((_currAction == OPCODE_LIFT) || (_obpart)) { + if ((_currAction == _menu._opcodeLift) || (_obpart)) { endSearch(); _caff = _coreVar._currPlace; _crep = 998; @@ -506,48 +503,48 @@ void MortevielleEngine::showPeoplePresent(int bitIndex) { int xp = 580 - (_screenSurface.getStringWidth("LEO") / 2); for (int i = 1; i <= 8; ++i) - _menu.disableMenuItem(_menu._discussMenu[i]._menuId, _menu._discussMenu[i]._actionId); + _menu.disableMenuItem(_menu._discussMenu[i]); clearUpperRightPart(); if ((bitIndex & 128) == 128) { _screenSurface.putxy(xp, 24); _screenSurface.drawString("LEO", 4); - _menu.enableMenuItem(_menu._discussMenu[1]._menuId, _menu._discussMenu[1]._actionId); + _menu.enableMenuItem(_menu._discussMenu[1]); } if ((bitIndex & 64) == 64) { _screenSurface.putxy(xp, 32); _screenSurface.drawString("PAT", 4); - _menu.enableMenuItem(_menu._discussMenu[2]._menuId, _menu._discussMenu[2]._actionId); + _menu.enableMenuItem(_menu._discussMenu[2]); } if ((bitIndex & 32) == 32) { _screenSurface.putxy(xp, 40); _screenSurface.drawString("GUY", 4); - _menu.enableMenuItem(_menu._discussMenu[3]._menuId, _menu._discussMenu[3]._actionId); + _menu.enableMenuItem(_menu._discussMenu[3]); } if ((bitIndex & 16) == 16) { _screenSurface.putxy(xp, 48); _screenSurface.drawString("EVA", 4); - _menu.enableMenuItem(_menu._discussMenu[4]._menuId, _menu._discussMenu[4]._actionId); + _menu.enableMenuItem(_menu._discussMenu[4]); } if ((bitIndex & 8) == 8) { _screenSurface.putxy(xp, 56); _screenSurface.drawString("BOB", 4); - _menu.enableMenuItem(_menu._discussMenu[5]._menuId, _menu._discussMenu[5]._actionId); + _menu.enableMenuItem(_menu._discussMenu[5]); } if ((bitIndex & 4) == 4) { _screenSurface.putxy(xp, 64); _screenSurface.drawString("LUC", 4); - _menu.enableMenuItem(_menu._discussMenu[6]._menuId, _menu._discussMenu[6]._actionId); + _menu.enableMenuItem(_menu._discussMenu[6]); } if ((bitIndex & 2) == 2) { _screenSurface.putxy(xp, 72); _screenSurface.drawString("IDA", 4); - _menu.enableMenuItem(_menu._discussMenu[7]._menuId, _menu._discussMenu[7]._actionId); + _menu.enableMenuItem(_menu._discussMenu[7]); } if ((bitIndex & 1) == 1) { _screenSurface.putxy(xp, 80); _screenSurface.drawString("MAX", 4); - _menu.enableMenuItem(_menu._discussMenu[8]._menuId, _menu._discussMenu[8]._actionId); + _menu.enableMenuItem(_menu._discussMenu[8]); } _currBitIndex = bitIndex; } @@ -701,7 +698,7 @@ int MortevielleEngine::getPresenceStatsRedRoom() { */ void MortevielleEngine::displayAloneText() { for (int i = 1; i <= 8; ++i) - _menu.disableMenuItem(_menu._discussMenu[i]._menuId, _menu._discussMenu[i]._actionId); + _menu.disableMenuItem(_menu._discussMenu[i]); Common::String sYou = getEngineString(S_YOU); Common::String sAre = getEngineString(S_ARE); @@ -1338,7 +1335,7 @@ void MortevielleEngine::startDialog(int16 rep) { _mouse.hideMouse(); Common::String dialogStr = getString(rep + kDialogStringIndex); - _text.displayStr(dialogStr, 230, 4, 65, 24, 5); + _text.displayStr(dialogStr, 230, 4, 65, 26, 5); _dialogManager.drawF3F8(); key = 0; @@ -1450,31 +1447,6 @@ void MortevielleEngine::floodedInWell() { } /** - * Engine function - Change Graphical Device - * @remarks Originally called 'change_gd' - */ -void MortevielleEngine::changeGraphicalDevice(int newDevice) { - _mouse.hideMouse(); - _currGraphicalDevice = newDevice; - clearScreen(); - _mouse.initMouse(); - _mouse.showMouse(); - drawRightFrame(); - prepareRoom(); - drawClock(); - if (_currBitIndex != 0) - showPeoplePresent(_currBitIndex); - else - displayAloneText(); - clearDescriptionBar(); - clearVerbBar(); - _maff = 68; - drawPictureWithText(); - handleDescriptionText(2, _crep); - _menu.displayMenu(); -} - -/** * Called when a savegame has been loaded. * @remarks Originally called 'antegame' */ @@ -1536,79 +1508,79 @@ void MortevielleEngine::handleOpcode() { _keyPressedEsc = false; if (!_anyone) { if (_uptodatePresence) { - if ((_currMenu == MENU_MOVE) || (_currAction == OPCODE_LEAVE) || (_currAction == OPCODE_SLEEP) || (_currAction == OPCODE_EAT)) { + if ((_currMenu == MENU_MOVE) || (_currAction == _menu._opcodeLeave) || (_currAction == _menu._opcodeSleep) || (_currAction == _menu._opcodeEat)) { _controlMenu = 4; menuUp(); return; } } + if (_currMenu == MENU_MOVE) fctMove(); - if (_currMenu == MENU_DISCUSS) + else if (_currMenu == MENU_DISCUSS) fctDiscuss(); - if (_currMenu == MENU_INVENTORY) + else if (_currMenu == MENU_INVENTORY) fctInventoryTake(); - if (_currAction == OPCODE_ATTACH) + else if (_currAction == _menu._opcodeAttach) fctAttach(); - if (_currAction == OPCODE_WAIT) + else if (_currAction == _menu._opcodeWait) fctWait(); - if (_currAction == OPCODE_FORCE) + else if (_currAction == _menu._opcodeForce) fctForce(); - if (_currAction == OPCODE_SLEEP) + else if (_currAction == _menu._opcodeSleep) fctSleep(); - if (_currAction == OPCODE_LISTEN) + else if (_currAction == _menu._opcodeListen) fctListen(); - if (_currAction == OPCODE_ENTER) + else if (_currAction == _menu._opcodeEnter) fctEnter(); - if (_currAction == OPCODE_CLOSE) + else if (_currAction == _menu._opcodeClose) fctClose(); - if (_currAction == OPCODE_SEARCH) + else if (_currAction == _menu._opcodeSearch) fctSearch(); - if (_currAction == OPCODE_KNOCK) + else if (_currAction == _menu._opcodeKnock) fctKnock(); - if (_currAction == OPCODE_SCRATCH) + else if (_currAction == _menu._opcodeScratch) fctScratch(); - if (_currAction == OPCODE_READ) + else if (_currAction == _menu._opcodeRead) fctRead(); - if (_currAction == OPCODE_EAT) + else if (_currAction == _menu._opcodeEat) fctEat(); - if (_currAction == OPCODE_PLACE) + else if (_currAction == _menu._opcodePlace) fctPlace(); - if (_currAction == OPCODE_OPEN) + else if (_currAction == _menu._opcodeOpen) fctOpen(); - if (_currAction == OPCODE_TAKE) + else if (_currAction == _menu._opcodeTake) fctTake(); - if (_currAction == OPCODE_LOOK) + else if (_currAction == _menu._opcodeLook) fctLook(); - if (_currAction == OPCODE_SMELL) + else if (_currAction == _menu._opcodeSmell) fctSmell(); - if (_currAction == OPCODE_SOUND) + else if (_currAction == _menu._opcodeSound) fctSound(); - if (_currAction == OPCODE_LEAVE) + else if (_currAction == _menu._opcodeLeave) fctLeave(); - if (_currAction == OPCODE_LIFT) + else if (_currAction == _menu._opcodeLift) fctLift(); - if (_currAction == OPCODE_TURN) + else if (_currAction == _menu._opcodeTurn) fctTurn(); - if (_currAction == OPCODE_SSEARCH) + else if (_currAction == _menu._opcodeSSearch) fctSelfSearch(); - if (_currAction == OPCODE_SREAD) + else if (_currAction == _menu._opcodeSRead) fctSelfRead(); - if (_currAction == OPCODE_SPUT) + else if (_currAction == _menu._opcodeSPut) fctSelfPut(); - if (_currAction == OPCODE_SLOOK) + else if (_currAction == _menu._opcodeSLook) fctSelftLook(); + _hiddenHero = false; - if (_currAction == OPCODE_SHIDE) + if (_currAction == _menu._opcodeSHide) fctSelfHide(); - } else { - if (_anyone) { - interactNPC(); - _anyone = false; - menuUp(); - return; - } + } else if (_anyone) { + interactNPC(); + _anyone = false; + menuUp(); + return; } int hour, day, minute; updateHour(day, hour, minute); @@ -1620,12 +1592,10 @@ void MortevielleEngine::handleOpcode() { if ((_coreVar._faithScore > 99) && (hour > 8) && (hour < 16)) { _crep = 1501; loseGame(); - } - if ((_coreVar._faithScore > 99) && (hour > 0) && (hour < 9)) { + } else if ((_coreVar._faithScore > 99) && (hour > 0) && (hour < 9)) { _crep = 1508; loseGame(); - } - if ((day > 1) && (hour > 8) && (!_loseGame)) { + } else if ((day > 1) && (hour > 8) && (!_loseGame)) { _crep = 1502; loseGame(); } @@ -1708,19 +1678,12 @@ void MortevielleEngine::clearVerbBar() { * @remarks Originally called 'clsf10' */ void MortevielleEngine::clearUpperRightPart() { - int x1, x2; Common::String st; _mouse.hideMouse(); - if (_resolutionScaler == 1) { - x2 = 634; - x1 = 534; - } else { - x2 = 600; - x1 = 544; - } + // Clear ambiance description - _screenSurface.fillRect(15, Common::Rect(x1, 93, x2, 98)); + _screenSurface.fillRect(15, Common::Rect(544, 93, 600, 98)); if (_coreVar._faithScore < 33) st = getEngineString(S_COOL); else if (_coreVar._faithScore < 66) @@ -1728,7 +1691,7 @@ void MortevielleEngine::clearUpperRightPart() { else if (_coreVar._faithScore > 65) st = getEngineString(S_MALSAINE); - x1 = 580 - (_screenSurface.getStringWidth(st) / 2); + int x1 = 580 - (_screenSurface.getStringWidth(st) / 2); _screenSurface.putxy(x1, 92); _screenSurface.drawString(st, 4); @@ -1750,7 +1713,7 @@ int MortevielleEngine::getRandomNumber(int minval, int maxval) { * @remarks Originally called 'aldepl' */ void MortevielleEngine::showMoveMenuAlert() { - _dialogManager.show(getEngineString(S_USE_DEP_MENU), 1); + _dialogManager.show(getEngineString(S_USE_DEP_MENU)); } /** @@ -1980,46 +1943,9 @@ void MortevielleEngine::resetVariables() { * @remarks Originally called 'writepal' */ void MortevielleEngine::setPal(int n) { - switch (_currGraphicalDevice) { - case MODE_TANDY: - case MODE_EGA: - case MODE_AMSTRAD1512: - for (int i = 1; i <= 16; ++i) { - _curPict[(2 * i)] = _stdPal[n][i].x; - _curPict[(2 * i) + 1] = _stdPal[n][i].y; - } - break; - case MODE_CGA: { - nhom pal[16]; - for (int i = 0; i < 16; ++i) { - pal[i] = _cgaPal[n]._a[i]; - } - - if (n < 89) - palette(_cgaPal[n]._p); - - for (int i = 0; i <= 15; ++i) - displayCGAPattern(i, &_patternArr[pal[i]._id], pal); - } - break; - default: - break; - } -} - -/** - * Engine function - Display a CGA pattern, using a specified palette - * @remarks Originally called 'outbloc' - */ -void MortevielleEngine::displayCGAPattern(int n, Pattern *p, nhom *pal) { - int addr = n * 404 + 0xd700; - - WRITE_LE_UINT16(&_curPict[addr], p->_tax); - WRITE_LE_UINT16(&_curPict[addr + 2], p->_tay); - addr += 4; - for (int i = 0; i < p->_tax; ++i) { - for (int j = 0; j < p->_tay; ++j) - _curPict[addr + j * p->_tax + i] = pal[n]._hom[p->_des[i + 1][j + 1]]; + for (int i = 1; i <= 16; ++i) { + _curPict[(2 * i)] = _stdPal[n][i].x; + _curPict[(2 * i) + 1] = _stdPal[n][i].y; } } @@ -2029,7 +1955,6 @@ void MortevielleEngine::displayCGAPattern(int n, Pattern *p, nhom *pal) { */ void MortevielleEngine::loadPalette() { Common::File f; - byte b; if (!f.open("fxx.mor")) { if (f.open("mfxx.mor")) @@ -2055,27 +1980,8 @@ void MortevielleEngine::loadPalette() { if (!f.open("cxx.mor")) error("Missing file - cxx.mor"); - for (int j = 0; j <= 90; ++j) { - _cgaPal[j]._p = f.readByte(); - for (int i = 0; i <= 15; ++i) { - nhom &with = _cgaPal[j]._a[i]; - - b = f.readByte(); - with._id = (uint)b >> 4; - with._hom[0] = ((uint)b >> 2) & 3; - with._hom[1] = b & 3; - } - } + // Skip CGA Palette and Patterns - _cgaPal[10]._a[9] = _cgaPal[10]._a[5]; - for (int j = 0; j <= 14; ++j) { - _patternArr[j]._tax = f.readByte(); - _patternArr[j]._tay = f.readByte(); - for (int i = 1; i <= 20; ++i) { - for (int k = 1; k <= 20; ++k) - _patternArr[j]._des[i][k] = f.readByte(); - } - } f.close(); } @@ -2088,8 +1994,8 @@ void MortevielleEngine::loadTexts() { Common::File ntpFile; _txxFileFl = false; - if (getLanguage() == Common::EN_ANY) { - warning("English version expected - Switching to DAT file"); + if (!useOriginalData()) { + warning("Using improved translation from DAT file"); return; } @@ -2216,13 +2122,11 @@ void MortevielleEngine::showTitleScreen() { _caff = 51; _text.taffich(); testKeyboard(); - if (_newGraphicalDevice != _currGraphicalDevice) - _currGraphicalDevice = _newGraphicalDevice; clearScreen(); draw(0, 0); Common::String cpr = "COPYRIGHT 1989 : LANKHOR"; - _screenSurface.putxy(104 + 72 * _resolutionScaler, 185); + _screenSurface.putxy(104 + 72 * kResolutionScaler, 185); _screenSurface.drawString(cpr, 0); } @@ -2243,9 +2147,6 @@ void MortevielleEngine::draw(int x, int y) { */ void MortevielleEngine::drawRightFrame() { setPal(89); - if (_currGraphicalDevice == MODE_HERCULES) - _curPict[14] = 15; - _mouse.hideMouse(); displayPicture(_rightFramePict, 0, 0); _mouse.showMouse(); @@ -2418,21 +2319,16 @@ void MortevielleEngine::drawClock() { const int x = 580; const int y = 123; const int rg = 9; - int hourColor; _mouse.hideMouse(); _screenSurface.drawRectangle(570, 118, 20, 10); _screenSurface.drawRectangle(578, 114, 6, 18); - if ((_currGraphicalDevice == MODE_CGA) || (_currGraphicalDevice == MODE_HERCULES)) - hourColor = 0; - else - hourColor = 1; if (_minute == 0) - _screenSurface.drawLine(((uint)x >> 1) * _resolutionScaler, y, ((uint)x >> 1) * _resolutionScaler, (y - rg), hourColor); + _screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y - rg), 1); else - _screenSurface.drawLine(((uint)x >> 1) * _resolutionScaler, y, ((uint)x >> 1) * _resolutionScaler, (y + rg), hourColor); + _screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)x >> 1) * kResolutionScaler, (y + rg), 1); int hour12 = _hour; if (hour12 > 12) @@ -2440,7 +2336,7 @@ void MortevielleEngine::drawClock() { if (hour12 == 0) hour12 = 12; - _screenSurface.drawLine(((uint)x >> 1) * _resolutionScaler, y, ((uint)(x + cv[0][hour12 - 1]) >> 1) * _resolutionScaler, y + cv[1][hour12 - 1], hourColor); + _screenSurface.drawLine(((uint)x >> 1) * kResolutionScaler, y, ((uint)(x + cv[0][hour12 - 1]) >> 1) * kResolutionScaler, y + cv[1][hour12 - 1], 1); _mouse.showMouse(); _screenSurface.putxy(568, 154); @@ -2486,20 +2382,6 @@ Common::String MortevielleEngine::copy(const Common::String &s, int idx, size_t * @remarks Originally called 'hirs' */ void MortevielleEngine::clearScreen() { - // Note: The original used this to set the graphics mode and clear the screen, both at - // the start of the game, and whenever the screen need to be cleared. As such, this - // method is deprecated in favour of clearing the screen - debugC(1, kMortevielleCore, "TODO: hirs is deprecated in favour of ScreenSurface::clearScreen"); - - if (_currGraphicalDevice == MODE_TANDY) { - _screenSurface.fillRect(0, Common::Rect(0, 0, 639, 200)); - _resolutionScaler = 1; - } else if (_currGraphicalDevice == MODE_CGA) { - palette(1); - _resolutionScaler = 1; - } else - _resolutionScaler = 2; - _screenSurface.clearScreen(); } @@ -2540,12 +2422,6 @@ void MortevielleEngine::displayControlMenu() { void MortevielleEngine::displayPicture(const byte *pic, int x, int y) { GfxSurface surface; surface.decode(pic); - - if (_currGraphicalDevice == MODE_HERCULES) { - _curPict[2] = 0; - _curPict[32] = 15; - } - _screenSurface.drawPicture(surface, x, y); } @@ -2592,14 +2468,8 @@ int MortevielleEngine::getAnimOffset(int frameNum, int animNum) { * @remarks Originally called 'text1' */ void MortevielleEngine::displayTextInDescriptionBar(int x, int y, int nb, int mesgId) { - int co; - - if (_resolutionScaler == 1) - co = 10; - else - co = 6; Common::String tmpStr = getString(mesgId); - if ((y == 182) && ((int) tmpStr.size() * co > nb * 6)) + if ((y == 182) && ((int) tmpStr.size() > nb)) y = 176; _text.displayStr(tmpStr, x, y, nb, 20, _textColor); } @@ -2612,7 +2482,7 @@ void MortevielleEngine::handleDescriptionText(int f, int mesgId) { if ((mesgId > 499) && (mesgId < 563)) { Common::String tmpStr = getString(mesgId - 501 + kInventoryStringIndex); - if ((int) tmpStr.size() > ((58 + (_resolutionScaler - 1) * 37) << 1)) + if ((int) tmpStr.size() > ((58 + (kResolutionScaler - 1) * 37) << 1)) _largestClearScreen = true; else _largestClearScreen = false; @@ -2629,7 +2499,7 @@ void MortevielleEngine::handleDescriptionText(int f, int mesgId) { displayTextInDescriptionBar(8, 182, 103, mesgId); if ((mesgId == 68) || (mesgId == 69)) _coreVar._availableQuestion[40] = '*'; - if ((mesgId == 104) && (_caff == CELLAR)) { + else if ((mesgId == 104) && (_caff == CELLAR)) { _coreVar._availableQuestion[36] = '*'; if (_coreVar._availableQuestion[39] == '*') { _coreVar._pctHintFound[3] = '*'; @@ -2721,7 +2591,7 @@ void MortevielleEngine::resetOpenObjects() { void MortevielleEngine::displayTextBlock(Common::String text) { // Some dead code was present in the original: removed _screenSurface.putxy(8, 177); - int tlig = 59 + (_resolutionScaler - 1) * 36; + int tlig = 59 + (kResolutionScaler - 1) * 36; if ((int)text.size() < tlig) _screenSurface.drawString(text, 5); @@ -2758,8 +2628,8 @@ void MortevielleEngine::displayItemInHand(int objId) { if (objId != 500) strp = getString(objId - 501 + kInventoryStringIndex); - _menu.setText(_menu._inventoryMenu[8]._menuId, _menu._inventoryMenu[8]._actionId, strp); - _menu.disableMenuItem(_menu._inventoryMenu[8]._menuId, _menu._inventoryMenu[8]._actionId); + _menu.setText(_menu._inventoryMenu[8], strp); + _menu.disableMenuItem(_menu._inventoryMenu[8]); } /** @@ -2906,34 +2776,54 @@ int MortevielleEngine::getPresence(int roomId) { displayAloneText(); else { int h = 0; - if (roomId == DINING_ROOM) + switch (roomId) { + case DINING_ROOM: pres = getPresenceStatsDiningRoom(h); - else if (roomId == BUREAU) + break; + case BUREAU: pres = getPresenceStatsBureau(h); - else if (roomId == KITCHEN) + break; + case KITCHEN: pres = getPresenceStatsKitchen(); - else if ((roomId == ATTIC) || (roomId == CELLAR)) + break; + case ATTIC: + case CELLAR: pres = getPresenceStatsAttic(); - else if ((roomId == LANDING) || (roomId == ROOM26)) + break; + case LANDING: + case ROOM26: pres = getPresenceStatsLanding(); - else if (roomId == CHAPEL) + break; + case CHAPEL: pres = getPresenceStatsChapel(h); + break; + } pres += _coreVar._faithScore; rand = getRandomNumber(1, 100); if (rand > pres) { displayAloneText(); retVal = 0; } else { - if (roomId == DINING_ROOM) + switch (roomId) { + case DINING_ROOM: pres = setPresenceDiningRoom(h); - else if (roomId == BUREAU) + break; + case BUREAU: pres = setPresenceBureau(h); - else if ((roomId == KITCHEN) || (roomId == ATTIC) || (roomId == CELLAR)) + break; + case KITCHEN: + case ATTIC: + case CELLAR: pres = setPresenceKitchen(); - else if ((roomId == LANDING) || (roomId == ROOM26)) + break; + case LANDING: + case ROOM26: pres = setPresenceLanding(); - else if (roomId == CHAPEL) + break; + case CHAPEL: pres = setPresenceChapel(h); + break; + } retVal = pres; } } @@ -2947,10 +2837,7 @@ int MortevielleEngine::getPresence(int roomId) { * @remarks Originally called 'writetp' */ void MortevielleEngine::displayQuestionText(Common::String s, int cmd) { - if (_resolutionScaler == 2) - _screenSurface.drawString(s, cmd); - else - _screenSurface.drawString(copy(s, 1, 25), cmd); + _screenSurface.drawString(s, cmd); } /** @@ -3000,18 +2887,27 @@ void MortevielleEngine::drawPicture() { displayAnimFrame(1, _openObjects[i]); } - if (_caff == ATTIC) { + switch (_caff) { + case ATTIC: if (_coreVar._atticBallHoleObjectId == 141) displayAnimFrame(1, 7); if (_coreVar._atticRodHoleObjectId == 159) displayAnimFrame(1, 6); - } else if ((_caff == CELLAR) && (_coreVar._cellarObjectId == 151)) - displayAnimFrame(1, 2); - else if ((_caff == SECRET_PASSAGE) && (_coreVar._secretPassageObjectId == 143)) - displayAnimFrame(1, 1); - else if ((_caff == WELL) && (_coreVar._wellObjectId != 0)) - displayAnimFrame(1, 1); + break; + case CELLAR: + if (_coreVar._cellarObjectId == 151) + displayAnimFrame(1, 2); + break; + case SECRET_PASSAGE: + if (_coreVar._secretPassageObjectId == 143) + displayAnimFrame(1, 1); + break; + case WELL: + if (_coreVar._wellObjectId != 0) + displayAnimFrame(1, 1); + break; + } } if (_caff < ROOM26) @@ -3319,12 +3215,12 @@ void MortevielleEngine::displayStatusArrow() { return; if (getMouseClick()) - inRect = (_mouse._pos.x < 256 * _resolutionScaler) && (_mouse._pos.y < 176) && (_mouse._pos.y > 12); + inRect = (_mouse._pos.x < 256 * kResolutionScaler) && (_mouse._pos.y < 176) && (_mouse._pos.y > 12); prepareRoom(); } while (!(qust || inRect || _anyone)); if (qust && (touch == '\103')) - _dialogManager.show(_hintPctMessage, 1); + _dialogManager.show(_hintPctMessage); } while (!((touch == '\73') || ((touch == '\104') && (_x != 0) && (_y != 0)) || (_anyone) || (inRect))); if (touch == '\73') @@ -3376,10 +3272,10 @@ void MortevielleEngine::setCoordinates(int sx) { cy = 1; do { cb += 2; - sx = _tabdon[a + cb] * _resolutionScaler; + sx = _tabdon[a + cb] * kResolutionScaler; sy = _tabdon[(a + cb + 1)]; cb += 2; - ix = _tabdon[a + cb] * _resolutionScaler; + ix = _tabdon[a + cb] * kResolutionScaler; iy = _tabdon[(a + cb + 1)]; ++cy; } while (!(((_x >= sx) && (_x <= ix) && (_y >= sy) && (_y <= iy)) || (cy > ib))); @@ -3400,7 +3296,7 @@ void MortevielleEngine::displayLookScreen(int objId) { int mdes = _caff; _caff = objId; - if (((_caff > 29) && (_caff < 33)) || (_caff == 144) || (_caff == 147) || (_caff == 149) || (_currAction == OPCODE_SLOOK)) { + if (((_caff > 29) && (_caff < 33)) || (_caff == 144) || (_caff == 147) || (_caff == 149) || (_currAction == _menu._opcodeSLook)) { drawPictureWithText(); if ((_caff > 29) && (_caff < 33)) handleDescriptionText(2, _caff); @@ -3465,17 +3361,8 @@ int MortevielleEngine::checkLeaveSecretPassage() { * @remarks Originally called 'fenat' */ void MortevielleEngine::displayStatusInDescriptionBar(char stat) { - int color; - _mouse.hideMouse(); - if (_currGraphicalDevice == MODE_CGA) - color = 2; - else if (_currGraphicalDevice == MODE_HERCULES) - color = 1; - else - color = 12; - - _screenSurface.writeCharacter(Common::Point(306, 193), stat, color); + _screenSurface.writeCharacter(Common::Point(306, 193), stat, 12); _screenSurface.drawBox(300, 191, 16, 8, 15); _mouse.showMouse(); } diff --git a/engines/sci/detection.cpp b/engines/sci/detection.cpp index 09c348f273..883a4d965b 100644 --- a/engines/sci/detection.cpp +++ b/engines/sci/detection.cpp @@ -105,9 +105,8 @@ static const PlainGameDescriptor s_sciGameTitles[] = { // === SCI2.1 games ======================================================== {"chest", "Inside the Chest"}, // aka Behind the Developer's Shield {"gk2", "The Beast Within: A Gabriel Knight Mystery"}, - // TODO: Inside The Chest/Behind the Developer's Shield {"kq7", "King's Quest VII: The Princeless Bride"}, - // TODO: King's Questions + {"kquestions", "King's Questions"}, {"lsl6hires", "Leisure Suit Larry 6: Shape Up or Slip Out!"}, {"mothergoosehires","Mixed-Up Mother Goose Deluxe"}, {"phantasmagoria", "Phantasmagoria"}, @@ -161,6 +160,7 @@ static const GameIdStrToEnum s_gameIdStrToEnum[] = { { "kq5", GID_KQ5 }, { "kq6", GID_KQ6 }, { "kq7", GID_KQ7 }, + { "kquestions", GID_KQUESTIONS }, { "laurabow", GID_LAURABOW }, { "laurabow2", GID_LAURABOW2 }, { "lighthouse", GID_LIGHTHOUSE }, @@ -242,6 +242,7 @@ static const OldNewIdTableEntry s_oldNewTable[] = { // kq5 is the same // kq6 is the same { "kq7cd", "kq7", SCI_VERSION_NONE }, + { "quizgame-demo", "kquestions", SCI_VERSION_NONE }, { "mm1", "laurabow", SCI_VERSION_NONE }, { "cb1", "laurabow", SCI_VERSION_NONE }, { "lb2", "laurabow2", SCI_VERSION_NONE }, diff --git a/engines/sci/detection_tables.h b/engines/sci/detection_tables.h index 7c4638a992..92e77cead9 100644 --- a/engines/sci/detection_tables.h +++ b/engines/sci/detection_tables.h @@ -1656,6 +1656,14 @@ static const struct ADGameDescription SciGameDescriptions[] = { AD_LISTEND}, Common::EN_ANY, Common::kPlatformWindows, ADGF_DEMO | ADGF_UNSTABLE, GUIO5(GUIO_NOSPEECH, GUIO_NOASPECT, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_ORIGINAL_SAVELOAD, GAMEOPTION_FB01_MIDI) }, + // King's Questions mini-game from the King's Quest Collection + // SCI interpreter version 2.000.000 + {"kquestions", "", { + {"resource.000", 0, "9b1cddecd4f0720d83661ba7aed28891", 162697}, + {"resource.map", 0, "93a2251fa64e729d7a7d2fe56b217c8e", 502}, + AD_LISTEND}, + Common::EN_ANY, Common::kPlatformDOS, ADGF_UNSTABLE, GUIO3(GUIO_NOSPEECH, GAMEOPTION_PREFER_DIGITAL_SFX, GAMEOPTION_FB01_MIDI) }, + #endif // ENABLE_SCI32 // Laura Bow - English Amiga diff --git a/engines/sci/engine/features.cpp b/engines/sci/engine/features.cpp index 6005ac50be..c26c787fbd 100644 --- a/engines/sci/engine/features.cpp +++ b/engines/sci/engine/features.cpp @@ -467,9 +467,9 @@ bool GameFeatures::autoDetectSci21KernelType() { // seen it happen in the RAMA demo, thus we can assume that the // game is using a SCI2.1 table - // HACK: The Inside the Chest Demo doesn't have sounds at all, but - // it's using a SCI2 kernel - if (g_sci->getGameId() == GID_CHEST) { + // HACK: The Inside the Chest Demo and King's Questions minigame + // don't have sounds at all, but they're using a SCI2 kernel + if (g_sci->getGameId() == GID_CHEST || g_sci->getGameId() == GID_KQUESTIONS) { _sci21KernelType = SCI_VERSION_2; return true; } diff --git a/engines/sci/engine/script_patches.cpp b/engines/sci/engine/script_patches.cpp index 20c5c52178..d4dddb6faf 100644 --- a/engines/sci/engine/script_patches.cpp +++ b/engines/sci/engine/script_patches.cpp @@ -953,10 +953,10 @@ const uint16 qfg1vgaPatchDialogHeader[] = { // When clicking on the crusher in room 331, Ego approaches him to talk to him, // an action that is handled by moveToCrusher::changeState in script 331. The -// scripts set Ego to move close to the crusher, but when Ego is running instead +// scripts set Ego to move close to the crusher, but when Ego is sneaking instead // of walking, the target coordinates specified by script 331 are never reached, // as Ego is making larger steps, and never reaches the required spot. This is an -// edge case that can occur when Ego is set to run. Normally, when clicking on +// edge case that can occur when Ego is set to sneak. Normally, when clicking on // the crusher, ego is supposed to move close to position 79, 165. We change it // to 85, 165, which is not an edge case thus the freeze is avoided. // Fixes bug #3585189. @@ -976,6 +976,25 @@ const uint16 qfg1vgaPatchMoveToCrusher[] = { PATCH_END }; +// Same pathfinding bug as above, where Ego is set to move to an impossible +// spot when sneaking. In GuardsTrumpet::changeState, we change the final +// location where Ego is moved from 111, 111 to 114, 114. Fixes bug #3604939. +const byte qfg1vgaSignatureMoveToCastleGate[] = { + 7, + 0x51, 0x1f, // class MoveTo + 0x36, // push + 0x39, 0x6f, // pushi 6f (111 - x) + 0x3c, // dup (111 - y) + 0x7c, // pushSelf + 0 +}; + +const uint16 qfg1vgaPatchMoveToCastleGate[] = { + PATCH_ADDTOOFFSET | +3, + 0x39, 0x72, // pushi 72 (114 - x) + PATCH_END +}; + // script, description, magic DWORD, adjust const SciScriptSignature qfg1vgaSignatures[] = { { 215, "fight event issue", 1, PATCH_MAGICDWORD(0x6d, 0x76, 0x51, 0x07), -1, qfg1vgaSignatureFightEvents, qfg1vgaPatchFightEvents }, @@ -983,6 +1002,7 @@ const SciScriptSignature qfg1vgaSignatures[] = { { 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 }, SCI_SIGNATUREENTRY_TERMINATOR }; diff --git a/engines/sci/engine/vm_types.cpp b/engines/sci/engine/vm_types.cpp index 27015d9be4..5327dd1a2e 100644 --- a/engines/sci/engine/vm_types.cpp +++ b/engines/sci/engine/vm_types.cpp @@ -28,12 +28,12 @@ namespace Sci { -reg_t reg_t::lookForWorkaround(const reg_t right) const { +reg_t reg_t::lookForWorkaround(const reg_t right, const char *operation) const { SciTrackOriginReply originReply; SciWorkaroundSolution solution = trackOriginAndFindWorkaround(0, arithmeticWorkarounds, &originReply); if (solution.type == WORKAROUND_NONE) - error("Invalid arithmetic operation (params: %04x:%04x and %04x:%04x) from method %s::%s (room %d, script %d, localCall %x)", - PRINT_REG(*this), PRINT_REG(right), originReply.objectName.c_str(), + error("Invalid arithmetic operation (%s - params: %04x:%04x and %04x:%04x) from method %s::%s (room %d, script %d, localCall %x)", + operation, PRINT_REG(*this), PRINT_REG(right), originReply.objectName.c_str(), originReply.methodName.c_str(), g_sci->getEngineState()->currentRoomNumber(), originReply.scriptNr, originReply.localCallOffset); assert(solution.type == WORKAROUND_FAKE); @@ -55,7 +55,7 @@ reg_t reg_t::operator+(const reg_t right) const { case SEG_TYPE_DYNMEM: return make_reg(getSegment(), getOffset() + right.toSint16()); default: - return lookForWorkaround(right); + return lookForWorkaround(right, "addition"); } } else if (isNumber() && right.isPointer()) { // Adding a pointer to a number, flip the order @@ -64,7 +64,7 @@ reg_t reg_t::operator+(const reg_t right) const { // Normal arithmetics return make_reg(0, toSint16() + right.toSint16()); } else { - return lookForWorkaround(right); + return lookForWorkaround(right, "addition"); } } @@ -82,14 +82,14 @@ reg_t reg_t::operator*(const reg_t right) const { if (isNumber() && right.isNumber()) return make_reg(0, toSint16() * right.toSint16()); else - return lookForWorkaround(right); + return lookForWorkaround(right, "multiplication"); } reg_t reg_t::operator/(const reg_t right) const { if (isNumber() && right.isNumber() && !right.isNull()) return make_reg(0, toSint16() / right.toSint16()); else - return lookForWorkaround(right); + return lookForWorkaround(right, "division"); } reg_t reg_t::operator%(const reg_t right) const { @@ -109,21 +109,21 @@ reg_t reg_t::operator%(const reg_t right) const { result += modulo; return make_reg(0, result); } else - return lookForWorkaround(right); + return lookForWorkaround(right, "modulo"); } reg_t reg_t::operator>>(const reg_t right) const { if (isNumber() && right.isNumber()) return make_reg(0, toUint16() >> right.toUint16()); else - return lookForWorkaround(right); + return lookForWorkaround(right, "shift right"); } reg_t reg_t::operator<<(const reg_t right) const { if (isNumber() && right.isNumber()) return make_reg(0, toUint16() << right.toUint16()); else - return lookForWorkaround(right); + return lookForWorkaround(right, "shift left"); } reg_t reg_t::operator+(int16 right) const { @@ -140,7 +140,7 @@ uint16 reg_t::requireUint16() const { else // The right parameter is NULL_REG because // we're not comparing *this with anything here. - return lookForWorkaround(NULL_REG).toUint16(); + return lookForWorkaround(NULL_REG, "require unsigned number").toUint16(); } int16 reg_t::requireSint16() const { @@ -149,28 +149,28 @@ int16 reg_t::requireSint16() const { else // The right parameter is NULL_REG because // we're not comparing *this with anything here. - return lookForWorkaround(NULL_REG).toSint16(); + return lookForWorkaround(NULL_REG, "require signed number").toSint16(); } reg_t reg_t::operator&(const reg_t right) const { if (isNumber() && right.isNumber()) return make_reg(0, toUint16() & right.toUint16()); else - return lookForWorkaround(right); + return lookForWorkaround(right, "bitwise AND"); } reg_t reg_t::operator|(const reg_t right) const { if (isNumber() && right.isNumber()) return make_reg(0, toUint16() | right.toUint16()); else - return lookForWorkaround(right); + return lookForWorkaround(right, "bitwise OR"); } reg_t reg_t::operator^(const reg_t right) const { if (isNumber() && right.isNumber()) return make_reg(0, toUint16() ^ right.toUint16()); else - return lookForWorkaround(right); + return lookForWorkaround(right, "bitwise XOR"); } int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { @@ -184,7 +184,7 @@ int reg_t::cmp(const reg_t right, bool treatAsUnsigned) const { } else if (right.pointerComparisonWithInteger(*this)) { return -1; } else - return lookForWorkaround(right).toSint16(); + return lookForWorkaround(right, "comparison").toSint16(); } bool reg_t::pointerComparisonWithInteger(const reg_t right) const { diff --git a/engines/sci/engine/vm_types.h b/engines/sci/engine/vm_types.h index 9a7589e9a7..22bd8beaa1 100644 --- a/engines/sci/engine/vm_types.h +++ b/engines/sci/engine/vm_types.h @@ -156,7 +156,7 @@ private: * - a negative number if *this < right */ int cmp(const reg_t right, bool treatAsUnsigned) const; - reg_t lookForWorkaround(const reg_t right) const; + reg_t lookForWorkaround(const reg_t right, const char *operation) const; bool pointerComparisonWithInteger(const reg_t right) const; }; diff --git a/engines/sci/engine/workarounds.cpp b/engines/sci/engine/workarounds.cpp index 6f0b34b457..49d6145607 100644 --- a/engines/sci/engine/workarounds.cpp +++ b/engines/sci/engine/workarounds.cpp @@ -37,6 +37,7 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = { { GID_ECOQUEST2, 100, 0, 0, "Rain", "points", 0xce0, 0, { WORKAROUND_FAKE, 0 } }, // Same as above, for the Spanish version - bug #3313962 { GID_FANMADE, 516, 983, 0, "Wander", "setTarget", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_mul: The Legend of the Lost Jewel Demo (fan made): called with object as second parameter when attacked by insects - bug #3038913 { GID_GK1, 800,64992, 0, "Fwd", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_gt: when Mosely finds Gabriel and Grace near the end of the game, compares the Grooper object with 7 + { GID_HOYLE4, 700, -1, 1, "Code", "doit", -1, 0, { WORKAROUND_FAKE, 1 } }, // op_add: while bidding in Bridge, an object ("Bid") is added to an object in another segment ("hand3") { GID_ICEMAN, 199, 977, 0, "Grooper", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_add: While dancing with the girl { GID_MOTHERGOOSE256, -1, 999, 0, "Event", "new", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_and: constantly during the game (SCI1 version) { GID_MOTHERGOOSE256, -1, 4, 0, "rm004", "doit", -1, 0, { WORKAROUND_FAKE, 0 } }, // op_or: when going north and reaching the castle (rooms 4 and 37) - bug #3038228 @@ -74,9 +75,11 @@ const SciWorkaroundEntry uninitializedReadWorkarounds[] = { { GID_HOYLE4, -1, 0, 0, NULL, "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when selecting "Control" from the menu (temp vars 0-3) - bug #3039294 { GID_HOYLE4, 910, 18, 0, NULL, "init", -1, 0, { WORKAROUND_FAKE, 0 } }, // during tutorial - bug #3042756 { GID_HOYLE4, 910, 910, 0, NULL, "setup", -1, 3, { WORKAROUND_FAKE, 0 } }, // when selecting "Tutorial" from the main menu - bug #3039294 - { GID_HOYLE4, 700, 718, 0, "compete_tree", "doit", -1, 75, { WORKAROUND_FAKE, 0 } }, // when placing a bid in bridge - bug #3292332 - { GID_HOYLE4, 700, 716, 0, "other1_tree", "doit", -1, 46, { WORKAROUND_FAKE, 0 } }, // sometimes when placing a bid in bridge - { GID_HOYLE4, 700, 700, 1, "BridgeHand", "calcQTS", -1, 3, { WORKAROUND_FAKE, 0 } }, // sometimes when placing a bid in bridge + { GID_HOYLE4, 700, 700, 1, "BridgeHand", "calcQTS", -1, 3, { WORKAROUND_FAKE, 0 } }, // when placing a bid in bridge (always) + { GID_HOYLE4, 700, 710, 1, "BridgeStrategyPlay", "checkSplitTops", -1, 10, { WORKAROUND_FAKE, 0 } }, // while playing bridge, objects LeadReturn_Trump, SecondSeat_Trump, ThirdSeat_Trump and others - bug #3361925 + { GID_HOYLE4, 700, -1, 1, "BridgeDefense", "think", -1, -1, { WORKAROUND_FAKE, 0 } }, // sometimes while playing bridge, temp var 3, 17 and others, objects LeadReturn_Trump, ThirdSeat_Trump and others + { GID_HOYLE4, 700, 730, 1, "BridgeDefense", "beatTheirBest", -1, 3, { WORKAROUND_FAKE, 0 } }, // rarely while playing bridge + { GID_HOYLE4, 700, -1, 1, "Code", "doit", -1, -1, { WORKAROUND_FAKE, 0 } }, // when placing a bid in bridge (always), temp var 11, 24, 27, 46, 75, objects compete_tree, compwe_tree, other1_tree, b1 - bugs #3292332 and #3361925 { GID_HOYLE4, 300, 300, 0, "", "export 2", 0x1d4d, 0, { WORKAROUND_FAKE, 0 } }, // after passing around cards in hearts { GID_HOYLE4, 400, 400, 1, "GinHand", "calcRuns", -1, 4, { WORKAROUND_FAKE, 0 } }, // sometimes while playing Gin Rummy (e.g. when knocking and placing a card) - bug #3292334 { GID_HOYLE4, 500, 17, 1, "Character", "say", -1, 504, { WORKAROUND_FAKE, 0 } }, // sometimes while playing Cribbage (e.g. when the opponent says "Last Card") - bug #3292327 diff --git a/engines/sci/graphics/picture.cpp b/engines/sci/graphics/picture.cpp index af372640da..91c72456a8 100644 --- a/engines/sci/graphics/picture.cpp +++ b/engines/sci/graphics/picture.cpp @@ -236,7 +236,9 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos byte *ptr = NULL; byte *headerPtr = inbuffer + headerPos; byte *rlePtr = inbuffer + rlePos; - int16 displaceX, displaceY; + // displaceX, displaceY fields are ignored, and may contain garbage + // (e.g. pic 261 in Dr. Brain 1 Spanish - bug #3614914) + //int16 displaceX, displaceY; byte priority = _addToFlag ? _priority : 0; byte clearColor; bool compression = true; @@ -251,8 +253,8 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos // Width/height here are always LE, even in Mac versions width = READ_LE_UINT16(headerPtr + 0); height = READ_LE_UINT16(headerPtr + 2); - displaceX = (signed char)headerPtr[4]; - displaceY = (unsigned char)headerPtr[5]; + //displaceX = (signed char)headerPtr[4]; + //displaceY = (unsigned char)headerPtr[5]; if (_resourceType == SCI_PICTURE_TYPE_SCI11) // SCI1.1 uses hardcoded clearcolor for pictures, even if cel header specifies otherwise clearColor = _screen->getColorWhite(); @@ -262,16 +264,16 @@ void GfxPicture::drawCelData(byte *inbuffer, int size, int headerPos, int rlePos } else { width = READ_SCI11ENDIAN_UINT16(headerPtr + 0); height = READ_SCI11ENDIAN_UINT16(headerPtr + 2); - displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!? - displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!? + //displaceX = READ_SCI11ENDIAN_UINT16(headerPtr + 4); // probably signed?!? + //displaceY = READ_SCI11ENDIAN_UINT16(headerPtr + 6); // probably signed?!? clearColor = headerPtr[8]; if (headerPtr[9] == 0) compression = false; } #endif - if (displaceX || displaceY) - error("unsupported embedded cel-data in picture"); + //if (displaceX || displaceY) + // error("unsupported embedded cel-data in picture"); // We will unpack cel-data into a temporary buffer and then plot it to screen // That needs to be done cause a mirrored picture may be requested diff --git a/engines/sci/sci.h b/engines/sci/sci.h index 3b9844b326..0a75e115fd 100644 --- a/engines/sci/sci.h +++ b/engines/sci/sci.h @@ -138,6 +138,7 @@ enum SciGameId { GID_KQ5, GID_KQ6, GID_KQ7, + GID_KQUESTIONS, GID_LAURABOW, GID_LAURABOW2, GID_LIGHTHOUSE, diff --git a/engines/scumm/actor.cpp b/engines/scumm/actor.cpp index 5c148a7b57..4e14473921 100644 --- a/engines/scumm/actor.cpp +++ b/engines/scumm/actor.cpp @@ -1485,7 +1485,7 @@ void ScummEngine::playActorSounds() { int sound; for (i = 1; i < _numActors; i++) { - if (_actors[i]->_cost.soundCounter && _actors[i]->isInCurrentRoom() && _actors[i]->_sound) { + if (_actors[i]->_cost.soundCounter && _actors[i]->isInCurrentRoom()) { _currentScript = 0xFF; if (_game.version == 0) { sound = v0ActorSounds[i - 1] & 0x3F; diff --git a/engines/scumm/detection_tables.h b/engines/scumm/detection_tables.h index aaf84c1471..6717ea9b06 100644 --- a/engines/scumm/detection_tables.h +++ b/engines/scumm/detection_tables.h @@ -299,7 +299,11 @@ static const GameSettings gameVariantsTable[] = { // Changed o_getResourceSize to cover all resource types {"farm", "", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, - {"puttzoo", "", 0, GID_HEGAME, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "", 0, GID_PUTTZOO, 6, 73, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 72", 0, GID_PUTTZOO, 6, 72, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 98.5", 0, GID_PUTTZOO, 6, 98, MDT_NONE, GF_USE_KEY | GF_HE_985, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 99", 0, GID_PUTTZOO, 6, 99, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, + {"puttzoo", "HE 100", 0, GID_PUTTZOO, 6, 100, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, // Added VAR_PLATFORM variable {"jungle", "", 0, GID_HEGAME, 6, 74, MDT_NONE, GF_USE_KEY, UNK, GUIO3(GUIO_NOLAUNCHLOAD, GUIO_NOMIDI, GUIO_NOASPECT)}, @@ -860,6 +864,7 @@ static const GameFilenamePattern gameFilenamesTable[] = { { "puttzoo", "Zoo Demo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttzoo", "Putt-Putt Saves the Zoo", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, { "puttzoo", "game", kGenHEPC, Common::EN_ANY, Common::kPlatformIOS, 0 }, + { "puttzoo", "pp3_unlocked", kGenHEPC, Common::EN_ANY, Common::kPlatformWindows, 0 }, { "SamsFunShop", "SamsFunShop", kGenHEPC, UNK_LANG, UNK, 0 }, { "SamsFunShop", "Sam's FunShop", kGenHEMac, UNK_LANG, Common::kPlatformMacintosh, 0 }, diff --git a/engines/scumm/gfx.cpp b/engines/scumm/gfx.cpp index 4c1fdaf673..1bb4a28f65 100644 --- a/engines/scumm/gfx.cpp +++ b/engines/scumm/gfx.cpp @@ -1769,11 +1769,8 @@ void Gdi::drawBitmap(const byte *ptr, VirtScreen *vs, int x, const int y, const // Check whether lights are turned on or not const bool lightsOn = _vm->isLightOn(); - if (_vm->_game.features & GF_SMALL_HEADER) { + if ((_vm->_game.features & GF_SMALL_HEADER) || _vm->_game.version == 8) { smap_ptr = ptr; - } else if (_vm->_game.version == 8) { - // Skip to the BSTR->WRAP->OFFS chunk - smap_ptr = ptr + 24; } else { smap_ptr = _vm->findResource(MKTAG('S','M','A','P'), ptr); assert(smap_ptr); @@ -1887,8 +1884,14 @@ bool Gdi::drawStrip(byte *dstPtr, VirtScreen *vs, int x, int y, const int width, smapLen = READ_LE_UINT32(smap_ptr); if (stripnr * 4 + 4 < smapLen) offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 4); + } else if (_vm->_game.version == 8) { + smapLen = READ_BE_UINT32(smap_ptr + 4); + // Skip to the BSTR->WRAP->OFFS chunk + smap_ptr += 24; + if (stripnr * 4 + 8 < smapLen) + offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 8); } else { - smapLen = READ_BE_UINT32(smap_ptr); + smapLen = READ_BE_UINT32(smap_ptr + 4); if (stripnr * 4 + 8 < smapLen) offset = READ_LE_UINT32(smap_ptr + stripnr * 4 + 8); } diff --git a/engines/scumm/he/script_v100he.cpp b/engines/scumm/he/script_v100he.cpp index b024154c7f..987f74957c 100644 --- a/engines/scumm/he/script_v100he.cpp +++ b/engines/scumm/he/script_v100he.cpp @@ -2148,7 +2148,7 @@ void ScummEngine_v100he::o100_systemOps() { break; case 132: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 133: quitGame(); diff --git a/engines/scumm/he/script_v70he.cpp b/engines/scumm/he/script_v70he.cpp index adb2fcac2e..9259e0db2f 100644 --- a/engines/scumm/he/script_v70he.cpp +++ b/engines/scumm/he/script_v70he.cpp @@ -309,7 +309,7 @@ void ScummEngine_v70he::o70_systemOps() { break; case 160: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 244: quitGame(); diff --git a/engines/scumm/he/script_v72he.cpp b/engines/scumm/he/script_v72he.cpp index f36f5cc130..42bf9a4bb6 100644 --- a/engines/scumm/he/script_v72he.cpp +++ b/engines/scumm/he/script_v72he.cpp @@ -158,7 +158,7 @@ int ScummEngine_v72he::readArray(int array, int idx2, int idx1) { ArrayHeader *ah = (ArrayHeader *)getResourceAddress(rtString, readVar(array)); - if (ah == NULL || ah->data == NULL) + if (!ah) error("readArray: invalid array %d (%d)", array, readVar(array)); if (idx2 < (int)FROM_LE_32(ah->dim2start) || idx2 > (int)FROM_LE_32(ah->dim2end) || @@ -1199,7 +1199,7 @@ void ScummEngine_v72he::o72_systemOps() { break; case 160: // Confirm shutdown - quitGame(); + confirmExitDialog(); break; case 244: quitGame(); diff --git a/engines/scumm/insane/insane_enemy.cpp b/engines/scumm/insane/insane_enemy.cpp index 3876966fd1..d711b63342 100644 --- a/engines/scumm/insane/insane_enemy.cpp +++ b/engines/scumm/insane/insane_enemy.cpp @@ -1519,6 +1519,7 @@ void Insane::chooseEnemyWeaponAnim(int32 buttons) { case INV_BOOT: case INV_HAND: case INV_DUST: + // fallthrough default: switchEnemyWeapon(); } diff --git a/engines/scumm/script_v6.cpp b/engines/scumm/script_v6.cpp index a75e864e7a..6983c51f30 100644 --- a/engines/scumm/script_v6.cpp +++ b/engines/scumm/script_v6.cpp @@ -394,7 +394,7 @@ ScummEngine_v6::ArrayHeader *ScummEngine_v6::getArray(int array) { int ScummEngine_v6::readArray(int array, int idx, int base) { ArrayHeader *ah = getArray(array); - if (ah == NULL || ah->data == NULL) + if (!ah) error("readArray: invalid array %d (%d)", array, readVar(array)); // WORKAROUND bug #645711. This is clearly a script bug, as this script diff --git a/engines/scumm/scumm-md5.h b/engines/scumm/scumm-md5.h index f5609f1b03..979573c5f5 100644 --- a/engines/scumm/scumm-md5.h +++ b/engines/scumm/scumm-md5.h @@ -1,5 +1,5 @@ /* - This file was generated by the md5table tool on Sat Aug 3 16:52:02 2013 + This file was generated by the md5table tool on Thu Aug 15 12:47:39 2013 DO NOT EDIT MANUALLY! */ @@ -344,6 +344,7 @@ static const MD5Table md5table[] = { { "78c07ca088526d8d4446a4c2cb501203", "freddi3", "HE 99", "", -1, Common::FR_FRA, Common::kPlatformUnknown }, { "7974365d3dc0f43a2748c975f91ff042", "monkey2", "", "", -1, Common::ES_ESP, Common::kPlatformDOS }, { "79b05f628586837e7166e82b2279bb50", "loom", "PC-Engine", "", -1, Common::JA_JPN, Common::kPlatformPCEngine }, + { "7b4ee071eecadc2d8cd0c3509110825c", "puttzoo", "HE 100", "Remastered", -1, Common::EN_ANY, Common::kPlatformWindows }, { "7bad72e332a59f9fcc1d437f4edad32a", "puttcircus", "", "", -1, Common::RU_RUS, Common::kPlatformUnknown }, { "7c2e76087027eeee9c8f8985f93a1cc5", "freddi4", "", "Demo", 13584, Common::EN_ANY, Common::kPlatformUnknown }, { "7c8100e360e8ef05f88069d4cfa0afd1", "puttrace", "HE 99", "Demo", 13108, Common::EN_GRB, Common::kPlatformWindows }, diff --git a/engines/scumm/scumm.h b/engines/scumm/scumm.h index a77c1c0141..ca05c90936 100644 --- a/engines/scumm/scumm.h +++ b/engines/scumm/scumm.h @@ -240,6 +240,7 @@ enum ScummGameId { GID_FBEAR, GID_PUTTMOON, GID_FUNPACK, + GID_PUTTZOO, GID_FREDDI3, GID_BIRTHDAYRED, GID_BIRTHDAYYELLOW, diff --git a/engines/scumm/vars.cpp b/engines/scumm/vars.cpp index 77c7daa0df..9c90d7575d 100644 --- a/engines/scumm/vars.cpp +++ b/engines/scumm/vars.cpp @@ -714,6 +714,12 @@ void ScummEngine_v99he::resetScummVars() { VAR(140) = 0; #endif } + + if (_game.id == GID_PUTTZOO && _game.heversion == 100 && _game.platform == Common::kPlatformWindows) { + // Specific to Nimbus Games version. + VAR(156) = 1; + VAR(157) = 0; + } } #endif diff --git a/engines/testbed/graphics.cpp b/engines/testbed/graphics.cpp index 590e6c6d81..26e073d407 100644 --- a/engines/testbed/graphics.cpp +++ b/engines/testbed/graphics.cpp @@ -927,17 +927,29 @@ TestExitStatus GFXtests::overlayGraphics() { Graphics::PixelFormat pf = g_system->getOverlayFormat(); - OverlayColor buffer[50 * 100]; - OverlayColor value = pf.RGBToColor(0, 255, 0); + byte *buffer = new byte[50 * 100 * pf.bytesPerPixel]; + const uint32 value = pf.RGBToColor(0, 255, 0); - for (int i = 0; i < 50 * 100; i++) { - buffer[i] = value; + if (pf.bytesPerPixel == 2) { + uint16 *dst = (uint16 *)buffer; + for (int i = 50 * 100; i > 0; --i) { + *dst++ = value; + } + } else if (pf.bytesPerPixel == 4) { + uint32 *dst = (uint32 *)buffer; + for (int i = 50 * 100; i > 0; --i) { + *dst++ = value; + } + } else { + error("GFXtests::overlayGraphics: Unsupported color depth: %d", pf.bytesPerPixel); } g_system->showOverlay(); - g_system->copyRectToOverlay(buffer, 200, 270, 175, 100, 50); + g_system->copyRectToOverlay(buffer, 100 * pf.bytesPerPixel, 270, 175, 100, 50); g_system->updateScreen(); + delete[] buffer; + g_system->delayMillis(1000); g_system->hideOverlay(); diff --git a/engines/tinsel/detection_tables.h b/engines/tinsel/detection_tables.h index a945672da2..cc8166f295 100644 --- a/engines/tinsel/detection_tables.h +++ b/engines/tinsel/detection_tables.h @@ -478,6 +478,26 @@ static const TinselGameDescription gameDescriptions[] = { }, #endif + { // Mac English CD, see tracker #3614864 + { + "dw", + "CD", + { + {"dw.scn", 0, "114643df0d1f1530a0a9c5d4e38917bc", 1268553}, + {"english.smp", 0, NULL, -1}, + {NULL, 0, NULL, 0} + }, + Common::EN_ANY, + Common::kPlatformMacintosh, + ADGF_CD, + GUIO0() + }, + GID_DW1, + 0, + GF_SCNFILES | GF_ENHANCED_AUDIO_SUPPORT, + TINSEL_V1, + }, + { // Mac multilanguage CD { "dw", diff --git a/engines/tsage/blue_force/blueforce_scenes0.cpp b/engines/tsage/blue_force/blueforce_scenes0.cpp index 95598babc6..f1f00599e0 100644 --- a/engines/tsage/blue_force/blueforce_scenes0.cpp +++ b/engines/tsage/blue_force/blueforce_scenes0.cpp @@ -888,6 +888,7 @@ void Scene60::Action1::signal() { break; case 4: remove(); + break; case 5: setDelay(120); break; diff --git a/engines/tsage/blue_force/blueforce_scenes1.cpp b/engines/tsage/blue_force/blueforce_scenes1.cpp index 9f1e9ce36e..32d87581c0 100644 --- a/engines/tsage/blue_force/blueforce_scenes1.cpp +++ b/engines/tsage/blue_force/blueforce_scenes1.cpp @@ -3237,7 +3237,7 @@ void Scene190::postInit(SceneObjectList *OwnerList) { BF_GLOBALS._player.postInit(); BF_GLOBALS._player.disableControl(); - // Initialise objects + // Initialize objects _door.postInit(); _door.setVisage(190); _door.setStrip(1); diff --git a/engines/tsage/blue_force/blueforce_scenes5.cpp b/engines/tsage/blue_force/blueforce_scenes5.cpp index abadc4300a..25accbb8a6 100644 --- a/engines/tsage/blue_force/blueforce_scenes5.cpp +++ b/engines/tsage/blue_force/blueforce_scenes5.cpp @@ -1459,7 +1459,7 @@ void Scene560::postInit(SceneObjectList *OwnerList) { _lamp.setDetails(Rect(197, 43, 214, 56), 560, 7, 19, 30, 1, NULL); _item4.setDetails(Rect(121, 18, 156, 54), 560, 8, 20, 31, 1, NULL); _trophy.setDetails(Rect(259, 52, 275, 63), 560, 10, 22, 33, 1, NULL); - _watercolours.setDetails(Rect(214, 48, 239, 64), 560, 12, 24, 35, 1, NULL); + _waterColors.setDetails(Rect(214, 48, 239, 64), 560, 12, 24, 35, 1, NULL); _fileCabinets.setDetails(Rect(0, 47, 49, 100), 560, 14, 26, 37, 1, NULL); _certificate.setDetails(Rect(280, 51, 292, 62), 560, 11, 23, 34, 1, NULL); _bookcase.setDetails(Rect(176, 0, 319, 103), 560, 9, 21, 32, 1, NULL); diff --git a/engines/tsage/blue_force/blueforce_scenes5.h b/engines/tsage/blue_force/blueforce_scenes5.h index 73d323fc54..56bf20c93b 100644 --- a/engines/tsage/blue_force/blueforce_scenes5.h +++ b/engines/tsage/blue_force/blueforce_scenes5.h @@ -225,7 +225,7 @@ public: NamedObject _object6; PicturePart _picture1, _picture2, _picture3, _picture4; Computer _computer; - NamedHotspot _chair, _lamp, _item4, _trophy, _watercolours, _fileCabinets; + NamedHotspot _chair, _lamp, _item4, _trophy, _waterColors, _fileCabinets; NamedHotspot _certificate, _bookcase, _desk, _carpet, _item12, _office; ASound _sound1; bool _field380; diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index 753a835389..9828ca71d4 100644 --- a/engines/tsage/converse.cpp +++ b/engines/tsage/converse.cpp @@ -707,7 +707,7 @@ void StripManager::synchronize(Serializer &s) { for (int i = 0; i < arrSize; ++i) _obj44List[i].synchronize(s); - // Synhcronise script data + // Synchronize script data int scriptSize = _script.size(); s.syncAsUint16LE(scriptSize); if (s.isLoading()) @@ -754,6 +754,9 @@ void StripManager::remove() { if (_onEnd) _onEnd(); + if (g_vm->getGameID() == GType_Ringworld2) + _endHandler = NULL; + Action::remove(); } @@ -855,6 +858,11 @@ void StripManager::signal() { ++obj44Idx; if (_obj44List[obj44Idx]._field16[0]) { + // WORKAROUND: The _lookupList isn't always correctly initialized. But it always + // seems to be set to the R2_GLOBALS._stripManager_lookupList, so manually set it + if (!_lookupList) + _lookupList = R2_GLOBALS._stripManager_lookupList; + int f16Index = _lookupList[_obj44List[obj44Idx]._field16[0] - 1]; listId = _obj44List[obj44Idx]._field16[f16Index]; @@ -865,13 +873,16 @@ void StripManager::signal() { choiceStr = (const char *)&_script[0] + _obj44List[obj44Idx]._list[listIdx]._scriptOffset; } else { - for (int listIdx = 0; listIdx < OBJ0A_LIST_SIZE; ++listIdx) { + for (int listIdx = idx; listIdx < (OBJ0A_LIST_SIZE - 1); ++listIdx) { obj44._list[listIdx]._id = obj44._list[listIdx + 1]._id; obj44._list[listIdx]._scriptOffset = obj44._list[listIdx + 1]._scriptOffset; if (!obj44._list[listIdx + 1]._id) obj44._list[listIdx]._id = 0; } + + --idx; + continue; } } } diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index 6b4e2963a5..0080226cbe 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -2111,8 +2111,13 @@ int SceneObject::getFrameCount() { void SceneObject::animEnded() { _animateMode = ANIM_MODE_NONE; - if (_endAction) - _endAction->signal(); + if (_endAction) { + Action *endAction = _endAction; + if (g_vm->getGameID() == GType_Ringworld2) + _endAction = NULL; + + endAction->signal(); + } } int SceneObject::changeFrame() { @@ -3992,7 +3997,7 @@ int WalkRegions::indexOf(const Common::Point &pt, const Common::List<int> *index } void WalkRegions::synchronize(Serializer &s) { - // Synchronise the list of disabled regions as a list of values terminated with a '-1' + // Synchronize the list of disabled regions as a list of values terminated with a '-1' int regionId = 0; if (s.isLoading()) { _disabledRegions.clear(); @@ -4242,9 +4247,10 @@ void SceneHandler::process(Event &event) { // Scan the item list to find one the mouse is within SynchronizedList<SceneItem *>::iterator i; for (i = g_globals->_sceneItems.begin(); i != g_globals->_sceneItems.end(); ++i) { - if ((*i)->contains(event.mousePos)) { + SceneItem *item = *i; + if (item->contains(event.mousePos)) { // Pass the action to the item - bool handled = (*i)->startAction(g_globals->_events.getCursor(), event); + bool handled = item->startAction(g_globals->_events.getCursor(), event); if (!handled) // Item wasn't handled, keep scanning continue; diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 5c4fa967e5..71ea160cf5 100644 --- a/engines/tsage/globals.cpp +++ b/engines/tsage/globals.cpp @@ -26,6 +26,7 @@ #include "tsage/ringworld/ringworld_demo.h" #include "tsage/ringworld/ringworld_logic.h" #include "tsage/ringworld2/ringworld2_logic.h" +#include "tsage/staticres.h" namespace TsAGE { @@ -389,7 +390,7 @@ void Ringworld2Globals::reset() { _scrollFollower = &_player; // Reset fields - Common::fill(&_fadePaletteMap[0][0], &_fadePaletteMap[10][256], 0); + Common::fill(&_fadePaletteMap[0][0], &_fadePaletteMap[9][256], 0); Common::fill(&_paletteMap[0], &_paletteMap[4096], 0); _fadePaletteFlag = false; @@ -404,7 +405,7 @@ void Ringworld2Globals::reset() { _v565E7 = 0; _v565E9 = -5; _v565EB = 26; - _v565F5 = 0; + _foodCount = 0; _v565F6 = 0; _v565F8 = 0; _v565FA = 0; @@ -449,7 +450,7 @@ void Ringworld2Globals::reset() { _v56613[(17 * 4) + 1] = 1; _v566A6 = 3800; - _v566A3 = 2; + _landerSuitNumber = 2; _v566A4 = 1; _v566A5 = 0; _v566A8 = 5; @@ -475,15 +476,12 @@ void Ringworld2Globals::reset() { _v5780E = 0; _v57810 = 0; _v57C2C = 0; - _v565EC[0] = 0; - _v565EC[1] = 27; - _v565EC[2] = 27; - _v565EC[3] = 4; - _v565EC[4] = 4; + _s1550PlayerArea[R2_QUINN] = Common::Point(27, 4); + _s1550PlayerArea[R2_SEEKER] = Common::Point(27, 4); Common::fill(&_scannerFrequencies[0], &_scannerFrequencies[MAX_CHARACTERS], 1); _speechSubtitles = SPEECH_VOICE | SPEECH_TEXT; _insetUp = 0; - _frameEdgeColour = 2; + _frameEdgeColor = 2; Common::fill(&_stripManager_lookupList[0], &_stripManager_lookupList[12], 0); _stripManager_lookupList[0] = 1; _stripManager_lookupList[1] = 1; @@ -496,6 +494,10 @@ void Ringworld2Globals::reset() { _stripManager_lookupList[10] = 1; _stripManager_lookupList[11] = 1; + // Reset junk/component data in scene 1550 + Common::copy(&scene1550JunkLocationsDefault[0], &scene1550JunkLocationsDefault[508], + &_scene1550JunkLocations[0]); + // Reset fields stored in the player class _player._characterIndex = R2_QUINN; _player._characterScene[1] = 100; @@ -519,11 +521,11 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsSint16LE(_v565E7); s.syncAsSint16LE(_v565E9); s.syncAsSint16LE(_v565EB); - s.syncAsSint16LE(_v565F5); + s.syncAsSint16LE(_foodCount); s.syncAsSint16LE(_v565F6); s.syncAsSint16LE(_v565F8); s.syncAsSint16LE(_v565FA); - s.syncAsSint16LE(_v566A3); + s.syncAsSint16LE(_landerSuitNumber); s.syncAsSint16LE(_v566A6); s.syncAsSint16LE(_v56A93); s.syncAsSint16LE(_scene1925CurrLevel); // _v56A9C @@ -539,8 +541,12 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsSint16LE(_v57C2C); s.syncAsSint16LE(_speechSubtitles); - for (i = 0; i < 5; i++) - s.syncAsByte(_v565EC[i]); + byte temp; + s.syncAsByte(temp); + s.syncAsByte(_s1550PlayerArea[R2_QUINN].x); + s.syncAsByte(_s1550PlayerArea[R2_SEEKER].x); + s.syncAsByte(_s1550PlayerArea[R2_QUINN].y); + s.syncAsByte(_s1550PlayerArea[R2_SEEKER].y); for (i = 0; i < MAX_CHARACTERS; ++i) s.syncAsByte(_scannerFrequencies[i]); @@ -566,7 +572,10 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsByte(_stripManager_lookupList[i]); s.syncAsSint16LE(_insetUp); - s.syncAsByte(_frameEdgeColour); + s.syncAsByte(_frameEdgeColor); + + for (i = 0; i < 508; i += 4) + s.syncAsByte(_scene1550JunkLocations[i + 2]); } } // end of namespace Ringworld2 diff --git a/engines/tsage/globals.h b/engines/tsage/globals.h index ed27ff0556..839895cea5 100644 --- a/engines/tsage/globals.h +++ b/engines/tsage/globals.h @@ -242,11 +242,6 @@ namespace Ringworld2 { #define SPEECH_TEXT 1 #define SPEECH_VOICE 2 -#define k5A78C 15 -#define k5A78D 16 -#define k5A790 18 -#define k5A791 17 - class ScannerDialog; class Ringworld2Globals: public TsAGE2Globals { @@ -258,7 +253,7 @@ public: byte _fadePaletteMap[10][256]; byte _paletteMap[4096]; int _insetUp; - int _frameEdgeColour; // _v421e + int _frameEdgeColor; // _v421e Rect _v5589E; Rect _v558B6; int _v558C2; @@ -269,7 +264,7 @@ public: int _v565E7; int _v565E9; int _v565EB; - int _v565F5; + int _foodCount; int _v565F6; int _v565F8; int _v565FA; @@ -280,7 +275,7 @@ public: byte _v566A4; byte _v566A5; int _v566A6; - byte _v566A3; + byte _landerSuitNumber; byte _v566A8; byte _v566A9; byte _v566AA; @@ -304,9 +299,10 @@ public: int _v57810; int _v57C2C; int _speechSubtitles; - byte _v565EC[5]; + Common::Point _s1550PlayerArea[3]; // only used for Quinn and Seeker byte _scannerFrequencies[4]; byte _stripManager_lookupList[12]; + byte _scene1550JunkLocations[508]; ScannerDialog *_scannerDialog; Ringworld2Globals(); diff --git a/engines/tsage/graphics.cpp b/engines/tsage/graphics.cpp index 1815c3d751..2395cc67ed 100644 --- a/engines/tsage/graphics.cpp +++ b/engines/tsage/graphics.cpp @@ -806,20 +806,20 @@ void GfxElement::drawFrame() { *((byte *)surface.getBasePtr(tempRect.right - 1, tempRect.bottom - 1)) = 0; // Inner frame border - surface.hLine(tempRect.left + 2, tempRect.top + 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColour); - surface.hLine(tempRect.left + 2, tempRect.bottom - 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColour); - surface.vLine(tempRect.left + 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColour); - surface.vLine(tempRect.right - 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColour); - *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColour; - *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColour; - *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColour; - *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColour; + surface.hLine(tempRect.left + 2, tempRect.top + 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColor); + surface.hLine(tempRect.left + 2, tempRect.bottom - 1, tempRect.right - 2, R2_GLOBALS._frameEdgeColor); + surface.vLine(tempRect.left + 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColor); + surface.vLine(tempRect.right - 1, tempRect.top + 2, tempRect.bottom - 2, R2_GLOBALS._frameEdgeColor); + *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColor; + *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.top + 2)) = R2_GLOBALS._frameEdgeColor; + *((byte *)surface.getBasePtr(tempRect.left + 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColor; + *((byte *)surface.getBasePtr(tempRect.right - 2, tempRect.bottom - 2)) = R2_GLOBALS._frameEdgeColor; gfxManager.unlockSurface(); gfxManager.getSurface().addDirtyRect(tempRect); } else { - // Fill dialog content with specified background colour + // Fill dialog content with specified background color gfxManager.fillRect(tempRect, _colors.background); --tempRect.bottom; --tempRect.right; diff --git a/engines/tsage/ringworld2/ringworld2_dialogs.cpp b/engines/tsage/ringworld2/ringworld2_dialogs.cpp index 57fdef6405..e2afa574de 100644 --- a/engines/tsage/ringworld2/ringworld2_dialogs.cpp +++ b/engines/tsage/ringworld2/ringworld2_dialogs.cpp @@ -234,9 +234,9 @@ void CharacterDialog::show() { SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene; scene->saveCharacter(oldCharacter); - // Play a transition sound as the character is changed + // Play the correctfrequency, if any, of the character being switched to's scanner device if (R2_GLOBALS._player._characterScene[0] != 300) { - switch (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] - 1) { case 0: R2_GLOBALS._sound4.stop(); break; @@ -256,7 +256,7 @@ void CharacterDialog::show() { break; } } else if (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] > 1) { - switch (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._scannerFrequencies[R2_GLOBALS._player._characterIndex] - 1) { case 2: R2_GLOBALS._sound4.play(45); break; @@ -273,7 +273,7 @@ void CharacterDialog::show() { break; } } else if ((R2_GLOBALS._player._characterScene[1] == 300) && (R2_GLOBALS._scannerFrequencies[1] != 1)) { - switch (R2_GLOBALS._scannerFrequencies[1]) { + switch (R2_GLOBALS._scannerFrequencies[1] - 1) { case 2: R2_GLOBALS._sound4.play(45); break; @@ -294,7 +294,7 @@ void CharacterDialog::show() { } else if (R2_GLOBALS._scannerFrequencies[2] == 1) { R2_GLOBALS._sound4.stop(); } else { - switch (R2_GLOBALS._scannerFrequencies[1]) { + switch (R2_GLOBALS._scannerFrequencies[1] - 1) { case 2: R2_GLOBALS._sound4.play(45); break; diff --git a/engines/tsage/ringworld2/ringworld2_logic.cpp b/engines/tsage/ringworld2/ringworld2_logic.cpp index f1f9f9fe5a..a50dccda03 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.cpp +++ b/engines/tsage/ringworld2/ringworld2_logic.cpp @@ -133,6 +133,7 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Cutscene - Elevator return new Scene1530(); case 1550: + // Spaceport return new Scene1550(); case 1575: return new Scene1575(); @@ -337,7 +338,7 @@ void SceneExt::postInit(SceneObjectList *OwnerList) { // Exclude the bottom area of the screen to allow room for the UI T2_GLOBALS._interfaceY = UI_INTERFACE_Y; - // Initialise fields + // Initialize fields _action = NULL; _field12 = 0; _sceneMode = 0; @@ -358,6 +359,7 @@ void SceneExt::postInit(SceneObjectList *OwnerList) { void SceneExt::remove() { _sceneAreas.clear(); Scene::remove(); + R2_GLOBALS._uiElements._active = true; } void SceneExt::process(Event &event) { @@ -382,27 +384,6 @@ void SceneExt::dispatch() { Scene::dispatch(); } -void SceneExt::loadScene(int sceneNum) { - Scene::loadScene(sceneNum); - - _v51C34.top = 0; - _v51C34.bottom = 300; - - int prevScene = R2_GLOBALS._sceneManager._previousScene; - int sceneNumber = R2_GLOBALS._sceneManager._sceneNumber; - - if (((prevScene == -1) && (sceneNumber != 180) && (sceneNumber != 205) && (sceneNumber != 50)) || - (sceneNumber == 50) || ((prevScene == 205) && (sceneNumber == 100)) || - ((prevScene == 180) && (sceneNumber == 100))) { - // TODO: sub_17875 - R2_GLOBALS._uiElements._active = true; - R2_GLOBALS._uiElements.show(); - } else { - // Update the user interface - R2_GLOBALS._uiElements.updateInventory(); - } -} - bool SceneExt::display(CursorType action, Event &event) { switch (action) { case CURSOR_CROSSHAIRS: @@ -620,7 +601,7 @@ void SceneHandlerExt::postLoad(int priorSceneBeforeLoad, int currentSceneBeforeL R2_GLOBALS._gfxColors.foreground = 59; R2_GLOBALS._fontColors.background = 4; R2_GLOBALS._fontColors.foreground = 15; - R2_GLOBALS._frameEdgeColour = 2; + R2_GLOBALS._frameEdgeColor = 2; R2_GLOBALS._scenePalette.loadPalette(0); R2_GLOBALS._scenePalette.setEntry(255, 0xff, 0xff, 0xff); @@ -664,7 +645,7 @@ void SceneHandlerExt::setupPaletteMaps() { break; } - // Scan for the palette index with the closest matching colour + // Scan for the palette index with the closest matching color int threshold = 769; int foundIndex = -1; for (int pIndex2 = 223; pIndex2 >= 0; --pIndex2) { @@ -970,7 +951,8 @@ void Ringworld2InvObjectList::setObjectScene(int objectNum, int sceneNumber) { R2_GLOBALS._events.setCursor(CURSOR_USE); // Update the user interface if necessary - T2_GLOBALS._uiElements.updateInventory(); + T2_GLOBALS._uiElements.updateInventory( + (sceneNumber == R2_GLOBALS._player._characterIndex) ? objectNum : 0); } /** @@ -1324,7 +1306,7 @@ GfxSurface SceneActor::getFrame() { /*--------------------------------------------------------------------------*/ -SceneArea::SceneArea(): EventHandler() { +SceneArea::SceneArea(): SceneItem() { _enabled = true; _insideArea = false; _savedCursorNum = CURSOR_NONE; @@ -1428,6 +1410,7 @@ void SceneExit::process(Event &event) { /*--------------------------------------------------------------------------*/ void SceneAreaObject::remove() { + R2_GLOBALS._sceneItems.remove(this); _object1.remove(); SceneArea::remove(); --R2_GLOBALS._insetUp; @@ -1437,19 +1420,22 @@ void SceneAreaObject::process(Event &event) { if (_insetCount == R2_GLOBALS._insetUp) { CursorType cursor = R2_GLOBALS._events.getCursor(); - if (_bounds.contains(event.mousePos)) { + if (_object1._bounds.contains(event.mousePos)) { // Cursor moving in bounded area if (cursor == _cursorNum) { R2_GLOBALS._events.setCursor(_savedCursorNum); } } else if (event.mousePos.y < 168) { - if (_cursorNum != cursor) + if (_cursorNum != cursor) { // Cursor moved outside bounded area - R2_GLOBALS._events.setCursor(_savedCursorNum); - + _savedCursorNum = R2_GLOBALS._events.getCursor(); + R2_GLOBALS._events.setCursor(CURSOR_INVALID); + } + if (event.eventType == EVENT_BUTTON_DOWN) { - R2_GLOBALS._events.setCursor(_savedCursorNum); event.handled = true; + R2_GLOBALS._events.setCursor(_savedCursorNum); + remove(); } } } @@ -1469,7 +1455,7 @@ void SceneAreaObject::setDetails(int visage, int strip, int frameNumber, const C } void SceneAreaObject::setDetails(int resNum, int lookLineNum, int talkLineNum, int useLineNum) { - ((SceneHotspot *)(this))->setDetails(resNum, lookLineNum, talkLineNum, useLineNum, + _object1.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *)NULL); } @@ -1881,7 +1867,7 @@ bool AnimationPlayer::load(int animId, Action *endAction) { default: // ANIMPALMODE_CURR_PALETTE - // Use the closest matching colours in the currently active palette to those specified in the animation + // Use the closest matching colors in the currently active palette to those specified in the animation for (int idx = _subData._palStart; idx < (_subData._palStart + _subData._palSize); ++idx) { byte r = _subData._palData[idx * 3]; byte g = _subData._palData[idx * 3 + 1]; @@ -2269,14 +2255,14 @@ void ScannerDialog::Button::reset() { scanner._obj5.postInit(); scanner._obj5.setup(4, 4, 1); - scanner._obj5.setPosition(Common::Point(R2_GLOBALS._v565EC[1] + 145, - R2_GLOBALS._v565EC[3] + 59)); + scanner._obj5.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_QUINN].x + 145, + R2_GLOBALS._s1550PlayerArea[R2_QUINN].y + 59)); scanner._obj5.fixPriority(257); scanner._obj6.postInit(); scanner._obj6.setup(4, 4, 2); - scanner._obj6.setPosition(Common::Point(R2_GLOBALS._v565EC[2] + 145, - R2_GLOBALS._v565EC[4] + 59)); + scanner._obj6.setPosition(Common::Point(R2_GLOBALS._s1550PlayerArea[R2_SEEKER].x + 145, + R2_GLOBALS._s1550PlayerArea[R2_SEEKER].y + 59)); scanner._obj6.fixPriority(257); break; case 1700: @@ -2416,7 +2402,7 @@ void ScannerDialog::remove() { switch (R2_GLOBALS._sceneManager._sceneNumber) { case 1550: case 1700: - R2_GLOBALS._events.setCursor(R2_GLOBALS._player._canWalk ? CURSOR_ARROW : CURSOR_USE); + R2_GLOBALS._events.setCursor(R2_GLOBALS._player._canWalk ? CURSOR_WALK : CURSOR_USE); break; case 3800: case 3900: { diff --git a/engines/tsage/ringworld2/ringworld2_logic.h b/engines/tsage/ringworld2/ringworld2_logic.h index 1b4b7fca1f..2b2a28aff8 100644 --- a/engines/tsage/ringworld2/ringworld2_logic.h +++ b/engines/tsage/ringworld2/ringworld2_logic.h @@ -42,9 +42,8 @@ public: static Scene *createScene(int sceneNumber); }; -class SceneArea: public EventHandler { +class SceneArea: public SceneItem { public: - Rect _bounds; bool _enabled; bool _insideArea; CursorType _cursorNum; @@ -54,9 +53,12 @@ public: SceneArea(); void setDetails(const Rect &bounds, CursorType cursor); + virtual Common::String getClassName() { return "SceneArea"; } virtual void synchronize(Serializer &s); virtual void remove(); virtual void process(Event &event); + virtual bool startAction(CursorType action, Event &event) { return false; } + virtual void doAction(int action) {} }; class SceneExit: public SceneArea { @@ -99,7 +101,6 @@ public: virtual void remove(); virtual void process(Event &event); virtual void dispatch(); - virtual void loadScene(int sceneNum); virtual void refreshBackground(int xAmount, int yAmount); virtual void saveCharacter(int characterIndex); virtual void restore() {} diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.cpp b/engines/tsage/ringworld2/ringworld2_scenes0.cpp index 8d35fc7222..1439557d1e 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes0.cpp @@ -392,11 +392,11 @@ void Scene100::dispatch() { * *--------------------------------------------------------------------------*/ -bool Scene125::Object5::startAction(CursorType action, Event &event) { +bool Scene125::Food::startAction(CursorType action, Event &event) { if (action == CURSOR_USE) return true; - else - return SceneActor::startAction(action, event); + + return SceneActor::startAction(action, event); } /*--------------------------------------------------------------------------*/ @@ -631,9 +631,9 @@ void Scene125::postInit(SceneObjectList *OwnerList) { _infoDisk.setPosition(Common::Point(47, 167)); } - _object6.postInit(); - _object6.setup(162, 1, 1); - _object6.setPosition(Common::Point(214, 168)); + _foodDispenser.postInit(); + _foodDispenser.setup(162, 1, 1); + _foodDispenser.setPosition(Common::Point(214, 168)); _diskSlot.setDetails(Rect(27, 145, 81, 159), 126, 9, -1, -1, 1, NULL); _item3.setDetails(Rect(144, 119, 286, 167), 126, 6, 7, 8, 1, NULL); @@ -656,8 +656,8 @@ void Scene125::signal() { _icon4.postInit(); _icon4._sceneRegionId = 5; - _sceneMode = 2; setAction(&_sequenceManager, this, 127, &_icon1, &_icon2, &_icon3, &_icon4, &R2_GLOBALS._player, NULL); + _sceneMode = 2; break; case 2: _icon1.setup(160, 1, 1); @@ -698,7 +698,7 @@ void Scene125::signal() { _icon6._sceneRegionId = 8; consoleAction(5); - R2_GLOBALS._player.enableControl(); + R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; break; case 10: @@ -971,14 +971,17 @@ void Scene125::consoleAction(int id) { case 15: consoleAction(3); - if (R2_GLOBALS._v565F5 < 3) { + if (R2_GLOBALS._foodCount < 3) { R2_GLOBALS._player.disableControl(); - _object5.postInit(); - _object5.setup(162, 2, 2); - _object5.setPosition(Common::Point(216, UI_INTERFACE_Y)); + _food.postInit(); + _food.setup(162, 2, 2); + _food.setPosition(Common::Point(216, UI_INTERFACE_Y)); - R2_GLOBALS._v565F5 += 2; - } else if (R2_GLOBALS._v565F5 == 3) { + R2_GLOBALS._foodCount += 2; + + _sceneMode = 128; + this->setAction(&_sequenceManager, this, 128, &_foodDispenser, &_food, NULL); + } else if (R2_GLOBALS._foodCount == 3) { SceneItem::display2(126, 13); } else { SceneItem::display2(126, 14); @@ -987,13 +990,16 @@ void Scene125::consoleAction(int id) { case 16: consoleAction(3); - if (R2_GLOBALS._v565F5 < 4) { + if (R2_GLOBALS._foodCount < 4) { R2_GLOBALS._player.disableControl(); - _object5.postInit(); - _object5.setup(162, 2, 3); - _object5.setPosition(Common::Point(218, UI_INTERFACE_Y)); + _food.postInit(); + _food.setup(162, 2, 3); + _food.setPosition(Common::Point(218, UI_INTERFACE_Y)); - ++R2_GLOBALS._v565F5; + ++R2_GLOBALS._foodCount; + + _sceneMode = 128; + this->setAction(&_sequenceManager, this, 128, &_foodDispenser, &_food, NULL); } else { SceneItem::display2(126, 15); } @@ -1001,13 +1007,16 @@ void Scene125::consoleAction(int id) { case 17: consoleAction(3); - if (R2_GLOBALS._v565F5 < 4) { + if (R2_GLOBALS._foodCount < 4) { R2_GLOBALS._player.disableControl(); - _object5.postInit(); - _object5.setup(162, 2, 1); - _object5.setPosition(Common::Point(215, UI_INTERFACE_Y)); + _food.postInit(); + _food.setup(162, 2, 1); + _food.setPosition(Common::Point(215, UI_INTERFACE_Y)); + + ++R2_GLOBALS._foodCount; - ++R2_GLOBALS._v565F5; + _sceneMode = 128; + this->setAction(&_sequenceManager, this, 128, &_foodDispenser, &_food, NULL); } else { SceneItem::display2(126, 16); } @@ -1924,7 +1933,7 @@ void Scene180::restore() { R2_GLOBALS._gfxColors.foreground = 4; R2_GLOBALS._gfxColors.background = 3; R2_GLOBALS._fontColors.background = 3; - R2_GLOBALS._frameEdgeColour = 3; + R2_GLOBALS._frameEdgeColor = 3; break; case 1: @@ -1933,7 +1942,7 @@ void Scene180::restore() { R2_GLOBALS._gfxColors.foreground = 25; R2_GLOBALS._gfxColors.background = 43; R2_GLOBALS._fontColors.background = 48; - R2_GLOBALS._frameEdgeColour = 48; + R2_GLOBALS._frameEdgeColor = 48; break; case 2: @@ -1943,7 +1952,7 @@ void Scene180::restore() { R2_GLOBALS._gfxColors.background = 136; R2_GLOBALS._fontColors.background = 48; R2_GLOBALS._fontColors.foreground = 253; - R2_GLOBALS._frameEdgeColour = 48; + R2_GLOBALS._frameEdgeColor = 48; break; case 3: @@ -1952,7 +1961,7 @@ void Scene180::restore() { R2_GLOBALS._gfxColors.foreground = 84; R2_GLOBALS._gfxColors.background = 118; R2_GLOBALS._fontColors.background = 47; - R2_GLOBALS._frameEdgeColour = 48; + R2_GLOBALS._frameEdgeColor = 48; break; case 14: @@ -1962,7 +1971,7 @@ void Scene180::restore() { R2_GLOBALS._fontColors.foreground = 38; R2_GLOBALS._gfxColors.foreground = 192; R2_GLOBALS._gfxColors.background = 30; - R2_GLOBALS._frameEdgeColour = 48; + R2_GLOBALS._frameEdgeColor = 48; break; default: @@ -2026,7 +2035,7 @@ void Scene200::EastExit::changeScene() { Scene200 *scene = (Scene200 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._player.disableControl(); + R2_GLOBALS._player.disableControl(CURSOR_WALK); scene->_sceneMode = 206; scene->setAction(&scene->_sequenceManager, scene, 206, &R2_GLOBALS._player, NULL); } @@ -2035,7 +2044,7 @@ void Scene200::WestExit::changeScene() { Scene200 *scene = (Scene200 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._player.disableControl(); + R2_GLOBALS._player.disableControl(CURSOR_WALK); scene->_sceneMode = 208; scene->setAction(&scene->_sequenceManager, scene, 208, &R2_GLOBALS._player, NULL); } @@ -3142,7 +3151,7 @@ bool Scene300::Doorway::startAction(CursorType action, Event &event) { if (action == CURSOR_USE) { if ((R2_GLOBALS._player._characterIndex == R2_QUINN) && - (!R2_GLOBALS.getFlag(44) || R2_GLOBALS._player._characterScene[R2_MIRANDA] == 500)) { + (!R2_GLOBALS.getFlag(44) || R2_GLOBALS._player._characterScene[R2_SEEKER] == 500)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 301; scene->setAction(&scene->_sequenceManager1, scene, 301, &R2_GLOBALS._player, this, NULL); @@ -3559,7 +3568,7 @@ void Scene300::signal() { break; case 16: - if (_stripManager._field2E8 == 1) { + if (_stripManager._exitMode == 1) { R2_GLOBALS._player.setAction(NULL); R2_GLOBALS._sceneManager.changeScene(1000); } else { @@ -4813,6 +4822,11 @@ void Scene400::dispatch() { * *--------------------------------------------------------------------------*/ +Scene500::PanelDialog::Button::Button() { + _buttonId = 0; + _buttonDown = false; +} + bool Scene500::ControlPanel::startAction(CursorType action, Event &event) { Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene; @@ -4835,17 +4849,18 @@ bool Scene500::ControlPanel::startAction(CursorType action, Event &event) { /*--------------------------------------------------------------------------*/ -bool Scene500::Object2::startAction(CursorType action, Event &event) { +bool Scene500::Seeker::startAction(CursorType action, Event &event) { Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene; if (action == CURSOR_TALK) { R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._player._characterIndex == 1) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { scene->_stripNumber = R2_GLOBALS.getFlag(26) ? 1101 : 1103; } else { scene->_stripNumber = R2_GLOBALS.getFlag(26) ? 1102 : 1105; } + scene->_sceneMode = 524; scene->setAction(&scene->_sequenceManager1, scene, 524, &R2_GLOBALS._player, NULL); return true; } else { @@ -4853,7 +4868,7 @@ bool Scene500::Object2::startAction(CursorType action, Event &event) { } } -bool Scene500::Object3::startAction(CursorType action, Event &event) { +bool Scene500::Suit::startAction(CursorType action, Event &event) { Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene; switch (action) { @@ -4864,20 +4879,20 @@ bool Scene500::Object3::startAction(CursorType action, Event &event) { case CURSOR_USE: if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if ((_strip != 3) && (_strip != 7)) - SceneItem::display2(500, _strip); + SceneItem::display2(500, _strip + 25); else if (R2_GLOBALS.getFlag(26)) { R2_GLOBALS._player.disableControl(); scene->_stripNumber = 1103; scene->_sceneMode = 524; - scene->setAction(&scene->_sequenceManager1, scene, 524, &R2_GLOBALS._player, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 512, &R2_GLOBALS._player, NULL); } else if (!R2_GLOBALS.getFlag(28)) SceneItem::display2(500, 41); - else if (!R2_GLOBALS.getFlag(40)) + else if (!R2_GLOBALS.getFlag(25)) SceneItem::display2(500, 40); else { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 512; - scene->setAction(&scene->_sequenceManager1, scene, 524, &R2_GLOBALS._player, &scene->_object3, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 512, &R2_GLOBALS._player, &scene->_suit, NULL); R2_GLOBALS.setFlag(26); } } else { @@ -4893,7 +4908,7 @@ bool Scene500::Object3::startAction(CursorType action, Event &event) { else { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 515; - scene->setAction(&scene->_sequenceManager1, scene, 515, &R2_GLOBALS._player, &scene->_object3, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 515, &R2_GLOBALS._player, &scene->_suit, NULL); R2_GLOBALS.setFlag(28); } return true; @@ -4903,12 +4918,7 @@ bool Scene500::Object3::startAction(CursorType action, Event &event) { return true; default: - if (action < R2_LAST_INVENT) { - SceneItem::display2(500, action); - return true; - } else { - return SceneActor::startAction(action, event); - } + return SceneActor::startAction(action, event); } } @@ -4976,7 +4986,7 @@ bool Scene500::AirLock::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = (R2_GLOBALS._player._characterIndex == R2_QUINN) ? 521 : 522; scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, - &scene->_object2, &scene->_airLock, NULL); + &scene->_seeker, &scene->_airLock, NULL); return true; } else { return SceneActor::startAction(action, event); @@ -5045,7 +5055,36 @@ bool Scene500::Locker2::startAction(CursorType action, Event &event) { } } -bool Scene500::Object::startAction(CursorType action, Event &event) { +/*--------------------------------------------------------------------------*/ + +void Scene500::PanelDialog::setDetails(int visage, int strip, int frameNumber, + const Common::Point &pt) { + SceneAreaObject::setDetails(visage, strip, frameNumber, pt); + SceneAreaObject::setDetails(500, 43, 32, 45); + + _button1.setupButton(1); + _button2.setupButton(2); + _button3.setupButton(3); +} + +void Scene500::PanelDialog::remove() { + Scene500 *scene = (Scene500 *)BF_GLOBALS._sceneManager._scene; + scene->_sceneAreas.remove(&_button1); + scene->_sceneAreas.remove(&_button2); + scene->_sceneAreas.remove(&_button3); + + _button1.remove(); + _button2.remove(); + _button3.remove(); + + SceneAreaObject::remove(); + + R2_GLOBALS._player.disableControl(); + scene->_sceneMode = 511; + scene->setAction(&scene->_sequenceManager1, scene, 511, &R2_GLOBALS._player, NULL); +} + +bool Scene500::PanelDialog::Button::startAction(CursorType action, Event &event) { if (action == CURSOR_USE) { return false; } else { @@ -5053,6 +5092,119 @@ bool Scene500::Object::startAction(CursorType action, Event &event) { } } +void Scene500::PanelDialog::Button::setupButton(int buttonId) { + _buttonId = buttonId; + _buttonDown = false; + SceneActor::postInit(); + setup(500, 7, 1); + fixPriority(251); + + switch (_buttonId) { + case 1: + setPosition(Common::Point(139, 78)); + break; + case 2: + setPosition(Common::Point(139, 96)); + break; + case 3: + setPosition(Common::Point(139, 114)); + break; + default: + break; + } + + Scene500 *scene = (Scene500 *)BF_GLOBALS._sceneManager._scene; + scene->_sceneAreas.push_front(this); +} + +void Scene500::PanelDialog::Button::synchronize(Serializer &s) { + SceneActor::synchronize(s); + + s.syncAsSint16LE(_buttonId); + s.syncAsSint16LE(_buttonDown); +} + +void Scene500::PanelDialog::Button::process(Event &event) { + if ((event.eventType == EVENT_BUTTON_DOWN) && + (R2_GLOBALS._events.getCursor() == CURSOR_USE) && + _bounds.contains(event.mousePos) && !_buttonDown) { + _buttonDown = true; + event.handled = true; + setFrame(2); + } + + if ((event.eventType == EVENT_BUTTON_UP) && _buttonDown) { + setFrame(1); + _buttonDown = false; + event.handled = true; + + doButtonPress(); + } +} + +void Scene500::PanelDialog::Button::doButtonPress() { + Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene; + + if (R2_GLOBALS.getFlag(28)) { + SceneItem::display2(500, 48); + } else { + R2_GLOBALS._player.disableControl(); + scene->_sceneMode = _buttonId; + + switch (_buttonId) { + case 1: + if (--R2_GLOBALS._landerSuitNumber == 0) + R2_GLOBALS._landerSuitNumber = 3; + + if (R2_GLOBALS.getFlag(35)) { + scene->_sceneMode = 5; + scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_object1, + &scene->_suit, &scene->_object8, NULL); + } else { + scene->_sound1.play(127); + scene->_object1.animate(ANIM_MODE_6, scene); + } + break; + + case 2: + if (++R2_GLOBALS._landerSuitNumber == 4) + R2_GLOBALS._v566A4 = 1; + + if (R2_GLOBALS.getFlag(35)) { + scene->_sceneMode = 6; + scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_object1, + &scene->_suit, &scene->_object8, NULL); + } else { + scene->_sound1.play(127); + scene->_object1.animate(ANIM_MODE_6, scene); + } + break; + + case 3: + if (R2_GLOBALS.getFlag(35)) { + scene->_sceneMode = 509; + scene->setAction(&scene->_sequenceManager1, scene, 509, &scene->_object1, + &scene->_suit, &scene->_object8, NULL); + } else { + scene->_suit.postInit(); + scene->_suit.hide(); + scene->_suit._effect = 1; + scene->_suit.setDetails(500, -1, -1, -1, 2, (SceneItem *)NULL); + scene->_suit.setup(502, R2_GLOBALS._landerSuitNumber + 2, 1); + + scene->setAction(&scene->_sequenceManager1, scene, 508, + &R2_GLOBALS._player, &scene->_object1, &scene->_suit, + &scene->_object8, NULL); + R2_GLOBALS.setFlag(35); + } + break; + + default: + break; + } + } +} + /*--------------------------------------------------------------------------*/ void Scene500::postInit(SceneObjectList *OwnerList) { @@ -5071,23 +5223,23 @@ void Scene500::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._walkRegions.disableRegion(1); - _object2.postInit(); - _object2._effect = 1; - _object2.setup(1505, 1, 1); - _object2._moveDiff.x = 5; - _object2.setPosition(Common::Point(42, 151)); - _object2.setDetails(500, 34, 35, 36, 1, (SceneItem *)NULL); + _seeker.postInit(); + _seeker._effect = 1; + _seeker.setup(1505, 1, 1); + _seeker._moveDiff.x = 5; + _seeker.setPosition(Common::Point(42, 151)); + _seeker.setDetails(500, 34, 35, 36, 1, (SceneItem *)NULL); } else if (R2_GLOBALS._player._characterScene[R2_QUINN] == 500) { - _object2.postInit(); - _object2._effect = 1; - _object2.setup(R2_GLOBALS.getFlag(26) ? 1500 : 10, 1, 1); - _object2.setPosition(Common::Point(42, 151)); + _seeker.postInit(); + _seeker._effect = 1; + _seeker.setup(R2_GLOBALS.getFlag(26) ? 1500 : 10, 1, 1); + _seeker.setPosition(Common::Point(42, 151)); R2_GLOBALS._walkRegions.disableRegion(1); R2_GLOBALS._walkRegions.disableRegion(2); R2_GLOBALS._walkRegions.disableRegion(3); - _object2.setDetails(500, 37, 38, -1, 1, (SceneItem *)NULL); + _seeker.setDetails(500, 37, 38, -1, 1, (SceneItem *)NULL); } } @@ -5167,16 +5319,16 @@ void Scene500::postInit(SceneObjectList *OwnerList) { } else { _object8.setup(500, 8, 7); - _object3.postInit(); - _object3._effect = 1; - _object3.setPosition(Common::Point(247, 52)); - _object3.setDetails(500, -1, -1, -1, 2, (SceneItem *)NULL); + _suit.postInit(); + _suit._effect = 1; + _suit.setPosition(Common::Point(247, 52)); + _suit.setDetails(500, -1, -1, -1, 2, (SceneItem *)NULL); if (!R2_GLOBALS.getFlag(26)) { if (R2_GLOBALS.getFlag(28)) - _object3.setup(502, 7, 2); + _suit.setup(502, 7, 2); else - _object3.setup(502, R2_GLOBALS._v566A3 + 2, 7); + _suit.setup(502, R2_GLOBALS._landerSuitNumber + 2, 7); } } @@ -5222,7 +5374,7 @@ void Scene500::signal() { _object1.animate(ANIM_MODE_6, this); R2_GLOBALS.clearFlag(35); - _object3.remove(); + _suit.remove(); R2_GLOBALS._player.enableControl(); break; case 6: @@ -5231,7 +5383,7 @@ void Scene500::signal() { _object1.animate(ANIM_MODE_5, this); R2_GLOBALS.clearFlag(35); - _object3.remove(); + _suit.remove(); R2_GLOBALS._player.enableControl(); break; case 7: @@ -5239,14 +5391,14 @@ void Scene500::signal() { _object8.animate(ANIM_MODE_6, this); R2_GLOBALS.clearFlag(35); - _object3.remove(); + _suit.remove(); R2_GLOBALS._player.enableControl(); break; case 500: R2_GLOBALS._sceneManager.changeScene(700); break; case 501: - if (R2_GLOBALS._player._characterScene[R2_MIRANDA] == 500) { + if (R2_GLOBALS._player._characterScene[R2_SEEKER] == 500) { _stripNumber = 1100; _sceneMode = 523; setAction(&_sequenceManager1, this, 523, &R2_GLOBALS._player, NULL); @@ -5277,7 +5429,7 @@ void Scene500::signal() { break; case 506: case 518: - R2_GLOBALS.setFlag(11); + R2_GLOBALS.setFlag(12); R2_GLOBALS._player.enableControl(); break; case 507: @@ -5287,12 +5439,12 @@ void Scene500::signal() { break; case 509: R2_GLOBALS.clearFlag(35); - _object3.remove(); + _suit.remove(); R2_GLOBALS._player.enableControl(); break; case 510: R2_GLOBALS._player.enableControl(); - _area1.setDetails(500, 6, 1, Common::Point(160, 120)); + _panelDialog.setDetails(500, 6, 1, Common::Point(160, 120)); R2_GLOBALS._player.enableControl(); break; case 513: @@ -5391,22 +5543,22 @@ bool Scene600::Item4::startAction(CursorType action, Event &event) { Scene600 *scene = (Scene600 *)R2_GLOBALS._sceneManager._scene; scene->_object1.setup2(603, 3, 1, 239, 54, 10, 0); - scene->_actor3.postInit(); - scene->_actor2.postInit(); + scene->_stasisField.postInit(); + scene->_computer.postInit(); scene->_sceneMode = 612; - scene->setAction(&scene->_sequenceManager1, scene, 612, &scene->_actor3, &scene->_actor2, &R2_GLOBALS._player, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 612, &scene->_stasisField, &scene->_computer, &R2_GLOBALS._player, NULL); return true; } -void Scene600::Actor4::signal() { +void Scene600::Smoke::signal() { Common::Point pt(177 + R2_GLOBALS._randomSource.getRandomNumber(5), 108 + R2_GLOBALS._randomSource.getRandomNumber(3)); NpcMover *mover = new NpcMover(); addMover(mover, &pt, this); } -bool Scene600::Actor4::startAction(CursorType action, Event &event) { +bool Scene600::Smoke::startAction(CursorType action, Event &event) { if (action >= CURSOR_WALK) // Only action cursors return SceneActor::startAction(action, event); @@ -5414,7 +5566,7 @@ bool Scene600::Actor4::startAction(CursorType action, Event &event) { return false; } -GfxSurface Scene600::Actor4::getFrame() { +GfxSurface Scene600::Smoke::getFrame() { GfxSurface frame = SceneActor::getFrame(); if (_effect) { @@ -5435,7 +5587,8 @@ GfxSurface Scene600::Actor4::getFrame() { } bool Scene600::Doorway::startAction(CursorType action, Event &event) { - if ((action < CURSOR_WALK) && (action >= R2CURSORS_START)) + // Only action cursors + if (action < CURSOR_WALK) return false; if (action != CURSOR_USE) @@ -5478,16 +5631,17 @@ bool Scene600::Laser::startAction(CursorType action, Event &event) { if (action < CURSOR_WALK) { switch (action) { case R2_COM_SCANNER: + // If laser is destroyed if (R2_GLOBALS.getFlag(6)) { if (R2_GLOBALS.getFlag(8)) { SceneItem::display(600, 29, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); return true; } else { R2_GLOBALS._player.disableControl(); - scene->_actor8.postInit(); - scene->_actor8.setDetails(600, 20, -1, -1, 4, &scene->_laser); + scene->_scanner.postInit(); + scene->_scanner.setDetails(600, 20, -1, -1, 4, &scene->_laser); scene->_sceneMode = 607; - scene->setAction(&scene->_sequenceManager1, scene, 607, &R2_GLOBALS._player, &scene->_actor8, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 607, &R2_GLOBALS._player, &scene->_scanner, NULL); return true; } } else { @@ -5503,21 +5657,22 @@ bool Scene600::Laser::startAction(CursorType action, Event &event) { scene->_aerosol.postInit(); scene->_aerosol.setDetails(600, 27, -1, -1, 5, &scene->_laser); - scene->_actor4.postInit(); - scene->_actor4.setup(601, 3, 1); - scene->_actor4._effect = 3; - scene->_actor4._moveDiff = Common::Point(1, 1); - scene->_actor4._moveRate = 2; - scene->_actor4._numFrames = 3; - scene->_actor4.setDetails(600, 24, 25, 26, 5, &scene->_aerosol); + scene->_smoke.postInit(); + scene->_smoke.setup(601, 3, 1); + scene->_smoke._effect = 3; + scene->_smoke._moveDiff = Common::Point(1, 1); + scene->_smoke._moveRate = 2; + scene->_smoke._numFrames = 3; + scene->_smoke.setDetails(600, 24, 25, 26, 5, &scene->_aerosol); scene->_sceneMode = 605; - scene->setAction(&scene->_sequenceManager1, scene, 605, &R2_GLOBALS._player, &scene->_aerosol, &scene->_actor4, &scene->_doorway, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 605, &R2_GLOBALS._player, &scene->_aerosol, &scene->_smoke, &scene->_doorway, NULL); return true; } break; case R2_CLAMP: + // If cloud is active if (R2_GLOBALS.getFlag(5)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 606; @@ -5547,9 +5702,11 @@ bool Scene600::Laser::startAction(CursorType action, Event &event) { bool Scene600::Aerosol::startAction(CursorType action, Event &event) { Scene600 *scene = (Scene600 *)R2_GLOBALS._sceneManager._scene; - if ((action < CURSOR_WALK) && (action >= R2CURSORS_START)) { + // Only action cursors + if (action < CURSOR_WALK) return false; - } else if (action == CURSOR_USE) { + + if (action == CURSOR_USE) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 614; scene->setAction(&scene->_sequenceManager1, scene, 614, &R2_GLOBALS._player, &scene->_aerosol, NULL); @@ -5574,17 +5731,17 @@ void Scene600::synchronize(Serializer &s) { s.syncAsByte(_pixelMap[i]); } -bool Scene600::Actor8::startAction(CursorType action, Event &event) { +bool Scene600::Scanner::startAction(CursorType action, Event &event) { Scene600 *scene = (Scene600 *)R2_GLOBALS._sceneManager._scene; - if ((action == CURSOR_USE) && (R2_INVENTORY.getObjectScene(9) == 600)) { + if ((action == CURSOR_USE) && (R2_INVENTORY.getObjectScene(R2_COM_SCANNER) == 600)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 615; - scene->setAction(&scene->_sequenceManager1, scene, 615, &R2_GLOBALS._player, &scene->_actor8, NULL); - } else if ((action == R2_SONIC_STUNNER) && (R2_INVENTORY.getObjectScene(9) == 600) && (R2_GLOBALS._scannerFrequencies[1] == 2) && (!R2_GLOBALS.getFlag(8))){ + scene->setAction(&scene->_sequenceManager1, scene, 615, &R2_GLOBALS._player, &scene->_scanner, NULL); + } else if ((action == R2_SONIC_STUNNER) && (R2_INVENTORY.getObjectScene(R2_COM_SCANNER) == 600) && (R2_GLOBALS._scannerFrequencies[1] == 2) && (!R2_GLOBALS.getFlag(8))){ R2_GLOBALS._player.disableControl(); scene->_sceneMode = 608; - scene->setAction(&scene->_sequenceManager1, scene, 608, &R2_GLOBALS._player, &scene->_actor4, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 608, &R2_GLOBALS._player, &scene->_smoke, NULL); } else { return SceneActor::startAction(action, event); } @@ -5599,7 +5756,7 @@ void Scene600::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._walkRegions.enableRegion(3); _field412 = 0; - // Initialise pixel map for the obscuring effect + // Initialize pixel map for the obscuring effect ScenePalette &pal = R2_GLOBALS._scenePalette; uint r, g, b; for (int i = 0; i < 256; ++i) { @@ -5618,11 +5775,11 @@ void Scene600::postInit(SceneObjectList *OwnerList) { _laser.postInit(); _laser.setPosition(Common::Point(246, 41)); - if (R2_INVENTORY.getObjectScene(9) == 600) { - _actor8.postInit(); - _actor8.setup(602, 5, 1); - _actor8.setPosition(Common::Point(246, 41)); - _actor8.setDetails(600, 20, -1, -1, 1, (SceneItem *) NULL); + if (R2_INVENTORY.getObjectScene(R2_COM_SCANNER) == 600) { + _scanner.postInit(); + _scanner.setup(602, 5, 1); + _scanner.setPosition(Common::Point(246, 41)); + _scanner.setDetails(600, 20, -1, -1, 1, (SceneItem *) NULL); switch (R2_GLOBALS._scannerFrequencies[1] - 2) { case 0: R2_GLOBALS._sound4.play(45); @@ -5658,7 +5815,7 @@ void Scene600::postInit(SceneObjectList *OwnerList) { _object1.setup2(603, 1, 1, 244, 50, 10, 0); if (R2_GLOBALS.getFlag(5)) { - if (R2_INVENTORY.getObjectScene(12) == 600) { + if (R2_INVENTORY.getObjectScene(R2_AEROSOL) == 600) { _aerosol.postInit(); _aerosol.setup(602, 2, 2); _aerosol.setPosition(Common::Point(189, 95)); @@ -5667,23 +5824,25 @@ void Scene600::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS.getFlag(8)) { if (R2_GLOBALS.getFlag(9)) { - _actor2.postInit(); - _actor2.setup(603, 2, 1); - _actor2.setPosition(Common::Point(233, 45)); - _actor2.animate(ANIM_MODE_2, NULL);_actor2.fixPriority(11); + // Computer is active + _computer.postInit(); + _computer.setup(603, 2, 1); + _computer.setPosition(Common::Point(233, 45)); + _computer.animate(ANIM_MODE_2, NULL); + _computer.fixPriority(11); } } else { - _actor4.postInit(); - _actor4.setup(601, 1, 1); - _actor4.setPosition(Common::Point(180, 110)); - _actor4._moveDiff = Common::Point(1, 1); - _actor4._moveRate = 2; - _actor4._numFrames = 3; - _actor4.animate(ANIM_MODE_2, NULL); - _actor4.fixPriority(130); - _actor4._effect = 3; - _actor4.setDetails(600, 24, 25, 26, 1, (SceneItem *) NULL); - _actor4.signal(); + _smoke.postInit(); + _smoke.setup(601, 1, 1); + _smoke.setPosition(Common::Point(180, 110)); + _smoke._moveDiff = Common::Point(1, 1); + _smoke._moveRate = 2; + _smoke._numFrames = 3; + _smoke.animate(ANIM_MODE_2, NULL); + _smoke.fixPriority(130); + _smoke._effect = 3; + _smoke.setDetails(600, 24, 25, 26, 1, (SceneItem *) NULL); + _smoke.signal(); } } @@ -5727,7 +5886,7 @@ void Scene600::postInit(SceneObjectList *OwnerList) { } void Scene600::remove() { - if (R2_INVENTORY.getObjectScene(9) == 600) + if (R2_INVENTORY.getObjectScene(R2_COM_SCANNER) == 600) R2_GLOBALS._sound4.fadeOut2(NULL); SceneExt::remove(); } @@ -5742,6 +5901,7 @@ void Scene600::signal() { R2_GLOBALS._sceneManager.changeScene(700); break; case 605: + // After cloud is active R2_GLOBALS._player.enableControl(); R2_GLOBALS._walkRegions.enableRegion(6); R2_GLOBALS._walkRegions.enableRegion(7); @@ -5751,42 +5911,48 @@ void Scene600::signal() { R2_INVENTORY.setObjectScene(R2_AEROSOL, 600); R2_GLOBALS.setFlag(5); - _actor4._effect = 3; - _actor4.signal(); + _smoke._effect = 3; + _smoke.signal(); break; case 606: - R2_INVENTORY.setObjectScene(15, 600); + // After Clamp is put on laser + R2_INVENTORY.setObjectScene(R2_CLAMP, 600); R2_GLOBALS._player.enableControl(); break; case 607: - R2_INVENTORY.setObjectScene(9, 600); + // After scanner is put on laser + R2_INVENTORY.setObjectScene(R2_COM_SCANNER, 600); R2_GLOBALS._player.enableControl(); break; case 608: + // deactivate cloud R2_GLOBALS.setFlag(8); - _actor4.remove(); + _smoke.remove(); R2_GLOBALS._walkRegions.disableRegion(6); R2_GLOBALS._walkRegions.disableRegion(9); R2_GLOBALS._walkRegions.disableRegion(10); R2_GLOBALS._player.enableControl(); break; case 612: + // Deactivate stasis field R2_GLOBALS.setFlag(9); - _actor3.remove(); + _stasisField.remove(); R2_GLOBALS._sceneItems.remove(&_item4); - _actor2.setDetails(600, 21, -1, 23, 4, &_item4); + _computer.setDetails(600, 21, -1, 23, 4, &_item4); _background.setDetails(600, 7, -1, -1, 3, (SceneItem *) NULL); R2_GLOBALS._player.enableControl(CURSOR_USE); break; case 614: + // Pick up Aerosol R2_GLOBALS._player.enableControl(); _aerosol.remove(); - R2_INVENTORY.setObjectScene(12, 1); + R2_INVENTORY.setObjectScene(R2_AEROSOL, 1); R2_GLOBALS._walkRegions.disableRegion(7); break; case 615: - _actor8.remove(); - R2_INVENTORY.setObjectScene(9, 1); + // Pick up Com Scanner + _scanner.remove(); + R2_INVENTORY.setObjectScene(R2_COM_SCANNER, 1); R2_GLOBALS._player.enableControl(); break; default: @@ -5842,7 +6008,7 @@ void Scene600::dispatch() { _aSound1.play(40); Scene::dispatch(); - if ((_actor4._strip == 3) && (_actor4._frame == 3)) { + if ((_smoke._strip == 3) && (_smoke._frame == 3)) { _actor1.setStrip(4); _actor1.setFrame(1); } @@ -5868,26 +6034,26 @@ bool Scene700::Item11::startAction(CursorType action, Event &event) { return NamedHotspot::startAction(action, event); } -bool Scene700::Item12::startAction(CursorType action, Event &event) { +bool Scene700::HandGrip::startAction(CursorType action, Event &event) { Scene700 *scene = (Scene700 *)R2_GLOBALS._sceneManager._scene; switch (action) { case R2_CABLE_HARNESS: R2_GLOBALS._player.disableControl(); - scene->_actor5.postInit(); - scene->_actor5.setup(701, 3, 2); - scene->_actor5.setPosition(Common::Point(243, 98)); - scene->_actor5.setDetails(700, 37, -1, -1, 2, (SceneItem *) NULL); - scene->_actor5.hide(); + scene->_cable.postInit(); + scene->_cable.setup(701, 3, 2); + scene->_cable.setPosition(Common::Point(243, 98)); + scene->_cable.setDetails(700, 37, -1, -1, 2, (SceneItem *) NULL); + scene->_cable.hide(); scene->_sceneMode = 20; break; case R2_ATTRACTOR_CABLE_HARNESS: R2_GLOBALS._player.disableControl(); - scene->_actor5.postInit(); - scene->_actor5.setup(701, 2, 8); - scene->_actor5.setPosition(Common::Point(243, 98)); - scene->_actor5.setDetails(700, 38, -1, -1, 2, (SceneItem *) NULL); - scene->_actor5.hide(); + scene->_cable.postInit(); + scene->_cable.setup(701, 2, 8); + scene->_cable.setPosition(Common::Point(243, 98)); + scene->_cable.setDetails(700, 38, -1, -1, 2, (SceneItem *) NULL); + scene->_cable.hide(); scene->_sceneMode = 21; break; default: @@ -5895,7 +6061,7 @@ bool Scene700::Item12::startAction(CursorType action, Event &event) { break; } - scene->setAction(&scene->_sequenceManager, scene, 707, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager, scene, 707, &R2_GLOBALS._player, &scene->_cable, NULL); return true; } @@ -5947,7 +6113,7 @@ bool Scene700::Actor4::startAction(CursorType action, Event &event) { return true; } -bool Scene700::Actor5::startAction(CursorType action, Event &event) { +bool Scene700::Cable::startAction(CursorType action, Event &event) { Scene700 *scene = (Scene700 *)R2_GLOBALS._sceneManager._scene; switch (action) { @@ -5981,9 +6147,9 @@ bool Scene700::Actor5::startAction(CursorType action, Event &event) { break; case R2_ATTRACTOR_UNIT: R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) == 700) { + if (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) != 700) { scene->_sceneMode = 706; - scene->setAction(&scene->_sequenceManager, scene, 706, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager, scene, 706, &R2_GLOBALS._player, &scene->_cable, NULL); } else { scene->_sceneMode = 15; Common::Point pt(_position.x - 12, _position.y + 1); @@ -6065,20 +6231,20 @@ void Scene700::postInit(SceneObjectList *OwnerList) { _actor9.setDetails(700, 33, -1, 35, 1, (SceneItem *) NULL); if ((R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS) != 1) && (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS) != 1)) { - _actor5.postInit(); - _actor5.fixPriority(10); + _cable.postInit(); + _cable.fixPriority(10); switch (R2_INVENTORY.getObjectScene(R2_ATTRACTOR_CABLE_HARNESS)) { case 0: switch (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS)) { case 0: - _actor5.setup(701, 3, 2); - _actor5.setPosition(Common::Point(243, 98)); - _actor5.setDetails(700, 37, -1, -1, 1, (SceneItem *) NULL); + _cable.setup(701, 3, 2); + _cable.setPosition(Common::Point(243, 98)); + _cable.setDetails(700, 37, -1, -1, 1, (SceneItem *) NULL); break; case 700: - _actor5.setup(701, 3, 1); - _actor5.setPosition(Common::Point(356 - (R2_GLOBALS._v565EB * 8), 148 - (((R2_GLOBALS._v565E9 + 10) / 5) * 4))); - _actor5.setDetails(700, 37, -1, -1, 1, (SceneItem *) NULL); + _cable.setup(701, 3, 1); + _cable.setPosition(Common::Point(356 - (R2_GLOBALS._v565EB * 8), 148 - (((R2_GLOBALS._v565E9 + 10) / 5) * 4))); + _cable.setDetails(700, 37, -1, -1, 1, (SceneItem *) NULL); break; default: break; @@ -6088,22 +6254,22 @@ void Scene700::postInit(SceneObjectList *OwnerList) { switch (R2_INVENTORY.getObjectScene(R2_CABLE_HARNESS)) { case 0: if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) - _actor5.setup(701, 2, 1); + _cable.setup(701, 2, 1); else - _actor5.setup(701, 2, 8); - _actor5.setPosition(Common::Point(243, 98)); - _actor5.fixPriority(77); - _actor5.setDetails(700, 38, -1, -1, 1, (SceneItem *) NULL); + _cable.setup(701, 2, 8); + _cable.setPosition(Common::Point(243, 98)); + _cable.fixPriority(77); + _cable.setDetails(700, 38, -1, -1, 1, (SceneItem *) NULL); break; case 700: - _actor5.setup(701, 1, 8); + _cable.setup(701, 1, 8); if (R2_GLOBALS._v565E7 == 0) { - _actor5.setPosition(Common::Point(356 - (R2_GLOBALS._v565EB * 8), 148 - (((R2_GLOBALS._v565E9 + 10) / 5) * 4))); + _cable.setPosition(Common::Point(356 - (R2_GLOBALS._v565EB * 8), 148 - (((R2_GLOBALS._v565E9 + 10) / 5) * 4))); } else { - _actor5.setup(701, 1, 1); - _actor5.setPosition(Common::Point(_actor1._position.x + 1, _actor1._position.y + 120)); + _cable.setup(701, 1, 1); + _cable.setPosition(Common::Point(_actor1._position.x + 1, _actor1._position.y + 120)); } - _actor5.setDetails(700, 38, -1, -1, 1, (SceneItem *) NULL); + _cable.setDetails(700, 38, -1, -1, 1, (SceneItem *) NULL); break; default: break; @@ -6118,7 +6284,7 @@ void Scene700::postInit(SceneObjectList *OwnerList) { _actor4.setPosition(Common::Point(454, 117)); _actor4.setDetails(700, 27, -1, -1, 1, (SceneItem *) NULL); - _item12.setDetails(Rect(234, 90, 252, 110), 700, 39, -1, -1, 1, NULL); + _handGrip.setDetails(Rect(234, 90, 252, 110), 700, 39, -1, -1, 1, NULL); _item6.setDetails(Rect(91, 158, 385, 167), 700, 6, -1, 8, 1, NULL); _item2.setDetails(Rect(47, 115, 149, 124), 700, 40, -1, 41, 1, NULL); _item3.setDetails(Rect(151, 108, 187, 124), 700, 40, -1, 41, 1, NULL); @@ -6223,7 +6389,7 @@ void Scene700::signal() { break; case 11: _sceneMode = 12; - _actor5.remove(); + _cable.remove(); R2_GLOBALS._player.animate(ANIM_MODE_6, this); break; case 12: @@ -6248,13 +6414,13 @@ void Scene700::signal() { break; case 16: _sceneMode = 17; - _actor5.setup(701, 1, 8); - _actor5.setDetails(700, 38, -1, -1, 3, (SceneItem *) NULL); - if ((R2_GLOBALS._v565E5 != 0) && (_actor5._position.x == _actor1._position.x + 1) && (_actor5._position.x == 148 - (((R2_GLOBALS._electromagnetChangeAmount + 10) / 5) * 4))) { - _actor5.animate(ANIM_MODE_6, NULL); - Common::Point pt(_actor5._position.x, _actor1._position.y + 120); + _cable.setup(701, 1, 8); + _cable.setDetails(700, 38, -1, -1, 3, (SceneItem *) NULL); + if ((R2_GLOBALS._v565E5 != 0) && (_cable._position.x == _actor1._position.x + 1) && (_cable._position.x == 148 - (((R2_GLOBALS._electromagnetChangeAmount + 10) / 5) * 4))) { + _cable.animate(ANIM_MODE_6, NULL); + Common::Point pt(_cable._position.x, _actor1._position.y + 120); NpcMover *mover = new NpcMover(); - _actor5.addMover(mover, &pt, NULL); + _cable.addMover(mover, &pt, NULL); R2_GLOBALS._v565E7 = 1; } R2_GLOBALS._player.animate(ANIM_MODE_6, this); @@ -6274,9 +6440,9 @@ void Scene700::signal() { R2_GLOBALS._player.enableControl(); break; case 21: - _actor5.fixPriority(77); + _cable.fixPriority(77); if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) - _actor5.animate(ANIM_MODE_6, NULL); + _cable.animate(ANIM_MODE_6, NULL); R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 700); R2_GLOBALS._player.enableControl(); @@ -6291,10 +6457,10 @@ void Scene700::signal() { R2_GLOBALS._sceneManager.changeScene(900); break; case 706: - _actor5.setDetails(700, 38, -1, -1, 3, (SceneItem *) NULL); - _actor5.fixPriority(77); + _cable.setDetails(700, 38, -1, -1, 3, (SceneItem *) NULL); + _cable.fixPriority(77); if ((R2_GLOBALS._v565E5 != 0) && (R2_GLOBALS._electromagnetChangeAmount == 20) && (R2_GLOBALS._electromagnetZoom == 70)) - _actor5.animate(ANIM_MODE_6, NULL); + _cable.animate(ANIM_MODE_6, NULL); R2_INVENTORY.setObjectScene(R2_ATTRACTOR_UNIT, 0); R2_INVENTORY.setObjectScene(R2_ATTRACTOR_CABLE_HARNESS, 700); R2_GLOBALS._player.enableControl(); diff --git a/engines/tsage/ringworld2/ringworld2_scenes0.h b/engines/tsage/ringworld2/ringworld2_scenes0.h index bc30743aca..a2f2accaba 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes0.h +++ b/engines/tsage/ringworld2/ringworld2_scenes0.h @@ -102,7 +102,7 @@ public: class Scene125: public SceneExt { /* Objects */ - class Object5: public SceneActor { + class Food: public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -136,7 +136,7 @@ public: ASoundExt _sound1; NamedHotspot _background, _item2, _item3; DiskSlot _diskSlot; - SceneActor _object1, _object2, _object3, _object4, _object5, _object6, _infoDisk; + SceneActor _object1, _object2, _object3, _object4, _food, _foodDispenser, _infoDisk; Icon _icon1, _icon2, _icon3, _icon4, _icon5, _icon6; SequenceManager _sequenceManager; SceneText _sceneText; @@ -524,6 +524,31 @@ public: }; class Scene500: public SceneExt { + /* Dialogs */ + class PanelDialog: public SceneAreaObject { + class Button: public SceneActor { + private: + int _buttonId; + bool _buttonDown; + + void doButtonPress(); + public: + Button(); + virtual Common::String getClassName() { return "Scene500_Button"; } + virtual void process(Event &event); + virtual bool startAction(CursorType action, Event &event); + virtual void synchronize(Serializer &s); + + void setupButton(int buttonId); + }; + public: + Button _button1, _button2, _button3; + + virtual Common::String getClassName() { return "Scene500_PanelWindow"; } + virtual void remove(); + void setDetails(int visage, int strip, int frameNumber, const Common::Point &pt); + }; + /* Items */ class ControlPanel: public SceneHotspot { public: @@ -531,11 +556,11 @@ class Scene500: public SceneExt { }; /* Objects */ - class Object2: public SceneActor { + class Seeker: public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Object3: public SceneActor { + class Suit: public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -570,20 +595,16 @@ class Scene500: public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Object: public SceneActor { - public: - virtual bool startAction(CursorType action, Event &event); - }; public: int _stripNumber; byte _buffer[2710]; - SpeakerSeeker _seekerSpeaker; - SpeakerQuinn _quinnSpeaker; + SpeakerSeeker500 _seekerSpeaker; + SpeakerQuinn500 _quinnSpeaker; SceneHotspot _background, _item2; ControlPanel _controlPanel; SceneActor _object1; - Object2 _object2; - Object3 _object3; + Seeker _seeker; + Suit _suit; Doorway _doorway; OxygenTanks _tanks1, _tanks2; AirLock _airLock; @@ -592,8 +613,7 @@ public: SonicStunner _sonicStunner; Locker1 _locker1; Locker2 _locker2; - SceneAreaObject _area1; - Object _obj1, _obj2, _obj3; + PanelDialog _panelDialog; ASoundExt _sound1; SequenceManager _sequenceManager1, _sequenceManager2; public: @@ -622,7 +642,7 @@ class Scene600 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; - class Actor4 : public SceneActor { + class Smoke : public SceneActor { public: virtual void signal(); virtual bool startAction(CursorType action, Event &event); @@ -640,7 +660,7 @@ class Scene600 : public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor8 : public SceneActor { + class Scanner : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -653,13 +673,13 @@ public: CompartmentHotspot _item5; BackgroundSceneObject _object1; SceneActor _actor1; - SceneActor _actor2; - SceneActor _actor3; - Actor4 _actor4; + SceneActor _computer; + SceneActor _stasisField; + Smoke _smoke; Doorway _doorway; Laser _laser; Aerosol _aerosol; - Actor8 _actor8; + Scanner _scanner; ASoundExt _aSound1; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; @@ -679,7 +699,7 @@ class Scene700: public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Item12 : public NamedHotspot { + class HandGrip : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; @@ -696,7 +716,7 @@ class Scene700: public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor5 : public SceneActor { + class Cable : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -716,12 +736,12 @@ public: NamedHotspot _item9; NamedHotspot _item10; Item11 _item11; - Item12 _item12; + HandGrip _handGrip; SceneActor _actor1; Actor2 _actor2; Actor3 _actor3; Actor4 _actor4; - Actor5 _actor5; + Cable _cable; Actor6 _actor6; Actor6 _actor7; Actor6 _actor8; diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.cpp b/engines/tsage/ringworld2/ringworld2_scenes1.cpp index 6ea53d0852..33eb9b9afb 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -39,6 +39,7 @@ Scene1000::Scene1000(): SceneExt() { R2_GLOBALS._uiElements._active = false; _gameTextSpeaker._displayMode = 9; _fieldD2E = 0; + _field412 = 0; } void Scene1000::postInit(SceneObjectList *OwnerList) { @@ -672,7 +673,7 @@ void Scene1100::synchronize(Serializer &s) { s.syncAsSint16LE(_field414); } -bool Scene1100::Actor16::startAction(CursorType action, Event &event) { +bool Scene1100::Seeker::startAction(CursorType action, Event &event) { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_TALK) @@ -680,7 +681,7 @@ bool Scene1100::Actor16::startAction(CursorType action, Event &event) { if (R2_GLOBALS.getFlag(52)) { R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_field412 = 327; else scene->_field412 = 328; @@ -690,14 +691,14 @@ bool Scene1100::Actor16::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 55; if (R2_GLOBALS._v565AE >= 3) { - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_stripManager.start3(329, scene, R2_GLOBALS._stripManager_lookupList); else scene->_stripManager.start3(330, scene, R2_GLOBALS._stripManager_lookupList); } else { ++R2_GLOBALS._v565AE; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_stripManager.start3(304, scene, R2_GLOBALS._stripManager_lookupList); else scene->_stripManager.start3(308, scene, R2_GLOBALS._stripManager_lookupList); @@ -706,7 +707,7 @@ bool Scene1100::Actor16::startAction(CursorType action, Event &event) { return true; } -bool Scene1100::Actor17::startAction(CursorType action, Event &event) { +bool Scene1100::Trooper::startAction(CursorType action, Event &event) { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; switch (action) { @@ -714,7 +715,7 @@ bool Scene1100::Actor17::startAction(CursorType action, Event &event) { if (_visage == 1105) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1114; - scene->setAction(&scene->_sequenceManager1, scene, 1114, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1114, &R2_GLOBALS._player, &scene->_trooper, NULL); return true; } else { return SceneActor::startAction(action, event); @@ -725,21 +726,21 @@ bool Scene1100::Actor17::startAction(CursorType action, Event &event) { case R2_PHOTON_STUNNER: if (_visage == 1105) { R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._player._characterIndex == 1) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { scene->_sceneMode = 1112; - scene->setAction(&scene->_sequenceManager1, scene, 1112, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1112, &R2_GLOBALS._player, &scene->_trooper, NULL); } else { scene->_sceneMode = 1115; - scene->setAction(&scene->_sequenceManager1, scene, 1115, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1115, &R2_GLOBALS._player, &scene->_trooper, NULL); } return true; } else if (_strip == 2) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1113; - if (R2_GLOBALS._player._characterIndex == 1) { - scene->setAction(&scene->_sequenceManager1, scene, 1113, &R2_GLOBALS._player, &scene->_actor17, NULL); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + scene->setAction(&scene->_sequenceManager1, scene, 1113, &R2_GLOBALS._player, &scene->_trooper, NULL); } else { - scene->setAction(&scene->_sequenceManager1, scene, 1118, &R2_GLOBALS._player, &scene->_actor17, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1118, &R2_GLOBALS._player, &scene->_trooper, NULL); } return true; } else { @@ -752,7 +753,7 @@ bool Scene1100::Actor17::startAction(CursorType action, Event &event) { } } -bool Scene1100::Actor18::startAction(CursorType action, Event &event) { +bool Scene1100::Chief::startAction(CursorType action, Event &event) { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; if ((action == CURSOR_TALK) && (!R2_GLOBALS.getFlag(54)) && (R2_GLOBALS.getFlag(52))) { @@ -814,7 +815,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.stop(); if (R2_GLOBALS._sceneManager._previousScene == 300) { - if (R2_GLOBALS._player._characterIndex == 3) + if (R2_GLOBALS._player._characterIndex == R2_MIRANDA) R2_GLOBALS._player._characterIndex = R2_QUINN; R2_GLOBALS._player._characterScene[1] = 1100; R2_GLOBALS._player._characterScene[2] = 1100; @@ -824,28 +825,28 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.hide(); R2_GLOBALS._player.disableControl(); - _actor16.postInit(); - _actor16.hide(); - if (R2_GLOBALS._player._characterIndex == 1) - _actor16.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + _seeker.postInit(); + _seeker.hide(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) + _seeker.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); else - _actor16.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _seeker.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); - _actor18.postInit(); - _actor18.setup(1113, 3, 1); - _actor18.setPosition(Common::Point(181, 125)); - _actor18.fixPriority(110); + _chief.postInit(); + _chief.setup(1113, 3, 1); + _chief.setPosition(Common::Point(181, 125)); + _chief.fixPriority(110); if (R2_GLOBALS.getFlag(54)) - _actor18.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); else - _actor18.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); - _actor17.postInit(); - _actor17.setup(1105, 3, 1); - _actor17.setPosition(Common::Point(312, 165)); - _actor17._numFrames = 5; - _actor17.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); + _trooper.postInit(); + _trooper.setup(1105, 3, 1); + _trooper.setPosition(Common::Point(312, 165)); + _trooper._numFrames = 5; + _trooper.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); _actor1.postInit(); _actor1.setup(1512, 1, 1); @@ -907,66 +908,66 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.postInit(); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); - _actor16.postInit(); + _seeker.postInit(); if (R2_GLOBALS.getFlag(52)) { - if (R2_GLOBALS._player._characterIndex == 1) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.setup(19, 7, 1); - _actor16.setup(29, 6, 1); + _seeker.setup(29, 6, 1); } else { R2_GLOBALS._player.setup(29, 7, 1); - _actor16.setup(19, 6, 1); + _seeker.setup(19, 6, 1); } R2_GLOBALS._player.setPosition(Common::Point(140, 124)); - _actor16.setPosition(Common::Point(237, 134)); + _seeker.setPosition(Common::Point(237, 134)); R2_GLOBALS._player.enableControl(); } else { - if (R2_GLOBALS._player._characterIndex == 1) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.setup(1107, 2, 1); - _actor16.setup(1107, 4, 1); + _seeker.setup(1107, 4, 1); R2_GLOBALS._player.setPosition(Common::Point(247, 169)); - _actor16.setPosition(Common::Point(213, 169)); + _seeker.setPosition(Common::Point(213, 169)); } else { R2_GLOBALS._player.setup(1107, 4, 1); - _actor16.setup(1107, 2, 1); + _seeker.setup(1107, 2, 1); R2_GLOBALS._player.setPosition(Common::Point(213, 169)); - _actor16.setPosition(Common::Point(247, 169)); + _seeker.setPosition(Common::Point(247, 169)); } R2_GLOBALS._player.enableControl(); R2_GLOBALS._player._canWalk = false; } - if (R2_GLOBALS._player._characterIndex == 1) - _actor16.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) + _seeker.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); else - _actor16.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _seeker.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); - _actor18.postInit(); - _actor18.setup(1113, 3, 1); - _actor18.setPosition(Common::Point(181, 125)); - _actor18.fixPriority(110); + _chief.postInit(); + _chief.setup(1113, 3, 1); + _chief.setPosition(Common::Point(181, 125)); + _chief.fixPriority(110); if (R2_GLOBALS.getFlag(54)) - _actor18.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 4, -1, -1, 1, (SceneItem *) NULL); else - _actor18.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); + _chief.setDetails(1100, 3, -1, -1, 1, (SceneItem *) NULL); if (!R2_GLOBALS.getFlag(52)) { - _actor17.postInit(); + _trooper.postInit(); if (R2_GLOBALS.getFlag(53)) - _actor17.setup(1106, 2, 4); + _trooper.setup(1106, 2, 4); else - _actor17.setup(1105, 4, 4); + _trooper.setup(1105, 4, 4); - _actor17.setPosition(Common::Point(17, 54)); - _actor17._numFrames = 5; + _trooper.setPosition(Common::Point(17, 54)); + _trooper._numFrames = 5; if (R2_GLOBALS.getFlag(53)) - _actor17.setDetails(1100, 28, -1, -1, 1, (SceneItem *) NULL); + _trooper.setDetails(1100, 28, -1, -1, 1, (SceneItem *) NULL); else - _actor17.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); + _trooper.setDetails(1100, 22, 23, 24, 1, (SceneItem *) NULL); - _actor17.fixPriority(200); + _trooper.fixPriority(200); } _actor1.postInit(); _actor1.setup(1512, 1, 1); @@ -1026,9 +1027,9 @@ void Scene1100::signal() { } break; case 4: - _actor18.postInit(); - _actor18.show(); - setAction(&_sequenceManager1, this, 1101, &_actor18, &_actor10, NULL); + _chief.postInit(); + _chief.show(); + setAction(&_sequenceManager1, this, 1101, &_chief, &_actor10, NULL); break; case 5: _actor13.postInit(); @@ -1054,12 +1055,12 @@ void Scene1100::signal() { } break; case 7: - setAction(&_sequenceManager1, this, 1103, &_actor18, &_actor10); + setAction(&_sequenceManager1, this, 1103, &_chief, &_actor10); break; case 8: R2_GLOBALS._player._effect = 0; _actor11.postInit(); - setAction(&_sequenceManager1, this, 1105, &R2_GLOBALS._player, &_actor10, &_actor11, &_actor18, NULL); + setAction(&_sequenceManager1, this, 1105, &R2_GLOBALS._player, &_actor10, &_actor11, &_chief, NULL); break; case 9: _object1.copySceneToBackground(); @@ -1090,8 +1091,8 @@ void Scene1100::signal() { // Really nothing break; case 13: - _actor17.postInit(); - R2_GLOBALS._scrollFollower = &_actor17; + _trooper.postInit(); + R2_GLOBALS._scrollFollower = &_trooper; _actor11.setup(1100, 2, 1); _actor11.setPosition(Common::Point(408, 121)); @@ -1099,7 +1100,7 @@ void Scene1100::signal() { _actor10.setup(1100, 3, 5); _actor10.setPosition(Common::Point(409, 121)); - setAction(&_sequenceManager1, this, 1104, &_actor17, NULL); + setAction(&_sequenceManager1, this, 1104, &_trooper, NULL); break; case 14: setAction(&_sequenceManager1, this, 1100, &_actor11, &_actor10, NULL); @@ -1115,14 +1116,14 @@ void Scene1100::signal() { break; case 21: { R2_GLOBALS._sound2.play(92); - _actor17.animate(ANIM_MODE_5, NULL); + _trooper.animate(ANIM_MODE_5, NULL); Common::Point pt(187, 45); NpcMover *mover = new NpcMover(); _actor1.addMover(mover, &pt, this); } break; case 22: - setAction(&_sequenceManager1, this, 1110, &_actor16, &R2_GLOBALS._player, NULL); + setAction(&_sequenceManager1, this, 1110, &_seeker, &R2_GLOBALS._player, NULL); break; case 23: R2_GLOBALS._player.disableControl(); @@ -1136,46 +1137,49 @@ void Scene1100::signal() { break; case 25: R2_GLOBALS._player.disableControl(); - _stripManager._lookupList[9] = 1; - _stripManager._lookupList[10] = 1; - _stripManager._lookupList[11] = 1; + R2_GLOBALS._stripManager_lookupList[9] = 1; + R2_GLOBALS._stripManager_lookupList[10] = 1; + R2_GLOBALS._stripManager_lookupList[11] = 1; R2_GLOBALS._sound1.play(95); - setAction(&_sequenceManager1, this, 1111, &_actor17, &R2_GLOBALS._player, &_actor16, NULL); + setAction(&_sequenceManager1, this, 1111, &_trooper, &R2_GLOBALS._player, &_seeker, NULL); break; case 26: R2_GLOBALS._player.disableControl(); - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_ARROW); _stripManager.start(302, this); break; case 27: R2_GLOBALS._player.disableControl(); - setAction(&_sequenceManager1, this, 1120, &_actor16, &R2_GLOBALS._player, NULL); + setAction(&_sequenceManager1, this, 1120, &_seeker, &R2_GLOBALS._player, NULL); break; case 28: R2_GLOBALS._player.disableControl(); - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_ARROW); _stripManager.start(303, this); break; + case 29: + case 50: + R2_GLOBALS._player.enableControl(CURSOR_USE); + R2_GLOBALS._player._canWalk = false; + break; case 51: R2_GLOBALS.setFlag(53); - _actor17.setDetails(1100, 28, -1, -1, 3, (SceneItem *) NULL); - // No break on purpose - case 50: - // No break on purpose - case 29: + _trooper.setDetails(1100, 28, -1, -1, 3, (SceneItem *) NULL); + R2_GLOBALS._player.enableControl(CURSOR_USE); + R2_GLOBALS._player._canWalk = false; break; case 52: R2_GLOBALS._sound1.play(98); R2_GLOBALS.setFlag(52); R2_GLOBALS._player.disableControl(); _sceneMode = 1116; - if (R2_GLOBALS._player._characterIndex == 1) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { setAction(&_sequenceManager1, this, 1116, &R2_GLOBALS._player, NULL); - _actor16.setAction(&_sequenceManager2, NULL, 1123, &_actor16, NULL); + _seeker.setAction(&_sequenceManager2, NULL, 1123, &_seeker, NULL); } else { setAction(&_sequenceManager1, this, 1124, &R2_GLOBALS._player, NULL); - _actor16.setAction(&_sequenceManager2, NULL, 1117, &_actor16, NULL); + _seeker.setAction(&_sequenceManager2, NULL, 1117, &_seeker, NULL); } break; case 53: @@ -1184,13 +1188,13 @@ void Scene1100::signal() { if (_field412 == 0) { R2_GLOBALS.setFlag(55); if (R2_GLOBALS.getFlag(55)) { - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _stripManager.start(318, this); else _stripManager.start(323, this); } else { // This part is totally useless as flag 55 has been set right before the check - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _stripManager.start(317, this); else _stripManager.start(322, this); @@ -1200,10 +1204,10 @@ void Scene1100::signal() { } break; case 54: - if (_stripManager._field2E8 == 1) { + if (_stripManager._exitMode == 1) { R2_GLOBALS._player.disableControl(); _sceneMode = 1125; - setAction(&_sequenceManager1, this, 1125, &R2_GLOBALS._player, &_actor16, NULL); + setAction(&_sequenceManager1, this, 1125, &R2_GLOBALS._player, &_seeker, NULL); } else R2_GLOBALS._player.enableControl(CURSOR_TALK); break; @@ -1244,9 +1248,9 @@ void Scene1100::signal() { break; case 1116: R2_GLOBALS._player.enableControl(CURSOR_ARROW); - _stripManager._lookupList[9] = 1; - _stripManager._lookupList[10] = 1; - _stripManager._lookupList[11] = 1; + R2_GLOBALS._stripManager_lookupList[9] = 1; + R2_GLOBALS._stripManager_lookupList[10] = 1; + R2_GLOBALS._stripManager_lookupList[11] = 1; break; case 1125: { _sceneMode = 99; @@ -1295,7 +1299,7 @@ void Scene1100::dispatch() { } void Scene1100::saveCharacter(int characterIndex) { - if (R2_GLOBALS._player._characterIndex == 3) + if (R2_GLOBALS._player._characterIndex == R2_MIRANDA) R2_GLOBALS._sound1.fadeOut2(NULL); SceneExt::saveCharacter(characterIndex); } @@ -5973,7 +5977,8 @@ void Scene1337::subCF31D() { if ((_arrunkObj1337[1]._arr2[i]._field34 == 0) && (!subC2687(_arrunkObj1337[1]._arr3[0]._field34))) { subC340B(&_arrunkObj1337[1]._arr1[tmpVal], &_arrunkObj1337[1]._arr2[i]); found = true; - } + break; + } } } @@ -5983,8 +5988,10 @@ void Scene1337::subCF31D() { tmpVal = subC274D(1); int tmpVal2 = subC331B(1); - if ((tmpVal != -1) && ( tmpVal2 != -1)) + if ((tmpVal != -1) && ( tmpVal2 != -1)) { subC358E(&_arrunkObj1337[1]._arr1[tmpVal], tmpVal2); + found = true; + } if (found) return; @@ -7008,7 +7015,7 @@ void Scene1500::signal() { } break; case 24: - R2_GLOBALS._sceneManager.changeScene(300); + R2_GLOBALS._sceneManager.changeScene(1550); break; default: break; @@ -7169,21 +7176,22 @@ void Scene1530::dispatch() { } /*-------------------------------------------------------------------------- - * Scene 1550 - + * Scene 1550 - Spaceport * *--------------------------------------------------------------------------*/ -Scene1550::UnkObj15501::UnkObj15501() { - _fieldA4 = _fieldA6 = 0; + +Scene1550::Junk::Junk() { + _fieldA4 = _junkNumber = 0; } -void Scene1550::UnkObj15501::synchronize(Serializer &s) { +void Scene1550::Junk::synchronize(Serializer &s) { SceneActor::synchronize(s); s.syncAsSint16LE(_fieldA4); - s.syncAsSint16LE(_fieldA6); + s.syncAsSint16LE(_junkNumber); } -bool Scene1550::UnkObj15501::startAction(CursorType action, Event &event) { +bool Scene1550::Junk::startAction(CursorType action, Event &event) { Scene1550 *scene = (Scene1550 *)R2_GLOBALS._sceneManager._scene; switch (action) { @@ -7236,36 +7244,36 @@ bool Scene1550::UnkObj15501::startAction(CursorType action, Event &event) { } } -Scene1550::UnkObj15502::UnkObj15502() { - _fieldA4 = 0; +Scene1550::ShipComponent::ShipComponent() { + _componentId = 0; } -void Scene1550::UnkObj15502::synchronize(Serializer &s) { +void Scene1550::ShipComponent::synchronize(Serializer &s) { SceneActor::synchronize(s); - s.syncAsSint16LE(_fieldA4); + s.syncAsSint16LE(_componentId); } -bool Scene1550::UnkObj15502::startAction(CursorType action, Event &event) { +bool Scene1550::ShipComponent::startAction(CursorType action, Event &event) { Scene1550 *scene = (Scene1550 *)R2_GLOBALS._sceneManager._scene; switch (action) { case CURSOR_USE: - if (_fieldA4 == 8) { + if (_componentId == 8) { scene->_field412 = 1; R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1576; else scene->_sceneMode = 1584; - // strcpy(scene->_arrUnkObj15502[7]._actorName, 'hatch'); - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[7], NULL); + // strcpy(scene->_shipComponents[7]._actorName, 'hatch'); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[7], NULL); return true; } return SceneActor::startAction(action, event); break; case CURSOR_LOOK: - if (_fieldA4 == 8) + if (_componentId == 8) SceneItem::display(1550, 75, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); else if (_frame == 1) SceneItem::display(1550, 70, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); @@ -7275,92 +7283,92 @@ bool Scene1550::UnkObj15502::startAction(CursorType action, Event &event) { break; case R2_FUEL_CELL: scene->_field412 = 1; - if (_fieldA4 == 6) { + if (_componentId == 6) { R2_GLOBALS._player.disableControl(); - scene->_actor1.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) + scene->_landingStrut.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1574; else scene->_sceneMode = 1582; - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[5], &scene->_actor1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[5], &scene->_landingStrut, NULL); return true; } return SceneActor::startAction(action, event); break; case R2_GYROSCOPE: scene->_field412 = 1; - if (_fieldA4 == 3) { + if (_componentId == 3) { R2_GLOBALS._player.disableControl(); - scene->_actor1.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) + scene->_landingStrut.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1571; else scene->_sceneMode = 1581; - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[2], &scene->_actor1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[2], &scene->_landingStrut, NULL); return true; } return SceneActor::startAction(action, event); break; case R2_GUIDANCE_MODULE: scene->_field412 = 1; - if (_fieldA4 == 1) { + if (_componentId == 1) { R2_GLOBALS._player.disableControl(); - scene->_actor1.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) + scene->_landingStrut.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1569; else scene->_sceneMode = 1579; - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[0], &scene->_actor1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[0], &scene->_landingStrut, NULL); return true; } return SceneActor::startAction(action, event); break; case R2_THRUSTER_VALVE: scene->_field412 = 1; - if (_fieldA4 == 4) { + if (_componentId == 4) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1572; - scene->_actor1.postInit(); - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[3], &scene->_actor1, NULL); + scene->_landingStrut.postInit(); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[3], &scene->_landingStrut, NULL); return true; } return SceneActor::startAction(action, event); break; case R2_RADAR_MECHANISM: scene->_field412 = 1; - if (_fieldA4 == 2) { + if (_componentId == 2) { R2_GLOBALS._player.disableControl(); - scene->_actor1.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) + scene->_landingStrut.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1570; else scene->_sceneMode = 1580; - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[1], &scene->_actor1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[1], &scene->_landingStrut, NULL); return true; } return SceneActor::startAction(action, event); break; case R2_IGNITOR: scene->_field412 = 1; - if (_fieldA4 == 5) { + if (_componentId == 5) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1573; - scene->_actor1.postInit(); - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[4], &scene->_actor1, NULL); + scene->_landingStrut.postInit(); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[4], &scene->_landingStrut, NULL); return true; } return SceneActor::startAction(action, event); break; case R2_BATTERY: scene->_field412 = 1; - if (_fieldA4 == 7) { + if (_componentId == 7) { R2_GLOBALS._player.disableControl(); - scene->_actor1.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) + scene->_landingStrut.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1575; else scene->_sceneMode = 1583; - scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_arrUnkObj15502[6], &scene->_actor1, NULL); + scene->setAction(&scene->_sequenceManager1, scene, scene->_sceneMode, &R2_GLOBALS._player, &scene->_shipComponents[6], &scene->_landingStrut, NULL); return true; } return SceneActor::startAction(action, event); @@ -7371,11 +7379,12 @@ bool Scene1550::UnkObj15502::startAction(CursorType action, Event &event) { } } -void Scene1550::UnkObj15502::subA5CDF(int strip) { - _fieldA4 = strip; +void Scene1550::ShipComponent::setupShipComponent(int componentId) { + _componentId = componentId; postInit(); - setup(1517, _fieldA4, 1); - switch (_fieldA4 - 1) { + setup(1517, _componentId, 1); + + switch (_componentId - 1) { case 0: if (R2_INVENTORY.getObjectScene(R2_GUIDANCE_MODULE) == 0) setFrame(5); @@ -7510,19 +7519,16 @@ void Scene1550::UnkArea1550::process(Event &event) { if (_areaActor._bounds.contains(event.mousePos.x + g_globals->gfxManager()._bounds.left , event.mousePos.y)) { if (cursor == _cursorNum) { - warning("TODO: _cursorState = ???"); - R2_GLOBALS._events.setCursor(_savedCursorNum); //, _cursorState); + R2_GLOBALS._events.setCursor(_savedCursorNum); } } else if (event.mousePos.y < 168) { if (cursor != _cursorNum) { _savedCursorNum = cursor; - warning("TODO: _cursorState = ???"); R2_GLOBALS._events.setCursor(CURSOR_INVALID); } if (event.eventType == EVENT_BUTTON_DOWN) { event.handled = true; - warning("TODO: _cursorState = ???"); - R2_GLOBALS._events.setCursor(_savedCursorNum); //, _cursorState); + R2_GLOBALS._events.setCursor(_savedCursorNum); remove(); } } @@ -7570,26 +7576,30 @@ void Scene1550::UnkArea1550::proc13(int resNum, int lookLineNum, int talkLineNum _areaActor.setDetails(resNum, lookLineNum, talkLineNum, useLineNum, 2, (SceneItem *) NULL); } -bool Scene1550::Hotspot1::startAction(CursorType action, Event &event) { +bool Scene1550::WorkingShip::startAction(CursorType action, Event &event) { return SceneHotspot::startAction(action, event); } bool Scene1550::Hotspot3::startAction(CursorType action, Event &event) { // Arrays related to this scene are all hacky in the origina: they are based on the impossibility to use Miranda - assert ((R2_GLOBALS._player._characterIndex == 1) || (R2_GLOBALS._player._characterIndex == 2)); + assert ((R2_GLOBALS._player._characterIndex == R2_QUINN) || (R2_GLOBALS._player._characterIndex == R2_SEEKER)); // The original contains a debug message when CURSOR_TALK is used. // This part is totally useless, we could remove it (and the entire function as well) if (action == CURSOR_TALK) - warning("Location: %d/%d - %d", R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex], R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2], k5A4D6[(R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] * 30)] + R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]); + warning("Location: %d/%d - %d", + R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x, + R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y, + scene1550AreaMap[(R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y * 30)] + + R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x); return SceneHotspot::startAction(action, event); } -bool Scene1550::Actor6::startAction(CursorType action, Event &event) { +bool Scene1550::Wreckage::startAction(CursorType action, Event &event) { return SceneActor::startAction(action, event); } -bool Scene1550::Actor7::startAction(CursorType action, Event &event) { +bool Scene1550::Companion::startAction(CursorType action, Event &event) { if (action != CURSOR_TALK) return SceneActor::startAction(action, event); @@ -7607,7 +7617,7 @@ bool Scene1550::Actor8::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); Scene1550 *scene = (Scene1550 *)R2_GLOBALS._sceneManager._scene; scene->_field412 = 1; - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1552; else scene->_sceneMode = 1588; @@ -7624,7 +7634,7 @@ bool Scene1550::Actor9::startAction(CursorType action, Event &event) { scene->_sceneMode = 50; R2_GLOBALS._player.disableControl(); R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_stripManager.start(518, scene); else scene->_stripManager.start(520, scene); @@ -7645,7 +7655,7 @@ bool Scene1550::Actor10::startAction(CursorType action, Event &event) { Scene1550 *scene = (Scene1550 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1555; else scene->_sceneMode = 1589; @@ -7661,7 +7671,7 @@ bool Scene1550::Actor11::startAction(CursorType action, Event &event) { Scene1550 *scene = (Scene1550 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); scene->_field412 = 1; - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_sceneMode = 1586; else scene->_sceneMode = 1587; @@ -7676,7 +7686,7 @@ bool Scene1550::Actor12::startAction(CursorType action, Event &event) { Scene1550 *scene = (Scene1550 *)R2_GLOBALS._sceneManager._scene; - if (R2_GLOBALS._player._characterIndex == 2) { + if (R2_GLOBALS._player._characterIndex == R2_SEEKER) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1585; scene->setAction(&scene->_sequenceManager1, scene, 1585, &R2_GLOBALS._player, NULL); @@ -7756,19 +7766,22 @@ void Scene1550::synchronize(Serializer &s) { } void Scene1550::postInit(SceneObjectList *OwnerList) { - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 9) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 11)) + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 9) && + (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 11)) + // Exiting the intact spaceship loadScene(1234); else + // Normal scene entry loadScene(1550); + SceneExt::postInit(); scalePalette(65, 65, 65); setZoomPercents(30, 75, 170, 100); _field417 = 1550; _field419 = 0; - SceneExt::postInit(); if (R2_GLOBALS._sceneManager._previousScene == -1) - R2_GLOBALS.setFlag(R2_ATTRACTOR_CABLE_HARNESS); + R2_GLOBALS.setFlag(16); if ((R2_GLOBALS._player._characterScene[1] != 1550) && (R2_GLOBALS._player._characterScene[1] != 1580)) { R2_GLOBALS._player._characterScene[1] = 1550; @@ -7783,14 +7796,15 @@ void Scene1550::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.postInit(); R2_GLOBALS._player._effect = 6; - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) R2_GLOBALS._player.setup(1500, 3, 1); else R2_GLOBALS._player.setup(1505, 3, 1); R2_GLOBALS._player._moveDiff = Common::Point(5, 3); - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 9) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 11)) + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 9) && + (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 11)) R2_GLOBALS._player.setPosition(Common::Point(157, 135)); else R2_GLOBALS._player.setPosition(Common::Point(160, 100)); @@ -7799,7 +7813,7 @@ void Scene1550::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.disableControl(); _field414 = 0; - _actor7.changeZoom(-1); + _companion.changeZoom(-1); R2_GLOBALS._player.changeZoom(-1); switch (R2_GLOBALS._sceneManager._previousScene) { @@ -7814,21 +7828,22 @@ void Scene1550::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(105); break; case 1580: + // Leaving intact ship if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1580) { R2_GLOBALS._player.disableControl(); R2_GLOBALS._player.animate(ANIM_MODE_NONE, NULL); _field412 = 1; - _actor1.postInit(); - _arrUnkObj15502[7].subA5CDF(8); - _arrUnkObj15502[7].hide(); - if (R2_GLOBALS._player._characterIndex == 1) + _landingStrut.postInit(); + _shipComponents[7].setupShipComponent(8); + _shipComponents[7].hide(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _sceneMode = 1577; else _sceneMode = 1578; - setAction(&_sequenceManager1, this, _sceneMode, &R2_GLOBALS._player, &_actor1, &_arrUnkObj15502[7], NULL); + setAction(&_sequenceManager1, this, _sceneMode, &R2_GLOBALS._player, &_landingStrut, &_shipComponents[7], NULL); R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 1550; } else { R2_GLOBALS._player.enableControl(); @@ -7838,29 +7853,29 @@ void Scene1550::postInit(SceneObjectList *OwnerList) { break; } - subA2B2F(); + enterArea(); - _item1.setDetails(16, 1550, 10, -1, -1); + _shipHull.setDetails(16, 1550, 10, -1, -1); _item2.setDetails(24, 1550, 10, -1, -1); _item3.setDetails(Rect(0, 0, 320, 200), 1550, 0, 1, -1, 1, NULL); if ((R2_GLOBALS._sceneManager._previousScene == 1500) && (R2_GLOBALS.getFlag(16))) { _sceneMode = 70; - if (!R2_GLOBALS._sceneObjects->contains(&_actor7)) - _actor7.postInit(); + if (!R2_GLOBALS._sceneObjects->contains(&_companion)) + _companion.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) - _actor7.setVisage(1505); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) + _companion.setVisage(1505); else - _actor7.setVisage(1500); + _companion.setVisage(1500); - _actor7.changeZoom(77); - _actor7.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); + _companion.changeZoom(77); + _companion.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); assert(_field419 >= 1550); R2_GLOBALS._walkRegions.enableRegion(k5A750[_field419 - 1550]); - setAction(&_sequenceManager1, this, 1590, &_actor7, NULL); + setAction(&_sequenceManager1, this, 1590, &_companion, NULL); } else if ((_sceneMode != 1577) && (_sceneMode != 1578)) R2_GLOBALS._player.enableControl(); } @@ -7876,7 +7891,7 @@ void Scene1550::signal() { case 7: _field412 = 0; R2_GLOBALS._v56AAB = 0; - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); break; case 20: // No break on purpose @@ -7917,14 +7932,14 @@ void Scene1550::signal() { break; case 40: { _sceneMode = 41; - Common::Point pt(_arrUnkObj15501[0]._position.x, _arrUnkObj15501[0]._position.y + 20); + Common::Point pt(_junk[0]._position.x, _junk[0]._position.y + 20); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, this); } break; case 41: _sceneMode = 42; - if (R2_GLOBALS._player._characterIndex == 1) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.setup(1502, 8, 1); } else { R2_GLOBALS._player.changeZoom(R2_GLOBALS._player._percent + 14); @@ -7932,37 +7947,42 @@ void Scene1550::signal() { } R2_GLOBALS._player.animate(ANIM_MODE_5, this); break; - case 42: + + case 42: { _sceneMode = 43; - warning("TODO: unknown use of arrUnkObj15501[0]._fieldA6"); - switch (_arrUnkObj15501[0]._frame - 1) { - case 0: - R2_INVENTORY.setObjectScene(26, R2_GLOBALS._player._characterIndex); - break; + int junkRegionIndex = R2_GLOBALS._scene1550JunkLocations[_junk[0]._junkNumber + 3]; + R2_GLOBALS._walkRegions.disableRegion(scene1550JunkRegions[junkRegionIndex]); + + switch (_junk[0]._frame) { case 1: - R2_INVENTORY.setObjectScene(17, R2_GLOBALS._player._characterIndex); + R2_INVENTORY.setObjectScene(R2_JOYSTICK, R2_GLOBALS._player._characterIndex); break; case 2: - R2_INVENTORY.setObjectScene(22, R2_GLOBALS._player._characterIndex); + R2_INVENTORY.setObjectScene(R2_FUEL_CELL, R2_GLOBALS._player._characterIndex); break; case 3: - R2_INVENTORY.setObjectScene(25, R2_GLOBALS._player._characterIndex); + R2_INVENTORY.setObjectScene(R2_GUIDANCE_MODULE, R2_GLOBALS._player._characterIndex); break; case 4: - R2_INVENTORY.setObjectScene(45, R2_GLOBALS._player._characterIndex); + R2_INVENTORY.setObjectScene(R2_RADAR_MECHANISM, R2_GLOBALS._player._characterIndex); break; case 5: - R2_INVENTORY.setObjectScene(28, R2_GLOBALS._player._characterIndex); + R2_INVENTORY.setObjectScene(R2_BATTERY, R2_GLOBALS._player._characterIndex); + break; + case 6: + R2_INVENTORY.setObjectScene(R2_DIAGNOSTICS_DISPLAY, R2_GLOBALS._player._characterIndex); break; default: break; } - _arrUnkObj15501[0].remove(); + + _junk[0].remove(); R2_GLOBALS._player.animate(ANIM_MODE_6, this); break; + } case 43: - warning("TODO: unknown use of arrUnkObj15501[0]._fieldA6"); - if (R2_GLOBALS._player._characterIndex == 1) + R2_GLOBALS._scene1550JunkLocations[_junk[0]._junkNumber + 2] = 0; + if (R2_GLOBALS._player._characterIndex == R2_QUINN) R2_GLOBALS._player.setVisage(1500); else { R2_GLOBALS._player.changeZoom(-1); @@ -7976,29 +7996,29 @@ void Scene1550::signal() { warning("STUB: sub_1D227()"); ++_sceneMode; setAction(&_sequenceManager1, this, 1591, &R2_GLOBALS._player, NULL); - if (g_globals->_sceneObjects->contains(&_actor7)) + if (g_globals->_sceneObjects->contains(&_companion)) signal(); else { - _actor7.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) - _actor7.setVisage(1505); + _companion.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) + _companion.setVisage(1505); else - _actor7.setVisage(1500); - _actor7.changeZoom(77); - _actor7.setAction(&_sequenceManager2, this, 1590, &_actor7, NULL); - _actor7.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); + _companion.setVisage(1500); + _companion.changeZoom(77); + _companion.setAction(&_sequenceManager2, this, 1590, &_companion, NULL); + _companion.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); } break; case 51: ++_sceneMode; break; case 52: - _actor7.changeZoom(-1); + _companion.changeZoom(-1); _sceneMode = 1592; - if (R2_GLOBALS._player._characterIndex == 1) - setAction(&_sequenceManager1, this, 1592, &R2_GLOBALS._player, &_actor7, &_arrUnkObj15501[0], &_actor9, NULL); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) + setAction(&_sequenceManager1, this, 1592, &R2_GLOBALS._player, &_companion, &_junk[0], &_actor9, NULL); else - setAction(&_sequenceManager1, this, 1593, &R2_GLOBALS._player, &_actor7, &_arrUnkObj15501[0], &_actor9, NULL); + setAction(&_sequenceManager1, this, 1593, &R2_GLOBALS._player, &_companion, &_junk[0], &_actor9, NULL); break; case 61: R2_GLOBALS._player.enableControl(CURSOR_USE); @@ -8013,9 +8033,8 @@ void Scene1550::signal() { } break; case 70: - R2_GLOBALS._v565EC[2] = R2_GLOBALS._v565EC[1]; - R2_GLOBALS._v565EC[4] = R2_GLOBALS._v565EC[3]; - R2_GLOBALS._v565EC[0] = 1; + R2_GLOBALS._s1550PlayerArea[R2_SEEKER] = R2_GLOBALS._s1550PlayerArea[R2_QUINN]; + //R2_GLOBALS._s1550PlayerAreas[0] = 1; _sceneMode = 60; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(500, this); @@ -8026,13 +8045,13 @@ void Scene1550::signal() { R2_GLOBALS._player.disableControl(); R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); if (R2_GLOBALS._v565AE >= 3) { - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _stripManager.start(572, this); else _stripManager.start(573, this); } else { ++R2_GLOBALS._v565AE; - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _stripManager.start(499 + R2_GLOBALS._v565AE, this); else _stripManager.start(502 + R2_GLOBALS._v565AE, this); @@ -8042,13 +8061,13 @@ void Scene1550::signal() { R2_GLOBALS._player.disableControl(); R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); if (R2_GLOBALS._v565AE >= 4) { - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _stripManager.start(572, this); else _stripManager.start(573, this); } else { ++R2_GLOBALS._v565AE; - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _stripManager.start(563 + R2_GLOBALS._v565AE, this); else _stripManager.start(567 + R2_GLOBALS._v565AE, this); @@ -8112,7 +8131,7 @@ void Scene1550::signal() { // No break on purpose case 1579: _field412 = 0; - _actor1.remove(); + _landingStrut.remove(); R2_INVENTORY.setObjectScene(R2_GUIDANCE_MODULE, 0); R2_GLOBALS._player.enableControl(); break; @@ -8120,7 +8139,7 @@ void Scene1550::signal() { // No break on purpose case 1580: _field412 = 0; - _actor1.remove(); + _landingStrut.remove(); R2_INVENTORY.setObjectScene(R2_RADAR_MECHANISM, 0); R2_GLOBALS._player.enableControl(); break; @@ -8128,19 +8147,19 @@ void Scene1550::signal() { // No break on purpose case 1581: _field412 = 0; - _actor1.remove(); + _landingStrut.remove(); R2_INVENTORY.setObjectScene(R2_GYROSCOPE, 0); R2_GLOBALS._player.enableControl(); break; case 1572: _field412 = 0; - _actor1.remove(); + _landingStrut.remove(); R2_INVENTORY.setObjectScene(R2_THRUSTER_VALVE, 0); R2_GLOBALS._player.enableControl(); break; case 1573: _field412 = 0; - _actor1.remove(); + _landingStrut.remove(); R2_INVENTORY.setObjectScene(R2_IGNITOR, 0); R2_GLOBALS._player.enableControl(); break; @@ -8148,7 +8167,7 @@ void Scene1550::signal() { // No break on purpose case 1582: _field412 = 0; - _actor1.remove(); + _landingStrut.remove(); R2_INVENTORY.setObjectScene(R2_FUEL_CELL, 0); R2_GLOBALS._player.enableControl(); break; @@ -8156,7 +8175,7 @@ void Scene1550::signal() { // No break on purpose case 1583: _field412 = 0; - _actor1.remove(); + _landingStrut.remove(); R2_INVENTORY.setObjectScene(R2_BATTERY, 0); R2_GLOBALS._player.enableControl(); break; @@ -8170,7 +8189,7 @@ void Scene1550::signal() { // No break on purpose case 1578: _sceneMode = 0; - _actor1.remove(); + _landingStrut.remove(); _field412 = 0; R2_GLOBALS._player.fixPriority(-1); R2_GLOBALS._player.enableControl(); @@ -8183,19 +8202,17 @@ void Scene1550::signal() { // No break on purpose case 1587: R2_INVENTORY.setObjectScene(R2_DIAGNOSTICS_DISPLAY, R2_GLOBALS._player._characterIndex); - _actor1.remove(); + _landingStrut.remove(); _field412 = 0; R2_GLOBALS._player.enableControl(); break; case 1592: _actor9.remove(); R2_INVENTORY.setObjectScene(R2_JOYSTICK, 1); - if (R2_GLOBALS._player._characterIndex == 1) { - R2_GLOBALS._v565EC[2] = R2_GLOBALS._v565EC[1]; - R2_GLOBALS._v565EC[4] = R2_GLOBALS._v565EC[3]; + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + R2_GLOBALS._s1550PlayerArea[R2_SEEKER] = R2_GLOBALS._s1550PlayerArea[R2_QUINN]; } else { - R2_GLOBALS._v565EC[1] = R2_GLOBALS._v565EC[2]; - R2_GLOBALS._v565EC[3] = R2_GLOBALS._v565EC[4]; + R2_GLOBALS._s1550PlayerArea[R2_QUINN] = R2_GLOBALS._s1550PlayerArea[R2_SEEKER]; } R2_GLOBALS._player.enableControl(); break; @@ -8227,11 +8244,11 @@ void Scene1550::dispatch() { Scene::dispatch(); // Arrays related to this scene are all hacky in the origina: they are based on the impossibility to use Miranda - assert ((R2_GLOBALS._player._characterIndex == 1) || (R2_GLOBALS._player._characterIndex == 2)); + assert ((R2_GLOBALS._player._characterIndex == R2_QUINN) || (R2_GLOBALS._player._characterIndex == R2_SEEKER)); - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 15) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 16)) { + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 15) && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 16)) { R2_GLOBALS._player._shade = 0; - // Original game contains a switch based on an uninitialised variable. + // Original game contains a switch based on an uninitialized variable. // Until we understand what should really happen there, this code is unused on purpose int missingVariable = 0; switch (missingVariable) { @@ -8263,12 +8280,13 @@ void Scene1550::dispatch() { case 0: // No break on purpose case 5: + // Exiting the top of the screen R2_GLOBALS._player.disableControl(); _sceneMode = 1; _field412 = 1; - --R2_GLOBALS._v565EC[2 + R2_GLOBALS._player._characterIndex]; + --R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y; - subA2B2F(); + enterArea(); R2_GLOBALS._player.setPosition(Common::Point( 160 - (((((160 - R2_GLOBALS._player._position.x) * 100) / 108) * 172) / 100), 145)); if (R2_GLOBALS._player._position.x < 160) { @@ -8286,12 +8304,13 @@ void Scene1550::dispatch() { } break; case 1: + // Exiting the bottom of the screen R2_GLOBALS._player.disableControl(); _sceneMode = 3; _field412 = 1; - ++R2_GLOBALS._v565EC[2 + R2_GLOBALS._player._characterIndex]; + ++R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y; - subA2B2F(); + enterArea(); R2_GLOBALS._player.setPosition(Common::Point( 160 - (((((160 - R2_GLOBALS._player._position.x) * 100) / 172) * 108) / 100), 19)); if (R2_GLOBALS._player._position.x < 160) { @@ -8309,14 +8328,15 @@ void Scene1550::dispatch() { } break; case 2: + // Exiting the right of the screen R2_GLOBALS._player.disableControl(); _sceneMode = 5; _field412 = 1; - ++R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]; + ++R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x; - subA2B2F(); + enterArea(); - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 9) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 11) && (R2_GLOBALS._player._position.y > 50) && (R2_GLOBALS._player._position.y < 135)) { + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 9) && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 11) && (R2_GLOBALS._player._position.y > 50) && (R2_GLOBALS._player._position.y < 135)) { if (R2_GLOBALS._player._position.y >= 85) { R2_GLOBALS._player.setPosition(Common::Point(320 - R2_GLOBALS._player._position.x, R2_GLOBALS._player._position.y + 10)); Common::Point pt(R2_GLOBALS._player._position.x + 30, R2_GLOBALS._player._position.y + 20); @@ -8336,16 +8356,20 @@ void Scene1550::dispatch() { } break; case 3: + // Exiting to the left of the screen R2_GLOBALS._player.disableControl(); _sceneMode = 7; _field412 = 1; - --R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]; - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 24) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 11)) { + --R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x; + + enterArea(); + + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 24) && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 11)) { R2_GLOBALS._player.setPosition(Common::Point(320 - R2_GLOBALS._player._position.x, R2_GLOBALS._player._position.y / 2)); Common::Point pt(265, 29); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, this); - } else if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 9) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 11) && (R2_GLOBALS._player._position.y > 50) && (R2_GLOBALS._player._position.y < 135)) { + } else if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 9) && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 11) && (R2_GLOBALS._player._position.y > 50) && (R2_GLOBALS._player._position.y < 135)) { if (R2_GLOBALS._player._position.y >= 85) { R2_GLOBALS._player.setPosition(Common::Point(320 - R2_GLOBALS._player._position.x, R2_GLOBALS._player._position.y + 10)); Common::Point pt(R2_GLOBALS._player._position.x - 30, R2_GLOBALS._player._position.y + 20); @@ -8370,7 +8394,7 @@ void Scene1550::dispatch() { } void Scene1550::saveCharacter(int characterIndex) { - if (R2_GLOBALS._player._characterIndex == 3) + if (R2_GLOBALS._player._characterIndex == R2_MIRANDA) R2_GLOBALS._sound1.fadeOut2(NULL); SceneExt::saveCharacter(characterIndex); @@ -8560,7 +8584,7 @@ void Scene1550::SceneActor1550::subA4D14(int frameNumber, int strip) { } -void Scene1550::subA2B2F() { +void Scene1550::enterArea() { Rect tmpRect; _field419 = 0; _field415 = 0; @@ -8568,19 +8592,19 @@ void Scene1550::subA2B2F() { tmpRect = R2_GLOBALS._v5589E; _actor14.remove(); - _actor17.remove(); - _actor15.remove(); - _actor19.remove(); + _westWall.remove(); + _northWall.remove(); + _southWall.remove(); _actor16.remove(); - _actor18.remove(); + _eastWall.remove(); for (int i = 0; i < 8; ++i) - _arrUnkObj15501[i].remove(); + _junk[i].remove(); - _actor6.remove(); + _wreckage.remove(); for (int i = 0; i < 8; ++i) - _arrUnkObj15502[i].remove(); + _shipComponents[i].remove(); _actor8.remove(); _actor9.remove(); @@ -8589,18 +8613,19 @@ void Scene1550::subA2B2F() { _actor11.remove(); if ((_sceneMode != 1577) && (_sceneMode != 1578)) - _actor1.remove(); + _landingStrut.remove(); _actor2.remove(); - _actor7.remove(); + _companion.remove(); _actor13.remove(); _actor5.remove(); _actor12.remove(); _actor4.remove(); - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2]) { + // Set up of special walk regions for certain areas + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y) { case 0: - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x) { case 3: R2_GLOBALS._walkRegions.load(1554); _field419 = 1554; @@ -8616,7 +8641,7 @@ void Scene1550::subA2B2F() { case 3: // No break on purpose case 4: - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 23) || (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex])) { + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 23) || (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x)) { if (!R2_GLOBALS.getFlag(16)) { R2_GLOBALS._walkRegions.load(1559); _field419 = 1559; @@ -8624,7 +8649,7 @@ void Scene1550::subA2B2F() { } break; case 7: - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x) { case 10: R2_GLOBALS._walkRegions.load(1555); _field419 = 1555; @@ -8638,7 +8663,7 @@ void Scene1550::subA2B2F() { } break; case 11: - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x) { case 24: R2_GLOBALS._walkRegions.load(1558); _field419 = 1558; @@ -8652,7 +8677,7 @@ void Scene1550::subA2B2F() { } break; case 16: - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x) { case 2: R2_GLOBALS._walkRegions.load(1552); _field419 = 1552; @@ -8675,12 +8700,12 @@ void Scene1550::subA2B2F() { int varA = 0; if (!R2_GLOBALS.getFlag(16)) { - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] - 2) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y - 2) { case 0: - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] - 22) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x - 22) { case 0: varA = 1553; - _actor15.subA4D14(6, 0); + _northWall.subA4D14(6, 0); break; case 1: // No break on purpose @@ -8693,7 +8718,7 @@ void Scene1550::subA2B2F() { break; case 5: varA = 1553; - _actor15.subA4D14(6, 0); + _northWall.subA4D14(6, 0); break; default: break; @@ -8702,14 +8727,14 @@ void Scene1550::subA2B2F() { case 1: // No break on purpose case 2: - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] - 21) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x - 21) { case 0: varA = 1550; - _actor15.subA4D14(9, 0); + _northWall.subA4D14(9, 0); break; case 1: varA = 1552; - _actor15.subA4D14(10, 0); + _northWall.subA4D14(10, 0); break; case 2: // No break on purpose @@ -8722,25 +8747,25 @@ void Scene1550::subA2B2F() { break; case 6: varA = 1552; - _actor15.subA4D14(7, 0); + _northWall.subA4D14(7, 0); break; case 7: varA = 1550; - _actor15.subA4D14(8, 0); + _northWall.subA4D14(8, 0); break; default: break; } break; case 3: - switch (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] - 21) { + switch (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x - 21) { case 0: varA = 1550; - _actor15.subA4D14(4, 0); + _northWall.subA4D14(4, 0); break; case 1: varA = 1550; - _actor15.subA4D14(3, 0); + _northWall.subA4D14(3, 0); break; case 2: // No break on purpose @@ -8753,11 +8778,11 @@ void Scene1550::subA2B2F() { break; case 6: varA = 1550; - _actor15.subA4D14(2, 0); + _northWall.subA4D14(2, 0); break; case 7: varA = 1550; - _actor15.subA4D14(1, 0); + _northWall.subA4D14(1, 0); break; default: break; @@ -8766,21 +8791,22 @@ void Scene1550::subA2B2F() { default: break; } - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] > 0) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] <= 29) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] >= 20) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] > 7)) { + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y > 0) && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x <= 29) && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x >= 20) && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y > 7)) { R2_GLOBALS.setFlag(16); R2_GLOBALS._sceneManager.changeScene(1500); } } - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == 9) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 11)) { - if (R2_GLOBALS._sceneManager._sceneNumber != 1234) { + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == 9) && + (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 11)) { + if (_screenNumber != 1234) { R2_GLOBALS._sceneManager._fadeMode = FADEMODE_IMMEDIATE; loadScene(1234); R2_GLOBALS._sceneManager._hasPalette = false; _field414 = 0; } } else { - if (R2_GLOBALS._sceneManager._sceneNumber == 1234) { + if (_screenNumber == 1234) { R2_GLOBALS._sceneManager._fadeMode = FADEMODE_IMMEDIATE; loadScene(1550); R2_GLOBALS._sceneManager._hasPalette = false; @@ -8828,71 +8854,75 @@ void Scene1550::subA2B2F() { } } - switch (k5A4D6[(R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] * 30)] + R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex]) { + // Scene setup dependent on the type of cell specified in the scene map + switch (scene1550AreaMap[(R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y * 30) + + R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x]) { case 0: + // Standard cell if (_field419 == 0) { R2_GLOBALS._walkRegions.load(1550); _field419 = 1550; } break; case 1: + // North end of the spaceport if (_field419 == 0) { R2_GLOBALS._walkRegions.load(1560); _field419 = 1560; } _actor14.subA4D14(2, 1); - _actor15.subA4D14(1, 3); + _northWall.subA4D14(1, 3); _actor16.subA4D14(2, 5); break; case 2: R2_GLOBALS._walkRegions.load(1561); _field419 = 1561; _actor14.subA4D14(2, 1); - _actor17.subA4D14(2, 2); - _actor15.subA4D14(1, 3); + _westWall.subA4D14(2, 2); + _northWall.subA4D14(1, 3); _actor16.subA4D14(2, 5); break; case 3: R2_GLOBALS._walkRegions.load(1562); _field419 = 1562; _actor14.subA4D14(2, 1); - _actor15.subA4D14(1, 3); + _northWall.subA4D14(1, 3); _actor16.subA4D14(2, 5); - _actor18.subA4D14(2, 6); + _eastWall.subA4D14(2, 6); break; case 4: R2_GLOBALS._walkRegions.load(1563); _field419 = 1563; - _actor15.subA4D14(2, 3); + _northWall.subA4D14(2, 3); break; case 5: R2_GLOBALS._walkRegions.load(1564); _field419 = 1564; - _actor19.subA4D14(2, 4); + _southWall.subA4D14(2, 4); break; case 6: R2_GLOBALS._walkRegions.load(1565); _field419 = 1565; _actor14.subA4D14(1, 1); - _actor17.subA4D14(1, 2); - _actor15.subA4D14(3, 3); + _westWall.subA4D14(1, 2); + _northWall.subA4D14(3, 3); break; case 7: R2_GLOBALS._walkRegions.load(1566); _field419 = 1566; _actor14.subA4D14(1, 1); - _actor17.subA4D14(1, 2); - _actor15.subA4D14(2, 4); + _westWall.subA4D14(1, 2); + _northWall.subA4D14(2, 4); break; case 8: R2_GLOBALS._walkRegions.load(1567); _field419 = 1567; - _actor17.subA4D14(5, 2); + _westWall.subA4D14(5, 2); break; case 9: R2_GLOBALS._walkRegions.load(1568); _field419 = 1568; - _actor17.subA4D14(4, 2); + _westWall.subA4D14(4, 2); break; case 10: R2_GLOBALS._walkRegions.load(1569); @@ -8903,56 +8933,57 @@ void Scene1550::subA2B2F() { R2_GLOBALS._walkRegions.load(1570); _field419 = 1570; _actor14.subA4D14(1, 1); - _actor17.subA4D14(1, 2); + _westWall.subA4D14(1, 2); break; case 12: R2_GLOBALS._walkRegions.load(1571); _field419 = 1571; _actor16.subA4D14(1, 5); - _actor18.subA4D14(1, 6); + _eastWall.subA4D14(1, 6); break; case 13: R2_GLOBALS._walkRegions.load(1572); _field419 = 1572; _actor14.subA4D14(1, 1); - _actor17.subA4D14(1, 2); - _actor19.subA4D14(1, 4); + _westWall.subA4D14(1, 2); + _southWall.subA4D14(1, 4); break; case 14: R2_GLOBALS._walkRegions.load(1573); _field419 = 1573; - _actor19.subA4D14(1, 4); + _southWall.subA4D14(1, 4); _actor16.subA4D14(1, 5); - _actor18.subA4D14(1, 6); + _eastWall.subA4D14(1, 6); break; case 15: + // South wall R2_GLOBALS._walkRegions.load(1574); _field419 = 1574; - _actor19.subA4D14(1, 4); + _southWall.subA4D14(1, 4); break; case 16: R2_GLOBALS._walkRegions.load(1570); _field419 = 1570; _actor14.subA4D14(2, 1); - _actor17.subA4D14(2, 2); + _westWall.subA4D14(2, 2); break; case 17: R2_GLOBALS._walkRegions.load(1570); _field419 = 1570; _actor14.subA4D14(2, 1); - _actor17.subA4D14(3, 2); + _westWall.subA4D14(3, 2); break; case 18: R2_GLOBALS._walkRegions.load(1571); _field419 = 1571; _actor16.subA4D14(2, 5); - _actor18.subA4D14(2, 6); + _eastWall.subA4D14(2, 6); break; case 19: R2_GLOBALS._walkRegions.load(1571); _field419 = 1571; _actor16.subA4D14(2, 5); - _actor18.subA4D14(3, 6); + _eastWall.subA4D14(3, 6); break; default: break; @@ -8960,24 +8991,27 @@ void Scene1550::subA2B2F() { int di = 0; int tmpIdx = 0; - // Original game was checking "i < 129" but it was clearly a bug as it's out of bounds - for (int i = 0; i < 129 * 4; i += 4) { - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == k562CC[i]) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == k562CC[i + 1]) && (k562CC[i + 2] != 0)) { - tmpIdx = k562CC[i + 3]; - _arrUnkObj15501[di].postInit(); - _arrUnkObj15501[di]._effect = 6; - _arrUnkObj15501[di]._shade = 0; - _arrUnkObj15501[di]._fieldA4 = tmpIdx; - _arrUnkObj15501[di]._fieldA6 = i; - _arrUnkObj15501[di].setDetails(1550, 62, -1, 63, 2, (SceneItem *) NULL); - if (k562CC[i + 2] == 41) { - _arrUnkObj15501[di].changeZoom(-1); - _arrUnkObj15501[di].setPosition(Common::Point(150, 70)); - _arrUnkObj15501[di].setup(1562, 1, 1); - R2_GLOBALS._walkRegions.enableRegion(k5A78C); - R2_GLOBALS._walkRegions.enableRegion(k5A78D); - R2_GLOBALS._walkRegions.enableRegion(k5A790); - R2_GLOBALS._walkRegions.enableRegion(k5A791); + for (int i = 0; i < 127 * 4; i += 4) { + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == R2_GLOBALS._scene1550JunkLocations[i]) && + (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == R2_GLOBALS._scene1550JunkLocations[i + 1]) && + (R2_GLOBALS._scene1550JunkLocations[i + 2] != 0)) { + tmpIdx = R2_GLOBALS._scene1550JunkLocations[i + 3]; + _junk[di].postInit(); + _junk[di]._effect = 6; + _junk[di]._shade = 0; + _junk[di]._fieldA4 = tmpIdx; + _junk[di]._junkNumber = i; + _junk[di].setDetails(1550, 62, -1, 63, 2, (SceneItem *) NULL); + if (R2_GLOBALS._scene1550JunkLocations[i + 2] == 41) { + _junk[di].changeZoom(-1); + _junk[di].setPosition(Common::Point(150, 70)); + _junk[di].setup(1562, 1, 1); + + R2_GLOBALS._walkRegions.enableRegion(scene1550JunkRegions[2]); + R2_GLOBALS._walkRegions.enableRegion(scene1550JunkRegions[3]); + R2_GLOBALS._walkRegions.enableRegion(scene1550JunkRegions[6]); + R2_GLOBALS._walkRegions.enableRegion(scene1550JunkRegions[7]); + if (R2_INVENTORY.getObjectScene(R2_JOYSTICK) == 1550) { _actor9.postInit(); _actor9.setup(1562, 3, 1); @@ -8986,35 +9020,36 @@ void Scene1550::subA2B2F() { _actor9.setDetails(1550, 41, -1, 42, 2, (SceneItem *) NULL); } } else { - if (k562CC[i + 2] > 40) { - _arrUnkObj15501[di].changeZoom(100); - _arrUnkObj15501[di].setup(1561, 1, k562CC[i + 2] - 40); + if (R2_GLOBALS._scene1550JunkLocations[i + 2] > 40) { + _junk[di].changeZoom(100); + _junk[di].setup(1561, 1, R2_GLOBALS._scene1550JunkLocations[i + 2] - 40); } else { - _arrUnkObj15501[di].changeZoom(-1); - _arrUnkObj15501[di].setup(1552, ((k562CC[i + 2] - 1) / 5) + 1, ((k562CC[i + 2] - 1) % 5) + 1); + _junk[di].changeZoom(-1); + _junk[di].setup(1552, ((R2_GLOBALS._scene1550JunkLocations[i + 2] - 1) / 5) + 1, ((R2_GLOBALS._scene1550JunkLocations[i + 2] - 1) % 5) + 1); } - _arrUnkObj15501[di].setPosition(Common::Point(k5A72E[tmpIdx], k5A73F[tmpIdx])); - if (k5A78A[tmpIdx] != 0) - R2_GLOBALS._walkRegions.enableRegion(k5A78A[tmpIdx]); + _junk[di].setPosition(Common::Point(k5A72E[tmpIdx], k5A73F[tmpIdx])); + if (scene1550JunkRegions[tmpIdx] != 0) + R2_GLOBALS._walkRegions.enableRegion(scene1550JunkRegions[tmpIdx]); di++; } } } for (int i = 0; i < 15 * 3; i++) { - if ((R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex] == k5A79B[i]) && (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == k5A79B[i + 1])) { + if ((R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].x == k5A79B[i]) + && (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == k5A79B[i + 1])) { tmpIdx = k5A79B[i + 2]; switch (tmpIdx - 1) { case 0: if (!R2_GLOBALS.getFlag(16)) { - _actor1.postInit(); - if (R2_GLOBALS._v565EC[R2_GLOBALS._player._characterIndex + 2] == 3) - _actor1.setup(1555, 2, 1); + _landingStrut.postInit(); + if (R2_GLOBALS._s1550PlayerArea[R2_GLOBALS._player._characterIndex].y == 3) + _landingStrut.setup(1555, 2, 1); else - _actor1.setup(1555, 1, 1); - _actor1.setPosition(Common::Point(150, 100)); - _actor1.fixPriority(92); - _actor1.setDetails(1550, 73, -1, -1, 2, (SceneItem *) NULL); + _landingStrut.setup(1555, 1, 1); + _landingStrut.setPosition(Common::Point(150, 100)); + _landingStrut.fixPriority(92); + _landingStrut.setDetails(1550, 73, -1, -1, 2, (SceneItem *) NULL); } break; case 1: @@ -9053,20 +9088,20 @@ void Scene1550::subA2B2F() { _actor4.setPosition(Common::Point(172, 48)); _actor4.fixPriority(169); - R2_GLOBALS._walkRegions.enableRegion(k5A78A[15]); + R2_GLOBALS._walkRegions.enableRegion(scene1550JunkRegions[15]); break; case 2: - _actor6.postInit(); - _actor6.setup(1550, 1, 1); - _actor6.setPosition(Common::Point(259, 55)); - _actor6.fixPriority(133); - _actor6.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); - - _actor1.postInit(); - _actor1.setup(1550, 1, 2); - _actor1.setPosition(Common::Point(259, 133)); - _actor1.fixPriority(105); - _actor1.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 1, 1); + _wreckage.setPosition(Common::Point(259, 55)); + _wreckage.fixPriority(133); + _wreckage.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + + _landingStrut.postInit(); + _landingStrut.setup(1550, 1, 2); + _landingStrut.setPosition(Common::Point(259, 133)); + _landingStrut.fixPriority(105); + _landingStrut.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); if (R2_INVENTORY.getObjectScene(R2_GYROSCOPE) == 1550) { _actor10.postInit(); _actor10.setup(1550, 7, 2); @@ -9076,16 +9111,16 @@ void Scene1550::subA2B2F() { } break; case 3: - _actor6.postInit(); - _actor6.setup(1550, 1, 4); - _actor6.setPosition(Common::Point(76, 131)); - _actor6.fixPriority(10); - _actor6.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); - - _actor1.postInit(); - _actor1.setup(1550, 1, 3); - _actor1.setPosition(Common::Point(76, 64)); - _actor1.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 1, 4); + _wreckage.setPosition(Common::Point(76, 131)); + _wreckage.fixPriority(10); + _wreckage.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + + _landingStrut.postInit(); + _landingStrut.setup(1550, 1, 3); + _landingStrut.setPosition(Common::Point(76, 64)); + _landingStrut.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); if (R2_INVENTORY.getObjectScene(R2_DIAGNOSTICS_DISPLAY) == 1550) { _actor11.postInit(); _actor11.setup(1504, 4, 1); @@ -9104,48 +9139,48 @@ void Scene1550::subA2B2F() { } break; case 4: - _actor6.postInit(); - _actor6.setup(1550, 2, 4); - _actor6.setPosition(Common::Point(243, 131)); - _actor6.fixPriority(10); - _actor6.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); - - _actor1.postInit(); - _actor1.setup(1550, 2, 3); - _actor1.setPosition(Common::Point(243, 64)); - _actor1.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 2, 4); + _wreckage.setPosition(Common::Point(243, 131)); + _wreckage.fixPriority(10); + _wreckage.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + + _landingStrut.postInit(); + _landingStrut.setup(1550, 2, 3); + _landingStrut.setPosition(Common::Point(243, 64)); + _landingStrut.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); break; case 5: - _actor6.postInit(); - _actor6.setup(1550, 2, 1); - _actor6.setPosition(Common::Point(60, 55)); - _actor6.fixPriority(133); - _actor6.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); - - _actor1.postInit(); - _actor1.setup(1550, 2, 2); - _actor1.setPosition(Common::Point(60, 133)); - _actor1.fixPriority(106); - _actor1.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 2, 1); + _wreckage.setPosition(Common::Point(60, 55)); + _wreckage.fixPriority(133); + _wreckage.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); + + _landingStrut.postInit(); + _landingStrut.setup(1550, 2, 2); + _landingStrut.setPosition(Common::Point(60, 133)); + _landingStrut.fixPriority(106); + _landingStrut.setDetails(1550, 9, -1, -1, 2, (SceneItem *) NULL); break; case 6: - _actor6.postInit(); - _actor6.setup(1550, 3, 1); - _actor6.setPosition(Common::Point(281, 132)); - _actor6.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 3, 1); + _wreckage.setPosition(Common::Point(281, 132)); + _wreckage.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); break; case 7: - _actor6.postInit(); - _actor6.setup(1550, 3, 2); - _actor6.setPosition(Common::Point(57, 96)); - _actor6.fixPriority(70); - _actor6.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); - - _actor1.postInit(); - _actor1.setup(1550, 3, 3); - _actor1.setPosition(Common::Point(145, 88)); - _actor1.fixPriority(55); - _actor1.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 3, 2); + _wreckage.setPosition(Common::Point(57, 96)); + _wreckage.fixPriority(70); + _wreckage.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); + + _landingStrut.postInit(); + _landingStrut.setup(1550, 3, 3); + _landingStrut.setPosition(Common::Point(145, 88)); + _landingStrut.fixPriority(55); + _landingStrut.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); _actor2.postInit(); _actor2.setup(1550, 3, 4); @@ -9159,17 +9194,17 @@ void Scene1550::subA2B2F() { _actor3.fixPriority(45); break; case 8: - _actor6.postInit(); - _actor6.setup(1550, 4, 2); - _actor6.setPosition(Common::Point(262, 96)); - _actor6.fixPriority(70); - _actor6.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); - - _actor1.postInit(); - _actor1.setup(1550, 4, 3); - _actor1.setPosition(Common::Point(174, 88)); - _actor1.fixPriority(55); - _actor1.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 4, 2); + _wreckage.setPosition(Common::Point(262, 96)); + _wreckage.fixPriority(70); + _wreckage.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); + + _landingStrut.postInit(); + _landingStrut.setup(1550, 4, 3); + _landingStrut.setPosition(Common::Point(174, 88)); + _landingStrut.fixPriority(55); + _landingStrut.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); _actor2.postInit(); _actor2.setup(1550, 4, 4); @@ -9183,55 +9218,56 @@ void Scene1550::subA2B2F() { _actor3.fixPriority(45); break; case 9: - _actor6.postInit(); - _actor6.setup(1550, 4, 1); - _actor6.setPosition(Common::Point(38, 132)); - _actor6.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); + _wreckage.postInit(); + _wreckage.setup(1550, 4, 1); + _wreckage.setPosition(Common::Point(38, 132)); + _wreckage.setDetails(1550, 56, -1, -1, 2, (SceneItem *) NULL); break; case 11: - _arrUnkObj15502[7].subA5CDF(8); - _arrUnkObj15502[0].subA5CDF(1); - _arrUnkObj15502[1].subA5CDF(2); - _arrUnkObj15502[2].subA5CDF(3); - _arrUnkObj15502[3].subA5CDF(4); - _arrUnkObj15502[4].subA5CDF(5); - _arrUnkObj15502[5].subA5CDF(6); - _arrUnkObj15502[6].subA5CDF(7); + // Intact ship + _shipComponents[7].setupShipComponent(8); + _shipComponents[0].setupShipComponent(1); + _shipComponents[1].setupShipComponent(2); + _shipComponents[2].setupShipComponent(3); + _shipComponents[3].setupShipComponent(4); + _shipComponents[4].setupShipComponent(5); + _shipComponents[5].setupShipComponent(6); + _shipComponents[6].setupShipComponent(7); default: break; } } } - if ((R2_GLOBALS._v565EC[1] == R2_GLOBALS._v565EC[2]) && (R2_GLOBALS._v565EC[3] == R2_GLOBALS._v565EC[4])) { - _actor7.postInit(); - _actor7._effect = 7; - _actor7.changeZoom(-1); + if (R2_GLOBALS._s1550PlayerArea[R2_QUINN] == R2_GLOBALS._s1550PlayerArea[R2_SEEKER]) { + _companion.postInit(); + _companion._effect = 7; + _companion.changeZoom(-1); assert((_field419 >= 1550) && (_field419 <= 2008)); R2_GLOBALS._walkRegions.enableRegion(k5A750[_field419 - 1550]); - _actor7.setPosition(Common::Point(k5A72E[k5A76D[_field419 - 1550]], k5A73F[k5A76D[_field419 - 1550]] + 8)); - if (R2_GLOBALS._player._characterIndex == 1) { + _companion.setPosition(Common::Point(k5A72E[k5A76D[_field419 - 1550]], k5A73F[k5A76D[_field419 - 1550]] + 8)); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS._player._characterScene[2] == 1580) { - _actor7.setup(1516, 3, 17); - _actor7.setPosition(Common::Point(272, 94)); - _actor7.fixPriority(91); - _actor7.changeZoom(100); - _actor7.setDetails(1550, -1, -1, -1, 5, &_arrUnkObj15502[7]); + _companion.setup(1516, 3, 17); + _companion.setPosition(Common::Point(272, 94)); + _companion.fixPriority(91); + _companion.changeZoom(100); + _companion.setDetails(1550, -1, -1, -1, 5, &_shipComponents[7]); } else { - _actor7.setup(1505, 6, 1); - _actor7.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); + _companion.setup(1505, 6, 1); + _companion.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); } } else { if (R2_GLOBALS._player._characterScene[1] == 1580) { - _actor7.setup(1516, 2, 14); - _actor7.setPosition(Common::Point(276, 97)); - _actor7.fixPriority(91); - _actor7.changeZoom(100); - _actor7.setDetails(1550, -1, -1, -1, 5, &_arrUnkObj15502[7]); + _companion.setup(1516, 2, 14); + _companion.setPosition(Common::Point(276, 97)); + _companion.fixPriority(91); + _companion.changeZoom(100); + _companion.setDetails(1550, -1, -1, -1, 5, &_shipComponents[7]); } else { - _actor7.setup(1500, 6, 1); - _actor7.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); + _companion.setup(1500, 6, 1); + _companion.setDetails(1550, -1, -1, -1, 2, (SceneItem *) NULL); } } } @@ -9636,7 +9672,7 @@ bool Scene1580::Hotspot1::startAction(CursorType action, Event &event) { Scene1580 *scene = (Scene1580 *)R2_GLOBALS._sceneManager._scene; if (action == R2_JOYSTICK) { - R2_INVENTORY.setObjectScene(26, 1580); + R2_INVENTORY.setObjectScene(R2_JOYSTICK, 1580); R2_GLOBALS._sceneItems.remove(&scene->_item1); scene->_actor2.postInit(); scene->_actor2.setup(1580, 1, 4); @@ -9655,7 +9691,7 @@ bool Scene1580::Hotspot2::startAction(CursorType action, Event &event) { Scene1580 *scene = (Scene1580 *)R2_GLOBALS._sceneManager._scene; if (action == R2_DIAGNOSTICS_DISPLAY) { - R2_INVENTORY.setObjectScene(28, 1580); + R2_INVENTORY.setObjectScene(R2_DIAGNOSTICS_DISPLAY, 1580); R2_GLOBALS._player.disableControl(); R2_GLOBALS._sceneItems.remove(&scene->_item2); @@ -9664,7 +9700,7 @@ bool Scene1580::Hotspot2::startAction(CursorType action, Event &event) { scene->_actor3.setPosition(Common::Point(124, 108)); scene->_actor3.fixPriority(10); - if (R2_INVENTORY.getObjectScene(26) == 1580) + if (R2_INVENTORY.getObjectScene(R2_JOYSTICK) == 1580) scene->_actor3.setDetails(1550, 14, -1, -1, 5, &scene->_actor2); else scene->_actor3.setDetails(1550, 14, -1, -1, 2, (SceneItem *)NULL); @@ -9684,15 +9720,15 @@ bool Scene1580::Hotspot2::startAction(CursorType action, Event &event) { } bool Scene1580::Actor2::startAction(CursorType action, Event &event) { - if ( (action == CURSOR_USE) && (R2_INVENTORY.getObjectScene(28) == 1580) - && (R2_INVENTORY.getObjectScene(17) == 0) && (R2_INVENTORY.getObjectScene(22) == 0) - && (R2_INVENTORY.getObjectScene(25) == 0) && (R2_INVENTORY.getObjectScene(18) == 0) - && (R2_INVENTORY.getObjectScene(23) == 0) && (R2_INVENTORY.getObjectScene(27) == 0)) { + if ( (action == CURSOR_USE) && (R2_INVENTORY.getObjectScene(R2_DIAGNOSTICS_DISPLAY) == 1580) + && (R2_INVENTORY.getObjectScene(R2_FUEL_CELL) == 0) && (R2_INVENTORY.getObjectScene(R2_GUIDANCE_MODULE) == 0) + && (R2_INVENTORY.getObjectScene(R2_RADAR_MECHANISM) == 0) && (R2_INVENTORY.getObjectScene(R2_GYROSCOPE) == 0) + && (R2_INVENTORY.getObjectScene(R2_THRUSTER_VALVE) == 0) && (R2_INVENTORY.getObjectScene(R2_IGNITOR) == 0)) { Scene1580 *scene = (Scene1580 *)R2_GLOBALS._sceneManager._scene; scene->_sceneMode = 31; R2_GLOBALS._player.disableControl(); R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) scene->_stripManager.start(536, scene); else scene->_stripManager.start(537, scene); @@ -9704,10 +9740,10 @@ bool Scene1580::Actor2::startAction(CursorType action, Event &event) { } bool Scene1580::Actor3::startAction(CursorType action, Event &event) { - if ((action == CURSOR_USE) && (R2_INVENTORY.getObjectScene(51) == 1580)) { + if ((action == CURSOR_USE) && (R2_INVENTORY.getObjectScene(R2_BROKEN_DISPLAY) == 1580)) { Scene1580 *scene = (Scene1580 *)R2_GLOBALS._sceneManager._scene; - R2_INVENTORY.setObjectScene(51, R2_GLOBALS._player._characterIndex); + R2_INVENTORY.setObjectScene(R2_BROKEN_DISPLAY, R2_GLOBALS._player._characterIndex); scene->_item2.setDetails(Rect(69, 29, 177, 108), 1550, 82, -1, -1, 2, NULL); scene->_actor1.remove(); remove(); @@ -9750,8 +9786,8 @@ bool Scene1580::Actor6::startAction(CursorType action, Event &event) { switch (action) { case CURSOR_USE: - if (R2_GLOBALS._player._characterIndex == 1) { - R2_INVENTORY.setObjectScene(23, 1); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + R2_INVENTORY.setObjectScene(R2_THRUSTER_VALVE, 1); remove(); return true; } @@ -9782,8 +9818,8 @@ bool Scene1580::Actor7::startAction(CursorType action, Event &event) { switch (action) { case CURSOR_USE: - if (R2_GLOBALS._player._characterIndex == 1) { - R2_INVENTORY.setObjectScene(27, 1); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + R2_INVENTORY.setObjectScene(R2_IGNITOR, 1); remove(); return true; } @@ -9823,7 +9859,7 @@ void Scene1580::postInit(SceneObjectList *OwnerList) { _sceneMode = 0; R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(26) == 1580) { + if (R2_INVENTORY.getObjectScene(R2_JOYSTICK) == 1580) { _actor2.postInit(); _actor2.setup(1580, 1, 4); _actor2.setPosition(Common::Point(159, 163)); @@ -9832,7 +9868,7 @@ void Scene1580::postInit(SceneObjectList *OwnerList) { _item1.setDetails(Rect(141, 148, 179, 167), 1550, 79, -1, -1, 1, NULL); } - if (R2_INVENTORY.getObjectScene(51) == 1580) { + if (R2_INVENTORY.getObjectScene(R2_BROKEN_DISPLAY) == 1580) { _actor3.postInit(); _actor3.setup(1580, 1, 1); _actor3.setPosition(Common::Point(124, 108)); @@ -9843,7 +9879,7 @@ void Scene1580::postInit(SceneObjectList *OwnerList) { _actor1.setup(1580, 1, 3); _actor1.setPosition(Common::Point(124, 96)); _actor1.fixPriority(20); - } else if (R2_INVENTORY.getObjectScene(28) == 1580) { + } else if (R2_INVENTORY.getObjectScene(R2_DIAGNOSTICS_DISPLAY) == 1580) { _actor3.postInit(); _actor3.setup(1580, 1, 1); _actor3.setPosition(Common::Point(124, 108)); @@ -9861,7 +9897,7 @@ void Scene1580::postInit(SceneObjectList *OwnerList) { } _actor4.postInit(); - if (R2_INVENTORY.getObjectScene(58) == 0) { + if (R2_GLOBALS.getFlag(58) == 0) { _actor4.setup(1580, 5, 1); _actor4.setDetails(1550, 80, -1, -1, 1, (SceneItem *) NULL); } else { @@ -9876,8 +9912,8 @@ void Scene1580::postInit(SceneObjectList *OwnerList) { _actor5.setPosition(Common::Point(291, 147)); _actor5.fixPriority(100); _actor5.setDetails(1550, 81, -1, -1, 1, (SceneItem *) NULL); - - if (R2_INVENTORY.getObjectScene(23) == 1580) { + + if (R2_INVENTORY.getObjectScene(R2_THRUSTER_VALVE) == 1580) { _actor6.postInit(); _actor6.setup(1580, 6, 2); _actor6.setPosition(Common::Point(222, 108)); @@ -9885,7 +9921,7 @@ void Scene1580::postInit(SceneObjectList *OwnerList) { _actor6.setDetails(1550, 32, -1, 34, 1, (SceneItem *) NULL); } - if (R2_INVENTORY.getObjectScene(27) == 1580) { + if (R2_INVENTORY.getObjectScene(R2_IGNITOR) == 1580) { _actor7.postInit(); _actor7.setup(1580, 6, 1); _actor7.setPosition(Common::Point(195, 108)); @@ -9894,11 +9930,9 @@ void Scene1580::postInit(SceneObjectList *OwnerList) { } R2_GLOBALS._player.postInit(); - R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 1580; R2_GLOBALS._player.hide(); setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL); _item3.setDetails(Rect(0, 0, 320, 200), 1550, 50, -1, -1, 1, NULL); - } void Scene1580::signal() { @@ -9910,49 +9944,49 @@ void Scene1580::signal() { _actor1.setup(1580, 1, 2); _actor1.setPosition(Common::Point(124, 94)); - if (R2_INVENTORY.getObjectScene(18) != 0) { + if (R2_INVENTORY.getObjectScene(R2_GYROSCOPE) != 0) { _arrActor[0].postInit(); _arrActor[0].setup(1580, 2, 1); _arrActor[0].setPosition(Common::Point(138, 56)); } - if (R2_INVENTORY.getObjectScene(25) != 0) { + if (R2_INVENTORY.getObjectScene(R2_RADAR_MECHANISM) != 0) { _arrActor[1].postInit(); _arrActor[1].setup(1580, 2, 2); _arrActor[1].setPosition(Common::Point(140, 66)); } - if (R2_INVENTORY.getObjectScene(27) != 0) { + if (R2_INVENTORY.getObjectScene(R2_IGNITOR) != 0) { _arrActor[2].postInit(); _arrActor[2].setup(1580, 2, 3); _arrActor[2].setPosition(Common::Point(142, 85)); } - if (R2_INVENTORY.getObjectScene(23) != 0) { + if (R2_INVENTORY.getObjectScene(R2_THRUSTER_VALVE) != 0) { _arrActor[3].postInit(); _arrActor[3].setup(1580, 2, 4); _arrActor[3].setPosition(Common::Point(142, 92)); } - if (R2_INVENTORY.getObjectScene(22) != 0) { + if (R2_INVENTORY.getObjectScene(R2_GUIDANCE_MODULE) != 0) { _arrActor[4].postInit(); _arrActor[4].setup(1580, 2, 5); _arrActor[4].setPosition(Common::Point(108, 54)); } - if (R2_INVENTORY.getObjectScene(26) != 0) { + if (R2_INVENTORY.getObjectScene(R2_JOYSTICK) != 0) { _arrActor[5].postInit(); _arrActor[5].setup(1580, 2, 6); _arrActor[5].setPosition(Common::Point(110, 64)); } - if (R2_INVENTORY.getObjectScene(45) != 0) { + if (R2_INVENTORY.getObjectScene(R2_BATTERY) != 0) { _arrActor[6].postInit(); _arrActor[6].setup(1580, 2, 7); _arrActor[6].setPosition(Common::Point(108, 80)); } - if (R2_INVENTORY.getObjectScene(17) != 0) { + if (R2_INVENTORY.getObjectScene(R2_FUEL_CELL) != 0) { _arrActor[7].postInit(); _arrActor[7].setup(1580, 2, 8); _arrActor[7].setPosition(Common::Point(111, 92)); @@ -10197,7 +10231,7 @@ void Scene1625::signal() { _actor6.postInit(); warning("_actor6._actorName = \"arm\";"); - R2_INVENTORY.setObjectScene(40, 3); + R2_INVENTORY.setObjectScene(R2_SUPERCONDUCTOR_WIRE, 3); _sceneMode = 14; setAction(&_sequenceManager, this, 1625, &_actor1, &_actor6, NULL); @@ -10644,7 +10678,7 @@ void Scene1700::signal() { Common::Point pt(271, 90); PlayerMover *mover = new PlayerMover(); _actor12.addMover(mover, &pt, NULL); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) setAction(&_sequenceManager, this, 1700, &R2_GLOBALS._player, &_actor8, NULL); else setAction(&_sequenceManager, this, 1701, &R2_GLOBALS._player, &_actor8, NULL); @@ -12755,7 +12789,7 @@ void Scene1900::signal() { R2_GLOBALS._sceneManager.changeScene(1925); break; case 1910: - R2_INVENTORY.setObjectScene(22, 2535); + R2_INVENTORY.setObjectScene(R2_GUIDANCE_MODULE, 2535); R2_GLOBALS._player.disableControl(CURSOR_ARROW); R2_GLOBALS._player._oldCharacterScene[1] = 1900; R2_GLOBALS._player._oldCharacterScene[2] = 1900; @@ -13505,7 +13539,6 @@ void Scene1950::Area1::remove() { _areaActor.remove(); SceneArea::remove(); R2_GLOBALS._insetUp--; - // if (!R2_GLOBALS.getFlag(37)) R2_GLOBALS._sound2.play(278); @@ -13525,7 +13558,7 @@ void Scene1950::Area1::remove() { } void Scene1950::Area1::process(Event &event) { -// This is a copy of Scene1200::LaserPanel::process + // This is a copy of Scene1200::LaserPanel::process if (_field20 != R2_GLOBALS._insetUp) return; @@ -13533,19 +13566,16 @@ void Scene1950::Area1::process(Event &event) { if (_areaActor._bounds.contains(event.mousePos.x + g_globals->gfxManager()._bounds.left , event.mousePos.y)) { if (cursor == _cursorNum) { - warning("TODO: _cursorState = ???"); - R2_GLOBALS._events.setCursor(_savedCursorNum); //, _cursorState); + R2_GLOBALS._events.setCursor(_savedCursorNum); } } else if (event.mousePos.y < 168) { if (cursor != _cursorNum) { _savedCursorNum = cursor; - warning("TODO: _cursorState = ???"); R2_GLOBALS._events.setCursor(CURSOR_INVALID); } if (event.eventType == EVENT_BUTTON_DOWN) { event.handled = true; - warning("TODO: _cursorState = ???"); - R2_GLOBALS._events.setCursor(_savedCursorNum); //, _cursorState); + R2_GLOBALS._events.setCursor(_savedCursorNum); remove(); } } @@ -13606,14 +13636,14 @@ bool Scene1950::Actor2::startAction(CursorType action, Event &event) { Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); - R2_INVENTORY.setObjectScene(31, 0); + R2_INVENTORY.setObjectScene(R2_SCRITH_KEY, 0); scene->_sceneMode = 1958; scene->setAction(&scene->_sequenceManager, scene, 1958, &R2_GLOBALS._player, &scene->_actor2, NULL); return true; } bool Scene1950::Actor3::startAction(CursorType action, Event &event) { - if ((action != CURSOR_USE) || (R2_INVENTORY.getObjectScene(35) != 1950)) + if ((action != CURSOR_USE) || (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) != 1950)) return SceneActor::startAction(action, event); Scene1950 *scene = (Scene1950 *)R2_GLOBALS._sceneManager._scene; @@ -13882,7 +13912,7 @@ void Scene1950::Exit6::changeScene() { R2_GLOBALS._player.disableControl(CURSOR_ARROW); R2_GLOBALS._v566A5 = 5; if (R2_GLOBALS._v566A4 == 2) { - if ((R2_GLOBALS.getFlag(36)) && (R2_INVENTORY.getObjectScene(34) == 2) && (R2_INVENTORY.getObjectScene(35) == 2)) { + if ((R2_GLOBALS.getFlag(36)) && (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 2) && (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2)) { scene->_sceneMode = 1961; Common::Point pt(-20, 160); NpcMover *mover = new NpcMover(); @@ -13890,7 +13920,7 @@ void Scene1950::Exit6::changeScene() { } else { if (!R2_GLOBALS.getFlag(36)) SceneItem::display(1950, 33, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); - if ((R2_INVENTORY.getObjectScene(34) == 1950) || (R2_INVENTORY.getObjectScene(35) == 1950)) + if ((R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950) || (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 1950)) SceneItem::display(1950, 34, 0, 280, 1, 160, 9, 1, 2, 20, 7, 7, -999); scene->_sceneMode = 0; Common::Point pt(30, 160); @@ -14201,7 +14231,7 @@ void Scene1950::subBDC1E() { switch (R2_GLOBALS._v566A4 - 1) { case 0: _exit7._enabled = true; - if ((R2_INVENTORY.getObjectScene(31) == 0) && (R2_INVENTORY.getObjectScene(34) == 1950)) + if ((R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0) && (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950)) _exit8._enabled = true; R2_GLOBALS._walkRegions.enableRegion(2); R2_GLOBALS._walkRegions.enableRegion(3); @@ -14719,7 +14749,7 @@ void Scene1950::subBE59B() { _field416 = 1; } } - if ((R2_GLOBALS._v566A4 == 1) && (R2_INVENTORY.getObjectScene(31) != 0)) { + if ((R2_GLOBALS._v566A4 == 1) && (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) != 0)) { _actor2.postInit(); _actor2.setVisage(1948); _actor2.setStrip(3); @@ -14755,7 +14785,7 @@ void Scene1950::subBE59B() { _item2.setDetails(Rect(188, 124, 199, 133), 1950, 27, 28, -1, 2, NULL); - if (R2_INVENTORY.getObjectScene(34) == 1950) { + if (R2_INVENTORY.getObjectScene(R2_SAPPHIRE_BLUE) == 1950) { _actor5.postInit(); _actor5.setVisage(1970); _actor5.setStrip(1); @@ -14786,7 +14816,7 @@ void Scene1950::subBE59B() { _actor3.setPosition(Common::Point(76, 94)); _actor3.fixPriority(25); _actor3.setDetails(1950, 30, -1, -1, 2, (SceneItem *) NULL); - if (R2_INVENTORY.getObjectScene(35) == 2) + if (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2) _actor3.setFrame(2); else _actor3.setFrame(1); @@ -14805,7 +14835,7 @@ void Scene1950::subBE59B() { switch (R2_GLOBALS._v566A5) { case 0: _sceneMode = 1950; - if (R2_INVENTORY.getObjectScene(31) == 0) { + if (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0) { R2_GLOBALS._v56AAB = 0; R2_GLOBALS._player.enableControl(CURSOR_ARROW); } else { @@ -15020,8 +15050,8 @@ void Scene1950::postInit(SceneObjectList *OwnerList) { _exit8.setDest(Common::Point(268, 149)); R2_GLOBALS._player.postInit(); - if ( (R2_INVENTORY.getObjectScene(32) == 0) && (R2_INVENTORY.getObjectScene(33) == 0) - && (R2_INVENTORY.getObjectScene(46) == 0) && (!R2_GLOBALS.getFlag(36)) ) + if ( (R2_INVENTORY.getObjectScene(R2_TANNER_MASK) == 0) && (R2_INVENTORY.getObjectScene(R2_PURE_GRAIN_ALCOHOL) == 0) + && (R2_INVENTORY.getObjectScene(R2_SOAKED_FACEMASK) == 0) && (!R2_GLOBALS.getFlag(36)) ) R2_GLOBALS._player.setVisage(22); else R2_GLOBALS._player.setVisage(20); @@ -15124,7 +15154,7 @@ void Scene1950::signal() { _exit8._enabled = true; break; case 1959: - R2_INVENTORY.setObjectScene(46, 0); + R2_INVENTORY.setObjectScene(R2_SOAKED_FACEMASK, 0); R2_GLOBALS._v56AAB = 0; R2_GLOBALS._player.enableControl(CURSOR_ARROW); _exit8._enabled = true; @@ -15155,7 +15185,7 @@ void Scene1950::signal() { _actor5.setDetails(1950, 9, -1, -1, 2, (SceneItem *) NULL); case 1967: { _sceneMode = 0; - R2_INVENTORY.setObjectScene(34, 2); + R2_INVENTORY.setObjectScene(R2_SAPPHIRE_BLUE, 2); _actor5.remove(); if (R2_GLOBALS.getFlag(36)) R2_GLOBALS._player.setVisage(20); @@ -15170,7 +15200,7 @@ void Scene1950::signal() { break; case 1968: R2_GLOBALS._player.disableControl(); - R2_INVENTORY.setObjectScene(35, 2); + R2_INVENTORY.setObjectScene(R2_ANCIENT_SCROLLS, 2); _actor3.setFrame(2); if (R2_GLOBALS.getFlag(36)) R2_GLOBALS._player.setVisage(20); @@ -15190,7 +15220,7 @@ void Scene1950::process(Event &event) { && (R2_GLOBALS._player._uiEnabled) && (R2_GLOBALS._events.getCursor() == R2_LIGHT_BULB) && (R2_GLOBALS._player._bounds.contains(event.mousePos)) - && (R2_INVENTORY.getObjectScene(31) == 0)) { + && (R2_INVENTORY.getObjectScene(R2_SCRITH_KEY) == 0)) { event.handled = true; R2_GLOBALS._player.disableControl(); _exit7._enabled = false; diff --git a/engines/tsage/ringworld2/ringworld2_scenes1.h b/engines/tsage/ringworld2/ringworld2_scenes1.h index 23ebb2c276..f984a6986a 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.h +++ b/engines/tsage/ringworld2/ringworld2_scenes1.h @@ -75,15 +75,15 @@ public: }; class Scene1100 : public SceneExt { - class Actor16 : public SceneActor { + class Seeker : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor17 : public SceneActor { + class Trooper : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor18 : public SceneActor { + class Chief : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -118,9 +118,9 @@ public: SceneActor _actor15; BackgroundSceneObject _object1; BackgroundSceneObject _object2; - Actor16 _actor16; - Actor17 _actor17; - Actor18 _actor18; + Seeker _seeker; + Trooper _trooper; + Chief _chief; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; SequenceManager _sequenceManager3; @@ -427,26 +427,26 @@ class Scene1550 : public SceneExt { void subA4D14(int frameNumber, int strip); }; - class UnkObj15501 : public SceneActor { + class Junk : public SceneActor { public: int _fieldA4; - int _fieldA6; + int _junkNumber; - UnkObj15501(); + Junk(); void synchronize(Serializer &s); virtual bool startAction(CursorType action, Event &event); }; - class UnkObj15502 : public SceneActor { + class ShipComponent : public SceneActor { public: - int _fieldA4; + int _componentId; - UnkObj15502(); + ShipComponent(); void synchronize(Serializer &s); virtual bool startAction(CursorType action, Event &event); - void subA5CDF(int strip); + void setupShipComponent(int componentId); }; class UnkObj15503 : public SceneActor { @@ -472,7 +472,7 @@ class Scene1550 : public SceneExt { virtual void proc13(int resNum, int lookLineNum, int talkLineNum, int useLineNum); }; - class Hotspot1 : public NamedHotspot { + class WorkingShip : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; @@ -482,12 +482,12 @@ class Scene1550 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; - class Actor6 : public SceneActor { + class Wreckage : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor7 : public SceneActor { + class Companion : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -522,7 +522,7 @@ class Scene1550 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; - class Actor14 : public SceneActor1550 { + class Wall : public SceneActor1550 { // Nothing specific found in the original // TODO: check if it's an useless class }; @@ -530,30 +530,30 @@ class Scene1550 : public SceneExt { public: SpeakerQuinn _quinnSpeaker; SpeakerSeeker _seekerSpeaker; - Hotspot1 _item1; - Hotspot1 _item2; + WorkingShip _shipHull; + WorkingShip _item2; Hotspot3 _item3; - SceneActor _actor1; + SceneActor _landingStrut; SceneActor _actor2; SceneActor _actor3; SceneActor _actor4; SceneActor _actor5; - Actor6 _actor6; - Actor7 _actor7; + Wreckage _wreckage; + Companion _companion; Actor8 _actor8; Actor9 _actor9; Actor10 _actor10; Actor11 _actor11; Actor12 _actor12; Actor13 _actor13; - UnkObj15501 _arrUnkObj15501[8]; - Actor14 _actor14; - Actor14 _actor15; - Actor14 _actor16; - Actor14 _actor17; - Actor14 _actor18; - Actor14 _actor19; - UnkObj15502 _arrUnkObj15502[8]; + Junk _junk[8]; + Wall _actor14; + Wall _northWall; // Is also reused for landing strip + Wall _actor16; + Wall _westWall; // Is also reused for left hand space + Wall _eastWall; + Wall _southWall; + ShipComponent _shipComponents[8]; UnkArea1550 _unkArea1; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; @@ -566,7 +566,7 @@ public: Scene1550(); void synchronize(Serializer &s); - void subA2B2F(); + void enterArea(); virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void signal(); diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.cpp b/engines/tsage/ringworld2/ringworld2_scenes2.cpp index 9246c4b6a4..432f284890 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes2.cpp @@ -769,6 +769,7 @@ Scene2000::Scene2000(): SceneExt() { } _exitingFlag = false; + _mazePlayerMode = 0; } void Scene2000::postInit(SceneObjectList *OwnerList) { @@ -1116,7 +1117,7 @@ void Scene2350::postInit(SceneObjectList *OwnerList) { _actor3.postInit(); _actor4.postInit(); - if (R2_INVENTORY.getObjectScene(20) == 2350) { + if (R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 2350) { _actor3.hide(); _actor4.hide(); } else { @@ -1176,12 +1177,12 @@ void Scene2350::signal() { break; case 21: R2_GLOBALS._player.disableControl(); - R2_INVENTORY.setObjectScene(36, 1); + R2_INVENTORY.setObjectScene(R2_FLUTE, 1); _sceneMode = 2354; setAction(&_sequenceManager, this, 2354, &R2_GLOBALS._player, NULL); break; case 2354: - R2_INVENTORY.setObjectScene(20, 2350); + R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 2350); g_globals->_sceneManager.changeScene(2900); break; case 2355: @@ -1534,7 +1535,7 @@ void Scene2430::postInit(SceneObjectList *OwnerList) { _exit1.setDetails(Rect(68, 155, 147, 168), EXITCURSOR_S, 2000); _exit1.setDest(Common::Point(108, 160)); - if (R2_INVENTORY.getObjectScene(37) == 2430) { + if (R2_INVENTORY.getObjectScene(R2_GUNPOWDER) == 2430) { _actor2.postInit(); _actor2.setup(2435, 1, 5); _actor2.setPosition(Common::Point(205, 119)); @@ -1542,7 +1543,7 @@ void Scene2430::postInit(SceneObjectList *OwnerList) { _actor2.setDetails(2430, 51, -1, 53, 1, (SceneItem *)NULL); } - if (R2_INVENTORY.getObjectScene(50) == 2435) { + if (R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_3) == 2435) { _actor3.postInit(); _actor3.setup(2435, 1, 1); _actor3.setPosition(Common::Point(31, 65)); @@ -1820,7 +1821,7 @@ void Scene2440::postInit(SceneObjectList *OwnerList) { // Fix exit cursor, the original was using NW _exit1.setDetails(Rect(172, 155, 250, 167), EXITCURSOR_SE, 2000); _exit1.setDest(Common::Point(210, 160)); - if (R2_INVENTORY.getObjectScene(49) == 2440) { + if (R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_2) == 2440) { _actor2.postInit(); _actor2.setup(2435, 1, 1); _actor2.setPosition(Common::Point(94, 80)); @@ -1885,7 +1886,7 @@ void Scene2440::signal() { break; case 2440: _actor2.remove(); - R2_INVENTORY.setObjectScene(49, 2); + R2_INVENTORY.setObjectScene(R2_ALCOHOL_LAMP_2, 2); // No break on purpose default: R2_GLOBALS._player.enableControl(); @@ -2212,7 +2213,7 @@ bool Scene2455::Actor1::startAction(CursorType action, Event &event) { Scene2455 *scene = (Scene2455 *)R2_GLOBALS._sceneManager._scene; if (action == R2_GLASS_DOME) { - if ((R2_INVENTORY.getObjectScene(49) == 2455) || (R2_INVENTORY.getObjectScene(50) == 2455)) { + if ((R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_2) == 2455) || (R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_3) == 2455)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 2458; scene->_actor2._lookLineNum = 9; @@ -2232,7 +2233,7 @@ bool Scene2455::Actor2::startAction(CursorType action, Event &event) { switch (action) { case R2_ALCOHOL_LAMP_2: - if (R2_INVENTORY.getObjectScene(50) != 2455) { + if (R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_3) != 2455) { R2_GLOBALS._player.disableControl(); scene->_actor1.postInit(); scene->_actor1.setup(2456, 3, 3); @@ -2244,7 +2245,7 @@ bool Scene2455::Actor2::startAction(CursorType action, Event &event) { } break; case R2_ALCOHOL_LAMP_3: - if (R2_INVENTORY.getObjectScene(49) != 2455) { + if (R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_2) != 2455) { R2_GLOBALS._player.disableControl(); scene->_actor1.postInit(); scene->_actor1.setup(2456, 3, 3); @@ -2290,15 +2291,15 @@ void Scene2455::postInit(SceneObjectList *OwnerList) { SceneExt::postInit(); if (R2_GLOBALS._sceneManager._previousScene == -1) { - R2_INVENTORY.setObjectScene(29, 2); - R2_INVENTORY.setObjectScene(50, 2); + R2_INVENTORY.setObjectScene(R2_GLASS_DOME, 2); + R2_INVENTORY.setObjectScene(R2_ALCOHOL_LAMP_3, 2); } R2_GLOBALS._sound1.play(200); _exit1.setDetails(Rect(0, 0, 320, 15), EXITCURSOR_N, 2425); - if (R2_INVENTORY.getObjectScene(29) == 2455) { - if ((R2_INVENTORY.getObjectScene(50) == 2455) || (R2_INVENTORY.getObjectScene(49) == 2455)) { + if (R2_INVENTORY.getObjectScene(R2_GLASS_DOME) == 2455) { + if ((R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_3) == 2455) || (R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_2) == 2455)) { _actor1.postInit(); _actor1.setup(2456, 3, 3); _actor1.setPosition(Common::Point(162, 165)); @@ -2312,11 +2313,11 @@ void Scene2455::postInit(SceneObjectList *OwnerList) { } _actor2.postInit(); - if (R2_INVENTORY.getObjectScene(29) == 2455) { + if (R2_INVENTORY.getObjectScene(R2_GLASS_DOME) == 2455) { _actor2.setup(2456, 3, 2); _actor2.setDetails(2455, 9, 1, -1, 1, (SceneItem *)NULL); } else { - if ((R2_INVENTORY.getObjectScene(50) != 2455) && (R2_INVENTORY.getObjectScene(49) != 2455)) + if ((R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_3) != 2455) && (R2_INVENTORY.getObjectScene(R2_ALCOHOL_LAMP_2) != 2455)) _actor2.setup(2455, 1, 1); else _actor2.setup(2456, 1, 1); @@ -2324,7 +2325,7 @@ void Scene2455::postInit(SceneObjectList *OwnerList) { } _actor2.setPosition(Common::Point(162, 165)); _actor2.fixPriority(20); - if (R2_INVENTORY.getObjectScene(29) != 2455) + if (R2_INVENTORY.getObjectScene(R2_GLASS_DOME) != 2455) _actor2.animate(ANIM_MODE_2, NULL); R2_GLOBALS._player.postInit(); @@ -2356,23 +2357,23 @@ void Scene2455::signal() { g_globals->_sceneManager.changeScene(2425); break; case 11: - R2_INVENTORY.setObjectScene(49, 2455); + R2_INVENTORY.setObjectScene(R2_ALCOHOL_LAMP_2, 2455); R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; break; case 12: - R2_INVENTORY.setObjectScene(50, 2455); + R2_INVENTORY.setObjectScene(R2_ALCOHOL_LAMP_3, 2455); R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; break; case 2458: - R2_INVENTORY.setObjectScene(29, 2455); + R2_INVENTORY.setObjectScene(R2_GLASS_DOME, 2455); R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; break; case 2459: _actor3.remove(); - R2_INVENTORY.setObjectScene(31, 2); + R2_INVENTORY.setObjectScene(R2_SCRITH_KEY, 2); R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; break; @@ -2542,7 +2543,7 @@ void Scene2525::postInit(SceneObjectList *OwnerList) { _exit1.setDetails(Rect(86, 155, 228, 168), EXITCURSOR_S, 2000); - if (R2_INVENTORY.getObjectScene(29) == 2525) { + if (R2_INVENTORY.getObjectScene(R2_GLASS_DOME) == 2525) { _actor3.postInit(); _actor3.setup(2435, 1, 2); _actor3.setPosition(Common::Point(78, 155)); @@ -2615,7 +2616,7 @@ void Scene2525::signal() { break; case 2525: _actor3.remove(); - R2_INVENTORY.setObjectScene(29, 2); + R2_INVENTORY.setObjectScene(R2_GLASS_DOME, 2); R2_GLOBALS._player.enableControl(); break; case 2526: @@ -2698,7 +2699,7 @@ void Scene2530::postInit(SceneObjectList *OwnerList) { _exit1.setDetails(Rect(68, 155, 147, 168), EXITCURSOR_S, 2000); _exit1.setDest(Common::Point(108, 160)); - if (R2_INVENTORY.getObjectScene(33) == 2530) { + if (R2_INVENTORY.getObjectScene(R2_PURE_GRAIN_ALCOHOL) == 2530) { _actor2.postInit(); _actor2.setup(2435, 1, 3); _actor2.setPosition(Common::Point(299, 80)); @@ -2766,7 +2767,7 @@ void Scene2530::signal() { g_globals->_sceneManager.changeScene(2000); break; case 2530: - R2_INVENTORY.setObjectScene(33, 2); + R2_INVENTORY.setObjectScene(R2_PURE_GRAIN_ALCOHOL, 2); _actor2.remove(); break; case 2531: @@ -2798,7 +2799,7 @@ bool Scene2535::Actor3::startAction(CursorType action, Event &event) { if (R2_GLOBALS._player._characterIndex == 1) { R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(20) == 2535) { + if (R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 2535) { scene->_sceneMode = 2536; scene->setAction(&scene->_sequenceManager, scene, 2536, &R2_GLOBALS._player, &scene->_actor3, NULL); } else { @@ -2846,12 +2847,12 @@ void Scene2535::postInit(SceneObjectList *OwnerList) { SceneExt::postInit(); if (R2_GLOBALS._sceneManager._previousScene == -1) { R2_GLOBALS.setFlag(73); - R2_INVENTORY.setObjectScene(20, 2535); + R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 2535); } _exit1.setDetails(Rect(172, 155, 250, 167), EXITCURSOR_S, 2000); _exit1.setDest(Common::Point(210, 160)); - if (R2_INVENTORY.getObjectScene(32) == 2535) { + if (R2_INVENTORY.getObjectScene(R2_TANNER_MASK) == 2535) { _actor4.postInit(); _actor4.setup(2435, 1, 4); _actor4.setPosition(Common::Point(47, 74)); @@ -2859,7 +2860,7 @@ void Scene2535::postInit(SceneObjectList *OwnerList) { _actor4.setDetails(2535, 21, -1, -1, 1, (SceneItem *)NULL); } - if (R2_INVENTORY.getObjectScene(20) == 2535) { + if (R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 2535) { _actor3.postInit(); _actor3.setup(2535, 3, 1); _actor3.setPosition(Common::Point(203, 131)); @@ -2867,7 +2868,7 @@ void Scene2535::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._walkRegions.enableRegion(6); } - if ((R2_INVENTORY.getObjectScene(20) == 0) && (R2_GLOBALS.getFlag(73))) { + if ((R2_INVENTORY.getObjectScene(R2_REBREATHER_TANK) == 0) && (R2_GLOBALS.getFlag(73))) { _actor3.postInit(); _actor3.setup(2536, 1, 2); _actor3.setPosition(Common::Point(164, 133)); @@ -2933,12 +2934,12 @@ void Scene2535::signal() { g_globals->_sceneManager.changeScene(2000); break; case 2535: - R2_INVENTORY.setObjectScene(32, 2); + R2_INVENTORY.setObjectScene(R2_TANNER_MASK, 2); _actor4.remove(); R2_GLOBALS._player.enableControl(); break; case 2536: - R2_INVENTORY.setObjectScene(20, 0); + R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 0); R2_GLOBALS._walkRegions.disableRegion(6); if (!R2_GLOBALS.getFlag(73)) { _actor3.remove(); @@ -2958,7 +2959,7 @@ void Scene2535::signal() { break; case 2537: _actor3.remove(); - R2_INVENTORY.setObjectScene(20, 1); + R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 1); R2_GLOBALS._player.enableControl(); break; case 20: @@ -3211,7 +3212,7 @@ void Scene2700::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(2, 2); R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(36) == 0) + if (R2_INVENTORY.getObjectScene(R2_FLUTE) == 0) R2_GLOBALS._sound1.changeSound(234); if (R2_GLOBALS._sceneManager._previousScene == 2750) { @@ -3452,7 +3453,7 @@ void Scene2700::signal() { } break; case 11: - R2_INVENTORY.setObjectScene(36, 0); + R2_INVENTORY.setObjectScene(R2_FLUTE, 0); R2_GLOBALS._player.disableControl(); _field412 = 0; _sceneMode = 2700; @@ -3854,7 +3855,7 @@ void Scene2750::postInit(SceneObjectList *OwnerList) { _rect2.set(130, 142, 210, 167); _rect3.set(-1, 137, 290, 147); - if (R2_INVENTORY.getObjectScene(36) == 0) { + if (R2_INVENTORY.getObjectScene(R2_FLUTE) == 0) { R2_GLOBALS._sound1.changeSound(235); _actor2.postInit(); _actor2.setup(2751, 1, 1); @@ -3929,7 +3930,7 @@ void Scene2750::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_quinnSpeaker); _stripManager.addSpeaker(&_nejSpeaker); - if (R2_INVENTORY.getObjectScene(36) == 0) { + if (R2_INVENTORY.getObjectScene(R2_FLUTE) == 0) { _actor1.postInit(); _actor1.setup(2752, 5, 1); _actor1.animate(ANIM_MODE_NONE, NULL); @@ -3943,7 +3944,7 @@ void Scene2750::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._sceneManager._previousScene == 2700) { - if (R2_INVENTORY.getObjectScene(36) == 0) { + if (R2_INVENTORY.getObjectScene(R2_FLUTE) == 0) { R2_GLOBALS._player.setVisage(2752); R2_GLOBALS._player.setStrip(6); R2_GLOBALS._player.animate(ANIM_MODE_NONE, NULL); @@ -4448,7 +4449,7 @@ void Scene2800::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_nejSpeaker); _stripManager.addSpeaker(&_guardSpeaker); - if (R2_INVENTORY.getObjectScene(36) == 0) { + if (R2_INVENTORY.getObjectScene(R2_FLUTE) == 0) { R2_GLOBALS._sound1.fadeSound(237); if (R2_GLOBALS.getFlag(47)) { _item2.setDetails(Rect(76, 45, 155, 90), 2800, 3, -1, -1, 2, NULL); @@ -4469,7 +4470,7 @@ void Scene2800::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(2, 2); R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(36) == 0) { + if (R2_INVENTORY.getObjectScene(R2_FLUTE) == 0) { R2_GLOBALS._player.setAction(&_sequenceManager, this, 2800, &R2_GLOBALS._player, NULL); } else if (R2_GLOBALS.getFlag(47)) { R2_GLOBALS._player.setVisage(3110); diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 6af2a0cad4..b2958a3d5e 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -378,7 +378,7 @@ bool Scene3150::Item5::startAction(CursorType action, Event &event) { switch (action) { case CURSOR_USE: - if (R2_INVENTORY.getObjectScene(47) != 3150) + if (R2_INVENTORY.getObjectScene(R2_LIGHT_BULB) != 3150) return SceneHotspot::startAction(action, event); R2_GLOBALS._player.disableControl(); @@ -386,7 +386,7 @@ bool Scene3150::Item5::startAction(CursorType action, Event &event) { scene->setAction(&scene->_sequenceManager, scene, 3154, &R2_GLOBALS._player, &scene->_actor3, NULL); return true; case R2_SUPERCONDUCTOR_WIRE: - if ((R2_INVENTORY.getObjectScene(47) != 3150) && (R2_GLOBALS.getFlag(75))) { + if ((R2_INVENTORY.getObjectScene(R2_LIGHT_BULB) != 3150) && (R2_GLOBALS.getFlag(75))) { R2_GLOBALS._player.disableControl(); scene->_actor3.postInit(); scene->_actor3._effect = 3; @@ -417,7 +417,7 @@ bool Scene3150::Item6::startAction(CursorType action, Event &event) { scene->setAction(&scene->_sequenceManager, scene, 3158, &R2_GLOBALS._player, &scene->_actor4, NULL); return true; case R2_FOOD_TRAY: - if ((R2_INVENTORY.getObjectScene(47) != 3150) && (R2_INVENTORY.getObjectScene(40) == 3150) && (R2_GLOBALS.getFlag(75))) { + if ((R2_INVENTORY.getObjectScene(R2_LIGHT_BULB) != 3150) && (R2_INVENTORY.getObjectScene(R2_SUPERCONDUCTOR_WIRE) == 3150) && (R2_GLOBALS.getFlag(75))) { scene->_actor5.postInit(); scene->_actor5._effect = 6; scene->_actor5._shade = 3; @@ -535,7 +535,7 @@ void Scene3150::Exit2::changeScene() { void Scene3150::postInit(SceneObjectList *OwnerList) { loadScene(3150); if (R2_GLOBALS._sceneManager._previousScene == -1) { - R2_INVENTORY.setObjectScene(35, 2000); + R2_INVENTORY.setObjectScene(R2_ANCIENT_SCROLLS, 2000); R2_GLOBALS._player._oldCharacterScene[1] = 3100; R2_GLOBALS._player._oldCharacterScene[3] = 0; R2_GLOBALS._player._characterIndex = R2_MIRANDA; @@ -583,7 +583,7 @@ void Scene3150::postInit(SceneObjectList *OwnerList) { _actor7.fixPriority(50); _actor7.setDetails(3150, 17, -1, 19, 1, (SceneItem *)NULL); - if (R2_INVENTORY.getObjectScene(41) == 3150) { + if (R2_INVENTORY.getObjectScene(R2_PILLOW) == 3150) { _actor4.postInit(); if (R2_GLOBALS.getFlag(75)) { if (R2_GLOBALS.getFlag(76)) { @@ -608,13 +608,13 @@ void Scene3150::postInit(SceneObjectList *OwnerList) { } } - if (R2_INVENTORY.getObjectScene(47) == 3150) { + if (R2_INVENTORY.getObjectScene(R2_LIGHT_BULB) == 3150) { _actor3.postInit(); _actor3.setup(3152, 7, 1); _actor3.setPosition(Common::Point(73, 83)); } - if (R2_INVENTORY.getObjectScene(40) == 3150) { + if (R2_INVENTORY.getObjectScene(R2_SUPERCONDUCTOR_WIRE) == 3150) { _actor3.postInit(); _actor3.setup(3152, 7, 3); _actor3.setPosition(Common::Point(70, 55)); @@ -623,7 +623,7 @@ void Scene3150::postInit(SceneObjectList *OwnerList) { _actor3._shade = 5; } - if (R2_INVENTORY.getObjectScene(42) == 3150) { + if (R2_INVENTORY.getObjectScene(R2_FOOD_TRAY) == 3150) { _actor5.postInit(); if (R2_GLOBALS.getFlag(77)) { _actor5.setup(3152, 7, 8); @@ -675,7 +675,7 @@ void Scene3150::postInit(SceneObjectList *OwnerList) { break; } default: - if ((R2_GLOBALS._v56AA0 == 1) && (R2_INVENTORY.getObjectScene(35) == 2000) && (R2_GLOBALS._player._oldCharacterScene[1] == 3100)) { + if ((R2_GLOBALS._v56AA0 == 1) && (R2_INVENTORY.getObjectScene(R2_ANCIENT_SCROLLS) == 2000) && (R2_GLOBALS._player._oldCharacterScene[1] == 3100)) { ++R2_GLOBALS._v56AA0; _sceneMode = 3156; _actor1.postInit(); @@ -713,7 +713,7 @@ void Scene3150::signal() { break; case 3151: _actor1.remove(); - R2_INVENTORY.setObjectScene(41, 3); + R2_INVENTORY.setObjectScene(R2_PILLOW, 3); R2_GLOBALS._player.enableControl(); break; case 3153: @@ -726,37 +726,37 @@ void Scene3150::signal() { break; case 3154: _actor3.remove(); - R2_INVENTORY.setObjectScene(47, 3); + R2_INVENTORY.setObjectScene(R2_LIGHT_BULB, 3); R2_GLOBALS._player.enableControl(); break; case 3155: - R2_INVENTORY.setObjectScene(40, 3150); + R2_INVENTORY.setObjectScene(R2_SUPERCONDUCTOR_WIRE, 3150); R2_GLOBALS._player.enableControl(); break; case 3156: _actor5.setDetails(3150, 30, -1, -1, 2, (SceneItem *)NULL); - R2_INVENTORY.setObjectScene(42, 3150); + R2_INVENTORY.setObjectScene(R2_FOOD_TRAY, 3150); R2_GLOBALS._player.enableControl(); break; case 3157: _actor5.remove(); - R2_INVENTORY.setObjectScene(42, 3); + R2_INVENTORY.setObjectScene(R2_FOOD_TRAY, 3); R2_GLOBALS._player.enableControl(); break; case 3158: R2_GLOBALS.setFlag(75); - R2_INVENTORY.setObjectScene(41, 3150); + R2_INVENTORY.setObjectScene(R2_PILLOW, 3150); _actor4.fixPriority(110); _actor4.setDetails(3150, 13, -1, -1, 2, (SceneItem *)NULL); R2_GLOBALS._player.enableControl(); break; case 3159: R2_GLOBALS.setFlag(77); - R2_INVENTORY.setObjectScene(42, 3150); + R2_INVENTORY.setObjectScene(R2_FOOD_TRAY, 3150); R2_GLOBALS._player.enableControl(); break; case 3160: - R2_INVENTORY.setObjectScene(52, 3150); + R2_INVENTORY.setObjectScene(R2_TOOLBOX, 3150); R2_GLOBALS.setFlag(80); R2_GLOBALS._sceneManager.changeScene(1200); break; @@ -1407,7 +1407,7 @@ void Scene3260::postInit(SceneObjectList *OwnerList) { _actor13.setPosition(Common::Point(40, 106)); _actor13.setDetails(3260, 18, 1, -1, 1, (SceneItem *)NULL); - if (R2_INVENTORY.getObjectScene(52) == 3260) { + if (R2_INVENTORY.getObjectScene(R2_TOOLBOX) == 3260) { _actor14.postInit(); _actor14.setup(3260, 7, 1); _actor14.setPosition(Common::Point(202, 66)); @@ -1524,8 +1524,8 @@ void Scene3260::signal() { R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); SceneItem::display(3260, 15, 0, 280, 1, 160, 9, 1, 2, 20, 7, 154, -999); R2_GLOBALS._player.disableControl(); - R2_INVENTORY.setObjectScene(52, 3); - R2_INVENTORY.setObjectScene(43, 3); + R2_INVENTORY.setObjectScene(R2_TOOLBOX, 3); + R2_INVENTORY.setObjectScene(R2_LASER_HACKSAW, 3); setAction(&_sequenceManager, this, 3273, &R2_GLOBALS._player, &_actor14, NULL); break; case 3273: @@ -2771,7 +2771,7 @@ void Scene3400::signal() { _actor2.setStrip(6); _actor3.setStrip(3); _actor4.setStrip(1); - R2_INVENTORY.setObjectScene(34, 0); + R2_INVENTORY.setObjectScene(R2_SAPPHIRE_BLUE, 0); _stripManager.start(3307, this); if (R2_GLOBALS._player._characterIndex == 2) { _sceneMode = 3400; diff --git a/engines/tsage/ringworld2/ringworld2_speakers.cpp b/engines/tsage/ringworld2/ringworld2_speakers.cpp index cd2ff669ff..e7109829b0 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.cpp +++ b/engines/tsage/ringworld2/ringworld2_speakers.cpp @@ -204,13 +204,12 @@ void VisualSpeaker::setText(const Common::String &msg) { _sceneText._textMode = _textMode; _sceneText.setup(s); - //_sceneText.clone(); - _sceneText.setPosition(_textPos); _sceneText.fixPriority(256); // If subtitles are turned off, don't show the text - if (!(R2_GLOBALS._speechSubtitles & SPEECH_TEXT)) { + if ((R2_GLOBALS._speechSubtitles & SPEECH_VOICE) && + !(R2_GLOBALS._speechSubtitles & SPEECH_TEXT)) { _sceneText.hide(); } @@ -360,7 +359,7 @@ void SpeakerChief1100::proc15() { Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { - _object2 = &scene->_actor18; + _object2 = &scene->_chief; _object2->hide(); _object1.postInit(); _object1.setPosition(_object2->_position); @@ -1180,6 +1179,7 @@ void SpeakerQuinn300::proc15() { if (R2_GLOBALS._player._characterIndex == 3) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 300); Scene300 *scene = (Scene300 *)R2_GLOBALS._sceneManager._scene; _object2 = &scene->_quinn; } @@ -1220,6 +1220,51 @@ void SpeakerQuinn300::proc15() { } } +void SpeakerQuinn500::proc15() { + int v = _speakerMode; + + if (!_object2) { + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + _object2 = &R2_GLOBALS._player; + } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 500); + Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene; + _object2 = &scene->_seeker; + } + + _object2->hide(); + + _object1.postInit(); + _object1._effect = _object2->_effect; + _object1._shade = _object2->_shade; + _object1.setPosition(_object2->_position); + + if (_object2->_mover) + _object2->addMover(NULL); + } + + if (v == 0) { + _object1.animate(ANIM_MODE_2, NULL); + } else { + ((SceneItem *)_action)->_sceneRegionId = 0; + + switch (_object2->_visage) { + case 10: + _object1.setup(4021, (v == 1) ? 5 : 7, 1); + break; + + case 1500: + _object1.setup(4021, (v == 1) ? 1 : 3, 1); + break; + + default: + break; + } + + _object1.animate(ANIM_MODE_5, this); + } +} + void SpeakerQuinn1100::proc15() { int v = _speakerMode; @@ -1230,8 +1275,9 @@ void SpeakerQuinn1100::proc15() { if (R2_GLOBALS._player._characterIndex == 1) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 1100); Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor16; + _object2 = &scene->_seeker; } _object2->hide(); @@ -1275,6 +1321,7 @@ void SpeakerQuinn2435::proc15() { if (R2_GLOBALS._player._characterIndex == 1) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 2435); Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; _object2 = &scene->_actor1; } @@ -1301,6 +1348,7 @@ void SpeakerQuinn2450::proc15() { if (R2_GLOBALS._player._characterIndex == 1) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 2435); Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; _object2 = &scene->_actor1; } @@ -1948,9 +1996,9 @@ void SpeakerSeeker300::proc15() { int v = _speakerMode; if (!_object2) { - if (R2_GLOBALS._player._characterIndex == 2) { + if (R2_GLOBALS._player._characterIndex == R2_SEEKER) { _object2 = &R2_GLOBALS._player; - } else { + } else {assert(R2_GLOBALS._sceneManager._sceneNumber == 300); Scene300 *scene = (Scene300 *)R2_GLOBALS._sceneManager._scene; _object2 = &scene->_seeker; } @@ -1980,6 +2028,43 @@ void SpeakerSeeker300::proc15() { } } +void SpeakerSeeker500::proc15() { + int v = _speakerMode; + + if (!_object2) { + if (R2_GLOBALS._player._characterIndex == R2_SEEKER) { + _object2 = &R2_GLOBALS._player; + } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 500); + Scene500 *scene = (Scene500 *)R2_GLOBALS._sceneManager._scene; + _object2 = &scene->_seeker; + } + + _object2->hide(); + _object1.postInit(); + + _object1._effect = _object2->_effect; + _object1._shade = _object2->_shade; + _object1.setPosition(_object2->_position); + + if (_object2->_mover) + _object2->addMover(NULL); + } + + if (v == 0) { + _object1.animate(ANIM_MODE_2, NULL); + } else { + ((SceneItem *)_action)->_sceneRegionId = 0; + + if (v == 1) + _object1.setup(4041, 3, 1); + else + _object1.setup(4041, 1, 1); + + _object1.animate(ANIM_MODE_5, this); + } +} + void SpeakerSeeker1100::proc15() { int v = _speakerMode; @@ -1990,8 +2075,9 @@ void SpeakerSeeker1100::proc15() { if (R2_GLOBALS._player._characterIndex == 2) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 1100); Scene1100 *scene = (Scene1100 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor16; + _object2 = &scene->_seeker; } _object2->hide(); @@ -2046,6 +2132,7 @@ void SpeakerSeeker1900::proc15() { if (R2_GLOBALS._player._characterIndex == 2) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 1900); Scene1900 *scene = (Scene1900 *)R2_GLOBALS._sceneManager._scene; _object2 = &scene->_actor1; } @@ -2076,6 +2163,7 @@ void SpeakerSeeker2435::proc15() { if (R2_GLOBALS._player._characterIndex == 2) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 2435); Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; _object2 = &scene->_actor1; } @@ -2102,6 +2190,7 @@ void SpeakerSeeker2450::proc15() { if (R2_GLOBALS._player._characterIndex == 2) { _object2 = &R2_GLOBALS._player; } else { + assert(R2_GLOBALS._sceneManager._sceneNumber == 2450); Scene2450 *scene = (Scene2450 *)R2_GLOBALS._sceneManager._scene; _object2 = &scene->_actor1; } @@ -2492,9 +2581,9 @@ void SpeakerSocko3200::proc15() { // Classes related to SOLDIER //---------------------------------------------------------------------------- -SpeakerSoldier::SpeakerSoldier(int colour) { +SpeakerSoldier::SpeakerSoldier(int color) { _speakerName = "SOLDIER"; - _color1 = colour; + _color1 = color; _color2 = 0; _speakerMode = 0; _textWidth = 300; @@ -2788,9 +2877,9 @@ void SpeakerTomko3245::proc15() { // Classes related to WEBBSTER //---------------------------------------------------------------------------- -SpeakerWebbster::SpeakerWebbster(int colour) { +SpeakerWebbster::SpeakerWebbster(int color) { _speakerName = "WEBBSTER"; - _color1 = colour; + _color1 = color; _color2 = 0; _speakerMode = 0; _textWidth = 300; diff --git a/engines/tsage/ringworld2/ringworld2_speakers.h b/engines/tsage/ringworld2/ringworld2_speakers.h index 532e02576c..4dfb500f2d 100644 --- a/engines/tsage/ringworld2/ringworld2_speakers.h +++ b/engines/tsage/ringworld2/ringworld2_speakers.h @@ -282,6 +282,12 @@ public: virtual void proc15(); }; +class SpeakerQuinn500 : public SpeakerQuinn { +public: + virtual Common::String getClassName() { return "SpeakerQuinn500"; } + virtual void proc15(); +}; + class SpeakerQuinn1100 : public SpeakerQuinn { public: virtual Common::String getClassName() { return "SpeakerQuinn1100"; } @@ -420,6 +426,12 @@ public: virtual void proc15(); }; +class SpeakerSeeker500 : public SpeakerSeeker { +public: + virtual Common::String getClassName() { return "SpeakerSeeker500"; } + virtual void proc15(); +}; + class SpeakerSeeker1100 : public SpeakerSeeker { public: virtual Common::String getClassName() { return "SpeakerSeeker1100"; } @@ -504,7 +516,7 @@ public: class SpeakerSoldier : public VisualSpeaker { public: - SpeakerSoldier(int colour); + SpeakerSoldier(int color); virtual Common::String getClassName() { return "SpeakerSoldier"; } }; @@ -579,7 +591,7 @@ public: class SpeakerWebbster : public VisualSpeaker { public: - SpeakerWebbster(int colour); + SpeakerWebbster(int color); virtual Common::String getClassName() { return "SpeakerWebbster"; } }; diff --git a/engines/tsage/staticres.cpp b/engines/tsage/staticres.cpp index a273ec2a0b..db38862365 100644 --- a/engines/tsage/staticres.cpp +++ b/engines/tsage/staticres.cpp @@ -244,7 +244,7 @@ char const *const USE_INTERCEPTOR = "Do you want to use your interceptor card?"; char const *const USE_DOUBLE_AGENT = "Do you want to use your double agent?"; char const *const NEED_INSTRUCTIONS = "Do you want instructions?"; char const *const WRONG_ANSWER_MSG = "Wrong respond value sent."; -const byte k562CC[] = { +const byte scene1550JunkLocationsDefault[] = { 20, 7, 41, 6, 3, 6, 42, 11, 10, 15, 43, 6, @@ -374,7 +374,7 @@ const byte k562CC[] = { 28, 18, 21, 1 }; -const byte k5A4D6[] = { +const byte scene1550AreaMap[] = { 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 18, 17, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, @@ -409,7 +409,7 @@ const byte k5A76D[] = { 3, 3, 3, 7, 3, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3 }; -const byte k5A78A[] = {0, 8, 15, 16, 12, 7, 18, 17, 13, 6, 19, 20, 14, 5, 11, 10, 9}; +const byte scene1550JunkRegions[] = {0, 8, 15, 16, 12, 7, 18, 17, 13, 6, 19, 20, 14, 5, 11, 10, 9}; const byte k5A79B[] = { 23, 3, 1, 23, 4, 1, diff --git a/engines/tsage/staticres.h b/engines/tsage/staticres.h index e3daf73333..8c21147191 100644 --- a/engines/tsage/staticres.h +++ b/engines/tsage/staticres.h @@ -199,13 +199,13 @@ extern char const *const NEED_INSTRUCTIONS; extern char const *const WRONG_ANSWER_MSG; // Scene 1550 arrays of constants -extern const byte k562CC[]; -extern const byte k5A4D6[]; +extern const byte scene1550JunkLocationsDefault[]; +extern const byte scene1550AreaMap[]; extern const byte k5A72E[]; extern const byte k5A73F[]; extern const byte k5A750[]; extern const byte k5A76D[]; -extern const byte k5A78A[]; +extern const byte scene1550JunkRegions[]; extern const byte k5A79B[]; extern const byte k5A7F6[]; diff --git a/engines/tsage/user_interface.cpp b/engines/tsage/user_interface.cpp index c0ebb804d2..09cc2fd56d 100644 --- a/engines/tsage/user_interface.cpp +++ b/engines/tsage/user_interface.cpp @@ -454,7 +454,7 @@ void UIElements::add(UIElement *obj) { /** * Handles updating the visual inventory in the user interface */ -void UIElements::updateInventory() { +void UIElements::updateInventory(int objectNumber) { switch (g_vm->getGameID()) { case GType_BlueForce: // Update the score @@ -483,6 +483,17 @@ void UIElements::updateInventory() { else if (_slotStart > (lastPage - 1)) _slotStart = 0; + // Handle changing the page, if necessary, to ensure an optionally supplied + // object number will be on-screen + if (objectNumber != 0) { + for (uint idx = 0; idx < _itemList.size(); ++idx) { + if (_itemList[idx] == objectNumber) { + _slotStart = idx / 4; + break; + } + } + } + // Handle refreshing slot graphics UIInventorySlot *slotList[4] = { &_slot1, &_slot2, &_slot3, &_slot4 }; diff --git a/engines/tsage/user_interface.h b/engines/tsage/user_interface.h index 0fbfc5a00f..d06dccd9a4 100644 --- a/engines/tsage/user_interface.h +++ b/engines/tsage/user_interface.h @@ -137,7 +137,7 @@ public: virtual void process(Event &event); void setup(const Common::Point &pt); - void updateInventory(); + void updateInventory(int objectNumber = 0); void addScore(int amount); void scrollInventory(bool isLeft); diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index 3059a69047..e073f27970 100644 --- a/engines/wintermute/base/font/base_font_truetype.cpp +++ b/engines/wintermute/base/font/base_font_truetype.cpp @@ -272,7 +272,7 @@ BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width, // void drawString(Surface *dst, const Common::String &str, int x, int y, int w, uint32 color, TextAlign align = kTextAlignLeft, int deltax = 0, bool useEllipsis = true) const; Graphics::Surface *surface = new Graphics::Surface(); if (_deletableFont) { // We actually have a TTF - surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)); + surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), _gameRef->_renderer->getPixelFormat()); } else { // We are using a fallback, they can't do 32bpp surface->create((uint16)width, (uint16)(_lineHeight * lines.size()), Graphics::PixelFormat(2, 5, 5, 5, 1, 11, 6, 1, 0)); } @@ -285,7 +285,7 @@ BaseSurface *BaseFontTT::renderTextToTexture(const WideString &text, int width, } BaseSurface *retSurface = _gameRef->_renderer->createSurface(); - Graphics::Surface *convertedSurface = surface->convertTo(Graphics::PixelFormat(4, 8, 8, 8, 8, 16, 8, 0, 24)); + Graphics::Surface *convertedSurface = surface->convertTo(_gameRef->_renderer->getPixelFormat()); retSurface->putSurface(*convertedSurface, true); convertedSurface->free(); surface->free(); diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index b16cf60752..e6d769c653 100644 --- a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp @@ -84,7 +84,6 @@ BaseRenderOSystem::~BaseRenderOSystem() { delete _renderSurface; _blankSurface->free(); delete _blankSurface; - TransparentSurface::destroyLookup(); } ////////////////////////////////////////////////////////////////////////// @@ -127,7 +126,7 @@ bool BaseRenderOSystem::initRenderer(int width, int height, bool windowed) { _windowed = !ConfMan.getBool("fullscreen"); - Graphics::PixelFormat format(4, 8, 8, 8, 8, 16, 8, 0, 24); + Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0); g_system->beginGFXTransaction(); g_system->initSize(_width, _height, &format); OSystem::TransactionError gfxError = g_system->endGFXTransaction(); @@ -613,8 +612,8 @@ bool BaseRenderOSystem::setViewport(int left, int top, int right, int bottom) { // TODO: Hopefully this is the same logic that ScummVM uses. rect.left = (int16)(left + _borderLeft); rect.top = (int16)(top + _borderTop); - rect.right = (int16)((right - left) * _ratioX); - rect.bottom = (int16)((bottom - top) * _ratioY); + rect.setWidth((int16)((right - left) * _ratioX)); + rect.setHeight((int16)((bottom - top) * _ratioY)); _renderRect = rect; return STATUS_OK; @@ -631,15 +630,13 @@ Rect32 BaseRenderOSystem::getViewPort() { ////////////////////////////////////////////////////////////////////////// void BaseRenderOSystem::modTargetRect(Common::Rect *rect) { - // FIXME: This is wrong in quite a few ways right now, and ends up - // breaking the notebook in Dirty Split, so we disable the correction - // for now, this will need fixing when a game with odd aspect-ratios - // show up. return; - rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft - _renderRect.left); - rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop - _renderRect.top); - rect->setWidth((int16)MathUtil::roundUp(rect->width() * _ratioX)); - rect->setHeight((int16)MathUtil::roundUp(rect->height() * _ratioY)); + int newWidth = (int16)MathUtil::roundUp(rect->width() * _ratioX); + int newHeight = (int16)MathUtil::roundUp(rect->height() * _ratioY); + rect->left = (int16)MathUtil::round(rect->left * _ratioX + _borderLeft); + rect->top = (int16)MathUtil::round(rect->top * _ratioY + _borderTop); + rect->setWidth(newWidth); + rect->setHeight(newHeight); } ////////////////////////////////////////////////////////////////////////// diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp index d4c5905c4b..14767aa067 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.cpp @@ -48,7 +48,7 @@ namespace Wintermute { BaseSurfaceOSystem::BaseSurfaceOSystem(BaseGame *inGame) : BaseSurface(inGame) { _surface = new Graphics::Surface(); _alphaMask = nullptr; - _hasAlpha = true; + _alphaType = TransparentSurface::ALPHA_FULL; _lockPixels = nullptr; _lockPitch = 0; _loaded = false; @@ -71,22 +71,37 @@ BaseSurfaceOSystem::~BaseSurfaceOSystem() { renderer->invalidateTicketsFromSurface(this); } -bool hasTransparency(Graphics::Surface *surf) { +TransparentSurface::AlphaType hasTransparencyType(const Graphics::Surface *surf) { if (surf->format.bytesPerPixel != 4) { - warning("hasTransparency:: non 32 bpp surface passed as argument"); - return false; + warning("hasTransparencyType:: non 32 bpp surface passed as argument"); + return TransparentSurface::ALPHA_OPAQUE; } uint8 r, g, b, a; + bool seenAlpha = false; + bool seenFullAlpha = false; for (int i = 0; i < surf->h; i++) { + if (seenFullAlpha) { + break; + } for (int j = 0; j < surf->w; j++) { - uint32 pix = *(uint32 *)surf->getBasePtr(j, i); + uint32 pix = *(const uint32 *)surf->getBasePtr(j, i); surf->format.colorToARGB(pix, a, r, g, b); if (a != 255) { - return true; + seenAlpha = true; + if (a != 0) { + seenFullAlpha = true; + break; + } } } } - return false; + if (seenFullAlpha) { + return TransparentSurface::ALPHA_FULL; + } else if (seenAlpha) { + return TransparentSurface::ALPHA_BINARY; + } else { + return TransparentSurface::ALPHA_OPAQUE; + } } ////////////////////////////////////////////////////////////////////////// @@ -128,39 +143,36 @@ bool BaseSurfaceOSystem::finishLoad() { _width = image->getSurface()->w; _height = image->getSurface()->h; - bool isSaveGameGrayscale = scumm_strnicmp(_filename.c_str(), "savegame:", 9) == 0 && (_filename.c_str()[_filename.size() - 1] == 'g' || _filename.c_str()[_filename.size() - 1] == 'G'); + bool isSaveGameGrayscale = _filename.matchString("savegame:*g", true); if (isSaveGameGrayscale) { warning("grayscaleConversion not yet implemented"); // FIBITMAP *newImg = FreeImage_ConvertToGreyscale(img); TODO } - // no alpha, set color key - /* if (surface->format.bytesPerPixel != 4) - SDL_SetColorKey(surf, SDL_TRUE, SDL_MapRGB(surf->format, ck_red, ck_green, ck_blue));*/ - - // convert 32-bit BMPs to 24-bit or they appear totally transparent (does any app actually write alpha in BMP properly?) - // Well, actually, we don't convert via 24-bit as the color-key application overwrites the Alpha-channel anyhow. _surface->free(); delete _surface; bool needsColorKey = false; bool replaceAlpha = true; - if (_filename.hasSuffix(".bmp") && image->getSurface()->format.bytesPerPixel == 4) { - _surface = image->getSurface()->convertTo(g_system->getScreenFormat(), image->getPalette()); - needsColorKey = true; - replaceAlpha = false; - } else if (image->getSurface()->format.bytesPerPixel == 1 && image->getPalette()) { + if (image->getSurface()->format.bytesPerPixel == 1) { + if (!image->getPalette()) { + error("Missing palette while loading 8bit image %s", _filename.c_str()); + } _surface = image->getSurface()->convertTo(g_system->getScreenFormat(), image->getPalette()); needsColorKey = true; - } else if (image->getSurface()->format.bytesPerPixel >= 3 && image->getSurface()->format != g_system->getScreenFormat()) { - _surface = image->getSurface()->convertTo(g_system->getScreenFormat()); - if (image->getSurface()->format.bytesPerPixel == 3) { - needsColorKey = true; - } } else { - _surface = new Graphics::Surface(); - _surface->copyFrom(*image->getSurface()); - if (_surface->format.aBits() == 0) { + if (image->getSurface()->format != g_system->getScreenFormat()) { + _surface = image->getSurface()->convertTo(g_system->getScreenFormat()); + } else { + _surface = new Graphics::Surface(); + _surface->copyFrom(*image->getSurface()); + } + + if (_filename.hasSuffix(".bmp") && image->getSurface()->format.bytesPerPixel == 4) { + // 32 bpp BMPs have nothing useful in their alpha-channel -> color-key + needsColorKey = true; + replaceAlpha = false; + } else if (image->getSurface()->format.aBits() == 0) { needsColorKey = true; } } @@ -170,7 +182,7 @@ bool BaseSurfaceOSystem::finishLoad() { trans.applyColorKey(_ckRed, _ckGreen, _ckBlue, replaceAlpha); } - _hasAlpha = hasTransparency(_surface); + _alphaType = hasTransparencyType(_surface); _valid = true; _gameRef->addMem(_width * _height * 4); @@ -409,8 +421,6 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, if (newRect) { position.top = y; position.left = x; - position.right = x + newRect->width(); - position.bottom = y + newRect->height(); position.setWidth(newRect->width()); position.setHeight(newRect->height()); } else { @@ -422,17 +432,11 @@ bool BaseSurfaceOSystem::drawSprite(int x, int y, Rect32 *rect, Rect32 *newRect, // TODO: This actually requires us to have the SAME source-offsets every time, // But no checking is in place for that yet. - // TODO: Optimize by not doing alpha-blits if we lack or disable alpha - - bool hasAlpha = false; - - if (_hasAlpha && !transform._alphaDisable) { - hasAlpha = true; - } - - if (transform._alphaDisable) { - warning("BaseSurfaceOSystem::drawSprite - AlphaDisable ignored"); + // Optimize by not doing alpha-blits if we lack alpha + if (_alphaType == TransparentSurface::ALPHA_OPAQUE && !transform._alphaDisable) { + transform._alphaDisable = true; } + renderer->drawSurface(this, _surface, &srcRect, &position, transform); return STATUS_OK; } @@ -447,7 +451,11 @@ bool BaseSurfaceOSystem::putSurface(const Graphics::Surface &surface, bool hasAl _loaded = true; _surface->free(); _surface->copyFrom(surface); - _hasAlpha = hasAlpha; + if (hasAlpha) { + _alphaType = TransparentSurface::ALPHA_FULL; + } else { + _alphaType = TransparentSurface::ALPHA_OPAQUE; + } BaseRenderOSystem *renderer = static_cast<BaseRenderOSystem *>(_gameRef->_renderer); renderer->invalidateTicketsFromSurface(this); diff --git a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h index da86833517..6cf19d00fb 100644 --- a/engines/wintermute/base/gfx/osystem/base_surface_osystem.h +++ b/engines/wintermute/base/gfx/osystem/base_surface_osystem.h @@ -30,6 +30,7 @@ #define WINTERMUTE_BASE_SURFACESDL_H #include "graphics/surface.h" +#include "engines/wintermute/graphics/transparent_surface.h" #include "engines/wintermute/base/gfx/base_surface.h" #include "common/list.h" @@ -81,6 +82,7 @@ public: return _height; } + TransparentSurface::AlphaType getAlphaType() const { return _alphaType; } private: Graphics::Surface *_surface; bool _loaded; @@ -90,7 +92,7 @@ private: uint32 getPixelAt(Graphics::Surface *surface, int x, int y); uint32 _rotation; - bool _hasAlpha; + TransparentSurface::AlphaType _alphaType; void *_lockPixels; int _lockPitch; byte *_alphaMask; diff --git a/engines/wintermute/base/gfx/osystem/render_ticket.cpp b/engines/wintermute/base/gfx/osystem/render_ticket.cpp index 98739e0778..b1720c1b0b 100644 --- a/engines/wintermute/base/gfx/osystem/render_ticket.cpp +++ b/engines/wintermute/base/gfx/osystem/render_ticket.cpp @@ -28,6 +28,7 @@ #include "engines/wintermute/base/gfx/osystem/render_ticket.h" +#include "engines/wintermute/base/gfx/osystem/base_surface_osystem.h" #include "engines/wintermute/graphics/transform_tools.h" #include "common/textconsole.h" @@ -104,7 +105,13 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface) const { clipRect.setWidth(getSurface()->w); clipRect.setHeight(getSurface()->h); - src._enableAlphaBlit = !_transform._alphaDisable; + if (_owner) { + if (_transform._alphaDisable) { + src._alphaMode = TransparentSurface::ALPHA_OPAQUE; + } else { + src._alphaMode = _owner->getAlphaType(); + } + } src.blit(*_targetSurface, _dstRect.left, _dstRect.top, _transform._flip, &clipRect, _transform._rgbaMod, clipRect.width(), clipRect.height()); } @@ -118,7 +125,13 @@ void RenderTicket::drawToSurface(Graphics::Surface *_targetSurface, Common::Rect clipRect->setHeight(getSurface()->h); } - src._enableAlphaBlit = !_transform._alphaDisable; + if (_owner) { + if (_transform._alphaDisable) { + src._alphaMode = TransparentSurface::ALPHA_OPAQUE; + } else { + src._alphaMode = _owner->getAlphaType(); + } + } src.blit(*_targetSurface, dstRect->left, dstRect->top, _transform._flip, clipRect, _transform._rgbaMod, clipRect->width(), clipRect->height()); if (doDelete) { delete clipRect; diff --git a/engines/wintermute/detection_tables.h b/engines/wintermute/detection_tables.h index 702c0b28ba..63f5078c12 100644 --- a/engines/wintermute/detection_tables.h +++ b/engines/wintermute/detection_tables.h @@ -40,16 +40,20 @@ static const PlainGameDescriptor wintermuteGames[] = { {"dreaming", "Des Reves Elastiques Avec Mille Insectes Nommes Georges"}, {"dirtysplit", "Dirty Split"}, {"dreamscape", "Dreamscape"}, + {"escapemansion", "Escape from the Mansion"}, {"ghostsheet", "Ghost in the Sheet"}, {"hamlet", "Hamlet or the last game without MMORPS features, shaders and product placement"}, {"jamesperis", "James Peris: No License Nor Control"}, + {"looky", "Looky"}, {"julia", "J.U.L.I.A."}, {"mirage", "Mirage"}, {"pigeons", "Pigeons in the Park"}, {"reversion1", "Reversion: The Escape"}, {"reversion2", "Reversion: The Meeting"}, {"rosemary", "Rosemary"}, + {"shaban", "Shaban"}, {"shinestar", "The Shine of a Star"}, + {"spacemadness", "Space Madness"}, {"thebox", "The Box"}, {"tib", "Fairy Tales About Toshechka and Boshechka"}, {"tradestory", "The Trader of Stories"}, @@ -284,6 +288,26 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Escape from the Mansion + { + "escapemansion", + "Beta 1", + AD_ENTRY1s("data.dcp", "d8e348b2312cc36a929cad75f12e0b3a", 21452380), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, + // Escape from the Mansion + { + "escapemansion", + "Beta 2", + AD_ENTRY1s("data.dcp", "ded5fa6c5f2afdaf2cafb53e52cd3dd8", 21455763), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Ghosts in the Sheet { "ghostsheet", @@ -379,6 +403,48 @@ static const ADGameDescription gameDescriptions[] = { ADGF_DEMO, GUIO0() }, + // Looky Demo (English) + { + "looky", + "Demo", + { + {"english.dcp", 0, "1388e1dd320f4d553dea3b0316812f9d", 1358442}, + {"data.dcp", 0, "7074bcd7bc7ad7eb04c271aafb964c32", 13815660}, + AD_LISTEND + }, + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, + // Looky Demo (German) + { + "looky", + "Demo", + { + {"german.dcp", 0, "606c048426dfbe94442b59fd34a5c76e", 14339496}, + {"data.dcp", 0, "7074bcd7bc7ad7eb04c271aafb964c32", 13815660}, + AD_LISTEND + }, + Common::DE_DEU, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, + // Looky (German) + { + "looky", + "", + { + {"german.dcp", 0, "bf4c2b8c26342342441a6d64934ab832", 107027865}, + {"data.dcp", 0, "50de0beaa5ad621aa9f020df901d1e74", 1342214}, + AD_LISTEND + }, + Common::DE_DEU, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // Mirage { "mirage", @@ -625,6 +691,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Shaban + { + "shaban", + "", + AD_ENTRY1s("data.dcp", "35f702ca9baabc5c620e0be230195c8a", 755388466), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // The Shine of a Star { "shinestar", @@ -635,6 +711,16 @@ static const ADGameDescription gameDescriptions[] = { ADGF_UNSTABLE, GUIO0() }, + // Space Madness + { + "spacemadness", + "1.0.2", + AD_ENTRY1s("data.dcp", "b9b83135dc7a9e1b4b5f50195dbeb630", 39546622), + Common::EN_ANY, + Common::kPlatformWindows, + ADGF_UNSTABLE, + GUIO0() + }, // The Box { "thebox", diff --git a/engines/wintermute/graphics/transparent_surface.cpp b/engines/wintermute/graphics/transparent_surface.cpp index df6286e37a..cd200354f7 100644 --- a/engines/wintermute/graphics/transparent_surface.cpp +++ b/engines/wintermute/graphics/transparent_surface.cpp @@ -140,16 +140,9 @@ void TransparentSurface::copyPixelNearestNeighbor(float projX, float projY, int } #endif -byte *TransparentSurface::_lookup = nullptr; +TransparentSurface::TransparentSurface() : Surface(), _alphaMode(ALPHA_FULL) {} -void TransparentSurface::destroyLookup() { - delete[] _lookup; - _lookup = nullptr; -} - -TransparentSurface::TransparentSurface() : Surface(), _enableAlphaBlit(true) {} - -TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface(), _enableAlphaBlit(true) { +TransparentSurface::TransparentSurface(const Surface &surf, bool copyData) : Surface(), _alphaMode(ALPHA_FULL) { if (copyData) { copyFrom(surf); } else { @@ -168,9 +161,9 @@ void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pit byte *in, *out; #ifdef SCUMM_LITTLE_ENDIAN - const int aIndex = 3; -#else const int aIndex = 0; +#else + const int aIndex = 3; #endif for (uint32 i = 0; i < height; i++) { @@ -186,42 +179,60 @@ void doBlitOpaque(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pit } } -void TransparentSurface::generateLookup() { - _lookup = new byte[256 * 256]; - for (int i = 0; i < 256; i++) { - for (int j = 0; j < 256; j++) { - _lookup[(i << 8) + j] = (i * j) >> 8; +void doBlitBinary(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { + byte *in, *out; + +#ifdef SCUMM_LITTLE_ENDIAN + const int aIndex = 0; +#else + const int aIndex = 3; +#endif + const int aShift = 0;//img->format.aShift; + + for (uint32 i = 0; i < height; i++) { + out = outo; + in = ino; + for (uint32 j = 0; j < width; j++) { + uint32 pix = *(uint32 *)in; + int a = (pix >> aShift) & 0xff; + in += inStep; + + if (a == 0) { // Full transparency + out += 4; + } else { // Full opacity (Any value not exactly 0 is Opaque here) + *(uint32 *)out = pix; + out[aIndex] = 0xFF; + out += 4; + } } + outo += pitch; + ino += inoStep; } } -void TransparentSurface::doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { +void doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep) { byte *in, *out; - if (!_lookup) { - generateLookup(); - } - #ifdef SCUMM_LITTLE_ENDIAN - const int aIndex = 3; - const int bIndex = 0; - const int gIndex = 1; - const int rIndex = 2; -#else const int aIndex = 0; - const int bIndex = 3; + const int bIndex = 1; const int gIndex = 2; - const int rIndex = 1; + const int rIndex = 3; +#else + const int aIndex = 3; + const int bIndex = 2; + const int gIndex = 1; + const int rIndex = 0; #endif - const int bShift = 0;//img->format.bShift; - const int gShift = 8;//img->format.gShift; - const int rShift = 16;//img->format.rShift; - const int aShift = 24;//img->format.aShift; + const int bShift = 8;//img->format.bShift; + const int gShift = 16;//img->format.gShift; + const int rShift = 24;//img->format.rShift; + const int aShift = 0;//img->format.aShift; - const int bShiftTarget = 0;//target.format.bShift; - const int gShiftTarget = 8;//target.format.gShift; - const int rShiftTarget = 16;//target.format.rShift; + const int bShiftTarget = 8;//target.format.bShift; + const int gShiftTarget = 16;//target.format.gShift; + const int rShiftTarget = 24;//target.format.rShift; for (uint32 i = 0; i < height; i++) { out = outo; @@ -255,13 +266,9 @@ void TransparentSurface::doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 default: // alpha blending outa = 255; - - outb = _lookup[(((oPix >> bShiftTarget) & 0xff)) + ((255 - a) << 8)]; - outg = _lookup[(((oPix >> gShiftTarget) & 0xff)) + ((255 - a) << 8)]; - outr = _lookup[(((oPix >> rShiftTarget) & 0xff)) + ((255 - a) << 8)]; - outb += _lookup[b + (a << 8)]; - outg += _lookup[g + (a << 8)]; - outr += _lookup[r + (a << 8)]; + outb = ((b * a) + ((oPix >> bShiftTarget) & 0xff) * (255-a)) >> 8; + outg = ((g * a) + ((oPix >> gShiftTarget) & 0xff) * (255-a)) >> 8; + outr = ((r * a) + ((oPix >> rShiftTarget) & 0xff) * (255-a)) >> 8; out[aIndex] = outa; out[bIndex] = outb; @@ -292,14 +299,6 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p int cg = (color >> 8) & 0xff; int cb = (color >> 0) & 0xff; - // Compensate for transparency. Since we're coming - // down to 255 alpha, we just compensate for the colors here - if (ca != 255) { - cr = cr * ca >> 8; - cg = cg * ca >> 8; - cb = cb * ca >> 8; - } - // Create an encapsulating surface for the data TransparentSurface srcImage(*this, false); // TODO: Is the data really in the screen format? @@ -309,7 +308,19 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p } if (pPartRect) { - srcImage.pixels = getBasePtr(pPartRect->left, pPartRect->top); + + int xOffset = pPartRect->left; + int yOffset = pPartRect->top; + + if (flipping & FLIP_V) { + yOffset = srcImage.h - pPartRect->bottom; + } + + if (flipping & FLIP_H) { + xOffset = srcImage.w - pPartRect->right; + } + + srcImage.pixels = getBasePtr(xOffset, yOffset); srcImage.w = pPartRect->width(); srcImage.h = pPartRect->height(); @@ -379,29 +390,32 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p byte *in, *out; #ifdef SCUMM_LITTLE_ENDIAN - const int aIndex = 3; - const int bIndex = 0; - const int gIndex = 1; - const int rIndex = 2; -#else const int aIndex = 0; - const int bIndex = 3; + const int bIndex = 1; const int gIndex = 2; - const int rIndex = 1; + const int rIndex = 3; +#else + const int aIndex = 3; + const int bIndex = 2; + const int gIndex = 1; + const int rIndex = 0; #endif - const int bShift = 0;//img->format.bShift; - const int gShift = 8;//img->format.gShift; - const int rShift = 16;//img->format.rShift; - const int aShift = 24;//img->format.aShift; - const int bShiftTarget = 0;//target.format.bShift; - const int gShiftTarget = 8;//target.format.gShift; - const int rShiftTarget = 16;//target.format.rShift; + const int bShift = 8;//img->format.bShift; + const int gShift = 16;//img->format.gShift; + const int rShift = 24;//img->format.rShift; + const int aShift = 0;//img->format.aShift; + + const int bShiftTarget = 8;//target.format.bShift; + const int gShiftTarget = 16;//target.format.gShift; + const int rShiftTarget = 24;//target.format.rShift; if (ca == 255 && cb == 255 && cg == 255 && cr == 255) { - if (_enableAlphaBlit) { + if (_alphaMode == ALPHA_FULL) { doBlitAlpha(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); - } else { + } else if (_alphaMode == ALPHA_BINARY) { + doBlitBinary(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); + } else if (_alphaMode == ALPHA_OPAQUE) { doBlitOpaque(ino, outo, img->w, img->h, target.pitch, inStep, inoStep); } } else { @@ -421,7 +435,6 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p if (ca != 255) { a = a * ca >> 8; } - switch (a) { case 0: // Full transparency out += 4; @@ -451,27 +464,27 @@ Common::Rect TransparentSurface::blit(Graphics::Surface &target, int posX, int p default: // alpha blending outa = 255; - outb = (o_pix >> bShiftTarget) & 0xff; - outg = (o_pix >> gShiftTarget) & 0xff; - outr = (o_pix >> rShiftTarget) & 0xff; + outb = ((o_pix >> bShiftTarget) & 0xff) * (255 - a); + outg = ((o_pix >> gShiftTarget) & 0xff) * (255 - a); + outr = ((o_pix >> rShiftTarget) & 0xff) * (255 - a); if (cb == 0) - outb = 0; + outb = outb >> 8; else if (cb != 255) - outb += ((b - outb) * a * cb) >> 16; + outb = ((outb<<8) + b * a * cb) >> 16; else - outb += ((b - outb) * a) >> 8; + outb = (outb + b * a) >> 8; if (cg == 0) - outg = 0; + outg = outg >> 8; else if (cg != 255) - outg += ((g - outg) * a * cg) >> 16; + outg = ((outg<<8) + g * a * cg) >> 16; else - outg += ((g - outg) * a) >> 8; + outg = (outg + g * a) >> 8; if (cr == 0) - outr = 0; + outr = outr >> 8; else if (cr != 255) - outr += ((r - outr) * a * cr) >> 16; + outr = ((outr<<8) + r * a * cr) >> 16; else - outr += ((r - outr) * a) >> 8; + outr = (outr + r * a) >> 8; out[aIndex] = outa; out[bIndex] = outb; out[gIndex] = outg; diff --git a/engines/wintermute/graphics/transparent_surface.h b/engines/wintermute/graphics/transparent_surface.h index 9d06f3e006..598aaa55d7 100644 --- a/engines/wintermute/graphics/transparent_surface.h +++ b/engines/wintermute/graphics/transparent_surface.h @@ -75,7 +75,13 @@ struct TransparentSurface : public Graphics::Surface { FLIP_VH = FLIP_H | FLIP_V }; - bool _enableAlphaBlit; + enum AlphaType { + ALPHA_OPAQUE = 0, + ALPHA_BINARY = 1, + ALPHA_FULL = 2 + }; + + AlphaType _alphaMode; /** @brief renders the surface to another surface @@ -114,11 +120,6 @@ struct TransparentSurface : public Graphics::Surface { TransparentSurface *scale(uint16 newWidth, uint16 newHeight) const; TransparentSurface *rotoscale(const TransformStruct &transform) const; - static byte *_lookup; - static void destroyLookup(); -private: - static void doBlitAlpha(byte *ino, byte *outo, uint32 width, uint32 height, uint32 pitch, int32 inStep, int32 inoStep); - static void generateLookup(); }; /** diff --git a/engines/wintermute/utils/string_util.cpp b/engines/wintermute/utils/string_util.cpp index 23abb5d579..e8e078aba8 100644 --- a/engines/wintermute/utils/string_util.cpp +++ b/engines/wintermute/utils/string_util.cpp @@ -146,26 +146,21 @@ Utf8String StringUtil::wideToUtf8(const WideString &WideStr) { return ""; } -// Currently this only does Ansi->ISO 8859, and only for carets. -char simpleAnsiToWide(const AnsiString &str, uint32 &offset) { - byte c = str[offset]; - - if (c == 146) { - offset++; - return 39; // Replace right-quote with apostrophe - } else { - offset++; - return c; - } -} - ////////////////////////////////////////////////////////////////////////// WideString StringUtil::ansiToWide(const AnsiString &str) { // TODO: This function gets called a lot, so warnings like these drown out the usefull information Common::String converted = ""; uint32 index = 0; while (index != str.size()) { - converted += simpleAnsiToWide(str, index); + byte c = str[index]; + if (c == 146) { + converted += (char)39; // Replace right-quote with apostrophe + } else if (c == 133) { + converted += Common::String("..."); // Replace ...-symbol with ... + } else { + converted += c; + } + index++; } // using default os locale! diff --git a/engines/wintermute/wintermute.cpp b/engines/wintermute/wintermute.cpp index a878944661..0a6be4caf8 100644 --- a/engines/wintermute/wintermute.cpp +++ b/engines/wintermute/wintermute.cpp @@ -105,7 +105,7 @@ bool WintermuteEngine::hasFeature(EngineFeature f) const { Common::Error WintermuteEngine::run() { // Initialize graphics using following: - Graphics::PixelFormat format(4, 8, 8, 8, 8, 16, 8, 0, 24); + Graphics::PixelFormat format(4, 8, 8, 8, 8, 24, 16, 8, 0); initGraphics(800, 600, true, &format); if (g_system->getScreenFormat() != format) { error("Wintermute currently REQUIRES 32bpp"); diff --git a/graphics/VectorRenderer.h b/graphics/VectorRenderer.h index 5d6369c08f..8e1c5e91e1 100644 --- a/graphics/VectorRenderer.h +++ b/graphics/VectorRenderer.h @@ -73,6 +73,8 @@ struct DrawStep { uint8 shadow, stroke, factor, radius, bevel; /**< Misc options... */ uint8 fillMode; /**< active fill mode */ + uint8 shadowFillMode; /**< fill mode of the shadow used */ + uint32 extraData; /**< Generic parameter for extra options (orientation/bevel) */ uint32 scale; /**< scale of all the coordinates in FIXED POINT with 16 bits mantissa */ @@ -103,7 +105,7 @@ VectorRenderer *createRenderer(int mode); */ class VectorRenderer { public: - VectorRenderer() : _activeSurface(NULL), _fillMode(kFillDisabled), _shadowOffset(0), + VectorRenderer() : _activeSurface(NULL), _fillMode(kFillDisabled), _shadowOffset(0), _shadowFillMode(kShadowExponential), _disableShadows(false), _strokeWidth(1), _gradientFactor(1) { } @@ -126,6 +128,11 @@ public: kTriangleRight }; + enum ShadowFillMode { + kShadowLinear = 0, + kShadowExponential = 1 + }; + /** * Draws a line by considering the special cases for optimization. * @@ -292,6 +299,10 @@ public: _fillMode = mode; } + virtual void setShadowFillMode(ShadowFillMode mode) { + _shadowFillMode = mode; + } + /** * Sets the stroke width. All shapes drawn with a stroke will * have that width. Pass 0 to disable shape stroking. @@ -466,7 +477,7 @@ public: */ virtual void drawString(const Graphics::Font *font, const Common::String &text, const Common::Rect &area, Graphics::TextAlign alignH, - GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool useEllipsis) = 0; + GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool useEllipsis, const Common::Rect &textDrawableArea) = 0; /** * Allows to temporarily enable/disable all shadows drawing. @@ -485,6 +496,7 @@ protected: Surface *_activeSurface; /**< Pointer to the surface currently being drawn */ FillMode _fillMode; /**< Defines in which way (if any) are filled the drawn shapes */ + ShadowFillMode _shadowFillMode; int _shadowOffset; /**< offset for drawn shadows */ int _bevel; /**< amount of fake bevel */ diff --git a/graphics/VectorRendererSpec.cpp b/graphics/VectorRendererSpec.cpp index e4843ba78b..491a9d7f42 100644 --- a/graphics/VectorRendererSpec.cpp +++ b/graphics/VectorRendererSpec.cpp @@ -119,6 +119,38 @@ inline frac_t fp_sqroot(uint32 x) { *(ptr4 + (y) + (px)) = color2; \ } while (0) +#define BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (y) - (px), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (x) - (py), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (x) - (py), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (y) - (px), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (y) + (px), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (x) + (py), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (x) + (py), color, a); \ +} while (0) + +#define BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (y) + (px), color, a); \ +} while (0) + #define BE_DRAWCIRCLE_XCOLOR_TOP(ptr1,ptr2,x,y,px,py) do { \ *(ptr1 + (y) - (px)) = color1; \ *(ptr1 + (x) - (py)) = color2; \ @@ -222,6 +254,37 @@ inline frac_t fp_sqroot(uint32 x) { this->blendPixelPtr(ptr4 + (y) + (px), color2, a); \ } while (0) +#define WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (y) - (px), color, a); \ +} while (0) + +#define WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (x) - (py), color, a); \ +} while (0) + +#define WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (x) - (py), color, a); \ +} while (0) + +#define WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (y) - (px), color, a); \ +} while (0) + +#define WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (y) + (px), color, a); \ +} while (0) + +#define WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr - (x) + (py), color, a); \ +} while (0) + +#define WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (x) + (py), color, a); \ +} while (0) + +#define WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr,x,y,px,py,a) do { \ + this->blendPixelPtr(ptr + (y) + (px), color, a); \ +} while (0) // optimized Wu's algorithm #define WU_ALGORITHM() do { \ @@ -287,12 +350,14 @@ VectorRenderer *createRenderer(int mode) { return new VectorRendererSpec<uint32>(format); else if (g_system->getOverlayFormat().bytesPerPixel == 2) return new VectorRendererSpec<uint16>(format); + break; #ifndef DISABLE_FANCY_THEMES case GUI::ThemeEngine::kGfxAntialias: if (g_system->getOverlayFormat().bytesPerPixel == 4) return new VectorRendererAA<uint32>(format); else if (g_system->getOverlayFormat().bytesPerPixel == 2) return new VectorRendererAA<uint16>(format); + break; #endif default: break; @@ -646,24 +711,45 @@ darkenFill(PixelType *ptr, PixelType *end) { template<typename PixelType> void VectorRendererSpec<PixelType>:: drawString(const Graphics::Font *font, const Common::String &text, const Common::Rect &area, - Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool ellipsis) { + Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool ellipsis, const Common::Rect &textDrawableArea) { int offset = area.top; if (font->getFontHeight() < area.height()) { switch (alignV) { - case GUI::ThemeEngine::kTextAlignVCenter: - offset = area.top + ((area.height() - font->getFontHeight()) >> 1); - break; - case GUI::ThemeEngine::kTextAlignVBottom: - offset = area.bottom - font->getFontHeight(); - break; - default: - break; + case GUI::ThemeEngine::kTextAlignVCenter: + offset = area.top + ((area.height() - font->getFontHeight()) >> 1); + break; + case GUI::ThemeEngine::kTextAlignVBottom: + offset = area.bottom - font->getFontHeight(); + break; + default: + break; } } - font->drawString(_activeSurface, text, area.left, offset, area.width() - deltax, _fgColor, alignH, deltax, ellipsis); + Common::Rect drawArea; + if (textDrawableArea.isEmpty()) { + // In case no special area to draw to is given we only draw in the + // area specified by the user. + drawArea = area; + // warning("there is no text drawable area. Please set this area for clipping"); + } else { + // The area we can draw to is the intersection between the allowed + // drawing area (textDrawableArea) and the area where we try to draw + // the text (area). + drawArea = textDrawableArea.findIntersectingRect(area); + } + + // Better safe than sorry. We intersect with the actual surface boundaries + // to avoid any ugly clipping in _activeSurface->getSubArea which messes + // up the calculation of the x and y coordinates where to draw the string. + drawArea = drawArea.findIntersectingRect(Common::Rect(0, 0, _activeSurface->w, _activeSurface->h)); + + if (!drawArea.isEmpty()) { + Surface textAreaSurface = _activeSurface->getSubArea(drawArea); + font->drawString(&textAreaSurface, text, area.left - drawArea.left, offset - drawArea.top, area.width() - deltax, _fgColor, alignH, deltax, ellipsis); + } } /** LINES **/ @@ -817,7 +903,8 @@ drawRoundedSquare(int x, int y, int r, int w, int h) { if (Base::_fillMode != kFillDisabled && Base::_shadowOffset && x + w + Base::_shadowOffset + 1 < Base::_activeSurface->w - && y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h) { + && y + h + Base::_shadowOffset + 1 < Base::_activeSurface->h + && h > (Base::_shadowOffset + 1) * 2) { drawRoundedSquareShadow(x, y, r, w, h, Base::_shadowOffset); } @@ -848,13 +935,14 @@ drawTab(int x, int y, int r, int w, int h) { // FIXME: This is broken for the AA renderer. // See the rounded rect alg for how to fix it. (The border should // be drawn before the interior, both inside drawTabAlg.) - drawTabAlg(x, y, w, h, r, (Base::_fillMode == kFillBackground) ? _bgColor : _fgColor, Base::_fillMode); + drawTabShadow(x, y, w - 2, h, r); + drawTabAlg(x, y, w - 2, h, r, _bgColor, Base::_fillMode); if (Base::_strokeWidth) drawTabAlg(x, y, w, h, r, _fgColor, kFillDisabled, (Base::_dynamicData >> 16), (Base::_dynamicData & 0xFFFF)); break; case kFillForeground: - drawTabAlg(x, y, w, h, r, (Base::_fillMode == kFillBackground) ? _bgColor : _fgColor, Base::_fillMode); + drawTabAlg(x, y, w, h, r, _fgColor, Base::_fillMode); break; } } @@ -1035,6 +1123,67 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer: } +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawTabShadow(int x1, int y1, int w, int h, int r) { + int offset = 3; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + + // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme) + uint8 expFactor = 3; + uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; + + int xstart = x1; + int ystart = y1; + int width = w; + int height = h + offset + 1; + + for (int i = offset; i >= 0; i--) { + int f, ddF_x, ddF_y; + int x, y, px, py; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart); + + int short_h = height - (2 * r) + 2; + PixelType color = _format.RGBToColor(0, 0, 0); + + BE_RESET(); + + // HACK: As we are drawing circles exploting 8-axis symmetry, + // there are 4 pixels on each circle which are drawn twice. + // this is ok on filled circles, but when blending on surfaces, + // we cannot let it blend twice. awful. + uint32 hb = 0; + + while (x++ < y) { + BE_ALGORITHM(); + + if (((1 << x) & hb) == 0) { + blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha); + hb |= (1 << x); + } + + if (((1 << y) & hb) == 0) { + blendFill(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha); + hb |= (1 << y); + } + } + + ptr_fill += pitch * r; + while (short_h--) { + blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha); + ptr_fill += pitch; + } + + // Move shadow one pixel upward each iteration + xstart += 1; + // Multiply with expfactor + alpha = (alpha * (expFactor << 8)) >> 9; + } +} + /** BEVELED TABS FOR CLASSIC THEME **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: @@ -1468,118 +1617,160 @@ drawTriangleFast(int x1, int y1, int size, bool inverted, PixelType color, Vecto /** ROUNDED SQUARE ALGORITHM **/ template<typename PixelType> void VectorRendererSpec<PixelType>:: -drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { +drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) { int f, ddF_x, ddF_y; int x, y, px, py; int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; + int sw = 0, sp = 0, hp = h * pitch; - // TODO: Split this up into border, bevel and interior functions - - if (fill_m != kFillDisabled) { - PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); - PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); - PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); - PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); - PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); - - int real_radius = r; - int short_h = h - (2 * r) + 2; - int long_h = h; + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); - BE_RESET(); + int real_radius = r; + int short_h = h - (2 * r) + 2; - PixelType color1 = color; - if (fill_m == kFillBackground) - color1 = _bgColor; + PixelType color1 = color; + PixelType color2 = color; - if (fill_m == kFillGradient) { - PixelType color2, color3, color4; - precalcGradient(long_h); + while (sw++ < Base::_strokeWidth) { + blendFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1, alpha_t); // top + blendFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2, alpha_b); // bottom + sp += pitch; - while (x++ < y) { - BE_ALGORITHM(); + BE_RESET(); + r--; + + int alphaStep_tr = ((alpha_t - alpha_r)/(y+1)); + int alphaStep_br = ((alpha_r - alpha_b)/(y+1)); + int alphaStep_bl = ((alpha_b - alpha_l)/(y+1)); + int alphaStep_tl = ((alpha_l - alpha_t)/(y+1)); + + // Avoid blending the last pixels twice, since we have an alpha + while (x++ < (y - 2)) { + BE_ALGORITHM(); - color1 = calcGradient(real_radius - x, long_h); - color2 = calcGradient(real_radius - y, long_h); - color3 = calcGradient(long_h - r + x, long_h); - color4 = calcGradient(long_h - r + y, long_h); + BE_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)(alpha_r + (alphaStep_tr * x))); + BE_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)(alpha_b + (alphaStep_br * x))); + BE_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)(alpha_l + (alphaStep_bl * x))); + BE_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)(alpha_t + (alphaStep_tl * x))); + + BE_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)(alpha_t - (alphaStep_tr * x))); + BE_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)(alpha_r - (alphaStep_br * x))); + BE_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)(alpha_b - (alphaStep_bl * x))); + BE_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)(alpha_l - (alphaStep_tl * x))); + + if (Base::_strokeWidth > 1) { + BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py); + BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py); + } + } + } - gradientFill(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y); - gradientFill(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x); + ptr_fill += pitch * real_radius; + while (short_h--) { + blendFill(ptr_fill, ptr_fill + Base::_strokeWidth, color1, alpha_l); // left + blendFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2, alpha_r); // right + ptr_fill += pitch; + } +} - gradientFill(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y); - gradientFill(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x); +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + int f, ddF_x, ddF_y; + int x, y, px, py; + int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; - BE_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); - } - } else { - while (x++ < y) { - BE_ALGORITHM(); + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); - colorFill<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1); - colorFill<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1); + int real_radius = r; + int short_h = h - (2 * r) + 2; + int long_h = h; - colorFill<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1); - colorFill<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1); + BE_RESET(); - // do not remove - messes up the drawing at lower resolutions - BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); - } - } + PixelType color1 = color; - ptr_fill += pitch * r; - while (short_h--) { - if (fill_m == kFillGradient) { - gradientFill(ptr_fill, w + 1, x1, real_radius++); - } else { - colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color1); - } - ptr_fill += pitch; - } - } + if (fill_m == kFillGradient) { + PixelType color2, color3, color4; + precalcGradient(long_h); + while (x++ < y) { + BE_ALGORITHM(); - if (Base::_strokeWidth) { - int sw = 0, sp = 0, hp = h * pitch; + color1 = calcGradient(real_radius - x, long_h); + color2 = calcGradient(real_radius - y, long_h); + color3 = calcGradient(long_h - r + x, long_h); + color4 = calcGradient(long_h - r + y, long_h); - PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); - PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); - PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); - PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); - PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + gradientFill(ptr_tl - x - py, w - 2 * r + 2 * x, x1 + r - x - y, real_radius - y); + gradientFill(ptr_tl - y - px, w - 2 * r + 2 * y, x1 + r - y - x, real_radius - x); - int real_radius = r; - int short_h = h - (2 * r) + 2; + gradientFill(ptr_bl - x + py, w - 2 * r + 2 * x, x1 + r - x - y, long_h - r + y); + gradientFill(ptr_bl - y + px, w - 2 * r + 2 * y, x1 + r - y - x, long_h - r + x); - // TODO: A gradient effect on the bevel - PixelType color1, color2; - color1 = Base::_bevel ? _bevelColor : color; - color2 = color; + BE_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); + } + } else { + while (x++ < y) { + BE_ALGORITHM(); - while (sw++ < Base::_strokeWidth) { - colorFill<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1); - colorFill<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2); - sp += pitch; + colorFill<PixelType>(ptr_tl - x - py, ptr_tr + x - py, color1); + colorFill<PixelType>(ptr_tl - y - px, ptr_tr + y - px, color1); - BE_RESET(); - r--; + colorFill<PixelType>(ptr_bl - x + py, ptr_br + x + py, color1); + colorFill<PixelType>(ptr_bl - y + px, ptr_br + y + px, color1); - while (x++ < y) { - BE_ALGORITHM(); - BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); + // do not remove - messes up the drawing at lower resolutions + BE_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py); + } + } - if (Base::_strokeWidth > 1) { - BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x - 1, y, px, py); - BE_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px - pitch, py); - } - } + ptr_fill += pitch * r; + while (short_h--) { + if (fill_m == kFillGradient) { + gradientFill(ptr_fill, w + 1, x1, real_radius++); + } else { + colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color1); } + ptr_fill += pitch; + } +} - ptr_fill += pitch * real_radius; - while (short_h--) { - colorFill<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color1); - colorFill<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2); - ptr_fill += pitch; +template<typename PixelType> +void VectorRendererSpec<PixelType>:: +drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + const uint8 borderAlpha_t = 0; + const uint8 borderAlpha_r = 127; + const uint8 borderAlpha_b = 255; + const uint8 borderAlpha_l = 63; + + const uint8 bevelAlpha_t = 255; + const uint8 bevelAlpha_r = 31; + const uint8 bevelAlpha_b = 0; + const uint8 bevelAlpha_l = 127; + + // If only border is visible + if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) { + if (fill_m == Base::kFillBackground) + drawInteriorRoundedSquareAlg(x1, y1, r, w, h, _bgColor, fill_m); + else + drawInteriorRoundedSquareAlg(x1, y1, r, w, h, color, fill_m); + } + + if (Base::_strokeWidth) { + if (r != 0 && _bevel > 0) { + drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l); + drawBorderRoundedSquareAlg(x1, y1, r, w, h, _bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l); + } else { + drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255); } } } @@ -1638,85 +1829,112 @@ drawCircleAlg(int x1, int y1, int r, PixelType color, VectorRenderer::FillMode f ********************************************************************/ template<typename PixelType> void VectorRendererSpec<PixelType>:: -drawSquareShadow(int x, int y, int w, int h, int blur) { - PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + blur); +drawSquareShadow(int x, int y, int w, int h, int offset) { + PixelType *ptr = (PixelType *)_activeSurface->getBasePtr(x + w - 1, y + offset); int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; int i, j; - i = h - blur; + i = h - offset; while (i--) { - j = blur; + j = offset; while (j--) - blendPixelPtr(ptr + j, 0, ((blur - j) << 8) / blur); + blendPixelPtr(ptr + j, 0, ((offset - j) << 8) / offset); ptr += pitch; } - ptr = (PixelType *)_activeSurface->getBasePtr(x + blur, y + h - 1); + ptr = (PixelType *)_activeSurface->getBasePtr(x + offset, y + h - 1); - while (i++ < blur) { - j = w - blur; + while (i++ < offset) { + j = w - offset; while (j--) - blendPixelPtr(ptr + j, 0, ((blur - i) << 8) / blur); + blendPixelPtr(ptr + j, 0, ((offset - i) << 8) / offset); ptr += pitch; } ptr = (PixelType *)_activeSurface->getBasePtr(x + w, y + h); i = 0; - while (i++ < blur) { - j = blur - 1; + while (i++ < offset) { + j = offset - 1; while (j--) - blendPixelPtr(ptr + j, 0, (((blur - j) * (blur - i)) << 8) / (blur * blur)); + blendPixelPtr(ptr + j, 0, (((offset - j) * (offset - i)) << 8) / (offset * offset)); ptr += pitch; } } template<typename PixelType> void VectorRendererSpec<PixelType>:: -drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int blur) { - int f, ddF_x, ddF_y; - int x, y, px, py; +drawRoundedSquareShadow(int x1, int y1, int r, int w, int h, int offset) { int pitch = _activeSurface->pitch / _activeSurface->format.bytesPerPixel; - int alpha = 102; - x1 += blur; - y1 += blur; + // "Harder" shadows when having lower BPP, since we will have artifacts (greenish tint on the modern theme) + uint8 expFactor = 3; + uint16 alpha = (_activeSurface->format.bytesPerPixel > 2) ? 4 : 8; + + // These constants ensure a border of 2px on the left and of each rounded square + int xstart = (x1 > 2) ? x1 - 2 : x1; + int ystart = y1; + int width = w + offset + 2; + int height = h + offset + 1; + + for (int i = offset; i >= 0; i--) { + int f, ddF_x, ddF_y; + int x, y, px, py; + + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(xstart + r, ystart + height - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(xstart + width - r, ystart + height - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(xstart, ystart); + + int short_h = height - (2 * r) + 2; + PixelType color = _format.RGBToColor(0, 0, 0); - PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); - PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); - PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); - PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - blur, y1 + r); - - int short_h = h - (2 * r) + 1; + BE_RESET(); - BE_RESET(); + // HACK: As we are drawing circles exploting 8-axis symmetry, + // there are 4 pixels on each circle which are drawn twice. + // this is ok on filled circles, but when blending on surfaces, + // we cannot let it blend twice. awful. + uint32 hb = 0; + + while (x++ < y) { + BE_ALGORITHM(); - // HACK: As we are drawing circles exploting 8-axis symmetry, - // there are 4 pixels on each circle which are drawn twice. - // this is ok on filled circles, but when blending on surfaces, - // we cannot let it blend twice. awful. - uint32 hb = 0; - while (x++ < y) { - BE_ALGORITHM(); + if (((1 << x) & hb) == 0) { + blendFill(ptr_tl - y - px, ptr_tr + y - px, color, (uint8)alpha); + + // Will create a dark line of pixles if left out + if (hb > 0) { + blendFill(ptr_bl - y + px, ptr_br + y + px, color, (uint8)alpha); + } + hb |= (1 << x); + } - if (((1 << x) & hb) == 0) { - blendFill(ptr_tr - px - r, ptr_tr + y - px, 0, alpha); - blendFill(ptr_bl - y + px, ptr_br + y + px, 0, alpha); - hb |= (1 << x); + if (((1 << y) & hb) == 0) { + blendFill(ptr_tl - x - py, ptr_tr + x - py, color, (uint8)alpha); + blendFill(ptr_bl - x + py, ptr_br + x + py, color, (uint8)alpha); + hb |= (1 << y); + } } - - if (((1 << y) & hb) == 0) { - blendFill(ptr_tr - r - py, ptr_tr + x - py, 0, alpha); - blendFill(ptr_bl - x + py, ptr_br + x + py, 0, alpha); - hb |= (1 << y); + + ptr_fill += pitch * r; + while (short_h--) { + blendFill(ptr_fill, ptr_fill + width + 1, color, (uint8)alpha); + ptr_fill += pitch; } - } - while (short_h--) { - blendFill(ptr_fill - r, ptr_fill + blur, 0, alpha); - ptr_fill += pitch; + // Make shadow smaller each iteration, and move it one pixel inward + xstart += 1; + ystart += 1; + width -= 2; + height -= 2; + + if (_shadowFillMode == kShadowExponential) + // Multiply with expfactor + alpha = (alpha * (expFactor << 8)) >> 9; } } @@ -1909,7 +2127,7 @@ drawTabAlg(int x1, int y1, int w, int h, int r, PixelType color, VectorRenderer: /** ROUNDED SQUARES **/ template<typename PixelType> void VectorRendererAA<PixelType>:: -drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { +drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l) { int x, y; const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; int px, py; @@ -1918,65 +2136,89 @@ drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, Vecto frac_t T = 0, oldT; uint8 a1, a2; - // TODO: Split this up into border, bevel and interior functions + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); - if (Base::_strokeWidth) { - PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); - PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); - PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); - PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); - PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); - - int sw = 0, sp = 0; - int short_h = h - 2 * r; - int hp = h * pitch; - - int strokeWidth = Base::_strokeWidth; - // If we're going to fill the inside, draw a slightly thicker border - // so we can blend the inside on top of it. - if (fill_m != Base::kFillDisabled) strokeWidth++; - - // TODO: A gradient effect on the bevel - PixelType color1, color2; - color1 = Base::_bevel ? Base::_bevelColor : color; - color2 = color; + int sw = 0, sp = 0; + int short_h = h - 2 * r; + int hp = h * pitch; + int strokeWidth = Base::_strokeWidth; - while (sw++ < strokeWidth) { - colorFill<PixelType>(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color1); - colorFill<PixelType>(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color2); - sp += pitch; + while (sw++ < strokeWidth) { + this->blendFill(ptr_fill + hp - sp + r, ptr_fill + w + hp + 1 - sp - r, color, alpha_b); // bottom + this->blendFill(ptr_fill + sp + r, ptr_fill + w + 1 + sp - r, color, alpha_t); // top - x = r - (sw - 1); - y = 0; - T = 0; - px = pitch * x; - py = 0; + sp += pitch; - while (x > y++) { - WU_ALGORITHM(); + x = r - (sw - 1); + y = 0; + T = 0; + px = pitch * x; + py = 0; - // sw == 1: outside, sw = _strokeWidth: inside - // We always draw the outer edge AAed, but the inner edge - // only when the inside isn't filled - if (sw != strokeWidth || fill_m != Base::kFillDisabled) - a2 = 255; + int alphaStep_tr = ((alpha_t - alpha_r)/(x+1)); + int alphaStep_br = ((alpha_r - alpha_b)/(x+1)); + int alphaStep_bl = ((alpha_b - alpha_l)/(x+1)); + int alphaStep_tl = ((alpha_l - alpha_t)/(x+1)); - // inner arc - WU_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, (x - 1), y, (px - pitch), py, a2); + while (x > y++) { + WU_ALGORITHM(); - if (sw == 1) // outer arc - WU_DRAWCIRCLE_BCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1); + // sw == 1: outside, sw = _strokeWidth: inside + // We always draw the outer edge AAed, but the inner edge + // only when the inside isn't filled + if (sw != strokeWidth || fill_m != Base::kFillDisabled) + a2 = 255; + + // inner arc + WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a2) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a2) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a2) >> 16)); + WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a2) >> 16)); + + WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a2) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a2) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a2) >> 16)); + WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, (x - 1), y, (px - pitch), py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a2) >> 16)); + + // outer arc + if (sw == 1) { + WU_DRAWCIRCLE_BCOLOR_TR_CW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_t - (alphaStep_tr * y)) << 8) * a1) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BR_CW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_r - (alphaStep_br * y)) << 8) * a1) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BL_CW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_b - (alphaStep_bl * y)) << 8) * a1) >> 16)); + WU_DRAWCIRCLE_BCOLOR_TL_CW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_l - (alphaStep_tl * y)) << 8) * a1) >> 16)); + + WU_DRAWCIRCLE_BCOLOR_TR_CCW(ptr_tr, x, y, px, py, (uint8)((uint32)(((alpha_r + (alphaStep_tr * y)) << 8) * a1) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BR_CCW(ptr_br, x, y, px, py, (uint8)((uint32)(((alpha_b + (alphaStep_br * y)) << 8) * a1) >> 16)); + WU_DRAWCIRCLE_BCOLOR_BL_CCW(ptr_bl, x, y, px, py, (uint8)((uint32)(((alpha_l + (alphaStep_bl * y)) << 8) * a1) >> 16)); + WU_DRAWCIRCLE_BCOLOR_TL_CCW(ptr_tl, x, y, px, py, (uint8)((uint32)(((alpha_t + (alphaStep_tl * y)) << 8) * a1) >> 16)); + } } - } ptr_fill += pitch * r; - while (short_h-- >= 0) { - colorFill<PixelType>(ptr_fill, ptr_fill + Base::_strokeWidth, color1); - colorFill<PixelType>(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color2); + + while (short_h-- >= -2) { + this->blendFill(ptr_fill, ptr_fill + Base::_strokeWidth, color, alpha_l); // left + this->blendFill(ptr_fill + w - Base::_strokeWidth + 1, ptr_fill + w + 1, color, alpha_r); // right ptr_fill += pitch; } } +} + +template<typename PixelType> +void VectorRendererAA<PixelType>:: +drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + int x, y; + const int pitch = Base::_activeSurface->pitch / Base::_activeSurface->format.bytesPerPixel; + int px, py; + + uint32 rsq = r*r; + frac_t T = 0, oldT; + uint8 a1, a2; r -= Base::_strokeWidth; x1 += Base::_strokeWidth; @@ -1985,93 +2227,116 @@ drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, Vecto h -= 2*Base::_strokeWidth; rsq = r*r; - if (w <= 0 || h <= 0) - return; // Only border is visible + PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); + PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); + PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); + PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); + PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); - if (fill_m != Base::kFillDisabled) { - if (fill_m == Base::kFillBackground) - color = Base::_bgColor; + int short_h = h - 2 * r; + x = r; + y = 0; + T = 0; + px = pitch * x; + py = 0; - PixelType *ptr_tl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + r); - PixelType *ptr_tr = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + r); - PixelType *ptr_bl = (PixelType *)Base::_activeSurface->getBasePtr(x1 + r, y1 + h - r); - PixelType *ptr_br = (PixelType *)Base::_activeSurface->getBasePtr(x1 + w - r, y1 + h - r); - PixelType *ptr_fill = (PixelType *)Base::_activeSurface->getBasePtr(x1, y1); + if (fill_m == Base::kFillGradient) { - int short_h = h - 2 * r; - x = r; - y = 0; - T = 0; - px = pitch * x; - py = 0; + Base::precalcGradient(h); - if (fill_m == Base::kFillGradient) { + PixelType color1, color2, color3, color4; + while (x > y++) { + WU_ALGORITHM(); - Base::precalcGradient(h); + color1 = Base::calcGradient(r - x, h); + color2 = Base::calcGradient(r - y, h); + color3 = Base::calcGradient(h - r + x, h); + color4 = Base::calcGradient(h - r + y, h); - PixelType color1, color2, color3, color4; - while (x > y++) { - WU_ALGORITHM(); + Base::gradientFill(ptr_tl - x - py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, r - y); - color1 = Base::calcGradient(r - x, h); - color2 = Base::calcGradient(r - y, h); - color3 = Base::calcGradient(h - r + x, h); - color4 = Base::calcGradient(h - r + y, h); + // Only fill each horizontal line once (or we destroy + // the gradient effect at the edges) + if (T < oldT || y == 1) + Base::gradientFill(ptr_tl - y - px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, r - x); - Base::gradientFill(ptr_tl - x - py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, r - y); + Base::gradientFill(ptr_bl - x + py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, h - r + y); - // Only fill each horizontal line once (or we destroy - // the gradient effect at the edges) - if (T < oldT || y == 1) - Base::gradientFill(ptr_tl - y - px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, r - x); + // Only fill each horizontal line once (or we destroy + // the gradient effect at the edges) + if (T < oldT || y == 1) + Base::gradientFill(ptr_bl - y + px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, h - r + x); - Base::gradientFill(ptr_bl - x + py + 1, w - 2 * r + 2 * x - 1, x1 + r - x - y + 1, h - r + y); + // This shape is used for dialog backgrounds. + // If we're drawing on top of an empty overlay background, + // and the overlay supports alpha, we have to do AA by + // setting the dest alpha channel, instead of blending with + // dest color channels. + if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) + WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelPtr); + else + WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelDestAlphaPtr); + } - // Only fill each horizontal line once (or we destroy - // the gradient effect at the edges) - if (T < oldT || y == 1) - Base::gradientFill(ptr_bl - y + px + 1, w - 2 * r + 2 * y - 1, x1 + r - y - x + 1, h - r + x); - - // This shape is used for dialog backgrounds. - // If we're drawing on top of an empty overlay background, - // and the overlay supports alpha, we have to do AA by - // setting the dest alpha channel, instead of blending with - // dest color channels. - if (!g_system->hasFeature(OSystem::kFeatureOverlaySupportsAlpha)) - WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelPtr); - else - WU_DRAWCIRCLE_XCOLOR(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1, blendPixelDestAlphaPtr); - } + ptr_fill += pitch * r; + while (short_h-- >= 0) { + Base::gradientFill(ptr_fill, w + 1, x1, r++); + ptr_fill += pitch; + } - ptr_fill += pitch * r; - while (short_h-- >= 0) { - Base::gradientFill(ptr_fill, w + 1, x1, r++); - ptr_fill += pitch; - } + } else { - } else { + while (x > 1 + y++) { + WU_ALGORITHM(); - while (x > 1 + y++) { - WU_ALGORITHM(); + colorFill<PixelType>(ptr_tl - x - py + 1, ptr_tr + x - py, color); + if (T < oldT || y == 1) + colorFill<PixelType>(ptr_tl - y - px + 1, ptr_tr + y - px, color); - colorFill<PixelType>(ptr_tl - x - py + 1, ptr_tr + x - py, color); - if (T < oldT || y == 1) - colorFill<PixelType>(ptr_tl - y - px + 1, ptr_tr + y - px, color); + colorFill<PixelType>(ptr_bl - x + py + 1, ptr_br + x + py, color); + if (T < oldT || y == 1) + colorFill<PixelType>(ptr_bl - y + px + 1, ptr_br + y + px, color); - colorFill<PixelType>(ptr_bl - x + py + 1, ptr_br + x + py, color); - if (T < oldT || y == 1) - colorFill<PixelType>(ptr_bl - y + px + 1, ptr_br + y + px, color); + WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1); + } - WU_DRAWCIRCLE(ptr_tr, ptr_tl, ptr_bl, ptr_br, x, y, px, py, a1); - } + ptr_fill += pitch * r; + while (short_h-- >= 0) { + colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color); + ptr_fill += pitch; + } + } +} - ptr_fill += pitch * r; - while (short_h-- >= 0) { - colorFill<PixelType>(ptr_fill, ptr_fill + w + 1, color); - ptr_fill += pitch; - } +template<typename PixelType> +void VectorRendererAA<PixelType>:: +drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m) { + const uint8 borderAlpha_t = 0; + const uint8 borderAlpha_r = 127; + const uint8 borderAlpha_b = 255; + const uint8 borderAlpha_l = 63; + + const uint8 bevelAlpha_t = 255; + const uint8 bevelAlpha_r = 31; + const uint8 bevelAlpha_b = 0; + const uint8 bevelAlpha_l = 127; + + if (Base::_strokeWidth) { + if (r != 0 && Base::_bevel > 0) { + drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, borderAlpha_t, borderAlpha_r, borderAlpha_b, borderAlpha_l); + drawBorderRoundedSquareAlg(x1, y1, r, w, h, Base::_bevelColor, fill_m, bevelAlpha_t, bevelAlpha_r, bevelAlpha_b, bevelAlpha_l); + } else { + drawBorderRoundedSquareAlg(x1, y1, r, w, h, color, fill_m, 255, 255, 255, 255); } } + + // If only border is visible + if ((!(w <= 0 || h <= 0)) && (fill_m != Base::kFillDisabled)) { + if (fill_m == Base::kFillBackground) + drawInteriorRoundedSquareAlg(x1, y1, r, w, h, Base::_bgColor, fill_m); + else + drawInteriorRoundedSquareAlg(x1, y1, r, w, h, color, fill_m); + } } /** CIRCLES **/ diff --git a/graphics/VectorRendererSpec.h b/graphics/VectorRendererSpec.h index 4ed80cb55f..c035ca0e19 100644 --- a/graphics/VectorRendererSpec.h +++ b/graphics/VectorRendererSpec.h @@ -61,7 +61,7 @@ public: } void drawString(const Graphics::Font *font, const Common::String &text, const Common::Rect &area, Graphics::TextAlign alignH, - GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool elipsis); + GUI::ThemeEngine::TextAlignVertical alignV, int deltax, bool elipsis, const Common::Rect &textDrawableArea = Common::Rect(0, 0, 0, 0)); void setFgColor(uint8 r, uint8 g, uint8 b) { _fgColor = _format.RGBToColor(r, g, b); } void setBgColor(uint8 r, uint8 g, uint8 b) { _bgColor = _format.RGBToColor(r, g, b); } @@ -158,6 +158,12 @@ protected: virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, FillMode fill_m); + virtual void drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, + PixelType color, FillMode fill_m, uint8 alpha_t, uint8 alpha_r, uint8 alpha_b, uint8 alpha_l); + + virtual void drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, + PixelType color, FillMode fill_m); + virtual void drawSquareAlg(int x, int y, int w, int h, PixelType color, FillMode fill_m); @@ -174,6 +180,8 @@ protected: PixelType color, VectorRenderer::FillMode fill_m, int baseLeft = 0, int baseRight = 0); + virtual void drawTabShadow(int x, int y, int w, int h, int r); + virtual void drawBevelTabAlg(int x, int y, int w, int h, int bevel, PixelType topColor, PixelType bottomColor, int baseLeft = 0, int baseRight = 0); @@ -186,10 +194,10 @@ protected: * There functions may be overloaded in inheriting classes to improve performance * in the slowest platforms where pixel alpha blending just doesn't cut it. * - * @param blur Intensity/size of the shadow. + * @param offset Intensity/size of the shadow. */ - virtual void drawSquareShadow(int x, int y, int w, int h, int blur); - virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int blur); + virtual void drawSquareShadow(int x, int y, int w, int h, int offset); + virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int offset); /** * Calculates the color gradient on a given point. @@ -292,10 +300,12 @@ protected: */ virtual void drawRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m); - virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int blur) { - Base::drawRoundedSquareShadow(x, y, r, w, h, blur); -// VectorRenderer::applyConvolutionMatrix(VectorRenderer::kConvolutionHardBlur, -// Common::Rect(x, y, x + w + blur * 2, y + h + blur * 2)); + virtual void drawBorderRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m, uint8 alpha_t, uint8 alpha_l, uint8 alpha_r, uint8 alpha_b); + + virtual void drawInteriorRoundedSquareAlg(int x1, int y1, int r, int w, int h, PixelType color, VectorRenderer::FillMode fill_m); + + virtual void drawRoundedSquareShadow(int x, int y, int r, int w, int h, int offset) { + Base::drawRoundedSquareShadow(x, y, r, w, h, offset); } virtual void drawTabAlg(int x, int y, int w, int h, int r, diff --git a/graphics/font.cpp b/graphics/font.cpp index 3b00cd8568..a852274b06 100644 --- a/graphics/font.cpp +++ b/graphics/font.cpp @@ -128,7 +128,7 @@ void Font::drawString(Surface *dst, const Common::String &sOld, int x, int y, in w = getCharWidth(cur); if (x+w > rightX) break; - if (x >= leftX) + if (x+w >= leftX) drawChar(dst, str[i], x, y, color); x += w; } diff --git a/gui/ThemeEngine.cpp b/gui/ThemeEngine.cpp index 561c0244a2..688654d208 100644 --- a/gui/ThemeEngine.cpp +++ b/gui/ThemeEngine.cpp @@ -122,15 +122,16 @@ protected: class ThemeItemTextData : public ThemeItem { public: - ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const TextColorData *color, const Common::Rect &area, const Common::String &text, - Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV, + ThemeItemTextData(ThemeEngine *engine, const TextDrawData *data, const TextColorData *color, const Common::Rect &area, const Common::Rect &textDrawableArea, + const Common::String &text, Graphics::TextAlign alignH, GUI::ThemeEngine::TextAlignVertical alignV, bool ellipsis, bool restoreBg, int deltaX) : ThemeItem(engine, area), _data(data), _color(color), _text(text), _alignH(alignH), _alignV(alignV), - _ellipsis(ellipsis), _restoreBg(restoreBg), _deltax(deltaX) {} + _ellipsis(ellipsis), _restoreBg(restoreBg), _deltax(deltaX), _textDrawableArea(textDrawableArea) {} void drawSelf(bool draw, bool restore); protected: + Common::Rect _textDrawableArea; const TextDrawData *_data; const TextColorData *_color; Common::String _text; @@ -246,7 +247,7 @@ void ThemeItemTextData::drawSelf(bool draw, bool restore) { if (draw) { _engine->renderer()->setFgColor(_color->r, _color->g, _color->b); - _engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis); + _engine->renderer()->drawString(_data->_fontPtr, _text, _area, _alignH, _alignV, _deltax, _ellipsis, _textDrawableArea); } _engine->addDirtyRect(_area); @@ -521,6 +522,12 @@ void ThemeEngine::setGraphicsMode(GraphicsMode mode) { delete _vectorRenderer; _vectorRenderer = Graphics::createRenderer(mode); _vectorRenderer->setSurface(&_screen); + + // Since we reinitialized our screen surfaces we know nothing has been + // drawn so far. Sometimes we still end up with dirty screen bits in the + // list. Clearing it avoids invalid overlay writes when the backend + // resizes the overlay. + _dirtyScreen.clear(); } void WidgetDrawData::calcBackgroundOffset() { @@ -836,7 +843,7 @@ void ThemeEngine::queueDD(DrawData type, const Common::Rect &r, uint32 dynamic, } void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg, - bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax) { + bool ellipsis, Graphics::TextAlign alignH, TextAlignVertical alignV, int deltax, const Common::Rect &drawableTextArea) { if (_texts[type] == 0) return; @@ -844,7 +851,7 @@ void ThemeEngine::queueDDText(TextData type, TextColor color, const Common::Rect Common::Rect area = r; area.clip(_screen.w, _screen.h); - ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], _textColors[color], area, text, alignH, alignV, ellipsis, restoreBg, deltax); + ThemeItemTextData *q = new ThemeItemTextData(this, _texts[type], _textColors[color], area, drawableTextArea, text, alignH, alignV, ellipsis, restoreBg, deltax); if (_buffering) { _screenQueue.push_back(q); @@ -1115,7 +1122,7 @@ void ThemeEngine::drawTab(const Common::Rect &r, int tabHeight, int tabWidth, co } } -void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color, bool restore) { +void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state, Graphics::TextAlign align, TextInversionState inverted, int deltax, bool useEllipsis, FontStyle font, FontColor color, bool restore, const Common::Rect &drawableTextArea) { if (!ready()) return; @@ -1185,7 +1192,7 @@ void ThemeEngine::drawText(const Common::Rect &r, const Common::String &str, Wid break; } - queueDDText(textId, colorId, r, str, restore, useEllipsis, align, kTextAlignVCenter, deltax); + queueDDText(textId, colorId, r, str, restore, useEllipsis, align, kTextAlignVCenter, deltax, drawableTextArea); } void ThemeEngine::drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state, FontColor color) { diff --git a/gui/ThemeEngine.h b/gui/ThemeEngine.h index c0e47a19e6..4dffb13e71 100644 --- a/gui/ThemeEngine.h +++ b/gui/ThemeEngine.h @@ -29,6 +29,7 @@ #include "common/hashmap.h" #include "common/list.h" #include "common/str.h" +#include "common/rect.h" #include "graphics/surface.h" #include "graphics/font.h" @@ -39,10 +40,6 @@ class OSystem; -namespace Common { -struct Rect; -} - namespace Graphics { struct DrawStep; class VectorRenderer; @@ -376,7 +373,7 @@ public: void drawDialogBackground(const Common::Rect &r, DialogBackground type, WidgetStateInfo state = kStateEnabled); - void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, TextInversionState inverted = kTextInversionNone, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold, FontColor color = kFontColorNormal, bool restore = true); + void drawText(const Common::Rect &r, const Common::String &str, WidgetStateInfo state = kStateEnabled, Graphics::TextAlign align = Graphics::kTextAlignCenter, TextInversionState inverted = kTextInversionNone, int deltax = 0, bool useEllipsis = true, FontStyle font = kFontStyleBold, FontColor color = kFontColorNormal, bool restore = true, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0)); void drawChar(const Common::Rect &r, byte ch, const Graphics::Font *font, WidgetStateInfo state = kStateEnabled, FontColor color = kFontColorNormal); @@ -588,7 +585,7 @@ protected: */ void queueDD(DrawData type, const Common::Rect &r, uint32 dynamic = 0, bool restore = false); void queueDDText(TextData type, TextColor color, const Common::Rect &r, const Common::String &text, bool restoreBg, - bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0); + bool elipsis, Graphics::TextAlign alignH = Graphics::kTextAlignLeft, TextAlignVertical alignV = kTextAlignVTop, int deltax = 0, const Common::Rect &drawableTextArea = Common::Rect(0, 0, 0, 0)); void queueBitmap(const Graphics::Surface *bitmap, const Common::Rect &r, bool alpha); /** diff --git a/gui/about.cpp b/gui/about.cpp index 20145886c6..3bb1934e28 100644 --- a/gui/about.cpp +++ b/gui/about.cpp @@ -180,9 +180,10 @@ void AboutDialog::close() { } void AboutDialog::drawDialog() { -// g_gui.theme()->setDrawArea(Common::Rect(_x, _y, _x+_w, _y+_h)); Dialog::drawDialog(); + setTextDrawableArea(Common::Rect(_x, _y, _x + _w, _y + _h)); + // Draw text // TODO: Add a "fade" effect for the top/bottom text lines // TODO: Maybe prerender all of the text into another surface, @@ -239,8 +240,8 @@ void AboutDialog::drawDialog() { while (*str && *str == ' ') str++; - if (*str && y > _y && y + g_gui.theme()->getFontHeight() < _y + _h) - g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, ThemeEngine::kTextInversionNone, 0, false); + if (*str) + g_gui.theme()->drawText(Common::Rect(_x + _xOff, y, _x + _w - _xOff, y + g_gui.theme()->getFontHeight()), str, state, align, ThemeEngine::kTextInversionNone, 0, false, ThemeEngine::kFontStyleBold, ThemeEngine::kFontColorNormal, true, _textDrawableArea); y += _lineHeight; } } diff --git a/gui/credits.h b/gui/credits.h index 70f79ac9a5..3a4d7769f6 100644 --- a/gui/credits.h +++ b/gui/credits.h @@ -170,6 +170,15 @@ static const char *credits[] = { "C0""Eugene Sandulenko", "C0""David Turner", "", +"C1""Mortevielle", +"A0""Arnaud Boutonne", +"C0""Arnaud Boutonn\351", +"C0""Paul Gilbert", +"", +"C1""Neverhood", +"C0""Benjamin Haisch", +"C0""Filippos Karapetis", +"", "C1""Parallaction", "C0""peres", "", diff --git a/gui/object.cpp b/gui/object.cpp index 73c4f74d6c..189a286ead 100644 --- a/gui/object.cpp +++ b/gui/object.cpp @@ -29,7 +29,7 @@ namespace GUI { GuiObject::GuiObject(const Common::String &name) - : _x(-1000), _y(-1000), _w(0), _h(0), _name(name), _firstWidget(0) { + : _x(-1000), _y(-1000), _w(0), _h(0), _name(name), _firstWidget(0), _textDrawableArea(Common::Rect(0, 0, 0, 0)) { reflowLayout(); } diff --git a/gui/object.h b/gui/object.h index bce3cd7846..dac3341b5a 100644 --- a/gui/object.h +++ b/gui/object.h @@ -24,6 +24,7 @@ #include "common/scummsys.h" #include "common/str.h" +#include "common/rect.h" namespace GUI { @@ -59,6 +60,8 @@ class Widget; class GuiObject : public CommandReceiver { friend class Widget; protected: + Common::Rect _textDrawableArea; + int16 _x, _y; uint16 _w, _h; const Common::String _name; @@ -66,10 +69,12 @@ protected: Widget *_firstWidget; public: - GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _firstWidget(0) { } + GuiObject(int x, int y, int w, int h) : _x(x), _y(y), _w(w), _h(h), _firstWidget(0), _textDrawableArea(Common::Rect(0, 0, 0, 0)) { } GuiObject(const Common::String &name); ~GuiObject(); + virtual void setTextDrawableArea(const Common::Rect &r) { _textDrawableArea = r; } + virtual int16 getAbsX() const { return _x; } virtual int16 getAbsY() const { return _y; } virtual int16 getChildX() const { return getAbsX(); } diff --git a/gui/themes/default.inc b/gui/themes/default.inc index 1b6ae3ec27..352cc86852 100644 --- a/gui/themes/default.inc +++ b/gui/themes/default.inc @@ -1,142 +1,142 @@ "<?xml version = '1.0'?>" -"<render_info> " -"<palette> " +"<render_info>" +"<palette>" "<color name='black' " "rgb='0,0,0' " -"/> " +"/>" "<color name='lightgrey' " "rgb='104,104,104' " -"/> " +"/>" "<color name='darkgrey' " "rgb='64,64,64' " -"/> " +"/>" "<color name='green' " "rgb='32,160,32' " -"/> " +"/>" "<color name='green2' " "rgb='0,255,0' " -"/> " -"</palette> " -"<fonts> " +"/>" +"</palette>" +"<fonts>" "<font id='text_default' " "file='helvb12.bdf' " -"/> " +"/>" "<font resolution='y<400' " "id='text_default' " "file='clR6x12.bdf' " -"/> " +"/>" "<font id='text_button' " "file='helvb12.bdf' " -"/> " +"/>" "<font resolution='y<400' " "id='text_button' " "file='clR6x12.bdf' " -"/> " +"/>" "<font id='text_normal' " "file='helvb12.bdf' " -"/> " +"/>" "<font resolution='y<400' " "id='text_normal' " "file='clR6x12.bdf' " -"/> " +"/>" "<font id='tooltip_normal' " "file='fixed5x8.bdf' " -"/> " +"/>" "<text_color id='color_normal' " "color='green' " -"/> " +"/>" "<text_color id='color_normal_inverted' " "color='black' " -"/> " +"/>" "<text_color id='color_normal_hover' " "color='green2' " -"/> " +"/>" "<text_color id='color_normal_disabled' " "color='lightgrey' " -"/> " +"/>" "<text_color id='color_alternative' " "color='lightgrey' " -"/> " +"/>" "<text_color id='color_alternative_inverted' " "color='255,255,255' " -"/> " +"/>" "<text_color id='color_alternative_hover' " "color='176,176,176' " -"/> " +"/>" "<text_color id='color_alternative_disabled' " "color='darkgrey' " -"/> " +"/>" "<text_color id='color_button' " "color='green' " -"/> " +"/>" "<text_color id='color_button_hover' " "color='green2' " -"/> " +"/>" "<text_color id='color_button_disabled' " "color='lightgrey' " -"/> " -"</fonts> " -"<defaults fill='foreground' fg_color='darkgrey' bg_color='black' shadow='0' bevel_color='lightgrey'/> " -"<drawdata id='text_selection' cache='false'> " +"/>" +"</fonts>" +"<defaults fill='foreground' fg_color='darkgrey' bg_color='black' shadow='0' bevel_color='lightgrey'/>" +"<drawdata id='text_selection' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='text_selection_focus' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='text_selection_focus' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='mainmenu_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='mainmenu_bg' cache='false'>" "<drawstep func='fill' " "fill='foreground' " "fg_color='black' " -"/> " -"</drawdata> " -"<drawdata id='special_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='special_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='tooltip_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tooltip_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='foreground' " "fg_color='black' " -"/> " -"</drawdata> " -"<drawdata id='separator' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='separator' cache='false'>" "<drawstep func='square' " "fill='foreground' " "height='2' " "ypos='center' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_base' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_base' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_handle_hover' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_handle_hover' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green2' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_handle_idle' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_handle_idle' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_idle' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_idle' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -146,13 +146,13 @@ "ypos='center' " "padding='0,0,3,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_idle' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_idle' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -162,13 +162,13 @@ "ypos='center' " "padding='0,0,2,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_hover' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_hover' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -178,13 +178,13 @@ "ypos='center' " "padding='0,0,3,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='scrollbar_button_hover' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='scrollbar_button_hover' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -194,69 +194,69 @@ "ypos='center' " "padding='0,0,2,0' " "orientation='top' " -"/> " -"</drawdata> " -"<drawdata id='tab_active' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tab_active' cache='false'>" "<text font='text_default' " "text_color='color_normal_hover' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='tab' " "bevel='2' " "radius='0' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='tab_inactive' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tab_inactive' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='tab' " "bevel='2' " "radius='0' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='tab_background' cache='false'> " -"</drawdata> " -"<drawdata id='widget_slider' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='tab_background' cache='false'>" +"</drawdata>" +"<drawdata id='widget_slider' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='slider_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='slider_disabled' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='slider_full' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='slider_full' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='slider_hover' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='slider_hover' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='green2' " -"/> " -"</drawdata> " -"<drawdata id='widget_small' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_small' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='popup_idle' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='popup_idle' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -266,7 +266,7 @@ "ypos='10' " "padding='0,0,7,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -276,18 +276,18 @@ "ypos='4' " "padding='0,0,7,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_idle' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='popup_idle' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -297,7 +297,7 @@ "ypos='9' " "padding='0,0,3,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -307,18 +307,18 @@ "ypos='4' " "padding='0,0,3,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_disabled' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='popup_disabled' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -328,7 +328,7 @@ "ypos='10' " "padding='0,0,7,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -338,18 +338,18 @@ "ypos='4' " "padding='0,0,7,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_disabled' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='popup_disabled' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -359,7 +359,7 @@ "ypos='9' " "padding='0,0,3,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -369,18 +369,18 @@ "ypos='4' " "padding='0,0,3,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_hover' cache='false' resolution='y>399'> " +"/>" +"</drawdata>" +"<drawdata id='popup_hover' cache='false' resolution='y>399'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -390,7 +390,7 @@ "ypos='10' " "padding='0,0,7,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -400,18 +400,18 @@ "ypos='4' " "padding='0,0,7,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal_hover' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='popup_hover' cache='false' resolution='y<400'> " +"/>" +"</drawdata>" +"<drawdata id='popup_hover' cache='false' resolution='y<400'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -421,7 +421,7 @@ "ypos='9' " "padding='0,0,3,0' " "orientation='bottom' " -"/> " +"/>" "<drawstep func='triangle' " "fg_color='green' " "fill='foreground' " @@ -431,123 +431,123 @@ "ypos='4' " "padding='0,0,3,0' " "orientation='top' " -"/> " +"/>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " -"</drawdata> " -"<drawdata id='widget_textedit' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_textedit' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='plain_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='plain_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='caret' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='caret' cache='false'>" "<drawstep func='square' " "fill='foreground' " "fg_color='lightgrey' " -"/> " -"</drawdata> " -"<drawdata id='default_bg' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='default_bg' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='button_pressed' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_pressed' cache='false'>" "<text font='text_button' " "text_color='color_alternative_inverted' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='square' " "fill='foreground' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='button_idle' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_idle' cache='false'>" "<text font='text_button' " "text_color='color_button' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='button_hover' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_hover' cache='false'>" "<text font='text_button' " "text_color='color_button_hover' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='button_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='button_disabled' cache='false'>" "<text font='text_button' " "text_color='color_button_disabled' " "vertical_align='center' " "horizontal_align='center' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='checkbox_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='checkbox_disabled' cache='false'>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='top' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='checkbox_selected' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='checkbox_selected' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='top' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " +"/>" "<drawstep func='cross' " "fill='foreground' " "stroke='2' " "fg_color='green' " -"/> " -"</drawdata> " -"<drawdata id='checkbox_default' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='checkbox_default' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='top' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='bevelsq' " "bevel='2' " "fill='none' " -"/> " -"</drawdata> " -"<drawdata id='radiobutton_default' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='radiobutton_default' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -556,14 +556,14 @@ "bg_color='darkgrey' " "xpos='0' " "ypos='0' " -"/> " -"</drawdata> " -"<drawdata id='radiobutton_selected' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='radiobutton_selected' cache='false'>" "<text font='text_default' " "text_color='color_normal' " "vertical_align='center' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -572,7 +572,7 @@ "fill='none' " "xpos='0' " "ypos='0' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -581,14 +581,14 @@ "fill='foreground' " "xpos='2' " "ypos='2' " -"/> " -"</drawdata> " -"<drawdata id='radiobutton_disabled' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='radiobutton_disabled' cache='false'>" "<text font='text_default' " "text_color='color_normal_disabled' " "vertical_align='center' " "horizontal_align='left' " -"/> " +"/>" "<drawstep func='circle' " "width='7' " "height='7' " @@ -597,2510 +597,2510 @@ "fill='background' " "xpos='0' " "ypos='0' " -"/> " -"</drawdata> " -"<drawdata id='widget_default' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_default' cache='false'>" "<drawstep func='bevelsq' " "bevel='2' " -"/> " -"</drawdata> " -"<drawdata id='widget_small' cache='false'> " +"/>" +"</drawdata>" +"<drawdata id='widget_small' cache='false'>" "<drawstep func='square' " "stroke='0' " -"/> " -"</drawdata> " -"</render_info> " -"<layout_info resolution='y>399'> " -"<globals> " -"<def var='Line.Height' value='16' /> " -"<def var='Font.Height' value='16' /> " -"<def var='About.OuterBorder' value='80'/> " -"<def var='Layout.Spacing' value='8' /> " -"<def var='ShowLauncherLogo' value='0'/> " -"<def var='ShowGlobalMenuLogo' value='0'/> " -"<def var='ShowSearchPic' value='0'/> " -"<def var='ShowChooserPics' value='0'/> " -"<def var='ShowChooserPageDisplay' value='1'/> " -"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/> " -"<def var='RecorderDialog.ExtInfo.Visible' value='1'/> " -"<def var='OnScreenDialog.ShowPics' value='0'/> " -"<def var='KeyMapper.Spacing' value='10'/> " -"<def var='KeyMapper.LabelWidth' value='100'/> " -"<def var='KeyMapper.ButtonWidth' value='80'/> " -"<def var='Tooltip.MaxWidth' value='200'/> " +"/>" +"</drawdata>" +"</render_info>" +"<layout_info resolution='y>399'>" +"<globals>" +"<def var='Line.Height' value='16' />" +"<def var='Font.Height' value='16' />" +"<def var='About.OuterBorder' value='80'/>" +"<def var='Layout.Spacing' value='8' />" +"<def var='ShowLauncherLogo' value='0'/>" +"<def var='ShowGlobalMenuLogo' value='0'/>" +"<def var='ShowSearchPic' value='0'/>" +"<def var='ShowChooserPics' value='0'/>" +"<def var='ShowChooserPageDisplay' value='1'/>" +"<def var='SaveLoadChooser.ExtInfo.Visible' value='1'/>" +"<def var='RecorderDialog.ExtInfo.Visible' value='1'/>" +"<def var='OnScreenDialog.ShowPics' value='0'/>" +"<def var='KeyMapper.Spacing' value='10'/>" +"<def var='KeyMapper.LabelWidth' value='100'/>" +"<def var='KeyMapper.ButtonWidth' value='80'/>" +"<def var='Tooltip.MaxWidth' value='200'/>" "<def var='Tooltip.XDelta' value='16'/> " -"<def var='Tooltip.YDelta' value='16'/> " -"<def var='Predictive.Button.Width' value='60' /> " +"<def var='Tooltip.YDelta' value='16'/>" +"<def var='Predictive.Button.Width' value='60' />" "<widget name='OptionsLabel' " "size='110,Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='SmallLabel' " "size='24,Globals.Line.Height' " -"/> " +"/>" "<widget name='ShortOptionsLabel' " "size='60,Globals.Line.Height' " -"/> " +"/>" "<widget name='Button' " "size='108,24' " -"/> " +"/>" "<widget name='Slider' " "size='128,18' " -"/> " +"/>" "<widget name='PopUp' " "size='-1,19' " -"/> " +"/>" "<widget name='Checkbox' " "size='-1,14' " -"/> " +"/>" "<widget name='Radiobutton' " "size='-1,Globals.Line.Height' " -"/> " +"/>" "<widget name='ListWidget' " "padding='5,0,8,0' " -"/> " +"/>" "<widget name='PopUpWidget' " "padding='7,5,0,0' " -"/> " +"/>" "<widget name='EditTextWidget' " "padding='5,5,0,0' " -"/> " +"/>" "<widget name='Console' " "padding='7,5,5,5' " -"/> " +"/>" "<widget name='Scrollbar' " "size='15,0' " -"/> " +"/>" "<widget name='TabWidget.Tab' " "size='75,27' " "padding='0,0,8,0' " -"/> " +"/>" "<widget name='TabWidget.Body' " "padding='0,0,0,0' " -"/> " +"/>" "<widget name='TabWidget.NavButton' " "size='15,18' " "padding='0,3,4,0' " -"/> " +"/>" "<widget name='EditRecordLabel' " "size='60,25' " -"/> " +"/>" "<widget name='EditRecord' " "size='240,25' " -"/> " -"</globals> " -"<dialog name='Launcher' overlays='screen'> " -"<layout type='vertical' center='true' padding='16,16,8,8'> " +"/>" +"</globals>" +"<dialog name='Launcher' overlays='screen'>" +"<layout type='vertical' center='true' padding='16,16,8,8'>" "<widget name='Version' " "height='Globals.Line.Height' " "textalign='center' " -"/> " -"<layout type='horizontal' spacing='5' padding='10,0,0,0'> " +"/>" +"<layout type='horizontal' spacing='5' padding='10,0,0,0'>" "<widget name='SearchDesc' " "width='60' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='Search' " "width='150' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SearchClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space /> " -"</layout> " -"<widget name='GameList'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"<space />" +"</layout>" +"<widget name='GameList'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='LoadGameButton' " "height='20' " -"/> " +"/>" "<widget name='AddGameButton' " "height='20' " -"/> " +"/>" "<widget name='EditGameButton' " "height='20' " -"/> " +"/>" "<widget name='RemoveGameButton' " "height='20' " -"/> " -"</layout> " -"<space size='4'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<space size='4'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='QuitButton' " "height='20' " -"/> " +"/>" "<widget name='AboutButton' " "height='20' " -"/> " +"/>" "<widget name='OptionsButton' " "height='20' " -"/> " +"/>" "<widget name='StartButton' " "height='20' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='Browser' overlays='Dialog.Launcher.GameList' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='Headline' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Path' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " -"<layout type='vertical' padding='0,0,16,0'> " +"/>" +"<widget name='List'/>" +"<layout type='vertical' padding='0,0,16,0'>" "<widget name='Hidden' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Up' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,16'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions' overlays='Dialog.Launcher.GameList' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='16,16,16,16'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='grModePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grModePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='grRenderPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grRenderPopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='grAspectCheckbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='grFullscreenCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auMidiPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auMidiPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auOPLPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auOPLPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auSampleRatePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auSampleRatePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='horizontal' padding='16,16,16,16' spacing='8'> " -"<layout type='vertical' padding='0,0,0,0' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='horizontal' padding='16,16,16,16' spacing='8'>" +"<layout type='vertical' padding='0,0,0,0' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"<layout type='vertical' padding='24,0,24,0' center='true'> " +"/>" +"</layout>" +"</layout>" +"<layout type='vertical' padding='24,0,24,0' center='true'>" "<widget name='vcMuteCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auPrefGmPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefGmPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='mcFontButton' " "type='Button' " -"/> " +"/>" "<widget name='mcFontPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='mcFontClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMixedCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='mcMidiGainText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='mcMidiGainSlider' " "type='Slider' " -"/> " +"/>" "<widget name='mcMidiGainLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcFluidSynthSettings' " "width='200' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='auPrefMt32PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefMt32Popup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMt32Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='mcGSCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='SaveButton' " "type='Button' " -"/> " +"/>" "<widget name='SavePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='ThemePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ThemePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='ExtraButton' " "type='Button' " -"/> " +"/>" "<widget name='ExtraPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='PluginsButton' " "type='Button' " -"/> " +"/>" "<widget name='PluginsPath' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='CurTheme' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='RendererPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='RendererPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='AutosavePeriodPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='AutosavePeriodPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='GuiLanguagePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='GuiLanguagePopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeysButton' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Action' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " +"/>" +"<widget name='List'/>" "<widget name='Mapping' " "height='Globals.Line.Height' " -"/> " -"<space size='Globals.Line.Height'/> " -"<layout type='horizontal'> " +"/>" +"<space size='Globals.Line.Height'/>" +"<layout type='horizontal'>" "<widget name='Map' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0' spacing='16'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,4'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions' overlays='Dialog.Launcher.GameList' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0' spacing='16'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='16,16,16,4'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Graphics' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_Graphics' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Audio' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_Audio' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MIDI' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_MIDI' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MT32' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"<import layout='Dialog.GlobalOptions_MT32' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Volume' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<import layout='Dialog.GlobalOptions_Volume' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='16,16,16,16'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Id' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Domain' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Name' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Desc' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LangPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LangPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='PlatformPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='PlatformPopup' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='16,16,16,16'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Savepath' " "type='Button' " -"/> " +"/>" "<widget name='SavepathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Extrapath' " "type='Button' " -"/> " +"/>" "<widget name='ExtrapathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='Gamepath' " "type='Button' " -"/> " +"/>" "<widget name='GamepathText' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='16,16,16,16'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='16,16,16,16'>" "<widget name='customOption1Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption2Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption3Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption4Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption5Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption6Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption7Checkbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalMenu' overlays='screen_center'> " -"<layout type='vertical' padding='16,16,16,16' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalMenu' overlays='screen_center'>" +"<layout type='vertical' padding='16,16,16,16' center='true'>" "<widget name='Title' " "width='210' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Version' " "width='210' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Resume' " "width='150' " "height='Globals.Button.Height' " -"/> " -"<space size='10'/> " +"/>" +"<space size='10'/>" "<widget name='Load' " "width='150' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Save' " "width='150' " "height='Globals.Button.Height' " -"/> " -"<space size='10'/> " +"/>" +"<space size='10'/>" "<widget name='Options' " "width='150' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Help' " "width='150' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='About' " "width='150' " "height='Globals.Button.Height' " -"/> " -"<space size='10'/> " +"/>" +"<space size='10'/>" "<widget name='RTL' " "width='150' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Quit' " "width='150' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalConfig' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0'> " -"<layout type='vertical' padding='0,0,0,0' center='true'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalConfig' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0'>" +"<layout type='vertical' padding='0,0,0,0' center='true'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"<layout type='vertical' padding='24,24,24,24' center='true'> " +"/>" +"</layout>" +"</layout>" +"<layout type='vertical' padding='24,24,24,24' center='true'>" "<widget name='vcMuteCheckbox' " "type='Checkbox' " "width='80' " -"/> " -"</layout> " -"</layout> " -"<space size='8' /> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"</layout>" +"<space size='8' />" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " "width='100' " -"/> " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " "width='100' " -"/> " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " "width='100' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<space size='60'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10'> " +"/>" +"</layout>" +"<space size='60'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10'>" "<widget name='Keys' " "type='Button' " -"/> " -"<space size='Globals.Button.Width' /> " +"/>" +"<space size='Globals.Button.Width' />" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='16,16,16,16'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='16,16,16,16'>" +"<space/>" "<widget name='ResetSettings' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='VoiceCountText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='VoiceCountSlider' " "type='Slider' " -"/> " +"/>" "<widget name='VoiceCountLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='SpeedText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='SpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='SpeedLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DepthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DepthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DepthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WaveFormTypeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WaveFormType' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='RoomSizeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='RoomSizeSlider' " "type='Slider' " -"/> " +"/>" "<widget name='RoomSizeLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DampingText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DampingSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DampingLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WidthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WidthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='WidthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='InterpolationText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Interpolation' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,32' center='true'> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,32' center='true'>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Title' " "height='Globals.Line.Height' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='PageDisplay' " "width='200' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,16' spacing='16'> " -"<widget name='List' /> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,16' spacing='16'>" +"<widget name='List' />" "<widget name='Thumbnail' " "width='180' " "height='200' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='ListSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " +"/>" "<widget name='GridSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Delete' " "type='Button' " -"/> " -"<space size='32'/> " +"/>" +"<space size='32'/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SavenameDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SavenameDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='DescriptionText' " "width='320' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description' " "height='19' " -"/> " -"<layout type='horizontal' padding='0,0,16,0'> " +"/>" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='Cancel' " "type='Button' " -"/> " -"<space size='96'/> " +"/>" +"<space size='96'/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,32' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,32' center='true'>" "<widget name='Title' " "height='Globals.Line.Height' " -"/> " -"<layout type='horizontal' padding='0,0,0,16' spacing='16'> " -"<widget name='List' /> " -"<layout type='vertical' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,16' spacing='16'>" +"<widget name='List' />" +"<layout type='vertical' padding='0,0,0,0'>" "<widget name='Thumbnail' " "width='180' " "height='170' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='NextScreenShotButton' " "width='25' " "height='25' " -"/> " +"/>" "<widget name='currentScreenshot' " "width='125' " "height='25' " "textalign='center' " -"/> " +"/>" "<widget name='PreviousScreenShotButton' " "width='25' " "height='25' " -"/> " -"</layout> " -"<widget name='Author' height='Globals.Line.Height' /> " -"<widget name='Notes' height='Globals.Line.Height' /> " -"</layout> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"</layout>" +"<widget name='Author' height='Globals.Line.Height' />" +"<widget name='Notes' height='Globals.Line.Height' />" +"</layout>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Delete' " "type='Button' " -"/> " -"<space size='16'/> " +"/>" +"<space size='16'/>" "<widget name='Cancel' " "type='Button' " -"/> " -"<space size='16'/> " +"/>" +"<space size='16'/>" "<widget name='Edit' " "type='Button' " -"/> " +"/>" "<widget name='Record' " "type='Button' " -"/> " +"/>" "<widget name='Playback' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='OnScreenDialog' overlays='screen_center'> " -"<layout type='horizontal' spacing='5' padding='5,3,5,3' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='OnScreenDialog' overlays='screen_center'>" +"<layout type='horizontal' spacing='5' padding='5,3,5,3' center='true'>" "<widget name='StopButton' " "width='32' " "height='32' " -"/> " +"/>" "<widget name='EditButton' " "width='32' " "height='32' " -"/> " +"/>" "<widget name='SwitchModeButton' " "width='32' " "height='32' " -"/> " +"/>" "<widget name='FastReplayButton' " "width='32' " "height='32' " -"/> " +"/>" "<widget name='TimeLabel' " "width='50' " "height='30' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='EditRecordDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='EditRecordDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Title' " "width='320' " "height='Globals.Line.Height' " -"/> " -"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"/>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" "<widget name='AuthorLabel' " "type='EditRecordLabel' " -"/> " +"/>" "<widget name='AuthorEdit' " "type='EditRecord' " -"/> " -"</layout> " -"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" "<widget name='NameLabel' " "type='EditRecordLabel' " -"/> " +"/>" "<widget name='NameEdit' " "type='EditRecord' " -"/> " -"</layout> " -"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" "<widget name='NotesLabel' " "type='EditRecordLabel' " -"/> " +"/>" "<widget name='NotesEdit' " "type='EditRecord' " -"/> " -"</layout> " -"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='OK' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='ScummHelp' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='ScummHelp' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Title' " "width='320' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='HelpText' " "height='200' " -"/> " -"<layout type='horizontal' padding='0,0,16,0'> " +"/>" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='Prev' " "type='Button' " -"/> " +"/>" "<widget name='Next' " "type='Button' " -"/> " -"<space size='32'/> " +"/>" +"<space size='32'/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Description1' " "width='320' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description2' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Standard' " "type='Button' " -"/> " +"/>" "<widget name='Practice' " "type='Button' " -"/> " +"/>" "<widget name='Expert' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='MassAdd' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,32,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='MassAdd' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='8,8,32,8' center='true'>" "<widget name='DirProgressText' " "width='480' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameProgressText' " "width='480' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameList' " "width='480' " "height='250' " -"/> " -"<layout type='horizontal' padding='8,8,8,8'> " +"/>" +"<layout type='horizontal' padding='8,8,8,8'>" "<widget name='Ok' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='KeyMapper' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='KeyMapper' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='8,8,32,8' spacing='10' center='true'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Popup' " "type='PopUp' " "width='400' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeymapArea' " "width='600' " "height='280' " -"/> " +"/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='Predictive' overlays='screen_center'> " -"<layout type='vertical' padding='5,5,5,5' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='Predictive' overlays='screen_center'>" +"<layout type='vertical' padding='5,5,5,5' center='true'>" "<widget name='Headline' " "height='Globals.Line.Height' " "width='210' " "textalign='center' " -"/> " -"<layout type='horizontal' padding='5,5,5,5'> " +"/>" +"<layout type='horizontal' padding='5,5,5,5'>" "<widget name='Word' " "width='190' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Delete' " "width='20' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"<space size='5' /> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<space size='5' />" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button1' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Button2' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Button3' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button4' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Button5' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Button6' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button7' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Button8' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Button9' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Pre' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Button0' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Next' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"<space size='5' /> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<space size='5' />" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Add' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " -"<space size='22'/> " +"/>" +"<space size='22'/>" "<widget name='Cancel' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='OK' " "width='Globals.Predictive.Button.Width' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"</layout_info> " -"<layout_info resolution='y<400'> " -"<globals> " -"<def var='Line.Height' value='12' /> " -"<def var='Font.Height' value='10' /> " -"<def var='About.OuterBorder' value='10'/> " -"<def var='Layout.Spacing' value='8'/> " -"<def var='ShowLauncherLogo' value='0'/> " -"<def var='ShowGlobalMenuLogo' value='0'/> " -"<def var='ShowSearchPic' value='0'/> " -"<def var='ShowChooserPics' value='0'/> " -"<def var='ShowChooserPageDisplay' value='0'/> " -"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/> " -"<def var='RecorderDialog.ExtInfo.Visible' value='0'/> " -"<def var='OnScreenDialog.ShowPics' value='0'/> " -"<def var='KeyMapper.Spacing' value='5'/> " -"<def var='KeyMapper.LabelWidth' value='80'/> " -"<def var='KeyMapper.ButtonWidth' value='60'/> " -"<def var='Tooltip.MaxWidth' value='70'/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"</layout_info>" +"<layout_info resolution='y<400'>" +"<globals>" +"<def var='Line.Height' value='12' />" +"<def var='Font.Height' value='10' />" +"<def var='About.OuterBorder' value='10'/>" +"<def var='Layout.Spacing' value='8'/>" +"<def var='ShowLauncherLogo' value='0'/>" +"<def var='ShowGlobalMenuLogo' value='0'/>" +"<def var='ShowSearchPic' value='0'/>" +"<def var='ShowChooserPics' value='0'/>" +"<def var='ShowChooserPageDisplay' value='0'/>" +"<def var='SaveLoadChooser.ExtInfo.Visible' value='0'/>" +"<def var='RecorderDialog.ExtInfo.Visible' value='0'/>" +"<def var='OnScreenDialog.ShowPics' value='0'/>" +"<def var='KeyMapper.Spacing' value='5'/>" +"<def var='KeyMapper.LabelWidth' value='80'/>" +"<def var='KeyMapper.ButtonWidth' value='60'/>" +"<def var='Tooltip.MaxWidth' value='70'/>" "<def var='Tooltip.XDelta' value='8'/> " -"<def var='Tooltip.YDelta' value='8'/> " -"<def var='Predictive.Button.Width' value='45' /> " -"<def var='Predictive.Button.Height' value='15' /> " +"<def var='Tooltip.YDelta' value='8'/>" +"<def var='Predictive.Button.Width' value='45' />" +"<def var='Predictive.Button.Height' value='15' />" "<widget name='Button' " "size='72,16' " -"/> " +"/>" "<widget name='Slider' " "size='85,12' " -"/> " +"/>" "<widget name='OptionsLabel' " "size='110,Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='SmallLabel' " "size='18,Globals.Line.Height' " -"/> " +"/>" "<widget name='PopUp' " "size='-1,15' " -"/> " +"/>" "<widget name='Checkbox' " "size='-1,Globals.Line.Height' " -"/> " +"/>" "<widget name='Radiobutton' " "size='-1,Globals.Line.Height' " -"/> " +"/>" "<widget name='ListWidget' " "padding='5,0,0,0' " -"/> " +"/>" "<widget name='PopUpWidget' " "padding='7,5,0,0' " -"/> " +"/>" "<widget name='EditTextWidget' " "padding='5,5,0,0' " -"/> " +"/>" "<widget name='Console' " "padding='7,5,5,5' " -"/> " +"/>" "<widget name='Scrollbar' " "size='9,0' " -"/> " +"/>" "<widget name='TabWidget.Tab' " "size='45,16' " "padding='0,0,2,0' " -"/> " +"/>" "<widget name='TabWidget.Body' " "padding='0,0,0,-8' " -"/> " +"/>" "<widget name='TabWidget.NavButton' " "size='32,18' " "padding='0,0,1,0' " -"/> " +"/>" "<widget name='EditRecordLabel' " "size='60,Globals.Line.Height' " -"/> " +"/>" "<widget name='EditRecord' " "size='120,15' " -"/> " -"</globals> " -"<dialog name='Launcher' overlays='screen'> " -"<layout type='vertical' center='true' padding='6,6,2,2'> " +"/>" +"</globals>" +"<dialog name='Launcher' overlays='screen'>" +"<layout type='vertical' center='true' padding='6,6,2,2'>" "<widget name='Version' " "height='Globals.Line.Height' " "textalign='center' " -"/> " -"<layout type='horizontal' spacing='5' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' spacing='5' padding='0,0,0,0'>" "<widget name='SearchDesc' " "width='50' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='Search' " "width='150' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SearchClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space /> " -"</layout> " -"<widget name='GameList'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"<space />" +"</layout>" +"<widget name='GameList'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='LoadGameButton' " "height='12' " -"/> " +"/>" "<widget name='AddGameButton' " "height='12' " -"/> " +"/>" "<widget name='EditGameButton' " "height='12' " -"/> " +"/>" "<widget name='RemoveGameButton' " "height='12' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='8'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='8'>" "<widget name='QuitButton' " "height='12' " -"/> " +"/>" "<widget name='AboutButton' " "height='12' " -"/> " +"/>" "<widget name='OptionsButton' " "height='12' " -"/> " +"/>" "<widget name='StartButton' " "height='12' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='Browser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,0,4'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='Browser' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,0,4'>" "<widget name='Headline' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Path' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " -"<layout type='vertical' padding='0,0,8,0'> " +"/>" +"<widget name='List'/>" +"<layout type='vertical' padding='0,0,8,0'>" "<widget name='Hidden' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Up' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions' overlays='screen' inset='16' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='8,8,8,8'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='grModePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grModePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='grRenderPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='grRenderPopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='grAspectCheckbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='grFullscreenCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auMidiPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auMidiPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auOPLPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auOPLPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auSampleRatePopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auSampleRatePopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='3' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='3' center='true'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " -"/> " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " -"<space size='110' /> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" +"<space size='110' />" "<widget name='vcMuteCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='6'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='6'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auPrefGmPopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefGmPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='mcFontButton' " "type='Button' " -"/> " +"/>" "<widget name='mcFontPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='mcFontClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMixedCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='mcMidiGainText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='mcMidiGainSlider' " "type='Slider' " -"/> " +"/>" "<widget name='mcMidiGainLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcFluidSynthSettings' " "width='150' " "height='Globals.Button.Height' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='auPrefMt32PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='auPrefMt32Popup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='mcMt32Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='mcGSCheckbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Paths' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='SaveButton' " "type='Button' " -"/> " +"/>" "<widget name='SavePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='ThemePath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ThemePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='ExtraButton' " "type='Button' " -"/> " +"/>" "<widget name='ExtraPath' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='PluginsButton' " "type='Button' " -"/> " +"/>" "<widget name='PluginsPath' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='16,16,16,16' spacing='8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GlobalOptions_Misc' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='16,16,16,16' spacing='8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16'>" "<widget name='ThemeButton' " "type='Button' " -"/> " +"/>" "<widget name='CurTheme' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='RendererPopupDesc' " "width='80' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='RendererPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='AutosavePeriodPopupDesc' " "width='80' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='AutosavePeriodPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='GuiLanguagePopupDesc' " "width='80' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='GuiLanguagePopup' " "type='PopUp' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeysButton' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='KeysDialog' overlays='Dialog.GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Action' " "height='Globals.Line.Height' " -"/> " -"<widget name='List'/> " +"/>" +"<widget name='List'/>" "<widget name='Mapping' " "height='Globals.Line.Height' " -"/> " -"<space size='Globals.Line.Height'/> " -"<layout type='horizontal'> " +"/>" +"<space size='Globals.Line.Height'/>" +"<layout type='horizontal'>" "<widget name='Map' " "type='Button' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0' spacing='16'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions' overlays='screen' inset='16' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0' spacing='16'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='8,8,8,8'>" +"<space/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Graphics' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Graphics' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_Graphics' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Audio' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Audio' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_Audio' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MIDI' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MIDI' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_MIDI' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_MT32' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_MT32' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"<import layout='Dialog.GlobalOptions_MT32' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Volume' overlays='Dialog.GlobalOptions.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<import layout='Dialog.GlobalOptions_Volume' /> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"<import layout='Dialog.GlobalOptions_Volume' />" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Game' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='Id' " "width='35' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='Domain' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='Name' " "width='35' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='Desc' " "type='PopUp' " -"/> " -"</layout> " -"<space size='8'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<space size='8'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='LangPopupDesc' " "width='60' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='LangPopup' " "type='PopUp' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='PlatformPopupDesc' " "width='60' " "height='Globals.Line.Height' " "textalign='right' " -"/> " +"/>" "<widget name='PlatformPopup' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Paths' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='Savepath' " "type='Button' " -"/> " +"/>" "<widget name='SavepathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='SavePathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='Extrapath' " "type='Button' " -"/> " +"/>" "<widget name='ExtrapathText' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='ExtraPathClearButton' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='16' center='true'>" "<widget name='Gamepath' " "type='Button' " -"/> " +"/>" "<widget name='GamepathText' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='GameOptions_Engine' overlays='Dialog.GameOptions.TabWidget' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='customOption1Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption2Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption3Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption4Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption5Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption6Checkbox' " "type='Checkbox' " -"/> " +"/>" "<widget name='customOption7Checkbox' " "type='Checkbox' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalMenu' overlays='screen_center'> " -"<layout type='vertical' padding='2,2,4,6' center='true' spacing='6'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalMenu' overlays='screen_center'>" +"<layout type='vertical' padding='2,2,4,6' center='true' spacing='6'>" "<widget name='Title' " "width='160' " "height='4' " -"/> " +"/>" "<widget name='Version' " "width='160' " "height='4' " -"/> " -"<space size='1'/> " +"/>" +"<space size='1'/>" "<widget name='Load' " "width='120' " "height='12' " -"/> " +"/>" "<widget name='Save' " "width='120' " "height='12' " -"/> " -"<space size='1'/> " +"/>" +"<space size='1'/>" "<widget name='Options' " "width='120' " "height='12' " -"/> " +"/>" "<widget name='Help' " "width='120' " "height='12' " -"/> " +"/>" "<widget name='About' " "width='120' " "height='12' " -"/> " -"<space size='1'/> " +"/>" +"<space size='1'/>" "<widget name='Resume' " "width='120' " "height='12' " -"/> " +"/>" "<widget name='RTL' " "width='120' " "height='12' " -"/> " +"/>" "<widget name='Quit' " "width='120' " "height='12' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='GlobalConfig' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='GlobalConfig' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcMusicText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcMusicSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcMusicLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSfxText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSfxSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSfxLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='vcSpeechText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='vcSpeechSlider' " "type='Slider' " -"/> " +"/>" "<widget name='vcSpeechLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " -"<space size='110' /> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" +"<space size='110' />" "<widget name='vcMuteCheckbox' " "type='Checkbox' " "width='80' " -"/> " -"</layout> " -"<layout type='vertical' padding='0,0,0,0' spacing='1' center='true'> " +"/>" +"</layout>" +"<layout type='vertical' padding='0,0,0,0' spacing='1' center='true'>" "<widget name='subToggleDesc' " "type='OptionsLabel' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='subToggleSpeechOnly' " "type='Radiobutton' " "width='90' " -"/> " +"/>" "<widget name='subToggleSubOnly' " "type='Radiobutton' " "width='90' " -"/> " +"/>" "<widget name='subToggleSubBoth' " "type='Radiobutton' " "width='90' " -"/> " -"</layout> " -"</layout> " -"<space size='2' /> " -"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'> " +"/>" +"</layout>" +"</layout>" +"<space size='2' />" +"<layout type='horizontal' padding='0,0,0,0' spacing='6' center='true'>" "<widget name='subSubtitleSpeedDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='subSubtitleSpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='subSubtitleSpeedLabel' " "type='SmallLabel' " -"/> " -"</layout> " -"<space size='16'/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='4'> " +"/>" +"</layout>" +"<space size='16'/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='4'>" "<widget name='Keys' " "type='Button' " -"/> " -"<space size='Globals.Button.Width' /> " +"/>" +"<space size='Globals.Button.Width' />" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'> " -"<layout type='vertical' padding='0,0,0,0'> " -"<widget name='TabWidget'/> " -"<layout type='horizontal' padding='8,8,8,8'> " -"<space/> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings' overlays='GlobalOptions' shading='dim'>" +"<layout type='vertical' padding='0,0,0,0'>" +"<widget name='TabWidget'/>" +"<layout type='horizontal' padding='8,8,8,8'>" +"<space/>" "<widget name='ResetSettings' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Chorus' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='VoiceCountText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='VoiceCountSlider' " "type='Slider' " -"/> " +"/>" "<widget name='VoiceCountLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='SpeedText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='SpeedSlider' " "type='Slider' " -"/> " +"/>" "<widget name='SpeedLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DepthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DepthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DepthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WaveFormTypeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WaveFormType' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Reverb' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" "<widget name='EnableTabCheckbox' " "type='Checkbox' " -"/> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='RoomSizeText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='RoomSizeSlider' " "type='Slider' " -"/> " +"/>" "<widget name='RoomSizeLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='DampingText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='DampingSlider' " "type='Slider' " -"/> " +"/>" "<widget name='DampingLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='WidthText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='WidthSlider' " "type='Slider' " -"/> " +"/>" "<widget name='WidthLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='LevelText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='LevelSlider' " "type='Slider' " -"/> " +"/>" "<widget name='LevelLabel' " "width='32' " "height='Globals.Line.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'> " -"<layout type='vertical' padding='8,8,8,8' spacing='6'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='FluidSynthSettings_Misc' overlays='Dialog.FluidSynthSettings.TabWidget'>" +"<layout type='vertical' padding='8,8,8,8' spacing='6'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='InterpolationText' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Interpolation' " "type='PopUp' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " -"<widget name='Title' height='Globals.Line.Height'/> " -"<widget name='List' /> " -"<layout type='horizontal' padding='0,0,16,0'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SaveLoadChooser' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" +"<widget name='Title' height='Globals.Line.Height'/>" +"<widget name='List' />" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='ListSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " +"/>" "<widget name='GridSwitch' " "height='Globals.Line.Height' " "width='Globals.Line.Height' " -"/> " -"<space/> " +"/>" +"<space/>" "<widget name='Delete' " "type='Button' " -"/> " -"<space size='16'/> " +"/>" +"<space size='16'/>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Choose' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='SavenameDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='SavenameDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='DescriptionText' " "width='180' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description' " "height='19' " -"/> " -"<layout type='horizontal' padding='0,0,16,0'> " +"/>" +"<layout type='horizontal' padding='0,0,16,0'>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Ok' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'> " -"<layout type='vertical' padding='8,8,8,4' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='RecorderDialog' overlays='screen' inset='8' shading='dim'>" +"<layout type='vertical' padding='8,8,8,4' center='true'>" "<widget name='Title' " "height='Globals.Line.Height' " -"/> " -"<widget name='List' /> " -"<layout type='horizontal' padding='0,0,0,0' spacing='2'> " +"/>" +"<widget name='List' />" +"<layout type='horizontal' padding='0,0,0,0' spacing='2'>" "<widget name='Edit' " "type='Button' " -"/> " -"<space /> " +"/>" +"<space />" "<widget name='Record' " "type='Button' " -"/> " -"</layout> " -"<layout type='horizontal' padding='0,0,0,0' spacing='2'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='0,0,0,0' spacing='2'>" "<widget name='Delete' " "type='Button' " -"/> " -"<space /> " +"/>" +"<space />" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='Playback' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='OnScreenDialog' overlays='screen_center'> " -"<layout type='horizontal' spacing='5' padding='3,2,3,2' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='OnScreenDialog' overlays='screen_center'>" +"<layout type='horizontal' spacing='5' padding='3,2,3,2' center='true'>" "<widget name='StopButton' " "width='16' " "height='16' " -"/> " +"/>" "<widget name='EditButton' " "width='16' " "height='16' " -"/> " +"/>" "<widget name='SwitchModeButton' " "width='16' " "height='16' " -"/> " +"/>" "<widget name='FastReplayButton' " "width='16' " "height='16' " -"/> " +"/>" "<widget name='TimeLabel' " "width='50' " "height='16' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='EditRecordDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='EditRecordDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Title' " "height='Globals.Line.Height' " -"/> " -"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"/>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" "<widget name='AuthorLabel' " "type='EditRecordLabel' " -"/> " +"/>" "<widget name='AuthorEdit' " "type='EditRecord' " -"/> " -"</layout> " -"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" "<widget name='NameLabel' " "type='EditRecordLabel' " -"/> " +"/>" "<widget name='NameEdit' " "type='EditRecord' " -"/> " -"</layout> " -"<layout type='horizontal' spacing='5' padding='0,0,0,10'> " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,10'>" "<widget name='NotesLabel' " "type='EditRecordLabel' " -"/> " +"/>" "<widget name='NotesEdit' " "type='EditRecord' " -"/> " -"</layout> " -"<layout type='horizontal' spacing='5' padding='0,0,0,0'> " +"/>" +"</layout>" +"<layout type='horizontal' spacing='5' padding='0,0,0,0'>" "<widget name='Cancel' " "type='Button' " -"/> " +"/>" "<widget name='OK' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='ScummHelp' overlays='screen'> " -"<layout type='vertical' padding='8,8,8,8'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='ScummHelp' overlays='screen'>" +"<layout type='vertical' padding='8,8,8,8'>" "<widget name='Title' " "width='180' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='HelpText' " "height='140' " -"/> " -"<layout type='horizontal' padding='0,0,0,0'> " +"/>" +"<layout type='horizontal' padding='0,0,0,0'>" "<widget name='Prev' " "type='Button' " -"/> " +"/>" "<widget name='Next' " "type='Button' " -"/> " -"<space size='32'/> " +"/>" +"<space size='32'/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'> " -"<layout type='vertical' padding='8,8,8,8' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='LoomTownsDifficultyDialog' overlays='screen_center'>" +"<layout type='vertical' padding='8,8,8,8' center='true'>" "<widget name='Description1' " "width='280' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Description2' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='Standard' " "type='Button' " -"/> " +"/>" "<widget name='Practice' " "type='Button' " -"/> " +"/>" "<widget name='Expert' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='MassAdd' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='4,4,16,4' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='MassAdd' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='4,4,16,4' center='true'>" "<widget name='DirProgressText' " "width='280' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameProgressText' " "width='280' " "height='Globals.Line.Height' " -"/> " +"/>" "<widget name='GameList' " "width='280' " "height='100' " -"/> " -"<layout type='horizontal' padding='4,4,4,4'> " +"/>" +"<layout type='horizontal' padding='4,4,4,4'>" "<widget name='Ok' " "type='Button' " -"/> " +"/>" "<widget name='Cancel' " "type='Button' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"<dialog name='KeyMapper' overlays='screen_center' shading='dim'> " -"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'> " -"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"<dialog name='KeyMapper' overlays='screen_center' shading='dim'>" +"<layout type='vertical' padding='8,8,8,8' spacing='10' center='true'>" +"<layout type='horizontal' padding='0,0,0,0' spacing='10' center='true'>" "<widget name='PopupDesc' " "type='OptionsLabel' " -"/> " +"/>" "<widget name='Popup' " "type='PopUp' " "width='150' " "height='Globals.Line.Height' " -"/> " -"</layout> " +"/>" +"</layout>" "<widget name='KeymapArea' " "width='300' " "height='120' " -"/> " +"/>" "<widget name='Close' " "type='Button' " -"/> " -"</layout> " -"</dialog> " -"<dialog name='Predictive' overlays='screen_center'> " -"<layout type='vertical' padding='1,1,1,1' center='true'> " +"/>" +"</layout>" +"</dialog>" +"<dialog name='Predictive' overlays='screen_center'>" +"<layout type='vertical' padding='1,1,1,1' center='true'>" "<widget name='Headline' " "height='Globals.Line.Height' " "width='150' " "textalign='center' " -"/> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Word' " "width='120' " "height='Globals.Button.Height' " -"/> " +"/>" "<widget name='Delete' " "width='20' " "height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button1' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Button2' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Button3' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button4' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Button5' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Button6' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,3'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,3'>" "<widget name='Button7' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Button8' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Button9' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<layout type='horizontal' padding='3,3,3,0'> " +"/>" +"</layout>" +"<layout type='horizontal' padding='3,3,3,0'>" "<widget name='Pre' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Button0' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Next' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"<space size='3' /> " -"<layout type='horizontal' padding='3,3,0,3'> " +"/>" +"</layout>" +"<space size='3' />" +"<layout type='horizontal' padding='3,3,0,3'>" "<widget name='Add' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='Cancel' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " +"/>" "<widget name='OK' " "width='Globals.Predictive.Button.Width' " "height='Globals.Predictive.Button.Height' " -"/> " -"</layout> " -"</layout> " -"</dialog> " -"</layout_info> " +"/>" +"</layout>" +"</layout>" +"</dialog>" +"</layout_info>" diff --git a/gui/themes/scummclassic.zip b/gui/themes/scummclassic.zip Binary files differindex 4154c6c33a..1085aa64a4 100644 --- a/gui/themes/scummclassic.zip +++ b/gui/themes/scummclassic.zip diff --git a/gui/themes/scummmodern.zip b/gui/themes/scummmodern.zip Binary files differindex 0f10003e94..e40e8b1e26 100644 --- a/gui/themes/scummmodern.zip +++ b/gui/themes/scummmodern.zip diff --git a/gui/themes/scummmodern/scummmodern_gfx.stx b/gui/themes/scummmodern/scummmodern_gfx.stx index 1b3bcea0d6..3a1ec5a5f0 100644 --- a/gui/themes/scummmodern/scummmodern_gfx.stx +++ b/gui/themes/scummmodern/scummmodern_gfx.stx @@ -38,6 +38,14 @@ rgb = '203, 126, 107' /> + <color name = 'brightredborder' + rgb = '238, 213, 207' + /> + + <color name = 'darkredborder' + rgb = '30, 7, 1' + /> + <!-- Disabled button/slider --> <color name = 'darkeneddarkred' rgb = '120, 28, 0' @@ -73,7 +81,7 @@ rgb = '255, 255, 255' /> <color name = 'shadowcolor' - rgb = '63, 60, 17' + rgb = '105, 101, 86' /> <color name = 'darkgray' rgb = '176, 168, 144' @@ -170,6 +178,10 @@ color = '128, 128, 128' /> + <text_color id = 'color_button_hover' + color = 'white' + /> + <text_color id = 'color_alternative_inverted' color = 'white' /> @@ -186,10 +198,6 @@ color = 'white' /> - <text_color id = 'color_button_hover' - color = '255, 214, 84' - /> - <text_color id = 'color_button_disabled' color = '192, 192, 192' /> @@ -232,7 +240,7 @@ stroke = '0' gradient_start = 'darkorange' gradient_end = 'brightorange' - shadow = '3' + shadow = '7' gradient_factor = '3' /> </drawdata> @@ -466,7 +474,7 @@ fg_color = 'lightgray2' fill = 'background' bg_color = 'xtrabrightred' - shadow = '2' + shadow = '1' /> <drawstep func = 'triangle' @@ -505,7 +513,7 @@ fg_color = 'lightgray2' fill = 'background' bg_color = 'xtrabrightred' - shadow = '2' + shadow = '1' /> <drawstep func = 'triangle' @@ -663,7 +671,7 @@ fg_color = 'lightgray2' fill = 'background' bg_color = 'xtrabrightred' - shadow = '2' + shadow = '1' /> <drawstep func = 'triangle' @@ -716,7 +724,7 @@ gradient_start = 'blandyellow' gradient_end = 'xtrabrightred' fill = 'gradient' - shadow = '3' + shadow = '7' /> </drawdata> @@ -737,7 +745,7 @@ gradient_start = 'blandyellow' gradient_end = 'xtrabrightred' gradient_factor = '4' - shadow = '3' + shadow = '7' /> </drawdata> @@ -783,18 +791,18 @@ stroke = '1' fill = 'gradient' shadow = '0' - fg_color = 'shadowcolor' + fg_color = 'darkredborder' gradient_start = 'brightred' gradient_end = 'darkred' bevel = '1' - bevel_color = '237, 169, 72' + bevel_color = 'brightredborder' /> </drawdata> <!-- Hovered button --> <drawdata id = 'button_hover' cache = 'false'> <text font = 'text_button' - text_color = 'color_button_hover' + text_color = 'color_button' vertical_align = 'center' horizontal_align = 'center' /> @@ -803,11 +811,11 @@ stroke = '1' fill = 'gradient' shadow = '0' - fg_color = 'shadowcolor' + fg_color = 'darkredborder' gradient_start = 'brightpink' gradient_end = 'darkpink' bevel = '1' - bevel_color = 'xtrabrightred' + bevel_color = 'brightredborder' /> </drawdata> @@ -915,7 +923,7 @@ gradient_factor = '6' fill = 'gradient' bg_color = 'xtrabrightred' - shadow = '3' + shadow = '7' /> </drawdata> diff --git a/gui/themes/scummtheme.py b/gui/themes/scummtheme.py index 4c55fd79de..524e91468e 100755 --- a/gui/themes/scummtheme.py +++ b/gui/themes/scummtheme.py @@ -37,9 +37,13 @@ def parseSTX(theme_file, def_file): comm = re.compile("<!--(.*?)-->", re.DOTALL) head = re.compile("<\?(.*?)\?>") + strlitcount = 0 output = "" for line in theme_file: - output += line.rstrip("\r\n\t ").lstrip() + " \n" + output += line.rstrip("\r\n\t ").lstrip() + if not output.endswith('>'): + output += ' ' + output += "\n" output = re.sub(comm, "", output) output = re.sub(head, "", output) @@ -48,7 +52,9 @@ def parseSTX(theme_file, def_file): for line in output.splitlines(): if line and not line.isspace(): + strlitcount += len(line) def_file.write("\"" + line + "\"\n") + return strlitcount def buildDefTheme(themeName): def_file = open("default.inc", "w") @@ -57,16 +63,23 @@ def buildDefTheme(themeName): print ("Cannot open default theme dir.") def_file.write(""" "<?xml version = '1.0'?>"\n""") + strlitcount = 24 for filename in os.listdir(themeName): filename = os.path.join(themeName, filename) if os.path.isfile(filename) and filename.endswith(".stx"): theme_file = open(filename, "r") - parseSTX(theme_file, def_file) + strlitcount += parseSTX(theme_file, def_file) theme_file.close() def_file.close() + if strlitcount > 65535: + print("WARNING: default.inc string literal is of length %d which exceeds the" % strlitcount) + print(" maximum length of 65536 that C++ compilers are required to support.") + print(" It is likely that bugs will occur dependent on compiler behaviour.") + print(" To avoid this, reduce the size of the theme.") + def printUsage(): print ("===============================") print ("ScummVM Theme Generation Script") diff --git a/gui/widgets/editable.cpp b/gui/widgets/editable.cpp index 6fae9346b2..667850d6cc 100644 --- a/gui/widgets/editable.cpp +++ b/gui/widgets/editable.cpp @@ -277,7 +277,7 @@ void EditableWidget::drawCaret(bool erase) { int chrWidth = g_gui.getCharWidth(_editString[_caretPos], _font); const uint last = (_caretPos > 0) ? _editString[_caretPos - 1] : 0; x += g_gui.getKerningOffset(last, _editString[_caretPos], _font); - g_gui.theme()->drawText(Common::Rect(x, y, x + chrWidth, y + editRect.height() - 2), chr, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font); + g_gui.theme()->drawText(Common::Rect(x, y, x + chrWidth, y + editRect.height() - 2), chr, _state, Graphics::kTextAlignLeft, _inversion, 0, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea); } } diff --git a/gui/widgets/edittext.cpp b/gui/widgets/edittext.cpp index 3677f02e47..52527effd8 100644 --- a/gui/widgets/edittext.cpp +++ b/gui/widgets/edittext.cpp @@ -93,11 +93,15 @@ void EditTextWidget::drawWidget() { // Draw the text adjustOffset(); - g_gui.theme()->drawText(Common::Rect(_x+2+ _leftPadding,_y+2, _x+_leftPadding+getEditRect().width()+2, _y+_h-2), _editString, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, -_editScrollOffset, false, _font); + + const Common::Rect &r = Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 8, _y + _h); + setTextDrawableArea(r); + + g_gui.theme()->drawText(Common::Rect(_x + 2 + _leftPadding, _y + 2, _x + _leftPadding + getEditRect().width() + 2, _y + _h), _editString, _state, Graphics::kTextAlignLeft, ThemeEngine::kTextInversionNone, -_editScrollOffset, false, _font, ThemeEngine::kFontColorNormal, true, _textDrawableArea); } Common::Rect EditTextWidget::getEditRect() const { - Common::Rect r(2 + _leftPadding, 2, _w - 2 - _leftPadding - _rightPadding, _h-1); + Common::Rect r(2 + _leftPadding, 2, _w - 2 - _leftPadding - _rightPadding, _h - 1); return r; } diff --git a/video/avi_decoder.cpp b/video/avi_decoder.cpp index beb68fc969..aee2d88988 100644 --- a/video/avi_decoder.cpp +++ b/video/avi_decoder.cpp @@ -80,6 +80,13 @@ namespace Video { #define ID_DUCK MKTAG('D','U','C','K') #define ID_MPG2 MKTAG('m','p','g','2') +// Stream Types +enum { + kStreamTypePaletteChange = MKTAG16('p', 'c'), + kStreamTypeRawVideo = MKTAG16('d', 'b'), + kStreamTypeAudio = MKTAG16('w', 'b') +}; + AVIDecoder::AVIDecoder(Audio::Mixer::SoundType soundType) : _frameRateOverride(0), _soundType(soundType) { initCommon(); @@ -106,6 +113,12 @@ void AVIDecoder::initCommon() { memset(&_header, 0, sizeof(_header)); } +bool AVIDecoder::isSeekable() const { + // Only videos with an index can seek + // Anyone else who wants to seek is crazy. + return isVideoLoaded() && !_indexEntries.empty(); +} + bool AVIDecoder::parseNextChunk() { uint32 tag = _fileStream->readUint32BE(); uint32 size = _fileStream->readUint32LE(); @@ -150,10 +163,10 @@ bool AVIDecoder::parseNextChunk() { OldIndex indexEntry; indexEntry.id = _fileStream->readUint32BE(); indexEntry.flags = _fileStream->readUint32LE(); - indexEntry.offset = _fileStream->readUint32LE(); + indexEntry.offset = _fileStream->readUint32LE() + _movieListStart - 4; // Adjust to absolute indexEntry.size = _fileStream->readUint32LE(); _indexEntries.push_back(indexEntry); - debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size); + debug(0, "Index %d == Tag \'%s\', Offset = %d, Size = %d (Flags = %d)", i, tag2str(indexEntry.id), indexEntry.offset, indexEntry.size, indexEntry.flags); } break; default: @@ -187,7 +200,7 @@ void AVIDecoder::handleList(uint32 listSize) { _decodedHeader = true; break; case ID_INFO: // Metadata - case ID_PRMI: // Unknown (ZEngine) + case ID_PRMI: // Unknown metadata, should be safe to ignore // Ignore metadata _fileStream->skip(listSize); return; @@ -254,21 +267,22 @@ void AVIDecoder::handleStreamHeader(uint32 size) { if (sHeader.streamHandler == 0) sHeader.streamHandler = bmInfo.compression; - AVIVideoTrack *track = new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo); + byte *initialPalette = 0; if (bmInfo.bitCount == 8) { - byte *palette = const_cast<byte *>(track->getPalette()); + initialPalette = new byte[256 * 3]; + memset(initialPalette, 0, 256 * 3); + + byte *palette = initialPalette; for (uint32 i = 0; i < bmInfo.clrUsed; i++) { palette[i * 3 + 2] = _fileStream->readByte(); palette[i * 3 + 1] = _fileStream->readByte(); palette[i * 3] = _fileStream->readByte(); _fileStream->readByte(); } - - track->markPaletteDirty(); } - addTrack(track); + addTrack(new AVIVideoTrack(_header.totalFrames, sHeader, bmInfo, initialPalette)); } else if (sHeader.streamType == ID_AUDS) { PCMWaveFormat wvInfo; wvInfo.tag = _fileStream->readUint16LE(); @@ -383,7 +397,7 @@ void AVIDecoder::readNextPacket() { } if (track->getTrackType() == Track::kTrackTypeAudio) { - if (getStreamType(nextTag) != MKTAG16('w', 'b')) + if (getStreamType(nextTag) != kStreamTypeAudio) error("Invalid audio track tag '%s'", tag2str(nextTag)); assert(chunk); @@ -391,29 +405,10 @@ void AVIDecoder::readNextPacket() { } else { AVIVideoTrack *videoTrack = (AVIVideoTrack *)track; - if (getStreamType(nextTag) == MKTAG16('p', 'c')) { + if (getStreamType(nextTag) == kStreamTypePaletteChange) { // Palette Change - assert(chunk); - byte firstEntry = chunk->readByte(); - uint16 numEntries = chunk->readByte(); - chunk->readUint16LE(); // Reserved - - // 0 entries means all colors are going to be changed - if (numEntries == 0) - numEntries = 256; - - byte *palette = const_cast<byte *>(videoTrack->getPalette()); - - for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { - palette[i * 3] = chunk->readByte(); - palette[i * 3 + 1] = chunk->readByte(); - palette[i * 3 + 2] = chunk->readByte(); - chunk->readByte(); // Flags that don't serve us any purpose - } - - delete chunk; - videoTrack->markPaletteDirty(); - } else if (getStreamType(nextTag) == MKTAG16('d', 'b')) { + videoTrack->loadPaletteFromChunk(chunk); + } else if (getStreamType(nextTag) == kStreamTypeRawVideo) { // TODO: Check if this really is uncompressed. Many videos // falsely put compressed data in here. error("Uncompressed AVI frame found"); @@ -424,6 +419,201 @@ void AVIDecoder::readNextPacket() { } } +bool AVIDecoder::rewind() { + if (!VideoDecoder::rewind()) + return false; + + _fileStream->seek(_movieListStart); + return true; +} + +bool AVIDecoder::seekIntern(const Audio::Timestamp &time) { + // Can't seek beyond the end + if (time > getDuration()) + return false; + + // Track down our video track (optionally audio too). + // We only support seeking with one track right now. + AVIVideoTrack *videoTrack = 0; + AVIAudioTrack *audioTrack = 0; + int videoIndex = -1; + int audioIndex = -1; + uint trackID = 0; + + for (TrackListIterator it = getTrackListBegin(); it != getTrackListEnd(); it++, trackID++) { + if ((*it)->getTrackType() == Track::kTrackTypeVideo) { + if (videoTrack) { + // Already have one + // -> Not supported + return false; + } + + videoTrack = (AVIVideoTrack *)*it; + videoIndex = trackID; + } else if ((*it)->getTrackType() == Track::kTrackTypeAudio) { + if (audioTrack) { + // Already have one + // -> Not supported + return false; + } + + audioTrack = (AVIAudioTrack *)*it; + audioIndex = trackID; + } + } + + // Need a video track to go forwards + // If there isn't a video track, why would anyone be using AVI then? + if (!videoTrack) + return false; + + // If we seek directly to the end, just mark the tracks as over + if (time == getDuration()) { + videoTrack->setCurFrame(videoTrack->getFrameCount() - 1); + + if (audioTrack) + audioTrack->resetStream(); + + return true; + } + + // Get the frame we should be on at this time + uint frame = videoTrack->getFrameAtTime(time); + + // Reset any palette, if necessary + videoTrack->useInitialPalette(); + + int lastKeyFrame = -1; + int frameIndex = -1; + int lastRecord = -1; + uint curFrame = 0; + + // Go through and figure out where we should be + // If there's a palette, we need to find the palette too + for (uint32 i = 0; i < _indexEntries.size(); i++) { + const OldIndex &index = _indexEntries[i]; + + if (index.id == ID_REC) { + // Keep track of any records we find + lastRecord = i; + } else { + if (getStreamIndex(index.id) != videoIndex) + continue; + + uint16 streamType = getStreamType(index.id); + + if (streamType == kStreamTypePaletteChange) { + // We need to handle any palette change we see since there's no + // flag to tell if this is a "key" palette. + // Decode the palette + _fileStream->seek(_indexEntries[i].offset + 8); + Common::SeekableReadStream *chunk = 0; + + if (_indexEntries[i].size != 0) + chunk = _fileStream->readStream(_indexEntries[i].size); + + videoTrack->loadPaletteFromChunk(chunk); + } else { + // Check to see if this is a keyframe + // The first frame has to be a keyframe + if ((_indexEntries[i].flags & AVIIF_INDEX) || curFrame == 0) + lastKeyFrame = i; + + // Did we find the target frame? + if (frame == curFrame) { + frameIndex = i; + break; + } + + curFrame++; + } + } + } + + if (frameIndex < 0) // This shouldn't happen. + return false; + + if (audioTrack) { + // We need to find where the start of audio should be. + // Which is exactly 'initialFrames' audio chunks back from where + // our found frame is. + + // Recreate the audio stream + audioTrack->resetStream(); + + uint framesNeeded = _header.initialFrames; + uint startAudioChunk = 0; + int startAudioSearch = (lastRecord < 0) ? (frameIndex - 1) : (lastRecord - 1); + + for (int i = startAudioSearch; i >= 0; i--) { + if (getStreamIndex(_indexEntries[i].id) != audioIndex) + continue; + + assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio); + + framesNeeded--; + + if (framesNeeded == 0) { + startAudioChunk = i; + break; + } + } + + // Now go forward and queue them all + for (int i = startAudioChunk; i <= startAudioSearch; i++) { + if (_indexEntries[i].id == ID_REC) + continue; + + if (getStreamIndex(_indexEntries[i].id) != audioIndex) + continue; + + assert(getStreamType(_indexEntries[i].id) == kStreamTypeAudio); + + _fileStream->seek(_indexEntries[i].offset + 8); + Common::SeekableReadStream *chunk = _fileStream->readStream(_indexEntries[i].size); + audioTrack->queueSound(chunk); + } + + // Skip any audio to bring us to the right time + audioTrack->skipAudio(time, videoTrack->getFrameTime(frame)); + } + + // Decode from keyFrame to curFrame - 1 + for (int i = lastKeyFrame; i < frameIndex; i++) { + if (_indexEntries[i].id == ID_REC) + continue; + + if (getStreamIndex(_indexEntries[i].id) != videoIndex) + continue; + + uint16 streamType = getStreamType(_indexEntries[i].id); + + // Ignore palettes, they were already handled + if (streamType == kStreamTypePaletteChange) + continue; + + // Frame, hopefully + _fileStream->seek(_indexEntries[i].offset + 8); + Common::SeekableReadStream *chunk = 0; + + if (_indexEntries[i].size != 0) + chunk = _fileStream->readStream(_indexEntries[i].size); + + videoTrack->decodeFrame(chunk); + } + + // Seek to the right spot + // To the beginning of the last record, or frame if that doesn't exist + if (lastRecord >= 0) + _fileStream->seek(_indexEntries[lastRecord].offset); + else + _fileStream->seek(_indexEntries[frameIndex].offset); + + videoTrack->setCurFrame((int)frame - 1); + + return true; +} + byte AVIDecoder::getStreamIndex(uint32 tag) const { char string[3]; WRITE_BE_UINT16(string, tag >> 16); @@ -431,17 +621,18 @@ byte AVIDecoder::getStreamIndex(uint32 tag) const { return strtol(string, 0, 16); } -AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader) - : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader) { - memset(_palette, 0, sizeof(_palette)); +AVIDecoder::AVIVideoTrack::AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette) + : _frameCount(frameCount), _vidsHeader(streamHeader), _bmInfo(bitmapInfoHeader), _initialPalette(initialPalette) { _videoCodec = createCodec(); - _dirtyPalette = false; _lastFrame = 0; _curFrame = -1; + + useInitialPalette(); } AVIDecoder::AVIVideoTrack::~AVIVideoTrack() { delete _videoCodec; + delete[] _initialPalette; } void AVIDecoder::AVIVideoTrack::decodeFrame(Common::SeekableReadStream *stream) { @@ -464,6 +655,47 @@ Graphics::PixelFormat AVIDecoder::AVIVideoTrack::getPixelFormat() const { return Graphics::PixelFormat(); } +void AVIDecoder::AVIVideoTrack::loadPaletteFromChunk(Common::SeekableReadStream *chunk) { + assert(chunk); + byte firstEntry = chunk->readByte(); + uint16 numEntries = chunk->readByte(); + chunk->readUint16LE(); // Reserved + + // 0 entries means all colors are going to be changed + if (numEntries == 0) + numEntries = 256; + + for (uint16 i = firstEntry; i < numEntries + firstEntry; i++) { + _palette[i * 3] = chunk->readByte(); + _palette[i * 3 + 1] = chunk->readByte(); + _palette[i * 3 + 2] = chunk->readByte(); + chunk->readByte(); // Flags that don't serve us any purpose + } + + delete chunk; + _dirtyPalette = true; +} + +void AVIDecoder::AVIVideoTrack::useInitialPalette() { + _dirtyPalette = false; + + if (_initialPalette) { + memcpy(_palette, _initialPalette, sizeof(_palette)); + _dirtyPalette = true; + } +} + +bool AVIDecoder::AVIVideoTrack::rewind() { + _curFrame = -1; + + useInitialPalette(); + + delete _videoCodec; + _videoCodec = createCodec(); + _lastFrame = 0; + return true; +} + Codec *AVIDecoder::AVIVideoTrack::createCodec() { switch (_vidsHeader.streamHandler) { case ID_CRAM: @@ -525,6 +757,31 @@ void AVIDecoder::AVIAudioTrack::queueSound(Common::SeekableReadStream *stream) { } } +void AVIDecoder::AVIAudioTrack::skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime) { + Audio::Timestamp timeDiff = time.convertToFramerate(_wvInfo.samplesPerSec) - frameTime.convertToFramerate(_wvInfo.samplesPerSec); + int skipFrames = timeDiff.totalNumberOfFrames(); + + if (skipFrames <= 0) + return; + + if (_audStream->isStereo()) + skipFrames *= 2; + + int16 *tempBuffer = new int16[skipFrames]; + _audStream->readBuffer(tempBuffer, skipFrames); + delete[] tempBuffer; +} + +void AVIDecoder::AVIAudioTrack::resetStream() { + delete _audStream; + _audStream = createAudioStream(); +} + +bool AVIDecoder::AVIAudioTrack::rewind() { + resetStream(); + return true; +} + Audio::AudioStream *AVIDecoder::AVIAudioTrack::getAudioStream() const { return _audStream; } diff --git a/video/avi_decoder.h b/video/avi_decoder.h index f7259bf030..80c11b1e09 100644 --- a/video/avi_decoder.h +++ b/video/avi_decoder.h @@ -66,8 +66,13 @@ public: uint16 getWidth() const { return _header.width; } uint16 getHeight() const { return _header.height; } + bool rewind(); + bool isRewindable() const { return true; } + bool isSeekable() const; + protected: void readNextPacket(); + bool seekIntern(const Audio::Timestamp &time); struct BitmapInfoHeader { uint32 size; @@ -156,7 +161,7 @@ protected: class AVIVideoTrack : public FixedRateVideoTrack { public: - AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader); + AVIVideoTrack(int frameCount, const AVIStreamHeader &streamHeader, const BitmapInfoHeader &bitmapInfoHeader, byte *initialPalette = 0); ~AVIVideoTrack(); void decodeFrame(Common::SeekableReadStream *stream); @@ -169,7 +174,12 @@ protected: const Graphics::Surface *decodeNextFrame() { return _lastFrame; } const byte *getPalette() const { _dirtyPalette = false; return _palette; } bool hasDirtyPalette() const { return _dirtyPalette; } - void markPaletteDirty() { _dirtyPalette = true; } + void setCurFrame(int frame) { _curFrame = frame; } + void loadPaletteFromChunk(Common::SeekableReadStream *chunk); + void useInitialPalette(); + + bool isRewindable() const { return true; } + bool rewind(); protected: Common::Rational getFrameRate() const { return Common::Rational(_vidsHeader.rate, _vidsHeader.scale); } @@ -178,6 +188,7 @@ protected: AVIStreamHeader _vidsHeader; BitmapInfoHeader _bmInfo; byte _palette[3 * 256]; + byte *_initialPalette; mutable bool _dirtyPalette; int _frameCount, _curFrame; @@ -193,6 +204,11 @@ protected: virtual void queueSound(Common::SeekableReadStream *stream); Audio::Mixer::SoundType getSoundType() const { return _soundType; } + void skipAudio(const Audio::Timestamp &time, const Audio::Timestamp &frameTime); + void resetStream(); + + bool isRewindable() const { return true; } + bool rewind(); protected: Audio::AudioStream *getAudioStream() const; diff --git a/video/video_decoder.cpp b/video/video_decoder.cpp index a512a49fac..0ab1478727 100644 --- a/video/video_decoder.cpp +++ b/video/video_decoder.cpp @@ -62,6 +62,8 @@ void VideoDecoder::close() { delete *it; _tracks.clear(); + _internalTracks.clear(); + _externalTracks.clear(); _dirtyPalette = false; _palette = 0; _startTime = 0; @@ -340,6 +342,11 @@ bool VideoDecoder::seek(const Audio::Timestamp &time) { if (!seekIntern(time)) return false; + // Seek any external track too + for (TrackListIterator it = _externalTracks.begin(); it != _externalTracks.end(); it++) + if (!(*it)->seek(time)) + return false; + _lastTimeChange = time; // Now that we've seeked, start all tracks again @@ -356,12 +363,12 @@ bool VideoDecoder::seek(const Audio::Timestamp &time) { } bool VideoDecoder::seekToFrame(uint frame) { + if (!isSeekable()) + return false; + VideoTrack *track = 0; for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) { - if (!(*it)->isSeekable()) - return false; - if ((*it)->getTrackType() == Track::kTrackTypeVideo) { // We only allow seeking by frame when one video track // is present @@ -472,7 +479,7 @@ Audio::Timestamp VideoDecoder::getDuration() const { } bool VideoDecoder::seekIntern(const Audio::Timestamp &time) { - for (TrackList::iterator it = _tracks.begin(); it != _tracks.end(); it++) + for (TrackList::iterator it = _internalTracks.begin(); it != _internalTracks.end(); it++) if (!(*it)->seek(time)) return false; @@ -524,10 +531,9 @@ Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getFrameTime(uint frame) con if (frameRate == frameRate.toInt()) // The nice case (a whole number) return Audio::Timestamp(0, frame, frameRate.toInt()); - // Just convert to milliseconds. - Common::Rational time = frame * 1000; - time /= frameRate; - return Audio::Timestamp(time.toInt(), 1000); + // Convert as best as possible + Common::Rational time = frameRate.getInverse() * frame; + return Audio::Timestamp(0, time.getNumerator(), time.getDenominator()); } uint VideoDecoder::FixedRateVideoTrack::getFrameAtTime(const Audio::Timestamp &time) const { @@ -537,8 +543,10 @@ uint VideoDecoder::FixedRateVideoTrack::getFrameAtTime(const Audio::Timestamp &t if (frameRate == time.framerate()) return time.totalNumberOfFrames(); - // Default case - return (time.totalNumberOfFrames() * frameRate / time.framerate()).toInt(); + // Create the rational based on the time first to hopefully cancel out + // *something* when multiplying by the frameRate (which can be large in + // some AVI videos). + return (Common::Rational(time.totalNumberOfFrames(), time.framerate()) * frameRate).toInt(); } Audio::Timestamp VideoDecoder::FixedRateVideoTrack::getDuration() const { @@ -649,9 +657,14 @@ bool VideoDecoder::StreamFileAudioTrack::loadFromFile(const Common::String &base return _stream != 0; } -void VideoDecoder::addTrack(Track *track) { +void VideoDecoder::addTrack(Track *track, bool isExternal) { _tracks.push_back(track); + if (isExternal) + _externalTracks.push_back(track); + else + _internalTracks.push_back(track); + if (track->getTrackType() == Track::kTrackTypeAudio) { // Update volume settings if it's an audio track ((AudioTrack *)track)->setVolume(_audioVolume); @@ -681,7 +694,7 @@ bool VideoDecoder::addStreamFileTrack(const Common::String &baseName) { bool result = track->loadFromFile(baseName); if (result) - addTrack(track); + addTrack(track, true); else delete track; @@ -712,17 +725,17 @@ void VideoDecoder::setEndTime(const Audio::Timestamp &endTime) { } VideoDecoder::Track *VideoDecoder::getTrack(uint track) { - if (track > _tracks.size()) + if (track > _internalTracks.size()) return 0; - return _tracks[track]; + return _internalTracks[track]; } const VideoDecoder::Track *VideoDecoder::getTrack(uint track) const { - if (track > _tracks.size()) + if (track > _internalTracks.size()) return 0; - return _tracks[track]; + return _internalTracks[track]; } bool VideoDecoder::endOfVideoTracks() const { diff --git a/video/video_decoder.h b/video/video_decoder.h index 7811734dd5..ac6586d8dd 100644 --- a/video/video_decoder.h +++ b/video/video_decoder.h @@ -594,17 +594,17 @@ protected: virtual Audio::Timestamp getDuration() const; Audio::Timestamp getFrameTime(uint frame) const; - protected: - /** - * Get the rate at which this track is played. - */ - virtual Common::Rational getFrameRate() const = 0; - /** * Get the frame that should be displaying at the given time. This is * helpful for someone implementing seek(). */ uint getFrameAtTime(const Audio::Timestamp &time) const; + + protected: + /** + * Get the rate at which this track is played. + */ + virtual Common::Rational getFrameRate() const = 0; }; /** @@ -761,8 +761,11 @@ protected: * Define a track to be used by this class. * * The pointer is then owned by this base class. + * + * @param track The track to add + * @param isExternal Is this an external track not found by loadStream()? */ - void addTrack(Track *track); + void addTrack(Track *track, bool isExternal = false); /** * Whether or not getTime() will sync with a playing audio track. @@ -814,12 +817,12 @@ protected: /** * Get the begin iterator of the tracks */ - TrackListIterator getTrackListBegin() { return _tracks.begin(); } + TrackListIterator getTrackListBegin() { return _internalTracks.begin(); } /** * Get the end iterator of the tracks */ - TrackListIterator getTrackListEnd() { return _tracks.end(); } + TrackListIterator getTrackListEnd() { return _internalTracks.end(); } /** * The internal seek function that does the actual seeking. @@ -833,6 +836,8 @@ protected: private: // Tracks owned by this VideoDecoder TrackList _tracks; + TrackList _internalTracks; + TrackList _externalTracks; // Current playback status bool _needsUpdate; |