mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-04 01:46:42 +00:00
674 lines
21 KiB
C++
674 lines
21 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 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 "common/tokenizer.h"
|
|
#include "common/events.h"
|
|
#include "graphics/cursorman.h"
|
|
|
|
#include "hypno/grammar.h"
|
|
#include "hypno/hypno.h"
|
|
|
|
namespace Hypno {
|
|
|
|
extern int parse_arc(const char *);
|
|
|
|
void HypnoEngine::splitArcadeFile(const Common::String &filename, Common::String &arc, Common::String &list) {
|
|
Common::File file;
|
|
if (!file.open(filename.c_str()))
|
|
error("Failed to open %s", filename.c_str());
|
|
|
|
while (!file.eos()) {
|
|
byte x = file.readByte();
|
|
arc += x;
|
|
if (x == 'X') {
|
|
while (!file.eos()) {
|
|
x = file.readByte();
|
|
if (x == 'Y' && list.size() > 0 && list[list.size()-1] == '\n')
|
|
break;
|
|
list += x;
|
|
}
|
|
break; // No need to keep parsing
|
|
}
|
|
}
|
|
file.close();
|
|
}
|
|
|
|
void HypnoEngine::parseArcadeShooting(const Common::String &prefix, const Common::String &filename, const Common::String &data) {
|
|
debugC(1, kHypnoDebugParser, "Parsing %s/%s", prefix.c_str(), filename.c_str());
|
|
parse_arc(data.c_str());
|
|
ArcadeShooting *arcade = new ArcadeShooting();
|
|
*arcade = *g_parsedArc;
|
|
_levels[filename] = (Level*) arcade;
|
|
g_parsedArc->backgroundVideo.clear();
|
|
g_parsedArc->transitionPalette.clear();
|
|
g_parsedArc->player.clear();
|
|
g_parsedArc->shoots.clear();
|
|
g_parsedArc->intros.clear();
|
|
g_parsedArc->defeatNoEnergyFirstVideo.clear();
|
|
g_parsedArc->defeatMissBossVideo.clear();
|
|
g_parsedArc->defeatNoEnergySecondVideo.clear();
|
|
g_parsedArc->beforeVideo.clear();
|
|
g_parsedArc->briefingVideo.clear();
|
|
g_parsedArc->segments.clear();
|
|
}
|
|
|
|
SegmentShootsSequence HypnoEngine::parseShootList(const Common::String &filename, const Common::String &data) {
|
|
debugC(1, kHypnoDebugParser, "Parsing %s", filename.c_str());
|
|
debugC(1, kHypnoDebugParser, "%s", data.c_str());
|
|
// Preparsing
|
|
Common::String pdata;
|
|
Common::StringTokenizer lines(data, "\n");
|
|
Common::String t;
|
|
while (!lines.empty()) {
|
|
t = lines.nextToken();
|
|
if (t[0] == ';')
|
|
continue;
|
|
if (t.size() == 0)
|
|
continue;
|
|
pdata += "\n" + t;
|
|
}
|
|
Common::String n;
|
|
ShootInfo si;
|
|
SegmentShootsSequence seq;
|
|
// Parsing
|
|
pdata.trim();
|
|
pdata = "\n" + pdata;
|
|
|
|
if (pdata[1] == 'L') { // List of elements
|
|
SegmentShoots ss;
|
|
ss.segmentRepetition = 0;
|
|
Common::StringTokenizer tok(pdata, " ,.\n\t");
|
|
while (!tok.empty()) {
|
|
t = tok.nextToken();
|
|
while (t == "L") {
|
|
if (ss.segmentRepetition > 0)
|
|
seq.push_back(ss);
|
|
t = tok.nextToken();
|
|
ss.segmentRepetition = atoi(t.c_str());
|
|
ss.shootSequence.clear();
|
|
t = tok.nextToken();
|
|
}
|
|
|
|
n = tok.nextToken();
|
|
if (t == "Z") {
|
|
seq.push_back(ss);
|
|
break;
|
|
}
|
|
|
|
si.name = n;
|
|
si.timestamp = atoi(t.c_str());
|
|
if (si.timestamp == 0 && si.name != "0") // 0,0 is a special case
|
|
error("Error at parsing '%s' with timestamp: %s", n.c_str(), t.c_str());
|
|
ss.shootSequence.push_back(si);
|
|
debugC(1, kHypnoDebugParser, "%d -> %s", si.timestamp, si.name.c_str());
|
|
}
|
|
} else if (pdata[1] == 'S' ) { // Single element
|
|
SegmentShoots ss;
|
|
Common::StringTokenizer tok(pdata, " ,.\t\r");
|
|
while (!tok.empty()) {
|
|
t = tok.nextToken();
|
|
if (t[0] == '\n')
|
|
continue;
|
|
n = tok.nextToken();
|
|
if (t == "Z")
|
|
break;
|
|
|
|
Common::replace(n, "\nS", "");
|
|
Common::replace(n, "\nZ\n", "");
|
|
si.name = n;
|
|
si.timestamp = atoi(t.c_str());
|
|
if (si.timestamp == 0)
|
|
error("Error at parsing '%s' with timestamp: %s", n.c_str(), t.c_str());
|
|
ss.shootSequence.push_back(si);
|
|
debugC(1, kHypnoDebugParser, "%d -> %s", si.timestamp, si.name.c_str());
|
|
}
|
|
seq.push_back(ss);
|
|
} else
|
|
error("Invalid shoot sequence to parse: %c", pdata[1]);
|
|
|
|
return seq;
|
|
}
|
|
|
|
void HypnoEngine::loadArcadeLevel(const Common::String &arclevel, const Common::String &nextWin, const Common::String &nextLose, const Common::String &prefix) {
|
|
debugC(1, kHypnoDebugParser, "Parsing %s", arclevel.c_str());
|
|
Common::String arc;
|
|
Common::String list;
|
|
splitArcadeFile(arclevel, arc, list);
|
|
debugC(1, kHypnoDebugParser, "%s", arc.c_str());
|
|
parseArcadeShooting("", arclevel, arc);
|
|
ArcadeShooting *arcade = (ArcadeShooting *) _levels[arclevel];
|
|
arcade->shootSequence = parseShootList(arclevel, list);
|
|
arcade->prefix = prefix;
|
|
arcade->levelIfWin = nextWin;
|
|
arcade->levelIfLose = nextLose;
|
|
}
|
|
|
|
void HypnoEngine::drawPlayer() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
void HypnoEngine::drawHealth() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
void HypnoEngine::drawShoot(const Common::Point &target) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
void HypnoEngine::hitPlayer() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
void HypnoEngine::missTarget(Shoot *s, ArcadeShooting *arc, MVideo &background) {}
|
|
|
|
void HypnoEngine::runBeforeArcade(ArcadeShooting *arc) {}
|
|
void HypnoEngine::runAfterArcade(ArcadeShooting *arc) {}
|
|
|
|
void HypnoEngine::initSegment(ArcadeShooting *arc) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
void HypnoEngine::findNextSegment(ArcadeShooting *arc) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
|
|
|
void HypnoEngine::runArcade(ArcadeShooting *arc) {
|
|
_arcadeMode = arc->mode;
|
|
Common::Point mousePos;
|
|
Common::List<uint32> shootsToRemove;
|
|
|
|
// statistics
|
|
resetStatistics();
|
|
|
|
// segment/shoots
|
|
Segments segments = arc->segments;
|
|
initSegment(arc);
|
|
|
|
_levelId = arc->id;
|
|
_shootSound = arc->shootSound;
|
|
_hitSound = arc->hitSound;
|
|
_health = arc->health;
|
|
_maxHealth = _health;
|
|
debugC(1, kHypnoDebugArcade, "Starting segment of type %x", segments[_segmentIdx].type);
|
|
changeCursor("arcade");
|
|
_shoots.clear();
|
|
_skipLevel = false;
|
|
|
|
Common::Point offset;
|
|
MVideo background = MVideo(arc->backgroundVideo, offset, false, false, false);
|
|
|
|
changeCursor("arcade");
|
|
playVideo(background);
|
|
float rate = background.decoder->getFrameRate().toDouble();
|
|
if (rate < 10) {
|
|
debugC(1, kHypnoDebugArcade, "Used frame rate looks odd: %f, increasing x 10", rate);
|
|
background.decoder->setRate(10.0);
|
|
}
|
|
loadPalette(arc->backgroundPalette);
|
|
bool shootingPrimary = false;
|
|
bool shootingSecondary = false;
|
|
bool needsUpdate = true;
|
|
bool transition = false;
|
|
|
|
_objIdx = 0;
|
|
_objKillsCount[0] = 0;
|
|
_objKillsCount[1] = 0;
|
|
_objMissesCount[0] = 0;
|
|
_objMissesCount[1] = 0;
|
|
|
|
_objKillsRequired[0] = arc->objKillsRequired[0];
|
|
_objKillsRequired[1] = arc->objKillsRequired[1];
|
|
_objMissesAllowed[0] = arc->objMissesAllowed[0];
|
|
_objMissesAllowed[1] = arc->objMissesAllowed[1];
|
|
|
|
debugC(1, kHypnoDebugArcade, "Using frame delay: %d", arc->frameDelay);
|
|
|
|
Common::Event event;
|
|
while (!shouldQuit()) {
|
|
needsUpdate = background.decoder->needsUpdate();
|
|
while (g_system->getEventManager()->pollEvent(event)) {
|
|
mousePos = g_system->getEventManager()->getMousePos();
|
|
// Events
|
|
switch (event.type) {
|
|
|
|
case Common::EVENT_QUIT:
|
|
case Common::EVENT_RETURN_TO_LAUNCHER:
|
|
break;
|
|
|
|
case Common::EVENT_KEYDOWN:
|
|
if (event.kbd.keycode == Common::KEYCODE_c) {
|
|
background.decoder->pauseVideo(true);
|
|
showCredits();
|
|
|
|
if (transition && !arc->transitionPalette.empty())
|
|
loadPalette(arc->transitionPalette);
|
|
else
|
|
loadPalette(arc->backgroundPalette);
|
|
|
|
changeScreenMode("320x200");
|
|
background.decoder->pauseVideo(false);
|
|
updateScreen(background);
|
|
drawScreen();
|
|
} else if (event.kbd.keycode == Common::KEYCODE_k) { // Added for testing
|
|
_health = 0;
|
|
} else if (event.kbd.keycode == Common::KEYCODE_LEFT) {
|
|
_lastPlayerPosition = _currentPlayerPosition;
|
|
_currentPlayerPosition = kPlayerLeft;
|
|
} else if (event.kbd.keycode == Common::KEYCODE_DOWN) {
|
|
_lastPlayerPosition = _currentPlayerPosition;
|
|
_currentPlayerPosition = kPlayerBottom;
|
|
} else if (event.kbd.keycode == Common::KEYCODE_RIGHT) {
|
|
_lastPlayerPosition = _currentPlayerPosition;
|
|
_currentPlayerPosition = kPlayerRight;
|
|
} else if (event.kbd.keycode == Common::KEYCODE_UP) {
|
|
_lastPlayerPosition = _currentPlayerPosition;
|
|
_currentPlayerPosition = kPlayerTop;
|
|
}
|
|
break;
|
|
|
|
case Common::EVENT_LBUTTONDOWN:
|
|
if (clickedPrimaryShoot(mousePos))
|
|
shootingPrimary = true;
|
|
break;
|
|
|
|
case Common::EVENT_RBUTTONDOWN:
|
|
if (clickedSecondaryShoot(mousePos))
|
|
shootingSecondary = true;
|
|
break;
|
|
|
|
case Common::EVENT_RBUTTONUP:
|
|
shootingSecondary = false;
|
|
break;
|
|
|
|
case Common::EVENT_MOUSEMOVE:
|
|
drawCursorArcade(mousePos);
|
|
if (mousePos.x <= 100 && offset.x < 0) {
|
|
for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
|
|
if (it->video && it->video->decoder)
|
|
it->video->position.x = it->video->position.x + 1;
|
|
}
|
|
offset.x = offset.x + 1;
|
|
needsUpdate = true;
|
|
} else if (mousePos.x >= 300 && offset.x > 320 - background.decoder->getWidth()) {
|
|
for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
|
|
if (it->video && it->video->decoder)
|
|
it->video->position.x = it->video->position.x - 1;
|
|
}
|
|
offset.x = offset.x - 1;
|
|
needsUpdate = true;
|
|
}
|
|
background.position = offset;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (needsUpdate) {
|
|
drawScreen();
|
|
updateScreen(background);
|
|
}
|
|
|
|
if (_health <= 0) {
|
|
skipVideo(background);
|
|
if (!arc->defeatNoEnergySecondVideo.empty() && transition) {
|
|
MVideo video(arc->defeatNoEnergySecondVideo, Common::Point(0, 0), false, true, false);
|
|
runIntro(video);
|
|
} else if (!arc->defeatNoEnergyFirstVideo.empty()) {
|
|
MVideo video(arc->defeatNoEnergyFirstVideo, Common::Point(0, 0), false, true, false);
|
|
runIntro(video);
|
|
}
|
|
assert(!arc->levelIfLose.empty());
|
|
_nextLevel = arc->levelIfLose;
|
|
debugC(1, kHypnoDebugArcade, "Losing level and jumping to %s", _nextLevel.c_str());
|
|
_lives = _lives - 1;
|
|
break;
|
|
}
|
|
|
|
if (!arc->transitionVideo.empty() && !transition && background.decoder->getCurFrame() >= (int)arc->transitionTime) {
|
|
transition = true;
|
|
background.decoder->pauseVideo(true);
|
|
|
|
debugC(1, kHypnoDebugArcade, "Playing transition %s", arc->transitionVideo.c_str());
|
|
MVideo video(arc->transitionVideo, Common::Point(0, 0), false, true, false);
|
|
runIntro(video);
|
|
|
|
if (!arc->transitionPalette.empty())
|
|
loadPalette(arc->transitionPalette);
|
|
else
|
|
loadPalette(arc->backgroundPalette);
|
|
background.decoder->pauseVideo(false);
|
|
updateScreen(background);
|
|
drawScreen();
|
|
}
|
|
|
|
if (background.decoder && background.decoder->getCurFrame() >= int(segments[_segmentIdx].start + segments[_segmentIdx].size - 2)) {
|
|
debugC(1, kHypnoDebugArcade, "Finished segment %d of type %x", _segmentIdx, segments[_segmentIdx].type);
|
|
|
|
// Clear shoots
|
|
/*for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
|
|
if (it->video && it->video->decoder)
|
|
skipVideo(*it->video);
|
|
delete it->video;
|
|
}
|
|
_shoots.clear();*/
|
|
findNextSegment(arc);
|
|
|
|
if (_segmentIdx >= segments.size())
|
|
error("Invalid segment %d", _segmentIdx);
|
|
|
|
debugC(1, kHypnoDebugArcade, "Starting segment %d of type %x at %d", _segmentIdx, segments[_segmentIdx].type, segments[_segmentIdx].start);
|
|
if (!segments[_segmentIdx].end) { // If it is not the end segment
|
|
background.decoder->forceSeekToFrame(segments[_segmentIdx].start);
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (segments[_segmentIdx].end || _skipLevel) {
|
|
skipVideo(background);
|
|
// Objectives
|
|
if ((_objKillsRequired[_objIdx] > 0 || _objMissesAllowed[_objIdx] > 0) && !_skipLevel) {
|
|
if (_objKillsCount[_objIdx] < _objKillsRequired[_objIdx] || _objMissesCount[_objIdx] > _objMissesAllowed[_objIdx]) {
|
|
if (!arc->defeatMissBossVideo.empty()) {
|
|
MVideo video(arc->defeatMissBossVideo, Common::Point(0, 0), false, true, false);
|
|
runIntro(video);
|
|
}
|
|
assert(!arc->levelIfLose.empty());
|
|
_nextLevel = arc->levelIfLose;
|
|
_lives = _lives - 1;
|
|
_arcadeMode = "";
|
|
debugC(1, kHypnoDebugArcade, "Losing level (objectives) and jumping to %s", _nextLevel.c_str());
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!arc->nextLevelVideo.empty()) {
|
|
MVideo video(arc->nextLevelVideo, Common::Point(0, 0), false, true, false);
|
|
runIntro(video);
|
|
}
|
|
assert(!arc->levelIfWin.empty());
|
|
_nextLevel = arc->levelIfWin;
|
|
_checkpoint = _nextLevel;
|
|
_arcadeMode = "";
|
|
_skipLevel = false;
|
|
debugC(1, kHypnoDebugArcade, "Wining level and jumping to %s", _nextLevel.c_str());
|
|
break;
|
|
}
|
|
|
|
if (_shootSequence.size() > 0) {
|
|
ShootInfo si = _shootSequence.front();
|
|
int idx = (int)segments[_segmentIdx].size * _segmentRepetition \
|
|
+ background.decoder->getCurFrame() \
|
|
- (int)segments[_segmentIdx].start + 3;
|
|
//debug("%d %d", si.timestamp, idx);
|
|
if ((int)si.timestamp <= idx) {
|
|
_shootSequence.pop_front();
|
|
incEnemyTargets();
|
|
for (Shoots::iterator it = arc->shoots.begin(); it != arc->shoots.end(); ++it) {
|
|
if (it->name == si.name) {
|
|
Shoot s = *it;
|
|
if (it->animation == "NONE") {
|
|
if ((uint32)(it->name[0]) == _currentPlayerPosition) {
|
|
_health = _health - it->attackWeight;
|
|
hitPlayer();
|
|
}
|
|
byte p[3] = {0xff, 0x00, 0x00}; // Always red?
|
|
assert(s.paletteSize == 1 || s.paletteSize == 0);
|
|
loadPalette((byte *) &p, s.paletteOffset, s.paletteSize);
|
|
_shoots.push_back(s);
|
|
} else {
|
|
s.video = new MVideo(it->animation, offset + it->position, true, false, false);
|
|
playVideo(*s.video);
|
|
s.video->decoder->decodeNextFrame(); // Make sure the palette is loaded
|
|
if (s.attackFrames.size() == 0) {
|
|
uint32 lastFrame = s.bodyFrames.back().lastFrame();
|
|
s.attackFrames.push_back(lastFrame - 3);
|
|
}
|
|
s.lastFrame = s.bodyFrames[s.bodyFrames.size() - 1].lastFrame();
|
|
loadPalette(s.video->decoder->getPalette() + 3*s.paletteOffset, s.paletteOffset, s.paletteSize);
|
|
_shoots.push_back(s);
|
|
|
|
if (!s.noEnemySound) {
|
|
if (!s.enemySound.empty())
|
|
playSound(_soundPath + s.enemySound, 1);
|
|
else if (!arc->enemySound.empty())
|
|
playSound(_soundPath + arc->enemySound, 1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
uint32 i = 0;
|
|
shootsToRemove.clear();
|
|
|
|
for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
|
|
if (it->video && it->video->decoder) {
|
|
int frame = it->video->decoder->getCurFrame();
|
|
if (it->attackFrames.size() > 0) {
|
|
uint32 attackFrame = it->attackFrames.front();
|
|
if (frame > 0 && frame >= (int)(attackFrame - 2) && !it->destroyed) {
|
|
_health = _health - it->attackWeight;
|
|
hitPlayer();
|
|
it->attackFrames.pop_front();
|
|
}
|
|
}
|
|
|
|
uint32 bodyLastFrame = it->bodyFrames[it->bodyFrames.size() - 1].lastFrame();
|
|
if (frame > 0 && frame >= (int)(bodyLastFrame - 3) && !it->destroyed) {
|
|
missTarget(it, arc, background);
|
|
incTargetsMissed();
|
|
// No need to pop attackFrames or explosionFrames
|
|
skipVideo(*it->video);
|
|
} else if (frame > 0 && frame >= (int)(it->lastFrame)) {
|
|
skipVideo(*it->video);
|
|
shootsToRemove.push_back(i);
|
|
} else if (it->video->decoder->needsUpdate() && needsUpdate) {
|
|
updateScreen(*it->video);
|
|
}
|
|
}
|
|
i++;
|
|
}
|
|
if (shootsToRemove.size() > 0) {
|
|
for (Common::List<uint32>::iterator it = shootsToRemove.begin(); it != shootsToRemove.end(); ++it) {
|
|
debugC(1, kHypnoDebugArcade, "Removing %d from %d size", *it, _shoots.size());
|
|
delete _shoots[*it].video;
|
|
_shoots.remove_at(*it);
|
|
}
|
|
}
|
|
|
|
if (_music.empty() && !arc->music.empty()) {
|
|
_music = _soundPath + arc->music;
|
|
playSound(_music, 0, arc->musicRate); // music loop forever
|
|
}
|
|
|
|
if (needsUpdate) {
|
|
if (shootingPrimary || shootingSecondary) {
|
|
shoot(mousePos, arc, background);
|
|
drawShoot(mousePos);
|
|
shootingPrimary = false;
|
|
}
|
|
|
|
drawPlayer();
|
|
drawHealth();
|
|
}
|
|
|
|
g_system->delayMillis(arc->frameDelay);
|
|
}
|
|
|
|
// Deallocate shoots
|
|
for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
|
|
if (it->video && it->video->decoder)
|
|
skipVideo(*it->video);
|
|
delete it->video;
|
|
}
|
|
|
|
if (background.decoder)
|
|
skipVideo(background);
|
|
|
|
stopSound();
|
|
_music.clear();
|
|
}
|
|
|
|
int HypnoEngine::detectTarget(const Common::Point &mousePos) {
|
|
int i = -1;
|
|
int x = mousePos.x;
|
|
int y = mousePos.y;
|
|
for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
|
|
i++;
|
|
if (it->destroyed)
|
|
continue;
|
|
|
|
if (it->animation != "NONE" && !it->video->decoder)
|
|
continue;
|
|
|
|
uint32 c = _compositeSurface->getPixel(x, y);
|
|
if (c >= it->paletteOffset && c < it->paletteOffset + it->paletteSize) {
|
|
return i;
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
void HypnoEngine::drawCursorArcade(const Common::Point &mousePos) {
|
|
int i = detectTarget(mousePos);
|
|
if (i >= 0)
|
|
changeCursor("target");
|
|
else
|
|
changeCursor("arcade");
|
|
|
|
g_system->copyRectToScreen(_compositeSurface->getPixels(), _compositeSurface->pitch, 0, 0, _screenW, _screenH);
|
|
}
|
|
|
|
bool HypnoEngine::clickedPrimaryShoot(const Common::Point &mousePos) { return true; }
|
|
|
|
void HypnoEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, MVideo &background) {
|
|
incShotsFired();
|
|
int i = detectTarget(mousePos);
|
|
if (i >= 0) {
|
|
if (!_shoots[i].hitSound.empty())
|
|
playSound(_soundPath + _shoots[i].hitSound, 1);
|
|
|
|
incEnemyHits();
|
|
if (_shoots[i].timesToShoot > 1) {
|
|
_shoots[i].timesToShoot = _shoots[i].timesToShoot - 1;
|
|
return;
|
|
}
|
|
|
|
if (!_shoots[i].deathSound.empty())
|
|
playSound(_soundPath + _shoots[i].deathSound, 1);
|
|
|
|
incTargetsDestroyed();
|
|
incScore(_shoots[i].pointsToShoot);
|
|
incBonus(_shoots[i].pointsToShoot);
|
|
_shoots[i].destroyed = true;
|
|
|
|
if (_shoots[i].animation != "NONE") {
|
|
if (_shoots[i].deathPosition.x != 0 && _shoots[i].deathPosition.y != 0)
|
|
_shoots[i].video->position = Common::Point(mousePos.x, mousePos.y) - _shoots[i].deathPosition;
|
|
|
|
int currentFrame = _shoots[i].video->decoder->getCurFrame();
|
|
uint32 explosionIdx;
|
|
for (explosionIdx = 0; explosionIdx < _shoots[i].bodyFrames.size(); explosionIdx++) {
|
|
if (int(_shoots[i].bodyFrames[explosionIdx].lastFrame()) >= currentFrame)
|
|
break;
|
|
}
|
|
if (explosionIdx > 0)
|
|
explosionIdx = explosionIdx - 1;
|
|
|
|
uint32 explosionStartFrame = _shoots[i].explosionFrames[explosionIdx].start;
|
|
uint32 explosionLastFrame = _shoots[i].explosionFrames[explosionIdx].lastFrame();
|
|
_objKillsCount[_objIdx] = _objKillsCount[_objIdx] + _shoots[i].objKillsCount;
|
|
_shoots[i].video->decoder->forceSeekToFrame(explosionStartFrame - 2);
|
|
_shoots[i].lastFrame = explosionLastFrame - 2;
|
|
} else {
|
|
if (!_shoots[i].explosionAnimation.empty()) {
|
|
_shoots[i].video = new MVideo(_shoots[i].explosionAnimation, mousePos, true, false, false);
|
|
playVideo(*_shoots[i].video);
|
|
int w = _shoots[i].video->decoder->getWidth();
|
|
int h = _shoots[i].video->decoder->getHeight();
|
|
_shoots[i].video->position = Common::Point(mousePos.x - w / 2, mousePos.y - h / 2);
|
|
} else if (_objIdx == 0 && !arc->hitBoss1Video.empty()) {
|
|
background.decoder->pauseVideo(true);
|
|
MVideo video(arc->hitBoss1Video, Common::Point(0, 0), false, true, false);
|
|
runIntro(video);
|
|
loadPalette(arc->backgroundPalette);
|
|
background.decoder->pauseVideo(false);
|
|
updateScreen(background);
|
|
drawScreen();
|
|
} else if (_objIdx == 1 && !arc->hitBoss2Video.empty()) {
|
|
background.decoder->pauseVideo(true);
|
|
MVideo video(arc->hitBoss2Video, Common::Point(0, 0), false, true, false);
|
|
runIntro(video);
|
|
loadPalette(arc->backgroundPalette);
|
|
background.decoder->pauseVideo(false);
|
|
updateScreen(background);
|
|
drawScreen();
|
|
}
|
|
byte p[3] = {0x00, 0x00, 0x00}; // Always black?
|
|
assert(_shoots[i].paletteSize == 1 || _shoots[i].paletteSize == 0);
|
|
loadPalette((byte *) &p, _shoots[i].paletteOffset, _shoots[i].paletteSize);
|
|
_objKillsCount[_objIdx] = _objKillsCount[_objIdx] + _shoots[i].objKillsCount;
|
|
}
|
|
}
|
|
}
|
|
|
|
void HypnoEngine::incBonus(int inc) {
|
|
_bonus = _bonus + inc;
|
|
}
|
|
|
|
void HypnoEngine::incScore(int inc) {
|
|
_score = _score + inc;
|
|
}
|
|
|
|
void HypnoEngine::incShotsFired() {
|
|
_shootsFired++;
|
|
}
|
|
|
|
void HypnoEngine::incEnemyHits() {
|
|
_enemyHits++;
|
|
}
|
|
|
|
void HypnoEngine::incEnemyTargets() {
|
|
_enemyTargets++;
|
|
}
|
|
|
|
void HypnoEngine::incTargetsDestroyed() {
|
|
_targetsDestroyed++;
|
|
}
|
|
|
|
void HypnoEngine::incTargetsMissed() {
|
|
_targetsMissed++;
|
|
}
|
|
|
|
uint32 HypnoEngine::killRatio() {
|
|
if (_enemyTargets == 0)
|
|
return 0;
|
|
return 100 * _targetsDestroyed / _enemyTargets;
|
|
}
|
|
|
|
uint32 HypnoEngine::accuracyRatio() {
|
|
if (_shootsFired == 0)
|
|
return 0;
|
|
return 100 * _enemyHits / _shootsFired;
|
|
}
|
|
|
|
void HypnoEngine::resetStatistics() {
|
|
_shootsFired = 0;
|
|
_enemyHits = 0;
|
|
_enemyTargets = 0;
|
|
_targetsDestroyed = 0;
|
|
_targetsMissed = 0;
|
|
_bonus = 0;
|
|
}
|
|
|
|
bool HypnoEngine::clickedSecondaryShoot(const Common::Point &mousePos) {
|
|
return false;
|
|
}
|
|
|
|
} // End of namespace Hypno
|
|
|