/** * @brief Gets the outfit's graphic effect. * @param o Outfit to get information from. */ glTexture* outfit_gfx( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.gfx_space; else if (outfit_isBeam(o)) return o->u.bem.gfx; else if (outfit_isAmmo(o)) return o->u.amm.gfx_space; return NULL; }
/** * @brief Gets the outfit's energy usage. * @param o Outfit to get information from. */ double outfit_energy( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.energy; else if (outfit_isBeam(o)) return o->u.bem.energy; else if (outfit_isAmmo(o)) return o->u.amm.energy; return -1.; }
/** * @brief Gets the outfit's range. * @param o Outfit to get information from. */ double outfit_range( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.range; else if (outfit_isBeam(o)) return o->u.bem.range; else if (outfit_isAmmo(o)) return 0.8*o->u.amm.speed*o->u.amm.duration; return -1.; }
/** * @brief Gets the outfit's damage type. * @param o Outfit to get information from. */ DamageType outfit_damageType( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.dtype; else if (outfit_isBeam(o)) return o->u.bem.dtype; else if (outfit_isAmmo(o)) return o->u.amm.dtype; return DAMAGE_TYPE_NULL; }
/** * @brief Gets the outfit's damage. * @param o Outfit to get information from. */ double outfit_damage( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.damage; else if (outfit_isBeam(o)) return o->u.bem.damage; else if (outfit_isAmmo(o)) return o->u.amm.damage; return -1.; }
/** * @brief Gets the outfit's sound effect. * @param o Outfit to get information from. */ int outfit_spfxShield( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.spfx_shield; else if (outfit_isBeam(o)) return o->u.bem.spfx_shield; else if (outfit_isAmmo(o)) return o->u.amm.spfx_shield; return -1; }
/** * @brief Gets the outfit's sound effect. * @param o Outfit to get information from. */ int outfit_spfxArmour( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.spfx_armour; else if (outfit_isBeam(o)) return o->u.bem.spfx_armour; else if (outfit_isAmmo(o)) return o->u.amm.spfx_armour; return -1; }
/** * @brief Creates a new weapon. * * @param outfit Outfit which spawns the weapon. * @param dir Direction of the shooter. * @param pos Position of the shooter. * @param vel Velocity of the shooter. * @param parent Pilot ID of the shooter. * @param target Target ID that is getting shot. */ void weapon_add( const Outfit* outfit, const double dir, const Vector2d* pos, const Vector2d* vel, unsigned int parent, unsigned int target ) { WeaponLayer layer; Weapon *w; Weapon **curLayer; int *mLayer, *nLayer; GLsizei size; if (!outfit_isBolt(outfit) && !outfit_isAmmo(outfit)) { ERR("Trying to create a Weapon from a non-Weapon type Outfit"); return; } layer = (parent==PLAYER_ID) ? WEAPON_LAYER_FG : WEAPON_LAYER_BG; w = weapon_create( outfit, dir, pos, vel, parent, target ); /* set the proper layer */ switch (layer) { case WEAPON_LAYER_BG: curLayer = wbackLayer; nLayer = &nwbackLayer; mLayer = &mwbacklayer; break; case WEAPON_LAYER_FG: curLayer = wfrontLayer; nLayer = &nwfrontLayer; mLayer = &mwfrontLayer; break; default: WARN("Unknown weapon layer!"); } if (*mLayer > *nLayer) /* more memory alloced than needed */ curLayer[(*nLayer)++] = w; else { /* need to allocate more memory */ switch (layer) { case WEAPON_LAYER_BG: (*mLayer) += WEAPON_CHUNK; curLayer = wbackLayer = realloc(curLayer, (*mLayer)*sizeof(Weapon*)); break; case WEAPON_LAYER_FG: (*mLayer) += WEAPON_CHUNK; curLayer = wfrontLayer = realloc(curLayer, (*mLayer)*sizeof(Weapon*)); break; } curLayer[(*nLayer)++] = w; /* Grow the vertex stuff. */ weapon_vboSize = mwfrontLayer + mwbacklayer; size = sizeof(GLfloat) * (2+4) * weapon_vboSize; weapon_vboData = realloc( weapon_vboData, size ); if (weapon_vbo == NULL) weapon_vbo = gl_vboCreateStream( size, NULL ); } }
/** * @brief Gets the outfit's delay. * @param o Outfit to get information from. */ int outfit_delay( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.delay; else if (outfit_isBeam(o)) return o->u.bem.delay; else if (outfit_isLauncher(o)) return o->u.lau.delay; else if (outfit_isFighterBay(o)) return o->u.bay.delay; return -1; }
/** * @brief Dumps the bolt weapon data to csv. */ void dout_csvBolt( const char *path ) { Outfit *o, *o_all; int i, n, l; SDL_RWops *rw; char buf[ 1024 ]; Damage *dmg; /* File to output to. */ rw = SDL_RWFromFile( path, "w" ); if (rw == NULL) { WARN("Unable to open '%s' for writing: %s", path, SDL_GetError()); return; } /* Write "header" */ l = nsnprintf( buf, sizeof(buf), "name,type,slot,license," "mass,price," "delay,speed,range,falloff," "lockon,energy,heatup,cpu," "track,swivel," "penetrate,dtype,damage,disable\n" ); SDL_RWwrite( rw, buf, l, 1 ); o_all = outfit_getAll( &n ); for (i=0; i<n; i++) { o = &o_all[i]; /* Only handle bolt weapons. */ if (!outfit_isBolt(o)) continue; dmg = &o->u.blt.dmg; l = nsnprintf( buf, sizeof(buf), "%s,%s,%s,%s," "%f,%"CREDITS_PRI"," "%f,%f,%f,%f," "%f,%f,%f,%f," "%f,%f," "%f,%s,%f,%f\n", o->name, outfit_getType(o), outfit_slotName(o), o->license, o->mass, o->price, o->u.blt.delay*1000., o->u.blt.speed, o->u.blt.range, o->u.blt.falloff, o->u.blt.ew_lockon, o->u.blt.energy, o->u.blt.heatup, o->u.blt.cpu, o->u.blt.track, o->u.blt.swivel * 180. / M_PI, dmg->penetration*100, dtype_damageTypeToStr(dmg->type), dmg->damage, dmg->disable ); SDL_RWwrite( rw, buf, l, 1 ); } /* Close file. */ SDL_RWclose( rw ); }
/** * @brief Dumps the bolt weapon data to csv. */ void dout_csvBolt( const char *path ) { Outfit *o, *o_all; int i, n, l; SDL_RWops *rw; char buf[ 1024 ]; /* File to output to. */ rw = SDL_RWFromFile( path, "w" ); /* Write "header" */ l = snprintf( buf, sizeof(buf), "name,type,slot,license," "mass,price," "delay,speed,range,falloff," "lockon,energy,heatup,cpu," "track,swivel," "dtype,damage\n" ); SDL_RWwrite( rw, buf, l, 1 ); o_all = outfit_getAll( &n ); for (i=0; i<n; i++) { o = &o_all[i]; /* Only handle bolt weapons. */ if (!outfit_isBolt(o)) continue; l = snprintf( buf, sizeof(buf), "%s,%s,%s,%s," "%f,%"CREDITS_PRI"," "%f,%f,%f,%f," "%f,%f,%f,%f," "%f,%f," "%s,%f\n", o->name, outfit_getType(o), outfit_slotName(o), o->license, o->mass, o->price, o->u.blt.delay*1000., o->u.blt.speed, o->u.blt.range, o->u.blt.falloff, o->u.blt.ew_lockon, o->u.blt.energy, o->u.blt.heatup, o->u.blt.cpu, o->u.blt.track, o->u.blt.swivel * 180. / M_PI, outfit_damageTypeToStr(o->u.blt.dtype), o->u.blt.damage ); SDL_RWwrite( rw, buf, l, 1 ); } /* Close file. */ SDL_RWclose( rw ); }
/** * @brief Gets the outfit's broad type. * * @param o Outfit to get the type of. * @return The outfit's broad type in human readable form. */ const char* outfit_getTypeBroad( const Outfit* o ) { if (outfit_isBolt(o)) return "Bolt Weapon"; else if (outfit_isBeam(o)) return "Beam Weapon"; else if (outfit_isLauncher(o)) return "Launcher"; else if (outfit_isAmmo(o)) return "Ammo"; else if (outfit_isTurret(o)) return "Turret"; else if (outfit_isMod(o)) return "Modification"; else if (outfit_isAfterburner(o)) return "Afterburner"; else if (outfit_isJammer(o)) return "Jammer"; else if (outfit_isFighterBay(o)) return "Fighter Bay"; else if (outfit_isFighter(o)) return "Fighter"; else if (outfit_isMap(o)) return "Map"; else if (outfit_isLicense(o)) return "License"; else return "Unknown"; }
/** * @brief Adds an outfit to a weapon set. * * @param p Pilot to manipulate. * @param id ID of the weapon set. * @param o Outfit to add. * @param level Level of the trigger. */ void pilot_weapSetAdd( Pilot* p, int id, PilotOutfitSlot *o, int level ) { PilotWeaponSet *ws; PilotWeaponSetOutfit *slot; Outfit *oo; int i; ws = pilot_weapSet(p,id); /* Make sure outfit is valid. */ oo = o->outfit; if (oo == NULL) return; /* Make sure outfit type is weapon (or usable). */ if (!(outfit_isBeam(oo) || outfit_isBolt(oo) || outfit_isLauncher(oo) || outfit_isFighterBay(oo))) return; /* Create if needed. */ if (ws->slots == NULL) ws->slots = array_create( PilotWeaponSetOutfit ); /* Check if already there. */ for (i=0; i<array_size(ws->slots); i++) { if (ws->slots[i].slot == o) { ws->slots[i].level = level; /* Update if needed. */ if (id == p->active_set) pilot_weapSetUpdateOutfits( p, ws ); return; } } /* Add it. */ slot = &array_grow( &ws->slots ); slot->level = level; slot->slot = o; /* Update range. */ pilot_weapSetUpdateRange( ws ); /* Update if needed. */ if (id == p->active_set) pilot_weapSetUpdateOutfits( p, ws ); }
/** * @brief Adds an outfit to the pilot, ignoring CPU or other limits. * * @note Does not call pilot_calcStats(). * * @param pilot Pilot to add the outfit to. * @param outfit Outfit to add to the pilot. * @param s Slot to add ammo to. * @return 0 on success. */ int pilot_addOutfitRaw( Pilot* pilot, Outfit* outfit, PilotOutfitSlot *s ) { Outfit *o; /* Set the outfit. */ s->outfit = outfit; /* Set some default parameters. */ s->timer = 0.; /* Some per-case scenarios. */ if (outfit_isFighterBay(outfit)) { s->u.ammo.outfit = NULL; s->u.ammo.quantity = 0; s->u.ammo.deployed = 0; } if (outfit_isTurret(outfit)) /* used to speed up AI */ pilot->nturrets++; else if (outfit_isBolt(outfit)) pilot->ncannons++; else if (outfit_isJammer(outfit)) pilot->njammers++; else if (outfit_isAfterburner(outfit)) pilot->nafterburners++; if (outfit_isBeam(outfit)) { /* Used to speed up some calculations. */ s->u.beamid = 0; pilot->nbeams++; } if (outfit_isLauncher(outfit)) { s->u.ammo.outfit = NULL; s->u.ammo.quantity = 0; s->u.ammo.deployed = 0; /* Just in case. */ } /* Check if active. */ o = s->outfit; s->active = outfit_isActive(o); /* Update heat. */ pilot_heatCalcSlot( s ); return 0; }
static void weapon_explodeLayer( WeaponLayer layer, double x, double y, double radius, unsigned int parent, int mode ) { (void)parent; int i; Weapon **curLayer; int *nLayer; double dist, rad2; /* set the proper layer */ switch (layer) { case WEAPON_LAYER_BG: curLayer = wbackLayer; nLayer = &nwbackLayer; break; case WEAPON_LAYER_FG: curLayer = wfrontLayer; nLayer = &nwfrontLayer; break; default: ERR("Invalid WEAPON_LAYER specified"); return; } rad2 = radius*radius; /* Now try to destroy the weapons affected. */ for (i=0; i<*nLayer; i++) { if (((mode & EXPL_MODE_MISSILE) && outfit_isAmmo(curLayer[i]->outfit)) || ((mode & EXPL_MODE_BOLT) && outfit_isBolt(curLayer[i]->outfit))) { dist = pow2(curLayer[i]->solid->pos.x - x) + pow2(curLayer[i]->solid->pos.y - y); if (dist < rad2) { weapon_destroy(curLayer[i], layer); i--; } } } }
/** * @brief Removes an outfit from the pilot without doing any checks. * * @note Does not run pilot_calcStats(). * * @param pilot Pilot to remove the outfit from. * @param s Slot to remove. * @return 0 on success. */ int pilot_rmOutfitRaw( Pilot* pilot, PilotOutfitSlot *s ) { int ret; /* Decrement counters if necessary. */ if (s->outfit != NULL) { if (outfit_isTurret(s->outfit)) pilot->nturrets--; else if (outfit_isBolt(s->outfit)) pilot->ncannons--; if (outfit_isBeam(s->outfit)) pilot->nbeams--; } /* Remove the outfit. */ ret = (s->outfit==NULL); s->outfit = NULL; /* Remove secondary and such if necessary. */ if (pilot->afterburner == s) pilot->afterburner = NULL; return ret; }
/** * @brief Renders an individual weapon. * * @param w Weapon to render. * @param dt Current delta tick. */ static void weapon_render( Weapon* w, const double dt ) { double x,y, cx,cy, gx,gy; glTexture *gfx; double z; glColour c = { .r=1., .g=1., .b=1. }; switch (w->outfit->type) { /* Weapons that use sprites. */ case OUTFIT_TYPE_AMMO: case OUTFIT_TYPE_TURRET_AMMO: case OUTFIT_TYPE_BOLT: case OUTFIT_TYPE_TURRET_BOLT: gfx = outfit_gfx(w->outfit); /* Alpha based on strength. */ c.a = w->strength; /* Outfit spins around. */ if (outfit_isProp(w->outfit, OUTFIT_PROP_WEAP_SPIN)) { /* Check timer. */ w->anim -= dt; if (w->anim < 0.) { w->anim = outfit_spin(w->outfit); /* Increment sprite. */ w->sprite++; if (w->sprite >= gfx->sx*gfx->sy) w->sprite = 0; } /* Render. */ if (outfit_isBolt(w->outfit) && w->outfit->u.blt.gfx_end) gl_blitSpriteInterpolate( gfx, w->outfit->u.blt.gfx_end, w->timer / w->life, w->solid->pos.x, w->solid->pos.y, w->sprite % (int)gfx->sx, w->sprite / (int)gfx->sx, &c ); else gl_blitSprite( gfx, w->solid->pos.x, w->solid->pos.y, w->sprite % (int)gfx->sx, w->sprite / (int)gfx->sx, &c ); } /* Outfit faces direction. */ else { if (outfit_isBolt(w->outfit) && w->outfit->u.blt.gfx_end) gl_blitSpriteInterpolate( gfx, w->outfit->u.blt.gfx_end, w->timer / w->life, w->solid->pos.x, w->solid->pos.y, w->sx, w->sy, &c ); else gl_blitSprite( gfx, w->solid->pos.x, w->solid->pos.y, w->sx, w->sy, &c ); } break; /* Beam weapons. */ case OUTFIT_TYPE_BEAM: case OUTFIT_TYPE_TURRET_BEAM: gfx = outfit_gfx(w->outfit); /* Zoom. */ gl_cameraZoomGet( &z ); /* Position. */ gl_cameraGet( &cx, &cy ); gui_getOffset( &gx, &gy ); x = (w->solid->pos.x - cx)*z + gx; y = (w->solid->pos.y - cy)*z + gy; /* Set up the matrix. */ glMatrixMode(GL_PROJECTION); glPushMatrix(); glTranslated( x, y, 0. ); glRotated( 270. + w->solid->dir / M_PI * 180., 0., 0., 1. ); /* Preparatives. */ glEnable(GL_TEXTURE_2D); glBindTexture( GL_TEXTURE_2D, gfx->texture); glShadeModel(GL_SMOOTH); /* Actual rendering. */ glBegin(GL_QUAD_STRIP); /* Start faded. */ ACOLOUR(cWhite, 0.); glTexCoord2d( w->anim, 0. ); glVertex2d( -gfx->sh/2.*z, 0. ); glTexCoord2d( w->anim, 1. ); glVertex2d( +gfx->sh/2.*z, 0. ); /* Full strength. */ COLOUR(cWhite); glTexCoord2d( w->anim + 10. / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, 10.*z ); glTexCoord2d( w->anim + 10. / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, 10.*z ); glTexCoord2d( w->anim + 0.8*w->outfit->u.bem.range / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, 0.8*w->outfit->u.bem.range*z ); glTexCoord2d( w->anim + 0.8*w->outfit->u.bem.range / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, 0.8*w->outfit->u.bem.range*z ); /* Fades out. */ ACOLOUR(cWhite, 0.); glTexCoord2d( w->anim + w->outfit->u.bem.range / gfx->sw, 0. ); glVertex2d( -gfx->sh/2.*z, w->outfit->u.bem.range*z ); glTexCoord2d( w->anim + w->outfit->u.bem.range / gfx->sw, 1. ); glVertex2d( +gfx->sh/2.*z, w->outfit->u.bem.range*z ); glEnd(); /* GL_QUAD_STRIP */ /* Do the beam movement. */ w->anim -= 5. * dt; if (w->anim <= -gfx->sw) w->anim += gfx->sw; /* Clean up. */ glDisable(GL_TEXTURE_2D); glShadeModel(GL_FLAT); glPopMatrix(); /* GL_PROJECTION */ gl_checkErr(); break; default: WARN("Weapon of type '%s' has no render implemented yet!", w->outfit->name); break; } } /** * @brief Checks to see if the weapon can hit the pilot. * * @param w Weapon to check if hits pilot. * @param p Pilot to check if is hit by weapon. * @return 1 if can be hit, 0 if can't. */ static int weapon_checkCanHit( Weapon* w, Pilot *p ) { Pilot *parent; /* Can't hit invincible stuff. */ if (pilot_isFlag(p, PILOT_INVINCIBLE)) return 0; /* Can never hit same faction. */ if (p->faction == w->faction) return 0; /* Go "through" dead pilots. */ if (pilot_isFlag(p, PILOT_DEAD)) return 0; /* Player behaves differently. */ if (w->faction == FACTION_PLAYER) { /* Always hit without safety. */ if (!weapon_safety) return 1; /* Always hit target. */ else if (w->target == p->id) return 1; /* Always hit hostiles. */ else if (pilot_isFlag(p, PILOT_HOSTILE)) return 1; /* Always hit unbribed enemies. */ else if (!pilot_isFlag(p, PILOT_BRIBED) && areEnemies(w->faction, p->faction)) return 1; /* Miss rest - can be neutral/ally. */ else return 0; } /* Let hostiles hit player. */ if (p->faction == FACTION_PLAYER) { parent = pilot_get(w->parent); if (parent != NULL) { if (pilot_isFlag(parent, PILOT_BRIBED)) return 0; if (pilot_isFlag(parent, PILOT_HOSTILE)) return 1; } } /* Hit non-allies. */ if (areEnemies(w->faction, p->faction)) return 1; return 0; }
/** * @brief Gets the outfit's animation spin. * @param o Outfit to get information from. */ double outfit_spin( const Outfit* o ) { if (outfit_isBolt(o)) return o->u.blt.spin; else if (outfit_isAmmo(o)) return o->u.amm.spin; return -1.; }
/** * @brief Actually handles the shooting, how often the player.p can shoot and such. * * @param p Pilot that is shooting. * @param w Pilot's outfit to shoot. * @return 0 if nothing was shot and 1 if something was shot. */ static int pilot_shootWeapon( Pilot* p, PilotOutfitSlot* w ) { Vector2d vp, vv; double rate_mod, energy_mod; double energy; /* Make sure weapon has outfit. */ if (w->outfit == NULL) return 0; /* check to see if weapon is ready */ if (w->timer > 0.) return 0; /* Calculate rate modifier. */ pilot_getRateMod( &rate_mod, &energy_mod, p, w->outfit ); /* Get weapon mount position. */ pilot_getMount( p, w, &vp ); vp.x += p->solid->pos.x; vp.y += p->solid->pos.y; /* Modify velocity to take into account the rotation. */ vect_cset( &vv, p->solid->vel.x + vp.x*p->solid->dir_vel, p->solid->vel.y + vp.y*p->solid->dir_vel ); /* * regular bolt weapons */ if (outfit_isBolt(w->outfit)) { /* enough energy? */ if (outfit_energy(w->outfit)*energy_mod > p->energy) return 0; energy = outfit_energy(w->outfit)*energy_mod; p->energy -= energy; pilot_heatAddSlot( p, w ); weapon_add( w->outfit, w->heat_T, p->solid->dir, &vp, &p->solid->vel, p, p->target ); } /* * Beam weapons. */ else if (outfit_isBeam(w->outfit)) { /* Check if enough energy to last a second. */ if (outfit_energy(w->outfit)*energy_mod > p->energy) return 0; /** @todo Handle warmup stage. */ w->state = PILOT_OUTFIT_ON; w->u.beamid = beam_start( w->outfit, p->solid->dir, &vp, &p->solid->vel, p, p->target, w ); } /* * missile launchers * * must be a secondary weapon */ else if (outfit_isLauncher(w->outfit)) { /* Shooter can't be the target - sanity check for the player.p */ if ((w->outfit->u.lau.ammo->u.amm.ai > 0) && (p->id==p->target)) return 0; /* Must have ammo left. */ if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0)) return 0; /* enough energy? */ if (outfit_energy(w->u.ammo.outfit)*energy_mod > p->energy) return 0; energy = outfit_energy(w->u.ammo.outfit)*energy_mod; p->energy -= energy; pilot_heatAddSlot( p, w ); weapon_add( w->outfit, w->heat_T, p->solid->dir, &vp, &p->solid->vel, p, p->target ); w->u.ammo.quantity -= 1; /* we just shot it */ p->mass_outfit -= w->u.ammo.outfit->mass; pilot_updateMass( p ); } /* * Fighter bays. */ else if (outfit_isFighterBay(w->outfit)) { /* Must have ammo left. */ if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0)) return 0; /* Create the escort. */ escort_create( p, w->u.ammo.outfit->u.fig.ship, &vp, &p->solid->vel, p->solid->dir, ESCORT_TYPE_BAY, 1 ); w->u.ammo.quantity -= 1; /* we just shot it */ p->mass_outfit -= w->u.ammo.outfit->mass; w->u.ammo.deployed += 1; /* Mark as deployed. */ pilot_updateMass( p ); } else WARN("Shooting unknown weapon type: %s", w->outfit->name); /* Reset timer. */ w->timer += rate_mod * outfit_delay( w->outfit ); return 1; }
/** * @brief Actually handles the shooting, how often the player.p can shoot and such. * * @param p Pilot that is shooting. * @param w Pilot's outfit to shoot. * @param time Expected flight time. * @return 0 if nothing was shot and 1 if something was shot. */ static int pilot_shootWeapon( Pilot* p, PilotOutfitSlot* w, double time ) { Vector2d vp, vv; double rate_mod, energy_mod; double energy; int j; /* Make sure weapon has outfit. */ if (w->outfit == NULL) return 0; /* Reset beam shut-off if needed. */ if (outfit_isBeam(w->outfit) && w->outfit->u.bem.min_duration) w->stimer = INFINITY; /* check to see if weapon is ready */ if (w->timer > 0.) return 0; /* Calculate rate modifier. */ pilot_getRateMod( &rate_mod, &energy_mod, p, w->outfit ); /* Get weapon mount position. */ pilot_getMount( p, w, &vp ); vp.x += p->solid->pos.x; vp.y += p->solid->pos.y; /* Modify velocity to take into account the rotation. */ vect_cset( &vv, p->solid->vel.x + vp.x*p->solid->dir_vel, p->solid->vel.y + vp.y*p->solid->dir_vel ); /* * regular bolt weapons */ if (outfit_isBolt(w->outfit)) { /* enough energy? */ if (outfit_energy(w->outfit)*energy_mod > p->energy) return 0; energy = outfit_energy(w->outfit)*energy_mod; p->energy -= energy; pilot_heatAddSlot( p, w ); weapon_add( w->outfit, w->heat_T, p->solid->dir, &vp, &p->solid->vel, p, p->target, time ); } /* * Beam weapons. */ else if (outfit_isBeam(w->outfit)) { /* Don't fire if the existing beam hasn't been destroyed yet. */ if (w->u.beamid > 0) return 0; /* Check if enough energy to last a second. */ if (outfit_energy(w->outfit)*energy_mod > p->energy) return 0; /** @todo Handle warmup stage. */ w->state = PILOT_OUTFIT_ON; w->u.beamid = beam_start( w->outfit, p->solid->dir, &vp, &p->solid->vel, p, p->target, w ); w->timer = w->outfit->u.bem.duration; return 1; /* Return early due to custom timer logic. */ } /* * missile launchers * * must be a secondary weapon */ else if (outfit_isLauncher(w->outfit)) { /* Shooter can't be the target - sanity check for the player.p */ if ((w->outfit->u.lau.ammo->u.amm.ai != AMMO_AI_DUMB) && (p->id==p->target)) return 0; /* Must have ammo left. */ if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0)) return 0; /* enough energy? */ if (outfit_energy(w->u.ammo.outfit)*energy_mod > p->energy) return 0; energy = outfit_energy(w->u.ammo.outfit)*energy_mod; p->energy -= energy; pilot_heatAddSlot( p, w ); weapon_add( w->outfit, w->heat_T, p->solid->dir, &vp, &p->solid->vel, p, p->target, time ); w->u.ammo.quantity -= 1; /* we just shot it */ p->mass_outfit -= w->u.ammo.outfit->mass; p->solid->mass -= w->u.ammo.outfit->mass; pilot_updateMass( p ); /* If last ammo was shot, update the range */ if (w->u.ammo.quantity <= 0) { for (j=0; j<PILOT_WEAPON_SETS; j++) pilot_weapSetUpdateRange( &p->weapon_sets[j] ); } } /* * Fighter bays. */ else if (outfit_isFighterBay(w->outfit)) { /* Must have ammo left. */ if ((w->u.ammo.outfit == NULL) || (w->u.ammo.quantity <= 0)) return 0; /* Create the escort. */ escort_create( p, w->u.ammo.outfit->u.fig.ship, &vp, &p->solid->vel, p->solid->dir, ESCORT_TYPE_BAY, 1 ); w->u.ammo.quantity -= 1; /* we just shot it */ p->mass_outfit -= w->u.ammo.outfit->mass; w->u.ammo.deployed += 1; /* Mark as deployed. */ pilot_updateMass( p ); } else WARN(_("Shooting unknown weapon type: %s"), w->outfit->name); /* Reset timer. */ w->timer += rate_mod * outfit_delay( w->outfit ); return 1; }
/** * @brief Tries to automatically set and create the pilot's weapon set. * * Weapon set 0 is for all weapons. <br /> * Weapon set 1 is for forward weapons. Ammo using weapons are secondaries. <br /> * Weapon set 2 is for turret weapons. Ammo using weapons are secondaries. <br /> * Weapon set 3 is for all weapons. Forwards are primaries and turrets are secondaries. <br /> * Weapon set 4 is for seeking weapons. High payload variants are secondaries. <br /> * Weapon set 5 is for fighter bays. <br /> * * @param p Pilot to automagically generate weapon lists. */ void pilot_weaponAuto( Pilot *p ) { PilotOutfitSlot *slot; Outfit *o; int i, level, id; /* Clear weapons. */ pilot_weaponClear( p ); /* Set modes. */ pilot_weapSetMode( p, 0, 0 ); pilot_weapSetMode( p, 1, 0 ); pilot_weapSetMode( p, 2, 0 ); pilot_weapSetMode( p, 3, 0 ); pilot_weapSetMode( p, 4, 1 ); pilot_weapSetMode( p, 5, 1 ); pilot_weapSetMode( p, 6, 0 ); pilot_weapSetMode( p, 7, 0 ); pilot_weapSetMode( p, 8, 0 ); pilot_weapSetMode( p, 9, 0 ); /* Set names. */ pilot_weapSetNameSet( p, 0, "All" ); pilot_weapSetNameSet( p, 1, "Forward" ); pilot_weapSetNameSet( p, 2, "Turret" ); pilot_weapSetNameSet( p, 3, "Fwd/Tur" ); pilot_weapSetNameSet( p, 4, "Seekers" ); pilot_weapSetNameSet( p, 5, "Fighter Bays" ); pilot_weapSetNameSet( p, 6, "Weaponset 7" ); pilot_weapSetNameSet( p, 7, "Weaponset 8" ); pilot_weapSetNameSet( p, 8, "Weaponset 9" ); pilot_weapSetNameSet( p, 9, "Weaponset 0" ); /* Iterate through all the outfits. */ for (i=0; i<p->outfit_nweapon; i++) { slot = &p->outfit_weapon[i]; o = slot->outfit; /* Must have outfit. */ if (o == NULL) { slot->level = -1; /* Clear level. */ continue; } /* Bolts and beams. */ if (outfit_isBolt(o) || outfit_isBeam(o) || (outfit_isLauncher(o) && !outfit_isSeeker(o->u.lau.ammo))) { id = outfit_isTurret(o) ? 2 : 1; level = (outfit_ammo(o) != NULL) ? 1 : 0; } /* Seekers. */ else if (outfit_isLauncher(o) && outfit_isSeeker(o->u.lau.ammo)) { id = 4; level = 1; } /* Fighter bays. */ else if (outfit_isFighterBay(o)) { id = 5; level = 0; } /* Ignore rest. */ else continue; /* Add to it's base group. */ pilot_weapSetAdd( p, id, slot, level ); /* Also add another copy to another group. */ if (id == 1) { /* Forward. */ pilot_weapSetAdd( p, 0, slot, level ); /* Also get added to 'All'. */ pilot_weapSetAdd( p, 3, slot, 0 ); /* Also get added to 'Fwd/Tur'. */ } else if (id == 2) { /* Turrets. */ pilot_weapSetAdd( p, 0, slot, level ); /* Also get added to 'All'. */ pilot_weapSetAdd( p, 3, slot, 1 ); /* Also get added to 'Fwd/Tur'. */ } else if (id == 4) { /* Seekers */ pilot_weapSetAdd( p, 0, slot, level ); /* Also get added to 'All'. */ } } }
/** * @brief Tries to automatically set and create the pilot's weapon set. * * Weapon set 0 is for all weapons. <br /> * Weapon set 1 is for forward weapons. Ammo using weapons are secondaries. <br /> * Weapon set 2 is for turret weapons. Ammo using weapons are secondaries. <br /> * Weapon set 3 is for all weapons. Forwards are primaries and turrets are secondaries. <br /> * Weapon set 4 is for seeking weapons. High payload variants are secondaries. <br /> * Weapon set 5 is for fighter bays. <br /> * * @param p Pilot to automagically generate weapon lists. */ void pilot_weaponAuto( Pilot *p ) { PilotOutfitSlot *slot; Outfit *o; int i, level, id; /* Clear weapons. */ pilot_weaponClear( p ); /* Set modes. */ pilot_weapSetType( p, 0, WEAPSET_TYPE_CHANGE ); pilot_weapSetType( p, 1, WEAPSET_TYPE_CHANGE ); pilot_weapSetType( p, 2, WEAPSET_TYPE_CHANGE ); pilot_weapSetType( p, 3, WEAPSET_TYPE_CHANGE ); pilot_weapSetType( p, 4, WEAPSET_TYPE_WEAPON ); pilot_weapSetType( p, 5, WEAPSET_TYPE_WEAPON ); pilot_weapSetType( p, 6, WEAPSET_TYPE_ACTIVE ); pilot_weapSetType( p, 7, WEAPSET_TYPE_ACTIVE ); pilot_weapSetType( p, 8, WEAPSET_TYPE_ACTIVE ); pilot_weapSetType( p, 9, WEAPSET_TYPE_ACTIVE ); /* All should be inrange. */ if (!pilot_isPlayer(p)) for (i=0; i<PILOT_WEAPON_SETS; i++){ pilot_weapSetInrange( p, i, 1 ); /* Update range and speed (at 0)*/ pilot_weapSetUpdateRange( &p->weapon_sets[i] ); } /* Iterate through all the outfits. */ for (i=0; i<p->noutfits; i++) { slot = p->outfits[i]; o = slot->outfit; /* Must be non-empty, and a weapon or active outfit. */ if ((o == NULL) || !outfit_isActive(o)) { slot->level = -1; /* Clear level. */ slot->weapset = -1; continue; } /* Manually defined group preempts others. */ if (o->group) { id = o->group; } /* Bolts and beams. */ else if (outfit_isBolt(o) || outfit_isBeam(o) || (outfit_isLauncher(o) && !outfit_isSeeker(o->u.lau.ammo))) { id = outfit_isTurret(o) ? 2 : 1; } /* Seekers. */ else if (outfit_isLauncher(o) && outfit_isSeeker(o->u.lau.ammo)) { id = 4; } /* Fighter bays. */ else if (outfit_isFighterBay(o)) { id = 5; } /* Ignore rest. */ else { slot->level = -1; continue; } /* Set level based on secondary flag. */ level = outfit_isSecondary(o); /* Add to its base group. */ pilot_weapSetAdd( p, id, slot, level ); /* Also add another copy to another group. */ if (id == 1) { /* Forward. */ pilot_weapSetAdd( p, 0, slot, level ); /* Also get added to 'All'. */ pilot_weapSetAdd( p, 3, slot, 0 ); /* Also get added to 'Fwd/Tur'. */ } else if (id == 2) { /* Turrets. */ pilot_weapSetAdd( p, 0, slot, level ); /* Also get added to 'All'. */ pilot_weapSetAdd( p, 3, slot, 1 ); /* Also get added to 'Fwd/Tur'. */ } else if (id == 4) /* Seekers */ pilot_weapSetAdd( p, 0, slot, level ); /* Also get added to 'All'. */ } /* Update active weapon set. */ pilot_weapSetUpdateOutfits( p, &p->weapon_sets[ p->active_set ] ); }
/** * @brief Parses and returns Outfit from parent node. * * @param temp Outfit to load into. * @param parent Parent node to parse outfit from. * @return 0 on success. */ static int outfit_parse( Outfit* temp, const xmlNodePtr parent ) { xmlNodePtr cur, node; char *prop; /* Clear data. */ memset( temp, 0, sizeof(Outfit) ); temp->name = xml_nodeProp(parent,"name"); /* already mallocs */ if (temp->name == NULL) WARN("Outfit in "OUTFIT_DATA" has invalid or no name"); node = parent->xmlChildrenNode; do { /* load all the data */ if (xml_isNode(node,"general")) { cur = node->children; do { xmlr_int(cur,"max",temp->max); xmlr_int(cur,"tech",temp->tech); xmlr_strd(cur,"license",temp->license); xmlr_int(cur,"mass",temp->mass); xmlr_int(cur,"price",temp->price); xmlr_strd(cur,"description",temp->description); if (xml_isNode(cur,"gfx_store")) { temp->gfx_store = xml_parseTexture( cur, OUTFIT_GFX"store/%s.png", 1, 1, 0 ); } } while (xml_nextNode(cur)); } else if (xml_isNode(node,"specific")) { /* has to be processed seperately */ /* get the type */ prop = xml_nodeProp(node,"type"); if (prop == NULL) ERR("Outfit '%s' element 'specific' missing property 'type'",temp->name); temp->type = outfit_strToOutfitType(prop); free(prop); /* is secondary weapon? */ prop = xml_nodeProp(node,"secondary"); if (prop != NULL) { if ((int)atoi(prop)) outfit_setProp(temp, OUTFIT_PROP_WEAP_SECONDARY); free(prop); } if (temp->type==OUTFIT_TYPE_NULL) WARN("Outfit '%s' is of type NONE", temp->name); else if (outfit_isBolt(temp)) outfit_parseSBolt( temp, node ); else if (outfit_isBeam(temp)) outfit_parseSBeam( temp, node ); else if (outfit_isLauncher(temp)) outfit_parseSLauncher( temp, node ); else if (outfit_isAmmo(temp)) outfit_parseSAmmo( temp, node ); else if (outfit_isMod(temp)) outfit_parseSMod( temp, node ); else if (outfit_isAfterburner(temp)) outfit_parseSAfterburner( temp, node ); else if (outfit_isJammer(temp)) outfit_parseSJammer( temp, node ); else if (outfit_isFighterBay(temp)) outfit_parseSFighterBay( temp, node ); else if (outfit_isFighter(temp)) outfit_parseSFighter( temp, node ); else if (outfit_isMap(temp)) outfit_parseSMap( temp, node ); else if (outfit_isLicense(temp)) outfit_parseSLicense( temp, node ); } } while (xml_nextNode(node)); #define MELEMENT(o,s) \ if (o) WARN("Outfit '%s' missing/invalid '"s"' element", temp->name) /**< Define to help check for data errors. */ MELEMENT(temp->name==NULL,"name"); MELEMENT(temp->max==0,"max"); MELEMENT(temp->tech==0,"tech"); MELEMENT(temp->gfx_store==NULL,"gfx_store"); /*MELEMENT(temp->mass==0,"mass"); Not really needed */ MELEMENT(temp->type==0,"type"); MELEMENT(temp->price==0,"price"); MELEMENT(temp->description==NULL,"description"); #undef MELEMENT return 0; }