diff options
Diffstat (limited to 'engines/kyra/engine/timer.cpp')
-rw-r--r-- | engines/kyra/engine/timer.cpp | 304 |
1 files changed, 304 insertions, 0 deletions
diff --git a/engines/kyra/engine/timer.cpp b/engines/kyra/engine/timer.cpp new file mode 100644 index 0000000000..9728838015 --- /dev/null +++ b/engines/kyra/engine/timer.cpp @@ -0,0 +1,304 @@ +/* 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 "kyra/engine/timer.h" + +#include "common/system.h" + +namespace Kyra { + +namespace { +struct TimerResync : public Common::UnaryFunction<TimerEntry&, void> { + uint32 _tickLength, _curTime; + TimerResync(KyraEngine_v1 *vm, uint32 curTime) : _tickLength(vm->tickLength()), _curTime(curTime) {} + + void operator()(TimerEntry &entry) const { + if (entry.lastUpdate < 0) { + if ((uint32)(ABS(entry.lastUpdate)) >= entry.countdown * _tickLength) + entry.nextRun = 0; + else + entry.nextRun = _curTime + entry.lastUpdate + entry.countdown * _tickLength; + } else { + uint32 nextRun = entry.lastUpdate + entry.countdown * _tickLength; + if (_curTime < nextRun) + nextRun = 0; + entry.nextRun = nextRun; + } + } +}; + +struct TimerEqual : public Common::UnaryFunction<const TimerEntry&, bool> { + uint8 _id; + + TimerEqual(uint8 id) : _id(id) {} + + bool operator()(const TimerEntry &entry) const { + return entry.id == _id; + } +}; +} // end of anonymous namespace + +void TimerManager::pause(bool p) { + if (p) { + ++_isPaused; + + if (_isPaused == 1) { + _isPaused = true; + _pauseStart = _system->getMillis(); + } + } else if (!p && _isPaused > 0) { + --_isPaused; + + if (_isPaused == 0) { + const uint32 pausedTime = _system->getMillis() - _pauseStart; + _nextRun += pausedTime; + + for (Iterator pos = _timers.begin(); pos != _timers.end(); ++pos) { + pos->lastUpdate += pausedTime; + pos->nextRun += pausedTime; + } + } + } +} + +void TimerManager::reset() { + for (Iterator pos = _timers.begin(); pos != _timers.end(); ++pos) + delete pos->func; + + _timers.clear(); +} + +void TimerManager::addTimer(uint8 id, TimerFunc *func, int countdown, bool enabled) { + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) { + warning("Adding already existing timer %d", id); + return; + } + + TimerEntry newTimer; + + newTimer.id = id; + newTimer.countdown = countdown; + newTimer.enabled = enabled ? 1 : 0; + newTimer.lastUpdate = newTimer.nextRun = 0; + newTimer.func = func; + newTimer.pauseStartTime = 0; + + _timers.push_back(newTimer); +} + +void TimerManager::update() { + if (_system->getMillis() < _nextRun || _isPaused) + return; + + _nextRun += 99999; + + for (Iterator pos = _timers.begin(); pos != _timers.end(); ++pos) { + if (pos->enabled == 1 && pos->countdown >= 0) { + if (pos->nextRun <= _system->getMillis()) { + if (pos->func && pos->func->isValid()) { + (*pos->func)(pos->id); + } + + uint32 curTime = _system->getMillis(); + pos->lastUpdate = curTime; + pos->nextRun = curTime + pos->countdown * _vm->tickLength(); + } + + _nextRun = MIN(_nextRun, pos->nextRun); + } + } +} + +void TimerManager::resync() { + const uint32 curTime = _isPaused ? _pauseStart : _system->getMillis(); + + _nextRun = 0; // force rerun + Common::for_each(_timers.begin(), _timers.end(), TimerResync(_vm, curTime)); +} + +void TimerManager::resetNextRun() { + _nextRun = 0; +} + +void TimerManager::setCountdown(uint8 id, int32 countdown) { + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) { + timer->countdown = countdown; + + if (countdown >= 0) { + uint32 curTime = _system->getMillis(); + timer->lastUpdate = curTime; + timer->nextRun = curTime + countdown * _vm->tickLength(); + if (timer->enabled & 2) + timer->pauseStartTime = curTime; + + _nextRun = MIN(_nextRun, timer->nextRun); + } + } else { + warning("TimerManager::setCountdown: No timer %d", id); + } +} + +void TimerManager::setDelay(uint8 id, int32 countdown) { + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) + timer->countdown = countdown; + else + warning("TimerManager::setDelay: No timer %d", id); +} + +int32 TimerManager::getDelay(uint8 id) const { + CIterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) + return timer->countdown; + + warning("TimerManager::getDelay: No timer %d", id); + return -1; +} + +void TimerManager::setNextRun(uint8 id, uint32 nextRun) { + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) { + if (timer->enabled & 2) + timer->pauseStartTime = _system->getMillis(); + timer->nextRun = nextRun; + return; + } + + warning("TimerManager::setNextRun: No timer %d", id); +} + +uint32 TimerManager::getNextRun(uint8 id) const { + CIterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) + return timer->nextRun; + + warning("TimerManager::getNextRun: No timer %d", id); + return 0xFFFFFFFF; +} + +void TimerManager::pauseSingleTimer(uint8 id, bool p) { + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + + if (timer == _timers.end()) { + warning("TimerManager::pauseSingleTimer: No timer %d", id); + return; + } + + if (p) { + timer->pauseStartTime = _system->getMillis(); + timer->enabled |= 2; + } else if (timer->pauseStartTime) { + int32 elapsedTime = _system->getMillis() - timer->pauseStartTime; + timer->enabled &= (~2); + timer->lastUpdate += elapsedTime; + timer->nextRun += elapsedTime; + resetNextRun(); + timer->pauseStartTime = 0; + } +} + +bool TimerManager::isEnabled(uint8 id) const { + CIterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) + return (timer->enabled & 1); + + warning("TimerManager::isEnabled: No timer %d", id); + return false; +} + +void TimerManager::enable(uint8 id) { + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) + timer->enabled |= 1; + else + warning("TimerManager::enable: No timer %d", id); +} + +void TimerManager::disable(uint8 id) { + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) + timer->enabled &= (~1); + else + warning("TimerManager::disable: No timer %d", id); +} + +void TimerManager::loadDataFromFile(Common::SeekableReadStream &file, int version) { + const uint32 loadTime = _isPaused ? _pauseStart : _system->getMillis(); + + if (version <= 7) { + _nextRun = 0; + for (int i = 0; i < 32; ++i) { + uint8 enabled = file.readByte(); + int32 countdown = file.readSint32BE(); + uint32 nextRun = file.readUint32BE(); + + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(i)); + if (timer != _timers.end()) { + timer->enabled = enabled; + timer->countdown = countdown; + + if (nextRun) { + timer->nextRun = nextRun + loadTime; + timer->lastUpdate = timer->nextRun - countdown * _vm->tickLength(); + } else { + timer->nextRun = loadTime; + timer->lastUpdate = loadTime - countdown * _vm->tickLength(); + } + } else { + warning("Loading timer data for non existing timer %d", i); + } + } + } else { + int entries = file.readByte(); + for (int i = 0; i < entries; ++i) { + uint8 id = file.readByte(); + + Iterator timer = Common::find_if(_timers.begin(), _timers.end(), TimerEqual(id)); + if (timer != _timers.end()) { + timer->enabled = file.readByte(); + timer->countdown = file.readSint32BE(); + timer->lastUpdate = file.readSint32BE(); + } else { + warning("Loading timer data for non existing timer %d", id); + file.seek(7, SEEK_CUR); + } + } + + resync(); + } +} + +void TimerManager::saveDataToFile(Common::WriteStream &file) const { + const uint32 saveTime = _isPaused ? _pauseStart : _system->getMillis(); + + file.writeByte(count()); + for (CIterator pos = _timers.begin(); pos != _timers.end(); ++pos) { + file.writeByte(pos->id); + file.writeByte(pos->enabled); + file.writeSint32BE(pos->countdown); + file.writeSint32BE(pos->lastUpdate - saveTime); + } +} + +} // End of namespace Kyra |