From aadb810f137d25ce3b9f6e666be3522200b4b24f Mon Sep 17 00:00:00 2001 From: Roy Falk Date: Mon, 21 Oct 2024 21:31:54 +0300 Subject: [PATCH] Implement Drive and Afterburner Also DriveUpgrade and AfterburnerUpgrade Move limits from Computer to Drive and Afterburner Get rid of fuzzy numbers. MJ is exactly x100 game numbers in ship info. Modify fuel efficiency in both ways to reduce tons on ship and increase actual usage. A note on clamps in movable.cpp: these essentially check something is within min/max. With the resource class, most of these are now redundant. Issues: - Ship damage model is very severe on drives. --- engine/CMakeLists.txt | 7 + engine/src/cmd/ai/aggressive.cpp | 4 +- engine/src/cmd/ai/fire.cpp | 4 +- engine/src/cmd/ai/flybywire.cpp | 48 ++-- engine/src/cmd/ai/flyjoystick.cpp | 2 +- engine/src/cmd/ai/hard_coded_scripts.cpp | 28 +- engine/src/cmd/ai/navigation.cpp | 49 ++-- engine/src/cmd/ai/script.cpp | 6 +- engine/src/cmd/ai/warpto.cpp | 4 +- engine/src/cmd/basecomputer.cpp | 246 ++++++---------- engine/src/cmd/computer.cpp | 21 -- engine/src/cmd/computer.h | 17 +- engine/src/cmd/drawable.cpp | 4 +- engine/src/cmd/energetic.cpp | 61 +--- engine/src/cmd/energetic.h | 10 +- engine/src/cmd/jump_capable.cpp | 4 +- engine/src/cmd/mount.cpp | 4 +- engine/src/cmd/movable.cpp | 267 ++++++++---------- engine/src/cmd/movable.h | 6 +- engine/src/cmd/unit_csv.cpp | 113 ++------ engine/src/cmd/unit_generic.cpp | 188 ++---------- engine/src/cmd/unit_generic.h | 18 +- engine/src/cmd/unit_util_generic.cpp | 4 +- engine/src/cmd/upgradeable_unit.cpp | 29 +- engine/src/cmd/vs_limits.h | 56 ---- engine/src/components/afterburner.cpp | 97 +++++++ engine/src/components/afterburner.h | 59 ++++ engine/src/components/afterburner_upgrade.cpp | 105 +++++++ engine/src/components/afterburner_upgrade.h | 65 +++++ engine/src/components/cloak.cpp | 1 - engine/src/components/component.cpp | 3 +- engine/src/components/component_utils.cpp | 41 ++- engine/src/components/component_utils.h | 13 + engine/src/components/drive.cpp | 226 +++++++++++++++ engine/src/components/drive.h | 96 +++++++ engine/src/components/drive_upgrade.cpp | 167 +++++++++++ engine/src/components/drive_upgrade.h | 96 +++++++ engine/src/components/dummy_component.cpp | 57 ++++ engine/src/components/dummy_component.h | 50 ++++ engine/src/components/jump_drive.cpp | 6 +- .../components/tests/afterburner_tests.cpp | 119 ++++++++ engine/src/components/tests/drive_tests.cpp | 219 ++++++++++++++ engine/src/configuration/configuration.cpp | 5 +- engine/src/configuration/configuration.h | 15 +- engine/src/gfx/cockpit.cpp | 6 +- engine/src/gfx/nav/drawsystem.cpp | 2 +- engine/src/ship_commands.cpp | 2 +- 47 files changed, 1820 insertions(+), 830 deletions(-) delete mode 100644 engine/src/cmd/vs_limits.h create mode 100644 engine/src/components/afterburner.cpp create mode 100644 engine/src/components/afterburner.h create mode 100644 engine/src/components/afterburner_upgrade.cpp create mode 100644 engine/src/components/afterburner_upgrade.h create mode 100644 engine/src/components/drive.cpp create mode 100644 engine/src/components/drive.h create mode 100644 engine/src/components/drive_upgrade.cpp create mode 100644 engine/src/components/drive_upgrade.h create mode 100644 engine/src/components/dummy_component.cpp create mode 100644 engine/src/components/dummy_component.h create mode 100644 engine/src/components/tests/afterburner_tests.cpp create mode 100644 engine/src/components/tests/drive_tests.cpp diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index eb4fc262da..c665ef0ff9 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -725,13 +725,18 @@ SET(LIBPYTHON SET(LIBCOMPONENT src/components/component.cpp + src/components/dummy_component.cpp src/components/component_utils src/components/energy_consumer.cpp src/components/energy_container.cpp src/components/reactor.cpp + src/components/afterburner.cpp + src/components/afterburner_upgrade.cpp src/components/cloak.cpp + src/components/drive.cpp + src/components/drive_upgrade.cpp src/components/ftl_drive.cpp src/components/jump_drive.cpp ) @@ -1749,6 +1754,8 @@ IF (USE_GTEST) src/exit_unit_tests.cpp src/components/tests/energy_container_tests.cpp src/components/tests/balancing_tests.cpp + src/components/tests/drive_tests.cpp + src/components/tests/afterburner_tests.cpp ) ADD_LIBRARY(vegastrike-testing diff --git a/engine/src/cmd/ai/aggressive.cpp b/engine/src/cmd/ai/aggressive.cpp index 0a71ff1d5d..24fe4d775f 100644 --- a/engine/src/cmd/ai/aggressive.cpp +++ b/engine/src/cmd/ai/aggressive.cpp @@ -321,7 +321,7 @@ bool AggressiveAI::ProcessLogicItem(const AIEvents::AIEvresult &item) { value = (pdmag - parent->rSize() - targ->rSize()); float myvel = PosDifference.Dot(parent->GetVelocity() - targ->GetVelocity()) / value; ///pdmag; if (myvel > 0) { - value -= myvel * myvel / (2 * (parent->limits.retro / parent->getMass())); + value -= myvel * myvel / (2 * (parent->drive.retro / parent->getMass())); } } else { value = 10000; @@ -1727,7 +1727,7 @@ void AggressiveAI::Execute() { mag = 1 / mag; } parent->SetVelocity( - parent->GetVelocity() * (mag * parent->GetComputerData().max_speed() / getTimeCompression())); + parent->GetVelocity() * (mag * parent->MaxSpeed() / getTimeCompression())); parent->NetLocalForce = parent->NetForce = Vector(0, 0, 0); } target = parent->Target(); diff --git a/engine/src/cmd/ai/fire.cpp b/engine/src/cmd/ai/fire.cpp index 9adbd18edf..686003b457 100644 --- a/engine/src/cmd/ai/fire.cpp +++ b/engine/src/cmd/ai/fire.cpp @@ -110,11 +110,11 @@ bool FireAt::PursueTarget(Unit *un, bool leader) { bool CanFaceTarget(Unit *su, Unit *targ, const Matrix &matrix) { return true; - float limitmin = su->limits.limitmin; + float limitmin = su->limit_min; if (limitmin > -.99) { QVector pos = (targ->Position() - su->Position()).Normalize(); QVector pnorm = pos.Cast(); - Vector structurelimits = su->limits.structurelimits; + Vector structurelimits = su->structure_limits; Vector worldlimit = TransformNormal(matrix, structurelimits); if (pnorm.Dot(worldlimit) < limitmin) { return false; diff --git a/engine/src/cmd/ai/flybywire.cpp b/engine/src/cmd/ai/flybywire.cpp index a7af62bfe8..c2faba1fb0 100644 --- a/engine/src/cmd/ai/flybywire.cpp +++ b/engine/src/cmd/ai/flybywire.cpp @@ -192,16 +192,16 @@ FlyByWire::FlyByWire() : MatchVelocity(Vector(0, 0, 0), Vector(0, 0, 0), true, f } void FlyByWire::Stop(float per) { - SetDesiredVelocity(Vector(0, 0, per * parent->GetComputerData().max_speed()), true); + SetDesiredVelocity(Vector(0, 0, per * parent->MaxSpeed()), true); - parent->GetComputerData().set_speed = per * parent->GetComputerData().max_speed(); + parent->GetComputerData().set_speed = per * parent->MaxSpeed(); } void FlyByWire::Right(float per) { desired_ang_velocity += (-per * (per - > 0 ? parent->GetComputerData().max_yaw_left : parent->GetComputerData().max_yaw_right) + > 0 ? parent->drive.max_yaw_left : parent->drive.max_yaw_right) / getTimeCompression()) * Vector( 0, 1, @@ -212,7 +212,7 @@ void FlyByWire::Up(float per) { desired_ang_velocity += (-per * (per - > 0 ? parent->GetComputerData().max_pitch_down : parent->GetComputerData().max_pitch_up) + > 0 ? parent->drive.max_pitch_down : parent->drive.max_pitch_up) / getTimeCompression()) * Vector( 1, 0, @@ -223,7 +223,7 @@ void FlyByWire::RollRight(float per) { desired_ang_velocity += (-per * (per - > 0 ? parent->GetComputerData().max_roll_left : parent->GetComputerData().max_roll_right) + > 0 ? parent->drive.max_roll_left : parent->drive.max_roll_right) / getTimeCompression()) * Vector( 0, 0, @@ -235,9 +235,9 @@ void FlyByWire::Afterburn(float per) { afterburn = (per > .1); if (!sheltonslide && !inertial_flight_model) { - desired_velocity = Vector(0, 0, cpu->set_speed + per * (cpu->max_ab_speed() - cpu->set_speed)); + desired_velocity = Vector(0, 0, cpu->set_speed + per * (parent->MaxAfterburnerSpeed() - cpu->set_speed)); } else if (inertial_flight_model) { - DirectThrust += Vector(0, 0, parent->limits.afterburn * per); + DirectThrust += Vector(0, 0, parent->afterburner.thrust * per); } if (parent == _Universe->AccessCockpit()->GetParent()) { //printf("afterburn is %d\n",afterburn); // DELETEME WTF all this force feedback code and its unused. @@ -254,22 +254,22 @@ void FlyByWire::MatchSpeed(const Vector &vec) { Computer *cpu = &parent->GetComputerData(); cpu->set_speed = (vec).Magnitude(); - if (cpu->set_speed > cpu->max_speed()) { - cpu->set_speed = cpu->max_speed(); + if (cpu->set_speed > parent->MaxSpeed()) { + cpu->set_speed = parent->MaxSpeed(); } } void FlyByWire::Accel(float per) { Computer *cpu = &parent->GetComputerData(); - cpu->set_speed += per * cpu->max_speed() * simulation_atom_var; //SIMULATION_ATOM? - if (cpu->set_speed > cpu->max_speed()) { - cpu->set_speed = cpu->max_speed(); + cpu->set_speed += per * parent->MaxSpeed() * simulation_atom_var; //SIMULATION_ATOM? + if (cpu->set_speed > parent->MaxSpeed()) { + cpu->set_speed = parent->MaxSpeed(); } static float reverse_speed_limit = XMLSupport::parse_float(vs_config->getVariable("physics", "reverse_speed_limit", "1.0")); - if (cpu->set_speed < -cpu->max_speed() * reverse_speed_limit) { - cpu->set_speed = -cpu->max_speed() * reverse_speed_limit; + if (cpu->set_speed < -parent->MaxSpeed() * reverse_speed_limit) { + cpu->set_speed = -parent->MaxSpeed() * reverse_speed_limit; } afterburn = false; @@ -279,30 +279,30 @@ void FlyByWire::Accel(float per) { #define FBWABS(m) (m >= 0 ? m : -m) void FlyByWire::ThrustRight(float percent) { - DesiredShiftVelocity.i = parent->GetComputerData().max_speed() * percent; + DesiredShiftVelocity.i = parent->MaxSpeed() * percent; } void FlyByWire::ThrustUp(float percent) { - DesiredShiftVelocity.j = parent->GetComputerData().max_speed() * percent; + DesiredShiftVelocity.j = parent->MaxSpeed() * percent; } void FlyByWire::ThrustFront(float percent) { - DesiredShiftVelocity.k = parent->GetComputerData().max_speed() * percent; + DesiredShiftVelocity.k = parent->MaxSpeed() * percent; } void FlyByWire::DirectThrustRight(float percent) { - DirectThrust.i = parent->limits.lateral * percent; + DirectThrust.i = parent->drive.lateral * percent; } void FlyByWire::DirectThrustUp(float percent) { - DirectThrust.j = parent->limits.vertical * percent; + DirectThrust.j = parent->drive.vertical * percent; } void FlyByWire::DirectThrustFront(float percent) { if (percent > 0) { - DirectThrust.k = parent->limits.forward * percent; + DirectThrust.k = parent->drive.forward * percent; } else { - DirectThrust.k = parent->limits.retro * percent; + DirectThrust.k = parent->drive.retro * percent; } } @@ -312,8 +312,8 @@ void FlyByWire::Execute() { if (!inertial_flight_model) { //Must translate the thrust values to velocities, which is somewhat cumbersome. Vector Limit( - parent->limits.lateral, parent->limits.vertical, - ((DirectThrust.k > 0) ? parent->limits.forward : parent->limits.retro) + parent->drive.lateral, parent->drive.vertical, + ((DirectThrust.k > 0) ? parent->drive.forward : parent->drive.retro) ); if (Limit.i <= 1) { Limit.i = 1; @@ -330,7 +330,7 @@ void FlyByWire::Execute() { DirectThrust.k / Limit.k ); //Now, scale so that maximum shift velocity is max_speed - DesiredDrift *= parent->GetComputerData().max_speed(); + DesiredDrift *= parent->MaxSpeed(); //And apply DesiredShiftVelocity += DesiredDrift; } diff --git a/engine/src/cmd/ai/flyjoystick.cpp b/engine/src/cmd/ai/flyjoystick.cpp index a7134ed885..fbf92af001 100644 --- a/engine/src/cmd/ai/flyjoystick.cpp +++ b/engine/src/cmd/ai/flyjoystick.cpp @@ -233,7 +233,7 @@ void FlyByJoystick::Execute() { float(expamountc * (exp(expfactorc * axis_value) - 1) / norm + pamountc * pow(axis_value, pfactorc)); } - cpu->set_speed = axis_value * cpu->max_speed(); + cpu->set_speed = axis_value * parent->MaxSpeed(); desired_velocity = Vector(0, 0, cpu->set_speed); } } diff --git a/engine/src/cmd/ai/hard_coded_scripts.cpp b/engine/src/cmd/ai/hard_coded_scripts.cpp index 1c73d5b3f0..82e4a5cd1d 100644 --- a/engine/src/cmd/ai/hard_coded_scripts.cpp +++ b/engine/src/cmd/ai/hard_coded_scripts.cpp @@ -235,7 +235,7 @@ void BarrelRoll(Order *aisc, Unit *un) { bool afterburn = useAfterburner(); broll->MatchSpeed(Vector(0, 0, - afterburn ? un->GetComputerData().max_ab_speed() : un->GetComputerData().max_speed())); + afterburn ? un->MaxAfterburnerSpeed() : un->MaxSpeed())); broll->Afterburn(afterburn); } @@ -246,7 +246,7 @@ static void EvadeWavy(Order *aisc, Unit *un, bool updown, bool ab) { bool afterburn = ab && useAfterburner(); broll->MatchSpeed(Vector(0, 0, - afterburn ? un->GetComputerData().max_ab_speed() : un->GetComputerData().max_speed())); + afterburn ? un->MaxAfterburnerSpeed() : un->MaxSpeed())); broll->Afterburn(afterburn); } @@ -330,11 +330,10 @@ class LoopAround : public Orders::FaceTargetITTS { Vector r = targ->cumulative_transformation_matrix.getR(); bool afterburn = useAfterburner() && this->afterburn; bool ab_needed = - force_afterburn || targ->GetVelocity().MagnitudeSquared() > parent->GetComputerData().max_speed(); + force_afterburn || targ->GetVelocity().MagnitudeSquared() > parent->MaxSpeed(); m.SetDesiredVelocity(Vector(0, 0, afterburn - && ab_needed ? parent->GetComputerData().max_ab_speed() - : parent->GetComputerData(). - max_speed()), true); + && ab_needed ? parent->MaxAfterburnerSpeed() + : parent->MaxSpeed()), true); float spseed, grange = 0, mrange = 0; parent->getAverageGunSpeed(spseed, grange, mrange); if (r.Dot(relloc) < 0) { @@ -429,7 +428,7 @@ class LoopAroundAgro : public Orders::FaceTargetITTS { Vector r = targ->cumulative_transformation_matrix.getR(); bool afterburn = useAfterburner() && this->afterburn; bool ab_needed = - force_afterburn || targ->GetVelocity().MagnitudeSquared() > parent->GetComputerData().max_speed(); + force_afterburn || targ->GetVelocity().MagnitudeSquared() > parent->MaxSpeed(); if (r.Dot(relloc) < 0) { FaceTargetITTS::Execute(); m.SetAfterburn(afterburn && ab_needed); @@ -530,11 +529,10 @@ class FacePerpendicular : public Orders::FaceTargetITTS { Vector r = targ->cumulative_transformation_matrix.getR(); bool afterburn = useAfterburner() && this->afterburn; bool ab_needed = - force_afterburn || targ->GetVelocity().MagnitudeSquared() > parent->GetComputerData().max_speed(); + force_afterburn || targ->GetVelocity().MagnitudeSquared() > parent->MaxSpeed(); m.SetDesiredVelocity(Vector(0, 0, afterburn - && ab_needed ? parent->GetComputerData().max_ab_speed() - : parent->GetComputerData(). - max_speed()), true); + && ab_needed ? parent->MaxAfterburnerSpeed() + : parent->MaxSpeed()), true); float speed, grange = 0, mrange = 0; parent->getAverageGunSpeed(speed, grange, mrange); if (r.Dot(relloc) < 0) { @@ -585,7 +583,7 @@ void RollLeft(Order *aisc, Unit *un) { if (un->aistate) { AddOrd(un->aistate, un, - new Orders::ExecuteFor(new Orders::MatchRoll(un->GetComputerData().max_roll_right, false), 1.0f)); + new Orders::ExecuteFor(new Orders::MatchRoll(un->drive.max_roll_right, false), 1.0f)); } } @@ -593,7 +591,7 @@ void RollRight(Order *aisc, Unit *un) { if (un->aistate) { AddOrd(un->aistate, un, - new Orders::ExecuteFor(new Orders::MatchRoll(-un->GetComputerData().max_roll_left, false), 1.0f)); + new Orders::ExecuteFor(new Orders::MatchRoll(-un->drive.max_roll_left, false), 1.0f)); } } @@ -602,7 +600,7 @@ void RollLeftHard(Order *aisc, Unit *un) { if (un->aistate) { AddOrd(un->aistate, un, - new Orders::ExecuteFor(new Orders::MatchRoll(un->GetComputerData().max_roll_right, false), durvar)); + new Orders::ExecuteFor(new Orders::MatchRoll(un->drive.max_roll_right, false), durvar)); } } @@ -611,7 +609,7 @@ void RollRightHard(Order *aisc, Unit *un) { if (un->aistate) { AddOrd(un->aistate, un, - new Orders::ExecuteFor(new Orders::MatchRoll(-un->GetComputerData().max_roll_left, false), durvar)); + new Orders::ExecuteFor(new Orders::MatchRoll(-un->drive.max_roll_left, false), durvar)); } } diff --git a/engine/src/cmd/ai/navigation.cpp b/engine/src/cmd/ai/navigation.cpp index 5e75f06f73..8926c81a4b 100644 --- a/engine/src/cmd/ai/navigation.cpp +++ b/engine/src/cmd/ai/navigation.cpp @@ -171,10 +171,10 @@ bool MoveToParent::Execute(Unit *parent, const QVector &targetlocation) { last_velocity = local_vel; Vector heading = parent->ToLocalCoordinates((targetlocation - parent->Position()).Cast()); - Vector thrust(parent->limits.lateral, parent->limits.vertical, - afterburn ? parent->limits.afterburn : parent->limits.forward); + Vector thrust(parent->drive.lateral, parent->drive.vertical, + afterburn ? parent->afterburner.thrust : parent->drive.forward); float max_speed = - (afterburn ? parent->GetComputerData().max_ab_speed() : parent->GetComputerData().max_speed()); + (afterburn ? parent->MaxAfterburnerSpeed() : parent->MaxSpeed()); Vector normheading = heading; normheading.Normalize(); Vector max_velocity = max_speed * normheading; @@ -222,18 +222,18 @@ bool MoveToParent::Execute(Unit *parent, const QVector &targetlocation) { } //start with Forward/Reverse: float t = - CalculateDecelTime(heading.k, last_velocity.k, thrust.k, parent->limits.retro / div, parent->getMass()); + CalculateDecelTime(heading.k, last_velocity.k, thrust.k, parent->drive.retro / div, parent->getMass()); if (t < THRESHOLD) { thrust.k = - (thrust.k > 0 ? -parent->limits.retro - / div : (afterburn ? parent->limits.afterburn / div : parent->limits.forward / div)); + (thrust.k > 0 ? -parent->drive.retro + / div : (afterburn ? parent->afterburner.thrust / div : parent->drive.forward / div)); } else if (t < simulation_atom_var) { thrust.k *= t / simulation_atom_var; thrust.k += (simulation_atom_var - t) - * (thrust.k > 0 ? -parent->limits.retro - / div : (afterburn ? parent->limits.afterburn / div : parent->limits.forward / div)) + * (thrust.k > 0 ? -parent->drive.retro + / div : (afterburn ? parent->afterburner.thrust / div : parent->drive.forward / div)) / simulation_atom_var; } OptimizeSpeed(parent, last_velocity.k, thrust.k, max_velocity.k / vdiv); @@ -349,7 +349,7 @@ void ChangeHeading::Execute() { bool cheater = false; static float min_for_no_oversteer = XMLSupport::parse_float(vs_config->getVariable("AI", "min_angular_accel_cheat", "50")); - if (AICheat && ((parent->limits.yaw + parent->limits.pitch) * 180 / (PI * parent->getMass()) > min_for_no_oversteer) + if (AICheat && ((parent->drive.yaw + parent->drive.pitch) * 180 / (PI * parent->getMass()) > min_for_no_oversteer) && !parent->isSubUnit()) { if (xswitch || yswitch) { Vector P, Q, R; @@ -388,7 +388,7 @@ void ChangeHeading::Execute() { if (done /*||(xswitch&&yswitch)*/) { return; } - Vector torque(parent->limits.pitch, parent->limits.yaw, 0); //set torque to max accel in any direction + Vector torque(parent->drive.pitch, parent->drive.yaw, 0); //set torque to max accel in any direction if (terminatingX > switchbacks && terminatingY > switchbacks) { if (Done(local_velocity)) { if (this->terminating) { @@ -404,14 +404,14 @@ void ChangeHeading::Execute() { TurnToward(atan2(local_heading.j, local_heading.k), local_velocity.i, torque.i); //find angle away from axis 0,0,1 in yz plane - OptimizeAngSpeed(turningspeed * parent->GetComputerData().max_pitch_down, - turningspeed * parent->GetComputerData().max_pitch_up, + OptimizeAngSpeed(turningspeed * parent->drive.max_pitch_down, + turningspeed * parent->drive.max_pitch_up, local_velocity.i, torque.i); TurnToward(atan2(local_heading.i, local_heading.k), -local_velocity.j, torque.j); torque.j = -torque.j; - OptimizeAngSpeed(turningspeed * parent->GetComputerData().max_yaw_left, - turningspeed * parent->GetComputerData().max_yaw_right, + OptimizeAngSpeed(turningspeed * parent->drive.max_yaw_left, + turningspeed * parent->drive.max_yaw_right, local_velocity.j, torque.j); torque.k = -parent->GetMoment() * local_velocity.k / simulation_atom_var; //try to counteract roll; @@ -506,9 +506,8 @@ void AutoLongHaul::MakeLinearVelocityOrder() { XMLSupport::parse_float(vs_config->getVariable("auto_physics", "auto_docking_speed_boost", "20")); float speed = - parent->GetComputerData().combat_mode ? parent->GetComputerData().max_combat_speed - : parent->GetComputerData(). - max_combat_ab_speed /*won't do insanity flight mode + spec = ludicrous speed*/; + parent->GetComputerData().combat_mode ? parent->drive.speed + : parent->afterburner.speed /*won't do insanity flight mode + spec = ludicrous speed*/; if (inside_landing_zone) { speed *= combat_mode_mult; } @@ -568,7 +567,7 @@ bool useJitteryAutopilot(Unit *parent, Unit *target, float minaccel) { if (parent->computer.combat_mode == false) { return true; } - float maxspeed = parent->GetComputerData().max_combat_ab_speed; + float maxspeed = parent->afterburner.speed; static float accel_auto_limit = XMLSupport::parse_float(vs_config->getVariable("physics", "max_accel_for_smooth_autopilot", "10")); static float speed_auto_limit = @@ -587,7 +586,7 @@ bool AutoLongHaul::InsideLandingPort(const Unit *obstacle) const { XMLSupport::parse_float(vs_config->getVariable("physics", "auto_landing_port_unclamped_seconds", "120")); return UnitUtil::getSignificantDistance(parent, obstacle) - < -landing_port_limit * parent->GetComputerData().max_combat_ab_speed; + < -landing_port_limit * parent->afterburner.speed; } void AutoLongHaul::Execute() { @@ -685,8 +684,8 @@ void AutoLongHaul::Execute() { } float mass = parent->getMass(); float minaccel = - mymin(parent->limits.lateral, - mymin(parent->limits.vertical, mymin(parent->limits.forward, parent->limits.retro))); + mymin(parent->drive.lateral, + mymin(parent->drive.vertical, mymin(parent->drive.forward, parent->drive.retro))); if (mass) { minaccel /= mass; } @@ -710,7 +709,7 @@ void AutoLongHaul::Execute() { deactivatewarp = true; } float maxspeed = - mymax(speed, parent->graphicOptions.WarpFieldStrength * parent->GetComputerData().max_combat_ab_speed); + mymax(speed, parent->graphicOptions.WarpFieldStrength * parent->afterburner.speed); double dis = UnitUtil::getSignificantDistance(parent, target); float time_to_destination = dis / maxspeed; @@ -749,10 +748,10 @@ void AutoLongHaul::Execute() { static bool do_auto_finish = XMLSupport::parse_bool(vs_config->getVariable("physics", "autopilot_terminate", "true")); bool stopnow = false; - maxspeed = parent->GetComputerData().max_combat_ab_speed; - if (maxspeed && parent->limits.retro) { + maxspeed = parent->afterburner.speed; + if (maxspeed && parent->drive.retro) { float time_to_destination = dis / maxspeed; //conservative - float time_to_stop = speed * mass / parent->limits.retro; + float time_to_stop = speed * mass / parent->drive.retro; if (time_to_destination <= time_to_stop) { stopnow = true; } diff --git a/engine/src/cmd/ai/script.cpp b/engine/src/cmd/ai/script.cpp index 33849ff00c..149a7d591a 100644 --- a/engine/src/cmd/ai/script.cpp +++ b/engine/src/cmd/ai/script.cpp @@ -811,8 +811,8 @@ void AIScript::LoadXML() { } if (_Universe->isPlayerStarship(parent->Target())) { float value; - static float game_speed = XMLSupport::parse_float(vs_config->getVariable("physics", "game_speed", "1")); - static float game_accel = XMLSupport::parse_float(vs_config->getVariable("physics", "game_accel", "1")); + static const double game_speed = configuration()->physics_config.game_speed; + static const double game_accel = configuration()->physics_config.game_accel; { Unit *targ = parent->Target(); if (targ) { @@ -822,7 +822,7 @@ void AIScript::LoadXML() { float myvel = pdmag > 0 ? PosDifference.Dot(parent->GetVelocity() - targ->GetVelocity()) / pdmag : 0; if (myvel > 0) { - value -= myvel * myvel / (2 * (parent->limits.retro / parent->getMass())); + value -= myvel * myvel / (2 * (parent->drive.retro / parent->getMass())); } } else { value = 10000; diff --git a/engine/src/cmd/ai/warpto.cpp b/engine/src/cmd/ai/warpto.cpp index 4ba894886f..e041070bed 100644 --- a/engine/src/cmd/ai/warpto.cpp +++ b/engine/src/cmd/ai/warpto.cpp @@ -44,7 +44,7 @@ bool DistanceWarrantsWarpTo(Unit *parent, float dist, bool following) { float toodamnclose = following ? tooclosefollowing : tooclose; float diff = 1; parent->GetVelocityDifficultyMult(diff); - float timetolive = dist / (diff * parent->GetComputerData().max_combat_speed); + float timetolive = dist / (diff * parent->drive.speed); if (timetolive > (5 * max_allowable_travel_time())) { return true; } else if (timetolive > (max_allowable_travel_time())) { @@ -69,7 +69,7 @@ bool DistanceWarrantsTravelTo(Unit *parent, float dist, bool following) { //first let us decide whether the target is far enough to warrant using warp float diff = 1; parent->GetVelocityDifficultyMult(diff); - float timetolive = dist / (diff * parent->GetComputerData().max_combat_speed); + float timetolive = dist / (diff * parent->drive.speed); if (timetolive > max_allowable_travel_time()) { return true; } diff --git a/engine/src/cmd/basecomputer.cpp b/engine/src/cmd/basecomputer.cpp index 57974c6316..7584181e9d 100644 --- a/engine/src/cmd/basecomputer.cpp +++ b/engine/src/cmd/basecomputer.cpp @@ -62,7 +62,7 @@ using VSFileSystem::SaveFile; #include "facet_configuration.h" #include "vs_logging.h" #include "controls_factory.h" - +#include "configuration/configuration.h" //for directory thing #if defined (_WIN32) && !defined (__CYGWIN__) @@ -3940,7 +3940,9 @@ string buildUpgradeDescription(Cargo &item) { current_unit_load_mode = DEFAULT; string str = ""; str += item.GetDescription(); + showUnitStats(newPart, str, 0, 1, item); + newPart->Kill(); // delete newPart; return str; @@ -4631,8 +4633,6 @@ static const char *WeaponTypeStrings[] = { void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, Cargo &item) { static Unit *blankUnit = new Unit("upgrading_dummy_unit", 1, FactionUtil::GetFactionIndex("upgrades")); - static float - warpenratio = XMLSupport::parse_float(vs_config->getVariable("physics", "warp_energy_multiplier", "0.12")); static float shield_maintenance_cost = XMLSupport::parse_float(vs_config->getVariable("physics", "shield_maintenance_charge", ".25")); static bool shields_require_power = @@ -4642,7 +4642,6 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C static float shieldenergycap = XMLSupport::parse_float(vs_config->getVariable("physics", "shield_energy_capacitance", ".2")); - float Wconv = warpenratio == 0.0 ? 0.0 : (1.0 / warpenratio); //converts from reactor to warp energy scales char conversionBuffer[128]; string prefix = ""; for (int i = 0; i < subunitlevel; i++) { @@ -4652,7 +4651,7 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C static float kj_per_unit_damage = XMLSupport::parse_float(vs_config->getVariable("physics", "kilojoules_per_unit_damage", "5400")); float VSDM = kj_per_unit_damage / 1000.0; - float RSconverter = 100; //100MJ per reactor or shield recharge energy unit + float RSconverter = configuration()->fuel.megajoules_factor; //100MJ per reactor or shield recharge energy unit float totalWeaponEnergyUsage = 0; float totalWeaponDamage = 0; string MPLdesc = ""; @@ -4792,7 +4791,9 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C if (!mode) { - PRETTY_ADDU(statcolor + "Fuel capacity: #-c", playerUnit->fuelData(), 2, "metric tons of Lithium-6"); + double f = playerUnit->fuelData(); + double mod = configuration()->fuel.fuel_ton_modifier; + PRETTY_ADDU(statcolor + "Fuel capacity: #-c", f * mod, 2, "metric tons of Lithium-6"); } const Computer &uc = playerUnit->ViewComputerData(); @@ -4801,17 +4802,18 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C text += "#n##n#" + prefix + "#c0:1:.5#[FLIGHT CHARACTERISTICS]#n##-c"; text += "#n#" + prefix + statcolor + "Turning response: #-c"; } - if (playerUnit->limits.yaw == playerUnit->limits.pitch && playerUnit->limits.yaw == playerUnit->limits.roll) { - prettyPrintFloat(conversionBuffer, playerUnit->limits.yaw + if (playerUnit->drive.yaw.MaxValue() == playerUnit->drive.pitch.MaxValue() && + playerUnit->drive.yaw.MaxValue() == playerUnit->drive.roll.MaxValue()) { + prettyPrintFloat(conversionBuffer, playerUnit->drive.yaw / ((playerUnit->GetMoment() != 0) ? playerUnit->GetMoment() : 1), 0, 4); if (!mode) { text += conversionBuffer; text += " radians/second^2#n#" + expstatcolor + " (yaw, pitch, roll)#-c"; - } else if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.yaw)) { + } else if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.yaw)) { switch (replacement_mode) { case 0: //Replacement or new Module PRETTY_ADDU(statcolor + "#n#Installs maneuvering jets with turning response #-c", - playerUnit->limits.yaw, + playerUnit->drive.yaw, 0, " radians/second^2#n#" + statcolor + " (yaw, pitch, roll)#-c"); break; @@ -4819,7 +4821,7 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C break; case 2: //multiplicative PRETTY_ADDU(statcolor + "#n#Increases turning response by #-c", - 100.0 * ((playerUnit->limits.yaw * 180 / PI) - 1), + 100.0 * ((playerUnit->drive.yaw * 180 / PI) - 1), 0, "%#n#" + statcolor + " (yaw, pitch, roll)#-c"); break; @@ -4831,34 +4833,34 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C } else { if (!mode) { float moment = (playerUnit->GetMoment() != 0) ? playerUnit->GetMoment() : 1; - PRETTY_ADDN(substatcolor + " yaw #-c", playerUnit->limits.yaw / (moment), 4); - PRETTY_ADDN(substatcolor + " pitch #-c", playerUnit->limits.pitch / (moment), 4); - PRETTY_ADDN(substatcolor + " roll #-c", playerUnit->limits.roll / (moment), 4); + PRETTY_ADDN(substatcolor + " yaw #-c", playerUnit->drive.yaw / (moment), 4); + PRETTY_ADDN(substatcolor + " pitch #-c", playerUnit->drive.pitch / (moment), 4); + PRETTY_ADDN(substatcolor + " roll #-c", playerUnit->drive.roll / (moment), 4); text += " radians/second^2"; - } else if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.yaw) - || MODIFIES(replacement_mode, playerUnit, blankUnit, limits.pitch) - || MODIFIES(replacement_mode, playerUnit, blankUnit, limits.roll)) { + } else if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.yaw) + || MODIFIES(replacement_mode, playerUnit, blankUnit, drive.pitch) + || MODIFIES(replacement_mode, playerUnit, blankUnit, drive.roll)) { switch (replacement_mode) { case 0: //Replacement or new Module text += "#n#Replaces existing maneuvering system with one rated at: #-c#n#"; - PRETTY_ADDN(substatcolor + "Yaw #-c", playerUnit->limits.yaw, 2); - PRETTY_ADDN(substatcolor + " Pitch #-c", playerUnit->limits.pitch, 2); - PRETTY_ADDN(substatcolor + " Roll #-c", playerUnit->limits.roll, 2); + PRETTY_ADDN(substatcolor + "Yaw #-c", playerUnit->drive.yaw, 2); + PRETTY_ADDN(substatcolor + " Pitch #-c", playerUnit->drive.pitch, 2); + PRETTY_ADDN(substatcolor + " Roll #-c", playerUnit->drive.roll, 2); text += " metric-ton*radians/second^2"; break; case 1: //Additive text += "#n#Upgrades existing maneuvering system by the following amounts: #-c#n#"; - PRETTY_ADDN(substatcolor + "Yaw #-c", playerUnit->limits.yaw, 2); - PRETTY_ADDN(substatcolor + " Pitch #-c", playerUnit->limits.pitch, 2); - PRETTY_ADDN(substatcolor + " Roll #-c", playerUnit->limits.roll, 2); + PRETTY_ADDN(substatcolor + "Yaw #-c", playerUnit->drive.yaw, 2); + PRETTY_ADDN(substatcolor + " Pitch #-c", playerUnit->drive.pitch, 2); + PRETTY_ADDN(substatcolor + " Roll #-c", playerUnit->drive.roll, 2); text += " metric-ton*radians/second^2"; break; case 2: //multiplicative text += "#n#Increases performance of existing maneuvering system by the following percentages: #-c#n#"; - PRETTY_ADDN(substatcolor + "Yaw #-c", 100.0 * ((playerUnit->limits.yaw * 180 / PI) - 1), 0); - PRETTY_ADDN(substatcolor + " Pitch #-c", 100.0 * ((playerUnit->limits.pitch * 180 / PI) - 1), 0); - PRETTY_ADDN(substatcolor + " Roll #-c", 100.0 * ((playerUnit->limits.roll * 180 / PI) - 1), 0); + PRETTY_ADDN(substatcolor + "Yaw #-c", 100.0 * ((playerUnit->drive.yaw * 180 / PI) - 1), 0); + PRETTY_ADDN(substatcolor + " Pitch #-c", 100.0 * ((playerUnit->drive.pitch * 180 / PI) - 1), 0); + PRETTY_ADDN(substatcolor + " Roll #-c", 100.0 * ((playerUnit->drive.roll * 180 / PI) - 1), 0); break; default: //Failure text += "Oh dear, this wasn't an upgrade. Please debug code."; @@ -4869,118 +4871,118 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C if (!subunitlevel) { if (!mode && (playerUnit->getMass() != 0)) { PRETTY_ADDU(statcolor + "Fore acceleration: #-c", - playerUnit->limits.forward / (9.8 * playerUnit->getMass()), 2, "gravities"); + playerUnit->drive.forward / (9.8 * playerUnit->getMass()), 2, "gravities"); PRETTY_ADDU(statcolor + "Aft acceleration: #-c", - playerUnit->limits.retro / (9.8 * playerUnit->getMass()), 2, "gravities"); - if (playerUnit->limits.lateral == playerUnit->limits.vertical) { + playerUnit->drive.retro / (9.8 * playerUnit->getMass()), 2, "gravities"); + if (playerUnit->drive.lateral.MaxValue() == playerUnit->drive.vertical.MaxValue()) { PRETTY_ADDU(statcolor + "Orthogonal acceleration: #-c", - playerUnit->limits.vertical / (9.8 * playerUnit->getMass()), 2, "gravities"); + playerUnit->drive.vertical / (9.8 * playerUnit->getMass()), 2, "gravities"); text += expstatcolor + "#n# (vertical and lateral axes)#-c"; } else { PRETTY_ADDN(statcolor + " Lateral acceleration #-c", - playerUnit->limits.lateral / (9.8 * playerUnit->getMass()), + playerUnit->drive.lateral / (9.8 * playerUnit->getMass()), 2); PRETTY_ADDN(statcolor + " Vertical acceleration #-c", - playerUnit->limits.vertical / (9.8 * playerUnit->getMass()), 2); + playerUnit->drive.vertical / (9.8 * playerUnit->getMass()), 2); text += " gravities"; } - PRETTY_ADDU(statcolor + "Forward acceleration with overthrust: #-c", playerUnit->limits.afterburn + PRETTY_ADDU(statcolor + "Forward acceleration with overthrust: #-c", playerUnit->afterburner.thrust / (9.8 * playerUnit->getMass()), 2, "gravities"); text.append("#n##n##c0:1:.5#" + prefix + "[GOVERNOR SETTINGS]#n##-c"); } else { switch (replacement_mode) { case 0: //Replacement or new Module - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.forward)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.forward)) { PRETTY_ADDU(statcolor + "Provides forward thrust rated at: #-c", - playerUnit->limits.forward / 1000.0, + playerUnit->drive.forward / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.retro)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.retro)) { PRETTY_ADDU(statcolor + "Provides aftward thrust rated at: #-c", - playerUnit->limits.retro / 1000.0, + playerUnit->drive.retro / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.vertical)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.vertical)) { PRETTY_ADDU(statcolor + "Provides vertical thrust rated at: #-c", - playerUnit->limits.vertical / 1000.0, + playerUnit->drive.vertical / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.lateral)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.lateral)) { PRETTY_ADDU(statcolor + "Provides lateral thrust rated at: #-c", - playerUnit->limits.lateral / 1000.0, + playerUnit->drive.lateral / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.afterburn)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, afterburner.thrust)) { PRETTY_ADDU(statcolor + "Overdrive thrust rated at: #-c", - playerUnit->limits.afterburn / 1000.0, + playerUnit->afterburner.thrust / 1000.0, 2, "MegaNewtons"); } break; case 1: //Additive - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.forward)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.forward)) { PRETTY_ADDU(statcolor + "Increases forward thrust rating by: #-c", - playerUnit->limits.forward / 1000.0, + playerUnit->drive.forward / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.retro)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.retro)) { PRETTY_ADDU(statcolor + "Increases aftward thrust rating by: #-c", - playerUnit->limits.retro / 1000.0, + playerUnit->drive.retro / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.vertical)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.vertical)) { PRETTY_ADDU(statcolor + "Increases vertical thrust rating by: #-c", - playerUnit->limits.vertical / 1000.0, + playerUnit->drive.vertical / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.lateral)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.lateral)) { PRETTY_ADDU(statcolor + "Increases lateral thrust rating by: #-c", - playerUnit->limits.lateral / 1000.0, + playerUnit->drive.lateral / 1000.0, 2, "MegaNewtons"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.afterburn)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, afterburner.thrust)) { PRETTY_ADDU(statcolor + "Increases overdrive thrust rating by: #-c", - playerUnit->limits.afterburn / 1000.0, + playerUnit->afterburner.thrust / 1000.0, 2, "MegaNewtons"); } break; case 2: //multiplicative - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.forward)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.forward)) { PRETTY_ADDU(statcolor + "Increases forward thrust rating by: #-c", - (playerUnit->limits.forward - 1) * 100, + (playerUnit->drive.forward - 1) * 100, 0, "%"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.retro)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.retro)) { PRETTY_ADDU(statcolor + "Increases aftward thrust rating by: #-c", - (playerUnit->limits.retro - 1) * 100, + (playerUnit->drive.retro - 1) * 100, 0, "%"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.vertical)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.vertical)) { PRETTY_ADDU(statcolor + "Increases vertical thrust rating by: #-c", - (playerUnit->limits.vertical - 1) * 100, + (playerUnit->drive.vertical - 1) * 100, 0, "%"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.lateral)) { + if (MODIFIES(replacement_mode, playerUnit, blankUnit, drive.lateral)) { PRETTY_ADDU(statcolor + "Increases lateral thrust rating by: #-c", - (playerUnit->limits.lateral - 1) * 100, + (playerUnit->drive.lateral - 1) * 100, 0, "%"); } - if (MODIFIES(replacement_mode, playerUnit, blankUnit, limits.afterburn)) + if (MODIFIES(replacement_mode, playerUnit, blankUnit, afterburner.thrust)) PRETTY_ADDU(statcolor + "Overdrive thrust rating by: #-c", - (playerUnit->limits.afterburn - 1) * 100, + (playerUnit->afterburner.thrust - 1) * 100, 0, "%"); break; @@ -4992,94 +4994,24 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C static float non_combat_mode_mult = XMLSupport::parse_float(vs_config->getVariable("physics", "combat_speed_boost", "100")); if (!mode) { - PRETTY_ADDU(statcolor + "Max combat speed: #-c", uc.max_speed(), 0, "m/s"); - PRETTY_ADDU(statcolor + "Max overdrive combat speed: #-c", uc.max_ab_speed(), 0, "m/s"); - PRETTY_ADDU(statcolor + "Max non-combat speed: #-c", uc.max_speed() * non_combat_mode_mult, 0, "m/s"); - } else { - switch (replacement_mode) { - case 0: //Replacement or new Module - if (MODIFIES(replacement_mode, &uc, &buc, max_speed())) { - PRETTY_ADDU(statcolor + "Sets max combat speed governor to: #-c", uc.max_speed(), 0, "m/s"); - PRETTY_ADDU(statcolor + "Sets max non-combat speed governor to: #-c", - uc.max_speed() * non_combat_mode_mult, 0, "m/s"); - } - if (MODIFIES(replacement_mode, &uc, &buc, max_ab_speed())) - PRETTY_ADDU(statcolor + "Sets max overdrive combat speed governor to: #-c", - uc.max_ab_speed(), - 0, - "m/s"); - break; - case 1: //Additive - if (MODIFIES(replacement_mode, &uc, &buc, max_speed())) { - PRETTY_ADDU(statcolor + "Increases max combat speed governor setting by: #-c", - uc.max_speed(), - 0, - "m/s"); - PRETTY_ADDU(statcolor + "Increases max non-combat speed governor setting by: #-c", - uc.max_speed() * non_combat_mode_mult, 0, "m/s"); - } - if (MODIFIES(replacement_mode, &uc, &buc, max_ab_speed())) - PRETTY_ADDU(statcolor + "Increases max overdrive combat speed governor setting by: #-c", - uc.max_ab_speed(), 0, "m/s"); - break; - case 2: //multiplicative - if (MODIFIES(replacement_mode, &uc, &buc, max_speed())) { - PRETTY_ADDU(statcolor + "Increases max combat speed governor settings by: #-c", - 100.0 * (uc.max_speed() - 1), 0, "%"); - PRETTY_ADDU(statcolor + "Increases max non-combat speed governor settings by: #-c", - 100.0 * (uc.max_speed() - 1), 0, "%"); - } - if (MODIFIES(replacement_mode, &uc, &buc, max_ab_speed())) - PRETTY_ADDU(statcolor + "Increases max overdrive combat speed governor settings by: #-c", - (uc.max_ab_speed() - 1) * 100, 0, "%"); - break; - default: //Failure - text += "Oh dear, this wasn't an upgrade. Please debug code."; - break; - } + PRETTY_ADDU(statcolor + "Max combat speed: #-c", playerUnit->MaxSpeed(), 0, "m/s"); + PRETTY_ADDU(statcolor + "Max overdrive combat speed: #-c", playerUnit->MaxAfterburnerSpeed(), 0, "m/s"); + PRETTY_ADDU(statcolor + "Max non-combat speed: #-c", playerUnit->MaxSpeed() * non_combat_mode_mult, 0, "m/s"); } } if (!mode) { - if (uc.max_yaw_right == uc.max_pitch_up && uc.max_yaw_right == uc.max_roll_right) { - PRETTY_ADD(statcolor + "Max turn rate: #-c", uc.max_yaw_right, 2); + if (playerUnit->drive.max_yaw_right.MaxValue() == playerUnit->drive.max_pitch_up.MaxValue() && + playerUnit->drive.max_yaw_right.MaxValue() == playerUnit->drive.max_roll_right.MaxValue()) { + PRETTY_ADD(statcolor + "Max turn rate: #-c", playerUnit->drive.max_yaw_right, 2); text += " radians/second " + expstatcolor + "(yaw, pitch, roll)#-c"; } else { text += ("#n#" + prefix + statcolor + "Max turn rates:#-c"); - PRETTY_ADDU(substatcolor + " - yaw: #-c", uc.max_yaw_right, 2, "radians/second"); - PRETTY_ADDU(substatcolor + " - pitch: #-c", uc.max_pitch_up, 2, "radians/second"); - PRETTY_ADDU(substatcolor + " - roll: #-c", uc.max_roll_right, 2, "radians/second"); + PRETTY_ADDU(substatcolor + " - yaw: #-c", playerUnit->drive.max_yaw_right, 2, "radians/second"); + PRETTY_ADDU(substatcolor + " - pitch: #-c", playerUnit->drive.max_pitch_up, 2, "radians/second"); + PRETTY_ADDU(substatcolor + " - roll: #-c", playerUnit->drive.max_roll_right, 2, "radians/second"); } text += "#n##n##c0:1:.5#" + prefix + "[TARGETTING SUBSYSTEM]#n##-c"; - } else if (MODIFIES(replacement_mode, &uc, &buc, max_yaw_right) - || MODIFIES(replacement_mode, &uc, &buc, max_pitch_up) - || MODIFIES(replacement_mode, &uc, &buc, max_roll_right)) { - switch (replacement_mode) { - case 0: //Replacement or new Module - text += ("#n#" + prefix + "Governor settings for maximum turn rates set to: "); - PRETTY_ADDN(substatcolor + " yaw #-c", uc.max_yaw_right, 2); - PRETTY_ADDN(substatcolor + " pitch #-c", uc.max_pitch_up, 2); - PRETTY_ADDN(substatcolor + " roll #-c", uc.max_roll_right, 2); - text += " radians/second"; - break; - case 1: //Additive - text += ("#n#" + prefix + "Governor settings for maximum turn rates increased by: "); - PRETTY_ADDN(substatcolor + " yaw #-c", uc.max_yaw_right, 2); - PRETTY_ADDN(substatcolor + " pitch #-c", uc.max_pitch_up, 2); - PRETTY_ADDN(substatcolor + " roll #-c", uc.max_roll_right, 2); - text += " radians/second"; - break; - case 2: //multiplicative - text += ("#n#" + substatcolor + "Increases governor settings for maximum turn rates by: #-c"); - PRETTY_ADDN(substatcolor + " yaw #-c", 100.0 * ((uc.max_yaw_right * 180 / PI) - 1), 0); - PRETTY_ADDN(substatcolor + " pitch #-c", 100.0 * ((uc.max_pitch_up * 180 / PI) - 1), 0); - PRETTY_ADDN(substatcolor + " roll #-c", 100.0 * ((uc.max_roll_right * 180 / PI) - 1), 0); - text += " %"; - break; - default: //Failure - text += "Oh dear, this wasn't an upgrade. Please debug code."; - break; - } - } + } if (!mode) { PRETTY_ADDU(statcolor + "Tracking range: #-c", uc.radar.maxrange / 1000, 0, "km"); if ((acos(uc.radar.maxcone) * 360 / PI) < 359) { @@ -5167,19 +5099,19 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C maxshield = 0; } PRETTY_ADDU(statcolor + "Recharge: #-c", playerUnit->reactor.Capacity() * RSconverter, 0, "MJ/s"); - PRETTY_ADDU(statcolor + "Weapon capacitor bank storage: #-c", - ((playerUnit->maxEnergyData() - maxshield) * RSconverter), 0, "MJ"); - //note: I found no function to get max warp energy, but since we're docked they are the same + PRETTY_ADDU(statcolor + "Main capacitor bank storage: #-c", + playerUnit->energy.MaxLevel() * RSconverter, 0, "MJ"); + if (!subunitlevel) { - PRETTY_ADDU(statcolor + "Warp capacitor bank storage: #-c", - playerUnit->ftl_energy.MaxLevel() * RSconverter * Wconv, + PRETTY_ADDU(statcolor + "SPEC capacitor bank storage: #-c", + playerUnit->ftl_energy.MaxLevel() * RSconverter, 0, "MJ"); text += "#n##n##c0:1:.5#" + prefix + "[SPEC SUBSYSTEM]#n##-c"; PRETTY_ADDU(statcolor + "Active SPEC Energy Requirements: #-c", - ftl.GetConsumption() * RSconverter * Wconv, + ftl.GetConsumption() * RSconverter, 0, "MJ/s"); @@ -5188,7 +5120,7 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C text += "#n##c1:.3:.3#No outsystem jump drive present#-c"; //fixed?? } else { PRETTY_ADDU(statcolor + "Energy cost for jumpnode travel: #-c", - uj.GetConsumption() * RSconverter * Wconv, + uj.GetConsumption() * RSconverter, 0, "MJ"); if (uj.Delay() > 0) @@ -5198,7 +5130,7 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C if (playerUnit->ftl_energy.MaxLevel() < uj.GetAtomConsumption()) { text += "#n##c1:.3:.3#" + prefix + - "WARNING: Warp capacitor banks under capacity for jump: upgrade warp capacitance#-c"; + "WARNING: SPEC capacitor banks under capacity for jump: upgrade SPEC capacitance#-c"; } } } @@ -5212,8 +5144,8 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C PRETTY_ADDU(statcolor + "Installs main capacitor bank with storage capacity: #-c", (playerUnit->maxEnergyData() * RSconverter), 0, "MJ"); if (MODIFIES(replacement_mode, playerUnit, blankUnit, ftl_energy.MaxLevel())) - PRETTY_ADDU(statcolor + "Installs warp capacitor bank with storage capacity: #-c", - playerUnit->ftl_energy.MaxLevel() * RSconverter * Wconv, 0, "MJ"); + PRETTY_ADDU(statcolor + "Installs SPEC capacitor bank with storage capacity: #-c", + playerUnit->ftl_energy.MaxLevel() * RSconverter, 0, "MJ"); if (buj.Installed() && !uj.Installed()) { text += statcolor + "#n#Allows travel via Jump Points.#n#Consult your personal info screen for ship specific energy requirements. #-c"; @@ -5388,14 +5320,14 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C if (playerUnit->cloak.Capable()) { if (!mode) { PRETTY_ADDU(statcolor + "Cloaking device available, energy usage: #-c", - playerUnit->cloak.GetConsumption() * RSconverter * Wconv, + playerUnit->cloak.GetConsumption() * RSconverter, 0, "MJ/s"); } else { switch (replacement_mode) { case 0: //Replacement or new Module PRETTY_ADDU(statcolor + "Installs a cloaking device.#n# Activated energy usage: #-c", - playerUnit->cloak.GetConsumption() * RSconverter * Wconv, + playerUnit->cloak.GetConsumption() * RSconverter, 0, "MJ/s"); break; @@ -5563,7 +5495,7 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C maxshield = 0; } PRETTY_ADDU(statcolor + "Minimum time to reach full overthrust speed: #-c", - playerUnit->getMass() * uc.max_ab_speed() / playerUnit->limits.afterburn, 2, "seconds"); + playerUnit->getMass() * playerUnit->MaxAfterburnerSpeed() / playerUnit->afterburner.thrust, 2, "seconds"); //reactor float avail = (playerUnit->maxEnergyData() * RSconverter - maxshield * VSDM); @@ -5586,7 +5518,7 @@ void showUnitStats(Unit *playerUnit, string &text, int subunitlevel, int mode, C if (uj.Installed() && playerUnit->jump_drive.GetAtomConsumption() > playerUnit->ftl_energy.MaxLevel()) { text += "#n##c1:.3:.3#" + prefix + - "WARNING: Warp capacitor banks under capacity for jump: upgrade warp capacitance#-c"; + "WARNING: SPEC capacitor banks under capacity for jump: upgrade SPEC capacitance#-c"; } if (num_shields) { diff --git a/engine/src/cmd/computer.cpp b/engine/src/cmd/computer.cpp index 1f6b662e72..83d3d5f90e 100644 --- a/engine/src/cmd/computer.cpp +++ b/engine/src/cmd/computer.cpp @@ -32,33 +32,12 @@ Computer::Computer() : NavPoint(0, 0, 0), force_velocity_ref(false), threatlevel(0), set_speed(0), - max_combat_speed(1), - max_combat_ab_speed(1), - max_yaw_left(1), - max_yaw_right(1), - max_pitch_down(1), - max_pitch_up(1), - max_roll_left(1), - max_roll_right(1), slide_start(1), slide_end(1), itts(false), combat_mode(true) { } -float Computer::max_speed() const { - static float - combat_mode_mult = XMLSupport::parse_float(vs_config->getVariable("physics", "combat_speed_boost", "100")); - return (!combat_mode) ? combat_mode_mult * max_combat_speed : max_combat_speed; -} - -float Computer::max_ab_speed() const { - static float - combat_mode_mult = XMLSupport::parse_float(vs_config->getVariable("physics", "combat_speed_boost", "100")); - //same capped big speed as combat...else different - return (!combat_mode) ? combat_mode_mult * max_combat_speed : max_combat_ab_speed; -} - Computer::RADARLIM::RADARLIM() : maxrange(0), maxcone(-1), diff --git a/engine/src/cmd/computer.h b/engine/src/cmd/computer.h index 3ad4156c02..f455d96eba 100644 --- a/engine/src/cmd/computer.h +++ b/engine/src/cmd/computer.h @@ -107,26 +107,15 @@ class Computer { float threatlevel; //The speed the flybywire system attempts to maintain float set_speed; - //Computers limitation of speed - float max_combat_speed; - float max_combat_ab_speed; - //Computer's restrictions of YPR to limit space combat maneuvers - float max_yaw_left; - float max_yaw_right; - float max_pitch_down; - float max_pitch_up; - float max_roll_left; - float max_roll_right; + //Whether or not an 'lead' indicator appears in front of target unsigned char slide_start; unsigned char slide_end; bool itts; - //tells whether the speed is clamped draconian-like or not + + // In hud - Maneuver (true) Travel (false) bool combat_mode; - float max_speed() const; - float max_ab_speed() const; - Computer(); }; diff --git a/engine/src/cmd/drawable.cpp b/engine/src/cmd/drawable.cpp index 04e20c2678..58859f15d2 100644 --- a/engine/src/cmd/drawable.cpp +++ b/engine/src/cmd/drawable.cpp @@ -436,7 +436,7 @@ void Drawable::DrawNow(const Matrix &mato, float lod) { (un)->DrawNow(submat, lod); } } - float cmas = unit->computer.max_ab_speed() * unit->computer.max_ab_speed(); + float cmas = unit->MaxAfterburnerSpeed() * unit->MaxAfterburnerSpeed(); if (cmas == 0) { cmas = 1; } @@ -724,7 +724,7 @@ void Drawable::DrawHalo(bool on_screen, float apparent_size, Matrix wmat, Cloak float maxaccel = unit->GetMaxAccelerationInDirectionOf(wmat.getR(), true); Vector velocity = unit->GetVelocity(); - float cmas = unit->computer.max_ab_speed() * unit->computer.max_ab_speed(); + float cmas = unit->MaxAfterburnerSpeed() * unit->MaxAfterburnerSpeed(); if (cmas == 0) { cmas = 1; } diff --git a/engine/src/cmd/energetic.cpp b/engine/src/cmd/energetic.cpp index a57d766ade..48dd6b7b2f 100644 --- a/engine/src/cmd/energetic.cpp +++ b/engine/src/cmd/energetic.cpp @@ -42,7 +42,6 @@ Energetic::Energetic() : constrained_charge_to_shields(0.0f), sufficient_energy_to_recharge_shields(true), - afterburnenergy(0), afterburntype(0) { } @@ -73,48 +72,10 @@ float Energetic::getFuelUsage(bool afterburner) { return configuration()->fuel.normal_fuel_usage; } -/** - * @brief Energetic::WCWarpIsFuelHack - in Wing Commander, warp and fuel are the same variable. - * Therefore, we need to transfer from one to the other to maintain equality - * @param transfer_warp_to_fuel - true means fuel = warpenergy - */ -// TODO: this is still an ugly hack -void Energetic::WCWarpIsFuelHack(bool transfer_warp_to_fuel) { - Unit *unit = vega_dynamic_cast_ptr(this); - if (!configuration()->fuel.fuel_equals_warp) { - return; - } - if (transfer_warp_to_fuel) { - unit->fuel.SetLevel(unit->ftl_energy.Level()); - } else { - unit->ftl_energy.SetLevel(unit->fuel.Level()); - } -} -float Energetic::ExpendMomentaryFuelUsage(float magnitude) { - // TODO: have this make some kind of sense to someone other than the person who wrote the comment below. - //HACK this forces the reaction to be Li-6+D fusion with efficiency governed by the getFuelUsage function - float quantity = Energetic::getFuelUsage(false) * simulation_atom_var * magnitude * - configuration()->fuel.fmec_exit_velocity_inverse / configuration()->fuel.fuel_efficiency; - return ExpendFuel(quantity); -} -/** - * @brief expendFuel - reduce fuel by burning it - * @param quantity - requested quantity to use - * @return - actual quantity used - */ -float Energetic::ExpendFuel(double quantity) { - Unit *unit = vega_dynamic_cast_ptr(this); - return quantity * unit->fuel.Deplete(true, configuration()->fuel.normal_fuel_usage * quantity); -} - -float Energetic::getWarpEnergy() const { - const Unit *unit = vega_dynamic_cast_ptr(this); - return unit->ftl_energy.Level(); -} float Energetic::maxEnergyData() const { @@ -129,9 +90,6 @@ void Energetic::rechargeEnergy() { } } -void Energetic::setAfterburnerEnergy(float aft) { - afterburnenergy = aft; -} void Energetic::setEnergyRecharge(float enrech) { Unit *unit = vega_dynamic_cast_ptr(this); @@ -139,11 +97,6 @@ void Energetic::setEnergyRecharge(float enrech) { } -float Energetic::warpCapData() const { - const Unit *unit = vega_dynamic_cast_ptr(this); - return unit->ftl_energy.MaxLevel(); -} - // Basically max or current shield x 0.2 float Energetic::totalShieldEnergyCapacitance() const { const Unit *unit = vega_dynamic_cast_ptr(this); @@ -171,6 +124,8 @@ void Energetic::ExpendEnergy(const bool player_ship) { DecreaseWarpEnergyInWarp(); unit->reactor.Generate(); + + unit->drive.Consume(); } void Energetic::ExpendEnergy(float usage) { @@ -179,18 +134,6 @@ void Energetic::ExpendEnergy(float usage) { unit->energy.Deplete(true, usage); } -// The original code was a continuation of the comment above and simply unclear. -// I replaced it with a very simple model. -void Energetic::ExpendFuel() { - Unit *unit = vega_dynamic_cast_ptr(this); - - if (!configuration()->fuel.reactor_uses_fuel) { - return; - } - - const float fuel_usage = configuration()->fuel.fmec_exit_velocity_inverse * unit->reactor.Capacity() * simulation_atom_var; - unit->fuel.Deplete(true, fuel_usage); -} void Energetic::MaintainECM() { Unit *unit = vega_dynamic_cast_ptr(this); diff --git a/engine/src/cmd/energetic.h b/engine/src/cmd/energetic.h index 0ff4b43655..d7f462b444 100644 --- a/engine/src/cmd/energetic.h +++ b/engine/src/cmd/energetic.h @@ -37,14 +37,9 @@ class Energetic { static float getFuelUsage(bool afterburner); - void WCWarpIsFuelHack(bool transfer_warp_to_fuel); - float ExpendMomentaryFuelUsage(float magnitude); - float ExpendFuel(double quantity); void ExpendEnergy(const bool player_ship); void ExpendEnergy(float usage); void ExpendEnergyToRechargeShields(); - void ExpendFuel(); - float getWarpEnergy() const; float maxEnergyData() const; @@ -55,22 +50,19 @@ class Energetic { void rechargeEnergy(); void RechargeWarpCapacitors(const bool player_ship); - void setAfterburnerEnergy(float aft); void setEnergyRecharge(float enrech); float totalShieldEnergyCapacitance() const; static float VSDPercent(); - float warpCapData() const; - float WarpEnergyMultiplier(const bool player_ship); float constrained_charge_to_shields; bool sufficient_energy_to_recharge_shields; - float afterburnenergy; //short fix + // TODO: delete one and move the other to Afterburner class int afterburntype; //0--energy, 1--fuel //-1 means it is off. -2 means it doesn't exist. otherwise it's engaged to destination (positive number) }; diff --git a/engine/src/cmd/jump_capable.cpp b/engine/src/cmd/jump_capable.cpp index 1bd793f5a9..f56b8576b1 100644 --- a/engine/src/cmd/jump_capable.cpp +++ b/engine/src/cmd/jump_capable.cpp @@ -482,8 +482,8 @@ float JumpCapable::CalculateNearestWarpUnit(float minmultiplier, float JumpCapable::CourseDeviation(const Vector &OriginalCourse, const Vector &FinalCourse) const { const Unit *unit = vega_dynamic_cast_ptr(this); - if (unit->ViewComputerData().max_ab_speed() > .001) { - return (OriginalCourse - (FinalCourse)).Magnitude() / unit->ViewComputerData().max_ab_speed(); + if (unit->MaxAfterburnerSpeed() > .001) { + return (OriginalCourse - (FinalCourse)).Magnitude() / unit->MaxAfterburnerSpeed(); } else { return (FinalCourse - OriginalCourse).Magnitude(); } diff --git a/engine/src/cmd/mount.cpp b/engine/src/cmd/mount.cpp index 1fc446e494..baa158740e 100644 --- a/engine/src/cmd/mount.cpp +++ b/engine/src/cmd/mount.cpp @@ -330,8 +330,8 @@ bool Mount::PhysicsAlignedFire(Unit *caller, type->radial_speed, type->pulse_speed /*detonation_radius*/); if (!match_speed_with_target) { - temp->GetComputerData().max_combat_speed = type->speed + velocity.Magnitude(); - temp->GetComputerData().max_combat_ab_speed = type->speed + velocity.Magnitude(); + temp->drive.speed = type->speed + velocity.Magnitude(); + temp->afterburner.speed = type->speed + velocity.Magnitude(); } } else { Flightgroup *testfg = caller->getFlightgroup(); diff --git a/engine/src/cmd/movable.cpp b/engine/src/cmd/movable.cpp index d7acbde776..f420456c18 100644 --- a/engine/src/cmd/movable.cpp +++ b/engine/src/cmd/movable.cpp @@ -113,12 +113,14 @@ Vector Movable::GetNetAngularAcceleration() const { } float Movable::GetMaxAccelerationInDirectionOf(const Vector &ref, bool afterburn) const { + const Unit *unit = vega_dynamic_const_cast_ptr(this); + Vector p, q, r; GetOrientation(p, q, r); Vector lref(ref * p, ref * q, ref * r); - float tp = (lref.i == 0) ? 0 : fabs(Limits().lateral / lref.i); - float tq = (lref.j == 0) ? 0 : fabs(Limits().vertical / lref.j); - float tr = (lref.k == 0) ? 0 : fabs(((lref.k > 0) ? Limits().forward : Limits().retro) / lref.k); + float tp = (lref.i == 0) ? 0 : fabs(unit->drive.lateral.Value() / lref.i); + float tq = (lref.j == 0) ? 0 : fabs(unit->drive.vertical.Value() / lref.j); + float tr = (lref.k == 0) ? 0 : fabs(((lref.k > 0) ? unit->drive.forward.Value() : unit->drive.retro.Value()) / lref.k); float trqmin = (tr < tq) ? tr : tq; float tm = tp < trqmin ? tp : trqmin; return lref.Magnitude() * tm / Mass; @@ -154,6 +156,7 @@ void Movable::UpdatePhysics(const Transformation &trans, if (resolveforces) { //clamp velocity + // TODO: use resource class to do this more elegantly ResolveForces(trans, transmat); float velocity_max = configuration()->physics_config.velocity_max; if (Velocity.i > velocity_max) { @@ -258,6 +261,7 @@ void Movable::UpdatePhysics2(const Transformation &trans, } void Movable::Rotate(const Vector &axis) { + const Unit *unit = vega_dynamic_const_cast_ptr(this); double theta = axis.Magnitude(); double ootheta = 0; if (theta == 0) { @@ -270,10 +274,10 @@ void Movable::Rotate(const Vector &axis) { rot = identity_quaternion; } curr_physical_state.orientation *= rot; - if (limits.limitmin > -1) { + if (unit->limit_min > -1) { Matrix mat; curr_physical_state.orientation.to_matrix(mat); - if (limits.structurelimits.Dot(mat.getR()) < limits.limitmin) { + if (unit->structure_limits.Dot(mat.getR()) < unit->limit_min) { curr_physical_state.orientation = prev_physical_state.orientation; } } @@ -474,8 +478,6 @@ double Movable::GetMaxWarpFieldStrength(float rampmult) const { void Movable::FireEngines(const Vector &Direction /*unit vector... might default to "r"*/, float FuelSpeed, float FMass) { - Unit *unit = vega_dynamic_cast_ptr(this); - FMass = unit->ExpendFuel(FMass); NetForce += Direction * ((double)FuelSpeed * (double)FMass / GetElapsedTime()); } @@ -526,32 +528,30 @@ void Movable::ApplyLocalTorque(const Vector &torque) { } Vector Movable::MaxTorque(const Vector &torque) { + const Unit *unit = vega_dynamic_const_cast_ptr(this); + //torque is a normal - return torque * (Vector(copysign(limits.pitch, torque.i), - copysign(limits.yaw, torque.j), - copysign(limits.roll, torque.k)) * torque); + return torque * (Vector(copysign(unit->drive.pitch.Value(), torque.i), + copysign(unit->drive.yaw.Value(), torque.j), + copysign(unit->drive.roll.Value(), torque.k)) * torque); } Vector Movable::ClampTorque(const Vector &amt1) { Unit *unit = vega_dynamic_cast_ptr(this); Vector Res = amt1; - unit->WCWarpIsFuelHack(true); - float fuelclamp = (unit->fuel.Level() <= 0) ? configuration()->fuel.no_fuel_thrust : 1; - if (fabs(amt1.i) > fuelclamp * limits.pitch) { - Res.i = copysign(fuelclamp * limits.pitch, amt1.i); + if (fabs(amt1.i) > fuelclamp * unit->drive.pitch) { + Res.i = copysign(fuelclamp * unit->drive.pitch, amt1.i); } - if (fabs(amt1.j) > fuelclamp * limits.yaw) { - Res.j = copysign(fuelclamp * limits.yaw, amt1.j); + if (fabs(amt1.j) > fuelclamp * unit->drive.yaw) { + Res.j = copysign(fuelclamp * unit->drive.yaw, amt1.j); } - if (fabs(amt1.k) > fuelclamp * limits.roll) { - Res.k = copysign(fuelclamp * limits.roll, amt1.k); + if (fabs(amt1.k) > fuelclamp * unit->drive.roll) { + Res.k = copysign(fuelclamp * unit->drive.roll, amt1.k); } //1/5,000,000 m/s - unit->ExpendMomentaryFuelUsage(Res.Magnitude()); - unit->WCWarpIsFuelHack(false); return Res; } @@ -559,55 +559,66 @@ Vector Movable::ClampTorque(const Vector &amt1) { Vector Movable::ClampVelocity(const Vector &velocity, const bool afterburn) { const Unit *unit = vega_dynamic_const_cast_ptr(this); - float fuelclamp = (unit->fuel.Level() <= 0) ? configuration()->fuel.no_fuel_thrust : 1; - float abfuelclamp = (unit->fuel.Level() <= 0 || (unit->energy.Level() < unit->afterburnenergy * static_cast(simulation_atom_var))) ? configuration()->fuel.no_fuel_afterburn : 1; + double max_speed; + double magnitude = velocity.Magnitude(); - float limit = - afterburn ? (abfuelclamp - * (unit->computer.max_ab_speed() - - unit->computer.max_speed()) + (fuelclamp * unit->computer.max_speed())) : fuelclamp - * unit->computer.max_speed(); - float tmp = velocity.Magnitude(); - if (tmp > fabs(limit)) { - return velocity * (limit / tmp); + // If we're using afterburn and have enough energy + // TODO: Need to make sure somewhere that damage to Afterburner.speed does not + // reduce it below Drive.speed + if(afterburn && (unit->afterburner.CanConsume() || configuration()->fuel.no_fuel_afterburn)) { + max_speed = unit->MaxAfterburnerSpeed(); + } else if(unit->drive.CanConsume() ) { //|| configuration()->fuel.no_fuel_thrust) { + max_speed = unit->MaxSpeed(); + } else { + max_speed = 0; } + + if(magnitude > max_speed) { + return velocity * (max_speed / magnitude); + } + return velocity; } +// TODO: move somewhere (drive?) or do something more elegant. +// Would this be fixed by simply setting the Resource and getting the value back? +// Yes. If we use the drive resources, we don't need this. Vector Movable::ClampAngVel(const Vector &velocity) { const Unit *unit = vega_dynamic_const_cast_ptr(this); Vector res(velocity); if (res.i >= 0) { - if (res.i > unit->computer.max_pitch_down) { - res.i = unit->computer.max_pitch_down; + if (res.i > unit->drive.max_pitch_down.Value()) { + res.i = unit->drive.max_pitch_down.Value(); } - } else if (-res.i > unit->computer.max_pitch_up) { - res.i = -unit->computer.max_pitch_up; + } else if (-res.i > unit->drive.max_pitch_up.Value()) { + res.i = -unit->drive.max_pitch_up.Value(); } if (res.j >= 0) { - if (res.j > unit->computer.max_yaw_left) { - res.j = unit->computer.max_yaw_left; + if (res.j > unit->drive.max_yaw_left.Value()) { + res.j = unit->drive.max_yaw_left.Value(); } - } else if (-res.j > unit->computer.max_yaw_right) { - res.j = -unit->computer.max_yaw_right; + } else if (-res.j > unit->drive.max_yaw_right.Value()) { + res.j = -unit->drive.max_yaw_right.Value(); } if (res.k >= 0) { - if (res.k > unit->computer.max_roll_left) { - res.k = unit->computer.max_roll_left; + if (res.k > unit->drive.max_roll_left.Value()) { + res.k = unit->drive.max_roll_left.Value(); } - } else if (-res.k > unit->computer.max_roll_right) { - res.k = -unit->computer.max_roll_right; + } else if (-res.k > unit->drive.max_roll_right.Value()) { + res.k = -unit->drive.max_roll_right.Value(); } return res; } Vector Movable::MaxThrust(const Vector &amt1) { + const Unit *unit = vega_dynamic_const_cast_ptr(this); + //amt1 is a normal - return amt1 * (Vector(copysign(limits.lateral, amt1.i), - copysign(limits.vertical, amt1.j), - amt1.k > 0 ? limits.forward : -limits.retro) * amt1); + return amt1 * (Vector(copysign(unit->drive.lateral.Value(), amt1.i), + copysign(unit->drive.vertical.Value(), amt1.j), + amt1.k > 0 ? unit->drive.forward.Value() : -unit->drive.retro.Value()) * amt1); } //CMD_FLYBYWIRE depends on new version of Clampthrust... don't change without resolving it @@ -615,173 +626,115 @@ Vector Movable::MaxThrust(const Vector &amt1) { Vector Movable::ClampThrust(const Vector &amt1, bool afterburn) { Unit *unit = vega_dynamic_cast_ptr(this); - const bool WCfuelhack = configuration()->fuel.fuel_equals_warp; const bool finegrainedFuelEfficiency = configuration()->fuel.variable_fuel_consumption; - if (WCfuelhack) { - // TODO: just don't use fuel in WC - if (unit->fuel.Level() > unit->ftl_energy.Level()) { - unit->fuel.SetLevel(unit->ftl_energy.Level()); - } - if (unit->fuel.Level() < unit->ftl_energy.Level()) { - unit->ftl_energy.SetLevel(unit->fuel.Level()); - } - } - float instantenergy = unit->afterburnenergy * simulation_atom_var; - if ((unit->afterburntype == 0) && unit->energy.Level() < instantenergy) { - afterburn = false; - } - if ((unit->afterburntype == 1) && unit->fuel.Level() < 0) { - unit->fuel.Zero(); - afterburn = false; - } - if ((unit->afterburntype == 2) && unit->ftl_energy.Level() < 0) { - unit->ftl_energy.SetCapacity(0); - afterburn = false; - } - if (3 == unit->afterburntype) { //no afterburner -- we should really make these types an enum :-/ + + + if(!unit->afterburner.CanConsume()) { afterburn = false; } + + Vector Res = amt1; float fuelclamp = (unit->fuel.Level() <= 0) ? configuration()->fuel.no_fuel_thrust : 1; float abfuelclamp = (unit->fuel.Level() <= 0) ? configuration()->fuel.no_fuel_afterburn : 1; - if (fabs(amt1.i) > fabs(fuelclamp * limits.lateral)) { - Res.i = copysign(fuelclamp * limits.lateral, amt1.i); + if (fabs(amt1.i) > fabs(fuelclamp * unit->drive.lateral)) { + Res.i = copysign(fuelclamp * unit->drive.lateral, amt1.i); } - if (fabs(amt1.j) > fabs(fuelclamp * limits.vertical)) { - Res.j = copysign(fuelclamp * limits.vertical, amt1.j); + if (fabs(amt1.j) > fabs(fuelclamp * unit->drive.vertical)) { + Res.j = copysign(fuelclamp * unit->drive.vertical, amt1.j); } float ablimit = afterburn - ? ((limits.afterburn - limits.forward) * abfuelclamp + limits.forward * fuelclamp) - : limits.forward; + ? ((unit->afterburner.thrust - unit->drive.forward.Value()) * abfuelclamp + unit->drive.forward.Value() * fuelclamp) + : unit->drive.forward.Value(); if (amt1.k > ablimit) { Res.k = ablimit; } - if (amt1.k < -limits.retro) { - Res.k = -limits.retro; - } - const float Lithium6constant = configuration()->fuel.deuterium_relative_efficiency_lithium; - //1/5,000,000 m/s - const float FMEC_exit_vel_inverse = configuration()->fuel.fmec_exit_velocity_inverse; - if (unit->afterburntype == 2) { - //Energy-consuming afterburner - //HACK this forces the reaction to be Li-6+Li-6 fusion with efficiency governed by the getFuelUsage function - unit->ftl_energy.Deplete(true, unit->afterburnenergy * Energetic::getFuelUsage(afterburn) * simulation_atom_var * Res.Magnitude() - * FMEC_exit_vel_inverse / Lithium6constant); - } - if (3 == unit->afterburntype || unit->afterburntype == 1) { - //fuel-burning overdrive - uses afterburner efficiency. In NO_AFTERBURNER case, "afterburn" will always be false, so can reuse code. - //HACK this forces the reaction to be Li-6+Li-6 fusion with efficiency governed by the getFuelUsage function - unit->fuel.Deplete(true, - ((afterburn - && finegrainedFuelEfficiency) ? unit->afterburnenergy : Energetic::getFuelUsage(afterburn)) - * simulation_atom_var * Res.Magnitude() - * FMEC_exit_vel_inverse / Lithium6constant); -#ifndef __APPLE__ - if (ISNAN(unit->fuel.Level())) { - VS_LOG(error, "Fuel is NAN A"); - unit->fuel.Zero(); - } -#endif - } - if (unit->afterburntype == 0) { - //fuel-burning afterburner - uses default efficiency - appears to check for available energy? FIXME - //HACK this forces the reaction to be Li-6+Li-6 fusion with efficiency governed by the getFuelUsage function - unit->fuel.Deplete(true, unit->getFuelUsage(false) * simulation_atom_var * Res.Magnitude() * FMEC_exit_vel_inverse / Lithium6constant); -#ifndef __APPLE__ - if (ISNAN(unit->fuel.Level())) { - VS_LOG(error, "Fuel is NAN B"); - unit->fuel.Zero(); - } -#endif - } - if ((afterburn) && (unit->afterburntype == 0)) { - unit->energy.Deplete(true, instantenergy); + if (amt1.k < -unit->drive.retro) { + Res.k = -unit->drive.retro; } - if (WCfuelhack) { - // TODO: just don't use fuel in WC - if (unit->fuel.Level() > unit->ftl_energy.Level()) { - unit->fuel.SetLevel(unit->ftl_energy.Level()); - } - if (unit->fuel.Level() < unit->ftl_energy.Level()) { - unit->ftl_energy.SetLevel(unit->fuel.Level()); - } + + if (afterburn) { + unit->afterburner.Consume(); } + return Res; } void Movable::LateralThrust(float amt) { + const Unit *unit = vega_dynamic_const_cast_ptr(this); + if (amt > 1.0) { amt = 1.0; } if (amt < -1.0) { amt = -1.0; } - ApplyLocalForce(amt * limits.lateral * Vector(1, 0, 0)); + ApplyLocalForce(amt * unit->drive.lateral.Value() * Vector(1, 0, 0)); } void Movable::VerticalThrust(float amt) { + const Unit *unit = vega_dynamic_const_cast_ptr(this); + if (amt > 1.0) { amt = 1.0; } if (amt < -1.0) { amt = -1.0; } - ApplyLocalForce(amt * limits.vertical * Vector(0, 1, 0)); + ApplyLocalForce(amt * unit->drive.vertical.Value() * Vector(0, 1, 0)); } void Movable::LongitudinalThrust(float amt) { + const Unit *unit = vega_dynamic_const_cast_ptr(this); + if (amt > 1.0) { amt = 1.0; } if (amt < -1.0) { amt = -1.0; } - ApplyLocalForce(amt * limits.forward * Vector(0, 0, 1)); + ApplyLocalForce(amt * unit->drive.forward.Value() * Vector(0, 0, 1)); } void Movable::YawTorque(float amt) { - if (amt > limits.yaw) { - amt = limits.yaw; - } else if (amt < -limits.yaw) { - amt = -limits.yaw; + const Unit *unit = vega_dynamic_const_cast_ptr(this); + + if (amt > unit->drive.yaw.Value()) { + amt = unit->drive.yaw.Value(); + } else if (amt < -unit->drive.yaw.Value()) { + amt = -unit->drive.yaw.Value(); } ApplyLocalTorque(amt * Vector(0, 1, 0)); } void Movable::PitchTorque(float amt) { - if (amt > limits.pitch) { - amt = limits.pitch; - } else if (amt < -limits.pitch) { - amt = -limits.pitch; + const Unit *unit = vega_dynamic_const_cast_ptr(this); + + if (amt > unit->drive.pitch.Value()) { + amt = unit->drive.pitch.Value(); + } else if (amt < -unit->drive.pitch.Value()) { + amt = -unit->drive.pitch.Value(); } ApplyLocalTorque(amt * Vector(1, 0, 0)); } void Movable::RollTorque(float amt) { - if (amt > limits.roll) { - amt = limits.roll; - } else if (amt < -limits.roll) { - amt = -limits.roll; + const Unit *unit = vega_dynamic_const_cast_ptr(this); + + if (amt > unit->drive.roll.Value()) { + amt = unit->drive.roll.Value(); + } else if (amt < -unit->drive.roll.Value()) { + amt = -unit->drive.roll.Value(); } ApplyLocalTorque(amt * Vector(0, 0, 1)); } void Movable::Thrust(const Vector &amt1, bool afterburn) { Unit *unit = vega_dynamic_cast_ptr(this); - - if (unit->afterburntype == 0) { - afterburn = afterburn && unit->energy.Level() > unit->afterburnenergy * static_cast(simulation_atom_var); - } //SIMULATION_ATOM; ? - if (unit->afterburntype == 1) { - afterburn = afterburn && unit->fuel.Level() > 0; - } - if (unit->afterburntype == 2) { - afterburn = afterburn && unit->ftl_energy.Level() > 0; - } - - + afterburn = afterburn && unit->afterburner.CanConsume(); + //Unit::Thrust( amt1, afterburn ); { Vector amt = ClampThrust(amt1, afterburn); @@ -830,3 +783,19 @@ void Movable::Thrust(const Vector &amt1, bool afterburn) { } } } + +// If in Travel mode (non-combat), speed is limited to x100 +double Movable::MaxSpeed() const { + static const double combat_mode_multiplier = configuration()->physics_config.combat_mode_multiplier; + const Unit *unit = vega_dynamic_const_cast_ptr(this); + return (unit->computer.combat_mode) ? unit->drive.speed.AdjustedValue() : combat_mode_multiplier * unit->drive.speed.AdjustedValue(); +} + +// Same as comment above. It makes less sense to limit travel speed with afterburners to afterburner speed x 100. +double Movable::MaxAfterburnerSpeed() const { + static const double combat_mode_multiplier = configuration()->physics_config.combat_mode_multiplier; + const Unit *unit = vega_dynamic_const_cast_ptr(this); + + //same capped big speed as combat...else different + return (unit->computer.combat_mode) ? unit->afterburner.speed.AdjustedValue() : combat_mode_multiplier * unit->drive.speed.AdjustedValue(); +} diff --git a/engine/src/cmd/movable.h b/engine/src/cmd/movable.h index e6c450659e..6b286b521e 100644 --- a/engine/src/cmd/movable.h +++ b/engine/src/cmd/movable.h @@ -25,7 +25,6 @@ #define VEGA_STRIKE_ENGINE_CMD_MOVABLE_H #include "gfx/vec.h" -#include "vs_limits.h" #include "gfx/quaternion.h" #include "star_system.h" @@ -59,8 +58,6 @@ class Movable { } // Fields - - Limits limits; //The velocity this unit has in World Space Vector cumulative_velocity; //The force applied from outside accrued over the whole physics frame @@ -295,6 +292,9 @@ class Movable { void PitchTorque(float amt); //Applies a roll of amt void RollTorque(float amt); + + double MaxSpeed() const; + double MaxAfterburnerSpeed() const; }; #endif //VEGA_STRIKE_ENGINE_CMD_MOVABLE_H diff --git a/engine/src/cmd/unit_csv.cpp b/engine/src/cmd/unit_csv.cpp index bb88d22a5e..05d7812697 100644 --- a/engine/src/cmd/unit_csv.cpp +++ b/engine/src/cmd/unit_csv.cpp @@ -47,6 +47,7 @@ #include "resource/resource.h" #include "unit_csv_factory.h" #include "upgradeable_unit.h" +#include "components/component_utils.h" extern int GetModeFromName(const char *input_buffer); extern void pushMesh(std::vector &mesh, @@ -375,13 +376,7 @@ static void AddSubUnits(Unit *thus, faction, modification, NULL)); //I set here the fg arg to NULL - if (xml.units.back()->name == "LOAD_FAILED") { - xml.units.back()->limits.yaw = 0; - xml.units.back()->limits.pitch = 0; - xml.units.back()->limits.roll = 0; - xml.units.back()->limits.lateral = xml.units.back()->limits.retro = xml.units.back()->limits.forward = - xml.units.back()->limits.afterburn = 0.0; - } + if (!thus->isSubUnit()) { //Useless to set recursive owner in subunits - as parent will do the same xml.units.back()->SetRecursiveOwner(thus); } @@ -389,8 +384,11 @@ static void AddSubUnits(Unit *thus, R.Normalize(); xml.units.back()->prev_physical_state = xml.units.back()->curr_physical_state; xml.units.back()->SetPosition(pos * xml.unitscale); - xml.units.back()->limits.structurelimits = R.Cast(); - xml.units.back()->limits.limitmin = restricted; + + // Subunit movement restrictions + xml.units.back()->structure_limits = R.Cast(); + xml.units.back()->limit_min = restricted; + xml.units.back()->name = filename; if (xml.units.back()->pImage->unitwriter != NULL) { xml.units.back()->pImage->unitwriter->setName(filename); @@ -400,7 +398,7 @@ static void AddSubUnits(Unit *thus, for (int a = xml.units.size() - 1; a >= 0; a--) { bool randomspawn = xml.units[a]->name.get().find("randomspawn") != string::npos; if (randomspawn) { - int chancetospawn = float_to_int(xml.units[a]->warpCapData()); + int chancetospawn = float_to_int(xml.units[a]->ftl_energy.MaxLevel()); if (chancetospawn > rand() % 100) { thus->SubUnits.prepend(xml.units[a]); } else { @@ -611,18 +609,7 @@ void LoadCockpit(Unit *thus, const string &cockpit) { const std::string EMPTY_STRING(""); -void YawPitchRollParser(std::string unit_key, - std::string main_string, - std::string left_string, - std::string right_string, - float &left_pointer, - float &right_pointer) { - float main_value = UnitCSVFactory::GetVariable(unit_key, main_string, 0.0f); - float right_value = UnitCSVFactory::GetVariable(unit_key, right_string, 0.0f); - float left_value = UnitCSVFactory::GetVariable(unit_key, left_string, 0.0f); - right_pointer = (right_value > 0 ? right_value : main_value) * M_PI / 180.; - left_pointer = (left_value > 0 ? left_value : main_value) * M_PI / 180.; -} + void Unit::LoadRow(std::string unit_identifier, string modification, bool saved_game) { Unit::XML xml; @@ -820,9 +807,14 @@ void Unit::LoadRow(std::string unit_identifier, string modification, bool saved_ graphicOptions.MinWarpMultiplier = UnitCSVFactory::GetVariable(unit_key, "Warp_Min_Multiplier", 1.0f); graphicOptions.MaxWarpMultiplier = UnitCSVFactory::GetVariable(unit_key, "Warp_Max_Multiplier", 1.0f); - // Bleed factor hints at losing energy. However, here, at 2.0 it's a factor - // for reducing warp cost - double ftl_factor = configuration()->warp_config.bleed_factor; + // Begin Drive Section + // Afterburner + afterburner = Afterburner(GetSource(ComponentType::Afterburner, &fuel, &energy, &ftl_energy)); + afterburner.Load("", unit_key); + + drive = Drive(GetSource(ComponentType::Drive, &fuel, &energy, &ftl_energy)); + drive.Load("", unit_key); + ftl_drive.Load("", unit_key); jump_drive.Load("", unit_key); @@ -832,48 +824,9 @@ void Unit::LoadRow(std::string unit_identifier, string modification, bool saved_ "Collide_Subunits", graphicOptions.RecurseIntoSubUnitsOnCollision ? true : false) ? 1 : 0; - - afterburnenergy = UnitCSVFactory::GetVariable(unit_key, "Afterburner_Usage_Cost", 32767.0f); - afterburntype = UnitCSVFactory::GetVariable(unit_key, - "Afterburner_Type", - 0); //type 1 == "use fuel", type 0 == "use reactor energy", type 2 ==(hopefully) "use jump fuel" 3: NO AFTERBURNER - limits.yaw = UnitCSVFactory::GetVariable(unit_key, "Maneuver_Yaw", 0.0f) * M_PI / 180.0; - limits.pitch = UnitCSVFactory::GetVariable(unit_key, "Maneuver_Pitch", 0.0f) * M_PI / 180.0; - limits.roll = UnitCSVFactory::GetVariable(unit_key, "Maneuver_Roll", 0.0f) * M_PI / 180.0; - - YawPitchRollParser(unit_key, - "Yaw_Governor", - "Yaw_Governor", - "Yaw_Governor", - computer.max_yaw_right, - computer.max_yaw_left); - YawPitchRollParser(unit_key, - "Pitch_Governor", - "Pitch_Governor_Up", - "Pitch_Governor_Down", - computer.max_pitch_up, - computer.max_pitch_down); - YawPitchRollParser(unit_key, - "Roll_Governor", - "Roll_Governor_Right", - "Roll_Governor_Left", - computer.max_roll_right, - computer.max_roll_left); - - const float game_accel = configuration()->physics_config.game_accel; - const float game_speed = configuration()->physics_config.game_speed; - limits.afterburn = UnitCSVFactory::GetVariable(unit_key, "Afterburner_Accel", 0.0f) * game_accel * game_speed; - limits.forward = UnitCSVFactory::GetVariable(unit_key, "Forward_Accel", 0.0f) * game_accel * game_speed; - limits.retro = UnitCSVFactory::GetVariable(unit_key, "Retro_Accel", 0.0f) * game_accel * game_speed; - limits.lateral = 0.5 * (UnitCSVFactory::GetVariable(unit_key, "Left_Accel", 0.0f) + - UnitCSVFactory::GetVariable(unit_key, "Right_Accel", 0.0f)) * game_accel * game_speed; - - limits.vertical = 0.5 * (UnitCSVFactory::GetVariable(unit_key, "Top_Accel", 0.0f) + - UnitCSVFactory::GetVariable(unit_key, "Bottom_Accel", 0.0f)) * game_accel * game_speed; - - computer.max_combat_speed = UnitCSVFactory::GetVariable(unit_key, "Default_Speed_Governor", 0.0f) * game_speed; - computer.max_combat_ab_speed = - UnitCSVFactory::GetVariable(unit_key, "Afterburner_Speed_Governor", 0.0f) * game_speed; + + // End Drive Section + computer.itts = UnitCSVFactory::GetVariable(unit_key, "ITTS", true); computer.radar.canlock = UnitCSVFactory::GetVariable(unit_key, "Can_Lock", true); @@ -1334,30 +1287,16 @@ string Unit::WriteUnitString() { unit["Warp_Max_Multiplier"] = tos(graphicOptions.MaxWarpMultiplier); unit["Primary_Capacitor"] = tos(energy.Level()); unit["Reactor_Recharge"] = tos(reactor.Capacity()); + + afterburner.SaveToCSV(unit); + drive.SaveToCSV(unit); jump_drive.SaveToCSV(unit); ftl_drive.SaveToCSV(unit); + unit["Wormhole"] = tos(forcejump != 0); - unit["Afterburner_Usage_Cost"] = tos(afterburnenergy); - unit["Afterburner_Type"] = tos(afterburntype); - unit["Maneuver_Yaw"] = tos(limits.yaw * 180 / (M_PI)); - unit["Maneuver_Pitch"] = tos(limits.pitch * 180 / (M_PI)); - unit["Maneuver_Roll"] = tos(limits.roll * 180 / (M_PI)); - unit["Yaw_Governor_Right"] = tos(computer.max_yaw_right * 180 / M_PI); - unit["Yaw_Governor_Left"] = tos(computer.max_yaw_left * 180 / M_PI); - unit["Pitch_Governor_Up"] = tos(computer.max_pitch_up * 180 / M_PI); - unit["Pitch_Governor_Down"] = tos(computer.max_pitch_down * 180 / M_PI); - unit["Roll_Governor_Right"] = tos(computer.max_roll_right * 180 / M_PI); - unit["Roll_Governor_Left"] = tos(computer.max_roll_left * 180 / M_PI); - const float game_accel = configuration()->physics_config.game_accel; - const float game_speed = configuration()->physics_config.game_speed; - unit["Afterburner_Accel"] = tos(limits.afterburn / (game_accel * game_speed)); - unit["Forward_Accel"] = tos(limits.forward / (game_accel * game_speed)); - unit["Retro_Accel"] = tos(limits.retro / (game_accel * game_speed)); - unit["Left_Accel"] = unit["Right_Accel"] = tos(limits.lateral / (game_accel * game_speed)); - unit["Bottom_Accel"] = unit["Top_Accel"] = tos(limits.vertical / (game_accel * game_speed)); - unit["Default_Speed_Governor"] = tos(computer.max_combat_speed / game_speed); - unit["Afterburner_Speed_Governor"] = tos(computer.max_combat_ab_speed / game_speed); + + unit["ITTS"] = tos(computer.itts); unit["Can_Lock"] = tos(computer.radar.canlock); unit["Radar_Color"] = tos(computer.radar.capability); diff --git a/engine/src/cmd/unit_generic.cpp b/engine/src/cmd/unit_generic.cpp index 8ce0cc8fa0..f9a22e2541 100644 --- a/engine/src/cmd/unit_generic.cpp +++ b/engine/src/cmd/unit_generic.cpp @@ -536,9 +536,9 @@ static float tmpmax(float a, float b) { bool CheckAccessory(Unit *tur) { bool accessory = tur->name.get().find("accessory") != string::npos; if (accessory) { - tur->SetAngularVelocity(tur->DownCoordinateLevel(Vector(tur->GetComputerData().max_pitch_up, - tur->GetComputerData().max_yaw_right, - tur->GetComputerData().max_roll_right))); + tur->SetAngularVelocity(tur->DownCoordinateLevel(Vector(tur->drive.max_pitch_up, + tur->drive.max_yaw_right, + tur->drive.max_roll_right))); } return accessory; } @@ -640,11 +640,11 @@ float Unit::cosAngleTo(Unit *targ, float &dist, float speed, float range, bool t //Trial code float turnlimit = - tmpmax(tmpmax(computer.max_yaw_left, computer.max_yaw_right), - tmpmax(computer.max_pitch_up, computer.max_pitch_down)); + tmpmax(tmpmax(drive.max_yaw_left.Value(), drive.max_yaw_right.Value()), + tmpmax(drive.max_pitch_up.Value(), drive.max_pitch_down.Value())); float turnangle = simulation_atom_var * tmpmax(turnlimit, - tmpmax(simulation_atom_var * .5 * (limits.yaw + limits.pitch), + tmpmax(simulation_atom_var * .5 * (drive.yaw.Value() + drive.pitch.Value()), sqrtf(AngularVelocity.i * AngularVelocity.i + AngularVelocity.j * AngularVelocity.j))); float ittsangle = safeacos(Normal.Cast().Dot(totarget.Scale(1. / totarget.Magnitude()))); QVector edgeLocation = (targ->cumulative_transformation_matrix.getP() * targ->rSize() + totarget); @@ -1182,7 +1182,7 @@ void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degr //THIS IS NOT YET SUPPORTED IN NETWORKING computer.target = nullptr; //set the target to NULL } else if (randnum >= .4) { - limits.retro *= dam; + drive.retro.RandomDamage(); } else if (randnum >= .3275) { const float maxdam = configuration()->physics_config.max_radar_cone_damage; computer.radar.maxcone += (1 - dam); @@ -1214,29 +1214,13 @@ void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degr return; } if (rand01() < configuration()->physics_config.thruster_hit_chance) { - //DAMAGE ROLL/YAW/PITCH/THRUST - float orandnum = rand01() * .82 + .18; - if (randnum >= .9) { - computer.max_pitch_up *= orandnum; - } else if (randnum >= .8) { - computer.max_yaw_right *= orandnum; - } else if (randnum >= .6) { - computer.max_yaw_left *= orandnum; - } else if (randnum >= .4) { - computer.max_pitch_down *= orandnum; - } else if (randnum >= .2) { - computer.max_roll_right *= orandnum; - } else if (randnum >= .18) { - computer.max_roll_left *= orandnum; - } else if (randnum >= .17) { - limits.roll *= dam; - } else if (randnum >= .10) { - limits.yaw *= dam; - } else if (randnum >= .03) { - limits.pitch *= dam; - } else { - limits.lateral *= dam; - } + // This is fairly severe. One or two hits can disable the engine. + // Note that retro can be damaged by both this and above. + // Drive can also be damaged by code below - really computer. + // TODO: figure out a better damage system that doesn't rely on where + // the shots are coming from. + drive.Damage(); + afterburner.Damage(); damages |= Damages::LIMITS_DAMAGED; return; } @@ -1276,7 +1260,7 @@ void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degr case 2: ftl_energy.Damage(); break; case 3: ftl_drive.Damage(); break; case 4: jump_drive.Damage(); break; - case 5: this->afterburnenergy += ((1 - dam) * reactor.Capacity()); break; + case 5: afterburner.Damage(); break; case 6: CargoVolume *= dam; break; case 7: UpgradeVolume *= dam; break; case 8: @@ -1352,17 +1336,7 @@ void Unit::DamageRandSys(float dam, const Vector &vec, float randnum, float degr } if (degrees >= 150 && degrees <= 180) { //DAMAGE ENGINES - if (randnum >= .8) { - computer.max_combat_ab_speed *= dam; - } else if (randnum >= .6) { - computer.max_combat_speed *= dam; - } else if (randnum >= .4) { - limits.afterburn *= dam; - } else if (randnum >= .2) { - limits.vertical *= dam; - } else { - limits.forward *= dam; - } + drive.Damage(); damages |= Damages::LIMITS_DAMAGED; return; } @@ -2032,6 +2006,7 @@ std::set arrested_list_do_not_dereference; // A simple utility to recharge energy, ftl_energy and shields // Also to charge for docking and refueling void rechargeShip(Unit *unit, unsigned int cockpit) { + unit->fuel.Refill(); unit->energy.Refill(); unit->ftl_energy.Refill(); unit->shield->FullyCharge(); @@ -2508,10 +2483,10 @@ bool Unit::UpgradeSubUnitsWithFactory(const Unit *up, int subunitoffset, bool to un->SetFaction(faction); un->curr_physical_state = addToMeCur; un->prev_physical_state = addToMePrev; - un->limits.yaw = 0; - un->limits.pitch = 0; - un->limits.roll = 0; - un->limits.lateral = un->limits.retro = un->limits.forward = un->limits.afterburn = 0.0; + un->drive.yaw = 0; + un->drive.pitch = 0; + un->drive.roll = 0; + un->drive.lateral = un->drive.retro = un->drive.forward = un->afterburner.thrust = 0.0; un->name = turSize + "_blank"; if (un->pImage->unitwriter != NULL) { @@ -2887,22 +2862,7 @@ bool Unit::UpAndDownGrade(const Unit *up, AddToDowngradeMap(up->name, 1, curdowngrademapoffset++, tempdownmap); } } - float tmax_speed = up->computer.max_combat_speed; - float tmax_ab_speed = up->computer.max_combat_ab_speed; - float tmax_yaw_right = up->computer.max_yaw_right; - float tmax_yaw_left = up->computer.max_yaw_left; - float tmax_pitch_up = up->computer.max_pitch_up; - float tmax_pitch_down = up->computer.max_pitch_down; - float tmax_roll_right = up->computer.max_roll_right; - float tmax_roll_left = up->computer.max_roll_left; - float tlimits_yaw = up->limits.yaw; - float tlimits_roll = up->limits.roll; - float tlimits_pitch = up->limits.pitch; - float tlimits_lateral = up->limits.lateral; - float tlimits_vertical = up->limits.vertical; - float tlimits_forward = up->limits.forward; - float tlimits_retro = up->limits.retro; - float tlimits_afterburn = up->limits.afterburn; + if (downgrade) { Adder = &SubtractUp; Percenter = &computeDowngradePercent; @@ -2914,22 +2874,6 @@ bool Unit::UpAndDownGrade(const Unit *up, } else if (additive == 2) { Adder = &MultUp; Percenter = &computeMultPercent; - tmax_speed = speedStarHandler(tmax_speed); - tmax_ab_speed = speedStarHandler(tmax_ab_speed); - tmax_yaw_right = speedStarHandler(tmax_yaw_right); - tmax_yaw_left = speedStarHandler(tmax_yaw_left); - tmax_pitch_up = speedStarHandler(tmax_pitch_up); - tmax_pitch_down = speedStarHandler(tmax_pitch_down); - tmax_roll_right = speedStarHandler(tmax_roll_right); - tmax_roll_left = speedStarHandler(tmax_roll_left); - tlimits_yaw = speedStarHandler(tlimits_yaw); - tlimits_pitch = speedStarHandler(tlimits_pitch); - tlimits_roll = speedStarHandler(tlimits_roll); - tlimits_forward = accelStarHandler(tlimits_forward); - tlimits_retro = accelStarHandler(tlimits_retro); - tlimits_lateral = accelStarHandler(tlimits_lateral); - tlimits_vertical = accelStarHandler(tlimits_vertical); - tlimits_afterburn = accelStarHandler(tlimits_afterburn); } else { Adder = &GetsB; Percenter = &computePercent; @@ -3079,60 +3023,7 @@ bool Unit::UpAndDownGrade(const Unit *up, || cell_has_recursive_data(upgrade_name, up->faction, "ECM_Rating")) STDUPGRADE(ecm, up->ecm, templ->ecm, 0); //ecm is unsigned --chuck_starchaser } - //Maneuvering stuff - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, - up->faction, - "Maneuver_Yaw|Maneuver_Pitch|Maneuver_Roll|Left_Accel|Top_Accel|Retro_Accel|Forward_Accel|Afterburner_Accel|Default_Speed_Governor|Afterburner_Speed_Governor|Yaw_Governor|Pitch_Governor|Roll_Speed_Governor")) { - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Maneuver_Yaw")) - STDUPGRADE(limits.yaw, tlimits_yaw, templ->limits.yaw, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Maneuver_Pitch")) - STDUPGRADE(limits.pitch, tlimits_pitch, templ->limits.pitch, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Maneuver_Roll")) - STDUPGRADE(limits.roll, tlimits_roll, templ->limits.roll, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Left_Accel")) - STDUPGRADE(limits.lateral, tlimits_lateral, templ->limits.lateral, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Top_Accel")) - STDUPGRADE(limits.vertical, tlimits_vertical, templ->limits.vertical, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Retro_Accel")) - STDUPGRADE(limits.retro, tlimits_retro, templ->limits.retro, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Forward_Accel")) - STDUPGRADE(limits.forward, tlimits_forward, templ->limits.forward, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Afterburner_Accel")) - STDUPGRADE(limits.afterburn, tlimits_afterburn, templ->limits.afterburn, 0); - /*if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Fuel_Capacity")) - STDUPGRADE(fuel, up->fuel, templ->fuel, 0);*/ - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Default_Speed_Governor")) - STDUPGRADE(computer.max_combat_speed, tmax_speed, templ->computer.max_combat_speed, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Afterburner_Speed_Governor")) - STDUPGRADE(computer.max_combat_ab_speed, tmax_ab_speed, templ->computer.max_combat_ab_speed, 0); - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Yaw_Governor")) { - STDUPGRADE(computer.max_yaw_right, tmax_yaw_right, templ->computer.max_yaw_right, 0); - STDUPGRADE(computer.max_yaw_left, tmax_yaw_left, templ->computer.max_yaw_left, 0); - } - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Pitch_Governor")) { - STDUPGRADE(computer.max_pitch_down, tmax_pitch_down, templ->computer.max_pitch_down, 0); - STDUPGRADE(computer.max_pitch_up, tmax_pitch_up, templ->computer.max_pitch_up, 0); - } - if (!csv_cell_null_check || force_change_on_nothing - || cell_has_recursive_data(upgrade_name, up->faction, "Roll_Speed_Governor")) { - STDUPGRADE(computer.max_roll_left, tmax_roll_left, templ->computer.max_roll_left, 0); - STDUPGRADE(computer.max_roll_right, tmax_roll_right, templ->computer.max_roll_right, 0); - } - } + //FIXME - do cell lookup later here static bool UpgradeCockpitDamage = XMLSupport::parse_bool(vs_config->getVariable("physics", "upgrade_cockpit_damage", "false")); @@ -3301,23 +3192,7 @@ bool Unit::UpAndDownGrade(const Unit *up, } //NO CLUE FOR BELOW if (downgrade) { - //NOTE: Afterburner type 2 (jmp) - //NOTE: Afterburner type 1 (gas) - //NOTE: Afterburner type 0 (pwr) - if (afterburnenergy < 32767 && afterburnenergy <= up->afterburnenergy && up->afterburnenergy != 32767 - && up->afterburnenergy != 0) { - if (touchme) { - afterburnenergy = 32767, afterburntype = 0; - } - ++numave; - ++percentage; - if (gen_downgrade_list) { - AddToDowngradeMap(up->name, - up->afterburntype, - ((char *) &this->afterburnenergy) - ((char *) this), - tempdownmap); - } - } + } else { //we are upgrading! if (touchme) { @@ -3327,21 +3202,6 @@ bool Unit::UpAndDownGrade(const Unit *up, } } } - - //NOTE: Afterburner type 2 (jmp) - //NOTE: Afterburner type 1 (gas) - //NOTE: Afterburner type 0 (pwr) - if (((afterburnenergy > up->afterburnenergy - || (afterburntype != up->afterburntype && up->afterburnenergy != 32767)) - && up->afterburnenergy > 0) || force_change_on_nothing) { - ++numave; - if (touchme) { - afterburnenergy = up->afterburnenergy, afterburntype = up->afterburntype; - } - } else if (afterburnenergy <= up->afterburnenergy && afterburnenergy >= 0 && up->afterburnenergy > 0 - && up->afterburnenergy < 32767) { - cancompletefully = false; - } } if (needs_redemption) { if (!can_be_redeemed) { diff --git a/engine/src/cmd/unit_generic.h b/engine/src/cmd/unit_generic.h index 95d3e5df29..e1da9b7de8 100644 --- a/engine/src/cmd/unit_generic.h +++ b/engine/src/cmd/unit_generic.h @@ -83,9 +83,13 @@ void UncheckUnit( class Unit*un ); #include "cargo_color.h" // Components +#include "components/afterburner.h" +#include "components/afterburner_upgrade.h" #include "components/cloak.h" #include "components/energy_container.h" #include "components/reactor.h" +#include "components/drive.h" +#include "components/drive_upgrade.h" #include "components/ftl_drive.h" #include "components/jump_drive.h" @@ -107,7 +111,6 @@ class Box; class StarSystem; struct colTrees; class Pilot; -class Limits; class MissileGeneric; class AsteroidGeneric; @@ -160,7 +163,11 @@ class Unit : public Armed, public Audible, public Drawable, public Damageable, p // TODO: move this to a single constructor?! Reactor reactor = Reactor(&fuel, &energy, &ftl_energy); + Afterburner afterburner; + AfterburnerUpgrade afterburner_upgrade = AfterburnerUpgrade(&afterburner); Cloak cloak; + Drive drive; + DriveUpgrade drive_upgrade = DriveUpgrade(&drive); FtlDrive ftl_drive = FtlDrive(&ftl_energy); JumpDrive jump_drive = JumpDrive(&ftl_energy); @@ -290,6 +297,15 @@ class Unit : public Armed, public Audible, public Drawable, public Damageable, p //the turrets and spinning parts fun fun stuff UnitCollection SubUnits; +// Turret limits + //the vector denoting the "front" of the turret cone! + // Again, an inconsistency between constructor and Init(). Chose Init + // value as it comes later + Vector structure_limits = Vector(0.0f, 0.0f, 1.0f); + + //the minimum dot that the current heading can have with the structurelimit + double limit_min = -1; + /** * Contains information about a particular Mount on a unit. * And the weapons it has, where it is, where it's aimed, diff --git a/engine/src/cmd/unit_util_generic.cpp b/engine/src/cmd/unit_util_generic.cpp index 1f4512ceb2..4f739f4be8 100644 --- a/engine/src/cmd/unit_util_generic.cpp +++ b/engine/src/cmd/unit_util_generic.cpp @@ -839,14 +839,14 @@ float maxSpeed(const Unit *my_unit) { if (!my_unit) { return 0; } - return my_unit->ViewComputerData().max_speed(); + return my_unit->MaxSpeed(); } float maxAfterburnerSpeed(const Unit *my_unit) { if (!my_unit) { return 0; } - return my_unit->ViewComputerData().max_ab_speed(); + return my_unit->MaxAfterburnerSpeed(); } void setECM(Unit *my_unit, int NewECM) { diff --git a/engine/src/cmd/upgradeable_unit.cpp b/engine/src/cmd/upgradeable_unit.cpp index 150c5b52eb..a619e1ef03 100644 --- a/engine/src/cmd/upgradeable_unit.cpp +++ b/engine/src/cmd/upgradeable_unit.cpp @@ -150,6 +150,16 @@ UpgradeOperationResult UpgradeableUnit::UpgradeUnit(const std::string upgrade_na result.success = unit->reactor.CanWillUpDowngrade(upgrade_key, upgrade, apply); break; + case ComponentType::Afterburner: break; // Integrated + case ComponentType::AfterburnerUpgrade: + result.upgradeable = true; + result.success = unit->afterburner_upgrade.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; + case ComponentType::Drive: break; // Integrated + case ComponentType::DriveUpgrade: + result.upgradeable = true; + result.success = unit->drive_upgrade.CanWillUpDowngrade(upgrade_key, upgrade, apply); + break; case ComponentType::FtlDrive: result.upgradeable = true; result.success = unit->ftl_drive.CanWillUpDowngrade(upgrade_key, upgrade, apply); @@ -164,15 +174,6 @@ UpgradeOperationResult UpgradeableUnit::UpgradeUnit(const std::string upgrade_na result.upgradeable = true; result.success = unit->cloak.CanWillUpDowngrade(upgrade_key, upgrade, apply); break; - /*case UpgradeType::Afterburner: - result.upgradeable = true; - result.success = unit->afterburner.CanWillUpDowngrade(upgrade_key, upgrade, apply); - std::cout << "Afterburner upgraded successfully\n"; - break; - case UpgradeType::Drive: - result.upgradeable = true; - result.success = unit->armor->CanWillUpDowngrade(upgrade_key, upgrade, apply); - break;*/ /*case UpgradeType::ECM: @@ -225,6 +226,16 @@ void UpgradeableUnit::UpgradeUnit(const std::string &upgrades) { // TODO: change this when we make this a sub-class of unit Unit *unit = vega_dynamic_cast_ptr(this); unit->Upgrade(upgradee, mount_offset, subunit_offset, mode, true, percent, nullptr); + + // Code to handle DriveUpgrade and AfterburnerUpgrade + // Should eventually replace all the code above + CargoUpgrade cargo_upgrade(upgrade); + ComponentType component_type = GetComponentTypeFromName(cargo_upgrade.name); + if(component_type == ComponentType::AfterburnerUpgrade) { + unit->afterburner_upgrade.Load(cargo_upgrade.name + "__upgrades"); + } else if(component_type == ComponentType::DriveUpgrade) { + unit->drive_upgrade.Load(cargo_upgrade.name + "__upgrades"); + } } } diff --git a/engine/src/cmd/vs_limits.h b/engine/src/cmd/vs_limits.h deleted file mode 100644 index ac75198f70..0000000000 --- a/engine/src/cmd/vs_limits.h +++ /dev/null @@ -1,56 +0,0 @@ -/** - * vs_limits.h - * - * Copyright (c) 2001-2002 Daniel Horn - * Copyright (c) 2002-2019 pyramid3d and other Vega Strike Contributors - * Copyright (c) 2019-2021 Stephen G. Tuggy, and other Vega Strike Contributors - * Copyright (C) 2022-2023 Stephen G. Tuggy, Benjamen R. Meyer - * - * https://github.com/vegastrike/Vega-Strike-Engine-Source - * - * This file is part of Vega Strike. - * - * Vega Strike is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 2 of the License, or - * (at your option) any later version. - * - * Vega Strike is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with Vega Strike. If not, see . - */ -#ifndef VEGA_STRIKE_ENGINE_CMD_LIMITS_H -#define VEGA_STRIKE_ENGINE_CMD_LIMITS_H - -#include "gfx/vec.h" - -class Limits { -public: - // Init overrides default values of 0 with the following values -//max ypr--both pos/neg are symmetrical - float yaw = 2.55; - float pitch = 2.55; - float roll = 2.55; -//side-side engine thrust max - float lateral = 2; -//vertical engine thrust max - float vertical = 8; -//forward engine thrust max - float forward = 2; -//reverse engine thrust max - float retro = 2; -//after burner acceleration max - float afterburn = 5; -//the vector denoting the "front" of the turret cone! - // Again, an inconsistency between constructor and Init(). Chose Init - // value as it comes later - Vector structurelimits = Vector(0, 0, 1); -//the minimum dot that the current heading can have with the structurelimit - float limitmin = -1; -}; - -#endif //VEGA_STRIKE_ENGINE_CMD_LIMITS_H diff --git a/engine/src/components/afterburner.cpp b/engine/src/components/afterburner.cpp new file mode 100644 index 0000000000..8caaa9c8cd --- /dev/null +++ b/engine/src/components/afterburner.cpp @@ -0,0 +1,97 @@ +/* + * afterburner.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include "afterburner.h" + +#include "component_utils.h" +#include "unit_csv_factory.h" +#include "configuration/configuration.h" + +Afterburner::Afterburner(EnergyContainer *source) : + Component(0.0, 0.0, true, true), EnergyConsumer(source, false), thrust(1,0,1), speed(1,0,1) { + type = ComponentType::Afterburner; +} + + + +// Component Methods +void Afterburner::Load(std::string upgrade_key, + std::string unit_key) { + static const double game_speed = configuration()->physics_config.game_speed; + static const double game_accel = configuration()->physics_config.game_accel; + static const double game_accel_speed = game_speed * game_accel; + Component::Load(upgrade_key, unit_key); + + thrust = Resource(UnitCSVFactory::GetVariable(unit_key, "Afterburner_Accel", std::string("0.0")), game_accel_speed); + speed = Resource(UnitCSVFactory::GetVariable(unit_key, "Afterburner_Speed_Governor", std::string("0.0")), game_speed); + double consumption = UnitCSVFactory::GetVariable(unit_key, "Afterburner_Usage_Cost", 1.0); + SetConsumption(consumption); +} + +void Afterburner::SaveToCSV(std::map& unit) const { + static const double game_speed = configuration()->physics_config.game_speed; + static const double game_accel = configuration()->physics_config.game_accel; + static const double game_accel_speed = game_speed * game_accel; + unit["Afterburner_Accel"] = thrust.Serialize(game_accel_speed); + unit["Afterburner_Speed_Governor"] = speed.Serialize(game_speed); +} + +// Afterburner is integrated and so cannot be upgraded/downgraded +// Use AfterburnerUpgrade to make changes +bool Afterburner::CanDowngrade() const { + return false; +} + +bool Afterburner::Downgrade() { + return false; +} + +bool Afterburner::CanUpgrade(const std::string upgrade_name) const { + return false; +} + +bool Afterburner::Upgrade(const std::string upgrade_name) { + return false; +} + +void Afterburner::Damage() { + thrust.RandomDamage(); + speed.RandomDamage(); + + operational = (thrust.Percent() + speed.Percent()) / 2 * 100; +} + +void Afterburner::DamageByPercent(double percent) { + thrust.DamageByPercent(percent); + speed.DamageByPercent(percent); + + operational = (thrust.Percent() + speed.Percent()) / 2 * 100; +} + +void Afterburner::Repair() { + thrust.RepairFully(); + speed.RepairFully(); + + operational.RepairFully(); +} \ No newline at end of file diff --git a/engine/src/components/afterburner.h b/engine/src/components/afterburner.h new file mode 100644 index 0000000000..f904c9ecbd --- /dev/null +++ b/engine/src/components/afterburner.h @@ -0,0 +1,59 @@ +/* + * afterburner.h + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#ifndef VEGA_STRIKE_ENGINE_COMPONENTS_AFTERBURNER_H +#define VEGA_STRIKE_ENGINE_COMPONENTS_AFTERBURNER_H + +#include "component.h" +#include "energy_consumer.h" + +class EnergyContainer; + +/** We split this class from Drive for one reason - it may use a different source. */ +class Afterburner : public Component, public EnergyConsumer { +public: + //after burner acceleration max + Resource thrust; + + Resource speed; + + Afterburner(EnergyContainer *source = nullptr); + + // Component Methods + virtual void Load(std::string upgrade_key, + std::string unit_key = ""); + + virtual void SaveToCSV(std::map& unit) const; + + virtual bool CanDowngrade() const; + virtual bool Downgrade(); + virtual bool CanUpgrade(const std::string upgrade_name) const; + virtual bool Upgrade(const std::string upgrade_name); + + virtual void Damage(); + virtual void DamageByPercent(double percent); + virtual void Repair(); +}; + +#endif // VEGA_STRIKE_ENGINE_COMPONENTS_AFTERBURNER_H diff --git a/engine/src/components/afterburner_upgrade.cpp b/engine/src/components/afterburner_upgrade.cpp new file mode 100644 index 0000000000..6e3eaa84bf --- /dev/null +++ b/engine/src/components/afterburner_upgrade.cpp @@ -0,0 +1,105 @@ +/* + * afterburner_upgrade.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include "afterburner_upgrade.h" + +#include "afterburner.h" +#include "unit_csv_factory.h" + +#include + + +AfterburnerUpgrade::AfterburnerUpgrade(Afterburner *afterburner): + Component(), afterburner(afterburner), thrust(1.0), + speed(1.0), consumption(1.0) { + type = ComponentType::AfterburnerUpgrade; +} + + + +// Component Methods +void AfterburnerUpgrade::Load(std::string upgrade_key, + std::string unit_key) { + Component::Load(upgrade_key, unit_key); + + thrust = UnitCSVFactory::GetVariable(upgrade_key, "Afterburner_Accel", 1.0); + speed = UnitCSVFactory::GetVariable(upgrade_key, "Afterburner_Speed_Governor", 1.0); + consumption = UnitCSVFactory::GetVariable(upgrade_key, "Afterburner_Usage_Cost", 1.0); +} + +void AfterburnerUpgrade::SaveToCSV(std::map& unit) const { + // Not supported with the current file format + // Instead, we save the modified Afterburner stats and load the upgrade above. + // Then, if we sell the upgrade, we get the original. +} + + +// Can only upgrade/downgrade if Afterburner is undamaged. +// Otherwise, there are a lot of edge cases. +bool AfterburnerUpgrade::CanDowngrade() const { + return !afterburner->Damaged(); +} + +bool AfterburnerUpgrade::Downgrade() { + if(!CanDowngrade()) { + return false; + } + + // Component + Component::Downgrade(); + + // Remove effects of upgrade on afterburner + afterburner->thrust.SetMaxValue(afterburner->thrust.MaxValue() / thrust); + afterburner->speed.SetMaxValue(afterburner->speed.MaxValue() / speed); + afterburner->SetConsumption(afterburner->GetConsumption() / consumption); + + // Remove modifiers + thrust = speed = consumption = 1.0; + + return true; +} + +bool AfterburnerUpgrade::CanUpgrade(const std::string upgrade_name) const { + return !afterburner->Damaged(); +} + +bool AfterburnerUpgrade::Upgrade(const std::string upgrade_name) { + if(!CanUpgrade(upgrade_name)) { + return false; + } + + // Component + Component::Upgrade(upgrade_name + "__upgrades"); + + // Load modifiers + Load(upgrade_name + "__upgrades"); + + // Add effects of upgrade on afterburner + afterburner->thrust.SetMaxValue(afterburner->thrust.MaxValue() * thrust); + afterburner->speed.SetMaxValue(afterburner->speed.MaxValue() * speed); + afterburner->SetConsumption(afterburner->GetConsumption() * consumption); + + return true; +} + diff --git a/engine/src/components/afterburner_upgrade.h b/engine/src/components/afterburner_upgrade.h new file mode 100644 index 0000000000..1d37ba2837 --- /dev/null +++ b/engine/src/components/afterburner_upgrade.h @@ -0,0 +1,65 @@ +/* + * afterburner_upgrade.h + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#ifndef VEGA_STRIKE_ENGINE_COMPONENTS_AFTERBURNER_UPGRADE_H +#define VEGA_STRIKE_ENGINE_COMPONENTS_AFTERBURNER_UPGRADE_H + +#include "component.h" + +class Afterburner; + +/** An AfterburnerUpgrade applies a modifier to Afterburner class. + * This is the same use case as DriveUpgrade. + * The game previously supported both additive and multiplicative upgrades. + * I've removed the additive one for simplicity's sake. + * The default value is 1.0 (no change). + */ +class AfterburnerUpgrade : public Component { + Afterburner *afterburner; +public: + //after burner acceleration + double thrust; + double speed; + double consumption; + + AfterburnerUpgrade(Afterburner *afterburner = nullptr); + + double MaxAfterburnerSpeed() const; + + // Component Methods + virtual void Load(std::string upgrade_key, + std::string unit_key = ""); + + virtual void SaveToCSV(std::map& unit) const; + + virtual bool CanDowngrade() const; + + virtual bool Downgrade(); + + virtual bool CanUpgrade(const std::string upgrade_name) const; + + virtual bool Upgrade(const std::string upgrade_name); +}; + +#endif // VEGA_STRIKE_ENGINE_COMPONENTS_AFTERBURNER_UPGRADE_H diff --git a/engine/src/components/cloak.cpp b/engine/src/components/cloak.cpp index 8078d27468..692cbaedda 100644 --- a/engine/src/components/cloak.cpp +++ b/engine/src/components/cloak.cpp @@ -25,7 +25,6 @@ #include "cloak.h" #include "unit_csv_factory.h" #include "configuration/configuration.h" -#include "unit_generic.h" Cloak::Cloak() : Component(), diff --git a/engine/src/components/component.cpp b/engine/src/components/component.cpp index 7cc3993363..2e1fe9783c 100644 --- a/engine/src/components/component.cpp +++ b/engine/src/components/component.cpp @@ -57,7 +57,6 @@ void Component::Load(std::string upgrade_key, std::string unit_key) { mass = UnitCSVFactory::GetVariable(upgrade_key, "Mass", 0.0); // Get volume and description from MasterPartList. - // We need try/catch for unit tests where MPL isn't loaded. const Cargo cargo = Manifest::MPL().GetCargoByName(upgrade_key); if(!cargo.GetName().empty()) { price = cargo.GetPrice(); @@ -69,6 +68,8 @@ void Component::Load(std::string upgrade_key, std::string unit_key) { // TODO: bool integral = false; } + + // TODO: convert to std::pair bool Component::CanWillUpDowngrade(const std::string upgrade_key, bool upgrade, bool apply) { diff --git a/engine/src/components/component_utils.cpp b/engine/src/components/component_utils.cpp index 58f4ce77cb..5879a4e417 100644 --- a/engine/src/components/component_utils.cpp +++ b/engine/src/components/component_utils.cpp @@ -25,10 +25,15 @@ #include "component_utils.h" #include "component.h" +#include "dummy_component.h" #include "reactor.h" #include "energy_container.h" +#include "afterburner.h" +#include "afterburner_upgrade.h" +#include "drive.h" +#include "drive_upgrade.h" #include "jump_drive.h" #include "ftl_drive.h" #include "cloak.h" @@ -39,7 +44,6 @@ #include - const ComponentType GetComponentTypeFromName(const std::string name) { std::string upgrade_key = name + "__upgrades"; @@ -129,3 +133,38 @@ EnergyContainer* GetSourceFromConfiguration(const EnergyConsumerSource source, E default: return nullptr; } } + + +// For Drive and DriveUpgrade +const std::string yaw_governor[] = {"Yaw_Governor", "Yaw_Governor", "Yaw_Governor"}; +const std::string pitch_governor[] = {"Pitch_Governor", "Pitch_Governor_Up", "Pitch_Governor_Down"}; +const std::string roll_governor[] = {"Roll_Governor", "Roll_Governor_Right", "Roll_Governor_Left"}; + +const std::string* GetGovernor(const YPR ypr) { + switch(ypr) { + case YPR::Yaw: return yaw_governor; break; + case YPR::Pitch: return pitch_governor; break; + case YPR::Roll: return roll_governor; break; + } +} + + +void DoubleYawPitchRollParser(std::string unit_key, const YPR ypr, + double &right_value, double &left_value) { + const std::string* governor = GetGovernor(ypr); + + const double main_value = UnitCSVFactory::GetVariable(unit_key, governor[0], 1.0); + right_value = UnitCSVFactory::GetVariable(unit_key, governor[1], main_value); + left_value = UnitCSVFactory::GetVariable(unit_key, governor[2], main_value); +} + +void ResourceYawPitchRollParser(std::string unit_key, const YPR ypr, + Resource &right_value, Resource &left_value, + const double minimum_functionality) { + double left, right; + DoubleYawPitchRollParser(unit_key, ypr, right, left); + left *= M_PI / 180.0; + right *= M_PI / 180.0; + right_value = Resource(right,right * minimum_functionality,right); + left_value = Resource(left,right * minimum_functionality,left); +} diff --git a/engine/src/components/component_utils.h b/engine/src/components/component_utils.h index f48661a615..6256ed2634 100644 --- a/engine/src/components/component_utils.h +++ b/engine/src/components/component_utils.h @@ -28,6 +28,7 @@ #include "component.h" #include "energy_consumer.h" #include "energy_container.h" +#include "resource/resource.h" #include @@ -39,5 +40,17 @@ EnergyContainer* GetSource(ComponentType component_type, EnergyContainer* fuel, EnergyContainer* GetSourceFromConfiguration(const EnergyConsumerSource source, EnergyContainer* fuel, EnergyContainer* energy, EnergyContainer* ftl_energy); + +enum class YPR { + Yaw, Pitch, Roll +}; + + +void DoubleYawPitchRollParser(std::string unit_key, const YPR ypr, + double &right_value, double &left_value); + + void ResourceYawPitchRollParser(std::string unit_key, const YPR ypr, + Resource &right_value, Resource &left_value, + const double minimum_functionality = 0.0); #endif // VEGA_STRIKE_ENGINE_COMPONENTS_COMPONENT_UTILS_H diff --git a/engine/src/components/drive.cpp b/engine/src/components/drive.cpp new file mode 100644 index 0000000000..883fd28456 --- /dev/null +++ b/engine/src/components/drive.cpp @@ -0,0 +1,226 @@ +/* + * drive.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include "drive.h" + +#include "component_utils.h" +#include "unit_csv_factory.h" +#include "configuration/configuration.h" + +#include +#include + + +Drive::Drive(EnergyContainer *source): + Component(0.0, 0.0, true, true), + EnergyConsumer(source, false), + yaw(1,0,1), pitch(1,0,1), roll(1,0,1), lateral(1,0,1), + vertical(1,0,1), forward(1,0,1), retro(1,0,1), + speed(1,0,1), max_yaw_left(1,0,1), + max_yaw_right(1,0,1), max_pitch_down(1,0,1), max_pitch_up(1,0,1), + max_roll_left(1,0,1), max_roll_right(1,0,1) { + type = ComponentType::Drive; +} + + +// Component Methods +void Drive::Load(std::string upgrade_key, + std::string unit_key) { + static const double game_speed = configuration()->physics_config.game_speed; + static const double game_accel = configuration()->physics_config.game_accel; + static const double game_accel_speed = game_speed * game_accel; + + // Minimum drive capability for limp home (in %) + static const double minimal_drive_functionality = configuration()->fuel.minimum_drive; + + Component::Load(upgrade_key, unit_key); + + // Consumer + // We do not support all options here. + if(configuration()->fuel.drive_source == EnergyConsumerSource::Fuel) { + SetConsumption(1.0); + } else { + SetConsumption(1.0); + infinite = true; + } + + // Drive + yaw = Resource(UnitCSVFactory::GetVariable(unit_key, "Maneuver_Yaw", std::string("0.0")), + M_PI / 180.0, minimal_drive_functionality); + pitch = Resource(UnitCSVFactory::GetVariable(unit_key, "Maneuver_Pitch", std::string("0.0")), + M_PI / 180.0, minimal_drive_functionality); + roll = Resource(UnitCSVFactory::GetVariable(unit_key, "Maneuver_Roll", std::string("0.0")), + M_PI / 180.0, minimal_drive_functionality); + + ResourceYawPitchRollParser(unit_key, YPR::Yaw, max_yaw_right, max_yaw_left); + ResourceYawPitchRollParser(unit_key, YPR::Pitch, max_pitch_up, max_pitch_down); + ResourceYawPitchRollParser(unit_key, YPR::Roll, max_roll_right, max_roll_left); + + forward = Resource(UnitCSVFactory::GetVariable(unit_key, "Forward_Accel", std::string("0.0")), + game_accel_speed, minimal_drive_functionality); + retro = Resource(UnitCSVFactory::GetVariable(unit_key, "Retro_Accel", std::string("0.0")), + game_accel_speed, minimal_drive_functionality); + + const double lateral_accel = 0.5 * UnitCSVFactory::GetVariable(unit_key, "Left_Accel", 0.0) + + 0.5 * UnitCSVFactory::GetVariable(unit_key, "Right_Accel", 0.0); + const std::string lateral_accel_string = std::to_string(lateral_accel); + lateral = Resource(lateral_accel_string, game_accel_speed, minimal_drive_functionality); + + const double vertical_accel = 0.5 * UnitCSVFactory::GetVariable(unit_key, "Top_Accel", 0.0) + + 0.5 * UnitCSVFactory::GetVariable(unit_key, "Bottom_Accel", 0.0); + const std::string vertical_accel_string = std::to_string(vertical_accel); + vertical = Resource(vertical_accel_string, game_accel_speed, minimal_drive_functionality); + + speed = Resource(UnitCSVFactory::GetVariable(unit_key, "Default_Speed_Governor", std::string("0.0")), + game_speed, minimal_drive_functionality); +} + + + + +void Drive::SaveToCSV(std::map& unit) const { + static const double game_speed = configuration()->physics_config.game_speed; + static const double game_accel = configuration()->physics_config.game_accel; + static const double game_accel_speed = game_speed * game_accel; + const double to_degrees = 180 / M_PI; + unit["Maneuver_Yaw"] = yaw.Serialize(to_degrees); + unit["Maneuver_Pitch"] = pitch.Serialize(to_degrees); + unit["Maneuver_Roll"] = roll.Serialize(to_degrees); + + unit["Yaw_Governor_Right"] = max_yaw_right.Serialize(to_degrees); + unit["Yaw_Governor_Left"] = max_yaw_left.Serialize(to_degrees); + unit["Pitch_Governor_Up"] = max_pitch_up.Serialize(to_degrees); + unit["Pitch_Governor_Down"] = max_pitch_down.Serialize(to_degrees); + unit["Roll_Governor_Right"] = max_roll_right.Serialize(to_degrees); + unit["Roll_Governor_Left"] = max_roll_left.Serialize(to_degrees); + + + unit["Forward_Accel"] = forward.Serialize(game_accel_speed); + unit["Retro_Accel"] = retro.Serialize(game_accel_speed); + unit["Left_Accel"] = unit["Right_Accel"] = lateral.Serialize(game_accel_speed); + unit["Bottom_Accel"] = unit["Top_Accel"] = vertical.Serialize(game_accel_speed); + + unit["Default_Speed_Governor"] = speed.Serialize(game_speed); +} + +// Drive is integrated and so cannot be upgraded/downgraded +// Use DriveUpgrade to make changes +bool Drive::CanDowngrade() const { + return false; +} + +bool Drive::Downgrade() { + return false; +} + +bool Drive::CanUpgrade(const std::string upgrade_name) const { + return false; +} + +bool Drive::Upgrade(const std::string upgrade_name) { + return false; +} + + +void Drive::Damage() { + yaw.RandomDamage(); + pitch.RandomDamage(); + roll.RandomDamage(); + + lateral.RandomDamage(); + vertical.RandomDamage(); + forward.RandomDamage(); + retro.RandomDamage(); + + speed.RandomDamage(); + + max_yaw_left.RandomDamage(); + max_yaw_right.RandomDamage(); + max_pitch_down.RandomDamage(); + max_pitch_up.RandomDamage(); + max_roll_left.RandomDamage(); + max_roll_right.RandomDamage(); + + operational = (yaw.Percent() + pitch.Percent() + roll.Percent() + + lateral.Percent() + vertical.Percent() + forward.Percent() + + retro.Percent() + speed.Percent() + + max_yaw_left.Percent() + max_yaw_right.Percent() + max_pitch_down.Percent() + + max_pitch_up.Percent() + max_roll_left.Percent() + max_roll_right.Percent()) / 14 * 100; +} + +void Drive::DamageByPercent(double percent) { + yaw.DamageByPercent(percent); + pitch.DamageByPercent(percent); + roll.DamageByPercent(percent); + + lateral.DamageByPercent(percent); + vertical.DamageByPercent(percent); + forward.DamageByPercent(percent); + retro.DamageByPercent(percent); + + speed.DamageByPercent(percent); + + max_yaw_left.DamageByPercent(percent); + max_yaw_right.DamageByPercent(percent); + max_pitch_down.DamageByPercent(percent); + max_pitch_up.DamageByPercent(percent); + max_roll_left.DamageByPercent(percent); + max_roll_right.DamageByPercent(percent); + + operational = (yaw.Percent() + pitch.Percent() + roll.Percent() + + lateral.Percent() + vertical.Percent() + forward.Percent() + + retro.Percent() + speed.Percent() + + max_yaw_left.Percent() + max_yaw_right.Percent() + max_pitch_down.Percent() + + max_pitch_up.Percent() + max_roll_left.Percent() + max_roll_right.Percent()) / 14 * 100; +} + +void Drive::Repair() { + yaw.RepairFully(); + pitch.RepairFully(); + roll.RepairFully(); + + lateral.RepairFully(); + vertical.RepairFully(); + forward.RepairFully(); + retro.RepairFully(); + + speed.RepairFully(); + + max_yaw_left.RepairFully(); + max_yaw_right.RepairFully(); + max_pitch_down.RepairFully(); + max_pitch_up.RepairFully(); + max_roll_left.RepairFully(); + max_roll_right.RepairFully(); + + operational.RepairFully(); +} + + + + + + + + diff --git a/engine/src/components/drive.h b/engine/src/components/drive.h new file mode 100644 index 0000000000..edbaccc9bd --- /dev/null +++ b/engine/src/components/drive.h @@ -0,0 +1,96 @@ +/* + * drive.h + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#ifndef VEGA_STRIKE_ENGINE_COMPONENTS_DRIVE_H +#define VEGA_STRIKE_ENGINE_COMPONENTS_DRIVE_H + +#include "component.h" +#include "energy_consumer.h" + +#include "resource/resource.h" + +class EnergyContainer; + +class Drive : public Component, public EnergyConsumer { + // TODO: implement damage so something will actually happen + // Right now, damage is recorded in component superclass but game doesn't + // take it into account. + + /* @discussion use of Resource class in Drive + Unlike other use cases, where max, adjusted and value are all used, here + we only use max and adjusted. This shouldn't be an issue as adjusted and + value should be identical unless someone sets value to less. */ + + /* Afterburner was split from drive. Same comments apply there. */ +public: +// Limits + //max ypr--both pos/neg are symmetrical + Resource yaw; + Resource pitch; + Resource roll; + + //side-side engine thrust max + Resource lateral; + + //vertical engine thrust max + Resource vertical; + + //forward engine thrust max + Resource forward; + + //reverse engine thrust max + Resource retro; + +// Computer + //Computers limitation of speed during combat + Resource speed; + + //Computer's restrictions of YPR to limit space combat maneuvers + Resource max_yaw_left; + Resource max_yaw_right; + Resource max_pitch_down; + Resource max_pitch_up; + Resource max_roll_left; + Resource max_roll_right; + +// Constructors + Drive(EnergyContainer *source = nullptr); + + // Component Methods + virtual void Load(std::string upgrade_key, + std::string unit_key = ""); + + virtual void SaveToCSV(std::map& unit) const; + + virtual bool CanDowngrade() const; + virtual bool Downgrade(); + virtual bool CanUpgrade(const std::string upgrade_name) const; + virtual bool Upgrade(const std::string upgrade_name); + + virtual void Damage(); + virtual void DamageByPercent(double percent); + virtual void Repair(); +}; + +#endif // VEGA_STRIKE_ENGINE_COMPONENTS_DRIVE_H diff --git a/engine/src/components/drive_upgrade.cpp b/engine/src/components/drive_upgrade.cpp new file mode 100644 index 0000000000..63d17f57df --- /dev/null +++ b/engine/src/components/drive_upgrade.cpp @@ -0,0 +1,167 @@ +/* + * drive_upgrade.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include "drive_upgrade.h" + +#include "drive.h" +#include "component_utils.h" +#include "unit_csv_factory.h" + + +DriveUpgrade::DriveUpgrade(Drive *drive) : + Component(), + drive(drive), + yaw(1.0), pitch(1.0), roll(1.0), lateral(1.0), + vertical(1.0), forward(1.0), retro(1.0), afterburn(1.0), + speed(1.0), max_yaw_left(1.0), + max_yaw_right(1.0), max_pitch_down(1.0), max_pitch_up(1.0), + max_roll_left(1.0), max_roll_right(1.0), fuel_consumption(1.0) { + type = ComponentType::DriveUpgrade; +} + + + +// Component Methods +void DriveUpgrade::Load(std::string upgrade_key, + std::string unit_key) { + Component::Load(upgrade_key, unit_key); + + // Consumer + fuel_consumption = UnitCSVFactory::GetVariable(upgrade_key, "Fuel_Consumption", 1.0); + + // DriveUpgrade + yaw = UnitCSVFactory::GetVariable(upgrade_key, "Maneuver_Yaw", 1.0); + pitch = UnitCSVFactory::GetVariable(upgrade_key, "Maneuver_Pitch", 1.0); + roll = UnitCSVFactory::GetVariable(upgrade_key, "Maneuver_Roll", 1.0); + + DoubleYawPitchRollParser(upgrade_key, YPR::Yaw, max_yaw_right, max_yaw_left); + DoubleYawPitchRollParser(upgrade_key, YPR::Pitch, max_pitch_up, max_pitch_down); + DoubleYawPitchRollParser(upgrade_key, YPR::Roll, max_roll_right, max_roll_left); + + forward = UnitCSVFactory::GetVariable(upgrade_key, "Forward_Accel", 1.0); + retro = UnitCSVFactory::GetVariable(upgrade_key, "Retro_Accel", 1.0); + lateral = 0.5 * (UnitCSVFactory::GetVariable(upgrade_key, "Left_Accel", 1.0) + + UnitCSVFactory::GetVariable(upgrade_key, "Right_Accel", 1.0)); + + vertical = 0.5 * (UnitCSVFactory::GetVariable(upgrade_key, "Top_Accel", 1.0) + + UnitCSVFactory::GetVariable(upgrade_key, "Bottom_Accel", 1.0)); + + speed = UnitCSVFactory::GetVariable(upgrade_key, "Default_Speed_Governor", 1.0); +} + + +void DriveUpgrade::SaveToCSV(std::map& unit) const { + unit["Yaw_Governor_Right"] = max_yaw_right; + unit["Yaw_Governor_Left"] = max_yaw_left; + unit["Pitch_Governor_Up"] = max_pitch_up; + unit["Pitch_Governor_Down"] = max_pitch_down; + unit["Roll_Governor_Right"] = max_roll_right; + unit["Roll_Governor_Left"] = max_roll_left; + + unit["Forward_Accel"] = forward; + unit["Retro_Accel"] = retro; + unit["Left_Accel"] = unit["Right_Accel"] = lateral; + unit["Bottom_Accel"] = unit["Top_Accel"] = vertical; + + unit["Default_Speed_Governor"] = speed; +} + + +// Can only upgrade/downgrade if Drive is undamaged. +// Otherwise, there are a lot of edge cases. +bool DriveUpgrade::CanDowngrade() const { + return !drive->Damaged(); +} + +bool DriveUpgrade::Downgrade() { + if(!CanDowngrade()) { + return false; + } + + // Component + Component::Downgrade(); + + // Add effects of upgrade on drive + drive->yaw.SetMaxValue(drive->yaw.MaxValue() / yaw); + drive->pitch.SetMaxValue(drive->pitch.MaxValue() / pitch); + drive->roll.SetMaxValue(drive->roll.MaxValue() / roll); + + drive->lateral.SetMaxValue(drive->lateral.MaxValue() / lateral); + drive->vertical.SetMaxValue(drive->vertical.MaxValue() / vertical); + drive->forward.SetMaxValue(drive->forward.MaxValue() / forward); + drive->retro.SetMaxValue(drive->retro.MaxValue() / retro); + + drive->speed.SetMaxValue(drive->speed.MaxValue() / speed); + + drive->max_yaw_left.SetMaxValue(drive->max_yaw_left.MaxValue() / max_yaw_left); + drive->max_yaw_right.SetMaxValue(drive->max_yaw_right.MaxValue() / max_yaw_right); + drive->max_pitch_up.SetMaxValue(drive->max_pitch_up.MaxValue() / max_pitch_up); + drive->max_pitch_down.SetMaxValue(drive->max_pitch_down.MaxValue() / max_pitch_down); + drive->max_roll_left.SetMaxValue(drive->max_roll_left.MaxValue() / max_roll_left); + drive->max_roll_right.SetMaxValue(drive->max_roll_right.MaxValue() / max_roll_right); + + drive->SetConsumption(drive->GetConsumption() / fuel_consumption); + + yaw = pitch = roll = lateral = vertical = forward = retro = speed = fuel_consumption = 1.0; + max_yaw_left = max_yaw_right = max_pitch_up = max_pitch_down = max_roll_left = max_roll_right = 1.0; +} + +bool DriveUpgrade::CanUpgrade(const std::string upgrade_name) const { + return !drive->Damaged(); +} + +bool DriveUpgrade::Upgrade(const std::string upgrade_name) { + if(!CanUpgrade(upgrade_name)) { + return false; + } + + // Component + Component::Upgrade(upgrade_name + "__upgrades"); + + // Load modifiers + Load(upgrade_name + "__upgrades"); + + // Add effects of upgrade on drive + drive->yaw.SetMaxValue(drive->yaw.MaxValue() * yaw); + drive->pitch.SetMaxValue(drive->pitch.MaxValue() * pitch); + drive->roll.SetMaxValue(drive->roll.MaxValue() * roll); + + drive->lateral.SetMaxValue(drive->lateral.MaxValue() * lateral); + drive->vertical.SetMaxValue(drive->vertical.MaxValue() * vertical); + drive->forward.SetMaxValue(drive->forward.MaxValue() * forward); + drive->retro.SetMaxValue(drive->retro.MaxValue() * retro); + + drive->speed.SetMaxValue(drive->speed.MaxValue() * speed); + + drive->max_yaw_left.SetMaxValue(drive->max_yaw_left.MaxValue() * max_yaw_left); + drive->max_yaw_right.SetMaxValue(drive->max_yaw_right.MaxValue() * max_yaw_right); + drive->max_pitch_up.SetMaxValue(drive->max_pitch_up.MaxValue() * max_pitch_up); + drive->max_pitch_down.SetMaxValue(drive->max_pitch_down.MaxValue() * max_pitch_down); + drive->max_roll_left.SetMaxValue(drive->max_roll_left.MaxValue() * max_roll_left); + drive->max_roll_right.SetMaxValue(drive->max_roll_right.MaxValue() * max_roll_right); + + drive->SetConsumption(drive->GetConsumption() * fuel_consumption); +} + + diff --git a/engine/src/components/drive_upgrade.h b/engine/src/components/drive_upgrade.h new file mode 100644 index 0000000000..c394c587a2 --- /dev/null +++ b/engine/src/components/drive_upgrade.h @@ -0,0 +1,96 @@ +/* + * drive_upgrade.h + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#ifndef VEGA_STRIKE_ENGINE_COMPONENTS_DRIVE_UPGRADE_H +#define VEGA_STRIKE_ENGINE_COMPONENTS_DRIVE_UPGRADE_H + +#include "component.h" + +class Drive; + +/** A DriveUpgrade applies a modifier to Drive class. + * This is a unique use case from other components, as allowing a slow + * ship (e.g. cargo) to upgrade to a fighter engine would break both + * game balance and believability. + * The game previously supported both additive and multiplicative upgrades. + * I've removed the additive one for simplicity's sake. + */ +class DriveUpgrade : public Component { +public: + Drive *drive; + +// Limits + //max ypr--both pos/neg are symmetrical + double yaw; + double pitch; + double roll; + + //side-side engine thrust max + double lateral; + + //vertical engine thrust max + double vertical; + + //forward engine thrust max + double forward; + + //reverse engine thrust max + double retro; + + //after burner acceleration max + double afterburn; + +// Computer + //Computers limitation of speed + double speed; + + //Computer's restrictions of YPR to limit space combat maneuvers + double max_yaw_left; + double max_yaw_right; + double max_pitch_down; + double max_pitch_up; + double max_roll_left; + double max_roll_right; + + double fuel_consumption; + +// Constructors + DriveUpgrade(Drive *drive = nullptr); + + // Component Methods + virtual void Load(std::string upgrade_key, + std::string unit_key = ""); + + virtual void SaveToCSV(std::map& unit) const; + + virtual bool CanDowngrade() const; + + virtual bool Downgrade(); + + virtual bool CanUpgrade(const std::string upgrade_name) const; + + virtual bool Upgrade(const std::string upgrade_name); +}; + +#endif // VEGA_STRIKE_ENGINE_COMPONENTS_DRIVE_UPGRADE_H diff --git a/engine/src/components/dummy_component.cpp b/engine/src/components/dummy_component.cpp new file mode 100644 index 0000000000..df352c17e0 --- /dev/null +++ b/engine/src/components/dummy_component.cpp @@ -0,0 +1,57 @@ +/* + * dummy_component.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include "dummy_component.h" + + +DummyComponent::DummyComponent() : + Component() { + type = ComponentType::Dummy; +} + + +// Component Methods +void DummyComponent::Load(std::string upgrade_key, + std::string unit_key) { + Component::Load(upgrade_key, unit_key); +} + +void DummyComponent::SaveToCSV(std::map& unit) const {} + +bool DummyComponent::CanDowngrade() const { + return false; +} + +bool DummyComponent::Downgrade() { + return false; +} + +bool DummyComponent::CanUpgrade(const std::string upgrade_name) const { + return false; +} + +bool DummyComponent::Upgrade(const std::string upgrade_name) { + return false; +} + diff --git a/engine/src/components/dummy_component.h b/engine/src/components/dummy_component.h new file mode 100644 index 0000000000..39861b4df2 --- /dev/null +++ b/engine/src/components/dummy_component.h @@ -0,0 +1,50 @@ +/* + * dummy_component.h + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#ifndef VEGA_STRIKE_ENGINE_COMPONENTS_DUMMY_COMPONENT_H +#define VEGA_STRIKE_ENGINE_COMPONENTS_DUMMY_COMPONENT_H + +#include "component.h" + +/** A dummy component. Does nothing. Comes in useful in some places. */ +class DummyComponent : public Component { +public: + DummyComponent(); + + // Component Methods + virtual void Load(std::string upgrade_key, + std::string unit_key = ""); + + virtual void SaveToCSV(std::map& unit) const; + + virtual bool CanDowngrade() const; + + virtual bool Downgrade(); + + virtual bool CanUpgrade(const std::string upgrade_name) const; + + virtual bool Upgrade(const std::string upgrade_name); +}; + +#endif // VEGA_STRIKE_ENGINE_COMPONENTS_DUMMY_COMPONENT_H diff --git a/engine/src/components/jump_drive.cpp b/engine/src/components/jump_drive.cpp index 5478424aed..12359062a6 100644 --- a/engine/src/components/jump_drive.cpp +++ b/engine/src/components/jump_drive.cpp @@ -87,11 +87,7 @@ void JumpDrive::Load(std::string upgrade_key, std::string unit_key) { // Jump Drive - bool installed = UnitCSVFactory::GetVariable(unit_key, "Jump_Drive_Present", false); - if(!installed) { - this->unit_key = ""; - } - + installed = UnitCSVFactory::GetVariable(unit_key, "Jump_Drive_Present", false); delay = UnitCSVFactory::GetVariable(unit_key, "Jump_Drive_Delay", 0); } diff --git a/engine/src/components/tests/afterburner_tests.cpp b/engine/src/components/tests/afterburner_tests.cpp new file mode 100644 index 0000000000..6aaa60ff83 --- /dev/null +++ b/engine/src/components/tests/afterburner_tests.cpp @@ -0,0 +1,119 @@ +/* + * afterburner_tests.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include +#include + +#include "afterburner.h" +#include "afterburner_upgrade.h" + +#include "unit_csv_factory.h" + +static const std::string upgrades_suffix_string = "__upgrades"; +const std::string afterburner_string = "afterburner"; +const std::string upgrade_string = "upgrade"; + +std::map afterburner_map = { + { "Name", "Afterburner"}, + { "Mass", "5.0"}, + { "Afterburner_Accel", "10"}, + { "Afterburner_Speed_Governor", "100"}, + { "Afterburner_Usage_Cost", "2.0"} +}; + +std::map afterburner_upgrade_map = { + { "Name", "AfterburnerUpgrade"}, + { "Mass", "5.0"}, + { "Afterburner_Accel", "1.5"}, + { "Afterburner_Speed_Governor", "1.5"}, + { "Afterburner_Usage_Cost", "1.5"} +}; + +TEST(Afterburner, Sanity) { + UnitCSVFactory::LoadUnit(afterburner_string + upgrades_suffix_string, afterburner_map); + UnitCSVFactory::LoadUnit(upgrade_string + upgrades_suffix_string, afterburner_upgrade_map); + + Afterburner afterburner; + AfterburnerUpgrade upgrade(&afterburner); + + afterburner.Load("", afterburner_string + upgrades_suffix_string); + upgrade.Load(upgrade_string + upgrades_suffix_string); + + EXPECT_EQ(afterburner.GetMass(), 0.0); + EXPECT_EQ(afterburner.thrust.MaxValue(), 10.0); + EXPECT_EQ(afterburner.speed.MaxValue(), 100.0); + EXPECT_EQ(afterburner.GetConsumption(), 2.0); + + EXPECT_EQ(upgrade.GetMass(), 5.0); + EXPECT_EQ(upgrade.thrust, 1.5); + EXPECT_EQ(upgrade.speed, 1.5); + EXPECT_EQ(upgrade.consumption, 1.5); +} + +TEST(Afterburner, UpgradeDowngrade) { + UnitCSVFactory::LoadUnit(afterburner_string + upgrades_suffix_string, afterburner_map); + UnitCSVFactory::LoadUnit(upgrade_string + upgrades_suffix_string, afterburner_upgrade_map); + + Afterburner afterburner; + AfterburnerUpgrade upgrade(&afterburner); + + afterburner.Load("", afterburner_string + upgrades_suffix_string); + + // Original + EXPECT_EQ(afterburner.GetMass(), 0.0); + EXPECT_EQ(afterburner.thrust.MaxValue(), 10.0); + EXPECT_EQ(afterburner.speed.MaxValue(), 100.0); + EXPECT_EQ(afterburner.GetConsumption(), 2.0); + + EXPECT_EQ(upgrade.GetMass(), 0.0); + EXPECT_EQ(upgrade.thrust, 1.0); + EXPECT_EQ(upgrade.speed, 1.0); + EXPECT_EQ(upgrade.consumption, 1.0); + + // Upgrade + upgrade.Upgrade(upgrade_string); + + EXPECT_EQ(afterburner.GetMass(), 0.0); + EXPECT_EQ(afterburner.thrust.MaxValue(), 15.0); + EXPECT_EQ(afterburner.speed.MaxValue(), 150.0); + EXPECT_EQ(afterburner.GetConsumption(), 3.0); + + EXPECT_EQ(upgrade.GetMass(), 5.0); + EXPECT_EQ(upgrade.thrust, 1.5); + EXPECT_EQ(upgrade.speed, 1.5); + EXPECT_EQ(upgrade.consumption, 1.5); + + // Downgrade + upgrade.Downgrade(); + + EXPECT_EQ(afterburner.GetMass(), 0.0); + EXPECT_EQ(afterburner.thrust.MaxValue(), 10.0); + EXPECT_EQ(afterburner.speed.MaxValue(), 100.0); + EXPECT_EQ(afterburner.GetConsumption(), 2.0); + + EXPECT_EQ(upgrade.GetMass(), 0.0); + EXPECT_EQ(upgrade.thrust, 1.0); + EXPECT_EQ(upgrade.speed, 1.0); + EXPECT_EQ(upgrade.consumption, 1.0); +} \ No newline at end of file diff --git a/engine/src/components/tests/drive_tests.cpp b/engine/src/components/tests/drive_tests.cpp new file mode 100644 index 0000000000..78b4e09514 --- /dev/null +++ b/engine/src/components/tests/drive_tests.cpp @@ -0,0 +1,219 @@ +/* + * drive_tests.cpp + * + * Copyright (C) 2001-2023 Daniel Horn, Benjamen Meyer, Roy Falk, Stephen G. Tuggy, + * and other Vega Strike contributors. + * + * https://github.com/vegastrike/Vega-Strike-Engine-Source + * + * This file is part of Vega Strike. + * + * Vega Strike is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Vega Strike is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Vega Strike. If not, see . + */ + +#include +#include +#include +#include + +#include "drive.h" +#include "drive_upgrade.h" + +#include "unit_csv_factory.h" + +static const std::string upgrades_suffix_string = "__upgrades"; +static const std::string drive_string = "drive"; +static const std::string upgrade_string = "upgrade"; + +static const std::map drive_map = { + { "Name", "Drive"}, + { "Mass", "5.0"}, + { "Maneuver_Yaw", "10.0" }, + { "Maneuver_Pitch", "10.0" }, + { "Maneuver_Roll", "10.0" }, + { "Forward_Accel", "10.0" }, + { "Retro_Accel", "10.0" }, + { "Left_Accel", "10.0" }, + { "Right_Accel", "10.0" }, + { "Top_Accel", "10.0" }, + { "Bottom_Accel", "10.0" }, + { "Default_Speed_Governor", "10.0" }, + { "Yaw_Governor", "10.0" }, + { "Yaw_Governor", "10.0" }, + { "Yaw_Governor", "10.0" }, + { "Pitch_Governor", "10.0" }, + { "Pitch_Governor_Up", "10.0" }, + { "Pitch_Governor_Down", "10.0" }, + { "Roll_Governor", "10.0" }, + { "Roll_Governor_Right", "10.0" }, + { "Roll_Governor_Left", "10.0" } +}; + +static const std::map drive_upgrade_map = { + { "Name", "Upgrade"}, + { "Mass", "5.0"}, + { "Fuel_Consumption", "1.5"}, + { "Maneuver_Yaw", "1.5" }, + { "Maneuver_Pitch", "1.5" }, + { "Maneuver_Roll", "1.5" }, + { "Forward_Accel", "1.5" }, + { "Retro_Accel", "1.5" }, + { "Left_Accel", "1.5" }, + { "Right_Accel", "1.5" }, + { "Top_Accel", "1.5" }, + { "Bottom_Accel", "1.5" }, + { "Default_Speed_Governor", "1.5" }, + { "Yaw_Governor", "1.5" }, + { "Yaw_Governor", "1.5" }, + { "Yaw_Governor", "1.5" }, + { "Pitch_Governor", "1.5" }, + { "Pitch_Governor_Up", "1.5" }, + { "Pitch_Governor_Down", "1.5" }, + { "Roll_Governor", "1.5" }, + { "Roll_Governor_Right", "1.5" }, + { "Roll_Governor_Left", "1.5" } +}; + +static void DriveExpectEq(Drive& drive, const double value) { + EXPECT_EQ(drive.yaw.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.pitch.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.roll.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.forward.MaxValue(), value); + EXPECT_EQ(drive.retro.MaxValue(), value); + EXPECT_EQ(drive.lateral.MaxValue(), value); + EXPECT_EQ(drive.vertical.MaxValue(), value); + EXPECT_EQ(drive.speed.MaxValue(), value); + + EXPECT_EQ(drive.max_pitch_down.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.max_pitch_up.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.max_roll_left.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.max_roll_right.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.max_yaw_left.MaxValue(), value * M_PI / 180.0); + EXPECT_EQ(drive.max_yaw_right.MaxValue(), value * M_PI / 180.0); +} + +static void DriveUpgradeExpectEq(DriveUpgrade &upgrade, const double value) { + EXPECT_EQ(upgrade.yaw, value); + EXPECT_EQ(upgrade.pitch, value); + EXPECT_EQ(upgrade.roll, value); + EXPECT_EQ(upgrade.forward, value); + EXPECT_EQ(upgrade.retro, value); + EXPECT_EQ(upgrade.lateral, value); + EXPECT_EQ(upgrade.vertical, value); + + EXPECT_EQ(upgrade.max_pitch_down, value); + EXPECT_EQ(upgrade.max_pitch_up, value); + EXPECT_EQ(upgrade.max_roll_left, value); + EXPECT_EQ(upgrade.max_roll_right, value); + EXPECT_EQ(upgrade.max_yaw_left, value); + EXPECT_EQ(upgrade.max_yaw_right, value); +} + + +TEST(Drive, Sanity) { + UnitCSVFactory::LoadUnit(drive_string + upgrades_suffix_string, drive_map); + UnitCSVFactory::LoadUnit(upgrade_string + upgrades_suffix_string, drive_upgrade_map); + + Drive drive; + DriveUpgrade upgrade(&drive); + + drive.Load("", drive_string + upgrades_suffix_string); + upgrade.Load(upgrade_string + upgrades_suffix_string); + + // Check Drive Values + EXPECT_EQ(drive.GetUpgradeName(), ""); // Integrated + EXPECT_EQ(drive.GetMass(), 0.0); + + DriveExpectEq(drive, 10.0); + + EXPECT_EQ(drive.GetConsumption(), 1.0); + + // Check DriveUpgrade Values + EXPECT_EQ(upgrade.GetUpgradeName(), "Upgrade"); + EXPECT_EQ(upgrade.GetMass(), 5.0); + + DriveUpgradeExpectEq(upgrade, 1.5); + + EXPECT_EQ(upgrade.fuel_consumption, 1.5); +} + +TEST(Drive, UpgradeDowngrade) { + UnitCSVFactory::LoadUnit(drive_string + upgrades_suffix_string, drive_map); + UnitCSVFactory::LoadUnit(upgrade_string + upgrades_suffix_string, drive_upgrade_map); + + Drive drive; + DriveUpgrade upgrade(&drive); + + drive.Load("", drive_string + upgrades_suffix_string); + +// Original + std::cout << "Original\n--------\n"; + + // Drive + EXPECT_EQ(drive.GetUpgradeName(), ""); + EXPECT_EQ(drive.GetMass(), 0.0); + + DriveExpectEq(drive, 10.0); + + EXPECT_EQ(drive.GetConsumption(), 1.0); + + // Upgrade + EXPECT_EQ(upgrade.GetUpgradeName(), ""); + EXPECT_EQ(upgrade.GetMass(), 0.0); + + DriveUpgradeExpectEq(upgrade, 1.0); + + EXPECT_EQ(upgrade.fuel_consumption, 1.0); + +// Upgrade + std::cout << "Upgrade\n-------\n"; + + // Drive + upgrade.Upgrade(upgrade_string); + + EXPECT_EQ(drive.GetUpgradeName(), ""); + EXPECT_EQ(drive.GetMass(), 0.0); + + DriveExpectEq(drive, 15.0); + + EXPECT_EQ(drive.GetConsumption(), 1.5); + + // Upgrade + EXPECT_EQ(upgrade.GetUpgradeName(), "Upgrade"); + EXPECT_EQ(upgrade.GetMass(), 5.0); + + DriveUpgradeExpectEq(upgrade, 1.5); + + EXPECT_EQ(upgrade.fuel_consumption, 1.5); + +// Downgrade + std::cout << "Downgrade\n---------\n"; + // Drive + upgrade.Downgrade(); + + EXPECT_EQ(drive.GetUpgradeName(), ""); + EXPECT_EQ(drive.GetMass(), 0.0); + + DriveExpectEq(drive, 10.0); + + EXPECT_EQ(drive.GetConsumption(), 1.0); + + // Upgrade + EXPECT_EQ(upgrade.GetUpgradeName(), ""); + EXPECT_EQ(upgrade.GetMass(), 0.0); + + DriveUpgradeExpectEq(upgrade, 1.0); + + EXPECT_EQ(upgrade.fuel_consumption, 1.0); +} \ No newline at end of file diff --git a/engine/src/configuration/configuration.cpp b/engine/src/configuration/configuration.cpp index 26f1b3c1fb..f43a4ac95f 100644 --- a/engine/src/configuration/configuration.cpp +++ b/engine/src/configuration/configuration.cpp @@ -328,8 +328,9 @@ void Configuration::OverrideDefaultsWithUserConfiguration() { physics_config.max_ecm = GetGameConfig().GetSizeT("physics.max_ecm", physics_config.max_ecm); physics_config.max_lost_target_live_time = GetGameConfig().GetFloat("physics.max_lost_target_live_time", physics_config.max_lost_target_live_time); physics_config.percent_missile_match_target_velocity = GetGameConfig().GetFloat("physics.percent_missile_match_target_velocity", physics_config.percent_missile_match_target_velocity); - physics_config.game_speed = GetGameConfig().GetFloat("physics.game_speed", physics_config.game_speed); - physics_config.game_accel = GetGameConfig().GetFloat("physics.game_accel", physics_config.game_accel); + physics_config.game_speed = GetGameConfig().GetDouble("physics.game_speed", physics_config.game_speed); + physics_config.game_accel = GetGameConfig().GetDouble("physics.game_accel", physics_config.game_accel); + physics_config.combat_mode_multiplier = GetGameConfig().GetDouble("physics.combat_mode_multiplier", physics_config.combat_mode_multiplier); physics_config.velocity_max = GetGameConfig().GetFloat("physics.velocity_max", physics_config.velocity_max); physics_config.max_player_rotation_rate = GetGameConfig().GetFloat("physics.maxplayerrot", physics_config.max_player_rotation_rate); physics_config.max_non_player_rotation_rate = GetGameConfig().GetFloat("physics.maxNPCrot", physics_config.max_non_player_rotation_rate); diff --git a/engine/src/configuration/configuration.h b/engine/src/configuration/configuration.h index b1f520f373..890e64da57 100644 --- a/engine/src/configuration/configuration.h +++ b/engine/src/configuration/configuration.h @@ -187,9 +187,15 @@ struct Fuel { float min_reactor_efficiency{0.00001F}; float ecm_energy_cost{0.05F}; - double fuel_factor{60.0}; // Multiply fuel by this to get fuel by minutes + double megajoules_factor{100}; + + // Reduce the number of tons in a ship to something realistic + // The more we multiply fuel_factor, the more we match here + double fuel_ton_modifier{0.0001}; + + double fuel_factor{1000.0}; // Multiply fuel by this to get fuel by minutes double energy_factor{1.0}; - double ftl_energy_factor{0.1}; + double ftl_energy_factor{1.0}; double reactor_factor{1.0}; @@ -382,8 +388,9 @@ struct PhysicsConfig { uintmax_t max_ecm{4U}; float max_lost_target_live_time{30.0F}; float percent_missile_match_target_velocity{1.0F}; - float game_speed{1.0F}; - float game_accel{1.0F}; + double game_speed{1.0}; + double game_accel{1.0}; + double combat_mode_multiplier{100.0}; float velocity_max{10000.0F}; float max_player_rotation_rate{24.0F}; float max_non_player_rotation_rate{360.0F}; diff --git a/engine/src/gfx/cockpit.cpp b/engine/src/gfx/cockpit.cpp index 651cd79930..fbcdcf9c41 100644 --- a/engine/src/gfx/cockpit.cpp +++ b/engine/src/gfx/cockpit.cpp @@ -559,13 +559,13 @@ float GameCockpit::LookupUnitStat(int stat, Unit *target) { value = target->GetComputerData().set_speed; break; case UnitImages::MAXKPS: - value = target->GetComputerData().max_speed(); + value = target->MaxSpeed(); break; case UnitImages::MAXCOMBATKPS: - value = target->GetComputerData().max_combat_speed; + value = target->drive.speed.Value(); break; case UnitImages::MAXCOMBATABKPS: - value = target->GetComputerData().max_combat_ab_speed; + value = target->afterburner.speed.Value(); break; default: value = 0; diff --git a/engine/src/gfx/nav/drawsystem.cpp b/engine/src/gfx/nav/drawsystem.cpp index 13d04729fd..ce164c5997 100644 --- a/engine/src/gfx/nav/drawsystem.cpp +++ b/engine/src/gfx/nav/drawsystem.cpp @@ -303,7 +303,7 @@ void NavigationSystem::DrawSystem() { * {*/ if (UnitUtil::isSignificant(*blah)) { //capship or station - if ((*blah)->GetComputerData().max_speed() == 0) { + if ((*blah)->MaxSpeed() == 0) { //is this item STATIONARY? insert_type = navstation; insert_size = navstationsize; diff --git a/engine/src/ship_commands.cpp b/engine/src/ship_commands.cpp index 07ed7a2267..ffa98e0f32 100644 --- a/engine/src/ship_commands.cpp +++ b/engine/src/ship_commands.cpp @@ -149,7 +149,7 @@ void ShipCommands::setkps(const char *in) { } else { kps /= game_options()->display_in_meters ? 1.0f : 3.6f; } - player->GetComputerData().set_speed = fmin(player->GetComputerData().max_speed(), kps); + player->GetComputerData().set_speed = fmin(player->MaxSpeed(), kps); } }