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/alan3/state.h"
24 #include "glk/alan3/syserr.h"
25 #include "glk/alan3/current.h"
26 #include "glk/alan3/word.h"
27 #include "glk/alan3/state_stack.h"
28 #include "glk/alan3/instance.h"
29 #include "glk/alan3/attribute.h"
30 #include "glk/alan3/memory.h"
31 #include "glk/alan3/score.h"
32 #include "glk/alan3/event.h"
33 #include "glk/alan3/set.h"
34
35 namespace Glk {
36 namespace Alan3 {
37
38 /* PRIVATE TYPES */
39
40 /* Implementation of the abstract type typedef struct game_state GameState */
41 struct game_state {
42 /* Event queue */
43 EventQueueEntry *eventQueue;
44 int eventQueueTop; /* Event queue top pointer */
45
46 /* Scores */
47 int score;
48 Aword *scores; /* Score table pointer */
49
50 /* Instance data */
51 AdminEntry *admin; /* Administrative data about instances */
52 AttributeEntry *attributes; /* Attributes data area */
53 /* Sets and strings are dynamically allocated areas for which the
54 attribute is just a pointer to. So they are not catched by the
55 saving of attributes, instead they require special storage */
56 Set **sets; /* Array of set pointers */
57 char **strings; /* Array of string pointers */
58 };
59
60 /* PRIVATE DATA */
61 static GameState gameState; /* TODO: Make pointer, then we don't have to copy to stack, we can just use the pointer */
62 static StateStackP stateStack = NULL;
63
64 static char *playerCommand;
65
66
67 /*----------------------------------------------------------------------*/
countStrings(void)68 static int countStrings(void) {
69 StringInitEntry *entry;
70 int count = 0;
71
72 if (header->stringInitTable != 0)
73 for (entry = (StringInitEntry *)pointerTo(header->stringInitTable); * (Aword *)entry != EOD; entry++)
74 count++;
75 return (count);
76 }
77
78
79 /*----------------------------------------------------------------------*/
deallocateStrings(GameState * gState)80 static void deallocateStrings(GameState *gState) {
81 int count = countStrings();
82 int i;
83
84 for (i = 0; i < count; i++)
85 deallocate(gState->strings[i]);
86 deallocate(gState->strings);
87 }
88
89 /*----------------------------------------------------------------------*/
countSets(void)90 static int countSets(void) {
91 SetInitEntry *entry;
92 int count = 0;
93
94 if (header->setInitTable != 0)
95 for (entry = (SetInitEntry *)pointerTo(header->setInitTable); * (Aword *)entry != EOD; entry++)
96 count++;
97 return (count);
98 }
99
100
101 /*----------------------------------------------------------------------*/
deallocateSets(GameState * gState)102 static void deallocateSets(GameState *gState) {
103 int count = countSets();
104 int i;
105
106 for (i = 0; i < count; i++)
107 freeSet(gState->sets[i]);
108 deallocate(gState->sets);
109 }
110
111 /*======================================================================*/
deallocateGameState(GameState * gState)112 void deallocateGameState(GameState *gState) {
113
114 deallocate(gState->admin);
115 deallocate(gState->attributes);
116
117 if (gState->eventQueueTop > 0) {
118 deallocate(gState->eventQueue);
119 gState->eventQueue = NULL;
120 }
121 if (gState->scores)
122 deallocate(gState->scores);
123
124 deallocateStrings(gState);
125 deallocateSets(gState);
126
127 memset(gState, 0, sizeof(GameState));
128 }
129
130
131 /*======================================================================*/
forgetGameState(void)132 void forgetGameState(void) {
133 char *playerCmd;
134 popGameState(stateStack, &gameState, &playerCmd);
135 deallocateGameState(&gameState);
136 if (playerCmd != NULL)
137 deallocate(playerCmd);
138 }
139
140
141 /*======================================================================*/
initStateStack(void)142 void initStateStack(void) {
143 if (stateStack != NULL)
144 deleteStateStack(stateStack);
145 stateStack = createStateStack(sizeof(GameState));
146 }
147
148
149 /*======================================================================*/
terminateStateStack(void)150 void terminateStateStack(void) {
151 deleteStateStack(stateStack);
152 stateStack = NULL;
153 }
154
155
156 /*======================================================================*/
anySavedState(void)157 bool anySavedState(void) {
158 return !stateStackIsEmpty(stateStack);
159 }
160
161
162 /*----------------------------------------------------------------------*/
collectSets(void)163 static Set **collectSets(void) {
164 SetInitEntry *entry;
165 int count = countSets();
166 Set **sets;
167 int i;
168
169 if (count == 0) return NULL;
170
171 sets = (Set **)allocate(count * sizeof(Set));
172
173 entry = (SetInitEntry *)pointerTo(header->setInitTable);
174 for (i = 0; i < count; i++)
175 sets[i] = getInstanceSetAttribute(entry[i].instanceCode, entry[i].attributeCode);
176
177 return sets;
178 }
179
180
181 /*----------------------------------------------------------------------*/
collectStrings(void)182 static char **collectStrings(void) {
183 StringInitEntry *entry;
184 int count = countStrings();
185 char **strings;
186 int i;
187
188 if (count == 0) return NULL;
189
190 strings = (char **)allocate(count * sizeof(char *));
191
192 entry = (StringInitEntry *)pointerTo(header->stringInitTable);
193 for (i = 0; i < count; i++)
194 strings[i] = getInstanceStringAttribute(entry[i].instanceCode, entry[i].attributeCode);
195
196 return strings;
197 }
198
199
200 /*======================================================================*/
rememberCommands(void)201 void rememberCommands(void) {
202 char *command = playerWordsAsCommandString();
203 attachPlayerCommandsToLastState(stateStack, command);
204 deallocate(command);
205 }
206
207
208 /*----------------------------------------------------------------------*/
collectEvents(void)209 static void collectEvents(void) {
210 gameState.eventQueueTop = eventQueueTop;
211 if (eventQueueTop > 0)
212 gameState.eventQueue = (EventQueueEntry *)duplicate(eventQueue, eventQueueTop * sizeof(EventQueueEntry));
213 }
214
215
216 /*----------------------------------------------------------------------*/
collectInstanceData(void)217 static void collectInstanceData(void) {
218 gameState.admin = (AdminEntry *)duplicate(admin, (header->instanceMax + 1) * sizeof(AdminEntry));
219 gameState.attributes = (AttributeEntry *)duplicate(attributes, header->attributesAreaSize * sizeof(Aword));
220 gameState.sets = collectSets();
221 gameState.strings = collectStrings();
222 }
223
224
225 /*----------------------------------------------------------------------*/
collectScores(void)226 static void collectScores(void) {
227 gameState.score = current.score;
228 if (scores == NULL)
229 gameState.scores = NULL;
230 else
231 gameState.scores = (Aword *)duplicate(scores, header->scoreCount * sizeof(Aword));
232 }
233
234
235 /*======================================================================*/
rememberGameState(void)236 void rememberGameState(void) {
237 collectEvents();
238 collectInstanceData();
239 collectScores();
240
241 if (stateStack == NULL)
242 initStateStack();
243
244 pushGameState(stateStack, &gameState);
245 gameStateChanged = FALSE;
246 }
247
248
249 /*----------------------------------------------------------------------*/
freeCurrentSetAttributes(void)250 static void freeCurrentSetAttributes(void) {
251 SetInitEntry *entry;
252
253 if (header->setInitTable == 0) return;
254 for (entry = (SetInitEntry *)pointerTo(header->setInitTable); * (Aword *)entry != EOD; entry++) {
255 Aptr attributeValue = getAttribute(admin[entry->instanceCode].attributes, entry->attributeCode);
256 freeSet((Set *)fromAptr(attributeValue));
257 }
258 }
259
260
261 /*----------------------------------------------------------------------*/
recallSets(Set ** sets)262 static void recallSets(Set **sets) {
263 SetInitEntry *entry;
264 int count = countSets();
265 int i;
266
267 if (header->setInitTable == 0) return;
268
269 entry = (SetInitEntry *)pointerTo(header->setInitTable);
270 for (i = 0; i < count; i++) {
271 setAttribute(admin[entry[i].instanceCode].attributes, entry[i].attributeCode, toAptr(sets[i]));
272 sets[i] = NULL; /* Since we reuse the saved set, we need to clear the pointer */
273 }
274 }
275
276
277 /*----------------------------------------------------------------------*/
freeCurrentStringAttributes(void)278 static void freeCurrentStringAttributes(void) {
279 StringInitEntry *entry;
280
281 if (header->stringInitTable == 0) return;
282 for (entry = (StringInitEntry *)pointerTo(header->stringInitTable); * (Aword *)entry != EOD; entry++) {
283 Aptr attributeValue = getAttribute(admin[entry->instanceCode].attributes, entry->attributeCode);
284 deallocate(fromAptr(attributeValue));
285 }
286 }
287
288
289 /*----------------------------------------------------------------------*/
recallStrings(char ** strings)290 static void recallStrings(char **strings) {
291 StringInitEntry *entry;
292 int count = countStrings();
293 int i;
294
295 if (header->stringInitTable == 0) return;
296
297 entry = (StringInitEntry *)pointerTo(header->stringInitTable);
298 for (i = 0; i < count; i++) {
299 setAttribute(admin[entry[i].instanceCode].attributes, entry[i].attributeCode, toAptr(strings[i]));
300 strings[i] = NULL; /* Since we reuse the saved, we need to clear the state */
301 }
302 }
303
304
305 /*----------------------------------------------------------------------*/
recallEvents(void)306 static void recallEvents(void) {
307 eventQueueTop = gameState.eventQueueTop;
308 if (eventQueueTop > 0) {
309 memcpy(eventQueue, gameState.eventQueue,
310 (eventQueueTop + 1)*sizeof(EventQueueEntry));
311 }
312 }
313
314
315 /*----------------------------------------------------------------------*/
recallInstances(void)316 static void recallInstances(void) {
317
318 if (admin == NULL)
319 syserr("admin[] == NULL in recallInstances()");
320
321 memcpy(admin, gameState.admin,
322 (header->instanceMax + 1)*sizeof(AdminEntry));
323
324 freeCurrentSetAttributes(); /* Need to free previous set values */
325 freeCurrentStringAttributes(); /* Need to free previous string values */
326
327 memcpy(attributes, gameState.attributes,
328 header->attributesAreaSize * sizeof(Aword));
329
330 recallSets(gameState.sets);
331 recallStrings(gameState.strings);
332 }
333
334
335 /*----------------------------------------------------------------------*/
recallScores(void)336 static void recallScores(void) {
337 current.score = gameState.score;
338 memcpy(scores, gameState.scores, header->scoreCount * sizeof(Aword));
339 }
340
341
342 /*======================================================================*/
recallGameState(void)343 void recallGameState(void) {
344 popGameState(stateStack, &gameState, &playerCommand);
345 recallEvents();
346 recallInstances();
347 recallScores();
348 deallocateGameState(&gameState);
349 }
350
351
352 /*======================================================================*/
recreatePlayerCommand(void)353 char *recreatePlayerCommand(void) {
354 return playerCommand;
355 }
356
357 } // End of namespace Alan3
358 } // End of namespace Glk
359