Merge branch 'develop' into trophies

Conflicts:
	src/battle/bullets.c
	src/battle/bullets.h
	src/battle/fighters.c
This commit is contained in:
Steve 2016-04-04 11:30:27 +01:00
commit 5e1220b9a4
45 changed files with 2035 additions and 155 deletions

View File

@ -7,6 +7,7 @@ Changelog
* Added control remapping
* New game mode: Challenges
* Added i18n support
* Added start of German translation
0.51

View File

@ -54,6 +54,7 @@ CC BY-NC-SA 3.0, with the following attribution: Copyright 2015-2016, Stephen J
* 278142__ricemaster__effect-notify.ogg - effect_notify.wav, by ricemaster - https://freesound.org/people/ricemaster/sounds/278142/
* 254174__kwahmah-02__s.ogg - s.wav, by kwahmah_02 - https://freesound.org/people/kwahmah_02/sounds/254174/
* 172870__escortmarius__carbidexplosion.ogg - carbidexplosion.wav, by escortmarius - https://freesound.org/people/escortmarius/sounds/172870/
* 320181__dland__hint.ogg - hint.wav, by dland - https://freesound.org/people/dland/sounds/320181/
### MUSIC

54
data/challenges/12.json Normal file
View File

@ -0,0 +1,54 @@
{
"name" : "Collect packages",
"description" : "Collect packages",
"background" : "AUTO",
"planet" : "AUTO",
"music" : "AUTO",
"player" : {
"type" : "Shuttle",
"side" : "SIDE_ALLIES",
"pilot" : "-",
"squadron" : "-",
"x" : 25,
"y" : 25
},
"challenge" : {
"itemLimit" : 8,
"timeLimit" : 105,
"allowPlayerDeath" : 1,
"challenges" : [
{
"type" : "CHALLENGE_ITEMS",
"value" : 3
},
{
"type" : "CHALLENGE_ITEMS",
"value" : 5
},
{
"type" : "CHALLENGE_ITEMS",
"value" : 8
}
]
},
"items" : [
{
"name" : "package",
"number" : 8,
"type" : "smallCrate",
"x" : 25,
"y" : 25,
"scatter" : 5000,
"flags" : "+EF_MISSION_TARGET"
}
],
"entities" : [
{
"type" : "ET_MINE",
"number" : 750,
"x" : 25,
"y" : 25,
"scatter" : 10000
}
]
}

View File

