Challenge integration updates.

This commit is contained in:
Steve 2016-02-28 13:02:57 +00:00
parent a1703d5066
commit ad7a1eefda
28 changed files with 385 additions and 211 deletions

View File

@ -1,6 +1,6 @@
{
"name" : "Destroy all the Darts",
"description" : "Destroy all the Darts",
"name" : "Destroy all Darts",
"description" : "Destroy all Darts",
"background" : "gfx/backgrounds/background03.jpg",
"planet" : "gfx/planets/spirit.png",
"music" : "",
@ -12,32 +12,20 @@
"x" : 25,
"y" : 25
},
"objectives" : [
{
"description" : "Destroy Dart",
"targetName" : "Dart",
"targetValue" : 3,
"targetType" : "TT_DESTROY"
}
],
"challenge" : {
"timeLimit" : 30,
"killLimit" : 3,
"challenges" : [
{
"type" : "CHALLENGE_TIME",
"value" : 20
},
{
"type" : "CHALLENGE_TIME",
"value" : 15
},
{
"type" : "CHALLENGE_TIME",
"value" : 10
"value" : 30
}
],
]
},
"fighters" : [
{
"name" : "Dart",
"types" : "Dart",
"types" : "SimpleDart",
"side" : "SIDE_PIRATE",
"x" : 25,
"y" : 22,

40
data/challenges/02.json Normal file
View File

@ -0,0 +1,40 @@
{
"name" : "Destroy all Darts",
"description" : "Destroy all Darts",
"background" : "gfx/backgrounds/background03.jpg",
"planet" : "gfx/planets/spirit.png",
"music" : "",
"player" : {
"type" : "Nymph",
"side" : "SIDE_ALLIES",
"pilot" : "-",
"squadron" : "-",
"x" : 25,
"y" : 25
},
"challenge" : {
"timeLimit" : 20,
"killLimit" : 5,
"challenges" : [
{
"type" : "CHALLENGE_TIME",
"value" : 30
},
{
"type" : "CHALLENGE_TIME",
"value" : 15
}
]
},
"fighters" : [
{
"name" : "Dart",
"types" : "Dart",
"side" : "SIDE_PIRATE",
"x" : 25,
"y" : 22,
"number" : 3,
"scatter" : 1000
}
]
}

44
data/challenges/03.json Normal file
View File

@ -0,0 +1,44 @@
{
"name" : "Destroy all Darts",
"description" : "Destroy all Darts",
"background" : "gfx/backgrounds/background03.jpg",
"planet" : "gfx/planets/spirit.png",
"music" : "",
"player" : {
"type" : "Nymph",
"side" : "SIDE_ALLIES",
"pilot" : "-",
"squadron" : "-",
"x" : 25,
"y" : 25
},
"challenge" : {
"timeLimit" : 20,
"killLimit" : 3,
"challenges" : [
{
"type" : "CHALLENGE_TIME",
"value" : 20
},
{
"type" : "CHALLENGE_TIME",
"value" : 15
},
{
"type" : "CHALLENGE_TIME",
"value" : 10
}
]
},
"fighters" : [
{
"name" : "Dart",
"types" : "Dart",
"side" : "SIDE_PIRATE",
"x" : 25,
"y" : 22,
"number" : 3,
"scatter" : 1000
}
]
}

View File

@ -290,7 +290,7 @@ static void findTarget(void)
Entity *e, **candidates;
unsigned int dist, closest;
dist = closest = (battle.epic || (self->aiFlags & AIF_UNLIMITED_RANGE)) ? MAX_TARGET_RANGE : 2000;
dist = closest = (battle.isEpic || (self->aiFlags & AIF_UNLIMITED_RANGE)) ? MAX_TARGET_RANGE : 2000;
candidates = getAllEntsWithin(self->x - (self->w / 2) - (dist / 2), self->y - (self->h / 2) - (dist / 2), self->w + dist, self->h + dist, self);

View File

@ -102,11 +102,11 @@ static void logic(void)
if (show == SHOW_BATTLE)
{
if (!battle.epic || (battle.epic && !battle.playerSelect))
if (!battle.isEpic || (battle.isEpic && !battle.playerSelect))
{
doBattle();
}
else if (battle.epic && battle.playerSelect)
else if (battle.isEpic && battle.playerSelect)
{
doPlayerSelect();
}
@ -135,6 +135,8 @@ static void doBattle(void)
doObjectives();
doChallenges();
doHud();
doStars(ssx, ssy);
@ -303,7 +305,7 @@ static void continueGame(void)
destroyBattle();
if (!battle.isChallenge)
if (!battle.challengeData.isChallenge)
{
initGalacticMap();
}
@ -344,7 +346,7 @@ static void quitBattle(void)
destroyBattle();
if (!battle.isChallenge)
if (!battle.challengeData.isChallenge)
{
initGalacticMap();
}
@ -366,7 +368,7 @@ static void postBattle(void)
}
}
if (!battle.isChallenge)
if (!battle.challengeData.isChallenge)
{
if (game.currentMission && !game.currentMission->completed)
{

View File

@ -39,6 +39,7 @@ extern void drawHud(void);
extern void drawEffects(void);
extern void doEffects(void);
extern void doObjectives(void);
extern void doChallenges(void);
extern void blitScaled(SDL_Texture *texture, int x, int y, int w, int h);
extern void initHud(void);
extern void initRadar(void);

View File

@ -180,7 +180,7 @@ void doEntities(void)
{
player = NULL;
battle.playerSelect = battle.epic;
battle.playerSelect = battle.isEpic;
}
cutRope(e);
@ -221,10 +221,10 @@ void doEntities(void)
prev = e;
}
battle.numAllies = (battle.epic) ? numAllies : numActiveAllies;
battle.numEnemies = (battle.epic) ? numEnemies : numActiveEnemies;
battle.numAllies = (battle.isEpic) ? numAllies : numActiveAllies;
battle.numEnemies = (battle.isEpic) ? numEnemies : numActiveEnemies;
if (battle.epic && battle.stats[STAT_TIME] % FPS == 0)
if (battle.isEpic && battle.stats[STAT_TIME] % FPS == 0)
{
if (numAllies > battle.epicFighterLimit)
{

View File

@ -283,7 +283,7 @@ void doFighter(void)
if (strcmp(self->name, "Civilian") == 0)
{
battle.stats[STAT_CIVILIANS_KILLED]++;
if (!battle.epic)
if (!battle.isEpic)
{
addHudMessage(colors.red, "Civilian has been killed");
}
@ -291,7 +291,7 @@ void doFighter(void)
else
{
battle.stats[STAT_ALLIES_KILLED]++;
if (!battle.epic)
if (!battle.isEpic)
{
addHudMessage(colors.red, "Ally has been killed");
}
@ -483,7 +483,7 @@ static void die(void)
break;
}
if (self == player && battle.epic)
if (self == player && battle.isEpic)
{
n = 1;
}

View File

@ -394,13 +394,20 @@ static void drawNumFighters(void)
static void drawObjectives(void)
{
if (!battle.isChallenge)
if (!battle.challengeData.isChallenge)
{
drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, "%d / %d", battle.numObjectivesComplete, battle.numObjectivesTotal);
}
else
{
drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, "%d.%02d", battle.stats[STAT_TIME] / FPS, battle.stats[STAT_TIME] % 100);
if (battle.challengeData.timeLimit)
{
drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, timeToString(battle.challengeData.timeLimit - battle.stats[STAT_TIME], 0));
}
else
{
drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, timeToString(battle.stats[STAT_TIME], 0));
}
}
}

View File

@ -33,6 +33,7 @@ extern void drawRadarRangeWarning(void);
extern int getPercent(float current, float total);
extern int playerHasGun(int type);
extern char *getTranslatedString(char *string);
extern char *timeToString(long millis, int showHours);
extern App app;
extern Battle battle;

View File

@ -21,6 +21,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "missionInfo.h"
static void drawMissionSummary(SDL_Texture *title);
static void drawObjectives(void);
static void drawChallenges(void);
static SDL_Texture *missionStartTexture;
static SDL_Texture *missionInProgressTexture;
@ -30,10 +32,10 @@ static const char *objectiveStatus[] = {"Incomplete", "Complete", "Failed", "Con
void initMissionInfo(void)
{
missionStartTexture = !battle.isChallenge ? getTexture("gfx/battle/missionStart.png") : getTexture("gfx/battle/challengeStart.png");
missionInProgressTexture = !battle.isChallenge ? getTexture("gfx/battle/missionInProgress.png") : getTexture("gfx/battle/challengeInProgress.png");
missionCompleteTexture = !battle.isChallenge ? getTexture("gfx/battle/missionComplete.png") : getTexture("gfx/battle/challengeComplete.png");
missionFailedTexture = !battle.isChallenge ? getTexture("gfx/battle/missionFailed.png") : getTexture("gfx/battle/challengeFailed.png");
missionStartTexture = !battle.challengeData.isChallenge ? getTexture("gfx/battle/missionStart.png") : getTexture("gfx/battle/challengeStart.png");
missionInProgressTexture = !battle.challengeData.isChallenge ? getTexture("gfx/battle/missionInProgress.png") : getTexture("gfx/battle/challengeInProgress.png");
missionCompleteTexture = !battle.challengeData.isChallenge ? getTexture("gfx/battle/missionComplete.png") : getTexture("gfx/battle/challengeComplete.png");
missionFailedTexture = !battle.challengeData.isChallenge ? getTexture("gfx/battle/missionFailed.png") : getTexture("gfx/battle/challengeFailed.png");
}
void drawMissionInfo(void)
@ -70,12 +72,6 @@ void drawMissionInfo(void)
static void drawMissionSummary(SDL_Texture *header)
{
Objective *o;
Challenge *c;
int y;
SDL_Color color;
char *challengeStatus;
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
SDL_RenderFillRect(app.renderer, NULL);
@ -83,10 +79,22 @@ static void drawMissionSummary(SDL_Texture *header)
blit(header, SCREEN_WIDTH / 2, 150, 1);
y = 215;
if (!battle.isChallenge)
if (!battle.challengeData.isChallenge)
{
drawObjectives();
}
else
{
drawChallenges();
}
}
static void drawObjectives(void)
{
Objective *o;
SDL_Color color;
int y = 215;
drawText(SCREEN_WIDTH / 2, y, 28, TA_CENTER, colors.white, _("OBJECTIVES"));
y += 10;
@ -131,10 +139,22 @@ static void drawMissionSummary(SDL_Texture *header)
y += 75;
}
if (battle.isChallenge)
static void drawChallenges(void)
{
Challenge *c;
char *challengeStatus;
SDL_Color color;
int y = 215;
drawText(SCREEN_WIDTH / 2, y, 24, TA_CENTER, colors.white, game.currentMission->description);
if (battle.status == MS_START && battle.challengeData.timeLimit)
{
y+= 50;
drawText(SCREEN_WIDTH / 2, y, 20, TA_CENTER, colors.white, "Time Limit: %s", timeToString(battle.challengeData.timeLimit, 0));
}
y += 25;
for (c = game.currentMission->challengeHead.next ; c != NULL ; c = c->next)
@ -143,23 +163,23 @@ static void drawMissionSummary(SDL_Texture *header)
color = colors.white;
challengeStatus = "Incomplete";
challengeStatus = _("Incomplete");
if (c->passed)
{
color = colors.green;
challengeStatus = "Complete";
challengeStatus = _("Complete");
}
else if (battle.status == MS_COMPLETE ||battle.status == MS_FAILED)
{
color = colors.red;
challengeStatus = "Failed";
challengeStatus = _("Failed");
}
drawText(SCREEN_WIDTH / 2 - 50, y, 22, TA_RIGHT, colors.white, "%s", getChallengeDescription(c));
drawText(SCREEN_WIDTH / 2 + 50, y, 22, TA_LEFT, color, challengeStatus);
}
}
}

