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