@ -6,6 +6,7 @@
"planet" : "gfx/planets/torelli.png",
"music" : "music/battle/heroism.ogg",
"manualComplete" : 1,
"waypointAutoAdvance" : 1,
"objectives" : [
{
"description" : "Check all waypoints",
@ -42,12 +43,6 @@
}
],
"script" : [
{
"function" : "TIME 0",
"lines" : [
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "Waypoint #2",
"lines" : [

View File

@ -6,6 +6,7 @@
"planet" : "gfx/planets/torelli.png",
"music" : "music/battle/heroism.ogg",
"manualComplete" : 1,
"waypointAutoAdvance" : 1,
"objectives" : [
{
"description" : "Check all Waypoints",
@ -59,12 +60,6 @@
}
],
"script" : [
{
"function" : "TIME 0",
"lines" : [
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "Waypoint #3",
"lines" : [

View File

@ -9,6 +9,7 @@
"planet" : "gfx/planets/torelli.png",
"music" : "",
"manualComplete" : 1,
"waypointAutoAdvance" : 1,
"objectives" : [
{
"description" : "Check all Waypoints",
@ -45,12 +46,6 @@
}
],
"script" : [
{
"function" : "TIME 0",
"lines" : [
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "TIME 3",
"lines" : [

View File

@ -0,0 +1,145 @@
{
"name" : "Alba Defence #1",
"description" : "Tzac forces have been detected moving into the area. They need to be dispatched as quickly as possible, so that Christabel cannot make any significant gains in amassing her forces in the system. The Eightballers, with additional support, will move in to intercept.",
"requires" : 35,
"background" : "gfx/backgrounds/background03.jpg",
"planet" : "gfx/planets/torelli.png",
"music" : "music/battle/battleThemeA.mp3",
"manualComplete" : 1,
"objectives" : [
{
"description" : "Check all Waypoints",
"targetName" : "Waypoint",
"targetValue" : 3,
"targetType" : "TT_WAYPOINT"
},
{
"description" : "Eliminate all enemy target",
"targetName" : "ENEMY",
"targetValue" : 1,
"targetType" : "TT_DESTROY",
"isEliminateAll" : 1
}
],
"player" : {
"type" : "Firefly",
"side" : "SIDE_ALLIES",
"pilot" : "1st Lt. Curtis Rice",
"squadron" : "Eightballers"
},
"fighters" : [
{
"name" : "Ally",
"types" : "Firefly;Nymph",
"number" : 6,
"side" : "SIDE_ALLIES",
"x" : 25,
"y" : 25,
"scatter" : 500
},
{
"groupName" : "Rebels-1",
"types" : "Shale",
"number" : 4,
"side" : "SIDE_REBEL",
"x" : 25,
"y" : 8,
"scatter" : 500,
"active" : 0
},
{
"groupName" : "Rebels-2",
"types" : "Shale",
"number" : 5,
"side" : "SIDE_REBEL",
"x" : 28,
"y" : 37,
"scatter" : 500,
"active" : 0
},
{
"groupName" : "Rebels-3",
"types" : "Shale",
"number" : 6,
"side" : "SIDE_REBEL",
"x" : 12,
"y" : 25,
"scatter" : 500,
"active" : 0
}
],
"entities" : [
{
"type" : "ET_WAYPOINT",
"x" : 25,
"y" : 18
},
{
"type" : "ET_WAYPOINT",
"x" : 28,
"y" : 27
},
{
"type" : "ET_WAYPOINT",
"x" : 22,
"y" : 25
}
],
"script" : [
{
"function" : "TIME 0",
"lines" : [
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "Waypoint #1",
"lines" : [
"ACTIVATE_ENTITY_GROUPS Rebels-1",
"MSG_BOX Wingmate;Enemies sighted.",
"MSG_BOX Rice;Break and attack, people!"
]
},
{
"function" : "ENEMIES_KILLED 4",
"lines" : [
"MSG_BOX Rice;That's the first group handled. Let's get to the next waypoint.",
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "Waypoint #2",
"lines" : [
"ACTIVATE_ENTITY_GROUPS Rebels-2",
"MSG_BOX Rice;Second group located."
]
},
{
"function" : "ENEMIES_KILLED 9",
"lines" : [
"MSG_BOX Rice;Control, this is Rice. Nine enemy fighters downed. Moving to the final waypoint.",
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "Waypoint #3",
"lines" : [
"ACTIVATE_ENTITY_GROUPS Rebels-3",
"MSG_BOX Rice;Final group spotted."
]
},
{
"function" : "ENEMIES_KILLED 15",
"lines" : [
"WAIT 2",
"MSG_BOX Rice;That's all of them.",
"MSG_BOX Wingmate;Not as tough as I was expecting.",
"MSG_BOX Rice;I think they're testing the water, like our Pandoran friends before them.",
"MSG_BOX Rice;We'd better prepare ourselves for a major attack in the next few days. Hopefully not from both of them at once.",
"WAIT_MSG_BOX",
"COMPLETE_MISSION"
]
}
]
}

View File

@ -1,6 +1,6 @@
{
"name" : "Return to Aster",
"description" : "",
"description" : "We've received word from CSN Florin that they have suffered a power failure, affecting the entire ship. The stranded vessel has attracted the attention of the Pandorans, who have already deployed shuttles and tugs to absorb it into their ranks. The Salty Wildcats will intercept and provide cover until Florin can affect repairs.",
"requires" : 30,
"background" : "gfx/backgrounds/background04.jpg",
"planet" : "gfx/planets/bluePlanet.png",
@ -143,7 +143,7 @@
"WAIT 2",
"MSG_BOX Black;Looks like that's all of them.",
"MSG_BOX CSN Florin;Those were Nation of Tzac fighters. We've heard reports of them being active in some Confederation systems.",
"MSG_BOX Black;Would appear that Crystabelle is finally ready to make good on all her threats. Great, so now we have both her AND the Pandorans to deal with.",
"MSG_BOX Black;Would appear that Christabel is finally ready to make good on all her threats. Great, so now we have both her AND the Pandorans to deal with.",
"MSG_BOX CSN Florin;It never rains ...",
"MSG_BOX CSN Florin;We're starting systems up again. Once we've completed pre-jump checks we're heading for Temper. Thank you for your assistance.",
"MSG_BOX Black;We'll meet you there.",

View File

@ -1,6 +1,6 @@
{
"name" : "Mine Sweeper",
"description" : "",
"description" : "Tzac bombers have been identified in the area, deploying mines. While this violates intergalactic treaties, we could never assume that Tzac, much like the Pandorans, would abide by the rules of war. We need to take down those bombers quickly. Exercise caution around the mines, as they are especially potent.",
"requires" : 33,
"background" : "gfx/backgrounds/background04.jpg",
"planet" : "gfx/planets/bluePlanet.png",

View File

@ -6,6 +6,7 @@
"planet" : "gfx/planets/bluePlanet.png",
"music" : "music/battle/determination.mp3",
"manualComplete" : 1,
"waypointAutoAdvance" : 1,
"objectives" : [
{
"description" : "Check all wayponts",
@ -126,12 +127,6 @@
}
],
"script" : [
{
"function" : "TIME 0",
"lines" : [
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "Waypoint #2",
"lines" : [

View File

@ -6,6 +6,7 @@
"planet" : "gfx/planets/bluePlanet.png",
"music" : "music/battle/determination.mp3",
"manualComplete" : 1,
"waypointAutoAdvance" : 1,
"player" : {
"pilot" : "Lt. Cdr. Daniel Carr",
"squadron" : "Iron Patriots",
@ -126,12 +127,6 @@
}
],
"script" : [
{
"function" : "TIME 0",
"lines" : [
"ACTIVATE_NEXT_WAYPOINT"
]
},
{
"function" : "Waypoint #1",
"lines" : [

1500
locale/de.po Normal file

File diff suppressed because it is too large Load Diff

View File

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: TBFTSS: The Pandoran War\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2016-04-01 08:08:53+0100\n"
"POT-Creation-Date: 2016-04-04 11:25:33+0100\n"
"PO-Revision-Date: ???\n"
"Last-Translator: ???\n"
"Language-Team: ???\n"
@ -310,6 +310,9 @@ msgstr ""
msgid "Capital Ships Lost"
msgstr ""
msgid "Mines Destroyed"
msgstr ""
msgid "Time Played"
msgstr ""
@ -577,6 +580,42 @@ msgstr ""
msgid "Okay, let's get home and report in."
msgstr ""
msgid "Tzac forces have been detected moving into the area. They need to be dispatched as quickly as possible, so that Christabel cannot make any significant gains in amassing her forces in the system. The Eightballers, with additional support, will move in to intercept."
msgstr ""
msgid "Enemies sighted."
msgstr ""
msgid "Break and attack, people!"
msgstr ""
msgid "That's the first group handled. Let's get to the next waypoint."
msgstr ""
msgid "Second group located."
msgstr ""
msgid "Control, this is Rice. Nine enemy fighters downed. Moving to the final waypoint."
msgstr ""
msgid "Final group spotted."
msgstr ""
msgid "That's all of them."
msgstr ""
msgid "Not as tough as I was expecting."
msgstr ""
msgid "I think they're testing the water, like our Pandoran friends before them."
msgstr ""
msgid "We'd better prepare ourselves for a major attack in the next few days. Hopefully not from both of them at once."
msgstr ""
msgid "We've received word from CSN Florin that they have suffered a power failure, affecting the entire ship. The stranded vessel has attracted the attention of the Pandorans, who have already deployed shuttles and tugs to absorb it into their ranks. The Salty Wildcats will intercept and provide cover until Florin can affect repairs."
msgstr ""
msgid "Florin, this is Black of the Salty Wildcats, here to assist."
msgstr ""
@ -613,7 +652,7 @@ msgstr ""
msgid "Those were Nation of Tzac fighters. We've heard reports of them being active in some Confederation systems."
msgstr ""
msgid "Would appear that Crystabelle is finally ready to make good on all her threats. Great, so now we have both her AND the Pandorans to deal with."
msgid "Would appear that Christabel is finally ready to make good on all her threats. Great, so now we have both her AND the Pandorans to deal with."
msgstr ""
msgid "It never rains ..."
@ -625,6 +664,21 @@ msgstr ""
msgid "We'll meet you there."
msgstr ""
msgid "Tzac bombers have been identified in the area, deploying mines. While this violates intergalactic treaties, we could never assume that Tzac, much like the Pandorans, would abide by the rules of war. We need to take down those bombers quickly. Exercise caution around the mines, as they are especially potent."
msgstr ""
msgid "Watch out for those mines. They're on proximity triggers and have a large area of effect."
msgstr ""
msgid "Take them out from a distance, otherwise you'll be in trouble."
msgstr ""
msgid "That's the bombers taken care of, but the area is still littered with mines."
msgstr ""
msgid "We'll need to get a team in here to take care of them."
msgstr ""
msgid "The day that we have feared and the events that we attempted to avert are now upon us - the Pandoran army has commenced its push beyond Mitikas space, and is beginning to assault neighbouring Independent star systems. We need to fight back, in order to protect Clarke from becoming underrun by this menace. Take heed: this will not be an easy battle, but we have little choice and must secure victory here today."
msgstr ""
@ -1417,3 +1471,6 @@ msgstr ""
msgid "Destroy INF Klondike and INF Canfield"
msgstr ""
msgid "Collect packages"
msgstr ""

Binary file not shown.

View File

@ -165,6 +165,11 @@ static void doBattle(void)
if (battle.stats[STAT_TIME]++ % FPS == 0)
{
runScriptFunction("TIME %d", battle.stats[STAT_TIME] / FPS);
if (game.currentMission->challengeData.timeLimit && game.currentMission->challengeData.timeLimit - battle.stats[STAT_TIME] < 11 * FPS)
{
playSound(SND_TIME_WARNING);
}
}
}
}

View File

@ -121,7 +121,7 @@ void doBullets(void)
}
else
{
if (collision(b->x - (b->w / 2) - battle.camera.x, b->y - (b->h / 2) - battle.camera.y, b->w * 2, b->h * 2, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
if (isOnBattleScreen(b->x, b->y, b->w, b->h))
{
bulletsToDraw[i++] = b;
@ -142,7 +142,7 @@ static void resizeDrawList(void)
n = drawCapacity + INITIAL_BULLET_DRAW_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing bullet draw capacity: %d -> %d\n", drawCapacity, n);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing bullet draw capacity: %d -> %d", drawCapacity, n);
bulletsToDraw = resize(bulletsToDraw, sizeof(Bullet*) * drawCapacity, sizeof(Bullet*) * n);
@ -212,6 +212,8 @@ static void checkCollisions(Bullet *b)
{
awardTrophy("PANDORAN");
}
e->killedBy = b->owner;
}
if (b->owner == player && b->type == BT_MISSILE)

View File

@ -44,6 +44,7 @@ extern void playSound(int id);
extern char *getTranslatedString(char *string);
extern void *resize(void *array, int oldSize, int newSize);
extern void awardTrophy(char *id);
extern int isOnBattleScreen(int x, int y, int w, int h);
extern Battle battle;
extern Colors colors;

View File

@ -50,7 +50,6 @@ Entity *spawnCapitalShip(char *name, int x, int y, int side)
memcpy(e, def, sizeof(Entity));
e->id = battle.entId;
e->next = NULL;
e->x = x;
@ -384,6 +383,7 @@ static void loadCapitalShipDef(char *filename)
e->shieldRechargeRate = cJSON_GetObjectItem(root, "shieldRechargeRate")->valueint;
e->texture = getTexture(cJSON_GetObjectItem(root, "texture")->valuestring);
e->speed = 1;
e->systemPower = MAX_SYSTEM_POWER;
e->action = think;
e->die = die;
@ -555,7 +555,7 @@ static void loadEngines(Entity *parent, cJSON *engines)
}
}
void updateCapitalShipComponentProperties(Entity *parent, long flags, int addFlags)
void updateCapitalShipComponentProperties(Entity *parent, long flags)
{
Entity *e;
@ -580,18 +580,9 @@ void updateCapitalShipComponentProperties(Entity *parent, long flags, int addFla
e->active = parent->active;
if (flags != -1)
if (flags & EF_DISABLED)
{
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->flags |= EF_DISABLED;
}
}
}
@ -669,7 +660,7 @@ void loadCapitalShips(cJSON *node)
}
}
updateCapitalShipComponentProperties(e, flags, addFlags);
updateCapitalShipComponentProperties(e, flags);
}
node = node->next;

View File

@ -104,7 +104,7 @@ void doDebris(void)
}
else
{
if (collision(d->x - 16 - battle.camera.x, d->y - 16 - battle.camera.y, 32, 32, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT))
if (isOnBattleScreen(d->x, d->y, 32, 32))
{
debrisToDraw[i++] = d;
@ -125,7 +125,7 @@ static void resizeDrawList(void)
n = drawCapacity + INITIAL_DEBRIS_DRAW_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing debris draw capacity: %d -> %d\n", drawCapacity, n);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing debris draw capacity: %d -> %d", drawCapacity, n);
debrisToDraw = resize(debrisToDraw, sizeof(Debris*) * drawCapacity, sizeof(Debris*) * n);
drawCapacity = n;

View File

@ -27,9 +27,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern float mod(float n, float x);
extern void blitRotated(SDL_Texture *texture, int x, int y, float angle);
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
extern SDL_Texture *getTexture(char *filename);
extern void addDebrisFire(int x, int y);
extern void *resize(void *array, int oldSize, int newSize);
extern int isOnBattleScreen(int x, int y, int w, int h);
extern Battle battle;

View File

@ -91,7 +91,7 @@ void doEffects(void)
break;
default:
onScreen = collision(e->x - (e->size / 2) - battle.camera.x, e->y - (e->size / 2) - battle.camera.y, e->size * 2, e->size * 2, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
onScreen = isOnBattleScreen(e->x, e->y, e->size, e->size);
break;
}
@ -121,7 +121,7 @@ static void resizeDrawList(void)
n = drawCapacity + INITIAL_EFFECT_DRAW_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing effect draw capacity: %d -> %d\n", drawCapacity, n);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing effect draw capacity: %d -> %d", drawCapacity, n);
effectsToDraw = resize(effectsToDraw, sizeof(Effect*) * drawCapacity, sizeof(Effect*) * n);

View File

@ -27,6 +27,7 @@ extern SDL_Texture *getTexture(char *name);
extern void blit(SDL_Texture *t, int x, int y, int center);
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
extern void *resize(void *array, int oldSize, int newSize);
extern int isOnBattleScreen(int x, int y, int w, int h);
extern App app;
extern Battle battle;

View File

@ -30,11 +30,15 @@ static void drawTargetRects(Entity *e);
static int drawComparator(const void *a, const void *b);
static void notifyNewArrivals(void);
static int isCapitalShipComponent(Entity *e);
static void resizeDrawList(void);
static Entity deadHead;
static Entity *deadTail;
static int disabledGlow;
static int disabledGlowDir;
static Entity **entsToDraw;
static int drawCapacity;
static int numEntsToDraw;
void initEntities(void)
{
@ -44,13 +48,17 @@ void initEntities(void)
disabledGlow = DISABLED_GLOW_MAX;
disabledGlowDir = -DISABLED_GLOW_SPEED;
drawCapacity = INITIAL_ENTITY_DRAW_CAPACITY;
entsToDraw = malloc(sizeof(Entity*) * drawCapacity);
memset(entsToDraw, 0, sizeof(Entity*) * drawCapacity);
}
Entity *spawnEntity(void)
{
Entity *e = malloc(sizeof(Entity));
memset(e, 0, sizeof(Entity));
e->id = battle.entId++;
e->active = 1;
battle.entityTail->next = e;
@ -76,6 +84,10 @@ void doEntities(void)
player->shield = player->maxShield;
}
numEntsToDraw = 0;
memset(entsToDraw, 0, sizeof(Entity*) * drawCapacity);
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
removeFromQuadtree(e, &battle.quadtree);
@ -167,6 +179,16 @@ void doEntities(void)
{
addToQuadtree(e, &battle.quadtree);
}
if (isOnBattleScreen(e->x, e->y, e->w, e->h))
{
entsToDraw[numEntsToDraw++] = e;
if (numEntsToDraw == drawCapacity)
{
resizeDrawList();
}
}
}
else
{
@ -262,6 +284,19 @@ void doEntities(void)
}
}
static void resizeDrawList(void)
{
int n;
n = drawCapacity + INITIAL_ENTITY_DRAW_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing entity draw capacity: %d -> %d", drawCapacity, n);
entsToDraw = resize(entsToDraw, sizeof(Entity*) * drawCapacity, sizeof(Entity*) * n);
drawCapacity = n;
}
static void restrictToBattleArea(Entity *e)
{
float force;
@ -363,17 +398,12 @@ static int isCapitalShipComponent(Entity *e)
void drawEntities(void)
{
Entity *e, **candidates;
Entity *e;
int i;
candidates = getAllEntsWithin(battle.camera.x, battle.camera.y, SCREEN_WIDTH, SCREEN_HEIGHT, NULL);
qsort(entsToDraw, numEntsToDraw, sizeof(Entity*), drawComparator);
/* count number of candidates for use with qsort */
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i]) {}
qsort(candidates, i, sizeof(Entity*), drawComparator);
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
for (i = 0, e = entsToDraw[i] ; e != NULL ; e = entsToDraw[++i])
{
self = e;
@ -467,7 +497,7 @@ void activateEntities(char *names)
if (e->type == ET_CAPITAL_SHIP)
{
updateCapitalShipComponentProperties(e);
updateCapitalShipComponentProperties(e, 0);
}
}
}
@ -495,7 +525,7 @@ void activateEntityGroups(char *groupNames)
if (e->type == ET_CAPITAL_SHIP)
{
updateCapitalShipComponentProperties(e);
updateCapitalShipComponentProperties(e, 0);
}
}
}
@ -559,15 +589,28 @@ void countNumEnemies(void)
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "battle.numInitialEnemies=%d", battle.numInitialEnemies);
}
void addAllEntsToQuadtree(void)
void addVisibleEntsToDrawList(void)
{
Entity *e;
battle.camera.x = player->x - (SCREEN_WIDTH / 2);
battle.camera.y = player->y - (SCREEN_HEIGHT / 2);
numEntsToDraw = 0;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->active)
{
addToQuadtree(e, &battle.quadtree);
if (isOnBattleScreen(e->x, e->y, e->w, e->h))
{
entsToDraw[numEntsToDraw++] = e;
if (numEntsToDraw == drawCapacity)
{
resizeDrawList();
}
}
}
}
}
@ -592,4 +635,8 @@ void destroyEntities(void)
}
deadTail = &deadHead;
free(entsToDraw);
entsToDraw = NULL;
}

View File

@ -20,6 +20,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../common.h"
#define INITIAL_ENTITY_DRAW_CAPACITY 8
#define DISABLED_GLOW_SPEED 3
#define DISABLED_GLOW_MIN 128
#define DISABLED_GLOW_MAX 255
@ -27,14 +28,15 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern void blitRotated(SDL_Texture *texture, int x, int y, float angle);
extern void doFighter(void);
extern void doCapitalShip(void);
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
extern void doRope(Entity *e);
extern void drawRope(Entity *e);
extern void cutRope(Entity *e);
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 updateCapitalShipComponentProperties(Entity *parent, long flags);
extern void *resize(void *array, int oldSize, int newSize);
extern int isOnBattleScreen(int x, int y, int w, int h);
extern App app;
extern Battle battle;

View File

@ -44,7 +44,6 @@ Entity *spawnFighter(char *name, int x, int y, int side)
memcpy(e, def, sizeof(Entity));
e->id = battle.entId;
e->next = NULL;
e->x = x;
@ -276,17 +275,7 @@ void doFighter(void)
if (self->alive == ALIVE_DEAD)
{
if (self == player)
{
battle.stats[STAT_PLAYER_KILLED]++;
/* the player is known as "Player", so we need to check the craft they were assigned to */
if (strcmp(game.currentMission->craft, "ATAF") == 0)
{
awardTrophy("ATAF_DESTROYED");
}
}
else if (player != NULL)
if (player != NULL && self != player)
{
if (player->alive == ALIVE_ALIVE)
{
@ -527,6 +516,16 @@ static void die(void)
self->action = simpleDie;
break;
}
if (self->killedBy == player && (!(self->flags & EF_NO_KILL_INC)))
{
battle.stats[STAT_ENEMIES_KILLED_PLAYER]++;
if (battle.isEpic)
{
battle.stats[STAT_EPIC_KILL_STREAK]++;
}
}
}
static void immediateDie(void)

View File

@ -406,6 +406,8 @@ static void drawNumFighters(void)
static void drawObjectives(void)
{
int timeRemaining;
if (!game.currentMission->challengeData.isChallenge)
{
blit(objectives, (SCREEN_WIDTH / 2) - 50, 14, 0);
@ -415,8 +417,16 @@ static void drawObjectives(void)
{
if (game.currentMission->challengeData.timeLimit)
{
timeRemaining = game.currentMission->challengeData.timeLimit - battle.stats[STAT_TIME];
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));
drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, (timeRemaining < 11 * FPS) ? colors.red : colors.white, timeToString(timeRemaining, 0));
}
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);
}
if (game.currentMission->challengeData.itemLimit)
{
@ -427,12 +437,6 @@ static void drawObjectives(void)
drawText(SCREEN_WIDTH / 2, 35, 14, TA_CENTER, colors.white, "%d / %d", battle.stats[STAT_CIVILIANS_RESCUED], game.currentMission->challengeData.rescueLimit);
}
}
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);
}
}
}
static float distanceToKM(int x1, int y1, int x2, int y2)

