scummvm/engines/pegasus/energymonitor.cpp
2016-09-03 12:46:38 +02:00

300 lines
7.2 KiB
C++

/* 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.
*
* Additional copyright for this file:
* Copyright (C) 1995-1997 Presto Studios, Inc.
*
* 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 "pegasus/energymonitor.h"
#include "pegasus/pegasus.h"
#include "pegasus/surface.h"
namespace Pegasus {
Blinker::Blinker() {
_sprite = 0;
_frame1 = -1;
_frame2 = -1;
_blinkDuration = 0;
}
void Blinker::startBlinking(Sprite *sprite, int32 frame1, int32 frame2, uint32 numBlinks, TimeValue blinkDuration, TimeScale blinkScale) {
stopBlinking();
_sprite = sprite;
_frame1 = frame1;
_frame2 = frame2;
_blinkDuration = blinkDuration;
setScale(blinkScale);
setSegment(0, blinkDuration * numBlinks * 2, blinkScale);
setTime(0);
start();
}
void Blinker::stopBlinking() {
if (_sprite) {
_sprite->setCurrentFrameIndex(_frame2);
_sprite = 0;
stop();
}
}
void Blinker::timeChanged(const TimeValue time) {
if (_sprite && _blinkDuration != 0) {
if (((time / _blinkDuration) & 1) != 0 || time == getDuration()) {
_sprite->setCurrentFrameIndex(_frame2);
if (!isRunning())
stopBlinking();
} else {
_sprite->setCurrentFrameIndex(_frame1);
}
}
}
enum {
kEnergyExpiredFlag = 1
};
EnergyMonitor *g_energyMonitor = 0;
EnergyMonitor::EnergyMonitor() : IdlerAnimation(kEnergyBarID), _energyLight(kWarningLightID) {
PegasusEngine *vm = (PegasusEngine *)g_engine;
_stage = kStageNoStage;
_calibrating = false;
_dontFlash = false;
setBounds(338, 48, 434, 54);
setDisplayOrder(kEnergyBarOrder);
startDisplaying();
SpriteFrame *frame = new SpriteFrame();
frame->initFromPICTResource(vm->_resFork, kLightOffID);
_energyLight.addFrame(frame, 0, 0);
frame = new SpriteFrame();
frame->initFromPICTResource(vm->_resFork, kLightYellowID);
_energyLight.addFrame(frame, 0, 0);
frame = new SpriteFrame();
frame->initFromPICTResource(vm->_resFork, kLightOrangeID);
_energyLight.addFrame(frame, 0, 0);
frame = new SpriteFrame();
frame->initFromPICTResource(vm->_resFork, kLightRedID);
_energyLight.addFrame(frame, 0, 0);
_energyLight.setBounds(540, 35, 600, 59);
_energyLight.setDisplayOrder(kEnergyLightOrder);
_energyLight.startDisplaying();
setScale(1);
setSegment(0, kMaxJMPEnergy);
setEnergyValue(kCasualEnergy);
g_energyMonitor = this;
}
EnergyMonitor::~EnergyMonitor() {
g_energyMonitor = 0;
}
void EnergyMonitor::setEnergyValue(const uint32 value) {
if (isRunning()) {
stop();
setTime(getStop() - value);
start();
} else {
setTime(getStop() - value);
}
}
void EnergyMonitor::startEnergyDraining() {
if (!isRunning()) {
_energyLight.show();
start();
show();
}
}
void EnergyMonitor::setEnergyDrainRate(Common::Rational rate) {
setRate(rate);
}
Common::Rational EnergyMonitor::getEnergyDrainRate() {
return getRate();
}
void EnergyMonitor::stopEnergyDraining() {
if (isRunning()) {
stop();
_energyLight.hide();
hide();
}
}
void EnergyMonitor::drainEnergy(const int32 delta) {
setTime(getTime() + delta);
}
int32 EnergyMonitor::getCurrentEnergy() {
return kMaxJMPEnergy - getTime();
}
void EnergyMonitor::timeChanged(const TimeValue currentTime) {
if (currentTime == getStop()) {
PegasusEngine *vm = (PegasusEngine *)g_engine;
if (vm->getEnergyDeathReason() != -1)
vm->die(vm->getEnergyDeathReason());
} else {
uint32 currentEnergy = kMaxJMPEnergy - currentTime;
EnergyStage newStage;
if (currentEnergy > kWorriedEnergy)
newStage = kStageCasual;
else if (currentEnergy > kNervousEnergy)
newStage = kStageWorried;
else if (currentEnergy > kPanicStrickenEnergy)
newStage = kStageNervous;
else
newStage = kStagePanicStricken;
if (_stage != newStage) {
uint32 newFrame;
switch (newStage) {
case kStageCasual:
_barColor = g_system->getScreenFormat().RGBToColor(0x48, 0xB0, 0xD8);
newFrame = kFrameLightOff;
break;
case kStageWorried:
_barColor = g_system->getScreenFormat().RGBToColor(0xD8, 0xC0, 0x30);
newFrame = kFrameLightYellow;
break;
case kStageNervous:
_barColor = g_system->getScreenFormat().RGBToColor(0xD8, 0x78, 0x38);
newFrame = kFrameLightOrange;
break;
case kStagePanicStricken:
_barColor = g_system->getScreenFormat().RGBToColor(0xD8, 0x40, 0x38);
newFrame = kFrameLightRed;
break;
default:
error("no stage in energy monitor?");
break;
}
_stage = newStage;
uint32 oldFrame = _energyLight.getCurrentFrameIndex();
if (!_calibrating) {
if (oldFrame > newFrame || oldFrame == 0xffffffff || _dontFlash) {
_energyLight.setCurrentFrameIndex(newFrame);
_dontFlash = false;
} else {
_lightBlinker.startBlinking(&_energyLight, oldFrame, newFrame, 4, 1, 3);
triggerRedraw();
}
}
}
Common::Rect r;
calcLevelRect(r);
if (r != _levelRect) {
_levelRect = r;
triggerRedraw();
}
}
}
void EnergyMonitor::calcLevelRect(Common::Rect &r) {
if (getStop() == 0) {
r = Common::Rect();
} else {
getBounds(r);
r.left = r.right - r.width() * (kMaxJMPEnergy - getTime()) / getStop();
}
}
void EnergyMonitor::draw(const Common::Rect &r) {
Common::Rect r2 = r.findIntersectingRect(_levelRect);
if (!r2.isEmpty()) {
Graphics::Surface *screen = ((PegasusEngine *)g_engine)->_gfx->getWorkArea();
screen->fillRect(r2, _barColor);
}
}
void EnergyMonitor::calibrateEnergyBar() {
PegasusEngine *vm = (PegasusEngine *)g_engine;
_calibrating = true;
vm->setEnergyDeathReason(-1);
uint32 numFrames = _energyLight.getNumFrames();
for (uint32 i = 1; i < numFrames; i++) {
_energyLight.setCurrentFrameIndex(i);
_energyLight.show();
vm->delayShell(1, 3);
_energyLight.hide();
vm->delayShell(1, 3);
}
_energyLight.setCurrentFrameIndex(0);
_energyLight.hide();
setEnergyValue(0);
setEnergyDrainRate(-(int32)kMaxJMPEnergy / 2);
show();
// Make sure warning light is hidden...
_energyLight.hide();
while (getCurrentEnergy() != (int32)kMaxJMPEnergy) {
InputDevice.pumpEvents();
vm->checkCallBacks();
vm->refreshDisplay();
g_system->delayMillis(10);
}
vm->refreshDisplay();
setEnergyDrainRate(0);
hide();
_calibrating = false;
}
void EnergyMonitor::restoreLastEnergyValue() {
PegasusEngine *vm = (PegasusEngine *)g_engine;
_dontFlash = true;
setEnergyValue(vm->getSavedEnergyValue());
vm->resetEnergyDeathReason();
}
void EnergyMonitor::saveCurrentEnergyValue() {
((PegasusEngine *)g_engine)->setLastEnergyValue(getCurrentEnergy());
}
} // End of namespace Pegasus