1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "glk/frotz/processor.h"
24
25 namespace Glk {
26 namespace Frotz {
27
flagsChanged(zbyte value)28 void Processor::flagsChanged(zbyte value) {
29 if (value & SCRIPTING_FLAG) {
30 if (!ostream_script)
31 script_open();
32 } else {
33 if (ostream_script)
34 script_close();
35 }
36 }
37
save_undo()38 int Processor::save_undo() {
39 long diff_size;
40 zword stack_size;
41 undo_t *p;
42
43 if (_undo_slots == 0)
44 // undo feature unavailable
45 return -1;
46
47 // save undo possible
48 while (last_undo != curr_undo) {
49 p = last_undo;
50 last_undo = last_undo->prev;
51 delete p;
52 undo_count--;
53 }
54 if (last_undo)
55 last_undo->next = nullptr;
56 else
57 first_undo = nullptr;
58
59 if (undo_count == _undo_slots)
60 free_undo(1);
61
62 diff_size = mem_diff(zmp, prev_zmp, h_dynamic_size, undo_diff);
63 stack_size = _stack + STACK_SIZE - _sp;
64 do {
65 p = (undo_t *) malloc(sizeof(undo_t) + diff_size + stack_size * sizeof(*_sp));
66 if (p == nullptr)
67 free_undo(1);
68 } while (!p && undo_count);
69 if (p == nullptr)
70 return -1;
71
72 GET_PC(p->pc);
73 p->frame_count = _frameCount;
74 p->diff_size = diff_size;
75 p->stack_size = stack_size;
76 p->frame_offset = _fp - _stack;
77 memcpy(p + 1, undo_diff, diff_size);
78 memcpy((zbyte *)(p + 1) + diff_size, _sp, stack_size * sizeof(*_sp));
79
80 if (!first_undo) {
81 p->prev = nullptr;
82 first_undo = p;
83 } else {
84 last_undo->next = p;
85 p->prev = last_undo;
86 }
87
88 p->next = nullptr;
89 curr_undo = last_undo = p;
90 undo_count++;
91
92 return 1;
93 }
94
restore_undo(void)95 int Processor::restore_undo(void) {
96 if (_undo_slots == 0)
97 // undo feature unavailable
98 return -1;
99
100 if (curr_undo == nullptr)
101 // no saved game state
102 return 0;
103
104 // undo possible
105 memcpy(zmp, prev_zmp, h_dynamic_size);
106 SET_PC(curr_undo->pc);
107 _sp = _stack + STACK_SIZE - curr_undo->stack_size;
108 _fp = _stack + curr_undo->frame_offset;
109 _frameCount = curr_undo->frame_count;
110 mem_undiff((zbyte *)(curr_undo + 1), curr_undo->diff_size, prev_zmp);
111 memcpy(_sp, (zbyte *)(curr_undo + 1) + curr_undo->diff_size,
112 curr_undo->stack_size * sizeof(*_sp));
113
114 curr_undo = curr_undo->prev;
115
116 restart_header();
117
118 return 2;
119 }
120
121 /**
122 * TOR: glkify -- this is for V6 only
123 */
get_max_width(zword win)124 static zword get_max_width(zword win) { return 80; }
125
memory_open(zword table,zword xsize,bool buffering)126 void Processor::memory_open(zword table, zword xsize, bool buffering) {
127 if (_redirect.size() < MAX_NESTING) {
128 if (!buffering)
129 xsize = 0xffff;
130 if (buffering && (short)xsize <= 0)
131 xsize = get_max_width((zword)(-(short)xsize));
132
133 storew(table, 0);
134
135 _redirect.push(Redirect(xsize, table));
136 ostream_memory = true;
137 } else {
138 runtimeError(ERR_STR3_NESTING);
139 }
140 }
141
memory_new_line()142 void Processor::memory_new_line() {
143 zword size;
144 zword addr;
145
146 Redirect &r = _redirect.top();
147 r._total += r._width;
148 r._width = 0;
149
150 addr = r._table;
151
152 LOW_WORD(addr, size);
153 addr += 2;
154
155 if (r._xSize != 0xffff) {
156 r._table = addr + size;
157 size = 0;
158 } else {
159 storeb((zword)(addr + (size++)), 13);
160 }
161
162 storew(r._table, size);
163 }
164
memory_word(const zchar * s)165 void Processor::memory_word(const zchar *s) {
166 zword size;
167 zword addr;
168 zchar c;
169
170 Redirect &r = _redirect.top();
171 if (h_version == V6) {
172 int width = os_string_width(s);
173
174 if (r._xSize != 0xffff) {
175 if (r._width + width > r._xSize) {
176
177 if (*s == ' ' || *s == ZC_INDENT || *s == ZC_GAP)
178 width = os_string_width(++s);
179
180 memory_new_line();
181 }
182 }
183
184 r._width += width;
185 }
186
187 addr = r._table;
188
189 LOW_WORD(addr, size);
190 addr += 2;
191
192 while ((c = *s++) != 0)
193 storeb((zword)(addr + (size++)), translate_to_zscii(c));
194
195 storew(r._table, size);
196 }
197
memory_close(void)198 void Processor::memory_close(void) {
199 if (!_redirect.empty()) {
200 Redirect &r = _redirect.top();
201
202 if (r._xSize != 0xffff)
203 memory_new_line();
204
205 if (h_version == V6) {
206 h_line_width = (r._xSize != 0xffff) ? r._total : r._width;
207
208 SET_WORD(H_LINE_WIDTH, h_line_width);
209 }
210
211 _redirect.pop();
212 if (_redirect.empty())
213 ostream_memory = false;
214 }
215 }
216
217 } // End of namespace Frotz
218 } // End of namespace Glk
219