Skip to content

Commit

Permalink
feat(enhancement): Allow assisting/boarding ships to recharge batteri…
Browse files Browse the repository at this point in the history
  • Loading branch information
tibetiroka authored Jul 6, 2024
1 parent 1d19165 commit 4645181
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 20 deletions.
34 changes: 23 additions & 11 deletions source/AI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -64,10 +64,20 @@ namespace {
return cancelers;
}

bool IsStranded(const Ship &ship)
bool NeedsFuel(const Ship &ship)
{
return ship.GetSystem() && !ship.IsEnteringHyperspace() && !ship.GetSystem()->HasFuelFor(ship)
&& ship.NeedsFuel();
&& ship.NeedsFuel();
}

bool NeedsEnergy(const Ship &ship)
{
return ship.GetSystem() && !ship.IsEnteringHyperspace() && ship.NeedsEnergy();
}

bool IsStranded(const Ship &ship)
{
return NeedsFuel(ship) || NeedsEnergy(ship);
}

bool CanBoard(const Ship &ship, const Ship &target)
Expand Down Expand Up @@ -891,7 +901,7 @@ void AI::Step(Command &activeCommands)
if(shipToAssist->IsDestroyed() || shipToAssist->GetSystem() != it->GetSystem()
|| shipToAssist->IsLanding() || shipToAssist->IsHyperspacing()
|| shipToAssist->GetGovernment()->IsEnemy(gov)
|| (!shipToAssist->IsDisabled() && !shipToAssist->NeedsFuel()))
|| (!shipToAssist->IsDisabled() && !shipToAssist->NeedsFuel() && !shipToAssist->NeedsEnergy()))
{
shipToAssist.reset();
it->SetShipToAssist(nullptr);
Expand Down Expand Up @@ -924,7 +934,7 @@ void AI::Step(Command &activeCommands)

// Stranded ships that have a helper need to stop and be assisted.
bool strandedWithHelper = isStranded &&
(HasHelper(*it, isStranded) || it->GetPersonality().IsDerelict() || it->IsYours());
(HasHelper(*it, NeedsFuel(*it), NeedsEnergy(*it)) || it->GetPersonality().IsDerelict() || it->IsYours());

// Behave in accordance with personality traits.
if(isPresent && personality.IsSwarming() && !strandedWithHelper)
Expand Down Expand Up @@ -1279,7 +1289,9 @@ bool AI::CanPursue(const Ship &ship, const Ship &target) const
// Check if the ship is being helped, and if not, ask for help.
void AI::AskForHelp(Ship &ship, bool &isStranded, const Ship *flagship)
{
if(HasHelper(ship, isStranded))
bool needsFuel = NeedsFuel(ship);
bool needsEnergy = NeedsEnergy(ship);
if(HasHelper(ship, needsFuel, needsEnergy))
isStranded = true;
else if(!Random::Int(30))
{
Expand Down Expand Up @@ -1329,7 +1341,7 @@ void AI::AskForHelp(Ship &ship, bool &isStranded, const Ship *flagship)
}

// Check if this ship is physically able to help.
if(!CanHelp(ship, *helper, isStranded))
if(!CanHelp(ship, *helper, needsFuel, needsEnergy))
continue;

// Prefer fast ships over slow ones.
Expand All @@ -1353,7 +1365,7 @@ void AI::AskForHelp(Ship &ship, bool &isStranded, const Ship *flagship)


// Determine if the selected ship is physically able to render assistance.
bool AI::CanHelp(const Ship &ship, const Ship &helper, const bool needsFuel) const
bool AI::CanHelp(const Ship &ship, const Ship &helper, const bool needsFuel, const bool needsEnergy) const
{
// A ship being assisted cannot assist.
if(helperList.find(&helper) != helperList.end())
Expand All @@ -1370,22 +1382,22 @@ bool AI::CanHelp(const Ship &ship, const Ship &helper, const bool needsFuel) con
|| (ship.IsDisabled() && helper.GetGovernment() != ship.GetGovernment()))
return false;

// If the helper has insufficient fuel, it cannot help this ship unless this ship is also disabled.
if(!ship.IsDisabled() && needsFuel && !helper.CanRefuel(ship))
// If the helper has insufficient fuel or energy, it cannot help this ship unless this ship is also disabled.
if(!ship.IsDisabled() && ((needsFuel && !helper.CanRefuel(ship)) || (needsEnergy && !helper.CanGiveEnergy(ship))))
return false;

return true;
}



bool AI::HasHelper(const Ship &ship, const bool needsFuel)
bool AI::HasHelper(const Ship &ship, const bool needsFuel, const bool needsEnergy)
{
// Do we have an existing ship that was asked to assist?
if(helperList.find(&ship) != helperList.end())
{
shared_ptr<Ship> helper = helperList[&ship].lock();
if(helper && helper->GetShipToAssist().get() == &ship && CanHelp(ship, *helper, needsFuel))
if(helper && helper->GetShipToAssist().get() == &ship && CanHelp(ship, *helper, needsFuel, needsEnergy))
return true;
else
helperList.erase(&ship);
Expand Down
4 changes: 2 additions & 2 deletions source/AI.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ template <class Type>
bool CanPursue(const Ship &ship, const Ship &target) const;
// Disabled or stranded ships coordinate with other ships to get assistance.
void AskForHelp(Ship &ship, bool &isStranded, const Ship *flagship);
bool CanHelp(const Ship &ship, const Ship &helper, const bool needsFuel) const;
bool HasHelper(const Ship &ship, const bool needsFuel);
bool CanHelp(const Ship &ship, const Ship &helper, const bool needsFuel, const bool needsEnergy) const;
bool HasHelper(const Ship &ship, const bool needsFuel, const bool needsEnergy);
// Pick a new target for the given ship.
std::shared_ptr<Ship> FindTarget(const Ship &ship) const;
std::shared_ptr<Ship> FindNonHostileTarget(const Ship &ship) const;
Expand Down
31 changes: 25 additions & 6 deletions source/HailPanel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,12 +81,17 @@ HailPanel::HailPanel(PlayerInfo &player, const shared_ptr<Ship> &ship, function<
{
// Is the player in any need of assistance?
const Ship *flagship = player.Flagship();
// Check if the player is out of fuel.
// Check if the player is out of fuel or energy.
if(flagship->NeedsFuel(false))
{
playerNeedsHelp = true;
canGiveFuel = ship->CanRefuel(*flagship) && canAssistPlayer;
}
if(flagship->NeedsEnergy())
{
playerNeedsHelp = true;
canGiveEnergy = ship->CanGiveEnergy(*flagship) && canAssistPlayer;
}
// Check if the player is disabled.
if(flagship->IsDisabled())
{
Expand All @@ -112,6 +117,8 @@ HailPanel::HailPanel(PlayerInfo &player, const shared_ptr<Ship> &ship, function<
helpOffer += "give you some fuel?";
else if(canRepair)
helpOffer += "patch you up?";
else if(canGiveEnergy)
helpOffer += "recharge you?";
SetMessage(helpOffer);
}
else if(playerNeedsHelp && !canAssistPlayer)
Expand Down Expand Up @@ -320,15 +327,27 @@ bool HailPanel::KeyDown(SDL_Keycode key, Uint16 mod, const Command &command, boo
{
if(ship->GetPersonality().IsSurveillance())
SetMessage("Sorry, I'm too busy to help you right now.");
else if(canGiveFuel || canRepair)
else if(canGiveFuel || canRepair || canGiveEnergy)
{
ship->SetShipToAssist(player.FlagshipPtr());
SetMessage("Hang on, we'll be there in a minute.");
}
else if(ship->Fuel())
SetMessage("Sorry, but if we give you fuel we won't have enough to make it to the next system.");
else
SetMessage("Sorry, we don't have any fuel.");
else if(player.Flagship()->NeedsFuel(false))
{
if(ship->Fuel())
SetMessage("Sorry, but if we give you fuel we won't have enough to make it to the next system.");
else
SetMessage("Sorry, we don't have any fuel.");
}
else if(player.Flagship()->NeedsEnergy())
{
if(ship->Energy())
SetMessage("Sorry, but if we give you energy we won't have enough for our ship.");
else
SetMessage("Sorry, we don't have any energy.");
}
else // shouldn't happen
SetMessage("Sorry, we are unable to assist you.");
}
else
{
Expand Down
1 change: 1 addition & 0 deletions source/HailPanel.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class HailPanel : public Panel {
bool playerNeedsHelp = false;
bool canAssistPlayer = true;
bool canGiveFuel = false;
bool canGiveEnergy = false;
bool canRepair = false;
bool hasLanguage = true;
bool requestedToBribeShip = false;
Expand Down
40 changes: 39 additions & 1 deletion source/Ship.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1790,6 +1790,13 @@ shared_ptr<Ship> Ship::Board(bool autoPlunder, bool nonDocking)
helped = true;
TransferFuel(victim->JumpFuelMissing(), victim.get());
}
// Transfer some energy, if needed.
if(victim->Attributes().Get("energy capacity") > 0 && victim->energy < 200.)
{
helped = true;
double toGive = max(attributes.Get("energy capacity") * 0.1, victim->Attributes().Get("energy capacity") * 0.2);
TransferEnergy(max(200., toGive), victim.get());
}
if(helped)
{
pilotError = 120;
Expand All @@ -1801,8 +1808,9 @@ shared_ptr<Ship> Ship::Board(bool autoPlunder, bool nonDocking)
return shared_ptr<Ship>();

// If the boarding ship is the player, they will choose what to plunder.
// Always take fuel if you can.
// Always take fuel and energy if you can.
victim->TransferFuel(victim->fuel, this);
victim->TransferEnergy(victim->energy, this);
if(autoPlunder)
{
// Take any commodities that fit.
Expand Down Expand Up @@ -2551,6 +2559,14 @@ bool Ship::CanRefuel(const Ship &other) const



bool Ship::CanGiveEnergy(const Ship &other) const
{
double toGive = min(other.attributes.Get("energy capacity"), max(200., other.attributes.Get("energy capacity") * 0.2));
return energy >= 2 * toGive;
}



double Ship::TransferFuel(double amount, Ship *to)
{
amount = max(fuel - attributes.Get("fuel capacity"), amount);
Expand All @@ -2565,6 +2581,20 @@ double Ship::TransferFuel(double amount, Ship *to)



double Ship::TransferEnergy(double amount, Ship *to)
{
amount = max(energy - attributes.Get("energy capacity"), amount);
if(to)
{
amount = min(to->attributes.Get("energy capacity") - to->energy, amount);
to->energy += amount;
}
energy -= amount;
return amount;
}



// Convert this ship from one government to another, as a result of boarding
// actions (if the player is capturing) or player death (poor decision-making).
// Returns the number of crew transferred from the capturer.
Expand Down Expand Up @@ -2803,6 +2833,14 @@ bool Ship::NeedsFuel(bool followParent) const



bool Ship::NeedsEnergy() const
{
return attributes.Get("energy capacity") && !energy && !attributes.Get("energy generation")
&& !attributes.Get("fuel energy") && !attributes.Get("solar collection");
}



double Ship::JumpFuelMissing() const
{
// Used for smart refueling: transfer only as much as really needed
Expand Down
6 changes: 6 additions & 0 deletions source/Ship.h
Original file line number Diff line number Diff line change
Expand Up @@ -312,8 +312,12 @@ class Ship : public Body, public std::enable_shared_from_this<Ship> {
void Recharge(int rechargeType = Port::RechargeType::All, bool hireCrew = true);
// Check if this ship is able to give the given ship enough fuel to jump.
bool CanRefuel(const Ship &other) const;
// Check if this ship can transfer sufficient energy to the other ship.
bool CanGiveEnergy(const Ship &other) const;
// Give the other ship enough fuel for it to jump.
double TransferFuel(double amount, Ship *to);
// Give the other ship some energy.
double TransferEnergy(double amount, Ship *to);
// Mark this ship as property of the given ship. Returns the number of crew transferred from the capturer.
int WasCaptured(const std::shared_ptr<Ship> &capturer);
// Clear all orders and targets this ship has (after capture or transfer of control).
Expand Down Expand Up @@ -354,6 +358,8 @@ class Ship : public Body, public std::enable_shared_from_this<Ship> {
// If followParent is false, this ship will not follow the parent.
int JumpsRemaining(bool followParent = true) const;
bool NeedsFuel(bool followParent = true) const;
// Checks whether this ship needs energy to function.
bool NeedsEnergy() const;
// Get the amount of fuel missing for the next jump (smart refueling)
double JumpFuelMissing() const;
// Get the heat level at idle.
Expand Down

0 comments on commit 4645181

Please sign in to comment.