mirror of
https://github.com/libretro/scummvm.git
synced 2025-02-21 19:51:49 +00:00
HUGO: Clean-up
svn-id: r52988
This commit is contained in:
parent
77fe52bbd7
commit
694758fd2a
@ -50,13 +50,6 @@ namespace Hugo {
|
||||
#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) {
|
||||
|
||||
}
|
||||
@ -78,17 +71,16 @@ void Screen::initDisplay() {
|
||||
|
||||
// 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) {
|
||||
debugC(3, kDebugDisplay, "moveImage(srcImage, %d, %d, %d, %d, %d, dstImage, %d, %d, %d)", x1, y1, dx, dy, width1, x2, y2, 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
|
||||
for (int16 x = dx; x--;) // For each column
|
||||
*dstImage++ = *srcImage++;
|
||||
srcImage += wrap_src; // Wrap to next line
|
||||
dstImage += wrap_dst;
|
||||
@ -157,24 +149,17 @@ overlayState_t Screen::findOvl(seq_t *seq_p, image_pt dst_p, uint16 y) {
|
||||
// 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;
|
||||
image_pt image = seq->imagePtr; // Ptr to object image data
|
||||
image_pt subFrontBuffer = &_frontBuffer[sy * XPIX + sx]; // Ptr to offset in _frontBuffer
|
||||
image_pt overlay = &_vm.getFirstOverlay()[(sy * XPIX + sx) >> 3]; // Ptr to overlay data
|
||||
int16 frontBufferwrap = XPIX - seq->x2 - 1; // Wraps dest_p after each line
|
||||
int16 imageWrap = seq->bytesPerLine8 - seq->x2 - 1;
|
||||
|
||||
for (y = 0; y < seq->lines; y++) { // Each line in object
|
||||
for (x = 0; x <= seq->x2; x++) {
|
||||
overlayState_t overlayState = UNDEF; // Overlay state of object
|
||||
for (uint16 y = 0; y < seq->lines; y++) { // Each line in object
|
||||
for (uint16 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
|
||||
@ -182,8 +167,9 @@ void Screen::displayFrame(int sx, int sy, seq_t *seq, bool foreFl) {
|
||||
overlayState = findOvl(seq, subFrontBuffer, y);// No, find it.
|
||||
if (foreFl || overlayState == FG) // Object foreground
|
||||
*subFrontBuffer = *image; // Copy pixel
|
||||
} else // No overlay
|
||||
} else { // No overlay
|
||||
*subFrontBuffer = *image; // Copy pixel
|
||||
}
|
||||
}
|
||||
image++;
|
||||
subFrontBuffer++;
|
||||
@ -216,24 +202,24 @@ void Screen::merge(rect_t *rectA, rect_t *rectB) {
|
||||
// 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");
|
||||
|
||||
int16 coalesce[BMAX]; // List of overlapping rects
|
||||
// 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++)
|
||||
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
|
||||
if (c == 0) { // None, add a new entry
|
||||
blist[blen++] = *list;
|
||||
else { // At least one overlapping
|
||||
} else { // At least one overlapping
|
||||
// Merge add-list entry with first blist entry
|
||||
bp = &blist[coalesce[0]];
|
||||
merge(list, bp);
|
||||
@ -252,15 +238,15 @@ int16 Screen::mergeLists(rect_t *list, rect_t *blist, int16 len, int16 blen, int
|
||||
// Process the display list
|
||||
// Trailing args are int16 x,y,dx,dy for the D_ADD operation
|
||||
void Screen::displayList(dupdate_t update, ...) {
|
||||
debugC(6, kDebugDisplay, "displayList");
|
||||
|
||||
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");
|
||||
rect_t *p; // Ptr to dlist entry
|
||||
|
||||
switch (update) {
|
||||
case D_INIT: // Init lists, restore whole screen
|
||||
@ -269,7 +255,7 @@ void Screen::displayList(dupdate_t update, ...) {
|
||||
break;
|
||||
case D_ADD: // Add a rectangle to list
|
||||
if (addIndex >= DMAX) {
|
||||
Utils::Warn(false, "%s", "Display list exceeded");
|
||||
Utils::Warn("%s", "Display list exceeded");
|
||||
return;
|
||||
}
|
||||
va_start(marker, update); // Initialize variable arguments
|
||||
@ -295,9 +281,10 @@ void Screen::displayList(dupdate_t update, ...) {
|
||||
blitLength = mergeLists(addList, blistList, addIndex, blitLength, BMAX);
|
||||
|
||||
// Blit the combined blit-list
|
||||
for (restoreIndex = 0, p = blistList; restoreIndex < blitLength; restoreIndex++, p++)
|
||||
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++) {
|
||||
@ -311,22 +298,19 @@ void Screen::displayList(dupdate_t update, ...) {
|
||||
}
|
||||
|
||||
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)
|
||||
*/
|
||||
|
||||
// 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];
|
||||
|
||||
// This can probably be optimized quite a bit...
|
||||
for (int y = 0; y < height; ++y)
|
||||
for (int y = 0; y < height; ++y) {
|
||||
for (int x = 0; x < width; ++x) {
|
||||
int pixel = y * width + x;
|
||||
int bitpos = pixel % 8;
|
||||
@ -334,8 +318,8 @@ void Screen::writeChr(int sx, int sy, byte color, char *local_fontdata) {
|
||||
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
|
||||
@ -343,40 +327,38 @@ int16 Screen::fontHeight() {
|
||||
debugC(2, kDebugDisplay, "fontHeight");
|
||||
|
||||
static int16 height[NUM_FONTS] = {5, 7, 8};
|
||||
return(height[_fnt - FIRST_FONT]);
|
||||
return height[_fnt - FIRST_FONT];
|
||||
}
|
||||
|
||||
|
||||
// Returns length of supplied string in pixels
|
||||
int16 Screen::stringLength(const char *s) {
|
||||
int16 sum;
|
||||
byte **fontArr = _font[_fnt];
|
||||
|
||||
debugC(2, kDebugDisplay, "stringLength(%s)", s);
|
||||
|
||||
for (sum = 0; *s; s++)
|
||||
byte **fontArr = _font[_fnt];
|
||||
int16 sum = 0;
|
||||
for (; *s; s++)
|
||||
sum += *(fontArr[(uint)*s] + 1) + 1;
|
||||
|
||||
return(sum);
|
||||
return sum;
|
||||
}
|
||||
|
||||
// Return x which would center supplied string
|
||||
int16 Screen::center(const char *s) {
|
||||
debugC(1, kDebugDisplay, "center(%s)", s);
|
||||
|
||||
return ((int16)((XPIX - stringLength(s)) >> 1));
|
||||
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, const 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);
|
||||
|
||||
byte **font = _font[_fnt];
|
||||
for (; *s; s++) {
|
||||
writeChr(sx, sy, color, (char *)font[(uint)*s]);
|
||||
sx += *(font[(uint)*s] + 1) + 1;
|
||||
@ -430,8 +412,6 @@ void Screen::drawStatusText() {
|
||||
}
|
||||
|
||||
void Screen::drawShape(int x, int y, int color1, int color2) {
|
||||
#define shapeSize 24
|
||||
|
||||
for (int i = 0; i < shapeSize; i++) {
|
||||
for (int j = 0; j < i; j++) {
|
||||
_backBuffer[320 * (y + i) + (x + shapeSize + j - i)] = color1;
|
||||
@ -451,11 +431,12 @@ void Screen::drawRectangle(bool filledFl, uint16 x1, uint16 y1, uint16 x2, uint1
|
||||
assert(y1 <= y2);
|
||||
|
||||
if (filledFl) {
|
||||
for (int i = y1; i < y2; i++)
|
||||
for (int i = y1; i < y2; i++) {
|
||||
for (int j = x1; j < x2; j++) {
|
||||
_backBuffer[320 * i + j] = color;
|
||||
_frontBuffer[320 * i + j] = color;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
warning("STUB: drawRectangle()");
|
||||
}
|
||||
@ -471,11 +452,10 @@ Screen_v1d::~Screen_v1d() {
|
||||
// TODO: This uses hardcoded fonts in hugo.dat, it should be replaced
|
||||
// by a proper implementation of .FON files
|
||||
void Screen_v1d::loadFont(int16 fontId) {
|
||||
byte height, width;
|
||||
static bool fontLoadedFl[NUM_FONTS] = {false, false, false};
|
||||
|
||||
debugC(2, kDebugDisplay, "loadFont(%d)", fontId);
|
||||
|
||||
static bool fontLoadedFl[NUM_FONTS] = {false, false, false};
|
||||
|
||||
_fnt = fontId - FIRST_FONT; // Set current font number
|
||||
|
||||
if (fontLoadedFl[_fnt]) // If already loaded, return
|
||||
@ -491,8 +471,8 @@ void Screen_v1d::loadFont(int16 fontId) {
|
||||
// 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);
|
||||
byte height = *(_fontdata[_fnt] + offset);
|
||||
byte width = *(_fontdata[_fnt] + offset + 1);
|
||||
|
||||
int16 size = height * ((width + 7) >> 3);
|
||||
for (int j = 0; j < size; j++)
|
||||
@ -510,11 +490,10 @@ Screen_v1w::~Screen_v1w() {
|
||||
|
||||
// Load font file, construct font ptrs and reverse data bytes
|
||||
void Screen_v1w::loadFont(int16 fontId) {
|
||||
byte height, width;
|
||||
static bool fontLoadedFl[NUM_FONTS] = {false, false, false};
|
||||
|
||||
debugC(2, kDebugDisplay, "loadFont(%d)", fontId);
|
||||
|
||||
static bool fontLoadedFl[NUM_FONTS] = {false, false, false};
|
||||
|
||||
_fnt = fontId - FIRST_FONT; // Set current font number
|
||||
|
||||
if (fontLoadedFl[_fnt]) // If already loaded, return
|
||||
@ -531,8 +510,8 @@ void Screen_v1w::loadFont(int16 fontId) {
|
||||
// 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);
|
||||
byte height = *(_fontdata[_fnt] + offset);
|
||||
byte width = *(_fontdata[_fnt] + offset + 1);
|
||||
|
||||
int16 size = height * ((width + 7) >> 3);
|
||||
for (int j = 0; j < size; j++)
|
||||
|
@ -32,10 +32,17 @@
|
||||
|
||||
#ifndef HUGO_DISPLAY_H
|
||||
#define HUGO_DISPLAY_H
|
||||
namespace Hugo {
|
||||
|
||||
enum overlayState_t {UNDEF, FG, BG}; // Overlay state
|
||||
struct rect_t;
|
||||
namespace Hugo {
|
||||
#define shapeSize 24
|
||||
|
||||
enum overlayState_t {UNDEF, FG, BG}; // Overlay state
|
||||
struct rect_t { // Rectangle used in Display list
|
||||
int16 x; // Position in dib
|
||||
int16 y; // Position in dib
|
||||
int16 dx; // width
|
||||
int16 dy; // height
|
||||
};
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
|
@ -48,14 +48,14 @@
|
||||
|
||||
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 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 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
|
||||
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
|
||||
@ -126,11 +126,12 @@ void HugoEngine::initConfig(inst_t action) {
|
||||
break;
|
||||
case RESET:
|
||||
// Find first tune and play it
|
||||
for (int16 i = 0; i < MAX_TUNES; i++)
|
||||
for (int16 i = 0; i < MAX_TUNES; i++) {
|
||||
if (_config.playlist[i]) {
|
||||
sound().playMusic(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
file().initSavedGame(); // Initialize saved game
|
||||
break;
|
||||
@ -210,12 +211,6 @@ void HugoEngine::readScreenFiles(int screenNum) {
|
||||
// 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
|
||||
int8 radius; // Radius for chase (8 bit signed)
|
||||
|
||||
debugC(4, kDebugEngine, "moveObjects");
|
||||
|
||||
// If route mode enabled, do special route processing
|
||||
@ -226,18 +221,19 @@ void HugoEngine::moveObjects() {
|
||||
// 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
|
||||
object_t *obj = &_objects[i]; // Get pointer to object
|
||||
seq_t *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
|
||||
case CHASE2: {
|
||||
int8 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;
|
||||
// Allowable motion wrt boundary
|
||||
int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - currImage->x1;
|
||||
int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - currImage->y2 - 1;
|
||||
if (abs(dx) <= radius)
|
||||
obj->vx = 0;
|
||||
else
|
||||
@ -266,7 +262,7 @@ void HugoEngine::moveObjects() {
|
||||
break;
|
||||
case 3:
|
||||
case 2:
|
||||
if (obj->vx != obj->oldvx) { // vx just stopped
|
||||
if (obj->vx != obj->oldvx) { // vx just stopped
|
||||
if (dx > 0) // Left & right only
|
||||
obj->currImagePtr = obj->seqList[RIGHT].seqPtr;
|
||||
else
|
||||
@ -285,6 +281,7 @@ void HugoEngine::moveObjects() {
|
||||
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
|
||||
@ -325,29 +322,31 @@ void HugoEngine::moveObjects() {
|
||||
|
||||
// Move objects, allowing for boundaries
|
||||
for (int i = 0; i < _numObj; i++) {
|
||||
obj = &_objects[i]; // Get pointer to object
|
||||
object_t *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
|
||||
// to move as close to a boundary as possible without crossing it.
|
||||
seq_t *currImage = obj->currImagePtr; // Get ptr to current image
|
||||
// object coordinates
|
||||
int x1 = obj->x + currImage->x1; // Left edge of object
|
||||
int x2 = obj->x + currImage->x2; // Right edge
|
||||
int y1 = obj->y + currImage->y1; // Top edge
|
||||
int 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);
|
||||
|
||||
// Allowable motion wrt boundary
|
||||
int 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);
|
||||
|
||||
int dy = deltaY(x1, x2, obj->vy, y2);
|
||||
if (dy != obj->vy) {
|
||||
// An object boundary collision!
|
||||
boundaryCollision(obj);
|
||||
@ -377,8 +376,8 @@ void HugoEngine::moveObjects() {
|
||||
|
||||
// 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
|
||||
object_t *obj = &_objects[i]; // Get pointer to object
|
||||
seq_t *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);
|
||||
}
|
||||
@ -405,70 +404,72 @@ int HugoEngine::deltaX(int x1, int x2, int vx, int y) {
|
||||
// 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
|
||||
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
|
||||
for (int i = x1 >> 3; i <= (x2 + vx) >> 3; i++) {// Search by byte
|
||||
int b = Utils::firstBit((byte)(_boundary[y + i] | _objBound[y + i]));
|
||||
if (b < 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
|
||||
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
|
||||
for (int i = x2 >> 3; i >= (x1 + vx) >> 3; i--) {// Search by byte
|
||||
int b = Utils::lastBit((byte)(_boundary[y + i] | _objBound[y + i]));
|
||||
if (b < 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 (b > x1 + ((x2 - x1) >> 1)) ? vx : b - x1 + 1; // return dx
|
||||
}
|
||||
}
|
||||
}
|
||||
return(vx);
|
||||
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
|
||||
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]) != 0) { // Any bit set
|
||||
int inc = (vy > 0) ? 1 : -1;
|
||||
for (int j = y + inc; j != (y + vy + inc); j += inc) { //Search by byte
|
||||
for (int i = x1 >> 3; i <= x2 >> 3; i++) {
|
||||
int b = _boundary[j * XBYTES + i] | _objBound[j * XBYTES + i];
|
||||
if (b != 0) { // 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 j - y - inc;
|
||||
}
|
||||
return(vy);
|
||||
}
|
||||
}
|
||||
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
|
||||
byte *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
|
||||
@ -480,13 +481,10 @@ void HugoEngine::storeBoundary(int x1, int x2, int y) {
|
||||
|
||||
// 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
|
||||
for (int i = x1 >> 3; i <= x2 >> 3; i++) { // For each byte in line
|
||||
byte *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
|
||||
@ -499,16 +497,15 @@ void HugoEngine::clearBoundary(int x1, int x2, int y) {
|
||||
// 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");
|
||||
|
||||
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
|
||||
seq_t *currImage = _hero->currImagePtr; // Get ptr to current image
|
||||
|
||||
// hero coordinates
|
||||
int x1 = _hero->x + currImage->x1; // Left edge of object
|
||||
int x2 = _hero->x + currImage->x2; // Right edge
|
||||
int y1 = _hero->y + currImage->y1; // Top edge
|
||||
int y2 = _hero->y + currImage->y2; // Bottom edge
|
||||
|
||||
if (x1 < _maze.x1) {
|
||||
// Exit west
|
||||
@ -545,8 +542,6 @@ void HugoEngine::processMaze() {
|
||||
// increasing vertical position, using y+y2 as the baseline
|
||||
// Returns -1 if ay2 < by2 else 1 if ay2 > by2 else 0
|
||||
int HugoEngine::y2comp(const void *a, const void *b) {
|
||||
int ay2, by2;
|
||||
|
||||
debugC(6, kDebugEngine, "y2comp");
|
||||
|
||||
const object_t *p1 = &s_Engine->_objects[*(const byte *)a];
|
||||
@ -554,24 +549,24 @@ int HugoEngine::y2comp(const void *a, const void *b) {
|
||||
|
||||
if (p1 == p2)
|
||||
// Why does qsort try the same indexes?
|
||||
return (0);
|
||||
return 0;
|
||||
|
||||
if (p1->priority == BACKGROUND)
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
if (p2->priority == BACKGROUND)
|
||||
return (1);
|
||||
return 1;
|
||||
|
||||
if (p1->priority == FOREGROUND)
|
||||
return (1);
|
||||
return 1;
|
||||
|
||||
if (p2->priority == FOREGROUND)
|
||||
return (-1);
|
||||
return -1;
|
||||
|
||||
ay2 = p1->y + p1->currImagePtr->y2;
|
||||
by2 = p2->y + p2->currImagePtr->y2;
|
||||
int ay2 = p1->y + p1->currImagePtr->y2;
|
||||
int by2 = p2->y + p2->currImagePtr->y2;
|
||||
|
||||
return(ay2 - by2);
|
||||
return ay2 - by2;
|
||||
}
|
||||
|
||||
// Draw all objects on screen as follows:
|
||||
@ -579,16 +574,14 @@ int HugoEngine::y2comp(const void *a, const void *b) {
|
||||
// 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];
|
||||
int num_objs = 0;
|
||||
byte objindex[MAX_OBJECTS]; // Array of indeces to objects
|
||||
|
||||
for (int i = 0; i < _numObj; i++) {
|
||||
object_t *obj = &_objects[i];
|
||||
if ((obj->screenIndex == *_screen_p) && (obj->cycling >= ALMOST_INVISIBLE))
|
||||
objindex[num_objs++] = i;
|
||||
}
|
||||
@ -597,13 +590,13 @@ void HugoEngine::updateImages() {
|
||||
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]];
|
||||
for (int i = 0; i < num_objs; i++) {
|
||||
object_t *obj = &_objects[objindex[i]];
|
||||
// Count down inter-frame timer
|
||||
if (obj->frameTimer)
|
||||
obj->frameTimer--;
|
||||
|
||||
if (obj->cycling > ALMOST_INVISIBLE) // Only if visible
|
||||
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);
|
||||
@ -614,21 +607,24 @@ void HugoEngine::updateImages() {
|
||||
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
|
||||
case CYCLE_BACKWARD: {
|
||||
seq_t *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]];
|
||||
for (int i = 0; i < num_objs; i++) {
|
||||
object_t *obj = &_objects[objindex[i]];
|
||||
if (obj->cycling != INVISIBLE) {
|
||||
// Only if it's visible
|
||||
if (obj->cycling == ALMOST_INVISIBLE)
|
||||
@ -646,32 +642,39 @@ void HugoEngine::updateImages() {
|
||||
// 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
|
||||
for (int 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:
|
||||
case CYCLE_BACKWARD: {
|
||||
if (!obj->frameTimer) {
|
||||
// Time to step to prev frame
|
||||
seqPtr = obj->currImagePtr;
|
||||
seq_t *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
|
||||
for (int 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;
|
||||
}
|
||||
@ -684,39 +687,39 @@ void HugoEngine::updateImages() {
|
||||
// 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);
|
||||
|
||||
int16 objIndex = -1; // Index of found object
|
||||
uint16 y2Max = 0; // Greatest y2
|
||||
object_t *obj = _objects;
|
||||
// Check objects on screen
|
||||
for (i = 0, obj = _objects; i < _numObj; i++, obj++) {
|
||||
for (int i = 0; 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;
|
||||
seq_t *curImage = obj->currImagePtr;
|
||||
// Object must have a visible image...
|
||||
if (curImage != NULL && obj->cycling != INVISIBLE) {
|
||||
if (curImage != 0 && 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 (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
|
||||
}
|
||||
} else {
|
||||
// ...or a dummy object that has a hotspot rectangle
|
||||
if (curImage == NULL && obj->vxPath != 0 && !obj->carriedFl) {
|
||||
if (curImage == 0 && 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 ((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;
|
||||
@ -724,64 +727,70 @@ int16 HugoEngine::findObject(uint16 x, uint16 y) {
|
||||
|
||||
// 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++)
|
||||
seq_t *curImage = obj->currImagePtr;
|
||||
int16 y = obj->y + curImage->y2 - 1;
|
||||
|
||||
bool foundFl = true;
|
||||
// Try left rear corner
|
||||
for (int16 x = *destx = 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 (!foundFl) { // Try right rear corner
|
||||
foundFl = true;
|
||||
for (int16 x = *destx = 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 (!foundFl) { // Try left front corner
|
||||
foundFl = true;
|
||||
y += 2;
|
||||
for (int16 x = *destx = 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 (!foundFl) { // Try right rear corner
|
||||
foundFl = true;
|
||||
for (int16 x = *destx = 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);
|
||||
return foundFl;
|
||||
}
|
||||
|
||||
// Search background command list for this screen for supplied object.
|
||||
// Return first associated verb (not "look") or NULL if none found.
|
||||
// Return first associated verb (not "look") or 0 if none found.
|
||||
char *HugoEngine::useBG(char *name) {
|
||||
debugC(1, kDebugEngine, "useBG(%s)", name);
|
||||
|
||||
objectList_t p = _backgroundObjects[*_screen_p];
|
||||
for (int i = 0; *_arrayVerbs[p[i].verbIndex]; i++)
|
||||
for (int 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]);
|
||||
p[i].verbIndex != _look) &&
|
||||
((p[i].roomState == DONT_CARE) || (p[i].roomState == _screenStates[*_screen_p])))
|
||||
return _arrayVerbs[p[i].verbIndex][0];
|
||||
}
|
||||
|
||||
return (NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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);
|
||||
|
||||
char *verb; // Background verb to use directly
|
||||
object_t *obj = &_objects[objId]; // Ptr to object
|
||||
if (_status.inventoryObjId == -1) {
|
||||
// Get or use objid directly
|
||||
if ((obj->genericCmd & TAKE) || obj->objValue) // Get collectible item
|
||||
@ -792,7 +801,7 @@ void HugoEngine::useObject(int16 objId) {
|
||||
sprintf(_line, "%s %s", _arrayVerbs[_drop][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)
|
||||
else if ((verb = useBG(_arrayNouns[obj->nounIndex][0])) != 0)
|
||||
sprintf(_line, "%s %s", verb, _arrayNouns[obj->nounIndex][0]);
|
||||
else
|
||||
return; // Can't use object directly
|
||||
@ -802,10 +811,11 @@ void HugoEngine::useObject(int16 objId) {
|
||||
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++)
|
||||
for (uses_t *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++)
|
||||
bool foundFl = false;
|
||||
for (target_t *target = use->targets; _arrayNouns[target->nounIndex] != 0; 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]);
|
||||
@ -820,6 +830,7 @@ void HugoEngine::useObject(int16 objId) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (_status.inventoryState == I_ACTIVE) // If inventory active, remove it
|
||||
@ -833,30 +844,27 @@ void HugoEngine::useObject(int16 objId) {
|
||||
void HugoEngine::lookObject(object_t *obj) {
|
||||
debugC(1, kDebugEngine, "lookObject");
|
||||
|
||||
if (obj == _hero) {
|
||||
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)
|
||||
if (_hero->seqList[0].seqPtr == 0)
|
||||
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
|
||||
object_t *obj = &_objects[i];
|
||||
for (int j = 0; j < obj->seqNumb; j++) { // for each sequence
|
||||
seq_t *seq = obj->seqList[j].seqPtr; // Free image
|
||||
if (seq == 0) // Failure during database load
|
||||
break;
|
||||
do {
|
||||
free(seq->imagePtr);
|
||||
@ -869,10 +877,9 @@ void HugoEngine::freeObjects() {
|
||||
|
||||
// Add action lists for this screen to event queue
|
||||
void HugoEngine::screenActions(int screenNum) {
|
||||
uint16 *screenAct = _screenActs[screenNum];
|
||||
|
||||
debugC(1, kDebugEngine, "screenActions(%d)", screenNum);
|
||||
|
||||
uint16 *screenAct = _screenActs[screenNum];
|
||||
if (screenAct) {
|
||||
for (int i = 0; screenAct[i]; i++)
|
||||
scheduler().insertActionList(screenAct[i]);
|
||||
@ -884,29 +891,27 @@ 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
|
||||
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;
|
||||
int8 radius; // 8 bits signed
|
||||
hotspot_t *hotspot;
|
||||
|
||||
debugC(1, kDebugEngine, "boundaryCollision");
|
||||
|
||||
if (obj == _hero) {
|
||||
// Hotspots only relevant to HERO
|
||||
int x;
|
||||
if (obj->vx > 0)
|
||||
x = obj->x + obj->currImagePtr->x2;
|
||||
else
|
||||
x = obj->x + obj->currImagePtr->x1;
|
||||
y = obj->y + obj->currImagePtr->y2;
|
||||
int y = obj->y + obj->currImagePtr->y2;
|
||||
|
||||
for (int i = 0; _hotspots[i].screenIndex >= 0; i++) {
|
||||
hotspot = &_hotspots[i];
|
||||
hotspot_t *hotspot = &_hotspots[i];
|
||||
if (hotspot->screenIndex == obj->screenIndex)
|
||||
if ((x >= hotspot->x1) && (x <= hotspot->x2) && (y >= hotspot->y1) && (y <= hotspot->y2)) {
|
||||
scheduler().insertActionList(hotspot->actIndex);
|
||||
@ -915,10 +920,10 @@ void HugoEngine::boundaryCollision(object_t *obj) {
|
||||
}
|
||||
} 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;
|
||||
int dx = _hero->x + _hero->currImagePtr->x1 - obj->x - obj->currImagePtr->x1;
|
||||
int dy = _hero->y + _hero->currImagePtr->y2 - obj->y - obj->currImagePtr->y2;
|
||||
// If object's radius is infinity, use a closer value
|
||||
radius = obj->radius;
|
||||
int8 radius = obj->radius;
|
||||
if (radius < 0)
|
||||
radius = DX * 2;
|
||||
if ((abs(dx) <= radius) && (abs(dy) <= radius))
|
||||
@ -940,14 +945,12 @@ void HugoEngine::initNewScreenDisplay() {
|
||||
|
||||
// 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++)
|
||||
for (int i = 0; i < _numObj; i++)
|
||||
_maxscore += _objects[i].objValue;
|
||||
|
||||
for (i = 0; i < _numBonuses; i++)
|
||||
for (int i = 0; i < _numBonuses; i++)
|
||||
_maxscore += _points[i].score;
|
||||
}
|
||||
|
||||
|
@ -52,18 +52,17 @@ FileManager::~FileManager() {
|
||||
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
|
||||
int8 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
|
||||
for (int16 r = 0, g = bpl, b = g + bpl, i = b + bpl; r < bpl; r++, g++, b++, i++) { // Each byte in all planes
|
||||
for (int8 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;
|
||||
}
|
||||
|
||||
@ -71,28 +70,10 @@ seq_t *FileManager::readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool
|
||||
// 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
|
||||
static PCC_header_t PCC_header;
|
||||
PCC_header.mfctr = f.readByte();
|
||||
PCC_header.vers = f.readByte();
|
||||
PCC_header.enc = f.readByte();
|
||||
@ -112,31 +93,38 @@ seq_t *FileManager::readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool
|
||||
if (PCC_header.mfctr != 10)
|
||||
Utils::Error(PCCH_ERR, "%s", name);
|
||||
|
||||
// Allocate memory for seq_t if NULL
|
||||
if (seqPtr == NULL)
|
||||
if ((seqPtr = (seq_t *)malloc(sizeof(seq_t))) == NULL)
|
||||
// Allocate memory for seq_t if 0
|
||||
if (seqPtr == 0) {
|
||||
if ((seqPtr = (seq_t *)malloc(sizeof(seq_t))) == 0)
|
||||
Utils::Error(HEAP_ERR, "%s", 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
|
||||
uint16 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;
|
||||
// Size of the image
|
||||
uint16 size = seqPtr->lines * seqPtr->bytesPerLine8;
|
||||
|
||||
// Allocate memory for image data if NULL
|
||||
if (imagePtr == NULL)
|
||||
if ((imagePtr = (byte *)malloc((size_t) size)) == NULL)
|
||||
if (imagePtr == 0) {
|
||||
if ((imagePtr = (byte *)malloc((size_t) size)) == 0)
|
||||
Utils::Error(HEAP_ERR, "%s", name);
|
||||
}
|
||||
|
||||
seqPtr->imagePtr = imagePtr;
|
||||
|
||||
// Process the image data, converting to 8-bit DIB format
|
||||
uint16 y = 0; // Current line index
|
||||
byte pline[XPIX]; // Hold 4 planes of data
|
||||
byte *p = pline; // Ptr to above
|
||||
while (y < seqPtr->lines) {
|
||||
c = f.readByte();
|
||||
byte c = f.readByte();
|
||||
if ((c & REP_MASK) == REP_MASK) {
|
||||
d = f.readByte(); // Read data byte
|
||||
for (i = 0; i < (c & LEN_MASK); i++) {
|
||||
byte d = f.readByte(); // Read data byte
|
||||
for (int i = 0; i < (c & LEN_MASK); i++) {
|
||||
*p++ = d;
|
||||
if ((uint16)(p - pline) == bytesPerLine4)
|
||||
p = convertPCC(pline, y++, PCC_header.bytesPerLine, imagePtr);
|
||||
@ -152,13 +140,6 @@ seq_t *FileManager::readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool
|
||||
|
||||
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 = 0; // 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
|
||||
@ -167,6 +148,7 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
|
||||
if (_vm.isPacked()) {
|
||||
_objectsArchive.seek((uint32)objNum * sizeof(objBlock_t), SEEK_SET);
|
||||
|
||||
objBlock_t objBlock; // Info on file within database
|
||||
objBlock.objOffset = _objectsArchive.readUint32LE();
|
||||
objBlock.objLength = _objectsArchive.readUint32LE();
|
||||
|
||||
@ -182,31 +164,35 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
|
||||
}
|
||||
}
|
||||
|
||||
bool firstFl = true; // Initializes pcx read function
|
||||
seq_t *seqPtr = 0; // Ptr to sequence structure
|
||||
|
||||
// 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
|
||||
for (int j = 0; j < objPtr->seqNumb; j++) { // for each sequence
|
||||
for (int 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]);
|
||||
seqPtr = readPCX(_objectsArchive, 0, 0, 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->nextSeqPtr = readPCX(_objectsArchive, 0, 0, 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;
|
||||
uint16 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
|
||||
|
||||
image_pt dibPtr = seqPtr->imagePtr;
|
||||
for (int y = 0; y < seqPtr->lines; y++, dibPtr += seqPtr->bytesPerLine8 - x2) {
|
||||
for (int x = 0; x < x2; x++) {
|
||||
if (*dibPtr++) { // Some data found
|
||||
if (x < seqPtr->x1)
|
||||
seqPtr->x1 = x;
|
||||
if (x > seqPtr->x2)
|
||||
@ -216,6 +202,8 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
|
||||
if (y > seqPtr->y2)
|
||||
seqPtr->y2 = y;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
seqPtr->nextSeqPtr = objPtr->seqList[j].seqPtr; // loop linked list to head
|
||||
}
|
||||
@ -242,27 +230,23 @@ void FileManager::readImage(int objNum, object_t *objPtr) {
|
||||
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);
|
||||
return 0;
|
||||
|
||||
// Open sounds file
|
||||
Common::File fp; // Handle to SOUND_FILE
|
||||
if (!fp.open(SOUND_FILE)) {
|
||||
// Error(FILE_ERR, "%s", SOUND_FILE);
|
||||
warning("Hugo Error: File not found %s", SOUND_FILE);
|
||||
return(NULL);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If this is the first call, read the lookup table
|
||||
static bool has_read_header = false;
|
||||
static sound_hdr_t s_hdr[MAX_SOUNDS]; // Sound lookup table
|
||||
|
||||
if (!has_read_header) {
|
||||
if (fp.read(s_hdr, sizeof(s_hdr)) != sizeof(s_hdr))
|
||||
Utils::Error(FILE_ERR, "%s", SOUND_FILE);
|
||||
@ -274,9 +258,10 @@ sound_pt FileManager::getSound(int16 sound, uint16 *size) {
|
||||
Utils::Error(SOUND_ERR, "%s", SOUND_FILE);
|
||||
|
||||
// Allocate memory for sound or music, if possible
|
||||
if ((soundPtr = (byte *)malloc(s_hdr[sound].size)) == 0) {
|
||||
Utils::Warn(false, "%s", "Low on memory");
|
||||
return(NULL);
|
||||
sound_pt soundPtr = (byte *)malloc(s_hdr[sound].size); // Ptr to sound data
|
||||
if (soundPtr == 0) {
|
||||
Utils::Warn("%s", "Low on memory");
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Seek to data and read it
|
||||
@ -301,46 +286,39 @@ bool FileManager::fileExists(char *filename) {
|
||||
|
||||
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++) {
|
||||
bool found = false;
|
||||
for (int j = 0; !found && (j < obj->seqNumb); j++) {
|
||||
seq_t *q = obj->seqList[j].seqPtr;
|
||||
for (int k = 0; !found && (k < obj->seqList[j].imageNbr); k++) {
|
||||
if (obj->currImagePtr == q) {
|
||||
found = true;
|
||||
obj->curSeqNum = j;
|
||||
obj->curImageNum = k;
|
||||
} else
|
||||
} 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++)
|
||||
seq_t *q = obj->seqList[obj->curSeqNum].seqPtr;
|
||||
for (int 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
|
||||
char path[256]; // Full path of saved game
|
||||
if (slot == -1)
|
||||
sprintf(path, "%s", _vm._initFilename);
|
||||
else
|
||||
@ -359,7 +337,7 @@ void FileManager::saveGame(int16 slot, const char *descrip) {
|
||||
out->write(descrip, DESCRIPLEN);
|
||||
|
||||
// Save objects
|
||||
for (i = 0; i < _vm._numObj; i++) {
|
||||
for (int 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));
|
||||
@ -405,20 +383,13 @@ void FileManager::saveGame(int16 slot, const char *descrip) {
|
||||
|
||||
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
|
||||
char path[256]; // Full path of saved game
|
||||
if (slot == -1)
|
||||
sprintf(path, "%s", _vm._initFilename);
|
||||
else
|
||||
@ -445,10 +416,11 @@ void FileManager::restoreGame(int16 slot) {
|
||||
|
||||
// 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];
|
||||
for (int i = 0; i < _vm._numObj; i++) {
|
||||
object_t *p = &_vm._objects[i];
|
||||
seqList_t seqList[MAX_SEQUENCES];
|
||||
memcpy(seqList, p->seqList, sizeof(seqList_t));
|
||||
cmdIndex = p->cmdIndex;
|
||||
uint16 cmdIndex = p->cmdIndex;
|
||||
in->read(p, sizeof(object_t));
|
||||
p->cmdIndex = cmdIndex;
|
||||
memcpy(p->seqList, seqList, sizeof(seqList_t));
|
||||
@ -457,9 +429,10 @@ void FileManager::restoreGame(int16 slot) {
|
||||
in->read(&_vm._heroImage, sizeof(_vm._heroImage));
|
||||
|
||||
// If hero swapped in saved game, swap it
|
||||
if ((i = _vm._heroImage) != HERO)
|
||||
int heroImg = _vm._heroImage;
|
||||
if (heroImg != HERO)
|
||||
_vm.scheduler().swapImages(HERO, _vm._heroImage);
|
||||
_vm._heroImage = i;
|
||||
_vm._heroImage = heroImg;
|
||||
|
||||
status_t &gameStatus = _vm.getGameStatus();
|
||||
|
||||
@ -476,7 +449,7 @@ void FileManager::restoreGame(int16 slot) {
|
||||
in->read(_vm._points, sizeof(point_t) * _vm._numBonuses);
|
||||
|
||||
// Restore ptrs to currently loaded objects
|
||||
for (i = 0; i < _vm._numObj; i++)
|
||||
for (int i = 0; i < _vm._numObj; i++)
|
||||
restoreSeq(&_vm._objects[i]);
|
||||
|
||||
// Now restore time of the save and the event queue
|
||||
@ -498,15 +471,12 @@ void FileManager::initSavedGame() {
|
||||
// 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
|
||||
char path[256]; // Full path of INITFILE
|
||||
sprintf(path, "%s", _vm._initFilename);
|
||||
|
||||
|
||||
// Force save of initial game
|
||||
if (_vm.getGameStatus().initSaveFl)
|
||||
saveGame(-1, "");
|
||||
@ -530,22 +500,15 @@ void FileManager::initSavedGame() {
|
||||
Utils::Error(WRITE_ERR, "%s", 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, "%s", PBFILE);
|
||||
} else if (recordFl)
|
||||
} else if (recordFl) {
|
||||
fpb = fopen(PBFILE, "wb");
|
||||
}
|
||||
pbdata.time = 0; // Say no key available
|
||||
}
|
||||
|
||||
@ -555,23 +518,21 @@ void FileManager::closePlaybackFile() {
|
||||
|
||||
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");
|
||||
|
||||
Common::File ofp;
|
||||
if (!ofp.open(BOOTFILE)) {
|
||||
if (_vm._gameVariant == 3) {
|
||||
//TODO initialize properly _boot structure
|
||||
warning("printBootText - Skipping as H1 Dos may be a freeware");
|
||||
return;
|
||||
} else
|
||||
} else {
|
||||
Utils::Error(FILE_ERR, "%s", BOOTFILE);
|
||||
}
|
||||
}
|
||||
|
||||
// Allocate space for the text and print it
|
||||
buf = (char *)malloc(_boot.exit_len + 1);
|
||||
char *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);
|
||||
@ -579,6 +540,7 @@ void FileManager::printBootText() {
|
||||
Utils::Error(FILE_ERR, "%s", BOOTFILE);
|
||||
|
||||
// Decrypt the exit text, using CRYPT substring
|
||||
int i;
|
||||
for (i = 0; i < _boot.exit_len; i++)
|
||||
buf[i] ^= CRYPT[i % strlen(CRYPT)];
|
||||
|
||||
@ -595,20 +557,17 @@ void FileManager::printBootText() {
|
||||
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");
|
||||
|
||||
Common::File ofp;
|
||||
if (!ofp.open(BOOTFILE)) {
|
||||
if (_vm._gameVariant == 3) {
|
||||
//TODO initialize properly _boot structure
|
||||
warning("readBootFile - Skipping as H1 Dos may be a freeware");
|
||||
return;
|
||||
} else
|
||||
} else {
|
||||
Utils::Error(FILE_ERR, "%s", BOOTFILE);
|
||||
}
|
||||
}
|
||||
|
||||
if (ofp.size() < (int32)sizeof(_boot))
|
||||
@ -620,8 +579,10 @@ void FileManager::readBootFile() {
|
||||
ofp.read(_boot.distrib, sizeof(_boot.distrib));
|
||||
_boot.exit_len = ofp.readUint16LE();
|
||||
|
||||
p = (byte *)&_boot;
|
||||
for (i = 0, checksum = 0; i < sizeof(_boot); i++) {
|
||||
byte *p = (byte *)&_boot;
|
||||
|
||||
byte checksum = 0;
|
||||
for (uint32 i = 0; i < sizeof(_boot); i++) {
|
||||
checksum ^= p[i];
|
||||
p[i] ^= CRYPT[i % strlen(CRYPT)];
|
||||
}
|
||||
@ -633,16 +594,16 @@ void FileManager::readBootFile() {
|
||||
|
||||
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);
|
||||
|
||||
static bool firstFl = true;
|
||||
static uif_hdr_t UIFHeader[MAX_UIFS]; // Lookup for uif fonts/images
|
||||
|
||||
// Initialize offset lookup if not read yet
|
||||
if (firstFl) {
|
||||
firstFl = false;
|
||||
// Open unbuffered to do far read
|
||||
Common::File ip; // Image data file
|
||||
if (!ip.open(UIF_FILE))
|
||||
Utils::Error(FILE_ERR, "%s", UIF_FILE);
|
||||
|
||||
@ -661,24 +622,22 @@ uif_hdr_t *FileManager::getUIFHeader(uif_t 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
|
||||
Common::File ip; // UIF_FILE handle
|
||||
if (!ip.open(UIF_FILE))
|
||||
Utils::Error(FILE_ERR, "%s", UIF_FILE);
|
||||
|
||||
// Seek to data
|
||||
UIFHeaderPtr = getUIFHeader((uif_t)id);
|
||||
uif_hdr_t *UIFHeaderPtr = getUIFHeader((uif_t)id);
|
||||
ip.seek(UIFHeaderPtr->offset, SEEK_SET);
|
||||
|
||||
// We support pcx images and straight data
|
||||
seq_t dummySeq; // Dummy seq_t for image data
|
||||
switch (id) {
|
||||
case UIF_IMAGES: // Read uif images file
|
||||
readPCX(ip, &seq, buf, true, UIF_FILE);
|
||||
readPCX(ip, &dummySeq, buf, true, UIF_FILE);
|
||||
break;
|
||||
default: // Read file data into supplied array
|
||||
if (ip.read(buf, UIFHeaderPtr->size) != UIFHeaderPtr->size)
|
||||
@ -694,30 +653,28 @@ void FileManager::instructions() {
|
||||
// Only in DOS versions
|
||||
|
||||
Common::File f;
|
||||
char line[1024], *wrkLine;
|
||||
char readBuf[2];
|
||||
|
||||
wrkLine = line;
|
||||
if (!f.open(HELPFILE)) {
|
||||
warning("help.dat not found");
|
||||
return;
|
||||
}
|
||||
|
||||
char readBuf[2];
|
||||
while (f.read(readBuf, 1)) {
|
||||
char line[1024], *wrkLine;
|
||||
wrkLine = line;
|
||||
wrkLine[0] = readBuf[0];
|
||||
wrkLine++;
|
||||
do {
|
||||
f.read(wrkLine, 1);
|
||||
} while (*wrkLine++ != EOP);
|
||||
wrkLine[-2] = '\0'; /* Remove EOP and previous CR */
|
||||
wrkLine[-2] = '\0'; // Remove EOP and previous CR
|
||||
Utils::Box(BOX_ANY, "%s", line);
|
||||
wrkLine = line;
|
||||
f.read(readBuf, 2); /* Remove CRLF after EOP */
|
||||
f.read(readBuf, 2); // Remove CRLF after EOP
|
||||
}
|
||||
f.close();
|
||||
}
|
||||
|
||||
|
||||
FileManager_v1d::FileManager_v1d(HugoEngine &vm) : FileManager(vm) {
|
||||
}
|
||||
|
||||
@ -734,18 +691,15 @@ void FileManager_v1d::closeDatabaseFiles() {
|
||||
|
||||
void FileManager_v1d::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
|
||||
// Open and read in an overlay file, close file
|
||||
uint32 i = 0;
|
||||
image_pt tmpImage = image; // temp ptr to overlay file
|
||||
|
||||
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
|
||||
|
||||
const char *ovl_ext[] = {".b", ".o", ".ob"};
|
||||
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
|
||||
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++)
|
||||
for (uint32 i = 0; i < OVL_SIZE; i++)
|
||||
image[i] = 0;
|
||||
return;
|
||||
}
|
||||
@ -753,22 +707,23 @@ void FileManager_v1d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
if (!_sceneryArchive1.open(buf))
|
||||
Utils::Error(FILE_ERR, "%s", buf);
|
||||
|
||||
image_pt tmpImage = image; // temp ptr to overlay file
|
||||
|
||||
_sceneryArchive1.read(tmpImage, OVL_SIZE);
|
||||
_sceneryArchive1.close();
|
||||
}
|
||||
|
||||
void FileManager_v1d::readBackground(int screenIndex) {
|
||||
// Read a PCX image into dib_a
|
||||
seq_t seq; // Image sequence structure for Read_pcx
|
||||
|
||||
debugC(1, kDebugFile, "readBackground(%d)", screenIndex);
|
||||
|
||||
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
|
||||
char *buf = (char *) malloc(2048 + 1); // Buffer for file access
|
||||
strcat(strcpy(buf, _vm._screenNames[screenIndex]), ".ART");
|
||||
if (!_sceneryArchive1.open(buf))
|
||||
Utils::Error(FILE_ERR, "%s", buf);
|
||||
// Read the image into dummy seq and static dib_a
|
||||
readPCX(_sceneryArchive1, &seq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
seq_t dummySeq; // Image sequence structure for Read_pcx
|
||||
readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
|
||||
_sceneryArchive1.close();
|
||||
}
|
||||
@ -806,13 +761,11 @@ void FileManager_v2d::closeDatabaseFiles() {
|
||||
|
||||
void FileManager_v2d::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);
|
||||
|
||||
_sceneryArchive1.seek((uint32) screenIndex * sizeof(sceneBlock_t), SEEK_SET);
|
||||
|
||||
sceneBlock_t sceneBlock; // Read a database header entry
|
||||
sceneBlock.scene_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.scene_len = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.b_off = _sceneryArchive1.readUint32LE();
|
||||
@ -825,21 +778,18 @@ void FileManager_v2d::readBackground(int screenIndex) {
|
||||
_sceneryArchive1.seek(sceneBlock.scene_off, SEEK_SET);
|
||||
|
||||
// Read the image into dummy seq and static dib_a
|
||||
readPCX(_sceneryArchive1, &seq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
seq_t dummySeq; // Image sequence structure for Read_pcx
|
||||
readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
}
|
||||
|
||||
void FileManager_v2d::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
|
||||
// Open and read in an overlay file, close file
|
||||
uint32 i = 0;
|
||||
int16 j, k;
|
||||
int8 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);
|
||||
|
||||
image_pt tmpImage = image; // temp ptr to overlay file
|
||||
_sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET);
|
||||
|
||||
sceneBlock_t sceneBlock; // Database header entry
|
||||
sceneBlock.scene_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.scene_len = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.b_off = _sceneryArchive1.readUint32LE();
|
||||
@ -849,6 +799,7 @@ void FileManager_v2d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
sceneBlock.ob_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.ob_len = _sceneryArchive1.readUint32LE();
|
||||
|
||||
uint32 i = 0;
|
||||
switch (overlayType) {
|
||||
case BOUNDARY:
|
||||
_sceneryArchive1.seek(sceneBlock.b_off, SEEK_SET);
|
||||
@ -873,16 +824,16 @@ void FileManager_v2d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
}
|
||||
|
||||
// Read in the overlay file using MAC Packbits. (We're not proud!)
|
||||
k = 0; // byte count
|
||||
int16 k = 0; // byte count
|
||||
do {
|
||||
data = _sceneryArchive1.readByte(); // Read a code byte
|
||||
if ((byte)data == 0x80) // Noop
|
||||
int8 data = _sceneryArchive1.readByte(); // Read a code byte
|
||||
if ((byte)data == 0x80) // Noop
|
||||
k = k;
|
||||
else if (data >= 0) { // Copy next data+1 literally
|
||||
else if (data >= 0) { // Copy next data+1 literally
|
||||
for (i = 0; i <= (byte)data; i++, k++)
|
||||
*tmpImage++ = _sceneryArchive1.readByte();
|
||||
} else { // Repeat next byte -data+1 times
|
||||
j = _sceneryArchive1.readByte();
|
||||
} else { // Repeat next byte -data+1 times
|
||||
int16 j = _sceneryArchive1.readByte();
|
||||
|
||||
for (i = 0; i < (byte)(-data + 1); i++, k++)
|
||||
*tmpImage++ = j;
|
||||
@ -892,12 +843,11 @@ void FileManager_v2d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
|
||||
char *FileManager_v2d::fetchString(int index) {
|
||||
// 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);
|
||||
uint32 off1, off2;
|
||||
if (_stringArchive.read((char *)&off1, sizeof(uint32)) == 0)
|
||||
Utils::Error(FILE_ERR, "%s", "String offset");
|
||||
if (_stringArchive.read((char *)&off2, sizeof(uint32)) == 0)
|
||||
@ -927,14 +877,12 @@ FileManager_v1w::~FileManager_v1w() {
|
||||
|
||||
void FileManager_v1w::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
|
||||
// Open and read in an overlay file, close file
|
||||
uint32 i = 0;
|
||||
image_pt tmpImage = image; // temp ptr to overlay file
|
||||
sceneBlock_t sceneBlock; // Database header entry
|
||||
|
||||
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
|
||||
|
||||
image_pt tmpImage = image; // temp ptr to overlay file
|
||||
_sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET);
|
||||
|
||||
sceneBlock_t sceneBlock; // Database header entry
|
||||
sceneBlock.scene_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.scene_len = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.b_off = _sceneryArchive1.readUint32LE();
|
||||
@ -944,6 +892,7 @@ void FileManager_v1w::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
sceneBlock.ob_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.ob_len = _sceneryArchive1.readUint32LE();
|
||||
|
||||
uint32 i = 0;
|
||||
switch (overlayType) {
|
||||
case BOUNDARY:
|
||||
_sceneryArchive1.seek(sceneBlock.b_off, SEEK_SET);
|
||||
@ -966,7 +915,6 @@ void FileManager_v1w::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
image[i] = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
_sceneryArchive1.read(tmpImage, OVL_SIZE);
|
||||
}
|
||||
|
||||
@ -978,14 +926,11 @@ FileManager_v3d::~FileManager_v3d() {
|
||||
|
||||
void FileManager_v3d::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
|
||||
Common::File sceneryArchive;
|
||||
|
||||
debugC(1, kDebugFile, "readBackground(%d)", screenIndex);
|
||||
|
||||
_sceneryArchive1.seek((uint32) screenIndex * sizeof(sceneBlock_t), SEEK_SET);
|
||||
|
||||
sceneBlock_t sceneBlock; // Read a database header entry
|
||||
sceneBlock.scene_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.scene_len = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.b_off = _sceneryArchive1.readUint32LE();
|
||||
@ -995,16 +940,15 @@ void FileManager_v3d::readBackground(int screenIndex) {
|
||||
sceneBlock.ob_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.ob_len = _sceneryArchive1.readUint32LE();
|
||||
|
||||
seq_t dummySeq; // Image sequence structure for Read_pcx
|
||||
if (screenIndex < 20) {
|
||||
_sceneryArchive1.seek(sceneBlock.scene_off, SEEK_SET);
|
||||
|
||||
// Read the image into dummy seq and static dib_a
|
||||
readPCX(_sceneryArchive1, &seq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
readPCX(_sceneryArchive1, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
} else {
|
||||
_sceneryArchive2.seek(sceneBlock.scene_off, SEEK_SET);
|
||||
|
||||
// Read the image into dummy seq and static dib_a
|
||||
readPCX(_sceneryArchive2, &seq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
readPCX(_sceneryArchive2, &dummySeq, _vm.screen().getFrontBuffer(), true, _vm._screenNames[screenIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1032,17 +976,12 @@ void FileManager_v3d::closeDatabaseFiles() {
|
||||
|
||||
void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayType) {
|
||||
// Open and read in an overlay file, close file
|
||||
uint32 i = 0;
|
||||
int16 j, k;
|
||||
int8 data; // Must be 8 bits signed
|
||||
image_pt tmpImage = image; // temp ptr to overlay file
|
||||
sceneBlock_t sceneBlock; // Database header entry
|
||||
Common::File sceneryArchive;
|
||||
|
||||
debugC(1, kDebugFile, "readOverlay(%d, ...)", screenNum);
|
||||
|
||||
image_pt tmpImage = image; // temp ptr to overlay file
|
||||
_sceneryArchive1.seek((uint32)screenNum * sizeof(sceneBlock_t), SEEK_SET);
|
||||
|
||||
sceneBlock_t sceneBlock; // Database header entry
|
||||
sceneBlock.scene_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.scene_len = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.b_off = _sceneryArchive1.readUint32LE();
|
||||
@ -1052,6 +991,8 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
sceneBlock.ob_off = _sceneryArchive1.readUint32LE();
|
||||
sceneBlock.ob_len = _sceneryArchive1.readUint32LE();
|
||||
|
||||
uint32 i = 0;
|
||||
|
||||
if (screenNum < 20) {
|
||||
switch (overlayType) {
|
||||
case BOUNDARY:
|
||||
@ -1077,16 +1018,16 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
}
|
||||
|
||||
// Read in the overlay file using MAC Packbits. (We're not proud!)
|
||||
k = 0; // byte count
|
||||
int16 k = 0; // byte count
|
||||
do {
|
||||
data = _sceneryArchive1.readByte(); // Read a code byte
|
||||
if ((byte)data == 0x80) // Noop
|
||||
int8 data = _sceneryArchive1.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++ = _sceneryArchive1.readByte();
|
||||
} else { // Repeat next byte -data+1 times
|
||||
j = _sceneryArchive1.readByte();
|
||||
int16 j = _sceneryArchive1.readByte();
|
||||
|
||||
for (i = 0; i < (byte)(-data + 1); i++, k++)
|
||||
*tmpImage++ = j;
|
||||
@ -1117,16 +1058,16 @@ void FileManager_v3d::readOverlay(int screenNum, image_pt image, ovl_t overlayTy
|
||||
}
|
||||
|
||||
// Read in the overlay file using MAC Packbits. (We're not proud!)
|
||||
k = 0; // byte count
|
||||
int16 k = 0; // byte count
|
||||
do {
|
||||
data = _sceneryArchive2.readByte(); // Read a code byte
|
||||
if ((byte)data == 0x80) // Noop
|
||||
int8 data = _sceneryArchive2.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++ = _sceneryArchive2.readByte();
|
||||
} else { // Repeat next byte -data+1 times
|
||||
j = _sceneryArchive2.readByte();
|
||||
} else { // Repeat next byte -data+1 times
|
||||
int16 j = _sceneryArchive2.readByte();
|
||||
|
||||
for (i = 0; i < (byte)(-data + 1); i++, k++)
|
||||
*tmpImage++ = j;
|
||||
|
@ -35,7 +35,23 @@
|
||||
|
||||
// TODO get rid of those defines
|
||||
#define HELPFILE "help.dat"
|
||||
#define EOP '#' /* Marks end of a page in help file */
|
||||
#define EOP '#' // Marks end of a page in help file
|
||||
|
||||
struct PCC_header_t { // 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];
|
||||
}; // Header of a PCC file
|
||||
|
||||
// Record and playback handling stuff:
|
||||
struct pbdata_t {
|
||||
// int key; // Character
|
||||
uint32 time; // Time at which character was pressed
|
||||
};
|
||||
|
||||
namespace Hugo {
|
||||
|
||||
@ -70,9 +86,9 @@ public:
|
||||
protected:
|
||||
HugoEngine &_vm;
|
||||
|
||||
Common::File _stringArchive; /* Handle for string file */
|
||||
Common::File _sceneryArchive1; /* Handle for scenery file */
|
||||
Common::File _objectsArchive; /* Handle for objects file */
|
||||
Common::File _stringArchive; // Handle for string file
|
||||
Common::File _sceneryArchive1; // Handle for scenery file
|
||||
Common::File _objectsArchive; // Handle for objects file
|
||||
|
||||
seq_t *readPCX(Common::File &f, seq_t *seqPtr, byte *imagePtr, bool firstFl, const char *name);
|
||||
private:
|
||||
@ -80,6 +96,9 @@ private:
|
||||
byte *convertPCC(byte *p, uint16 y, uint16 bpl, image_pt data_p);
|
||||
uif_hdr_t *getUIFHeader(uif_t id);
|
||||
|
||||
pbdata_t pbdata;
|
||||
FILE *fpb;
|
||||
|
||||
//Strangerke : Not used?
|
||||
void openPlaybackFile(bool playbackFl, bool recordFl);
|
||||
void printBootText();
|
||||
@ -121,7 +140,7 @@ public:
|
||||
void readBackground(int screenIndex);
|
||||
void readOverlay(int screenNum, image_pt image, ovl_t overlayType);
|
||||
private:
|
||||
Common::File _sceneryArchive2; /* Handle for scenery file */
|
||||
Common::File _sceneryArchive2; // Handle for scenery file
|
||||
};
|
||||
|
||||
class FileManager_v1w : public FileManager_v2d {
|
||||
|
@ -841,7 +841,7 @@ 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 */
|
||||
// Structure of scenery file lookup entry
|
||||
struct sceneBlock_t {
|
||||
uint32 scene_off;
|
||||
uint32 scene_len;
|
||||
@ -853,7 +853,7 @@ struct sceneBlock_t {
|
||||
uint32 ob_len;
|
||||
};
|
||||
|
||||
/* Structure of object file lookup entry */
|
||||
// Structure of object file lookup entry
|
||||
struct objBlock_t {
|
||||
uint32 objOffset;
|
||||
uint32 objLength;
|
||||
|
@ -34,18 +34,19 @@ 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 LEN_MASK 0x3F /* Lower 6 bits are length */
|
||||
#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 LEN_MASK 0x3F // Lower 6 bits are length
|
||||
#define PBFILE "playback.dat"
|
||||
|
||||
/* Name scenery and objects picture databases */
|
||||
// Name scenery and objects picture databases
|
||||
#define OBJECTS_FILE "objects.dat"
|
||||
#define STRING_FILE "strings.dat"
|
||||
#define SOUND_FILE "sounds.dat"
|
||||
|
||||
/* User interface database (Windows Only) */
|
||||
// User interface database (Windows Only)
|
||||
// This file contains, between others, the bitmaps of the fonts used in the application
|
||||
#define UIF_FILE "uif.dat"
|
||||
|
||||
static const int kSavegameVersion = 1;
|
||||
|
@ -44,7 +44,7 @@
|
||||
|
||||
namespace Hugo {
|
||||
|
||||
HugoEngine *HugoEngine::s_Engine = NULL;
|
||||
HugoEngine *HugoEngine::s_Engine = 0;
|
||||
|
||||
overlay_t HugoEngine::_boundary;
|
||||
overlay_t HugoEngine::_overlay;
|
||||
@ -273,7 +273,6 @@ void HugoEngine::runMachine() {
|
||||
static uint32 lastTime;
|
||||
|
||||
status_t &gameStatus = getGameStatus();
|
||||
|
||||
// Don't process if we're in a textbox
|
||||
if (gameStatus.textBoxFl)
|
||||
return;
|
||||
@ -324,10 +323,6 @@ void HugoEngine::runMachine() {
|
||||
|
||||
bool HugoEngine::loadHugoDat() {
|
||||
Common::File in;
|
||||
int numElem, numSubElem, numSubAct;
|
||||
char buf[256];
|
||||
int majVer, minVer;
|
||||
|
||||
in.open("hugo.dat");
|
||||
|
||||
if (!in.isOpen()) {
|
||||
@ -338,6 +333,7 @@ bool HugoEngine::loadHugoDat() {
|
||||
}
|
||||
|
||||
// Read header
|
||||
char buf[256];
|
||||
in.read(buf, 4);
|
||||
buf[4] = '\0';
|
||||
|
||||
@ -348,8 +344,8 @@ bool HugoEngine::loadHugoDat() {
|
||||
return false;
|
||||
}
|
||||
|
||||
majVer = in.readByte();
|
||||
minVer = in.readByte();
|
||||
int majVer = in.readByte();
|
||||
int minVer = in.readByte();
|
||||
|
||||
if ((majVer != HUGO_DAT_VER_MAJ) || (minVer != HUGO_DAT_VER_MIN)) {
|
||||
snprintf(buf, 256, "File 'hugo.dat' is wrong version. Expected %d.%d but got %d.%d. Get it from the ScummVM website", HUGO_DAT_VER_MAJ, HUGO_DAT_VER_MIN, majVer, minVer);
|
||||
@ -380,9 +376,8 @@ bool HugoEngine::loadHugoDat() {
|
||||
// Read palette
|
||||
_paletteSize = in.readUint16BE();
|
||||
_palette = (byte *)malloc(sizeof(byte) * _paletteSize);
|
||||
for (int i = 0; i < _paletteSize; i++) {
|
||||
for (int i = 0; i < _paletteSize; i++)
|
||||
_palette[i] = in.readByte();
|
||||
}
|
||||
|
||||
// Read textEngine
|
||||
_textEngine = loadTexts(in);
|
||||
@ -455,6 +450,7 @@ bool HugoEngine::loadHugoDat() {
|
||||
}
|
||||
}
|
||||
|
||||
int numElem, numSubElem, numSubAct;
|
||||
//Read _invent
|
||||
for (int varnt = 0; varnt < _numVariant; varnt++) {
|
||||
numElem = in.readUint16BE();
|
||||
@ -614,9 +610,9 @@ bool HugoEngine::loadHugoDat() {
|
||||
_screenActs = (uint16 **)malloc(sizeof(uint16 *) * numElem);
|
||||
for (int i = 0; i < numElem; i++) {
|
||||
numSubElem = in.readUint16BE();
|
||||
if (numSubElem == 0)
|
||||
if (numSubElem == 0) {
|
||||
_screenActs[i] = 0;
|
||||
else {
|
||||
} else {
|
||||
_screenActs[i] = (uint16 *)malloc(sizeof(uint16) * numSubElem);
|
||||
for (int j = 0; j < numSubElem; j++)
|
||||
_screenActs[i][j] = in.readUint16BE();
|
||||
@ -1432,25 +1428,23 @@ char **HugoEngine::loadTextsVariante(Common::File &in, uint16 *arraySize) {
|
||||
|
||||
uint16 **HugoEngine::loadLongArray(Common::File &in) {
|
||||
uint16 **resArray = 0;
|
||||
uint16 *resRow = 0;
|
||||
uint16 dummy, numRows, numElems;
|
||||
|
||||
for (int varnt = 0; varnt < _numVariant; varnt++) {
|
||||
numRows = in.readUint16BE();
|
||||
uint16 numRows = in.readUint16BE();
|
||||
if (varnt == _gameVariant) {
|
||||
resArray = (uint16 **)malloc(sizeof(uint16 *) * (numRows + 1));
|
||||
resArray[numRows] = 0;
|
||||
}
|
||||
for (int i = 0; i < numRows; i++) {
|
||||
numElems = in.readUint16BE();
|
||||
uint16 numElems = in.readUint16BE();
|
||||
if (varnt == _gameVariant) {
|
||||
resRow = (uint16 *)malloc(sizeof(uint16) * numElems);
|
||||
uint16 *resRow = (uint16 *)malloc(sizeof(uint16) * numElems);
|
||||
for (int j = 0; j < numElems; j++)
|
||||
resRow[j] = in.readUint16BE();
|
||||
resArray[i] = resRow;
|
||||
} else {
|
||||
for (int j = 0; j < numElems; j++)
|
||||
dummy = in.readUint16BE();
|
||||
in.readUint16BE();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1458,24 +1452,19 @@ uint16 **HugoEngine::loadLongArray(Common::File &in) {
|
||||
}
|
||||
|
||||
char ***HugoEngine::loadTextsArray(Common::File &in) {
|
||||
int numNouns;
|
||||
int numTexts;
|
||||
int entryLen;
|
||||
int len;
|
||||
char ***resArray = 0;
|
||||
char **res = 0;
|
||||
char *pos = 0;
|
||||
|
||||
for (int varnt = 0; varnt < _numVariant; varnt++) {
|
||||
numNouns = in.readUint16BE();
|
||||
int numNouns = in.readUint16BE();
|
||||
if (varnt == _gameVariant) {
|
||||
resArray = (char ** *)malloc(sizeof(char **) * (numNouns + 1));
|
||||
resArray[numNouns] = 0;
|
||||
}
|
||||
for (int i = 0; i < numNouns; i++) {
|
||||
numTexts = in.readUint16BE();
|
||||
entryLen = in.readUint16BE();
|
||||
pos = (char *)malloc(entryLen);
|
||||
int numTexts = in.readUint16BE();
|
||||
int entryLen = in.readUint16BE();
|
||||
char *pos = (char *)malloc(entryLen);
|
||||
char **res = 0;
|
||||
if (varnt == _gameVariant) {
|
||||
res = (char **)malloc(sizeof(char *) * numTexts);
|
||||
res[0] = pos;
|
||||
@ -1492,7 +1481,7 @@ char ***HugoEngine::loadTextsArray(Common::File &in) {
|
||||
res[j] = pos;
|
||||
|
||||
pos -= 2;
|
||||
len = READ_BE_UINT16(pos);
|
||||
int len = READ_BE_UINT16(pos);
|
||||
pos += 2 + len;
|
||||
}
|
||||
|
||||
@ -1507,12 +1496,8 @@ char ***HugoEngine::loadTextsArray(Common::File &in) {
|
||||
char **HugoEngine::loadTexts(Common::File &in) {
|
||||
int numTexts = in.readUint16BE();
|
||||
char **res = (char **)malloc(sizeof(char *) * numTexts);
|
||||
int entryLen;
|
||||
char *pos = 0;
|
||||
int len;
|
||||
|
||||
entryLen = in.readUint16BE();
|
||||
pos = (char *)malloc(entryLen);
|
||||
int entryLen = in.readUint16BE();
|
||||
char *pos = (char *)malloc(entryLen);
|
||||
|
||||
in.read(pos, entryLen);
|
||||
|
||||
@ -1521,7 +1506,7 @@ char **HugoEngine::loadTexts(Common::File &in) {
|
||||
|
||||
for (int i = 1; i < numTexts; i++) {
|
||||
pos -= 2;
|
||||
len = READ_BE_UINT16(pos);
|
||||
int len = READ_BE_UINT16(pos);
|
||||
pos += 2 + len;
|
||||
res[i] = pos;
|
||||
}
|
||||
|
@ -157,7 +157,7 @@ public:
|
||||
|
||||
// Temporary, until the engine is fully objectified.
|
||||
static HugoEngine &get() {
|
||||
assert(s_Engine != NULL);
|
||||
assert(s_Engine != 0);
|
||||
return *s_Engine;
|
||||
}
|
||||
|
||||
|
@ -149,8 +149,8 @@ void intro_v1d::introInit() {
|
||||
}
|
||||
|
||||
bool intro_v1d::introPlay() {
|
||||
byte introSize = _vm.getIntroSize();
|
||||
static int state = 0;
|
||||
byte introSize = _vm.getIntroSize();
|
||||
|
||||
if (introTicks < introSize) {
|
||||
switch (state++) {
|
||||
|
@ -54,8 +54,6 @@ InventoryHandler::InventoryHandler(HugoEngine &vm) : _vm(vm) {
|
||||
// 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
|
||||
@ -77,11 +75,11 @@ void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, b
|
||||
// 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;
|
||||
int16 ux = (i + NUM_ARROWS) * INV_DX % XPIX;
|
||||
int16 uy = (i + NUM_ARROWS) * INV_DX / XPIX * INV_DY;
|
||||
|
||||
// Compute dest coordinates in dib_i
|
||||
ix = ((scrollFl) ? displayed + 1 : displayed) * INV_DX;
|
||||
int16 ix = ((scrollFl) ? displayed + 1 : displayed) * INV_DX;
|
||||
displayed++; // Count number displayed
|
||||
|
||||
// Copy the icon
|
||||
@ -95,24 +93,23 @@ void InventoryHandler::constructInventory(int16 imageTotNumb, int displayNumb, b
|
||||
// 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, ...)");
|
||||
|
||||
static int16 firstIconId = 0; // Index of first icon to display
|
||||
|
||||
int16 imageNumb; // Total number of inventory items
|
||||
int displayNumb; // Total number displayed/carried
|
||||
// Compute total number and number displayed, i.e. number carried
|
||||
for (imageNumb = 0, displayNumb = 0; imageNumb < _vm._maxInvent && _vm._invent[imageNumb] != -1; imageNumb++)
|
||||
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;
|
||||
bool scrollFl = displayNumb > MAX_DISP;
|
||||
va_list marker; // Args used for D_ADD operation
|
||||
int16 cursorx, cursory; // Current cursor position
|
||||
int16 objId = -1; // Return objid under cursor
|
||||
|
||||
switch (action) {
|
||||
case INV_INIT: // Initialize inventory display
|
||||
@ -135,11 +132,11 @@ int16 InventoryHandler::processInventory(invact_t action, ...) {
|
||||
|
||||
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
|
||||
int16 i = cursorx / INV_DX; // Compute icon index
|
||||
if (scrollFl) { // Scroll buttons displayed
|
||||
if (i == 0) { // Left scroll button
|
||||
objId = LEFT_ARROW;
|
||||
else {
|
||||
} else {
|
||||
if (i == MAX_DISP - 1) // Right scroll button
|
||||
objId = RIGHT_ARROW;
|
||||
else // Adjust for scroll
|
||||
@ -148,12 +145,16 @@ int16 InventoryHandler::processInventory(invact_t action, ...) {
|
||||
}
|
||||
|
||||
// If not an arrow, find object id - limit to valid range
|
||||
if (objId == -1 && i < displayNumb)
|
||||
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)
|
||||
int16 j;
|
||||
for (j = 0, i++; i > 0 && j < _vm._numObj; j++) {
|
||||
if (_vm._objects[j].carriedFl) {
|
||||
if (--i == 0)
|
||||
objId = j;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
@ -64,7 +64,6 @@ 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);
|
||||
|
||||
_vm.screen().loadFont(fontId);
|
||||
@ -80,28 +79,23 @@ void MouseHandler::cursorText(char *buffer, int16 cx, int16 cy, uif_t fontId, in
|
||||
_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)
|
||||
int i = 0;
|
||||
for (hotspot_t *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);
|
||||
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();
|
||||
@ -109,21 +103,23 @@ void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) {
|
||||
if (gameStatus.storyModeFl || _vm._hero->pathType == QUIET) // Make sure user has control
|
||||
return;
|
||||
|
||||
bool foundFl = false; // TRUE if route found to object
|
||||
// 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
|
||||
gameStatus.inventoryObjId = -1; // Same icon - deselect it
|
||||
else
|
||||
_vm.useObject(objId); // Use status.objid on object
|
||||
_vm.useObject(objId); // Use status.objid on object
|
||||
} else { // Clicked over viewport object
|
||||
obj = &_vm._objects[objId];
|
||||
object_t *obj = &_vm._objects[objId];
|
||||
int16 x, y;
|
||||
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
|
||||
if (!foundFl) // Can't get there, try to use from here
|
||||
_vm.useObject(objId);
|
||||
break;
|
||||
case 0: // Immediate use
|
||||
@ -131,7 +127,7 @@ void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) {
|
||||
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
|
||||
if (_vm._hero->cycling == INVISIBLE)// If invisible do
|
||||
_vm.useObject(objId); // immediate use
|
||||
else
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there
|
||||
@ -148,11 +144,10 @@ void MouseHandler::processRightClick(int16 objId, int16 cx, int16 cy) {
|
||||
// 4. Nothing - attempt to walk there
|
||||
// 5. Exit - walk to exit hotspot
|
||||
void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
|
||||
debugC(1, kDebugMouse, "Process_lclick(%d, %d, %d)", objId, cx, 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();
|
||||
|
||||
@ -202,11 +197,12 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
|
||||
if (gameStatus.inventoryState == I_ACTIVE && cy < INV_DY + DIBOFF_Y)
|
||||
_vm.lookObject(obj);
|
||||
else {
|
||||
bool foundFl = false; // TRUE if route found to object
|
||||
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
|
||||
if (!foundFl) // Can't get there, immediate description
|
||||
_vm.lookObject(obj);
|
||||
break;
|
||||
case 0: // Immediate description
|
||||
@ -215,7 +211,7 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
|
||||
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
|
||||
_vm.lookObject(obj); // immediate decription
|
||||
else
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textMouse[kMsNoWayText]); // Can't get there
|
||||
}
|
||||
@ -228,12 +224,6 @@ void MouseHandler::processLeftClick(int16 objId, int16 cx, int16 cy) {
|
||||
|
||||
// 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();
|
||||
@ -241,7 +231,7 @@ void MouseHandler::mouseHandler() {
|
||||
|
||||
status_t &gameStatus = _vm.getGameStatus();
|
||||
|
||||
gameStatus.cx = cx; // Save cursor coords
|
||||
gameStatus.cx = cx; // Save cursor coords
|
||||
gameStatus.cy = cy;
|
||||
|
||||
// Don't process if outside client area
|
||||
@ -251,17 +241,19 @@ void MouseHandler::mouseHandler() {
|
||||
// Display dragged inventory icon if one currently selected
|
||||
if (gameStatus.inventoryObjId != -1) {
|
||||
// Find index of icon
|
||||
for (iconId = 0; iconId < _vm._maxInvent; iconId++)
|
||||
int16 iconId; // Find index of dragged 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;
|
||||
int16 ux = (iconId + NUM_ARROWS) * INV_DX % XPIX;
|
||||
int16 uy = (iconId + NUM_ARROWS) * INV_DX / XPIX * INV_DY;
|
||||
|
||||
// Compute destination coordinates in dib_a
|
||||
iconx = cx + IX_OFF;
|
||||
icony = cy + IY_OFF;
|
||||
int iconx = cx + IX_OFF;
|
||||
int icony = cy + IY_OFF;
|
||||
iconx = MAX(iconx, 0); // Keep within dib_a bounds
|
||||
iconx = MIN(iconx, XPIX - INV_DX);
|
||||
icony = MAX(icony, 0);
|
||||
@ -272,6 +264,7 @@ void MouseHandler::mouseHandler() {
|
||||
_vm.screen().displayList(D_ADD, iconx, icony, INV_DX, INV_DY);
|
||||
}
|
||||
|
||||
int16 objId = -1; // Current source object
|
||||
// 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);
|
||||
@ -280,7 +273,7 @@ void MouseHandler::mouseHandler() {
|
||||
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];
|
||||
char *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);
|
||||
|
||||
|
@ -57,11 +57,11 @@ Parser::Parser(HugoEngine &vm) :
|
||||
}
|
||||
|
||||
void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
|
||||
debugC(1, kDebugParser, "keyHandler(%d, %d)", nChar, 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
|
||||
@ -126,21 +126,17 @@ void Parser::keyHandler(uint16 nChar, uint16 nFlags) {
|
||||
// Add any new chars to line buffer and display them.
|
||||
// If CR pressed, pass line to Line_handler()
|
||||
void Parser::charHandler() {
|
||||
debugC(4, kDebugParser, "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
|
||||
|
||||
debugC(4, kDebugParser, "charHandler");
|
||||
|
||||
// Check for one or more characters in ring buffer
|
||||
while (_getIndex != _putIndex) {
|
||||
c = _ringBuffer[_getIndex++];
|
||||
char c = _ringBuffer[_getIndex++];
|
||||
if (_getIndex >= sizeof(_ringBuffer))
|
||||
_getIndex = 0;
|
||||
|
||||
@ -172,11 +168,8 @@ void Parser::charHandler() {
|
||||
}
|
||||
|
||||
// See if time to blink cursor, set cursor character
|
||||
if ((tick++ % (TPS / BLINKS)) == 0) {
|
||||
// Strangerke : Useless ?
|
||||
// updateFl = true; // Force an update
|
||||
if ((tick++ % (TPS / BLINKS)) == 0)
|
||||
cursor = (cursor == '_') ? ' ' : '_';
|
||||
}
|
||||
|
||||
// See if recall button pressed
|
||||
if (gameStatus.recallFl) {
|
||||
@ -211,15 +204,10 @@ void Parser::command(const char *format, ...) {
|
||||
|
||||
// Parse the user's line of text input. Generate events as necessary
|
||||
void Parser::lineHandler() {
|
||||
char *noun, *verb; // ptrs to noun and verb strings
|
||||
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");
|
||||
|
||||
status_t &gameStatus = _vm.getGameStatus();
|
||||
|
||||
// Toggle God Mode
|
||||
if (!strncmp(_line, "PPG", 3)) {
|
||||
_vm.sound().playSound(!_vm._soundTest, BOTH_CHANNELS, HIGH_PRI);
|
||||
@ -236,36 +224,42 @@ void Parser::lineHandler() {
|
||||
// find <object name> Takes hero to screen containing named object
|
||||
if (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 (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++)
|
||||
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++)
|
||||
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 (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
|
||||
@ -300,21 +294,26 @@ void Parser::lineHandler() {
|
||||
return;
|
||||
}
|
||||
|
||||
char farComment[XBYTES * 5] = ""; // hold 5 line comment if object not nearby
|
||||
|
||||
// Test for nearby objects referenced explicitly
|
||||
for (int i = 0; i < _vm._numObj; i++) {
|
||||
obj = &_vm._objects[i];
|
||||
if (isWordPresent(_vm._arrayNouns[obj->nounIndex]))
|
||||
object_t *obj = &_vm._objects[i];
|
||||
if (isWordPresent(_vm._arrayNouns[obj->nounIndex])) {
|
||||
if (isObjectVerb(obj, farComment) || isGenericVerb(obj, 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)
|
||||
object_t *obj = &_vm._objects[i];
|
||||
if (obj->verbOnlyFl) {
|
||||
char contextComment[XBYTES * 5] = ""; // Unused comment for context objects
|
||||
if (isObjectVerb(obj, contextComment) || isGenericVerb(obj, contextComment))
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// No objects match command line, try background and catchall commands
|
||||
@ -334,19 +333,20 @@ void Parser::lineHandler() {
|
||||
}
|
||||
|
||||
// Nothing matches. Report recognition success to user.
|
||||
verb = findVerb();
|
||||
noun = findNoun();
|
||||
char *verb = findVerb();
|
||||
char *noun = findNoun();
|
||||
if (verb == _vm._arrayVerbs[_vm._look][0] && _maze.enabledFl) {
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBMaze]);
|
||||
showTakeables();
|
||||
} else if (verb && noun) // A combination I didn't think of
|
||||
} else if (verb && noun) { // A combination I didn't think of
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoPoint]);
|
||||
else if (noun)
|
||||
} else if (noun) {
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNoun]);
|
||||
else if (verb)
|
||||
} else if (verb) {
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBVerb]);
|
||||
else
|
||||
} else {
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBEh]);
|
||||
}
|
||||
}
|
||||
|
||||
// Search for matching verb/noun pairs in background command list
|
||||
@ -354,15 +354,16 @@ void Parser::lineHandler() {
|
||||
bool Parser::isBackgroundWord(objectList_t obj) {
|
||||
debugC(1, kDebugParser, "isBackgroundWord(object_list_t obj)");
|
||||
|
||||
for (int i = 0; obj[i].verbIndex != 0; i++)
|
||||
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]))) {
|
||||
isWordPresent(_vm._arrayNouns[obj[i].nounIndex]) &&
|
||||
((obj[i].roomState == DONT_CARE) ||
|
||||
(obj[i].roomState == _vm._screenStates[*_vm._screen_p]))) {
|
||||
Utils::Box(BOX_ANY, "%s", _vm.file().fetchString(obj[i].commentIndex));
|
||||
_vm.scheduler().processBonus(obj[i].bonusIndex);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -373,7 +374,7 @@ bool Parser::isBackgroundWord(objectList_t obj) {
|
||||
bool Parser::isCatchallVerb(objectList_t obj) {
|
||||
debugC(1, kDebugParser, "isCatchallVerb(object_list_t obj)");
|
||||
|
||||
for (int i = 0; obj[i].verbIndex != 0; i++)
|
||||
for (int i = 0; obj[i].verbIndex != 0; i++) {
|
||||
if (isWordPresent(_vm._arrayVerbs[obj[i].verbIndex]) && obj[i].nounIndex == 0 &&
|
||||
(!obj[i].matchFl || !findNoun()) &&
|
||||
((obj[i].roomState == DONT_CARE) ||
|
||||
@ -385,8 +386,9 @@ bool Parser::isCatchallVerb(objectList_t obj) {
|
||||
if (*(_vm._arrayVerbs[obj[i].verbIndex]) == _vm._arrayVerbs[_vm._look][0])
|
||||
showTakeables();
|
||||
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -398,7 +400,7 @@ 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);
|
||||
return true;
|
||||
|
||||
if (obj->screenIndex != *_vm._screen_p) {
|
||||
// Not in same screen
|
||||
@ -406,41 +408,42 @@ bool Parser::isNear(object_t *obj, char *verb, char *comment) {
|
||||
strcpy(comment, _vm._textParser[kCmtAny1]);
|
||||
else
|
||||
strcpy(comment, _vm._textParser[kCmtAny2]);
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (obj->cycling == INVISIBLE) {
|
||||
if (obj->seqNumb) {
|
||||
// There is an image
|
||||
strcpy(comment, _vm._textParser[kCmtAny3]);
|
||||
return(false);
|
||||
} else
|
||||
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 {
|
||||
(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);
|
||||
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 {
|
||||
(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 false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -449,12 +452,12 @@ bool Parser::isNear(object_t *obj, char *verb, char *comment) {
|
||||
bool Parser::isWordPresent(char **wordArr) {
|
||||
debugC(1, kDebugParser, "isWordPresent(%s)", wordArr[0]);
|
||||
|
||||
if (wordArr != NULL) {
|
||||
for (int i = 0; strlen(wordArr[i]); i++)
|
||||
if (wordArr != 0) {
|
||||
for (int i = 0; strlen(wordArr[i]); i++) {
|
||||
if (strstr(_line, wordArr[i]))
|
||||
return(true);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -462,36 +465,37 @@ bool Parser::isWordPresent(char **wordArr) {
|
||||
char *Parser::findNoun() {
|
||||
debugC(1, kDebugParser, "findNoun()");
|
||||
|
||||
for (int i = 0; _vm._arrayNouns[i]; i++)
|
||||
for (int j = 0; strlen(_vm._arrayNouns[i][j]); j++)
|
||||
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;
|
||||
return _vm._arrayNouns[i][0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Locate word in list of verbs and return ptr to first string in verb list
|
||||
char *Parser::findVerb() {
|
||||
debugC(1, kDebugParser, "findVerb()");
|
||||
|
||||
for (int i = 0; _vm._arrayVerbs[i]; i++)
|
||||
for (int j = 0; strlen(_vm._arrayVerbs[i][j]); j++)
|
||||
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;
|
||||
return _vm._arrayVerbs[i][0];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// 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];
|
||||
object_t *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, "You can also see:\n%s.", _vm._arrayNouns[obj->nounIndex][LOOK_NAME]);
|
||||
}
|
||||
}
|
||||
@ -545,13 +549,14 @@ bool Parser::isGenericVerb(object_t *obj, char *comment) {
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textData[obj->stateDataIndex[obj->state]]);
|
||||
warning("isGenericVerb: use of state dependant look - To be validated");
|
||||
} else {
|
||||
if ((LOOK & obj->genericCmd) == LOOK)
|
||||
if ((LOOK & obj->genericCmd) == LOOK) {
|
||||
if (_vm._textData[obj->dataIndex])
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textData[obj->dataIndex]);
|
||||
else
|
||||
return(false);
|
||||
else
|
||||
return false;
|
||||
} else {
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBUnusual]);
|
||||
}
|
||||
}
|
||||
} else if (isWordPresent(_vm._arrayVerbs[_vm._take]) && isNear(obj, _vm._arrayVerbs[_vm._take][0], comment)) {
|
||||
if (obj->carriedFl)
|
||||
@ -573,8 +578,9 @@ bool Parser::isGenericVerb(object_t *obj, char *comment) {
|
||||
Utils::Box(BOX_ANY, "%s", _vm._textParser[kTBNeed]);
|
||||
else
|
||||
return false;
|
||||
} else // It was not a generic cmd
|
||||
} else { // It was not a generic cmd
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@ -583,9 +589,10 @@ bool Parser::isGenericVerb(object_t *obj, char *comment) {
|
||||
bool Parser::isCarrying(uint16 wordIndex) {
|
||||
debugC(1, kDebugParser, "isCarrying(%d)", wordIndex);
|
||||
|
||||
for (int i = 0; i < _vm._numObj; i++)
|
||||
for (int i = 0; i < _vm._numObj; i++) {
|
||||
if ((wordIndex == _vm._objects[i].nounIndex) && _vm._objects[i].carriedFl)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -593,39 +600,37 @@ bool Parser::isCarrying(uint16 wordIndex) {
|
||||
// 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 *comment) {
|
||||
int i;
|
||||
cmd *cmnd;
|
||||
char *verb;
|
||||
uint16 *reqs;
|
||||
uint16 cmdIndex;
|
||||
|
||||
debugC(1, kDebugParser, "isObjectVerb(object_t *obj, %s)", comment);
|
||||
|
||||
// First, find matching verb in cmd list
|
||||
cmdIndex = obj->cmdIndex; // ptr to list of commands
|
||||
uint16 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
|
||||
int i;
|
||||
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];
|
||||
char *verb = *_vm._arrayVerbs[_vm._cmdList[cmdIndex][i].verbIndex];
|
||||
if (!isNear(obj, verb, comment))
|
||||
return(false);
|
||||
return false;
|
||||
|
||||
// Check all required objects are being carried
|
||||
cmnd = &_vm._cmdList[cmdIndex][i]; // ptr to struct cmd
|
||||
cmd *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
|
||||
uint16 *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, "%s", _vm._textData[cmnd->textDataNoCarryIndex]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Required objects are present, now check state is correct
|
||||
@ -649,27 +654,27 @@ bool Parser::isObjectVerb(object_t *obj, char *comment) {
|
||||
void Parser::showDosInventory() {
|
||||
// Show user all objects being carried in a variable width 2 column format
|
||||
static const char *blanks = " ";
|
||||
uint16 index, len, len1 = 0, len2 = 0;
|
||||
char buffer[XBYTES *NUM_ROWS] = "\0";
|
||||
uint16 index = 0, len1 = 0, len2 = 0;
|
||||
|
||||
index = 0;
|
||||
for (int i = 0; i < _vm._numObj; i++) /* Find widths of 2 columns */
|
||||
for (int i = 0; i < _vm._numObj; i++) { // Find widths of 2 columns
|
||||
if (_vm._objects[i].carriedFl) {
|
||||
len = strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]);
|
||||
if (index++ & 1) /* Right hand column */
|
||||
uint16 len = strlen(_vm._arrayNouns[_vm._objects[i].nounIndex][1]);
|
||||
if (index++ & 1) // Right hand column
|
||||
len2 = (len > len2) ? len : len2;
|
||||
else
|
||||
len1 = (len > len1) ? len : len1;
|
||||
}
|
||||
len1 += 1; /* For gap between columns */
|
||||
}
|
||||
len1 += 1; // For gap between columns
|
||||
|
||||
if (len1 + len2 < (uint16)strlen(_vm._textParser[kTBOutro]))
|
||||
len1 = strlen(_vm._textParser[kTBOutro]);
|
||||
|
||||
char buffer[XBYTES *NUM_ROWS] = "\0";
|
||||
strncat(buffer, blanks, (len1 + len2 - strlen(_vm._textParser[kTBIntro])) / 2);
|
||||
strcat(strcat(buffer, _vm._textParser[kTBIntro]), "\n");
|
||||
index = 0;
|
||||
for (int i = 0; i < _vm._numObj; i++) { /* Assign strings */
|
||||
for (int i = 0; i < _vm._numObj; i++) { // Assign strings
|
||||
if (_vm._objects[i].carriedFl) {
|
||||
if (index++ & 1)
|
||||
strcat(strcat(buffer, _vm._arrayNouns[_vm._objects[i].nounIndex][1]), "\n");
|
||||
|
@ -45,10 +45,10 @@ 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);
|
||||
|
||||
object_t *obj = _vm._hero; // Pointer to hero object
|
||||
|
||||
// Set first image in sequence
|
||||
switch (keyCode) {
|
||||
case Common::KEYCODE_UP:
|
||||
@ -81,11 +81,11 @@ void Route::setDirection(uint16 keyCode) {
|
||||
// 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);
|
||||
|
||||
static uint16 oldDirection = 0; // Last direction char
|
||||
object_t *obj = _vm._hero; // Pointer to hero object
|
||||
|
||||
if (_vm.getGameStatus().storyModeFl || obj->pathType != USER) // Make sure user has control
|
||||
return;
|
||||
|
||||
@ -148,13 +148,12 @@ void Route::setWalk(uint16 direction) {
|
||||
// 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
|
||||
debugC(1, kDebugRoute, "segment(%d, %d)", x, y);
|
||||
|
||||
// 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;
|
||||
@ -162,16 +161,21 @@ void Route::segment(int16 x, int16 y) {
|
||||
|
||||
// Find and fill on either side of point
|
||||
p = _boundaryMap[y];
|
||||
for (x1 = x; x1 > 0; x1--)
|
||||
int16 x1, x2; // Range of segment
|
||||
for (x1 = x; x1 > 0; x1--) {
|
||||
if (p[x1] == 0) {
|
||||
p[x1] = kMapFill;
|
||||
} else
|
||||
} else {
|
||||
break;
|
||||
for (x2 = x + 1; x2 < XPIX; x2++)
|
||||
}
|
||||
}
|
||||
for (x2 = x + 1; x2 < XPIX; x2++) {
|
||||
if (p[x2] == 0) {
|
||||
p[x2] = kMapFill;
|
||||
} else
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
x1++;
|
||||
x2--;
|
||||
|
||||
@ -190,48 +194,59 @@ void Route::segment(int16 x, int16 y) {
|
||||
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++)
|
||||
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++)
|
||||
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--)
|
||||
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--)
|
||||
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++)
|
||||
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++)
|
||||
}
|
||||
|
||||
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++)
|
||||
}
|
||||
|
||||
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++)
|
||||
}
|
||||
|
||||
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)
|
||||
if (_segmentNumb >= kMaxSeg - 1) {
|
||||
_fullSegmentFl = true;
|
||||
else {
|
||||
} else {
|
||||
// Create segment
|
||||
seg_p = &_segment[_segmentNumb];
|
||||
seg_p->y = y;
|
||||
@ -243,15 +258,15 @@ void Route::segment(int16 x, int16 y) {
|
||||
}
|
||||
|
||||
// Create and return ptr to new node. Initialize with previous node.
|
||||
// Returns NULL if MAX_NODES exceeded
|
||||
// Returns 0 if MAX_NODES exceeded
|
||||
Point *Route::newNode() {
|
||||
debugC(1, kDebugRoute, "newNode");
|
||||
|
||||
if (_routeListIndex >= kMaxNodes) // Too many nodes
|
||||
return(NULL); // Incomplete route - failure
|
||||
return 0; // Incomplete route - failure
|
||||
_routeListIndex++;
|
||||
_route[_routeListIndex] = _route[_routeListIndex - 1]; // Initialize with previous node
|
||||
return(&_route[_routeListIndex]);
|
||||
return &_route[_routeListIndex];
|
||||
}
|
||||
|
||||
// Construct route to cx, cy. Return TRUE if successful.
|
||||
@ -259,13 +274,6 @@ Point *Route::newNode() {
|
||||
// 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
|
||||
@ -276,32 +284,39 @@ bool Route::findRoute(int16 cx, int16 cy) {
|
||||
_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
|
||||
|
||||
int16 herox1 = _vm._hero->x + _vm._hero->currImagePtr->x1; // Hero baseline
|
||||
int16 herox2 = _vm._hero->x + _vm._hero->currImagePtr->x2; // Hero baseline
|
||||
int16 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++)
|
||||
object_t *obj; // Ptr to object
|
||||
int i;
|
||||
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 (int16 y = 0; y < YPIX; y++) {
|
||||
for (int16 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++)
|
||||
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);
|
||||
|
||||
}
|
||||
|
||||
// Search from hero to destination
|
||||
segment(herox1, heroy);
|
||||
|
||||
// Not found or not enough stack or MAX_SEG exceeded
|
||||
if (!_routeFoundFl || _fullStackFl || _fullSegmentFl) {
|
||||
return(false);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Now find the route of nodes from destination back to hero
|
||||
@ -315,29 +330,30 @@ bool Route::findRoute(int16 cx, int16 cy) {
|
||||
_segment[_segmentNumb].x2 = herox2;
|
||||
_segmentNumb++;
|
||||
|
||||
Point *routeNode; // Ptr to route node
|
||||
// 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
|
||||
if ((routeNode = newNode()) == 0) // 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];
|
||||
for (int16 j = i + 1; j < _segmentNumb; j++) {
|
||||
segment_t *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)
|
||||
if (seg_p->x1 <= routeNode->x && seg_p->x2 >= routeNode->x + _heroWidth - 1) {
|
||||
routeNode->y = seg_p->y; // Yes, keep updating node
|
||||
else {
|
||||
} else {
|
||||
// No, create another node on previous segment to reach it
|
||||
if ((routeNode = newNode()) == NULL) // Add new route node
|
||||
return (false); // Too many nodes
|
||||
if ((routeNode = newNode()) == 0) // 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);
|
||||
int16 x1 = MAX(_segment[j - 1].x1, seg_p->x1);
|
||||
int16 x2 = MIN(_segment[j - 1].x2, seg_p->x2);
|
||||
|
||||
// If room, add a little offset to reduce staircase effect
|
||||
dx = HERO_MAX_WIDTH >> 1;
|
||||
int16 dx = HERO_MAX_WIDTH >> 1;
|
||||
if (x2 - x1 < _heroWidth + dx)
|
||||
dx = 0;
|
||||
|
||||
@ -364,18 +380,15 @@ bool Route::findRoute(int16 cx, int16 cy) {
|
||||
|
||||
// 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");
|
||||
|
||||
static bool turnedFl = false; // Used to get extra cylce for turning
|
||||
|
||||
// Current hero position
|
||||
herox = _vm._hero->x + _vm._hero->currImagePtr->x1;
|
||||
heroy = _vm._hero->y + _vm._hero->currImagePtr->y2;
|
||||
routeNode = &_route[gameStatus.routeIndex];
|
||||
int16 herox = _vm._hero->x + _vm._hero->currImagePtr->x1;
|
||||
int16 heroy = _vm._hero->y + _vm._hero->currImagePtr->y2;
|
||||
status_t &gameStatus = _vm.getGameStatus();
|
||||
Point *routeNode = &_route[gameStatus.routeIndex];
|
||||
|
||||
// Arrived at node?
|
||||
if (abs(herox - routeNode->x) < DX + 1 && abs(heroy - routeNode->y) < DY) {
|
||||
@ -422,11 +435,11 @@ void Route::processRoute() {
|
||||
// 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)
|
||||
if (herox < routeNode->x) {
|
||||
setWalk(Common::KEYCODE_RIGHT);
|
||||
else if (herox > routeNode->x)
|
||||
} else if (herox > routeNode->x) {
|
||||
setWalk(Common::KEYCODE_LEFT);
|
||||
else if (heroy < routeNode->y) {
|
||||
} 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) {
|
||||
@ -440,16 +453,13 @@ void Route::processRoute() {
|
||||
// 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;
|
||||
|
||||
status_t &gameStatus = _vm.getGameStatus();
|
||||
// if inventory showing, make it go away
|
||||
if (gameStatus.inventoryState != I_OFF)
|
||||
gameStatus.inventoryState = I_UP;
|
||||
@ -461,6 +471,7 @@ bool Route::startRoute(go_t go_for, int16 id, int16 cx, int16 cy) {
|
||||
if (gameStatus.go_for == GO_SPACE)
|
||||
cx -= HERO_MIN_WIDTH / 2;
|
||||
|
||||
bool foundFl = false; // TRUE if route found ok
|
||||
if ((foundFl = findRoute(cx, cy))) { // Found a route?
|
||||
gameStatus.routeIndex = _routeListIndex; // Node index
|
||||
_vm._hero->vx = _vm._hero->vy = 0; // Stop manual motion
|
||||
|
@ -76,11 +76,10 @@ void Scheduler::initEventQueue() {
|
||||
// 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, "%s", "getQueue");
|
||||
resEvent = _freeEvent;
|
||||
event_t *resEvent = _freeEvent;
|
||||
_freeEvent = _freeEvent->nextEvent;
|
||||
resEvent->nextEvent = 0;
|
||||
return resEvent;
|
||||
@ -94,10 +93,11 @@ event_t *Scheduler::getQueue() {
|
||||
// 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
|
||||
debugC(4, kDebugSchedule, "delQueue()");
|
||||
|
||||
if (curEvent == _headEvent) { // If p was the head ptr
|
||||
_headEvent = curEvent->nextEvent; // then make new head_p
|
||||
else { // Unlink p
|
||||
} else { // Unlink p
|
||||
curEvent->prevEvent->nextEvent = curEvent->nextEvent;
|
||||
if (curEvent->nextEvent)
|
||||
curEvent->nextEvent->prevEvent = curEvent->prevEvent;
|
||||
@ -119,7 +119,7 @@ void Scheduler::delQueue(event_t *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);
|
||||
debugC(1, kDebugSchedule, "insertAction() - Action type A%d", action->a0.actType);
|
||||
|
||||
// First, get and initialise the event structure
|
||||
event_t *curEvent = getQueue();
|
||||
@ -138,7 +138,7 @@ void Scheduler::insertAction(act *action) {
|
||||
// Now find the place to insert the event
|
||||
if (!_tailEvent) { // Empty queue
|
||||
_tailEvent = _headEvent = curEvent;
|
||||
curEvent->nextEvent = curEvent->prevEvent = NULL;
|
||||
curEvent->nextEvent = curEvent->prevEvent = 0;
|
||||
} else {
|
||||
event_t *wrkEvent = _tailEvent; // Search from latest time back
|
||||
bool found = false;
|
||||
@ -160,7 +160,7 @@ void Scheduler::insertAction(act *action) {
|
||||
if (!found) { // Must be earliest in list
|
||||
_headEvent->prevEvent = curEvent; // So insert as new head
|
||||
curEvent->nextEvent = _headEvent;
|
||||
curEvent->prevEvent = NULL;
|
||||
curEvent->prevEvent = 0;
|
||||
_headEvent = curEvent;
|
||||
}
|
||||
}
|
||||
@ -170,16 +170,17 @@ 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])
|
||||
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);
|
||||
|
||||
const char *cypher = getCypher();
|
||||
static const char *cypher = getCypher();
|
||||
|
||||
for (uint16 i = 0; i < strlen(line); i++)
|
||||
line[i] -= cypher[i % strlen(cypher)];
|
||||
@ -190,18 +191,16 @@ 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
|
||||
debugC(1, kDebugSchedule, "doAction - Event action type : %d", curEvent->action->a0.actType);
|
||||
|
||||
status_t &gameStatus = _vm.getGameStatus();
|
||||
act *action = curEvent->action;
|
||||
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);
|
||||
event_t *wrkEvent; // Save ev_p->next_p for return
|
||||
event_t *saveEvent; // Used in DEL_EVENTS
|
||||
|
||||
switch (action->a0.actType) {
|
||||
case ANULL: // Big NOP from DEL_EVENTS
|
||||
@ -217,7 +216,7 @@ event_t *Scheduler::doAction(event_t *curEvent) {
|
||||
_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
|
||||
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, "%s", _vm.file().fetchString(action->a3.promptIndex));
|
||||
|
||||
@ -243,6 +242,7 @@ event_t *Scheduler::doAction(event_t *curEvent) {
|
||||
//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
|
||||
_vm.screen().setBackgroundColor(action->a4.newBackgroundColor);
|
||||
break;
|
||||
@ -443,7 +443,7 @@ event_t *Scheduler::doAction(event_t *curEvent) {
|
||||
break;
|
||||
case YESNO: // act43: Prompt user for Yes or No
|
||||
warning("doAction(act43) - Yes/No Box");
|
||||
if (Utils::Box(BOX_YESNO, "%s", _vm.file().fetchString(action->a43.promptIndex)) != NULL)
|
||||
if (Utils::Box(BOX_YESNO, "%s", _vm.file().fetchString(action->a43.promptIndex)) != 0)
|
||||
insertActionList(action->a43.actYesIndex);
|
||||
else
|
||||
insertActionList(action->a43.actNoIndex);
|
||||
@ -486,12 +486,12 @@ event_t *Scheduler::doAction(event_t *curEvent) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (action->a0.actType == NEW_SCREEN) // New_screen() deletes entire list
|
||||
return (NULL); // next_p = NULL since list now empty
|
||||
else {
|
||||
if (action->a0.actType == NEW_SCREEN) { // New_screen() deletes entire list
|
||||
return 0; // next_p = 0 since list now empty
|
||||
} else {
|
||||
wrkEvent = curEvent->nextEvent;
|
||||
delQueue(curEvent); // Return event to free list
|
||||
return(wrkEvent); // Return next event ptr
|
||||
return wrkEvent; // Return next event ptr
|
||||
}
|
||||
}
|
||||
|
||||
@ -502,8 +502,8 @@ 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()
|
||||
@ -573,45 +573,39 @@ void Scheduler::newScreen(int screenIndex) {
|
||||
// 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()");
|
||||
|
||||
debugC(1, kDebugSchedule, "saveEvents");
|
||||
|
||||
curTime = getTicks();
|
||||
uint32 curTime = getTicks();
|
||||
event_t saveEventArr[kMaxEvents]; // Convert event ptrs to indexes
|
||||
|
||||
// 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);
|
||||
event_t *wrkEvent = &_events[i];
|
||||
saveEventArr[i] = *wrkEvent;
|
||||
saveEventArr[i].prevEvent = (wrkEvent->prevEvent == 0) ? (event_t *) - 1 : (event_t *)(wrkEvent->prevEvent - _events);
|
||||
saveEventArr[i].nextEvent = (wrkEvent->nextEvent == 0) ? (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;
|
||||
|
||||
int16 freeIndex = (_freeEvent == 0) ? -1 : _freeEvent - _events;
|
||||
int16 headIndex = (_headEvent == 0) ? -1 : _headEvent - _events;
|
||||
int16 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_));
|
||||
f->write(saveEventArr, sizeof(saveEventArr));
|
||||
}
|
||||
|
||||
// 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
|
||||
debugC(1, kDebugSchedule, "restoreEvents");
|
||||
|
||||
uint32 saveTime;
|
||||
int16 freeIndex; // Free list index
|
||||
int16 headIndex; // Head of list index
|
||||
int16 tailIndex; // Tail of list index
|
||||
|
||||
debugC(1, kDebugSchedule, "restoreEvents");
|
||||
event_t savedEvents[kMaxEvents]; // Convert event ptrs to indexes
|
||||
|
||||
f->read(&saveTime, sizeof(saveTime)); // time of save
|
||||
f->read(&freeIndex, sizeof(freeIndex));
|
||||
@ -619,6 +613,7 @@ void Scheduler::restoreEvents(Common::SeekableReadStream *f) {
|
||||
f->read(&tailIndex, sizeof(tailIndex));
|
||||
f->read(savedEvents, sizeof(savedEvents));
|
||||
|
||||
event_t *wrkEvent;
|
||||
// Restore events indexes to pointers
|
||||
for (int i = 0; i < kMaxEvents; i++) {
|
||||
wrkEvent = &savedEvents[i];
|
||||
@ -626,12 +621,12 @@ void Scheduler::restoreEvents(Common::SeekableReadStream *f) {
|
||||
_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];
|
||||
_freeEvent = (freeIndex == -1) ? 0 : &_events[freeIndex];
|
||||
_headEvent = (headIndex == -1) ? 0 : &_events[headIndex];
|
||||
_tailEvent = (tailIndex == -1) ? 0 : &_events[tailIndex];
|
||||
|
||||
// Adjust times to fit our time
|
||||
curTime = getTicks();
|
||||
uint32 curTime = getTicks();
|
||||
wrkEvent = _headEvent; // The earliest event
|
||||
while (wrkEvent) { // While mature events found
|
||||
wrkEvent->time = wrkEvent->time - saveTime + curTime;
|
||||
@ -661,12 +656,13 @@ 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];
|
||||
int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES;
|
||||
|
||||
debugC(1, kDebugSchedule, "swapImages(%d, %d)", objNumb1, objNumb2);
|
||||
|
||||
_vm.file().saveSeq(&_vm._objects[objNumb1]);
|
||||
|
||||
seqList_t tmpSeqList[MAX_SEQUENCES];
|
||||
int seqListSize = sizeof(seqList_t) * MAX_SEQUENCES;
|
||||
|
||||
memcpy(tmpSeqList, _vm._objects[objNumb1].seqList, seqListSize);
|
||||
memcpy(_vm._objects[objNumb1].seqList, _vm._objects[objNumb2].seqList, seqListSize);
|
||||
memcpy(_vm._objects[objNumb2].seqList, tmpSeqList, seqListSize);
|
||||
|
@ -35,14 +35,14 @@
|
||||
|
||||
namespace Hugo {
|
||||
|
||||
#define kMaxEvents 50 /* Max events in event queue */
|
||||
#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 */
|
||||
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 {
|
||||
@ -71,11 +71,11 @@ private:
|
||||
|
||||
HugoEngine &_vm;
|
||||
|
||||
event_t _events[kMaxEvents]; /* Statically declare event structures */
|
||||
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 *_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);
|
||||
|
@ -184,11 +184,11 @@ int MidiPlayer::open() {
|
||||
void MidiPlayer::close() {
|
||||
stop();
|
||||
_mutex.lock();
|
||||
_driver->setTimerCallback(NULL, NULL);
|
||||
_driver->setTimerCallback(0, 0);
|
||||
_driver->close();
|
||||
delete _driver;
|
||||
_driver = 0;
|
||||
_parser->setMidiDriver(NULL);
|
||||
_parser->setMidiDriver(0);
|
||||
delete _parser;
|
||||
_mutex.unlock();
|
||||
}
|
||||
@ -314,7 +314,7 @@ void SoundHandler::playSound(int16 sound, stereo_t channel, byte priority) {
|
||||
curPriority = priority;
|
||||
//
|
||||
/* Get sound data */
|
||||
if ((sound_p = _vm.file().getSound(sound, &size)) == NULL)
|
||||
if ((sound_p = _vm.file().getSound(sound, &size)) == 0)
|
||||
return;
|
||||
|
||||
Audio::AudioStream *stream = Audio::makeRawStream(sound_p, size, 11025, Audio::FLAG_UNSIGNED);
|
||||
|
@ -41,67 +41,68 @@
|
||||
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;
|
||||
|
||||
// Returns index (0 to 7) of first 1 in supplied byte, or 8 if not found
|
||||
if (!data)
|
||||
return(8);
|
||||
return 8;
|
||||
|
||||
int i;
|
||||
for (i = 0; i < 8; i++) {
|
||||
if ((data << i) & 0x80)
|
||||
break;
|
||||
}
|
||||
|
||||
return(i);
|
||||
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;
|
||||
// Returns index (0 to 7) of last 1 in supplied byte, or 8 if not found
|
||||
if (!data)
|
||||
return(8);
|
||||
return 8;
|
||||
|
||||
int i;
|
||||
for (i = 7; i >= 0; i--) {
|
||||
if ((data << i) & 0x80)
|
||||
break;
|
||||
}
|
||||
|
||||
return(i);
|
||||
return i;
|
||||
}
|
||||
|
||||
void Utils::reverseByte(byte *data) {
|
||||
/* Reverse the bit order in supplied byte */
|
||||
// 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)
|
||||
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)
|
||||
return 0; // NULL strings catered for
|
||||
|
||||
if (s[0] == '\0')
|
||||
return(NULL);
|
||||
return 0;
|
||||
|
||||
if (strlen(s) > MAX_STRLEN - 100) { // Test length
|
||||
Warn(false, "String too big:\n%s", s);
|
||||
return(NULL);
|
||||
Warn("String too big:\n%s", s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
va_list marker;
|
||||
va_start(marker, s);
|
||||
vsprintf(buffer, s, marker); // Format string into buffer
|
||||
va_end(marker);
|
||||
|
||||
if (buffer[0] == '\0')
|
||||
return(NULL);
|
||||
return 0;
|
||||
|
||||
switch(dismiss) {
|
||||
case BOX_ANY:
|
||||
@ -113,7 +114,7 @@ char *Utils::Box(box_t dismiss, const char *s, ...) {
|
||||
case BOX_YESNO: {
|
||||
GUI::MessageDialog dialog(buffer, "YES", "NO");
|
||||
if (dialog.runModal() == GUI::kMessageOK)
|
||||
return(buffer);
|
||||
return buffer;
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
@ -128,27 +129,20 @@ char *Utils::Box(box_t dismiss, const char *s, ...) {
|
||||
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 */
|
||||
void Utils::Warn(const char *format, ...) {
|
||||
// Warning handler. Print supplied message and continue
|
||||
// Arguments are same as printf
|
||||
char buffer[WARNLEN];
|
||||
va_list marker;
|
||||
|
||||
va_start(marker, format);
|
||||
vsnprintf(buffer, WARNLEN, format, marker);
|
||||
va_end(marker);
|
||||
//// if (technote)
|
||||
//// strcat (buffer, sTech);
|
||||
//MessageBeep(MB_ICONEXCLAMATION);
|
||||
//MessageBox(hwnd, buffer, "HugoWin Warning", MB_OK | MB_ICONEXCLAMATION);
|
||||
warning("Hugo warning: %s", buffer);
|
||||
}
|
||||
|
||||
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;
|
||||
// Fatal error handler. Reset environment, print error and exit
|
||||
// Arguments are same as printf
|
||||
char buffer[ERRLEN + 1];
|
||||
bool fatal = true; // Fatal error, else continue
|
||||
|
||||
@ -177,6 +171,7 @@ void Utils::Error(int error_type, const char *format, ...) {
|
||||
if (fatal)
|
||||
HugoEngine::get().shutdown(); // Restore any devices before exit
|
||||
|
||||
va_list marker;
|
||||
va_start(marker, format);
|
||||
vsnprintf(&buffer[strlen(buffer)], ERRLEN - strlen(buffer), format, marker);
|
||||
va_end(marker);
|
||||
|
@ -55,7 +55,7 @@ int lastBit(byte data);
|
||||
void gameOverMsg();
|
||||
void reverseByte(byte *data);
|
||||
void Error(int code, const char *format, ...) GCC_PRINTF(2, 3);
|
||||
void Warn(bool technote, const char *format, ...) GCC_PRINTF(2, 3);
|
||||
void Warn(const char *format, ...) GCC_PRINTF(1, 2);
|
||||
|
||||
char *Box(box_t, const char *, ...) GCC_PRINTF(2, 3);
|
||||
char *strlwr(char *buffer);
|
||||
|
Loading…
x
Reference in New Issue
Block a user