diff --git a/data/challenges/10.json b/data/challenges/10.json new file mode 100644 index 0000000..53e2535 --- /dev/null +++ b/data/challenges/10.json @@ -0,0 +1,60 @@ +{ + "name" : "Rescue Civilians", + "description" : "Rescue Civilians", + "background" : "AUTO", + "planet" : "AUTO", + "music" : "AUTO", + "player" : { + "type" : "Tug", + "side" : "SIDE_ALLIES", + "pilot" : "-", + "squadron" : "-", + "x" : 25, + "y" : 25 + }, + "challenge" : { + "rescueLimit" : 8, + "timeLimit" : 300, + "challenges" : [ + { + "type" : "CHALLENGE_RESCUE", + "value" : 4 + }, + { + "type" : "CHALLENGE_RESCUE", + "value" : 5 + }, + { + "type" : "CHALLENGE_RESCUE", + "value" : 8 + } + ] + }, + "fighters" : [ + { + "types" : "Civilian", + "x" : 25, + "y" : 25, + "side" : "SIDE_ALLIES", + "flags" : "+EF_DISABLED", + "number" : 8, + "scatter" : 5000 + } + ], + "entities" : [ + { + "name" : "Jumpgate", + "type" : "ET_JUMPGATE", + "x" : 25, + "y" : 25 + } + ], + "script" : [ + { + "function" : "INTERVAL 30", + "lines" : [ + "SPAWN_FIGHTERS Dart SIDE_PIRATE 1 OFFSCREEN" + ] + } + ] +} diff --git a/data/fighters/rook.json b/data/fighters/rook.json index 40d9295..f1974e4 100644 --- a/data/fighters/rook.json +++ b/data/fighters/rook.json @@ -7,6 +7,11 @@ "shieldRechargeRate" : 45, "texture" : "gfx/fighters/rook.png", "guns" : [ + { + "type" : "BT_PLASMA", + "x" : 0, + "y" : 0 + }, { "type" : "BT_PLASMA", "x" : -9, diff --git a/data/missions/alba/01 - patrol #1.json b/data/missions/alba/01 - patrol #1.json index 8fcb918..34495c5 100644 --- a/data/missions/alba/01 - patrol #1.json +++ b/data/missions/alba/01 - patrol #1.json @@ -8,7 +8,7 @@ "manualComplete" : 1, "objectives" : [ { - "description" : "Check all wayponts", + "description" : "Check all waypoints", "targetName" : "Waypoint", "targetValue" : 5, "targetType" : "TT_WAYPOINT" @@ -42,6 +42,12 @@ } ], "script" : [ + { + "function" : "TIME 0", + "lines" : [ + "ACTIVATE_NEXT_WAYPOINT" + ] + }, { "function" : "Waypoint #2", "lines" : [ diff --git a/data/missions/alba/02 - patrol #2.json b/data/missions/alba/02 - patrol #2.json index f586241..74a8b56 100644 --- a/data/missions/alba/02 - patrol #2.json +++ b/data/missions/alba/02 - patrol #2.json @@ -59,6 +59,12 @@ } ], "script" : [ + { + "function" : "TIME 0", + "lines" : [ + "ACTIVATE_NEXT_WAYPOINT" + ] + }, { "function" : "Waypoint #3", "lines" : [ diff --git a/data/missions/alba/03 - patrol #3.json b/data/missions/alba/03 - patrol #3.json index fe1ccb2..32e6290 100644 --- a/data/missions/alba/03 - patrol #3.json +++ b/data/missions/alba/03 - patrol #3.json @@ -45,6 +45,12 @@ } ], "script" : [ + { + "function" : "TIME 0", + "lines" : [ + "ACTIVATE_NEXT_WAYPOINT" + ] + }, { "function" : "TIME 3", "lines" : [ diff --git a/data/missions/coyote/03 - coyote assault #3.json b/data/missions/coyote/03 - coyote assault #3.json index 1d71700..74e6198 100644 --- a/data/missions/coyote/03 - coyote assault #3.json +++ b/data/missions/coyote/03 - coyote assault #3.json @@ -74,7 +74,7 @@ "type" : "ET_JUMPGATE", "x" : 25, "y" : 25, - "systemPower" : 0 + "flags" : "+EF_DISABLED" } ], "script" : [ @@ -99,7 +99,7 @@ "MSG_BOX Dodds;Estelle, we've got this. We can take them.", "MSG_BOX de Winter;We're taking too many losses, Dodds. Fall back now, that's an order.", "WAIT_MSG_BOX", - "ACTIVATE_JUMPGATE", + "ACTIVATE_JUMPGATE 1", "RETREAT_ALLIES" ] } diff --git a/data/missions/granada/02 - suspect packages #2.json b/data/missions/granada/02 - suspect packages #2.json index 5e6a208..2f76c94 100644 --- a/data/missions/granada/02 - suspect packages #2.json +++ b/data/missions/granada/02 - suspect packages #2.json @@ -110,7 +110,7 @@ "type" : "ET_JUMPGATE", "x" : 10, "y" : 8, - "systemPower" : 0 + "flags" : "+EF_DISABLED" } ], "items" : [ @@ -126,6 +126,12 @@ } ], "script" : [ + { + "function" : "TIME 0", + "lines" : [ + "ACTIVATE_NEXT_WAYPOINT" + ] + }, { "function" : "Waypoint #2", "lines" : [ @@ -153,7 +159,7 @@ "WAIT 2", "MSG_BOX Tug;Tow cable attached. Ready to head home.", "MSG_BOX Carr;We're done here. Let's bring our mystery guest in.", - "ACTIVATE_JUMPGATE", + "ACTIVATE_JUMPGATE 1", "WAIT 20", "ACTIVATE_ENTITIES Dart", "ACTIVATE_OBJECTIVES Destroy intercepting Darts", diff --git a/data/missions/granada/03 - suspect packages #3.json b/data/missions/granada/03 - suspect packages #3.json index 87663cf..ef8e8e5 100644 --- a/data/missions/granada/03 - suspect packages #3.json +++ b/data/missions/granada/03 - suspect packages #3.json @@ -126,6 +126,12 @@ } ], "script" : [ + { + "function" : "TIME 0", + "lines" : [ + "ACTIVATE_NEXT_WAYPOINT" + ] + }, { "function" : "Waypoint #1", "lines" : [ diff --git a/data/missions/rothan/01 - rothan defence #1.json b/data/missions/rothan/01 - rothan defence #1.json index d762c03..ea40cb3 100644 --- a/data/missions/rothan/01 - rothan defence #1.json +++ b/data/missions/rothan/01 - rothan defence #1.json @@ -75,8 +75,7 @@ "y" : 25, "number" : 12, "scatter" : 5000, - "systemPower" : 0, - "flags" : "+EF_NO_KILL+EF_MISSION_TARGET" + "flags" : "+EF_DISABLED+EF_NO_KILL+EF_MISSION_TARGET" }, { "name" : "CSN Tug", diff --git a/data/missions/rothan/02 - rothan defence #2.json b/data/missions/rothan/02 - rothan defence #2.json new file mode 100644 index 0000000..42b580d --- /dev/null +++ b/data/missions/rothan/02 - rothan defence #2.json @@ -0,0 +1,156 @@ +{ + "name" : "Rothan Defence #2", + "description" : "", + "requires" : 29, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/determination.mp3", + "objectives" : [ + { + "description" : "Rendezvous with Irregular Nomads", + "targetName" : "Waypoint", + "targetValue" : 1, + "targetType" : "TT_WAYPOINT" + }, + { + "description" : "Eliminate UNF fighters", + "targetName" : "Enemy", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1, + "active" : 0 + }, + { + "description" : "Retreat to jumpgate", + "targetName" : "Player", + "targetValue" : 1, + "targetType" : "TT_ESCAPED", + "active" : 0 + } + ], + "player" : { + "type" : "Rook", + "side" : "SIDE_ALLIES", + "pilot" : "Julian Spencer", + "squadron" : "Blue Jesters", + "x" : 10, + "y" : 5 + }, + "fighters" : [ + { + "name" : "CSN Pilot", + "types" : "TAF;Ray;Kingfisher;Hammerhead;Rook", + "side" : "SIDE_ALLIES", + "x" : 10, + "y" : 5, + "number" : 3, + "scatter" : 500 + }, + { + "name" : "CSN Pilot", + "groupName" : "Irregular Nomads", + "types" : "TAF;Ray;Kingfisher;Hammerhead;Rook", + "side" : "SIDE_ALLIES", + "x" : 30, + "y" : 1, + "number" : 4, + "active" : 0 + }, + { + "name" : "Rebel", + "groupName" : "Rebels", + "types" : "Nymph;Firefly", + "side" : "SIDE_REBEL", + "x" : -1, + "y" : -1, + "number" : 5, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + }, + { + "name" : "Rebel", + "groupName" : "Rebels", + "types" : "Nymph;Firefly", + "side" : "SIDE_REBEL", + "x" : 15, + "y" : -1, + "number" : 5, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + }, + { + "name" : "Rebel", + "groupName" : "Rebels", + "types" : "Nymph;Firefly", + "side" : "SIDE_REBEL", + "x" : -1, + "y" : 15, + "number" : 5, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + } + ], + "entities" : [ + { + "type" : "ET_WAYPOINT", + "x" : 15, + "y" : 15, + "active" : 0 + }, + { + "type" : "ET_JUMPGATE", + "x" : 30, + "y" : 1, + "flags" : "+EF_DISABLED" + } + ], + "script" : [ + { + "function" : "TIME 1", + "lines" : [ + "MSG_BOX Spencer;Control, we're in position. Awaiting the Irregular Nomads.", + "MSG_BOX Control;Irregular Nomads have just exited the jumpgate. They'll be with you shortly.", + "ACTIVATE_ENTITY_GROUPS Irregular Nomads" + ] + }, + { + "function" : "TIME 15", + "lines" : [ + "MSG_BOX Fox;Commander Spencer, we're on our way. We'll join you at the waypoint.", + "WAIT_MSG_BOX", + "ACTIVATE_NEXT_WAYPOINT", + "MSG_BOX Fox;Acknowledged, Lieutenant, we'll see you in a bit." + ] + }, + { + "function" : "Waypoint #1", + "lines" : [ + "MSG_BOX Spencer;Control, we're ready to--", + "MSG_BOX Control;Commander, be advised that we are detecting UNF fighters advancing on your position, several Nymphs and Fireflies. They are not responding to requests to identify presence or purpose.", + "MSG_BOX Spencer;Pandorans?", + "MSG_BOX Control;Their signatures don't suggest so.", + "WAIT_MSG_BOX", + "WAIT 4,", + "ACTIVATE_ENTITY_GROUPS Rebels", + "ACTIVATE_OBJECTIVES Eliminate UNF fighters", + "MSG_BOX Control;Commander, incoming fighters are hostile. Suggest you prepare to engage or fallback to the jumpgate.", + "MSG_BOX Spencer;Acknowledged, moving to engage." + ] + }, + { + "function" : "OBJECTIVES_COMPLETE 2", + "lines" : [ + "MSG_BOX Spencer;Control, enemy targets have been eliminated.", + "MSG_BOX Control;Any survivors?", + "MSG_BOX Spencer;Negative, I didn't see anyone eject from those fighters.", + "MSG_BOX Control;Commander, your current missions has been aborted. Return to the jumpgate. We need a full report as to what just happened out there.", + "MSG_BOX Spencer;Got it, coming home.", + "WAIT_MSG_BOX", + "ACTIVATE_JUMPGATE 1", + "ACTIVATE_OBJECTIVES Retreat to jumpgate", + "RETREAT_ALLIES" + ] + } + ] +} + diff --git a/gfx/entities/waypoint.png b/gfx/entities/waypoint.png index e84fa0e..7a8fee7 100644 Binary files a/gfx/entities/waypoint.png and b/gfx/entities/waypoint.png differ diff --git a/locale/tbftss.pot b/locale/tbftss.pot index d349a58..1eea83f 100644 --- a/locale/tbftss.pot +++ b/locale/tbftss.pot @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: TBFTSS: The Pandoran War\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2016-03-10 15:44:08+0000\n" +"POT-Creation-Date: 2016-03-12 15:00:11+0000\n" "PO-Revision-Date: ???\n" "Last-Translator: ???\n" "Language-Team: ???\n" @@ -190,6 +190,9 @@ msgstr "" msgid "Collect %d packages" msgstr "" +msgid "Rescue %d civilians" +msgstr "" + msgid "%s has fallen to the Pandorans" msgstr "" @@ -934,7 +937,7 @@ msgstr "" msgid "Can you disable the gate remotely?" msgstr "" -msgid "Negative, the Pandorans have control. We're working take back command function. Stand by." +msgid "Negative, the Pandorans have control. We're working take back command functions. Stand by." msgstr "" msgid "Griffin, all enemy tugs have been dispatched." @@ -955,6 +958,51 @@ msgstr "" msgid "I knew I could count on you, de Winter. Head back to Griffin." msgstr "" +msgid "Control, we're in position. Awaiting the Irregular Nomads." +msgstr "" + +msgid "Irregular Nomads have just exited the jumpgate. They'll be with you shortly." +msgstr "" + +msgid "Commander Spencer, we're on our way. We'll join you at the waypoint." +msgstr "" + +msgid "Acknowledged, Lieutenant, we'll see you in a bit." +msgstr "" + +msgid "Control, we're ready to--" +msgstr "" + +msgid "Commander, be advised that we are detecting UNF fighters advancing on your position, several Nymphs and Fireflies. They are not responding to requests to identify presence or purpose." +msgstr "" + +msgid "Pandorans?" +msgstr "" + +msgid "Their signatures don't suggest so." +msgstr "" + +msgid "Commander, incoming fighters are hostile. Suggest you prepare to engage or fallback to the jumpgate." +msgstr "" + +msgid "Acknowledged, moving to engage." +msgstr "" + +msgid "Control, enemy targets have been eliminated." +msgstr "" + +msgid "Any survivors?" +msgstr "" + +msgid "Negative, I didn't see anyone eject from those fighters." +msgstr "" + +msgid "Commander, your current missions has been aborted. Return to the jumpgate. We need a full report as to what just happened out there." +msgstr "" + +msgid "Got it, coming home." +msgstr "" + msgid "A simple test flight. Get used to piloting your fighter, without threat of attack or any other dangers to face. There are no objectives to complete in this mission, so you may quit it at any time and move on to the next one." msgstr "" diff --git a/src/battle/ai.c b/src/battle/ai.c index 1d3c0a0..074f221 100644 --- a/src/battle/ai.c +++ b/src/battle/ai.c @@ -607,9 +607,11 @@ static void moveToPlayer(void) { if (fabs(player->dx) >= 1 && fabs(player->dy) >= 1) { - wantedAngle = getAngle(player->x, player->y, player->x + (player->dx * 10), player->y + (player->dy * 10)); + wantedAngle = getAngle(player->x, player->y, player->x + (player->dx * 100), player->y + (player->dy * 100)); turnToFace(wantedAngle); + + applyFighterThrust(); } if (dist <= 250) @@ -806,6 +808,8 @@ static void moveToLeader(void) wantedAngle = getAngle(self->leader->x, self->leader->y, self->leader->x + (self->leader->dx * 10), self->leader->y + (self->leader->dy * 10)); turnToFace(wantedAngle); + + applyFighterThrust(); } if (dist <= 250) diff --git a/src/battle/battle.c b/src/battle/battle.c index 0769312..bc393e2 100644 --- a/src/battle/battle.c +++ b/src/battle/battle.c @@ -60,8 +60,6 @@ void initBattle(void) initStars(); - initBullets(); - initBackground(); initEffects(); @@ -160,12 +158,10 @@ static void doBattle(void) if (battle.status == MS_IN_PROGRESS) { doScript(); - - battle.stats[STAT_TIME]++; - - if (battle.stats[STAT_TIME] % FPS == 0) + + if (battle.stats[STAT_TIME]++ % FPS == 0) { - runScriptFunction("TIME %d", battle.stats[STAT_TIME] / 60); + runScriptTimeFunctions(); } } } diff --git a/src/battle/battle.h b/src/battle/battle.h index c507df1..0662b49 100644 --- a/src/battle/battle.h +++ b/src/battle/battle.h @@ -84,6 +84,7 @@ extern void destroyEffects(void); extern void initChallengeHome(void); extern void updateAccuracyStats(unsigned int *stats); extern void clearInput(void); +extern void runScriptTimeFunctions(void); extern App app; extern Battle battle; diff --git a/src/battle/capitalShips.c b/src/battle/capitalShips.c index b5910cd..12f0aed 100644 --- a/src/battle/capitalShips.c +++ b/src/battle/capitalShips.c @@ -379,6 +379,10 @@ static void loadCapitalShipDef(char *filename) cJSON_Delete(root); } + else + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Failed to load '%s'", filename); + } free(text); } diff --git a/src/battle/fighters.c b/src/battle/fighters.c index 4cf275a..7c8ec45 100644 --- a/src/battle/fighters.c +++ b/src/battle/fighters.c @@ -99,6 +99,42 @@ Entity *spawnFighter(char *name, int x, int y, int side) return e; } +void spawnScriptFighter(char *fighterTypes, char *sideStr, int num, char *location) +{ + Entity *e; + int i, numTypes, side, offscreen; + char **types, *type; + + types = toTypeArray(fighterTypes, &numTypes); + side = lookup(sideStr); + offscreen = strcmp(location, "OFFSCREEN") == 0; + + for (i = 0 ; i < num ; i++) + { + type = types[rand() % numTypes]; + + e = spawnFighter(type, 0, 0, side); + + if (offscreen) + { + e->x = player->x; + e->y = player->y; + } + else + { + e->x = rand() % 2 ? 0 : BATTLE_AREA_WIDTH; + e->y = rand() % 2 ? 0 : BATTLE_AREA_HEIGHT; + } + + e->x += (rand() % 2) ? -SCREEN_WIDTH : SCREEN_WIDTH; + e->y += (rand() % 2) ? -SCREEN_HEIGHT : SCREEN_HEIGHT; + + e->aiFlags |= AIF_UNLIMITED_RANGE; + } + + free(types); +} + static void randomizeDart(Entity *dart) { char texture[MAX_DESCRIPTION_LENGTH]; @@ -728,6 +764,10 @@ static void loadFighterDef(char *filename) cJSON_Delete(root); } + else + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Failed to load '%s'", filename); + } free(text); } diff --git a/src/battle/fighters.h b/src/battle/fighters.h index 11c3600..c6394d5 100644 --- a/src/battle/fighters.h +++ b/src/battle/fighters.h @@ -47,6 +47,7 @@ extern void addDebris(int x, int y, int amount); extern char **getFileList(char *dir, int *count); extern char *getTranslatedString(char *string); extern int getJSONValue(cJSON *node, char *name, int defValue); +extern char **toTypeArray(char *types, int *numTypes); extern App app; extern Battle battle; diff --git a/src/battle/hud.c b/src/battle/hud.c index 9fbdc0b..eca800b 100644 --- a/src/battle/hud.c +++ b/src/battle/hud.c @@ -330,7 +330,7 @@ static void drawPlayerTargeter(void) float angle; int x, y; - if (player->target || battle.missionTarget || battle.jumpgate) + if (player->target || battle.missionTarget || jumpgateEnabled()) { if (player->target) { @@ -376,7 +376,7 @@ static void drawPlayerTargeter(void) blitRotated(targetPointer, x - battle.camera.x, y - battle.camera.y, angle); } - if (battle.jumpgate) + if (jumpgateEnabled()) { angle = getAngle(player->x, player->y, battle.jumpgate->x, battle.jumpgate->y); x = player->x; @@ -422,6 +422,10 @@ static void drawObjectives(void) { drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_ITEMS_COLLECTED] + battle.stats[STAT_ITEMS_COLLECTED_PLAYER], game.currentMission->challengeData.itemLimit); } + else if (game.currentMission->challengeData.rescueLimit) + { + drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_CIVILIANS_RESCUED], game.currentMission->challengeData.rescueLimit); + } } else { @@ -452,7 +456,7 @@ static void drawDistancesInfo(void) y = 11; - if (player->target != NULL) + if (player->target) { drawText(SCREEN_WIDTH - 15, y, 18, TA_RIGHT, colors.red, player->target->name); @@ -465,7 +469,7 @@ static void drawDistancesInfo(void) y += 25; } - if (battle.missionTarget != NULL) + if (battle.missionTarget) { distance = distanceToKM(player->x, player->y, battle.missionTarget->x, battle.missionTarget->y); @@ -474,7 +478,7 @@ static void drawDistancesInfo(void) y += 25; } - if (battle.jumpgate != NULL) + if (jumpgateEnabled()) { distance = distanceToKM(player->x, player->y, battle.jumpgate->x, battle.jumpgate->y); diff --git a/src/battle/hud.h b/src/battle/hud.h index 832fc6e..b67c9b8 100644 --- a/src/battle/hud.h +++ b/src/battle/hud.h @@ -34,6 +34,7 @@ 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 int jumpgateEnabled(void); extern App app; extern Battle battle; diff --git a/src/battle/items.c b/src/battle/items.c index a2acb0b..1d9931e 100644 --- a/src/battle/items.c +++ b/src/battle/items.c @@ -54,6 +54,7 @@ void loadItemDefs(void) SDL_QueryTexture(e->texture, NULL, NULL, &e->w, &e->h); defTail->next = e; + defTail = e; } cJSON_Delete(root); diff --git a/src/battle/jumpgate.c b/src/battle/jumpgate.c index 5dec983..64c6365 100644 --- a/src/battle/jumpgate.c +++ b/src/battle/jumpgate.c @@ -45,6 +45,26 @@ Entity *spawnJumpgate(void) return jumpgate; } +int jumpgateEnabled(void) +{ + return (battle.jumpgate && (!(battle.jumpgate->flags & EF_DISABLED))); +} + +void activateJumpgate(int activate) +{ + if (battle.jumpgate) + { + if (activate) + { + battle.jumpgate->flags &= ~EF_DISABLED; + } + else + { + battle.jumpgate->flags |= EF_DISABLED; + } + } +} + static void think(void) { self->thinkTime = 4; @@ -55,7 +75,7 @@ static void think(void) self->angle -= 360; } - if (self->systemPower) + if (jumpgateEnabled()) { handleFleeingEntities(); } @@ -128,7 +148,7 @@ static void addEscapeEffect(Entity *ent) static void draw(void) { - if (self->systemPower) + if (jumpgateEnabled()) { blitRotated(portal, self->x - battle.camera.x, self->y - battle.camera.y, portalAngle); } diff --git a/src/battle/quadtree.c b/src/battle/quadtree.c index 303c96a..c6eecf6 100644 --- a/src/battle/quadtree.c +++ b/src/battle/quadtree.c @@ -24,8 +24,6 @@ static Entity **candidates; static int cIndex; static int cCapacity; -static int memory; - static int getIndex(Quadtree *root, int x, int y, int w, int h); static void removeEntity(Entity *e, Quadtree *root); static int candidatesComparator(const void *a, const void *b); @@ -48,11 +46,12 @@ void initQuadtree(Quadtree *root) root->ents = malloc(sizeof(Entity*) * root->capacity); memset(root->ents, 0, sizeof(Entity*) * root->capacity); - memory = 0; + cIndex = 0; + cCapacity = QT_INITIAL_CAPACITY; + candidates = malloc(sizeof(Entity*) * cCapacity); + memset(candidates, 0, sizeof(Entity*) * cCapacity); } - memory += sizeof(Quadtree); - w = root->w / 2; h = root->h / 2; @@ -101,11 +100,6 @@ void initQuadtree(Quadtree *root) initQuadtree(node); } } - - cIndex = 0; - cCapacity = QT_INITIAL_CAPACITY; - candidates = malloc(sizeof(Entity*) * cCapacity); - memset(candidates, 0, sizeof(Entity*) * cCapacity); } void addToQuadtree(Entity *e, Quadtree *root) @@ -277,23 +271,28 @@ void destroyQuadtree(void) { destroyQuadtreeNode(&battle.quadtree); - free(candidates); - - candidates = NULL; + if (candidates) + { + free(candidates); + + candidates = NULL; + } } static void destroyQuadtreeNode(Quadtree *root) { int i; + free(root->ents); + + root->ents = NULL; + if (root->node[0]) { for (i = 0 ; i < 4 ; i++) { destroyQuadtreeNode(root->node[i]); - free(root->node[i]->ents); - free(root->node[i]); root->node[i] = NULL; diff --git a/src/battle/script.c b/src/battle/script.c index 6aafdb4..929422b 100644 --- a/src/battle/script.c +++ b/src/battle/script.c @@ -28,10 +28,24 @@ static ScriptRunner *tail; void initScript(cJSON *scriptNode) { + cJSON *function; + memset(&head, 0, sizeof(ScriptRunner)); tail = &head; scriptJSON = scriptNode; + + if (scriptJSON) + { + function = scriptJSON->child; + + while (function) + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Found script function: '%s'", cJSON_GetObjectItem(function, "function")->valuestring); + + function = function->next; + } + } } void doScript(void) @@ -110,11 +124,65 @@ void runScriptFunction(const char *format, ...) } } +void runScriptTimeFunctions(void) +{ + ScriptRunner *scriptRunner; + cJSON *function; + char *functionName; + char funcNameBuffer[MAX_NAME_LENGTH]; + int intParam; + + if (scriptJSON) + { + function = scriptJSON->child; + + sprintf(funcNameBuffer, "TIME %d", battle.stats[STAT_TIME] / 60); + + while (function) + { + functionName = cJSON_GetObjectItem(function, "function")->valuestring; + + if (strcmp(functionName, funcNameBuffer) == 0) + { + scriptRunner = malloc(sizeof(ScriptRunner)); + memset(scriptRunner, 0, sizeof(ScriptRunner)); + + scriptRunner->line = cJSON_GetObjectItem(function, "lines")->child; + + tail->next = scriptRunner; + tail = scriptRunner; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Running script '%s'", funcNameBuffer); + } + + if (strstr(functionName, "INTERVAL")) + { + sscanf(functionName, "%*s %d", &intParam); + + if ((battle.stats[STAT_TIME] / 60) % intParam == 0) + { + scriptRunner = malloc(sizeof(ScriptRunner)); + memset(scriptRunner, 0, sizeof(ScriptRunner)); + + scriptRunner->line = cJSON_GetObjectItem(function, "lines")->child; + + tail->next = scriptRunner; + tail = scriptRunner; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Running script '%s'", funcNameBuffer); + } + } + + function = function->next; + } + } +} + static void executeNextLine(ScriptRunner *runner) { char *line; char command[24]; - char strParam[2][256]; + char strParam[3][256]; int intParam[2]; line = runner->line->valuestring; @@ -143,7 +211,12 @@ static void executeNextLine(ScriptRunner *runner) } else if (strcmp(command, "ACTIVATE_JUMPGATE") == 0) { - battle.jumpgate->systemPower = MAX_SYSTEM_POWER; + sscanf(line, "%*s %d", &intParam[0]); + activateJumpgate(intParam[0]); + } + else if (strcmp(command, "ACTIVATE_NEXT_WAYPOINT") == 0) + { + activateNextWaypoint(0); } else if (strcmp(command, "MSG_BOX") == 0) { @@ -183,6 +256,11 @@ static void executeNextLine(ScriptRunner *runner) battle.isEpic = 0; retreatEnemies(); } + else if (strcmp(command, "SPAWN_FIGHTERS") == 0) + { + sscanf(line, "%*s %s %s %d %s", strParam[0], strParam[1], &intParam[0], strParam[2]); + spawnScriptFighter(strParam[0], strParam[1], intParam[0], strParam[2]); + } else { printf("ERROR: Unrecognised script command '%s'\n", command); @@ -196,6 +274,13 @@ static void executeNextLine(ScriptRunner *runner) void destroyScript(void) { ScriptRunner *scriptRunner; + + if (scriptJSON) + { + cJSON_Delete(scriptJSON); + + scriptJSON = NULL; + } while (head.next) { diff --git a/src/battle/script.h b/src/battle/script.h index aadcba0..b2c98c1 100644 --- a/src/battle/script.h +++ b/src/battle/script.h @@ -34,6 +34,9 @@ extern void activateLocations(char *locations); void activateObjectives(char *objectives); extern int showingMessageBoxes(void); extern char *getTranslatedString(char *string); +extern void spawnScriptFighter(char *fighters, char *side, int num, char *location); +extern void activateNextWaypoint(int id); +extern void activateJumpgate(int activate); extern Battle battle; extern Colors colors; diff --git a/src/battle/waypoints.c b/src/battle/waypoints.c index cd87001..70226d4 100644 --- a/src/battle/waypoints.c +++ b/src/battle/waypoints.c @@ -50,25 +50,29 @@ Entity *spawnWaypoint(void) static void think(void) { - self->thinkTime = 4; + self->angle += 0.25; - self->angle++; if (self->angle >= 360) { self->angle -= 360; } - if (player != NULL && getDistance(player->x, player->y, self->x, self->y) <= 64 && isCurrentObjective() && teamMatesClose()) + if (--self->aiActionTime <= 0) { - self->health = 0; + self->aiActionTime = 0; - updateObjective("Waypoint", TT_WAYPOINT); - - runScriptFunction(self->name); - - activateNextWaypoint(self->id); - - battle.stats[STAT_WAYPOINTS_VISITED]++; + if (self->health && player != NULL && getDistance(player->x, player->y, self->x, self->y) <= 128 && isCurrentObjective() && teamMatesClose()) + { + self->health = 0; + + updateObjective("Waypoint", TT_WAYPOINT); + + runScriptFunction(self->name); + + activateNextWaypoint(self->id); + + battle.stats[STAT_WAYPOINTS_VISITED]++; + } } } @@ -79,7 +83,7 @@ static int isCurrentObjective(void) if (numActiveObjectives > 1) { addHudMessage(colors.cyan, _("Cannot activate waypoint - outstanding objectives not yet complete")); - self->thinkTime = FPS; + self->aiActionTime = FPS; return 0; } @@ -97,7 +101,7 @@ static int teamMatesClose(void) if (getDistance(player->x, player->y, e->x, e->y) > 350) { addHudMessage(colors.cyan, _("Cannot activate waypoint - team mates too far away")); - self->thinkTime = FPS; + self->aiActionTime = FPS; return 0; } } diff --git a/src/challenges/challenges.c b/src/challenges/challenges.c index 61180ee..27082ad 100644 --- a/src/challenges/challenges.c +++ b/src/challenges/challenges.c @@ -57,6 +57,7 @@ void initChallenges(void) challengeDescription[CHALLENGE_PLAYER_KILLS] = _("Take down %d enemy targets"); challengeDescription[CHALLENGE_DISABLE] = _("Disable %d or more enemy fighters"); challengeDescription[CHALLENGE_ITEMS] = _("Collect %d packages"); + challengeDescription[CHALLENGE_RESCUE] = _("Rescue %d civilians"); tail = &game.challengeMissionHead; @@ -128,6 +129,11 @@ static int challengeFinished(void) return 1; } + if (game.currentMission->challengeData.rescueLimit > 0 && (battle.stats[STAT_CIVILIANS_RESCUED] + battle.stats[STAT_CIVILIANS_KILLED]) >= game.currentMission->challengeData.rescueLimit) + { + return 1; + } + if (game.currentMission->challengeData.scriptedEnd) { return 1; diff --git a/src/defs.h b/src/defs.h index a004116..2feb4bd 100644 --- a/src/defs.h +++ b/src/defs.h @@ -293,6 +293,7 @@ enum CHALLENGE_PLAYER_KILLS, CHALLENGE_DISABLE, CHALLENGE_ITEMS, + CHALLENGE_RESCUE, CHALLENGE_MAX }; diff --git a/src/galaxy/mission.c b/src/galaxy/mission.c index 9ada9e3..69700eb 100644 --- a/src/galaxy/mission.c +++ b/src/galaxy/mission.c @@ -28,7 +28,6 @@ static void loadEntities(cJSON *node); static void loadItems(cJSON *node); 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 char *getAutoBackground(char *filename); static char *getAutoPlanet(char *filename); @@ -87,6 +86,7 @@ Mission *loadMissionMeta(char *filename) mission->challengeData.escapeLimit = getJSONValue(node, "escapeLimit", 0); mission->challengeData.waypointLimit = getJSONValue(node, "waypointLimit", 0); mission->challengeData.itemLimit = getJSONValue(node, "itemLimit", 0); + mission->challengeData.rescueLimit = getJSONValue(node, "rescueLimit", 0); /* restrictions */ mission->challengeData.noMissiles = getJSONValue(node, "noMissiles", 0); @@ -121,6 +121,10 @@ Mission *loadMissionMeta(char *filename) cJSON_Delete(root); } + else + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Failed to load '%s'", filename); + } free(text); @@ -216,8 +220,6 @@ void loadMission(char *filename) battle.status = MS_IN_PROGRESS; } - activateNextWaypoint(); - countNumEnemies(); initPlayer(); @@ -376,7 +378,7 @@ static void loadFighters(cJSON *node) Entity *e; char **types, *name, *groupName, *type; int side, scatter, number, active; - int i, numTypes, addFlags, addAIFlags, systemPower; + int i, numTypes, addFlags, addAIFlags; long flags, aiFlags; float x, y; @@ -400,7 +402,6 @@ static void loadFighters(cJSON *node) number = getJSONValue(node, "number", 1); scatter = getJSONValue(node, "scatter", 1); active = getJSONValue(node, "active", 1); - systemPower = getJSONValue(node, "systemPower", MAX_SYSTEM_POWER); if (cJSON_GetObjectItem(node, "flags")) { @@ -463,12 +464,6 @@ static void loadFighters(cJSON *node) { STRNCPY(e->groupName, groupName, MAX_NAME_LENGTH); } - - e->systemPower = systemPower; - if (!e->systemPower) - { - e->flags |= EF_DISABLED; - } } node = node->next; @@ -574,8 +569,9 @@ static void loadEntities(cJSON *node) { Entity *e; char *name, *groupName; - int i, type, scatter, number, active, systemPower; + int i, type, scatter, number, active, addFlags; float x, y; + long flags; if (node) { @@ -595,7 +591,11 @@ static void loadEntities(cJSON *node) number = getJSONValue(node, "number", 1); active = getJSONValue(node, "active", 1); scatter = getJSONValue(node, "scatter", 1); - systemPower = getJSONValue(node, "systemPower", MAX_SYSTEM_POWER); + + if (cJSON_GetObjectItem(node, "flags")) + { + flags = flagsToLong(cJSON_GetObjectItem(node, "flags")->valuestring, &addFlags); + } for (i = 0 ; i < number ; i++) { @@ -624,6 +624,20 @@ static void loadEntities(cJSON *node) { STRNCPY(e->groupName, groupName, MAX_NAME_LENGTH); } + + if (flags != -1) + { + if (addFlags) + { + e->flags |= flags; + } + else + { + e->flags = flags; + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Flags for '%s' (%s) replaced", e->name, e->defName); + } + } e->x = x; e->y = y; @@ -636,8 +650,6 @@ static void loadEntities(cJSON *node) e->active = active; - e->systemPower = systemPower; - SDL_QueryTexture(e->texture, NULL, NULL, &e->w, &e->h); } @@ -759,38 +771,6 @@ static void loadLocations(cJSON *node) } } -static char **toTypeArray(char *types, int *numTypes) -{ - int i; - char **typeArray, *type; - - *numTypes = 1; - - for (i = 0 ; i < strlen(types) ; i++) - { - if (types[i] == ';') - { - *numTypes = *numTypes + 1; - } - } - - typeArray = malloc(*numTypes * sizeof(char*)); - - i = 0; - type = strtok(types, ";"); - while (type) - { - typeArray[i] = malloc(strlen(type) + 1); - strcpy(typeArray[i], type); - - type = strtok(NULL, ";"); - - i++; - } - - return typeArray; -} - static void loadEpicData(cJSON *node) { Entity *e; diff --git a/src/galaxy/mission.h b/src/galaxy/mission.h index af2a4d9..c6a8647 100644 --- a/src/galaxy/mission.h +++ b/src/galaxy/mission.h @@ -35,7 +35,6 @@ extern void stopMusic(void); extern void initPlayer(void); extern long flagsToLong(char *flags, int *add); extern Entity *spawnWaypoint(void); -extern void activateNextWaypoint(void); extern void selectWidget(const char *name, const char *group); extern Entity *spawnJumpgate(void); extern Entity *spawnItem(char *type); @@ -55,6 +54,7 @@ extern char *getMusicFilename(int n); extern int getJSONValue(cJSON *node, char *name, int defValue); extern char *getJSONValueStr(cJSON *node, char *name, char *defValue); extern void addAllEntsToQuadtree(void); +extern char **toTypeArray(char *types, int *numTypes); extern Battle battle; extern Entity *player; diff --git a/src/main.c b/src/main.c index c1d08d7..6617833 100644 --- a/src/main.c +++ b/src/main.c @@ -27,9 +27,10 @@ int main(int argc, char *argv[]) float td; long then, lastFrameTime, frames; long expireTextTimer; - SDL_Event event; + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN); + memset(&app, 0, sizeof(App)); memset(&dev, 0, sizeof(Dev)); @@ -169,6 +170,8 @@ static void handleArguments(int argc, char *argv[]) dev.debug = 1; createScreenshotFolder(); + + SDL_LogSetPriority(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG); } } } diff --git a/src/structs.h b/src/structs.h index 245c007..34c0587 100644 --- a/src/structs.h +++ b/src/structs.h @@ -251,6 +251,7 @@ typedef struct { int itemLimit; int escapeLimit; int waypointLimit; + int rescueLimit; int noMissiles; int noBoost; int noECM; diff --git a/src/system/i18n.c b/src/system/i18n.c index 6f17493..7283929 100644 --- a/src/system/i18n.c +++ b/src/system/i18n.c @@ -79,7 +79,7 @@ void setLanguage(char *applicationName, char *languageCode) STRNCPY(language, lang, MAX_LINE_LENGTH); } - printf("Locale is %s\n", language); + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Locale is %s", language); sprintf(c, "%s/%s/LC_MESSAGES/%s.mo", LOCALE_DIR, language, applicationName); diff --git a/src/system/init.c b/src/system/init.c index 507c0b8..2d04920 100644 --- a/src/system/init.c +++ b/src/system/init.c @@ -131,9 +131,9 @@ void initGameSystem(void) initStarSystems, initChallenges, initStats, - initBattle, initModalDialog, initBackground, + initStars, initControls }; @@ -338,10 +338,10 @@ void cleanup(void) destroyWidgets(); destroyResources(); + + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Done"); TTF_Quit(); SDL_Quit(); - - SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Done"); } diff --git a/src/system/init.h b/src/system/init.h index 78133cb..6d6dd05 100644 --- a/src/system/init.h +++ b/src/system/init.h @@ -70,6 +70,7 @@ extern void createSaveFolder(void); extern void setLanguage(char *applicationName, char *languageCode); extern char *getLookupName(char *prefix, long num); extern long lookup(char *name); +extern void initStars(void); extern App app; extern Colors colors; diff --git a/src/system/lookup.c b/src/system/lookup.c index 2d66ca5..f205f21 100644 --- a/src/system/lookup.c +++ b/src/system/lookup.c @@ -132,6 +132,7 @@ void initLookups(void) addLookup("CHALLENGE_PLAYER_KILLS", CHALLENGE_PLAYER_KILLS); addLookup("CHALLENGE_DISABLE", CHALLENGE_DISABLE); addLookup("CHALLENGE_ITEMS", CHALLENGE_ITEMS); + addLookup("CHALLENGE_RESCUE", CHALLENGE_RESCUE); addLookup("STAT_PERCENT_COMPLETE", STAT_PERCENT_COMPLETE); addLookup("STAT_MISSIONS_STARTED", STAT_MISSIONS_STARTED); diff --git a/src/system/resources.c b/src/system/resources.c index d4b5ef1..ba88d56 100644 --- a/src/system/resources.c +++ b/src/system/resources.c @@ -98,7 +98,20 @@ char *getMusicFilename(int i) void destroyResources(void) { - free(backgrounds); - free(planets); - free(musicFiles); + int i; + + for (i = 0 ; i < numBackgrounds ; i++) + { + free(backgrounds[i]); + } + + for (i = 0 ; i < numPlanets ; i++) + { + free(planets[i]); + } + + for (i = 0 ; i < numMusicFiles ; i++) + { + free(musicFiles[i]); + } } diff --git a/src/system/util.c b/src/system/util.c index 982b45f..2d9f409 100644 --- a/src/system/util.c +++ b/src/system/util.c @@ -73,6 +73,38 @@ void getSlope(int x1, int y1, int x2, int y2, float *dx, float *dy) *dy /= steps; } +char **toTypeArray(char *types, int *numTypes) +{ + int i; + char **typeArray, *type; + + *numTypes = 1; + + for (i = 0 ; i < strlen(types) ; i++) + { + if (types[i] == ';') + { + *numTypes = *numTypes + 1; + } + } + + typeArray = malloc(*numTypes * sizeof(char*)); + + i = 0; + type = strtok(types, ";"); + while (type) + { + typeArray[i] = malloc(strlen(type) + 1); + strcpy(typeArray[i], type); + + type = strtok(NULL, ";"); + + i++; + } + + return typeArray; +} + char *timeToString(long millis, int showHours) { static char TIME[MAX_NAME_LENGTH]; diff --git a/src/system/widgets.c b/src/system/widgets.c index c5fa49a..d8fa666 100644 --- a/src/system/widgets.c +++ b/src/system/widgets.c @@ -427,6 +427,10 @@ static void loadWidgetSet(char *filename) cJSON_Delete(root); } + else + { + SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_WARN, "Failed to load '%s'", filename); + } free(text); } @@ -507,6 +511,8 @@ void destroyWidgets(void) { free(w->options[i]); } + + free(w->options); next = w->next; free(w);