View File

@ -26,6 +26,7 @@ extern SDL_Texture *getTexture(char *filename);
extern char *getChallengeDescription(Challenge *c);
extern void drawWidgets(char *groupName);
extern char *getTranslatedString(char *string);
extern char *timeToString(long millis, int showHours);
extern App app;
extern Battle battle;

View File

@ -64,8 +64,6 @@ void doObjectives(void)
if (!battle.manualComplete && numHiddenObjectives == 0 && battle.numObjectivesTotal > 0 && battle.numObjectivesComplete == battle.numObjectivesTotal)
{
completeMission();
updateChallenges();
}
if (objectiveFailed)

View File

@ -114,7 +114,7 @@ void doPlayer(void)
if (player->health <= 0 && battle.status == MS_IN_PROGRESS)
{
if (!battle.epic)
if (!battle.isEpic)
{
failMission();
}
@ -326,7 +326,7 @@ void initPlayerSelect(void)
}
else
{
battle.epic = 0;
battle.isEpic = 0;
failMission();
}

View File

@ -167,12 +167,12 @@ static void executeNextLine(ScriptRunner *runner)
}
else if (strcmp(command, "RETREAT_ALLIES") == 0)
{
battle.epic = 0;
battle.isEpic = 0;
retreatAllies();
}
else if (strcmp(command, "RETREAT_ENEMIES") == 0)
{
battle.epic = 0;
battle.isEpic = 0;
retreatEnemies();
}
else

