Initial commit
This commit is contained in:
303
engines/kyra/engine/timer.cpp
Normal file
303
engines/kyra/engine/timer.cpp
Normal file
@@ -0,0 +1,303 @@
|
||||
/* 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 3 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, see <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#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
|
||||
Reference in New Issue
Block a user