Example #1
0
// temporary one-point version
static void CollideWithTerrain(Body *body)
{
    if (!body->IsType(Object::DYNAMICBODY)) return;
    DynamicBody *dynBody = static_cast<DynamicBody*>(body);
    if (!dynBody->IsMoving()) return;

    Frame *f = body->GetFrame();
    if (!f || !f->GetBody() || f != f->GetBody()->GetFrame()) return;
    if (!f->GetBody()->IsType(Object::TERRAINBODY)) return;
    TerrainBody *terrain = static_cast<TerrainBody*>(f->GetBody());

    const Aabb &aabb = dynBody->GetAabb();
    double altitude = body->GetPosition().Length() + aabb.min.y;
    if (altitude >= terrain->GetMaxFeatureRadius()) return;

    double terrHeight = terrain->GetTerrainHeight(body->GetPosition().Normalized());
    if (altitude >= terrHeight) return;

    CollisionContact c;
    c.pos = body->GetPosition();
    c.normal = c.pos.Normalized();
    c.depth = terrHeight - altitude;
    c.userData1 = static_cast<void*>(body);
    c.userData2 = static_cast<void*>(f->GetBody());
    hitCallback(&c);
}
Example #2
0
// ok, need thing to step down through bodies and find closest approach
// modify targpos directly to aim short of dangerous bodies
static bool ParentSafetyAdjust(Ship *ship, Frame *targframe, vector3d &targpos, vector3d &targvel)
{
	Body *body = 0;
	Frame *frame = targframe->GetNonRotFrame();
	while (frame)
	{
		if (ship->GetFrame()->GetNonRotFrame() == frame) break;		// ship in frame, stop
		if (frame->GetBody()) body = frame->GetBody();			// ignore grav points?

		double sdist = ship->GetPositionRelTo(frame).Length();
		if (sdist < frame->GetRadius()) break;					// ship inside frame, stop

		frame = frame->GetParent()->GetNonRotFrame();			// check next frame down
	}
	if (!body) return false;

	// aim for zero velocity at surface of that body
	// still along path to target

	vector3d targpos2 = targpos - ship->GetPosition();
	double targdist = targpos2.Length();
	double bodydist = body->GetPositionRelTo(ship).Length() - MaxEffectRad(body, ship)*1.5;
	if (targdist < bodydist) return false;
	targpos -= (targdist - bodydist) * targpos2 / targdist;
	targvel = body->GetVelocityRelTo(ship->GetFrame());
	return true;
}
Example #3
0
/*
 * Method: GetGroundPosition
 *
 * Get latitude, longitude and altitude of a dynamic body close to the ground or nil the body is not a dynamic body
 * or is not close to the ground.
 *
 * > latitude, longitude, altitude = body:GetGroundPosition()
 *
 * Returns:
 *
 *   latitude - the latitude of the body in radians
 *   longitude - the longitude of the body in radians
 *   altitude - altitude above the ground in meters
 *
 * Examples:
 *
 * > -- Get ground position of the player
 * > local lat, long, alt = Game.player:GetGroundPosition()
 * > lat = math.rad2deg(lat)
 * > long = math.rad2deg(long)
 *
 * Availability:
 *
 *   July 2013
 *
 * Status:
 *
 *   experimental
 */
