// 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; }
/* * 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 = LuaObject<Body>::CheckFromLua(2); float min_dist = luaL_checknumber(l, 3); float max_dist = luaL_checknumber(l, 4); SystemPath *path = 0; 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->IsRotFrame() && newframe->GetRadius() < newPosition.Length()) { assert(newframe->GetParent()); newframe = newframe->GetParent(); } thing->SetFrame(newframe);; thing->SetPosition(newPosition); thing->SetVelocity(vector3d(0,0,0)); Pi::game->GetSpace()->AddBody(thing); LuaObject<Ship>::PushToLua(ship); LUA_DEBUG_END(l, 1); return 1; }
//----------------------------------------------------------------------------- // Name: Frame::IsAncestor() // Desc: Returns TRUE if the specified frame is an ancestor of this frame // ancestor = parent, parent->parent, etc. // Also returns TRUE if specified frame is NULL. //----------------------------------------------------------------------------- BOOL Frame::IsAncestor( Frame* pOtherFrame ) { if( pOtherFrame == NULL ) return TRUE; if( pOtherFrame == this ) return FALSE; Frame* pFrame = GetParent(); while( pFrame != NULL ) { if( pFrame == pOtherFrame ) return TRUE; pFrame = pFrame->GetParent(); } return FALSE; }
void AmbientSounds::Update() { const float v_env = (Pi::worldView->GetCameraController()->IsExternal() ? 1.0f : 0.5f) * Sound::GetSfxVolume(); if (Pi::player->GetFlightState() == Ship::DOCKED) { if (s_starNoise.IsPlaying()) { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; s_starNoise.VolumeAnimate(target, dv_dt); s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } for(int i=0; i<eMaxNumAtmosphereSounds; i++) { if (s_atmosphereNoises[i].IsPlaying()) { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; s_atmosphereNoises[i].VolumeAnimate(target, dv_dt); s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } } if (s_planetSurfaceNoise.IsPlaying()) { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; s_planetSurfaceNoise.VolumeAnimate(target, dv_dt); s_planetSurfaceNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } if (!s_stationNoise.IsPlaying()) { // just use a random station noise until we have a // concept of 'station size' s_stationNoise.Play(s_stationNoiseSounds[Pi::player->GetDockedWith()->GetSystemBody()->GetSeed() % NUM_STATION_SOUNDS], 0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT); } } else if (Pi::player->GetFlightState() == Ship::LANDED) { /* Planet surface noise on rough-landing */ if (s_starNoise.IsPlaying()) { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; s_starNoise.VolumeAnimate(target, dv_dt); s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } for(int i=0; i<eMaxNumAtmosphereSounds; i++) { if (s_atmosphereNoises[i].IsPlaying()) { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; s_atmosphereNoises[i].VolumeAnimate(target, dv_dt); s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } } if (s_stationNoise.IsPlaying()) { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; s_stationNoise.VolumeAnimate(target, dv_dt); s_stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } // lets try something random for the time being if (!s_planetSurfaceNoise.IsPlaying()) { const SystemBody *sbody = Pi::player->GetFrame()->GetSystemBody(); assert(sbody); const char *sample = 0; if (sbody->GetLifeAsFixed() > fixed(1,5)) { sample = s_surfaceLifeSounds[sbody->GetSeed() % NUM_SURFACE_LIFE_SOUNDS]; } else if (sbody->GetVolatileGasAsFixed() > fixed(1,2)) { sample = s_surfaceSounds[sbody->GetSeed() % NUM_SURFACE_DEAD_SOUNDS]; } else if (sbody->GetVolatileGasAsFixed() > fixed(1,10)) { sample = "Wind"; } if (sample) { s_planetSurfaceNoise.Play(sample, 0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT); } } } else if (s_planetSurfaceNoise.IsPlaying()) { // s_planetSurfaceNoise.IsPlaying() - if we are out of the atmosphere then stop playing if (Pi::player->GetFrame()->IsRotFrame()) { const Body *astro = Pi::player->GetFrame()->GetBody(); if (astro->IsType(Object::PLANET)) { const double dist = Pi::player->GetPosition().Length(); double pressure, density; static_cast<const Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density); if (pressure < 0.001) { // Stop playing surface noise once out of the atmosphere s_planetSurfaceNoise.Stop(); } } } } else { if (s_stationNoise.IsPlaying()) { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; s_stationNoise.VolumeAnimate(target, dv_dt); s_stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } if (Pi::game->IsNormalSpace()) { StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get(); if (astroNoiseSeed != s->GetSeed()) { // change sound! astroNoiseSeed = s->GetSeed(); const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {0.1f,0.1f}; s_starNoise.VolumeAnimate(target, dv_dt); s_starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); // XXX the way Sound::Event works isn't totally obvious. // to destroy the object doesn't stop the sound. it is // really just a sound event reference s_starNoise = Sound::Event(); } } // when all the sounds are in we can use the body we are in frame of reference to if (!s_starNoise.IsPlaying()) { Frame *f = Pi::player->GetFrame(); if (!f) return; // When player has no frame (game abort) then get outta here!! const SystemBody *sbody = f->GetSystemBody(); const char *sample = 0; for (; sbody && !sample; sbody = f->GetSystemBody()) { switch (sbody->GetType()) { case SystemBody::TYPE_BROWN_DWARF: sample = "Brown_Dwarf_Substellar_Object"; break; case SystemBody::TYPE_STAR_M: sample = "M_Red_Star"; break; case SystemBody::TYPE_STAR_K: sample = "K_Star"; break; case SystemBody::TYPE_WHITE_DWARF: sample = "White_Dwarf_Star"; break; case SystemBody::TYPE_STAR_G: sample = "G_Star"; break; case SystemBody::TYPE_STAR_F: sample = "F_Star"; break; case SystemBody::TYPE_STAR_A: sample = "A_Star"; break; case SystemBody::TYPE_STAR_B: sample = "B_Hot_Blue_STAR"; break; case SystemBody::TYPE_STAR_O: sample = "Blue_Super_Giant"; break; case SystemBody::TYPE_PLANET_GAS_GIANT: { if (sbody->GetMassAsFixed() > fixed(400,1)) { sample = "Very_Large_Gas_Giant"; } else if (sbody->GetMassAsFixed() > fixed(80,1)) { sample = "Large_Gas_Giant"; } else if (sbody->GetMassAsFixed() > fixed(20,1)) { sample = "Medium_Gas_Giant"; } else { sample = "Small_Gas_Giant"; } } break; default: sample = 0; break; } if (sample) { s_starNoise.Play(sample, 0.0f, 0.0f, Sound::OP_REPEAT); s_starNoise.VolumeAnimate(.3f*v_env, .3f*v_env, .05f, .05f); } else { // go up orbital hierarchy tree to see if we can find a sound f = f->GetParent(); if (f == 0) break; } } } const Body *astro = Pi::player->GetFrame()->GetBody(); if (astro && Pi::player->GetFrame()->IsRotFrame() && (astro->IsType(Object::PLANET))) { double dist = Pi::player->GetPosition().Length(); double pressure, density; static_cast<const Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density); // maximum volume at around 2km/sec at earth density, pressure const float pressureVolume = float(density * Pi::player->GetVelocity().Length() * 0.0005); //volume = Clamp(volume, 0.0f, 1.0f) * v_env; float volumes[eMaxNumAtmosphereSounds]; for(int i=0; i<eMaxNumAtmosphereSounds; i++) { const float beg = s_rangeTable[i][0]; const float inv = s_rangeTable[i][1]; volumes[i] = Clamp((pressureVolume - beg) * inv, 0.0f, 1.0f) * v_env; } for(int i=0; i<eMaxNumAtmosphereSounds; i++) { const float volume = volumes[i]; if (s_atmosphereNoises[i].IsPlaying()) { const float target[2] = {volume, volume}; const float dv_dt[2] = {1.0f,1.0f}; s_atmosphereNoises[i].VolumeAnimate(target, dv_dt); } else { s_atmosphereNoises[i].Play(s_airflowTable[i], volume, volume, Sound::OP_REPEAT); } } } else { const float target[2] = {0.0f,0.0f}; const float dv_dt[2] = {1.0f,1.0f}; for(int i=0; i<eMaxNumAtmosphereSounds; i++) { s_atmosphereNoises[i].VolumeAnimate(target, dv_dt); s_atmosphereNoises[i].SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } } } }
void AmbientSounds::Update() { float v_env = (Pi::worldView->GetActiveCamera()->IsExternal() ? 1.0f : 0.5f) * Sound::GetSfxVolume(); if (Pi::player->GetFlightState() == Ship::DOCKED) { if (starNoise.IsPlaying()) { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; starNoise.VolumeAnimate(target, dv_dt); starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } if (atmosphereNoise.IsPlaying()) { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; atmosphereNoise.VolumeAnimate(target, dv_dt); atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } if (planetSurfaceNoise.IsPlaying()) { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; planetSurfaceNoise.VolumeAnimate(target, dv_dt); planetSurfaceNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } if (!stationNoise.IsPlaying()) { const char *sounds[] = { "Large_Station_ambient", "Medium_Station_ambient", "Small_Station_ambient" }; // just use a random station noise until we have a // concept of 'station size' stationNoise.Play(sounds[Pi::player->GetDockedWith()->GetSystemBody()->seed % 3], 0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT); } } else if (Pi::player->GetFlightState() == Ship::LANDED) { /* Planet surface noise on rough-landing */ if (starNoise.IsPlaying()) { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; starNoise.VolumeAnimate(target, dv_dt); starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } if (atmosphereNoise.IsPlaying()) { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; atmosphereNoise.VolumeAnimate(target, dv_dt); atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } if (stationNoise.IsPlaying()) { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; stationNoise.VolumeAnimate(target, dv_dt); stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } // lets try something random for the time being if (!planetSurfaceNoise.IsPlaying()) { SystemBody *sbody = Pi::player->GetFrame()->GetSystemBody(); assert(sbody); const char *sample = NULL; if (sbody->m_life > fixed(1,5)) { const char *s[] = { "Wind", "Thunder_1", "Thunder_2", "Thunder_3", "Thunder_4", "Storm", "Rain_Light", "River", "RainForestIntroducedNight", "RainForestIntroduced", "NormalForestIntroduced" }; sample = s[sbody->seed % 11]; } else if (sbody->m_volatileGas > fixed(1,2)) { const char *s[] = { "Wind", "Thunder_1", "Thunder_2", "Thunder_3", "Thunder_4", "Storm" }; sample = s[sbody->seed % 6]; } else if (sbody->m_volatileGas > fixed(1,10)) { sample = "Wind"; } if (sample) { planetSurfaceNoise.Play(sample, 0.3f*v_env, 0.3f*v_env, Sound::OP_REPEAT); } } } else if (planetSurfaceNoise.IsPlaying()) { // planetSurfaceNoise.IsPlaying() - if we are out of the atmosphere then stop playing if (Pi::player->GetFrame()->IsRotFrame()) { Body *astro = Pi::player->GetFrame()->GetBody(); if (astro->IsType(Object::PLANET)) { double dist = Pi::player->GetPosition().Length(); double pressure, density; static_cast<Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density); if (pressure < 0.001) { // Stop playing surface noise once out of the atmosphere planetSurfaceNoise.Stop(); } } } } else { if (stationNoise.IsPlaying()) { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; stationNoise.VolumeAnimate(target, dv_dt); stationNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } { if (Pi::game->IsNormalSpace()) { StarSystem *s = Pi::game->GetSpace()->GetStarSystem().Get(); if (astroNoiseSeed != s->GetSeed()) { // change sound! astroNoiseSeed = s->GetSeed(); float target[2] = {0.0f,0.0f}; float dv_dt[2] = {0.1f,0.1f}; starNoise.VolumeAnimate(target, dv_dt); starNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); // XXX the way Sound::Event works isn't totally obvious. // to destroy the object doesn't stop the sound. it is // really just a sound event reference starNoise = Sound::Event(); } } } // when all the sounds are in we can use the body we are in frame of reference to if (!starNoise.IsPlaying()) { Frame *f = Pi::player->GetFrame(); if (!f) return; // When player has no frame (game abort) then get outta here!! const SystemBody *sbody = f->GetSystemBody(); const char *sample = 0; for (; sbody && !sample; sbody = f->GetSystemBody()) { switch (sbody->type) { case SystemBody::TYPE_BROWN_DWARF: sample = "Brown_Dwarf_Substellar_Object"; break; case SystemBody::TYPE_STAR_M: sample = "M_Red_Star"; break; case SystemBody::TYPE_STAR_K: sample = "K_Star"; break; case SystemBody::TYPE_WHITE_DWARF: sample = "White_Dwarf_Star"; break; case SystemBody::TYPE_STAR_G: sample = "G_Star"; break; case SystemBody::TYPE_STAR_F: sample = "F_Star"; break; case SystemBody::TYPE_STAR_A: sample = "A_Star"; break; case SystemBody::TYPE_STAR_B: sample = "B_Hot_Blue_STAR"; break; case SystemBody::TYPE_STAR_O: sample = "Blue_Super_Giant"; break; case SystemBody::TYPE_PLANET_GAS_GIANT: { if (sbody->mass > fixed(400,1)) { sample = "Very_Large_Gas_Giant"; } else if (sbody->mass > fixed(80,1)) { sample = "Large_Gas_Giant"; } else if (sbody->mass > fixed(20,1)) { sample = "Medium_Gas_Giant"; } else { sample = "Small_Gas_Giant"; } } break; default: sample = 0; break; } if (sample) { starNoise.Play(sample, 0.0f, 0.0f, Sound::OP_REPEAT); starNoise.VolumeAnimate(.3f*v_env, .3f*v_env, .05f, .05f); } else { // go up orbital hierarchy tree to see if we can find a sound f = f->GetParent(); if (f == 0) break; } } } Body *astro; if ((astro = Pi::player->GetFrame()->GetBody()) && Pi::player->GetFrame()->IsRotFrame() && (astro->IsType(Object::PLANET))) { double dist = Pi::player->GetPosition().Length(); double pressure, density; static_cast<Planet*>(astro)->GetAtmosphericState(dist, &pressure, &density); // maximum volume at around 2km/sec at earth density, pressure float volume = float(density * Pi::player->GetVelocity().Length() * 0.0005); volume = Clamp(volume, 0.0f, 1.0f) * v_env; if (atmosphereNoise.IsPlaying()) { float target[2] = {volume, volume}; float dv_dt[2] = {1.0f,1.0f}; atmosphereNoise.VolumeAnimate(target, dv_dt); } else { atmosphereNoise.Play("Atmosphere_Flying", volume, volume, Sound::OP_REPEAT); } } else { float target[2] = {0.0f,0.0f}; float dv_dt[2] = {1.0f,1.0f}; atmosphereNoise.VolumeAnimate(target, dv_dt); atmosphereNoise.SetOp(Sound::OP_REPEAT | Sound::OP_STOP_AT_TARGET_VOLUME); } } }