[Add] Afterburners are in! After buying the outfit, double tap 'w'.

This commit is contained in:
Allanis 2013-03-19 22:34:20 +00:00
parent 4abe914310
commit 0d6ac1e5b1
15 changed files with 205 additions and 60 deletions

View File

@ -245,5 +245,39 @@
<energy>-10</energy>
</specific>
</outfit>
<outfit name="Generic Afterburner">
<general>
<max>1</max>
<tech>3</tech>
<mass>2</mass>
<price>20000</price>
<description>Being able to run from your enemies is a very powerful ability. A generic afterburner will allow you to do that. It may not be as powerful as some of the more high-end afterburners, but ther're not nearly as affordable as a generic one.</description>
<gfx_store>afterburner</gfx_store>
</general>
<specific type="16">
<thrust_perc>50</thrust_perc>
<thrust_abs>30</thrust_abs>
<speed_perc>50</speed_perc>
<speed_abs>30</speed_abs>
<energy>60</energy>
</specific>
</outfit>
<outfit name="Hellburner">
<general>
<max>1</max>
<tech>13</tech>
<mass>1</mass>
<price>95000</price>
<description>The Hellburner is one of the best afterburners available in the market. They have a much better energy to speed ratio then the generics and are much stronger. A must for any spacefarer whose proud of thier ship.</description>
<gfx_store>afterburner</gfx_store>
</general>
<specific type="16">
<thrust_perc>85</thrust_perc>
<thrust_abs>50</thrust_abs>
<speed_perc>85</speed_perc>
<speed_abs>50</speed_abs>
<energy>65</energy>
</specific>
</outfit>
</Outfits>

View File