static int l_body_get_ground_position(lua_State *l)
{
	Body *b = LuaObject<Body>::CheckFromLua(1);
	if (!b->IsType(Object::DYNAMICBODY)) {
		lua_pushnil(l);
		return 1;
	}

	Frame *f = b->GetFrame();
	if (!f->IsRotFrame())
		return 0;

	vector3d pos = b->GetPosition();
	double latitude = atan2(pos.y, sqrt(pos.x * pos.x + pos.z * pos.z));
	double longitude = atan2(pos.x, pos.z);
	lua_pushnumber(l, latitude);
	lua_pushnumber(l, longitude);
	Body *astro = f->GetBody();
	if (astro->IsType(Object::TERRAINBODY)) {
		double radius = static_cast<TerrainBody *>(astro)->GetTerrainHeight(pos.Normalized());
		double altitude = pos.Length() - radius;
		lua_pushnumber(l, altitude);
	} else {
		lua_pushnil(l);
	}
	return 3;
}
Example #4
0
/*
 * Attribute: frameBody
 *
 * The non-dynamic body attached to the frame this dynamic body is in.
 *
 * Only valid for dynamic <Bodies>. For non-dynamic bodies <frameBody> will be
 * nil.
 *
 * <frameBody> can also be nil if this dynamic body is in a frame with no
 * non-dynamic body. This most commonly occurs when the player is in
 * hyperspace.
 *
 * Availability:
 *
 *   alpha 12
 *
 * Status:
 *
 *   experimental
 */