View File

@ -104,6 +104,11 @@ static void lookForFighters(void)
static void die(void)
{
if (self->killedBy == player)
{
battle.stats[STAT_MINES_DESTROYED]++;
}
addMineExplosion();
doSplashDamage();

View File

@ -33,4 +33,5 @@ extern void damageFighter(Entity *e, int amount, long flags);
extern void playBattleSound(int id, int x, int y);
extern Battle battle;
extern Entity *player;
extern Entity *self;

View File

@ -119,7 +119,22 @@ void doPlayer(void)
if (player->health <= 0 && battle.status == MS_IN_PROGRESS)
{
if (!battle.isEpic)
battle.stats[STAT_PLAYER_KILLED]++;
/* the player is known as "Player", so we need to check the craft they were assigned to */
if (strcmp(game.currentMission->craft, "ATAF") == 0)
{
awardTrophy("ATAF_DESTROYED");
}
if (game.currentMission->challengeData.isChallenge)
{
if (!game.currentMission->challengeData.allowPlayerDeath)
{
failMission();
}
}
else if (!battle.isEpic)
{
failMission();
}
@ -555,7 +570,7 @@ static void selectMissionTarget(void)
closest = dist;
}
}
else if (battle.missionTarget->type == ET_WAYPOINT && e->type == ET_WAYPOINT && e->id < battle.missionTarget->id)
else if (battle.missionTarget->type == ET_WAYPOINT && e->type == ET_WAYPOINT && e->id == battle.missionTarget->id)
{
battle.missionTarget = e;
}

