299 lines
7.0 KiB
C
299 lines
7.0 KiB
C
#include <stdlib.h>
|
|
#include "state.h"
|
|
#include "report.h"
|
|
|
|
/*
|
|
================================
|
|
StateManager
|
|
The StateManager is the entity that, as its name implies, manages State(s). States should not be directly managed, but should rather rely on this mofo, so as to prevent bungling.
|
|
*/
|
|
struct StateManager *newStateManager() {
|
|
struct StateManager *manager = malloc(sizeof(struct StateManager));
|
|
manager->count = 0;
|
|
manager->first = NULL;
|
|
manager->last = NULL;
|
|
manager->temp = NULL;
|
|
return manager;
|
|
}
|
|
|
|
// NOTE: should freeStateManager also free states while close only calls doClose?
|
|
int freeStateManager(struct StateManager *manager) {
|
|
if (manager == NULL) {
|
|
return 1;
|
|
}
|
|
free(manager);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
This function closes and frees all States in a StateManager, starting from manager->last and working backwards from that double linked list.
|
|
|
|
Returns:
|
|
int of states freed
|
|
*/
|
|
int closeStateManager(struct StateManager *manager) {
|
|
if (manager == NULL) return -1;
|
|
|
|
struct State *state = manager->last;
|
|
struct State *prev_state;
|
|
int free_count = 0;
|
|
while (state != NULL) {
|
|
free_count++;
|
|
prev_state = state->prev;
|
|
closeState(state);
|
|
remState(state);
|
|
freeState(state);
|
|
state = prev_state;
|
|
report(DEBUG, "closeStateManager", "freed state %d", manager->count-free_count);
|
|
}
|
|
manager->count -= free_count;
|
|
manager->last = NULL;
|
|
manager->first = NULL;
|
|
return free_count;
|
|
}
|
|
|
|
int cleanStates(struct StateManager *manager) {
|
|
// move State(s) on the temp push stack into our main
|
|
if (manager->temp != NULL) {
|
|
manager->temp->prev = manager->last;
|
|
if (manager->first == NULL) {
|
|
manager->first = manager->temp;
|
|
}
|
|
if (manager->last == NULL ) {
|
|
manager->last = manager->temp;
|
|
} else {
|
|
manager->last->next = manager->temp;
|
|
}
|
|
manager->last = manager->temp;
|
|
manager->temp = NULL;
|
|
}
|
|
// iterate over each state, checking what it wants to do
|
|
struct State *state = manager->last;
|
|
while (state != NULL) {
|
|
// clear States that were requested to be removed via pop
|
|
if (state->s_flags & STATE_DO_CLEAR) {
|
|
struct State *prev = state->prev;
|
|
// close if open
|
|
if (state->s_flags & STATE_IS_OPEN) {
|
|
closeState(state);
|
|
}
|
|
// remove from state chain/double linked list
|
|
if (state == manager->last) manager->last = state->prev;
|
|
if (state == manager->first) manager->first = state->next;
|
|
remState(state);
|
|
// free if flag is set
|
|
if (state->flags & STATE_FREE) {
|
|
freeState(state);
|
|
}
|
|
state = prev;
|
|
continue;
|
|
}
|
|
// open State if STATE_IS_OPEN and doOpen is not null
|
|
if ((state->s_flags & STATE_IS_OPEN) != STATE_IS_OPEN) {
|
|
openState(state);
|
|
}
|
|
state = state->prev;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int handleStates(struct StateManager *manager, int order, SDL_Event event) {
|
|
struct State *state = NULL;
|
|
if (order == FIRST) {
|
|
state = manager->first;
|
|
while (state != NULL) {
|
|
// handle input, if doInput returns 1, that means we do not pass events
|
|
if (state->doInput != NULL) {
|
|
if (state->doInput(event) == 1) {
|
|
state = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
state = state->next;
|
|
}
|
|
} else {
|
|
state = manager->last;
|
|
while (state != NULL) {
|
|
// handle input, if doInput returns 1, that means we do not pass events
|
|
if (state->doInput != NULL) {
|
|
if (state->doInput(event) == 1) {
|
|
state = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
state = state->prev;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int processStates(struct StateManager *manager, int order) {
|
|
struct State *state = NULL;
|
|
if (order == FIRST) {
|
|
state = manager->first;
|
|
while (state != NULL) {
|
|
if (state->doProcess != NULL) {
|
|
if (state->doProcess() == 1) {
|
|
state = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
state = state->next;
|
|
}
|
|
} else {
|
|
state = manager->last;
|
|
while (state != NULL) {
|
|
if (state->doProcess != NULL) {
|
|
if (state->doProcess() == 1) {
|
|
state = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
state = state->prev;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int renderStates(struct StateManager *manager, int order) {
|
|
struct State *state = NULL;
|
|
if (order == FIRST) {
|
|
state = manager->first;
|
|
while (state != NULL) {
|
|
if (state->doRender != NULL) {
|
|
if (state->doRender() == 1) {
|
|
state = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
state = state->next;
|
|
}
|
|
} else {
|
|
state = manager->last;
|
|
while (state != NULL) {
|
|
if (state->doRender != NULL) {
|
|
if (state->doRender() == 1) {
|
|
state = NULL;
|
|
continue;
|
|
}
|
|
}
|
|
state = state->prev;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int pushState(struct StateManager *manager, struct State *peasant) {
|
|
if (manager == NULL) {
|
|
return 1;
|
|
}
|
|
if (peasant == NULL) {
|
|
return 2;
|
|
}
|
|
struct State *state = manager->temp;
|
|
if (state == NULL) {
|
|
manager->temp = peasant;
|
|
return 0;
|
|
}
|
|
while(state->next != NULL) {
|
|
state = state->next;
|
|
}
|
|
state->next = peasant;
|
|
peasant->prev = state;
|
|
return 0;
|
|
}
|
|
|
|
int popState(struct StateManager *manager) {
|
|
if (manager == NULL) return 1; // hate this syntax, but lazy
|
|
struct State *last = manager->last;
|
|
if (last == NULL) return 2;
|
|
while(last->prev != NULL) {
|
|
if(last->s_flags & STATE_DO_CLEAR) {
|
|
last = last->prev;
|
|
} else {
|
|
last->s_flags |= STATE_DO_CLEAR;
|
|
return 0;
|
|
break;
|
|
}
|
|
}
|
|
// if we got here, then this is the last item
|
|
last->s_flags |= STATE_DO_CLEAR;
|
|
return 0;
|
|
}
|
|
|
|
int remState(struct State *state) {
|
|
if (state == NULL) return 1;
|
|
if (state->next != NULL) {
|
|
state->next->prev = state->prev;
|
|
}
|
|
if (state->prev != NULL) {
|
|
state->prev->next = state->next;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
// a bit ugly :S
|
|
struct State *newState(int flags, void (*doOpen), void (*doClose), void (*doInput), void (*doProcess), void (*doRender)) {
|
|
struct State *state = malloc(sizeof(struct State));
|
|
state->prev = NULL;
|
|
state->next = NULL;
|
|
state->flags = flags;
|
|
state->s_flags = 0;
|
|
if (doOpen != NULL) {
|
|
state->doOpen = doOpen;
|
|
} else {
|
|
state->doOpen = NULL;
|
|
}
|
|
if (doInput != NULL) {
|
|
state->doInput = doInput;
|
|
} else {
|
|
state->doInput = NULL;
|
|
}
|
|
if (doProcess != NULL) {
|
|
state->doProcess = doProcess;
|
|
} else {
|
|
state->doProcess = NULL;
|
|
}
|
|
if (doRender != NULL) {
|
|
state->doRender = doRender;
|
|
} else {
|
|
state->doRender = NULL;
|
|
}
|
|
if (doClose != NULL) {
|
|
state->doClose = doClose;
|
|
} else {
|
|
state->doClose = NULL;
|
|
}
|
|
return state;
|
|
}
|
|
|
|
int freeState(struct State *state) {
|
|
if (state == NULL) {
|
|
return 1;
|
|
}
|
|
free(state);
|
|
return 0;
|
|
}
|
|
|
|
int openState(struct State *state) {
|
|
if (state == NULL) {
|
|
return 1;
|
|
}
|
|
state->s_flags |= STATE_IS_OPEN;
|
|
if (state->doOpen != NULL) {
|
|
return state->doOpen();
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int closeState(struct State *state) {
|
|
if (state == NULL) {
|
|
return 1;
|
|
}
|
|
state->s_flags &= ~STATE_IS_OPEN;
|
|
if (state->doClose != NULL) {
|
|
state->doClose();
|
|
}
|
|
return 0;
|
|
}
|