Skip to content

Commit

Permalink
feat(mechanics): Disabled fighters and drones will no longer be hit b…
Browse files Browse the repository at this point in the history
…y stray projectiles (endless-sky#9760)

This greatly increases their odds of survival after being disabled.
Explosions will still damage them.
  • Loading branch information
tibetiroka authored Mar 18, 2024
1 parent fcd54da commit 93c36ce
Show file tree
Hide file tree
Showing 6 changed files with 33 additions and 57 deletions.
3 changes: 2 additions & 1 deletion source/AI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -675,7 +675,8 @@ void AI::Step(Command &activeCommands)
// Each ship only switches targets twice a second, so that it can
// focus on damaging one particular ship.
targetTurn = (targetTurn + 1) & 31;
if(targetTurn == step || !target || target->IsDestroyed() || (target->IsDisabled() && personality.Disables())
if(targetTurn == step || !target || target->IsDestroyed() || (target->IsDisabled() &&
(personality.Disables() || (target->CanBeCarried() && !personality.IsVindictive())))
|| (target->IsFleeing() && personality.IsMerciful()) || !target->IsTargetable())
{
target = FindTarget(*it);
Expand Down
58 changes: 11 additions & 47 deletions source/CollisionSet.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,34 +39,6 @@ namespace {
constexpr int USED_MAX_VELOCITY = MAX_VELOCITY - 1;
// Warn the user only once about too-large projectile velocities.
bool warned = false;


// Keep track of the closest collision found so far. If an external "closest
// hit" value was given, there is no need to check collisions farther out
// than that.
class Closest {
public:
explicit Closest(double closestHit)
: closest_dist(closestHit)
, closest_body(nullptr)
{}

void TryNearer(double new_closest, Body *new_body)
{
if(new_closest >= closest_dist)
return;

closest_dist = new_closest;
closest_body = new_body;
}

double GetClosestDistance() const { return closest_dist; }
Body *GetClosestBody() const { return closest_body; }

private:
double closest_dist;
Body *closest_body;
};
}


Expand Down Expand Up @@ -166,9 +138,8 @@ void CollisionSet::Finish()



// Get all collisions for the given projectile. Collisions are not necessarily
// sorted by distance. If the projectile is incapable if impacting multiple ships
// in the same frame then only the closest collision is returned.
// Get all possible collisions for the given projectile. Collisions are not necessarily
// sorted by distance.
const vector<Collision> &CollisionSet::Line(const Projectile &projectile) const
{
// What objects the projectile hits depends on its government.
Expand All @@ -177,15 +148,15 @@ const vector<Collision> &CollisionSet::Line(const Projectile &projectile) const
// Convert the projectile to a line represented by its start and end points.
Point from = projectile.Position();
Point to = from + projectile.Velocity();
return Line(from, to, pGov, projectile.Target(), projectile.HitsRemaining() != 1);
return Line(from, to, pGov, projectile.Target());
}



// Get all collisions along a line. Collisions are not necessarily sorted by
// distance. If the all variable is false then only the closest collision is returned.
// Get all possible collisions along a line. Collisions are not necessarily sorted by
// distance.
const vector<Collision> &CollisionSet::Line(const Point &from, const Point &to,
const Government *pGov, const Body *target, bool all) const
const Government *pGov, const Body *target) const
{
const int x = from.X();
const int y = from.Y();
Expand All @@ -198,7 +169,6 @@ const vector<Collision> &CollisionSet::Line(const Point &from, const Point &to,
const int endGX = endX >> SHIFT;
const int endGY = endY >> SHIFT;

Closest closer_result(1.);
lineResult.clear();

// Special case, very common: the projectile is contained in one grid cell.
Expand Down Expand Up @@ -226,13 +196,10 @@ const vector<Collision> &CollisionSet::Line(const Point &from, const Point &to,
Point offset = from - it->body->Position();
const double range = mask.Collide(offset, to - from, it->body->Facing());

closer_result.TryNearer(range, it->body);
if(range < 1. && all)
if(range < 1.)
lineResult.emplace_back(it->body, collisionType, range);
}

if(!all && closer_result.GetClosestDistance() < 1.)
lineResult.emplace_back(closer_result.GetClosestBody(), collisionType, closer_result.GetClosestDistance());
return lineResult;
}

Expand All @@ -247,7 +214,7 @@ const vector<Collision> &CollisionSet::Line(const Point &from, const Point &to,
}
Point newEnd = from + pVelocity.Unit() * USED_MAX_VELOCITY;

return Line(from, newEnd, pGov, target, all);
return Line(from, newEnd, pGov, target);
}

// When stepping from one grid cell to the next, we'll go in this direction.
Expand Down Expand Up @@ -300,13 +267,12 @@ const vector<Collision> &CollisionSet::Line(const Point &from, const Point &to,
Point offset = from - it->body->Position();
const double range = mask.Collide(offset, to - from, it->body->Facing());

closer_result.TryNearer(range, it->body);
if(range < 1. && all)
if(range < 1.)
lineResult.emplace_back(it->body, collisionType, range);
}

// Check if we've found a collision or reached the final grid cell.
if((closer_result.GetClosestBody() && !all) || (gx == endGX && gy == endGY))
// Check if we've reached the final grid cell.
if(gx == endGX && gy == endGY)
break;
// If not, move to the next one. Check whether rx / mx < ry / my.
const int64_t diff = rx * my - ry * mx;
Expand Down Expand Up @@ -342,8 +308,6 @@ const vector<Collision> &CollisionSet::Line(const Point &from, const Point &to,
}
}

if(!all && closer_result.GetClosestBody())
lineResult.emplace_back(closer_result.GetClosestBody(), collisionType, closer_result.GetClosestDistance());
return lineResult;
}