View File

@ -131,7 +131,7 @@ static void resizeQTEntCapacity(Quadtree *root)
n = root->capacity + QT_INITIAL_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing QT node: %d -> %d\n", root->capacity, n);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing QT node: %d -> %d", root->capacity, n);
root->ents = resize(root->ents, sizeof(Entity*) * root->capacity, sizeof(Entity*) * n);
root->capacity = n;
@ -261,7 +261,7 @@ static void resizeCandidates(void)
n = cCapacity + QT_INITIAL_CAPACITY;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing candidates: %d -> %d\n", cCapacity, n);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Resizing candidates: %d -> %d", cCapacity, n);
candidates = resize(candidates, sizeof(Entity*) * cCapacity, sizeof(Entity*) * n);
cCapacity = n;

View File

@ -216,7 +216,7 @@ static void executeNextLine(ScriptRunner *runner)
}
else if (strcmp(command, "ACTIVATE_NEXT_WAYPOINT") == 0)
{
activateNextWaypoint(0);
activateNextWaypoint();
}
else if (strcmp(command, "ACTIVATE_SPAWNERS") == 0)
{

View File

@ -34,7 +34,7 @@ extern void activateLocations(char *locations);
void activateObjectives(char *objectives);
extern int showingMessageBoxes(void);
extern char *getTranslatedString(char *string);
extern void activateNextWaypoint(int id);
extern void activateNextWaypoint(void);
extern void activateJumpgate(int activate);
extern void activateSpawner(char *name, int active);

View File

@ -23,20 +23,23 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
static void think(void);
static int teamMatesClose(void);
static int isCurrentObjective(void);
void activateNextWaypoint(int id);
void activateNextWaypoint(void);
static int waypointId;
static int currentWaypointId;
void resetWaypoints(void)
{
waypointId = 1;
currentWaypointId = 0;
}
Entity *spawnWaypoint(void)
{
Entity *waypoint = spawnEntity();
sprintf(waypoint->name, "Waypoint #%d", waypointId++);
sprintf(waypoint->name, "Waypoint #%d", waypointId);
waypoint->id = waypointId;
waypoint->type = ET_WAYPOINT;
waypoint->active = 0;
waypoint->health = waypoint->maxHealth = FPS;
@ -47,6 +50,8 @@ Entity *spawnWaypoint(void)
SDL_QueryTexture(waypoint->texture, NULL, NULL, &waypoint->w, &waypoint->h);
waypointId++;
return waypoint;
}
@ -71,7 +76,10 @@ static void think(void)
runScriptFunction(self->name);
activateNextWaypoint(self->id);
if (battle.waypointAutoAdvance)
{
activateNextWaypoint();
}
battle.stats[STAT_WAYPOINTS_VISITED]++;
}
@ -112,14 +120,16 @@ static int teamMatesClose(void)
return 1;
}
void activateNextWaypoint(int id)
void activateNextWaypoint(void)
{
Entity *e;
Entity *nextWaypoint = NULL;
currentWaypointId++;
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->type == ET_WAYPOINT && e->id > id && (nextWaypoint == NULL || e->id < nextWaypoint->id))
if (e->type == ET_WAYPOINT && e->id == currentWaypointId)
{
nextWaypoint = e;
}
@ -128,5 +138,7 @@ void activateNextWaypoint(int id)
if (nextWaypoint != NULL)
{
nextWaypoint->active = 1;
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_DEBUG, "Activating %s", nextWaypoint->name);
}
}

