aboutsummaryrefslogtreecommitdiff
path: root/engines/gargoyle/frotz
diff options
context:
space:
mode:
authorPaul Gilbert2018-11-12 10:54:59 -0800
committerPaul Gilbert2018-12-08 19:05:59 -0800
commit7a52f21c0bb267d6851ede650298b1d084493ef6 (patch)
treebbc154228f0b19486d242d3aa1c22e6fb5472aa4 /engines/gargoyle/frotz
parent2c37a949136e4bd6a38daf420eb4638ce8d5f4ae (diff)
downloadscummvm-rg350-7a52f21c0bb267d6851ede650298b1d084493ef6.tar.gz
scummvm-rg350-7a52f21c0bb267d6851ede650298b1d084493ef6.tar.bz2
scummvm-rg350-7a52f21c0bb267d6851ede650298b1d084493ef6.zip
GLK: FROTZ: Added script/record/transcript/replay methods
Diffstat (limited to 'engines/gargoyle/frotz')
-rw-r--r--engines/gargoyle/frotz/processor.cpp3
-rw-r--r--engines/gargoyle/frotz/processor.h101
-rw-r--r--engines/gargoyle/frotz/processor_input.cpp40
-rw-r--r--engines/gargoyle/frotz/processor_streams.cpp306
4 files changed, 414 insertions, 36 deletions
diff --git a/engines/gargoyle/frotz/processor.cpp b/engines/gargoyle/frotz/processor.cpp
index 934101332d..ac18a23593 100644
--- a/engines/gargoyle/frotz/processor.cpp
+++ b/engines/gargoyle/frotz/processor.cpp
@@ -136,7 +136,8 @@ Processor::Processor(OSystem *syst, const GargoyleGameDescription *gameDesc) :
_finished(0), _sp(nullptr), _fp(nullptr), _frameCount(0),
zargc(0), _decoded(nullptr), _encoded(nullptr), _resolution(0),
_randomInterval(0), _randomCtr(0), first_restart(true), script_valid(false),
- _bufPos(0), _locked(false), _prevC('\0') {
+ _bufPos(0), _locked(false), _prevC('\0'), script_width(0),
+ sfp(nullptr), rfp(nullptr), pfp(nullptr) {
static const Opcode OP0_OPCODES[16] = {
&Processor::z_rtrue,
&Processor::z_rfalse,
diff --git a/engines/gargoyle/frotz/processor.h b/engines/gargoyle/frotz/processor.h
index f9352ec19c..50c951a589 100644
--- a/engines/gargoyle/frotz/processor.h
+++ b/engines/gargoyle/frotz/processor.h
@@ -79,6 +79,10 @@ private:
Opcode op1_opcodes[16];
static Opcode var_opcodes[64];
static Opcode ext_opcodes[64];
+
+ // Stream related fields
+ int script_width;
+ strid_t sfp, rfp, pfp;
private:
/**
* \defgroup General support methods
@@ -358,7 +362,102 @@ private:
*/
void script_close();
- /**@}*/
+ /**
+ * Write a newline to the transscript file.
+ */
+ void script_new_line();
+
+ /**
+ * Write a single character to the transscript file.
+ */
+ void script_char(zchar c);
+
+ /**
+ * Write a string to the transscript file.
+ */
+ void script_word(const zchar *s);
+
+ /**
+ * Send an input line to the transscript file.
+ */
+ void script_write_input(const zchar *buf, zchar key);
+
+ /**
+ * Remove an input line from the transscript file.
+ */
+ void script_erase_input(const zchar *buf);
+
+ /**
+ * Start sending a "debugging" message to the transscript file.
+ */
+ void script_mssg_on();
+
+ /**
+ * Stop writing a "debugging" message.
+ */
+ void script_mssg_off();
+
+ /**
+ * Open a file to record the player's input.
+ */
+ void record_open();
+
+ /**
+ * Stop recording the player's input.
+ */
+ void record_close();
+
+ /**
+ * Helper function for record_char.
+ */
+ void record_code(int c, bool force_encoding);
+
+ /**
+ * Write a character to the command file.
+ */
+ void record_char(zchar c);
+
+ /**
+ * Copy a keystroke to the command file.
+ */
+ void record_write_key(zchar key);
+
+ /**
+ * Copy a line of input to a command file.
+ */
+ void record_write_input(const zchar *buf, zchar key);
+
+ /**
+ * Open a file of commands for playback.
+ */
+ void replay_open();
+
+ /**
+ * Stop playback of commands.
+ */
+ void replay_close();
+
+ /*
+ * Helper function for replay_key and replay_line.
+ */
+ int replay_code();
+
+ /**
+ * Read a character from the command file.
+ */
+ zchar replay_char();
+
+ /**
+ * Read a keystroke from a command file.
+ */
+ zchar replay_read_key();
+
+ /*
+ * Read a line of input from a command file.
+ */
+ zchar replay_read_input(zchar *buf);
+
+ /**@}*/
/**
* \defgroup Text support methods
diff --git a/engines/gargoyle/frotz/processor_input.cpp b/engines/gargoyle/frotz/processor_input.cpp
index 48951d2402..89aa1889fd 100644
--- a/engines/gargoyle/frotz/processor_input.cpp
+++ b/engines/gargoyle/frotz/processor_input.cpp
@@ -31,13 +31,6 @@ static zword os_read_mouse() { return 0; }
#define INPUT_BUFFER_SIZE 200
-void Processor::z_make_menu() {
- // This opcode was only used for the Macintosh version of Journey.
- // It controls menus with numbers greater than 2 (menus 0, 1 and 2
- // are system menus).
- branch (false);
-}
-
bool Processor::read_yes_or_no(const char *s) {
zchar key;
@@ -65,6 +58,39 @@ void Processor::read_string(int max, zchar *buffer) {
} while (key != ZC_RETURN);
}
+bool Processor::is_terminator(zchar key) {
+ if (key == ZC_TIME_OUT)
+ return true;
+ if (key == ZC_RETURN)
+ return true;
+ if (key >= ZC_HKEY_MIN && key <= ZC_HKEY_MAX)
+ return true;
+
+ if (h_terminating_keys != 0) {
+ if (key >= ZC_ARROW_MIN && key <= ZC_MENU_CLICK) {
+
+ zword addr = h_terminating_keys;
+ zbyte c;
+
+ do {
+ LOW_BYTE(addr, c);
+ if (c == 255 || key == translate_from_zscii(c))
+ return true;
+ addr++;
+ } while (c != 0);
+ }
+ }
+
+ return false;
+}
+
+void Processor::z_make_menu() {
+ // This opcode was only used for the Macintosh version of Journey.
+ // It controls menus with numbers greater than 2 (menus 0, 1 and 2
+ // are system menus).
+ branch(false);
+}
+
int Processor::read_number() {
zchar buffer[6];
int value = 0;
diff --git a/engines/gargoyle/frotz/processor_streams.cpp b/engines/gargoyle/frotz/processor_streams.cpp
index 44062757ef..95205a58bd 100644
--- a/engines/gargoyle/frotz/processor_streams.cpp
+++ b/engines/gargoyle/frotz/processor_streams.cpp
@@ -28,30 +28,15 @@ namespace Frotz {
// TODO: Implement method stubs
static void os_scrollback_char(zchar) {}
static void os_scrollback_erase(zword) {}
-static void script_mssg_on() {}
-static void script_mssg_off() {}
-static void script_char(zchar) {}
-static void script_word(const zchar *) {}
-static void script_new_line() {}
-static void script_erase_input(const zchar *) {}
-static void script_write_input(zchar *, char) {}
static void memory_open(zword, zword, bool) {}
static void memory_close() {}
static void memory_word(const zchar *) {}
static void memory_new_line() {}
-static void replay_open() {}
-static void replay_close() {}
-static zchar replay_read_key() { return 0; }
-static zchar replay_read_input(zchar *) { return 0; }
static zchar console_read_key(zword) { return 0; }
static zchar console_read_input(uint, zchar *, uint, bool) { return 0; }
-static void record_open() {}
-static void record_close() {}
-static void record_write_key(zchar) {}
-static void record_write_input(zchar *, zchar) {}
-void Processor::scrollback_char (zchar c) {
+void Processor::scrollback_char(zchar c) {
if (c == ZC_INDENT)
{ scrollback_char (' '); scrollback_char (' '); scrollback_char (' '); return; }
if (c == ZC_GAP)
@@ -219,13 +204,282 @@ continue_input:
}
void Processor::script_open() {
- // TODO
+ h_flags &= ~SCRIPTING_FLAG;
+
+ frefid_t fref = glk_fileref_create_by_prompt(fileusage_Transcript,
+ filemode_WriteAppend);
+ sfp = glk_stream_open_file(fref, filemode_WriteAppend);
+
+ if (sfp != nullptr) {
+ sfp->setPosition(0, seekmode_End);
+
+ h_flags |= SCRIPTING_FLAG;
+
+ script_valid = true;
+ ostream_script = true;
+
+ script_width = 0;
+ } else {
+ print_string("Cannot open file\n");
+ }
+
+ SET_WORD(H_FLAGS, h_flags);
}
void Processor::script_close() {
- // TODO
+ h_flags &= ~SCRIPTING_FLAG;
+ SET_WORD(H_FLAGS, h_flags);
+
+ glk_stream_close(sfp);
+ ostream_script = false;
+}
+
+void Processor::script_new_line() {
+ script_char('\n');
+ script_width = 0;
+}
+
+void Processor::script_char(zchar c) {
+ if (c == ZC_INDENT && script_width != 0)
+ c = ' ';
+
+ if (c == ZC_INDENT) {
+ script_char(' ');
+ script_char(' ');
+ script_char(' ');
+ return;
+ }
+ if (c == ZC_GAP) {
+ script_char(' ');
+ script_char(' ');
+ return;
+ }
+
+ sfp->putCharUni(c);
+ script_width++;
+}
+
+void Processor::script_word(const zchar *s) {
+ int width;
+ int i;
+
+ if (*s == ZC_INDENT && script_width != 0)
+ script_char(*s++);
+
+ for (i = 0, width = 0; s[i] != 0; i++) {
+ if (s[i] == ZC_NEW_STYLE || s[i] == ZC_NEW_FONT)
+ i++;
+ else if (s[i] == ZC_GAP)
+ width += 3;
+ else if (s[i] == ZC_INDENT)
+ width += 2;
+ else
+ width += 1;
+ }
+
+ if (_script_cols != 0 && script_width + width > _script_cols) {
+ if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
+ s++;
+
+ script_new_line();
+ }
+
+ for (i = 0; s[i] != 0; i++) {
+ if (s[i] == ZC_NEW_FONT || s[i] == ZC_NEW_STYLE)
+ i++;
+ else
+ script_char(s[i]);
+ }
+}
+
+void Processor::script_write_input(const zchar *buf, zchar key) {
+ int width;
+ int i;
+
+ for (i = 0, width = 0; buf[i] != 0; i++)
+ width++;
+
+ if (_script_cols != 0 && script_width + width > _script_cols)
+ script_new_line();
+
+ for (i = 0; buf[i] != 0; i++)
+ script_char(buf[i]);
+
+ if (key == ZC_RETURN)
+ script_new_line();
+}
+
+void Processor::script_erase_input(const zchar *buf) {
+ int width;
+ int i;
+
+ for (i = 0, width = 0; buf[i] != 0; i++)
+ width++;
+
+ sfp->setPosition(-width, seekmode_Current);
+ script_width -= width;
+}
+
+void Processor::script_mssg_on() {
+ if (script_width != 0)
+ script_new_line();
+
+ script_char(ZC_INDENT);
+}
+
+void Processor::script_mssg_off() {
+ script_new_line();
+}
+
+void Processor::record_open() {
+ frefid_t fref = glk_fileref_create_by_prompt(fileusage_Transcript, filemode_Write);
+ if ((rfp = glk_stream_open_file(fref, filemode_Write)) != nullptr)
+ ostream_record = true;
+ else
+ print_string("Cannot open file\n");
+}
+
+void Processor::record_close() {
+ glk_stream_close(rfp);
+ ostream_record = false;
+}
+
+void Processor::record_code(int c, bool force_encoding) {
+ if (force_encoding || c == '[' || c < 0x20 || c > 0x7e) {
+ int i;
+
+ rfp->putChar('[');
+
+ for (i = 10000; i != 0; i /= 10)
+ if (c >= i || i == 1)
+ rfp->putChar('0' + (c / i) % 10);
+
+ rfp->putChar(']');
+ } else {
+ rfp->putChar(c);
+ }
+}
+
+void Processor::record_char(zchar c) {
+ if (c != ZC_RETURN) {
+ if (c < ZC_HKEY_MIN || c > ZC_HKEY_MAX) {
+ record_code(translate_to_zscii(c), false);
+ if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
+ record_code(mouse_x, true);
+ record_code(mouse_y, true);
+ }
+ } else {
+ record_code(1000 + c - ZC_HKEY_MIN, true);
+ }
+ }
+}
+
+void Processor::record_write_key(zchar key) {
+ record_char(key);
+ rfp->putChar('\n');
+}
+
+void Processor::record_write_input(const zchar *buf, zchar key) {
+ zchar c;
+
+ while ((c = *buf++) != 0)
+ record_char(c);
+
+ record_write_key(key);
+}
+
+void Processor::replay_open() {
+ frefid_t fref = glk_fileref_create_by_prompt(fileusage_Transcript, filemode_Read);
+ if ((pfp = glk_stream_open_file(fref, filemode_Read)) != nullptr)
+ istream_replay = true;
+ else
+ print_string("Cannot open file\n");
+}
+
+void Processor::replay_close() {
+ glk_stream_close(pfp);
+ istream_replay = false;
}
+int Processor::replay_code() {
+ int c;
+
+ if ((c = pfp->getChar()) == '[') {
+ int c2;
+
+ c = 0;
+
+ while ((c2 = pfp->getChar()) != EOF && c2 >= '0' && c2 <= '9')
+ c = 10 * c + c2 - '0';
+
+ return (c2 == ']') ? c : EOF;
+ } else {
+ return c;
+ }
+}
+
+zchar Processor::replay_char() {
+ int c;
+
+ if ((c = replay_code()) != EOF) {
+ if (c != '\n') {
+ if (c < 1000) {
+
+ c = translate_from_zscii(c);
+
+ if (c == ZC_SINGLE_CLICK || c == ZC_DOUBLE_CLICK) {
+ mouse_x = replay_code();
+ mouse_y = replay_code();
+ }
+
+ return c;
+ } else {
+ return ZC_HKEY_MIN + c - 1000;
+ }
+ }
+
+ pfp->unputBuffer("\n", 1);
+ return ZC_RETURN;
+
+ } else {
+ return ZC_BAD;
+ }
+}
+
+zchar Processor::replay_read_key() {
+ zchar key = replay_char();
+
+ if (pfp->getChar() != '\n') {
+ replay_close();
+ return ZC_BAD;
+ } else {
+ return key;
+ }
+}
+
+zchar Processor::replay_read_input(zchar *buf) {
+ zchar c;
+
+ for (;;) {
+ c = replay_char();
+
+ if (c == ZC_BAD || is_terminator(c))
+ break;
+
+ *buf++ = c;
+ }
+
+ *buf = 0;
+
+ if (pfp->getChar() != '\n') {
+ replay_close();
+ return ZC_BAD;
+ } else {
+ return c;
+ }
+}
+
+
void Processor::z_input_stream() {
flush_buffer();
@@ -260,7 +514,7 @@ void Processor::z_output_stream() {
}
}
-void Processor::z_restart(void) {
+void Processor::z_restart() {
flush_buffer();
os_restart_game(RESTART_BEGIN);
@@ -293,8 +547,7 @@ void Processor::z_restart(void) {
os_restart_game(RESTART_END);
}
-
-void Processor::z_save(void) {
+void Processor::z_save() {
#ifdef TODO
bool success = false;
@@ -310,8 +563,7 @@ void Processor::z_save(void) {
glk_put_buffer_stream(f, (const char *)zmp + zargs[0], zargs[1]);
- stream_result_t result;
- glk_stream_close(f, &result);
+ glk_stream_close(f);
} else {
long pc;
@@ -430,8 +682,8 @@ void Processor::z_restore() {
release = (unsigned) fgetc (gfp) << 8;
release |= fgetc (gfp);
- (void) fgetc (gfp);
- (void) fgetc (gfp);
+ () fgetc (gfp);
+ () fgetc (gfp);
/* Check the release number */
@@ -460,7 +712,7 @@ void Processor::z_restore() {
for (i = 0; i < skip; i++)
zmp[addr++] = fgetc (story_fp);
zmp[addr] = fgetc (gfp);
- (void) fgetc (story_fp);
+ () fgetc (story_fp);
}
/* Check for errors */
@@ -519,7 +771,7 @@ finished:
#endif
}
-void Processor::z_verify(void) {
+void Processor::z_verify() {
zword checksum = 0;
// Sum all bytes in story file except header bytes