/** * @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; /* * 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; /* Stats. */ memcpy( &pilot->stats, &pilot->ship->stats_array, sizeof(ShipStats) ); memset( &amount, 0, sizeof(ShipStats) ); /* cargo has to be reset */ pilot_cargoCalc(pilot); /* * 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; /* 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; /* * Stats. */ ss_statsModFromList( &pilot->stats, o->u.mod.stats, &amount ); /* TODO Handle q or remove it? */ } else if (outfit_isAfterburner(o)) /* Afterburner */ pilot->afterburner = pilot->outfits[i]; /* Set afterburner */ else if (outfit_isJammer(o)) { /* Jammer */ pilot->jamming = 1; pilot->energy_regen -= o->u.jam.energy; } /* 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; /* Slot voodoo. */ s = &pilot->stats; /* * Electronic warfare setting base parameters. */ 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 = s->ew_jumpDetect; /* 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 mass. */ pilot->solid->mass = 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 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; /* * 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; /* 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)) ); } /* * Electronic warfare setting base parameters. */ 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_jump_detect = 1. + (s->ew_jump_detect-1.) * 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; /* * 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 Dumps the modification data to csv. * * Note that this function is primarily intended for balancing core outfits. * * To that end, it omits a number of seldom-used properties, and is primarily * concerned with those that are common to most types of modifications, or at * least one category of core outfit. */ void dout_csvMod( const char *path ) { Outfit *o, *o_all; int i, n, l; SDL_RWops *rw; char buf[ 1024 ]; ShipStats base, stats; /* 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,size," "license,mass,price,cpu,cpu_max," "thrust,turn,speed,fuel,energy_usage," "armour,armour_regen," "shield,shield_regen," "energy,energy_regen," "absorb,cargo,ew_hide\n" ); SDL_RWwrite( rw, buf, l, 1 ); ss_statsInit( &base ); o_all = outfit_getAll( &n ); for (i=0; i<n; i++) { o = &o_all[i]; /* Only handle modifications. */ if (!outfit_isMod(o)) continue; stats = base; ss_statsModFromList( &stats, o->u.mod.stats, NULL ); l = nsnprintf( buf, sizeof(buf), "%s,%s,%s,%s," "%s,%f,%"CREDITS_PRI",%f,%f," "%f,%f,%f,%f,%f," "%f,%f," "%f,%f," "%f,%f," "%f,%f,%f\n", o->name, outfit_getType(o), outfit_slotName(o), outfit_slotSize(o), o->license, o->mass, o->price, o->cpu, stats.cpu_max, o->u.mod.thrust, o->u.mod.turn * 180. / M_PI, o->u.mod.speed, o->u.mod.fuel, stats.energy_usage, o->u.mod.armour, o->u.mod.armour_regen, o->u.mod.shield, o->u.mod.shield_regen, o->u.mod.energy, o->u.mod.energy_regen, o->u.mod.absorb * 100, o->u.mod.cargo, (stats.ew_hide - 1.) * 100 ); SDL_RWwrite( rw, buf, l, 1 ); } /* Close file. */ SDL_RWclose( rw ); }