View File

@ -29,7 +29,7 @@ static void updateDisabledChallenge(Challenge *c);
static void updateItemsChallenge(Challenge *c);
static void completeChallenge(void);
static void failChallenge(void);
static void updateChallenges(void);
static int updateChallenges(void);
static char *getFormattedChallengeDescription(const char *format, ...);
char *getChallengeDescription(Challenge *c);
static int challengeFinished(void);
@ -83,19 +83,21 @@ void initChallenges(void)
void doChallenges(void)
{
int passed;
if (game.currentMission->challengeData.isChallenge && battle.status == MS_IN_PROGRESS)
{
if (challengeFinished())
{
if (battle.stats[STAT_TIME] >= game.currentMission->challengeData.timeLimit)
passed = updateChallenges();
if (passed)
{
failChallenge();
completeChallenge();
}
else
{
updateChallenges();
completeChallenge();
failChallenge();
}
}
}
@ -139,21 +141,30 @@ static int challengeFinished(void)
return 1;
}
if (player->health <= 0)
{
return 1;
}
return 0;
}
static void updateChallenges(void)
static int updateChallenges(void)
{
int i;
int i, numPassed;
Challenge *c;
updateAccuracyStats(battle.stats);
numPassed = 0;
for (i = 0 ; i < MAX_CHALLENGES ; i++)
{
c = game.currentMission->challengeData.challenges[i];
if (c && !c->passed)
if (c)
{
if (!c->passed)
{
switch (c->type)
{
@ -190,12 +201,20 @@ static void updateChallenges(void)
break;
}
}
if (c->passed)
{
numPassed++;
}
}
}
if (dev.debug)
{
printStats();
}
return numPassed;
}
static void printStats(void)

