Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow projectiles to not collide with ships or asteroids #9823

Merged
merged 3 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 17 additions & 12 deletions source/Engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2147,12 +2147,15 @@ void Engine::DoCollisions(Projectile &projectile)
// shields the ship (unless the projectile has a blast radius).
vector<Collision> collisions;
const Government *gov = projectile.GetGovernment();
const Weapon &weapon = projectile.GetWeapon();

if(projectile.ShouldExplode())
collisions.emplace_back(nullptr, CollisionType::NONE, 0.);
else if(projectile.GetWeapon().IsPhasing() && projectile.Target())
else if(weapon.IsPhasing() && projectile.Target())
{
// "Phasing" projectiles that have a target will never hit any other ship.
// They also don't care whether the weapon has "no ship collisions" on, as
// otherwise a phasing projectile would never hit anything.
shared_ptr<Ship> target = projectile.TargetPtr();
if(target)
{
Expand All @@ -2165,7 +2168,7 @@ void Engine::DoCollisions(Projectile &projectile)
else
{
// For weapons with a trigger radius, check if any detectable object will set it off.
double triggerRadius = projectile.GetWeapon().TriggerRadius();
double triggerRadius = weapon.TriggerRadius();
if(triggerRadius)
for(const Body *body : shipCollisions.Circle(projectile.Position(), triggerRadius))
if(body == projectile.Target() || (gov->IsEnemy(body->GetGovernment())
Expand All @@ -2178,16 +2181,18 @@ void Engine::DoCollisions(Projectile &projectile)
// If nothing triggered the projectile, check for collisions with ships and asteroids.
if(collisions.empty())
{
const vector<Collision> &newShipHits = shipCollisions.Line(projectile);
collisions.insert(collisions.end(), newShipHits.begin(), newShipHits.end());

// "Phasing" projectiles can pass through asteroids. For all other
// projectiles, check if they've hit an asteroid.
if(!projectile.GetWeapon().IsPhasing())
if(weapon.CanCollideShips())
{
const vector<Collision> &newShipHits = shipCollisions.Line(projectile);
collisions.insert(collisions.end(), newShipHits.begin(), newShipHits.end());
}
if(weapon.CanCollideAsteroids())
{
const vector<Collision> &newAsteroidHits = asteroids.CollideAsteroids(projectile);
collisions.insert(collisions.end(), newAsteroidHits.begin(), newAsteroidHits.end());

}
if(weapon.CanCollideMinables())
{
const vector<Collision> &newMinableHits = asteroids.CollideMinables(projectile);
collisions.insert(collisions.end(), newMinableHits.begin(), newMinableHits.end());
}
Expand All @@ -2197,7 +2202,7 @@ void Engine::DoCollisions(Projectile &projectile)
// Sort the Collisions by increasing range so that the closer collisions are evaluated first.
sort(collisions.begin(), collisions.end());

// Run all collisiions until either the projectile dies or there are no more collisions left.
// Run all collisions until either the projectile dies or there are no more collisions left.
for(Collision &collision : collisions)
{
Body *hit = collision.HitBody();
Expand All @@ -2217,13 +2222,13 @@ void Engine::DoCollisions(Projectile &projectile)
// If this projectile has a blast radius, find all ships within its
// radius. Otherwise, only one is damaged.
// TODO: Also deal blast damage to minables?
double blastRadius = projectile.GetWeapon().BlastRadius();
double blastRadius = weapon.BlastRadius();
if(blastRadius)
{
// Even friendly ships can be hit by the blast, unless it is a
// "safe" weapon.
Point hitPos = projectile.Position() + range * projectile.Velocity();
bool isSafe = projectile.GetWeapon().IsSafe();
bool isSafe = weapon.IsSafe();
for(Body *body : shipCollisions.Circle(hitPos, blastRadius))
{
Ship *ship = reinterpret_cast<Ship *>(body);
Expand Down
12 changes: 12 additions & 0 deletions source/Weapon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,13 @@ void Weapon::LoadWeapon(const DataNode &node)
else if(key == "safe")
isSafe = true;
else if(key == "phasing")
{
isPhasing = true;
// Phasing projectiles implicitly have no asteroid collisions
// for reverse compatibility.
canCollideAsteroids = false;
canCollideMinables = false;
}
else if(key == "no damage scaling")
isDamageScaled = false;
else if(key == "parallel")
Expand All @@ -60,6 +66,12 @@ void Weapon::LoadWeapon(const DataNode &node)
isGravitational = true;
else if(key == "fused")
isFused = true;
else if(key == "no ship collisions")
canCollideShips = false;
else if(key == "no asteroid collisions")
canCollideAsteroids = false;
else if(key == "no minable collisions")
canCollideMinables = false;
else if(child.Size() < 2)
child.PrintTrace("Skipping weapon attribute with no value specified:");
else if(key == "sprite")
Expand Down
10 changes: 10 additions & 0 deletions source/Weapon.h
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,10 @@ class Weapon {
// instead of simply disappearing or only creating a die effect. Blast radius
// weapons will cause a blast at the end of their lifetime.
bool IsFused() const;
// Whether projectiles from this weapon can directly collide with objects.
bool CanCollideShips() const;
bool CanCollideAsteroids() const;
bool CanCollideMinables() const;

// These values include all submunitions:
// Normal damage types:
Expand Down Expand Up @@ -244,6 +248,9 @@ class Weapon {
bool isDamageScaled = true;
bool isGravitational = false;
bool isFused = false;
bool canCollideShips = true;
bool canCollideAsteroids = true;
bool canCollideMinables = true;
// Guns and missiles are by default aimed a converged point at the
// maximum weapons range in front of the ship. When either the installed
// weapon or the gun-port (or both) have the isParallel attribute set
Expand Down Expand Up @@ -426,6 +433,9 @@ inline bool Weapon::IsPhasing() const { return isPhasing; }
inline bool Weapon::IsDamageScaled() const { return isDamageScaled; }
inline bool Weapon::IsGravitational() const { return isGravitational; }
inline bool Weapon::IsFused() const { return isFused; }
inline bool Weapon::CanCollideShips() const { return canCollideShips; }
inline bool Weapon::CanCollideAsteroids() const { return canCollideAsteroids; }
inline bool Weapon::CanCollideMinables() const { return canCollideMinables; }

inline double Weapon::ShieldDamage() const { return TotalDamage(SHIELD_DAMAGE); }
inline double Weapon::HullDamage() const { return TotalDamage(HULL_DAMAGE); }
Expand Down
Loading