/* called by Area(const Polygon&) */ double calc(const Point &rhs1, const Point &rhs2){ vector<Point> p; bool in1 = (cmp(rhs1.Abs()-R) < 0); bool in2 = (cmp(rhs2.Abs()-R) < 0); if(in1){ if(in2) return fabs(rhs1.Cross(rhs2)) / 2.0; else{ p = Intersection(Line(rhs1, rhs2)); return SectorArea(rhs2, p[0]) + fabs(rhs1.Cross(p[0])) / 2.0; } }else{ if(in2){ p = Intersection(Line(rhs1, rhs2)); return SectorArea(p[0], rhs1) + fabs(rhs2.Cross(p[0])) / 2.0; }else{ p = Intersection(Line(rhs1, rhs2)); if((int)p.size() == 2){ return SectorArea(rhs1, p[0]) + SectorArea(p[1], rhs2) + fabs(p[0].Cross(p[1])) / 2.0; }else{ return SectorArea(rhs1, rhs2); } } } }
double Mask::Intersection(Point sA, Point vA) const { // Keep track of the closest intersection point found. double closest = 1.; Point prev = outline.back(); for(const Point &next : outline) { // Check if there is an intersection. (If not, the cross would be 0.) If // there is, handle it only if it is a point where the segment is // entering the polygon rather than exiting it (i.e. cross > 0). Point vB = next - prev; double cross = vB.Cross(vA); if(cross > 0.) { Point vS = prev - sA; double uB = vA.Cross(vS); double uA = vB.Cross(vS); // If the intersection occurs somewhere within this segment of the // outline, find out how far along the query vector it occurs and // remember it if it is the closest so far. if((uB >= 0.) & (uB < cross) & (uA >= 0.)) closest = min(closest, uA / cross); } prev = next; } return closest; }
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; } }
// Check if this ship is currently able to enter hyperspace to it target. int Ship::CheckHyperspace() const { if(commands.Has(Command::WAIT)) return 0; // Find out where we're going and how we're getting there, const System *destination = GetTargetSystem(); int type = HyperspaceType(); // You can't jump to a system with no link to it. if(!type) return 0; if(fuel < type) return 0; Point direction = destination->Position() - currentSystem->Position(); // The ship can only enter hyperspace if it is traveling slowly enough // and pointed in the right direction. if(type == 150) { double deviation = fabs(direction.Unit().Cross(velocity)); if(deviation > attributes.Get("scram drive")) return 0; } else if(velocity.Length() > attributes.Get("jump speed")) return 0; if(type != 200) { // Figure out if we're within one turn step of facing this system. bool left = direction.Cross(angle.Unit()) < 0.; Angle turned = angle + TurnRate() * (left - !left); bool stillLeft = direction.Cross(turned.Unit()) < 0.; if(left == stillLeft) return 0; } return type; }
double AI::TurnToward(const Ship &ship, const Point &vector) { static const double RAD_TO_DEG = 180. / 3.14159265358979; Point facing = ship.Facing().Unit(); double cross = vector.Cross(facing); if(vector.Dot(facing) > 0.) { double angle = asin(cross / vector.Length()) * RAD_TO_DEG; if(fabs(angle) <= ship.TurnRate()) return -angle / ship.TurnRate(); } bool left = cross < 0.; return left - !left; }
DrawList::Item::Item(const Animation &animation, Point pos, Point unit, Point blur, float clip, int step) : position{static_cast<float>(pos.X()), static_cast<float>(pos.Y())}, clip(clip), flags(animation.GetSwizzle()) { Animation::Frame frame = animation.Get(step); tex0 = frame.first; tex1 = frame.second; flags |= static_cast<uint32_t>(frame.fade * 256.f) << 8; double width = animation.Width(); double height = animation.Height(); Point uw = unit * width; Point uh = unit * height; if(clip < 1.) { // "clip" is the fraction of its height that we're clipping the sprite // to. We still want it to start at the same spot, though. pos -= uh * ((1. - clip) * .5); position[0] = static_cast<float>(pos.X()); position[1] = static_cast<float>(pos.Y()); uh *= clip; } // (0, -1) means a zero-degree rotation (since negative Y is up). transform[0] = -uw.Y(); transform[1] = uw.X(); transform[2] = -uh.X(); transform[3] = -uh.Y(); // Calculate the blur vector, in texture coordinates. This should be done by // projecting the blur vector onto the unit vector and then scaling it based // on the sprite size. But, the unit vector first has to be normalized (i.e. // divided by the unit vector length), and the sprite size also has to be // multiplied by the unit vector size, so: double zoomCorrection = 4. * unit.LengthSquared(); this->blur[0] = unit.Cross(blur) / (width * zoomCorrection); this->blur[1] = -unit.Dot(blur) / (height * zoomCorrection); }
DrawList::Item::Item(const Body &body, Point pos, Point blur, float cloak, float clip, int swizzle, int step) : position{static_cast<float>(pos.X()), static_cast<float>(pos.Y())}, clip(clip), flags(swizzle) { Body::Frame frame = body.GetFrame(step); tex0 = frame.first; tex1 = frame.second; flags |= static_cast<uint32_t>(frame.fade * 256.f) << 8; double width = body.Width(); double height = body.Height(); Point unit = body.Facing().Unit(); Point uw = unit * width; Point uh = unit * height; if(clip < 1.) { // "clip" is the fraction of its height that we're clipping the sprite // to. We still want it to start at the same spot, though. pos -= uh * ((1. - clip) * .5); position[0] = static_cast<float>(pos.X()); position[1] = static_cast<float>(pos.Y()); uh *= clip; } // (0, -1) means a zero-degree rotation (since negative Y is up). transform[0] = -uw.Y(); transform[1] = uw.X(); transform[2] = -uh.X(); transform[3] = -uh.Y(); // Calculate the blur vector, in texture coordinates. this->blur[0] = unit.Cross(blur) / (width * 4.); this->blur[1] = -unit.Dot(blur) / (height * 4.); if(cloak > 0.) Cloak(cloak); }
ll Area(const Point &a, const Point &b, const Point &c){ return abs(a.Cross(b) + b.Cross(c) + c.Cross(a)); }
// Only override the ones you need; the default action is to return false. bool MapDetailPanel::KeyDown(SDL_Keycode key, Uint16 mod, const Command &command) { if(command.Has(Command::MAP) || key == 'd' || key == SDLK_ESCAPE || (key == 'w' && (mod & (KMOD_CTRL | KMOD_GUI)))) GetUI()->Pop(this); else if(key == SDLK_PAGEUP || key == SDLK_PAGEDOWN || key == 'i') { GetUI()->Pop(this); GetUI()->Push(new MissionPanel(*this)); } else if(key == 'o') { GetUI()->Pop(this); GetUI()->Push(new MapOutfitterPanel(*this)); } else if(key == 's') { GetUI()->Pop(this); GetUI()->Push(new MapShipyardPanel(*this)); } else if((key == SDLK_TAB || command.Has(Command::JUMP)) && player.Flagship()) { // Toggle to the next link connected to the "source" system. If the // shift key is down, the source is the end of the travel plan; otherwise // it is one step before the end. vector<const System *> &plan = player.TravelPlan(); const System *source = plan.empty() ? player.GetSystem() : plan.front(); const System *next = nullptr; Point previousUnit = Point(0., -1.); if(!plan.empty() && !(mod & KMOD_SHIFT)) { previousUnit = plan.front()->Position(); plan.erase(plan.begin()); next = source; source = plan.empty() ? player.GetSystem() : plan.front(); previousUnit = (previousUnit - source->Position()).Unit(); } Point here = source->Position(); // Depending on whether the flagship has a jump drive, the possible links // we can travel along are different: bool hasJumpDrive = player.Flagship()->Attributes().Get("jump drive"); const vector<const System *> &links = hasJumpDrive ? source->Neighbors() : source->Links(); double bestAngle = 2. * PI; for(const System *it : links) { if(!player.HasSeen(it)) continue; if(!(hasJumpDrive || player.HasVisited(it) || player.HasVisited(source))) continue; Point unit = (it->Position() - here).Unit(); double angle = acos(unit.Dot(previousUnit)); if(unit.Cross(previousUnit) >= 0.) angle = 2. * PI - angle; if(angle <= bestAngle) { next = it; bestAngle = angle; } } if(next) { plan.insert(plan.begin(), next); Select(next); } } else if((key == SDLK_DELETE || key == SDLK_BACKSPACE) && player.HasTravelPlan()) { vector<const System *> &plan = player.TravelPlan(); plan.erase(plan.begin()); Select(plan.empty() ? player.GetSystem() : plan.front()); } else if(key == SDLK_DOWN) { if(commodity < 0 || commodity == 9) commodity = 0; else ++commodity; } else if(key == SDLK_UP) { if(commodity <= 0) commodity = 9; else --commodity; } else if(key == 'f') GetUI()->Push(new Dialog( this, &MapDetailPanel::DoFind, "Search for:")); else if(key == '+' || key == '=') ZoomMap(); else if(key == '-') UnzoomMap(); else return false; return true; }