void AI::DoScatter(Ship &ship, Command &command, const list<shared_ptr<Ship>> &ships) { if(!command.Has(Command::FORWARD)) return; double turnRate = ship.TurnRate(); double acceleration = ship.Acceleration(); for(const shared_ptr<Ship> &other : ships) { if(other.get() == &ship) continue; // Check for any ships that have nearly the same movement profile as // this ship and are in nearly the same location. Point offset = other->Position() - ship.Position(); if(offset.LengthSquared() > 400.) continue; if(fabs(other->TurnRate() / turnRate - 1.) > .05) continue; if(fabs(other->Acceleration() / acceleration - 1.) > .05) continue; // Move away from this ship. What side of me is it on? command.SetTurn(offset.Cross(ship.Facing().Unit()) > 0. ? 1. : -1.); return; } }
void AI::PrepareForHyperspace(Ship &ship, Command &command) { int type = ship.HyperspaceType(); if(!type) return; Point direction = ship.GetTargetSystem()->Position() - ship.GetSystem()->Position(); if(type == 150) { direction = direction.Unit(); Point normal(-direction.Y(), direction.X()); double deviation = ship.Velocity().Dot(normal); if(fabs(deviation) > ship.Attributes().Get("scram drive")) { // Need to maneuver; not ready to jump if((ship.Facing().Unit().Dot(normal) < 0) == (deviation < 0)) // Thrusting from this angle is counterproductive direction = -deviation * normal; else { command |= Command::FORWARD; // How much correction will be applied to deviation by thrusting // as I turn back toward the jump direction. double turnRateRadians = ship.TurnRate() * TO_RAD; double cos = ship.Facing().Unit().Dot(direction); // integral(t*sin(r*x), angle/r, 0) = t/r * (1 - cos(angle)), so: double correctionWhileTurning = fabs(1 - cos) * ship.Acceleration() / turnRateRadians; // (Note that this will always underestimate because thrust happens before turn) if(fabs(deviation) - correctionWhileTurning > ship.Attributes().Get("scram drive")) // Want to thrust from an even sharper angle direction = -deviation * normal; } } command.SetTurn(TurnToward(ship, direction)); } // If we are moving too fast, point in the right direction. else if(Stop(ship, command, ship.Attributes().Get("jump speed"))) { if(type != 200) command.SetTurn(TurnToward(ship, direction)); } }
Point AI::StoppingPoint(const Ship &ship) { const Point &position = ship.Position(); const Point &velocity = ship.Velocity(); const Angle &angle = ship.Facing(); double acceleration = ship.Acceleration(); double turnRate = ship.TurnRate(); // If I were to turn around and stop now, where would that put me? double v = velocity.Length(); if(!v) return position; // This assumes you're facing exactly the wrong way. double degreesToTurn = TO_DEG * acos(-velocity.Unit().Dot(angle.Unit())); double stopDistance = v * (degreesToTurn / turnRate); // Sum of: v + (v - a) + (v - 2a) + ... + 0. // The number of terms will be v / a. // The average term's value will be v / 2. So: stopDistance += .5 * v * v / acceleration; return position + stopDistance * velocity.Unit(); }