Expand Down
11 changes: 5 additions & 6 deletions source/CollisionSet.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,15 +45,14 @@ class CollisionSet {
// Finish adding objects (and organize them into the final lookup table).
void Finish();

// Get all collisions for the given projectile. Collisions are not necessarily
// sorted by distance. If the projectile is incapable if impacting multiple ships
// in the same frame then only the closest collision is returned.
// Get all possible collisions for the given projectile. Collisions are not necessarily
// sorted by distance.
const std::vector<Collision> &Line(const Projectile &projectile) const;

// Get all collisions along a line. Collisions are not necessarily sorted by
// distance. If the all variable is false then only the closest collision is returned.
// Get all possible collisions along a line. Collisions are not necessarily sorted by
// distance.
const std::vector<Collision> &Line(const Point &from, const Point &to,
const Government *pGov = nullptr, const Body *target = nullptr, bool all = true) const;
const Government *pGov = nullptr, const Body *target = nullptr) const;

// Get all objects within the given range of the given point.
const std::vector<Body *> &Circle(const Point &center, double radius) const;
Expand Down
5 changes: 5 additions & 0 deletions source/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2175,6 +2175,11 @@ void Engine::DoCollisions(Projectile &projectile)
if(hit && collisionType == CollisionType::SHIP)
shipHit = reinterpret_cast<Ship *>(hit)->shared_from_this();

// Don't collide with carried ships that are disabled and not directly targeted.
if(shipHit && hit != projectile.Target()
&& shipHit->CanBeCarried() && shipHit->IsDisabled())
continue;

// Create the explosion the given distance along the projectile's
// motion path for this step.
projectile.Explode(visuals, range, hit ? hit->Velocity() : Point());
Expand Down
12 changes: 9 additions & 3 deletions source/Projectile.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,10 @@ Projectile::Projectile(const Ship &parent, Point position, Angle angle, const We

cachedTarget = TargetPtr().get();
if(cachedTarget)
{
targetGovernment = cachedTarget->GetGovernment();
targetDisabled = cachedTarget->IsDisabled();
}

dV = this->angle.Unit() * (weapon->Velocity() + Random::Real() * weapon->RandomVelocity());
velocity += dV;
Expand All @@ -79,6 +82,7 @@ Projectile::Projectile(const Projectile &parent, const Point &offset, const Angl
{
government = parent.government;
targetGovernment = parent.targetGovernment;
targetDisabled = parent.targetDisabled;
hitsRemaining = weapon->PenetrationCount();

cachedTarget = TargetPtr().get();
Expand Down Expand Up @@ -137,14 +141,15 @@ void Projectile::Move(vector<Visual> &visuals, vector<Projectile> &projectiles)

// If the target has left the system, stop following it. Also stop if the
// target has been captured by a different government.
// Also stop targeting fighters that have become disabled after this projectile was fired.
const Ship *target = cachedTarget;
if(target)
{
target = TargetPtr().get();
if(!target || !target->IsTargetable() || target->GetGovernment() != targetGovernment)
if(!target || !target->IsTargetable() || target->GetGovernment() != targetGovernment ||
(!targetDisabled && target->IsDisabled() && target->CanBeCarried()))
{
targetShip.reset();
cachedTarget = nullptr;
BreakTarget();
target = nullptr;
}
}
Expand Down Expand Up @@ -380,6 +385,7 @@ void Projectile::BreakTarget()
targetShip.reset();
cachedTarget = nullptr;
targetGovernment = nullptr;
targetDisabled = false;
}


Expand Down
1 change: 1 addition & 0 deletions source/Projectile.h
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ class Projectile : public Body {

std::weak_ptr<Ship> targetShip;
const Ship *cachedTarget = nullptr;
bool targetDisabled = false;
const Government *targetGovernment = nullptr;

// The change in velocity of all stages of this projectile
Expand Down

0 comments on commit 93c36ce

Please sign in to comment.