View File

@ -177,6 +177,11 @@ static void drawChallenges(void)
i++;
}
if (game.currentMission)
{
drawText(SCREEN_WIDTH / 2, SCREEN_HEIGHT - 130, 24, TA_CENTER, colors.white, game.currentMission->description);
}
}
static void handleKeyboard(void)

View File

@ -26,6 +26,9 @@ static void updateArmourChallenge(Challenge *c);
static void updateLossesChallenge(Challenge *c);
static void updatePlayerKillsChallenge(Challenge *c);
static void updateDisabledChallenge(Challenge *c);
static void completeChallenge(void);
static void failChallenge(void);
static void updateChallenges(void);
static char *getFormattedChallengeDescription(const char *format, ...);
char *getChallengeDescription(Challenge *c);
@ -68,7 +71,28 @@ void initChallenges(void)
free(filenames);
}
void updateChallenges(void)
void doChallenges(void)
{
if (battle.challengeData.isChallenge && battle.status == MS_IN_PROGRESS)
{
if (battle.challengeData.timeLimit > 0 && battle.stats[STAT_TIME] / FPS >= battle.challengeData.timeLimit)
{
failChallenge();
}
if (battle.challengeData.killLimit > 0 && battle.stats[STAT_ENEMIES_KILLED_PLAYER] >= battle.challengeData.killLimit)
{
completeChallenge();
}
if (battle.status != MS_IN_PROGRESS)
{
updateChallenges();
}
}
}
static void updateChallenges(void)
{
Challenge *c;
@ -213,3 +237,37 @@ static char *getFormattedChallengeDescription(const char *format, ...)
return descriptionBuffer;
}
static void completeChallenge(void)
{
if (battle.status == MS_IN_PROGRESS)
{
battle.status = MS_COMPLETE;
battle.missionFinishedTimer = FPS;
selectWidget("continue", "battleWon");
game.stats[STAT_CHALLENGES_COMPLETED]++;
retreatAllies();
retreatEnemies();
player->flags |= EF_IMMORTAL;
}
}
static void failChallenge(void)
{
if (battle.status == MS_IN_PROGRESS)
{
battle.status = MS_FAILED;
battle.missionFinishedTimer = FPS;
selectWidget("retry", "battleLost");
retreatAllies();
retreatEnemies();
player->flags |= EF_IMMORTAL;
}
}

