ResidualVM logo ResidualVM website - Forums - Contact us BuildBot - Doxygen - Wiki curved edge

chore.cpp

Go to the documentation of this file.
00001 /* ResidualVM - A 3D game interpreter
00002  *
00003  * ResidualVM is the legal property of its developers, whose names
00004  * are too numerous to list here. Please refer to the COPYRIGHT
00005  * file distributed with this source distribution.
00006  *
00007  * This program is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License
00009  * as published by the Free Software Foundation; either version 2
00010  * of the License, or (at your option) any later version.
00011  *
00012  * This program is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015  * GNU General Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License
00018  * along with this program; if not, write to the Free Software
00019  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00020  *
00021  */
00022 
00023 #include "engines/grim/costume.h"
00024 #include "engines/grim/savegame.h"
00025 #include "engines/grim/textsplit.h"
00026 
00027 #include "engines/grim/costume/chore.h"
00028 #include "engines/grim/costume/component.h"
00029 #include "engines/grim/costume/keyframe_component.h"
00030 
00031 namespace Grim {
00032 
00033 // Should initialize the status variables so the chore can't play unexpectedly
00034 Chore::Chore(char name[32], int id, Costume *owner, int length, int numTracks) :
00035         _hasPlayed(false), _playing(false), _looping(false), _paused(false), _currTime(-1),
00036         _numTracks(numTracks), _length(length), _choreId(id), _owner(owner) {
00037 
00038     memcpy(_name, name, 32);
00039     _tracks = new ChoreTrack[_numTracks];
00040 }
00041 
00042 Chore::~Chore() {
00043     if (_tracks) {
00044         for (int i = 0; i < _numTracks; i++)
00045             delete[] _tracks[i].keys;
00046 
00047         delete[] _tracks;
00048         _tracks = nullptr;
00049     }
00050 }
00051 
00052 void Chore::load(TextSplitter &ts) {
00053     _hasPlayed = _playing = false;
00054     for (int i = 0; i < _numTracks; i++) {
00055         int compID, numKeys;
00056         ts.scanString(" %d %d", 2, &compID, &numKeys);
00057         _tracks[i].compID = compID;
00058         _tracks[i].numKeys = numKeys;
00059         _tracks[i].keys = new TrackKey[numKeys];
00060         for (int j = 0; j < numKeys; j++) {
00061             ts.scanString(" %d %d", 2, &_tracks[i].keys[j].time, &_tracks[i].keys[j].value);
00062         }
00063     }
00064 }
00065 
00066 void Chore::play(uint msecs) {
00067     _playing = true;
00068     _paused = false;
00069     _hasPlayed = true;
00070     _looping = false;
00071     _currTime = -1;
00072 
00073     if (msecs > 0)
00074         fade(Animation::FadeIn, msecs);
00075     else
00076         fade(Animation::None, 0);
00077 }
00078 
00079 void Chore::playLooping(uint msecs) {
00080     _playing = true;
00081     _paused = false;
00082     _hasPlayed = true;
00083     _looping = true;
00084     _currTime = -1;
00085 
00086     if (msecs > 0)
00087         fade(Animation::FadeIn, msecs);
00088     else
00089         fade(Animation::None, 0);
00090 }
00091 
00092 Component *Chore::getComponentForTrack(int i) const {
00093     if (_tracks[i].compID == -1)
00094         return _tracks[i].component;
00095     else
00096         return _owner->_components[_tracks[i].compID];
00097 }
00098 
00099 void Chore::stop(uint msecs) {
00100     if (msecs > 0)
00101         fade(Animation::FadeOut, msecs);
00102 
00103     _playing = false;
00104     _hasPlayed = false;
00105 
00106     for (int i = 0; i < _numTracks; i++) {
00107         Component *comp = getComponentForTrack(i);
00108         if (comp)
00109             comp->reset();
00110     }
00111 }
00112 
00113 void Chore::setKeys(int startTime, int stopTime) {
00114     for (int i = 0; i < _numTracks; i++) {
00115         Component *comp = getComponentForTrack(i);
00116         if (!comp)
00117             continue;
00118 
00119         for (int j = 0; j < _tracks[i].numKeys; j++) {
00120             if (_tracks[i].keys[j].time > stopTime && stopTime != -1)
00121                 break;
00122             if (_tracks[i].keys[j].time > startTime)
00123                 comp->setKey(_tracks[i].keys[j].value);
00124         }
00125     }
00126 }
00127 
00128 void Chore::setLastFrame() {
00129     // If the chore has already played then don't set it to the end
00130     // Example: This executing would result in Glottis being
00131     // choppy when he hands Manny the work order
00132     //  if (_hasPlayed)
00133     //      return;
00134 
00135     // This comment above is perfectly right, but unfortunately doing that
00136     // breaks glottis movements when he answers to "i'm calavera, manny calavera".
00137     // Moreover, the choppy behaviour stated above happens with grim original too,
00138     // meaning the bug is not in Residual but in the scripts or in GrimE design.
00139 
00140     _currTime = -1;
00141     _playing = false;
00142     _paused = false;
00143     _hasPlayed = true;
00144     _looping = false;
00145 
00146     // In the demo, the chore 4 (stop_talk) of ms.cos, has length 67, and 4 keys,
00147     // the last two of which are at time 133 and 200. We use -1 as stopTime here
00148     // as a special value, instead of _length, to ensure all the keys are run.
00149     // (failing to do so will result in manny's mouth not closing when he stops talking)
00150     setKeys(-1, -1);
00151 }
00152 
00153 void Chore::update(uint time) {
00154     if (!_playing || _paused)
00155         return;
00156 
00157     int newTime;
00158     if (_currTime < 0)
00159         newTime = 0; // For first time through
00160     else
00161         newTime = _currTime + time;
00162 
00163     setKeys(_currTime, newTime);
00164 
00165     if (newTime > _length) {
00166         if (!_looping) {
00167             _playing = false;
00168         } else {
00169             do {
00170                 newTime -= _length;
00171                 setKeys(-1, newTime);
00172             } while (newTime > _length);
00173         }
00174     }
00175     _currTime = newTime;
00176 }
00177 
00178 void Chore::fade(Animation::FadeMode mode, uint msecs) {
00179     if (mode == Animation::FadeIn) {
00180         if (!_playing) {
00181             _playing = true;
00182             _hasPlayed = true;
00183             _currTime = -1;
00184         }
00185     } else if (mode == Animation::FadeOut) {
00186         // Stop the chore, but do not alter the components state.
00187         _playing = false;
00188     }
00189 
00190     for (int i = 0; i < _numTracks; i++) {
00191         Component *comp = getComponentForTrack(i);
00192         if (comp) {
00193             comp->fade(mode, msecs);
00194         }
00195     }
00196 }
00197 
00198 void Chore::fadeIn(uint msecs) {
00199     fade(Animation::FadeIn, msecs);
00200 }
00201 
00202 void Chore::fadeOut(uint msecs) {
00203     // Note: It doesn't matter whether the chore is playing or not. The keyframe
00204     // components should fade out in either case.
00205     fade(Animation::FadeOut, msecs);
00206 }
00207 
00208 void Chore::setPaused(bool paused) {
00209     _paused = paused;
00210 
00211     for (int i = 0; i < _numTracks; i++) {
00212         Component *comp = getComponentForTrack(i);
00213         if (comp) {
00214             comp->setPaused(paused);
00215         }
00216     }
00217 }
00218 
00219 void Chore::advance(uint msecs) {
00220     setKeys(_currTime, _currTime + msecs);
00221 
00222     for (int i = 0; i < _numTracks; i++) {
00223         Component *comp = getComponentForTrack(i);
00224         if (comp) {
00225             comp->advance(msecs);
00226         }
00227     }
00228 
00229     _currTime += msecs;
00230 }
00231 
00232 void Chore::saveState(SaveGame *state) const {
00233     state->writeBool(_hasPlayed);
00234     state->writeBool(_playing);
00235     state->writeBool(_looping);
00236     state->writeLESint32(_currTime);
00237     state->writeBool(_paused);
00238 }
00239 
00240 void Chore::restoreState(SaveGame *state) {
00241     _hasPlayed = state->readBool();
00242     _playing = state->readBool();
00243     _looping = state->readBool();
00244     _currTime = state->readLESint32();
00245     if (state->saveMinorVersion() >= 10)
00246         _paused = state->readBool();
00247 }
00248 
00249 } // end of namespace Grim


Generated on Sat Mar 23 2019 05:01:22 for ResidualVM by doxygen 1.7.1
curved edge   curved edge