static int l_body_attr_frame_body(lua_State *l)
{
	Body *b = LuaObject<Body>::CheckFromLua(1);
	if (!b->IsType(Object::DYNAMICBODY)) {
		lua_pushnil(l);
		return 1;
	}

	Frame *f = b->GetFrame();
	LuaObject<Body>::PushToLua(f->GetBody());
	return 1;
}
// Creates a child AI command to fly the ship to nearest transit location if it wasn't within transit location
// Returns false if ship is already in transit location, true if it wasn't and a new AI command is created to go there
bool AIParagonCmdFlyTo::GoToTransitDistance()
{
	m_remainingDistance = m_data.ship_to_target_distance;
	// is target far enough for transit and transit is not possible right now?
	if (m_remainingDistance > VICINITY_DISTANCE && !m_ship->IsTransitPossible()) {
		Frame* sframe = m_ship->GetFrame();
		Body* sbody = sframe->GetBody();
		assert(sframe && sbody);
		double transit_radius = GetTransitRadius(sbody);
		// if transit is not possible (IsTransitPossible) then ship is within planet or spacestation so no need to check for that
		vector3d transit_position = (m_ship->GetPosition() - sbody->GetPosition()).Normalized() * transit_radius;
		m_child = new AIParagonCmdGoTo(m_ship, sframe, transit_position);
		return true;
	} else {
		return false;
	}
}
Example #6
0
static Frame *MakeFrameFor(SystemBody *sbody, Body *b, Frame *f)
{
    if (!sbody->parent) {
        if (b) b->SetFrame(f);
        f->SetBodies(sbody, b);
        return f;
    }

    if (sbody->type == SystemBody::TYPE_GRAVPOINT) {
        Frame *orbFrame = new Frame(f, sbody->name.c_str());
        orbFrame->SetBodies(sbody, b);
        orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1);
        return orbFrame;
    }

    SystemBody::BodySuperType supertype = sbody->GetSuperType();

    if ((supertype == SystemBody::SUPERTYPE_GAS_GIANT) ||
            (supertype == SystemBody::SUPERTYPE_ROCKY_PLANET)) {
        // for planets we want an non-rotating frame for a few radii
        // and a rotating frame with no radius to contain attached objects
        double frameRadius = std::max(4.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.05);
        Frame *orbFrame = new Frame(f, sbody->name.c_str(), Frame::FLAG_HAS_ROT);
        orbFrame->SetBodies(sbody, b);
        orbFrame->SetRadius(frameRadius);
        //printf("\t\t\t%s has frame size %.0fkm, body radius %.0fkm\n", sbody->name.c_str(),
        //	(frameRadius ? frameRadius : 10*sbody->GetRadius())*0.001f,
        //	sbody->GetRadius()*0.001f);

        assert(sbody->rotationPeriod != 0);
        Frame *rotFrame = new Frame(orbFrame, sbody->name.c_str(), Frame::FLAG_ROTATING);
        rotFrame->SetBodies(sbody, b);

        // rotating frame has atmosphere radius or feature height, whichever is larger
        rotFrame->SetRadius(b->GetPhysRadius());

        matrix3x3d rotMatrix = matrix3x3d::RotateX(sbody->axialTilt.ToDouble());
        double angSpeed = 2.0*M_PI/sbody->GetRotationPeriod();
        rotFrame->SetAngSpeed(angSpeed);

        if (sbody->rotationalPhaseAtStart != fixed(0))
            rotMatrix = rotMatrix * matrix3x3d::RotateY(sbody->rotationalPhaseAtStart.ToDouble());
        rotFrame->SetOrient(rotMatrix);

        b->SetFrame(rotFrame);
        return orbFrame;
    }
    else if (supertype == SystemBody::SUPERTYPE_STAR) {
        // stars want a single small non-rotating frame
        // bigger than it's furtherest orbiting body.
        // if there are no orbiting bodies use a frame of several radii.
        Frame *orbFrame = new Frame(f, sbody->name.c_str());
        orbFrame->SetBodies(sbody, b);
        orbFrame->SetRadius(std::max(10.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.1));
        b->SetFrame(orbFrame);
        return orbFrame;
    }
    else if (sbody->type == SystemBody::TYPE_STARPORT_ORBITAL) {
        // space stations want non-rotating frame to some distance
        // and a zero-size rotating frame
        Frame *orbFrame = new Frame(f, sbody->name.c_str(), Frame::FLAG_HAS_ROT);
        orbFrame->SetBodies(sbody, b);
//		orbFrame->SetRadius(10*sbody->GetRadius());
        orbFrame->SetRadius(20000.0);				// 4x standard parking radius
        b->SetFrame(orbFrame);
        return orbFrame;

//		assert(sbody->rotationPeriod != 0);
//		rotFrame = new Frame(orbFrame, sbody->name.c_str(), Frame::FLAG_ROTATING);
//		rotFrame->SetBodies(sbody, b);
//		rotFrame->SetRadius(0.0);
//		rotFrame->SetAngVelocity(vector3d(0.0,double(static_cast<SpaceStation*>(b)->GetDesiredAngVel()),0.0));
//		b->SetFrame(rotFrame);

    } else if (sbody->type == SystemBody::TYPE_STARPORT_SURFACE) {
        // just put body into rotating frame of planet, not in its own frame
        // (because collisions only happen between objects in same frame,
        // and we want collisions on starport and on planet itself)
        Frame *rotFrame = f->GetRotFrame();
        b->SetFrame(rotFrame);
        assert(rotFrame->IsRotFrame());
        assert(rotFrame->GetBody()->IsType(Object::PLANET));
        matrix3x3d rot;
        vector3d pos;
        Planet *planet = static_cast<Planet*>(rotFrame->GetBody());
        RelocateStarportIfUnderwaterOrBuried(sbody, rotFrame, planet, pos, rot);
        sbody->orbit.rotMatrix = rot;
        b->SetPosition(pos * planet->GetTerrainHeight(pos));
        b->SetOrient(rot);
        return rotFrame;
    } else {
        assert(0);
    }
    return NULL;
}
Example #7
0
static Frame *MakeFrameFor(double at_time, SystemBody *sbody, Body *b, Frame *f)
{
	if (!sbody->GetParent()) {
		if (b) b->SetFrame(f);
		f->SetBodies(sbody, b);
		return f;
	}

	if (sbody->GetType() == SystemBody::TYPE_GRAVPOINT) {
		Frame *orbFrame = new Frame(f, sbody->GetName().c_str());
		orbFrame->SetBodies(sbody, b);
		orbFrame->SetRadius(sbody->GetMaxChildOrbitalDistance()*1.1);
		return orbFrame;
	}

	SystemBody::BodySuperType supertype = sbody->GetSuperType();

	if ((supertype == SystemBody::SUPERTYPE_GAS_GIANT) ||
	    (supertype == SystemBody::SUPERTYPE_ROCKY_PLANET)) {
		// for planets we want an non-rotating frame for a few radii
		// and a rotating frame with no radius to contain attached objects
		double frameRadius = std::max(4.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.05);
		Frame *orbFrame = new Frame(f, sbody->GetName().c_str(), Frame::FLAG_HAS_ROT);
		orbFrame->SetBodies(sbody, b);
		orbFrame->SetRadius(frameRadius);
		//Output("\t\t\t%s has frame size %.0fkm, body radius %.0fkm\n", sbody->name.c_str(),
		//	(frameRadius ? frameRadius : 10*sbody->GetRadius())*0.001f,
		//	sbody->GetRadius()*0.001f);

		assert(sbody->IsRotating() != 0);
		Frame *rotFrame = new Frame(orbFrame, sbody->GetName().c_str(), Frame::FLAG_ROTATING);
		rotFrame->SetBodies(sbody, b);

		// rotating frame has atmosphere radius or feature height, whichever is larger
		rotFrame->SetRadius(b->GetPhysRadius());

		matrix3x3d rotMatrix = matrix3x3d::RotateX(sbody->GetAxialTilt());
		double angSpeed = 2.0*M_PI/sbody->GetRotationPeriod();
		rotFrame->SetAngSpeed(angSpeed);

		if (sbody->HasRotationPhase())
			rotMatrix = rotMatrix * matrix3x3d::RotateY(sbody->GetRotationPhaseAtStart());
		rotFrame->SetInitialOrient(rotMatrix, at_time);

		b->SetFrame(rotFrame);
		return orbFrame;
	}
	else if (supertype == SystemBody::SUPERTYPE_STAR) {
		// stars want a single small non-rotating frame
		// bigger than it's furtherest orbiting body.
		// if there are no orbiting bodies use a frame of several radii.
		Frame *orbFrame = new Frame(f, sbody->GetName().c_str());
		orbFrame->SetBodies(sbody, b);
		double frameRadius = std::max(10.0*sbody->GetRadius(), sbody->GetMaxChildOrbitalDistance()*1.1);
		// Respect the frame of other stars in the multi-star system. We still make sure that the frame ends outside
		// the body. For a minimum separation of 1.236 radii, nothing will overlap (see StarSystem::StarSystem()).
		if (sbody->GetParent() && frameRadius > AU * 0.11 * sbody->GetOrbMin())
			frameRadius = std::max(1.1*sbody->GetRadius(), AU * 0.11 * sbody->GetOrbMin());
		orbFrame->SetRadius(frameRadius);
		b->SetFrame(orbFrame);
		return orbFrame;
	}
	else if (sbody->GetType() == SystemBody::TYPE_STARPORT_ORBITAL) {
		// space stations want non-rotating frame to some distance
		Frame *orbFrame = new Frame(f, sbody->GetName().c_str());
		orbFrame->SetBodies(sbody, b);
//		orbFrame->SetRadius(10*sbody->GetRadius());
		orbFrame->SetRadius(20000.0);				// 4x standard parking radius
		b->SetFrame(orbFrame);
		return orbFrame;

	} else if (sbody->GetType() == SystemBody::TYPE_STARPORT_SURFACE) {
		// just put body into rotating frame of planet, not in its own frame
		// (because collisions only happen between objects in same frame,
		// and we want collisions on starport and on planet itself)
		Frame *rotFrame = f->GetRotFrame();
		b->SetFrame(rotFrame);
		assert(rotFrame->IsRotFrame());
		assert(rotFrame->GetBody()->IsType(Object::PLANET));
		matrix3x3d rot;
		vector3d pos;
		Planet *planet = static_cast<Planet*>(rotFrame->GetBody());
		RelocateStarportIfUnderwaterOrBuried(sbody, rotFrame, planet, pos, rot);
		sbody->SetOrbitPlane(rot);
		b->SetPosition(pos * planet->GetTerrainHeight(pos));
		b->SetOrient(rot);
		return rotFrame;
	} else {
		assert(0);
	}
	return 0;
}
Example #8
0
/*
 * Function: SpawnShipLandedNear
 *
 * Create a ship and place it on the surface near the given <Body>.
 *
 * > ship = Space.SpawnShipLandedNear(type, body, min, max)
 *
 * Parameters:
 *
 *   type - the name of the ship
 *
 *   body - the <Body> near which the ship should be spawned. It must be on the ground or close to it,
 *          i.e. it must be in the rotating frame of the planetary body.
 *
 *   min - minimum distance from the surface point below the body to place the ship, in Km
 *
 *   max - maximum distance to place the ship
 *
 * Return:
 *
 *   ship - a <Ship> object for the new ship
 *
 * Example:
 *
 * > -- spawn a ship 10km from the player
 * > local ship = Ship.SpawnShipLandedNear("viper_police", Game.player, 10, 10)
 *
 * Availability:
 *
 *   July 2013
 *
 * Status:
 *
 *   experimental
 */
