scummvm/engines/hypno/wet/arcade.cpp

1180 lines
37 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 "hypno/grammar.h"
#include "hypno/hypno.h"
#include "common/events.h"
#include "gui/message.h"
#include "graphics/cursorman.h"
namespace Hypno {
void WetEngine::initSegment(ArcadeShooting *arc) {
if (_arcadeMode == "Y1") {
_segmentShootSequenceOffset = 0;
_segmentShootSequenceMax = 3;
} else if (_arcadeMode == "Y3") {
_segmentShootSequenceOffset = 0;
_segmentShootSequenceMax = 7;
} else if (_arcadeMode == "Y4") {
_c40SegmentNext.clear();
_c40SegmentNext.push_back(2); // Road fork (down)
_c40SegmentPath.push_back(3); // Go straight
_c40SegmentNext.push_back(9); // Tunnel entry
_c40SegmentPath.push_back(9); // Go straight
_c40SegmentNext.push_back(1); // Tunnel section
_c40SegmentPath.push_back(11); // Tunnel exit
_c40SegmentNext.push_back(2); // Road fork
_c40SegmentPath.push_back(5); // Turn left
_c40SegmentNext.push_back(6); // Ramp
_c40SegmentPath.push_back(8); // Take ramp
_c40SegmentNext.push_back(15); // Road fork (up)
_c40SegmentPath.push_back(18); // Take right
_c40SegmentNext.push_back(22); // Tunnel entry
_c40SegmentPath.push_back(22); // Go straight
_c40SegmentNext.push_back(14); // Tunnel section
_c40SegmentPath.push_back(24); // Tunnel exit
_c40SegmentNext.push_back(15); // Road fork (up)
_c40SegmentPath.push_back(17); // Take left
_c40SegmentNext.push_back(19); // Ramp
_c40SegmentPath.push_back(21); // Take ramp
_c40SegmentNext.push_back(2); // Road fork (down)
_c40SegmentPath.push_back(3); // Go straight
_c40SegmentNext.push_back(26);
_c40SegmentIdx = 0;
_c40lastTurn = -1;
_segmentShootSequenceOffset = 0;
_segmentShootSequenceMax = 5;
} else if (_arcadeMode == "Y5") {
_c50LeftTurns = 0;
_c50RigthTurns = 0;
_segmentShootSequenceOffset = 1;
_segmentShootSequenceMax = 9;
} else {
_segmentShootSequenceOffset = 0;
_segmentShootSequenceMax = 0;
}
uint32 randomSegmentShootSequence = _segmentShootSequenceOffset + _rnd->getRandomNumber(_segmentShootSequenceMax);
debugC(1, kHypnoDebugArcade, "Select random sequence %d", randomSegmentShootSequence);
SegmentShoots segmentShoots = arc->shootSequence[randomSegmentShootSequence];
_segments = arc->segments;
_shootSequence = segmentShoots.shootSequence;
_segmentRepetitionMax = segmentShoots.segmentRepetition; // Usually zero
_segmentRepetition = 0;
_segmentOffset = 0;
_segmentIdx = _segmentOffset;
if (_arcadeMode == "Y3") {
ShootInfo si;
si.name = "SP_CBREAKER_L";
si.timestamp = 30 * (_segmentRepetitionMax + 1) - 3;
_shootSequence.push_back(si);
}
}
void WetEngine::findNextSegment(ArcadeShooting *arc) {
debugC(1, kHypnoDebugArcade, "Repetition %d of %d", _segmentRepetition, _segmentRepetitionMax);
Common::Point mousePos = g_system->getEventManager()->getMousePos();
if (_segmentRepetition < _segmentRepetitionMax) {
_segmentRepetition = _segmentRepetition + 1;
} else {
_segmentRepetition = 0;
_segmentRepetitionMax = 0;
if (_segments[_segmentIdx].type == 0xb3) {
if (_arcadeMode == "Y1") {
if (_rnd->getRandomBit())
_segmentIdx = _segmentIdx + 1;
else
_segmentIdx = _segmentIdx + 5;
} else if (_arcadeMode == "Y4") {
_segmentIdx = _c40SegmentNext[_c40SegmentIdx];
} else if (_arcadeMode == "Y5") {
int r = _rnd->getRandomNumber(4);
if (r == 0)
_segmentIdx = 1;
else
_segmentIdx = r + 4;
if (_segments[_segmentIdx].type == 'L') {
_shootSequence = arc->shootSequence[11].shootSequence;
_segmentRepetitionMax = 0;
} else if (_segments[_segmentIdx].type == 'R') {
_shootSequence = arc->shootSequence[12].shootSequence;
_segmentRepetitionMax = 0;
} else if (_segments[_segmentIdx].type == 'A') {
_shootSequence = arc->shootSequence[15].shootSequence;
_segmentRepetitionMax = 0;
} else if (_segments[_segmentIdx].type == 'P') {
r = _rnd->getRandomNumber(1);
_shootSequence = arc->shootSequence[13 + r].shootSequence; //13-14
_segmentRepetitionMax = 0;
}
} else
_segmentIdx = _segmentIdx + 1;
} else if (_segments[_segmentIdx].type == 0xc5) {
if (_arcadeMode == "Y1") {
if (mousePos.x <= 106)
_segmentIdx = _segmentIdx + 1;
else if (mousePos.x >= 213)
_segmentIdx = _segmentIdx + 3;
else
_segmentIdx = _segmentIdx + 2;
} else if (_arcadeMode == "Y4") {
if (mousePos.x <= 106)
_segmentIdx = _segmentIdx + 2;
else if (mousePos.x >= 213)
_segmentIdx = _segmentIdx + 3;
else
_segmentIdx = _segmentIdx + 1;
} else if (_arcadeMode == "Y5") {
if (mousePos.x <= 106) {
_segmentIdx = _segmentIdx + 2;
_c50LeftTurns++;
} else if (mousePos.x >= 213) {
_segmentIdx = _segmentIdx + 3;
_c50RigthTurns++;
} else
_segmentIdx = _segmentIdx + 1;
} else
error("Invalid segment type for mode: %s at the end of segment %x", _arcadeMode.c_str(), _segments[_segmentIdx].type);
} else if (_segments[_segmentIdx].type == 0xc2) {
if (mousePos.x <= 160)
_segmentIdx = _segmentIdx + 1;
else
_segmentIdx = _segmentIdx + 2;
} else if (_segments[_segmentIdx].type == 0xcc) {
if (mousePos.x <= 160)
_segmentIdx = _segmentIdx + 1;
else {
_segmentIdx = _segmentIdx + 2;
if (_arcadeMode == "Y3") {
ShootInfo si;
si.name = "SP_WALKER_U";
si.timestamp = 25;
_shootSequence.push_back(si);
}
}
} else if (_segments[_segmentIdx].type == 'Y') {
if (mousePos.x <= 160) {
_segmentIdx = _segmentIdx + 2;
if (_arcadeMode == "Y3") {
ShootInfo si;
si.name = "SP_WALKER_D";
si.timestamp = 25;
_shootSequence.push_back(si);
}
} else
_segmentIdx = _segmentIdx + 1;
/*} else if (_segments[_segmentIdx].type == 'a') {
_segmentIdx = 1;*/
} else if (_segments[_segmentIdx].type == 's') {
_segmentIdx = _segmentIdx + 10; // _segmentIdx = 11;
} else {
// Objective checking
if (availableObjectives() && checkArcadeObjectives()) {
if (_objIdx == 0) {
_objIdx = 1;
if (_arcadeMode == "Y1") {
_segmentOffset = 8;
_segmentRepetition = 0;
_segmentShootSequenceOffset = 8;
MVideo video(arc->hitBoss1Video, Common::Point(0, 0), false, true, false);
disableCursor();
runIntro(video);
} else if (_arcadeMode == "Y3")
_skipLevel = true;
} else {
_loseLevel = true;
return;
}
}
if (_segments[_segmentIdx].type == 0xc9) {
if (_arcadeMode == "Y3") {
_segmentOffset = _segmentIdx + 1;
_segmentShootSequenceOffset = 8;
_segmentShootSequenceMax = 7;
} else if (_arcadeMode == "Y4") {
if (_segmentOffset == 0) {
_segmentOffset = 13;
_segmentShootSequenceOffset = 10; // TODO
_segmentShootSequenceMax = 5; // TODO
} else {
_segmentOffset = 0;
_segmentShootSequenceOffset = 0;
_segmentShootSequenceMax = 5;
}
} else
error("Invalid segment type for mode: %s at the end of segment %x", _arcadeMode.c_str(), _segments[_segmentIdx].type);
} else if (_segments[_segmentIdx].type == 0xbb) {
_segmentOffset = 0;
_segmentShootSequenceOffset = 0;
_segmentShootSequenceMax = 7;
} else if (_segments[_segmentIdx].type == 0x61) {
_segmentOffset = _segmentOffset + 1; // _segmentOffset = 1;
_segmentShootSequenceOffset = 6;
_segmentShootSequenceMax = 4;
} else if (_segments[_segmentIdx].type == 0x63) {
_segmentOffset = _segmentOffset - 1; // _segmentOffset = 0;
//_segmentShootSequenceOffset = 0; // TODO
//_segmentShootSequenceMax = 7; // TODO
}
// TODO: refactor the following code to avoid using a variable here
bool addBarrier = false;
if (_arcadeMode == "Y4") {
if (_c40SegmentPath[_c40SegmentIdx] == _segmentIdx) {
_c40SegmentIdx++;
} else {
if (_c40lastTurn == int(_segmentIdx))
_health = 0;
else {
addBarrier = true;
_c40lastTurn = int(_segmentIdx);
}
}
} else if (_arcadeMode == "Y5") {
if (_c50LeftTurns >= 1 && _c50RigthTurns >= 3) {
_segmentIdx = 9; // last segment
return;
}
}
_segmentIdx = _segmentOffset;
// select a new shoot sequence
uint32 randomSegmentShootSequence = _segmentShootSequenceOffset + _rnd->getRandomNumber(_segmentShootSequenceMax);
debugC(1, kHypnoDebugArcade, "Selected random sequence %d", randomSegmentShootSequence);
SegmentShoots segmentShoots = arc->shootSequence[randomSegmentShootSequence];
_shootSequence = segmentShoots.shootSequence;
_segmentRepetitionMax = segmentShoots.segmentRepetition; // Usually one
if (_arcadeMode == "Y3") {
ShootInfo si;
if (_segmentOffset == 0)
si.name = "SP_CBREAKER_L";
else
si.name = "SP_CBREAKER_U";
si.timestamp = 30 * (_segmentRepetitionMax + 1) - 3;
_shootSequence.push_back(si);
} else if (_arcadeMode == "Y4" && addBarrier) {
// Add a barrier near the end
ShootInfo si;
si.name = "SP_BLOCKADE";
si.timestamp = (30 * _segmentRepetitionMax) - 20;
_shootSequence.push_back(si);
}
}
}
}
bool WetEngine::checkTransition(ArcadeTransitions &transitions, ArcadeShooting *arc) {
ArcadeTransition at = *transitions.begin();
int ttime = at.time;
if (ttime == 0) { // This special case is only reachable in c33
assert(_objIdx == 1);
transitions.pop_front();
} else if (_background->decoder->getCurFrame() > ttime) {
if (at.video == "NONE") {
//TODO
return true;
}
if (_playerFrameSeps.size() == 1) {
_playerFrameStart = _playerFrameEnd + 1;
_playerFrameSep = *_playerFrameSeps.begin();
_playerFrameSeps.pop_front();
_playerFrameEnd = _playerFrames.size();
_playerFrameIdx = _playerFrameStart;
debugC(1, kHypnoDebugArcade, "New separator frames %d %d %d", _playerFrameStart, _playerFrameSep, _playerFrameEnd);
} else if (_playerFrameSeps.size() >= 2) {
_playerFrameStart = _playerFrameEnd + 1;
_playerFrameSep = *_playerFrameSeps.begin();
_playerFrameSeps.pop_front();
_playerFrameEnd = *_playerFrameSeps.begin();
_playerFrameSeps.pop_front();
_playerFrameIdx = _playerFrameStart;
debugC(1, kHypnoDebugArcade, "New separator frames %d %d %d", _playerFrameStart, _playerFrameSep, _playerFrameEnd);
}
if (_levelId == 33) {
if (checkArcadeObjectives()) {
_objIdx = 1;
} else {
// We do not play the transition, just skip the level
_loseLevel = true;
return true;
}
} else if (_levelId == 52) {
// Ignore the first objective, this will be checked when the targets are missed
// just go to the second one
_objIdx = 1;
} else if (_levelId == 61 && transitions.size() == 1) {
// Check the first objective during the second transition
if (checkArcadeObjectives()) {
_objIdx = 1;
} else {
// We do not play the transition, just skip the level
_loseLevel = true;
return true;
}
}
if (at.video.empty() && !at.palette.empty()) {
_background->decoder->pauseVideo(true);
_currentPalette = at.palette;
loadPalette(_currentPalette);
_background->decoder->pauseVideo(false);
drawPlayer();
updateScreen(*_background);
drawScreen();
} else if (!at.video.empty()) {
_background->decoder->pauseVideo(true);
debugC(1, kHypnoDebugArcade, "Playing transition %s", at.video.c_str());
MVideo video(at.video, Common::Point(0, 0), false, true, false);
disableCursor();
runIntro(video);
if (!at.palette.empty())
_currentPalette = at.palette;
loadPalette(_currentPalette);
_background->decoder->pauseVideo(false);
drawPlayer();
updateScreen(*_background);
drawScreen();
drawCursorArcade(g_system->getEventManager()->getMousePos());
if (!_music.empty())
playSound(_music, 0, _musicRate); // restore music
} else
error ("Invalid transition at %d", ttime);
transitions.pop_front();
return true;
}
return false;
}
void WetEngine::runAfterArcade(ArcadeShooting *arc) {
_checkpoint = _currentLevel;
_playerFrameSeps.clear();
for (Frames::iterator it =_playerFrames.begin(); it != _playerFrames.end(); ++it) {
(*it)->free();
delete (*it);
}
_playerFrames.clear();
if (_health < 0)
_health = 0;
if (arc->mode == "YT") {
for (Frames::iterator it = _c33PlayerCursor.begin(); it != _c33PlayerCursor.end(); ++it) {
(*it)->free();
delete (*it);
}
}
if (isDemo() && _variant != "Demo" && _variant != "M&MCD" && _restoredContentEnabled) {
showDemoScore();
} else if (!isDemo() || _variant == "Demo" || _variant == "M&MCD" || _variant == "Gen4") {
byte *palette;
Graphics::Surface *frame = decodeFrame("c_misc/zones.smk", 12, &palette);
loadPalette(palette, 0, 256);
free(palette);
uint32 c = kHypnoColorGreen; // green
int bonusCounter = 0;
int scoreCounter = _score - _bonus;
bool extraLife = false;
assert(scoreCounter >= 0);
bool skip = false;
Common::Event event;
while (!shouldQuit() && !skip) {
drawImage(*frame, 0, 0, false);
drawString("scifi08.fgx", Common::String::format("Lives : %d", _lives), 36, 2, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %7d", "SHOTS FIRED", _stats.shootsFired), 60, 46, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %7d", "ENEMY TARGETS", _stats.enemyTargets), 60, 56, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %7d", "TARGETS DESTROYED", _stats.targetsDestroyed), 60, 66, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %7d", "TARGETS MISSED", _stats.targetsMissed), 60, 76, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %5d %%", "KILL RATIO", killRatio()), 60, 86, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %5d %%", "ACCURACY", accuracyRatio()), 60, 96, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %5d %%", "ENERGY", _health), 60, 106, 0, c);
while (g_system->getEventManager()->pollEvent(event)) {
// Events
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_KEYDOWN:
bonusCounter = _bonus;
drawString("scifi08.fgx", Common::String::format("%-20s = %3d pts", "BONUS", _bonus), 60, 116, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %3d pts", "SCORE", _score), 60, 126, 0, c);
skip = true;
break;
default:
break;
}
}
if (bonusCounter < _bonus) {
bonusCounter++;
scoreCounter++;
drawString("scifi08.fgx", Common::String::format("%-20s = %3d pts", "BONUS", bonusCounter), 60, 116, 0, c);
drawString("scifi08.fgx", Common::String::format("%-20s = %3d pts", "SCORE", scoreCounter), 60, 126, 0, c);
}
extraLife |= checkScoreMilestones(scoreCounter); // This increase the number of lives, if necessary
if (extraLife) {
drawString("scifi08.fgx", "EXTRA LIFE", 164, 140, 0, kHypnoColorRed);
}
drawScreen();
g_system->delayMillis(25);
}
frame->free();
delete frame;
}
if (!arc->postStatsVideo.empty()) {
MVideo video(arc->postStatsVideo, Common::Point(0, 0), false, true, false);
disableCursor();
runIntro(video);
}
}
void WetEngine::restoreScoreMilestones(int score) {
if (score == 0) {
_scoreMilestones.clear();
_scoreMilestones.push_back(10000);
_scoreMilestones.push_back(25000);
_scoreMilestones.push_back(50000);
_scoreMilestones.push_back(100000);
} else {
while (true) {
if (_scoreMilestones.empty() || score < *_scoreMilestones.begin())
break;
_scoreMilestones.pop_front();
}
}
}
bool WetEngine::checkScoreMilestones(int score) {
bool extraLife = false;
while (true) {
if (_scoreMilestones.empty() || score < *_scoreMilestones.begin())
break;
_scoreMilestones.pop_front();
_lives = _lives + 1;
extraLife = true;
}
return extraLife;
}
uint32 WetEngine::findPaletteIndexZones(uint32 id) {
switch (id) {
case 11:
return 237;
case 10:
return 239;
case 21:
return 240;
case 22:
return 237;
case 23:
return 238;
case 20:
return 239;
default:
break;
}
switch (id / 10) {
case 3:
if (id == 30)
return 241;
else
return 237 + id % 10;
case 4:
if (id == 40)
return 241;
else
return 236 + id % 10;
case 5:
if (id == 50)
return 240;
else
return 237 + id % 10;
case 6:
if (id == 60)
return 238;
else
return 237;
default:
error("Invalid level id: %d", id);
}
}
void WetEngine::runBeforeArcade(ArcadeShooting *arc) {
_health = arc->health;
_maxHealth = _health;
resetStatistics();
_checkpoint = _currentLevel;
MVideo *video;
if (!isDemo() || ((_variant == "Demo" || _variant == "M&MCD") && _restoredContentEnabled)) {
saveProfile(_name, int(arc->id));
byte *palette;
Graphics::Surface *frame = decodeFrame("c_misc/zones.smk", (arc->id / 10 - 1) * 2, &palette);
loadPalette(palette, 0, 256);
free(palette);
byte red[3] = {0xff, 0x00, 0x00};
for (int i = 0; i < 5; i++)
loadPalette((byte *) &red, 237 + i, 1);
byte blue[3] = {0x00, 0x00, 0xff};
for (uint32 id = 10 * (arc->id / 10) + 1; id < arc->id; id++)
loadPalette((byte *) &blue, findPaletteIndexZones(id), 1);
byte green[3] = {0x00, 0xff, 0x00};
uint32 idx = findPaletteIndexZones(arc->id);
loadPalette((byte *) &green, idx, 1);
drawImage(*frame, 0, 0, false);
frame->free();
delete frame;
bool showedBriefing = false;
bool endedBriefing = false;
Common::Event event;
uint32 c = kHypnoColorGreen; // green
drawString("scifi08.fgx", Common::String::format("Lives : %d", _lives), 36, 2, 0, c);
while (!shouldQuit() && !endedBriefing) {
while (g_system->getEventManager()->pollEvent(event)) {
// Events
switch (event.type) {
case Common::EVENT_QUIT:
case Common::EVENT_RETURN_TO_LAUNCHER:
break;
case Common::EVENT_LBUTTONDOWN:
case Common::EVENT_KEYDOWN:
if (showedBriefing) {
endedBriefing = true;
break;
}
if (!arc->briefingVideo.empty()) {
Graphics::Surface *bframe = decodeFrame(arc->briefingVideo, 1, &palette);
loadPalette(palette, 0, 256);
free(palette);
video = new MVideo(arc->briefingVideo, Common::Point(44, 22), false, false, false);
runIntro(*video);
delete video;
bframe->free();
delete bframe;
}
showedBriefing = true;
break;
default:
break;
}
}
drawScreen();
g_system->delayMillis(10);
}
}
if (!arc->beforeVideo.empty()) {
video = new MVideo(arc->beforeVideo, Common::Point(0, 0), false, true, false);
runIntro(*video);
delete video;
}
if (arc->mode == "Y2" && !arc->additionalVideo.empty()) {
video = new MVideo(arc->additionalVideo, Common::Point(0, 0), false, true, false);
runIntro(*video);
delete video;
}
if (!arc->player.empty()) {
_playerFrames = decodeFrames(arc->player);
}
if (_variant == "EarlyDemo" && (arc->id == 31 || arc->id == 41)) {
int cutX = 36;
for (int i = 0; i < int(_playerFrames.size()); i++) {
Graphics::Surface *frame = _playerFrames[i];
Graphics::Surface *newFrame = new Graphics::Surface();
newFrame->create(320, 200, frame->format);
newFrame->fillRect(Common::Rect(0, 0, 320, 200), frame->format.ARGBToColor(0, 0, 0, 0));
newFrame->copyRectToSurfaceWithKey(*frame, 0, 0, Common::Rect(0, 0, 320, cutX), 0);
newFrame->copyRectToSurfaceWithKey(*frame, 0, 200 - (frame->h - cutX - 1), Common::Rect(0, cutX, 320, frame->h - 1), 0);
frame->free();
delete frame;
_playerFrames[i] = newFrame;
}
}
if (arc->mode == "Y4" || arc->mode == "Y5") { // These images are flipped, for some reason
for (Frames::iterator it = _playerFrames.begin(); it != _playerFrames.end(); ++it) {
for (int i = 0 ; i < (*it)->w ; i++)
for (int j = 0 ; j < (*it)->h/2 ; j++) {
uint32 p1 = (*it)->getPixel(i, j);
uint32 p2 = (*it)->getPixel(i, (*it)->h - j - 1);
(*it)->setPixel(i, j, p2);
(*it)->setPixel(i, (*it)->h - j - 1, p1);
}
}
}
for (int i = 0; i < int(_playerFrames.size()); i++) {
if (_playerFrames[i]->getPixel(0, 0) == 255)
_playerFrameSeps.push_back(i);
else if (_playerFrames[i]->getPixel(0, 0) == 252)
_playerFrameSeps.push_back(i);
}
if (_playerFrameSeps.size() == 0) {
debugC(1, kHypnoDebugArcade, "No player separator frame found in %s! (size: %d)", arc->player.c_str(), _playerFrames.size());
} else
debugC(1, kHypnoDebugArcade, "Number of separator frames: %d", _playerFrameSeps.size());
_playerFrameStart = 0;
_playerFrameSep = _playerFrames.size();
if (_playerFrameSeps.size() > 0) {
_playerFrameSep = *_playerFrameSeps.begin();
_playerFrameSeps.pop_front();
}
if (_playerFrameSeps.size() > 0) {
_playerFrameEnd = *_playerFrameSeps.begin();
_playerFrameSeps.pop_front();
} else {
_playerFrameEnd = _playerFrames.size();
}
_playerFrameIdx = -1;
_ammo = 150;
_maxAmmo = 150;
_c33PlayerPosition = Common::Point(_screenW/2, _screenH/2);
if (arc->mode == "YT") {
_c33PlayerCursor = decodeFrames("c33/c33i2.smk");
_c33UseMouse = true;
_c33PlayerDirection.clear();
}
if (arc->mode == "Y3") {
bool started = startCountdown(420); // 7 minutes
if (!started)
error("Failed to start countdown in level %d!", arc->id);
} else
_timerStarted = false;
}
void WetEngine::pressedKey(const int keycode) {
if (keycode == Common::KEYCODE_c) {
_background->decoder->pauseVideo(true);
showCredits();
loadPalette(_currentPalette);
changeScreenMode("320x200");
_background->decoder->pauseVideo(false);
updateScreen(*_background);
drawScreen();
if (!_music.empty())
playSound(_music, 0, _musicRate); // restore music
} else if (keycode == Common::KEYCODE_s) { // Added for testing
if (_cheatsEnabled) {
_skipLevel = true;
}
} else if (keycode == Common::KEYCODE_k) { // Added for testing
_health = 0;
} else if (keycode == Common::KEYCODE_ESCAPE) {
openMainMenuDialog();
} else if (keycode == Common::KEYCODE_LEFT) {
if (_arcadeMode == "YT" && _c33PlayerPosition.x > 0) {
_c33UseMouse = false;
if (_c33PlayerDirection.size() < 3)
_c33PlayerDirection.push_back(kPlayerLeft);
}
} else if (keycode == Common::KEYCODE_DOWN) {
if (_arcadeMode == "YT" && _c33PlayerPosition.y < 130) { // Viewport value minus 30
_c33UseMouse = false;
if (_c33PlayerDirection.size() < 3)
_c33PlayerDirection.push_back(kPlayerBottom);
}
} else if (keycode == Common::KEYCODE_RIGHT) {
if (_arcadeMode == "YT" && _c33PlayerPosition.x < _screenW) {
_c33UseMouse = false;
if (_c33PlayerDirection.size() < 3)
_c33PlayerDirection.push_back(kPlayerRight);
}
} else if (keycode == Common::KEYCODE_UP) {
if (_arcadeMode == "YT" && _c33PlayerPosition.y > 0) {
_c33UseMouse = false;
if (_c33PlayerDirection.size() < 3)
_c33PlayerDirection.push_back(kPlayerTop);
}
}
}
Common::Point WetEngine::getPlayerPosition(bool needsUpdate) {
Common::Point mousePos = g_system->getEventManager()->getMousePos();
if (_arcadeMode == "YT") {
if (needsUpdate) {
if (!_c33UseMouse) {
disableCursor();
if (_c33PlayerDirection.size() == 0)
drawImage(*_c33PlayerCursor[10], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
else if (_c33PlayerDirection.front() == kPlayerRight) {
_c33PlayerPosition.x = _c33PlayerPosition.x + 4;
drawImage(*_c33PlayerCursor[4], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
} else if (_c33PlayerDirection.front() == kPlayerLeft) {
_c33PlayerPosition.x = _c33PlayerPosition.x - 4;
drawImage(*_c33PlayerCursor[8], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
} else if (_c33PlayerDirection.front() == kPlayerBottom) {
_c33PlayerPosition.y = _c33PlayerPosition.y + 4;
drawImage(*_c33PlayerCursor[12], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
} else if (_c33PlayerDirection.front() == kPlayerTop) {
_c33PlayerPosition.y = _c33PlayerPosition.y - 4;
drawImage(*_c33PlayerCursor[10], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
} else
error("Invalid condition in getPlayerPosition");
if (_c33PlayerDirection.size() > 0)
_c33PlayerDirection.pop_front();
} else {
Common::Point diff = mousePos - _c33PlayerPosition;
if (abs(diff.x) > 1 || abs(diff.y) > 1)
diff = diff / 10;
if (abs(diff.x) >= 10)
diff.x = (diff.x / abs(diff.x)) * 10;
if (abs(diff.y) >= 10)
diff.y = (diff.x / abs(diff.x)) * 10;
_c33PlayerPosition = _c33PlayerPosition + diff;
if (diff.x > 0 && abs(diff.x) > abs(diff.y))
drawImage(*_c33PlayerCursor[4], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
else if (diff.x < 0 && abs(diff.x) > abs(diff.y))
drawImage(*_c33PlayerCursor[8], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
else if (diff.y > 0)
drawImage(*_c33PlayerCursor[12], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
else
drawImage(*_c33PlayerCursor[10], _c33PlayerPosition.x - 10, _c33PlayerPosition.y, true);
}
}
uint32 c = _compositeSurface->getPixel(_c33PlayerPosition.x, _c33PlayerPosition.y);
if (c >= 225 && c <= 231) {
if (!_infiniteHealthCheat)
_health = _health - 1;
generateStaticEffect();
}
return _c33PlayerPosition;
}
return mousePos;
}
void WetEngine::drawCursorArcade(const Common::Point &mousePos) {
int i = detectTarget(mousePos);
if (_arcadeMode == "YT") {
if (_c33UseMouse)
changeCursor("arcade");
else
disableCursor();
return;
}
if (i >= 0)
changeCursor("target");
else
changeCursor("arcade");
}
bool WetEngine::clickedSecondaryShoot(const Common::Point &mousePos) {
if (_ammo <= 0)
return false;
if (!_infiniteAmmoCheat)
_ammo--;
incShotsFired();
return clickedPrimaryShoot(mousePos);
}
void WetEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
if (s->name == "SP_SWITCH_R" || s->name == "SP_SWITCH_L") {
_health = 0;
} else if (s->name == "SP_LIZARD1") {
if (!_infiniteHealthCheat)
_health = _health - 15;
_background->decoder->pauseVideo(true);
MVideo video(arc->additionalVideo, Common::Point(0, 0), false, true, false);
runIntro(video);
loadPalette(arc->backgroundPalette);
_background->decoder->pauseVideo(false);
updateScreen(*_background);
drawScreen();
} else if (s->name.hasPrefix("DOOR")) {
_health = 0;
_background->decoder->pauseVideo(true);
// In some levels, the hit boss video is used to store this ending
MVideo video(arc->hitBoss1Video, Common::Point(0, 0), false, true, false);
runIntro(video);
loadPalette(_currentPalette);
_background->decoder->pauseVideo(false);
updateScreen(*_background);
drawScreen();
_skipDefeatVideo = true;
} else if (s->attackFrames.empty()) {
if (!_infiniteHealthCheat)
_health = _health - s->attackWeight;
hitPlayer();
}
}
void WetEngine::missNoTarget(ArcadeShooting *arc) {
for (int i = _shoots.size() - 1; i >= 0; --i) {
Shoot *it = &_shoots[i];
if ((it->name == "SP_BOSS" || it->name == "SP_BOSS1") && !arc->missBoss1Video.empty()) {
_background->decoder->pauseVideo(true);
MVideo video(arc->missBoss1Video, 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); // restore music
break;
} else if (it->name == "SP_BOSS2" && !arc->missBoss2Video.empty()) {
_background->decoder->pauseVideo(true);
MVideo video(arc->missBoss2Video, 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); // restore music
break;
}
}
}
void WetEngine::generateStaticEffect() {
// random static
uint8 c = _compositeSurface->getPixel(150, 120); // some pixel in the middle
if (c != 0 && c != 254) {
for (int i = 0; i < _screenW; i++) {
for (int j = 50; j < 60; j++) {
c = _rnd->getRandomBit() ? 254 : 0;
_compositeSurface->setPixel(i, j, c);
}
}
for (int i = 0; i < _screenW; i++) {
for (int j = 80; j < 90; j++) {
c = _rnd->getRandomBit() ? 254 : 0;
_compositeSurface->setPixel(i, j, c);
}
}
for (int i = 0; i < _screenW; i++) {
for (int j = 120; j < 150; j++) {
c = _rnd->getRandomBit() ? 254 : 0;
_compositeSurface->setPixel(i, j, c);
}
}
drawScreen();
if (!_additionalSound.empty()) {
playSound(_soundPath + _additionalSound, 1, 11025);
}
}
}
void WetEngine::hitPlayer() {
if (_arcadeMode != "YT" && _arcadeMode != "Y1" && _arcadeMode != "Y2" && _arcadeMode != "Y3" && _arcadeMode != "Y4" && _arcadeMode != "Y5") {
assert( _playerFrameSep < (int)_playerFrames.size());
if (_playerFrameIdx < _playerFrameSep)
_playerFrameIdx = _playerFrameSep;
}
if (!_hitSound.empty()) {
playSound(_soundPath + _hitSound, 1, 11025);
}
}
Common::Point WetEngine::computeTargetPosition(const Common::Point &mousePos) {
if (_arcadeMode == "YT") {
return Common::Point(mousePos.x, mousePos.y - 20);
}
return mousePos;
}
void WetEngine::drawShoot(const Common::Point &mousePos) {
uint32 c = kHypnoColorYellow;
if (_arcadeMode == "YT") {
_compositeSurface->drawLine(mousePos.x, mousePos.y - 20, mousePos.x + 5, mousePos.y, c);
_compositeSurface->drawLine(mousePos.x, mousePos.y - 20, mousePos.x + 5, mousePos.y, c);
_compositeSurface->drawLine(mousePos.x, mousePos.y - 20, mousePos.x - 5, mousePos.y, c);
_compositeSurface->drawLine(mousePos.x, mousePos.y - 20, mousePos.x - 5, mousePos.y, c);
} else if (_arcadeMode == "Y4") {
_compositeSurface->drawLine(_screenW/2 - 50, _screenH, mousePos.x, mousePos.y, c);
_compositeSurface->drawLine(_screenW/2 - 50, _screenH, mousePos.x - 1, mousePos.y, c);
_compositeSurface->drawLine(_screenW/2 + 50, _screenH, mousePos.x, mousePos.y, c);
_compositeSurface->drawLine(_screenW/2 + 50, _screenH, mousePos.x - 1, mousePos.y, c);
} else {
_compositeSurface->drawLine(0, _screenH, mousePos.x, mousePos.y, c);
_compositeSurface->drawLine(0, _screenH, mousePos.x - 1, mousePos.y, c);
_compositeSurface->drawLine(0, _screenH, mousePos.x - 2, mousePos.y, c);
_compositeSurface->drawLine(_screenW, _screenH, mousePos.x, mousePos.y, c);
_compositeSurface->drawLine(_screenW, _screenH, mousePos.x - 1, mousePos.y, c);
_compositeSurface->drawLine(_screenW, _screenH, mousePos.x - 2, mousePos.y, c);
}
playSound(_soundPath + _shootSound, 1);
if (_arcadeMode == "Y4") {
if (mousePos.x <= 25)
_playerFrameIdx = 10;
else if (mousePos.x <= 50)
_playerFrameIdx = 12;
else if (mousePos.x >= 295)
_playerFrameIdx = 18;
else if (mousePos.x >= 270)
_playerFrameIdx = 16;
else
_playerFrameIdx = 14;
drawImage(*_playerFrames[_playerFrameIdx], 0, 200 - _playerFrames[_playerFrameIdx]->h, true);
}
}
void WetEngine::drawPlayer() {
uint8 segmentType = _segments[_segmentIdx].type;
if (segmentType == 0xc5 || segmentType == 0xc2 || segmentType == 0xcc)
if (_background->decoder->getCurFrame() % 3 > 0) // Avoid flashing too much
drawString("block05.fgx", _directionString, 113, 13, 80, kHypnoColorCyan);
// TARGET ACQUIRED frame
uint32 c = kHypnoColorGreen; // green
_compositeSurface->drawLine(113, 1, 119, 1, c);
_compositeSurface->drawLine(200, 1, 206, 1, c);
_compositeSurface->drawLine(113, 1, 113, 9, c);
_compositeSurface->drawLine(206, 1, 206, 9, c);
_compositeSurface->drawLine(113, 9, 119, 9, c);
_compositeSurface->drawLine(200, 9, 206, 9, c);
if (_timerStarted) {
assert(_arcadeMode == "Y3");
c = kHypnoColorYellow;
uint32 minutes = _countdown / 60;
uint32 seconds = _countdown % 60;
drawString("block05.fgx", Common::String::format("CLOCK %02d:%02d", minutes, seconds), 19, 11, 0, c);
const chapterEntry *entry = _chapterTable[_levelId];
Common::Point ep(entry->energyPos[0], entry->energyPos[1]);
Common::Rect r = Common::Rect(ep.x - 2, ep.y + 6, ep.x + 69, ep.y + 15);
_compositeSurface->frameRect(r, kHypnoColorGreen);
}
c = kHypnoColorRed; // red ?
Common::Point mousePos = g_system->getEventManager()->getMousePos();
int i = detectTarget(mousePos);
if (i >= 0)
drawString("block05.fgx", _targetString.c_str(), 116, 3, 80, c);
if (_arcadeMode == "Y1" || _arcadeMode == "Y3")
return;
_playerFrameIdx++;
if (_playerFrameIdx == _playerFrameSep || _playerFrameIdx >= _playerFrameEnd) {
_playerFrameIdx = _playerFrameStart;
}
if (_arcadeMode == "Y5") {
int x = mousePos.x / (_screenW / 3);
int y = mousePos.y / (_screenH / 3);
_playerFrameIdx = 2 * (x + 3*y) + 1;
} else if (_arcadeMode == "Y4") {
if (mousePos.x <= 25)
_playerFrameIdx = 0;
else if (mousePos.x <= 50)
_playerFrameIdx = 2;
else if (mousePos.x >= 295)
_playerFrameIdx = 8;
else if (mousePos.x >= 270)
_playerFrameIdx = 6;
else
_playerFrameIdx = 4;
}
int offset = 0;
// Ugly, but seems to be necessary
if (_levelId == 31 && _variant != "EarlyDemo")
offset = 2;
else if (_levelId == 52)
offset = 2;
drawImage(*_playerFrames[_playerFrameIdx], 0, 200 - _playerFrames[_playerFrameIdx]->h + offset, true);
}
void WetEngine::drawHealth() {
uint32 c = kHypnoColorYellow;
int p = (100 * _health) / _maxHealth;
int s = _score;
int mo = _objKillsCount[_objIdx];
int mm = _objKillsRequired[_objIdx];
if (_playerFrameIdx < _playerFrameSep) {
const chapterEntry *entry = _chapterTable[_levelId];
Common::Point ep(entry->energyPos[0], entry->energyPos[1]);
Common::Point sp(entry->scorePos[0], entry->scorePos[1]);
Common::Point op(entry->objectivesPos[0], entry->objectivesPos[1]);
Common::String healthFormat = _healthString + " %d%%";
drawString("block05.fgx", Common::String::format(healthFormat.c_str(), p), ep.x, ep.y, 65, c);
Common::String scoreFormat = _scoreString + " %04d";
Common::String moFormat = _objString + " %d/%d";
if (_arcadeMode == "Y1" || _arcadeMode == "Y3" || _arcadeMode == "Y4" || _arcadeMode == "Y5") {
Common::Rect r;
r = Common::Rect(ep.x - 2, ep.y - 2, ep.x + 69, sp.y + 7);
_compositeSurface->frameRect(r, kHypnoColorGreen);
r = Common::Rect(sp.x - 2, sp.y - 2, sp.x + 74, sp.y + 7);
_compositeSurface->frameRect(r, kHypnoColorGreen);
r = Common::Rect(op.x - 2, op.y - 2, op.x + 74, op.y + 7);
_compositeSurface->frameRect(r, kHypnoColorGreen);
scoreFormat = _scoreString + " %04d";
moFormat = _objString + " %d/%d";
}
drawString("block05.fgx", Common::String::format(scoreFormat.c_str(), s), sp.x, sp.y, 72, c);
if (op.x > 0 && op.y > 0)
drawString("block05.fgx", Common::String::format(moFormat.c_str(), mo, mm), op.x, op.y, 60, c);
}
}
void WetEngine::drawAmmo() {
const chapterEntry *entry = _chapterTable[_levelId];
if (entry->ammoPos[0] == 0 && entry->ammoPos[1] == 0)
return;
if (_playerFrameIdx > _playerFrameSep) // Player was hit
return;
int d = (13 * (_maxAmmo - _ammo) / _maxAmmo);
if (d >= 13)
return;
Common::Point p(entry->ammoPos[0], entry->ammoPos[1]);
int ao = entry->ammoOffset;
Common::Rect r;
if (_arcadeMode == "Y1" || _arcadeMode == "Y3" || _arcadeMode == "Y4" || _arcadeMode == "Y5") {
r = Common::Rect(p.x - 1, p.y - 1, p.x + 16, p.y + 14);
_compositeSurface->frameRect(r, kHypnoColorGreen);
}
if (_levelId / 10 == 5 && _arcadeMode != "Y5") {
r = Common::Rect(p.x, p.y + d, p.x + 13, p.y + 13);
_compositeSurface->fillRect(r, kHypnoColorWhiteOrBlue); // blue
if (ao > 0) {
r = Common::Rect(p.x + ao, p.y + d, p.x + 13 + ao, p.y + 13);
_compositeSurface->fillRect(r, kHypnoColorWhiteOrBlue); // blue
}
} else {
r = Common::Rect(p.x, p.y + d, p.x + 15, p.y + 13);
_compositeSurface->fillRect(r, kHypnoColorWhiteOrBlue); // blue
if (ao > 0) {
r = Common::Rect(p.x + ao, p.y + d, p.x + 15 + ao, p.y + 13);
_compositeSurface->fillRect(r, kHypnoColorWhiteOrBlue); // blue
}
}
}
byte *WetEngine::getTargetColor(Common::String name, int levelId) {
if (name == "BOSS1" || name == "BOSS2" || name == "BOSS3" || name == "BOSS4")
return getPalette(kHypnoColorGreen);
const chapterEntry *entry = _chapterTable[levelId];
if (entry->targetColor < 0)
error ("No target color specified for level %d", levelId);
return getPalette(entry->targetColor);
}
bool WetEngine::checkRButtonUp() {
return _rButtonUp;
}
void WetEngine::setRButtonUp(const bool val) {
_rButtonUp = val;
}
} // End of namespace Hypno