diff --git a/CHANGELOG b/CHANGELOG index 76cb17c..82b2b75 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -4,7 +4,7 @@ Changelog * Added control remapping * New game mode: Challenges - * Add i18n support + * Added i18n support 0.51 diff --git a/data/craft/infTug.json b/data/craft/infTug.json new file mode 100644 index 0000000..473ad61 --- /dev/null +++ b/data/craft/infTug.json @@ -0,0 +1,11 @@ +{ + "name" : "INF Tug", + "health" : 50, + "shield" : 0, + "speed" : 1.85, + "reloadTime" : 10, + "shieldRechargeRate" : 0, + "texture" : "gfx/craft/infTug.png", + "flags" : "EF_HAS_ROPE+EF_TAKES_DAMAGE", + "aiFlags" : "AIF_AVOIDS_COMBAT+AIF_TOWS" +} diff --git a/data/missions/rothan/01 - rothan defence #1.json b/data/missions/rothan/01 - rothan defence #1.json new file mode 100644 index 0000000..b44c90c --- /dev/null +++ b/data/missions/rothan/01 - rothan defence #1.json @@ -0,0 +1,194 @@ +{ + "name" : "Rothan Defence #1", + "description" : "", + "requires" : 28, + "background" : "gfx/backgrounds/background05.jpg", + "planet" : "gfx/planets/bluePlanet.png", + "music" : "music/battle/track-1.mp3", + "manualComplete" : 1, + "objectives" : [ + { + "description" : "Destroy all Pandoran Tugs", + "targetName" : "Pandoran Tug", + "targetValue" : 12, + "targetType" : "TT_DESTROY" + }, + { + "description" : "Rescue all CSN pilots", + "targetName" : "CSN Pilot", + "targetValue" : 12, + "targetType" : "TT_ESCAPED" + }, + { + "description" : "Protect Tugs", + "targetName" : "CSN Tug", + "targetValue" : 8, + "targetType" : "TT_DESTROY", + "isCondition" : 1, + "active" : 0 + }, + { + "description" : "Eliminate all Pandoran fighters", + "targetName" : "ENEMY", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isEliminateAll" : 1, + "active" : 0 + }, + { + "description" : "Do not allow any pilots to be killed", + "targetName" : "CSN Pilot", + "targetValue" : 1, + "targetType" : "TT_DESTROY", + "isCondition" : 1 + }, + { + "description" : "Do not allow any pilots to be kidnapped", + "targetName" : "CSN Pilot", + "targetValue" : 1, + "targetType" : "TT_STOLEN", + "isCondition" : 1 + } + ], + "player" : { + "type" : "ATAF", + "side" : "SIDE_ALLIES", + "pilot" : "Estelle de Winter", + "squadron" : "White Knights", + "x" : 25, + "y" : 48 + }, + "fighters" : [ + { + "name" : "ALLIES", + "types" : "ATAF", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 48, + "scatter" : 500 + }, + { + "name" : "CSN Pilot", + "types" : "TAF;Ray;Kingfisher;Hammerhead;Rook", + "side" : "SIDE_ALLIES", + "x" : 25, + "y" : 25, + "number" : 12, + "scatter" : 5000, + "systemPower" : 0, + "flags" : "+EF_NO_KILL+EF_MISSION_TARGET" + }, + { + "name" : "CSN Tug", + "groupName" : "CSNTugs", + "types" : "Tug", + "side" : "SIDE_ALLIES", + "x" : 45, + "y" : 45, + "number" : 6, + "scatter" : 750, + "flags" : "+EF_AI_TARGET", + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + }, + { + "name" : "Pandoran Tug", + "types" : "INF Tug", + "side" : "SIDE_PANDORAN", + "x" : 25, + "y" : 25, + "number" : 12, + "scatter" : 5000, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "flags" : "+EF_AI_LEADER" + }, + { + "types" : "Sphinx;Thunderhead", + "side" : "SIDE_PANDORAN", + "x" : 25, + "y" : 25, + "number" : 12, + "scatter" : 0, + "aiFlags" : "+AIF_MOVES_TO_LEADER", + "flags" : "+EF_AI_LEADER" + }, + { + "types" : "Jackal;Sphinx;Thunderhead;Mantis", + "groupName" : "Reinforcements", + "side" : "SIDE_PANDORAN", + "x" : 51, + "y" : 35, + "number" : 8, + "scatter" : 0, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + }, + { + "types" : "Jackal;Sphinx;Thunderhead;Mantis", + "groupName" : "Reinforcements", + "side" : "SIDE_PANDORAN", + "x" : 35, + "y" : 51, + "number" : 8, + "scatter" : 0, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + }, + { + "types" : "Jackal;Sphinx;Thunderhead;Mantis", + "groupName" : "Reinforcements", + "side" : "SIDE_PANDORAN", + "x" : -1, + "y" : -1, + "number" : 8, + "scatter" : 0, + "aiFlags" : "+AIF_UNLIMITED_RANGE", + "active" : 0 + } + ], + "entities" : [ + { + "name" : "Jumpgate", + "type" : "ET_JUMPGATE", + "x" : 45, + "y" : 45 + } + ], + "script" : [ + { + "function" : "TIME 2", + "lines" : [ + "MSG_BOX CSN Griffin;White Knights, the enemy tugs are already in position and are attaching tow ropes. They must not be allowed to get those fighters and pilots to the jumpgate.", + "MSG_BOX de Winter;Can you disable the gate remotely?", + "MSG_BOX CSN Griffin;Negative, the Pandorans have control. We're working take back command function. Stand by." + ] + }, + { + "function" : "OBJECTIVES_COMPLETE 1", + "lines" : [ + "WAIT 2", + "MSG_BOX de Winter;Griffin, all enemy tugs have been dispatched.", + "MSG_BOX CSN Griffin;Good work, Commander. We've regained control of the gate. We're sending our own tugs through now.", + "WAIT_MSG_BOX", + "ACTIVATE_ENTITY_GROUPS CSNTugs", + "WAIT 10", + "ACTIVATE_ENTITY_GROUPS Reinforcements", + "ACTIVATE_OBJECTIVES Protect Tugs", + "MSG_BOX Taylor;Estelle, I'm picking up incoming INF fighters.", + "MSG_BOX de Winter;Hell! Protect the tugs. Make sure they get everyone home.", + "ACTIVATE_OBJECTIVES Eliminate all Pandoran fighters" + ] + }, + { + "function" : "ALL_OBJECTIVES_COMPLETE", + "lines" : [ + "WAIT 2", + "MSG_BOX de Winter;Griffin, this is de Winter. Operation successful.", + "MSG_BOX Parks;I knew I could count on you, de Winter. Head back to Griffin.", + "WAIT_MSG_BOX", + "COMPLETE_MISSION" + ] + } + ] +} + diff --git a/data/trophies/trophies.json b/data/trophies/trophies.json index d1ef643..20bbd46 100644 --- a/data/trophies/trophies.json +++ b/data/trophies/trophies.json @@ -5,12 +5,6 @@ "description" : "Earn all other trophies", "value" : "TROPHY_PLATINUM" }, - { - "id" : "READY_DUTY", - "title" : "Ready for duty", - "description" : "Complete all the training missions at Sol", - "value" : "TROPHY_BRONZE" - }, { "id" : "CAMPAIGN_1", "title" : "2nd Lieutenant", @@ -66,17 +60,11 @@ "value" : "TROPHY_SILVER" }, { - "id" : "EPIC", - "title" : "Truly epic", - "description" : "Survive an epic battle", + "id" : "CAMPAIGN_SOL", + "title" : "Ready for duty", + "description" : "Complete all the training missions at Sol", "value" : "TROPHY_BRONZE" }, - { - "id" : "BIGGER_FALL", - "title" : "The bigger they are", - "description" : "Destroy an enemy capital ship", - "value" : "TROPHY_SILVER" - }, { "id" : "CAMPAIGN_COYOTE", "title" : "Coyote Ugly", @@ -93,7 +81,7 @@ }, { "id" : "CAMPAIGN_ILIAD", - "title" : "Shape of things to come", + "title" : "The shape of things to come", "description" : "Complete all missions at Iliad", "value" : "TROPHY_BRONZE", "hidden" : 1 @@ -105,6 +93,20 @@ "value" : "TROPHY_BRONZE", "hidden" : 1 }, + { + "id" : "EPIC", + "title" : "Truly epic", + "description" : "Survive an epic battle", + "value" : "TROPHY_BRONZE" + }, + { + "id" : "BIGGER_FALL", + "title" : "The bigger they are", + "description" : "Destroy an enemy capital ship", + "value" : "TROPHY_SILVER", + "stat" : "STAT_CAPITAL_SHIPS_DESTROYED", + "statValue" : 1 + }, { "id" : "PANDORAN_FIRST", "title" : "Plenty more where that came from", diff --git a/gfx/craft/infTug.png b/gfx/craft/infTug.png new file mode 100644 index 0000000..c1c27c8 Binary files /dev/null and b/gfx/craft/infTug.png differ diff --git a/gfx/hud/clock.png b/gfx/hud/clock.png new file mode 100644 index 0000000..978612d Binary files /dev/null and b/gfx/hud/clock.png differ diff --git a/gfx/hud/objectives.png b/gfx/hud/objectives.png new file mode 100644 index 0000000..d106699 Binary files /dev/null and b/gfx/hud/objectives.png differ diff --git a/makefile b/makefile index af627c9..afd1d2e 100644 --- a/makefile +++ b/makefile @@ -10,7 +10,7 @@ OBJS += unixInit.o include common.mk CXXFLAGS += `sdl2-config --cflags` -DVERSION=$(VERSION) -DREVISION=$(REVISION) -DDATA_DIR=\"$(DATA_DIR)\" -DLOCALE_DIR=\"$(LOCALE_DIR)\" -CXXFLAGS += -Wall -ansi -pedantic -Werror -Wstrict-prototypes +CXXFLAGS += -Wall -Wempty-body -ansi -pedantic -Werror -Wstrict-prototypes CXXFLAGS += -g -lefence LFLAGS := `sdl2-config --libs` -lSDL2_mixer -lSDL2_image -lSDL2_ttf -lm diff --git a/src/battle/ai.c b/src/battle/ai.c index dbd07f9..1d3c0a0 100644 --- a/src/battle/ai.c +++ b/src/battle/ai.c @@ -708,25 +708,25 @@ static void moveToItem(void) static int nearTowableCraft(void) { int i; - long closest, distance; + long closest, dist; Entity *e, **candidates; - candidates = getAllEntsWithin(self->x - (self->w / 2) - (SCREEN_WIDTH / 4), self->y - (self->h / 2) - (SCREEN_HEIGHT / 4), SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, self); + dist = closest = (battle.isEpic || (self->aiFlags & AIF_UNLIMITED_RANGE)) ? MAX_TARGET_RANGE : 2000; - closest = MAX_TARGET_RANGE; + candidates = getAllEntsWithin(self->x - (self->w / 2) - (dist / 2), self->y - (self->h / 2) - (dist / 2), self->w + dist, self->h + dist, self); self->target = NULL; for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { - if ((e->flags & (EF_DISABLED|EF_MISSION_TARGET)) == (EF_DISABLED|EF_MISSION_TARGET)) + if ((e->flags & (EF_DISABLED|EF_MISSION_TARGET)) == (EF_DISABLED|EF_MISSION_TARGET) && (e->flags & EF_ROPED_ATTACHED) == 0) { - distance = getDistance(self->x, self->y, e->x, e->y); + dist = getDistance(self->x, self->y, e->x, e->y); - if (distance < closest) + if (dist < closest) { self->target = e; - closest = distance; + closest = dist; } } } diff --git a/src/battle/ai.h b/src/battle/ai.h index 921282b..9038b97 100644 --- a/src/battle/ai.h +++ b/src/battle/ai.h @@ -44,4 +44,3 @@ extern Colors colors; extern Dev dev; extern Entity *self; extern Entity *player; -extern Game game; diff --git a/src/battle/battle.c b/src/battle/battle.c index e5f6689..0769312 100644 --- a/src/battle/battle.c +++ b/src/battle/battle.c @@ -130,8 +130,8 @@ static void doBattle(void) scrollBackground(-ssx * 0.1, -ssy * 0.1); - battle.planet.x -= ssx * 0.05; - battle.planet.y -= ssy * 0.05; + battle.planet.x -= ssx * 0.1; + battle.planet.y -= ssy * 0.1; doObjectives(); diff --git a/src/battle/effects.c b/src/battle/effects.c index 29f1152..8c67054 100644 --- a/src/battle/effects.c +++ b/src/battle/effects.c @@ -95,7 +95,7 @@ void doEffects(void) break; } - if (onScreen); + if (onScreen) { effectsToDraw[i++] = e; diff --git a/src/battle/entities.h b/src/battle/entities.h index 4656bdc..0d9f070 100644 --- a/src/battle/entities.h +++ b/src/battle/entities.h @@ -35,8 +35,6 @@ extern void drawShieldHitEffect(Entity *e); extern void removeFromQuadtree(Entity *e, Quadtree *root); extern void addToQuadtree(Entity *e, Quadtree *root); extern void updateCapitalShipComponentProperties(Entity *parent); -extern void drawJumpPortal(Entity *e); -extern SDL_Texture *getTexture(char *filename); extern App app; extern Battle battle; diff --git a/src/battle/fighters.c b/src/battle/fighters.c index c57241e..4cf275a 100644 --- a/src/battle/fighters.c +++ b/src/battle/fighters.c @@ -254,14 +254,23 @@ void doFighter(void) addHudMessage(colors.red, _("Mission target has escaped.")); battle.stats[STAT_ENEMIES_ESCAPED]++; } - else if (strcmp(self->defName, "Civilian") == 0) + + if (strcmp(self->defName, "Civilian") == 0) { battle.stats[STAT_CIVILIANS_RESCUED]++; } - updateObjective(self->name, TT_ESCAPED); - - updateCondition(self->name, TT_ESCAPED); + /* if you did not escape under your own volition, or with the aid of a friend, you've been stolen */ + if (!self->owner || self->side == self->owner->side) + { + updateObjective(self->name, TT_ESCAPED); + updateCondition(self->name, TT_ESCAPED); + } + else + { + updateObjective(self->name, TT_STOLEN); + updateCondition(self->name, TT_STOLEN); + } } if (self->alive == ALIVE_DEAD) diff --git a/src/battle/hud.c b/src/battle/hud.c index 54bb234..9fbdc0b 100644 --- a/src/battle/hud.c +++ b/src/battle/hud.c @@ -44,6 +44,8 @@ static SDL_Texture *shield; static SDL_Texture *ecm; static SDL_Texture *boost; static SDL_Texture *nextGun; +static SDL_Texture *clock; +static SDL_Texture *objectives; static int numMessages; static const char *gunName[BT_MAX]; @@ -70,6 +72,8 @@ void initHud(void) ecm = getTexture("gfx/hud/ecm.png"); boost = getTexture("gfx/hud/boost.png"); nextGun = getTexture("gfx/hud/nextGun.png"); + clock = getTexture("gfx/hud/clock.png"); + objectives = getTexture("gfx/hud/objectives.png"); } void doHud(void) @@ -404,12 +408,14 @@ static void drawObjectives(void) { if (!game.currentMission->challengeData.isChallenge) { + blit(objectives, (SCREEN_WIDTH / 2) - 50, 14, 0); drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, "%d / %d", battle.numObjectivesComplete, battle.numObjectivesTotal); } else { if (game.currentMission->challengeData.timeLimit) { + blit(clock, (SCREEN_WIDTH / 2) - 50, 14, 0); drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, timeToString(game.currentMission->challengeData.timeLimit - battle.stats[STAT_TIME], 0)); if (game.currentMission->challengeData.itemLimit) @@ -420,6 +426,7 @@ static void drawObjectives(void) else { drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, timeToString(battle.stats[STAT_TIME], 0)); + blit(clock, (SCREEN_WIDTH / 2) - 50, 14, 0); } } } diff --git a/src/battle/jumpgate.c b/src/battle/jumpgate.c index f3dc96f..5dec983 100644 --- a/src/battle/jumpgate.c +++ b/src/battle/jumpgate.c @@ -67,7 +67,7 @@ static void think(void) if (battle.jumpgate == self) { - portalAngle++; + portalAngle += 2; if (portalAngle >= 360) { portalAngle -= 360; diff --git a/src/battle/rope.c b/src/battle/rope.c index d43dc47..e4a236f 100644 --- a/src/battle/rope.c +++ b/src/battle/rope.c @@ -31,7 +31,7 @@ void attachRope(void) for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) { - if ((e->flags & EF_DISABLED) && e->alive == ALIVE_ALIVE) + if ((e->flags & EF_DISABLED) && (e->flags & EF_ROPED_ATTACHED) == 0 && e->alive == ALIVE_ALIVE) { distance = getDistance(e->x, e->y, self->x, self->y); @@ -43,6 +43,7 @@ void attachRope(void) self->aiFlags |= AIF_GOAL_JUMPGATE; e->flags |= EF_RETREATING; + e->flags |= EF_ROPED_ATTACHED; runScriptFunction("TOWING %s", e->name); @@ -95,10 +96,18 @@ void drawRope(Entity *e) void cutRope(Entity *e) { + /* thing being towed is dead */ if (e->owner && e->owner->towing == e) { e->owner->towing = NULL; e->owner->aiFlags &= ~AIF_GOAL_JUMPGATE; - e->owner = NULL; + } + + /* tug is dead - reset thing being tugged */ + if (e->towing) + { + e->towing->flags &= ~EF_RETREATING; + e->towing->flags &= ~EF_ROPED_ATTACHED; + e->towing = NULL; } } diff --git a/src/challenges/challengeHome.c b/src/challenges/challengeHome.c index 178dbb2..05771e4 100644 --- a/src/challenges/challengeHome.c +++ b/src/challenges/challengeHome.c @@ -106,16 +106,20 @@ void initChallengeHome(void) static void unlockChallenges(void) { Mission *m; - int i; + + int i, prevCompleted; i = completedChallenges = totalChallenges = 0; + prevCompleted = 1; + for (m = game.challengeMissionHead.next ; m != NULL ; m = m->next) { - m->available = (i <= completedChallenges || dev.debug); + m->available = (prevCompleted > 0 || dev.debug); completedChallenges += m->completedChallenges; totalChallenges += m->totalChallenges; + prevCompleted = m->completedChallenges; i++; } diff --git a/src/defs.h b/src/defs.h index 9efe424..d5359dd 100644 --- a/src/defs.h +++ b/src/defs.h @@ -95,6 +95,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #define EF_SECONDARY_TARGET (2 << 12) #define EF_AI_TARGET (2 << 13) #define EF_AI_LEADER (2 << 14) +#define EF_ROPED_ATTACHED (2 << 15) #define AIF_NONE 0 #define AIF_FOLLOWS_PLAYER (2 << 0) @@ -255,7 +256,8 @@ enum TT_WAYPOINT, TT_ESCAPED, TT_PLAYER_ESCAPED, - TT_ITEM + TT_ITEM, + TT_STOLEN }; enum diff --git a/src/galaxy/mission.c b/src/galaxy/mission.c index 8c3ea1c..9ada9e3 100644 --- a/src/galaxy/mission.c +++ b/src/galaxy/mission.c @@ -376,7 +376,7 @@ static void loadFighters(cJSON *node) Entity *e; char **types, *name, *groupName, *type; int side, scatter, number, active; - int i, numTypes, addFlags, addAIFlags; + int i, numTypes, addFlags, addAIFlags, systemPower; long flags, aiFlags; float x, y; @@ -400,6 +400,7 @@ 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")) { @@ -462,6 +463,12 @@ 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; diff --git a/src/game/trophies.c b/src/game/trophies.c index 0fb2f7d..ee02e6d 100644 --- a/src/game/trophies.c +++ b/src/game/trophies.c @@ -219,3 +219,8 @@ void awardCampaignTrophies(void) } } } + +void awardPostMissionTrophies(void) +{ + +} diff --git a/src/system/lookup.c b/src/system/lookup.c index 84509fe..2d66ca5 100644 --- a/src/system/lookup.c +++ b/src/system/lookup.c @@ -88,6 +88,7 @@ void initLookups(void) addLookup("TT_ESCAPED", TT_ESCAPED); addLookup("TT_PLAYER_ESCAPED", TT_PLAYER_ESCAPED); addLookup("TT_ITEM", TT_ITEM); + addLookup("TT_STOLEN", TT_STOLEN); addLookup("WT_BUTTON", WT_BUTTON); addLookup("WT_SELECT", WT_SELECT); diff --git a/src/system/widgets.c b/src/system/widgets.c index d3942b4..c5fa49a 100644 --- a/src/system/widgets.c +++ b/src/system/widgets.c @@ -109,7 +109,7 @@ void drawWidgets(const char *group) if (mouseOver && selectedWidget != w) { - if (w->type == WT_BUTTON) + if (w->type == WT_BUTTON || w->type == WT_CONTROL_CONFIG) { playSound(SND_GUI_CLICK); } @@ -262,6 +262,7 @@ static void handleMouse(void) { app.awaitingWidgetInput = 1; app.lastKeyPressed = app.lastButtonPressed = -1; + playSound(SND_GUI_SELECT); } app.mouse.button[SDL_BUTTON_LEFT] = 0; break; @@ -305,6 +306,7 @@ static void handleControlWidgets(void) } else if (app.lastKeyPressed == SDL_SCANCODE_ESCAPE) { + playSound(SND_GUI_CLOSE); app.awaitingWidgetInput = 0; } else diff --git a/tools/createPOT.sh b/tools/createPOT.sh index 39e6e76..4d43b4b 100755 --- a/tools/createPOT.sh +++ b/tools/createPOT.sh @@ -152,15 +152,11 @@ $potHeader = str_replace("{POT_CREATION_DATE}", $dateTime, $potHeader); fwrite($handle, "$potHeader\n"); -$i = 0; - foreach ($strings as $string) { fwrite($handle, "msgid \"$string\"\n"); fwrite($handle, "msgstr \"\"\n"); fwrite($handle, "\n"); - - $i++; } fclose($handle);