Widget and trophy updates.

This commit is contained in:
Steve 2018-02-14 19:12:29 +00:00
parent c87b9a6986
commit 6c2d39e1d1
13 changed files with 434 additions and 92 deletions

View File

@ -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_RAIDANS(angleDegrees) (angleDegrees * PI / 180.0)
#define TO_DEGREES(angleRadians) (angleRadians * 180.0 / PI) #define TO_DEGREES(angleRadians) (angleRadians * 180.0 / PI)
#define SAVE_FILENAME "game.save" #define SAVE_FILENAME "game.save"
#define CONFIG_FILENAME "config.json" #define CONFIG_FILENAME "config.json"
#define SCREEN_WIDTH 1280 #define SCREEN_WIDTH 1280
#define SCREEN_HEIGHT 720 #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 NUM_TEXT_BUCKETS 64
#define TEXT_TTL (1000 * 20) #define TEXT_TTL (1000 * 20)
#define MAX_WIDGETS 48
#define MAX_NAME_LENGTH 32 #define MAX_NAME_LENGTH 32
#define MAX_DESCRIPTION_LENGTH 512 #define MAX_DESCRIPTION_LENGTH 512
#define MAX_LINE_LENGTH 1024 #define MAX_LINE_LENGTH 1024
@ -306,6 +308,7 @@ enum
SND_CONFIRMED, SND_CONFIRMED,
SND_MISSION_COMPLETE, SND_MISSION_COMPLETE,
SND_HEART_CELL, SND_HEART_CELL,
SND_TROPHY,
SND_MAX SND_MAX
}; };
@ -327,7 +330,16 @@ enum
{ {
WT_BUTTON, WT_BUTTON,
WT_SPINNER, WT_SPINNER,
WT_PLAIN_BUTTON WT_PLAIN_BUTTON,
WT_INPUT
};
enum
{
TROPHY_BRONZE,
TROPHY_SILVER,
TROPHY_GOLD,
TROPHY_PLATINUM
}; };
enum enum

View File

@ -20,6 +20,220 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "trophies.h" #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) 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);
}

View File

@ -19,3 +19,16 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "../common.h" #include "../common.h"
#include "../json/cJSON.h"
#include <time.h>
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;

View File

@ -76,6 +76,8 @@ int main(int argc, char *argv[])
game.stats[STAT_TIME_PLAYED]++; game.stats[STAT_TIME_PLAYED]++;
nextSecond = SDL_GetTicks() + 1000; nextSecond = SDL_GetTicks() + 1000;
awardTrophies();
} }
} }

View File

@ -30,6 +30,7 @@ extern void presentScene(void);
extern void initAtlasTest(void); extern void initAtlasTest(void);
extern void init18N(int argc, char *argv[]); extern void init18N(int argc, char *argv[]);
extern void initLookups(void); extern void initLookups(void);
extern void awardTrophies(void);
App app; App app;
Camera camera; Camera camera;

View File