View File

@ -243,6 +243,7 @@ enum
SND_RADIO,
SND_TROPHY,
SND_MINE_WARNING,
SND_TIME_WARNING,
SND_GUI_CLICK,
SND_GUI_SELECT,
SND_GUI_CLOSE,
@ -343,6 +344,7 @@ enum
STAT_EPIC_KILL_STREAK,
STAT_CAPITAL_SHIPS_DESTROYED,
STAT_CAPITAL_SHIPS_LOST,
STAT_MINES_DESTROYED,
/* add stats before here, so as not to mess up the stats screen */
STAT_TIME,
STAT_MAX

View File

@ -183,6 +183,25 @@ void drawBackground(SDL_Texture *texture)
}
}
int isOnBattleScreen(int x, int y, int w, int h)
{
x -= (w / 2);
x -= (SCREEN_WIDTH / 2);
x -= battle.camera.x;
y -= (h / 2);
y -= (SCREEN_HEIGHT / 2);
y -= battle.camera.y;
w *= 2;
w += SCREEN_WIDTH;
h *= 2;
h += SCREEN_HEIGHT;
return collision(x, y, w, h, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);
}
void saveScreenshot(void)
{
static int i = 0;

View File

@ -22,7 +22,9 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
extern void drawText(int x, int y, int size, int align, SDL_Color c, const char *format, ...);
extern void drawMouse(void);
extern int collision(int x1, int y1, int w1, int h1, int x2, int y2, int w2, int h2);
extern App app;
extern Battle battle;
extern Colors colors;
extern Dev dev;

View File

@ -88,6 +88,9 @@ Mission *loadMissionMeta(char *filename)
mission->challengeData.noBoost = getJSONValue(node, "noBoost", 0);
mission->challengeData.noGuns = getJSONValue(node, "noGuns", 0);
/* misc */
mission->challengeData.allowPlayerDeath = getJSONValue(node, "allowPlayerDeath", 0);
node = cJSON_GetObjectItem(node, "challenges");
if (node)
@ -164,6 +167,7 @@ void loadMission(char *filename)
battle.manualComplete = getJSONValue(root, "manualComplete", 0);
battle.unwinnable = getJSONValue(root, "unwinnable", 0);
battle.waypointAutoAdvance = getJSONValue(root, "waypointAutoAdvance", 0);
initScript(cJSON_GetObjectItem(root, "script"));
@ -216,13 +220,18 @@ void loadMission(char *filename)
battle.status = MS_IN_PROGRESS;
}
if (battle.waypointAutoAdvance)
{
activateNextWaypoint();
}
countNumEnemies();
initPlayer();
initMissionInfo();
addAllEntsToQuadtree();
addVisibleEntsToDrawList();
playMusic(music);
}
@ -347,6 +356,7 @@ static void loadEntities(cJSON *node)
{
case ET_WAYPOINT:
e = spawnWaypoint();
active = 0;
break;
case ET_JUMPGATE:

View File

@ -49,7 +49,7 @@ extern char *getPlanetTextureName(int n);
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 void addVisibleEntsToDrawList(void);
extern void loadObjectives(cJSON *node);
extern void loadPlayer(cJSON *node);
extern void loadCapitalShips(cJSON *node);
@ -58,6 +58,7 @@ extern void loadItems(cJSON *node);
extern void loadLocations(cJSON *node);
extern void loadSpawners(cJSON *node);
extern Entity *spawnMine(void);
extern void activateNextWaypoint(void);
extern Battle battle;
extern Dev dev;

View File

@ -68,6 +68,7 @@ void initStats(void)
statDescription[STAT_WAYPOINTS_VISITED] = _("Waypoints Visited");
statDescription[STAT_CAPITAL_SHIPS_DESTROYED] = _("Capital Ships Destroyed");
statDescription[STAT_CAPITAL_SHIPS_LOST] = _("Capital Ships Lost");
statDescription[STAT_MINES_DESTROYED] = _("Mines Destroyed");
statDescription[STAT_TIME] = _("Time Played");
}

