scummvm/engines/glk/alan3/state.cpp
2019-07-06 15:27:08 -07:00

359 lines
10 KiB
C++

/* ScummVM - Graphic Adventure Engine
*
* ScummVM is the legal property of its developers, whose names
* are too numerous to list here. Please refer to the COPYRIGHT
* file distributed with this source distribution.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
*/
#include "glk/alan3/state.h"
#include "glk/alan3/syserr.h"
#include "glk/alan3/current.h"
#include "glk/alan3/word.h"
#include "glk/alan3/state_stack.h"
#include "glk/alan3/instance.h"
#include "glk/alan3/attribute.h"
#include "glk/alan3/memory.h"
#include "glk/alan3/score.h"
#include "glk/alan3/event.h"
#include "glk/alan3/set.h"
namespace Glk {
namespace Alan3 {
/* PRIVATE TYPES */
/* Implementation of the abstract type typedef struct game_state GameState */
struct game_state {
/* Event queue */
EventQueueEntry *eventQueue;
int eventQueueTop; /* Event queue top pointer */
/* Scores */
int score;
Aword *scores; /* Score table pointer */
/* Instance data */
AdminEntry *admin; /* Administrative data about instances */
AttributeEntry *attributes; /* Attributes data area */
/* Sets and strings are dynamically allocated areas for which the
attribute is just a pointer to. So they are not catched by the
saving of attributes, instead they require special storage */
Set **sets; /* Array of set pointers */
char **strings; /* Array of string pointers */
};
/* PRIVATE DATA */
static GameState gameState; /* TODO: Make pointer, then we don't have to copy to stack, we can just use the pointer */
static StateStackP stateStack = NULL;
static char *playerCommand;
/*----------------------------------------------------------------------*/
static int countStrings(void) {
StringInitEntry *entry;
int count = 0;
if (header->stringInitTable != 0)
for (entry = (StringInitEntry *)pointerTo(header->stringInitTable); * (Aword *)entry != EOD; entry++)
count++;
return (count);
}
/*----------------------------------------------------------------------*/
static void deallocateStrings(GameState *gState) {
int count = countStrings();
int i;
for (i = 0; i < count; i++)
deallocate(gState->strings[i]);
deallocate(gState->strings);
}
/*----------------------------------------------------------------------*/
static int countSets(void) {
SetInitEntry *entry;
int count = 0;
if (header->setInitTable != 0)
for (entry = (SetInitEntry *)pointerTo(header->setInitTable); * (Aword *)entry != EOD; entry++)
count++;
return (count);
}
/*----------------------------------------------------------------------*/
static void deallocateSets(GameState *gState) {
int count = countSets();
int i;
for (i = 0; i < count; i++)
freeSet(gState->sets[i]);
deallocate(gState->sets);
}
/*======================================================================*/
void deallocateGameState(GameState *gState) {
deallocate(gState->admin);
deallocate(gState->attributes);
if (gState->eventQueueTop > 0) {
deallocate(gState->eventQueue);
gState->eventQueue = NULL;
}
if (gState->scores)
deallocate(gState->scores);
deallocateStrings(gState);
deallocateSets(gState);
memset(gState, 0, sizeof(GameState));
}
/*======================================================================*/
void forgetGameState(void) {
char *playerCmd;
popGameState(stateStack, &gameState, &playerCmd);
deallocateGameState(&gameState);
if (playerCmd != NULL)
deallocate(playerCmd);
}
/*======================================================================*/
void initStateStack(void) {
if (stateStack != NULL)
deleteStateStack(stateStack);
stateStack = createStateStack(sizeof(GameState));
}
/*======================================================================*/
void terminateStateStack(void) {
deleteStateStack(stateStack);
stateStack = NULL;
}
/*======================================================================*/
bool anySavedState(void) {
return !stateStackIsEmpty(stateStack);
}
/*----------------------------------------------------------------------*/
static Set **collectSets(void) {
SetInitEntry *entry;
int count = countSets();
Set **sets;
int i;
if (count == 0) return NULL;
sets = (Set **)allocate(count * sizeof(Set));
entry = (SetInitEntry *)pointerTo(header->setInitTable);
for (i = 0; i < count; i++)
sets[i] = getInstanceSetAttribute(entry[i].instanceCode, entry[i].attributeCode);
return sets;
}
/*----------------------------------------------------------------------*/
static char **collectStrings(void) {
StringInitEntry *entry;
int count = countStrings();
char **strings;
int i;
if (count == 0) return NULL;
strings = (char **)allocate(count * sizeof(char *));
entry = (StringInitEntry *)pointerTo(header->stringInitTable);
for (i = 0; i < count; i++)
strings[i] = getInstanceStringAttribute(entry[i].instanceCode, entry[i].attributeCode);
return strings;
}
/*======================================================================*/
void rememberCommands(void) {
char *command = playerWordsAsCommandString();
attachPlayerCommandsToLastState(stateStack, command);
deallocate(command);
}
/*----------------------------------------------------------------------*/
static void collectEvents(void) {
gameState.eventQueueTop = eventQueueTop;
if (eventQueueTop > 0)
gameState.eventQueue = (EventQueueEntry *)duplicate(eventQueue, eventQueueTop * sizeof(EventQueueEntry));
}
/*----------------------------------------------------------------------*/
static void collectInstanceData(void) {
gameState.admin = (AdminEntry *)duplicate(admin, (header->instanceMax + 1) * sizeof(AdminEntry));
gameState.attributes = (AttributeEntry *)duplicate(attributes, header->attributesAreaSize * sizeof(Aword));
gameState.sets = collectSets();
gameState.strings = collectStrings();
}
/*----------------------------------------------------------------------*/
static void collectScores(void) {
gameState.score = current.score;
if (scores == NULL)
gameState.scores = NULL;
else
gameState.scores = (Aword *)duplicate(scores, header->scoreCount * sizeof(Aword));
}
/*======================================================================*/
void rememberGameState(void) {
collectEvents();
collectInstanceData();
collectScores();
if (stateStack == NULL)
initStateStack();
pushGameState(stateStack, &gameState);
gameStateChanged = FALSE;
}
/*----------------------------------------------------------------------*/
static void freeCurrentSetAttributes(void) {
SetInitEntry *entry;
if (header->setInitTable == 0) return;
for (entry = (SetInitEntry *)pointerTo(header->setInitTable); * (Aword *)entry != EOD; entry++) {
Aptr attributeValue = getAttribute(admin[entry->instanceCode].attributes, entry->attributeCode);
freeSet((Set *)fromAptr(attributeValue));
}
}
/*----------------------------------------------------------------------*/
static void recallSets(Set **sets) {
SetInitEntry *entry;
int count = countSets();
int i;
if (header->setInitTable == 0) return;
entry = (SetInitEntry *)pointerTo(header->setInitTable);
for (i = 0; i < count; i++) {
setAttribute(admin[entry[i].instanceCode].attributes, entry[i].attributeCode, toAptr(sets[i]));
sets[i] = NULL; /* Since we reuse the saved set, we need to clear the pointer */
}
}
/*----------------------------------------------------------------------*/
static void freeCurrentStringAttributes(void) {
StringInitEntry *entry;
if (header->stringInitTable == 0) return;
for (entry = (StringInitEntry *)pointerTo(header->stringInitTable); * (Aword *)entry != EOD; entry++) {
Aptr attributeValue = getAttribute(admin[entry->instanceCode].attributes, entry->attributeCode);
deallocate(fromAptr(attributeValue));
}
}
/*----------------------------------------------------------------------*/
static void recallStrings(char **strings) {
StringInitEntry *entry;
int count = countStrings();
int i;
if (header->stringInitTable == 0) return;
entry = (StringInitEntry *)pointerTo(header->stringInitTable);
for (i = 0; i < count; i++) {
setAttribute(admin[entry[i].instanceCode].attributes, entry[i].attributeCode, toAptr(strings[i]));
strings[i] = NULL; /* Since we reuse the saved, we need to clear the state */
}
}
/*----------------------------------------------------------------------*/
static void recallEvents(void) {
eventQueueTop = gameState.eventQueueTop;
if (eventQueueTop > 0) {
memcpy(eventQueue, gameState.eventQueue,
(eventQueueTop + 1)*sizeof(EventQueueEntry));
}
}
/*----------------------------------------------------------------------*/
static void recallInstances(void) {
if (admin == NULL)
syserr("admin[] == NULL in recallInstances()");
memcpy(admin, gameState.admin,
(header->instanceMax + 1)*sizeof(AdminEntry));
freeCurrentSetAttributes(); /* Need to free previous set values */
freeCurrentStringAttributes(); /* Need to free previous string values */
memcpy(attributes, gameState.attributes,
header->attributesAreaSize * sizeof(Aword));
recallSets(gameState.sets);
recallStrings(gameState.strings);
}
/*----------------------------------------------------------------------*/
static void recallScores(void) {
current.score = gameState.score;
memcpy(scores, gameState.scores, header->scoreCount * sizeof(Aword));
}
/*======================================================================*/
void recallGameState(void) {
popGameState(stateStack, &gameState, &playerCommand);
recallEvents();
recallInstances();
recallScores();
deallocateGameState(&gameState);
}
/*======================================================================*/
char *recreatePlayerCommand(void) {
return playerCommand;
}
} // End of namespace Alan3
} // End of namespace Glk