#include #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; }