View File

@ -101,7 +101,7 @@ static void initFighters(void)
for (i = 0 ; i < NUM_FIGHTERS ; i++)
{
fighters[i].x = rand() % (SCREEN_WIDTH - 64);
fighters[i].x = rand() % (SCREEN_WIDTH - 32);
fighters[i].y = SCREEN_HEIGHT + (rand() % SCREEN_HEIGHT);
fighters[i].texture = getTexture(fighterTextures[rand() % numTextures]);
fighters[i].dy = -(1 + rand() % 3);
@ -133,7 +133,9 @@ static void logic(void)
static void doFighters(void)
{
int i;
int i, numTextures;
numTextures = sizeof(fighterTextures) / sizeof(char*);
for (i = 0 ; i < NUM_FIGHTERS ; i++)
{
@ -145,8 +147,10 @@ static void doFighters(void)
if (fighters[i].y <= -64)
{
fighters[i].x = rand() % (SCREEN_WIDTH - 64);
fighters[i].x = rand() % (SCREEN_WIDTH - 32);
fighters[i].y = SCREEN_HEIGHT + (rand() % SCREEN_HEIGHT);
fighters[i].texture = getTexture(fighterTextures[rand() % numTextures]);
fighters[i].dy = -(1 + rand() % 3);
}
}
}
@ -251,5 +255,5 @@ static void returnFromOptions(void)
static void quit(void)
{
exit(1);
exit(0);
}

View File

@ -146,6 +146,7 @@ struct Entity {
Entity *target;
Entity *leader;
Entity *owner;
Entity *killedBy;
void (*action)(void);
void (*draw)(void);
void (*die)(void);
@ -261,6 +262,7 @@ typedef struct {
int noECM;
int noGuns;
int scriptedEnd;
int allowPlayerDeath;
Challenge *challenges[MAX_CHALLENGES];
} ChallengeData;
@ -322,7 +324,6 @@ struct Spawner {
};
typedef struct {
int entId;
SDL_Point camera;
int numAllies;
int numEnemies;
@ -333,6 +334,7 @@ typedef struct {
int playerSelect;
int manualComplete;
int unwinnable;
int waypointAutoAdvance;
int missionFinishedTimer;
int boostTimer;
int ecmTimer;

View File

@ -40,15 +40,15 @@ void init18N(int argc, char *argv[])
if (languageId >= argc)
{
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "You must specify a language to use with -language. Using default.\n");
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_ERROR, "You must specify a language to use with -language. Using default.");
}
}
}
setLanguage("tbftss", languageId == -1 ? NULL : argv[languageId]);
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Numeric is %s\n", setlocale(LC_NUMERIC, "C"));
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "atof(2.75) is %f\n", atof("2.75"));
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "Numeric is %s", setlocale(LC_NUMERIC, "C"));
SDL_LogMessage(SDL_LOG_CATEGORY_APPLICATION, SDL_LOG_PRIORITY_INFO, "atof(2.75) is %f", atof("2.75"));
}
void initSDL(void)

