kettek2/wiki/games/newsboy/Newsboy_0x00/engine/state.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;
}