Merge branch 'develop' into trophies

Conflicts:
	README.md
	src/defs.h
	src/galaxy/mission.c
	src/system/sound.c
This commit is contained in:
Steve 2016-04-01 17:14:06 +01:00
commit 28eec0b8e0
36 changed files with 663 additions and 90 deletions

View File

@ -2,6 +2,8 @@ Changelog
0.6
* New Campaign missions
* Added new fighters: Bliizard, Razor, and Shale, part of the unstable Nation of Tzac
* Added control remapping
* New game mode: Challenges
* Added i18n support

View File

@ -52,6 +52,8 @@ CC BY-NC-SA 3.0, with the following attribution: Copyright 2015-2016, Stephen J
* 172591__timbre__zapitydooda.ogg - d1clsstf.wav, by wildweasel - https://freesound.org/people/wildweasel/sounds/39030/
* 39030__wildweasel__d1clsstf.ogg - push_button_switch_07.wav, by joedeshon - https://freesound.org/people/joedeshon/sounds/139061/
* 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/
### MUSIC

View File

@ -1,10 +1,10 @@
# DEVELOPMENT / DEBUG Stuff
You can run the game with
You can run the game with:
`./tbftss -debug`
to access some (rather crude) debugging and development stuff, activated by pressing certain keys on the keyboard. Press the following keys to toggle the states (see the console for output). Note to porters - you shouldn't distribute the game in this state (either as a hard compile or run script), as it could result in unexpected behaviour.
to access some (rather crude) debugging and development stuff, activated by pressing certain keys on the keyboard. Press the following keys to toggle the states (see the console for output). Note to packagers - you shouldn't distribute the game in this state (either as a hard compile or run script), as it could result in unexpected behaviour.
* [1] - Make the player immortal
* [2] - Unlimited missiles
@ -15,3 +15,9 @@ to access some (rather crude) debugging and development stuff, activated by pres
* [9] - Show the current frames per second
* [0] - Take a screenshot once per second, saving to /tmp/tbftss on Linux.
By default, the game will output WARN level messages, or greater. To see INFO level messages, you can use:
`./tbftss -info`
Note that using `-debug` will automatically output DEBUG level messages.

View File

@ -19,7 +19,7 @@ OBJS += hud.o
OBJS += i18n.o init.o input.o io.o items.o
OBJS += jumpgate.o
OBJS += load.o locations.o lookup.o
OBJS += main.o messageBox.o mission.o missionInfo.o modalDialog.o
OBJS += main.o messageBox.o mine.o mission.o missionInfo.o modalDialog.o
OBJS += objectives.o options.o
OBJS += player.o
OBJS += quadtree.o

View File

@ -0,0 +1,33 @@
{
"name" : "Blizzard",
"health" : 120,
"shield" : 70,
"speed" : 1.85,
"reloadTime" : 14,
"shieldRechargeRate" : 45,
"texture" : "gfx/fighters/blizzard.png",
"guns" : [
{
"type" : "BT_PLASMA",
"x" : -14,
"y" : 0
},
{
"type" : "BT_PLASMA",
"x" : -14,
"y" : 0
},
{
"type" : "BT_PARTICLE",
"x" : 8,
"y" : 0
},
{
"type" : "BT_PARTICLE",
"x" : 8,
"y" : 0
}
],
"missiles" : 5,
"flags" : "EF_TAKES_DAMAGE"
}

View File

