diff --git a/src/defs.h b/src/defs.h index e198b58..91d356f 100644 --- a/src/defs.h +++ b/src/defs.h @@ -35,8 +35,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define TO_RAIDANS(angleDegrees) (angleDegrees * PI / 180.0) #define TO_DEGREES(angleRadians) (angleRadians * 180.0 / PI) -#define SAVE_FILENAME "game.save" -#define CONFIG_FILENAME "config.json" +#define SAVE_FILENAME "game.save" +#define CONFIG_FILENAME "config.json" #define SCREEN_WIDTH 1280 #define SCREEN_HEIGHT 720 @@ -51,6 +51,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define NUM_TEXT_BUCKETS 64 #define TEXT_TTL (1000 * 20) +#define MAX_WIDGETS 48 + #define MAX_NAME_LENGTH 32 #define MAX_DESCRIPTION_LENGTH 512 #define MAX_LINE_LENGTH 1024 @@ -306,6 +308,7 @@ enum SND_CONFIRMED, SND_MISSION_COMPLETE, SND_HEART_CELL, + SND_TROPHY, SND_MAX }; @@ -327,7 +330,16 @@ enum { WT_BUTTON, WT_SPINNER, - WT_PLAIN_BUTTON + WT_PLAIN_BUTTON, + WT_INPUT +}; + +enum +{ + TROPHY_BRONZE, + TROPHY_SILVER, + TROPHY_GOLD, + TROPHY_PLATINUM }; enum diff --git a/src/game/trophies.c b/src/game/trophies.c index 76a2163..ed23d6b 100644 --- a/src/game/trophies.c +++ b/src/game/trophies.c @@ -20,6 +20,220 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "trophies.h" +static void loadTrophyData(void); +static void resetAlert(void); +static void nextAlert(void); + +static Trophy trophyHead, *trophyTail; +static int numTrophies; +static SDL_Rect alertRect; +static int alertTimer; +static Trophy *alertTrophy; +static float sparkleAngle; +/* +static SDL_Texture *trophyIcons[TROPHY_MAX]; +static SDL_Texture *sparkle; +static SDL_Texture *alertSphere; +*/ +static int awarded; + +void initTrophies(void) +{ + memset(&trophyHead, 0, sizeof(Trophy)); + trophyTail = &trophyHead; + + numTrophies = 0; + + awarded = 0; + + alertTimer = 0; + + sparkleAngle = 0; + + loadTrophyData(); +} + void awardTrophy(char *id) { + Trophy *t; + int numRemaining; + + numRemaining = 0; + + for (t = trophyHead.next ; t != NULL ; t = t->next) + { + if (t->awardDate == 0 && strcmp(t->id, id) == 0) + { + t->awardDate = time(NULL); + t->notify = SDL_GetTicks(); + + SDL_Delay(1); + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Awarding trophy '%s'", t->id); + } + + if (t->awardDate == 0) + { + numRemaining++; + } + } + + /* the Platinum will always be the last trophy to unlock */ + if (numRemaining == 1) + { + awardTrophy("PLATINUM"); + } } + +void awardTrophies(void) +{ + int val; + Trophy *t; + + for (t = trophyHead.next ; t != NULL ; t = t->next) + { + if (t->awardDate == 0 && t->statValue != 0) + { + val = game.stats[t->stat]; + + if (val >= t->statValue) + { + awardTrophy(t->id); + } + } + } +} + +void doTrophyAlerts(void) +{ + if (!alertTrophy) + { + nextAlert(); + } + else if (alertTrophy) + { + alertRect.x = MIN(alertRect.x + 24, -1); + + if (alertRect.x > -150) + { + alertTimer--; + } + + if (alertTimer <= 0) + { + alertTrophy->notify = 0; + resetAlert(); + } + } + + sparkleAngle = mod(sparkleAngle + 0.25, 360); +} + +static void nextAlert(void) +{ + int w, h; + Trophy *t; + + for (t = trophyHead.next ; t != NULL ; t = t->next) + { + if (t->notify) + { + if (!alertTrophy || t->notify < alertTrophy->notify) + { + alertTrophy = t; + } + } + } + + if (alertTrophy) + { + playSound(SND_TROPHY, -1); + + textSize(alertTrophy->title, 30, &alertRect.w, &h); + textSize(alertTrophy->description, 20, &w, &h); + + alertRect.w = MAX(alertRect.w, w); + alertRect.w = MAX(400, alertRect.w); + alertRect.w += 125; + alertRect.x = -alertRect.w; + } +} + +static void resetAlert(void) +{ + alertTimer = FPS * 3; + alertTrophy = NULL; +} + +void drawTrophyAlert(void) +{ + /*int x, y;*/ + + if (alertTrophy) + { + SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, SDL_ALPHA_OPAQUE); + SDL_RenderFillRect(app.renderer, &alertRect); + + SDL_SetRenderDrawColor(app.renderer, 64, 64, 64, SDL_ALPHA_OPAQUE); + SDL_RenderDrawRect(app.renderer, &alertRect); + + drawText(alertRect.x + 15, alertRect.y + 5, 30, TA_LEFT, colors.white, alertTrophy->title); + drawText(alertRect.x + 15, alertRect.y + 45, 20, TA_LEFT, colors.white, alertTrophy->description); + + /* + x = alertRect.x alertRect.w - 72; + y = alertRect.y 20; + + setSparkleColor(alertTrophy); + blit(alertSphere, x 24, y 24, 1); + blitRotated(sparkle, x 24, y 24, sparkleAngle); + blitRotated(sparkle, x 24, y 24, -sparkleAngle); + blitScaled(trophyIcons[alertTrophy->value], x, y, 48, 48, 0); + */ + } +} + +static void loadTrophyData(void) +{ + cJSON *root, *node; + char *text; + Trophy *t; + char *filename; + + filename = "data/misc/trophies.json"; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Loading %s", filename); + + text = readFile(filename); + root = cJSON_Parse(text); + + for (node = root->child ; node != NULL ; node = node->next) + { + t = malloc(sizeof(Trophy)); + memset(t, 0, sizeof(Trophy)); + trophyTail->next = t; + trophyTail = t; + + STRNCPY(t->id, cJSON_GetObjectItem(node, "id")->valuestring, MAX_NAME_LENGTH); + STRNCPY(t->title, _(cJSON_GetObjectItem(node, "title")->valuestring), MAX_DESCRIPTION_LENGTH); + STRNCPY(t->description, _(cJSON_GetObjectItem(node, "description")->valuestring), MAX_DESCRIPTION_LENGTH); + t->value = lookup(cJSON_GetObjectItem(node, "value")->valuestring); + + if (cJSON_GetObjectItem(node, "hidden")) + { + t->hidden = cJSON_GetObjectItem(node, "hidden")->valueint; + } + + t->stat = -1; + + if (cJSON_GetObjectItem(node, "stat")) + { + t->stat = lookup(cJSON_GetObjectItem(node, "stat")->valuestring); + t->statValue = cJSON_GetObjectItem(node, "statValue")->valueint; + } + } + + cJSON_Delete(root); + free(text); +} + diff --git a/src/game/trophies.h b/src/game/trophies.h index 8ad0dc9..05789a9 100644 --- a/src/game/trophies.h +++ b/src/game/trophies.h @@ -19,3 +19,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "../common.h" +#include "../json/cJSON.h" +#include + +extern char *readFile(const char *filename); +extern long lookup(const char *name); +extern void textSize(char *text, int size, int *w, int *h); +extern void playSound(int snd, int ch); +extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...); +extern float mod(float n, float x); + +extern App app; +extern Colors colors; +extern Game game; diff --git a/src/main.c b/src/main.c index 07061a8..7d82bba 100644 --- a/src/main.c +++ b/src/main.c @@ -76,6 +76,8 @@ int main(int argc, char *argv[]) game.stats[STAT_TIME_PLAYED]++; nextSecond = SDL_GetTicks() + 1000; + + awardTrophies(); } } diff --git a/src/main.h b/src/main.h index 7a4ba3d..27d8a40 100644 --- a/src/main.h +++ b/src/main.h @@ -30,6 +30,7 @@ extern void presentScene(void); extern void initAtlasTest(void); extern void init18N(int argc, char *argv[]); extern void initLookups(void); +extern void awardTrophies(void); App app; Camera camera; diff --git a/src/structs.h b/src/structs.h index 808d507..c1b5c96 100644 --- a/src/structs.h +++ b/src/structs.h @@ -32,6 +32,7 @@ typedef struct Widget Widget; typedef struct Atlas Atlas; typedef struct Bucket Bucket; typedef struct EntityDef EntityDef; +typedef struct Trophy Trophy; typedef struct cJSON cJSON; typedef struct Entity Entity; @@ -464,21 +465,17 @@ typedef struct { } World; struct Widget { - int type; - int x; - int y; - int w; - int h; - int visible; - int enabled; char name[MAX_NAME_LENGTH]; char group[MAX_NAME_LENGTH]; char label[MAX_NAME_LENGTH]; + int type; + int x; + int y; + int visible; + int enabled; int numOptions; char **options; int value; - int clicked; - Widget *next; }; struct Atlas { @@ -487,6 +484,21 @@ struct Atlas { Atlas *next; }; +struct Trophy { + char id[MAX_NAME_LENGTH]; + char title[MAX_DESCRIPTION_LENGTH]; + char description[MAX_DESCRIPTION_LENGTH]; + char awardDateStr[MAX_NAME_LENGTH]; + int value; + int hidden; + int stat; + int statValue; + int awarded; + unsigned long awardDate; + int notify; + Trophy *next; +}; + /* ===== i18n stuff ==== */ struct Bucket { diff --git a/src/system/init.c b/src/system/init.c index 9365162..a9659c3 100644 --- a/src/system/init.c +++ b/src/system/init.c @@ -135,6 +135,7 @@ void initGameSystem(void) initFonts, initAtlas, initWidgets, + initTrophies, initSounds, initSprites, initEntityFactory diff --git a/src/system/init.h b/src/system/init.h index c1daa19..57f63f3 100644 --- a/src/system/init.h +++ b/src/system/init.h @@ -35,6 +35,7 @@ extern void initAtlas(void); extern void initSounds(void); extern void initSprites(void); extern void initWidgets(void); +extern void initTrophies(void); extern void initEntityFactory(void); extern void destroyLookups(void); extern void destroyFonts(void); diff --git a/src/system/input.c b/src/system/input.c index 92125c4..cc36270 100644 --- a/src/system/input.c +++ b/src/system/input.c @@ -33,6 +33,8 @@ static void doKeyDown(SDL_KeyboardEvent *event) if (event->keysym.scancode >= 0 && event->keysym.scancode < MAX_KEYBOARD_KEYS && event->repeat == 0) { app.keyboard[event->keysym.scancode] = 1; + + app.lastKeyPressed = event->keysym.scancode; } } @@ -107,6 +109,8 @@ static void doButtonDown(SDL_JoyButtonEvent *event) if (event->state == SDL_PRESSED) { app.joypadButton[event->button] = 1; + + app.lastButtonPressed = event->button; } } diff --git a/src/system/lookup.c b/src/system/lookup.c index a6ac5e1..8ba8d25 100644 --- a/src/system/lookup.c +++ b/src/system/lookup.c @@ -52,6 +52,29 @@ void initLookups(void) addLookup("WT_BUTTON", WT_BUTTON); addLookup("WT_SPINNER", WT_SPINNER); addLookup("WT_PLAIN_BUTTON", WT_PLAIN_BUTTON); + + addLookup("TROPHY_BRONZE", TROPHY_BRONZE); + addLookup("TROPHY_SILVER", TROPHY_SILVER); + addLookup("TROPHY_GOLD", TROPHY_GOLD); + addLookup("TROPHY_PLATINUM", TROPHY_PLATINUM); + + addLookup("STAT_KEYS_FOUND", STAT_KEYS_FOUND); + addLookup("STAT_CELLS_FOUND", STAT_CELLS_FOUND); + addLookup("STAT_HEARTS_FOUND", STAT_HEARTS_FOUND); + addLookup("STAT_TARGETS_DEFEATED", STAT_TARGETS_DEFEATED); + addLookup("STAT_MIAS_RESCUED", STAT_MIAS_RESCUED); + addLookup("STAT_DEATHS", STAT_DEATHS); + addLookup("STAT_SHOTS_FIRED", STAT_SHOTS_FIRED); + addLookup("STAT_SHOTS_HIT", STAT_SHOTS_HIT); + addLookup("STAT_EYE_DROID_EXPLOSION_KILLS", STAT_EYE_DROID_EXPLOSION_KILLS); + addLookup("STAT_FLY_TIME", STAT_FLY_TIME); + addLookup("STAT_SWIM_TIME", STAT_SWIM_TIME); + addLookup("STAT_CHERRIES_PICKED_UP", STAT_CHERRIES_PICKED_UP); + addLookup("STAT_BATTERIES_PICKED_UP", STAT_BATTERIES_PICKED_UP); + addLookup("STAT_WEAPONS_PICKED_UP", STAT_WEAPONS_PICKED_UP); + addLookup("STAT_ENEMIES_KILLED", STAT_ENEMIES_KILLED); + addLookup("STAT_MISSIONS_PLAYED", STAT_MISSIONS_PLAYED); + addLookup("STAT_TIME_PLAYED", STAT_TIME_PLAYED); } static void addLookup(const char *name, long value) diff --git a/src/system/widgets.c b/src/system/widgets.c index 4bddd5e..785faf1 100644 --- a/src/system/widgets.c +++ b/src/system/widgets.c @@ -20,28 +20,109 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "widgets.h" -Widget *getWidgetAt(int x, int y); static void loadWidgetGroup(char *filename); static void loadWidgets(void); +static void createWidgetOptions(Widget *w, char *options); +static void selectWidget(int dir); -static Widget widgetHead; -static Widget *widgetTail; +static Widget widgets[MAX_WIDGETS]; static Widget *selectedWidget; +static int widgetIndex; +static int numWidgets; void initWidgets(void) { - memset(&widgetHead, 0, sizeof(Widget)); - widgetTail = &widgetHead; + memset(widgets, 0, sizeof(Widget) * MAX_WIDGETS); + + numWidgets = 0; loadWidgets(); } +void doWidgets(void) +{ + if (app.keyboard[SDL_SCANCODE_UP]) + { + selectWidget(-1); + + app.keyboard[SDL_SCANCODE_UP] = 0; + } + + if (app.keyboard[SDL_SCANCODE_DOWN]) + { + selectWidget(1); + + app.keyboard[SDL_SCANCODE_DOWN] = 0; + } + + if (app.keyboard[SDL_SCANCODE_LEFT] && selectedWidget->type == WT_SPINNER) + { + } + + if (app.keyboard[SDL_SCANCODE_RIGHT] && selectedWidget->type == WT_SPINNER) + { + } +} + +void drawWidgets(void) +{ + int i; + Widget *w; + + for (i = 0 ; i < numWidgets ; i++) + { + w = &widgets[i]; + + if (w->visible) + { + switch (w->type) + { + case WT_BUTTON: + break; + + case WT_PLAIN_BUTTON: + break; + + case WT_SPINNER: + break; + + case WT_INPUT: + break; + } + } + } +} + +static void selectWidget(int dir) +{ + do + { + widgetIndex += dir; + + if (widgetIndex < 0) + { + widgetIndex = numWidgets - 1; + } + + if (widgetIndex >= numWidgets) + { + widgetIndex = 0; + } + + selectedWidget = &widgets[widgetIndex]; + + } while (!selectedWidget->enabled && !selectedWidget->visible); +} + Widget *getWidget(char *name, char *group) { + int i; Widget *w; - for (w = widgetHead.next ; w != NULL ; w = w->next) + for (i = 0 ; i < numWidgets ; i++) { + w = &widgets[i]; + if (strcmp(w->name, name) == 0 && strcmp(w->group, group) == 0) { return w; @@ -54,59 +135,13 @@ Widget *getWidget(char *name, char *group) return NULL; } -void handleWidgetClick(int x, int y) -{ - Widget *w; - - w = getWidgetAt(x, y); - - if (w != NULL) - { - if (w->type == WT_SPINNER) - { - w->value++; - - w->value %= w->numOptions; - } - - w->clicked = 1; - } -} - -void activeSelected(void) -{ - if (selectedWidget->type == WT_SPINNER) - { - selectedWidget->value++; - - selectedWidget->value %= selectedWidget->numOptions; - } - - selectedWidget->clicked = 1; -} - -Widget *getWidgetAt(int x, int y) -{ - Widget *w; - - for (w = widgetHead.next ; w != NULL ; w = w->next) - { - if (w->visible && w->enabled && collision(x, y, 1, 1, w->x - (w->w / 2), w->y, w->w, w->h)) - { - return w; - } - } - - return NULL; -} - void hideAllWidgets(void) { - Widget *w; + int i; - for (w = widgetHead.next ; w != NULL ; w = w->next) + for (i = 0 ; i < numWidgets ; i++) { - w->visible = 0; + widgets[i].visible = 0; } selectedWidget = NULL; @@ -114,12 +149,15 @@ void hideAllWidgets(void) void showWidgetGroup(char *group) { + int i; Widget *w; hideAllWidgets(); - for (w = widgetHead.next ; w != NULL ; w = w->next) + for (i = 0 ; i < numWidgets ; i++) { + w = &widgets[i]; + if (strcmp(w->group, group) == 0) { if (selectedWidget == NULL) @@ -132,17 +170,6 @@ void showWidgetGroup(char *group) } } -int wasWidgetClicked(Widget *w) -{ - int wasClicked; - - wasClicked = w->clicked; - - w->clicked = 0; - - return wasClicked; -} - static void loadWidgets(void) { char **filenames; @@ -176,29 +203,28 @@ static void loadWidgetGroup(char *filename) for (node = root->child ; node != NULL ; node = node->next) { - w = malloc(sizeof(Widget)); - memset(w, 0, sizeof(Widget)); - widgetTail->next = w; - widgetTail = w; + if (++numWidgets >= MAX_WIDGETS) + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Out of widget space."); + exit(1); + } + + w = &widgets[numWidgets]; STRNCPY(w->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH); STRNCPY(w->group, cJSON_GetObjectItem(node, "group")->valuestring, MAX_NAME_LENGTH); STRNCPY(w->label, cJSON_GetObjectItem(node, "label")->valuestring, MAX_NAME_LENGTH); w->x = cJSON_GetObjectItem(node, "x")->valueint; w->y = cJSON_GetObjectItem(node, "y")->valueint; - w->w = cJSON_GetObjectItem(node, "w")->valueint; - w->h = cJSON_GetObjectItem(node, "h")->valueint; w->type = lookup(cJSON_GetObjectItem(node, "type")->valuestring); switch (w->type) { - case WT_BUTTON: - break; - case WT_SPINNER: + createWidgetOptions(w, cJSON_GetObjectItem(node, "options")->valuestring); break; - case WT_PLAIN_BUTTON: + default: break; } } @@ -208,6 +234,38 @@ static void loadWidgetGroup(char *filename) free(text); } +static void createWidgetOptions(Widget *w, char *options) +{ + int i; + char *option; + + w->numOptions = 1; + + for (i = 0 ; i < strlen(options) ; i++) + { + if (options[i] == '|') + { + w->numOptions++; + } + } + + w->options = malloc(w->numOptions * sizeof(char*)); + + i = 0; + option = strtok(options, "|"); + while (option) + { + w->options[i] = malloc(strlen(option) + 1); + strcpy(w->options[i], option); + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "widget.option[%d] = %s", i, option); + + option = strtok(NULL, "|"); + + i++; + } +} + void destroy(void) { } diff --git a/src/system/widgets.h b/src/system/widgets.h index f9cdc32..bb05c91 100644 --- a/src/system/widgets.h +++ b/src/system/widgets.h @@ -21,7 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "../common.h" #include "../json/cJSON.h" -extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2); extern char *readFile(const char *filename); extern char **getFileList(const char *dir, int *count); extern long lookup(const char *name); + +extern App app; diff --git a/src/util/maths.c b/src/util/maths.c index e8d9331..cdb4cd7 100644 --- a/src/util/maths.c +++ b/src/util/maths.c @@ -20,9 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #include "maths.h" -int mod(int n, int x) +float mod(float n, float x) { - return ((n % x) + x) % x; + return fmod(fmod(n, x) + x, x); } int rrnd(int low, int high)