Load / continue game updates.
This commit is contained in:
parent
ea5e23d568
commit
eae43acc73
|
@ -31,6 +31,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#define PI 3.14159265358979323846
|
#define PI 3.14159265358979323846
|
||||||
#define MIN(a,b) (((a)<(b))?(a):(b))
|
#define MIN(a,b) (((a)<(b))?(a):(b))
|
||||||
#define MAX(a,b) (((a)>(b))?(a):(b))
|
#define MAX(a,b) (((a)>(b))?(a):(b))
|
||||||
|
#define CAROLINE(a,b) MIN(a,b)
|
||||||
#define STRNCPY(dest, src, n) strncpy(dest, src, n); dest[n - 1] = '\0'
|
#define STRNCPY(dest, src, n) strncpy(dest, src, n); dest[n - 1] = '\0'
|
||||||
#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)
|
||||||
|
@ -51,8 +52,6 @@ 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
|
||||||
|
|
|
@ -23,6 +23,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
static void loadMetaInfo(void);
|
static void loadMetaInfo(void);
|
||||||
static void addKeyToStash(Item *item);
|
static void addKeyToStash(Item *item);
|
||||||
static int sortItems(const void *a, const void *b);
|
static int sortItems(const void *a, const void *b);
|
||||||
|
void destroyGame(void);
|
||||||
|
|
||||||
void initGame(void)
|
void initGame(void)
|
||||||
{
|
{
|
||||||
|
@ -37,6 +38,8 @@ void initGame(void)
|
||||||
game.stats[STAT_TIME_PLAYED] = 0;
|
game.stats[STAT_TIME_PLAYED] = 0;
|
||||||
|
|
||||||
loadMetaInfo();
|
loadMetaInfo();
|
||||||
|
|
||||||
|
loadTrophyData();
|
||||||
}
|
}
|
||||||
|
|
||||||
int addItem(Item *item, int num)
|
int addItem(Item *item, int num)
|
||||||
|
@ -270,6 +273,10 @@ void loadGame(void)
|
||||||
Tuple *t;
|
Tuple *t;
|
||||||
Trophy *trophy;
|
Trophy *trophy;
|
||||||
|
|
||||||
|
destroyGame();
|
||||||
|
|
||||||
|
initGame();
|
||||||
|
|
||||||
sprintf(filename, "%s/%d/game.json", app.saveDir, game.saveSlot);
|
sprintf(filename, "%s/%d/game.json", app.saveDir, game.saveSlot);
|
||||||
|
|
||||||
if (fileExists(filename))
|
if (fileExists(filename))
|
||||||
|
@ -439,6 +446,72 @@ void restoreGameState(void)
|
||||||
free(text);
|
free(text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *getSaveWidgetLabel(char *filename)
|
||||||
|
{
|
||||||
|
static char label[MAX_NAME_LENGTH];
|
||||||
|
cJSON *root, *statsJSON;
|
||||||
|
char *text, *statName;
|
||||||
|
int i, gameDone, gameTotal, stats[STAT_MAX];
|
||||||
|
|
||||||
|
strcpy(label, "");
|
||||||
|
|
||||||
|
sprintf(filename, "%s/%d/game.json", app.saveDir, game.saveSlot);
|
||||||
|
|
||||||
|
text = readFile(filename);
|
||||||
|
|
||||||
|
root = cJSON_Parse(text);
|
||||||
|
|
||||||
|
statsJSON = cJSON_GetObjectItem(root, "stats");
|
||||||
|
|
||||||
|
memset(stats, 0, sizeof(int) * STAT_MAX);
|
||||||
|
|
||||||
|
for (i = 0 ; i < STAT_MAX ; i++)
|
||||||
|
{
|
||||||
|
statName = getLookupName("STAT_", i);
|
||||||
|
|
||||||
|
if (cJSON_GetObjectItem(statsJSON, statName))
|
||||||
|
{
|
||||||
|
stats[i] = cJSON_GetObjectItem(statsJSON, statName)->valueint;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cJSON_Delete(root);
|
||||||
|
|
||||||
|
free(text);
|
||||||
|
|
||||||
|
gameDone = stats[STAT_MISSIONS_COMPLETE] + stats[STAT_MIAS_RESCUED] + stats[STAT_TARGETS_DEFEATED] + stats[STAT_KEYS_FOUND] + stats[STAT_HEARTS_FOUND] + stats[STAT_CELLS_FOUND];
|
||||||
|
gameTotal = game.totalMissions + game.totalMIAs + game.totalTargets + game.totalKeys + game.totalHearts + game.totalCells;
|
||||||
|
|
||||||
|
sprintf(label, "%d%% - %s", getPercent(gameDone, gameTotal), timeToString(stats[STAT_TIME_PLAYED], 1));
|
||||||
|
|
||||||
|
return label;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deleteSaveSlot(int slot)
|
||||||
|
{
|
||||||
|
int i, numFiles;
|
||||||
|
char path[MAX_FILENAME_LENGTH], **filenames;
|
||||||
|
|
||||||
|
sprintf(path, "%s/%d", app.saveDir, slot);
|
||||||
|
|
||||||
|
filenames = getFileList(path, &numFiles);
|
||||||
|
|
||||||
|
for (i = 0 ; i < numFiles ; i++)
|
||||||
|
{
|
||||||
|
sprintf(path, "%s/%d/%s", app.saveDir, i, filenames[i]);
|
||||||
|
|
||||||
|
if (!deleteFile(path))
|
||||||
|
{
|
||||||
|
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "Failed to delete save file '%s'", path);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(filenames[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(filenames);
|
||||||
|
}
|
||||||
|
|
||||||
static int sortItems(const void *a, const void *b)
|
static int sortItems(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
Entity *e1 = *((Entity**)a);
|
Entity *e1 = *((Entity**)a);
|
||||||
|
@ -460,4 +533,26 @@ static int sortItems(const void *a, const void *b)
|
||||||
|
|
||||||
void destroyGame(void)
|
void destroyGame(void)
|
||||||
{
|
{
|
||||||
|
Tuple *t;
|
||||||
|
Trophy *trophy;
|
||||||
|
|
||||||
|
memset(game.keys, 0, sizeof(Tuple) * MAX_KEY_TYPES);
|
||||||
|
|
||||||
|
while (game.missionStatusHead.next)
|
||||||
|
{
|
||||||
|
t = game.missionStatusHead.next;
|
||||||
|
|
||||||
|
game.missionStatusHead.next = t->next;
|
||||||
|
|
||||||
|
free(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
while (game.trophyHead.next)
|
||||||
|
{
|
||||||
|
trophy = game.trophyHead.next;
|
||||||
|
|
||||||
|
game.trophyHead.next = trophy->next;
|
||||||
|
|
||||||
|
free(trophy);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,6 +28,11 @@ extern Trophy *getTrophy(char *id);
|
||||||
extern int lookup(char *name);
|
extern int lookup(char *name);
|
||||||
extern char *readFile(const char *filename);
|
extern char *readFile(const char *filename);
|
||||||
extern int writeFile(const char *filename, const char *data);
|
extern int writeFile(const char *filename, const char *data);
|
||||||
|
extern char *timeToString(int seconds, int showHours);
|
||||||
|
extern int getPercent(float current, float total);
|
||||||
|
extern char **getFileList(const char *dir, int *count);
|
||||||
|
extern int deleteFile(char *path);
|
||||||
|
extern void loadTrophyData(void);
|
||||||
|
|
||||||
extern App app;
|
extern App app;
|
||||||
extern Entity *self;
|
extern Entity *self;
|
||||||
|
|
153
src/game/title.c
153
src/game/title.c
|
@ -23,16 +23,32 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
static void logic(void);
|
static void logic(void);
|
||||||
static void draw(void);
|
static void draw(void);
|
||||||
static int getRecentSave(void);
|
static int getRecentSave(void);
|
||||||
|
static void populateSaveSlotWidgets(void);
|
||||||
|
static void doNewGame(void);
|
||||||
|
static void doLoadGame(void);
|
||||||
|
static void doContinueGame(void);
|
||||||
|
static void doOptions(void);
|
||||||
|
static void doCredits(void);
|
||||||
|
static void doQuit(void);
|
||||||
|
static void doSaveSlot(void);
|
||||||
|
static void doLoadCancel(void);
|
||||||
|
static void doOK(void);
|
||||||
|
static void doCancel(void);
|
||||||
|
|
||||||
static Texture *atlasTexture;
|
static Texture *atlasTexture;
|
||||||
static Atlas *title;
|
static Atlas *title;
|
||||||
static int recentSaveSlot;
|
static int recentSaveSlot;
|
||||||
|
static int saveAction;
|
||||||
static Widget *newGame;
|
static Widget *newGame;
|
||||||
static Widget *loadGame;
|
static Widget *load;
|
||||||
static Widget *continueGame;
|
static Widget *continueGame;
|
||||||
static Widget *options;
|
static Widget *options;
|
||||||
static Widget *credits;
|
static Widget *credits;
|
||||||
static Widget *quit;
|
static Widget *quit;
|
||||||
|
static Widget *save[MAX_SAVE_SLOTS];
|
||||||
|
static Widget *loadCancel;
|
||||||
|
static Widget *ok;
|
||||||
|
static Widget *cancel;
|
||||||
|
|
||||||
void initTitle(void)
|
void initTitle(void)
|
||||||
{
|
{
|
||||||
|
@ -43,11 +59,33 @@ void initTitle(void)
|
||||||
title = getImageFromAtlas("gfx/main/title.png");
|
title = getImageFromAtlas("gfx/main/title.png");
|
||||||
|
|
||||||
newGame = getWidget("new", "title");
|
newGame = getWidget("new", "title");
|
||||||
loadGame = getWidget("load", "title");
|
newGame->action = &doNewGame;
|
||||||
|
|
||||||
|
load = getWidget("load", "title");
|
||||||
|
load->action = &doLoadGame;
|
||||||
|
|
||||||
continueGame = getWidget("continue", "title");
|
continueGame = getWidget("continue", "title");
|
||||||
|
continueGame->action = &doContinueGame;
|
||||||
|
|
||||||
options = getWidget("options", "title");
|
options = getWidget("options", "title");
|
||||||
|
options->action = &doOptions;
|
||||||
|
|
||||||
credits = getWidget("credits", "title");
|
credits = getWidget("credits", "title");
|
||||||
|
credits->action = &doCredits;
|
||||||
|
|
||||||
quit = getWidget("exit", "title");
|
quit = getWidget("exit", "title");
|
||||||
|
quit->action = &doQuit;
|
||||||
|
|
||||||
|
populateSaveSlotWidgets();
|
||||||
|
|
||||||
|
loadCancel = getWidget("cancel", "load");
|
||||||
|
loadCancel->action = doLoadCancel;
|
||||||
|
|
||||||
|
ok = getWidget("ok", "destroy");
|
||||||
|
ok->action = doOK;
|
||||||
|
|
||||||
|
cancel = getWidget("cancel", "destroy");
|
||||||
|
cancel->action = doCancel;
|
||||||
|
|
||||||
recentSaveSlot = getRecentSave();
|
recentSaveSlot = getRecentSave();
|
||||||
|
|
||||||
|
@ -59,7 +97,7 @@ void initTitle(void)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
loadGame->disabled = 1;
|
load->disabled = 1;
|
||||||
continueGame->disabled = 1;
|
continueGame->disabled = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,8 +116,8 @@ static void draw(void)
|
||||||
{
|
{
|
||||||
blitRect(atlasTexture->texture, SCREEN_WIDTH / 2, 175, &title->rect, 1);
|
blitRect(atlasTexture->texture, SCREEN_WIDTH / 2, 175, &title->rect, 1);
|
||||||
|
|
||||||
drawText(10, SCREEN_HEIGHT - 30, 18, TA_LEFT, colors.white, "Copyright 2014, 2018 Parallel Realities");
|
drawText(10, SCREEN_HEIGHT - 30, 16, TA_LEFT, colors.white, "Copyright 2014, 2018 Parallel Realities");
|
||||||
drawText(SCREEN_WIDTH - 10, SCREEN_HEIGHT - 30, 18, TA_RIGHT, colors.white, "Version %.2f.%d", VERSION, REVISION);
|
drawText(SCREEN_WIDTH - 10, SCREEN_HEIGHT - 30, 16, TA_RIGHT, colors.white, "Version %.2f.%d", VERSION, REVISION);
|
||||||
|
|
||||||
drawWidgets();
|
drawWidgets();
|
||||||
}
|
}
|
||||||
|
@ -110,3 +148,108 @@ static int getRecentSave(void)
|
||||||
|
|
||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void populateSaveSlotWidgets(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
char name[MAX_NAME_LENGTH], filename[MAX_FILENAME_LENGTH];
|
||||||
|
|
||||||
|
for (i = 0 ; i < MAX_SAVE_SLOTS ; i++)
|
||||||
|
{
|
||||||
|
sprintf(name, "save%d", i);
|
||||||
|
|
||||||
|
save[i] = getWidget(name, "saveSlot");
|
||||||
|
|
||||||
|
sprintf(filename, "%s/%d/game.json", app.saveDir, i);
|
||||||
|
|
||||||
|
if (fileExists(filename))
|
||||||
|
{
|
||||||
|
strcpy(save[i]->label, getSaveWidgetLabel(filename));
|
||||||
|
save[i]->value[0] = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
strcpy(save[i]->label, "(empty)");
|
||||||
|
save[i]->value[0] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
save[i]->value[1] = i;
|
||||||
|
|
||||||
|
save[i]->action = &doSaveSlot;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doNewGame(void)
|
||||||
|
{
|
||||||
|
saveAction = SA_DELETE;
|
||||||
|
|
||||||
|
destroyGame();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doLoadGame(void)
|
||||||
|
{
|
||||||
|
saveAction = SA_LOAD;
|
||||||
|
|
||||||
|
showWidgetGroup("saveSlot");
|
||||||
|
|
||||||
|
loadCancel->visible = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doContinueGame(void)
|
||||||
|
{
|
||||||
|
game.saveSlot = continueGame->value[1];
|
||||||
|
|
||||||
|
loadGame();
|
||||||
|
|
||||||
|
initHub();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doOptions(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doCredits(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doQuit(void)
|
||||||
|
{
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doSaveSlot(void)
|
||||||
|
{
|
||||||
|
Widget *w;
|
||||||
|
|
||||||
|
w = getSelectedWidget();
|
||||||
|
|
||||||
|
game.saveSlot = w->value[1];
|
||||||
|
|
||||||
|
if (saveAction == SA_LOAD)
|
||||||
|
{
|
||||||
|
loadGame();
|
||||||
|
|
||||||
|
initHub();
|
||||||
|
}
|
||||||
|
else if (saveAction == SA_DELETE)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doLoadCancel(void)
|
||||||
|
{
|
||||||
|
showWidgetGroup("title");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doOK(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
static void doCancel(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,12 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
|
|
||||||
#include "../common.h"
|
#include "../common.h"
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
SA_LOAD,
|
||||||
|
SA_DELETE
|
||||||
|
};
|
||||||
|
|
||||||
extern void blitRect(SDL_Texture *texture, int x, int y, SDL_Rect *srcRect, int center);
|
extern void blitRect(SDL_Texture *texture, int x, int y, SDL_Rect *srcRect, int center);
|
||||||
extern void doWidgets(void);
|
extern void doWidgets(void);
|
||||||
extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...);
|
extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...);
|
||||||
|
@ -35,6 +41,12 @@ extern void startSectionTransition(void);
|
||||||
extern long getFileModTime(char *filename);
|
extern long getFileModTime(char *filename);
|
||||||
extern int fileExists(const char *filename);
|
extern int fileExists(const char *filename);
|
||||||
extern void setSelectedWidget(char *name, char *group);
|
extern void setSelectedWidget(char *name, char *group);
|
||||||
|
extern char *getSaveWidgetLabel(char *filename);
|
||||||
|
extern Widget *getSelectedWidget(void);
|
||||||
|
extern void loadGame(void);
|
||||||
|
extern void initHub(void);
|
||||||
|
extern void destroyGame(void);
|
||||||
|
|
||||||
extern App app;
|
extern App app;
|
||||||
extern Colors colors;
|
extern Colors colors;
|
||||||
|
extern Game game;
|
||||||
|
|
|
@ -21,7 +21,6 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||||||
#include "trophies.h"
|
#include "trophies.h"
|
||||||
|
|
||||||
static void setSparkleColor(Trophy *t);
|
static void setSparkleColor(Trophy *t);
|
||||||
static void loadTrophyData(void);
|
|
||||||
static void resetAlert(void);
|
static void resetAlert(void);
|
||||||
static void nextAlert(void);
|
static void nextAlert(void);
|
||||||
|
|
||||||
|
@ -68,12 +67,6 @@ void initTrophies(void)
|
||||||
|
|
||||||
page = 0;
|
page = 0;
|
||||||
|
|
||||||
loadTrophyData();
|
|
||||||
|
|
||||||
maxPages = numTrophies;
|
|
||||||
maxPages /= TROPHIES_PER_PAGE;
|
|
||||||
maxPages = ceil(maxPages);
|
|
||||||
|
|
||||||
resetAlert();
|
resetAlert();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,7 +344,7 @@ void saveTrophyScreenshot(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void loadTrophyData(void)
|
void loadTrophyData(void)
|
||||||
{
|
{
|
||||||
cJSON *root, *node;
|
cJSON *root, *node;
|
||||||
char *text;
|
char *text;
|
||||||
|
@ -395,6 +388,10 @@ static void loadTrophyData(void)
|
||||||
|
|
||||||
cJSON_Delete(root);
|
cJSON_Delete(root);
|
||||||
free(text);
|
free(text);
|
||||||
|
|
||||||
|
maxPages = numTrophies;
|
||||||
|
maxPages /= TROPHIES_PER_PAGE;
|
||||||
|
maxPages = ceil(maxPages);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void setSparkleColor(Trophy *t)
|
static void setSparkleColor(Trophy *t)
|
||||||
|
|
|
@ -195,6 +195,11 @@ char **getFileList(const char *dir, int *count)
|
||||||
return filenames;
|
return filenames;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int deleteFile(char *path)
|
||||||
|
{
|
||||||
|
return unlink(path);
|
||||||
|
}
|
||||||
|
|
||||||
static int stringComparator(const void *a, const void *b)
|
static int stringComparator(const void *a, const void *b)
|
||||||
{
|
{
|
||||||
char **s1 = (char **)a;
|
char **s1 = (char **)a;
|
||||||
|
|
|
@ -299,7 +299,25 @@ Widget *getWidget(char *name, char *group)
|
||||||
|
|
||||||
void setSelectedWidget(char *name, char *group)
|
void setSelectedWidget(char *name, char *group)
|
||||||
{
|
{
|
||||||
selectedWidget = getWidget(name, group);
|
Widget *w;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0 ; i < numWidgets ; i++)
|
||||||
|
{
|
||||||
|
w = &widgets[i];
|
||||||
|
|
||||||
|
if (strcmp(w->name, name) == 0 && strcmp(w->group, group) == 0)
|
||||||
|
{
|
||||||
|
widgetIndex = i;
|
||||||
|
selectedWidget = w;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Widget *getSelectedWidget(void)
|
||||||
|
{
|
||||||
|
return selectedWidget;
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget *selectWidgetAt(int x, int y)
|
Widget *selectWidgetAt(int x, int y)
|
||||||
|
|
|
@ -21,6 +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"
|
||||||
|
|
||||||
|
#define MAX_WIDGETS 64
|
||||||
|
|
||||||
extern void clearControl(int type);
|
extern void clearControl(int type);
|
||||||
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
|
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
|
||||||
extern void drawOutlineRect(int x, int y, int w, int h, int r, int g, int b, int a);
|
extern void drawOutlineRect(int x, int y, int w, int h, int r, int g, int b, int a);
|
||||||
|
|
Loading…
Reference in New Issue