@ -3,7 +3,7 @@
"health" : 50,
"shield" : 50,
"speed" : 2,
"reloadTime" : 8,
"reloadTime" : 18,
"shieldRechargeRate" : 20,
"texture" : "gfx/fighters/shale.png",
"guns" : [

View File

@ -53,7 +53,7 @@
"x" : 25,
"y" : 25,
"number" : 6,
"aiFlags" : "+AIF_MOVES_TO_LEADER"
"aiFlags" : "AIF_MOVES_TO_LEADER+AIF_UNLIMITED_RANGE+AIF_DEFENSIVE"
},
{
"groupName" : "ShuttleTug",
@ -62,7 +62,7 @@
"x" : 25,
"y" : 25,
"number" : 6,
"aiFlags" : "+AIF_MOVES_TO_LEADER"
"aiFlags" : "AIF_MOVES_TO_LEADER+AIF_UNLIMITED_RANGE+AIF_DEFENSIVE"
},
{
"types" : "Thunderhead;Jackal;Sphinx",
@ -72,6 +72,28 @@
"number" : 4,
"flags" : "+EF_AI_LEADER",
"aiFlags" : "+AIF_UNLIMITED_RANGE"
},
{
"groupName" : "Rebels",
"types" : "Razor",
"side" : "SIDE_REBEL",
"x" : 10,
"y" : 51,
"number" : 4,
"aiFlags" : "+AIF_UNLIMITED_RANGE",
"scatter" : 500,
"active" : 0
},
{
"groupName" : "Rebels",
"types" : "Khepri",
"side" : "SIDE_REBEL",
"x" : 10,
"y" : 51,
"number" : 8,
"aiFlags" : "+AIF_UNLIMITED_RANGE+AIF_TARGET_FOCUS",
"scatter" : 500,
"active" : 0
}
],
"capitalShips" : [
@ -80,7 +102,7 @@
"types" : "CSN Corvette 01",
"side" : "SIDE_ALLIES",
"x" : 10,
"y" : 40,
"y" : 37,
"flags" : "+EF_AI_TARGET+EF_DISABLED+EF_MISSION_TARGET"
}
],
@ -96,7 +118,7 @@
]
},
{
"function" : "ENEMIES_DESTROYED 16",
"function" : "ENEMIES_KILLED 16",
"lines" : [
"WAIT 2",
"MSG_BOX Black;Florin, Pandoran vessels have been dealt with.",
@ -108,12 +130,26 @@
"MSG_BOX CSN Florin;Negative. These appear to be non-aligned forces, fighters and bombers.",
"WAIT_MSG_BOX",
"WAIT 5",
"ACTIVATE_ENTITY_GROUP Rebels",
"ACTIVATE_ENTITY_GROUPS Rebels",
"MSG_BOX CSN Florin;Incoming forces are on intercept vectors. We only need a few more minutes.",
"MSG_BOX Black;On it.",
"WAIT_MSG_BOX",
"ACTIVATE_OBJECTIVES Defeat rebel forces"
]
},
{
"function" : "OBJECTIVES_COMPLETE 2",
"lines" : [
"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 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.",
"WAIT_MSG_BOX",
"COMPLETE_MISSION"
]
}
]
}

View File

@ -0,0 +1,74 @@
{
"name" : "Mine Sweeper",
"description" : "",
"requires" : 33,
"background" : "gfx/backgrounds/background04.jpg",
"planet" : "gfx/planets/bluePlanet.png",
"music" : "music/battle/track-3.mp3",
"manualComplete" : 1,
"objectives" : [
{
"description" : "Destroy all enemy forces",
"targetName" : "Enemy",
"targetValue" : 1,
"targetType" : "TT_DESTROY",
"isEliminateAll" : 1
}
],
"player" : {
"type" : "Ray",
"side" : "SIDE_ALLIES",
"pilot" : "1st Lt. Cora Pope",
"squadron" : "Midnight Runners",
"x" : 25,
"y" : 45
},
"fighters" : [
{
"types" : "TAF",
"side" : "SIDE_ALLIES",
"x" : 25,
"y" : 45,
"number" : 3,
"scatter" : 500
},
{
"types" : "Khepri",
"side" : "SIDE_REBEL",
"x" : 25,
"y" : 30,
"number" : 5,
"scatter" : 4000,
"flags" : "+EF_AI_LEADER",
"aiFlags" : "+AIF_DROPS_MINES+AIF_WANDERS"
},
{
"types" : "Shale",
"side" : "SIDE_REBEL",
"x" : 25,
"y" : 35,
"number" : 3,
"scatter" : 2500,
"aiFlags" : "+AIF_MOVES_TO_LEADER"
}
],
"script" : [
{
"function" : "TIME 2",
"lines" : [
"MSG_BOX Pope;Watch out for those mines. They're on proximity triggers and have a large area of effect.",
"MSG_BOX Pope;Take them out from a distance, otherwise you'll be in trouble."
]
},
{
"function" : "ALL_OBJECTIVES_COMPLETE",
"lines" : [
"WAIT 1",
"MSG_BOX Pope;That's the bombers taken care of, but the area is still littered with mines.",
"MSG_BOX Pope;We'll need to get a team in here to take care of them.",
"WAIT_MSG_BOX",
"COMPLETE_MISSION"
]
}
]
}

View File