@ -556,12 +556,15 @@ static int ai_getpos(lua_State* L) {
// ==> 180.*360./cur_pilot->turn
// Add it to general euler equation x = v*t + 0.5 * a * t^2
// Have fun.
//
// I really hate this function. Why isn't it depricated yet?
// ========================================================
static int ai_minbrakedist(lua_State* L) {
double time = VMOD(cur_pilot->solid->vel) /
double time, dist;
time = VMOD(cur_pilot->solid->vel) /
(cur_pilot->thrust / cur_pilot->solid->mass);
double dist = VMOD(cur_pilot->solid->vel)*(time + 180./cur_pilot->turn)-
dist = VMOD(cur_pilot->solid->vel)*0.9*(time+180./cur_pilot->turn) -
0.5 * (cur_pilot->thrust / cur_pilot->solid->mass)*time*time;
lua_pushnumber(L, dist); // return

View File

@ -44,12 +44,15 @@ if(lua_isstring(L, -1)) { \
}
// Some crap from main.
extern int nosound;
extern int show_fps;
extern int max_fps;
extern int indjoystick;
extern char* namjoystick;
// From player.c
extern const char* keybindNames[]; // Keybindings.
// input.c.
extern unsigned int input_afterburnSensibility;
static void print_usage(char** argv);
@ -115,6 +118,9 @@ int conf_loadConfig(const char* file) {
conf_loadBool("showfps", show_fps);
conf_loadInt("maxfps", max_fps);
// Input.
conf_loadInt("afterburn", input_afterburnSensibility);
// Sound.
conf_loadFloat("sound", d);
if(d) { sound_volume(d); d = 0.; }

View File

@ -23,14 +23,18 @@ static Keybind** input_keybinds; // Contains the players keybindings.
// Name of each keybinding.
const char* keybindNames[] =
{ "accel", "left", "right", "reverse", // Movement.
const char* keybindNames[] = {
"accel", "left", "right", "reverse", // Movement.
"primary", "target", "target_nearest", "face", "board", // Combat.
"secondary", "secondary_next", // Secondary weapons.
"target_planet", "land", "thyperspace","starmap", "jump", // Navigation.
"mapzoomin", "mapzoomout", "screenshot", "pause", "menu", "info", // Misc.
"end" }; // Must terminate at the end.
// Accel hacks.
static unsigned int input_accelLast = 0; // Used to see if double tap.
int input_afterburnSensibility = 500; // ms between taps to afterburn.
// From player.c
extern double player_turn;
extern double player_acc;
@ -46,7 +50,6 @@ void input_setDefault(void) {
input_setKeybind("left", KEYBIND_KEYBOARD, SDLK_a, 0);
input_setKeybind("right", KEYBIND_KEYBOARD, SDLK_d, 0);
input_setKeybind("reverse", KEYBIND_KEYBOARD, SDLK_s, 0);
// Combat.
input_setKeybind("primary", KEYBIND_KEYBOARD, SDLK_SPACE, 0);
input_setKeybind("target", KEYBIND_KEYBOARD, SDLK_TAB, 0);
@ -123,11 +126,23 @@ void input_setKeybind(char* keybind, KeybindType type, int key, int reverse) {
!pilot_isFlag(player, PILOT_HYP_BEGIN) && \
!pilot_isFlag(player, PILOT_HYPERSPACE))
static void input_key(int keynum, double value, int abs) {
unsigned int t;
// Accelerating.
if(KEY("accel")) {
if(abs)player_acc = value;
else player_acc += value;
// Double tap accel = afterburn!
t = SDL_GetTicks();
if((value == KEY_PRESS) && (t-input_accelLast <= input_afterburnSensibility)) {
player_afterburn();
}
else if((value == KEY_RELEASE) && player_isFlag(PLAYER_AFTERBURNER))
player_afterburnOver();
else
player_acc = ABS(player_acc); // Make sure value is sane.
if(value == KEY_PRESS) input_accelLast = t;
}
// Turning left.
else if(KEY("left")) {

View File

@ -295,7 +295,11 @@ static void outfits_buy(char* str) {
toolkit_alert("You can only carry %d of this outfit.", outfit->max);
return;
}
// Not enough.
else if(outfit_isAfterburner(outfit) && (player->afterburner != NULL)) {
toolkit_alert("You can only have one afterburner.");
return;
}
// Not enough $$.
else if(q*(int)outfit->price >= player_credits) {
credits2str(buf, q*outfit->price - player_credits, 2);
toolkit_alert("You need %s more SCred.", buf);

View File

@ -29,6 +29,7 @@ static void outfit_parseSWeapon(Outfit* tmp, const xmlNodePtr parent);
static void outfit_parseSLauncher(Outfit* tmp, const xmlNodePtr parent);
static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent);
static void outfit_parseSMod(Outfit* tmp, const xmlNodePtr parent);
static void outfit_parseSAfterburner(Outfit* tmp, const xmlNodePtr parent);
// Return an outfit.
Outfit* outfit_get(const char* name) {
@ -95,6 +96,11 @@ int outfit_isMod(const Outfit* o) {
return (o->type == OUTFIT_TYPE_MODIFICATION);
}
// Return 1 if o is an afterburner.
int outfit_isAfterburner(const Outfit* o) {
return (o->type == OUTFIT_TYPE_AFTERBURNER);
}
// Get the outfit graphics.
glTexture* outfit_gfx(const Outfit* o) {
if(outfit_isWeapon(o)) return o->u.blt.gfx_space;
@ -155,7 +161,8 @@ const char* outfit_typename[] = {
"Smart Swarm Missile Ammunition Pack",
"Bolt Turret",
"Beam Turret",
"Modification"
"Ship Modification",
"Afterburner"
};
const char* outfit_getType(const Outfit* o) {
@ -169,7 +176,8 @@ const char* outfit_typenamebroad[] = {
"Launcher",
"Ammo",
"Turret",
"Modification"
"Modification",
"Afterburner"
};
const char* outfit_getTypeBroad(const Outfit* o) {
@ -179,6 +187,7 @@ const char* outfit_getTypeBroad(const Outfit* o) {
else if(outfit_isAmmo(o)) i = 3;
else if(outfit_isTurret(o)) i = 4;
else if(outfit_isMod(o)) i = 5;
else if(outfit_isAfterburner(o)) i = 6;
return outfit_typenamebroad[i];
}
@ -295,7 +304,7 @@ static void outfit_parseSAmmo(Outfit* tmp, const xmlNodePtr parent) {
static void outfit_parseSMod(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node;
node = parent->xmlChildrenNode;
node = parent->children;
// Load all the data.
do {
@ -324,6 +333,29 @@ static void outfit_parseSMod(Outfit* tmp, const xmlNodePtr parent) {
} while((node = node->next));
}
// Parses the afterburner tidbits of the outfit.
static void outfit_parseSAfterburner(Outfit* tmp, const xmlNodePtr parent) {
xmlNodePtr node;
node = parent->children;
// Must be >= 1.
tmp->u.afb.thrust_perc = 1.;
tmp->u.afb.speed_perc = 1.;
do {
if(xml_isNode(node, "thrust_perc"))
tmp->u.afb.thrust_perc = 1. + xml_getFloat(node)/100.;
else if(xml_isNode(node, "thrust_abs"))
tmp->u.afb.thrust_abs = xml_getFloat(node);
else if(xml_isNode(node, "speed_perc"))
tmp->u.afb.speed_perc = 1. + xml_getFloat(node)/100.;
else if(xml_isNode(node, "speed_abs"))
tmp->u.afb.speed_abs = xml_getFloat(node);
else if(xml_isNode(node, "energy"))
tmp->u.afb.energy = xml_getFloat(node);
} while((node = node->next));
}
// Parse and return Outfits from parent node.
static Outfit* outfit_parse(const xmlNodePtr parent) {
Outfit* tmp = CALLOC_L(Outfit);
@ -381,6 +413,8 @@ static Outfit* outfit_parse(const xmlNodePtr parent) {
outfit_parseSWeapon(tmp, node);
else if(outfit_isMod(tmp))
outfit_parseSMod(tmp, node);
else if(outfit_isAfterburner(tmp))
outfit_parseSAfterburner(tmp, node);
}
} while((node = node->next));
#define MELEMENT(o,s) if(o) WARN("Outfit '%s' missing '"s"' element", tmp->name)

View File

@ -23,7 +23,8 @@ typedef enum OutfitType_ {
OUTFIT_TYPE_MISSILE_SWARM_SMART_AMMO = 12,
OUTFIT_TYPE_TURRET_BOLT = 13,
OUTFIT_TYPE_TURRET_BEAM = 14,
OUTFIT_TYPE_MODIFICATION = 15
OUTFIT_TYPE_MODIFICATION = 15,
OUTFIT_TYPE_AFTERBURNER = 16
} OutfitType;
// An outfit depends a lot on the type.
@ -90,6 +91,11 @@ typedef struct Outfit_ {
double shield, shield_regen;
double energy, energy_regen;
} mod;
struct { // Afterburner.
double thrust_perc, thrust_abs; // Percent and absolute thrust bonus.
double speed_perc, speed_abs; // Percent and absolute speed bonus.
double energy; // Energy used while active.
} afb;
} u;
} Outfit;
@ -102,6 +108,7 @@ int outfit_isLauncher(const Outfit* o);
int outfit_isAmmo(const Outfit* o);
int outfit_isTurret(const Outfit* o);
int outfit_isMod(const Outfit* o);
int outfit_isAfterburner(const Outfit* o);
const char* outfit_getType(const Outfit* o);
const char* outfit_getTypeBroad(const Outfit* o);

View File

@ -14,14 +14,8 @@ double angle_diff(const double ref, double a) {
return (d <= M_PI) ? d : d - 2*M_PI;
}
void limit_speed(Vec2* vel, const double speed) {
if(VMOD(*vel) > speed) // Should not go faster.
vect_pset(vel, speed, VANGLE(*vel));
}
void limit_speeddt(Vec2* vel, const double speed, const double dt) {
double vmod;
vmod = VMOD(*vel);
void limit_speed(Vec2* vel, const double speed, const double dt) {
double vmod = VMOD(*vel);
if(vmod > speed) // Should not go faster.
vect_pset(vel, (vmod-speed)*(1.-dt*3.) + speed, VANGLE(*vel));
}

View File

@ -22,8 +22,7 @@ typedef struct Vec2_ {
// Misc
double angle_diff(const double ref, double a);
void limit_speed(Vec2* vel, const double speed);
void limit_speeddt(Vec2* vel, const double speed, const double dt);
void limit_speed(Vec2* vel, const double speed, const double dt);
// Vector manupulation.
void vect_cset(Vec2* v, const double x, const double y);

View File

@ -375,9 +375,16 @@ static void pilot_update(Pilot* pilot, const double dt) {
gl_getSpriteFromDir(&pilot->tsx, &pilot->tsy,
pilot->ship->gfx_space, pilot->solid->dir);
if(!pilot_isFlag(pilot, PILOT_HYPERSPACE))
// Should not go faster.
limit_speeddt(&pilot->solid->vel, pilot->speed, dt);
if(!pilot_isFlag(pilot, PILOT_HYPERSPACE)) { // Limit the speed.
if(pilot_isFlag(pilot, PILOT_AFTERBURNER) && // Must have enough energy.
(player->energy > pilot->afterburner->outfit->u.afb.energy * dt)) {
limit_speed(&pilot->solid->vel,
pilot->speed * pilot->afterburner->outfit->u.afb.speed_perc +
pilot->afterburner->outfit->u.afb.speed_abs, dt);
pilot->energy -= pilot->afterburner->outfit->u.afb.energy * dt;
} else
limit_speed(&pilot->solid->vel, pilot->speed, dt);
}
}
// Pilot is getting ready or is in, hyperspace.
@ -482,6 +489,9 @@ int pilot_rmOutfit(Pilot* pilot, Outfit* outfit, int quantity) {
q += pilot->outfits[i].quantity;
// Hack in case it reallocs - Can happen even when shrinking.
s = (pilot->secondary) ? pilot->secondary->outfit->name : NULL;
// Clear it if it's the afterburner.
if(&pilot->outfits[i] == pilot->afterburner)
pilot->afterburner = NULL;
// Remove the outfit.
memmove(pilot->outfits+i, pilot->outfits+i+1,
@ -524,7 +534,7 @@ static void pilot_calcStats(Pilot* pilot) {
pilot->energy_regen = pilot->ship->energy_regen;
// Now add outfit changes.
for(i = 0; i < pilot->noutfits; i++)
for(i = 0; i < pilot->noutfits; i++) {
if(outfit_isMod(pilot->outfits[i].outfit)) {
q = (double) pilot->outfits[i].quantity;
o = pilot->outfits[i].outfit;
@ -542,6 +552,11 @@ static void pilot_calcStats(Pilot* pilot) {
pilot->energy_regen += o->u.mod.energy_regen * q;
}
else if(outfit_isAfterburner(pilot->outfits[i].outfit)) {
// Set the afterburner.
pilot->afterburner = &pilot->outfits[i];
}
}
// Give the pilot her health proportion back.
pilot->armour = ac * pilot->armour_max;
@ -641,6 +656,7 @@ void pilot_init(Pilot* pilot, Ship* ship, char* name, Faction* faction,
pilot->outfits = NULL;
pilot->secondary = NULL;
pilot->ammo = NULL;
pilot->afterburner = NULL;
ShipOutfit* so;
if(ship->outfit) {
pilot->noutfits = 0;

View File

@ -30,6 +30,7 @@
// Dynamic.
#define PILOT_HOSTILE (1<<1) // Pilot is hostile to the player.
#define PILOT_COMBAT (1<<2) // Pilot is engaged in combat.
#define PILOT_AFTERBURNER (1<<3) // Pilot has her afterburner activated.
#define PILOT_HYP_PREP (1<<5) // Pilot is getting ready for hyperspace.
#define PILOT_HYP_BEGIN (1<<6) // Pilot is starting engines.
#define PILOT_HYPERSPACE (1<<7) // Pilot is in hyperspace.
@ -83,6 +84,7 @@ typedef struct Pilot_ {
int noutfits;
PilotOutfit* secondary; // Secondary weapon.
PilotOutfit* ammo; // Secondary ammo (if needed).
PilotOutfit* afterburner; // Ze afterburner.
// Cargo.
int credits; // Moniez the pilot has.

View File

@ -907,6 +907,11 @@ void player_think(Pilot* player) {
if(player_isFlag(PLAYER_SECONDARY)) // Needs a target.
pilot_shoot(player, player_target, 1);
if(player_isFlag(PLAYER_AFTERBURNER))
vect_pset(&player->solid->force,
player->thrust * player->afterburner->outfit->u.afb.thrust_perc +
player->afterburner->outfit->u.afb.thrust_abs, player->solid->dir);
else
vect_pset(&player->solid->force, player->thrust * player_acc,
player->solid->dir);
@ -1055,8 +1060,8 @@ void player_brokeHyperspace(void) {
space_init(systems_stack[cur_system->jumps[hyperspace_target]].name);
// Set position, pilot_update will handle the lowering of velocity.
player_warp(-cos(player->solid->dir) * MIN_HYPERSPACE_DIST * 1.5,
-sin(player->solid->dir) * MIN_HYPERSPACE_DIST * 1.5);
player_warp(-cos(player->solid->dir) * MIN_HYPERSPACE_DIST * 2.5,
-sin(player->solid->dir) * MIN_HYPERSPACE_DIST * 2.5);
// Stop hyperspace.
pilot_rmFlag(player, PILOT_HYPERSPACE | PILOT_HYP_BEGIN | PILOT_HYP_PREP);
@ -1075,6 +1080,22 @@ double player_faceHyperspace(void) {
return pilot_face(player, a);
}
// Activate afterburner.
void player_afterburn(void) {
// TODO: Fancy effects.
if(player->afterburner != NULL) {
player_setFlag(PLAYER_AFTERBURNER);
pilot_setFlag(player, PILOT_AFTERBURNER);
}
}
void player_afterburnOver(void) {
if(player->afterburner != NULL) {
player_rmFlag(PLAYER_AFTERBURNER);
pilot_rmFlag(player, PILOT_AFTERBURNER);
}
}
// Take a screenshot.
static int screenshot_cur = 0;
void player_screenshot(void) {

View File

@ -5,6 +5,7 @@
#define PLAYER_TURN_LEFT (1<<0) // Player is turning left.
#define PLAYER_TURN_RIGHT (1<<1) // Player is turning right.
#define PLAYER_REVERSE (1<<2) // Player is facint opposite vel.
#define PLAYER_AFTERBURNER (1<<3) // Player is burning it up.
#define PLAYER_FACE (1<<10) // Player is facing target.
#define PLAYER_PRIMARY (1<<11) // Player is shooting primary weapon.
#define PLAYER_SECONDARY (1<<12) // Player is shooting secondary weapon.
@ -52,4 +53,6 @@ void player_land(void);
void player_targetHyperspace(void);
void player_jump(void);
void player_screenshot(void);
void player_afterburn(void);
void player_afterburnOver(void);

View File

@ -226,25 +226,29 @@ void space_update(const double dt) {
// Crate a fleet.
static void space_addFleet(Fleet* fleet) {
int i;
Vec2 v, vn;
double a;
Vec2 vv, vp, vn;
// Simulate them coming from hyperspace.
vect_pset(&v, 2*RNG(MIN_HYPERSPACE_DIST/2, MIN_HYPERSPACE_DIST),
vect_pset(&vp, RNG(MIN_HYPERSPACE_DIST, MIN_HYPERSPACE_DIST*1.5),
RNG(0, 360)*M_PI/180.);
vectnull(&vn);
for(i = 0; i < fleet->npilots; i++)
if(RNG(0, 100) <= fleet->pilots[i].chance) {
vect_cadd(&v, RNG(75, 150) * (RNG(0,1) ? 1 : -1),
vect_cadd(&vp, RNG(75, 150) * (RNG(0,1) ? 1 : -1),
RNG(75, 150) * (RNG(0,1) ? 1 : -1));
a = vect_angle(&vp, &vn);
vectnull(&vv);
pilot_create(fleet->pilots[i].ship,
fleet->pilots[i].name,
fleet->faction,
fleet->ai,
vect_angle(&v, &vn),
&v,
NULL,
a,
&vp,
&vv,
0);
}
}

View File

@ -37,7 +37,7 @@ typedef struct Weapon_ {
// Update position and render.
void(*update)(struct Weapon_*, const double, WeaponLayer); // Position update and render.
void(*think)(struct Weapon_*); // Some missiles need to be inteligent.
void(*think)(struct Weapon_*, const double); // Some missiles need to be inteligent.
} Weapon;
// Behind Pilot layer.
@ -60,7 +60,8 @@ static void weapon_hit(Weapon* w, Pilot* p, WeaponLayer layer);
static void weapon_destroy(Weapon* w, WeaponLayer layer);
static void weapon_free(Weapon* w);
// Think.
static void think_seeker(Weapon* w);
static void think_seeker(Weapon* w, const double dt);
static void think_smart(Weapon* w, const double dt);
// Draw the minimap weapons (player.c).
#define PIXEL(x,y) if((shape == RADAR_RECT && ABS(x) < w/2. && ABS(y)<h/2.) || \
@ -115,13 +116,13 @@ void weapons_delay(unsigned int delay) {
}
// Seeker brain, You get what you pay for. :)
static void think_seeker(Weapon* w) {
static void think_seeker(Weapon* w, const double dt) {
double diff;
if(w->target == w->parent) return; // HEY! Self harm is not allowed.
Pilot* p = pilot_get(w->target);
if(p == NULL) {
limit_speed(&w->solid->vel, w->outfit->u.amm.speed);
limit_speed(&w->solid->vel, w->outfit->u.amm.speed, dt);
return;
}
@ -138,11 +139,11 @@ static void think_seeker(Weapon* w) {
vect_pset(&w->solid->force, w->outfit->u.amm.thrust, w->solid->dir);
limit_speed(&w->solid->vel, w->outfit->u.amm.speed);
limit_speed(&w->solid->vel, w->outfit->u.amm.speed, dt);
}
// Smart seeker brain. Much better at homing.
static void think_smart(Weapon* w) {
static void think_smart(Weapon* w, const double dt) {
double diff;
Vec2 tv, sv;
@ -151,7 +152,7 @@ static void think_smart(Weapon* w) {
Pilot* p = pilot_get(w->target); // No null pilots..
if(p == NULL) {
limit_speed(&w->solid->vel, w->outfit->u.amm.speed);
limit_speed(&w->solid->vel, w->outfit->u.amm.speed, dt);
return;
}
@ -170,7 +171,7 @@ static void think_smart(Weapon* w) {
vect_pset(&w->solid->force, w->outfit->u.amm.thrust, w->solid->dir);
limit_speed(&w->solid->vel, w->outfit->u.amm.speed);
limit_speed(&w->solid->vel, w->outfit->u.amm.speed, dt);
}
@ -290,7 +291,9 @@ static void weapon_update(Weapon* w, const double dt, WeaponLayer layer) {
return;
}
}
if(weapon_isSmart(w)) (*w->think)(w);
if(weapon_isSmart(w)) (*w->think)(w,dt);
(*w->solid->update)(w->solid, dt);
// Update the sound.