aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Gilbert2018-11-12 08:41:57 -0800
committerPaul Gilbert2018-12-08 19:05:59 -0800
commite1de76b491e5145b837b55f7313b8fff07986572 (patch)
treeec19cc14fc5c629533787e6ab6370da89c858d52
parent5507242395a0b183b8f445ca5a56284d974687f2 (diff)
downloadscummvm-rg350-e1de76b491e5145b837b55f7313b8fff07986572.tar.gz
scummvm-rg350-e1de76b491e5145b837b55f7313b8fff07986572.tar.bz2
scummvm-rg350-e1de76b491e5145b837b55f7313b8fff07986572.zip
GLK: FROTZ: Added remaining memory methods
-rw-r--r--engines/gargoyle/frotz/mem.cpp97
-rw-r--r--engines/gargoyle/frotz/mem.h25
-rw-r--r--engines/gargoyle/frotz/processor.h12
-rw-r--r--engines/gargoyle/frotz/processor_input.cpp1
-rw-r--r--engines/gargoyle/frotz/processor_mem.cpp83
5 files changed, 217 insertions, 1 deletions
diff --git a/engines/gargoyle/frotz/mem.cpp b/engines/gargoyle/frotz/mem.cpp
index 57b282531d..ad60b89bbb 100644
--- a/engines/gargoyle/frotz/mem.cpp
+++ b/engines/gargoyle/frotz/mem.cpp
@@ -320,6 +320,103 @@ void Mem::storew(zword addr, zword value) {
storeb((zword)(addr + 1), lo(value));
}
+void Mem::free_undo(int count) {
+ undo_t *p;
+
+ if (count > undo_count)
+ count = undo_count;
+ while (count--) {
+ p = first_undo;
+ if (curr_undo == first_undo)
+ curr_undo = curr_undo->next;
+ first_undo = first_undo->next;
+ free(p);
+ undo_count--;
+ }
+ if (first_undo)
+ first_undo->prev = NULL;
+ else
+ last_undo = NULL;
+}
+
+void Mem::reset_memory() {
+ story_fp = nullptr;
+ blorb_ofs = 0;
+ blorb_len = 0;
+
+ if (undo_mem) {
+ free_undo(undo_count);
+ delete undo_mem;
+ }
+
+ undo_mem = nullptr;
+ undo_count = 0;
+ delete[] zmp;
+ zmp = nullptr;
+}
+
+long Mem::mem_diff(zbyte *a, zbyte *b, zword mem_size, zbyte *diff) {
+ unsigned size = mem_size;
+ zbyte *p = diff;
+ unsigned j;
+ zbyte c = 0;
+
+ for (;;) {
+ for (j = 0; size > 0 && (c = *a++ ^ *b++) == 0; j++)
+ size--;
+ if (size == 0) break;
+ size--;
+ if (j > 0x8000) {
+ *p++ = 0;
+ *p++ = 0xff;
+ *p++ = 0xff;
+ j -= 0x8000;
+ }
+ if (j > 0) {
+ *p++ = 0;
+ j--;
+ if (j <= 0x7f) {
+ *p++ = j;
+ } else {
+ *p++ = (j & 0x7f) | 0x80;
+ *p++ = (j & 0x7f80) >> 7;
+ }
+ }
+
+ *p++ = c;
+ *(b - 1) ^= c;
+ }
+
+ return p - diff;
+}
+
+void Mem::mem_undiff(zbyte *diff, long diff_length, zbyte *dest) {
+ zbyte c;
+
+ while (diff_length) {
+ c = *diff++;
+ diff_length--;
+ if (c == 0) {
+ unsigned runlen;
+
+ if (!diff_length)
+ return; // Incomplete run
+ runlen = *diff++;
+ diff_length--;
+ if (runlen & 0x80) {
+ if (!diff_length)
+ return; // Incomplete extended run
+ c = *diff++;
+ diff_length--;
+ runlen = (runlen & 0x7f) | (((unsigned)c) << 7);
+ }
+
+ dest += runlen + 1;
+ } else {
+ *dest++ ^= c;
+ }
+ }
+}
} // End of namespace Scott
} // End of namespace Gargoyle
diff --git a/engines/gargoyle/frotz/mem.h b/engines/gargoyle/frotz/mem.h
index c128994df1..a45eec5e7f 100644
--- a/engines/gargoyle/frotz/mem.h
+++ b/engines/gargoyle/frotz/mem.h
@@ -230,6 +230,11 @@ protected:
void storew(zword addr, zword value);
/**
+ * Free count undo blocks from the beginning of the undo list
+ */
+ void free_undo(int count);
+
+ /**
* Generates a runtime error
*/
virtual void runtimeError(ErrorCode errNum) = 0;
@@ -238,6 +243,26 @@ protected:
* Called when the flags are changed
*/
virtual void flagsChanged(zbyte value) = 0;
+
+ /**
+ * Close the story file and deallocate memory.
+ */
+ void reset_memory();
+
+ /**
+ * Set diff to a Quetzal-like difference between a and b,
+ * copying a to b as we go. It is assumed that diff points to a
+ * buffer which is large enough to hold the diff.
+ * mem_size is the number of bytes to compare.
+ * Returns the number of bytes copied to diff.
+ *
+ */
+ long mem_diff(zbyte *a, zbyte *b, zword mem_size, zbyte *diff);
+
+ /**
+ * Applies a quetzal-like diff to dest
+ */
+ void mem_undiff(zbyte *diff, long diff_length, zbyte *dest);
public:
/**
* Constructor
diff --git a/engines/gargoyle/frotz/processor.h b/engines/gargoyle/frotz/processor.h
index b70bf440a2..f9352ec19c 100644
--- a/engines/gargoyle/frotz/processor.h
+++ b/engines/gargoyle/frotz/processor.h
@@ -220,6 +220,18 @@ private:
virtual void flagsChanged(zbyte value) override;
/**
+ * This function does the dirty work for z_save_undo.
+ */
+ int save_undo();
+
+ /**
+ * This function does the dirty work for z_restore_undo.
+ */
+ int restore_undo();
+
+ /**@}*/
+
+ /**
* \defgroup Object support methods
* @{
*/
diff --git a/engines/gargoyle/frotz/processor_input.cpp b/engines/gargoyle/frotz/processor_input.cpp
index b9c9604183..48951d2402 100644
--- a/engines/gargoyle/frotz/processor_input.cpp
+++ b/engines/gargoyle/frotz/processor_input.cpp
@@ -26,7 +26,6 @@ namespace Gargoyle {
namespace Frotz {
// TODO: Implement method stubs
-static void save_undo() {}
static zword os_read_mouse() { return 0; }
diff --git a/engines/gargoyle/frotz/processor_mem.cpp b/engines/gargoyle/frotz/processor_mem.cpp
index 1f3944ea17..71abe77c1f 100644
--- a/engines/gargoyle/frotz/processor_mem.cpp
+++ b/engines/gargoyle/frotz/processor_mem.cpp
@@ -35,5 +35,88 @@ void Processor::flagsChanged(zbyte value) {
}
}
+int Processor::save_undo() {
+ long diff_size;
+ zword stack_size;
+ undo_t *p;
+
+ if (_undo_slots == 0)
+ // undo feature unavailable
+ return -1;
+
+ // save undo possible
+ while (last_undo != curr_undo) {
+ p = last_undo;
+ last_undo = last_undo->prev;
+ delete p;
+ undo_count--;
+ }
+ if (last_undo)
+ last_undo->next = nullptr;
+ else
+ first_undo = nullptr;
+
+ if (undo_count == _undo_slots)
+ free_undo(1);
+
+ diff_size = mem_diff(zmp, prev_zmp, h_dynamic_size, undo_diff);
+ stack_size = _stack + STACK_SIZE - _sp;
+ do {
+ p = (undo_t *) malloc(sizeof(undo_t) + diff_size + stack_size * sizeof(*_sp));
+ if (p == nullptr)
+ free_undo(1);
+ } while (!p && undo_count);
+ if (p == nullptr)
+ return -1;
+
+ GET_PC(p->pc);
+ p->frame_count = _frameCount;
+ p->diff_size = diff_size;
+ p->stack_size = stack_size;
+ p->frame_offset = _fp - _stack;
+ memcpy(p + 1, undo_diff, diff_size);
+ memcpy((zbyte *)(p + 1) + diff_size, _sp, stack_size * sizeof(*_sp));
+
+ if (!first_undo) {
+ p->prev = nullptr;
+ first_undo = p;
+ } else {
+ last_undo->next = p;
+ p->prev = last_undo;
+ }
+
+ p->next = nullptr;
+ curr_undo = last_undo = p;
+ undo_count++;
+
+ return 1;
+}
+
+int Processor::restore_undo(void) {
+ if (_undo_slots == 0)
+ // undo feature unavailable
+ return -1;
+
+ if (curr_undo == nullptr)
+ // no saved game state
+ return 0;
+
+ // undo possible
+ memcpy(zmp, prev_zmp, h_dynamic_size);
+ SET_PC(curr_undo->pc);
+ _sp = _stack + STACK_SIZE - curr_undo->stack_size;
+ _fp = _stack + curr_undo->frame_offset;
+ _frameCount = curr_undo->frame_count;
+ mem_undiff((zbyte *)(curr_undo + 1), curr_undo->diff_size, prev_zmp);
+ memcpy(_sp, (zbyte *)(curr_undo + 1) + curr_undo->diff_size,
+ curr_undo->stack_size * sizeof(*_sp));
+
+ curr_undo = curr_undo->prev;
+
+ restart_header();
+
+ return 2;
+}
+
} // End of namespace Scott
} // End of namespace Gargoyle