Skip to content

Commit

Permalink
Implement hull, armor and shield components (#1016)
Browse files Browse the repository at this point in the history
* Remove 8 facet support for armor and shield

Remove extra text in ship_view from the C++ end of things (basecomputer)

* Implement hull, armor and shield components

- Delete Health class. Very similar to Resource.
- Move functions to components - e.g. Percent, Get,
- Move shield functionality like AdjustPower from DamageableLayer to Shield class
- Disable enhance shields from collision. This should probably be handled by a python script.
- Delete many functions that are now unused.
- Delete x4 sparkling missile
- Delete planet.cpp fawg weird hull value
- Delete incorrect GetHullPercent by planet. For now it can be damaged and destroyed.
- Move some python API from macros to actual code.
- Fix issue in energy_container, where Capacitor and FTL Capacitor were not saved.
- Add two shield factors in configuration. Currently not read from file.

* Fix bug in units.json and ships.json reading.

If file doesn't open, game crashes.
Polish the code a little.

* Tweak the shield modifiers to make the game work better.

This stops the shields from eating all the reactor capacity.

* Make upgrade view take unit stats into account.

Upgrades installed on ship now display damage.
Fix bug #1019.
Convert Radar_Range to int before saving - prevent exponent format for upgrade view.
Fix issue in armor and shield, where Resource was initiated without max value. Use proper string constructor instead.
Fix issue in armor, hull and shield, where PercentOperational did not use actual libdamage damage.
Fix issue in EnergyContainer applied modifier in the wrong direction. Also, use Serialize to save all three values.
Fix issue in Reactor, where Serialize was not used.

* Add support for new lib component style upgrade repair

Add integral components to ship - hull, afterburner, drive and FTL drive.
Fix incorrect reporting of operational as 0-100 and not 0-1.
Add missing functions in several components - Damaged, Repair.
Fix several bugs in EnergyContainer, including applying fuel_factor to energy and ftl_energy.
Correct issue with Reactor incorrectly apply reactor_factor when saving.
Fix issue in armor and shield, where the value is read incorrectly.
Delete unused code from energetic.

* Fix several issues:

- Component repairs cost money again
- Some sanity checks for eject cargo
- Integral components have non-zero volume and mass. Prevent all sorts of nan errors in code.
- General repair and refuel no longer repairs integral components.
- Shield no longer reports shield strength as percent operational. Damaged/Fixing shields is now also reported correctly.

* Fix issue of repairs not costing money.

Possible fix for multiple integral components.
  • Loading branch information
royfalk authored Feb 18, 2025
1 parent 8479b9b commit ca3df7f
Show file tree
Hide file tree
Showing 57 changed files with 1,564 additions and 1,737 deletions.
6 changes: 4 additions & 2 deletions engine/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,6 @@ SET(LIBCONFIG
SET(LIBDAMAGE
src/damage/damageable_layer.cpp
src/damage/damageable_object.cpp
src/damage/health.cpp
)

SET(LIBRESOURCE
Expand All @@ -486,6 +485,10 @@ SET(LIBCOMPONENT
src/components/energy_container.cpp
src/components/reactor.cpp

src/components/armor.cpp
src/components/hull.cpp
src/components/shield.cpp

src/components/afterburner.cpp
src/components/afterburner_upgrade.cpp
src/components/cloak.cpp
Expand Down Expand Up @@ -1479,7 +1482,6 @@ IF (USE_GTEST)
src/cmd/tests/csv_tests.cpp
src/cmd/tests/json_tests.cpp
src/configuration/tests/configuration_tests.cpp
src/damage/tests/health_tests.cpp
src/damage/tests/layer_tests.cpp
src/damage/tests/object_tests.cpp
src/resource/tests/buy_sell.cpp
Expand Down
43 changes: 22 additions & 21 deletions engine/src/cmd/ai/aggressive.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,16 +260,16 @@ void AggressiveAI::SetParent(Unit *parent1) {
last_directive = "b"; //prevent escort race condition

//INIT stored stuff
Fshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->FShieldData();
Fshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::front);
Fshield_rate_old = 0.0;
Fshield_prev_time = UniverseUtil::GetGameTime();
Bshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->BShieldData();
Bshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::back);
Bshield_rate_old = 0.0;
Bshield_prev_time = UniverseUtil::GetGameTime();
Lshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->LShieldData();
Lshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::left);
Lshield_rate_old = 0.0;
Lshield_prev_time = UniverseUtil::GetGameTime();
Rshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->RShieldData();
Rshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::right);
Rshield_rate_old = 0.0;
Rshield_prev_time = UniverseUtil::GetGameTime();
Farmour_prev = 1.0;
Expand All @@ -284,7 +284,7 @@ void AggressiveAI::SetParent(Unit *parent1) {
Rarmour_prev = 1.0;
Rarmour_rate_old = 0.0;
Rarmour_prev_time = UniverseUtil::GetGameTime();
Hull_prev = parent->GetHullPercent();
Hull_prev = parent->hull.Percent();
Hull_rate_old = 0.0;
Hull_prev_time = UniverseUtil::GetGameTime();
}
Expand Down Expand Up @@ -333,30 +333,31 @@ bool AggressiveAI::ProcessLogicItem(const AIEvents::AIEvresult &item) {
value = parent->GetComputerData().threatlevel;
break;
case FSHIELD:
value = parent->ftl_drive.Enabled() ? 1 : parent->FShieldData();
value = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::front);
break;
case BSHIELD:
value = parent->ftl_drive.Enabled() ? 1 : parent->BShieldData();
value = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::back);
break;
case HULL: {
value = parent->GetHullPercent();
value = parent->hull.Percent();
break;
}
case LSHIELD:
value = parent->ftl_drive.Enabled() ? 1 : parent->LShieldData();
value = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::left);
break;
case RSHIELD:
value = parent->ftl_drive.Enabled() ? 1 : parent->RShieldData();
value = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::right);
break;
case FSHIELD_HEAL_RATE: {
// TODO: refactor this. We don't need to repeat this code
double delta_t = UniverseUtil::GetGameTime() - Fshield_prev_time;
if (delta_t > 0.5) {
//0.5 = reaction time limit for hit rate
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->FShieldData() - Fshield_prev;
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::front) - Fshield_prev;
value = delta_v / delta_t;
Fshield_rate_old = value;
Fshield_prev_time = UniverseUtil::GetGameTime();
Fshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->FShieldData();
Fshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::front);
} else {
value = Fshield_rate_old;
}
Expand All @@ -366,11 +367,11 @@ bool AggressiveAI::ProcessLogicItem(const AIEvents::AIEvresult &item) {
double delta_t = UniverseUtil::GetGameTime() - Bshield_prev_time;
if (delta_t > 0.5) {
//0.5 = reaction time limit for hit rate
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->BShieldData() - Bshield_prev;
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::back) - Bshield_prev;
value = delta_v / delta_t;
Bshield_rate_old = value;
Bshield_prev_time = UniverseUtil::GetGameTime();
Bshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->BShieldData();
Bshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::back);
} else {
value = Bshield_rate_old;
}
Expand All @@ -380,11 +381,11 @@ bool AggressiveAI::ProcessLogicItem(const AIEvents::AIEvresult &item) {
double delta_t = UniverseUtil::GetGameTime() - Lshield_prev_time;
if (delta_t > 0.5) {
//0.5 = reaction time limit for hit rate
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->LShieldData() - Lshield_prev;
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::left) - Lshield_prev;
value = delta_v / delta_t;
Lshield_rate_old = value;
Lshield_prev_time = UniverseUtil::GetGameTime();
Lshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->LShieldData();
Lshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::left);
} else {
value = Lshield_rate_old;
}
Expand All @@ -394,11 +395,11 @@ bool AggressiveAI::ProcessLogicItem(const AIEvents::AIEvresult &item) {
double delta_t = UniverseUtil::GetGameTime() - Rshield_prev_time;
if (delta_t > 0.5) {
//0.5 = reaction time limit for hit rate
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->RShieldData() - Rshield_prev;
double delta_v = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::right) - Rshield_prev;
value = delta_v / delta_t;
Rshield_rate_old = value;
Rshield_prev_time = UniverseUtil::GetGameTime();
Rshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->RShieldData();
Rshield_prev = parent->ftl_drive.Enabled() ? 1 : parent->shield.Percent(Shield::right);
} else {
value = Rshield_rate_old;
}
Expand All @@ -420,11 +421,11 @@ bool AggressiveAI::ProcessLogicItem(const AIEvents::AIEvresult &item) {
double delta_t = UniverseUtil::GetGameTime() - Hull_prev_time;
if (delta_t > 0.5) {
//0.5 = reaction time limit for hit rate
double delta_v = parent->GetHullPercent() - Hull_prev;
double delta_v = parent->hull.Percent() - Hull_prev;
value = delta_v / delta_t;
Hull_rate_old = value;
Hull_prev_time = UniverseUtil::GetGameTime();
Hull_prev = parent->GetHullPercent();
Hull_prev = parent->hull.Percent();
} else {
value = Hull_rate_old;
}
Expand Down Expand Up @@ -1190,7 +1191,7 @@ void AggressiveAI::ReCommandWing(Flightgroup *fg) {
//computer won't override capital orders
if (nullptr != (lead = fg->leader.GetUnit())) {
if (float ( rand())/RAND_MAX < simulation_atom_var / time_to_recommand_wing) {
if (parent->Threat() && (parent->FShieldData() < .2 || parent->RShieldData() < .2)) {
if (parent->Threat() && (parent->shield.Percent() < .2)) {
fg->directive = string("h");
LeadMe(parent, "h", "I need help here!", false);
if (verbose_debug) {
Expand Down
8 changes: 4 additions & 4 deletions engine/src/cmd/ai/firekeyboard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1194,7 +1194,7 @@ bool ChooseTargets(Unit *me, bool (*typeofunit)(Unit *, Unit *), bool reverse) {
int cur = 0;
while (1) {
while (veciter != vec.end()) {
if (((*veciter) != me) && ((*veciter)->GetHull() >= 0) && typeofunit(me, (*veciter))) {
if (((*veciter) != me) && ((*veciter)->hull.Get() >= 0) && typeofunit(me, (*veciter))) {
me->Target(*veciter);

if ((*veciter) != NULL) {
Expand Down Expand Up @@ -1541,7 +1541,7 @@ void FireKeyboard::ProcessCommMessage(class CommunicationMessage &c) {
} //wait till later

bool reallydospeech = false;
if (un && un->GetHull() > 0) {
if (un && !un->Destroyed()) {
reallydospeech = true;
for (list<CommunicationMessage>::iterator i = resp.begin(); i != resp.end(); i++) {
if ((*i).sender.GetUnit() == un) {
Expand Down Expand Up @@ -1715,7 +1715,7 @@ void FireKeyboard::Execute() {
if (targ) {
double mm = 0.0;
ShouldFire(targ);
if (targ->GetHull() < 0) {
if (targ->Destroyed()) {
parent->Target(NULL);
ForceChangeTarget(parent);
refresh_target = true;
Expand All @@ -1732,7 +1732,7 @@ void FireKeyboard::Execute() {

float f_result = f().shieldpowerstate;
if (f_result != 1) {
parent->shield->AdjustPower(f_result);
parent->shield.AdjustPower(f_result);
}
if (f().firekey == PRESS || f().jfirekey == PRESS || j().firekey == DOWN || j().jfirekey == DOWN) {
if (!_Universe->AccessCockpit()->CanDrawNavSystem()) {
Expand Down
23 changes: 13 additions & 10 deletions engine/src/cmd/basecomputer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -245,7 +245,7 @@ string buildShipDescription(Cargo &item, string &descriptiontexture);
string buildCargoDescription(const Cargo &item, BaseComputer &computer, float price);
//put in buffer a pretty prepresentation of the POSITIVE float f (ie 4,732.17)
void prettyPrintFloat(char *buffer, float f, int digitsBefore, int digitsAfter, int bufferLen = 128);
string buildUpgradeDescription(Cargo &item);
string buildUpgradeDescription(Cargo &item, std::map<std::string, std::string> ship_map);
int basecargoassets(Unit *base, string cargoname);

//"Basic Repair" item that is added to Buy UPGRADE mode.
Expand Down Expand Up @@ -1922,7 +1922,7 @@ void BaseComputer::updateTransactionControlsForSelection(TransactionList *tlist)
}
descString += tempString;
if (item.GetDescription() == "" || item.GetDescription()[0] != '#') {
item.SetDescription(buildUpgradeDescription(item));
item.SetDescription(buildUpgradeDescription(item, std::map<std::string, std::string>()));
}
break;
case BUY_SHIP:
Expand Down Expand Up @@ -1989,19 +1989,20 @@ void BaseComputer::updateTransactionControlsForSelection(TransactionList *tlist)

//********************************************************************************************
{
double percent_working = m_player.GetUnit() ? UnitUtil::PercentOperational(
m_player.GetUnit(), item.GetName(), item.GetCategory(), false) : 0.0;
double percent_working = UnitUtil::PercentOperational(
m_player.GetUnit(), item.GetName(), item.GetCategory(), false);
if (percent_working < 1) {
//IF DAMAGED
tempString = (boost::format("Damaged and Used value: #b#%1$.2f#-b, purchased for %2$.2f#n1.5#")
% SellPrice(percent_working, baseUnit->PriceCargo(item.GetName()))
% item.GetPrice())
.str();
descString += tempString;

double repair_price = RepairPrice(percent_working, baseUnit->PriceCargo(item.GetName()));

tempString = (boost::format("Percent Working: #b#%1$.2f#-b, Repair Cost: %2$.2f#n1.5#")
% (percent_working * 100)
% RepairPrice(percent_working, baseUnit->PriceCargo(item.GetName())))
% repair_price)
.str();
descString += tempString;
} else {
Expand All @@ -2017,7 +2018,8 @@ void BaseComputer::updateTransactionControlsForSelection(TransactionList *tlist)
}
//********************************************************************************************
if (item.GetDescription() == "" || item.GetDescription()[0] != '#') {
item.SetDescription(buildUpgradeDescription(item));
std::map<std::string, std::string> ship_map = m_player.GetUnit()->UnitToMap();
item.SetDescription(buildUpgradeDescription(item, ship_map));
}
break;
}
Expand Down Expand Up @@ -3781,6 +3783,7 @@ bool BaseComputer::fixUpgrade(const EventCommandId &command, Control *control) {
Cargo *item = selectedItem();
Unit *playerUnit = m_player.GetUnit();
Unit *baseUnit = m_base.GetUnit();

if (baseUnit && playerUnit && item) {
float *credits = NULL;
Cockpit *cp = _Universe->isPlayerStarship(playerUnit);
Expand Down Expand Up @@ -3940,11 +3943,11 @@ string buildShipDescription(Cargo &item, std::string &texturedescription) {
}

//UNDER CONSTRUCTION
string buildUpgradeDescription(Cargo &item) {
string buildUpgradeDescription(Cargo &item, std::map<std::string, std::string> ship_map) {
const std::string key = item.GetName() + "__upgrades";
PyObject* args = PyTuple_Pack(1, PyUnicode_FromString(key.c_str()));
ship_map["upgrade_key"] = key;
const std::string text = GetString("get_upgrade_info", "upgrade_view",
"upgrade_view.py", args);
"upgrade_view.py", ship_map);
return text;
}

Expand Down
15 changes: 15 additions & 0 deletions engine/src/cmd/carrier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,21 @@ void Carrier::EjectCargo(unsigned int index) {
if (index < numCargo()) {
tmp = &GetCargo(index);
}

// Some sanity checks for tmp
// Can't eject an upgrade, unless ship is destroyed
if(tmp->GetInstalled() && !unit->hull.Destroyed()) {
return;
}

// Can't eject cargo from the hidden hold unless ship is destroyed.
// TODO: implement

// Make sure ejected mass isn't 0. This causes game to mishandle
if(tmp->GetMass() == 0) {
tmp->SetMass(0.01);
}

static float cargotime = XMLSupport::parse_float(vs_config->getVariable("physics", "cargo_live_time", "600"));
if (tmp) {
string tmpcontent = tmp->name;
Expand Down
6 changes: 2 additions & 4 deletions engine/src/cmd/collision.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -120,13 +120,11 @@ void Collision::shouldApplyForceAndDealDamage(Unit *other_unit) {
return;
}

// I've changed the behavior of enhancements for now.
// Instead of upgrading the shields, the simply max them out
// at 150%.
// disabled for now.
// TODO: someone from the "product" team needs to define the
// exact behavior. Preferably after we sort the upgrade
// code.
other_unit->shield->Enhance();


/*double percent;
char tempdata[sizeof(Shield)];
Expand Down
Loading

0 comments on commit ca3df7f

Please sign in to comment.