/** * @brief Calculates how much cargo ship has left and such. * * @param pilot Pilot to calculate free cargo space of. */ void pilot_cargoCalc( Pilot* pilot ) { pilot->mass_cargo = pilot_cargoUsed( pilot ); pilot->cargo_free = pilot->cap_cargo - pilot->mass_cargo; pilot->solid->mass = pilot->ship->mass + pilot->stats.cargo_inertia * pilot->mass_cargo + pilot->mass_outfit; pilot_updateMass( pilot ); }
/** * @brief Removes some ammo from the pilot stock. * * @param pilot Pilot to remove ammo from. * @param s Slot to remove ammo from. * @param quantity Amount to remove. * @return Amount actually removed. */ int pilot_rmAmmo( Pilot* pilot, PilotOutfitSlot *s, int quantity ) { (void) pilot; int q; /* Failure cases. */ if (s->outfit == NULL) { WARN("Pilot '%s': Trying to remove ammo from unequiped slot.", pilot->name ); return 0; } else if (!outfit_isLauncher(s->outfit) && !outfit_isFighterBay(s->outfit)) { WARN("Pilot '%s': Trying to remove ammo from non-launcher/fighter bay type outfit '%s'", pilot->name, s->outfit->name); return 0; } /* No ammo already. */ if (s->u.ammo.outfit == NULL) return 0; /* Remove ammo. */ q = MIN( quantity, s->u.ammo.quantity ); s->u.ammo.quantity -= q; pilot->mass_outfit -= q * s->u.ammo.outfit->mass; pilot_updateMass( pilot ); /* We don't set the outfit to null so it "remembers" old ammo. */ return q; }
/** * @brief Adds cargo without checking the pilot's free space. * * Does not check if currently exists. * * @param pilot Pilot to add cargo to. * @param cargo Cargo to add. * @param quantity Quantity to add. * @param id Mission ID to add (0 is none). */ int pilot_cargoAddRaw( Pilot* pilot, Commodity* cargo, int quantity, unsigned int id ) { int i, q; q = quantity; /* If not mission cargo check to see if already exists. */ if (id == 0) { for (i=0; i<pilot->ncommodities; i++) if (!pilot->commodities[i].id && (pilot->commodities[i].commodity == cargo)) { /* Tweak results. */ pilot->commodities[i].quantity += q; pilot->cargo_free -= q; pilot->mass_cargo += q; pilot->solid->mass += pilot->stats.cargo_inertia * q; pilot_updateMass( pilot ); gui_setGeneric( pilot ); return q; } } /* Create the memory space. */ pilot->commodities = realloc( pilot->commodities, sizeof(PilotCommodity) * (pilot->ncommodities+1)); pilot->commodities[ pilot->ncommodities ].commodity = cargo; /* Set parameters. */ pilot->commodities[ pilot->ncommodities ].id = id; pilot->commodities[ pilot->ncommodities ].quantity = q; /* Tweak pilot. */ pilot->cargo_free -= q; pilot->mass_cargo += q; pilot->solid->mass += pilot->stats.cargo_inertia * q; pilot->ncommodities++; pilot_updateMass( pilot ); gui_setGeneric( pilot ); return q; }
/** * @brief Adds some ammo to the pilot stock. * * @param pilot Pilot to add ammo to. * @param s Slot to add ammo to. * @param ammo Ammo to add. * @param quantity Amount to add. * @return Amount actually added. */ int pilot_addAmmo( Pilot* pilot, PilotOutfitSlot *s, Outfit* ammo, int quantity ) { int q, max; (void) pilot; /* Failure cases. */ if (s->outfit == NULL) { WARN("Pilot '%s': Trying to add ammo to unequiped slot.", pilot->name ); return 0; } else if (!outfit_isLauncher(s->outfit) && !outfit_isFighterBay(s->outfit)) { WARN("Pilot '%s': Trying to add ammo to non-launcher/fighterbay type outfit '%s'", pilot->name, s->outfit->name); return 0; } else if (!outfit_isAmmo(ammo) && !outfit_isFighter(ammo)) { WARN( "Pilot '%s': Trying to add non-ammo/fighter type outfit '%s' as ammo.", pilot->name, ammo->name ); return 0; } else if (outfit_isLauncher(s->outfit) && outfit_isFighter(ammo)) { WARN("Pilot '%s': Trying to add fighter '%s' as launcher '%s' ammo", pilot->name, ammo->name, s->outfit->name ); return 0; } else if (outfit_isFighterBay(s->outfit) && outfit_isAmmo(ammo)) { WARN("Pilot '%s': Trying to add ammo '%s' as fighter bay '%s' ammo", pilot->name, ammo->name, s->outfit->name ); return 0; } else if ((s->u.ammo.outfit != NULL) && (s->u.ammo.quantity > 0) && (s->u.ammo.outfit != ammo)) { WARN("Pilot '%s': Trying to add ammo to outfit that already has ammo.", pilot->name ); return 0; } /* Set the ammo type. */ s->u.ammo.outfit = ammo; /* Add the ammo. */ max = outfit_amount(s->outfit) - s->u.ammo.deployed; q = s->u.ammo.quantity; /* Amount have. */ s->u.ammo.quantity += quantity; s->u.ammo.quantity = MIN( max, s->u.ammo.quantity ); q = s->u.ammo.quantity - q; /* Amount actually added. */ pilot->mass_outfit += q * s->u.ammo.outfit->mass; pilot_updateMass( pilot ); return q; }
/** * @brief Tries to get rid of quantity cargo from pilot. Can remove mission cargo. * * @param pilot Pilot to get rid of cargo. * @param cargo Cargo to get rid of. * @param quantity Amount of cargo to get rid of. * @param cleanup Whether we're cleaning up or not (removes mission cargo). * @return Amount of cargo gotten rid of. */ int pilot_cargoRmRaw( Pilot* pilot, Commodity* cargo, int quantity, int cleanup ) { int i; int q; /* check if pilot has it */ q = quantity; for (i=0; i<pilot->ncommodities; i++) { if (pilot->commodities[i].commodity != cargo) continue; /* Must not be mission cargo unless cleaning up. */ if (!cleanup && (pilot->commodities[i].id != 0)) continue; if (quantity >= pilot->commodities[i].quantity) { q = pilot->commodities[i].quantity; /* remove cargo */ pilot->ncommodities--; if (pilot->ncommodities <= 0) { if (pilot->commodities != NULL) { free( pilot->commodities ); pilot->commodities = NULL; } pilot->ncommodities = 0; } else { memmove( &pilot->commodities[i], &pilot->commodities[i+1], sizeof(PilotCommodity) * (pilot->ncommodities-i) ); pilot->commodities = realloc( pilot->commodities, sizeof(PilotCommodity) * pilot->ncommodities ); } } else pilot->commodities[i].quantity -= q; pilot->cargo_free += q; pilot->mass_cargo -= q; pilot->solid->mass -= pilot->stats.cargo_inertia * q; pilot_updateMass( pilot ); gui_setGeneric( pilot ); return q; } return 0; /* pilot didn't have it */ }
/** * @brief Removes special mission cargo based on id. * * @param pilot Pilot to remove cargo from. * @param cargo_id ID of the cargo to remove. * @param jettison Should jettison the cargo? * @return 0 on success (cargo removed). */ int pilot_rmMissionCargo( Pilot* pilot, unsigned int cargo_id, int jettison ) { int i; /* check if pilot has it */ for (i=0; i<pilot->ncommodities; i++) if (pilot->commodities[i].id == cargo_id) break; if (i>=pilot->ncommodities) return 1; /* pilot doesn't have it */ if (jettison) commodity_Jettison( pilot->id, pilot->commodities[i].commodity, pilot->commodities[i].quantity ); /* remove cargo */ pilot->cargo_free += pilot->commodities[i].quantity; pilot->mass_cargo -= pilot->commodities[i].quantity; pilot->solid->mass -= pilot->stats.cargo_inertia * pilot->commodities[i].quantity; pilot->ncommodities--; if (pilot->ncommodities <= 0) { if (pilot->commodities != NULL) { free( pilot->commodities ); pilot->commodities = NULL; } pilot->ncommodities = 0; } else { memmove( &pilot->commodities[i], &pilot->commodities[i+1], sizeof(PilotCommodity) * (pilot->ncommodities-i) ); pilot->commodities = realloc( pilot->commodities, sizeof(PilotCommodity) * pilot->ncommodities ); } /* Update mass. */ pilot_updateMass( pilot ); gui_setGeneric( pilot ); return 0; }
/** * @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 Recalculates the pilot's stats based on his outfits. * * @param pilot Pilot to recalculate his stats. */ void pilot_calcStats( Pilot* pilot ) { int i; Outfit* o; PilotOutfitSlot *slot; double ac, sc, ec, fc; /* temporary health coefficients to set */ ShipStats amount, *s, *default_s; /* * set up the basic stuff */ /* mass */ pilot->solid->mass = pilot->ship->mass; pilot->base_mass = pilot->solid->mass; /* cpu */ pilot->cpu = 0.; /* movement */ pilot->thrust_base = pilot->ship->thrust; pilot->turn_base = pilot->ship->turn; pilot->speed_base = pilot->ship->speed; /* crew */ pilot->crew = pilot->ship->crew; /* cargo */ pilot->cap_cargo = pilot->ship->cap_cargo; /* fuel_consumption. */ pilot->fuel_consumption = pilot->ship->fuel_consumption; /* health */ ac = (pilot->armour_max > 0.) ? pilot->armour / pilot->armour_max : 0.; sc = (pilot->shield_max > 0.) ? pilot->shield / pilot->shield_max : 0.; ec = (pilot->energy_max > 0.) ? pilot->energy / pilot->energy_max : 0.; fc = (pilot->fuel_max > 0.) ? pilot->fuel / pilot->fuel_max : 0.; pilot->armour_max = pilot->ship->armour; pilot->shield_max = pilot->ship->shield; pilot->fuel_max = pilot->ship->fuel; pilot->armour_regen = pilot->ship->armour_regen; pilot->shield_regen = pilot->ship->shield_regen; /* Absorption. */ pilot->dmg_absorb = pilot->ship->dmg_absorb; /* Energy. */ pilot->energy_max = pilot->ship->energy; pilot->energy_regen = pilot->ship->energy_regen; pilot->energy_loss = 0.; /* Initially no net loss. */ /* Stats. */ s = &pilot->stats; memcpy( s, &pilot->ship->stats_array, sizeof(ShipStats) ); memset( &amount, 0, sizeof(ShipStats) ); /* * Now add outfit changes */ pilot->mass_outfit = 0.; pilot->jamming = 0; for (i=0; i<pilot->noutfits; i++) { slot = pilot->outfits[i]; o = slot->outfit; /* Outfit must exist. */ if (o==NULL) continue; /* Modify CPU. */ pilot->cpu += outfit_cpu(o); /* Add mass. */ pilot->mass_outfit += o->mass; /* Keep a separate counter for required (core) outfits. */ if (sp_required( o->slot.spid )) pilot->base_mass += o->mass; /* Add ammo mass. */ if (outfit_ammo(o) != NULL) if (slot->u.ammo.outfit != NULL) pilot->mass_outfit += slot->u.ammo.quantity * slot->u.ammo.outfit->mass; if (outfit_isAfterburner(o)) /* Afterburner */ pilot->afterburner = pilot->outfits[i]; /* Set afterburner */ /* Active outfits must be on to affect stuff. */ if (slot->active && !(slot->state==PILOT_OUTFIT_ON)) continue; if (outfit_isMod(o)) { /* Modification */ /* Movement. */ pilot->thrust_base += o->u.mod.thrust; pilot->turn_base += o->u.mod.turn; pilot->speed_base += o->u.mod.speed; /* Health. */ pilot->dmg_absorb += o->u.mod.absorb; pilot->armour_max += o->u.mod.armour; pilot->armour_regen += o->u.mod.armour_regen; pilot->shield_max += o->u.mod.shield; pilot->shield_regen += o->u.mod.shield_regen; pilot->energy_max += o->u.mod.energy; pilot->energy_regen += o->u.mod.energy_regen; pilot->energy_loss += o->u.mod.energy_loss; /* Fuel. */ pilot->fuel_max += o->u.mod.fuel; /* Misc. */ pilot->cap_cargo += o->u.mod.cargo; pilot->mass_outfit += o->u.mod.mass_rel * pilot->ship->mass; pilot->crew += o->u.mod.crew_rel * pilot->ship->crew; /* * Stats. */ ss_statsModFromList( s, o->u.mod.stats, &amount ); } else if (outfit_isAfterburner(o)) { /* Afterburner */ pilot_setFlag( pilot, PILOT_AFTERBURNER ); /* We use old school flags for this still... */ pilot->energy_loss += pilot->afterburner->outfit->u.afb.energy; /* energy loss */ } else if (outfit_isJammer(o)) { /* Jammer */ pilot->jamming = 1; pilot->energy_loss += o->u.jam.energy; } } if (!pilot_isFlag( pilot, PILOT_AFTERBURNER )) pilot->solid->speed_max = pilot->speed; /* Slot voodoo. */ s = &pilot->stats; default_s = &pilot->ship->stats_array; /* Fire rate: * amount = p * exp( -0.15 * (n-1) ) * 1x 15% -> 15% * 2x 15% -> 25.82% * 3x 15% -> 33.33% * 6x 15% -> 42.51% */ if (amount.fwd_firerate > 0) { s->fwd_firerate = default_s->fwd_firerate + (s->fwd_firerate-default_s->fwd_firerate) * exp( -0.15 * (double)(MAX(amount.fwd_firerate-1.,0)) ); } /* Cruiser. */ if (amount.tur_firerate > 0) { s->tur_firerate = default_s->tur_firerate + (s->tur_firerate-default_s->tur_firerate) * exp( -0.15 * (double)(MAX(amount.tur_firerate-1.,0)) ); } /* * Electronic warfare setting base parameters. */ s->ew_hide = default_s->ew_hide + (s->ew_hide-default_s->ew_hide) * exp( -0.2 * (double)(MAX(amount.ew_hide-1.,0)) ); s->ew_detect = default_s->ew_detect + (s->ew_detect-default_s->ew_detect) * exp( -0.2 * (double)(MAX(amount.ew_detect-1.,0)) ); s->ew_jump_detect = default_s->ew_jump_detect + (s->ew_jump_detect-default_s->ew_jump_detect) * exp( -0.2 * (double)(MAX(amount.ew_jump_detect-1.,0)) ); /* Square the internal values to speed up comparisons. */ pilot->ew_base_hide = pow2( s->ew_hide ); pilot->ew_detect = pow2( s->ew_detect ); pilot->ew_jump_detect = pow2( s->ew_jump_detect ); /* * Relative increases. */ /* Movement. */ pilot->thrust_base *= s->thrust_mod; pilot->turn_base *= s->turn_mod; pilot->speed_base *= s->speed_mod; /* Health. */ pilot->armour_max *= s->armour_mod; pilot->armour_regen *= s->armour_regen_mod; pilot->shield_max *= s->shield_mod; pilot->shield_regen *= s->shield_regen_mod; pilot->energy_max *= s->energy_mod; pilot->energy_regen *= s->energy_regen_mod; /* cpu */ pilot->cpu_max = (int)floor((float)(pilot->ship->cpu + s->cpu_max)*s->cpu_mod); pilot->cpu += pilot->cpu_max; /* CPU is negative, this just sets it so it's based off of cpu_max. */ /* Misc. */ pilot->dmg_absorb = MAX( 0., pilot->dmg_absorb ); pilot->crew *= s->crew_mod; pilot->cap_cargo *= s->cargo_mod; s->engine_limit *= s->engine_limit_rel; /* * Flat increases. */ pilot->energy_max += s->energy_flat; pilot->energy += s->energy_flat; pilot->energy_regen -= s->energy_usage; /* Give the pilot his health proportion back */ pilot->armour = ac * pilot->armour_max; pilot->shield = sc * pilot->shield_max; pilot->energy = ec * pilot->energy_max; pilot->fuel = fc * pilot->fuel_max; /* Set final energy tau. */ pilot->energy_tau = pilot->energy_max / pilot->energy_regen; /* Cargo has to be reset. */ pilot_cargoCalc(pilot); /* Calculate mass. */ pilot->solid->mass = s->mass_mod*pilot->ship->mass + pilot->stats.cargo_inertia*pilot->mass_cargo + pilot->mass_outfit; /* Calculate the heat. */ pilot_heatCalc( pilot ); /* Modulate by mass. */ pilot_updateMass( pilot ); /* Update GUI as necessary. */ gui_setGeneric( pilot ); }
/** * @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 Recalculates the pilot's stats based on his outfits. * * @param pilot Pilot to recalculate his stats. */ void pilot_calcStats( Pilot* pilot ) { int i; double q; Outfit* o; PilotOutfitSlot *slot; double ac, sc, ec, fc; /* temporary health coefficients to set */ double arel, srel, erel; /* relative health bonuses. */ ShipStats *s, *os; int nfirerate_turret, nfirerate_forward; int njammers; int ew_ndetect, ew_nhide; /* Comfortability. */ s = &pilot->stats; /* * set up the basic stuff */ /* mass */ pilot->solid->mass = pilot->ship->mass; /* movement */ pilot->thrust = pilot->ship->thrust; pilot->turn_base = pilot->ship->turn; pilot->speed = pilot->ship->speed; /* cpu */ pilot->cpu_max = pilot->ship->cpu; pilot->cpu = pilot->cpu_max; /* crew */ pilot->crew = pilot->ship->crew; /* health */ ac = pilot->armour / pilot->armour_max; sc = pilot->shield / pilot->shield_max; ec = pilot->energy / pilot->energy_max; fc = pilot->fuel / pilot->fuel_max; pilot->armour_max = pilot->ship->armour; pilot->shield_max = pilot->ship->shield; pilot->fuel_max = pilot->ship->fuel; pilot->armour_regen = pilot->ship->armour_regen; pilot->shield_regen = pilot->ship->shield_regen; /* Absorption. */ pilot->dmg_absorb = pilot->ship->dmg_absorb; /* Energy. */ pilot->energy_max = pilot->ship->energy; pilot->energy_regen = pilot->ship->energy_regen; /* Jamming */ pilot->jam_range = 0.; pilot->jam_chance = 0.; /* Stats. */ memcpy( s, &pilot->ship->stats, sizeof(ShipStats) ); /* cargo has to be reset */ pilot_cargoCalc(pilot); /* * now add outfit changes */ nfirerate_forward = nfirerate_turret = 0; pilot->mass_outfit = 0.; njammers = 0; ew_ndetect = 0; ew_nhide = 0; pilot->jam_range = 0.; pilot->jam_chance = 0.; arel = 0.; srel = 0.; erel = 0.; for (i=0; i<pilot->noutfits; i++) { slot = pilot->outfits[i]; o = slot->outfit; if (o==NULL) continue; q = (double) slot->quantity; /* Subtract CPU. */ pilot->cpu -= outfit_cpu(o) * q; if (outfit_cpu(o) < 0.) pilot->cpu_max -= outfit_cpu(o) * q; /* Add mass. */ pilot->mass_outfit += o->mass; if (outfit_isMod(o)) { /* Modification */ /* movement */ pilot->thrust += o->u.mod.thrust * pilot->ship->mass * q; pilot->thrust += o->u.mod.thrust_rel * pilot->ship->thrust * q; pilot->turn_base += o->u.mod.turn * q; pilot->turn_base += o->u.mod.turn_rel * pilot->ship->turn * q; pilot->speed += o->u.mod.speed * q; pilot->speed += o->u.mod.speed_rel * pilot->ship->speed * q; /* health */ pilot->armour_max += o->u.mod.armour * q; pilot->armour_regen += o->u.mod.armour_regen * q; arel += o->u.mod.armour_rel * q; pilot->shield_max += o->u.mod.shield * q; pilot->shield_regen += o->u.mod.shield_regen * q; srel += o->u.mod.shield_rel * q; pilot->energy_max += o->u.mod.energy * q; pilot->energy_regen += o->u.mod.energy_regen * q; erel += o->u.mod.energy_rel * q; /* fuel */ pilot->fuel_max += o->u.mod.fuel * q; /* misc */ pilot->cargo_free += o->u.mod.cargo * q; pilot->mass_outfit += o->u.mod.mass_rel * pilot->ship->mass * q; pilot->crew += o->u.mod.crew_rel * pilot->ship->crew * q; /* * Stats. */ os = &o->u.mod.stats; /* Freighter. */ s->jump_delay += os->jump_delay * q; s->jump_range += os->jump_range * q; s->cargo_inertia += os->cargo_inertia * q; /* Scout. */ if (os->ew_hide != 0.) { s->ew_hide += os->ew_hide * q; ew_nhide++; } if (os->ew_detect != 0.) { s->ew_detect += os->ew_detect * q; ew_ndetect++; } s->jam_range += os->jam_range * q; /* Military. */ s->heat_dissipation += os->heat_dissipation * q; /* Bomber. */ s->launch_rate += os->launch_rate * q; s->launch_range += os->launch_range * q; s->jam_counter += os->jam_counter * q; s->ammo_capacity += os->ammo_capacity * q; /* Fighter. */ s->heat_forward += os->heat_forward * q; s->damage_forward += os->damage_forward * q; s->energy_forward += os->energy_forward * q; if (os->firerate_forward != 0.) { s->firerate_forward += os->firerate_forward * q; nfirerate_forward += q; } /* Cruiser. */ s->heat_turret += os->heat_turret * q; s->damage_turret += os->damage_turret * q; s->energy_turret += os->energy_turret * q; if (os->firerate_turret != 0.) { s->firerate_turret += os->firerate_turret * q; if (os->firerate_turret > 0.) /* Only modulate bonuses. */ nfirerate_turret += q; } /* Misc. */ s->nebula_dmg_shield += os->nebula_dmg_shield * q; s->nebula_dmg_armour += os->nebula_dmg_armour * q; } else if (outfit_isAfterburner(o)) /* Afterburner */ pilot->afterburner = pilot->outfits[i]; /* Set afterburner */ else if (outfit_isJammer(o)) { /* Jammer */ pilot->jam_range += o->u.jam.range * q; pilot->jam_chance += o->u.jam.chance * q; pilot->energy_regen -= o->u.jam.energy * q; njammers += q;; } /* Add ammo mass. */ if (outfit_ammo(o) != NULL) { if (slot->u.ammo.outfit != NULL) pilot->mass_outfit += slot->u.ammo.quantity * slot->u.ammo.outfit->mass; } } /* Set final energy tau. */ pilot->energy_tau = pilot->energy_max / pilot->energy_regen; /* * Electronic warfare setting base parameters. */ s->ew_hide = 1. + s->ew_hide/100. * exp( -0.2 * (double)(MAX(ew_nhide-1,0)) ); s->ew_detect = 1. + s->ew_detect/100. * exp( -0.2 * (double)(MAX(ew_ndetect-1,0)) ); pilot->ew_base_hide = s->ew_hide; pilot->ew_detect = s->ew_detect; /* * Normalize stats. */ /* Freighter. */ s->jump_range = s->jump_range/100. + 1.; s->jump_delay = s->jump_delay/100. + 1.; s->cargo_inertia = s->cargo_inertia/100. + 1.; /* Scout. */ s->jam_range = s->jam_range/100. + 1.; /* Military. */ s->heat_dissipation = s->heat_dissipation/100. + 1.; /* Bomber. */ s->launch_rate = s->launch_rate/100. + 1.; s->launch_range = s->launch_range/100. + 1.; s->jam_counter = s->jam_counter/100. + 1.; s->ammo_capacity = s->ammo_capacity/100. + 1.; /* Fighter. */ s->heat_forward = s->heat_forward/100. + 1.; s->damage_forward = s->damage_forward/100. + 1.; s->energy_forward = s->energy_forward/100. + 1.; /* Fire rate: * amount = p * exp( -0.15 * (n-1) ) * 1x 15% -> 15% * 2x 15% -> 25.82% * 3x 15% -> 33.33% * 6x 15% -> 42.51% */ s->firerate_forward = s->firerate_forward/100.; if (nfirerate_forward > 0) s->firerate_forward *= exp( -0.15 * (double)(MAX(nfirerate_forward-1,0)) ); s->firerate_forward += 1.; /* Cruiser. */ s->heat_turret = s->heat_turret/100. + 1.; s->damage_turret = s->damage_turret/100. + 1.; s->energy_turret = s->energy_turret/100. + 1.; s->firerate_turret = s->firerate_turret/100.; if (nfirerate_turret > 0) s->firerate_turret *= exp( -0.15 * (double)(MAX(nfirerate_turret-1,0)) ); s->firerate_turret += 1.; /* Misc. */ s->nebula_dmg_shield = s->nebula_dmg_shield/100. + 1.; s->nebula_dmg_armour = s->nebula_dmg_armour/100. + 1.; /* * Calculate jammers. * * Range is averaged. * Diminishing return on chance. * chance = p * exp( -0.2 * (n-1) ) * 1x 20% -> 20% * 2x 20% -> 32% * 2x 40% -> 65% * 6x 40% -> 88% */ if (njammers > 1) { pilot->jam_range /= (double)njammers; pilot->jam_range *= s->jam_range; pilot->jam_chance *= exp( -0.2 * (double)(MAX(njammers-1,0)) ); } /* Increase health by relative bonuses. */ pilot->armour_max += arel * pilot->ship->armour; pilot->shield_max += srel * pilot->ship->shield; pilot->energy_max += erel * pilot->ship->energy; /* Give the pilot his health proportion back */ pilot->armour = ac * pilot->armour_max; pilot->shield = sc * pilot->shield_max; pilot->energy = ec * pilot->energy_max; pilot->fuel = fc * pilot->fuel_max; /* Calculate mass. */ pilot->solid->mass = pilot->ship->mass + s->cargo_inertia*pilot->mass_cargo + pilot->mass_outfit; /* Calculate the heat. */ pilot_heatCalc( pilot ); /* Modulate by mass. */ pilot_updateMass( pilot ); /* Update GUI as necessary. */ gui_setGeneric( pilot ); }
/** * @brief Recalculates the pilot's stats based on his outfits. * * @param pilot Pilot to recalculate his stats. */ void pilot_calcStats( Pilot* pilot ) { int i; Outfit* o; PilotOutfitSlot *slot; double ac, sc, ec, fc; /* temporary health coefficients to set */ double arel, srel, erel; /* relative health bonuses. */ ShipStats amount, *s; /* @TODO remove old school PILOT_AFTERBURN flags. */ pilot_rmFlag( pilot, PILOT_AFTERBURNER ); /* * set up the basic stuff */ /* mass */ pilot->solid->mass = pilot->ship->mass; /* movement */ pilot->thrust = pilot->ship->thrust; pilot->turn_base = pilot->ship->turn; pilot->speed = pilot->ship->speed; /* cpu */ pilot->cpu_max = pilot->ship->cpu; pilot->cpu = pilot->cpu_max; /* crew */ pilot->crew = pilot->ship->crew; /* health */ ac = pilot->armour / pilot->armour_max; sc = pilot->shield / pilot->shield_max; ec = pilot->energy / pilot->energy_max; fc = pilot->fuel / pilot->fuel_max; pilot->armour_max = pilot->ship->armour; pilot->shield_max = pilot->ship->shield; pilot->fuel_max = pilot->ship->fuel; pilot->armour_regen = pilot->ship->armour_regen; pilot->shield_regen = pilot->ship->shield_regen; /* Absorption. */ pilot->dmg_absorb = pilot->ship->dmg_absorb; /* Energy. */ pilot->energy_max = pilot->ship->energy; pilot->energy_regen = pilot->ship->energy_regen; pilot->energy_loss = 0.; /* Initially no net loss. */ /* Stats. */ memcpy( &pilot->stats, &pilot->ship->stats_array, sizeof(ShipStats) ); memset( &amount, 0, sizeof(ShipStats) ); /* cargo has to be reset */ pilot_cargoCalc(pilot); /* Slot voodoo. */ s = &pilot->stats; /* * Electronic warfare setting base parameters. * @TODO ew_hide and ew_detect should be squared so XML-sourced values are linear. */ s->ew_hide = 1. + (s->ew_hide-1.) * exp( -0.2 * (double)(MAX(amount.ew_hide-1,0)) ); s->ew_detect = 1. + (s->ew_detect-1.) * exp( -0.2 * (double)(MAX(amount.ew_detect-1,0)) ); s->ew_jumpDetect = 1. + (s->ew_jumpDetect-1.) * exp( -0.2 * (double)(MAX(amount.ew_jumpDetect-1,0)) ); pilot->ew_base_hide = s->ew_hide; pilot->ew_detect = s->ew_detect; pilot->ew_jumpDetect = pow2(s->ew_jumpDetect); /* * now add outfit changes */ pilot->mass_outfit = 0.; pilot->jamming = 0; arel = 0.; srel = 0.; erel = 0.; for (i=0; i<pilot->noutfits; i++) { slot = pilot->outfits[i]; o = slot->outfit; /* Outfit must exist. */ if (o==NULL) continue; /* Subtract CPU. */ pilot->cpu -= outfit_cpu(o); if (outfit_cpu(o) < 0.) pilot->cpu_max -= outfit_cpu(o); /* Add mass. */ pilot->mass_outfit += o->mass; /* Add ammo mass. */ if (outfit_ammo(o) != NULL) if (slot->u.ammo.outfit != NULL) pilot->mass_outfit += slot->u.ammo.quantity * slot->u.ammo.outfit->mass; /* Set afterburner. */ if (outfit_isAfterburner(o)) pilot->afterburner = pilot->outfits[i]; /* Active outfits must be on to affect stuff. */ if (slot->active && !(slot->state==PILOT_OUTFIT_ON)) continue; if (outfit_isMod(o)) { /* Modification */ /* movement */ pilot->thrust += o->u.mod.thrust * pilot->ship->mass; pilot->thrust += o->u.mod.thrust_rel * pilot->ship->thrust; pilot->turn_base += o->u.mod.turn; pilot->turn_base += o->u.mod.turn_rel * pilot->ship->turn; pilot->speed += o->u.mod.speed; pilot->speed += o->u.mod.speed_rel * pilot->ship->speed; /* health */ pilot->armour_max += o->u.mod.armour; pilot->armour_regen += o->u.mod.armour_regen; arel += o->u.mod.armour_rel; pilot->shield_max += o->u.mod.shield; pilot->shield_regen += o->u.mod.shield_regen; srel += o->u.mod.shield_rel; pilot->energy_max += o->u.mod.energy; pilot->energy_regen += o->u.mod.energy_regen; erel += o->u.mod.energy_rel; /* fuel */ pilot->fuel_max += o->u.mod.fuel; /* misc */ pilot->cargo_free += o->u.mod.cargo; pilot->mass_outfit += o->u.mod.mass_rel * pilot->ship->mass; pilot->crew += o->u.mod.crew_rel * pilot->ship->crew; pilot->ew_base_hide += o->u.mod.hide_rel * pilot->ew_base_hide; /* * Stats. */ ss_statsModFromList( &pilot->stats, o->u.mod.stats, &amount ); } else if (outfit_isAfterburner(o)) { /* Afterburner */ pilot_setFlag( pilot, PILOT_AFTERBURNER ); /* We use old school flags for this still... */ pilot->energy_loss += pilot->afterburner->outfit->u.afb.energy; /* energy loss */ pilot->solid->speed_max = pilot->speed + pilot->speed * pilot->afterburner->outfit->u.afb.speed * MIN( 1., pilot->afterburner->outfit->u.afb.mass_limit/pilot->solid->mass); } else if (outfit_isJammer(o)) { /* Jammer */ pilot->jamming = 1; pilot->energy_loss += o->u.jam.energy; } } if (!pilot_isFlag( pilot, PILOT_AFTERBURNER )) pilot->solid->speed_max = pilot->speed; /* Set final energy tau. */ pilot->energy_tau = pilot->energy_max / pilot->energy_regen; /* Fire rate: * amount = p * exp( -0.15 * (n-1) ) * 1x 15% -> 15% * 2x 15% -> 25.82% * 3x 15% -> 33.33% * 6x 15% -> 42.51% */ if (amount.fwd_firerate > 0) { s->fwd_firerate = 1. + (s->fwd_firerate-1.) * exp( -0.15 * (double)(MAX(amount.fwd_firerate-1,0)) ); } /* Cruiser. */ if (amount.tur_firerate > 0) { s->tur_firerate = 1. + (s->tur_firerate-1.) * exp( -0.15 * (double)(MAX(amount.tur_firerate-1,0)) ); } /* Increase health by relative bonuses. */ pilot->armour_max += arel * pilot->ship->armour; pilot->armour_max *= pilot->stats.armour_mod; pilot->shield_max += srel * pilot->ship->shield; pilot->shield_max *= pilot->stats.shield_mod; pilot->energy_max += erel * pilot->ship->energy; /* pilot->energy_max *= pilot->stats.energy_mod; */ /* Give the pilot his health proportion back */ pilot->armour = ac * pilot->armour_max; pilot->shield = sc * pilot->shield_max; pilot->energy = ec * pilot->energy_max; pilot->fuel = fc * pilot->fuel_max; /* Calculate the heat. */ pilot_heatCalc( pilot ); /* Modulate by mass. */ pilot_updateMass( pilot ); /* Update GUI as necessary. */ gui_setGeneric( pilot ); }