diff options
author | Strangerke | 2013-09-11 21:33:10 +0200 |
---|---|---|
committer | Strangerke | 2013-09-11 21:33:10 +0200 |
commit | da1a427e794434a09cd39ab45e32ae7afca9a170 (patch) | |
tree | 85b4700515bc7853e4f90ddae22bc3b785c4ab3a | |
parent | 49dbac6a2a5cde294a4c4c9a47467e7b5d95e08b (diff) | |
parent | 5c6ee7573c0cf05bbbb154d4734e94e478f453e5 (diff) | |
download | scummvm-rg350-da1a427e794434a09cd39ab45e32ae7afca9a170.tar.gz scummvm-rg350-da1a427e794434a09cd39ab45e32ae7afca9a170.tar.bz2 scummvm-rg350-da1a427e794434a09cd39ab45e32ae7afca9a170.zip |
Merge branch 'master' of https://github.com/urukgit/scummvm into avalanche
211 files changed, 18310 insertions, 4976 deletions
diff --git a/.gitignore b/.gitignore index 99c9296dba..0fe212098c 100644 --- a/.gitignore +++ b/.gitignore @@ -168,6 +168,8 @@ ipch/ [Rr]elease32/ [Dd]ebug64/ [Rr]elease64/ +LLVM32/ +LLVM64/ #Ignore Qt Creator project files ScummVM.config @@ -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/devtools/create_mortdat/create_mortdat.cpp b/devtools/create_mortdat/create_mortdat.cpp index 00b9b1ce4a..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() { +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,6 +229,11 @@ 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' }; diff --git a/devtools/create_mortdat/create_mortdat.h b/devtools/create_mortdat/create_mortdat.h index 1ebbbe37e0..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 1 +#define VERSION_MINOR 2 enum AccessMode { kFileReadMode = 1, diff --git a/devtools/create_mortdat/menudata.h b/devtools/create_mortdat/menudata.h index 6a5f8dcfad..ec8724135c 100644 --- a/devtools/create_mortdat/menudata.h +++ b/devtools/create_mortdat/menudata.h @@ -76,18 +76,68 @@ const char *menuDataEn = "@@@ @@@ @@@ @@@ " " "; -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 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 }; + 0x306, 0x30d, 0x30e, 0x303, 0x30c, 0x30b, 0x313, 0x30a, + 0x311, 0x312, 0x307, 0x308, 0x314, 0x401, 0x405, 0x404, + 0x403, 0x402 }; -const int verbsDe[26] = { 0x30a, 0x310, 0x313, 0x301, 0x315, 0x308, 0x303, 0x306, - 0x30c, 0x311, 0x314, 0x309, 0x30b, 0x30f, 0x30e, 0x304, - 0x307, 0x30d, 0x312, 0x302, 0x305, 0x405, 0x402, 0x404, - 0x403, 0x401 }; +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 60aa35b739..7bab5c1078 100644 --- a/devtools/create_project/msbuild.cpp +++ b/devtools/create_project/msbuild.cpp @@ -67,10 +67,10 @@ inline void outputConfiguration(std::ostream &project, const std::string &config "\t\t</ProjectConfiguration>\n"; } -inline void outputConfigurationType(const BuildSetup &setup, std::ostream &project, const std::string &name, const std::string &config, int version) { +inline void outputConfigurationType(const BuildSetup &setup, std::ostream &project, const std::string &name, const std::string &config, std::string toolset) { project << "\t<PropertyGroup Condition=\"'$(Configuration)|$(Platform)'=='" << config << "'\" Label=\"Configuration\">\n" "\t\t<ConfigurationType>" << ((name == setup.projectName || setup.devTools || setup.tests) ? "Application" : "StaticLibrary") << "</ConfigurationType>\n" - "\t\t<PlatformToolset>v" << version << "0</PlatformToolset>\n" + "\t\t<PlatformToolset>" << toolset << "</PlatformToolset>\n" "\t</PropertyGroup>\n"; } @@ -98,6 +98,8 @@ void MSBuildProvider::createProjectFile(const std::string &name, const std::stri outputConfiguration(project, "Debug", "x64"); outputConfiguration(project, "Analysis", "Win32"); outputConfiguration(project, "Analysis", "x64"); + outputConfiguration(project, "LLVM", "Win32"); + outputConfiguration(project, "LLVM", "x64"); outputConfiguration(project, "Release", "Win32"); outputConfiguration(project, "Release", "x64"); @@ -108,18 +110,23 @@ void MSBuildProvider::createProjectFile(const std::string &name, const std::stri "\t\t<ProjectGuid>{" << uuid << "}</ProjectGuid>\n" "\t\t<RootNamespace>" << name << "</RootNamespace>\n" "\t\t<Keyword>Win32Proj</Keyword>\n" - "\t\t<VCTargetsPath Condition=\"'$(VCTargetsPath" << _version << ")' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath" << _version << ")</VCTargetsPath>\n" + "\t\t<VCTargetsPath Condition=\"'$(VCTargetsPath" << _version << ")' != '' and '$(VSVersion)' == '' and $(VisualStudioVersion) == ''\">$(VCTargetsPath" << _version << ")</VCTargetsPath>\n" "\t</PropertyGroup>\n"; // Shared configuration project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.Default.props\" />\n"; - outputConfigurationType(setup, project, name, "Release|Win32", _version); - outputConfigurationType(setup, project, name, "Analysis|Win32", _version); - outputConfigurationType(setup, project, name, "Debug|Win32", _version); - outputConfigurationType(setup, project, name, "Release|x64", _version); - outputConfigurationType(setup, project, name, "Analysis|x64", _version); - outputConfigurationType(setup, project, name, "Debug|x64", _version); + std::string version = "v" + std::to_string(_version) + "0"; + std::string llvm = "LLVM-vs" + std::to_string(getVisualStudioVersion()); + + outputConfigurationType(setup, project, name, "Release|Win32", version); + outputConfigurationType(setup, project, name, "Analysis|Win32", version); + outputConfigurationType(setup, project, name, "LLVM|Win32", llvm); + outputConfigurationType(setup, project, name, "Debug|Win32", version); + outputConfigurationType(setup, project, name, "Release|x64", version); + outputConfigurationType(setup, project, name, "LLVM|x64", llvm); + outputConfigurationType(setup, project, name, "Analysis|x64", version); + outputConfigurationType(setup, project, name, "Debug|x64", version); project << "\t<Import Project=\"$(VCTargetsPath)\\Microsoft.Cpp.props\" />\n" "\t<ImportGroup Label=\"ExtensionSettings\">\n" @@ -127,20 +134,24 @@ void MSBuildProvider::createProjectFile(const std::string &name, const std::stri outputProperties(project, "Release|Win32", setup.projectDescription + "_Release.props"); outputProperties(project, "Analysis|Win32", setup.projectDescription + "_Analysis.props"); + outputProperties(project, "LLVM|Win32", setup.projectDescription + "_LLVM.props"); outputProperties(project, "Debug|Win32", setup.projectDescription + "_Debug.props"); outputProperties(project, "Release|x64", setup.projectDescription + "_Release64.props"); outputProperties(project, "Analysis|x64", setup.projectDescription + "_Analysis64.props"); + outputProperties(project, "LLVM|x64", setup.projectDescription + "_LLVM64.props"); outputProperties(project, "Debug|x64", setup.projectDescription + "_Debug64.props"); project << "\t<PropertyGroup Label=\"UserMacros\" />\n"; // Project-specific settings (analysis uses debug properties) - outputProjectSettings(project, name, setup, false, true, false); - outputProjectSettings(project, name, setup, false, true, true); - outputProjectSettings(project, name, setup, true, true, false); - outputProjectSettings(project, name, setup, false, false, false); - outputProjectSettings(project, name, setup, false, false, true); - outputProjectSettings(project, name, setup, true, false, false); + outputProjectSettings(project, name, setup, false, true, "Debug"); + outputProjectSettings(project, name, setup, false, true, "Analysis"); + outputProjectSettings(project, name, setup, false, true, "LLVM"); + outputProjectSettings(project, name, setup, true, true, "Release"); + outputProjectSettings(project, name, setup, false, false, "Debug"); + outputProjectSettings(project, name, setup, false, false, "Analysis"); + outputProjectSettings(project, name, setup, false, false, "LLVM"); + outputProjectSettings(project, name, setup, true, false, "Release"); // Files std::string modulePath; @@ -255,9 +266,7 @@ void MSBuildProvider::writeReferences(const BuildSetup &setup, std::ofstream &ou output << "\t</ItemGroup>\n"; } -void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis) { - const std::string configuration = (enableAnalysis ? "Analysis" : (isRelease ? "Release" : "Debug")); - +void MSBuildProvider::outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32, std::string configuration) { // Check for project-specific warnings: std::map<std::string, StringList>::iterator warningsIterator = _projectWarnings.find(name); bool enableLanguageExtensions = find(_enableLanguageExtensions.begin(), _enableLanguageExtensions.end(), name) != _enableLanguageExtensions.end(); @@ -382,13 +391,12 @@ void MSBuildProvider::outputGlobalPropFile(const BuildSetup &setup, std::ofstrea properties.flush(); } -void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis) { - const std::string outputType = (enableAnalysis ? "Analysis" : (isRelease ? "Release" : "Debug")); +void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, std::string configuration) { const std::string outputBitness = (isWin32 ? "32" : "64"); - std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str()); + std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_" + configuration + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str()); if (!properties) - error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing"); + error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_" + configuration + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing"); properties << "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" "<Project DefaultTargets=\"Build\" ToolsVersion=\"" << (_version >= 12 ? _version : 4) << ".0\" xmlns=\"http://schemas.microsoft.com/developer/msbuild/2003\">\n" @@ -396,7 +404,7 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b "\t\t<Import Project=\"" << setup.projectDescription << "_Global" << (isWin32 ? "" : "64") << ".props\" />\n" "\t</ImportGroup>\n" "\t<PropertyGroup>\n" - "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_" << outputType << outputBitness << "</_PropertySheetDisplayName>\n" + "\t\t<_PropertySheetDisplayName>" << setup.projectDescription << "_" << configuration << outputBitness << "</_PropertySheetDisplayName>\n" "\t\t<LinkIncremental>" << (isRelease ? "false" : "true") << "</LinkIncremental>\n" "\t</PropertyGroup>\n" "\t<ItemDefinitionGroup>\n" @@ -410,22 +418,26 @@ void MSBuildProvider::createBuildProp(const BuildSetup &setup, bool isRelease, b "\t\t\t<BufferSecurityCheck>false</BufferSecurityCheck>\n" "\t\t\t<DebugInformationFormat></DebugInformationFormat>\n" "\t\t\t<RuntimeLibrary>MultiThreaded</RuntimeLibrary>\n" - "\t\t\t<EnablePREfast>" << (enableAnalysis ? "true" : "false") << "</EnablePREfast>\n" + "\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n" "\t\t</ClCompile>\n" "\t\t<Link>\n" "\t\t\t<IgnoreSpecificDefaultLibraries>%(IgnoreSpecificDefaultLibraries)</IgnoreSpecificDefaultLibraries>\n" "\t\t\t<SetChecksum>true</SetChecksum>\n"; } else { properties << "\t\t\t<Optimization>Disabled</Optimization>\n" - "\t\t\t<PreprocessorDefinitions>WIN32;%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" + "\t\t\t<PreprocessorDefinitions>WIN32;" << (configuration == "LLVM" ? "_CRT_SECURE_NO_WARNINGS;" : "") << "%(PreprocessorDefinitions)</PreprocessorDefinitions>\n" "\t\t\t<MinimalRebuild>true</MinimalRebuild>\n" "\t\t\t<BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>\n" "\t\t\t<RuntimeLibrary>MultiThreadedDebug</RuntimeLibrary>\n" "\t\t\t<FunctionLevelLinking>true</FunctionLevelLinking>\n" "\t\t\t<TreatWarningAsError>false</TreatWarningAsError>\n" "\t\t\t<DebugInformationFormat>" << (isWin32 ? "EditAndContinue" : "ProgramDatabase") << "</DebugInformationFormat>\n" // For x64 format Edit and continue is not supported, thus we default to Program Database - "\t\t\t<EnablePREfast>" << (enableAnalysis ? "true" : "false") << "</EnablePREfast>\n" - "\t\t</ClCompile>\n" + "\t\t\t<EnablePREfast>" << (configuration == "Analysis" ? "true" : "false") << "</EnablePREfast>\n"; + + if (configuration == "LLVM") + properties << "\t\t\t<AdditionalOptions>-Wno-microsoft -Wno-long-long -Wno-multichar -Wno-unknown-pragmas -Wno-reorder -Wpointer-arith -Wcast-qual -Wshadow -Wnon-virtual-dtor -Wwrite-strings -Wno-conversion -Wno-shorten-64-to-32 -Wno-sign-compare -Wno-four-char-constants -Wno-nested-anon-types %(AdditionalOptions)</AdditionalOptions>\n"; + + properties << "\t\t</ClCompile>\n" "\t\t<Link>\n" "\t\t\t<GenerateDebugInformation>true</GenerateDebugInformation>\n" "\t\t\t<ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>\n" @@ -481,7 +493,7 @@ void MSBuildProvider::writeFileListToProject(const FileNode &dir, std::ofstream // Deal with duplicated file names if (isDuplicate) { projectFile << "\t\t<ClCompile Include=\"" << (*entry).path << "\">\n" - "\t\t\t<ObjectFileName>$(IntDir)" << (*entry).prefix << "%(Filename).obj</ObjectFileName>\n"; + "\t\t\t<ObjectFileName>$(IntDir)" << (*entry).prefix << "%(Filename).obj</ObjectFileName>\n"; projectFile << "\t\t</ClCompile>\n"; } else { diff --git a/devtools/create_project/msbuild.h b/devtools/create_project/msbuild.h index fa6667741a..829657beff 100644 --- a/devtools/create_project/msbuild.h +++ b/devtools/create_project/msbuild.h @@ -35,7 +35,7 @@ protected: void createProjectFile(const std::string &name, const std::string &uuid, const BuildSetup &setup, const std::string &moduleDir, const StringList &includeList, const StringList &excludeList); - void outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis); + void outputProjectSettings(std::ofstream &project, const std::string &name, const BuildSetup &setup, bool isRelease, bool isWin32, std::string configuration); void writeFileListToProject(const FileNode &dir, std::ofstream &projectFile, const int indentation, const StringList &duplicate, const std::string &objPrefix, const std::string &filePrefix); @@ -44,7 +44,7 @@ protected: void outputGlobalPropFile(const BuildSetup &setup, std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix, bool runBuildEvents); - void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis); + void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, std::string configuration); const char *getProjectExtension(); const char *getPropertiesExtension(); diff --git a/devtools/create_project/msvc.cpp b/devtools/create_project/msvc.cpp index 2fedadcba5..cdd2d8a7c1 100644 --- a/devtools/create_project/msvc.cpp +++ b/devtools/create_project/msvc.cpp @@ -79,9 +79,11 @@ void MSVCProvider::createWorkspace(const BuildSetup &setup) { "\tGlobalSection(SolutionConfigurationPlatforms) = preSolution\n" "\t\tDebug|Win32 = Debug|Win32\n" "\t\tAnalysis|Win32 = Analysis|Win32\n" + "\t\tLLVM|Win32 = LLVM|Win32\n" "\t\tRelease|Win32 = Release|Win32\n" "\t\tDebug|x64 = Debug|x64\n" "\t\tAnalysis|x64 = Analysis|x64\n" + "\t\tLLVM|x64 = LLVM|x64\n" "\t\tRelease|x64 = Release|x64\n" "\tEndGlobalSection\n" "\tGlobalSection(ProjectConfigurationPlatforms) = postSolution\n"; @@ -91,12 +93,16 @@ void MSVCProvider::createWorkspace(const BuildSetup &setup) { "\t\t{" << i->second << "}.Debug|Win32.Build.0 = Debug|Win32\n" "\t\t{" << i->second << "}.Analysis|Win32.ActiveCfg = Analysis|Win32\n" "\t\t{" << i->second << "}.Analysis|Win32.Build.0 = Analysis|Win32\n" + "\t\t{" << i->second << "}.LLVM|Win32.ActiveCfg = LLVM|Win32\n" + "\t\t{" << i->second << "}.LLVM|Win32.Build.0 = LLVM|Win32\n" "\t\t{" << i->second << "}.Release|Win32.ActiveCfg = Release|Win32\n" "\t\t{" << i->second << "}.Release|Win32.Build.0 = Release|Win32\n" "\t\t{" << i->second << "}.Debug|x64.ActiveCfg = Debug|x64\n" "\t\t{" << i->second << "}.Debug|x64.Build.0 = Debug|x64\n" "\t\t{" << i->second << "}.Analysis|x64.ActiveCfg = Analysis|x64\n" "\t\t{" << i->second << "}.Analysis|x64.Build.0 = Analysis|x64\n" + "\t\t{" << i->second << "}.LLVM|x64.ActiveCfg = LLVM|x64\n" + "\t\t{" << i->second << "}.LLVM|x64.Build.0 = LLVM|x64\n" "\t\t{" << i->second << "}.Release|x64.ActiveCfg = Release|x64\n" "\t\t{" << i->second << "}.Release|x64.Build.0 = Release|x64\n"; } @@ -114,12 +120,14 @@ void MSVCProvider::createOtherBuildFiles(const BuildSetup &setup) { // Create the configuration property files (for Debug and Release with 32 and 64bits versions) // Note: we use the debug properties for the analysis configuration - createBuildProp(setup, true, false, false); - createBuildProp(setup, true, true, false); - createBuildProp(setup, false, false, false); - createBuildProp(setup, false, false, true); - createBuildProp(setup, false, true, false); - createBuildProp(setup, false, true, true); + createBuildProp(setup, true, false, "Release"); + createBuildProp(setup, true, true, "Release"); + createBuildProp(setup, false, false, "Debug"); + createBuildProp(setup, false, true, "Debug"); + createBuildProp(setup, false, false, "Analysis"); + createBuildProp(setup, false, true, "Analysis"); + createBuildProp(setup, false, false, "LLVM"); + createBuildProp(setup, false, true, "LLVM"); } void MSVCProvider::createGlobalProp(const BuildSetup &setup) { diff --git a/devtools/create_project/msvc.h b/devtools/create_project/msvc.h index b9b93fe109..3a3eb98034 100644 --- a/devtools/create_project/msvc.h +++ b/devtools/create_project/msvc.h @@ -70,7 +70,7 @@ protected: * @param isWin32 Bitness of property file * @param enableAnalysis PREfast support */ - virtual void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis) = 0; + virtual void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, std::string configuration) = 0; /** * Get the file extension for property files diff --git a/devtools/create_project/visualstudio.cpp b/devtools/create_project/visualstudio.cpp index 23225d3435..438e0772f9 100644 --- a/devtools/create_project/visualstudio.cpp +++ b/devtools/create_project/visualstudio.cpp @@ -92,6 +92,7 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std: // Win32 outputConfiguration(project, setup, libraries, "Debug", "Win32", "", true); outputConfiguration(project, setup, libraries, "Analysis", "Win32", "", true); + outputConfiguration(project, setup, libraries, "LLVM", "Win32", "", true); outputConfiguration(project, setup, libraries, "Release", "Win32", "", true); // x64 @@ -100,6 +101,7 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std: // libraries list created for IA-32. If that changes in the future, we need to adjust this part! outputConfiguration(project, setup, libraries, "Debug", "x64", "64", false); outputConfiguration(project, setup, libraries, "Analysis", "x64", "64", false); + outputConfiguration(project, setup, libraries, "LLVM", "Win32", "64", false); outputConfiguration(project, setup, libraries, "Release", "x64", "64", false); } else { @@ -119,9 +121,11 @@ void VisualStudioProvider::createProjectFile(const std::string &name, const std: // Win32 outputConfiguration(setup, project, toolConfig, "Debug", "Win32", ""); outputConfiguration(setup, project, toolConfig, "Analysis", "Win32", ""); + outputConfiguration(setup, project, toolConfig, "LLVM", "Win32", ""); outputConfiguration(setup, project, toolConfig, "Release", "Win32", ""); outputConfiguration(setup, project, toolConfig, "Debug", "x64", "64"); outputConfiguration(setup, project, toolConfig, "Analysis", "x64", "64"); + outputConfiguration(setup, project, toolConfig, "LLVM", "x64", "64"); outputConfiguration(setup, project, toolConfig, "Release", "x64", "64"); } @@ -265,19 +269,18 @@ void VisualStudioProvider::outputGlobalPropFile(const BuildSetup &setup, std::of properties.flush(); } -void VisualStudioProvider::createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis) { - const std::string outputType = (enableAnalysis ? "Analysis" : (isRelease ? "Release" : "Debug")); +void VisualStudioProvider::createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, std::string configuration) { const std::string outputBitness = (isWin32 ? "32" : "64"); - std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str()); + std::ofstream properties((setup.outputDir + '/' + setup.projectDescription + "_" + configuration + (isWin32 ? "" : "64") + getPropertiesExtension()).c_str()); if (!properties) - error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_" + outputType + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing"); + error("Could not open \"" + setup.outputDir + '/' + setup.projectDescription + "_" + configuration + (isWin32 ? "" : "64") + getPropertiesExtension() + "\" for writing"); properties << "<?xml version=\"1.0\" encoding=\"Windows-1252\"?>\n" "<VisualStudioPropertySheet\n" "\tProjectType=\"Visual C++\"\n" "\tVersion=\"8.00\"\n" - "\tName=\"" << setup.projectDescription << "_" << outputType << outputBitness << "\"\n" + "\tName=\"" << setup.projectDescription << "_" << configuration << outputBitness << "\"\n" "\tInheritedPropertySheets=\".\\" << setup.projectDescription << "_Global" << (isWin32 ? "" : "64") << ".vsprops\"\n" "\t>\n" "\t<Tool\n" @@ -291,7 +294,7 @@ void VisualStudioProvider::createBuildProp(const BuildSetup &setup, bool isRelea "\t\tBufferSecurityCheck=\"false\"\n" "\t\tDebugInformationFormat=\"0\"\n" "\t\tRuntimeLibrary=\"0\"\n" - "\t\tAdditionalOption=\"" << (enableAnalysis ? "/analyze" : "") << "\"\n" + "\t\tAdditionalOption=\"" << (configuration == "Analysis" ? "/analyze" : "") << "\"\n" "\t/>\n" "\t<Tool\n" "\t\tName=\"VCLinkerTool\"\n" @@ -307,7 +310,7 @@ void VisualStudioProvider::createBuildProp(const BuildSetup &setup, bool isRelea "\t\tEnableFunctionLevelLinking=\"true\"\n" "\t\tWarnAsError=\"false\"\n" "\t\tDebugInformationFormat=\"" << (isWin32 ? "4" : "3") << "\"\n" // For x64 format "4" (Edit and continue) is not supported, thus we default to "3" - "\t\tAdditionalOption=\"" << (enableAnalysis ? "/analyze" : "") << "\"\n" + "\t\tAdditionalOption=\"" << (configuration == "Analysis" ? "/analyze" : "") << "\"\n" "\t/>\n" "\t<Tool\n" "\t\tName=\"VCLinkerTool\"\n" @@ -354,9 +357,9 @@ void VisualStudioProvider::writeFileListToProject(const FileNode &dir, std::ofst << indentString << "\t<FileConfiguration Name=\"Debug|Win32\">\n" << toolLine << indentString << "\t</FileConfiguration>\n" - << indentString << "\t<FileConfiguration Name=\"Analysis|Win32\">\n" - << toolLine - << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Analysis|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" << indentString << "\t<FileConfiguration Name=\"Release|Win32\">\n" << toolLine << indentString << "\t</FileConfiguration>\n" @@ -369,18 +372,18 @@ void VisualStudioProvider::writeFileListToProject(const FileNode &dir, std::ofst << indentString << "\t<FileConfiguration Name=\"Debug|Win32\">\n" << toolLine << indentString << "\t</FileConfiguration>\n" - << indentString << "\t<FileConfiguration Name=\"Analysis|Win32\">\n" - << toolLine - << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Analysis|Win32\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" << indentString << "\t<FileConfiguration Name=\"Release|Win32\">\n" << toolLine << indentString << "\t</FileConfiguration>\n" - << indentString << "\t<FileConfiguration Name=\"Debug|x64\">\n" - << toolLine - << indentString << "\t</FileConfiguration>\n" - << indentString << "\t<FileConfiguration Name=\"Analysis|x64\">\n" - << toolLine - << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Debug|x64\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" + << indentString << "\t<FileConfiguration Name=\"Analysis|x64\">\n" + << toolLine + << indentString << "\t</FileConfiguration>\n" << indentString << "\t<FileConfiguration Name=\"Release|x64\">\n" << toolLine << indentString << "\t</FileConfiguration>\n" diff --git a/devtools/create_project/visualstudio.h b/devtools/create_project/visualstudio.h index 845550139c..7eb66c4f2d 100644 --- a/devtools/create_project/visualstudio.h +++ b/devtools/create_project/visualstudio.h @@ -42,7 +42,7 @@ protected: void outputGlobalPropFile(const BuildSetup &setup, std::ofstream &properties, int bits, const StringList &defines, const std::string &prefix, bool runBuildEvents); - void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, bool enableAnalysis); + void createBuildProp(const BuildSetup &setup, bool isRelease, bool isWin32, std::string configuration); const char *getProjectExtension(); const char *getPropertiesExtension(); 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/dists/engine-data/mort.dat b/dists/engine-data/mort.dat Binary files differindex ae9579ee13..0d6a44206d 100644 --- a/dists/engine-data/mort.dat +++ b/dists/engine-data/mort.dat diff --git a/engines/advancedDetector.cpp b/engines/advancedDetector.cpp index fd0c8dc2da..40783a2407 100644 --- a/engines/advancedDetector.cpp +++ b/engines/advancedDetector.cpp @@ -78,7 +78,7 @@ static Common::String generatePreferredTarget(const Common::String &id, const AD res = res + "-cd"; } - if (desc->platform != Common::kPlatformDOS && desc->platform != Common::kPlatformUnknown) { + if (desc->platform != Common::kPlatformDOS && desc->platform != Common::kPlatformUnknown && !(desc->flags & ADGF_DROPPLATFORM)) { res = res + "-" + getPlatformAbbrev(desc->platform); } diff --git a/engines/advancedDetector.h b/engines/advancedDetector.h index 71d2c4a446..376a59e471 100644 --- a/engines/advancedDetector.h +++ b/engines/advancedDetector.h @@ -87,7 +87,8 @@ enum ADGameFlags { ADGF_ADDENGLISH = (1 << 24), ///< always add English as language option ADGF_MACRESFORK = (1 << 25), ///< the md5 for this entry will be calculated from the resource fork ADGF_USEEXTRAASTITLE = (1 << 26), ///< Extra field value will be used as main game title, not gameid - ADGF_DROPLANGUAGE = (1 << 28), ///< don't add language to gameid + ADGF_DROPLANGUAGE = (1 << 27), ///< don't add language to gameid + ADGF_DROPPLATFORM = (1 << 28), ///< don't add platform to gameid ADGF_CD = (1 << 29), ///< add "-cd" to gameid ADGF_DEMO = (1 << 30) ///< add "-demo" to gameid }; 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/configure.engines b/engines/configure.engines index 7004f4111f..f3dfd6e7dd 100644 --- a/engines/configure.engines +++ b/engines/configure.engines @@ -14,6 +14,7 @@ add_engine cruise "Cinematique evo 2" yes add_engine draci "Dragon History" yes add_engine drascula "Drascula: The Vampire Strikes Back" yes add_engine dreamweb "Dreamweb" yes +add_engine fullpipe "Full Pipe" yes add_engine gob "Gobli*ns" yes add_engine groovie "Groovie" yes "groovie2" "7th Guest" add_engine groovie2 "Groovie 2 games" no 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/engines.mk b/engines/engines.mk index 3401df37e5..c710fb143c 100644 --- a/engines/engines.mk +++ b/engines/engines.mk @@ -66,6 +66,11 @@ DEFINES += -DENABLE_DREAMWEB=$(ENABLE_DREAMWEB) MODULES += engines/dreamweb endif +ifdef ENABLE_FULLPIPE +DEFINES += -DENABLE_FULLPIPE=$(ENABLE_FULLPIPE) +MODULES += engines/fullpipe +endif + ifdef ENABLE_GOB DEFINES += -DENABLE_GOB=$(ENABLE_GOB) MODULES += engines/gob diff --git a/engines/fullpipe/behavior.cpp b/engines/fullpipe/behavior.cpp new file mode 100644 index 0000000000..6bfb400c24 --- /dev/null +++ b/engines/fullpipe/behavior.cpp @@ -0,0 +1,315 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/behavior.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +BehaviorManager::BehaviorManager() { + _scene = 0; + _isActive = 1; +} + +BehaviorManager::~BehaviorManager() { + clear(); +} + +void BehaviorManager::clear() { + for (uint i = 0; i < _behaviors.size(); i++) { + for (int j = 0; j < _behaviors[i]->_itemsCount; j++) + delete _behaviors[i]->_bheItems[j]; + + delete _behaviors[i]; + } + _behaviors.clear(); +} + +void BehaviorManager::initBehavior(Scene *sc, CGameVar *var) { + clear(); + _scene = sc; + + BehaviorInfo *behinfo; + + CGameVar *behvar = var->getSubVarByName("BEHAVIOR"); + if (!behvar) + return; + + for (CGameVar *subvar = behvar->_subVars; subvar; subvar = subvar->_nextVarObj) { + if (!strcmp(subvar->_varName, "AMBIENT")) { + behinfo = new BehaviorInfo; + behinfo->initAmbientBehavior(subvar, sc); + + _behaviors.push_back(behinfo); + } else { + StaticANIObject *ani = sc->getStaticANIObject1ByName(subvar->_varName, -1); + if (ani) + for (uint i = 0; i < sc->_staticANIObjectList1.size(); i++) + if (((StaticANIObject *)sc->_staticANIObjectList1[i])->_id == ani->_id) { + behinfo = new BehaviorInfo; + behinfo->initObjectBehavior(subvar, sc, ani); + behinfo->_ani = (StaticANIObject *)sc->_staticANIObjectList1[i]; + + _behaviors.push_back(behinfo); + } + } + } +} + +void BehaviorManager::updateBehaviors() { + if (!_isActive) + return; + + debug(0, "BehaviorManager::updateBehaviors()"); + for (uint i = 0; i < _behaviors.size(); i++) { + BehaviorInfo *beh = _behaviors[i]; + + if (!beh->_ani) { + beh->_counter++; + if (beh->_counter >= beh->_counterMax) + updateBehavior(beh, beh->_bheItems[0]); + + continue; + } + + if (beh->_ani->_movement || !(beh->_ani->_flags & 4) || (beh->_ani->_flags & 2)) { + beh->_staticsId = 0; + continue; + } + + if (beh->_ani->_statics->_staticsId == beh->_staticsId) { + beh->_counter++; + if (beh->_counter >= beh->_counterMax) { + if (beh->_subIndex >= 0 && !(beh->_flags & 1) && beh->_ani->_messageQueueId <= 0) + updateStaticAniBehavior(beh->_ani, beh->_counter, beh->_bheItems[beh->_subIndex]); + } + } else { + beh->_staticsId = beh->_ani->_statics->_staticsId; + beh->_counter = 0; + beh->_subIndex = -1; + + for (int j = 0; j < beh->_itemsCount; j++) + if (beh->_bheItems[j]->_staticsId == beh->_staticsId) { + beh->_subIndex = j; + break; + } + + } + } +} + +void BehaviorManager::updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry) { + debug(0, "BehaviorManager::updateBehavior() %d", entry->_itemsCount); + for (int i = 0; i < entry->_itemsCount; i++) { + BehaviorEntryInfo *bhi = entry->_items[i]; + if (!(bhi->_flags & 1)) { + if (bhi->_flags & 2) { + MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1); + + mq->sendNextCommand(); + + bhi->_flags &= 0xFFFFFFFD; + } else if (behaviorInfo->_counter >= bhi->_delay && bhi->_percent && g_fullpipe->_rnd->getRandomNumber(32767) <= entry->_items[i]->_percent) { + MessageQueue *mq = new MessageQueue(bhi->_messageQueue, 0, 1); + + mq->sendNextCommand(); + + behaviorInfo->_counter = 0; + } + } + } +} + +void BehaviorManager::updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *bhe) { + debug(0, "BehaviorManager::updateStaticAniBehavior(%s)", transCyrillic((byte *)ani->_objectName)); + + MessageQueue *mq = 0; + + if (bhe->_flags & 1) { + uint rnd = g_fullpipe->_rnd->getRandomNumber(32767); + uint runPercent = 0; + for (int i = 0; i < bhe->_itemsCount; i++) { + if (!(bhe->_items[i]->_flags & 1) && bhe->_items[i]->_percent) { + if ((rnd >= runPercent && rnd <= runPercent + bhe->_items[i]->_percent) || i == bhe->_itemsCount - 1) { + mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1); + break; + } + runPercent += bhe->_items[i]->_percent; + } + } + } else { + for (int i = 0; i < bhe->_itemsCount; i++) { + if (!(bhe->_items[i]->_flags & 1) && delay >= bhe->_items[i]->_delay) { + if (bhe->_items[i]->_percent) { + if (g_fullpipe->_rnd->getRandomNumber(32767) <= bhe->_items[i]->_percent) { + mq = new MessageQueue(bhe->_items[i]->_messageQueue, 0, 1); + break; + } + } + } + } + } + + if (mq) { + mq->replaceKeyCode(-1, ani->_okeyCode); + mq->chain(ani); + } +} + +void BehaviorInfo::clear() { + _ani = 0; + _staticsId = 0; + _counter = 0; + _counterMax = 0; + _flags = 0; + _subIndex = 0; + _itemsCount = 0; + + _bheItems.clear(); +} + +void BehaviorInfo::initAmbientBehavior(CGameVar *var, Scene *sc) { + debug(0, "BehaviorInfo::initAmbientBehavior(%s)", transCyrillic((byte *)var->_varName)); + + clear(); + _itemsCount = 1; + _counterMax = -1; + + BehaviorEntry *bi = new BehaviorEntry(); + + _bheItems.push_back(bi); + + bi->_itemsCount = var->getSubVarsCount(); + + bi->_items = (BehaviorEntryInfo**)calloc(bi->_itemsCount, sizeof(BehaviorEntryInfo *)); + + for (int i = 0; i < bi->_itemsCount; i++) { + int delay; + bi->_items[i] = new BehaviorEntryInfo(var->getSubVarByIndex(i), sc, &delay); + + if (bi->_items[i]->_delay <_counterMax) + _counterMax = bi->_items[i]->_delay; + } +} + +void BehaviorInfo::initObjectBehavior(CGameVar *var, Scene *sc, StaticANIObject *ani) { + debug(0, "BehaviorInfo::initObjectBehavior(%s)", transCyrillic((byte *)var->_varName)); + + clear(); + + _itemsCount = var->getSubVarsCount(); + _counterMax = -1; + + while (var->_varType == 2) { + if (strcmp(var->_value.stringValue, "ROOT")) + break; + + CGameVar *v1 = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("BEHAVIOR")->getSubVarByName(ani->getName()); + if (v1 == var) + return; + + sc = g_fullpipe->accessScene(ani->_sceneId); + clear(); + var = v1; + _itemsCount = var->getSubVarsCount(); + _counterMax = -1; + } + + for (int i = 0; i < _itemsCount; i++) { + int maxDelay; + + _bheItems.push_back(new BehaviorEntry(var->getSubVarByIndex(i), sc, ani, &maxDelay)); + + if (maxDelay < _counterMax) + _counterMax = maxDelay; + } +} + +BehaviorEntry::BehaviorEntry() { + _staticsId = 0; + _itemsCount = 0; + _flags = 0; + _items = 0; +} + +BehaviorEntry::BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay) { + _staticsId = 0; + _itemsCount = 0; + + *minDelay = 100000000; + + int totalPercent = 0; + _flags = 0; + _items = 0; + + Statics *st = ani->getStaticsByName(var->_varName); + if (st) + _staticsId = st->_staticsId; + + _itemsCount = var->getSubVarsCount(); + if (_itemsCount) { + _items = (BehaviorEntryInfo**)calloc(_itemsCount, sizeof(BehaviorEntryInfo *)); + + for (int i = 0; i < _itemsCount; i++) { + CGameVar *subvar = var->getSubVarByIndex(i); + int delay; + + _items[i] = new BehaviorEntryInfo(subvar, sc, &delay); + totalPercent += delay; + + if (_items[i]->_delay < *minDelay) + *minDelay = _items[i]->_delay; + } + + if (!*minDelay && totalPercent == 1000) + _flags |= 1; + } +} + +BehaviorEntryInfo::BehaviorEntryInfo(CGameVar *subvar, Scene *sc, int *delay) { + _messageQueue = 0; + _delay = 0; + _percent = 0; + _flags = 0; + _messageQueue = sc->getMessageQueueByName(subvar->_varName); + + CGameVar *vart = subvar->getSubVarByName("dwDelay"); + if (vart) + _delay = vart->_value.intValue; + + *delay = 0; + vart = subvar->getSubVarByName("dwPercent"); + if (vart) { + _percent = 0x7FFF * vart->_value.intValue / 1000; + *delay = vart->_value.intValue; + } + + vart = subvar->getSubVarByName("dwFlags"); + if (vart && vart->_varType == 2 && strstr(vart->_value.stringValue, "QDESC_AUTOSTART")) + _flags |= 2; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/behavior.h b/engines/fullpipe/behavior.h new file mode 100644 index 0000000000..d9375d4d01 --- /dev/null +++ b/engines/fullpipe/behavior.h @@ -0,0 +1,84 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_BEHAVIOR_H +#define FULLPIPE_BEHAVIOR_H + +namespace Fullpipe { + +struct BehaviorEntryInfo { + MessageQueue *_messageQueue; + int _delay; + uint32 _percent; + int _flags; + + BehaviorEntryInfo(CGameVar *subvar, Scene *sc, int *delay); +}; + +struct BehaviorEntry { + int _staticsId; + int _itemsCount; + int _flags; + BehaviorEntryInfo **_items; + + BehaviorEntry(); + BehaviorEntry(CGameVar *var, Scene *sc, StaticANIObject *ani, int *minDelay); +}; + +struct BehaviorInfo { + StaticANIObject *_ani; + int _staticsId; + int _counter; + int _counterMax; + int _flags; + int _subIndex; + int _itemsCount; + Common::Array<BehaviorEntry *> _bheItems; + + BehaviorInfo() { clear(); } + + void clear(); + void initAmbientBehavior(CGameVar *var, Scene *sc); + void initObjectBehavior(CGameVar *var, Scene *sc, StaticANIObject *ani); +}; + +class BehaviorManager : public CObject { + Common::Array<BehaviorInfo *> _behaviors; + Scene *_scene; + bool _isActive; + + public: + BehaviorManager(); + ~BehaviorManager(); + + void clear(); + + void initBehavior(Scene *scene, CGameVar *var); + + void updateBehaviors(); + void updateBehavior(BehaviorInfo *behaviorInfo, BehaviorEntry *entry); + void updateStaticAniBehavior(StaticANIObject *ani, int delay, BehaviorEntry *beh); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_BEHAVIOR_H */ diff --git a/engines/fullpipe/constants.h b/engines/fullpipe/constants.h new file mode 100644 index 0000000000..4f389f80a8 --- /dev/null +++ b/engines/fullpipe/constants.h @@ -0,0 +1,179 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_CONSTANTS_H +#define FULLPIPE_CONSTANTS_H + +namespace Fullpipe { + +#define ANI_BOOT_1 4231 +#define ANI_IN1MAN 5110 +#define ANI_INV_MAP 5321 +#define ANI_LIFTBUTTON 2751 +#define ANI_MAN 322 +#define MSG_DISABLESAVES 5201 +#define MSG_ENABLESAVES 5202 +#define MSG_HMRKICK_METAL 4764 +#define MSG_HMRKICK_STUCCO 4765 +#define MSG_MANSHADOWSOFF 5196 +#define MSG_MANSHADOWSON 5197 +#define MSG_RESTARTGAME 4767 +#define MSG_SC1_SHOWOSK 1019 +#define MSG_SC1_SHOWOSK2 468 +#define MSG_SC1_UTRUBACLICK 1100 +#define MV_MAN_GOLADDER 451 +#define MV_MAN_GOLADDER2 2844 +#define MV_MAN_LOOKUP 4773 +#define MV_MAN_STARTLADDER 452 +#define MV_MAN_STARTLADDER2 2842 +#define MV_MAN_STOPLADDER 454 +#define MV_MAN_STOPLADDER2 2845 +#define MV_MAN_TOLADDER 448 +#define MV_MAN_TOLADDER2 2841 +#define MV_MAN_TURN_LU 486 +#define PIC_CMN_EVAL 3468 +#define PIC_CSR_DEFAULT 4891 +#define PIC_CSR_DEFAULT_INV 4892 +#define PIC_CSR_ITN 4893 +#define PIC_CSR_ITN_INV 4894 +#define PIC_CSR_GOFAR_L 4895 +#define PIC_CSR_GOFAR_R 4896 +#define PIC_CSR_ARCADE1 4901 +#define PIC_CSR_ARCADE2 4902 +#define PIC_CSR_ARCADE2_D 4903 +#define PIC_CSR_ARCADE3 4904 +#define PIC_CSR_ARCADE4 4905 +#define PIC_CSR_ARCADE5 4906 +#define PIC_CSR_ARCADE6 4907 +#define PIC_CSR_ARCADE6_D 4908 +#define PIC_CSR_ARCADE7 4909 +#define PIC_CSR_ARCADE7_D 4910 +#define PIC_CSR_ARCADE8 4911 +#define PIC_CSR_DEFAULT 4891 +#define PIC_CSR_DEFAULT_INV 4892 +#define PIC_CSR_GOD 4900 +#define PIC_CSR_GOFAR_L 4895 +#define PIC_CSR_GOFAR_R 4896 +#define PIC_CSR_GOL 4897 +#define PIC_CSR_GOR 4898 +#define PIC_CSR_GOU 4899 +#define PIC_CSR_HELPERBGR 5331 +#define PIC_CSR_ITN 4893 +#define PIC_CSR_ITN_GREEN 5330 +#define PIC_CSR_ITN_INV 4894 +#define PIC_CSR_ITN_RED 5329 +#define PIC_CSR_LIFT 5176 +#define PIC_CSR_MAP 5339 +#define PIC_IN1_PIPETITLE 5167 +#define PIC_INV_MENU 991 +#define PIC_MAP_A13 5275 +#define PIC_MAP_S01 5223 +#define PIC_SC1_KUCHKA 1321 +#define PIC_SC1_LADDER 1091 +#define PIC_SC1_OSK 1018 +#define PIC_SC1_OSK2 2932 +#define PIC_SCD_SEL 734 +#define SC_1 301 +#define SC_10 653 +#define SC_11 654 +#define SC_12 655 +#define SC_13 1137 +#define SC_14 1138 +#define SC_15 1139 +#define SC_16 1140 +#define SC_17 1141 +#define SC_18 1142 +#define SC_19 1143 +#define SC_2 302 +#define SC_20 1144 +#define SC_21 1546 +#define SC_22 1547 +#define SC_23 1548 +#define SC_24 1549 +#define SC_25 1550 +#define SC_26 1551 +#define SC_27 1552 +#define SC_28 2062 +#define SC_29 2063 +#define SC_3 303 +#define SC_30 2064 +#define SC_31 2065 +#define SC_32 2066 +#define SC_33 2067 +#define SC_34 2068 +#define SC_35 2069 +#define SC_36 2070 +#define SC_37 2071 +#define SC_38 2072 +#define SC_4 304 +#define SC_5 305 +#define SC_6 649 +#define SC_7 650 +#define SC_8 651 +#define SC_9 652 +#define SC_COMMON 321 +#define SC_DBGMENU 726 +#define SC_FINAL1 4999 +#define SC_FINAL2 5000 +#define SC_FINAL3 5001 +#define SC_FINAL4 2460 +#define SC_INTRO1 3896 +#define SC_INTRO2 3907 +#define SC_INV 858 +#define SC_LDR 635 +#define SC_MAINMENU 4620 +#define SC_MAP 5222 +#define SC_TEST 903 +#define SC_TITLES 5166 +#define SND_CMN_031 3516 +#define SND_CMN_070 5199 +#define ST_LBN_0N 2832 +#define ST_LBN_0P 2833 +#define ST_LBN_1N 2753 +#define ST_LBN_1P 2754 +#define ST_LBN_2N 2756 +#define ST_LBN_2P 2757 +#define ST_LBN_3N 2759 +#define ST_LBN_3P 2760 +#define ST_LBN_4N 2762 +#define ST_LBN_4P 2763 +#define ST_LBN_5N 2765 +#define ST_LBN_5P 2766 +#define ST_LBN_6N 2768 +#define ST_LBN_6P 2769 +#define ST_LBN_7N 2771 +#define ST_LBN_7P 2772 +#define ST_LBN_8N 2774 +#define ST_LBN_8P 2775 +#define ST_LBN_9N 2777 +#define ST_LBN_9P 2778 +#define ST_MAN_EMPTY 476 +#define ST_MAN_RIGHT 325 +#define TrubaDown 697 +#define TrubaLeft 474 +#define TrubaRight 696 +#define TrubaUp 680 +#define rMV_MAN_LOOKUP 4775 + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_CONSTANTS_H */ diff --git a/engines/fullpipe/detection.cpp b/engines/fullpipe/detection.cpp new file mode 100644 index 0000000000..8c4a422333 --- /dev/null +++ b/engines/fullpipe/detection.cpp @@ -0,0 +1,112 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "base/plugins.h" + +#include "engines/advancedDetector.h" +#include "common/file.h" + +#include "fullpipe/fullpipe.h" + + +namespace Fullpipe { + +const char *FullpipeEngine::getGameId() const { + return _gameDescription->gameid; +} + +} + +static const PlainGameDescriptor fullpipeGames[] = { + {"fullpipe", "Full Pipe"}, + {0, 0} +}; + +namespace Fullpipe { + +static const ADGameDescription gameDescriptions[] = { + + // Fullpipe Russian version + { + "fullpipe", + 0, + AD_ENTRY1s("0654.sc2", "099f54f86d33ad2395f3b854b7e05058", 2272), + Common::RU_RUS, + Common::kPlatformWindows, + ADGF_DROPPLATFORM, + GUIO1(GUIO_NONE) + }, + + // Fullpipe German version + { + "fullpipe", + 0, + AD_ENTRY1s("0654.sc2", "d8743351fc53d205f42d91f6d791e51b", 2272), + Common::RU_RUS, + Common::kPlatformWindows, + ADGF_DROPPLATFORM, + GUIO1(GUIO_NONE) + }, + + AD_TABLE_END_MARKER +}; + +} // End of namespace Fullpipe + +class FullpipeMetaEngine : public AdvancedMetaEngine { +public: + FullpipeMetaEngine() : AdvancedMetaEngine(Fullpipe::gameDescriptions, sizeof(ADGameDescription), fullpipeGames) { + _singleid = "fullpipe"; + } + + virtual const char *getName() const { + return "Fullpipe Engine"; + } + + virtual const char *getOriginalCopyright() const { + return "Fullpipe Engine (C) Pipe Studio"; + } + + virtual bool hasFeature(MetaEngineFeature f) const; + virtual bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const; +}; + +bool FullpipeMetaEngine::hasFeature(MetaEngineFeature f) const { + return false; +} + +bool Fullpipe::FullpipeEngine::hasFeature(EngineFeature f) const { + return false; +} + +bool FullpipeMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const { + if (desc) { + *engine = new Fullpipe::FullpipeEngine(syst, desc); + } + return desc != 0; +} + +#if PLUGIN_ENABLED_DYNAMIC(FULLPIPE) + REGISTER_PLUGIN_DYNAMIC(FULLPIPE, PLUGIN_TYPE_ENGINE, FullpipeMetaEngine); +#else + REGISTER_PLUGIN_STATIC(FULLPIPE, PLUGIN_TYPE_ENGINE, FullpipeMetaEngine); +#endif diff --git a/engines/fullpipe/fullpipe.cpp b/engines/fullpipe/fullpipe.cpp new file mode 100644 index 0000000000..11808e95c2 --- /dev/null +++ b/engines/fullpipe/fullpipe.cpp @@ -0,0 +1,441 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "base/plugins.h" + +#include "common/archive.h" +#include "common/config-manager.h" + +#include "engines/util.h" + +#include "fullpipe/fullpipe.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/messages.h" +#include "fullpipe/behavior.h" +#include "fullpipe/modal.h" +#include "fullpipe/input.h" +#include "fullpipe/scenes.h" + +namespace Fullpipe { + +FullpipeEngine *g_fullpipe = 0; +Vars *g_vars = 0; + +FullpipeEngine::FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc) : Engine(syst), _gameDescription(gameDesc) { + // Setup mixer + if (!_mixer->isReady()) { + warning("Sound initialization failed."); + } + + _mixer->setVolumeForSoundType(Audio::Mixer::kSFXSoundType, ConfMan.getInt("sfx_volume")); + _mixer->setVolumeForSoundType(Audio::Mixer::kMusicSoundType, ConfMan.getInt("music_volume")); + + _rnd = new Common::RandomSource("fullpipe"); + + _gameProjectVersion = 0; + _pictureScale = 8; + _scrollSpeed = 0; + _currSoundListCount = 0; + _globalPalette = 0; + + _updateTicks = 0; + _lastInputTicks = 0; + _lastButtonUpTicks = 0; + + _currArchive = 0; + + _soundEnabled = true; + _flgSoundList = true; + + _sfxVolume = 0; + + _inputController = 0; + _inputDisabled = false; + + _modalObject = 0; + + _gameContinue = true; + _needRestart = false; + _flgPlayIntro = false; + _gamePaused = false; + _inputArFlag = false; + _recordEvents = false; + + _flgGameIsRunning = true; + + _isProcessingMessages = false; + + _musicAllowed = -1; + + _aniMan = 0; + _aniMan2 = 0; + _currentScene = 0; + _scene2 = 0; + _movTable = 0; + + _globalMessageQueueList = 0; + _messageHandlers = 0; + + _updateScreenCallback = 0; + _updateCursorCallback = 0; + + _msgX = 0; + _msgY = 0; + _msgObjectId2 = 0; + _msgId = 0; + _mouseVirtX = 0; + _mouseVirtY = 0; + + _currSelectedInventoryItemId = 0; + + _behaviorManager = 0; + + _cursorId = 0; + + _keyState = Common::KEYCODE_INVALID; + _buttonState = 0; + + _gameLoader = 0; + _gameProject = 0; + + _updateFlag = true; + _flgCanOpenMap = true; + + _sceneWidth = 1; + _sceneHeight = 1; + + for (int i = 0; i < 11; i++) + _currSoundList1[i] = 0; + + for (int i = 0; i < 200; i++) + _mapTable[i] = 0; + + _inventoryScene = 0; + _inventory = 0; + + _minCursorId = 0xffff; + _maxCursorId = 0; + _objectAtCursor = 0; + _objectIdAtCursor = 0; + + _isSaveAllowed = true; + + g_fullpipe = this; + g_vars = new Vars; +} + +FullpipeEngine::~FullpipeEngine() { + delete _rnd; + delete _globalMessageQueueList; +} + +void FullpipeEngine::initialize() { + _globalMessageQueueList = new GlobalMessageQueueList; + _behaviorManager = new BehaviorManager; + + _sceneRect.left = 0; + _sceneRect.top = 0; + _sceneRect.right = 799; + _sceneRect.bottom = 599; +} + +Common::Error FullpipeEngine::run() { + const Graphics::PixelFormat format(2, 5, 6, 5, 0, 11, 5, 0, 0); + // Initialize backend + initGraphics(800, 600, true, &format); + + _backgroundSurface.create(800, 600, format); + + initialize(); + + _isSaveAllowed = false; + + int scene = 0; + if (ConfMan.hasKey("boot_param")) + scene = ConfMan.getInt("boot_param"); + + if (!loadGam("fullpipe.gam", scene)) + return Common::kNoGameDataFoundError; + +#if 0 + loadAllScenes(); +#endif + + _gameContinue = true; + + while (_gameContinue) { + updateEvents(); + + updateScreen(); + + if (_needRestart) { + if (_modalObject) { + delete _modalObject; + _modalObject = 0; + } + + freeGameLoader(); + _currentScene = 0; + _updateTicks = 0; + + loadGam("fullpipe.gam"); + _needRestart = false; + } + + _system->delayMillis(10); + _system->updateScreen(); + } + + freeGameLoader(); + + cleanup(); + + return Common::kNoError; +} + +void FullpipeEngine::updateEvents() { + Common::Event event; + Common::EventManager *eventMan = _system->getEventManager(); + ExCommand *ex; + + while (eventMan->pollEvent(event)) { + switch (event.type) { + case Common::EVENT_KEYDOWN: + _keyState = event.kbd.keycode; + + switch (event.kbd.keycode) { + case Common::KEYCODE_SPACE: + if (_gamePaused) { + if (_modalObject) { + if (_modalObject->init(42)) { + _modalObject->update(); + } else { + _modalObject->saveload(); + CBaseModalObject *obj = _modalObject->_parentObj; + if (obj) + delete _modalObject; + _modalObject = obj; + } + } else { + _gameLoader->updateSystems(42); + } + return; + } + + ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = 32; + ex->_excFlags |= 3; + ex->handle(); + break; + case Common::KEYCODE_s: + if (_gamePaused) { + _gamePaused = 0; + _flgGameIsRunning = true; + return; + } + + ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = 83; + ex->_excFlags |= 3; + ex->handle(); + break; + case Common::KEYCODE_q: + return; + break; + default: + ex = new ExCommand(0, 17, 36, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = event.kbd.keycode; + ex->_excFlags |= 3; + ex->handle(); + break; + } + break; + case Common::EVENT_KEYUP: + if (!_inputArFlag) { + ex = new ExCommand(0, 17, 37, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->handle(); + } + _keyState = Common::KEYCODE_INVALID; + break; + case Common::EVENT_MOUSEMOVE: + if (_recordEvents) { + ex = new ExCommand(0, 17, 31, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->handle(); + } + + _mouseScreenPos = event.mouse; + break; + case Common::EVENT_QUIT: + _gameContinue = false; + break; + case Common::EVENT_RBUTTONDOWN: + if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) { + ex = new ExCommand(0, 17, 107, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + _lastInputTicks = _updateTicks; + ex->handle(); + } + break; + case Common::EVENT_LBUTTONDOWN: + if (!_inputArFlag && (_updateTicks - _lastInputTicks) >= 2) { + ex = new ExCommand(0, 17, 29, event.mouse.x, event.mouse.y, 0, 1, 0, 0, 0); + + ex->_sceneClickX = _sceneRect.left + ex->_x; + ex->_sceneClickY = _sceneRect.top + ex->_y; + ex->_keyCode = getGameLoaderInventory()->getSelectedItemId(); + ex->_excFlags |= 3; + _lastInputTicks = _updateTicks; + ex->handle(); + } + break; + case Common::EVENT_LBUTTONUP: + if (!_inputArFlag && (_updateTicks - _lastButtonUpTicks) >= 2) { + ex = new ExCommand(0, 17, 30, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + _lastButtonUpTicks = _updateTicks; + ex->handle(); + } + break; + default: + break; + } + } + + +#if 0 + warning("STUB: FullpipeEngine::updateEvents() <mainWindowProc>"); + if (Msg == MSG_SC11_SHOWSWING && _modalObject) { + _modalObject->method14(); + } +#endif +} + +void FullpipeEngine::freeGameLoader() { + warning("STUB: FullpipeEngine::freeGameLoader()"); +} + +void FullpipeEngine::cleanup() { + warning("STUB: FullpipeEngine::cleanup()"); +} + +void FullpipeEngine::updateScreen() { + debug(4, "FullpipeEngine::updateScreen()"); + + _mouseVirtX = _mouseScreenPos.x + _sceneRect.left; + _mouseVirtY = _mouseScreenPos.y + _sceneRect.top; + + //if (inputArFlag) + // updateGame_inputArFlag(); + + if (_modalObject || (_flgGameIsRunning && (_gameLoader->updateSystems(42), _modalObject != 0))) { + if (_flgGameIsRunning) { + if (_modalObject->init(42)) { + _modalObject->update(); + } else { + _modalObject->saveload(); + CBaseModalObject *tmp = _modalObject->_parentObj; + + delete _modalObject; + + _modalObject = tmp; + } + } + } else if (_currentScene) { + _currentScene->draw(); + + if (_inventoryScene) + _inventory->draw(); + + if (_updateScreenCallback) + _updateScreenCallback(); + + //if (inputArFlag && _currentScene) { + // vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "DEMO", 4, 380, 580); + // vrtTextOut(*(_DWORD *)g_vrtHandle, smallNftData, "Alt+F4 - exit", 14, 695, 580); + //} + } else { + //vrtRectangle(*(_DWORD *)g_vrtHandle, 0, 0, 0, 800, 600); + } + _inputController->drawCursor(_mouseScreenPos.x, _mouseScreenPos.y); + + ++_updateTicks; +} + +int FullpipeEngine::getObjectEnumState(const char *name, const char *state) { + CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (!var) { + var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0); + } + + var = var->getSubVarByName(name); + if (var) { + var = var->getSubVarByName("ENUMSTATES"); + if (var) + return var->getSubVarAsInt(state); + } + + return 0; +} + +int FullpipeEngine::getObjectState(const char *objname) { + CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (var) + return var->getSubVarAsInt(objname); + + return 0; +} + +void FullpipeEngine::setObjectState(const char *name, int state) { + CGameVar *var = _gameLoader->_gameVar->getSubVarByName("OBJSTATES"); + + if (!var) { + var = _gameLoader->_gameVar->addSubVarAsInt("OBJSTATES", 0); + } + + var->setSubVarAsInt(name, state); +} + +void FullpipeEngine::updateMapPiece(int mapId, int update) { + for (int i = 0; i < 200; i++) { + int hiWord = (_mapTable[i] >> 16) & 0xffff; + + if (hiWord == mapId) { + _mapTable[i] |= update; + return; + } + if (!hiWord) { + _mapTable[i] = (mapId << 16) | update; + return; + } + } +} + +void FullpipeEngine::disableSaves(ExCommand *ex) { + warning("STUB: FullpipeEngine::disableSaves()"); +} + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/fullpipe.h b/engines/fullpipe/fullpipe.h new file mode 100644 index 0000000000..f688151267 --- /dev/null +++ b/engines/fullpipe/fullpipe.h @@ -0,0 +1,241 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_FULLPIPE_H +#define FULLPIPE_FULLPIPE_H + +#include "common/scummsys.h" +#include "common/events.h" +#include "common/keyboard.h" +#include "common/random.h" +#include "common/savefile.h" +#include "common/system.h" + +#include "audio/mixer.h" + +#include "graphics/surface.h" + +#include "engines/engine.h" + +struct ADGameDescription; + +namespace Fullpipe { + +enum FullpipeGameFeatures { +}; + +class BehaviorManager; +class CBaseModalObject; +class CGameLoader; +class CGameVar; +class CInputController; +class CInventory2; +struct CursorInfo; +struct EntranceInfo; +class ExCommand; +class GameProject; +class GameObject; +class GlobalMessageQueueList; +struct MessageHandler; +struct MovTable; +class NGIArchive; +class Scene; +class SoundList; +class StaticANIObject; +class Vars; + +int global_messageHandler1(ExCommand *cmd); +int global_messageHandler2(ExCommand *cmd); +int global_messageHandler3(ExCommand *cmd); +int global_messageHandler4(ExCommand *cmd); +void global_messageHandler_handleSound(ExCommand *cmd); + + +class FullpipeEngine : public ::Engine { +protected: + + Common::Error run(); + +public: + FullpipeEngine(OSystem *syst, const ADGameDescription *gameDesc); + virtual ~FullpipeEngine(); + + void initialize(); + + void setMusicAllowed(int val) { _musicAllowed = val; } + + // Detection related functions + const ADGameDescription *_gameDescription; + const char *getGameId() const; + Common::Platform getPlatform() const; + bool hasFeature(EngineFeature f) const; + + Common::RandomSource *_rnd; + + Common::KeyCode _keyState; + uint16 _buttonState; + + void updateEvents(); + + Graphics::Surface _backgroundSurface; + + CGameLoader *_gameLoader; + GameProject *_gameProject; + bool loadGam(const char *fname, int scene = 0); + + CGameVar *getGameLoaderGameVar(); + CInputController *getGameLoaderInputController(); + + int _gameProjectVersion; + int _pictureScale; + int _scrollSpeed; + bool _updateFlag; + bool _flgCanOpenMap; + bool _gamePaused; + bool _flgGameIsRunning; + bool _inputArFlag; + bool _recordEvents; + + Common::Rect _sceneRect; + int _sceneWidth; + int _sceneHeight; + Scene *_currentScene; + Scene *_scene2; + StaticANIObject *_aniMan; + StaticANIObject *_aniMan2; + byte *_globalPalette; + + CInputController *_inputController; + bool _inputDisabled; + + void defHandleKeyDown(int key); + + SoundList *_currSoundList1[11]; + int _currSoundListCount; + bool _soundEnabled; + bool _flgSoundList; + + void stopAllSounds(); + void toggleMute(); + void playSound(int id, int flag); + void startSceneTrack(); + + int _sfxVolume; + + GlobalMessageQueueList *_globalMessageQueueList; + MessageHandler *_messageHandlers; + + int _msgX; + int _msgY; + int _msgObjectId2; + int _msgId; + + Common::List<ExCommand *> _exCommandList; + bool _isProcessingMessages; + + int _mouseVirtX; + int _mouseVirtY; + Common::Point _mouseScreenPos; + + BehaviorManager *_behaviorManager; + + MovTable *_movTable; + + void initMap(); + void updateMapPiece(int mapId, int update); + void updateScreen(); + + void freeGameLoader(); + void cleanup(); + + bool _gameContinue; + bool _needRestart; + bool _flgPlayIntro; + int _musicAllowed; + + void enableSaves() { _isSaveAllowed = true; } + void disableSaves(ExCommand *ex); + + void initObjectStates(); + void setLevelStates(); + void setSwallowedEggsState(); + void loadAllScenes(); + + void initCursors(); + void addCursor(CursorInfo *cursorInfo, Scene *inv, int pictureId, int hotspotX, int hotspotY, int itemPictureOffsX, int itemPictureOffsY); + + int32 _mapTable[200]; + + Scene *_inventoryScene; + CInventory2 *_inventory; + int _currSelectedInventoryItemId; + + int32 _updateTicks; + int32 _lastInputTicks; + int32 _lastButtonUpTicks; + + CBaseModalObject *_modalObject; + + int (*_updateScreenCallback)(); + int (*_updateCursorCallback)(); + + int _cursorId; + int _minCursorId; + int _maxCursorId; + Common::Array<int> _objectIdCursors; + GameObject *_objectAtCursor; + int _objectIdAtCursor; + + void setCursor(int id); + void updateCursorsCommon(); + + int getObjectState(const char *objname); + void setObjectState(const char *name, int state); + int getObjectEnumState(const char *name, const char *state); + + bool sceneSwitcher(EntranceInfo *entrance); + Scene *accessScene(int sceneId); + void setSceneMusicParameters(CGameVar *var); + + NGIArchive *_currArchive; + + void openMap(); + void openHelp(); + void openMainMenu(); + + int lift_getButtonIdP(int objid); + +public: + + bool _isSaveAllowed; + + bool canLoadGameStateCurrently() { return _isSaveAllowed; } + bool canSaveGameStateCurrently() { return _isSaveAllowed; } + +}; + +extern FullpipeEngine *g_fullpipe; +extern Vars *g_vars; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_FULLPIPE_H */ diff --git a/engines/fullpipe/gameloader.cpp b/engines/fullpipe/gameloader.cpp new file mode 100644 index 0000000000..a44501b17d --- /dev/null +++ b/engines/fullpipe/gameloader.cpp @@ -0,0 +1,342 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/gameloader.h" +#include "fullpipe/scene.h" +#include "fullpipe/input.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +CInventory2 *getGameLoaderInventory() { + return &g_fullpipe->_gameLoader->_inventory; +} + +CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId) { + for (uint i = 0; i < g_fullpipe->_gameLoader->_sc2array.size(); i++) + if (g_fullpipe->_gameLoader->_sc2array[i]._sceneId == sceneId) + return (CMctlCompound *)g_fullpipe->_gameLoader->_sc2array[i]._motionController; + + return 0; +} + +CInteractionController *getGameLoaderInteractionController() { + return g_fullpipe->_gameLoader->_interactionController; +} + +CGameLoader::CGameLoader() { + _interactionController = new CInteractionController(); + _inputController = new CInputController(); + + _gameProject = 0; + _gameName = 0; + + addMessageHandlerByIndex(global_messageHandler2, 0, 0); + insertMessageHandler(global_messageHandler3, 0, 128); + insertMessageHandler(global_messageHandler4, 0, 1); + + _field_FA = 0; + _field_F8 = 0; + _sceneSwitcher = 0; + _preloadCallback = 0; + _readSavegameCallback = 0; + _gameVar = 0; + _preloadSceneId = 0; + _preloadEntranceId = 0; + _updateCounter = 0; + + g_fullpipe->_msgX = 0; + g_fullpipe->_msgY = 0; + g_fullpipe->_msgObjectId2 = 0; + g_fullpipe->_msgId = 0; +} + +CGameLoader::~CGameLoader() { + free(_gameName); + delete _gameProject; + delete _interactionController; + delete _inputController; +} + +bool CGameLoader::load(MfcArchive &file) { + debug(5, "CGameLoader::load()"); + + _gameName = file.readPascalString(); + debug(6, "_gameName: %s", _gameName); + + _gameProject = new GameProject(); + + _gameProject->load(file); + + g_fullpipe->_gameProject = _gameProject; + + if (g_fullpipe->_gameProjectVersion < 12) { + error("Old gameProjectVersion: %d", g_fullpipe->_gameProjectVersion); + } + + _gameName = file.readPascalString(); + debug(6, "_gameName: %s", _gameName); + + _inventory.load(file); + + _interactionController->load(file); + + debug(6, "sceneTag count: %d", _gameProject->_sceneTagList->size()); + + _sc2array.resize(_gameProject->_sceneTagList->size()); + + int i = 0; + for (SceneTagList::const_iterator it = _gameProject->_sceneTagList->begin(); it != _gameProject->_sceneTagList->end(); ++it, i++) { + char tmp[12]; + + snprintf(tmp, 11, "%04d.sc2", it->_sceneId); + + debug(2, "sc: %s", tmp); + + _sc2array[i].loadFile((const char *)tmp); + } + + _preloadItems.load(file); + + _field_FA = file.readUint16LE(); + _field_F8 = file.readUint16LE(); + + _gameVar = (CGameVar *)file.readClass(); + + return true; +} + +bool CGameLoader::loadScene(int sceneId) { + SceneTag *st; + + int idx = getSceneTagBySceneId(sceneId, &st); + + if (idx < 0) + return false; + + if (!st->_scene) + st->loadScene(); + + if (st->_scene) { + st->_scene->init(); + + applyPicAniInfos(st->_scene, _sc2array[idx]._defPicAniInfos, _sc2array[idx]._defPicAniInfosCount); + applyPicAniInfos(st->_scene, _sc2array[idx]._picAniInfos, _sc2array[idx]._picAniInfosCount); + + _sc2array[idx]._scene = st->_scene; + _sc2array[idx]._isLoaded = 1; + + return true; + } + + return false; +} + +bool CGameLoader::gotoScene(int sceneId, int entranceId) { + SceneTag *st; + + int sc2idx = getSceneTagBySceneId(sceneId, &st); + + if (sc2idx < 0) + return false; + + if (!_sc2array[sc2idx]._isLoaded) + return 0; + + if (_sc2array[sc2idx]._entranceDataCount < 1) { + g_fullpipe->_currentScene = st->_scene; + return true; + } + + if (_sc2array[sc2idx]._entranceDataCount <= 0) + return false; + + if (sceneId == 726) + return true; + + int entranceIdx; + for (entranceIdx = 0; _sc2array[sc2idx]._entranceData[entranceIdx]->_field_4 != entranceId; entranceIdx++) { + if (entranceIdx >= _sc2array[sc2idx]._entranceDataCount) + return false; + } + + CGameVar *sg = _gameVar->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); + + if (sg || (sg = _gameVar->getSubVarByName("OBJSTATES")->addSubVarAsInt("SAVEGAME", 0)) != 0) + sg->setSubVarAsInt("Entrance", entranceId); + + if (!g_fullpipe->sceneSwitcher(_sc2array[sc2idx]._entranceData[entranceIdx])) + return false; + + g_fullpipe->_msgObjectId2 = 0; + g_fullpipe->_msgY = -1; + g_fullpipe->_msgX = -1; + + g_fullpipe->_currentScene = st->_scene; + + MessageQueue *mq1 = g_fullpipe->_currentScene->getMessageQueueById(_sc2array[sc2idx]._entranceData[entranceIdx]->_messageQueueId); + if (mq1) { + MessageQueue *mq = new MessageQueue(mq1, 0, 0); + + StaticANIObject *stobj = g_fullpipe->_currentScene->getStaticANIObject1ById(_field_FA, -1); + if (stobj) { + stobj->_flags &= 0x100; + + ExCommand *ex = new ExCommand(stobj->_id, 34, 256, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_14 = 256; + ex->_messageNum = 0; + ex->_excFlags |= 3; + + mq->_exCommands.push_back(ex); + } + + mq->setFlags(mq->getFlags() | 1); + + if (!mq->chain(0)) { + delete mq; + + return false; + } + } else { + StaticANIObject *stobj = g_fullpipe->_currentScene->getStaticANIObject1ById(_field_FA, -1); + if (stobj) + stobj->_flags &= 0xfeff; + } + + return true; +} + +bool CGameLoader::preloadScene(int sceneId, int entranceId) { + warning("STUB: preloadScene(%d, %d), ", sceneId, entranceId); + + return true; +} + +int CGameLoader::getSceneTagBySceneId(int sceneId, SceneTag **st) { + if (_sc2array.size() > 0 && _gameProject->_sceneTagList->size() > 0) { + for (uint i = 0; i < _sc2array.size(); i++) { + if (_sc2array[i]._sceneId == sceneId) { + int num = 0; + for (SceneTagList::iterator s = _gameProject->_sceneTagList->begin(); s != _gameProject->_sceneTagList->end(); ++s, num++) { + if (s->_sceneId == sceneId) { + *st = &(*s); + return num; + } + } + } + } + } + + *st = 0; + return -1; +} + +void CGameLoader::applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount) { + if (picAniInfoCount <= 0) + return; + + debug(0, "CGameLoader::applyPicAniInfos(sc, ptr, %d)", picAniInfoCount); + + PictureObject *pict; + StaticANIObject *ani; + + for (int i = 0; i < picAniInfoCount; i++) { + debug(7, "PicAniInfo: id: %d type: %d", picAniInfo[i]->objectId, picAniInfo[i]->type); + if (picAniInfo[i]->type & 2) { + pict = sc->getPictureObjectById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); + if (pict) { + pict->setPicAniInfo(picAniInfo[i]); + continue; + } + pict = sc->getPictureObjectById(picAniInfo[i]->objectId, 0); + if (pict) { + PictureObject *pictNew = new PictureObject(pict); + + sc->_picObjList.push_back(pictNew); + pictNew->setPicAniInfo(picAniInfo[i]); + continue; + } + } else { + if (!(picAniInfo[i]->type & 1)) + continue; + + Scene *scNew = g_fullpipe->accessScene(picAniInfo[i]->sceneId); + if (!scNew) + continue; + + ani = sc->getStaticANIObject1ById(picAniInfo[i]->objectId, picAniInfo[i]->field_8); + if (ani) { + ani->setPicAniInfo(picAniInfo[i]); + continue; + } + + ani = scNew->getStaticANIObject1ById(picAniInfo[i]->objectId, 0); + if (ani) { + StaticANIObject *aniNew = new StaticANIObject(ani); + + sc->addStaticANIObject(aniNew, 1); + + aniNew->setPicAniInfo(picAniInfo[i]); + continue; + } + } + } +} + +void CGameLoader::updateSystems(int counterdiff) { + if (g_fullpipe->_currentScene) { + g_fullpipe->_currentScene->update(counterdiff); + + _exCommand._messageKind = 17; + _updateCounter++; + _exCommand._messageNum = 33; + _exCommand._excFlags = 0; + _exCommand.postMessage(); + } + + processMessages(); + + if (_preloadSceneId) { + processMessages(); + preloadScene(_preloadSceneId, _preloadEntranceId); + } +} + +CGameVar *FullpipeEngine::getGameLoaderGameVar() { + if (_gameLoader) + return _gameLoader->_gameVar; + else + return 0; +} + +CInputController *FullpipeEngine::getGameLoaderInputController() { + if (_gameLoader) + return _gameLoader->_inputController; + else + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gameloader.h b/engines/fullpipe/gameloader.h new file mode 100644 index 0000000000..a8d51cd794 --- /dev/null +++ b/engines/fullpipe/gameloader.h @@ -0,0 +1,77 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_GAMELOADER_H +#define FULLPIPE_GAMELOADER_H + +#include "fullpipe/objects.h" +#include "fullpipe/inventory.h" +#include "fullpipe/messages.h" + +namespace Fullpipe { + +class SceneTag; +class CMctlCompound; +class CInputController; +class CInteractionController; + +class CGameLoader : public CObject { + public: + CGameLoader(); + virtual ~CGameLoader(); + + virtual bool load(MfcArchive &file); + bool loadScene(int sceneId); + bool gotoScene(int sceneId, int entranceId); + bool preloadScene(int sceneId, int entranceId); + + void updateSystems(int counterdiff); + + int getSceneTagBySceneId(int sceneId, SceneTag **st); + void applyPicAniInfos(Scene *sc, PicAniInfo **picAniInfo, int picAniInfoCount); + + GameProject *_gameProject; + CInteractionController *_interactionController; + CInputController *_inputController; + CInventory2 _inventory; + Sc2Array _sc2array; + void *_sceneSwitcher; + void *_preloadCallback; + void *_readSavegameCallback; + int16 _field_F8; + int16 _field_FA; + PreloadItems _preloadItems; + CGameVar *_gameVar; + char *_gameName; + ExCommand _exCommand; + int _updateCounter; + int _preloadSceneId; + int _preloadEntranceId; +}; + +CInventory2 *getGameLoaderInventory(); +CInteractionController *getGameLoaderInteractionController(); +CMctlCompound *getSc2MctlCompoundBySceneId(int16 sceneId); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_GAMELOADER_H */ diff --git a/engines/fullpipe/gfx.cpp b/engines/fullpipe/gfx.cpp new file mode 100644 index 0000000000..e16d56cd8d --- /dev/null +++ b/engines/fullpipe/gfx.cpp @@ -0,0 +1,1236 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/gfx.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/interaction.h" +#include "fullpipe/gameloader.h" + +#include "common/memstream.h" + +namespace Fullpipe { + +Bitmap::Bitmap() { + _x = 0; + _y = 0; + _width = 0; + _height = 0; + _pixels = 0; + _type = 0; + _dataSize = 0; + _flags = 0; +} + +Bitmap::Bitmap(Bitmap *src) { + _x = src->_x; + _y = src->_y; + _flags = src->_flags; + _dataSize = src->_dataSize; + _type = src->_type; + _width = src->_width; + _height = src->_height; + _pixels = src->_pixels; +} + +Bitmap::~Bitmap() { + if (_pixels) + free(_pixels); +} + +void Bitmap::load(Common::ReadStream *s) { + debug(5, "Bitmap::load()"); + + _x = s->readUint32LE(); + _y = s->readUint32LE(); + _width = s->readUint32LE(); + _height = s->readUint32LE(); + s->readUint32LE(); // pixels + _type = s->readUint32LE(); + _dataSize = s->readUint32LE(); + _flags = s->readUint32LE(); + + debug(8, "Bitmap: x: %d y: %d w: %d h: %d dataSize: 0x%x", _x, _y, _width, _height, _dataSize); + debug(8, "Bitmap: type: %s (0x%04x) flags: 0x%x", Common::tag2string(_type).c_str(), _type, _flags); +} + +Background::Background() { + _x = 0; + _y = 0; + _messageQueueId = 0; + _bigPictureArray1Count = 0; + _bigPictureArray2Count = 0; + _bigPictureArray = 0; + _bgname = 0; + _palette = 0; +} + +bool Background::load(MfcArchive &file) { + debug(5, "Background::load()"); + _bgname = file.readPascalString(); + + int count = file.readUint16LE(); + + for (int i = 0; i < count; i++) { + PictureObject *pct = new PictureObject(); + + pct->load(file, i == 0); + addPictureObject(pct); + } + + assert(g_fullpipe->_gameProjectVersion >= 4); + + _bigPictureArray1Count = file.readUint32LE(); + + assert(g_fullpipe->_gameProjectVersion >= 5); + + _bigPictureArray2Count = file.readUint32LE(); + + _bigPictureArray = (BigPicture ***)calloc(_bigPictureArray1Count, sizeof(BigPicture **)); + + debug(6, "bigPictureArray[%d][%d]", _bigPictureArray1Count, _bigPictureArray2Count); + + for (int i = 0; i < _bigPictureArray1Count; i++) { + _bigPictureArray[i] = (BigPicture **)calloc(_bigPictureArray2Count, sizeof(BigPicture *)); + for (int j = 0; j < _bigPictureArray2Count; j++) { + _bigPictureArray[i][j] = new BigPicture(); + + _bigPictureArray[i][j]->load(file); + } + } + + return true; +} + +void Background::addPictureObject(PictureObject *pct) { + if (pct->_okeyCode) + pct->renumPictures(&_picObjList); + + bool inserted = false; + for (uint i = 0; i < _picObjList.size(); i++) { + if (((PictureObject *)_picObjList[i])->_priority == pct->_priority) { + _picObjList.insert_at(i, pct); + inserted = true; + break; + } + } + + if (!inserted) { + _picObjList.push_back(pct); + } +} + +PictureObject::PictureObject() { + _ox = 0; + _oy = 0; + _picture = 0; + _ox2 = 0; + _oy2 = 0; + _pictureObject2List = 0; + _objtype = kObjTypePictureObject; +} + +PictureObject::PictureObject(PictureObject *src) : GameObject(src) { + _picture = src->_picture; + _ox2 = _ox; + _oy2 = _oy; + _pictureObject2List = src->_pictureObject2List; + _objtype = kObjTypePictureObject; +} + +bool PictureObject::load(MfcArchive &file, bool bigPicture) { + debug(5, "PictureObject::load()"); + GameObject::load(file); + + if (bigPicture) + _picture = new BigPicture(); + else + _picture = new Picture(); + + _picture->load(file); + + _pictureObject2List = new CPtrList(); + + int count = file.readUint16LE(); + + if (count > 0) { + GameObject *o = new GameObject(); + + o->load(file); + _pictureObject2List->push_back(o); + } + + _ox2 = _ox; + _oy2 = _oy; + +#if 0 + _picture->displayPicture(); +#endif + + return true; +} + +Common::Point *PictureObject::getDimensions(Common::Point *p) { + _picture->getDimensions(p); + + return p; +} + +void PictureObject::draw() { + if (_flags & 1) + _picture->draw(_ox, _oy, 2, 0); + else + _picture->draw(_ox, _oy, 0, 0); +} + +void PictureObject::drawAt(int x, int y) { + if (x == -1) + x = _ox; + if (y == -1) + y = _oy; + + _picture->_x = x; + _picture->_y = y; + + if (_flags & 1) + _picture->draw(x, y, 2, 0); + else + _picture->draw(x, y, 0, 0); +} + +bool PictureObject::setPicAniInfo(PicAniInfo *picAniInfo) { + if (!(picAniInfo->type & 2) || (picAniInfo->type & 1)) { + error("Picture::setPicAniInfo(): Wrong type: %d", picAniInfo->type); + + return false; + } + + if (picAniInfo->type & 2) { + setOXY(picAniInfo->ox, picAniInfo->oy); + _priority = picAniInfo->priority; + _okeyCode = picAniInfo->field_8; + setFlags(picAniInfo->flags); + _field_8 = picAniInfo->field_24; + + return true; + } + + return false; +} + +bool PictureObject::isPointInside(int x, int y) { + bool res; + int oldx = _picture->_x; + int oldy = _picture->_y; + + _picture->_x = _ox; + _picture->_y = _oy; + + res = _picture->isPointInside(x, y); + + _picture->_x = oldx; + _picture->_y = oldy; + + return res; +} + +bool PictureObject::isPixelHitAtPos(int x, int y) { + int oldx = _picture->_x; + int oldy = _picture->_y; + + _picture->_x = _ox; + _picture->_y = _oy; + bool res = _picture->isPixelHitAtPos(x, y); + _picture->_x = oldx; + _picture->_y = oldy; + + return res; +} + +GameObject::GameObject() { + _okeyCode = 0; + _flags = 0; + _id = 0; + _ox = 0; + _oy = 0; + _priority = 0; + _field_20 = 0; + _field_8 = 0; + _objectName = 0; +} + +GameObject::GameObject(GameObject *src) { + _okeyCode = 1; + _flags = 0; + _id = src->_id; + + _objectName = (char *)calloc(strlen(src->_objectName) + 1, 1); + strncpy(_objectName, src->_objectName, strlen(src->_objectName)); + + _ox = src->_ox; + _oy = src->_oy; + _priority = src->_priority; + _field_20 = 1; + _field_8 = src->_field_8; +} + +GameObject::~GameObject() { + free(_objectName); +} + +bool GameObject::load(MfcArchive &file) { + debug(5, "GameObject::load()"); + _okeyCode = 0; + _flags = 0; + _field_20 = 0; + + _id = file.readUint16LE(); + + _objectName = file.readPascalString(); + _ox = file.readUint32LE(); + _oy = file.readUint32LE(); + _priority = file.readUint16LE(); + + if (g_fullpipe->_gameProjectVersion >= 11) { + _field_8 = file.readUint32LE(); + } + + return true; +} + +void GameObject::setOXY(int x, int y) { + _ox = x; + _oy = y; +} + +void GameObject::renumPictures(CPtrList *lst) { + int *buf = (int *)calloc(lst->size() + 2, sizeof(int)); + + for (uint i = 0; i < lst->size(); i++) { + if (_id == ((PictureObject *)((*lst)[i]))->_id) + buf[((PictureObject *)((*lst)[i]))->_okeyCode] = 1; + } + + if (buf[_okeyCode]) { + uint count; + for (count = 1; buf[count] && count < lst->size() + 2; count++) + ; + _okeyCode = count; + } + + free(buf); +} + +bool GameObject::getPicAniInfo(PicAniInfo *info) { + if (_objtype == kObjTypePictureObject) { + info->type = 2; + info->objectId = _id; + info->sceneId = 0; + info->field_8 = _okeyCode; + info->flags = _flags; + info->field_24 = _field_8; + info->ox = _ox; + info->oy = _oy; + info->priority = _priority; + + return true; + } + + if (_objtype == kObjTypeStaticANIObject) { + StaticANIObject *ani = (StaticANIObject *)this; + + info->type = (ani->_messageQueueId << 16) | 1; + info->objectId = ani->_id; + info->field_8 = ani->_okeyCode; + info->sceneId = ani->_sceneId; + info->flags = ani->_flags; + info->field_24 = ani->_field_8; + if (ani->_movement) { + info->ox = ani->_movement->_ox; + info->oy = ani->_movement->_oy; + } else { + info->ox = ani->_ox; + info->oy = ani->_oy; + } + info->priority = ani->_priority; + + if (ani->_statics) + info->staticsId = ani->_statics->_staticsId; + + if (ani->_movement) { + info->movementId = ani->_movement->_id; + info->dynamicPhaseIndex = ani->_movement->_currDynamicPhaseIndex; + } + + info->someDynamicPhaseIndex = ani->_someDynamicPhaseIndex; + + return true; + } + + return false; +} + +bool GameObject::setPicAniInfo(PicAniInfo *picAniInfo) { + if (!(picAniInfo->type & 3)) { + warning("StaticANIObject::setPicAniInfo(): Wrong type: %d", picAniInfo->type); + + return false; + } + + if (picAniInfo->type & 3) { + setOXY(picAniInfo->ox, picAniInfo->oy); + _priority = picAniInfo->priority; + _okeyCode = picAniInfo->field_8; + setFlags(picAniInfo->flags); + _field_8 = picAniInfo->field_24; + } + + if (picAniInfo->type & 1) { + StaticANIObject *ani = (StaticANIObject *)this; + + ani->_messageQueueId = (picAniInfo->type >> 16) & 0xffff; + + if (picAniInfo->staticsId) { + ani->_statics = ani->getStaticsById(picAniInfo->staticsId); + } else { + ani->_statics = 0; + } + + if (picAniInfo->movementId) { + ani->_movement = ani->getMovementById(picAniInfo->movementId); + if (ani->_movement) + ani->_movement->setDynamicPhaseIndex(picAniInfo->dynamicPhaseIndex); + } else { + ani->_movement = 0; + } + + ani->setSomeDynamicPhaseIndex(picAniInfo->someDynamicPhaseIndex); + } + + return true; +} + +Picture::Picture() { + _x = 0; + _y = 0; + _field_44 = 0; + _field_54 = 0; + _bitmap = 0; + _alpha = -1; + _paletteData = 0; + _convertedBitmap = 0; + _memoryObject2 = 0; + _width = 0; + _height = 0; +} + +Picture::~Picture() { + freePicture(); + + _bitmap = 0; + + if (_memoryObject2) + delete _memoryObject2; + + if (_paletteData) + free(_paletteData); + + if (_convertedBitmap) { + delete _convertedBitmap; + _convertedBitmap = 0; + } +} + +void Picture::freePicture() { + if (_bitmap) { + if (testFlags() && !_field_54) { + freeData(); + delete _bitmap; + _bitmap = 0; + } + } + + if (_bitmap) { + _bitmap = 0; + _data = 0; + } + + if (_convertedBitmap) { + free(_convertedBitmap->_pixels); + delete _convertedBitmap; + _convertedBitmap = 0; + } +} + +bool Picture::load(MfcArchive &file) { + debug(5, "Picture::load()"); + MemoryObject::load(file); + + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _field_44 = file.readUint16LE(); + + assert(g_fullpipe->_gameProjectVersion >= 2); + + _width = file.readUint32LE(); + _height = file.readUint32LE(); + + _mflags |= 1; + + _memoryObject2 = new MemoryObject2; + _memoryObject2->load(file); + + if (_memoryObject2->_data) { + setAOIDs(); + } + + assert (g_fullpipe->_gameProjectVersion >= 12); + + _alpha = file.readUint32LE() & 0xff; + + int havePal = file.readUint32LE(); + + if (havePal > 0) { + _paletteData = (byte *)calloc(1024, 1); + file.read(_paletteData, 1024); + } + + getData(); + + debug(5, "Picture::load: <%s>", _memfilename); + + return true; +} + +void Picture::setAOIDs() { + int w = (g_fullpipe->_pictureScale + _width - 1) / g_fullpipe->_pictureScale; + int h = (g_fullpipe->_pictureScale + _height - 1) / g_fullpipe->_pictureScale; + + _memoryObject2->_rows = (byte **)malloc(w * sizeof(int *)); + + int pitch = 2 * h; + byte *ptr = _memoryObject2->getData(); + for (int i = 0; i < w; i++) { + _memoryObject2->_rows[i] = ptr; + ptr += pitch; + } +} + +void Picture::init() { + _bitmap = new Bitmap(); + + getDibInfo(); + + _bitmap->_flags |= 0x1000000; +} + +Common::Point *Picture::getDimensions(Common::Point *p) { + p->x = _width; + p->y = _height; + + return p; +} + +void Picture::getDibInfo() { + int off = _dataSize & ~0xf; + + debug(9, "Picture::getDibInfo: _dataSize: %d", _dataSize); + + if (!_dataSize) { + warning("Picture::getDibInfo(): Empty data size"); + return; + } + + if (_dataSize != off) { + warning("Uneven data size: 0x%x", _dataSize); + } + + Common::MemoryReadStream *s = new Common::MemoryReadStream(_data + off - 32, 32); + + _bitmap->load(s); + _bitmap->_pixels = _data; +} + +Bitmap *Picture::getPixelData() { + if (!_bitmap) + init(); + + return _bitmap; +} + +void Picture::draw(int x, int y, int style, int angle) { + int x1 = x; + int y1 = y; + + debug(0, "Picture::draw(%d, %d, %d, %d) (%s)", x, y, style, angle, _memfilename); + + if (x != -1) + x1 = x; + + if (y != -1) + y1 = y; + + if (!_bitmap) + init(); + + if (!_bitmap) + return; + + if ((_alpha & 0xff) < 0xff) { + debug(0, "Picture:draw: alpha = %0x", _alpha); + } + + byte *pal = _paletteData; + + if (!pal) { + //warning("Picture:draw: using global palette"); + pal = g_fullpipe->_globalPalette; + } + + Common::Point point; + + switch (style) { + case 1: + //flip + getDimensions(&point); + _bitmap->flipVertical()->drawShaded(1, x1, y1 + 30 + point.y, pal); + break; + case 2: + //vrtSetFadeRatio(g_vrtDrawHandle, 0.34999999); + //vrtSetFadeTable(g_vrtDrawHandle, &unk_477F88, 1.0, 1000.0, 0, 0); + _bitmap->drawShaded(2, x1, y1, pal); + //vrtSetFadeRatio(g_vrtDrawHandle, 0.0); + //vrtSetFadeTable(g_vrtDrawHandle, &unk_477F90, 1.0, 1000.0, 0, 0); + break; + default: + if (angle) + drawRotated(x1, y1, angle); + else { + _bitmap->putDib(x1, y1, (int32 *)pal); + } + } +} + +void Picture::drawRotated(int x, int y, int angle) { + warning("STUB: Picture::drawRotated(%d, %d, %d)", x, y, angle); +} + +void Picture::displayPicture() { + if (!g_fullpipe->_gameContinue) + return; + + getData(); + init(); + + if (!_dataSize) + return; + + g_fullpipe->_backgroundSurface.fillRect(Common::Rect(0, 0, 799, 599), 0); + g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(0, 0), g_fullpipe->_backgroundSurface.pitch, 0, 0, 799, 599); + + draw(0, 0, 0, 0); + + g_fullpipe->updateEvents(); + g_fullpipe->_system->delayMillis(10); + g_fullpipe->_system->updateScreen(); + + while (g_fullpipe->_gameContinue) { + g_fullpipe->updateEvents(); + g_fullpipe->_system->delayMillis(10); + g_fullpipe->_system->updateScreen(); + + if (g_fullpipe->_keyState == ' ') { + g_fullpipe->_keyState = Common::KEYCODE_INVALID; + break; + } + } +} + +void Picture::setPaletteData(byte *pal) { + if (_paletteData) + free(_paletteData); + + if (pal) { + _paletteData = (byte *)malloc(1024); + memcpy(_paletteData, pal, 1024); + } +} + +void Picture::copyMemoryObject2(Picture *src) { + if (_width == src->_width && _height == src->_height) { + if (src->_memoryObject2 && src->_memoryObject2->_rows && _memoryObject2) { + byte *data = loadData(); + _memoryObject2->copyData(data, _dataSize); + setAOIDs(); + } + } +} + +bool Picture::isPointInside(int x, int y) { + if (x >= _x) { + if (y >= _y && x < _x + _width && y < _y + _height) + return true; + } + return false; +} + +bool Picture::isPixelHitAtPos(int x, int y) { + if (x < _x || y < _y || x >= _x + _width || y >= _y + _height) + return false; + + if (!_bitmap) + init(); + + _bitmap->_x = _x; + _bitmap->_y = _y; + + return _bitmap->isPixelHitAtPos(x, y); +} + +int Picture::getPixelAtPos(int x, int y) { + return getPixelAtPosEx(x / g_fullpipe->_pictureScale, y / g_fullpipe->_pictureScale); + + return false; +} + +int Picture::getPixelAtPosEx(int x, int y) { + if (x < 0 || y < 0) + return 0; + + if (x < (g_fullpipe->_pictureScale + _width - 1) / g_fullpipe->_pictureScale && + y < (g_fullpipe->_pictureScale + _height - 1) / g_fullpipe->_pictureScale && + _memoryObject2 != 0 && _memoryObject2->_rows != 0) + return _memoryObject2->_rows[x][2 * y]; + + return 0; +} + +bool Bitmap::isPixelHitAtPos(int x, int y) { + if (x < _x || x >= _width + _x || y < _y || y >= _y + _height) + return false; + + int off; + + if (_type == 'CB\x05e') + off = 2 * ((_width + 1) / 2); + else + off = 4 * ((_width + 3) / 4); + + off = x + off * (_y + _height - y - 1) - _x; + + if (_flags & 0x1000000) { + switch (_type) { + case 'CB\0\0': + if (_pixels[off] == (_flags & 0xff)) + return false; + break; + case 'CB\x05e': + if (!*(int16 *)&_pixels[2 * off]) + return false; + break; + case 'RB\0\0': + return isPixelAtHitPosRB(x, y); + } + } + return true; +} + +bool Bitmap::isPixelAtHitPosRB(int x, int y) { + int ox = _x; + int oy = _y; + + _x = _y = 0; + + bool res = putDibRB(0, x, y); + _x = ox; + _y = oy; + + return res; +} + +void Bitmap::putDib(int x, int y, int32 *palette) { + debug(0, "Bitmap::putDib(%d, %d)", x, y); + + _x = x - g_fullpipe->_sceneRect.left; + _y = y - g_fullpipe->_sceneRect.top; + + if (_type == MKTAG('R', 'B', '\0', '\0')) + putDibRB(palette); + else + putDibCB(palette); +} + +bool Bitmap::putDibRB(int32 *palette, int pX, int pY) { + uint16 *curDestPtr; + int endy; + int x; + int start1; + int fillLen; + uint16 pixel; + int endx; + int y; + uint16 *srcPtr2; + uint16 *srcPtr; + + if (!palette && pX == -1) + error("Bitmap::putDibRB(): Both global and local palettes are empty"); + + debug(8, "Bitmap::putDibRB()"); + + endx = _width + _x - 1; + endy = _height + _y - 1; + + if (_x > 799 || endx < 0 || _y > 599 || endy < 0) + return false; + + if (pX == -1) { + if (endy > 599) + endy = 599; + + if (endx > 799) + endx = 799; + } + + int startx = _x; + if (startx < 0) + startx = 0; + + int starty = _y; + if (starty < 0) + starty = 0; + + y = endy; + + srcPtr = (uint16 *)_pixels; + + bool breakup = false; + for (y = endy; y >= starty && !breakup; y--) { + x = startx; + + while ((pixel = *srcPtr++) != 0) { + if (pixel == 0x100) { + breakup = true; + break; + } + + while (pixel == 0x200 && y >= starty) { + uint16 value = *srcPtr++; + + x += (byte)(value & 0xff); + y -= (byte)((value >> 8) & 0xff); + + pixel = *srcPtr++; + } + + if (y < starty || pixel == 0) + break; + + start1 = x; + fillLen = (byte)(pixel & 0xff); + + if (fillLen) { + x += fillLen; + + if (start1 < 0) { + fillLen += start1; + + if (fillLen > 0) + start1 = 0; + } + + if (fillLen > 0 || start1 >= 0) { + if (x <= 799 + 1 || (fillLen += 799 - x + 1, fillLen > 0)) { + if (y <= endy) { + if (pX == -1) { + int bgcolor = palette[(pixel >> 8) & 0xff]; + curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(start1, y); + colorFill(curDestPtr, fillLen, bgcolor); + } else { + if (y == pY && pX >= start1 && pX < start1 + fillLen) + return true; + } + } + } + } + } else { + fillLen = (pixel >> 8) & 0xff; + srcPtr2 = srcPtr; + x += fillLen; + srcPtr += (fillLen + 1) >> 1; + + if (start1 < 0) { + fillLen += start1; + if (fillLen > 0) { + srcPtr2 = (uint16 *)((byte *)srcPtr2 - start1); + start1 = 0; + } + } + + if (x > 799 + 1) { + fillLen += 799 - x + 1; + if (fillLen <= 0) + continue; + } + + if (y <= endy) { + if (pX == -1) { + curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(start1, y); + paletteFill(curDestPtr, (byte *)srcPtr2, fillLen, (int32 *)palette); + } else { + if (y == pY && pX >= start1 && pX < start1 + fillLen) + return true; + } + } + } + } + } + + if (pX == -1) + g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(startx, starty), g_fullpipe->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); + + return false; +} + +void Bitmap::putDibCB(int32 *palette) { + uint16 *curDestPtr; + int endx; + int endy; + int bpp; + uint pitch; + bool cb05_format; + + endx = _width + _x - 1; + endy = _height + _y - 1; + + debug(8, "Bitmap::putDibCB(): %d, %d, %d, %d [%d, %d]", _x, _y, endx, endy, _width, _height); + + if (_x > 799 || endx < 0 || _y > 599 || endy < 0) + return; + + if (endy > 599) + endy = 599; + + if (endx > 799) + endx = 799; + + cb05_format = (_type == MKTAG('C', 'B', '\05', 'e')); + + if (!palette && !cb05_format) + error("Bitmap::putDibCB(): Both global and local palettes are empty"); + + bpp = cb05_format ? 2 : 1; + pitch = (bpp * _width + 3) & 0xFFFFFFFC; + + byte *srcPtr = &_pixels[pitch * (endy - _y)]; + + int starty = _y; + if (starty < 0) { + starty = 0; + srcPtr = &_pixels[pitch * (_height + _y)]; + } + + int startx = _x; + if (startx < 0) { + srcPtr += bpp * -_x; + startx = 0; + } + + if (_flags & 0x1000000) { + for (int y = starty; y < endy; srcPtr -= pitch, y++) { + curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(startx, y); + copierKeyColor(curDestPtr, srcPtr, endx - startx + 1, _flags & 0xff, (int32 *)palette, cb05_format); + } + } else { + for (int y = starty; y <= endy; srcPtr -= pitch, y++) { + curDestPtr = (uint16 *)g_fullpipe->_backgroundSurface.getBasePtr(startx, y); + copier(curDestPtr, srcPtr, endx - startx + 1, (int32 *)palette, cb05_format); + } + } + + g_fullpipe->_system->copyRectToScreen(g_fullpipe->_backgroundSurface.getBasePtr(startx, starty), g_fullpipe->_backgroundSurface.pitch, startx, starty, endx + 1 - startx, endy + 1 - starty); +} + +void Bitmap::colorFill(uint16 *dest, int len, int32 color) { +#if 0 + if (blendMode) { + if (blendMode != 1) + error("vrtPutDib : RLE Fill : Invalid alpha blend mode"); + + colorFill = ptralphaFillColor16bit; + } else { + colorFill = ptrfillColor16bit; + } +#endif + + for (int i = 0; i < len; i++) + *dest++ = (int16)(color & 0xffff); +} + +void Bitmap::paletteFill(uint16 *dest, byte *src, int len, int32 *palette) { +#if 0 + if (blendMode) { + if (blendMode != 1) + error("vrtPutDib : RLE Fill : Invalid alpha blend mode"); + + paletteFill = ptrcopierWithPaletteAlpha; + } else { + paletteFill = ptrcopierWithPalette; + } +#endif + + for (int i = 0; i < len; i++) + *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; +} + +void Bitmap::copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format) { +#if 0 + if (blendMode) { + if (blendMode == 1) { + if (cb05_format) + copierKeyColor = ptrcopier16bitKeycolorAlpha; + else + copierKeyColor = ptrcopierKeycolorAlpha; + } else { + copier = 0; + } + } else if (cb05_format) { + copierKeyColor = ptrcopier16bitKeycolor; + } else { + copierKeyColor = ptrkeyColor16bit; + } +#endif + + if (!cb05_format) { + for (int i = 0; i < len; i++) { + if (*src != keyColor) + *dest = READ_LE_UINT32(&palette[*src]) & 0xffff; + + dest++; + src++; + } + } else { + int16 *src16 = (int16 *)src; + + for (int i = 0; i < len; i++) { + if (*src16 != 0) + *dest = *src16; + + dest++; + src16++; + } + } +} + +void Bitmap::copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format) { +#if 0 + if (blendMode) { + if (blendMode == 1) { + if (cb05_format) + copier = ptrcopier16bitAlpha; + else + copier = ptrcopierWithPaletteAlpha; + } else { + copier = 0; + } + } else if (cb05_format) { + copier = ptrcopier16bit; + } else { + copier = ptrcopierWithPalette; + } +#endif + + if (!cb05_format) { + for (int i = 0; i < len; i++) + *dest++ = READ_LE_UINT32(&palette[*src++]) & 0xffff; + } else { + int16 *src16 = (int16 *)src; + + for (int i = 0; i < len; i++) + *dest++ = *src16++; + } +} + +Bitmap *Bitmap::reverseImage() { + switch (_type) { + case MKTAG('R', 'B', '\0', '\0'): + return reverseImageRB(); + case MKTAG('C', 'B', '\0', '\0'): + return reverseImageCB(); + case MKTAG('C', 'B', '\05', 'e'): + return reverseImageCB05(); + default: + error("Bitmap::reverseImage: Unknown image type: %x", _type); + } + + return 0; +} + +Bitmap *Bitmap::reverseImageRB() { + uint16 *newpixels = (uint16 *)calloc(((_dataSize + 15) & 0xfffffff0) + sizeof(Bitmap), 1); + uint16 *srcPtr = (uint16 *)_pixels; + + int idx = 0; + while (srcPtr[idx] != 0x100) { + uint16 *srcPtr2 = &srcPtr[idx]; + + int prevIdx = idx; + int i = idx; + + while (*srcPtr2) { + ++srcPtr2; + ++idx; + } + + int idx2 = idx; + + newpixels[idx] = srcPtr[idx]; + + while (i != idx) { + int fillLen = 2 - ((srcPtr[prevIdx] & 0xff) != 0 ? 1 : 0); + idx2 -= fillLen; + memcpy(&newpixels[idx2], &srcPtr[prevIdx], 2 * fillLen); + prevIdx = fillLen + i; + i += fillLen; + } + ++idx; + } + newpixels[idx] = 256; + + int oldBmp = ((_dataSize + 15) >> 1) & 0x7FFFFFF8; + memcpy(&newpixels[oldBmp], &srcPtr[oldBmp], sizeof(Bitmap)); + + Bitmap *res = new Bitmap(this); + res->_pixels = (byte *)newpixels; + + return res; +} + +Bitmap *Bitmap::reverseImageCB() { + warning("STUB: Bitmap::reverseImageCB()"); + + return this; +} + +Bitmap *Bitmap::reverseImageCB05() { + warning("STUB: Bitmap::reverseImageCB05()"); + + return this; +} + +Bitmap *Bitmap::flipVertical() { + warning("STUB: Bitmap::flipVertical()"); + + return this; +} + +void Bitmap::drawShaded(int type, int x, int y, byte *palette) { + warning("STUB: Bitmap::drawShaded(%d, %d, %d)", type, x, y); + + putDib(x, y, (int32 *)palette); +} + + void Bitmap::drawRotated(int x, int y, int angle, byte *palette) { + warning("STUB: Bitmap::drawShaded(%d, %d, %d)", x, y, angle); + + putDib(x, y, (int32 *)palette); +} + +bool BigPicture::load(MfcArchive &file) { + debug(5, "BigPicture::load()"); + Picture::load(file); + + return true; +} + +Shadows::Shadows() { + _staticAniObjectId = 0; + _movementId = 0; + _sceneId = 0; +} + +bool Shadows::load(MfcArchive &file) { + debug(5, "Shadows::load()"); + _sceneId = file.readUint32LE(); + _staticAniObjectId = file.readUint32LE(); + _movementId = file.readUint32LE(); + + return true; +} + +void Shadows::init() { + Scene *scene = g_fullpipe->accessScene(_sceneId); + + StaticANIObject *st; + Movement *mov; + + if (scene && (st = scene->getStaticANIObject1ById(_staticAniObjectId, -1)) != 0 + && ((mov = st->getMovementById(_movementId)) != 0)) + initMovement(mov); +} + +void Shadows::initMovement(Movement *mov) { + uint num; + + if (mov->_currMovement) + num = mov->_currMovement->_dynamicPhases.size(); + else + num = mov->_dynamicPhases.size(); + + _items.clear(); + _items.resize(num); + + Common::Point point; + + _items[0].dynPhase = (DynamicPhase *)mov->_staticsObj1; + _items[0].dynPhase->getDimensions(&point); + _items[0].width = point.x; + _items[0].height = point.y; + + for (uint i = 1; i < num; i++) { + _items[i].dynPhase = mov->getDynamicPhaseByIndex(i - 1); + _items[i].dynPhase->getDimensions(&point); + _items[i].width = point.x; + _items[i].height = point.y; + } +} + +DynamicPhase *Shadows::findSize(int width, int height) { + int idx = 0; + int min = 1000; + + if (!_items.size()) + return 0; + + for (uint i = 0; i < _items.size(); i++) { + int w = abs(width - _items[i].width); + if (w < min) { + min = w; + idx = i; + } + } + return _items[idx].dynPhase; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/gfx.h b/engines/fullpipe/gfx.h new file mode 100644 index 0000000000..82e082d8cb --- /dev/null +++ b/engines/fullpipe/gfx.h @@ -0,0 +1,216 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_GFX_H +#define FULLPIPE_GFX_H + +namespace Fullpipe { + +class DynamicPhase; +class Movement; +struct PicAniInfo; + +struct Bitmap { + int _x; + int _y; + int _width; + int _height; + byte *_pixels; + int _type; + int _dataSize; + int _flags; + + Bitmap(); + Bitmap(Bitmap *src); + ~Bitmap(); + + void load(Common::ReadStream *s); + void putDib(int x, int y, int32 *palette); + bool putDibRB(int32 *palette, int x = -1, int y = -1); + void putDibCB(int32 *palette); + + void colorFill(uint16 *dest, int len, int32 color); + void paletteFill(uint16 *dest, byte *src, int len, int32 *palette); + void copierKeyColor(uint16 *dest, byte *src, int len, int keyColor, int32 *palette, bool cb05_format); + void copier(uint16 *dest, byte *src, int len, int32 *palette, bool cb05_format); + + Bitmap *reverseImage(); + Bitmap *reverseImageRB(); + Bitmap *reverseImageCB(); + Bitmap *reverseImageCB05(); + Bitmap *flipVertical(); + + void drawShaded(int type, int x, int y, byte *palette); + void drawRotated(int x, int y, int angle, byte *palette); + + bool isPixelHitAtPos(int x, int y); + bool isPixelAtHitPosRB(int x, int y); +}; + +class Picture : public MemoryObject { + public: + Common::Rect _rect; + Bitmap *_convertedBitmap; + int _x; + int _y; + int _field_44; + int _width; + int _height; + Bitmap *_bitmap; + int _field_54; + MemoryObject2 *_memoryObject2; + int _alpha; + byte *_paletteData; + + void displayPicture(); + + public: + Picture(); + virtual ~Picture(); + + void freePicture(); + + virtual bool load(MfcArchive &file); + void setAOIDs(); + void init(); + void getDibInfo(); + Bitmap *getPixelData(); + void draw(int x, int y, int style, int angle); + void drawRotated(int x, int y, int angle); + + byte getAlpha() { return (byte)_alpha; } + void setAlpha(byte alpha) { _alpha = alpha; } + + Common::Point *getDimensions(Common::Point *p); + bool isPointInside(int x, int y); + bool isPixelHitAtPos(int x, int y); + int getPixelAtPos(int x, int y); + int getPixelAtPosEx(int x, int y); + + byte *getPaletteData() { return _paletteData; } + void setPaletteData(byte *pal); + + void copyMemoryObject2(Picture *src); +}; + +class BigPicture : public Picture { + public: + BigPicture() {} + virtual bool load(MfcArchive &file); +}; + +class GameObject : public CObject { + public: + int16 _okeyCode; + int _field_8; + int16 _flags; + int16 _id; + char *_objectName; + int _ox; + int _oy; + int _priority; + int _field_20; + + public: + GameObject(); + GameObject(GameObject *src); + ~GameObject(); + + virtual bool load(MfcArchive &file); + void setOXY(int x, int y); + void renumPictures(CPtrList *lst); + void setFlags(int16 flags) { _flags = flags; } + void clearFlags() { _flags = 0; } + const char *getName() { return _objectName; } + + bool getPicAniInfo(PicAniInfo *info); + bool setPicAniInfo(PicAniInfo *info); +}; + +class PictureObject : public GameObject { + public: + Picture *_picture; + CPtrList *_pictureObject2List; + int _ox2; + int _oy2; + + public: + PictureObject(); + PictureObject(PictureObject *src); + + bool load(MfcArchive &file, bool bigPicture); + Common::Point *getDimensions(Common::Point *p); + void draw(); + void drawAt(int x, int y); + + bool setPicAniInfo(PicAniInfo *picAniInfo); + bool isPointInside(int x, int y); + bool isPixelHitAtPos(int x, int y); +}; + +class Background : public CObject { + public: + CPtrList _picObjList; + + char *_bgname; + int _x; + int _y; + int16 _messageQueueId; + MemoryObject *_palette; + int _bigPictureArray1Count; + int _bigPictureArray2Count; + BigPicture ***_bigPictureArray; + + public: + Background(); + virtual bool load(MfcArchive &file); + void addPictureObject(PictureObject *pct); + + BigPicture *getBigPicture(int x, int y) { return _bigPictureArray[x][y]; } +}; + +struct ShadowsItem { + int width; + int height; + DynamicPhase *dynPhase; +}; + +typedef Common::Array<ShadowsItem> ShadowsItemArray; + +class Shadows : public CObject { + int _sceneId; + int _staticAniObjectId; + int _movementId; + ShadowsItemArray _items; + + public: + Shadows(); + virtual bool load(MfcArchive &file); + void init(); + + void initMovement(Movement *mov); + DynamicPhase *findSize(int width, int height); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_GFX_H */ diff --git a/engines/fullpipe/init.cpp b/engines/fullpipe/init.cpp new file mode 100644 index 0000000000..c334542247 --- /dev/null +++ b/engines/fullpipe/init.cpp @@ -0,0 +1,247 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/objectnames.h" +#include "fullpipe/input.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +void FullpipeEngine::initObjectStates() { + setLevelStates(); + + setObjectState(sO_Dude, getObjectEnumState(sO_Dude, sO_NotCarryingEgg)); + setObjectState(sO_EggCracker, getObjectEnumState(sO_EggCracker, sO_DidNotCrackEgg)); + setObjectState(sO_GuvTheDrawer, getObjectEnumState(sO_GuvTheDrawer, sO_Awaken)); + setObjectState(sO_EggGulper, getObjectEnumState(sO_EggGulper, sO_First)); + setObjectState(sO_EggGulperGaveCoin, getObjectEnumState(sO_EggGulperGaveCoin, sO_No)); + setObjectState(sO_Jar_4, getObjectEnumState(sO_Jar_4, sO_OnTheSpring)); + setObjectState(sO_GulpedEggs, getObjectEnumState(sO_GulpedEgg, sO_NotPresent)); + + setSwallowedEggsState(); + + setObjectState(sO_WeirdWacko, getObjectEnumState(sO_WeirdWacko, sO_InGlasses)); + setObjectState(sO_TumyTrampie, getObjectEnumState(sO_TumyTrampie, sO_Drinking)); + setObjectState(sO_StairsUp_8, getObjectEnumState(sO_StairsUp_8, sO_NotBroken)); + setObjectState(sO_HareTheNooksiter, getObjectEnumState(sO_HareTheNooksiter, sO_WithHandle)); + setObjectState(sO_Elephantine, getObjectEnumState(sO_Elephantine, sO_WithBoot)); + setObjectState(sO_Fly_12, 0); + setObjectState(sO_ClockAxis, getObjectEnumState(sO_ClockAxis, sO_NotAvailable)); + setObjectState(sO_ClockHandle, getObjectEnumState(sO_ClockHandle, sO_In_7)); + setObjectState(sO_BigMumsy, getObjectEnumState(sO_BigMumsy, sO_Sleeping)); + setObjectState(sO_CoinSlot_1, getObjectEnumState(sO_CoinSlot_1, sO_Empty)); + setObjectState(sO_FriesPit, getObjectEnumState(sO_FriesPit, sO_WithApple)); + setObjectState(sO_Jug, getObjectEnumState(sO_Jug, sO_Blocked)); + setObjectState(sO_RightStairs_9, getObjectEnumState(sO_RightStairs_9, sO_ClosedShe)); + setObjectState(sO_Pipe_9, getObjectEnumState(sO_Pipe_9, sO_WithJug)); + setObjectState(sO_Inflater, getObjectEnumState(sO_Inflater, sO_WithGum)); + setObjectState(sO_Swingie, getObjectEnumState(sO_Swingie, sO_Swinging)); + setObjectState(sO_DudeJumped, getObjectEnumState(sO_DudeJumped, sO_No)); + setObjectState(sO_Bridge, getObjectEnumState(sO_Bridge, sO_Convoluted)); + setObjectState(sO_Guardian, getObjectEnumState(sO_Guardian, sO_OnRight)); + setObjectState(sO_Grandma, getObjectEnumState(sO_Grandma, sO_In_14)); + setObjectState(sO_Boot_15, getObjectEnumState(sO_Boot_15, sO_NotPresent)); + setObjectState(sO_LeftPipe_15, getObjectEnumState(sO_LeftPipe_15, sO_OpenedShe)); + setObjectState(sO_Pedestal_16, getObjectEnumState(sO_Pedestal_16, sO_IsFree)); + setObjectState(sO_Cup, getObjectEnumState(sO_Cup, sO_InSmokeRoom)); + setObjectState(sO_Pedestal_17, getObjectEnumState(sO_Pedestal_17, sO_IsFree)); + setObjectState(sO_UsherHand, getObjectEnumState(sO_UsherHand, sO_WithoutCoin)); + setObjectState(sO_RightPipe_17, getObjectEnumState(sO_RightPipe_17, sO_ClosedShe)); + setObjectState(sO_Fly_17, 1); + setObjectState(sO_DudeSwinged, 0); + setObjectState(sO_Girl, getObjectEnumState(sO_Girl, sO_Swinging)); + setObjectState(sO_Sugar, getObjectEnumState(sO_Sugar, sO_Present)); + setObjectState(sO_Janitors, getObjectEnumState(sO_Janitors, sO_Together)); + setObjectState(sO_Bag_22, getObjectEnumState(sO_Bag_22, sO_NotFallen)); + setObjectState(sO_Grandpa, getObjectEnumState(sO_Grandpa, sO_InSock)); + setObjectState(sO_CoinSlot_22, getObjectEnumState(sO_CoinSlot_22, sO_Empty)); + setObjectState(sO_UpperHatch_23, getObjectEnumState(sO_UpperHatch_23, sO_Closed)); + setObjectState(sO_LowerHatch_23, getObjectEnumState(sO_LowerHatch_23, sO_Closed)); + setObjectState(sO_Lever_23, getObjectEnumState(sO_Lever_23, sO_NotTaken)); + setObjectState(sO_LeverHandle_23, getObjectEnumState(sO_LeverHandle_23, sO_WithoutStool)); + setObjectState(sO_LowerPipe_21, getObjectEnumState(sO_LowerPipe_21, sO_ClosedShe)); + setObjectState(sO_StarsDown_24, getObjectEnumState(sO_StarsDown_24, sO_OpenedShe)); + setObjectState(sO_Hatch_26, getObjectEnumState(sO_Hatch_26, sO_Closed)); + setObjectState(sO_Sock_26, getObjectEnumState(sO_Sock_26, sO_NotHanging)); + setObjectState(sO_LeftPipe_26, getObjectEnumState(sO_LeftPipe_26, sO_ClosedShe)); + setObjectState(sO_Valve1_26, getObjectEnumState(sO_Valve1_26, sO_Opened)); + setObjectState(sO_Valve2_26, getObjectEnumState(sO_Valve2_26, sO_Closed)); + setObjectState(sO_Valve3_26, getObjectEnumState(sO_Valve3_26, sO_Closed)); + setObjectState(sO_Valve4_26, getObjectEnumState(sO_Valve4_26, sO_Closed)); + setObjectState(sO_Valve5_26, getObjectEnumState(sO_Valve5_26, sO_Opened)); + setObjectState(sO_Pool, getObjectEnumState(sO_Pool, sO_Overfull)); + setObjectState(sO_Plank_25, getObjectEnumState(sO_Plank_25, sO_NearDudesStairs)); + setObjectState(sO_Driver, getObjectEnumState(sO_Driver, sO_WithSteering)); + setObjectState(sO_Janitress, getObjectEnumState(sO_Janitress, sO_WithMop)); + setObjectState(sO_LeftPipe_29, getObjectEnumState(sO_LeftPipe_29, sO_ClosedShe)); + setObjectState(sO_LeftPipe_30, getObjectEnumState(sO_LeftPipe_30, sO_ClosedShe)); + setObjectState(sO_Leg, getObjectEnumState(sO_Leg, sO_ShowingHeel)); + setObjectState(sO_Tub, getObjectEnumState(sO_Tub, sO_EmptyShe)); + setObjectState(sO_Cactus, getObjectEnumState(sO_Cactus, sO_NotGrown)); + setObjectState(sO_Fireman, getObjectEnumState(sO_Fireman, sO_WithHose)); + setObjectState(sO_Cube, getObjectEnumState(sO_Cube, sO_In_33)); + setObjectState(sO_MommyOfHandle_32, getObjectEnumState(sO_MommyOfHandle_32, sO_WithoutHandle)); + setObjectState(sO_Pedestal_33, getObjectEnumState(sO_Pedestal_33, sO_IsFree)); + setObjectState(sO_Valve_34, getObjectEnumState(sO_Valve_34, sO_WithNothing)); + setObjectState(sO_Stool_34, getObjectEnumState(sO_Stool_34, sO_WithoutDrawer)); + setObjectState(sO_Plank_34, getObjectEnumState(sO_Plank_34, sO_Passive)); + setObjectState(sO_Hatch_34, getObjectEnumState(sO_Hatch_34, sO_Closed)); + setObjectState(sO_Valve_35, getObjectEnumState(sO_Valve_35, sO_TurnedOff)); + setObjectState(sO_Carpet_35, getObjectEnumState(sO_Carpet_35, sO_CannotTake)); + setObjectState(sO_CoinSlot_35, getObjectEnumState(sO_CoinSlot_35, sO_WithCoin)); + setObjectState(sO_BellyInflater, getObjectEnumState(sO_BellyInflater, sO_WithCork)); + setObjectState(sO_Jawcrucnher, getObjectEnumState(sO_Jawcrucnher, sO_WithoutCarpet)); + setObjectState(sO_Guard_1, getObjectEnumState(sO_Guard_1, sO_On)); + setObjectState(sO_Gurad_2, getObjectEnumState(sO_Gurad_2, sO_On)); + setObjectState(sO_Guard_3, getObjectEnumState(sO_Guard_3, sO_On)); + setObjectState(sO_Bottle_38, getObjectEnumState(sO_Bottle_38, sO_OnTheTable)); + setObjectState(sO_Boss, getObjectEnumState(sO_Boss, sO_WithHammer)); +} + +void FullpipeEngine::setLevelStates() { + CGameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + + if (v) { + v->setSubVarAsInt(sO_Level0, 2833); + v->setSubVarAsInt(sO_Level1, 2754); + v->setSubVarAsInt(sO_Level2, 2757); + v->setSubVarAsInt(sO_Level3, 2760); + v->setSubVarAsInt(sO_Level4, 2763); + v->setSubVarAsInt(sO_Level5, 2766); + v->setSubVarAsInt(sO_Level6, 2769); + v->setSubVarAsInt(sO_Level7, 2772); + v->setSubVarAsInt(sO_Level8, 2775); + v->setSubVarAsInt(sO_Level9, 2778); + } +} + +void FullpipeEngine::addCursor(CursorInfo *cursorInfo, Scene *inv, int pictureId, int hotspotX, int hotspotY, int itemPictureOffsX, int itemPictureOffsY) { + cursorInfo->pictureId = pictureId; + cursorInfo->picture = inv->getPictureObjectById(pictureId, 0)->_picture; + cursorInfo->hotspotX = hotspotX; + cursorInfo->hotspotY = hotspotY; + cursorInfo->itemPictureOffsX = itemPictureOffsX; + cursorInfo->itemPictureOffsY = itemPictureOffsY; + + getGameLoaderInputController()->addCursor(cursorInfo); +} + +void FullpipeEngine::initCursors() { + CursorInfo crs; + Scene *inv = accessScene(SC_INV); + + addCursor(&crs, inv, PIC_CSR_DEFAULT, 15, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_DEFAULT_INV, 18, 18, 23, 23); + addCursor(&crs, inv, PIC_CSR_ITN, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ITN_RED, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ITN_GREEN, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ITN_INV, 23, 17, 23, 17); + addCursor(&crs, inv, PIC_CSR_GOU, 15, 17, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOD, 15, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOL, 26, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOR, 15, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOFAR_L, 1, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_GOFAR_R, 39, 1, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE1, 12, 24, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE2, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE2_D, 22, 15, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE3, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE4, 18, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE5, 23, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE6, 11, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE6_D, 0, 0, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE7, 21, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE7_D, 7, 20, 10, 10); + addCursor(&crs, inv, PIC_CSR_ARCADE8, 23, 11, 10, 10); + addCursor(&crs, inv, PIC_CSR_LIFT, 6, 13, 10, 10); + + getGameLoaderInputController()->setCursorMode(0); +} + +void FullpipeEngine::initMap() { + memset(_mapTable, 0, sizeof(_mapTable)); + + updateMapPiece(PIC_MAP_S01, 1); + updateMapPiece(PIC_MAP_A13, 1u); +} + +void FullpipeEngine::loadAllScenes() { + accessScene(301); + accessScene(302); + accessScene(303); + accessScene(304); + accessScene(305); + accessScene(321); + accessScene(635); + accessScene(649); + accessScene(650); + accessScene(651); + accessScene(652); + accessScene(653); + accessScene(654); + accessScene(655); + accessScene(726); + accessScene(858); + accessScene(903); + accessScene(1137); + accessScene(1138); + accessScene(1139); + accessScene(1140); + accessScene(1141); + accessScene(1142); + accessScene(1143); + accessScene(1144); + accessScene(1546); + accessScene(1547); + accessScene(1548); + accessScene(1549); + accessScene(1550); + accessScene(1551); + accessScene(1552); + accessScene(2062); + accessScene(2063); + accessScene(2064); + accessScene(2065); + accessScene(2066); + accessScene(2067); + accessScene(2068); + accessScene(2069); + accessScene(2070); + accessScene(2071); + accessScene(2072); + accessScene(2460); + accessScene(3896); + accessScene(3907); + accessScene(4620); + accessScene(4999); + accessScene(5000); + accessScene(5001); + accessScene(5166); + accessScene(5222); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/input.cpp b/engines/fullpipe/input.cpp new file mode 100644 index 0000000000..8cc7654f52 --- /dev/null +++ b/engines/fullpipe/input.cpp @@ -0,0 +1,215 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/input.h" +#include "fullpipe/gfx.h" +#include "fullpipe/scene.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" +#include "fullpipe/constants.h" + +namespace Fullpipe { + +CInputController::CInputController() { + g_fullpipe->_inputController = this; + + _flag = 0; + _cursorHandle = 0; + _hCursor = 0; + _field_14 = 0; + _cursorId = 0; + _cursorIndex = -1; + _inputFlags = 1; + + _cursorBounds.left = 0; + _cursorBounds.top = 0; + _cursorBounds.right = 0; + _cursorBounds.bottom = 0; + + _cursorItemPicture = 0; +} + +CInputController::~CInputController() { + removeMessageHandler(126, -1); + + g_fullpipe->_inputController = 0; +} + +void CInputController::setInputDisabled(bool state) { + _flag = state; + g_fullpipe->_inputDisabled = state; +} + +void setInputDisabled(bool state) { + g_fullpipe->_inputController->setInputDisabled(state); +} + +void CInputController::addCursor(CursorInfo *cursor) { + CursorInfo *newc = new CursorInfo(cursor); + Common::Point p; + + cursor->picture->getDimensions(&p); + + newc->width = p.x; + newc->height = p.y; + + newc->picture->_x = -1; + newc->picture->_y = -1; + + _cursorsArray.push_back(newc); +} + +void CInputController::setCursorMode(bool enabled) { + if (enabled) + _inputFlags |= 1; + else + _inputFlags &= ~1; +} + +void CInputController::drawCursor(int x, int y) { + if (_cursorIndex == -1) + return; + + _cursorBounds.left = g_fullpipe->_sceneRect.left + x - _cursorsArray[_cursorIndex]->hotspotX; + _cursorBounds.top = g_fullpipe->_sceneRect.top + y - _cursorsArray[_cursorIndex]->hotspotY; + _cursorBounds.right = _cursorBounds.left + _cursorsArray[_cursorIndex]->width; + _cursorBounds.bottom = _cursorBounds.top + _cursorsArray[_cursorIndex]->height; + + _cursorsArray[_cursorIndex]->picture->draw(_cursorBounds.left, _cursorBounds.top, 0, 0); + + if (_cursorItemPicture) + _cursorItemPicture->draw(_cursorBounds.left + _cursorsArray[_cursorIndex]->itemPictureOffsX, + _cursorBounds.top + _cursorsArray[_cursorIndex]->itemPictureOffsY, 0, 0); +} + +void CInputController::setCursor(int cursorId) { + if (_cursorIndex == -1 || _cursorsArray[_cursorIndex]->pictureId != cursorId) { + _cursorIndex = -1; + + for (uint i = 0; i < _cursorsArray.size(); i++) { + if (_cursorsArray[i]->pictureId == cursorId) { + _cursorIndex = i; + break; + } + } + } +} + +CursorInfo::CursorInfo() { + pictureId = 0; + picture = 0; + hotspotX = 0; + hotspotY = 0; + itemPictureOffsX = 0; + itemPictureOffsY = 0; + width = 0; + height = 0; +} + +CursorInfo::CursorInfo(CursorInfo *src) { + pictureId = src->pictureId; + picture = src->picture; + hotspotX = src->hotspotX; + hotspotY = src->hotspotY; + itemPictureOffsX = src->itemPictureOffsX; + itemPictureOffsY = src->itemPictureOffsY; + width = src->width; + height = src->height; +} + +void FullpipeEngine::setCursor(int id) { + if (_inputController) + _inputController->setCursor(id); +} + +void FullpipeEngine::defHandleKeyDown(int key) { + warning("STUB: FullpipeEngine::defHandleKeyDown(%d)", key); +} + +void FullpipeEngine::updateCursorsCommon() { + GameObject *ani = _currentScene->getStaticANIObjectAtPos(_mouseVirtX, _mouseVirtY); + + GameObject *pic = _currentScene->getPictureObjectAtPos(_mouseVirtX, _mouseVirtY); + if (!ani || (pic && pic->_priority < ani->_priority)) + ani = pic; + + int selId = getGameLoaderInventory()->getSelectedItemId(); + + _objectAtCursor = ani; + + if (ani) { + _objectIdAtCursor = ani->_id; + + if (!selId && ani->_id >= _minCursorId && ani->_id <= _maxCursorId) { + selId = _objectIdCursors[ani->_id - _minCursorId]; + if (selId) { + _cursorId = selId; + return; + } + } + if (canInteractAny(_aniMan, ani, selId)) { + _cursorId = selId > 0 ? PIC_CSR_ITN_INV : PIC_CSR_ITN; + return; + } + if (selId) { + _cursorId = PIC_CSR_DEFAULT_INV; + return; + } + if (_objectIdAtCursor == ANI_LIFTBUTTON && lift_getButtonIdP(((StaticANIObject *)ani)->_statics->_staticsId)) { + _cursorId = PIC_CSR_LIFT; + return; + } + if (_sceneRect.right - _mouseVirtX < 47 && _sceneRect.right < _sceneWidth - 1) { + _cursorId = PIC_CSR_GOFAR_R; + return; + } + if (_mouseVirtX - _sceneRect.left < 47 && _sceneRect.left > 0) { + _cursorId = PIC_CSR_GOFAR_L; + return; + } + _cursorId = PIC_CSR_DEFAULT; + return; + } else { + _objectIdAtCursor = 0; + + if (selId) { + _cursorId = PIC_CSR_DEFAULT_INV; + return; + } + if (_sceneRect.right - _mouseVirtX < 47 && _sceneRect.right < _sceneWidth - 1) { + _cursorId = PIC_CSR_GOFAR_R; + return; + } + if (_mouseVirtX - _sceneRect.left < 47 && _sceneRect.left > 0) { + _cursorId = PIC_CSR_GOFAR_L; + return; + } + } + + _cursorId = PIC_CSR_DEFAULT; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/input.h b/engines/fullpipe/input.h new file mode 100644 index 0000000000..4b32e510e3 --- /dev/null +++ b/engines/fullpipe/input.h @@ -0,0 +1,77 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_INPUT_H +#define FULLPIPE_INPUT_H + +namespace Fullpipe { + +class Picture; + +void setInputDisabled(bool state); + +struct CursorInfo { + int pictureId; + Picture *picture; + int hotspotX; + int hotspotY; + int itemPictureOffsX; + int itemPictureOffsY; + int width; + int height; + + CursorInfo(); + CursorInfo(CursorInfo *src); +}; + +typedef Common::Array<CursorInfo *> CursorsArray; + +class CInputController { + //CObject obj; + int _flag; + int _inputFlags; + int _cursorHandle; + int _hCursor; + int _field_14; + int _cursorId; + int _cursorIndex; + CursorsArray _cursorsArray; + Common::Rect _cursorBounds; + Picture *_cursorItemPicture; + + public: + CInputController(); + ~CInputController(); + + void setInputDisabled(bool state); + void addCursor(CursorInfo *cursor); + void setCursorMode(bool mode); + + void drawCursor(int x, int y); + void setCursor(int id); + + void setCursorItemPicture(Picture *pic) { _cursorItemPicture = pic; } +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INPUT_H */ diff --git a/engines/fullpipe/interaction.cpp b/engines/fullpipe/interaction.cpp new file mode 100644 index 0000000000..f392a084dd --- /dev/null +++ b/engines/fullpipe/interaction.cpp @@ -0,0 +1,520 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/interaction.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId) { + return getGameLoaderInteractionController()->handleInteraction(subject, object, invId); +} + +bool canInteractAny(GameObject *obj1, GameObject *obj2, int invId) { + int sceneId = 0; + + if (g_fullpipe->_currentScene) + sceneId = g_fullpipe->_currentScene->_sceneId; + + CInteractionController *intC = getGameLoaderInteractionController(); + for (CObList::iterator i = intC->_interactions.begin(); i != intC->_interactions.end(); ++i) { + CInteraction *intr = (CInteraction *)*i; + + if (intr->_sceneId > 0 && intr->_sceneId != sceneId) + break; + + if (invId == -3) { + invId = getGameLoaderInventory()->getSelectedItemId(); + } + if (intr->canInteract(obj1, obj2, invId)) + return true; + } + return false; +} + +bool CInteractionController::load(MfcArchive &file) { + debug(5, "CInteractionController::load()"); + + return _interactions.load(file); +} + +int static_compSceneId = 0; + +bool CInteractionController::compareInteractions(const void *p1, const void *p2) { + const CInteraction *i1 = (const CInteraction *)p1; + const CInteraction *i2 = (const CInteraction *)p2; + + if (i2->_sceneId < i1->_sceneId) { + if (i1->_sceneId != static_compSceneId) + return false; + } + if (i2->_sceneId != i1->_sceneId) { + if (i1->_sceneId > 0 && i2->_sceneId == static_compSceneId) + return false; + if (i2->_sceneId != i1->_sceneId) + return true; + } + if (i2->_objectId3 == -1) + return true; + + if (i1->_objectId3 == i2->_objectId3) + return true; + + if (i1->_objectId3 == -1 || i1->_objectId3 == -2) + return false; + + return true; +} + +void CInteractionController::sortInteractions(int sceneId) { + static_compSceneId = sceneId; + + Common::sort(_interactions.begin(), _interactions.end(), CInteractionController::compareInteractions); +} + +bool CInteractionController::handleInteraction(StaticANIObject *subj, GameObject *obj, int invId) { + if (subj) { + if (!subj->isIdle() || (subj->_flags & 0x100)) + return false; + } else { + error("CInteractionController::handleInteraction(): subj is null"); + return false; + } + + if (!_interactions.size()) + return false; + + CInteraction *inter = 0; + CInteraction *previnter = 0; + int dur = 0; + int mindur = 0xFFFF; + + MessageQueue *mq; + ExCommand *ex; + + for (CObList::iterator i = _interactions.begin(); i != _interactions.end(); ++i) { + CInteraction *cinter = (CInteraction *)*i; + + if (!cinter->canInteract(subj, obj, invId)) + continue; + + if ((inter || cinter->_objectId2) && (!obj || cinter->_objectId3 != obj->_id)) { + if (cinter->_messageQueue) + cinter->_messageQueue->calcDuration(subj); + + PicAniInfo aniInfo; + + obj->getPicAniInfo(&aniInfo); + + if (cinter->_staticsId1) { + StaticANIObject *ani = (StaticANIObject *)obj; + ani->_messageQueueId = 0; + ani->changeStatics2(cinter->_staticsId1); + } + int xpos = cinter->_xOffs + obj->_ox; + int ypos = cinter->_yOffs + obj->_oy; + + obj->setPicAniInfo(&aniInfo); + + if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1) { + mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->method4C(subj, xpos, ypos, 1, cinter->_staticsId2); + if (mq) { + dur = mq->calcDuration(subj); + delete mq; + } else { + dur = 0x10000; + } + inter = previnter; + } else { + dur = 0; + } + if (dur < mindur) { + inter = cinter; + mindur = dur; + previnter = cinter; + } + } else { + inter = cinter; + break; + } + } + + if (!inter) + return false; + + if (!inter->_objectId2) { + StaticANIObject *ani = (StaticANIObject *)obj; + + if (!ani->isIdle()) + return false; + + if (ani->_flags & 0x100) + return false; + + if (!inter->_staticsId1 || !(inter->_flags & 1)) + goto LABEL_38; + + if (ani->_movement || ani->_statics == 0 || ani->_statics->_staticsId != inter->_staticsId1) { + mq = ani->changeStatics1(inter->_staticsId1); + if (!mq) + return false; + + ex = new ExCommand((subj ? subj->_id : 0), 55, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_x = obj->_id; + ex->_y = obj->_okeyCode; + ex->_keyCode = subj ? subj->_okeyCode : 0; + ex->_excFlags = 3; + ex->_field_14 = (obj->_objtype != kObjTypePictureObject); + ex->_field_20 = invId; + mq->_exCommands.push_back(ex); + + if (mq->_isFinished) { + mq->_isFinished = 0; + ani->queueMessageQueue(mq); + } + } else { + if (ani->getMessageQueue()) + ani->queueMessageQueue(0); +LABEL_38: + if (inter->_messageQueue) { + mq = new MessageQueue(inter->_messageQueue, 0, 1); + mq->changeParam28ForObjectId(ani->_id, -1, ani->_okeyCode); + + if (!mq->chain(0)) + return false; + } + } + return true; + } + + if (obj && !subj) + return true; + + if (!obj || inter->_objectId3 == obj->_id) { + if (subj) { + if (inter->_messageQueue) { + if (subj->isIdle()) { + mq = new MessageQueue(inter->_messageQueue, 0, 1); + + if (!mq->chain(subj)) { + delete mq; + + return false; + } + } + } + } + return true; + } + + if (inter->isOverlapping(subj, obj)) { + if (obj->_objtype == kObjTypeStaticANIObject) { + StaticANIObject *ani = (StaticANIObject *)obj; + + ani->queueMessageQueue(0); + + if (inter->_staticsId1) + ani->changeStatics2(inter->_staticsId1); + + if (!(inter->_flags & 0x10000)) + obj->_flags |= 0x80; + } + + if (!inter->_messageQueue) + return false; + + subj->setOXY(inter->_xOffs + obj->_ox, inter->_yOffs + obj->_oy); + + mq = new MessageQueue(inter->_messageQueue, 0, 1); + mq->changeParam28ForObjectId(obj->_id, -1, obj->_okeyCode); + mq->_flags |= 1; + + if (!(inter->_flags & 0x10000)) { + ex = new ExCommand(obj->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = obj->_okeyCode; + ex->_field_14 = 0x100; + ex->_messageNum = 0; + ex->_excFlags = 3; + mq->_exCommands.push_back(ex); + } + + ex = new ExCommand(obj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = obj->_okeyCode; + ex->_field_14 = 0x100; + ex->_messageNum = 0; + ex->_excFlags = 3; + mq->_exCommands.push_back(ex); + + ex = new ExCommand(subj->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = subj->_okeyCode; + ex->_field_14 = 0x100; + ex->_messageNum = 0; + ex->_excFlags = 3; + mq->_exCommands.push_back(ex); + + ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0); + ex->_excFlags |= 3; + ex->_keyCode = 0; + mq->_exCommands.push_back(ex); + + if (!mq->chain(subj)) { + delete mq; + + return false; + } + + subj->_flags |= 1; + obj->_flags |= 1; + } else { + bool someFlag = false; + PicAniInfo aniInfo; + + obj->getPicAniInfo(&aniInfo); + + if (obj->_objtype == kObjTypeStaticANIObject && inter->_staticsId1) { + StaticANIObject *ani = (StaticANIObject *)obj; + + ani->_messageQueueId = 0; + ani->changeStatics2(inter->_staticsId1); + } + + int xpos = inter->_yOffs + obj->_ox; + int ypos = inter->_yOffs + obj->_oy; + + obj->setPicAniInfo(&aniInfo); + + if (abs(xpos - subj->_ox) > 1 || abs(ypos - subj->_oy) > 1 + || (inter->_staticsId2 != 0 && (subj->_statics == 0 || subj->_statics->_staticsId != inter->_staticsId2))) { + mq = getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->method34(subj, xpos, ypos, 1, inter->_staticsId2); + + if (!mq) + return false; + + ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_x = obj->_id; + ex->_y = obj->_okeyCode; + ex->_keyCode = subj->_okeyCode; + ex->_excFlags = 3; + ex->_field_20 = invId; + ex->_field_14 = (obj->_objtype != kObjTypePictureObject); + mq->_exCommands.push_back(ex); + + someFlag = true; + + ex = new ExCommand(subj->_id, 17, 0x40, 0, 0, 0, 1, 0, 0, 0); + ex->_x = xpos; + ex->_y = ypos; + ex->_excFlags |= 3; + ex->_keyCode = 6; + ex->_field_14 = obj->_id; + ex->_field_20 = obj->_okeyCode; + ex->postMessage(); + } + + if (!inter->_staticsId1 || !(inter->_flags & 1)) + return true; + + StaticANIObject *ani = (StaticANIObject *)obj; + + if (!ani->isIdle()) + return false; + + if (ani->getMessageQueue()) + ani->queueMessageQueue(0); + + if (!ani->_statics || ani->_statics->_staticsId != inter->_staticsId1 || ani->_movement) { + mq = ani->changeStatics1(inter->_staticsId1); + + if (!mq) + return false; + + if (someFlag) { + if (!(inter->_flags & 0x10000)) { + if (mq->_isFinished) { + ani->_flags |= 0x80u; + } else { + ex = new ExCommand(ani->_id, 34, 0x80, 0, 0, 0, 1, 0, 0, 0); + ex->_field_14 = 0x80; + ex->_keyCode = ani->_okeyCode; + ex->_excFlags = 3; + mq->_exCommands.push_back(ex); + } + } + ex = new ExCommand(ani->_id, 34, 0x100, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = ani->_okeyCode; + ex->_field_14 = 0x100; + ex->_excFlags = 3; + mq->_exCommands.push_back(ex); + } else { + ex = new ExCommand(subj->_id, 55, 0, 0, 0, 0, 1, 0, 0, 0); + ex->_x = ani->_id; + ex->_y = ani->_okeyCode; + ex->_keyCode = subj->_okeyCode; + ex->_excFlags = 2; + ex->_field_14 = (obj->_objtype != kObjTypePictureObject); + ex->_field_20 = invId; + mq->_exCommands.push_back(ex); + + if (!mq->_isFinished) + return true; + + mq->_isFinished = 0; + ani->queueMessageQueue(mq); + } + } else { + obj->_flags |= 1; + + if (inter->_flags & 0x10000) + return true; + + obj->_flags |= 0x80; + } + } + + return true; +} + +CInteraction::CInteraction() { + _objectId1 = 0; + _objectId2 = 0; + _staticsId1 = 0; + _objectId3 = 0; + _objectState2 = 0; + _objectState1 = 0; + _messageQueue = 0; + _flags = 0; + _yOffs = 0; + _xOffs = 0; + _staticsId2 = 0; + _field_28 = 0; + _sceneId = -1; + _actionName = 0; +} + +bool CInteraction::load(MfcArchive &file) { + debug(5, "CInteraction::load()"); + + _objectId1 = file.readUint16LE(); + _objectId2 = file.readUint16LE(); + _staticsId1 = file.readUint16LE(); + _staticsId2 = file.readUint16LE(); + _objectId3 = file.readUint16LE(); + _objectState2 = file.readUint32LE(); + _objectState1 = file.readUint32LE(); + _xOffs = file.readUint32LE(); + _yOffs = file.readUint32LE(); + _sceneId = file.readUint32LE(); + _flags = file.readUint32LE(); + _actionName = file.readPascalString(); + + _messageQueue = (MessageQueue *)file.readClass(); + + return true; +} + +bool CInteraction::canInteract(GameObject *obj1, GameObject *obj2, int invId) { + if (_sceneId > 0 && g_fullpipe->_currentScene && g_fullpipe->_currentScene->_sceneId != _sceneId) + return false; + + if (_flags & 0x20000) + return false; + + if (!obj2) + return false; + + if (obj2->_id != _objectId1) + return false; + + if ((_flags & 8) && (_flags & 1)) { + if (obj2->_objtype != kObjTypeStaticANIObject) + return false; + + StaticANIObject *st = (StaticANIObject *)obj2; + + if (!st->_statics) + return false; + + if (st->_statics->_staticsId != _staticsId1) { + if (_staticsId1) + return false; + } + } + + if ((_objectId3 != invId && _objectId3 != -1 && _objectId3 != -2) || (!invId && _objectId3 == -2)) + return false; + + if (_objectState1) { + if (_flags & 0x10) { + if ((g_fullpipe->getObjectState(obj1->getName()) & _objectState1) == 0) + return false; + } else { + if (g_fullpipe->getObjectState(obj1->getName()) != _objectState1) + return false; + } + } + + if (_objectState2) { + if (_flags & 0x10) { + if ((g_fullpipe->getObjectState(obj2->getName()) & _objectState2) == 0) + return false; + } else { + if (g_fullpipe->getObjectState(obj2->getName()) != _objectState2) + return false; + } + } + + if (_objectId2 && (!obj1 || _objectId2 != obj1->_id)) + return false; + + return true; +} + +bool CInteraction::isOverlapping(StaticANIObject *subj, GameObject *obj) { + StaticANIObject *ani = (StaticANIObject *)obj; + + if (abs(_xOffs + obj->_ox - subj->_ox) <= 1 + && abs(obj->_oy + _yOffs - subj->_oy) <= 1) { + if (!_staticsId2 || (subj->_statics != 0 && subj->_statics->_staticsId == _staticsId2)) { + if (!_staticsId1 || !(_flags & 1) || (ani->_statics != 0 && ani->_statics->_staticsId == _staticsId1)) + return true; + } + } + return false; +} + +bool EntranceInfo::load(MfcArchive &file) { + debug(5, "EntranceInfo::load()"); + + _sceneId = file.readUint32LE(); + _field_4 = file.readUint32LE(); + _messageQueueId = file.readUint32LE(); + file.read(_gap_C, 292); // FIXME, Ugh + _field_130 = file.readUint32LE(); + + return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/interaction.h b/engines/fullpipe/interaction.h new file mode 100644 index 0000000000..28a03fb496 --- /dev/null +++ b/engines/fullpipe/interaction.h @@ -0,0 +1,96 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_INTERACTION_H +#define FULLPIPE_INTERACTION_H + +#include "fullpipe/utils.h" + +namespace Fullpipe { + +class GameObject; +class MessageQueue; +class StaticANIObject; + +int handleObjectInteraction(StaticANIObject *subject, GameObject *object, int invId); +bool canInteractAny(GameObject *obj1, GameObject *obj2, int invId); + + +class CInteraction : public CObject { + public: + int16 _objectId1; + int16 _objectId2; + int16 _objectId3; + int16 _staticsId1; + int16 _staticsId2; + int _objectState1; + int _objectState2; + int _xOffs; + int _yOffs; + MessageQueue *_messageQueue; + int _sceneId; + int _field_28; + int _flags; + char *_actionName; + + public: + CInteraction(); + virtual bool load(MfcArchive &file); + bool canInteract(GameObject *obj1, GameObject *obj2, int invId); + bool isOverlapping(StaticANIObject *subj, GameObject *obj); +}; + +class CInteractionController : public CObject { + public: + CObList _interactions; + int16 _field_20; + bool _flag24; + + private: + static bool compareInteractions(const void *p1, const void *p2); + + public: + CInteractionController() : _field_20(0), _flag24(true) {} + + virtual bool load(MfcArchive &file); + + void enableFlag24() { _flag24 = true; } + void disableFlag24() { _flag24 = false; } + + void sortInteractions(int sceneId); + + bool handleInteraction(StaticANIObject *subj, GameObject *obj, int invId); +}; + +struct EntranceInfo { + int32 _sceneId; + int32 _field_4; + int32 _messageQueueId; + byte _gap_C[292]; // FIXME + int32 _field_130; + + bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INTERACTION_H */ diff --git a/engines/fullpipe/inventory.cpp b/engines/fullpipe/inventory.cpp new file mode 100644 index 0000000000..1e229f3408 --- /dev/null +++ b/engines/fullpipe/inventory.cpp @@ -0,0 +1,420 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/utils.h" +#include "fullpipe/inventory.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/statics.h" +#include "fullpipe/input.h" + +namespace Fullpipe { + +bool CInventory::load(MfcArchive &file) { + debug(5, "CInventory::load()"); + + _sceneId = file.readUint16LE(); + int numInvs = file.readUint32LE(); + + for (int i = 0; i < numInvs; i++) { + InventoryPoolItem *t = new InventoryPoolItem(); + t->id = file.readUint16LE(); + t->pictureObjectNormal = file.readUint16LE(); + t->pictureObjectId1 = file.readUint16LE(); + t->pictureObjectHover = file.readUint16LE(); + t->pictureObjectSelected = file.readUint16LE(); + t->flags = file.readUint32LE(); + t->field_C = 0; + t->field_A = -536; + _itemsPool.push_back(t); + } + + return true; +} + +int CInventory::getInventoryPoolItemIndexById(int itemId) { + if (_itemsPool.size() <= 0) + return -1; + + for (uint i = 0; i < _itemsPool.size(); i++) { + if (_itemsPool[i]->id == itemId) + return i; + } + + return 0; +} + +bool CInventory::setItemFlags(int itemId, int flags) { + int idx = getInventoryPoolItemIndexById(itemId); + + if (idx < 0) + return false; + else + _itemsPool[idx]->flags = flags; + + return true; +} + +CInventory2::CInventory2() { + _selectedId = -1; + _field_48 = -1; + _scene = 0; + _picture = 0; + _isInventoryOut = false; + _isLocked = 0; + _topOffset = -65; +} + +bool CInventory2::loadPartial(MfcArchive &file) { // CInventory2_SerializePartially + int numInvs = file.readUint32LE(); + + for (int i = 0; i < numInvs; i++) { + InventoryItem *t = new InventoryItem(); + t->itemId = file.readUint16LE(); + t->count = file.readUint16LE(); + _inventoryItems.push_back(t); + } + + return true; +} + +void CInventory2::addItem(int itemId, int count) { + if (getInventoryPoolItemIndexById(itemId) >= 0) + _inventoryItems.push_back(new InventoryItem(itemId, count)); +} + +void CInventory2::addItem2(StaticANIObject *obj) { + if (getInventoryPoolItemIndexById(obj->_id) >= 0 && getInventoryPoolItemFieldCById(obj->_id) != 2) { + addItem(obj->_id, 1); + obj->hide(); + } +} + +void CInventory2::removeItem(int itemId, int count) { + warning("STUB: CInventory2::removeItem(%d, %d)", itemId, count); +} + +void CInventory2::removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority) { + warning("STUB: void removeItem2(sc, %d, %d, %d, %d)", itemId, x, y, priority); +} + +int CInventory2::getCountItemsWithId(int itemId) { + int res = 0; + + for (uint i = 0; i < _inventoryItems.size(); i++) { + if (_inventoryItems[i]->itemId == itemId) + res += _inventoryItems[i]->count; + } + + return res; +} + +int CInventory2::getInventoryItemIndexById(int itemId) { + for (uint i = 0; i < _inventoryItems.size(); i++) { + if (_inventoryItems[i]->itemId == itemId) + return i; + } + + return -1; +} + +int CInventory2::getInventoryPoolItemFieldCById(int itemId) { + for (uint i = 0; i < _itemsPool.size(); i++) { + if (_itemsPool[i]->id == itemId) + return _itemsPool[i]->field_C; + } + + return 0; +} + +int CInventory2::getItemFlags(int itemId) { + int idx = getInventoryPoolItemIndexById(itemId); + + if (idx < 0) + return 0; + + return _itemsPool[idx]->flags; +} + +void CInventory2::rebuildItemRects() { + _scene = g_fullpipe->accessScene(_sceneId); + + if (!_scene) + return; + + _picture = _scene->getBigPicture(0, 0); + _picture->setAlpha(50); + + int itemX = 9; + int itemY = 0; + + for (uint i = 0; i < _scene->_picObjList.size(); i++) { + PictureObject *pic = (PictureObject *)_scene->_picObjList[i]; + + for (uint j = 0; j < _itemsPool.size(); j++) { + if (_itemsPool[j]->pictureObjectNormal == pic->_id) { + if (pic->_okeyCode) + _scene->deletePictureObject(pic); + else + pic->_flags &= 0xFFFB; + } + } + } + + for (uint i = 0; i < _inventoryItems.size(); i++) { + Common::Point point; + + int idx = getInventoryPoolItemIndexById(_inventoryItems[i]->itemId); + + InventoryIcon *icn = new InventoryIcon(); + + icn->inventoryItemId = _itemsPool[idx]->id; + + icn->pictureObjectNormal = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectNormal, 0); + icn->pictureObjectHover = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectHover, 0); + icn->pictureObjectSelected = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectSelected, 0); + + icn->pictureObjectNormal->getDimensions(&point); + + if (_itemsPool[idx]->flags & 0x10000) { + icn->x1 = 730; + icn->y1 = itemY; + icn->x2 = point.x + 730; + icn->y2 = point.y + itemY + 10; + } else { + icn->x1 = itemX; + icn->y1 = itemY; + icn->x2 = itemX + point.x; + itemX = icn->x2 + 1; + icn->y2 = point.y + itemY + 10; + } + + _inventoryIcons.push_back(icn); + + if (itemX >= 2 * (icn->x1 - icn->x2) + 800) { + itemX = 9; + itemY = icn->y2 + 1; + } + } +} + +void CInventory2::draw() { + if (!_scene) + return; + + int oldScLeft = g_fullpipe->_sceneRect.left; + int oldScTop = g_fullpipe->_sceneRect.top; + + g_fullpipe->_sceneRect.top = -_topOffset; + g_fullpipe->_sceneRect.left = 0; + + _picture->draw(-1, -1, 0, 0); + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + InventoryIcon *icn = _inventoryIcons[i]; + + if (icn->isSelected) { + icn->pictureObjectSelected->drawAt(icn->x1, icn->y1 + 10); + } else { + if (icn->isMouseHover) + icn->pictureObjectHover->drawAt(icn->x1, icn->y1 + 10); + else + icn->pictureObjectNormal->drawAt(icn->x1, icn->y1 + 10); + } + } + + if (!_isInventoryOut) + goto LABEL_30; + + int v10, v11, v12; + + if (_topOffset != -10) { + if (_topOffset < -10) { + v10 = -10; + goto LABEL_13; + } + if (_topOffset + 10 >= 20) { + v11 = -20; +cont: + _topOffset += v11; + goto reset; + } + v12 = -10; + goto LABEL_25; + } + if (!_isInventoryOut) { +LABEL_30: + if (_topOffset != -65) { + if (_topOffset < -65) { + v10 = -65; +LABEL_13: + v11 = v10 - _topOffset; + if (v11 >= 20) + v11 = 20; + goto cont; + } + if (_topOffset + 65 >= 20) { + v11 = -20; + goto cont; + } + v12 = -65; +LABEL_25: + v11 = v12 - _topOffset; + goto cont; + } + } + +reset: + + g_fullpipe->_sceneRect.top = oldScTop; + g_fullpipe->_sceneRect.left = oldScLeft; + +} + +void CInventory2::slideIn() { + _isInventoryOut = false; + + ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_2C = 10; + ex->_field_14 = _isInventoryOut; + ex->_field_20 = !_isInventoryOut; + ex->_excFlags |= 3; + ex->postMessage(); +} + +void CInventory2::slideOut() { + _isInventoryOut = true; + + ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + + ex->_field_2C = 10; + ex->_field_14 = _isInventoryOut; + ex->_field_20 = !_isInventoryOut; + ex->_excFlags |= 3; + ex->postMessage(); +} + +bool CInventory2::handleLeftClick(ExCommand *cmd) { + if (!_isInventoryOut) + return false; + + bool res = false; + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + if (cmd->_x >= _inventoryIcons[i]->x1 && cmd->_x <= _inventoryIcons[i]->x2 && + cmd->_y >= _inventoryIcons[i]->y1 && cmd->_y <= _inventoryIcons[i]->y2) { + if (getSelectedItemId()) { + if (getSelectedItemId() != _inventoryIcons[i]->inventoryItemId) + unselectItem(0); + } + if (getItemFlags(_inventoryIcons[i]->inventoryItemId) & 1) { + ExCommand *ex = new ExCommand(0, 17, 65, 0, 0, 0, 1, 0, 0, 0); + ex->_field_2C = 11; + ex->_field_14 = _inventoryIcons[i]->inventoryItemId; + ex->_excFlags |= 3; + ex->postMessage(); + } + if (!(getItemFlags(_inventoryIcons[i]->inventoryItemId) & 2)) { + selectItem(_inventoryIcons[i]->inventoryItemId); + _inventoryIcons[i]->isSelected = true; + } + res = true; + } + } + + if (!res) + unselectItem(0); + + return res; +} + +int CInventory2::selectItem(int itemId) { + if (getInventoryItemIndexById(itemId) < 0) + return -1; + + unselectItem(0); + + _selectedId = itemId; + + if (_scene) { + int idx = getInventoryPoolItemIndexById(itemId); + + Picture *pic = _scene->getPictureObjectById(_itemsPool[idx]->pictureObjectId1, 0)->_picture; + g_fullpipe->getGameLoaderInputController()->setCursorItemPicture(pic); + } + + return _selectedId; +} + +bool CInventory2::unselectItem(bool flag) { + if (_selectedId < 0) + return false; + + _selectedId = -1; + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + if (_inventoryIcons[i]->isSelected) + _inventoryIcons[i]->isSelected = false; + } + + g_fullpipe->getGameLoaderInputController()->setCursorItemPicture(0); + + return true; +} + +int CInventory2::getHoveredItem(Common::Point *point) { + int selId = getSelectedItemId(); + + if (point->y <= 20 && !_isInventoryOut && !_isLocked) + slideOut(); + + if (!selId && point->y >= 55) { + if (!_isInventoryOut) + return 0; + + if (!_isLocked) + slideIn(); + } + + if (!_isInventoryOut) + return 0; + + for (uint i = 0; i < _inventoryIcons.size(); i++) { + InventoryIcon *icn = _inventoryIcons[i]; + if (selId || + point->x < icn->x1 || + point->x > icn->x2 || + point->y < _topOffset + icn->y1 || + point->y > _topOffset + icn->y2) { + icn->isMouseHover = false; + } else { + icn->isMouseHover = true; + return icn->inventoryItemId; + } + } + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/inventory.h b/engines/fullpipe/inventory.h new file mode 100644 index 0000000000..f84d27dde5 --- /dev/null +++ b/engines/fullpipe/inventory.h @@ -0,0 +1,130 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_INVENTORY_H +#define FULLPIPE_INVENTORY_H + +namespace Fullpipe { + +class Scene; +class BigPicture; + +struct InventoryPoolItem { + int16 id; + int16 pictureObjectNormal; + int16 pictureObjectId1; + int16 pictureObjectHover; + int16 pictureObjectSelected; + int16 field_A; + int field_C; + int obj; + int flags; +}; + +typedef Common::Array<InventoryPoolItem *> InventoryPoolItems; + +class CInventory : public CObject { + protected: + int16 _sceneId; + InventoryPoolItems _itemsPool; + + public: + CInventory() { _sceneId = 0; } + virtual bool load(MfcArchive &file); + + int getInventoryPoolItemIndexById(int itemId); + bool setItemFlags(int itemId, int flags); +}; + +struct InventoryItem { + int16 itemId; + int16 count; + + InventoryItem() { itemId = count = 0; } + InventoryItem(int id, int cnt) : itemId(id), count(cnt) {} +}; + +typedef Common::Array<InventoryItem *> InventoryItems; + +class PictureObject; + +struct InventoryIcon { + PictureObject *pictureObjectNormal; + PictureObject *pictureObjectHover; + PictureObject *pictureObjectSelected; + int x1; + int y1; + int x2; + int y2; + int16 inventoryItemId; + bool isSelected; + bool isMouseHover; +}; + +typedef Common::Array<InventoryIcon *> InventoryIcons; + +class CInventory2 : public CInventory { + InventoryItems _inventoryItems; + InventoryIcons _inventoryIcons; + int _selectedId; + int _field_48; + bool _isInventoryOut; + bool _isLocked; + int _topOffset; + Scene *_scene; + BigPicture *_picture; + + public: + CInventory2(); + bool loadPartial(MfcArchive &file); + void addItem(int itemId, int count); + void addItem2(StaticANIObject *obj); + void removeItem(int itemId, int count); + void removeItem2(Scene *sceneObj, int itemId, int x, int y, int priority); + + int getInventoryItemIndexById(int itemId); + int getInventoryPoolItemFieldCById(int itemId); + int getCountItemsWithId(int itemId); + int getItemFlags(int itemId); + + void rebuildItemRects(); + + Scene *getScene() { return _scene; } + bool getIsLocked() { return _isLocked; } + void setIsLocked(bool val) { _isLocked = val; } + bool getIsInventoryOut() { return _isInventoryOut; } + + int getSelectedItemId() { return _selectedId < 0 ? 0 : _selectedId; } + int getHoveredItem(Common::Point *point); + void slideIn(); + void slideOut(); + + bool handleLeftClick(ExCommand *cmd); + int selectItem(int itemId); + bool unselectItem(bool flag); + + void draw(); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_INVENTORY_H */ diff --git a/engines/fullpipe/lift.cpp b/engines/fullpipe/lift.cpp new file mode 100644 index 0000000000..25dd2613fe --- /dev/null +++ b/engines/fullpipe/lift.cpp @@ -0,0 +1,67 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +int FullpipeEngine::lift_getButtonIdP(int objid) { + switch (objid) { + case ST_LBN_0N: + return ST_LBN_0P; + break; + case ST_LBN_1N: + return ST_LBN_1P; + break; + case ST_LBN_2N: + return ST_LBN_2P; + break; + case ST_LBN_3N: + return ST_LBN_3P; + break; + case ST_LBN_4N: + return ST_LBN_4P; + break; + case ST_LBN_5N: + return ST_LBN_5P; + break; + case ST_LBN_6N: + return ST_LBN_6P; + break; + case ST_LBN_7N: + return ST_LBN_7P; + break; + case ST_LBN_8N: + return ST_LBN_8P; + break; + case ST_LBN_9N: + return ST_LBN_9P; + break; + default: + return 0; + break; + } +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.cpp b/engines/fullpipe/messages.cpp new file mode 100644 index 0000000000..478112f75c --- /dev/null +++ b/engines/fullpipe/messages.cpp @@ -0,0 +1,723 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/messages.h" +#include "fullpipe/modal.h" +#include "fullpipe/statics.h" + +namespace Fullpipe { + +ExCommand::ExCommand() { + _field_3C = 1; + _messageNum = 0; + _excFlags = 0; + _parId = 0; +} + +ExCommand::ExCommand(ExCommand *src) : Message(src) { + _field_3C = 1; + _messageNum = src->_messageNum; + _excFlags = src->_excFlags; + _parId = src->_parId; + +} + +ExCommand::ExCommand(int16 parentId, int messageKind, int messageNum, int x, int y, int a7, int a8, int sceneClickX, int sceneClickY, int a11) : + Message(parentId, messageKind, x, y, a7, a8, sceneClickX, sceneClickY, a11) { + _field_3C = 1; + _messageNum = messageNum; + _excFlags = 0; + _parId = 0; +} + +bool ExCommand::load(MfcArchive &file) { + debug(5, "ExCommand::load()"); + + _parentId = file.readUint16LE(); + _messageKind = file.readUint32LE(); + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _field_14 = file.readUint32LE(); + _sceneClickX = file.readUint32LE(); + _sceneClickY = file.readUint32LE(); + _field_20 = file.readUint32LE(); + _field_24 = file.readUint32LE(); + _keyCode = file.readUint32LE(); + _field_2C = file.readUint32LE(); + _field_30 = file.readUint32LE(); + _field_34 = file.readUint32LE(); + + _messageNum = file.readUint32LE(); + + _field_3C = 0; + + if (g_fullpipe->_gameProjectVersion >= 12) { + _excFlags = file.readUint32LE(); + _parId = file.readUint32LE(); + } + + return true; +} + +bool ExCommand::handleMessage() { + int cnt = 0; + for (MessageHandler *m = g_fullpipe->_messageHandlers; m; m = m->nextItem) + cnt += m->callback(this); + + if (_messageKind == 17 || (_excFlags & 1)) { + if (_parId) { + MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(_parId); + if (mq) + mq->update(); + } + } + + if (_excFlags & 2) + delete this; + + return (cnt > 0); +} + +void ExCommand::sendMessage() { + g_fullpipe->_exCommandList.push_back(this); + + processMessages(); +} + +void ExCommand::postMessage() { + g_fullpipe->_exCommandList.push_back(this); +} + +void ExCommand::handle() { + if (g_fullpipe->_modalObject) { + g_fullpipe->_modalObject->handleMessage(this); + + delete this; + } else { + postMessage(); + } +} + +Message::Message() { + _messageKind = 0; + _parentId = 0; + + _x = 0; + _y = 0; + _field_14 = 0; + _sceneClickX = 0; + _sceneClickY = 0; + _field_20 = 0; + _field_24 = 0; + _keyCode = 0; + _field_2C = 0; + _field_30 = 0; + _field_34 = 0; +} + +Message::Message(Message *src) { + _parentId = src->_parentId; + _messageKind = src->_messageKind; + _x = src->_x; + _y = src->_y; + _field_14 = src->_field_14; + _sceneClickX = src->_sceneClickX; + _sceneClickY = src->_sceneClickY; + _field_20 = src->_field_20; + _field_24 = src->_field_24; + _keyCode = src->_keyCode; + _field_2C = src->_field_2C; + _field_30 = src->_field_30; + _field_34 = src->_field_34; +} + +Message::Message(int16 parentId, int messageKind, int x, int y, int a6, int a7, int sceneClickX, int sceneClickY, int a10) { + _messageKind = messageKind; + _parentId = parentId; + _x = x; + _y = y; + _field_14 = a6; + _sceneClickX = sceneClickX; + _sceneClickY = sceneClickY; + _field_24 = a7; + _field_20 = a10; + _keyCode = 0; + _field_2C = 0; + _field_30 = 0; + _field_34 = 0; +} + +CObjstateCommand::CObjstateCommand() { + _value = 0; + _objCommandName = 0; +} + +bool CObjstateCommand::load(MfcArchive &file) { + debug(5, "CObjStateCommand::load()"); + + _objtype = kObjTypeObjstateCommand; + + _cmd.load(file); + + _value = file.readUint32LE(); + + _objCommandName = file.readPascalString(); + + return true; +} + +MessageQueue::MessageQueue() { + _field_14 = 0; + _parId = 0; + _dataId = 0; + _id = 0; + _isFinished = 0; + _flags = 0; + _queueName = 0; +} + +MessageQueue::MessageQueue(MessageQueue *src, int parId, int field_38) { + _counter = 0; + _field_38 = (field_38 == 0); + + for (Common::List<ExCommand *>::iterator it = src->_exCommands.begin(); it != src->_exCommands.end(); ++it) { + ExCommand *ex = new ExCommand(*it); + ex->_excFlags |= 2; + + _exCommands.push_back(ex); + } + _field_14 = src->_field_14; + + if (parId) + _parId = parId; + else + _parId = src->_parId; + + _id = g_fullpipe->_globalMessageQueueList->compact(); + _dataId = src->_dataId; + _flags = src->_flags; + + g_fullpipe->_globalMessageQueueList->addMessageQueue(this); + + _isFinished = 0; +} + +MessageQueue::~MessageQueue() { + for (Common::List<ExCommand *>::iterator it = _exCommands.begin(); it != _exCommands.end(); ++it) { + ExCommand *ex = (ExCommand *)*it; + + if (ex && ex->_excFlags & 2) + delete ex; + } + + _exCommands.clear(); + + if (_field_14) + delete _field_14; + + if (_flags & 2) { + g_fullpipe->_globalMessageQueueList->removeQueueById(_id); + } + + finish(); + + free(_queueName); +} + +bool MessageQueue::load(MfcArchive &file) { + debug(5, "MessageQueue::load()"); + + _dataId = file.readUint16LE(); + + int count = file.readUint16LE(); + + assert(g_fullpipe->_gameProjectVersion >= 12); + + _queueName = file.readPascalString(); + + for (int i = 0; i < count; i++) { + ExCommand *tmp = (ExCommand *)file.readClass(); + + _exCommands.push_back(tmp); + } + + _id = -1; + _field_14 = 0; + _parId = 0; + _isFinished = 0; + + return true; +} + +bool MessageQueue::chain(StaticANIObject *ani) { + if (checkGlobalExCommandList1() && checkGlobalExCommandList2()) { + if (!(getFlags() & 2)) { + g_fullpipe->_globalMessageQueueList->addMessageQueue(this); + _flags |= 2; + } + if (ani) { + ani->queueMessageQueue(this); + return true; + } else { + sendNextCommand(); + return true; + } + } + return false; +} + +void MessageQueue::update() { + if (_counter > 0) + _counter--; + + if (_exCommands.size()) { + sendNextCommand(); + } else if (_counter == 0) { + _isFinished = 1; + finish(); + } +} + +void MessageQueue::messageQueueCallback1(int par) { + // Autosave + debug(3, "STUB: MessageQueue::messageQueueCallback1()"); +} + +ExCommand *MessageQueue::getExCommandByIndex(uint idx) { + if (idx > _exCommands.size()) + return 0; + + Common::List<ExCommand *>::iterator it = _exCommands.begin(); + + while (idx) { + ++it; + idx--; + } + + return *it; +} + +void MessageQueue::sendNextCommand() { + if (_exCommands.size()) { + if (!(_flags & 4) && (_flags & 1)) { + messageQueueCallback1(16); + } + ExCommand *ex = _exCommands.front(); + + _exCommands.pop_front(); + + _counter++; + ex->_parId = _id; + ex->_excFlags |= (ex->_field_24 == 0 ? 1 : 0) | (ex->_field_3C != 0 ? 2 : 0); + + _flags |= 4; + ex->sendMessage(); + } else if (_counter <= 0) { + _isFinished = 1; + finish(); + } +} + +bool MessageQueue::checkGlobalExCommandList1() { + ExCommand *ex, *ex1; + + for (uint i = 0; i < getCount(); i++) { + ex = getExCommandByIndex(i); + + if (ex->_messageKind != 1 && ex->_messageKind != 20 && ex->_messageKind != 5 && ex->_messageKind != 27) + continue; + + for (Common::List<ExCommand *>::iterator it = g_fullpipe->_exCommandList.begin(); it != g_fullpipe->_exCommandList.end(); it++) { + ex1 = *it; + + if (ex1->_messageKind != 1 && ex1->_messageKind != 20 && ex1->_messageKind != 5 && ex1->_messageKind != 27) + continue; + + if (ex1->_keyCode != ex->_keyCode && ex1->_keyCode != -1 && ex->_keyCode != -1) + continue; + + MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(ex1->_parId); + + if (mq) { + if (mq->getFlags() & 1) + return false; + } + } + } + return true; +} + +bool MessageQueue::checkGlobalExCommandList2() { + ExCommand *ex, *ex1; + + for (uint i = 0; i < getCount(); i++) { + ex = getExCommandByIndex(i); + + if (ex->_messageKind != 1 && ex->_messageKind != 20 && ex->_messageKind != 5 && ex->_messageKind != 27) + continue; + + for (Common::List<ExCommand *>::iterator it = g_fullpipe->_exCommandList.begin(); it != g_fullpipe->_exCommandList.end();) { + ex1 = *it; + + if (ex1->_messageKind != 1 && ex1->_messageKind != 20 && ex1->_messageKind != 5 && ex1->_messageKind != 27) { + it++; + continue; + } + + if (ex1->_keyCode != ex->_keyCode && ex1->_keyCode != -1 && ex->_keyCode != -1) { + it++; + continue; + } + + MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(ex1->_parId); + + if (mq) { + if (mq->getFlags() & 1) + return false; + + delete mq; + } + + it = g_fullpipe->_exCommandList.erase(it); + + if (ex1->_excFlags & 2) { + delete ex1; + } + } + } + return true; +} + +void MessageQueue::finish() { + if (!_parId) + return; + + MessageQueue *mq = g_fullpipe->_globalMessageQueueList->getMessageQueueById(_parId); + + _parId = 0; + + if (!mq) + return; + + if (!_flag1) { + mq->update(); + return; + } + + mq->_counter--; + + if (!mq->_counter && !mq->_exCommands.size()) + mq->update(); +} + +void MessageQueue::replaceKeyCode(int key1, int key2) { + for (uint i = 0; i < getCount(); i++) { + ExCommand *ex = getExCommandByIndex(i); + int k = ex->_messageKind; + if ((k == 1 || k == 20 || k == 5 || k == 6 || k == 2 || k == 18 || k == 19 || k == 22 || k == 55) + && ex->_keyCode == key1) + ex->_keyCode = key2; + } +} + +int MessageQueue::calcDuration(StaticANIObject *obj) { + int res = 0; + ExCommand *ex; + Movement *mov; + + for (uint i = 0; (ex = getExCommandByIndex(i)); i++) + if (ex->_parentId == obj->_id) { + if (ex->_messageKind == 1 || ex->_messageKind == 20) { + if ((mov = obj->getMovementById(ex->_messageNum)) != 0) { + if (ex->_field_14 >= 1) + res += ex->_field_14; + else + res += mov->calcDuration(); + } + } + } + + return res; +} + +void MessageQueue::changeParam28ForObjectId(int objId, int oldParam28, int newParam28) { + for (uint i = 0; i < _exCommands.size(); i++) { + ExCommand *ex = getExCommandByIndex(i); + int k = ex->_messageKind; + + if ((k == 1 || k == 20 || k == 5 || k == 6 || k == 2 || k == 18 || k == 19 || k == 22 || k == 55) + && ex->_keyCode == oldParam28 + && ex->_parentId == objId) + ex->_keyCode = newParam28; + } +} + +MessageQueue *GlobalMessageQueueList::getMessageQueueById(int id) { + for (Common::Array<MessageQueue *>::iterator s = begin(); s != end(); ++s) { + if ((*s)->_id == id) + return *s; + } + + return 0; +} + +void GlobalMessageQueueList::deleteQueueById(int id) { + for (uint i = 0; i < size(); i++) + if (_storage[i]->_id == id) { + remove_at(i); + + disableQueueById(id); + return; + } +} + +void GlobalMessageQueueList::removeQueueById(int id) { + for (uint i = 0; i < size(); i++) + if (_storage[i]->_id == id) { + _storage[i]->_flags &= 0xFD; // It is quite pointless + remove_at(i); + + disableQueueById(id); + return; + } +} + +void GlobalMessageQueueList::disableQueueById(int id) { + for (Common::Array<MessageQueue *>::iterator s = begin(); s != end(); ++s) { + if ((*s)->_parId == id) + (*s)->_parId = 0; + } +} + +int GlobalMessageQueueList::compact() { + for (uint i = 0; i < size();) { + if (((MessageQueue *)_storage[i])->_isFinished) { + disableQueueById(_storage[i]->_id); + remove_at(i); + } else { + i++; + } + } + + return size() + 1; +} + +void GlobalMessageQueueList::addMessageQueue(MessageQueue *msg) { + msg->setFlags(msg->getFlags() | 2); + + push_back(msg); +} + +bool removeMessageHandler(int16 id, int pos) { + if (g_fullpipe->_messageHandlers) { + MessageHandler *curItem = g_fullpipe->_messageHandlers; + MessageHandler *prevItem = 0; + int curPos = 0; + + while (id != curItem->id) { + prevItem = curItem; + curItem = curItem->nextItem; + curPos++; + + if (!curItem) + return false; + } + + if (pos == -1 || curPos == pos) { + prevItem->nextItem = curItem->nextItem; + delete curItem; + updateMessageHandlerIndex(prevItem->nextItem, -1); + + return true; + } + } + + return false; +} + +void updateMessageHandlerIndex(MessageHandler *msg, int offset) { + for (; msg; msg = msg->nextItem) + msg->index += offset; +} + +void addMessageHandler(int (*callback)(ExCommand *), int16 id) { + if (getMessageHandlerById(id)) + return; + + MessageHandler *curItem = g_fullpipe->_messageHandlers; + + if (!curItem) + return; + + int index = 0; + for (MessageHandler *i = g_fullpipe->_messageHandlers->nextItem; i; i = i->nextItem) { + curItem = i; + index++; + } + + allocMessageHandler(curItem, id, callback, index); + + if (curItem) + updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); +} + +MessageHandler *getMessageHandlerById(int16 id) { + MessageHandler *curItem = g_fullpipe->_messageHandlers; + + if (!curItem) + return 0; + + while (id != curItem->id) { + curItem = curItem->nextItem; + + if (!curItem) + return 0; + } + + return curItem; +} + +bool allocMessageHandler(MessageHandler *where, int16 id, int (*callback)(ExCommand *), int index) { + MessageHandler *msg = new MessageHandler; + + if (where) { + msg->nextItem = where->nextItem; + where->nextItem = msg; + msg->id = id; + msg->callback = callback; + msg->index = index; + } else { + msg->nextItem = 0; + msg->id = id; + msg->callback = callback; + msg->index = 0; + + g_fullpipe->_messageHandlers = msg; + } + + return true; +} + +int getMessageHandlersCount() { + int result; + MessageHandler *curItem = g_fullpipe->_messageHandlers; + + for (result = 0; curItem; result++) + curItem = curItem->nextItem; + + return result; +} + +bool addMessageHandlerByIndex(int (*callback)(ExCommand *), int index, int16 id) { + if (getMessageHandlerById(id)) + return false; + + if (index) { + MessageHandler *curItem = g_fullpipe->_messageHandlers; + + for (int i = index - 1; i > 0; i--) + if (curItem) + curItem = curItem->nextItem; + + if (!curItem) + return false; + + bool res = allocMessageHandler(curItem, id, callback, index); + + if (res) + updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); + + return res; + } else { + MessageHandler *newItem = new MessageHandler; + + newItem->nextItem = g_fullpipe->_messageHandlers; + newItem->id = id; + newItem->callback = callback; + newItem->index = 0; + + updateMessageHandlerIndex(g_fullpipe->_messageHandlers, 1); + g_fullpipe->_messageHandlers = newItem; + + return true; + } +} + +bool insertMessageHandler(int (*callback)(ExCommand *), int index, int16 id) { + if (getMessageHandlerById(id)) + return false; + + MessageHandler *curItem = g_fullpipe->_messageHandlers; + + for (int i = index; i > 0; i--) + if (curItem) + curItem = curItem->nextItem; + + bool res = allocMessageHandler(curItem, id, callback, index + 1); + if (curItem) + updateMessageHandlerIndex(curItem->nextItem->nextItem, 1); + + return res; +} + +void clearMessageHandlers() { + MessageHandler *curItem; + MessageHandler *nextItem; + + curItem = g_fullpipe->_messageHandlers; + if (curItem) { + do { + nextItem = curItem->nextItem; + + delete curItem; + + curItem = nextItem; + } while (nextItem); + + g_fullpipe->_messageHandlers = 0; + } +} + +void processMessages() { + if (!g_fullpipe->_isProcessingMessages) { + g_fullpipe->_isProcessingMessages = true; + + while (g_fullpipe->_exCommandList.size()) { + ExCommand *ex = g_fullpipe->_exCommandList.front(); + g_fullpipe->_exCommandList.pop_front(); + ex->handleMessage(); + } + g_fullpipe->_isProcessingMessages = false; + } +} + +void updateGlobalMessageQueue(int id, int objid) { + MessageQueue *m = g_fullpipe->_globalMessageQueueList->getMessageQueueById(id); + if (m) { + m->update(); + } +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/messages.h b/engines/fullpipe/messages.h new file mode 100644 index 0000000000..960e184a88 --- /dev/null +++ b/engines/fullpipe/messages.h @@ -0,0 +1,174 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_MESSAGEQUEUE_H +#define FULLPIPE_MESSAGEQUEUE_H + +#include "fullpipe/utils.h" +#include "fullpipe/inventory.h" +#include "fullpipe/gfx.h" +#include "fullpipe/sound.h" +#include "fullpipe/scene.h" + +namespace Fullpipe { + +class Message : public CObject { + public: + int _messageKind; + int16 _parentId; + int _x; + int _y; + int _field_14; + int _sceneClickX; + int _sceneClickY; + int _field_20; + int _field_24; + int _keyCode; + int _field_2C; + int _field_30; + int _field_34; + + public: + Message(); + Message(Message *src); + virtual ~Message() {} + + Message(int16 parentId, int messageKind, int x, int y, int a6, int a7, int sceneClickX, int sceneClickY, int a10); +}; + +class ExCommand : public Message { + public: + + int _messageNum; + int _field_3C; + int _excFlags; + int _parId; + + ExCommand(); + ExCommand(ExCommand *src); + ExCommand(int16 parentId, int messageKind, int messageNum, int x, int y, int a7, int a8, int sceneClickX, int sceneClickY, int a11); + virtual ~ExCommand() {} + + virtual bool load(MfcArchive &file); + + bool handleMessage(); + void sendMessage(); + void postMessage(); + void handle(); +}; + +class ExCommand2 : public ExCommand { + public: + Common::Point **_points; + int _pointsSize; +}; + +class CObjstateCommand : public CObject { + public: + ExCommand _cmd; + char *_objCommandName; + int _value; + + public: + CObjstateCommand(); + virtual bool load(MfcArchive &file); +}; + +class MessageQueue : public CObject { + public: + int _id; + int _flags; + char *_queueName; + int16 _dataId; + int16 _field_12; + CObject *_field_14; + Common::List<ExCommand *> _exCommands; + int _counter; + int _field_38; + int _isFinished; + int _parId; + int _flag1; + + public: + MessageQueue(); + MessageQueue(MessageQueue *src, int parId, int field_38); + virtual ~MessageQueue(); + + virtual bool load(MfcArchive &file); + + int getFlags() { return _flags; } + void setFlags(int flags) { _flags = flags; } + + uint getCount() { return _exCommands.size(); } + + ExCommand *getExCommandByIndex(uint idx); + + void replaceKeyCode(int key1, int key2); + + bool chain(StaticANIObject *ani); + void update(); + void sendNextCommand(); + void finish(); + + void messageQueueCallback1(int par); + + bool checkGlobalExCommandList1(); + bool checkGlobalExCommandList2(); + + int calcDuration(StaticANIObject *obj); + void changeParam28ForObjectId(int objId, int oldParam28, int newParam28); +}; + +class GlobalMessageQueueList : public Common::Array<MessageQueue *> { + public: + MessageQueue *getMessageQueueById(int id); + void deleteQueueById(int id); + void removeQueueById(int id); + void disableQueueById(int id); + void addMessageQueue(MessageQueue *msg); + + int compact(); +}; + +struct MessageHandler { + int (*callback)(ExCommand *cmd); + int16 id; + int16 field_6; + int index; + MessageHandler *nextItem; +}; + +bool removeMessageHandler(int16 id, int pos); +void updateMessageHandlerIndex(MessageHandler *msg, int offset); +void addMessageHandler(int (*callback)(ExCommand *), int16 id); +MessageHandler *getMessageHandlerById(int16 id); +bool allocMessageHandler(MessageHandler *where, int16 id, int (*callback)(ExCommand *), int index); +int getMessageHandlersCount(); +bool addMessageHandlerByIndex(int (*callback)(ExCommand *), int index, int16 id); +bool insertMessageHandler(int (*callback)(ExCommand *), int index, int16 id); +void clearMessageHandlers(); +void processMessages(); +void updateGlobalMessageQueue(int id, int objid); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MESSAGEQUEUE_H */ diff --git a/engines/fullpipe/modal.cpp b/engines/fullpipe/modal.cpp new file mode 100644 index 0000000000..6f1bc0cc1f --- /dev/null +++ b/engines/fullpipe/modal.cpp @@ -0,0 +1,106 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" +#include "fullpipe/modal.h" +#include "fullpipe/messages.h" +#include "fullpipe/constants.h" +#include "fullpipe/scenes.h" + +namespace Fullpipe { + +bool CBaseModalObject::handleMessage(ExCommand *message) { + warning("STUB: CBaseModalObject::handleMessage()"); + + return true; +} + +bool CBaseModalObject::init(int counterdiff) { + warning("STUB: CBaseModalObject::init(%d)", counterdiff); + + return true; +} + +bool CBaseModalObject::update() { + warning("STUB: CBaseModalObject::update()"); + + return true; +} + +void CBaseModalObject::saveload() { + warning("STUB: CBaseModalObject::saveload()"); +} + + +CModalIntro::CModalIntro() { + _field_8 = 0; + _countDown = 0; + _needRedraw = 0; + if (g_vars->sceneIntro_skipIntro) { + _introFlags = 4; + } else { + _introFlags = 33; + _countDown = 150; + + PictureObject *pict = g_fullpipe->accessScene(SC_INTRO1)->getPictureObjectById(PIC_IN1_PIPETITLE, 0); + pict->setFlags(pict->_flags & 0xFFFB); + } + g_vars->sceneIntro_skipIntro = false; + _sfxVolume = g_fullpipe->_sfxVolume; +} + +bool CModalIntro::handleMessage(ExCommand *message) { + if (message->_messageKind != 17) + return false; + + if (message->_messageNum != 36) + return false; + + if (message->_keyCode != 13 && message->_keyCode != 27 && message->_keyCode != 32) + return false; + + if (_needRedraw) { + if (!(_introFlags & 0x10)) { + _countDown = 0; + g_vars->sceneIntro_needBlackout = true; + return true; + } + g_vars->sceneIntro_playing = false; + g_vars->sceneIntro_needBlackout = true; + } + + return true; +} + +void FullpipeEngine::openMap() { + warning("STUB: FullpipeEngine::openMap()"); +} + +void FullpipeEngine::openHelp() { + warning("STUB: FullpipeEngine::openHelp()"); +} + +void FullpipeEngine::openMainMenu() { + warning("STUB: FullpipeEngine::openMainMenu()"); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/modal.h b/engines/fullpipe/modal.h new file mode 100644 index 0000000000..73236e8e5b --- /dev/null +++ b/engines/fullpipe/modal.h @@ -0,0 +1,59 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_MODAL_H +#define FULLPIPE_MODAL_H + +namespace Fullpipe { + +class CBaseModalObject { + public: + + CBaseModalObject *_parentObj; + + public: + CBaseModalObject() : _parentObj(0) {} + virtual ~CBaseModalObject() {} + + virtual bool handleMessage(ExCommand *message); + virtual bool init(int counterdiff); + virtual bool update(); + + void saveload(); +}; + +class CModalIntro : public CBaseModalObject { + int _field_8; + int _introFlags; + int _countDown; + int _needRedraw; + int _sfxVolume; + + public: + CModalIntro(); + + virtual bool handleMessage(ExCommand *message); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MODAL_H */ diff --git a/engines/fullpipe/module.mk b/engines/fullpipe/module.mk new file mode 100644 index 0000000000..380f582c08 --- /dev/null +++ b/engines/fullpipe/module.mk @@ -0,0 +1,31 @@ +MODULE := engines/fullpipe + +MODULE_OBJS = \ + behavior.o \ + detection.o \ + fullpipe.o \ + gameloader.o \ + gfx.o \ + init.o \ + input.o \ + interaction.o \ + inventory.o \ + lift.o \ + messages.o \ + modal.o \ + motion.o \ + ngiarchive.o \ + scene.o \ + scenes.o \ + sound.o \ + stateloader.o \ + statics.o \ + utils.o + +# This module can be built as a plugin +ifeq ($(ENABLE_FULLPIPE), DYNAMIC_PLUGIN) +PLUGIN := 1 +endif + +# Include common rules +include $(srcdir)/rules.mk diff --git a/engines/fullpipe/motion.cpp b/engines/fullpipe/motion.cpp new file mode 100644 index 0000000000..514dde5185 --- /dev/null +++ b/engines/fullpipe/motion.cpp @@ -0,0 +1,280 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "common/file.h" +#include "common/array.h" +#include "common/list.h" + +#include "fullpipe/objects.h" +#include "fullpipe/motion.h" + +namespace Fullpipe { + +bool CMotionController::load(MfcArchive &file) { + // Is originally empty file.readClass(); + + debug(5, "CMotionController::load()"); + + return true; +} + +bool CMctlCompound::load(MfcArchive &file) { + debug(5, "CMctlCompound::load()"); + + int count = file.readUint32LE(); + + debug(6, "CMctlCompound::count = %d", count); + + for (int i = 0; i < count; i++) { + debug(6, "CompoundArray[%d]", i); + CMctlCompoundArrayItem *obj = (CMctlCompoundArrayItem *)file.readClass(); + + int count1 = file.readUint32LE(); + + debug(6, "ConnectionPoint::count: %d", count1); + for (int j = 0; j < count1; j++) { + debug(6, "ConnectionPoint[%d]", j); + CMctlConnectionPoint *obj1 = (CMctlConnectionPoint *)file.readClass(); + + obj->_connectionPoints.push_back(*obj1); + } + + obj->_field_20 = file.readUint32LE(); + obj->_field_24 = file.readUint32LE(); + + debug(6, "graphReact"); + obj->_movGraphReactObj = (CMovGraphReact *)file.readClass(); + + _motionControllers.push_back(*obj); + } + + return true; +} + +void CMctlCompound::addObject(StaticANIObject *obj) { + warning("STUB: CMctlCompound::addObject()"); +} + +void CMctlCompound::initMovGraph2() { + warning("STUB: CMctlCompound::initMovGraph2()"); +} + +MessageQueue *CMctlCompound::method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { + warning("STUB: CMctlCompound::method34()"); + + return 0; +} + +MessageQueue *CMctlCompound::method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId) { + warning("STUB: CMctlCompound::method4C()"); + + return 0; +} + +bool CMctlCompoundArray::load(MfcArchive &file) { + debug(5, "CMctlCompoundArray::load()"); + + int count = file.readUint32LE(); + + debug(0, "CMctlCompoundArray::count = %d", count); + + assert(0); + + return true; +} + +CMovGraph::CMovGraph() { + warning("STUB: CMovGraph::CMovGraph()"); + _itemsCount = 0; + _items = 0; + //_callback1 = CMovGraphCallback1; // TODO + _field_44 = 0; + // insertMessageHandler(CMovGraph_messageHandler, getMessageHandlersCount() - 1, 129); +} + +bool CMovGraph::load(MfcArchive &file) { + debug(5, "CMovGraph::load()"); + + _links.load(file); + _nodes.load(file); + + return true; +} + +void CMovGraph::addObject(StaticANIObject *obj) { + warning("STUB: CMovGraph::addObject()"); +} + +CMovGraphLink::CMovGraphLink() { + _distance = 0; + _angle = 0; + _flags = 0x10000000; + _movGraphNode2 = 0; + _movGraphNode1 = 0; + _field_3C = 0; + _field_38 = 0; + _movGraphReact = 0; + _name = 0; +} + +bool CMovGraphLink::load(MfcArchive &file) { + debug(5, "CMovGraphLink::load()"); + + _dwordArray1.load(file); + _dwordArray2.load(file); + + _flags = file.readUint32LE(); + + debug(8, "GraphNode1"); + _movGraphNode1 = (CMovGraphNode *)file.readClass(); + debug(8, "GraphNode2"); + _movGraphNode2 = (CMovGraphNode *)file.readClass(); + + _distance = file.readDouble(); + _angle = file.readDouble(); + + debug(8, "distance: %g, angle: %g", _distance, _angle); + + _movGraphReact = (CMovGraphReact *)file.readClass(); + _name = file.readPascalString(); + + return true; +} + +bool CMovGraphNode::load(MfcArchive &file) { + debug(5, "CMovGraphNode::load()"); + + _field_14 = file.readUint32LE(); + _x = file.readUint32LE(); + _y = file.readUint32LE(); + _distance = file.readUint32LE(); + + return true; +} + +CReactParallel::CReactParallel() { + _x1 = 0; + _x2 = 0; + _dy = 0; + _dx = 0; + _points = 0; + _y1 = 0; + _y2 = 0; +} + +bool CReactParallel::load(MfcArchive &file) { + debug(5, "CReactParallel::load()"); + + _x1 = file.readUint32LE(); + _y1 = file.readUint32LE(); + _x2 = file.readUint32LE(); + _y2 = file.readUint32LE(); + _dx = file.readUint32LE(); + _dy = file.readUint32LE(); + + createRegion(); + + return true; +} + +void CReactParallel::createRegion() { + _points = (Common::Point **)malloc(sizeof(Common::Point *) * 4); + + for (int i = 0; i < 4; i++) + _points[i] = new Common::Point; + + double at = atan2((double)(_x1 - _x2), (double)(_y1 - _y2)) + 1.570796; + double sn = sin(at); + double cs = cos(at); + + _points[0]->x = (int16)(_x1 - _dx * cs); + _points[0]->y = (int16)(_y1 - _dx * sn); + + _points[1]->x = (int16)(_x2 - _dx * cs); + _points[1]->y = (int16)(_y2 - _dx * sn); + + _points[2]->x = (int16)(_x1 + _dy * cs); + _points[2]->y = (int16)(_y2 + _dy * sn); + + _points[3]->x = (int16)(_x1 + _dy * cs); + _points[3]->y = (int16)(_y1 + _dy * sn); + + // GdiObject::Attach(_rgn, CreatePolygonRgn(_points, 4, 2); +} + +CReactPolygonal::CReactPolygonal() { + _field_C = 0; + _points = 0; + _pointCount = 0; + _field_10 = 0; +} + +bool CReactPolygonal::load(MfcArchive &file) { + debug(5, "CReactPolygonal::load()"); + + _field_C = file.readUint32LE(); + _field_10 = file.readUint32LE(); + _pointCount = file.readUint32LE(); + + if (_pointCount > 0) { + _points = (Common::Point **)malloc(sizeof(Common::Point *) * _pointCount); + + for (int i = 0; i < _pointCount; i++) { + _points[i] = new Common::Point; + + _points[i]->x = file.readUint32LE(); + _points[i]->y = file.readUint32LE(); + } + + } + + createRegion(); + + return true; +} + +void CReactPolygonal::createRegion() { + if (_points) { + + // GdiObject::Attach(_rgn, CreatePolygonRgn(_points, _pointCount, 2); + } +} + +int startWalkTo(int objId, int objKey, int x, int y, int a5) { + warning("STUB: startWalkTo(%d, %d, %d, %d, %d)", objId, objKey, x, y, a5); + + return 0; +} + +int doSomeAnimation(int objId, int objKey, int a3) { + warning("STUB: doSomeAnimation(%d, %d, %d)", objId, objKey, a3); + + return 0; +} + +int doSomeAnimation2(int objId, int objKey) { + return doSomeAnimation(objId, objKey, 0); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/motion.h b/engines/fullpipe/motion.h new file mode 100644 index 0000000000..89a98967fb --- /dev/null +++ b/engines/fullpipe/motion.h @@ -0,0 +1,185 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_MOTION_H +#define FULLPIPE_MOTION_H + +namespace Fullpipe { + +int startWalkTo(int objId, int objKey, int x, int y, int a5); +int doSomeAnimation(int objId, int objKey, int a3); +int doSomeAnimation2(int objId, int objKey); + +class CMotionController : public CObject { + public: + int _field_4; + bool _isEnabled; + + public: + CMotionController() : _isEnabled(true) {} + virtual bool load(MfcArchive &file); + + void setEnabled() { _isEnabled = true; } + void clearEnabled() { _isEnabled = false; } + + virtual void addObject(StaticANIObject *obj) {} +}; + +class CMctlCompoundArray : public Common::Array<CObject>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class CMctlConnectionPointsArray : public Common::Array<CObject>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class CMctlCompound : public CMotionController { + CMctlCompoundArray _motionControllers; + + public: + virtual bool load(MfcArchive &file); + + virtual void addObject(StaticANIObject *obj); + void initMovGraph2(); + + MessageQueue *method34(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); + MessageQueue *method4C(StaticANIObject *subj, int xpos, int ypos, int flag, int staticsId); +}; + +class Unk2 : public CObject { + int _items; + int _count; + + public: + Unk2() : _items(0), _count(0) {} +}; + +class CMovGraphNode : public CObject { + int _x; + int _y; + int _distance; + int16 _field_10; + int _field_14; + + public: + CMovGraphNode() : _x(0), _y(0), _distance(0), _field_10(0), _field_14(0) {} + virtual bool load(MfcArchive &file); +}; + +class CMovGraphReact : public CObject { + // Empty +}; + +class CMctlCompoundArrayItem : public CObject { + friend class CMctlCompound; + + protected: + CMotionController *_motionControllerObj; + CMovGraphReact *_movGraphReactObj; + CMctlConnectionPointsArray _connectionPoints; + int _field_20; + int _field_24; + int _field_28; + + public: + CMctlCompoundArrayItem() : _movGraphReactObj(0) {} +}; + +class CReactParallel : public CMovGraphReact { + //CRgn _rgn; + int _x1; + int _y1; + int _x2; + int _y2; + int _dx; + int _dy; + Common::Point **_points; + + public: + CReactParallel(); + virtual bool load(MfcArchive &file); + void createRegion(); +}; + +class CReactPolygonal : public CMovGraphReact { + //CRgn _rgn; + int _field_C; + int _field_10; + int _pointCount; + Common::Point **_points; + + public: + CReactPolygonal(); + virtual bool load(MfcArchive &file); + void createRegion(); +}; + +class CMovGraphLink : public CObject { + CMovGraphNode *_movGraphNode1; + CMovGraphNode *_movGraphNode2; + CDWordArray _dwordArray1; + CDWordArray _dwordArray2; + int _flags; + int _field_38; + int _field_3C; + double _distance; + double _angle; + CMovGraphReact *_movGraphReact; + char *_name; + + public: + CMovGraphLink(); + virtual bool load(MfcArchive &file); +}; + +class CMovGraph : public CMotionController { + CObList _nodes; + CObList _links; + int _field_44; + int _items; + int _itemsCount; + int (*_callback1)(int, int, int); + Unk2 _unk2; + + public: + CMovGraph(); + virtual bool load(MfcArchive &file); + + virtual void addObject(StaticANIObject *obj); +}; + +class CMctlConnectionPoint : public CObject { + int _connectionX; + int _connectionY; + int _field_C; + int _field_10; + int16 _field_14; + int16 _field_16; + int _messageQueueObj; + int _motionControllerObj; +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_MOTION_H */ diff --git a/engines/fullpipe/ngiarchive.cpp b/engines/fullpipe/ngiarchive.cpp new file mode 100644 index 0000000000..5d895c17a0 --- /dev/null +++ b/engines/fullpipe/ngiarchive.cpp @@ -0,0 +1,156 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" +#include "common/archive.h" + +#include "common/file.h" +#include "common/hash-str.h" +#include "common/memstream.h" +#include "common/bufferedstream.h" +#include "common/textconsole.h" + +#include "fullpipe/ngiarchive.h" + +namespace Fullpipe { + +NGIArchive::NGIArchive(const Common::String &filename) : _ngiFilename(filename) { + Common::File ngiFile; + + if (!ngiFile.open(_ngiFilename)) { + warning("NGIArchive::NGIArchive(): Could not find the archive file"); + return; + } + + ngiFile.seek(4, SEEK_SET); + + unsigned int count = ngiFile.readUint16LE(); // How many entries? + + ngiFile.seek(20, SEEK_SET); + + unsigned int key = ngiFile.readUint16LE(); + + byte key1, key2; + + key1 = key & 0xff; + key2 = (key >> 8) & 0xff; + + int fatSize = count * 32; + + ngiFile.seek(32, SEEK_SET); + + byte *fat = (byte *)calloc(fatSize, 1); + + ngiFile.read(fat, fatSize); + + for (int i = 0; i < fatSize; i++) { + key1 = (key1 << 1) ^ key2; + key2 = (key2 >> 1) ^ key1; + + fat[i] ^= key1; + } + + NgiHeader header; + NgiHeader *head; + + for (uint i = 0; i < count; i++) { + memcpy(header.filename, &fat[i * 32], 12); + header.filename[12] = 0; + header.flags = READ_LE_UINT32(&fat[i * 32 + 16]); + header.extVal = READ_LE_UINT32(&fat[i * 32 + 20]); + header.pos = READ_LE_UINT32(&fat[i * 32 + 24]); + header.size = READ_LE_UINT32(&fat[i * 32 + 28]); + + if (header.flags & 0x1e0) { + warning("File has flags: %.8x\n", header.flags & 0x1e0); + } + + head = new NgiHeader(header); + + _headers[header.filename] = head; + } + + free(fat); + + g_fullpipe->_currArchive = this; + + debug(0, "NGIArchive::NGIArchive(%s): Located %d files", filename.c_str(), _headers.size()); +} + +NGIArchive::~NGIArchive() { + debug(0, "NGIArchive Destructor Called"); + NgiHeadersMap::iterator it = _headers.begin(); + for ( ; it != _headers.end(); ++it) { + delete it->_value; + } + + g_fullpipe->_currArchive = 0; +} + +bool NGIArchive::hasFile(const Common::String &name) const { + return _headers.contains(name); +} + + int NGIArchive::listMembers(Common::ArchiveMemberList &list) const { + int matches = 0; + + NgiHeadersMap::const_iterator it = _headers.begin(); + for ( ; it != _headers.end(); ++it) { + list.push_back(Common::ArchiveMemberList::value_type(new Common::GenericArchiveMember(it->_value->filename, this))); + matches++; + } + + return matches; +} + +const Common::ArchiveMemberPtr NGIArchive::getMember(const Common::String &name) const { + if (!hasFile(name)) + return Common::ArchiveMemberPtr(); + + return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(name, this)); +} + +Common::SeekableReadStream *NGIArchive::createReadStreamForMember(const Common::String &name) const { + if (!_headers.contains(name)) { + return 0; + } + + NgiHeader *hdr = _headers[name]; + + Common::File archiveFile; + archiveFile.open(_ngiFilename); + archiveFile.seek(hdr->pos, SEEK_SET); + + byte *data = (byte *)malloc(hdr->size); + assert(data); + + int32 len = archiveFile.read(data, hdr->size); + assert(len == hdr->size); + + return new Common::MemoryReadStream(data, hdr->size, DisposeAfterUse::YES); +} + +Common::Archive *makeNGIArchive(const Common::String &name) { + return new NGIArchive(name); +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/ngiarchive.h b/engines/fullpipe/ngiarchive.h new file mode 100644 index 0000000000..a5b05a2e50 --- /dev/null +++ b/engines/fullpipe/ngiarchive.h @@ -0,0 +1,69 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_NGIARCHIVE_H +#define FULLPIPE_NGIARCHIVE_H + +#include "common/str.h" + +namespace Fullpipe { + +class Archive; + +#define NGI_FILENAME_MAX 13 + +struct NgiHeader { + int32 pos; + int32 extVal; + int32 flags; + int32 size; + char filename[NGI_FILENAME_MAX]; +}; + +typedef Common::HashMap<Common::String, NgiHeader*, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> NgiHeadersMap; + +class NGIArchive : public Common::Archive { + NgiHeadersMap _headers; + Common::String _ngiFilename; + +public: + NGIArchive(const Common::String &name); + virtual ~NGIArchive(); + + // Archive implementation + virtual bool hasFile(const Common::String &name) const; + virtual int listMembers(Common::ArchiveMemberList &list) const; + virtual const Common::ArchiveMemberPtr getMember(const Common::String &name) const; + virtual Common::SeekableReadStream *createReadStreamForMember(const Common::String &name) const; +}; + +/** + * This factory method creates an Archive instance corresponding to the content + * of the NGI compressed file with the given name. + * + * May return 0 in case of a failure. + */ +Common::Archive *makeNGIArchive(const Common::String &name); + +} // End of namespace Fullpipe + +#endif diff --git a/engines/fullpipe/objectnames.h b/engines/fullpipe/objectnames.h new file mode 100644 index 0000000000..015df727e9 --- /dev/null +++ b/engines/fullpipe/objectnames.h @@ -0,0 +1,250 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +// This file is used in order to avoid usage of constants in Russian accross the code + +#ifndef FULLPIPE_OBJECTNAMES_H +#define FULLPIPE_OBJECTNAMES_H + +namespace Fullpipe { + +#define sO_Grandma "\xc1\xe0\xe1\xf3\xeb\xff" // "Бабуля" +#define sO_Jar_4 "\xc1\xe0\xed\xea\xe0_4" // "Банка_4" +#define sO_Pool "\xc1\xe0\xf1\xf1\xe5\xe9\xed" // "Бассейн" +#define sO_TumyTrampie "\xc1\xe0\xf2\xf3\xf2\xe0" // "Батута" +#define sO_WithoutBoot "\xc1\xe5\xe7 \xe1\xee\xf2\xe8\xed\xea\xe0" // "Без ботинка" +#define sO_WithoutJug "\xc1\xe5\xe7 \xe3\xee\xf0\xf8\xea\xee\xe2" // "Без горшков" +#define sO_WithoutCarpet "\xc1\xe5\xe7 \xea\xee\xe2\xf0\xe8\xea\xe0" // "Без коврика" +#define sO_WithoutCoin "\xc1\xe5\xe7 \xec\xee\xed\xe5\xf2\xfb" // "Без монеты" +#define sO_WithNothing "\xc1\xe5\xe7 \xed\xe8\xf7\xe5\xe3\xee" // "Без ничего" +#define sO_WithoutHandle "\xc1\xe5\xe7 \xf0\xf3\xf7\xea\xe8" // "Без ручки" +#define sO_WithoutStool "\xc1\xe5\xe7 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xe8" // "Без табуретки" +#define sO_WithoutDrawer "\xc1\xe5\xe7 \xff\xf9\xe8\xea\xe0" // "Без ящика" +#define sO_Blocked "\xc1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed" // "Блокирован" +#define sO_BlockedShe "\xc1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed\xe0" // "Блокирована" +#define sO_Awaken "\xc1\xee\xe4\xf0\xf1\xf2\xe2\xf3\xe5\xf2" // "Бодрствует" +#define sO_Boot_15 "\xc1\xee\xf2\xe8\xed\xee\xea_15" // "Ботинок_15" +#define sO_Bottle_38 "\xc1\xf3\xf2\xfb\xeb\xea\xe0_38" // "Бутылка_38" +#define sO_InSmokeRoom "\xc2 \xea\xf3\xf0\xe8\xeb\xea\xe5" // "В курилке" +#define sO_InSock "\xc2 \xed\xee\xf1\xea\xe5" // "В носке" +#define sO_InGlasses "\xc2 \xee\xf7\xea\xe0\xf5" // "В очках" +#define sO_In_14 "\xc2_14" // "В_14" +#define sO_In_32_Lies "\xc2_32 \xeb\xe5\xe6\xe8\xf2" // "В_32 лежит" +#define sO_In_32_Stands "\xc2_32 \xf2\xee\xf0\xf7\xe8\xf2" // "В_32 торчит" +#define sO_In_33 "\xc2_33" // "В_33" +#define sO_In_7 "\xc2_7" // "В_7" +#define sO_Together "\xc2\xe4\xe2\xee\xe5\xec" // "Вдвоем" +#define sO_Valve1_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x31_26" // "Вентиль1_26" +#define sO_Valve2_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x32_26" // "Вентиль2_26" +#define sO_Valve3_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x33_26" // "Вентиль3_26" +#define sO_Valve4_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x34_26" // "Вентиль4_26" +#define sO_Valve5_26 "\xc2\xe5\xed\xf2\xe8\xeb\xfc\x35_26" // "Вентиль5_26" +#define sO_Valve_34 "\xc2\xe5\xed\xf2\xe8\xeb\xfc_34" // "Вентиль_34" +#define sO_UpperHatch_23 "\xc2\xe5\xf0\xf5\xed\xe8\xe9 \xeb\xfe\xea_23" // "Верхний люк_23" +#define sO_Taken "\xc2\xe7\xff\xf2" // "Взят" +#define sO_HangsOnPipe "\xc2\xe8\xf1\xe8\xf2 \xed\xe0 \xf2\xf0\xf3\xe1\xe5" // "Висит на трубе" +#define sO_On "\xc2\xea\xeb" // "Вкл" +#define sO_TurnedOn "\xc2\xea\xeb\xfe\xf7\xe5\xed" // "Включен" +#define sO_Driver "\xc2\xee\xe4\xe8\xeb\xe0" // "Водила" +#define sO_HareTheNooksiter "\xc2\xf3\xe3\xeb\xf3\xf1\xe5\xe4" // "Вуглусед" +#define sO_Off "\xc2\xfb\xea\xeb" // "Выкл" +#define sO_TurnedOff "\xc2\xfb\xea\xeb\xfe\xf7\xe5\xed" // "Выключен" +#define sO_HasGrown "\xc2\xfb\xf0\xee\xf1" // "Вырос" +#define sO_Boss "\xc3\xeb\xe0\xe2\xe0\xf0\xfc" // "Главарь" +#define sO_Jug "\xc3\xee\xf0\xf8\xee\xea" // "Горшок" +#define sO_Strolling "\xc3\xf3\xeb\xff\xe5\xf2" // "Гуляет" +#define sO_Yes "\xc4\xe0" // "Да" +#define sO_Girl "\xc4\xe5\xe2\xee\xf7\xea\xe0" // "Девочка" +#define sO_Elephantine "\xc4\xe5\xe2\xee\xf7\xea\xe0-\xf1\xeb\xee\xed\xe8\xea" // "Девочка-слоник" +#define sO_Grandpa "\xc4\xe5\xe4\xf3\xf8\xea\xe0" // "Дедушка" +#define sO_Plank_25 "\xc4\xee\xf1\xea\xe0_25" // "Доска_25" +#define sO_Plank_34 "\xc4\xee\xf1\xea\xe0_34" // "Доска_34" +#define sO_DudeJumped "\xc4\xff\xe4\xff \xef\xf0\xfb\xe3\xe0\xeb" // "Дядя прыгал" +#define sO_Dude "\xc4\xff\xe4\xff" // "Дядя" +#define sO_GuvTheDrawer "\xc4\xff\xe4\xff-\xff\xf9\xe8\xea" // "Дядя-ящик" +#define sO_DudeSwinged "\xc4\xff\xe4\xff_\xea\xe0\xf2\xe0\xeb\xf1\xff" // "Дядя_катался" +#define sO_Eats "\xc5\xf1\xf2" // "Ест" +#define sO_Present "\xc5\xf1\xf2\xfc" // "Есть" +#define sO_CloseThing1 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 1" // "Закрываемое 1" +#define sO_CloseThing2 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 2" // "Закрываемое 2" +#define sO_CloseThing3 "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5 3" // "Закрываемое 3" +#define sO_CloseThing "\xc7\xe0\xea\xf0\xfb\xe2\xe0\xe5\xec\xee\xe5" // "Закрываемое" +#define sO_Closed "\xc7\xe0\xea\xf0\xfb\xf2" // "Закрыт" +#define sO_ClosedWithBoot "\xc7\xe0\xea\xf0\xfb\xf2\xe0 \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec" // "Закрыта с ботинком" +#define sO_ClosedShe "\xc7\xe0\xea\xf0\xfb\xf2\xe0" // "Закрыта" +#define sO_HalfFull "\xc7\xe0\xef\xee\xeb\xed\xe5\xed \xed\xe0\xef\xee\xeb\xee\xe2\xe8\xed\xf3" // "Заполнен наполовину" +#define sO_Full "\xc7\xe0\xef\xee\xeb\xed\xe5\xed \xf6\xe5\xeb\xe8\xea\xee\xec" // "Заполнен целиком" +#define sO_MirroredTo "\xc7\xe5\xf0\xea\xe0\xeb\xfc\xed\xe0\xff \xea" // "Зеркальная к" +#define sO_Playing "\xc8\xe3\xf0\xe0\xe5\xf2" // "Играет" +#define sO_Tub "\xca\xe0\xe4\xea\xe0" // "Кадка" +#define sO_Cactus "\xca\xe0\xea\xf2\xf3\xf1" // "Кактус" +#define sO_SwingingWithBoot "\xca\xe0\xf2\xe0\xe5\xf2\xf1\xff \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec" // "Катается с ботинком" +#define sO_Swinging "\xca\xe0\xf2\xe0\xe5\xf2\xf1\xff" // "Катается" +#define sO_Swingie "\xca\xe0\xf7\xe5\xeb\xe5\xed\xff" // "Качеленя" +#define sO_LiftButtons "\xca\xed\xee\xef\xea\xe8 \xeb\xe8\xf4\xf2\xe0" // "Кнопки лифта" +#define sO_Carpet_35 "\xca\xee\xe2\xf0\xe8\xea_35" // "Коврик_35" +#define sO_Valve_35 "\xca\xf0\xe0\xed_35" // "Кран_35" +#define sO_Cup "\xca\xf0\xf3\xe6\xea\xe0" // "Кружка" +#define sO_Cube "\xca\xf3\xe1\xe8\xea" // "Кубик" +#define sO_LeftPipe_15 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_15" // "Левая труба_15" +#define sO_LeftPipe_26 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_26" // "Левая труба_26" +#define sO_LeftPipe_29 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_29" // "Левая труба_29" +#define sO_LeftPipe_30 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_30" // "Левая труба_30" +#define sO_LeftPipe_37 "\xcb\xe5\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_37" // "Левая труба_37" +#define sO_StarsDown_24 "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0 \xe2\xed\xe8\xe7_24" // "Лестница вниз_24" +#define sO_StairsUp_8 "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0 \xf1\xe2\xe5\xf0\xf5\xf3_8" // "Лестница сверху_8" +#define sO_Stairway "\xcb\xe5\xf1\xf2\xed\xe8\xf6\xe0" // "Лестница" +#define sO_Fliers "\xcb\xe5\xf2\xf3\xed\xfb" // "Летуны" +#define sO_Hatch_26 "\xcb\xfe\xea_26" // "Люк_26" +#define sO_Hatch_34 "\xcb\xfe\xea_34" // "Люк_34" +#define sO_MommyOfHandle_32 "\xcc\xe0\xec\xe0 \xf0\xf3\xf7\xea\xe8_32" // "Мама ручки_32" +#define sO_BigMumsy "\xcc\xe0\xec\xe0\xf8\xe0" // "Мамаша" +#define sO_Bag_22 "\xcc\xe5\xf8\xee\xea_22" // "Мешок_22" +#define sO_CoinSlot_1 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea 1" // "Монетоприемник 1" +#define sO_CoinSlot_22 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea_22" // "Монетоприемник_22" +#define sO_CoinSlot_35 "\xcc\xee\xed\xe5\xf2\xee\xef\xf0\xe8\xe5\xec\xed\xe8\xea_35" // "Монетоприемник_35" +#define sO_Bridge "\xcc\xee\xf1\xf2" // "Мост" +#define sO_Fly_12 "\xcc\xf3\xf5\xe0_12" // "Муха_12" +#define sO_Fly_17 "\xcc\xf3\xf5\xe0_17" // "Муха_17" +#define sO_OnTheFloor "\xcd\xe0 \xef\xee\xeb\xf3" // "На полу" +#define sO_OnTheSpring "\xcd\xe0 \xef\xf0\xf3\xe6\xe8\xed\xe5" // "На пружине" +#define sO_OnTheTable "\xcd\xe0 \xf1\xf2\xee\xeb\xe5" // "На столе" +#define sO_OnStool "\xcd\xe0 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xe5" // "На табуретке" +#define sO_Inflater "\xcd\xe0\xe4\xf3\xe2\xe0\xf2\xe5\xeb\xfc" // "Надуватель" +#define sO_NotTaken "\xcd\xe5 \xe2\xe7\xff\xf2" // "Не взят" +#define sO_NotHanging "\xcd\xe5 \xe2\xe8\xf1\xe8\xf2" // "Не висит" +#define sO_NotGrown "\xcd\xe5 \xe2\xfb\xf0\xee\xf1" // "Не вырос" +#define sO_DidNotCrackEgg "\xcd\xe5 \xea\xee\xeb\xee\xeb \xff\xe9\xf6\xee" // "Не колол яйцо" +#define sO_NotFallen "\xcd\xe5 \xef\xe0\xe4\xe0\xeb" // "Не падал" +#define sO_NotAvailable "\xcd\xe5\xe4\xee\xf1\xf2\xf3\xef\xed\xe0" // "Недоступна" +#define sO_CannotTake "\xcd\xe5\xeb\xfc\xe7\xff \xe2\xe7\xff\xf2\xfc" // "Нельзя взять" +#define sO_No "\xcd\xe5\xf2" // "Нет" +#define sO_LowerHatch_23 "\xcd\xe8\xe6\xed\xe8\xe9 \xeb\xfe\xea_23" // "Нижний люк_23" +#define sO_LowerPipe "\xcd\xe8\xe6\xed\xff\xff \xf2\xf0\xf3\xe1\xe0" // "Нижняя труба" +#define sO_LowerPipe_21 "\xcd\xe8\xe6\xed\xff\xff \xf2\xf0\xf3\xe1\xe0_21" // "Нижняя труба_21" +#define sO_WantsNothing "\xcd\xe8\xf7\xe5\xe3\xee \xed\xe5 \xf5\xee\xf7\xe5\xf2" // "Ничего не хочет" +#define sO_Leg "\xcd\xee\xe3\xe0" // "Нога" +#define sO_FriesPit "\xcd\xee\xf0\xea\xe0 \xea\xee\xe7\xff\xe2\xea\xe8" // "Норка козявки" +#define sO_Sock_26 "\xcd\xee\xf1\xee\xea_26" // "Носок_26" +#define sO_ClockAxis "\xce\xf1\xfc \xf7\xe0\xf1\xee\xe2" // "Ось часов" +#define sO_Opened "\xce\xf2\xea\xf0\xfb\xf2" // "Открыт" +#define sO_OpenedWithBoot "\xce\xf2\xea\xf0\xfb\xf2\xe0 \xf1 \xe1\xee\xf2\xe8\xed\xea\xee\xec" // "Открыта с ботинком" +#define sO_OpenedShe "\xce\xf2\xea\xf0\xfb\xf2\xe0" // "Открыта" +#define sO_WeirdWacko "\xce\xf2\xec\xee\xf0\xee\xe6\xe5\xed\xed\xfb\xe9" // "Отмороженный" +#define sO_NotPresent "\xce\xf2\xf1\xf3\xf2\xf1\xf2\xe2\xf3\xe5\xf2" // "Отсутствует" +#define sO_Error "\xce\xf8\xe8\xe1\xea\xe0" // "Ошибка" +#define sO_Passive "\xcf\xe0\xf1\xf1\xe8\xe2\xed\xe0" // "Пассивна" +#define sO_First "\xcf\xe5\xf0\xe2\xfb\xe9" // "Первый" +#define sO_UpsideDown "\xcf\xe5\xf0\xe5\xe2\xe5\xf0\xed\xf3\xf2\xe0" // "Перевернута" +#define sO_Overfull "\xcf\xe5\xf0\xe5\xef\xee\xeb\xed\xe5\xed" // "Переполнен" +#define sO_Fireman "\xcf\xee\xe6\xe0\xf0\xed\xe8\xea" // "Пожарник" +#define sO_ShowingHeel "\xcf\xee\xea\xe0\xe7\xfb\xe2\xe0\xe5\xf2 \xef\xff\xf2\xea\xf3" // "Показывает пятку" +#define sO_FullPipe "\xcf\xee\xeb\xed\xe0\xff \xd2\xf0\xf3\xe1\xe0" // "Полная Труба" +#define sO_RightStairs_9 "\xcf\xf0\xe0\xe2\xe0\xff \xeb\xe5\xf1\xf2\xed\xe8\xf6\xe0_9" // "Правая лестница_9" +#define sO_RightPipe_17 "\xcf\xf0\xe0\xe2\xe0\xff \xf2\xf0\xf3\xe1\xe0_17" // "Правая труба_17" +#define sO_Available "\xcf\xf0\xe8\xf1\xf3\xf2\xf1\xf2\xe2\xf3\xe5\xf2" // "Присутствует" +#define sO_GulpedEgg "\xcf\xf0\xee\xe3\xeb\xee\xf7\xe5\xed\xed\xee\xe5 \xff\xe9\xf6\xee" // "Проглоченное яйцо" +#define sO_GulpedEggs "\xcf\xf0\xee\xe3\xeb\xee\xf7\xe5\xed\xed\xfb\xe5 \xff\xe9\xf6\xe0" // "Проглоченные яйца" +#define sO_BellyInflater "\xcf\xf3\xe7\xee\xe4\xf3\xe2" // "Пузодув" +#define sO_Empty "\xcf\xf3\xf1\xf2" // "Пуст" +#define sO_EmptyShe "\xcf\xf3\xf1\xf2\xe0\xff" // "Пустая" +#define sO_WayToPipe "\xcf\xf3\xf2\xfc \xea \xf2\xf0\xf3\xe1\xe5" // "Путь к трубе" +#define sO_Drinking "\xcf\xfc\xe5\xf2" // "Пьет" +#define sO_BrokenInPieces "\xd0\xe0\xe7\xe1\xe8\xf2\xe0" // "Разбита" +#define sO_Unblocked "\xd0\xe0\xe7\xe1\xeb\xee\xea\xe8\xf0\xee\xe2\xe0\xed" // "Разблокирован" +#define sO_Unfolded "\xd0\xe0\xe7\xe2\xe5\xf0\xed\xf3\xf2" // "Развернут" +#define sO_Jawcrucnher "\xd0\xee\xf2\xee\xf5\xf0\xf3\xf1" // "Ротохрус" +#define sO_UsherHand "\xd0\xf3\xea\xe0 \xc1\xe8\xeb\xe5\xf2\xe5\xf0\xf8\xe8" // "Рука Билетерши" +#define sO_LeverHandle_23 "\xd0\xf3\xea\xee\xff\xf2\xea\xe0 \xf0\xfb\xf7\xe0\xe3\xe0_23" // "Рукоятка рычага_23" +#define sO_ClockHandle "\xd0\xf3\xf7\xea\xe0 \xee\xf2 \xf7\xe0\xf1\xee\xe2" // "Ручка от часов" +#define sO_Lever_23 "\xd0\xfb\xf7\xe0\xe3_23" // "Рычаг_23" +#define sO_WithDudeOnLeft "\xd1 \xc4\xff\xe4\xe5\xe9 \xf1\xeb\xe5\xe2\xe0" // "С Дядей слева" +#define sO_WithDudeOnRight "\xd1 \xc4\xff\xe4\xe5\xe9 \xf1\xef\xf0\xe0\xe2\xe0" // "С Дядей справа" +#define sO_WithBoot "\xd1 \xe1\xe0\xf8\xec\xe0\xea\xee\xec" // "С башмаком" +#define sO_WithBig "\xd1 \xe1\xee\xeb\xfc\xf8\xe8\xec" // "С большим" +#define sO_WithPlunger "\xd1 \xe2\xe0\xed\xf2\xf3\xe7\xee\xec" // "С вантузом" +#define sO_WithJug "\xd1 \xe3\xee\xf0\xf8\xea\xee\xec" // "С горшком" +#define sO_WithGum "\xd1 \xe6\xe2\xe0\xf7\xea\xee\xe9" // "С жвачкой" +#define sO_WithShovel "\xd1 \xeb\xee\xef\xe0\xf2\xee\xe9" // "С лопатой" +#define sO_WithTiny "\xd1 \xec\xe0\xeb\xfb\xec" // "С малым" +#define sO_WithHammer "\xd1 \xec\xee\xeb\xee\xf2\xea\xee\xec" // "С молотком" +#define sO_WithCoin "\xd1 \xec\xee\xed\xe5\xf2\xee\xe9" // "С монетой" +#define sO_WithSock "\xd1 \xed\xee\xf1\xea\xee\xec" // "С носком" +#define sO_WithCork "\xd1 \xef\xf0\xee\xe1\xea\xee\xe9" // "С пробкой" +#define sO_WithSteering "\xd1 \xf0\xf3\xeb\xe5\xec" // "С рулем" +#define sO_WithHandle "\xd1 \xf0\xf3\xf7\xea\xee\xe9" // "С ручкой" +#define sO_WithApple "\xd1 \xff\xe1\xeb\xee\xea\xee\xec" // "С яблоком" +#define sO_WithDrawer "\xd1 \xff\xf9\xe8\xea\xee\xec" // "С ящиком" +#define sO_Sugar "\xd1\xe0\xf5\xe0\xf0\xee\xea" // "Сахарок" +#define sO_Convoluted "\xd1\xe2\xe5\xf0\xed\xf3\xf2" // "Свернут" +#define sO_IsFree "\xd1\xe2\xee\xe1\xee\xe4\xed\xe0" // "Свободна" +#define sO_Sitting "\xd1\xe8\xe4\xe8\xf2" // "Сидит" +#define sO_Laughing "\xd1\xec\xe5\xe5\xf2\xf1\xff" // "Смеется" +#define sO_WithEveryone "\xd1\xee \xe2\xf1\xe5\xec\xe8" // "Со всеми" +#define sO_WithMop "\xd1\xee \xf8\xe2\xe0\xe1\xf0\xee\xe9" // "Со шваброй" +#define sO_WithHose "\xd1\xee \xf8\xeb\xe0\xed\xe3\xee\xec" // "Со шлангом" +#define sO_WithBrush "\xd1\xee \xf9\xe5\xf2\xea\xee\xe9" // "Со щеткой" +#define sO_Sleeping "\xd1\xef\xe8\xf2" // "Спит" +#define sO_OnRight "\xd1\xef\xf0\xe0\xe2\xe0" // "Справа" +#define sO_StandsInBoots "\xd1\xf2\xee\xe8\xf2 \xe2 \xe1\xee\xf2\xe8\xed\xea\xe0\xf5" // "Стоит в ботинках" +#define sO_StandsInCorner "\xd1\xf2\xee\xe8\xf2 \xe2 \xf3\xe3\xeb\xf3" // "Стоит в углу" +#define sO_Guardian "\xd1\xf2\xee\xf0\xee\xe6" // "Сторож" +#define sO_Guard_1 "\xd1\xf2\xf0\xe0\xe6 1" // "Страж 1" +#define sO_Gurad_2 "\xd1\xf2\xf0\xe0\xe6 2" // "Страж 2" +#define sO_Guard_3 "\xd1\xf2\xf0\xe0\xe6 3" // "Страж 3" +#define sO_Stool_34 "\xd2\xe0\xe1\xf3\xf0\xe5\xf2_34" // "Табурет_34" +#define sO_Pipe_9 "\xd2\xf0\xf3\xe1\xe0_9" // "Труба_9" +#define sO_Pedestal_16 "\xd2\xf3\xec\xe1\xe0_16" // "Тумба_16" +#define sO_Pedestal_17 "\xd2\xf3\xec\xe1\xe0_17" // "Тумба_17" +#define sO_Pedestal_33 "\xd2\xf3\xec\xe1\xe0_33" // "Тумба_33" +#define sO_NearDudesStairs "\xd3 \xc4\xff\xe4\xe8 \xed\xe0 \xeb\xe5\xf1\xf2\xed\xe8\xf6\xe5" // "У Дяди на лестнице" +#define sO_NearDude "\xd3 \xc4\xff\xe4\xe8" // "У Дяди" +#define sO_NearPipeWithStool "\xd3 \xf2\xf0\xf3\xe1\xfb \xf1 \xf2\xe0\xe1\xf3\xf0\xe5\xf2\xea\xee\xe9" // "У трубы с табуреткой" +#define sO_NearPipe "\xd3 \xf2\xf0\xf3\xe1\xfb" // "У трубы" +#define sO_Janitors "\xd3\xe1\xee\xf0\xf9\xe8\xea\xe8" // "Уборщики" +#define sO_Janitress "\xd3\xe1\xee\xf0\xf9\xe8\xf6\xe0" // "Уборщица" +#define sO_Gone "\xd3\xe5\xf5\xe0\xeb\xe0" // "Уехала" +#define sO_FallenOnce "\xd3\xef\xe0\xeb \xf0\xe0\xe7" // "Упал раз" +#define sO_FallenBrush "\xd3\xef\xe0\xeb\xe0 \xf9\xe5\xf2\xea\xe0" // "Упала щетка" +#define sO_NotBroken "\xd6\xe5\xeb\xe0" // "Цела" +#define sO_ScratchingBelly "\xd7\xe5\xf8\xe5\xf2 \xef\xf3\xe7\xee" // "Чешет пузо" +#define sO_Level0 "\xdd\xf2\xe0\xe6 0" // "Этаж 0" +#define sO_Level1 "\xdd\xf2\xe0\xe6 1" // "Этаж 1" +#define sO_Level2 "\xdd\xf2\xe0\xe6 2" // "Этаж 2" +#define sO_Level3 "\xdd\xf2\xe0\xe6 3" // "Этаж 3" +#define sO_Level4 "\xdd\xf2\xe0\xe6 4" // "Этаж 4" +#define sO_Level5 "\xdd\xf2\xe0\xe6 5" // "Этаж 5" +#define sO_Level6 "\xdd\xf2\xe0\xe6 6" // "Этаж 6" +#define sO_Level7 "\xdd\xf2\xe0\xe6 7" // "Этаж 7" +#define sO_Level8 "\xdd\xf2\xe0\xe6 8" // "Этаж 8" +#define sO_Level9 "\xdd\xf2\xe0\xe6 9" // "Этаж 9" +#define sO_EggGulperGaveCoin "\xdf\xe9\xf6\xe5\xe3\xeb\xee\xf2 \xee\xf2\xe4\xe0\xeb \xec\xee\xed\xe5\xf2\xf3" // "Яйцеглот отдал монету" +#define sO_EggGulper "\xdf\xe9\xf6\xe5\xe3\xeb\xee\xf2" // "Яйцеглот" +#define sO_EggCracker "\xdf\xe9\xf6\xe5\xea\xee\xeb" // "Яйцекол" +#define sO_NotCarryingEgg "\xdf\xe9\xf6\xee \xed\xe5 \xed\xe5\xf1\xe5\xf2" // "Яйцо не несет" +#define sO_Egg1 "\xdf\xe9\xf6\xee\x31" // "Яйцо1" +#define sO_Egg2 "\xdf\xe9\xf6\xee\x32" // "Яйцо2" +#define sO_Egg3 "\xdf\xe9\xf6\xee\x33" // "Яйцо3" + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_OBJECTNAMES_H */ diff --git a/engines/fullpipe/objects.h b/engines/fullpipe/objects.h new file mode 100644 index 0000000000..55686acaec --- /dev/null +++ b/engines/fullpipe/objects.h @@ -0,0 +1,134 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_OBJECTS_H +#define FULLPIPE_OBJECTS_H + +#include "fullpipe/utils.h" + +namespace Fullpipe { + +class MessageQueue; +class SceneTagList; + +class GameProject : public CObject { + public: + int _field_4; + char *_headerFilename; + SceneTagList *_sceneTagList; + int _field_10; + + public: + GameProject(); + ~GameProject(); + virtual bool load(MfcArchive &file); +}; + +struct PicAniInfo { + int32 type; + int16 objectId; + int16 field_6; + int32 field_8; + int16 sceneId; + int16 field_E; + int32 ox; + int32 oy; + int32 priority; + int16 staticsId; + int16 movementId; + int16 dynamicPhaseIndex; + int16 flags; + int32 field_24; + int32 someDynamicPhaseIndex; + + bool load(MfcArchive &file); +}; + +class CMotionController; + +class Sc2 : public CObject { + public: + int16 _sceneId; + int16 _field_2; + Scene *_scene; + CMotionController *_motionController; + int32 *_data1; // FIXME, could be a struct + int _count1; + PicAniInfo **_defPicAniInfos; + int _defPicAniInfosCount; + PicAniInfo **_picAniInfos; + int _picAniInfosCount; + int _isLoaded; + EntranceInfo **_entranceData; + int _entranceDataCount; + + public: + Sc2(); + virtual bool load(MfcArchive &file); +}; + +typedef Common::Array<Sc2> Sc2Array; + +union VarValue { + float floatValue; + int32 intValue; + char *stringValue; +}; + +class CGameVar : public CObject { + public: + CGameVar *_nextVarObj; + CGameVar *_prevVarObj; + CGameVar *_parentVarObj; + CGameVar *_subVars; + CGameVar *_field_14; + char *_varName; + VarValue _value; + int _varType; + + public: + CGameVar(); + virtual bool load(MfcArchive &file); + CGameVar *getSubVarByName(const char *name); + bool setSubVarAsInt(const char *name, int value); + int getSubVarAsInt(const char *name); + CGameVar *addSubVarAsInt(const char *name, int value); + bool addSubVar(CGameVar *subvar); + int getSubVarsCount(); + CGameVar *getSubVarByIndex(int idx); +}; + +struct PreloadItem { + int preloadId1; + int preloadId2; + int sceneId; + int field_C; +}; + +class PreloadItems : public Common::Array<PreloadItem>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_OBJECTS_H */ diff --git a/engines/fullpipe/scene.cpp b/engines/fullpipe/scene.cpp new file mode 100644 index 0000000000..6ac062fb37 --- /dev/null +++ b/engines/fullpipe/scene.cpp @@ -0,0 +1,690 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" +#include "fullpipe/gameloader.h" + +#include "fullpipe/constants.h" + +#include "common/algorithm.h" + +namespace Fullpipe { + +Scene *FullpipeEngine::accessScene(int sceneId) { + SceneTag *t = 0; + + for (SceneTagList::iterator s = _gameProject->_sceneTagList->begin(); s != _gameProject->_sceneTagList->end(); ++s) { + if (s->_sceneId == sceneId) { + t = &(*s); + break; + } + } + + if (!t) + return 0; + + if (!t->_scene) { + t->loadScene(); + } + + return t->_scene; +} + +bool SceneTagList::load(MfcArchive &file) { + debug(5, "SceneTagList::load()"); + + int numEntries = file.readUint16LE(); + + for (int i = 0; i < numEntries; i++) { + SceneTag *t = new SceneTag(); + t->load(file); + push_back(*t); + } + + return true; +} + +SceneTag::SceneTag() { + _field_4 = 0; + _scene = 0; + _tag = 0; +} + +bool SceneTag::load(MfcArchive &file) { + debug(5, "SceneTag::load()"); + + _field_4 = 0; + _scene = 0; + + _sceneId = file.readUint16LE(); + + _tag = file.readPascalString(); + + debug(6, "sceneId: %d tag: %s", _sceneId, _tag); + + return true; +} + +SceneTag::~SceneTag() { + free(_tag); +} + +void SceneTag::loadScene() { + char *archname = genFileName(0, _sceneId, "nl"); + + Common::Archive *arch = makeNGIArchive(archname); + + char *fname = genFileName(0, _sceneId, "sc"); + + Common::SeekableReadStream *file = arch->createReadStreamForMember(fname); + + _scene = new Scene(); + + MfcArchive archive(file); + + _scene->load(archive); + + if (_scene->_shadows) + _scene->_shadows->init(); + + delete file; + + g_fullpipe->_currArchive = 0; + + free(fname); + free(archname); +} + +Scene::Scene() { + _sceneId = 0; + _field_BC = 0; + _shadows = 0; + _soundList = 0; + _libHandle = 0; + _sceneName = 0; +} + +bool Scene::load(MfcArchive &file) { + debug(5, "Scene::load()"); + + Background::load(file); + + _sceneId = file.readUint16LE(); + + _sceneName = file.readPascalString(); + debug(0, "scene: <%s> %d", transCyrillic((byte *)_sceneName), _sceneId); + + int count = file.readUint16LE(); + debug(7, "scene.ani: %d", count); + + for (int i = 0; i < count; i++) { + int aniNum = file.readUint16LE(); + char *aniname = genFileName(0, aniNum, "ani"); + + Common::SeekableReadStream *f = g_fullpipe->_currArchive->createReadStreamForMember(aniname); + + StaticANIObject *ani = new StaticANIObject(); + + MfcArchive archive(f); + + ani->load(archive); + ani->_sceneId = _sceneId; + + _staticANIObjectList1.push_back(ani); + + delete f; + free(aniname); + } + + count = file.readUint16LE(); + debug(7, "scene.mq: %d", count); + + for (int i = 0; i < count; i++) { + int qNum = file.readUint16LE(); + char *qname = genFileName(0, qNum, "qu"); + + Common::SeekableReadStream *f = g_fullpipe->_currArchive->createReadStreamForMember(qname); + MfcArchive archive(f); + + archive.readUint16LE(); // Skip 2 bytes + + MessageQueue *mq = new MessageQueue(); + + mq->load(archive); + + _messageQueueList.push_back(mq); + + delete f; + free(qname); + } + + count = file.readUint16LE(); + debug(7, "scene.fa: %d", count); + + for (int i = 0; i < count; i++) { + // There are no .FA files + assert(0); + } + + _libHandle = g_fullpipe->_currArchive; + + if (_picObjList.size() > 0 && _bgname && strlen(_bgname) > 1) { + char fname[260]; + + strcpy(fname, _bgname); + strcpy(strrchr(fname, '.') + 1, "col"); + + MemoryObject *col = new MemoryObject(); + col->loadFile(fname); + + _palette = col; + } + + char *shdname = genFileName(0, _sceneId, "shd"); + + Shadows *shd = new Shadows(); + + if (shd->loadFile(shdname)) + _shadows = shd; + + free(shdname); + + char *slsname = genFileName(0, _sceneId, "sls"); + + if (g_fullpipe->_soundEnabled) { + _soundList = new SoundList(); + + if (g_fullpipe->_flgSoundList) { + char *nlname = genFileName(17, _sceneId, "nl"); + + _soundList->loadFile(slsname, nlname); + + free(nlname); + } else { + _soundList->loadFile(slsname, 0); + } + } + + free(slsname); + + initStaticANIObjects(); + + if (file.size() - file.pos() > 0) + error("Scene::load (%d bytes left)", file.size() - file.pos()); + + return true; +} + +void Scene::initStaticANIObjects() { + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + ((StaticANIObject *)_staticANIObjectList1[i])->initMovements(); +} + +void Scene::init() { + _x = 0; + _y = 0; + + g_fullpipe->_sceneRect.moveTo(0, 0); + + for (uint i = 0; i < _picObjList.size(); i++) + ((PictureObject *)_picObjList[i])->clearFlags(); + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) + ((StaticANIObject *)_staticANIObjectList1[i])->clearFlags(); + + if (_staticANIObjectList2.size() != _staticANIObjectList1.size()) { + _staticANIObjectList2.clear(); + + for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) + _staticANIObjectList2.push_back(*s); + } +} + +StaticANIObject *Scene::getAniMan() { + StaticANIObject *aniMan = getStaticANIObject1ById(ANI_MAN, -1); + + deleteStaticANIObject(aniMan); + + return aniMan; +} + +StaticANIObject *Scene::getStaticANIObject1ById(int obj, int a3) { + for (CPtrList::iterator s = _staticANIObjectList1.begin(); s != _staticANIObjectList1.end(); ++s) { + StaticANIObject *o = (StaticANIObject *)*s; + if (o->_id == obj && (a3 == -1 || o->_okeyCode == a3)) + return o; + } + + return 0; +} + +StaticANIObject *Scene::getStaticANIObject1ByName(char *name, int a3) { + for (uint n = 0; n < _staticANIObjectList1.size(); n++) { + StaticANIObject *o = (StaticANIObject *)_staticANIObjectList1[n]; + if (!strcmp(o->_objectName, name) && (a3 == -1 || o->_okeyCode == a3)) + return o; + } + + return 0; +} + +void Scene::deleteStaticANIObject(StaticANIObject *obj) { + for (uint n = 0; n < _staticANIObjectList1.size(); n++) + if ((StaticANIObject *)_staticANIObjectList1[n] == obj) { + _staticANIObjectList1.remove_at(n); + break; + } + + for (uint n = 0; n < _staticANIObjectList2.size(); n++) + if ((StaticANIObject *)_staticANIObjectList2[n] == obj) { + _staticANIObjectList2.remove_at(n); + break; + } +} + +void Scene::addStaticANIObject(StaticANIObject *obj, bool addList2) { + if (obj->_okeyCode) + obj->renumPictures(&_staticANIObjectList1); + + _staticANIObjectList1.push_back(obj); + + if (addList2) { + if (!obj->_okeyCode) + obj->clearFlags(); + + _staticANIObjectList2.push_back(obj); + } +} + +void Scene::setPictureObjectsFlag4() { + for (uint i = 0; i < _picObjList.size(); i++) { + ((PictureObject *)_picObjList[i])->_flags |= 4; + } +} + +PictureObject *Scene::getPictureObjectById(int objId, int flags) { + for (uint i = 0; i < _picObjList.size(); i++) { + if (((PictureObject *)_picObjList[i])->_id == objId && ((PictureObject *)_picObjList[i])->_okeyCode == flags) + return (PictureObject *)_picObjList[i]; + } + + return 0; +} + +PictureObject *Scene::getPictureObjectByName(const char *objName, int flags) { + for (uint i = 0; i < _picObjList.size(); i++) { + if (!strcmp(((PictureObject *)_picObjList[i])->_objectName, objName) && (((PictureObject *)_picObjList[i])->_okeyCode == flags || flags == -1)) + return (PictureObject *)_picObjList[i]; + } + + return 0; +} + +void Scene::deletePictureObject(PictureObject *obj) { + for (uint i = 0; i < _picObjList.size(); i++) { + if (((PictureObject *)_picObjList[i]) == obj) { + _picObjList.remove_at(i); + delete obj; + + return; + } + } +} + +MessageQueue *Scene::getMessageQueueById(int messageId) { + for (uint i = 0; i < _messageQueueList.size(); i++) + if (((MessageQueue *)_messageQueueList[i])->_dataId == messageId) + return (MessageQueue *)_messageQueueList[i]; + + return 0; +} + +MessageQueue *Scene::getMessageQueueByName(char *name) { + for (uint i = 0; i < _messageQueueList.size(); i++) + if (!strcmp(((MessageQueue *)_messageQueueList[i])->_queueName, name)) + return (MessageQueue *)_messageQueueList[i]; + + return 0; +} + +void Scene::preloadMovements(CGameVar *var) { + CGameVar *preload = var->getSubVarByName("PRELOAD"); + if (!preload) + return; + + for (CGameVar *i = preload->_subVars; i; i = i->_nextVarObj) { + StaticANIObject *ani = getStaticANIObject1ByName(i->_varName, -1); + + if (ani) { + CGameVar *subVars = i->_subVars; + + if (subVars) { + for (;subVars; subVars = subVars->_nextVarObj) { + Movement *mov = ani->getMovementByName(subVars->_varName); + + if (mov) + mov->loadPixelData(); + } + } else { + ani->loadMovementsPixelData(); + } + } + } +} + +void Scene::initObjectCursors(const char *varname) { + CGameVar *cursorsVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(varname)->getSubVarByName("CURSORS"); + + if (!cursorsVar || !cursorsVar->_subVars) + return; + + int maxId = 0; + int minId = 0xffff; + + for (CGameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) { + GameObject *obj = getPictureObjectByName(sub->_varName, -1); + + if (obj || (obj = getStaticANIObject1ByName(sub->_varName, -1)) != 0) { + if (obj->_id < minId) + minId = obj->_id; + if (obj->_id > maxId) + maxId = obj->_id; + } + } + + g_fullpipe->_minCursorId = minId; + g_fullpipe->_maxCursorId = maxId; + + g_fullpipe->_objectIdCursors.resize(maxId - minId + 1); + + for (CGameVar *sub = cursorsVar->_subVars; sub; sub = sub->_nextVarObj) { + GameObject *obj = getPictureObjectByName(sub->_varName, -1); + + if (!obj) + obj = getStaticANIObject1ByName(sub->_varName, -1); + + PictureObject *pic = getGameLoaderInventory()->getScene()->getPictureObjectByName(sub->_value.stringValue, -1); + + if (obj && pic) + g_fullpipe->_objectIdCursors[obj->_id - minId] = pic->_id; + } +} + +bool Scene::compareObjPriority(const void *p1, const void *p2) { + if (((const StaticANIObject *)p1)->_priority > ((const StaticANIObject *)p2)->_priority) + return true; + + return false; +} + +void Scene::objectList_sortByPriority(CPtrList &list) { + Common::sort(list.begin(), list.end(), Scene::compareObjPriority); +} + +void Scene::draw() { + debug(0, ">>>>> Scene::draw()"); + updateScrolling(); + + drawContent(60000, 0, true); + + objectList_sortByPriority(_staticANIObjectList2); + + for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) { + ((StaticANIObject *)*s)->draw2(); + } + + int priority = -1; + for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) { + drawContent(((StaticANIObject *)*s)->_priority, priority, false); + ((StaticANIObject *)*s)->draw(); + + priority = ((StaticANIObject *)*s)->_priority; + } + + drawContent(-1, priority, false); +} + +void Scene::updateScrolling() { + debug(0, "STUB Scene::updateScrolling()"); +} + +void Scene::updateScrolling2() { + warning("STUB Scene::updateScrolling2()"); +} + +StaticANIObject *Scene::getStaticANIObjectAtPos(int x, int y) { + StaticANIObject *res = 0; + + for (uint i = 0; i < _staticANIObjectList1.size(); i++) { + StaticANIObject *p = (StaticANIObject *)_staticANIObjectList1[i]; + int pixel; + + if ((p->_field_8 & 0x100) && (p->_flags & 4) && + p->getPixelAtPos(x, y, &pixel) && + (!res || res->_priority >= p->_priority)) + res = p; + } + + return res; +} + +PictureObject *Scene::getPictureObjectAtPos(int x, int y) { + PictureObject *res = 0; + + for (uint i = 0; i < _picObjList.size(); i++) { + PictureObject *p = (PictureObject *)_picObjList[i]; + if ((p->_field_8 & 0x100) && (p->_flags & 4) && + p->isPixelHitAtPos(x, y) && + (!res || res->_priority >= p->_priority)) + res = p; + } + + return res; +} + +int Scene::getPictureObjectIdAtPos(int x, int y) { + PictureObject *resp = 0; + int res = 0; + + for (uint i = 0; i < _picObjList.size(); i++) { + PictureObject *p = (PictureObject *)_picObjList[i]; + if ((p->_field_8 & 0x100) && (p->_flags & 4) && + p->isPixelHitAtPos(x, y) && + (!res || resp->_priority >= p->_priority)) { + resp = p; + res = p->_id; + } + } + + return res; +} + +void Scene::update(int counterdiff) { + debug(0, "Scene::update(%d)", counterdiff); + + for (CPtrList::iterator s = _staticANIObjectList2.begin(); s != _staticANIObjectList2.end(); ++s) + ((StaticANIObject *)*s)->update(counterdiff); +} + +void Scene::drawContent(int minPri, int maxPri, bool drawBg) { + if (!_picObjList.size() && !_bigPictureArray1Count) + return; + + if (_palette) { + g_fullpipe->_globalPalette = _palette->_data; + } + + debug(8, "Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + + if (_picObjList.size() > 2) { // We need to z-sort them + objectList_sortByPriority(_picObjList); + } + + if (minPri == -1 && _picObjList.size()) + minPri = ((PictureObject *)_picObjList.back())->_priority - 1; + + if (maxPri == -1) + maxPri = 60000; + + debug(8, "-> Scene::drawContent(>%d, <%d, %d)", minPri, maxPri, drawBg); + + Common::Point point; + + debug(8, "_bigPict: %d objlist: %d", _bigPictureArray1Count, _picObjList.size()); + if (drawBg && _bigPictureArray1Count && _picObjList.size()) { + + _bigPictureArray[0][0]->getDimensions(&point); + + int width = point.x; + int height = point.y; + + debug(8, "w: %d h:%d", width, height); + + ((PictureObject *)_picObjList[0])->getDimensions(&point); + + debug(8, "w2: %d h2:%d", point.x, point.y); + + int bgStX = g_fullpipe->_sceneRect.left % point.x; + + if (bgStX < 0) + bgStX += point.x; + + int bgNumX = bgStX / width; + int bgOffsetX = bgStX % width; + + int bgStY = g_fullpipe->_sceneRect.top % point.y; + + if (bgStY < 0) + bgStY += point.y; + + int bgNumY = bgStY / height; + int bgOffsetY = bgStY % height; + + int bgPosX = g_fullpipe->_sceneRect.left - bgOffsetX; + + if (bgPosX < g_fullpipe->_sceneRect.right - 1) { + while (1) { + int v25 = bgNumY; + for (int y = g_fullpipe->_sceneRect.top - bgOffsetY; y < g_fullpipe->_sceneRect.bottom - 1;) { + BigPicture *v27 = _bigPictureArray[bgNumX][v25]; + v27->draw(bgPosX, y, 0, 0); + y += v27->getDimensions(&point)->y; + v25++; + + if (v25 >= _bigPictureArray2Count) { + if (!(((PictureObject *)_picObjList[0])->_flags & 0x20)) + break; + v25 = 0; + } + } + _bigPictureArray[bgNumX][0]->getDimensions(&point); + int v32 = point.x + bgPosX; + bgPosX += point.x; + bgNumX++; + + if (bgNumX >= _bigPictureArray1Count) { + if (!(((PictureObject *)_picObjList[0])->_flags & 0x2)) + break; + bgNumX = 0; + } + if (v32 >= g_fullpipe->_sceneRect.right - 1) + break; + } + } + } + + + for (uint i = 1; i < _picObjList.size(); i++) { + PictureObject *obj = (PictureObject *)_picObjList[i]; + + debug(8, "pri: %d", obj->_priority); + if (obj->_priority < minPri || obj->_priority >= maxPri) + continue; + + int objX = obj->_ox; + int objY = obj->_oy; + + debug(8, "obj: %d %d", objX, objY); + + obj->getDimensions(&point); + + int width = point.x; + int height = point.y; + + if (obj->_flags & 8) { + while (objX > g_fullpipe->_sceneRect.right) { + objX -= width; + obj->setOXY(objX, objY); + } + for (int j = width + objX; width + objX < g_fullpipe->_sceneRect.left; j = width + objX) { + objX = j; + obj->setOXY(j, objY); + } + } + + if (obj->_flags & 0x10) { + while (objY > g_fullpipe->_sceneRect.bottom) { + objY -= height; + obj->setOXY(objX, objY); + } + for (int j = objY + height; objY + height < g_fullpipe->_sceneRect.top; j = objY + height) { + objY = j; + obj->setOXY(objX, j); + } + } + if (obj->_flags & 4) + obj->draw(); + + if (obj->_flags & 2) { + if (objX > g_fullpipe->_sceneRect.left) { + obj->setOXY(objX - width, objY); + obj->draw(); + obj->setOXY(objX, objY); + } + if (width + objX < g_fullpipe->_sceneRect.right) { + obj->setOXY(width + objX, objY); + obj->draw(); + obj->setOXY(objX, objY); + } + } + + if (obj->_flags & 0x20) { + if (objY > g_fullpipe->_sceneRect.top) { + obj->setOXY(objX, objY - height); + obj->draw(); + obj->setOXY(objX, objY); + } + if (height + objY < g_fullpipe->_sceneRect.bottom) { + obj->setOXY(objX, height + objY); + obj->draw(); + obj->setOXY(objX, objY); + } + } + } +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scene.h b/engines/fullpipe/scene.h new file mode 100644 index 0000000000..c1c8d47ba8 --- /dev/null +++ b/engines/fullpipe/scene.h @@ -0,0 +1,108 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_SCENE_H +#define FULLPIPE_SCENE_H + +#include "fullpipe/gfx.h" + +namespace Fullpipe { + +class MessageQueue; + +class Scene : public Background { + public: + CPtrList _staticANIObjectList1; + CPtrList _staticANIObjectList2; + CPtrList _messageQueueList; + CPtrList _faObjectList; + Shadows *_shadows; + SoundList *_soundList; + int16 _sceneId; + char *_sceneName; + int _field_BC; + NGIArchive *_libHandle; + + public: + Scene(); + + virtual bool load(MfcArchive &file); + + void initStaticANIObjects(); + void init(); + void draw(); + void drawContent(int minPri, int maxPri, bool drawBG); + void updateScrolling(); + void updateScrolling2(); + + void update(int counterdiff); + + StaticANIObject *getAniMan(); + StaticANIObject *getStaticANIObject1ById(int obj, int a3); + StaticANIObject *getStaticANIObject1ByName(char *name, int a3); + MessageQueue *getMessageQueueById(int messageId); + MessageQueue *getMessageQueueByName(char *name); + + void deleteStaticANIObject(StaticANIObject *obj); + void addStaticANIObject(StaticANIObject *obj, bool addList2); + + void setPictureObjectsFlag4(); + PictureObject *getPictureObjectById(int objId, int flags); + PictureObject *getPictureObjectByName(const char *name, int keyCode); + void deletePictureObject(PictureObject *obj); + void preloadMovements(CGameVar *var); + + StaticANIObject *getStaticANIObjectAtPos(int x, int y); + PictureObject *getPictureObjectAtPos(int x, int y); + int getPictureObjectIdAtPos(int x, int y); + + void initObjectCursors(const char *name); + + private: + static bool compareObjPriority(const void *p1, const void *p2); + void objectList_sortByPriority(CPtrList &list); +}; + +class SceneTag : public CObject { + public: + int _field_4; + char *_tag; + Scene *_scene; + int16 _sceneId; + int16 _field_12; + + public: + SceneTag(); + ~SceneTag(); + + virtual bool load(MfcArchive &file); + void loadScene(); +}; + +class SceneTagList : public Common::List<SceneTag>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SCENE_H */ diff --git a/engines/fullpipe/scenes.cpp b/engines/fullpipe/scenes.cpp new file mode 100644 index 0000000000..37be7facc9 --- /dev/null +++ b/engines/fullpipe/scenes.cpp @@ -0,0 +1,1508 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/utils.h" +#include "fullpipe/gfx.h" +#include "fullpipe/objects.h" +#include "fullpipe/statics.h" +#include "fullpipe/scene.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/sound.h" +#include "fullpipe/motion.h" +#include "fullpipe/input.h" +#include "fullpipe/messages.h" +#include "fullpipe/behavior.h" + +#include "fullpipe/constants.h" +#include "fullpipe/objectnames.h" +#include "fullpipe/scenes.h" +#include "fullpipe/modal.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +int defaultUpdateCursor(); +void setElevatorButton(const char *name, int state); + +int sceneIntro_updateCursor(); +void sceneIntro_initScene(Scene *sc); +int sceneHandlerIntro(ExCommand *cmd); + +void scene01_fixEntrance(); +void scene01_initScene(Scene *sc, int entrance); +int sceneHandler01(ExCommand *cmd); + +void sceneDbgMenu_initScene(Scene *sc); +int sceneHandlerDbgMenu(ExCommand *cmd); + +Vars::Vars() { + sceneIntro_aniin1man = 0; + sceneIntro_needSleep = true; + sceneIntro_needGetup = false; + sceneIntro_skipIntro = true; + sceneIntro_playing = false; + sceneIntro_needBlackout = false; + + swallowedEgg1 = 0; + swallowedEgg2 = 0; + swallowedEgg3 = 0; + + scene01_picSc01Osk = 0; + scene01_picSc01Osk2 = 0; +} + +bool FullpipeEngine::sceneSwitcher(EntranceInfo *entrance) { + CGameVar *sceneVar; + Common::Point sceneDim; + + Scene *scene = accessScene(entrance->_sceneId); + + if (!scene) + return 0; + + ((PictureObject *)scene->_picObjList.front())->getDimensions(&sceneDim); + _sceneWidth = sceneDim.x; + _sceneHeight = sceneDim.y; + + _sceneRect.top = 0; + _sceneRect.left = 0; + _sceneRect.right = 799; + _sceneRect.bottom = 599; + + scene->_x = 0; + scene->_y = 0; + + _aniMan->setOXY(0, 0); + _aniMan->clearFlags(); + _aniMan->_callback1 = 0; + _aniMan->_callback2 = 0; + _aniMan->_shadowsOn = 1; + + _scrollSpeed = 8; + + _isSaveAllowed = true; + _updateFlag = true; + _flgCanOpenMap = true; + + if (entrance->_sceneId == SC_DBGMENU) { + _inventoryScene = 0; + } else { + _gameLoader->loadScene(SC_INV); + getGameLoaderInventory()->rebuildItemRects(); + _inventoryScene = getGameLoaderInventory()->getScene(); + } + if (_soundEnabled) { + if (scene->_soundList) { + _currSoundListCount = 2; + _currSoundList1[0] = accessScene(SC_COMMON)->_soundList; + _currSoundList1[1] = scene->_soundList; + + for (int i = 0; i < scene->_soundList->getCount(); i++) { + scene->_soundList->getSoundByIndex(i)->updateVolume(); + } + } else { + _currSoundListCount = 1; + _currSoundList1[0] = accessScene(SC_COMMON)->_soundList; + } + } + + getGameLoaderInteractionController()->sortInteractions(scene->_sceneId); + _currentScene = scene; + scene->addStaticANIObject(_aniMan, 1); + _scene2 = scene; + _aniMan->_movement = 0; + _aniMan->_statics = _aniMan->getStaticsById(ST_MAN_EMPTY); + _aniMan->setOXY(0, 0); + + if (_aniMan) { + _aniMan2 = _aniMan; + CMctlCompound *cmp = getSc2MctlCompoundBySceneId(entrance->_sceneId); + cmp->initMovGraph2(); + cmp->addObject(_aniMan); + cmp->setEnabled(); + getGameLoaderInteractionController()->enableFlag24(); + setInputDisabled(0); + } else { + _aniMan2 = 0; + } + + scene->setPictureObjectsFlag4(); + + for (CPtrList::iterator s = scene->_staticANIObjectList1.begin(); s != scene->_staticANIObjectList1.end(); ++s) { + StaticANIObject *o = (StaticANIObject *)*s; + o->setFlags(o->_flags & 0xFE7F); + } + + PictureObject *p = accessScene(SC_INV)->getPictureObjectById(PIC_INV_MENU, 0); + p->setFlags(p->_flags & 0xFFFB); + + removeMessageHandler(2, -1); + _updateScreenCallback = 0; + + switch (entrance->_sceneId) { + case SC_INTRO1: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_INTRO1"); + scene->preloadMovements(sceneVar); + sceneIntro_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_INTRO1"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandlerIntro, 2); + _updateCursorCallback = sceneIntro_updateCursor; + break; + + case SC_1: + scene01_fixEntrance(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_1"); + scene->preloadMovements(sceneVar); + scene01_initScene(scene, entrance->_field_4); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_1"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler01, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + +#if 0 + case SC_2: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_2"); + scene->preloadMovements(sceneVar); + scene02_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_2"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler02, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_3: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_3"); + scene->preloadMovements(sceneVar); + scene03_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_3"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler03, 2); + j_Scene_sc03_sub_40F160(scene); + _updateCursorCallback = scene03_updateCursor; + break; + + case SC_4: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_4"); + scene->preloadMovements(sceneVar); + scene04_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_4"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler04, 2, 2); + _updateCursorCallback = scene04_updateCursor; + break; + + case SC_5: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_5"); + scene->preloadMovements(sceneVar); + scene05_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_5"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler05, 2, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_6: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_6"); + scene->preloadMovements(sceneVar); + scene06_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_6"); + setSceneMusicParameters(sceneVar); + sub_415300(); + insertMessageHandler(sceneHandler06, 2, 2); + _updateCursorCallback = scene06_updateCursor; + break; + + case SC_7: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_7"); + scene->preloadMovements(sceneVar); + scene07_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_7"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler07, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_8: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_8"); + scene->preloadMovements(sceneVar); + scene08_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_8"); + setSceneMusicParameters(sceneVar); + sub_416890(); + addMessageHandler(sceneHandler08, 2); + _updateCursorCallback = scene08_updateCursor; + break; + + case SC_9: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_9"); + scene->preloadMovements(sceneVar); + scene09_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_9"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler09, 2, 2); + _updateCursorCallback = scene09_updateCursor; + break; + + case SC_10: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_10"); + scene->preloadMovements(sceneVar); + scene10_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_10"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler10, 2, 2); + _updateCursorCallback = scene10_updateCursor; + break; + + case SC_11: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_11"); + scene->preloadMovements(sceneVar); + scene11_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_11"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler11, 2, 2); + scene11_sub_41A980(); + _updateCursorCallback = scene11_updateCursor; + break; + + case SC_12: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_12"); + scene->preloadMovements(sceneVar); + scene12_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_12"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler12, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_13: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_13"); + scene->preloadMovements(sceneVar); + scene13_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_13"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler13, 2, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_14: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_14"); + scene->preloadMovements(sceneVar); + scene14_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_14"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler14, 2, 2); + scene14_sub_41D2B0(); + _updateCursorCallback = scene14_updateCursor; + break; + + case SC_15: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_15"); + scene->preloadMovements(sceneVar); + scene15_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_15"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler15, 2, 2); + _updateCursorCallback = scene15_updateCursor; + break; + + case SC_16: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_16"); + scene->preloadMovements(sceneVar); + scene16_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_16"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler16, 2); + _updateCursorCallback = scene16_updateCursor; + break; + + case SC_17: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_17"); + scene->preloadMovements(sceneVar); + scene17_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_17"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler17, 2); + scene17_sub_41F060(); + _updateCursorCallback = scene17_updateCursor; + break; + + case SC_18: + sub_40E1B0(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_18"); + scene->preloadMovements(sceneVar); + sub_4062D0(); + if (dword_476C38) + scene18_initScene1(scene); + else + scene18_initScene2(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_18"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler18, 2, 2); + _updateCursorCallback = scene18_updateCursor; + break; + + case SC_19: + if (!g_scene3) { + g_scene3 = accessScene(SC_18); + getGameLoader()->loadScene(SC_18); + scene18_initScene2(g_scene3); + sub_40C5F0(); + scene19_sub_420B10(g_scene3, entrance->field_4); + dword_476C38 = 1; + } + sub_40C650(); + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_19"); + scene->preloadMovements(sceneVar); + sub_4062D0(); + if (dword_476C38) + scene18_initScene1(scene); + else + scene19_initScene2(); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_19"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler19, 2); + scene19_sub_4211D0(scene); + _updateCursorCallback = scene19_updateCursor; + break; + + case SC_20: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_20"); + scene->preloadMovements(sceneVar); + scene20_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_20"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler20, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_21: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_21"); + scene->preloadMovements(sceneVar); + scene21_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_21"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler21, 2, 2); + _updateCursorCallback = scene21_updateCursor; + break; + + case SC_22: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_22"); + scene->preloadMovements(sceneVar); + scene22_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_22"); + setSceneMusicParameters(sceneVar); + scene22_sub_4228A0(); + insertMessageHandler(sceneHandler22, 2, 2); + _updateCursorCallback = scene22_updateCursor; + break; + + case SC_23: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_23"); + scene->preloadMovements(sceneVar); + scene23_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_23"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler23, 2, 2); + scene23_sub_423B00(); + _updateCursorCallback = scene23_updateCursor; + break; + + case SC_24: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_24"); + scene->preloadMovements(sceneVar); + scene24_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_24"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler24, 2); + scene24_sub_423DD0(); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_25: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_25"); + scene->preloadMovements(sceneVar); + scene25_initScene(scene, entrance->field_4); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_25"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler25, 2); + scene25_sub_4253B0(scene, entrance->field_4); + _updateCursorCallback = scene25_updateCursor; + break; + + case SC_26: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_26"); + scene->preloadMovements(sceneVar); + scene26_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_26"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler26, 2, 2); + scene26_sub_426140(scene); + _updateCursorCallback = scene26_updateCursor; + break; + + case SC_27: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_27"); + scene->preloadMovements(sceneVar); + scene27_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_27"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler27, 2); + _updateCursorCallback = scene27_updateCursor; + break; + + case SC_28: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_28"); + scene->preloadMovements(sceneVar); + scene28_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_28"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler28, 2, 2); + _updateCursorCallback = scene28_updateCursor; + break; + + case SC_29: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_29"); + scene->preloadMovements(sceneVar); + scene29_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_29"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler29, 2); + _updateCursorCallback = scene29_updateCursor; + break; + + case SC_30: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_30"); + scene->preloadMovements(sceneVar); + scene30_initScene(scene, entrance->field_4); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_30"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler30, 2); + _updateCursorCallback = scene30_updateCursor; + break; + + case SC_31: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_31"); + scene->preloadMovements(sceneVar); + scene31_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_31"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler31, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_32: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_32"); + scene->preloadMovements(sceneVar); + scene32_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_32"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler32, 2, 2); + scene32_sub_42C5C0(); + _updateCursorCallback = scene32_updateCursor; + break; + + case SC_33: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_33"); + scene->preloadMovements(sceneVar); + scene33_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_33"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler33, 2, 2); + scene33_sub_42CEF0(); + _updateCursorCallback = scene33_updateCursor; + break; + + case SC_34: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_34"); + scene->preloadMovements(sceneVar); + scene34_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_34"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler34, 2, 2); + scene34_sub_42DEE0(); + _updateCursorCallback = scene34_updateCursor; + break; + + case SC_35: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_35"); + scene->preloadMovements(sceneVar); + scene35_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_35"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler35, 2, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_36: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_36"); + scene->preloadMovements(sceneVar); + scene36_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_36"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler36, 2); + _updateCursorCallback = scene36_updateCursor; + break; + + case SC_37: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_37"); + scene->preloadMovements(sceneVar); + scene37_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_37"); + setSceneMusicParameters(sceneVar); + insertMessageHandler(sceneHandler37, 2, 2); + _updateCursorCallback = scene37_updateCursor; + break; + + case SC_38: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_38"); + scene->preloadMovements(sceneVar); + scene38_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_38"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandler38, 2); + _updateCursorCallback = defaultUpdateCursor; + break; + + case SC_FINAL1: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_FINAL1"); + scene->preloadMovements(sceneVar); + sceneFinal1_initScene(); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_FINAL1"); + setSceneMusicParameters(sceneVar); + addMessageHandler(sceneHandlerFinal1, 2); + _updateCursorCallback = sceneFinal1_updateCursor; + break; +#endif + + case SC_DBGMENU: + sceneVar = _gameLoader->_gameVar->getSubVarByName("SC_DBGMENU"); + scene->preloadMovements(sceneVar); + sceneDbgMenu_initScene(scene); + _behaviorManager->initBehavior(scene, sceneVar); + scene->initObjectCursors("SC_DBGMENU"); + addMessageHandler(sceneHandlerDbgMenu, 2); + break; + + default: + _behaviorManager->initBehavior(0, 0); + break; + } + + return true; +} + +void setElevatorButton(const char *name, int state) { + CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName(sO_LiftButtons); + + if (var) + var->setSubVarAsInt(name, state); +} + +void global_messageHandler_KickStucco() { + warning("STUB: global_messageHandler_KickStucco()"); +} + +void global_messageHandler_KickMetal() { + warning("STUB: global_messageHandler_KickMetal()"); +} + +int global_messageHandler1(ExCommand *cmd) { + debug(0, "global_messageHandler1: %d %d", cmd->_messageKind, cmd->_messageNum); + + if (cmd->_excFlags & 0x10000) { + if (cmd->_messageNum == MV_MAN_TOLADDER) + cmd->_messageNum = MV_MAN_TOLADDER2; + if (cmd->_messageNum == MV_MAN_STARTLADDER) + cmd->_messageNum = MV_MAN_STARTLADDER2; + if (cmd->_messageNum == MV_MAN_GOLADDER) + cmd->_messageNum = MV_MAN_GOLADDER2; + if (cmd->_messageNum == MV_MAN_STOPLADDER) + cmd->_messageNum = MV_MAN_STOPLADDER2; + } + + if (g_fullpipe->_inputDisabled) { + if (cmd->_messageKind == 17) { + switch (cmd->_messageNum) { + case 29: + case 30: + case 36: + case 106: + cmd->_messageKind = 0; + break; + default: + break; + } + } + } else if (cmd->_messageKind == 17) { + switch (cmd->_messageNum) { + case MSG_MANSHADOWSON: + g_fullpipe->_aniMan->_shadowsOn = 1; + break; + case MSG_HMRKICK_STUCCO: + global_messageHandler_KickStucco(); + break; + case MSG_MANSHADOWSOFF: + g_fullpipe->_aniMan->_shadowsOn = 0; + break; + case MSG_DISABLESAVES: + g_fullpipe->disableSaves(cmd); + break; + case MSG_ENABLESAVES: + g_fullpipe->enableSaves(); + break; + case MSG_HMRKICK_METAL: + global_messageHandler_KickMetal(); + break; + case 29: // left mouse + if (g_fullpipe->_inventoryScene) { + if (getGameLoaderInventory()->handleLeftClick(cmd)) + cmd->_messageKind = 0; + } + break; + case 107: // right mouse + if (getGameLoaderInventory()->getSelectedItemId()) { + getGameLoaderInventory()->unselectItem(0); + cmd->_messageKind = 0; + } + break; + case 36: // keydown + switch (cmd->_keyCode) { + case '\x1B': // ESC + if (g_fullpipe->_currentScene) { + getGameLoaderInventory()->unselectItem(0); + g_fullpipe->openMainMenu(); + cmd->_messageKind = 0; + } + break; + case 't': + g_fullpipe->stopAllSounds(); + cmd->_messageKind = 0; + break; + case 'u': + g_fullpipe->toggleMute(); + cmd->_messageKind = 0; + break; + case ' ': + if (getGameLoaderInventory()->getIsLocked()) { + if (getGameLoaderInventory()->getIsInventoryOut()) { + getGameLoaderInventory()->setIsLocked(0); + } + } else { + getGameLoaderInventory()->slideOut(); + getGameLoaderInventory()->setIsLocked(1); + } + break; + case '\t': + if (g_fullpipe->_flgCanOpenMap) + g_fullpipe->openMap(); + cmd->_messageKind = 0; + break; + case 'p': + if (g_fullpipe->_flgCanOpenMap) + g_fullpipe->openHelp(); + cmd->_messageKind = 0; + break; + default: + g_fullpipe->defHandleKeyDown(cmd->_keyCode); + break; + } + break; + case 33: + if (!g_fullpipe->_inventoryScene) + break; + + int invItem; + + if (g_fullpipe->_updateFlag && (invItem = g_fullpipe->_inventory->getHoveredItem(&g_fullpipe->_mouseScreenPos))) { + g_fullpipe->_cursorId = PIC_CSR_ITN; + if (!g_fullpipe->_currSelectedInventoryItemId && !g_fullpipe->_aniMan->_movement && + !(g_fullpipe->_aniMan->_flags & 0x100) && g_fullpipe->_aniMan->isIdle()) { + int st = g_fullpipe->_aniMan->_statics->_staticsId; + ExCommand *newex = 0; + + if (st == ST_MAN_RIGHT) { + newex = new ExCommand(g_fullpipe->_aniMan->_id, 1, rMV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); + } else if (st == (0x4000 | ST_MAN_RIGHT)) { + newex = new ExCommand(g_fullpipe->_aniMan->_id, 1, MV_MAN_LOOKUP, 0, 0, 0, 1, 0, 0, 0); + } + + if (newex) { + newex->_keyCode = g_fullpipe->_aniMan->_okeyCode; + newex->_excFlags |= 3; + newex->postMessage(); + } + } + + if (g_fullpipe->_currSelectedInventoryItemId != invItem) + g_fullpipe->playSound(SND_CMN_070, 0); + + g_fullpipe->_currSelectedInventoryItemId = invItem; + g_fullpipe->setCursor(g_fullpipe->_cursorId); + break; + } + if (g_fullpipe->_updateCursorCallback) + g_fullpipe->_updateCursorCallback(); + + g_fullpipe->_currSelectedInventoryItemId = 0; + g_fullpipe->setCursor(g_fullpipe->_cursorId); + break; + case 65: // open map + if (cmd->_field_2C == 11 && cmd->_field_14 == ANI_INV_MAP && g_fullpipe->_flgCanOpenMap) + g_fullpipe->openMap(); + break; + default: + break; + } + } + + if (cmd->_messageKind == 56) { + getGameLoaderInventory()->rebuildItemRects(); + + ExCommand *newex = new ExCommand(0, 35, SND_CMN_031, 0, 0, 0, 1, 0, 0, 0); + + newex->_field_14 = 1; + newex->_excFlags |= 3; + newex->postMessage(); + + return 1; + } else if (cmd->_messageKind == 57) { + getGameLoaderInventory()->rebuildItemRects(); + + return 1; + } + + return 0; +} + +void staticANIObjectCallback(int *arg) { + (*arg)--; +} + +int global_messageHandler2(ExCommand *cmd) { + if (cmd->_messageKind != 17) + return 0; + + int res = 0; + StaticANIObject *ani; + + switch (cmd->_messageNum) { + case 0x44c8: + error("0x44c8"); + // Unk3_sub_4477A0(&unk3, _parentId, _field_14 != 0); + break; + + case 28: + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) + ani->_priority = cmd->_field_14; + break; + + case 25: + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) { + if (cmd->_field_14) { + ani->setFlags40(true); + ani->_callback2 = staticANIObjectCallback; + } else { + ani->setFlags40(false); + ani->_callback2 = 0; + } + } + break; + + case 26: + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) { + Movement *mov = ani->_movement; + if (mov) + mov->_currDynamicPhase->_field_68 = 0; + } + break; + + default: +#if 0 + // We never put anything into _defMsgArray + while (::iterator it = g_fullpipe->_defMsgArray.begin(); it != g_fullpipe->_defMsgArray.end(); ++it) + if (((ExCommand *)*it)->_field_24 == _messageNum) { + ((ExCommand *)*it)->firef34(v13); + res = 1; + } +#endif + + //debug_msg(_messageNum); + + if (!g_fullpipe->_soundEnabled || cmd->_messageNum != 33 || g_fullpipe->_currSoundListCount <= 0) + return res; + + for (int snd = 0; snd < g_fullpipe->_currSoundListCount; snd++) { + SoundList *s = g_fullpipe->_currSoundList1[snd]; + int ms = s->getCount(); + for (int i = 0; i < ms; i++) { + s->getSoundByIndex(i)->setPanAndVolumeByStaticAni(); + } + } + } + + return res; +} + +int global_messageHandler3(ExCommand *cmd) { + int result = 0; + + if (cmd->_messageKind == 17) { + switch (cmd->_messageNum) { + case 29: + case 30: + case 31: + case 32: + case 36: + if (g_fullpipe->_inputDisabled) + cmd->_messageKind = 0; + break; + default: + break; + } + } + + StaticANIObject *ani, *ani2; + + switch (cmd->_messageKind) { + case 17: + switch (cmd->_messageNum) { + case 61: + return g_fullpipe->_gameLoader->preloadScene(cmd->_parentId, cmd->_keyCode); + case 62: + return g_fullpipe->_gameLoader->gotoScene(cmd->_parentId, cmd->_keyCode); + case 64: + if (g_fullpipe->_currentScene && g_fullpipe->_msgObjectId2 + && (!(cmd->_keyCode & 4) || g_fullpipe->_msgObjectId2 != cmd->_field_14 || g_fullpipe->_msgId != cmd->_field_20)) { + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_msgObjectId2, g_fullpipe->_msgId); + if (ani) { + ani->_flags &= 0xFF7F; + ani->_flags &= 0xFEFF; + ani->deleteFromGlobalMessageQueue(); + } + } + g_fullpipe->_msgX = 0; + g_fullpipe->_msgY = 0; + g_fullpipe->_msgObjectId2 = 0; + g_fullpipe->_msgId = 0; + if ((cmd->_keyCode & 1) || (cmd->_keyCode & 2)) { + g_fullpipe->_msgX = cmd->_x; + g_fullpipe->_msgY = cmd->_y; + } + if (cmd->_keyCode & 4) { + g_fullpipe->_msgObjectId2 = cmd->_field_14; + g_fullpipe->_msgId = cmd->_field_20; + } + return result; + case 29: + if (!g_fullpipe->_currentScene) + return result; + + if (g_fullpipe->_gameLoader->_interactionController->_flag24) { + ani = g_fullpipe->_currentScene->getStaticANIObjectAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + ani2 = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); + if (ani) { + if (g_fullpipe->_msgObjectId2 == ani->_id && g_fullpipe->_msgId == ani->_okeyCode) { + cmd->_messageKind = 0; + return result; + } + if (canInteractAny(ani2, ani, cmd->_keyCode)) { + handleObjectInteraction(ani2, ani, cmd->_keyCode); + return 1; + } + } else { + int id = g_fullpipe->_currentScene->getPictureObjectIdAtPos(cmd->_sceneClickX, cmd->_sceneClickY); + PictureObject *pic = g_fullpipe->_currentScene->getPictureObjectById(id, 0); + if (pic) { + if (g_fullpipe->_msgObjectId2 == pic->_id && g_fullpipe->_msgId == pic->_okeyCode) { + cmd->_messageKind = 0; + return result; + } + if (!ani2 || canInteractAny(ani2, pic, cmd->_keyCode)) { + if (!ani2 || (ani2->isIdle() && !(ani2->_flags & 0x80) && !(ani2->_flags & 0x100))) + handleObjectInteraction(ani2, pic, cmd->_keyCode); + return 1; + } + } + } + } + if (getSc2MctlCompoundBySceneId(g_fullpipe->_currentScene->_sceneId)->_isEnabled && cmd->_keyCode <= 0) { + if (g_fullpipe->_msgX != cmd->_sceneClickX || g_fullpipe->_msgY != cmd->_sceneClickY) { + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); + if (!ani || (ani->isIdle() && !(ani->_flags & 0x80) && !(ani->_flags & 0x100))) { + result = startWalkTo(g_fullpipe->_gameLoader->_field_FA, -1, cmd->_sceneClickX, cmd->_sceneClickY, 0); + if (result) { + ExCommand *ex = new ExCommand(g_fullpipe->_gameLoader->_field_FA, 17, 64, 0, 0, 0, 1, 0, 0, 0); + + ex->_keyCode = 1; + ex->_excFlags |= 3; + ex->_x = cmd->_sceneClickX; + ex->_y = cmd->_sceneClickY; + ex->postMessage(); + } + } + } else { + cmd->_messageKind = 0; + } + } + return result; + default: + return result; + } + case 58: + g_fullpipe->setCursor(cmd->_keyCode); + return result; + case 59: + setInputDisabled(1); + return result; + case 60: + setInputDisabled(0); + return result; + case 56: + if (cmd->_field_2C) { + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (ani) { + getGameLoaderInventory()->addItem2(ani); + result = 1; + } + } else { + result = 1; + getGameLoaderInventory()->addItem(cmd->_parentId, 1); + } + getGameLoaderInventory()->rebuildItemRects(); + return result; + case 57: + if (cmd->_field_2C) { + if (!cmd->_field_20) { + getGameLoaderInventory()->removeItem2(g_fullpipe->_currentScene, cmd->_parentId, cmd->_x, cmd->_y, cmd->_field_14); + getGameLoaderInventory()->rebuildItemRects(); + return 1; + } + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(g_fullpipe->_gameLoader->_field_FA, -1); + if (ani) { + getGameLoaderInventory()->removeItem2(g_fullpipe->_currentScene, cmd->_parentId, ani->_ox + cmd->_x, ani->_oy + cmd->_y, ani->_priority + cmd->_field_14); + getGameLoaderInventory()->rebuildItemRects(); + return 1; + } + } else { + getGameLoaderInventory()->removeItem(cmd->_parentId, 1); + } + getGameLoaderInventory()->rebuildItemRects(); + return 1; + case 55: + if (g_fullpipe->_currentScene) { + GameObject *obj; + if (cmd->_field_14) + obj = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_x, cmd->_y); + else + obj = g_fullpipe->_currentScene->getPictureObjectById(cmd->_x, cmd->_y); + handleObjectInteraction(g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode), obj, cmd->_field_20); + result = 1; + } + return result; + case 51: + return startWalkTo(cmd->_parentId, cmd->_keyCode, cmd->_x, cmd->_y, cmd->_field_20); + case 52: + return doSomeAnimation(cmd->_parentId, cmd->_keyCode, cmd->_field_20); + case 53: + return doSomeAnimation2(cmd->_parentId, cmd->_keyCode); + case 63: + if (cmd->_objtype == kObjTypeObjstateCommand) { + CObjstateCommand *c = (CObjstateCommand *)cmd; + result = 1; + g_fullpipe->setObjectState(c->_objCommandName, c->_value); + } + return result; + default: + return result; + } +} + +int global_messageHandler4(ExCommand *cmd) { + StaticANIObject *ani = 0; + + switch (cmd->_messageKind) { + case 18: { + MessageQueue *mq = new MessageQueue(g_fullpipe->_currentScene->getMessageQueueById(cmd->_messageNum), cmd->_parId, 0); + + if (cmd->_excFlags & 1) + mq->_flag1 = 1; + else + mq->_flag1 = 0; + + mq->sendNextCommand(); + break; + } + case 2: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->trySetMessageQueue(cmd->_messageNum, cmd->_parId); + break; + + case 1: { + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + int flags = cmd->_field_14; + if (flags <= 0) + flags = -1; + + if (cmd->_excFlags & 1) + ani->startAnim(cmd->_messageNum, 0, flags); + else + ani->startAnim(cmd->_messageNum, cmd->_parId, flags); + + break; + } + case 8: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->startAnimEx(cmd->_messageNum, cmd->_parId, -1, -1); + break; + + case 20: { + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + int flags = cmd->_field_14; + if (flags <= 0) + flags = -1; + + ExCommand2 *cmd2 = (ExCommand2 *)cmd; + + if (cmd->_excFlags & 1) { + ani->startAnimSteps(cmd->_messageNum, 0, cmd->_x, cmd->_y, cmd2->_points, cmd2->_pointsSize >> 3, flags); + } else { + ani->startAnimSteps(cmd->_messageNum, cmd->_parId, cmd->_x, cmd->_y, cmd2->_points, cmd2->_pointsSize >> 3, flags); + } + break; + } + case 21: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->queueMessageQueue(0); + ani->playIdle(); + break; + case 9: + // Nop in original + break; + case 3: + g_fullpipe->_currentScene->_y = cmd->_messageNum - cmd->_messageNum % g_fullpipe->_scrollSpeed; + break; + + case 4: + g_fullpipe->_currentScene->_x = cmd->_messageNum - cmd->_messageNum % g_fullpipe->_scrollSpeed; + break; + + case 19: { + if (!g_fullpipe->_currentScene) + break; + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + MessageQueue *mq = ani->getMessageQueue(); + MessageQueue *mq2 = ani->changeStatics1(cmd->_messageNum); + + if (!mq2 || !mq2->getExCommandByIndex(0) || !mq) + break; + + mq2->_parId = mq->_id; + mq2->_flag1 = (cmd->_field_24 == 0); + break; + } + case 22: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->_flags |= 4; + ani->changeStatics2(cmd->_messageNum); + break; + + case 6: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->hide(); + break; + + case 27: + if (!g_fullpipe->_currentScene || g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode) == 0) { + ani = g_fullpipe->accessScene(cmd->_field_20)->getStaticANIObject1ById(cmd->_parentId, -1); + if (ani) { + ani = new StaticANIObject(ani); + g_fullpipe->_currentScene->addStaticANIObject(ani, 1); + } + } + + // fall through + case 5: + if (g_fullpipe->_currentScene) + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + + if (!ani) + break; + + if (cmd->_field_14 >= 0) + ani->_priority = cmd->_field_14; + + ani->show1(cmd->_x, cmd->_y, cmd->_messageNum, cmd->_parId); + break; + + case 10: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + if (cmd->_field_14 >= 0) + ani->_priority = cmd->_field_14; + + ani->show2(cmd->_x, cmd->_y, cmd->_messageNum, cmd->_parId); + break; + + case 7: { + if (!g_fullpipe->_currentScene->_picObjList.size()) + break; + + int offX = g_fullpipe->_scrollSpeed * (cmd->_x / g_fullpipe->_scrollSpeed); + int offY = g_fullpipe->_scrollSpeed * (cmd->_y / g_fullpipe->_scrollSpeed); + + if (cmd->_messageNum) { + g_fullpipe->_currentScene->_x = offX - g_fullpipe->_sceneRect.left; + g_fullpipe->_currentScene->_y = offY - g_fullpipe->_sceneRect.top; + + if (cmd->_field_24) { + g_fullpipe->_currentScene->_messageQueueId = cmd->_parId; + } + } else { + g_fullpipe->_sceneRect.moveTo(offX, offY); + + g_fullpipe->_currentScene->_x = 0; + g_fullpipe->_currentScene->_y = 0; + + g_fullpipe->_currentScene->updateScrolling2(); + } + break; + } + case 34: + if (!g_fullpipe->_currentScene) + break; + + ani = g_fullpipe->_currentScene->getStaticANIObject1ById(cmd->_parentId, cmd->_keyCode); + if (!ani) + break; + + ani->_flags = cmd->_messageNum | (ani->_flags & ~cmd->_field_14); + + break; + + case 35: + global_messageHandler_handleSound(cmd); + break; + + case 11: + case 12: + break; + default: + return 0; + break; + } + + return 1; +} + +int defaultUpdateCursor() { + g_fullpipe->updateCursorsCommon(); + + return g_fullpipe->_cursorId; +} + +int sceneIntro_updateCursor() { + g_fullpipe->_cursorId = 0; + + return 0; +} + +void FullpipeEngine::setSwallowedEggsState() { + CGameVar *v = _gameLoader->_gameVar->getSubVarByName("OBJSTATES")->getSubVarByName(sO_GulpedEggs); + + g_vars->swallowedEgg1 = v->getSubVarByName(sO_Egg1); + g_vars->swallowedEgg2 = v->getSubVarByName(sO_Egg2); + g_vars->swallowedEgg3 = v->getSubVarByName(sO_Egg3); + + g_vars->swallowedEgg1->_value.intValue = 0; + g_vars->swallowedEgg2->_value.intValue = 0; + g_vars->swallowedEgg3->_value.intValue = 0; +} + +void sceneIntro_initScene(Scene *sc) { + g_fullpipe->_gameLoader->loadScene(SC_INTRO2); + + g_vars->sceneIntro_aniin1man = sc->getStaticANIObject1ById(ANI_IN1MAN, -1); + g_vars->sceneIntro_needSleep = true; + g_vars->sceneIntro_needGetup = false; + g_vars->sceneIntro_playing = true; + g_vars->sceneIntro_needBlackout = false; + + if (g_fullpipe->_recordEvents || g_fullpipe->_inputArFlag) + g_vars->sceneIntro_skipIntro = false; + + g_fullpipe->_modalObject = new CModalIntro; +} + +int sceneHandlerIntro(ExCommand *cmd) { + warning("STUB: sceneHandlerIntro()"); + + return 0; +} + +void scene01_fixEntrance() { + CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName("OBJSTATES")->getSubVarByName("SAVEGAME"); + if (var->getSubVarAsInt("Entrance") == TrubaLeft) + var->setSubVarAsInt("Entrance", TrubaRight); +} + +void scene01_initScene(Scene *sc, int entrance) { + g_vars->scene01_picSc01Osk = sc->getPictureObjectById(PIC_SC1_OSK, 0); + g_vars->scene01_picSc01Osk->_flags &= 0xFFFB; + + g_vars->scene01_picSc01Osk2 = sc->getPictureObjectById(PIC_SC1_OSK2, 0); + g_vars->scene01_picSc01Osk2->_flags &= 0xFFFB; + + if (g_fullpipe->getObjectState(sO_EggCracker) == g_fullpipe->getObjectEnumState(sO_EggCracker, sO_DidNotCrackEgg)) { + PictureObject *pic = sc->getPictureObjectById(PIC_SC1_KUCHKA, 0); + if (pic) + pic->_flags &= 0xFFFB; + } + + if (entrance != TrubaLeft) { + StaticANIObject *bootAnim = sc->getStaticANIObject1ById(ANI_BOOT_1, -1); + if (bootAnim) + bootAnim->_flags &= ~0x04; + } + + setElevatorButton(sO_Level2, ST_LBN_2N); +} + +int sceneHandler01(ExCommand *cmd) { + int res = 0; + + if (cmd->_messageKind != 17) + return 0; + + if (cmd->_messageNum > MSG_SC1_SHOWOSK) { + if (cmd->_messageNum == MSG_SC1_UTRUBACLICK) + handleObjectInteraction(g_fullpipe->_aniMan, g_fullpipe->_currentScene->getPictureObjectById(PIC_SC1_LADDER, 0), 0); + + return 0; + } + + if (cmd->_messageNum == MSG_SC1_SHOWOSK) { + g_vars->scene01_picSc01Osk->_flags |= 4; + + g_vars->scene01_picSc01Osk->_priority = 20; + g_vars->scene01_picSc01Osk2->_priority = 21; + + return 0; + } + + if (cmd->_messageNum != 0x21) { + if (cmd->_messageNum == MSG_SC1_SHOWOSK2) { + g_vars->scene01_picSc01Osk2->_flags |= 4; + g_vars->scene01_picSc01Osk2->_priority = 20; + g_vars->scene01_picSc01Osk->_priority = 21; + + return 0; + } + + return 0; + } + + if (g_fullpipe->_aniMan2) { + if (g_fullpipe->_aniMan2->_ox < g_fullpipe->_sceneRect.left + 200) { + g_fullpipe->_currentScene->_x = g_fullpipe->_aniMan2->_ox - g_fullpipe->_sceneRect.left - 300; + } + + if (g_fullpipe->_aniMan2->_ox > g_fullpipe->_sceneRect.right - 200) + g_fullpipe->_currentScene->_x = g_fullpipe->_aniMan2->_ox - g_fullpipe->_sceneRect.right + 300; + + res = 1; + } + g_fullpipe->_behaviorManager->updateBehaviors(); + + g_fullpipe->startSceneTrack(); + + return res; +} + +void sceneDbgMenu_initScene(Scene *sc) { + g_vars->selector = sc->getPictureObjectById(PIC_SCD_SEL, 0); + getGameLoaderInteractionController()->disableFlag24(); + setInputDisabled(0); +} + +GameObject *sceneHandlerDbgMenu_getObjectAtXY(int x, int y) { + if (g_fullpipe->_currentScene) + for (uint i = 0; i < g_fullpipe->_currentScene->_picObjList.size(); i++) { + PictureObject *pic = (PictureObject *)g_fullpipe->_currentScene->_picObjList[i]; + + if (x >= pic->_ox && y >= pic->_oy) { + Common::Point point; + + pic->getDimensions(&point); + + if (x <= pic->_ox + point.x && y <= pic->_oy + point.y && pic != g_vars->selector) + return pic; + } + } + + return 0; +} + +int sceneHandlerDbgMenu(ExCommand *ex) { + if (ex->_messageKind != 17) + return 0; + + int mx = g_fullpipe->_mouseScreenPos.x + g_fullpipe->_sceneRect.left; + int my = g_fullpipe->_mouseScreenPos.y + g_fullpipe->_sceneRect.top; + + if (ex->_messageNum == 29) { + GameObject *obj = sceneHandlerDbgMenu_getObjectAtXY(mx, my); + if (obj && canInteractAny(0, obj, -3) ) { + getGameLoaderInteractionController()->enableFlag24(); + handleObjectInteraction(0, obj, 0); + } + return 0; + } + if (ex->_messageNum != 33) { + if (ex->_messageNum == MSG_RESTARTGAME) { + g_fullpipe->_needRestart = true; + return 0; + } + return 0; + } + + g_fullpipe->_cursorId = PIC_CSR_DEFAULT; + GameObject *obj = g_fullpipe->_currentScene->getStaticANIObjectAtPos(mx, my); + if (obj) { + if (canInteractAny(0, obj, -3)) { + g_fullpipe->_cursorId = PIC_CSR_DEFAULT; + g_fullpipe->setCursor(PIC_CSR_DEFAULT); + return 0; + } + } else { + obj = sceneHandlerDbgMenu_getObjectAtXY(mx, my); + if (obj && canInteractAny(0, obj, -3) ) { + g_vars->selector->_flags |= 4; + g_vars->selector->setOXY(obj->_ox, obj->_oy); + g_fullpipe->_cursorId = PIC_CSR_DEFAULT; + g_fullpipe->setCursor(PIC_CSR_DEFAULT); + return 0; + } + g_vars->selector->_flags &= 0xFFFB; + } + g_fullpipe->setCursor(g_fullpipe->_cursorId); + + return 0; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/scenes.h b/engines/fullpipe/scenes.h new file mode 100644 index 0000000000..be42838920 --- /dev/null +++ b/engines/fullpipe/scenes.h @@ -0,0 +1,53 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_SCENES_H +#define FULLPIPE_SCENES_H + +namespace Fullpipe { + +class StaticANIObject; + +class Vars { + public: + Vars(); + + CGameVar *swallowedEgg1; + CGameVar *swallowedEgg2; + CGameVar *swallowedEgg3; + + StaticANIObject *sceneIntro_aniin1man; + bool sceneIntro_needSleep; + bool sceneIntro_needGetup; + bool sceneIntro_skipIntro; + bool sceneIntro_playing; + bool sceneIntro_needBlackout; + + PictureObject *scene01_picSc01Osk; + PictureObject *scene01_picSc01Osk2; + + GameObject *selector; +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SCENES_H */ diff --git a/engines/fullpipe/sound.cpp b/engines/fullpipe/sound.cpp new file mode 100644 index 0000000000..7f34412334 --- /dev/null +++ b/engines/fullpipe/sound.cpp @@ -0,0 +1,140 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/sound.h" +#include "fullpipe/ngiarchive.h" + +namespace Fullpipe { + +SoundList::SoundList() { + _soundItems = 0; + _soundItemsCount = 0; + _libHandle = 0; +} + +bool SoundList::load(MfcArchive &file, char *fname) { + debug(5, "SoundList::load()"); + + _soundItemsCount = file.readUint32LE(); + _soundItems = (Sound **)calloc(_soundItemsCount, sizeof(Sound *)); + + if (fname) { + _libHandle = (NGIArchive *)makeNGIArchive(fname); + } else { + _libHandle = 0; + } + + for (int i = 0; i < _soundItemsCount; i++) { + Sound *snd = new Sound(); + + _soundItems[i] = 0; + snd->load(file, _libHandle); + } + + return true; + +} + +bool SoundList::loadFile(const char *fname, char *libname) { + Common::File file; + + if (!file.open(fname)) + return false; + + MfcArchive archive(&file); + + return load(archive, libname); +} + +Sound::Sound() { + _id = 0; + _directSoundBuffer = 0; + _soundData = 0; + _objectId = 0; + memset(_directSoundBuffers, 0, sizeof(_directSoundBuffers)); + _description = 0; +} + + +bool Sound::load(MfcArchive &file, NGIArchive *archive) { + debug(5, "Sound::load()"); + + MemoryObject::load(file); + + _id = file.readUint32LE(); + _description = file.readPascalString(); + + assert(g_fullpipe->_gameProjectVersion >= 6); + + _objectId = file.readUint16LE(); + + if (archive && archive->hasFile(_memfilename)) { + Common::SeekableReadStream *s = archive->createReadStreamForMember(_memfilename); + + _soundData = (byte *)calloc(s->size(), 1); + + s->read(_soundData, s->size()); + + delete s; + } + + return true; +} + +void Sound::updateVolume() { + debug(3, "STUB Sound::updateVolume()"); +} + +void Sound::setPanAndVolumeByStaticAni() { + debug(3, "STUB Sound::setPanAndVolumeByStaticAni()"); +} + +void FullpipeEngine::setSceneMusicParameters(CGameVar *var) { + warning("STUB: FullpipeEngine::setSceneMusicParameters()"); +} + +void FullpipeEngine::startSceneTrack() { + debug(3, "STUB: FullpipeEngine::startSceneTrack()"); +} + +void FullpipeEngine::stopAllSounds() { + warning("STUB: FullpipeEngine::stopAllSounds()"); +} + +void FullpipeEngine::toggleMute() { + warning("STUB: FullpipeEngine::toggleMute()"); +} + +void FullpipeEngine::playSound(int id, int flag) { + warning("STUB: FullpipeEngine::playSounds(%d, %d)", id, flag); +} + +void global_messageHandler_handleSound(ExCommand *cmd) { + debug(0, "STUB: global_messageHandler_handleSound()"); +} + + + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/sound.h b/engines/fullpipe/sound.h new file mode 100644 index 0000000000..4014cdd94e --- /dev/null +++ b/engines/fullpipe/sound.h @@ -0,0 +1,61 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_SOUND_H +#define FULLPIPE_SOUND_H + +namespace Fullpipe { + +class Sound : public MemoryObject { + int _id; + char *_description; + int16 _objectId; + int16 _field_32; + int _directSoundBuffer; + int _directSoundBuffers[7]; + byte *_soundData; + + public: + Sound(); + bool load(MfcArchive &file, NGIArchive *archive); + void updateVolume(); + + void setPanAndVolumeByStaticAni(); +}; + +class SoundList : public CObject { + Sound **_soundItems; + int _soundItemsCount; + NGIArchive *_libHandle; + + public: + SoundList(); + bool load(MfcArchive &file, char *fname); + bool loadFile(const char *fname, char *libname); + + int getCount() { return _soundItemsCount; } + Sound *getSoundByIndex(int idx) { return _soundItems[idx]; } +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_SOUND_H */ diff --git a/engines/fullpipe/stateloader.cpp b/engines/fullpipe/stateloader.cpp new file mode 100644 index 0000000000..40169ddf9f --- /dev/null +++ b/engines/fullpipe/stateloader.cpp @@ -0,0 +1,411 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "common/file.h" +#include "common/array.h" +#include "common/list.h" + +#include "fullpipe/objects.h" +#include "fullpipe/gameloader.h" +#include "fullpipe/scene.h" +#include "fullpipe/statics.h" +#include "fullpipe/interaction.h" + +#include "fullpipe/constants.h" + +namespace Fullpipe { + +bool FullpipeEngine::loadGam(const char *fname, int scene) { + _gameLoader = new CGameLoader(); + + if (!_gameLoader->loadFile(fname)) + return false; + + _currSoundListCount = 0; + initObjectStates(); + // set_g_messageQueueCallback1(messageQueueCallback1); // substituted with direct call + + addMessageHandlerByIndex(global_messageHandler1, 0, 4); + + _inventory = getGameLoaderInventory(); + _inventory->setItemFlags(ANI_INV_MAP, 0x10003); + _inventory->addItem(ANI_INV_MAP, 1); + + _inventory->rebuildItemRects(); + + for (CPtrList::iterator p = _inventory->getScene()->_picObjList.begin(); p != _inventory->getScene()->_picObjList.end(); ++p) { + ((MemoryObject *)((PictureObject *)*p)->_picture)->load(); + } + + // _sceneSwitcher = sceneSwitcher; // substituted with direct call + // _preloadCallback = gameLoaderPreloadCallback + // _readSavegameCallback = gameLoaderReadSavegameCallback; + + _aniMan = accessScene(SC_COMMON)->getAniMan(); + _scene2 = 0; + + _movTable = _aniMan->countMovements(); + + _aniMan->setSpeed(1); + + PictureObject *pic = accessScene(SC_INV)->getPictureObjectById(PIC_INV_MENU, 0); + + pic->setFlags(pic->_flags & 0xFFFB); + + // Not used in full game + //_evalVersionPic = accessScene(SC_COMMON)->getPictureObjectById(PIC_CMN_EVAL, 0); + + initMap(); + initCursors(); + + setMusicAllowed(_gameLoader->_gameVar->getSubVarAsInt("MUSIC_ALLOWED")); + + if (scene) { + _gameLoader->loadScene(scene); + _gameLoader->gotoScene(scene, TrubaLeft); + } else { + if (_flgPlayIntro) { + _gameLoader->loadScene(SC_INTRO1); + _gameLoader->gotoScene(SC_INTRO1, TrubaUp); + } else { + _gameLoader->loadScene(SC_1); + _gameLoader->gotoScene(SC_1, TrubaLeft); + } + } + + if (!_currentScene) + return false; + + return true; +} + +GameProject::GameProject() { + _field_4 = 0; + _headerFilename = 0; + _field_10 = 12; +} + +bool GameProject::load(MfcArchive &file) { + debug(5, "GameProject::load()"); + + _field_4 = 0; + _headerFilename = 0; + _field_10 = 12; + + g_fullpipe->_gameProjectVersion = file.readUint32LE(); + g_fullpipe->_pictureScale = file.readUint16LE(); + g_fullpipe->_scrollSpeed = file.readUint32LE(); + + _headerFilename = file.readPascalString(); + + debug(1, "_gameProjectVersion = %d", g_fullpipe->_gameProjectVersion); + debug(1, "_pictureScale = %d", g_fullpipe->_pictureScale); + debug(1, "_scrollSpeed = %d", g_fullpipe->_scrollSpeed); + debug(1, "_headerFilename = %s", _headerFilename); + + _sceneTagList = new SceneTagList(); + + _sceneTagList->load(file); + + if (g_fullpipe->_gameProjectVersion >= 3) + _field_4 = file.readUint32LE(); + + if (g_fullpipe->_gameProjectVersion >= 5) { + file.readUint32LE(); + file.readUint32LE(); + } + + return true; +} + +GameProject::~GameProject() { + free(_headerFilename); +} + +bool PreloadItems::load(MfcArchive &file) { + debug(5, "PreloadItems::load()"); + + int count = file.readCount(); + + resize(count); + + for (int i = 0; i < count; i++) { + PreloadItem *t = new PreloadItem(); + t->preloadId1 = file.readUint32LE(); + t->preloadId2 = file.readUint32LE(); + t->sceneId = file.readUint32LE(); + t->field_C = file.readUint32LE(); + + push_back(*t); + } + + return true; +} + +CGameVar::CGameVar() { + _subVars = 0; + _parentVarObj = 0; + _nextVarObj = 0; + _prevVarObj = 0; + _field_14 = 0; + _varType = 0; + _value.floatValue = 0; + _varName = 0; +} + +bool CGameVar::load(MfcArchive &file) { + _varName = file.readPascalString(); + _varType = file.readUint32LE(); + + debugN(6, "[%03d] ", file.getLevel()); + for (int i = 0; i < file.getLevel(); i++) + debugN(6, " "); + + debugN(6, "<%s>: ", transCyrillic((byte *)_varName)); + + switch (_varType) { + case 0: + _value.intValue = file.readUint32LE(); + debug(6, "d --> %d", _value.intValue); + break; + case 1: + _value.intValue = file.readUint32LE(); // FIXME + debug(6, "f --> %f", _value.floatValue); + break; + case 2: + _value.stringValue = file.readPascalString(); + debug(6, "s --> %s", _value.stringValue); + break; + default: + error("Unknown var type: %d (0x%x)", _varType, _varType); + } + + file.incLevel(); + _parentVarObj = (CGameVar *)file.readClass(); + _prevVarObj = (CGameVar *)file.readClass(); + _nextVarObj = (CGameVar *)file.readClass(); + _field_14 = (CGameVar *)file.readClass(); + _subVars = (CGameVar *)file.readClass(); + file.decLevel(); + + return true; +} + +CGameVar *CGameVar::getSubVarByName(const char *name) { + CGameVar *sv = 0; + + if (_subVars != 0) { + sv = _subVars; + for (;sv && scumm_stricmp(sv->_varName, name); sv = sv->_nextVarObj) + ; + } + return sv; +} + +bool CGameVar::setSubVarAsInt(const char *name, int value) { + CGameVar *var = getSubVarByName(name); + + if (var) { + if (var->_varType == 0) { + var->_value.intValue = value; + + return true; + } + return false; + } + + var = new CGameVar(); + var->_varType = 0; + var->_value.intValue = value; + var->_varName = (char *)calloc(strlen(name) + 1, 1); + strcpy(var->_varName, name); + + return addSubVar(var); +} + +int CGameVar::getSubVarAsInt(const char *name) { + CGameVar *var = getSubVarByName(name); + + if (var) + return var->_value.intValue; + else + return 0; +} + +CGameVar *CGameVar::addSubVarAsInt(const char *name, int value) { + if (getSubVarByName(name)) { + return 0; + } else { + CGameVar *var = new CGameVar(); + + var->_varType = 0; + var->_value.intValue = value; + + var->_varName = (char *)calloc(strlen(name) + 1, 1); + strcpy(var->_varName, name); + + return (addSubVar(var) != 0) ? var : 0; + } +} + +bool CGameVar::addSubVar(CGameVar *subvar) { + CGameVar *var = _subVars; + + if (var) { + for (CGameVar *i = var->_nextVarObj; i; i = i->_nextVarObj) + var = i; + + var->_nextVarObj = subvar; + subvar->_prevVarObj = var; + subvar->_parentVarObj = this; + + return true; + } else { + _subVars = subvar; + subvar->_parentVarObj = this; + + return true; + } + + return false; +} + +int CGameVar::getSubVarsCount() { + int res; + CGameVar *sub = _subVars; + + for (res = 0; sub; res++) + sub = sub->_nextVarObj; + + return res; +} + +CGameVar *CGameVar::getSubVarByIndex(int idx) { + CGameVar *sub = _subVars; + + while (idx--) { + sub = sub->_nextVarObj; + + if (!sub) + return 0; + } + + return sub; +} + +Sc2::Sc2() { + _sceneId = 0; + _field_2 = 0; + _scene = 0; + _motionController = 0; + _data1 = 0; + _count1 = 0; + _defPicAniInfos = 0; + _defPicAniInfosCount = 0; + _picAniInfos = 0; + _picAniInfosCount = 0; + _isLoaded = 0; + _entranceData = 0; + _entranceDataCount = 0; +} + +bool Sc2::load(MfcArchive &file) { + debug(5, "Sc2::load()"); + + _sceneId = file.readUint16LE(); + + _motionController = (CMotionController *)file.readClass(); + + _count1 = file.readUint32LE(); + debug(4, "count1: %d", _count1); + if (_count1 > 0) { + _data1 = (int32 *)malloc(_count1 * sizeof(int32)); + + for (int i = 0; i < _count1; i++) { + _data1[i] = file.readUint32LE(); + } + } else { + _data1 = 0; + } + + _defPicAniInfosCount = file.readUint32LE(); + debug(4, "defPicAniInfos: %d", _defPicAniInfosCount); + if (_defPicAniInfosCount > 0) { + _defPicAniInfos = (PicAniInfo **)malloc(_defPicAniInfosCount * sizeof(PicAniInfo *)); + + for (int i = 0; i < _defPicAniInfosCount; i++) { + _defPicAniInfos[i] = new PicAniInfo(); + + _defPicAniInfos[i]->load(file); + } + } else { + _defPicAniInfos = 0; + } + + _picAniInfos = 0; + _picAniInfosCount = 0; + + _entranceDataCount = file.readUint32LE(); + debug(4, "_entranceData: %d", _entranceDataCount); + + if (_entranceDataCount > 0) { + _entranceData = (EntranceInfo **)malloc(_entranceDataCount * sizeof(EntranceInfo *)); + + for (int i = 0; i < _entranceDataCount; i++) { + _entranceData[i] = new EntranceInfo(); + _entranceData[i]->load(file); + } + } else { + _entranceData = 0; + } + + if (file.size() - file.pos() > 0) + error("Sc2::load(): (%d bytes left)", file.size() - file.pos()); + + return true; +} + +bool PicAniInfo::load(MfcArchive &file) { + debug(5, "PicAniInfo::load()"); + + type = file.readUint32LE(); + objectId = file.readUint16LE(); + field_6 = file.readUint16LE(); + field_8 = file.readUint32LE(); + sceneId = file.readUint16LE(); + field_E = file.readUint16LE(); + ox = file.readUint32LE(); + oy = file.readUint32LE(); + priority = file.readUint32LE(); + staticsId = file.readUint16LE(); + movementId = file.readUint16LE(); + dynamicPhaseIndex = file.readUint16LE(); + flags = file.readUint16LE(); + field_24 = file.readUint32LE(); + someDynamicPhaseIndex = file.readUint32LE(); + + return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/statics.cpp b/engines/fullpipe/statics.cpp new file mode 100644 index 0000000000..1fd02f8eb6 --- /dev/null +++ b/engines/fullpipe/statics.cpp @@ -0,0 +1,1720 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "fullpipe/objects.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/statics.h" +#include "fullpipe/messages.h" +#include "fullpipe/interaction.h" + +#include "fullpipe/constants.h" +#include "fullpipe/objectnames.h" + +namespace Fullpipe { + +CStepArray::CStepArray() { + _points = 0; + _maxPointIndex = 0; + _currPointIndex = 0; + _pointsCount = 0; + _isEos = 0; +} + +CStepArray::~CStepArray() { + if (_pointsCount) { + for (int i = 0; i < _pointsCount; i++) + delete _points[i]; + + delete _points; + + _points = 0; + } +} + +void CStepArray::clear() { + _currPointIndex = 0; + _maxPointIndex = 0; + _isEos = 0; + + for (int i = 0; i < _pointsCount; i++) { + _points[i]->x = 0; + _points[i]->y = 0; + } +} + +Common::Point *CStepArray::getCurrPoint(Common::Point *point) { + if (_isEos || _points == 0) { + point->x = 0; + point->y = 0; + } else { + point = _points[_currPointIndex]; + } + return point; +} + +bool CStepArray::gotoNextPoint() { + if (_currPointIndex < _maxPointIndex) { + _currPointIndex++; + return true; + } else { + _isEos = 1; + return false; + } +} + +StaticANIObject::StaticANIObject() { + _shadowsOn = 1; + _field_30 = 0; + _field_34 = 1; + _initialCounter = 0; + _messageQueueId = 0; + _animExFlag = 0; + _counter = 0; + _movement = 0; + _statics = 0; + _flags = 0; + _callback1 = 0; + _callback2 = 0; + _sceneId = -1; + _someDynamicPhaseIndex = -1; + + _field_32 = 0; + _field_96 = 0; + _messageNum = 0; + _objtype = kObjTypeStaticANIObject; +} + +StaticANIObject::StaticANIObject(StaticANIObject *src) : GameObject(src) { + _shadowsOn = src->_shadowsOn; + _field_30 = src->_field_30; + _field_34 = 1; + _initialCounter = 0; + + _field_32 = 0; + _field_96 = 0; + _messageNum = 0; + + _messageQueueId = 0; + _animExFlag = 0; + _counter = 0; + _someDynamicPhaseIndex = -1; + _sceneId = src->_sceneId; + _callback1 = src->_callback1; + _callback2 = src->_callback2; + _objtype = kObjTypeStaticANIObject; + + for (uint i = 0; i < src->_staticsList.size(); i++) + _staticsList.push_back(new Statics((Statics *)src->_staticsList[i], 0)); + + _movement = 0; + _statics = 0; + + for (uint i = 0; i < src->_movements.size(); i++) { + Movement *mov; + if (((Movement *)src->_movements[i])->_currMovement) { + mov = new Movement(getMovementById(src->getMovementIdById(((Movement *)src->_movements[i])->_id)), this); + mov->_id = ((Movement *)src->_movements[i])->_id; + } else { + mov = new Movement(((Movement *)src->_movements[i]), 0, -1, this); + } + + _movements.push_back(mov); + } +} + +bool StaticANIObject::load(MfcArchive &file) { + debug(5, "StaticANIObject::load()"); + + GameObject::load(file); + + int count = file.readUint16LE(); + + for (int i = 0; i < count; i++) { + Statics *st = new Statics(); + + st->load(file); + _staticsList.push_back(st); + } + + count = file.readUint16LE(); + debug(7, "Movements: %d", count); + + for (int i = 0; i < count; i++) { + int movNum = file.readUint16LE(); + + char *movname = genFileName(_id, movNum, "mov"); + + Common::SeekableReadStream *f = g_fullpipe->_currArchive->createReadStreamForMember(movname); + + Movement *mov = new Movement(); + + MfcArchive archive(f); + + mov->load(archive, this); + + _movements.push_back(mov); + + delete f; + free(movname); + } + + Common::Point pt; + if (count) { // We have movements + ((Movement *)_movements[0])->getCurrDynamicPhaseXY(pt); + } else { + pt.x = pt.y = 100; + } + + setOXY(pt.x, pt.y); + + return true; +} + +void StaticANIObject::setOXY(int x, int y) { + _ox = x; + _oy = y; + + if (_movement) + _movement->setOXY(x, y); +} + +void StaticANIObject::clearFlags() { + _flags = 0; + + deleteFromGlobalMessageQueue(); + _messageQueueId = 0; + _movement = 0; + _statics = 0; + _animExFlag = 0; + _counter = 0; + _messageNum = 0; + _stepArray.clear(); +} + +void StaticANIObject::setFlags40(bool state) { + if (state) { + _flags |= 0x40; + } else { + if (_flags & 0x40) + _flags ^= 0x40; + } +} + +void StaticANIObject::deleteFromGlobalMessageQueue() { + while (_messageQueueId) { + if (g_fullpipe->_globalMessageQueueList->getMessageQueueById(_messageQueueId)) { + if (!isIdle()) + return; + + g_fullpipe->_globalMessageQueueList->deleteQueueById(_messageQueueId); + } else { + _messageQueueId = 0; + } + } +} + +void StaticANIObject::queueMessageQueue(MessageQueue *mq) { + if (isIdle() && !(_flags & 0x80)) { + deleteFromGlobalMessageQueue(); + _messageQueueId = 0; + _messageNum = 0; + + if (_flags & 2) + _flags ^= 2; + + if (mq) { + _animExFlag = 0; + if (_movement) + _messageQueueId = mq->_id; + else + mq->sendNextCommand(); + } else { + _messageQueueId = 0; + } + } +} + +MessageQueue *StaticANIObject::getMessageQueue() { + if (this->_messageQueueId <= 0) + return 0; + + return g_fullpipe->_globalMessageQueueList->getMessageQueueById(_messageQueueId); +} + +bool StaticANIObject::trySetMessageQueue(int msgNum, int qId) { + if (_messageQueueId || !msgNum) { + updateGlobalMessageQueue(qId, _id); + return false; + } + + _flags |= 2; + + _messageNum = msgNum; + _messageQueueId = qId; + + return true; +} + +bool StaticANIObject::isIdle() { + if (_messageQueueId) { + MessageQueue *m = g_fullpipe->_globalMessageQueueList->getMessageQueueById(_messageQueueId); + + if (m && m->getFlags() & 1) + return false; + } + + return true; +} + +Statics *StaticANIObject::getStaticsById(int itemId) { + for (uint i = 0; i < _staticsList.size(); i++) + if (((Statics *)_staticsList[i])->_staticsId == itemId) + return (Statics *)_staticsList[i]; + + return 0; +} + +Statics *StaticANIObject::getStaticsByName(char *name) { + for (uint i = 0; i < _staticsList.size(); i++) + if (!strcmp(((Statics *)_staticsList[i])->_staticsName, name)) + return (Statics *)_staticsList[i]; + + return 0; +} + +Movement *StaticANIObject::getMovementById(int itemId) { + for (uint i = 0; i < _movements.size(); i++) + if (((Movement *)_movements[i])->_id == itemId) + return (Movement *)_movements[i]; + + return 0; +} + +int StaticANIObject::getMovementIdById(int itemId) { + for (uint i = 0; i < _movements.size(); i++) { + Movement *mov = (Movement *)_movements[i]; + if (mov->_currMovement) { + if (mov->_id == itemId) + return mov->_id; + if (mov->_currMovement->_id == itemId) + return mov->_id; + } + } + + return 0; +} + +Movement *StaticANIObject::getMovementByName(char *name) { + for (uint i = 0; i < _movements.size(); i++) + if (!strcmp(((Movement *)_movements[i])->_objectName, name)) + return (Movement *)_movements[i]; + + return 0; +} + +bool StaticANIObject::getPixelAtPos(int x, int y, int *pixel) { + bool res = false; + Picture *pic; + + if (_movement) + pic = _movement->_currDynamicPhase; + else + pic = _statics; + + if (!pic) + return false; + + int ongoing; + int xani, yani; + int oxani, oyani; + Common::Point point; + + if (_movement) + ongoing = _movement->_currMovement != 0; + else + ongoing = _statics->_staticsId & 0x4000; + + if (_movement) { + _movement->getCurrDynamicPhaseXY(point); + xani = point.x; + yani = point.y; + oxani = _movement->_ox; + oyani = _movement->_oy; + } else { + _statics->getSomeXY(point); + xani = point.x; + yani = point.y; + oxani = _ox; + oyani = _oy; + } + + int xtarget = x - (oxani - xani); + int ytarget = y - (oyani - yani); + + if (ongoing && _movement) + xtarget = pic->getDimensions(&point)->x - xtarget; + + x = pic->_x; + y = pic->_y; + pic->_x = 0; + pic->_y = 0; + if (pic->isPixelHitAtPos(xtarget, ytarget)) { + *pixel = pic->getPixelAtPos(xtarget, ytarget); + + res = true; + } else { + res = false; + } + pic->_x = x; + pic->_y = y; + + return res; +} + +void Movement::draw(bool flipFlag, int angle) { + debug(3, "Movement::draw(%d, %d)", flipFlag, angle); + + Common::Point point; + + getCurrDynamicPhaseXY(point); + + int x = _ox - point.x; + int y = _oy - point.y; + + if (_currDynamicPhase->getPaletteData()) + g_fullpipe->_globalPalette = _currDynamicPhase->getPaletteData(); + + if (_currDynamicPhase->getAlpha() < 0xFF) { + warning("Movement::draw: alpha < 0xff: %d", _currDynamicPhase->getAlpha()); + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, _currDynamicPhase->getAlpha()); + } + + Bitmap *bmp; + if (_currMovement) { + bmp = _currDynamicPhase->getPixelData()->reverseImage(); + } else { + bmp = _currDynamicPhase->getPixelData(); + } + + if (flipFlag) { + bmp->flipVertical()->drawShaded(1, x, y + 30 + _currDynamicPhase->_rect->bottom, _currDynamicPhase->_paletteData); + } if (angle) { + bmp->drawRotated(x, y, angle, _currDynamicPhase->_paletteData); + } else { + bmp->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + } + + if (_currDynamicPhase->_rect->top) { + if (!_currDynamicPhase->_convertedBitmap) { + //v12 = Picture_getPixelData(v5); + //v13 = Bitmap_convertTo16Bit565(v12, (unsigned int *)&_currDynamicPhase->rect); + //_currDynamicPhase->convertedBitmap = v13; + } + + if (_currDynamicPhase->_convertedBitmap) { + if (_currMovement) { + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); + _currDynamicPhase->_convertedBitmap->reverseImage()->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); + } else { + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 1, LOBYTE(_currDynamicPhase->rect.top)); + _currDynamicPhase->_convertedBitmap->putDib(x, y, (int32 *)_currDynamicPhase->_paletteData); + //vrtSetAlphaBlendMode(g_vrtDrawHandle, 0, 255); + } + } + } +} + + +void StaticANIObject::loadMovementsPixelData() { + for (uint i = 0; i < _movements.size(); i++) + ((Movement *)_movements[i])->loadPixelData(); +} + +Statics *StaticANIObject::addReverseStatics(Statics *st) { + Statics *res = getStaticsById(st->_staticsId ^ 0x4000); + + if (!res) { + res = new Statics(st, true); + + _staticsList.push_back(res); + } + + return res; +} + +void StaticANIObject::draw() { + if ((_flags & 4) == 0) + return; + + Common::Point point; + Common::Rect rect; + + debug(0, "StaticANIObject::draw() (%s) [%d] [%d, %d]", transCyrillic((byte *)_objectName), _id, _ox, _oy); + + if (_shadowsOn && g_fullpipe->_currentScene && g_fullpipe->_currentScene->_shadows + && (getCurrDimensions(point)->x != 1 || getCurrDimensions(point)->y != 1)) { + + DynamicPhase *dyn; + + if (!_movement || _flags & 0x20) + dyn = _statics; + else + dyn = _movement->_currDynamicPhase; + + if (!dyn) { + warning("HACK: StaticANIObject::draw(): dyn is missing"); + return; + } + + if (dyn->getDynFlags() & 4) { + rect = *dyn->_rect; + + DynamicPhase *shd = g_fullpipe->_currentScene->_shadows->findSize(rect.width(), rect.height()); + if (shd) { + shd->getDimensions(&point); + int midx = _ox - point.x / 2 - dyn->_someX; + int midy = _oy - point.y / 2 - dyn->_someY + rect.bottom - 3; + int shdw = point.y; + + int px; + if (!_movement || (_flags & 0x20)) + px = _statics->getCenter(&point)->x; + else + px = _movement->getCenter(&point)->x; + + if (_shadowsOn != 1) + midy = _shadowsOn - shdw / 2; + + shd->draw(px + midx, midy, 0, 0); + } + } + } + + int angle = 0; + if (_field_30 & 0xC000) { + if (_field_30 & 0x8000) + angle = -(_field_30 ^ 0x8000); + else + angle = _field_30 ^ 0x4000; + } + + if (!_movement || (_flags & 0x20)) { + _statics->getSomeXY(point); + _statics->_x = _ox - point.x; + _statics->_y = _oy - point.y; + _statics->draw(_statics->_x, _statics->_y, 0, angle); + } else { + _movement->draw(0, angle); + } +} + +void StaticANIObject::draw2() { + debug(0, "StatciANIObject::draw2(): id: (%s) %d [%d, %d]", transCyrillic((byte *)_objectName), _id, _ox, _oy); + + if ((_flags & 4) && (_flags & 0x10)) { + if (_movement) { + _movement->draw(1, 0); + } else { + Common::Point point; + + _statics->getSomeXY(point); + + _statics->draw(_ox - point.x, _oy - point.y, 1, 0); + } + } +} + +MovTable *StaticANIObject::countMovements() { + CGameVar *preloadSubVar = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("PRELOAD"); + + if (preloadSubVar || preloadSubVar->getSubVarsCount() == 0) + return 0; + + MovTable *movTable = new MovTable; + + movTable->count = _movements.size(); + movTable->movs = (int16 *)calloc(_movements.size(), sizeof(int16)); + + for (uint i = 0; i < _movements.size(); i++) { + GameObject *obj = (GameObject *)_movements[i]; + movTable->movs[i] = 2; + + for (CGameVar *sub = preloadSubVar->_subVars; sub; sub = sub->_nextVarObj) { + if (scumm_stricmp(obj->getName(), sub->_varName) == 0) { + movTable->movs[i] = 1; + break; + } + } + } + + return movTable; +} + +void StaticANIObject::setSpeed(int speed) { + CGameVar *var = g_fullpipe->getGameLoaderGameVar()->getSubVarByName(getName())->getSubVarByName("SpeedUp"); + + if (!var) + return; + + for (var = var->_subVars; var; var = var->_nextVarObj) { + Movement *mov = getMovementById(var->_value.intValue); + + if (mov) { + if (speed) { + if (mov->_counterMax == 83) + mov->_counterMax = 41; + } else if (mov->_counterMax == 41) { + mov->_counterMax = 83; + } + } + } + +} + +void StaticANIObject::setAlpha(int alpha) { + for (uint i = 0; i < _movements.size(); i++) + ((Movement *)_movements[i])->setAlpha(alpha); + + for (uint i = 0; i < _staticsList.size(); i++) + ((Statics *)_staticsList[i])->setAlpha(alpha); +} + +void StaticANIObject::initMovements() { + for (uint i = 0; i < _movements.size(); i++) + ((Movement *)_movements[i])->removeFirstPhase(); +} + +Common::Point *StaticANIObject::getCurrDimensions(Common::Point &p) { + Picture *pic; + + if (_movement) + pic = _movement->_currDynamicPhase; + else + pic = _statics; + + if (pic) { + Common::Point point; + + pic->getDimensions(&point); + p.x = point.x; + p.y = point.y; + } else { + p.x = 0; + p.y = 0; + } + + return &p; +} + +void StaticANIObject::update(int counterdiff) { + int mqid; + + debug(6, "StaticANIObject::update() (%s) [%d] [%d, %d] fl: %x", transCyrillic((byte *)_objectName), _id, _ox, _oy, _flags); + + if (_flags & 2) { + _messageNum--; + if (_messageNum) + return; + + mqid = _messageQueueId; + _messageQueueId = 0; + _flags ^= 2; + + updateGlobalMessageQueue(mqid, _id); + return; + } + + Common::Point point; + ExCommand *ex, *newex; + + if (_movement) { + _movement->_counter += counterdiff; + + if (_movement->_counter < _movement->_counterMax) + return; + + _movement->_counter = 0; + + if (_flags & 1) { + if (_counter) { + _counter--; + + return; + } + + DynamicPhase *dyn = _movement->_currDynamicPhase; + if (dyn->_initialCountdown == dyn->_countdown) { + + ex = dyn->getExCommand(); + if (ex && ex->_messageKind != 35) { + newex = new ExCommand(ex); + newex->_excFlags |= 2; + if (newex->_messageKind == 17) { + newex->_parentId = _id; + newex->_keyCode = _okeyCode; + } + newex->sendMessage(); + + if (!_movement) + return; + } + } + + if (dyn->_initialCountdown != dyn->_countdown || dyn->_field_68 == 0) { + newex = new ExCommand(_id, 17, dyn->_field_68, 0, 0, 0, 1, 0, 0, 0); + newex->_excFlags = 2; + newex->_keyCode = _okeyCode; + newex->sendMessage(); + + if (!_movement) + return; + } + + if (!_movement->gotoNextFrame(_callback1, _callback2)) { + stopAnim_maybe(); + } else { + setOXY(_movement->_ox, _movement->_oy); + _counter = _initialCounter; + + if (dyn->_initialCountdown == dyn->_countdown) { + ex = dyn->getExCommand(); + if (ex) { + if (ex->_messageKind == 35) { + newex = new ExCommand(ex); + newex->_excFlags |= 2; + newex->sendMessage(); + } + } + } + if (!_movement) + return; + + _stepArray.getCurrPoint(&point); + setOXY(point.x + _ox, point.y + _oy); + _stepArray.gotoNextPoint(); + if (_someDynamicPhaseIndex == _movement->_currDynamicPhaseIndex) + adjustSomeXY(); + } + } else if (_flags & 0x20) { + _flags ^= 0x20; + _flags |= 1; + + _movement->gotoFirstFrame(); + _movement->getCurrDynamicPhaseXY(point); + + Common::Point pointS; + _statics->getSomeXY(pointS); + _movement->setOXY(_ox + point.x + _movement->_mx - pointS.x, + _oy + point.y + _movement->_my - pointS.y); + } + } else { + if (_statics) { + if (_messageQueueId) { + if (_statics->_countdown) { + _statics->_countdown--; + return; + } + mqid = _messageQueueId; + _messageQueueId = 0; + updateGlobalMessageQueue(mqid, _id); + } + } + } +} + +void StaticANIObject::stopAnim_maybe() { + debug(6, "StaticANIObject::stopAnim_maybe()"); + + if (!(_flags & 1)) + return; + + _flags ^= 1; + + int oid = 0; + int oldmqid = _messageQueueId; + Common::Point point; + + if (_movement) { + setOXY(_movement->_ox, _movement->_oy); + + if (_flags & 0x40) { + if (!_movement->_currMovement && !_movement->_currDynamicPhaseIndex) { + _statics = _movement->_staticsObj1; + _movement->getCurrDynamicPhaseXY(point); + _ox -= point.x; + _oy -= point.y; + + _ox -= _movement->_mx; + _oy -= _movement->_my; + + _statics->getSomeXY(point); + if (_movement->_currMovement) { + _oy += point.y; + _ox -= point.x; + _ox += _statics->getDimensions(&point)->x; + } else { + _ox += point.x; + _oy += point.y; + } + } + } + + if (_movement->_currDynamicPhaseIndex || !(_flags & 0x40)) + _statics = _movement->_staticsObj2; + + _statics->getSomeXY(point); + + _statics->_x = _ox - point.x; + _statics->_y = _oy - point.y; + oid = _movement->_id; + _movement = 0; + + ExCommand *ex = new ExCommand(_id, 17, 24, 0, 0, 0, 1, 0, 0, 0); + ex->_keyCode = _okeyCode; + ex->_excFlags = 2; + ex->postMessage(); + } + + int mqid = _messageQueueId; + + if (_animExFlag) { + _messageQueueId = 0; + startAnimEx(oid, mqid, -1, -1); + } else { + if (_messageQueueId == oldmqid) { + _messageQueueId = 0; + if (_field_34 == 1) + updateGlobalMessageQueue(mqid, _id); + } + } +} + +void StaticANIObject::adjustSomeXY() { + warning("STUB: StaticANIObject::adjustSomeXY()"); +} + +MessageQueue *StaticANIObject::changeStatics1(int msgNum) { + warning("STUB: StaticANIObject::changeStatics1(%d)", msgNum); + + return 0; +} + +void StaticANIObject::changeStatics2(int objId) { + warning("STUB: StaticANIObject::changeStatics2(%d)", objId); +} + +void StaticANIObject::hide() { + if (!_messageQueueId) { + if (_flags & 4) + _flags ^= 4; + } +} + +void StaticANIObject::show1(int x, int y, int movId, int mqId) { + debug(0, "StaticANIObject::show1(%d, %d, %d, %d)", x, y, movId, mqId); + + if (_messageQueueId) + return; + + if (movId == -1) { + _flags |= 4u; + if (x != -1 && y != -1) { + setOXY(x, y); + } + + return; + } + + Movement *mov = getMovementById(movId); + if (!mov) + return; + + if (x != -1 && y != -1) { + setOXY(x, y); + } + + _statics = mov->_staticsObj1; + + Common::Point point; + + mov->_staticsObj1->getSomeXY(point); + _statics->_x = x - point.x; + _statics->_y = y - point.y; + + _statics->_countdown = _statics->_initialCountdown; + + _flags |= 4; + _ox = x; + _oy = y; + _movement = 0; + + if (mov->_currMovement) + _flags |= 8; + else if (_flags & 8) + _flags ^= 8; + + if (_flags & 1) + _flags ^= 1; + + _messageQueueId = mqId; +} + +void StaticANIObject::show2(int x, int y, int movementId, int mqId) { + warning("STUB: StaticANIObject::show2(%d, %d, %d, %d)", x, y, movementId, mqId); +} + +void StaticANIObject::playIdle() { + if (isIdle()) + adjustSomeXY(); +} + +void StaticANIObject::startAnimSteps(int movementId, int messageQueueId, int x, int y, Common::Point **points, int pointsCount, int someDynamicPhaseIndex) { + warning("STUB: StaticANIObject::startAnimSteps()"); +} + +bool StaticANIObject::startAnimEx(int movid, int parId, int flag1, int flag2) { + bool res = startAnim(movid, parId, -1); + if (res) + _animExFlag = 1; + + _someDynamicPhaseIndex = -1; + return res; +} + +bool StaticANIObject::startAnim(int movementId, int messageQueueId, int dynPhaseIdx) { + if (_flags & 0x80) + return false; + + debug(0, "StaticANIObject::startAnim(%d, %d, %d) (%s [%d]) [%d, %d]", movementId, messageQueueId, dynPhaseIdx, transCyrillic((byte *)_objectName), _id, _ox, _oy); + + if (_messageQueueId) { + updateGlobalMessageQueue(messageQueueId, _id); + return false; + } + + Movement *mov = 0; + + for (uint i = 0; i < _movements.size(); i++) { + + if (((Movement *)_movements[i])->_id == movementId) { + mov = (Movement *)_movements[i]; + break; + } + } + + if (!mov) { + updateGlobalMessageQueue(messageQueueId, _id); + return false; + } + + if (mov == _movement) { + _flags |= 1; + _messageQueueId = messageQueueId; + + return true; + } + + int newx = _ox; + int newy = _oy; + Common::Point point; + + debug(0, "0 %d %d", newx, newy); + if (_movement) { + _movement->getCurrDynamicPhaseXY(point); + + newx -= point.x; + newy -= point.y; + + debug(0, "1 %d %d", newx, newy); + } else if (_statics) { + _statics->getSomeXY(point); + + newx -= point.x; + newy -= point.y; + debug(0, "2 %d %d - %d %d assa", newx, newy, point.x, point.y); + } + + _movement = mov; + + _stepArray.clear(); + + if (_flags & 0x40) + _movement->gotoLastFrame(); + else + _movement->gotoFirstFrame(); + + if (!(_flags & 0x40)) { + if (!_movement->_currDynamicPhaseIndex) { + _stepArray.getCurrPoint(&point); + newx += point.x + _movement->_mx; + newy += point.y + _movement->_my; + + debug(0, "3 %d %d", newx, newy); + _stepArray.gotoNextPoint(); + + ExCommand *ex = _movement->_currDynamicPhase->getExCommand(); + if (ex) { + if (ex->_messageKind == 35) { + ExCommand *newex = new ExCommand(ex); + newex->_excFlags |= 2; + newex->sendMessage(); + } + } + } + } + + _movement->getCurrDynamicPhaseXY(point); + setOXY(point.x + newx, point.y + newy); + + if (_movement->_staticsObj2->_staticsId & 0x4000) + _flags |= 8; + else + _flags &= 0xFFF7; + + _flags |= 1; + + _messageQueueId = messageQueueId; + _movement->_currDynamicPhase->_countdown = _movement->_currDynamicPhase->_initialCountdown; + _movement->_counter = 0; + + _counter = _initialCounter; + _someDynamicPhaseIndex = dynPhaseIdx; + + _stepArray.clear(); + + ExCommand *newex = new ExCommand(_id, 17, 23, 0, 0, movementId, 1, 0, 0, 0); + + newex->_keyCode = _okeyCode; + newex->_excFlags = 2; + + newex->postMessage(); + + return true; +} + +Statics::Statics() { + _staticsId = 0; + _picture = 0; + _staticsName = 0; +} + +Statics::Statics(Statics *src, bool reverse) : DynamicPhase(src, reverse) { + _staticsId = src->_staticsId; + + if (reverse) { + _staticsId ^= 0x4000; + int newlen = strlen(src->_staticsName) + strlen(sO_MirroredTo) + 1; + _staticsName = (char *)calloc(newlen, 1); + + snprintf(_staticsName, newlen, "%s%s", sO_MirroredTo, src->_staticsName); + } else { + _staticsName = (char *)calloc(strlen(src->_staticsName) + 1, 1); + strncpy(_staticsName, src->_staticsName, strlen(src->_staticsName) + 1); + } + + _memfilename = (char *)calloc(strlen(src->_memfilename) + 1, 1); + strncpy(_memfilename, src->_memfilename, strlen(src->_memfilename) + 1); + + _picture = new Picture(); +} + +bool Statics::load(MfcArchive &file) { + debug(5, "Statics::load()"); + + DynamicPhase::load(file); + + _staticsId = file.readUint16LE(); + + _staticsName = file.readPascalString(); + debug(7, "statics: <%s> id: %d (%x)", transCyrillic((byte *)_staticsName), _staticsId, _staticsId); + + _picture = new Picture(); + _picture->load(file); + + return true; +} + +Common::Point *Statics::getSomeXY(Common::Point &p) { + p.x = _someX; + p.y = _someY; + + return &p; +} + +Common::Point *Statics::getCenter(Common::Point *p) { + Common::Rect rect; + + rect = *_rect; + + if (_staticsId & 0x4000) { + Common::Point point; + + getDimensions(&point); + rect.moveTo(point.x - _rect->right, _rect->top); + } + + p->x = rect.left + _rect->width() / 2; + p->y = rect.top + _rect->height() / 2; + + return p; +} + +Movement::Movement() { + _lastFrameSpecialFlag = 0; + _flipFlag = 0; + _updateFlag1 = 0; + _staticsObj1 = 0; + _staticsObj2 = 0; + _mx = 0; + _my = 0; + _m2x = 0; + _m2y = 0; + _field_50 = 1; + _field_78 = 0; + _framePosOffsets = 0; + _field_84 = 0; + _currDynamicPhase = 0; + _field_8C = 0; + _currDynamicPhaseIndex = 0; + _field_94 = 0; + _currMovement = 0; + _counter = 0; + _counterMax = 83; + + _field_24 = 0; + _field_28 = 0; +} + +Movement::Movement(Movement *src, StaticANIObject *ani) { + _lastFrameSpecialFlag = 0; + _flipFlag = src->_flipFlag; + _updateFlag1 = src->_updateFlag1; + _staticsObj1 = 0; + _staticsObj2 = 0; + _mx = 0; + _my = 0; + _m2x = 0; + _m2y = 0; + + _field_78 = 0; + _framePosOffsets = 0; + _field_84 = 0; + _currDynamicPhase = 0; + _field_8C = 0; + _currDynamicPhaseIndex = src->_currDynamicPhaseIndex; + _field_94 = 0; + + _currMovement = src; + _ox = src->_ox; + _oy = src->_oy; + + initStatics(ani); + + _counterMax = src->_counterMax; + _counter = src->_counter; + _field_50 = src->_field_50; + + updateCurrDynamicPhase(); +} + +Movement::Movement(Movement *src, int *flag1, int flag2, StaticANIObject *ani) { + warning("STUB: Movement(src, %p, %d, ani)", (void *)flag1, flag2); +} + +bool Movement::load(MfcArchive &file) { + warning("STUB: Movement::load"); + return true; +} + +bool Movement::load(MfcArchive &file, StaticANIObject *ani) { + GameObject::load(file); + + int dynCount = file.readUint16LE(); + + debug(7, "dynCount: %d _id: %d", dynCount, _id); + if (dynCount != 0xffff || _id == MV_MAN_TURN_LU) { + _framePosOffsets = (Common::Point **)calloc(dynCount + 2, sizeof(Common::Point *)); + + for (int i = 0; i < dynCount + 2; i++) + _framePosOffsets[i] = new Common::Point(); + + for (int i = 0; i < dynCount; i++) { + DynamicPhase *ph = new DynamicPhase(); + ph->load(file); + + _dynamicPhases.push_back(ph); + + _framePosOffsets[i]->x = ph->_x; + _framePosOffsets[i]->y = ph->_y; + } + + int staticsid = file.readUint16LE(); + + _staticsObj1 = ani->getStaticsById(staticsid); + + if (!_staticsObj1 && (staticsid & 0x4000)) { + Statics *s = ani->getStaticsById(staticsid ^ 0x4000); + _staticsObj1 = ani->addReverseStatics(s); + } + + _mx = file.readUint32LE(); + _my = file.readUint32LE(); + + staticsid = file.readUint16LE(); + + _staticsObj2 = ani->getStaticsById(staticsid); + + if (!_staticsObj2 && (staticsid & 0x4000)) { + Statics *s = ani->getStaticsById(staticsid ^ 0x4000); + _staticsObj2 = ani->addReverseStatics(s); + } + + _m2x = file.readUint32LE(); + _m2y = file.readUint32LE(); + + if (_staticsObj2) { + _dynamicPhases.push_back(_staticsObj2); + + _framePosOffsets[_dynamicPhases.size() - 1]->x = _m2x; + _framePosOffsets[_dynamicPhases.size() - 1]->y = _m2y; + } + + } else { + int movid = file.readUint16LE(); + + _currMovement = ani->getMovementById(movid); + _staticsObj1 = 0; + _staticsObj2 = 0; + + initStatics(ani); + } + + if (_staticsObj1 && _staticsObj2) { + if ((_staticsObj1->_staticsId ^ _staticsObj2->_staticsId) & 0x4000) + _flipFlag = 1; + } + + if (g_fullpipe->_gameProjectVersion >= 8) + _field_50 = file.readUint32LE(); + + if (g_fullpipe->_gameProjectVersion < 12) + _counterMax = 83; + else + _counterMax = file.readUint32LE(); + + _counter = 0; + updateCurrDynamicPhase(); + + return true; +} + +Common::Point *Movement::getCurrDynamicPhaseXY(Common::Point &p) { + p.x = _currDynamicPhase->_someX; + p.y = _currDynamicPhase->_someY; + + return &p; +} + +void Movement::setAlpha(int alpha) { + if (_currMovement) + for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { + ((DynamicPhase *)_currMovement->_dynamicPhases[i])->setAlpha(alpha); + } + else + for (uint i = 0; i < _dynamicPhases.size(); i++) { + ((DynamicPhase *)_dynamicPhases[i])->setAlpha(alpha); + } +} + +Common::Point *Movement::getDimensionsOfPhase(Common::Point *p, int phaseIndex) { + int idx = phaseIndex; + + if (idx == -1) + idx = _currDynamicPhaseIndex; + + DynamicPhase *dyn; + + if (_currMovement) + dyn = (DynamicPhase *)_currMovement->_dynamicPhases[idx]; + else + dyn = (DynamicPhase *)_dynamicPhases[idx]; + + Common::Point point; + + dyn->getDimensions(&point); + + *p = point; + + return p; +} + +void Movement::initStatics(StaticANIObject *ani) { + if (!_currMovement) + return; + + debug(7, "Movement::initStatics()"); + + _staticsObj2 = ani->addReverseStatics(_currMovement->_staticsObj2); + _staticsObj1 = ani->addReverseStatics(_currMovement->_staticsObj1); + + _mx = _currMovement->_mx; + _my = _currMovement->_my; + + _currMovement->setDynamicPhaseIndex(_currMovement->_updateFlag1 != 0 ? 1 : 0); + + Common::Point point; + + int x1 = _currMovement->_staticsObj1->getDimensions(&point)->x - _mx; + + _mx = x1 - _currMovement->_currDynamicPhase->getDimensions(&point)->x; + + _currMovement->setDynamicPhaseIndex(_currMovement->_currDynamicPhaseIndex); + + _m2x = _currMovement->_m2x; + _m2y = _currMovement->_m2y; + _currMovement->gotoLastFrame(); + + x1 = _currMovement->_staticsObj2->getDimensions(&point)->x; + _m2x = _currMovement->_currDynamicPhase->getDimensions(&point)->x - _m2x - x1; +} + +void Movement::updateCurrDynamicPhase() { + debug(7, "Movement::updateCurrDynamicPhase()"); + + if (_currMovement) { + if (_currMovement->_dynamicPhases.size() == 0 || (uint)_currDynamicPhaseIndex >= _currMovement->_dynamicPhases.size()) + return; + + if (_currMovement->_dynamicPhases[_currDynamicPhaseIndex]) + _currDynamicPhase = (DynamicPhase *)_currMovement->_dynamicPhases[_currDynamicPhaseIndex]; + } else { + if (_dynamicPhases.size() == 0 || (uint)_currDynamicPhaseIndex >= _dynamicPhases.size()) + return; + + if (_dynamicPhases[_currDynamicPhaseIndex]) + _currDynamicPhase = (DynamicPhase *)_dynamicPhases[_currDynamicPhaseIndex]; + } +} + +int Movement::calcDuration() { + int res = 0; + + if (_currMovement) + for (uint i = 0; i < _currMovement->_dynamicPhases.size(); i++) { + res += ((DynamicPhase *)_currMovement->_dynamicPhases[i])->_initialCountdown; + } + else + for (uint i = 0; i < _dynamicPhases.size(); i++) { + res += ((DynamicPhase *)_dynamicPhases[i])->_initialCountdown; + } + + return res; +} + +void Movement::setDynamicPhaseIndex(int index) { + debug(7, "Movement::setDynamicPhaseIndex(%d)", index); + while (_currDynamicPhaseIndex < index) + gotoNextFrame(0, 0); + + while (_currDynamicPhaseIndex > index) + gotoPrevFrame(); +} + +DynamicPhase *Movement::getDynamicPhaseByIndex(int idx) { + debug(7, "Movement::updateCurrDynamicPhase()"); + + if (_currMovement) { + if (_currMovement->_dynamicPhases.size() == 0 || (uint)idx >= _currMovement->_dynamicPhases.size()) + return 0; + + return (DynamicPhase *)_currMovement->_dynamicPhases[idx]; + } else { + if (_dynamicPhases.size() == 0 || (uint)idx >= _dynamicPhases.size()) + return 0; + + return (DynamicPhase *)_dynamicPhases[idx]; + } +} + +void Movement::loadPixelData() { + Movement *mov = this; + for (Movement *i = _currMovement; i; i = i->_currMovement) + mov = i; + + for (uint i = 0; i < _dynamicPhases.size(); i++) { + if ((Statics *)_dynamicPhases[i] != mov->_staticsObj2 || !(mov->_staticsObj2->_staticsId & 0x4000)) + ((Statics *)_dynamicPhases[i])->getPixelData(); + } + + if (!(mov->_staticsObj1->_staticsId & 0x4000)) + mov->_staticsObj1->getPixelData(); +} + +void Movement::removeFirstPhase() { + if (_updateFlag1) { + if (!_currDynamicPhaseIndex) + gotoNextFrame(0, 0); + + if (!_currMovement) { + _dynamicPhases.remove_at(0); + + for (uint i = 0; i < _dynamicPhases.size(); i++) { + _framePosOffsets[i - 1]->x = _framePosOffsets[i]->x; + _framePosOffsets[i - 1]->y = _framePosOffsets[i]->y; + } + } + _currDynamicPhaseIndex--; + } + + updateCurrDynamicPhase(); + _updateFlag1 = 0; +} + +bool Movement::gotoNextFrame(int callback1, void (*callback2)(int *)) { + debug(8, "Movement::gotoNextFrame()"); + + if (!callback2) { + if (_currMovement) { + if ((uint)_currDynamicPhaseIndex == _currMovement->_dynamicPhases.size() - 1 + && !(((DynamicPhase *)(_currMovement->_dynamicPhases.back()))->_countdown)) { + return false; + } + } else if ((uint)_currDynamicPhaseIndex == _dynamicPhases.size() - 1 + && !(((DynamicPhase *)(_dynamicPhases.back()))->_countdown)) { + return false; + } + } + + if (_currDynamicPhase->_countdown) { + _currDynamicPhase->_countdown--; + return true; + } + + Common::Point point; + + getCurrDynamicPhaseXY(point); + _ox -= point.x; + _oy -= point.y; + + int deltax = 0; + + if (_currMovement) + deltax = _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; + + int oldDynIndex = _currDynamicPhaseIndex; + + if (callback2) + callback2(&_currDynamicPhaseIndex); + else + _currDynamicPhaseIndex++; + + bool result = true; + + if (_currMovement) { + if (_currMovement->_dynamicPhases.size() <= (uint)_currDynamicPhaseIndex) { + _currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; + result = (callback2 == 0); + } + if (_currDynamicPhaseIndex < 0) { + _currDynamicPhaseIndex = 0; + result = false; + } + if (_currMovement->_framePosOffsets) { + if (callback1) { + point = *_currMovement->_framePosOffsets[_currDynamicPhaseIndex]; + //callback1(_currDynamicPhaseIndex, &point, _ox, _oy); + + _ox += deltax - point.x; + _oy += point.y; + + _ox -= _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; + } else if (oldDynIndex >= _currDynamicPhaseIndex) { + while (oldDynIndex > _currDynamicPhaseIndex) { + _ox += deltax; + deltax = _currMovement->getDimensionsOfPhase(&point, oldDynIndex)->x; + + _ox += _currMovement->_framePosOffsets[oldDynIndex]->x; + _oy -= _currMovement->_framePosOffsets[oldDynIndex]->y; + oldDynIndex--; + + _ox -= _currMovement->getDimensionsOfPhase(&point, oldDynIndex)->x; + } + } else { + for (int i = oldDynIndex + 1; i <= _currDynamicPhaseIndex; i++) { + _ox += deltax; + deltax = _currMovement->getDimensionsOfPhase(&point, i)->x; + _ox -= _currMovement->_framePosOffsets[i]->x; + _oy += _currMovement->_framePosOffsets[i]->y; + _ox -= _currMovement->getDimensionsOfPhase(&point, i)->x; + } + } + } + } else { + if (_dynamicPhases.size() <= (uint)_currDynamicPhaseIndex) { + _currDynamicPhaseIndex = _dynamicPhases.size() - 1; + result = (callback2 == 0); + } + if (_currDynamicPhaseIndex < 0) { + _currDynamicPhaseIndex = 0; + result = false; + } + + if (_framePosOffsets) { + if (callback1) { + point.x = _framePosOffsets[_currDynamicPhaseIndex]->x; + point.y = _framePosOffsets[_currDynamicPhaseIndex]->y; + + //callback1(_currDynamicPhaseIndex, &point, _ox, _oy); + _ox += point.x; + _oy += point.y; + } else if (oldDynIndex >= _currDynamicPhaseIndex) { + for (int i = oldDynIndex; i > _currDynamicPhaseIndex; i--) { + _ox -= _framePosOffsets[i]->x; + _oy -= _framePosOffsets[i]->y; + } + } else { + for (int i = oldDynIndex + 1; i <= _currDynamicPhaseIndex; i++) { + _ox += _framePosOffsets[i]->x; + _oy += _framePosOffsets[i]->y; + } + } + } + } + + updateCurrDynamicPhase(); + getCurrDynamicPhaseXY(point); + _ox += point.x; + _oy += point.y; + + _currDynamicPhase->_countdown = _currDynamicPhase->_initialCountdown; + + return result; +} + +bool Movement::gotoPrevFrame() { + debug(8, "Movement::gotoPrevFrame()"); + + if (!_currDynamicPhaseIndex) { + gotoLastFrame(); + return false; + } + + Common::Point point; + + getCurrDynamicPhaseXY(point); + + _ox -= point.x; + _oy -= point.y; + + if (_currMovement) { + if (_currMovement->_framePosOffsets) { + _ox += _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; + _ox += _currMovement->_framePosOffsets[_currDynamicPhaseIndex]->x; + _oy -= _currMovement->_framePosOffsets[_currDynamicPhaseIndex]->y; + } + + _currDynamicPhaseIndex--; + if (_currDynamicPhaseIndex < 0) + _currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; + + _ox -= _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex)->x; + } else { + if (_framePosOffsets) { + _ox -= _framePosOffsets[_currDynamicPhaseIndex]->x; + _oy -= _framePosOffsets[_currDynamicPhaseIndex]->y; + } + + _currDynamicPhaseIndex--; + if (_currDynamicPhaseIndex < 0) + _currDynamicPhaseIndex = _currMovement->_dynamicPhases.size() - 1; + } + + updateCurrDynamicPhase(); + getCurrDynamicPhaseXY(point); + + _ox += point.x; + _oy += point.y; + + return true; +} + +void Movement::gotoFirstFrame() { + while (_currDynamicPhaseIndex) + gotoPrevFrame(); +} + +void Movement::gotoLastFrame() { + if (_currMovement) { + while ((uint)_currDynamicPhaseIndex != _currMovement->_dynamicPhases.size() - 1) + gotoNextFrame(0, 0); + } else { + while ((uint)_currDynamicPhaseIndex != _dynamicPhases.size() - 1) + gotoNextFrame(0, 0); + } +} + +Common::Point *Movement::getCenter(Common::Point *p) { + Common::Rect rect; + + rect = *_currDynamicPhase->_rect; + + if (_currMovement) { + Common::Point point; + + _currMovement->getDimensionsOfPhase(&point, _currDynamicPhaseIndex); + + rect.moveTo(point.x - _currDynamicPhase->_rect->right, _currDynamicPhase->_rect->top); + } + + p->x = rect.left + _currDynamicPhase->_rect->width() / 2; + p->y = rect.top + _currDynamicPhase->_rect->height() / 2; + + return p; +} + +DynamicPhase::DynamicPhase() { + _someX = 0; + _rect = 0; + _field_7C = 0; + _field_7E = 0; + _dynFlags = 0; + _someY = 0; +} + +DynamicPhase::DynamicPhase(DynamicPhase *src, bool reverse) { + _field_7C = src->_field_7C; + _field_7E = 0; + _rect = new Common::Rect(); + + debug(0, "DynamicPhase::DynamicPhase(src, %d)", reverse); + + if (reverse) { + if (!src->_bitmap) + src->init(); + + _bitmap = src->_bitmap->reverseImage(); + _data = _bitmap->_pixels; + _dataSize = src->_dataSize; + + if (g_fullpipe->_currArchive) { + _mfield_14 = 0; + _libHandle = g_fullpipe->_currArchive; + } + + _mflags |= 1; + + _someX = src->_someX; + _someY = src->_someY; + } else { + _mfield_14 = src->_mfield_14; + _mfield_8 = src->_mfield_8; + _mflags = src->_mflags; + + _memfilename = (char *)calloc(strlen(src->_memfilename) + 1, 1); + strncpy(_memfilename, src->_memfilename, strlen(src->_memfilename) + 1); + _dataSize = src->_dataSize; + _mfield_10 = src->_mfield_10; + _libHandle = src->_libHandle; + + _bitmap = src->_bitmap; + if (_bitmap) + _field_54 = 1; + + _someX = src->_someX; + _someY = src->_someY; + } + + *_rect = *src->_rect; + + _width = src->_width; + _height = src->_height; + _field_7C = src->_field_7C; + + if (src->getExCommand()) + _exCommand = new ExCommand(src->getExCommand()); + else + _exCommand = 0; + + _initialCountdown = src->_initialCountdown; + _field_6A = src->_field_6A; + _dynFlags = src->_dynFlags; + + setPaletteData(src->getPaletteData()); + + copyMemoryObject2(src); +} + +bool DynamicPhase::load(MfcArchive &file) { + debug(5, "DynamicPhase::load()"); + + StaticPhase::load(file); + + _field_7C = file.readUint16LE(); + _rect = new Common::Rect(); + _rect->left = file.readUint32LE(); + _rect->top = file.readUint32LE(); + _rect->right = file.readUint32LE(); + _rect->bottom = file.readUint32LE(); + + assert (g_fullpipe->_gameProjectVersion >= 1); + + _someX = file.readUint32LE(); + _someY = file.readUint32LE(); + + assert (g_fullpipe->_gameProjectVersion >= 12); + + _dynFlags = file.readUint32LE(); + + return true; +} + +StaticPhase::StaticPhase() { + _field_6A = 1; + _initialCountdown = 0; + _countdown = 0; + _field_68 = 0; + _exCommand = 0; +} + +bool StaticPhase::load(MfcArchive &file) { + debug(5, "StaticPhase::load()"); + + Picture::load(file); + + _initialCountdown = file.readUint16LE(); + _field_6A = file.readUint16LE(); + + if (g_fullpipe->_gameProjectVersion >= 12) { + _exCommand = (ExCommand *)file.readClass(); + + return true; + } + + assert (g_fullpipe->_gameProjectVersion >= 12); + + return true; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/statics.h b/engines/fullpipe/statics.h new file mode 100644 index 0000000000..3d45ac6623 --- /dev/null +++ b/engines/fullpipe/statics.h @@ -0,0 +1,247 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_STATICS_H +#define FULLPIPE_STATICS_H + +#include "fullpipe/gfx.h" + +namespace Fullpipe { + +class ExCommand; + +class CStepArray : public CObject { + int _currPointIndex; + Common::Point **_points; + int _maxPointIndex; + int _pointsCount; + int _isEos; + + public: + CStepArray(); + ~CStepArray(); + void clear(); + + int getCurrPointIndex() { return _currPointIndex; } + Common::Point *getCurrPoint(Common::Point *point); + bool gotoNextPoint(); +}; + +class StaticPhase : public Picture { + public: + int16 _initialCountdown; + int16 _countdown; + int16 _field_68; + int16 _field_6A; + ExCommand *_exCommand; + + public: + StaticPhase(); + + virtual bool load(MfcArchive &file); + + ExCommand *getExCommand() { return _exCommand; } +}; + +class DynamicPhase : public StaticPhase { + public: + int _someX; + int _someY; + Common::Rect *_rect; + int16 _field_7C; + int16 _field_7E; + int _dynFlags; + + public: + DynamicPhase(); + DynamicPhase(DynamicPhase *src, bool reverse); + + virtual bool load(MfcArchive &file); + + int getDynFlags() { return _dynFlags; } +}; + +class Statics : public DynamicPhase { + public: + int16 _staticsId; + char *_staticsName; + Picture *_picture; + + public: + Statics(); + Statics(Statics *src, bool reverse); + + virtual bool load(MfcArchive &file); + Statics *getStaticsById(int itemId); + + Common::Point *getSomeXY(Common::Point &p); + Common::Point *getCenter(Common::Point *p); +}; + +class StaticANIObject; + +class Movement : public GameObject { + public: + int _field_24; + int _field_28; + int _lastFrameSpecialFlag; + int _flipFlag; + int _updateFlag1; + Statics *_staticsObj1; + Statics *_staticsObj2; + int _mx; + int _my; + int _m2x; + int _m2y; + int _field_50; + int _counterMax; + int _counter; + CPtrList _dynamicPhases; + int _field_78; + Common::Point **_framePosOffsets; + Movement *_currMovement; + int _field_84; + DynamicPhase *_currDynamicPhase; + int _field_8C; + int _currDynamicPhaseIndex; + int _field_94; + + public: + Movement(); + Movement(Movement *src, StaticANIObject *ani); + Movement(Movement *src, int *flag1, int flag2, StaticANIObject *ani); + + virtual bool load(MfcArchive &file); + bool load(MfcArchive &file, StaticANIObject *ani); + + Common::Point *getCurrDynamicPhaseXY(Common::Point &p); + Common::Point *getCenter(Common::Point *p); + Common::Point *getDimensionsOfPhase(Common::Point *p, int phaseIndex); + + void initStatics(StaticANIObject *ani); + void updateCurrDynamicPhase(); + + void setAlpha(int alpha); + + void setDynamicPhaseIndex(int index); + DynamicPhase *getDynamicPhaseByIndex(int idx); + + int calcDuration(); + + void removeFirstPhase(); + bool gotoNextFrame(int callback1, void (*callback2)(int *)); + bool gotoPrevFrame(); + void gotoFirstFrame(); + void gotoLastFrame(); + + void loadPixelData(); + + void draw(bool flipFlag, int angle); +}; + +class StaticANIObject : public GameObject { + public: + Movement *_movement; + Statics *_statics; + int _shadowsOn; + int16 _field_30; + int16 _field_32; + int _field_34; + int _initialCounter; + int _callback1; + void (*_callback2)(int *); + CPtrList _movements; + CPtrList _staticsList; + CStepArray _stepArray; + int16 _field_96; + int _messageQueueId; + int _messageNum; + int _animExFlag; + int _counter; + int _someDynamicPhaseIndex; + + public: + int16 _sceneId; + + public: + StaticANIObject(); + StaticANIObject(StaticANIObject *src); + + virtual bool load(MfcArchive &file); + + void setOXY(int x, int y); + Statics *getStaticsById(int id); + Statics *getStaticsByName(char *name); + Movement *getMovementById(int id); + int getMovementIdById(int itemId); + Movement *getMovementByName(char *name); + Common::Point *getCurrDimensions(Common::Point &p); + + void clearFlags(); + void setFlags40(bool state); + bool isIdle(); + void setAlpha(int alpha); + + void deleteFromGlobalMessageQueue(); + void queueMessageQueue(MessageQueue *msg); + MessageQueue *getMessageQueue(); + bool trySetMessageQueue(int msgNum, int qId); + + void initMovements(); + void loadMovementsPixelData(); + + void setSomeDynamicPhaseIndex(int val) { _someDynamicPhaseIndex = val; } + void adjustSomeXY(); + + bool startAnim(int movementId, int messageQueueId, int dynPhaseIdx); + bool startAnimEx(int movid, int parId, int flag1, int flag2); + void startAnimSteps(int movementId, int messageQueueId, int x, int y, Common::Point **points, int pointsCount, int someDynamicPhaseIndex); + + void hide(); + void show1(int x, int y, int movementId, int mqId); + void show2(int x, int y, int movementId, int mqId); + void playIdle(); + void update(int counterdiff); + + Statics *addReverseStatics(Statics *ani); + void draw(); + void draw2(); + + MovTable *countMovements(); + void setSpeed(int speed); + + void stopAnim_maybe(); + + MessageQueue *changeStatics1(int msgNum); + void changeStatics2(int objId); + + bool getPixelAtPos(int x, int y, int *pixel); +}; + +struct MovTable { + int count; + int16 *movs; +}; + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_STATICS_H */ diff --git a/engines/fullpipe/utils.cpp b/engines/fullpipe/utils.cpp new file mode 100644 index 0000000000..ee73aeaa64 --- /dev/null +++ b/engines/fullpipe/utils.cpp @@ -0,0 +1,484 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#include "fullpipe/fullpipe.h" + +#include "common/file.h" +#include "common/memstream.h" + +#include "fullpipe/objects.h" +#include "fullpipe/motion.h" +#include "fullpipe/ngiarchive.h" +#include "fullpipe/messages.h" +#include "fullpipe/interaction.h" + +namespace Fullpipe { + +bool CObject::loadFile(const char *fname) { + Common::File file; + + if (!file.open(fname)) + return false; + + MfcArchive archive(&file); + + return load(archive); +} + +bool CObList::load(MfcArchive &file) { + debug(5, "CObList::load()"); + int count = file.readCount(); + + debug(9, "CObList::count: %d:", count); + + for (int i = 0; i < count; i++) { + debug(9, "CObList::[%d]", i); + CObject *t = file.readClass(); + + push_back(t); + } + + return true; +} + +bool CObArray::load(MfcArchive &file) { + debug(5, "CObArray::load()"); + int count = file.readCount(); + + resize(count); + + for (int i = 0; i < count; i++) { + CObject *t = file.readClass(); + + push_back(*t); + } + + return true; +} + +bool CDWordArray::load(MfcArchive &file) { + debug(5, "CWordArray::load()"); + int count = file.readCount(); + + debug(9, "CDWordArray::count: %d", count); + + resize(count); + + for (int i = 0; i < count; i++) { + int32 t = file.readUint32LE(); + + push_back(t); + } + + return true; +} + +char *MfcArchive::readPascalString(bool twoByte) { + char *tmp; + int len; + + if (twoByte) + len = readUint16LE(); + else + len = readByte(); + + tmp = (char *)calloc(len + 1, 1); + read(tmp, len); + + debug(9, "readPascalString: %d <%s>", len, transCyrillic((byte *)tmp)); + + return tmp; +} + +MemoryObject::MemoryObject() { + _memfilename = 0; + _mfield_8 = 0; + _mfield_C = 0; + _mfield_10 = -1; + _mfield_14 = 1; + _dataSize = 0; + _mflags = 0; + _libHandle = 0; + _data = 0; +} + +MemoryObject::~MemoryObject() { + freeData(); + if (_memfilename) + free(_memfilename); +} + +bool MemoryObject::load(MfcArchive &file) { + debug(5, "MemoryObject::load()"); + _memfilename = file.readPascalString(); + + if (char *p = strchr(_memfilename, '\\')) { + for (char *d = _memfilename; *p;) { + p++; + *d++ = *p; + } + } + + if (g_fullpipe->_currArchive) { + _mfield_14 = 0; + _libHandle = g_fullpipe->_currArchive; + } + + return true; +} + +void MemoryObject::loadFile(char *filename) { + debug(5, "MemoryObject::loadFile(<%s>)", filename); + if (!_data) { + Common::SeekableReadStream *s = g_fullpipe->_currArchive->createReadStreamForMember(filename); + + if (s) { + assert(s->size() > 0); + + _dataSize = s->size(); + + debug(5, "Loading %s (%d bytes)", filename, _dataSize); + _data = (byte *)calloc(_dataSize, 1); + s->read(_data, _dataSize); + + delete s; + } + } +} + +byte *MemoryObject::getData() { + load(); + + if (_mfield_14 || _mflags & 1) { + return _data; + } else { + error("Unhandled packed data"); + } +} + +byte *MemoryObject::loadData() { + load(); + return _data; +} + +void MemoryObject::freeData() { + if (_data) + free(_data); + + _data = 0; +} + +bool MemoryObject::testFlags() { + if (_mfield_8) + return false; + + if (_mflags & 1) + return true; + + return false; +} + +MemoryObject2::MemoryObject2() { + _rows = 0; +} + +MemoryObject2::~MemoryObject2() { + if (_rows) + free(_rows); +} + +bool MemoryObject2::load(MfcArchive &file) { + debug(5, "MemoryObject2::load()"); + MemoryObject::load(file); + + _mflags |= 1; + + debug(5, "MemoryObject2::load: <%s>", _memfilename); + + if (_memfilename && *_memfilename) { + MemoryObject::loadFile(_memfilename); + } + + return true; +} + +void MemoryObject2::copyData(byte *src, int dataSize) { + if (_data) + freeData(); + + _dataSize = dataSize; + _data = (byte *)malloc(dataSize); + + memcpy(_data, src, _dataSize); +} + +int MfcArchive::readCount() { + int count = readUint16LE(); + + if (count == 0xffff) + count = readUint32LE(); + + return count; +} + +double MfcArchive::readDouble() { + // FIXME: This is utterly cruel and unportable + // Some articles on the matter: + // http://randomascii.wordpress.com/2013/02/07/float-precision-revisited-nine-digit-float-portability/ + // http://randomascii.wordpress.com/2012/01/11/tricks-with-the-floating-point-format/ + + union { + struct { + int32 a; + int32 b; + } i; + double d; + } tmp; + + tmp.i.a = readUint32LE(); + tmp.i.b = readUint32LE(); + + return tmp.d; +} + +enum { + kNullObject, + kCInteraction, + kMessageQueue, + kExCommand, + kCObjstateCommand, + kCGameVar, + kCMctlCompound, + kCMovGraph, + kCMovGraphLink, + kCMovGraphNode, + kCReactParallel, + kCReactPolygonal +}; + +const struct { + const char *name; + int id; +} classMap[] = { + { "CInteraction", kCInteraction }, + { "MessageQueue", kMessageQueue }, + { "ExCommand", kExCommand }, + { "CObjstateCommand", kCObjstateCommand }, + { "CGameVar", kCGameVar }, + { "CMctlCompound", kCMctlCompound }, + { "CMovGraph", kCMovGraph }, + { "CMovGraphLink", kCMovGraphLink }, + { "CMovGraphNode", kCMovGraphNode }, + { "CReactParallel", kCReactParallel }, + { "CReactPolygonal", kCReactPolygonal }, + { 0, 0 } +}; + +static const char *lookupObjectId(int id) { + for (int i = 0; classMap[i].name; i++) { + if (classMap[i].id == id) + return classMap[i].name; + } + + return ""; +} + +static CObject *createObject(int objectId) { + switch (objectId) { + case kNullObject: + return 0; + case kCInteraction: + return new CInteraction(); + case kMessageQueue: + return new MessageQueue(); + case kExCommand: + return new ExCommand(); + case kCObjstateCommand: + return new CObjstateCommand(); + case kCGameVar: + return new CGameVar(); + case kCMctlCompound: + return new CMctlCompound(); + case kCMovGraph: + return new CMovGraph(); + case kCMovGraphLink: + return new CMovGraphLink(); + case kCMovGraphNode: + return new CMovGraphNode(); + case kCReactParallel: + return new CReactParallel(); + case kCReactPolygonal: + return new CReactPolygonal(); + default: + error("Unknown objectId: %d", objectId); + } + + return 0; +} + +MfcArchive::MfcArchive(Common::SeekableReadStream *stream) { + for (int i = 0; classMap[i].name; i++) { + _classMap[classMap[i].name] = classMap[i].id; + } + + _lastIndex = 1; + _level = 0; + + _stream = stream; + + _objectMap.push_back(0); + _objectIdMap.push_back(kNullObject); +} + +CObject *MfcArchive::readClass() { + bool isCopyReturned; + CObject *res = parseClass(&isCopyReturned); + + if (res && !isCopyReturned) + res->load(*this); + + return res; +} + +CObject *MfcArchive::parseClass(bool *isCopyReturned) { + char *name; + int objectId = 0; + CObject *res = 0; + + uint obTag = readUint16LE(); + + debug(7, "parseClass::obTag = %d (%04x) at 0x%08x", obTag, obTag, pos() - 2); + + if (obTag == 0xffff) { + int schema = readUint16LE(); + + debug(7, "parseClass::schema = %d", schema); + + name = readPascalString(true); + debug(7, "parseClass::class <%s>", name); + + if (!_classMap.contains(name)) { + error("Unknown class in MfcArchive: <%s>", name); + } + + objectId = _classMap[name]; + + debug(7, "tag: %d 0x%x (%x)", _objectMap.size() - 1, _objectMap.size() - 1, objectId); + + res = createObject(objectId); + _objectMap.push_back(res); + _objectIdMap.push_back(objectId); + + _objectMap.push_back(res); // Basically a hack, but behavior is all correct + _objectIdMap.push_back(objectId); + + *isCopyReturned = false; + } else if ((obTag & 0x8000) == 0) { + if (_objectMap.size() < obTag) { + error("Object index too big: %d at 0x%08x", obTag, pos() - 2); + } + res = _objectMap[obTag]; + + *isCopyReturned = true; + } else { + + obTag &= ~0x8000; + + if (_objectMap.size() < obTag) { + error("Object index too big: %d at 0x%08x", obTag, pos() - 2); + } + + debug(7, "parseClass::obTag <%s>", lookupObjectId(_objectIdMap[obTag])); + + objectId = _objectIdMap[obTag]; + + res = createObject(objectId); + _objectMap.push_back(res); + _objectIdMap.push_back(objectId); + + *isCopyReturned = false; + } + + return res; +} + +char *genFileName(int superId, int sceneId, const char *ext) { + char *s = (char *)calloc(256, 1); + + if (superId) { + snprintf(s, 255, "%04d%04d.%s", superId, sceneId, ext); + } else { + snprintf(s, 255, "%04d.%s", sceneId, ext); + } + + debug(7, "genFileName: %s", s); + + return s; +} + +// Translates cp-1251..utf-8 +byte *transCyrillic(byte *s) { + static byte tmp[1024]; + + static int trans[] = { 0xa8, 0xd081, 0xb8, 0xd191, 0xc0, 0xd090, + 0xc1, 0xd091, 0xc2, 0xd092, 0xc3, 0xd093, 0xc4, 0xd094, + 0xc5, 0xd095, 0xc6, 0xd096, 0xc7, 0xd097, 0xc8, 0xd098, + 0xc9, 0xd099, 0xca, 0xd09a, 0xcb, 0xd09b, 0xcc, 0xd09c, + 0xcd, 0xd09d, 0xce, 0xd09e, 0xcf, 0xd09f, 0xd0, 0xd0a0, + 0xd1, 0xd0a1, 0xd2, 0xd0a2, 0xd3, 0xd0a3, 0xd4, 0xd0a4, + 0xd5, 0xd0a5, 0xd6, 0xd0a6, 0xd7, 0xd0a7, 0xd8, 0xd0a8, + 0xd9, 0xd0a9, 0xda, 0xd0aa, 0xdb, 0xd0ab, 0xdc, 0xd0ac, + 0xdd, 0xd0ad, 0xde, 0xd0ae, 0xdf, 0xd0af, 0xe0, 0xd0b0, + 0xe1, 0xd0b1, 0xe2, 0xd0b2, 0xe3, 0xd0b3, 0xe4, 0xd0b4, + 0xe5, 0xd0b5, 0xe6, 0xd0b6, 0xe7, 0xd0b7, 0xe8, 0xd0b8, + 0xe9, 0xd0b9, 0xea, 0xd0ba, 0xeb, 0xd0bb, 0xec, 0xd0bc, + 0xed, 0xd0bd, 0xee, 0xd0be, 0xef, 0xd0bf, 0xf0, 0xd180, + 0xf1, 0xd181, 0xf2, 0xd182, 0xf3, 0xd183, 0xf4, 0xd184, + 0xf5, 0xd185, 0xf6, 0xd186, 0xf7, 0xd187, 0xf8, 0xd188, + 0xf9, 0xd189, 0xfa, 0xd18a, 0xfb, 0xd18b, 0xfc, 0xd18c, + 0xfd, 0xd18d, 0xfe, 0xd18e, 0xff, 0xd18f }; + + int i = 0; + + for (byte *p = s; *p; p++) { + if (*p < 128) { + tmp[i++] = *p; + } else { + int j; + for (j = 0; trans[j]; j += 2) { + if (trans[j] == *p) { + tmp[i++] = (trans[j + 1] >> 8) & 0xff; + tmp[i++] = trans[j + 1] & 0xff; + break; + } + } + + assert(trans[j]); + } + } + + tmp[i] = 0; + + return tmp; +} + +} // End of namespace Fullpipe diff --git a/engines/fullpipe/utils.h b/engines/fullpipe/utils.h new file mode 100644 index 0000000000..76a1ae944c --- /dev/null +++ b/engines/fullpipe/utils.h @@ -0,0 +1,154 @@ +/* ScummVM - Graphic Adventure Engine + * + * ScummVM is the legal property of its developers, whose names + * are too numerous to list here. Please refer to the COPYRIGHT + * file distributed with this source distribution. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * + */ + +#ifndef FULLPIPE_UTILS_H +#define FULLPIPE_UTILS_H + +#include "common/hash-str.h" +#include "common/array.h" +#include "common/file.h" + +namespace Fullpipe { + +class CObject; +class NGIArchive; + +typedef Common::HashMap<Common::String, int, Common::IgnoreCase_Hash, Common::IgnoreCase_EqualTo> ClassMap; + +class MfcArchive : public Common::SeekableReadStream { + ClassMap _classMap; + Common::Array<CObject *> _objectMap; + Common::Array<int> _objectIdMap; + + int _lastIndex; + int _level; + + Common::SeekableReadStream *_stream; + + public: + MfcArchive(Common::SeekableReadStream *file); + + char *readPascalString(bool twoByte = false); + int readCount(); + double readDouble(); + CObject *parseClass(bool *isCopyReturned); + CObject *readClass(); + + void incLevel() { _level++; } + void decLevel() { _level--; } + int getLevel() { return _level; } + + virtual bool eos() const { return _stream->eos(); } + virtual uint32 read(void *dataPtr, uint32 dataSize) { return _stream->read(dataPtr, dataSize); } + virtual int32 pos() const { return _stream->pos(); } + virtual int32 size() const { return _stream->size(); } + virtual bool seek(int32 offset, int whence = SEEK_SET) { return _stream->seek(offset, whence); } +}; + +enum ObjType { + kObjTypeDefault, + kObjTypeObjstateCommand, + kObjTypeStaticANIObject, + kObjTypePictureObject +}; + +class CObject { + public: + ObjType _objtype; + + CObject() : _objtype(kObjTypeDefault) {} + virtual bool load(MfcArchive &in) { return true; } + virtual ~CObject() {} + + bool loadFile(const char *fname); +}; + +class CObList : public Common::List<CObject *>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class MemoryObject : CObject { + friend class Picture; + friend class Scene; + + protected: + char *_memfilename; + int _mfield_8; + int _mfield_C; + int _mfield_10; + char _mfield_14; + char _mfield_15; + char _mfield_16; + char _mfield_17; + byte *_data; + int _dataSize; + int _mflags; + NGIArchive *_libHandle; + + public: + MemoryObject(); + virtual ~MemoryObject(); + + virtual bool load(MfcArchive &file); + void loadFile(char *filename); + void load() { loadFile(_memfilename); } + byte *getData(); + byte *loadData(); + + bool testFlags(); + + void freeData(); +}; + +class MemoryObject2 : public MemoryObject { + friend class Picture; + + protected: + byte **_rows; + + public: + MemoryObject2(); + virtual ~MemoryObject2(); + virtual bool load(MfcArchive &file); + + void copyData(byte *src, int dataSize); +}; + +class CObArray : public Common::Array<CObject>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +class CDWordArray : public Common::Array<int32>, public CObject { + public: + virtual bool load(MfcArchive &file); +}; + +typedef Common::Array<void *> CPtrList; + +char *genFileName(int superId, int sceneId, const char *ext); +byte *transCyrillic(byte *s); + +} // End of namespace Fullpipe + +#endif /* FULLPIPE_UTILS_H */ diff --git a/engines/kyra/text_rpg.cpp b/engines/kyra/text_rpg.cpp index a19d678e35..24c523c856 100644 --- a/engines/kyra/text_rpg.cpp +++ b/engines/kyra/text_rpg.cpp @@ -129,7 +129,7 @@ void TextDisplayer_rpg::displayText(char *str, ...) { uint16 charsPerLine = (sd->w << 3) / (_screen->getFontWidth() + _screen->_charWidth); while (c) { - char a = tolower(_ctrl[1]); + char a = tolower((unsigned char)_ctrl[1]); if (!_tempString2 && c == '%') { if (a == 'd') { diff --git a/engines/lastexpress/data/scene.h b/engines/lastexpress/data/scene.h index 69a1417459..b99e56a74c 100644 --- a/engines/lastexpress/data/scene.h +++ b/engines/lastexpress/data/scene.h @@ -83,6 +83,7 @@ class Scene; class SceneHotspot { public: enum Action { + kActionNone = 0, kActionInventory = 1, kActionSavePoint = 2, kActionPlaySound = 3, @@ -152,8 +153,19 @@ public: byte cursor; uint32 next; - SceneHotspot() {} + SceneHotspot() { + coordsOffset = 0; + scene = kSceneNone; + location = 0; + action = kActionNone; + param1 = 0; + param2 = 0; + param3 = 0; + cursor = 0; + next = 0; + } ~SceneHotspot(); + static SceneHotspot *load(Common::SeekableReadStream *stream); bool isInside(const Common::Point &point); diff --git a/engines/lastexpress/debug.cpp b/engines/lastexpress/debug.cpp index db3a3e3962..7c83aff93d 100644 --- a/engines/lastexpress/debug.cpp +++ b/engines/lastexpress/debug.cpp @@ -487,7 +487,9 @@ bool Debugger::cmdPlaySeq(int argc, const char **argv) { // Handle right-click to interrupt sequence Common::Event ev; - _engine->getEventManager()->pollEvent(ev); + if (!_engine->getEventManager()->pollEvent(ev)) + break; + if (ev.type == Common::EVENT_RBUTTONUP) break; @@ -596,7 +598,9 @@ bool Debugger::cmdPlaySbe(int argc, const char **argv) { // Handle right-click to interrupt sequence Common::Event ev; - _engine->getEventManager()->pollEvent(ev); + if (!_engine->getEventManager()->pollEvent(ev)) + break; + if (ev.type == Common::EVENT_RBUTTONUP) break; diff --git a/engines/lastexpress/game/scenes.cpp b/engines/lastexpress/game/scenes.cpp index a2c7226b93..82688fff2e 100644 --- a/engines/lastexpress/game/scenes.cpp +++ b/engines/lastexpress/game/scenes.cpp @@ -587,8 +587,8 @@ void SceneManager::updateDoorsAndClock() { Common::String name = Common::String::format("633X%c-%02d.seq", (index - firstIndex) + 65, scene->position); Sequence *sequence = loadSequence1(name, 255); - // If the sequence doesn't exists, skip - if (!sequence || !sequence->isLoaded()) + // If the sequence doesn't exists or could not be loaded, skip index + if (!sequence) continue; // Adjust frame data and store in frame list diff --git a/engines/lastexpress/game/state.h b/engines/lastexpress/game/state.h index 2c484f6976..944f6d47b1 100644 --- a/engines/lastexpress/game/state.h +++ b/engines/lastexpress/game/state.h @@ -502,6 +502,7 @@ public: volume = _defaultVolume; //Game data + field_0 = 0; time = kTimeCityParis; timeDelta = _defaultTimeDelta; timeTicks = 0; diff --git a/engines/lastexpress/lastexpress.cpp b/engines/lastexpress/lastexpress.cpp index 01d2634dec..bc1624d171 100644 --- a/engines/lastexpress/lastexpress.cpp +++ b/engines/lastexpress/lastexpress.cpp @@ -165,10 +165,10 @@ Common::Error LastExpressEngine::run() { void LastExpressEngine::pollEvents() { Common::Event ev; - _eventMan->pollEvent(ev); + if (!_eventMan->pollEvent(ev)) + return; switch (ev.type) { - case Common::EVENT_LBUTTONUP: getGameLogic()->getGameState()->getGameFlags()->mouseLeftClick = true; break; 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 c06f19dadc..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; @@ -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) @@ -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 8e2eab52b8..ee9cb40c99 100644 --- a/engines/mortevielle/detection.cpp +++ b/engines/mortevielle/detection.cpp @@ -30,6 +30,7 @@ namespace Mortevielle { struct MortevielleGameDescription { ADGameDescription desc; Common::Language originalLanguage; + uint8 dataFeature; }; uint32 MortevielleEngine::getGameFlags() const { return _gameDescription->desc.flags; } @@ -38,6 +39,8 @@ Common::Language MortevielleEngine::getLanguage() const { return _gameDescriptio Common::Language MortevielleEngine::getOriginalLanguage() const { return _gameDescription->originalLanguage; } +bool MortevielleEngine::useOriginalData() const { return _gameDescription->dataFeature == kUseOriginalData; } + } static const PlainGameDescriptor MortevielleGame[] = { @@ -53,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 a7bd381603..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); @@ -164,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); } diff --git a/engines/mortevielle/dialogs.h b/engines/mortevielle/dialogs.h index ee210a62b2..3f30851960 100644 --- a/engines/mortevielle/dialogs.h +++ b/engines/mortevielle/dialogs.h @@ -52,7 +52,7 @@ private: 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/menu.cpp b/engines/mortevielle/menu.cpp index 1077f66fc2..641a527c98 100644 --- a/engines/mortevielle/menu.cpp +++ b/engines/mortevielle/menu.cpp @@ -168,17 +168,23 @@ void Menu::setText(MenuItem item, Common::String name) { _inventoryStringArray[item._actionId].insertChar(' ', 0); } break; - case MENU_MOVE: + 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: { // If the first character isn't '*' or ' ' then it's missing a heading space char c = s[0]; if (c != '*' && c != ' ') - s = ' ' + s; + s.insertChar(' ', 0); while (s.size() < 10) s += ' '; @@ -190,7 +196,7 @@ void Menu::setText(MenuItem item, Common::String name) { // If the first character isn't '*' or ' ' then it's missing a heading space char c = s[0]; if (c != '*' && c != ' ') - s = ' ' + s; + s.insertChar(' ', 0); while (s.size() < 10) s += ' '; @@ -591,12 +597,30 @@ void Menu::setParent(MortevielleEngine *vm) { 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); @@ -611,12 +635,20 @@ void Menu::initMenu() { 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 @@ -626,12 +658,13 @@ void Menu::initMenu() { } // 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 (!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"); @@ -639,7 +672,7 @@ void Menu::initMenu() { if (!f.open("menual.mor")) error("Missing file - menual.mor"); } - f.read(_charArr, 7 * 24); + f.read(_charArr, 6 * 24); f.close(); } @@ -652,13 +685,16 @@ void Menu::initMenu() { _moveStringArray[i] = "* "; 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] += ' '; } diff --git a/engines/mortevielle/menu.h b/engines/mortevielle/menu.h index d1271bca2e..debf5b09b6 100644 --- a/engines/mortevielle/menu.h +++ b/engines/mortevielle/menu.h @@ -51,7 +51,7 @@ class Menu { private: MortevielleEngine *_vm; - byte _charArr[7][24]; + byte _charArr[6][24]; int _msg3; int _msg4; diff --git a/engines/mortevielle/mortevielle.cpp b/engines/mortevielle/mortevielle.cpp index 7748ce9371..d434150977 100644 --- a/engines/mortevielle/mortevielle.cpp +++ b/engines/mortevielle/mortevielle.cpp @@ -63,6 +63,7 @@ MortevielleEngine::MortevielleEngine(OSystem *system, const MortevielleGameDescr _mouseClick = false; _inMainGameLoop = false; _quitGame = false; + _pauseStartTime = -1; _roomPresenceLuc = false; _roomPresenceIda = false; @@ -165,6 +166,25 @@ Common::String MortevielleEngine::generateSaveFilename(const Common::String &tar } /** + * Pause the game. + */ +void MortevielleEngine::pauseEngineIntern(bool pause) { + Engine::pauseEngineIntern(pause); + if (pause) { + if (_pauseStartTime == -1) + _pauseStartTime = readclock(); + } else { + if (_pauseStartTime != -1) { + int pauseEndTime = readclock(); + _currentTime += (pauseEndTime - _pauseStartTime); + if (_uptodatePresence) + _startTime += (pauseEndTime - _pauseStartTime); + } + _pauseStartTime = -1; + } +} + +/** * Initialize the game state */ Common::ErrorCode MortevielleEngine::initialize() { @@ -347,13 +367,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(); + resetVariables(); if (loadSlot != 0) _savegameManager.loadSavegame(generateSaveFilename(loadSlot)); - else - resetVariables(); // Run the main game loop mainGame(); diff --git a/engines/mortevielle/mortevielle.h b/engines/mortevielle/mortevielle.h index 4c9e57acd1..5ae94987a0 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, @@ -209,8 +214,8 @@ private: int _minute; int _curSearchObjId; int _controlMenu; - int _startHour; - int _endHour; + int _startTime; + int _endTime; Common::Point _stdPal[91][17]; int _x26KeyCount; @@ -224,7 +229,8 @@ private: int _x; int _y; int _currentHourCount; - int _currentDayHour; + int _currentTime; + int _pauseStartTime; Common::String _hintPctMessage; byte *_cfiecBuffer; @@ -441,9 +447,12 @@ public: virtual Common::Error loadGameState(int slot); virtual Common::Error saveGameState(int slot, const Common::String &desc); virtual Common::Error run(); + virtual void pauseEngineIntern(bool pause); + virtual GUI::Debugger *getDebugger() {return &_debugger;} 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/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 f138dde5c5..7809143176 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 @@ -290,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))) { @@ -412,8 +413,8 @@ void MortevielleEngine::prepareScreenType3() { * @remarks Originally called 'calch' */ void MortevielleEngine::updateHour(int &day, int &hour, int &minute) { - int newHour = readclock(); - int th = _currentHourCount + ((newHour - _currentDayHour) / _inGameHourDuration); + int newTime = readclock(); + int th = _currentHourCount + ((newTime - _currentTime) / _inGameHourDuration); minute = ((th % 2) + _currHalfHour) * 30; hour = ((uint)th >> 1) + _currHour; if (minute == 60) { @@ -1081,7 +1082,7 @@ void MortevielleEngine::initGame() { if (!_coreVar._alreadyEnteredManor) _blo = true; _inGameHourDuration = kTime1; - _currentDayHour = readclock(); + _currentTime = readclock(); } /** @@ -1334,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; @@ -1464,8 +1465,8 @@ void MortevielleEngine::gameLoaded() { _x = 0; _y = 0; _num = 0; - _startHour = 0; - _endHour = 0; + _startTime = 0; + _endTime = 0; _searchCount = 0; _roomDoorId = OWN_ROOM; _syn = true; @@ -1712,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)); } /** @@ -1993,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; } @@ -2155,12 +2156,7 @@ void MortevielleEngine::drawRightFrame() { * Read the current system time */ int MortevielleEngine::readclock() { - TimeDate dateTime; - g_system->getTimeAndDate(dateTime); - - int m = dateTime.tm_min * 60; - int h = dateTime.tm_hour * 3600; - return h + m + dateTime.tm_sec; + return (int)(g_system->getMillis() / 1000); } /** @@ -2223,12 +2219,12 @@ void MortevielleEngine::prepareRoom() { if (_coreVar._faithScore > 65) _inGameHourDuration -= ((_inGameHourDuration / 3) * 2); - int newHour = readclock(); - if ((newHour - _currentDayHour) > _inGameHourDuration) { + int newTime = readclock(); + if ((newTime - _currentTime) > _inGameHourDuration) { bool activeMenu = _menu._menuActive; _menu.eraseMenu(); - _currentHourCount += ((newHour - _currentDayHour) / _inGameHourDuration); - _currentDayHour = newHour; + _currentHourCount += ((newTime - _currentTime) / _inGameHourDuration); + _currentTime = newTime; switch (_place) { case GREEN_ROOM: case DARKBLUE_ROOM: @@ -2278,7 +2274,7 @@ void MortevielleEngine::prepareRoom() { _currBitIndex = 0; if (!_uptodatePresence) { _uptodatePresence = true; - _startHour = readclock(); + _startTime = readclock(); if (getRandomNumber(1, 5) < 5) { clearVerbBar(); prepareScreenType2(); @@ -2296,11 +2292,11 @@ void MortevielleEngine::prepareRoom() { _menu.drawMenu(); } } - _endHour = readclock(); - if ((_uptodatePresence) && ((_endHour - _startHour) > 17)) { + _endTime = readclock(); + if ((_uptodatePresence) && ((_endTime - _startTime) > 17)) { getPresenceBitIndex(_place); _uptodatePresence = false; - _startHour = 0; + _startTime = 0; if ((_coreVar._currPlace > OWN_ROOM) && (_coreVar._currPlace < DINING_ROOM)) _anyone = true; } @@ -2498,7 +2494,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] = '*'; @@ -2775,34 +2771,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; } } @@ -2866,18 +2882,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) @@ -3190,7 +3215,7 @@ void MortevielleEngine::displayStatusArrow() { } 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') diff --git a/engines/plugins_table.h b/engines/plugins_table.h index d1519c367f..ca2fe3fa5b 100644 --- a/engines/plugins_table.h +++ b/engines/plugins_table.h @@ -32,6 +32,9 @@ LINK_PLUGIN(DRASCULA) #if PLUGIN_ENABLED_STATIC(DREAMWEB) LINK_PLUGIN(DREAMWEB) #endif +#if PLUGIN_ENABLED_STATIC(FULLPIPE) +LINK_PLUGIN(FULLPIPE) +#endif #if PLUGIN_ENABLED_STATIC(GOB) LINK_PLUGIN(GOB) #endif 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..154ac8f8b4 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 @@ -50,6 +51,7 @@ const SciWorkaroundEntry arithmeticWorkarounds[] = { // gameID, room,script,lvl, object-name, method-name, call,index, workaround const SciWorkaroundEntry uninitializedReadWorkarounds[] = { + { GID_CAMELOT, 40, 40, 0, "Rm40", "handleEvent", -1, 0, { WORKAROUND_FAKE, 0 } }, // when looking at the ground at the pool of Siloam - bug #3614968 { GID_CASTLEBRAIN, 280, 280, 0, "programmer", "dispatchEvent", -1, 0, { WORKAROUND_FAKE, 0xf } }, // pressing 'q' on the computer screen in the robot room, and closing the help dialog that pops up (bug #3039656). Moves the cursor to the view with the ID returned (in this case, the robot hand) { GID_CNICK_KQ, -1, 0, 1, "Character", "say", -1, -1, { WORKAROUND_FAKE, 0 } }, // checkers/backgammon, like in hoyle 3 - temps 504 and 505 - bug #3606025 { GID_CNICK_KQ, -1, 700, 0, "gcWindow", "open", -1, -1, { WORKAROUND_FAKE, 0 } }, // when entering the control menu, like in hoyle 3 @@ -74,9 +76,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/gfx.cpp b/engines/scumm/gfx.cpp index 4d65ccc88a..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,6 +1884,12 @@ 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 + 4); if (stripnr * 4 + 8 < smapLen) diff --git a/engines/sword25/gfx/microtiles.cpp b/engines/sword25/gfx/microtiles.cpp index 8dceed5348..18e4a9a1fb 100644 --- a/engines/sword25/gfx/microtiles.cpp +++ b/engines/sword25/gfx/microtiles.cpp @@ -119,7 +119,6 @@ RectangleList *MicroTileArray::getRectangles() { for (y = 0; y < _tilesH; ++y) { for (x = 0; x < _tilesW; ++x) { - int start; int finish = 0; BoundingBox boundingBox = _tiles[i]; @@ -132,8 +131,6 @@ RectangleList *MicroTileArray::getRectangles() { y0 = (y * TileSize) + TileY0(boundingBox); y1 = (y * TileSize) + TileY1(boundingBox); - start = i; - if (TileX1(boundingBox) == TileSize - 1 && x != _tilesW - 1) { // check if the tile continues while (!finish) { ++x; 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/toltecs/detection.cpp b/engines/toltecs/detection.cpp index c5652f0c8d..380f4a3a26 100644 --- a/engines/toltecs/detection.cpp +++ b/engines/toltecs/detection.cpp @@ -73,6 +73,20 @@ static const ToltecsGameDescription gameDescriptions[] = { }, { + // 3 Skulls of the Toltecs English version (alternate) + // From bug #3614933 + { + "toltecs", + 0, + AD_ENTRY1s("WESTERN", "a9c9cfef9d05b8f7a5573b626fa4ea87", 337643527), + Common::EN_ANY, + Common::kPlatformDOS, + ADGF_NO_FLAGS, + GUIO1(GUIO_NONE) + }, + }, + + { // 3 Skulls of the Toltecs Russian version { "toltecs", diff --git a/engines/tsage/blue_force/blueforce_logic.cpp b/engines/tsage/blue_force/blueforce_logic.cpp index 3aef18f4f0..63f84d25e1 100644 --- a/engines/tsage/blue_force/blueforce_logic.cpp +++ b/engines/tsage/blue_force/blueforce_logic.cpp @@ -678,7 +678,7 @@ void FocusObject::process(Event &event) { BF_GLOBALS._events.setCursor(BF_GLOBALS._events.getCursor()); if ((event.eventType == EVENT_BUTTON_DOWN) && (BF_GLOBALS._events.getCursor() == CURSOR_WALK) && - (event.btnState == 3)) { + (event.btnState == BTNSHIFT_RIGHT)) { BF_GLOBALS._events.setCursor(CURSOR_USE); event.handled = true; } 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..d26e34ae23 100644 --- a/engines/tsage/blue_force/blueforce_scenes1.cpp +++ b/engines/tsage/blue_force/blueforce_scenes1.cpp @@ -2649,7 +2649,7 @@ void Scene160::Action2::signal() { } void Scene160::Action2::process(Event &event) { - if ((event.handled) || (event.eventType == 5)) + if ((event.handled) || ((event.eventType != EVENT_BUTTON_DOWN) && (event.eventType != EVENT_KEYPRESS))) return; if (_actionIndex == 25) { @@ -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..0cf487daa9 100644 --- a/engines/tsage/blue_force/blueforce_scenes5.cpp +++ b/engines/tsage/blue_force/blueforce_scenes5.cpp @@ -1220,7 +1220,7 @@ void Scene560::SafeInset::process(Event &event) { } if ((event.eventType == EVENT_BUTTON_DOWN) && (BF_GLOBALS._events.getCursor() == CURSOR_WALK) && - (event.btnState == 3)) { + (event.btnState == BTNSHIFT_RIGHT)) { BF_GLOBALS._events.setCursor(CURSOR_USE); event.handled = true; } @@ -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/blue_force/blueforce_scenes8.cpp b/engines/tsage/blue_force/blueforce_scenes8.cpp index 5a60cd7c5e..9a20788b6a 100644 --- a/engines/tsage/blue_force/blueforce_scenes8.cpp +++ b/engines/tsage/blue_force/blueforce_scenes8.cpp @@ -1984,7 +1984,7 @@ void Scene840::BoatKeysInset::process(Event &event) { CursorType cursorId = BF_GLOBALS._events.getCursor(); BF_GLOBALS._events.setCursor(cursorId); - if ((event.eventType == EVENT_BUTTON_DOWN) && (cursorId == CURSOR_WALK) && (event.btnState == 3)) { + if ((event.eventType == EVENT_BUTTON_DOWN) && (cursorId == CURSOR_WALK) && (event.btnState == BTNSHIFT_RIGHT)) { BF_GLOBALS._events.setCursor(CURSOR_USE); event.handled = true; } diff --git a/engines/tsage/converse.cpp b/engines/tsage/converse.cpp index 8ae6a0d97e..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()) @@ -858,7 +858,7 @@ void StripManager::signal() { ++obj44Idx; if (_obj44List[obj44Idx]._field16[0]) { - // WORKAROUND: The _lookupList isn't always correctly initialised. But it always + // 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; diff --git a/engines/tsage/core.cpp b/engines/tsage/core.cpp index 6b4e2963a5..055005808c 100644 --- a/engines/tsage/core.cpp +++ b/engines/tsage/core.cpp @@ -1179,7 +1179,7 @@ void PaletteRotation::signal() { int count = _end - _currIndex; g_system->getPaletteManager()->setPalette((const byte *)&_palette[_currIndex * 3], _start, count); - if (count2) { + if (count2 > 0) { g_system->getPaletteManager()->setPalette((const byte *)&_palette[_start * 3], _start + count, count2); } } @@ -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() { @@ -3262,6 +3267,7 @@ void Player::postInit(SceneObjectList *OwnerList) { _moveDiff.y = 2; _effect = 1; _shade = 0; + _linkedActor = NULL; setObjectWrapper(new SceneObjectWrapper()); setPosition(_characterPos[_characterIndex]); @@ -3992,7 +3998,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 +4248,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/events.cpp b/engines/tsage/events.cpp index 5ca531fdb9..ac6ce0bf8e 100644 --- a/engines/tsage/events.cpp +++ b/engines/tsage/events.cpp @@ -113,7 +113,7 @@ bool EventsClass::getEvent(Event &evt, int eventMask) { case Common::EVENT_RBUTTONUP: case Common::EVENT_MBUTTONUP: evt.eventType = EVENT_BUTTON_UP; - evt.btnState = 0; + evt.btnState = BTNSHIFT_LEFT; break; case Common::EVENT_KEYDOWN: evt.eventType = EVENT_KEYPRESS; diff --git a/engines/tsage/globals.cpp b/engines/tsage/globals.cpp index 5c4fa967e5..3ca54d67a9 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 { @@ -380,6 +381,9 @@ void Ringworld2Globals::reset() { if (!_scannerDialog) _scannerDialog = new ScannerDialog(); + // Default to Quinn as the active character + T2_GLOBALS._player._characterIndex = R2_QUINN; + // Reset the inventory R2_INVENTORY.reset(); T2_GLOBALS._uiElements.updateInventory(); @@ -389,7 +393,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,25 +408,24 @@ void Ringworld2Globals::reset() { _v565E7 = 0; _v565E9 = -5; _v565EB = 26; - _v565F5 = 0; - _v565F6 = 0; - _v565F8 = 0; - _v565FA = 0; + _foodCount = 0; + _rimLocation = 0; + _rimTransportLocation = 0; _v565AE = 0; - _v56605[0] = 0; - _v56605[1] = 3; - _v56605[2] = 5; - _v56605[3] = 1; - _v56605[4] = 2; - _v56605[5] = 5; - _v56605[6] = 9; - _v56605[7] = 14; - _v56605[8] = 15; - _v56605[9] = 18; - _v56605[10] = 20; - _v56605[11] = 25; - _v56605[12] = 27; - _v56605[13] = 31; + _spillLocation[0] = 0; + _spillLocation[1] = 3; + _spillLocation[R2_SEEKER] = 5; + _spillLocation[3] = 1; + _spillLocation[4] = 2; + _spillLocation[5] = 5; + _spillLocation[6] = 9; + _spillLocation[7] = 14; + _spillLocation[8] = 15; + _spillLocation[9] = 18; + _spillLocation[10] = 20; + _spillLocation[11] = 25; + _spillLocation[12] = 27; + _spillLocation[13] = 31; for (int i = 0; i < 18; i++) { _v56613[(i * 4) ] = 1; @@ -449,7 +452,7 @@ void Ringworld2Globals::reset() { _v56613[(17 * 4) + 1] = 1; _v566A6 = 3800; - _v566A3 = 2; + _landerSuitNumber = 2; _v566A4 = 1; _v566A5 = 0; _v566A8 = 5; @@ -475,15 +478,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,10 +496,14 @@ 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; - _player._characterScene[2] = 300; + _player._characterScene[R2_QUINN] = 100; + _player._characterScene[R2_SEEKER] = 300; _player._characterScene[3] = 300; } @@ -519,11 +523,10 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsSint16LE(_v565E7); s.syncAsSint16LE(_v565E9); s.syncAsSint16LE(_v565EB); - s.syncAsSint16LE(_v565F5); - s.syncAsSint16LE(_v565F6); - s.syncAsSint16LE(_v565F8); - s.syncAsSint16LE(_v565FA); - s.syncAsSint16LE(_v566A3); + s.syncAsSint16LE(_foodCount); + s.syncAsSint32LE(_rimLocation); + s.syncAsSint16LE(_rimTransportLocation); + s.syncAsSint16LE(_landerSuitNumber); s.syncAsSint16LE(_v566A6); s.syncAsSint16LE(_v56A93); s.syncAsSint16LE(_scene1925CurrLevel); // _v56A9C @@ -539,8 +542,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]); @@ -558,7 +565,7 @@ void Ringworld2Globals::synchronize(Serializer &s) { s.syncAsByte(_v56AA8); for (i = 0; i < 14; ++i) - s.syncAsByte(_v56605[i]); + s.syncAsByte(_spillLocation[i]); for (i = 0; i < 1000; ++i) s.syncAsByte(_v566AB[i]); s.syncAsByte(_v56A99); @@ -566,7 +573,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..9d4de26b91 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,18 +264,17 @@ public: int _v565E7; int _v565E9; int _v565EB; - int _v565F5; - int _v565F6; - int _v565F8; - int _v565FA; + int _foodCount; + int _rimLocation; + int _rimTransportLocation; int _v5657C; byte _v565AE; - byte _v56605[14]; + byte _spillLocation[14]; int _v56613[76]; byte _v566A4; byte _v566A5; int _v566A6; - byte _v566A3; + byte _landerSuitNumber; byte _v566A8; byte _v566A9; byte _v566AA; @@ -304,9 +298,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..663697d94d 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; @@ -272,8 +272,8 @@ void CharacterDialog::show() { default: break; } - } else if ((R2_GLOBALS._player._characterScene[1] == 300) && (R2_GLOBALS._scannerFrequencies[1] != 1)) { - switch (R2_GLOBALS._scannerFrequencies[1]) { + } else if ((R2_GLOBALS._player._characterScene[R2_QUINN] == 300) && (R2_GLOBALS._scannerFrequencies[1] != 1)) { + switch (R2_GLOBALS._scannerFrequencies[1] - 1) { case 2: R2_GLOBALS._sound4.play(45); break; @@ -289,12 +289,12 @@ void CharacterDialog::show() { default: break; } - } else if (R2_GLOBALS._player._characterScene[2] != 300) { + } else if (R2_GLOBALS._player._characterScene[R2_SEEKER] != 300) { R2_GLOBALS._sound4.stop(); } 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 2a8e50bd67..98e455b41b 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(); @@ -143,16 +144,22 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { // Miranda being questioned return new Scene1625(); case 1700: + // Rim return new Scene1700(); case 1750: + // Rim Transport Vechile return new Scene1750(); case 1800: + // Rim Lift Exterior return new Scene1800(); case 1850: + // Rim Lift Interior return new Scene1850(); case 1875: + // Rim Lift Computer return new Scene1875(); case 1900: + // Spill Mountains Elevator Exit return new Scene1900(); case 1925: return new Scene1925(); @@ -163,49 +170,49 @@ Scene *Ringworld2Game::createScene(int sceneNumber) { /* Scene group #2 */ // case 2000: - // Ice Maze + // Spill Mountains return new Scene2000(); case 2350: - // Ice Maze: Balloon Launch Platform + // Spill Mountains: Balloon Launch Platform return new Scene2350(); case 2400: - // Ice Maze: Large empty room + // Spill Mountains: Large empty room return new Scene2400(); case 2425: - // Ice Maze: The Hall of Records + // Spill Mountains: The Hall of Records return new Scene2425(); case 2430: - // Ice Maze: Bedroom + // Spill Mountains: Bedroom return new Scene2430(); case 2435: - // Ice Maze: Throne room + // Spill Mountains: Throne room return new Scene2435(); case 2440: - // Ice Maze: Another bedroom + // Spill Mountains: Another bedroom return new Scene2440(); case 2445: - // Ice Maze: + // Spill Mountains: return new Scene2445(); case 2450: - // Ice Maze: Another bedroom + // Spill Mountains: Another bedroom return new Scene2450(); case 2455: - // Ice Maze: Inside crevasse + // Spill Mountains: Inside crevasse return new Scene2455(); case 2500: - // Ice Maze: Large Cave + // Spill Mountains: Large Cave return new Scene2500(); case 2525: - // Ice Maze: Furnace room + // Spill Mountains: Furnace room return new Scene2525(); case 2530: - // Ice Maze: Well + // Spill Mountains: Well return new Scene2530(); case 2535: - // Ice Maze: Tannery + // Spill Mountains: Tannery return new Scene2535(); case 2600: - // Ice Maze: Exit + // Spill Mountains: Exit return new Scene2600(); case 2700: // Forest Maze @@ -318,11 +325,10 @@ SceneExt::SceneExt(): Scene() { for (int i = 0; i < 256; i++) _field312[i] = 0; - _field372 = _field37A = 0; + _savedPlayerEnabled = false; _savedUiEnabled = false; _savedCanWalk = false; - _focusObject = NULL; // WORKAROUND: In the original, playing animations don't reset the global _animationCtr // counter as scene changes unless the playing animation explicitly finishes. For now, @@ -331,13 +337,20 @@ SceneExt::SceneExt(): Scene() { R2_GLOBALS._animationCtr = 0; } +void SceneExt::synchronize(Serializer &s) { + Scene::synchronize(s); + + s.syncBytes(&_field312[0], 256); + _sceneAreas.synchronize(s); +} + void SceneExt::postInit(SceneObjectList *OwnerList) { Scene::postInit(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; @@ -383,27 +396,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: @@ -465,7 +457,6 @@ void SceneExt::fadeOut() { void SceneExt::startStrip() { SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene; - scene->_field372 = 1; scene->_savedPlayerEnabled = R2_GLOBALS._player._enabled; if (scene->_savedPlayerEnabled) { @@ -481,7 +472,6 @@ void SceneExt::startStrip() { void SceneExt::endStrip() { SceneExt *scene = (SceneExt *)R2_GLOBALS._sceneManager._scene; - scene->_field372 = 0; if (scene->_savedPlayerEnabled) { R2_GLOBALS._player.enableControl(); @@ -621,7 +611,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); @@ -665,7 +655,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) { @@ -971,7 +961,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); } /** @@ -1325,7 +1316,7 @@ GfxSurface SceneActor::getFrame() { /*--------------------------------------------------------------------------*/ -SceneArea::SceneArea(): EventHandler() { +SceneArea::SceneArea(): SceneItem() { _enabled = true; _insideArea = false; _savedCursorNum = CURSOR_NONE; @@ -1338,8 +1329,8 @@ void SceneArea::synchronize(Serializer &s) { _bounds.synchronize(s); s.syncAsSint16LE(_enabled); s.syncAsSint16LE(_insideArea); - s.syncAsSint16LE(_cursorNum); - s.syncAsSint16LE(_savedCursorNum); + s.syncAsSint32LE(_cursorNum); + s.syncAsSint32LE(_savedCursorNum); s.syncAsSint16LE(_cursorState); } @@ -1429,6 +1420,7 @@ void SceneExit::process(Event &event) { /*--------------------------------------------------------------------------*/ void SceneAreaObject::remove() { + R2_GLOBALS._sceneItems.remove(this); _object1.remove(); SceneArea::remove(); --R2_GLOBALS._insetUp; @@ -1438,19 +1430,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(); } } } @@ -1470,7 +1465,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); } @@ -1882,7 +1877,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]; @@ -2270,21 +2265,21 @@ 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: case 1800: - if (R2_GLOBALS._v565F8 < 0 || (R2_GLOBALS._v565F8 == 0 && R2_GLOBALS._v565F6 < 1201)) + if (R2_GLOBALS._rimLocation < 1201) scanner._obj4.setup(4, 3, 3); - else if (R2_GLOBALS._v565F8 > 0 || (R2_GLOBALS._v565F8 == 0 && R2_GLOBALS._v565F6 < 1201)) + else if (R2_GLOBALS._rimLocation < 1201) scanner._obj4.setup(4, 3, 4); else scanner._obj4.setup(4, 3, 5); @@ -2417,7 +2412,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..c7e36fc5f0 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 { @@ -80,26 +82,21 @@ private: static void endStrip(); public: byte _field312[256]; - int _field372; bool _savedPlayerEnabled; bool _savedUiEnabled; bool _savedCanWalk; - int _field37A; - SceneObject *_focusObject; Visage _cursorVisage; SynchronizedList<EventHandler *> _sceneAreas; - - Rect _v51C34; public: SceneExt(); virtual Common::String getClassName() { return "SceneExt"; } + virtual void synchronize(Serializer &s); virtual void postInit(SceneObjectList *OwnerList = NULL); 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 63bb24f384..40e17b6ed9 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); } /*--------------------------------------------------------------------------*/ @@ -577,7 +577,7 @@ bool Scene125::DiskSlot::startAction(CursorType action, Event &event) { Scene125 *scene = (Scene125 *)R2_GLOBALS._sceneManager._scene; switch (action) { case CURSOR_USE: - if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[1]) { + if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[R2_QUINN]) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 126; scene->setAction(&scene->_sequenceManager, scene, 126, &scene->_infoDisk, NULL); @@ -619,21 +619,21 @@ void Scene125::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene != 125) // Save the prior scene to return to when the console is turned off - R2_GLOBALS._player._oldCharacterScene[1] = R2_GLOBALS._sceneManager._previousScene; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = R2_GLOBALS._sceneManager._previousScene; R2_GLOBALS._player.postInit(); R2_GLOBALS._player.hide(); R2_GLOBALS._player.disableControl(); - if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[1]) { + if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) == R2_GLOBALS._player._oldCharacterScene[R2_QUINN]) { _infoDisk.postInit(); _infoDisk.setup(160, 3, 5); _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: @@ -781,7 +781,7 @@ void Scene125::signal() { } break; case 125: - R2_INVENTORY.setObjectScene(R2_OPTO_DISK, R2_GLOBALS._player._oldCharacterScene[1]); + R2_INVENTORY.setObjectScene(R2_OPTO_DISK, R2_GLOBALS._player._oldCharacterScene[R2_QUINN]); R2_GLOBALS._player.enableControl(); break; case 126: @@ -883,7 +883,7 @@ void Scene125::consoleAction(int id) { _icon2.setIcon(23); break; case 6: - R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._oldCharacterScene[1]); + R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._oldCharacterScene[R2_QUINN]); break; case 7: if (_consoleMode == 11) @@ -946,7 +946,7 @@ void Scene125::consoleAction(int id) { break; case 13: consoleAction(2); - if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) != R2_GLOBALS._player._oldCharacterScene[1]) { + if (R2_INVENTORY.getObjectScene(R2_OPTO_DISK) != R2_GLOBALS._player._oldCharacterScene[R2_QUINN]) { SceneItem::display2(126, 17); } else { R2_GLOBALS._player.disableControl(); @@ -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._v565F5; + ++R2_GLOBALS._foodCount; + + _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: @@ -2480,14 +2489,13 @@ void Scene205::handleText() { *--------------------------------------------------------------------------*/ Scene250::Button::Button(): SceneActor() { - _floorNumber = _v2 = 0; + _floorNumber = 0; } void Scene250::Button::synchronize(Serializer &s) { SceneActor::synchronize(s); s.syncAsSint16LE(_floorNumber); - s.syncAsSint16LE(_v2); } bool Scene250::Button::startAction(CursorType action, Event &event) { @@ -2495,7 +2503,7 @@ bool Scene250::Button::startAction(CursorType action, Event &event) { switch (action) { case CURSOR_USE: - if (scene->_field414) { + if (scene->_destButtonY) { SceneItem::display2(250, 15); } else { switch (_floorNumber) { @@ -2546,7 +2554,6 @@ bool Scene250::Button::startAction(CursorType action, Event &event) { void Scene250::Button::setFloor(int floorNumber) { SceneActor::postInit(); _floorNumber = floorNumber; - _v2 = 0; if (_floorNumber <= 9) { SceneObject::setup(250, 1, 4); @@ -2571,17 +2578,18 @@ void Scene250::Button::setFloor(int floorNumber) { /*--------------------------------------------------------------------------*/ Scene250::Scene250(): SceneExt() { - _field412 = _field414 = _field416 = _field418 = _field41A = 0; + _currButtonY = _destButtonY = _elevatorSpeed = 0; + _skippingFl = _skippableFl = false; } void Scene250::synchronize(Serializer &s) { SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); - s.syncAsSint16LE(_field414); - s.syncAsSint16LE(_field416); - s.syncAsSint16LE(_field418); - s.syncAsSint16LE(_field41A); + s.syncAsSint16LE(_currButtonY); + s.syncAsSint16LE(_destButtonY); + s.syncAsSint16LE(_elevatorSpeed); + s.syncAsSint16LE(_skippableFl); + s.syncAsSint16LE(_skippingFl); } void Scene250::postInit(SceneObjectList *OwnerList) { @@ -2623,28 +2631,28 @@ void Scene250::postInit(SceneObjectList *OwnerList) { switch (R2_GLOBALS._sceneManager._previousScene) { case 200: - _field412 = 55; + _currButtonY = 55; break; case 300: - _field412 = 43; + _currButtonY = 43; break; case 700: - _field412 = 139; + _currButtonY = 139; break; case 850: - _field412 = 91; + _currButtonY = 91; break; default: R2_GLOBALS._sceneManager._previousScene = 200; - _field412 = 55; + _currButtonY = 55; break; } - _currentFloor.setPosition(Common::Point(111, _field412)); + _currentFloor.setPosition(Common::Point(111, _currButtonY)); } void Scene250::signal() { - if (_field41A) + if (_skippingFl) _sceneMode = 20; switch (_sceneMode) { @@ -2655,20 +2663,24 @@ void Scene250::signal() { R2_GLOBALS._player.setPosition(Common::Point(261, 185)); ADD_MOVER(R2_GLOBALS._player, 261, 15); - _field416 = 0; + _elevatorSpeed = 0; _sceneMode = 2; break; case 2: - _sceneMode = ((_field414 - 12) == _field412) ? 4 : 3; + if (_destButtonY - 12 == _currButtonY) + _sceneMode = 4; + else + _sceneMode = 3; + signal(); break; case 3: _currentFloor.setPosition(Common::Point(111, _currentFloor._position.y + 12)); - _field412 += 12; + _currButtonY += 12; R2_GLOBALS._player.setPosition(Common::Point(261, 185)); ADD_MOVER(R2_GLOBALS._player, 261, 15); - if ((_field414 - 12) == _field412) + if ((_destButtonY - 12) == _currButtonY) _sceneMode = 4; break; case 4: @@ -2690,12 +2702,12 @@ void Scene250::signal() { R2_GLOBALS._player.setup(250, 1, 2); R2_GLOBALS._player.setPosition(Common::Point(261, 15)); ADD_MOVER(R2_GLOBALS._player, 261, 185); - _field416 = 0; + _elevatorSpeed = 0; _sceneMode = 7; break; case 7: - _field418 = 1; - if ((_field414 + 12) == _field412) + _skippableFl = true; + if ((_destButtonY + 12) == _currButtonY) _sceneMode = 9; else _sceneMode = 8; @@ -2703,11 +2715,11 @@ void Scene250::signal() { break; case 8: _currentFloor.setPosition(Common::Point(111, _currentFloor._position.y - 12)); - _field412 -= 12; + _currButtonY -= 12; R2_GLOBALS._player.setPosition(Common::Point(261, 15)); ADD_MOVER(R2_GLOBALS._player, 261, 185); - if ((_field414 + 12) == _field412) + if ((_destButtonY + 12) == _currButtonY) _sceneMode = 9; break; case 9: @@ -2723,7 +2735,7 @@ void Scene250::signal() { break; case 20: // Handle changing scene - switch (_field414) { + switch (_destButtonY) { case 55: R2_GLOBALS._sceneManager.changeScene(200); break; @@ -2746,12 +2758,13 @@ void Scene250::signal() { } void Scene250::changeFloor(int floorNumber) { - _field414 = (floorNumber - 1) * 12 + 43; - _button1.setPosition(Common::Point(111, _field414)); + _destButtonY = (floorNumber - 1) * 12 + 43; + _button1.setPosition(Common::Point(111, _destButtonY)); _button1.show(); - _sceneMode = (_field412 >= _field414) ? 6 : 1; - if (_field414 == _field412) + _skippableFl = true; + _sceneMode = (_currButtonY >= _destButtonY) ? 6 : 1; + if (_destButtonY == _currButtonY) _sceneMode = 20; signal(); @@ -2759,8 +2772,8 @@ void Scene250::changeFloor(int floorNumber) { void Scene250::process(Event &event) { if (!event.handled) { - if (((event.eventType == EVENT_KEYPRESS) || (event.btnState != 0)) && _field418) { - _field41A = 1; + if (((event.eventType == EVENT_KEYPRESS) || (event.btnState == BTNSHIFT_RIGHT)) && _skippableFl) { + _skippingFl = true; event.handled = true; } @@ -2771,14 +2784,14 @@ void Scene250::process(Event &event) { void Scene250::dispatch() { SceneExt::dispatch(); - if (((_sceneMode == 2) || (_sceneMode == 7)) && (_field416 < 100)) { - ++_field416; - R2_GLOBALS._player._moveDiff.y = _field416 / 5; + if (((_sceneMode == 2) || (_sceneMode == 7)) && (_elevatorSpeed < 100)) { + ++_elevatorSpeed; + R2_GLOBALS._player._moveDiff.y = _elevatorSpeed / 5; } if (((_sceneMode == 5) || (_sceneMode == 10)) && (R2_GLOBALS._player._moveDiff.y > 4)) { - --_field416; - R2_GLOBALS._player._moveDiff.y = _field416 / 7 + 3; + --_elevatorSpeed; + R2_GLOBALS._player._moveDiff.y = (_elevatorSpeed / 7) + 3; } } @@ -3266,7 +3279,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _miranda.setAction(&_action3); _miranda.setDetails(300, 39, 40, 41, 1, (SceneItem *)NULL); - if ((R2_GLOBALS._player._characterScene[2] == 300) || (R2_GLOBALS._player._characterScene[2] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_SEEKER] == 300) || (R2_GLOBALS._player._characterScene[R2_SEEKER] == 325)) { _seeker.postInit(); _seeker.setVisage(302); _seeker.setPosition(Common::Point(158, 108)); @@ -3288,7 +3301,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _miranda.setAction(&_action3); _miranda.setDetails(300, 39, 40, 41, 1, (SceneItem *)NULL); - if ((R2_GLOBALS._player._characterScene[1] == 300) || (R2_GLOBALS._player._characterScene[1] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_QUINN] == 300) || (R2_GLOBALS._player._characterScene[R2_QUINN] == 325)) { _quinn.postInit(); _quinn.setup(302, 3, 1); _quinn.setPosition(Common::Point(271, 150)); @@ -3304,7 +3317,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { break; case 3: - if ((R2_GLOBALS._player._characterScene[2] == 300) || (R2_GLOBALS._player._characterScene[2] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_SEEKER] == 300) || (R2_GLOBALS._player._characterScene[R2_SEEKER] == 325)) { _seeker.postInit(); _seeker.setVisage(302); _seeker.setPosition(Common::Point(158, 108)); @@ -3313,7 +3326,7 @@ void Scene300::postInit(SceneObjectList *OwnerList) { _seeker.setDetails(300, 42, 43, 44, 1, (SceneItem *)NULL); } - if ((R2_GLOBALS._player._characterScene[1] == 300) || (R2_GLOBALS._player._characterScene[1] == 325)) { + if ((R2_GLOBALS._player._characterScene[R2_QUINN] == 300) || (R2_GLOBALS._player._characterScene[R2_QUINN] == 325)) { _quinn.postInit(); _quinn.setup(302, 3, 1); _quinn.setPosition(Common::Point(271, 150)); @@ -3644,7 +3657,7 @@ void Scene300::signal() { break; case 316: - R2_GLOBALS._player._characterScene[2] = 500; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 500; _seeker.remove(); R2_GLOBALS._player.enableControl(CURSOR_CROSSHAIRS); break; @@ -4813,6 +4826,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 +4853,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 +4872,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 +4883,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 +4912,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 +4922,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 +4990,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 +5059,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 +5096,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 +5227,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 +5323,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 +5378,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 +5387,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 +5395,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 +5433,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 +5443,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 +5547,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 +5570,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 +5591,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 +5635,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 +5661,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 +5706,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 +5735,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 +5760,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 +5779,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 +5819,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 +5828,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 +5890,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 +5905,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 +5915,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 +6012,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 +6038,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 +6065,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 +6117,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 +6151,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 +6235,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 +6258,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 +6288,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 +6393,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 +6418,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 +6444,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 +6461,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..df0b4d8fc6 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; @@ -310,7 +310,7 @@ public: class Scene250: public SceneExt { class Button: public SceneActor { public: - int _floorNumber, _v2; + int _floorNumber; Button(); void setFloor(int floorNumber); @@ -318,7 +318,8 @@ class Scene250: public SceneExt { virtual bool startAction(CursorType action, Event &event); }; public: - int _field412, _field414, _field416, _field418, _field41A; + int _currButtonY, _destButtonY, _elevatorSpeed; + bool _skippingFl, _skippableFl; NamedHotspot _background, _item2, _item3, _item4; Button _button1, _currentFloor; Button _floor1, _floor2, _floor3, _floor4, _floor5; @@ -524,6 +525,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 +557,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 +596,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 +614,7 @@ public: SonicStunner _sonicStunner; Locker1 _locker1; Locker2 _locker2; - SceneAreaObject _area1; - Object _obj1, _obj2, _obj3; + PanelDialog _panelDialog; ASoundExt _sound1; SequenceManager _sequenceManager1, _sequenceManager2; public: @@ -622,7 +643,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 +661,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 +674,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 +700,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 +717,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 +737,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 4e9d019f01..4e7508f14d 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes1.cpp @@ -5,7 +5,7 @@ * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License + * modify it under the terms of the GNU GenWeral Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. @@ -38,7 +38,8 @@ Scene1000::Scene1000(): SceneExt() { R2_GLOBALS._sceneManager._hasPalette = false; R2_GLOBALS._uiElements._active = false; _gameTextSpeaker._displayMode = 9; - _fieldD2E = 0; + _forceCheckAnimationFl = false; + _animCounter = 0; } void Scene1000::postInit(SceneObjectList *OwnerList) { @@ -115,7 +116,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, true, 0); for (int percent = 0; percent < 100; percent += 5) @@ -140,7 +141,7 @@ void Scene1000::signal() { R2_GLOBALS._player.setPosition(Common::Point(160, 100)); R2_GLOBALS._player.show(); - _field412 = 0; + _animCounter = 0; _stripManager.start(29, this); break; @@ -148,7 +149,7 @@ void Scene1000::signal() { if (R2_GLOBALS._speechSubtitles & SPEECH_TEXT) { setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL); } else { - if (++_field412 < 3) + if (++_animCounter < 3) _sceneMode = 2; setAction(&_sequenceManager1, this, 2, &R2_GLOBALS._player, NULL); @@ -173,7 +174,7 @@ void Scene1000::signal() { _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -203,7 +204,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -225,7 +226,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -245,7 +246,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -270,7 +271,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -296,7 +297,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -318,7 +319,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -345,7 +346,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -370,7 +371,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -393,7 +394,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -411,7 +412,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -438,7 +439,7 @@ void Scene1000::signal() { R2_GLOBALS._sceneManager._hasPalette = false; _animationPlayer.dispatch(); - _fieldD2E = 1; + _forceCheckAnimationFl = true; R2_GLOBALS._scenePalette.fade((const byte *)&black, 1, 0); for (int percent = 0; percent < 100; percent += 5) R2_GLOBALS._scenePalette.fade((const byte *)&black, true, percent); @@ -454,9 +455,9 @@ void Scene1000::signal() { } void Scene1000::dispatch() { - if (_fieldD2E) { + if (_forceCheckAnimationFl) { if (_animationPlayer.isCompleted()) { - _fieldD2E = 0; + _forceCheckAnimationFl = false; _animationPlayer.close(); _animationPlayer.remove(); @@ -661,15 +662,15 @@ void Scene1020::dispatch() { * *--------------------------------------------------------------------------*/ Scene1100::Scene1100() { - _field412 = 0; - _field414 = 0; + _nextStripNum = 0; + _paletteRefreshStatus = 0; } void Scene1100::synchronize(Serializer &s) { SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); - s.syncAsSint16LE(_field414); + s.syncAsSint16LE(_nextStripNum); + s.syncAsSint16LE(_paletteRefreshStatus); } bool Scene1100::Seeker::startAction(CursorType action, Event &event) { @@ -680,24 +681,24 @@ bool Scene1100::Seeker::startAction(CursorType action, Event &event) { if (R2_GLOBALS.getFlag(52)) { R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._player._characterIndex == 1) - scene->_field412 = 327; + if (R2_GLOBALS._player._characterIndex == R2_QUINN) + scene->_nextStripNum = 327; else - scene->_field412 = 328; + scene->_nextStripNum = 328; scene->_sceneMode = 53; scene->setAction(&scene->_sequenceManager1, scene, 1122, &R2_GLOBALS._player, NULL); } else { 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); @@ -725,7 +726,7 @@ bool Scene1100::Trooper::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->_trooper, NULL); } else { @@ -736,7 +737,7 @@ bool Scene1100::Trooper::startAction(CursorType action, Event &event) { } else if (_strip == 2) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1113; - if (R2_GLOBALS._player._characterIndex == 1) { + 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->_trooper, NULL); @@ -756,7 +757,7 @@ 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))) { - scene->_field412 = 0; + scene->_nextStripNum = 0; R2_GLOBALS._player.disableControl(); scene->_sceneMode = 53; scene->setAction(&scene->_sequenceManager1, scene, 1122, &R2_GLOBALS._player, NULL); @@ -778,7 +779,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._v5589E.right = 200; } - if (R2_GLOBALS._player._characterScene[1] == 1100) + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 1100) R2_GLOBALS._sceneManager._previousScene = 1100; if (R2_GLOBALS._sceneManager._previousScene == -1) { @@ -814,10 +815,10 @@ 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; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1100; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1100; _actor2.setPosition(Common::Point(150, 30)); R2_GLOBALS._sound1.play(93); R2_GLOBALS._player.postInit(); @@ -826,7 +827,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { _seeker.postInit(); _seeker.hide(); - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _seeker.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); else _seeker.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); @@ -859,7 +860,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL); } else if (R2_GLOBALS._sceneManager._previousScene == 1000) { _actor2.setPosition(Common::Point(50, 30)); - _field414 = 0; + _paletteRefreshStatus = 0; _palette1.loadPalette(1101); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.disableControl(); @@ -872,25 +873,25 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveRate = 30; R2_GLOBALS._player._moveDiff = Common::Point(16, 2); - _object1.setup2(1104, 2, 1, 175, 125, 102, 1); + _rightLandslide.setup2(1104, 2, 1, 175, 125, 102, 1); _object2.setup2(1102, 5, 1, 216, 167, 1, 0); - _actor12.postInit(); - _actor12.setup(1113, 2, 1); - _actor12.setPosition(Common::Point(67, 151)); - _actor12.fixPriority(255); + _leftImpacts.postInit(); + _leftImpacts.setup(1113, 2, 1); + _leftImpacts.setPosition(Common::Point(67, 151)); + _leftImpacts.fixPriority(255); - _actor3.postInit(); - _actor3.setup(1102, 6, 1); - _actor3._moveRate = 30; - _actor3._moveDiff.x = 2; + _shipFormation.postInit(); + _shipFormation.setup(1102, 6, 1); + _shipFormation._moveRate = 30; + _shipFormation._moveDiff.x = 2; - _actor4.postInit(); - _actor4.setup(1102, 6, 2); - _actor4._moveRate = 30; - _actor4._moveDiff.x = 2; - _actor4._effect = 5; - _actor4._field9C = _field312; + _shipFormationShadow.postInit(); + _shipFormationShadow.setup(1102, 6, 2); + _shipFormationShadow._moveRate = 30; + _shipFormationShadow._moveDiff.x = 2; + _shipFormationShadow._effect = 5; + _shipFormationShadow._field9C = _field312; R2_GLOBALS._sound1.play(86); @@ -910,7 +911,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { _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); _seeker.setup(29, 6, 1); } else { @@ -921,7 +922,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { _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); _seeker.setup(1107, 4, 1); R2_GLOBALS._player.setPosition(Common::Point(247, 169)); @@ -936,7 +937,7 @@ void Scene1100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._canWalk = false; } - if (R2_GLOBALS._player._characterIndex == 1) + if (R2_GLOBALS._player._characterIndex == R2_QUINN) _seeker.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); else _seeker.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); @@ -992,30 +993,30 @@ void Scene1100::remove() { void Scene1100::signal() { switch (_sceneMode++) { case 0: - _actor3.setPosition(Common::Point(350, 20)); + _shipFormation.setPosition(Common::Point(350, 20)); setAction(&_sequenceManager1, this, 1, &R2_GLOBALS._player, NULL); break; case 1:{ Common::Point pt(-150, 20); NpcMover *mover = new NpcMover(); - _actor3.addMover(mover, &pt, this); - _actor4.setPosition(Common::Point(350, 55)); + _shipFormation.addMover(mover, &pt, this); + _shipFormationShadow.setPosition(Common::Point(350, 55)); Common::Point pt2(-150, 55); NpcMover *mover2 = new NpcMover(); - _actor4.addMover(mover2, &pt2, NULL); + _shipFormationShadow.addMover(mover2, &pt2, NULL); } break; case 2: - _actor3.remove(); - _actor4.remove(); - _actor5.postInit(); - _actor6.postInit(); - _actor7.postInit(); - _actor8.postInit(); - _actor9.postInit(); - _actor10.postInit(); - setAction(&_sequenceManager1, this, 1102, &_actor5, &_actor6, &_actor7, &_actor8, &_actor9, &_actor10, NULL); + _shipFormation.remove(); + _shipFormationShadow.remove(); + _shotImpact1.postInit(); + _shotImpact2.postInit(); + _shotImpact3.postInit(); + _shotImpact4.postInit(); + _shotImpact5.postInit(); + _laserShot.postInit(); + setAction(&_sequenceManager1, this, 1102, &_shotImpact1, &_shotImpact2, &_shotImpact3, &_shotImpact4, &_shotImpact5, &_laserShot, NULL); break; case 3: { R2_GLOBALS._sound2.play(84); @@ -1028,24 +1029,24 @@ void Scene1100::signal() { case 4: _chief.postInit(); _chief.show(); - setAction(&_sequenceManager1, this, 1101, &_chief, &_actor10, NULL); + setAction(&_sequenceManager1, this, 1101, &_chief, &_laserShot, NULL); break; case 5: - _actor13.postInit(); - _actor13._effect = 6; - _actor13.setup(1103, 3, 1); - _actor13._moveRate = 30; + _runningGuy1.postInit(); + _runningGuy1._effect = 6; + _runningGuy1.setup(1103, 3, 1); + _runningGuy1._moveRate = 30; - _actor14.postInit(); - _actor14._effect = 6; - _actor14.setup(1103, 4, 1); - _actor4._moveRate = 25; + _runningGuy2.postInit(); + _runningGuy2._effect = 6; + _runningGuy2.setup(1103, 4, 1); + _runningGuy2._moveRate = 25; - _actor13.setAction(&_sequenceManager2, this, 1109, &_actor13, &_actor14, NULL); + _runningGuy1.setAction(&_sequenceManager2, this, 1109, &_runningGuy1, &_runningGuy2, NULL); break; case 6: { - _actor13.remove(); - _actor14.remove(); + _runningGuy1.remove(); + _runningGuy2.remove(); R2_GLOBALS._player.setPosition(Common::Point(-50, 136)); R2_GLOBALS._sound2.play(84); Common::Point pt(350, 236); @@ -1054,29 +1055,30 @@ void Scene1100::signal() { } break; case 7: - setAction(&_sequenceManager1, this, 1103, &_chief, &_actor10); + setAction(&_sequenceManager1, this, 1103, &_chief, &_laserShot, NULL); break; case 8: R2_GLOBALS._player._effect = 0; - _actor11.postInit(); - setAction(&_sequenceManager1, this, 1105, &R2_GLOBALS._player, &_actor10, &_actor11, &_chief, NULL); + _animation.postInit(); + setAction(&_sequenceManager1, this, 1105, &R2_GLOBALS._player, &_laserShot, &_animation, &_chief, NULL); break; case 9: - _object1.copySceneToBackground(); + _rightLandslide.copySceneToBackground(); - _actor15.postInit(); - _actor15.setup(1103, 2, 1); - _actor15._moveRate = 30; - _actor15.setAction(&_sequenceManager3, this, 1107, &_actor15, NULL); + _runningGuy3.postInit(); + _runningGuy3.setup(1103, 2, 1); + _runningGuy3._moveRate = 30; + _runningGuy3.setAction(&_sequenceManager3, this, 1107, &_runningGuy3, NULL); break; case 10: - _actor13.postInit(); - _actor13.setup(1103, 1, 1); - _actor13._moveRate = 15; - _actor13.setAction(&_sequenceManager2, this, 1108, &_actor13, NULL); + _runningGuy1.postInit(); + _runningGuy1.setup(1103, 1, 1); + _runningGuy1._moveRate = 15; + _runningGuy1.setAction(&_sequenceManager2, this, 1108, &_runningGuy1, NULL); break; case 11: { - setAction(&_sequenceManager1, this, 1106, &_actor11, &_actor10, &_actor12, NULL); + setAction(&_sequenceManager1, this, 1106, &_animation, &_laserShot, &_leftImpacts, NULL); + R2_GLOBALS._player._effect = 5; R2_GLOBALS._player.setup(1102, 3, 2); R2_GLOBALS._player.setPosition(Common::Point(-50, 131)); @@ -1093,16 +1095,16 @@ void Scene1100::signal() { _trooper.postInit(); R2_GLOBALS._scrollFollower = &_trooper; - _actor11.setup(1100, 2, 1); - _actor11.setPosition(Common::Point(408, 121)); + _animation.setup(1100, 2, 1); + _animation.setPosition(Common::Point(408, 121)); - _actor10.setup(1100, 3, 5); - _actor10.setPosition(Common::Point(409, 121)); + _laserShot.setup(1100, 3, 5); + _laserShot.setPosition(Common::Point(409, 121)); setAction(&_sequenceManager1, this, 1104, &_trooper, NULL); break; case 14: - setAction(&_sequenceManager1, this, 1100, &_actor11, &_actor10, NULL); + setAction(&_sequenceManager1, this, 1100, &_animation, &_laserShot, NULL); break; case 15: R2_GLOBALS._sceneManager.changeScene(1000); @@ -1173,7 +1175,7 @@ void Scene1100::signal() { 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); _seeker.setAction(&_sequenceManager2, NULL, 1123, &_seeker, NULL); } else { @@ -1184,22 +1186,22 @@ void Scene1100::signal() { case 53: _sceneMode = 54; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); - if (_field412 == 0) { + if (_nextStripNum == 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); } } else { - _stripManager.start3(_field412, this, _stripManager._lookupList); + _stripManager.start3(_nextStripNum, this, _stripManager._lookupList); } break; case 54: @@ -1215,8 +1217,8 @@ void Scene1100::signal() { R2_GLOBALS._player._canWalk = false; break; case 99: - R2_GLOBALS._player._characterScene[1] = 300; - R2_GLOBALS._player._characterScene[2] = 300; + R2_GLOBALS._player._characterScene[R2_QUINN] = 300; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 300; R2_GLOBALS._player._characterIndex = R2_QUINN; R2_GLOBALS._sceneManager.changeScene(300); break; @@ -1268,37 +1270,37 @@ void Scene1100::signal() { } void Scene1100::dispatch() { - if ((g_globals->_sceneObjects->contains(&_actor10)) && (_actor10._visage == 1102) && (_actor10._strip == 4) && (_actor10._frame == 1) && (_actor10._flags & OBJFLAG_HIDING)) { - if (_field414 == 1) { - _field414 = 2; + if ((g_globals->_sceneObjects->contains(&_laserShot)) && (_laserShot._visage == 1102) && (_laserShot._strip == 4) && (_laserShot._frame == 1) && (_laserShot._flags & OBJFLAG_HIDING)) { + if (_paletteRefreshStatus == 1) { + _paletteRefreshStatus = 2; R2_GLOBALS._scenePalette.refresh(); } } else { - if (_field414 == 2) + if (_paletteRefreshStatus == 2) R2_GLOBALS._scenePalette.refresh(); - _field414 = 1; + _paletteRefreshStatus = 1; } Scene::dispatch(); - if (R2_GLOBALS._player._bounds.contains(_actor13._position)) - _actor13._shade = 3; + if (R2_GLOBALS._player._bounds.contains(_runningGuy1._position)) + _runningGuy1._shade = 3; else - _actor13._shade = 0; + _runningGuy1._shade = 0; - if (R2_GLOBALS._player._bounds.contains(_actor14._position)) - _actor14._shade = 3; + if (R2_GLOBALS._player._bounds.contains(_runningGuy2._position)) + _runningGuy2._shade = 3; else - _actor14._shade = 0; + _runningGuy2._shade = 0; - if (R2_GLOBALS._player._bounds.contains(_actor15._position)) - _actor15._shade = 3; + if (R2_GLOBALS._player._bounds.contains(_runningGuy3._position)) + _runningGuy3._shade = 3; else - _actor15._shade = 0; + _runningGuy3._shade = 0; } 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); } @@ -5976,7 +5978,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; + } } } @@ -5986,8 +5989,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; @@ -7011,7 +7016,7 @@ void Scene1500::signal() { } break; case 24: - R2_GLOBALS._sceneManager.changeScene(300); + R2_GLOBALS._sceneManager.changeScene(1550); break; default: break; @@ -7172,21 +7177,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) { @@ -7239,36 +7245,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); @@ -7278,92 +7284,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); @@ -7374,47 +7380,48 @@ 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) { - case 0: + setup(1517, _componentId, 1); + + switch (_componentId) { + case 1: if (R2_INVENTORY.getObjectScene(R2_GUIDANCE_MODULE) == 0) setFrame(5); setPosition(Common::Point(287, 85)); break; - case 1: + case 2: if (R2_INVENTORY.getObjectScene(R2_RADAR_MECHANISM) == 0) setFrame(5); setPosition(Common::Point(248, 100)); break; - case 2: - if (R2_INVENTORY.getObjectScene(R2_DIAGNOSTICS_DISPLAY) == 0) + case 3: + if (R2_INVENTORY.getObjectScene(R2_GYROSCOPE) == 0) setFrame(5); setPosition(Common::Point(217, 85)); break; - case 3: - if (R2_INVENTORY.getObjectScene(R2_THRUSTER_VALVE)) + case 4: + if (R2_INVENTORY.getObjectScene(R2_THRUSTER_VALVE) == 0) setFrame(5); setPosition(Common::Point(161, 121)); break; - case 4: - if (R2_INVENTORY.getObjectScene(R2_IGNITOR)) + case 5: + if (R2_INVENTORY.getObjectScene(R2_IGNITOR) == 0) setFrame(5); setPosition(Common::Point(117, 121)); break; - case 5: - if (R2_INVENTORY.getObjectScene(R2_FUEL_CELL)) + case 6: + if (R2_INVENTORY.getObjectScene(R2_FUEL_CELL) == 0) setFrame(5); setPosition(Common::Point(111, 85)); break; - case 6: - if (R2_INVENTORY.getObjectScene(R2_BATTERY)) + case 7: + if (R2_INVENTORY.getObjectScene(R2_BATTERY) == 0) setFrame(5); setPosition(Common::Point(95, 84)); break; - case 7: { + case 8: { setup(1516, 1, 1); setPosition(Common::Point(201, 45)); Scene1550 *scene = (Scene1550 *)R2_GLOBALS._sceneManager._scene; @@ -7427,6 +7434,9 @@ void Scene1550::UnkObj15502::subA5CDF(int strip) { default: break; } + + fixPriority(92); + setDetails(1550, 70, -1, -1, 2, (SceneItem *)NULL); } Scene1550::UnkObj15503::UnkObj15503() { @@ -7513,19 +7523,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(); } } @@ -7573,26 +7580,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); @@ -7610,7 +7621,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; @@ -7627,7 +7638,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); @@ -7648,7 +7659,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; @@ -7664,7 +7675,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; @@ -7679,7 +7690,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); @@ -7759,23 +7770,26 @@ 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; - R2_GLOBALS._player._characterScene[2] = 1550; + if ((R2_GLOBALS._player._characterScene[R2_QUINN] != 1550) && (R2_GLOBALS._player._characterScene[R2_QUINN] != 1580)) { + R2_GLOBALS._player._characterScene[R2_QUINN] = 1550; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1550; } _stripManager.setColors(60, 255); @@ -7786,14 +7800,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)); @@ -7802,7 +7817,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) { @@ -7817,21 +7832,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(); @@ -7841,29 +7857,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(); } @@ -7879,7 +7895,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 @@ -7920,14 +7936,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); @@ -7935,37 +7951,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); @@ -7979,29 +8000,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); @@ -8016,9 +8037,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); @@ -8029,13 +8049,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); @@ -8045,13 +8065,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); @@ -8115,7 +8135,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; @@ -8123,7 +8143,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; @@ -8131,19 +8151,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; @@ -8151,7 +8171,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; @@ -8159,7 +8179,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; @@ -8173,7 +8193,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(); @@ -8186,19 +8206,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; @@ -8230,11 +8248,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) { @@ -8266,12 +8284,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) { @@ -8289,12 +8308,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) { @@ -8312,14 +8332,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); @@ -8339,16 +8360,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); @@ -8373,7 +8398,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); @@ -8563,7 +8588,7 @@ void Scene1550::SceneActor1550::subA4D14(int frameNumber, int strip) { } -void Scene1550::subA2B2F() { +void Scene1550::enterArea() { Rect tmpRect; _field419 = 0; _field415 = 0; @@ -8571,19 +8596,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(); @@ -8592,18 +8617,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; @@ -8619,7 +8645,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; @@ -8627,7 +8653,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; @@ -8641,7 +8667,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; @@ -8655,7 +8681,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; @@ -8678,12 +8704,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 @@ -8696,7 +8722,7 @@ void Scene1550::subA2B2F() { break; case 5: varA = 1553; - _actor15.subA4D14(6, 0); + _northWall.subA4D14(6, 0); break; default: break; @@ -8705,14 +8731,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 @@ -8725,25 +8751,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 @@ -8756,11 +8782,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; @@ -8769,21 +8795,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; @@ -8831,71 +8858,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); @@ -8906,56 +8937,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; @@ -8963,24 +8995,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); @@ -8989,35 +9024,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: @@ -9056,20 +9092,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); @@ -9079,16 +9115,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); @@ -9107,48 +9143,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); @@ -9162,17 +9198,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); @@ -9186,55 +9222,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) { - 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.setPosition(Common::Point(k5A72E[k5A76D[_field419 - 1550]], k5A73F[k5A76D[_field419 - 1550]] + 8)); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + if (R2_GLOBALS._player._characterScene[R2_SEEKER] == 1580) { + _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]); + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 1580) { + _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); } } } @@ -9639,7 +9676,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); @@ -9658,7 +9695,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); @@ -9667,7 +9704,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); @@ -9687,15 +9724,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); @@ -9707,10 +9744,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(); @@ -9753,8 +9790,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; } @@ -9785,8 +9822,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; } @@ -9826,7 +9863,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)); @@ -9835,7 +9872,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)); @@ -9846,7 +9883,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)); @@ -9864,7 +9901,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 { @@ -9879,8 +9916,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)); @@ -9888,7 +9925,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)); @@ -9897,11 +9934,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() { @@ -9913,49 +9948,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) != 1580) { _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)); @@ -9981,17 +10016,8 @@ void Scene1580::signal() { * Scene 1625 - Miranda being questioned * *--------------------------------------------------------------------------*/ -Scene1625::Scene1625() { - _field412 = 0; -} -void Scene1625::synchronize(Serializer &s) { - SceneExt::synchronize(s); - - s.syncAsSint16LE(_field412); -} - -bool Scene1625::Actor7::startAction(CursorType action, Event &event) { +bool Scene1625::Wire::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); @@ -10000,10 +10026,20 @@ bool Scene1625::Actor7::startAction(CursorType action, Event &event) { scene->_sceneMode = 1631; scene->_actor3.postInit(); - scene->setAction(&scene->_sequenceManager, scene, 1631, &scene->_actor3, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1631, &scene->_actor3, &scene->_wire, NULL); return true; } +Scene1625::Scene1625() { + _field412 = 0; +} + +void Scene1625::synchronize(Serializer &s) { + SceneExt::synchronize(s); + + s.syncAsSint16LE(_field412); +} + void Scene1625::postInit(SceneObjectList *OwnerList) { loadScene(1625); R2_GLOBALS._player._characterIndex = R2_MIRANDA; @@ -10014,23 +10050,24 @@ void Scene1625::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_soldierSpeaker); R2_GLOBALS._player.postInit(); + R2_GLOBALS._player.hide(); - _actor7.postInit(); - _actor7.setup(1626, 2, 1); - _actor7.setPosition(Common::Point(206, 133)); - _actor7.setDetails(1625, 0, -1, -1, 1, (SceneItem *) NULL); + _wire.postInit(); + _wire.setup(1626, 2, 1); + _wire.setPosition(Common::Point(206, 133)); + _wire.setDetails(1625, 0, -1, -1, 1, (SceneItem *) NULL); _actor5.postInit(); _actor5.setup(1625, 8, 1); _actor5.setPosition(Common::Point(190, 131)); _actor5.setDetails(1625, 6, -1, 2, 1, (SceneItem *) NULL); - if (R2_GLOBALS._player._oldCharacterScene[3] == 1625) { + if (R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] == 1625) { if (!R2_GLOBALS.getFlag(83)) { - _actor4.postInit(); - _actor4.setup(1626, 4, 1); - _actor4.setPosition(Common::Point(96, 166)); - _actor4.setDetails(1625, -1, -1, -1, 1, (SceneItem *) NULL); + _glass.postInit(); + _glass.setup(1626, 4, 1); + _glass.setPosition(Common::Point(96, 166)); + _glass.setDetails(1625, -1, -1, -1, 1, (SceneItem *) NULL); } R2_GLOBALS._player.enableControl(); R2_GLOBALS._player._canWalk = false; @@ -10047,8 +10084,8 @@ void Scene1625::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(245); _item1.setDetails(Rect(0, 0, 320, 200), 1625, 12, -1, -1, 1, NULL); - R2_GLOBALS._player._oldCharacterScene[3] = 1625; - R2_GLOBALS._player._characterScene[3] = 1625; + R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] = 1625; + R2_GLOBALS._player._characterScene[R2_MIRANDA] = 1625; } void Scene1625::remove() { @@ -10060,70 +10097,69 @@ void Scene1625::signal() { switch (_sceneMode) { case 10: R2_GLOBALS._player.disableControl(); - _actor4.postInit(); - _actor4.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); + _glass.postInit(); + _glass.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); _sceneMode = 1626; - setAction(&_sequenceManager, this, 1626, &_actor2, &_actor4, NULL); + setAction(&_sequenceManager, this, 1626, &_tealHead, &_glass, NULL); break; case 12: - // TODO: check if OK_BTN_STRING is required MessageDialog::show(DONE_MSG, OK_BTN_STRING); break; case 14: - _actor2.postInit(); - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); + _tealHead.postInit(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(831, this); break; case 99: R2_GLOBALS._player.disableControl(); - switch (_stripManager._field2E8) { - case 0: + switch (_stripManager._exitMode) { + case 1: _sceneMode = 1627; - setAction(&_sequenceManager, this, 1627, &_actor3, &_actor4, NULL); + setAction(&_sequenceManager, this, 1627, &_actor3, &_glass, NULL); break; - case 1: + case 2: _sceneMode = 1629; - setAction(&_sequenceManager, this, 1629, &_actor2, &_actor5, NULL); + setAction(&_sequenceManager, this, 1629, &_tealHead, &_actor5, NULL); break; - case 3: - R2_GLOBALS._player._oldCharacterScene[3] = 3150; - R2_GLOBALS._player._characterScene[3] = 3150; + case 4: + R2_GLOBALS._player._oldCharacterScene[R2_MIRANDA] = 3150; + R2_GLOBALS._player._characterScene[R2_MIRANDA] = 3150; R2_GLOBALS._player._characterIndex = R2_QUINN; - R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._characterScene[1]); + R2_GLOBALS._sceneManager.changeScene(R2_GLOBALS._player._characterScene[R2_QUINN]); break; - case 4: + case 5: _sceneMode = 1628; - _actor2.remove(); - setAction(&_sequenceManager, this, 1628, &_actor3, &_actor4, NULL); + _tealHead.remove(); + setAction(&_sequenceManager, this, 1628, &_actor3, &_glass, NULL); break; - case 5: - _actor4.postInit(); - _actor4.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); + case 6: + _glass.postInit(); + _glass.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); _sceneMode = 1632; - setAction(&_sequenceManager, this, 1632, &_actor4, NULL); + setAction(&_sequenceManager, this, 1632, &_glass, NULL); break; - case 6: + case 7: _sceneMode = 1633; - setAction(&_sequenceManager, this, 1633, &_actor4, NULL); + setAction(&_sequenceManager, this, 1633, &_glass, NULL); break; - case 7: + case 8: _sceneMode = 1635; setAction(&_sequenceManager, this, 1635, &_actor3, &_actor5, NULL); break; - case 8: - _actor4.postInit(); - _actor4.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); + case 9: + _glass.postInit(); + _glass.setDetails(1625, -1, -1, -1, 2, (SceneItem *) NULL); _sceneMode = 1634; setAction(&_sequenceManager, this, 1634, &_actor3, &_actor5, NULL); break; - case 2: + case 3: // No break on purpose default: _sceneMode = 1630; - _actor2.postInit(); + _tealHead.remove(); setAction(&_sequenceManager, this, 1630, &_actor1, &_actor6, NULL); break; } @@ -10131,17 +10167,17 @@ void Scene1625::signal() { _stripManager._field2E8 = 0; break; case 1625: - _actor2.postInit(); - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); + _tealHead.postInit(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); _sceneMode = 10; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(800, this); break; case 1626: - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); - _actor2.show(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); + _tealHead.show(); _actor3.postInit(); _actor3.setup(1627, 3, 1); @@ -10162,9 +10198,9 @@ void Scene1625::signal() { break; case 1628: R2_GLOBALS.setFlag(83); - _actor2.postInit(); - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); + _tealHead.postInit(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); _actor3.setup(1627, 3, 1); _actor3.setPosition(Common::Point(196, 65)); @@ -10175,9 +10211,9 @@ void Scene1625::signal() { _stripManager.start(834, this); break; case 1629: - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); - _actor2.show(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); + _tealHead.show(); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); @@ -10192,30 +10228,29 @@ void Scene1625::signal() { _actor3.setPosition(Common::Point(196, 65)); _actor3.show(); - _actor7.remove(); + _wire.remove(); _actor1.postInit(); _actor1.fixPriority(10); _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); break; case 1632: - _actor2.setup(1627, 1, 1); - _actor2.setPosition(Common::Point(68, 68)); - _actor2.show(); + _tealHead.setup(1627, 1, 1); + _tealHead.setPosition(Common::Point(68, 68)); + _tealHead.show(); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(835, this); break; case 1633: - _actor4.remove(); + _glass.remove(); _sceneMode = 99; R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); _stripManager.start(818, this); @@ -10247,9 +10282,10 @@ void Scene1625::process(Event &event) { } /*-------------------------------------------------------------------------- - * Scene 1700 - + * Scene 1700 - Rim * *--------------------------------------------------------------------------*/ + Scene1700::Scene1700() { _field77A = 0; _field77C = 0; @@ -10268,7 +10304,7 @@ bool Scene1700::Item2::startAction(CursorType action, Event &event) { return SceneHotspot::startAction(action, event); } -bool Scene1700::Actor11::startAction(CursorType action, Event &event) { +bool Scene1700::RimTransport::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); @@ -10296,7 +10332,7 @@ bool Scene1700::Actor12::startAction(CursorType action, Event &event) { return true; } -void Scene1700::Exit1::changeScene() { +void Scene1700::NorthExit::changeScene() { Scene1700 *scene = (Scene1700 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); @@ -10308,7 +10344,7 @@ void Scene1700::Exit1::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene1700::Exit2::changeScene() { +void Scene1700::SouthExit::changeScene() { Scene1700 *scene = (Scene1700 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); @@ -10320,7 +10356,7 @@ void Scene1700::Exit2::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene1700::Exit3::changeScene() { +void Scene1700::WestExit::changeScene() { Scene1700 *scene = (Scene1700 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); @@ -10332,20 +10368,20 @@ void Scene1700::Exit3::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene1700::subAF3F8() { +void Scene1700::enterArea() { Rect tmpRect; R2_GLOBALS._walkRegions.load(1700); - _actor3.remove(); - _actor4.remove(); - _actor5.remove(); - _actor6.remove(); - _actor7.remove(); - _actor8.remove(); - _actor11.remove(); - + _slabWest.remove(); + _slabEast.remove(); + _slabShadowWest.remove(); + _slabShadowEast.remove(); + _westPlatform.remove(); + _rimTransportDoor.remove(); + _rimTransport.remove(); + if (_sceneMode != 40) { - _actor9.remove(); + _ledgeHopper.remove(); _actor10.remove(); } @@ -10361,68 +10397,72 @@ void Scene1700::subAF3F8() { warning("set_pane_p(_paneNumber);"); - if ((_sceneMode != 40) && (R2_GLOBALS._v565F6 != 0)){ - _actor9.postInit(); - _actor9.setup(1701, 1, 1); - _actor9.setPosition(Common::Point(220, 137)); - _actor9.setDetails(1700, 6, -1, -1, 2, (SceneItem *) NULL); + if (_sceneMode != 40 && R2_GLOBALS._rimLocation == 0) { + // Crashed ledge hopper + _ledgeHopper.postInit(); + _ledgeHopper.setup(1701, 1, 1); + _ledgeHopper.setPosition(Common::Point(220, 137)); + _ledgeHopper.setDetails(1700, 6, -1, -1, 2, (SceneItem *) NULL); R2_GLOBALS._walkRegions.enableRegion(2); R2_GLOBALS._walkRegions.enableRegion(12); } - if ((R2_GLOBALS._v565F6 + 2) % 4 == 0) { - _actor3.postInit(); - _actor3.setup(1700, 1, 1); - _actor3.setPosition(Common::Point(222, 82)); - _actor3.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); + if ((R2_GLOBALS._rimLocation + 2) % 4 == 0) { + // The slabs forming the bottom of the regular rings the rim transport travels through + _slabWest.postInit(); + _slabWest.setup(1700, 1, 1); + _slabWest.setPosition(Common::Point(222, 82)); + _slabWest.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); - _actor5.postInit(); - _actor5.setup(1700, 2, 1); - _actor5.setPosition(Common::Point(177, 82)); - _actor5.fixPriority(0); + _slabShadowWest.postInit(); + _slabShadowWest.setup(1700, 2, 1); + _slabShadowWest.setPosition(Common::Point(177, 82)); + _slabShadowWest.fixPriority(0); - _actor6.postInit(); - _actor6.setup(1700, 2, 2); - _actor6.setPosition(Common::Point(332, 96)); - _actor6.fixPriority(0); + _slabShadowEast.postInit(); + _slabShadowEast.setup(1700, 2, 2); + _slabShadowEast.setPosition(Common::Point(332, 96)); + _slabShadowEast.fixPriority(0); - _actor4.postInit(); - _actor4.setup(1700, 1, 2); - _actor4.setPosition(Common::Point(424, 84)); + _slabEast.postInit(); + _slabEast.setup(1700, 1, 2); + _slabEast.setPosition(Common::Point(424, 84)); R2_GLOBALS._walkRegions.enableRegion(11); } - if ((R2_GLOBALS._v565F6 + 399) % 800 == 0) { - _actor7.postInit(); - _actor7.setup(1700, 3, 2); - _actor7.setPosition(Common::Point(51, 141)); - _actor7.fixPriority(0); - _actor7.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); + if ((R2_GLOBALS._rimLocation + 399) % 800 == 0) { + // Enable west exit to lift + _westPlatform.postInit(); + _westPlatform.setup(1700, 3, 2); + _westPlatform.setPosition(Common::Point(51, 141)); + _westPlatform.fixPriority(0); + _westPlatform.setDetails(100, -1, -1, -1, 2, (SceneItem *) NULL); - _exit3._enabled = true; + _westExit._enabled = true; } else { R2_GLOBALS._walkRegions.enableRegion(1); - _exit3._enabled = false; + _westExit._enabled = false; } - if ( ((!R2_GLOBALS.getFlag(15)) && ((R2_GLOBALS._v565F6 == 25) || (R2_GLOBALS._v565F6 == -3))) - || ((R2_GLOBALS.getFlag(15)) && (R2_GLOBALS._v565F6 == R2_GLOBALS._v565FA)) + if ( ((!R2_GLOBALS.getFlag(15)) && ((R2_GLOBALS._rimLocation == 25) || (R2_GLOBALS._rimLocation == -3))) + || ((R2_GLOBALS.getFlag(15)) && (R2_GLOBALS._rimLocation == R2_GLOBALS._rimTransportLocation)) ) { - R2_GLOBALS._v565FA = R2_GLOBALS._v565F6; + // Rim transport vechile located + R2_GLOBALS._rimTransportLocation = R2_GLOBALS._rimLocation; if (!R2_GLOBALS.getFlag(15)) _field77C = 1; - _actor11.postInit(); - _actor11.setup(1700, 3, 1); - _actor11.setPosition(Common::Point(338, 150)); - _actor11.setDetails(1700, 9, -1, -1, 2, (SceneItem *) NULL); - _actor11.fixPriority(15); + _rimTransport.postInit(); + _rimTransport.setup(1700, 3, 1); + _rimTransport.setPosition(Common::Point(338, 150)); + _rimTransport.setDetails(1700, 9, -1, -1, 2, (SceneItem *) NULL); + _rimTransport.fixPriority(15); - _actor8.postInit(); - _actor8.setup(1700, 4, 1); - _actor8.setPosition(Common::Point(312, 106)); - _actor8.fixPriority(130); + _rimTransportDoor.postInit(); + _rimTransportDoor.setup(1700, 4, 1); + _rimTransportDoor.setPosition(Common::Point(312, 106)); + _rimTransportDoor.fixPriority(130); } } @@ -10436,12 +10476,9 @@ void Scene1700::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_quinnSpeaker); _stripManager.addSpeaker(&_seekerSpeaker); - _field77A = 0; - _field77C = 0; - - _exit1.setDetails(Rect(94, 0, 319, 12), EXITCURSOR_N, 1700); - _exit2.setDetails(Rect(0, 161, 319, 168), EXITCURSOR_S, 1700); - _exit3.setDetails(Rect(0, 0, 2, 138), EXITCURSOR_W, 1800); + _northExit.setDetails(Rect(94, 0, 319, 12), EXITCURSOR_N, 1700); + _southExit.setDetails(Rect(0, 161, 319, 168), EXITCURSOR_S, 1700); + _westExit.setDetails(Rect(0, 0, 12, 138), EXITCURSOR_W, 1800); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.setPosition(Common::Point(0, 0)); @@ -10506,14 +10543,14 @@ void Scene1700::postInit(SceneObjectList *OwnerList) { warning("_actor10._actorName = \"hatch\";"); _actor10.hide(); - _actor9.postInit(); - _actor9.setup(1701, 1, 1); - _actor9.setPosition(Common::Point(220, 137)); - _actor9.setDetails(1700, 6, -1, -1, 1, (SceneItem *) NULL); + _ledgeHopper.postInit(); + _ledgeHopper.setup(1701, 1, 1); + _ledgeHopper.setPosition(Common::Point(220, 137)); + _ledgeHopper.setDetails(1700, 6, -1, -1, 1, (SceneItem *) NULL); _actor1.hide(); _actor2.hide(); - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_WALK); _stripManager.start(539, this); _sceneMode = 40; break; @@ -10560,13 +10597,13 @@ void Scene1700::postInit(SceneObjectList *OwnerList) { setAction(&_sequenceManager, this, 1, &R2_GLOBALS._player, NULL); break; } - R2_GLOBALS._player._characterScene[1] = 1700; - R2_GLOBALS._player._characterScene[2] = 1700; - R2_GLOBALS._player._oldCharacterScene[1] = 1700; - R2_GLOBALS._player._oldCharacterScene[2] = 1700; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1700; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1700; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1700; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1700; R2_GLOBALS._v558B6.set(20, 0, 320, 200); - subAF3F8(); + enterArea(); _item1.setDetails(1, 1700, 3, -1, -1); _item2.setDetails(Rect(0, 0, 480, 200), 1700, 0, -1, -1, 1, NULL); } @@ -10580,9 +10617,9 @@ void Scene1700::signal() { switch (_sceneMode) { case 1: { _sceneMode = 3; - if ((R2_GLOBALS._v565F6 < 2400) && (R2_GLOBALS._v565F6 >= 0)) - ++R2_GLOBALS._v565F6; - subAF3F8(); + if (R2_GLOBALS._rimLocation < 2400) + ++R2_GLOBALS._rimLocation; + enterArea(); R2_GLOBALS._player.setPosition(Common::Point(235 - (((((235 - R2_GLOBALS._player._position.x) * 100) / 103) * 167) / 100), 170)); Common::Point pt(R2_GLOBALS._player._position.x, 160); NpcMover *mover = new NpcMover(); @@ -10605,9 +10642,9 @@ void Scene1700::signal() { break; case 2: { _sceneMode = 3; - if ((R2_GLOBALS._v565F6 > -2400) && (R2_GLOBALS._v565F6 < 0)) - R2_GLOBALS._v565F6--; - subAF3F8(); + if (R2_GLOBALS._rimLocation > -2400) + --R2_GLOBALS._rimLocation; + enterArea(); R2_GLOBALS._player.setPosition(Common::Point(235 - (((((235 - R2_GLOBALS._player._position.x) * 100) / 167) * 103) / 100), 0)); Common::Point pt(R2_GLOBALS._player._position.x, 10); NpcMover *mover = new NpcMover(); @@ -10630,12 +10667,12 @@ void Scene1700::signal() { break; case 3: if (_field77C == 0) { - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); } else { R2_GLOBALS.setFlag(15); _field77C = 0; _sceneMode = 31; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_WALK); if (R2_GLOBALS._player._characterIndex == R2_QUINN) _stripManager.start(542, this); else @@ -10647,10 +10684,10 @@ void Scene1700::signal() { Common::Point pt(271, 90); PlayerMover *mover = new PlayerMover(); _actor12.addMover(mover, &pt, NULL); - if (R2_GLOBALS._player._characterIndex == 1) - setAction(&_sequenceManager, this, 1700, &R2_GLOBALS._player, &_actor8, NULL); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) + setAction(&_sequenceManager, this, 1700, &R2_GLOBALS._player, &_rimTransportDoor, NULL); else - setAction(&_sequenceManager, this, 1701, &R2_GLOBALS._player, &_actor8, NULL); + setAction(&_sequenceManager, this, 1701, &R2_GLOBALS._player, &_rimTransportDoor, NULL); } break; case 5: @@ -10664,13 +10701,13 @@ void Scene1700::signal() { R2_GLOBALS._player._strip = 1; _actor12.setObjectWrapper(new SceneObjectWrapper()); _actor12._strip = 1; - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); R2_GLOBALS._walkRegions.enableRegion(14); break; case 8: R2_GLOBALS._player._strip = 2; _actor12._strip = 1; - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); R2_GLOBALS._walkRegions.enableRegion(12); break; case 30: @@ -10689,7 +10726,7 @@ void Scene1700::signal() { case 40: R2_GLOBALS._player.disableControl(); _sceneMode = 1704; - setAction(&_sequenceManager, this, 1704, &R2_GLOBALS._player, &_actor12, &_actor10, &_actor9, &_actor1, &_actor2, NULL); + setAction(&_sequenceManager, this, 1704, &R2_GLOBALS._player, &_actor12, &_actor10, &_ledgeHopper, &_actor1, &_actor2, NULL); break; case 50: if (R2_GLOBALS._player._characterIndex == R2_QUINN) @@ -10705,7 +10742,7 @@ void Scene1700::signal() { R2_GLOBALS._walkRegions.enableRegion(2); R2_GLOBALS._walkRegions.enableRegion(12); R2_GLOBALS._player.fixPriority(-1); - R2_GLOBALS._player.enableControl(CURSOR_ARROW); + R2_GLOBALS._player.enableControl(CURSOR_WALK); break; default: R2_GLOBALS._player.enableControl(); @@ -10714,162 +10751,171 @@ void Scene1700::signal() { } /*-------------------------------------------------------------------------- - * Scene 1750 - + * Scene 1750 - Maintaiance Vechile * *--------------------------------------------------------------------------*/ -Scene1750::Actor4::Actor4() { - _fieldA4 = 0; - _fieldA6 = 0; - _fieldA8 = 0; - _fieldAA = 0; - _fieldAC = 0; - _fieldAE = 0; + +Scene1750::Button::Button() { + _buttonId = 0; } -void Scene1750::Actor4::synchronize(Serializer &s) { +void Scene1750::Button::synchronize(Serializer &s) { SceneActor::synchronize(s); - s.syncAsSint16LE(_fieldA4); - s.syncAsSint16LE(_fieldA6); - s.syncAsSint16LE(_fieldA8); - s.syncAsSint16LE(_fieldAA); - s.syncAsSint16LE(_fieldAC); - s.syncAsSint16LE(_fieldAE); + s.syncAsSint16LE(_buttonId); } -Scene1750::Actor5::Actor5() { - _fieldA4 = 0; -} +bool Scene1750::Button::startAction(CursorType action, Event &event) { + if (action != CURSOR_USE) + return SceneActor::startAction(action, event); -void Scene1750::Actor5::synchronize(Serializer &s) { - SceneActor::synchronize(s); + Scene1750 *scene = (Scene1750 *)R2_GLOBALS._sceneManager._scene; - s.syncAsSint16LE(_fieldA4); + switch (_buttonId) { + case 1: + // Forward button + show(); + scene->_backwardButton.hide(); + if (scene->_speed < 0) + scene->_speed = -scene->_speed; + scene->_direction = 1; + break; + case 2: + // Backwards button + show(); + scene->_forwardButton.hide(); + if (scene->_speed > 0) + scene->_speed = -scene->_speed; + scene->_direction = -1; + break; + case 3: + // Exit button + if (scene->_rotation->_idxChange == 0) { + show(); + R2_GLOBALS._sceneManager.changeScene(1700); + } else { + scene->_speed = 0; + scene->_speedSlider._moveRate = 20; + scene->_forwardButton._moveDiff.y = 1; + Common::Point pt(286, 143); + NpcMover *mover = new NpcMover(); + scene->_speedSlider.addMover(mover, &pt, NULL); + } + default: + break; + } + + return true; } -Scene1750::Scene1750() { - _field412 = 0; - _field413 = 0; - _field415 = 0; - _field417 = 0; - _field419 = 0; - _field41B = 0; - _field41D = 0; +/*------------------------------------------------------------------------*/ + +Scene1750::SpeedSlider::SpeedSlider() { + _incrAmount = 0; + _xp = 0; + _ys = 0; + _height = 0; + _thumbHeight = 0; + _mouseDown = false; } -void Scene1750::synchronize(Serializer &s) { - SceneExt::synchronize(s); - SYNC_POINTER(_rotation); +void Scene1750::SpeedSlider::synchronize(Serializer &s) { + SceneActor::synchronize(s); - s.syncAsSint16LE(_field412); - s.syncAsSint16LE(_field413); - s.syncAsSint16LE(_field415); - s.syncAsSint16LE(_field417); - s.syncAsSint16LE(_field419); - s.syncAsSint16LE(_field41B); - s.syncAsSint16LE(_field41D); + s.syncAsSint16LE(_incrAmount); + s.syncAsSint16LE(_xp); + s.syncAsSint16LE(_ys); + s.syncAsSint16LE(_height); + s.syncAsSint16LE(_thumbHeight); + s.syncAsSint16LE(_mouseDown); } -void Scene1750::Actor4::subB1A76(int arg1, int arg2, int arg3, int arg4, int arg5) { - _fieldA4 = arg1; - _fieldAE = 0; - _fieldA6 = arg2; - _fieldA8 = arg3; - _fieldAA = arg4; - _fieldAC = arg5; +void Scene1750::SpeedSlider::setupSlider(int incrAmount, int xp, int ys, int height, int thumbHeight) { + _mouseDown = false; + _incrAmount = incrAmount; + _xp = xp; + _ys = ys; + _height = height; + _thumbHeight = thumbHeight; postInit(); setup(1750, 1, 1); fixPriority(255); - setPosition(Common::Point(_fieldA6, _fieldA8 + ((_fieldAA * (arg1 - 1)) / (_fieldAC - 1)))); + setPosition(Common::Point(_xp, _ys + ((_height * (incrAmount - 1)) / (_thumbHeight - 1)))); } -void Scene1750::Actor4::subB1B27() { +void Scene1750::SpeedSlider::calculateSlider() { Scene1750 *scene = (Scene1750 *)R2_GLOBALS._sceneManager._scene; - int tmpVar = (_fieldAA / (_fieldAC - 1)) / 2; - int tmpVar2 = ((_position.y - _fieldA8 + tmpVar) * _fieldAC) / (_fieldAA + 2 * tmpVar); + int tmpVar = (_height / (_thumbHeight - 1)) / 2; + int tmpVar2 = ((_position.y - _ys + tmpVar) * _thumbHeight) / (_height + 2 * tmpVar); - setPosition(Common::Point(_fieldA6, _fieldA8 + ((_fieldAA * tmpVar2) / (_fieldAC - 1)))); - scene->_field415 = scene->_field412 * tmpVar2; + setPosition(Common::Point(_xp, _ys + ((_height * tmpVar2) / (_thumbHeight - 1)))); + scene->_speed = scene->_direction * tmpVar2; } -void Scene1750::Actor4::remove() { +void Scene1750::SpeedSlider::remove() { // Function kept to match IDA. Could be removed. SceneActor::remove(); } -void Scene1750::Actor4::process(Event &event) { - if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == CURSOR_USE) && (_bounds.contains(event.mousePos))) { - _fieldAE = 1; +void Scene1750::SpeedSlider::process(Event &event) { + if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == CURSOR_USE) && + (_bounds.contains(event.mousePos))) { + _mouseDown = true; event.eventType = EVENT_NONE; } - if ((event.eventType == EVENT_BUTTON_UP) && (_fieldAE != 0)) { - _fieldAE = 0; + if ((event.eventType == EVENT_BUTTON_UP) && _mouseDown) { + _mouseDown = false; event.handled = true; addMover(NULL); - subB1B27(); + calculateSlider(); } - if (_fieldAE != 0) { + if (_mouseDown) { event.handled = true; - if (event.mousePos.y >= _fieldA8) { - if (_fieldA8 + _fieldAA >= event.mousePos.y) - setPosition(Common::Point(_fieldA6, event.mousePos.y)); + if (event.mousePos.y >= _ys) { + if (_ys + _height >= event.mousePos.y) + setPosition(Common::Point(_xp, event.mousePos.y)); else - setPosition(Common::Point(_fieldA6, _fieldA8 + _fieldAA)); + setPosition(Common::Point(_xp, _ys + _height)); } else { - setPosition(Common::Point(_fieldA6, _fieldA8)); + setPosition(Common::Point(_xp, _ys)); } } } -bool Scene1750::Actor4::startAction(CursorType action, Event &event) { +bool Scene1750::SpeedSlider::startAction(CursorType action, Event &event) { if (action == CURSOR_USE) return SceneActor::startAction(action, event); return false; } -bool Scene1750::Actor5::startAction(CursorType action, Event &event) { - if (action != CURSOR_USE) - return SceneActor::startAction(action, event); +/*------------------------------------------------------------------------*/ - Scene1750 *scene = (Scene1750 *)R2_GLOBALS._sceneManager._scene; +Scene1750::Scene1750() { + _direction = 0; + _field413 = 0; + _speed = 0; + _field417 = 0; + _field419 = 0; + _field41B = 0; + _field41D = 0; +} - switch (_fieldA4) { - case 1: - show(); - scene->_actor6.hide(); - if (scene->_field415 < 0) - scene->_field415 ^= 0xFFFE; - scene->_field412 = 1; - break; - case 2: - show(); - scene->_actor5.hide(); - if (scene->_field415 > 0) - scene->_field415 ^= 0xFFFE; - scene->_field412 = -1; - break; - case 3: - if (scene->_rotation->_idxChange == 0) { - show(); - R2_GLOBALS._sceneManager.changeScene(1700); - } else { - scene->_field415 = 0; - scene->_actor4._moveRate = 20; - scene->_actor5._moveDiff.y = 1; - Common::Point pt(286, 143); - NpcMover *mover = new NpcMover(); - scene->_actor4.addMover(mover, &pt, NULL); - } - default: - break; - } +void Scene1750::synchronize(Serializer &s) { + SceneExt::synchronize(s); + SYNC_POINTER(_rotation); - return true; + s.syncAsSint16LE(_direction); + s.syncAsSint16LE(_field413); + s.syncAsSint16LE(_speed); + s.syncAsSint16LE(_field417); + s.syncAsSint16LE(_field419); + s.syncAsSint16LE(_field41B); + s.syncAsSint16LE(_field41D); } void Scene1750::postInit(SceneObjectList *OwnerList) { @@ -10879,17 +10925,17 @@ void Scene1750::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._v5589E.set(0, 0, 320, 200); SceneExt::postInit(); - R2_GLOBALS._player._characterScene[1] = 1750; - R2_GLOBALS._player._characterScene[2] = 1750; - R2_GLOBALS._player._oldCharacterScene[1] = 1750; - R2_GLOBALS._player._oldCharacterScene[2] = 1750; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1750; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1750; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1750; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1750; _rotation = R2_GLOBALS._scenePalette.addRotation(224, 254, 1); _rotation->setDelay(0); _rotation->_idxChange = 0; _rotation->_countdown = 2; - switch ((R2_GLOBALS._v565F6 + 2) % 4) { + switch ((R2_GLOBALS._rimLocation + 2) % 4) { case 0: _rotation->_currIndex = 247; break; @@ -10935,7 +10981,7 @@ void Scene1750::postInit(SceneObjectList *OwnerList) { _actor1.postInit(); _actor1.setup(1750, 2, 1); - _actor1.setPosition(Common::Point(35, ((_rotation->_currIndex - 218) % 4) + ((R2_GLOBALS._v565F6 % 800) * 4) - 1440)); + _actor1.setPosition(Common::Point(35, ((_rotation->_currIndex - 218) % 4) + ((R2_GLOBALS._rimLocation % 800) * 4) - 1440)); _actor1.fixPriority(8); _actor2.postInit(); @@ -10950,51 +10996,49 @@ void Scene1750::postInit(SceneObjectList *OwnerList) { else _actor2.setPosition(Common::Point(148, (tmpVar * 7) + 122)); - _actor4.subB1A76(1, 286, 143, 41, 15); - _actor4.setDetails(1750, 24, 1, -1, 1, (SceneItem *) NULL); - - _actor5.postInit(); - _actor5._fieldA4 = 1; - _actor5.setup(1750, 1, 2); - _actor5.setPosition(Common::Point(192, 140)); - _actor5.setDetails(1750, 18, 1, -1, 1, (SceneItem *) NULL); - - _actor6.postInit(); - _actor6._fieldA4 = 2; - _actor6.setup(1750, 1, 3); - _actor6.setPosition(Common::Point(192, 163)); - _actor6.setDetails(1750, 18, 1, -1, 1, (SceneItem *) NULL); - _actor6.hide(); - - _actor7.postInit(); - _actor7._fieldA4 = 3; - _actor7.setup(1750, 1, 5); - _actor7.setPosition(Common::Point(230, 183)); - _actor7.setDetails(1750, 27, 1, -1, 1, (SceneItem *) NULL); - - _field412 = 1; + _speedSlider.setupSlider(1, 286, 143, 41, 15); + _speedSlider.setDetails(1750, 24, 1, -1, 1, (SceneItem *) NULL); + + _forwardButton.postInit(); + _forwardButton._buttonId = 1; + _forwardButton.setup(1750, 1, 2); + _forwardButton.setPosition(Common::Point(192, 140)); + _forwardButton.setDetails(1750, 18, 1, -1, 1, (SceneItem *) NULL); + + _backwardButton.postInit(); + _backwardButton._buttonId = 2; + _backwardButton.setup(1750, 1, 3); + _backwardButton.setPosition(Common::Point(192, 163)); + _backwardButton.setDetails(1750, 18, 1, -1, 1, (SceneItem *) NULL); + _backwardButton.hide(); + + _exitButton.postInit(); + _exitButton._buttonId = 3; + _exitButton.setup(1750, 1, 5); + _exitButton.setPosition(Common::Point(230, 183)); + _exitButton.setDetails(1750, 27, 1, -1, 1, (SceneItem *) NULL); + + _direction = 1; // Forward by default _field417 = 0; _field413 = 0; - _field415 = 0; + _speed = 0; _field419 = ((_rotation->_currIndex - 218) / 4) % 4; - _item2.setDetails(Rect(129, 112, 155, 175), 1750, 21, -1, -1, 1, NULL); - _item3.setDetails(Rect(93, 122, 126, 172), 1750, 15, -1, -1, 1, NULL); - _item4.setDetails(Rect(3, 3, 157, 99), 1750, 9, -1, -1, 1, NULL); - _item5.setDetails(Rect(162, 3, 316, 99), 1750, 12, -1, -1, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 1750, 6, 1, -1, 1, NULL); + _redLights.setDetails(Rect(129, 112, 155, 175), 1750, 21, -1, -1, 1, NULL); + _greenLights.setDetails(Rect(93, 122, 126, 172), 1750, 15, -1, -1, 1, NULL); + _frontView.setDetails(Rect(3, 3, 157, 99), 1750, 9, -1, -1, 1, NULL); + _rearView.setDetails(Rect(162, 3, 316, 99), 1750, 12, -1, -1, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 1750, 6, 1, -1, 1, NULL); } void Scene1750::remove() { - _rotation->remove(); - - if (R2_GLOBALS._v565F6 == 2400) - R2_GLOBALS._v565F6 = 2399; + if (R2_GLOBALS._rimLocation == 2400) + R2_GLOBALS._rimLocation = 2399; - if (R2_GLOBALS._v565F6 == -2400) - R2_GLOBALS._v565F6 = -2399; + if (R2_GLOBALS._rimLocation == -2400) + R2_GLOBALS._rimLocation = -2399; - R2_GLOBALS._v565FA = R2_GLOBALS._v565F6; + R2_GLOBALS._rimTransportLocation = R2_GLOBALS._rimLocation; SceneExt::remove(); R2_GLOBALS._sound1.fadeOut2(NULL); @@ -11010,26 +11054,95 @@ void Scene1750::signal() { void Scene1750::process(Event &event) { Scene::process(event); if (!event.handled) - _actor4.process(event); + _speedSlider.process(event); } -void Scene1750::dispatch() {} +void Scene1750::dispatch() { + if (_rotation) { + if (!_field417 && (_speed != _field413)) { + if (_field413 >= _speed) + --_field413; + else + ++_field413; + + _field417 = 21 - ABS(_field413); + } + + if (_field417 == 1) { + if (_field413 == 0) { + _actor3.show(); + _rotation->_idxChange = 0; + } else { + if (_rotation->_idxChange == 0) + _actor3.hide(); + + if (_field413 < -12) { + _rotation->setDelay(15 - ABS(_field413)); + _rotation->_idxChange = -2; + } else if (_field413 < 0) { + _rotation->setDelay(10 - ABS(_field413)); + _rotation->_idxChange = -1; + } else if (_field413 < 11) { + _rotation->setDelay(10 - _field413); + _rotation->_idxChange = 1; + } else { + _rotation->setDelay(15 - _field413); + _rotation->_idxChange = 2; + } + } + } + + if (_field417) + --_field417; + + _field41B = _field419; + _field419 = ((_rotation->_currIndex - 218) / 4) / 4; + + if ((_field41B + 1) == _field419 || (_field41B - 3) == _field419) { + if (R2_GLOBALS._rimLocation < 2400) { + ++R2_GLOBALS._rimLocation; + } + } + + if ((_field41B - 1) == _field419 || (_field41B + 3) == _field419) { + if (R2_GLOBALS._rimLocation > -2400) { + --R2_GLOBALS._rimLocation; + } + } + + if (_rotation->_currIndex != _field41D) { + _field41D = _rotation->_currIndex; + _actor1.setPosition(Common::Point(35, ((_rotation->_currIndex - 218) % 4) + + ((R2_GLOBALS._rimLocation % 800) * 4) - 1440)); + } + } + + int v = ABS(_actor1._position.y - 158) / 100; + if (v < 8) { + _actor2.show(); + _actor2.setPosition(Common::Point((_actor1._position.y <= 158) ? 137 : 148, + v * 7 + 122)); + } else { + _actor2.hide(); + } +} /*-------------------------------------------------------------------------- - * Scene 1800 - + * Scene 1800 - Rim Lift Exterior * *--------------------------------------------------------------------------*/ + Scene1800::Scene1800() { - _field412 = 0; + _locationMode = 0; } void Scene1800::synchronize(Serializer &s) { SceneExt::synchronize(s); - s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_locationMode); } -bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { +bool Scene1800::Background::startAction(CursorType action, Event &event) { if ((action != R2_COM_SCANNER) && (action != R2_COM_SCANNER_2)) return false; @@ -11038,7 +11151,7 @@ bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - if (R2_GLOBALS._v565F6 == 1201) { + if (R2_GLOBALS._rimLocation == 1201) { scene->_stripManager.start(548, this); } else if (R2_GLOBALS.getFlag(66)) { return false; @@ -11046,7 +11159,7 @@ bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { scene->_stripManager.start(546, this); } } else { - if (R2_GLOBALS._v565F6 == 1201) { + if (R2_GLOBALS._rimLocation == 1201) { scene->_stripManager.start(549, this); } else if (R2_GLOBALS.getFlag(66)) { return false; @@ -11059,7 +11172,7 @@ bool Scene1800::Hotspot5::startAction(CursorType action, Event &event) { return true; } -bool Scene1800::Actor6::startAction(CursorType action, Event &event) { +bool Scene1800::Lever::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); @@ -11075,31 +11188,34 @@ bool Scene1800::Actor6::startAction(CursorType action, Event &event) { if (_frame == 1) { R2_GLOBALS.setFlag(64); scene->_sceneMode = 1810; - scene->setAction(&scene->_sequenceManager, scene, 1810, &R2_GLOBALS._player, &scene->_actor6, &scene->_actor4, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1810, &R2_GLOBALS._player, &scene->_lever, &scene->_leftStaircase, &scene->_rightStaircase, NULL); } else { R2_GLOBALS.clearFlag(64); scene->_sceneMode = 1811; - scene->setAction(&scene->_sequenceManager, scene, 1811, &R2_GLOBALS._player, &scene->_actor6, &scene->_actor4, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1811, &R2_GLOBALS._player, &scene->_lever, &scene->_leftStaircase, &scene->_rightStaircase, NULL); } return true; } -bool Scene1800::Actor7::startAction(CursorType action, Event &event) { +bool Scene1800::Doors::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); Scene1800 *scene = (Scene1800 *)R2_GLOBALS._sceneManager._scene; if (R2_GLOBALS._player._characterIndex == R2_SEEKER) { + // Seeker trying to force open the door R2_GLOBALS._player.disableControl(); - if (scene->_field412 >= 2) { + if (scene->_locationMode >= 2) { if (R2_GLOBALS.getFlag(14)) { + // Allow door to close scene->_sceneMode = 1809; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { + // Force open door scene->_sceneMode = 1808; - scene->setAction(&scene->_sequenceManager, scene, 1808, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1808, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.setFlag(14); } } else { @@ -11109,6 +11225,7 @@ bool Scene1800::Actor7::startAction(CursorType action, Event &event) { } else if (R2_GLOBALS.getFlag(14)) { return SceneActor::startAction(action, event); } else { + // Quinn trying to force open doors R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1812; scene->setAction(&scene->_sequenceManager, scene, 1812, &R2_GLOBALS._player, NULL); @@ -11117,40 +11234,40 @@ bool Scene1800::Actor7::startAction(CursorType action, Event &event) { return true; } -bool Scene1800::Actor8::startAction(CursorType action, Event &event) { +bool Scene1800::PassengerDoor::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneActor::startAction(action, event); Scene1800 *scene = (Scene1800 *)R2_GLOBALS._sceneManager._scene; if (_position.x < 160) { - if (scene->_actor4._frame == 1) { + if (scene->_leftStaircase._frame == 1) { return SceneActor::startAction(action, event); } else { R2_GLOBALS.setFlag(29); R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(14)) { - scene->_sceneMode = 1804; - scene->setAction(&scene->_sequenceManager, scene, 1804, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor8, NULL); - } else { scene->_sceneMode = 1; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_companion, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); + } else { + scene->_sceneMode = 1804; + scene->setAction(&scene->_sequenceManager, scene, 1804, &R2_GLOBALS._player, &scene->_companion, &scene->_leftDoor, NULL); } } else { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 1; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1805; - scene->setAction(&scene->_sequenceManager, scene, 1805, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor8, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1805, &R2_GLOBALS._player, &scene->_companion, &scene->_leftDoor, NULL); } } } } else { - if (scene->_actor4._frame == 1) { + if (scene->_leftStaircase._frame == 1) { return SceneActor::startAction(action, event); } else { R2_GLOBALS.clearFlag(29); @@ -11158,20 +11275,20 @@ bool Scene1800::Actor8::startAction(CursorType action, Event &event) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 2; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_companion, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1806; - scene->setAction(&scene->_sequenceManager, scene, 1806, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor9, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1806, &R2_GLOBALS._player, &scene->_companion, &scene->_rightDoor, NULL); } } else { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 2; - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1807; - scene->setAction(&scene->_sequenceManager, scene, 1807, &R2_GLOBALS._player, &scene->_actor2, &scene->_actor9, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1807, &R2_GLOBALS._player, &scene->_companion, &scene->_rightDoor, NULL); } } } @@ -11189,16 +11306,16 @@ void Scene1800::Exit1::changeScene() { if (R2_GLOBALS.getFlag(14)) { scene->_sceneMode = 3; if (R2_GLOBALS._player._characterIndex == R2_QUINN) - scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_companion, &scene->_doors, NULL); else - scene->setAction(&scene->_sequenceManager, scene, 1809, &scene->_actor2, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1809, &R2_GLOBALS._player, &scene->_doors, NULL); R2_GLOBALS.clearFlag(14); } else { scene->_sceneMode = 1802; if (R2_GLOBALS._player._characterIndex == R2_QUINN) - scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_companion, NULL); else - scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager, scene, 1802, &R2_GLOBALS._player, &scene->_companion, NULL); } } @@ -11210,95 +11327,98 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_seekerSpeaker); if (R2_GLOBALS._sceneManager._previousScene == -1) - R2_GLOBALS._v565F6 = 1201; + R2_GLOBALS._rimLocation = 1201; - if (R2_GLOBALS._v565F6 == 1201) - _field412 = 2; + // Set the mode based on whether this is the "correct" lift or not + if (R2_GLOBALS._rimLocation == 1201) + _locationMode = 2; else - _field412 = 0; + _locationMode = 0; scalePalette(65, 65, 65); _exit1.setDetails(Rect(0, 160, 319, 168), EXITCURSOR_S, 1800); - _item5.setDetails(Rect(0, 0, 320, 200), -1, -1, -1, -1, 1, NULL); - - _actor6.postInit(); - _actor6.setup(1801, 4, 1); - _actor6.setPosition(Common::Point(170, 24)); - _actor6.setDetails(1800, 13, 14, 15, 1, (SceneItem *) NULL); - - _actor7.postInit(); - _actor7.setup(1801, 3, 1); - _actor7.setPosition(Common::Point(160, 139)); - _actor7.setDetails(1800, 6, -1, -1, 1, (SceneItem *) NULL); - - _actor8.postInit(); - _actor8.setup(1800, 1, 1); - _actor8.setPosition(Common::Point(110, 78)); - _actor8.fixPriority(135); - _actor8.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); - - _actor9.postInit(); - _actor9.setup(1800, 2, 1); - _actor9.setPosition(Common::Point(209, 78)); - _actor9.fixPriority(135); - _actor9.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); - - _actor4.postInit(); - if ((_field412 != 1) && (_field412 != 3) && (!R2_GLOBALS.getFlag(64))) - _actor4.setup(1801, 2, 1); + _background.setDetails(Rect(0, 0, 320, 200), -1, -1, -1, -1, 1, NULL); + + _lever.postInit(); + _lever.setup(1801, 4, 1); + _lever.setPosition(Common::Point(170, 124)); + _lever.setDetails(1800, 13, 14, 15, 1, (SceneItem *) NULL); + + _doors.postInit(); + _doors.setup(1801, 3, 1); + _doors.setPosition(Common::Point(160, 139)); + _doors.setDetails(1800, 6, -1, -1, 1, (SceneItem *) NULL); + + _leftDoor.postInit(); + _leftDoor.setup(1800, 1, 1); + _leftDoor.setPosition(Common::Point(110, 78)); + _leftDoor.fixPriority(135); + _leftDoor.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); + + _rightDoor.postInit(); + _rightDoor.setup(1800, 2, 1); + _rightDoor.setPosition(Common::Point(209, 78)); + _rightDoor.fixPriority(135); + _rightDoor.setDetails(1800, 20, -1, -1, 1, (SceneItem *) NULL); + + _leftStaircase.postInit(); + if ((_locationMode != 1) && (_locationMode != 3) && (!R2_GLOBALS.getFlag(64))) + _leftStaircase.setup(1801, 2, 1); else - _actor4.setup(1801, 2, 10); - _actor4.setPosition(Common::Point(76, 142)); - _actor4.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); + _leftStaircase.setup(1801, 2, 10); + _leftStaircase.setPosition(Common::Point(76, 142)); + _leftStaircase.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); - _actor5.postInit(); - if ((_field412 != 1) && (_field412 != 3) && (!R2_GLOBALS.getFlag(64))) - _actor5.setup(1801, 1, 1); + _rightStaircase.postInit(); + if ((_locationMode != 1) && (_locationMode != 3) && (!R2_GLOBALS.getFlag(64))) + _rightStaircase.setup(1801, 1, 1); else - _actor5.setup(1801, 1, 10); - _actor5.setPosition(Common::Point(243, 142)); - _actor5.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); + _rightStaircase.setup(1801, 1, 10); + _rightStaircase.setPosition(Common::Point(243, 142)); + _rightStaircase.setDetails(1800, 3, -1, -1, 1, (SceneItem *) NULL); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + // Standard Quinn setup + R2_GLOBALS._player.setVisage(1503); + R2_GLOBALS._player._moveDiff = Common::Point(2, 2); + } else { + // Seeker setup dependent on whether he's holding the doors or not if (R2_GLOBALS.getFlag(14)) { R2_GLOBALS._player.animate(ANIM_MODE_NONE, NULL); R2_GLOBALS._player.setObjectWrapper(NULL); R2_GLOBALS._player.setup(1801, 5, 12); R2_GLOBALS._player.setPosition(Common::Point(160, 139)); R2_GLOBALS._walkRegions.enableRegion(9); - _actor7.hide(); + _doors.hide(); } else { R2_GLOBALS._player.setVisage(1507); } R2_GLOBALS._player._moveDiff = Common::Point(4, 2); - } else { - R2_GLOBALS._player.setVisage(1503); - R2_GLOBALS._player._moveDiff = Common::Point(2, 2); } - _actor2.postInit(); - _actor2.animate(ANIM_MODE_1, NULL); - _actor2.setObjectWrapper(new SceneObjectWrapper()); + _companion.postInit(); + _companion.animate(ANIM_MODE_1, NULL); + _companion.setObjectWrapper(new SceneObjectWrapper()); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(14)) { - _actor2.animate(ANIM_MODE_NONE, NULL); - _actor2.setObjectWrapper(NULL); - _actor2.setup(1801, 5, 12); + _companion.animate(ANIM_MODE_NONE, NULL); + _companion.setObjectWrapper(NULL); + _companion.setup(1801, 5, 12); R2_GLOBALS._walkRegions.enableRegion(9); - _actor7.hide(); + _doors.hide(); } else { - _actor2.setup(1507, 1, 1); - _actor2.setPosition(Common::Point(180, 160)); + _companion.setup(1507, 1, 1); + _companion.setPosition(Common::Point(180, 160)); } - _actor2.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); - _actor2._moveDiff = Common::Point(4, 2); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + _companion._moveDiff = Common::Point(4, 2); } else { - _actor2.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); - _actor2.setVisage(1503); - _actor2._moveDiff = Common::Point(2, 2); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _companion.setVisage(1503); + _companion._moveDiff = Common::Point(2, 2); } if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1800) { @@ -11306,11 +11426,11 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setPosition(Common::Point(114, 150)); R2_GLOBALS._player.setStrip(5); if (R2_GLOBALS.getFlag(14)) { - _actor2.setPosition(Common::Point(160, 139)); + _companion.setPosition(Common::Point(160, 139)); R2_GLOBALS._walkRegions.enableRegion(8); } else { - _actor2.setPosition(Common::Point(209, 150)); - _actor2.setStrip(6); + _companion.setPosition(Common::Point(209, 150)); + _companion.setStrip(6); R2_GLOBALS._walkRegions.enableRegion(8); } } else { @@ -11321,18 +11441,18 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setPosition(Common::Point(209, 150)); R2_GLOBALS._player.setStrip(6); } - _actor2.setPosition(Common::Point(114, 150)); - _actor2.setStrip(5); + _companion.setPosition(Common::Point(114, 150)); + _companion.setStrip(5); R2_GLOBALS._walkRegions.enableRegion(10); R2_GLOBALS._walkRegions.enableRegion(11); } } else { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.setPosition(Common::Point(140, 160)); - _actor2.setPosition(Common::Point(180, 160)); + _companion.setPosition(Common::Point(180, 160)); } else { R2_GLOBALS._player.setPosition(Common::Point(180, 160)); - _actor2.setPosition(Common::Point(140, 160)); + _companion.setPosition(Common::Point(140, 160)); } } @@ -11358,10 +11478,10 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { _actor3._effect = 5; _actor3._field9C = _field312; - _actor2._linkedActor = &_actor3; + _companion._linkedActor = &_actor3; - R2_GLOBALS._player._characterScene[1] = 1800; - R2_GLOBALS._player._characterScene[2] = 1800; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1800; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1800; _item2.setDetails(Rect(128, 95, 190, 135), 1800, 10, -1, -1, 1, NULL); _item1.setDetails(Rect(95, 3, 223, 135), 1800, 0, -1, -1, 1, NULL); @@ -11383,32 +11503,32 @@ void Scene1800::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS.getFlag(29)) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1814; - setAction(&_sequenceManager, this, 1814, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1814, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } else { _sceneMode = 1815; - setAction(&_sequenceManager, this, 1815, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1815, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } } else { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1816; - setAction(&_sequenceManager, this, 1816, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1816, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { _sceneMode = 1817; - setAction(&_sequenceManager, this, 1817, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1817, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } } } else { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1800; - setAction(&_sequenceManager, this, 1800, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1800, &R2_GLOBALS._player, &_companion, NULL); } else { _sceneMode = 1801; - setAction(&_sequenceManager, this, 1801, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1801, &R2_GLOBALS._player, &_companion, NULL); } } - R2_GLOBALS._player._oldCharacterScene[1] = 1800; - R2_GLOBALS._player._oldCharacterScene[2] = 1800; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1800; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1800; } void Scene1800::signal() { @@ -11416,27 +11536,27 @@ void Scene1800::signal() { case 1: if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1804; - setAction(&_sequenceManager, this, 1804, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1804, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } else { _sceneMode = 1805; - setAction(&_sequenceManager, this, 1805, &R2_GLOBALS._player, &_actor2, &_actor8, NULL); + setAction(&_sequenceManager, this, 1805, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } break; case 2: if (R2_GLOBALS._player._characterIndex == R2_QUINN) { _sceneMode = 1806; - setAction(&_sequenceManager, this, 1806, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1806, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { _sceneMode = 1807; - setAction(&_sequenceManager, this, 1807, &R2_GLOBALS._player, &_actor2, &_actor9, NULL); + setAction(&_sequenceManager, this, 1807, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } break; case 3: _sceneMode = 1802; if (R2_GLOBALS._player._characterIndex == R2_QUINN) - setAction(&_sequenceManager, this, 1802, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1802, &R2_GLOBALS._player, &_companion, NULL); else - setAction(&_sequenceManager, this, 1803, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager, this, 1803, &R2_GLOBALS._player, &_companion, NULL); break; case 10: // No break on purpose @@ -11506,7 +11626,7 @@ void Scene1800::signal() { break; case 1808: _sceneMode = 12; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_WALK); _stripManager.start(553, this); break; case 1812: @@ -11540,18 +11660,11 @@ void Scene1800::saveCharacter(int characterIndex) { } /*-------------------------------------------------------------------------- - * Scene 1850 - + * Scene 1850 - Rim Lift Interior * *--------------------------------------------------------------------------*/ -Scene1850::Scene1850() { - warning("STUBBED: Scene1850()"); -} -void Scene1850::synchronize(Serializer &s) { - warning("STUBBED: Scene1850::synchronize()"); -} - -bool Scene1850::Hotspot2::startAction(CursorType action, Event &event) { +bool Scene1850::Button::startAction(CursorType action, Event &event) { if (action != CURSOR_USE) return SceneHotspot::startAction(action, event); @@ -11569,9 +11682,9 @@ bool Scene1850::Hotspot2::startAction(CursorType action, Event &event) { scene->_sceneMode = 1860; if (R2_GLOBALS.getFlag(32)) - scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_robot, NULL); else - scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_robot, NULL); R2_GLOBALS.clearFlag(30); } else { @@ -11586,21 +11699,21 @@ bool Scene1850::Hotspot2::startAction(CursorType action, Event &event) { return true; } -bool Scene1850::Actor5::startAction(CursorType action, Event &event) { +bool Scene1850::Robot::startAction(CursorType action, Event &event) { Scene1850 *scene = (Scene1850 *)R2_GLOBALS._sceneManager._scene; switch (action) { case CURSOR_USE: - if ((R2_GLOBALS._player._characterIndex != R2_SEEKER) || (R2_GLOBALS.getFlag(33)) || (R2_GLOBALS.getFlag(30))) + if ((R2_GLOBALS._player._characterIndex != R2_SEEKER) || R2_GLOBALS.getFlag(33) || R2_GLOBALS.getFlag(30)) return SceneActor::startAction(action, event); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1857; if (R2_GLOBALS.getFlag(32)) - scene->setAction(&scene->_sequenceManager1, scene, 1858, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1858, &R2_GLOBALS._player, &scene->_robot, NULL); else - scene->setAction(&scene->_sequenceManager1, scene, 1857, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1857, &R2_GLOBALS._player, &scene->_robot, NULL); R2_GLOBALS.setFlag(30); return true; @@ -11619,7 +11732,7 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 30; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + R2_GLOBALS._events.setCursor(CURSOR_WALK); scene->_stripManager.start(558, scene); return true; @@ -11639,8 +11752,8 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { return true; } else if (R2_GLOBALS.getFlag(70)) { R2_GLOBALS._player.disableControl(); - scene->_sceneMode = 30; - R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); + scene->_sceneMode = 20; + R2_GLOBALS._events.setCursor(CURSOR_WALK); scene->_stripManager.start(557, scene); R2_GLOBALS.setFlag(69); @@ -11656,7 +11769,7 @@ bool Scene1850::Actor5::startAction(CursorType action, Event &event) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1878; - scene->setAction(&scene->_sequenceManager1, scene, 1878, &R2_GLOBALS._player, &scene->_actor5, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1878, &R2_GLOBALS._player, &scene->_robot, &scene->_actor2, NULL); } return true; @@ -11696,23 +11809,23 @@ bool Scene1850::Actor6::startAction(CursorType action, Event &event) { scene->_sceneMode = 1860; if (R2_GLOBALS.getFlag(32)) { - scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1860, &R2_GLOBALS._player, &scene->_robot, NULL); } else { - scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_actor5, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1859, &R2_GLOBALS._player, &scene->_robot, NULL); } } else { scene->_sceneMode = 11; if (_position.x >= 160) { - scene->setAction(&scene->_sequenceManager1, scene, 1866, &R2_GLOBALS._player, &scene->_actor7, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1866, &R2_GLOBALS._player, &scene->_rightDoor, NULL); } else { - scene->setAction(&scene->_sequenceManager1, scene, 1865, &R2_GLOBALS._player, &scene->_actor6, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1865, &R2_GLOBALS._player, &scene->_leftDoor, NULL); } } return true; } -bool Scene1850::Actor8::startAction(CursorType action, Event &event) { +bool Scene1850::DisplayScreen::startAction(CursorType action, Event &event) { if ((action != CURSOR_USE) || (_position.y != 120)) return SceneHotspot::startAction(action, event); @@ -11730,6 +11843,28 @@ bool Scene1850::Actor8::startAction(CursorType action, Event &event) { return true; } +/*------------------------------------------------------------------------*/ + +Scene1850::Scene1850() { + _field412 = 0; + _field414 = 0; + _field416 = 0; + _field418 = 0; + _field41E = 0; +} + +void Scene1850::synchronize(Serializer &s) { + SceneExt::synchronize(s); + + s.syncAsSint16LE(_field412); + s.syncAsSint16LE(_field414); + s.syncAsSint16LE(_field416); + s.syncAsSint16LE(_field418); + s.syncAsSint16LE(_field41E); + s.syncAsSint16LE(_field41A.x); + s.syncAsSint16LE(_field41A.y); +} + void Scene1850::postInit(SceneObjectList *OwnerList) { loadScene(1850); @@ -11758,62 +11893,62 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { _field41E = 0; _field41A = Common::Point(0, 0); - R2_GLOBALS._player._characterScene[1] = 1850; - R2_GLOBALS._player._characterScene[2] = 1850; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1850; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1850; - _item2.setDetails(Rect(101, 56, 111, 63), 1850, 19, -1, -1, 1, NULL); + _button.setDetails(Rect(101, 56, 111, 63), 1850, 19, -1, -1, 1, NULL); - _actor6.postInit(); - _actor6.setup(1850, 3, 1); - _actor6.setPosition(Common::Point(66, 102)); - _actor6.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); + _leftDoor.postInit(); + _leftDoor.setup(1850, 3, 1); + _leftDoor.setPosition(Common::Point(66, 102)); + _leftDoor.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); - _actor7.postInit(); - _actor7.setup(1850, 2, 1); - _actor7.setPosition(Common::Point(253, 102)); - _actor7.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); + _rightDoor.postInit(); + _rightDoor.setup(1850, 2, 1); + _rightDoor.setPosition(Common::Point(253, 102)); + _rightDoor.setDetails(1850, 22, -1, -1, 1, (SceneItem *) NULL); R2_GLOBALS._walkRegions.enableRegion(1); - _actor5.postInit(); + _robot.postInit(); if (R2_GLOBALS.getFlag(34)) { R2_GLOBALS._walkRegions.enableRegion(2); - _actor5.setup(1851, 4, 3); + _robot.setup(1851, 4, 3); } else if (R2_GLOBALS.getFlag(30)) { - _actor5.setup(1851, 2, 2); + _robot.setup(1851, 2, 2); } else { R2_GLOBALS._walkRegions.enableRegion(5); if (R2_GLOBALS.getFlag(33)) { R2_GLOBALS._walkRegions.enableRegion(2); - _actor5.setup(1851, 1, 3); + _robot.setup(1851, 1, 3); } else { - _actor5.setup(1851, 2, 1); + _robot.setup(1851, 2, 1); } } - _actor5.setPosition(Common::Point(219, 130)); - _actor5.fixPriority(114); - _actor5.setDetails(1850, -1, -1, -1, 1, (SceneItem *) NULL); + _robot.setPosition(Common::Point(219, 130)); + _robot.fixPriority(114); + _robot.setDetails(1850, -1, -1, -1, 1, (SceneItem *) NULL); R2_GLOBALS._player.postInit(); - _actor1.postInit(); + _companion.postInit(); if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *) NULL); } else { - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *) NULL); } if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1850) { R2_GLOBALS._player._effect = 6; - _actor1._effect = 6; + _companion._effect = 6; if (R2_GLOBALS.getFlag(31)) { R2_GLOBALS._player._shade = 0; - _actor1._shade = 0; + _companion._shade = 0; } else { R2_GLOBALS._player._shade = 6; - _actor1._shade = 6; + _companion._shade = 6; } if (R2_INVENTORY.getObjectScene(R2_AIRBAG) == 1850) { @@ -11827,7 +11962,7 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { _actor2.setPosition(Common::Point(179, 113)); - if ((_actor5._strip == 1) && (_actor5._frame == 3)){ + if ((_robot._strip == 1) && (_robot._frame == 3)){ _actor2.hide(); } @@ -11837,7 +11972,7 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(32)) { R2_GLOBALS._player.setVisage(1511); - _actor1.setVisage(1508); + _companion.setVisage(1508); _actor3.postInit(); _actor3.setup(1853, 3, 1); @@ -11876,12 +12011,12 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { } } else { R2_GLOBALS._player.setVisage(1500); - _actor1.setVisage(1505); + _companion.setVisage(1505); } } else { // Not Quinn if (R2_GLOBALS.getFlag(32)) { R2_GLOBALS._player.setVisage(1508); - _actor1.setVisage(1511); + _companion.setVisage(1511); _actor3.postInit(); _actor3.setup(1853, 3, 1); @@ -11920,7 +12055,7 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { } } else { R2_GLOBALS._player.setVisage(1505); - _actor1.setVisage(1500); + _companion.setVisage(1500); } } @@ -11928,25 +12063,25 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setStrip(3); R2_GLOBALS._player.setPosition(Common::Point(80, 114)); - _actor1.animate(ANIM_MODE_1, NULL); - _actor1.setObjectWrapper(new SceneObjectWrapper()); - _actor1.setStrip(3); - _actor1.setPosition(Common::Point(180, 96)); + _companion.animate(ANIM_MODE_1, NULL); + _companion.setObjectWrapper(new SceneObjectWrapper()); + _companion.setStrip(3); + _companion.setPosition(Common::Point(180, 96)); if (R2_GLOBALS.getFlag(30)) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - _actor1.animate(ANIM_MODE_NONE, NULL); - _actor1.setObjectWrapper(NULL); + _companion.animate(ANIM_MODE_NONE, NULL); + _companion.setObjectWrapper(NULL); if (R2_GLOBALS.getFlag(32)) { - _actor1.setup(1854, 1, 3); + _companion.setup(1854, 1, 3); } else { - _actor1.setup(1854, 2, 3); + _companion.setup(1854, 2, 3); } - _actor1.setPosition(Common::Point(164, 106)); + _companion.setPosition(Common::Point(164, 106)); } else { - _actor1.animate(ANIM_MODE_NONE, NULL); - _actor1.setObjectWrapper(NULL); + _companion.animate(ANIM_MODE_NONE, NULL); + _companion.setObjectWrapper(NULL); if (R2_GLOBALS.getFlag(32)) { R2_GLOBALS._player.setup(1854, 1, 3); } else { @@ -11960,57 +12095,57 @@ void Scene1850::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.enableControl(); } else { // R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] != 1850 R2_GLOBALS._player._effect = 1; - _actor1._effect = 1; + _companion._effect = 1; R2_GLOBALS._player.disableControl(); _sceneMode = 10; if (R2_GLOBALS._player._characterIndex == R2_QUINN) { if (R2_GLOBALS.getFlag(29)) { - setAction(&_sequenceManager1, this, 1863, &R2_GLOBALS._player, &_actor1, &_actor7, NULL); + setAction(&_sequenceManager1, this, 1863, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { - setAction(&_sequenceManager1, this, 1861, &R2_GLOBALS._player, &_actor1, &_actor6, NULL); + setAction(&_sequenceManager1, this, 1861, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } } else { if (R2_GLOBALS.getFlag(29)) { - setAction(&_sequenceManager1, this, 1864, &R2_GLOBALS._player, &_actor1, &_actor7, NULL); + setAction(&_sequenceManager1, this, 1864, &R2_GLOBALS._player, &_companion, &_rightDoor, NULL); } else { - setAction(&_sequenceManager1, this, 1862, &R2_GLOBALS._player, &_actor1, &_actor6, NULL); + setAction(&_sequenceManager1, this, 1862, &R2_GLOBALS._player, &_companion, &_leftDoor, NULL); } } } if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player._moveDiff = Common::Point(3, 2); - _actor1._moveDiff = Common::Point(5, 3); + _companion._moveDiff = Common::Point(5, 3); } else { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); - _actor1._moveDiff = Common::Point(3, 2); + _companion._moveDiff = Common::Point(3, 2); } - _actor8.postInit(); - _actor8.setup(1850, 1, 1); + _displayScreen.postInit(); + _displayScreen.setup(1850, 1, 1); if (R2_GLOBALS.getFlag(62)) { - _actor8.setPosition(Common::Point(159, 120)); + _displayScreen.setPosition(Common::Point(159, 120)); } else { - _actor8.setPosition(Common::Point(159, 184)); + _displayScreen.setPosition(Common::Point(159, 184)); } - _actor8.fixPriority(113); + _displayScreen.fixPriority(113); if (R2_GLOBALS.getFlag(34)) { - _actor8.setDetails(1850, 25, -1, -1, 4, &_actor5); + _displayScreen.setDetails(1850, 25, -1, -1, 4, &_robot); } else { - _actor8.setDetails(1850, 25, -1, -1, 2, (SceneItem *) NULL); + _displayScreen.setDetails(1850, 25, -1, -1, 2, (SceneItem *) NULL); } if (!R2_GLOBALS.getFlag(62)) { - _actor8.hide(); + _displayScreen.hide(); } - _item1.setDetails(Rect(0, 0, 320, 200), 1850, 16, -1, -1, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 1850, 16, -1, -1, 1, NULL); - R2_GLOBALS._player._oldCharacterScene[1] = 1850; - R2_GLOBALS._player._oldCharacterScene[2] = 1850; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1850; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1850; } void Scene1850::remove() { @@ -12029,8 +12164,8 @@ void Scene1850::signal() { R2_GLOBALS._player._effect = 6; R2_GLOBALS._player._shade = 6; - _actor1._effect = 6; - _actor1._shade = 6; + _companion._effect = 6; + _companion._shade = 6; R2_GLOBALS._walkRegions.enableRegion(5); @@ -12052,7 +12187,7 @@ void Scene1850::signal() { break; case 16: _sceneMode = 1870; - setAction(&_sequenceManager1, this, 1870, &R2_GLOBALS._player, &_actor1, &_actor3, &_actor4, NULL); + setAction(&_sequenceManager1, this, 1870, &R2_GLOBALS._player, &_companion, &_actor3, &_actor4, NULL); break; case 20: R2_GLOBALS._player.enableControl(CURSOR_TALK); @@ -12060,7 +12195,7 @@ void Scene1850::signal() { case 21: R2_GLOBALS._player.disableControl(); _sceneMode = 1877; - setAction(&_sequenceManager1, this, 1877, &R2_GLOBALS._player, &_actor1, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1877, &R2_GLOBALS._player, &_companion, &_robot, NULL); break; case 30: R2_GLOBALS._player.disableControl(); @@ -12082,14 +12217,14 @@ void Scene1850::signal() { _field418 = 1; if (R2_GLOBALS.getFlag(30)) { - _actor8.setAction(&_sequenceManager2, NULL, 1867, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, NULL, 1867, &_displayScreen, NULL); } else if (R2_GLOBALS.getFlag(34)) { if (R2_GLOBALS.getFlag(62)) { R2_GLOBALS.clearFlag(62); - _actor8.setAction(&_sequenceManager2, this, 1851, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, this, 1851, &_displayScreen, NULL); } else { R2_GLOBALS.setFlag(62); - _actor8.setAction(&_sequenceManager2, this, 1850, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, this, 1850, &_displayScreen, NULL); } } else if (R2_GLOBALS.getFlag(33)) { R2_GLOBALS.setFlag(62); @@ -12097,13 +12232,13 @@ void Scene1850::signal() { R2_GLOBALS._walkRegions.enableRegion(2); _actor2.postInit(); - _actor2.setDetails(1850, 6, -1, -1, 5, &_actor5); + _actor2.setDetails(1850, 6, -1, -1, 5, &_robot); _sceneMode = 1879; - _actor8.setAction(&_sequenceManager2, this, 1879, &_actor5, &_actor8, &_actor2, NULL); + _displayScreen.setAction(&_sequenceManager2, this, 1879, &_robot, &_displayScreen, &_actor2, NULL); } else { - _actor8.setAction(&_sequenceManager2, NULL, 1867, &_actor8, NULL); + _displayScreen.setAction(&_sequenceManager2, NULL, 1867, &_displayScreen, NULL); } if (R2_GLOBALS.getFlag(34)) @@ -12152,7 +12287,7 @@ void Scene1850::signal() { case 1858: R2_GLOBALS._player.disableControl(); _sceneMode = 1859; - setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_robot, NULL); R2_GLOBALS.clearFlag(30); break; case 1859: @@ -12182,12 +12317,11 @@ void Scene1850::signal() { break; case 2: _sceneMode = 11; - setAction(&_sequenceManager1, this, 1865, &R2_GLOBALS._player, &_actor6, NULL); + setAction(&_sequenceManager1, this, 1865, &R2_GLOBALS._player, &_leftDoor, NULL); break; case 3: - warning("_field41E == 3"); _sceneMode = 11; - setAction(&_sequenceManager1, this, 1866, &R2_GLOBALS._player, &_actor7, NULL); + setAction(&_sequenceManager1, this, 1866, &R2_GLOBALS._player, &_rightDoor, NULL); break; default: break; @@ -12237,7 +12371,7 @@ void Scene1850::signal() { R2_GLOBALS.clearFlag(30); _sceneMode = 15; setAction(&_sequenceManager1, this, 1869, &R2_GLOBALS._player, &_actor3, NULL); - setAction(&_sequenceManager2, this, 1868, &_actor1, &_actor4, NULL); + _companion.setAction(&_sequenceManager2, this, 1868, &_companion, &_actor4, NULL); break; case 1878: R2_INVENTORY.setObjectScene(R2_REBREATHER_TANK, 1850); @@ -12268,9 +12402,9 @@ void Scene1850::process(Event &event) { R2_GLOBALS._player.disableControl(); _sceneMode = 1860; if (R2_GLOBALS.getFlag(32)) { - setAction(&_sequenceManager1, this, 1860, &R2_GLOBALS._player, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1860, &R2_GLOBALS._player, &_robot, NULL); } else { - setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_actor5, NULL); + setAction(&_sequenceManager1, this, 1859, &R2_GLOBALS._player, &_robot, NULL); } R2_GLOBALS.clearFlag(32); event.handled = true; @@ -12292,8 +12426,8 @@ void Scene1850::dispatch() { } R2_GLOBALS._player._flags |= OBJFLAG_PANES; - _actor1._shade = R2_GLOBALS._player._shade; - _actor1._flags |= OBJFLAG_PANES; + _companion._shade = R2_GLOBALS._player._shade; + _companion._flags |= OBJFLAG_PANES; _actor3._shade = R2_GLOBALS._player._shade; _actor3._flags |= OBJFLAG_PANES; @@ -12303,46 +12437,47 @@ void Scene1850::dispatch() { } if (R2_GLOBALS.getFlag(32)) { - _actor3.setPosition(Common::Point(_actor8._position.x - 37, _actor8._position.y - 71)); - _actor4.setPosition(Common::Point(_actor8._position.x - 20, _actor8._position.y - 73)); + _actor3.setPosition(Common::Point(_displayScreen._position.x - 37, _displayScreen._position.y - 71)); + _actor4.setPosition(Common::Point(_displayScreen._position.x - 20, _displayScreen._position.y - 73)); } if (R2_INVENTORY.getObjectScene(R2_AIRBAG) == 1850) { - _actor2.setPosition(Common::Point(_actor8._position.x + 20, _actor8._position.y - 71)); + _actor2.setPosition(Common::Point(_displayScreen._position.x + 20, _displayScreen._position.y - 71)); } Scene::dispatch(); } /*-------------------------------------------------------------------------- - * Scene 1875 - + * Scene 1875 - Rim Lift Computer * *--------------------------------------------------------------------------*/ -Scene1875::Actor1875::Actor1875() { - _fieldA4 = 0; - _fieldA6 = 0; + +Scene1875::Button::Button() { + _buttonId = 0; + _buttonDown = false; } -void Scene1875::Actor1875::synchronize(Serializer &s) { +void Scene1875::Button::synchronize(Serializer &s) { SceneActor::synchronize(s); - s.syncAsSint16LE(_fieldA4); - s.syncAsSint16LE(_fieldA6); + s.syncAsSint16LE(_buttonId); + s.syncAsSint16LE(_buttonDown); } -void Scene1875::Actor1875::subB84AB() { +void Scene1875::Button::doButtonPress() { Scene1875 *scene = (Scene1875 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._sound1.play(227); int newFrameNumber; - switch (_fieldA4) { + switch (_buttonId) { case 3: - if ((scene->_actor1._frame == 1) && (scene->_actor4._strip == 2)) { + if ((scene->_actor1._frame == 1) && (scene->_button1._strip == 2)) { R2_GLOBALS._player.disableControl(); R2_GLOBALS._events.setCursor(CURSOR_CROSSHAIRS); scene->_sceneMode = 10; - scene->_stripManager.start(576, this); + scene->_stripManager.start(576, scene); } else { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 1890; @@ -12367,32 +12502,32 @@ void Scene1875::Actor1875::subB84AB() { } } -void Scene1875::Actor1875::subB8271(int indx) { +void Scene1875::Button::initButton(int buttonId) { postInit(); - _fieldA4 = indx; - _fieldA6 = 0; + _buttonId = buttonId; + _buttonDown = false; setVisage(1855); - if (_fieldA4 == 1) + if (_buttonId == 1) setStrip(2); else setStrip(1); - setFrame(_fieldA4); - switch (_fieldA4 - 1) { - case 0: + setFrame(_buttonId); + switch (_buttonId) { + case 1: setPosition(Common::Point(20, 144)); break; - case 1: + case 2: setPosition(Common::Point(82, 144)); break; - case 2: + case 3: setPosition(Common::Point(136, 144)); break; - case 3: + case 4: setPosition(Common::Point(237, 144)); break; - case 4: + case 5: setPosition(Common::Point(299, 144)); break; default: @@ -12402,36 +12537,37 @@ void Scene1875::Actor1875::subB8271(int indx) { setDetails(1875, 6, 1, -1, 2, (SceneItem *) NULL); } -void Scene1875::Actor1875::process(Event &event) { - if ((R2_GLOBALS._player._uiEnabled) || (event.handled)) +void Scene1875::Button::process(Event &event) { + if (!R2_GLOBALS._player._uiEnabled || event.handled) return; Scene1875 *scene = (Scene1875 *)R2_GLOBALS._sceneManager._scene; - if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == R2_STEPPING_DISKS) && (_bounds.contains(event.mousePos)) && (_fieldA6 == 0)) { + if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._events.getCursor() == CURSOR_USE) + && (_bounds.contains(event.mousePos)) && !_buttonDown) { setStrip(2); - switch (_fieldA4) { + switch (_buttonId) { case 1: R2_GLOBALS._sound2.play(227); - scene->_actor5.setStrip(1); + scene->_button2.setStrip(1); break; case 2: R2_GLOBALS._sound2.play(227); - scene->_actor4.setStrip(1); + scene->_button1.setStrip(1); break; default: break; } - _fieldA6 = 1; + _buttonDown = true; event.handled = true; } - if ((event.eventType == EVENT_BUTTON_UP) && (_fieldA6 != 0)) { - if ((_fieldA4 == 3) || (_fieldA4 == 4) || (_fieldA4 == 5)) { + if ((event.eventType == EVENT_BUTTON_UP) && _buttonDown) { + if ((_buttonId == 3) || (_buttonId == 4) || (_buttonId == 5)) { setStrip(1); - subB84AB(); + doButtonPress(); } - _fieldA6 = 0; + _buttonDown = false; event.handled = true; } } @@ -12440,32 +12576,36 @@ void Scene1875::postInit(SceneObjectList *OwnerList) { loadScene(1875); SceneExt::postInit(); - R2_GLOBALS._player._characterScene[1] = 1875; - R2_GLOBALS._player._characterScene[2] = 1875; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1875; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1875; _stripManager.addSpeaker(&_quinnSpeaker); _stripManager.addSpeaker(&_seekerSpeaker); - _actor4.subB8271(1); - _actor5.subB8271(2); - _actor6.subB8271(3); - _actor7.subB8271(4); - _actor8.subB8271(5); + _button1.initButton(1); + _button2.initButton(2); + _button3.initButton(3); + _button4.initButton(4); + _button5.initButton(5); _actor1.postInit(); _actor1.setup(1855, 4, 1); _actor1.setPosition(Common::Point(160, 116)); R2_GLOBALS._player.postInit(); + R2_GLOBALS._player.hide(); + if (R2_GLOBALS._sceneManager._previousScene == 1625) { R2_GLOBALS._sound1.play(122); R2_GLOBALS._player.disableControl(); _sceneMode = 11; _actor2.postInit(); setAction(&_sequenceManager, this, 1892, &_actor2, NULL); - } else if (R2_GLOBALS._sceneManager._previousScene == 3150) { - R2_GLOBALS._sound1.play(116); } else { + if (R2_GLOBALS._sceneManager._previousScene == 3150) { + R2_GLOBALS._sound1.play(116); + } + R2_GLOBALS._player.enableControl(); R2_GLOBALS._player._canWalk = false; } @@ -12473,10 +12613,10 @@ void Scene1875::postInit(SceneObjectList *OwnerList) { _item2.setDetails(Rect(43, 14, 275, 122), 1875, 9, 1, -1, 1, NULL); _item1.setDetails(Rect(0, 0, 320, 200), 1875, 3, -1, -1, 1, NULL); - R2_GLOBALS._player._characterScene[1] = 1875; - R2_GLOBALS._player._characterScene[2] = 1875; - R2_GLOBALS._player._oldCharacterScene[1] = 1875; - R2_GLOBALS._player._oldCharacterScene[2] = 1875; + R2_GLOBALS._player._characterScene[R2_QUINN] = 1875; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1875; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1875; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1875; } void Scene1875::signal() { @@ -12515,18 +12655,19 @@ void Scene1875::signal() { void Scene1875::process(Event &event) { Scene::process(event); - _actor4.process(event); - _actor5.process(event); - _actor6.process(event); - _actor7.process(event); - _actor8.process(event); + _button1.process(event); + _button2.process(event); + _button3.process(event); + _button4.process(event); + _button5.process(event); } /*-------------------------------------------------------------------------- - * Scene 1900 - + * Scene 1900 - Spill Mountains Elevator Exit * *--------------------------------------------------------------------------*/ -bool Scene1900::Actor2::startAction(CursorType action, Event &event) { + +bool Scene1900::LiftDoor::startAction(CursorType action, Event &event) { Scene1900 *scene = (Scene1900 *)R2_GLOBALS._sceneManager._scene; if (action != CURSOR_USE) @@ -12543,17 +12684,17 @@ bool Scene1900::Actor2::startAction(CursorType action, Event &event) { if (_position.x >= 160) { scene->_sceneMode = 1905; - scene->setAction(&scene->_sequenceManager1, scene, 1905, &R2_GLOBALS._player, &scene->_actor3, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1905, &R2_GLOBALS._player, &scene->_rightDoor, NULL); } else { R2_GLOBALS.setFlag(29); scene->_sceneMode = 1904; - scene->setAction(&scene->_sequenceManager1, scene, 1904, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager1, scene, 1904, &R2_GLOBALS._player, &scene->_leftDoor, NULL); } return true; } -void Scene1900::Exit1::changeScene() { +void Scene1900::WestExit::changeScene() { Scene1900 *scene = (Scene1900 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(CURSOR_ARROW); @@ -12564,7 +12705,7 @@ void Scene1900::Exit1::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene1900::Exit2::changeScene() { +void Scene1900::EastExit::changeScene() { Scene1900 *scene = (Scene1900 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(CURSOR_ARROW); @@ -12584,7 +12725,7 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene == -1) { R2_GLOBALS._sceneManager._previousScene = 1925; R2_GLOBALS._player._characterIndex = R2_SEEKER; - R2_GLOBALS._player._oldCharacterScene[2] = 1925; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1925; } if (R2_GLOBALS._sceneManager._previousScene != 1875) @@ -12594,11 +12735,11 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { _stripManager.setFontNumber(3); _stripManager.addSpeaker(&_seekerSpeaker); - _exit1.setDetails(Rect(0, 105, 14, 145), R2_COM_SCANNER, 2000); - _exit1.setDest(Common::Point(14, 135)); + _westExit.setDetails(Rect(0, 105, 14, 145), EXITCURSOR_W, 2000); + _westExit.setDest(Common::Point(14, 135)); - _exit2.setDetails(Rect(305, 105, 320, 145), R2_SPENT_POWER_CAPSULE, 2000); - _exit2.setDest(Common::Point(315, 135)); + _eastExit.setDetails(Rect(305, 105, 320, 145), EXITCURSOR_E, 2000); + _eastExit.setDest(Common::Point(315, 135)); R2_GLOBALS._player.postInit(); if (R2_GLOBALS._player._characterIndex == R2_QUINN) @@ -12615,24 +12756,24 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene != 1925) R2_GLOBALS.clearFlag(29); - _actor2.postInit(); - _actor2.setup(1901, 1, 1); - _actor2.setPosition(Common::Point(95, 109)); - _actor2.fixPriority(100); + _leftDoor.postInit(); + _leftDoor.setup(1901, 1, 1); + _leftDoor.setPosition(Common::Point(95, 109)); + _leftDoor.fixPriority(100); if (R2_GLOBALS._player._characterIndex == R2_QUINN) - _actor2.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); + _leftDoor.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); else - _actor2.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); + _leftDoor.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); - _actor3.postInit(); - _actor3.setup(1901, 2, 1); - _actor3.setPosition(Common::Point(225, 109)); - _actor3.fixPriority(100); + _rightDoor.postInit(); + _rightDoor.setup(1901, 2, 1); + _rightDoor.setPosition(Common::Point(225, 109)); + _rightDoor.fixPriority(100); if (R2_GLOBALS._player._characterIndex == R2_QUINN) - _actor3.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); + _rightDoor.setDetails(1900, 0, 1, 2, 1, (SceneItem *) NULL); else - _actor3.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); + _rightDoor.setDetails(1900, 0, 1, -1, 1, (SceneItem *) NULL); if (R2_GLOBALS._sceneManager._previousScene != 1875) { _object1.postInit(); @@ -12650,26 +12791,26 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._characterIndex = R2_QUINN; _actor1.postInit(); _sceneMode = 20; - R2_GLOBALS._player.setAction(&_sequenceManager1, NULL, 1901, &R2_GLOBALS._player, &_actor2, NULL); - _actor1.setAction(&_sequenceManager2, this, 1900, &_actor1, &_actor3, NULL); + R2_GLOBALS._player.setAction(&_sequenceManager1, NULL, 1901, &R2_GLOBALS._player, &_leftDoor, NULL); + _actor1.setAction(&_sequenceManager2, this, 1900, &_actor1, &_rightDoor, NULL); } else if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1925) { if (R2_GLOBALS.getFlag(29)) { R2_GLOBALS.clearFlag(29); - _actor2.hide(); + _leftDoor.hide(); R2_GLOBALS._player.setStrip(6); R2_GLOBALS._player.setPosition(Common::Point(90, 106)); _sceneMode = 1906; - setAction(&_sequenceManager1, this, 1906, &R2_GLOBALS._player, &_actor2, NULL); + setAction(&_sequenceManager1, this, 1906, &R2_GLOBALS._player, &_leftDoor, NULL); } else { - _actor3.hide(); + _rightDoor.hide(); R2_GLOBALS._player.setStrip(5); R2_GLOBALS._player.setPosition(Common::Point(230, 106)); _sceneMode = 1907; - setAction(&_sequenceManager1, this, 1907, &R2_GLOBALS._player, &_actor3, NULL); + setAction(&_sequenceManager1, this, 1907, &R2_GLOBALS._player, &_rightDoor, NULL); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); _actor1.setPosition(Common::Point(30, 110)); R2_GLOBALS._walkRegions.enableRegion(1); @@ -12677,21 +12818,23 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { _actor1.setDetails(9001, 0, -1, -1, 1, (SceneItem *) NULL); } R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 1900; - } else if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { - _actor1.postInit(); - _actor1.setPosition(Common::Point(30, 110)); - R2_GLOBALS._walkRegions.enableRegion(1); - if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - _actor1.setup(20, 3, 1); - _actor1.setDetails(9002, 1, -1, -1, 1, (SceneItem *) NULL); - } else { - _actor1.setup(2008, 3, 1); - _actor1.setDetails(9001, 0, -1, -1, 1, (SceneItem *) NULL); + } else { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { + _actor1.postInit(); + _actor1.setPosition(Common::Point(30, 110)); + R2_GLOBALS._walkRegions.enableRegion(1); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + _actor1.setup(20, 3, 1); + _actor1.setDetails(9002, 1, -1, -1, 1, (SceneItem *) NULL); + } else { + _actor1.setup(2008, 3, 1); + _actor1.setDetails(9001, 0, -1, -1, 1, (SceneItem *) NULL); + } } if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2000) { if (R2_GLOBALS._player._characterIndex == R2_QUINN) { - if (R2_GLOBALS._v56605[1] == 5) { + if (R2_GLOBALS._spillLocation[R2_QUINN] == 5) { _sceneMode = 1902; setAction(&_sequenceManager1, this, 1902, &R2_GLOBALS._player, NULL); } else { @@ -12699,7 +12842,7 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { setAction(&_sequenceManager1, this, 1903, &R2_GLOBALS._player, NULL); } } else { - if (R2_GLOBALS._v56605[2] == 5) { + if (R2_GLOBALS._spillLocation[R2_SEEKER] == 5) { _sceneMode = 1908; setAction(&_sequenceManager1, this, 1908, &R2_GLOBALS._player, NULL); } else { @@ -12714,8 +12857,8 @@ void Scene1900::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 1900; } - _item2.setDetails(Rect(77, 2, 240, 103), 1900, 6, -1, -1, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 1900, 3, -1, -1, 1, NULL); + _elevator.setDetails(Rect(77, 2, 240, 103), 1900, 6, -1, -1, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 1900, 3, -1, -1, 1, NULL); } void Scene1900::remove() { @@ -12726,11 +12869,11 @@ void Scene1900::remove() { void Scene1900::signal() { switch (_sceneMode) { case 10: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 5; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 5; R2_GLOBALS._sceneManager.changeScene(2000); break; case 11: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 6; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 6; R2_GLOBALS._sceneManager.changeScene(2000); break; case 20: @@ -12758,10 +12901,10 @@ 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; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1900; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1900; R2_GLOBALS._sceneManager.changeScene(2450); break; case 1906: @@ -12988,7 +13131,7 @@ void Scene1925::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(220); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.disableControl(); - R2_GLOBALS._player._characterScene[2] = 1925; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1925; R2_GLOBALS._player._characterIndex = R2_SEEKER; switch (R2_GLOBALS._scene1925CurrLevel) { case -2: @@ -13047,7 +13190,7 @@ void Scene1925::postInit(SceneObjectList *OwnerList) { void Scene1925::remove() { R2_GLOBALS._sound1.fadeOut2(NULL); - R2_GLOBALS._player._oldCharacterScene[2] = 1925; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1925; SceneExt::remove(); } @@ -13255,7 +13398,7 @@ void Scene1945::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.postInit(); R2_GLOBALS._player.enableControl(CURSOR_USE); R2_GLOBALS._player._canWalk = false; - R2_GLOBALS._player._characterScene[2] = 1945; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 1945; R2_GLOBALS._player._characterIndex = R2_SEEKER; _exitUp.setDetails(Rect(128, 0, 186, 10), EXITCURSOR_N, 1945); @@ -13508,7 +13651,6 @@ void Scene1950::Area1::remove() { _areaActor.remove(); SceneArea::remove(); R2_GLOBALS._insetUp--; - // if (!R2_GLOBALS.getFlag(37)) R2_GLOBALS._sound2.play(278); @@ -13528,7 +13670,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; @@ -13536,19 +13678,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(); } } @@ -13609,14 +13748,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; @@ -13885,7 +14024,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(); @@ -13893,7 +14032,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); @@ -14204,7 +14343,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); @@ -14722,7 +14861,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); @@ -14758,7 +14897,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); @@ -14789,7 +14928,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); @@ -14808,7 +14947,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 { @@ -15023,8 +15162,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); @@ -15127,7 +15266,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; @@ -15158,7 +15297,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); @@ -15173,7 +15312,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); @@ -15193,7 +15332,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 eaca667377..82895c7ab0 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes1.h +++ b/engines/tsage/ringworld2/ringworld2_scenes1.h @@ -46,8 +46,8 @@ public: SpeakerGameText _gameTextSpeaker; AnimationPlayer _animationPlayer; - int _field412; - int _fieldD2E; + int _animCounter; + bool _forceCheckAnimationFl; public: Scene1000(); @@ -89,7 +89,7 @@ class Scene1100 : public SceneExt { }; public: - int _field412, _field414; + int _nextStripNum, _paletteRefreshStatus; SpeakerSeeker1100 _seekerSpeaker; SpeakerQuinn1100 _quinnSpeaker; SpeakerChief1100 _chiefSpeaker; @@ -103,20 +103,20 @@ public: NamedHotspot _item7; SceneActor _actor1; SceneActor _actor2; - SceneActor _actor3; - SceneActor _actor4; - SceneActor _actor5; - SceneActor _actor6; - SceneActor _actor7; - SceneActor _actor8; - SceneActor _actor9; - SceneActor _actor10; - SceneActor _actor11; - SceneActor _actor12; - SceneActor _actor13; - SceneActor _actor14; - SceneActor _actor15; - BackgroundSceneObject _object1; + SceneActor _shipFormation; + SceneActor _shipFormationShadow; + SceneActor _shotImpact1; + SceneActor _shotImpact2; + SceneActor _shotImpact3; + SceneActor _shotImpact4; + SceneActor _shotImpact5; + SceneActor _laserShot; + SceneActor _animation; + SceneActor _leftImpacts; + SceneActor _runningGuy1; + SceneActor _runningGuy2; + SceneActor _runningGuy3; + BackgroundSceneObject _rightLandslide; BackgroundSceneObject _object2; Seeker _seeker; Trooper _trooper; @@ -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(); @@ -687,7 +687,7 @@ public: }; class Scene1625 : public SceneExt { - class Actor7 : public SceneActor { + class Wire : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -698,12 +698,12 @@ public: SpeakerSoldier1625 _soldierSpeaker; NamedHotspot _item1; SceneActor _actor1; - SceneActor _actor2; + SceneActor _tealHead; SceneActor _actor3; - SceneActor _actor4; + SceneActor _glass; SceneActor _actor5; SceneActor _actor6; - Actor7 _actor7; + Wire _wire; SequenceManager _sequenceManager; Scene1625(); @@ -721,7 +721,7 @@ class Scene1700 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; - class Actor11 : public SceneActor { + class RimTransport : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -730,15 +730,15 @@ class Scene1700 : public SceneExt { virtual bool startAction(CursorType action, Event &event); }; - class Exit1 : public SceneExit { + class NorthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit2 : public SceneExit { + class SouthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit3 : public SceneExit { + class WestExit : public SceneExit { public: virtual void changeScene(); }; @@ -749,19 +749,19 @@ public: Item2 _item2; SceneActor _actor1; SceneActor _actor2; - SceneActor _actor3; - SceneActor _actor4; - SceneActor _actor5; - SceneActor _actor6; - SceneActor _actor7; - SceneActor _actor8; - SceneActor _actor9; + SceneActor _slabWest; + SceneActor _slabEast; + SceneActor _slabShadowWest; + SceneActor _slabShadowEast; + SceneActor _westPlatform; + SceneActor _rimTransportDoor; + SceneActor _ledgeHopper; SceneActor _actor10; - Actor11 _actor11; + RimTransport _rimTransport; Actor12 _actor12; - Exit1 _exit1; - Exit2 _exit2; - Exit3 _exit3; + NorthExit _northExit; + SouthExit _southExit; + WestExit _westExit; SequenceManager _sequenceManager; int _field77A; @@ -769,7 +769,7 @@ public: Scene1700(); void synchronize(Serializer &s); - void subAF3F8(); + void enterArea(); virtual void postInit(SceneObjectList *OwnerList = NULL); virtual void remove(); @@ -777,54 +777,54 @@ public: }; class Scene1750 : public SceneExt { - class Actor4 : public SceneActor { + class SpeedSlider : public SceneActor { public: - int _fieldA4; - int _fieldA6; - int _fieldA8; - int _fieldAA; - int _fieldAC; - int _fieldAE; + int _incrAmount; + int _xp; + int _ys; + int _height; + int _thumbHeight; + bool _mouseDown; - Actor4(); + SpeedSlider(); virtual void synchronize(Serializer &s); - void subB1A76(int arg1, int arg2, int arg3, int arg4, int arg5); - void subB1B27(); + void setupSlider(int incrAmount, int xp, int ys, int height, int thumbHeight); + void calculateSlider(); virtual void remove(); virtual void process(Event &event); virtual bool startAction(CursorType action, Event &event); }; - class Actor5 : public SceneActor { + class Button : public SceneActor { public: - int _fieldA4; + int _buttonId; - Actor5(); + Button(); virtual void synchronize(Serializer &s); virtual bool startAction(CursorType action, Event &event); }; public: - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - NamedHotspot _item4; - NamedHotspot _item5; + NamedHotspot _background; + NamedHotspot _redLights; + NamedHotspot _greenLights; + NamedHotspot _frontView; + NamedHotspot _rearView; SceneActor _actor1; SceneActor _actor2; SceneActor _actor3; - Actor4 _actor4; - Actor5 _actor5; - Actor5 _actor6; - Actor5 _actor7; + SpeedSlider _speedSlider; + Button _forwardButton; + Button _backwardButton; + Button _exitButton; SequenceManager _sequenceManager; PaletteRotation *_rotation; - int _field412; + int _direction; int _field413; - int _field415; + int _speed; int _field417; int _field419; int _field41B; @@ -841,20 +841,20 @@ public: }; class Scene1800 : public SceneExt { - class Hotspot5 : public NamedHotspot { + class Background : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor6 : public SceneActor { + class Lever : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor7 : public SceneActor { + class Doors : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor8 : public SceneActor { + class PassengerDoor : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -864,23 +864,23 @@ class Scene1800 : public SceneExt { virtual void changeScene(); }; public: - int _field412; + int _locationMode; SpeakerQuinn _quinnSpeaker; SpeakerSeeker _seekerSpeaker; NamedHotspot _item1; NamedHotspot _item2; NamedHotspot _item3; NamedHotspot _item4; - Hotspot5 _item5; + Background _background; SceneActor _actor1; - SceneActor _actor2; + SceneActor _companion; SceneActor _actor3; - SceneActor _actor4; - SceneActor _actor5; - Actor6 _actor6; - Actor7 _actor7; - Actor8 _actor8; - Actor8 _actor9; + SceneActor _leftStaircase; + SceneActor _rightStaircase; + Lever _lever; + Doors _doors; + PassengerDoor _leftDoor; + PassengerDoor _rightDoor; Exit1 _exit1; SequenceManager _sequenceManager; @@ -893,12 +893,12 @@ public: }; class Scene1850 : public SceneExt { - class Hotspot2 : public NamedHotspot { + class Button : public NamedHotspot { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor5 : public SceneActor { + class Robot : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -906,7 +906,7 @@ class Scene1850 : public SceneExt { public: virtual bool startAction(CursorType action, Event &event); }; - class Actor8 : public SceneActor { + class DisplayScreen : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; @@ -921,16 +921,16 @@ public: ScenePalette _palette1; SpeakerQuinn _quinnSpeaker; SpeakerSeeker _seekerSpeaker; - NamedHotspot _item1; - Hotspot2 _item2; - SceneActor _actor1; + NamedHotspot _background; + Button _button; + SceneActor _companion; SceneActor _actor2; SceneActor _actor3; SceneActor _actor4; - Actor5 _actor5; - Actor6 _actor6; - Actor6 _actor7; - Actor8 _actor8; + Robot _robot; + Actor6 _leftDoor; + Actor6 _rightDoor; + DisplayScreen _displayScreen; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; @@ -945,15 +945,16 @@ public: }; class Scene1875 : public SceneExt { - class Actor1875 : public SceneActor { + class Button : public SceneActor { public: - int _fieldA4; - int _fieldA6; + int _buttonId; + bool _buttonDown; - Actor1875(); - void subB84AB(); - void subB8271(int indx); + Button(); + void doButtonPress(); + void initButton(int buttonId); + virtual Common::String getClassName() { return "Scene1875_Button"; } void synchronize(Serializer &s); virtual void process(Event &event); }; @@ -965,11 +966,11 @@ public: SceneActor _actor1; SceneActor _actor2; SceneActor _actor3; - Actor1875 _actor4; - Actor1875 _actor5; - Actor1875 _actor6; - Actor1875 _actor7; - Actor1875 _actor8; + Button _button1; + Button _button2; + Button _button3; + Button _button4; + Button _button5; SequenceManager _sequenceManager; virtual void postInit(SceneObjectList *OwnerList = NULL); @@ -978,30 +979,29 @@ public: }; class Scene1900 : public SceneExt { - class Actor2 : public SceneActor { + class LiftDoor : public SceneActor { public: virtual bool startAction(CursorType action, Event &event); }; - class Exit1 : public SceneExit { + class WestExit : public SceneExit { public: virtual void changeScene(); }; - class Exit2 : public SceneExit { + class EastExit : public SceneExit { public: virtual void changeScene(); }; public: SpeakerSeeker1900 _seekerSpeaker; - NamedHotspot _item1; - NamedHotspot _item2; + NamedHotspot _background; + NamedHotspot _elevator; SceneActor _actor1; BackgroundSceneObject _object1; BackgroundSceneObject _object2; - Actor2 _actor2; - Actor2 _actor3; - Exit1 _exit1; - Exit2 _exit2; + LiftDoor _leftDoor, _rightDoor; + WestExit _westExit; + EastExit _eastExit; SequenceManager _sequenceManager1; SequenceManager _sequenceManager2; diff --git a/engines/tsage/ringworld2/ringworld2_scenes2.cpp b/engines/tsage/ringworld2/ringworld2_scenes2.cpp index 9246c4b6a4..9c601778cc 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes2.cpp @@ -30,17 +30,19 @@ namespace TsAGE { namespace Ringworld2 { /*-------------------------------------------------------------------------- - * Scene 2000 - Ice Maze + * Scene 2000 - Spill Mountains * *--------------------------------------------------------------------------*/ + void Scene2000::initPlayer() { + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); switch (_mazePlayerMode) { case 0: R2_GLOBALS._player.setStrip(5); - if (_exit1._enabled) { - if (_exit2._enabled) + if (_westExit._enabled) { + if (_eastExit._enabled) R2_GLOBALS._player.setPosition(Common::Point(140, 129)); else R2_GLOBALS._player.setPosition(Common::Point(20, 129)); @@ -129,11 +131,11 @@ void Scene2000::initPlayer() { break; } for (int i = 0; i < 11; i++) { - if (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] == R2_GLOBALS._v56605[3 + i]) + if (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] == R2_GLOBALS._spillLocation[3 + i]) _objList1[i].show(); } - if ((R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) && (R2_GLOBALS._v56605[1] == R2_GLOBALS._v56605[2])) { + if ((R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) && (R2_GLOBALS._spillLocation[R2_QUINN] == R2_GLOBALS._spillLocation[R2_SEEKER])) { _object1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _object1.setup(20, 5, 1); @@ -142,8 +144,8 @@ void Scene2000::initPlayer() { _object1.setup(2008, 5, 1); _object1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); } - if (_exit1._enabled) { - if (_exit2._enabled) + if (_westExit._enabled) { + if (_eastExit._enabled) _object1.setPosition(Common::Point(180, 128)); else _object1.setPosition(Common::Point(75, 128)); @@ -153,53 +155,53 @@ void Scene2000::initPlayer() { } void Scene2000::initExits() { - _exit1._enabled = true; - _exit2._enabled = true; - _exit3._enabled = false; - _exit4._enabled = false; - _exit5._enabled = false; - - _exit1._insideArea = false; - _exit2._insideArea = false; - _exit3._insideArea = false; - _exit4._insideArea = false; - _exit5._insideArea = false; - - _exit1._moving = false; - _exit2._moving = false; - _exit3._moving = false; - _exit4._moving = false; - _exit5._moving = false; + _westExit._enabled = true; + _eastExit._enabled = true; + _southExit._enabled = false; + _northExit._enabled = false; + _doorExit._enabled = false; + + _westExit._insideArea = false; + _eastExit._insideArea = false; + _southExit._insideArea = false; + _northExit._insideArea = false; + _doorExit._insideArea = false; + + _westExit._moving = false; + _eastExit._moving = false; + _southExit._moving = false; + _northExit._moving = false; + _doorExit._moving = false; for (int i = 0; i < 11; i++) _objList1[i].hide(); _object1.remove(); - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 3: case 10: case 16: case 21: - _exit5._enabled = true; - _exit5._bounds.set(61, 68, 90, 125); - _exit5.setDest(Common::Point(92, 129)); - _exit5._cursorNum = EXITCURSOR_W; + _doorExit._enabled = true; + _doorExit._bounds.set(61, 68, 90, 125); + _doorExit.setDest(Common::Point(92, 129)); + _doorExit._cursorNum = EXITCURSOR_W; break; case 4: case 12: case 25: case 34: - _exit5._enabled = true; - _exit5._bounds.set(230, 68, 259, 125); - _exit5.setDest(Common::Point(244, 129)); - _exit5._cursorNum = EXITCURSOR_E; + _doorExit._enabled = true; + _doorExit._bounds.set(230, 68, 259, 125); + _doorExit.setDest(Common::Point(244, 129)); + _doorExit._cursorNum = EXITCURSOR_E; break; default: break; } - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] - 1) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] - 1) { case 0: case 6: case 13: @@ -207,7 +209,7 @@ void Scene2000::initExits() { case 22: case 27: case 30: - _exit1._enabled = false; + _westExit._enabled = false; loadScene(2225); R2_GLOBALS._walkRegions.load(2225); if (!_exitingFlag) @@ -216,10 +218,10 @@ void Scene2000::initExits() { break; case 1: case 19: - _exit3._enabled = true; - _exit3._bounds.set(71, 130, 154, 168); - _exit3.setDest(Common::Point(94, 129)); - _exit3._cursorNum = EXITCURSOR_SE; + _southExit._enabled = true; + _southExit._bounds.set(71, 130, 154, 168); + _southExit.setDest(Common::Point(94, 129)); + _southExit._cursorNum = EXITCURSOR_SE; loadScene(2300); if (!_exitingFlag) _mazePlayerMode = 0; @@ -283,8 +285,8 @@ void Scene2000::initExits() { case 21: case 26: loadScene(2200); - R2_GLOBALS._walkRegions.load(2000); - _exit2._enabled = false; + R2_GLOBALS._walkRegions.load(2200); + _eastExit._enabled = false; if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 1900) _mazePlayerMode = 2; else if (!_exitingFlag) @@ -294,10 +296,10 @@ void Scene2000::initExits() { break; case 7: case 29: - _exit4._enabled = true; - _exit4._bounds.set(138, 83, 211, 125); - _exit4.setDest(Common::Point(129, 188)); - _exit4._cursorNum = EXITCURSOR_NW; + _northExit._enabled = true; + _northExit._bounds.set(138, 83, 211, 125); + _northExit.setDest(Common::Point(188, 129)); + _northExit._cursorNum = EXITCURSOR_NW; loadScene(2250); R2_GLOBALS._walkRegions.load(2000); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2500) @@ -309,10 +311,10 @@ void Scene2000::initExits() { break; case 10: case 25: - _exit3._enabled = true; - _exit3._bounds.set(78, 130, 148, 168); - _exit3.setDest(Common::Point(100, 129)); - _exit3._cursorNum = EXITCURSOR_SE; + _southExit._enabled = true; + _southExit._bounds.set(78, 130, 148, 168); + _southExit.setDest(Common::Point(100, 129)); + _southExit._cursorNum = EXITCURSOR_SE; loadScene(2075); R2_GLOBALS._walkRegions.load(2000); if (!_exitingFlag) @@ -320,10 +322,10 @@ void Scene2000::initExits() { R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 2000; break; case 14: - _exit3._enabled = true; - _exit3._bounds.set(160, 130, 248, 168); - _exit3.setDest(Common::Point(225, 129)); - _exit3._cursorNum = EXITCURSOR_SW; + _southExit._enabled = true; + _southExit._bounds.set(160, 130, 248, 168); + _southExit.setDest(Common::Point(225, 129)); + _southExit._cursorNum = EXITCURSOR_SW; loadScene(2325); R2_GLOBALS._walkRegions.load(2000); if (!_exitingFlag) @@ -332,10 +334,10 @@ void Scene2000::initExits() { break; case 16: case 31: - _exit4._enabled = true; - _exit4._bounds.set(122, 83, 207, 125); - _exit4.setDest(Common::Point(210, 129)); - _exit4._cursorNum = EXITCURSOR_NW; + _northExit._enabled = true; + _northExit._bounds.set(122, 83, 207, 125); + _northExit.setDest(Common::Point(210, 129)); + _northExit._cursorNum = EXITCURSOR_NW; loadScene(2125); R2_GLOBALS._walkRegions.load(2000); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2400) @@ -346,10 +348,10 @@ void Scene2000::initExits() { R2_GLOBALS._sceneManager._previousScene = 2000; break; case 23: - _exit4._enabled = true; - _exit4._bounds.set(108, 83, 128, 184); - _exit4.setDest(Common::Point(135, 129)); - _exit4._cursorNum = CURSOR_INVALID; + _northExit._enabled = true; + _northExit._bounds.set(108, 83, 128, 184); + _northExit.setDest(Common::Point(135, 129)); + _northExit._cursorNum = CURSOR_INVALID; loadScene(2275); R2_GLOBALS._walkRegions.load(2000); if (!_exitingFlag) @@ -357,10 +359,10 @@ void Scene2000::initExits() { R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 2000; break; case 28: - _exit3._enabled = true; - _exit3._bounds.set(171, 130, 241, 168); - _exit3.setDest(Common::Point(218, 129)); - _exit3._cursorNum = EXITCURSOR_SW; + _southExit._enabled = true; + _southExit._bounds.set(171, 130, 241, 168); + _southExit.setDest(Common::Point(218, 129)); + _southExit._cursorNum = EXITCURSOR_SW; loadScene(2050); R2_GLOBALS._walkRegions.load(2000); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2350) @@ -396,34 +398,34 @@ void Scene2000::Action1::signal() { } case 1: scene->_objList1[_state].setPosition(Common::Point(340, 127)); - --R2_GLOBALS._v56605[4 + _state]; + --R2_GLOBALS._spillLocation[4 + _state]; _actionIndex = 0; switch (_state - 1) { case 0: - if (R2_GLOBALS._v56605[4] == 1) + if (R2_GLOBALS._spillLocation[4] == 1) _actionIndex = 10; break; case 2: - if (R2_GLOBALS._v56605[6] == 7) + if (R2_GLOBALS._spillLocation[6] == 7) _actionIndex = 10; break; case 4: - if (R2_GLOBALS._v56605[8] == 14) + if (R2_GLOBALS._spillLocation[8] == 14) _actionIndex = 10; break; case 6: - if (R2_GLOBALS._v56605[10] == 19) + if (R2_GLOBALS._spillLocation[10] == 19) _actionIndex = 10; break; case 7: - if (R2_GLOBALS._v56605[11] == 23) + if (R2_GLOBALS._spillLocation[11] == 23) _actionIndex = 10; break; default: break; } - if (R2_GLOBALS._v56605[3 + _state] == R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) + if (R2_GLOBALS._spillLocation[3 + _state] == R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) scene->_objList1[_state].show(); else scene->_objList1[_state].hide(); @@ -439,34 +441,34 @@ void Scene2000::Action1::signal() { } case 6: scene->_objList1[_state].setPosition(Common::Point(-20, 127)); - ++R2_GLOBALS._v56605[3 + _state]; + ++R2_GLOBALS._spillLocation[3 + _state]; _actionIndex = 5; switch (_state - 1) { case 0: - if (R2_GLOBALS._v56605[4] == 5) + if (R2_GLOBALS._spillLocation[4] == 5) _actionIndex = 15; break; case 2: - if (R2_GLOBALS._v56605[6] == 13) + if (R2_GLOBALS._spillLocation[6] == 13) _actionIndex = 15; break; case 4: - if (R2_GLOBALS._v56605[8] == 16) + if (R2_GLOBALS._spillLocation[8] == 16) _actionIndex = 15; break; case 6: - if (R2_GLOBALS._v56605[10] == 22) + if (R2_GLOBALS._spillLocation[10] == 22) _actionIndex = 15; break; case 7: - if (R2_GLOBALS._v56605[11] == 27) + if (R2_GLOBALS._spillLocation[11] == 27) _actionIndex = 15; break; default: break; } - if (R2_GLOBALS._v56605[3 + _state] == R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) + if (R2_GLOBALS._spillLocation[3 + _state] == R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) scene->_objList1[_state].show(); else scene->_objList1[_state].hide(); @@ -498,7 +500,7 @@ void Scene2000::Action1::signal() { signal(); break; case 15: - if ((R2_GLOBALS._v56605[3 + _state] == 13) || (R2_GLOBALS._v56605[3 + _state] == 22) || (R2_GLOBALS._v56605[3 + _state] == 27)) { + if ((R2_GLOBALS._spillLocation[3 + _state] == 13) || (R2_GLOBALS._spillLocation[3 + _state] == 22) || (R2_GLOBALS._spillLocation[3 + _state] == 27)) { Common::Point pt(30, 127); NpcMover *mover = new NpcMover(); scene->_objList1[_state].addMover(mover, &pt, this); @@ -534,26 +536,24 @@ void Scene2000::Action1::signal() { } } -void Scene2000::Exit1::changeScene() { +void Scene2000::WestExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 10; Common::Point pt(-10, 129); NpcMover *mover = new NpcMover(); R2_GLOBALS._player.addMover(mover, &pt, scene); - - scene->setAction(&scene->_sequenceManager, scene, 206, &R2_GLOBALS._player, NULL); } -void Scene2000::Exit2::changeScene() { +void Scene2000::EastExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 11; @@ -562,38 +562,38 @@ void Scene2000::Exit2::changeScene() { R2_GLOBALS._player.addMover(mover, &pt, scene); } -void Scene2000::Exit3::changeScene() { +void Scene2000::SouthExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 12; - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 2: scene->_mazePlayerMode = 4; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 8; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 8; break; case 11: scene->_mazePlayerMode = 6; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 17; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 17; break; case 15: scene->_mazePlayerMode = 8; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 24; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 24; break; case 20: scene->_mazePlayerMode = 4; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 30; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 30; break; case 26: scene->_mazePlayerMode = 6; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 32; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 32; break; case 29: scene->_mazePlayerMode = 11; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 29; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 29; break; default: break; @@ -631,34 +631,34 @@ void Scene2000::Exit3::changeScene() { } } -void Scene2000::Exit4::changeScene() { +void Scene2000::NorthExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; scene->_exitingFlag = true; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 13; - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 8: scene->_mazePlayerMode = 5; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 2; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 2; break; case 17: scene->_mazePlayerMode = 7; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 11; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 11; break; case 24: scene->_mazePlayerMode = 9; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 15; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 15; break; case 30: scene->_mazePlayerMode = 5; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 20; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 20; break; case 32: scene->_mazePlayerMode = 7; - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 26; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 26; break; default: break; @@ -688,14 +688,14 @@ void Scene2000::Exit4::changeScene() { } } -void Scene2000::Exit5::changeScene() { +void Scene2000::DoorExit::changeScene() { Scene2000 *scene = (Scene2000 *)R2_GLOBALS._sceneManager._scene; - scene->_sceneMode = 0; + _enabled = false; R2_GLOBALS._player.disableControl(CURSOR_ARROW); scene->_sceneMode = 14; - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 3: scene->_mazePlayerMode = 1; if (R2_GLOBALS._player._characterIndex == 1) @@ -758,9 +758,9 @@ void Scene2000::Exit5::changeScene() { } Scene2000::Scene2000(): SceneExt() { - if (R2_GLOBALS._sceneManager._previousScene != -1) { - R2_GLOBALS._v56605[1] = 21; - R2_GLOBALS._v56605[2] = 21; + if (R2_GLOBALS._sceneManager._previousScene == -1) { + R2_GLOBALS._spillLocation[R2_QUINN] = 21; + R2_GLOBALS._spillLocation[R2_SEEKER] = 21; } if ((R2_GLOBALS._player._characterScene[R2_GLOBALS._player._characterIndex] != R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex]) @@ -769,19 +769,20 @@ Scene2000::Scene2000(): SceneExt() { } _exitingFlag = false; + _mazePlayerMode = 0; } void Scene2000::postInit(SceneObjectList *OwnerList) { - _exit1.setDetails(Rect(0, 100, 14, 140), EXITCURSOR_W, 2000); - _exit1.setDest(Common::Point(14, 129)); - _exit2.setDetails(Rect(305, 100, 320, 140), EXITCURSOR_E, 2000); - _exit2.setDest(Common::Point(315, 129)); - _exit3.setDetails(Rect(71, 130, 154, 168), EXITCURSOR_S, 2000); - _exit3.setDest(Common::Point(94, 129)); - _exit4.setDetails(Rect(138, 83, 211, 125), EXITCURSOR_N, 2000); - _exit4.setDest(Common::Point(188, 128)); - _exit5.setDetails(Rect(61, 68, 90, 125), EXITCURSOR_W, 2000); - _exit5.setDest(Common::Point(92, 129)); + _westExit.setDetails(Rect(0, 100, 14, 140), EXITCURSOR_W, 2000); + _westExit.setDest(Common::Point(14, 129)); + _eastExit.setDetails(Rect(305, 100, 320, 140), EXITCURSOR_E, 2000); + _eastExit.setDest(Common::Point(315, 129)); + _southExit.setDetails(Rect(71, 130, 154, 168), EXITCURSOR_S, 2000); + _southExit.setDest(Common::Point(94, 129)); + _northExit.setDetails(Rect(138, 83, 211, 125), EXITCURSOR_N, 2000); + _northExit.setDest(Common::Point(188, 129)); + _doorExit.setDetails(Rect(61, 68, 90, 125), EXITCURSOR_W, 2000); + _doorExit.setDest(Common::Point(92, 129)); R2_GLOBALS._sound1.play(200); initExits(); @@ -858,39 +859,39 @@ void Scene2000::postInit(SceneObjectList *OwnerList) { _objList1[i].hide(); switch (i - 1) { case 0: - if (R2_GLOBALS._v56605[3 + i] == 1) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 5) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 1) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 5) + --R2_GLOBALS._spillLocation[3 + i]; break; case 2: - if (R2_GLOBALS._v56605[3 + i] == 7) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 13) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 7) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 13) + --R2_GLOBALS._spillLocation[3 + i]; break; case 4: - if (R2_GLOBALS._v56605[3 + i] == 14) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 16) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 14) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 16) + --R2_GLOBALS._spillLocation[3 + i]; break; case 6: - if (R2_GLOBALS._v56605[3 + i] == 19) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 22) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 19) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 22) + --R2_GLOBALS._spillLocation[3 + i]; break; case 8: - if (R2_GLOBALS._v56605[3 + i] == 23) - ++R2_GLOBALS._v56605[3 + i]; - else if (R2_GLOBALS._v56605[3 + i] == 27) - --R2_GLOBALS._v56605[3 + i]; + if (R2_GLOBALS._spillLocation[3 + i] == 23) + ++R2_GLOBALS._spillLocation[3 + i]; + else if (R2_GLOBALS._spillLocation[3 + i] == 27) + --R2_GLOBALS._spillLocation[3 + i]; break; default: break; } - switch (R2_GLOBALS._v56605[3 + i] - 1) { + switch (R2_GLOBALS._spillLocation[3 + i] - 1) { case 0: case 6: case 13: @@ -925,6 +926,7 @@ void Scene2000::postInit(SceneObjectList *OwnerList) { } void Scene2000::remove() { + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._sound1.fadeOut(NULL); SceneExt::remove(); } @@ -932,17 +934,19 @@ void Scene2000::remove() { void Scene2000::signal() { switch (_sceneMode) { case 10: - if (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] == 6) + // Leaving left-hand side of scene + if (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] == 6) g_globals->_sceneManager.changeScene(1900); else { _mazePlayerMode = 1; - --R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]; + --R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]; initExits(); initPlayer(); } break; case 11: - switch (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]) { + // Leaving right-hand side of scene + switch (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]) { case 5: g_globals->_sceneManager.changeScene(1900); break; @@ -954,7 +958,7 @@ void Scene2000::signal() { break; default: _mazePlayerMode = 2; - ++R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex]; + ++R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex]; initExits(); initPlayer(); break; @@ -962,6 +966,7 @@ void Scene2000::signal() { break; case 12: case 13: + // Top/bottom scene exits initExits(); initPlayer(); break; @@ -1025,6 +1030,12 @@ void Scene2000::process(Event &event) { void Scene2000::synchronize(Serializer &s) { SceneExt::synchronize(s); + // Synchronise active walk regions + int regionsId = R2_GLOBALS._walkRegions._resNum; + s.syncAsUint16LE(regionsId); + if (s.isLoading()) + R2_GLOBALS._walkRegions.load(regionsId); + s.syncAsByte(_exitingFlag); s.syncAsSint16LE(_mazePlayerMode); } @@ -1084,7 +1095,7 @@ void Scene2350::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_quinnSpeaker); if (R2_GLOBALS._sceneManager._previousScene == -1) - R2_GLOBALS._player._characterScene[2] = 2350; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2350; _exitUp.setDetails(Rect(25, 83, 93, 125), EXITCURSOR_NW, 2350); _exitUp.setDest(Common::Point(80, 129)); @@ -1102,7 +1113,7 @@ void Scene2350::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor2.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor2.setup(20, 5, 1); @@ -1116,7 +1127,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 { @@ -1133,7 +1144,7 @@ void Scene2350::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2000) { - if (R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] == 34) { + if (R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] == 34) { if (R2_GLOBALS._player._characterIndex == 1) _sceneMode = 2351; else @@ -1163,11 +1174,11 @@ void Scene2350::remove() { void Scene2350::signal() { switch (_sceneMode) { case 11: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 34; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 34; g_globals->_sceneManager.changeScene(2000); break; case 12: - R2_GLOBALS._v56605[R2_GLOBALS._player._characterIndex] = 29; + R2_GLOBALS._spillLocation[R2_GLOBALS._player._characterIndex] = 29; g_globals->_sceneManager.changeScene(2000); break; case 20: @@ -1176,12 +1187,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: @@ -1207,7 +1218,7 @@ void Scene2350::process(Event &event) { } /*-------------------------------------------------------------------------- - * Scene 2400 - Ice Maze: Large empty room + * Scene 2400 - Spill Mountains: Large empty room * *--------------------------------------------------------------------------*/ void Scene2400::Exit1::changeScene() { @@ -1243,7 +1254,7 @@ void Scene2400::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.postInit(); R2_GLOBALS._player.disableControl(); - if (R2_GLOBALS._v56605[1] == 16) { + if (R2_GLOBALS._spillLocation[R2_QUINN] == 16) { _sceneMode = 2400; setAction(&_sequenceManager, this, 2400, &R2_GLOBALS._player, NULL); } else { @@ -1255,11 +1266,11 @@ void Scene2400::postInit(SceneObjectList *OwnerList) { void Scene2400::signal() { switch (_sceneMode) { case 10: - R2_GLOBALS._v56605[1] = 16; + R2_GLOBALS._spillLocation[R2_QUINN] = 16; g_globals->_sceneManager.changeScene(2000); break; case 11: - R2_GLOBALS._v56605[1] = 17; + R2_GLOBALS._spillLocation[R2_QUINN] = 17; g_globals->_sceneManager.changeScene(2000); break; default: @@ -1269,7 +1280,7 @@ void Scene2400::signal() { } /*-------------------------------------------------------------------------- - * Scene 2425 - Ice Maze: + * Scene 2425 - Spill Mountains: * *--------------------------------------------------------------------------*/ @@ -1364,7 +1375,7 @@ void Scene2425::Exit1::changeScene() { Scene2425 *scene = (Scene2425 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._events.setCursor(R2_NEGATOR_GUN); + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 11; @@ -1395,7 +1406,7 @@ void Scene2425::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor2.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor2.setup(20, 5, 1); @@ -1484,7 +1495,7 @@ void Scene2425::signal() { } /*-------------------------------------------------------------------------- - * Scene 2430 - Ice Maze: Bedroom + * Scene 2430 - Spill Mountains: Bedroom * *--------------------------------------------------------------------------*/ @@ -1520,7 +1531,7 @@ void Scene2430::Exit1::changeScene() { Scene2430 *scene = (Scene2430 *)R2_GLOBALS._sceneManager._scene; scene->_sceneMode = 0; - R2_GLOBALS._events.setCursor(R2_NEGATOR_GUN); + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 11; Common::Point pt(108, 200); @@ -1534,7 +1545,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 +1553,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)); @@ -1560,7 +1571,7 @@ void Scene2430::postInit(SceneObjectList *OwnerList) { } R2_GLOBALS._player.setPosition(Common::Point(100, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -1623,14 +1634,15 @@ void Scene2430::signal() { } /*-------------------------------------------------------------------------- - * Scene 2435 - Ice Maze: Throne room + * Scene 2435 - Spill Mountains: Throne room * *--------------------------------------------------------------------------*/ -bool Scene2435::Actor1::startAction(CursorType action, Event &event) { + +bool Scene2435::Companion::startAction(CursorType action, Event &event) { return SceneActor::startAction(action, event); } -bool Scene2435::Actor2::startAction(CursorType action, Event &event) { +bool Scene2435::Astor::startAction(CursorType action, Event &event) { Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; switch (action) { @@ -1671,7 +1683,7 @@ void Scene2435::Exit1::changeScene() { Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; _enabled = false; - R2_GLOBALS._events.setCursor(R2_NEGATOR_GUN); + R2_GLOBALS._events.setCursor(CURSOR_WALK); R2_GLOBALS._player.disableControl(); scene->_sceneMode = 11; Common::Point pt(175, 200); @@ -1689,36 +1701,38 @@ void Scene2435::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_pharishaSpeaker); _exit1.setDetails(Rect(142, 155, 207, 167), EXITCURSOR_S, 2000); _exit1.setDest(Common::Point(175, 160)); - _actor2.postInit(); - _actor2.setup(2005, 3, 1); - _actor2.setPosition(Common::Point(219, 106)); - _actor2.setDetails(2001, 25, 26, -1, 1, (SceneItem *)NULL); + _astor.postInit(); + _astor.setup(2005, 3, 1); + _astor.setPosition(Common::Point(219, 106)); + _astor.setDetails(2001, 25, 26, -1, 1, (SceneItem *)NULL); R2_GLOBALS._player.postInit(); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); - if (R2_GLOBALS._player._characterIndex == 1) { + + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { R2_GLOBALS._player.setVisage(2008); R2_GLOBALS._player._moveDiff = Common::Point(3, 2); } else { R2_GLOBALS._player.setVisage(20); R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - R2_GLOBALS._player.setPosition(Common::Point(715, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { - _actor1.postInit(); - if (R2_GLOBALS._player._characterIndex == 1) { - _actor1.setup(20, 5, 1); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + R2_GLOBALS._player.setPosition(Common::Point(175, 200)); + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { + _companion.postInit(); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + _companion.setup(20, 5, 1); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); } else { - _actor1.setup(2008, 5, 1); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setup(2008, 5, 1); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); } - _actor1.setPosition(Common::Point(107, 145)); + _companion.setPosition(Common::Point(107, 145)); R2_GLOBALS._walkRegions.enableRegion(2); } - _item2.setDetails(Rect(52, 44, 96, 82), 2430, 3, -1, 5, 1, NULL); - _item3.setDetails(Rect(117, 36, 161, 74), 2430, 3, -1, 5, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); + _leftWindow.setDetails(Rect(52, 44, 96, 82), 2430, 3, -1, 5, 1, NULL); + _rightWindow.setDetails(Rect(117, 36, 161, 74), 2430, 3, -1, 5, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); + R2_GLOBALS._player.disableControl(); if (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] == 2000) { _sceneMode = 10; @@ -1736,7 +1750,7 @@ void Scene2435::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.enableControl(); } R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex] = 2435; - R2_GLOBALS._v56605[1 + R2_GLOBALS._player._characterIndex] = 12; + R2_GLOBALS._spillLocation[1 + R2_GLOBALS._player._characterIndex] = 12; } void Scene2435::remove() { @@ -1753,21 +1767,21 @@ void Scene2435::signal() { R2_GLOBALS._player.enableControl(CURSOR_TALK); break; case 30: - R2_GLOBALS._player._characterScene[1] = 2435; - R2_GLOBALS._player._characterScene[2] = 2435; - R2_GLOBALS._player._oldCharacterScene[1] = 2435; - R2_GLOBALS._player._oldCharacterScene[2] = 2435; - R2_GLOBALS._v56605[1] = 12; - R2_GLOBALS._v56605[2] = 12; + R2_GLOBALS._player._characterScene[R2_QUINN] = 2435; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2435; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 2435; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2435; + R2_GLOBALS._spillLocation[R2_QUINN] = 12; + R2_GLOBALS._spillLocation[R2_SEEKER] = 12; R2_GLOBALS.setFlag(81); _sceneMode = 2436; R2_GLOBALS._player.setStrip(7); - _actor1.postInit(); + _companion.postInit(); if (R2_GLOBALS._player._characterIndex == 1) - _actor1.setVisage(20); + _companion.setVisage(20); else - _actor1.setVisage(2008); - setAction(&_sequenceManager, this, 2436, &_actor1, NULL); + _companion.setVisage(2008); + setAction(&_sequenceManager, this, 2436, &_companion, NULL); break; case 2436: R2_GLOBALS._walkRegions.enableRegion(2); @@ -1781,7 +1795,7 @@ void Scene2435::signal() { } /*-------------------------------------------------------------------------- - * Scene 2440 - Ice Maze: Another bedroom + * Scene 2440 - Spill Mountains: Another bedroom * *--------------------------------------------------------------------------*/ @@ -1820,7 +1834,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)); @@ -1839,7 +1853,7 @@ void Scene2440::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } R2_GLOBALS._player.setPosition(Common::Point(210, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -1885,7 +1899,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(); @@ -1894,7 +1908,7 @@ void Scene2440::signal() { } /*-------------------------------------------------------------------------- - * Scene 2445 - Ice Maze: + * Scene 2445 - Spill Mountains: * *--------------------------------------------------------------------------*/ void Scene2445::postInit(SceneObjectList *OwnerList) { @@ -1912,23 +1926,23 @@ void Scene2445::signal() { } /*-------------------------------------------------------------------------- - * Scene 2450 - Ice Maze: Another bedroom + * Scene 2450 - Spill Mountains: Another bedroom * *--------------------------------------------------------------------------*/ -bool Scene2450::Actor2::startAction(CursorType action, Event &event) { +bool Scene2450::Parker::startAction(CursorType action, Event &event) { Scene2450 *scene = (Scene2450 *)R2_GLOBALS._sceneManager._scene; if ((action == CURSOR_USE) && (R2_GLOBALS._player._characterIndex == 1)) { R2_GLOBALS._player.disableControl(); scene->_sceneMode = 2452; - scene->setAction(&scene->_sequenceManager, scene, 2452, &R2_GLOBALS._player, &scene->_actor2, NULL); + scene->setAction(&scene->_sequenceManager, scene, 2452, &R2_GLOBALS._player, &scene->_parker, NULL); return true; } return SceneActor::startAction(action, event); } -bool Scene2450::Actor3::startAction(CursorType action, Event &event) { +bool Scene2450::CareTaker::startAction(CursorType action, Event &event) { Scene2450 *scene = (Scene2450 *)R2_GLOBALS._sceneManager._scene; if (action == CURSOR_TALK) { @@ -1942,7 +1956,8 @@ bool Scene2450::Actor3::startAction(CursorType action, Event &event) { else scene->_stripManager.start(700 + (R2_GLOBALS._v565AE * 2), scene); } - return true;} else { + return true; + } else { return SceneActor::startAction(action, event); } } @@ -1973,8 +1988,8 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(200); if (R2_GLOBALS._sceneManager._previousScene == -1) { R2_GLOBALS._sceneManager._previousScene = 1900; - R2_GLOBALS._player._oldCharacterScene[1] = 1900; - R2_GLOBALS._player._oldCharacterScene[2] = 1900; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1900; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 1900; } _stripManager.addSpeaker(&_quinnSpeaker); _stripManager.addSpeaker(&_seekerSpeaker); @@ -1986,11 +2001,11 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { } if (!R2_GLOBALS.getFlag(61)) { - _actor2.postInit(); - _actor2.setVisage(2009); - _actor2.setPosition(Common::Point(190, 119)); - _actor2.fixPriority(50); - _actor2.setDetails(2450, 0, -1, -1, 1, (SceneItem *)NULL); + _parker.postInit(); + _parker.setVisage(2009); + _parker.setPosition(Common::Point(190, 119)); + _parker.fixPriority(50); + _parker.setDetails(2450, 0, -1, -1, 1, (SceneItem *)NULL); } R2_GLOBALS._player.postInit(); @@ -1998,10 +2013,10 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { switch (R2_GLOBALS._player._oldCharacterScene[R2_GLOBALS._player._characterIndex]) { case 1900: R2_GLOBALS._v565AE = 0; - R2_GLOBALS._player._characterScene[1] = 2450; - R2_GLOBALS._player._characterScene[2] = 2450; - R2_GLOBALS._player._oldCharacterScene[1] = 2450; - R2_GLOBALS._player._oldCharacterScene[2] = 2450; + R2_GLOBALS._player._characterScene[R2_QUINN] = 2450; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2450; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 2450; + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2450; R2_GLOBALS._player.setup(2450, 1, 1); R2_GLOBALS._player.setPosition(Common::Point(126, 101)); setAction(&_sequenceManager, this, 2450, &R2_GLOBALS._player, NULL); @@ -2009,24 +2024,24 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { case 2000: _sceneMode = 2451; if (R2_GLOBALS._player._characterIndex == 1) { - if (R2_GLOBALS._player._characterScene[2] == 2450) { - _actor1.postInit(); - _actor1.setup(20, 6, 1); - _actor1.setPosition(Common::Point(240, 120)); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + if (R2_GLOBALS._player._characterScene[R2_SEEKER] == 2450) { + _companion.postInit(); + _companion.setup(20, 6, 1); + _companion.setPosition(Common::Point(240, 120)); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); } setAction(&_sequenceManager, this, 2451, &R2_GLOBALS._player, NULL); } else { - R2_GLOBALS._player._oldCharacterScene[2] = 2450; - R2_GLOBALS._player._characterScene[2] = 2450; - if (R2_GLOBALS._player._characterScene[1] == 2450) { - _actor1.postInit(); + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2450; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2450; + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 2450) { + _companion.postInit(); if (R2_GLOBALS.getFlag(61)) - _actor1.setup(2008, 6, 1); + _companion.setup(2008, 6, 1); else - _actor1.setup(10, 6, 1); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); - _actor1.setPosition(Common::Point(106, 111)); + _companion.setup(10, 6, 1); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setPosition(Common::Point(106, 111)); } setAction(&_sequenceManager, this, 2456, &R2_GLOBALS._player, NULL); } @@ -2042,22 +2057,22 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.setPosition(Common::Point(106, 111)); R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); if (R2_GLOBALS.getFlag(72)) { - if (R2_GLOBALS._player._characterScene[2] == 2450) { - _actor1.postInit(); - _actor1.setup(20, 6, 1); - _actor1.setPosition(Common::Point(240, 120)); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + if (R2_GLOBALS._player._characterScene[R2_SEEKER] == 2450) { + _companion.postInit(); + _companion.setup(20, 6, 1); + _companion.setPosition(Common::Point(240, 120)); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); } } else { - _actor1.postInit(); - _actor1.setup(20, 8, 1); - _actor1.setPosition(Common::Point(93, 158)); - _actor1.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); + _companion.postInit(); + _companion.setup(20, 8, 1); + _companion.setPosition(Common::Point(93, 158)); + _companion.setDetails(9002, 0, 4, 3, 1, (SceneItem *)NULL); - _actor3.postInit(); - _actor3.setup(2001, 7, 1); - _actor3.setPosition(Common::Point(34, 153)); - _actor3.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); + _careTaker.postInit(); + _careTaker.setup(2001, 7, 1); + _careTaker.setPosition(Common::Point(34, 153)); + _careTaker.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); _exit1._enabled = false; } @@ -2067,30 +2082,30 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.animate(ANIM_MODE_1, NULL); R2_GLOBALS._player.setPosition(Common::Point(93, 158)); if (R2_GLOBALS.getFlag(72)) { - if (R2_GLOBALS._player._characterScene[1] == 2450) { - _actor1.postInit(); + if (R2_GLOBALS._player._characterScene[R2_QUINN] == 2450) { + _companion.postInit(); if (R2_GLOBALS.getFlag(61)) { - _actor1.setup(2008, 6, 1); + _companion.setup(2008, 6, 1); } else { - _actor1.setup(10, 6, 1); + _companion.setup(10, 6, 1); } - _actor1.setPosition(Common::Point(106, 111)); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setPosition(Common::Point(106, 111)); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); } } else { - _actor1.postInit(); + _companion.postInit(); if (R2_GLOBALS.getFlag(61)) { - _actor1.setup(2008, 6, 1); + _companion.setup(2008, 6, 1); } else { - _actor1.setup(10, 6, 1); + _companion.setup(10, 6, 1); } - _actor1.setPosition(Common::Point(106, 111)); - _actor1.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); + _companion.setPosition(Common::Point(106, 111)); + _companion.setDetails(9001, 0, 5, 3, 1, (SceneItem *)NULL); - _actor3.postInit(); - _actor3.setup(2001, 7, 1); - _actor3.setPosition(Common::Point(34, 153)); - _actor3.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); + _careTaker.postInit(); + _careTaker.setup(2001, 7, 1); + _careTaker.setPosition(Common::Point(34, 153)); + _careTaker.setDetails(2001, 40, -1, -1, 1, (SceneItem *)NULL); _exit1._enabled = false; } @@ -2117,9 +2132,9 @@ void Scene2450::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player.enableControl(); break; } - _item2.setDetails(Rect(174, 4, 199, 123), 2430, 30, 31, 32, 1, NULL); - _item3.setDetails(Rect(67, 73, 207, 121), 2430, 36, -1, 38, 1, NULL); - _item1.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); + _post.setDetails(Rect(174, 4, 199, 123), 2430, 30, 31, 32, 1, NULL); + _bedspread.setDetails(Rect(67, 73, 207, 121), 2430, 36, -1, 38, 1, NULL); + _background.setDetails(Rect(0, 0, 320, 200), 2430, 0, -1, -1, 1, NULL); } void Scene2450::remove() { @@ -2137,7 +2152,7 @@ void Scene2450::signal() { R2_GLOBALS._player.disableControl(); R2_GLOBALS._v565AE = 4; _sceneMode = 2454; - setAction(&_sequenceManager, this, 2454, &_actor3, NULL); + setAction(&_sequenceManager, this, 2454, &_careTaker, NULL); } else { R2_GLOBALS._player.enableControl(CURSOR_TALK); if (R2_GLOBALS._v565AE < 4) @@ -2147,7 +2162,7 @@ void Scene2450::signal() { case 30: R2_GLOBALS._player.disableControl(); _sceneMode = 2455; - setAction(&_sequenceManager, this, 2455, &_actor1, NULL); + setAction(&_sequenceManager, this, 2455, &_companion, NULL); break; case 31: R2_GLOBALS.setFlag(61); @@ -2158,7 +2173,7 @@ void Scene2450::signal() { break; case 2452: R2_GLOBALS.setFlag(61); - _actor2.remove(); + _parker.remove(); R2_GLOBALS._player.enableControl(); if (!R2_GLOBALS.getFlag(72)) { R2_GLOBALS._player.setStrip(6); @@ -2173,38 +2188,38 @@ void Scene2450::signal() { case 2454: _exit1._enabled = true; R2_GLOBALS.setFlag(72); - _actor3.remove(); + _careTaker.remove(); if (R2_GLOBALS.getFlag(61)) { g_globals->_sceneManager.changeScene(2435); } else { _sceneMode = 31; - if (R2_GLOBALS._player._characterIndex == 1) { - setAction(&_sequenceManager, this, 2452, &R2_GLOBALS._player, NULL); + if (R2_GLOBALS._player._characterIndex == R2_QUINN) { + setAction(&_sequenceManager, this, 2452, &R2_GLOBALS._player, &_parker, NULL); } else { - setAction(&_sequenceManager, this, 2452, &_actor1, &_actor2, NULL); + setAction(&_sequenceManager, this, 2452, &_companion, &_parker, NULL); } } break; case 2455: - R2_GLOBALS._player._oldCharacterScene[2] = 2450; - R2_GLOBALS._player._characterScene[2] = 2000; - R2_GLOBALS._v56605[2] = 3; - _actor1.remove(); + R2_GLOBALS._player._oldCharacterScene[R2_SEEKER] = 2450; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 2000; + R2_GLOBALS._spillLocation[R2_SEEKER] = 3; + _companion.remove(); R2_GLOBALS._player.enableControl(CURSOR_ARROW); break; default: - _actor1.postInit(); - _actor1.setDetails(9002, 0, 4, 3, 2, (SceneItem *)NULL); - _actor3.postInit(); - _actor3.setDetails(2001, 40, -1, -1, 2, (SceneItem *)NULL); + _companion.postInit(); + _companion.setDetails(9002, 0, 4, 3, 2, (SceneItem *)NULL); + _careTaker.postInit(); + _careTaker.setDetails(2001, 40, -1, -1, 2, (SceneItem *)NULL); _sceneMode = 2453; - setAction(&_sequenceManager, this, 2453, &_actor3, &_actor1, NULL); + setAction(&_sequenceManager, this, 2453, &_careTaker, &_companion, NULL); break; } } /*-------------------------------------------------------------------------- - * Scene 2455 - Ice Maze: Inside crevasse + * Scene 2455 - Spill Mountains: Inside crevasse * *--------------------------------------------------------------------------*/ @@ -2212,7 +2227,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 +2247,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 +2259,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 +2305,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 +2327,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 +2339,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 +2371,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; @@ -2384,7 +2399,7 @@ void Scene2455::signal() { } /*-------------------------------------------------------------------------- - * Scene 2500 - Ice Maze: Large Cave + * Scene 2500 - Spill Mountains: Large Cave * *--------------------------------------------------------------------------*/ @@ -2429,7 +2444,7 @@ void Scene2500::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(3, 2); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(21, 3, 1); @@ -2542,7 +2557,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)); @@ -2567,7 +2582,7 @@ void Scene2525::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._player._moveDiff = Common::Point(5, 3); } - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -2615,7 +2630,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: @@ -2629,7 +2644,7 @@ void Scene2525::signal() { } /*-------------------------------------------------------------------------- - * Scene 2530 - Ice Maze: Well + * Scene 2530 - Spill Mountains: Well * *--------------------------------------------------------------------------*/ bool Scene2530::Actor2::startAction(CursorType action, Event &event) { @@ -2698,7 +2713,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)); @@ -2728,7 +2743,7 @@ void Scene2530::postInit(SceneObjectList *OwnerList) { } R2_GLOBALS._player.setPosition(Common::Point(100, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -2766,7 +2781,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: @@ -2786,7 +2801,7 @@ void Scene2530::signal() { } /*-------------------------------------------------------------------------- - * Scene 2535 - Ice Maze: Tannery + * Scene 2535 - Spill Mountains: Tannery * *--------------------------------------------------------------------------*/ @@ -2798,7 +2813,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 +2861,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 +2874,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 +2882,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)); @@ -2893,7 +2908,7 @@ void Scene2535::postInit(SceneObjectList *OwnerList) { } R2_GLOBALS._player.setPosition(Common::Point(210, 200)); - if (R2_GLOBALS._player._characterScene[1] == R2_GLOBALS._player._characterScene[2]) { + if (R2_GLOBALS._player._characterScene[R2_QUINN] == R2_GLOBALS._player._characterScene[R2_SEEKER]) { _actor1.postInit(); if (R2_GLOBALS._player._characterIndex == 1) { _actor1.setup(20, 5, 1); @@ -2933,12 +2948,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 +2973,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: @@ -2970,7 +2985,7 @@ void Scene2535::signal() { } /*-------------------------------------------------------------------------- - * Scene 2600 - Ice Maze: Exit + * Scene 2600 - Spill Mountains: Exit * *--------------------------------------------------------------------------*/ Scene2600::Scene2600(): SceneExt() { @@ -3056,7 +3071,7 @@ void Scene2700::Action4::signal() { void Scene2700::Area1::process(Event &event) { SceneArea::process(event); - if ((event.eventType == 1) && (R2_GLOBALS._player._canWalk) && (_bounds.contains(event.mousePos))) { + if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._player._canWalk) && (_bounds.contains(event.mousePos))) { Scene2700 *scene = (Scene2700 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); scene->_sceneMode = 10; @@ -3106,7 +3121,7 @@ void Scene2700::Area1::process(Event &event) { void Scene2700::Area2::process(Event &event) { SceneArea::process(event); - if ((event.eventType == 1) && (R2_GLOBALS._player._canWalk) && (_bounds.contains(event.mousePos))) { + if ((event.eventType == EVENT_BUTTON_DOWN) && (R2_GLOBALS._player._canWalk) && (_bounds.contains(event.mousePos))) { Scene2700 *scene = (Scene2700 *)R2_GLOBALS._sceneManager._scene; R2_GLOBALS._player.disableControl(); scene->_sceneMode = 10; @@ -3211,7 +3226,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 +3467,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 +3869,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 +3944,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 +3958,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 +4463,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 +4484,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_scenes2.h b/engines/tsage/ringworld2/ringworld2_scenes2.h index feceaa1537..9802168a80 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes2.h +++ b/engines/tsage/ringworld2/ringworld2_scenes2.h @@ -45,23 +45,23 @@ class Scene2000 : public SceneExt { virtual void signal(); }; - class Exit1 : public SceneExit { + class WestExit : public SceneExit { public: virtual void changeScene(); }; - class Exit2 : public SceneExit { + class EastExit : public SceneExit { public: virtual void changeScene(); }; - class Exit3 : public SceneExit { + class SouthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit4 : public SceneExit { + class NorthExit : public SceneExit { public: virtual void changeScene(); }; - class Exit5 : public SceneExit { + class DoorExit : public SceneExit { public: virtual void changeScene(); }; @@ -72,11 +72,11 @@ public: NamedHotspot _item1; SceneActor _object1; SceneActor _objList1[11]; - Exit1 _exit1; - Exit2 _exit2; - Exit3 _exit3; - Exit4 _exit4; - Exit5 _exit5; + WestExit _westExit; + EastExit _eastExit; + SouthExit _southExit; + NorthExit _northExit; + DoorExit _doorExit; Action1 _action1, _action2, _action3, _action4, _action5; SequenceManager _sequenceManager; @@ -230,11 +230,11 @@ public: }; class Scene2435 : public SceneExt { - class Actor1 : public SceneActor { + class Companion : public SceneActor { public: bool startAction(CursorType action, Event &event); }; - class Actor2 : public SceneActor { + class Astor : public SceneActor { public: bool startAction(CursorType action, Event &event); }; @@ -247,11 +247,11 @@ public: SpeakerQuinn2435 _quinnSpeaker; SpeakerSeeker2435 _seekerSpeaker; SpeakerPharisha2435 _pharishaSpeaker; - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - Actor1 _actor1; - Actor2 _actor2; + NamedHotspot _background; + NamedHotspot _leftWindow; + NamedHotspot _rightWindow; + Companion _companion; + Astor _astor; Exit1 _exit1; SequenceManager _sequenceManager; @@ -301,11 +301,11 @@ public: }; class Scene2450 : public SceneExt { - class Actor2 : public SceneActor { + class Parker : public SceneActor { public: bool startAction(CursorType action, Event &event); }; - class Actor3 : public SceneActor { + class CareTaker : public SceneActor { public: bool startAction(CursorType action, Event &event); }; @@ -318,12 +318,12 @@ public: SpeakerQuinn2450 _quinnSpeaker; SpeakerSeeker2450 _seekerSpeaker; SpeakerCaretaker2450 _caretakerSpeaker; - NamedHotspot _item1; - NamedHotspot _item2; - NamedHotspot _item3; - SceneActor _actor1; - Actor2 _actor2; - Actor3 _actor3; + NamedHotspot _background; + NamedHotspot _post; + NamedHotspot _bedspread; + SceneActor _companion; + Parker _parker; + CareTaker _careTaker; Exit1 _exit1; SequenceManager _sequenceManager; diff --git a/engines/tsage/ringworld2/ringworld2_scenes3.cpp b/engines/tsage/ringworld2/ringworld2_scenes3.cpp index 6af2a0cad4..3c9a36c646 100644 --- a/engines/tsage/ringworld2/ringworld2_scenes3.cpp +++ b/engines/tsage/ringworld2/ringworld2_scenes3.cpp @@ -58,7 +58,7 @@ bool Scene3100::Guard::startAction(CursorType action, Event &event) { void Scene3100::postInit(SceneObjectList *OwnerList) { if (R2_GLOBALS._sceneManager._previousScene == 1000) { - if (R2_GLOBALS._player._oldCharacterScene[1] == 3100) { + if (R2_GLOBALS._player._oldCharacterScene[R2_QUINN] == 3100) { loadScene(3101); R2_GLOBALS._uiElements._active = false; } else { @@ -89,7 +89,7 @@ void Scene3100::postInit(SceneObjectList *OwnerList) { _field412 = 0; if (R2_GLOBALS._sceneManager._previousScene == 1000) { - if (R2_GLOBALS._player._oldCharacterScene[1] == 3100) { + if (R2_GLOBALS._player._oldCharacterScene[R2_QUINN] == 3100) { _sceneMode = 3102; _actor3.postInit(); _actor4.postInit(); @@ -153,7 +153,7 @@ void Scene3100::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._sound1.play(243); } - R2_GLOBALS._player._oldCharacterScene[1] = 3100; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 3100; } void Scene3100::remove() { @@ -178,7 +178,7 @@ void Scene3100::signal() { R2_GLOBALS._sceneManager.changeScene(1000); break; case 3102: - R2_GLOBALS._player._oldCharacterScene[1] = 1000; + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 1000; R2_GLOBALS._sceneManager.changeScene(1000); break; default: @@ -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,8 +535,8 @@ void Scene3150::Exit2::changeScene() { void Scene3150::postInit(SceneObjectList *OwnerList) { loadScene(3150); if (R2_GLOBALS._sceneManager._previousScene == -1) { - R2_INVENTORY.setObjectScene(35, 2000); - R2_GLOBALS._player._oldCharacterScene[1] = 3100; + R2_INVENTORY.setObjectScene(R2_ANCIENT_SCROLLS, 2000); + R2_GLOBALS._player._oldCharacterScene[R2_QUINN] = 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[R2_QUINN] == 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: @@ -1957,8 +1957,8 @@ void Scene3375::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_mirandaSpeaker); _stripManager.addSpeaker(&_webbsterSpeaker); - R2_GLOBALS._player._characterScene[1] = 3375; - R2_GLOBALS._player._characterScene[2] = 3375; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3375; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3375; R2_GLOBALS._player._characterScene[3] = 3375; setZoomPercents(126, 55, 200, 167); @@ -2292,8 +2292,8 @@ void Scene3385::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_mirandaSpeaker); _stripManager.addSpeaker(&_webbsterSpeaker); - R2_GLOBALS._player._characterScene[1] = 3385; - R2_GLOBALS._player._characterScene[2] = 3385; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3385; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3385; R2_GLOBALS._player._characterScene[3] = 3385; if (R2_GLOBALS._sceneManager._previousScene == 3375) @@ -2512,8 +2512,8 @@ void Scene3395::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_mirandaSpeaker); _stripManager.addSpeaker(&_webbsterSpeaker); - R2_GLOBALS._player._characterScene[1] = 3395; - R2_GLOBALS._player._characterScene[2] = 3395; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3395; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3395; R2_GLOBALS._player._characterScene[3] = 3395; if (R2_GLOBALS._sceneManager._previousScene == 3385) @@ -2669,8 +2669,8 @@ void Scene3400::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_tealSpeaker); setZoomPercents(51, 46, 180, 200); - R2_GLOBALS._player._characterScene[1] = 3400; - R2_GLOBALS._player._characterScene[2] = 3400; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3400; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3400; R2_GLOBALS._player._characterScene[3] = 3400; _actor7.postInit(); @@ -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; @@ -3577,8 +3577,8 @@ void Scene3500::postInit(SceneObjectList *OwnerList) { R2_GLOBALS._v5589E.set(0, 0, 320, 200); R2_GLOBALS._sound1.play(305); R2_GLOBALS._player._characterIndex = R2_QUINN; - R2_GLOBALS._player._characterScene[1] = 3500; - R2_GLOBALS._player._characterScene[2] = 3500; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3500; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3500; R2_GLOBALS._player._characterScene[3] = 3500; _field1284 = 0; _field1282 = 0; @@ -4377,8 +4377,8 @@ void Scene3600::postInit(SceneObjectList *OwnerList) { _stripManager.addSpeaker(&_protectorSpeaker); setZoomPercents(142, 80, 167, 105); - R2_GLOBALS._player._characterScene[1] = 3600; - R2_GLOBALS._player._characterScene[2] = 3600; + R2_GLOBALS._player._characterScene[R2_QUINN] = 3600; + R2_GLOBALS._player._characterScene[R2_SEEKER] = 3600; R2_GLOBALS._player._characterScene[3] = 3600; _item2.setDetails(33, 3600, 6, -1, -1); @@ -5319,7 +5319,7 @@ void Scene3800::signal() { } void Scene3800::process(Event &event) { - if ((R2_GLOBALS._player._uiEnabled) && (event.eventType == 1) && (_rect1.contains(event.mousePos))) { + if ((R2_GLOBALS._player._uiEnabled) && (event.eventType == EVENT_BUTTON_DOWN) && (_rect1.contains(event.mousePos))) { event.handled = true; switch (R2_GLOBALS._events.getCursor()) { case R2_NEGATOR_GUN: @@ -5582,7 +5582,7 @@ void Scene3900::signal() { } void Scene3900::process(Event &event) { - if ((R2_GLOBALS._player._uiEnabled) && (event.eventType == 1) && (_rect1.contains(event.mousePos))) { + if ((R2_GLOBALS._player._uiEnabled) && (event.eventType == EVENT_BUTTON_DOWN) && (_rect1.contains(event.mousePos))) { event.handled = true; switch (R2_GLOBALS._events.getCursor()) { case R2_NEGATOR_GUN: diff --git a/engines/tsage/ringworld2/ringworld2_speakers.cpp b/engines/tsage/ringworld2/ringworld2_speakers.cpp index 8d91787272..e908fb4412 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(); } @@ -1042,7 +1041,7 @@ void SpeakerPharisha2435::proc15() { Scene2435 *scene = (Scene2435 *)R2_GLOBALS._sceneManager._scene; if (!_object2) { - _object2 = &scene->_actor2; + _object2 = &scene->_astor; _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,6 +1275,7 @@ 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->_seeker; } @@ -1275,8 +1321,9 @@ 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; + _object2 = &scene->_companion; } _object2->hide(); @@ -1301,8 +1348,9 @@ 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; + _object2 = &scene->_companion; } _object2->hide(); @@ -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,6 +2075,7 @@ 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->_seeker; } @@ -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,8 +2163,9 @@ 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; + _object2 = &scene->_companion; } _object2->hide(); @@ -2102,8 +2190,9 @@ 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; + _object2 = &scene->_companion; } _object2->hide(); @@ -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; @@ -2577,7 +2666,7 @@ void SpeakerTeal1625::proc15() { if (!_object2) { Scene1625 *scene = (Scene1625 *)R2_GLOBALS._sceneManager._scene; - _object2 = &scene->_actor2; + _object2 = &scene->_tealHead; _object2->hide(); _object1.postInit(); @@ -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/base_persistence_manager.cpp b/engines/wintermute/base/base_persistence_manager.cpp index 2e2726f361..e5542d96b7 100644 --- a/engines/wintermute/base/base_persistence_manager.cpp +++ b/engines/wintermute/base/base_persistence_manager.cpp @@ -465,44 +465,53 @@ uint32 BasePersistenceManager::getDWORD() { ////////////////////////////////////////////////////////////////////////// -void BasePersistenceManager::putString(const Common::String &val) { - if (!val.size()) { - putString("(null)"); - } else { - _saveStream->writeUint32LE(val.size()); - _saveStream->writeString(val); +void BasePersistenceManager::putString(const char *val) { + if (!val) { + _saveStream->writeUint32LE(0); + return; } -} - -Common::String BasePersistenceManager::getStringObj() { - uint32 len = _loadStream->readUint32LE(); - char *ret = new char[len + 1]; - _loadStream->read(ret, len); - ret[len] = '\0'; - Common::String retString = ret; - delete[] ret; + uint32 len = strlen(val); - if (retString == "(null)") { - retString = ""; - } + _saveStream->writeUint32LE(len + 1); + _saveStream->write(val, len); +} - return retString; +Common::String BasePersistenceManager::getStringObj() { + return getString(); } ////////////////////////////////////////////////////////////////////////// char *BasePersistenceManager::getString() { uint32 len = _loadStream->readUint32LE(); - char *ret = new char[len + 1]; - _loadStream->read(ret, len); - ret[len] = '\0'; - if (!strcmp(ret, "(null)")) { - delete[] ret; - return nullptr; + if (checkVersion(1,2,2)) { + // Version 1.2.2 and above: len == strlen() + 1, NULL has len == 0 + + if (len == 0) + return nullptr; + + char *ret = new char[len]; + _loadStream->read(ret, len - 1); + ret[len - 1] = '\0'; + + return ret; + } else { + + // Version 1.2.1 and older: NULL strings are represented as "(null)" + char *ret = new char[len + 1]; + _loadStream->read(ret, len); + ret[len] = '\0'; + + if (!strcmp(ret, "(null)")) { + delete[] ret; + return nullptr; + } + return ret; } + } bool BasePersistenceManager::putTimeDate(const TimeDate &t) { @@ -536,8 +545,7 @@ void BasePersistenceManager::putFloat(float val) { int exponent = 0; float significand = frexp(val, &exponent); Common::String str = Common::String::format("FS%f", significand); - _saveStream->writeUint32LE(str.size()); - _saveStream->writeString(str); + putString(str.c_str()); _saveStream->writeSint32LE(exponent); } @@ -559,8 +567,7 @@ void BasePersistenceManager::putDouble(double val) { int exponent = 0; double significand = frexp(val, &exponent); Common::String str = Common::String::format("DS%f", significand); - _saveStream->writeUint32LE(str.size()); - _saveStream->writeString(str); + putString(str.c_str()); _saveStream->writeSint32LE(exponent); } @@ -711,7 +718,7 @@ bool BasePersistenceManager::transfer(const char *name, const char **val) { // Common::String bool BasePersistenceManager::transfer(const char *name, Common::String *val) { if (_saving) { - putString(*val); + putString(val->c_str()); return STATUS_OK; } else { char *str = getString(); diff --git a/engines/wintermute/base/base_persistence_manager.h b/engines/wintermute/base/base_persistence_manager.h index c09b3345b7..3c0587b362 100644 --- a/engines/wintermute/base/base_persistence_manager.h +++ b/engines/wintermute/base/base_persistence_manager.h @@ -52,7 +52,7 @@ public: void putDWORD(uint32 val); char *getString(); Common::String getStringObj(); - void putString(const Common::String &val); + void putString(const char *val); float getFloat(); void putFloat(float val); double getDouble(); diff --git a/engines/wintermute/base/font/base_font_truetype.cpp b/engines/wintermute/base/font/base_font_truetype.cpp index 3059a69047..b6f372f377 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(); @@ -559,7 +559,7 @@ bool BaseFontTT::initFont() { } if (file) { - _deletableFont = Graphics::loadTTFFont(*file, 96, _fontHeight); // Use the same dpi as WME (96 vs 72). + _deletableFont = Graphics::loadTTFFont(*file, _fontHeight, 96); // Use the same dpi as WME (96 vs 72). _font = _deletableFont; BaseFileManager::getEngineInstance()->closeFile(file); file = nullptr; diff --git a/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp b/engines/wintermute/base/gfx/osystem/base_render_osystem.cpp index 668105457f..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(); 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/base/scriptables/script_engine.cpp b/engines/wintermute/base/scriptables/script_engine.cpp index dd24457d6c..bb819b23e4 100644 --- a/engines/wintermute/base/scriptables/script_engine.cpp +++ b/engines/wintermute/base/scriptables/script_engine.cpp @@ -362,6 +362,8 @@ bool ScEngine::tick() { ////////////////////////////////////////////////////////////////////////// bool ScEngine::tickUnbreakable() { + ScScript *oldScript = _currentScript; + // execute unbreakable scripts for (uint32 i = 0; i < _scripts.size(); i++) { if (!_scripts[i]->_unbreakable) { @@ -373,9 +375,12 @@ bool ScEngine::tickUnbreakable() { _scripts[i]->executeInstruction(); } _scripts[i]->finish(); - _currentScript = nullptr; + _currentScript = oldScript; } - removeFinishedScripts(); + + // NB: Don't remove finished scripts here since we could be recursively + // executing scripts. Doing so could invalidate the outer iteration in + // ::tick() over _scripts. return STATUS_OK; } diff --git a/engines/wintermute/base/scriptables/script_value.cpp b/engines/wintermute/base/scriptables/script_value.cpp index 3532e127d0..31ec457df1 100644 --- a/engines/wintermute/base/scriptables/script_value.cpp +++ b/engines/wintermute/base/scriptables/script_value.cpp @@ -827,6 +827,17 @@ bool ScValue::persist(BasePersistenceManager *persistMgr) { persistMgr->transferPtr(TMEMBER_PTR(_valRef)); persistMgr->transfer(TMEMBER(_valString)); + if (!persistMgr->getIsSaving() && !persistMgr->checkVersion(1,2,2)) { + // Savegames prior to 1.2.2 stored empty strings as NULL. + // We disambiguate those by turning NULL strings into empty + // strings if _type is VAL_STRING instead of VAL_NULL. + + if (_type == VAL_STRING && !_valString) { + _valString = new char[1]; + _valString[0] = '\0'; + } + } + /* // TODO: Convert to Debug-statements. FILE* f = fopen("c:\\val.log", "a+"); switch(_type) diff --git a/engines/wintermute/dcgf.h b/engines/wintermute/dcgf.h index fe92194443..3db443965e 100644 --- a/engines/wintermute/dcgf.h +++ b/engines/wintermute/dcgf.h @@ -33,7 +33,7 @@ ////////////////////////////////////////////////////////////////////////// #define DCGF_VER_MAJOR 1 #define DCGF_VER_MINOR 2 -#define DCGF_VER_BUILD 1 +#define DCGF_VER_BUILD 2 #define DCGF_VER_SUFFIX "ScummVM" #define DCGF_VER_BETA true 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 e375322ae9..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? @@ -391,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 { @@ -433,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; @@ -463,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/EventRecorder.cpp b/gui/EventRecorder.cpp index 21152dd079..71f66911e9 100644 --- a/gui/EventRecorder.cpp +++ b/gui/EventRecorder.cpp @@ -481,6 +481,8 @@ Common::List<Common::Event> EventRecorder::mapEvent(const Common::Event &ev, Com default: return Common::DefaultEventMapper::mapEvent(ev, source); } + + return Common::DefaultEventMapper::mapEvent(ev, source); } void EventRecorder::setGameMd5(const ADGameDescription *gameDesc) { 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/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/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 34bc8c4a7a..5e4b91d1bd 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(); @@ -102,6 +109,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(); @@ -146,10 +159,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: @@ -250,21 +263,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(); @@ -379,7 +393,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); @@ -387,29 +401,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"); @@ -420,6 +415,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); @@ -427,17 +617,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) { @@ -460,6 +651,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: @@ -521,6 +753,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 5d52c7c797..fffcbfbe16 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); private: struct BitmapInfoHeader { @@ -157,7 +162,7 @@ private: 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); @@ -170,7 +175,12 @@ private: 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); } @@ -179,6 +189,7 @@ private: AVIStreamHeader _vidsHeader; BitmapInfoHeader _bmInfo; byte _palette[3 * 256]; + byte *_initialPalette; mutable bool _dirtyPalette; int _frameCount, _curFrame; @@ -194,6 +205,11 @@ private: 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/codecs/truemotion1.cpp b/video/codecs/truemotion1.cpp index e475c8426c..720e86a4ff 100644 --- a/video/codecs/truemotion1.cpp +++ b/video/codecs/truemotion1.cpp @@ -400,11 +400,14 @@ void TrueMotion1Decoder::decode16() { const Graphics::Surface *TrueMotion1Decoder::decodeImage(Common::SeekableReadStream *stream) { decodeHeader(stream); - if (compressionTypes[_header.compression].algorithm == ALGO_NOP) + if (compressionTypes[_header.compression].algorithm == ALGO_NOP) { + delete[] _buf; return 0; + } if (compressionTypes[_header.compression].algorithm == ALGO_RGB24H) { warning("Unhandled TrueMotion1 24bpp frame"); + delete[] _buf; return 0; } else decode16(); 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; |