Exemplo n.º 1
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;
}
Exemplo n.º 2
0
// 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;
	}
}
Exemplo n.º 3
0
/*
 * Function: SpawnShipNear
 *
 * Create a ship and place it in space near the given <Body>.
 *
 * > ship = Space.SpawnShip(type, body, min, max, hyperspace)
 *
 * Parameters:
 *
 *   type - the name of the ship
 *
 *   body - the <Body> near which the ship should be spawned
 *
 *   min - minimum distance from the body to place the ship, in Km
 *
 *   max - maximum distance to place the ship
 *
 *   hyperspace - optional table containing hyperspace entry information. If
 *                this is provided the ship will not spawn directly. Instead,
 *                a hyperspace cloud will be created that the ship will exit
 *                from. The table contains two elements, a <SystemPath> for
 *                the system the ship is travelling from, and the due
 *                date/time that the ship should emerge from the cloud.
 *
 * Return:
 *
 *   ship - a <Ship> object for the new ship
 *
 * Example:
 *
 * > -- spawn a ship 10km from the player
 * > local ship = Ship.SpawnNear("viper_police_craft", Game.player, 10, 10)
 *
 * Availability:
 *
 *   alpha 10
 *
 * Status:
 *
 *   experimental
 */
static int l_space_spawn_ship_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 = LuaBody::CheckFromLua(2);
	float min_dist = luaL_checknumber(l, 3);
	float max_dist = luaL_checknumber(l, 4);

	SystemPath *path = NULL;
	double due = -1;
	_unpack_hyperspace_args(l, 5, path, due);

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

	Body *thing = _maybe_wrap_ship_with_cloud(ship, path, due);

	// XXX protect against spawning inside the body
	Frame * newframe = nearbody->GetFrame();
	const vector3d newPosition = (MathUtil::RandomPointOnSphere(min_dist, max_dist)* 1000.0) + nearbody->GetPosition();
	// If the frame is rotating and the chosen position is too far, use non-rotating parent.
	// Otherwise the ship will be given a massive initial velocity when it's bumped out of the
	// rotating frame in the next update
	if (newframe->IsRotatingFrame() && !newframe->IsLocalPosInFrame(newPosition)) {
		assert(newframe->m_parent);
		newframe = newframe->m_parent;
	}

	thing->SetFrame(newframe);;
	thing->SetPosition(newPosition);
	thing->SetVelocity(vector3d(0,0,0));
	Pi::game->GetSpace()->AddBody(thing);

	LuaShip::PushToLua(ship);

	LUA_DEBUG_END(l, 1);

	return 1;
}
Exemplo n.º 4
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;
}