static int l_space_spawn_ship_landed_near(lua_State *l)
{
    if (!Pi::game)
        luaL_error(l, "Game is not started");

    LUA_DEBUG_START(l);

    const char *type = luaL_checkstring(l, 1);
    if (! ShipType::Get(type))
        luaL_error(l, "Unknown ship type '%s'", type);

    Body *nearbody = LuaObject<Body>::CheckFromLua(2);
    const float min_dist = luaL_checknumber(l, 3);
    const float max_dist = luaL_checknumber(l, 4);
    if (min_dist > max_dist)
        luaL_error(l, "min_dist must not be larger than max_dist");

    Ship *ship = new Ship(type);
    assert(ship);

    // XXX protect against spawning inside the body
    Frame * newframe = nearbody->GetFrame()->GetRotFrame();
    if (!newframe->IsRotFrame())
        luaL_error(l, "Body must be in rotating frame");
    SystemBody *sbody = newframe->GetSystemBody();
    if (sbody->GetSuperType() != SystemBody::SUPERTYPE_ROCKY_PLANET)
        luaL_error(l, "Body is not on a rocky planet");
    if (max_dist > sbody->GetRadius())
        luaL_error(l, "max_dist too large for planet radius");
    // We assume that max_dist is much smaller than the planet radius, i.e. that our area is reasonably flat
    // So, we
    const vector3d up = nearbody->GetPosition().Normalized();
    vector3d x;
    vector3d y;
    // Calculate a orthonormal basis for a horizontal plane. For numerical reasons we do that determining the smallest
    // coordinate and take the cross product with (1,0,0), (0,1,0) or (0,0,1) respectively to calculate the first vector.
    // The second vector is just the cross product of the up-vector and out first vector.
    if (up.x <= up.y && up.x <= up.z) {
        x = vector3d(0.0, up.z, -up.y).Normalized();
        y = vector3d(-up.y*up.y - up.z*up.z, up.x*up.y, up.x*up.z).Normalized();
    } else if (up.y <= up.x && up.y <= up.z) {
        x = vector3d(-up.z, 0.0, up.x).Normalized();
        y = vector3d(up.x*up.y, -up.x*up.x - up.z*up.z, up.y*up.z).Normalized();
    } else {
        x = vector3d(up.y, -up.x, 0.0).Normalized();
        y = vector3d(up.x*up.z, up.y*up.z, -up.x*up.x - up.y*up.y).Normalized();
    }
    Planet *planet = static_cast<Planet*>(newframe->GetBody());
    const double radius = planet->GetSystemBody()->GetRadius();
    const vector3d planar = MathUtil::RandomPointInCircle(min_dist * 1000.0, max_dist * 1000.0);
    vector3d pos = (radius * up + x * planar.x + y * planar.y).Normalized();
    float latitude = atan2(pos.y, sqrt(pos.x*pos.x + pos.z * pos.z));
    float longitude = atan2(pos.x, pos.z);

    Pi::game->GetSpace()->AddBody(ship);
    ship->SetLandedOn(planet, latitude, longitude);

    LuaObject<Ship>::PushToLua(ship);

    LUA_DEBUG_END(l, 1);

    return 1;
}