View File

@ -175,6 +175,7 @@ void initLookups(void)
addLookup("STAT_EPIC_KILL_STREAK", STAT_EPIC_KILL_STREAK);
addLookup("STAT_CAPITAL_SHIPS_DESTROYED", STAT_CAPITAL_SHIPS_DESTROYED);
addLookup("STAT_CAPITAL_SHIPS_LOST", STAT_CAPITAL_SHIPS_LOST);
addLookup("STAT_MINES_DESTROYED", STAT_MINES_DESTROYED);
addLookup("STAT_TIME", STAT_TIME);
addLookup("TROPHY_BRONZE", TROPHY_BRONZE);

View File

@ -120,6 +120,7 @@ static void loadSounds(void)
sounds[SND_SELECT_WEAPON] = loadSound("sound/329359__bassoonrckr__reed-guillotine.ogg");
sounds[SND_TROPHY] = loadSound("sound/278142__ricemaster__effect-notify.ogg");
sounds[SND_MINE_WARNING] = loadSound("sound/254174__kwahmah-02__s.ogg");
sounds[SND_TIME_WARNING] = loadSound("sound/320181__dland__hint.ogg");
sounds[SND_GUI_CLICK] = loadSound("sound/257786__xtrgamr__mouse-click.ogg");
sounds[SND_GUI_SELECT] = loadSound("sound/321104__nsstudios__blip2.ogg");