HUGO: Adding engine to the main tree
svn-id: r52137
This commit is contained in:
parent
e075f05395
commit
06960d33e1
46 changed files with 24896 additions and 1 deletions
|
@ -233,6 +233,9 @@ DIST_FILES_ENGINEDATA=
|
||||||
ifdef ENABLE_DRASCULA
|
ifdef ENABLE_DRASCULA
|
||||||
DIST_FILES_ENGINEDATA+=drascula.dat
|
DIST_FILES_ENGINEDATA+=drascula.dat
|
||||||
endif
|
endif
|
||||||
|
ifdef ENABLE_HUGO
|
||||||
|
DIST_FILES_ENGINEDATA+=hugo.dat
|
||||||
|
endif
|
||||||
ifdef ENABLE_KYRA
|
ifdef ENABLE_KYRA
|
||||||
DIST_FILES_ENGINEDATA+=kyra.dat
|
DIST_FILES_ENGINEDATA+=kyra.dat
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -115,6 +115,9 @@ public:
|
||||||
#if PLUGIN_ENABLED_STATIC(GROOVIE)
|
#if PLUGIN_ENABLED_STATIC(GROOVIE)
|
||||||
LINK_PLUGIN(GROOVIE)
|
LINK_PLUGIN(GROOVIE)
|
||||||
#endif
|
#endif
|
||||||
|
#if PLUGIN_ENABLED_STATIC(HUGO)
|
||||||
|
LINK_PLUGIN(HUGO)
|
||||||
|
#endif
|
||||||
#if PLUGIN_ENABLED_STATIC(KYRA)
|
#if PLUGIN_ENABLED_STATIC(KYRA)
|
||||||
LINK_PLUGIN(KYRA)
|
LINK_PLUGIN(KYRA)
|
||||||
#endif
|
#endif
|
||||||
|
|
1
configure
vendored
1
configure
vendored
|
@ -88,6 +88,7 @@ add_engine drascula "Drascula: The Vampire Strikes Back" yes
|
||||||
add_engine gob "Gobli*ns" yes
|
add_engine gob "Gobli*ns" yes
|
||||||
add_engine groovie "Groovie" yes "groovie2"
|
add_engine groovie "Groovie" yes "groovie2"
|
||||||
add_engine groovie2 "Groovie 2 games" no
|
add_engine groovie2 "Groovie 2 games" no
|
||||||
|
add_engine hugo "Hugo Trilogy" no
|
||||||
add_engine kyra "Legend of Kyrandia" yes "lol"
|
add_engine kyra "Legend of Kyrandia" yes "lol"
|
||||||
add_engine lol "Lands of Lore" no
|
add_engine lol "Lands of Lore" no
|
||||||
add_engine lure "Lure of the Temptress" yes
|
add_engine lure "Lure of the Temptress" yes
|
||||||
|
|
BIN
dists/engine-data/hugo.dat
Executable file
BIN
dists/engine-data/hugo.dat
Executable file
Binary file not shown.
|
@ -60,6 +60,11 @@ DEFINES += -DENABLE_GROOVIE2
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifdef ENABLE_HUGO
|
||||||
|
DEFINES += -DENABLE_HUGO=$(ENABLE_HUGO)
|
||||||
|
MODULES += engines/hugo
|
||||||
|
endif
|
||||||
|
|
||||||
ifdef ENABLE_KYRA
|
ifdef ENABLE_KYRA
|
||||||
DEFINES += -DENABLE_KYRA=$(ENABLE_KYRA)
|
DEFINES += -DENABLE_KYRA=$(ENABLE_KYRA)
|
||||||
MODULES += engines/kyra
|
MODULES += engines/kyra
|
||||||
|
|
234
engines/hugo/detection.cpp
Executable file
234
engines/hugo/detection.cpp
Executable file
|
@ -0,0 +1,234 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "engines/advancedDetector.h"
|
||||||
|
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/intro.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
struct HugoGameDescription {
|
||||||
|
ADGameDescription desc;
|
||||||
|
GameType gameType;
|
||||||
|
};
|
||||||
|
|
||||||
|
uint32 HugoEngine::getFeatures() const {
|
||||||
|
return _gameDescription->desc.flags;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const PlainGameDescriptor hugoGames[] = {
|
||||||
|
// Games
|
||||||
|
{"hugo1", "Hugo 1: Hugo's House of Horrors"},
|
||||||
|
{"hugo2", "Hugo 2: Hugo's Mystery Adventure"},
|
||||||
|
{"hugo3", "Hugo 3: Hugo's Amazon Adventure"},
|
||||||
|
|
||||||
|
{0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const HugoGameDescription gameDescriptions[] = {
|
||||||
|
|
||||||
|
// Hugo1 DOS
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"hugo1", 0,
|
||||||
|
AD_ENTRY1s("house.art", "c9403b2fe539185c9fd569b6cc4ff5ca", 14811),
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformPC,
|
||||||
|
ADGF_NO_FLAGS,
|
||||||
|
Common::GUIO_NONE
|
||||||
|
},
|
||||||
|
kGameTypeHugo1
|
||||||
|
},
|
||||||
|
// Hugo1 Windows
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"hugo1", 0,
|
||||||
|
AD_ENTRY1s("objects.dat", "3ba0f108f7690a05a34c56a02fbe644a", 126488),
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
GF_PACKED,
|
||||||
|
Common::GUIO_NONE
|
||||||
|
},
|
||||||
|
kGameTypeHugo1
|
||||||
|
},
|
||||||
|
// Hugo2 DOS
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"hugo2", 0,
|
||||||
|
AD_ENTRY1s("objects.dat", "88a718cc0ff2b3b25d49aaaa69d6d52c", 155240),
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformPC,
|
||||||
|
GF_PACKED,
|
||||||
|
Common::GUIO_NONE
|
||||||
|
},
|
||||||
|
kGameTypeHugo2
|
||||||
|
},
|
||||||
|
// Hugo2 Windows
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"hugo2", 0,
|
||||||
|
AD_ENTRY1s("objects.dat", "5df4ffc851e66a544c0e95e4e084a806", 158480),
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
GF_PACKED,
|
||||||
|
Common::GUIO_NONE
|
||||||
|
},
|
||||||
|
kGameTypeHugo2
|
||||||
|
},
|
||||||
|
// Hugo3 DOS
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"hugo3", 0,
|
||||||
|
AD_ENTRY1s("objects.dat", "bb1b061538a445f2eb99b682c0f506cc", 136419),
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformPC,
|
||||||
|
GF_PACKED,
|
||||||
|
Common::GUIO_NONE
|
||||||
|
},
|
||||||
|
kGameTypeHugo3
|
||||||
|
},
|
||||||
|
// Hugo3 Windows
|
||||||
|
{
|
||||||
|
{
|
||||||
|
"hugo3", 0,
|
||||||
|
AD_ENTRY1s("objects.dat", "c9a8af7aa14cc907434eecee3ddd06d3", 136638),
|
||||||
|
Common::EN_ANY,
|
||||||
|
Common::kPlatformWindows,
|
||||||
|
GF_PACKED,
|
||||||
|
Common::GUIO_NONE
|
||||||
|
},
|
||||||
|
kGameTypeHugo3
|
||||||
|
},
|
||||||
|
|
||||||
|
{AD_TABLE_END_MARKER, kGameTypeNone}
|
||||||
|
};
|
||||||
|
|
||||||
|
static const ADParams detectionParams = {
|
||||||
|
// Pointer to ADGameDescription or its superset structure
|
||||||
|
(const byte *)gameDescriptions,
|
||||||
|
// Size of that superset structure
|
||||||
|
sizeof(HugoGameDescription),
|
||||||
|
// Number of bytes to compute MD5 sum for
|
||||||
|
5000,
|
||||||
|
// List of all engine targets
|
||||||
|
hugoGames,
|
||||||
|
// Structure for autoupgrading obsolete targets
|
||||||
|
0,
|
||||||
|
// Name of single gameid (optional)
|
||||||
|
0,
|
||||||
|
// List of files for file-based fallback detection (optional)
|
||||||
|
0,
|
||||||
|
// Flags
|
||||||
|
0,
|
||||||
|
// Additional GUI options (for every game}
|
||||||
|
Common::GUIO_NONE,
|
||||||
|
// Maximum directory depth
|
||||||
|
1,
|
||||||
|
// List of directory globs
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
class HugoMetaEngine : public AdvancedMetaEngine {
|
||||||
|
public:
|
||||||
|
HugoMetaEngine() : AdvancedMetaEngine(detectionParams) {}
|
||||||
|
|
||||||
|
const char *getName() const {
|
||||||
|
return "Hugo Engine";
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *getOriginalCopyright() const {
|
||||||
|
return "Hugo Engine (C) 1989-1997 David P. Gray";
|
||||||
|
}
|
||||||
|
|
||||||
|
bool createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const;
|
||||||
|
|
||||||
|
bool hasFeature(MetaEngineFeature f) const;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool HugoMetaEngine::createInstance(OSystem *syst, Engine **engine, const ADGameDescription *gd) const {
|
||||||
|
if (gd) {
|
||||||
|
*engine = new HugoEngine(syst, (const HugoGameDescription *)gd);
|
||||||
|
((HugoEngine *)*engine)->initGame((const HugoGameDescription *)gd);
|
||||||
|
((HugoEngine *)*engine)->initGamePart((const HugoGameDescription *)gd);
|
||||||
|
}
|
||||||
|
return gd != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool HugoMetaEngine::hasFeature(MetaEngineFeature f) const {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Hugo
|
||||||
|
|
||||||
|
#if PLUGIN_ENABLED_DYNAMIC(HUGO)
|
||||||
|
REGISTER_PLUGIN_DYNAMIC(HUGO, PLUGIN_TYPE_ENGINE, Hugo::HugoMetaEngine);
|
||||||
|
#else
|
||||||
|
REGISTER_PLUGIN_STATIC(HUGO, PLUGIN_TYPE_ENGINE, Hugo::HugoMetaEngine);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
void HugoEngine::initGame(const HugoGameDescription *gd) {
|
||||||
|
_gameType = gd->gameType;
|
||||||
|
_platform = gd->desc.platform;
|
||||||
|
_packedFl = (getFeatures() & GF_PACKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
void HugoEngine::initGamePart(const HugoGameDescription *gd) {
|
||||||
|
char tmpStr[8];
|
||||||
|
_gameVariant = _gameType - 1 + (_platform == Common::kPlatformWindows ? 0 : 3);
|
||||||
|
|
||||||
|
//Generate filenames
|
||||||
|
if (gd->desc.platform == Common::kPlatformWindows)
|
||||||
|
sprintf(tmpStr, "%s%c", gd->desc.gameid, 'w');
|
||||||
|
else
|
||||||
|
sprintf(tmpStr, "%s%c", gd->desc.gameid, 'd');
|
||||||
|
|
||||||
|
sprintf(_initFilename, "%s-00.SAV", tmpStr);
|
||||||
|
sprintf(_saveFilename, "%s-%s.SAV", tmpStr, "%d");
|
||||||
|
|
||||||
|
switch (_gameVariant) {
|
||||||
|
case 0:
|
||||||
|
_introHandler = new intro_1w(*this);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
_introHandler = new intro_2w(*this);
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
_introHandler = new intro_3w(*this);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
_introHandler = new intro_1d(*this);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
_introHandler = new intro_2d(*this);
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
_introHandler = new intro_3d(*this);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // End of namespace Gob
|
509
engines/hugo/display.cpp
Executable file
509
engines/hugo/display.cpp
Executable file
|
@ -0,0 +1,509 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Display.c - DIB related code for HUGOWIN
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define CENTER -1 // Used to center text in x
|
||||||
|
#define NUM_COLORS 16 // Num colors to save in palette
|
||||||
|
#define DMAX 16 // Size of add/restore rect lists
|
||||||
|
#define BMAX (DMAX * 2) // Size of dirty rect blit list
|
||||||
|
|
||||||
|
#define INX(X, B) (X >= B->x && X <= B->x + B->dx)
|
||||||
|
#define INY(Y, B) (Y >= B->y && Y <= B->y + B->dy)
|
||||||
|
#define OVERLAP(A, B) ((INX(A->x, B) || INX(A->x + A->dx, B) || INX(B->x, A) || INX(B->x + B->dx, A)) && (INY(A->y, B) || INY(A->y + A->dy, B) || INY(B->y, A) || INY(B->y + B->dy, A)))
|
||||||
|
|
||||||
|
struct rect_t { // Rectangle used in Display list
|
||||||
|
int16 x; // Position in dib
|
||||||
|
int16 y; // Position in dib
|
||||||
|
int16 dx; // width
|
||||||
|
int16 dy; // height
|
||||||
|
};
|
||||||
|
|
||||||
|
Screen::Screen(HugoEngine &vm) : _vm(vm) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::createPal() {
|
||||||
|
debugC(1, kDebugDisplay, "createPal");
|
||||||
|
|
||||||
|
g_system->setPalette(_vm._palette, 0, NUM_COLORS);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Translate from our 16-color palette to Windows logical palette index
|
||||||
|
uint32 Screen::GetPalIndex(byte color) {
|
||||||
|
debugC(1, kDebugDisplay, "getPalIndex(%d)", color);
|
||||||
|
|
||||||
|
warning("STUB: GetPalIndex()");
|
||||||
|
return 0;
|
||||||
|
//return(PALETTEINDEX(ctab[color]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create DIB headers and init palette
|
||||||
|
void Screen::initDisplay() {
|
||||||
|
debugC(1, kDebugDisplay, "initDisplay");
|
||||||
|
// Create logical palette
|
||||||
|
createPal();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move an image from source to destination
|
||||||
|
void Screen::moveImage(image_pt srcImage, uint16 x1, uint16 y1, uint16 dx, uint16 dy, uint16 width1, image_pt dstImage, uint16 x2, uint16 y2, uint16 width2) {
|
||||||
|
int16 wrap_src = width1 - dx; // Wrap to next src row
|
||||||
|
int16 wrap_dst = width2 - dx; // Wrap to next dst row
|
||||||
|
int16 x;
|
||||||
|
|
||||||
|
debugC(3, kDebugDisplay, "moveImage(srcImage, %d, %d, %d, %d, %d, dstImage, %d, %d, %d)", x1, y1, dx, dy, width1, x2, y2, width2);
|
||||||
|
|
||||||
|
srcImage += y1 * width1 + x1; // Offset into src image
|
||||||
|
dstImage += y2 * width2 + x2; // offset into dst image
|
||||||
|
|
||||||
|
while (dy--) { // For each row
|
||||||
|
for (x = dx; x--;) // For each column
|
||||||
|
*dstImage++ = *srcImage++;
|
||||||
|
srcImage += wrap_src; // Wrap to next line
|
||||||
|
dstImage += wrap_dst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::displayBackground() {
|
||||||
|
debugC(1, kDebugDisplay, "displayBackground");
|
||||||
|
|
||||||
|
g_system->copyRectToScreen(_frontBuffer, 320, 0, 0, 320, 200);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Blit the supplied rectangle from _frontBuffer to the screen
|
||||||
|
void Screen::displayRect(int16 x, int16 y, int16 dx, int16 dy) {
|
||||||
|
|
||||||
|
/* TODO: Suppress this commented block if it's confirmed to be useless
|
||||||
|
// Find destination rectangle from current scaling
|
||||||
|
int16 sx = (int16)((int32)config.cx * x / XPIX);
|
||||||
|
int16 sy = (int16)((int32)config.cy * (y - DIBOFF_Y) / VIEW_DY);
|
||||||
|
int16 dsx = (int16)((int32)config.cx * dx / XPIX);
|
||||||
|
int16 dsy = (int16)((int32)config.cy * dy / VIEW_DY);
|
||||||
|
*/
|
||||||
|
debugC(3, kDebugDisplay, "displayRect(%d, %d, %d, %d)", x, y, dx, dy);
|
||||||
|
|
||||||
|
g_system->copyRectToScreen(&_frontBuffer[x + y * 320], 320, x, y, dx, dy);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::remapPal(uint16 oldIndex, uint16 newIndex) {
|
||||||
|
// Change a color by remapping supplied palette index with new index
|
||||||
|
debugC(1, kDebugDisplay, "Remap_pal(%d, %d)", oldIndex, newIndex);
|
||||||
|
|
||||||
|
warning("STUB: Remap_pal()");
|
||||||
|
//bminfo.bmiColors[oldIndex] = ctab[newIndex];
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::savePal(Common::WriteStream *f) {
|
||||||
|
debugC(1, kDebugDisplay, "savePal");
|
||||||
|
|
||||||
|
warning("STUB: savePal()");
|
||||||
|
//fwrite(bminfo.bmiColors, sizeof(bminfo.bmiColors), 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::restorePal(Common::SeekableReadStream *f) {
|
||||||
|
debugC(1, kDebugDisplay, "restorePal");
|
||||||
|
|
||||||
|
warning("STUB: restorePal()");
|
||||||
|
//fread(bminfo.bmiColors, sizeof(bminfo.bmiColors), 1, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Set the new background color
|
||||||
|
void Screen::setBackgroundColor(long color) {
|
||||||
|
debugC(1, kDebugDisplay, "setBackgroundColor(%ld)", color);
|
||||||
|
|
||||||
|
// How??? Translate existing pixels in dib before objects rendered?
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the supplied character in the supplied color to x,y pixel coords
|
||||||
|
void Screen::writeChar(int16 x, int16 y, char c, byte color) {
|
||||||
|
debugC(1, kDebugDisplay, "writeChar(%d, %d, %c, %d)", x, y, c, color);
|
||||||
|
|
||||||
|
warning("STUB: writeChar()");
|
||||||
|
// x = (int16)((long) x * config.cx / XPIX);
|
||||||
|
// y = (int16)((long) y * config.cy / YPIX);
|
||||||
|
// SetTextColor(hDC, GetPalIndex(color));
|
||||||
|
// TextOut(hDC, x, y, &c, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear prompt line for next command
|
||||||
|
void Screen::clearPromptLine() {
|
||||||
|
debugC(1, kDebugDisplay, "clearPromptLine");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Return the overlay state (Foreground/Background) of the currently
|
||||||
|
// processed object by looking down the current column for an overlay
|
||||||
|
// base bit set (in which case the object is foreground).
|
||||||
|
overlayState_t Screen::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) {
|
||||||
|
debugC(4, kDebugDisplay, "findOvl");
|
||||||
|
|
||||||
|
for (; y < seq_p->lines; y++) { // Each line in object
|
||||||
|
image_pt ovb_p = _vm.getBaseBoundaryOverlay() + ((uint16)(dst_p - _frontBuffer) >> 3); // Ptr into overlay bits
|
||||||
|
if (*ovb_p & (0x80 >> ((uint16)(dst_p - _frontBuffer) & 7))) // Overlay bit is set
|
||||||
|
return FG; // Found a bit - must be foreground
|
||||||
|
dst_p += XPIX;
|
||||||
|
}
|
||||||
|
|
||||||
|
return BG; // No bits set, must be background
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge an object frame into _frontBuffer at sx, sy and update rectangle list.
|
||||||
|
// If fore TRUE, force object above any overlay
|
||||||
|
void Screen::displayFrame(int sx, int sy, seq_t *seq, bool foreFl) {
|
||||||
|
overlayState_t overlayState = UNDEF; // Overlay state of object
|
||||||
|
image_pt image; // Ptr to object image data
|
||||||
|
image_pt subFrontBuffer; // Ptr to offset in _frontBuffer
|
||||||
|
image_pt overlay; // Ptr to overlay data
|
||||||
|
int16 frontBufferwrap; // Wrap dst_p to next line
|
||||||
|
int16 imageWrap; // Wrap src_p to next line
|
||||||
|
uint16 x, y; // Index into object data
|
||||||
|
|
||||||
|
debugC(3, kDebugDisplay, "displayFrame(%d, %d, seq, %d)", sx, sy, (foreFl) ? 1 : 0);
|
||||||
|
|
||||||
|
image = seq->imagePtr; // Source ptr
|
||||||
|
subFrontBuffer = &_frontBuffer[sy * XPIX + sx]; // Destination ptr
|
||||||
|
overlay = &_vm.getFirstOverlay()[(sy * XPIX + sx) >> 3]; // Overlay ptr
|
||||||
|
frontBufferwrap = XPIX - seq->x2 - 1; // Wraps dest_p after each line
|
||||||
|
imageWrap = seq->bytesPerLine8 - seq->x2 - 1;
|
||||||
|
|
||||||
|
for (y = 0; y < seq->lines; y++) { // Each line in object
|
||||||
|
for (x = 0; x <= seq->x2; x++) {
|
||||||
|
if (*image) { // Non-transparent
|
||||||
|
overlay = _vm.getFirstOverlay() + ((uint16)(subFrontBuffer - _frontBuffer) >> 3); // Ptr into overlay bits
|
||||||
|
if (*overlay & (0x80 >> ((uint16)(subFrontBuffer - _frontBuffer) & 7))) { // Overlay bit is set
|
||||||
|
if (overlayState == UNDEF) // Overlay defined yet?
|
||||||
|
overlayState = findOvl(seq, subFrontBuffer, y);// No, find it.
|
||||||
|
if (foreFl || overlayState == FG) // Object foreground
|
||||||
|
*subFrontBuffer = *image; // Copy pixel
|
||||||
|
} else // No overlay
|
||||||
|
*subFrontBuffer = *image; // Copy pixel
|
||||||
|
}
|
||||||
|
image++;
|
||||||
|
subFrontBuffer++;
|
||||||
|
}
|
||||||
|
image += imageWrap;
|
||||||
|
subFrontBuffer += frontBufferwrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add this rectangle to the display list
|
||||||
|
displayList(D_ADD, sx, sy, seq->x2 + 1, seq->lines);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge rectangles A,B leaving result in B
|
||||||
|
void Screen::merge(rect_t *rectA, rect_t *rectB) {
|
||||||
|
debugC(6, kDebugDisplay, "merge");
|
||||||
|
|
||||||
|
int16 xa = rectA->x + rectA->dx; // Find x2,y2 for each rectangle
|
||||||
|
int16 xb = rectB->x + rectB->dx;
|
||||||
|
int16 ya = rectA->y + rectA->dy;
|
||||||
|
int16 yb = rectB->y + rectB->dy;
|
||||||
|
|
||||||
|
rectB->x = MIN(rectA->x, rectB->x); // Minimum x,y
|
||||||
|
rectB->y = MIN(rectA->y, rectB->y);
|
||||||
|
rectB->dx = MAX(xa, xb) - rectB->x; // Maximum dx,dy
|
||||||
|
rectB->dy = MAX(ya, yb) - rectB->y;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coalesce the rectangles in the restore/add list into one unified
|
||||||
|
// blist. len is the sizes of alist or rlist. blen is current length
|
||||||
|
// of blist. bmax is the max size of the blist. Note that blist can
|
||||||
|
// have holes, in which case dx = 0. Returns used length of blist.
|
||||||
|
int16 Screen::mergeLists(rect_t *list, rect_t *blist, int16 len, int16 blen, int16 bmax) {
|
||||||
|
int16 coalesce[BMAX]; // List of overlapping rects
|
||||||
|
|
||||||
|
debugC(4, kDebugDisplay, "mergeLists");
|
||||||
|
|
||||||
|
// Process the list
|
||||||
|
for (int16 a = 0; a < len; a++, list++) {
|
||||||
|
// Compile list of overlapping rectangles in blit list
|
||||||
|
int16 c = 0;
|
||||||
|
rect_t *bp = blist;
|
||||||
|
for (int16 b = 0; b < blen; b++, bp++)
|
||||||
|
if (bp->dx) // blist entry used
|
||||||
|
if (OVERLAP(list, bp))
|
||||||
|
coalesce[c++] = b;
|
||||||
|
|
||||||
|
// Any overlapping blit rects?
|
||||||
|
if (c == 0) // None, add a new entry
|
||||||
|
blist[blen++] = *list;
|
||||||
|
else { // At least one overlapping
|
||||||
|
// Merge add-list entry with first blist entry
|
||||||
|
bp = &blist[coalesce[0]];
|
||||||
|
merge(list, bp);
|
||||||
|
|
||||||
|
// Merge any more blist entries
|
||||||
|
while (--c) {
|
||||||
|
rect_t *cp = &blist[coalesce[c]];
|
||||||
|
merge(cp, bp);
|
||||||
|
cp->dx = 0; // Delete entry
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return blen;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process the display list
|
||||||
|
// Trailing args are int16 x,y,dx,dy for the D_ADD operation
|
||||||
|
void Screen::displayList(dupdate_t update, ...) {
|
||||||
|
static int16 addIndex, restoreIndex; // Index into add/restore lists
|
||||||
|
static rect_t restoreList[DMAX]; // The restore list
|
||||||
|
static rect_t addList[DMAX]; // The add list
|
||||||
|
static rect_t blistList[BMAX]; // The blit list
|
||||||
|
int16 blitLength = 0; // Length of blit list
|
||||||
|
rect_t *p; // Ptr to dlist entry
|
||||||
|
va_list marker; // Args used for D_ADD operation
|
||||||
|
|
||||||
|
debugC(6, kDebugDisplay, "displayList");
|
||||||
|
|
||||||
|
switch (update) {
|
||||||
|
case D_INIT: // Init lists, restore whole screen
|
||||||
|
addIndex = restoreIndex = 0;
|
||||||
|
memcpy(_frontBuffer, _backBuffer, sizeof(_frontBuffer));
|
||||||
|
break;
|
||||||
|
case D_ADD: // Add a rectangle to list
|
||||||
|
if (addIndex >= DMAX) {
|
||||||
|
Utils::Warn(false, "Display list exceeded");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
va_start(marker, update); // Initialize variable arguments
|
||||||
|
p = &addList[addIndex];
|
||||||
|
p->x = va_arg(marker, int); // x
|
||||||
|
p->y = va_arg(marker, int); // y
|
||||||
|
p->dx = va_arg(marker, int); // dx
|
||||||
|
p->dy = va_arg(marker, int); // dy
|
||||||
|
va_end(marker); // Reset variable arguments
|
||||||
|
addIndex++;
|
||||||
|
break;
|
||||||
|
case D_DISPLAY: // Display whole list
|
||||||
|
// Don't blit if newscreen just loaded because _frontBuffer will
|
||||||
|
// get blitted via InvalidateRect() at end of this cycle
|
||||||
|
// and blitting here causes objects to appear too soon.
|
||||||
|
if (_vm.getGameStatus().newScreenFl) {
|
||||||
|
_vm.getGameStatus().newScreenFl = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Coalesce restore-list, add-list into combined blit-list
|
||||||
|
blitLength = mergeLists(restoreList, blistList, restoreIndex, blitLength, BMAX);
|
||||||
|
blitLength = mergeLists(addList, blistList, addIndex, blitLength, BMAX);
|
||||||
|
|
||||||
|
// Blit the combined blit-list
|
||||||
|
for (restoreIndex = 0, p = blistList; restoreIndex < blitLength; restoreIndex++, p++)
|
||||||
|
if (p->dx) // Marks a used entry
|
||||||
|
displayRect(p->x, p->y, p->dx, p->dy);
|
||||||
|
break;
|
||||||
|
case D_RESTORE: // Restore each rectangle
|
||||||
|
for (restoreIndex = 0, p = addList; restoreIndex < addIndex; restoreIndex++, p++) {
|
||||||
|
// Restoring from _backBuffer to _frontBuffer
|
||||||
|
restoreList[restoreIndex] = *p; // Copy add-list to restore-list
|
||||||
|
moveImage(_backBuffer, p->x, p->y, p->dx, p->dy, XPIX, _frontBuffer, p->x, p->y, XPIX);
|
||||||
|
}
|
||||||
|
addIndex = 0; // Reset add-list
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::writeChr(int sx, int sy, byte color, char *local_fontdata) {
|
||||||
|
/*
|
||||||
|
Write supplied character (font data) at sx,sy in supplied color
|
||||||
|
Font data as follows:
|
||||||
|
|
||||||
|
*(fontdata+1) = Font Height (pixels)
|
||||||
|
*(fontdata+1) = Font Width (pixels)
|
||||||
|
*(fontdata+x) = Font Bitmap (monochrome)
|
||||||
|
*/
|
||||||
|
|
||||||
|
debugC(2, kDebugDisplay, "writeChr(%d, %d, %d, %d)", sx, sy, color, local_fontdata[0]);
|
||||||
|
|
||||||
|
byte height = local_fontdata[0];
|
||||||
|
byte width = 8; //local_fontdata[1];
|
||||||
|
|
||||||
|
//warning("STUB: writechr(sx %u, sy %u, color %u, height %u, width %u)", sx, sy, color, height, width);
|
||||||
|
|
||||||
|
// This can probably be optimized quite a bit...
|
||||||
|
for (int y = 0; y < height; ++y)
|
||||||
|
for (int x = 0; x < width; ++x) {
|
||||||
|
int pixel = y * width + x;
|
||||||
|
int bitpos = pixel % 8;
|
||||||
|
int offset = pixel / 8;
|
||||||
|
byte bitTest = (1 << bitpos);
|
||||||
|
if ((local_fontdata[2 + offset] & bitTest) == bitTest)
|
||||||
|
_frontBuffer[(sy + y) * 320 + sx + x] = color;
|
||||||
|
//printf("offset: %u, bitpos %u\n", offset, bitpos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns height of characters in current font
|
||||||
|
int16 Screen::fontHeight() {
|
||||||
|
debugC(2, kDebugDisplay, "fontHeight");
|
||||||
|
|
||||||
|
static int16 height[NUM_FONTS] = {5, 7, 8};
|
||||||
|
return(height[_fnt - FIRST_FONT]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* TODO: Suppress block if it's confirmed to be useless */
|
||||||
|
// static int16 Char_len (char c) {
|
||||||
|
// /* Returns length of single character in pixels */
|
||||||
|
// return (*(_font[_fnt][c] + 1) + 1);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
// Returns length of supplied string in pixels
|
||||||
|
int16 Screen::stringLength(char *s) {
|
||||||
|
int16 sum;
|
||||||
|
byte **fontArr = _font[_fnt];
|
||||||
|
|
||||||
|
debugC(2, kDebugDisplay, "stringLength(%s)", s);
|
||||||
|
|
||||||
|
for (sum = 0; *s; s++)
|
||||||
|
sum += *(fontArr[*s] + 1) + 1;
|
||||||
|
|
||||||
|
return(sum);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return x which would center supplied string
|
||||||
|
int16 Screen::center(char *s) {
|
||||||
|
debugC(1, kDebugDisplay, "center(%s)", s);
|
||||||
|
|
||||||
|
return ((int16)((XPIX - stringLength(s)) >> 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write string at sx,sy in supplied color in current font
|
||||||
|
// If sx == CENTER, center it
|
||||||
|
void Screen::writeStr(int16 sx, int16 sy, char *s, byte color) {
|
||||||
|
byte **font = _font[_fnt];
|
||||||
|
|
||||||
|
debugC(2, kDebugDisplay, "writeStr(%d, %d, %s, %d)", sx, sy, s, color);
|
||||||
|
|
||||||
|
if (sx == CENTER)
|
||||||
|
sx = center(s);
|
||||||
|
|
||||||
|
for (; *s; s++) {
|
||||||
|
writeChr(sx, sy, color, (char *)font[*s]);
|
||||||
|
sx += *(font[*s] + 1) + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shadowed version of writestr
|
||||||
|
void Screen::shadowStr(int16 sx, int16 sy, char *s, byte color) {
|
||||||
|
debugC(1, kDebugDisplay, "shadowStr(%d, %d, %s, %d)", sx, sy, s, color);
|
||||||
|
|
||||||
|
if (sx == CENTER)
|
||||||
|
sx = center(s);
|
||||||
|
|
||||||
|
writeStr(sx + 1, sy + 1, s, _TBLACK);
|
||||||
|
writeStr(sx, sy, s, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load font file, construct font ptrs and reverse data bytes
|
||||||
|
void Screen::loadFont(int16 fontId) {
|
||||||
|
byte height, width;
|
||||||
|
static bool fontLoadedFl[NUM_FONTS] = {0, 0, 0};
|
||||||
|
|
||||||
|
debugC(2, kDebugDisplay, "loadFont(%d)", fontId);
|
||||||
|
|
||||||
|
_fnt = fontId - FIRST_FONT; // Set current font number
|
||||||
|
|
||||||
|
if (fontLoadedFl[_fnt]) // If already loaded, return
|
||||||
|
return;
|
||||||
|
|
||||||
|
fontLoadedFl[_fnt] = true;
|
||||||
|
_vm.file().readUIFItem(fontId, _fontdata[_fnt]);
|
||||||
|
|
||||||
|
// Compile font ptrs. Note: First ptr points to height,width of font
|
||||||
|
_font[_fnt][0] = _fontdata[_fnt]; // Store height,width of fonts
|
||||||
|
|
||||||
|
int16 offset = 2; // Start at fontdata[2] ([0],[1] used for height,width)
|
||||||
|
|
||||||
|
// Setup the font array (127 characters)
|
||||||
|
for (int i = 1; i < 128; i++) {
|
||||||
|
_font[_fnt][i] = _fontdata[_fnt] + offset;
|
||||||
|
height = *(_fontdata[_fnt] + offset);
|
||||||
|
width = *(_fontdata[_fnt] + offset + 1);
|
||||||
|
|
||||||
|
int16 size = height * ((width + 7) >> 3);
|
||||||
|
for (int j = 0; j < size; j++)
|
||||||
|
Utils::reverseByte(&_fontdata[_fnt][offset + 2 + j]);
|
||||||
|
|
||||||
|
offset += 2 + size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// for (i = 0; i < 128; ++i) {
|
||||||
|
// if( (char)i != 'f' && (char)i != '\\'){
|
||||||
|
// continue;
|
||||||
|
// }
|
||||||
|
// int myHeight = _font[_fnt][i][0];
|
||||||
|
// int myWidth = _font[_fnt][i][1];
|
||||||
|
// printf("\n\nFor the letter %c, (%u, %u):\n", i, myWidth, myHeight);
|
||||||
|
// for (int y = 0; y < myHeight; ++y) {
|
||||||
|
// for (int x = 0; x < 8; ++x) {
|
||||||
|
// int pixel = y * (8) + x;
|
||||||
|
// int bitpos = pixel % 8;
|
||||||
|
// int offset = pixel / 8;
|
||||||
|
// byte bitTest = (1 << bitpos);
|
||||||
|
// if ((_font[_fnt][i][2 + offset] & bitTest) == bitTest)
|
||||||
|
// printf("1");
|
||||||
|
// else
|
||||||
|
// printf("0");
|
||||||
|
// }
|
||||||
|
// printf("\n");
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void Screen::userHelp() {
|
||||||
|
// Introduce user to the game
|
||||||
|
// DOS versions Only
|
||||||
|
Utils::Box(BOX_ANY , "F1 - Press F1 again\n"
|
||||||
|
" for instructions\n"
|
||||||
|
"F2 - Sound on/off\n"
|
||||||
|
"F3 - Recall last line\n"
|
||||||
|
"F4 - Save game\n"
|
||||||
|
"F5 - Restore game\n"
|
||||||
|
"F6 - Inventory\n"
|
||||||
|
"F8 - Turbo button\n"
|
||||||
|
"F9 - Boss button\n\n"
|
||||||
|
"ESC - Return to game");
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
109
engines/hugo/display.h
Executable file
109
engines/hugo/display.h
Executable file
|
@ -0,0 +1,109 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_DISPLAY_H
|
||||||
|
#define HUGO_DISPLAY_H
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
enum overlayState_t {UNDEF, FG, BG}; // Overlay state
|
||||||
|
struct rect_t;
|
||||||
|
|
||||||
|
class Screen {
|
||||||
|
public:
|
||||||
|
Screen(HugoEngine &vm);
|
||||||
|
|
||||||
|
int16 fontHeight();
|
||||||
|
int16 stringLength(char *s);
|
||||||
|
|
||||||
|
void displayBackground();
|
||||||
|
void displayFrame(int sx, int sy, seq_t *seq, bool foreFl);
|
||||||
|
void displayList(dupdate_t update, ...);
|
||||||
|
void displayRect(int16 x, int16 y, int16 dx, int16 dy);
|
||||||
|
void initDisplay();
|
||||||
|
void loadFont(int16 fontId);
|
||||||
|
void moveImage(image_pt srcImage, uint16 x1, uint16 y1, uint16 dx, uint16 dy, uint16 width1, image_pt dstImage, uint16 x2, uint16 y2, uint16 width2);
|
||||||
|
void remapPal(uint16 oldIndex, uint16 newIndex);
|
||||||
|
void restorePal(Common::SeekableReadStream *f);
|
||||||
|
void savePal(Common::WriteStream *f);
|
||||||
|
void setBackgroundColor(long color);
|
||||||
|
void shadowStr(int16 sx, int16 sy, char *s, byte color);
|
||||||
|
void userHelp();
|
||||||
|
void writeChar(int16 x, int16 y, char c, byte color);
|
||||||
|
void writeStr(int16 sx, int16 sy, char *s, byte color);
|
||||||
|
|
||||||
|
icondib_t &getIconBuffer() {
|
||||||
|
return _iconBuffer;
|
||||||
|
}
|
||||||
|
viewdib_t &getBackBuffer() {
|
||||||
|
return _backBuffer;
|
||||||
|
}
|
||||||
|
viewdib_t &getBackBufferBackup() {
|
||||||
|
return _backBufferBackup;
|
||||||
|
}
|
||||||
|
viewdib_t &getFrontBuffer() {
|
||||||
|
return _frontBuffer;
|
||||||
|
}
|
||||||
|
viewdib_t &getGUIBuffer() {
|
||||||
|
return _GUIBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
|
||||||
|
// Fonts used in dib (non-GDI)
|
||||||
|
byte _fnt; // Current font number
|
||||||
|
byte _fontdata[NUM_FONTS][FONTSIZE]; // Font data
|
||||||
|
byte *_font[NUM_FONTS][FONT_LEN]; // Ptrs to each char
|
||||||
|
|
||||||
|
viewdib_t _frontBuffer;
|
||||||
|
viewdib_t _backBuffer;
|
||||||
|
viewdib_t _GUIBuffer; // User interface images
|
||||||
|
viewdib_t _backBufferBackup; // Backup _backBuffer during inventory
|
||||||
|
icondib_t _iconBuffer; // Inventory icon DIB
|
||||||
|
|
||||||
|
void createPal();
|
||||||
|
overlayState_t findOvl(seq_t *seq_p, image_pt dst_p, uint16 y);
|
||||||
|
void merge(rect_t *rectA, rect_t *rectB);
|
||||||
|
int16 mergeLists(rect_t *list, rect_t *blist, int16 len, int16 blen, int16 bmax);
|
||||||
|
void writeChr(int sx, int sy, byte color, char *local_fontdata);
|
||||||
|
int16 center(char *s);
|
||||||
|
|
||||||
|
// Also used in rout.cpp when DEBUG_ROUTE is defined
|
||||||
|
unsigned int GetPalIndex(byte color);
|
||||||
|
|
||||||
|
// Useless ?
|
||||||
|
void clearPromptLine();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif //HUGO_DISPLAY_H
|
993
engines/hugo/engine.cpp
Executable file
993
engines/hugo/engine.cpp
Executable file
|
@ -0,0 +1,993 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo 1-3 Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
#include "common/random.h"
|
||||||
|
#include "common/EventRecorder.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/engine.h"
|
||||||
|
#include "hugo/global.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/schedule.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/parser.h"
|
||||||
|
#include "hugo/route.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
#include "hugo/sound.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define EDGE 10 // Closest object can get to edge of screen
|
||||||
|
#define EDGE2 (EDGE * 2) // Push object further back on edge collision
|
||||||
|
#define SHIFT 8 // Place hero this far inside bounding box
|
||||||
|
#define MAX_OBJECTS 128 // Used in Update_images()
|
||||||
|
#define BOUND(X, Y) ((_boundary[Y * XBYTES + X / 8] & (0x80 >> X % 8)) != 0) // Boundary bit set
|
||||||
|
|
||||||
|
config_t _config; // User's config
|
||||||
|
maze_t _maze = {false, 0, 0, 0, 0, 0, 0, 0, 0}; // Default to not in maze
|
||||||
|
hugo_boot_t _boot; // Boot info structure file
|
||||||
|
char _textBoxBuffer[MAX_BOX]; // Buffer for text box
|
||||||
|
command_t _line = ""; // Line of user text input
|
||||||
|
|
||||||
|
|
||||||
|
// Sets the playlist to be the default tune selection
|
||||||
|
void HugoEngine::initPlaylist(bool playlist[MAX_TUNES]) {
|
||||||
|
debugC(1, kDebugEngine, "initPlaylist");
|
||||||
|
|
||||||
|
for (int16 i = 0; i < MAX_TUNES; i++)
|
||||||
|
playlist[i] = false;
|
||||||
|
for (int16 i = 0; _defltTunes[i] != -1; i++)
|
||||||
|
playlist[_defltTunes[i]] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize the dynamic game status
|
||||||
|
void HugoEngine::initStatus() {
|
||||||
|
debugC(1, kDebugEngine, "initStatus");
|
||||||
|
_status.initSaveFl = false; // Don't force initial save
|
||||||
|
_status.storyModeFl = false; // Not in story mode
|
||||||
|
_status.gameOverFl = false; // Hero not knobbled yet
|
||||||
|
_status.recordFl = false; // Not record mode
|
||||||
|
_status.playbackFl = false; // Not playback mode
|
||||||
|
_status.demoFl = false; // Not demo mode
|
||||||
|
_status.textBoxFl = false; // Not processing a text box
|
||||||
|
// Strangerke - Not used ?
|
||||||
|
// _status.mmtime = false; // Multimedia timer support
|
||||||
|
_status.lookFl = false; // Toolbar "look" button
|
||||||
|
_status.recallFl = false; // Toolbar "recall" button
|
||||||
|
_status.leftButtonFl = false; // Left mouse button pressed
|
||||||
|
_status.rightButtonFl = false; // Right mouse button pressed
|
||||||
|
_status.newScreenFl = false; // Screen not just loaded
|
||||||
|
_status.jumpExitFl = false; // Can't jump to a screen exit
|
||||||
|
_status.godModeFl = false; // No special cheats allowed
|
||||||
|
_status.helpFl = false; // Not calling WinHelp()
|
||||||
|
_status.path[0] = 0; // Path to write files
|
||||||
|
_status.saveSlot = 0; // Slot to save/restore game
|
||||||
|
_status.screenWidth = 0; // Desktop screen width
|
||||||
|
|
||||||
|
// Initialize every start of new game
|
||||||
|
_status.tick = 0; // Tick count
|
||||||
|
_status.saveTick = 0; // Time of last save
|
||||||
|
_status.viewState = V_IDLE; // View state
|
||||||
|
_status.inventoryState = I_OFF; // Inventory icon bar state
|
||||||
|
_status.inventoryHeight = 0; // Inventory icon bar pos
|
||||||
|
_status.inventoryObjId = -1; // Inventory object selected (none)
|
||||||
|
_status.routeIndex = -1; // Hero not following a route
|
||||||
|
_status.go_for = GO_SPACE; // Hero walking to space
|
||||||
|
_status.go_id = -1; // Hero not walking to anything
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize default config values. Must be done before Initialize().
|
||||||
|
// Reset needed to save config.cx,cy which get splatted during OnFileNew()
|
||||||
|
void HugoEngine::initConfig(inst_t action) {
|
||||||
|
static int16 cx, cy; // Save window size, pos
|
||||||
|
int16 i;
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "initConfig(%d)", action);
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case INSTALL:
|
||||||
|
_config.musicFl = true; // Music state initially on
|
||||||
|
_config.soundFl = true; // Sound state initially on
|
||||||
|
_config.turboFl = false; // Turbo state initially off
|
||||||
|
_config.backgroundMusicFl = false; // No music when inactive
|
||||||
|
_config.cx = VIEW_DX * 2; // Window view size
|
||||||
|
_config.cy = VIEW_DY * 2;
|
||||||
|
|
||||||
|
// _config.wx = 0;
|
||||||
|
// _config.wy = 0;
|
||||||
|
|
||||||
|
_config.musicVolume = 85; // Music volume %
|
||||||
|
_config.soundVolume = 100; // Sound volume %
|
||||||
|
initPlaylist(_config.playlist); // Initialize default tune playlist
|
||||||
|
|
||||||
|
HugoEngine::get().file().readBootFile(); // Read startup structure
|
||||||
|
HugoEngine::get().file().readConfig(); // Read user's saved config
|
||||||
|
|
||||||
|
cx = _config.cx; // Save these around OnFileNew()
|
||||||
|
cy = _config.cy;
|
||||||
|
// wx = _config.wx;
|
||||||
|
// wy = _config.wy;
|
||||||
|
break;
|
||||||
|
case RESET:
|
||||||
|
_config.cx = cx; // Restore cx, cy
|
||||||
|
_config.cy = cy;
|
||||||
|
// _config.wx = wx;
|
||||||
|
// _config.wy = wy;
|
||||||
|
|
||||||
|
// Find first tune and play it
|
||||||
|
for (i = 0; i < MAX_TUNES; i++)
|
||||||
|
if (_config.playlist[i]) {
|
||||||
|
sound().playMusic(i);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
HugoEngine::get().file().initSavedGame(); // Initialize saved game
|
||||||
|
break;
|
||||||
|
case RESTORE:
|
||||||
|
warning("Unhandled action RESTORE");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void HugoEngine::initialize() {
|
||||||
|
debugC(1, kDebugEngine, "initialize");
|
||||||
|
|
||||||
|
sound().initSound(INSTALL);
|
||||||
|
HugoEngine::get().scheduler().initEventQueue(); // Init scheduler stuff
|
||||||
|
screen().initDisplay(); // Create Dibs and palette
|
||||||
|
HugoEngine::get().file().openDatabaseFiles(); // Open database files
|
||||||
|
calcMaxScore(); // Initialise maxscore
|
||||||
|
|
||||||
|
_rnd = new Common::RandomSource();
|
||||||
|
g_eventRec.registerRandomSource(*_rnd, "hugo");
|
||||||
|
|
||||||
|
_rnd->setSeed(42); // Kick random number generator
|
||||||
|
|
||||||
|
switch (getGameType()) {
|
||||||
|
case kGameTypeHugo1:
|
||||||
|
_episode = "\"HUGO'S HOUSE OF HORRORS\"";
|
||||||
|
_picDir = "";
|
||||||
|
break;
|
||||||
|
case kGameTypeHugo2:
|
||||||
|
_episode = "\"Hugo's Mystery Adventure\"";
|
||||||
|
_picDir = "hugo2/";
|
||||||
|
break;
|
||||||
|
case kGameTypeHugo3:
|
||||||
|
_episode = "\"Hugo's Amazon Adventure\"";
|
||||||
|
_picDir = "hugo3/";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
error("Unknown game");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore all resources before termination
|
||||||
|
void HugoEngine::shutdown() {
|
||||||
|
debugC(1, kDebugEngine, "shutdown");
|
||||||
|
|
||||||
|
sound().initSound(RESTORE);
|
||||||
|
|
||||||
|
HugoEngine::get().file().closeDatabaseFiles();
|
||||||
|
if (_status.recordFl || _status.playbackFl)
|
||||||
|
HugoEngine::get().file().closePlaybackFile();
|
||||||
|
freeObjects();
|
||||||
|
}
|
||||||
|
|
||||||
|
void HugoEngine::readObjectImages() {
|
||||||
|
debugC(1, kDebugEngine, "readObjectImages");
|
||||||
|
|
||||||
|
for (int i = 0; i < _numObj; i++)
|
||||||
|
HugoEngine::get().file().readImage(i, &_objects[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the uif image file (inventory icons)
|
||||||
|
void HugoEngine::readUIFImages() {
|
||||||
|
debugC(1, kDebugEngine, "readUIFImages");
|
||||||
|
|
||||||
|
HugoEngine::get().file().readUIFItem(UIF_IMAGES, screen().getGUIBuffer()); // Read all uif images
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read scenery, overlay files for given screen number
|
||||||
|
void HugoEngine::readScreenFiles(int screenNum) {
|
||||||
|
debugC(1, kDebugEngine, "readScreenFiles(%d)", screenNum);
|
||||||
|
|
||||||
|
HugoEngine::get().file().readBackground(screenNum); // Scenery file
|
||||||
|
memcpy(screen().getBackBuffer(), screen().getFrontBuffer(), sizeof(screen().getFrontBuffer()));// Make a copy
|
||||||
|
HugoEngine::get().file().readOverlay(screenNum, _boundary, BOUNDARY); // Boundary file
|
||||||
|
HugoEngine::get().file().readOverlay(screenNum, _overlay, OVERLAY); // Overlay file
|
||||||
|
HugoEngine::get().file().readOverlay(screenNum, _ovlBase, OVLBASE); // Overlay base file
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update all object positions. Process object 'local' events
|
||||||
|
// including boundary events and collisions
|
||||||
|
void HugoEngine::moveObjects() {
|
||||||
|
object_t *obj;
|
||||||
|
seq_t *currImage;
|
||||||
|
int x1, x2, y1, y2; // object coordinates
|
||||||
|
int dx, dy; // Allowable motion wrt boundary
|
||||||
|
char radius; // Radius for chase (8 bit signed)
|
||||||
|
|
||||||
|
debugC(4, kDebugEngine, "moveObjects");
|
||||||
|
|
||||||
|
// If route mode enabled, do special route processing
|
||||||
|
if (_status.routeIndex >= 0)
|
||||||
|
route().processRoute();
|
||||||
|
|
||||||
|
// Perform any adjustments to velocity based on special path types
|
||||||
|
// and store all (visible) object baselines into the boundary file.
|
||||||
|
// Don't store foreground or background objects
|
||||||
|
for (int i = 0; i < _numObj; i++) {
|
||||||
|
obj = &_objects[i]; // Get pointer to object
|
||||||
|
currImage = obj->currImagePtr; // Get ptr to current image
|
||||||
|
if (obj->screenIndex == *_screen_p) {
|
||||||
|
switch (obj->pathType) {
|
||||||
|
case CHASE:
|
||||||
|
case CHASE2:
|
||||||
|
radius = obj->radius; // Default to object's radius
|
||||||
|
if (radius < 0) // If radius infinity, use closer value
|
||||||
|
radius = DX;
|
||||||
|
|
||||||
|
dx = _hero->x + _hero->currImagePtr->x1 - obj->x - currImage->x1;
|
||||||
|
dy = _hero->y + _hero->currImagePtr->y2 - obj->y - currImage->y2 - 1;
|
||||||
|
if (abs(dx) <= radius)
|
||||||
|
obj->vx = 0;
|
||||||
|
else
|
||||||
|
obj->vx = dx > 0 ? MIN(dx, obj->vxPath) : MAX(dx, -obj->vxPath);
|
||||||
|
if (abs(dy) <= radius)
|
||||||
|
obj->vy = 0;
|
||||||
|
else
|
||||||
|
obj->vy = dy > 0 ? MIN(dy, obj->vyPath) : MAX(dy, -obj->vyPath);
|
||||||
|
|
||||||
|
// Set first image in sequence (if multi-seq object)
|
||||||
|
switch (obj->seqNumb) {
|
||||||
|
case 4:
|
||||||
|
if (!obj->vx) { // Got 4 directions
|
||||||
|
if (obj->vx != obj->oldvx) // vx just stopped
|
||||||
|
if (dy >= 0)
|
||||||
|
obj->currImagePtr = obj->seqList[DOWN].seqPtr;
|
||||||
|
else
|
||||||
|
obj->currImagePtr = obj->seqList[_UP].seqPtr;
|
||||||
|
} else if (obj->vx != obj->oldvx)
|
||||||
|
if (dx > 0)
|
||||||
|
obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
|
||||||
|
else
|
||||||
|
obj->currImagePtr = obj->seqList[LEFT].seqPtr;
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
case 2:
|
||||||
|
if (obj->vx != obj->oldvx) // vx just stopped
|
||||||
|
if (dx > 0) // Left & right only
|
||||||
|
obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
|
||||||
|
else
|
||||||
|
obj->currImagePtr = obj->seqList[LEFT].seqPtr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->vx || obj->vy)
|
||||||
|
obj->cycling = CYCLE_FORWARD;
|
||||||
|
else {
|
||||||
|
obj->cycling = NOT_CYCLING;
|
||||||
|
boundaryCollision(obj); // Must have got hero!
|
||||||
|
}
|
||||||
|
obj->oldvx = obj->vx;
|
||||||
|
obj->oldvy = obj->vy;
|
||||||
|
currImage = obj->currImagePtr; // Get (new) ptr to current image
|
||||||
|
break;
|
||||||
|
case WANDER2:
|
||||||
|
case WANDER:
|
||||||
|
if (!_rnd->getRandomNumber(3 * NORMAL_TPS)) { // Kick on random interval
|
||||||
|
obj->vx = _rnd->getRandomNumber(obj->vxPath << 1) - obj->vxPath;
|
||||||
|
obj->vy = _rnd->getRandomNumber(obj->vyPath << 1) - obj->vyPath;
|
||||||
|
|
||||||
|
// Set first image in sequence (if multi-seq object)
|
||||||
|
if (obj->seqNumb > 1) {
|
||||||
|
if (!obj->vx && (obj->seqNumb >= 4)) {
|
||||||
|
if (obj->vx != obj->oldvx) // vx just stopped
|
||||||
|
if (obj->vy > 0)
|
||||||
|
obj->currImagePtr = obj->seqList[DOWN].seqPtr;
|
||||||
|
else
|
||||||
|
obj->currImagePtr = obj->seqList[_UP].seqPtr;
|
||||||
|
} else if (obj->vx != obj->oldvx)
|
||||||
|
if (obj->vx > 0)
|
||||||
|
obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
|
||||||
|
else
|
||||||
|
obj->currImagePtr = obj->seqList[LEFT].seqPtr;
|
||||||
|
}
|
||||||
|
obj->oldvx = obj->vx;
|
||||||
|
obj->oldvy = obj->vy;
|
||||||
|
currImage = obj->currImagePtr; // Get (new) ptr to current image
|
||||||
|
}
|
||||||
|
if (obj->vx || obj->vy)
|
||||||
|
obj->cycling = CYCLE_FORWARD;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
; // Really, nothing
|
||||||
|
}
|
||||||
|
// Store boundaries
|
||||||
|
if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
|
||||||
|
storeBoundary(obj->x + currImage->x1, obj->x + currImage->x2, obj->y + currImage->y2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move objects, allowing for boundaries
|
||||||
|
for (int i = 0; i < _numObj; i++) {
|
||||||
|
obj = &_objects[i]; // Get pointer to object
|
||||||
|
if ((obj->screenIndex == *_screen_p) && (obj->vx || obj->vy)) {
|
||||||
|
// Only process if it's moving
|
||||||
|
|
||||||
|
// Do object movement. Delta_x,y return allowed movement in x,y
|
||||||
|
// to move as close to a boundary as possible without crossing it.
|
||||||
|
currImage = obj->currImagePtr; // Get ptr to current image
|
||||||
|
x1 = obj->x + currImage->x1; // Left edge of object
|
||||||
|
x2 = obj->x + currImage->x2; // Right edge
|
||||||
|
y1 = obj->y + currImage->y1; // Top edge
|
||||||
|
y2 = obj->y + currImage->y2; // Bottom edge
|
||||||
|
|
||||||
|
if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
|
||||||
|
clearBoundary(x1, x2, y2); // Clear our own boundary
|
||||||
|
dx = deltaX(x1, x2, obj->vx, y2);
|
||||||
|
if (dx != obj->vx) {
|
||||||
|
// An object boundary collision!
|
||||||
|
boundaryCollision(obj);
|
||||||
|
obj->vx = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
dy = deltaY(x1, x2, obj->vy, y2);
|
||||||
|
|
||||||
|
if (dy != obj->vy) {
|
||||||
|
// An object boundary collision!
|
||||||
|
boundaryCollision(obj);
|
||||||
|
obj->vy = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
|
||||||
|
storeBoundary(x1, x2, y2); // Re-store our own boundary
|
||||||
|
|
||||||
|
obj->x += dx; // Update object position
|
||||||
|
obj->y += dy;
|
||||||
|
|
||||||
|
// Don't let object go outside screen
|
||||||
|
if (x1 < EDGE)
|
||||||
|
obj->x = EDGE2;
|
||||||
|
if (x2 > (XPIX - EDGE))
|
||||||
|
obj->x = XPIX - EDGE2 - (x2 - x1);
|
||||||
|
if (y1 < EDGE)
|
||||||
|
obj->y = EDGE2;
|
||||||
|
if (y2 > (YPIX - EDGE))
|
||||||
|
obj->y = YPIX - EDGE2 - (y2 - y1);
|
||||||
|
|
||||||
|
if ((obj->vx == 0) && (obj->vy == 0) && (obj->pathType != WANDER2) && (obj->pathType != CHASE2))
|
||||||
|
obj->cycling = NOT_CYCLING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear all object baselines from the boundary file.
|
||||||
|
for (int i = 0; i < _numObj; i++) {
|
||||||
|
obj = &_objects[i]; // Get pointer to object
|
||||||
|
currImage = obj->currImagePtr; // Get ptr to current image
|
||||||
|
if ((obj->screenIndex == *_screen_p) && (obj->cycling > ALMOST_INVISIBLE) && (obj->priority == FLOATING))
|
||||||
|
clearBoundary(obj->oldx + currImage->x1, obj->oldx + currImage->x2, obj->oldy + currImage->y2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If maze mode is enabled, do special maze processing
|
||||||
|
if (_maze.enabledFl)
|
||||||
|
processMaze();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return maximum allowed movement (from zero to vx) such that object does
|
||||||
|
// not cross a boundary (either background or another object)
|
||||||
|
int HugoEngine::deltaX(int x1, int x2, int vx, int y) {
|
||||||
|
// Explanation of algorithm: The boundaries are drawn as contiguous
|
||||||
|
// lines 1 pixel wide. Since DX,DY are not necessarily 1, we must
|
||||||
|
// detect boundary crossing. If vx positive, examine each pixel from
|
||||||
|
// x1 old to x2 new, else x2 old to x1 new, both at the y2 line.
|
||||||
|
// If vx zero, no need to check. If vy non-zero then examine each
|
||||||
|
// pixel on the line segment x1 to x2 from y old to y new.
|
||||||
|
// Fix from Hugo I v1.5:
|
||||||
|
// Note the diff is munged in the return statement to cater for a special
|
||||||
|
// cases arising from differences in image widths from one sequence to
|
||||||
|
// another. The problem occurs reversing direction at a wall where the
|
||||||
|
// new image intersects before the object can move away. This is cured
|
||||||
|
// by comparing the intersection with half the object width pos. If the
|
||||||
|
// intersection is in the other half wrt the intended direction, use the
|
||||||
|
// desired vx, else use the computed delta. i.e. believe the desired vx
|
||||||
|
int b;
|
||||||
|
|
||||||
|
debugC(3, kDebugEngine, "deltaX(%d, %d, %d, %d)", x1, x2, vx, y);
|
||||||
|
|
||||||
|
if (vx == 0)
|
||||||
|
return(0); // Object stationary
|
||||||
|
|
||||||
|
y *= XBYTES; // Offset into boundary file
|
||||||
|
if (vx > 0) {
|
||||||
|
// Moving to right
|
||||||
|
for (int i = x1 >> 3; i <= (x2 + vx) >> 3; i++) // Search by byte
|
||||||
|
if ((b = Utils::firstBit((byte)(_boundary[y + i] | _objBound[y + i]))) < 8) { // b is index or 8
|
||||||
|
// Compute x of boundary and test if intersection
|
||||||
|
b += i << 3;
|
||||||
|
if ((b >= x1) && (b <= x2 + vx))
|
||||||
|
return((b < x1 + ((x2 - x1) >> 1)) ? vx : b - x2 - 1); // return dx
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Moving to left
|
||||||
|
for (int i = x2 >> 3; i >= (x1 + vx) >> 3; i--)// Search by byte
|
||||||
|
if ((b = Utils::lastBit((byte)(_boundary[y + i] | _objBound[y + i]))) < 8) { // b is index or 8
|
||||||
|
// Compute x of boundary and test if intersection
|
||||||
|
b += i << 3;
|
||||||
|
if ((b >= x1 + vx) && (b <= x2))
|
||||||
|
return((b > x1 + ((x2 - x1) >> 1)) ? vx : b - x1 + 1); // return dx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return(vx);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Similar to Delta_x, but for movement in y direction. Special case of
|
||||||
|
// bytes at end of line segment; must only count boundary bits falling on
|
||||||
|
// line segment.
|
||||||
|
int HugoEngine::deltaY(int x1, int x2, int vy, int y) {
|
||||||
|
int inc, i, j, b;
|
||||||
|
|
||||||
|
debugC(3, kDebugEngine, "deltaY(%d, %d, %d, %d)", x1, x2, vy, y);
|
||||||
|
|
||||||
|
if (vy == 0)
|
||||||
|
return(0); // Object stationary
|
||||||
|
|
||||||
|
inc = (vy > 0 ? 1 : -1);
|
||||||
|
for (j = y + inc; j != (y + vy + inc); j += inc) //Search by byte
|
||||||
|
for (i = x1 >> 3; i <= x2 >> 3; i++)
|
||||||
|
if (b = _boundary[j * XBYTES + i] | _objBound[j * XBYTES + i]) { // Any bit set
|
||||||
|
// Make sure boundary bits fall on line segment
|
||||||
|
if (i == (x2 >> 3)) // Adjust right end
|
||||||
|
b &= 0xff << ((i << 3) + 7 - x2);
|
||||||
|
else if (i == (x1 >> 3)) // Adjust left end
|
||||||
|
b &= 0xff >> (x1 - (i << 3));
|
||||||
|
if (b)
|
||||||
|
return(j - y - inc);
|
||||||
|
}
|
||||||
|
return(vy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Store a horizontal line segment in the object boundary file
|
||||||
|
void HugoEngine::storeBoundary(int x1, int x2, int y) {
|
||||||
|
byte *b; // ptr to boundary byte
|
||||||
|
|
||||||
|
debugC(5, kDebugEngine, "storeBoundary(%d, %d, %d)", x1, x2, y);
|
||||||
|
|
||||||
|
for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line
|
||||||
|
b = &_objBound[y * XBYTES + i]; // get boundary byte
|
||||||
|
if (i == x2 >> 3) // Adjust right end
|
||||||
|
*b |= 0xff << ((i << 3) + 7 - x2);
|
||||||
|
else if (i == x1 >> 3) // Adjust left end
|
||||||
|
*b |= 0xff >> (x1 - (i << 3));
|
||||||
|
else
|
||||||
|
*b = 0xff;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear a horizontal line segment in the object boundary file
|
||||||
|
void HugoEngine::clearBoundary(int x1, int x2, int y) {
|
||||||
|
int i;
|
||||||
|
byte *b; // ptr to boundary byte
|
||||||
|
|
||||||
|
debugC(5, kDebugEngine, "clearBoundary(%d, %d, %d)", x1, x2, y);
|
||||||
|
|
||||||
|
for (i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line
|
||||||
|
b = &_objBound[y * XBYTES + i]; // get boundary byte
|
||||||
|
if (i == x2 >> 3) // Adjust right end
|
||||||
|
*b &= ~(0xff << ((i << 3) + 7 - x2));
|
||||||
|
else if (i == x1 >> 3) // Adjust left end
|
||||||
|
*b &= ~(0xff >> (x1 - (i << 3)));
|
||||||
|
else
|
||||||
|
*b = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Maze mode is enabled. Check to see whether hero has crossed the maze
|
||||||
|
// bounding box, if so, go to the next room */
|
||||||
|
void HugoEngine::processMaze() {
|
||||||
|
seq_t *currImage;
|
||||||
|
int x1, x2, y1, y2; // hero coordinates
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "processMaze");
|
||||||
|
|
||||||
|
//actlist alnewscr = {&aheroxy,&astophero,&aherostop,&anewscr,NULL};
|
||||||
|
//actlist_pt alist = &alnewscr[0];
|
||||||
|
|
||||||
|
currImage = _hero->currImagePtr; // Get ptr to current image
|
||||||
|
x1 = _hero->x + currImage->x1; // Left edge of object
|
||||||
|
x2 = _hero->x + currImage->x2; // Right edge
|
||||||
|
y1 = _hero->y + currImage->y1; // Top edge
|
||||||
|
y2 = _hero->y + currImage->y2; // Bottom edge
|
||||||
|
|
||||||
|
if (x1 < _maze.x1) {
|
||||||
|
// Exit west
|
||||||
|
// anewscr.screen = *_screen_p - 1;
|
||||||
|
_actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p - 1;
|
||||||
|
// aheroxy.x = _maze.x2 - SHIFT - (x2 - x1);
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.x = _maze.x2 - SHIFT - (x2 - x1);
|
||||||
|
// aheroxy.y = _hero_p->y;
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.y = _hero->y;
|
||||||
|
_status.routeIndex = -1;
|
||||||
|
HugoEngine::get().scheduler().insertActionList(_alNewscrIndex);
|
||||||
|
} else if (x2 > _maze.x2) {
|
||||||
|
// Exit east
|
||||||
|
// anewscr.screen = *_screen_p + 1;
|
||||||
|
_actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p + 1;
|
||||||
|
// aheroxy.x = _maze.x1 + SHIFT;
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.x = _maze.x1 + SHIFT;
|
||||||
|
// aheroxy.y = _hero_p->y;
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.y = _hero->y;
|
||||||
|
_status.routeIndex = -1;
|
||||||
|
HugoEngine::get().scheduler().insertActionList(_alNewscrIndex);
|
||||||
|
} else if (y1 < _maze.y1 - SHIFT) {
|
||||||
|
// Exit north
|
||||||
|
// anewscr.screen = *_screen_p - _maze.size;
|
||||||
|
_actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p - _maze.size;
|
||||||
|
// aheroxy.x = _maze.x3; // special offset for perspective
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.x = _maze.x3;
|
||||||
|
// aheroxy.y = _maze.y2 - SHIFT - (y2 - y1);
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.y = _maze.y2 - SHIFT - (y2 - y1);
|
||||||
|
_status.routeIndex = -1;
|
||||||
|
HugoEngine::get().scheduler().insertActionList(_alNewscrIndex);
|
||||||
|
} else if (y2 > _maze.y2 - SHIFT / 2) {
|
||||||
|
// Exit south
|
||||||
|
// anewscr.screen = *_screen_p + _maze.size;
|
||||||
|
_actListArr[_alNewscrIndex][3].a8.screenIndex = *_screen_p + _maze.size;
|
||||||
|
// aheroxy.x = _maze.x4; // special offset for perspective
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.x = _maze.x4;
|
||||||
|
// aheroxy.y = _maze.y1 + SHIFT;
|
||||||
|
_actListArr[_alNewscrIndex][0].a2.y = _maze.y1 + SHIFT;
|
||||||
|
_status.routeIndex = -1;
|
||||||
|
HugoEngine::get().scheduler().insertActionList(_alNewscrIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare function for the quicksort. The sort is to order the objects in
|
||||||
|
// increasing vertical position, using y+y2 as the baseline
|
||||||
|
// Returns -1 if ay2 < by2 else 1 if ay2 > by2 else 0
|
||||||
|
int y2comp(const void *a, const void *b) {
|
||||||
|
int ay2, by2;
|
||||||
|
|
||||||
|
debugC(6, kDebugEngine, "y2comp");
|
||||||
|
|
||||||
|
const object_t *p1 = &HugoEngine::get()._objects[*(const byte *)a];
|
||||||
|
const object_t *p2 = &HugoEngine::get()._objects[*(const byte *)b];
|
||||||
|
|
||||||
|
if (p1 == p2)
|
||||||
|
// Why does qsort try the same indexes?
|
||||||
|
return (0);
|
||||||
|
|
||||||
|
if (p1->priority == BACKGROUND)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
if (p2->priority == BACKGROUND)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (p1->priority == FOREGROUND)
|
||||||
|
return (1);
|
||||||
|
|
||||||
|
if (p2->priority == FOREGROUND)
|
||||||
|
return (-1);
|
||||||
|
|
||||||
|
ay2 = p1->y + p1->currImagePtr->y2;
|
||||||
|
by2 = p2->y + p2->currImagePtr->y2;
|
||||||
|
|
||||||
|
return(ay2 - by2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw all objects on screen as follows:
|
||||||
|
// 1. Sort 'FLOATING' objects in order of y2 (base of object)
|
||||||
|
// 2. Display new object frames/positions in dib
|
||||||
|
// Finally, cycle any animating objects to next frame
|
||||||
|
void HugoEngine::updateImages() {
|
||||||
|
int i, j, num_objs;
|
||||||
|
object_t *obj; // Pointer to object
|
||||||
|
seq_t *seqPtr; // Save curr_seq_p
|
||||||
|
byte objindex[MAX_OBJECTS]; // Array of indeces to objects
|
||||||
|
|
||||||
|
debugC(5, kDebugEngine, "updateImages");
|
||||||
|
|
||||||
|
// Initialise the index array to visible objects in current screen
|
||||||
|
for (i = 0, num_objs = 0; i < _numObj; i++) {
|
||||||
|
obj = &_objects[i];
|
||||||
|
if ((obj->screenIndex == *_screen_p) && (obj->cycling >= ALMOST_INVISIBLE))
|
||||||
|
objindex[num_objs++] = i;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sort the objects into increasing y+y2 (painter's algorithm)
|
||||||
|
qsort(objindex, num_objs, sizeof(objindex[0]), y2comp);
|
||||||
|
|
||||||
|
// Add each visible object to display list
|
||||||
|
for (i = 0; i < num_objs; i++) {
|
||||||
|
obj = &_objects[objindex[i]];
|
||||||
|
// Count down inter-frame timer
|
||||||
|
if (obj->frameTimer)
|
||||||
|
obj->frameTimer--;
|
||||||
|
|
||||||
|
if (obj->cycling > ALMOST_INVISIBLE) // Only if visible
|
||||||
|
switch (obj->cycling) {
|
||||||
|
case NOT_CYCLING:
|
||||||
|
screen().displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
|
||||||
|
break;
|
||||||
|
case CYCLE_FORWARD:
|
||||||
|
if (obj->frameTimer) // Not time to see next frame yet
|
||||||
|
screen().displayFrame(obj->x, obj->y, obj->currImagePtr, obj->priority == OVEROVL);
|
||||||
|
else
|
||||||
|
screen().displayFrame(obj->x, obj->y, obj->currImagePtr->nextSeqPtr, obj->priority == OVEROVL);
|
||||||
|
break;
|
||||||
|
case CYCLE_BACKWARD:
|
||||||
|
seqPtr = obj->currImagePtr;
|
||||||
|
if (!obj->frameTimer) // Show next frame
|
||||||
|
while (seqPtr->nextSeqPtr != obj->currImagePtr)
|
||||||
|
seqPtr = seqPtr->nextSeqPtr;
|
||||||
|
screen().displayFrame(obj->x, obj->y, seqPtr, obj->priority == OVEROVL);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cycle any animating objects
|
||||||
|
for (i = 0; i < num_objs; i++) {
|
||||||
|
obj = &_objects[objindex[i]];
|
||||||
|
if (obj->cycling != INVISIBLE) {
|
||||||
|
// Only if it's visible
|
||||||
|
if (obj->cycling == ALMOST_INVISIBLE)
|
||||||
|
obj->cycling = INVISIBLE;
|
||||||
|
|
||||||
|
// Now Rotate to next picture in sequence
|
||||||
|
switch (obj->cycling) {
|
||||||
|
case NOT_CYCLING:
|
||||||
|
break;
|
||||||
|
case CYCLE_FORWARD:
|
||||||
|
if (!obj->frameTimer) {
|
||||||
|
// Time to step to next frame
|
||||||
|
obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
|
||||||
|
// Find out if this is last frame of sequence
|
||||||
|
// If so, reset frame_timer and decrement n_cycle
|
||||||
|
if (obj->frameInterval || obj->cycleNumb) {
|
||||||
|
obj->frameTimer = obj->frameInterval;
|
||||||
|
for (j = 0; j < obj->seqNumb; j++)
|
||||||
|
if (obj->currImagePtr->nextSeqPtr == obj->seqList[j].seqPtr)
|
||||||
|
if (obj->cycleNumb) // Decr cycleNumb if Non-continous
|
||||||
|
if (!--obj->cycleNumb)
|
||||||
|
obj->cycling = NOT_CYCLING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case CYCLE_BACKWARD:
|
||||||
|
if (!obj->frameTimer) {
|
||||||
|
// Time to step to prev frame
|
||||||
|
seqPtr = obj->currImagePtr;
|
||||||
|
while (obj->currImagePtr->nextSeqPtr != seqPtr)
|
||||||
|
obj->currImagePtr = obj->currImagePtr->nextSeqPtr;
|
||||||
|
// Find out if this is first frame of sequence
|
||||||
|
// If so, reset frame_timer and decrement n_cycle
|
||||||
|
if (obj->frameInterval || obj->cycleNumb) {
|
||||||
|
obj->frameTimer = obj->frameInterval;
|
||||||
|
for (j = 0; j < obj->seqNumb; j++)
|
||||||
|
if (obj->currImagePtr == obj->seqList[j].seqPtr)
|
||||||
|
if (obj->cycleNumb) // Decr cycleNumb if Non-continous
|
||||||
|
if (!--obj->cycleNumb)
|
||||||
|
obj->cycling = NOT_CYCLING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
obj->oldx = obj->x;
|
||||||
|
obj->oldy = obj->y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return object index of the topmost object under the cursor, or -1 if none
|
||||||
|
// Objects are filtered if not "useful"
|
||||||
|
int16 HugoEngine::findObject(uint16 x, uint16 y) {
|
||||||
|
object_t *obj;
|
||||||
|
seq_t *curImage;
|
||||||
|
int16 objIndex = -1; // Index of found object
|
||||||
|
uint16 y2Max = 0; // Greatest y2
|
||||||
|
int i;
|
||||||
|
|
||||||
|
debugC(3, kDebugEngine, "findObject(%d, %d)", x, y);
|
||||||
|
|
||||||
|
// Check objects on screen
|
||||||
|
for (i = 0, obj = _objects; i < _numObj; i++, obj++) {
|
||||||
|
// Object must be in current screen and "useful"
|
||||||
|
if (obj->screenIndex == *_screen_p && (obj->genericCmd || obj->objValue || obj->cmdIndex)) {
|
||||||
|
curImage = obj->currImagePtr;
|
||||||
|
// Object must have a visible image...
|
||||||
|
if (curImage != NULL && obj->cycling != INVISIBLE) {
|
||||||
|
// If cursor inside object
|
||||||
|
if (x >= (uint16)obj->x && x <= obj->x + curImage->x2 && y >= (uint16)obj->y && y <= obj->y + curImage->y2)
|
||||||
|
// If object is closest so far
|
||||||
|
if (obj->y + curImage->y2 > y2Max) {
|
||||||
|
y2Max = obj->y + curImage->y2;
|
||||||
|
objIndex = i; // Found an object!
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
// ...or a dummy object that has a hotspot rectangle
|
||||||
|
if (curImage == NULL && obj->vxPath != 0 && !obj->carriedFl) {
|
||||||
|
// If cursor inside special rectangle
|
||||||
|
if ((int16)x >= obj->oldx && (int16)x < obj->oldx + obj->vxPath && (int16)y >= obj->oldy && (int16)y < obj->oldy + obj->vyPath)
|
||||||
|
// If object is closest so far
|
||||||
|
if (obj->oldy + obj->vyPath - 1 > (int16)y2Max) {
|
||||||
|
y2Max = obj->oldy + obj->vyPath - 1;
|
||||||
|
objIndex = i; // Found an object!
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return objIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find a clear space around supplied object that hero can walk to
|
||||||
|
bool HugoEngine::findObjectSpace(object_t *obj, int16 *destx, int16 *desty) {
|
||||||
|
// bool found = false; // TRUE if we found a clear space
|
||||||
|
bool foundFl;
|
||||||
|
seq_t *curImage = obj->currImagePtr;
|
||||||
|
int16 x;
|
||||||
|
int16 y = obj->y + curImage->y2 - 1;
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "findObjectSpace(obj, %d, %d)", *destx, *desty);
|
||||||
|
|
||||||
|
// if (!found) // Try left rear corner
|
||||||
|
for (foundFl = true, *destx = x = obj->x + curImage->x1; x < *destx + HERO_MAX_WIDTH; x++)
|
||||||
|
if (BOUND(x, y))
|
||||||
|
foundFl = false;
|
||||||
|
|
||||||
|
if (!foundFl) // Try right rear corner
|
||||||
|
for (foundFl = true, *destx = x = obj->x + curImage->x2 - HERO_MAX_WIDTH + 1; x <= obj->x + (int16)curImage->x2; x++)
|
||||||
|
if (BOUND(x, y))
|
||||||
|
foundFl = false;
|
||||||
|
|
||||||
|
if (!foundFl) // Try left front corner
|
||||||
|
for (foundFl = true, y += 2, *destx = x = obj->x + curImage->x1; x < *destx + HERO_MAX_WIDTH; x++)
|
||||||
|
if (BOUND(x, y))
|
||||||
|
foundFl = false;
|
||||||
|
|
||||||
|
if (!foundFl) // Try right rear corner
|
||||||
|
for (foundFl = true, *destx = x = obj->x + curImage->x2 - HERO_MAX_WIDTH + 1; x <= obj->x + (int16)curImage->x2; x++)
|
||||||
|
if (BOUND(x, y))
|
||||||
|
foundFl = false;
|
||||||
|
|
||||||
|
*desty = y;
|
||||||
|
return(foundFl);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search background command list for this screen for supplied object.
|
||||||
|
// Return first associated verb (not "look") or NULL if none found.
|
||||||
|
char *HugoEngine::useBG(char *name) {
|
||||||
|
int i;
|
||||||
|
objectList_t p = _backgroundObjects[*_screen_p];
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "useBG(%s)", name);
|
||||||
|
|
||||||
|
for (i = 0; *_arrayVerbs[p[i].verbIndex]; i++)
|
||||||
|
if ((name == _arrayNouns[p[i].nounIndex][0] &&
|
||||||
|
p[i].verbIndex != _look) &&
|
||||||
|
((p[i].roomState == DONT_CARE) || (p[i].roomState == _screenStates[*_screen_p])))
|
||||||
|
return (_arrayVerbs[p[i].verbIndex][0]);
|
||||||
|
|
||||||
|
return (NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If status.objid = -1, pick up objid, else use status.objid on objid,
|
||||||
|
// if objid can't be picked up, use it directly
|
||||||
|
void HugoEngine::useObject(int16 objId) {
|
||||||
|
object_t *obj = &_objects[objId]; // Ptr to object
|
||||||
|
uses_t *use; // Ptr to use entry
|
||||||
|
target_t *target; // Ptr to target entry
|
||||||
|
bool foundFl; // TRUE if found target entry
|
||||||
|
char *verb; // Background verb to use directly
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "useObject(%d)", objId);
|
||||||
|
|
||||||
|
if (_status.inventoryObjId == -1) {
|
||||||
|
// Get or use objid directly
|
||||||
|
if ((obj->genericCmd & TAKE) || obj->objValue) // Get collectible item
|
||||||
|
sprintf(_line, "%s %s", _arrayVerbs[_take][0], _arrayNouns[obj->nounIndex][0]);
|
||||||
|
else if (obj->cmdIndex != 0) // Use non-collectible item if able
|
||||||
|
sprintf(_line, "%s %s", _arrayVerbs[_cmdList[obj->cmdIndex][1].verbIndex][0], _arrayNouns[obj->nounIndex][0]);
|
||||||
|
else if ((verb = useBG(_arrayNouns[obj->nounIndex][0])) != NULL)
|
||||||
|
sprintf(_line, "%s %s", verb, _arrayNouns[obj->nounIndex][0]);
|
||||||
|
else
|
||||||
|
return; // Can't use object directly
|
||||||
|
} else {
|
||||||
|
// Use status.objid on objid
|
||||||
|
// Default to first cmd verb
|
||||||
|
sprintf(_line, "%s %s %s", _arrayVerbs[_cmdList[_objects[_status.inventoryObjId].cmdIndex][1].verbIndex][0], _arrayNouns[_objects[_status.inventoryObjId].nounIndex][0], _arrayNouns[obj->nounIndex][0]);
|
||||||
|
|
||||||
|
// Check valid use of objects and override verb if necessary
|
||||||
|
for (use = _uses; use->objId != _numObj; use++)
|
||||||
|
if (_status.inventoryObjId == use->objId) {
|
||||||
|
// Look for secondary object, if found use matching verb
|
||||||
|
for (foundFl = false, target = use->targets; _arrayNouns[target->nounIndex] != NULL; target++)
|
||||||
|
if (_arrayNouns[target->nounIndex][0] == _arrayNouns[obj->nounIndex][0]) {
|
||||||
|
foundFl = true;
|
||||||
|
sprintf(_line, "%s %s %s", _arrayVerbs[target->verbIndex][0], _arrayNouns[_objects[_status.inventoryObjId].nounIndex][0], _arrayNouns[obj->nounIndex][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// No valid use of objects found, print failure string
|
||||||
|
if (!foundFl) {
|
||||||
|
// Deselect dragged icon if inventory not active
|
||||||
|
if (_status.inventoryState != I_ACTIVE)
|
||||||
|
_status.inventoryObjId = -1;
|
||||||
|
Utils::Box(BOX_ANY, HugoEngine::get()._textData[use->dataIndex]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_status.inventoryState == I_ACTIVE) // If inventory active, remove it
|
||||||
|
_status.inventoryState = I_UP;
|
||||||
|
_status.inventoryObjId = -1; // Deselect any dragged icon
|
||||||
|
parser().lineHandler(); // and process command
|
||||||
|
}
|
||||||
|
|
||||||
|
// Issue "Look at <object>" command
|
||||||
|
// Note special case of swapped hero image
|
||||||
|
void HugoEngine::lookObject(object_t *obj) {
|
||||||
|
debugC(1, kDebugEngine, "lookObject");
|
||||||
|
|
||||||
|
if (obj == _hero) {
|
||||||
|
// Hero swapped - look at other
|
||||||
|
obj = &_objects[_heroImage];
|
||||||
|
}
|
||||||
|
parser().command("%s %s", _arrayVerbs[_look][0], _arrayNouns[obj->nounIndex][0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Free all object images
|
||||||
|
void HugoEngine::freeObjects() {
|
||||||
|
object_t *obj;
|
||||||
|
seq_t *seq;
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "freeObjects");
|
||||||
|
|
||||||
|
// Nothing to do if not allocated yet
|
||||||
|
if (_hero->seqList[0].seqPtr == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Free all sequence lists and image data
|
||||||
|
for (int i = 0; i < _numObj; i++) {
|
||||||
|
obj = &_objects[i];
|
||||||
|
for (int j = 0; j < obj->seqNumb; j++) { // for each sequence
|
||||||
|
seq = obj->seqList[j].seqPtr; // Free image
|
||||||
|
if (seq == NULL) // Failure during database load
|
||||||
|
break;
|
||||||
|
do {
|
||||||
|
free(seq->imagePtr);
|
||||||
|
seq = seq->nextSeqPtr;
|
||||||
|
} while (seq != obj->seqList[j].seqPtr);
|
||||||
|
free(seq); // Free sequence record
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add action lists for this screen to event queue
|
||||||
|
void HugoEngine::screenActions(int screenNum) {
|
||||||
|
uint16 *screenAct = _screenActs[screenNum];
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "screenActions(%d)", screenNum);
|
||||||
|
|
||||||
|
if (screenAct) {
|
||||||
|
for (int i = 0; screenAct[i]; i++)
|
||||||
|
HugoEngine::get().scheduler().insertActionList(screenAct[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the new screen number into the hero object and any carried objects
|
||||||
|
void HugoEngine::setNewScreen(int screenNum) {
|
||||||
|
debugC(1, kDebugEngine, "setNewScreen(%d)", screenNum);
|
||||||
|
|
||||||
|
*_screen_p = screenNum; // HERO object
|
||||||
|
for (int i = HERO + 1; i < _numObj; i++) // Any others
|
||||||
|
if (_objects[i].carriedFl) // being carried
|
||||||
|
_objects[i].screenIndex = screenNum;
|
||||||
|
}
|
||||||
|
|
||||||
|
// An object has collided with a boundary. See if any actions are required
|
||||||
|
void HugoEngine::boundaryCollision(object_t *obj) {
|
||||||
|
int x, y, dx, dy;
|
||||||
|
char radius; // 8 bits signed
|
||||||
|
hotspot_t *hotspot;
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "boundaryCollision");
|
||||||
|
|
||||||
|
if (obj == _hero) {
|
||||||
|
// Hotspots only relevant to HERO
|
||||||
|
if (obj->vx > 0)
|
||||||
|
x = obj->x + obj->currImagePtr->x2;
|
||||||
|
else
|
||||||
|
x = obj->x + obj->currImagePtr->x1;
|
||||||
|
y = obj->y + obj->currImagePtr->y2;
|
||||||
|
|
||||||
|
for (int i = 0; _hotspots[i].screenIndex >= 0; i++) {
|
||||||
|
hotspot = &_hotspots[i];
|
||||||
|
if (hotspot->screenIndex == obj->screenIndex)
|
||||||
|
if ((x >= hotspot->x1) && (x <= hotspot->x2) && (y >= hotspot->y1) && (y <= hotspot->y2)) {
|
||||||
|
HugoEngine::get().scheduler().insertActionList(hotspot->actIndex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Check whether an object collided with HERO
|
||||||
|
dx = _hero->x + _hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1;
|
||||||
|
dy = _hero->y + _hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2;
|
||||||
|
// If object's radius is infinity, use a closer value
|
||||||
|
radius = obj->radius;
|
||||||
|
if (radius < 0)
|
||||||
|
radius = DX * 2;
|
||||||
|
if ((abs(dx) <= radius) && (abs(dy) <= radius))
|
||||||
|
HugoEngine::get().scheduler().insertActionList(obj->actIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize screen components and display results
|
||||||
|
void HugoEngine::initNewScreenDisplay() {
|
||||||
|
debugC(1, kDebugEngine, "initNewScreenDisplay");
|
||||||
|
|
||||||
|
screen().displayList(D_INIT);
|
||||||
|
screen().setBackgroundColor(_TBLACK);
|
||||||
|
screen().displayBackground();
|
||||||
|
|
||||||
|
// Stop premature object display in Display_list(D_DISPLAY)
|
||||||
|
_status.newScreenFl = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add up all the object values and all the bonus points
|
||||||
|
void HugoEngine::calcMaxScore() {
|
||||||
|
int i;
|
||||||
|
|
||||||
|
debugC(1, kDebugEngine, "calcMaxScore");
|
||||||
|
|
||||||
|
for (i = 0; i < _numObj; i++)
|
||||||
|
_maxscore += _objects[i].objValue;
|
||||||
|
|
||||||
|
for (i = 0; i < _numBonuses; i++)
|
||||||
|
_maxscore += _points[i].score;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit game, advertise trilogy, show copyright
|
||||||
|
void HugoEngine::endGame() {
|
||||||
|
debugC(1, kDebugEngine, "endGame");
|
||||||
|
|
||||||
|
if (!_boot.registered)
|
||||||
|
Utils::Box(BOX_ANY, HugoEngine::get()._textEngine[kEsAdvertise]);
|
||||||
|
Utils::Box(BOX_ANY, "%s\n%s", _episode, COPYRIGHT);
|
||||||
|
_status.viewState = V_EXIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
43
engines/hugo/engine.h
Executable file
43
engines/hugo/engine.h
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo 1-3 Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_ENGINE_H
|
||||||
|
#define HUGO_ENGINE_H
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
enum seqTextEngine {
|
||||||
|
// Strings used by the engine
|
||||||
|
kEsAdvertise = 0
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif // HUGO_ENGINE_H
|
924
engines/hugo/file.cpp
Executable file
924
engines/hugo/file.cpp
Executable file
|
@ -0,0 +1,924 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
#include "common/savefile.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/global.h"
|
||||||
|
#include "hugo/schedule.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
FileManager::FileManager(HugoEngine &vm) : _vm(vm) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
byte *FileManager::convertPCC(byte *p, uint16 y, uint16 bpl, image_pt dataPtr) {
|
||||||
|
// Convert 4 planes (RGBI) data to 8-bit DIB format
|
||||||
|
// Return original plane data ptr
|
||||||
|
uint16 r, g, b, i; // Byte index within each plane
|
||||||
|
char bit; // Bit index within a byte
|
||||||
|
|
||||||
|
debugC(2, kDebugFile, "convertPCC(byte *p, %d, %d, image_pt data_p)", y, bpl);
|
||||||
|
|
||||||
|
dataPtr += y * bpl * 8; // Point to correct DIB line
|
||||||
|
for (r = 0, g = bpl, b = g + bpl, i = b + bpl; r < bpl; r++, g++, b++, i++) // Each byte in all planes
|
||||||
|
for (bit = 7; bit >= 0; bit--) // Each bit in byte
|
||||||
|
*dataPtr++ = (((p[r] >> bit & 1) << 0) |
|
||||||
|
((p[g] >> bit & 1) << 1) |
|
||||||
|
((p[b] >> bit & 1) << 2) |
|
||||||
|
((p[i] >> bit & 1) << 3));
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
seq_t *FileManager::readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool firstFl, const char *name) {
|
||||||
|
// Read a pcx file of length len. Use supplied seq_p and image_p or
|
||||||
|
// allocate space if NULL. Name used for errors. Returns address of seq_p
|
||||||
|
// Set first TRUE to initialize b_index (i.e. not reading a sequential image in file).
|
||||||
|
|
||||||
|
struct { // Structure of PCX file header
|
||||||
|
byte mfctr, vers, enc, bpx;
|
||||||
|
uint16 x1, y1, x2, y2; // bounding box
|
||||||
|
uint16 xres, yres;
|
||||||
|
byte palette[48]; // EGA color palette
|
||||||
|
byte vmode, planes;
|
||||||
|
uint16 bytesPerLine; // Bytes per line
|
||||||
|
byte fill2[60];
|
||||||
|
} PCC_header; // Header of a PCC file
|
||||||
|
|
||||||
|
byte c, d; // code and data bytes from PCX file
|
||||||
|
byte pline[XPIX]; // Hold 4 planes of data
|
||||||
|
byte *p = pline; // Ptr to above
|
||||||
|
byte i; // PCX repeat count
|
||||||
|
uint16 bytesPerLine4; // BPL in 4-bit format
|
||||||
|
uint16 size; // Size of image
|
||||||
|
uint16 y = 0; // Current line index
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "readPCX(..., %s)", name);
|
||||||
|
|
||||||
|
// Read in the PCC header and check consistency
|
||||||
|
PCC_header.mfctr = f.readByte();
|
||||||
|
PCC_header.vers = f.readByte();
|
||||||
|
PCC_header.enc = f.readByte();
|
||||||
|
PCC_header.bpx = f.readByte();
|
||||||
|
PCC_header.x1 = f.readUint16LE();
|
||||||
|
PCC_header.y1 = f.readUint16LE();
|
||||||
|
PCC_header.x2 = f.readUint16LE();
|
||||||
|
PCC_header.y2 = f.readUint16LE();
|
||||||
|
PCC_header.xres = f.readUint16LE();
|
||||||
|
PCC_header.yres = f.readUint16LE();
|
||||||
|
f.read(PCC_header.palette, sizeof(PCC_header.palette));
|
||||||
|
PCC_header.vmode = f.readByte();
|
||||||
|
PCC_header.planes = f.readByte();
|
||||||
|
PCC_header.bytesPerLine = f.readUint16LE();
|
||||||
|
f.read(PCC_header.fill2, sizeof(PCC_header.fill2));
|
||||||
|
|
||||||
|
if (PCC_header.mfctr != 10)
|
||||||
|
Utils::Error(PCCH_ERR, name);
|
||||||
|
|
||||||
|
// Allocate memory for seq_t if NULL
|
||||||
|
if (seqPtr == NULL)
|
||||||
|
if ((seqPtr = (seq_t *)malloc(sizeof(seq_t))) == NULL)
|
||||||
|
Utils::Error(HEAP_ERR, name);
|
||||||
|
|
||||||
|
// Find size of image data in 8-bit DIB format
|
||||||
|
// Note save of x2 - marks end of valid data before garbage
|
||||||
|
bytesPerLine4 = PCC_header.bytesPerLine * 4; // 4-bit bpl
|
||||||
|
seqPtr->bytesPerLine8 = bytesPerLine4 * 2; // 8-bit bpl
|
||||||
|
seqPtr->lines = PCC_header.y2 - PCC_header.y1 + 1;
|
||||||
|
seqPtr->x2 = PCC_header.x2 - PCC_header.x1 + 1;
|
||||||
|
size = seqPtr->lines * seqPtr->bytesPerLine8;
|
||||||
|
|
||||||
|
// Allocate memory for image data if NULL
|
||||||
|
if (imagePtr == NULL)
|
||||||
|
if ((imagePtr = (byte *)malloc((size_t) size)) == NULL)
|
||||||
|
Utils::Error(HEAP_ERR, name);
|
||||||
|
seqPtr->imagePtr = imagePtr;
|
||||||
|
|
||||||
|
// Process the image data, converting to 8-bit DIB format
|
||||||
|
while (y < seqPtr->lines) {
|
||||||
|
c = f.readByte();
|
||||||
|
if ((c & REP_MASK) == REP_MASK) {
|
||||||
|
d = f.readByte(); // Read data byte
|
||||||
|
for (i = 0; i < (c & LEN_MASK); i++) {
|
||||||
|
*p++ = d;
|
||||||
|
if ((uint16)(p - pline) == bytesPerLine4)
|
||||||
|
p = convertPCC(pline, y++, PCC_header.bytesPerLine, imagePtr);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
*p++ = c;
|
||||||
|
if ((uint16)(p - pline) == bytesPerLine4)
|
||||||
|
p = convertPCC(pline, y++, PCC_header.bytesPerLine, imagePtr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seqPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::readImage(int objNum, object_t *objPtr) {
|
||||||
|
// Read object file of PCC images into object supplied
|
||||||
|
byte x, y, j, k;
|
||||||
|
uint16 x2; // Limit on x in image data
|
||||||
|
seq_t *seqPtr; // Ptr to sequence structure
|
||||||
|
image_pt dibPtr; // Ptr to DIB data
|
||||||
|
objBlock_t objBlock; // Info on file within database
|
||||||
|
bool firstFl = true; // Initializes pcx read function
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "readImage(%d, object_t *objPtr)", objNum);
|
||||||
|
|
||||||
|
if (!objPtr->seqNumb) // This object has no images
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (_vm.isPacked()) {
|
||||||
|
_objectsArchive.seek((uint32)objNum * sizeof(objBlock_t), SEEK_SET);
|
||||||
|
|
||||||
|
objBlock.objOffset = _objectsArchive.readUint32LE();
|
||||||
|
objBlock.objLength = _objectsArchive.readUint32LE();
|
||||||
|
|
||||||
|
_objectsArchive.seek(objBlock.objOffset, SEEK_SET);
|
||||||
|
} else {
|
||||||
|
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
|
||||||
|
strcat(strcat(strcpy(buf, _vm._picDir), _vm._arrayNouns[objPtr->nounIndex][0]), OBJEXT);
|
||||||
|
if (!_objectsArchive.open(buf)) {
|
||||||
|
warning("File %s not found, trying again with %s%s", buf, _vm._arrayNouns[objPtr->nounIndex][0], OBJEXT);
|
||||||
|
strcat(strcpy(buf, _vm._arrayNouns[objPtr->nounIndex][0]), OBJEXT);
|
||||||
|
if (!_objectsArchive.open(buf))
|
||||||
|
Utils::Error(FILE_ERR, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now read the images into an images list
|
||||||
|
for (j = 0; j < objPtr->seqNumb; j++) { // for each sequence
|
||||||
|
for (k = 0; k < objPtr->seqList[j].imageNbr; k++) { // each image
|
||||||
|
if (k == 0) { // First image
|
||||||
|
// Read this image - allocate both seq and image memory
|
||||||
|
seqPtr = readPCX(_objectsArchive, NULL, NULL, firstFl, _vm._arrayNouns[objPtr->nounIndex][0]);
|
||||||
|
objPtr->seqList[j].seqPtr = seqPtr;
|
||||||
|
firstFl = false;
|
||||||
|
} else { // Subsequent image
|
||||||
|
// Read this image - allocate both seq and image memory
|
||||||
|
seqPtr->nextSeqPtr = readPCX(_objectsArchive, NULL, NULL, firstFl, _vm._arrayNouns[objPtr->nounIndex][0]);
|
||||||
|
seqPtr = seqPtr->nextSeqPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute the bounding box - x1, x2, y1, y2
|
||||||
|
// Note use of x2 - marks end of valid data in row
|
||||||
|
x2 = seqPtr->x2;
|
||||||
|
seqPtr->x1 = seqPtr->x2;
|
||||||
|
seqPtr->x2 = 0;
|
||||||
|
seqPtr->y1 = seqPtr->lines;
|
||||||
|
seqPtr->y2 = 0;
|
||||||
|
dibPtr = seqPtr->imagePtr;
|
||||||
|
for (y = 0; y < seqPtr->lines; y++, dibPtr += seqPtr->bytesPerLine8 - x2)
|
||||||
|
for (x = 0; x < x2; x++)
|
||||||
|
if (*dibPtr++) { // Some data found
|
||||||
|
if (x < seqPtr->x1)
|
||||||
|
seqPtr->x1 = x;
|
||||||
|
if (x > seqPtr->x2)
|
||||||
|
seqPtr->x2 = x;
|
||||||
|
if (y < seqPtr->y1)
|
||||||
|
seqPtr->y1 = y;
|
||||||
|
if (y > seqPtr->y2)
|
||||||
|
seqPtr->y2 = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
seqPtr->nextSeqPtr = objPtr->seqList[j].seqPtr; // loop linked list to head
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the current image sequence to first or last
|
||||||
|
switch (objPtr->cycling) {
|
||||||
|
case INVISIBLE: // (May become visible later)
|
||||||
|
case ALMOST_INVISIBLE:
|
||||||
|
case NOT_CYCLING:
|
||||||
|
case CYCLE_FORWARD:
|
||||||
|
objPtr->currImagePtr = objPtr->seqList[0].seqPtr;
|
||||||
|
break;
|
||||||
|
case CYCLE_BACKWARD:
|
||||||
|
objPtr->currImagePtr = seqPtr;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_vm.isPacked())
|
||||||
|
_objectsArchive.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::readBackground(int screenIndex) {
|
||||||
|
// Read a PCX image into dib_a
|
||||||
|
seq_t seq; // Image sequence structure for Read_pcx
|
||||||
|
sceneBlock_t sceneBlock; // Read a database header entry
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "readBackground(%d)", screenIndex);
|
||||||
|
|
||||||
|
if (_vm.isPacked()) {
|
||||||
|
_sceneryArchive.seek((uint32) screenIndex * sizeof(sceneBlock_t), SEEK_SET);
|
||||||
|
|
||||||
|
sceneBlock.scene_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.scene_len = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.b_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.b_len = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.o_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.o_len = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.ob_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.ob_len = _sceneryArchive.readUint32LE();
|
||||||
|
|
||||||
|
_sceneryArchive.seek(sceneBlock.scene_off, SEEK_SET);
|
||||||
|
} else {
|
||||||
|
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
|
||||||
|
strcat(strcat(strcpy(buf, _vm._picDir), _vm._screenNames[screenIndex]), BKGEXT);
|
||||||
|
if (!_sceneryArchive.open(buf)) {
|
||||||
|
warning("File %s not found, trying again with %s.ART", buf, _vm._screenNames[screenIndex]);
|
||||||
|
strcat(strcpy(buf, _vm._screenNames[screenIndex]), ".ART");
|
||||||
|
if (!_sceneryArchive.open(buf))
|
||||||
|
Utils::Error(FILE_ERR, buf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read the image into dummy seq and static dib_a
|
||||||
|
readPCX(_sceneryArchive, &seq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||||
|
|
||||||
|
if (!_vm.isPacked())
|
||||||
|
_sceneryArchive.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
sound_pt FileManager::getSound(int16 sound, uint16 *size) {
|
||||||
|
// Read sound (or music) file data. Call with SILENCE to free-up
|
||||||
|
// any allocated memory. Also returns size of data
|
||||||
|
|
||||||
|
static sound_hdr_t s_hdr[MAX_SOUNDS]; // Sound lookup table
|
||||||
|
sound_pt soundPtr; // Ptr to sound data
|
||||||
|
Common::File fp; // Handle to SOUND_FILE
|
||||||
|
// bool music = sound < NUM_TUNES; // TRUE if music, else sound file
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "getSound(%d, %d)", sound, *size);
|
||||||
|
|
||||||
|
// No more to do if SILENCE (called for cleanup purposes)
|
||||||
|
if (sound == _vm._soundSilence)
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
|
// Open sounds file
|
||||||
|
if (!fp.open(SOUND_FILE)) {
|
||||||
|
// Error(FILE_ERR, SOUND_FILE);
|
||||||
|
warning("Hugo Error: File not found %s", SOUND_FILE);
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If this is the first call, read the lookup table
|
||||||
|
static bool has_read_header = false;
|
||||||
|
if (!has_read_header) {
|
||||||
|
if (fp.read(s_hdr, sizeof(s_hdr)) != sizeof(s_hdr))
|
||||||
|
Utils::Error(FILE_ERR, SOUND_FILE);
|
||||||
|
has_read_header = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*size = s_hdr[sound].size;
|
||||||
|
if (*size == 0)
|
||||||
|
Utils::Error(SOUND_ERR, SOUND_FILE);
|
||||||
|
|
||||||
|
// Allocate memory for sound or music, if possible
|
||||||
|
if ((soundPtr = (byte *)malloc(s_hdr[sound].size)) == 0) {
|
||||||
|
Utils::Warn(false, "Low on memory");
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Seek to data and read it
|
||||||
|
fp.seek(s_hdr[sound].offset, SEEK_SET);
|
||||||
|
if (fp.read(soundPtr, s_hdr[sound].size) != s_hdr[sound].size)
|
||||||
|
Utils::Error(FILE_ERR, SOUND_FILE);
|
||||||
|
|
||||||
|
fp.close();
|
||||||
|
|
||||||
|
return soundPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool FileManager::fileExists(char *filename) {
|
||||||
|
// Return whether file exists or not
|
||||||
|
Common::File f;
|
||||||
|
if (f.open(filename)) {
|
||||||
|
f.close();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
|
||||||
|
// Open and read in an overlay file, close file
|
||||||
|
uint32 i;
|
||||||
|
int16 j, k;
|
||||||
|
char data; // Must be 8 bits signed
|
||||||
|
image_pt tmpImage = image; // temp ptr to overlay file
|
||||||
|
sceneBlock_t sceneBlock; // Database header entry
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
|
||||||
|
|
||||||
|
if (_vm.isPacked()) {
|
||||||
|
_sceneryArchive.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET);
|
||||||
|
|
||||||
|
sceneBlock.scene_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.scene_len = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.b_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.b_len = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.o_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.o_len = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.ob_off = _sceneryArchive.readUint32LE();
|
||||||
|
sceneBlock.ob_len = _sceneryArchive.readUint32LE();
|
||||||
|
|
||||||
|
switch (overlayType) {
|
||||||
|
case BOUNDARY:
|
||||||
|
_sceneryArchive.seek(sceneBlock.b_off, SEEK_SET);
|
||||||
|
i = sceneBlock.b_len;
|
||||||
|
break;
|
||||||
|
case OVERLAY:
|
||||||
|
_sceneryArchive.seek(sceneBlock.o_off, SEEK_SET);
|
||||||
|
i = sceneBlock.o_len;
|
||||||
|
break;
|
||||||
|
case OVLBASE:
|
||||||
|
_sceneryArchive.seek(sceneBlock.ob_off, SEEK_SET);
|
||||||
|
i = sceneBlock.ob_len;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Utils::Error(FILE_ERR, "Bad ovl_type");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (i == 0) {
|
||||||
|
for (i = 0; i < OVL_SIZE; i++)
|
||||||
|
image[i] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const char *ovl_ext[] = {".b", ".o", ".ob"};
|
||||||
|
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
|
||||||
|
|
||||||
|
strcat(strcpy(buf, _vm._screenNames[screenNum]), ovl_ext[overlayType]);
|
||||||
|
|
||||||
|
if (!fileExists(buf)) {
|
||||||
|
for (i = 0; i < OVL_SIZE; i++)
|
||||||
|
image[i] = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_sceneryArchive.open(buf))
|
||||||
|
Utils::Error(FILE_ERR, buf);
|
||||||
|
|
||||||
|
// if (eof(f_scenery)) {
|
||||||
|
// _lclose(f_scenery);
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (_vm._gameVariant) {
|
||||||
|
case 0: // Hugo 1 DOS and WIN don't pack data
|
||||||
|
case 3:
|
||||||
|
_sceneryArchive.read(tmpImage, OVL_SIZE);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// Read in the overlay file using MAC Packbits. (We're not proud!)
|
||||||
|
k = 0; // byte count
|
||||||
|
do {
|
||||||
|
data = _sceneryArchive.readByte(); // Read a code byte
|
||||||
|
if ((byte)data == 0x80) // Noop
|
||||||
|
k = k;
|
||||||
|
else if (data >= 0) { // Copy next data+1 literally
|
||||||
|
for (i = 0; i <= (byte)data; i++, k++)
|
||||||
|
*tmpImage++ = _sceneryArchive.readByte();
|
||||||
|
} else { // Repeat next byte -data+1 times
|
||||||
|
j = _sceneryArchive.readByte();
|
||||||
|
|
||||||
|
for (i = 0; i < (byte)(-data + 1); i++, k++)
|
||||||
|
*tmpImage++ = j;
|
||||||
|
}
|
||||||
|
} while (k < OVL_SIZE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!_vm.isPacked())
|
||||||
|
_sceneryArchive.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::saveSeq(object_t *obj) {
|
||||||
|
// Save sequence number and image number in given object
|
||||||
|
byte j, k;
|
||||||
|
seq_t *q;
|
||||||
|
bool found;
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "saveSeq");
|
||||||
|
|
||||||
|
for (j = 0, found = false; !found && (j < obj->seqNumb); j++) {
|
||||||
|
q = obj->seqList[j].seqPtr;
|
||||||
|
for (k = 0; !found && (k < obj->seqList[j].imageNbr); k++) {
|
||||||
|
if (obj->currImagePtr == q) {
|
||||||
|
found = true;
|
||||||
|
obj->curSeqNum = j;
|
||||||
|
obj->curImageNum = k;
|
||||||
|
} else
|
||||||
|
q = q->nextSeqPtr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::restoreSeq(object_t *obj) {
|
||||||
|
// Set up cur_seq_p from stored sequence and image number in object
|
||||||
|
int j;
|
||||||
|
seq_t *q;
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "restoreSeq");
|
||||||
|
|
||||||
|
q = obj->seqList[obj->curSeqNum].seqPtr;
|
||||||
|
for (j = 0; j < obj->curImageNum; j++)
|
||||||
|
q = q->nextSeqPtr;
|
||||||
|
obj->currImagePtr = q;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::saveGame(int16 slot, const char *descrip) {
|
||||||
|
// Save game to supplied slot (-1 is INITFILE)
|
||||||
|
int i;
|
||||||
|
char path[256]; // Full path of saved game
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "saveGame(%d, %s)", slot, descrip);
|
||||||
|
|
||||||
|
// Get full path of saved game file - note test for INITFILE
|
||||||
|
if (slot == -1)
|
||||||
|
sprintf(path, "%s", _vm._initFilename);
|
||||||
|
else
|
||||||
|
sprintf(path, _vm._saveFilename, slot);
|
||||||
|
|
||||||
|
Common::WriteStream *out = 0;
|
||||||
|
if (!(out = _vm.getSaveFileManager()->openForSaving(path))) {
|
||||||
|
warning("Can't create file '%s', game not saved", path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write version. We can't restore from obsolete versions
|
||||||
|
out->write(&kSavegameVersion, sizeof(kSavegameVersion));
|
||||||
|
|
||||||
|
// Save description of saved game
|
||||||
|
out->write(descrip, DESCRIPLEN);
|
||||||
|
|
||||||
|
// Save objects
|
||||||
|
for (i = 0; i < _vm._numObj; i++) {
|
||||||
|
// Save where curr_seq_p is pointing to
|
||||||
|
saveSeq(&_vm._objects[i]);
|
||||||
|
out->write(&_vm._objects[i], sizeof(object_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
const status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
// Save whether hero image is swapped
|
||||||
|
out->write(&_vm._heroImage, sizeof(_vm._heroImage));
|
||||||
|
|
||||||
|
// Save score
|
||||||
|
int score = _vm.getScore();
|
||||||
|
out->write(&score, sizeof(score));
|
||||||
|
|
||||||
|
// Save story mode
|
||||||
|
out->write(&gameStatus.storyModeFl, sizeof(gameStatus.storyModeFl));
|
||||||
|
|
||||||
|
// Save jumpexit mode
|
||||||
|
out->write(&gameStatus.jumpExitFl, sizeof(gameStatus.jumpExitFl));
|
||||||
|
|
||||||
|
// Save gameover status
|
||||||
|
out->write(&gameStatus.gameOverFl, sizeof(gameStatus.gameOverFl));
|
||||||
|
|
||||||
|
// Save screen states
|
||||||
|
out->write(_vm._screenStates, sizeof(*_vm._screenStates) * _vm._numScreens);
|
||||||
|
|
||||||
|
// Save points table
|
||||||
|
out->write(_vm._points, sizeof(point_t) * _vm._numBonuses);
|
||||||
|
|
||||||
|
// Now save current time and all current events in event queue
|
||||||
|
_vm.scheduler().saveEvents(out);
|
||||||
|
|
||||||
|
// Save palette table
|
||||||
|
_vm.screen().savePal(out);
|
||||||
|
|
||||||
|
// Save maze status
|
||||||
|
out->write(&_maze, sizeof(maze_t));
|
||||||
|
|
||||||
|
out->finalize();
|
||||||
|
|
||||||
|
delete out;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::restoreGame(int16 slot) {
|
||||||
|
// Restore game from supplied slot number (-1 is INITFILE)
|
||||||
|
int i;
|
||||||
|
char path[256]; // Full path of saved game
|
||||||
|
object_t *p;
|
||||||
|
seqList_t seqList[MAX_SEQUENCES];
|
||||||
|
// cmdList *cmds; // Save command list pointer
|
||||||
|
uint16 cmdIndex; // Save command list pointer
|
||||||
|
// char ver[sizeof(VER)]; // Compare versions
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "restoreGame(%d)", slot);
|
||||||
|
|
||||||
|
// Initialize new-game status
|
||||||
|
_vm.initStatus();
|
||||||
|
|
||||||
|
// Get full path of saved game file - note test for INITFILE
|
||||||
|
if (slot == -1)
|
||||||
|
sprintf(path, "%s", _vm._initFilename);
|
||||||
|
else
|
||||||
|
sprintf(path, _vm._saveFilename, slot);
|
||||||
|
|
||||||
|
Common::SeekableReadStream *in = 0;
|
||||||
|
if (!(in = _vm.getSaveFileManager()->openForLoading(path)))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check version, can't restore from different versions
|
||||||
|
int saveVersion;
|
||||||
|
in->read(&saveVersion, sizeof(saveVersion));
|
||||||
|
if (saveVersion != kSavegameVersion) {
|
||||||
|
Utils::Error(GEN_ERR, "Savegame of incompatible version");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip over description
|
||||||
|
in->seek(DESCRIPLEN, SEEK_CUR);
|
||||||
|
|
||||||
|
// If hero image is currently swapped, swap it back before restore
|
||||||
|
if (_vm._heroImage != HERO)
|
||||||
|
_vm.scheduler().swapImages(HERO, _vm._heroImage);
|
||||||
|
|
||||||
|
// Restore objects, retain current seqList which points to dynamic mem
|
||||||
|
// Also, retain cmnd_t pointers
|
||||||
|
for (i = 0; i < _vm._numObj; i++) {
|
||||||
|
p = &_vm._objects[i];
|
||||||
|
memcpy(seqList, p->seqList, sizeof(seqList_t));
|
||||||
|
cmdIndex = p->cmdIndex;
|
||||||
|
in->read(p, sizeof(object_t));
|
||||||
|
p->cmdIndex = cmdIndex;
|
||||||
|
memcpy(p->seqList, seqList, sizeof(seqList_t));
|
||||||
|
}
|
||||||
|
|
||||||
|
in->read(&_vm._heroImage, sizeof(_vm._heroImage));
|
||||||
|
|
||||||
|
// If hero swapped in saved game, swap it
|
||||||
|
if ((i = _vm._heroImage) != HERO)
|
||||||
|
_vm.scheduler().swapImages(HERO, _vm._heroImage);
|
||||||
|
_vm._heroImage = i;
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
int score;
|
||||||
|
in->read(&score, sizeof(score));
|
||||||
|
_vm.setScore(score);
|
||||||
|
|
||||||
|
in->read(&gameStatus.storyModeFl, sizeof(gameStatus.storyModeFl));
|
||||||
|
in->read(&gameStatus.jumpExitFl, sizeof(gameStatus.jumpExitFl));
|
||||||
|
in->read(&gameStatus.gameOverFl, sizeof(gameStatus.gameOverFl));
|
||||||
|
in->read(_vm._screenStates, sizeof(*_vm._screenStates) * _vm._numScreens);
|
||||||
|
|
||||||
|
// Restore points table
|
||||||
|
in->read(_vm._points, sizeof(point_t) * _vm._numBonuses);
|
||||||
|
|
||||||
|
// Restore ptrs to currently loaded objects
|
||||||
|
for (i = 0; i < _vm._numObj; i++)
|
||||||
|
restoreSeq(&_vm._objects[i]);
|
||||||
|
|
||||||
|
// Now restore time of the save and the event queue
|
||||||
|
_vm.scheduler().restoreEvents(in);
|
||||||
|
|
||||||
|
// Restore palette and change it if necessary
|
||||||
|
_vm.screen().restorePal(in);
|
||||||
|
|
||||||
|
// Restore maze status
|
||||||
|
in->read(&_maze, sizeof(maze_t));
|
||||||
|
|
||||||
|
delete in;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::initSavedGame() {
|
||||||
|
// Initialize the size of a saved game (from the fixed initial game).
|
||||||
|
// If status.initsave is TRUE, or the initial saved game is not found,
|
||||||
|
// force a save to create one. Normally the game will be shipped with
|
||||||
|
// the initial game file but useful to force a write during development
|
||||||
|
// when the size is changeable.
|
||||||
|
// The net result is a valid INITFILE, with status.savesize initialized.
|
||||||
|
Common::File f; // Handle of saved game file
|
||||||
|
char path[256]; // Full path of INITFILE
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "initSavedGame");
|
||||||
|
|
||||||
|
// Get full path of INITFILE
|
||||||
|
sprintf(path, "%s", _vm._initFilename);
|
||||||
|
|
||||||
|
|
||||||
|
// Force save of initial game
|
||||||
|
if (_vm.getGameStatus().initSaveFl)
|
||||||
|
saveGame(-1, "");
|
||||||
|
|
||||||
|
// If initial game doesn't exist, create it
|
||||||
|
Common::SeekableReadStream *in = 0;
|
||||||
|
if (!(in = _vm.getSaveFileManager()->openForLoading(path))) {
|
||||||
|
saveGame(-1, "");
|
||||||
|
if (!(in = _vm.getSaveFileManager()->openForLoading(path))) {
|
||||||
|
Utils::Error(WRITE_ERR, path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Must have an open saved game now
|
||||||
|
_vm.getGameStatus().saveSize = in->size();
|
||||||
|
delete in;
|
||||||
|
|
||||||
|
// Check sanity - maybe disk full or path set to read-only drive?
|
||||||
|
if (_vm.getGameStatus().saveSize == -1)
|
||||||
|
Utils::Error(WRITE_ERR, path);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Record and playback handling stuff:
|
||||||
|
typedef struct {
|
||||||
|
// int key; // Character
|
||||||
|
uint32 time; // Time at which character was pressed
|
||||||
|
} pbdata_t;
|
||||||
|
static pbdata_t pbdata;
|
||||||
|
FILE *fpb;
|
||||||
|
|
||||||
|
void FileManager::openPlaybackFile(bool playbackFl, bool recordFl) {
|
||||||
|
debugC(1, kDebugFile, "openPlaybackFile(%d, %d)", (playbackFl) ? 1 : 0, (recordFl) ? 1 : 0);
|
||||||
|
|
||||||
|
if (playbackFl) {
|
||||||
|
if (!(fpb = fopen(PBFILE, "r+b")))
|
||||||
|
Utils::Error(FILE_ERR, PBFILE);
|
||||||
|
} else if (recordFl)
|
||||||
|
fpb = fopen(PBFILE, "wb");
|
||||||
|
pbdata.time = 0; // Say no key available
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::closePlaybackFile() {
|
||||||
|
fclose(fpb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::openDatabaseFiles() {
|
||||||
|
//TODO : HUGO 1 DOS uses _stringtData instead of a strings.dat
|
||||||
|
//This should be tested adequately and should be handled by an error and not by a warning.
|
||||||
|
debugC(1, kDebugFile, "openDatabaseFiles");
|
||||||
|
|
||||||
|
if (!_stringArchive.open(STRING_FILE))
|
||||||
|
// Error(FILE_ERR, STRING_FILE);
|
||||||
|
warning("Hugo Error: File not found %s", STRING_FILE);
|
||||||
|
if (_vm.isPacked()) {
|
||||||
|
if (!_sceneryArchive.open(SCENERY_FILE))
|
||||||
|
Utils::Error(FILE_ERR, SCENERY_FILE);
|
||||||
|
if (!_objectsArchive.open(OBJECTS_FILE))
|
||||||
|
Utils::Error(FILE_ERR, OBJECTS_FILE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::closeDatabaseFiles() {
|
||||||
|
// TODO: stringArchive shouldn't be closed in Hugo 1 DOS
|
||||||
|
debugC(1, kDebugFile, "closeDatabaseFiles");
|
||||||
|
|
||||||
|
_stringArchive.close();
|
||||||
|
if (_vm.isPacked()) {
|
||||||
|
_sceneryArchive.close();
|
||||||
|
_objectsArchive.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char *FileManager::fetchString(int index) {
|
||||||
|
//TODO : HUGO 1 DOS uses _stringtData instead of a strings.dat
|
||||||
|
// Fetch string from file, decode and return ptr to string in memory
|
||||||
|
uint32 off1, off2;
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "fetchString(%d)", index);
|
||||||
|
|
||||||
|
// Get offset to string[index] (and next for length calculation)
|
||||||
|
_stringArchive.seek((uint32)index * sizeof(uint32), SEEK_SET);
|
||||||
|
if (_stringArchive.read((char *)&off1, sizeof(uint32)) == 0)
|
||||||
|
Utils::Error(FILE_ERR, "String offset");
|
||||||
|
if (_stringArchive.read((char *)&off2, sizeof(uint32)) == 0)
|
||||||
|
Utils::Error(FILE_ERR, "String offset");
|
||||||
|
|
||||||
|
// Check size of string
|
||||||
|
if ((off2 - off1) >= MAX_BOX)
|
||||||
|
Utils::Error(FILE_ERR, "Fetched string too long!");
|
||||||
|
|
||||||
|
// Position to string and read it into gen purpose _textBoxBuffer
|
||||||
|
_stringArchive.seek(off1, SEEK_SET);
|
||||||
|
if (_stringArchive.read(_textBoxBuffer, (uint16)(off2 - off1)) == 0)
|
||||||
|
Utils::Error(FILE_ERR, "Fetch_string");
|
||||||
|
|
||||||
|
// Null terminate, decode and return it
|
||||||
|
_textBoxBuffer[off2-off1] = '\0';
|
||||||
|
_vm.scheduler().decodeString(_textBoxBuffer);
|
||||||
|
return _textBoxBuffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::printBootText() {
|
||||||
|
// Read the encrypted text from the boot file and print it
|
||||||
|
Common::File ofp;
|
||||||
|
int i;
|
||||||
|
char *buf;
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "printBootText");
|
||||||
|
|
||||||
|
if (!ofp.open(BOOTFILE))
|
||||||
|
Utils::Error(FILE_ERR, BOOTFILE);
|
||||||
|
|
||||||
|
// Allocate space for the text and print it
|
||||||
|
buf = (char *)malloc(_boot.exit_len + 1);
|
||||||
|
if (buf) {
|
||||||
|
// Skip over the boot structure (already read) and read exit text
|
||||||
|
ofp.seek((long)sizeof(_boot), SEEK_SET);
|
||||||
|
if (ofp.read(buf, _boot.exit_len) != (size_t)_boot.exit_len)
|
||||||
|
Utils::Error(FILE_ERR, BOOTFILE);
|
||||||
|
|
||||||
|
// Decrypt the exit text, using CRYPT substring
|
||||||
|
for (i = 0; i < _boot.exit_len; i++)
|
||||||
|
buf[i] ^= CRYPT[i % strlen(CRYPT)];
|
||||||
|
|
||||||
|
buf[i] = '\0';
|
||||||
|
//Box(BOX_OK, buf_p);
|
||||||
|
//MessageBox(hwnd, buf_p, "License", MB_ICONINFORMATION);
|
||||||
|
warning("printBootText(): License: %s", buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
ofp.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::readBootFile() {
|
||||||
|
// Reads boot file for program environment. Fatal error if not there or
|
||||||
|
// file checksum is bad. De-crypts structure while checking checksum
|
||||||
|
byte checksum;
|
||||||
|
byte *p;
|
||||||
|
Common::File ofp;
|
||||||
|
uint32 i;
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "readBootFile");
|
||||||
|
|
||||||
|
if (!ofp.open(BOOTFILE))
|
||||||
|
Utils::Error(FILE_ERR, BOOTFILE);
|
||||||
|
|
||||||
|
if (ofp.size() < (int32)sizeof(_boot))
|
||||||
|
Utils::Error(FILE_ERR, BOOTFILE);
|
||||||
|
|
||||||
|
_boot.checksum = ofp.readByte();
|
||||||
|
_boot.registered = ofp.readByte();
|
||||||
|
ofp.read(_boot.pbswitch, sizeof(_boot.pbswitch));
|
||||||
|
ofp.read(_boot.distrib, sizeof(_boot.distrib));
|
||||||
|
_boot.exit_len = ofp.readUint16LE();
|
||||||
|
|
||||||
|
p = (byte *)&_boot;
|
||||||
|
for (i = 0, checksum = 0; i < sizeof(_boot); i++) {
|
||||||
|
checksum ^= p[i];
|
||||||
|
p[i] ^= CRYPT[i % strlen(CRYPT)];
|
||||||
|
}
|
||||||
|
ofp.close();
|
||||||
|
|
||||||
|
if (checksum)
|
||||||
|
Utils::Error(GEN_ERR, "Program startup file invalid");
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::readConfig() {
|
||||||
|
// Read the user's config if it exists
|
||||||
|
Common::File f;
|
||||||
|
fpath_t path;
|
||||||
|
config_t tmpConfig = _config;
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "readConfig");
|
||||||
|
|
||||||
|
sprintf(path, "%s%s", _vm.getGameStatus().path, CONFIGFILE);
|
||||||
|
if (f.open(path)) {
|
||||||
|
// If config format changed, ignore it and use defaults
|
||||||
|
if (f.read(&_config, sizeof(_config)) != sizeof(_config))
|
||||||
|
_config = tmpConfig;
|
||||||
|
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::writeConfig() {
|
||||||
|
// Write the user's config
|
||||||
|
FILE *f;
|
||||||
|
fpath_t path;
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "writeConfig");
|
||||||
|
|
||||||
|
// Write user's config
|
||||||
|
// No error checking in case CD-ROM with no alternate path specified
|
||||||
|
sprintf(path, "%s%s", _vm.getGameStatus().path, CONFIGFILE);
|
||||||
|
if ((f = fopen(path, "w+")) != NULL)
|
||||||
|
fwrite(&_config, sizeof(_config), 1, f);
|
||||||
|
|
||||||
|
fclose(f);
|
||||||
|
}
|
||||||
|
|
||||||
|
uif_hdr_t *FileManager::getUIFHeader(uif_t id) {
|
||||||
|
// Returns address of uif_hdr[id], reading it in if first call
|
||||||
|
static uif_hdr_t UIFHeader[MAX_UIFS]; // Lookup for uif fonts/images
|
||||||
|
static bool firstFl = true;
|
||||||
|
Common::File ip; // Image data file
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "getUIFHeader(%d)", id);
|
||||||
|
|
||||||
|
// Initialize offset lookup if not read yet
|
||||||
|
if (firstFl) {
|
||||||
|
firstFl = false;
|
||||||
|
// Open unbuffered to do far read
|
||||||
|
if (!ip.open(UIF_FILE))
|
||||||
|
Utils::Error(FILE_ERR, UIF_FILE);
|
||||||
|
|
||||||
|
if (ip.size() < (int32)sizeof(UIFHeader))
|
||||||
|
Utils::Error(FILE_ERR, UIF_FILE);
|
||||||
|
|
||||||
|
for (int i = 0; i < MAX_UIFS; ++i) {
|
||||||
|
UIFHeader[i].size = ip.readUint16LE();
|
||||||
|
UIFHeader[i].offset = ip.readUint32LE();
|
||||||
|
}
|
||||||
|
|
||||||
|
ip.close();
|
||||||
|
}
|
||||||
|
return &UIFHeader[id];
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::readUIFItem(int16 id, byte *buf) {
|
||||||
|
// Read uif item into supplied buffer.
|
||||||
|
Common::File ip; // UIF_FILE handle
|
||||||
|
uif_hdr_t *UIFHeaderPtr; // Lookup table of items
|
||||||
|
seq_t seq; // Dummy seq_t for image data
|
||||||
|
|
||||||
|
debugC(1, kDebugFile, "readUIFItem(%d, ...)", id);
|
||||||
|
|
||||||
|
// Open uif file to read data
|
||||||
|
if (!ip.open(UIF_FILE))
|
||||||
|
Utils::Error(FILE_ERR, UIF_FILE);
|
||||||
|
|
||||||
|
// Seek to data
|
||||||
|
UIFHeaderPtr = getUIFHeader((uif_t)id);
|
||||||
|
ip.seek(UIFHeaderPtr->offset, SEEK_SET);
|
||||||
|
|
||||||
|
// We support pcx images and straight data
|
||||||
|
switch (id) {
|
||||||
|
case UIF_IMAGES: // Read uif images file
|
||||||
|
readPCX(ip, &seq, buf, true, UIF_FILE);
|
||||||
|
break;
|
||||||
|
default: // Read file data into supplied array
|
||||||
|
if (ip.read(buf, UIFHeaderPtr->size) != UIFHeaderPtr->size)
|
||||||
|
Utils::Error(FILE_ERR, UIF_FILE);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ip.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FileManager::instructions() {
|
||||||
|
// Simple instructions given when F1 pressed twice in a row
|
||||||
|
// Only in DOS versions
|
||||||
|
#define HELPFILE "help.dat"
|
||||||
|
#define EOP '#' /* Marks end of a page in help file */
|
||||||
|
|
||||||
|
Common::File f;
|
||||||
|
char line[1024], *wrkLine;
|
||||||
|
char readBuf[2];
|
||||||
|
|
||||||
|
wrkLine = line;
|
||||||
|
if (!f.open(UIF_FILE))
|
||||||
|
Utils::Error(FILE_ERR, HELPFILE);
|
||||||
|
|
||||||
|
while (f.read(readBuf, 1)) {
|
||||||
|
wrkLine[0] = readBuf[0];
|
||||||
|
do {
|
||||||
|
f.read(wrkLine, 1);
|
||||||
|
} while (*wrkLine++ != EOP);
|
||||||
|
wrkLine[-2] = '\0'; /* Remove EOP and previous CR */
|
||||||
|
Utils::Box(BOX_ANY, line);
|
||||||
|
f.read(wrkLine, 1); /* Remove CR after EOP */
|
||||||
|
}
|
||||||
|
f.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
86
engines/hugo/file.h
Executable file
86
engines/hugo/file.h
Executable file
|
@ -0,0 +1,86 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_FILE_H
|
||||||
|
#define HUGO_FILE_H
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
class FileManager {
|
||||||
|
public:
|
||||||
|
FileManager(HugoEngine &vm);
|
||||||
|
|
||||||
|
|
||||||
|
bool fileExists(char *filename);
|
||||||
|
|
||||||
|
char *fetchString(int index);
|
||||||
|
|
||||||
|
sound_pt getSound(short sound, uint16 *size);
|
||||||
|
|
||||||
|
void closePlaybackFile();
|
||||||
|
void closeDatabaseFiles();
|
||||||
|
void initSavedGame();
|
||||||
|
void instructions();
|
||||||
|
void openDatabaseFiles();
|
||||||
|
void readBackground(int screenIndex);
|
||||||
|
void readBootFile();
|
||||||
|
void readConfig();
|
||||||
|
void readImage(int objNum, object_t *objPtr);
|
||||||
|
void readOverlay(int screenNum, image_pt image, ovl_t overlayType);
|
||||||
|
void readUIFItem(short id, byte *buf);
|
||||||
|
void restoreGame(short slot);
|
||||||
|
void restoreSeq(object_t *obj);
|
||||||
|
void saveGame(short slot, const char *descrip);
|
||||||
|
void saveSeq(object_t *obj);
|
||||||
|
void writeConfig();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
|
||||||
|
Common::File _stringArchive; /* Handle for string file */
|
||||||
|
Common::File _sceneryArchive; /* Handle for scenery file */
|
||||||
|
Common::File _objectsArchive; /* Handle for objects file */
|
||||||
|
|
||||||
|
byte *convertPCC(byte *p, uint16 y, uint16 bpl, image_pt data_p);
|
||||||
|
seq_t *readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool firstFl, const char *name);
|
||||||
|
uif_hdr_t *getUIFHeader(uif_t id);
|
||||||
|
|
||||||
|
//Strangerke : Not used?
|
||||||
|
void openPlaybackFile(bool playbackFl, bool recordFl);
|
||||||
|
void printBootText();
|
||||||
|
// bool pkkey();
|
||||||
|
// char pbget();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif //HUGO_FILE_H
|
880
engines/hugo/game.h
Executable file
880
engines/hugo/game.h
Executable file
|
@ -0,0 +1,880 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_GAME_H
|
||||||
|
#define HUGO_GAME_H
|
||||||
|
|
||||||
|
#include "common/keyboard.h"
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
class WriteStream;
|
||||||
|
class SeekableReadStream;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
// WARNING!! Run the program at least once before release to
|
||||||
|
// generate the initial save file! (Using the -i cmd switch)
|
||||||
|
// Set EPISODE_NUM & build. Build pictures.mak and run "Tools/Hugo N".
|
||||||
|
// Copy helpedit\hugow_?.hlp to .\hugowin?.hlp
|
||||||
|
// Type "PPG" in the game to enter cheat mode.
|
||||||
|
|
||||||
|
#define DEBUG false // Allow me to do special things (EDIT, GOTO)
|
||||||
|
#define STORY true // Skip any intro stuff if FALSE
|
||||||
|
//#define DATABASE TRUE // Use database instead of individual files. Individual files are used by Hugo1 DOS!
|
||||||
|
//#define BETA FALSE // Puts big msg in intro/about box
|
||||||
|
#define EPISODE_NUM 1 // Episode we are building
|
||||||
|
#define TITLE "Hugo for Windows"
|
||||||
|
#define COPYRIGHT "Copyright © 1995-97, David P. Gray"
|
||||||
|
// Started code on 04/01/95
|
||||||
|
// Don't forget to update Hugowin.rc2 with version info
|
||||||
|
//#define VER "1.0" // 10/01/95 Initial Release
|
||||||
|
//#define VER "1.1" // 10/06/95 Restore system volume levels on exit
|
||||||
|
//#define VER "v1.2"// 10/12/95 Added "background music" checkbox in volume dlg
|
||||||
|
//#define VER "v1.3"// 10/23/95 Support game 1 as shareware
|
||||||
|
//#define VER "v1.4"// 12/06/95 Faster graphics, logical palette
|
||||||
|
#define VER "v1.5" // 10/07/97 Added order form, new web site
|
||||||
|
|
||||||
|
// Game specific equates
|
||||||
|
#define MAX_TUNES 16 // Max number of tunes
|
||||||
|
#define NORMAL_TPS 9 // Number of ticks (frames) per second
|
||||||
|
#define TURBO_TPS 16 // This many in turbo mode
|
||||||
|
#define DX 5 // Num pixels moved in x by HERO per step
|
||||||
|
#define DY 4 // Num pixels moved in y by HERO per step
|
||||||
|
#define XBYTES 40 // number of bytes in a compressed line
|
||||||
|
#define XPIX 320 // Width of pcx background file
|
||||||
|
#define YPIX 200 // Height of pcx background file
|
||||||
|
#define VIEW_DX XPIX // Width of window view
|
||||||
|
#define VIEW_DY 184 // Height of window view
|
||||||
|
#define INV_DX 32 // Width of an inventory icon
|
||||||
|
#define INV_DY 32 // Height of inventory icon
|
||||||
|
#define DIBOFF_Y 8 // Offset into dib SrcY (old status line area)
|
||||||
|
#define OVL_SIZE (XBYTES * YPIX) // Size of an overlay file
|
||||||
|
#define MAX_SEQUENCES 4 // Number of sequences of images in object
|
||||||
|
#define MAX_CHARS (XBYTES - 2) // Max length of user input line
|
||||||
|
#define NUM_ROWS 25 // Number of text lines in display
|
||||||
|
#define MAX_BOX (MAX_CHARS * NUM_ROWS) // Max chars on screen
|
||||||
|
#define DONT_CARE 0xFF // Any state allowed in command verb
|
||||||
|
#define MAX_FPATH 256 // Max length of a full path name
|
||||||
|
#define HERO_MAX_WIDTH 24 // Maximum width of hero
|
||||||
|
#define HERO_MIN_WIDTH 16 // Minimum width of hero
|
||||||
|
#define LOOK_NAME 1 // Index of name used in showing takeables
|
||||||
|
#define TAKE_NAME 2 // Index of name used in confirming take
|
||||||
|
#define TAKE_TEXT "Picked up the %s ok."
|
||||||
|
#define REP_MASK 0xC0 // Top 2 bits mean a repeat code
|
||||||
|
#define MAX_STRLEN 1024
|
||||||
|
#define WARNLEN 512
|
||||||
|
#define ERRLEN 512
|
||||||
|
#define STEP_DY 8 // Pixels per step movement
|
||||||
|
|
||||||
|
// Only for non-database
|
||||||
|
#define BKGEXT ".PCX" // Extension of background files
|
||||||
|
#define OBJEXT ".PIX" // Extension of object picture files
|
||||||
|
#define NAME_LEN 12 // Max length of a DOS file name
|
||||||
|
|
||||||
|
// Definitions of 'generic' commands: Max # depends on size of gencmd in
|
||||||
|
// the object_t record since each requires 1 bit. Currently up to 16
|
||||||
|
#define LOOK 1
|
||||||
|
#define TAKE 2
|
||||||
|
#define DROP 4
|
||||||
|
#define LOOK_S 8 // Description depends on state of object
|
||||||
|
|
||||||
|
// Macros:
|
||||||
|
#define TPS (_config.turboFl ? TURBO_TPS : NORMAL_TPS)
|
||||||
|
|
||||||
|
|
||||||
|
enum TEXTCOLORS {
|
||||||
|
_TBLACK, _TBLUE, _TGREEN, _TCYAN,
|
||||||
|
_TRED, _TMAGENTA, _TBROWN, _TWHITE,
|
||||||
|
_TGRAY, _TLIGHTBLUE, _TLIGHTGREEN, _TLIGHTCYAN,
|
||||||
|
_TLIGHTRED, _TLIGHTMAGENTA, _TLIGHTYELLOW, _TBRIGHTWHITE
|
||||||
|
};
|
||||||
|
|
||||||
|
#define CRYPT "Copyright 1992, David P Gray, Gray Design Associates"
|
||||||
|
|
||||||
|
struct hugo_boot_t { // Common HUGO boot file
|
||||||
|
char checksum; // Checksum for boot structure (not exit text)
|
||||||
|
char registered; // TRUE if registered version, else FALSE
|
||||||
|
char pbswitch[8]; // Playback switch string
|
||||||
|
char distrib[32]; // Distributor branding string
|
||||||
|
uint16 exit_len; // Length of exit text (next in file)
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_UIFS 32 // Max possible uif items in hdr
|
||||||
|
#define NUM_FONTS 3 // Number of dib fonts
|
||||||
|
#define FIRST_FONT U_FONT5
|
||||||
|
#define FONT_LEN 128 // Number of chars in font
|
||||||
|
#define FONTSIZE 1200 // Max size of font data
|
||||||
|
|
||||||
|
struct uif_hdr_t { // UIF font/image look up
|
||||||
|
uint16 size; // Size of uif item
|
||||||
|
uint32 offset; // Offset of item in file
|
||||||
|
};
|
||||||
|
|
||||||
|
enum uif_t {U_FONT5, U_FONT6, U_FONT8, UIF_IMAGES, NUM_UIF_ITEMS};
|
||||||
|
|
||||||
|
// Game specific type definitions
|
||||||
|
typedef byte *image_pt; // ptr to an object image (sprite)
|
||||||
|
typedef byte *sound_pt; // ptr to sound (or music) data
|
||||||
|
|
||||||
|
// Enumerate overlay file types
|
||||||
|
enum ovl_t {BOUNDARY, OVERLAY, OVLBASE};
|
||||||
|
|
||||||
|
// Enumerate error types
|
||||||
|
enum {
|
||||||
|
GEN_ERR, FILE_ERR, WRITE_ERR, PCCH_ERR, HEAP_ERR, EVNT_ERR, SOUND_ERR
|
||||||
|
//MOUSE_ERR, VID_ERR, FONT_ERR, ARG_ERR, CHK_ERR, TIMER_ERR, VBX_ERR
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enumerate ways of cycling a sequence of frames
|
||||||
|
enum cycle_t {INVISIBLE, ALMOST_INVISIBLE, NOT_CYCLING, CYCLE_FORWARD, CYCLE_BACKWARD};
|
||||||
|
|
||||||
|
// Enumerate sequence index matching direction of travel
|
||||||
|
enum {RIGHT, LEFT, DOWN, _UP};
|
||||||
|
|
||||||
|
// Channel requirement during sound effect
|
||||||
|
enum stereo_t {BOTH_CHANNELS, RIGHT_CHANNEL, LEFT_CHANNEL};
|
||||||
|
|
||||||
|
// Priority for sound effect
|
||||||
|
enum priority_t {LOW_PRI, MED_PRI, HIGH_PRI};
|
||||||
|
|
||||||
|
// Enumerate the different path types for an object
|
||||||
|
enum path_t {
|
||||||
|
USER, // User has control of object via cursor keys
|
||||||
|
AUTO, // Computer has control, controlled by action lists
|
||||||
|
QUIET, // Computer has control and no commands allowed
|
||||||
|
CHASE, // Computer has control, object is chasing hero
|
||||||
|
CHASE2, // Same as CHASE, except keeps cycling when stationary
|
||||||
|
WANDER, // Computer has control, object is wandering randomly
|
||||||
|
WANDER2 // Same as WANDER, except keeps cycling when stationary
|
||||||
|
};
|
||||||
|
|
||||||
|
// Enumerate whether object is foreground, background or 'floating'
|
||||||
|
// If floating, HERO can collide with it and fore/back ground is determined
|
||||||
|
// by relative y-coord of object base. This is the general case.
|
||||||
|
// If fore or background, no collisions can take place and object is either
|
||||||
|
// behind or in front of all others, although can still be hidden by the
|
||||||
|
// the overlay plane. OVEROVL means the object is FLOATING (to other
|
||||||
|
// objects) but is never hidden by the overlay plane
|
||||||
|
enum {FOREGROUND, BACKGROUND, FLOATING, OVEROVL};
|
||||||
|
|
||||||
|
// Game view state machine
|
||||||
|
enum vstate_t {V_IDLE, V_INTROINIT, V_INTRO, V_PLAY, V_INVENT, V_EXIT};
|
||||||
|
|
||||||
|
enum font_t {LARGE_ROMAN, MED_ROMAN, NUM_GDI_FONTS, INIT_FONTS, DEL_FONTS};
|
||||||
|
|
||||||
|
// Ways to dismiss a text/prompt box
|
||||||
|
enum box_t {BOX_ANY, BOX_OK, BOX_PROMPT, BOX_YESNO};
|
||||||
|
|
||||||
|
// Standard viewport sizes
|
||||||
|
enum wsize_t {SIZE_DEF, SIZE_1, SIZE_2, SIZE_3};
|
||||||
|
|
||||||
|
// Display list functions
|
||||||
|
enum dupdate_t {D_INIT, D_ADD, D_DISPLAY, D_RESTORE};
|
||||||
|
|
||||||
|
// General device installation commands
|
||||||
|
enum inst_t {INSTALL, RESTORE, RESET};
|
||||||
|
|
||||||
|
// Inventory icon bar states
|
||||||
|
enum istate_t {I_OFF, I_UP, I_DOWN, I_ACTIVE};
|
||||||
|
|
||||||
|
// Actions for Process_inventory()
|
||||||
|
enum invact_t {INV_INIT, INV_LEFT, INV_RIGHT, INV_GET};
|
||||||
|
|
||||||
|
// Purpose of an automatic route
|
||||||
|
enum go_t {GO_SPACE, GO_EXIT, GO_LOOK, GO_GET};
|
||||||
|
|
||||||
|
// Following are points for achieving certain actions.
|
||||||
|
struct point_t {
|
||||||
|
byte score; // The value of the point
|
||||||
|
bool scoredFl; // Whether scored yet
|
||||||
|
};
|
||||||
|
|
||||||
|
// Structure for initializing maze processing
|
||||||
|
struct maze_t {
|
||||||
|
bool enabledFl; // TRUE when maze processing enabled
|
||||||
|
byte size; // Size of (square) maze matrix
|
||||||
|
int x1, y1, x2, y2; // maze hotspot bounding box
|
||||||
|
int x3, x4; // north, south x entry coordinates
|
||||||
|
byte firstScreenIndex; // index of first screen in maze
|
||||||
|
};
|
||||||
|
|
||||||
|
// Following defines the action types and action list
|
||||||
|
enum action_t { // Parameters:
|
||||||
|
ANULL = 0xff, // Special NOP used to 'delete' events in DEL_EVENTS
|
||||||
|
ASCHEDULE = 0, // 0 - Ptr to action list to be rescheduled
|
||||||
|
START_OBJ, // 1 - Object number
|
||||||
|
INIT_OBJXY, // 2 - Object number, x,y
|
||||||
|
PROMPT, // 3 - index of prompt & response string, ptrs to action
|
||||||
|
// lists. First if response matches, 2nd if not.
|
||||||
|
BKGD_COLOR, // 4 - new background color
|
||||||
|
INIT_OBJVXY, // 5 - Object number, vx, vy
|
||||||
|
INIT_CARRY, // 6 - Object number, carried status
|
||||||
|
INIT_HF_COORD, // 7 - Object number (gets hero's 'feet' coordinates)
|
||||||
|
NEW_SCREEN, // 8 - New screen number
|
||||||
|
INIT_OBJSTATE, // 9 - Object number, new object state
|
||||||
|
INIT_PATH, // 10 - Object number, new path type
|
||||||
|
COND_R, // 11 - Conditional on object state - req state, 2 act_lists
|
||||||
|
TEXT, // 12 - Simple text box
|
||||||
|
SWAP_IMAGES, // 13 - Swap 2 object images
|
||||||
|
COND_SCR, // 14 - Conditional on current screen
|
||||||
|
AUTOPILOT, // 15 - Set object to home in on another (stationary) object
|
||||||
|
INIT_OBJ_SEQ, // 16 - Object number, sequence index to set curr_seq_p to
|
||||||
|
SET_STATE_BITS, // 17 - Objnum, mask to OR with obj states word
|
||||||
|
CLEAR_STATE_BITS, // 18 - Objnum, mask to ~AND with obj states word
|
||||||
|
TEST_STATE_BITS, // 19 - Objnum, mask to test obj states word
|
||||||
|
DEL_EVENTS, // 20 - Action type to delete all occurrences of
|
||||||
|
GAMEOVER, // 21 - Disable hero & commands. Game is over
|
||||||
|
INIT_HH_COORD, // 22 - Object number (gets hero's actual coordinates)
|
||||||
|
EXIT, // 23 - Exit game back to DOS
|
||||||
|
BONUS, // 24 - Get score bonus for an action
|
||||||
|
COND_BOX, // 25 - Conditional on object within bounding box
|
||||||
|
SOUND, // 26 - Set currently playing sound
|
||||||
|
ADD_SCORE, // 27 - Add object's value to current score
|
||||||
|
SUB_SCORE, // 28 - Subtract object's value from current score
|
||||||
|
COND_CARRY, // 29 - Conditional on carrying object
|
||||||
|
INIT_MAZE, // 30 - Start special maze hotspot processing
|
||||||
|
EXIT_MAZE, // 31 - Exit special maze processing
|
||||||
|
INIT_PRIORITY, // 32 - Initialize fbg field
|
||||||
|
INIT_SCREEN, // 33 - Initialise screen field of object
|
||||||
|
AGSCHEDULE, // 34 - Global schedule - lasts over new screen
|
||||||
|
REMAPPAL, // 35 - Remappe palette - palette index, color
|
||||||
|
COND_NOUN, // 36 - Conditional on noun appearing in line
|
||||||
|
SCREEN_STATE, // 37 - Set new screen state - used for comments
|
||||||
|
INIT_LIPS, // 38 - Position lips object for supplied object
|
||||||
|
INIT_STORY_MODE, // 39 - Set story mode TRUE/FALSE (user can't type)
|
||||||
|
WARN, // 40 - Same as TEXT but can't dismiss box by typing
|
||||||
|
COND_BONUS, // 41 - Conditional on bonus having been scored
|
||||||
|
TEXT_TAKE, // 42 - Issue text box with "take" info string
|
||||||
|
YESNO, // 43 - Prompt user for Yes or No
|
||||||
|
STOP_ROUTE, // 44 - Skip any route in progress (hero still walks)
|
||||||
|
COND_ROUTE, // 45 - Conditional on route in progress
|
||||||
|
INIT_JUMPEXIT, // 46 - Initialize status.jumpexit
|
||||||
|
INIT_VIEW, // 47 - Initialize viewx, viewy, dir
|
||||||
|
INIT_OBJ_FRAME, // 48 - Object number, seq,frame to set curr_seq_p to
|
||||||
|
OLD_SONG = 49 // Added by Strangerke - Set currently playing sound, old way: that is, using a string index instead of a reference in a file
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct act0 { // Type 0 - Schedule
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 actIndex; // Ptr to an action list
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act1 { // Type 1 - Start an object
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int cycleNumb; // Number of times to cycle
|
||||||
|
cycle_t cycle; // Direction to start cycling
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act2 { // Type 2 - Initialise an object coords
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int x, y; // Coordinates
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act3 { // Type 3 - Prompt user for text
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 promptIndex; // Index of prompt string
|
||||||
|
int *responsePtr; // Array of indexes to valid response
|
||||||
|
// string(s) (terminate list with -1)
|
||||||
|
uint16 actPassIndex; // Ptr to action list if success
|
||||||
|
uint16 actFailIndex; // Ptr to action list if failure
|
||||||
|
bool encodedFl; // (HUGO 1 DOS ONLY) Whether response is encoded or not
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act4 { // Type 4 - Set new background color
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
long newBackgroundColor; // New color
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act5 { // Type 5 - Initialise an object velocity
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int vx, vy; // velocity
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act6 { // Type 6 - Initialise an object carrying
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
bool carriedFl; // carrying
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act7 { // Type 7 - Initialise an object to hero's coords
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act8 { // Type 8 - switch to new screen
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int screenIndex; // The new screen number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act9 { // Type 9 - Initialise an object state
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
byte newState; // New state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act10 { // Type 10 - Initialise an object path type
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int newPathType; // New path type
|
||||||
|
char vxPath, vyPath; // Max delta velocities e.g. for CHASE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act11 { // Type 11 - Conditional on object's state
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
byte stateReq; // Required state
|
||||||
|
uint16 actPassIndex; // Ptr to action list if success
|
||||||
|
uint16 actFailIndex; // Ptr to action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act12 { // Type 12 - Simple text box
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int stringIndex; // Index (enum) of string in strings.dat
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act13 { // Type 13 - Swap first object image with second
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int obj1; // Index of first object
|
||||||
|
int obj2; // 2nd
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act14 { // Type 14 - Conditional on current screen
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The required object
|
||||||
|
int screenReq; // The required screen number
|
||||||
|
uint16 actPassIndex; // Ptr to action list if success
|
||||||
|
uint16 actFailIndex; // Ptr to action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act15 { // Type 15 - Home in on an object
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int obj1; // The object number homing in
|
||||||
|
int obj2; // The object number to home in on
|
||||||
|
char dx, dy; // Max delta velocities
|
||||||
|
};
|
||||||
|
// Note: Don't set a sequence at time 0 of a new screen, it causes
|
||||||
|
// problems clearing the boundary bits of the object! timer > 0 is safe
|
||||||
|
struct act16 { // Type 16 - Set curr_seq_p to seq
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int seqIndex; // The index of seq array to set to
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act17 { // Type 17 - SET obj individual state bits
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int stateMask; // The mask to OR with current obj state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act18 { // Type 18 - CLEAR obj individual state bits
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int stateMask; // The mask to ~AND with current obj state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act19 { // Type 19 - TEST obj individual state bits
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int stateMask; // The mask to AND with current obj state
|
||||||
|
uint16 actPassIndex; // Ptr to action list (all bits set)
|
||||||
|
uint16 actFailIndex; // Ptr to action list (not all set)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act20 { // Type 20 - Remove all events with this type of action
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
action_t actTypeDel; // The action type to remove
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act21 { // Type 21 - Gameover. Disable hero & commands
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act22 { // Type 22 - Initialise an object to hero's coords
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act23 { // Type 23 - Exit game back to DOS
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act24 { // Type 24 - Get bonus score
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int pointIndex; // Index into points array
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act25 { // Type 25 - Conditional on bounding box
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The required object number
|
||||||
|
int x1, y1, x2, y2; // The bounding box
|
||||||
|
uint16 actPassIndex; // Ptr to action list if success
|
||||||
|
uint16 actFailIndex; // Ptr to action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act26 { // Type 26 - Play a sound
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int16 soundIndex; // Sound index in data file
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act27 { // Type 27 - Add object's value to score
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act28 { // Type 28 - Subtract object's value from score
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act29 { // Type 29 - Conditional on object carried
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The required object number
|
||||||
|
uint16 actPassIndex; // Ptr to action list if success
|
||||||
|
uint16 actFailIndex; // Ptr to action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act30 { // Type 30 - Start special maze processing
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
byte mazeSize; // Size of (square) maze
|
||||||
|
int x1, y1, x2, y2; // Bounding box of maze
|
||||||
|
int x3, x4; // Extra x points for perspective correction
|
||||||
|
byte firstScreenIndex; // First (top left) screen of maze
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act31 { // Type 31 - Exit special maze processing
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act32 { // Type 32 - Init fbg field of object
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
byte priority; // Value of foreground/background field
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act33 { // Type 33 - Init screen field of object
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int screenIndex; // Screen number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act34 { // Type 34 - Global Schedule
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 actIndex; // Ptr to an action list
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act35 { // Type 35 - Remappe palette
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int16 oldColorIndex; // Old color index, 0..15
|
||||||
|
int16 newColorIndex; // New color index, 0..15
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act36 { // Type 36 - Conditional on noun mentioned
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 nounIndex; // The required noun (list)
|
||||||
|
uint16 actPassIndex; // Ptr to action list if success
|
||||||
|
uint16 actFailIndex; // Ptr to action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act37 { // Type 37 - Set new screen state
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int screenIndex; // The screen number
|
||||||
|
byte newState; // The new state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act38 { // Type 38 - Position lips
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int lipsObjNumb; // The LIPS object
|
||||||
|
int objNumb; // The object to speak
|
||||||
|
byte dxLips; // Relative offset of x
|
||||||
|
byte dyLips; // Relative offset of y
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act39 { // Type 39 - Init story mode
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
bool storyModeFl; // New state of story_mode flag
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act40 { // Type 40 - Unsolicited text box
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int stringIndex; // Index (enum) of string in strings.dat
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act41 { // Type 41 - Conditional on bonus scored
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int BonusIndex; // Index into bonus list
|
||||||
|
uint16 actPassIndex; // Index of the action list if scored for the first time
|
||||||
|
uint16 actFailIndex; // Index of the action list if already scored
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act42 { // Type 42 - Text box with "take" string
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object taken
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act43 { // Type 43 - Prompt user for Yes or No
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int promptIndex; // index of prompt string
|
||||||
|
uint16 actYesIndex; // Ptr to action list if YES
|
||||||
|
uint16 actNoIndex; // Ptr to action list if NO
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act44 { // Type 44 - Stop any route in progress
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act45 { // Type 45 - Conditional on route in progress
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int routeIndex; // Must be >= current status.rindex
|
||||||
|
uint16 actPassIndex; // Ptr to action list if en-route
|
||||||
|
uint16 actFailIndex; // Ptr to action list if not
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act46 { // Type 46 - Init status.jumpexit
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
bool jumpExitFl; // New state of jumpexit flag
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act47 { // Type 47 - Init viewx,viewy,dir
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object
|
||||||
|
int16 viewx; // object.viewx
|
||||||
|
int16 viewy; // object.viewy
|
||||||
|
int16 direction; // object.dir
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act48 { // Type 48 - Set curr_seq_p to frame n
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int seqIndex; // The index of seq array to set to
|
||||||
|
int frameIndex; // The index of frame to set to
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act49 { // Added by Strangerke - Type 79 - Play a sound (DOS way)
|
||||||
|
action_t actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 soundIndex; // Sound index in string array
|
||||||
|
};
|
||||||
|
|
||||||
|
union act {
|
||||||
|
act0 a0;
|
||||||
|
act1 a1;
|
||||||
|
act2 a2;
|
||||||
|
act3 a3;
|
||||||
|
act4 a4;
|
||||||
|
act5 a5;
|
||||||
|
act6 a6;
|
||||||
|
act7 a7;
|
||||||
|
act8 a8;
|
||||||
|
act9 a9;
|
||||||
|
act10 a10;
|
||||||
|
act11 a11;
|
||||||
|
act12 a12;
|
||||||
|
act13 a13;
|
||||||
|
act14 a14;
|
||||||
|
act15 a15;
|
||||||
|
act16 a16;
|
||||||
|
act17 a17;
|
||||||
|
act18 a18;
|
||||||
|
act19 a19;
|
||||||
|
act20 a20;
|
||||||
|
act21 a21;
|
||||||
|
act22 a22;
|
||||||
|
act23 a23;
|
||||||
|
act24 a24;
|
||||||
|
act25 a25;
|
||||||
|
act26 a26;
|
||||||
|
act27 a27;
|
||||||
|
act28 a28;
|
||||||
|
act29 a29;
|
||||||
|
act30 a30;
|
||||||
|
act31 a31;
|
||||||
|
act32 a32;
|
||||||
|
act33 a33;
|
||||||
|
act34 a34;
|
||||||
|
act35 a35;
|
||||||
|
act36 a36;
|
||||||
|
act37 a37;
|
||||||
|
act38 a38;
|
||||||
|
act39 a39;
|
||||||
|
act40 a40;
|
||||||
|
act41 a41;
|
||||||
|
act42 a42;
|
||||||
|
act43 a43;
|
||||||
|
act44 a44;
|
||||||
|
act45 a45;
|
||||||
|
act46 a46;
|
||||||
|
act47 a47;
|
||||||
|
act48 a48;
|
||||||
|
act49 a49;
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following determines how a verb is acted on, for an object
|
||||||
|
struct cmd {
|
||||||
|
uint16 verbIndex; // the verb
|
||||||
|
uint16 reqIndex; // ptr to list of required objects
|
||||||
|
uint16 textDataNoCarryIndex; // ptr to string if any of above not carried
|
||||||
|
byte reqState; // required state for verb to be done
|
||||||
|
byte newState; // new states if verb done
|
||||||
|
uint16 textDataWrongIndex; // ptr to string if wrong state
|
||||||
|
uint16 textDataDoneIndex; // ptr to string if verb done
|
||||||
|
uint16 actIndex; // Ptr to action list if verb done
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following is a linked list of images in an animation sequence
|
||||||
|
// The image data is in 8-bit DIB format, i.e. 1 byte = 1 pixel
|
||||||
|
struct seq_t { // Linked list of images
|
||||||
|
byte *imagePtr; // ptr to image
|
||||||
|
uint16 bytesPerLine8; // bytes per line (8bits)
|
||||||
|
uint16 lines; // lines
|
||||||
|
uint16 x1, x2, y1, y2; // Offsets from x,y: data bounding box
|
||||||
|
seq_t *nextSeqPtr; // ptr to next record
|
||||||
|
};
|
||||||
|
|
||||||
|
// The following is an array of structures of above sequences
|
||||||
|
struct seqList_t {
|
||||||
|
uint16 imageNbr; // Number of images in sequence
|
||||||
|
seq_t *seqPtr; // Ptr to sequence structure
|
||||||
|
};
|
||||||
|
|
||||||
|
// Following is definition of object attributes
|
||||||
|
struct object_t {
|
||||||
|
uint16 nounIndex; // String identifying object
|
||||||
|
uint16 dataIndex; // String describing the object
|
||||||
|
uint16 *stateDataIndex; // Added by Strangerke to handle the LOOK_S state-dependant descriptions
|
||||||
|
path_t pathType; // Describe path object follows
|
||||||
|
int vxPath, vyPath; // Delta velocities (e.g. for CHASE)
|
||||||
|
uint16 actIndex; // Action list to do on collision with hero
|
||||||
|
byte seqNumb; // Number of sequences in list
|
||||||
|
seq_t *currImagePtr; // Sequence image currently in use
|
||||||
|
seqList_t seqList[MAX_SEQUENCES]; // Array of sequence structure ptrs and lengths
|
||||||
|
cycle_t cycling; // Whether cycling, forward or backward
|
||||||
|
byte cycleNumb; // No. of times to cycle
|
||||||
|
byte frameInterval; // Interval (in ticks) between frames
|
||||||
|
byte frameTimer; // Decrementing timer for above
|
||||||
|
char radius; // Defines sphere of influence by hero
|
||||||
|
byte screenIndex; // Screen in which object resides
|
||||||
|
int x, y; // Current coordinates of object
|
||||||
|
int oldx, oldy; // Previous coordinates of object
|
||||||
|
char vx, vy; // Velocity
|
||||||
|
byte objValue; // Value of object
|
||||||
|
int genericCmd; // Bit mask of 'generic' commands for object
|
||||||
|
uint16 cmdIndex; // ptr to list of cmd structures for verbs
|
||||||
|
bool carriedFl; // TRUE if object being carried
|
||||||
|
byte state; // state referenced in cmd list
|
||||||
|
bool verbOnlyFl; // TRUE if verb-only cmds allowed e.g. sit,look
|
||||||
|
byte priority; // Whether object fore, background or floating
|
||||||
|
int16 viewx, viewy; // Position to view object from (or 0 or -1)
|
||||||
|
int16 direction; // Direction to view object from
|
||||||
|
byte curSeqNum; // Save which seq number currently in use
|
||||||
|
byte curImageNum; // Save which image of sequence currently in use
|
||||||
|
char oldvx; // Previous vx (used in wandering)
|
||||||
|
char oldvy; // Previous vy
|
||||||
|
};
|
||||||
|
|
||||||
|
// Following is structure of verbs and nouns for 'background' objects
|
||||||
|
// These are objects that appear in the various screens, but nothing
|
||||||
|
// interesting ever happens with them. Rather than just be dumb and say
|
||||||
|
// "don't understand" we produce an interesting msg to keep user sane.
|
||||||
|
struct background_t {
|
||||||
|
uint16 verbIndex;
|
||||||
|
uint16 nounIndex;
|
||||||
|
int commentIndex; // Index of comment produced on match
|
||||||
|
bool matchFl; // TRUE if noun must match when present
|
||||||
|
byte roomState; // "State" of room. Comments might differ.
|
||||||
|
byte bonusIndex; // Index of bonus score (0 = no bonus)
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef background_t *objectList_t;
|
||||||
|
|
||||||
|
typedef byte overlay_t[OVL_SIZE]; // Overlay file
|
||||||
|
typedef byte viewdib_t[(long)XPIX *YPIX]; // Viewport dib
|
||||||
|
typedef byte icondib_t[XPIX *INV_DY]; // Icon bar dib
|
||||||
|
|
||||||
|
typedef char command_t[MAX_CHARS + 8]; // Command line (+spare for prompt,cursor)
|
||||||
|
typedef char fpath_t[MAX_FPATH]; // File path
|
||||||
|
|
||||||
|
// Structure to define an EXIT or other collision-activated hotspot
|
||||||
|
struct hotspot_t {
|
||||||
|
int screenIndex; // Screen in which hotspot appears
|
||||||
|
int x1, y1, x2, y2; // Bounding box of hotspot
|
||||||
|
uint16 actIndex; // Actions to carry out if a 'hit'
|
||||||
|
int16 viewx, viewy, direction; // Used in auto-route mode
|
||||||
|
};
|
||||||
|
|
||||||
|
struct status_t { // Game status (not saved)
|
||||||
|
bool initSaveFl; // Force save of initial game
|
||||||
|
bool storyModeFl; // Game is telling story - no commands
|
||||||
|
bool gameOverFl; // Game is over - hero knobbled
|
||||||
|
bool playbackFl; // Game is in playback mode
|
||||||
|
bool recordFl; // Game is in record mode
|
||||||
|
bool demoFl; // Game is in demo mode
|
||||||
|
bool debugFl; // Game is in debug mode
|
||||||
|
bool textBoxFl; // Game is (halted) in text box
|
||||||
|
// Strangerke - Not used ?
|
||||||
|
// bool mmtimeFl; // Multimedia timer supported
|
||||||
|
bool lookFl; // Toolbar "look" button pressed
|
||||||
|
bool recallFl; // Toolbar "recall" button pressed
|
||||||
|
bool leftButtonFl; // Left mouse button pressed
|
||||||
|
bool rightButtonFl; // Right button pressed
|
||||||
|
bool newScreenFl; // New screen just loaded in dib_a
|
||||||
|
bool jumpExitFl; // Allowed to jump to a screen exit
|
||||||
|
bool godModeFl; // Allow DEBUG features in live version
|
||||||
|
bool helpFl; // Calling WinHelp (don't disable music)
|
||||||
|
uint32 tick; // Current time in ticks
|
||||||
|
uint32 saveTick; // Time of last save in ticks
|
||||||
|
vstate_t viewState; // View state machine
|
||||||
|
istate_t inventoryState; // Inventory icon bar state
|
||||||
|
int16 inventoryHeight; // Inventory icon bar height
|
||||||
|
int16 inventoryObjId; // Inventory object selected, or -1
|
||||||
|
int16 routeIndex; // Index into route list, or -1
|
||||||
|
go_t go_for; // Purpose of an automatic route
|
||||||
|
int16 go_id; // Index of exit of object walking to
|
||||||
|
fpath_t path; // Alternate path for saved files
|
||||||
|
long saveSize; // Size of a saved game
|
||||||
|
int16 saveSlot; // Current slot to save/restore game
|
||||||
|
int16 screenWidth; // Desktop screen width
|
||||||
|
int16 song; // Current song
|
||||||
|
int16 cx, cy; // Cursor position (dib coords)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct config_t { // User's config (saved)
|
||||||
|
bool musicFl; // State of Music button/menu item
|
||||||
|
bool soundFl; // State of Sound button/menu item
|
||||||
|
bool turboFl; // State of Turbo button/menu item
|
||||||
|
// int16 wx, wy; // Position of viewport
|
||||||
|
int16 cx, cy; // Size of viewport
|
||||||
|
bool backgroundMusicFl; // Continue music when task inactive
|
||||||
|
byte musicVolume; // Music volume percentage
|
||||||
|
byte soundVolume; // Sound volume percentage
|
||||||
|
bool playlist[MAX_TUNES]; // Tune playlist
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_t { // Secondary target for action
|
||||||
|
uint16 nounIndex; // Secondary object
|
||||||
|
uint16 verbIndex; // Action on secondary object
|
||||||
|
};
|
||||||
|
|
||||||
|
struct uses_t { // Define uses of certain objects
|
||||||
|
int16 objId; // Primary object
|
||||||
|
uint16 dataIndex; // String if no secondary object matches
|
||||||
|
target_t *targets; // List of secondary targets
|
||||||
|
};
|
||||||
|
|
||||||
|
// Global externs
|
||||||
|
extern config_t _config; // User's config
|
||||||
|
extern maze_t _maze; // Maze control structure
|
||||||
|
extern hugo_boot_t _boot; // Boot info structure
|
||||||
|
extern char _textBoxBuffer[]; // Useful box text buffer
|
||||||
|
extern command_t _line; // Line of user text input
|
||||||
|
|
||||||
|
/* Structure of scenery file lookup entry */
|
||||||
|
struct sceneBlock_t {
|
||||||
|
uint32 scene_off;
|
||||||
|
uint32 scene_len;
|
||||||
|
uint32 b_off;
|
||||||
|
uint32 b_len;
|
||||||
|
uint32 o_off;
|
||||||
|
uint32 o_len;
|
||||||
|
uint32 ob_off;
|
||||||
|
uint32 ob_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Structure of object file lookup entry */
|
||||||
|
struct objBlock_t {
|
||||||
|
uint32 objOffset;
|
||||||
|
uint32 objLength;
|
||||||
|
};
|
||||||
|
|
||||||
|
#include "common/pack-start.h" // START STRUCT PACKING
|
||||||
|
struct sound_hdr_t { // Sound file lookup entry
|
||||||
|
uint16 size; // Size of sound data in bytes
|
||||||
|
uint32 offset; // Offset of sound data in file
|
||||||
|
} PACKED_STRUCT;
|
||||||
|
#include "common/pack-end.h" // END STRUCT PACKING
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
55
engines/hugo/global.h
Executable file
55
engines/hugo/global.h
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define HERO 0 // In all enums, HERO is the first element
|
||||||
|
|
||||||
|
#define DESCRIPLEN 32 /* Length of description string */
|
||||||
|
#define MAX_SOUNDS 64 /* Max number of sounds */
|
||||||
|
#define BOOTFILE "HUGO.BSF" /* Name of boot structure file */
|
||||||
|
#define CONFIGFILE "CONFIG.DAT" /* Name of config file */
|
||||||
|
#define LEN_MASK 0x3F /* Lower 6 bits are length */
|
||||||
|
#define PBFILE "playback.dat"
|
||||||
|
|
||||||
|
/* Name scenery and objects picture databases */
|
||||||
|
#define SCENERY_FILE "scenery.dat"
|
||||||
|
#define OBJECTS_FILE "objects.dat"
|
||||||
|
#define STRING_FILE "strings.dat"
|
||||||
|
#define SOUND_FILE "sounds.dat"
|
||||||
|
|
||||||
|
/* User interface database (Windows Only) */
|
||||||
|
#define UIF_FILE "uif.dat"
|
||||||
|
|
||||||
|
static const int kSavegameVersion = 1;
|
||||||
|
} // Namespace Hugo
|
||||||
|
|
1446
engines/hugo/hugo.cpp
Executable file
1446
engines/hugo/hugo.cpp
Executable file
File diff suppressed because it is too large
Load diff
310
engines/hugo/hugo.h
Executable file
310
engines/hugo/hugo.h
Executable file
|
@ -0,0 +1,310 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_H
|
||||||
|
#define HUGO_H
|
||||||
|
|
||||||
|
#include "engines/engine.h"
|
||||||
|
#include "common/file.h"
|
||||||
|
|
||||||
|
// This include is here temporarily while the engine is being refactored.
|
||||||
|
#include "hugo/game.h"
|
||||||
|
|
||||||
|
#define HUGO_DAT_VER_MAJ 0 // 1 byte
|
||||||
|
#define HUGO_DAT_VER_MIN 16 // 1 byte
|
||||||
|
#define DATAALIGNMENT 4
|
||||||
|
|
||||||
|
namespace Common {
|
||||||
|
class RandomSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
enum GameType {
|
||||||
|
kGameTypeNone = 0,
|
||||||
|
kGameTypeHugo1,
|
||||||
|
kGameTypeHugo2,
|
||||||
|
kGameTypeHugo3
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HugoebugChannels {
|
||||||
|
kDebugSchedule = 1 << 0,
|
||||||
|
kDebugEngine = 1 << 1,
|
||||||
|
kDebugDisplay = 1 << 2,
|
||||||
|
kDebugMouse = 1 << 3,
|
||||||
|
kDebugParser = 1 << 4,
|
||||||
|
kDebugFile = 1 << 5,
|
||||||
|
kDebugRoute = 1 << 6,
|
||||||
|
kDebugInventory = 1 << 7
|
||||||
|
};
|
||||||
|
|
||||||
|
enum HugoGameFeatures {
|
||||||
|
GF_PACKED = (1 << 0) // Database
|
||||||
|
};
|
||||||
|
|
||||||
|
struct HugoGameDescription;
|
||||||
|
|
||||||
|
class FileManager;
|
||||||
|
class Scheduler;
|
||||||
|
class Screen;
|
||||||
|
class MouseHandler;
|
||||||
|
class InventoryHandler;
|
||||||
|
class Parser;
|
||||||
|
class Route;
|
||||||
|
class SoundHandler;
|
||||||
|
class IntroHandler;
|
||||||
|
|
||||||
|
class HugoEngine : public Engine {
|
||||||
|
public:
|
||||||
|
HugoEngine(OSystem *syst, const HugoGameDescription *gd);
|
||||||
|
~HugoEngine();
|
||||||
|
|
||||||
|
byte _numVariant;
|
||||||
|
byte _gameVariant;
|
||||||
|
byte _maxInvent;
|
||||||
|
byte _numBonuses;
|
||||||
|
byte _soundSilence;
|
||||||
|
byte _soundTest;
|
||||||
|
byte _tunesNbr;
|
||||||
|
uint16 _numScreens;
|
||||||
|
|
||||||
|
object_t *_hero;
|
||||||
|
byte *_screen_p;
|
||||||
|
byte _heroImage;
|
||||||
|
|
||||||
|
byte *_palette;
|
||||||
|
byte *_introX;
|
||||||
|
byte *_introY;
|
||||||
|
byte *_screenStates;
|
||||||
|
char **_textData;
|
||||||
|
char **_stringtData;
|
||||||
|
char **_screenNames;
|
||||||
|
char **_textEngine;
|
||||||
|
char **_textIntro;
|
||||||
|
char **_textMouse;
|
||||||
|
char **_textParser;
|
||||||
|
char **_textSchedule;
|
||||||
|
char **_textUtil;
|
||||||
|
char ***_arrayNouns;
|
||||||
|
char ***_arrayVerbs;
|
||||||
|
uint16 **_arrayReqs;
|
||||||
|
hotspot_t *_hotspots;
|
||||||
|
int16 *_invent;
|
||||||
|
uses_t *_uses;
|
||||||
|
background_t *_catchallList;
|
||||||
|
background_t **_backgroundObjects;
|
||||||
|
point_t *_points;
|
||||||
|
cmd **_cmdList;
|
||||||
|
uint16 **_screenActs;
|
||||||
|
object_t *_objects;
|
||||||
|
act **_actListArr;
|
||||||
|
int16 *_defltTunes;
|
||||||
|
uint16 _look;
|
||||||
|
uint16 _take;
|
||||||
|
uint16 _drop;
|
||||||
|
uint16 _numObj;
|
||||||
|
uint16 _alNewscrIndex;
|
||||||
|
|
||||||
|
Common::RandomSource *_rnd;
|
||||||
|
|
||||||
|
const char *_episode;
|
||||||
|
const char *_picDir;
|
||||||
|
|
||||||
|
char _initFilename[20];
|
||||||
|
char _saveFilename[20];
|
||||||
|
|
||||||
|
const HugoGameDescription *_gameDescription;
|
||||||
|
uint32 getFeatures() const;
|
||||||
|
|
||||||
|
GameType getGameType() const;
|
||||||
|
Common::Platform getPlatform() const;
|
||||||
|
bool isPacked() const;
|
||||||
|
|
||||||
|
// Temporary, until the engine is fully objectified.
|
||||||
|
static HugoEngine &get() {
|
||||||
|
assert(s_Engine != NULL);
|
||||||
|
return *s_Engine;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileManager &file() {
|
||||||
|
return *_fileManager;
|
||||||
|
}
|
||||||
|
Scheduler &scheduler() {
|
||||||
|
return *_scheduler;
|
||||||
|
}
|
||||||
|
Screen &screen() {
|
||||||
|
return *_screen;
|
||||||
|
}
|
||||||
|
MouseHandler &mouse() {
|
||||||
|
return *_mouseHandler;
|
||||||
|
}
|
||||||
|
InventoryHandler &inventory() {
|
||||||
|
return *_inventoryHandler;
|
||||||
|
}
|
||||||
|
Parser &parser() {
|
||||||
|
return *_parser;
|
||||||
|
}
|
||||||
|
Route &route() {
|
||||||
|
return *_route;
|
||||||
|
}
|
||||||
|
SoundHandler &sound() {
|
||||||
|
return *_soundHandler;
|
||||||
|
}
|
||||||
|
IntroHandler &intro() {
|
||||||
|
return *_introHandler;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initGame(const HugoGameDescription *gd);
|
||||||
|
void initGamePart(const HugoGameDescription *gd);
|
||||||
|
bool loadHugoDat();
|
||||||
|
|
||||||
|
int getMouseX() const {
|
||||||
|
return _mouseX;
|
||||||
|
}
|
||||||
|
int getMouseY() const {
|
||||||
|
return _mouseY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void initStatus();
|
||||||
|
void readObjectImages();
|
||||||
|
void readUIFImages();
|
||||||
|
void updateImages();
|
||||||
|
void moveObjects();
|
||||||
|
void useObject(int16 objId);
|
||||||
|
bool findObjectSpace(object_t *obj, int16 *destx, int16 *desty);
|
||||||
|
int16 findObject(uint16 x, uint16 y);
|
||||||
|
void lookObject(object_t *obj);
|
||||||
|
void storeBoundary(int x1, int x2, int y);
|
||||||
|
void clearBoundary(int x1, int x2, int y);
|
||||||
|
void endGame();
|
||||||
|
void readScreenFiles(int screen);
|
||||||
|
void setNewScreen(int screen);
|
||||||
|
void initNewScreenDisplay();
|
||||||
|
void screenActions(int screen);
|
||||||
|
void shutdown();
|
||||||
|
|
||||||
|
overlay_t &getBoundaryOverlay() {
|
||||||
|
return _boundary;
|
||||||
|
}
|
||||||
|
overlay_t &getObjectBoundaryOverlay() {
|
||||||
|
return _objBound;
|
||||||
|
}
|
||||||
|
overlay_t &getBaseBoundaryOverlay() {
|
||||||
|
return _ovlBase;
|
||||||
|
}
|
||||||
|
overlay_t &getFirstOverlay() {
|
||||||
|
return _overlay;
|
||||||
|
}
|
||||||
|
|
||||||
|
status_t &getGameStatus() {
|
||||||
|
return _status;
|
||||||
|
}
|
||||||
|
|
||||||
|
int getScore() const {
|
||||||
|
return _score;
|
||||||
|
}
|
||||||
|
void setScore(int newScore) {
|
||||||
|
_score = newScore;
|
||||||
|
}
|
||||||
|
void adjustScore(int adjustment) {
|
||||||
|
_score += adjustment;
|
||||||
|
}
|
||||||
|
int getMaxScore() const {
|
||||||
|
return _maxscore;
|
||||||
|
}
|
||||||
|
void setMaxScore(int newScore) {
|
||||||
|
_maxscore = newScore;
|
||||||
|
}
|
||||||
|
byte getIntroSize() {
|
||||||
|
return _introXSize;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
|
||||||
|
// Engine APIs
|
||||||
|
Common::Error run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
int _mouseX;
|
||||||
|
int _mouseY;
|
||||||
|
byte _paletteSize;
|
||||||
|
byte _introXSize;
|
||||||
|
status_t _status; // Game status structure
|
||||||
|
|
||||||
|
static HugoEngine *s_Engine;
|
||||||
|
|
||||||
|
// The following are bit plane display overlays which mark travel boundaries,
|
||||||
|
// foreground stationary objects and baselines for those objects (used to
|
||||||
|
// determine foreground/background wrt moving objects)
|
||||||
|
|
||||||
|
// Vinterstum: These shouldn't be static, but we get weird pathfinding issues (and Valgrind warnings) without.
|
||||||
|
// Needs more investigation. Alignment issues?
|
||||||
|
|
||||||
|
static overlay_t _boundary; // Boundary overlay file
|
||||||
|
static overlay_t _overlay; // First overlay file
|
||||||
|
static overlay_t _ovlBase; // First overlay base file
|
||||||
|
static overlay_t _objBound; // Boundary file marks object baselines
|
||||||
|
|
||||||
|
GameType _gameType;
|
||||||
|
Common::Platform _platform;
|
||||||
|
bool _packedFl;
|
||||||
|
|
||||||
|
FileManager *_fileManager;
|
||||||
|
Scheduler *_scheduler;
|
||||||
|
Screen *_screen;
|
||||||
|
MouseHandler *_mouseHandler;
|
||||||
|
InventoryHandler *_inventoryHandler;
|
||||||
|
Parser *_parser;
|
||||||
|
Route *_route;
|
||||||
|
SoundHandler *_soundHandler;
|
||||||
|
IntroHandler *_introHandler;
|
||||||
|
|
||||||
|
int _score; // Holds current score
|
||||||
|
int _maxscore; // Holds maximum score
|
||||||
|
|
||||||
|
char **loadTextsVariante(Common::File &in, uint16 *arraySize);
|
||||||
|
char ***loadTextsArray(Common::File &in);
|
||||||
|
uint16 **loadLongArray(Common::File &in);
|
||||||
|
char **loadTexts(Common::File &in);
|
||||||
|
void freeTexts(char **ptr);
|
||||||
|
|
||||||
|
void initPlaylist(bool playlist[MAX_TUNES]);
|
||||||
|
void initConfig(inst_t action);
|
||||||
|
void initialize();
|
||||||
|
int deltaX(int x1, int x2, int vx, int y);
|
||||||
|
int deltaY(int x1, int x2, int vy, int y);
|
||||||
|
void processMaze();
|
||||||
|
//int y2comp (const void *a, const void *b);
|
||||||
|
char *useBG(char *name);
|
||||||
|
void freeObjects();
|
||||||
|
void boundaryCollision(object_t *obj);
|
||||||
|
void calcMaxScore();
|
||||||
|
|
||||||
|
void initMachine();
|
||||||
|
void runMachine();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // End of namespace Hugo
|
||||||
|
|
||||||
|
#endif // Hugo_H
|
187
engines/hugo/intro.cpp
Executable file
187
engines/hugo/intro.cpp
Executable file
|
@ -0,0 +1,187 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/intro.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
IntroHandler::IntroHandler(HugoEngine &vm) : _vm(vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
IntroHandler::~IntroHandler() {
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_1w::intro_1w(HugoEngine &vm) : IntroHandler(_vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_1w::~intro_1w() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_1w::preNewGame() {
|
||||||
|
// Auto-start a new game
|
||||||
|
_vm.file().restoreGame(-1);
|
||||||
|
_vm.getGameStatus().viewState = V_INTROINIT;
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_1w::introInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intro_1w::introPlay() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_2w::intro_2w(HugoEngine &vm) : IntroHandler(_vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_2w::~intro_2w() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_2w::preNewGame() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_2w::introInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intro_2w::introPlay() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_3w::intro_3w(HugoEngine &vm) : IntroHandler(_vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_3w::~intro_3w() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_3w::preNewGame() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_3w::introInit() {
|
||||||
|
// Hugo 3 - show map and set up for introPlay()
|
||||||
|
//#if STORY
|
||||||
|
_vm.file().readBackground(INTRO_2_FILE);
|
||||||
|
_vm.screen().displayBackground();
|
||||||
|
introTicks = 0;
|
||||||
|
//#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intro_3w::introPlay() {
|
||||||
|
byte introSize = _vm.getIntroSize();
|
||||||
|
|
||||||
|
// Hugo 3 - Preamble screen before going into game. Draws path of Hugo's plane.
|
||||||
|
// Called every tick. Returns TRUE when complete
|
||||||
|
//TODO : Add proper check of story mode
|
||||||
|
//#if STORY
|
||||||
|
// SetBkMode(TRANSPARENT);
|
||||||
|
if (introTicks < introSize) {
|
||||||
|
// Scale viewport x_intro,y_intro to screen (offsetting y)
|
||||||
|
_vm.screen().writeChar(_vm._introX[introTicks], _vm._introY[introTicks] - DIBOFF_Y, 'x', _TBRIGHTWHITE);
|
||||||
|
|
||||||
|
// Text boxes at various times
|
||||||
|
switch (introTicks) {
|
||||||
|
case 4:
|
||||||
|
Utils::Box(BOX_OK, _vm._textIntro[kIntro1]);
|
||||||
|
break;
|
||||||
|
case 9:
|
||||||
|
Utils::Box(BOX_OK, _vm._textIntro[kIntro2]);
|
||||||
|
break;
|
||||||
|
case 35:
|
||||||
|
Utils::Box(BOX_OK, _vm._textIntro[kIntro3]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return (++introTicks >= introSize);
|
||||||
|
//#else //STORY
|
||||||
|
// return true;
|
||||||
|
//#endif //STORY
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_1d::intro_1d(HugoEngine &vm) : IntroHandler(_vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_1d::~intro_1d() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_1d::preNewGame() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_1d::introInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intro_1d::introPlay() {
|
||||||
|
warning("STUB: intro_1d::introPlay()");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//TODO : Add code for intro H2 DOS
|
||||||
|
intro_2d::intro_2d(HugoEngine &vm) : IntroHandler(_vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_2d::~intro_2d() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_2d::preNewGame() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_2d::introInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intro_2d::introPlay() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO : Add code for intro H3 DOS
|
||||||
|
intro_3d::intro_3d(HugoEngine &vm) : IntroHandler(_vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
intro_3d::~intro_3d() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_3d::preNewGame() {
|
||||||
|
}
|
||||||
|
|
||||||
|
void intro_3d::introInit() {
|
||||||
|
}
|
||||||
|
|
||||||
|
bool intro_3d::introPlay() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
|
130
engines/hugo/intro.h
Executable file
130
engines/hugo/intro.h
Executable file
|
@ -0,0 +1,130 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef INTRO_H
|
||||||
|
#define INTRO_H
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
// TODO : Remove this enum. Only used in Hugo 3w intro.
|
||||||
|
// Enumerate picture files. All screens must have an entry here, in order
|
||||||
|
enum screenid_3w {
|
||||||
|
CRASH, WEB, BRIDGE_3w, BRIDGE2, CLIFFTOP, WFALL,
|
||||||
|
WFALL_B, WBASE, STREAM_3w, STREAM2, PATH_UL, VILLAGE,
|
||||||
|
HUT_OUT, HUT_IN, GARDEN_3w, OLDMAN_3w, CLIFF, SLOPE,
|
||||||
|
CAMP, SUNSET, TURN, PLANE, MAP, PATH,
|
||||||
|
CAVE, FINTRO, NUM_PICS
|
||||||
|
};
|
||||||
|
#define INTRO_2_FILE MAP
|
||||||
|
|
||||||
|
enum seqTextIntro {
|
||||||
|
kIntro1 = 0,
|
||||||
|
kIntro2 = 1,
|
||||||
|
kIntro3 = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
class IntroHandler {
|
||||||
|
public:
|
||||||
|
IntroHandler(HugoEngine &vm);
|
||||||
|
virtual ~IntroHandler();
|
||||||
|
|
||||||
|
virtual void preNewGame() = 0;
|
||||||
|
virtual void introInit() = 0;
|
||||||
|
virtual bool introPlay() = 0;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
int16 introTicks; // Count calls to introPlay()
|
||||||
|
};
|
||||||
|
|
||||||
|
class intro_1w : public IntroHandler {
|
||||||
|
public:
|
||||||
|
intro_1w(HugoEngine &vm);
|
||||||
|
~intro_1w();
|
||||||
|
|
||||||
|
void preNewGame();
|
||||||
|
void introInit();
|
||||||
|
bool introPlay();
|
||||||
|
};
|
||||||
|
|
||||||
|
class intro_1d : public IntroHandler {
|
||||||
|
public:
|
||||||
|
intro_1d(HugoEngine &vm);
|
||||||
|
~intro_1d();
|
||||||
|
|
||||||
|
void preNewGame();
|
||||||
|
void introInit();
|
||||||
|
bool introPlay();
|
||||||
|
};
|
||||||
|
|
||||||
|
class intro_2w : public IntroHandler {
|
||||||
|
public:
|
||||||
|
intro_2w(HugoEngine &vm);
|
||||||
|
~intro_2w();
|
||||||
|
|
||||||
|
void preNewGame();
|
||||||
|
void introInit();
|
||||||
|
bool introPlay();
|
||||||
|
};
|
||||||
|
|
||||||
|
class intro_2d : public IntroHandler {
|
||||||
|
public:
|
||||||
|
intro_2d(HugoEngine &vm);
|
||||||
|
~intro_2d();
|
||||||
|
|
||||||
|
void preNewGame();
|
||||||
|
void introInit();
|
||||||
|
bool introPlay();
|
||||||
|
};
|
||||||
|
|
||||||
|
class intro_3w : public IntroHandler {
|
||||||
|
public:
|
||||||
|
intro_3w(HugoEngine &vm);
|
||||||
|
~intro_3w();
|
||||||
|
|
||||||
|
void preNewGame();
|
||||||
|
void introInit();
|
||||||
|
bool introPlay();
|
||||||
|
};
|
||||||
|
|
||||||
|
class intro_3d : public IntroHandler {
|
||||||
|
public:
|
||||||
|
intro_3d(HugoEngine &vm);
|
||||||
|
~intro_3d();
|
||||||
|
|
||||||
|
void preNewGame();
|
||||||
|
void introInit();
|
||||||
|
bool introPlay();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
} // Namespace Hugo
|
||||||
|
#endif
|
229
engines/hugo/inventory.cpp
Executable file
229
engines/hugo/inventory.cpp
Executable file
|
@ -0,0 +1,229 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/schedule.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/mouse.h"
|
||||||
|
#include "hugo/inventory.h"
|
||||||
|
#include "hugo/parser.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define MAX_DISP (XPIX / INV_DX) // Max icons displayable
|
||||||
|
|
||||||
|
InventoryHandler::InventoryHandler(HugoEngine &vm) : _vm(vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the inventory scrollbar in dib_i
|
||||||
|
// imageTotNumb is total number of inventory icons
|
||||||
|
// displayNumb is number requested for display
|
||||||
|
// scrollFl is TRUE if scroll arrows required
|
||||||
|
// firstObjId is index of first (scrolled) inventory object to display
|
||||||
|
void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, bool scrollFl, int16 firstObjId) {
|
||||||
|
int16 ux, uy, ix; // Coordinates of icons
|
||||||
|
|
||||||
|
debugC(1, kDebugInventory, "constructInventory(%d, %d, %d, %d)", imageTotNumb, displayNumb, (scrollFl) ? 0 : 1, firstObjId);
|
||||||
|
|
||||||
|
// Clear out icon buffer
|
||||||
|
memset(_vm.screen().getIconBuffer(), 0, sizeof(_vm.screen().getIconBuffer()));
|
||||||
|
|
||||||
|
// If needed, copy arrows - reduce number of icons displayable
|
||||||
|
if (scrollFl) { // Display at first and last icon positions
|
||||||
|
_vm.screen().moveImage(_vm.screen().getGUIBuffer(), 0, 0, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), 0, 0, XPIX);
|
||||||
|
_vm.screen().moveImage(_vm.screen().getGUIBuffer(), INV_DX, 0, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), INV_DX *(MAX_DISP - 1), 0, XPIX);
|
||||||
|
displayNumb = MIN(displayNumb, MAX_DISP - NUM_ARROWS);
|
||||||
|
} else // No, override first index - we can show 'em all!
|
||||||
|
firstObjId = 0;
|
||||||
|
|
||||||
|
// Copy inventory icons to remaining positions
|
||||||
|
int16 displayed = 0;
|
||||||
|
int16 carried = 0;
|
||||||
|
for (int16 i = 0; i < imageTotNumb; i++) {
|
||||||
|
if (_vm._objects[_vm._invent[i]].carriedFl) {
|
||||||
|
// Check still room to display and past first scroll index
|
||||||
|
if (displayed < displayNumb && carried >= firstObjId) {
|
||||||
|
// Compute source coordinates in dib_u
|
||||||
|
ux = (i + NUM_ARROWS) * INV_DX % XPIX;
|
||||||
|
uy = (i + NUM_ARROWS) * INV_DX / XPIX * INV_DY;
|
||||||
|
|
||||||
|
// Compute dest coordinates in dib_i
|
||||||
|
ix = ((scrollFl) ? displayed + 1 : displayed) * INV_DX;
|
||||||
|
displayed++; // Count number displayed
|
||||||
|
|
||||||
|
// Copy the icon
|
||||||
|
_vm.screen().moveImage(_vm.screen().getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm.screen().getIconBuffer(), ix, 0, XPIX);
|
||||||
|
}
|
||||||
|
carried++; // Count number carried
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process required action for inventory
|
||||||
|
// Returns objId under cursor (or -1) for INV_GET
|
||||||
|
int16 InventoryHandler::processInventory(invact_t action, ...) {
|
||||||
|
static int16 firstIconId = 0; // Index of first icon to display
|
||||||
|
int16 i, j;
|
||||||
|
int16 objId = -1; // Return objid under cursor
|
||||||
|
int16 imageNumb; // Total number of inventory items
|
||||||
|
int displayNumb; // Total number displayed/carried
|
||||||
|
int16 cursorx, cursory; // Current cursor position
|
||||||
|
bool scrollFl; // TRUE if scroll arrows needed
|
||||||
|
va_list marker; // Args used for D_ADD operation
|
||||||
|
|
||||||
|
debugC(1, kDebugInventory, "processInventory(invact_t action, ...)");
|
||||||
|
|
||||||
|
// Compute total number and number displayed, i.e. number carried
|
||||||
|
for (imageNumb = 0, displayNumb = 0; imageNumb < _vm._maxInvent && _vm._invent[imageNumb] != -1; imageNumb++)
|
||||||
|
if (_vm._objects[_vm._invent[imageNumb]].carriedFl)
|
||||||
|
displayNumb++;
|
||||||
|
|
||||||
|
// Will we need the scroll arrows?
|
||||||
|
scrollFl = displayNumb > MAX_DISP;
|
||||||
|
|
||||||
|
switch (action) {
|
||||||
|
case INV_INIT: // Initialize inventory display
|
||||||
|
constructInventory(imageNumb, displayNumb, scrollFl, firstIconId);
|
||||||
|
break;
|
||||||
|
case INV_LEFT: // Scroll left by one icon
|
||||||
|
firstIconId = MAX(0, firstIconId - 1);
|
||||||
|
constructInventory(imageNumb, displayNumb, scrollFl, firstIconId);
|
||||||
|
break;
|
||||||
|
case INV_RIGHT: // Scroll right by one icon
|
||||||
|
firstIconId = MIN(displayNumb, firstIconId + 1);
|
||||||
|
constructInventory(imageNumb, displayNumb, scrollFl, firstIconId);
|
||||||
|
break;
|
||||||
|
case INV_GET: // Return object id under cursor
|
||||||
|
// Get cursor position from variable argument list
|
||||||
|
va_start(marker, action); // Initialize variable arguments
|
||||||
|
cursorx = va_arg(marker, int); // Cursor x
|
||||||
|
cursory = va_arg(marker, int); // Cursor y
|
||||||
|
va_end(marker); // Reset variable arguments
|
||||||
|
|
||||||
|
cursory -= DIBOFF_Y; // Icon bar is at true zero
|
||||||
|
if (cursory > 0 && cursory < INV_DY) { // Within icon bar?
|
||||||
|
i = cursorx / INV_DX; // Compute icon index
|
||||||
|
if (scrollFl) // Scroll buttons displayed
|
||||||
|
if (i == 0) // Left scroll button
|
||||||
|
objId = LEFT_ARROW;
|
||||||
|
else {
|
||||||
|
if (i == MAX_DISP - 1) // Right scroll button
|
||||||
|
objId = RIGHT_ARROW;
|
||||||
|
else // Adjust for scroll
|
||||||
|
i += firstIconId - 1; // i is icon index
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not an arrow, find object id - limit to valid range
|
||||||
|
if (objId == -1 && i < displayNumb)
|
||||||
|
// Find objid by counting # carried objects == i+1
|
||||||
|
for (j = 0, i++; i > 0 && j < _vm._numObj; j++)
|
||||||
|
if (_vm._objects[j].carriedFl)
|
||||||
|
if (--i == 0)
|
||||||
|
objId = j;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return objId; // For the INV_GET action
|
||||||
|
}
|
||||||
|
|
||||||
|
void InventoryHandler::runInventory() {
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
debugC(1, kDebugInventory, "runInventory");
|
||||||
|
|
||||||
|
// Process inventory state machine
|
||||||
|
switch (gameStatus.inventoryState) {
|
||||||
|
case I_OFF: // Icon bar off screen
|
||||||
|
break;
|
||||||
|
case I_UP: // Icon bar moving up
|
||||||
|
gameStatus.inventoryHeight -= STEP_DY; // Move the icon bar up
|
||||||
|
if (gameStatus.inventoryHeight <= 0) // Limit travel
|
||||||
|
gameStatus.inventoryHeight = 0;
|
||||||
|
|
||||||
|
// Move visible portion to _frontBuffer, restore uncovered portion, display results
|
||||||
|
_vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX);
|
||||||
|
_vm.screen().moveImage(_vm.screen().getBackBufferBackup(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX, STEP_DY, XPIX, _vm.screen().getFrontBuffer(), 0, gameStatus.inventoryHeight + DIBOFF_Y, XPIX);
|
||||||
|
_vm.screen().displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight + STEP_DY);
|
||||||
|
|
||||||
|
if (gameStatus.inventoryHeight == 0) { // Finished moving up?
|
||||||
|
// Yes, restore dibs and exit back to game state machine
|
||||||
|
_vm.screen().moveImage(_vm.screen().getBackBufferBackup(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBuffer(), 0, 0, XPIX);
|
||||||
|
_vm.screen().moveImage(_vm.screen().getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getFrontBuffer(), 0, 0, XPIX);
|
||||||
|
_vm.updateImages(); // Add objects back into display list for restore
|
||||||
|
gameStatus.inventoryState = I_OFF;
|
||||||
|
gameStatus.viewState = V_PLAY;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case I_DOWN: // Icon bar moving down
|
||||||
|
// If this is the first step, initialize dib_i
|
||||||
|
// and get any icon/text out of _frontBuffer
|
||||||
|
if (gameStatus.inventoryHeight == 0) {
|
||||||
|
processInventory(INV_INIT); // Initialize dib_i
|
||||||
|
_vm.screen().displayList(D_RESTORE); // Restore _frontBuffer
|
||||||
|
_vm.updateImages(); // Rebuild _frontBuffer without icons/text
|
||||||
|
_vm.screen().displayList(D_DISPLAY); // Blit display list to screen
|
||||||
|
}
|
||||||
|
|
||||||
|
gameStatus.inventoryHeight += STEP_DY; // Move the icon bar down
|
||||||
|
if (gameStatus.inventoryHeight >= INV_DY) // Limit travel
|
||||||
|
gameStatus.inventoryHeight = INV_DY;
|
||||||
|
|
||||||
|
// Move visible portion to _frontBuffer, display results
|
||||||
|
_vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, gameStatus.inventoryHeight, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX);
|
||||||
|
_vm.screen().displayRect(0, DIBOFF_Y, XPIX, gameStatus.inventoryHeight);
|
||||||
|
|
||||||
|
if (gameStatus.inventoryHeight == INV_DY) { // Finished moving down?
|
||||||
|
// Yes, prepare view dibs for special inventory display since
|
||||||
|
// we can't refresh objects while icon bar overlayed...
|
||||||
|
// 1. Save backing store _backBuffer in temporary dib_c
|
||||||
|
// 2. Make snapshot of _frontBuffer the new _backBuffer backing store
|
||||||
|
// 3. Reset the display list
|
||||||
|
_vm.screen().moveImage(_vm.screen().getBackBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBufferBackup(), 0, 0, XPIX);
|
||||||
|
_vm.screen().moveImage(_vm.screen().getFrontBuffer(), 0, 0, XPIX, YPIX, XPIX, _vm.screen().getBackBuffer(), 0, 0, XPIX);
|
||||||
|
_vm.screen().displayList(D_INIT);
|
||||||
|
gameStatus.inventoryState = I_ACTIVE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case I_ACTIVE: // Inventory active
|
||||||
|
_vm.parser().charHandler(); // Still allow commands
|
||||||
|
_vm.screen().displayList(D_RESTORE); // Restore previous background
|
||||||
|
_vm.mouse().mouseHandler(); // Mouse activity - adds to display list
|
||||||
|
_vm.screen().displayList(D_DISPLAY); // Blit the display list to screen
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // End of namespace Hugo
|
55
engines/hugo/inventory.h
Executable file
55
engines/hugo/inventory.h
Executable file
|
@ -0,0 +1,55 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_INVENTORY_H
|
||||||
|
#define HUGO_INVENTORY_H
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define NUM_ARROWS 2 // Number of arrows (left/right)
|
||||||
|
#define LEFT_ARROW -2 // Cursor over Left arrow in inventory icon bar
|
||||||
|
#define RIGHT_ARROW -3 // Cursor over Right arrow in inventory icon bar
|
||||||
|
|
||||||
|
class InventoryHandler {
|
||||||
|
public:
|
||||||
|
InventoryHandler(HugoEngine &vm);
|
||||||
|
|
||||||
|
int16 processInventory(invact_t action, ...);
|
||||||
|
void runInventory();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
|
||||||
|
void constructInventory(int16 imageTotNumb, int displayNumb, bool scrollFl, int16 firstObjId);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif // HUGO_INVENTORY_H
|
24
engines/hugo/module.mk
Executable file
24
engines/hugo/module.mk
Executable file
|
@ -0,0 +1,24 @@
|
||||||
|
MODULE := engines/hugo
|
||||||
|
|
||||||
|
MODULE_OBJS := \
|
||||||
|
detection.o \
|
||||||
|
display.o \
|
||||||
|
engine.o \
|
||||||
|
file.o \
|
||||||
|
hugo.o \
|
||||||
|
intro.o \
|
||||||
|
inventory.o \
|
||||||
|
mouse.o \
|
||||||
|
parser.o \
|
||||||
|
route.o \
|
||||||
|
schedule.o \
|
||||||
|
sound.o \
|
||||||
|
util.o
|
||||||
|
|
||||||
|
# This module can be built as a plugin
|
||||||
|
ifeq ($(ENABLE_HUGO), DYNAMIC_PLUGIN)
|
||||||
|
PLUGIN := 1
|
||||||
|
endif
|
||||||
|
|
||||||
|
# Include common rules
|
||||||
|
include $(srcdir)/rules.mk
|
309
engines/hugo/mouse.cpp
Executable file
309
engines/hugo/mouse.cpp
Executable file
|
@ -0,0 +1,309 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// mouse.cpp : Handle all mouse activity
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/mouse.h"
|
||||||
|
#include "hugo/global.h"
|
||||||
|
#include "hugo/schedule.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/inventory.h"
|
||||||
|
#include "hugo/route.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define EXIT_HOTSPOT -4 // Cursor over Exit hotspot
|
||||||
|
#define CURSOR_NAME 2 // Index of name used under cursor
|
||||||
|
#define CURSOR_NOCHAR '~' // Don't show name of object under cursor
|
||||||
|
#define SX_OFF 10 // Cursor offset to name string
|
||||||
|
#define SY_OFF -2 // Cursor offset to name string
|
||||||
|
#define IX_OFF 8 // Cursor to icon image (dib coords)
|
||||||
|
#define IY_OFF 10 // Cursor to icon image (dib coords)
|
||||||
|
|
||||||
|
enum seqTextMouse {
|
||||||
|
kMsNoWayText = 0,
|
||||||
|
kMsExit = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
MouseHandler::MouseHandler(HugoEngine &vm) : _vm(vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shadow-blit supplied string into dib_a at cx,cy and add to display list
|
||||||
|
void MouseHandler::cursorText(char *buffer, int16 cx, int16 cy, uif_t fontId, int16 color) {
|
||||||
|
|
||||||
|
debugC(1, kDebugMouse, "cursorText(%s, %d, %d, %d, %d)", buffer, cx, cy, fontId, color);
|
||||||
|
|
||||||
|
if (_vm.getPlatform() == Common::kPlatformWindows)
|
||||||
|
_vm.screen().loadFont(fontId);
|
||||||
|
|
||||||
|
// Find bounding rect for string
|
||||||
|
int16 sdx = _vm.screen().stringLength(buffer);
|
||||||
|
int16 sdy = _vm.screen().fontHeight() + 1; // + 1 for shadow
|
||||||
|
int16 sx = (cx < XPIX / 2) ? cx + SX_OFF : cx - sdx - SX_OFF / 2;
|
||||||
|
int16 sy = cy + SY_OFF;
|
||||||
|
|
||||||
|
// Display the string and add rect to display list
|
||||||
|
_vm.screen().shadowStr(sx, sy, buffer, _TBRIGHTWHITE);
|
||||||
|
_vm.screen().displayList(D_ADD, sx, sy, sdx, sdy);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find the exit hotspot containing cx, cy.
|
||||||
|
// Return hotspot index or -1 if not found.
|
||||||
|
int16 MouseHandler::findExit(int16 cx, int16 cy) {
|
||||||
|
int i;
|
||||||
|
hotspot_t *hotspot;
|
||||||
|
|
||||||
|
debugC(2, kDebugMouse, "findExit(%d, %d)", cx, cy);
|
||||||
|
|
||||||
|
for (i = 0, hotspot = _vm._hotspots; hotspot->screenIndex >= 0; i++, hotspot++)
|
||||||
|
if (hotspot->screenIndex == *_vm._screen_p)
|
||||||
|
if (cx >= hotspot->x1 && cx <= hotspot->x2 && cy >= hotspot->y1 && cy <= hotspot->y2)
|
||||||
|
return(i);
|
||||||
|
return(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process a mouse right click at coord cx, cy over object objid
|
||||||
|
void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) {
|
||||||
|
object_t *obj;
|
||||||
|
int16 x, y;
|
||||||
|
bool foundFl = false; // TRUE if route found to object
|
||||||
|
|
||||||
|
debugC(1, kDebugMouse, "Process_rclick(%d, %d, %d)", objId, cx, cy);
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
if (gameStatus.storyModeFl || _vm._hero->pathType == QUIET) // Make sure user has control
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Check if this was over iconbar
|
||||||
|
if (gameStatus.inventoryState == I_ACTIVE && cy < INV_DY + DIBOFF_Y) { // Clicked over iconbar object
|
||||||
|
if (gameStatus.inventoryObjId == -1)
|
||||||
|
gameStatus.inventoryObjId = objId; // Not using so select new object
|
||||||
|
else if (gameStatus.inventoryObjId == objId)
|
||||||
|
gameStatus.inventoryObjId = -1; // Same icon - deselect it
|
||||||
|
else
|
||||||
|
_vm.useObject(objId); // Use status.objid on object
|
||||||
|
} else { // Clicked over viewport object
|
||||||
|
obj = &_vm._objects[objId];
|
||||||
|
switch (obj->viewx) { // Where to walk to
|
||||||
|
case -1: // Walk to object position
|
||||||
|
if (_vm.findObjectSpace(obj, &x, &y))
|
||||||
|
foundFl = _vm.route().startRoute(GO_GET, objId, x, y);
|
||||||
|
if (!foundFl) // Can't get there, try to use from here
|
||||||
|
_vm.useObject(objId);
|
||||||
|
break;
|
||||||
|
case 0: // Immediate use
|
||||||
|
_vm.useObject(objId); // Pick up or use object
|
||||||
|
break;
|
||||||
|
default: // Walk to view point if possible
|
||||||
|
if (!_vm.route().startRoute(GO_GET, objId, obj->viewx, obj->viewy))
|
||||||
|
if (_vm._hero->cycling == INVISIBLE) // If invisible do
|
||||||
|
_vm.useObject(objId); // immediate use
|
||||||
|
else
|
||||||
|
Utils::Box(BOX_ANY, _vm._textMouse[kMsNoWayText]); // Can't get there
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process a left mouse click over:
|
||||||
|
// 1. An icon - show description
|
||||||
|
// 2. An object - walk to and show description
|
||||||
|
// 3. An icon scroll arrow - scroll the iconbar
|
||||||
|
// 4. Nothing - attempt to walk there
|
||||||
|
// 5. Exit - walk to exit hotspot
|
||||||
|
void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
|
||||||
|
int16 i, x, y;
|
||||||
|
object_t *obj;
|
||||||
|
bool foundFl = false; // TRUE if route found to object
|
||||||
|
|
||||||
|
debugC(1, kDebugMouse, "Process_lclick(%d, %d, %d)", objId, cx, cy);
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
if (gameStatus.storyModeFl || _vm._hero->pathType == QUIET) // Make sure user has control
|
||||||
|
return;
|
||||||
|
|
||||||
|
switch (objId) {
|
||||||
|
case -1: // Empty space - attempt to walk there
|
||||||
|
_vm.route().startRoute(GO_SPACE, 0, cx, cy);
|
||||||
|
break;
|
||||||
|
case LEFT_ARROW: // A scroll arrow - scroll the iconbar
|
||||||
|
case RIGHT_ARROW:
|
||||||
|
// Scroll the iconbar and display results
|
||||||
|
_vm.inventory().processInventory(objId == LEFT_ARROW ? INV_LEFT : INV_RIGHT);
|
||||||
|
_vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm.screen().getFrontBuffer(), 0, DIBOFF_Y, XPIX);
|
||||||
|
_vm.screen().moveImage(_vm.screen().getIconBuffer(), 0, 0, XPIX, INV_DY, XPIX, _vm.screen().getBackBuffer(), 0, DIBOFF_Y, XPIX);
|
||||||
|
_vm.screen().displayList(D_ADD, 0, DIBOFF_Y, XPIX, INV_DY);
|
||||||
|
break;
|
||||||
|
case EXIT_HOTSPOT: // Walk to exit hotspot
|
||||||
|
i = findExit(cx, cy);
|
||||||
|
x = _vm._hotspots[i].viewx;
|
||||||
|
y = _vm._hotspots[i].viewy;
|
||||||
|
if (x >= 0) { // Hotspot refers to an exit
|
||||||
|
// Special case of immediate exit
|
||||||
|
if (gameStatus.jumpExitFl) {
|
||||||
|
// Get rid of iconbar if necessary
|
||||||
|
if (gameStatus.inventoryState != I_OFF)
|
||||||
|
gameStatus.inventoryState = I_UP;
|
||||||
|
_vm.scheduler().insertActionList(_vm._hotspots[i].actIndex);
|
||||||
|
} else { // Set up route to exit spot
|
||||||
|
if (_vm._hotspots[i].direction == Common::KEYCODE_RIGHT)
|
||||||
|
x -= HERO_MAX_WIDTH;
|
||||||
|
else if (_vm._hotspots[i].direction == Common::KEYCODE_LEFT)
|
||||||
|
x += HERO_MAX_WIDTH;
|
||||||
|
if (!_vm.route().startRoute(GO_EXIT, i, x, y))
|
||||||
|
Utils::Box(BOX_ANY, _vm._textMouse[kMsNoWayText]); // Can't get there
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get rid of any attached icon
|
||||||
|
gameStatus.inventoryObjId = -1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // Look at an icon or object
|
||||||
|
obj = &_vm._objects[objId];
|
||||||
|
|
||||||
|
// Over iconbar - immediate description
|
||||||
|
if (gameStatus.inventoryState == I_ACTIVE && cy < INV_DY + DIBOFF_Y)
|
||||||
|
_vm.lookObject(obj);
|
||||||
|
else {
|
||||||
|
switch (obj->viewx) { // Clicked over viewport object
|
||||||
|
case -1: // Walk to object position
|
||||||
|
if (_vm.findObjectSpace(obj, &x, &y))
|
||||||
|
foundFl = _vm.route().startRoute(GO_LOOK, objId, x, y);
|
||||||
|
if (!foundFl) // Can't get there, immediate description
|
||||||
|
_vm.lookObject(obj);
|
||||||
|
break;
|
||||||
|
case 0: // Immediate description
|
||||||
|
_vm.lookObject(obj);
|
||||||
|
break;
|
||||||
|
default: // Walk to view point if possible
|
||||||
|
if (!_vm.route().startRoute(GO_LOOK, objId, obj->viewx, obj->viewy))
|
||||||
|
if (_vm._hero->cycling == INVISIBLE) // If invisible do
|
||||||
|
_vm.lookObject(obj); // immediate decription
|
||||||
|
else
|
||||||
|
Utils::Box(BOX_ANY, _vm._textMouse[kMsNoWayText]); // Can't get there
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process mouse activity
|
||||||
|
void MouseHandler::mouseHandler() {
|
||||||
|
int16 iconId; // Find index of dragged icon
|
||||||
|
int iconx, icony; // Icon position (in dib_a)
|
||||||
|
int16 ux, uy; // Icon position (in dib_u)
|
||||||
|
int16 objId = -1; // Current source object
|
||||||
|
char *name; // Name of object to display
|
||||||
|
|
||||||
|
debugC(2, kDebugMouse, "mouseHandler");
|
||||||
|
|
||||||
|
int16 cx = _vm.getMouseX();
|
||||||
|
int16 cy = _vm.getMouseY();
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
gameStatus.cx = cx; // Save cursor coords
|
||||||
|
gameStatus.cy = cy;
|
||||||
|
|
||||||
|
// Don't process if outside client area
|
||||||
|
if (cx < 0 || cx > XPIX || cy < DIBOFF_Y || cy > VIEW_DY + DIBOFF_Y)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Display dragged inventory icon if one currently selected
|
||||||
|
if (gameStatus.inventoryObjId != -1) {
|
||||||
|
// Find index of icon
|
||||||
|
for (iconId = 0; iconId < _vm._maxInvent; iconId++)
|
||||||
|
if (gameStatus.inventoryObjId == _vm._invent[iconId])
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Compute source coordinates in dib_u
|
||||||
|
ux = (iconId + NUM_ARROWS) * INV_DX % XPIX;
|
||||||
|
uy = (iconId + NUM_ARROWS) * INV_DX / XPIX * INV_DY;
|
||||||
|
|
||||||
|
// Compute destination coordinates in dib_a
|
||||||
|
iconx = cx + IX_OFF;
|
||||||
|
icony = cy + IY_OFF;
|
||||||
|
iconx = MAX(iconx, 0); // Keep within dib_a bounds
|
||||||
|
iconx = MIN(iconx, XPIX - INV_DX);
|
||||||
|
icony = MAX(icony, 0);
|
||||||
|
icony = MIN(icony, YPIX - INV_DY);
|
||||||
|
|
||||||
|
// Copy the icon and add to display list
|
||||||
|
_vm.screen().moveImage(_vm.screen().getGUIBuffer(), ux, uy, INV_DX, INV_DY, XPIX, _vm.screen().getFrontBuffer(), iconx, icony, XPIX);
|
||||||
|
_vm.screen().displayList(D_ADD, iconx, icony, INV_DX, INV_DY);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process cursor over an object or icon
|
||||||
|
if (gameStatus.inventoryState == I_ACTIVE) // Check inventory icon bar first
|
||||||
|
objId = _vm.inventory().processInventory(INV_GET, cx, cy);
|
||||||
|
if (objId == -1) // No match, check rest of view
|
||||||
|
objId = _vm.findObject(cx, cy);
|
||||||
|
if (objId >= 0) { // Got a match
|
||||||
|
// Display object name next to cursor (unless CURSOR_NOCHAR)
|
||||||
|
// Note test for swapped hero name
|
||||||
|
name = _vm._arrayNouns[_vm._objects[objId == HERO ? _vm._heroImage : objId].nounIndex][CURSOR_NAME];
|
||||||
|
if (name[0] != CURSOR_NOCHAR)
|
||||||
|
cursorText(name, cx, cy, U_FONT8, _TBRIGHTWHITE);
|
||||||
|
|
||||||
|
// Process right click over object in view or iconbar
|
||||||
|
if (gameStatus.rightButtonFl)
|
||||||
|
processRightClick(objId, cx, cy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process cursor over an exit hotspot
|
||||||
|
if (objId == -1) {
|
||||||
|
int i = findExit(cx, cy);
|
||||||
|
if (i != -1 && _vm._hotspots[i].viewx >= 0) {
|
||||||
|
objId = EXIT_HOTSPOT;
|
||||||
|
cursorText(_vm._textMouse[kMsExit], cx, cy, U_FONT8, _TBRIGHTWHITE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Left click over icon, object or to move somewhere
|
||||||
|
if (gameStatus.leftButtonFl)
|
||||||
|
processLeftClick(objId, cx, cy);
|
||||||
|
|
||||||
|
// Clear mouse click states
|
||||||
|
gameStatus.leftButtonFl = false;
|
||||||
|
gameStatus.rightButtonFl = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
53
engines/hugo/mouse.h
Executable file
53
engines/hugo/mouse.h
Executable file
|
@ -0,0 +1,53 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_MOUSE_H
|
||||||
|
#define HUGO_MOUSE_H
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
class MouseHandler {
|
||||||
|
public:
|
||||||
|
MouseHandler(HugoEngine &vm);
|
||||||
|
|
||||||
|
void mouseHandler();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
|
||||||
|
void cursorText(char *buffer, int16 cx, int16 cy, uif_t fontId, int16 color);
|
||||||
|
int16 findExit(int16 cx, int16 cy);
|
||||||
|
void processRightClick(int16 objId, int16 cx, int16 cy);
|
||||||
|
void processLeftClick(int16 objId, int16 cx, int16 cy);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif //HUGO_MOUSE_H
|
676
engines/hugo/parser.cpp
Executable file
676
engines/hugo/parser.cpp
Executable file
|
@ -0,0 +1,676 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// parser.c - handles all keyboard/command input
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
#include "common/keyboard.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/parser.h"
|
||||||
|
#include "hugo/global.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/schedule.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/route.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
#include "hugo/sound.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define BLINKS 2 // Cursor blinks per second
|
||||||
|
#define CX(X) LOWORD(X)
|
||||||
|
#define CY(Y) HIWORD(Y)
|
||||||
|
|
||||||
|
Parser::Parser(HugoEngine &vm) :
|
||||||
|
_vm(vm), _putIndex(0), _getIndex(0) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
bool repeatedFl = (nFlags & 0x4000); // TRUE if key is a repeat
|
||||||
|
|
||||||
|
debugC(1, kDebugParser, "keyHandler(%d, %d)", nChar, nFlags);
|
||||||
|
|
||||||
|
// Process key down event - called from OnKeyDown()
|
||||||
|
switch (nChar) { // Set various toggle states
|
||||||
|
case Common::KEYCODE_ESCAPE: // Escape key, may want to QUIT
|
||||||
|
if (gameStatus.inventoryState == I_ACTIVE) // Remove inventory, if displayed
|
||||||
|
gameStatus.inventoryState = I_UP;
|
||||||
|
gameStatus.inventoryObjId = -1; // Deselect any dragged icon
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_END:
|
||||||
|
case Common::KEYCODE_HOME:
|
||||||
|
case Common::KEYCODE_LEFT:
|
||||||
|
case Common::KEYCODE_RIGHT:
|
||||||
|
case Common::KEYCODE_UP:
|
||||||
|
case Common::KEYCODE_DOWN:
|
||||||
|
if (!repeatedFl) {
|
||||||
|
gameStatus.routeIndex = -1; // Stop any automatic route
|
||||||
|
_vm.route().setWalk(nChar); // Direction of hero travel
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_F1: // User Help (DOS)
|
||||||
|
if (repeatedFl) {
|
||||||
|
_vm.file().instructions();
|
||||||
|
nChar = '\0';
|
||||||
|
} else
|
||||||
|
_vm.screen().userHelp();
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_F2: // Toggle sound
|
||||||
|
case Common::KEYCODE_F3: // Repeat last line
|
||||||
|
case Common::KEYCODE_F4: // Save game
|
||||||
|
case Common::KEYCODE_F5: // Restore game
|
||||||
|
case Common::KEYCODE_F6: // Inventory
|
||||||
|
case Common::KEYCODE_F8: // Turbo mode
|
||||||
|
case Common::KEYCODE_F9: // Boss button
|
||||||
|
warning("STUB: KeyHandler() - F2-F9 (DOS)");
|
||||||
|
break;
|
||||||
|
default: // Any other key
|
||||||
|
if (!gameStatus.storyModeFl) { // Keyboard disabled
|
||||||
|
// Add printable keys to ring buffer
|
||||||
|
|
||||||
|
uint16 bnext = _putIndex + 1;
|
||||||
|
if (bnext >= sizeof(_ringBuffer))
|
||||||
|
bnext = 0;
|
||||||
|
if (bnext != _getIndex) {
|
||||||
|
_ringBuffer[_putIndex] = nChar;
|
||||||
|
_putIndex = bnext;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add any new chars to line buffer and display them.
|
||||||
|
// If CR pressed, pass line to Line_handler()
|
||||||
|
void Parser::charHandler() {
|
||||||
|
static int16 lineIndex = 0; // Index into line
|
||||||
|
static uint32 tick = 0; // For flashing cursor
|
||||||
|
static char cursor = '_';
|
||||||
|
char c;
|
||||||
|
static command_t cmdLine; // Build command line
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
// Strangerke : Useless ?
|
||||||
|
// bool updateFl = (_getIndex != _putIndex); // TRUE if any chars processed
|
||||||
|
// command_t status_line; // Includes prompt, cursor
|
||||||
|
|
||||||
|
//Strangerke : Useless ?
|
||||||
|
// bool updateFl = (_getIndex != _putIndex); // TRUE if any chars processed
|
||||||
|
//command_t status_line; // Includes prompt, cursor
|
||||||
|
|
||||||
|
debugC(4, kDebugParser, "charHandler");
|
||||||
|
|
||||||
|
// Check for one or more characters in ring buffer
|
||||||
|
while (_getIndex != _putIndex) {
|
||||||
|
c = _ringBuffer[_getIndex++];
|
||||||
|
if (_getIndex >= sizeof(_ringBuffer))
|
||||||
|
_getIndex = 0;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case Common::KEYCODE_BACKSPACE: // Rubout key
|
||||||
|
if (lineIndex)
|
||||||
|
cmdLine[--lineIndex] = '\0';
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_RETURN: // EOL, pass line to line handler
|
||||||
|
if (lineIndex && (_vm._hero->pathType != QUIET)) {
|
||||||
|
// Remove inventory bar if active
|
||||||
|
if (gameStatus.inventoryState == I_ACTIVE)
|
||||||
|
gameStatus.inventoryState = I_UP;
|
||||||
|
// Call Line handler and reset line
|
||||||
|
command(cmdLine);
|
||||||
|
cmdLine[lineIndex = 0] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default: // Normal text key, add to line
|
||||||
|
if (lineIndex >= MAX_CHARS) {
|
||||||
|
//MessageBeep(MB_ICONASTERISK);
|
||||||
|
warning("STUB: MessageBeep(MB_ICONASTERISK);");
|
||||||
|
} else if (isprint(c)) {
|
||||||
|
cmdLine[lineIndex++] = c;
|
||||||
|
cmdLine[lineIndex] = '\0';
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if time to blink cursor, set cursor character
|
||||||
|
if ((tick++ % (TPS / BLINKS)) == 0) {
|
||||||
|
// Strangerke : Useless ?
|
||||||
|
// updateFl = true; // Force an update
|
||||||
|
cursor = cursor == '_' ? ' ' : '_';
|
||||||
|
}
|
||||||
|
|
||||||
|
// See if recall button pressed
|
||||||
|
if (gameStatus.recallFl) {
|
||||||
|
// Copy previous line to current cmdline
|
||||||
|
gameStatus.recallFl = false;
|
||||||
|
strcpy(cmdLine, _line);
|
||||||
|
lineIndex = strlen(cmdLine);
|
||||||
|
}
|
||||||
|
|
||||||
|
sprintf(_statusLine, ">%s%c", cmdLine, cursor);
|
||||||
|
sprintf(_scoreLine, "Score: %d of %d", _vm.getScore(), _vm.getMaxScore());
|
||||||
|
|
||||||
|
// See if "look" button pressed
|
||||||
|
if (gameStatus.lookFl) {
|
||||||
|
command("look around");
|
||||||
|
gameStatus.lookFl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Parser::drawStatusText() {
|
||||||
|
debugC(4, kDebugParser, "drawStatusText");
|
||||||
|
|
||||||
|
if (_vm.getPlatform() == Common::kPlatformWindows)
|
||||||
|
_vm.screen().loadFont(U_FONT8);
|
||||||
|
uint16 sdx = _vm.screen().stringLength(_statusLine);
|
||||||
|
uint16 sdy = _vm.screen().fontHeight() + 1; // + 1 for shadow
|
||||||
|
uint16 posX = 0;
|
||||||
|
uint16 posY = YPIX - sdy;
|
||||||
|
// Display the string and add rect to display list
|
||||||
|
_vm.screen().writeStr(posX, posY, _statusLine, _TLIGHTYELLOW);
|
||||||
|
_vm.screen().displayList(D_ADD, posX, posY, sdx, sdy);
|
||||||
|
|
||||||
|
sdx = _vm.screen().stringLength(_scoreLine);
|
||||||
|
posY = 0;
|
||||||
|
_vm.screen().writeStr(posX, posY, _scoreLine, _TCYAN);
|
||||||
|
_vm.screen().displayList(D_ADD, posX, posY, sdx, sdy);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform an immediate command. Takes parameters a la sprintf
|
||||||
|
// Assumes final string will not overrun line[] length
|
||||||
|
void Parser::command(const char *format, ...) {
|
||||||
|
va_list marker;
|
||||||
|
|
||||||
|
debugC(1, kDebugParser, "Command(%s, ...)", format);
|
||||||
|
|
||||||
|
va_start(marker, format);
|
||||||
|
vsprintf(_line, format, marker);
|
||||||
|
va_end(marker);
|
||||||
|
|
||||||
|
lineHandler();
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Parser::strlwr(char *buffer) {
|
||||||
|
char *result = buffer;
|
||||||
|
|
||||||
|
debugC(1, kDebugParser, "strlwr(%s)", buffer);
|
||||||
|
|
||||||
|
while (*buffer != '\0') {
|
||||||
|
if (isupper(*buffer))
|
||||||
|
*buffer = tolower(*buffer);
|
||||||
|
buffer++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Parse the user's line of text input. Generate events as necessary
|
||||||
|
void Parser::lineHandler() {
|
||||||
|
char *noun, *verb; // ptrs to noun and verb strings
|
||||||
|
// int i;
|
||||||
|
object_t *obj;
|
||||||
|
char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
|
||||||
|
char contextComment[XBYTES * 5] = ""; // Unused comment for context objects
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
|
||||||
|
debugC(1, kDebugParser, "lineHandler");
|
||||||
|
|
||||||
|
// Toggle God Mode
|
||||||
|
if (!strncmp(_line, "PPG", 3)) {
|
||||||
|
_vm.sound().playSound(!_vm._soundTest, BOTH_CHANNELS, HIGH_PRI);
|
||||||
|
gameStatus.godModeFl ^= 1;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
strlwr(_line); // Convert to lower case
|
||||||
|
|
||||||
|
// God Mode cheat commands:
|
||||||
|
// goto <screen> Takes hero to named screen
|
||||||
|
// fetch <object name> Hero carries named object
|
||||||
|
// fetch all Hero carries all possible objects
|
||||||
|
// find <object name> Takes hero to screen containing named object
|
||||||
|
if (DEBUG || gameStatus.godModeFl) {
|
||||||
|
// Special code to allow me to go straight to any screen
|
||||||
|
if (strstr(_line, "goto"))
|
||||||
|
for (int i = 0; i < _vm._numScreens; i++)
|
||||||
|
if (!strcmp(&_line[strlen("goto") + 1], _vm._screenNames[i])) {
|
||||||
|
_vm.scheduler().newScreen(i);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special code to allow me to get objects from anywhere
|
||||||
|
if (strstr(_line, "fetch all")) {
|
||||||
|
for (int i = 0; i < _vm._numObj; i++)
|
||||||
|
if (_vm._objects[i].genericCmd & TAKE)
|
||||||
|
takeObject(&_vm._objects[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strstr(_line, "fetch")) {
|
||||||
|
for (int i = 0; i < _vm._numObj; i++)
|
||||||
|
if (!strcmp(&_line[strlen("fetch") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) {
|
||||||
|
takeObject(&_vm._objects[i]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special code to allow me to goto objects
|
||||||
|
if (strstr(_line, "find"))
|
||||||
|
for (int i = 0; i < _vm._numObj; i++)
|
||||||
|
if (!strcmp(&_line[strlen("find") + 1], _vm._arrayNouns[_vm._objects[i].nounIndex][0])) {
|
||||||
|
_vm.scheduler().newScreen(_vm._objects[i].screenIndex);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Special meta commands
|
||||||
|
// EXIT/QUIT
|
||||||
|
if (!strcmp("exit", _line) || strstr(_line, "quit")) {
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBExit]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAVE/RESTORE
|
||||||
|
if (!strcmp("save", _line) && gameStatus.viewState == V_PLAY) {
|
||||||
|
_vm.file().saveGame(gameStatus.saveSlot, "Current game");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!strcmp("restore", _line) && gameStatus.viewState == V_PLAY || gameStatus.viewState == V_IDLE) {
|
||||||
|
_vm.file().restoreGame(gameStatus.saveSlot);
|
||||||
|
_vm.scheduler().restoreScreen(*_vm._screen_p);
|
||||||
|
gameStatus.viewState = V_PLAY;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty line
|
||||||
|
if (*_line == '\0') // Empty line
|
||||||
|
return;
|
||||||
|
if (strspn(_line, " ") == strlen(_line)) // Nothing but spaces!
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (gameStatus.gameOverFl) {
|
||||||
|
// No commands allowed!
|
||||||
|
Utils::gameOverMsg();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for nearby objects referenced explicitly
|
||||||
|
for (int i = 0; i < _vm._numObj; i++) {
|
||||||
|
obj = &_vm._objects[i];
|
||||||
|
if (isWordPresent(_vm._arrayNouns[obj->nounIndex]))
|
||||||
|
if (isObjectVerb(obj, _line, farComment) || isGenericVerb(obj, _line, farComment))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test for nearby objects that only require a verb
|
||||||
|
// Note comment is unused if not near.
|
||||||
|
for (int i = 0; i < _vm._numObj; i++) {
|
||||||
|
obj = &_vm._objects[i];
|
||||||
|
if (obj->verbOnlyFl)
|
||||||
|
if (isObjectVerb(obj, _line, contextComment) || isGenericVerb(obj, _line, contextComment))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// No objects match command line, try background and catchall commands
|
||||||
|
if (isBackgroundWord(_vm._backgroundObjects[*_vm._screen_p], _line))
|
||||||
|
return;
|
||||||
|
if (isCatchallVerb(_vm._backgroundObjects[*_vm._screen_p], _line))
|
||||||
|
return;
|
||||||
|
if (isBackgroundWord(_vm._catchallList, _line))
|
||||||
|
return;
|
||||||
|
if (isCatchallVerb(_vm._catchallList, _line))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If a not-near comment was generated, print it
|
||||||
|
if (*farComment != '\0') {
|
||||||
|
Utils::Box(BOX_ANY, farComment);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Nothing matches. Report recognition success to user.
|
||||||
|
verb = findVerb(_line);
|
||||||
|
noun = findNoun(_line);
|
||||||
|
if (verb == _vm._arrayVerbs[_vm._look][0] && _maze.enabledFl) {
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBMaze]);
|
||||||
|
showTakeables();
|
||||||
|
} else if (verb && noun) // A combination I didn't think of
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBNoPoint]);
|
||||||
|
else if (noun)
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBNoun]);
|
||||||
|
else if (verb)
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBVerb]);
|
||||||
|
else
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBEh]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for matching verb/noun pairs in background command list
|
||||||
|
// Print text for possible background object. Return TRUE if match found
|
||||||
|
bool Parser::isBackgroundWord(objectList_t obj, char *line) {
|
||||||
|
debugC(1, kDebugParser, "isBackgroundWord(object_list_t obj, %s)", line);
|
||||||
|
|
||||||
|
for (int i = 0; obj[i].verbIndex != 0; i++)
|
||||||
|
if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) &&
|
||||||
|
isWordPresent(_vm._arrayNouns[obj[i].nounIndex]) &&
|
||||||
|
((obj[i].roomState == DONT_CARE) ||
|
||||||
|
(obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
|
||||||
|
Utils::Box(BOX_ANY, _vm.file().fetchString(obj[i].commentIndex));
|
||||||
|
_vm.scheduler().processBonus(obj[i].bonusIndex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Search for matching verbs in background command list.
|
||||||
|
// Noun is not required. Return TRUE if match found
|
||||||
|
// Note that if the background command list has match set TRUE then do not
|
||||||
|
// print text if there are any recognizable nouns in the command line
|
||||||
|
bool Parser::isCatchallVerb(objectList_t obj, char *line) {
|
||||||
|
debugC(1, kDebugParser, "isCatchallVerb(object_list_t obj, %s)", line);
|
||||||
|
|
||||||
|
for (int i = 0; obj[i].verbIndex != 0; i++)
|
||||||
|
if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 &&
|
||||||
|
(!obj[i].matchFl || !findNoun(line)) &&
|
||||||
|
((obj[i].roomState == DONT_CARE) ||
|
||||||
|
(obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
|
||||||
|
Utils::Box(BOX_ANY, _vm.file().fetchString(obj[i].commentIndex));
|
||||||
|
_vm.scheduler().processBonus(obj[i].bonusIndex);
|
||||||
|
|
||||||
|
// If this is LOOK (without a noun), show any takeable objects
|
||||||
|
if (*(_vm._arrayVerbs[obj[i].verbIndex]) == _vm._arrayVerbs[_vm._look][0])
|
||||||
|
showTakeables();
|
||||||
|
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test whether hero is close to object. Return TRUE or FALSE
|
||||||
|
// If object not near, return suitable comment; may be another object close
|
||||||
|
// If radius is -1, treat radius as infinity
|
||||||
|
// Verb is included to determine correct comment if not near
|
||||||
|
bool Parser::isNear(object_t *obj, char *verb, char *comment) {
|
||||||
|
debugC(1, kDebugParser, "isNear(object_t *obj, %s, %s)", verb, comment);
|
||||||
|
|
||||||
|
if (obj->carriedFl) // Object is being carried
|
||||||
|
return(true);
|
||||||
|
|
||||||
|
if (obj->screenIndex != *_vm._screen_p) {
|
||||||
|
// Not in same screen
|
||||||
|
if (obj->objValue)
|
||||||
|
strcpy(comment, _vm._textParser[kCmtAny1]);
|
||||||
|
else
|
||||||
|
strcpy(comment, _vm._textParser[kCmtAny2]);
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (obj->cycling == INVISIBLE)
|
||||||
|
if (obj->seqNumb) {
|
||||||
|
// There is an image
|
||||||
|
strcpy(comment, _vm._textParser[kCmtAny3]);
|
||||||
|
return(false);
|
||||||
|
} else
|
||||||
|
// No image, assume visible
|
||||||
|
if ((obj->radius < 0) ||
|
||||||
|
((abs(obj->x - _vm._hero->x) <= obj->radius) &&
|
||||||
|
(abs(obj->y - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius)))
|
||||||
|
return(true);
|
||||||
|
else {
|
||||||
|
// User is not close enough
|
||||||
|
if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
|
||||||
|
strcpy(comment, _vm._textParser[kCmtAny1]);
|
||||||
|
else
|
||||||
|
strcpy(comment, _vm._textParser[kCmtClose]);
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((obj->radius < 0) ||
|
||||||
|
((abs(obj->x - _vm._hero->x) <= obj->radius) &&
|
||||||
|
(abs(obj->y + obj->currImagePtr->y2 - _vm._hero->y - _vm._hero->currImagePtr->y2) <= obj->radius)))
|
||||||
|
return(true);
|
||||||
|
else {
|
||||||
|
// User is not close enough
|
||||||
|
if (obj->objValue && (verb != _vm._arrayVerbs[_vm._take][0]))
|
||||||
|
strcpy(comment, _vm._textParser[kCmtAny1]);
|
||||||
|
else
|
||||||
|
strcpy(comment, _vm._textParser[kCmtClose]);
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate any member of object name list appearing in command line
|
||||||
|
bool Parser::isWordPresent(char **wordArr) {
|
||||||
|
debugC(1, kDebugParser, "isWordPresent(%s)", wordArr[0]);
|
||||||
|
|
||||||
|
if (wordArr != NULL) {
|
||||||
|
for (int i = 0; strlen(wordArr[i]); i++)
|
||||||
|
if (strstr(_line, wordArr[i]))
|
||||||
|
return(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate word in list of nouns and return ptr to first string in noun list
|
||||||
|
char *Parser::findNoun(char *line) {
|
||||||
|
debugC(1, kDebugParser, "findNoun(%s)", line);
|
||||||
|
|
||||||
|
for (int i = 0; _vm._arrayNouns[i]; i++)
|
||||||
|
for (int j = 0; strlen(_vm._arrayNouns[i][j]); j++)
|
||||||
|
if (strstr(line, _vm._arrayNouns[i][j]))
|
||||||
|
return(_vm._arrayNouns[i][0]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Locate word in list of verbs and return ptr to first string in verb list
|
||||||
|
char *Parser::findVerb(char *line) {
|
||||||
|
debugC(1, kDebugParser, "findVerb(%s)", line);
|
||||||
|
|
||||||
|
for (int i = 0; _vm._arrayVerbs[i]; i++)
|
||||||
|
for (int j = 0; strlen(_vm._arrayVerbs[i][j]); j++)
|
||||||
|
if (strstr(line, _vm._arrayVerbs[i][j]))
|
||||||
|
return(_vm._arrayVerbs[i][0]);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Describe any takeable objects visible in this screen
|
||||||
|
void Parser::showTakeables() {
|
||||||
|
object_t *obj;
|
||||||
|
|
||||||
|
debugC(1, kDebugParser, "showTakeables");
|
||||||
|
|
||||||
|
for (int j = 0; j < _vm._numObj; j++) {
|
||||||
|
obj = &_vm._objects[j];
|
||||||
|
if ((obj->cycling != INVISIBLE) &&
|
||||||
|
(obj->screenIndex == *_vm._screen_p) &&
|
||||||
|
(((TAKE & obj->genericCmd) == TAKE) || obj->objValue)) {
|
||||||
|
sprintf(_textBoxBuffer, "You can also see:\n%s.", _vm._arrayNouns[obj->nounIndex][LOOK_NAME]);
|
||||||
|
Utils::Box(BOX_ANY, _textBoxBuffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do all things necessary to carry an object
|
||||||
|
void Parser::takeObject(object_t *obj) {
|
||||||
|
debugC(1, kDebugParser, "takeObject(object_t *obj)");
|
||||||
|
|
||||||
|
obj->carriedFl = true;
|
||||||
|
if (obj->seqNumb) { // Don't change if no image to display
|
||||||
|
obj->cycling = INVISIBLE;
|
||||||
|
if (_vm.getPlatform() != Common::kPlatformWindows)
|
||||||
|
warning("takeObject : DOS version should use ALMOST_INVISIBLE");
|
||||||
|
}
|
||||||
|
_vm.adjustScore(obj->objValue);
|
||||||
|
|
||||||
|
if (obj->seqNumb > 0) // If object has an image, force walk to dropped
|
||||||
|
obj->viewx = -1; // (possibly moved) object next time taken!
|
||||||
|
Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[obj->nounIndex][TAKE_NAME]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Do all necessary things to drop an object
|
||||||
|
void Parser::dropObject(object_t *obj) {
|
||||||
|
debugC(1, kDebugParser, "dropObject(object_t *obj)");
|
||||||
|
|
||||||
|
obj->carriedFl = false;
|
||||||
|
obj->screenIndex = *_vm._screen_p;
|
||||||
|
if ((obj->seqNumb > 1) || (obj->seqList[0].imageNbr > 1))
|
||||||
|
obj->cycling = CYCLE_FORWARD;
|
||||||
|
else
|
||||||
|
obj->cycling = NOT_CYCLING;
|
||||||
|
obj->x = _vm._hero->x - 1;
|
||||||
|
obj->y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1;
|
||||||
|
obj->y = (obj->y + obj->currImagePtr->y2 < YPIX) ? obj->y : YPIX - obj->currImagePtr->y2 - 10;
|
||||||
|
_vm.adjustScore(-obj->objValue);
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBOk]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test whether command line contains one of the generic actions
|
||||||
|
bool Parser::isGenericVerb(object_t *obj, char *line, char *comment) {
|
||||||
|
debugC(1, kDebugParser, "isGenericVerb(object_t *obj, %s, %s)", line, comment);
|
||||||
|
|
||||||
|
if (!obj->genericCmd)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Following is equivalent to switch, but couldn't do one
|
||||||
|
if (isWordPresent(_vm._arrayVerbs[_vm._look]) && isNear(obj, _vm._arrayVerbs[_vm._look][0], comment)) {
|
||||||
|
// Test state-dependent look before general look
|
||||||
|
if ((obj->genericCmd & LOOK_S) == LOOK_S) {
|
||||||
|
Utils::Box(BOX_ANY, _vm._textData[obj->stateDataIndex[obj->state]]);
|
||||||
|
warning("isGenericVerb: use of state dependant look - To be validated");
|
||||||
|
} else {
|
||||||
|
if ((LOOK & obj->genericCmd) == LOOK)
|
||||||
|
if (_vm._textData[obj->dataIndex])
|
||||||
|
Utils::Box(BOX_ANY, _vm._textData[obj->dataIndex]);
|
||||||
|
else
|
||||||
|
return(false);
|
||||||
|
else
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBUnusual]);
|
||||||
|
}
|
||||||
|
} else if (isWordPresent(_vm._arrayVerbs[_vm._take]) && isNear(obj, _vm._arrayVerbs[_vm._take][0], comment)) {
|
||||||
|
if (obj->carriedFl)
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBHave]);
|
||||||
|
else if ((TAKE & obj->genericCmd) == TAKE)
|
||||||
|
takeObject(obj);
|
||||||
|
else if (obj->cmdIndex != 0) // No comment if possible commands
|
||||||
|
return false;
|
||||||
|
else if (!obj->verbOnlyFl && (TAKE & obj->genericCmd) == TAKE) // Make sure not taking object in context!
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBNoUse]);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else if (isWordPresent(_vm._arrayVerbs[_vm._drop])) {
|
||||||
|
if (!obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBDontHave]);
|
||||||
|
else if (obj->carriedFl && ((DROP & obj->genericCmd) == DROP))
|
||||||
|
dropObject(obj);
|
||||||
|
else if (obj->cmdIndex == 0)
|
||||||
|
Utils::Box(BOX_ANY, _vm._textParser[kTBNeed]);
|
||||||
|
else
|
||||||
|
return false;
|
||||||
|
} else // It was not a generic cmd
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return TRUE if object being carried by hero
|
||||||
|
bool Parser::isCarrying(uint16 wordIndex) {
|
||||||
|
debugC(1, kDebugParser, "isCarrying(%d)", wordIndex);
|
||||||
|
|
||||||
|
for (int i = 0; i < _vm._numObj; i++)
|
||||||
|
if ((wordIndex == _vm._objects[i].nounIndex) && _vm._objects[i].carriedFl)
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test whether command line contains a verb allowed by this object.
|
||||||
|
// If it does, and the object is near and passes the tests in the command
|
||||||
|
// list then carry out the actions in the action list and return TRUE
|
||||||
|
bool Parser::isObjectVerb(object_t *obj, char *line, char *comment) {
|
||||||
|
int i;
|
||||||
|
cmd *cmnd;
|
||||||
|
char *verb;
|
||||||
|
uint16 *reqs;
|
||||||
|
uint16 cmdIndex;
|
||||||
|
|
||||||
|
debugC(1, kDebugParser, "isObjectVerb(object_t *obj, %s, %s)", line, comment);
|
||||||
|
|
||||||
|
// First, find matching verb in cmd list
|
||||||
|
cmdIndex = obj->cmdIndex; // ptr to list of commands
|
||||||
|
if (cmdIndex == 0) // No commands for this obj
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (i = 0; _vm._cmdList[cmdIndex][i].verbIndex != 0; i++) // For each cmd
|
||||||
|
if (isWordPresent(_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex])) // Was this verb used?
|
||||||
|
break;
|
||||||
|
if (_vm._cmdList[cmdIndex][i].verbIndex == 0) // No verbs used.
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// Verb match found. Check if object is Near
|
||||||
|
verb = *_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex];
|
||||||
|
if (!isNear(obj, verb, comment))
|
||||||
|
return(false);
|
||||||
|
|
||||||
|
// Check all required objects are being carried
|
||||||
|
cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd
|
||||||
|
if (cmnd->reqIndex) { // At least 1 thing in list
|
||||||
|
reqs = _vm._arrayReqs[cmnd->reqIndex]; // ptr to list of required objects
|
||||||
|
for (i = 0; reqs[i]; i++) // for each obj
|
||||||
|
if (!isCarrying(reqs[i])) {
|
||||||
|
Utils::Box(BOX_ANY, _vm._textData[cmnd->textDataNoCarryIndex]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Required objects are present, now check state is correct
|
||||||
|
if ((obj->state != cmnd->reqState) && (cmnd->reqState != DONT_CARE)) {
|
||||||
|
Utils::Box(BOX_ANY, _vm._textData[cmnd->textDataWrongIndex]);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Everything checked. Change the state and carry out any actions
|
||||||
|
if (cmnd->reqState != DONT_CARE) // Don't change new state if required state didn't care
|
||||||
|
obj->state = cmnd->newState;
|
||||||
|
Utils::Box(BOX_ANY, _vm._textData[cmnd->textDataDoneIndex]);
|
||||||
|
_vm.scheduler().insertActionList(cmnd->actIndex);
|
||||||
|
|
||||||
|
// See if any additional generic actions
|
||||||
|
if ((verb == _vm._arrayVerbs[_vm._look][0]) || (verb == _vm._arrayVerbs[_vm._take][0]) || (verb == _vm._arrayVerbs[_vm._drop][0]))
|
||||||
|
isGenericVerb(obj, line, comment);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
95
engines/hugo/parser.h
Executable file
95
engines/hugo/parser.h
Executable file
|
@ -0,0 +1,95 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_PARSER_H
|
||||||
|
#define HUGO_PARSER_H
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
enum seqTextParser {
|
||||||
|
kTBExit = 0,
|
||||||
|
kTBMaze = 1,
|
||||||
|
kTBNoPoint = 2,
|
||||||
|
kTBNoun = 3,
|
||||||
|
kTBVerb = 4,
|
||||||
|
kTBEh = 5,
|
||||||
|
kTBUnusual = 6,
|
||||||
|
kTBHave = 7,
|
||||||
|
kTBNoUse = 8,
|
||||||
|
kTBDontHave = 9,
|
||||||
|
kTBNeed = 10,
|
||||||
|
kTBOk = 11,
|
||||||
|
kCmtAny1 = 12,
|
||||||
|
kCmtAny2 = 13,
|
||||||
|
kCmtAny3 = 14,
|
||||||
|
kCmtClose = 15
|
||||||
|
};
|
||||||
|
|
||||||
|
class Parser {
|
||||||
|
public:
|
||||||
|
Parser(HugoEngine &vm);
|
||||||
|
|
||||||
|
bool isWordPresent(char **wordArr);
|
||||||
|
|
||||||
|
void charHandler();
|
||||||
|
void command(const char *format, ...);
|
||||||
|
void drawStatusText();
|
||||||
|
void keyHandler(uint16 nChar, uint16 nFlags);
|
||||||
|
void lineHandler();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
|
||||||
|
char _ringBuffer[32]; // Ring buffer
|
||||||
|
uint16 _putIndex;
|
||||||
|
uint16 _getIndex; // Index into ring buffer
|
||||||
|
|
||||||
|
command_t _statusLine;
|
||||||
|
command_t _scoreLine;
|
||||||
|
|
||||||
|
bool isBackgroundWord(objectList_t obj, char *line);
|
||||||
|
bool isCarrying(uint16 wordIndex);
|
||||||
|
bool isCatchallVerb(objectList_t obj, char *line);
|
||||||
|
bool isGenericVerb(object_t *obj, char *line, char *comment);
|
||||||
|
bool isNear(object_t *obj, char *verb, char *comment);
|
||||||
|
bool isObjectVerb(object_t *obj, char *line, char *comment);
|
||||||
|
|
||||||
|
char *findNoun(char *line);
|
||||||
|
char *findVerb(char *line);
|
||||||
|
char *strlwr(char *buffer);
|
||||||
|
|
||||||
|
void dropObject(object_t *obj);
|
||||||
|
void showTakeables();
|
||||||
|
void takeObject(object_t *obj);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif //HUGO_PARSER_H
|
509
engines/hugo/route.cpp
Executable file
509
engines/hugo/route.cpp
Executable file
|
@ -0,0 +1,509 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Find shortest route from hero to destination
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/route.h"
|
||||||
|
#include "hugo/global.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
Route::Route(HugoEngine &vm) : _vm(vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Face hero in new direction, based on cursor key input by user.
|
||||||
|
void Route::setDirection(uint16 keyCode) {
|
||||||
|
object_t *obj = _vm._hero; // Pointer to hero object
|
||||||
|
|
||||||
|
debugC(1, kDebugRoute, "setDirection(%d)", keyCode);
|
||||||
|
|
||||||
|
// Set first image in sequence
|
||||||
|
switch (keyCode) {
|
||||||
|
case Common::KEYCODE_UP:
|
||||||
|
obj->currImagePtr = obj->seqList[_UP].seqPtr;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_DOWN:
|
||||||
|
obj->currImagePtr = obj->seqList[DOWN].seqPtr;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_LEFT:
|
||||||
|
obj->currImagePtr = obj->seqList[LEFT].seqPtr;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_RIGHT:
|
||||||
|
obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_HOME:
|
||||||
|
obj->currImagePtr = obj->seqList[LEFT].seqPtr;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_END:
|
||||||
|
obj->currImagePtr = obj->seqList[LEFT].seqPtr;
|
||||||
|
break;
|
||||||
|
// case Common::KEYCODE_PRIOR:
|
||||||
|
// obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
|
||||||
|
// break;
|
||||||
|
// case Common::KEYCODE_NEXT:
|
||||||
|
// obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set hero walking, based on cursor key input by user.
|
||||||
|
// Hitting same key twice will stop hero.
|
||||||
|
void Route::setWalk(uint16 direction) {
|
||||||
|
object_t *obj = _vm._hero; // Pointer to hero object
|
||||||
|
static uint16 oldDirection = 0; // Last direction char
|
||||||
|
|
||||||
|
debugC(1, kDebugRoute, "setWalk(%d)", direction);
|
||||||
|
|
||||||
|
if (_vm.getGameStatus().storyModeFl || obj->pathType != USER) // Make sure user has control
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!obj->vx && !obj->vy)
|
||||||
|
oldDirection = 0; // Fix for consistant restarts
|
||||||
|
|
||||||
|
if (direction != oldDirection) {
|
||||||
|
// Direction has changed
|
||||||
|
setDirection(direction); // Face new direction
|
||||||
|
obj->vx = obj->vy = 0;
|
||||||
|
switch (direction) { // And set correct velocity
|
||||||
|
case Common::KEYCODE_UP:
|
||||||
|
obj->vy = -DY;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_DOWN:
|
||||||
|
obj->vy = DY;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_LEFT:
|
||||||
|
obj->vx = -DX;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_RIGHT:
|
||||||
|
obj->vx = DX;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_HOME:
|
||||||
|
obj->vx = -DX;
|
||||||
|
obj->vy = -DY / 2;
|
||||||
|
break;
|
||||||
|
case Common::KEYCODE_END:
|
||||||
|
obj->vx = -DX;
|
||||||
|
obj->vy = DY / 2;
|
||||||
|
break;
|
||||||
|
// case Common::KEYCODE_PRIOR:
|
||||||
|
// obj->vx = DX;
|
||||||
|
// obj->vy = -DY / 2;
|
||||||
|
// break;
|
||||||
|
// case Common::KEYCODE_NEXT:
|
||||||
|
// obj->vx = DX;
|
||||||
|
// obj->vy = DY / 2;
|
||||||
|
// break;
|
||||||
|
}
|
||||||
|
oldDirection = direction;
|
||||||
|
obj->cycling = CYCLE_FORWARD;
|
||||||
|
} else {
|
||||||
|
// Same key twice - halt hero
|
||||||
|
obj->vy = 0;
|
||||||
|
obj->vx = 0;
|
||||||
|
oldDirection = 0;
|
||||||
|
obj->cycling = NOT_CYCLING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Recursive algorithm! Searches from hero to dest_x, dest_y
|
||||||
|
// Find horizontal line segment about supplied point and recursively
|
||||||
|
// find line segments for each point above and below that segment.
|
||||||
|
// When destination point found in segment, start surfacing and leave
|
||||||
|
// a trail in segment[] from destination back to hero.
|
||||||
|
//
|
||||||
|
// Note: there is a bug which allows a route through a 1-pixel high
|
||||||
|
// narrow gap if between 2 segments wide enough for hero. To work
|
||||||
|
// around this, make sure any narrow gaps are 2 or more pixels high.
|
||||||
|
// An example of this was the blocking guard in Hugo1/Dead-End.
|
||||||
|
void Route::segment(int16 x, int16 y) {
|
||||||
|
int16 x1, x2; // Range of segment
|
||||||
|
// Note use of static - can't waste stack
|
||||||
|
static image_pt p; // Ptr to _boundaryMap[y]
|
||||||
|
static segment_t *seg_p; // Ptr to segment
|
||||||
|
|
||||||
|
debugC(1, kDebugRoute, "segment(%d, %d)", x, y);
|
||||||
|
|
||||||
|
// Bomb out if stack exhausted
|
||||||
|
// Vinterstum: Is this just a safeguard, or actually used?
|
||||||
|
//_fullStackFl = _stackavail () < 256;
|
||||||
|
_fullStackFl = false;
|
||||||
|
|
||||||
|
// Find and fill on either side of point
|
||||||
|
p = _boundaryMap[y];
|
||||||
|
for (x1 = x; x1 > 0; x1--)
|
||||||
|
if (p[x1] == 0) {
|
||||||
|
#if DEBUG_ROUTE
|
||||||
|
SetPixel(hDC, (int16)((long)config.cx * x1 / XPIX), (int16)((long)config.cy *(y - DIBOFF_Y) / VIEW_DY), GetPalIndex(_TLIGHTMAGENTA));
|
||||||
|
#endif
|
||||||
|
p[x1] = kMapFill;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
for (x2 = x + 1; x2 < XPIX; x2++)
|
||||||
|
if (p[x2] == 0) {
|
||||||
|
#if DEBUG_ROUTE
|
||||||
|
SetPixel(hDC, (int16)((long)config.cx * x2 / XPIX), (int16)((long)config.cy *(y - DIBOFF_Y) / VIEW_DY), GetPalIndex(_TLIGHTGREEN));
|
||||||
|
#endif
|
||||||
|
p[x2] = kMapFill;
|
||||||
|
} else
|
||||||
|
break;
|
||||||
|
x1++;
|
||||||
|
x2--;
|
||||||
|
|
||||||
|
// Discard path if not wide enough for hero - dead end
|
||||||
|
if (_heroWidth > x2 - x1 + 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Have we found the destination yet?
|
||||||
|
if (y == _destY && x1 <= _destX && x2 >= _destX)
|
||||||
|
_routeFoundFl = true;
|
||||||
|
|
||||||
|
// Bounds check y in case no boundary around screen
|
||||||
|
if (y <= 0 || y >= YPIX - 1)
|
||||||
|
return;
|
||||||
|
#if FALSE
|
||||||
|
// Find all segments above and below current
|
||||||
|
if (hero_p->x < x1 || hero_p->x + HERO_MAX_WIDTH > x2) {
|
||||||
|
// Hero x not in segment, search x1..x2
|
||||||
|
// Find all segments above current
|
||||||
|
for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
|
||||||
|
if (_boundaryMap[y - 1][x] == 0)
|
||||||
|
segment(x, y - 1);
|
||||||
|
|
||||||
|
// Find all segments below current
|
||||||
|
for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
|
||||||
|
if (_boundaryMap[y + 1][x] == 0)
|
||||||
|
segment(x, y + 1);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
if (_vm._hero->x < x1) {
|
||||||
|
// Hero x not in segment, search x1..x2
|
||||||
|
// Find all segments above current
|
||||||
|
for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
|
||||||
|
if (_boundaryMap[y - 1][x] == 0)
|
||||||
|
segment(x, y - 1);
|
||||||
|
|
||||||
|
// Find all segments below current
|
||||||
|
for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
|
||||||
|
if (_boundaryMap[y + 1][x] == 0)
|
||||||
|
segment(x, y + 1);
|
||||||
|
} else if (_vm._hero->x + HERO_MAX_WIDTH > x2) {
|
||||||
|
// Hero x not in segment, search x1..x2
|
||||||
|
// Find all segments above current
|
||||||
|
for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--)
|
||||||
|
if (_boundaryMap[y - 1][x] == 0)
|
||||||
|
segment(x, y - 1);
|
||||||
|
|
||||||
|
// Find all segments below current
|
||||||
|
for (x = x2; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x >= x1; x--)
|
||||||
|
if (_boundaryMap[y + 1][x] == 0)
|
||||||
|
segment(x, y + 1);
|
||||||
|
} else {
|
||||||
|
// Organize search around hero x position - this gives
|
||||||
|
// better chance for more direct route.
|
||||||
|
for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
|
||||||
|
if (_boundaryMap[y - 1][x] == 0)
|
||||||
|
segment(x, y - 1);
|
||||||
|
for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++)
|
||||||
|
if (_boundaryMap[y - 1][x] == 0)
|
||||||
|
segment(x, y - 1);
|
||||||
|
for (x = _vm._hero->x; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x <= x2; x++)
|
||||||
|
if (_boundaryMap[y + 1][x] == 0)
|
||||||
|
segment(x, y + 1);
|
||||||
|
for (x = x1; !(_routeFoundFl | _fullStackFl | _fullSegmentFl) && x < _vm._hero->x; x++)
|
||||||
|
if (_boundaryMap[y + 1][x] == 0)
|
||||||
|
segment(x, y + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If found, surface, leaving trail back to hero
|
||||||
|
if (_routeFoundFl) {
|
||||||
|
// Bomb out if too many segments (leave one spare)
|
||||||
|
if (_segmentNumb >= kMaxSeg - 1)
|
||||||
|
_fullSegmentFl = true;
|
||||||
|
else {
|
||||||
|
// Create segment
|
||||||
|
seg_p = &_segment[_segmentNumb];
|
||||||
|
seg_p->y = y;
|
||||||
|
seg_p->x1 = x1;
|
||||||
|
seg_p->x2 = x2;
|
||||||
|
_segmentNumb++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create and return ptr to new node. Initialize with previous node.
|
||||||
|
// Returns NULL if MAX_NODES exceeded
|
||||||
|
Point *Route::newNode() {
|
||||||
|
debugC(1, kDebugRoute, "newNode");
|
||||||
|
|
||||||
|
if (_routeListIndex >= kMaxNodes) // Too many nodes
|
||||||
|
return(NULL); // Incomplete route - failure
|
||||||
|
_routeListIndex++;
|
||||||
|
_route[_routeListIndex] = _route[_routeListIndex - 1]; // Initialize with previous node
|
||||||
|
return(&_route[_routeListIndex]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct route to cx, cy. Return TRUE if successful.
|
||||||
|
// 1. Copy boundary bitmap to local byte map (include object bases)
|
||||||
|
// 2. Construct list of segments segment[] from hero to destination
|
||||||
|
// 3. Compress to shortest route in route[]
|
||||||
|
bool Route::findRoute(int16 cx, int16 cy) {
|
||||||
|
int16 i, j, x, y; // Loop on coordinates
|
||||||
|
int16 x1, x2, dx; // Overlap between segments
|
||||||
|
int16 herox1, herox2, heroy; // Current hero baseline
|
||||||
|
object_t *obj; // Ptr to object
|
||||||
|
segment_t *seg_p; // Ptr to segment
|
||||||
|
Point *routeNode; // Ptr to route node
|
||||||
|
|
||||||
|
debugC(1, kDebugRoute, "findRoute(%d, %d)", cx, cy);
|
||||||
|
|
||||||
|
// Initialize for search
|
||||||
|
_routeFoundFl = false; // Path not found yet
|
||||||
|
_fullStackFl = false; // Stack not exhausted
|
||||||
|
_fullSegmentFl = false; // Segments not exhausted
|
||||||
|
_segmentNumb = 0; // Segment index
|
||||||
|
_heroWidth = HERO_MIN_WIDTH; // Minimum width of hero
|
||||||
|
_destY = cy; // Destination coords
|
||||||
|
_destX = cx; // Destination coords
|
||||||
|
herox1 = _vm._hero->x + _vm._hero->currImagePtr->x1; // Hero baseline
|
||||||
|
herox2 = _vm._hero->x + _vm._hero->currImagePtr->x2; // Hero baseline
|
||||||
|
heroy = _vm._hero->y + _vm._hero->currImagePtr->y2; // Hero baseline
|
||||||
|
|
||||||
|
// Store all object baselines into objbound (except hero's = [0])
|
||||||
|
for (i = 1, obj = &_vm._objects[i]; i < _vm._numObj; i++, obj++)
|
||||||
|
if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
|
||||||
|
_vm.storeBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
|
||||||
|
|
||||||
|
// Combine objbound and boundary bitmaps to local byte map
|
||||||
|
for (y = 0; y < YPIX; y++)
|
||||||
|
for (x = 0; x < XBYTES; x++)
|
||||||
|
for (i = 0; i < 8; i++)
|
||||||
|
_boundaryMap[y][x * 8 + i] = ((_vm.getObjectBoundaryOverlay()[y * XBYTES + x] | _vm.getBoundaryOverlay()[y * XBYTES + x]) & (0x80 >> i)) ? kMapBound : 0;
|
||||||
|
|
||||||
|
// Clear all object baselines from objbound
|
||||||
|
for (i = 0, obj = _vm._objects; i < _vm._numObj; i++, obj++)
|
||||||
|
if ((obj->screenIndex == *_vm._screen_p) && (obj->cycling != INVISIBLE) && (obj->priority == FLOATING))
|
||||||
|
_vm.clearBoundary(obj->oldx + obj->currImagePtr->x1, obj->oldx + obj->currImagePtr->x2, obj->oldy + obj->currImagePtr->y2);
|
||||||
|
|
||||||
|
#if DEBUG_ROUTE
|
||||||
|
{
|
||||||
|
// hDC = GetDC(hview);
|
||||||
|
for (y = 0; y < YPIX; y++)
|
||||||
|
for (x = 0; x < XPIX; x++)
|
||||||
|
if (_boundaryMap[y][x])
|
||||||
|
SetPixel(hDC, (int16)((long)config.cx * x / XPIX), (int16)((long)config.cy *(y - DIBOFF_Y) / VIEW_DY), GetPalIndex(_TBRIGHTWHITE));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Search from hero to destination
|
||||||
|
segment(herox1, heroy);
|
||||||
|
|
||||||
|
//#if DEBUG_ROUTE
|
||||||
|
// ReleaseDC(hview, hDC);
|
||||||
|
//#endif
|
||||||
|
|
||||||
|
// Not found or not enough stack or MAX_SEG exceeded
|
||||||
|
if (!_routeFoundFl || _fullStackFl || _fullSegmentFl) {
|
||||||
|
#if DEBUG_ROUTE
|
||||||
|
Box(BOX_ANY, "%s", (_fullStackFl) ? "Stack blown!" : (_fullSegmentFl) ? "Ran out of segments!" : "No Route!");
|
||||||
|
#endif
|
||||||
|
return(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now find the route of nodes from destination back to hero
|
||||||
|
// Assign first node as destination
|
||||||
|
_route[0].x = _destX;
|
||||||
|
_route[0].y = _destY;
|
||||||
|
|
||||||
|
// Make a final segment for hero's base (we left a spare)
|
||||||
|
_segment[_segmentNumb].y = heroy;
|
||||||
|
_segment[_segmentNumb].x1 = herox1;
|
||||||
|
_segment[_segmentNumb].x2 = herox2;
|
||||||
|
_segmentNumb++;
|
||||||
|
|
||||||
|
// Look in segments[] for straight lines from destination to hero
|
||||||
|
for (i = 0, _routeListIndex = 0; i < _segmentNumb - 1; i++) {
|
||||||
|
if ((routeNode = newNode()) == NULL) // New node for new segment
|
||||||
|
return(false); // Too many nodes
|
||||||
|
routeNode->y = _segment[i].y;
|
||||||
|
|
||||||
|
// Look ahead for furthest straight line
|
||||||
|
for (j = i + 1; j < _segmentNumb; j++) {
|
||||||
|
seg_p = &_segment[j];
|
||||||
|
// Can we get to this segment from previous node?
|
||||||
|
if (seg_p->x1 <= routeNode->x && seg_p->x2 >= routeNode->x + _heroWidth - 1)
|
||||||
|
routeNode->y = seg_p->y; // Yes, keep updating node
|
||||||
|
else {
|
||||||
|
// No, create another node on previous segment to reach it
|
||||||
|
if ((routeNode = newNode()) == NULL) // Add new route node
|
||||||
|
return (false); // Too many nodes
|
||||||
|
|
||||||
|
// Find overlap between old and new segments
|
||||||
|
x1 = MAX(_segment[j - 1].x1, seg_p->x1);
|
||||||
|
x2 = MIN(_segment[j - 1].x2, seg_p->x2);
|
||||||
|
|
||||||
|
// If room, add a little offset to reduce staircase effect
|
||||||
|
dx = HERO_MAX_WIDTH >> 1;
|
||||||
|
if (x2 - x1 < _heroWidth + dx)
|
||||||
|
dx = 0;
|
||||||
|
|
||||||
|
// Bear toward final hero position
|
||||||
|
if (j == _segmentNumb - 1)
|
||||||
|
routeNode->x = herox1;
|
||||||
|
else if (herox1 < x1)
|
||||||
|
routeNode->x = x1 + dx;
|
||||||
|
else if (herox1 > x2 - _heroWidth + 1)
|
||||||
|
routeNode->x = x2 - _heroWidth - dx;
|
||||||
|
else
|
||||||
|
routeNode->x = herox1;
|
||||||
|
i = j - 2; // Restart segment (-1 to offset auto increment)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminate loop if we've reached hero
|
||||||
|
if (routeNode->x == herox1 && routeNode->y == heroy)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Process hero in route mode - called from Move_objects()
|
||||||
|
void Route::processRoute() {
|
||||||
|
int16 herox, heroy; // Hero position
|
||||||
|
Point *routeNode; // Ptr to current route node
|
||||||
|
static bool turnedFl = false; // Used to get extra cylce for turning
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
debugC(1, kDebugRoute, "processRoute");
|
||||||
|
|
||||||
|
// Current hero position
|
||||||
|
herox = _vm._hero->x + _vm._hero->currImagePtr->x1;
|
||||||
|
heroy = _vm._hero->y + _vm._hero->currImagePtr->y2;
|
||||||
|
routeNode = &_route[gameStatus.routeIndex];
|
||||||
|
|
||||||
|
// Arrived at node?
|
||||||
|
if (abs(herox - routeNode->x) < DX + 1 && abs(heroy - routeNode->y) < DY) {
|
||||||
|
// DX too low
|
||||||
|
// Close enough - position hero exactly
|
||||||
|
_vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
|
||||||
|
_vm._hero->y = _vm._hero->oldy = routeNode->y - _vm._hero->currImagePtr->y2;
|
||||||
|
_vm._hero->vx = _vm._hero->vy = 0;
|
||||||
|
_vm._hero->cycling = NOT_CYCLING;
|
||||||
|
|
||||||
|
// Arrived at final node?
|
||||||
|
if (--gameStatus.routeIndex < 0) {
|
||||||
|
// See why we walked here
|
||||||
|
switch (gameStatus.go_for) {
|
||||||
|
case GO_EXIT: // Walked to an exit, proceed into it
|
||||||
|
setWalk(_vm._hotspots[gameStatus.go_id].direction);
|
||||||
|
break;
|
||||||
|
case GO_LOOK: // Look at an object
|
||||||
|
if (turnedFl) {
|
||||||
|
_vm.lookObject(&_vm._objects[gameStatus.go_id]);
|
||||||
|
turnedFl = false;
|
||||||
|
} else {
|
||||||
|
setDirection(_vm._objects[gameStatus.go_id].direction);
|
||||||
|
gameStatus.routeIndex++; // Come round again
|
||||||
|
turnedFl = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GO_GET: // Get (or use) an object
|
||||||
|
if (turnedFl) {
|
||||||
|
_vm.useObject(gameStatus.go_id);
|
||||||
|
turnedFl = false;
|
||||||
|
} else {
|
||||||
|
setDirection(_vm._objects[gameStatus.go_id].direction);
|
||||||
|
gameStatus.routeIndex++; // Come round again
|
||||||
|
turnedFl = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GO_SPACE:
|
||||||
|
warning("Unhandled gameStatus.go_for GO_STATUS");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (_vm._hero->vx == 0 && _vm._hero->vy == 0) {
|
||||||
|
// Set direction of travel if at a node
|
||||||
|
// Note realignment when changing to (thinner) up/down sprite,
|
||||||
|
// otherwise hero could bump into boundaries along route.
|
||||||
|
if (herox < routeNode->x)
|
||||||
|
setWalk(Common::KEYCODE_RIGHT);
|
||||||
|
else if (herox > routeNode->x)
|
||||||
|
setWalk(Common::KEYCODE_LEFT);
|
||||||
|
else if (heroy < routeNode->y) {
|
||||||
|
setWalk(Common::KEYCODE_DOWN);
|
||||||
|
_vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
|
||||||
|
} else if (heroy > routeNode->y) {
|
||||||
|
setWalk(Common::KEYCODE_UP);
|
||||||
|
_vm._hero->x = _vm._hero->oldx = routeNode->x - _vm._hero->currImagePtr->x1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Start a new route from hero to cx, cy
|
||||||
|
// go_for is the purpose, id indexes the exit or object to walk to
|
||||||
|
// Returns FALSE if route not found
|
||||||
|
bool Route::startRoute(go_t go_for, int16 id, int16 cx, int16 cy) {
|
||||||
|
bool foundFl = false; // TRUE if route found ok
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
debugC(1, kDebugRoute, "startRoute(%d, %d, %d, %d)", go_for, id, cx, cy);
|
||||||
|
|
||||||
|
// Don't attempt to walk if user does not have control
|
||||||
|
if (_vm._hero->pathType != USER)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// if inventory showing, make it go away
|
||||||
|
if (gameStatus.inventoryState != I_OFF)
|
||||||
|
gameStatus.inventoryState = I_UP;
|
||||||
|
|
||||||
|
gameStatus.go_for = go_for; // Purpose of trip
|
||||||
|
gameStatus.go_id = id; // Index of exit/object
|
||||||
|
|
||||||
|
// Adjust destination to center hero if walking to cursor
|
||||||
|
if (gameStatus.go_for == GO_SPACE)
|
||||||
|
cx -= HERO_MIN_WIDTH / 2;
|
||||||
|
|
||||||
|
if ((foundFl = findRoute(cx, cy))) { // Found a route?
|
||||||
|
gameStatus.routeIndex = _routeListIndex; // Node index
|
||||||
|
_vm._hero->vx = _vm._hero->vy = 0; // Stop manual motion
|
||||||
|
}
|
||||||
|
|
||||||
|
return foundFl;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
84
engines/hugo/route.h
Executable file
84
engines/hugo/route.h
Executable file
|
@ -0,0 +1,84 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_ROUTE_H
|
||||||
|
#define HUGO_ROUTE_H
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define kMapBound 1 // Mark a boundary outline
|
||||||
|
#define kMapFill 2 // Mark a boundary filled
|
||||||
|
#define kMaxSeg 256 // Maximum number of segments
|
||||||
|
#define kMaxNodes 256 // Maximum nodes in route
|
||||||
|
#define DEBUG_ROUTE FALSE
|
||||||
|
|
||||||
|
struct Point {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct segment_t { // Search segment
|
||||||
|
int16 y; // y position
|
||||||
|
int16 x1, x2; // Range of segment
|
||||||
|
};
|
||||||
|
|
||||||
|
class Route {
|
||||||
|
public:
|
||||||
|
Route(HugoEngine &vm);
|
||||||
|
|
||||||
|
void processRoute();
|
||||||
|
bool startRoute(go_t go_for, short id, short cx, short cy);
|
||||||
|
void setDirection(uint16 keyCode);
|
||||||
|
void setWalk(uint16 direction);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
|
||||||
|
byte _boundaryMap[YPIX][XPIX]; // Boundary byte map
|
||||||
|
segment_t _segment[kMaxSeg]; // List of points in fill-path
|
||||||
|
Point _route[kMaxNodes]; // List of nodes in route (global)
|
||||||
|
int16 _segmentNumb; // Count number of segments
|
||||||
|
int16 _routeListIndex; // Index into route list
|
||||||
|
int16 _destX;
|
||||||
|
int16 _destY;
|
||||||
|
int16 _heroWidth; // Hero width
|
||||||
|
bool _routeFoundFl; // TRUE when path found
|
||||||
|
bool _fullStackFl; // TRUE if stack exhausted
|
||||||
|
bool _fullSegmentFl; // Segments exhausted
|
||||||
|
|
||||||
|
void segment(int16 x, int16 y);
|
||||||
|
bool findRoute(int16 cx, int16 cy);
|
||||||
|
Point *newNode();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif //HUGO_ROUTE_H
|
677
engines/hugo/schedule.cpp
Executable file
677
engines/hugo/schedule.cpp
Executable file
|
@ -0,0 +1,677 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
// This module contains all the scheduling and timing stuff
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
#include "common/stream.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/schedule.h"
|
||||||
|
#include "hugo/global.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/display.h"
|
||||||
|
#include "hugo/parser.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
#include "hugo/sound.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define SIGN(X) (X < 0 ? -1 : 1)
|
||||||
|
|
||||||
|
Scheduler::Scheduler(HugoEngine &vm) : _vm(vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialise the timer event queue
|
||||||
|
void Scheduler::initEventQueue() {
|
||||||
|
debugC(1, kDebugSchedule, "initEventQueue");
|
||||||
|
|
||||||
|
// Chain next_p from first to last
|
||||||
|
for (int i = kMaxEvents; --i;)
|
||||||
|
_events[i - 1].nextEvent = &_events[i];
|
||||||
|
_events[kMaxEvents - 1].nextEvent = 0;
|
||||||
|
|
||||||
|
// Chain prev_p from last to first
|
||||||
|
for (int i = 1; i < kMaxEvents; i++)
|
||||||
|
_events[i].prevEvent = &_events[i - 1];
|
||||||
|
_events[0].prevEvent = 0;
|
||||||
|
|
||||||
|
_headEvent = _tailEvent = 0; // Event list is empty
|
||||||
|
_freeEvent = _events; // Free list is full
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return a ptr to an event structure from the free list
|
||||||
|
event_t *Scheduler::getQueue() {
|
||||||
|
debugC(4, kDebugSchedule, "getQueue");
|
||||||
|
event_t *resEvent;
|
||||||
|
|
||||||
|
if (!_freeEvent) // Error: no more events available
|
||||||
|
Utils::Error(EVNT_ERR, "getQueue");
|
||||||
|
resEvent = _freeEvent;
|
||||||
|
_freeEvent = _freeEvent->nextEvent;
|
||||||
|
resEvent->nextEvent = 0;
|
||||||
|
return resEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete an event structure (i.e. return it to the free list)
|
||||||
|
// Historical note: Originally event p was assumed to be at head of queue
|
||||||
|
// (i.e. earliest) since all events were deleted in order when proceeding to
|
||||||
|
// a new screen. To delete an event from the middle of the queue, the action
|
||||||
|
// was overwritten to be ANULL. With the advent of GLOBAL events, Del_queue
|
||||||
|
// was modified to allow deletes anywhere in the list, and the DEL_EVENT
|
||||||
|
// action was modified to perform the actual delete.
|
||||||
|
void Scheduler::delQueue(event_t *curEvent) {
|
||||||
|
debugC(4, kDebugSchedule, "delQueue");
|
||||||
|
if (curEvent == _headEvent) // If p was the head ptr
|
||||||
|
_headEvent = curEvent->nextEvent; // then make new head_p
|
||||||
|
else { // Unlink p
|
||||||
|
curEvent->prevEvent->nextEvent = curEvent->nextEvent;
|
||||||
|
if (curEvent->nextEvent)
|
||||||
|
curEvent->nextEvent->prevEvent = curEvent->prevEvent;
|
||||||
|
else
|
||||||
|
_tailEvent = curEvent->prevEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_headEvent)
|
||||||
|
_headEvent->prevEvent = 0; // Mark end of list
|
||||||
|
else
|
||||||
|
_tailEvent = 0; // Empty queue
|
||||||
|
|
||||||
|
curEvent->nextEvent = _freeEvent; // Return p to free list
|
||||||
|
if (_freeEvent) // Special case, if free list was empty
|
||||||
|
_freeEvent->prevEvent = curEvent;
|
||||||
|
_freeEvent = curEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Insert the action pointed to by p into the timer event queue
|
||||||
|
// The queue goes from head (earliest) to tail (latest) timewise
|
||||||
|
void Scheduler::insertAction(act *action) {
|
||||||
|
debugC(1, kDebugSchedule, "insertAction - Action type A%d", action->a0.actType);
|
||||||
|
|
||||||
|
// First, get and initialise the event structure
|
||||||
|
event_t *curEvent = getQueue();
|
||||||
|
curEvent->action = action;
|
||||||
|
switch (action->a0.actType) { // Assign whether local or global
|
||||||
|
case AGSCHEDULE:
|
||||||
|
curEvent->localActionFl = false; // Lasts over a new screen
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
curEvent->localActionFl = true; // Rest are for current screen only
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
curEvent->time = action->a0.timer + getTicks(); // Convert rel to abs time
|
||||||
|
|
||||||
|
// Now find the place to insert the event
|
||||||
|
if (!_tailEvent) { // Empty queue
|
||||||
|
_tailEvent = _headEvent = curEvent;
|
||||||
|
curEvent->nextEvent = curEvent->prevEvent = NULL;
|
||||||
|
} else {
|
||||||
|
event_t *wrkEvent = _tailEvent; // Search from latest time back
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
while (wrkEvent && !found) {
|
||||||
|
if (wrkEvent->time <= curEvent->time) { // Found if new event later
|
||||||
|
found = true;
|
||||||
|
if (wrkEvent == _tailEvent) // New latest in list
|
||||||
|
_tailEvent = curEvent;
|
||||||
|
else
|
||||||
|
wrkEvent->nextEvent->prevEvent = curEvent;
|
||||||
|
curEvent->nextEvent = wrkEvent->nextEvent;
|
||||||
|
wrkEvent->nextEvent = curEvent;
|
||||||
|
curEvent->prevEvent = wrkEvent;
|
||||||
|
}
|
||||||
|
wrkEvent = wrkEvent->prevEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) { // Must be earliest in list
|
||||||
|
_headEvent->prevEvent = curEvent; // So insert as new head
|
||||||
|
curEvent->nextEvent = _headEvent;
|
||||||
|
curEvent->prevEvent = NULL;
|
||||||
|
_headEvent = curEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::insertActionList(uint16 actIndex) {
|
||||||
|
// Call Insert_action for each action in the list supplied
|
||||||
|
debugC(1, kDebugSchedule, "insertActionList(%d)", actIndex);
|
||||||
|
|
||||||
|
if (_vm._actListArr[actIndex])
|
||||||
|
for (int i = 0; _vm._actListArr[actIndex][i].a0.actType != ANULL; i++)
|
||||||
|
insertAction(&_vm._actListArr[actIndex][i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::decodeString(char *line) {
|
||||||
|
// Decode a string
|
||||||
|
debugC(1, kDebugSchedule, "decodeString(%s)", line);
|
||||||
|
|
||||||
|
static char cypher[] = "Copyright 1992, Gray Design Associates";
|
||||||
|
|
||||||
|
for (uint16 i = 0; i < strlen(line); i++)
|
||||||
|
line[i] -= cypher[i % strlen(cypher)];
|
||||||
|
debugC(1, kDebugSchedule, "result : %s", line);
|
||||||
|
}
|
||||||
|
|
||||||
|
event_t *Scheduler::doAction(event_t *curEvent) {
|
||||||
|
// This function performs the action in the event structure pointed to by p
|
||||||
|
// It dequeues the event and returns it to the free list. It returns a ptr
|
||||||
|
// to the next action in the list, except special case of NEW_SCREEN
|
||||||
|
event_t *wrkEvent; // Save ev_p->next_p for return
|
||||||
|
event_t *saveEvent; // Used in DEL_EVENTS
|
||||||
|
char *response; // User's response string
|
||||||
|
object_t *obj1;
|
||||||
|
object_t *obj2;
|
||||||
|
int dx, dy;
|
||||||
|
act *action; // Ptr to action structure
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
action = curEvent->action;
|
||||||
|
debugC(1, kDebugSchedule, "doAction - Event action type : %d", action->a0.actType);
|
||||||
|
|
||||||
|
switch (action->a0.actType) {
|
||||||
|
case ANULL: // Big NOP from DEL_EVENTS
|
||||||
|
break;
|
||||||
|
case ASCHEDULE: // act0: Schedule an action list
|
||||||
|
insertActionList(action->a0.actIndex);
|
||||||
|
break;
|
||||||
|
case START_OBJ: // act1: Start an object cycling
|
||||||
|
_vm._objects[action->a1.objNumb].cycleNumb = action->a1.cycleNumb;
|
||||||
|
_vm._objects[action->a1.objNumb].cycling = action->a1.cycle;
|
||||||
|
break;
|
||||||
|
case INIT_OBJXY: // act2: Initialise an object
|
||||||
|
_vm._objects[action->a2.objNumb].x = action->a2.x; // Coordinates
|
||||||
|
_vm._objects[action->a2.objNumb].y = action->a2.y;
|
||||||
|
break;
|
||||||
|
case PROMPT: // act3: Prompt user for key phrase
|
||||||
|
// TODO : Add specific code for Hugo 1 DOS, which is handled differently,
|
||||||
|
response = Utils::Box(BOX_PROMPT, _vm.file().fetchString(action->a3.promptIndex));
|
||||||
|
|
||||||
|
warning("STUB: doAction(act3), expecting answer %s", response);
|
||||||
|
|
||||||
|
// TODO : The answer of the player is not handled currently! Once it'll be read in the messageBox, uncomment this block
|
||||||
|
#if 0
|
||||||
|
bool found;
|
||||||
|
char *tmpStr; // General purpose string ptr
|
||||||
|
|
||||||
|
for (found = false, dx = 0; !found && (action->a3.responsePtr[dx] != -1); dx++) {
|
||||||
|
tmpStr = _vm.file().Fetch_string(action->a3.responsePtr[dx]);
|
||||||
|
if (strstr(_vm.parser().strlwr(response) , tmpStr))
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (found)
|
||||||
|
insertActionList(action->a3.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a3.actFailIndex);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//HACK: As the answer is not read, currently it's always considered correct
|
||||||
|
insertActionList(action->a3.actPassIndex);
|
||||||
|
break;
|
||||||
|
case BKGD_COLOR: // act4: Set new background color
|
||||||
|
HugoEngine::get().screen().setBackgroundColor(action->a4.newBackgroundColor);
|
||||||
|
break;
|
||||||
|
case INIT_OBJVXY: // act5: Initialise an object
|
||||||
|
_vm._objects[action->a5.objNumb].vx = action->a5.vx; // velocities
|
||||||
|
_vm._objects[action->a5.objNumb].vy = action->a5.vy;
|
||||||
|
break;
|
||||||
|
case INIT_CARRY: // act6: Initialise an object
|
||||||
|
_vm._objects[action->a6.objNumb].carriedFl = action->a6.carriedFl; // carried status
|
||||||
|
break;
|
||||||
|
case INIT_HF_COORD: // act7: Initialise an object to hero's "feet" coords
|
||||||
|
_vm._objects[action->a7.objNumb].x = _vm._hero->x - 1;
|
||||||
|
_vm._objects[action->a7.objNumb].y = _vm._hero->y + _vm._hero->currImagePtr->y2 - 1;
|
||||||
|
_vm._objects[action->a7.objNumb].screenIndex = *_vm._screen_p; // Don't forget screen!
|
||||||
|
break;
|
||||||
|
case NEW_SCREEN: // act8: Start new screen
|
||||||
|
newScreen(action->a8.screenIndex);
|
||||||
|
break;
|
||||||
|
case INIT_OBJSTATE: // act9: Initialise an object state
|
||||||
|
_vm._objects[action->a9.objNumb].state = action->a9.newState;
|
||||||
|
break;
|
||||||
|
case INIT_PATH: // act10: Initialise an object path and velocity
|
||||||
|
_vm._objects[action->a10.objNumb].pathType = (path_t) action->a10.newPathType;
|
||||||
|
_vm._objects[action->a10.objNumb].vxPath = action->a10.vxPath;
|
||||||
|
_vm._objects[action->a10.objNumb].vyPath = action->a10.vyPath;
|
||||||
|
break;
|
||||||
|
case COND_R: // act11: action lists conditional on object state
|
||||||
|
if (_vm._objects[action->a11.objNumb].state == action->a11.stateReq)
|
||||||
|
insertActionList(action->a11.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a11.actFailIndex);
|
||||||
|
break;
|
||||||
|
case TEXT: // act12: Text box (CF WARN)
|
||||||
|
Utils::Box(BOX_ANY, _vm.file().fetchString(action->a12.stringIndex)); // Fetch string from file
|
||||||
|
break;
|
||||||
|
case SWAP_IMAGES: // act13: Swap 2 object images
|
||||||
|
swapImages(action->a13.obj1, action->a13.obj2);
|
||||||
|
break;
|
||||||
|
case COND_SCR: // act14: Conditional on current screen
|
||||||
|
if (_vm._objects[action->a14.objNumb].screenIndex == action->a14.screenReq)
|
||||||
|
insertActionList(action->a14.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a14.actFailIndex);
|
||||||
|
break;
|
||||||
|
case AUTOPILOT: // act15: Home in on a (stationary) object
|
||||||
|
// object p1 will home in on object p2
|
||||||
|
obj1 = &_vm._objects[action->a15.obj1];
|
||||||
|
obj2 = &_vm._objects[action->a15.obj2];
|
||||||
|
obj1->pathType = AUTO;
|
||||||
|
dx = obj1->x + obj1->currImagePtr->x1 - obj2->x - obj2->currImagePtr->x1;
|
||||||
|
dy = obj1->y + obj1->currImagePtr->y1 - obj2->y - obj2->currImagePtr->y1;
|
||||||
|
|
||||||
|
if (dx == 0) // Don't EVER divide by zero!
|
||||||
|
dx = 1;
|
||||||
|
if (dy == 0)
|
||||||
|
dy = 1;
|
||||||
|
|
||||||
|
if (abs(dx) > abs(dy)) {
|
||||||
|
obj1->vx = action->a15.dx * -SIGN(dx);
|
||||||
|
obj1->vy = abs((action->a15.dy * dy) / dx) * -SIGN(dy);
|
||||||
|
} else {
|
||||||
|
obj1->vy = action->a15.dy * -SIGN(dy);
|
||||||
|
obj1->vx = abs((action->a15.dx * dx) / dy) * -SIGN(dx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case INIT_OBJ_SEQ: // act16: Set sequence number to use
|
||||||
|
// Note: Don't set a sequence at time 0 of a new screen, it causes
|
||||||
|
// problems clearing the boundary bits of the object! t>0 is safe
|
||||||
|
_vm._objects[action->a16.objNumb].currImagePtr = _vm._objects[action->a16.objNumb].seqList[action->a16.seqIndex].seqPtr;
|
||||||
|
break;
|
||||||
|
case SET_STATE_BITS: // act17: OR mask with curr obj state
|
||||||
|
_vm._objects[action->a17.objNumb].state |= action->a17.stateMask;
|
||||||
|
break;
|
||||||
|
case CLEAR_STATE_BITS: // act18: AND ~mask with curr obj state
|
||||||
|
_vm._objects[action->a18.objNumb].state &= ~action->a18.stateMask;
|
||||||
|
break;
|
||||||
|
case TEST_STATE_BITS: // act19: If all bits set, do apass else afail
|
||||||
|
if ((_vm._objects[action->a19.objNumb].state & action->a19.stateMask) == action->a19.stateMask)
|
||||||
|
insertActionList(action->a19.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a19.actFailIndex);
|
||||||
|
break;
|
||||||
|
case DEL_EVENTS: // act20: Remove all events of this action type
|
||||||
|
// Note: actions are not deleted here, simply turned into NOPs!
|
||||||
|
wrkEvent = _headEvent; // The earliest event
|
||||||
|
while (wrkEvent) { // While events found in list
|
||||||
|
saveEvent = wrkEvent->nextEvent;
|
||||||
|
if (wrkEvent->action->a20.actType == action->a20.actTypeDel)
|
||||||
|
delQueue(wrkEvent);
|
||||||
|
wrkEvent = saveEvent;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case GAMEOVER: // act21: Game over!
|
||||||
|
// NOTE: Must wait at least 1 tick before issuing this action if
|
||||||
|
// any objects are to be made invisible!
|
||||||
|
gameStatus.gameOverFl = true;
|
||||||
|
break;
|
||||||
|
case INIT_HH_COORD: // act22: Initialise an object to hero's actual coords
|
||||||
|
_vm._objects[action->a22.objNumb].x = _vm._hero->x;
|
||||||
|
_vm._objects[action->a22.objNumb].y = _vm._hero->y;
|
||||||
|
_vm._objects[action->a22.objNumb].screenIndex = *_vm._screen_p;// Don't forget screen!
|
||||||
|
break;
|
||||||
|
case EXIT: // act23: Exit game back to DOS
|
||||||
|
_vm.endGame();
|
||||||
|
break;
|
||||||
|
case BONUS: // act24: Get bonus score for action
|
||||||
|
processBonus(action->a24.pointIndex);
|
||||||
|
break;
|
||||||
|
case COND_BOX: // act25: Conditional on bounding box
|
||||||
|
obj1 = &_vm._objects[action->a25.objNumb];
|
||||||
|
dx = obj1->x + obj1->currImagePtr->x1;
|
||||||
|
dy = obj1->y + obj1->currImagePtr->y2;
|
||||||
|
if ((dx >= action->a25.x1) && (dx <= action->a25.x2) &&
|
||||||
|
(dy >= action->a25.y1) && (dy <= action->a25.y2))
|
||||||
|
insertActionList(action->a25.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a25.actFailIndex);
|
||||||
|
break;
|
||||||
|
case SOUND: // act26: Play a sound (or tune)
|
||||||
|
if (action->a26.soundIndex < _vm._tunesNbr)
|
||||||
|
_vm.sound().playMusic(action->a26.soundIndex);
|
||||||
|
else
|
||||||
|
_vm.sound().playSound(action->a26.soundIndex, BOTH_CHANNELS, MED_PRI);
|
||||||
|
break;
|
||||||
|
case ADD_SCORE: // act27: Add object's value to score
|
||||||
|
_vm.adjustScore(_vm._objects[action->a27.objNumb].objValue);
|
||||||
|
break;
|
||||||
|
case SUB_SCORE: // act28: Subtract object's value from score
|
||||||
|
_vm.adjustScore(-_vm._objects[action->a28.objNumb].objValue);
|
||||||
|
break;
|
||||||
|
case COND_CARRY: // act29: Conditional on object being carried
|
||||||
|
if (_vm._objects[action->a29.objNumb].carriedFl)
|
||||||
|
insertActionList(action->a29.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a29.actFailIndex);
|
||||||
|
break;
|
||||||
|
case INIT_MAZE: // act30: Enable and init maze structure
|
||||||
|
_maze.enabledFl = true;
|
||||||
|
_maze.size = action->a30.mazeSize;
|
||||||
|
_maze.x1 = action->a30.x1;
|
||||||
|
_maze.y1 = action->a30.y1;
|
||||||
|
_maze.x2 = action->a30.x2;
|
||||||
|
_maze.y2 = action->a30.y2;
|
||||||
|
_maze.x3 = action->a30.x3;
|
||||||
|
_maze.x4 = action->a30.x4;
|
||||||
|
_maze.firstScreenIndex = action->a30.firstScreenIndex;
|
||||||
|
break;
|
||||||
|
case EXIT_MAZE: // act31: Disable maze mode
|
||||||
|
_maze.enabledFl = false;
|
||||||
|
break;
|
||||||
|
case INIT_PRIORITY:
|
||||||
|
_vm._objects[action->a32.objNumb].priority = action->a32.priority;
|
||||||
|
break;
|
||||||
|
case INIT_SCREEN:
|
||||||
|
_vm._objects[action->a33.objNumb].screenIndex = action->a33.screenIndex;
|
||||||
|
break;
|
||||||
|
case AGSCHEDULE: // act34: Schedule a (global) action list
|
||||||
|
insertActionList(action->a34.actIndex);
|
||||||
|
break;
|
||||||
|
case REMAPPAL: // act35: Remap a palette color
|
||||||
|
HugoEngine::get().screen().remapPal(action->a35.oldColorIndex, action->a35.newColorIndex);
|
||||||
|
break;
|
||||||
|
case COND_NOUN: // act36: Conditional on noun mentioned
|
||||||
|
if (_vm.parser().isWordPresent(_vm._arrayNouns[action->a36.nounIndex]))
|
||||||
|
insertActionList(action->a36.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a36.actFailIndex);
|
||||||
|
break;
|
||||||
|
case SCREEN_STATE: // act37: Set new screen state
|
||||||
|
_vm._screenStates[action->a37.screenIndex] = action->a37.newState;
|
||||||
|
break;
|
||||||
|
case INIT_LIPS: // act38: Position lips on object
|
||||||
|
_vm._objects[action->a38.lipsObjNumb].x = _vm._objects[action->a38.objNumb].x + action->a38.dxLips;
|
||||||
|
_vm._objects[action->a38.lipsObjNumb].y = _vm._objects[action->a38.objNumb].y + action->a38.dyLips;
|
||||||
|
_vm._objects[action->a38.lipsObjNumb].screenIndex = *_vm._screen_p; // Don't forget screen!
|
||||||
|
_vm._objects[action->a38.lipsObjNumb].cycling = CYCLE_FORWARD;
|
||||||
|
break;
|
||||||
|
case INIT_STORY_MODE: // act39: Init story_mode flag
|
||||||
|
// This is similar to the QUIET path mode, except that it is
|
||||||
|
// independant of it and it additionally disables the ">" prompt
|
||||||
|
gameStatus.storyModeFl = action->a39.storyModeFl;
|
||||||
|
|
||||||
|
// End the game after story if this is special vendor demo mode
|
||||||
|
if (gameStatus.demoFl && action->a39.storyModeFl == false)
|
||||||
|
_vm.endGame();
|
||||||
|
break;
|
||||||
|
case WARN: // act40: Text box (CF TEXT)
|
||||||
|
Utils::Box(BOX_OK, _vm.file().fetchString(action->a40.stringIndex));
|
||||||
|
break;
|
||||||
|
case COND_BONUS: // act41: Perform action if got bonus
|
||||||
|
if (_vm._points[action->a41.BonusIndex].scoredFl)
|
||||||
|
insertActionList(action->a41.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a41.actFailIndex);
|
||||||
|
break;
|
||||||
|
case TEXT_TAKE: // act42: Text box with "take" message
|
||||||
|
Utils::Box(BOX_ANY, TAKE_TEXT, _vm._arrayNouns[_vm._objects[action->a42.objNumb].nounIndex][TAKE_NAME]);
|
||||||
|
break;
|
||||||
|
case YESNO: // act43: Prompt user for Yes or No
|
||||||
|
warning("doAction(act43) - Yes/No Box");
|
||||||
|
if (Utils::Box(BOX_YESNO, _vm.file().fetchString(action->a43.promptIndex)) != NULL)
|
||||||
|
insertActionList(action->a43.actYesIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a43.actNoIndex);
|
||||||
|
break;
|
||||||
|
case STOP_ROUTE: // act44: Stop any route in progress
|
||||||
|
gameStatus.routeIndex = -1;
|
||||||
|
break;
|
||||||
|
case COND_ROUTE: // act45: Conditional on route in progress
|
||||||
|
if (gameStatus.routeIndex >= action->a45.routeIndex)
|
||||||
|
insertActionList(action->a45.actPassIndex);
|
||||||
|
else
|
||||||
|
insertActionList(action->a45.actFailIndex);
|
||||||
|
break;
|
||||||
|
case INIT_JUMPEXIT: // act46: Init status.jumpexit flag
|
||||||
|
// This is to allow left click on exit to get there immediately
|
||||||
|
// For example the plane crash in Hugo2 where hero is invisible
|
||||||
|
// Couldn't use INVISIBLE flag since conflicts with boat in Hugo1
|
||||||
|
gameStatus.jumpExitFl = action->a46.jumpExitFl;
|
||||||
|
break;
|
||||||
|
case INIT_VIEW: // act47: Init object.viewx, viewy, dir
|
||||||
|
_vm._objects[action->a47.objNumb].viewx = action->a47.viewx;
|
||||||
|
_vm._objects[action->a47.objNumb].viewy = action->a47.viewy;
|
||||||
|
_vm._objects[action->a47.objNumb].direction = action->a47.direction;
|
||||||
|
break;
|
||||||
|
case INIT_OBJ_FRAME: // act48: Set seq,frame number to use
|
||||||
|
// Note: Don't set a sequence at time 0 of a new screen, it causes
|
||||||
|
// problems clearing the boundary bits of the object! t>0 is safe
|
||||||
|
_vm._objects[action->a48.objNumb].currImagePtr = _vm._objects[action->a48.objNumb].seqList[action->a48.seqIndex].seqPtr;
|
||||||
|
for (dx = 0; dx < action->a48.frameIndex; dx++)
|
||||||
|
_vm._objects[action->a48.objNumb].currImagePtr = _vm._objects[action->a48.objNumb].currImagePtr->nextSeqPtr;
|
||||||
|
break;
|
||||||
|
case OLD_SONG:
|
||||||
|
//TODO For Hugo 1 and Hugo2 DOS: The songs were not stored in a DAT file, but directly as
|
||||||
|
//strings. the current play_music should be modified to use a strings instead of reading
|
||||||
|
//the file, in those cases. This replaces, for those DOS versions, act26.
|
||||||
|
warning("STUB: doAction(act49)");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Utils::Error(EVNT_ERR, "doAction");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (action->a0.actType == NEW_SCREEN) // New_screen() deletes entire list
|
||||||
|
return (NULL); // next_p = NULL since list now empty
|
||||||
|
else {
|
||||||
|
wrkEvent = curEvent->nextEvent;
|
||||||
|
delQueue(curEvent); // Return event to free list
|
||||||
|
return(wrkEvent); // Return next event ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is the scheduler which runs every tick. It examines the event queue
|
||||||
|
// for any events whose time has come. It dequeues these events and performs
|
||||||
|
// the action associated with the event, returning it to the free queue
|
||||||
|
void Scheduler::runScheduler() {
|
||||||
|
debugC(6, kDebugSchedule, "runScheduler");
|
||||||
|
|
||||||
|
status_t &gameStatus = _vm.getGameStatus();
|
||||||
|
|
||||||
|
event_t *curEvent = _headEvent; // The earliest event
|
||||||
|
while (curEvent && curEvent->time <= gameStatus.tick) // While mature events found
|
||||||
|
curEvent = doAction(curEvent); // Perform the action (returns next_p)
|
||||||
|
gameStatus.tick++; // Accessed elsewhere via getTicks()
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Scheduler::getTicks() {
|
||||||
|
// Return system time in ticks. A tick is 1/TICKS_PER_SEC mS
|
||||||
|
debugC(3, kDebugSchedule, "getTicks");
|
||||||
|
|
||||||
|
return _vm.getGameStatus().tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::processBonus(int bonusIndex) {
|
||||||
|
// Add indecated bonus to score if not added already
|
||||||
|
debugC(1, kDebugSchedule, "processBonus(%d)", bonusIndex);
|
||||||
|
|
||||||
|
if (!_vm._points[bonusIndex].scoredFl) {
|
||||||
|
_vm.adjustScore(_vm._points[bonusIndex].score);
|
||||||
|
_vm._points[bonusIndex].scoredFl = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Transition to a new screen as follows:
|
||||||
|
// 1. Clear out all non-global events from event list.
|
||||||
|
// 2. Set the new screen (in the hero object and any carried objects)
|
||||||
|
// 3. Read in the screen files for the new screen
|
||||||
|
// 4. Schedule action list for new screen
|
||||||
|
// 5. Initialise prompt line and status line
|
||||||
|
void Scheduler::newScreen(int screenIndex) {
|
||||||
|
debugC(1, kDebugSchedule, "newScreen(%d)", screenIndex);
|
||||||
|
|
||||||
|
// Make sure the background file exists!
|
||||||
|
if (!_vm.isPacked()) {
|
||||||
|
char line[32];
|
||||||
|
if (!_vm.file().fileExists(strcat(strncat(strcpy(line, _vm._picDir), _vm._screenNames[screenIndex], NAME_LEN), BKGEXT)) &&
|
||||||
|
!_vm.file().fileExists(strcat(strcpy(line, _vm._screenNames[screenIndex]), ".ART"))) {
|
||||||
|
Utils::Box(BOX_ANY, _vm._textSchedule[kSsNoBackground]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. Clear out all local events
|
||||||
|
event_t *curEvent = _headEvent; // The earliest event
|
||||||
|
event_t *wrkEvent; // Event ptr
|
||||||
|
while (curEvent) { // While mature events found
|
||||||
|
wrkEvent = curEvent->nextEvent; // Save p (becomes undefined after Del)
|
||||||
|
if (curEvent->localActionFl)
|
||||||
|
delQueue(curEvent); // Return event to free list
|
||||||
|
curEvent = wrkEvent;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. Set the new screen in the hero object and any being carried
|
||||||
|
_vm.setNewScreen(screenIndex);
|
||||||
|
|
||||||
|
// 3. Read in new screen files
|
||||||
|
_vm.readScreenFiles(screenIndex);
|
||||||
|
|
||||||
|
// 4. Schedule action list for this screen
|
||||||
|
_vm.screenActions(screenIndex);
|
||||||
|
|
||||||
|
// 5. Initialise prompt line and status line
|
||||||
|
_vm.initNewScreenDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write the event queue to the file with handle f
|
||||||
|
// Note that we convert all the event structure ptrs to indexes
|
||||||
|
// using -1 for NULL. We can't convert the action ptrs to indexes
|
||||||
|
// so we save address of first dummy action ptr to compare on restore.
|
||||||
|
void Scheduler::saveEvents(Common::WriteStream *f) {
|
||||||
|
uint32 curTime;
|
||||||
|
event_t saveEvents_[kMaxEvents]; // Convert event ptrs to indexes
|
||||||
|
event_t *wrkEvent; // Event ptr
|
||||||
|
int16 freeIndex; // Free list index
|
||||||
|
int16 headIndex; // Head of list index
|
||||||
|
int16 tailIndex; // Tail of list index
|
||||||
|
|
||||||
|
debugC(1, kDebugSchedule, "saveEvents");
|
||||||
|
|
||||||
|
curTime = getTicks();
|
||||||
|
|
||||||
|
// Convert event ptrs to indexes
|
||||||
|
for (int16 i = 0; i < kMaxEvents; i++) {
|
||||||
|
wrkEvent = &_events[i];
|
||||||
|
saveEvents_[i] = *wrkEvent;
|
||||||
|
saveEvents_[i].prevEvent = (wrkEvent->prevEvent == NULL) ? (event_t *) - 1 : (event_t *)(wrkEvent->prevEvent - _events);
|
||||||
|
saveEvents_[i].nextEvent = (wrkEvent->nextEvent == NULL) ? (event_t *) - 1 : (event_t *)(wrkEvent->nextEvent - _events);
|
||||||
|
}
|
||||||
|
freeIndex = (_freeEvent == 0) ? -1 : _freeEvent - _events;
|
||||||
|
headIndex = (_headEvent == 0) ? -1 : _headEvent - _events;
|
||||||
|
tailIndex = (_tailEvent == 0) ? -1 : _tailEvent - _events;
|
||||||
|
|
||||||
|
f->write(&curTime, sizeof(curTime));
|
||||||
|
f->write(&freeIndex, sizeof(freeIndex));
|
||||||
|
f->write(&headIndex, sizeof(headIndex));
|
||||||
|
f->write(&tailIndex, sizeof(tailIndex));
|
||||||
|
f->write(saveEvents_, sizeof(saveEvents_));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Restore the event list from file with handle f
|
||||||
|
void Scheduler::restoreEvents(Common::SeekableReadStream *f) {
|
||||||
|
uint32 curTime, saveTime;
|
||||||
|
event_t *wrkEvent; // Event ptr
|
||||||
|
event_t savedEvents[kMaxEvents]; // Convert event ptrs to indexes
|
||||||
|
int16 freeIndex; // Free list index
|
||||||
|
int16 headIndex; // Head of list index
|
||||||
|
int16 tailIndex; // Tail of list index
|
||||||
|
|
||||||
|
debugC(1, kDebugSchedule, "restoreEvents");
|
||||||
|
|
||||||
|
f->read(&saveTime, sizeof(saveTime)); // time of save
|
||||||
|
f->read(&freeIndex, sizeof(freeIndex));
|
||||||
|
f->read(&headIndex, sizeof(headIndex));
|
||||||
|
f->read(&tailIndex, sizeof(tailIndex));
|
||||||
|
f->read(savedEvents, sizeof(savedEvents));
|
||||||
|
|
||||||
|
// Restore events indexes to pointers
|
||||||
|
for (int i = 0; i < kMaxEvents; i++) {
|
||||||
|
wrkEvent = &savedEvents[i];
|
||||||
|
_events[i] = *wrkEvent;
|
||||||
|
_events[i].prevEvent = (wrkEvent->prevEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->prevEvent ];
|
||||||
|
_events[i].nextEvent = (wrkEvent->nextEvent == (event_t *) - 1) ? (event_t *)0 : &_events[(size_t)wrkEvent->nextEvent ];
|
||||||
|
}
|
||||||
|
_freeEvent = (freeIndex == -1) ? NULL : &_events[freeIndex];
|
||||||
|
_headEvent = (headIndex == -1) ? NULL : &_events[headIndex];
|
||||||
|
_tailEvent = (tailIndex == -1) ? NULL : &_events[tailIndex];
|
||||||
|
|
||||||
|
// Adjust times to fit our time
|
||||||
|
curTime = getTicks();
|
||||||
|
wrkEvent = _headEvent; // The earliest event
|
||||||
|
while (wrkEvent) { // While mature events found
|
||||||
|
wrkEvent->time = wrkEvent->time - saveTime + curTime;
|
||||||
|
wrkEvent = wrkEvent->nextEvent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::restoreScreen(int screenIndex) {
|
||||||
|
// Transition to a new screen as follows:
|
||||||
|
// 1. Set the new screen (in the hero object and any carried objects)
|
||||||
|
// 2. Read in the screen files for the new screen
|
||||||
|
// 3. Initialise prompt line and status line
|
||||||
|
|
||||||
|
debugC(1, kDebugSchedule, "restoreScreen(%d)", screenIndex);
|
||||||
|
|
||||||
|
// 1. Set the new screen in the hero object and any being carried
|
||||||
|
_vm.setNewScreen(screenIndex);
|
||||||
|
|
||||||
|
// 2. Read in new screen files
|
||||||
|
_vm.readScreenFiles(screenIndex);
|
||||||
|
|
||||||
|
// 3. Initialise prompt line and status line
|
||||||
|
_vm.initNewScreenDisplay();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Scheduler::swapImages(int objNumb1, int objNumb2) {
|
||||||
|
// Swap all the images of one object with another. Set hero_image (we make
|
||||||
|
// the assumption for now that the first obj is always the HERO) to the object
|
||||||
|
// number of the swapped image
|
||||||
|
seqList_t tmpSeqList[MAX_SEQUENCES];
|
||||||
|
|
||||||
|
debugC(1, kDebugSchedule, "swapImages(%d, %d)", objNumb1, objNumb2);
|
||||||
|
|
||||||
|
_vm.file().saveSeq(&_vm._objects[objNumb1]);
|
||||||
|
memcpy(tmpSeqList, _vm._objects[objNumb1].seqList, sizeof(seqList_t));
|
||||||
|
memcpy(_vm._objects[objNumb1].seqList, _vm._objects[objNumb2].seqList, sizeof(seqList_t));
|
||||||
|
memcpy(_vm._objects[objNumb2].seqList, tmpSeqList, sizeof(seqList_t));
|
||||||
|
_vm.file().restoreSeq(&_vm._objects[objNumb1]);
|
||||||
|
_vm._objects[objNumb2].currImagePtr = _vm._objects[objNumb2].seqList[0].seqPtr;
|
||||||
|
_vm._heroImage = (_vm._heroImage == HERO) ? objNumb2 : HERO;
|
||||||
|
|
||||||
|
// Make sure baseline stays constant
|
||||||
|
_vm._objects[objNumb1].y += _vm._objects[objNumb2].currImagePtr->y2 - _vm._objects[objNumb1].currImagePtr->y2;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
85
engines/hugo/schedule.h
Executable file
85
engines/hugo/schedule.h
Executable file
|
@ -0,0 +1,85 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_SCHEDULE_H
|
||||||
|
#define HUGO_SCHEDULE_H
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
#define kMaxEvents 50 /* Max events in event queue */
|
||||||
|
|
||||||
|
struct event_t {
|
||||||
|
act *action; /* Ptr to action to perform */
|
||||||
|
bool localActionFl; /* TRUE if action is only for this screen */
|
||||||
|
uint32 time; /* (absolute) time to perform action */
|
||||||
|
struct event_t *prevEvent; /* Chain to previous event */
|
||||||
|
struct event_t *nextEvent; /* Chain to next event */
|
||||||
|
};
|
||||||
|
|
||||||
|
class Scheduler {
|
||||||
|
public:
|
||||||
|
Scheduler(HugoEngine &vm);
|
||||||
|
|
||||||
|
void initEventQueue();
|
||||||
|
void insertAction(act *action);
|
||||||
|
void insertActionList(uint16 actIndex);
|
||||||
|
void decodeString(char *line);
|
||||||
|
void runScheduler();
|
||||||
|
uint32 getTicks();
|
||||||
|
void processBonus(int bonusIndex);
|
||||||
|
void newScreen(int screenIndex);
|
||||||
|
void restoreEvents(Common::SeekableReadStream *f);
|
||||||
|
void saveEvents(Common::WriteStream *f);
|
||||||
|
void restoreScreen(int screenIndex);
|
||||||
|
void swapImages(int objNumb1, int objNumb2);
|
||||||
|
|
||||||
|
private:
|
||||||
|
enum seqTextSchedule {
|
||||||
|
kSsNoBackground = 0,
|
||||||
|
kSsBadSaveGame = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
HugoEngine &_vm;
|
||||||
|
|
||||||
|
event_t _events[kMaxEvents]; /* Statically declare event structures */
|
||||||
|
|
||||||
|
event_t *_freeEvent; /* Free list of event structures */
|
||||||
|
event_t *_headEvent; /* Head of list (earliest time) */
|
||||||
|
event_t *_tailEvent; /* Tail of list (latest time) */
|
||||||
|
|
||||||
|
event_t *getQueue();
|
||||||
|
void delQueue(event_t *curEvent);
|
||||||
|
event_t *doAction(event_t *curEvent);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif //HUGO_SCHEDULE_H
|
189
engines/hugo/sound.cpp
Executable file
189
engines/hugo/sound.cpp
Executable file
|
@ -0,0 +1,189 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* sound.c - sound effects and music support */
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
|
||||||
|
#include "sound/decoders/raw.h"
|
||||||
|
#include "sound/audiostream.h"
|
||||||
|
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/file.h"
|
||||||
|
#include "hugo/sound.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
uint16 SeqID; // Device id of (MIDI) sequencer
|
||||||
|
uint16 SeqVolID; // Low level id to set midi volume
|
||||||
|
uint16 WavID = 0; // Device id of waveaudio
|
||||||
|
|
||||||
|
//HWAVEOUT hwav; // Handle of waveaudio
|
||||||
|
//LPWAVEHDR lphdr; // WaveOut structure ptr
|
||||||
|
|
||||||
|
SoundHandler::SoundHandler(HugoEngine &vm) : _vm(vm) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::setMusicVolume() {
|
||||||
|
/* Set the FM music volume from config.mvolume (0..100%) */
|
||||||
|
warning("STUB: setMusicVolume()");
|
||||||
|
|
||||||
|
// uint32 dwVolume;
|
||||||
|
//
|
||||||
|
// if (config.music) {
|
||||||
|
// dwVolume = config.mvolume * 0xffffL / 100; // Convert % to 0..0xffff
|
||||||
|
// dwVolume |= dwVolume << 16; // Set volume in both stereo words
|
||||||
|
// midiOutSetVolume(SeqVolID, dwVolume);
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::stopSound() {
|
||||||
|
/* Stop any sound that might be playing */
|
||||||
|
warning("STUB: stopSound()");
|
||||||
|
|
||||||
|
// waveOutReset(hwav);
|
||||||
|
// waveOutUnprepareHeader(hwav, lphdr, sizeof(WAVEHDR));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::stopMusic() {
|
||||||
|
/* Stop any tune that might be playing */
|
||||||
|
warning("STUB: stopMusic()");
|
||||||
|
//mciSendCommand(SeqID, MCI_CLOSE, MCI_WAIT, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::toggleMusic() {
|
||||||
|
// Turn music on and off
|
||||||
|
if (_config.musicFl)
|
||||||
|
stopMusic();
|
||||||
|
_config.musicFl = !_config.musicFl;
|
||||||
|
initSound(RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::toggleSound() {
|
||||||
|
// Turn digitized sound on and off
|
||||||
|
_config.soundFl = !_config.soundFl;
|
||||||
|
initSound(RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::playMIDI(sound_pt seq_p, uint16 size) {
|
||||||
|
// Write supplied midi data to a temp file for MCI interface
|
||||||
|
// If seq_p is NULL, delete temp file
|
||||||
|
|
||||||
|
warning("STUB: playMIDI()");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SoundHandler::playMusic(int16 tune) {
|
||||||
|
/* Read a tune sequence from the sound database and start playing it */
|
||||||
|
sound_pt seqPtr; // Sequence data from file
|
||||||
|
uint16 size; // Size of sequence data
|
||||||
|
|
||||||
|
if (_config.musicFl) {
|
||||||
|
_vm.getGameStatus().song = tune;
|
||||||
|
seqPtr = _vm.file().getSound(tune, &size);
|
||||||
|
playMIDI(seqPtr, size);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void SoundHandler::playSound(int16 sound, stereo_t channel, byte priority) {
|
||||||
|
/* Produce various sound effects on supplied stereo channel(s) */
|
||||||
|
/* Override currently playing sound only if lower or same priority */
|
||||||
|
|
||||||
|
// uint32 dwVolume; // Left, right volume of sound
|
||||||
|
sound_pt sound_p; // Sound data
|
||||||
|
uint16 size; // Size of data
|
||||||
|
static byte curPriority = 0; // Priority of currently playing sound
|
||||||
|
//
|
||||||
|
/* Sound disabled */
|
||||||
|
if (!_config.soundFl || !_vm._mixer->isReady())
|
||||||
|
return;
|
||||||
|
//
|
||||||
|
// // See if last wave still playing - if so, check priority
|
||||||
|
// if (waveOutUnprepareHeader(hwav, lphdr, sizeof(WAVEHDR)) == WAVERR_STILLPLAYING)
|
||||||
|
// if (priority < curPriority) // Don't override unless priority >= current
|
||||||
|
// return;
|
||||||
|
// else
|
||||||
|
// Stop_sound();
|
||||||
|
curPriority = priority;
|
||||||
|
//
|
||||||
|
/* Get sound data */
|
||||||
|
if ((sound_p = _vm.file().getSound(sound, &size)) == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Audio::AudioStream *stream = Audio::makeRawStream(sound_p, size, 11025, Audio::FLAG_UNSIGNED);
|
||||||
|
_vm._mixer->playStream(Audio::Mixer::kSpeechSoundType, &_soundHandle, stream);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::initSound(inst_t action) {
|
||||||
|
/* Initialize for MCI sound and midi */
|
||||||
|
|
||||||
|
warning("STUB: initSound()");
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundHandler::pauseSound(bool activeFl, int hTask) {
|
||||||
|
// Pause and restore music, sound on losing activity to hTask
|
||||||
|
// Don't stop music if we are parent of new task, i.e. WinHelp()
|
||||||
|
// or config.music_bkg is TRUE.
|
||||||
|
|
||||||
|
//TODO: Is 'hTask' still useful ?
|
||||||
|
|
||||||
|
static bool firstFl = true;
|
||||||
|
static bool musicFl, soundFl;
|
||||||
|
|
||||||
|
if (firstFl) {
|
||||||
|
firstFl = false;
|
||||||
|
musicFl = _config.musicFl;
|
||||||
|
soundFl = _config.soundFl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill or restore music, sound
|
||||||
|
if (activeFl) { // Remember states, reset WinHelp flag
|
||||||
|
_config.musicFl = musicFl;
|
||||||
|
_config.soundFl = soundFl;
|
||||||
|
_vm.getGameStatus().helpFl = false;
|
||||||
|
} else { // Store states and disable
|
||||||
|
musicFl = _config.musicFl;
|
||||||
|
soundFl = _config.soundFl;
|
||||||
|
|
||||||
|
// Don't disable music during WinHelp() or config.music_bkg
|
||||||
|
if (!_vm.getGameStatus().helpFl && !_config.backgroundMusicFl) {
|
||||||
|
_config.musicFl = false;
|
||||||
|
_config.soundFl = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
initSound(RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
63
engines/hugo/sound.h
Executable file
63
engines/hugo/sound.h
Executable file
|
@ -0,0 +1,63 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_SOUND_H
|
||||||
|
#define HUGO_SOUND_H
|
||||||
|
|
||||||
|
#include "sound/mixer.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
class SoundHandler {
|
||||||
|
public:
|
||||||
|
SoundHandler(HugoEngine &vm);
|
||||||
|
|
||||||
|
void toggleMusic();
|
||||||
|
void toggleSound();
|
||||||
|
void setMusicVolume();
|
||||||
|
void playMusic(short tune);
|
||||||
|
void playSound(short sound, stereo_t channel, byte priority);
|
||||||
|
void initSound(inst_t action);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HugoEngine &_vm;
|
||||||
|
Audio::SoundHandle _soundHandle;
|
||||||
|
|
||||||
|
void stopSound();
|
||||||
|
void stopMusic();
|
||||||
|
void playMIDI(sound_pt seq_p, uint16 size);
|
||||||
|
void pauseSound(bool activeFl, int hTask);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
} // end of namespace Hugo
|
||||||
|
#endif //HUGO_SOUND_H
|
215
engines/hugo/util.cpp
Executable file
215
engines/hugo/util.cpp
Executable file
|
@ -0,0 +1,215 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "common/system.h"
|
||||||
|
#include "gui/message.h"
|
||||||
|
|
||||||
|
#include "hugo/game.h"
|
||||||
|
#include "hugo/hugo.h"
|
||||||
|
#include "hugo/util.h"
|
||||||
|
#include "hugo/sound.h"
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
int Utils::firstBit(byte data) {
|
||||||
|
/* Returns index (0 to 7) of first 1 in supplied byte, or 8 if not found */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (!data)
|
||||||
|
return(8);
|
||||||
|
|
||||||
|
for (i = 0; i < 8; i++) {
|
||||||
|
if ((data << i) & 0x80)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
int Utils::lastBit(byte data) {
|
||||||
|
/* Returns index (0 to 7) of last 1 in supplied byte, or 8 if not found */
|
||||||
|
int i;
|
||||||
|
if (!data)
|
||||||
|
return(8);
|
||||||
|
|
||||||
|
for (i = 7; i >= 0; i--) {
|
||||||
|
if ((data << i) & 0x80)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::reverseByte(byte *data) {
|
||||||
|
/* Reverse the bit order in supplied byte */
|
||||||
|
byte maskIn = 0x80;
|
||||||
|
byte maskOut = 0x01;
|
||||||
|
byte result = 0;
|
||||||
|
|
||||||
|
for (byte i = 0; i < 8; i++, maskIn >>= 1, maskOut <<= 1)
|
||||||
|
if (*data & maskIn)
|
||||||
|
result |= maskOut;
|
||||||
|
|
||||||
|
*data = result;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *Utils::Box(box_t dismiss, const char *s, ...) {
|
||||||
|
static char buffer[MAX_STRLEN + 1]; // Format text into this
|
||||||
|
va_list marker;
|
||||||
|
|
||||||
|
if (!s) return(NULL); // NULL strings catered for
|
||||||
|
|
||||||
|
if (s[0] == '\0')
|
||||||
|
return(NULL);
|
||||||
|
|
||||||
|
if (strlen(s) > MAX_STRLEN - 100) { // Test length
|
||||||
|
Warn(false, "String too big:\n%s", s);
|
||||||
|
return(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(marker, s);
|
||||||
|
vsprintf(buffer, s, marker); // Format string into buffer
|
||||||
|
va_end(marker);
|
||||||
|
|
||||||
|
//Warn(false, "BOX: %s", buffer);
|
||||||
|
int boxTime = strlen(buffer) * 30;
|
||||||
|
GUI::TimedMessageDialog dialog(buffer, MAX(1500, boxTime));
|
||||||
|
dialog.runModal();
|
||||||
|
|
||||||
|
// TODO: Some boxes (i.e. the combination code for the shed), needs to return an input.
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::Warn(bool technote, const char *format, ...) {
|
||||||
|
/* Warning handler. Print supplied message and continue */
|
||||||
|
/* Arguments are same as printf */
|
||||||
|
/* technote TRUE if we are to refer user to technote file */
|
||||||
|
char buffer[WARNLEN];
|
||||||
|
bool soundFl = _config.soundFl;
|
||||||
|
va_list marker;
|
||||||
|
|
||||||
|
_config.soundFl = false; // Kill sound to allow beep sound
|
||||||
|
HugoEngine::get().sound().initSound(RESET);
|
||||||
|
|
||||||
|
va_start(marker, format);
|
||||||
|
vsnprintf(buffer, WARNLEN, format, marker);
|
||||||
|
//// if (technote)
|
||||||
|
//// strcat (buffer, sTech);
|
||||||
|
//MessageBeep(MB_ICONEXCLAMATION);
|
||||||
|
//MessageBox(hwnd, buffer, "HugoWin Warning", MB_OK | MB_ICONEXCLAMATION);
|
||||||
|
warning("Hugo warning: %s", buffer);
|
||||||
|
va_end(marker);
|
||||||
|
|
||||||
|
//sndPlaySound(NULL, 0); // Stop beep and restore sound
|
||||||
|
|
||||||
|
_config.soundFl = soundFl;
|
||||||
|
HugoEngine::get().sound().initSound(RESET);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::Error(int error_type, const char *format, ...) {
|
||||||
|
/* Fatal error handler. Reset environment, print error and exit */
|
||||||
|
/* Arguments are same as printf */
|
||||||
|
va_list marker;
|
||||||
|
char buffer[ERRLEN + 1];
|
||||||
|
bool fatal = true; // Fatal error, else continue
|
||||||
|
|
||||||
|
switch (error_type) {
|
||||||
|
case FILE_ERR:
|
||||||
|
// case FONT_ERR:
|
||||||
|
strcpy(buffer, HugoEngine::get()._textUtil[kErr1]);
|
||||||
|
break;
|
||||||
|
case WRITE_ERR:
|
||||||
|
strcpy(buffer, HugoEngine::get()._textUtil[kErr2]);
|
||||||
|
fatal = false; // Allow continuation
|
||||||
|
break;
|
||||||
|
case PCCH_ERR:
|
||||||
|
strcpy(buffer, HugoEngine::get()._textUtil[kErr3]);
|
||||||
|
break;
|
||||||
|
case HEAP_ERR:
|
||||||
|
strcpy(buffer, HugoEngine::get()._textUtil[kErr4]);
|
||||||
|
break;
|
||||||
|
case SOUND_ERR:
|
||||||
|
strcpy(buffer, HugoEngine::get()._textUtil[kErr5]);
|
||||||
|
break;
|
||||||
|
// case TIMER_ERR:
|
||||||
|
// strcpy(buffer, HugoEngine::get()._textUtil[kObsoleteErr1]);
|
||||||
|
// break;
|
||||||
|
// case VBX_ERR:
|
||||||
|
// strcpy(buffer, HugoEngine::get()._textUtil[kObsoleteErr2]);
|
||||||
|
// break;
|
||||||
|
default:
|
||||||
|
strcpy(buffer, HugoEngine::get()._textUtil[kErr6]);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fatal)
|
||||||
|
HugoEngine::get().shutdown(); // Restore any devices before exit
|
||||||
|
|
||||||
|
va_start(marker, format);
|
||||||
|
snprintf(&buffer[strlen(buffer)], ERRLEN - strlen(buffer), format, marker);
|
||||||
|
//MessageBeep(MB_ICONEXCLAMATION);
|
||||||
|
//MessageBox(hwnd, buffer, "HugoWin Error", MB_OK | MB_ICONEXCLAMATION);
|
||||||
|
warning("Hugo Error: %s", buffer);
|
||||||
|
va_end(marker);
|
||||||
|
|
||||||
|
if (fatal)
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Utils::gameOverMsg(void) {
|
||||||
|
// Print options for user when dead
|
||||||
|
//MessageBox(hwnd, gameoverstring, "Be more careful next time!", MB_OK | MB_ICONINFORMATION);
|
||||||
|
warning("STUB: Gameover_msg(): %s", HugoEngine::get()._textUtil[kGameOver]);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
// Strangerke: Useless?
|
||||||
|
void Utils::Debug_out(char *format, ...) {
|
||||||
|
/* Write debug info to file */
|
||||||
|
static FILE *fp = NULL;
|
||||||
|
va_list marker;
|
||||||
|
|
||||||
|
if (HugoEngine::get().getGameStatus().debugFl) {
|
||||||
|
/* Create/truncate if first call, else append */
|
||||||
|
if ((fp = fopen("debug.txt", fp == NULL ? "w" : "a")) == NULL) {
|
||||||
|
Error(WRITE_ERR, "debug.txt");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_start(marker, format);
|
||||||
|
vfprintf(fp, format, marker);
|
||||||
|
va_end(marker);
|
||||||
|
fclose(fp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} // end of namespace Hugo
|
63
engines/hugo/util.h
Executable file
63
engines/hugo/util.h
Executable file
|
@ -0,0 +1,63 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef HUGO_UTIL_H
|
||||||
|
#define HUGO_UTIL_H
|
||||||
|
|
||||||
|
namespace Hugo {
|
||||||
|
|
||||||
|
enum seqTextUtil {
|
||||||
|
kTech = 0,
|
||||||
|
kErr1 = 1,
|
||||||
|
kErr2 = 2,
|
||||||
|
kErr3 = 3,
|
||||||
|
kErr4 = 4,
|
||||||
|
kErr5 = 5,
|
||||||
|
kErr6 = 6,
|
||||||
|
kGameOver = 7
|
||||||
|
// kObsoleteErr1 = 8,
|
||||||
|
// kObsoleteErr2 = 9
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace Utils {
|
||||||
|
int firstBit(byte data);
|
||||||
|
int lastBit(byte data);
|
||||||
|
void reverseByte(byte *data);
|
||||||
|
void Warn(bool technote, const char *format, ...);
|
||||||
|
void Error(int code, const char *format, ...);
|
||||||
|
void gameOverMsg();
|
||||||
|
// void Debug_out(char *format, ...);
|
||||||
|
char *Box(box_t, const char *, ...);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // Namespace Hugo
|
||||||
|
#endif
|
|
@ -30,7 +30,7 @@ convbdf
|
||||||
where SIZE is replaced by the desired font height.
|
where SIZE is replaced by the desired font height.
|
||||||
|
|
||||||
|
|
||||||
create_drascula
|
create_drascula (sev)
|
||||||
---------------
|
---------------
|
||||||
Stores a lot of hardcoded data of Drascula in a data file, based on
|
Stores a lot of hardcoded data of Drascula in a data file, based on
|
||||||
the game's original source code. This includes the game's character
|
the game's original source code. This includes the game's character
|
||||||
|
@ -39,6 +39,10 @@ create_drascula
|
||||||
(mostly the dialog subtitles) in English, Spanish, German, French
|
(mostly the dialog subtitles) in English, Spanish, German, French
|
||||||
and Italian. This tool is used to create the drascula.dat file.
|
and Italian. This tool is used to create the drascula.dat file.
|
||||||
|
|
||||||
|
create_hugo (Strangerke)
|
||||||
|
-----------
|
||||||
|
Creates hugo.dat file which contains all kinds of static data contained
|
||||||
|
in original game executable.
|
||||||
|
|
||||||
create_kyradat (LordHoto, athrxx)
|
create_kyradat (LordHoto, athrxx)
|
||||||
--------------
|
--------------
|
||||||
|
|
1269
tools/create_hugo/create_hugo.cpp
Executable file
1269
tools/create_hugo/create_hugo.cpp
Executable file
File diff suppressed because it is too large
Load diff
555
tools/create_hugo/create_hugo.h
Executable file
555
tools/create_hugo/create_hugo.h
Executable file
|
@ -0,0 +1,555 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef CREATE_HUGO_H
|
||||||
|
#define CREATE_HUGO_H
|
||||||
|
|
||||||
|
#define ARRAYSIZE(x) ((int)(sizeof(x) / sizeof(x[0])))
|
||||||
|
|
||||||
|
#define DATAALIGNMENT 4
|
||||||
|
|
||||||
|
#define HUGO_DAT_VER_MAJ 0 // 1 byte
|
||||||
|
#define HUGO_DAT_VER_MIN 16 // 1 byte
|
||||||
|
|
||||||
|
typedef unsigned char uint8;
|
||||||
|
typedef unsigned char byte;
|
||||||
|
typedef unsigned short uint16;
|
||||||
|
typedef signed short int16;
|
||||||
|
|
||||||
|
// Structure to define an EXIT or other collision-activated hotspot
|
||||||
|
struct hotspot_t {
|
||||||
|
int screenIndex; // Screen in which hotspot appears
|
||||||
|
int x1, y1, x2, y2; // Bounding box of hotspot
|
||||||
|
uint16 actIndex; // Index of the action list to carry out if a 'hit'
|
||||||
|
int16 viewx, viewy, direction; // Used in auto-route mode
|
||||||
|
};
|
||||||
|
|
||||||
|
struct target_t { // Secondary target for action
|
||||||
|
uint16 nounIndex; // Index of the noun
|
||||||
|
uint16 verbIndex; // Index of the verb
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_TARGET 12 // Max # secondary "MakeUseOf" targets
|
||||||
|
|
||||||
|
struct uses_t { // Define uses of certain objects
|
||||||
|
int16 objid; // Primary object
|
||||||
|
uint16 dataIndex; // Index of the string if no secondary object matches
|
||||||
|
target_t targets[MAX_TARGET]; // List of secondary targets
|
||||||
|
};
|
||||||
|
|
||||||
|
// Following is structure of verbs and nouns for 'background' objects
|
||||||
|
// These are objects that appear in the various screens, but nothing
|
||||||
|
// interesting ever happens with them. Rather than just be dumb and say
|
||||||
|
// "don't understand" we produce an interesting msg to keep user sane.
|
||||||
|
struct background_t {
|
||||||
|
uint16 verbIndex; // Index of the verb
|
||||||
|
uint16 nounIndex; // Index of the noun
|
||||||
|
int commentIndex; // Index of comment produced on match
|
||||||
|
bool matchFl; // TRUE if noun must match when present
|
||||||
|
byte roomState; // "State" of room. Comments might differ.
|
||||||
|
byte bonusIndex; // Index of bonus score (0 = no bonus)
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef background_t *objectList_t;
|
||||||
|
|
||||||
|
struct cmd {
|
||||||
|
uint16 verbIndex; // Index of the verb
|
||||||
|
uint16 reqIndex; // Index of the list of required objects
|
||||||
|
uint16 textDataNoCarryIndex; // Index of the string if any of above not carried
|
||||||
|
byte reqstate; // required state for verb to be done
|
||||||
|
byte newstate; // new states if verb done
|
||||||
|
uint16 textDataWrongIndex; // Index of the string if wrong state
|
||||||
|
uint16 textDataDoneIndex; // Index of the string if verb done
|
||||||
|
uint16 actIndex; // Index of the action list if verb done
|
||||||
|
};
|
||||||
|
|
||||||
|
struct seq_t { // Linked list of images
|
||||||
|
byte *imagePtr; // ptr to image
|
||||||
|
uint16 bytesPerLine8; // bytes per line (8 bits)
|
||||||
|
uint16 lines; // lines
|
||||||
|
uint16 x1, x2, y1, y2; // Offsets from x,y: data bounding box
|
||||||
|
seq_t *nextSeqPtr; // ptr to next record
|
||||||
|
};
|
||||||
|
|
||||||
|
struct seqList_t {
|
||||||
|
uint16 imageNbr; // Number of images in sequence
|
||||||
|
seq_t *seqPtr; // Ptr to sequence structure
|
||||||
|
};
|
||||||
|
|
||||||
|
#define MAX_SEQUENCES 4 // Number of sequences of images in object
|
||||||
|
struct object_t {
|
||||||
|
uint16 nounIndex; // String identifying object
|
||||||
|
uint16 dataIndex; // String describing the object
|
||||||
|
uint16 *stateDataIndex; // Added by Strangerke to handle the LOOK_S state-dependant descriptions
|
||||||
|
path_t pathType; // Describe path object follows
|
||||||
|
int vxPath, vyPath; // Velocity (e.g. for CHASE)
|
||||||
|
uint16 actIndex; // Action list to do on collision with hero
|
||||||
|
byte seqNumb; // Number of sequences in list
|
||||||
|
seq_t *currImagePtr; // Sequence image currently in use
|
||||||
|
seqList_t seqList[MAX_SEQUENCES]; // Array of sequence structure ptrs and lengths
|
||||||
|
cycle_t cycling; // Whether cycling, forward or backward
|
||||||
|
byte cycleNumb; // No. of times to cycle
|
||||||
|
byte frameInterval; // Interval (in ticks) between frames
|
||||||
|
byte frameTimer; // Decrementing timer for above
|
||||||
|
char radius; // Defines sphere of influence by hero
|
||||||
|
byte screenIndex; // Screen in which object resides
|
||||||
|
int x, y; // Current coordinates of object
|
||||||
|
int oldx, oldy; // Previous coordinates of object
|
||||||
|
char vx, vy; // Velocity
|
||||||
|
byte objValue; // Value of object
|
||||||
|
int genericCmd; // Bit mask of 'generic' commands for object
|
||||||
|
uint16 cmdIndex; // ptr to list of cmd structures for verbs
|
||||||
|
bool carriedFl; // TRUE if object being carried
|
||||||
|
byte state; // state referenced in cmd list
|
||||||
|
bool verbOnlyFl; // TRUE if verb-only cmds allowed e.g. sit,look
|
||||||
|
byte priority; // Whether object fore, background or floating
|
||||||
|
int16 viewx, viewy; // Position to view object from (or 0 or -1)
|
||||||
|
int16 direction; // Direction to view object from
|
||||||
|
byte curSeqNumb; // Save which seq number currently in use
|
||||||
|
byte curImageNumb; // Save which image of sequence currently in use
|
||||||
|
char oldvx; // Previous vx (used in wandering)
|
||||||
|
char oldvy; // Previous vy
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act0 { // Type 0 - Schedule
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 actIndex; // Index of an action list
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act1 { // Type 1 - Start an object
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int cycleNumb; // Number of times to cycle
|
||||||
|
cycle_t cycle; // Direction to start cycling
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act2 { // Type 2 - Initialise an object coords
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int x, y; // Coordinates
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act3 { // Type 3 - Prompt user for text
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 promptIndex; // index of prompt string
|
||||||
|
int *responsePtr; // Array of indexes to valid response
|
||||||
|
// string(s) (terminate list with -1)
|
||||||
|
uint16 actPassIndex; // Index of the action list if success
|
||||||
|
uint16 actFailIndex; // Index of the action list if failure
|
||||||
|
bool encoded; // (HUGO 1 DOS ONLY) Whether response is encoded or not
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act4 { // Type 4 - Set new background color
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
long newBkgColor; // New color
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act5 { // Type 5 - Initialise an object velocity
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int vx, vy; // velocity
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act6 { // Type 6 - Initialise an object carrying
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
bool carriedFl; // carrying
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act7 { // Type 7 - Initialise an object to hero's coords
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act8 { // Type 8 - switch to new screen
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int screenIndex; // The new screen number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act9 { // Type 9 - Initialise an object state
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
byte newState; // New state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act10 { // Type 10 - Initialise an object path type
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int newPathType; // New path type
|
||||||
|
char vxPath, vyPath; // Max delta velocities e.g. for CHASE
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act11 { // Type 11 - Conditional on object's state
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
byte stateReq; // Required state
|
||||||
|
uint16 actPassIndex; // Index of the action list if success
|
||||||
|
uint16 actFailIndex; // Index of the action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act12 { // Type 12 - Simple text box
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int stringIndex; // Index (enum) of string in strings.dat
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act13 { // Type 13 - Swap first object image with second
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int obj1; // Index of first object
|
||||||
|
int obj2; // 2nd
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act14 { // Type 14 - Conditional on current screen
|
||||||
|
byte atype; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The required object
|
||||||
|
int screenReq; // The required screen number
|
||||||
|
uint16 actPassIndex; // Index of the action list if success
|
||||||
|
uint16 actFailIndex; // Index of the action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act15 { // Type 15 - Home in on an object
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int obj1; // The object number homing in
|
||||||
|
int obj2; // The object number to home in on
|
||||||
|
char vx, vy; // Max delta velocities
|
||||||
|
};
|
||||||
|
// Note: Don't set a sequence at time 0 of a new screen, it causes
|
||||||
|
// problems clearing the boundary bits of the object! t>0 is safe
|
||||||
|
struct act16 { // Type 16 - Set curr_seq_p to seq
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int seqIndex; // The index of seq array to set to
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act17 { // Type 17 - SET obj individual state bits
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int stateMask; // The mask to OR with current obj state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act18 { // Type 18 - CLEAR obj individual state bits
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int stateMask; // The mask to ~AND with current obj state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act19 { // Type 19 - TEST obj individual state bits
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int stateMask; // The mask to AND with current obj state
|
||||||
|
uint16 actPassIndex; // Index of the action list (all bits set)
|
||||||
|
uint16 actFailIndex; // Index of the action list (not all set)
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act20 { // Type 20 - Remove all events with this type of action
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
byte actTypeDel; // The action type to remove
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act21 { // Type 21 - Gameover. Disable hero & commands
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act22 { // Type 22 - Initialise an object to hero's coords
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act23 { // Type 23 - Exit game back to DOS
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act24 { // Type 24 - Get bonus score
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int pointIndex; // Index into points array
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act25 { // Type 25 - Conditional on bounding box
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The required object number
|
||||||
|
int x1, y1, x2, y2; // The bounding box
|
||||||
|
uint16 actPassIndex; // Index of the action list if success
|
||||||
|
uint16 actFailIndex; // Index of the action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act26 { // Type 26 - Play a sound
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int16 soundIndex; // Sound index in data file
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act27 { // Type 27 - Add object's value to score
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act28 { // Type 28 - Subtract object's value from score
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // object number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act29 { // Type 29 - Conditional on object carried
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The required object number
|
||||||
|
uint16 actPassIndex; // Index of the action list if success
|
||||||
|
uint16 actFailIndex; // Index of the action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act30 { // Type 30 - Start special maze processing
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
byte mazeSize; // Size of (square) maze
|
||||||
|
int x1, y1, x2, y2; // Bounding box of maze
|
||||||
|
int x3, x4; // Extra x points for perspective correction
|
||||||
|
byte firstScreenIndex; // First (top left) screen of maze
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act31 { // Type 31 - Exit special maze processing
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act32 { // Type 32 - Init fbg field of object
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
byte priority; // Value of foreground/background field
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act33 { // Type 33 - Init screen field of object
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int screenIndex; // Screen number
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act34 { // Type 34 - Global Schedule
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 actIndex; // Index of an action list
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act35 { // Type 35 - Remappe palette
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int16 oldColorIndex; // Old color index, 0..15
|
||||||
|
int16 newColorIndex; // New color index, 0..15
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act36 { // Type 36 - Conditional on noun mentioned
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 nounIndex; // The required noun (list)
|
||||||
|
uint16 actPassIndex; // Index of the action list if success
|
||||||
|
uint16 actFailIndex; // Index of the action list if failure
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act37 { // Type 37 - Set new screen state
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int screenIndex; // The screen number
|
||||||
|
byte newState; // The new state
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act38 { // Type 38 - Position lips
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int lipsObjNumb; // The LIPS object
|
||||||
|
int objNumb; // The object to speak
|
||||||
|
byte dxLips; // Relative offset of x
|
||||||
|
byte dyLips; // Relative offset of y
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act39 { // Type 39 - Init story mode
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
bool storyModeFl; // New state of story_mode flag
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act40 { // Type 40 - Unsolicited text box
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int stringIndex; // Index (enum) of string in strings.dat
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act41 { // Type 41 - Conditional on bonus scored
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int BonusIndex; // Index into bonus list
|
||||||
|
uint16 actPassIndex; // Index of the action list if scored for the first time
|
||||||
|
uint16 actFailIndex; // Index of the action list if already scored
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act42 { // Type 42 - Text box with "take" string
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object taken
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act43 { // Type 43 - Prompt user for Yes or No
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int prompt; // Index of prompt string
|
||||||
|
uint16 actYesIndex; // Index of the action list if YES
|
||||||
|
uint16 actNoIndex; // Index of the action list if NO
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act44 { // Type 44 - Stop any route in progress
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act45 { // Type 45 - Conditional on route in progress
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int routeIndex; // Must be >= current status.rindex
|
||||||
|
uint16 actPassIndex; // Index of the action list if en-route
|
||||||
|
uint16 actFailIndex; // Index of the action list if not
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act46 { // Type 46 - Init status.jumpexit
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
bool jumpExitFl; // New state of jumpexit flag
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act47 { // Type 47 - Init viewx,viewy,dir
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object
|
||||||
|
int16 viewx; // object.viewx
|
||||||
|
int16 viewy; // object.viewy
|
||||||
|
int16 direction; // object.dir
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act48 { // Type 48 - Set curr_seq_p to frame n
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
int objNumb; // The object number
|
||||||
|
int seqIndex; // The index of seq array to set to
|
||||||
|
int frameIndex; // The index of frame to set to
|
||||||
|
};
|
||||||
|
|
||||||
|
struct act49 { // Added by Strangerke - Type 79 - Play a sound (DOS way)
|
||||||
|
byte actType; // The type of action
|
||||||
|
int timer; // Time to set off the action
|
||||||
|
uint16 songIndex; // Song index in string array
|
||||||
|
};
|
||||||
|
|
||||||
|
union act {
|
||||||
|
act0 a0;
|
||||||
|
act1 a1;
|
||||||
|
act2 a2;
|
||||||
|
act3 a3;
|
||||||
|
act4 a4;
|
||||||
|
act5 a5;
|
||||||
|
act6 a6;
|
||||||
|
act7 a7;
|
||||||
|
act8 a8;
|
||||||
|
act9 a9;
|
||||||
|
act10 a10;
|
||||||
|
act11 a11;
|
||||||
|
act12 a12;
|
||||||
|
act13 a13;
|
||||||
|
act14 a14;
|
||||||
|
act15 a15;
|
||||||
|
act16 a16;
|
||||||
|
act17 a17;
|
||||||
|
act18 a18;
|
||||||
|
act19 a19;
|
||||||
|
act20 a20;
|
||||||
|
act21 a21;
|
||||||
|
act22 a22;
|
||||||
|
act23 a23;
|
||||||
|
act24 a24;
|
||||||
|
act25 a25;
|
||||||
|
act26 a26;
|
||||||
|
act27 a27;
|
||||||
|
act28 a28;
|
||||||
|
act29 a29;
|
||||||
|
act30 a30;
|
||||||
|
act31 a31;
|
||||||
|
act32 a32;
|
||||||
|
act33 a33;
|
||||||
|
act34 a34;
|
||||||
|
act35 a35;
|
||||||
|
act36 a36;
|
||||||
|
act37 a37;
|
||||||
|
act38 a38;
|
||||||
|
act39 a39;
|
||||||
|
act40 a40;
|
||||||
|
act41 a41;
|
||||||
|
act42 a42;
|
||||||
|
act43 a43;
|
||||||
|
act44 a44;
|
||||||
|
act45 a45;
|
||||||
|
act46 a46;
|
||||||
|
act47 a47;
|
||||||
|
act48 a48;
|
||||||
|
act49 a49;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef void *actListPtr; // Ptr to a list of actions
|
||||||
|
typedef actListPtr *actList; // A list of actions
|
||||||
|
|
||||||
|
void writeTextArray(FILE *outFile, char *textData[], int nbrText);
|
||||||
|
void writeUint16Array(FILE *outFile, uint16 *uint16Array[], int nbrElem);
|
||||||
|
void writeHotspot(FILE *outFile, hotspot_t hotspots[], int nbrElem);
|
||||||
|
void writeUseArray(FILE *outFile, uses_t uses[], int nbrElem);
|
||||||
|
void writeBackgroundArray(FILE *outFile, background_t background[], int nbrElem);
|
||||||
|
void writeCmdArray(FILE *outFile, cmd *cmdList[], int nbrElem);
|
||||||
|
void writeScreenActs(FILE *outFile, uint16 *screenActs[], int nbrElem);
|
||||||
|
void writeObjectArray(FILE *outFile, object_t objects[], int nbrElem);
|
||||||
|
void writeActListArray(FILE *outFile, actList actListArr[], int nbrElem);
|
||||||
|
|
||||||
|
#endif // CREATE_HUGO_H
|
1565
tools/create_hugo/enums.h
Executable file
1565
tools/create_hugo/enums.h
Executable file
File diff suppressed because it is too large
Load diff
10
tools/create_hugo/module.mk
Executable file
10
tools/create_hugo/module.mk
Executable file
|
@ -0,0 +1,10 @@
|
||||||
|
MODULE := tools/create_hugo
|
||||||
|
|
||||||
|
MODULE_OBJS := \
|
||||||
|
create_hugo.o
|
||||||
|
|
||||||
|
# Set the name of the executable
|
||||||
|
TOOL_EXECUTABLE := create_hugo
|
||||||
|
|
||||||
|
# Include common rules
|
||||||
|
include $(srcdir)/rules.mk
|
11879
tools/create_hugo/staticdata.h
Executable file
11879
tools/create_hugo/staticdata.h
Executable file
File diff suppressed because it is too large
Load diff
65
tools/create_hugo/staticdisplay.h
Executable file
65
tools/create_hugo/staticdisplay.h
Executable file
|
@ -0,0 +1,65 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STATICDISPLAY_H
|
||||||
|
#define STATICDISPLAY_H
|
||||||
|
|
||||||
|
#define SIZE_PAL_ARRAY 64
|
||||||
|
|
||||||
|
// Color table of standard 16 VGA colors
|
||||||
|
// Values from "Programmers guide to EGA/VGA cards" Ferraro, p303
|
||||||
|
#define V1 168 // Low intensity value
|
||||||
|
#define V2 255 // High intensity value
|
||||||
|
#define V3 87 // Special for Brown/Gray
|
||||||
|
#define V4 32 // De-saturate hi intensity
|
||||||
|
|
||||||
|
|
||||||
|
byte _palette[SIZE_PAL_ARRAY] = {
|
||||||
|
0, 0, 0, 0, // BLACK
|
||||||
|
0, 0, V1, 0, // BLUE
|
||||||
|
0, V1, 0, 0, // GREEN
|
||||||
|
0, V1, V1, 0, // CYAN
|
||||||
|
V1, 0, 0, 0, // RED
|
||||||
|
V1, 0, V1, 0, // MAGENTA
|
||||||
|
V1, V3, 0, 0, // BROWN
|
||||||
|
V1, V1, V1, 0, // WHITE (LIGHT GRAY)
|
||||||
|
V3, V3, V3, 0, // GRAY (DARK GRAY)
|
||||||
|
V4, V4, V2, 0, // LIGHTBLUE
|
||||||
|
V4, V2, V4, 0, // LIGHTGREEN
|
||||||
|
V4, V2, V2, 0, // LIGHTCYAN
|
||||||
|
V2, V4, V4, 0, // LIGHTRED
|
||||||
|
V2, V4, V2, 0, // LIGHTMAGENTA
|
||||||
|
V2, V2, V4, 0, // YELLOW
|
||||||
|
V2, V2, V2, 0 // BRIGHTWHITE
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
52
tools/create_hugo/staticengine.h
Executable file
52
tools/create_hugo/staticengine.h
Executable file
|
@ -0,0 +1,52 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STATICENGINE_H
|
||||||
|
#define STATICENGINE_H
|
||||||
|
|
||||||
|
#define NUM_ENGINE_TEXT 1
|
||||||
|
const char *textEngine[NUM_ENGINE_TEXT] = {
|
||||||
|
"Hugo and Penelope say:\n\n"
|
||||||
|
"We hope you liked our adventure and\n"
|
||||||
|
"hope to see you very soon in Hugo's\n"
|
||||||
|
"Mystery Adventure and Hugo's Amazon\n"
|
||||||
|
"Adventure. They are just like this\n"
|
||||||
|
"game but bigger and better!\n\n"
|
||||||
|
"Call 1-800-2424-PsL now to order the\n"
|
||||||
|
"Hugo Trilogy for Windows for only $36!\n"
|
||||||
|
"(Note: This number is for ORDERS only).\n\n"
|
||||||
|
"It includes all 3 games plus the 30-page\n"
|
||||||
|
"answer book. See Ordering information\n"
|
||||||
|
"for more details and some screenshots."
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
59
tools/create_hugo/staticintro.h
Executable file
59
tools/create_hugo/staticintro.h
Executable file
|
@ -0,0 +1,59 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STATICINTRO_H
|
||||||
|
#define STATICINTRO_H
|
||||||
|
|
||||||
|
#define NUM_INTRO_TEXT 3
|
||||||
|
#define NUM_INTRO_TICK 36
|
||||||
|
// We use intro_tick as an index into the following coordinate list for the plane path.
|
||||||
|
const byte x_intro[NUM_INTRO_TICK] = {
|
||||||
|
210, 204, 198, 192, 186, 180, 174, 168, 162, 156,
|
||||||
|
152, 149, 152, 158, 165, 171, 170, 165, 161, 157,
|
||||||
|
150, 144, 138, 134, 133, 134, 138, 144, 146, 142,
|
||||||
|
137, 132, 128, 124, 120, 115
|
||||||
|
};
|
||||||
|
|
||||||
|
const byte y_intro[NUM_INTRO_TICK] = {
|
||||||
|
61, 61, 61, 61, 61, 61, 61, 61, 61, 61,
|
||||||
|
63, 66, 71, 74, 72, 75, 80, 82, 83, 84,
|
||||||
|
84, 84, 85, 89, 94, 99, 103, 104, 100, 98,
|
||||||
|
100, 103, 106, 109, 111, 112
|
||||||
|
};
|
||||||
|
|
||||||
|
const char *textIntro[NUM_INTRO_TEXT] = {
|
||||||
|
"Hugo and Penelope are returning\nhome from their vacation at the\ncottage of Great Uncle Horace.",
|
||||||
|
"Suddenly, a freak magnetic storm\ncauses the compass in their light\naircraft to spin wildly! Unable\nto navigate, Hugo loses all sense\nof direction...",
|
||||||
|
"Finally, hopelessly lost over a\nSouth American Jungle, the plane\nabout to run out of gas, Hugo\nspots a clearing just big enough\nto land it.\n\nWith fingers clenching the controls\nhe shouts: Hold on Penelope, we're\ngoing down...!"
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
43
tools/create_hugo/staticmouse.h
Executable file
43
tools/create_hugo/staticmouse.h
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STATICMOUSE_H
|
||||||
|
#define STATICMOUSE_H
|
||||||
|
|
||||||
|
#define NUM_MOUSE_TEXT 2
|
||||||
|
|
||||||
|
const char *textMouse[NUM_MOUSE_TEXT] = {
|
||||||
|
"I don't know how to get there!",
|
||||||
|
"Exit"
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
56
tools/create_hugo/staticparser.h
Executable file
56
tools/create_hugo/staticparser.h
Executable file
|
@ -0,0 +1,56 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STATICPARSER_H
|
||||||
|
#define STATICPARSER_H
|
||||||
|
|
||||||
|
#define NUM_PARSER_TEXT 16
|
||||||
|
const char *textParser[NUM_PARSER_TEXT] = {
|
||||||
|
"You should press ALT+F4 or click on Game/Exit.",
|
||||||
|
"You are in a maze of\ntwisty little paths,\nwhich are all alike!",
|
||||||
|
"There's no point!",
|
||||||
|
"I don't fully understand.",
|
||||||
|
"I don't quite understand.",
|
||||||
|
"Eh?",
|
||||||
|
"You see nothing\nunusual about it.",
|
||||||
|
"You already have it.",
|
||||||
|
"It is of no use to you.",
|
||||||
|
"You don't have it.",
|
||||||
|
"No! You'll be needing it.",
|
||||||
|
"Ok.",
|
||||||
|
"You don't have any!",
|
||||||
|
"There aren't any!",
|
||||||
|
"I don't see any here!",
|
||||||
|
"You're not close enough!"
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //STATICPARSER_H
|
43
tools/create_hugo/staticschedule.h
Executable file
43
tools/create_hugo/staticschedule.h
Executable file
|
@ -0,0 +1,43 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STATICSCHEDULE_H
|
||||||
|
#define STATICSCHEDULE_H
|
||||||
|
|
||||||
|
#define NUM_SCHEDULE_TEXT 2
|
||||||
|
|
||||||
|
const char *textSchedule[NUM_SCHEDULE_TEXT] = {
|
||||||
|
"Can't find background file!",
|
||||||
|
"Obsolete saved game format will be converted!"
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
51
tools/create_hugo/staticutil.h
Executable file
51
tools/create_hugo/staticutil.h
Executable file
|
@ -0,0 +1,51 @@
|
||||||
|
/* ScummVM - Graphic Adventure Engine
|
||||||
|
*
|
||||||
|
* ScummVM is the legal property of its developers, whose names
|
||||||
|
* are too numerous to list here. Please refer to the COPYRIGHT
|
||||||
|
* file distributed with this source distribution.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or
|
||||||
|
* modify it under the terms of the GNU General Public License
|
||||||
|
* as published by the Free Software Foundation; either version 2
|
||||||
|
* of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program; if not, write to the Free Software
|
||||||
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||||
|
*
|
||||||
|
* $URL$
|
||||||
|
* $Id$
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is based on original Hugo Trilogy source code
|
||||||
|
*
|
||||||
|
* Copyright (c) 1989-1995 David P. Gray
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef STATICUTIL_H
|
||||||
|
#define STATICUTIL_H
|
||||||
|
|
||||||
|
#define NUM_UTIL_TEXT 8
|
||||||
|
|
||||||
|
const char *textUtil[NUM_UTIL_TEXT] = {
|
||||||
|
"\n\nPlease read the supplied 'technote' file which may contain information on this problem.",
|
||||||
|
"File not found: ",
|
||||||
|
"Unable to write file.\nDisk full or perhaps read-only?\n",
|
||||||
|
"Bad data file format:\n",
|
||||||
|
"Insufficient memory to run game.\n",
|
||||||
|
"Sound missing from sound file:\n",
|
||||||
|
"An error has occurred.\n",
|
||||||
|
"I'm afraid all you can do at this point is:\n\n- Load a saved game (Ctrl+L)\n- Start a new game (Ctrl+N)\n- Quit! (Alt+F4)"
|
||||||
|
// "No timers available, try again later.\n",
|
||||||
|
// "Unable to find or load VBX file:\n"
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif //STATICENGINE_H
|
Loading…
Add table
Add a link
Reference in a new issue