Initial commit
This commit is contained in:
1
engines/hypno/POTFILES
Normal file
1
engines/hypno/POTFILES
Normal file
@@ -0,0 +1 @@
|
||||
engines/hypno/metaengine.cpp
|
||||
255
engines/hypno/actions.cpp
Normal file
255
engines/hypno/actions.cpp
Normal file
@@ -0,0 +1,255 @@
|
||||
/* 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/events.h"
|
||||
|
||||
#include "hypno/grammar.h"
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
// Actions
|
||||
|
||||
void HypnoEngine::runMenu(Hotspots *hs, bool only_menu) {
|
||||
Hotspot *h = hs->begin();
|
||||
assert(h->type == MakeMenu);
|
||||
|
||||
debugC(1, kHypnoDebugScene, "hotspot actions size: %d", h->actions.size());
|
||||
for (Actions::const_iterator itt = h->actions.begin(); !only_menu && itt != h->actions.end(); ++itt) {
|
||||
Action *action = *itt;
|
||||
switch (action->type) {
|
||||
case QuitAction:
|
||||
runQuit((Quit *)action);
|
||||
break;
|
||||
case TimerAction:
|
||||
runTimer((Timer *)action);
|
||||
break;
|
||||
case BackgroundAction:
|
||||
runBackground((Background *)action);
|
||||
break;
|
||||
case OverlayAction:
|
||||
runOverlay((Overlay *)action);
|
||||
break;
|
||||
case AmbientAction:
|
||||
runAmbient((Ambient *)action);
|
||||
break;
|
||||
case IntroAction:
|
||||
runIntro((Intro *)action);
|
||||
break;
|
||||
case PaletteAction:
|
||||
runPalette((Palette *)action);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// else if (typeid(*action) == typeid(Mice))
|
||||
// runMice(h, (Mice*) action);
|
||||
}
|
||||
|
||||
drawBackToMenu(h);
|
||||
}
|
||||
|
||||
void HypnoEngine::drawBackToMenu(Hotspot *h) {}
|
||||
|
||||
void HypnoEngine::runBackground(Background *a) {
|
||||
if (a->condition.size() > 0) {
|
||||
bool condition = _sceneState[a->condition];
|
||||
|
||||
if (a->flag1 == "/NSTATE" || a->flag2 == "/NSTATE")
|
||||
condition = !condition;
|
||||
|
||||
if (!condition)
|
||||
return;
|
||||
}
|
||||
|
||||
loadImage(a->path, a->origin.x, a->origin.y, false);
|
||||
}
|
||||
|
||||
void HypnoEngine::runTimer(Timer *a) {
|
||||
if (_timerStarted)
|
||||
return; // Do not start another timer
|
||||
|
||||
uint32 delay = a->delay / 1000;
|
||||
if (a->flag == "vus0")
|
||||
_keepTimerDuringScenes = true;
|
||||
debugC(1, kHypnoDebugScene, "Starting timer with %d secons", delay);
|
||||
|
||||
if (delay == 0 || !startCountdown(delay))
|
||||
error("Failed to start countdown");
|
||||
}
|
||||
|
||||
void HypnoEngine::runOverlay(Overlay *a) {
|
||||
loadImage(a->path, a->origin.x, a->origin.y, false);
|
||||
}
|
||||
|
||||
void HypnoEngine::runMice(Mice *a) {
|
||||
changeCursor(a->path, a->index);
|
||||
}
|
||||
|
||||
void HypnoEngine::runSwapPointer(SwapPointer *a) {
|
||||
_defaultCursorIdx = a->index;
|
||||
defaultCursor();
|
||||
}
|
||||
|
||||
void HypnoEngine::runPalette(Palette *a) {
|
||||
loadPalette(a->path);
|
||||
}
|
||||
|
||||
void HypnoEngine::runEscape() {
|
||||
_nextHotsToRemove = stack.back();
|
||||
_nextSequentialVideoToPlay = _escapeSequentialVideoToPlay;
|
||||
_escapeSequentialVideoToPlay.clear();
|
||||
}
|
||||
|
||||
void HypnoEngine::runIntro(Intro *a) {
|
||||
// Should not repeat the same
|
||||
if (_intros.contains(a->path))
|
||||
return;
|
||||
|
||||
_intros[a->path] = true;
|
||||
MVideo v(a->path, Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(v);
|
||||
defaultCursor();
|
||||
}
|
||||
|
||||
void HypnoEngine::runCutscene(Cutscene *a) {
|
||||
stopSound();
|
||||
defaultCursor();
|
||||
MVideo v(a->path, Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(v);
|
||||
defaultCursor();
|
||||
runMenu(stack.back());
|
||||
drawScreen();
|
||||
}
|
||||
|
||||
bool HypnoEngine::runGlobal(Global *a) {
|
||||
debugC(1, kHypnoDebugScene, "Running global with command '%s' and variable '%s'", a->command.c_str(), a->variable.c_str());
|
||||
if (a->command == "TURNON")
|
||||
_sceneState[a->variable] = 1;
|
||||
else if (a->command == "TURNOFF")
|
||||
_sceneState[a->variable] = 0;
|
||||
else if (a->command == "TOGGLE")
|
||||
_sceneState[a->variable] = !_sceneState[a->variable];
|
||||
else if (a->command == "CHECK") {
|
||||
if (!_sceneState[a->variable]) // Clear any video to play
|
||||
_nextSequentialVideoToPlay.clear();
|
||||
return _sceneState[a->variable];
|
||||
} else if (a->command == "NCHECK") {
|
||||
if (_sceneState[a->variable]) // Clear any video to play
|
||||
_nextSequentialVideoToPlay.clear();
|
||||
return !_sceneState[a->variable];
|
||||
} else if (a->command == "CLEAR") {
|
||||
resetSceneState();
|
||||
return true;
|
||||
} else
|
||||
error("Invalid command %s", a->command.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
void HypnoEngine::runPlay(Play *a) {
|
||||
if (a->condition.size() > 0 && !_sceneState[a->condition])
|
||||
return;
|
||||
|
||||
if (a->flag == "/BITMAP")
|
||||
loadImage(a->path, a->origin.x, a->origin.y, false);
|
||||
else {
|
||||
_nextSequentialVideoToPlay.push_back(MVideo(a->path, a->origin, false, false, false));
|
||||
}
|
||||
}
|
||||
|
||||
void HypnoEngine::runSound(Sound *a) {
|
||||
playSound(a->path, 1);
|
||||
}
|
||||
|
||||
void HypnoEngine::runAmbient(Ambient *a) {
|
||||
if (a->flag == "/BITMAP") {
|
||||
Graphics::Surface *frame = decodeFrame(a->path, a->frameNumber);
|
||||
Graphics::Surface *sframe;
|
||||
if (a->fullscreen)
|
||||
sframe = frame->scale(_screenW, _screenH);
|
||||
else
|
||||
sframe = frame;
|
||||
drawImage(*sframe, a->origin.x, a->origin.y, true);
|
||||
if (a->fullscreen) {
|
||||
frame->free();
|
||||
delete frame;
|
||||
}
|
||||
sframe->free();
|
||||
delete sframe;
|
||||
} else {
|
||||
bool loop = a->flag == "/LOOP";
|
||||
if (loop) { // Avoid re-adding the same looping video
|
||||
if (_intros.contains(a->path))
|
||||
return;
|
||||
_intros[a->path] = true;
|
||||
}
|
||||
_nextSequentialVideoToPlay.push_back(MVideo(a->path, a->origin, false, a->fullscreen, loop));
|
||||
}
|
||||
}
|
||||
|
||||
void HypnoEngine::runWalN(WalN *a) {
|
||||
if (a->condition.size() > 0 && !_sceneState[a->condition])
|
||||
return;
|
||||
|
||||
if (a->wn == "WAL0")
|
||||
_nextSequentialVideoToPlay.push_back(MVideo(a->path, a->origin, false, false, false));
|
||||
else if (a->wn == "WAL1")
|
||||
_escapeSequentialVideoToPlay.push_back(MVideo(a->path, a->origin, false, false, false));
|
||||
else
|
||||
error("Invalid WALN command: %s", a->wn.c_str());
|
||||
}
|
||||
|
||||
void HypnoEngine::runSave(Save *a) {
|
||||
// TODO: enable this when saving in the main menu is available
|
||||
// saveGameDialog();
|
||||
}
|
||||
|
||||
void HypnoEngine::runLoad(Load *a) {
|
||||
loadGameDialog();
|
||||
}
|
||||
|
||||
void HypnoEngine::runLoadCheckpoint(LoadCheckpoint *a) {
|
||||
if (_checkpoint.empty())
|
||||
error("Invalid checkpoint!");
|
||||
loadGame(_checkpoint, _score, _sceneState["GS_PUZZLELEVEL"], _sceneState["GS_COMBATLEVEL"]);
|
||||
}
|
||||
|
||||
void HypnoEngine::runQuit(Quit *a) {
|
||||
quitGame();
|
||||
}
|
||||
|
||||
void HypnoEngine::runChangeLevel(ChangeLevel *a) {
|
||||
debugC(1, kHypnoDebugScene, "Next level is '%s'", a->level.c_str());
|
||||
_nextLevel = a->level;
|
||||
}
|
||||
|
||||
void HypnoEngine::runTalk(Talk *a) {
|
||||
// Recreate the items to allow modifications
|
||||
Talk *n = new Talk(a);
|
||||
_conversation.push_back(n);
|
||||
_refreshConversation = true;
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
836
engines/hypno/arcade.cpp
Normal file
836
engines/hypno/arcade.cpp
Normal file
@@ -0,0 +1,836 @@
|
||||
/* 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 "graphics/framelimiter.h"
|
||||
|
||||
#include "hypno/grammar.h"
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.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;
|
||||
Common::Point anchor = arc->anchor;
|
||||
anchor.x = 0; // This is almost always zero, except when the screen starts at the middle
|
||||
// We don't really need it
|
||||
anchor.y = MAX(0, anchor.y - arc->mouseBox.bottom);
|
||||
|
||||
// Correct mouseBox
|
||||
arc->mouseBox.moveTo(anchor.x, anchor.y);
|
||||
_background = new MVideo(arc->backgroundVideo, anchor, 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];
|
||||
|
||||
bool vsync = g_system->getFeatureState(OSystem::kFeatureVSync);
|
||||
// Disable vsync for arcade sequences, since these require a fixed frame rate
|
||||
g_system->beginGFXTransaction();
|
||||
g_system->setFeatureState(OSystem::kFeatureVSync, false);
|
||||
g_system->endGFXTransaction();
|
||||
|
||||
debugC(1, kHypnoDebugArcade, "Using frame delay: %d", arc->frameDelay);
|
||||
Graphics::FrameLimiter limiter(g_system, 1000.0 / arc->frameDelay);
|
||||
limiter.startFrame();
|
||||
|
||||
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_CUSTOM_ENGINE_ACTION_START:
|
||||
pressedKey(event.customType);
|
||||
if (event.customType == kActionPrimaryShoot)
|
||||
if (clickedPrimaryShoot(mousePos))
|
||||
shootingPrimary = true;
|
||||
break;
|
||||
|
||||
case Common::EVENT_KEYDOWN:
|
||||
pressedKey(event.kbd.keycode);
|
||||
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.top) { // Usually top is zero
|
||||
g_system->warpMouse(mousePos.x, arc->mouseBox.top + 1);
|
||||
} 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.x = offset.x;
|
||||
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 (!isMusicActive() && !arc->music.empty()) {
|
||||
playMusic(_soundPath + arc->music, arc->musicRate, arc->musicStereo);
|
||||
}
|
||||
|
||||
if (needsUpdate) {
|
||||
if (shootingPrimary) {
|
||||
shootingPrimary = shoot(mousePos, arc, false);
|
||||
} else if (shootingSecondary) {
|
||||
shootingSecondary = shoot(mousePos, arc, true);
|
||||
}
|
||||
|
||||
drawPlayer();
|
||||
drawHealth();
|
||||
drawAmmo();
|
||||
}
|
||||
|
||||
limiter.delayBeforeSwap();
|
||||
drawScreen();
|
||||
limiter.startFrame();
|
||||
}
|
||||
|
||||
g_system->beginGFXTransaction();
|
||||
// Restore vsync state
|
||||
g_system->setFeatureState(OSystem::kFeatureVSync, vsync);
|
||||
g_system->endGFXTransaction();
|
||||
|
||||
// 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();
|
||||
stopMusic();
|
||||
}
|
||||
|
||||
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");
|
||||
|
||||
}
|
||||
|
||||
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();
|
||||
} 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);
|
||||
}
|
||||
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);
|
||||
|
||||
if (checkRButtonUp()) {
|
||||
setRButtonUp(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
bool HypnoEngine::checkRButtonUp() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void HypnoEngine::setRButtonUp(const bool val) {
|
||||
return;
|
||||
}
|
||||
|
||||
void HypnoEngine::disableGameKeymaps() {
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
}
|
||||
|
||||
void HypnoEngine::enableGameKeymaps() {
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
903
engines/hypno/boyz/arcade.cpp
Normal file
903
engines/hypno/boyz/arcade.cpp
Normal file
@@ -0,0 +1,903 @@
|
||||
/* 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 "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
void BoyzEngine::runBeforeArcade(ArcadeShooting *arc) {
|
||||
_checkpoint = _currentLevel;
|
||||
_lastStats = _stats;
|
||||
if (!_flashbackMode) {
|
||||
// if we are flashback mode,
|
||||
// then we are testing some level
|
||||
// and we should not save
|
||||
saveProfile(_name, int(arc->id));
|
||||
}
|
||||
|
||||
if (arc->mode == "YM") {
|
||||
assert(!arc->player.empty());
|
||||
_playerFrames = decodeFrames(arc->player);
|
||||
_playerFrameSep = 0;
|
||||
|
||||
Common::Rect healthBarBox(0, 3, 107, 18);
|
||||
Common::Rect ammoBarBox(0, 20, 103, 34);
|
||||
Common::Rect portraitBox(0, 40, 57, 94);
|
||||
|
||||
for (int i = 0; i < int(_playerFrames.size()); i++) {
|
||||
_healthBar[i+1] = _playerFrames[i]->getSubArea(healthBarBox);
|
||||
_ammoBar[i+1] = _playerFrames[i]->getSubArea(ammoBarBox);
|
||||
_portrait[i+1] = _playerFrames[i]->getSubArea(portraitBox);
|
||||
}
|
||||
|
||||
_playerFrameSep = _playerFrames.size();
|
||||
_playerFrameIdx = -1;
|
||||
} else {
|
||||
uint32 r = 1 + _rnd->getRandomNumber(1);
|
||||
arc->backgroundVideo = Common::String::format("c3/c35c0%ds.smk", r);
|
||||
_playerFrameSep = 0;
|
||||
_playerFrameIdx = -1;
|
||||
if (arc->mode != "YS")
|
||||
error("Invalid mode: %s", arc->mode.c_str());
|
||||
}
|
||||
|
||||
if (!arc->beforeVideo.empty()) {
|
||||
MVideo video(arc->beforeVideo, Common::Point(0, 0), false, true, false);
|
||||
runIntro(video);
|
||||
}
|
||||
|
||||
_currentScript = arc->script;
|
||||
// Reload all weapons
|
||||
for (Script::iterator it = _currentScript.begin(); it != _currentScript.end(); ++it) {
|
||||
_ammo = _weaponMaxAmmo[it->cursor];
|
||||
}
|
||||
_currentActor = 0;
|
||||
updateFromScript();
|
||||
_shootsDestroyed.clear();
|
||||
_health = _previousHealth;
|
||||
_selectedCorrectBox = 0;
|
||||
}
|
||||
|
||||
void BoyzEngine::runAfterArcade(ArcadeShooting *arc) {
|
||||
for (int i = 0; i < int(_playerFrames.size()); i++) {
|
||||
_playerFrames[i]->free();
|
||||
delete _playerFrames[i];
|
||||
}
|
||||
_playerFrames.clear();
|
||||
|
||||
if (_flashbackMode) {
|
||||
resetStatistics();
|
||||
_nextLevel = "<select_t1>";
|
||||
return;
|
||||
}
|
||||
|
||||
if (_health <= 0) {
|
||||
if (_arcadeMode == "YS")
|
||||
return;
|
||||
_stats = _lastStats;
|
||||
disableCursor();
|
||||
|
||||
if (_levelId == 36 && !checkArcadeObjectives()) {
|
||||
MVideo video("warnings/w09s.smk", Common::Point(0, 0), false, true, false);
|
||||
runIntro(video);
|
||||
} else {
|
||||
if (getTerritory(_currentLevel) <= 4) {
|
||||
MVideo video(_deathDay[_currentActor], Common::Point(0, 0), false, true, false);
|
||||
runIntro(video);
|
||||
} else {
|
||||
MVideo video(_deathNight[_currentActor], Common::Point(0, 0), false, true, false);
|
||||
runIntro(video);
|
||||
}
|
||||
}
|
||||
return;
|
||||
} else {
|
||||
if (_levelId == 33 && checkArcadeObjectives()) {
|
||||
MVideo video("c3/c33a02s.smk", Common::Point(0, 0), false, true, false);
|
||||
runIntro(video);
|
||||
defaultCursor();
|
||||
waitForUserClick(1);
|
||||
} else if (_levelId == 42) {
|
||||
disableCursor();
|
||||
MVideo video("c4/c4bro8s.smk", Common::Point(0, 0), false, true, false);
|
||||
runIntro(video);
|
||||
}
|
||||
}
|
||||
|
||||
if (_currentLevel == lastLevelTerritory(_currentLevel)) {
|
||||
int territory = getTerritory(_currentLevel) - 1;
|
||||
showArcadeStats(territory, _stats);
|
||||
// Merge current stats with the global ones
|
||||
_globalStats.livesUsed = _stats.livesUsed + _globalStats.livesUsed;
|
||||
_globalStats.shootsFired = _stats.shootsFired + _globalStats.shootsFired;
|
||||
_globalStats.enemyHits = _stats.enemyHits + _globalStats.enemyHits;
|
||||
_globalStats.enemyTargets = _stats.enemyTargets + _globalStats.enemyTargets;
|
||||
_globalStats.targetsDestroyed = _stats.targetsDestroyed + _globalStats.targetsDestroyed;
|
||||
_globalStats.targetsMissed = _stats.targetsMissed + _globalStats.targetsMissed;
|
||||
_globalStats.friendliesEncountered = _stats.friendliesEncountered + _globalStats.friendliesEncountered;
|
||||
_globalStats.infoReceived = _stats.infoReceived + _globalStats.infoReceived;
|
||||
// If we are finishing the last level, show final stats
|
||||
if (_currentLevel == "c59.mi_")
|
||||
showArcadeStats(5, _globalStats);
|
||||
|
||||
// After that, we can reset the current stats
|
||||
resetStatistics();
|
||||
}
|
||||
|
||||
_previousHealth = _health;
|
||||
_sceneState[Common::String::format("GS_SEQ_%d", _levelId)] = 1;
|
||||
}
|
||||
|
||||
void BoyzEngine::showArcadeStats(int territory, const ArcadeStats &data) {
|
||||
byte *palette;
|
||||
Graphics::Surface *stats = decodeFrame("preload/stats.smk", territory, &palette);
|
||||
loadPalette(palette, 0, 256);
|
||||
drawImage(*stats, 0, 0, true);
|
||||
stats->free();
|
||||
delete stats;
|
||||
free(palette);
|
||||
uint32 enemiesAvailable = data.targetsDestroyed + data.targetsMissed;
|
||||
drawString("scifi08.fgx", Common::String::format("%d", enemiesAvailable), 278, 41, 0, kHypnoColorWhiteOrBlue);
|
||||
uint32 killRatio = enemiesAvailable > 0 ? 100 * data.targetsDestroyed / enemiesAvailable : 0;
|
||||
drawString("scifi08.fgx", Common::String::format("%d%%", killRatio), 278, 56, 0, kHypnoColorWhiteOrBlue);
|
||||
drawString("scifi08.fgx", Common::String::format("%d", data.shootsFired), 278, 79, 0, kHypnoColorWhiteOrBlue);
|
||||
uint32 accuracyRatio = data.shootsFired > 0 ? 100 * data.enemyHits / data.shootsFired : 0;
|
||||
drawString("scifi08.fgx", Common::String::format("%d%%", accuracyRatio), 278, 94, 0, kHypnoColorWhiteOrBlue);
|
||||
drawString("scifi08.fgx", Common::String::format("%d", data.livesUsed), 278, 119, 0, kHypnoColorWhiteOrBlue);
|
||||
drawString("scifi08.fgx", Common::String::format("%d", data.friendliesEncountered), 278, 144, 0, kHypnoColorWhiteOrBlue);
|
||||
drawString("scifi08.fgx", Common::String::format("%d", data.infoReceived), 278, 159, 0, kHypnoColorWhiteOrBlue);
|
||||
uint32 scorePercentage = (killRatio + accuracyRatio) / 2;
|
||||
drawString("scifi08.fgx", Common::String::format("%d%%", scorePercentage), 278, 184, 0, kHypnoColorWhiteOrBlue);
|
||||
|
||||
bool cont = true;
|
||||
while (!shouldQuit() && cont) {
|
||||
Common::Event event;
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
switch (event.type) {
|
||||
case Common::EVENT_KEYDOWN:
|
||||
cont = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
|
||||
void BoyzEngine::pressedKey(const int keycode) {
|
||||
if (keycode == kActionSkipLevel) {
|
||||
_skipLevel = true;
|
||||
return;
|
||||
} else if (keycode == kActionKillPlayer) { // Added for testing
|
||||
_health = 0;
|
||||
} else if (keycode == kActionPause) {
|
||||
openMainMenuDialog();
|
||||
}
|
||||
}
|
||||
|
||||
void BoyzEngine::updateFromScript() {
|
||||
if (_currentScript.size() > 0) {
|
||||
ScriptInfo si = *_currentScript.begin();
|
||||
//debug("%d %d %d", si.time, _background->decoder->getCurFrame(), si.actor);
|
||||
if (!_background || int(si.time) <= _background->decoder->getCurFrame()) {
|
||||
if (_currentActor != si.actor)
|
||||
_ammo = _weaponMaxAmmo[si.cursor];
|
||||
|
||||
_currentActor = si.actor;
|
||||
_currentMode = si.mode;
|
||||
_currentWeapon = si.cursor;
|
||||
_currentScript.pop_front();
|
||||
|
||||
if (_currentMode == NonInteractive)
|
||||
changeCursor(_crosshairsInactive[_currentWeapon], _crosshairsPalette, true);
|
||||
else
|
||||
changeCursor(_crosshairsActive[_currentWeapon], _crosshairsPalette, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void BoyzEngine::drawCursorArcade(const Common::Point &mousePos) {
|
||||
if (_currentMode == NonInteractive) {
|
||||
return;
|
||||
}
|
||||
|
||||
int i = detectTarget(mousePos);
|
||||
if (i >= 0)
|
||||
changeCursor(_crosshairsTarget[_currentWeapon], _crosshairsPalette, true);
|
||||
else
|
||||
changeCursor(_crosshairsActive[_currentWeapon], _crosshairsPalette, true);
|
||||
}
|
||||
|
||||
void BoyzEngine::drawPlayer() {
|
||||
updateFromScript();
|
||||
if (_arcadeMode != "YS")
|
||||
drawImage(_portrait[_currentActor], 0, 200 - _portrait[_currentActor].h, true);
|
||||
}
|
||||
|
||||
void BoyzEngine::drawHealth() {
|
||||
updateFromScript();
|
||||
if(_arcadeMode == "YS")
|
||||
return;
|
||||
|
||||
float w = float(_health) / float(_maxHealth);
|
||||
if (w <= 0 || _healthBar[_currentActor].w - 3 <= 0 || _healthBar[_currentActor].h / 2 <= 0)
|
||||
return;
|
||||
|
||||
Common::Rect healthBarBox(0, 0, int((_healthBar[_currentActor].w - 3) * w), _healthBar[_currentActor].h / 2);
|
||||
|
||||
uint32 c = kHypnoColorWhiteOrBlue; // white
|
||||
_compositeSurface->fillRect(healthBarBox, c);
|
||||
|
||||
for (int i = 0; i < _maxHealth; i = i + 10) {
|
||||
int x = (_healthBar[_currentActor].w - 3) * float(i) / float(_maxHealth);
|
||||
_compositeSurface->drawLine(x, 2, x, 6, 0);
|
||||
}
|
||||
|
||||
drawImage(_healthBar[_currentActor], 0, 0, true);
|
||||
}
|
||||
|
||||
void BoyzEngine::drawAmmo() {
|
||||
updateFromScript();
|
||||
if(_arcadeMode == "YS")
|
||||
return;
|
||||
|
||||
float w = float(_ammoBar[_currentActor].w) / float(_weaponMaxAmmo[_currentWeapon]);
|
||||
|
||||
Common::Rect ammoBarBox(320 - int(_ammo * w), 0, 320, _ammoBar[_currentActor].h / 2);
|
||||
uint32 c = kHypnoColorGreen; // green
|
||||
_compositeSurface->fillRect(ammoBarBox, c);
|
||||
|
||||
drawImage(_ammoBar[_currentActor], 320 - _ammoBar[_currentActor].w, 0, true);
|
||||
for (int i = 1; i < _weaponMaxAmmo[_currentWeapon]; i++) {
|
||||
int x = 320 - _ammoBar[_currentActor].w + int (i * w);
|
||||
_compositeSurface->drawLine(x, 2, x, 6, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void BoyzEngine::hitPlayer() {
|
||||
if(_arcadeMode == "YS")
|
||||
return; // Should never happen?
|
||||
|
||||
uint32 c = kHypnoColorRed; // red
|
||||
_compositeSurface->fillRect(Common::Rect(0, 0, _screenW, _screenH), c);
|
||||
drawScreen();
|
||||
if (!_infiniteHealthCheat) {
|
||||
_health = _health - 10;
|
||||
}
|
||||
if (!_hitSound.empty())
|
||||
playSound(_soundPath + _hitSound, 1, 11025);
|
||||
}
|
||||
void BoyzEngine::drawShoot(const Common::Point &target) {}
|
||||
|
||||
void BoyzEngine::initSegment(ArcadeShooting *arc) {
|
||||
_segmentShootSequenceOffset = 0;
|
||||
_segmentShootSequenceMax = 0;
|
||||
|
||||
uint32 randomSegmentShootSequence = _segmentShootSequenceOffset + _rnd->getRandomNumber(_segmentShootSequenceMax);
|
||||
SegmentShoots segmentShoots = arc->shootSequence[randomSegmentShootSequence];
|
||||
_shootSequence = segmentShoots.shootSequence;
|
||||
_segmentRepetitionMax = segmentShoots.segmentRepetition; // Usually zero
|
||||
_segmentRepetition = 0;
|
||||
_segmentOffset = 0;
|
||||
_segmentIdx = _segmentOffset;
|
||||
}
|
||||
|
||||
void BoyzEngine::findNextSegment(ArcadeShooting *arc) {
|
||||
_segmentIdx = _segmentIdx + 1;
|
||||
}
|
||||
|
||||
bool BoyzEngine::checkTransition(ArcadeTransitions &transitions, ArcadeShooting *arc) {
|
||||
ArcadeTransition at = *transitions.begin();
|
||||
int ttime = at.time;
|
||||
if (_background->decoder->getCurFrame() > ttime) {
|
||||
if (_background->decoder->getCurFrame() > ttime + 3) {
|
||||
debugC(1, kHypnoDebugArcade, "Skipped transition of %d at %d", ttime, _background->decoder->getCurFrame());
|
||||
} else if (at.video == "NONE") {
|
||||
if (!at.palette.empty()) {
|
||||
_background->decoder->pauseVideo(true);
|
||||
_currentPalette = at.palette;
|
||||
loadPalette(_currentPalette);
|
||||
_background->decoder->pauseVideo(false);
|
||||
drawPlayer();
|
||||
updateScreen(*_background);
|
||||
drawScreen();
|
||||
} else if (!arc->additionalSound.empty())
|
||||
playSound(arc->additionalSound, 1, arc->additionalSoundRate);
|
||||
else if (_levelId == 36) {
|
||||
if (!checkArcadeObjectives()) {
|
||||
_health = 0;
|
||||
// Not sure how to handle this
|
||||
}
|
||||
} else if (_levelId == 354) {
|
||||
if (ttime == 70) {
|
||||
incInfoReceived();
|
||||
_background->decoder->pauseVideo(true);
|
||||
MVideo video("tempdir/c35h4a1s.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
defaultCursor();
|
||||
waitForUserClick(1);
|
||||
_skipLevel = true;
|
||||
}
|
||||
} else if (_levelId == 51) {
|
||||
if (_selectedCorrectBox == 0) {
|
||||
_background->decoder->pauseVideo(true);
|
||||
_background->decoder->forceSeekToFrame(ttime - 2);
|
||||
_masks->decoder->forceSeekToFrame(ttime - 2);
|
||||
const Graphics::Surface *frame = _background->decoder->decodeNextFrame();
|
||||
Graphics::Surface *boxes = frame->convertTo(frame->format, _background->decoder->getPalette());
|
||||
drawImage(*boxes, 0, 0, false);
|
||||
drawScreen();
|
||||
boxes->free();
|
||||
delete boxes;
|
||||
_selectedCorrectBox = pickABox();
|
||||
if (_selectedCorrectBox == 1) {
|
||||
_background->decoder->forceSeekToFrame(582);
|
||||
_masks->decoder->forceSeekToFrame(582);
|
||||
} else if (_selectedCorrectBox == -1) {
|
||||
_background->decoder->forceSeekToFrame(525);
|
||||
_masks->decoder->forceSeekToFrame(525);
|
||||
} else
|
||||
error("Invalid value for _selectedCorrectBox: %d", _selectedCorrectBox);
|
||||
_background->decoder->pauseVideo(false);
|
||||
updateScreen(*_background);
|
||||
drawScreen();
|
||||
} else if (_selectedCorrectBox == -1) {
|
||||
_health = 0;
|
||||
}
|
||||
}
|
||||
} else if (!at.video.empty()) {
|
||||
_background->decoder->pauseVideo(true);
|
||||
_masks->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);
|
||||
if (_levelId == 59) {
|
||||
_background->decoder->forceSeekToFrame(97);
|
||||
_masks->decoder->forceSeekToFrame(97);
|
||||
}
|
||||
|
||||
_background->decoder->pauseVideo(false);
|
||||
_masks->decoder->pauseVideo(false);
|
||||
drawPlayer();
|
||||
updateScreen(*_background);
|
||||
drawScreen();
|
||||
drawCursorArcade(g_system->getEventManager()->getMousePos());
|
||||
} else if (!at.sound.empty()) {
|
||||
playSound(at.sound, 1, at.soundRate, at.soundStereo);
|
||||
} else if (at.jumpToTime > 0) {
|
||||
_background->decoder->forceSeekToFrame(at.jumpToTime);
|
||||
_masks->decoder->forceSeekToFrame(at.jumpToTime);
|
||||
} else if (at.loseLevel) {
|
||||
debugC(1, kHypnoDebugArcade, "Losing level in transition at %d", _background->decoder->getCurFrame());
|
||||
_health = 0;
|
||||
} else if (at.winLevel) {
|
||||
debugC(1, kHypnoDebugArcade, "Wining level in transition at %d", _background->decoder->getCurFrame());
|
||||
_skipLevel = true;
|
||||
} else
|
||||
error ("Invalid transition at %d", ttime);
|
||||
|
||||
transitions.pop_front();
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int BoyzEngine::detectTarget(const Common::Point &mousePos) {
|
||||
Common::Point target = computeTargetPosition(mousePos);
|
||||
if (!_mask)
|
||||
return -1;
|
||||
|
||||
uint32 m = _mask->getPixel(target.x, target.y);
|
||||
if (m == 0)
|
||||
return -1;
|
||||
|
||||
int i = 0;
|
||||
for (Shoots::iterator it = _shoots.begin(); it != _shoots.end(); ++it) {
|
||||
if (!it->bodyFrames.empty() && _background->decoder->getCurFrame() > int(it->bodyFrames.back().start)) {
|
||||
i++;
|
||||
continue; // This shoot is old!
|
||||
}
|
||||
|
||||
if (m == it->paletteOffset && !_shoots[i].destroyed)
|
||||
return i;
|
||||
i++;
|
||||
}
|
||||
if (i == int(_shoots.size()))
|
||||
return -1;
|
||||
|
||||
error("Invalid mask state (%d)!", m);
|
||||
}
|
||||
|
||||
char BoyzEngine::selectDirection() {
|
||||
Common::Event event;
|
||||
Common::Rect button(252, 158, 315, 195);
|
||||
Graphics::Surface *screen = _compositeSurface->convertTo(_compositeSurface->format, _background->decoder->getPalette());
|
||||
Frames mapFrames = decodeFrames("c4/minemap.smk");
|
||||
bool showMap = _sceneState["GS_MINEMAP"];
|
||||
bool viewingMap = false;
|
||||
if (showMap)
|
||||
drawImage(*mapFrames[0], 0, 0, true);
|
||||
|
||||
while (!shouldQuit()) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
Common::Point mousePos = g_system->getEventManager()->getMousePos();
|
||||
switch (event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
if (showMap && button.contains(mousePos))
|
||||
defaultCursor();
|
||||
else if (!viewingMap && mousePos.x <= _screenW / 3)
|
||||
changeCursor(_leftArrowPointer, _crosshairsPalette, true);
|
||||
else if (!viewingMap && mousePos.x >= 2 * _screenW / 3)
|
||||
changeCursor(_rightArrowPointer, _crosshairsPalette, true);
|
||||
else if (!viewingMap)
|
||||
changeCursor(_crossPointer, _crosshairsPalette, true);
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (showMap && button.contains(mousePos)) {
|
||||
if (viewingMap) {
|
||||
drawImage(*screen, 0, 0, false);
|
||||
drawImage(*mapFrames[0], 0, 0, true);
|
||||
} else {
|
||||
drawImage(*mapFrames[1], 0, 0, true);
|
||||
}
|
||||
viewingMap = !viewingMap;
|
||||
} else if (!viewingMap && mousePos.x <= _screenH / 2) {
|
||||
screen->free();
|
||||
delete screen;
|
||||
return 'L';
|
||||
} else if (!viewingMap) {
|
||||
screen->free();
|
||||
delete screen;
|
||||
return 'R';
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
screen->free();
|
||||
delete screen;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void BoyzEngine::waitForUserClick(uint32 timeout) {
|
||||
Common::Event event;
|
||||
bool cont = true;
|
||||
Common::Rect button(252, 158, 315, 195);
|
||||
while (!shouldQuit() && cont) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
Common::Point mousePos = g_system->getEventManager()->getMousePos();
|
||||
switch (event.type) {
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
cont = false;
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (button.contains(mousePos))
|
||||
cont = false;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
}
|
||||
|
||||
int BoyzEngine::pickABox() {
|
||||
Common::Event event;
|
||||
|
||||
Common::Rect correctBox(84, 14, 135, 66);
|
||||
Common::Rect incorrectBoxes[6];
|
||||
incorrectBoxes[0] = Common::Rect(15, 17, 77, 66);
|
||||
incorrectBoxes[1] = Common::Rect(2, 69, 84, 92);
|
||||
incorrectBoxes[2] = Common::Rect(74, 108, 242, 138);
|
||||
incorrectBoxes[3] = Common::Rect(62, 134, 245, 160);
|
||||
incorrectBoxes[4] = Common::Rect(59, 161, 239, 190);
|
||||
incorrectBoxes[5] = Common::Rect(135, 29, 223, 101);
|
||||
int i;
|
||||
while (!shouldQuit()) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
Common::Point mousePos = g_system->getEventManager()->getMousePos();
|
||||
switch (event.type) {
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
if (correctBox.contains(mousePos)) {
|
||||
changeCursor(_crosshairsTarget[_currentWeapon], _crosshairsPalette, true);
|
||||
break;
|
||||
}
|
||||
for (i = 0; i < 6; i++)
|
||||
if (incorrectBoxes[i].contains(mousePos)) {
|
||||
changeCursor(_crosshairsTarget[_currentWeapon], _crosshairsPalette, true);
|
||||
break;
|
||||
}
|
||||
if (i == 6)
|
||||
changeCursor(_crosshairsActive[_currentWeapon], _crosshairsPalette, true);
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (correctBox.contains(mousePos))
|
||||
return 1;
|
||||
for (i = 0; i < 6; i++)
|
||||
if (incorrectBoxes[i].contains(mousePos))
|
||||
return -1;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
bool BoyzEngine::shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool secondary) {
|
||||
if (_currentMode == NonInteractive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!secondary && _currentWeapon > 0) {
|
||||
if (_ammo == 0) {
|
||||
if (!arc->noAmmoSound.empty())
|
||||
playSound(_soundPath + arc->noAmmoSound, 1, arc->noAmmoSoundRate);
|
||||
return false;
|
||||
}
|
||||
if (!_infiniteAmmoCheat)
|
||||
_ammo--;
|
||||
playSound(_soundPath + _weaponShootSound[_currentWeapon], 1);
|
||||
incShotsFired();
|
||||
}
|
||||
int i = detectTarget(mousePos);
|
||||
if (i < 0) {
|
||||
missNoTarget(arc);
|
||||
} else {
|
||||
debugC(1, kHypnoDebugArcade, "Hit target %s", _shoots[i].name.c_str());
|
||||
if (_shoots[i].nonHostile && secondary) {
|
||||
playSound(_soundPath + _heySound[_currentActor], 1);
|
||||
|
||||
if (_shoots[i].isAnimal) {
|
||||
playSound(_soundPath + _shoots[i].animalSound, 1);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Not really killed, but counted as objective
|
||||
_objKillsCount[_objIdx] = _objKillsCount[_objIdx] + _shoots[i].objKillsCount;
|
||||
|
||||
if (!_shoots[i].additionalVideo.empty()) {
|
||||
incFriendliesEncountered();
|
||||
incInfoReceived();
|
||||
_background->decoder->pauseVideo(true);
|
||||
MVideo video(_shoots[i].additionalVideo, Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
defaultCursor();
|
||||
|
||||
if (_shoots[i].waitForClickAfterInteraction > 0) {
|
||||
waitForUserClick(_shoots[i].waitForClickAfterInteraction);
|
||||
if (_shoots[i].name == "LILKID")
|
||||
_sceneState["GS_MINEMAP"] = true;
|
||||
else if (_shoots[i].name == "HO3") {
|
||||
_sceneState["GS_C5MAP"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
loadPalette(_currentPalette);
|
||||
_background->decoder->pauseVideo(false);
|
||||
// Skip the rest of the interaction
|
||||
if (_shoots[i].explosionFrames[0].start == uint32(-1))
|
||||
_skipLevel = true;
|
||||
else {
|
||||
_background->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
|
||||
_masks->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start + 3);
|
||||
_shoots[i].destroyed = true;
|
||||
_shootsDestroyed[_shoots[i].name] = true;
|
||||
updateScreen(*_background);
|
||||
drawScreen();
|
||||
}
|
||||
} else if (_shoots[i].interactionFrame > 0) {
|
||||
incFriendliesEncountered();
|
||||
incInfoReceived();
|
||||
_background->decoder->forceSeekToFrame(_shoots[i].interactionFrame);
|
||||
_masks->decoder->forceSeekToFrame(_shoots[i].interactionFrame);
|
||||
if (!arc->missBoss2Video.empty()) {
|
||||
_additionalVideo = new MVideo(arc->missBoss2Video, Common::Point(0, 0), true, false, false);
|
||||
playVideo(*_additionalVideo);
|
||||
}
|
||||
//_shoots[i].lastFrame = _background->decoder->getFrameCount();
|
||||
_shoots[i].destroyed = true;
|
||||
_shootsDestroyed[_shoots[i].name] = true;
|
||||
updateScreen(*_background);
|
||||
drawScreen();
|
||||
}
|
||||
return false;
|
||||
} else if (_shoots[i].nonHostile && !secondary) {
|
||||
|
||||
if (checkCup(_shoots[i].name))
|
||||
return false;
|
||||
|
||||
if (!_shoots[i].hitSound.empty())
|
||||
playSound(_soundPath + _shoots[i].hitSound, 1);
|
||||
|
||||
if (!_shoots[i].deathSound.empty())
|
||||
playSound(_soundPath + _shoots[i].deathSound, 1);
|
||||
|
||||
if (!_shoots[i].additionalVideo.empty() || _shoots[i].interactionFrame > 0) // Only count the ones with info
|
||||
incFriendliesEncountered();
|
||||
|
||||
uint32 idx = _shoots[i].warningVideoIdx;
|
||||
if (idx > 0) {
|
||||
Common::String filename = _warningVideosDay[idx];
|
||||
|
||||
_background->decoder->pauseVideo(true);
|
||||
MVideo video(filename, Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
// Should be currentPalette?
|
||||
loadPalette(arc->backgroundPalette);
|
||||
_background->decoder->pauseVideo(false);
|
||||
updateScreen(*_background);
|
||||
drawScreen();
|
||||
hitPlayer();
|
||||
}
|
||||
if (_shoots[i].explosionFrames.size() == 0)
|
||||
return false;
|
||||
|
||||
debugC(1, kHypnoDebugArcade, "Jumping to %d", _shoots[i].explosionFrames[0].start - 3);
|
||||
_background->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start - 3);
|
||||
_masks->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start - 3);
|
||||
|
||||
|
||||
if (_shoots[i].jumpToTimeAfterKilled == -1000) {
|
||||
ArcadeTransition at("", 0, "", 0, _shoots[i].explosionFrames[0].lastFrame() - 1);
|
||||
at.loseLevel = true;
|
||||
_transitions.push_front(at);
|
||||
}
|
||||
|
||||
return false;
|
||||
} else if (!_shoots[i].nonHostile && secondary) {
|
||||
if (_shoots[i].interactionFrame > 0) {
|
||||
_background->decoder->forceSeekToFrame(_shoots[i].interactionFrame);
|
||||
_masks->decoder->forceSeekToFrame(_shoots[i].interactionFrame);
|
||||
_shoots[i].destroyed = true;
|
||||
|
||||
updateScreen(*_background);
|
||||
drawScreen();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!_shoots[i].hitSound.empty())
|
||||
playSound(_soundPath + _shoots[i].hitSound, 1);
|
||||
|
||||
incEnemyHits();
|
||||
if (!_shoots[i].deathSound.empty())
|
||||
playSound(_soundPath + _shoots[i].deathSound, 1);
|
||||
|
||||
if (_shoots[i].playInteractionAudio && !arc->missBoss2Video.empty()) {
|
||||
incInfoReceived();
|
||||
_additionalVideo = new MVideo(arc->missBoss2Video, Common::Point(0, 0), true, false, false);
|
||||
playVideo(*_additionalVideo);
|
||||
}
|
||||
|
||||
incTargetsDestroyed();
|
||||
incScore(_shoots[i].pointsToShoot);
|
||||
incBonus(_shoots[i].pointsToShoot);
|
||||
_shoots[i].destroyed = true;
|
||||
_objKillsCount[_objIdx] = _objKillsCount[_objIdx] + _shoots[i].objKillsCount;
|
||||
_shootsDestroyed[_shoots[i].name] = true;
|
||||
|
||||
if (_shoots[i].name == "HELICOPTER") {
|
||||
_background->decoder->pauseVideo(true);
|
||||
MVideo video(arc->hitBoss2Video, Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
_skipLevel = true;
|
||||
_skipNextVideo = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
_background->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start - 3);
|
||||
_masks->decoder->forceSeekToFrame(_shoots[i].explosionFrames[0].start - 3);
|
||||
debugC(1, kHypnoDebugArcade, "Jumping to: %d", _shoots[i].explosionFrames[0].start - 3);
|
||||
|
||||
changeCursor(_crosshairsActive[_currentWeapon], _crosshairsPalette, true);
|
||||
|
||||
if (_shoots[i].jumpToTimeAfterKilled > 0) {
|
||||
ArcadeTransition at("", 0, "", 0, _shoots[i].explosionFrames[0].lastFrame() - 1);
|
||||
at.jumpToTime = _shoots[i].jumpToTimeAfterKilled;
|
||||
_transitions.push_front(at);
|
||||
} else if ( _shoots[i].jumpToTimeAfterKilled == -1 ) {
|
||||
ArcadeTransition at("", 0, "", 0, _shoots[i].explosionFrames[0].lastFrame() - 1);
|
||||
at.winLevel = true;
|
||||
_transitions.push_front(at);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void BoyzEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
|
||||
debugC(1, kHypnoDebugArcade, "Missed target %s!", s->name.c_str());
|
||||
if (!s->checkIfDestroyed.empty()) {
|
||||
if (_shootsDestroyed.contains(s->checkIfDestroyed))
|
||||
return; // Precondition was destroyed, so we ignore the missed shoot
|
||||
}
|
||||
|
||||
if (s->nonHostile) {
|
||||
if (!s->additionalVideo.empty() || s->interactionFrame > 0) // Only count the ones with info
|
||||
incFriendliesEncountered();
|
||||
_stats.targetsMissed--; // If the target was not hostile, it should *not* count as missed
|
||||
}
|
||||
|
||||
if (s->name == "CAPTOR" || (s->name == "G1" && _currentLevel == "c354.mi_")) {
|
||||
_background->decoder->pauseVideo(true);
|
||||
MVideo video(_warningHostage, Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
hitPlayer();
|
||||
if (_health > 0)
|
||||
_skipLevel = true;
|
||||
return;
|
||||
} else if (s->name.hasPrefix("ALARM")) {
|
||||
if (s->missedAnimation != uint32(-1) && uint32(_background->decoder->getCurFrame()) > s->missedAnimation)
|
||||
return;
|
||||
_background->decoder->pauseVideo(true);
|
||||
int territory = getTerritory(_currentLevel);
|
||||
Filename path;
|
||||
if (territory <= 2)
|
||||
path = "misc/alrm_brs.smk";
|
||||
else if (territory <= 4)
|
||||
path = "misc/alrm_mbs.smk";
|
||||
else
|
||||
path = "misc/alrm_c5s.smk";
|
||||
|
||||
disableCursor();
|
||||
MVideo alarmVideo(path, Common::Point(0, 0), false, true, false);
|
||||
runIntro(alarmVideo);
|
||||
|
||||
MVideo warningVideo(_warningAlarmVideos.front(), Common::Point(0, 0), false, true, false);
|
||||
runIntro(warningVideo);
|
||||
_health = 0;
|
||||
return;
|
||||
} else if (s->direction > 0) {
|
||||
char selected = selectDirection();
|
||||
defaultCursor();
|
||||
|
||||
if (selected == s->direction) {
|
||||
int missedAnimation = s->missedAnimation;
|
||||
debugC(1, kHypnoDebugArcade, "Jumping to: %d", missedAnimation);
|
||||
_background->decoder->forceSeekToFrame(missedAnimation);
|
||||
_masks->decoder->forceSeekToFrame(missedAnimation);
|
||||
} else {
|
||||
_background->decoder->forceSeekToFrame(s->explosionFrames[0].start - 3);
|
||||
_masks->decoder->forceSeekToFrame(s->explosionFrames[0].start - 3);
|
||||
|
||||
if (s->jumpToTimeAfterKilled == -1000) {
|
||||
ArcadeTransition at("", 0, "", 0, s->explosionFrames[0].lastFrame() - 1);
|
||||
at.loseLevel = true;
|
||||
_transitions.push_front(at);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (s->missedAnimation == 0) {
|
||||
return;
|
||||
} else if (s->missedAnimation == uint32(-1)) {
|
||||
debugC(1, kHypnoDebugArcade, "Jumping to end of level");
|
||||
_skipLevel = true;
|
||||
} else if (s->missedAnimation == uint32(-1000)) {
|
||||
if (_background->decoder->getCurFrame() > int(s->explosionFrames[0].start))
|
||||
return; // Too late for this
|
||||
_health = 0;
|
||||
} else {
|
||||
int missedAnimation = s->missedAnimation;
|
||||
if (missedAnimation + 3 > int(_background->decoder->getFrameCount()) - 1) {
|
||||
_skipLevel = true;
|
||||
return;
|
||||
}
|
||||
if (_background->decoder->getCurFrame() > missedAnimation)
|
||||
return; // Too late for this
|
||||
debugC(1, kHypnoDebugArcade, "Jumping to: %d", missedAnimation);
|
||||
_background->decoder->forceSeekToFrame(missedAnimation);
|
||||
_masks->decoder->forceSeekToFrame(missedAnimation);
|
||||
}
|
||||
|
||||
if (s->attackFrames.size() > 0 && s->attackFrames.front() == 0)
|
||||
return;
|
||||
|
||||
if (!s->nonHostile)
|
||||
hitPlayer();
|
||||
}
|
||||
|
||||
bool BoyzEngine::checkCup(const Common::String &name) {
|
||||
if (name == "CUP1") {
|
||||
if (_background->path == "c3/c35c01s.smk") {
|
||||
MVideo video("c3/c35c07s.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
_skipLevel = true;
|
||||
_sceneState["GS_WONSHELLGAME"] = 1;
|
||||
} else {
|
||||
MVideo video("c3/c35c06s.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
_health = 0;
|
||||
}
|
||||
return true;
|
||||
} else if (name == "CUP2") {
|
||||
if (_background->path == "c3/c35c02s.smk") {
|
||||
MVideo video("c3/c35c07s.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
_skipLevel = true;
|
||||
_sceneState["GS_WONSHELLGAME"] = 1;
|
||||
} else {
|
||||
MVideo video("c3/c35c06s.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
_health = 0;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool BoyzEngine::clickedSecondaryShoot(const Common::Point &mousePos) {
|
||||
if (_currentMode == NonInteractive) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::Rect ammoBarBox(320 - _ammoBar[_currentActor].w, 0, 320, _ammoBar[_currentActor].h);
|
||||
if (ammoBarBox.contains(mousePos)) {
|
||||
_ammo = _weaponMaxAmmo[_currentWeapon];
|
||||
playSound(_soundPath + _weaponReloadSound[_currentWeapon], 1);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Hypno
|
||||
1142
engines/hypno/boyz/boyz.cpp
Normal file
1142
engines/hypno/boyz/boyz.cpp
Normal file
File diff suppressed because it is too large
Load Diff
521
engines/hypno/boyz/hard.cpp
Normal file
521
engines/hypno/boyz/hard.cpp
Normal file
@@ -0,0 +1,521 @@
|
||||
/* 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/bitarray.h"
|
||||
#include "gui/message.h"
|
||||
#include "common/events.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
void BoyzEngine::runCode(Code *code) {
|
||||
if (code->name == "<main_menu>")
|
||||
runMainMenu(code);
|
||||
else if (code->name == "<difficulty_menu>")
|
||||
runDifficultyMenu(code);
|
||||
else if (code->name == "<retry_menu>")
|
||||
runRetryMenu(code);
|
||||
else if (code->name == "<check_c3>")
|
||||
runCheckC3(code);
|
||||
else if (code->name == "<check_ho>")
|
||||
runCheckHo(code);
|
||||
else if (code->name == "<check_c5>")
|
||||
runCheckC5(code);
|
||||
else if (code->name == "<alarm_c5>")
|
||||
runAlarmC5(code);
|
||||
else if (code->name == "<credits>")
|
||||
endCredits(code);
|
||||
else
|
||||
error("invalid hardcoded level: %s", code->name.c_str());
|
||||
}
|
||||
|
||||
void BoyzEngine::runMainMenu(Code *code) {
|
||||
resetSceneState();
|
||||
resetStatistics();
|
||||
_globalStats = ArcadeStats();
|
||||
_flashbackMode = false;
|
||||
|
||||
Common::Event event;
|
||||
byte *palette;
|
||||
Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 0, &palette);
|
||||
loadPalette(palette, 0, 256);
|
||||
free(palette);
|
||||
|
||||
drawImage(*menu, 0, 0, false);
|
||||
_name.clear();
|
||||
bool cont = true;
|
||||
uint32 c = kHypnoColorWhiteOrBlue; // white
|
||||
uint32 posY = 105;
|
||||
Common::StringArray profiles = listProfiles();
|
||||
for (Common::StringArray::iterator it = profiles.begin(); it != profiles.end(); ++it) {
|
||||
drawString("block05.fgx", *it, 130, posY, 170, c);
|
||||
posY = posY + 10;
|
||||
if (posY >= 185)
|
||||
break;
|
||||
}
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
|
||||
while (!shouldQuit() && cont) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
// 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_BACKSPACE)
|
||||
_name.deleteLastChar();
|
||||
else if (event.kbd.keycode == Common::KEYCODE_RETURN && !_name.empty()) {
|
||||
cont = false;
|
||||
} else if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
|
||||
if (runExitMenu())
|
||||
quitGame();
|
||||
disableCursor();
|
||||
}
|
||||
|
||||
else if (Common::isAlpha(event.kbd.keycode)) {
|
||||
playSound("sound/m_choice.raw", 1);
|
||||
_name = _name + char(event.kbd.keycode - 32);
|
||||
}
|
||||
|
||||
drawImage(*menu, 0, 0, false);
|
||||
drawString("block05.fgx", _name, 130, 58, 170, c);
|
||||
posY = 105;
|
||||
for (Common::StringArray::iterator it = profiles.begin(); it != profiles.end(); ++it) {
|
||||
drawString("block05.fgx", *it, 130, posY, 170, c);
|
||||
posY = posY + 10;
|
||||
if (posY >= 185)
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
menu->free();
|
||||
delete menu;
|
||||
|
||||
if (shouldQuit())
|
||||
return;
|
||||
|
||||
_name.toLowercase();
|
||||
bool found = loadProfile(_name);
|
||||
if (!found) {
|
||||
_nextLevel = code->levelIfWin;
|
||||
} else if (_unlockAllLevels) {
|
||||
_nextLevel = "<select_t1>";
|
||||
unlockAllLevels();
|
||||
_flashbackMode = true;
|
||||
}
|
||||
|
||||
assert(!_nextLevel.empty());
|
||||
|
||||
}
|
||||
|
||||
bool BoyzEngine::runExitMenu() {
|
||||
changeCursor("crosshair");
|
||||
bool quit = false;
|
||||
Common::Event event;
|
||||
byte *palette;
|
||||
Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 8, &palette);
|
||||
loadPalette(palette, 0, 256);
|
||||
free(palette);
|
||||
drawImage(*menu, 0, 0, false);
|
||||
Common::Rect yesBox(142, 87, 179, 102);
|
||||
Common::Rect noBox(142, 104, 179, 119);
|
||||
bool cont = true;
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("exit-menu")->setEnabled(true);
|
||||
while (!shouldQuit() && cont) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
Common::Point mousePos = g_system->getEventManager()->getMousePos();
|
||||
// Events
|
||||
switch (event.type) {
|
||||
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType == kActionYes) {
|
||||
quit = true;
|
||||
cont = false;
|
||||
|
||||
} else if (event.customType == kActionNo) {
|
||||
quit = false;
|
||||
cont = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (yesBox.contains(mousePos)) {
|
||||
quit = true;
|
||||
cont = false;
|
||||
break;
|
||||
} else if (noBox.contains(mousePos)) {
|
||||
quit = false;
|
||||
cont = false;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
keymapper->getKeymap("exit-menu")->setEnabled(false);
|
||||
menu->free();
|
||||
delete menu;
|
||||
return quit;
|
||||
}
|
||||
|
||||
void BoyzEngine::runDifficultyMenu(Code *code) {
|
||||
changeCursor("crosshair");
|
||||
_difficulty.clear();
|
||||
Common::Rect chumpBox(121, 62, 199, 77);
|
||||
Common::Rect punkBox(121, 81, 199, 96);
|
||||
Common::Rect badAssBox(121, 100, 199, 115);
|
||||
Common::Rect cancelBox(121, 138, 245, 153);
|
||||
|
||||
Common::Event event;
|
||||
Common::Point mousePos;
|
||||
byte *palette;
|
||||
Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 1, &palette);
|
||||
loadPalette(palette, 0, 256);
|
||||
free(palette);
|
||||
drawImage(*menu, 0, 0, false);
|
||||
bool cont = true;
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
keymapper->getKeymap("difficulty-menu")->setEnabled(true);
|
||||
while (!shouldQuit() && cont) {
|
||||
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_LBUTTONDOWN:
|
||||
if (chumpBox.contains(mousePos)) {
|
||||
_difficulty = "chump";
|
||||
cont = false;
|
||||
} else if (punkBox.contains(mousePos)) {
|
||||
_difficulty = "punk";
|
||||
cont = false;
|
||||
} else if (badAssBox.contains(mousePos)) {
|
||||
_difficulty = "bad ass";
|
||||
cont = false;
|
||||
} else if (cancelBox.contains(mousePos)) {
|
||||
cont = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType == kActionDifficultyChump) {
|
||||
_difficulty = "chump";
|
||||
cont = false;
|
||||
} else if (event.customType == kActionDifficultyPunk) {
|
||||
_difficulty = "punk";
|
||||
cont = false;
|
||||
} else if (event.customType == kActionDifficultyBadass) {
|
||||
_difficulty = "bad ass";
|
||||
cont = false;
|
||||
} else if (event.customType == kActionDifficultExit) {
|
||||
cont = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
keymapper->getKeymap("difficulty-menu")->setEnabled(false);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
|
||||
if (_difficulty.empty())
|
||||
_nextLevel = "<main_menu>";
|
||||
else {
|
||||
saveProfile(_name, 0);
|
||||
if (_unlockAllLevels) {
|
||||
_nextLevel = "<select_t1>";
|
||||
unlockAllLevels();
|
||||
_flashbackMode = true;
|
||||
} else
|
||||
_nextLevel = code->levelIfWin;
|
||||
}
|
||||
|
||||
menu->free();
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void BoyzEngine::runRetryMenu(Code *code) {
|
||||
incLivesUsed();
|
||||
uint32 idx = _rnd->getRandomNumber(_deathVideo.size() - 1);
|
||||
Filename filename = _deathVideo[idx];
|
||||
MVideo video(filename, Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
changeCursor("crosshair");
|
||||
|
||||
Common::Rect retryMissionBox(73, 62, 245, 77);
|
||||
Common::Rect restartTerritoryBox(73, 81, 245, 96);
|
||||
Common::Rect restartMissionBox(73, 100, 245, 114);
|
||||
Common::Rect quitBox(73, 119, 245, 133);
|
||||
|
||||
Common::Event event;
|
||||
Common::Point mousePos;
|
||||
byte *palette;
|
||||
Graphics::Surface *menu = decodeFrame("preload/mainmenu.smk", 5, &palette);
|
||||
loadPalette(palette, 0, 256);
|
||||
free(palette);
|
||||
drawImage(*menu, 0, 0, false);
|
||||
bool cont = true;
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
keymapper->getKeymap("retry-menu")->setEnabled(true);
|
||||
while (!shouldQuit() && cont) {
|
||||
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_LBUTTONDOWN:
|
||||
if (retryMissionBox.contains(mousePos)) {
|
||||
_nextLevel = _checkpoint;
|
||||
cont = false;
|
||||
} else if (restartTerritoryBox.contains(mousePos)) {
|
||||
// Restore initial health for the team
|
||||
_health = _maxHealth;
|
||||
_stats = _globalStats;
|
||||
_nextLevel = firstLevelTerritory(_checkpoint);
|
||||
cont = false;
|
||||
} else if (restartMissionBox.contains(mousePos)) {
|
||||
_nextLevel = "<main_menu>";
|
||||
cont = false;
|
||||
} else if (quitBox.contains(mousePos))
|
||||
quitGame();
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType == kActionRetry) {
|
||||
_nextLevel = _checkpoint;
|
||||
cont = false;
|
||||
} else if (event.customType == kActionNewMission) {
|
||||
_nextLevel = "<main_menu>";
|
||||
cont = false;
|
||||
} else if (event.customType == kActionRestart) {
|
||||
// Restore initial health for the team
|
||||
_health = _maxHealth;
|
||||
_stats = _globalStats;
|
||||
_nextLevel = firstLevelTerritory(_checkpoint);
|
||||
cont = false;
|
||||
} else if (event.customType == kActionQuit)
|
||||
quitGame();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
keymapper->getKeymap("retry-menu")->setEnabled(false);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
|
||||
menu->free();
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void BoyzEngine::runAlarmC5(Code *code) {
|
||||
MVideo video1("misc/alrm_c5s.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video1);
|
||||
|
||||
MVideo video2("preload/deathn4s.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video2);
|
||||
|
||||
_nextLevel = "<check_c5>";
|
||||
}
|
||||
|
||||
|
||||
void BoyzEngine::runCheckC5(Code *code) {
|
||||
if (_sceneState["GS_C5MAP"]) {
|
||||
if (!_sceneState["GS_MINEMAP_VIEWED"]) {
|
||||
MVideo video("c5/c5_maps.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
defaultCursor();
|
||||
waitForUserClick(1);
|
||||
_sceneState["GS_MINEMAP_VIEWED"] = true;
|
||||
}
|
||||
}
|
||||
|
||||
Common::String nextLevel;
|
||||
if (_sceneState["GS_SEQ_51"] &&
|
||||
_sceneState["GS_SEQ_52"] &&\
|
||||
_sceneState["GS_SEQ_53"]) {
|
||||
MVideo video("c5/c5intrbs.smk", Common::Point(0, 0), false, true, false);
|
||||
disableCursor();
|
||||
runIntro(video);
|
||||
nextLevel = "c54.mi_";
|
||||
}
|
||||
|
||||
if (nextLevel.empty())
|
||||
nextLevel = "<select_c5>";
|
||||
|
||||
_nextLevel = nextLevel;
|
||||
saveProfile(_name, 531);
|
||||
}
|
||||
|
||||
|
||||
void BoyzEngine::runCheckC3(Code *code) {
|
||||
Common::String nextLevel;
|
||||
if (_sceneState["GS_SEQ_31"] && _sceneState["GS_SEQ_32"] &&\
|
||||
_sceneState["GS_SEQ_33"] && _sceneState["GS_SEQ_34"] &&\
|
||||
_sceneState["GS_HOTELDONE"]) {
|
||||
nextLevel = "c36.mi_";
|
||||
}
|
||||
|
||||
if (nextLevel.empty())
|
||||
nextLevel = "<select_c3>";
|
||||
|
||||
_nextLevel = nextLevel;
|
||||
saveProfile(_name, 3591);
|
||||
}
|
||||
|
||||
void BoyzEngine::runCheckHo(Code *code) {
|
||||
Common::String nextLevel;
|
||||
if (_sceneState["GS_SEQ_351"] && _sceneState["GS_SEQ_352"] &&\
|
||||
_sceneState["GS_SEQ_353"] && _sceneState["GS_SEQ_354"] &&\
|
||||
_sceneState["GS_SEQ_355"]) {
|
||||
_sceneState["GS_HOTELDONE"] = 1;
|
||||
nextLevel = "<check_c3>";
|
||||
}
|
||||
|
||||
if (nextLevel.empty())
|
||||
nextLevel = "<select_ho>";
|
||||
|
||||
_nextLevel = nextLevel;
|
||||
saveProfile(_name, 3592);
|
||||
}
|
||||
|
||||
void BoyzEngine::endCredits(Code *code) {
|
||||
_flashbackMode = true;
|
||||
saveProfile(_name, 59);
|
||||
showCredits();
|
||||
_nextLevel = "<select_t1>";
|
||||
}
|
||||
|
||||
void BoyzEngine::showCredits() {
|
||||
MVideo c1("intro/sbcred1.smk", Common::Point(0, 0), false, true, false);
|
||||
runIntro(c1);
|
||||
MVideo c2("intro/sbcred2.smk", Common::Point(0, 0), false, true, false);
|
||||
runIntro(c2);
|
||||
}
|
||||
|
||||
int BoyzEngine::getTerritory(const Common::String &level) {
|
||||
if (Common::matchString(level.c_str(), "c1#.mi_"))
|
||||
return 1;
|
||||
else if (Common::matchString(level.c_str(), "c2#.mi_"))
|
||||
return 2;
|
||||
else if (Common::matchString(level.c_str(), "c3#.mi_"))
|
||||
return 3;
|
||||
else if (Common::matchString(level.c_str(), "c3##.mi_"))
|
||||
return 3;
|
||||
else if (Common::matchString(level.c_str(), "c4#.mi_"))
|
||||
return 4;
|
||||
else if (Common::matchString(level.c_str(), "c5#.mi_"))
|
||||
return 5;
|
||||
else
|
||||
error("Invalid territory for level %s", level.c_str());
|
||||
}
|
||||
|
||||
Common::String BoyzEngine::firstLevelTerritory(const Common::String &level) {
|
||||
if (Common::matchString(level.c_str(), "c1#.mi_"))
|
||||
return "c19.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c2#.mi_"))
|
||||
return "c21.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c3#.mi_"))
|
||||
return "c31.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c3##.mi_"))
|
||||
return "c31.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c4#.mi_"))
|
||||
return "c41.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c5#.mi_"))
|
||||
return "c51.mi_";
|
||||
else
|
||||
error("Invalid territory for level %s", level.c_str());
|
||||
}
|
||||
|
||||
Common::String BoyzEngine::lastLevelTerritory(const Common::String &level) {
|
||||
if (Common::matchString(level.c_str(), "c1#.mi_"))
|
||||
return "c18.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c2#.mi_"))
|
||||
return "c22.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c3#.mi_"))
|
||||
return "c38.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c3##.mi_"))
|
||||
return "c38.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c4#.mi_"))
|
||||
return "c42.mi_";
|
||||
else if (Common::matchString(level.c_str(), "c5#.mi_"))
|
||||
return "c59.mi_";
|
||||
else
|
||||
error("Invalid territory for level %s", level.c_str());
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
208
engines/hypno/boyz/scene.cpp
Normal file
208
engines/hypno/boyz/scene.cpp
Normal file
@@ -0,0 +1,208 @@
|
||||
/* 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/events.h"
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
const char *sceneVariablesBoyz[] = {
|
||||
"GS_NONE",
|
||||
"GS_SCTEXT",
|
||||
"GS_AMBIENT",
|
||||
"GS_MUSIC",
|
||||
"GS_VOLUME",
|
||||
"GS_LEVELCOMPLETE",
|
||||
"GS_LEVELWON",
|
||||
"GS_HOLDMOUSE",
|
||||
"GS_DIFFICULTY",
|
||||
"GS_TERRITORY",
|
||||
"GS_SECTOR",
|
||||
"GS_HITPOINTS",
|
||||
"GS_TERRITORY1_RAND",
|
||||
"GS_C5MAP",
|
||||
"GS_WONSHELLGAME",
|
||||
"GS_C36_READY",
|
||||
"GS_MINEMAP",
|
||||
"GS_MINEMAP_VIEWED",
|
||||
"GS_HOTELDONE",
|
||||
"GS_SWITCH0",
|
||||
"GS_SWITCH1",
|
||||
"GS_SWITCH2",
|
||||
"GS_SWITCH3",
|
||||
"GS_SWITCH4",
|
||||
"GS_SWITCH5",
|
||||
"GS_SWITCH6",
|
||||
"GS_SWITCH7",
|
||||
"GS_SWITCH8",
|
||||
"GS_SWITCH9",
|
||||
"GS_SWITCH10",
|
||||
"GS_SWITCH11",
|
||||
"GS_SWITCH12",
|
||||
"GS_SEQ_11",
|
||||
"GS_SEQ_12",
|
||||
"GS_SEQ_13",
|
||||
"GS_SEQ_14",
|
||||
"GS_SEQ_15",
|
||||
"GS_SEQ_16",
|
||||
"GS_SEQ_17",
|
||||
"GS_SEQ_18",
|
||||
"GS_SEQ_19",
|
||||
"GS_SEQ_21",
|
||||
"GS_SEQ_22",
|
||||
"GS_SEQ_31",
|
||||
"GS_SEQ_32",
|
||||
"GS_SEQ_33",
|
||||
"GS_SEQ_34",
|
||||
"GS_SEQ_35",
|
||||
"GS_SEQ_351",
|
||||
"GS_SEQ_352",
|
||||
"GS_SEQ_353",
|
||||
"GS_SEQ_354",
|
||||
"GS_SEQ_355",
|
||||
"GS_SEQ_36",
|
||||
"GS_SEQ_41",
|
||||
"GS_SEQ_42",
|
||||
"GS_SEQ_51",
|
||||
"GS_SEQ_52",
|
||||
"GS_SEQ_53",
|
||||
"GS_SEQ_54",
|
||||
"GS_SEQ_55",
|
||||
"GS_SEQ_56",
|
||||
"GS_SEQ_57",
|
||||
"GS_SEQ_58",
|
||||
"GS_SEQ_59",
|
||||
nullptr
|
||||
};
|
||||
|
||||
void BoyzEngine::resetSceneState() {
|
||||
uint32 i = 0;
|
||||
while (sceneVariablesBoyz[i]) {
|
||||
_sceneState[sceneVariablesBoyz[i]] = 0;
|
||||
i++;
|
||||
}
|
||||
_intros.clear();
|
||||
}
|
||||
|
||||
void BoyzEngine::loadSceneState(Common::SeekableReadStream *stream) {
|
||||
uint32 i = 0;
|
||||
while (sceneVariablesBoyz[i]) {
|
||||
_sceneState[sceneVariablesBoyz[i]] = stream->readUint32LE();
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void BoyzEngine::saveSceneState(Common::WriteStream *stream) {
|
||||
uint32 i = 0;
|
||||
while (sceneVariablesBoyz[i]) {
|
||||
stream->writeUint32LE(_sceneState[sceneVariablesBoyz[i]]);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void BoyzEngine::unlockAllLevels() {
|
||||
uint32 i = 0;
|
||||
while (sceneVariablesBoyz[i]) {
|
||||
if (Common::String(sceneVariablesBoyz[i]).hasPrefix("GS_SEQ_"))
|
||||
_sceneState[sceneVariablesBoyz[i]] = true;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void BoyzEngine::runMenu(Hotspots *hs, bool only_menu) {
|
||||
Hotspot *h = hs->begin();
|
||||
assert(h->type == MakeMenu);
|
||||
if (!h->background.empty()) {
|
||||
loadImage(h->background, 0, 0, false, true, 1);
|
||||
if (h->backgroundFrames.empty()) {
|
||||
h->backgroundFrames = decodeFrames(h->background);
|
||||
}
|
||||
}
|
||||
renderHighlights(hs);
|
||||
}
|
||||
|
||||
void BoyzEngine::renderHighlights(Hotspots *hs) {
|
||||
Hotspot *menu = hs->begin();
|
||||
if (menu->type != MakeMenu || menu->background.empty())
|
||||
return;
|
||||
|
||||
for (Hotspots::const_iterator it = hs->begin(); it != hs->end(); ++it) {
|
||||
if (it->type == MakeMenu)
|
||||
continue;
|
||||
|
||||
Highlight *hl;
|
||||
for (Actions::const_iterator itt = it->actions.begin(); itt != it->actions.end(); ++itt) {
|
||||
Action *action = *itt;
|
||||
switch (action->type) {
|
||||
case HighlightAction:
|
||||
hl = (Highlight *)action;
|
||||
assert(_sceneState.contains(hl->condition));
|
||||
if (_sceneState[hl->condition]) {
|
||||
Graphics::Surface sub = menu->backgroundFrames[0]->getSubArea(it->rect);
|
||||
drawImage(sub, it->rect.left, it->rect.top, false);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool BoyzEngine::hoverHotspot(Common::Point mousePos) {
|
||||
if (_rnd->getRandomBit())
|
||||
return false; // Dirty trick to avoid updating the screen too often
|
||||
Hotspots *hots = stack.back();
|
||||
Hotspot selected(MakeHotspot);
|
||||
bool found = false;
|
||||
int rs = 100000000;
|
||||
for (Hotspots::const_iterator it = hots->begin(); it != hots->end(); ++it) {
|
||||
const Hotspot h = *it;
|
||||
if (h.type != MakeHotspot)
|
||||
continue;
|
||||
|
||||
int cs = h.rect.width() * h.rect.height();
|
||||
if (h.rect.contains(mousePos)) {
|
||||
if (cs < rs) {
|
||||
selected = h;
|
||||
found = true;
|
||||
rs = cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
Hotspot *menu = hots->begin();
|
||||
if (menu->type == MakeMenu && !menu->background.empty()) { // Hihghlight
|
||||
Graphics::Surface sub = menu->backgroundFrames[2]->getSubArea(selected.rect);
|
||||
drawImage(*menu->backgroundFrames[1], 0, 0, false);
|
||||
renderHighlights(hots);
|
||||
drawImage(sub, selected.rect.left, selected.rect.top, false);
|
||||
drawScreen();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
3
engines/hypno/configure.engine
Normal file
3
engines/hypno/configure.engine
Normal file
@@ -0,0 +1,3 @@
|
||||
# This file is included from the main "configure" script
|
||||
# add_engine [name] [desc] [build-by-default] [subengines] [base games] [deps] [components]
|
||||
add_engine hypno "Hypnotix Inc." yes "" "" ""
|
||||
3
engines/hypno/credits.pl
Normal file
3
engines/hypno/credits.pl
Normal file
@@ -0,0 +1,3 @@
|
||||
begin_section("Hypno");
|
||||
add_person("Gustavo Grieco", "neuromancer", "");
|
||||
end_section();
|
||||
193
engines/hypno/cursors.cpp
Normal file
193
engines/hypno/cursors.cpp
Normal file
@@ -0,0 +1,193 @@
|
||||
/* 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/rect.h"
|
||||
#include "graphics/cursorman.h"
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
static const byte MOUSECURSOR_SCI[] = {
|
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 1, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 1, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
|
||||
1, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0,
|
||||
1, 3, 1, 0, 1, 3, 3, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 1, 3, 3, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0};
|
||||
|
||||
static const byte circleCursor[] = {
|
||||
0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0,
|
||||
0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0,
|
||||
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
|
||||
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
|
||||
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
|
||||
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
|
||||
2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
|
||||
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
|
||||
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
|
||||
0, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 0, 0,
|
||||
0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0};
|
||||
|
||||
static const byte targetCursor[] = {
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0,
|
||||
0, 0, 1, 0, 0, 2, 2, 2, 2, 2, 0, 0, 1, 0, 0,
|
||||
0, 1, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0,
|
||||
1, 0, 2, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 1,
|
||||
1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 1,
|
||||
1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1,
|
||||
1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1,
|
||||
1, 2, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 2, 1,
|
||||
1, 0, 2, 0, 1, 0, 0, 0, 0, 0, 1, 0, 2, 0, 1,
|
||||
1, 0, 2, 0, 0, 1, 1, 1, 1, 1, 0, 0, 2, 0, 1,
|
||||
0, 1, 0, 2, 2, 0, 0, 0, 0, 0, 2, 2, 0, 1, 0,
|
||||
0, 0, 1, 0, 0, 2, 2, 2, 2, 2, 0, 0, 1, 0, 0,
|
||||
0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0};
|
||||
|
||||
static const byte crosshairCursor[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0,
|
||||
0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
|
||||
0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
|
||||
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
|
||||
2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2,
|
||||
0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0,
|
||||
0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
|
||||
0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0,
|
||||
0, 0, 0, 2, 2, 0, 0, 2, 0, 0, 2, 2, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
static const byte cursorPalette[] = {
|
||||
0x00, 0x00, 0x00, // Transparent
|
||||
0x00, 0x00, 0xff, // Blue
|
||||
0xff, 0x00, 0x00, // Red
|
||||
0xff, 0xff, 0xff // White
|
||||
};
|
||||
|
||||
static const byte sciCursorPalette[] = {
|
||||
0x00, 0x00, 0x00, // Transparent
|
||||
0xff, 0xff, 0xff, // Black
|
||||
0xff, 0x00, 0x00, // Red
|
||||
0xff, 0xff, 0xff // White
|
||||
};
|
||||
|
||||
struct CursorTable {
|
||||
const char *name;
|
||||
const void *buf;
|
||||
int w;
|
||||
int h;
|
||||
int hotspotX;
|
||||
int hotspotY;
|
||||
};
|
||||
|
||||
static const CursorTable cursorTable[] = {
|
||||
{"default", MOUSECURSOR_SCI, 11, 16, 0, 0},
|
||||
{"arcade", circleCursor, 13, 11, 7, 5},
|
||||
{"target", targetCursor, 15, 13, 8, 6},
|
||||
{"crosshair", crosshairCursor, 15, 13, 8, 6},
|
||||
{nullptr, nullptr, 0, 0, 0, 0}};
|
||||
|
||||
void HypnoEngine::disableCursor() {
|
||||
CursorMan.showMouse(false);
|
||||
}
|
||||
|
||||
void HypnoEngine::defaultCursor() {
|
||||
if (!_defaultCursor.empty()) {
|
||||
if (_defaultCursorIdx == uint32(-1))
|
||||
changeCursor(_defaultCursor);
|
||||
else
|
||||
changeCursor(_defaultCursor, _defaultCursorIdx);
|
||||
} else
|
||||
changeCursor("default");
|
||||
}
|
||||
|
||||
void HypnoEngine::changeCursor(const Common::String &cursor) {
|
||||
const CursorTable *entry = cursorTable;
|
||||
while (entry->name) {
|
||||
if (cursor == entry->name)
|
||||
break;
|
||||
entry++;
|
||||
}
|
||||
assert(entry->name);
|
||||
|
||||
if (cursor == "default")
|
||||
CursorMan.replaceCursorPalette(sciCursorPalette, 0, 3);
|
||||
else
|
||||
CursorMan.replaceCursorPalette(cursorPalette, 0, 3);
|
||||
CursorMan.replaceCursor(entry->buf, entry->w, entry->h, entry->hotspotX, entry->hotspotY, 0);
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
Graphics::Surface *CursorCache::getCursor(const Common::String &cursor, uint32 n, byte **palette) {
|
||||
if (cursor == _filename && n == _frame) {
|
||||
*palette = _palette;
|
||||
return _surface;
|
||||
}
|
||||
|
||||
free(_palette);
|
||||
_palette = nullptr;
|
||||
|
||||
if (_surface) {
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
_surface = nullptr;
|
||||
}
|
||||
|
||||
_filename = cursor;
|
||||
_frame = n;
|
||||
_surface = _vm->decodeFrame(cursor, n, &_palette);
|
||||
*palette = _palette;
|
||||
return _surface;
|
||||
}
|
||||
|
||||
void HypnoEngine::changeCursor(const Common::String &cursor, uint32 n, bool centerCursor) {
|
||||
byte *palette;
|
||||
Graphics::Surface *entry = _cursorCache->getCursor(cursor, n, &palette);
|
||||
uint32 hotspotX = centerCursor ? entry->w / 2 : 0;
|
||||
uint32 hotspotY = centerCursor ? entry->h / 2 : 0;
|
||||
CursorMan.replaceCursor(*entry, hotspotX, hotspotY, 0, false);
|
||||
CursorMan.replaceCursorPalette(palette, 0, 256);
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
void HypnoEngine::changeCursor(const Graphics::Surface &entry, byte *palette, bool centerCursor) {
|
||||
uint32 hotspotX = centerCursor ? entry.w / 2 : 0;
|
||||
uint32 hotspotY = centerCursor ? entry.h / 2 : 0;
|
||||
CursorMan.replaceCursor(entry, hotspotX, hotspotY, 0, false);
|
||||
CursorMan.replaceCursorPalette(palette, 0, 256);
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
322
engines/hypno/detection.cpp
Normal file
322
engines/hypno/detection.cpp
Normal file
@@ -0,0 +1,322 @@
|
||||
/* 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 "base/plugins.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "hypno/hypno.h"
|
||||
#include "hypno/detection.h"
|
||||
|
||||
static const DebugChannelDef debugFlagList[] = {
|
||||
{Hypno::kHypnoDebugMedia, "media", "Media debug channel"},
|
||||
{Hypno::kHypnoDebugParser, "parser", "Parser debug channel"},
|
||||
{Hypno::kHypnoDebugScene, "scene", "Scene debug channel"},
|
||||
{Hypno::kHypnoDebugArcade, "arcade", "Arcade debug channel"},
|
||||
DEBUG_CHANNEL_END};
|
||||
|
||||
namespace Hypno {
|
||||
static const PlainGameDescriptor hypnoGames[] = {
|
||||
{"sinistersix", "Marvel Comics Spider-Man: The Sinister Six"},
|
||||
{"wetlands", "Wetlands"},
|
||||
{"soldierboyz", "Soldier Boyz"},
|
||||
{"teacher", "Bruce Coville's My Teacher Is an Alien"},
|
||||
{nullptr, nullptr}};
|
||||
|
||||
static const ADGameDescription gameDescriptions[] = {
|
||||
{
|
||||
"sinistersix", // Demo from the US release
|
||||
"Demo",
|
||||
AD_ENTRY2s("DATA.Z", "2a9c7cf8920ec794482f0a5873102da5", 1285960,
|
||||
"DCINE1.SMK", "1ff3db09d148e8dd8b56d2e87e7296b8", 493752),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"sinistersix", // US release
|
||||
nullptr,
|
||||
AD_ENTRY2s("DATA.Z", "a1f71005a45e6ee454bb0bf3868dff54", 8766307,
|
||||
"MISSIONS.LIB", "585704e26094cbaf14fbee90798e8d5d", 119945),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"sinistersix", // ES release
|
||||
nullptr,
|
||||
AD_ENTRY2s("SPIDER.EXE", "dbd912d6f6724c6d44775fc19cfa8ca0", 483871,
|
||||
"MISSIONS.LIB", "585704e26094cbaf14fbee90798e8d5d", 119945),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"sinistersix", // DE release
|
||||
nullptr,
|
||||
AD_ENTRY2s("Setup1.Sax", "86b6ae45f45a8273ef3116be6bac01f5", 9591164,
|
||||
"MISSIONS.LIB", "585704e26094cbaf14fbee90798e8d5d", 119945),
|
||||
Common::DE_DEU,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"sinistersix", // IT release
|
||||
nullptr,
|
||||
AD_ENTRY2s("DATA.Z", "8e1aa1ab39e38c4f1bf67c0b330b3991", 8740866,
|
||||
"MISSIONS.LIB", "585704e26094cbaf14fbee90798e8d5d", 119945),
|
||||
Common::IT_ITA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"sinistersix", // HE release (CD, Installed)
|
||||
nullptr,
|
||||
AD_ENTRY2s("SPIDER.EXE", "dbd912d6f6724c6d44775fc19cfa8ca0", 483359,
|
||||
"MISSIONS.LIB", "585704e26094cbaf14fbee90798e8d5d", 119945),
|
||||
Common::HE_ISR,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"sinistersix", // HE release (CD, Not Installed)
|
||||
nullptr,
|
||||
AD_ENTRY2s("DATA.Z", "5068f15089ac05556c2f3f37e06c4f32", 8921748,
|
||||
"MISSIONS.LIB", "585704e26094cbaf14fbee90798e8d5d", 119945),
|
||||
Common::HE_ISR,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_UNSTABLE,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands Demo PC Spiel (October 1995)
|
||||
"EarlyDemo",
|
||||
AD_ENTRY2s("wetlands.exe", "edc5b0c0caf3d5b01d344cb555d9a085", 641411,
|
||||
"c61.mis", "11e384b3abe0f42995bb61566d877e45", 18497),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands Demo Disc (November 1995)
|
||||
"Demo",
|
||||
AD_ENTRY3s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 642231,
|
||||
"wetdemo.exe", "15a6b1b3819ef002438df340509b5373", 458319,
|
||||
"demo.exe", "15a6b1b3819ef002438df340509b5373", 533221),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands Demo from a Hebrew magazine
|
||||
"DemoHebrew",
|
||||
AD_ENTRY3s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 629503,
|
||||
"wetdemo.exe", "15a6b1b3819ef002438df340509b5373", 458319,
|
||||
"demo.exe", "15a6b1b3819ef002438df340509b5373", 533221),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Personal Computer World (UK) (May 1996) - Chapter 11 demo
|
||||
"PCWDemo",
|
||||
AD_ENTRY2s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 553355,
|
||||
"missions.lib", "6ffa658f22a00b6e17d7f920fcc13578", 12469),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // PC Gamer Disc 12 (November 1995) - Chapter 31 demo
|
||||
"PCGDemo",
|
||||
AD_ENTRY2s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 553355,
|
||||
"missions.lib", "34b922fac8f64546c0690aa83f09e98e", 40891),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Génération 4 (FR) - Number 81 (October 1995) - Chapters 31/52 demo
|
||||
"Gen4",
|
||||
AD_ENTRY2s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 629503,
|
||||
"missions.lib", "34b922fac8f64546c0690aa83f09e98e", 40891),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Might and Magic Trilogy CD (November 1995) - Chapters 31/52 demo
|
||||
"M&MCD",
|
||||
AD_ENTRY2s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 642231,
|
||||
"missions.lib", "7e3e5b23ade5ef0df88e9d31f5d669e6", 10188),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Non Interactive: PC Review 49 (November 1995)
|
||||
"NonInteractive",
|
||||
AD_ENTRY2s("playsmks.exe", "edc5b0c0caf3d5b01d344cb555d9a085", 422607,
|
||||
"wetmusic.81m", "0d99c63ce19633d09569b1fdcdff1505", 2833439),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Non Interactive: Joystick HS 7 (September 1995)
|
||||
"NonInteractiveJoystick",
|
||||
AD_ENTRY2s("playsmks.exe", "edc5b0c0caf3d5b01d344cb555d9a085", 422607,
|
||||
"c44_22k.raw", "4b2279af59ce3049cc5177b0047e8447", 5247618),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands (US)
|
||||
nullptr,
|
||||
AD_ENTRY2s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 647447,
|
||||
"missions.lib", "aeaaa8b26ab17e37f060334a311a3ff6", 309793),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands 1.1 (US)
|
||||
nullptr,
|
||||
AD_ENTRY2s("wetlands.exe", "15a6b1b3819ef002438df340509b5373", 647411,
|
||||
"missions.lib", "aeaaa8b26ab17e37f060334a311a3ff6", 309793),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands (FR)
|
||||
nullptr,
|
||||
AD_ENTRY2s("wetlands.exe", "edc5b0c0caf3d5b01d344cb555d9a085", 629575,
|
||||
"missions.lib", "aeaaa8b26ab17e37f060334a311a3ff6", 309793),
|
||||
Common::FR_FRA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands (ES)
|
||||
nullptr,
|
||||
AD_ENTRY2s("wetlands.exe", "8d0f3630523da827bb25e665b7d3f879", 644055,
|
||||
"missions.lib", "aeaaa8b26ab17e37f060334a311a3ff6", 309793),
|
||||
Common::ES_ESP,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"wetlands", // Wetlands (KO)
|
||||
nullptr,
|
||||
AD_ENTRY2s("wetlands.exe", "edc5b0c0caf3d5b01d344cb555d9a085", 360151,
|
||||
"missions.lib", "aeaaa8b26ab17e37f060334a311a3ff6", 309793),
|
||||
Common::KO_KOR,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"soldierboyz", // Solidier Boyz (US)
|
||||
nullptr,
|
||||
AD_ENTRY2s("boyz.exe", "bac1d734f2606dbdd0816dfa7a5cf518", 263347,
|
||||
"setup.exe", "bac1d734f2606dbdd0816dfa7a5cf518", 160740),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformDOS,
|
||||
ADGF_NO_FLAGS,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
{
|
||||
"teacher", // Bruce Coville's My Teacher Is an Alien Demo - PC Collector 10 (July 1997)
|
||||
"Demo",
|
||||
AD_ENTRY2s("teacher.exe", "7650ab104a21e2ca33a1d0d54a51e9d1", 258560,
|
||||
"demomenu.smk", "abb06755ff1d345b11b0f2c2d42e5dc7", 2424),
|
||||
Common::EN_USA,
|
||||
Common::kPlatformWindows,
|
||||
ADGF_UNSTABLE | ADGF_DEMO,
|
||||
GUIO1(GUIO_NOMIDI)
|
||||
},
|
||||
AD_TABLE_END_MARKER
|
||||
};
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
static const char *const directoryGlobs[] = {
|
||||
"boyz",
|
||||
"spider",
|
||||
"wetlands",
|
||||
"sixdemo",
|
||||
"demo",
|
||||
"factory",
|
||||
"movie",
|
||||
"c_misc",
|
||||
"data",
|
||||
"demo",
|
||||
nullptr
|
||||
};
|
||||
|
||||
class HypnoMetaEngineDetection : public AdvancedMetaEngineDetection<ADGameDescription> {
|
||||
public:
|
||||
HypnoMetaEngineDetection() : AdvancedMetaEngineDetection(Hypno::gameDescriptions, Hypno::hypnoGames) {
|
||||
_guiOptions = GUIO6(GUIO_NOMIDI, GAMEOPTION_ORIGINAL_CHEATS, GAMEOPTION_INFINITE_HEALTH, GAMEOPTION_INFINITE_AMMO, GAMEOPTION_UNLOCK_ALL_LEVELS, GAMEOPTION_RESTORED_CONTENT);
|
||||
_maxScanDepth = 3;
|
||||
_directoryGlobs = directoryGlobs;
|
||||
}
|
||||
|
||||
const char *getName() const override {
|
||||
return "hypno";
|
||||
}
|
||||
|
||||
const char *getEngineName() const override {
|
||||
return "Hypno";
|
||||
}
|
||||
|
||||
const char *getOriginalCopyright() const override {
|
||||
return "Marvel Comics Spider-Man: The Sinister Six (C) Brooklyn Multimedia\n"
|
||||
"Wetlands (C) Hypnotix, Inc.\n"
|
||||
"Soldier Boyz (C) Hypnotix, Inc., Motion Picture Corporation of America Interactive";
|
||||
}
|
||||
|
||||
const DebugChannelDef *getDebugChannels() const override {
|
||||
return debugFlagList;
|
||||
}
|
||||
};
|
||||
|
||||
REGISTER_PLUGIN_STATIC(HYPNO_DETECTION, PLUGIN_TYPE_ENGINE_DETECTION, HypnoMetaEngineDetection);
|
||||
|
||||
31
engines/hypno/detection.h
Normal file
31
engines/hypno/detection.h
Normal file
@@ -0,0 +1,31 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HYPNO_DETECTION_H
|
||||
#define HYPNO_DETECTION_H
|
||||
|
||||
#define GAMEOPTION_ORIGINAL_CHEATS GUIO_GAMEOPTIONS1
|
||||
#define GAMEOPTION_INFINITE_HEALTH GUIO_GAMEOPTIONS2
|
||||
#define GAMEOPTION_INFINITE_AMMO GUIO_GAMEOPTIONS3
|
||||
#define GAMEOPTION_UNLOCK_ALL_LEVELS GUIO_GAMEOPTIONS4
|
||||
#define GAMEOPTION_RESTORED_CONTENT GUIO_GAMEOPTIONS5
|
||||
|
||||
#endif
|
||||
770
engines/hypno/grammar.h
Normal file
770
engines/hypno/grammar.h
Normal file
@@ -0,0 +1,770 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HYPNO_GRAMMAR_H
|
||||
#define HYPNO_GRAMMAR_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/hash-ptr.h"
|
||||
#include "common/hash-str.h"
|
||||
#include "common/list.h"
|
||||
#include "common/queue.h"
|
||||
#include "common/rect.h"
|
||||
#include "common/str.h"
|
||||
|
||||
#include "video/smk_decoder.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
typedef Common::String Filename;
|
||||
typedef Common::List<Filename> Filenames;
|
||||
|
||||
class HypnoSmackerDecoder : public Video::SmackerDecoder {
|
||||
public:
|
||||
bool loadStream(Common::SeekableReadStream *stream) override;
|
||||
|
||||
protected:
|
||||
uint32 getSignatureVersion(uint32 signature) const override;
|
||||
};
|
||||
|
||||
class MVideo {
|
||||
public:
|
||||
MVideo(Filename, Common::Point, bool, bool, bool);
|
||||
Filename path;
|
||||
Common::Point position;
|
||||
bool scaled;
|
||||
bool transparent;
|
||||
bool loop;
|
||||
HypnoSmackerDecoder *decoder;
|
||||
};
|
||||
|
||||
typedef Common::Array<MVideo> Videos;
|
||||
|
||||
enum HotspotType {
|
||||
MakeMenu,
|
||||
MakeHotspot
|
||||
};
|
||||
|
||||
enum ActionType {
|
||||
MiceAction,
|
||||
TimerAction,
|
||||
PaletteAction,
|
||||
BackgroundAction,
|
||||
HighlightAction,
|
||||
OverlayAction,
|
||||
EscapeAction,
|
||||
SaveAction,
|
||||
LoadAction,
|
||||
LoadCheckpointAction,
|
||||
QuitAction,
|
||||
CutsceneAction,
|
||||
PlayAction,
|
||||
IntroAction,
|
||||
AmbientAction,
|
||||
WalNAction,
|
||||
GlobalAction,
|
||||
TalkAction,
|
||||
SwapPointerAction,
|
||||
SoundAction,
|
||||
ChangeLevelAction
|
||||
};
|
||||
|
||||
class Action {
|
||||
public:
|
||||
virtual ~Action() {} // needed to make Action polymorphic
|
||||
ActionType type;
|
||||
};
|
||||
|
||||
typedef Common::Array<Action *> Actions;
|
||||
|
||||
class Hotspot;
|
||||
|
||||
typedef Common::Array<Hotspot> Hotspots;
|
||||
typedef Common::Array<Hotspots *> HotspotsStack;
|
||||
typedef Common::Array<Graphics::Surface *> Frames;
|
||||
|
||||
class Hotspot {
|
||||
public:
|
||||
Hotspot(HotspotType type_, Common::Rect rect_ = Common::Rect(0, 0, 0, 0)) {
|
||||
type = type_;
|
||||
rect = rect_;
|
||||
smenu = nullptr;
|
||||
}
|
||||
HotspotType type;
|
||||
Common::String flags[3];
|
||||
Common::Rect rect;
|
||||
Common::String setting;
|
||||
Filename background;
|
||||
Frames backgroundFrames;
|
||||
Actions actions;
|
||||
Hotspots *smenu;
|
||||
};
|
||||
|
||||
class Mice : public Action {
|
||||
public:
|
||||
Mice(Filename path_, uint32 index_) {
|
||||
type = MiceAction;
|
||||
path = path_;
|
||||
index = index_;
|
||||
}
|
||||
Filename path;
|
||||
uint32 index;
|
||||
};
|
||||
|
||||
class SwapPointer : public Action {
|
||||
public:
|
||||
SwapPointer(uint32 index_) {
|
||||
type = SwapPointerAction;
|
||||
index = index_;
|
||||
}
|
||||
uint32 index;
|
||||
};
|
||||
|
||||
class Timer : public Action {
|
||||
public:
|
||||
Timer(uint32 delay_, Common::String flag_) {
|
||||
type = TimerAction;
|
||||
delay = delay_;
|
||||
flag = flag_;
|
||||
}
|
||||
uint32 delay;
|
||||
Common::String flag;
|
||||
};
|
||||
|
||||
class Palette : public Action {
|
||||
public:
|
||||
Palette(Filename path_) {
|
||||
type = PaletteAction;
|
||||
path = path_;
|
||||
}
|
||||
Filename path;
|
||||
};
|
||||
|
||||
class Highlight : public Action {
|
||||
public:
|
||||
Highlight(Common::String condition_) {
|
||||
type = HighlightAction;
|
||||
condition = condition_;
|
||||
}
|
||||
Common::String condition;
|
||||
};
|
||||
|
||||
class Background : public Action {
|
||||
public:
|
||||
Background(Filename path_, Common::Point origin_, Common::String condition_, Common::String flag1_, Common::String flag2_) {
|
||||
type = BackgroundAction;
|
||||
path = path_;
|
||||
origin = origin_;
|
||||
condition = condition_;
|
||||
flag1 = flag1_;
|
||||
flag2 = flag2_;
|
||||
}
|
||||
Filename path;
|
||||
Common::Point origin;
|
||||
Common::String condition;
|
||||
Common::String flag1;
|
||||
Common::String flag2;
|
||||
};
|
||||
|
||||
class Overlay : public Action {
|
||||
public:
|
||||
Overlay(Filename path_, Common::Point origin_, Common::String flag_) {
|
||||
type = OverlayAction;
|
||||
path = path_;
|
||||
origin = origin_;
|
||||
flag = flag_;
|
||||
}
|
||||
Filename path;
|
||||
Common::Point origin;
|
||||
Common::String flag;
|
||||
};
|
||||
|
||||
class Escape : public Action {
|
||||
public:
|
||||
Escape() {
|
||||
type = EscapeAction;
|
||||
}
|
||||
};
|
||||
|
||||
class Save : public Action {
|
||||
public:
|
||||
Save() {
|
||||
type = SaveAction;
|
||||
}
|
||||
};
|
||||
|
||||
class Load : public Action {
|
||||
public:
|
||||
Load() {
|
||||
type = LoadAction;
|
||||
}
|
||||
};
|
||||
|
||||
class LoadCheckpoint : public Action {
|
||||
public:
|
||||
LoadCheckpoint() {
|
||||
type = LoadCheckpointAction;
|
||||
}
|
||||
};
|
||||
|
||||
class Quit : public Action {
|
||||
public:
|
||||
Quit() {
|
||||
type = QuitAction;
|
||||
}
|
||||
};
|
||||
|
||||
class Cutscene : public Action {
|
||||
public:
|
||||
Cutscene(Filename path_) {
|
||||
type = CutsceneAction;
|
||||
path = path_;
|
||||
}
|
||||
Filename path;
|
||||
};
|
||||
|
||||
class Sound : public Action {
|
||||
public:
|
||||
Sound(Filename path_) {
|
||||
type = SoundAction;
|
||||
path = path_;
|
||||
}
|
||||
Filename path;
|
||||
};
|
||||
|
||||
class Intro : public Action {
|
||||
public:
|
||||
Intro(Filename path_) {
|
||||
type = IntroAction;
|
||||
path = path_;
|
||||
}
|
||||
Filename path;
|
||||
};
|
||||
|
||||
class Play : public Action {
|
||||
public:
|
||||
Play(Filename path_, Common::Point origin_, Common::String condition_, Common::String flag_) {
|
||||
type = PlayAction;
|
||||
path = path_;
|
||||
origin = origin_;
|
||||
condition = condition_;
|
||||
flag = flag_;
|
||||
}
|
||||
Filename path;
|
||||
Common::Point origin;
|
||||
Common::String condition;
|
||||
Common::String flag;
|
||||
};
|
||||
|
||||
class Ambient : public Action {
|
||||
public:
|
||||
Ambient(Filename path_, Common::Point origin_, Common::String flag_) {
|
||||
type = AmbientAction;
|
||||
path = path_;
|
||||
origin = origin_;
|
||||
flag = flag_;
|
||||
fullscreen = false;
|
||||
frameNumber = 0;
|
||||
}
|
||||
Filename path;
|
||||
Common::Point origin;
|
||||
Common::String flag;
|
||||
uint32 frameNumber;
|
||||
bool fullscreen;
|
||||
};
|
||||
|
||||
class WalN : public Action {
|
||||
public:
|
||||
WalN(Common::String wn_, Filename path_, Common::Point origin_, Common::String condition_, Common::String flag_) {
|
||||
wn = wn_;
|
||||
type = WalNAction;
|
||||
path = path_;
|
||||
origin = origin_;
|
||||
condition = condition_;
|
||||
flag = flag_;
|
||||
}
|
||||
Common::String wn;
|
||||
Filename path;
|
||||
Common::Point origin;
|
||||
Common::String condition;
|
||||
Common::String flag;
|
||||
};
|
||||
|
||||
class Global : public Action {
|
||||
public:
|
||||
Global(Common::String variable_, Common::String command_) {
|
||||
type = GlobalAction;
|
||||
variable = variable_;
|
||||
command = command_;
|
||||
}
|
||||
Common::String variable;
|
||||
Common::String command;
|
||||
};
|
||||
|
||||
class TalkCommand {
|
||||
public:
|
||||
Common::String command;
|
||||
Common::String variable;
|
||||
Filename path;
|
||||
uint32 num;
|
||||
Common::Point position;
|
||||
};
|
||||
|
||||
typedef Common::Array<TalkCommand> TalkCommands;
|
||||
|
||||
class Talk : public Action {
|
||||
public:
|
||||
Talk() {
|
||||
type = TalkAction;
|
||||
boxPos = Common::Point(0, 0);
|
||||
escape = false;
|
||||
active = true;
|
||||
}
|
||||
|
||||
Talk(Talk *t) {
|
||||
*this = *t;
|
||||
}
|
||||
|
||||
TalkCommands commands;
|
||||
bool active;
|
||||
bool escape;
|
||||
Common::Point introPos;
|
||||
Filename intro;
|
||||
Common::Point boxPos;
|
||||
Filename background;
|
||||
Common::Point backgroundPos;
|
||||
Common::Rect rect;
|
||||
Filename second;
|
||||
Common::Point secondPos;
|
||||
};
|
||||
|
||||
class ChangeLevel : public Action {
|
||||
public:
|
||||
ChangeLevel(Filename level_) {
|
||||
type = ChangeLevelAction;
|
||||
level = level_;
|
||||
}
|
||||
Filename level;
|
||||
};
|
||||
|
||||
enum LevelType {
|
||||
TransitionLevel,
|
||||
SceneLevel,
|
||||
ArcadeLevel,
|
||||
CodeLevel
|
||||
};
|
||||
|
||||
class Level {
|
||||
public:
|
||||
Level() {
|
||||
type = CodeLevel;
|
||||
musicRate = 22050;
|
||||
playMusicDuringIntro = false;
|
||||
musicStereo = false;
|
||||
}
|
||||
virtual ~Level() {} // needed to make Level polymorphic
|
||||
LevelType type;
|
||||
Filenames intros;
|
||||
Filename prefix;
|
||||
Filename levelIfWin;
|
||||
Filename levelIfLose;
|
||||
bool playMusicDuringIntro;
|
||||
Filename music;
|
||||
uint32 musicRate;
|
||||
bool musicStereo;
|
||||
};
|
||||
|
||||
class Scene : public Level {
|
||||
public:
|
||||
Scene() {
|
||||
type = SceneLevel;
|
||||
resolution = "640x480";
|
||||
}
|
||||
Common::String resolution;
|
||||
Hotspots hots;
|
||||
};
|
||||
|
||||
class FrameInfo {
|
||||
public:
|
||||
FrameInfo(uint32 start_, uint32 length_) {
|
||||
start = start_;
|
||||
length = length_;
|
||||
}
|
||||
|
||||
uint32 lastFrame() {
|
||||
return start + length;
|
||||
}
|
||||
uint32 start;
|
||||
uint32 length;
|
||||
};
|
||||
|
||||
enum ScriptMode {
|
||||
Interactive = 1,
|
||||
NonInteractive,
|
||||
};
|
||||
|
||||
class ScriptInfo {
|
||||
public:
|
||||
ScriptInfo(uint32 time_, uint32 mode_, uint32 actor_, uint32 cursor_) {
|
||||
time = time_;
|
||||
mode = ScriptMode(mode_);
|
||||
actor = actor_;
|
||||
cursor = cursor_;
|
||||
}
|
||||
uint32 time;
|
||||
ScriptMode mode;
|
||||
uint32 actor;
|
||||
uint32 cursor;
|
||||
};
|
||||
|
||||
typedef Common::List<ScriptInfo> Script;
|
||||
|
||||
class Shoot {
|
||||
public:
|
||||
Shoot() {
|
||||
destroyed = false;
|
||||
video = nullptr;
|
||||
timesToShoot = 1;
|
||||
pointsToShoot = 0;
|
||||
attackWeight = 0;
|
||||
paletteOffset = 0;
|
||||
paletteSize = 0;
|
||||
missedAnimation = 0;
|
||||
objKillsCount = 0;
|
||||
objMissesCount = 0;
|
||||
animation = "NONE";
|
||||
explosionAnimation = "";
|
||||
startFrame = 0;
|
||||
lastFrame = 1024;
|
||||
interactionFrame = 0;
|
||||
noEnemySound = false;
|
||||
enemySoundRate = 22050;
|
||||
isAnimal = false;
|
||||
nonHostile = false;
|
||||
playInteractionAudio = false;
|
||||
animalSound = "";
|
||||
jumpToTimeAfterKilled = 0;
|
||||
warningVideoIdx = 0;
|
||||
waitForClickAfterInteraction = 0;
|
||||
direction = 0;
|
||||
}
|
||||
Common::String name;
|
||||
Filename animation;
|
||||
Filename startSound;
|
||||
Common::Point position;
|
||||
Common::Point deathPosition;
|
||||
|
||||
|
||||
uint32 timesToShoot;
|
||||
uint32 pointsToShoot;
|
||||
uint32 attackWeight;
|
||||
|
||||
// Objectives
|
||||
uint32 objKillsCount;
|
||||
uint32 objMissesCount;
|
||||
|
||||
// Palette
|
||||
uint32 paletteOffset;
|
||||
uint32 paletteSize;
|
||||
|
||||
// Missed animation
|
||||
uint32 missedAnimation;
|
||||
|
||||
// Sounds
|
||||
Filename enemySound;
|
||||
uint32 enemySoundRate;
|
||||
Filename deathSound;
|
||||
Filename hitSound;
|
||||
Filename animalSound;
|
||||
|
||||
MVideo *video;
|
||||
Common::List<uint32> attackFrames;
|
||||
Common::Array<FrameInfo> bodyFrames;
|
||||
Common::Array<FrameInfo> explosionFrames;
|
||||
uint32 startFrame;
|
||||
uint32 lastFrame;
|
||||
uint32 interactionFrame;
|
||||
Filename explosionAnimation;
|
||||
Filename additionalVideo;
|
||||
bool playInteractionAudio;
|
||||
bool destroyed;
|
||||
bool noEnemySound;
|
||||
|
||||
// Soldier Boyz specific
|
||||
bool nonHostile;
|
||||
bool isAnimal;
|
||||
Common::String checkIfDestroyed;
|
||||
int jumpToTimeAfterKilled;
|
||||
char direction;
|
||||
uint32 waitForClickAfterInteraction;
|
||||
uint32 warningVideoIdx;
|
||||
};
|
||||
|
||||
typedef Common::Array<Shoot> Shoots;
|
||||
|
||||
class ShootInfo {
|
||||
public:
|
||||
Common::String name;
|
||||
uint32 timestamp;
|
||||
};
|
||||
|
||||
typedef Common::List<ShootInfo> ShootSequence;
|
||||
|
||||
class SegmentShoots {
|
||||
public:
|
||||
SegmentShoots() {
|
||||
segmentRepetition = 0;
|
||||
}
|
||||
ShootSequence shootSequence;
|
||||
uint32 segmentRepetition;
|
||||
};
|
||||
|
||||
typedef Common::Array<SegmentShoots> SegmentShootsSequence;
|
||||
typedef Common::Array<Common::String> Sounds;
|
||||
|
||||
enum SegmentType {
|
||||
Straight,
|
||||
Select3,
|
||||
TurnLeft3,
|
||||
Straight3,
|
||||
TurnRight3,
|
||||
Select2,
|
||||
TurnLeft2,
|
||||
TurnRight2,
|
||||
};
|
||||
|
||||
class Segment {
|
||||
public:
|
||||
Segment(byte type_, uint32 start_, uint32 size_) {
|
||||
type = type_;
|
||||
start = start_;
|
||||
size = size_;
|
||||
end = false;
|
||||
}
|
||||
|
||||
byte type;
|
||||
uint32 start;
|
||||
uint32 size;
|
||||
bool end;
|
||||
};
|
||||
|
||||
typedef Common::Array<Segment> Segments;
|
||||
|
||||
class ArcadeTransition {
|
||||
public:
|
||||
ArcadeTransition(Filename video_, Filename palette_, Filename sound_, uint32 soundRate_, uint32 time_) {
|
||||
video = video_;
|
||||
palette = palette_;
|
||||
sound = sound_;
|
||||
soundRate = soundRate_;
|
||||
soundStereo = false;
|
||||
loseLevel = false;
|
||||
winLevel = false;
|
||||
selection = false;
|
||||
jumpToTime = 0;
|
||||
time = time_;
|
||||
}
|
||||
|
||||
Filename video;
|
||||
Filename palette;
|
||||
Filename sound;
|
||||
uint32 soundRate;
|
||||
bool soundStereo;
|
||||
bool loseLevel;
|
||||
bool winLevel;
|
||||
bool selection;
|
||||
uint32 jumpToTime;
|
||||
uint32 time;
|
||||
};
|
||||
|
||||
typedef Common::List<ArcadeTransition> ArcadeTransitions;
|
||||
|
||||
class ArcadeShooting : public Level {
|
||||
public:
|
||||
ArcadeShooting() {
|
||||
type = ArcadeLevel;
|
||||
health = 100;
|
||||
id = 0;
|
||||
objKillsRequired[0] = 0;
|
||||
objKillsRequired[1] = 0;
|
||||
objMissesAllowed[0] = 0;
|
||||
objMissesAllowed[1] = 0;
|
||||
mouseBox = Common::Rect(0, 0, 320, 200);
|
||||
frameDelay = 0;
|
||||
targetSoundRate = 0; // TODO: unused
|
||||
shootSoundRate = 0;
|
||||
enemySoundRate = 0;
|
||||
hitSoundRate = 0;
|
||||
additionalSoundRate = 0;
|
||||
noAmmoSoundRate = 0;
|
||||
}
|
||||
void clear() {
|
||||
nextLevelVideo.clear();
|
||||
postStatsVideo.clear();
|
||||
backgroundVideo.clear();
|
||||
transitions.clear();
|
||||
maskVideo.clear();
|
||||
player.clear();
|
||||
shoots.clear();
|
||||
intros.clear();
|
||||
defeatNoEnergyFirstVideo.clear();
|
||||
defeatMissBossVideo.clear();
|
||||
defeatNoEnergySecondVideo.clear();
|
||||
missBoss1Video.clear();
|
||||
missBoss2Video.clear();
|
||||
hitBoss1Video.clear();
|
||||
hitBoss2Video.clear();
|
||||
beforeVideo.clear();
|
||||
briefingVideo.clear();
|
||||
additionalVideo.clear();
|
||||
additionalSound.clear();
|
||||
noAmmoSound.clear();
|
||||
segments.clear();
|
||||
script.clear();
|
||||
objKillsRequired[0] = 0;
|
||||
objKillsRequired[1] = 0;
|
||||
objMissesAllowed[0] = 0;
|
||||
objMissesAllowed[1] = 0;
|
||||
mouseBox = Common::Rect(0, 0, 320, 200);
|
||||
anchor = Common::Point(0, 0);
|
||||
targetSoundRate = 0;
|
||||
shootSoundRate = 0;
|
||||
enemySoundRate = 0;
|
||||
hitSoundRate = 0;
|
||||
noAmmoSoundRate = 0;
|
||||
}
|
||||
|
||||
uint32 id;
|
||||
uint32 frameDelay;
|
||||
Common::String mode;
|
||||
Common::Rect mouseBox;
|
||||
Common::Point anchor;
|
||||
ArcadeTransitions transitions;
|
||||
Segments segments;
|
||||
|
||||
// Objectives
|
||||
uint32 objKillsRequired [2];
|
||||
uint32 objMissesAllowed [2];
|
||||
|
||||
// Script
|
||||
Script script;
|
||||
|
||||
// Videos
|
||||
Filename nextLevelVideo;
|
||||
Filename postStatsVideo;
|
||||
Filename defeatNoEnergyFirstVideo;
|
||||
Filename defeatNoEnergySecondVideo;
|
||||
Filename defeatMissBossVideo;
|
||||
Filename hitBoss1Video;
|
||||
Filename missBoss1Video;
|
||||
Filename hitBoss2Video;
|
||||
Filename missBoss2Video;
|
||||
Filename beforeVideo;
|
||||
Filename additionalVideo;
|
||||
Filename briefingVideo;
|
||||
|
||||
Filename backgroundVideo;
|
||||
Filename backgroundPalette;
|
||||
Filename maskVideo;
|
||||
Filename player;
|
||||
int health;
|
||||
Shoots shoots;
|
||||
SegmentShootsSequence shootSequence;
|
||||
|
||||
// Sounds
|
||||
Filename targetSound;
|
||||
uint32 targetSoundRate;
|
||||
Filename shootSound;
|
||||
uint32 shootSoundRate;
|
||||
Filename enemySound;
|
||||
uint32 enemySoundRate;
|
||||
Filename hitSound;
|
||||
uint32 hitSoundRate;
|
||||
Filename additionalSound;
|
||||
uint32 additionalSoundRate;
|
||||
Filename noAmmoSound;
|
||||
uint32 noAmmoSoundRate;
|
||||
};
|
||||
|
||||
class Transition : public Level {
|
||||
public:
|
||||
Transition(Common::String level) {
|
||||
type = TransitionLevel;
|
||||
nextLevel = level;
|
||||
levelEasy = "";
|
||||
levelHard = "";
|
||||
frameNumber = 0;
|
||||
frameImage = "";
|
||||
}
|
||||
|
||||
Transition(Common::String easy, Common::String hard) {
|
||||
type = TransitionLevel;
|
||||
levelEasy = easy;
|
||||
levelHard = hard;
|
||||
frameNumber = 0;
|
||||
frameImage = "";
|
||||
}
|
||||
Common::String nextLevel;
|
||||
Common::String levelEasy;
|
||||
Common::String levelHard;
|
||||
Filename frameImage;
|
||||
uint32 frameNumber;
|
||||
};
|
||||
|
||||
class Code : public Level {
|
||||
public:
|
||||
Code(Common::String name_) {
|
||||
type = CodeLevel;
|
||||
name = name_;
|
||||
}
|
||||
Common::String name;
|
||||
};
|
||||
|
||||
typedef Common::HashMap<Filename, Level*> Levels;
|
||||
extern Hotspots *g_parsedHots;
|
||||
extern ArcadeShooting *g_parsedArc;
|
||||
|
||||
class ArcadeStats {
|
||||
public:
|
||||
ArcadeStats() {
|
||||
livesUsed = 0;
|
||||
shootsFired = 0;
|
||||
enemyHits = 0;
|
||||
enemyTargets = 0;
|
||||
targetsDestroyed = 0;
|
||||
targetsMissed = 0;
|
||||
friendliesEncountered = 0;
|
||||
infoReceived = 0;
|
||||
}
|
||||
uint32 livesUsed;
|
||||
uint32 shootsFired;
|
||||
uint32 enemyHits;
|
||||
uint32 enemyTargets;
|
||||
uint32 targetsDestroyed;
|
||||
uint32 targetsMissed;
|
||||
uint32 friendliesEncountered;
|
||||
uint32 infoReceived;
|
||||
};
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
#endif
|
||||
|
||||
2575
engines/hypno/grammar_arc.cpp
Normal file
2575
engines/hypno/grammar_arc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
659
engines/hypno/grammar_arc.y
Normal file
659
engines/hypno/grammar_arc.y
Normal file
@@ -0,0 +1,659 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
%require "3.0"
|
||||
%defines "engines/hypno/tokens_arc.h"
|
||||
%output "engines/hypno/grammar_arc.cpp"
|
||||
%define api.prefix {HYPNO_ARC_}
|
||||
|
||||
%{
|
||||
|
||||
#include "common/array.h"
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
#undef yyerror
|
||||
#define yyerror HYPNO_ARC_xerror
|
||||
|
||||
namespace Hypno {
|
||||
Shoot *shoot = NULL;
|
||||
}
|
||||
|
||||
extern int HYPNO_ARC_lex();
|
||||
extern int HYPNO_ARC_lineno;
|
||||
uint32 HYPNO_ARC_default_sound_rate = 0;
|
||||
|
||||
void HYPNO_ARC_xerror(const char *str) {
|
||||
error("%s at line %d", str, HYPNO_ARC_lineno);
|
||||
}
|
||||
|
||||
int HYPNO_ARC_wrap() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
using namespace Hypno;
|
||||
|
||||
void parseSN(const char *sn, const char *path, const char *enc, const char *flag) {
|
||||
uint32 sampleRate = 11025;
|
||||
bool stereo = false;
|
||||
if (Common::String("22K") == enc || Common::String("22k") == enc)
|
||||
sampleRate = 22050;
|
||||
else if (HYPNO_ARC_default_sound_rate > 0)
|
||||
sampleRate = HYPNO_ARC_default_sound_rate;
|
||||
if (Common::String("STEREO") == flag)
|
||||
stereo = true;
|
||||
|
||||
if (Common::String("S0") == sn) {
|
||||
g_parsedArc->music = path;
|
||||
g_parsedArc->musicRate = sampleRate;
|
||||
g_parsedArc->musicStereo = stereo;
|
||||
} else if (Common::String("S1") == sn) {
|
||||
g_parsedArc->shootSound = path;
|
||||
g_parsedArc->shootSoundRate = sampleRate;
|
||||
assert(!stereo);
|
||||
} else if (Common::String("S2") == sn) {
|
||||
g_parsedArc->hitSound = path;
|
||||
g_parsedArc->hitSoundRate = sampleRate;
|
||||
assert(!stereo);
|
||||
} else if (Common::String("S4") == sn) {
|
||||
g_parsedArc->enemySound = path;
|
||||
g_parsedArc->enemySoundRate = sampleRate;
|
||||
assert(!stereo);
|
||||
} else if (Common::String("S5") == sn) {
|
||||
g_parsedArc->additionalSound = path;
|
||||
g_parsedArc->additionalSoundRate = sampleRate;
|
||||
assert(!stereo);
|
||||
} else if (Common::String("S7") == sn) {
|
||||
g_parsedArc->noAmmoSound = path;
|
||||
g_parsedArc->noAmmoSoundRate = sampleRate;
|
||||
assert(!stereo);
|
||||
} else if (Common::String("S8") == sn) {
|
||||
g_parsedArc->additionalSound = path;
|
||||
g_parsedArc->additionalSoundRate = sampleRate;
|
||||
assert(!stereo);
|
||||
}
|
||||
debugC(1, kHypnoDebugParser, "SN %s", path);
|
||||
}
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
char *s; /* string value */
|
||||
int i; /* integer value */
|
||||
}
|
||||
|
||||
%token<s> NAME FILENAME BNTOK SNTOK YXTOK FNTOK ENCTOK ONTOK H12TOK
|
||||
%token<i> NUM BYTE
|
||||
// header
|
||||
%token COMMENT ALTOK AVTOK ABTOK CTOK DTOK HTOK HETOK HLTOK HUTOK KNTOK RETTOK QTOK RESTOK
|
||||
%token PTOK FTOK TTOK TATOK TPTOK TSTOK ATOK VTOK OTOK LTOK MTOK NTOK NRTOK NSTOK RTOK R0TOK R1TOK
|
||||
%token ITOK I1TOK GTOK JTOK J0TOK KTOK UTOK ZTOK
|
||||
|
||||
// body
|
||||
%token NONETOK A0TOK P0TOK WTOK
|
||||
|
||||
// end
|
||||
%token XTOK
|
||||
|
||||
// bytes??
|
||||
%token CB3TOK C02TOK
|
||||
|
||||
%type<s> enc flag
|
||||
|
||||
%%
|
||||
|
||||
start: YXTOK { g_parsedArc->mode = $1; free($1); } header ZTOK RETTOK body XTOK
|
||||
| RETTOK start
|
||||
;
|
||||
|
||||
header: hline header
|
||||
| RETTOK header
|
||||
| /* nothing */
|
||||
;
|
||||
|
||||
hline: CTOK NUM {
|
||||
g_parsedArc->id = $2;
|
||||
HYPNO_ARC_default_sound_rate = 0;
|
||||
debugC(1, kHypnoDebugParser, "C %d", $2); }
|
||||
| FTOK NUM {
|
||||
HYPNO_ARC_default_sound_rate = $2;
|
||||
debugC(1, kHypnoDebugParser, "F %d", $2);
|
||||
}
|
||||
| DTOK NUM {
|
||||
g_parsedArc->frameDelay = $2;
|
||||
debugC(1, kHypnoDebugParser, "D %d", $2);
|
||||
}
|
||||
| PTOK NUM NUM { debugC(1, kHypnoDebugParser, "P %d %d", $2, $3); }
|
||||
| ATOK NUM NUM { g_parsedArc->anchor = Common::Point($2, $3);
|
||||
debugC(1, kHypnoDebugParser, "A %d %d", $2, $3);
|
||||
}
|
||||
| MTOK FILENAME {
|
||||
debugC(1, kHypnoDebugParser, "M %s", $2);
|
||||
g_parsedArc->maskVideo = $2;
|
||||
free($2);
|
||||
}
|
||||
| UTOK NUM NUM NUM NUM {
|
||||
debugC(1, kHypnoDebugParser, "U %d %d %d %d", $2, $3, $4, $5);
|
||||
ScriptInfo si($2, $3, $4, $5);
|
||||
g_parsedArc->script.push_back(si);
|
||||
}
|
||||
| VTOK NUM NUM {
|
||||
debugC(1, kHypnoDebugParser, "V %d %d", $2, $3);
|
||||
g_parsedArc->mouseBox = Common::Rect(0, 0, $2, $3);
|
||||
}
|
||||
| VTOK RESTOK {
|
||||
debugC(1, kHypnoDebugParser, "V 320,200");
|
||||
g_parsedArc->mouseBox = Common::Rect(0, 0, 320, 200);
|
||||
}
|
||||
| OTOK NUM NUM {
|
||||
g_parsedArc->objKillsRequired[0] = $2;
|
||||
g_parsedArc->objMissesAllowed[0] = $3;
|
||||
debugC(1, kHypnoDebugParser, "O %d %d", $2, $3);
|
||||
}
|
||||
| ONTOK NUM NUM {
|
||||
if (Common::String("O0") == $1) {
|
||||
g_parsedArc->objKillsRequired[0] = $2;
|
||||
g_parsedArc->objMissesAllowed[0] = $3;
|
||||
} else if (Common::String("O1") == $1) {
|
||||
g_parsedArc->objKillsRequired[1] = $2;
|
||||
g_parsedArc->objMissesAllowed[1] = $3;
|
||||
} else
|
||||
error("Invalid objective: '%s'", $1);
|
||||
debugC(1, kHypnoDebugParser, "ON %d %d", $2, $3);
|
||||
free($1);
|
||||
}
|
||||
| ONTOK NUM {
|
||||
if (Common::String("O0") == $1) {
|
||||
g_parsedArc->objKillsRequired[0] = $2;
|
||||
} else if (Common::String("O1") == $1) {
|
||||
g_parsedArc->objKillsRequired[1] = $2;
|
||||
} else
|
||||
error("Invalid objective: '%s'", $1);
|
||||
debugC(1, kHypnoDebugParser, "ON %d", $2);
|
||||
free($1);
|
||||
}
|
||||
| TPTOK NONETOK NUM FILENAME {
|
||||
ArcadeTransition at("NONE", $4, "", 0, $3);
|
||||
g_parsedArc->transitions.push_back(at);
|
||||
debugC(1, kHypnoDebugParser, "Tp %s %d %s", "NONE", $3, $4);
|
||||
free($4);
|
||||
}
|
||||
| TSTOK FILENAME NUM NUM {
|
||||
ArcadeTransition at($2, "", "", 0, $3);
|
||||
at.selection = true;
|
||||
g_parsedArc->transitions.push_back(at);
|
||||
debugC(1, kHypnoDebugParser, "Ts %s %d %d", $2, $3, $4);
|
||||
free($2);
|
||||
}
|
||||
| TPTOK FILENAME NUM FILENAME {
|
||||
ArcadeTransition at($2, $4, "", 0, $3);
|
||||
g_parsedArc->transitions.push_back(at);
|
||||
debugC(1, kHypnoDebugParser, "Tp %s %d %s", $2, $3, $4);
|
||||
free($2);
|
||||
free($4);
|
||||
}
|
||||
| TATOK NUM FILENAME flag enc {
|
||||
uint32 sampleRate = 11025;
|
||||
bool stereo = false;
|
||||
if (Common::String("22K") == $5 || Common::String("22k") == $5)
|
||||
sampleRate = 22050;
|
||||
if (Common::String("STEREO") == $4)
|
||||
stereo = true;
|
||||
|
||||
ArcadeTransition at("", "", $3, sampleRate, $2);
|
||||
at.soundStereo = stereo;
|
||||
g_parsedArc->transitions.push_back(at);
|
||||
debugC(1, kHypnoDebugParser, "Ta %d %s", $2, $3);
|
||||
free($3);
|
||||
free($4);
|
||||
free($5);
|
||||
}
|
||||
| TTOK FILENAME NUM {
|
||||
ArcadeTransition at($2, "", "", 0, $3);
|
||||
g_parsedArc->transitions.push_back(at);
|
||||
debugC(1, kHypnoDebugParser, "T %s %d", $2, $3);
|
||||
free($2);
|
||||
}
|
||||
| TTOK NONETOK NUM {
|
||||
ArcadeTransition at("NONE", "", "", 0, $3);
|
||||
g_parsedArc->transitions.push_back(at);
|
||||
debugC(1, kHypnoDebugParser, "T NONE %d", $3); }
|
||||
| NTOK FILENAME {
|
||||
g_parsedArc->backgroundVideo = $2;
|
||||
debugC(1, kHypnoDebugParser, "N %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| NSTOK FILENAME {
|
||||
g_parsedArc->backgroundVideo = $2;
|
||||
debugC(1, kHypnoDebugParser, "N* %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| RTOK FILENAME {
|
||||
g_parsedArc->backgroundPalette = $2;
|
||||
debugC(1, kHypnoDebugParser, "R %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| ITOK FILENAME {
|
||||
g_parsedArc->player = $2;
|
||||
debugC(1, kHypnoDebugParser, "I %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| I1TOK FILENAME {
|
||||
debugC(1, kHypnoDebugParser, "I1 %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| QTOK NUM NUM { debugC(1, kHypnoDebugParser, "Q %d %d", $2, $3); }
|
||||
| BNTOK FILENAME {
|
||||
if (Common::String("B0") == $1)
|
||||
g_parsedArc->beforeVideo = $2;
|
||||
else if (Common::String("B1") == $1)
|
||||
g_parsedArc->additionalVideo = $2;
|
||||
else if (Common::String("B2") == $1)
|
||||
g_parsedArc->nextLevelVideo = $2;
|
||||
else if (Common::String("B3") == $1)
|
||||
g_parsedArc->defeatNoEnergyFirstVideo = $2;
|
||||
else if (Common::String("B4") == $1)
|
||||
g_parsedArc->defeatMissBossVideo = $2;
|
||||
else if (Common::String("B5") == $1)
|
||||
g_parsedArc->defeatNoEnergySecondVideo = $2;
|
||||
else if (Common::String("B6") == $1)
|
||||
g_parsedArc->hitBoss1Video = $2;
|
||||
else if (Common::String("B7") == $1)
|
||||
g_parsedArc->missBoss1Video = $2;
|
||||
else if (Common::String("B8") == $1)
|
||||
g_parsedArc->hitBoss2Video = $2;
|
||||
else if (Common::String("B9") == $1)
|
||||
g_parsedArc->missBoss2Video = $2;
|
||||
else if (Common::String("BA") == $1)
|
||||
g_parsedArc->briefingVideo = $2;
|
||||
else if (Common::String("BB") == $1)
|
||||
g_parsedArc->postStatsVideo = $2;
|
||||
|
||||
debugC(1, kHypnoDebugParser, "BN %s", $2);
|
||||
free($1);
|
||||
free($2);
|
||||
}
|
||||
| SNTOK FILENAME enc flag {
|
||||
parseSN($1, $2, $3, $4);
|
||||
free($1);
|
||||
free($2);
|
||||
free($3);
|
||||
free($4);
|
||||
}
|
||||
| SNTOK FILENAME flag enc {
|
||||
parseSN($1, $2, $4, $3);
|
||||
free($1);
|
||||
free($2);
|
||||
free($3);
|
||||
free($4);
|
||||
}
|
||||
| HETOK BYTE NUM NUM {
|
||||
Segment segment($2, $4, $3);
|
||||
segment.end = true;
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "HE %x %d %d", $2, $3, $4);
|
||||
}
|
||||
| HLTOK BYTE NUM NUM {
|
||||
Segment segment($2, $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "HL %x %d %d", $2, $3, $4);
|
||||
}
|
||||
| HUTOK BYTE NUM NUM {
|
||||
Segment segment($2, $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "HU %x %d %d", $2, $3, $4);
|
||||
}
|
||||
| HTOK NAME NUM NUM {
|
||||
assert(Common::String($2).size() == 1);
|
||||
Segment segment($2[0], $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "H %s %d %d", $2, $3, $4);
|
||||
free($2);
|
||||
}
|
||||
| HTOK RTOK NUM NUM { // Workaround for BYTE == R
|
||||
Segment segment('R', $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "H R %d %d", $3, $4);
|
||||
}
|
||||
| HTOK ATOK NUM NUM { // Workaround for BYTE == A
|
||||
Segment segment('A', $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "H A %d %d", $3, $4);
|
||||
}
|
||||
| HTOK PTOK NUM NUM { // Workaround for BYTE == P
|
||||
Segment segment('P', $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "H P %d %d", $3, $4);
|
||||
}
|
||||
| HTOK LTOK NUM NUM { // Workaround for BYTE == P
|
||||
Segment segment('L', $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "H P %d %d", $3, $4);
|
||||
}
|
||||
| H12TOK BYTE NUM NUM {
|
||||
Segment segment($2, $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "HN %x %d %d", $2, $3, $4);
|
||||
free($1);
|
||||
}
|
||||
| HTOK BYTE NUM NUM {
|
||||
Segment segment($2, $4, $3);
|
||||
g_parsedArc->segments.push_back(segment);
|
||||
debugC(1, kHypnoDebugParser, "H %x %d %d", $2, $3, $4);
|
||||
}
|
||||
;
|
||||
|
||||
enc: ENCTOK { $$ = $1; }
|
||||
| /* nothing */ { $$ = scumm_strdup(""); }
|
||||
;
|
||||
|
||||
flag: NAME { $$ = $1; }
|
||||
| /* nothing */ { $$ = scumm_strdup(""); }
|
||||
;
|
||||
|
||||
body: bline body
|
||||
| RETTOK body
|
||||
| /* nothing */
|
||||
;
|
||||
|
||||
bline: FNTOK FILENAME {
|
||||
if (shoot) delete shoot;
|
||||
shoot = new Shoot();
|
||||
if (Common::String("F0") == $1)
|
||||
shoot->animation = $2;
|
||||
else if (Common::String("F4") == $1)
|
||||
shoot->explosionAnimation = $2;
|
||||
else if (Common::String("F6") == $1)
|
||||
shoot->additionalVideo = $2;
|
||||
debugC(1, kHypnoDebugParser, "FN %s", $2);
|
||||
free($1);
|
||||
free($2);
|
||||
}
|
||||
| AVTOK NUM {
|
||||
assert($2 == 0);
|
||||
shoot->nonHostile = true;
|
||||
debugC(1, kHypnoDebugParser, "AV %d", $2);
|
||||
}
|
||||
| ALTOK NUM {
|
||||
assert(g_parsedArc->shoots.size() > 0);
|
||||
shoot->checkIfDestroyed = g_parsedArc->shoots.back().name;
|
||||
debugC(1, kHypnoDebugParser, "AL %d", $2);
|
||||
}
|
||||
| ABTOK NUM {
|
||||
assert($2 == 1);
|
||||
shoot->playInteractionAudio = true;
|
||||
debugC(1, kHypnoDebugParser, "AB %d", $2);
|
||||
}
|
||||
| DTOK LTOK {
|
||||
shoot->direction = 'L';
|
||||
debugC(1, kHypnoDebugParser, "D L"); }
|
||||
| DTOK RTOK {
|
||||
shoot->direction = 'R';
|
||||
debugC(1, kHypnoDebugParser, "D R"); }
|
||||
| J0TOK NUM {
|
||||
assert($2 > 0);
|
||||
shoot->warningVideoIdx = $2;
|
||||
debugC(1, kHypnoDebugParser, "J0 %d", $2);
|
||||
}
|
||||
| FNTOK NONETOK {
|
||||
if (shoot) delete shoot;
|
||||
shoot = new Shoot();
|
||||
shoot->animation = "NONE";
|
||||
debugC(1, kHypnoDebugParser, "FN NONE");
|
||||
free($1);
|
||||
}
|
||||
| FTOK FILENAME {
|
||||
if (shoot) delete shoot;
|
||||
shoot = new Shoot();
|
||||
shoot->animation = $2;
|
||||
debugC(1, kHypnoDebugParser, "FN %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| ITOK NAME {
|
||||
shoot->name = $2;
|
||||
debugC(1, kHypnoDebugParser, "I %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| ITOK BNTOK { // Workaround for NAME == B1
|
||||
shoot->name = $2;
|
||||
debugC(1, kHypnoDebugParser, "I %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| ITOK ATOK { // Workaround for NAME == A
|
||||
shoot->name = "A";
|
||||
debugC(1, kHypnoDebugParser, "I A");
|
||||
}
|
||||
| ITOK CTOK { // Workaround for NAME == C
|
||||
shoot->name = "C";
|
||||
debugC(1, kHypnoDebugParser, "I C");
|
||||
}
|
||||
| ITOK DTOK { // Workaround for NAME == D
|
||||
shoot->name = "D";
|
||||
debugC(1, kHypnoDebugParser, "I D");
|
||||
}
|
||||
| ITOK FTOK { // Workaround for NAME == F
|
||||
shoot->name = "F";
|
||||
debugC(1, kHypnoDebugParser, "I F");
|
||||
}
|
||||
| ITOK GTOK { // Workaround for NAME == G
|
||||
shoot->name = "G";
|
||||
debugC(1, kHypnoDebugParser, "I G");
|
||||
}
|
||||
| ITOK HTOK { // Workaround for NAME == H
|
||||
shoot->name = "H";
|
||||
debugC(1, kHypnoDebugParser, "I H");
|
||||
}
|
||||
| ITOK H12TOK { // Workaround for NAME == H1/H2
|
||||
shoot->name = $2;
|
||||
debugC(1, kHypnoDebugParser, "I %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| ITOK ITOK { // Workaround for NAME == I
|
||||
shoot->name = "I";
|
||||
debugC(1, kHypnoDebugParser, "I I");
|
||||
}
|
||||
| ITOK JTOK { // Workaround for NAME == J
|
||||
shoot->name = "J";
|
||||
debugC(1, kHypnoDebugParser, "I J");
|
||||
}
|
||||
| ITOK KTOK { // Workaround for NAME == K
|
||||
shoot->name = "K";
|
||||
debugC(1, kHypnoDebugParser, "I K");
|
||||
}
|
||||
| ITOK NTOK { // Workaround for NAME == N
|
||||
shoot->name = "N";
|
||||
debugC(1, kHypnoDebugParser, "I N");
|
||||
}
|
||||
| ITOK OTOK { // Workaround for NAME == O
|
||||
shoot->name = "O";
|
||||
debugC(1, kHypnoDebugParser, "I O");
|
||||
}
|
||||
| ITOK PTOK { // Workaround for NAME == P
|
||||
shoot->name = "P";
|
||||
debugC(1, kHypnoDebugParser, "I P");
|
||||
}
|
||||
| ITOK QTOK { // Workaround for NAME == Q
|
||||
shoot->name = "Q";
|
||||
debugC(1, kHypnoDebugParser, "I Q");
|
||||
}
|
||||
| ITOK RTOK { // Workaround for NAME == R
|
||||
shoot->name = "R";
|
||||
debugC(1, kHypnoDebugParser, "I R");
|
||||
}
|
||||
| ITOK SNTOK { // Workaround for NAME == S1
|
||||
shoot->name = $2;
|
||||
debugC(1, kHypnoDebugParser, "I %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| ITOK TTOK { // Workaround for NAME == T
|
||||
shoot->name = "T";
|
||||
debugC(1, kHypnoDebugParser, "I T");
|
||||
}
|
||||
| ITOK LTOK { // Workaround for NAME == L
|
||||
shoot->name = "L";
|
||||
debugC(1, kHypnoDebugParser, "I L");
|
||||
}
|
||||
| ITOK MTOK { // Workaround for NAME == M
|
||||
shoot->name = "M";
|
||||
debugC(1, kHypnoDebugParser, "I M");
|
||||
}
|
||||
| ITOK UTOK { // Workaround for NAME == U
|
||||
shoot->name = "U";
|
||||
debugC(1, kHypnoDebugParser, "I U");
|
||||
}
|
||||
| JTOK NUM {
|
||||
debugC(1, kHypnoDebugParser, "J %d", $2);
|
||||
}
|
||||
| A0TOK NUM NUM {
|
||||
shoot->position = Common::Point($2, $3);
|
||||
debugC(1, kHypnoDebugParser, "A0 %d %d", $2, $3);
|
||||
}
|
||||
| RTOK NUM NUM {
|
||||
shoot->objKillsCount = $2;
|
||||
shoot->objMissesCount = $3;
|
||||
debugC(1, kHypnoDebugParser, "R %d %d", $2, $3);
|
||||
}
|
||||
| R0TOK NUM NUM {
|
||||
shoot->objKillsCount = $2;
|
||||
shoot->objMissesCount = $3;
|
||||
debugC(1, kHypnoDebugParser, "R0 %d %d", $2, $3);
|
||||
}
|
||||
| R1TOK NUM NUM {
|
||||
debugC(1, kHypnoDebugParser, "R1 %d %d", $2, $3);
|
||||
}
|
||||
| BNTOK NUM NUM {
|
||||
FrameInfo fi($3, $2);
|
||||
shoot->bodyFrames.push_back(fi);
|
||||
debugC(1, kHypnoDebugParser, "BN %d %d", $2, $3);
|
||||
free($1);
|
||||
}
|
||||
| KNTOK NUM NUM {
|
||||
FrameInfo fi($3, $2);
|
||||
shoot->explosionFrames.push_back(fi);
|
||||
debugC(1, kHypnoDebugParser, "KN %d %d", $2, $3);
|
||||
}
|
||||
| P0TOK NUM NUM {
|
||||
shoot->paletteSize = $2;
|
||||
shoot->paletteOffset = $3;
|
||||
debugC(1, kHypnoDebugParser, "P0 %d %d", $2, $3); }
|
||||
| OTOK NUM NUM {
|
||||
if ($2 == 0 && $3 == 0)
|
||||
error("Invalid O command (0, 0)");
|
||||
shoot->deathPosition = Common::Point($2, $3);
|
||||
debugC(1, kHypnoDebugParser, "O %d %d", $2, $3);
|
||||
}
|
||||
| CTOK NUM {
|
||||
shoot->timesToShoot = $2;
|
||||
debugC(1, kHypnoDebugParser, "C %d", $2);
|
||||
}
|
||||
| HTOK NUM {
|
||||
shoot->attackFrames.push_back($2);
|
||||
debugC(1, kHypnoDebugParser, "H %d", $2); }
|
||||
| VTOK NUM { debugC(1, kHypnoDebugParser, "V %d", $2); }
|
||||
| VTOK { debugC(1, kHypnoDebugParser, "V"); }
|
||||
| WTOK NUM {
|
||||
shoot->attackWeight = $2;
|
||||
debugC(1, kHypnoDebugParser, "W %d", $2); }
|
||||
| DTOK NUM {
|
||||
shoot->pointsToShoot = $2;
|
||||
debugC(1, kHypnoDebugParser, "D %d", $2);
|
||||
}
|
||||
| LTOK NUM NUM {
|
||||
debugC(1, kHypnoDebugParser, "L %d %d", $2, $3);
|
||||
}
|
||||
| LTOK NUM {
|
||||
debugC(1, kHypnoDebugParser, "L %d", $2);
|
||||
FrameInfo fi($2-1, 0);
|
||||
shoot->bodyFrames.push_back(fi);
|
||||
}
|
||||
| MTOK NUM { debugC(1, kHypnoDebugParser, "M %d", $2);
|
||||
shoot->missedAnimation = $2;
|
||||
}
|
||||
| KTOK { debugC(1, kHypnoDebugParser, "K"); }
|
||||
| KTOK NUM { debugC(1, kHypnoDebugParser, "K %d", $2);
|
||||
FrameInfo fi($2, 1);
|
||||
shoot->explosionFrames.push_back(fi);
|
||||
}
|
||||
| KTOK NUM NUM NUM {
|
||||
assert($3 > $2);
|
||||
FrameInfo fi($2, $3 - $2);
|
||||
shoot->jumpToTimeAfterKilled = $4;
|
||||
shoot->explosionFrames.push_back(fi);
|
||||
debugC(1, kHypnoDebugParser, "K %d %d %d", $2, $3, $4);
|
||||
}
|
||||
| KTOK NUM NUM { debugC(1, kHypnoDebugParser, "K %d %d", $2, $3);
|
||||
FrameInfo fi($2, 1);
|
||||
shoot->explosionFrames.push_back(fi);
|
||||
}
|
||||
| SNTOK FILENAME enc {
|
||||
if (Common::String("S0") == $1) {
|
||||
shoot->enemySound = $2;
|
||||
if (Common::String($3) == "11K")
|
||||
shoot->enemySoundRate = 11025;
|
||||
else
|
||||
shoot->enemySoundRate = 22050;
|
||||
} else if (Common::String("S1") == $1)
|
||||
shoot->deathSound = $2;
|
||||
else if (Common::String("S2") == $1)
|
||||
shoot->hitSound = $2;
|
||||
else if (Common::String("S4") == $1)
|
||||
shoot->animalSound = $2;
|
||||
|
||||
debugC(1, kHypnoDebugParser, "SN %s", $2);
|
||||
free($1);
|
||||
free($2);
|
||||
free($3);
|
||||
}
|
||||
| SNTOK {
|
||||
debugC(1, kHypnoDebugParser, "SN");
|
||||
free($1);
|
||||
}
|
||||
|
||||
| GTOK { debugC(1, kHypnoDebugParser, "G"); }
|
||||
| TTOK NUM NUM NUM {
|
||||
shoot->interactionFrame = $2;
|
||||
assert($3 == 0);
|
||||
shoot->waitForClickAfterInteraction = $4;
|
||||
debugC(1, kHypnoDebugParser, "T %d %d %d", $2, $3, $4);
|
||||
}
|
||||
| TTOK NUM {
|
||||
shoot->interactionFrame = $2;
|
||||
debugC(1, kHypnoDebugParser, "T %d", $2);
|
||||
}
|
||||
| TTOK {
|
||||
shoot->isAnimal = true;
|
||||
debugC(1, kHypnoDebugParser, "T");
|
||||
}
|
||||
| MTOK {
|
||||
debugC(1, kHypnoDebugParser, "M");
|
||||
}
|
||||
| NTOK {
|
||||
shoot->noEnemySound = true;
|
||||
debugC(1, kHypnoDebugParser, "N"); }
|
||||
| NRTOK {
|
||||
debugC(1, kHypnoDebugParser, "NR"); }
|
||||
| ZTOK {
|
||||
g_parsedArc->shoots.push_back(*shoot);
|
||||
//delete shoot;
|
||||
//shoot = nullptr;
|
||||
debugC(1, kHypnoDebugParser, "Z");
|
||||
}
|
||||
;
|
||||
|
||||
2023
engines/hypno/grammar_mis.cpp
Normal file
2023
engines/hypno/grammar_mis.cpp
Normal file
File diff suppressed because it is too large
Load Diff
435
engines/hypno/grammar_mis.y
Normal file
435
engines/hypno/grammar_mis.y
Normal file
@@ -0,0 +1,435 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
%require "3.0"
|
||||
%defines "engines/hypno/tokens_mis.h"
|
||||
%output "engines/hypno/grammar_mis.cpp"
|
||||
%define api.prefix {HYPNO_MIS_}
|
||||
|
||||
%{
|
||||
|
||||
#include "common/array.h"
|
||||
#include "hypno/hypno.h"
|
||||
//#include <stdio.h>
|
||||
|
||||
#undef yyerror
|
||||
#define yyerror HYPNO_MIS_xerror
|
||||
|
||||
extern int HYPNO_MIS_lex();
|
||||
extern int yylineno;
|
||||
|
||||
namespace Hypno {
|
||||
Common::Array<uint32> *smenu_idx = nullptr;
|
||||
HotspotsStack *stack = nullptr;
|
||||
Talk *talk_action = nullptr;
|
||||
}
|
||||
|
||||
void HYPNO_MIS_xerror(const char *str) {
|
||||
error("ERROR: %s", str);
|
||||
}
|
||||
|
||||
int HYPNO_MIS_wrap() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
using namespace Hypno;
|
||||
|
||||
%}
|
||||
|
||||
%union {
|
||||
char *s; /* string value */
|
||||
int i; /* integer value */
|
||||
}
|
||||
|
||||
%token<s> NAME FILENAME FLAG GSSWITCH WALNTOK ENCTOK
|
||||
%token<i> NUM
|
||||
%token COMMENT HOTSTOK CUTSTOK BACKTOK INTRTOK RETTOK TIMETOK PALETOK BBOXTOK OVERTOK MICETOK SONDTOK PLAYTOK ENDTOK
|
||||
%token MENUTOK SMENTOK ESCPTOK NRTOK AMBITOK SWPTTOK MPTRTOK
|
||||
%token GLOBTOK TONTOK TOFFTOK
|
||||
%token TALKTOK INACTOK FDTOK BOXXTOK ESCAPETOK SECONDTOK INTROTOK DEFAULTTOK
|
||||
%token<s> PG PA PD PH PF PP PI PS
|
||||
%token PE PL
|
||||
|
||||
%type<s> gsswitch flag mflag
|
||||
|
||||
%%
|
||||
|
||||
start: init lines
|
||||
;
|
||||
|
||||
init: {
|
||||
if (smenu_idx)
|
||||
delete smenu_idx;
|
||||
smenu_idx = new Common::Array<uint32>();
|
||||
smenu_idx->push_back((uint32)-1);
|
||||
if (stack)
|
||||
delete stack;
|
||||
stack = new Hypno::HotspotsStack();
|
||||
stack->push_back(new Hotspots());
|
||||
}
|
||||
|
||||
lines: line lines
|
||||
| /* nothing */
|
||||
;
|
||||
|
||||
|
||||
line: MENUTOK mflag mflag mflag {
|
||||
Hotspot hot(MakeMenu);
|
||||
debugC(1, kHypnoDebugParser, "MENU %s %s", $2, $3);
|
||||
hot.flags[0] = $2;
|
||||
hot.flags[1] = $3;
|
||||
hot.flags[2] = $4;
|
||||
|
||||
Hotspots *cur = stack->back();
|
||||
cur->push_back(hot);
|
||||
|
||||
// We don't care about menus, only hotspots
|
||||
int idx = smenu_idx->back();
|
||||
idx++;
|
||||
smenu_idx->pop_back();
|
||||
smenu_idx->push_back(idx);
|
||||
free($2);
|
||||
free($3);
|
||||
free($4);
|
||||
}
|
||||
| MENUTOK FILENAME {
|
||||
Hotspot hot(MakeMenu);
|
||||
debugC(1, kHypnoDebugParser, "MENU %s", $2);
|
||||
hot.background = $2;
|
||||
|
||||
Hotspots *cur = stack->back();
|
||||
cur->push_back(hot);
|
||||
|
||||
// We don't care about menus, only hotspots
|
||||
int idx = smenu_idx->back();
|
||||
idx++;
|
||||
smenu_idx->pop_back();
|
||||
smenu_idx->push_back(idx);
|
||||
free($2);
|
||||
}
|
||||
| HOTSTOK BBOXTOK NUM NUM NUM NUM {
|
||||
Hotspot hot(MakeHotspot, Common::Rect($3, $4, $5, $6));
|
||||
debugC(1, kHypnoDebugParser, "HOTS %d.", hot.type);
|
||||
Hotspots *cur = stack->back();
|
||||
cur->push_back(hot);
|
||||
}
|
||||
| SMENTOK {
|
||||
// This should always point to a hotspot
|
||||
int idx = smenu_idx->back();
|
||||
idx++;
|
||||
smenu_idx->pop_back();
|
||||
smenu_idx->push_back(idx);
|
||||
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &(*cur)[idx];
|
||||
|
||||
smenu_idx->push_back((uint32)-1);
|
||||
hot->smenu = new Hotspots();
|
||||
stack->push_back(hot->smenu);
|
||||
debugC(1, kHypnoDebugParser, "SUBMENU");
|
||||
}
|
||||
| ESCPTOK {
|
||||
Escape *a = new Escape();
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "ESC SUBMENU"); }
|
||||
| TIMETOK NUM mflag {
|
||||
Timer *a = new Timer($2, $3);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "TIME %d %s", $2, $3);
|
||||
free($3);
|
||||
}
|
||||
| SWPTTOK NUM {
|
||||
SwapPointer *a = new SwapPointer($2);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "SWPT %d", $2); }
|
||||
| BACKTOK FILENAME NUM NUM gsswitch flag flag {
|
||||
Background *a = new Background($2, Common::Point($3, $4), $5, $6, $7);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "BACK");
|
||||
free($2);
|
||||
free($5);
|
||||
free($6);
|
||||
free($7);
|
||||
}
|
||||
| GLOBTOK GSSWITCH NAME {
|
||||
Global *a = new Global($2, $3);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "GLOB");
|
||||
free($2);
|
||||
free($3);
|
||||
}
|
||||
| AMBITOK FILENAME NUM NUM flag {
|
||||
Ambient *a = new Ambient($2, Common::Point($3, $4), $5);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "AMBI %d %d", $3, $4);
|
||||
free($2);
|
||||
free($5);
|
||||
}
|
||||
| PLAYTOK FILENAME NUM NUM gsswitch flag {
|
||||
Play *a = new Play($2, Common::Point($3, $4), $5, $6);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "PLAY %s.", $2);
|
||||
free($2);
|
||||
free($5);
|
||||
free($6);
|
||||
}
|
||||
| SONDTOK FILENAME ENCTOK {
|
||||
//Play *a = new Play($2, Common::Point($3, $4), $5, $6);
|
||||
//Hotspots *cur = stack->back();
|
||||
//Hotspot *hot = &cur->back();
|
||||
//hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "SOND %s.", $2);
|
||||
free($2);
|
||||
free($3);
|
||||
}
|
||||
| SONDTOK FILENAME {
|
||||
//Play *a = new Play($2, Common::Point($3, $4), $5, $6);
|
||||
//Hotspots *cur = stack->back();
|
||||
//Hotspot *hot = &cur->back();
|
||||
//hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "SOND %s.", $2);
|
||||
free($2);
|
||||
}
|
||||
| OVERTOK FILENAME NUM NUM flag {
|
||||
Overlay *a = new Overlay($2, Common::Point($3, $4), $5);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
free($2);
|
||||
free($5);
|
||||
}
|
||||
| PALETOK FILENAME {
|
||||
Palette *a = new Palette($2);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "PALE");
|
||||
free($2);
|
||||
}
|
||||
| INTRTOK FILENAME NUM NUM {
|
||||
Intro *a = new Intro(Common::String("cine/") + $2);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "INTRO %s %d %d", $2, $3, $4);
|
||||
free($2);
|
||||
}
|
||||
| INTRTOK FILENAME {
|
||||
Intro *a = new Intro(Common::String("cine/") + $2);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "INTRO %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| CUTSTOK FILENAME {
|
||||
Cutscene *a = new Cutscene($2);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "CUTS %s", $2);
|
||||
free($2);
|
||||
}
|
||||
| WALNTOK FILENAME NUM NUM gsswitch flag {
|
||||
WalN *a = new WalN($1, $2, Common::Point($3, $4), $5, $6);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
debugC(1, kHypnoDebugParser, "WALN %s %d %d", $2, $3, $4);
|
||||
free($1);
|
||||
free($2);
|
||||
free($5);
|
||||
free($6);
|
||||
}
|
||||
| MICETOK FILENAME NUM {
|
||||
Mice *a = new Mice($2, $3-1);
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(a);
|
||||
free($2);
|
||||
}
|
||||
| MPTRTOK FILENAME NUM NUM NUM NUM NUM {
|
||||
debugC(1, kHypnoDebugParser, "MPTR %s %d %d %d %d %d", $2, $3, $4, $5, $6, $7);
|
||||
free($2);
|
||||
}
|
||||
| TALKTOK alloctalk talk {
|
||||
Hotspots *cur = stack->back();
|
||||
Hotspot *hot = &cur->back();
|
||||
hot->actions.push_back(talk_action);
|
||||
talk_action = nullptr;
|
||||
debugC(1, kHypnoDebugParser, "TALK"); }
|
||||
| ENDTOK anything RETTOK {
|
||||
debugC(1, kHypnoDebugParser, "explicit END");
|
||||
g_parsedHots = stack->back();
|
||||
stack->pop_back();
|
||||
smenu_idx->pop_back();
|
||||
}
|
||||
| RETTOK { debugC(1, kHypnoDebugParser, "implicit END"); }
|
||||
;
|
||||
|
||||
anything: NAME anything { free($1); }
|
||||
| // nothing
|
||||
;
|
||||
|
||||
alloctalk: {
|
||||
assert(talk_action == nullptr);
|
||||
talk_action = new Talk();
|
||||
talk_action->escape = false;
|
||||
talk_action->active = true;
|
||||
}
|
||||
|
||||
talk: INACTOK talk {
|
||||
talk_action->active = false;
|
||||
debugC(1, kHypnoDebugParser, "inactive"); }
|
||||
| FDTOK talk { debugC(1, kHypnoDebugParser, "inactive"); }
|
||||
| BACKTOK FILENAME NUM NUM gsswitch flag {
|
||||
talk_action->background = $2;
|
||||
talk_action->backgroundPos = Common::Point($3, $4);
|
||||
debugC(1, kHypnoDebugParser, "BACK in TALK");
|
||||
free($2);
|
||||
free($5);
|
||||
free($6);
|
||||
}
|
||||
| BOXXTOK NUM NUM {
|
||||
talk_action->boxPos = Common::Point($2, $3);
|
||||
debugC(1, kHypnoDebugParser, "BOXX %d %d", $2, $3); }
|
||||
| ESCAPETOK {
|
||||
talk_action->escape = true;
|
||||
debugC(1, kHypnoDebugParser, "ESCAPE"); }
|
||||
| SECONDTOK FILENAME NUM NUM flag {
|
||||
talk_action->second = $2;
|
||||
talk_action->secondPos = Common::Point($3, $4);
|
||||
debugC(1, kHypnoDebugParser, "SECOND %s %d %d '%s'", $2, $3, $4, $5);
|
||||
free($2);
|
||||
free($5);
|
||||
}
|
||||
| INTROTOK FILENAME NUM NUM {
|
||||
talk_action->intro = $2;
|
||||
talk_action->introPos = Common::Point($3, $4);
|
||||
debugC(1, kHypnoDebugParser, "INTRO %s %d %d", $2, $3, $4);
|
||||
free($2);
|
||||
}
|
||||
| DEFAULTTOK FILENAME NUM NUM {
|
||||
// Unsure how this is different from second
|
||||
talk_action->second = $2;
|
||||
talk_action->secondPos = Common::Point($3, $4);
|
||||
debugC(1, kHypnoDebugParser, "DEFAULT %s %d %d", $2, $3, $4);
|
||||
free($2);
|
||||
}
|
||||
| PG talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "G";
|
||||
talk_cmd.path = $1+2;
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "%s", $1);
|
||||
free($1);
|
||||
}
|
||||
| PH talk {
|
||||
debugC(1, kHypnoDebugParser, "%s", $1);
|
||||
free($1);
|
||||
}
|
||||
| PF talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "F";
|
||||
talk_cmd.num = atoi($1+2)-1;
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "%s", $1);
|
||||
free($1);
|
||||
}
|
||||
| PA talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "A";
|
||||
talk_cmd.num = atoi($1+2)-1;
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "|A%d", talk_cmd.num);
|
||||
free($1);
|
||||
}
|
||||
| PD talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "D";
|
||||
talk_cmd.num = atoi($1+2)-1;
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "%s", $1);
|
||||
free($1);
|
||||
}
|
||||
| PP NUM NUM flag talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "P";
|
||||
talk_cmd.path = $1+2;
|
||||
talk_cmd.position = Common::Point($2, $3);
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "%s %d %d '%s'", $1, $2, $3, $4);
|
||||
free($1);
|
||||
free($4);
|
||||
}
|
||||
| PI NUM NUM talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "I";
|
||||
talk_cmd.path = $1+2;
|
||||
talk_cmd.position = Common::Point($2, $3);
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "%s %d %d", $1, $2, $3);
|
||||
free($1);
|
||||
}
|
||||
| PS talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "S";
|
||||
talk_cmd.variable = $1+2;
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "%s", $1);
|
||||
free($1);
|
||||
}
|
||||
| PL talk {
|
||||
TalkCommand talk_cmd;
|
||||
talk_cmd.command = "L";
|
||||
talk_action->commands.push_back(talk_cmd);
|
||||
debugC(1, kHypnoDebugParser, "|L");
|
||||
}
|
||||
| PE { debugC(1, kHypnoDebugParser, "|E"); }
|
||||
| /*nothing*/
|
||||
;
|
||||
|
||||
mflag: NAME { $$ = $1; }
|
||||
| /* nothing */ { $$ = scumm_strdup(""); }
|
||||
;
|
||||
|
||||
flag: FLAG { $$ = $1; debugC(1, kHypnoDebugParser, "flag: %s", $1); }
|
||||
| /* nothing */ { $$ = scumm_strdup(""); }
|
||||
;
|
||||
|
||||
gsswitch: GSSWITCH { $$ = $1; debugC(1, kHypnoDebugParser, "switch %s", $1); }
|
||||
| /* nothing */ { $$ = scumm_strdup(""); }
|
||||
;
|
||||
|
||||
787
engines/hypno/hypno.cpp
Normal file
787
engines/hypno/hypno.cpp
Normal file
@@ -0,0 +1,787 @@
|
||||
/* 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 "audio/audiostream.h"
|
||||
#include "audio/decoders/raw.h"
|
||||
#include "common/archive.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/debug-channels.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/error.h"
|
||||
#include "common/events.h"
|
||||
#include "common/file.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/savefile.h"
|
||||
#include "common/str.h"
|
||||
#include "common/system.h"
|
||||
#include "common/substream.h"
|
||||
#include "common/timer.h"
|
||||
#include "engines/advancedDetector.h"
|
||||
#include "engines/util.h"
|
||||
#include "graphics/paletteman.h"
|
||||
#include "image/bmp.h"
|
||||
|
||||
#include "hypno/grammar.h"
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
Hotspots *g_parsedHots;
|
||||
ArcadeShooting *g_parsedArc;
|
||||
HypnoEngine *g_hypno;
|
||||
|
||||
HypnoEngine::HypnoEngine(OSystem *syst, const ADGameDescription *gd)
|
||||
: Engine(syst), _gameDescription(gd), _image(nullptr),
|
||||
_compositeSurface(nullptr), _transparentColor(0),
|
||||
_nextHotsToAdd(nullptr), _nextHotsToRemove(nullptr),
|
||||
_levelId(0), _skipLevel(false), _health(0), _maxHealth(0),
|
||||
_playerFrameIdx(0), _playerFrameSep(0), _refreshConversation(false),
|
||||
_countdown(0), _timerStarted(false), _score(0), _bonus(0), _lives(0),
|
||||
_defaultCursor(""), _defaultCursorIdx(0), _skipDefeatVideo(false),
|
||||
_background(nullptr), _masks(nullptr), _useSubtitles(false),
|
||||
_additionalVideo(nullptr), _ammo(0), _maxAmmo(0), _skipNextVideo(false),
|
||||
_screenW(0), _screenH(0), // Every games initializes its own resolution
|
||||
_keepTimerDuringScenes(false), _subtitles(nullptr) {
|
||||
_rnd = new Common::RandomSource("hypno");
|
||||
_checkpoint = "";
|
||||
|
||||
_cursorCache = new CursorCache(this);
|
||||
|
||||
if (gd->extra)
|
||||
_variant = gd->extra;
|
||||
else
|
||||
_variant = "FullGame";
|
||||
g_hypno = this;
|
||||
g_parsedArc = new ArcadeShooting();
|
||||
_language = Common::parseLanguage(ConfMan.get("language"));
|
||||
_platform = Common::parsePlatform(ConfMan.get("platform"));
|
||||
if (!Common::parseBool(ConfMan.get("cheats"), _cheatsEnabled))
|
||||
error("Failed to parse bool from cheats options");
|
||||
|
||||
if (!Common::parseBool(ConfMan.get("infiniteHealth"), _infiniteHealthCheat))
|
||||
error("Failed to parse bool from cheats options");
|
||||
|
||||
if (!Common::parseBool(ConfMan.get("infiniteAmmo"), _infiniteAmmoCheat))
|
||||
error("Failed to parse bool from cheats options");
|
||||
|
||||
if (!Common::parseBool(ConfMan.get("unlockAllLevels"), _unlockAllLevels))
|
||||
error("Failed to parse bool from cheats options");
|
||||
|
||||
if (!Common::parseBool(ConfMan.get("restored"), _restoredContentEnabled))
|
||||
error("Failed to parse bool from restored options");
|
||||
|
||||
// Only enable if subtitles are available
|
||||
if (!Common::parseBool(ConfMan.get("subtitles"), _useSubtitles))
|
||||
warning("Failed to parse bool from subtitles options");
|
||||
|
||||
// Add quit level
|
||||
Hotspot q(MakeMenu);
|
||||
Action *a = new Quit();
|
||||
q.actions.push_back(a);
|
||||
Scene *quit = new Scene();
|
||||
quit->hots.push_back(q);
|
||||
quit->resolution = "320x200";
|
||||
_levels["<quit>"] = quit;
|
||||
resetStatistics();
|
||||
}
|
||||
|
||||
HypnoEngine::~HypnoEngine() {
|
||||
// Deallocate actions
|
||||
// for (Levels::iterator it = _levels.begin(); it != _levels.end(); ++it) {
|
||||
// Level level = (*it)._value;
|
||||
// for (Hotspots::iterator itt = level.scene.hots.begin(); itt != level.scene.hots.end(); ++itt) {
|
||||
// Hotspot hot = *itt;
|
||||
// for (Actions::iterator ittt = hot.actions.begin(); ittt != hot.actions.end(); ++ittt)
|
||||
// delete (*ittt);
|
||||
// }
|
||||
// }
|
||||
|
||||
delete _rnd;
|
||||
delete _cursorCache;
|
||||
_compositeSurface->free();
|
||||
delete _compositeSurface;
|
||||
|
||||
delete g_parsedArc;
|
||||
}
|
||||
|
||||
void HypnoEngine::initializePath(const Common::FSNode &gamePath) {
|
||||
SearchMan.addDirectory(gamePath, 0, 10);
|
||||
}
|
||||
|
||||
LibFile *HypnoEngine::loadLib(const Common::Path &prefix, const Common::Path &filename, bool encrypted) {
|
||||
LibFile *lib = new LibFile();
|
||||
SearchMan.add(filename.toString(), (Common::Archive *)lib, 0, true);
|
||||
if (!lib->open(prefix, filename, encrypted)) {
|
||||
return nullptr;
|
||||
}
|
||||
_archive.push_back(lib);
|
||||
return lib;
|
||||
}
|
||||
|
||||
void HypnoEngine::loadAssets() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
Common::String HypnoEngine::findNextLevel(const Common::String &level) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
|
||||
Common::Error HypnoEngine::run() {
|
||||
Graphics::ModeList modes;
|
||||
modes.push_back(Graphics::Mode(640, 480));
|
||||
modes.push_back(Graphics::Mode(320, 200));
|
||||
initGraphicsModes(modes);
|
||||
|
||||
// Initialize graphics
|
||||
_pixelFormat = Graphics::PixelFormat::createFormatCLUT8();
|
||||
initGraphics(_screenW, _screenH, &_pixelFormat);
|
||||
|
||||
_compositeSurface = new Graphics::Surface();
|
||||
_compositeSurface->create(_screenW, _screenH, _pixelFormat);
|
||||
|
||||
// Main event loop
|
||||
loadAssets();
|
||||
|
||||
int saveSlot = ConfMan.getInt("save_slot");
|
||||
if (saveSlot >= 0) { // load the savegame
|
||||
loadGameState(saveSlot);
|
||||
}
|
||||
|
||||
assert(!_nextLevel.empty());
|
||||
while (!shouldQuit()) {
|
||||
debug("nextLevel: %s", _nextLevel.c_str());
|
||||
_prefixDir = "";
|
||||
_videosPlaying.clear();
|
||||
_videosLooping.clear();
|
||||
if (!_nextLevel.empty()) {
|
||||
_currentLevel = findNextLevel(_nextLevel);
|
||||
_nextLevel = "";
|
||||
_arcadeMode = "";
|
||||
runLevel(_currentLevel);
|
||||
} else
|
||||
g_system->delayMillis(300);
|
||||
}
|
||||
|
||||
// Only enable if subtitles are available
|
||||
bool useSubtitles = false;
|
||||
if (!Common::parseBool(ConfMan.get("subtitles"), useSubtitles))
|
||||
warning("Failed to parse bool from subtitles options");
|
||||
|
||||
if (useSubtitles) {
|
||||
g_system->showOverlay(false);
|
||||
}
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
void HypnoEngine::runLevel(Common::String &name) {
|
||||
if (!_levels.contains(name))
|
||||
error("Level %s cannot be found", name.c_str());
|
||||
|
||||
_prefixDir = _levels[name]->prefix;
|
||||
stopSound();
|
||||
stopMusic();
|
||||
|
||||
// Play intros
|
||||
disableCursor();
|
||||
|
||||
if (_levels[name]->playMusicDuringIntro && !_levels[name]->music.empty()) {
|
||||
playMusic(_levels[name]->music, _levels[name]->musicRate);
|
||||
}
|
||||
|
||||
debug("Number of videos to play: %d", _levels[name]->intros.size());
|
||||
for (Filenames::iterator it = _levels[name]->intros.begin(); it != _levels[name]->intros.end(); ++it) {
|
||||
MVideo v(*it, Common::Point(0, 0), false, true, false);
|
||||
runIntro(v);
|
||||
}
|
||||
|
||||
if (_levels[name]->type == TransitionLevel) {
|
||||
debugC(1, kHypnoDebugScene, "Executing transition level %s", name.c_str());
|
||||
runTransition((Transition *)_levels[name]);
|
||||
} else if (_levels[name]->type == ArcadeLevel) {
|
||||
debugC(1, kHypnoDebugArcade, "Executing arcade level %s", name.c_str());
|
||||
changeScreenMode("320x200");
|
||||
ArcadeShooting *arc = (ArcadeShooting *)_levels[name];
|
||||
runBeforeArcade(arc);
|
||||
runArcade(arc);
|
||||
runAfterArcade(arc);
|
||||
} else if (_levels[name]->type == CodeLevel) {
|
||||
debugC(1, kHypnoDebugScene, "Executing hardcoded level %s", name.c_str());
|
||||
// Resolution depends on the game
|
||||
runCode((Code *)_levels[name]);
|
||||
} else if (_levels[name]->type == SceneLevel) {
|
||||
debugC(1, kHypnoDebugScene, "Executing scene level %s with next level: %s", name.c_str(), _levels[name]->levelIfWin.c_str());
|
||||
runScene((Scene *)_levels[name]);
|
||||
} else {
|
||||
error("Invalid level %s", name.c_str());
|
||||
}
|
||||
}
|
||||
|
||||
void HypnoEngine::runIntros(Videos &videos) {
|
||||
debugC(1, kHypnoDebugScene, "Starting run intros with %d videos!", videos.size());
|
||||
Common::Event event;
|
||||
bool skip = false;
|
||||
int clicked[3] = {-1, -1, -1};
|
||||
int clicks = 0;
|
||||
|
||||
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it) {
|
||||
playVideo(*it);
|
||||
}
|
||||
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
disableGameKeymaps();
|
||||
keymapper->getKeymap("intro")->setEnabled(true);
|
||||
|
||||
while (!shouldQuit()) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
// Events
|
||||
switch (event.type) {
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType == kActionSkipIntro)
|
||||
skip = true;
|
||||
break;
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (videos.size() == 1) {
|
||||
int first = (clicks - 2) % 3;
|
||||
int last = clicks % 3;
|
||||
clicked[last] = videos[0].decoder->getCurFrame();
|
||||
if (clicks >= 2 && clicked[last] - clicked[first] <= 10)
|
||||
skip = true;
|
||||
clicks++;
|
||||
}
|
||||
break;
|
||||
case Common::EVENT_RBUTTONUP:
|
||||
setRButtonUp(true);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (skip) {
|
||||
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it) {
|
||||
if (it->decoder)
|
||||
skipVideo(*it);
|
||||
}
|
||||
videos.clear();
|
||||
}
|
||||
|
||||
bool playing = false;
|
||||
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it) {
|
||||
assert(!it->loop);
|
||||
if (it->decoder) {
|
||||
if (it->decoder->endOfVideo()) {
|
||||
it->decoder->close();
|
||||
delete it->decoder;
|
||||
it->decoder = nullptr;
|
||||
} else {
|
||||
playing = true;
|
||||
if (it->decoder->needsUpdate()) {
|
||||
updateScreen(*it);
|
||||
if (_subtitles && it->decoder && !it->decoder->isPaused())
|
||||
_subtitles->drawSubtitle(it->decoder->getTime(), false, false);
|
||||
|
||||
drawScreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!playing) {
|
||||
debugC(1, kHypnoDebugScene, "Not playing anymore!");
|
||||
break;
|
||||
}
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
for (Videos::iterator it = videos.begin(); it != videos.end(); ++it) {
|
||||
delete it->decoder;
|
||||
it->decoder = nullptr;
|
||||
}
|
||||
|
||||
keymapper->getKeymap("intro")->setEnabled(false);
|
||||
enableGameKeymaps();
|
||||
}
|
||||
|
||||
void HypnoEngine::runIntro(MVideo &video) {
|
||||
Common::Path path(video.path);
|
||||
loadSubtitles(path);
|
||||
Videos tmp;
|
||||
tmp.push_back(video);
|
||||
runIntros(tmp);
|
||||
|
||||
delete _subtitles;
|
||||
_subtitles = nullptr;
|
||||
g_system->hideOverlay();
|
||||
}
|
||||
|
||||
void HypnoEngine::runCode(Code *code) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
void HypnoEngine::showCredits() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
void HypnoEngine::loadGame(const Common::String &nextLevel, int score, int puzzleDifficulty, int combatDifficulty) {
|
||||
error("Function \"%s\" not implemented", __FUNCTION__);
|
||||
}
|
||||
|
||||
void HypnoEngine::loadFonts(const Common::String &prefix) {
|
||||
Common::File file;
|
||||
Common::Path path = Common::Path(prefix).append("block05.fgx");
|
||||
|
||||
if (!file.open(path))
|
||||
error("Cannot open font %s", path.toString().c_str());
|
||||
|
||||
byte *font = (byte *)malloc(file.size());
|
||||
file.read(font, file.size());
|
||||
|
||||
_font05.set_size(file.size()*8);
|
||||
_font05.set_bits((byte *)font);
|
||||
|
||||
file.close();
|
||||
free(font);
|
||||
path = Common::Path(prefix).append("scifi08.fgx");
|
||||
|
||||
if (!file.open(path))
|
||||
error("Cannot open font %s", path.toString().c_str());
|
||||
|
||||
font = (byte *)malloc(file.size());
|
||||
file.read(font, file.size());
|
||||
|
||||
_font08.set_size(file.size()*8);
|
||||
_font08.set_bits((byte *)font);
|
||||
|
||||
file.close();
|
||||
free(font);
|
||||
}
|
||||
|
||||
void HypnoEngine::drawString(const Filename &name, const Common::String &str, int x, int y, int w, uint32 c) {
|
||||
error("Function \"%s\" not implemented", __FUNCTION__);
|
||||
}
|
||||
|
||||
void HypnoEngine::loadImage(const Common::String &name, int x, int y, bool transparent, bool palette, int frameNumber) {
|
||||
|
||||
debugC(1, kHypnoDebugMedia, "%s(%s, %d, %d, %d)", __FUNCTION__, name.c_str(), x, y, transparent);
|
||||
Graphics::Surface *surf;
|
||||
if (palette) {
|
||||
byte *array;
|
||||
surf = decodeFrame(name, frameNumber, &array);
|
||||
loadPalette(array, 0, 256);
|
||||
free(array);
|
||||
} else
|
||||
surf = decodeFrame(name, frameNumber);
|
||||
|
||||
drawImage(*surf, x, y, transparent);
|
||||
|
||||
surf->free();
|
||||
delete surf;
|
||||
}
|
||||
|
||||
void HypnoEngine::drawImage(Graphics::Surface &surf, int x, int y, bool transparent) {
|
||||
Common::Rect srcRect(surf.w, surf.h);
|
||||
Common::Rect dstRect = srcRect;
|
||||
|
||||
dstRect.moveTo(x, y);
|
||||
_compositeSurface->clip(srcRect, dstRect);
|
||||
|
||||
if (transparent) {
|
||||
_compositeSurface->copyRectToSurfaceWithKey(surf, dstRect.left, dstRect.top, srcRect, _transparentColor);
|
||||
} else
|
||||
_compositeSurface->copyRectToSurface(surf, dstRect.left, dstRect.top, srcRect);
|
||||
}
|
||||
|
||||
Graphics::Surface *HypnoEngine::decodeFrame(const Common::String &name, int n, byte **palette) {
|
||||
Common::File *file = new Common::File();
|
||||
Common::Path path = convertPath(name);
|
||||
if (!_prefixDir.empty())
|
||||
path = _prefixDir.join(path);
|
||||
|
||||
if (!file->open(path))
|
||||
error("unable to find video file %s", path.toString().c_str());
|
||||
|
||||
HypnoSmackerDecoder vd;
|
||||
if (!vd.loadStream(file))
|
||||
error("unable to load video %s", path.toString().c_str());
|
||||
|
||||
for (int f = 0; f < n; f++)
|
||||
vd.decodeNextFrame();
|
||||
|
||||
const Graphics::Surface *frame = vd.decodeNextFrame();
|
||||
Graphics::Surface *rframe = frame->convertTo(frame->format, vd.getPalette());
|
||||
if (palette != nullptr) {
|
||||
byte *newPalette = (byte *)malloc(3 * 256);
|
||||
memcpy(newPalette, vd.getPalette(), 3 * 256);
|
||||
*palette = newPalette;
|
||||
}
|
||||
|
||||
return rframe;
|
||||
}
|
||||
|
||||
Frames HypnoEngine::decodeFrames(const Common::String &name) {
|
||||
Frames frames;
|
||||
Common::File *file = new Common::File();
|
||||
Common::Path path = convertPath(name);
|
||||
if (!_prefixDir.empty())
|
||||
path = _prefixDir.join(path);
|
||||
|
||||
if (!file->open(path))
|
||||
error("unable to find video file %s", path.toString().c_str());
|
||||
|
||||
HypnoSmackerDecoder vd;
|
||||
if (!vd.loadStream(file))
|
||||
error("unable to load video %s", path.toString().c_str());
|
||||
|
||||
const Graphics::Surface *frame = nullptr;
|
||||
Graphics::Surface *rframe = nullptr;
|
||||
|
||||
while (!vd.endOfVideo()) {
|
||||
frame = vd.decodeNextFrame();
|
||||
rframe = frame->convertTo(_pixelFormat, vd.getPalette());
|
||||
frames.push_back(rframe);
|
||||
}
|
||||
return frames;
|
||||
}
|
||||
|
||||
void HypnoEngine::changeScreenMode(const Common::String &mode) {
|
||||
debugC(1, kHypnoDebugMedia, "%s(%s)", __FUNCTION__, mode.c_str());
|
||||
if (mode == "640x480") {
|
||||
if (_screenW == 640 && _screenH == 480)
|
||||
return;
|
||||
|
||||
_screenW = 640;
|
||||
_screenH = 480;
|
||||
|
||||
initGraphics(_screenW, _screenH, &_pixelFormat);
|
||||
|
||||
_compositeSurface->free();
|
||||
delete _compositeSurface;
|
||||
|
||||
_compositeSurface = new Graphics::Surface();
|
||||
_compositeSurface->create(_screenW, _screenH, _pixelFormat);
|
||||
} else if (mode == "320x200") {
|
||||
if (_screenW == 320 && _screenH == 200)
|
||||
return;
|
||||
|
||||
_screenW = 320;
|
||||
_screenH = 200;
|
||||
|
||||
initGraphics(_screenW, _screenH, &_pixelFormat);
|
||||
|
||||
_compositeSurface->free();
|
||||
delete _compositeSurface;
|
||||
|
||||
_compositeSurface = new Graphics::Surface();
|
||||
_compositeSurface->create(_screenW, _screenH, _pixelFormat);
|
||||
} else
|
||||
error("Unknown screen mode %s", mode.c_str());
|
||||
}
|
||||
|
||||
void HypnoEngine::loadPalette(const Common::String &fname) {
|
||||
Common::File file;
|
||||
Common::Path path = convertPath(fname);
|
||||
if (!_prefixDir.empty())
|
||||
path = _prefixDir.join(path);
|
||||
|
||||
if (!file.open(path))
|
||||
error("unable to find palette file %s", path.toString().c_str());
|
||||
|
||||
debugC(1, kHypnoDebugMedia, "Loading palette from %s", path.toString().c_str());
|
||||
byte *videoPalette = (byte *)malloc(file.size());
|
||||
file.read(videoPalette, file.size());
|
||||
g_system->getPaletteManager()->setPalette(videoPalette + 8, 0, 256);
|
||||
}
|
||||
|
||||
void HypnoEngine::loadPalette(const byte *palette, uint32 offset, uint32 size) {
|
||||
debugC(1, kHypnoDebugMedia, "Loading palette from byte array with offset %d and size %d", offset, size);
|
||||
g_system->getPaletteManager()->setPalette(palette, offset, size);
|
||||
}
|
||||
|
||||
|
||||
byte *HypnoEngine::getPalette(uint32 idx) {
|
||||
byte *videoPalette = (byte *)malloc(3);
|
||||
g_system->getPaletteManager()->grabPalette(videoPalette, idx, 1);
|
||||
return videoPalette;
|
||||
}
|
||||
|
||||
void HypnoEngine::updateVideo(MVideo &video) {
|
||||
video.decoder->decodeNextFrame();
|
||||
}
|
||||
|
||||
void HypnoEngine::updateScreen(MVideo &video) {
|
||||
const Graphics::Surface *frame = video.decoder->decodeNextFrame();
|
||||
bool dirtyPalette = video.decoder->hasDirtyPalette();
|
||||
bool isFullscreen = (frame->w == _screenW && frame->h == _screenH);
|
||||
|
||||
if (frame->h == 0 || frame->w == 0 || video.decoder->getPalette() == nullptr)
|
||||
return;
|
||||
|
||||
const byte *videoPalette = nullptr;
|
||||
if (video.scaled && dirtyPalette) {
|
||||
debugC(1, kHypnoDebugMedia, "Updating palette at frame %d", video.decoder->getCurFrame());
|
||||
videoPalette = video.decoder->getPalette();
|
||||
g_system->getPaletteManager()->setPalette(videoPalette, 0, 256);
|
||||
}
|
||||
|
||||
if (video.scaled && !isFullscreen) {
|
||||
Graphics::Surface *sframe = frame->scale(_screenW, _screenH);
|
||||
Common::Rect srcRect(sframe->w, sframe->h);
|
||||
Common::Rect dstRect = srcRect;
|
||||
|
||||
dstRect.moveTo(video.position);
|
||||
_compositeSurface->clip(srcRect, dstRect);
|
||||
|
||||
if (video.transparent) {
|
||||
_compositeSurface->copyRectToSurfaceWithKey(*sframe, dstRect.left, dstRect.top, srcRect, _transparentColor);
|
||||
} else {
|
||||
_compositeSurface->copyRectToSurface(*sframe, dstRect.left, dstRect.top, srcRect);
|
||||
}
|
||||
|
||||
sframe->free();
|
||||
delete sframe;
|
||||
} else {
|
||||
Common::Rect srcRect(frame->w, frame->h);
|
||||
Common::Rect dstRect = srcRect;
|
||||
|
||||
dstRect.moveTo(video.position);
|
||||
_compositeSurface->clip(srcRect, dstRect);
|
||||
|
||||
if (video.transparent) {
|
||||
_compositeSurface->copyRectToSurfaceWithKey(*frame, dstRect.left, dstRect.top, srcRect, _transparentColor);
|
||||
} else {
|
||||
_compositeSurface->copyRectToSurface(*frame, dstRect.left, dstRect.top, srcRect);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HypnoEngine::drawScreen() {
|
||||
g_system->copyRectToScreen(_compositeSurface->getPixels(), _compositeSurface->pitch, 0, 0, _screenW, _screenH);
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
// Video handling
|
||||
|
||||
void HypnoEngine::adjustSubtitleSize() {
|
||||
debugC(1, kHypnoDebugMedia, "%s()", __FUNCTION__);
|
||||
if (_subtitles) {
|
||||
// Subtitle positioning constants (as percentages of screen height)
|
||||
const int HORIZONTAL_MARGIN = 20;
|
||||
const float BOTTOM_MARGIN_PERCENT = 0.009f; // ~20px at 2160p
|
||||
const float SUBTITLE_HEIGHT_PERCENT = 0.102f; // ~220px at 2160p
|
||||
|
||||
// Font sizing constants (as percentage of screen height)
|
||||
const int MIN_FONT_SIZE = 8;
|
||||
const float BASE_FONT_SIZE_PERCENT = 0.023f; // ~50px at 2160p
|
||||
|
||||
int16 h = g_system->getOverlayHeight();
|
||||
int16 w = g_system->getOverlayWidth();
|
||||
|
||||
int bottomMargin = int(h * BOTTOM_MARGIN_PERCENT);
|
||||
int topOffset = int(h * SUBTITLE_HEIGHT_PERCENT);
|
||||
|
||||
_subtitles->setBBox(Common::Rect(HORIZONTAL_MARGIN, h - topOffset, w - HORIZONTAL_MARGIN, h - bottomMargin));
|
||||
|
||||
int fontSize = MAX(MIN_FONT_SIZE, int(h * BASE_FONT_SIZE_PERCENT));
|
||||
_subtitles->setColor(0xff, 0xff, 0x80);
|
||||
_subtitles->setFont("NotoSerif-Regular.ttf", fontSize, Video::Subtitles::kFontStyleRegular);
|
||||
_subtitles->setFont("NotoSerif-Italic.ttf", fontSize, Video::Subtitles::kFontStyleItalic);
|
||||
}
|
||||
}
|
||||
|
||||
void HypnoEngine::loadSubtitles(const Common::Path &path) {
|
||||
debugC(1, kHypnoDebugMedia, "%s(%s)", __FUNCTION__, path.toString().c_str());
|
||||
if (!_useSubtitles)
|
||||
return;
|
||||
|
||||
debug("Subtitle path: %s", path.toString().c_str());
|
||||
Common::String subPathStr = path.toString() + ".srt";
|
||||
subPathStr.toLowercase();
|
||||
subPathStr.replace('/', '_');
|
||||
subPathStr.replace('\\', '_');
|
||||
Common::String language(Common::getLanguageCode(_language));
|
||||
if (language == "us")
|
||||
language = "en";
|
||||
|
||||
Common::Path subPath = "subtitles";
|
||||
subPath = subPath.appendComponent(language);
|
||||
subPath = subPath.appendComponent(subPathStr);
|
||||
debugC(1, kHypnoDebugMedia, "Loading subtitles from %s", subPath.toString().c_str());
|
||||
|
||||
if (_subtitles != nullptr) {
|
||||
delete _subtitles;
|
||||
_subtitles = nullptr;
|
||||
g_system->hideOverlay();
|
||||
}
|
||||
|
||||
_subtitles = new Video::Subtitles();
|
||||
_subtitles->loadSRTFile(subPath);
|
||||
if (!_subtitles->isLoaded()) {
|
||||
delete _subtitles;
|
||||
_subtitles = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
g_system->showOverlay(false);
|
||||
g_system->clearOverlay();
|
||||
adjustSubtitleSize();
|
||||
}
|
||||
|
||||
|
||||
void HypnoEngine::playVideo(MVideo &video) {
|
||||
debugC(1, kHypnoDebugMedia, "%s(%s)", __FUNCTION__, video.path.c_str());
|
||||
Common::File *file = new Common::File();
|
||||
Common::Path path = convertPath(video.path);
|
||||
if (!_prefixDir.empty())
|
||||
path = _prefixDir.join(path);
|
||||
|
||||
if (!file->open(path))
|
||||
error("unable to find video file %s", path.toString().c_str());
|
||||
|
||||
if (video.decoder != nullptr) {
|
||||
debugC(1, kHypnoDebugMedia, "Restarting %s!!!!", video.path.c_str());
|
||||
delete video.decoder;
|
||||
}
|
||||
// error("Video %s was not previously closed and deallocated", video.path.c_str());
|
||||
|
||||
video.decoder = new HypnoSmackerDecoder();
|
||||
|
||||
if (!video.decoder->loadStream(file))
|
||||
error("unable to load video %s", path.toString().c_str());
|
||||
|
||||
debugC(1, kHypnoDebugMedia, "audio track count: %d", video.decoder->getAudioTrackCount());
|
||||
video.decoder->start();
|
||||
}
|
||||
|
||||
void HypnoEngine::skipVideo(MVideo &video) {
|
||||
if (!video.decoder)
|
||||
return;
|
||||
debugC(1, kHypnoDebugMedia, "%s()", __FUNCTION__);
|
||||
video.decoder->close();
|
||||
delete video.decoder;
|
||||
video.decoder = nullptr;
|
||||
}
|
||||
|
||||
// Sound handling
|
||||
Audio::SeekableAudioStream *HypnoEngine::loadAudioStream(const Common::String &filename, uint32 sampleRate, bool stereo) {
|
||||
debugC(1, kHypnoDebugMedia, "%s(%s, %d)", __FUNCTION__, filename.c_str(), sampleRate);
|
||||
Common::Path name = convertPath(filename);
|
||||
|
||||
Common::File *file = new Common::File();
|
||||
if (file->open(name)) {
|
||||
uint32 flags = Audio::FLAG_UNSIGNED;
|
||||
|
||||
Common::SeekableSubReadStream *sub;
|
||||
if (stereo) {
|
||||
sub = new Common::SeekableSubReadStream(file, 0, file->size() - (file->size() % 2), DisposeAfterUse::YES);
|
||||
flags = flags | Audio::FLAG_STEREO;
|
||||
} else {
|
||||
sub = new Common::SeekableSubReadStream(file, 0, file->size(), DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
return Audio::makeRawStream(sub, sampleRate, flags, DisposeAfterUse::YES);
|
||||
} else {
|
||||
if (!_prefixDir.empty())
|
||||
name = _prefixDir.join(name);
|
||||
if (file->open(name)) {
|
||||
return Audio::makeRawStream(file, sampleRate, Audio::FLAG_UNSIGNED, DisposeAfterUse::YES);
|
||||
} else {
|
||||
debugC(1, kHypnoDebugMedia, "%s not found!", name.toString().c_str());
|
||||
delete file;
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HypnoEngine::playSound(const Common::String &filename, uint32 loops, uint32 sampleRate, bool stereo) {
|
||||
Audio::SeekableAudioStream *stream = loadAudioStream(filename, sampleRate, stereo);
|
||||
if (!stream)
|
||||
return;
|
||||
_mixer->stopHandle(_soundHandle);
|
||||
Audio::LoopingAudioStream *loopstream = new Audio::LoopingAudioStream(stream, loops);
|
||||
_mixer->playStream(Audio::Mixer::kSFXSoundType, &_soundHandle, loopstream, -1, Audio::Mixer::kMaxChannelVolume);
|
||||
}
|
||||
|
||||
void HypnoEngine::playMusic(const Common::String &filename, uint32 sampleRate, bool stereo) {
|
||||
Audio::SeekableAudioStream *stream = loadAudioStream(filename, sampleRate, stereo);
|
||||
if (!stream)
|
||||
return;
|
||||
_mixer->stopHandle(_musicHandle);
|
||||
Audio::LoopingAudioStream *loopstream = new Audio::LoopingAudioStream(stream, 0);
|
||||
_mixer->playStream(Audio::Mixer::kMusicSoundType, &_musicHandle, loopstream, -1, Audio::Mixer::kMaxChannelVolume);
|
||||
}
|
||||
|
||||
void HypnoEngine::stopSound() {
|
||||
debugC(1, kHypnoDebugMedia, "%s()", __FUNCTION__);
|
||||
_mixer->stopHandle(_soundHandle);
|
||||
}
|
||||
|
||||
void HypnoEngine::stopMusic() {
|
||||
debugC(1, kHypnoDebugMedia, "%s()", __FUNCTION__);
|
||||
_mixer->stopHandle(_musicHandle);
|
||||
}
|
||||
|
||||
bool HypnoEngine::isMusicActive() {
|
||||
return _mixer->isSoundHandleActive(_musicHandle);
|
||||
}
|
||||
|
||||
// Path handling
|
||||
|
||||
Common::Path HypnoEngine::convertPath(const Common::String &name) {
|
||||
Common::String path(name);
|
||||
Common::String s1("\\");
|
||||
Common::String s2("/");
|
||||
|
||||
while (path.contains(s1))
|
||||
Common::replace(path, s1, s2);
|
||||
|
||||
s1 = Common::String("\"");
|
||||
s2 = Common::String("");
|
||||
|
||||
Common::replace(path, s1, s2);
|
||||
Common::replace(path, s1, s2);
|
||||
|
||||
path.toLowercase();
|
||||
return Common::Path(path);
|
||||
}
|
||||
|
||||
// Timers
|
||||
static void alarmCallback(void *refCon) {
|
||||
g_system->getTimerManager()->removeTimerProc(&alarmCallback);
|
||||
Common::String *level = (Common::String *)refCon;
|
||||
g_hypno->_nextLevel = *level;
|
||||
delete level;
|
||||
}
|
||||
|
||||
static void countdownCallback(void *refCon) {
|
||||
g_hypno->_countdown = g_hypno->_countdown - 1;
|
||||
}
|
||||
|
||||
bool HypnoEngine::startAlarm(uint32 delay, Common::String *ns) {
|
||||
return g_system->getTimerManager()->installTimerProc(&alarmCallback, delay, (void *)ns, "alarm");
|
||||
}
|
||||
|
||||
bool HypnoEngine::startCountdown(uint32 delay) {
|
||||
_countdown = delay;
|
||||
_timerStarted = true;
|
||||
uint32 oneSecond = 1000000;
|
||||
return g_system->getTimerManager()->installTimerProc(&countdownCallback, oneSecond, 0x0, "countdown");
|
||||
}
|
||||
|
||||
void HypnoEngine::removeTimers() {
|
||||
_timerStarted = false;
|
||||
_keepTimerDuringScenes = false;
|
||||
g_system->getTimerManager()->removeTimerProc(&alarmCallback);
|
||||
g_system->getTimerManager()->removeTimerProc(&countdownCallback);
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
734
engines/hypno/hypno.h
Normal file
734
engines/hypno/hypno.h
Normal file
@@ -0,0 +1,734 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HYPNO_H
|
||||
#define HYPNO_H
|
||||
|
||||
#include "common/array.h"
|
||||
#include "common/compression/installshieldv3_archive.h"
|
||||
#include "common/random.h"
|
||||
#include "common/serializer.h"
|
||||
#include "common/str-array.h"
|
||||
#include "common/stream.h"
|
||||
#include "engines/engine.h"
|
||||
#include "graphics/font.h"
|
||||
#include "graphics/fontman.h"
|
||||
#include "graphics/surface.h"
|
||||
#include "video/subtitles.h"
|
||||
|
||||
#include "hypno/grammar.h"
|
||||
#include "hypno/libfile.h"
|
||||
|
||||
namespace Audio {
|
||||
class SeekableAudioStream;
|
||||
}
|
||||
|
||||
namespace Image {
|
||||
class ImageDecoder;
|
||||
}
|
||||
|
||||
struct ADGameDescription;
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
// debug channels
|
||||
enum {
|
||||
kHypnoDebugMedia = 1,
|
||||
kHypnoDebugParser,
|
||||
kHypnoDebugArcade,
|
||||
kHypnoDebugScene,
|
||||
};
|
||||
|
||||
// Player positions
|
||||
|
||||
enum PlayerPosition {
|
||||
kPlayerTop = 'T',
|
||||
kPlayerBottom = 'B',
|
||||
kPlayerLeft = 'L',
|
||||
kPlayerRight = 'R'
|
||||
};
|
||||
|
||||
// Common colors
|
||||
enum HypnoColors {
|
||||
kHypnoNoColor = -1,
|
||||
kHypnoColorRed = 250,
|
||||
kHypnoColorGreen = 251,
|
||||
kHypnoColorWhiteOrBlue = 252,
|
||||
kHypnoColorYellow = 253,
|
||||
kHypnoColorBlack = 254,
|
||||
kHypnoColorCyan = 255
|
||||
};
|
||||
|
||||
// Spider colors
|
||||
enum SpiderColors {
|
||||
kSpiderColorWhite = 248,
|
||||
kSpiderColorBlue = 252,
|
||||
};
|
||||
|
||||
enum HYPNOActions {
|
||||
kActionNone,
|
||||
kActionSkipIntro,
|
||||
kActionSkipCutscene,
|
||||
kActionPrimaryShoot,
|
||||
kActionSkipLevel,
|
||||
kActionKillPlayer,
|
||||
kActionPause,
|
||||
kActionLeft,
|
||||
kActionDown,
|
||||
kActionRight,
|
||||
kActionUp,
|
||||
kActionYes,
|
||||
kActionNo,
|
||||
kActionDifficultyChump,
|
||||
kActionDifficultyPunk,
|
||||
kActionDifficultyBadass,
|
||||
kActionDifficultExit,
|
||||
kActionRetry,
|
||||
kActionRestart,
|
||||
kActionNewMission,
|
||||
kActionQuit,
|
||||
kActionCredits,
|
||||
kActionSelect,
|
||||
};
|
||||
|
||||
class HypnoEngine;
|
||||
|
||||
class CursorCache {
|
||||
private:
|
||||
HypnoEngine *_vm;
|
||||
Common::String _filename;
|
||||
uint32 _frame;
|
||||
byte *_palette;
|
||||
Graphics::Surface *_surface;
|
||||
|
||||
public:
|
||||
CursorCache(HypnoEngine *vm) : _vm(vm), _filename(""), _frame(0), _palette(nullptr), _surface(nullptr) {}
|
||||
|
||||
~CursorCache() {
|
||||
if (_surface) {
|
||||
_surface->free();
|
||||
delete _surface;
|
||||
}
|
||||
free(_palette);
|
||||
}
|
||||
|
||||
Graphics::Surface *getCursor(const Common::String &cursor, uint32 n, byte **palette);
|
||||
};
|
||||
|
||||
class HypnoEngine : public Engine {
|
||||
private:
|
||||
Image::ImageDecoder *_image;
|
||||
|
||||
public:
|
||||
HypnoEngine(OSystem *syst, const ADGameDescription *gd);
|
||||
~HypnoEngine();
|
||||
|
||||
const ADGameDescription *_gameDescription;
|
||||
bool isDemo() const;
|
||||
Common::Language _language;
|
||||
Common::Platform _platform;
|
||||
Common::String _variant;
|
||||
bool _cheatsEnabled;
|
||||
bool _infiniteHealthCheat;
|
||||
bool _infiniteAmmoCheat;
|
||||
bool _unlockAllLevels;
|
||||
bool _restoredContentEnabled;
|
||||
|
||||
Audio::SoundHandle _soundHandle, _musicHandle;
|
||||
Common::InstallShieldV3 _installerArchive;
|
||||
Common::List<LibFile*> _archive;
|
||||
|
||||
Common::Error run() override;
|
||||
Levels _levels;
|
||||
Common::HashMap<Common::String, int> _sceneState;
|
||||
virtual void resetSceneState();
|
||||
bool checkSceneCompleted();
|
||||
bool checkLevelWon();
|
||||
void runLevel(Common::String &name);
|
||||
void runScene(Scene *scene);
|
||||
virtual void runBeforeArcade(ArcadeShooting *arc);
|
||||
virtual void runAfterArcade(ArcadeShooting *arc);
|
||||
void runArcade(ArcadeShooting *arc);
|
||||
// For some menus and hardcoded puzzles
|
||||
virtual void runCode(Code *code);
|
||||
// Level transitions
|
||||
void runTransition(Transition *trans);
|
||||
|
||||
void restartGame();
|
||||
void clearAreas();
|
||||
void initializePath(const Common::FSNode &gamePath) override;
|
||||
virtual void loadAssets();
|
||||
|
||||
// Parsing
|
||||
void splitArcadeFile(const Common::String &filename, Common::String &arc, Common::String &list);
|
||||
void parseArcadeShooting(const Common::String &prefix, const Common::String &name, const Common::String &data);
|
||||
SegmentShootsSequence parseShootList(const Common::String &name, const Common::String &data);
|
||||
void loadArcadeLevel(const Common::String ¤t, const Common::String &nextWin, const Common::String &nextLose, const Common::String &prefix);
|
||||
void loadSceneLevel(const Common::String ¤t, const Common::String &next, const Common::String &prefix);
|
||||
void loadSceneLevel(const char *buf, const Common::String &name, const Common::String &next, const Common::String &prefix);
|
||||
|
||||
LibFile *loadLib(const Common::Path &prefix, const Common::Path &filename, bool encrypted);
|
||||
|
||||
// User input
|
||||
void clickedHotspot(Common::Point);
|
||||
virtual bool hoverHotspot(Common::Point);
|
||||
|
||||
// Cursors
|
||||
bool cursorPauseMovie(Common::Point);
|
||||
bool cursorExit(Common::Point);
|
||||
bool cursorMask(Common::Point);
|
||||
|
||||
virtual void loadGame(const Common::String &nextLevel, int score, int puzzleDifficulty, int combatDifficulty);
|
||||
bool canLoadGameStateCurrently(Common::U32String *msg = nullptr) override { return (isDemo() ? false : true); }
|
||||
bool canSaveAutosaveCurrently() override { return false; }
|
||||
bool canSaveGameStateCurrently(Common::U32String *msg = nullptr) override { return (isDemo() ? false : true); }
|
||||
Common::String _checkpoint;
|
||||
|
||||
bool _useSubtitles;
|
||||
Video::Subtitles *_subtitles;
|
||||
void adjustSubtitleSize();
|
||||
void loadSubtitles(const Common::Path &path);
|
||||
|
||||
Common::Path _prefixDir;
|
||||
Common::Path convertPath(const Common::String &);
|
||||
void playVideo(MVideo &video);
|
||||
void skipVideo(MVideo &video);
|
||||
|
||||
Graphics::Surface *decodeFrame(const Common::String &name, int frame, byte **palette = nullptr);
|
||||
Frames decodeFrames(const Common::String &name);
|
||||
void loadImage(const Common::String &file, int x, int y, bool transparent, bool palette = false, int frameNumber = 0);
|
||||
void drawImage(Graphics::Surface &image, int x, int y, bool transparent);
|
||||
void loadPalette(const Common::String &fname);
|
||||
void loadPalette(const byte *palette, uint32 offset, uint32 size);
|
||||
byte *getPalette(uint32 idx);
|
||||
|
||||
// Cursors
|
||||
Common::String _defaultCursor;
|
||||
uint32 _defaultCursorIdx;
|
||||
CursorCache *_cursorCache;
|
||||
void disableCursor();
|
||||
void defaultCursor();
|
||||
virtual void changeCursor(const Common::String &cursor, uint32 n, bool centerCursor = false);
|
||||
virtual void changeCursor(const Common::String &cursor);
|
||||
virtual void changeCursor(const Graphics::Surface &entry, byte *palette, bool centerCursor = false);
|
||||
|
||||
// Actions
|
||||
virtual void runMenu(Hotspots *hs, bool only_menu = false);
|
||||
void runBackground(Background *a);
|
||||
void runOverlay(Overlay *a);
|
||||
void runMice(Mice *a);
|
||||
void runEscape();
|
||||
void runSave(Save *a);
|
||||
void runLoad(Load *a);
|
||||
void runLoadCheckpoint(LoadCheckpoint *a);
|
||||
void runTimer(Timer *a);
|
||||
void runQuit(Quit *a);
|
||||
void runCutscene(Cutscene *a);
|
||||
void runIntro(Intro *a);
|
||||
void runPlay(Play *a);
|
||||
void runSound(Sound *a);
|
||||
void runPalette(Palette *a);
|
||||
void runAmbient(Ambient *a);
|
||||
void runWalN(WalN *a);
|
||||
bool runGlobal(Global *a);
|
||||
void runTalk(Talk *a);
|
||||
void runSwapPointer(SwapPointer *a);
|
||||
void runChangeLevel(ChangeLevel *a);
|
||||
virtual void drawBackToMenu(Hotspot *h);
|
||||
|
||||
// Screen
|
||||
int _screenW, _screenH;
|
||||
Graphics::PixelFormat _pixelFormat;
|
||||
void changeScreenMode(const Common::String &mode);
|
||||
Graphics::Surface *_compositeSurface;
|
||||
uint32 _transparentColor;
|
||||
Common::Rect screenRect;
|
||||
void updateScreen(MVideo &video);
|
||||
void updateVideo(MVideo &video);
|
||||
void drawScreen();
|
||||
|
||||
// intros
|
||||
void runIntro(MVideo &video);
|
||||
void runIntros(Videos &videos);
|
||||
Common::HashMap<Filename, bool> _intros;
|
||||
|
||||
// levels
|
||||
Common::String _nextLevel;
|
||||
Common::String _currentLevel;
|
||||
virtual Common::String findNextLevel(const Common::String &level);
|
||||
virtual Common::String findNextLevel(const Transition *trans);
|
||||
uint32 _levelId;
|
||||
|
||||
// hotspots
|
||||
Hotspots *_nextHotsToAdd;
|
||||
Hotspots *_nextHotsToRemove;
|
||||
HotspotsStack stack;
|
||||
|
||||
// Movies
|
||||
Videos _nextSequentialVideoToPlay;
|
||||
Videos _nextParallelVideoToPlay;
|
||||
Videos _escapeSequentialVideoToPlay;
|
||||
Videos _videosPlaying;
|
||||
Videos _videosLooping;
|
||||
MVideo *_masks;
|
||||
MVideo *_additionalVideo;
|
||||
const Graphics::Surface *_mask;
|
||||
|
||||
// Sounds
|
||||
Filename _soundPath;
|
||||
Audio::SeekableAudioStream *loadAudioStream(const Filename &filename, uint32 sampleRate = 22050, bool stereo = false);
|
||||
void playSound(const Filename &filename, uint32 loops, uint32 sampleRate = 22050, bool stereo = false);
|
||||
void playMusic(const Filename &filename, uint32 sampleRate = 22050, bool stereo = false);
|
||||
void stopSound();
|
||||
void stopMusic();
|
||||
bool isMusicActive();
|
||||
|
||||
// Arcade
|
||||
Common::String _arcadeMode;
|
||||
MVideo *_background;
|
||||
Filename _currentPalette;
|
||||
virtual bool availableObjectives();
|
||||
virtual bool checkArcadeObjectives();
|
||||
ArcadeTransitions _transitions;
|
||||
virtual bool checkTransition(ArcadeTransitions &transitions, ArcadeShooting *arc);
|
||||
virtual Common::Point getPlayerPosition(bool needsUpdate);
|
||||
virtual Common::Point computeTargetPosition(const Common::Point &mousePos);
|
||||
virtual int detectTarget(const Common::Point &mousePos);
|
||||
virtual void pressedKey(const int keycode);
|
||||
virtual bool clickedPrimaryShoot(const Common::Point &mousePos);
|
||||
virtual bool clickedSecondaryShoot(const Common::Point &mousePos);
|
||||
virtual void drawShoot(const Common::Point &mousePos);
|
||||
virtual bool shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool secondary);
|
||||
virtual void hitPlayer();
|
||||
virtual void missedTarget(Shoot *s, ArcadeShooting *arc);
|
||||
virtual void missNoTarget(ArcadeShooting *arc);
|
||||
virtual byte *getTargetColor(Common::String name, int levelId);
|
||||
virtual bool checkRButtonUp();
|
||||
virtual void setRButtonUp(const bool val);
|
||||
virtual void disableGameKeymaps();
|
||||
virtual void enableGameKeymaps();
|
||||
|
||||
// Segments
|
||||
Segments _segments;
|
||||
uint32 _segmentIdx;
|
||||
uint32 _segmentOffset;
|
||||
uint32 _segmentRepetition;
|
||||
uint32 _segmentRepetitionMax;
|
||||
uint32 _segmentShootSequenceOffset;
|
||||
uint32 _segmentShootSequenceMax;
|
||||
ShootSequence _shootSequence;
|
||||
virtual void findNextSegment(ArcadeShooting *arc);
|
||||
virtual void initSegment(ArcadeShooting *arc);
|
||||
|
||||
ArcadeStats _stats;
|
||||
void resetStatistics();
|
||||
void incLivesUsed();
|
||||
void incShotsFired();
|
||||
void incEnemyHits();
|
||||
void incEnemyTargets();
|
||||
void incTargetsDestroyed();
|
||||
void incTargetsMissed();
|
||||
void incFriendliesEncountered();
|
||||
void incInfoReceived();
|
||||
|
||||
void incScore(int inc);
|
||||
void incBonus(int inc);
|
||||
|
||||
uint32 killRatio();
|
||||
uint32 accuracyRatio();
|
||||
|
||||
Common::String _difficulty;
|
||||
bool _skipLevel;
|
||||
bool _loseLevel;
|
||||
bool _skipDefeatVideo;
|
||||
bool _skipNextVideo;
|
||||
|
||||
virtual void drawCursorArcade(const Common::Point &mousePos);
|
||||
virtual void drawPlayer();
|
||||
virtual void drawHealth();
|
||||
virtual void drawAmmo();
|
||||
int _health;
|
||||
int _maxHealth;
|
||||
|
||||
int _ammo;
|
||||
int _maxAmmo;
|
||||
|
||||
int _score;
|
||||
int _bonus;
|
||||
int _lives;
|
||||
|
||||
Common::String _healthString;
|
||||
Common::String _scoreString;
|
||||
Common::String _objString;
|
||||
Common::String _targetString;
|
||||
Common::String _directionString;
|
||||
Common::String _enterNameString;
|
||||
|
||||
Filename _shootSound;
|
||||
Filename _hitSound;
|
||||
Filename _additionalSound;
|
||||
Shoots _shoots;
|
||||
Frames _playerFrames;
|
||||
int _playerFrameIdx;
|
||||
Common::List<int> _playerFrameSeps;
|
||||
int _playerFrameStart;
|
||||
int _playerFrameSep;
|
||||
int _playerFrameEnd;
|
||||
|
||||
// Objectives
|
||||
uint32 _objIdx;
|
||||
uint32 _objKillsCount[2];
|
||||
uint32 _objMissesCount[2];
|
||||
uint32 _objKillsRequired[2];
|
||||
uint32 _objMissesAllowed[2];
|
||||
|
||||
// Fonts
|
||||
Common::BitArray _font05;
|
||||
Common::BitArray _font08;
|
||||
virtual void loadFonts(const Common::String &prefix = "");
|
||||
virtual void drawString(const Filename &name, const Common::String &str, int x, int y, int w, uint32 c);
|
||||
|
||||
// Conversation
|
||||
Actions _conversation;
|
||||
bool _refreshConversation;
|
||||
virtual void showConversation();
|
||||
virtual void endConversation();
|
||||
virtual void rightClickedConversation(const Common::Point &mousePos);
|
||||
virtual void leftClickedConversation(const Common::Point &mousePos);
|
||||
virtual bool hoverConversation(const Common::Point &mousePos);
|
||||
// Credits
|
||||
virtual void showCredits();
|
||||
|
||||
// Timers
|
||||
int32 _countdown;
|
||||
bool _timerStarted;
|
||||
bool _keepTimerDuringScenes;
|
||||
bool startAlarm(uint32, Common::String *);
|
||||
bool startCountdown(uint32);
|
||||
void removeTimers();
|
||||
|
||||
// Random
|
||||
Common::RandomSource *_rnd;
|
||||
};
|
||||
|
||||
struct chapterEntry {
|
||||
int id;
|
||||
int energyPos[2];
|
||||
int scorePos[2];
|
||||
int objectivesPos[2];
|
||||
int ammoPos[2];
|
||||
int ammoOffset;
|
||||
int targetColor;
|
||||
};
|
||||
|
||||
class WetEngine : public HypnoEngine {
|
||||
public:
|
||||
WetEngine(OSystem *syst, const ADGameDescription *gd);
|
||||
~WetEngine();
|
||||
Common::HashMap<int, const struct chapterEntry*> _chapterTable;
|
||||
Common::Array<int> _ids;
|
||||
int _lastLevel;
|
||||
Common::String _name;
|
||||
|
||||
void loadAssets() override;
|
||||
void loadAssetsDemoDisc();
|
||||
void loadAssetsEarlyDemo();
|
||||
void loadAssetsGen4();
|
||||
void loadAssetsPCW();
|
||||
void loadAssetsPCG();
|
||||
void loadAssetsFullGame();
|
||||
void loadAssetsNI();
|
||||
|
||||
void loadFonts(const Common::String &prefix = "") override;
|
||||
void drawString(const Filename &name, const Common::String &str, int x, int y, int w, uint32 c) override;
|
||||
void changeCursor(const Common::String &cursor) override;
|
||||
|
||||
void showCredits() override;
|
||||
bool clickedSecondaryShoot(const Common::Point &mousePos) override;
|
||||
void drawShoot(const Common::Point &target) override;
|
||||
void drawPlayer() override;
|
||||
void drawHealth() override;
|
||||
void drawAmmo() override;
|
||||
void hitPlayer() override;
|
||||
void drawCursorArcade(const Common::Point &mousePos) override;
|
||||
Common::Point computeTargetPosition(const Common::Point &mousePos) override;
|
||||
void missedTarget(Shoot *s, ArcadeShooting *arc) override;
|
||||
void missNoTarget(ArcadeShooting *arc) override;
|
||||
|
||||
void runCode(Code *code) override;
|
||||
Common::String findNextLevel(const Common::String &level) override;
|
||||
Common::String findNextLevel(const Transition *trans) override;
|
||||
|
||||
// Saves
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
|
||||
bool loadProfile(const Common::String &name);
|
||||
void saveProfile(const Common::String &name, int levelId);
|
||||
|
||||
// Arcade
|
||||
Common::Point getPlayerPosition(bool needsUpdate) override;
|
||||
bool checkTransition(ArcadeTransitions &transitions, ArcadeShooting *arc) override;
|
||||
void pressedKey(const int keycode) override;
|
||||
void runBeforeArcade(ArcadeShooting *arc) override;
|
||||
void runAfterArcade(ArcadeShooting *arc) override;
|
||||
void findNextSegment(ArcadeShooting *arc) override;
|
||||
void initSegment(ArcadeShooting *arc) override;
|
||||
byte *getTargetColor(Common::String name, int levelId) override;
|
||||
bool checkRButtonUp() override;
|
||||
void setRButtonUp(const bool val) override;
|
||||
void disableGameKeymaps() override;
|
||||
void enableGameKeymaps() override;
|
||||
|
||||
|
||||
bool hasFeature(EngineFeature f) const override {
|
||||
return (f == kSupportsReturnToLauncher);
|
||||
}
|
||||
|
||||
private:
|
||||
Common::String getLocalizedString(const Common::String &name);
|
||||
uint16 getNextChar(const Common::String &str, uint32 &c);
|
||||
void drawGlyph(const Common::BitArray &font, int x, int y, int bitoffset, int width, int height, int pitch, uint32 color, bool invert);
|
||||
void drawKoreanChar(uint16 chr, int &curx, int y, uint32 color);
|
||||
void runMainMenu(Code *code);
|
||||
void runLevelMenu(Code *code);
|
||||
void runCheckLives(Code *code);
|
||||
void endCredits(Code *code);
|
||||
void showDemoScore();
|
||||
uint32 findPaletteIndexZones(uint32 id);
|
||||
|
||||
Common::List<int> _scoreMilestones;
|
||||
void restoreScoreMilestones(int score);
|
||||
bool checkScoreMilestones(int score);
|
||||
|
||||
|
||||
Frames _c33PlayerCursor;
|
||||
Common::Point _c33PlayerPosition;
|
||||
Common::List<PlayerPosition> _c33PlayerDirection;
|
||||
bool _c33UseMouse;
|
||||
void generateStaticEffect();
|
||||
|
||||
Common::BitArray _fontg9a;
|
||||
Common::Array<uint32> _c40SegmentPath;
|
||||
Common::Array<uint32> _c40SegmentNext;
|
||||
int _c40SegmentIdx;
|
||||
int _c40lastTurn;
|
||||
int _c50LeftTurns;
|
||||
int _c50RigthTurns;
|
||||
|
||||
bool _rButtonUp;
|
||||
};
|
||||
|
||||
class SpiderEngine : public HypnoEngine {
|
||||
public:
|
||||
SpiderEngine(OSystem *syst, const ADGameDescription *gd);
|
||||
~SpiderEngine();
|
||||
void loadAssets() override;
|
||||
void loadAssetsDemo();
|
||||
void loadAssetsFullGame();
|
||||
void showCredits() override;
|
||||
|
||||
void drawCursorArcade(const Common::Point &mousePos) override;
|
||||
void drawShoot(const Common::Point &target) override;
|
||||
void drawPlayer() override;
|
||||
void drawHealth() override;
|
||||
void missedTarget(Shoot *s, ArcadeShooting *arc) override;
|
||||
void hitPlayer() override;
|
||||
|
||||
// Arcade
|
||||
void pressedKey(const int keycode) override;
|
||||
void runBeforeArcade(ArcadeShooting *arc) override;
|
||||
void runAfterArcade(ArcadeShooting *arc) override;
|
||||
void findNextSegment(ArcadeShooting *arc) override;
|
||||
void initSegment(ArcadeShooting *arc) override;
|
||||
byte *getTargetColor(Common::String name, int levelId) override;
|
||||
|
||||
void drawBackToMenu(Hotspot *h) override;
|
||||
void runCode(Code *code) override;
|
||||
Common::String findNextLevel(const Common::String &level) override;
|
||||
Common::String findNextLevel(const Transition *trans) override;
|
||||
|
||||
void loadFonts(const Common::String &prefix = "") override;
|
||||
void drawString(const Filename &name, const Common::String &str, int x, int y, int w, uint32 c) override;
|
||||
|
||||
void showConversation() override;
|
||||
void endConversation() override;
|
||||
void rightClickedConversation(const Common::Point &mousePos) override;
|
||||
void leftClickedConversation(const Common::Point &mousePos) override;
|
||||
bool hoverConversation(const Common::Point &mousePos) override;
|
||||
|
||||
void loadGame(const Common::String &nextLevel, int score, int puzzleDifficulty, int combatDifficulty) override;
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
|
||||
bool canSaveAutosaveCurrently() override {
|
||||
return false; // No hypno engine should perform autosave using the default implementation
|
||||
}
|
||||
|
||||
bool hasFeature(EngineFeature f) const override {
|
||||
return (f == kSupportsSavingDuringRuntime || f == kSupportsLoadingDuringRuntime || f == kSupportsReturnToLauncher);
|
||||
}
|
||||
|
||||
private:
|
||||
void runMatrix(Code *code);
|
||||
void addIngredient(Code *code);
|
||||
void checkMixture(Code *code);
|
||||
void runNote(Code *code);
|
||||
void runFusePanel(Code *code);
|
||||
void runRecept(Code *code);
|
||||
void runOffice(Code *code);
|
||||
void runFileCabinet(Code *code);
|
||||
void runLock(Code *code);
|
||||
void runFuseBox(Code *code);
|
||||
void runGiveUp();
|
||||
void showScore(const Common::String &prefix);
|
||||
|
||||
uint32 _currentPlayerPosition;
|
||||
uint32 _lastPlayerPosition;
|
||||
|
||||
bool _fuseState[2][10] = {};
|
||||
bool _isFuseRust = true;
|
||||
bool _isFuseUnreadable = false;
|
||||
bool ingredients[7] = {};
|
||||
|
||||
Common::Rect _h1Area;
|
||||
Common::Rect _h2Area;
|
||||
Common::Rect _h3Area;
|
||||
|
||||
const Graphics::Font *_font;
|
||||
};
|
||||
|
||||
class BoyzEngine : public HypnoEngine {
|
||||
public:
|
||||
BoyzEngine(OSystem *syst, const ADGameDescription *gd);
|
||||
~BoyzEngine();
|
||||
Common::String _name;
|
||||
Common::Array<int> _ids;
|
||||
int _lastLevel;
|
||||
bool _flashbackMode;
|
||||
void loadAssets() override;
|
||||
void runCode(Code *code) override;
|
||||
Common::String findNextLevel(const Common::String &level) override;
|
||||
Common::String findNextLevel(const Transition *trans) override;
|
||||
|
||||
// Scenes
|
||||
void resetSceneState() override;
|
||||
void runMenu(Hotspots *hs, bool only_menu = false) override;
|
||||
bool hoverHotspot(Common::Point) override;
|
||||
|
||||
// Arcade
|
||||
void runBeforeArcade(ArcadeShooting *arc) override;
|
||||
void runAfterArcade(ArcadeShooting *arc) override;
|
||||
void pressedKey(const int keycode) override;
|
||||
int detectTarget(const Common::Point &mousePos) override;
|
||||
void drawCursorArcade(const Common::Point &mousePos) override;
|
||||
bool shoot(const Common::Point &mousePos, ArcadeShooting *arc, bool secondary) override;
|
||||
bool clickedSecondaryShoot(const Common::Point &mousePos) override;
|
||||
void showCredits() override;
|
||||
// Stats
|
||||
void showArcadeStats(int territory, const ArcadeStats &data);
|
||||
ArcadeStats _lastStats;
|
||||
ArcadeStats _globalStats;
|
||||
|
||||
void missedTarget(Shoot *s, ArcadeShooting *arc) override;
|
||||
void drawHealth() override;
|
||||
void drawAmmo() override;
|
||||
void drawShoot(const Common::Point &target) override;
|
||||
void hitPlayer() override;
|
||||
void drawPlayer() override;
|
||||
void findNextSegment(ArcadeShooting *arc) override;
|
||||
void initSegment(ArcadeShooting *arc) override;
|
||||
bool checkTransition(ArcadeTransitions &transitions, ArcadeShooting *arc) override;
|
||||
|
||||
void drawString(const Filename &name, const Common::String &str, int x, int y, int w, uint32 c) override;
|
||||
|
||||
// Saves
|
||||
Common::Error saveGameStream(Common::WriteStream *stream, bool isAutosave = false) override;
|
||||
Common::Error loadGameStream(Common::SeekableReadStream *stream) override;
|
||||
Common::StringArray listProfiles();
|
||||
bool loadProfile(const Common::String &name);
|
||||
void saveProfile(const Common::String &name, int levelId);
|
||||
|
||||
private:
|
||||
void renderHighlights(Hotspots *hs);
|
||||
void waitForUserClick(uint32 timeout);
|
||||
int pickABox();
|
||||
int _selectedCorrectBox;
|
||||
char selectDirection();
|
||||
|
||||
void runMainMenu(Code *code);
|
||||
bool runExitMenu();
|
||||
void runRetryMenu(Code *code);
|
||||
void runCheckC3(Code *code);
|
||||
void runCheckHo(Code *code);
|
||||
void runCheckC5(Code *code);
|
||||
void runAlarmC5(Code *code);
|
||||
void runDifficultyMenu(Code *code);
|
||||
void endCredits(Code *code);
|
||||
int getTerritory(const Common::String &level);
|
||||
Common::String lastLevelTerritory(const Common::String &level);
|
||||
Common::String firstLevelTerritory(const Common::String &level);
|
||||
|
||||
void loadSceneState(Common::SeekableReadStream *stream);
|
||||
void saveSceneState(Common::WriteStream *stream);
|
||||
void unlockAllLevels();
|
||||
|
||||
int _previousHealth;
|
||||
Graphics::Surface _healthBar[7];
|
||||
Graphics::Surface _ammoBar[7];
|
||||
Graphics::Surface _portrait[7];
|
||||
Filename _deathDay[7];
|
||||
Filename _deathNight[7];
|
||||
|
||||
Filename _weaponShootSound[8];
|
||||
Filename _weaponReloadSound[8];
|
||||
Filename _heySound[7];
|
||||
int _weaponMaxAmmo[8];
|
||||
|
||||
byte *_crosshairsPalette;
|
||||
Graphics::Surface _crosshairsInactive[8];
|
||||
Graphics::Surface _crosshairsActive[8];
|
||||
Graphics::Surface _crosshairsTarget[8];
|
||||
Graphics::Surface _leftArrowPointer;
|
||||
Graphics::Surface _rightArrowPointer;
|
||||
Graphics::Surface _crossPointer;
|
||||
|
||||
void updateFromScript();
|
||||
bool checkCup(const Common::String &name);
|
||||
|
||||
Script _currentScript;
|
||||
ScriptMode _currentMode;
|
||||
uint32 _currentActor;
|
||||
uint32 _currentWeapon;
|
||||
Common::Array<Filename> _warningVideosDay;
|
||||
Common::Array<Filename> _warningVideosNight;
|
||||
Common::Array<Filename> _warningAlarmVideos;
|
||||
Filename _warningHostage;
|
||||
|
||||
Common::Array<Filename> _deathVideo;
|
||||
Common::HashMap<Common::String, bool> _shootsDestroyed;
|
||||
|
||||
bool hasFeature(EngineFeature f) const override {
|
||||
return (f == kSupportsReturnToLauncher);
|
||||
}
|
||||
};
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
#endif
|
||||
2462
engines/hypno/lexer_arc.cpp
Normal file
2462
engines/hypno/lexer_arc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
129
engines/hypno/lexer_arc.l
Normal file
129
engines/hypno/lexer_arc.l
Normal file
@@ -0,0 +1,129 @@
|
||||
%top{
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define YY_NO_UNISTD_H
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fwrite
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fread
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getc
|
||||
#define YYERROR_VERBOSE
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
#include "hypno/grammar.h"
|
||||
#include "hypno/tokens_arc.h"
|
||||
|
||||
}
|
||||
|
||||
%option noyywrap
|
||||
%option noinput
|
||||
%option nounput
|
||||
%option yylineno
|
||||
%option never-interactive
|
||||
|
||||
%option outfile="engines/hypno/lexer_arc.cpp"
|
||||
%option prefix="HYPNO_ARC_"
|
||||
|
||||
%%
|
||||
NONE return NONETOK;
|
||||
C return CTOK;
|
||||
D return DTOK;
|
||||
HE return HETOK;
|
||||
HL return HLTOK;
|
||||
HU return HUTOK;
|
||||
H[1-2] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return H12TOK;
|
||||
H return HTOK;
|
||||
P return PTOK;
|
||||
AB return ABTOK;
|
||||
AL return ALTOK;
|
||||
AV return AVTOK;
|
||||
A return ATOK;
|
||||
V return VTOK;
|
||||
O return OTOK;
|
||||
O[0-1] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return ONTOK;
|
||||
L return LTOK;
|
||||
N return NTOK;
|
||||
NR return NRTOK;
|
||||
N\* return NSTOK;
|
||||
M return MTOK;
|
||||
R return RTOK;
|
||||
R0 return R0TOK;
|
||||
R1 return R1TOK;
|
||||
I return ITOK;
|
||||
I1 return I1TOK;
|
||||
J0 return J0TOK;
|
||||
J return JTOK;
|
||||
K return KTOK;
|
||||
G return GTOK;
|
||||
Q return QTOK;
|
||||
U return UTOK;
|
||||
Z return ZTOK;
|
||||
W return WTOK;
|
||||
X return XTOK;
|
||||
T return TTOK;
|
||||
Tp return TPTOK;
|
||||
Ts return TSTOK;
|
||||
Ta return TATOK;
|
||||
F[0-9] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return FNTOK;
|
||||
F return FTOK;
|
||||
S[0-9] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return SNTOK;
|
||||
S[A-C] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return SNTOK;
|
||||
A0 return A0TOK;
|
||||
B[0-9A-F] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return BNTOK;
|
||||
K[0-9] return KNTOK;
|
||||
P0 return P0TOK;
|
||||
Y[A-Z0-9] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return YXTOK;
|
||||
22[k|K] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return ENCTOK;
|
||||
11[k|K] HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return ENCTOK;
|
||||
[\-]?[0-9]+ HYPNO_ARC_lval.i = atoi(HYPNO_ARC_text); return NUM;
|
||||
[A-Za-z_][A-Za-z_0-9]*[0-9\.]* HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return NAME;
|
||||
[A-Za-z][\-A-Za-z_0-9\\\.]+ HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return FILENAME;
|
||||
[0-9][\-A-Za-z_0-9\\\.]+ HYPNO_ARC_lval.s = scumm_strdup(HYPNO_ARC_text); return FILENAME;
|
||||
320\,200 return RESTOK;
|
||||
[\n|\r\n] return RETTOK;
|
||||
\;.+\r /* ignore comment */
|
||||
[ \t]+ /* ignore whitespace */;
|
||||
. HYPNO_ARC_lval.i = HYPNO_ARC_text[0]; return BYTE;
|
||||
%%
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
extern Shoot *shoot;
|
||||
|
||||
int parse_arc(const char *code) {
|
||||
YY_BUFFER_STATE bp;
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
bp = yy_scan_string(code);
|
||||
yy_switch_to_buffer(bp);
|
||||
HYPNO_ARC_parse();
|
||||
yy_delete_buffer(bp);
|
||||
delete shoot;
|
||||
shoot = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
2449
engines/hypno/lexer_mis.cpp
Normal file
2449
engines/hypno/lexer_mis.cpp
Normal file
File diff suppressed because it is too large
Load Diff
121
engines/hypno/lexer_mis.l
Normal file
121
engines/hypno/lexer_mis.l
Normal file
@@ -0,0 +1,121 @@
|
||||
%top{
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#define YY_NO_UNISTD_H
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_FILE
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fprintf
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fwrite
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_fread
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdin
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stdout
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_stderr
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_exit
|
||||
#define FORBIDDEN_SYMBOL_EXCEPTION_getc
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
#include "hypno/grammar.h"
|
||||
#include "hypno/tokens_mis.h"
|
||||
|
||||
}
|
||||
|
||||
%option noyywrap
|
||||
%option noinput
|
||||
%option nounput
|
||||
%option yylineno
|
||||
%option never-interactive
|
||||
|
||||
%option outfile="engines/hypno/lexer_mis.cpp"
|
||||
%option prefix="HYPNO_MIS_"
|
||||
|
||||
%%
|
||||
\;.+ /* return COMMENT; */
|
||||
\/\/.+ /* return COMMENT; */
|
||||
MENU return MENUTOK;
|
||||
AMBI return AMBITOK;
|
||||
BACK return BACKTOK;
|
||||
CUTS return CUTSTOK;
|
||||
GLOB return GLOBTOK;
|
||||
PALE return PALETOK;
|
||||
HOTS return HOTSTOK;
|
||||
MICE return MICETOK;
|
||||
END return ENDTOK;
|
||||
TIME return TIMETOK;
|
||||
OVER return OVERTOK;
|
||||
SMEN return SMENTOK;
|
||||
ESCP return ESCPTOK;
|
||||
PLAY return PLAYTOK;
|
||||
SOND return SONDTOK;
|
||||
TALK return TALKTOK;
|
||||
INACTIVE return INACTOK;
|
||||
4DBOX return FDTOK;
|
||||
BOXX return BOXXTOK;
|
||||
MPTR return MPTRTOK;
|
||||
ESCAPE return ESCAPETOK;
|
||||
SECOND return SECONDTOK;
|
||||
INTRO return INTROTOK;
|
||||
INTR return INTRTOK;
|
||||
SWPT return SWPTTOK;
|
||||
DEFAULT return DEFAULTTOK;
|
||||
WAL[0-1] HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return WALNTOK;
|
||||
\|S[A-Za-z_0-9\\\.]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PS;
|
||||
\|G[A-Za-z_0-9\\\.]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PG;
|
||||
\|P[A-Za-z_0-9\\\.]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PP;
|
||||
\|I[A-Za-z_0-9\\\.]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PI;
|
||||
\|H[0-9]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PH;
|
||||
\|A[0-9]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PA;
|
||||
\|D[0-9]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PD;
|
||||
\|F[0-9]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return PF;
|
||||
\|E return PE;
|
||||
\|L return PL;
|
||||
22[k|K] HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return ENCTOK;
|
||||
11[k|K] HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return ENCTOK;
|
||||
GS_[A-Z_0-9]+ HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return GSSWITCH;
|
||||
\/BBOX\= return BBOXTOK;
|
||||
\/[A-Za-z_0-9]* HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return FLAG;
|
||||
[A-Za-z_][A-Za-z_0-9]* HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return NAME;
|
||||
[A-Za-z][A-Za-z_0-9\\\.]* HYPNO_MIS_lval.s = scumm_strdup(HYPNO_MIS_text); return FILENAME;
|
||||
[\-]?[0-9]+ HYPNO_MIS_lval.i = atoi(HYPNO_MIS_text); return NUM;
|
||||
[\n|\r\n] return RETTOK;
|
||||
[ \t]+ /* ignore whitespace */;
|
||||
. debugC(1, Hypno::kHypnoDebugParser, "<no match: %c>", *yytext); return *yytext;
|
||||
%%
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
extern Common::Array<uint32> *smenu_idx;
|
||||
extern HotspotsStack *stack;
|
||||
|
||||
int parse_mis(const char *code) {
|
||||
YY_BUFFER_STATE bp;
|
||||
yy_delete_buffer(YY_CURRENT_BUFFER);
|
||||
bp = yy_scan_string(code);
|
||||
yy_switch_to_buffer(bp);
|
||||
HYPNO_MIS_parse();
|
||||
yy_delete_buffer(bp);
|
||||
delete smenu_idx;
|
||||
smenu_idx = nullptr;
|
||||
delete stack;
|
||||
stack = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
145
engines/hypno/libfile.cpp
Normal file
145
engines/hypno/libfile.cpp
Normal file
@@ -0,0 +1,145 @@
|
||||
/* 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/libfile.h"
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
LibFile::LibFile() : Common::Archive() {
|
||||
_libfile = nullptr;
|
||||
_encrypted = true;
|
||||
}
|
||||
|
||||
LibFile::~LibFile() {
|
||||
close();
|
||||
}
|
||||
|
||||
bool LibFile::open(const Common::Path &prefix, const Common::Path &filename, bool encrypted) {
|
||||
close();
|
||||
|
||||
_prefix = prefix;
|
||||
_encrypted = encrypted;
|
||||
|
||||
_libfile = new Common::File();
|
||||
if (!_libfile->open(filename)) {
|
||||
warning("Failed to open %s", filename.toString(Common::Path::kNativeSeparator).c_str());
|
||||
return false;
|
||||
}
|
||||
uint32 offset = 0;
|
||||
while (offset < _libfile->size()) {
|
||||
byte b;
|
||||
uint32 size = 0;
|
||||
uint32 start = _libfile->size();
|
||||
FileEntry f;
|
||||
_libfile->seek(offset);
|
||||
debugC(1, kHypnoDebugParser, "parsing at offset %d with size %li", offset, long(_libfile->size()));
|
||||
while (true) {
|
||||
Common::String fname;
|
||||
for (uint32 i = 0; i < 12; i++) {
|
||||
b = _libfile->readByte();
|
||||
if (b != 0x96 && b != 0x0)
|
||||
fname += tolower(char(b));
|
||||
}
|
||||
|
||||
if (!Common::isAlnum(*fname.c_str()))
|
||||
break;
|
||||
|
||||
debugC(1, kHypnoDebugParser, "file: %s", fname.c_str());
|
||||
f.name = Common::Path(fname);
|
||||
f.start = start = _libfile->readUint32LE();
|
||||
f.size = size = _libfile->readUint32LE();
|
||||
if (size == 0)
|
||||
error("Trying to load an empty file");
|
||||
_libfile->readUint32LE(); // some field?
|
||||
|
||||
debugC(1, kHypnoDebugParser, "start: %d, size: %d", f.start, f.size);
|
||||
|
||||
_fileEntries.push_back(f);
|
||||
|
||||
};
|
||||
offset = start + size;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
const FileEntry *LibFile::getEntry(const Common::Path &path) const {
|
||||
for (Common::Array<FileEntry>::const_iterator it = _fileEntries.begin(); it != _fileEntries.end(); ++it) {
|
||||
if (((_prefix.join(it->name)).equalsIgnoreCase(path)) || it->name.equalsIgnoreCase(path))
|
||||
return it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void LibFile::close() {
|
||||
delete _libfile; _libfile = nullptr;
|
||||
_fileEntries.clear();
|
||||
}
|
||||
|
||||
bool LibFile::hasFile(const Common::Path &path) const {
|
||||
return getEntry(path) != nullptr;
|
||||
}
|
||||
|
||||
int LibFile::listMembers(Common::ArchiveMemberList &list) const {
|
||||
list.clear();
|
||||
for (Common::Array<FileEntry>::const_iterator it = _fileEntries.begin(); it != _fileEntries.end(); ++it)
|
||||
list.push_back(getMember(it->name));
|
||||
|
||||
return list.size();
|
||||
}
|
||||
|
||||
const Common::ArchiveMemberPtr LibFile::getMember(const Common::Path &path) const {
|
||||
return Common::ArchiveMemberPtr(new Common::GenericArchiveMember(path, *this));
|
||||
}
|
||||
|
||||
Common::SeekableReadStream *LibFile::createReadStreamForMember(const Common::Path &path) const {
|
||||
const FileEntry *entry = getEntry(path);
|
||||
if (!entry)
|
||||
return nullptr;
|
||||
|
||||
byte *data = (byte *)malloc(entry->size);
|
||||
if (!data) {
|
||||
warning("Not enough memory to load archive entry %s", path.toString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
_libfile->seek(entry->start);
|
||||
_libfile->read(data, entry->size);
|
||||
Common::String name = path.baseName();
|
||||
name.toLowercase(); // just in case
|
||||
|
||||
if (name.hasSuffix(".raw")) {
|
||||
for (uint32 i = 0; i < entry->size; i++) {
|
||||
data[i] = data[i] ^ 0xfe;
|
||||
}
|
||||
} else if (_encrypted) {
|
||||
for (uint32 i = 0; i < entry->size; i++) {
|
||||
if (data[i] != '\n')
|
||||
data[i] = data[i] ^ 0xfe;
|
||||
}
|
||||
}
|
||||
|
||||
return new Common::MemoryReadStream(data, entry->size, DisposeAfterUse::YES);
|
||||
}
|
||||
|
||||
} // namespace Hypno
|
||||
|
||||
64
engines/hypno/libfile.h
Normal file
64
engines/hypno/libfile.h
Normal file
@@ -0,0 +1,64 @@
|
||||
/* 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/>.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HYPNO_LIBFILE_H
|
||||
#define HYPNO_LIBFILE_H
|
||||
|
||||
#include "common/archive.h"
|
||||
#include "common/array.h"
|
||||
#include "common/file.h"
|
||||
#include "common/memstream.h"
|
||||
#include "common/stream.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
typedef struct FileEntry {
|
||||
Common::Path name;
|
||||
uint32 start;
|
||||
uint32 size;
|
||||
} FileEntry;
|
||||
|
||||
class LibFile : public Common::Archive {
|
||||
public:
|
||||
LibFile();
|
||||
~LibFile() override;
|
||||
|
||||
bool open(const Common::Path &prefix, const Common::Path &filename, bool encrypted);
|
||||
void close();
|
||||
|
||||
// Common::Archive API implementation
|
||||
bool hasFile(const Common::Path &path) const override;
|
||||
int listMembers(Common::ArchiveMemberList &list) const override;
|
||||
const Common::ArchiveMemberPtr getMember(const Common::Path &path) const override;
|
||||
Common::SeekableReadStream *createReadStreamForMember(const Common::Path &path) const override;
|
||||
|
||||
private:
|
||||
bool _encrypted;
|
||||
Common::File *_libfile;
|
||||
Common::Path _prefix;
|
||||
Common::Array<FileEntry> _fileEntries;
|
||||
const FileEntry *getEntry(const Common::Path &path) const;
|
||||
};
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
#endif
|
||||
|
||||
399
engines/hypno/metaengine.cpp
Normal file
399
engines/hypno/metaengine.cpp
Normal file
@@ -0,0 +1,399 @@
|
||||
/* 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 "engines/advancedDetector.h"
|
||||
|
||||
#include "common/translation.h"
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
#include "hypno/detection.h"
|
||||
|
||||
#include "backends/keymapper/action.h"
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
#include "backends/keymapper/standard-actions.h"
|
||||
|
||||
static const ADExtraGuiOptionsMap optionsList[] = {
|
||||
{
|
||||
GAMEOPTION_ORIGINAL_CHEATS,
|
||||
{
|
||||
_s("Enable original cheats"),
|
||||
_s("Allow cheats using the C key."),
|
||||
"cheats",
|
||||
true,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_INFINITE_HEALTH,
|
||||
{
|
||||
_s("Enable infinite health cheat"),
|
||||
_s("Player health will never decrease (except for game over scenes)."),
|
||||
"infiniteHealth",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_INFINITE_AMMO,
|
||||
{
|
||||
_s("Enable infinite ammo cheat"),
|
||||
_s("Player ammo will never decrease."),
|
||||
"infiniteAmmo",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_UNLOCK_ALL_LEVELS,
|
||||
{
|
||||
_s("Unlock all levels"),
|
||||
_s("All levels will be available to play."),
|
||||
"unlockAllLevels",
|
||||
false,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
{
|
||||
GAMEOPTION_RESTORED_CONTENT,
|
||||
{
|
||||
_s("Enable restored content"),
|
||||
_s("Add additional content that is not enabled the original implementation."),
|
||||
"restored",
|
||||
true,
|
||||
0,
|
||||
0
|
||||
}
|
||||
},
|
||||
AD_EXTRA_GUI_OPTIONS_TERMINATOR
|
||||
};
|
||||
|
||||
class HypnoMetaEngine : public AdvancedMetaEngine<ADGameDescription> {
|
||||
public:
|
||||
const char *getName() const override {
|
||||
return "hypno";
|
||||
}
|
||||
|
||||
const ADExtraGuiOptionsMap *getAdvancedExtraGuiOptions() const override {
|
||||
return optionsList;
|
||||
}
|
||||
|
||||
Common::Error createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const override;
|
||||
Common::KeymapArray initKeymaps(const char *target) const override;
|
||||
};
|
||||
|
||||
Common::Error HypnoMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *desc) const {
|
||||
if (Common::String(desc->gameId) == "wetlands") {
|
||||
*engine = (Engine *)new Hypno::WetEngine(syst, desc);
|
||||
} else if (Common::String(desc->gameId) == "sinistersix") {
|
||||
*engine = (Engine *)new Hypno::SpiderEngine(syst, desc);
|
||||
} else if (Common::String(desc->gameId) == "soldierboyz") {
|
||||
*engine = (Engine *)new Hypno::BoyzEngine(syst, desc);
|
||||
} else
|
||||
return Common::kUnsupportedGameidError;
|
||||
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
|
||||
Common::KeymapArray HypnoMetaEngine::initKeymaps(const char *target) const {
|
||||
using namespace Common;
|
||||
using namespace Hypno;
|
||||
|
||||
Common::String gameId = ConfMan.get("gameid", target);
|
||||
|
||||
KeymapArray keymaps;
|
||||
|
||||
Keymap *engineKeymap = new Keymap(Keymap::kKeymapTypeGame, "hypno-default", _("Default keymappings"));
|
||||
Keymap *introKeymap = new Keymap(Keymap::kKeymapTypeGame, "intro", _("Intro keymappings"));
|
||||
Keymap *cutsceneKeymap = new Keymap(Keymap::kKeymapTypeGame, "cutscene", _("Cutscene keymappings"));
|
||||
|
||||
Common::Action *act;
|
||||
|
||||
act = new Common::Action(kStandardActionLeftClick, _("Primary shoot"));
|
||||
act->setLeftClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_LEFT");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action(kStandardActionRightClick, _("Secondary shoot"));
|
||||
act->setRightClickEvent();
|
||||
act->addDefaultInputMapping("MOUSE_RIGHT");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
engineKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("SKIPINTRO", _("Skip intro"));
|
||||
act->setCustomEngineActionEvent(kActionSkipIntro);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
introKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("SKIPCUTSCENE", _("Skip cutscene"));
|
||||
act->setCustomEngineActionEvent(kActionSkipCutscene);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
cutsceneKeymap->addAction(act);
|
||||
|
||||
keymaps.push_back(engineKeymap);
|
||||
keymaps.push_back(introKeymap);
|
||||
keymaps.push_back(cutsceneKeymap);
|
||||
|
||||
introKeymap->setEnabled(false);
|
||||
cutsceneKeymap->setEnabled(false);
|
||||
|
||||
if (gameId == "soldierboyz") {
|
||||
Keymap *gameKeymap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
|
||||
Keymap *exitMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "exit-menu", _("Exit menu keymappings"));
|
||||
Keymap *difficulyMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "difficulty-menu", _("Difficulty selection menu keymappings"));
|
||||
Keymap *retryMenuKeymap = new Keymap(Keymap::kKeymapTypeGame, "retry-menu", _("Retry menu keymappings"));
|
||||
|
||||
if (ConfMan.getBool("cheats",target)) {
|
||||
act = new Common::Action("SKIPLEVEL", _("Skip level (cheat)"));
|
||||
act->setCustomEngineActionEvent(kActionSkipLevel);
|
||||
act->addDefaultInputMapping("c");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeymap->addAction(act);
|
||||
}
|
||||
|
||||
// I18N: (Game name: Soldier Boyz) player refers to the users own character.
|
||||
act = new Common::Action("KILLPLAYER", _("Kill player"));
|
||||
act->setCustomEngineActionEvent(kActionKillPlayer);
|
||||
act->addDefaultInputMapping("k");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("PAUSE", _("Pause"));
|
||||
act->setCustomEngineActionEvent(kActionPause);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("YES", _("Yes"));
|
||||
act->setCustomEngineActionEvent(kActionYes);
|
||||
act->addDefaultInputMapping("y");
|
||||
act->addDefaultInputMapping("JOY_A");
|
||||
exitMenuKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("NO", _("No"));
|
||||
act->setCustomEngineActionEvent(kActionNo);
|
||||
act->addDefaultInputMapping("n");
|
||||
act->addDefaultInputMapping("JOY_B");
|
||||
exitMenuKeymap->addAction(act);
|
||||
|
||||
// I18N: (Game name: Soldier Boyz) the game has 3 difficulty levels: Chump, Punk and Badass. Chump is the easy mode.
|
||||
act = new Common::Action("CHUMP", _("Chump"));
|
||||
act->setCustomEngineActionEvent(kActionDifficultyChump);
|
||||
act->addDefaultInputMapping("c");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
difficulyMenuKeymap->addAction(act);
|
||||
|
||||
// I18N: (Game name: Soldier Boyz) the game has 3 difficulty levels: Chump, Punk and Badass. Punk is the medium mode.
|
||||
act = new Common::Action("PUNK", _("Punk"));
|
||||
act->setCustomEngineActionEvent(kActionDifficultyPunk);
|
||||
act->addDefaultInputMapping("p");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
difficulyMenuKeymap->addAction(act);
|
||||
|
||||
// I18N: (Game name: Soldier Boyz) the game has 3 difficulty levels: Chump, Punk and Badass. Badass is the hard mode.
|
||||
act = new Common::Action("BADASS", _("Badass"));
|
||||
act->setCustomEngineActionEvent(kActionDifficultyBadass);
|
||||
act->addDefaultInputMapping("b");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
difficulyMenuKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("CANCEL", _("Cancel"));
|
||||
act->setCustomEngineActionEvent(kActionDifficultExit);
|
||||
act->addDefaultInputMapping("a");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
difficulyMenuKeymap->addAction(act);
|
||||
|
||||
// I18N: (Game name: Soldier Boyz) This makes the player restart from the last checkpoint.
|
||||
act = new Common::Action("RETRY", _("Retry sector"));
|
||||
act->setCustomEngineActionEvent(kActionRetry);
|
||||
act->addDefaultInputMapping("s");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
retryMenuKeymap->addAction(act);
|
||||
|
||||
// I18N: (Game name: Soldier Boyz) This makes the player restart the current mission / level.
|
||||
act = new Common::Action("RESTART", _("Restart territory"));
|
||||
act->setCustomEngineActionEvent(kActionRestart);
|
||||
act->addDefaultInputMapping("t");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
retryMenuKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("EXIT", _("Begin new mission"));
|
||||
act->setCustomEngineActionEvent(kActionNewMission);
|
||||
act->addDefaultInputMapping("n");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
retryMenuKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("QUIT", _("Quit"));
|
||||
act->setCustomEngineActionEvent(kActionQuit);
|
||||
act->addDefaultInputMapping("q");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
retryMenuKeymap->addAction(act);
|
||||
|
||||
keymaps.push_back(gameKeymap);
|
||||
keymaps.push_back(exitMenuKeymap);
|
||||
keymaps.push_back(difficulyMenuKeymap);
|
||||
keymaps.push_back(retryMenuKeymap);
|
||||
|
||||
exitMenuKeymap->setEnabled(false);
|
||||
difficulyMenuKeymap->setEnabled(false);
|
||||
retryMenuKeymap->setEnabled(false);
|
||||
|
||||
} else if (gameId == "sinistersix") {
|
||||
Keymap *gameKeymap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
|
||||
|
||||
if (ConfMan.getBool("cheats", target)) {
|
||||
act = new Common::Action("SKIPLEVEL", _("Skip level (cheat)"));
|
||||
act->setCustomEngineActionEvent(kActionSkipLevel);
|
||||
act->addDefaultInputMapping("c");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeymap->addAction(act);
|
||||
}
|
||||
|
||||
// I18N: (Game name: Marvel Comics Spider-Man: The Sinister Six) player refers to the users own character.
|
||||
act = new Common::Action("KILLPLAYER", _("Kill player"));
|
||||
act->setCustomEngineActionEvent(kActionKillPlayer);
|
||||
act->addDefaultInputMapping("k");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("LEFT", _("Move left"));
|
||||
act->setCustomEngineActionEvent(kActionLeft);
|
||||
act->addDefaultInputMapping("LEFT");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("DOWN", _("Move down"));
|
||||
act->setCustomEngineActionEvent(kActionDown);
|
||||
act->addDefaultInputMapping("DOWN");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("RIGHT", _("Move right"));
|
||||
act->setCustomEngineActionEvent(kActionRight);
|
||||
act->addDefaultInputMapping("RIGHT");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("UP", _("Move up"));
|
||||
act->setCustomEngineActionEvent(kActionUp);
|
||||
act->addDefaultInputMapping("UP");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
keymaps.push_back(gameKeymap);
|
||||
|
||||
} else if (gameId == "wetlands") {
|
||||
Keymap *gameKeymap = new Keymap(Keymap::kKeymapTypeGame, "game-shortcuts", _("Game keymappings"));
|
||||
Keymap *menuKeymap = new Keymap(Keymap::kKeymapTypeGame, "menu", _("Menu keymappings"));
|
||||
Keymap *pauseKeymap = new Keymap(Keymap::kKeymapTypeGame, "pause", _("Pause keymappings"));
|
||||
Keymap *directionKeymap = new Keymap(Keymap::kKeymapTypeGame, "direction", _("Direction keymappings"));
|
||||
|
||||
act = new Common::Action("CREDITS", _("Show credits"));
|
||||
act->setCustomEngineActionEvent(kActionCredits);
|
||||
act->addDefaultInputMapping("c");
|
||||
act->addDefaultInputMapping("JOY_LEFT_TRIGGER");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("SKIPLEVEL", _("Skip level (cheat)"));
|
||||
act->setCustomEngineActionEvent(kActionSkipLevel);
|
||||
act->addDefaultInputMapping("s");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
// I18N: (Game name: Wetlands) player refers to the users own character.
|
||||
act = new Common::Action("KILLPLAYER", _("Kill player"));
|
||||
act->setCustomEngineActionEvent(kActionKillPlayer);
|
||||
act->addDefaultInputMapping("k");
|
||||
act->addDefaultInputMapping("JOY_RIGHT_TRIGGER");
|
||||
gameKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("LEFT", _("Move left"));
|
||||
act->setCustomEngineActionEvent(kActionLeft);
|
||||
act->allowKbdRepeats();
|
||||
act->addDefaultInputMapping("LEFT");
|
||||
act->addDefaultInputMapping("JOY_LEFT");
|
||||
directionKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("DOWN", _("Move down"));
|
||||
act->setCustomEngineActionEvent(kActionDown);
|
||||
act->allowKbdRepeats();
|
||||
act->addDefaultInputMapping("DOWN");
|
||||
act->addDefaultInputMapping("JOY_DOWN");
|
||||
directionKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("RIGHT", _("Move right"));
|
||||
act->setCustomEngineActionEvent(kActionRight);
|
||||
act->allowKbdRepeats();
|
||||
act->addDefaultInputMapping("RIGHT");
|
||||
act->addDefaultInputMapping("JOY_RIGHT");
|
||||
directionKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("UP", _("Move up"));
|
||||
act->setCustomEngineActionEvent(kActionUp);
|
||||
act->allowKbdRepeats();
|
||||
act->addDefaultInputMapping("UP");
|
||||
act->addDefaultInputMapping("JOY_UP");
|
||||
directionKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("SELECT", _("Select"));
|
||||
act->setCustomEngineActionEvent(kActionSelect);
|
||||
act->addDefaultInputMapping("RETURN");
|
||||
act->addDefaultInputMapping("JOY_X");
|
||||
menuKeymap->addAction(act);
|
||||
|
||||
act = new Common::Action("PAUSE", _("Pause"));
|
||||
act->setCustomEngineActionEvent(kActionPause);
|
||||
act->addDefaultInputMapping("ESCAPE");
|
||||
act->addDefaultInputMapping("JOY_Y");
|
||||
pauseKeymap->addAction(act);
|
||||
|
||||
keymaps.push_back(gameKeymap);
|
||||
keymaps.push_back(menuKeymap);
|
||||
keymaps.push_back(pauseKeymap);
|
||||
keymaps.push_back(directionKeymap);
|
||||
|
||||
menuKeymap->setEnabled(false);
|
||||
}
|
||||
|
||||
return keymaps;
|
||||
}
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
bool HypnoEngine::isDemo() const {
|
||||
return (bool)(_gameDescription->flags & ADGF_DEMO);
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
#if PLUGIN_ENABLED_DYNAMIC(HYPNO)
|
||||
REGISTER_PLUGIN_DYNAMIC(HYPNO, PLUGIN_TYPE_ENGINE, HypnoMetaEngine);
|
||||
#else
|
||||
REGISTER_PLUGIN_STATIC(HYPNO, PLUGIN_TYPE_ENGINE, HypnoMetaEngine);
|
||||
#endif
|
||||
|
||||
50
engines/hypno/module.mk
Normal file
50
engines/hypno/module.mk
Normal file
@@ -0,0 +1,50 @@
|
||||
MODULE := engines/hypno
|
||||
|
||||
MODULE_OBJS := \
|
||||
actions.o \
|
||||
arcade.o \
|
||||
boyz/arcade.o \
|
||||
boyz/boyz.o \
|
||||
boyz/hard.o \
|
||||
boyz/scene.o \
|
||||
cursors.o \
|
||||
grammar_mis.o \
|
||||
grammar_arc.o \
|
||||
hypno.o \
|
||||
lexer_mis.o \
|
||||
lexer_arc.o \
|
||||
libfile.o \
|
||||
metaengine.o \
|
||||
scene.o \
|
||||
spider/arcade.o \
|
||||
spider/hard.o \
|
||||
spider/spider.o \
|
||||
spider/talk.o \
|
||||
video.o \
|
||||
wet/arcade.o \
|
||||
wet/cursors.o \
|
||||
wet/hard.o \
|
||||
wet/wet.o
|
||||
|
||||
MODULE_DIRS += \
|
||||
engines/hypno
|
||||
|
||||
# HACK: Skip this when including the file for detection objects.
|
||||
ifeq "$(LOAD_RULES_MK)" "1"
|
||||
hypno-grammar:
|
||||
flex engines/hypno/lexer_arc.l
|
||||
bison engines/hypno/grammar_arc.y
|
||||
flex engines/hypno/lexer_mis.l
|
||||
bison engines/hypno/grammar_mis.y
|
||||
endif
|
||||
|
||||
# This module can be built as a plugin
|
||||
ifeq ($(ENABLE_HYPNO), DYNAMIC_PLUGIN)
|
||||
PLUGIN := 1
|
||||
endif
|
||||
|
||||
# Include common rules
|
||||
include $(srcdir)/rules.mk
|
||||
|
||||
# Detection objects
|
||||
DETECT_OBJS += $(MODULE)/detection.o
|
||||
580
engines/hypno/scene.cpp
Normal file
580
engines/hypno/scene.cpp
Normal file
@@ -0,0 +1,580 @@
|
||||
/* 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/events.h"
|
||||
|
||||
#include "hypno/grammar.h"
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
extern int parse_mis(const char *);
|
||||
|
||||
const char *sceneVariables[] = {
|
||||
"GS_NONE",
|
||||
"GS_SCTEXT",
|
||||
"GS_AMBIENT",
|
||||
"GS_MUSIC",
|
||||
"GS_VOLUME",
|
||||
"GS_MOUSESPEED",
|
||||
"GS_MOUSEON",
|
||||
"GS_LEVELCOMPLETE",
|
||||
"GS_LEVELWON",
|
||||
"GS_CHEATS",
|
||||
"GS_SWITCH0",
|
||||
"GS_SWITCH1",
|
||||
"GS_SWITCH2",
|
||||
"GS_SWITCH3",
|
||||
"GS_SWITCH4",
|
||||
"GS_SWITCH5",
|
||||
"GS_SWITCH6",
|
||||
"GS_SWITCH7",
|
||||
"GS_SWITCH8",
|
||||
"GS_SWITCH9",
|
||||
"GS_SWITCH10",
|
||||
"GS_SWITCH11",
|
||||
"GS_SWITCH12",
|
||||
"GS_COMBATJSON",
|
||||
"GS_COMBATLEVEL",
|
||||
"GS_PUZZLELEVEL",
|
||||
nullptr
|
||||
};
|
||||
|
||||
void HypnoEngine::loadSceneLevel(const Common::String ¤t, const Common::String &next, const Common::String &prefix) {
|
||||
debugC(1, kHypnoDebugParser, "Parsing %s", current.c_str());
|
||||
Common::Path name = convertPath(current);
|
||||
|
||||
Common::File test;
|
||||
if (!test.open(name))
|
||||
error("Failed to open %s", name.toString().c_str());
|
||||
|
||||
const uint32 fileSize = test.size();
|
||||
char *buf = (char *)malloc(fileSize + 1);
|
||||
test.read(buf, fileSize);
|
||||
test.close();
|
||||
buf[fileSize] = '\0';
|
||||
debugC(1, kHypnoDebugParser, "%s", buf);
|
||||
parse_mis(buf);
|
||||
Scene *level = new Scene();
|
||||
level->prefix = prefix;
|
||||
level->levelIfWin = next;
|
||||
level->hots = *g_parsedHots;
|
||||
_levels[name.toString('/')] = level;
|
||||
free(buf);
|
||||
}
|
||||
|
||||
void HypnoEngine::loadSceneLevel(const char *buf, const Common::String &name, const Common::String &next, const Common::String &prefix) {
|
||||
debugC(1, kHypnoDebugParser, "Parsing %s", name.c_str());
|
||||
debugC(1, kHypnoDebugParser, "%s", buf);
|
||||
parse_mis(buf);
|
||||
Scene *level = new Scene();
|
||||
level->prefix = prefix;
|
||||
level->levelIfWin = next;
|
||||
level->hots = *g_parsedHots;
|
||||
_levels[name] = level;
|
||||
}
|
||||
|
||||
void HypnoEngine::resetSceneState() {
|
||||
uint32 i = 0;
|
||||
while (sceneVariables[i]) {
|
||||
// Preserve difficulty level variables
|
||||
if (sceneVariables[i] != Common::String("GS_COMBATLEVEL") && sceneVariables[i] != Common::String("GS_PUZZLELEVEL"))
|
||||
_sceneState[sceneVariables[i]] = 0;
|
||||
i++;
|
||||
}
|
||||
_intros.clear();
|
||||
}
|
||||
|
||||
bool HypnoEngine::checkSceneCompleted() {
|
||||
return _sceneState["GS_LEVELCOMPLETE"] || _sceneState["GS_LEVELWON"];
|
||||
}
|
||||
|
||||
bool HypnoEngine::checkLevelWon() {
|
||||
return _sceneState["GS_LEVELWON"];
|
||||
}
|
||||
|
||||
// Hotspots
|
||||
|
||||
void HypnoEngine::clickedHotspot(Common::Point mousePos) {
|
||||
Hotspots *hots = stack.back();
|
||||
Hotspot selected(MakeHotspot);
|
||||
bool found = false;
|
||||
int rs = 100000000;
|
||||
int cs = 0;
|
||||
for (Hotspots::const_iterator it = hots->begin(); it != hots->end(); ++it) {
|
||||
const Hotspot h = *it;
|
||||
cs = h.rect.width() * h.rect.height();
|
||||
if (h.rect.contains(mousePos)) {
|
||||
if (cs < rs) {
|
||||
selected = h;
|
||||
found = true;
|
||||
rs = cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (selected.type == MakeMenu) {
|
||||
if (isDemo()) {
|
||||
_nextLevel = "sixdemo/mis/demo.mis";
|
||||
resetSceneState();
|
||||
} else // TODO: remove when proper escape to main menu is implemented
|
||||
openMainMenuDialog();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!found)
|
||||
return;
|
||||
|
||||
if (selected.smenu) {
|
||||
if (selected.smenu->empty())
|
||||
error("Invalid menu selected");
|
||||
_nextHotsToAdd = selected.smenu;
|
||||
}
|
||||
|
||||
_videosPlaying.clear();
|
||||
_nextParallelVideoToPlay.clear();
|
||||
_nextSequentialVideoToPlay.clear();
|
||||
|
||||
bool cont = true;
|
||||
for (Actions::const_iterator itt = selected.actions.begin(); itt != selected.actions.end() && cont; ++itt) {
|
||||
Action *action = *itt;
|
||||
switch (action->type) {
|
||||
case ChangeLevelAction:
|
||||
runChangeLevel((ChangeLevel *)action);
|
||||
break;
|
||||
|
||||
case EscapeAction:
|
||||
runEscape();
|
||||
break;
|
||||
|
||||
case CutsceneAction:
|
||||
runCutscene((Cutscene *)action);
|
||||
break;
|
||||
|
||||
case PlayAction:
|
||||
runPlay((Play *)action);
|
||||
break;
|
||||
|
||||
case SoundAction:
|
||||
runSound((Sound *)action);
|
||||
break;
|
||||
|
||||
case WalNAction:
|
||||
runWalN((WalN *)action);
|
||||
break;
|
||||
|
||||
case GlobalAction:
|
||||
cont = runGlobal((Global *)action);
|
||||
break;
|
||||
|
||||
case TalkAction:
|
||||
runTalk((Talk *)action);
|
||||
break;
|
||||
|
||||
case SaveAction:
|
||||
runSave((Save *)action);
|
||||
break;
|
||||
|
||||
case LoadAction:
|
||||
runLoad((Load *)action);
|
||||
break;
|
||||
|
||||
case LoadCheckpointAction:
|
||||
runLoadCheckpoint((LoadCheckpoint *)action);
|
||||
break;
|
||||
|
||||
case QuitAction:
|
||||
runQuit((Quit *)action);
|
||||
break;
|
||||
|
||||
case AmbientAction:
|
||||
runAmbient((Ambient *)action);
|
||||
break;
|
||||
|
||||
case PaletteAction:
|
||||
runPalette((Palette *)action);
|
||||
break;
|
||||
|
||||
case SwapPointerAction:
|
||||
runSwapPointer((SwapPointer *)action);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool HypnoEngine::hoverHotspot(Common::Point mousePos) {
|
||||
Hotspots *hots = stack.back();
|
||||
Hotspot selected(MakeHotspot);
|
||||
bool found = false;
|
||||
int rs = 100000000;
|
||||
for (Hotspots::const_iterator it = hots->begin(); it != hots->end(); ++it) {
|
||||
const Hotspot h = *it;
|
||||
if (h.type != MakeHotspot)
|
||||
continue;
|
||||
|
||||
int cs = h.rect.width() * h.rect.height();
|
||||
if (h.rect.contains(mousePos)) {
|
||||
if (cs < rs) {
|
||||
selected = h;
|
||||
found = true;
|
||||
rs = cs;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (found) {
|
||||
for (Actions::const_iterator itt = selected.actions.begin(); itt != selected.actions.end(); ++itt) {
|
||||
Action *action = *itt;
|
||||
switch (action->type) {
|
||||
case MiceAction:
|
||||
runMice((Mice *)action);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
Common::String HypnoEngine::findNextLevel(const Transition *trans) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
|
||||
void HypnoEngine::runTransition(Transition *trans) {
|
||||
Common::String nextLevel = findNextLevel(trans);
|
||||
if (!trans->frameImage.empty()) {
|
||||
// This is only used in Wetlands, and therefore, resolution should be 320x200
|
||||
changeScreenMode("320x200");
|
||||
debugC(1, kHypnoDebugScene, "Rendering %s frame in transaction", trans->frameImage.c_str());
|
||||
loadImage(trans->frameImage, 0, 0, false, true, trans->frameNumber);
|
||||
drawScreen();
|
||||
Common::String *ptr = new Common::String(nextLevel);
|
||||
if (!startAlarm(2 * 1000000, ptr)) // 2 seconds
|
||||
error("Failed to install alarm");
|
||||
} else
|
||||
_nextLevel = nextLevel;
|
||||
}
|
||||
|
||||
void HypnoEngine::runScene(Scene *scene) {
|
||||
changeScreenMode(scene->resolution);
|
||||
_refreshConversation = false;
|
||||
Common::Event event;
|
||||
Common::Point mousePos;
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
Common::List<uint32> videosToRemove;
|
||||
bool enableLoopingVideos = true;
|
||||
int32 lastCountdown = 0;
|
||||
// These variables are always resetted
|
||||
_sceneState["GS_LEVELCOMPLETE"] = 0;
|
||||
_sceneState["GS_LEVELWON"] = 0;
|
||||
|
||||
stack.clear();
|
||||
_nextHotsToAdd = &scene->hots;
|
||||
defaultCursor();
|
||||
|
||||
while (!shouldQuit() && _nextLevel.empty()) {
|
||||
|
||||
if (_timerStarted && _videosPlaying.empty() && !_nextHotsToRemove) {
|
||||
|
||||
if (lastCountdown == _countdown) {
|
||||
} else if (_countdown > 0) {
|
||||
uint32 c = 251; // red
|
||||
if (stack.size() > 0)
|
||||
runMenu(stack.back());
|
||||
uint32 minutes = _countdown / 60;
|
||||
uint32 seconds = _countdown % 60;
|
||||
drawString("console", Common::String::format("TIME: %d:%d", minutes, seconds), 80, 10, 60, c);
|
||||
drawScreen();
|
||||
} else {
|
||||
assert(!scene->levelIfLose.empty());
|
||||
_nextLevel = scene->levelIfLose;
|
||||
debugC(1, kHypnoDebugScene, "Finishing level with timeout and jumping to %s", _nextLevel.c_str());
|
||||
resetSceneState();
|
||||
removeTimers();
|
||||
_defaultCursorIdx = 0;
|
||||
continue;
|
||||
}
|
||||
lastCountdown = _countdown;
|
||||
}
|
||||
|
||||
disableGameKeymaps();
|
||||
keymapper->getKeymap("cutscene")->setEnabled(true);
|
||||
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
mousePos = g_system->getEventManager()->getMousePos();
|
||||
// Events
|
||||
switch (event.type) {
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType == kActionSkipCutscene) {
|
||||
for (Videos::iterator it = _videosPlaying.begin(); it != _videosPlaying.end(); ++it) {
|
||||
if (it->decoder) {
|
||||
skipVideo(*it);
|
||||
if (it->scaled) {
|
||||
runMenu(stack.back());
|
||||
drawScreen();
|
||||
}
|
||||
}
|
||||
}
|
||||
_videosPlaying.clear();
|
||||
|
||||
if (!_conversation.empty())
|
||||
_refreshConversation = true;
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
break;
|
||||
|
||||
case Common::EVENT_RBUTTONDOWN:
|
||||
if (stack.empty())
|
||||
break;
|
||||
if (!_conversation.empty()) {
|
||||
rightClickedConversation(mousePos);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_LBUTTONDOWN:
|
||||
if (stack.empty())
|
||||
break;
|
||||
if (!_conversation.empty()) {
|
||||
leftClickedConversation(mousePos);
|
||||
break;
|
||||
}
|
||||
if (!_nextHotsToAdd && !_nextHotsToRemove /*&& _videosPlaying.empty()*/) {
|
||||
clickedHotspot(mousePos);
|
||||
drawScreen();
|
||||
}
|
||||
break;
|
||||
|
||||
case Common::EVENT_MOUSEMOVE:
|
||||
// Reset cursor to default
|
||||
// changeCursor("default");
|
||||
// The following functions will return true
|
||||
// if the cursor is changed
|
||||
|
||||
if (!_conversation.empty() && !hoverConversation(mousePos))
|
||||
defaultCursor();
|
||||
|
||||
if (stack.empty() || !_conversation.empty() || !_videosPlaying.empty())
|
||||
break;
|
||||
|
||||
if (!hoverHotspot(mousePos))
|
||||
defaultCursor();
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
keymapper->getKeymap("cutscene")->setEnabled(false);
|
||||
enableGameKeymaps();
|
||||
|
||||
if (_refreshConversation && !_conversation.empty() &&
|
||||
_nextSequentialVideoToPlay.empty() &&
|
||||
_nextParallelVideoToPlay.empty() &&
|
||||
_videosPlaying.empty()) {
|
||||
showConversation();
|
||||
runMenu(stack.back(), true);
|
||||
drawScreen();
|
||||
_refreshConversation = false;
|
||||
}
|
||||
|
||||
// Movies
|
||||
if (!_nextParallelVideoToPlay.empty()) {
|
||||
for (Videos::iterator it = _nextParallelVideoToPlay.begin(); it != _nextParallelVideoToPlay.end(); ++it) {
|
||||
playVideo(*it);
|
||||
if (it->loop)
|
||||
_videosLooping.push_back(*it);
|
||||
else
|
||||
_videosPlaying.push_back(*it);
|
||||
}
|
||||
_nextParallelVideoToPlay.clear();
|
||||
}
|
||||
|
||||
if (!_nextSequentialVideoToPlay.empty() && _videosPlaying.empty()) {
|
||||
MVideo *it = _nextSequentialVideoToPlay.begin();
|
||||
playVideo(*it);
|
||||
if (it->loop)
|
||||
_videosLooping.push_back(*it);
|
||||
else
|
||||
_videosPlaying.push_back(*it);
|
||||
_nextSequentialVideoToPlay.remove_at(0);
|
||||
}
|
||||
|
||||
for (Videos::iterator it = _videosLooping.begin(); it != _videosLooping.end(); ++it) {
|
||||
if (it->decoder && _conversation.empty()) {
|
||||
if (it->decoder->endOfVideo()) {
|
||||
if (it->loop && enableLoopingVideos) {
|
||||
it->decoder->rewind();
|
||||
it->decoder->start();
|
||||
}
|
||||
} else if (it->decoder->needsUpdate()) {
|
||||
updateScreen(*it);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32 i = 0;
|
||||
videosToRemove.clear();
|
||||
for (Videos::iterator it = _videosPlaying.begin(); it != _videosPlaying.end(); ++it) {
|
||||
|
||||
if (it->decoder) {
|
||||
if (it->decoder->endOfVideo()) {
|
||||
if (it->scaled ||
|
||||
( it->decoder->getWidth() == _screenW
|
||||
&& it->decoder->getHeight() == _screenH
|
||||
&& it->decoder->getCurFrame() > 0)) {
|
||||
runMenu(stack.back());
|
||||
drawScreen();
|
||||
}
|
||||
it->decoder->close();
|
||||
delete it->decoder;
|
||||
it->decoder = nullptr;
|
||||
videosToRemove.push_back(i);
|
||||
} else if (it->decoder->needsUpdate()) {
|
||||
updateScreen(*it);
|
||||
}
|
||||
}
|
||||
i++;
|
||||
}
|
||||
if (!videosToRemove.empty()) {
|
||||
|
||||
for (Common::List<uint32>::iterator it = videosToRemove.begin(); it != videosToRemove.end(); ++it) {
|
||||
debugC(1, kHypnoDebugScene, "removing %d from %d size", *it, _videosPlaying.size());
|
||||
_videosPlaying.remove_at(*it);
|
||||
}
|
||||
debugC(1, kHypnoDebugScene, "Something to play: %d", _videosPlaying.size());
|
||||
// Nothing else to play
|
||||
if (_videosPlaying.empty() && _nextSequentialVideoToPlay.empty() && !checkSceneCompleted()) {
|
||||
if (!_conversation.empty())
|
||||
_refreshConversation = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkSceneCompleted() || checkLevelWon()) {
|
||||
if (!checkLevelWon() && stack.size() > 1) {
|
||||
debugC(1, kHypnoDebugScene, "Executing escape instead of ending the scene");
|
||||
runEscape();
|
||||
_sceneState["GS_LEVELCOMPLETE"] = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Make sure all the videos are played before we finish
|
||||
enableLoopingVideos = false;
|
||||
if (_conversation.empty() &&
|
||||
_videosPlaying.empty() &&
|
||||
_nextSequentialVideoToPlay.empty() &&
|
||||
_nextParallelVideoToPlay.empty()) {
|
||||
|
||||
if (_nextLevel.empty()) {
|
||||
assert(!scene->levelIfWin.empty());
|
||||
_nextLevel = scene->levelIfWin;
|
||||
}
|
||||
|
||||
if (checkLevelWon()) {
|
||||
debugC(1, kHypnoDebugScene, "Resetting level variables");
|
||||
resetSceneState();
|
||||
_checkpoint = _nextLevel;
|
||||
_defaultCursorIdx = 0;
|
||||
}
|
||||
_sceneState["GS_LEVELCOMPLETE"] = 0;
|
||||
|
||||
debugC(1, kHypnoDebugScene, "Finishing level and jumping to %s", _nextLevel.c_str());
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (!_videosPlaying.empty() || !_videosLooping.empty() || !_nextSequentialVideoToPlay.empty()) {
|
||||
drawScreen();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (_nextHotsToRemove) {
|
||||
debugC(1, kHypnoDebugScene, "Removing a hotspot list!");
|
||||
stack.pop_back();
|
||||
runMenu(stack.back());
|
||||
_nextHotsToRemove = nullptr;
|
||||
drawScreen();
|
||||
} else if (_nextHotsToAdd) {
|
||||
debugC(1, kHypnoDebugScene, "Adding a hotspot list!");
|
||||
stack.push_back(_nextHotsToAdd);
|
||||
runMenu(stack.back());
|
||||
_nextHotsToAdd = nullptr;
|
||||
drawScreen();
|
||||
}
|
||||
|
||||
if (!isMusicActive() && !scene->music.empty()) {
|
||||
playMusic(scene->music, scene->musicRate);
|
||||
}
|
||||
|
||||
g_system->updateScreen();
|
||||
g_system->delayMillis(30);
|
||||
}
|
||||
|
||||
// Deallocate videos
|
||||
for (Videos::iterator it = _videosLooping.begin(); it != _videosLooping.end(); ++it) {
|
||||
if (it->decoder)
|
||||
skipVideo(*it);
|
||||
}
|
||||
|
||||
for (Videos::iterator it = _videosPlaying.begin(); it != _videosPlaying.end(); ++it) {
|
||||
if (it->decoder)
|
||||
skipVideo(*it);
|
||||
}
|
||||
|
||||
for (Videos::iterator it = _nextParallelVideoToPlay.begin(); it != _nextParallelVideoToPlay.end(); ++it) {
|
||||
if (it->decoder)
|
||||
skipVideo(*it);
|
||||
}
|
||||
|
||||
for (Videos::iterator it = _nextSequentialVideoToPlay.begin(); it != _nextSequentialVideoToPlay.end(); ++it) {
|
||||
if (it->decoder)
|
||||
skipVideo(*it);
|
||||
}
|
||||
|
||||
for (Videos::iterator it = _escapeSequentialVideoToPlay.begin(); it != _escapeSequentialVideoToPlay.end(); ++it) {
|
||||
if (it->decoder)
|
||||
skipVideo(*it);
|
||||
}
|
||||
|
||||
_nextParallelVideoToPlay.clear();
|
||||
_nextSequentialVideoToPlay.clear();
|
||||
_escapeSequentialVideoToPlay.clear();
|
||||
_conversation.clear();
|
||||
|
||||
if (!_keepTimerDuringScenes)
|
||||
removeTimers();
|
||||
}
|
||||
|
||||
void HypnoEngine::showConversation() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
void HypnoEngine::endConversation() { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
void HypnoEngine::rightClickedConversation(const Common::Point &mousePos) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
void HypnoEngine::leftClickedConversation(const Common::Point &mousePos) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
bool HypnoEngine::hoverConversation(const Common::Point &mousePos) { error("Function \"%s\" not implemented", __FUNCTION__); }
|
||||
|
||||
} // End of namespace Hypno
|
||||
347
engines/hypno/spider/arcade.cpp
Normal file
347
engines/hypno/spider/arcade.cpp
Normal file
@@ -0,0 +1,347 @@
|
||||
/* 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 "graphics/cursorman.h"
|
||||
#include "gui/message.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
static const int oIndexYB[9] = {0, 1, 2, 7, 8, 3, 6, 5, 4};
|
||||
static const int oIndexYE[9] = {4, 3, 2, 1, 0};
|
||||
static const int shootOriginIndex[9][2] = {
|
||||
{41, 3}, {51, 3}, {65, 6}, {40, 16}, {58, 20}, {67, 10}, {37, 14}, {37, 15}, {67, 22}};
|
||||
|
||||
void SpiderEngine::runBeforeArcade(ArcadeShooting *arc) {
|
||||
_health = arc->health;
|
||||
_maxHealth = _health;
|
||||
resetStatistics();
|
||||
_checkpoint = _currentLevel;
|
||||
assert(!arc->player.empty());
|
||||
_playerFrames = decodeFrames(arc->player);
|
||||
_playerFrameSep = 0;
|
||||
|
||||
for (Frames::iterator it =_playerFrames.begin(); it != _playerFrames.end(); ++it) {
|
||||
if ((*it)->getPixel(0, 0) == 255)
|
||||
break;
|
||||
if ((*it)->getPixel(0, 0) == 252)
|
||||
break;
|
||||
|
||||
_playerFrameSep++;
|
||||
}
|
||||
|
||||
if (_playerFrameSep == (int)_playerFrames.size()) {
|
||||
debugC(1, kHypnoDebugArcade, "No player separator frame found in %s! (size: %d)", arc->player.c_str(), _playerFrames.size());
|
||||
} else
|
||||
debugC(1, kHypnoDebugArcade, "Separator frame found at %d", _playerFrameSep);
|
||||
|
||||
_playerFrameIdx = -1;
|
||||
_currentPlayerPosition = kPlayerLeft;
|
||||
_lastPlayerPosition = kPlayerLeft;
|
||||
}
|
||||
|
||||
void SpiderEngine::runAfterArcade(ArcadeShooting *arc) {
|
||||
if (_health <= 0) {
|
||||
assert(_score >= _bonus);
|
||||
_score -= _bonus;
|
||||
}
|
||||
|
||||
for (Frames::iterator it =_playerFrames.begin(); it != _playerFrames.end(); ++it) {
|
||||
(*it)->free();
|
||||
delete (*it);
|
||||
}
|
||||
_playerFrames.clear();
|
||||
|
||||
if (isDemo() && _restoredContentEnabled) {
|
||||
if (_health <= 0)
|
||||
showScore("Spider-man was defeated!");
|
||||
else
|
||||
showScore("Spider-Man saved the day!");
|
||||
_score = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void SpiderEngine::initSegment(ArcadeShooting *arc) {
|
||||
_segmentShootSequenceOffset = 0;
|
||||
_segmentShootSequenceMax = 0;
|
||||
|
||||
uint32 randomSegmentShootSequence = _segmentShootSequenceOffset + _rnd->getRandomNumber(_segmentShootSequenceMax);
|
||||
SegmentShoots segmentShoots = arc->shootSequence[randomSegmentShootSequence];
|
||||
_shootSequence = segmentShoots.shootSequence;
|
||||
_segmentRepetitionMax = segmentShoots.segmentRepetition; // Usually zero
|
||||
_segmentRepetition = 0;
|
||||
_segmentOffset = 0;
|
||||
_segmentIdx = _segmentOffset;
|
||||
}
|
||||
|
||||
void SpiderEngine::findNextSegment(ArcadeShooting *arc) {
|
||||
_segmentIdx = _segmentIdx + 1;
|
||||
}
|
||||
|
||||
|
||||
void SpiderEngine::pressedKey(const int keycode) {
|
||||
if (keycode == kActionSkipLevel) {
|
||||
_skipLevel = true;
|
||||
return;
|
||||
} else if (keycode == kActionKillPlayer) { // Added for testing
|
||||
_health = 0;
|
||||
} else if (keycode == kActionLeft) {
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_currentPlayerPosition = kPlayerLeft;
|
||||
} else if (keycode == kActionDown) {
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_currentPlayerPosition = kPlayerBottom;
|
||||
} else if (keycode == kActionRight) {
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_currentPlayerPosition = kPlayerRight;
|
||||
} else if (keycode == kActionUp) {
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_currentPlayerPosition = kPlayerTop;
|
||||
}
|
||||
}
|
||||
|
||||
void SpiderEngine::missedTarget(Shoot *s, ArcadeShooting *arc) {
|
||||
if (_arcadeMode != "YC" && _arcadeMode != "YD")
|
||||
return;
|
||||
if ((uint32)(s->name[0]) == _currentPlayerPosition) {
|
||||
if (!_infiniteHealthCheat)
|
||||
_health = _health - s->attackWeight;
|
||||
hitPlayer();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void SpiderEngine::hitPlayer() {
|
||||
if (_playerFrameSep < (int)_playerFrames.size()) {
|
||||
if (_playerFrameIdx < _playerFrameSep)
|
||||
_playerFrameIdx = _playerFrameSep;
|
||||
} else {
|
||||
uint32 c = kHypnoColorRed; // red
|
||||
_compositeSurface->fillRect(Common::Rect(0, 0, 640, 480), c);
|
||||
drawScreen();
|
||||
}
|
||||
if (!_hitSound.empty())
|
||||
playSound(_soundPath + _hitSound, 1, 11025);
|
||||
}
|
||||
|
||||
void SpiderEngine::drawShoot(const Common::Point &target) {
|
||||
uint32 c = kSpiderColorWhite; // white
|
||||
uint32 ox = 0;
|
||||
uint32 oy = 0;
|
||||
|
||||
if (_arcadeMode == "YC" || _arcadeMode == "YD") {
|
||||
return; // Nothing to shoot
|
||||
} else if (_arcadeMode == "YE" || _arcadeMode == "YF") {
|
||||
ox = _screenW / 2;
|
||||
oy = _screenH - _playerFrames[0]->h / 2;
|
||||
} else if (_arcadeMode == "YB") {
|
||||
uint32 idx = MIN(2, target.x / (_screenW / 3)) + 3 * MIN(2, target.y / (_screenH / 3));
|
||||
ox = 60 + shootOriginIndex[idx][0];
|
||||
oy = 129 + shootOriginIndex[idx][1];
|
||||
} else
|
||||
error("Invalid arcade mode %s", _arcadeMode.c_str());
|
||||
|
||||
_compositeSurface->drawLine(ox, oy, target.x + 2, target.y, c);
|
||||
_compositeSurface->drawLine(ox, oy, target.x, target.y, c);
|
||||
_compositeSurface->drawLine(ox, oy, target.x - 2, target.y, c);
|
||||
|
||||
playSound(_soundPath + _shootSound, 1);
|
||||
}
|
||||
|
||||
void SpiderEngine::drawPlayer() {
|
||||
uint32 ox = 0;
|
||||
uint32 oy = 0;
|
||||
|
||||
if (_arcadeMode == "YC" || _arcadeMode == "YD") {
|
||||
disableCursor(); // Not sure this a good place
|
||||
ox = 0;
|
||||
oy = 0;
|
||||
|
||||
if (_playerFrameIdx < 0)
|
||||
_playerFrameIdx = 0;
|
||||
else if (_lastPlayerPosition != _currentPlayerPosition && (_playerFrameIdx % 4 == 0 || _playerFrameIdx % 4 == 3)) {
|
||||
|
||||
switch (_lastPlayerPosition) {
|
||||
case kPlayerLeft:
|
||||
switch (_currentPlayerPosition) {
|
||||
case kPlayerTop:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 1;
|
||||
break;
|
||||
case kPlayerBottom:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 13;
|
||||
break;
|
||||
case kPlayerRight:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 45;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kPlayerRight:
|
||||
switch (_currentPlayerPosition) {
|
||||
case kPlayerTop:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 5;
|
||||
break;
|
||||
case kPlayerBottom:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 17;
|
||||
break;
|
||||
case kPlayerLeft:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 33;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kPlayerBottom:
|
||||
switch (_currentPlayerPosition) {
|
||||
case kPlayerTop:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 9;
|
||||
break;
|
||||
case kPlayerLeft:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 29;
|
||||
break;
|
||||
case kPlayerRight:
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
_playerFrameIdx = 41;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case kPlayerTop:
|
||||
switch (_currentPlayerPosition) {
|
||||
case kPlayerBottom:
|
||||
_playerFrameIdx = 21;
|
||||
break;
|
||||
case kPlayerLeft:
|
||||
_playerFrameIdx = 25;
|
||||
break;
|
||||
case kPlayerRight:
|
||||
_playerFrameIdx = 37;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
} else if (_playerFrameIdx < 48 && _playerFrameIdx % 4 != 0 && _playerFrameIdx % 4 != 3) {
|
||||
_playerFrameIdx++;
|
||||
_lastPlayerPosition = _currentPlayerPosition;
|
||||
} else {
|
||||
if (_arcadeMode == "YD") {
|
||||
switch (_lastPlayerPosition) {
|
||||
case kPlayerTop:
|
||||
if ((_playerFrameIdx <= 11 && (_playerFrameIdx % 4 == 0 || _playerFrameIdx % 4 == 3)) || _playerFrameIdx >= 54)
|
||||
_playerFrameIdx = 49;
|
||||
else
|
||||
_playerFrameIdx++;
|
||||
break;
|
||||
|
||||
case kPlayerBottom:
|
||||
if ((_playerFrameIdx <= 23 && (_playerFrameIdx % 4 == 0 || _playerFrameIdx % 4 == 3)) || _playerFrameIdx >= 65)
|
||||
_playerFrameIdx = 60;
|
||||
else
|
||||
_playerFrameIdx++;
|
||||
break;
|
||||
case kPlayerLeft:
|
||||
if ((_playerFrameIdx <= 35 && (_playerFrameIdx % 4 == 0 || _playerFrameIdx % 4 == 3)) || _playerFrameIdx >= 77)
|
||||
_playerFrameIdx = 72;
|
||||
else
|
||||
_playerFrameIdx++;
|
||||
break;
|
||||
|
||||
case kPlayerRight:
|
||||
if ((_playerFrameIdx <= 47 && (_playerFrameIdx % 4 == 0 || _playerFrameIdx % 4 == 3)) || _playerFrameIdx >= 89)
|
||||
_playerFrameIdx = 84;
|
||||
else
|
||||
_playerFrameIdx++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (_arcadeMode == "YE" || _arcadeMode == "YF") {
|
||||
if (_arcadeMode == "YF") {
|
||||
int fraction = _background->decoder->getFrameCount() / (_maxHealth / 2);
|
||||
if (_background->decoder->getCurFrame() % fraction == 0)
|
||||
_health = MAX(1, _health - 1);
|
||||
|
||||
if (checkArcadeObjectives())
|
||||
_skipLevel = true;
|
||||
}
|
||||
|
||||
Common::Point mousePos = g_system->getEventManager()->getMousePos();
|
||||
uint32 idx = mousePos.x / (_screenW / 5);
|
||||
_playerFrameIdx = oIndexYE[idx];
|
||||
ox = _screenW / 2 - _playerFrames[0]->w / 2;
|
||||
oy = _screenH - _playerFrames[0]->h;
|
||||
} else if (_arcadeMode == "YB") {
|
||||
ox = 60;
|
||||
oy = 129;
|
||||
if (_playerFrameIdx < _playerFrameSep) {
|
||||
Common::Point mousePos = g_system->getEventManager()->getMousePos();
|
||||
uint32 idx = MIN(2, mousePos.x / (_screenW / 3)) + 3 * MIN(2, mousePos.y / (_screenH / 3));
|
||||
_playerFrameIdx = oIndexYB[idx];
|
||||
} else {
|
||||
_playerFrameIdx++;
|
||||
if (_playerFrameIdx >= (int)_playerFrames.size())
|
||||
_playerFrameIdx = 0;
|
||||
}
|
||||
} else
|
||||
error("Invalid arcade mode %s", _arcadeMode.c_str());
|
||||
|
||||
drawImage(*_playerFrames[_playerFrameIdx], ox, oy, true);
|
||||
}
|
||||
|
||||
void SpiderEngine::drawCursorArcade(const Common::Point &mousePos) {
|
||||
if (_arcadeMode != "YC" && _arcadeMode != "YD") {
|
||||
HypnoEngine::drawCursorArcade(mousePos);
|
||||
}
|
||||
}
|
||||
|
||||
void SpiderEngine::drawHealth() {
|
||||
Common::Rect r;
|
||||
uint32 c;
|
||||
int d = (22 * (_maxHealth - _health) / _maxHealth);
|
||||
if (d >= 22)
|
||||
return;
|
||||
r = Common::Rect(256, 152 + d, 272, 174);
|
||||
if (d >= 11)
|
||||
c = kHypnoColorRed; // red
|
||||
else
|
||||
c = kHypnoColorGreen; // green
|
||||
|
||||
_compositeSurface->fillRect(r, c);
|
||||
|
||||
r = Common::Rect(256, 152, 272, 174);
|
||||
c = kSpiderColorBlue; // blue
|
||||
_compositeSurface->frameRect(r, c);
|
||||
|
||||
drawString("block05.fgx", "ENERGY", 248, 180, 38, c);
|
||||
}
|
||||
byte *SpiderEngine::getTargetColor(Common::String name, int levelId) {
|
||||
return getPalette(kHypnoColorRed);
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
1197
engines/hypno/spider/hard.cpp
Normal file
1197
engines/hypno/spider/hard.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1277
engines/hypno/spider/spider.cpp
Normal file
1277
engines/hypno/spider/spider.cpp
Normal file
File diff suppressed because it is too large
Load Diff
241
engines/hypno/spider/talk.cpp
Normal file
241
engines/hypno/spider/talk.cpp
Normal file
@@ -0,0 +1,241 @@
|
||||
/* 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"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
void SpiderEngine::endConversation() {
|
||||
debugC(1, kHypnoDebugScene, "Ending and clearing conversation");
|
||||
for (Actions::iterator itt = _conversation.begin(); itt != _conversation.end(); ++itt) {
|
||||
Talk *a = (Talk *)*itt;
|
||||
delete a;
|
||||
}
|
||||
_conversation.clear();
|
||||
}
|
||||
|
||||
void SpiderEngine::showConversation() {
|
||||
debugC(1, kHypnoDebugScene, "Showing conversation");
|
||||
defaultCursor();
|
||||
uint32 x = 0;
|
||||
uint32 y = 0;
|
||||
Graphics::Surface *speaker = decodeFrame("dialog/speaker3.smk", 0);
|
||||
bool activeFound = false;
|
||||
bool skipRepeated = false;
|
||||
|
||||
// First iteration on the talk commands
|
||||
Videos videos;
|
||||
for (Actions::iterator itt = _conversation.begin(); itt != _conversation.end(); ++itt) {
|
||||
Talk *a = (Talk *)*itt;
|
||||
|
||||
for (TalkCommands::const_iterator it = a->commands.begin(); it != a->commands.end(); ++it) {
|
||||
if (it->command == "P") {
|
||||
if (_intros[it->path]) {
|
||||
skipRepeated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (a->boxPos != Common::Point(0, 0)) {
|
||||
if (!(x == 0 && x == y))
|
||||
error("Multiple BOX positions found");
|
||||
|
||||
x = a->boxPos.x;
|
||||
y = a->boxPos.y;
|
||||
}
|
||||
if (!a->intro.empty() && !_intros.contains(a->intro)) {
|
||||
videos.push_back(MVideo(a->intro, a->introPos, false, false, false));
|
||||
_intros[a->intro] = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (videos.size() > 0) {
|
||||
runIntros(videos);
|
||||
videos.clear();
|
||||
}
|
||||
|
||||
if (x == 0 && x == y)
|
||||
error("BOX position not found");
|
||||
|
||||
// Second iteration on the talk commands
|
||||
for (Actions::const_iterator itt = _conversation.begin(); itt != _conversation.end(); ++itt) {
|
||||
Talk *a = (Talk *)*itt;
|
||||
if (a->active && !skipRepeated) {
|
||||
uint32 frame = 0;
|
||||
Common::String path;
|
||||
for (TalkCommands::const_iterator it = a->commands.begin(); it != a->commands.end(); ++it) {
|
||||
if (it->command == "F") {
|
||||
frame = it->num;
|
||||
} else if (it->command == "G") {
|
||||
path = it->path;
|
||||
}
|
||||
}
|
||||
if (!path.empty()) {
|
||||
activeFound = true;
|
||||
Graphics::Surface *surf = decodeFrame("dialog/" + path, frame);
|
||||
|
||||
drawImage(*speaker, x, y, false);
|
||||
drawImage(*surf, x + speaker->w, y, false);
|
||||
a->rect = Common::Rect(x + speaker->w, y, x + surf->w, y + surf->h);
|
||||
y = y + surf->h;
|
||||
|
||||
surf->free();
|
||||
delete surf;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!activeFound) {
|
||||
debugC(1, kHypnoDebugScene, "No active item was found in the current conversation");
|
||||
// Final iteration on the talk commands
|
||||
bool shouldEscape = false;
|
||||
for (Actions::const_iterator itt = _conversation.begin(); itt != _conversation.end(); ++itt) {
|
||||
Talk *a = (Talk *)*itt;
|
||||
|
||||
// Avoid this conversation next time
|
||||
for (TalkCommands::const_iterator it = a->commands.begin(); it != a->commands.end(); ++it) {
|
||||
if (it->command == "P") {
|
||||
if (!it->path.empty()) {
|
||||
_intros[it->path] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!a->second.empty()) {
|
||||
debugC(1, kHypnoDebugScene, "Adding %s to play after the conversation ends", a->second.c_str());
|
||||
videos.push_back(MVideo(a->second, a->secondPos, false, false, false));
|
||||
}
|
||||
if (a->escape) {
|
||||
shouldEscape = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (videos.size() > 0) {
|
||||
runIntros(videos);
|
||||
videos.clear();
|
||||
}
|
||||
|
||||
endConversation();
|
||||
|
||||
if (shouldEscape) {
|
||||
runIntros(_escapeSequentialVideoToPlay);
|
||||
_escapeSequentialVideoToPlay.clear();
|
||||
|
||||
// HACK
|
||||
Hotspots *hots = stack.back();
|
||||
if (hots->size() == 2) {
|
||||
debugC(1, kHypnoDebugScene, "Level should end here, since there is nothing else to do");
|
||||
_sceneState["GS_LEVELCOMPLETE"] = true;
|
||||
_sceneState["GS_LEVELWON"] = true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
drawScreen();
|
||||
}
|
||||
speaker->free();
|
||||
delete speaker;
|
||||
}
|
||||
|
||||
void SpiderEngine::leftClickedConversation(const Common::Point &mousePos) {
|
||||
defaultCursor();
|
||||
Talk *t;
|
||||
Videos videos;
|
||||
for (Actions::const_iterator itt = _conversation.begin(); itt != _conversation.end(); ++itt) {
|
||||
Talk *a = (Talk *)*itt;
|
||||
if (a->active && a->rect.contains(mousePos)) {
|
||||
a->active = false;
|
||||
for (TalkCommands::const_iterator it = a->commands.begin(); it != a->commands.end(); ++it) {
|
||||
if (it->command == "A") {
|
||||
debugC(1, kHypnoDebugScene, "Adding option %d", it->num);
|
||||
t = (Talk *)_conversation[it->num];
|
||||
t->active = true;
|
||||
_refreshConversation = true;
|
||||
} else if (it->command == "D") {
|
||||
debugC(1, kHypnoDebugScene, "Disabling option %d", it->num);
|
||||
t = (Talk *)_conversation[it->num];
|
||||
t->active = false;
|
||||
_refreshConversation = true;
|
||||
} else if (it->command == "P") {
|
||||
debugC(1, kHypnoDebugScene, "Playing %s", it->path.c_str());
|
||||
videos.push_back(MVideo(it->path, it->position, false, false, false));
|
||||
_refreshConversation = true;
|
||||
} else if (it->command == "S") {
|
||||
debugC(1, kHypnoDebugScene, "Enabling variable %s", it->variable.c_str());
|
||||
_sceneState[it->variable] = 1;
|
||||
_refreshConversation = true;
|
||||
} else if (it->command == "L") {
|
||||
_sceneState["GS_LEVELCOMPLETE"] = true;
|
||||
_refreshConversation = true;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
if (_refreshConversation && !a->background.empty()) {
|
||||
loadImage(a->background, a->backgroundPos.x, a->backgroundPos.y, false);
|
||||
}
|
||||
}
|
||||
|
||||
if (_sceneState["GS_LEVELCOMPLETE"]) {
|
||||
debugC(1, kHypnoDebugScene, "Level is complete, clearing variables");
|
||||
resetSceneState();
|
||||
_sceneState["GS_LEVELCOMPLETE"] = true;
|
||||
_sceneState["GS_LEVELWON"] = true;
|
||||
}
|
||||
|
||||
if (videos.size() > 0)
|
||||
runIntros(videos);
|
||||
}
|
||||
|
||||
void SpiderEngine::rightClickedConversation(const Common::Point &mousePos) {
|
||||
defaultCursor();
|
||||
Videos videos;
|
||||
for (Actions::const_iterator itt = _conversation.begin(); itt != _conversation.end(); ++itt) {
|
||||
Talk *a = (Talk *)*itt;
|
||||
if (a->active && a->rect.contains(mousePos)) {
|
||||
for (TalkCommands::const_iterator it = a->commands.begin(); it != a->commands.end(); ++it) {
|
||||
if (it->command == "I") {
|
||||
debugC(1, kHypnoDebugScene, "Playing %s", it->path.c_str());
|
||||
// Not sure why position is 50, 50 since there is only one pixel
|
||||
videos.push_back(MVideo(it->path, Common::Point(0, 0), false, false, false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (videos.size() > 0)
|
||||
runIntros(videos);
|
||||
}
|
||||
|
||||
bool SpiderEngine::hoverConversation(const Common::Point &mousePos) {
|
||||
Mice mice(_defaultCursor, 1);
|
||||
|
||||
for (Actions::const_iterator itt = _conversation.begin(); itt != _conversation.end(); ++itt) {
|
||||
Talk *a = (Talk *)*itt;
|
||||
if (a->active && a->rect.contains(mousePos)) {
|
||||
runMice(&mice);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
150
engines/hypno/tokens_arc.h
Normal file
150
engines/hypno/tokens_arc.h
Normal file
@@ -0,0 +1,150 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY_HYPNO_ARC_ENGINES_HYPNO_TOKENS_ARC_H_INCLUDED
|
||||
# define YY_HYPNO_ARC_ENGINES_HYPNO_TOKENS_ARC_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef HYPNO_ARC_DEBUG
|
||||
# if defined YYDEBUG
|
||||
#if YYDEBUG
|
||||
# define HYPNO_ARC_DEBUG 1
|
||||
# else
|
||||
# define HYPNO_ARC_DEBUG 0
|
||||
# endif
|
||||
# else /* ! defined YYDEBUG */
|
||||
# define HYPNO_ARC_DEBUG 0
|
||||
# endif /* ! defined YYDEBUG */
|
||||
#endif /* ! defined HYPNO_ARC_DEBUG */
|
||||
#if HYPNO_ARC_DEBUG
|
||||
extern int HYPNO_ARC_debug;
|
||||
#endif
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef HYPNO_ARC_TOKENTYPE
|
||||
# define HYPNO_ARC_TOKENTYPE
|
||||
enum HYPNO_ARC_tokentype
|
||||
{
|
||||
HYPNO_ARC_EMPTY = -2,
|
||||
HYPNO_ARC_EOF = 0, /* "end of file" */
|
||||
HYPNO_ARC_error = 256, /* error */
|
||||
HYPNO_ARC_UNDEF = 257, /* "invalid token" */
|
||||
NAME = 258, /* NAME */
|
||||
FILENAME = 259, /* FILENAME */
|
||||
BNTOK = 260, /* BNTOK */
|
||||
SNTOK = 261, /* SNTOK */
|
||||
YXTOK = 262, /* YXTOK */
|
||||
FNTOK = 263, /* FNTOK */
|
||||
ENCTOK = 264, /* ENCTOK */
|
||||
ONTOK = 265, /* ONTOK */
|
||||
H12TOK = 266, /* H12TOK */
|
||||
NUM = 267, /* NUM */
|
||||
BYTE = 268, /* BYTE */
|
||||
COMMENT = 269, /* COMMENT */
|
||||
ALTOK = 270, /* ALTOK */
|
||||
AVTOK = 271, /* AVTOK */
|
||||
ABTOK = 272, /* ABTOK */
|
||||
CTOK = 273, /* CTOK */
|
||||
DTOK = 274, /* DTOK */
|
||||
HTOK = 275, /* HTOK */
|
||||
HETOK = 276, /* HETOK */
|
||||
HLTOK = 277, /* HLTOK */
|
||||
HUTOK = 278, /* HUTOK */
|
||||
KNTOK = 279, /* KNTOK */
|
||||
RETTOK = 280, /* RETTOK */
|
||||
QTOK = 281, /* QTOK */
|
||||
RESTOK = 282, /* RESTOK */
|
||||
PTOK = 283, /* PTOK */
|
||||
FTOK = 284, /* FTOK */
|
||||
TTOK = 285, /* TTOK */
|
||||
TATOK = 286, /* TATOK */
|
||||
TPTOK = 287, /* TPTOK */
|
||||
TSTOK = 288, /* TSTOK */
|
||||
ATOK = 289, /* ATOK */
|
||||
VTOK = 290, /* VTOK */
|
||||
OTOK = 291, /* OTOK */
|
||||
LTOK = 292, /* LTOK */
|
||||
MTOK = 293, /* MTOK */
|
||||
NTOK = 294, /* NTOK */
|
||||
NRTOK = 295, /* NRTOK */
|
||||
NSTOK = 296, /* NSTOK */
|
||||
RTOK = 297, /* RTOK */
|
||||
R0TOK = 298, /* R0TOK */
|
||||
R1TOK = 299, /* R1TOK */
|
||||
ITOK = 300, /* ITOK */
|
||||
I1TOK = 301, /* I1TOK */
|
||||
GTOK = 302, /* GTOK */
|
||||
JTOK = 303, /* JTOK */
|
||||
J0TOK = 304, /* J0TOK */
|
||||
KTOK = 305, /* KTOK */
|
||||
UTOK = 306, /* UTOK */
|
||||
ZTOK = 307, /* ZTOK */
|
||||
NONETOK = 308, /* NONETOK */
|
||||
A0TOK = 309, /* A0TOK */
|
||||
P0TOK = 310, /* P0TOK */
|
||||
WTOK = 311, /* WTOK */
|
||||
XTOK = 312, /* XTOK */
|
||||
CB3TOK = 313, /* CB3TOK */
|
||||
C02TOK = 314 /* C02TOK */
|
||||
};
|
||||
typedef enum HYPNO_ARC_tokentype HYPNO_ARC_token_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined HYPNO_ARC_STYPE && ! defined HYPNO_ARC_STYPE_IS_DECLARED
|
||||
union HYPNO_ARC_STYPE
|
||||
{
|
||||
#line 97 "engines/hypno/grammar_arc.y"
|
||||
|
||||
char *s; /* string value */
|
||||
int i; /* integer value */
|
||||
|
||||
#line 136 "engines/hypno/tokens_arc.h"
|
||||
|
||||
};
|
||||
typedef union HYPNO_ARC_STYPE HYPNO_ARC_STYPE;
|
||||
# define HYPNO_ARC_STYPE_IS_TRIVIAL 1
|
||||
# define HYPNO_ARC_STYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
extern HYPNO_ARC_STYPE HYPNO_ARC_lval;
|
||||
|
||||
|
||||
int HYPNO_ARC_parse (void);
|
||||
|
||||
|
||||
#endif /* !YY_HYPNO_ARC_ENGINES_HYPNO_TOKENS_ARC_H_INCLUDED */
|
||||
142
engines/hypno/tokens_mis.h
Normal file
142
engines/hypno/tokens_mis.h
Normal file
@@ -0,0 +1,142 @@
|
||||
/* A Bison parser, made by GNU Bison 3.8.2. */
|
||||
|
||||
/* Bison interface for Yacc-like parsers in C
|
||||
|
||||
Copyright (C) 1984, 1989-1990, 2000-2015, 2018-2021 Free Software Foundation,
|
||||
Inc.
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 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 <https://www.gnu.org/licenses/>. */
|
||||
|
||||
/* As a special exception, you may create a larger work that contains
|
||||
part or all of the Bison parser skeleton and distribute that work
|
||||
under terms of your choice, so long as that work isn't itself a
|
||||
parser generator using the skeleton or a modified version thereof
|
||||
as a parser skeleton. Alternatively, if you modify or redistribute
|
||||
the parser skeleton itself, you may (at your option) remove this
|
||||
special exception, which will cause the skeleton and the resulting
|
||||
Bison output files to be licensed under the GNU General Public
|
||||
License without this special exception.
|
||||
|
||||
This special exception was added by the Free Software Foundation in
|
||||
version 2.2 of Bison. */
|
||||
|
||||
/* DO NOT RELY ON FEATURES THAT ARE NOT DOCUMENTED in the manual,
|
||||
especially those whose name start with YY_ or yy_. They are
|
||||
private implementation details that can be changed or removed. */
|
||||
|
||||
#ifndef YY_HYPNO_MIS_ENGINES_HYPNO_TOKENS_MIS_H_INCLUDED
|
||||
# define YY_HYPNO_MIS_ENGINES_HYPNO_TOKENS_MIS_H_INCLUDED
|
||||
/* Debug traces. */
|
||||
#ifndef HYPNO_MIS_DEBUG
|
||||
# if defined YYDEBUG
|
||||
#if YYDEBUG
|
||||
# define HYPNO_MIS_DEBUG 1
|
||||
# else
|
||||
# define HYPNO_MIS_DEBUG 0
|
||||
# endif
|
||||
# else /* ! defined YYDEBUG */
|
||||
# define HYPNO_MIS_DEBUG 0
|
||||
# endif /* ! defined YYDEBUG */
|
||||
#endif /* ! defined HYPNO_MIS_DEBUG */
|
||||
#if HYPNO_MIS_DEBUG
|
||||
extern int HYPNO_MIS_debug;
|
||||
#endif
|
||||
|
||||
/* Token kinds. */
|
||||
#ifndef HYPNO_MIS_TOKENTYPE
|
||||
# define HYPNO_MIS_TOKENTYPE
|
||||
enum HYPNO_MIS_tokentype
|
||||
{
|
||||
HYPNO_MIS_EMPTY = -2,
|
||||
HYPNO_MIS_EOF = 0, /* "end of file" */
|
||||
HYPNO_MIS_error = 256, /* error */
|
||||
HYPNO_MIS_UNDEF = 257, /* "invalid token" */
|
||||
NAME = 258, /* NAME */
|
||||
FILENAME = 259, /* FILENAME */
|
||||
FLAG = 260, /* FLAG */
|
||||
GSSWITCH = 261, /* GSSWITCH */
|
||||
WALNTOK = 262, /* WALNTOK */
|
||||
ENCTOK = 263, /* ENCTOK */
|
||||
NUM = 264, /* NUM */
|
||||
COMMENT = 265, /* COMMENT */
|
||||
HOTSTOK = 266, /* HOTSTOK */
|
||||
CUTSTOK = 267, /* CUTSTOK */
|
||||
BACKTOK = 268, /* BACKTOK */
|
||||
INTRTOK = 269, /* INTRTOK */
|
||||
RETTOK = 270, /* RETTOK */
|
||||
TIMETOK = 271, /* TIMETOK */
|
||||
PALETOK = 272, /* PALETOK */
|
||||
BBOXTOK = 273, /* BBOXTOK */
|
||||
OVERTOK = 274, /* OVERTOK */
|
||||
MICETOK = 275, /* MICETOK */
|
||||
SONDTOK = 276, /* SONDTOK */
|
||||
PLAYTOK = 277, /* PLAYTOK */
|
||||
ENDTOK = 278, /* ENDTOK */
|
||||
MENUTOK = 279, /* MENUTOK */
|
||||
SMENTOK = 280, /* SMENTOK */
|
||||
ESCPTOK = 281, /* ESCPTOK */
|
||||
NRTOK = 282, /* NRTOK */
|
||||
AMBITOK = 283, /* AMBITOK */
|
||||
SWPTTOK = 284, /* SWPTTOK */
|
||||
MPTRTOK = 285, /* MPTRTOK */
|
||||
GLOBTOK = 286, /* GLOBTOK */
|
||||
TONTOK = 287, /* TONTOK */
|
||||
TOFFTOK = 288, /* TOFFTOK */
|
||||
TALKTOK = 289, /* TALKTOK */
|
||||
INACTOK = 290, /* INACTOK */
|
||||
FDTOK = 291, /* FDTOK */
|
||||
BOXXTOK = 292, /* BOXXTOK */
|
||||
ESCAPETOK = 293, /* ESCAPETOK */
|
||||
SECONDTOK = 294, /* SECONDTOK */
|
||||
INTROTOK = 295, /* INTROTOK */
|
||||
DEFAULTTOK = 296, /* DEFAULTTOK */
|
||||
PG = 297, /* PG */
|
||||
PA = 298, /* PA */
|
||||
PD = 299, /* PD */
|
||||
PH = 300, /* PH */
|
||||
PF = 301, /* PF */
|
||||
PP = 302, /* PP */
|
||||
PI = 303, /* PI */
|
||||
PS = 304, /* PS */
|
||||
PE = 305, /* PE */
|
||||
PL = 306 /* PL */
|
||||
};
|
||||
typedef enum HYPNO_MIS_tokentype HYPNO_MIS_token_kind_t;
|
||||
#endif
|
||||
|
||||
/* Value type. */
|
||||
#if ! defined HYPNO_MIS_STYPE && ! defined HYPNO_MIS_STYPE_IS_DECLARED
|
||||
union HYPNO_MIS_STYPE
|
||||
{
|
||||
#line 57 "engines/hypno/grammar_mis.y"
|
||||
|
||||
char *s; /* string value */
|
||||
int i; /* integer value */
|
||||
|
||||
#line 128 "engines/hypno/tokens_mis.h"
|
||||
|
||||
};
|
||||
typedef union HYPNO_MIS_STYPE HYPNO_MIS_STYPE;
|
||||
# define HYPNO_MIS_STYPE_IS_TRIVIAL 1
|
||||
# define HYPNO_MIS_STYPE_IS_DECLARED 1
|
||||
#endif
|
||||
|
||||
|
||||
extern HYPNO_MIS_STYPE HYPNO_MIS_lval;
|
||||
|
||||
|
||||
int HYPNO_MIS_parse (void);
|
||||
|
||||
|
||||
#endif /* !YY_HYPNO_MIS_ENGINES_HYPNO_TOKENS_MIS_H_INCLUDED */
|
||||
60
engines/hypno/video.cpp
Normal file
60
engines/hypno/video.cpp
Normal file
@@ -0,0 +1,60 @@
|
||||
/* 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"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
MVideo::MVideo(Common::String path_, Common::Point position_, bool transparent_, bool scaled_, bool loop_) {
|
||||
decoder = nullptr;
|
||||
path = path_;
|
||||
position = position_;
|
||||
scaled = scaled_;
|
||||
transparent = transparent_;
|
||||
loop = loop_;
|
||||
}
|
||||
|
||||
bool HypnoSmackerDecoder::loadStream(Common::SeekableReadStream *stream) {
|
||||
if (!SmackerDecoder::loadStream(stream))
|
||||
return false;
|
||||
|
||||
// Map audio tracks to sound types
|
||||
for (uint32 i = 0; i < 8; i++) {
|
||||
Track *t = getTrack(i);
|
||||
if (t && t->getTrackType() == Track::kTrackTypeAudio) {
|
||||
AudioTrack *audio = (AudioTrack *)t;
|
||||
audio->setMute(false);
|
||||
audio->setSoundType(i == 7 ? Audio::Mixer::kSpeechSoundType : Audio::Mixer::kSFXSoundType);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
uint32 HypnoSmackerDecoder::getSignatureVersion(uint32 signature) const {
|
||||
if (signature == MKTAG('H', 'Y', 'P', '2')) {
|
||||
return 2;
|
||||
} else {
|
||||
return SmackerDecoder::getSignatureVersion(signature);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
1198
engines/hypno/wet/arcade.cpp
Normal file
1198
engines/hypno/wet/arcade.cpp
Normal file
File diff suppressed because it is too large
Load Diff
119
engines/hypno/wet/cursors.cpp
Normal file
119
engines/hypno/wet/cursors.cpp
Normal file
@@ -0,0 +1,119 @@
|
||||
/* 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 "graphics/cursorman.h"
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
static const byte MOUSECURSOR_SCI[] = {
|
||||
1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 1, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 1, 0, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 1, 0, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 1, 0, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 1, 0, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 1, 0, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 1, 0,
|
||||
1, 3, 3, 3, 3, 3, 3, 3, 3, 3, 1,
|
||||
1, 3, 3, 3, 3, 3, 1, 0, 0, 0, 0,
|
||||
1, 3, 1, 0, 1, 3, 3, 1, 0, 0, 0,
|
||||
1, 1, 0, 0, 1, 3, 3, 1, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 3, 3, 1, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 3, 3, 1, 0};
|
||||
|
||||
static const byte circleCursor[] = {
|
||||
0, 0, 0, 0, 250, 250, 250, 250, 250, 0, 0, 0, 0,
|
||||
0, 0, 250, 250, 0, 0, 0, 0, 0, 250, 250, 0, 0,
|
||||
0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
|
||||
0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
|
||||
250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250,
|
||||
250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250,
|
||||
250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250,
|
||||
0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
|
||||
0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
|
||||
0, 0, 250, 250, 0, 0, 0, 0, 0, 250, 250, 0, 0,
|
||||
0, 0, 0, 0, 250, 250, 250, 250, 250, 0, 0, 0, 0};
|
||||
|
||||
static const byte targetCursor[] = {
|
||||
0, 0, 0, 252, 252, 252, 252, 252, 252, 252, 252, 252, 0, 0, 0,
|
||||
0, 0, 252, 0, 0, 250, 250, 250, 250, 250, 0, 0, 252, 0, 0,
|
||||
0, 252, 0, 250, 250, 0, 0, 0, 0, 0, 250, 250, 0, 252, 0,
|
||||
252, 0, 250, 0, 0, 252, 252, 252, 252, 252, 0, 0, 250, 0, 252,
|
||||
252, 0, 250, 0, 252, 0, 0, 0, 0, 0, 252, 0, 250, 0, 252,
|
||||
252, 250, 0, 252, 0, 0, 0, 0, 0, 0, 0, 252, 0, 250, 252,
|
||||
252, 250, 0, 252, 0, 0, 0, 0, 0, 0, 0, 252, 0, 250, 252,
|
||||
252, 250, 0, 252, 0, 0, 0, 0, 0, 0, 0, 252, 0, 250, 252,
|
||||
252, 0, 250, 0, 252, 0, 0, 0, 0, 0, 252, 0, 250, 0, 252,
|
||||
252, 0, 250, 0, 0, 252, 252, 252, 252, 252, 0, 0, 250, 0, 252,
|
||||
0, 252, 0, 250, 250, 0, 0, 0, 0, 0, 250, 250, 0, 252, 0,
|
||||
0, 0, 252, 0, 0, 250, 250, 250, 250, 250, 0, 0, 252, 0, 0,
|
||||
0, 0, 0, 252, 252, 252, 252, 252, 252, 252, 252, 252, 0, 0, 0};
|
||||
|
||||
static const byte crosshairCursor[] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 250, 250, 250, 250, 250, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 250, 250, 0, 0, 250, 0, 0, 250, 250, 0, 0, 0,
|
||||
0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
|
||||
0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
|
||||
0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
|
||||
250, 250, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 250, 250,
|
||||
0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0,
|
||||
0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
|
||||
0, 0, 250, 0, 0, 0, 0, 0, 0, 0, 0, 0, 250, 0, 0,
|
||||
0, 0, 0, 250, 250, 0, 0, 250, 0, 0, 250, 250, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 250, 250, 250, 250, 250, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 250, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
struct CursorTable {
|
||||
const char *name;
|
||||
const void *buf;
|
||||
int w;
|
||||
int h;
|
||||
int hotspotX;
|
||||
int hotspotY;
|
||||
};
|
||||
|
||||
static const CursorTable cursorTable[] = {
|
||||
{"default", MOUSECURSOR_SCI, 11, 16, 0, 0},
|
||||
{"arcade", circleCursor, 13, 11, 7, 5},
|
||||
{"target", targetCursor, 15, 13, 8, 6},
|
||||
{"crosshair", crosshairCursor, 15, 13, 8, 6},
|
||||
{nullptr, nullptr, 0, 0, 0, 0}};
|
||||
|
||||
void WetEngine::changeCursor(const Common::String &cursor) {
|
||||
const CursorTable *entry = cursorTable;
|
||||
while (entry->name) {
|
||||
if (cursor == entry->name)
|
||||
break;
|
||||
entry++;
|
||||
}
|
||||
assert(entry->name);
|
||||
|
||||
CursorMan.replaceCursor(entry->buf, entry->w, entry->h, entry->hotspotX, entry->hotspotY, 0);
|
||||
CursorMan.showMouse(true);
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
|
||||
427
engines/hypno/wet/hard.cpp
Normal file
427
engines/hypno/wet/hard.cpp
Normal file
@@ -0,0 +1,427 @@
|
||||
/* 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/bitarray.h"
|
||||
#include "gui/message.h"
|
||||
#include "common/events.h"
|
||||
#include "common/config-manager.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
#include "backends/keymapper/keymapper.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
void WetEngine::endCredits(Code *code) {
|
||||
showCredits();
|
||||
_nextLevel = "<main_menu>";
|
||||
}
|
||||
|
||||
void WetEngine::runCode(Code *code) {
|
||||
changeScreenMode("320x200");
|
||||
if (code->name == "<main_menu>")
|
||||
runMainMenu(code);
|
||||
else if (code->name == "<level_menu>")
|
||||
runLevelMenu(code);
|
||||
else if (code->name == "<check_lives>")
|
||||
runCheckLives(code);
|
||||
else if (code->name == "<credits>")
|
||||
endCredits(code);
|
||||
else
|
||||
error("invalid hardcoded level: %s", code->name.c_str());
|
||||
}
|
||||
|
||||
void WetEngine::runCheckLives(Code *code) {
|
||||
if (_lives < 0) {
|
||||
_nextLevel = "<game_over>";
|
||||
_score = 0;
|
||||
_lives = 2;
|
||||
restoreScoreMilestones(_score);
|
||||
saveProfile(_name, _lastLevel);
|
||||
} else
|
||||
_nextLevel = _checkpoint;
|
||||
}
|
||||
|
||||
void WetEngine::runLevelMenu(Code *code) {
|
||||
if (_lastLevel == 0) {
|
||||
_nextLevel = Common::String::format("c%d", _ids[0]);
|
||||
return;
|
||||
}
|
||||
|
||||
Common::Event event;
|
||||
byte *palette;
|
||||
Graphics::Surface *menu = decodeFrame("c_misc/menus.smk", 20, &palette);
|
||||
loadPalette(palette, 0, 256);
|
||||
free(palette);
|
||||
byte black[3] = {0x00, 0x00, 0x00}; // Always red?
|
||||
byte lime[3] = {0x00, 0xFF, 0x00}; // Always red?
|
||||
byte green[3] = {0x2C, 0x82, 0x28}; // Always red?
|
||||
int maxLevel = 20;
|
||||
int currentLevel = 0;
|
||||
for (int i = 0; i < maxLevel; i++)
|
||||
if (i <= _lastLevel)
|
||||
loadPalette((byte *) &green, 192+i, 1);
|
||||
else
|
||||
loadPalette((byte *) &black, 192+i, 1);
|
||||
|
||||
loadPalette((byte *) &lime, 192+currentLevel, 1);
|
||||
drawImage(*menu, 0, 0, false);
|
||||
bool cont = true;
|
||||
// TODO: Should this be played as music instead?
|
||||
playSound("sound/bub01.raw", 0, 22050);
|
||||
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
keymapper->getKeymap("menu")->setEnabled(true);
|
||||
|
||||
while (!shouldQuit() && cont) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
// Events
|
||||
switch (event.type) {
|
||||
|
||||
case Common::EVENT_QUIT:
|
||||
case Common::EVENT_RETURN_TO_LAUNCHER:
|
||||
break;
|
||||
|
||||
case Common::EVENT_CUSTOM_ENGINE_ACTION_START:
|
||||
if (event.customType == kActionDown && currentLevel < _lastLevel) {
|
||||
playSound("sound/m_hilite.raw", 1, 11025);
|
||||
currentLevel++;
|
||||
} else if (event.customType == kActionUp && currentLevel > 0) {
|
||||
playSound("sound/m_hilite.raw", 1, 11025);
|
||||
currentLevel--;
|
||||
} else if (event.customType == kActionSelect ) {
|
||||
playSound("sound/m_choice.raw", 1, 11025);
|
||||
_nextLevel = Common::String::format("c%d", _ids[currentLevel]);
|
||||
cont = false;
|
||||
} else if (event.customType == kActionPause) {
|
||||
openMainMenuDialog();
|
||||
}
|
||||
|
||||
for (int i = 0; i < maxLevel; i++)
|
||||
if (i <= _lastLevel)
|
||||
loadPalette((byte *) &green, 192+i, 1);
|
||||
else
|
||||
loadPalette((byte *) &black, 192+i, 1);
|
||||
|
||||
|
||||
loadPalette((byte *) &lime, 192+currentLevel, 1);
|
||||
drawImage(*menu, 0, 0, false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
keymapper->getKeymap("menu")->setEnabled(false);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
|
||||
menu->free();
|
||||
delete menu;
|
||||
}
|
||||
|
||||
void WetEngine::runMainMenu(Code *code) {
|
||||
Common::Event event;
|
||||
uint32 c = 252; // green
|
||||
byte *palette;
|
||||
Graphics::Surface *menu = decodeFrame("c_misc/menus.smk", 16, &palette);
|
||||
Graphics::Surface *overlay = decodeFrame("c_misc/menus.smk", 18, nullptr);
|
||||
loadPalette(palette, 0, 256);
|
||||
free(palette);
|
||||
Common::Rect subName(21, 10, 169, 24);
|
||||
|
||||
drawImage(*menu, 0, 0, false);
|
||||
Graphics::Surface surName = overlay->getSubArea(subName);
|
||||
drawImage(surName, subName.left, subName.top, true);
|
||||
drawString("scifi08.fgx", _enterNameString, 48, 50, 100, c);
|
||||
_name.clear();
|
||||
|
||||
Common::Keymapper *keymapper = g_system->getEventManager()->getKeymapper();
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
keymapper->getKeymap("pause")->setEnabled(false);
|
||||
keymapper->getKeymap("direction")->setEnabled(false);
|
||||
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, true);
|
||||
|
||||
bool cont = true;
|
||||
while (!shouldQuit() && cont) {
|
||||
while (g_system->getEventManager()->pollEvent(event)) {
|
||||
// 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_BACKSPACE)
|
||||
_name.deleteLastChar();
|
||||
else if (event.kbd.keycode == Common::KEYCODE_RETURN && !_name.empty()) {
|
||||
cont = false;
|
||||
} else if (Common::isAlpha(event.kbd.keycode)) {
|
||||
playSound("sound/m_choice.raw", 1);
|
||||
_name = _name + char(event.kbd.keycode - 32);
|
||||
} if (event.kbd.keycode == Common::KEYCODE_ESCAPE) {
|
||||
openMainMenuDialog();
|
||||
}
|
||||
|
||||
drawImage(*menu, 0, 0, false);
|
||||
drawImage(surName, subName.left, subName.top, true);
|
||||
drawString("scifi08.fgx", _enterNameString, 48, 50, 100, c);
|
||||
drawString("scifi08.fgx", _name, 140, 50, 170, c);
|
||||
break;
|
||||
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
if (_name == "COOLCOLE" || _unlockAllLevels) {
|
||||
_lastLevel = 19;
|
||||
playSound("sound/extra.raw", 1);
|
||||
} else
|
||||
_lastLevel = 0;
|
||||
|
||||
if (_name == "ELRAPIDO") {
|
||||
_infiniteAmmoCheat = true;
|
||||
playSound("sound/extra.raw", 1);
|
||||
}
|
||||
|
||||
if (_name == "SAVANNAH") {
|
||||
_infiniteHealthCheat = true;
|
||||
playSound("sound/extra.raw", 1);
|
||||
}
|
||||
|
||||
if ((_name == "FRASCAS" && _language == Common::ES_ESP) || \
|
||||
(_name == "RITCHY" && _language == Common::FR_FRA)) {
|
||||
_infiniteAmmoCheat = true;
|
||||
_infiniteHealthCheat = true;
|
||||
_lastLevel = 19;
|
||||
playSound("sound/extra.raw", 1);
|
||||
}
|
||||
|
||||
_name.toLowercase();
|
||||
bool found = loadProfile(_name);
|
||||
|
||||
g_system->setFeatureState(OSystem::kFeatureVirtualKeyboard, false);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
keymapper->getKeymap("pause")->setEnabled(true);
|
||||
keymapper->getKeymap("direction")->setEnabled(true);
|
||||
|
||||
if (found || _name.empty()) {
|
||||
menu->free();
|
||||
delete menu;
|
||||
overlay->free();
|
||||
delete overlay;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
saveProfile(_name, _ids[_lastLevel]);
|
||||
_name.toUppercase(); // We do this in order to show it again
|
||||
|
||||
Common::Rect subDifficulty(20, 104, 233, 119);
|
||||
Graphics::Surface surDifficulty = overlay->getSubArea(subDifficulty);
|
||||
drawImage(*menu, 0, 0, false);
|
||||
drawImage(surDifficulty, subDifficulty.left, subDifficulty.top, true);
|
||||
|
||||
Common::Rect subWet(129, 149, 195, 159);
|
||||
Graphics::Surface surWet = overlay->getSubArea(subWet);
|
||||
drawImage(surWet, subWet.left, subWet.top, true);
|
||||
playSound("sound/no_rapid.raw", 1, 11025);
|
||||
|
||||
Common::Rect subDamp(52, 149, 115, 159);
|
||||
Graphics::Surface surDamp = overlay->getSubArea(subDamp);
|
||||
|
||||
Common::Rect subSoaked(202, 149, 272, 159);
|
||||
Graphics::Surface surSoaked = overlay->getSubArea(subSoaked);
|
||||
|
||||
Common::Array<Common::String> difficulties;
|
||||
difficulties.push_back("0");
|
||||
difficulties.push_back("1");
|
||||
difficulties.push_back("2");
|
||||
uint32 idx = 1;
|
||||
|
||||
drawString("scifi08.fgx", _enterNameString, 48, 50, 100, c);
|
||||
drawString("scifi08.fgx", _name, 140, 50, 170, c);
|
||||
|
||||
cont = true;
|
||||
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(false);
|
||||
keymapper->getKeymap("pause")->setEnabled(false);
|
||||
keymapper->getKeymap("menu")->setEnabled(true);
|
||||
|
||||
while (!shouldQuit() && cont) {
|
||||
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_CUSTOM_ENGINE_ACTION_START:
|
||||
if (!g_system->hasFeature(OSystem::kFeatureTouchscreen))
|
||||
event.mouse = Common::Point(0, 0);
|
||||
|
||||
if (idx == 1 && (subDamp.contains(event.mouse) || subSoaked.contains(event.mouse))) {
|
||||
if (subDamp.contains(event.mouse)) {
|
||||
playSound("sound/no_rapid.raw", 1, 11025);
|
||||
idx--;
|
||||
} else if (subSoaked.contains(event.mouse)) {
|
||||
playSound("sound/no_rapid.raw", 1, 11025);
|
||||
idx++;
|
||||
}
|
||||
} else if (idx == 1 && subWet.contains(event.mouse)) {
|
||||
// Nothing
|
||||
} else if ((subWet.contains(event.mouse) || subDamp.contains(event.mouse) || event.customType == kActionLeft) && idx > 0) {
|
||||
playSound("sound/no_rapid.raw", 1, 11025);
|
||||
idx--;
|
||||
} else if ((subWet.contains(event.mouse) || subSoaked.contains(event.mouse) || event.customType == kActionRight) && idx < 2) {
|
||||
playSound("sound/no_rapid.raw", 1, 11025);
|
||||
idx++;
|
||||
} else if (event.customType == kActionSelect)
|
||||
cont = false;
|
||||
|
||||
drawImage(*menu, 0, 0, false);
|
||||
drawImage(surDifficulty, subDifficulty.left, subDifficulty.top, true);
|
||||
|
||||
if (difficulties[idx] == "0")
|
||||
drawImage(surDamp, subDamp.left, subDamp.top, true);
|
||||
else if (difficulties[idx] == "1")
|
||||
drawImage(surWet, subWet.left, subWet.top, true);
|
||||
else if (difficulties[idx] == "2")
|
||||
drawImage(surSoaked, subSoaked.left, subSoaked.top, true);
|
||||
else
|
||||
error("Invalid difficulty: %s", difficulties[idx].c_str());
|
||||
|
||||
drawString("scifi08.fgx", _enterNameString, 48, 50, 100, c);
|
||||
drawString("scifi08.fgx", _name, 140, 50, 170, c);
|
||||
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
drawScreen();
|
||||
g_system->delayMillis(10);
|
||||
}
|
||||
|
||||
keymapper->getKeymap("menu")->setEnabled(false);
|
||||
keymapper->getKeymap("game-shortcuts")->setEnabled(true);
|
||||
keymapper->getKeymap("pause")->setEnabled(true);
|
||||
|
||||
_name.toLowercase(); // make sure it is lowercase when we finish
|
||||
_difficulty = difficulties[idx];
|
||||
_nextLevel = code->levelIfWin;
|
||||
menu->free();
|
||||
delete menu;
|
||||
overlay->free();
|
||||
delete overlay;
|
||||
}
|
||||
|
||||
void WetEngine::showDemoScore() {
|
||||
Common::String fmessage = "You finished this demo level with an accuracy of %d%% and a score of %d points";
|
||||
Common::String message = Common::String::format(fmessage.c_str(), accuracyRatio(), _score);
|
||||
GUI::MessageDialog dialog(message);
|
||||
dialog.runModal();
|
||||
}
|
||||
|
||||
Common::String WetEngine::getLocalizedString(const Common::String &name) {
|
||||
if (name == "name") {
|
||||
switch (_language) {
|
||||
case Common::FR_FRA:
|
||||
return "NOM :";
|
||||
case Common::ES_ESP:
|
||||
return "NOMBRE :";
|
||||
case Common::KO_KOR:
|
||||
return "\xb7\xa1\x9f\x71\xb7\xb3\x9d\x62:";
|
||||
default:
|
||||
return "ENTER NAME :";
|
||||
}
|
||||
} else if (name == "health") {
|
||||
switch (_language) {
|
||||
case Common::FR_FRA:
|
||||
return "ENERGIE";
|
||||
case Common::ES_ESP:
|
||||
return "ENERGIA";
|
||||
case Common::KO_KOR:
|
||||
return "\xb5\x41\x90\xe1\xbb\xa1"; // 체력 (health)
|
||||
default:
|
||||
return "ENERGY";
|
||||
}
|
||||
} else if (name == "objectives") {
|
||||
switch (_language) {
|
||||
case Common::FR_FRA:
|
||||
return "OBJ.";
|
||||
case Common::ES_ESP:
|
||||
return "O. M.";
|
||||
case Common::KO_KOR:
|
||||
return "\xa1\xa2\xce\x61"; // 목표 (objective)
|
||||
default:
|
||||
return "M. O.";
|
||||
}
|
||||
} else if (name == "score") {
|
||||
switch (_language) {
|
||||
case Common::ES_ESP:
|
||||
return "PUNTOS";
|
||||
case Common::KO_KOR:
|
||||
return "\xb8\xf1\xae\x81"; // 점수 (score)
|
||||
default:
|
||||
return "SCORE";
|
||||
}
|
||||
} else if (name == "target") {
|
||||
switch (_language) {
|
||||
case Common::FR_FRA:
|
||||
return "VERROUILLAGE";
|
||||
case Common::ES_ESP:
|
||||
return "BLANCO FIJADO";
|
||||
case Common::KO_KOR:
|
||||
return "\xa1\xa2\xce\x61\x20\xbb\xe1\xaf\x81"; // 목표물포착 (target acquired)
|
||||
default:
|
||||
return "TARGET ACQUIRED";
|
||||
}
|
||||
} else if (name == "direction") {
|
||||
switch (_language) {
|
||||
case Common::FR_FRA:
|
||||
return "DIRECTION ?";
|
||||
case Common::ES_ESP:
|
||||
return "ELIGE DIRECCION";
|
||||
case Common::KO_KOR:
|
||||
return "\xa4\x77\xd0\xb7\xac\xe5\x00\x00\xc8\x82"; // 전향선택 (choose direction)
|
||||
default:
|
||||
return "CHOOSE DIRECTION";
|
||||
}
|
||||
} else
|
||||
error("Invalid string name to localize: %s", name.c_str());
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
861
engines/hypno/wet/wet.cpp
Normal file
861
engines/hypno/wet/wet.cpp
Normal file
@@ -0,0 +1,861 @@
|
||||
/* 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/bitarray.h"
|
||||
#include "common/events.h"
|
||||
#include "common/savefile.h"
|
||||
|
||||
#include "hypno/hypno.h"
|
||||
|
||||
#include "engines/metaengine.h"
|
||||
#include "engines/savestate.h"
|
||||
|
||||
namespace Hypno {
|
||||
|
||||
static const char *failedDetectionError = \
|
||||
"Failed to load any files from missions.lib.\
|
||||
Please review https://wiki.scummvm.org/index.php?title=Wetlands\
|
||||
and re-add the game.";
|
||||
|
||||
static const chapterEntry rawChapterTable[] = {
|
||||
{11, {44, 172}, {218, 172}, {0, 0}, {127, 172}, 0, kHypnoColorRed}, // c11
|
||||
{10, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoNoColor}, // c10
|
||||
{21, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorYellow}, // c21
|
||||
{22, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorGreen}, // c22
|
||||
{23, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorCyan}, // c23
|
||||
{20, {128, 150}, {238, 150},{0, 0}, {209, 146}, 0, kHypnoColorCyan}, // c20
|
||||
{31, {70, 160}, {180, 160}, {220, 185}, {44, 164}, 215, kHypnoColorGreen}, // c31
|
||||
{32, {70, 160}, {180, 160}, {220, 185}, {44, 164}, 215, kHypnoColorRed}, // c32
|
||||
{33, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c33
|
||||
{30, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoColorRed}, // c30
|
||||
{41, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c41
|
||||
{42, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c42
|
||||
{43, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c43
|
||||
{44, {70, 160}, {180, 160}, {220, 185}, {44, 162}, 215, kHypnoColorRed}, // c44
|
||||
{40, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoColorRed}, // c40
|
||||
{51, {60, 167}, {190, 167}, {135, 187}, {136, 163}, 36, kHypnoColorRed}, // c51
|
||||
{52, {60, 167}, {190, 167}, {135, 187}, {136, 165}, 36, kHypnoColorCyan}, // c52
|
||||
{50, {19, 3}, {246, 3}, {246, 11}, {2, 2}, 0, kHypnoColorRed}, // c50 (fixed)
|
||||
{61, {63, 167}, {187, 167}, {192, 188}, {152, 185}, 0, kHypnoColorCyan}, // c61
|
||||
{60, {63, 167}, {187, 167}, {192, 188}, {152, 185}, 0, kHypnoColorCyan}, // c60
|
||||
{0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoColorRed} // NULL
|
||||
};
|
||||
|
||||
static const chapterEntry rawChapterTableEarlyDemo[] = {
|
||||
{31, {48, 15}, {205, 15}, {0, 0}, {0, 0}, 0, kHypnoColorRed}, // c31
|
||||
{41, {48, 15}, {205, 15}, {0, 0}, {0, 0}, 0, kHypnoColorRed}, // c41
|
||||
{0, {0, 0}, {0, 0}, {0, 0}, {0, 0}, 0, kHypnoColorRed} // NULL
|
||||
};
|
||||
|
||||
WetEngine::WetEngine(OSystem *syst, const ADGameDescription *gd) : HypnoEngine(syst, gd) {
|
||||
_screenW = 320;
|
||||
_screenH = 200;
|
||||
_lives = 2;
|
||||
_lastLevel = 0;
|
||||
|
||||
_c33UseMouse = true;
|
||||
|
||||
_c40SegmentIdx = -1;
|
||||
_c40lastTurn = -1;
|
||||
|
||||
_c50LeftTurns = 0;
|
||||
_c50RigthTurns = 0;
|
||||
|
||||
_rButtonUp = false;
|
||||
|
||||
const chapterEntry *entry = rawChapterTable;
|
||||
while (entry->id) {
|
||||
_ids.push_back(entry->id);
|
||||
_chapterTable[entry->id] = entry;
|
||||
entry++;
|
||||
}
|
||||
|
||||
_healthString = getLocalizedString("health");
|
||||
_scoreString = getLocalizedString("score");
|
||||
_objString = getLocalizedString("objectives");
|
||||
_targetString = getLocalizedString("target");
|
||||
_directionString = getLocalizedString("direction");
|
||||
_enterNameString = getLocalizedString("name");
|
||||
}
|
||||
|
||||
WetEngine::~WetEngine() {
|
||||
}
|
||||
|
||||
void WetEngine::loadAssets() {
|
||||
if (!isDemo()) {
|
||||
_difficulty = "1"; // Medium difficulty by default
|
||||
loadAssetsFullGame();
|
||||
return;
|
||||
}
|
||||
_difficulty = ""; // No difficulty selection in demo
|
||||
|
||||
if (_variant == "Demo" || _variant == "DemoHebrew" || _variant == "M&MCD")
|
||||
loadAssetsDemoDisc();
|
||||
else if (_variant == "EarlyDemo")
|
||||
loadAssetsEarlyDemo();
|
||||
else if (_variant == "Gen4")
|
||||
loadAssetsGen4();
|
||||
else if (_variant == "PCWDemo")
|
||||
loadAssetsPCW();
|
||||
else if (_variant == "PCGDemo")
|
||||
loadAssetsPCG();
|
||||
else if (_variant == "NonInteractive" || _variant == "NonInteractiveJoystick")
|
||||
loadAssetsNI();
|
||||
else
|
||||
error("Invalid demo version: \"%s\"", _variant.c_str());
|
||||
}
|
||||
|
||||
|
||||
void WetEngine::loadAssetsDemoDisc() {
|
||||
|
||||
bool encrypted = _variant == "Demo" || _variant == "M&MCD" ? true : false;
|
||||
LibFile *missions = loadLib("", "wetlands/c_misc/missions.lib", encrypted);
|
||||
Common::ArchiveMemberList files;
|
||||
if (missions->listMembers(files) == 0)
|
||||
error("%s", failedDetectionError);
|
||||
|
||||
Hotspot h(MakeMenu);
|
||||
Hotspots hs;
|
||||
Ambient *a = new Ambient("movie/selector.smk", Common::Point(0, 0), "/LOOP");
|
||||
a->fullscreen = true;
|
||||
h.actions.push_back(a);
|
||||
|
||||
hs.push_back(h);
|
||||
|
||||
h.type = MakeHotspot;
|
||||
h.rect = Common::Rect(0, 177, 116, 192);
|
||||
h.actions.clear();
|
||||
h.smenu = nullptr;
|
||||
ChangeLevel *cl = new ChangeLevel("<intro>");
|
||||
h.actions.push_back(cl);
|
||||
|
||||
hs.push_back(h);
|
||||
|
||||
h.rect = Common::Rect(121, 177, 250, 200);
|
||||
cl = new ChangeLevel("<movies>");
|
||||
h.actions.clear();
|
||||
h.actions.push_back(cl);
|
||||
|
||||
hs.push_back(h);
|
||||
|
||||
h.rect = Common::Rect(252, 177, 318, 200);
|
||||
Quit *q = new Quit();
|
||||
h.actions.clear();
|
||||
h.actions.push_back(q);
|
||||
|
||||
hs.push_back(h);
|
||||
|
||||
Scene *start = new Scene();
|
||||
start->resolution = "320x200";
|
||||
start->hots = hs;
|
||||
_levels["<start>"] = start;
|
||||
|
||||
Transition *intro;
|
||||
if (_variant == "Demo" || _variant == "M&MCD")
|
||||
intro = new Transition("c31");
|
||||
else if (_variant == "DemoHebrew")
|
||||
intro = new Transition("c31.mis");
|
||||
else
|
||||
error("Unsupported language");
|
||||
|
||||
if (_variant == "M&MCD") {
|
||||
intro->intros.push_back("wetlands/c_misc/nw_logo.smk");
|
||||
intro->intros.push_back("wetlands/c_misc/h.s");
|
||||
intro->intros.push_back("wetlands/c_misc/w.s");
|
||||
intro->frameImage = "wetlands/c_misc/c.s";
|
||||
intro->frameNumber = 0;
|
||||
} else {
|
||||
intro->intros.push_back("movie/nw_logo.smk");
|
||||
intro->intros.push_back("movie/hypnotix.smk");
|
||||
intro->intros.push_back("movie/wetlogo.smk");
|
||||
intro->frameImage = "wetlands/c_misc/c.s";
|
||||
intro->frameNumber = 0;
|
||||
}
|
||||
_levels["<intro>"] = intro;
|
||||
|
||||
if (_variant == "M&MCD") // This variant has no selector
|
||||
_levels["<start>"] = intro;
|
||||
|
||||
Transition *movies = new Transition("<quit>");
|
||||
movies->intros.push_back("movie/nw_logo.smk");
|
||||
movies->intros.push_back("movie/hypnotix.smk");
|
||||
movies->intros.push_back("movie/wetlogo.smk");
|
||||
movies->intros.push_back("movie/c42e1s.smk");
|
||||
movies->intros.push_back("movie/c23e1s.smk");
|
||||
movies->intros.push_back("movie/c20o1s.smk");
|
||||
movies->intros.push_back("movie/c23d1s.smk");
|
||||
movies->intros.push_back("movie/c40o1s.smk");
|
||||
movies->intros.push_back("movie/c31d1s.smk");
|
||||
movies->intros.push_back("movie/c42d1s.smk");
|
||||
movies->intros.push_back("movie/c44d1s.smk");
|
||||
movies->intros.push_back("movie/c44e1s.smk");
|
||||
movies->intros.push_back("movie/c32d1s.smk");
|
||||
movies->intros.push_back("movie/c22e1s.smk");
|
||||
movies->intros.push_back("movie/c31e1s.smk");
|
||||
movies->intros.push_back("movie/gameover.smk");
|
||||
movies->frameImage = "";
|
||||
movies->frameNumber = 0;
|
||||
_levels["<movies>"] = movies;
|
||||
ArcadeShooting *arc;
|
||||
|
||||
if (_variant == "Demo" || _variant == "M&MCD") {
|
||||
loadArcadeLevel("c31.mi_", "c52", "c52", "wetlands");
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c31.mi_"];
|
||||
arc->segments[0].size = 1354;
|
||||
arc->objKillsRequired[0] = 2;
|
||||
}
|
||||
loadArcadeLevel("c52.mi_", "<game_over>", "<quit>", "wetlands");
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c52.mi_"];
|
||||
arc->segments[0].size = 2383;
|
||||
arc->objKillsRequired[0] = 2;
|
||||
arc->objKillsRequired[1] = 13;
|
||||
}
|
||||
} else if (_variant == "DemoHebrew") {
|
||||
loadArcadeLevel("c31.mis", "c52.mis", "c52.mis", "wetlands");
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c31.mis"];
|
||||
arc->segments[0].size = 1354;
|
||||
arc->objKillsRequired[0] = 2;
|
||||
}
|
||||
loadArcadeLevel("c52.mis", "<game_over>", "<quit>", "wetlands");
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c52.mis"];
|
||||
arc->segments[0].size = 2383;
|
||||
arc->objKillsRequired[0] = 2;
|
||||
arc->objKillsRequired[1] = 13;
|
||||
}
|
||||
} else {
|
||||
error("Unsupported variant");
|
||||
}
|
||||
|
||||
Transition *over = new Transition("<quit>");
|
||||
over->intros.push_back("movie/gameover.smk");
|
||||
_levels["<game_over>"] = over;
|
||||
|
||||
loadLib("", "wetlands/c_misc/fonts.lib", true);
|
||||
loadFonts();
|
||||
loadLib("wetlands/sound/", "wetlands/c_misc/sound.lib", true);
|
||||
_nextLevel = "<start>";
|
||||
}
|
||||
|
||||
|
||||
void WetEngine::loadAssetsEarlyDemo() {
|
||||
|
||||
Transition *intro;
|
||||
intro = new Transition("c_misc/c31.mis");
|
||||
|
||||
intro->prefix = "c_misc/";
|
||||
intro->intros.push_back("nw_logo.smk");
|
||||
intro->intros.push_back("h.s");
|
||||
intro->intros.push_back("w.s");
|
||||
intro->frameImage = "c.s";
|
||||
intro->frameNumber = 0;
|
||||
_levels["<start>"] = intro;
|
||||
|
||||
loadArcadeLevel("c_misc/c31.mis", "c_misc/c41.mis", "c_misc/c41.mis", "");
|
||||
loadArcadeLevel("c_misc/c41.mis", "c_misc/c61.mis", "c_misc/c61.mis", "");
|
||||
loadArcadeLevel("c_misc/c61.mis", "<quit>", "<quit>", "");
|
||||
|
||||
Transition *over = new Transition("<quit>");
|
||||
over->intros.push_back("g.s");
|
||||
_levels["<game_over>"] = over;
|
||||
|
||||
loadFonts("c_misc/");
|
||||
|
||||
const chapterEntry *entry = rawChapterTableEarlyDemo;
|
||||
while (entry->id) {
|
||||
_chapterTable[entry->id] = entry;
|
||||
entry++;
|
||||
}
|
||||
|
||||
_nextLevel = "<start>";
|
||||
}
|
||||
|
||||
void WetEngine::loadAssetsGen4() {
|
||||
|
||||
bool encrypted = false;
|
||||
LibFile *missions = loadLib("", "c_misc/missions.lib", encrypted);
|
||||
Common::ArchiveMemberList files;
|
||||
if (missions->listMembers(files) == 0)
|
||||
error("%s", failedDetectionError);
|
||||
|
||||
Transition *intro;
|
||||
intro = new Transition("c31.mis");
|
||||
|
||||
intro->intros.push_back("c_misc/nw_logo.smk");
|
||||
intro->intros.push_back("c_misc/h.s");
|
||||
intro->intros.push_back("c_misc/w.s");
|
||||
intro->frameImage = "c_misc/c.s";
|
||||
intro->frameNumber = 0;
|
||||
_levels["<start>"] = intro;
|
||||
|
||||
loadArcadeLevel("c31.mis", "c52.mis", "c52.mis", "");
|
||||
ArcadeShooting *arc;
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c31.mis"];
|
||||
arc->segments[0].size = 1354;
|
||||
arc->objKillsRequired[0] = 2;
|
||||
}
|
||||
loadArcadeLevel("c52.mis", "<game_over>", "<quit>", "");
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c52.mis"];
|
||||
arc->segments[0].size = 2383;
|
||||
arc->objKillsRequired[0] = 2;
|
||||
arc->objKillsRequired[1] = 13;
|
||||
}
|
||||
|
||||
Transition *over = new Transition("<quit>");
|
||||
over->intros.push_back("c_misc/g.s");
|
||||
_levels["<game_over>"] = over;
|
||||
|
||||
loadLib("", "c_misc/fonts.lib", true);
|
||||
loadFonts();
|
||||
loadLib("sound/", "c_misc/sound.lib", true);
|
||||
_nextLevel = "<start>";
|
||||
}
|
||||
|
||||
void WetEngine::loadAssetsNI() {
|
||||
Common::String musicFile = _variant == "NonInteractive" ? "wetmusic.81m" : "c44_22k.raw";
|
||||
int musicRate = _variant == "NonInteractive" ? 11025 : 22050;
|
||||
|
||||
Transition *movies = new Transition("<quit>");
|
||||
movies->music = musicFile;
|
||||
movies->musicRate = musicRate;
|
||||
movies->playMusicDuringIntro = true;
|
||||
movies->intros.push_back("demo/nw_logo.smk");
|
||||
movies->intros.push_back("demo/hypnotix.smk");
|
||||
movies->intros.push_back("demo/wetlogo.smk");
|
||||
movies->intros.push_back("demo/c31c1.smk");
|
||||
movies->intros.push_back("demo/demo31.smk");
|
||||
movies->intros.push_back("demo/c31c2.smk");
|
||||
movies->intros.push_back("demo/c31e1.smk");
|
||||
movies->intros.push_back("demo/logo_w.smk");
|
||||
movies->intros.push_back("demo/bar01b.smk");
|
||||
movies->intros.push_back("demo/gun_320.smk");
|
||||
movies->intros.push_back("demo/logo_e.smk");
|
||||
movies->intros.push_back("demo/c30peek.smk");
|
||||
movies->intros.push_back("demo/demo30.smk");
|
||||
movies->intros.push_back("demo/c30knife.smk");
|
||||
movies->intros.push_back("demo/logo_t.smk");
|
||||
movies->intros.push_back("demo/c51teez.smk");
|
||||
movies->intros.push_back("demo/demo21.smk");
|
||||
movies->intros.push_back("demo/c51kill.smk");
|
||||
movies->intros.push_back("demo/logo_l.smk");
|
||||
movies->intros.push_back("demo/run_320.smk");
|
||||
movies->intros.push_back("demo/logo_a.smk");
|
||||
movies->intros.push_back("demo/demo50.smk");
|
||||
movies->intros.push_back("demo/c50gate.smk");
|
||||
movies->intros.push_back("demo/logo_n.smk");
|
||||
movies->intros.push_back("demo/c22end.smk");
|
||||
movies->intros.push_back("demo/logo_d.smk");
|
||||
movies->intros.push_back("demo/demo44.smk");
|
||||
movies->intros.push_back("demo/c44boom.smk");
|
||||
movies->intros.push_back("demo/logo_s.smk");
|
||||
movies->intros.push_back("demo/xi.smk");
|
||||
movies->intros.push_back("demo/wetlogo.smk");
|
||||
movies->intros.push_back("demo/c30shoot.smk");
|
||||
movies->frameImage = "";
|
||||
movies->frameNumber = 0;
|
||||
_levels["<start>"] = movies;
|
||||
_nextLevel = "<start>";
|
||||
}
|
||||
|
||||
|
||||
void WetEngine::loadAssetsPCW() {
|
||||
|
||||
LibFile *missions = loadLib("", "c_misc/missions.lib", false);
|
||||
Common::ArchiveMemberList files;
|
||||
if (missions->listMembers(files) == 0)
|
||||
error("%s", failedDetectionError);
|
||||
|
||||
Transition *intro = new Transition("c11.mis");
|
||||
intro->intros.push_back("c_misc/nw_logo.smk");
|
||||
intro->intros.push_back("c_misc/h.s");
|
||||
intro->intros.push_back("c_misc/wet.smk");
|
||||
_levels["<start>"] = intro;
|
||||
|
||||
loadArcadeLevel("c11.mis", "<quit>", "<quit>", "");
|
||||
ArcadeShooting *arc;
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c11.mis"];
|
||||
arc->segments[0].size = 2002;
|
||||
arc->objKillsRequired[0] = 1;
|
||||
arc->transitions.push_back(ArcadeTransition("", "c11/c11p2.col", "", 0, 1501));
|
||||
// These videos were not included in the demo, so we replace them
|
||||
arc->defeatMissBossVideo = "c11\\c11d1.smk";
|
||||
arc->defeatNoEnergySecondVideo = "c11\\c11d1.smk";
|
||||
}
|
||||
|
||||
Transition *over = new Transition("<quit>");
|
||||
_levels["<game_over>"] = over;
|
||||
|
||||
loadLib("sound/", "c_misc/sound.lib", false);
|
||||
loadLib("", "c_misc/fonts.lib", true);
|
||||
loadFonts();
|
||||
_nextLevel = "<start>";
|
||||
}
|
||||
|
||||
void WetEngine::loadAssetsPCG() {
|
||||
|
||||
LibFile *missions = loadLib("", "missions.lib", false);
|
||||
Common::ArchiveMemberList files;
|
||||
if (missions->listMembers(files) == 0)
|
||||
error("%s", failedDetectionError);
|
||||
|
||||
Transition *intro = new Transition("c31.mis");
|
||||
intro->intros.push_back("nw_logo.smk");
|
||||
intro->intros.push_back("h.s");
|
||||
intro->intros.push_back("wet.smk");
|
||||
intro->frameImage = "c.s";
|
||||
intro->frameNumber = 0;
|
||||
_levels["<start>"] = intro;
|
||||
|
||||
loadArcadeLevel("c31.mis", "<quit>", "<quit>", "");
|
||||
ArcadeShooting *arc;
|
||||
if (_restoredContentEnabled) {
|
||||
arc = (ArcadeShooting*) _levels["c31.mis"];
|
||||
arc->segments[0].size = 1354;
|
||||
arc->objKillsRequired[0] = 2;
|
||||
// These videos were not included in the demo, so we replace or remove them
|
||||
arc->hitBoss1Video = "";
|
||||
arc->hitBoss2Video = "";
|
||||
arc->missBoss1Video = "";
|
||||
arc->missBoss2Video = "";
|
||||
arc->defeatMissBossVideo = "c31\\c31d1s.smk";
|
||||
}
|
||||
|
||||
Transition *over = new Transition("<quit>");
|
||||
over->intros.push_back("g.s");
|
||||
_levels["<game_over>"] = over;
|
||||
|
||||
loadLib("sound/", "sound.lib", false);
|
||||
loadLib("", "fonts.lib", true);
|
||||
loadFonts();
|
||||
_nextLevel = "<start>";
|
||||
}
|
||||
|
||||
void WetEngine::loadAssetsFullGame() {
|
||||
LibFile *missions = loadLib("", "c_misc/missions.lib", true);
|
||||
Common::ArchiveMemberList files;
|
||||
if (missions == nullptr || missions->listMembers(files) == 0)
|
||||
error("%s", failedDetectionError);
|
||||
|
||||
Transition *logos = new Transition("<main_menu>");
|
||||
logos->intros.push_back("c_misc/logo.smk");
|
||||
logos->intros.push_back("c_misc/nw_logo.smk");
|
||||
logos->intros.push_back("c_misc/hypnotix.smk");
|
||||
logos->intros.push_back("c_misc/wetlogo.smk");
|
||||
_levels["<start>"] = logos;
|
||||
|
||||
Code *menu = new Code("<main_menu>");
|
||||
_levels["<main_menu>"] = menu;
|
||||
_levels["<main_menu>"]->levelIfWin = "<intros>";
|
||||
|
||||
Code *level_menu = new Code("<level_menu>");
|
||||
_levels["<level_menu>"] = level_menu;
|
||||
_levels["<level_menu>"]->levelIfWin = "?";
|
||||
|
||||
Transition *over = new Transition("<main_menu>");
|
||||
over->intros.push_back("c_misc/gameover.smk");
|
||||
_levels["<game_over>"] = over;
|
||||
|
||||
Transition *intros = new Transition("<level_menu>");
|
||||
intros->intros.push_back("c_misc/stardate.smk");
|
||||
intros->intros.push_back("c_misc/intros.smk");
|
||||
intros->intros.push_back("c_misc/confs.smk");
|
||||
_levels["<intros>"] = intros;
|
||||
|
||||
Code *check_lives = new Code("<check_lives>");
|
||||
_levels["<check_lives>"] = check_lives;
|
||||
|
||||
Code *end_credits = new Code("<credits>");
|
||||
_levels["<credits>"] = end_credits;
|
||||
|
||||
ArcadeShooting *arc;
|
||||
loadArcadeLevel("c110.mi_", "c10", "<check_lives>", "");
|
||||
loadArcadeLevel("c111.mi_", "c10", "<check_lives>", "");
|
||||
loadArcadeLevel("c112.mi_", "c10", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c100.mi_", "c21", "<check_lives>", "");
|
||||
loadArcadeLevel("c101.mi_", "c21", "<check_lives>", "");
|
||||
loadArcadeLevel("c102.mi_", "c21", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c210.mi_", "c22", "<check_lives>", "");
|
||||
loadArcadeLevel("c211.mi_", "c22", "<check_lives>", "");
|
||||
loadArcadeLevel("c212.mi_", "c22", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c220.mi_", "c23", "<check_lives>", "");
|
||||
loadArcadeLevel("c221.mi_", "c23", "<check_lives>", "");
|
||||
loadArcadeLevel("c222.mi_", "c23", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c230.mi_", "c20", "<check_lives>", "");
|
||||
loadArcadeLevel("c231.mi_", "c20", "<check_lives>", "");
|
||||
loadArcadeLevel("c232.mi_", "c20", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c200.mi_", "c31", "<check_lives>", "");
|
||||
loadArcadeLevel("c201.mi_", "c31", "<check_lives>", "");
|
||||
loadArcadeLevel("c202.mi_", "c31", "<check_lives>", "");
|
||||
|
||||
arc = (ArcadeShooting*) _levels["c200.mi_"];
|
||||
arc->mouseBox.right = 320;
|
||||
arc->mouseBox.bottom = 135;
|
||||
|
||||
arc = (ArcadeShooting*) _levels["c201.mi_"];
|
||||
arc->mouseBox.right = 320;
|
||||
arc->mouseBox.bottom = 135;
|
||||
|
||||
arc = (ArcadeShooting*) _levels["c202.mi_"];
|
||||
arc->mouseBox.right = 320;
|
||||
arc->mouseBox.bottom = 135;
|
||||
|
||||
loadArcadeLevel("c310.mi_", "c32", "<check_lives>", "");
|
||||
loadArcadeLevel("c311.mi_", "c32", "<check_lives>", "");
|
||||
loadArcadeLevel("c312.mi_", "c32", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c320.mi_", "c33", "<check_lives>", "");
|
||||
loadArcadeLevel("c321.mi_", "c33", "<check_lives>", "");
|
||||
loadArcadeLevel("c322.mi_", "c33", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c330.mi_", "c30", "<check_lives>", "");
|
||||
loadArcadeLevel("c331.mi_", "c30", "<check_lives>", "");
|
||||
loadArcadeLevel("c332.mi_", "c30", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c300.mi_", "c41", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c300.mi_"];
|
||||
arc->id = 30; // Fixed from the original (3)
|
||||
|
||||
loadArcadeLevel("c301.mi_", "c41", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c301.mi_"];
|
||||
arc->id = 30; // Fixed from the original (3)
|
||||
|
||||
loadArcadeLevel("c302.mi_", "c41", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c302.mi_"];
|
||||
arc->id = 30; // Fixed from the original (3)
|
||||
|
||||
loadArcadeLevel("c410.mi_", "c42", "<check_lives>", "");
|
||||
loadArcadeLevel("c411.mi_", "c42", "<check_lives>", "");
|
||||
loadArcadeLevel("c412.mi_", "c42", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c420.mi_", "c43", "<check_lives>", "");
|
||||
loadArcadeLevel("c421.mi_", "c43", "<check_lives>", "");
|
||||
loadArcadeLevel("c422.mi_", "c43", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c430.mi_", "c44", "<check_lives>", "");
|
||||
loadArcadeLevel("c431.mi_", "c44", "<check_lives>", "");
|
||||
loadArcadeLevel("c432.mi_", "c44", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c440.mi_", "c40", "<check_lives>", "");
|
||||
loadArcadeLevel("c441.mi_", "c40", "<check_lives>", "");
|
||||
loadArcadeLevel("c442.mi_", "c40", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c400.mi_", "c51", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c400.mi_"];
|
||||
arc->id = 40; // Fixed from the original (4)
|
||||
|
||||
loadArcadeLevel("c401.mi_", "c51", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c401.mi_"];
|
||||
arc->id = 40; // Fixed from the original (4)
|
||||
|
||||
loadArcadeLevel("c402.mi_", "c51", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c402.mi_"];
|
||||
arc->id = 40; // Fixed from the original (4)
|
||||
|
||||
loadArcadeLevel("c510.mi_", "c52", "<check_lives>", "");
|
||||
loadArcadeLevel("c511.mi_", "c52", "<check_lives>", "");
|
||||
loadArcadeLevel("c512.mi_", "c52", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c520.mi_", "c50", "<check_lives>", "");
|
||||
loadArcadeLevel("c521.mi_", "c50", "<check_lives>", "");
|
||||
loadArcadeLevel("c522.mi_", "c50", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c500.mi_", "c61", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c500.mi_"];
|
||||
arc->id = 50; // Fixed from the original (5)
|
||||
|
||||
loadArcadeLevel("c501.mi_", "c61", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c501.mi_"];
|
||||
arc->id = 50; // Fixed from the original (5)
|
||||
|
||||
loadArcadeLevel("c502.mi_", "c61", "<check_lives>", "");
|
||||
arc = (ArcadeShooting*) _levels["c502.mi_"];
|
||||
arc->id = 50; // Fixed from the original (5)
|
||||
|
||||
loadArcadeLevel("c610.mi_", "c60", "<check_lives>", "");
|
||||
loadArcadeLevel("c611.mi_", "c60", "<check_lives>", "");
|
||||
loadArcadeLevel("c612.mi_", "c60", "<check_lives>", "");
|
||||
|
||||
loadArcadeLevel("c600.mi_", "<credits>", "<check_lives>", "");
|
||||
loadArcadeLevel("c601.mi_", "<credits>", "<check_lives>", "");
|
||||
loadArcadeLevel("c602.mi_", "<credits>", "<check_lives>", "");
|
||||
|
||||
loadLib("", "c_misc/fonts.lib", true);
|
||||
loadFonts();
|
||||
loadLib("sound/", "c_misc/sound.lib", true);
|
||||
restoreScoreMilestones(0);
|
||||
_nextLevel = "<start>";
|
||||
}
|
||||
|
||||
void WetEngine::showCredits() {
|
||||
if (!isDemo() || ((_variant == "Demo" || _variant == "M&MCD") && _language == Common::EN_USA)) {
|
||||
MVideo video("c_misc/credits.smk", Common::Point(0, 0), false, true, false);
|
||||
runIntro(video);
|
||||
}
|
||||
}
|
||||
|
||||
void WetEngine::loadFonts(const Common::String &prefix) {
|
||||
HypnoEngine::loadFonts(prefix);
|
||||
if (_language == Common::KO_KOR) {
|
||||
Common::File file;
|
||||
|
||||
if (!file.open("C_MISC/G9A.SYF"))
|
||||
error("Cannot open Korean font");
|
||||
|
||||
byte *font = (byte *)malloc(file.size());
|
||||
file.read(font, file.size());
|
||||
|
||||
_fontg9a.set_size(file.size()*8);
|
||||
_fontg9a.set_bits((byte *)font);
|
||||
|
||||
free(font);
|
||||
}
|
||||
}
|
||||
|
||||
uint16 WetEngine::getNextChar(const Common::String &str, uint32 &c) {
|
||||
if (c >= str.size())
|
||||
return 0;
|
||||
if (_language == Common::KO_KOR && (str[c] & 0x80) && c + 1 < str.size()) {
|
||||
uint16 r = (str[c] << 8) | (str[c+1] & 0xff);
|
||||
c += 2;
|
||||
return r;
|
||||
}
|
||||
|
||||
return str[c++];
|
||||
}
|
||||
|
||||
void WetEngine::drawGlyph(const Common::BitArray &font, int x, int y, int bitoffset, int width, int height, int pitch, uint32 color, bool invert) {
|
||||
for (int i = 0; i < width; i++) {
|
||||
for (int j = 0; j < height; j++) {
|
||||
if (font.get(bitoffset + j * pitch + i) == invert)
|
||||
_compositeSurface->setPixel(x + (width - i - 1), y + j, color);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WetEngine::drawKoreanChar(uint16 chr, int &curx, int y, uint32 color) {
|
||||
// TODO: What do the first 13 bytes and a byte before ASCII char mean?
|
||||
if (chr < 0x100) {
|
||||
if (chr < 0x20 || chr >= 0x80) {
|
||||
return;
|
||||
}
|
||||
drawGlyph(_fontg9a, curx, y, 104 + 19 * 8 * (chr - 0x20), 9, 9, 16, color, true);
|
||||
curx += 9;
|
||||
return;
|
||||
}
|
||||
|
||||
int initial = (chr >> 10) & 0x1f;
|
||||
int mid = (chr >> 5) & 0x1f;
|
||||
int fin = chr & 0x1f;
|
||||
|
||||
int initidx = initial - 1;
|
||||
static const int mididxlut[0x20] = {
|
||||
-1, -1, 0, 1, 2, 3, 4, 5, -1, -1, 6, 7, 8, 9,
|
||||
10, 11, -1, -1, 12, 13, 14, 15, 16, 17, -1, -1,
|
||||
18, 19, 20, 21, -1, -1};
|
||||
int mididx = mididxlut[mid];
|
||||
int finidx = fin >= 0x12 ? fin - 2 : fin - 1;
|
||||
|
||||
if (initidx < 0 || initidx > 19 || mididx < 0 || mididx > 21 || finidx < 0 || finidx >= 27)
|
||||
return;
|
||||
|
||||
const int mid_to_init_lut[32] = {
|
||||
0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 1, 3, 3,
|
||||
0, 0, 3, 1, 2, 4, 4, 4,
|
||||
0, 0, 2, 1, 3, 0, 0, 0,
|
||||
};
|
||||
const int mid_to_fin_lut[32] = {
|
||||
0, 0, 0, 0, 2, 0, 2, 1,
|
||||
0, 0, 2, 1, 2, 3, 0, 2,
|
||||
0, 0, 1, 3, 3, 1, 2, 1,
|
||||
0, 0, 3, 3, 1, 1, 0, 0,
|
||||
};
|
||||
int initialvariant = 2 * mid_to_init_lut[mid] + (fin == 1 ? 0 : 1);
|
||||
int midvariant = (fin == 1 ? 0 : 1) + (initial == 1 || initial == 2 || initial == 17 ? 0 : 2);
|
||||
int finvariant = mid_to_fin_lut[mid];
|
||||
|
||||
int initialglyph = initidx == 0 ? 0 : initidx * 10 + initialvariant - 9;
|
||||
int midglyph = mididx == 0 ? 0 : 4 * mididx + midvariant - 3;
|
||||
int finglyph = finidx == 0 ? 0 : 4 * finidx + finvariant - 3;
|
||||
|
||||
drawGlyph(_fontg9a, curx, y, 1836 * 8 + 16 * 9 * initialglyph, 9, 9, 16, color, true);
|
||||
drawGlyph(_fontg9a, curx, y, 1836 * 8 + 16 * 9 * 191 + 16 * 9 * midglyph, 9, 9, 16, color, true);
|
||||
drawGlyph(_fontg9a, curx, y, 1836 * 8 + 16 * 9 * 276 + 16 * 9 * finglyph, 9, 9, 16, color, true);
|
||||
curx += 9;
|
||||
}
|
||||
|
||||
void WetEngine::drawString(const Common::String &font, const Common::String &str, int x, int y, int w, uint32 color) {
|
||||
int offset = 0;
|
||||
int curx = x;
|
||||
if (font == "g9a.syf" && _language == Common::KO_KOR) {
|
||||
for (uint32 c = 0; c < str.size(); ) {
|
||||
uint16 chr = getNextChar(str, c);
|
||||
drawKoreanChar(chr, curx, y, color);
|
||||
}
|
||||
} else if (font == "block05.fgx") {
|
||||
for (uint32 c = 0; c < str.size(); ) {
|
||||
uint16 chr = getNextChar(str, c);
|
||||
|
||||
if (chr >= 0x100 && _language == Common::KO_KOR) {
|
||||
drawKoreanChar(chr, curx, y, color);
|
||||
continue;
|
||||
}
|
||||
|
||||
offset = 0;
|
||||
if (chr == ':')
|
||||
offset = 1;
|
||||
else if (chr == '.')
|
||||
offset = 4;
|
||||
|
||||
drawGlyph(_font05, curx + 1, offset + y, 275 + 40*chr, 5, 5, 8, color, _variant == "EarlyDemo");
|
||||
curx += 6;
|
||||
}
|
||||
} else if (font == "scifi08.fgx") {
|
||||
for (uint32 c = 0; c < str.size();) {
|
||||
uint16 chr = getNextChar(str, c);
|
||||
if (chr >= 0x100 && _language == Common::KO_KOR) {
|
||||
drawKoreanChar(chr, curx, y, color);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chr == 0)
|
||||
continue;
|
||||
assert(chr >= 32);
|
||||
offset = 0;
|
||||
if (chr == 't')
|
||||
offset = 0;
|
||||
else if (chr == 'i' || chr == '%')
|
||||
offset = 1;
|
||||
else if (Common::isLower(chr) || chr == ':')
|
||||
offset = 2;
|
||||
|
||||
drawGlyph(_font08, curx + 1, offset + y, 1554 + 72*(chr-32), 6, 8, 8, color, _variant == "EarlyDemo");
|
||||
curx += 7;
|
||||
}
|
||||
} else
|
||||
error("Invalid font: '%s'", font.c_str());
|
||||
}
|
||||
|
||||
void WetEngine::saveProfile(const Common::String &name, int levelId) {
|
||||
SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
|
||||
|
||||
// Find the correct level index to before saving
|
||||
for (uint32 i = 0; i < _ids.size(); i++) {
|
||||
if (levelId == _ids[i]) {
|
||||
if (_lastLevel < int(i))
|
||||
_lastLevel = int(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
uint32 slot = 0;
|
||||
for (SaveStateList::iterator save = saves.begin(); save != saves.end(); ++save) {
|
||||
if (save->getDescription() == name)
|
||||
break;
|
||||
slot++;
|
||||
}
|
||||
|
||||
saveGameState(slot, name, false);
|
||||
}
|
||||
|
||||
bool WetEngine::loadProfile(const Common::String &name) {
|
||||
SaveStateList saves = getMetaEngine()->listSaves(_targetName.c_str());
|
||||
uint32 slot = 0;
|
||||
for (SaveStateList::iterator save = saves.begin(); save != saves.end(); ++save) {
|
||||
if (save->getDescription() == name)
|
||||
break;
|
||||
slot++;
|
||||
}
|
||||
|
||||
if (slot == saves.size()) {
|
||||
debugC(1, kHypnoDebugMedia, "Failed to load %s", name.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
loadGameState(slot);
|
||||
return true;
|
||||
}
|
||||
|
||||
Common::Error WetEngine::saveGameStream(Common::WriteStream *stream, bool isAutosave) {
|
||||
if (isAutosave)
|
||||
return Common::kNoError;
|
||||
|
||||
if (_lastLevel < 0 || _lastLevel >= 20)
|
||||
error("Invalid last level!");
|
||||
|
||||
stream->writeString(_name);
|
||||
stream->writeByte(0);
|
||||
|
||||
stream->writeString(_difficulty);
|
||||
stream->writeByte(0);
|
||||
|
||||
stream->writeUint32LE(_lives);
|
||||
stream->writeUint32LE(_score);
|
||||
|
||||
stream->writeUint32LE(_lastLevel);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::Error WetEngine::loadGameStream(Common::SeekableReadStream *stream) {
|
||||
_name = stream->readString();
|
||||
_difficulty = stream->readString();
|
||||
_lives = stream->readUint32LE();
|
||||
_score = stream->readUint32LE();
|
||||
_lastLevel = stream->readUint32LE();
|
||||
|
||||
if (_lastLevel == 0)
|
||||
_nextLevel = Common::String::format("c%d", _ids[0]);
|
||||
else
|
||||
_nextLevel = "<level_menu>";
|
||||
|
||||
restoreScoreMilestones(_score);
|
||||
return Common::kNoError;
|
||||
}
|
||||
|
||||
Common::String WetEngine::findNextLevel(const Transition *trans) {
|
||||
if (trans->nextLevel.empty())
|
||||
error("Invalid transition!");
|
||||
return trans->nextLevel;
|
||||
}
|
||||
|
||||
Common::String WetEngine::findNextLevel(const Common::String &level) {
|
||||
Common::String nextLevel;
|
||||
if (Common::matchString(level.c_str(), "c#") || Common::matchString(level.c_str(), "c##"))
|
||||
nextLevel = level + _difficulty + ".mi_";
|
||||
else {
|
||||
nextLevel = level;
|
||||
}
|
||||
|
||||
return nextLevel;
|
||||
}
|
||||
|
||||
} // End of namespace Hypno
|
||||
Reference in New Issue
Block a user