#ifdef _WATER_PHYSICS #include "Game_local.h" #include "physics/Physics_Actor.h" #include "physics/Physics_AF.h" #include "SmokeParticles.h" #include "Liquid.h" // We do these splashes if the mass of the colliding object is less than these values. // Anything large than MEDIUM_SPLASH does a large splash. (get it?) const int SMALL_SPLASH = 25; const int MEDIUM_SPLASH = 1000; /* =============================================================================== idLiquid =============================================================================== */ CLASS_DECLARATION( idEntity, idLiquid ) EVENT( EV_Touch, idLiquid::Event_Touch ) END_CLASS /* ================ idLiquid::Save ================ */ void idLiquid::Save( idSaveGame *savefile ) const { int i; savefile->WriteStaticObject( this->physicsObj ); //savefile->WriteString(smokeName.c_str()); //savefile->WriteString(soundName.c_str()); //bool skipSound //ivan - don't waste space to save this for( i = 0; i < 3; i++ ){ savefile->WriteParticle(this->splash[i]); } savefile->WriteParticle(this->waves); } /* ================ idLiquid::Restore ================ */ void idLiquid::Restore( idRestoreGame *savefile ) { int i; savefile->ReadStaticObject( this->physicsObj ); RestorePhysics( &this->physicsObj ); //savefile->ReadString(this->smokeName); //savefile->ReadString(this->soundName); //bool skipSound //ivan - don't waste space to save this skipSound = false; for( i = 0; i < 3; i++ ){ savefile->ReadParticle(this->splash[i]); } savefile->ReadParticle(this->waves); } /* ================ idLiquid::Spawn ================ */ void idLiquid::Spawn() { /* model = dynamic_cast( renderEntity.hModel ); if ( !model ) { gameLocal.Error( "Entity '%s' must have liquid model", name.c_str() ); } model->Reset(); */ float liquidDensity; float liquidViscosity; //float liquidFriction; idVec3 minSplash; idVec3 minWave; idStr temp; const char *splashName; idStr tempName; //ivan // getters spawnArgs.GetFloat("density","0.01043",liquidDensity); //changes the gravity (>density --> > upward push) spawnArgs.GetFloat("viscosity","3.0",liquidViscosity); //changes the friction (>viscosity --> > friction) //spawnArgs.GetFloat("friction","3.0",liquidFriction); spawnArgs.GetString("liquid_name","water",temp); spawnArgs.GetVector("minSplashVelocity","100 100 100",minSplash); spawnArgs.GetVector("minWaveVelocity","60 60 60",minWave); // setters /* this->smokeName = "smoke_"; this->smokeName.Append(temp); */ /* this->soundName = "snd_"; this->soundName.Append(temp); */ //sndshader = declManager->FindSound( spawnArgs.GetString( "snd_water", "water/water_splash" ) ); //ivan //ivan start skipSound = false; //init sprintf( tempName, "%s_splash_tiny", temp.c_str() ); splashName = spawnArgs.GetString("smoke_small", tempName.c_str() ); this->splash[0] = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); sprintf( tempName, "%s_splash", temp.c_str() ); splashName = spawnArgs.GetString("smoke_medium", tempName.c_str() ); this->splash[1] = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); sprintf( tempName, "%s_splash_large", temp.c_str() ); splashName = spawnArgs.GetString("smoke_large", tempName.c_str() ); this->splash[2] = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); sprintf( tempName, "%s_waves", temp.c_str() ); splashName = spawnArgs.GetString("smoke_waves", tempName.c_str() ); this->waves = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); /* splashName = spawnArgs.GetString("smoke_small","water_splash_tiny"); this->splash[0] = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); splashName = spawnArgs.GetString("smoke_medium","water_splash"); this->splash[1] = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); splashName = spawnArgs.GetString("smoke_large","water_splash_large"); this->splash[2] = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); splashName = spawnArgs.GetString("smoke_waves","water_waves"); this->waves = static_cast(declManager->FindType(DECL_PARTICLE,splashName)); */ //ivan end // setup physics this->physicsObj.SetSelf(this); this->physicsObj.SetClipModel( new idClipModel(this->GetPhysics()->GetClipModel()), liquidDensity ); this->physicsObj.SetOrigin(this->GetPhysics()->GetOrigin()); this->physicsObj.SetAxis(this->GetPhysics()->GetAxis()); this->physicsObj.SetGravity( gameLocal.GetGravity() ); this->physicsObj.SetContents( CONTENTS_WATER | CONTENTS_TRIGGER ); this->physicsObj.SetDensity(liquidDensity); this->physicsObj.SetViscosity(liquidViscosity); this->physicsObj.SetMinSplashVelocity(minSplash); this->physicsObj.SetMinWaveVelocity(minWave); this->SetPhysics( &this->physicsObj ); BecomeActive( TH_THINK ); } /* ================ idLiquid::Event_Touch This is mainly used for actors who touch the liquid, it spawns a splash near they're feet if they're moving fast enough. ================ */ void idLiquid::Event_Touch( idEntity *other, trace_t *trace ) { //idPhysics_Liquid *liquid; idPhysics_Actor *phys; //only for actors! if( !other->GetPhysics()->IsType(idPhysics_Actor::Type) ){ return; } //only if enough in the water phys = static_cast(other->GetPhysics()); if( phys->GetWaterLevel() != WATERLEVEL_FEET ){ return; } //ivan start - stop actors from constantly splashing when they're in the water //nextWaterSplash can be reset by the player if its walking in order to force this random behaviour if ( phys->nextWaterSplash == 0 ) { //someone reset this (or it's the first time) if( gameLocal.random.RandomFloat() > 0.5f ){ return; } } //default behaviour if ( phys->nextWaterSplash < gameLocal.time ) { phys->nextWaterSplash = gameLocal.time + 50 + gameLocal.random.RandomInt(50); if( phys->nextWaterSnd < gameLocal.time ){ phys->nextWaterSnd = gameLocal.time + 300 + gameLocal.random.RandomInt(100); }else{ skipSound = true; } }else{ return; } //ivan end impactInfo_t info; other->GetImpactInfo(this,trace->c.id,trace->c.point,&info); //liquid = &this->physicsObj; trace->c.point = info.position + other->GetPhysics()->GetOrigin(); trace->c.entityNum = other->entityNumber; this->Collide(*trace,info.velocity); } /* ================ idLiquid::Collide Spawns a splash particle and attaches a sound to the colliding entity. ================ */ bool idLiquid::Collide( const trace_t &collision, const idVec3 &velocity ) { idEntity *e = gameLocal.entities[collision.c.entityNum]; const idDeclParticle *splash; float eMass; idVec3 splashSpot; float velSquare = velocity.LengthSqr(); //ivan start - why did he do this? We can directly use our physicsObj :| //was: idPhysics_Liquid *phys = static_cast( this->GetPhysics() ); //was: const char *sName; int customType; //avoid too many spashes for AFs! if( e->GetPhysics()->IsType(idPhysics_AF::Type) ){ idPhysics_AF *phys = static_cast(e->GetPhysics()); if ( phys->nextWaterSplash < gameLocal.time ) { phys->nextWaterSplash = gameLocal.time + 30 + gameLocal.random.RandomInt(50); }else{ return true; } } //ivan end eMass = e->GetPhysics()->GetMass(); splashSpot = collision.c.point; if( velSquare > physicsObj.GetMinSplashVelocity().LengthSqr() ) { //ivan - was: phys //ivan start /* // pick which splash particle to spawn // first we check the entity, if it's not defined we use // one defined for this liquid. sName = e->spawnArgs.GetString(this->smokeName.c_str()); if( *sName != '\0' ) { // load entity particle splash = static_cast(declManager->FindType(DECL_PARTICLE,sName)); } else { */ customType = e->spawnArgs.GetInt( "water_size" , "-1"); //default is invalid if( customType >= 0 && customType < 3 ){ splash = this->splash[customType]; }else{ //ivan end // load a liquid particle based on the mass of the splashing entity if( eMass < SMALL_SPLASH ) splash = this->splash[0]; else if( eMass < MEDIUM_SPLASH ) splash = this->splash[1]; else splash = this->splash[2]; } //ivan start // only play the sound for a splash //was: e->StartSound( this->soundName.c_str(), SND_CHANNEL_ANY, 0, false, NULL); if( skipSound ){ skipSound = false; }else{ e->StartSound( "snd_water", SND_CHANNEL_ANY, 0, false, NULL); } //ivan end } else if( velSquare > physicsObj.GetMinWaveVelocity().LengthSqr() ) { //ivan - was: phys splash = this->waves; } else { // the object is moving too slow so we abort return true; } // spawn the particle gameLocal.smokeParticles->EmitSmoke(splash,gameLocal.time,gameLocal.random.RandomFloat(),splashSpot,mat3_identity); return true; } #endif // _WATER_PHYSICS