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
|
||||
DIST_FILES_ENGINEDATA+=drascula.dat
|
||||
endif
|
||||
ifdef ENABLE_HUGO
|
||||
DIST_FILES_ENGINEDATA+=hugo.dat
|
||||
endif
|
||||
ifdef ENABLE_KYRA
|
||||
DIST_FILES_ENGINEDATA+=kyra.dat
|
||||
endif
|
||||
|
|
|
@ -115,6 +115,9 @@ public:
|
|||
#if PLUGIN_ENABLED_STATIC(GROOVIE)
|
||||
LINK_PLUGIN(GROOVIE)
|
||||
#endif
|
||||
#if PLUGIN_ENABLED_STATIC(HUGO)
|
||||
LINK_PLUGIN(HUGO)
|
||||
#endif
|
||||
#if PLUGIN_ENABLED_STATIC(KYRA)
|
||||
LINK_PLUGIN(KYRA)
|
||||
#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 groovie "Groovie" yes "groovie2"
|
||||
add_engine groovie2 "Groovie 2 games" no
|
||||
add_engine hugo "Hugo Trilogy" no
|
||||
add_engine kyra "Legend of Kyrandia" yes "lol"
|
||||
add_engine lol "Lands of Lore" no
|
||||
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
|
||||
|
||||
ifdef ENABLE_HUGO
|
||||
DEFINES += -DENABLE_HUGO=$(ENABLE_HUGO)
|
||||
MODULES += engines/hugo
|
||||
endif
|
||||
|
||||
ifdef ENABLE_KYRA
|
||||
DEFINES += -DENABLE_KYRA=$(ENABLE_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.
|
||||
|
||||
|
||||
create_drascula
|
||||
create_drascula (sev)
|
||||
---------------
|
||||
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
|
||||
|
@ -39,6 +39,10 @@ create_drascula
|
|||
(mostly the dialog subtitles) in English, Spanish, German, French
|
||||
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)
|
||||
--------------
|
||||
|
|
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