Initial commit.
This commit is contained in:
commit
c4e3fb7939
27 changed files with 9733 additions and 0 deletions
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*.sta filter=lfs diff=lfs merge=lfs -text
|
||||||
|
*.z5 filter=lfs diff=lfs merge=lfs -text
|
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
*~
|
||||||
|
*.user
|
BIN
8x8thin.sta
Normal file
BIN
8x8thin.sta
Normal file
Binary file not shown.
535
ansiterm.c
Normal file
535
ansiterm.c
Normal file
|
@ -0,0 +1,535 @@
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "joey.h"
|
||||||
|
#ifdef JOEY_IIGS
|
||||||
|
segment "ansiterm";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "ansiterm.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} Vector2T;
|
||||||
|
|
||||||
|
|
||||||
|
static int _columns = 40;
|
||||||
|
static int _rows = 25;
|
||||||
|
static int _xoff = 0;
|
||||||
|
static int _yoff = 0;
|
||||||
|
static bool _escFound = false;
|
||||||
|
static bool _inEscape = false;
|
||||||
|
static bool _bold = false;
|
||||||
|
static bool _blink = false;
|
||||||
|
static bool _reverse = false;
|
||||||
|
static int _foreground = 7;
|
||||||
|
static int _background = 0;
|
||||||
|
static int _fColor = 7;
|
||||||
|
static int _bColor = 0;
|
||||||
|
static int _number = 0;
|
||||||
|
static int _parameters[5];
|
||||||
|
static int _parameterCount = 0;
|
||||||
|
static Vector2T _cursorSave;
|
||||||
|
static Vector2T _cursor;
|
||||||
|
static jlStaT *_ansiFont = NULL;
|
||||||
|
static int *_screenBuffer = NULL;
|
||||||
|
|
||||||
|
|
||||||
|
void termDebug(const char *what, ...);
|
||||||
|
bool termParseANSI(char c);
|
||||||
|
void termRenderCharacterAtCursor(char c);
|
||||||
|
void termRepaint(void);
|
||||||
|
void termResetSequence(void);
|
||||||
|
void termScrollUp(void);
|
||||||
|
void termUpdateColors(void);
|
||||||
|
|
||||||
|
|
||||||
|
void termClearScreen(void) {
|
||||||
|
memset(_screenBuffer, 0, (size_t)(2 * _columns * _rows));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
__attribute__((__format__ (__printf__, 1, 0)))
|
||||||
|
void termDebug(const char *what, ...) {
|
||||||
|
char msg[1024];
|
||||||
|
va_list va;
|
||||||
|
|
||||||
|
va_start(va, what);
|
||||||
|
vsprintf(msg, what, va);
|
||||||
|
va_end(va);
|
||||||
|
|
||||||
|
printf("%s\n", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termGetCursor(int *x, int *y) {
|
||||||
|
*x = _cursor.x;
|
||||||
|
*y = _cursor.y;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termMoveCursor(int x, int y) {
|
||||||
|
if (x < 1) {
|
||||||
|
_cursor.x = 1;
|
||||||
|
termDebug("Attempt to position cursor too far left: %d", x);
|
||||||
|
} else {
|
||||||
|
if (x > _columns) {
|
||||||
|
_cursor.x = _columns;
|
||||||
|
termDebug("Attempt to position cursor too far right: %d", x);
|
||||||
|
} else {
|
||||||
|
_cursor.x = x;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (y < 1) {
|
||||||
|
_cursor.y = 1;
|
||||||
|
termDebug("Attempt to position cursor too far up: %d", y);
|
||||||
|
} else {
|
||||||
|
if (y > _rows) {
|
||||||
|
_cursor.y = _rows;
|
||||||
|
termDebug("Attempt to position cursor too far down: %d", y);
|
||||||
|
} else {
|
||||||
|
_cursor.y = y;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool termParseANSI(char c) {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
int oldX;
|
||||||
|
int cx;
|
||||||
|
int p;
|
||||||
|
bool updateDisplay = false;
|
||||||
|
Vector2T cursor = _cursor;
|
||||||
|
|
||||||
|
// Find leading ESC character.
|
||||||
|
if ((c == (char)27) && !_escFound && !_inEscape) {
|
||||||
|
_escFound = true;
|
||||||
|
return updateDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find [ character.
|
||||||
|
if ((c == '[') && _escFound && !_inEscape) {
|
||||||
|
_inEscape = true;
|
||||||
|
return updateDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We don't do non-'ESC[' sequences.
|
||||||
|
if (_escFound && !_inEscape) {
|
||||||
|
termDebug("Unexpected Character: %d", (int)c);
|
||||||
|
termResetSequence();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_inEscape) {
|
||||||
|
switch (c) {
|
||||||
|
// All we know is that a Xenomorph may be involved.
|
||||||
|
case '[':
|
||||||
|
case (char)27:
|
||||||
|
termDebug("BUG! Escape found inside sequence.");
|
||||||
|
break;
|
||||||
|
// End of a parameter.
|
||||||
|
case ';':
|
||||||
|
_parameters[_parameterCount++] = _number;
|
||||||
|
_number = 0;
|
||||||
|
break;
|
||||||
|
// Cursor up.
|
||||||
|
case 'A':
|
||||||
|
y = _number;
|
||||||
|
termDebug("Moving cursor up %d", y);
|
||||||
|
termMoveCursor(cursor.x, cursor.y - y);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor down.
|
||||||
|
case 'B':
|
||||||
|
y = _number;
|
||||||
|
termDebug("Moving cursor down %d", y);
|
||||||
|
termMoveCursor(cursor.x, cursor.y + y);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor forward.
|
||||||
|
case 'C':
|
||||||
|
x = _number;
|
||||||
|
termDebug("Moving cursor right %d", x);
|
||||||
|
termMoveCursor(cursor.x + x, cursor.y);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor backward.
|
||||||
|
case 'D':
|
||||||
|
x = _number;
|
||||||
|
termDebug("Moving cursor left %d", x);
|
||||||
|
termMoveCursor(cursor.x - x, cursor.y);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor line down.
|
||||||
|
case 'E':
|
||||||
|
y = _number;
|
||||||
|
termDebug("Moving cursor down line %d", y);
|
||||||
|
termMoveCursor(1, cursor.y + y);
|
||||||
|
//***TODO*** This should allow scrolling
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor line up.
|
||||||
|
case 'F':
|
||||||
|
y = _number;
|
||||||
|
termDebug("Moving cursor up line %d", y);
|
||||||
|
termMoveCursor(1, cursor.y - y);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor horizontal absolute.
|
||||||
|
case 'G':
|
||||||
|
x = _number;
|
||||||
|
termDebug("Moving cursor horizontally to %d", x);
|
||||||
|
termMoveCursor(x, cursor.y);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Move cursor.
|
||||||
|
case 'H':
|
||||||
|
case 'f':
|
||||||
|
switch (_parameterCount) {
|
||||||
|
case 0:
|
||||||
|
// Absolute position, Y. Kinda. Moves X to 1.
|
||||||
|
y = _number;
|
||||||
|
termDebug("Moving cursor to 1x%d", y);
|
||||||
|
termMoveCursor(1, y);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
// Absolute position.
|
||||||
|
x = _number;
|
||||||
|
y = _parameters[0];
|
||||||
|
termDebug("Moving cursor to %dx%d", x, y);
|
||||||
|
termMoveCursor(x, y);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
termDebug("Unknown Cursor Move");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Clear display.
|
||||||
|
case 'J':
|
||||||
|
if ((_parameterCount == 0) && (_number == 2)) {
|
||||||
|
termDebug("Clear display");
|
||||||
|
termClearScreen();
|
||||||
|
updateDisplay = true;
|
||||||
|
termMoveCursor(1, 1);
|
||||||
|
} else {
|
||||||
|
termDebug("Unimplemented Screen Clear");
|
||||||
|
}
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Clear from cursor to end of line.
|
||||||
|
case 'K':
|
||||||
|
x = _number;
|
||||||
|
if (x == 0) {
|
||||||
|
termDebug("Clear to end of line");
|
||||||
|
oldX = cursor.x;
|
||||||
|
for (cx=cursor.x; cx<=_columns; cx++) {
|
||||||
|
termMoveCursor(cx, cursor.y);
|
||||||
|
termRenderCharacterAtCursor(' ');
|
||||||
|
}
|
||||||
|
termMoveCursor(oldX, cursor.y);
|
||||||
|
} else {
|
||||||
|
termDebug("Unimplemented Line Clear");
|
||||||
|
}
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Insert lines.
|
||||||
|
case 'L':
|
||||||
|
//***TODO***
|
||||||
|
termDebug("Unimplemented Insert Line");
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Delete lines.
|
||||||
|
case 'M':
|
||||||
|
//***TODO***
|
||||||
|
termDebug("Unimplemented Delete Line");
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Delete characters.
|
||||||
|
case 'P':
|
||||||
|
//***TODO***
|
||||||
|
termDebug("Unimplemented Delete Character");
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Scroll Up.
|
||||||
|
case 'S':
|
||||||
|
//***TODO***
|
||||||
|
termDebug("Unimplemented Scroll Up");
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Scroll Down.
|
||||||
|
case 'T':
|
||||||
|
//***TODO***
|
||||||
|
termDebug("Unimplemented Scroll Down");
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Clear Screen with Normal Attribute.
|
||||||
|
case 'U':
|
||||||
|
x = _bColor;
|
||||||
|
_bColor = 0;
|
||||||
|
termUpdateColors();
|
||||||
|
termClearScreen();
|
||||||
|
updateDisplay = true;
|
||||||
|
_bColor = x;
|
||||||
|
termUpdateColors();
|
||||||
|
termMoveCursor(1, 1);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Back-TAB.
|
||||||
|
case 'Z':
|
||||||
|
//***TODO***
|
||||||
|
termDebug("Unimplemented Back TAB");
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Set attributes.
|
||||||
|
case 'm':
|
||||||
|
_parameters[_parameterCount++] = _number;
|
||||||
|
for (p=0; p<_parameterCount; p++) {
|
||||||
|
termDebug("Set attribute %d", _parameters[p]);
|
||||||
|
x = _parameters[p];
|
||||||
|
switch (x) {
|
||||||
|
case 0:
|
||||||
|
_bold = false;
|
||||||
|
_blink = false;
|
||||||
|
_reverse = false;
|
||||||
|
_fColor = 7;
|
||||||
|
_bColor = 0;
|
||||||
|
termUpdateColors();
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
_bold = true;
|
||||||
|
termUpdateColors();
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
case 6:
|
||||||
|
_blink = true;
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
if (!_reverse) {
|
||||||
|
x = _fColor;
|
||||||
|
_fColor = _bColor;
|
||||||
|
_bColor = x;
|
||||||
|
termUpdateColors();
|
||||||
|
}
|
||||||
|
_reverse = true;
|
||||||
|
break;
|
||||||
|
case 21:
|
||||||
|
case 22:
|
||||||
|
_bold = false;
|
||||||
|
termUpdateColors();
|
||||||
|
break;
|
||||||
|
case 25:
|
||||||
|
_blink = false;
|
||||||
|
break;
|
||||||
|
case 27:
|
||||||
|
if (_reverse) {
|
||||||
|
x = _fColor;
|
||||||
|
_fColor = _bColor;
|
||||||
|
_bColor = x;
|
||||||
|
termUpdateColors();
|
||||||
|
}
|
||||||
|
_reverse = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if ((x > 29) && (x < 38)) {
|
||||||
|
_fColor = x - 30;
|
||||||
|
termUpdateColors();
|
||||||
|
} else {
|
||||||
|
if ((x > 39) && (x < 48)) {
|
||||||
|
_bColor = x - 40;
|
||||||
|
termUpdateColors();
|
||||||
|
} else {
|
||||||
|
termDebug("Unknown attribute: %d", (int)c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Define scroll region.
|
||||||
|
case 'r':
|
||||||
|
//***TODO***
|
||||||
|
termDebug("Unimplemented Scroll Region");
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor save.
|
||||||
|
case 's':
|
||||||
|
termDebug("Saving cursor");
|
||||||
|
_cursorSave = cursor;
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Cursor restore.
|
||||||
|
case 'u':
|
||||||
|
termDebug("Restoring cursor");
|
||||||
|
termMoveCursor(_cursorSave.x, _cursorSave.y);
|
||||||
|
termResetSequence();
|
||||||
|
break;
|
||||||
|
// Something else.
|
||||||
|
default:
|
||||||
|
// Number?
|
||||||
|
if ((c >= '0') && (c <= '9')) {
|
||||||
|
_number = _number * 10 + (c - '0');
|
||||||
|
} else {
|
||||||
|
termDebug("Unknown sequence: %d", (int)c);
|
||||||
|
termResetSequence();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
switch (c) {
|
||||||
|
case (char)7:
|
||||||
|
// Beep!
|
||||||
|
termDebug("Unimplemented beep");
|
||||||
|
break;
|
||||||
|
case (char)8:
|
||||||
|
case (char)127:
|
||||||
|
//***TODO*** Backspace
|
||||||
|
termDebug("Unimplemented backspace");
|
||||||
|
break;
|
||||||
|
case (char)9:
|
||||||
|
//***TODO*** TAB
|
||||||
|
termDebug("Unimplemented tab");
|
||||||
|
break;
|
||||||
|
case (char)10:
|
||||||
|
cursor.y++;
|
||||||
|
if (cursor.y > _rows) {
|
||||||
|
cursor.y--;
|
||||||
|
termScrollUp();
|
||||||
|
updateDisplay = true;
|
||||||
|
}
|
||||||
|
termMoveCursor(cursor.x, cursor.y);
|
||||||
|
break;
|
||||||
|
case (char)12:
|
||||||
|
x = _bColor;
|
||||||
|
_bColor = 0;
|
||||||
|
termUpdateColors();
|
||||||
|
termClearScreen();
|
||||||
|
updateDisplay = true;
|
||||||
|
_bColor = x;
|
||||||
|
termUpdateColors();
|
||||||
|
termMoveCursor(1, 1);
|
||||||
|
break;
|
||||||
|
case (char)13:
|
||||||
|
termMoveCursor(1, cursor.y);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
updateDisplay = true;
|
||||||
|
termRenderCharacterAtCursor(c);
|
||||||
|
if (_blink) {
|
||||||
|
//***TODO*** Not handled
|
||||||
|
}
|
||||||
|
cursor.x++;
|
||||||
|
if (cursor.x > _columns) {
|
||||||
|
cursor.x = 1;
|
||||||
|
cursor.y++;
|
||||||
|
if (cursor.y > _rows) {
|
||||||
|
cursor.y--;
|
||||||
|
termScrollUp();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
termMoveCursor(cursor.x, cursor.y);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return updateDisplay;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termPrint(char *string) {
|
||||||
|
int x;
|
||||||
|
int l = (int)strlen(string);
|
||||||
|
for (x=0; x<l; x++) {
|
||||||
|
termPrintChar(string[x]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termPrintChar(char c) {
|
||||||
|
if (termParseANSI(c)) {
|
||||||
|
jlDisplayPresent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termRenderCharacterAtCursor(char c) {
|
||||||
|
int r = (_reverse ? 7 : 0);
|
||||||
|
int cx = c % 40;
|
||||||
|
int cy = (c / 40) + r;
|
||||||
|
_screenBuffer[(_cursor.y * _columns) + _cursor.x] = (cy * 40) + cx;
|
||||||
|
jlDrawBlit8x8(_ansiFont, cx, cy, _cursor.x - 1 + _xoff, _cursor.y - 1 + _yoff);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termRepaint(void) {
|
||||||
|
int i = 0;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
for (y=0; y<_rows; y++) {
|
||||||
|
for (x=0; x<_columns; x++) {
|
||||||
|
jlDrawBlit8x8(_ansiFont, _screenBuffer[i] % 40, _screenBuffer[i] / 40, x, y);
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termResetSequence(void) {
|
||||||
|
_number = 0;
|
||||||
|
_inEscape = false;
|
||||||
|
_escFound = false;
|
||||||
|
_parameterCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termRestoreCursor(void) {
|
||||||
|
_cursor = _cursorSave;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termSaveCursor(void) {
|
||||||
|
_cursorSave = _cursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termScrollUp(void) {
|
||||||
|
int x;
|
||||||
|
int i = 0;
|
||||||
|
int j = _columns;
|
||||||
|
for (x=0; x < (_rows - 1) * _columns; x++) {
|
||||||
|
_screenBuffer[i++] = _screenBuffer[j++];
|
||||||
|
}
|
||||||
|
termRepaint();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termStart(jlStaT *font, int xoff, int yoff, int cols, int rows) {
|
||||||
|
_ansiFont = font;
|
||||||
|
_xoff = xoff;
|
||||||
|
_yoff = yoff;
|
||||||
|
_columns = cols;
|
||||||
|
_rows = rows;
|
||||||
|
_cursorSave.x = 1;
|
||||||
|
_cursorSave.y = 1;
|
||||||
|
_cursor.x = 1;
|
||||||
|
_cursor.y = 1;
|
||||||
|
_screenBuffer = (int *)jlMalloc((size_t)(2 * _columns * _rows));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termStop(void) {
|
||||||
|
if (_screenBuffer != NULL) {
|
||||||
|
jlFree(_screenBuffer);
|
||||||
|
_screenBuffer = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void termUpdateColors(void) {
|
||||||
|
_foreground = _fColor + (_bold ? 8 : 0);
|
||||||
|
_background = _bColor;
|
||||||
|
}
|
16
ansiterm.h
Normal file
16
ansiterm.h
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef H_ANSITERM_
|
||||||
|
#define H_ANSITERM_
|
||||||
|
|
||||||
|
#include "joey.h"
|
||||||
|
|
||||||
|
void termClearScreen(void);
|
||||||
|
void termGetCursor(int *x, int *y);
|
||||||
|
void termMoveCursor(int x, int y);
|
||||||
|
void termPrint(char *string);
|
||||||
|
void termPrintChar(char c);
|
||||||
|
void termRestoreCursor(void);
|
||||||
|
void termSaveCursor(void);
|
||||||
|
void termStart(jlStaT *font, int xoff, int yoff, int cols, int rows);
|
||||||
|
void termStop(void);
|
||||||
|
|
||||||
|
#endif // _H_ANSITERM_
|
26
build-IIgs.sh
Executable file
26
build-IIgs.sh
Executable file
|
@ -0,0 +1,26 @@
|
||||||
|
#!/bin/bash -ex
|
||||||
|
|
||||||
|
PROJECT=ifengine
|
||||||
|
|
||||||
|
TARGET=${JOEY}/sdks/iix/IIgs/out/${PROJECT}
|
||||||
|
GSTARGET=31:/out/${PROJECT}
|
||||||
|
|
||||||
|
if [ -d ${TARGET} ]; then
|
||||||
|
rm -rf ${TARGET}
|
||||||
|
fi
|
||||||
|
mkdir -p ${TARGET}
|
||||||
|
|
||||||
|
cp -f ${JOEY}/dist/joey.h .
|
||||||
|
CFILES=($(ls -1 *.c))
|
||||||
|
OFILES=""
|
||||||
|
for F in "${CFILES[@]}"; do
|
||||||
|
O=${F%.*}
|
||||||
|
OFILES="${OFILES} ${GSTARGET}/${O}"
|
||||||
|
echo "Compiling ${F}..."
|
||||||
|
iix compile ${F} keep=${GSTARGET}/${O}
|
||||||
|
done
|
||||||
|
rm joey.h
|
||||||
|
|
||||||
|
cp -f ${JOEY}/dist/IIgs/joeylib#b20000 ${JOEY}/sdks/iix/IIgs/Libraries/joeylib
|
||||||
|
iix chtyp -t lib ${JOEY}/sdks/iix/IIgs/Libraries/joeylib
|
||||||
|
iix -DKeepType=S16 link ${OFILES} 13:joeylib keep=${GSTARGET}/${PROJECT}
|
369
control.c
Normal file
369
control.c
Normal file
|
@ -0,0 +1,369 @@
|
||||||
|
|
||||||
|
/* $Id: control.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: control.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: control.c,v $
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* control.c
|
||||||
|
*
|
||||||
|
* Functions that alter the flow of control.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
static const char *v1_lookup_table[3] = {
|
||||||
|
"abcdefghijklmnopqrstuvwxyz",
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
|
" 0123456789.,!?_#'\"/\\<-:()"
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *v3_lookup_table[3] = {
|
||||||
|
"abcdefghijklmnopqrstuvwxyz",
|
||||||
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
|
||||||
|
" \n0123456789.,!?_#'\"/\\-:()"
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_check_arg_count
|
||||||
|
*
|
||||||
|
* Jump if argument is present.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_check_arg_count( zword_t argc )
|
||||||
|
{
|
||||||
|
|
||||||
|
conditional_jump( argc <= ( zword_t ) ( stack[fp + 1] & ARGS_MASK ) );
|
||||||
|
|
||||||
|
} /* z_check_arg_count */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_call
|
||||||
|
*
|
||||||
|
* Call a subroutine. Save PC and FP then load new PC and initialise stack based
|
||||||
|
* local arguments.
|
||||||
|
*
|
||||||
|
* Implements: call_1s, call_1n, call_2s, call_2n, call, call_vs, call_vs2, call_vn, call_vn2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int z_call( int argc, zword_t * argv, int type )
|
||||||
|
{
|
||||||
|
zword_t arg;
|
||||||
|
int i = 1, args, status = 0;
|
||||||
|
|
||||||
|
/* Convert calls to 0 as returning FALSE */
|
||||||
|
|
||||||
|
if ( argv[0] == 0 )
|
||||||
|
{
|
||||||
|
if ( type == FUNCTION )
|
||||||
|
store_operand( FALSE );
|
||||||
|
return ( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Save current PC, FP and argument count on stack */
|
||||||
|
|
||||||
|
stack[--sp] = ( zword_t ) ( pc / PAGE_SIZE );
|
||||||
|
stack[--sp] = ( zword_t ) ( pc % PAGE_SIZE );
|
||||||
|
stack[--sp] = fp;
|
||||||
|
stack[--sp] = ( argc - 1 ) | type;
|
||||||
|
|
||||||
|
/* Create FP for new subroutine and load new PC */
|
||||||
|
|
||||||
|
fp = sp - 1;
|
||||||
|
pc = ( unsigned long ) argv[0] * story_scaler;
|
||||||
|
#if defined(USE_QUETZAL)
|
||||||
|
++frame_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Read argument count and initialise local variables */
|
||||||
|
|
||||||
|
args = ( unsigned int ) read_code_byte( );
|
||||||
|
#if defined(USE_QUETZAL)
|
||||||
|
stack[sp] |= args << VAR_SHIFT;
|
||||||
|
#endif
|
||||||
|
while ( --args >= 0 )
|
||||||
|
{
|
||||||
|
arg = ( h_type > V4 ) ? 0 : read_code_word( );
|
||||||
|
stack[--sp] = ( --argc > 0 ) ? argv[i++] : arg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the call is asynchronous then call the interpreter directly.
|
||||||
|
* We will return back here when the corresponding return frame is
|
||||||
|
* encountered in the ret call. */
|
||||||
|
|
||||||
|
if ( type == ASYNC )
|
||||||
|
{
|
||||||
|
status = interpret( );
|
||||||
|
interpreter_state = RUN;
|
||||||
|
interpreter_status = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( status );
|
||||||
|
|
||||||
|
} /* z_call */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_ret
|
||||||
|
*
|
||||||
|
* Return from subroutine. Restore FP and PC from stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_ret( zword_t value )
|
||||||
|
{
|
||||||
|
zword_t argc;
|
||||||
|
|
||||||
|
/* Clean stack */
|
||||||
|
|
||||||
|
sp = fp + 1;
|
||||||
|
|
||||||
|
/* Restore argument count, FP and PC */
|
||||||
|
|
||||||
|
argc = stack[sp++];
|
||||||
|
fp = stack[sp++];
|
||||||
|
pc = stack[sp++];
|
||||||
|
pc += ( unsigned long ) stack[sp++] * PAGE_SIZE;
|
||||||
|
#if defined(USE_QUETZAL)
|
||||||
|
--frame_count;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* If this was an async call then stop the interpreter and return
|
||||||
|
* the value from the async routine. This is slightly hacky using
|
||||||
|
* a global state variable, but ret can be called with conditional_jump
|
||||||
|
* which in turn can be called from all over the place, sigh. A
|
||||||
|
* better design would have all opcodes returning the status RUN, but
|
||||||
|
* this is too much work and makes the interpreter loop look ugly */
|
||||||
|
|
||||||
|
if ( ( argc & TYPE_MASK ) == ASYNC )
|
||||||
|
{
|
||||||
|
interpreter_state = STOP;
|
||||||
|
interpreter_status = ( int ) value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Return subroutine value for function call only */
|
||||||
|
if ( ( argc & TYPE_MASK ) == FUNCTION )
|
||||||
|
{
|
||||||
|
store_operand( value );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* z_ret */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_jump
|
||||||
|
*
|
||||||
|
* Unconditional jump. Jump is PC relative.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_jump( zword_t offset )
|
||||||
|
{
|
||||||
|
|
||||||
|
pc = ( unsigned long ) ( pc + ( ZINT16 ) offset - 2 );
|
||||||
|
|
||||||
|
} /* z_jump */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_restart
|
||||||
|
*
|
||||||
|
* Restart game by initialising environment and reloading start PC.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_restart( void )
|
||||||
|
{
|
||||||
|
unsigned int i, j, restart_size, scripting_flag;
|
||||||
|
|
||||||
|
/* Reset output buffer */
|
||||||
|
|
||||||
|
flush_buffer( TRUE );
|
||||||
|
|
||||||
|
/* Reset text control flags */
|
||||||
|
|
||||||
|
formatting = ON;
|
||||||
|
outputting = ON;
|
||||||
|
redirecting = OFF;
|
||||||
|
redirect_depth = 0;
|
||||||
|
scripting_disable = OFF;
|
||||||
|
|
||||||
|
/* Randomise */
|
||||||
|
|
||||||
|
SRANDOM_FUNC( ( unsigned int ) time( NULL ) );
|
||||||
|
|
||||||
|
/* Remember scripting state */
|
||||||
|
|
||||||
|
scripting_flag = get_word( H_FLAGS ) & SCRIPTING_FLAG;
|
||||||
|
|
||||||
|
/* Load restart size and reload writeable data area */
|
||||||
|
|
||||||
|
restart_size = ( h_restart_size / PAGE_SIZE ) + 1;
|
||||||
|
for ( i = 0; i < restart_size; i++ )
|
||||||
|
{
|
||||||
|
read_page( i, &datap[i * PAGE_SIZE] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Restart the screen */
|
||||||
|
|
||||||
|
z_split_window( 0 );
|
||||||
|
set_colours( 1, 1 ); /* set default colors, added by JDH 8/6/95 */
|
||||||
|
set_attribute( NORMAL );
|
||||||
|
z_erase_window( Z_SCREEN );
|
||||||
|
|
||||||
|
restart_screen( );
|
||||||
|
|
||||||
|
/* Reset the interpreter state */
|
||||||
|
|
||||||
|
restart_interp( scripting_flag );
|
||||||
|
|
||||||
|
/* Initialise the character translation lookup tables */
|
||||||
|
|
||||||
|
for ( i = 0; i < 3; i++ )
|
||||||
|
{
|
||||||
|
for ( j = 0; j < 26; j++ )
|
||||||
|
{
|
||||||
|
if ( h_alternate_alphabet_offset )
|
||||||
|
{
|
||||||
|
lookup_table[i][j] = get_byte( h_alternate_alphabet_offset + ( i * 26 ) + j );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( h_type == V1 )
|
||||||
|
{
|
||||||
|
lookup_table[i][j] = v1_lookup_table[i][j];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lookup_table[i][j] = v3_lookup_table[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load start PC, SP and FP */
|
||||||
|
|
||||||
|
pc = h_start_pc;
|
||||||
|
sp = STACK_SIZE;
|
||||||
|
fp = STACK_SIZE - 1;
|
||||||
|
#if defined (USE_QUETZAL)
|
||||||
|
frame_count = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} /* z_restart */
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* restart_interp
|
||||||
|
*
|
||||||
|
* Do all the things which need to be done after startup, restart, and restore
|
||||||
|
* commands.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void restart_interp( int scripting_flag )
|
||||||
|
{
|
||||||
|
if ( scripting_flag )
|
||||||
|
set_word( H_FLAGS, ( get_word( H_FLAGS ) | SCRIPTING_FLAG ) );
|
||||||
|
|
||||||
|
set_byte( H_INTERPRETER, h_interpreter );
|
||||||
|
set_byte( H_INTERPRETER_VERSION, h_interpreter_version );
|
||||||
|
set_byte( H_SCREEN_ROWS, screen_rows ); /* Screen dimension in characters */
|
||||||
|
set_byte( H_SCREEN_COLUMNS, screen_cols );
|
||||||
|
|
||||||
|
set_byte( H_SCREEN_LEFT, 0 ); /* Screen dimension in smallest addressable units, ie. pixels */
|
||||||
|
set_byte( H_SCREEN_RIGHT, screen_cols );
|
||||||
|
set_byte( H_SCREEN_TOP, 0 );
|
||||||
|
set_byte( H_SCREEN_BOTTOM, screen_rows );
|
||||||
|
|
||||||
|
set_byte( H_MAX_CHAR_WIDTH, 1 ); /* Size of a character in screen units */
|
||||||
|
set_byte( H_MAX_CHAR_HEIGHT, 1 );
|
||||||
|
|
||||||
|
/* Initialise status region */
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
{
|
||||||
|
z_split_window( 0 );
|
||||||
|
blank_status_line( );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( h_type == V3 && fTandy )
|
||||||
|
{
|
||||||
|
zbyte_t config_byte = get_byte( H_CONFIG );
|
||||||
|
|
||||||
|
config_byte |= CONFIG_TANDY;
|
||||||
|
set_byte( H_CONFIG, config_byte );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* restart_interp */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_catch
|
||||||
|
*
|
||||||
|
* Return the value of the frame pointer (FP) for later use with throw.
|
||||||
|
* Before V5 games this was a simple pop.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_catch( void )
|
||||||
|
{
|
||||||
|
if ( h_type > V4 )
|
||||||
|
{
|
||||||
|
#if defined (USE_QUETZAL)
|
||||||
|
store_operand( frame_count );
|
||||||
|
#else
|
||||||
|
store_operand( fp );
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sp++;
|
||||||
|
}
|
||||||
|
} /* z_catch */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_throw
|
||||||
|
*
|
||||||
|
* Remove one or more stack frames and return. Works like longjmp, see z_catch.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_throw( zword_t value, zword_t new_fp )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( new_fp > fp )
|
||||||
|
{
|
||||||
|
fatal( "z_throw(): nonexistant frame" );
|
||||||
|
}
|
||||||
|
#if defined (USE_QUETZAL)
|
||||||
|
for ( ; new_fp < frame_count; --frame_count )
|
||||||
|
{
|
||||||
|
sp = fp + 1;
|
||||||
|
fp = stack[sp + 1];
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
fp = new_fp;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
z_ret( value );
|
||||||
|
|
||||||
|
} /* z_throw */
|
147
extern.c
Normal file
147
extern.c
Normal file
|
@ -0,0 +1,147 @@
|
||||||
|
|
||||||
|
/* $Id: extern.c,v 1.2 2000/10/04 23:07:57 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: extern.c,v 1.2 2000/10/04 23:07:57 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: extern.c,v $
|
||||||
|
* Revision 1.2 2000/10/04 23:07:57 jholder
|
||||||
|
* fixed redirect problem with isolatin1 range chars
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* extern.c
|
||||||
|
*
|
||||||
|
* Global data.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
unsigned char JTERP;
|
||||||
|
int GLOBALVER;
|
||||||
|
|
||||||
|
/* Stuff for Latin-1 Charset */
|
||||||
|
unsigned char zscii2latin1[69] = {
|
||||||
|
0xe4, 0xf6, 0xfc, 0xc4, 0xd6, 0xdc, 0xdf, 0xbb,
|
||||||
|
0xab, 0xeb, 0xef, 0xff, 0xcb, 0xcf, 0xe1, 0xe9,
|
||||||
|
0xed, 0xf3, 0xfa, 0xfd, 0xc1, 0xc9, 0xcd, 0xd3,
|
||||||
|
0xda, 0xdd, 0xe0, 0xe8, 0xec, 0xf2, 0xf9, 0xc0,
|
||||||
|
0xc8, 0xcc, 0xd2, 0xd9, 0xe2, 0xea, 0xee, 0xf4,
|
||||||
|
0xfb, 0xc2, 0xca, 0xce, 0xd4, 0xdb, 0xe5, 0xc5,
|
||||||
|
0xf8, 0xd8, 0xe3, 0xf1, 0xf5, 0xc3, 0xd1, 0xd5,
|
||||||
|
0xe6, 0xc6, 0xe7, 0xc7, 0xfe, 0xf0, 0xde, 0xd0,
|
||||||
|
0xa3, 'o', 'O', 0xa1, 0xbf
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Game header data */
|
||||||
|
|
||||||
|
zbyte_t h_type = 0;
|
||||||
|
zbyte_t h_config = 0;
|
||||||
|
zword_t h_version = 0;
|
||||||
|
zword_t h_data_size = 0;
|
||||||
|
zword_t h_start_pc = 0;
|
||||||
|
zword_t h_words_offset = 0;
|
||||||
|
zword_t h_objects_offset = 0;
|
||||||
|
zword_t h_globals_offset = 0;
|
||||||
|
zword_t h_restart_size = 0;
|
||||||
|
zword_t h_flags = 0;
|
||||||
|
zword_t h_synonyms_offset = 0;
|
||||||
|
zword_t h_file_size = 0;
|
||||||
|
zword_t h_checksum = 0;
|
||||||
|
zbyte_t h_interpreter = INTERP_MSDOS;
|
||||||
|
zbyte_t h_interpreter_version = 'B'; /* Interpreter version 2 */
|
||||||
|
zword_t h_alternate_alphabet_offset = 0;
|
||||||
|
zword_t h_unicode_table = 0;
|
||||||
|
|
||||||
|
/* Game version specific data */
|
||||||
|
|
||||||
|
int story_scaler = 0;
|
||||||
|
int story_shift = 0;
|
||||||
|
int property_mask = 0;
|
||||||
|
int property_size_mask = 0;
|
||||||
|
|
||||||
|
/* Stack and PC data */
|
||||||
|
|
||||||
|
zword_t stack[STACK_SIZE];
|
||||||
|
zword_t sp = STACK_SIZE;
|
||||||
|
zword_t fp = STACK_SIZE - 1;
|
||||||
|
zword_t frame_count = 0; /* frame pointer for get_fp */
|
||||||
|
unsigned long pc = 0;
|
||||||
|
int interpreter_state = RUN;
|
||||||
|
int interpreter_status = 0;
|
||||||
|
|
||||||
|
/* Data region data */
|
||||||
|
|
||||||
|
unsigned int data_size = 0;
|
||||||
|
zbyte_t *datap = NULL;
|
||||||
|
zbyte_t *undo_datap = NULL;
|
||||||
|
|
||||||
|
/* Screen size data */
|
||||||
|
|
||||||
|
int screen_rows = 0;
|
||||||
|
int screen_cols = 0;
|
||||||
|
int right_margin = DEFAULT_RIGHT_MARGIN;
|
||||||
|
int top_margin = DEFAULT_TOP_MARGIN;
|
||||||
|
char bigscreen = 0;
|
||||||
|
char monochrome = 0;
|
||||||
|
int hist_buf_size;
|
||||||
|
|
||||||
|
/* Current window data */
|
||||||
|
|
||||||
|
int screen_window = TEXT_WINDOW;
|
||||||
|
int interp_initialized = 0;
|
||||||
|
|
||||||
|
/* Formatting and output control data */
|
||||||
|
|
||||||
|
int gFontNum = 0;
|
||||||
|
int formatting = ON;
|
||||||
|
int outputting = ON;
|
||||||
|
int redirecting = OFF;
|
||||||
|
int redirect_depth = 0; /* 1 or higher means ON */
|
||||||
|
int scripting_disable = OFF;
|
||||||
|
int scripting = OFF;
|
||||||
|
int recording = OFF;
|
||||||
|
int replaying = OFF;
|
||||||
|
int font = 1;
|
||||||
|
int use_bg_color = 1;
|
||||||
|
ZINT16 default_fg = 9, default_bg = 6;
|
||||||
|
|
||||||
|
/* Status region data */
|
||||||
|
|
||||||
|
int status_active = OFF;
|
||||||
|
int status_size = 0;
|
||||||
|
|
||||||
|
/* Tandy bit requested */
|
||||||
|
|
||||||
|
char fTandy = 0;
|
||||||
|
|
||||||
|
/* IBM (not international) glyphs requested */
|
||||||
|
|
||||||
|
char fIBMGraphics = 0;
|
||||||
|
|
||||||
|
/* Text output buffer data */
|
||||||
|
|
||||||
|
int lines_written = 0;
|
||||||
|
int status_pos = 0;
|
||||||
|
|
||||||
|
/* Dynamic buffer data */
|
||||||
|
|
||||||
|
char *line = NULL;
|
||||||
|
char *status_line = NULL;
|
||||||
|
|
||||||
|
/* Character translation tables */
|
||||||
|
|
||||||
|
char lookup_table[3][26];
|
BIN
gamedata.z5
Normal file
BIN
gamedata.z5
Normal file
Binary file not shown.
75
ifengine.pro
Normal file
75
ifengine.pro
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
TEMPLATE = app
|
||||||
|
CONFIG += console
|
||||||
|
CONFIG -= \
|
||||||
|
app_bundle \
|
||||||
|
qt
|
||||||
|
|
||||||
|
DESTDIR = $$OUT_PWD/build
|
||||||
|
|
||||||
|
JOEY = /home/scott/joey
|
||||||
|
|
||||||
|
JOEY_INCLUDES = \
|
||||||
|
$$JOEY/dist
|
||||||
|
|
||||||
|
JOEY_HEADERS = \
|
||||||
|
$$JOEY/dist/joey.h
|
||||||
|
|
||||||
|
JOEY_LIBS = \
|
||||||
|
-L$$JOEY/dist/linux/x64 \
|
||||||
|
-Wl,-rpath,$$JOEY/dist/linux/x64 \
|
||||||
|
-Wl,--enable-new-dtags \
|
||||||
|
-l:joeylib.a \
|
||||||
|
-Wl,--no-undefined \
|
||||||
|
-ldl \
|
||||||
|
-lsndio \
|
||||||
|
-lpthread \
|
||||||
|
-lrt \
|
||||||
|
-lm
|
||||||
|
|
||||||
|
JOEY_FLAGS = \
|
||||||
|
-pthread \
|
||||||
|
-D_REENTRANT
|
||||||
|
|
||||||
|
ZIP_FLAGS = \
|
||||||
|
-DANSI_COLOR \
|
||||||
|
-DUNIX \
|
||||||
|
-DSCREEN_WIDTH=40 \
|
||||||
|
-DSCREEN_HEIGHT=25 \
|
||||||
|
|
||||||
|
QMAKE_CFLAGS += \
|
||||||
|
$$JOEY_FLAGS
|
||||||
|
|
||||||
|
INCLUDEPATH += \
|
||||||
|
$$JOEY_INCLUDES
|
||||||
|
|
||||||
|
HEADERS += \
|
||||||
|
$$JOEY_HEADERS \
|
||||||
|
ansiterm.h \
|
||||||
|
jzip.h \
|
||||||
|
ztypes.h
|
||||||
|
|
||||||
|
SOURCES += \
|
||||||
|
main.c \
|
||||||
|
ansiterm.c \
|
||||||
|
control.c \
|
||||||
|
extern.c \
|
||||||
|
fileio.c \
|
||||||
|
input.c \
|
||||||
|
interpre.c \
|
||||||
|
math.c \
|
||||||
|
memory.c \
|
||||||
|
object.c \
|
||||||
|
operand.c \
|
||||||
|
osdepend.c \
|
||||||
|
property.c \
|
||||||
|
quetzal.c \
|
||||||
|
screen.c \
|
||||||
|
text.c \
|
||||||
|
variable.c \
|
||||||
|
joeyio.c
|
||||||
|
|
||||||
|
LIBS += \
|
||||||
|
$$JOEY_LIBS \
|
||||||
|
|
||||||
|
DISTFILES += \
|
||||||
|
build-IIgs.sh
|
606
input.c
Normal file
606
input.c
Normal file
|
@ -0,0 +1,606 @@
|
||||||
|
|
||||||
|
/* $Id: input.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: input.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: input.c,v $
|
||||||
|
* Revision 1.3 2000/07/05 15:20:34 jholder
|
||||||
|
* Updated code to remove warnings.
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* input.c
|
||||||
|
*
|
||||||
|
* Input routines
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/* Statically defined word separator list */
|
||||||
|
|
||||||
|
static const char *separators = " \t\n\f.,?";
|
||||||
|
static zword_t dictionary_offset = 0;
|
||||||
|
static ZINT16 dictionary_size = 0;
|
||||||
|
static unsigned int entry_size = 0;
|
||||||
|
|
||||||
|
static void tokenise_line( zword_t, zword_t, zword_t, zword_t );
|
||||||
|
static const char *next_token( const char *, const char *, const char **, int *, const char * );
|
||||||
|
static zword_t find_word( int, const char *, long );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_read_char
|
||||||
|
*
|
||||||
|
* Read one character with optional timeout
|
||||||
|
*
|
||||||
|
* argv[0] = input device (must be 1)
|
||||||
|
* argv[1] = timeout value in tenths of a second (optional)
|
||||||
|
* argv[2] = timeout action routine (optional)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_read_char( int argc, zword_t * argv )
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
zword_t arg_list[2];
|
||||||
|
|
||||||
|
/* Supply default parameters */
|
||||||
|
|
||||||
|
if ( argc < 3 )
|
||||||
|
argv[2] = 0;
|
||||||
|
if ( argc < 2 )
|
||||||
|
argv[1] = 0;
|
||||||
|
|
||||||
|
/* Flush any buffered output before read */
|
||||||
|
|
||||||
|
flush_buffer( FALSE );
|
||||||
|
|
||||||
|
/* Reset line count */
|
||||||
|
|
||||||
|
lines_written = 0;
|
||||||
|
|
||||||
|
/* If more than one characters was asked for then fail the call */
|
||||||
|
|
||||||
|
if ( argv[0] != 1 )
|
||||||
|
|
||||||
|
c = 0;
|
||||||
|
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( ( c = playback_key( ) ) == -1 )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Setup the timeout routine argument list */
|
||||||
|
|
||||||
|
arg_list[0] = argv[2];
|
||||||
|
arg_list[1] = 0; /* as per spec 1.0 */
|
||||||
|
/* was: arg_list[1] = argv[1]/10; */
|
||||||
|
|
||||||
|
/* Read a character with a timeout. If the input timed out then
|
||||||
|
* call the timeout action routine. If the return status from the
|
||||||
|
* timeout routine was 0 then try to read a character again */
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
flush_buffer( FALSE );
|
||||||
|
c = input_character( ( int ) argv[1] );
|
||||||
|
}
|
||||||
|
while ( c == -1 && z_call( 1, arg_list, ASYNC ) == 0 );
|
||||||
|
|
||||||
|
/* Fail call if input timed out */
|
||||||
|
|
||||||
|
if ( c == -1 )
|
||||||
|
c = 0;
|
||||||
|
else
|
||||||
|
record_key( c );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
store_operand( (zword_t)c );
|
||||||
|
|
||||||
|
} /* z_read_char */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_sread_aread
|
||||||
|
*
|
||||||
|
* Read a line of input with optional timeout.
|
||||||
|
*
|
||||||
|
* argv[0] = character buffer address
|
||||||
|
* argv[1] = token buffer address
|
||||||
|
* argv[2] = timeout value in seconds (optional)
|
||||||
|
* argv[3] = timeout action routine (optional)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_sread_aread( int argc, zword_t * argv )
|
||||||
|
{
|
||||||
|
int i, in_size, out_size, terminator;
|
||||||
|
char *cbuf, *buffer;
|
||||||
|
|
||||||
|
/* Supply default parameters */
|
||||||
|
|
||||||
|
if ( argc < 4 )
|
||||||
|
argv[3] = 0;
|
||||||
|
if ( argc < 3 )
|
||||||
|
argv[2] = 0;
|
||||||
|
if ( argc < 2 )
|
||||||
|
argv[1] = 0;
|
||||||
|
|
||||||
|
/* Refresh status line */
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
z_show_status( );
|
||||||
|
|
||||||
|
/* Flush any buffered output before read */
|
||||||
|
|
||||||
|
flush_buffer( TRUE );
|
||||||
|
|
||||||
|
/* Reset line count */
|
||||||
|
|
||||||
|
lines_written = 0;
|
||||||
|
|
||||||
|
/* Initialise character pointer and initial read size */
|
||||||
|
|
||||||
|
cbuf = ( char * ) &datap[argv[0]];
|
||||||
|
in_size = ( h_type > V4 ) ? cbuf[1] : 0;
|
||||||
|
|
||||||
|
/* Read the line then script and record it */
|
||||||
|
|
||||||
|
terminator = get_line( cbuf, argv[2], argv[3] );
|
||||||
|
script_line( ( h_type > V4 ) ? &cbuf[2] : &cbuf[1] );
|
||||||
|
record_line( ( h_type > V4 ) ? &cbuf[2] : &cbuf[1] );
|
||||||
|
|
||||||
|
/* Convert new text in line to lowercase */
|
||||||
|
|
||||||
|
if ( h_type > V4 )
|
||||||
|
{
|
||||||
|
buffer = &cbuf[2];
|
||||||
|
out_size = cbuf[1];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer = &cbuf[1];
|
||||||
|
out_size = strlen( buffer );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( out_size > in_size )
|
||||||
|
for ( i = in_size; i < out_size; i++ )
|
||||||
|
buffer[i] = ( char ) tolower( buffer[i] );
|
||||||
|
|
||||||
|
/* Tokenise the line, if a token buffer is present */
|
||||||
|
|
||||||
|
if ( argv[1] )
|
||||||
|
tokenise_line( argv[0], argv[1], h_words_offset, 0 );
|
||||||
|
|
||||||
|
/* Return the line terminator */
|
||||||
|
|
||||||
|
if ( h_type > V4 )
|
||||||
|
store_operand( ( zword_t ) terminator );
|
||||||
|
|
||||||
|
} /* z_sread_aread */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_line
|
||||||
|
*
|
||||||
|
* Read a line of input and lower case it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int get_line( char *cbuf, zword_t timeout, zword_t action_routine )
|
||||||
|
{
|
||||||
|
char *buffer;
|
||||||
|
int buflen, read_size, status, c;
|
||||||
|
zword_t arg_list[2];
|
||||||
|
|
||||||
|
/* Set maximum buffer size to width of screen minus any
|
||||||
|
* right margin and 1 character for a terminating NULL */
|
||||||
|
|
||||||
|
buflen = ( screen_cols > 127 ) ? 127 : screen_cols;
|
||||||
|
buflen -= right_margin + 1;
|
||||||
|
if ( ( int ) cbuf[0] <= buflen )
|
||||||
|
buflen = cbuf[0];
|
||||||
|
|
||||||
|
/* Set read size and start of read buffer. The buffer may already be
|
||||||
|
* primed with some text in V5 games. The Z-code will have already
|
||||||
|
* displayed the text so we don't have to do that */
|
||||||
|
|
||||||
|
if ( h_type > V4 )
|
||||||
|
{
|
||||||
|
read_size = cbuf[1];
|
||||||
|
buffer = &cbuf[2];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
read_size = 0;
|
||||||
|
buffer = &cbuf[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Try to read input from command file */
|
||||||
|
|
||||||
|
c = playback_line( buflen, buffer, &read_size );
|
||||||
|
|
||||||
|
if ( c == -1 )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Setup the timeout routine argument list */
|
||||||
|
|
||||||
|
arg_list[0] = action_routine;
|
||||||
|
arg_list[1] = 0; /* as per spec.1.0 */
|
||||||
|
/* arg_list[1] = timeout/10; */
|
||||||
|
|
||||||
|
/* Read a line with a timeout. If the input timed out then
|
||||||
|
* call the timeout action routine. If the return status from the
|
||||||
|
* timeout routine was 0 then try to read the line again */
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
c = input_line( buflen, buffer, timeout, &read_size );
|
||||||
|
status = 0;
|
||||||
|
}
|
||||||
|
while ( c == -1 && ( status = z_call( 1, arg_list, ASYNC ) ) == 0 );
|
||||||
|
|
||||||
|
/* Throw away any input if timeout returns success */
|
||||||
|
|
||||||
|
if ( status )
|
||||||
|
read_size = 0;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Zero terminate line */
|
||||||
|
|
||||||
|
if ( h_type > V4 )
|
||||||
|
{
|
||||||
|
cbuf[1] = ( char ) read_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Zero terminate line (V1-4 only) */
|
||||||
|
buffer[read_size] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( c );
|
||||||
|
|
||||||
|
} /* get_line */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* tokenise_line
|
||||||
|
*
|
||||||
|
* Convert a typed input line into tokens. The token buffer needs some
|
||||||
|
* additional explanation. The first byte is the maximum number of tokens
|
||||||
|
* allowed. The second byte is set to the actual number of token read. Each
|
||||||
|
* token is composed of 3 fields. The first (word) field contains the word
|
||||||
|
* offset in the dictionary, the second (byte) field contains the token length,
|
||||||
|
* and the third (byte) field contains the start offset of the token in the
|
||||||
|
* character buffer.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void tokenise_line( zword_t char_buf, zword_t token_buf, zword_t dictionary, zword_t flag )
|
||||||
|
{
|
||||||
|
int i, count, words, token_length;
|
||||||
|
long word_index, chop = 0;
|
||||||
|
int slen;
|
||||||
|
char *str_end;
|
||||||
|
char *cbuf, *tbuf, *tp;
|
||||||
|
const char *cp, *token;
|
||||||
|
char punctuation[16];
|
||||||
|
zword_t word;
|
||||||
|
|
||||||
|
/* Initialise character and token buffer pointers */
|
||||||
|
|
||||||
|
cbuf = ( char * ) &datap[char_buf];
|
||||||
|
tbuf = ( char * ) &datap[token_buf];
|
||||||
|
|
||||||
|
/* Find the string length */
|
||||||
|
|
||||||
|
if ( h_type > V4 )
|
||||||
|
{
|
||||||
|
slen = ( unsigned char ) ( cbuf[1] );
|
||||||
|
str_end = cbuf + 2 + slen;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
slen = strlen( cbuf + 1 );
|
||||||
|
str_end = cbuf + 1 + slen;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Initialise word count and pointers */
|
||||||
|
|
||||||
|
words = 0;
|
||||||
|
cp = ( h_type > V4 ) ? cbuf + 2 : cbuf + 1;
|
||||||
|
tp = tbuf + 2;
|
||||||
|
|
||||||
|
/* Initialise dictionary */
|
||||||
|
|
||||||
|
count = get_byte( dictionary++ );
|
||||||
|
for ( i = 0; i < count; i++ )
|
||||||
|
punctuation[i] = get_byte( dictionary++ );
|
||||||
|
punctuation[i] = '\0';
|
||||||
|
entry_size = get_byte( dictionary++ );
|
||||||
|
dictionary_size = ( ZINT16 ) get_word( dictionary );
|
||||||
|
dictionary_offset = dictionary + 2;
|
||||||
|
|
||||||
|
/* Calculate the binary chop start position */
|
||||||
|
|
||||||
|
if ( dictionary_size > 0 )
|
||||||
|
{
|
||||||
|
word_index = dictionary_size / 2;
|
||||||
|
chop = 1;
|
||||||
|
do
|
||||||
|
chop *= 2;
|
||||||
|
while ( word_index /= 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tokenise the line */
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Skip to next token */
|
||||||
|
|
||||||
|
cp = next_token( cp, str_end, &token, &token_length, punctuation );
|
||||||
|
if ( token_length )
|
||||||
|
|
||||||
|
/* If still space in token buffer then store word */
|
||||||
|
|
||||||
|
if ( words <= tbuf[0] )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Get the word offset from the dictionary */
|
||||||
|
|
||||||
|
word = find_word( token_length, token, chop );
|
||||||
|
|
||||||
|
/* Store the dictionary offset, token length and offset */
|
||||||
|
|
||||||
|
if ( word || flag == 0 )
|
||||||
|
{
|
||||||
|
tp[0] = ( char ) ( word >> 8 );
|
||||||
|
tp[1] = ( char ) ( word & 0xff );
|
||||||
|
}
|
||||||
|
tp[2] = ( char ) token_length;
|
||||||
|
tp[3] = ( char ) ( token - cbuf );
|
||||||
|
|
||||||
|
/* Step to next token position and count the word */
|
||||||
|
|
||||||
|
tp += 4;
|
||||||
|
words++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Moan if token buffer space exhausted */
|
||||||
|
|
||||||
|
output_string( "Too many words typed, discarding: " );
|
||||||
|
output_line( token );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while ( token_length );
|
||||||
|
|
||||||
|
/* Store word count */
|
||||||
|
|
||||||
|
tbuf[1] = ( char ) words;
|
||||||
|
|
||||||
|
} /* tokenise_line */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* next_token
|
||||||
|
*
|
||||||
|
* Find next token in a string. The token (word) is delimited by a statically
|
||||||
|
* defined and a game specific set of word separators. The game specific set
|
||||||
|
* of separators look like real word separators, but the parser wants to know
|
||||||
|
* about them. An example would be: 'grue, take the axe. go north'. The
|
||||||
|
* parser wants to know about the comma and the period so that it can correctly
|
||||||
|
* parse the line. The 'interesting' word separators normally appear at the
|
||||||
|
* start of the dictionary, and are also put in a separate list in the game
|
||||||
|
* file.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static const char *next_token( const char *s, const char *str_end, const char **token, int *length,
|
||||||
|
const char *punctuation )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
/* Set the token length to zero */
|
||||||
|
|
||||||
|
*length = 0;
|
||||||
|
|
||||||
|
/* Step through the string looking for separators */
|
||||||
|
|
||||||
|
for ( ; s < str_end; s++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Look for game specific word separators first */
|
||||||
|
|
||||||
|
for ( i = 0; punctuation[i] && *s != punctuation[i]; i++ )
|
||||||
|
;
|
||||||
|
|
||||||
|
/* If a separator is found then return the information */
|
||||||
|
|
||||||
|
if ( punctuation[i] )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If length has been set then just return the word position */
|
||||||
|
|
||||||
|
if ( *length )
|
||||||
|
return ( s );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* End of word, so set length, token pointer and return string */
|
||||||
|
|
||||||
|
( *length )++;
|
||||||
|
*token = s;
|
||||||
|
return ( ++s );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Look for statically defined separators last */
|
||||||
|
|
||||||
|
for ( i = 0; separators[i] && *s != separators[i]; i++ )
|
||||||
|
;
|
||||||
|
|
||||||
|
/* If a separator is found then return the information */
|
||||||
|
|
||||||
|
if ( separators[i] )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If length has been set then just return the word position */
|
||||||
|
|
||||||
|
if ( *length )
|
||||||
|
return ( ++s );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If first token character then remember its position */
|
||||||
|
|
||||||
|
if ( *length == 0 )
|
||||||
|
*token = s;
|
||||||
|
( *length )++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( s );
|
||||||
|
|
||||||
|
} /* next_token */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* find_word
|
||||||
|
*
|
||||||
|
* Search the dictionary for a word. Just encode the word and binary chop the
|
||||||
|
* dictionary looking for it.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static zword_t find_word( int len, const char *cp, long chop )
|
||||||
|
{
|
||||||
|
ZINT16 word[3];
|
||||||
|
long word_index, offset, status;
|
||||||
|
|
||||||
|
/* Don't look up the word if there are no dictionary entries */
|
||||||
|
|
||||||
|
if ( dictionary_size == 0 )
|
||||||
|
return ( 0 );
|
||||||
|
|
||||||
|
/* Encode target word */
|
||||||
|
|
||||||
|
encode_text( len, cp, word );
|
||||||
|
|
||||||
|
/* Do a binary chop search on the main dictionary, otherwise do
|
||||||
|
* a linear search */
|
||||||
|
|
||||||
|
word_index = chop - 1;
|
||||||
|
|
||||||
|
if ( dictionary_size > 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Binary chop until the word is found */
|
||||||
|
|
||||||
|
while ( chop )
|
||||||
|
{
|
||||||
|
|
||||||
|
chop /= 2;
|
||||||
|
|
||||||
|
/* Calculate dictionary offset */
|
||||||
|
|
||||||
|
if ( word_index > ( dictionary_size - 1 ) )
|
||||||
|
word_index = dictionary_size - 1;
|
||||||
|
|
||||||
|
offset = dictionary_offset + ( word_index * entry_size );
|
||||||
|
|
||||||
|
/* If word matches then return dictionary offset */
|
||||||
|
|
||||||
|
if ( ( status = word[0] - ( ZINT16 ) get_word( offset + 0 ) ) == 0 &&
|
||||||
|
( status = word[1] - ( ZINT16 ) get_word( offset + 2 ) ) == 0 &&
|
||||||
|
( h_type < V4 || ( status = word[2] - ( ZINT16 ) get_word( offset + 4 ) ) == 0 ) )
|
||||||
|
return ( ( zword_t ) offset );
|
||||||
|
|
||||||
|
/* Set next position depending on direction of overshoot */
|
||||||
|
|
||||||
|
if ( status > 0 )
|
||||||
|
{
|
||||||
|
word_index += chop;
|
||||||
|
|
||||||
|
/* Deal with end of dictionary case */
|
||||||
|
|
||||||
|
if ( word_index >= ( int ) dictionary_size )
|
||||||
|
word_index = dictionary_size - 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
word_index -= chop;
|
||||||
|
|
||||||
|
/* Deal with start of dictionary case */
|
||||||
|
|
||||||
|
if ( word_index < 0 )
|
||||||
|
word_index = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
for ( word_index = 0; word_index < -dictionary_size; word_index++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Calculate dictionary offset */
|
||||||
|
|
||||||
|
offset = dictionary_offset + ( word_index * entry_size );
|
||||||
|
|
||||||
|
/* If word matches then return dictionary offset */
|
||||||
|
|
||||||
|
if ( ( status = word[0] - ( ZINT16 ) get_word( offset + 0 ) ) == 0 &&
|
||||||
|
( status = word[1] - ( ZINT16 ) get_word( offset + 2 ) ) == 0 &&
|
||||||
|
( h_type < V4 || ( status = word[2] - ( ZINT16 ) get_word( offset + 4 ) ) == 0 ) )
|
||||||
|
return ( ( zword_t ) offset );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( 0 );
|
||||||
|
|
||||||
|
} /* find_word */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_tokenise
|
||||||
|
*
|
||||||
|
* argv[0] = character buffer address
|
||||||
|
* argv[1] = token buffer address
|
||||||
|
* argv[2] = alternate vocabulary table
|
||||||
|
* argv[3] = ignore unknown words flag
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_tokenise( int argc, zword_t * argv )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Supply default parameters */
|
||||||
|
|
||||||
|
if ( argc < 4 )
|
||||||
|
argv[3] = 0;
|
||||||
|
if ( argc < 3 )
|
||||||
|
argv[2] = h_words_offset;
|
||||||
|
|
||||||
|
/* Convert the line to tokens */
|
||||||
|
|
||||||
|
tokenise_line( argv[0], argv[1], argv[2], argv[3] );
|
||||||
|
|
||||||
|
} /* z_tokenise */
|
483
interpre.c
Normal file
483
interpre.c
Normal file
|
@ -0,0 +1,483 @@
|
||||||
|
|
||||||
|
/* $Id: interpre.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: interpre.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: interpre.c,v $
|
||||||
|
* Revision 1.3 2000/07/05 15:20:34 jholder
|
||||||
|
* Updated code to remove warnings.
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* interpre.c
|
||||||
|
*
|
||||||
|
* Main interpreter loop
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/*#define DEBUG_TERPRE*/
|
||||||
|
|
||||||
|
static int halt = FALSE;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* interpret
|
||||||
|
*
|
||||||
|
* Interpret Z code
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int interpret( void )
|
||||||
|
{
|
||||||
|
zbyte_t opcode;
|
||||||
|
zword_t specifier;
|
||||||
|
zword_t operand[8];
|
||||||
|
int maxoperands;
|
||||||
|
int count;
|
||||||
|
int extend;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
interpreter_status = 1;
|
||||||
|
|
||||||
|
/* Loop until HALT instruction executed */
|
||||||
|
|
||||||
|
for ( interpreter_state = RUN; interpreter_state == RUN && halt == FALSE; )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Load opcode and set operand count */
|
||||||
|
|
||||||
|
|
||||||
|
opcode = read_code_byte( );
|
||||||
|
if ( h_type > V4 && opcode == 0xbe )
|
||||||
|
{
|
||||||
|
opcode = read_code_byte( );
|
||||||
|
extend = TRUE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
extend = FALSE;
|
||||||
|
count = 0;
|
||||||
|
|
||||||
|
/* Multiple operand instructions */
|
||||||
|
|
||||||
|
if ( ( opcode < 0x80 || opcode > 0xc0 ) || extend == TRUE )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Two operand class, load both operands */
|
||||||
|
|
||||||
|
if ( opcode < 0x80 && extend == FALSE )
|
||||||
|
{
|
||||||
|
operand[count++] = load_operand( ( opcode & 0x40 ) ? 2 : 1 );
|
||||||
|
operand[count++] = load_operand( ( opcode & 0x20 ) ? 2 : 1 );
|
||||||
|
opcode &= 0x1f;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Variable operand class, load operand specifier */
|
||||||
|
|
||||||
|
opcode &= 0x3f;
|
||||||
|
if ( opcode == 0x2c || opcode == 0x3a )
|
||||||
|
{ /* Extended CALL instruction */
|
||||||
|
specifier = read_code_word( );
|
||||||
|
maxoperands = 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
specifier = read_code_byte( );
|
||||||
|
maxoperands = 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load operands */
|
||||||
|
|
||||||
|
for ( i = ( maxoperands - 1 ) * 2; i >= 0; i -= 2 )
|
||||||
|
if ( ( ( specifier >> i ) & 0x03 ) != 3 )
|
||||||
|
operand[count++] = load_operand( ( specifier >> i ) & 0x03 );
|
||||||
|
else
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( extend == TRUE )
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_TERPRE
|
||||||
|
fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x %d, %d, %d\n", pc, "(EX)", opcode,
|
||||||
|
operand[0], operand[1], operand[2] );
|
||||||
|
#endif
|
||||||
|
switch ( ( char ) opcode )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Extended operand instructions */
|
||||||
|
|
||||||
|
case 0x00:
|
||||||
|
z_save( count, operand[0], operand[1], operand[2] );
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
z_restore( count, operand[0], operand[1], operand[2] );
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
z_log_shift( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
z_art_shift( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
z_set_font( operand[0] );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x09:
|
||||||
|
z_save_undo( );
|
||||||
|
break;
|
||||||
|
case 0x0a:
|
||||||
|
z_restore_undo( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fatal( "interpret(): Illegal extended operand instruction" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef DEBUG_TERPRE
|
||||||
|
fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x %d, %d, %d\n", pc, "(2+)", opcode,
|
||||||
|
operand[0], operand[1], operand[2] );
|
||||||
|
#endif
|
||||||
|
switch ( ( char ) opcode )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Two or multiple operand instructions */
|
||||||
|
case 0x01:
|
||||||
|
z_je( count, operand );
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
z_jl( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
z_jg( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
z_dec_chk( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
z_inc_chk( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
z_jin( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x07:
|
||||||
|
z_test( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
z_or( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
z_and( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x0a:
|
||||||
|
z_test_attr( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x0b:
|
||||||
|
z_set_attr( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x0c:
|
||||||
|
z_clear_attr( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x0d:
|
||||||
|
z_store( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x0e:
|
||||||
|
z_insert_obj( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x0f:
|
||||||
|
z_loadw( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x10:
|
||||||
|
z_loadb( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x11:
|
||||||
|
z_get_prop( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x12:
|
||||||
|
z_get_prop_addr( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x13:
|
||||||
|
z_get_next_prop( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
z_add( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x15:
|
||||||
|
z_sub( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x16:
|
||||||
|
z_mul( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x17:
|
||||||
|
z_div( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
z_mod( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x19:
|
||||||
|
z_call( count, operand, FUNCTION );
|
||||||
|
break;
|
||||||
|
case 0x1a:
|
||||||
|
z_call( count, operand, PROCEDURE );
|
||||||
|
break;
|
||||||
|
case 0x1b:
|
||||||
|
z_set_colour( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x1c:
|
||||||
|
z_throw( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
|
||||||
|
/* Multiple operand instructions */
|
||||||
|
|
||||||
|
case 0x20:
|
||||||
|
z_call( count, operand, FUNCTION );
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
z_storew( operand[0], operand[1], operand[2] );
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
z_storeb( operand[0], operand[1], operand[2] );
|
||||||
|
break;
|
||||||
|
case 0x23:
|
||||||
|
z_put_prop( operand[0], operand[1], operand[2] );
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
z_sread_aread( count, operand );
|
||||||
|
break;
|
||||||
|
case 0x25:
|
||||||
|
z_print_char( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x26:
|
||||||
|
z_print_num( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x27:
|
||||||
|
z_random( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x28:
|
||||||
|
z_push( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x29:
|
||||||
|
z_pull( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x2a:
|
||||||
|
z_split_window( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x2b:
|
||||||
|
z_set_window( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x2c:
|
||||||
|
z_call( count, operand, FUNCTION );
|
||||||
|
break;
|
||||||
|
case 0x2d:
|
||||||
|
z_erase_window( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x2e:
|
||||||
|
z_erase_line( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x2f:
|
||||||
|
z_set_cursor( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x31:
|
||||||
|
z_set_text_style( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x32:
|
||||||
|
z_buffer_mode( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x33:
|
||||||
|
z_output_stream( operand[0], operand[1] );
|
||||||
|
break;
|
||||||
|
case 0x34:
|
||||||
|
z_input_stream( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x35:
|
||||||
|
sound( count, operand );
|
||||||
|
break;
|
||||||
|
case 0x36:
|
||||||
|
z_read_char( count, operand );
|
||||||
|
break;
|
||||||
|
case 0x37:
|
||||||
|
z_scan_table( count, operand );
|
||||||
|
break;
|
||||||
|
case 0x38:
|
||||||
|
z_not( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x39:
|
||||||
|
z_call( count, operand, PROCEDURE );
|
||||||
|
break;
|
||||||
|
case 0x3a:
|
||||||
|
z_call( count, operand, PROCEDURE );
|
||||||
|
break;
|
||||||
|
case 0x3b:
|
||||||
|
z_tokenise( count, operand );
|
||||||
|
break;
|
||||||
|
case 0x3c:
|
||||||
|
z_encode( operand[0], operand[1], operand[2], operand[3] );
|
||||||
|
break;
|
||||||
|
case 0x3d:
|
||||||
|
z_copy_table( operand[0], operand[1], operand[2] );
|
||||||
|
break;
|
||||||
|
case 0x3e:
|
||||||
|
z_print_table( count, operand );
|
||||||
|
break;
|
||||||
|
case 0x3f:
|
||||||
|
z_check_arg_count( operand[0] );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fatal( "interpret(): Illegal 2 or more operand instruction" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Single operand class, load operand and execute instruction */
|
||||||
|
|
||||||
|
if ( opcode < 0xb0 )
|
||||||
|
{
|
||||||
|
operand[0] = load_operand( ( opcode >> 4 ) & 0x03 );
|
||||||
|
#ifdef DEBUG_TERPRE
|
||||||
|
fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x %d\n", pc, "(1 )", opcode,
|
||||||
|
operand[0] );
|
||||||
|
#endif
|
||||||
|
switch ( ( char ) opcode & 0x0f )
|
||||||
|
{
|
||||||
|
case 0x00:
|
||||||
|
z_jz( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
z_get_sibling( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
z_get_child( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
z_get_parent( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
z_get_prop_len( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
z_inc( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
z_dec( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x07:
|
||||||
|
z_print_addr( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
z_call( 1, operand, FUNCTION );
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
z_remove_obj( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x0a:
|
||||||
|
z_print_obj( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x0b:
|
||||||
|
z_ret( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x0c:
|
||||||
|
z_jump( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x0d:
|
||||||
|
z_print_paddr( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x0e:
|
||||||
|
z_load( operand[0] );
|
||||||
|
break;
|
||||||
|
case 0x0f:
|
||||||
|
if ( h_type > V4 )
|
||||||
|
z_call( 1, operand, PROCEDURE );
|
||||||
|
else
|
||||||
|
z_not( operand[0] );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Zero operand class, execute instruction */
|
||||||
|
#ifdef DEBUG_TERPRE
|
||||||
|
fprintf( stderr, "PC = 0x%08lx Op%s = 0x%02x\n", pc, "(0 )", opcode );
|
||||||
|
#endif
|
||||||
|
switch ( ( char ) opcode & 0x0f )
|
||||||
|
{
|
||||||
|
case 0x00:
|
||||||
|
z_ret( TRUE );
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
z_ret( FALSE );
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
z_print( );
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
z_print_ret( );
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
/* z_nop */
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
z_save( 0, 0, 0, 0 );
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
z_restore( 0, 0, 0, 0 );
|
||||||
|
break;
|
||||||
|
case 0x07:
|
||||||
|
z_restart( );
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
z_ret( stack[sp++] );
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
z_catch( );
|
||||||
|
break;
|
||||||
|
case 0x0a:
|
||||||
|
halt = TRUE; /* z_quit */
|
||||||
|
break;
|
||||||
|
case 0x0b:
|
||||||
|
z_new_line( );
|
||||||
|
break;
|
||||||
|
case 0x0c:
|
||||||
|
z_show_status( );
|
||||||
|
break;
|
||||||
|
case 0x0d:
|
||||||
|
z_verify( );
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 0x0f:
|
||||||
|
z_piracy( TRUE );
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
fatal( "interpret(): Illegal zero operand instruction" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( interpreter_status );
|
||||||
|
|
||||||
|
} /* interpret */
|
223
joeyio.c
Normal file
223
joeyio.c
Normal file
|
@ -0,0 +1,223 @@
|
||||||
|
#include "joey.h"
|
||||||
|
#include "ansiterm.h"
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
static int head_col;
|
||||||
|
|
||||||
|
|
||||||
|
void clear_line(void) {
|
||||||
|
termPrint("\33[K");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void clear_screen(void) {
|
||||||
|
termClearScreen();
|
||||||
|
jlDisplayPresent();
|
||||||
|
termMoveCursor(1, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void clear_status_window(void) {
|
||||||
|
int i;
|
||||||
|
int row;
|
||||||
|
int col;
|
||||||
|
get_cursor_position(&row, &col);
|
||||||
|
for (i=status_size; i; i--) {
|
||||||
|
move_cursor(i, 1);
|
||||||
|
clear_line();
|
||||||
|
}
|
||||||
|
move_cursor(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void clear_text_window(void) {
|
||||||
|
int i;
|
||||||
|
int row;
|
||||||
|
int col;
|
||||||
|
get_cursor_position(&row, &col);
|
||||||
|
for (i=status_size + 1; i<=screen_rows; i++) {
|
||||||
|
move_cursor(i, 1);
|
||||||
|
clear_line();
|
||||||
|
}
|
||||||
|
move_cursor(row, col);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void create_status_window(void) {
|
||||||
|
printf("Create Status Window\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void delete_status_window(void) {
|
||||||
|
printf("Delete Status Window\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void display_char(int c) {
|
||||||
|
termPrintChar((char)c);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void get_cursor_position(int *row, int *col) {
|
||||||
|
termGetCursor(col, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void initialize_screen(void) {
|
||||||
|
// Handled in main
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int input_character(int timeout) {
|
||||||
|
char k = 0;
|
||||||
|
(void)timeout; // In 1/10ths of a second
|
||||||
|
while (!jlKeyPressed() && !jlUtilMustExit()) {
|
||||||
|
//***TODO*** Animate cursor here?
|
||||||
|
}
|
||||||
|
if (jlKeyPressed()) {
|
||||||
|
while (jlKeyPressed()) {
|
||||||
|
// Wait for key to be released
|
||||||
|
}
|
||||||
|
k = jlKeyRead();
|
||||||
|
} else {
|
||||||
|
interpreter_state = STOP;
|
||||||
|
}
|
||||||
|
return (int)k;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int input_line(int buflen, char *buffer, int timeout, int *read_size) {
|
||||||
|
int c = -1;
|
||||||
|
int col;
|
||||||
|
int row;
|
||||||
|
int init_char_pos;
|
||||||
|
int curr_char_pos;
|
||||||
|
int loop;
|
||||||
|
int tail_col;
|
||||||
|
|
||||||
|
(void)timeout; // In 1/10ths of a second
|
||||||
|
|
||||||
|
get_cursor_position(&row, &col);
|
||||||
|
head_col = tail_col = col;
|
||||||
|
init_char_pos = curr_char_pos = *read_size;
|
||||||
|
|
||||||
|
while (!jlUtilMustExit()) {
|
||||||
|
c = input_character(0);
|
||||||
|
|
||||||
|
if (c == 8) {
|
||||||
|
// Backspace
|
||||||
|
get_cursor_position(&row, &col);
|
||||||
|
if (col > head_col) {
|
||||||
|
move_cursor(row, --col);
|
||||||
|
for (loop = curr_char_pos; loop < *read_size; loop++) {
|
||||||
|
buffer[loop - 1] = buffer[loop];
|
||||||
|
display_char(buffer[loop - 1]);
|
||||||
|
}
|
||||||
|
display_char(' ');
|
||||||
|
curr_char_pos--;
|
||||||
|
tail_col--;
|
||||||
|
(*read_size)--;
|
||||||
|
move_cursor(row, col);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Normal key
|
||||||
|
if (*read_size == ( buflen - 1 )) {
|
||||||
|
//***TODO*** Buffer full - Flash border?
|
||||||
|
} else {
|
||||||
|
if (c == 13) {
|
||||||
|
// CR
|
||||||
|
scroll_line();
|
||||||
|
return c;
|
||||||
|
} else {
|
||||||
|
// Used if the cursor is not at the end of the line
|
||||||
|
if (col < tail_col) {
|
||||||
|
// Moves the input line one character to the right
|
||||||
|
for (loop = *read_size; loop >= curr_char_pos; loop--) {
|
||||||
|
buffer[loop + 1] = buffer[loop];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Puts the character into the space created by the "for" loop above
|
||||||
|
buffer[curr_char_pos] = (char)c;
|
||||||
|
|
||||||
|
// Increment the end of the line values
|
||||||
|
(*read_size)++;
|
||||||
|
tail_col++;
|
||||||
|
|
||||||
|
// Move the cursor back to its original position
|
||||||
|
move_cursor(row, col);
|
||||||
|
|
||||||
|
// Redisplays the input line from the point of insertion
|
||||||
|
for (loop = curr_char_pos; loop < *read_size; loop++) {
|
||||||
|
display_char(buffer[loop]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Moves the cursor to the next position
|
||||||
|
move_cursor(row, ++col);
|
||||||
|
curr_char_pos++;
|
||||||
|
} else {
|
||||||
|
// Used if the cursor is at the end of the line
|
||||||
|
buffer[curr_char_pos++] = (char)c;
|
||||||
|
display_char(c);
|
||||||
|
(*read_size)++;
|
||||||
|
tail_col++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void move_cursor(int row, int col) {
|
||||||
|
termMoveCursor(col, row);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void reset_screen(void) {
|
||||||
|
// Handled in main
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void restart_screen(void) {
|
||||||
|
// I don't think we need this.
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void restore_cursor_position(void) {
|
||||||
|
termRestoreCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void save_cursor_position(void) {
|
||||||
|
termSaveCursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void scroll_line(void) {
|
||||||
|
//***TODO*** Should really not clobber the status window.
|
||||||
|
termPrintChar(13);
|
||||||
|
termPrintChar(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void select_status_window(void) {
|
||||||
|
save_cursor_position();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void select_text_window(void) {
|
||||||
|
restore_cursor_position();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void set_attribute(int attribute) {
|
||||||
|
if (attribute == NORMAL) {
|
||||||
|
termPrint("\33[0m");
|
||||||
|
}
|
||||||
|
if (attribute & REVERSE) {
|
||||||
|
termPrint("\33[7m");
|
||||||
|
}
|
||||||
|
}
|
37
jzip.h
Normal file
37
jzip.h
Normal file
|
@ -0,0 +1,37 @@
|
||||||
|
|
||||||
|
/* $Id: jzip.h,v 1.5 2000/10/10 14:46:22 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: jzip.h,v 1.5 2000/10/10 14:46:22 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: jzip.h,v $
|
||||||
|
* Revision 1.5 2000/10/10 14:46:22 jholder
|
||||||
|
* Fixed text wrap bug when printing array w/ \r chars in it
|
||||||
|
*
|
||||||
|
* Revision 1.4 2000/10/05 17:09:12 jholder
|
||||||
|
* removed old email address
|
||||||
|
*
|
||||||
|
* Revision 1.3 2000/10/04 23:07:57 jholder
|
||||||
|
* fixed redirect problem with isolatin1 range chars
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/09/18 15:31:44 jholder
|
||||||
|
* Updated release date for package release
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define JZIPVER "Jzip V2.1"
|
||||||
|
#define JZIPRELDATE "Tue, Oct 10 2000"
|
||||||
|
#define JZIPAUTHOR "John Holder (j-holder@home.com)"
|
||||||
|
#define JZIPURL "http://jzip.sourceforge.net/"
|
||||||
|
|
122
main.c
Normal file
122
main.c
Normal file
|
@ -0,0 +1,122 @@
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include "joey.h"
|
||||||
|
#include "ansiterm.h"
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
|
||||||
|
extern int GLOBALVER;
|
||||||
|
|
||||||
|
|
||||||
|
void configure(zbyte_t min_version, zbyte_t max_version);
|
||||||
|
void process_arguments(char *game);
|
||||||
|
|
||||||
|
|
||||||
|
void configure(zbyte_t min_version, zbyte_t max_version) {
|
||||||
|
zbyte_t header[PAGE_SIZE];
|
||||||
|
|
||||||
|
read_page(0, header);
|
||||||
|
datap = header;
|
||||||
|
|
||||||
|
h_type = get_byte(H_TYPE);
|
||||||
|
GLOBALVER = h_type;
|
||||||
|
|
||||||
|
if (h_type < min_version || h_type > max_version || (get_byte( H_CONFIG ) & CONFIG_BYTE_SWAPPED)) {
|
||||||
|
fatal( "Wrong game or version" );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (h_type < V4) {
|
||||||
|
story_scaler = 2;
|
||||||
|
story_shift = 1;
|
||||||
|
property_mask = P3_MAX_PROPERTIES - 1;
|
||||||
|
property_size_mask = 0xe0;
|
||||||
|
} else if (h_type < V8) {
|
||||||
|
story_scaler = 4;
|
||||||
|
story_shift = 2;
|
||||||
|
property_mask = P4_MAX_PROPERTIES - 1;
|
||||||
|
property_size_mask = 0x3f;
|
||||||
|
} else {
|
||||||
|
story_scaler = 8;
|
||||||
|
story_shift = 3;
|
||||||
|
property_mask = P4_MAX_PROPERTIES - 1;
|
||||||
|
property_size_mask = 0x3f;
|
||||||
|
}
|
||||||
|
|
||||||
|
h_config = get_byte(H_CONFIG);
|
||||||
|
h_version = get_word(H_VERSION);
|
||||||
|
h_data_size = get_word(H_DATA_SIZE);
|
||||||
|
h_start_pc = get_word(H_START_PC);
|
||||||
|
h_words_offset = get_word(H_WORDS_OFFSET);
|
||||||
|
h_objects_offset = get_word(H_OBJECTS_OFFSET);
|
||||||
|
h_globals_offset = get_word(H_GLOBALS_OFFSET);
|
||||||
|
h_restart_size = get_word(H_RESTART_SIZE);
|
||||||
|
h_flags = get_word(H_FLAGS);
|
||||||
|
h_synonyms_offset = get_word(H_SYNONYMS_OFFSET);
|
||||||
|
h_file_size = get_word(H_FILE_SIZE);
|
||||||
|
if (h_file_size == 0) {
|
||||||
|
h_file_size = (zword_t)get_story_size();
|
||||||
|
}
|
||||||
|
h_checksum = get_word(H_CHECKSUM);
|
||||||
|
h_alternate_alphabet_offset = get_word(H_ALTERNATE_ALPHABET_OFFSET);
|
||||||
|
|
||||||
|
if (h_type >= V5) {
|
||||||
|
h_unicode_table = get_word(H_UNICODE_TABLE);
|
||||||
|
}
|
||||||
|
datap = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void process_arguments(char *game) {
|
||||||
|
int size;
|
||||||
|
|
||||||
|
monochrome = 0;
|
||||||
|
hist_buf_size = 1024;
|
||||||
|
bigscreen = 0;
|
||||||
|
screen_rows = 25;
|
||||||
|
screen_cols = 40;
|
||||||
|
right_margin = 0;
|
||||||
|
top_margin = 0;
|
||||||
|
size = 1024;
|
||||||
|
hist_buf_size = (hist_buf_size > size) ? hist_buf_size : size;
|
||||||
|
if (hist_buf_size > 16384) {
|
||||||
|
hist_buf_size = 16384;
|
||||||
|
}
|
||||||
|
fTandy = 0;
|
||||||
|
//default_fg = atoi( optarg );
|
||||||
|
//default_bg = atoi( optarg );
|
||||||
|
monochrome = 1;
|
||||||
|
|
||||||
|
open_story(game);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int main(void) {
|
||||||
|
|
||||||
|
jlStaT *font = NULL;
|
||||||
|
|
||||||
|
jlUtilStartup("IF Engine");
|
||||||
|
jlStaLoad(font, "8x8thin.sta");
|
||||||
|
|
||||||
|
termStart(font, 0, 0, 40, 25);
|
||||||
|
|
||||||
|
process_arguments("gamedata.z5");
|
||||||
|
configure(V1, V8);
|
||||||
|
initialize_screen();
|
||||||
|
load_cache();
|
||||||
|
z_restart();
|
||||||
|
(void)interpret();
|
||||||
|
unload_cache();
|
||||||
|
close_story();
|
||||||
|
close_script();
|
||||||
|
reset_screen();
|
||||||
|
|
||||||
|
termStop();
|
||||||
|
|
||||||
|
jlDisplayPresent();
|
||||||
|
jlKeyWaitForAny();
|
||||||
|
jlStaFree(font);
|
||||||
|
|
||||||
|
jlUtilShutdown();
|
||||||
|
}
|
305
math.c
Normal file
305
math.c
Normal file
|
@ -0,0 +1,305 @@
|
||||||
|
|
||||||
|
/* $Id: math.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: math.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: math.c,v $
|
||||||
|
* Revision 1.3 2000/07/05 15:20:34 jholder
|
||||||
|
* Updated code to remove warnings.
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* math.c
|
||||||
|
*
|
||||||
|
* Arithmetic, compare and logical instructions
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_add
|
||||||
|
*
|
||||||
|
* Add two operands
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_add( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
store_operand( (zword_t)(a + b) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_sub
|
||||||
|
*
|
||||||
|
* Subtract two operands
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_sub( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
store_operand( (zword_t)(a - b) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mul
|
||||||
|
*
|
||||||
|
* Multiply two operands
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_mul( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
store_operand( (zword_t)(( ZINT16 ) a * ( ZINT16 ) b) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_div
|
||||||
|
*
|
||||||
|
* Divide two operands
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_div( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
/* The magic rule is: round towards zero. */
|
||||||
|
ZINT16 sa = ( ZINT16 ) a;
|
||||||
|
ZINT16 sb = ( ZINT16 ) b;
|
||||||
|
ZINT16 res;
|
||||||
|
|
||||||
|
if ( sb < 0 )
|
||||||
|
{
|
||||||
|
sa = -sa;
|
||||||
|
sb = -sb;
|
||||||
|
}
|
||||||
|
if ( sb == 0 )
|
||||||
|
{
|
||||||
|
#ifdef STRICTZ
|
||||||
|
report_strictz_error( STRZERR_DIV_ZERO,
|
||||||
|
"@div attempted with a divisor of zero. Result set to 32767 (0x7fff)." );
|
||||||
|
#endif
|
||||||
|
res = 32767;
|
||||||
|
}
|
||||||
|
else if ( sa >= 0 )
|
||||||
|
{
|
||||||
|
res = sa / sb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = -( ( -sa ) / ( sb ) );
|
||||||
|
}
|
||||||
|
store_operand( res );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_mod
|
||||||
|
*
|
||||||
|
* Modulus divide two operands
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_mod( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
/* The magic rule is: be consistent with divide, because
|
||||||
|
* (a/b)*a + (a%b) == a. So (a%b) has the same sign as a. */
|
||||||
|
ZINT16 sa = ( ZINT16 ) a;
|
||||||
|
ZINT16 sb = ( ZINT16 ) b;
|
||||||
|
ZINT16 res;
|
||||||
|
|
||||||
|
if ( sb < 0 )
|
||||||
|
{
|
||||||
|
sb = -sb;
|
||||||
|
}
|
||||||
|
if ( sb == 0 )
|
||||||
|
{
|
||||||
|
#ifdef STRICTZ
|
||||||
|
report_strictz_error( STRZERR_DIV_ZERO,
|
||||||
|
"@mod attempted with a divisor of zero. Result set to 0." );
|
||||||
|
#endif
|
||||||
|
res = 0;
|
||||||
|
}
|
||||||
|
if ( sa >= 0 )
|
||||||
|
{
|
||||||
|
res = sa % sb;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
res = -( ( -sa ) % ( sb ) );
|
||||||
|
}
|
||||||
|
store_operand( res );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_log_shift
|
||||||
|
*
|
||||||
|
* Shift +/- n bits
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_log_shift( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( ( ZINT16 ) b > 0 )
|
||||||
|
store_operand( (zword_t)( a << ( ZINT16 ) b ) );
|
||||||
|
else
|
||||||
|
store_operand( (zword_t)( a >> -( ( ZINT16 ) b ) ) );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_art_shift
|
||||||
|
*
|
||||||
|
* Aritmetic shift +/- n bits
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_art_shift( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
if ( ( ZINT16 ) b > 0 )
|
||||||
|
store_operand( ( zword_t ) ( ( ZINT16 ) a << ( ZINT16 ) b ) );
|
||||||
|
else
|
||||||
|
store_operand( ( zword_t ) ( ( ZINT16 ) a >> -( ( ZINT16 ) b ) ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_or
|
||||||
|
*
|
||||||
|
* Logical OR
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_or( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
store_operand( (zword_t)(a | b) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_not
|
||||||
|
*
|
||||||
|
* Logical NOT
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_not( zword_t a )
|
||||||
|
{
|
||||||
|
store_operand( (zword_t)(~a) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_and
|
||||||
|
*
|
||||||
|
* Logical AND
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_and( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
store_operand( (zword_t)(a & b) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_random
|
||||||
|
*
|
||||||
|
* Return random number between 1 and operand
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_random( zword_t a )
|
||||||
|
{
|
||||||
|
if ( a == 0 )
|
||||||
|
store_operand( 0 );
|
||||||
|
else if ( a & 0x8000 )
|
||||||
|
{ /* (a < 0) - used to set seed with #RANDOM */
|
||||||
|
SRANDOM_FUNC( ( unsigned int ) abs( a ) );
|
||||||
|
store_operand( 0 );
|
||||||
|
}
|
||||||
|
else /* (a > 0) */
|
||||||
|
store_operand( (zword_t)(( RANDOM_FUNC( ) % a ) + 1) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_test
|
||||||
|
*
|
||||||
|
* Jump if operand 2 bit mask not set in operand 1
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_test( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
conditional_jump( ( ( ~a ) & b ) == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_jz
|
||||||
|
*
|
||||||
|
* Compare operand against zero
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_jz( zword_t a )
|
||||||
|
{
|
||||||
|
conditional_jump( a == 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_je
|
||||||
|
*
|
||||||
|
* Jump if operand 1 is equal to any other operand
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_je( int count, zword_t * operand )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for ( i = 1; i < count; i++ )
|
||||||
|
if ( operand[0] == operand[i] )
|
||||||
|
{
|
||||||
|
conditional_jump( TRUE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
conditional_jump( FALSE );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_jl
|
||||||
|
*
|
||||||
|
* Jump if operand 1 is less than operand 2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_jl( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
conditional_jump( ( ZINT16 ) a < ( ZINT16 ) b );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_jg
|
||||||
|
*
|
||||||
|
* Jump if operand 1 is greater than operand 2
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_jg( zword_t a, zword_t b )
|
||||||
|
{
|
||||||
|
conditional_jump( ( ZINT16 ) a > ( ZINT16 ) b );
|
||||||
|
}
|
419
memory.c
Normal file
419
memory.c
Normal file
|
@ -0,0 +1,419 @@
|
||||||
|
|
||||||
|
/* $Id: memory.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: memory.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: memory.c,v $
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* memory.c
|
||||||
|
*
|
||||||
|
* Code and data caching routines
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/* A cache entry */
|
||||||
|
|
||||||
|
typedef struct cache_entry
|
||||||
|
{
|
||||||
|
struct cache_entry *flink;
|
||||||
|
int page_number;
|
||||||
|
zbyte_t data[PAGE_SIZE];
|
||||||
|
}
|
||||||
|
cache_entry_t;
|
||||||
|
|
||||||
|
/* Cache chain anchor */
|
||||||
|
|
||||||
|
static cache_entry_t *cache = NULL;
|
||||||
|
|
||||||
|
/* Pseudo translation buffer, one entry each for code and data pages */
|
||||||
|
|
||||||
|
static unsigned int current_code_page = 0;
|
||||||
|
static cache_entry_t *current_code_cachep = NULL;
|
||||||
|
static unsigned int current_data_page = 0;
|
||||||
|
static cache_entry_t *current_data_cachep = NULL;
|
||||||
|
|
||||||
|
static unsigned int calc_data_pages( void );
|
||||||
|
static cache_entry_t *update_cache( int );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load_cache
|
||||||
|
*
|
||||||
|
* Initialise the cache and any other dynamic memory objects. The memory
|
||||||
|
* required can be split into two areas. Firstly, three buffers are required for
|
||||||
|
* input, output and status line. Secondly, two data areas are required for
|
||||||
|
* writeable data and read only data. The writeable data is the first chunk of
|
||||||
|
* the file and is put into non-paged cache. The read only data is the remainder
|
||||||
|
* of the file which can be paged into the cache as required. Writeable data has
|
||||||
|
* to be memory resident because it cannot be written out to a backing store.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void load_cache( void )
|
||||||
|
{
|
||||||
|
unsigned long file_size;
|
||||||
|
unsigned int i, file_pages, data_pages;
|
||||||
|
cache_entry_t *cachep;
|
||||||
|
|
||||||
|
/* Allocate output and status line buffers */
|
||||||
|
|
||||||
|
line = ( char * ) malloc( screen_cols + 1 );
|
||||||
|
if ( line == NULL )
|
||||||
|
{
|
||||||
|
fatal( "load_cache(): Insufficient memory to play game" );
|
||||||
|
}
|
||||||
|
status_line = ( char * ) malloc( screen_cols + 1 );
|
||||||
|
if ( status_line == NULL )
|
||||||
|
{
|
||||||
|
fatal( "load_cache(): Insufficient memory to play game" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must have at least one cache page for memory calculation */
|
||||||
|
cachep = ( cache_entry_t * ) malloc( sizeof ( cache_entry_t ) );
|
||||||
|
|
||||||
|
if ( cachep == NULL )
|
||||||
|
{
|
||||||
|
fatal( "load_cache(): Insufficient memory to play game" );
|
||||||
|
}
|
||||||
|
cachep->flink = cache;
|
||||||
|
cachep->page_number = 0;
|
||||||
|
cache = cachep;
|
||||||
|
|
||||||
|
/* Calculate dynamic cache pages required */
|
||||||
|
|
||||||
|
if ( h_config & CONFIG_MAX_DATA )
|
||||||
|
{
|
||||||
|
data_pages = calc_data_pages( );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data_pages = ( h_data_size + PAGE_MASK ) >> PAGE_SHIFT;
|
||||||
|
}
|
||||||
|
data_size = data_pages * PAGE_SIZE;
|
||||||
|
file_size = ( unsigned long ) h_file_size *story_scaler;
|
||||||
|
|
||||||
|
file_pages = ( unsigned int ) ( ( file_size + PAGE_MASK ) >> PAGE_SHIFT );
|
||||||
|
|
||||||
|
/* Allocate static data area and initialise it */
|
||||||
|
|
||||||
|
datap = ( zbyte_t * ) malloc( data_size );
|
||||||
|
if ( datap == NULL )
|
||||||
|
{
|
||||||
|
fatal( "load_cache(): Insufficient memory to play game" );
|
||||||
|
}
|
||||||
|
for ( i = 0; i < data_pages; i++ )
|
||||||
|
{
|
||||||
|
read_page( i, &datap[i * PAGE_SIZE] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Allocate memory for undo */
|
||||||
|
|
||||||
|
undo_datap = ( zbyte_t * ) malloc( data_size );
|
||||||
|
|
||||||
|
/* Allocate cache pages and initialise them */
|
||||||
|
|
||||||
|
for ( i = data_pages; cachep != NULL && i < file_pages; i++ )
|
||||||
|
{
|
||||||
|
cachep = ( cache_entry_t * ) malloc( sizeof ( cache_entry_t ) );
|
||||||
|
|
||||||
|
if ( cachep != NULL )
|
||||||
|
{
|
||||||
|
cachep->flink = cache;
|
||||||
|
cachep->page_number = i;
|
||||||
|
read_page( cachep->page_number, cachep->data );
|
||||||
|
cache = cachep;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* load_cache */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* unload_cache
|
||||||
|
*
|
||||||
|
* Deallocate cache and other memory objects.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void unload_cache( void )
|
||||||
|
{
|
||||||
|
cache_entry_t *cachep, *nextp;
|
||||||
|
|
||||||
|
/* Make sure all output has been flushed */
|
||||||
|
|
||||||
|
z_new_line( );
|
||||||
|
|
||||||
|
/* Free output buffer, status line and data memory */
|
||||||
|
|
||||||
|
free( line );
|
||||||
|
free( status_line );
|
||||||
|
free( datap );
|
||||||
|
free( undo_datap );
|
||||||
|
|
||||||
|
/* Free cache memory */
|
||||||
|
|
||||||
|
for ( cachep = cache; cachep->flink != NULL; cachep = nextp )
|
||||||
|
{
|
||||||
|
nextp = cachep->flink;
|
||||||
|
free( cachep );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* unload_cache */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read_code_word
|
||||||
|
*
|
||||||
|
* Read a word from the instruction stream.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
zword_t read_code_word( void )
|
||||||
|
{
|
||||||
|
zword_t w;
|
||||||
|
|
||||||
|
w = ( zword_t ) read_code_byte( ) << 8;
|
||||||
|
w |= ( zword_t ) read_code_byte( );
|
||||||
|
|
||||||
|
return ( w );
|
||||||
|
|
||||||
|
} /* read_code_word */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read_code_byte
|
||||||
|
*
|
||||||
|
* Read a byte from the instruction stream.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
zbyte_t read_code_byte( void )
|
||||||
|
{
|
||||||
|
unsigned int page_number, page_offset;
|
||||||
|
|
||||||
|
/* Calculate page and offset values */
|
||||||
|
|
||||||
|
page_number = ( unsigned int ) ( pc >> PAGE_SHIFT );
|
||||||
|
page_offset = ( unsigned int ) pc & PAGE_MASK;
|
||||||
|
|
||||||
|
/* Load page into translation buffer */
|
||||||
|
|
||||||
|
if ( page_number != current_code_page )
|
||||||
|
{
|
||||||
|
current_code_cachep = update_cache( page_number );
|
||||||
|
current_code_page = page_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the PC */
|
||||||
|
|
||||||
|
pc++;
|
||||||
|
|
||||||
|
/* Return byte from page offset */
|
||||||
|
|
||||||
|
if ( !current_code_cachep )
|
||||||
|
{
|
||||||
|
fatal
|
||||||
|
( "read_code_byte(): read from non-existant page!\n\t(Your dynamic memory usage _may_ be over 64k in size!)" );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( current_code_cachep->data[page_offset] );
|
||||||
|
|
||||||
|
} /* read_code_byte */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read_data_word
|
||||||
|
*
|
||||||
|
* Read a word from the data area.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
zword_t read_data_word( unsigned long *addr )
|
||||||
|
{
|
||||||
|
zword_t w;
|
||||||
|
|
||||||
|
w = ( zword_t ) read_data_byte( addr ) << 8;
|
||||||
|
w |= ( zword_t ) read_data_byte( addr );
|
||||||
|
|
||||||
|
return ( w );
|
||||||
|
|
||||||
|
} /* read_data_word */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* read_data_byte
|
||||||
|
*
|
||||||
|
* Read a byte from the data area.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
zbyte_t read_data_byte( unsigned long *addr )
|
||||||
|
{
|
||||||
|
unsigned int page_number, page_offset;
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
/* Check if byte is in non-paged cache */
|
||||||
|
|
||||||
|
if ( *addr < ( unsigned long ) data_size )
|
||||||
|
{
|
||||||
|
value = datap[*addr];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Calculate page and offset values */
|
||||||
|
|
||||||
|
page_number = ( int ) ( *addr >> PAGE_SHIFT );
|
||||||
|
page_offset = ( int ) *addr & PAGE_MASK;
|
||||||
|
|
||||||
|
/* Load page into translation buffer */
|
||||||
|
|
||||||
|
if ( page_number != current_data_page )
|
||||||
|
{
|
||||||
|
current_data_cachep = update_cache( page_number );
|
||||||
|
current_data_page = page_number;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Fetch byte from page offset */
|
||||||
|
|
||||||
|
if ( current_data_cachep )
|
||||||
|
{
|
||||||
|
value = current_data_cachep->data[page_offset];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
fatal( "read_data_byte(): Fetching data from invalid page!" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Update the address */
|
||||||
|
|
||||||
|
( *addr )++;
|
||||||
|
|
||||||
|
return ( value );
|
||||||
|
|
||||||
|
} /* read_data_byte */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* calc_data_pages
|
||||||
|
*
|
||||||
|
* Compute the best size for the data area cache. Some games have the data size
|
||||||
|
* header parameter set too low. This causes a write outside of data area on
|
||||||
|
* some games. To alleviate this problem the data area size is set to the
|
||||||
|
* maximum of the restart size, the data size and the end of the dictionary. An
|
||||||
|
* attempt is made to put the dictionary in the data area to stop paging during
|
||||||
|
* a dictionary lookup. Some games have the dictionary end very close to the
|
||||||
|
* 64K limit which may cause problems for machines that allocate memory in
|
||||||
|
* 64K chunks.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static unsigned int calc_data_pages( void )
|
||||||
|
{
|
||||||
|
unsigned long offset, data_end, dictionary_end;
|
||||||
|
int separator_count, word_size, word_count;
|
||||||
|
unsigned int data_pages;
|
||||||
|
|
||||||
|
/* Calculate end of data area, use restart size if data size is too low */
|
||||||
|
|
||||||
|
if ( h_data_size > h_restart_size )
|
||||||
|
{
|
||||||
|
data_end = h_data_size;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data_end = h_restart_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calculate end of dictionary table */
|
||||||
|
|
||||||
|
offset = h_words_offset;
|
||||||
|
separator_count = read_data_byte( &offset );
|
||||||
|
offset += separator_count;
|
||||||
|
word_size = read_data_byte( &offset );
|
||||||
|
word_count = read_data_word( &offset );
|
||||||
|
dictionary_end = offset + ( word_size * word_count );
|
||||||
|
|
||||||
|
/* If data end is too low then use end of dictionary instead */
|
||||||
|
|
||||||
|
if ( dictionary_end > data_end )
|
||||||
|
{
|
||||||
|
data_pages = ( unsigned int ) ( ( dictionary_end + PAGE_MASK ) >> PAGE_SHIFT );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
data_pages = ( unsigned int ) ( ( data_end + PAGE_MASK ) >> PAGE_SHIFT );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( data_pages );
|
||||||
|
|
||||||
|
} /* calc_data_pages */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* update_cache
|
||||||
|
*
|
||||||
|
* Called on a code or data page cache miss to find the page in the cache or
|
||||||
|
* read the page in from disk. The chain is kept as a simple LRU chain. If a
|
||||||
|
* page cannot be found then the page on the end of the chain is reused. If the
|
||||||
|
* page is found, or reused, then it is moved to the front of the chain.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static cache_entry_t *update_cache( int page_number )
|
||||||
|
{
|
||||||
|
cache_entry_t *cachep, *lastp;
|
||||||
|
|
||||||
|
/* Search the cache chain for the page */
|
||||||
|
|
||||||
|
for ( lastp = cache, cachep = cache;
|
||||||
|
cachep->flink != NULL && cachep->page_number && cachep->page_number != page_number;
|
||||||
|
lastp = cachep, cachep = cachep->flink )
|
||||||
|
;
|
||||||
|
|
||||||
|
/* If no page in chain then read it from disk */
|
||||||
|
|
||||||
|
if ( cachep->page_number != page_number )
|
||||||
|
{
|
||||||
|
/* Reusing last cache page, so invalidate cache if page was in use */
|
||||||
|
if ( cachep->flink == NULL && cachep->page_number )
|
||||||
|
{
|
||||||
|
if ( current_code_page == ( unsigned int ) cachep->page_number )
|
||||||
|
{
|
||||||
|
current_code_page = 0;
|
||||||
|
}
|
||||||
|
if ( current_data_page == ( unsigned int ) cachep->page_number )
|
||||||
|
{
|
||||||
|
current_data_page = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Load the new page number and the page contents from disk */
|
||||||
|
|
||||||
|
cachep->page_number = page_number;
|
||||||
|
read_page( page_number, cachep->data );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If page is not at front of cache chain then move it there */
|
||||||
|
|
||||||
|
if ( lastp != cache )
|
||||||
|
{
|
||||||
|
lastp->flink = cachep->flink;
|
||||||
|
cachep->flink = cache;
|
||||||
|
cache = cachep;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( cachep );
|
||||||
|
|
||||||
|
} /* update_cache */
|
454
object.c
Normal file
454
object.c
Normal file
|
@ -0,0 +1,454 @@
|
||||||
|
|
||||||
|
/* $Id: object.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: object.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: object.c,v $
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* object.c
|
||||||
|
*
|
||||||
|
* Object manipulation routines.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
#define PARENT 0
|
||||||
|
#define NEXT 1
|
||||||
|
#define CHILD 2
|
||||||
|
|
||||||
|
static zword_t read_object( zword_t objp, int field );
|
||||||
|
static void write_object( zword_t objp, int field, zword_t value );
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_object_address
|
||||||
|
*
|
||||||
|
* Calculate the address of an object in the data area.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
zword_t get_object_address( zword_t obj )
|
||||||
|
{
|
||||||
|
int offset;
|
||||||
|
|
||||||
|
/* Address calculation is object table base + size of default properties area +
|
||||||
|
* object number-1 * object size */
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
offset = h_objects_offset + ( ( P3_MAX_PROPERTIES - 1 ) * 2 ) + ( ( obj - 1 ) * O3_SIZE );
|
||||||
|
else
|
||||||
|
offset = h_objects_offset + ( ( P4_MAX_PROPERTIES - 1 ) * 2 ) + ( ( obj - 1 ) * O4_SIZE );
|
||||||
|
|
||||||
|
return ( ( zword_t ) offset );
|
||||||
|
|
||||||
|
} /* get_object_address */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_insert_obj
|
||||||
|
*
|
||||||
|
* Insert object 1 as the child of object 2 after first removing it from its
|
||||||
|
* previous parent. The object is inserted at the front of the child object
|
||||||
|
* chain.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_insert_obj( zword_t obj1, zword_t obj2 )
|
||||||
|
{
|
||||||
|
zword_t obj1p, obj2p, child2;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj1 == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_MOVE_OBJECT, "@insert_obj called moving object 0" );
|
||||||
|
}
|
||||||
|
if ( obj2 == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_MOVE_OBJECT_2, "@insert_obj called moving into object 0" );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* Get addresses of both objects */
|
||||||
|
|
||||||
|
obj1p = get_object_address( obj1 );
|
||||||
|
obj2p = get_object_address( obj2 );
|
||||||
|
|
||||||
|
/* Remove object 1 from current parent */
|
||||||
|
|
||||||
|
z_remove_obj( obj1 );
|
||||||
|
|
||||||
|
/* Make object 2 object 1's parent */
|
||||||
|
|
||||||
|
write_object( obj1p, PARENT, obj2 );
|
||||||
|
|
||||||
|
/* Get current first child of object 2 */
|
||||||
|
|
||||||
|
child2 = read_object( obj2p, CHILD );
|
||||||
|
|
||||||
|
/* Make object 1 first child of object 2 */
|
||||||
|
|
||||||
|
write_object( obj2p, CHILD, obj1 );
|
||||||
|
|
||||||
|
/* If object 2 had children then link them into the next child field of object 1 */
|
||||||
|
|
||||||
|
if ( child2 )
|
||||||
|
write_object( obj1p, NEXT, child2 );
|
||||||
|
|
||||||
|
} /* z_insert_obj */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_remove_obj
|
||||||
|
*
|
||||||
|
* Remove an object by unlinking from the its parent object and from its
|
||||||
|
* siblings.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_remove_obj( zword_t obj )
|
||||||
|
{
|
||||||
|
zword_t objp, parentp, childp, parent, child;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_REMOVE_OBJECT, "@remove_obj called with object 0" );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Get address of object to be removed */
|
||||||
|
|
||||||
|
objp = get_object_address( obj );
|
||||||
|
|
||||||
|
/* Get parent of object, and return if no parent */
|
||||||
|
|
||||||
|
if ( ( parent = read_object( objp, PARENT ) ) == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Get address of parent object */
|
||||||
|
|
||||||
|
parentp = get_object_address( parent );
|
||||||
|
|
||||||
|
/* Find first child of parent */
|
||||||
|
|
||||||
|
child = read_object( parentp, CHILD );
|
||||||
|
|
||||||
|
/* If object is first child then just make the parent child pointer
|
||||||
|
* equal to the next child */
|
||||||
|
|
||||||
|
if ( child == obj )
|
||||||
|
write_object( parentp, CHILD, read_object( objp, NEXT ) );
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Walk down the child chain looking for this object */
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
childp = get_object_address( child );
|
||||||
|
child = read_object( childp, NEXT );
|
||||||
|
}
|
||||||
|
while ( child != obj );
|
||||||
|
|
||||||
|
/* Set the next pointer thre previous child to the next pointer
|
||||||
|
* of the current object child pointer */
|
||||||
|
|
||||||
|
write_object( childp, NEXT, read_object( objp, NEXT ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Set the parent and next child pointers to NULL */
|
||||||
|
|
||||||
|
write_object( objp, PARENT, 0 );
|
||||||
|
write_object( objp, NEXT, 0 );
|
||||||
|
|
||||||
|
} /* z_remove_obj */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_get_parent
|
||||||
|
*
|
||||||
|
* Load the parent object pointer of an object
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_get_parent( zword_t obj )
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_GET_PARENT, "@get_parent called with object 0" );
|
||||||
|
store_operand( 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
store_operand( read_object( get_object_address( obj ), PARENT ) );
|
||||||
|
|
||||||
|
} /* z_get_parent */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_get_child
|
||||||
|
*
|
||||||
|
* Load the child object pointer of an object and jump if the child pointer is
|
||||||
|
* not NULL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_get_child( zword_t obj )
|
||||||
|
{
|
||||||
|
zword_t child;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_GET_CHILD, "@get_child called with object 0" );
|
||||||
|
store_operand( 0 );
|
||||||
|
conditional_jump( FALSE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
child = read_object( get_object_address( obj ), CHILD );
|
||||||
|
|
||||||
|
store_operand( child );
|
||||||
|
|
||||||
|
conditional_jump( child != 0 );
|
||||||
|
|
||||||
|
} /* z_get_child */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_get_sibling
|
||||||
|
*
|
||||||
|
* Load the next child object pointer of an object and jump if the next child
|
||||||
|
* pointer is not NULL.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_get_sibling( zword_t obj )
|
||||||
|
{
|
||||||
|
zword_t next;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_GET_SIBLING, "@get_sibling called with object 0" );
|
||||||
|
store_operand( 0 );
|
||||||
|
conditional_jump( FALSE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
next = read_object( get_object_address( obj ), NEXT );
|
||||||
|
|
||||||
|
store_operand( next );
|
||||||
|
|
||||||
|
conditional_jump( next != 0 );
|
||||||
|
|
||||||
|
} /* z_get_sibling */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_jin
|
||||||
|
*
|
||||||
|
* Jump if object 2 is the parent of object 1
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_jin( zword_t obj1, zword_t obj2 )
|
||||||
|
{
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj1 == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_JIN, "@jin called with object 0" );
|
||||||
|
conditional_jump( 0 == obj2 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
conditional_jump( read_object( get_object_address( obj1 ), PARENT ) == obj2 );
|
||||||
|
|
||||||
|
} /* z_jin */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_test_attr
|
||||||
|
*
|
||||||
|
* Test if an attribute bit is set.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_test_attr( zword_t obj, zword_t bit )
|
||||||
|
{
|
||||||
|
zword_t objp;
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
assert( O3_ATTRIBUTES == O4_ATTRIBUTES );
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_TEST_ATTR, "@test_attr called with object 0" );
|
||||||
|
conditional_jump( FALSE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Get attribute address */
|
||||||
|
|
||||||
|
objp = get_object_address( obj ) + ( bit >> 3 );
|
||||||
|
|
||||||
|
/* Load attribute byte */
|
||||||
|
|
||||||
|
value = get_byte( objp );
|
||||||
|
|
||||||
|
/* Test attribute */
|
||||||
|
|
||||||
|
conditional_jump( ( value >> ( 7 - ( bit & 7 ) ) ) & 1 );
|
||||||
|
|
||||||
|
} /* z_test_attr */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_set_attr
|
||||||
|
*
|
||||||
|
* Set an attribute bit.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_set_attr( zword_t obj, zword_t bit )
|
||||||
|
{
|
||||||
|
zword_t objp;
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
assert( O3_ATTRIBUTES == O4_ATTRIBUTES );
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_SET_ATTR, "@set_attr called with object 0" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Get attribute address */
|
||||||
|
|
||||||
|
objp = get_object_address( obj ) + ( bit >> 3 );
|
||||||
|
|
||||||
|
/* Load attribute byte */
|
||||||
|
|
||||||
|
value = get_byte( objp );
|
||||||
|
|
||||||
|
/* Set attribute bit */
|
||||||
|
|
||||||
|
value |= ( zbyte_t ) ( 1 << ( 7 - ( bit & 7 ) ) );
|
||||||
|
|
||||||
|
/* Store attribute byte */
|
||||||
|
|
||||||
|
set_byte( objp, value );
|
||||||
|
|
||||||
|
} /* z_set_attr */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_clear_attr
|
||||||
|
*
|
||||||
|
* Clear an attribute bit
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_clear_attr( zword_t obj, zword_t bit )
|
||||||
|
{
|
||||||
|
zword_t objp;
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
assert( O3_ATTRIBUTES == O4_ATTRIBUTES );
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_CLEAR_ATTR, "@clear_attr called with object 0" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Get attribute address */
|
||||||
|
|
||||||
|
objp = get_object_address( obj ) + ( bit >> 3 );
|
||||||
|
|
||||||
|
/* Load attribute byte */
|
||||||
|
|
||||||
|
value = get_byte( objp );
|
||||||
|
|
||||||
|
/* Clear attribute bit */
|
||||||
|
|
||||||
|
value &= ( zbyte_t ) ~ ( 1 << ( 7 - ( bit & 7 ) ) );
|
||||||
|
|
||||||
|
/* Store attribute byte */
|
||||||
|
|
||||||
|
set_byte( objp, value );
|
||||||
|
|
||||||
|
} /* z_clear_attr */
|
||||||
|
|
||||||
|
static zword_t read_object( zword_t objp, int field )
|
||||||
|
{
|
||||||
|
zword_t value;
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
{
|
||||||
|
if ( field == PARENT )
|
||||||
|
value = ( zword_t ) get_byte( PARENT3( objp ) );
|
||||||
|
else if ( field == NEXT )
|
||||||
|
value = ( zword_t ) get_byte( NEXT3( objp ) );
|
||||||
|
else
|
||||||
|
value = ( zword_t ) get_byte( CHILD3( objp ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( field == PARENT )
|
||||||
|
value = get_word( PARENT4( objp ) );
|
||||||
|
else if ( field == NEXT )
|
||||||
|
value = get_word( NEXT4( objp ) );
|
||||||
|
else
|
||||||
|
value = get_word( CHILD4( objp ) );
|
||||||
|
}
|
||||||
|
|
||||||
|
return ( value );
|
||||||
|
|
||||||
|
} /* read_object */
|
||||||
|
|
||||||
|
static void write_object( zword_t objp, int field, zword_t value )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
{
|
||||||
|
if ( field == PARENT )
|
||||||
|
set_byte( PARENT3( objp ), value );
|
||||||
|
else if ( field == NEXT )
|
||||||
|
set_byte( NEXT3( objp ), value );
|
||||||
|
else
|
||||||
|
set_byte( CHILD3( objp ), value );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if ( field == PARENT )
|
||||||
|
set_word( PARENT4( objp ), value );
|
||||||
|
else if ( field == NEXT )
|
||||||
|
set_word( NEXT4( objp ), value );
|
||||||
|
else
|
||||||
|
set_word( CHILD4( objp ), value );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* write_object */
|
234
operand.c
Normal file
234
operand.c
Normal file
|
@ -0,0 +1,234 @@
|
||||||
|
|
||||||
|
/* $Id: operand.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: operand.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: operand.c,v $
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* operand.c
|
||||||
|
*
|
||||||
|
* Operand manipulation routines
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load_operand
|
||||||
|
*
|
||||||
|
* Load an operand, either: a variable, popped from the stack or a literal.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
zword_t load_operand( int type )
|
||||||
|
{
|
||||||
|
zword_t operand;
|
||||||
|
|
||||||
|
if ( type )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Type 1: byte literal, or type 2: operand specifier */
|
||||||
|
|
||||||
|
operand = ( zword_t ) read_code_byte( );
|
||||||
|
if ( type == 2 )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If operand specifier non-zero then it's a variable, otherwise
|
||||||
|
* it's the top of the stack */
|
||||||
|
|
||||||
|
if ( operand )
|
||||||
|
{
|
||||||
|
return load_variable( operand );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return stack[sp++];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* Type 0: word literal */
|
||||||
|
return read_code_word( );
|
||||||
|
}
|
||||||
|
return ( operand );
|
||||||
|
|
||||||
|
} /* load_operand */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* store_operand
|
||||||
|
*
|
||||||
|
* Store an operand, either as a variable pushed on the stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void store_operand( zword_t operand )
|
||||||
|
{
|
||||||
|
zbyte_t specifier;
|
||||||
|
|
||||||
|
/* Read operand specifier byte */
|
||||||
|
|
||||||
|
specifier = read_code_byte( );
|
||||||
|
|
||||||
|
/* If operand specifier non-zero then it's a variable, otherwise it's the
|
||||||
|
* pushed on the stack */
|
||||||
|
|
||||||
|
if ( specifier )
|
||||||
|
z_store( specifier, operand );
|
||||||
|
else
|
||||||
|
stack[--sp] = operand;
|
||||||
|
|
||||||
|
} /* store_operand */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* load_variable
|
||||||
|
*
|
||||||
|
* Load a variable, either: a stack local variable, a global variable or
|
||||||
|
* the top of the stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
zword_t load_variable( int number )
|
||||||
|
{
|
||||||
|
if ( number )
|
||||||
|
{
|
||||||
|
if ( number < 16 )
|
||||||
|
{
|
||||||
|
/* number in range 1 - 15, it's a stack local variable */
|
||||||
|
return stack[fp - ( number - 1 )];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* number > 15, it's a global variable */
|
||||||
|
return get_word( h_globals_offset + ( ( number - 16 ) * 2 ) );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* number = 0, get from top of stack */
|
||||||
|
return stack[sp];
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* load_variable */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_store
|
||||||
|
*
|
||||||
|
* Store a variable, either: a stack local variable, a global variable or the
|
||||||
|
* top of the stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_store( int number, zword_t variable )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( number )
|
||||||
|
{
|
||||||
|
if ( number < 16 )
|
||||||
|
|
||||||
|
/* number in range 1 - 15, it's a stack local variable */
|
||||||
|
|
||||||
|
stack[fp - ( number - 1 )] = variable;
|
||||||
|
else
|
||||||
|
/* number > 15, it's a global variable */
|
||||||
|
|
||||||
|
set_word( h_globals_offset + ( ( number - 16 ) * 2 ), variable );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* number = 0, get from top of stack */
|
||||||
|
|
||||||
|
stack[sp] = variable;
|
||||||
|
|
||||||
|
} /* z_store */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_piracy
|
||||||
|
*
|
||||||
|
* Supposed to jump if the game thinks that it is pirated.
|
||||||
|
*/
|
||||||
|
void z_piracy( int flag )
|
||||||
|
{
|
||||||
|
conditional_jump( flag );
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* conditional_jump
|
||||||
|
*
|
||||||
|
* Take a jump after an instruction based on the flag, either true or false. The
|
||||||
|
* jump can be modified by the change logic flag. Normally jumps are taken
|
||||||
|
* when the flag is true. When the change logic flag is set then the jump is
|
||||||
|
* taken when flag is false. A PC relative jump can also be taken. This jump can
|
||||||
|
* either be a positive or negative byte or word range jump. An additional
|
||||||
|
* feature is the return option. If the jump offset is zero or one then that
|
||||||
|
* literal value is passed to the return instruction, instead of a jump being
|
||||||
|
* taken. Complicated or what!
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void conditional_jump( int flag )
|
||||||
|
{
|
||||||
|
zbyte_t specifier;
|
||||||
|
zword_t offset;
|
||||||
|
|
||||||
|
/* Read the specifier byte */
|
||||||
|
|
||||||
|
specifier = read_code_byte( );
|
||||||
|
|
||||||
|
/* If the reverse logic flag is set then reverse the flag */
|
||||||
|
|
||||||
|
if ( specifier & 0x80 )
|
||||||
|
flag = ( flag ) ? 0 : 1;
|
||||||
|
|
||||||
|
/* Jump offset is in bottom 6 bits */
|
||||||
|
|
||||||
|
offset = ( zword_t ) specifier & 0x3f;
|
||||||
|
|
||||||
|
/* If the byte range jump flag is not set then load another offset byte */
|
||||||
|
|
||||||
|
if ( ( specifier & 0x40 ) == 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Add extra offset byte to existing shifted offset */
|
||||||
|
|
||||||
|
offset = ( offset << 8 ) + read_code_byte( );
|
||||||
|
|
||||||
|
/* If top bit of offset is set then propogate the sign bit */
|
||||||
|
|
||||||
|
if ( offset & 0x2000 )
|
||||||
|
offset |= 0xc000;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the flag is false then do the jump */
|
||||||
|
|
||||||
|
if ( flag == 0 )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If offset equals 0 or 1 return that value instead */
|
||||||
|
|
||||||
|
if ( offset == 0 || offset == 1 )
|
||||||
|
{
|
||||||
|
z_ret( offset );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{ /* Add offset to PC */
|
||||||
|
pc = ( unsigned long ) ( pc + ( ZINT16 ) offset - 2 );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} /* conditional_jump */
|
525
osdepend.c
Normal file
525
osdepend.c
Normal file
|
@ -0,0 +1,525 @@
|
||||||
|
|
||||||
|
/* $Id: osdepend.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: osdepend.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: osdepend.c,v $
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* osdepend.c
|
||||||
|
*
|
||||||
|
* All non screen specific operating system dependent routines.
|
||||||
|
*
|
||||||
|
* Olaf Barthel 28-Jul-1992
|
||||||
|
* Modified John Holder(j-holder@home.com) 25-July-1995
|
||||||
|
* Support for standalone storyfiles by Magnu Olsson (mol@df.lth.se) Nov.1995
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
//#include "jzexe.h"
|
||||||
|
|
||||||
|
/* File names will be O/S dependent */
|
||||||
|
|
||||||
|
#if defined(AMIGA)
|
||||||
|
#define SAVE_NAME "Story.Save" /* Default save name */
|
||||||
|
#define SCRIPT_NAME "PRT:" /* Default script name */
|
||||||
|
#define RECORD_NAME "Story.Record" /* Default record name */
|
||||||
|
#define AUXILARY_NAME "Story.Aux" /* Default auxilary name */
|
||||||
|
#else /* defined(AMIGA) */
|
||||||
|
#define SAVE_NAME "story.sav" /* Default save name */
|
||||||
|
#define SCRIPT_NAME "story.scr" /* Default script name */
|
||||||
|
#define RECORD_NAME "story.rec" /* Default record name */
|
||||||
|
#define AUXILARY_NAME "story.aux" /* Default auxilary name */
|
||||||
|
#endif /* defined(AMIGA) */
|
||||||
|
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
|
||||||
|
/* Define stuff for stricter Z-code error checking, for the generic
|
||||||
|
* Unix/DOS/etc terminal-window interface. Feel free to change the way
|
||||||
|
* player prefs are specified, or replace report_zstrict_error()
|
||||||
|
* completely if you want to change the way errors are reported.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* There are four error reporting modes: never report errors;
|
||||||
|
* report only the first time a given error type occurs; report
|
||||||
|
* every time an error occurs; or treat all errors as fatal
|
||||||
|
* errors, killing the interpreter. I strongly recommend
|
||||||
|
* "report once" as the default. But you can compile in a
|
||||||
|
* different default by changing the definition of
|
||||||
|
* STRICTZ_DEFAULT_REPORT_MODE. In any case, the player can
|
||||||
|
* specify a report mode on the command line by typing "-s 0"
|
||||||
|
* through "-s 3".
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define STRICTZ_REPORT_NEVER (0)
|
||||||
|
#define STRICTZ_REPORT_ONCE (1)
|
||||||
|
#define STRICTZ_REPORT_ALWAYS (2)
|
||||||
|
#define STRICTZ_REPORT_FATAL (3)
|
||||||
|
|
||||||
|
#define STRICTZ_DEFAULT_REPORT_MODE STRICTZ_REPORT_NEVER
|
||||||
|
|
||||||
|
static int strictz_report_mode;
|
||||||
|
static int strictz_error_count[STRICTZ_NUM_ERRORS];
|
||||||
|
|
||||||
|
#endif /* STRICTZ */
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(AMIGA)
|
||||||
|
|
||||||
|
/* getopt linkages */
|
||||||
|
|
||||||
|
extern int optind;
|
||||||
|
extern const char *optarg;
|
||||||
|
extern ZINT16 default_fg, default_bg;
|
||||||
|
|
||||||
|
#endif /* !defined(AMIGA) */
|
||||||
|
|
||||||
|
|
||||||
|
#if defined OS2 || defined __MSDOS__
|
||||||
|
int iPalette;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(AMIGA)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* file_cleanup
|
||||||
|
*
|
||||||
|
* Perform actions when a file is successfully closed. Flag can be one of:
|
||||||
|
* GAME_SAVE, GAME_RESTORE, GAME_SCRIPT.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void file_cleanup( const char *file_name, int flag )
|
||||||
|
{
|
||||||
|
UNUSEDVAR( file_name );
|
||||||
|
UNUSEDVAR( flag );
|
||||||
|
} /* file_cleanup */
|
||||||
|
|
||||||
|
#endif /* !defined(AMIGA) */
|
||||||
|
|
||||||
|
#if !defined(AMIGA)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* sound
|
||||||
|
*
|
||||||
|
* Play a sound file or a note.
|
||||||
|
*
|
||||||
|
* argc = 1: argv[0] = note# (range 1 - 3)
|
||||||
|
*
|
||||||
|
* Play note.
|
||||||
|
*
|
||||||
|
* argc = 2: argv[0] = 0
|
||||||
|
* argv[1] = 3
|
||||||
|
*
|
||||||
|
* Stop playing current sound.
|
||||||
|
*
|
||||||
|
* argc = 2: argv[0] = 0
|
||||||
|
* argv[1] = 4
|
||||||
|
*
|
||||||
|
* Free allocated resources.
|
||||||
|
*
|
||||||
|
* argc = 3: argv[0] = ID# of sound file to replay.
|
||||||
|
* argv[1] = 2
|
||||||
|
* argv[2] = Volume to replay sound with, this value
|
||||||
|
* can range between 1 and 8.
|
||||||
|
*
|
||||||
|
* argc = 4: argv[0] = ID# of sound file to replay.
|
||||||
|
* argv[1] = 2
|
||||||
|
* argv[2] = Control information
|
||||||
|
* argv[3] = Volume information
|
||||||
|
*
|
||||||
|
* Volume information:
|
||||||
|
*
|
||||||
|
* 0x34FB -> Fade sound in
|
||||||
|
* 0x3507 -> Fade sound out
|
||||||
|
* other -> Replay sound at maximum volume
|
||||||
|
*
|
||||||
|
* Control information:
|
||||||
|
*
|
||||||
|
* This word is divided into two bytes,
|
||||||
|
* the upper byte determines the number of
|
||||||
|
* cycles to play the sound (e.g. how many
|
||||||
|
* times a clock chimes or a dog barks).
|
||||||
|
* The meaning of the lower byte is yet to
|
||||||
|
* be discovered :)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void sound( int argc, zword_t * argv )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Supply default parameters */
|
||||||
|
|
||||||
|
if ( argc < 4 )
|
||||||
|
argv[3] = 0;
|
||||||
|
if ( argc < 3 )
|
||||||
|
argv[2] = 0xff;
|
||||||
|
if ( argc < 2 )
|
||||||
|
argv[1] = 2;
|
||||||
|
|
||||||
|
/* Generic bell sounder */
|
||||||
|
|
||||||
|
if ( argc == 1 || argv[1] == 2 )
|
||||||
|
display_char( '\007' );
|
||||||
|
|
||||||
|
} /* sound */
|
||||||
|
|
||||||
|
#endif /* !defined(AMIGA) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_file_name
|
||||||
|
*
|
||||||
|
* Return the name of a file. Flag can be one of:
|
||||||
|
* GAME_SAVE - Save file (write only)
|
||||||
|
* GAME_RESTORE - Save file (read only)
|
||||||
|
* GAME_SCRIPT - Script file (write only)
|
||||||
|
* GAME_RECORD - Keystroke record file (write only)
|
||||||
|
* GAME_PLABACK - Keystroke record file (read only)
|
||||||
|
* GAME_SAVE_AUX - Auxilary (preferred settings) file (write only)
|
||||||
|
* GAME_LOAD_AUX - Auxilary (preferred settings) file (read only)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int get_file_name( char *file_name, char *default_name, int flag )
|
||||||
|
{
|
||||||
|
char buffer[127 + 2]; /* 127 is the biggest positive char */
|
||||||
|
int status = 0;
|
||||||
|
|
||||||
|
/* If no default file name then supply the standard name */
|
||||||
|
|
||||||
|
if ( default_name[0] == '\0' )
|
||||||
|
{
|
||||||
|
if ( flag == GAME_SCRIPT )
|
||||||
|
strcpy( default_name, SCRIPT_NAME );
|
||||||
|
else if ( flag == GAME_RECORD || flag == GAME_PLAYBACK )
|
||||||
|
strcpy( default_name, RECORD_NAME );
|
||||||
|
else if ( flag == GAME_SAVE_AUX || GAME_LOAD_AUX )
|
||||||
|
strcpy( default_name, AUXILARY_NAME );
|
||||||
|
else /* (flag == GAME_SAVE || flag == GAME_RESTORE) */
|
||||||
|
strcpy( default_name, SAVE_NAME );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Prompt for the file name */
|
||||||
|
|
||||||
|
output_line( "Enter a file name." );
|
||||||
|
output_string( "(Default is \"" );
|
||||||
|
output_string( default_name );
|
||||||
|
output_string( "\"): " );
|
||||||
|
|
||||||
|
buffer[0] = 127;
|
||||||
|
buffer[1] = 0;
|
||||||
|
( void ) get_line( buffer, 0, 0 );
|
||||||
|
|
||||||
|
/* Copy file name from the input buffer */
|
||||||
|
|
||||||
|
if ( h_type > V4 )
|
||||||
|
{
|
||||||
|
unsigned char len = buffer[1];
|
||||||
|
|
||||||
|
memcpy( file_name, &buffer[2], len );
|
||||||
|
file_name[len] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
strcpy( file_name, &buffer[1] );
|
||||||
|
|
||||||
|
/* If nothing typed then use the default name */
|
||||||
|
|
||||||
|
if ( file_name[0] == '\0' )
|
||||||
|
strcpy( file_name, default_name );
|
||||||
|
|
||||||
|
#if !defined(VMS) /* VMS has file version numbers, so cannot overwrite */
|
||||||
|
|
||||||
|
/* Check if we are going to overwrite the file */
|
||||||
|
|
||||||
|
if ( flag == GAME_SAVE || flag == GAME_SCRIPT || flag == GAME_RECORD || flag == GAME_SAVE_AUX )
|
||||||
|
{
|
||||||
|
FILE *tfp;
|
||||||
|
|
||||||
|
#if defined BUFFER_FILES
|
||||||
|
char tfpbuffer[BUFSIZ];
|
||||||
|
#endif
|
||||||
|
char c;
|
||||||
|
|
||||||
|
/* Try to access the file */
|
||||||
|
|
||||||
|
tfp = fopen( file_name, "r" );
|
||||||
|
if ( tfp != NULL )
|
||||||
|
{
|
||||||
|
/* If it succeeded then prompt to overwrite */
|
||||||
|
|
||||||
|
#if defined BUFFER_FILES
|
||||||
|
setbuf( tfp, tfpbuffer );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
output_line( "You are about to write over an existing file." );
|
||||||
|
output_string( "Proceed? (Y/N) " );
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
c = ( char ) input_character( 0 );
|
||||||
|
c = ( char ) toupper( c );
|
||||||
|
}
|
||||||
|
while ( c != 'Y' && c != 'N' );
|
||||||
|
|
||||||
|
output_char( c );
|
||||||
|
output_new_line( );
|
||||||
|
|
||||||
|
/* If no overwrite then fail the routine */
|
||||||
|
|
||||||
|
if ( c == 'N' )
|
||||||
|
status = 1;
|
||||||
|
|
||||||
|
fclose( tfp );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif /* !defined(VMS) */
|
||||||
|
|
||||||
|
/* Record the file name if it was OK */
|
||||||
|
|
||||||
|
if ( status == 0 )
|
||||||
|
record_line( file_name );
|
||||||
|
|
||||||
|
return ( status );
|
||||||
|
|
||||||
|
} /* get_file_name */
|
||||||
|
|
||||||
|
#if !defined(AMIGA)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fatal
|
||||||
|
*
|
||||||
|
* Display message and stop interpreter.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void fatal( const char *s )
|
||||||
|
{
|
||||||
|
|
||||||
|
reset_screen( );
|
||||||
|
fprintf( stderr, "\nFatal error: %s (PC = 0x%08lX)\n", s, pc );
|
||||||
|
#ifdef DEBUG_TERPRE
|
||||||
|
fprintf( stdout, "\nFatal error: %s (PC = 0x%08lX)\n", s, pc );
|
||||||
|
#endif
|
||||||
|
exit( 1 );
|
||||||
|
|
||||||
|
} /* fatal */
|
||||||
|
|
||||||
|
#endif /* !defined(AMIGA) */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* report_strictz_error
|
||||||
|
*
|
||||||
|
* This handles Z-code error conditions which ought to be fatal errors,
|
||||||
|
* but which players might want to ignore for the sake of finishing the
|
||||||
|
* game.
|
||||||
|
*
|
||||||
|
* The error is provided as both a numeric code and a string. This allows
|
||||||
|
* us to print a warning the first time a particular error occurs, and
|
||||||
|
* ignore it thereafter.
|
||||||
|
*
|
||||||
|
* errnum : Numeric code for error (0 to STRICTZ_NUM_ERRORS-1)
|
||||||
|
* errstr : Text description of error
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
|
||||||
|
void report_strictz_error( int errnum, const char *errstr )
|
||||||
|
{
|
||||||
|
int wasfirst;
|
||||||
|
char buf[256] = { 0 };
|
||||||
|
|
||||||
|
if ( errnum <= 0 || errnum >= STRICTZ_NUM_ERRORS )
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ( strictz_report_mode == STRICTZ_REPORT_FATAL )
|
||||||
|
{
|
||||||
|
sprintf( buf, "STRICTZ: %s (PC = %lx)", errstr, pc );
|
||||||
|
fatal( buf );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasfirst = ( strictz_error_count[errnum] == 0 );
|
||||||
|
strictz_error_count[errnum]++;
|
||||||
|
|
||||||
|
if ( ( strictz_report_mode == STRICTZ_REPORT_ALWAYS ) ||
|
||||||
|
( strictz_report_mode == STRICTZ_REPORT_ONCE && wasfirst ) )
|
||||||
|
{
|
||||||
|
sprintf( buf, "STRICTZ Warning: %s (PC = %lx)", errstr, pc );
|
||||||
|
write_string( buf );
|
||||||
|
|
||||||
|
if ( strictz_report_mode == STRICTZ_REPORT_ONCE )
|
||||||
|
{
|
||||||
|
write_string( " (will ignore further occurrences)" );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
sprintf( buf, " (occurrence %d)", strictz_error_count[errnum] );
|
||||||
|
write_string( buf );
|
||||||
|
}
|
||||||
|
z_new_line( );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* report_strictz_error */
|
||||||
|
|
||||||
|
#endif /* STRICTZ */
|
||||||
|
|
||||||
|
|
||||||
|
#if !defined(AMIGA)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* fit_line
|
||||||
|
*
|
||||||
|
* This routine determines whether a line of text will still fit
|
||||||
|
* on the screen.
|
||||||
|
*
|
||||||
|
* line : Line of text to test.
|
||||||
|
* pos : Length of text line (in characters).
|
||||||
|
* max : Maximum number of characters to fit on the screen.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
int fit_line( const char *line_buffer, int pos, int max )
|
||||||
|
{
|
||||||
|
UNUSEDVAR( line_buffer );
|
||||||
|
|
||||||
|
return ( pos < max );
|
||||||
|
} /* fit_line */
|
||||||
|
|
||||||
|
#endif /* !defined(AMIGA) */
|
||||||
|
|
||||||
|
#if !defined(AMIGA)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print_status
|
||||||
|
*
|
||||||
|
* Print the status line (type 3 games only).
|
||||||
|
*
|
||||||
|
* argv[0] : Location name
|
||||||
|
* argv[1] : Moves/Time
|
||||||
|
* argv[2] : Score
|
||||||
|
*
|
||||||
|
* Depending on how many arguments are passed to this routine
|
||||||
|
* it is to print the status line. The rendering attributes
|
||||||
|
* and the status line window will be have been activated
|
||||||
|
* when this routine is called. It is to return FALSE if it
|
||||||
|
* cannot render the status line in which case the interpreter
|
||||||
|
* will use display_char() to render it on its own.
|
||||||
|
*
|
||||||
|
* This routine has been provided in order to support
|
||||||
|
* proportional-spaced fonts.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int print_status( int argc, char *argv[] )
|
||||||
|
{
|
||||||
|
UNUSEDVAR( argc );
|
||||||
|
UNUSEDVAR( argv );
|
||||||
|
|
||||||
|
return ( FALSE );
|
||||||
|
} /* print_status */
|
||||||
|
|
||||||
|
#endif /* !defined(AMIGA) */
|
||||||
|
|
||||||
|
#if !defined(AMIGA)
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set_font
|
||||||
|
*
|
||||||
|
* Set a new character font. Font can be either be:
|
||||||
|
*
|
||||||
|
* TEXT_FONT (1) = normal text character font
|
||||||
|
* GRAPHICS_FONT (3) = graphical character font
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void set_font( int font_type )
|
||||||
|
{
|
||||||
|
UNUSEDVAR( font_type );
|
||||||
|
} /* set_font */
|
||||||
|
|
||||||
|
#endif /* !defined(AMIGA) */
|
||||||
|
|
||||||
|
#if !defined MSDOS && !defined OS2 && !defined AMIGA && !defined HARD_COLORS && !defined ATARIST
|
||||||
|
|
||||||
|
/*
|
||||||
|
* set_colours
|
||||||
|
*
|
||||||
|
* Sets screen foreground and background colours.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void set_colours( zword_t foreground, zword_t background )
|
||||||
|
{
|
||||||
|
|
||||||
|
} /* set_colours */
|
||||||
|
|
||||||
|
#endif /* !defined MSDOS && !defined OS2 && !defined AMIGA !defined HARD_COLORS && !defined ATARIST */
|
||||||
|
|
||||||
|
#if !defined VMS && !defined MSDOS && !defined OS2 && !defined POSIX
|
||||||
|
|
||||||
|
/*
|
||||||
|
* codes_to_text
|
||||||
|
*
|
||||||
|
* Translate Z-code characters to machine specific characters. These characters
|
||||||
|
* include line drawing characters and international characters.
|
||||||
|
*
|
||||||
|
* The routine takes one of the Z-code characters from the following table and
|
||||||
|
* writes the machine specific text replacement. The target replacement buffer
|
||||||
|
* is defined by MAX_TEXT_SIZE in ztypes.h. The replacement text should be in a
|
||||||
|
* normal C, zero terminated, string.
|
||||||
|
*
|
||||||
|
* Return 0 if a translation was available, otherwise 1.
|
||||||
|
*
|
||||||
|
* Arrow characters (0x18 - 0x1b):
|
||||||
|
*
|
||||||
|
* 0x18 Up arrow
|
||||||
|
* 0x19 Down arrow
|
||||||
|
* 0x1a Right arrow
|
||||||
|
* 0x1b Left arrow
|
||||||
|
*
|
||||||
|
* International characters (0x9b - 0xa3):
|
||||||
|
*
|
||||||
|
* 0x9b a umlaut (ae)
|
||||||
|
* 0x9c o umlaut (oe)
|
||||||
|
* 0x9d u umlaut (ue)
|
||||||
|
* 0x9e A umlaut (Ae)
|
||||||
|
* 0x9f O umlaut (Oe)
|
||||||
|
* 0xa0 U umlaut (Ue)
|
||||||
|
* 0xa1 sz (ss)
|
||||||
|
* 0xa2 open quote (>>)
|
||||||
|
* 0xa3 close quota (<<)
|
||||||
|
*
|
||||||
|
* Line drawing characters (0xb3 - 0xda):
|
||||||
|
*
|
||||||
|
* 0xb3 vertical line (|)
|
||||||
|
* 0xba double vertical line (#)
|
||||||
|
* 0xc4 horizontal line (-)
|
||||||
|
* 0xcd double horizontal line (=)
|
||||||
|
* all other are corner pieces (+)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
int codes_to_text( int c, char *s )
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
} /* codes_to_text */
|
||||||
|
|
||||||
|
#endif /* !defined VMS && !defined MSDOS && !defined OS2 && !defined POSIX */
|
583
property.c
Normal file
583
property.c
Normal file
|
@ -0,0 +1,583 @@
|
||||||
|
|
||||||
|
/* $Id: property.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: property.c,v 1.2 2000/05/25 22:28:56 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: property.c,v $
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* property.c
|
||||||
|
*
|
||||||
|
* Property manipulation routines
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_property_addr
|
||||||
|
*
|
||||||
|
* Calculate the address of the start of the property list associated with an
|
||||||
|
* object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static zword_t get_property_addr( zword_t obj )
|
||||||
|
{
|
||||||
|
zword_t object_addr;
|
||||||
|
zword_t prop_addr;
|
||||||
|
zbyte_t size;
|
||||||
|
|
||||||
|
/* Calculate the address of the property pointer in the object */
|
||||||
|
|
||||||
|
object_addr = get_object_address( obj );
|
||||||
|
object_addr += ( h_type <= V3 ) ? O3_PROPERTY_OFFSET : O4_PROPERTY_OFFSET;
|
||||||
|
|
||||||
|
/* Read the property address */
|
||||||
|
prop_addr = get_word( object_addr );
|
||||||
|
|
||||||
|
/* Skip past object description which is an ASCIC of encoded words */
|
||||||
|
size = get_byte( prop_addr );
|
||||||
|
|
||||||
|
return prop_addr + ( size * 2 ) + 1;
|
||||||
|
|
||||||
|
} /* get_property_addr */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* get_next_property
|
||||||
|
*
|
||||||
|
* Calculate the address of the next property in a property list.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static zword_t get_next_property( zword_t prop_addr )
|
||||||
|
{
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
/* Load the current property id */
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
prop_addr++;
|
||||||
|
|
||||||
|
/* Calculate the length of this property */
|
||||||
|
|
||||||
|
if ( h_type <= V3 )
|
||||||
|
value >>= 5;
|
||||||
|
else if ( !( value & 0x80 ) )
|
||||||
|
value >>= 6;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
value &= property_size_mask;
|
||||||
|
|
||||||
|
if ( value == 0 )
|
||||||
|
value = 64; /* spec 1.0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Address property length to current property pointer */
|
||||||
|
return prop_addr + value + 1;
|
||||||
|
|
||||||
|
} /* get_next_property */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_get_prop
|
||||||
|
*
|
||||||
|
* Load a property from a property list. Properties are held in list sorted by
|
||||||
|
* property id, with highest ids first. There is also a concept of a default
|
||||||
|
* property for loading only. The default properties are held in a table pointed
|
||||||
|
* to be the object pointer, and occupy the space before the first object.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_get_prop( zword_t obj, zword_t prop )
|
||||||
|
{
|
||||||
|
zword_t prop_addr;
|
||||||
|
zword_t wprop_val;
|
||||||
|
zbyte_t bprop_val;
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_GET_PROP, "@get_prop called with object 0" );
|
||||||
|
store_operand( 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Load address of first property */
|
||||||
|
prop_addr = get_property_addr( obj );
|
||||||
|
|
||||||
|
/* Scan down the property list */
|
||||||
|
for ( ;; )
|
||||||
|
{
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
if ( ( zbyte_t ) ( value & property_mask ) <= ( zbyte_t ) prop )
|
||||||
|
break;
|
||||||
|
prop_addr = get_next_property( prop_addr );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the property ids match then load the first property */
|
||||||
|
|
||||||
|
if ( ( zbyte_t ) ( value & property_mask ) == ( zbyte_t ) prop ) /* property found */
|
||||||
|
{
|
||||||
|
prop_addr++;
|
||||||
|
/* Only load first property if it is a byte sized property */
|
||||||
|
if ( h_type <= V3 && !( value & 0xe0 ) || h_type >= V4 && !( value & 0xc0 ) )
|
||||||
|
{
|
||||||
|
bprop_val = get_byte( prop_addr );
|
||||||
|
wprop_val = bprop_val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wprop_val = get_word( prop_addr );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else /* property not found */
|
||||||
|
{
|
||||||
|
/* Calculate the address of the default property */
|
||||||
|
prop_addr = h_objects_offset + ( ( prop - 1 ) * 2 );
|
||||||
|
wprop_val = get_word( prop_addr );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* store the property value */
|
||||||
|
|
||||||
|
store_operand( wprop_val );
|
||||||
|
|
||||||
|
} /* z_get_prop */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_put_prop
|
||||||
|
*
|
||||||
|
* Store a property value in a property list. The property must exist in the
|
||||||
|
* property list to be replaced.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_put_prop( zword_t obj, zword_t prop, zword_t setvalue )
|
||||||
|
{
|
||||||
|
zword_t prop_addr;
|
||||||
|
zword_t value;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_PUT_PROP, "@put_prop called with object 0" );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Load address of first property */
|
||||||
|
prop_addr = get_property_addr( obj );
|
||||||
|
|
||||||
|
/* Scan down the property list */
|
||||||
|
for ( ;; )
|
||||||
|
{
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
if ( ( value & property_mask ) <= prop )
|
||||||
|
break;
|
||||||
|
prop_addr = get_next_property( prop_addr );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the property id was found, store a new value, otherwise complain */
|
||||||
|
|
||||||
|
if ( ( value & property_mask ) != prop )
|
||||||
|
{
|
||||||
|
fatal( "store_property(): No such property" );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine if this is a byte or word sized property */
|
||||||
|
|
||||||
|
prop_addr++;
|
||||||
|
|
||||||
|
if ( h_type <= V3 && !( value & 0xe0 ) || h_type >= V4 && !( value & 0xc0 ) )
|
||||||
|
{
|
||||||
|
set_byte( prop_addr, ( zbyte_t ) setvalue );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
set_word( prop_addr, ( zword_t ) setvalue );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* z_put_prop */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_get_next_prop
|
||||||
|
*
|
||||||
|
* Load the property after the current property. If the current property is zero
|
||||||
|
* then load the first property.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_get_next_prop( zword_t obj, zword_t prop )
|
||||||
|
{
|
||||||
|
zword_t prop_addr;
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_GET_NEXT_PROP, "@get_next_prop called with object 0" );
|
||||||
|
store_operand( 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Load address of first property */
|
||||||
|
prop_addr = get_property_addr( obj );
|
||||||
|
|
||||||
|
/* If the property id is non zero then find the next property */
|
||||||
|
if ( prop != 0 )
|
||||||
|
{
|
||||||
|
/* Scan down the property list while the target property id is less
|
||||||
|
* than the property id in the list */
|
||||||
|
do
|
||||||
|
{
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
prop_addr = get_next_property( prop_addr );
|
||||||
|
}
|
||||||
|
while ( ( zbyte_t ) ( value & property_mask ) > ( zbyte_t ) prop );
|
||||||
|
|
||||||
|
/* If the property id wasn't found then complain */
|
||||||
|
if ( ( zbyte_t ) ( value & property_mask ) != ( zbyte_t ) prop )
|
||||||
|
{
|
||||||
|
fatal( "load_next_property(): No such property" );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Return the next property id */
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
store_operand( ( zword_t ) ( value & property_mask ) );
|
||||||
|
|
||||||
|
} /* z_get_next_prop */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_get_prop_addr
|
||||||
|
*
|
||||||
|
* Load the address address of the data associated with a property.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_get_prop_addr( zword_t obj, zword_t prop )
|
||||||
|
{
|
||||||
|
zword_t prop_addr;
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
if ( obj == 0 )
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_GET_PROP_ADDR, "@get_prop_addr called with object 0" );
|
||||||
|
store_operand( 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Load address of first property */
|
||||||
|
prop_addr = get_property_addr( obj );
|
||||||
|
|
||||||
|
/* Scan down the property list */
|
||||||
|
for ( ;; )
|
||||||
|
{
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
if ( ( zbyte_t ) ( value & property_mask ) <= ( zbyte_t ) prop )
|
||||||
|
break;
|
||||||
|
prop_addr = get_next_property( prop_addr );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the property id was found, calc the prop addr, else return zero */
|
||||||
|
|
||||||
|
if ( ( zbyte_t ) ( value & property_mask ) == ( zbyte_t ) prop )
|
||||||
|
{
|
||||||
|
/* Skip past property id, can be a byte or a word */
|
||||||
|
|
||||||
|
if ( h_type >= V4 && ( value & 0x80 ) )
|
||||||
|
{
|
||||||
|
prop_addr++;
|
||||||
|
}
|
||||||
|
store_operand( ( zword_t ) ( prop_addr + 1 ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* No property found, just return 0 */
|
||||||
|
store_operand( 0 );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* z_get_prop_addr */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_get_prop_len
|
||||||
|
*
|
||||||
|
* Load the length of a property.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_get_prop_len( zword_t prop_addr )
|
||||||
|
{
|
||||||
|
zbyte_t value;
|
||||||
|
|
||||||
|
/* This is proper according to an email to the Zmachine list by Graham*/
|
||||||
|
if ( prop_addr == 0 )
|
||||||
|
{
|
||||||
|
store_operand( ( zword_t ) 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Back up the property pointer to the property id */
|
||||||
|
prop_addr--;
|
||||||
|
value = get_byte( prop_addr );
|
||||||
|
|
||||||
|
if ( h_type <= V3 )
|
||||||
|
{
|
||||||
|
value = ( zbyte_t ) ( ( value >> ( zbyte_t ) 5 ) + ( zbyte_t ) 1 );
|
||||||
|
}
|
||||||
|
else if ( !( value & 0x80 ) )
|
||||||
|
{
|
||||||
|
value = ( zbyte_t ) ( ( value >> ( zbyte_t ) 6 ) + ( zbyte_t ) 1 );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value &= ( zbyte_t ) property_size_mask;
|
||||||
|
|
||||||
|
if ( value == 0 )
|
||||||
|
value = ( zbyte_t ) 64; /* spec 1.0 */
|
||||||
|
}
|
||||||
|
|
||||||
|
store_operand( value );
|
||||||
|
|
||||||
|
} /* z_get_prop_len */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_scan_table
|
||||||
|
*
|
||||||
|
* Scan an array of bytes or words looking for a target byte or word. The
|
||||||
|
* optional 4th parameter can set the address step and also whether to scan a
|
||||||
|
* byte array.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_scan_table( int argc, zword_t * argv )
|
||||||
|
{
|
||||||
|
unsigned long address;
|
||||||
|
unsigned int i, step;
|
||||||
|
|
||||||
|
/* Supply default parameters */
|
||||||
|
|
||||||
|
if ( argc < 4 )
|
||||||
|
argv[3] = 0x82;
|
||||||
|
|
||||||
|
address = argv[1];
|
||||||
|
step = argv[3];
|
||||||
|
|
||||||
|
/* Check size bit (bit 7 of step, 1 = word, 0 = byte) */
|
||||||
|
|
||||||
|
if ( step & 0x80 )
|
||||||
|
{
|
||||||
|
|
||||||
|
step &= 0x7f;
|
||||||
|
|
||||||
|
/* Scan down an array for count words looking for a match */
|
||||||
|
|
||||||
|
for ( i = 0; i < argv[2]; i++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If the word was found store its address and jump */
|
||||||
|
|
||||||
|
if ( read_data_word( &address ) == argv[0] )
|
||||||
|
{
|
||||||
|
store_operand( ( zword_t ) ( address - 2 ) );
|
||||||
|
conditional_jump( TRUE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Back up address then step by increment */
|
||||||
|
|
||||||
|
address = ( address - 2 ) + step;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
step &= 0x7f;
|
||||||
|
|
||||||
|
/* Scan down an array for count bytes looking for a match */
|
||||||
|
|
||||||
|
for ( i = 0; i < argv[2]; i++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If the byte was found store its address and jump */
|
||||||
|
|
||||||
|
if ( ( zword_t ) read_data_byte( &address ) == ( zword_t ) argv[0] )
|
||||||
|
{
|
||||||
|
store_operand( ( zword_t ) ( address - 1 ) );
|
||||||
|
conditional_jump( TRUE );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Back up address then step by increment */
|
||||||
|
|
||||||
|
address = ( address - 1 ) + step;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* If the data was not found store zero and jump */
|
||||||
|
|
||||||
|
store_operand( 0 );
|
||||||
|
conditional_jump( FALSE );
|
||||||
|
|
||||||
|
} /* z_scan_table */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_copy_table
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_copy_table( zword_t src, zword_t dst, zword_t count )
|
||||||
|
{
|
||||||
|
unsigned long address;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
/* Catch no-op move case */
|
||||||
|
|
||||||
|
if ( src == dst || count == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* If destination address is zero then fill source with zeros */
|
||||||
|
|
||||||
|
if ( dst == 0 )
|
||||||
|
{
|
||||||
|
for ( i = 0; i < count; i++ )
|
||||||
|
z_storeb( src++, 0, 0 );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
address = src;
|
||||||
|
|
||||||
|
if ( ( ZINT16 ) count < 0 )
|
||||||
|
{
|
||||||
|
while ( count++ )
|
||||||
|
z_storeb( dst++, 0, read_data_byte( &address ) );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
address += ( unsigned long ) count;
|
||||||
|
dst += count;
|
||||||
|
while ( count-- )
|
||||||
|
{
|
||||||
|
address--;
|
||||||
|
z_storeb( --dst, 0, read_data_byte( &address ) );
|
||||||
|
address--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* z_copy_table */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_loadw
|
||||||
|
*
|
||||||
|
* Load a word from an array of words
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_loadw( zword_t addr, zword_t offset )
|
||||||
|
{
|
||||||
|
unsigned long address;
|
||||||
|
|
||||||
|
/* Calculate word array index address */
|
||||||
|
|
||||||
|
address = addr + ( offset * 2 );
|
||||||
|
|
||||||
|
/* Store the byte */
|
||||||
|
|
||||||
|
store_operand( read_data_word( &address ) );
|
||||||
|
|
||||||
|
} /* z_loadw */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_loadb
|
||||||
|
*
|
||||||
|
* Load a byte from an array of bytes
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_loadb( zword_t addr, zword_t offset )
|
||||||
|
{
|
||||||
|
unsigned long address;
|
||||||
|
|
||||||
|
/* Calculate byte array index address */
|
||||||
|
|
||||||
|
address = addr + offset;
|
||||||
|
|
||||||
|
/* Load the byte */
|
||||||
|
|
||||||
|
store_operand( read_data_byte( &address ) );
|
||||||
|
|
||||||
|
} /* z_loadb */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_storew
|
||||||
|
*
|
||||||
|
* Store a word in an array of words
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_storew( zword_t addr, zword_t offset, zword_t value )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Calculate word array index address */
|
||||||
|
|
||||||
|
addr += offset * 2;
|
||||||
|
|
||||||
|
/* Check we are not writing outside of the writeable data area */
|
||||||
|
|
||||||
|
if ( addr > data_size )
|
||||||
|
fatal( "z_storew(): Attempted write outside of data area" );
|
||||||
|
|
||||||
|
/* Store the word */
|
||||||
|
|
||||||
|
set_word( addr, value );
|
||||||
|
|
||||||
|
} /* z_storew */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_storeb
|
||||||
|
*
|
||||||
|
* Store a byte in an array of bytes
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_storeb( zword_t addr, zword_t offset, zword_t value )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Calculate byte array index address */
|
||||||
|
|
||||||
|
addr += offset;
|
||||||
|
|
||||||
|
/* Check we are not writing outside of the writeable data area */
|
||||||
|
|
||||||
|
if ( addr > data_size )
|
||||||
|
fatal( "z_storeb(): Attempted write outside of data area" );
|
||||||
|
|
||||||
|
/* Store the byte */
|
||||||
|
|
||||||
|
set_byte( addr, value );
|
||||||
|
|
||||||
|
} /* z_storeb */
|
573
quetzal.c
Normal file
573
quetzal.c
Normal file
|
@ -0,0 +1,573 @@
|
||||||
|
|
||||||
|
/* $Id: quetzal.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: quetzal.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: quetzal.c,v $
|
||||||
|
* Revision 1.3 2000/07/05 15:20:34 jholder
|
||||||
|
* Updated code to remove warnings.
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* quetzal.c
|
||||||
|
*
|
||||||
|
* routines to handle QUETZAL save format
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/* You may want to define these as getc and putc, but then the code gets
|
||||||
|
* quite big (especially for put_c).
|
||||||
|
*/
|
||||||
|
#define get_c getc
|
||||||
|
#define put_c fputc
|
||||||
|
|
||||||
|
/* Some systems appear to have this in funny places, rather than in <stdio.h>
|
||||||
|
* where it should be.
|
||||||
|
*/
|
||||||
|
#ifndef SEEK_CUR
|
||||||
|
#define SEEK_CUR 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_QUETZAL) /* don't compile anything otherwise */
|
||||||
|
|
||||||
|
typedef unsigned long ul_t;
|
||||||
|
|
||||||
|
/* IDs of chunks we understand */
|
||||||
|
#define ID_FORM 0x464f524d
|
||||||
|
#define ID_IFZS 0x49465a53
|
||||||
|
#define ID_IFhd 0x49466864
|
||||||
|
#define ID_UMem 0x554d656d
|
||||||
|
#define ID_CMem 0x434d656d
|
||||||
|
#define ID_Stks 0x53746b73
|
||||||
|
#define ID_ANNO 0x414e4e4f
|
||||||
|
|
||||||
|
/* macros to write QUETZAL files */
|
||||||
|
#define write_byte(fp,b) (put_c ((unsigned)(b),fp) != EOF)
|
||||||
|
#define write_bytx(fp,b) write_byte(fp,(b) & 0xFF)
|
||||||
|
#define write_word(fp,w) \
|
||||||
|
(write_bytx(fp,(w)>> 8) && write_bytx(fp,(w)))
|
||||||
|
#define write_long(fp,l) \
|
||||||
|
(write_bytx(fp,(ul_t)(l)>>24) && write_bytx(fp,(ul_t)(l)>>16) && \
|
||||||
|
write_bytx(fp,(ul_t)(l)>> 8) && write_bytx(fp,(ul_t)(l)))
|
||||||
|
#define write_chnk(fp,id,len) \
|
||||||
|
(write_long(fp,id) && write_long(fp,len))
|
||||||
|
#define write_run(fp,run) \
|
||||||
|
(write_byte(fp,0) && write_byte(fp,(run)))
|
||||||
|
|
||||||
|
/* save_quetzal
|
||||||
|
*
|
||||||
|
* attempt to save game in QUETZAL format; return TRUE on success
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
int save_quetzal( FILE * sfp, gzFile * gfp )
|
||||||
|
#else
|
||||||
|
int save_quetzal( FILE * sfp, FILE * gfp )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ul_t ifzslen = 0, cmemlen = 0, stkslen = 0, tmp_pc;
|
||||||
|
int c;
|
||||||
|
zword_t i, j, n, init_fp, tmp_fp, nstk, nvars, args;
|
||||||
|
zword_t frames[STACK_SIZE / 4 + 1];
|
||||||
|
zbyte_t var;
|
||||||
|
long cmempos, stkspos;
|
||||||
|
|
||||||
|
/* write IFZS header */
|
||||||
|
if ( !write_chnk( sfp, ID_FORM, 0 ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_long( sfp, ID_IFZS ) )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* write IFhd chunk */
|
||||||
|
if ( !write_chnk( sfp, ID_IFhd, 13 ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_word( sfp, h_version ) )
|
||||||
|
return FALSE;
|
||||||
|
for ( i = 0; i < 6; ++i )
|
||||||
|
if ( !write_byte( sfp, get_byte( H_RELEASE_DATE + i ) ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_word( sfp, h_checksum ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_long( sfp, ( ( ul_t ) pc ) << 8 ) ) /* includes pad byte */
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* write CMem chunk */
|
||||||
|
/* j is current run length */
|
||||||
|
if ( ( cmempos = ftell( sfp ) ) < 0 )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_chnk( sfp, ID_CMem, 0 ) )
|
||||||
|
return FALSE;
|
||||||
|
jz_rewind( gfp );
|
||||||
|
for ( i = 0, j = 0, cmemlen = 0; i < h_restart_size; ++i )
|
||||||
|
{
|
||||||
|
if ( ( c = jz_getc( gfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
c ^= get_byte( i );
|
||||||
|
if ( c == 0 )
|
||||||
|
++j;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* write any run there may be */
|
||||||
|
if ( j > 0 )
|
||||||
|
{
|
||||||
|
for ( ; j > 0x100; j -= 0x100 )
|
||||||
|
{
|
||||||
|
if ( !write_run( sfp, 0xFF ) )
|
||||||
|
return FALSE;
|
||||||
|
cmemlen += 2;
|
||||||
|
}
|
||||||
|
if ( !write_run( sfp, j - 1 ) )
|
||||||
|
return FALSE;
|
||||||
|
cmemlen += 2;
|
||||||
|
j = 0;
|
||||||
|
}
|
||||||
|
/* write this byte */
|
||||||
|
if ( !write_byte( sfp, c ) )
|
||||||
|
return FALSE;
|
||||||
|
++cmemlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* there may be a run here, which we ignore */
|
||||||
|
if ( cmemlen & 1 ) /* chunk length must be even */
|
||||||
|
if ( !write_byte( sfp, 0 ) )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* write Stks chunk */
|
||||||
|
if ( ( stkspos = ftell( sfp ) ) < 0 )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_chnk( sfp, ID_Stks, 0 ) )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
/* frames is a list of FPs, most recent first */
|
||||||
|
frames[0] = sp - 5; /* what FP would be if we did a call now */
|
||||||
|
for ( init_fp = fp, n = 0; init_fp <= STACK_SIZE - 5; init_fp = stack[init_fp + 2] )
|
||||||
|
frames[++n] = init_fp;
|
||||||
|
init_fp = frames[n] + 4;
|
||||||
|
|
||||||
|
if ( h_type != 6 )
|
||||||
|
{ /* write a dummy frame for stack used before first call */
|
||||||
|
for ( i = 0; i < 6; ++i )
|
||||||
|
if ( !write_byte( sfp, 0 ) )
|
||||||
|
return FALSE;
|
||||||
|
nstk = STACK_SIZE - 1 - init_fp;
|
||||||
|
if ( !write_word( sfp, nstk ) )
|
||||||
|
return FALSE;
|
||||||
|
for ( i = STACK_SIZE - 1; i > init_fp; --i )
|
||||||
|
if ( !write_word( sfp, stack[i] ) )
|
||||||
|
return FALSE;
|
||||||
|
stkslen = 8 + 2 * nstk;
|
||||||
|
}
|
||||||
|
for ( i = n; i > 0; --i )
|
||||||
|
{
|
||||||
|
/* write out one stack frame.
|
||||||
|
*
|
||||||
|
* tmp_fp : FP when this frame was current
|
||||||
|
* tmp_pc : PC on return from this frame, plus 000pvvvv
|
||||||
|
* nvars : number of local vars for this frame
|
||||||
|
* args : argument mask for this frame
|
||||||
|
* nstk : words of evaluation stack used for this frame
|
||||||
|
* var : variable to store result
|
||||||
|
*/
|
||||||
|
tmp_fp = frames[i];
|
||||||
|
nvars = ( stack[tmp_fp + 1] & VARS_MASK ) >> VAR_SHIFT;
|
||||||
|
args = stack[tmp_fp + 1] & ARGS_MASK;
|
||||||
|
nstk = tmp_fp - frames[i - 1] - nvars - 4;
|
||||||
|
tmp_pc = stack[tmp_fp + 3] + ( ul_t ) stack[tmp_fp + 4] * PAGE_SIZE;
|
||||||
|
switch ( stack[tmp_fp + 1] & TYPE_MASK )
|
||||||
|
{
|
||||||
|
case FUNCTION:
|
||||||
|
var = read_data_byte( &tmp_pc ); /* also increments tmp_pc */
|
||||||
|
tmp_pc = ( tmp_pc << 8 ) | nvars;
|
||||||
|
break;
|
||||||
|
case PROCEDURE:
|
||||||
|
var = 0;
|
||||||
|
tmp_pc = ( tmp_pc << 8 ) | 0x10 | nvars; /* set procedure flag */
|
||||||
|
break;
|
||||||
|
/* case ASYNC: */
|
||||||
|
default:
|
||||||
|
output_line( "Illegal Z-machine operation: can't save while in interrupt." );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ( args != 0 )
|
||||||
|
args = ( 1 << args ) - 1; /* make args into bitmap */
|
||||||
|
if ( !write_long( sfp, tmp_pc ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_byte( sfp, var ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_byte( sfp, args ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !write_word( sfp, nstk ) )
|
||||||
|
return FALSE;
|
||||||
|
for ( j = 0; j < nvars + nstk; ++j, --tmp_fp )
|
||||||
|
if ( !write_word( sfp, stack[tmp_fp] ) )
|
||||||
|
return FALSE;
|
||||||
|
stkslen += 8 + 2 * ( nvars + nstk );
|
||||||
|
}
|
||||||
|
|
||||||
|
/* fill in lengths for variable-sized chunks */
|
||||||
|
ifzslen = 3 * 8 + 4 + 14 + cmemlen + stkslen;
|
||||||
|
if ( cmemlen & 1 )
|
||||||
|
++ifzslen;
|
||||||
|
( void ) fseek( sfp, ( long ) 4, SEEK_SET );
|
||||||
|
if ( !write_long( sfp, ifzslen ) )
|
||||||
|
return FALSE;
|
||||||
|
( void ) fseek( sfp, cmempos + 4, SEEK_SET );
|
||||||
|
if ( !write_long( sfp, cmemlen ) )
|
||||||
|
return FALSE;
|
||||||
|
( void ) fseek( sfp, stkspos + 4, SEEK_SET );
|
||||||
|
if ( !write_long( sfp, stkslen ) )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* end save_quetzal */
|
||||||
|
|
||||||
|
/* read_word
|
||||||
|
*
|
||||||
|
* attempt to read a word; return TRUE on success
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int read_word( FILE * fp, zword_t * result )
|
||||||
|
{
|
||||||
|
int a, b;
|
||||||
|
|
||||||
|
if ( ( a = get_c( fp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
if ( ( b = get_c( fp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
*result = ( ( zword_t ) a << 8 ) | b;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* read_long
|
||||||
|
*
|
||||||
|
* attempt to read a longword; return TRUE on success
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int read_long( FILE * fp, ul_t * result )
|
||||||
|
{
|
||||||
|
int a, b, c, d;
|
||||||
|
|
||||||
|
if ( ( a = get_c( fp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
if ( ( b = get_c( fp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
if ( ( c = get_c( fp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
if ( ( d = get_c( fp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
*result = ( ( ul_t ) a << 24 ) | ( ( ul_t ) b << 16 ) | ( ( ul_t ) c << 8 ) | d;
|
||||||
|
#ifdef QDEBUG
|
||||||
|
printf( "%c%c%c%c", a, b, c, d );
|
||||||
|
#endif
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* restore_quetzal
|
||||||
|
*
|
||||||
|
* attempt to restore game in QUETZAL format; return TRUE on success
|
||||||
|
*/
|
||||||
|
|
||||||
|
#define GOT_HEADER 0x01
|
||||||
|
#define GOT_STACK 0x02
|
||||||
|
#define GOT_MEMORY 0x04
|
||||||
|
#define GOT_NONE 0x00
|
||||||
|
#define GOT_ALL 0x07
|
||||||
|
#define GOT_ERROR 0x80
|
||||||
|
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
int restore_quetzal( FILE * sfp, gzFile * gfp )
|
||||||
|
#else
|
||||||
|
int restore_quetzal( FILE * sfp, FILE * gfp )
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
ul_t ifzslen, currlen, tmpl, skip = 0;
|
||||||
|
zword_t i, tmpw;
|
||||||
|
zbyte_t progress = GOT_NONE;
|
||||||
|
int x, y;
|
||||||
|
|
||||||
|
/* check for IFZS file */
|
||||||
|
if ( !read_long( sfp, &tmpl ) || !read_long( sfp, &ifzslen ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( !read_long( sfp, &currlen ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( tmpl != ID_FORM || currlen != ID_IFZS )
|
||||||
|
{
|
||||||
|
output_line( "This is not a saved game file!" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ( ( ifzslen & 1 ) || ifzslen < 4 )
|
||||||
|
return FALSE;
|
||||||
|
ifzslen -= 4;
|
||||||
|
|
||||||
|
/* read a chunk and process it */
|
||||||
|
while ( ifzslen > 0 )
|
||||||
|
{
|
||||||
|
/* read chunk header */
|
||||||
|
if ( ifzslen < 8 )
|
||||||
|
return FALSE;
|
||||||
|
if ( !read_long( sfp, &tmpl ) || !read_long( sfp, &currlen ) )
|
||||||
|
return FALSE;
|
||||||
|
ifzslen -= 8;
|
||||||
|
|
||||||
|
/* body of chunk */
|
||||||
|
if ( ifzslen < currlen )
|
||||||
|
return FALSE;
|
||||||
|
skip = currlen & 1;
|
||||||
|
ifzslen -= currlen + skip;
|
||||||
|
switch ( tmpl )
|
||||||
|
{
|
||||||
|
case ID_IFhd:
|
||||||
|
if ( progress & GOT_HEADER )
|
||||||
|
{
|
||||||
|
output_line( "Save file has two IFhd chunks!" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
progress |= GOT_HEADER;
|
||||||
|
if ( currlen < 13 || !read_word( sfp, &i ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( i != h_version )
|
||||||
|
progress = GOT_ERROR;
|
||||||
|
for ( i = H_RELEASE_DATE; i < H_RELEASE_DATE + 6; ++i )
|
||||||
|
{
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
if ( x != ( int ) get_byte( i ) )
|
||||||
|
progress = GOT_ERROR;
|
||||||
|
}
|
||||||
|
if ( !read_word( sfp, &i ) )
|
||||||
|
return FALSE;
|
||||||
|
if ( i != h_checksum )
|
||||||
|
progress = GOT_ERROR;
|
||||||
|
if ( progress == GOT_ERROR )
|
||||||
|
{
|
||||||
|
output_line( "File was not saved from this story!" );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
pc = ( ul_t ) x << 16;
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
pc |= ( ul_t ) x << 8;
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
pc |= ( ul_t ) x;
|
||||||
|
for ( i = 13; ( ul_t ) i < currlen; ++i )
|
||||||
|
( void ) get_c( sfp ); /* skip rest of chunk */
|
||||||
|
break;
|
||||||
|
case ID_Stks:
|
||||||
|
if ( progress & GOT_STACK )
|
||||||
|
{
|
||||||
|
output_line( "File contains two stack chunks!" );
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
progress |= GOT_STACK;
|
||||||
|
sp = STACK_SIZE;
|
||||||
|
if ( h_type != 6 )
|
||||||
|
{
|
||||||
|
/* dummy stack frame for stack used before call */
|
||||||
|
if ( currlen < 8 )
|
||||||
|
return FALSE;
|
||||||
|
for ( i = 0; i < 6; ++i )
|
||||||
|
if ( get_c( sfp ) != 0 )
|
||||||
|
return FALSE;
|
||||||
|
if ( !read_word( sfp, &tmpw ) )
|
||||||
|
return FALSE;
|
||||||
|
currlen -= 8;
|
||||||
|
if ( currlen < (unsigned long)(tmpw * 2) )
|
||||||
|
return FALSE;
|
||||||
|
for ( i = 0; i < tmpw; ++i )
|
||||||
|
if ( !read_word( sfp, stack + ( --sp ) ) )
|
||||||
|
return FALSE;
|
||||||
|
currlen -= tmpw * 2;
|
||||||
|
}
|
||||||
|
for ( fp = STACK_SIZE - 1, frame_count = 0; currlen > 0; currlen -= 8 )
|
||||||
|
{
|
||||||
|
if ( currlen < 8 )
|
||||||
|
return FALSE;
|
||||||
|
if ( sp < 4 )
|
||||||
|
{
|
||||||
|
output_line( "error: this save-file has too much stack, and I can't cope." );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
/* read PC, procedure flag, and arg count */
|
||||||
|
if ( !read_long( sfp, &tmpl ) )
|
||||||
|
return FALSE;
|
||||||
|
y = ( zword_t ) tmpl & 0x0F;
|
||||||
|
tmpw = y << VAR_SHIFT; /* number of variables */
|
||||||
|
/* read result variable */
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if ( tmpl & 0x10 )
|
||||||
|
{
|
||||||
|
tmpw |= PROCEDURE;
|
||||||
|
tmpl >>= 8;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
tmpw |= FUNCTION;
|
||||||
|
tmpl >>= 8;
|
||||||
|
--tmpl;
|
||||||
|
/* sanity check on result variable */
|
||||||
|
if ( read_data_byte( &tmpl ) != ( zbyte_t ) x )
|
||||||
|
{
|
||||||
|
output_line( "error: wrong variable number on stack (wrong story file?)." );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
--tmpl; /* read_data_byte increments it */
|
||||||
|
}
|
||||||
|
stack[--sp] = ( zword_t ) ( tmpl / PAGE_SIZE );
|
||||||
|
stack[--sp] = ( zword_t ) ( tmpl % PAGE_SIZE );
|
||||||
|
stack[--sp] = fp;
|
||||||
|
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
++x; /* hopefully x now contains a single set bit */
|
||||||
|
|
||||||
|
for ( i = 0; i < 8; ++i )
|
||||||
|
if ( x & ( 1 << i ) )
|
||||||
|
break;
|
||||||
|
if ( x ^ ( 1 << i ) ) /* if more than 1 bit set */
|
||||||
|
{
|
||||||
|
output_line
|
||||||
|
( "error: this game uses incomplete argument lists (which I can't handle)." );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
tmpw |= i;
|
||||||
|
stack[--sp] = tmpw;
|
||||||
|
fp = sp - 1; /* FP for next frame */
|
||||||
|
if ( !read_word( sfp, &tmpw ) )
|
||||||
|
return FALSE;
|
||||||
|
tmpw += y; /* local vars plus eval stack used */
|
||||||
|
if ( tmpw >= sp )
|
||||||
|
{
|
||||||
|
output_line( "error: this save-file uses more stack than I can cope with." );
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
if ( currlen < (unsigned long)(tmpw * 2) )
|
||||||
|
return FALSE;
|
||||||
|
for ( i = 0; i < tmpw; ++i )
|
||||||
|
if ( !read_word( sfp, stack + ( --sp ) ) )
|
||||||
|
return FALSE;
|
||||||
|
currlen -= tmpw * 2;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ID_ANNO:
|
||||||
|
z_buffer_mode( ON );
|
||||||
|
for ( ; currlen > 0; --currlen )
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
else
|
||||||
|
write_char( x );
|
||||||
|
write_char( ( char ) 13 );
|
||||||
|
break;
|
||||||
|
case ID_CMem:
|
||||||
|
if ( !( progress & GOT_MEMORY ) )
|
||||||
|
{
|
||||||
|
jz_rewind( gfp );
|
||||||
|
i = 0; /* bytes written to data area */
|
||||||
|
for ( ; currlen > 0; --currlen )
|
||||||
|
{
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
if ( x == 0 ) /* start run */
|
||||||
|
{
|
||||||
|
if ( currlen < 2 )
|
||||||
|
{
|
||||||
|
output_line( "File contains bogus CMem chunk" );
|
||||||
|
for ( ; currlen > 0; --currlen )
|
||||||
|
( void ) get_c( sfp ); /* skip rest */
|
||||||
|
currlen = 1;
|
||||||
|
i = 0xFFFF;
|
||||||
|
break; /* keep going in case there's a UMem */
|
||||||
|
}
|
||||||
|
--currlen;
|
||||||
|
if ( ( x = get_c( sfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
for ( ; x >= 0 && i < h_restart_size; --x, ++i )
|
||||||
|
if ( ( y = jz_getc( gfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
else
|
||||||
|
set_byte( i, y );
|
||||||
|
}
|
||||||
|
else /* not a run */
|
||||||
|
{
|
||||||
|
if ( ( y = jz_getc( gfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
set_byte( i, x ^ y );
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
if ( i > h_restart_size )
|
||||||
|
{
|
||||||
|
output_line( "warning: CMem chunk too long!" );
|
||||||
|
for ( ; currlen > 1; --currlen )
|
||||||
|
( void ) get_c( sfp ); /* skip rest */
|
||||||
|
break; /* keep going in case there's a UMem */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* if chunk is short, assume a run */
|
||||||
|
for ( ; i < h_restart_size; ++i )
|
||||||
|
if ( ( y = jz_getc( gfp ) ) == EOF )
|
||||||
|
return FALSE;
|
||||||
|
else
|
||||||
|
set_byte( i, y );
|
||||||
|
if ( currlen == 0 )
|
||||||
|
progress |= GOT_MEMORY; /* only if succeeded */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
/* Fall thru (to default) if already got memory */
|
||||||
|
case ID_UMem:
|
||||||
|
if ( !( progress & GOT_MEMORY ) )
|
||||||
|
{
|
||||||
|
if ( currlen == h_restart_size )
|
||||||
|
{
|
||||||
|
if ( fread( datap, h_restart_size, 1, sfp ) == 1 )
|
||||||
|
{
|
||||||
|
progress |= GOT_MEMORY; /* only if succeeded */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
output_line( "warning: UMem chunk wrong size!" );
|
||||||
|
/* and fall thru into default */
|
||||||
|
}
|
||||||
|
/* Fall thru (to default) if already got memory */
|
||||||
|
default:
|
||||||
|
( void ) fseek( sfp, currlen, SEEK_CUR ); /* skip chunk */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if ( skip )
|
||||||
|
( void ) get_c( sfp ); /* skip pad byte */
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( !( progress & GOT_HEADER ) )
|
||||||
|
output_line( "error: no header chunk in file." );
|
||||||
|
if ( !( progress & GOT_STACK ) )
|
||||||
|
output_line( "error: no stack chunk in file." );
|
||||||
|
if ( !( progress & GOT_MEMORY ) )
|
||||||
|
output_line( "error: no memory chunk in file." );
|
||||||
|
return ( progress == GOT_ALL );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* defined(USE_QUETZAL) */
|
577
screen.c
Normal file
577
screen.c
Normal file
|
@ -0,0 +1,577 @@
|
||||||
|
|
||||||
|
/* $Id: screen.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: screen.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: screen.c,v $
|
||||||
|
* Revision 1.3 2000/07/05 15:20:34 jholder
|
||||||
|
* Updated code to remove warnings.
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* screen.c
|
||||||
|
*
|
||||||
|
* Generic screen manipulation routines. Most of these routines call the machine
|
||||||
|
* specific routines to do the actual work.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_set_window
|
||||||
|
*
|
||||||
|
* Put the cursor in the text or status window. The cursor is free to move in
|
||||||
|
* the status window, but is fixed to the input line in the text window.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_set_window( zword_t w )
|
||||||
|
{
|
||||||
|
int row, col;
|
||||||
|
|
||||||
|
flush_buffer( FALSE );
|
||||||
|
|
||||||
|
screen_window = w;
|
||||||
|
|
||||||
|
if ( screen_window == STATUS_WINDOW )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Status window: disable formatting and select status window */
|
||||||
|
|
||||||
|
formatting = OFF;
|
||||||
|
scripting_disable = ON;
|
||||||
|
select_status_window( );
|
||||||
|
|
||||||
|
/* Put cursor at top of status area */
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
move_cursor( 2, 1 );
|
||||||
|
else
|
||||||
|
move_cursor( 1, 1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Text window: enable formatting and select text window */
|
||||||
|
|
||||||
|
select_text_window( );
|
||||||
|
scripting_disable = OFF;
|
||||||
|
formatting = ON;
|
||||||
|
|
||||||
|
/* Move cursor if it has been left in the status area */
|
||||||
|
|
||||||
|
get_cursor_position( &row, &col );
|
||||||
|
if ( row <= status_size )
|
||||||
|
move_cursor( status_size + 1, 1 );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Force text attribute to normal rendition */
|
||||||
|
|
||||||
|
set_attribute( NORMAL );
|
||||||
|
|
||||||
|
} /* z_set_window */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_split_window
|
||||||
|
*
|
||||||
|
* Set the size of the status window. The default size for the status window is
|
||||||
|
* zero lines for both type 3 and 4 games. The status line is handled specially
|
||||||
|
* for type 3 games and always occurs the line immediately above the status
|
||||||
|
* window.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_split_window( zword_t lines )
|
||||||
|
{
|
||||||
|
/* Maximum status window size is 255 */
|
||||||
|
|
||||||
|
lines &= 0xff;
|
||||||
|
|
||||||
|
/* The top line is always set for V1 to V3 games, so account for it here. */
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
lines++;
|
||||||
|
|
||||||
|
if ( lines )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If size is non zero the turn on the status window */
|
||||||
|
|
||||||
|
status_active = ON;
|
||||||
|
|
||||||
|
/* Bound the status size to one line less than the total screen height */
|
||||||
|
|
||||||
|
if ( lines > ( zword_t ) ( screen_rows - 1 ) )
|
||||||
|
status_size = ( zword_t ) ( screen_rows - 1 );
|
||||||
|
else
|
||||||
|
status_size = lines;
|
||||||
|
|
||||||
|
/* Create the status window, or resize it */
|
||||||
|
|
||||||
|
create_status_window( );
|
||||||
|
|
||||||
|
/* Need to clear the status window for type 3 games */
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
z_erase_window( STATUS_WINDOW );
|
||||||
|
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Lines are zero so turn off the status window */
|
||||||
|
|
||||||
|
status_active = OFF;
|
||||||
|
|
||||||
|
/* Reset the lines written counter and status size */
|
||||||
|
|
||||||
|
lines_written = 0;
|
||||||
|
status_size = 0;
|
||||||
|
|
||||||
|
/* Delete the status window */
|
||||||
|
|
||||||
|
delete_status_window( );
|
||||||
|
|
||||||
|
/* Return cursor to text window */
|
||||||
|
|
||||||
|
select_text_window( );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* z_split_window */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_erase_window
|
||||||
|
*
|
||||||
|
* Clear one or all windows on the screen.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_erase_window( zword_t w )
|
||||||
|
{
|
||||||
|
flush_buffer( TRUE );
|
||||||
|
|
||||||
|
if ( ( zbyte_t ) w == ( zbyte_t ) Z_SCREEN )
|
||||||
|
{
|
||||||
|
clear_screen( );
|
||||||
|
}
|
||||||
|
else if ( ( zbyte_t ) w == TEXT_WINDOW )
|
||||||
|
{
|
||||||
|
clear_text_window( );
|
||||||
|
}
|
||||||
|
else if ( ( zbyte_t ) w == STATUS_WINDOW )
|
||||||
|
{
|
||||||
|
clear_status_window( );
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( h_type > V4 )
|
||||||
|
move_cursor( 1, 1 );
|
||||||
|
else
|
||||||
|
move_cursor( screen_rows, 1 );
|
||||||
|
|
||||||
|
} /* z_erase_window */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_erase_line
|
||||||
|
*
|
||||||
|
* Clear one line on the screen.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_erase_line( zword_t flag )
|
||||||
|
{
|
||||||
|
if ( flag == TRUE )
|
||||||
|
clear_line( );
|
||||||
|
} /* z_erase_line */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_set_cursor
|
||||||
|
*
|
||||||
|
* Set the cursor position in the status window only.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_set_cursor( zword_t row, zword_t column )
|
||||||
|
{
|
||||||
|
/* Can only move cursor if format mode is off and in status window */
|
||||||
|
|
||||||
|
if ( formatting == OFF && screen_window == STATUS_WINDOW )
|
||||||
|
{
|
||||||
|
move_cursor( row, column );
|
||||||
|
}
|
||||||
|
#ifdef STRICTZ
|
||||||
|
else
|
||||||
|
{
|
||||||
|
report_strictz_error( STRZERR_MOV_CURSOR, "@set_cursor called outside the status window!" );
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
} /* z_set_cursor */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* pad_line
|
||||||
|
*
|
||||||
|
* Pad the status line with spaces up to a column position.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void pad_line( int column )
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for ( i = status_pos; i < column; i++ )
|
||||||
|
write_char( ' ' );
|
||||||
|
status_pos = column;
|
||||||
|
} /* pad_line */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_show_status
|
||||||
|
*
|
||||||
|
* Format and output the status line for type 3 games only.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_show_status( void )
|
||||||
|
{
|
||||||
|
int i, count = 0, end_of_string[3];
|
||||||
|
char *status_part[3];
|
||||||
|
|
||||||
|
/* Move the cursor to the top line of the status window, set the reverse
|
||||||
|
* rendition and print the status line */
|
||||||
|
|
||||||
|
z_set_window( STATUS_WINDOW );
|
||||||
|
move_cursor( 1, 1 );
|
||||||
|
set_attribute( REVERSE );
|
||||||
|
|
||||||
|
/* Redirect output to the status line buffer */
|
||||||
|
|
||||||
|
z_output_stream( 3, 0 );
|
||||||
|
|
||||||
|
/* Print the object description for global variable 16 */
|
||||||
|
|
||||||
|
pad_line( 1 );
|
||||||
|
status_part[count] = &status_line[status_pos];
|
||||||
|
if ( load_variable( 16 ) != 0 )
|
||||||
|
z_print_obj( load_variable( 16 ) );
|
||||||
|
end_of_string[count++] = status_pos;
|
||||||
|
status_line[status_pos++] = '\0';
|
||||||
|
|
||||||
|
if ( get_byte( H_CONFIG ) & CONFIG_TIME )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If a time display print the hours and minutes from global
|
||||||
|
* variables 17 and 18 */
|
||||||
|
|
||||||
|
pad_line( screen_cols - 21 );
|
||||||
|
status_part[count] = &status_line[status_pos];
|
||||||
|
write_string( " Time: " );
|
||||||
|
print_time( load_variable( 17 ), load_variable( 18 ) );
|
||||||
|
end_of_string[count++] = status_pos;
|
||||||
|
status_line[status_pos++] = '\0';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If a moves/score display print the score and moves from global
|
||||||
|
* variables 17 and 18 */
|
||||||
|
|
||||||
|
pad_line( screen_cols - 31 );
|
||||||
|
status_part[count] = &status_line[status_pos];
|
||||||
|
write_string( " Score: " );
|
||||||
|
z_print_num( load_variable( 17 ) );
|
||||||
|
end_of_string[count++] = status_pos;
|
||||||
|
status_line[status_pos++] = '\0';
|
||||||
|
|
||||||
|
pad_line( screen_cols - 15 );
|
||||||
|
status_part[count] = &status_line[status_pos];
|
||||||
|
write_string( " Moves: " );
|
||||||
|
z_print_num( load_variable( 18 ) );
|
||||||
|
end_of_string[count++] = status_pos;
|
||||||
|
status_line[status_pos++] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pad the end of status line with spaces then disable output redirection */
|
||||||
|
|
||||||
|
pad_line( screen_cols );
|
||||||
|
z_output_stream( ( zword_t ) - 3, 0 );
|
||||||
|
|
||||||
|
/* Try and print the status line for a proportional font screen. If this
|
||||||
|
* fails then remove embedded nulls in status line buffer and just output
|
||||||
|
* it to the screen */
|
||||||
|
|
||||||
|
if ( print_status( count, status_part ) == FALSE )
|
||||||
|
{
|
||||||
|
for ( i = 0; i < count; i++ )
|
||||||
|
status_line[end_of_string[i]] = ' ';
|
||||||
|
status_line[status_pos] = '\0';
|
||||||
|
write_string( status_line );
|
||||||
|
}
|
||||||
|
|
||||||
|
set_attribute( NORMAL );
|
||||||
|
z_set_window( TEXT_WINDOW );
|
||||||
|
|
||||||
|
} /* z_show_status */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* blank_status_line
|
||||||
|
*
|
||||||
|
* Output a blank status line for type 3 games only.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void blank_status_line( void )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Move the cursor to the top line of the status window, set the reverse
|
||||||
|
* rendition and print the status line */
|
||||||
|
|
||||||
|
z_set_window( STATUS_WINDOW );
|
||||||
|
move_cursor( 1, 1 );
|
||||||
|
set_attribute( REVERSE );
|
||||||
|
|
||||||
|
/* Redirect output to the status line buffer and pad the status line with
|
||||||
|
* spaces then disable output redirection */
|
||||||
|
|
||||||
|
z_output_stream( 3, 0 );
|
||||||
|
pad_line( screen_cols );
|
||||||
|
status_line[status_pos] = '\0';
|
||||||
|
z_output_stream( ( zword_t ) - 3, 0 );
|
||||||
|
|
||||||
|
/* Write the status line */
|
||||||
|
|
||||||
|
write_string( status_line );
|
||||||
|
|
||||||
|
/* Turn off attributes and return to text window */
|
||||||
|
|
||||||
|
set_attribute( NORMAL );
|
||||||
|
z_set_window( TEXT_WINDOW );
|
||||||
|
|
||||||
|
} /* blank_status_line */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* output_string
|
||||||
|
*
|
||||||
|
* Output a string of characters.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void output_string( const char *s )
|
||||||
|
{
|
||||||
|
while ( *s )
|
||||||
|
output_char( *s++ );
|
||||||
|
} /* output_string */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* output_line
|
||||||
|
*
|
||||||
|
* Output a string of characters followed by a new line.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void output_line( const char *s )
|
||||||
|
{
|
||||||
|
output_string( s );
|
||||||
|
output_new_line( );
|
||||||
|
} /* output_line */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* output_char
|
||||||
|
*
|
||||||
|
* Output a character.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void output_char( int c )
|
||||||
|
{
|
||||||
|
/* If output is enabled then either select the rendition attribute
|
||||||
|
* or just display the character */
|
||||||
|
|
||||||
|
if ( outputting == ON )
|
||||||
|
{
|
||||||
|
display_char( (unsigned int)(c & 0xff) );
|
||||||
|
}
|
||||||
|
} /* output_char */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* output_new_line
|
||||||
|
*
|
||||||
|
* Scroll the text window up one line and pause the window if it is full.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void output_new_line( void )
|
||||||
|
{
|
||||||
|
int row, col;
|
||||||
|
|
||||||
|
/* Don't print if output is disabled or replaying commands */
|
||||||
|
|
||||||
|
if ( outputting == ON )
|
||||||
|
{
|
||||||
|
|
||||||
|
if ( formatting == ON && screen_window == TEXT_WINDOW )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* If this is the text window then scroll it up one line */
|
||||||
|
|
||||||
|
scroll_line( );
|
||||||
|
|
||||||
|
/* See if we have filled the screen. The spare line is for
|
||||||
|
* the [MORE] message
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ( ++lines_written >= ( ( screen_rows - top_margin ) - status_size - 1 ) )
|
||||||
|
{
|
||||||
|
|
||||||
|
/* Display the new status line while the screen in paused */
|
||||||
|
|
||||||
|
if ( h_type < V4 )
|
||||||
|
z_show_status( );
|
||||||
|
|
||||||
|
/* Reset the line count and display the more message */
|
||||||
|
|
||||||
|
lines_written = 0;
|
||||||
|
|
||||||
|
if ( replaying == OFF )
|
||||||
|
{
|
||||||
|
get_cursor_position( &row, &col );
|
||||||
|
output_string( "[MORE]" );
|
||||||
|
( void ) input_character( 0 );
|
||||||
|
move_cursor( row, col );
|
||||||
|
output_string( " " );
|
||||||
|
move_cursor( row, col );
|
||||||
|
/* clear_line (); */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
/* If this is the status window then just output a new line */
|
||||||
|
|
||||||
|
output_char( '\n' );
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* output_new_line */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_print_table
|
||||||
|
*
|
||||||
|
* Writes text into a rectangular window on the screen.
|
||||||
|
*
|
||||||
|
* argv[0] = start of text address
|
||||||
|
* argv[1] = rectangle width
|
||||||
|
* argv[2] = rectangle height (default = 1)
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_print_table( int argc, zword_t * argv )
|
||||||
|
{
|
||||||
|
unsigned long address;
|
||||||
|
unsigned int width, height;
|
||||||
|
unsigned int row, column;
|
||||||
|
|
||||||
|
/* Supply default arguments */
|
||||||
|
|
||||||
|
if ( argc < 3 )
|
||||||
|
argv[2] = 1;
|
||||||
|
|
||||||
|
/* Don't do anything if the window is zero high or wide */
|
||||||
|
|
||||||
|
if ( argv[1] == 0 || argv[2] == 0 )
|
||||||
|
return;
|
||||||
|
|
||||||
|
/* Get coordinates of top left corner of rectangle */
|
||||||
|
|
||||||
|
get_cursor_position( ( int * ) &row, ( int * ) &column );
|
||||||
|
|
||||||
|
address = argv[0];
|
||||||
|
|
||||||
|
/* Write text in width * height rectangle */
|
||||||
|
|
||||||
|
for ( height = 0; height < argv[2]; height++ )
|
||||||
|
{
|
||||||
|
|
||||||
|
for ( width = 0; width < argv[1]; width++ )
|
||||||
|
write_char( read_data_byte( &address ) );
|
||||||
|
|
||||||
|
/* Put cursor back to lefthand side of rectangle on next line */
|
||||||
|
|
||||||
|
if ( height != (unsigned)( argv[2] - 1 ) )
|
||||||
|
move_cursor( ++row, column );
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
} /* z_print_table */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_set_font
|
||||||
|
*
|
||||||
|
* Set text or graphic font. 1 = text font, 3 = graphics font.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_set_font( zword_t new_font )
|
||||||
|
{
|
||||||
|
zword_t old_font = font;
|
||||||
|
|
||||||
|
if ( new_font != old_font )
|
||||||
|
{
|
||||||
|
font = new_font;
|
||||||
|
set_font( font );
|
||||||
|
}
|
||||||
|
|
||||||
|
store_operand( old_font );
|
||||||
|
|
||||||
|
} /* z_set_font */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_set_colour
|
||||||
|
*
|
||||||
|
* Set the colour of the screen. Colour can be set on four things:
|
||||||
|
* Screen background
|
||||||
|
* Text typed by player
|
||||||
|
* Text written by game
|
||||||
|
* Graphics characters
|
||||||
|
*
|
||||||
|
* Colors can be set to 1 of 9 values:
|
||||||
|
* 1 = machine default (IBM/PC = blue background, everything else white)
|
||||||
|
* 2 = black
|
||||||
|
* 3 = red
|
||||||
|
* 4 = green
|
||||||
|
* 5 = brown
|
||||||
|
* 6 = blue
|
||||||
|
* 7 = magenta
|
||||||
|
* 8 = cyan
|
||||||
|
* 9 = white
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_set_colour( zword_t foreground, zword_t background )
|
||||||
|
{
|
||||||
|
if ( ( ZINT16 ) foreground < -1 || ( ZINT16 ) foreground > 9 || ( ZINT16 ) background < -1 ||
|
||||||
|
( ZINT16 ) background > 9 )
|
||||||
|
fatal( "Bad colour!" );
|
||||||
|
|
||||||
|
|
||||||
|
flush_buffer( FALSE );
|
||||||
|
|
||||||
|
set_colours( foreground, background );
|
||||||
|
|
||||||
|
return;
|
||||||
|
} /* z_set_colour */
|
126
variable.c
Normal file
126
variable.c
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
|
||||||
|
/* $Id: variable.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: variable.c,v 1.3 2000/07/05 15:20:34 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: variable.c,v $
|
||||||
|
* Revision 1.3 2000/07/05 15:20:34 jholder
|
||||||
|
* Updated code to remove warnings.
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* variable.c
|
||||||
|
*
|
||||||
|
* Variable manipulation routines
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ztypes.h"
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_load
|
||||||
|
*
|
||||||
|
* Load and store a variable value on stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_load( zword_t variable )
|
||||||
|
{
|
||||||
|
store_operand( load_variable( variable ) );
|
||||||
|
} /* load */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_push
|
||||||
|
*
|
||||||
|
* Push a value onto the stack
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_push( zword_t value )
|
||||||
|
{
|
||||||
|
stack[--sp] = value;
|
||||||
|
} /* push_var */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_pull
|
||||||
|
*
|
||||||
|
* Pop a variable from the stack.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_pull( zword_t variable )
|
||||||
|
{
|
||||||
|
z_store( variable, stack[sp++] );
|
||||||
|
} /* pop_var */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_inc
|
||||||
|
*
|
||||||
|
* Increment a variable.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_inc( zword_t variable )
|
||||||
|
{
|
||||||
|
z_store( variable, (zword_t)(load_variable( variable ) + 1) );
|
||||||
|
} /* increment */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_dec
|
||||||
|
*
|
||||||
|
* Decrement a variable.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_dec( zword_t variable )
|
||||||
|
{
|
||||||
|
z_store( variable, (zword_t)(load_variable( variable ) - 1) );
|
||||||
|
} /* decrement */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_inc_chk
|
||||||
|
*
|
||||||
|
* Increment a variable and then check its value against a target.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_inc_chk( zword_t variable, zword_t target )
|
||||||
|
{
|
||||||
|
ZINT16 value;
|
||||||
|
|
||||||
|
value = ( ZINT16 ) load_variable( variable );
|
||||||
|
z_store( variable, ++value );
|
||||||
|
conditional_jump( value > ( ZINT16 ) target );
|
||||||
|
} /* increment_check */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* z_dec_chk
|
||||||
|
*
|
||||||
|
* Decrement a variable and then check its value against a target.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
void z_dec_chk( zword_t variable, zword_t target )
|
||||||
|
{
|
||||||
|
ZINT16 value;
|
||||||
|
|
||||||
|
value = ( ZINT16 ) load_variable( variable );
|
||||||
|
z_store( variable, --value );
|
||||||
|
conditional_jump( value < ( ZINT16 ) target );
|
||||||
|
} /* decrement_check */
|
799
ztypes.h
Normal file
799
ztypes.h
Normal file
|
@ -0,0 +1,799 @@
|
||||||
|
|
||||||
|
/* $Id: ztypes.h,v 1.4 2000/10/04 23:07:57 jholder Exp $
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
* see doc/License.txt for License Information
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*
|
||||||
|
* File name: $Id: ztypes.h,v 1.4 2000/10/04 23:07:57 jholder Exp $
|
||||||
|
*
|
||||||
|
* Description:
|
||||||
|
*
|
||||||
|
* Modification history:
|
||||||
|
* $Log: ztypes.h,v $
|
||||||
|
* Revision 1.4 2000/10/04 23:07:57 jholder
|
||||||
|
* fixed redirect problem with isolatin1 range chars
|
||||||
|
*
|
||||||
|
* Revision 1.3 2000/07/05 15:20:34 jholder
|
||||||
|
* Updated code to remove warnings.
|
||||||
|
*
|
||||||
|
* Revision 1.2 2000/05/25 22:28:56 jholder
|
||||||
|
* changes routine names to reflect zmachine opcode names per spec 1.0
|
||||||
|
*
|
||||||
|
* Revision 1.1.1.1 2000/05/10 14:21:34 jholder
|
||||||
|
*
|
||||||
|
* imported
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* --------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* ztypes.h
|
||||||
|
*
|
||||||
|
* Any global stuff required by the C modules.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#if !defined(__ZTYPES_INCLUDED)
|
||||||
|
#define __ZTYPES_INCLUDED
|
||||||
|
|
||||||
|
// IIgs stuff - everyone gets it
|
||||||
|
#include "joey.h"
|
||||||
|
#define LOUSY_RANDOM
|
||||||
|
|
||||||
|
/* AIX likes to see this define... */
|
||||||
|
#if defined(AIX)
|
||||||
|
#define _POSIX_SOURCE
|
||||||
|
#define POSIX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* for Turbo C & MSC */
|
||||||
|
#if defined(__MSDOS__)
|
||||||
|
#ifndef MSDOS
|
||||||
|
#define MSDOS
|
||||||
|
#endif
|
||||||
|
#define LOUSY_RANDOM
|
||||||
|
#define Z_FILENAME_MAX FILENAME_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
#if defined OS2
|
||||||
|
#define LOUSY_RANDOM
|
||||||
|
#define Z_FILENAME_MAX FILENAME_MAX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <assert.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#if defined(MSDOS)
|
||||||
|
#include <malloc.h>
|
||||||
|
#endif /* MSDOS */
|
||||||
|
|
||||||
|
/* Set Version of JZIP */
|
||||||
|
|
||||||
|
#include "jzip.h"
|
||||||
|
extern unsigned char JTERP;
|
||||||
|
|
||||||
|
/* Configuration options */
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
#include <zlib.h>
|
||||||
|
#define jz_rewind gzrewind
|
||||||
|
#define jz_seek gzseek
|
||||||
|
#define jz_open gzopen
|
||||||
|
#define jz_close gzclose
|
||||||
|
#define jz_getc gzgetc
|
||||||
|
#else
|
||||||
|
#define jz_rewind rewind
|
||||||
|
#define jz_seek fseek
|
||||||
|
#define jz_open fopen
|
||||||
|
#define jz_close fclose
|
||||||
|
#define jz_getc getc
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define USE_QUETZAL
|
||||||
|
|
||||||
|
#define DEFAULT_ROWS 25 /* Default screen height */
|
||||||
|
#define DEFAULT_COLS 40 /* Deafult screen width */
|
||||||
|
|
||||||
|
#define DEFAULT_RIGHT_MARGIN 1 /* # of characters in rt margin (UNIX likes 1)*/
|
||||||
|
#define DEFAULT_TOP_MARGIN 0 /* # of lines on screen before [MORE] message */
|
||||||
|
|
||||||
|
#ifdef LOUSY_RANDOM
|
||||||
|
#define RANDOM_FUNC rand
|
||||||
|
#define SRANDOM_FUNC srand
|
||||||
|
#else
|
||||||
|
#define RANDOM_FUNC random
|
||||||
|
#define SRANDOM_FUNC srandom
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Perform stricter z-code error checking. If STRICTZ is #defined,
|
||||||
|
* the interpreter will check for common opcode errors, such as reading
|
||||||
|
* or writing properties of the "nothing" (0) object. When such an
|
||||||
|
* error occurs, the opcode will call report_zstrict_error() and
|
||||||
|
* then continue in some safe manner. This may mean doing nothing,
|
||||||
|
* returning 0, or something like that.
|
||||||
|
*
|
||||||
|
* See osdepend.c for the definition of report_zstrict_error(). Note that
|
||||||
|
* this function may call fatal() to shut down the interpreter.
|
||||||
|
*
|
||||||
|
* If STRICTZ is not #defined, the STRICTZ patch has no effect at all.
|
||||||
|
* It does not even check to continue safely when an error occurs;
|
||||||
|
* it just behaves the way ZIP has always behaved. This typically
|
||||||
|
* means calling get_property_addr(0) or get_object_address(0),
|
||||||
|
* which will return a meaningless value, and continuing on with
|
||||||
|
* that.
|
||||||
|
*/
|
||||||
|
//#define STRICTZ
|
||||||
|
|
||||||
|
|
||||||
|
/* Global defines */
|
||||||
|
|
||||||
|
#ifndef UNUSEDVAR
|
||||||
|
#define UNUSEDVAR(a) a=a;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* number of bits in a byte. needed by AIX!!! ;^) */
|
||||||
|
#ifndef NBBY
|
||||||
|
#define NBBY 8
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef TRUE
|
||||||
|
#define TRUE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FALSE
|
||||||
|
#define FALSE 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef Z_FILENAME_MAX
|
||||||
|
#define Z_FILENAME_MAX 255
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef Z_PATHNAME_MAX
|
||||||
|
#define Z_PATHNAME_MAX 1024
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EXIT_SUCCESS
|
||||||
|
#define EXIT_SUCCESS 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef EXIT_FAILURE
|
||||||
|
#define EXIT_FAILURE 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEEK_SET
|
||||||
|
#define SEEK_SET 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef SEEK_END
|
||||||
|
#define SEEK_END 2
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef unix
|
||||||
|
|
||||||
|
#if defined (HAVE_BCOPY)
|
||||||
|
#define memmove(a, b, c) bcopy (b, a, c)
|
||||||
|
#else
|
||||||
|
#define memmove(a, b, c) memcpy ((a), (b), (c))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef const
|
||||||
|
#define const
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* unix */
|
||||||
|
|
||||||
|
|
||||||
|
/* Z types */
|
||||||
|
|
||||||
|
typedef unsigned char zbyte_t; /* unsigned 1 byte quantity */
|
||||||
|
typedef unsigned short zword_t; /* unsigned 2 byte quantity */
|
||||||
|
typedef short ZINT16; /* signed 2 byte quantity */
|
||||||
|
|
||||||
|
/* Data file header format */
|
||||||
|
|
||||||
|
typedef struct zheader
|
||||||
|
{
|
||||||
|
zbyte_t type;
|
||||||
|
zbyte_t config;
|
||||||
|
zword_t version;
|
||||||
|
zword_t data_size;
|
||||||
|
zword_t start_pc;
|
||||||
|
zword_t words_offset;
|
||||||
|
zword_t objects_offset;
|
||||||
|
zword_t globals_offset;
|
||||||
|
zword_t restart_size;
|
||||||
|
zword_t flags;
|
||||||
|
zbyte_t release_date[6];
|
||||||
|
zword_t synonyms_offset;
|
||||||
|
zword_t file_size;
|
||||||
|
zword_t checksum;
|
||||||
|
zbyte_t interpreter;
|
||||||
|
zbyte_t interpreter_version;
|
||||||
|
zbyte_t screen_rows;
|
||||||
|
zbyte_t screen_columns;
|
||||||
|
zbyte_t screen_left;
|
||||||
|
zbyte_t screen_right;
|
||||||
|
zbyte_t screen_top;
|
||||||
|
zbyte_t screen_bottom;
|
||||||
|
zbyte_t max_char_width;
|
||||||
|
zbyte_t max_char_height;
|
||||||
|
zword_t filler1[3];
|
||||||
|
zword_t function_keys_offset;
|
||||||
|
zword_t filler2[2];
|
||||||
|
zword_t alternate_alphabet_offset;
|
||||||
|
zword_t mouse_position_offset;
|
||||||
|
zword_t filler3[4];
|
||||||
|
}
|
||||||
|
zheader_t;
|
||||||
|
|
||||||
|
#define H_TYPE 0
|
||||||
|
#define H_CONFIG 1
|
||||||
|
|
||||||
|
#define CONFIG_BYTE_SWAPPED 0x01 /* Game data is byte swapped - V3 */
|
||||||
|
#define CONFIG_TIME 0x02 /* Status line displays time - V3 */
|
||||||
|
#define CONFIG_MAX_DATA 0x04 /* Data area should 64K if possible - V3 */
|
||||||
|
#define CONFIG_TANDY 0x08 /* Tandy licensed game - V3 */
|
||||||
|
#define CONFIG_NOSTATUSLINE 0x10 /* Interp can't support a status line - V3 */
|
||||||
|
#define CONFIG_WINDOWS 0x20 /* Interpr supports split screen mode - V3 */
|
||||||
|
|
||||||
|
#define CONFIG_COLOUR 0x01 /* Game supports colour - V5+ */
|
||||||
|
#define CONFIG_PICTURES 0x02 /* Picture displaying available? - V4+ */
|
||||||
|
#define CONFIG_BOLDFACE 0x04 /* Interpr supports boldface style - V4+ */
|
||||||
|
#define CONFIG_EMPHASIS 0x08 /* Interpreter supports text emphasis - V4+ */
|
||||||
|
#define CONFIG_FIXED 0x10 /* Interpr supports fixed width style - V4+ */
|
||||||
|
#define CONFIG_SFX 0x20 /* Interpr supports sound effects - V4+ */
|
||||||
|
#define CONFIG_TIMEDINPUT 0x80 /* Interpr supports timed input - V4+ */
|
||||||
|
|
||||||
|
#define CONFIG_PROPORTIONAL 0x40 /* Interpr uses proportional font - V3+ */
|
||||||
|
|
||||||
|
|
||||||
|
#define H_VERSION 2
|
||||||
|
#define H_DATA_SIZE 4
|
||||||
|
#define H_START_PC 6
|
||||||
|
#define H_WORDS_OFFSET 8
|
||||||
|
#define H_OBJECTS_OFFSET 10
|
||||||
|
#define H_GLOBALS_OFFSET 12
|
||||||
|
#define H_RESTART_SIZE 14
|
||||||
|
#define H_FLAGS 16
|
||||||
|
|
||||||
|
#define SCRIPTING_FLAG 0x01
|
||||||
|
#define FIXED_FONT_FLAG 0x02
|
||||||
|
#define REFRESH_FLAG 0x04
|
||||||
|
#define GRAPHICS_FLAG 0x08
|
||||||
|
#define SOUND_FLAG 0x10 /* V4 */
|
||||||
|
#define UNDO_AVAILABLE_FLAG 0x10 /* V5 */
|
||||||
|
#define COLOUR_FLAG 0x40
|
||||||
|
#define NEW_SOUND_FLAG 0x80
|
||||||
|
|
||||||
|
#define H_RELEASE_DATE 18
|
||||||
|
#define H_SYNONYMS_OFFSET 24
|
||||||
|
#define H_FILE_SIZE 26
|
||||||
|
#define H_CHECKSUM 28
|
||||||
|
#define H_INTERPRETER 30
|
||||||
|
#define H_UNICODE_TABLE 34
|
||||||
|
|
||||||
|
#define INTERP_GENERIC 0
|
||||||
|
#define INTERP_DEC_20 1
|
||||||
|
#define INTERP_APPLE_IIE 2
|
||||||
|
#define INTERP_MACINTOSH 3
|
||||||
|
#define INTERP_AMIGA 4
|
||||||
|
#define INTERP_ATARI_ST 5
|
||||||
|
#define INTERP_MSDOS 6
|
||||||
|
#define INTERP_CBM_128 7
|
||||||
|
#define INTERP_CBM_64 8
|
||||||
|
#define INTERP_APPLE_IIC 9
|
||||||
|
#define INTERP_APPLE_IIGS 10
|
||||||
|
#define INTERP_TANDY 11
|
||||||
|
#define INTERP_UNIX 12
|
||||||
|
#define INTERP_VMS 13
|
||||||
|
|
||||||
|
#define H_INTERPRETER_VERSION 31
|
||||||
|
#define H_SCREEN_ROWS 32
|
||||||
|
#define H_SCREEN_COLUMNS 33
|
||||||
|
#define H_SCREEN_LEFT 34
|
||||||
|
#define H_SCREEN_RIGHT 35
|
||||||
|
#define H_SCREEN_TOP 36
|
||||||
|
#define H_SCREEN_BOTTOM 37
|
||||||
|
#define H_MAX_CHAR_WIDTH 38
|
||||||
|
#define H_MAX_CHAR_HEIGHT 39
|
||||||
|
#define H_FILLER1 40
|
||||||
|
|
||||||
|
#define H_FUNCTION_KEYS_OFFSET 46
|
||||||
|
#define H_FILLER2 48
|
||||||
|
|
||||||
|
#define H_STANDARD_HIGH 50
|
||||||
|
#define H_STANDARD_LOW 51
|
||||||
|
|
||||||
|
#define H_ALTERNATE_ALPHABET_OFFSET 52
|
||||||
|
#define H_MOUSE_POSITION_OFFSET 54
|
||||||
|
#define H_FILLER3 56
|
||||||
|
|
||||||
|
#define V1 1
|
||||||
|
|
||||||
|
#define V2 2
|
||||||
|
|
||||||
|
/* Version 3 object format */
|
||||||
|
|
||||||
|
#define V3 3
|
||||||
|
|
||||||
|
typedef struct zobjectv3
|
||||||
|
{
|
||||||
|
zword_t attributes[2];
|
||||||
|
zbyte_t parent;
|
||||||
|
zbyte_t next;
|
||||||
|
zbyte_t child;
|
||||||
|
zword_t property_offset;
|
||||||
|
}
|
||||||
|
zobjectv3_t;
|
||||||
|
|
||||||
|
#define O3_ATTRIBUTES 0
|
||||||
|
#define O3_PARENT 4
|
||||||
|
#define O3_NEXT 5
|
||||||
|
#define O3_CHILD 6
|
||||||
|
#define O3_PROPERTY_OFFSET 7
|
||||||
|
|
||||||
|
#define O3_SIZE 9
|
||||||
|
|
||||||
|
#define PARENT3(offset) (offset + O3_PARENT)
|
||||||
|
#define NEXT3(offset) (offset + O3_NEXT)
|
||||||
|
#define CHILD3(offset) (offset + O3_CHILD)
|
||||||
|
|
||||||
|
#define P3_MAX_PROPERTIES 0x20
|
||||||
|
|
||||||
|
/* Version 4 object format */
|
||||||
|
|
||||||
|
#define V4 4
|
||||||
|
|
||||||
|
typedef struct zobjectv4
|
||||||
|
{
|
||||||
|
zword_t attributes[3];
|
||||||
|
zword_t parent;
|
||||||
|
zword_t next;
|
||||||
|
zword_t child;
|
||||||
|
zword_t property_offset;
|
||||||
|
}
|
||||||
|
zobjectv4_t;
|
||||||
|
|
||||||
|
#define O4_ATTRIBUTES 0
|
||||||
|
#define O4_PARENT 6
|
||||||
|
#define O4_NEXT 8
|
||||||
|
#define O4_CHILD 10
|
||||||
|
#define O4_PROPERTY_OFFSET 12
|
||||||
|
|
||||||
|
#define O4_SIZE 14
|
||||||
|
|
||||||
|
#define PARENT4(offset) (offset + O4_PARENT)
|
||||||
|
#define NEXT4(offset) (offset + O4_NEXT)
|
||||||
|
#define CHILD4(offset) (offset + O4_CHILD)
|
||||||
|
|
||||||
|
#define P4_MAX_PROPERTIES 0x40
|
||||||
|
|
||||||
|
#define V5 5
|
||||||
|
#define V6 6
|
||||||
|
#define V7 7
|
||||||
|
#define V8 8
|
||||||
|
|
||||||
|
/* Interpreter states */
|
||||||
|
|
||||||
|
#define STOP 0
|
||||||
|
#define RUN 1
|
||||||
|
|
||||||
|
/* Call types */
|
||||||
|
|
||||||
|
#define FUNCTION 0x0000
|
||||||
|
|
||||||
|
#if defined(USE_QUETZAL)
|
||||||
|
#define PROCEDURE 0x1000
|
||||||
|
#define ASYNC 0x2000
|
||||||
|
#else
|
||||||
|
#define PROCEDURE 0x0100
|
||||||
|
#define ASYNC 0x0200
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(USE_QUETZAL)
|
||||||
|
#define ARGS_MASK 0x00FF
|
||||||
|
#define VARS_MASK 0x0F00
|
||||||
|
#define TYPE_MASK 0xF000
|
||||||
|
#define VAR_SHIFT 8
|
||||||
|
#else
|
||||||
|
#define ARGS_MASK 0x00ff
|
||||||
|
#define TYPE_MASK 0xff00
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Local defines */
|
||||||
|
|
||||||
|
#define PAGE_SIZE 0x200
|
||||||
|
#define PAGE_MASK 0x1FF
|
||||||
|
#define PAGE_SHIFT 9
|
||||||
|
|
||||||
|
#define STACK_SIZE 1024
|
||||||
|
|
||||||
|
#define ON 1
|
||||||
|
#define OFF 0
|
||||||
|
#define RESET -1
|
||||||
|
|
||||||
|
#define Z_SCREEN 255
|
||||||
|
#define TEXT_WINDOW 0
|
||||||
|
#define STATUS_WINDOW 1
|
||||||
|
|
||||||
|
#define MIN_ATTRIBUTE 0
|
||||||
|
#define NORMAL 0
|
||||||
|
#define REVERSE 1
|
||||||
|
#define BOLD 2
|
||||||
|
#define EMPHASIS 4
|
||||||
|
#define FIXED_FONT 8
|
||||||
|
#define MAX_ATTRIBUTE 8
|
||||||
|
|
||||||
|
#define TEXT_FONT 1
|
||||||
|
#define GRAPHICS_FONT 3
|
||||||
|
|
||||||
|
#define FOREGROUND 0
|
||||||
|
#define BACKGROUND 1
|
||||||
|
|
||||||
|
#define GAME_RESTORE 0
|
||||||
|
#define GAME_SAVE 1
|
||||||
|
#define GAME_SCRIPT 2
|
||||||
|
#define GAME_RECORD 3
|
||||||
|
#define GAME_PLAYBACK 4
|
||||||
|
#define UNDO_SAVE 5
|
||||||
|
#define UNDO_RESTORE 6
|
||||||
|
#define GAME_SAVE_AUX 7
|
||||||
|
#define GAME_LOAD_AUX 8
|
||||||
|
|
||||||
|
#define MAX_TEXT_SIZE 8
|
||||||
|
|
||||||
|
/* Data access macros */
|
||||||
|
|
||||||
|
#define get_byte(offset) ((zbyte_t) datap[offset])
|
||||||
|
#define get_word(offset) ((zword_t) (((zword_t) datap[offset] << 8) + (zword_t) datap[offset + 1]))
|
||||||
|
#define set_byte(offset,value) datap[offset] = (zbyte_t) (value)
|
||||||
|
#define set_word(offset,value) datap[offset] = (zbyte_t) ((zword_t) (value) >> 8), datap[offset + 1] = (zbyte_t) ((zword_t) (value) & 0xff)
|
||||||
|
|
||||||
|
/* External data */
|
||||||
|
|
||||||
|
extern int GLOBALVER;
|
||||||
|
extern zbyte_t h_type;
|
||||||
|
extern zbyte_t h_config;
|
||||||
|
extern zword_t h_version;
|
||||||
|
extern zword_t h_data_size;
|
||||||
|
extern zword_t h_start_pc;
|
||||||
|
extern zword_t h_words_offset;
|
||||||
|
extern zword_t h_objects_offset;
|
||||||
|
extern zword_t h_globals_offset;
|
||||||
|
extern zword_t h_restart_size;
|
||||||
|
extern zword_t h_flags;
|
||||||
|
extern zword_t h_synonyms_offset;
|
||||||
|
extern zword_t h_file_size;
|
||||||
|
extern zword_t h_checksum;
|
||||||
|
extern zbyte_t h_interpreter;
|
||||||
|
extern zbyte_t h_interpreter_version;
|
||||||
|
extern zword_t h_alternate_alphabet_offset;
|
||||||
|
extern zword_t h_unicode_table;
|
||||||
|
|
||||||
|
extern int story_scaler;
|
||||||
|
extern int story_shift;
|
||||||
|
extern int property_mask;
|
||||||
|
extern int property_size_mask;
|
||||||
|
|
||||||
|
extern zword_t stack[STACK_SIZE];
|
||||||
|
extern zword_t sp;
|
||||||
|
extern zword_t fp;
|
||||||
|
extern zword_t frame_count;
|
||||||
|
extern unsigned long pc;
|
||||||
|
extern int interpreter_state;
|
||||||
|
extern int interpreter_status;
|
||||||
|
|
||||||
|
extern unsigned int data_size;
|
||||||
|
extern zbyte_t *datap;
|
||||||
|
extern zbyte_t *undo_datap;
|
||||||
|
|
||||||
|
extern int screen_rows;
|
||||||
|
extern int screen_cols;
|
||||||
|
extern int right_margin;
|
||||||
|
extern int top_margin;
|
||||||
|
|
||||||
|
extern int screen_window;
|
||||||
|
extern int interp_initialized;
|
||||||
|
|
||||||
|
extern int formatting;
|
||||||
|
extern int outputting;
|
||||||
|
extern int redirect_depth;
|
||||||
|
extern int redirecting;
|
||||||
|
extern int scripting;
|
||||||
|
extern int scripting_disable;
|
||||||
|
extern int recording;
|
||||||
|
extern int replaying;
|
||||||
|
extern int font;
|
||||||
|
|
||||||
|
extern int status_active;
|
||||||
|
extern int status_size;
|
||||||
|
|
||||||
|
extern char fTandy;
|
||||||
|
extern char fIBMGraphics;
|
||||||
|
|
||||||
|
extern int lines_written;
|
||||||
|
extern int status_pos;
|
||||||
|
|
||||||
|
extern char *line;
|
||||||
|
extern char *status_line;
|
||||||
|
|
||||||
|
extern char lookup_table[3][26];
|
||||||
|
|
||||||
|
extern char monochrome;
|
||||||
|
extern int hist_buf_size;
|
||||||
|
extern char bigscreen;
|
||||||
|
|
||||||
|
extern unsigned char zscii2latin1[69];
|
||||||
|
|
||||||
|
#ifdef STRICTZ
|
||||||
|
|
||||||
|
/* Definitions for STRICTZ functions and error codes. */
|
||||||
|
|
||||||
|
void report_strictz_error( int, const char * );
|
||||||
|
|
||||||
|
/* Error codes */
|
||||||
|
#define STRZERR_NO_ERROR (0)
|
||||||
|
#define STRZERR_JIN (1)
|
||||||
|
#define STRZERR_GET_CHILD (2)
|
||||||
|
#define STRZERR_GET_PARENT (3)
|
||||||
|
#define STRZERR_GET_SIBLING (4)
|
||||||
|
#define STRZERR_GET_PROP_ADDR (5)
|
||||||
|
#define STRZERR_GET_PROP (6)
|
||||||
|
#define STRZERR_PUT_PROP (7)
|
||||||
|
#define STRZERR_CLEAR_ATTR (8)
|
||||||
|
#define STRZERR_SET_ATTR (9)
|
||||||
|
#define STRZERR_TEST_ATTR (10)
|
||||||
|
#define STRZERR_MOVE_OBJECT (11)
|
||||||
|
#define STRZERR_MOVE_OBJECT_2 (12)
|
||||||
|
#define STRZERR_REMOVE_OBJECT (13)
|
||||||
|
#define STRZERR_GET_NEXT_PROP (14)
|
||||||
|
#define STRZERR_DIV_ZERO (15)
|
||||||
|
#define STRZERR_MOV_CURSOR (16)
|
||||||
|
#define STRICTZ_NUM_ERRORS (17)
|
||||||
|
|
||||||
|
#endif /* STRICTZ */
|
||||||
|
|
||||||
|
/* Global routines */
|
||||||
|
|
||||||
|
/* control.c */
|
||||||
|
|
||||||
|
void z_check_arg_count( zword_t );
|
||||||
|
int z_call( int, zword_t *, int );
|
||||||
|
void z_jump( zword_t );
|
||||||
|
void z_restart( void );
|
||||||
|
void restart_interp( int );
|
||||||
|
void z_ret( zword_t );
|
||||||
|
void z_catch( void );
|
||||||
|
void z_throw( zword_t, zword_t );
|
||||||
|
|
||||||
|
|
||||||
|
/* fileio.c */
|
||||||
|
|
||||||
|
void z_verify( void );
|
||||||
|
int z_restore( int, zword_t, zword_t, zword_t );
|
||||||
|
int z_save( int, zword_t, zword_t, zword_t );
|
||||||
|
void z_restore_undo( void );
|
||||||
|
void z_save_undo( void );
|
||||||
|
void z_open_playback( int );
|
||||||
|
void close_record( void );
|
||||||
|
void close_script( void );
|
||||||
|
void close_story( void );
|
||||||
|
void flush_script( void );
|
||||||
|
unsigned int get_story_size( void );
|
||||||
|
void open_record( void );
|
||||||
|
void open_script( void );
|
||||||
|
void open_story( const char * );
|
||||||
|
int playback_key( void );
|
||||||
|
int playback_line( int, char *, int * );
|
||||||
|
void read_page( int, void * );
|
||||||
|
void record_key( int );
|
||||||
|
void record_line( const char * );
|
||||||
|
void script_char( int );
|
||||||
|
void script_string( const char * );
|
||||||
|
void script_line( const char * );
|
||||||
|
void script_new_line( void );
|
||||||
|
|
||||||
|
|
||||||
|
/* getopt.c */
|
||||||
|
|
||||||
|
#ifndef HAVE_GETOPT
|
||||||
|
int getopt( int, char *[], const char * );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* input.c */
|
||||||
|
|
||||||
|
int get_line( char *, zword_t, zword_t );
|
||||||
|
void z_read_char( int, zword_t * );
|
||||||
|
void z_sread_aread( int, zword_t * );
|
||||||
|
void z_tokenise( int, zword_t * );
|
||||||
|
|
||||||
|
|
||||||
|
/* interpre.c */
|
||||||
|
|
||||||
|
int interpret( void );
|
||||||
|
|
||||||
|
|
||||||
|
/* license.c */
|
||||||
|
|
||||||
|
void print_license( void );
|
||||||
|
|
||||||
|
|
||||||
|
/* math.c */
|
||||||
|
|
||||||
|
void z_add( zword_t, zword_t );
|
||||||
|
void z_div( zword_t, zword_t );
|
||||||
|
void z_mul( zword_t, zword_t );
|
||||||
|
void z_sub( zword_t, zword_t );
|
||||||
|
void z_mod( zword_t, zword_t );
|
||||||
|
void z_or( zword_t, zword_t );
|
||||||
|
void z_and( zword_t, zword_t );
|
||||||
|
void z_not( zword_t );
|
||||||
|
void z_art_shift( zword_t, zword_t );
|
||||||
|
void z_log_shift( zword_t, zword_t );
|
||||||
|
void z_je( int, zword_t * );
|
||||||
|
void z_jg( zword_t, zword_t );
|
||||||
|
void z_jl( zword_t, zword_t );
|
||||||
|
void z_jz( zword_t );
|
||||||
|
void z_random( zword_t );
|
||||||
|
void z_test( zword_t, zword_t );
|
||||||
|
|
||||||
|
|
||||||
|
/* memory.c */
|
||||||
|
|
||||||
|
void load_cache( void );
|
||||||
|
void unload_cache( void );
|
||||||
|
zbyte_t read_code_byte( void );
|
||||||
|
zbyte_t read_data_byte( unsigned long * );
|
||||||
|
zword_t read_code_word( void );
|
||||||
|
zword_t read_data_word( unsigned long * );
|
||||||
|
|
||||||
|
|
||||||
|
/* object.c */
|
||||||
|
|
||||||
|
zword_t get_object_address( zword_t );
|
||||||
|
void z_insert_obj( zword_t, zword_t );
|
||||||
|
void z_remove_obj( zword_t );
|
||||||
|
void z_get_child( zword_t );
|
||||||
|
void z_get_sibling( zword_t );
|
||||||
|
void z_get_parent( zword_t );
|
||||||
|
void z_jin( zword_t, zword_t );
|
||||||
|
void z_clear_attr( zword_t, zword_t );
|
||||||
|
void z_set_attr( zword_t, zword_t );
|
||||||
|
void z_test_attr( zword_t, zword_t );
|
||||||
|
|
||||||
|
|
||||||
|
/* operand.c */
|
||||||
|
|
||||||
|
void z_piracy( int );
|
||||||
|
void z_store( int, zword_t );
|
||||||
|
void conditional_jump( int );
|
||||||
|
void store_operand( zword_t );
|
||||||
|
zword_t load_operand( int );
|
||||||
|
zword_t load_variable( int );
|
||||||
|
|
||||||
|
|
||||||
|
/* osdepend.c */
|
||||||
|
|
||||||
|
int codes_to_text( int, char * );
|
||||||
|
void fatal( const char * );
|
||||||
|
void file_cleanup( const char *, int );
|
||||||
|
int fit_line( const char *, int, int );
|
||||||
|
int get_file_name( char *, char *, int );
|
||||||
|
int print_status( int, char *[] );
|
||||||
|
//void process_arguments( int, char *[] );
|
||||||
|
void set_colours( zword_t, zword_t );
|
||||||
|
void set_font( int );
|
||||||
|
void sound( int, zword_t * );
|
||||||
|
|
||||||
|
|
||||||
|
/* property.c */
|
||||||
|
|
||||||
|
void z_get_next_prop( zword_t, zword_t );
|
||||||
|
void z_get_prop( zword_t, zword_t );
|
||||||
|
void z_get_prop_addr( zword_t, zword_t );
|
||||||
|
void z_get_prop_len( zword_t );
|
||||||
|
void z_put_prop( zword_t, zword_t, zword_t );
|
||||||
|
void z_copy_table( zword_t, zword_t, zword_t );
|
||||||
|
void z_scan_table( int, zword_t * );
|
||||||
|
void z_loadb( zword_t, zword_t );
|
||||||
|
void z_loadw( zword_t, zword_t );
|
||||||
|
void z_storeb( zword_t, zword_t, zword_t );
|
||||||
|
void z_storew( zword_t, zword_t, zword_t );
|
||||||
|
|
||||||
|
|
||||||
|
/* quetzal.c */
|
||||||
|
|
||||||
|
#ifdef USE_ZLIB
|
||||||
|
int save_quetzal( FILE *, gzFile * );
|
||||||
|
int restore_quetzal( FILE *, gzFile * );
|
||||||
|
#else
|
||||||
|
int save_quetzal( FILE *, FILE * );
|
||||||
|
int restore_quetzal( FILE *, FILE * );
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/* screen.c */
|
||||||
|
|
||||||
|
void z_show_status( void );
|
||||||
|
void z_set_cursor( zword_t, zword_t );
|
||||||
|
void z_set_font( zword_t );
|
||||||
|
void z_split_window( zword_t );
|
||||||
|
void z_set_window( zword_t );
|
||||||
|
void z_set_colour( zword_t, zword_t );
|
||||||
|
void z_erase_line( zword_t );
|
||||||
|
void z_erase_window( zword_t );
|
||||||
|
void z_print_table( int, zword_t * );
|
||||||
|
void blank_status_line( void );
|
||||||
|
void output_char( int );
|
||||||
|
void output_new_line( void );
|
||||||
|
void output_string( const char * );
|
||||||
|
void output_line( const char * );
|
||||||
|
|
||||||
|
|
||||||
|
/* screenio.c */
|
||||||
|
|
||||||
|
int input_character( int );
|
||||||
|
void clear_line( void );
|
||||||
|
void clear_screen( void );
|
||||||
|
void clear_status_window( void );
|
||||||
|
void clear_text_window( void );
|
||||||
|
void create_status_window( void );
|
||||||
|
void delete_status_window( void );
|
||||||
|
void display_char( int );
|
||||||
|
int fit_line( const char *, int, int );
|
||||||
|
void get_cursor_position( int *, int * );
|
||||||
|
void initialize_screen( void );
|
||||||
|
int input_line( int, char *, int, int * );
|
||||||
|
void move_cursor( int, int );
|
||||||
|
int print_status( int, char *[] );
|
||||||
|
void reset_screen( void );
|
||||||
|
void restart_screen( void );
|
||||||
|
void restore_cursor_position( void );
|
||||||
|
void save_cursor_position( void );
|
||||||
|
void scroll_line( void );
|
||||||
|
void select_status_window( void );
|
||||||
|
void select_text_window( void );
|
||||||
|
void set_attribute( int );
|
||||||
|
|
||||||
|
|
||||||
|
/* text.c */
|
||||||
|
|
||||||
|
void z_encode( zword_t, zword_t, zword_t, zword_t );
|
||||||
|
void z_new_line( void );
|
||||||
|
void z_print_char( zword_t );
|
||||||
|
void z_print_num( zword_t );
|
||||||
|
void z_print( void );
|
||||||
|
void z_print_addr( zword_t );
|
||||||
|
void z_print_paddr( zword_t );
|
||||||
|
void z_print_obj( zword_t );
|
||||||
|
void z_print_ret( void );
|
||||||
|
void z_buffer_mode( zword_t );
|
||||||
|
void z_output_stream( zword_t, zword_t );
|
||||||
|
void z_input_stream( int );
|
||||||
|
void z_set_text_style( zword_t );
|
||||||
|
void decode_text( unsigned long * );
|
||||||
|
void encode_text( int, const char *, ZINT16 * );
|
||||||
|
void flush_buffer( int );
|
||||||
|
void print_time( int, int );
|
||||||
|
void write_char( int );
|
||||||
|
void write_string( const char * );
|
||||||
|
void write_zchar( int );
|
||||||
|
|
||||||
|
|
||||||
|
/* variable.c */
|
||||||
|
|
||||||
|
void z_inc( zword_t );
|
||||||
|
void z_dec( zword_t );
|
||||||
|
void z_inc_chk( zword_t, zword_t );
|
||||||
|
void z_dec_chk( zword_t, zword_t );
|
||||||
|
void z_load( zword_t );
|
||||||
|
void z_pull( zword_t );
|
||||||
|
void z_push( zword_t );
|
||||||
|
|
||||||
|
#endif /* !defined(__ZTYPES_INCLUDED) */
|
Loading…
Add table
Reference in a new issue