aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2018-11-12 10:54:59 -0800
committerPaul Gilbert2018-12-08 19:05:59 -0800
commit7a52f21c0bb267d6851ede650298b1d084493ef6 (patch)
treebbc154228f0b19486d242d3aa1c22e6fb5472aa4
parent2c37a949136e4bd6a38daf420eb4638ce8d5f4ae (diff)
downloadscummvm-rg350-7a52f21c0bb267d6851ede650298b1d084493ef6.tar.gz
scummvm-rg350-7a52f21c0bb267d6851ede650298b1d084493ef6.tar.bz2
scummvm-rg350-7a52f21c0bb267d6851ede650298b1d084493ef6.zip
GLK: FROTZ: Added script/record/transcript/replay methods
-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
-rw-r--r--engines/gargoyle/glk.h4
-rw-r--r--engines/gargoyle/streams.cpp36
-rw-r--r--engines/gargoyle/streams.h6
7 files changed, 436 insertions, 60 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
diff --git a/engines/gargoyle/glk.h b/engines/gargoyle/glk.h
index a7a119866f..2f3620f876 100644
--- a/engines/gargoyle/glk.h
+++ b/engines/gargoyle/glk.h
@@ -66,7 +66,7 @@ public:
winid_t glk_window_open(winid_t split, glui32 method, glui32 size,
glui32 wintype, glui32 rock = 0) const;
- void glk_window_close(winid_t win, stream_result_t *result);
+ void glk_window_close(winid_t win, stream_result_t *result = nullptr);
void glk_window_get_size(winid_t win, glui32 *width, glui32 *height);
void glk_window_set_arrangement(winid_t win, glui32 method,
glui32 size, winid_t keyWin);
@@ -87,7 +87,7 @@ public:
strid_t glk_stream_open_file(frefid_t fileref, FileMode fmode, glui32 rock = 0);
strid_t glk_stream_open_memory(char *buf, glui32 buflen, FileMode fmode, glui32 rock = 0);
- void glk_stream_close(strid_t str, stream_result_t *result);
+ void glk_stream_close(strid_t str, stream_result_t *result = nullptr);
strid_t glk_stream_iterate(strid_t str, glui32 *rockptr) const;
glui32 glk_stream_get_rock(strid_t str) const;
void glk_stream_set_position(strid_t str, glsi32 pos, glui32 seekMode);
diff --git a/engines/gargoyle/streams.cpp b/engines/gargoyle/streams.cpp
index 41f3caf1b4..d5671f136a 100644
--- a/engines/gargoyle/streams.cpp
+++ b/engines/gargoyle/streams.cpp
@@ -458,32 +458,30 @@ glui32 MemoryStream::getPosition() const {
return ((unsigned char *)_bufPtr - (unsigned char *)_buf);
}
-void MemoryStream::setPosition(glui32 pos, glui32 seekMode) {
- glsi32 newPos = pos;
-
+void MemoryStream::setPosition(glsi32 pos, glui32 seekMode) {
if (!_unicode) {
if (seekMode == seekmode_Current)
- newPos = ((unsigned char *)_bufPtr - (unsigned char *)_buf) + newPos;
+ pos = ((unsigned char *)_bufPtr - (unsigned char *)_buf) + pos;
else if (seekMode == seekmode_End)
- newPos = ((unsigned char *)_bufEof - (unsigned char *)_buf) + newPos;
+ pos = ((unsigned char *)_bufEof - (unsigned char *)_buf) + pos;
else
- /* newPos = newPos */;
- if (newPos < 0)
- newPos = 0;
- if (newPos > ((unsigned char *)_bufEof - (unsigned char *)_buf))
- newPos = ((unsigned char *)_bufEof - (unsigned char *)_buf);
- _bufPtr = (unsigned char *)_buf + newPos;
+ /* pos = pos */;
+ if (pos < 0)
+ pos = 0;
+ if (pos > ((unsigned char *)_bufEof - (unsigned char *)_buf))
+ pos = ((unsigned char *)_bufEof - (unsigned char *)_buf);
+ _bufPtr = (unsigned char *)_buf + pos;
} else {
if (seekMode == seekmode_Current)
- newPos = ((glui32 *)_bufPtr - (glui32 *)_buf) + newPos;
+ pos = ((glui32 *)_bufPtr - (glui32 *)_buf) + pos;
else if (seekMode == seekmode_End)
- newPos = ((glui32 *)_bufEof - (glui32 *)_buf) + newPos;
+ pos = ((glui32 *)_bufEof - (glui32 *)_buf) + pos;
- if (newPos < 0)
- newPos = 0;
- if (newPos > ((glui32 *)_bufEof - (glui32 *)_buf))
- newPos = ((glui32 *)_bufEof - (glui32 *)_buf);
- _bufPtr = (glui32 *)_buf + newPos;
+ if (pos < 0)
+ pos = 0;
+ if (pos > ((glui32 *)_bufEof - (glui32 *)_buf))
+ pos = ((glui32 *)_bufEof - (glui32 *)_buf);
+ _bufPtr = (glui32 *)_buf + pos;
}
}
@@ -1000,7 +998,7 @@ glui32 FileStream::getPosition() const {
return _outFile ? _outFile->pos() : _inStream->pos();
}
-void FileStream::setPosition(glui32 pos, glui32 seekMode) {
+void FileStream::setPosition(glsi32 pos, glui32 seekMode) {
_lastOp = 0;
if (_unicode)
pos *= 4;
diff --git a/engines/gargoyle/streams.h b/engines/gargoyle/streams.h
index 772b0215c2..ea9c651e45 100644
--- a/engines/gargoyle/streams.h
+++ b/engines/gargoyle/streams.h
@@ -223,7 +223,7 @@ public:
return 0;
}
- virtual void setPosition(glui32 pos, glui32 seekMode) {}
+ virtual void setPosition(glsi32 pos, glui32 seekMode) {}
virtual void setStyle(glui32 val) {}
@@ -390,7 +390,7 @@ public:
virtual glui32 getPosition() const override;
- virtual void setPosition(glui32 pos, glui32 seekMode) override;
+ virtual void setPosition(glsi32 pos, glui32 seekMode) override;
/**
* Get a character from the stream
@@ -492,7 +492,7 @@ public:
virtual glui32 getPosition() const override;
- virtual void setPosition(glui32 pos, glui32 seekMode) override;
+ virtual void setPosition(glsi32 pos, glui32 seekMode) override;
/**
* Get a character from the stream