View File

@ -22,6 +22,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern Mission *loadMissionMeta(char *filename);
extern char **getFileList(char *dir, int *count);
extern void selectWidget(const char *name, const char *group);
extern void retreatAllies(void);
extern void retreatEnemies(void);
extern Battle battle;
extern Entity *player;

View File

@ -267,6 +267,8 @@ enum
{
STAT_MISSIONS_STARTED,
STAT_MISSIONS_COMPLETED,
STAT_CHALLENGES_STARTED,
STAT_CHALLENGES_COMPLETED,
STAT_SHOTS_FIRED,
STAT_SHOTS_HIT,
STAT_ROCKETS_FIRED,

View File

@ -30,6 +30,7 @@ static void loadLocations(cJSON *node);
static unsigned long hashcode(const char *str);
static char **toTypeArray(char *types, int *numTypes);
static void loadEpicData(cJSON *node);
static void loadChallengeData(cJSON *node);
Mission *loadMissionMeta(char *filename)
{
@ -72,7 +73,11 @@ Mission *loadMissionMeta(char *filename)
challengeTail = &mission->challengeHead;
node = cJSON_GetObjectItem(root, "challenges");
node = cJSON_GetObjectItem(root, "challenge");
if (node)
{
node = cJSON_GetObjectItem(node, "challenges");
if (node)
{
@ -92,6 +97,7 @@ Mission *loadMissionMeta(char *filename)
node = node->next;
}
}
}
cJSON_Delete(root);
free(text);
@ -147,6 +153,11 @@ void loadMission(char *filename)
loadEpicData(cJSON_GetObjectItem(root, "epic"));
}
if (cJSON_GetObjectItem(root, "challenge"))
{
loadChallengeData(cJSON_GetObjectItem(root, "challenge"));
}
if (cJSON_GetObjectItem(root, "manualComplete"))
{
battle.manualComplete = cJSON_GetObjectItem(root, "manualComplete")->valueint;
@ -165,11 +176,15 @@ void loadMission(char *filename)
endSectionTransition();
/* only increment num missions started if there are objectives (Free Flight excluded, for example) */
/* only increment num missions / challenges started if there are some (Free Flight excluded, for example) */
if (battle.objectiveHead.next)
{
game.stats[STAT_MISSIONS_STARTED]++;
}
else if (battle.challengeData.isChallenge)
{
game.stats[STAT_CHALLENGES_STARTED]++;
}
else
{
battle.status = MS_IN_PROGRESS;
@ -181,8 +196,6 @@ void loadMission(char *filename)
initPlayer();
battle.isChallenge = game.currentMission->challengeHead.next != NULL;
initMissionInfo();
playMusic(music);
@ -801,7 +814,7 @@ static void loadEpicData(cJSON *node)
int numFighters[SIDE_MAX];
memset(numFighters, 0, sizeof(int) * SIDE_MAX);
battle.epic = 1;
battle.isEpic = 1;
battle.epicFighterLimit = cJSON_GetObjectItem(node, "fighterLimit")->valueint;
@ -814,6 +827,13 @@ static void loadEpicData(cJSON *node)
}
}
static void loadChallengeData(cJSON *node)
{
battle.challengeData.isChallenge = 1;
battle.challengeData.timeLimit = cJSON_GetObjectItem(node, "timeLimit")->valueint * FPS;
battle.challengeData.killLimit = cJSON_GetObjectItem(node, "killLimit")->valueint;
}
Mission *getMission(char *filename)
{
StarSystem *starSystem;

View File

@ -74,9 +74,8 @@ void initStatsDisplay(void)
void drawStats(void)
{
int i, y, hours, minutes, seconds, startIndex;
int i, y, startIndex;
SDL_Rect r;
char timePlayed[MAX_NAME_LENGTH];
SDL_SetRenderDrawBlendMode(app.renderer, SDL_BLENDMODE_BLEND);
SDL_SetRenderDrawColor(app.renderer, 0, 0, 0, 128);
@ -111,15 +110,8 @@ void drawStats(void)
}
}
seconds = game.stats[STAT_TIME] / FPS;
minutes = (seconds / 60) % 60;
hours = seconds / (60 * 60);
seconds %= 60;
sprintf(timePlayed, "%dh:%02dm:%02ds", hours, minutes, seconds);
drawText(r.x + 20, 565, 18, TA_LEFT, colors.white, _("Time Played"));
drawText(r.x + r.w - 20, 565, 18, TA_RIGHT, colors.white, timePlayed);
drawText(r.x + r.w - 20, 565, 18, TA_RIGHT, colors.white, timeToString(game.stats[STAT_TIME], 1));
drawWidgets("stats");
}

