scummvm/engines/gob/minigames/geisha/diving.cpp
Sven Hesse 0f9b1364cf GOB: Remove the last remnants of Draw::_vgaSmallPalette
Draw::_vgaSmallPalette was supposed to be a 16-color VGA
palette / EGA palette, but we've been using the first 16
entries of Draw::_vgaPalette for that for ages now.

The only parts where we didn't were codepaths never
actually taken in the gob games, so for the sake of
clarity (and fixing Coverity issues), this commit removes
those as well.

Fixes Coverity issues 1192648 and 1192649.
2014-03-16 15:35:35 +01:00

832 lines
20 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.
*
* 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 "common/list.h"
#include "gob/global.h"
#include "gob/palanim.h"
#include "gob/draw.h"
#include "gob/video.h"
#include "gob/decfile.h"
#include "gob/anifile.h"
#include "gob/sound/sound.h"
#include "gob/minigames/geisha/evilfish.h"
#include "gob/minigames/geisha/oko.h"
#include "gob/minigames/geisha/meter.h"
#include "gob/minigames/geisha/diving.h"
namespace Gob {
namespace Geisha {
static const uint8 kAirDecreaseRate = 15;
static const byte kPalette[48] = {
0x00, 0x02, 0x12,
0x01, 0x04, 0x1D,
0x05, 0x08, 0x28,
0x0C, 0x0D, 0x33,
0x15, 0x14, 0x3F,
0x00, 0x3F, 0x00,
0x3F, 0x00, 0x00,
0x00, 0x00, 0x00,
0x21, 0x0D, 0x00,
0x2F, 0x1A, 0x04,
0x3D, 0x2B, 0x0D,
0x10, 0x10, 0x10,
0x1A, 0x1A, 0x1A,
0x24, 0x24, 0x24,
0x00, 0x01, 0x0F,
0x3F, 0x3F, 0x3F
};
enum Animation {
kAnimationLungs = 0,
kAnimationHeart = 1,
kAnimationPearl = 4,
kAnimationJellyfish = 6,
kAnimationWater = 7,
kAnimationShot = 17,
kAnimationSwarmRedGreen = 32,
kAnimationSwarmOrange = 33
};
const uint16 Diving::kEvilFishTypes[kEvilFishTypeCount][5] = {
{ 0, 14, 8, 9, 3}, // Shark
{15, 1, 12, 13, 3}, // Moray
{16, 2, 10, 11, 3} // Ray
};
const uint16 Diving::kPlantLevel1[] = { 18, 19, 20, 21 };
const uint16 Diving::kPlantLevel2[] = { 22, 23, 24, 25 };
const uint16 Diving::kPlantLevel3[] = { 26, 27, 28, 29, 30 };
const Diving::PlantLevel Diving::kPlantLevels[] = {
{ 150, ARRAYSIZE(kPlantLevel1), kPlantLevel1 },
{ 120, ARRAYSIZE(kPlantLevel2), kPlantLevel2 },
{ 108, ARRAYSIZE(kPlantLevel3), kPlantLevel3 },
};
Diving::Diving(GobEngine *vm) : _vm(vm), _background(0),
_objects(0), _gui(0), _okoAnim(0), _water(0), _lungs(0), _heart(0),
_blackPearl(0), _airMeter(0), _healthMeter(0), _isPlaying(false) {
_blackPearl = new Surface(11, 8, 1);
_airMeter = new Meter(3 , 195, 40, 2, 5, 7, 40, Meter::kFillToLeft);
_healthMeter = new Meter(275, 195, 40, 2, 6, 7, 4, Meter::kFillToLeft);
for (uint i = 0; i < kEvilFishCount; i++)
_evilFish[i].evilFish = 0;
for (uint i = 0; i < kDecorFishCount; i++)
_decorFish[i].decorFish = 0;
for (uint i = 0; i < kPlantCount; i++)
_plant[i].plant = 0;
for (uint i = 0; i < kMaxShotCount; i++)
_shot[i] = 0;
_pearl.pearl = 0;
_oko = 0;
}
Diving::~Diving() {
delete _airMeter;
delete _healthMeter;
delete _blackPearl;
deinit();
}
bool Diving::play(uint16 playerCount, bool hasPearlLocation) {
_hasPearlLocation = hasPearlLocation;
_isPlaying = true;
// Fade to black
_vm->_palAnim->fade(0, 0, 0);
// Initialize our playing field
init();
initScreen();
initCursor();
initPlants();
updateAirMeter();
updateAnims();
_vm->_draw->blitInvalidated();
_vm->_video->retrace();
// Fade in
_vm->_palAnim->fade(_vm->_global->_pPaletteDesc, 0, 0);
while (!_vm->shouldQuit()) {
checkShots(); // Check if a shot hit something
checkOkoHurt(); // Check if Oko was hurt
// Is Oko dead?
if (_oko->isPaused())
break;
// Update all objects and animations
updateAirMeter();
updateEvilFish();
updateDecorFish();
updatePlants();
updatePearl();
updateAnims();
_vm->_draw->animateCursor(1);
// Draw and wait for the end of the frame
_vm->_draw->blitInvalidated();
_vm->_util->waitEndFrame();
// Handle input
_vm->_util->processInput();
int16 mouseX, mouseY;
MouseButtons mouseButtons;
int16 key = checkInput(mouseX, mouseY, mouseButtons);
// Aborting the game
if (key == kKeyEscape)
break;
// Shoot the gun
if (mouseButtons == kMouseButtonsLeft)
shoot(mouseX, mouseY);
// Oko
handleOko(key);
// Game end check
if ((_whitePearlCount >= 20) || (_blackPearlCount >= 2))
break;
}
deinit();
_isPlaying = false;
// The game succeeded when we got 2 black pearls
return _blackPearlCount >= 2;
}
bool Diving::isPlaying() const {
return _isPlaying;
}
void Diving::cheatWin() {
_blackPearlCount = 2;
}
void Diving::init() {
// Load sounds
_vm->_sound->sampleLoad(&_soundShoot , SOUND_SND, "tirgim.snd");
_vm->_sound->sampleLoad(&_soundBreathe , SOUND_SND, "respir.snd");
_vm->_sound->sampleLoad(&_soundWhitePearl, SOUND_SND, "virtou.snd");
_vm->_sound->sampleLoad(&_soundBlackPearl, SOUND_SND, "trouve.snd");
// Load and initialize sprites and animations
_background = new DECFile(_vm, "tperle.dec" , 320, 200);
_objects = new ANIFile(_vm, "tperle.ani" , 320);
_gui = new ANIFile(_vm, "tperlcpt.ani", 320);
_okoAnim = new ANIFile(_vm, "tplonge.ani" , 320);
_water = new ANIObject(*_objects);
_lungs = new ANIObject(*_gui);
_heart = new ANIObject(*_gui);
_water->setAnimation(kAnimationWater);
_water->setPosition();
_water->setVisible(true);
_lungs->setAnimation(kAnimationLungs);
_lungs->setPosition();
_lungs->setVisible(true);
_lungs->setPause(true);
_heart->setAnimation(kAnimationHeart);
_heart->setPosition();
_heart->setVisible(true);
_heart->setPause(true);
for (uint i = 0; i < kEvilFishCount; i++) {
_evilFish[i].enterAt = 0;
_evilFish[i].leaveAt = 0;
_evilFish[i].evilFish = new EvilFish(*_objects, 320, 0, 0, 0, 0, 0);
}
for (uint i = 0; i < kDecorFishCount; i++) {
_decorFish[i].enterAt = 0;
_decorFish[i].decorFish = new ANIObject(*_objects);
}
for (uint i = 0; i < kPlantCount; i++) {
_plant[i].level = i / kPlantPerLevelCount;
_plant[i].deltaX = (kPlantLevelCount - _plant[i].level) * -2;
_plant[i].x = -1;
_plant[i].y = -1;
_plant[i].plant = new ANIObject(*_objects);
}
_pearl.pearl = new ANIObject(*_objects);
_pearl.black = false;
_pearl.pearl->setAnimation(kAnimationPearl);
_decorFish[0].decorFish->setAnimation(kAnimationJellyfish);
_decorFish[0].deltaX = 0;
_decorFish[1].decorFish->setAnimation(kAnimationSwarmRedGreen);
_decorFish[1].deltaX = -5;
_decorFish[2].decorFish->setAnimation(kAnimationSwarmOrange);
_decorFish[2].deltaX = -5;
for (uint i = 0; i < kMaxShotCount; i++) {
_shot[i] = new ANIObject(*_objects);
_shot[i]->setAnimation(kAnimationShot);
_shot[i]->setMode(ANIObject::kModeOnce);
}
_oko = new Oko(*_okoAnim, *_vm->_sound, _soundBreathe);
Surface tmp(320, 103, 1);
_vm->_video->drawPackedSprite("tperlobj.cmp", tmp);
_blackPearl->blit(tmp, 282, 80, 292, 87, 0, 0);
_blackPearlCount = 0;
_currentShot = 0;
// Add the animations to our animation list
_anims.push_back(_water);
for (uint i = 0; i < kMaxShotCount; i++)
_anims.push_back(_shot[i]);
_anims.push_back(_pearl.pearl);
for (uint i = 0; i < kDecorFishCount; i++)
_anims.push_back(_decorFish[i].decorFish);
for (uint i = 0; i < kEvilFishCount; i++)
_anims.push_back(_evilFish[i].evilFish);
for (int i = kPlantCount - 1; i >= 0; i--)
_anims.push_back(_plant[i].plant);
_anims.push_back(_oko);
_anims.push_back(_lungs);
_anims.push_back(_heart);
// Air and health meter
_airMeter->setMaxValue();
_healthMeter->setMaxValue();
_airCycle = 0;
_hurtGracePeriod = 0;
_whitePearlCount = 0;
_blackPearlCount = 0;
}
void Diving::deinit() {
_vm->_draw->_cursorHotspotX = -1;
_vm->_draw->_cursorHotspotY = -1;
_soundShoot.free();
_soundBreathe.free();
_soundWhitePearl.free();
_soundBlackPearl.free();
_anims.clear();
_activeShots.clear();
for (uint i = 0; i < kMaxShotCount; i++) {
delete _shot[i];
_shot[i] = 0;
}
for (uint i = 0; i < kEvilFishCount; i++) {
delete _evilFish[i].evilFish;
_evilFish[i].evilFish = 0;
}
for (uint i = 0; i < kDecorFishCount; i++) {
delete _decorFish[i].decorFish;
_decorFish[i].decorFish = 0;
}
for (uint i = 0; i < kPlantCount; i++) {
delete _plant[i].plant;
_plant[i].plant = 0;
}
delete _pearl.pearl;
_pearl.pearl = 0;
delete _oko;
_oko = 0;
delete _heart;
delete _lungs;
delete _water;
delete _okoAnim;
delete _gui;
delete _objects;
delete _background;
_water = 0;
_heart = 0;
_lungs = 0;
_okoAnim = 0;
_gui = 0;
_objects = 0;
_background = 0;
}
void Diving::initScreen() {
// Set framerate
_vm->_util->setFrameRate(15);
// Set palette
memcpy(_vm->_draw->_vgaPalette, kPalette, sizeof(kPalette));
// Draw background decal
_vm->_draw->_backSurface->clear();
_background->draw(*_vm->_draw->_backSurface);
// Draw heart and lung boxes
int16 left, top, right, bottom;
_lungs->draw(*_vm->_draw->_backSurface, left, top, right, bottom);
_heart->draw(*_vm->_draw->_backSurface, left, top, right, bottom);
// Mark everything as dirty
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 0, 0, 319, 199);
}
void Diving::initCursor() {
const int index = _vm->_draw->_cursorIndex;
const int16 left = index * _vm->_draw->_cursorWidth;
const int16 top = 0;
const int16 right = left + _vm->_draw->_cursorWidth - 1;
const int16 bottom = _vm->_draw->_cursorHeight - 1;
_vm->_draw->_cursorSprites->fillRect(left, top, right, bottom, 0);
_objects->draw(*_vm->_draw->_cursorSprites, 31, 0, left, top);
_vm->_draw->_cursorAnimLow[index] = 0;
_vm->_draw->_cursorHotspotX = 8;
_vm->_draw->_cursorHotspotY = 8;
}
void Diving::initPlants() {
// Create initial plantlife
for (uint i = 0; i < kPlantLevelCount; i++) {
for (uint j = 0; j < kPlantPerLevelCount; j++) {
int16 prevPlantX = -100;
if (j > 0)
prevPlantX = _plant[i * kPlantPerLevelCount + j - 1].x;
enterPlant(_plant[i * kPlantPerLevelCount + j], prevPlantX);
}
}
}
void Diving::enterPlant(ManagedPlant &plant, int16 prevPlantX) {
// Create a new plant outside the borders of the screen to scroll in
const PlantLevel &level = kPlantLevels[plant.level];
const uint anim = level.plants[_vm->_util->getRandom(kPlantLevels[plant.level].plantCount)];
plant.plant->setAnimation(anim);
plant.plant->rewind();
int16 width, height;
plant.plant->getFrameSize(width, height);
// The new plant is created 140 - 160 pixels to the right of the right-most plant
plant.x = prevPlantX + 150 - 10 + _vm->_util->getRandom(21);
plant.y = kPlantLevels[plant.level].y - height;
plant.plant->setPosition(plant.x, plant.y);
plant.plant->setVisible(true);
plant.plant->setPause(false);
// If the plant is outside of the screen, create a pearl too if necessary
if (plant.x > 320)
enterPearl(plant.x);
}
void Diving::enterPearl(int16 x) {
// Create a pearl outside the borders of the screen to scroll in
// Only one pearl is ever visible
if (_pearl.pearl->isVisible())
return;
// Only every 4th potential pearl position has a pearl
if (_vm->_util->getRandom(4) != 0)
return;
// Every 5th pearl is a black one, but only if the location is correct
_pearl.black = _hasPearlLocation && (_vm->_util->getRandom(5) == 0);
// Set the pearl about in the middle of two bottom-level plants
_pearl.pearl->setPosition(x + 80, 130);
_pearl.pearl->setVisible(true);
_pearl.pearl->setPause(false);
_pearl.picked = false;
}
void Diving::updateAirMeter() {
if (_oko->isBreathing()) {
// If Oko is breathing, increase the air meter and play the lungs animation
_airCycle = 0;
_airMeter->increase();
_lungs->setPause(false);
return;
} else
// Otherwise, don't play the lungs animation
_lungs->setPause(true);
// Update the air cycle and decrease the air meter when the cycle ended
_airCycle = (_airCycle + 1) % kAirDecreaseRate;
if (_airCycle == 0)
_airMeter->decrease();
// Without any air, Oko dies
if (_airMeter->getValue() == 0)
_oko->die();
}
void Diving::updateEvilFish() {
for (uint i = 0; i < kEvilFishCount; i++) {
ManagedEvilFish &fish = _evilFish[i];
if (fish.evilFish->isVisible()) {
// Evil fishes leave on their own after 30s - 40s
fish.enterAt = 0;
if (fish.leaveAt == 0)
fish.leaveAt = _vm->_util->getTimeKey() + 30000 + _vm->_util->getRandom(10000);
if (_vm->_util->getTimeKey() >= fish.leaveAt)
fish.evilFish->leave();
} else {
// Evil fishes enter the screen in 2s - 10s
fish.leaveAt = 0;
if (fish.enterAt == 0)
fish.enterAt = _vm->_util->getTimeKey() + 2000 + _vm->_util->getRandom(8000);
if (_vm->_util->getTimeKey() >= fish.enterAt) {
// The new fish has a random type
int fishType = _vm->_util->getRandom(kEvilFishTypeCount);
fish.evilFish->mutate(kEvilFishTypes[fishType][0], kEvilFishTypes[fishType][1],
kEvilFishTypes[fishType][2], kEvilFishTypes[fishType][3],
kEvilFishTypes[fishType][4]);
fish.evilFish->enter((EvilFish::Direction)_vm->_util->getRandom(2),
36 + _vm->_util->getRandom(3) * 40);
}
}
}
}
void Diving::updateDecorFish() {
for (uint i = 0; i < kDecorFishCount; i++) {
ManagedDecorFish &fish = _decorFish[i];
if (fish.decorFish->isVisible()) {
// Move the fish
int16 x, y;
fish.decorFish->getPosition(x, y);
fish.decorFish->setPosition(x + fish.deltaX, y);
// Check if the fish has left the screen
int16 width, height;
fish.decorFish->getFramePosition(x, y);
fish.decorFish->getFrameSize(width, height);
if ((x + width) <= 0) {
fish.decorFish->setVisible(false);
fish.decorFish->setPause(true);
fish.enterAt = 0;
}
} else {
// Decor fishes enter the screen every 0s - 10s
if (fish.enterAt == 0)
fish.enterAt = _vm->_util->getTimeKey() + _vm->_util->getRandom(10000);
if (_vm->_util->getTimeKey() >= fish.enterAt) {
fish.decorFish->rewind();
fish.decorFish->setPosition(320, 30 + _vm->_util->getRandom(100));
fish.decorFish->setVisible(true);
fish.decorFish->setPause(false);
}
}
}
}
void Diving::updatePlants() {
// When Oko isn't moving, the plants don't continue to scroll by
if (!_oko->isMoving())
return;
for (uint i = 0; i < kPlantCount; i++) {
ManagedPlant &plant = _plant[i];
if (plant.plant->isVisible()) {
// Move the plant
plant.plant->setPosition(plant.x += plant.deltaX, plant.y);
// Check if the plant has left the screen
int16 x, y, width, height;
plant.plant->getFramePosition(x, y);
plant.plant->getFrameSize(width, height);
if ((x + width) <= 0) {
plant.plant->setVisible(false);
plant.plant->setPause(true);
plant.x = 0;
}
} else {
// Find the right-most plant in this level and enter the plant to the right of it
int16 rightX = 320;
for (uint j = 0; j < kPlantPerLevelCount; j++)
rightX = MAX(rightX, _plant[plant.level * kPlantPerLevelCount + j].x);
enterPlant(plant, rightX);
}
}
}
void Diving::updatePearl() {
if (!_pearl.pearl->isVisible())
return;
// When Oko isn't moving, the pearl doesn't continue to scroll by
if (!_oko->isMoving())
return;
// Picking the pearl
if (_pearl.picked && (_oko->getState() == Oko::kStatePick) && (_oko->getFrame() == 8)) {
// Remove the pearl
_pearl.pearl->setVisible(false);
_pearl.pearl->setPause(true);
// Add the pearl to our found pearls repository
if (_pearl.black)
foundBlackPearl();
else
foundWhitePearl();
return;
}
// Move the pearl
int16 x, y, width, height;
_pearl.pearl->getPosition(x, y);
_pearl.pearl->setPosition(x - 5, y);
// Check if the pearl has left the screen
_pearl.pearl->getFramePosition(x, y);
_pearl.pearl->getFrameSize(width, height);
if ((x + width) <= 0) {
_pearl.pearl->setVisible(false);
_pearl.pearl->setPause(true);
}
}
void Diving::getPearl() {
if (!_pearl.pearl->isVisible())
return;
// Make sure the pearl is within Oko's grasp
int16 x, y, width, height;
_pearl.pearl->getFramePosition(x, y);
_pearl.pearl->getFrameSize(width, height);
if ((x > 190) || ((x + width) < 140))
return;
_pearl.picked = true;
}
void Diving::foundBlackPearl() {
_blackPearlCount++;
// Put the black pearl drawing into the black pearl box
if (_blackPearlCount == 1) {
_vm->_draw->_backSurface->blit(*_blackPearl, 0, 0, 10, 7, 147, 179, 0);
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 179, 157, 186);
} else if (_blackPearlCount == 2) {
_vm->_draw->_backSurface->blit(*_blackPearl, 0, 0, 10, 7, 160, 179, 0);
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, 147, 179, 160, 186);
}
_vm->_sound->blasterPlay(&_soundBlackPearl, 1, 0);
}
void Diving::foundWhitePearl() {
_whitePearlCount++;
// Put the white pearl drawing into the white pearl box
int16 x = 54 + (_whitePearlCount - 1) * 8;
if (_whitePearlCount > 10)
x += 48;
_background->drawLayer(*_vm->_draw->_backSurface, 0, 2, x, 177, 0);
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, x, 177, x + 3, 180);
_vm->_sound->blasterPlay(&_soundWhitePearl, 1, 0);
}
void Diving::updateAnims() {
int16 left, top, right, bottom;
// Clear the previous animation frames
for (Common::List<ANIObject *>::iterator a = _anims.reverse_begin();
a != _anims.end(); --a) {
if ((*a)->clear(*_vm->_draw->_backSurface, left, top, right, bottom))
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
}
// Draw the current animation frames
for (Common::List<ANIObject *>::iterator a = _anims.begin();
a != _anims.end(); ++a) {
if ((*a)->draw(*_vm->_draw->_backSurface, left, top, right, bottom))
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
(*a)->advance();
}
// Draw the meters
_airMeter->draw(*_vm->_draw->_backSurface, left, top, right, bottom);
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
_healthMeter->draw(*_vm->_draw->_backSurface, left, top, right, bottom);
_vm->_draw->dirtiedRect(_vm->_draw->_backSurface, left, top, right, bottom);
}
int16 Diving::checkInput(int16 &mouseX, int16 &mouseY, MouseButtons &mouseButtons) {
_vm->_util->getMouseState(&mouseX, &mouseY, &mouseButtons);
return _vm->_util->checkKey();
}
void Diving::shoot(int16 mouseX, int16 mouseY) {
// Outside the playable area?
if (mouseY > 157)
return;
// Too many shots still active?
if (_activeShots.size() >= kMaxShotCount)
return;
ANIObject &shot = *_shot[_currentShot];
shot.rewind();
shot.setVisible(true);
shot.setPause(false);
shot.setPosition(mouseX - 8, mouseY - 8);
_activeShots.push_back(_currentShot);
_currentShot = (_currentShot + 1) % kMaxShotCount;
_vm->_sound->blasterPlay(&_soundShoot, 1, 0);
}
void Diving::checkShots() {
Common::List<int>::iterator activeShot = _activeShots.begin();
// Check if we hit something with our shots
while (activeShot != _activeShots.end()) {
ANIObject &shot = *_shot[*activeShot];
if (shot.lastFrame()) {
int16 x, y;
shot.getPosition(x, y);
// When we hit an evil fish, it dies
for (uint i = 0; i < kEvilFishCount; i++) {
EvilFish &evilFish = *_evilFish[i].evilFish;
if (evilFish.isIn(x + 8, y + 8)) {
evilFish.die();
break;
}
}
activeShot = _activeShots.erase(activeShot);
} else
++activeShot;
}
}
void Diving::handleOko(int16 key) {
if (key == kKeyDown) {
// Oko sinks down a level or picks up a pearl if already at the bottom
_oko->sink();
if ((_oko->getState() == Oko::kStatePick) && (_oko->getFrame() == 0))
getPearl();
} else if (key == kKeyUp)
// Oko raises up a level or surfaces to breathe if already at the top
_oko->raise();
}
void Diving::checkOkoHurt() {
if (_oko->getState() != Oko::kStateSwim)
return;
// Give Oko a grace period after being hurt
if (_hurtGracePeriod > 0) {
_hurtGracePeriod--;
return;
}
// Check for a fish/Oko-collision
for (uint i = 0; i < kEvilFishCount; i++) {
EvilFish &evilFish = *_evilFish[i].evilFish;
if (!evilFish.isDead() && evilFish.isIn(*_oko)) {
_healthMeter->decrease();
// If the health reached 0, Oko dies. Otherwise, she gets hurt
if (_healthMeter->getValue() == 0)
_oko->die();
else
_oko->hurt();
_hurtGracePeriod = 10;
break;
}
}
}
} // End of namespace Geisha
} // End of namespace Gob