@ -98,7 +98,7 @@
{
"name" : "Tzac Commander",
"groupName" : "skirmishGroup",
"types" : "Firefly",
"types" : "Razor",
"side" : "SIDE_REBEL",
"x" : 15,
"y" : 40,
@ -107,7 +107,7 @@
},
{
"groupName" : "skirmishGroup",
"types" : "Firefly;Nymph",
"types" : "Razor;Shale",
"side" : "SIDE_REBEL",
"number" : 8,
"x" : 15,

View File

@ -59,7 +59,7 @@
{
"name" : "Rebel",
"groupName" : "Rebels",
"types" : "Nymph;Firefly",
"types" : "Razor;Shale",
"side" : "SIDE_REBEL",
"x" : -1,
"y" : -1,
@ -70,7 +70,7 @@
{
"name" : "Rebel",
"groupName" : "Rebels",
"types" : "Nymph;Firefly",
"types" : "Razor;Shale",
"side" : "SIDE_REBEL",
"x" : 15,
"y" : -1,
@ -81,7 +81,7 @@
{
"name" : "Rebel",
"groupName" : "Rebels",
"types" : "Nymph;Firefly",
"types" : "Razor;Shale",
"side" : "SIDE_REBEL",
"x" : -1,
"y" : 15,

BIN
gfx/entities/mine.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 702 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
gfx/fighters/blizzard.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

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-03-27 11:09:14+0100\n"
"POT-Creation-Date: 2016-04-01 08:08:53+0100\n"
"PO-Revision-Date: ???\n"
"Last-Translator: ???\n"
"Language-Team: ???\n"
@ -577,6 +577,54 @@ msgstr ""
msgid "Okay, let's get home and report in."
msgstr ""
msgid "Florin, this is Black of the Salty Wildcats, here to assist."
msgstr ""
msgid "Glad to see you, Wildcats. The Pandorans arrived shortly before you did. We've got tugs and shuttles incoming."
msgstr ""
msgid "Acknowledged, we'll secure the area while you get things up and running."
msgstr ""
msgid "Florin, Pandoran vessels have been dealt with."
msgstr ""
msgid "Many thanks, Wildcats. We've identified the cause of the power outage. Should be no more than a few minutes before we can restart all systems."
msgstr ""
msgid "Wildcats, we're picking up an incoming squadron."
msgstr ""
msgid "More Pandoran tugs?"
msgstr ""
msgid "Negative. These appear to be non-aligned forces, fighters and bombers."
msgstr ""
msgid "Incoming forces are on intercept vectors. We only need a few more minutes."
msgstr ""
msgid "On it."
msgstr ""
msgid "Looks like that's all of them."
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."
msgstr ""
msgid "It never rains ..."
msgstr ""
msgid "We're starting systems up again. Once we've completed pre-jump checks we're heading for Temper. Thank you for your assistance."
msgstr ""
msgid "We'll meet you there."
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 ""
@ -661,9 +709,6 @@ msgstr ""
msgid "Only way we'll find out is if we go to Kethlan, and I'm not keen on heading there anytime soon."
msgstr ""
msgid "Looks like that's all of them."
msgstr ""
msgid "Chaz, anything?"
msgstr ""
@ -910,9 +955,6 @@ msgstr ""
msgid "Too early to speculate. We want you to disable and bring in one craft from each side. The rest, you can eliminate."
msgstr ""
msgid "On it."
msgstr ""
msgid "This is Carr, reporting operation successful. Bagged us two squadron commanders."
msgstr ""

Binary file not shown.

Binary file not shown.

View File

@ -37,6 +37,7 @@ static int nearJumpgate(void);
static void moveToJumpgate(void);
static int nearEnemies(void);
static int nearItems(void);
static int nearMines(void);
static void moveToItem(void);
static int nearTowableCraft(void);
static void moveToTowableCraft(void);
@ -50,9 +51,16 @@ static void doGunAI(void);
static void moveToLeader(void);
static void wander(void);
static void doWander(void);
static int selectWeaponForTarget(Entity *e);
static void deployMine(void);
void doAI(void)
{
if (self->aiFlags & AIF_DROPS_MINES)
{
deployMine();
}
if ((self->aiFlags & (AIF_AVOIDS_COMBAT | AIF_EVADE)) && nearEnemies())
{
return;
@ -63,6 +71,11 @@ void doAI(void)
return;
}
if (nearMines())
{
return;
}
if ((self->aiFlags & AIF_GOAL_JUMPGATE) && nearJumpgate())
{
/* near jumpgate, but you might decide to continue to fight, anyway */
@ -302,7 +315,7 @@ static void findTarget(void)
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (e->active && (e->flags & EF_TAKES_DAMAGE) && (!(e->flags & EF_DISABLED)) && e->side != self->side && e->health > 0 && canAttack(e))
if (canAttack(e))
{
dist = getDistance(self->x, self->y, e->x, e->y);
@ -317,19 +330,36 @@ static void findTarget(void)
static int canAttack(Entity *e)
{
self->selectedGunType = self->guns[0].type;
if (!e->active || e->side == self->side || e->health <= 0)
{
return 0;
}
if (!(e->flags & EF_TAKES_DAMAGE))
{
return 0;
}
if (!(e->flags & EF_AI_TARGET))
{
if (e->aiFlags & (AIF_AVOIDS_COMBAT | AIF_EVADE) || e->flags & EF_SECONDARY_TARGET)
{
if (rand() % 5)
{
return 0;
}
return !(rand() % 5);
}
}
if ((self->aiFlags & AIF_TARGET_FOCUS) && (!(e->flags & EF_AI_TARGET)))
{
return 0;
}
return selectWeaponForTarget(e);
}
static int selectWeaponForTarget(Entity *e)
{
self->selectedGunType = self->guns[0].type;
if (e->flags & EF_MUST_DISABLE)
{
if (e->systemPower > 0)
@ -437,7 +467,7 @@ static void preAttack(void)
if (!(self->aiFlags & AIF_MISSILE_BOAT))
{
/* force weapon selection, otherwise we'll keep using lasers / mag */
canAttack(self->target);
selectWeaponForTarget(self->target);
if (self->guns[0].type && (self->missiles == 0 || rand() % 50 > 0))
{
@ -562,6 +592,11 @@ static int nearEnemies(void)
{
if ((e->flags & EF_TAKES_DAMAGE) && e->side != self->side && !(e->flags & EF_DISABLED))
{
if ((self->aiFlags & AIF_TARGET_FOCUS) && (e->flags & EF_AI_TARGET))
{
continue;
}
if (getDistance(e->x, e->y, self->x, self->y) < 1000)
{
self->targetLocation.x += e->x;
@ -589,6 +624,64 @@ static int nearEnemies(void)
return 0;
}
static void deployMine(void)
{
Entity *mine;
if (!self->reload && self->thrust > 0)
{
mine = spawnMine();
mine->x = self->x;
mine->y = self->y;
mine->dx = rand() % 20 - rand() % 20;
mine->dx *= 0.1;
mine->dy = rand() % 20 - rand() % 20;
mine->dy *= 0.1;
mine->side = self->side;
self->reload = rand() % (FPS * 3);
}
}
static int nearMines(void)
{
int i, numMines;
Entity *e, **candidates;
candidates = getAllEntsWithin(self->x - 500, self->y - 500, 1000, 1000, self);
self->targetLocation.x = self->targetLocation.y = 0;
numMines = 0;
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (e->side != self->side && e->type == ET_MINE && getDistance(e->x, e->y, self->x, self->y) < 500)
{
self->targetLocation.x += e->x;
self->targetLocation.y += e->y;
numMines++;
}
}
if (numMines)
{
self->targetLocation.x /= numMines;
self->targetLocation.y /= numMines;
/* dodge slightly */
self->targetLocation.x += (rand() % 100 - rand() % 100);
self->targetLocation.y += (rand() % 100 - rand() % 100);
self->action = fleeEnemies;
self->aiActionTime = FPS * 2;
return 1;
}
return 0;
}
static void fleeEnemies(void)
{
int wantedAngle = 180 + getAngle(self->x, self->y, self->targetLocation.x, self->targetLocation.y);

View File

@ -38,6 +38,7 @@ extern void applyFighterBrakes(void);
extern void addHudMessage(SDL_Color c, char *format, ...);
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
extern char *getTranslatedString(char *string);
extern Entity *spawnMine(void);
extern Battle battle;
extern Colors colors;

View File

@ -284,6 +284,56 @@ void addSmallExplosion(void)
}
}
void addMineExplosion(void)
{
int i;
Effect *e;
for (i = 0 ; i < 16 ; i++)
{
e = malloc(sizeof(Effect));
memset(e, 0, sizeof(Effect));
battle.effectTail->next = e;
battle.effectTail = e;
e->type = EFFECT_TEXTURE;
e->x = self->x + rand() % 16 - rand() % 16;
e->y = self->y + rand() % 16 - rand() % 16;
e->texture = explosionTexture;
e->size = 32 + (rand() % 32);
e->r = 255;
setRandomFlameHue(e);
e->a = 32 + (rand() % 192);
e->health = e->a;
e->x -= e->size / 2;
e->y -= e->size / 2;
}
e = malloc(sizeof(Effect));
memset(e, 0, sizeof(Effect));
battle.effectTail->next = e;
battle.effectTail = e;
e->type = EFFECT_HALO;
e->x = self->x;
e->y = self->y;
e->size = 32;
e->scaleAmount = 2;
e->texture = haloTexture;
e->r = 255;
e->g = 255;
e->b = 255;
e->a = 128;
e->health = 128;
}
void addLargeExplosion(void)
{
int i;

View File

@ -409,7 +409,7 @@ 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);
drawText(SCREEN_WIDTH / 2, 10, 16, TA_CENTER, colors.white, "%d / %d", battle.numObjectivesComplete, (battle.numObjectivesTotal + battle.numConditions));
}
else
{

View File

@ -41,6 +41,8 @@ Entity *spawnJumpgate(void)
portal = getTexture("gfx/entities/portal.png");
portalAngle = 0;
SDL_QueryTexture(jumpgate->texture, NULL, NULL, &jumpgate->w, &jumpgate->h);
return jumpgate;
}

154
src/battle/mine.c Normal file
View File

@ -0,0 +1,154 @@
/*
Copyright (C) 2015-2016 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "mine.h"
static void think(void);
static void die(void);
static void lookForFighters(void);
static void doSplashDamage(void);
static SDL_Texture *mineWarning = NULL;
static SDL_Texture *mineNormal = NULL;
Entity *spawnMine(void)
{
Entity *mine = spawnEntity();
if (!mineNormal || !mineWarning)
{
mineNormal = getTexture("gfx/entities/mine.png");
mineWarning = getTexture("gfx/entities/mineWarning.png");
}
mine->type = ET_MINE;
mine->health = mine->maxHealth = 1;
mine->speed = 1;
mine->systemPower = SYSTEM_POWER;
mine->texture = mineNormal;
mine->action = think;
mine->die = die;
mine->flags = EF_TAKES_DAMAGE+EF_NO_TARGET;
SDL_QueryTexture(mine->texture, NULL, NULL, &mine->w, &mine->h);
return mine;
}
static void think(void)
{
self->texture = mineNormal;
self->angle += 0.1;
if (self->angle >= 360)
{
self->angle -= 360;
}
self->dx *= 0.99;
self->dy *= 0.99;
lookForFighters();
if (self->systemPower < SYSTEM_POWER && battle.stats[STAT_TIME] % 8 < 4)
{
playBattleSound(SND_MINE_WARNING, self->x, self->y);
self->texture = mineWarning;
}
}
static void lookForFighters(void)
{
Entity *e, **candidates;
int i;
candidates = getAllEntsWithin(self->x - (self->w / 2) - DAMAGE_RANGE, self->y - (self->h / 2) - DAMAGE_RANGE, self->w + DAMAGE_RANGE, self->h + DAMAGE_RANGE, self);
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (e->side != self->side && e->health > 0 && e->type == ET_FIGHTER && getDistance(self->x, self->y, e->x, e->y) <= TRIGGER_RANGE)
{
self->systemPower--;
if (self->systemPower <= 0)
{
self->health = 0;
}
return;
}
}
self->systemPower = SYSTEM_POWER;
}
static void die(void)
{
addMineExplosion();
doSplashDamage();
playBattleSound(SND_EXPLOSION_5, self->x, self->y);
self->alive = ALIVE_DEAD;
}
static void doSplashDamage(void)
{
Entity *e, **candidates;
int i, dist;
float damage, percent;
candidates = getAllEntsWithin(self->x - (self->w / 2), self->y - (self->h / 2), self->w, self->h, self);
for (i = 0, e = candidates[i] ; e != NULL ; e = candidates[++i])
{
if (e->health > 0 && (e->type == ET_FIGHTER || e->type == ET_MINE) && !(e->flags & EF_IMMORTAL))
{
dist = getDistance(self->x, self->y, e->x, e->y);
if (dist <= DAMAGE_RANGE)
{
percent = dist;
percent /= DAMAGE_RANGE;
percent = 1 - percent;
damage = 100;
damage *= percent;
if (e->type == ET_FIGHTER)
{
damageFighter(e, damage, 0);
}
else if (e->type == ET_MINE)
{
e->dx = e->x - self->x;
e->dy = e->y - self->y;
e->dx *= 0.01;
e->dy *= 0.01;
}
}
}
}
}

36
src/battle/mine.h Normal file
View File

@ -0,0 +1,36 @@
/*
Copyright (C) 2015-2016 Parallel Realities
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "../common.h"
#define TRIGGER_RANGE 150
#define DAMAGE_RANGE 255
#define SYSTEM_POWER 50
extern Entity *spawnEntity(void);
extern SDL_Texture *getTexture(char *filename);
extern Entity **getAllEntsWithin(int x, int y, int w, int h, Entity *ignore);
extern int getDistance(int x1, int y1, int x2, int y2);
extern void addMineExplosion(void);
extern void damageFighter(Entity *e, int amount, long flags);
extern void playBattleSound(int id, int x, int y);
extern Battle battle;
extern Entity *self;

View File

@ -26,7 +26,7 @@ void doObjectives(void)
int numHiddenObjectives;
Objective *o;
battle.numObjectivesComplete = battle.numObjectivesTotal = 0;
battle.numObjectivesComplete = battle.numObjectivesTotal = battle.numConditions = 0;
objectiveFailed = 0;
numHiddenObjectives = 0;
@ -38,6 +38,10 @@ void doObjectives(void)
{
battle.numObjectivesTotal++;
}
else
{
battle.numConditions++;
}
}
else
{

View File

@ -480,7 +480,7 @@ static void selectTarget(void)
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->active && e != player && (e->flags & EF_TAKES_DAMAGE) && e->side != player->side && e->alive == ALIVE_ALIVE && e->systemPower > 0 && i < MAX_SELECTABLE_TARGETS)
if (e->active && e != player && (e->flags & EF_TAKES_DAMAGE) && (!(e->flags & EF_NO_TARGET)) && e->side != player->side && e->alive == ALIVE_ALIVE && e->systemPower > 0 && i < MAX_SELECTABLE_TARGETS)
{
dist = getDistance(self->x, self->y, e->x, e->y);
if (dist < closest)

View File

@ -34,6 +34,7 @@ void drawRadar(void)
{
SDL_Rect r;
Entity *e;
int dist, inRange;
blit(radarTexture, SCREEN_WIDTH - 85, SCREEN_HEIGHT - 85, 1);
@ -43,45 +44,57 @@ void drawRadar(void)
for (e = battle.entityHead.next ; e != NULL ; e = e->next)
{
if (e->active && getDistance(e->x, e->y, player->x, player->y) / radarRanges[battle.radarRange] < 70)
dist = getDistance(e->x, e->y, player->x, player->y);
if (e->active)
{
r.x = SCREEN_WIDTH - 85;
r.y = SCREEN_HEIGHT - 85;
inRange = (!(e->flags & EF_SHORT_RADAR_RANGE)) ? (dist / radarRanges[battle.radarRange]) < 70 : dist < 500;
r.x -= (player->x - e->x) / radarRanges[battle.radarRange];
r.y -= (player->y - e->y) / radarRanges[battle.radarRange];
r.x--;
r.y--;
switch (e->side)
if (inRange)
{
case SIDE_ALLIES:
SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255);
break;
case SIDE_PIRATE:
case SIDE_PANDORAN:
case SIDE_REBEL:
SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 255);
break;
case SIDE_NONE:
r.x = SCREEN_WIDTH - 85;
r.y = SCREEN_HEIGHT - 85;
r.x -= (player->x - e->x) / radarRanges[battle.radarRange];
r.y -= (player->y - e->y) / radarRanges[battle.radarRange];
r.x--;
r.y--;
switch (e->side)
{
case SIDE_ALLIES:
SDL_SetRenderDrawColor(app.renderer, 0, 255, 0, 255);
break;
case SIDE_PIRATE:
case SIDE_PANDORAN:
case SIDE_REBEL:
SDL_SetRenderDrawColor(app.renderer, 255, 0, 0, 255);
break;
case SIDE_NONE:
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
break;
}
if (e == player->target)
{
SDL_SetRenderDrawColor(app.renderer, 255, 255, 0, 255);
}
if (e == battle.missionTarget)
{
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
break;
}
if (e->type == ET_MINE)
{
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
}
SDL_RenderFillRect(app.renderer, &r);
}
if (e == player->target)
{
SDL_SetRenderDrawColor(app.renderer, 255, 255, 0, 255);
}
if (e == battle.missionTarget)
{
SDL_SetRenderDrawColor(app.renderer, 255, 255, 255, 255);
}
SDL_RenderFillRect(app.renderer, &r);
}
}
}

View File

@ -45,6 +45,8 @@ Entity *spawnWaypoint(void)
waypoint->action = think;
waypoint->flags |= EF_NO_MT_BOX;
SDL_QueryTexture(waypoint->texture, NULL, NULL, &waypoint->w, &waypoint->h);
return waypoint;
}

View File

@ -79,24 +79,26 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define BF_SHIELD_DAMAGE (2 << 2)
#define BF_EXPLODES (2 << 3)
#define EF_NONE 0
#define EF_NO_KILL (2 << 0)
#define EF_DISABLED (2 << 1)
#define EF_IMMORTAL (2 << 2)
#define EF_MISSION_TARGET (2 << 3)
#define EF_NO_MT_BOX (2 << 4)
#define EF_HAS_ROPE (2 << 5)
#define EF_COLLECTS_ITEMS (2 << 6)
#define EF_MUST_DISABLE (2 << 7)
#define EF_RETREATING (2 << 8)
#define EF_NO_EPIC (2 << 9)
#define EF_STATIC (2 << 10)
#define EF_TAKES_DAMAGE (2 << 11)
#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 EF_NO_KILL_INC (2 << 16)
#define EF_NONE 0
#define EF_NO_KILL (2 << 0)
#define EF_DISABLED (2 << 1)
#define EF_IMMORTAL (2 << 2)
#define EF_MISSION_TARGET (2 << 3)
#define EF_NO_MT_BOX (2 << 4)
#define EF_HAS_ROPE (2 << 5)
#define EF_COLLECTS_ITEMS (2 << 6)
#define EF_MUST_DISABLE (2 << 7)
#define EF_RETREATING (2 << 8)
#define EF_NO_EPIC (2 << 9)
#define EF_STATIC (2 << 10)
#define EF_TAKES_DAMAGE (2 << 11)
#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 EF_NO_KILL_INC (2 << 16)
#define EF_SHORT_RADAR_RANGE (2 << 17)
#define EF_NO_TARGET (2 << 18)
#define AIF_NONE 0
#define AIF_FOLLOWS_PLAYER (2 << 0)
@ -115,6 +117,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#define AIF_EVADE (2 << 13)
#define AIF_WANDERS (2 << 14)
#define AIF_COVERS_RETREAT (2 << 15)
#define AIF_TARGET_FOCUS (2 << 16)
#define AIF_DROPS_MINES (2 << 17)
/* player abilities */
#define BOOST_RECHARGE_TIME (FPS * 7)
@ -150,6 +154,7 @@ enum
ET_ITEM,
ET_WAYPOINT,
ET_JUMPGATE,
ET_MINE,
ET_CAPITAL_SHIP_GUN,
ET_CAPITAL_SHIP_COMPONENT,
ET_CAPITAL_SHIP_ENGINE,
@ -225,6 +230,7 @@ enum
SND_EXPLOSION_2,
SND_EXPLOSION_3,
SND_EXPLOSION_4,
SND_EXPLOSION_5,
SND_GET_ITEM,
SND_MISSILE,
SND_INCOMING,
@ -236,6 +242,7 @@ enum
SND_BOOST,
SND_RADIO,
SND_TROPHY,
SND_MINE_WARNING,
SND_GUI_CLICK,
SND_GUI_SELECT,
SND_GUI_CLOSE,

View File

@ -311,7 +311,7 @@ static void loadEntities(cJSON *node)
{
Entity *e;
char *name, *groupName;
int i, type, scatter, number, active, addFlags;
int i, type, scatter, number, active, addFlags, side;
float x, y;
long flags;
@ -334,7 +334,8 @@ static void loadEntities(cJSON *node)
number = getJSONValue(node, "number", 1);
active = getJSONValue(node, "active", 1);
scatter = getJSONValue(node, "scatter", 1);
side = getJSONValue(node, "side", SIDE_NONE);
if (cJSON_GetObjectItem(node, "flags"))
{
flags = flagsToLong(cJSON_GetObjectItem(node, "flags")->valuestring, &addFlags);
@ -351,6 +352,10 @@ static void loadEntities(cJSON *node)
case ET_JUMPGATE:
e = spawnJumpgate();
break;
case ET_MINE:
e = spawnMine();
break;
default:
printf("Error: Unhandled entity type: %s\n", cJSON_GetObjectItem(node, "type")->valuestring);
@ -384,6 +389,8 @@ static void loadEntities(cJSON *node)
e->x = x;
e->y = y;
e->side = side;
if (scatter > 1)
{
@ -392,8 +399,6 @@ static void loadEntities(cJSON *node)
}
e->active = active;
SDL_QueryTexture(e->texture, NULL, NULL, &e->w, &e->h);
}
node = node->next;

View File

@ -57,6 +57,7 @@ extern void loadFighters(cJSON *node);
extern void loadItems(cJSON *node);
extern void loadLocations(cJSON *node);
extern void loadSpawners(cJSON *node);
extern Entity *spawnMine(void);
extern Battle battle;
extern Dev dev;

View File

@ -25,3 +25,4 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "../../common.h"
extern App app;
extern Dev dev;

View File

@ -338,7 +338,7 @@ typedef struct {
int ecmTimer;
int radarRange;
int numPlayerGuns;
int numObjectivesComplete, numObjectivesTotal;
int numObjectivesComplete, numObjectivesTotal, numConditions;
Entity *missionTarget;
Entity *jumpgate;
SDL_Texture *background, *planetTexture;

View File

@ -54,9 +54,9 @@ void setLanguage(char *applicationName, char *languageCode)
if (c[0] != '\0')
{
strncat(language, "_", MAX_MESSAGE_LENGTH - strlen(language) - 1);
strncat(language, "_", MAX_DESCRIPTION_LENGTH - strlen(language) - 1);
strncat(language, c, MAX_MESSAGE_LENGTH - strlen(language) - 1);
strncat(language, c, MAX_DESCRIPTION_LENGTH - strlen(language) - 1);
}
}
#else

View File

@ -19,6 +19,10 @@ Foundation, 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA.
#include "../common.h"
#ifdef _WIN32
#include <windows.h>
#endif
#define TABLE_SIZE 255
char *getTranslatedString(char *);

View File

@ -45,6 +45,7 @@ void initLookups(void)
addLookup("ET_WAYPOINT", ET_WAYPOINT);
addLookup("ET_JUMPGATE", ET_JUMPGATE);
addLookup("ET_CAPITAL_SHIP", ET_CAPITAL_SHIP);
addLookup("ET_MINE", ET_MINE);
addLookup("EF_NO_KILL", EF_NO_KILL);
addLookup("EF_DISABLED", EF_DISABLED);
@ -79,6 +80,8 @@ void initLookups(void)
addLookup("AIF_MOVES_TO_LEADER", AIF_MOVES_TO_LEADER);
addLookup("AIF_WANDERS", AIF_WANDERS);
addLookup("AIF_COVERS_RETREAT", AIF_COVERS_RETREAT);
addLookup("AIF_TARGET_FOCUS", AIF_TARGET_FOCUS);
addLookup("AIF_DROPS_MINES", AIF_DROPS_MINES);
addLookup("DT_ANY", DT_ANY);
addLookup("DT_NO_SPIN", DT_NO_SPIN);

View File

@ -112,12 +112,14 @@ static void loadSounds(void)
sounds[SND_EXPLOSION_2] = loadSound("sound/207322__animationisaac__short-explosion.ogg");
sounds[SND_EXPLOSION_3] = loadSound("sound/254071__tb0y298__firework-explosion.ogg");
sounds[SND_EXPLOSION_4] = loadSound("sound/47252__nthompson__bad-explosion.ogg");
sounds[SND_EXPLOSION_5] = loadSound("sound/172870__escortmarius__carbidexplosion.ogg");
sounds[SND_JUMP] = loadSound("sound/276912__pauldihor__transform.ogg");
sounds[SND_ECM] = loadSound("sound/251431__onlytheghosts__fusion-gun-flash0-by-onlytheghosts.ogg");
sounds[SND_MAG_HIT] = loadSound("sound/172591__timbre__zapitydooda.ogg");
sounds[SND_POWER_DOWN] = loadSound("sound/39030__wildweasel__d1clsstf.ogg");
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_GUI_CLICK] = loadSound("sound/257786__xtrgamr__mouse-click.ogg");
sounds[SND_GUI_SELECT] = loadSound("sound/321104__nsstudios__blip2.ogg");