View File

@ -26,6 +26,7 @@ extern void drawWidgets(char *groupName);
extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...);
extern Widget *getWidget(const char *name, const char *group);
extern char *getTranslatedString(char *string);
extern char *timeToString(long millis, int showHours);
extern App app;
extern Colors colors;

View File

@ -250,11 +250,11 @@ struct Mission {
char craft[MAX_NAME_LENGTH];
int available;
int completed;
int epic;
int completedChallenges;
int totalChallenges;
SDL_Rect rect;
int epic;
Challenge challengeHead;
SDL_Rect rect;
Mission *next;
};
@ -282,6 +282,14 @@ struct Quadtree {
Quadtree *node[4];
};
typedef struct {
int isChallenge;
int timeLimit;
int killLimit;
int lossLimit;
int itemLimit;
} ChallengeData;
typedef struct {
int entId;
SDL_Point camera;
@ -289,8 +297,7 @@ typedef struct {
int numEnemies;
int numInitialEnemies;
int status;
int epic;
int isChallenge;
int isEpic;
int epicFighterLimit;
int playerSelect;
int manualComplete;
@ -314,6 +321,7 @@ typedef struct {
Location locationHead, *locationTail;
struct cJSON *missionJSON;
unsigned int stats[STAT_MAX];
ChallengeData challengeData;
Quadtree quadtree;
} Battle;

View File

@ -94,11 +94,14 @@ static void loadChallenges(cJSON *missionsJSON)
challenge = getChallenge(mission, type, value);
if (challenge)
{
challenge->passed = cJSON_GetObjectItem(challengeJSON, "passed")->valueint;
}
}
}
}
}
static void loadStats(cJSON *stats)
{

View File

@ -118,6 +118,8 @@ void initLookups(void)
addLookup("STAT_MISSIONS_STARTED", STAT_MISSIONS_STARTED);
addLookup("STAT_MISSIONS_COMPLETED", STAT_MISSIONS_COMPLETED);
addLookup("STAT_CHALLENGES_STARTED", STAT_CHALLENGES_STARTED);
addLookup("STAT_CHALLENGES_COMPLETED", STAT_CHALLENGES_COMPLETED);
addLookup("STAT_SHOTS_FIRED", STAT_SHOTS_FIRED);
addLookup("STAT_SHOTS_HIT", STAT_SHOTS_HIT);
addLookup("STAT_ROCKETS_FIRED", STAT_ROCKETS_FIRED);

View File

@ -72,3 +72,26 @@ void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy)
*dy = (y1 - y2);
*dy /= steps;
}
char *timeToString(long millis, int showHours)
{
static char TIME[MAX_NAME_LENGTH];
int hours, minutes, seconds;
seconds = millis / FPS;
minutes = (seconds / 60) % 60;
hours = seconds / (60 * 60);
seconds %= 60;
if (showHours)
{
sprintf(TIME, "%dh:%02dm:%02ds", hours, minutes, seconds);
}
else
{
sprintf(TIME, "%dm %02ds", minutes, seconds);
}
return TIME;
}

