92 static int base_contact_id = 0;
93 static double range_min = 0;
94 static double range_max = 250e3;
109 Ship::Ship(
const char* ship_name,
const char* reg_num,
ShipDesign* ship_dsn,
int IFF,
int cmd_ai,
const int* load)
110 : IFF_code(IFF), killer(0), throttle(0), augmenter(false), throttle_request(0),
111 shield(0), shieldRep(0), main_drive(0), quantum_drive(0), farcaster(0),
112 check_fire(false), probe(0), sensor_drone(0), primary(0), secondary(1),
113 cmd_chain_index(0), target(0), subtarget(0), radio_orders(0), launch_point(0),
114 g_force(0.0f), sensor(0), navsys(0), flcs(0), hangar(0), respawns(0), invulnerable(false),
115 thruster(0), decoy(0), ai_mode(2), command_ai_level(cmd_ai), flcs_mode(FLCS_AUTO), loadout(0),
116 emcon(3), old_emcon(3), master_caution(false), cockpit(0), gear(0), skin(0),
117 auto_repair(true), last_repair_time(0), last_eval_time(0), last_beam_time(0), last_bolt_time(0),
118 warp_fov(1), flight_phase(LAUNCH), launch_time(0), carrier(0), dock(0), ff_count(0),
119 inbound(0), element(0), director_info(
"Init"), combat_unit(0), net_control(0),
120 track(0), ntrack(0), track_time(0), helm_heading(0.0f), helm_pitch(0.0f),
121 altitude_agl(-1.0e6f), transition_time(0.0f), transition_type(TRANSITION_NONE),
122 friendly_fire_time(0), ward(0), net_observer_mode(false), orig_elem_index(-1)
126 strcpy_s(
name, ship_name);
127 if (reg_num && *reg_num)
128 strcpy_s(
regnum, reg_num);
135 sprintf_s(msg,
"No ship design found for '%s'\n", ship_name);
162 while (!base_contact_id)
163 base_contact_id = rand() % 1000;
171 reactor->
SetID(sys_id++);
179 drive->
SetID(sys_id++);
183 reactors[src_index]->AddClient(drive);
249 deck->
SetID(sys_id++);
254 reactors[src_index]->AddClient(deck);
310 gun->
SetID(sys_id++);
316 reactors[src_index]->AddClient(gun);
332 if (load && loadout_size > 0) {
333 loadout =
new(__FILE__,__LINE__)
int[loadout_size];
335 for (
int i = 0; i < loadout_size; i++) {
336 int mounted_weapon =
loadout[i] = load[i];
338 if (mounted_weapon < 0)
344 missile->
SetID(sys_id++);
380 ::Print(
"WARNING: Ship '%s' type '%s' has %d wep groups (max=4)\n",
401 navlight->
SetID(sys_id++);
402 navlight->
SetOffset(((DWORD)
this) << 2);
458 comp->
SetID(sys_id++);
461 reactors[src_index]->AddClient(comp);
533 for (
int i = 0; i < 4; i++) {
561 for (
int i = 0; i < deck->
NumSlots(); i++) {
679 const float ROLL_SPEED = (float)(
PI * 0.1500);
680 const float PITCH_SPEED = (float)(
PI * 0.0250);
681 const float YAW_SPEED = (float)(
PI * 0.0250);
700 float yaw_air_factor = 1.0f;
717 yaw_air_factor = 0.3f;
727 else if (!grounded && agility < 0.5 * design->
agility)
750 if (agility < 0.5 * design->
agility)
761 if (rr == 0) rr = (float)
agility * ROLL_SPEED;
762 if (pr == 0) pr = (float)
agility * PITCH_SPEED;
763 if (yr == 0) yr = (float)
agility * YAW_SPEED * yaw_air_factor;
775 const double GRAV = 6.673e-11;
791 double m0 = primary->
Mass();
792 double r = primary->
Radius();
833 return textures.
size();
892 for (i = 0; i < navlight->
NumBeacons(); i++) {
912 for (i = 0; i < w->
Ammo(); i++) {
980 for (i = 0; i < navlight->
NumBeacons(); i++) {
1000 for (i = 0; i < w->
Ammo(); i++) {
1040 track =
new(__FILE__,__LINE__)
Point[DEFAULT_TRACK_LENGTH];
1057 track =
new(__FILE__,__LINE__)
Point[DEFAULT_TRACK_LENGTH];
1063 else if (time -
track_time > DEFAULT_TRACK_UPDATE) {
1065 for (
int i = DEFAULT_TRACK_LENGTH-2; i >= 0; i--)
1221 return ((
Ship*)
this)->ContactList().size();
1231 return empty_contact_list;
1258 Ship* controller = 0;
1268 double distance = 10e6;
1360 if (hud && hud->GetShip() ==
this)
1429 bool enable =
false;
1481 static DWORD ff_warn_time = 0;
1497 double dlen = delta.
length();
1513 if (shot->
Owner()) {
1515 if (owner_design && owner_design->
scale < scale)
1516 scale = (float) owner_design->
scale;
1523 if (dlen < rep->
Radius()) {
1524 hull_impact = impact = shot_loc;
1529 if (shot->
Damage() > 0) {
1546 if (dlen < (damage_radius +
Radius())) {
1547 if (seeker && seeker->
Overshot()) {
1548 dscale = 1.0 - (dlen / (damage_radius +
Radius()));
1554 hull_impact = impact = shot_loc;
1556 if (shot->
Damage() > 0) {
1566 hull_impact = impact = shot_loc;
1568 if (shot->
Damage() > 0) {
1603 burst_vel *=
Radius() * 0.5;
1615 double effective_damage = shot->
Damage() * dscale;
1619 if (shot->
Owner()) {
1624 bool was_rogue = s->
IsRogue();
1630 if (shot->
IsBeam()) penalty = 5;
1631 else if (shot->
IsDrone()) penalty = 7;
1633 if (s->
GetTarget() ==
this) penalty *= 3;
1641 if (s->
IsRogue() && !was_rogue) {
1660 if (effective_damage > 0) {
1665 InflictDamage(effective_damage, shot, hit_type, hull_impact);
1673 static bool CheckRaySphereIntersection(
Point loc,
double radius,
Point Q,
Point w,
double len)
1677 double dlen = d1.
length();
1685 Point closest = Q + w * (d0 * w);
1688 Point leading_edge = Q + w*len;
1689 Point leading_delta = leading_edge - loc;
1690 double leading_dist = leading_delta.
length();
1693 if (leading_dist > radius) {
1696 Point delta1 = closest - Q;
1697 Point delta2 = leading_edge - Q;
1701 if (delta1 * delta2 < 0 || delta1.
length() > len) {
1715 Point shot_vpn = shot_loc - shot_org;
1717 double blow_len = shot_len;
1718 bool hit_hull =
false;
1724 if (shot_len < 1000)
1728 Point shield_impact;
1729 Point turret_impact;
1743 closest = shield_impact;
1747 ipt = shield_impact;
1758 hit_hull = CheckRaySphereIntersection(s->
Location(), s->
Radius(), shot_org, shot_vpn, shot_len);
1776 closest = hull_impact;
1795 if (CheckRaySphereIntersection(tloc, tsize, shot_org, shot_vpn, shot_len)) {
1796 Point delta = tloc - shot_org;
1802 turret_impact = tloc;
1806 closest = turret_impact;
1807 hull_impact = turret_impact;
1808 hpt = turret_impact;
1811 ipt = turret_impact;
1820 if (hit_type && shot->
IsBeam()) {
1837 const double MAX_SHAKE = 7;
1839 if (
shake < MAX_SHAKE)
shake += (float) newshake;
1840 if (
shake > MAX_SHAKE)
shake = (float) MAX_SHAKE;
1852 double sys_damage = damage;
1886 if (system->
Status() != status) {
1929 Point dir = tgt - wep;
1931 Point rho = obj - wep;
1939 Point dst = dir * r + wep;
1940 double err = (obj - dst).length();
1942 if (err < test->Radius() * 1.5)
1981 if (cship && cship !=
this && (cship->
GetIFF() == 0 || cship->
GetIFF() ==
GetIFF())) {
2025 return (
Ship*)
this;
2120 const char* msg =
"Captain on the bridge";
2126 if (!vox->
Start()) {
2136 const char* msg =
"Exec, you have the conn";
2142 if (!vox->
Start()) {
2178 double distance = 0;
2194 if (navpt && navpt->
Status() != status) {
2197 ::
Print(
"Completed Assault\n");
2200 ::
Print(
"Completed Strike\n");
2224 return dummy_flight_plan;
2336 subtgt = sys.
value();
2444 if (range > carrier_target->
Radius() * 1.5)
2461 Point global_cam_loc = global_cam->
Pos();
2462 bool disable_shadows =
false;
2466 disable_shadows =
true;
2526 int target_found = 0;
2551 bool auto_pilot =
false;
2578 if (navpt && !auto_pilot) {
2580 double distance = 0;
2596 if (distance < 10 *
Radius())
2610 const DWORD EVAL_FREQUENCY = 1000;
2611 static DWORD last_eval_frame = 0;
2673 double spool = 75 * seconds;
2718 bool winchester_cycle =
false;
2750 winchester_cycle =
true;
2761 if (winchester_cycle) {
2793 bool bubble =
false;
2835 double bottom = 1e9;
2839 if (flight_phase < ACTIVE || flight_phase >
APPROACH) {
2852 if (bottom < tlevel)
2873 double pitch_deflection = vnrm *
cam.
vup();
2874 double yaw_deflection = vnrm *
cam.
vrt();
2881 double factor = 1.2 + (250 - v) / 100;
2891 if (fabs(pitch_deflection) >
stall) {
2923 transvec *= (transvec *
velocity) * seconds * 0.5;
2930 transvec *= (transvec *
velocity) * seconds * 0.25;
2937 transvec *= (transvec *
velocity) * seconds * 0.5;
2972 double spool = 75 * seconds;
3103 Point global_cam_loc = global_cam->
Pos();
3104 bool disable_shadows =
false;
3110 disable_shadows =
true;
3122 bool bubble =
false;
3164 turret_base->
Show();
3168 for (
int i = 0; i < w->
Ammo(); i++) {
3265 for (
int i = 0; i < w->
Ammo(); i++) {
3285 for (
int i = 0; i < nmodels; i++) {
3328 turret_base->
Show();
3332 for (
int i = 0; i < w->
Ammo(); i++) {
3368 turret_base->
Hide();
3372 for (
int i = 0; i < w->
Ammo(); i++) {
3445 return reactor->
Charge();
3526 bool combat =
false;
3532 int ciff = c->
GetIFF(
this);
3534 double dist = delta.
length();
3536 if (c->
Threat(
this) && !cship) {
3538 combat = dist < 120e3;
3540 combat = dist < 60e3;
3543 else if (cship && ciff > 0 && ciff !=
GetIFF()) {
3545 combat = dist < 120e3;
3547 combat = dist < 60e3;
3624 double lateral_offset = 2 *
Radius();
3625 double vertical_offset =
Radius();
3627 if (vertical_offset > 300)
3628 vertical_offset = 300;
3631 lateral_offset *= -1;
3634 vertical_offset *= -1;
3636 offset +=
BeamLine() * lateral_offset;
3637 offset +=
LiftLine() * vertical_offset;
3729 Point trans = delta + unit * -20e3;
3730 double dist = trans.
length();
3731 double speed = navpt->
Speed();
3733 if (speed < 50) speed = 500;
3735 double etr = dist / speed;
3763 double compass_heading = atan2(fabs(heading.
x), heading.
z);
3766 compass_heading *= -1;
3768 double result = compass_heading +
PI;
3780 return asin(heading.
y);
3826 while (!group && ++iter)
3828 group = iter.
value();
3867 if (
weapons[n]->IsPrimary()) {
3912 if (index >= 0 && index < 4)
3924 for (
int i = 0; i < 4; i++)
3930 for (
int i = 0; i < 4 && index < 0; i++) {
3939 if (index >= 0 && index < 4) {
3966 double total_thrust = 0;
3974 double thrust_factor = 1;
3975 double vfwd = H * V;
3978 if (vmag >
vlimit && vfwd > 0) {
3983 vfwd = 0.5 * vfwd + 0.5;
3986 thrust_factor = (vfwd * pow(vmax,3) / pow(vmag,3)) + (1-vfwd);
3995 eff_throttle /= 100;
3996 eff_throttle *= eff_throttle;
3997 eff_throttle *= 100;
4003 if (aug_on &&
shake < 1.5)
4004 ((
Ship*)
this)->shake = 1.5f;
4007 return total_thrust;
4093 double vmag = fabs(vfwd);
4148 double vmag = fabs(vfwd);
4180 const double PITCH_LIMIT = 80 *
DEGREES;
4182 if (p < -PITCH_LIMIT)
4185 else if (p > PITCH_LIMIT)
4196 double turn = y *
PI/4;
4200 else if (compass < -
PI)
4204 if (fabs(compass + turn) > 170*
DEGREES)
4229 double limit = 0.5 - (
g_force - 12.0)/10.0;
4265 fired =
weapons[n]->GetTrigger();
4335 for (
int j = 0; j < wlist.
size(); j++) {
4494 double damage_applied = 0;
4497 return damage_applied;
4500 return damage_applied;
4502 const double MAX_SHAKE = 7;
4503 double hull_damage = damage;
4504 bool hit_shield = (hit_type &
HIT_SHIELD) != 0;
4505 bool hit_hull = (hit_type &
HIT_HULL) != 0;
4506 bool hit_turret = (hit_type &
HIT_TURRET) != 0;
4508 if (impact ==
Point(0,0,0))
4548 if (shot && shot->
Design())
4552 damage_applied = hull_damage;
4558 else if (hit_turret) {
4563 if (shot && shot->
Design())
4567 damage_applied = hull_damage;
4576 if (
shake < MAX_SHAKE)
shake += (float) newshake;
4577 if (
shake > MAX_SHAKE)
shake = (float) MAX_SHAKE;
4584 if (new_integrity < 5 && new_integrity < old_integrity) {
4589 double distance = direction.
Normalize() * 3;
4594 impact += direction * 0.2;
4606 return damage_applied;
4617 double distance = 1e6;
4618 double blast_radius = 0;
4627 double to_level = 0;
4630 to_level = 1 - damage / 1e4;
4644 double sysrad = candidate->
Radius();
4650 double test_distance = (impact - candidate->
MountLocation()).length();
4652 if ((test_distance-blast_radius) < sysrad || dmg_emp && candidate->
IsPowerCritical()) {
4653 if (test_distance < distance) {
4655 distance = test_distance;
4664 double sys_damage = damage - hull_damage;
4674 if (sys_damage < 100)
4675 damage -= sys_damage;
4701 if (rand() > 24000) {
4702 double base_damage = 33.0 + rand()/1000.0;
4706 damage -= sys_damage;
4750 if (s->
GetID() == sys_id)
4758 if (s->
GetID() == sys_id)
4811 const DWORD REPAIR_FREQUENCY = 5000;
4812 static DWORD last_repair_frame = 0;
4826 bool started_repairs =
false;
4864 started_repairs =
true;
4869 started_repairs =
true;
4874 if (started_repairs)
4912 for (
int j = 0; j < xfer.
size(); j++) {
4975 else if (
life == 0) {
4977 ::Print(
"Warning: dying ship '%' still has not been destroyed!\n",
name);
5002 nav =
new(__FILE__,__LINE__)
NavAI(
this);
5023 else if (
GetIFF() < 100) {
5044 c =
Color(192,192,192);
5048 c =
Color(70,70,220);
5052 c =
Color(220,20,20);
5056 c =
Color(200,180,20);
5060 c =
Color(20,200,20);
5064 c =
Color(128, 0, 128);
5068 c =
Color(40,192,192);
5072 c =
Color(128,128,128);
5113 Print(
"Ship '%s' has been made rogue\n",
Name());
5115 else if (rogue && !
IsRogue()) {
5116 Print(
"Ship '%s' is no longer rogue\n",
Name());
5130 else if (rogue && !
IsRogue()) {
5131 Print(
"Ship '%s' is no longer rogue\n",
Name());
5154 if (e < 1)
emcon = 1;
5155 else if (e > 3)
emcon = 3;
5156 else emcon = (BYTE) e;
5173 return clutter * e_factor;
5177 return e_factor *
pcs;
5189 return clutter *
acs;
5250 case DRONE: value = 10;
break;
5251 case FIGHTER: value = 20;
break;
5252 case ATTACK: value = 40;
break;
5253 case LCA: value = 50;
break;
5255 case COURIER: value = 100;
break;
5256 case CARGO: value = 100;
break;
5259 case FRIGATE: value = 200;
break;
5261 case CRUISER: value = 800;
break;
5263 case CARRIER: value = 1500;
break;
5266 case STATION: value = 2500;
break;
5269 case MINE: value = 20;
break;
5270 case COMSAT: value = 200;
break;
5271 case DEFSAT: value = 300;
break;
5272 case SWACS: value = 500;
break;
5275 case FACTORY: value = 250;
break;
5276 case SAM: value = 100;
break;
5277 case EWR: value = 200;
break;
5278 case C3I: value = 500;
break;
5279 case STARBASE: value = 2000;
break;
5281 default: value = 100;
break;
5297 value += r->
Value();
5302 value += d->
Value();
5307 value += w->
Value();