double AsteroidField::Asteroid::Collide(const Projectile &projectile, int step) const { Point pos = location - projectile.Position(); pos = Point(-remainder(pos.X(), WRAP), -remainder(pos.Y(), WRAP)); return animation.GetMask(step).Collide(pos, projectile.Velocity(), angle); }
// Fire an anti-missile. Returns true if the missile should be killed. bool Armament::Weapon::FireAntiMissile(Ship &ship, const Projectile &projectile, list<Effect> &effects) { int strength = outfit->AntiMissile(); if(!strength) return false; double range = outfit->Velocity(); // Check if the missile is in range. Point start = ship.Position() + ship.Facing().Rotate(point); Point offset = projectile.Position() - start; if(offset.Length() > range) return false; // Firing effects are displayed at the anti-missile that just fired. Angle aim = TO_DEG * atan2(offset.X(), -offset.Y()); for(const auto &eit : outfit->FireEffects()) for(int i = 0; i < eit.second; ++i) { effects.push_back(*eit.first); effects.back().Place(start, ship.Velocity(), aim); } // Figure out where the effect should be placed. Anti-missiles do not create // projectiles; they just create a blast animation. start += (.5 * range) * offset.Unit(); for(const auto &eit : outfit->HitEffects()) for(int i = 0; i < eit.second; ++i) { effects.push_back(*eit.first); effects.back().Place(start, ship.Velocity(), aim); } // Die effects are displayed at the projectile, whether or not it actually "dies." for(const auto &eit : outfit->DieEffects()) for(int i = 0; i < eit.second; ++i) { effects.push_back(*eit.first); effects.back().Place(projectile.Position(), projectile.Velocity(), aim); } Fire(ship); return (Random::Int(strength) > Random::Int(projectile.MissileStrength())); }