View File

@ -20,58 +20,11 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "testMission.h"
static Mission mission;
static void loadChallenges(char *filename);
void loadTestMission(char *filename)
{
memset(&mission, 0, sizeof(Mission));
STRNCPY(mission.filename, filename, MAX_DESCRIPTION_LENGTH);
game.currentMission = &mission;
game.currentMission = loadMissionMeta(filename);
initBattle();
loadChallenges(filename);
loadMission(filename);
}
static void loadChallenges(char *filename)
{
Challenge *challenge, *challengeTail;
cJSON *root, *node;
char *text;
text = readFile(filename);
root = cJSON_Parse(text);
challengeTail = &mission.challengeHead;
node = cJSON_GetObjectItem(root, "challenges");
if (node)
{
node = node->child;
while (node)
{
challenge = malloc(sizeof(Challenge));
memset(challenge, 0, sizeof(Challenge));
challenge->type = lookup(cJSON_GetObjectItem(node, "type")->valuestring);
challenge->value = cJSON_GetObjectItem(node, "value")->valueint;
challengeTail->next = challenge;
challengeTail = challenge;
node = node->next;
}
}
cJSON_Delete(root);
free(text);
}

View File

@ -25,6 +25,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern void initBattle(void);
extern void loadMission(char *filename);
extern long lookup(char *name);
extern Mission *loadMissionMeta(char *filename);
extern char *readFile(char *filename);
extern Battle battle;
extern Game game;