scummvm/engines/hypno/arcade.cpp

791 lines
24 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) {
debugC(1, kHypnoDebugParser, "Splitting %s", filename.c_str());
Common::File file;
if (!file.open(filename.c_str()))
error("Failed to open %s", filename.c_str());
while (!file.eos()) {
byte x = file.readByte();
byte p = arc.lastChar();
arc += x;
if (x == 'X' && p == '\n') {
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->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;
si.timestamp = 0;
si.name = "";
SegmentShootsSequence seq;
// Patch to fix an issue in the parsing of the c3 level in Spiderman
if (filename == "c3.mi_" || filename == "c3h.mi_")
Common::replace(pdata, "92.B", "92,B");
// 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", "");
Common::replace(n, "\nZ", "");
uint32 timestamp = atoi(t.c_str());
if (timestamp < si.timestamp) {
debugC(1, kHypnoDebugParser, "WARNING: stopping the sequence earlier than expected");
break;
}
si.name = n;
si.timestamp = timestamp;
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::drawAmmo() {}
void HypnoEngine::drawShoot(const Common::Point &target) { error("Function \"%s\" not implemented", __FUNCTION__); }
void HypnoEngine::hitPlayer() { error("Function \"%s\" not implemented", __FUNCTION__); }
void HypnoEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {}
void HypnoEngine::missNoTarget(ArcadeShooting *arc) {}
void HypnoEngine::runBeforeArcade(ArcadeShooting *arc) {}
void HypnoEngine::runAfterArcade(ArcadeShooting *arc) {}
void HypnoEngine::pressedKey(const int keycode) {}
void HypnoEngine::initSegment(ArcadeShooting *arc) { error("Function \"%s\" not implemented", __FUNCTION__); }
void HypnoEngine::findNextSegment(ArcadeShooting *arc) { error("Function \"%s\" not implemented", __FUNCTION__); }
byte *HypnoEngine::getTargetColor(Common::String name, int levelId) { error("Function \"%s\" not implemented", __FUNCTION__); }
bool HypnoEngine::availableObjectives() {
return (_objKillsRequired[_objIdx] > 0);
}
bool HypnoEngine::checkArcadeObjectives() {
debugC(1, kHypnoDebugArcade, "Checking objective %d (%d/%d)", _objIdx, _objKillsCount[_objIdx], _objKillsRequired[_objIdx]);
if (_objKillsRequired[_objIdx] > 0)
return (_objKillsCount[_objIdx] >= _objKillsRequired[_objIdx] && \
_objMissesCount[_objIdx] <= _objMissesAllowed[_objIdx]);
return true;
}
bool HypnoEngine::checkTransition(ArcadeTransitions &transitions, ArcadeShooting *arc) {
error("Function \"%s\" not implemented", __FUNCTION__);
}
void HypnoEngine::runArcade(ArcadeShooting *arc) {
_arcadeMode = arc->mode;
Common::Point mousePos;
Common::List<uint32> shootsToRemove;
// segment/shoots
Segments segments = arc->segments;
initSegment(arc);
// Transitions
_transitions = arc->transitions;
_levelId = arc->id;
_shootSound = arc->shootSound;
_hitSound = arc->hitSound;
_additionalSound = arc->additionalSound;
debugC(1, kHypnoDebugArcade, "Starting segment of type %x of size %d", segments[_segmentIdx].type, segments[_segmentIdx].size);
_shoots.clear();
_skipLevel = false;
_loseLevel = false;
_skipDefeatVideo = false;
_skipNextVideo = false;
_mask = nullptr;
_masks = nullptr;
if (arc->mouseBox == Common::Rect(0, 0, 0, 0))
error("Invalid or missing mouse box");
Common::Point offset;
_background = new MVideo(arc->backgroundVideo, offset, false, false, false);
drawCursorArcade(mousePos);
playVideo(*_background);
if (!arc->maskVideo.empty()) {
_masks = new MVideo(arc->maskVideo, offset, false, false, false);
playVideo(*_masks);
_mask = _masks->decoder->decodeNextFrame();
}
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);
}
_currentPalette = arc->backgroundPalette;
loadPalette(_currentPalette);
int firstFrame = segments[_segmentIdx].start;
if (firstFrame > 1) {
_background->decoder->forceSeekToFrame(firstFrame);
_masks->decoder->forceSeekToFrame(firstFrame);
segments[_segmentIdx].start = 1;
}
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()) {
if (_timerStarted) {
if (_countdown <= 0) {
_loseLevel = true;
debugC(1, kHypnoDebugArcade, "Finishing level (timeout)");
_timerStarted = false;
removeTimers();
}
}
needsUpdate = _background->decoder->needsUpdate();
while (g_system->getEventManager()->pollEvent(event)) {
mousePos = getPlayerPosition(false);
// Events
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
break;
case Common::EVENT_KEYDOWN:
pressedKey(event.kbd.keycode);
if (event.kbd.keycode == Common::KEYCODE_LCTRL)
if (clickedPrimaryShoot(mousePos))
shootingPrimary = true;
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 >= arc->mouseBox.right-1) {
g_system->warpMouse(arc->mouseBox.right-1, mousePos.y);
} else if (mousePos.y >= arc->mouseBox.bottom-1) {
g_system->warpMouse(mousePos.x, arc->mouseBox.bottom-1);
} else if (mousePos.x <= 40 && 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 >= 280 && 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) {
getPlayerPosition(true);
if (_background->decoder->getCurFrame() > firstFrame)
drawScreen();
updateScreen(*_background);
if (!arc->maskVideo.empty() && _masks->decoder->needsUpdate())
_mask = _masks->decoder->decodeNextFrame();
if (_additionalVideo && _additionalVideo->decoder->needsUpdate())
_additionalVideo->decoder->decodeNextFrame(); // only audio?
}
if (_health <= 0) {
skipVideo(*_background);
if (_skipDefeatVideo)
; // No video
else if (!arc->defeatNoEnergySecondVideo.empty() && transition) {
disableCursor();
MVideo video(arc->defeatNoEnergySecondVideo, Common::Point(0, 0), false, true, false);
runIntro(video);
} else if (!arc->defeatNoEnergyFirstVideo.empty()) {
disableCursor();
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 (!_transitions.empty()) {
transition = checkTransition(_transitions, arc);
}
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 || _loseLevel) {
skipVideo(*_background);
// Objectives
if (!checkArcadeObjectives() && !_skipLevel) {
if (!arc->defeatMissBossVideo.empty()) {
MVideo video(arc->defeatMissBossVideo, Common::Point(0, 0), false, true, false);
disableCursor();
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() && !_skipNextVideo) {
MVideo video(arc->nextLevelVideo, Common::Point(0, 0), false, true, false);
disableCursor();
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;
s.startFrame = si.timestamp;
if (_masks) {
s.startFrame = 0;
_shoots.push_back(s);
} else if (it->animation == "NONE") {
byte *c = getTargetColor(it->name, _levelId);
assert(s.paletteSize == 1 || s.paletteSize == 0);
loadPalette(c, 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, s.enemySoundRate);
else if (!arc->enemySound.empty())
playSound(_soundPath + arc->enemySound, 1, arc->enemySoundRate);
}
}
}
}
}
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) {
if (!_infiniteHealthCheat)
_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) {
incTargetsMissed();
missedTarget(it, arc);
// No need to pop attackFrames or explosionFrames
skipVideo(*it->video);
shootsToRemove.push_back(i);
} 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);
}
} else if (!it->video && it->bodyFrames.size() > 0) {
uint32 frame = _background->decoder->getCurFrame();
uint32 bodyLastFrame = it->bodyFrames[it->bodyFrames.size() - 1].lastFrame();
if (frame > it->startFrame && frame - it->startFrame >= bodyLastFrame)
if (!it->destroyed) {
incTargetsMissed();
missedTarget(it, arc);
shootsToRemove.push_back(i);
}
}
i++;
}
if (shootsToRemove.size() > 0) {
debugC(1, kHypnoDebugArcade, "Shoots to remove: %d", shootsToRemove.size());
Common::sort(shootsToRemove.begin(), shootsToRemove.end());
for (Common::List<uint32>::iterator it = shootsToRemove.reverse_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;
_musicRate = arc->musicRate;
_musicStereo = arc->musicStereo;
playSound(_music, 0, _musicRate, _musicStereo); // music loop forever
}
if (needsUpdate) {
if (shootingPrimary) {
shootingPrimary = shoot(mousePos, arc, false);
} else if (shootingSecondary) {
shootingSecondary = shoot(mousePos, arc, true);
}
drawPlayer();
drawHealth();
drawAmmo();
}
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);
}
delete _background;
_background = nullptr;
if (_masks) {
skipVideo(*_masks);
delete _masks;
_mask = nullptr;
_masks = nullptr;
}
if (_additionalVideo) {
skipVideo(*_additionalVideo);
delete _additionalVideo;
_additionalVideo = nullptr;
}
_timerStarted = false;
removeTimers();
stopSound();
_music.clear();
}
Common::Point HypnoEngine::computeTargetPosition(const Common::Point &mousePos) {
return mousePos;
}
Common::Point HypnoEngine::getPlayerPosition(bool needsUpdate) {
return g_system->getEventManager()->getMousePos();
}
int HypnoEngine::detectTarget(const Common::Point &mousePos) {
int i = -1;
Common::Point target = computeTargetPosition(mousePos);
if (target.x >= _compositeSurface->w || target.y >= _compositeSurface->h)
return -1;
if (target.x < 0 || target.y < 0)
return -1;
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(target.x, target.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; }
bool HypnoEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool secondary) {
incShotsFired();
int i = detectTarget(mousePos);
if (i < 0) {
missNoTarget(arc);
} else {
if (!_shoots[i].hitSound.empty())
playSound(_soundPath + _shoots[i].hitSound, 1);
incEnemyHits();
if (_shoots[i].timesToShoot > 1) {
_shoots[i].timesToShoot = _shoots[i].timesToShoot - 1;
// Redraw cursor
drawCursorArcade(mousePos);
goto end;
}
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) {
Common::Point position = computeTargetPosition(mousePos);
_shoots[i].video->position = Common::Point(position.x, position.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()) {
Common::Point position = computeTargetPosition(mousePos);
_shoots[i].video = new MVideo(_shoots[i].explosionAnimation, position, true, false, false);
playVideo(*_shoots[i].video);
int w = _shoots[i].video->decoder->getWidth();
int h = _shoots[i].video->decoder->getHeight();
uint32 explosionLastFrame = _shoots[i].video->decoder->getFrameCount() - 1;
_shoots[i].video->position = Common::Point(position.x - w / 2, position.y - h / 2);
_shoots[i].lastFrame = explosionLastFrame - 1;
} else if (_objIdx == 0 && !arc->hitBoss1Video.empty()) {
_background->decoder->pauseVideo(true);
MVideo video(arc->hitBoss1Video, Common::Point(0, 0), false, true, false);
disableCursor();
runIntro(video);
// Should be currentPalette?
loadPalette(arc->backgroundPalette);
_background->decoder->pauseVideo(false);
updateScreen(*_background);
drawScreen();
if (!_music.empty())
playSound(_music, 0, _musicRate, _musicStereo); // restore music
} else if (_objIdx == 1 && !arc->hitBoss2Video.empty()) {
_background->decoder->pauseVideo(true);
MVideo video(arc->hitBoss2Video, Common::Point(0, 0), false, true, false);
runIntro(video);
// Should be currentPalette?
loadPalette(arc->backgroundPalette);
_background->decoder->pauseVideo(false);
updateScreen(*_background);
drawScreen();
drawCursorArcade(mousePos);
if (!_music.empty())
playSound(_music, 0, _musicRate, _musicStereo); // restore music
}
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;
}
// Redraw cursor
drawCursorArcade(mousePos);
}
end:
if (secondary) {
if (_background->decoder->getCurFrame() % 2 == 0)
drawShoot(mousePos);
return clickedSecondaryShoot(mousePos);
} else {
drawShoot(mousePos);
return false;
}
}
void HypnoEngine::incBonus(int inc) {
_bonus = _bonus + inc;
}
void HypnoEngine::incScore(int inc) {
_score = _score + inc;
}
void HypnoEngine::incLivesUsed() {
_stats.livesUsed++;
}
void HypnoEngine::incShotsFired() {
_stats.shootsFired++;
}
void HypnoEngine::incEnemyHits() {
_stats.enemyHits++;
}
void HypnoEngine::incEnemyTargets() {
_stats.enemyTargets++;
}
void HypnoEngine::incTargetsDestroyed() {
_stats.targetsDestroyed++;
}
void HypnoEngine::incTargetsMissed() {
_stats.targetsMissed++;
}
uint32 HypnoEngine::killRatio() {
if (_stats.enemyTargets == 0)
return 0;
return 100 * _stats.targetsDestroyed / _stats.enemyTargets;
}
uint32 HypnoEngine::accuracyRatio() {
if (_stats.shootsFired == 0)
return 0;
return 100 * _stats.enemyHits / _stats.shootsFired;
}
void HypnoEngine::incFriendliesEncountered() {
_stats.friendliesEncountered++;
}
void HypnoEngine::incInfoReceived() {
_stats.infoReceived++;
}
void HypnoEngine::resetStatistics() {
_stats = ArcadeStats();
_bonus = 0;
}
bool HypnoEngine::clickedSecondaryShoot(const Common::Point &mousePos) {
return false;
}
} // End of namespace Hypno