@ -32,6 +32,7 @@ typedef struct Widget Widget;
typedef struct Atlas Atlas; typedef struct Atlas Atlas;
typedef struct Bucket Bucket; typedef struct Bucket Bucket;
typedef struct EntityDef EntityDef; typedef struct EntityDef EntityDef;
typedef struct Trophy Trophy;
typedef struct cJSON cJSON; typedef struct cJSON cJSON;
typedef struct Entity Entity; typedef struct Entity Entity;
@ -464,21 +465,17 @@ typedef struct {
} World; } World;
struct Widget { struct Widget {
int type;
int x;
int y;
int w;
int h;
int visible;
int enabled;
char name[MAX_NAME_LENGTH]; char name[MAX_NAME_LENGTH];
char group[MAX_NAME_LENGTH]; char group[MAX_NAME_LENGTH];
char label[MAX_NAME_LENGTH]; char label[MAX_NAME_LENGTH];
int type;
int x;
int y;
int visible;
int enabled;
int numOptions; int numOptions;
char **options; char **options;
int value; int value;
int clicked;
Widget *next;
}; };
struct Atlas { struct Atlas {
@ -487,6 +484,21 @@ struct Atlas {
Atlas *next; 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 ==== */ /* ===== i18n stuff ==== */
struct Bucket { struct Bucket {

View File

@ -135,6 +135,7 @@ void initGameSystem(void)
initFonts, initFonts,
initAtlas, initAtlas,
initWidgets, initWidgets,
initTrophies,
initSounds, initSounds,
initSprites, initSprites,
initEntityFactory initEntityFactory

View File

@ -35,6 +35,7 @@ extern void initAtlas(void);
extern void initSounds(void); extern void initSounds(void);
extern void initSprites(void); extern void initSprites(void);
extern void initWidgets(void); extern void initWidgets(void);
extern void initTrophies(void);
extern void initEntityFactory(void); extern void initEntityFactory(void);
extern void destroyLookups(void); extern void destroyLookups(void);
extern void destroyFonts(void); extern void destroyFonts(void);

View File

@ -33,6 +33,8 @@ static void doKeyDown(SDL_KeyboardEvent *event)
if (event->keysym.scancode >= 0 && event->keysym.scancode < MAX_KEYBOARD_KEYS && event->repeat == 0) if (event->keysym.scancode >= 0 && event->keysym.scancode < MAX_KEYBOARD_KEYS && event->repeat == 0)
{ {
app.keyboard[event->keysym.scancode] = 1; 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) if (event->state == SDL_PRESSED)
{ {
app.joypadButton[event->button] = 1; app.joypadButton[event->button] = 1;
app.lastButtonPressed = event->button;
} }
} }

View File

@ -52,6 +52,29 @@ void initLookups(void)
addLookup("WT_BUTTON", WT_BUTTON); addLookup("WT_BUTTON", WT_BUTTON);
addLookup("WT_SPINNER", WT_SPINNER); addLookup("WT_SPINNER", WT_SPINNER);
addLookup("WT_PLAIN_BUTTON", WT_PLAIN_BUTTON); 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) static void addLookup(const char *name, long value)

View File

@ -20,28 +20,109 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "widgets.h" #include "widgets.h"
Widget *getWidgetAt(int x, int y);
static void loadWidgetGroup(char *filename); static void loadWidgetGroup(char *filename);
static void loadWidgets(void); static void loadWidgets(void);
static void createWidgetOptions(Widget *w, char *options);
static void selectWidget(int dir);
static Widget widgetHead; static Widget widgets[MAX_WIDGETS];
static Widget *widgetTail;
static Widget *selectedWidget; static Widget *selectedWidget;
static int widgetIndex;
static int numWidgets;
void initWidgets(void) void initWidgets(void)
{ {
memset(&widgetHead, 0, sizeof(Widget)); memset(widgets, 0, sizeof(Widget) * MAX_WIDGETS);
widgetTail = &widgetHead;
numWidgets = 0;
loadWidgets(); loadWidgets();
} }
Widget *getWidget(char *name, char *group) 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; Widget *w;
for (w = widgetHead.next ; w != NULL ; w = w->next) 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 (i = 0 ; i < numWidgets ; i++)
{
w = &widgets[i];
if (strcmp(w->name, name) == 0 && strcmp(w->group, group) == 0) if (strcmp(w->name, name) == 0 && strcmp(w->group, group) == 0)
{ {
return w; return w;
@ -54,59 +135,13 @@ Widget *getWidget(char *name, char *group)
return NULL; 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) 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; selectedWidget = NULL;
@ -114,12 +149,15 @@ void hideAllWidgets(void)
void showWidgetGroup(char *group) void showWidgetGroup(char *group)
{ {
int i;
Widget *w; Widget *w;
hideAllWidgets(); 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 (strcmp(w->group, group) == 0)
{ {
if (selectedWidget == NULL) 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) static void loadWidgets(void)
{ {
char **filenames; char **filenames;
@ -176,29 +203,28 @@ static void loadWidgetGroup(char *filename)
for (node = root->child ; node != NULL ; node = node->next) for (node = root->child ; node != NULL ; node = node->next)
{ {
w = malloc(sizeof(Widget)); if (++numWidgets >= MAX_WIDGETS)
memset(w, 0, sizeof(Widget)); {
widgetTail->next = w; SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Out of widget space.");
widgetTail = w; exit(1);
}
w = &widgets[numWidgets];
STRNCPY(w->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH); STRNCPY(w->name, cJSON_GetObjectItem(node, "name")->valuestring, MAX_NAME_LENGTH);
STRNCPY(w->group, cJSON_GetObjectItem(node, "group")->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); STRNCPY(w->label, cJSON_GetObjectItem(node, "label")->valuestring, MAX_NAME_LENGTH);
w->x = cJSON_GetObjectItem(node, "x")->valueint; w->x = cJSON_GetObjectItem(node, "x")->valueint;
w->y = cJSON_GetObjectItem(node, "y")->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); w->type = lookup(cJSON_GetObjectItem(node, "type")->valuestring);
switch (w->type) switch (w->type)
{ {
case WT_BUTTON:
break;
case WT_SPINNER: case WT_SPINNER:
createWidgetOptions(w, cJSON_GetObjectItem(node, "options")->valuestring);
break; break;
case WT_PLAIN_BUTTON: default:
break; break;
} }
} }
@ -208,6 +234,38 @@ static void loadWidgetGroup(char *filename)
free(text); 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) void destroy(void)
{ {
} }

View File

@ -21,7 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../common.h" #include "../common.h"
#include "../json/cJSON.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 *readFile(const char *filename);
extern char **getFileList(const char *dir, int *count); extern char **getFileList(const char *dir, int *count);
extern long lookup(const char *name); extern long lookup(const char *name);
extern App app;

View File

@ -20,9 +20,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "maths.h" #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) int rrnd(int low, int high)