/* ================ sdWalker::UpdateModelTransform ================ */ void sdWalker::UpdateModelTransform( void ) { sdTeleporter* teleportEnt = teleportEntity; if ( teleportEnt != NULL ) { idPlayer* player = gameLocal.GetLocalPlayer(); if ( player != NULL && player->GetProxyEntity() == this ) { idEntity* viewer = teleportEnt->GetViewEntity(); if ( viewer ) { renderEntity.axis = viewer->GetPhysics()->GetAxis(); renderEntity.origin = viewer->GetPhysics()->GetOrigin(); return; } } } renderEntity.axis = viewAxis; renderEntity.origin = GetPhysics()->GetOrigin(); idPlayer* player = gameLocal.GetLocalViewPlayer(); if ( !player || player->GetProxyEntity() != this ) { DoPredictionErrorDecay(); } }
bool idActor::CheckFOV( const noVec3 &pos ) const { if ( fovDot == 1.0f ) { return true; } float dot; noVec3 delta; delta = pos - GetEyePosition(); // get our gravity normal const noVec3 &gravityDir = GetPhysics()->GetGravityNormal(); // infinite vertical vision, so project it onto our orientation plane delta -= gravityDir * ( gravityDir * delta ); delta.Normalize(); dot = viewAxis[ 0 ] * delta; return ( dot >= fovDot ); }
/* ================ idAF::SetConstraintPosition Only moves constraints that bind the entity to another entity. ================ */ void idAF::SetConstraintPosition(const char *name, const idVec3 &pos) { idAFConstraint *constraint; constraint = GetPhysics()->GetConstraint(name); if (!constraint) { gameLocal.Warning("can't find a constraint with the name '%s'", name); return; } if (constraint->GetBody2() != NULL) { gameLocal.Warning("constraint '%s' does not bind to another entity", name); return; } switch (constraint->GetType()) { case CONSTRAINT_BALLANDSOCKETJOINT: { idAFConstraint_BallAndSocketJoint *bs = static_cast<idAFConstraint_BallAndSocketJoint *>(constraint); bs->Translate(pos - bs->GetAnchor()); break; } case CONSTRAINT_UNIVERSALJOINT: { idAFConstraint_UniversalJoint *uj = static_cast<idAFConstraint_UniversalJoint *>(constraint); uj->Translate(pos - uj->GetAnchor()); break; } case CONSTRAINT_HINGE: { idAFConstraint_Hinge *hinge = static_cast<idAFConstraint_Hinge *>(constraint); hinge->Translate(pos - hinge->GetAnchor()); break; } default: { gameLocal.Warning("cannot set the constraint position for '%s'", name); break; } } }
bool rvMonsterStroggHover::MarkerPosValid ( void ) { //debouncer ftw if( markerCheckTime > gameLocal.GetTime() ) { return true; } markerCheckTime = gameLocal.GetTime() + 500 + (gameLocal.random.RandomFloat() * 500); trace_t trace; gameLocal.TracePoint( this, trace, marker.GetEntity()->GetPhysics()->GetOrigin(), marker.GetEntity()->GetPhysics()->GetOrigin(), GetPhysics()->GetClipMask(), NULL ); if ( !(trace.c.contents&GetPhysics()->GetClipMask()) ) {//not in solid gameLocal.TracePoint( this, trace, marker.GetEntity()->GetPhysics()->GetOrigin(), GetEnemy()->GetEyePosition(), MASK_SHOT_BOUNDINGBOX, GetEnemy() ); idActor* enemyAct = NULL; rvVehicle* enemyVeh = NULL; if ( GetEnemy()->IsType( rvVehicle::GetClassType() ) ) { enemyVeh = static_cast<rvVehicle*>(GetEnemy()); } else if ( GetEnemy()->IsType( idActor::GetClassType() ) ) { enemyAct = static_cast<idActor*>(GetEnemy()); } idEntity* hitEnt = gameLocal.entities[trace.c.entityNum]; idActor* hitAct = NULL; if ( hitEnt && hitEnt->IsType( idActor::GetClassType() ) ) { hitAct = static_cast<idActor*>(hitEnt); } if ( trace.fraction >= 1.0f || (enemyAct && enemyAct->IsInVehicle() && enemyAct->GetVehicleController().GetVehicle() == gameLocal.entities[trace.c.entityNum]) || (enemyVeh && hitAct && hitAct->IsInVehicle() && hitAct->GetVehicleController().GetVehicle() == enemyVeh) ) {//have a clear LOS to enemy if ( PointReachableAreaNum( marker.GetEntity()->GetPhysics()->GetOrigin() ) ) {//valid AAS there... return true; } } } return false; }
/* ================ rvMonsterConvoyGround::OnDeath ================ */ void rvMonsterConvoyGround::OnDeath ( void ) { idVec3 fxOrg; idVec3 up; idMat3 fxAxis; //center it fxOrg = GetPhysics()->GetCenterMass(); //point it up up.Set( 0, 0, 1 ); fxAxis = up.ToMat3(); //if we can play it at the joint, do that jointHandle_t axisJoint = animator.GetJointHandle ( "axis" ); if ( axisJoint != INVALID_JOINT ) { idMat3 junk; animator.GetJointLocalTransform( axisJoint, gameLocal.GetTime(), fxOrg, junk ); fxOrg = renderEntity.origin + (fxOrg*renderEntity.axis); } gameLocal.PlayEffect ( spawnArgs, "fx_death", fxOrg, fxAxis ); idAI::OnDeath ( ); }
int CVehicleMovementAerodynamic::AddBox(Vec3 *_pvPos,Vec3 *_pvSize,float _fMass,int _iID/*=-1*/) { IPhysicalEntity* pPhysics = GetPhysics(); IGeomManager *pGeomManager = gEnv->pPhysicalWorld->GetGeomManager(); primitives::box Box; Box.Basis.SetIdentity(); Box.center.Set(0.0f,0.0f,0.0f); Box.size = (*_pvSize) / 2.0f; Box.bOriented = 0; IGeometry *pGeometry = pGeomManager->CreatePrimitive(primitives::box::type,&Box); phys_geometry *pPhysGeometry = pGeomManager->RegisterGeometry(pGeometry); pGeometry->Release(); pe_geomparams partpos; partpos.pos = *_pvPos; partpos.mass = _fMass; int id = pPhysics->AddGeometry(pPhysGeometry,&partpos,_iID); pGeomManager->UnregisterGeometry(pPhysGeometry); return id; }
/* ================ idTrigger_EntityName::Spawn ================ */ void idTrigger_EntityName::Spawn( void ) { spawnArgs.GetFloat( "wait", "0.5", wait ); spawnArgs.GetFloat( "random", "0", random ); spawnArgs.GetFloat( "delay", "0", delay ); spawnArgs.GetFloat( "random_delay", "0", random_delay ); if( random && ( random >= wait ) && ( wait >= 0 ) ) { random = wait - 1; gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ) ); } if( random_delay && ( random_delay >= delay ) && ( delay >= 0 ) ) { random_delay = delay - 1; gameLocal.Warning( "idTrigger_EntityName '%s' at (%s) has random_delay >= delay", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ) ); } spawnArgs.GetBool( "triggerFirst", "0", triggerFirst ); entityName = spawnArgs.GetString( "entityname" ); if( !entityName.Length() ) { gameLocal.Error( "idTrigger_EntityName '%s' at (%s) doesn't have 'entityname' key specified", name.c_str(), GetPhysics()->GetOrigin().ToString( 0 ) ); } nextTriggerTime = 0; if( !spawnArgs.GetBool( "noTouch" ) ) { GetPhysics()->SetContents( CONTENTS_TRIGGER ); } }
void hhProxDoor::ReadFromSnapshot( const idBitMsgDelta &msg ) { ReadBindFromSnapshot(msg); GetPhysics()->ReadFromSnapshot(msg); int num = msg.ReadBits(8); doorPieces.SetNum(num); for (int i = 0; i < num; i++) { int spawnId = msg.ReadBits(32); if (!spawnId) { doorPieces[i] = NULL; } else { doorPieces[i].SetSpawnId(spawnId); } } EProxState newProxState = (EProxState)msg.ReadBits(8); if (proxState != newProxState) { SetDoorState(newProxState); } lastAmount = msg.ReadFloat(); bool closed = !!msg.ReadBits(1); if (aas_area_closed != closed) { SetAASAreaState(closed); } /* EPDoorSound newSndState = (EPDoorSound)msg.ReadBits(8); if (newSndState != doorSndState) { UpdateSoundState(newSndState); } */ hasNetData = true; }
/* ================= idMoveable::Collide ================= */ bool idMoveable::Collide( const trace_t &collision, const idVec3 &velocity ) { float v, f; idVec3 dir; idEntity *ent; //gameLocal.Printf("collision\n"); v = -( velocity * collision.c.normal ); if ( v > BOUNCE_SOUND_MIN_VELOCITY && gameLocal.time > nextSoundTime ) { f = v > BOUNCE_SOUND_MAX_VELOCITY ? 1.0f : idMath::Sqrt( v - BOUNCE_SOUND_MIN_VELOCITY ) * ( 1.0f / idMath::Sqrt( BOUNCE_SOUND_MAX_VELOCITY - BOUNCE_SOUND_MIN_VELOCITY ) ); if ( StartSound( "snd_bounce", SND_CHANNEL_BODY, 0, false, NULL ) ) { // don't set the volume unless there is a bounce sound as it overrides the entire channel // which causes footsteps on ai's to not honor their shader parms SetSoundVolume( f ); } nextSoundTime = gameLocal.time + 500; } if ( canDamage && damage.Length() && gameLocal.time > nextDamageTime ) { ent = gameLocal.entities[ collision.c.entityNum ]; if ( ent && v > minDamageVelocity ) { f = v > maxDamageVelocity ? 1.0f : idMath::Sqrt( v - minDamageVelocity ) * ( 1.0f / idMath::Sqrt( maxDamageVelocity - minDamageVelocity ) ); dir = velocity; dir.NormalizeFast(); ent->Damage( this, GetPhysics()->GetClipModel()->GetOwner(), dir, damage, f, INVALID_JOINT ); nextDamageTime = gameLocal.time + 1000; } } if ( fxCollide.Length() && gameLocal.time > nextCollideFxTime ) { idEntityFx::StartFx( fxCollide, &collision.c.point, NULL, this, false ); nextCollideFxTime = gameLocal.time + 3500; } return false; }
/* ================= idEntityFx::ReadFromSnapshot ================= */ void idEntityFx::ReadFromSnapshot( const idBitMsgDelta &msg ) { int fx_index, start_time, max_lapse; GetPhysics()->ReadFromSnapshot( msg ); ReadBindFromSnapshot( msg ); fx_index = gameLocal.ClientRemapDecl( DECL_FX, msg.ReadLong() ); start_time = msg.ReadLong(); if ( fx_index != -1 && start_time > 0 && !fxEffect && started < 0 ) { spawnArgs.GetInt( "effect_lapse", "1000", max_lapse ); if ( gameLocal.time - start_time > max_lapse ) { // too late, skip the effect completely started = 0; return; } const idDeclFX *fx = static_cast<const idDeclFX *>( declManager->DeclByIndex( DECL_FX, fx_index ) ); if ( !fx ) { gameLocal.Error( "FX at index %d not found", fx_index ); } fxEffect = fx; Setup( fx->GetName() ); Start( start_time ); } }
/* ================ idTrigger_Hurt::Event_Touch ================ */ void idTrigger_Hurt::Event_Touch( idEntity *other, trace_t *trace ) { const char *damage; if( on && other && gameLocal.time >= nextTime ) { #ifdef _D3XP bool playerOnly = spawnArgs.GetBool( "playerOnly" ); if( playerOnly ) { if( !other->IsType( idPlayer::Type ) ) { return; } } #endif damage = spawnArgs.GetString( "def_damage", "damage_painTrigger" ); #ifdef _D3XP idVec3 dir = vec3_origin; if( spawnArgs.GetBool( "kick_from_center", "0" ) ) { dir = other->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); dir.Normalize(); } other->Damage( NULL, NULL, dir, damage, 1.0f, INVALID_JOINT ); #else other->Damage( NULL, NULL, vec3_origin, damage, 1.0f, INVALID_JOINT ); #endif ActivateTargets( other ); CallScript(); nextTime = gameLocal.time + SEC2MS( delay ); } }
/* ================ rvEffect::Event_LookAtTarget Reorients the effect entity towards its target and sets the end origin as well ================ */ void rvEffect::Event_LookAtTarget ( void ) { const idKeyValue *kv; idVec3 dir; if ( !effect || !clientEffect ) { return; } kv = spawnArgs.MatchPrefix( "target", NULL ); while( kv ) { idEntity *ent = gameLocal.FindEntity( kv->GetValue() ); if( ent ) { if( !idStr::Icmp( ent->GetEntityDefName(), "target_null" ) ) { dir = ent->GetPhysics()->GetOrigin() - GetPhysics()->GetOrigin(); dir.Normalize(); clientEffect->SetEndOrigin ( ent->GetPhysics()->GetOrigin() ); clientEffect->SetAxis ( dir.ToMat3( ) ); return; } } kv = spawnArgs.MatchPrefix( "target", kv ); } }
/* ================ idTrigger_Multi::CheckFacing ================ */ bool idTrigger_Multi::CheckFacing( idEntity *activator ) { if ( spawnArgs.GetBool( "facing" ) ) { if ( !activator->IsType( idPlayer::GetClassType() ) ) { return true; } idPlayer *player = static_cast< idPlayer* >( activator ); // Unfortunately, the angle key rotates the trigger entity also. So I've added // an angleFacing key which is used instead when present, otherwise the code defaults // to the behaviour present prior to this change idVec3 tFacing = GetPhysics()->GetAxis()[0]; if ( spawnArgs.FindKey( "angleFacing" )) { idAngles angs(0,spawnArgs.GetFloat( "angleFacing", "0" ),0); tFacing = angs.ToForward(); } float dot = player->viewAngles.ToForward() * tFacing; float angle = RAD2DEG( idMath::ACos( dot ) ); if ( angle > spawnArgs.GetFloat( "angleLimit", "30" ) ) { return false; } } return true; }
// RAVEN BEGIN // kfuller: void idTrigger_Multi::Event_EarthQuake(float requiresLOS) { // does this entity even care about earthquakes? float quakeChance = 0; if (!spawnArgs.GetFloat("quakeChance", "0", quakeChance)) { return; } if (rvRandom::flrand(0, 1.0f) > quakeChance) { // failed its activation roll return; } if (requiresLOS) { // if the player doesn't have line of sight to this fx, don't do anything trace_t trace; idPlayer *player = gameLocal.GetLocalPlayer(); idVec3 viewOrigin; idMat3 viewAxis; player->GetViewPos(viewOrigin, viewAxis); // RAVEN BEGIN // ddynerman: multiple clip worlds gameLocal.TracePoint( this, trace, viewOrigin, GetPhysics()->GetOrigin(), MASK_OPAQUE, player ); // RAVEN END if (trace.fraction < 1.0f) { // something blocked LOS return; } } // activate this effect now TriggerAction(gameLocal.entities[ENTITYNUM_WORLD]); }
/* ================ rvEffect::Spawn ================ */ void rvEffect::Spawn( void ) { const char* fx; if ( !spawnArgs.GetString ( "fx", "", &fx ) || !*fx ) { if ( !( gameLocal.editors & EDITOR_FX ) ) { gameLocal.Warning ( "no effect file specified on effect entity '%s'", name.c_str() ); PostEventMS ( &EV_Remove, 0 ); return; } } else { effect = ( const idDecl * )declManager->FindEffect( spawnArgs.GetString ( "fx" ) ); if( effect->IsImplicit() ) { common->Warning( "Unknown effect \'%s\' on entity \'%s\'", spawnArgs.GetString ( "fx" ), GetName() ); } } spawnArgs.GetVector ( "endOrigin", "0 0 0", endOrigin ); spawnArgs.GetBool ( "loop", "0", loop ); // If look at target is set the effect will continually update itself to look at its target spawnArgs.GetBool( "lookAtTarget", "0", lookAtTarget ); renderEntity.shaderParms[SHADERPARM_ALPHA] = spawnArgs.GetFloat ( "_alpha", "1" ); renderEntity.shaderParms[SHADERPARM_BRIGHTNESS] = spawnArgs.GetFloat ( "_brightness", "1" ); if( spawnArgs.GetBool( "start_on", loop ? "1" : "0" ) ) { ProcessEvent( &EV_Activate, this ); } #if 0 // If anyone ever gets around to a flood fill from the origin rather than the over generous PushVolumeIntoTree bounds, // this warning will become useful. Until then, it's a bogus warning. if( gameRenderWorld->PointInArea( GetPhysics()->GetOrigin() ) < 0 ) { common->Warning( "Effect \'%s\' out of world", name.c_str() ); } #endif }
/* ================ idSecurityCamera::DrawFov ================ */ void idSecurityCamera::DrawFov() { int i; float radius, a, s, c, halfRadius; idVec3 right, up; idVec4 color( 1, 0, 0, 1 ), color2( 0, 0, 1, 1 ); idVec3 lastPoint, point, lastHalfPoint, halfPoint, center; idVec3 dir = GetAxis(); dir.NormalVectors( right, up ); radius = tan( scanFov * idMath::PI / 360.0f ); halfRadius = radius * 0.5f; lastPoint = dir + up * radius; lastPoint.Normalize(); lastPoint = GetPhysics()->GetOrigin() + lastPoint * scanDist; lastHalfPoint = dir + up * halfRadius; lastHalfPoint.Normalize(); lastHalfPoint = GetPhysics()->GetOrigin() + lastHalfPoint * scanDist; center = GetPhysics()->GetOrigin() + dir * scanDist; for( i = 1; i < 12; i++ ) { a = idMath::TWO_PI * i / 12.0f; idMath::SinCos( a, s, c ); point = dir + right * s * radius + up * c * radius; point.Normalize(); point = GetPhysics()->GetOrigin() + point * scanDist; gameRenderWorld->DebugLine( color, lastPoint, point ); gameRenderWorld->DebugLine( color, GetPhysics()->GetOrigin(), point ); lastPoint = point; halfPoint = dir + right * s * halfRadius + up * c * halfRadius; halfPoint.Normalize(); halfPoint = GetPhysics()->GetOrigin() + halfPoint * scanDist; gameRenderWorld->DebugLine( color2, point, halfPoint ); gameRenderWorld->DebugLine( color2, lastHalfPoint, halfPoint ); lastHalfPoint = halfPoint; gameRenderWorld->DebugLine( color2, halfPoint, center ); } }
/* ================ idLight::GetPhysicsToSoundTransform ================ */ bool idLight::GetPhysicsToSoundTransform( idVec3 &origin, idMat3 &axis ) { origin = localLightOrigin + renderLight.lightCenter; axis = localLightAxis * GetPhysics()->GetAxis(); return true; }
/* ================ idLight::Spawn ================ */ void idLight::Spawn( void ) { bool start_off; bool needBroken; const char *demonic_shader; // do the parsing the same way dmap and the editor do gameEdit->ParseSpawnArgsToRenderLight( &spawnArgs, &renderLight ); // we need the origin and axis relative to the physics origin/axis localLightOrigin = ( renderLight.origin - GetPhysics()->GetOrigin() ) * GetPhysics()->GetAxis().Transpose(); localLightAxis = renderLight.axis * GetPhysics()->GetAxis().Transpose(); // set the base color from the shader parms baseColor.Set( renderLight.shaderParms[ SHADERPARM_RED ], renderLight.shaderParms[ SHADERPARM_GREEN ], renderLight.shaderParms[ SHADERPARM_BLUE ] ); // set the number of light levels spawnArgs.GetInt( "levels", "1", levels ); currentLevel = levels; if ( levels <= 0 ) { gameLocal.Error( "Invalid light level set on entity #%d(%s)", entityNumber, name.c_str() ); } // make sure the demonic shader is cached if ( spawnArgs.GetString( "mat_demonic", NULL, &demonic_shader ) ) { declManager->FindType( DECL_MATERIAL, demonic_shader ); } // game specific functionality, not mirrored in // editor or dmap light parsing // also put the light texture on the model, so light flares // can get the current intensity of the light renderEntity.referenceShader = renderLight.shader; lightDefHandle = -1; // no static version yet // see if an optimized shadow volume exists // the renderer will ignore this value after a light has been moved, // but there may still be a chance to get it wrong if the game moves // a light before the first present, and doesn't clear the prelight renderLight.prelightModel = 0; if ( name[ 0 ] ) { // this will return 0 if not found renderLight.prelightModel = renderModelManager->CheckModel( va( "_prelight_%s", name.c_str() ) ); } spawnArgs.GetBool( "start_off", "0", start_off ); if ( start_off ) { Off(); } health = spawnArgs.GetInt( "health", "0" ); spawnArgs.GetString( "broken", "", brokenModel ); spawnArgs.GetBool( "break", "0", breakOnTrigger ); spawnArgs.GetInt( "count", "1", count ); triggercount = 0; fadeFrom.Set( 1, 1, 1, 1 ); fadeTo.Set( 1, 1, 1, 1 ); fadeStart = 0; fadeEnd = 0; // if we have a health make light breakable if ( health ) { idStr model = spawnArgs.GetString( "model" ); // get the visual model if ( !model.Length() ) { gameLocal.Error( "Breakable light without a model set on entity #%d(%s)", entityNumber, name.c_str() ); } fl.takedamage = true; // see if we need to create a broken model name needBroken = true; if ( model.Length() && !brokenModel.Length() ) { int pos; needBroken = false; pos = model.Find( "." ); if ( pos < 0 ) { pos = model.Length(); } if ( pos > 0 ) { model.Left( pos, brokenModel ); } brokenModel += "_broken"; if ( pos > 0 ) { brokenModel += &model[ pos ]; } } // make sure the model gets cached if ( !renderModelManager->CheckModel( brokenModel ) ) { if ( needBroken ) { gameLocal.Error( "Model '%s' not found for entity %d(%s)", brokenModel.c_str(), entityNumber, name.c_str() ); } else { brokenModel = ""; } } GetPhysics()->SetContents( spawnArgs.GetBool( "nonsolid" ) ? 0 : CONTENTS_SOLID ); // make sure the collision model gets cached idClipModel::CheckModel( brokenModel ); } PostEventMS( &EV_PostSpawn, 0 ); // sikk---> Soft Shadows PostProcess // only put lights that cast shadows into the list if ( spawnArgs.GetInt( "noshadows" ) == 0 ) { gameLocal.currentLights.Append( entityNumber ); } // <---sikk UpdateVisuals(); }
/* ================ idTrigger::Enable ================ */ void idTrigger::Enable( void ) { GetPhysics()->SetContents( CONTENTS_TRIGGER ); GetPhysics()->EnableClip(); }
/* ================ idTrigger_Touch::TouchEntities ================ */ void idTrigger_Touch::TouchEntities( void ) { int numClipModels, i; idBounds bounds; idClipModel *cm, *clipModelList[ MAX_GENTITIES ]; // RAVEN BEGIN // abahr: now scriptFunction list if ( clipModel == NULL || !scriptFunctions.Num() ) { // RAVEN END return; } bounds.FromTransformedBounds( clipModel->GetBounds(), GetBindMaster()!=NULL?GetPhysics()->GetOrigin():clipModel->GetOrigin(), GetBindMaster()!=NULL?GetPhysics()->GetAxis():clipModel->GetAxis() ); // RAVEN BEGIN // MCG: filterTeam if ( filterTeam != -1 ) { idActor* actor; // Iterate through the filter team for( actor = aiManager.GetAllyTeam ( (aiTeam_t)filterTeam ); actor; actor = actor->teamNode.Next() ) { // Skip hidden actors and actors that can't be targeted if( actor->fl.notarget || actor->fl.isDormant || ( actor->IsHidden ( ) && !actor->IsInVehicle() ) ) { continue; } if ( !bounds.IntersectsBounds ( actor->GetPhysics()->GetAbsBounds ( ) ) ) { continue; } cm = actor->GetPhysics()->GetClipModel(); if ( !cm || !cm->IsTraceModel() ) { continue; } if ( !gameLocal.ContentsModel( this, cm->GetOrigin(), cm, cm->GetAxis(), -1, clipModel->GetCollisionModel(), GetBindMaster()!=NULL?GetPhysics()->GetOrigin():clipModel->GetOrigin(), GetBindMaster()!=NULL?GetPhysics()->GetAxis():clipModel->GetAxis() ) ) { continue; } ActivateTargets( (idEntity*)actor ); CallScript( (idEntity*)actor ); } return; } // ddynerman: multiple clip worlds numClipModels = gameLocal.ClipModelsTouchingBounds( this, bounds, -1, clipModelList, MAX_GENTITIES ); // RAVEN END for ( i = 0; i < numClipModels; i++ ) { cm = clipModelList[ i ]; if ( !cm->IsTraceModel() ) { continue; } idEntity *entity = cm->GetEntity(); if ( !entity ) { continue; } // RAVEN BEGIN // ddynerman: multiple clip worlds if ( !gameLocal.ContentsModel( this, cm->GetOrigin(), cm, cm->GetAxis(), -1, clipModel->GetCollisionModel(), clipModel->GetOrigin(), clipModel->GetAxis() ) ) { // RAVEN END continue; } ActivateTargets( entity ); // RAVEN BEGIN // abahr: changed to be compatible with new script function utility CallScript( entity ); // RAVEN END } }
/* ================ idExplodingBarrel::Killed ================ */ void idExplodingBarrel::Killed( idEntity *inflictor, idEntity *attacker, int damage, const idVec3 &dir, int location ) { if ( IsHidden() || state == EXPLODING || state == BURNING ) { return; } float f = spawnArgs.GetFloat( "burn" ); if ( f > 0.0f && state == NORMAL ) { state = BURNING; PostEventSec( &EV_Explode, f ); StartSound( "snd_burn", SND_CHANNEL_ANY, 0, false, NULL ); AddParticles( spawnArgs.GetString ( "model_burn", "" ), true ); return; } else { state = EXPLODING; if ( gameLocal.isServer ) { idBitMsg msg; byte msgBuf[MAX_EVENT_PARAM_SIZE]; msg.Init( msgBuf, sizeof( msgBuf ) ); msg.WriteLong( gameLocal.time ); ServerSendEvent( EVENT_EXPLODE, &msg, false, -1 ); } } // do this before applying radius damage so the ent can trace to any damagable ents nearby Hide(); physicsObj.SetContents( 0 ); const char *splash = spawnArgs.GetString( "def_splash_damage", "damage_explosion" ); if ( splash && *splash ) { gameLocal.RadiusDamage( GetPhysics()->GetOrigin(), this, attacker, this, this, splash ); } ExplodingEffects( ); //FIXME: need to precache all the debris stuff here and in the projectiles const idKeyValue *kv = spawnArgs.MatchPrefix( "def_debris" ); // bool first = true; while ( kv ) { const idDict *debris_args = gameLocal.FindEntityDefDict( kv->GetValue(), false ); if ( debris_args ) { idEntity *ent; idVec3 dir; idDebris *debris; //if ( first ) { dir = physicsObj.GetAxis()[1]; // first = false; //} else { dir.x += gameLocal.random.CRandomFloat() * 4.0f; dir.y += gameLocal.random.CRandomFloat() * 4.0f; //dir.z = gameLocal.random.RandomFloat() * 8.0f; //} dir.Normalize(); gameLocal.SpawnEntityDef( *debris_args, &ent, false ); if ( !ent || !ent->IsType( idDebris::Type ) ) { gameLocal.Error( "'projectile_debris' is not an idDebris" ); } debris = static_cast<idDebris *>(ent); debris->Create( this, physicsObj.GetOrigin(), dir.ToMat3() ); debris->Launch(); debris->GetRenderEntity()->shaderParms[ SHADERPARM_TIME_OF_DEATH ] = ( gameLocal.time + 1500 ) * 0.001f; debris->UpdateVisuals(); } kv = spawnArgs.MatchPrefix( "def_debris", kv ); } physicsObj.PutToRest(); CancelEvents( &EV_Explode ); CancelEvents( &EV_Activate ); f = spawnArgs.GetFloat( "respawn" ); if ( f > 0.0f ) { PostEventSec( &EV_Respawn, f ); } else { PostEventMS( &EV_Remove, 5000 ); } if ( spawnArgs.GetBool( "triggerTargets" ) ) { ActivateTargets( this ); } }
/* ================ idTrigger_Timer::Spawn Repeatedly fires its targets. Can be turned on or off by using. ================ */ void idTrigger_Timer::Spawn( void ) { spawnArgs.GetFloat( "random", "1", random ); spawnArgs.GetFloat( "wait", "1", wait ); spawnArgs.GetBool( "start_on", "0", on ); spawnArgs.GetFloat( "delay", "0", delay ); onName = spawnArgs.GetString( "onName" ); offName = spawnArgs.GetString( "offName" ); if ( random >= wait && wait >= 0 ) { random = wait - 0.001; gameLocal.Warning( "idTrigger_Timer '%s' at (%s) has random >= wait", name.c_str(), GetPhysics()->GetOrigin().ToString(0) ); } if ( on ) { PostEventSec( &EV_Timer, delay ); } }
////////////////////////////////////////////////////////////////////////// // NOTE: This function must be thread-safe. Before adding stuff contact MarcoC. void CVehicleMovementHelicopter::ProcessMovement(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); IPhysicalEntity* pPhysics = GetPhysics(); assert(pPhysics); if (m_arcade.m_handling.maxSpeedForward>0.f) // Use the new handling code { CryAutoCriticalSection lk(m_lock); if (!m_isEnginePowered) return; CVehicleMovementBase::ProcessMovement(deltaTime); SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread]; if(m_bApplyNoiseAsVelocity) { physStatus->v -= m_pNoise->m_posDifference; physStatus->w -= m_pNoise->m_angDifference; m_pNoise->Update(deltaTime); } /////////////////////////////////////////////////////////////// // Pass on the movement request to the active physics handler // NB: m_physStatus is update by this call SVehiclePhysicsHelicopterProcessParams params; params.pPhysics = pPhysics; params.pPhysStatus = physStatus; params.pInputAction = &m_inputAction; params.dt = deltaTime; params.haveDriver = (m_actorId!=0)||m_remotePilot; params.isAI = m_movementAction.isAI; params.aiRequiredVel = m_CurrentVel; m_arcade.ProcessMovement(params); // Network error adjustment m_netPosAdjust *= max(0.f, 1.f-deltaTime*k_netErrorPosScale); physStatus->v += m_netPosAdjust * k_netErrorPosScale; if(m_bApplyNoiseAsVelocity) { physStatus->v += m_pNoise->m_posDifference; physStatus->w += m_pNoise->m_angDifference; } //=============================================== // Commit the velocity back to the physics engine //=============================================== // if (fabsf(m_movementAction.rotateYaw)>0.05f || vel.GetLengthSquared()>0.001f || m_chassis.vel.GetLengthSquared()>0.001f || angVel.GetLengthSquared()>0.001f || angVel.GetLengthSquared()>0.001f) { pe_action_set_velocity setVelocity; setVelocity.v = physStatus->v; setVelocity.w = physStatus->w; pPhysics->Action(&setVelocity, 1); } /////////////////////////////////////////////////////////////// } else { if (m_isEnginePowered && pPhysics) { m_movementAction.isAI = true; pe_status_pos psp; pe_status_dynamics psd; if (!pPhysics->GetStatus(&psp) || !pPhysics->GetStatus(&psd)) return; UpdatePhysicsStatus(&m_physStatus[k_physicsThread], &psp, &psd); ProcessAI(deltaTime); } } }
void CVehicleMovementHelicopter::ProcessAI(const float deltaTime) { FUNCTION_PROFILER( GetISystem(), PROFILE_GAME ); CryAutoCriticalSection lk(m_lock); SVehiclePhysicsStatus* physStatus = &m_physStatus[k_physicsThread]; if (m_arcade.m_handling.maxSpeedForward>0.f) // Use the new handling code { //ResetActions(); m_movementAction.Clear(); m_movementAction.isAI = true; SVehiclePhysicsHelicopterProcessAIParams params; params.pPhysStatus = physStatus; params.pInputAction = &m_inputAction; params.pAiRequest = &m_aiRequest; params.dt = deltaTime; params.aiRequiredVel = m_CurrentVel; params.aiCurrentSpeed = m_CurrentSpeed; params.aiYawResponseScalar = m_yawResponseScalar; m_yawResponseScalar = 1.f; // Use helper class to process the AI input // It will return a requested velocity, and change the input m_arcade.ProcessAI(params); // Get the output velocity m_CurrentVel = params.aiRequiredVel; m_CurrentSpeed = params.aiCurrentSpeed; return; } ////////////////////// OLD DEPRECATED CODE :( ////////////////////////////////// m_movementAction.Clear(); ResetActions(); // Our current state const Vec3 worldPos = physStatus->pos; const Matrix33 worldMat( physStatus->q); const Matrix33 localMat( physStatus->q.GetInverted()); const Ang3 worldAngles = Ang3::GetAnglesXYZ(worldMat); const Ang3 localAngles = Ang3::GetAnglesXYZ(localMat); const Vec3 currentVel = physStatus->v; const Vec3 currentVel2D(currentVel.x, currentVel.y, 0.0f); m_CurrentSpeed = m_CurrentVel.len(); //currentVel.len(); float currentSpeed2d = currentVel2D.len(); // +ve direction mean rotation anti-clocwise about the z axis - 0 means along y float currentDir = worldAngles.z; // to avoid singularity const Vec3 vWorldDir = worldMat.GetRow(1); const Vec3 vSideWays = worldMat.GetRow(0); const Vec3 vWorldDir2D = Vec3( vWorldDir.x, vWorldDir.y, 0.0f ).GetNormalizedSafe(); // Our inputs float desiredSpeed = m_aiRequest.HasDesiredSpeed() ? m_aiRequest.GetDesiredSpeed() : 0.0f; Limit(desiredSpeed, -m_maxSpeed, m_maxSpeed); const Vec3 desiredMoveDir = m_aiRequest.HasMoveTarget() ? (m_aiRequest.GetMoveTarget() - worldPos).GetNormalizedSafe() : vWorldDir; Vec3 desiredMoveDir2D = Vec3(desiredMoveDir.x, desiredMoveDir.y, 0.0f); desiredMoveDir2D = desiredMoveDir2D.GetNormalizedSafe(desiredMoveDir2D); const Vec3 desiredVel = desiredMoveDir * desiredSpeed; const Vec3 desiredVel2D(desiredVel.x, desiredVel.y, 0.0f); Vec3 desiredLookDir(desiredMoveDir); if (m_aiRequest.HasDesiredBodyDirectionAtTarget()) { desiredLookDir = m_aiRequest.GetDesiredBodyDirectionAtTarget().GetNormalizedSafe(desiredMoveDir); } else if (m_aiRequest.HasLookTarget()) { desiredLookDir = (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe(desiredMoveDir); } //const Vec3 desiredLookDir = m_aiRequest.HasLookTarget() ? (m_aiRequest.GetLookTarget() - worldPos).GetNormalizedSafe() : desiredMoveDir; const Vec3 desiredLookDir2D = Vec3(desiredLookDir.x, desiredLookDir.y, 0.0f).GetNormalizedSafe(vWorldDir2D); Vec3 prediction = m_aiRequest.HasBodyTarget() ? m_aiRequest.GetBodyTarget() : ZERO; prediction = (prediction.IsEquivalent(ZERO)) ? desiredMoveDir2D : prediction - worldPos; prediction.z = 0.0f; float speedLimit = prediction.GetLength2D(); if(speedLimit > 0.0f) { prediction *= 1.0f / speedLimit; } Vec3 tempDir = currentVel2D.IsEquivalent(ZERO) ? localMat.GetRow(1) : currentVel2D; tempDir.z = 0.0f; tempDir.NormalizeFast(); float dotProd = tempDir.dot(prediction); Limit(dotProd, FLT_EPSILON, 1.0f); float accel = m_enginePowerMax * min(2.0f, 1.0f / dotProd); // * dotProd; if (!m_aiRequest.HasDesiredBodyDirectionAtTarget()) { dotProd *= dotProd; dotProd *= dotProd; float tempf = min(max(speedLimit * speedLimit, 2.0f), m_maxSpeed * dotProd); Limit(desiredSpeed, -tempf, tempf); } else if (dotProd < 0.0125f) { Limit(desiredSpeed, -m_maxSpeed * 0.25f, m_maxSpeed * 0.25f); } float posNeg = (float)__fsel(desiredSpeed - m_CurrentSpeed, 1.0f, -5.0f); if (desiredVel2D.GetLengthSquared() > FLT_EPSILON) { m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime; } else { m_CurrentSpeed = m_CurrentSpeed + posNeg * accel * deltaTime; } if (posNeg > 0.0f && m_CurrentSpeed > desiredSpeed) { m_CurrentSpeed = desiredSpeed; } else if (posNeg < 0.0f && m_CurrentSpeed < desiredSpeed) { m_CurrentSpeed = desiredSpeed; } // ---------------------------- Rotation ---------------------------- float desiredDir = (desiredLookDir2D.GetLengthSquared() > 0.0f) ? atan2f(-desiredLookDir2D.x, desiredLookDir2D.y) : atan2f(-vWorldDir2D.x, vWorldDir2D.y); while (currentDir < desiredDir - gf_PI) currentDir += 2.0f * gf_PI; while (currentDir > desiredDir + gf_PI) currentDir -= 2.0f * gf_PI; // ---------------------------- Yaw ---------------------------- Ang3 dirDiff(0.0f, 0.0f, desiredDir - currentDir); dirDiff.RangePI(); float absDiff = fabsf(dirDiff.z); float rotSpeed = (float)__fsel(dirDiff.z, m_yawPerRoll, -m_yawPerRoll); m_actionYaw = m_actionYaw + deltaTime * (rotSpeed - m_actionYaw); float temp = fabsf(m_actionYaw); float multiplier = ((absDiff / (temp + 0.001f)) + 1.0f) * 0.5f; m_actionYaw *= (float)__fsel(absDiff - temp, 1.0f, multiplier); // ---------------------------- Yaw ------------------------------ m_CurrentVel = desiredMoveDir * m_CurrentSpeed; // ---------------------------- Pitch ---------------------------- if (m_CurrentVel.GetLengthSquared2D() > 0.1f) { CalculatePitch(worldAngles, desiredMoveDir, currentSpeed2d, desiredSpeed, deltaTime); } else { Quat rot; rot.SetRotationVDir(desiredLookDir, 0.0f); float desiredXRot = Ang3::GetAnglesXYZ(rot).x + m_steeringDamage.x; m_actionPitch = worldAngles.x + (desiredXRot - worldAngles.x) * deltaTime/* * 10.0f*/; Limit(m_actionPitch, -m_maxPitchAngle * 2.0f, m_maxPitchAngle * 2.0f); } // ---------------------------- Roll ---------------------------- float rollSpeed = GetRollSpeed(); rollSpeed *= deltaTime; rollSpeed = (float)__fsel(absDiff - rollSpeed, rollSpeed, absDiff); float roll =(float) __fsel(dirDiff.z, -rollSpeed, rollSpeed); float speedPerUnit = 1.5f; float desiredRollSpeed = absDiff * speedPerUnit * (float)__fsel(dirDiff.z, 1.0f, -1.0f); desiredRollSpeed = -m_actionYaw * 2.5f; desiredRollSpeed += m_steeringDamage.y; m_actionRoll = m_actionRoll + deltaTime * (desiredRollSpeed - m_actionRoll); Limit(m_actionRoll, -m_maxRollAngle + m_steeringDamage.y, m_maxRollAngle - m_steeringDamage.y); m_actionRoll *= m_rollDamping; // ---------------------------- Roll ---------------------------- // ---------------------------- Convert and apply ---------------------------- Ang3 angles(m_actionPitch, m_actionRoll, worldAngles.z + deltaTime * m_actionYaw); pe_params_pos paramPos; paramPos.q.SetRotationXYZ(angles); paramPos.q.Normalize(); IPhysicalEntity * pPhysicalEntity = GetPhysics(); pPhysicalEntity->SetParams(¶mPos, 1); pe_action_set_velocity vel; vel.v = m_CurrentVel + m_netPosAdjust; pPhysicalEntity->Action(&vel, 1); // ---------------------------- Convert and apply ---------------------------- m_rpmScale = max(0.2f, cry_fabsf(m_CurrentSpeed / m_maxSpeed)); }
//------------------------------------------------------------------------ void CVehicleMovementHelicopter::OnEvent(EVehicleMovementEvent event, const SVehicleMovementEventParams& params) { switch (event) { case eVME_Repair: { if(params.fValue < 0.25) { m_damageActual = 0.0f; m_damage = 0.0f; } } break; case eVME_Collision: { if (0) { m_isEnginePowered = false; pe_simulation_params simParams; simParams.dampingFreefall = 0.01f; simParams.gravity = Vec3(0.0f, 0.0f, -9.8f); GetPhysics()->SetParams(&simParams); } } break; case eVME_GroundCollision: { const float stopOver = 1.0f; } break; case eVME_Damage: { if (!m_pVehicle->IsIndestructable()) { const float stopOver = 1.0f; m_damage = params.fValue; if (m_damage > 0.95f) { m_isEngineDisabled = true; m_isEnginePowered = false; StopExhaust(); StopSounds(); IPhysicalEntity * pPhysicalEntity = GetPhysics(); pe_action_impulse impulse; impulse.angImpulse = Vec3(0.1f, 100.f, 0.0f); pPhysicalEntity->Action(&impulse); pe_simulation_params simParams; simParams.dampingFreefall = 0.01f; simParams.gravity = Vec3(0.0f, 0.0f, -9.8f); pPhysicalEntity->SetParams(&simParams); SVehicleEventParams eventParams; eventParams.entityId = 0; m_pVehicle->BroadcastVehicleEvent(eVE_Destroyed, eventParams); if (m_pVehicle) { if (IEntity *entity = m_pVehicle->GetEntity()) { if (IAIObject *aiobject = entity->GetAI()) { aiobject->Event(AIEVENT_DISABLE, NULL); } } } } } } break; case eVME_WarmUpEngine: m_enginePower = m_enginePowerMax; break; //case eVME_Turbulence: // m_turbulence = max(m_turbulence, params.fValue); // break; default: CVehicleMovementBase::OnEvent(event, params); break; } }
/* ================= rvEffect::WriteToSnapshot ================= */ void rvEffect::WriteToSnapshot( idBitMsgDelta &msg ) const { GetPhysics()->WriteToSnapshot( msg ); WriteBindToSnapshot( msg ); idGameLocal::WriteDecl( msg, effect ); msg.WriteBits( loop, 1 ); }
/* ================ sdDeliveryVehicle::Jotun_DoMove ================ */ void sdDeliveryVehicle::Jotun_DoMove( const idVec3& aheadPointIdeal, const idVec3& aheadPointDirIdeal, const idVec3& endPoint, bool levelOut, bool leaving, float pathSpeed ) { float frameTime = MS2SEC( gameLocal.msec ); idVec3 aheadPoint = aheadPointIdeal; idVec3 aheadPointDir = aheadPointDirIdeal; const idVec3& origin = GetPhysics()->GetOrigin(); const idVec3& velocity = GetPhysics()->GetLinearVelocity(); const idMat3& axis = GetPhysics()->GetAxis(); const idAngles angles = axis.ToAngles(); const idVec3& angVel = GetPhysics()->GetAngularVelocity(); const idVec3& currentFwd = axis[ 0 ]; const idVec3& currentRight = axis[ 1 ]; const idVec3& currentUp = axis[ 2 ]; float rollVel = angVel * currentFwd; float pitchVel = angVel * currentRight; float yawVel = angVel * currentUp; float aheadToEnd = ( aheadPoint - endPoint ).Length(); if ( aheadToEnd < 4096.0f && !leaving ) { aheadPoint.z += 4096.0f; } float currentHeight = JOTUN_FLY_HEIGHT_RESCUE; // check out ahead and see that we're not going to collide with something if ( velocity != vec3_origin ) { idVec3 futureSpot = velocity * 1.0f; futureSpot.z -= 4096.0f; futureSpot.Normalize();; futureSpot *= 3500.0f; futureSpot += origin; trace_t trace; gameLocal.clip.TraceBounds( CLIP_DEBUG_PARMS trace, origin, futureSpot, GetPhysics()->GetBounds(), axis, MASK_SOLID | MASK_OPAQUE, this ); futureSpot = trace.endpos; float futureFrac = trace.fraction; float futureDist = futureFrac * 3500.0f; if ( futureDist < 3500.0f ) { int surfaceFlags = trace.c.material != NULL ? trace.c.material->GetSurfaceFlags() : 0; if ( !( surfaceFlags & SURF_NOIMPACT ) ) { float moveUp = ( 3500.0f - futureDist ) / 3500.0f; moveUp = idMath::Sqrt( moveUp ); if ( aheadToEnd < 32.0f || leaving ) { aheadPoint = origin + currentFwd * 3500.0f; aheadPoint.z += moveUp * 4096.0f; aheadPointDir.z += moveUp * 10.0f; } aheadPoint.z += moveUp * 4096.0f; aheadPointDir.z += moveUp * 2.0f; aheadPointDir.Normalize(); } else { futureDist = 3500.0f; } } currentHeight = futureDist; // gameRenderWorld->DebugCircle( colorRed, origin, idVec3( 0.0f, 0.0f, 1.0f ), 16, 8 ); // gameRenderWorld->DebugArrow( colorRed, origin, futureSpot, 256 ); // gameRenderWorld->DebugCircle( colorRed, futureSpot, idVec3( 0.0f, 0.0f, 1.0f ), 16, 8 ); } // gameRenderWorld->DebugCircle( colorGreen, aheadPoint, idVec3( 0.0f, 0.0f, 1.0f ), 256, 16 ); // generate a cubic spline between the two points idVec3 point = vec3_origin; { idVec3 x0 = origin; idVec3 x1 = aheadPoint; idVec3 dx0 = velocity * 3.0f; // maintaining our current velocity is more important idVec3 dx1 = aheadPointDir * pathSpeed * 1.0f; // than matching the destination vector // calculate coefficients idVec3 D = x0; idVec3 C = dx0; idVec3 B = 3*x1 - dx1 - 2*C - 3*D; idVec3 A = x1 - B - C - D; float distanceLeft = ( endPoint - origin ).Length(); float lookaheadFactor = ( distanceLeft / 4096.0f ) * 0.5f; lookaheadFactor = idMath::ClampFloat( 0.2f, 0.5f, lookaheadFactor ); point = ( A * lookaheadFactor + B )*lookaheadFactor*lookaheadFactor + C*lookaheadFactor + D; } idVec3 idealNewForward = point - origin; idealNewForward.Normalize(); idVec3 delta = point - origin; idVec3 endDelta = endPoint - origin; endDelta.Normalize(); endDelta.z = 0.0f; idAngles endAngles = endDelta.ToAngles().Normalize180(); // treat the local delta as if the thing is on a flat plane - simplifies everything idVec3 localDelta = axis.TransposeMultiply( delta ); idVec3 newVelocity = vec3_origin; idVec3 newAngVel = angVel; // // A flying vehicle needs to roll and then pull up to turn (to look cool) // // // Roll! float targetRoll = endAngles.roll; if ( !levelOut ) { targetRoll = -( localDelta.y / 1024.0f ) * 45.0f; targetRoll = idMath::ClampFloat( -30.0f, 30.0f, targetRoll ); } float rollAmount = idMath::AngleNormalize180( targetRoll - angles.roll ); // so we know how much we need to roll to get to our new angle // how fast do we want to go to get there? float targetRollVel = ( rollAmount / 15 ) * 30; targetRollVel = idMath::ClampFloat( -30.0f, 30.0f, targetRollVel ); float maxRollAccel = 15.0f; if ( levelOut ) { maxRollAccel = 35.0f; } // now figure out what roll acceleration that needs, clamp it float rollAccel = idMath::AngleNormalize180( targetRollVel - rollVel ) / frameTime; rollAccel = idMath::ClampFloat( -maxRollAccel, maxRollAccel, rollAccel ); // dampen out the rolling inputs, like its a guy on a stick controlling it rollAccel = rollAccel * 0.2f + lastRollAccel * 0.8f; if ( idMath::Fabs( rollAccel ) < idMath::FLT_EPSILON ) { rollAccel = 0.f; } newAngVel += rollAccel * frameTime * currentFwd; lastRollAccel = rollAccel; // // Pull up! float targetPitch = -( localDelta.z / 256.0f ) * 15.0f; if ( !leaving ) { targetPitch = idMath::ClampFloat( -25.0f, 15.0f, targetPitch ); } else { targetPitch = idMath::ClampFloat( -25.0f, 15.0f, targetPitch ); } if ( leaving && targetPitch > -15.0f ) { targetPitch = -15.0f; } float pitchAmount = idMath::AngleNormalize180( targetPitch - angles.pitch ); // so we know how much we need to pitch to get to our new angle // how fast do we want to go to get there? float targetPitchVel = ( pitchAmount / 8 ) * 15; if ( !leaving ) { targetPitchVel = idMath::ClampFloat( -25.0f, 15.0f, targetPitchVel ); } else { targetPitchVel = idMath::ClampFloat( -35.0f, 15.0f, targetPitchVel ); } // now figure out what roll acceleration that needs, clamp it float pitchAccel = idMath::AngleNormalize180( targetPitchVel - pitchVel ) / frameTime; if ( !leaving ) { pitchAccel = idMath::ClampFloat( -12.0f, 12.0f, pitchAccel ); } else { pitchAccel = idMath::ClampFloat( -36.0f, 12.0f, pitchAccel ); } newAngVel += pitchAccel * frameTime * currentRight; // // Yaw float targetYaw = angles.yaw; if ( !levelOut ) { targetRoll = -( localDelta.y / 1024.0f ) * 5.0f; targetRoll = idMath::ClampFloat( -8.0f, 8.0f, targetRoll ); } else { targetYaw = endAngles.yaw; } float yawAmount = idMath::AngleNormalize180( targetYaw - angles.yaw ); // so we know how much we need to yaw to get to our new angle // how fast do we want to go to get there? float targetYawVel = ( yawAmount / 8 ) * 15; targetYawVel = idMath::ClampFloat( -15.0f, 15.0f, targetYawVel ); // now figure out what yaw acceleration that needs, clamp it float yawAccel = idMath::AngleNormalize180( targetYawVel - yawVel ) / frameTime; yawAccel = idMath::ClampFloat( -10.0f, 10.0f, yawAccel ); newAngVel += yawAccel * frameTime * currentUp; newVelocity = currentFwd * pathSpeed; if ( levelOut ) { // HACK: Drift back towards the target, to try to ensure it gets there ok newVelocity = newVelocity * 0.7f + endDelta * pathSpeed * 0.3f; } // HACK: ensure it never gets below the minimum height if ( currentHeight < JOTUN_FLY_HEIGHT_MIN ) { idVec3 newOrigin = origin; newOrigin.z = newOrigin.z - currentHeight + JOTUN_FLY_HEIGHT_MIN; GetPhysics()->SetOrigin( newOrigin ); } else if ( currentHeight < JOTUN_FLY_HEIGHT_RESCUE ) { float oldNewVelLength = newVelocity.Length(); float scale = ( JOTUN_FLY_HEIGHT_RESCUE - currentHeight ) / ( JOTUN_FLY_HEIGHT_RESCUE - JOTUN_FLY_HEIGHT_MIN ); scale = idMath::Sqrt( scale ); float rescueVelocity = scale * ( JOTUN_FLY_HEIGHT_RESCUE - JOTUN_FLY_HEIGHT_MIN ) / 0.5f; float rescueAcceleration = ( rescueVelocity - velocity.z ) / frameTime; rescueAcceleration = idMath::ClampFloat( 0.0f, 1800.0f, rescueAcceleration ); rescueVelocity = velocity.z + rescueAcceleration * frameTime; if ( rescueVelocity > newVelocity.z ) { newVelocity.z = rescueVelocity; } newVelocity.Normalize(); newVelocity *= oldNewVelLength; } // // set the new stuff // GetPhysics()->SetLinearVelocity( newVelocity ); GetPhysics()->SetAngularVelocity( newAngVel ); }
/* ================ idTrigger::Disable ================ */ void idTrigger::Disable( void ) { // we may be relinked if we're bound to another object, so clear the contents as well GetPhysics()->SetContents( 0 ); GetPhysics()->DisableClip(); }
/* ================ sdDeliveryVehicle::Magog_DoMove ================ */ void sdDeliveryVehicle::Magog_DoMove( const idVec3& aheadPointIdeal, const idVec3& aheadPointDir, const idVec3& endPoint, float itemRotation, float maxYawScale, bool orientToEnd, bool clampRoll, bool slowNearEnd, float pathSpeed ) { float frameTime = MS2SEC( gameLocal.msec ); idVec3 aheadPoint = aheadPointIdeal; const idVec3& origin = GetPhysics()->GetOrigin(); const idVec3& velocity = GetPhysics()->GetLinearVelocity(); const idMat3& axis = GetPhysics()->GetAxis(); const idAngles angles = axis.ToAngles(); const idVec3& angVel = GetPhysics()->GetAngularVelocity(); const idVec3& currentFwd = axis[ 0 ]; const idVec3& currentRight = axis[ 1 ]; const idVec3& currentUp = axis[ 2 ]; float rollVel = angVel * currentFwd; float pitchVel = angVel * currentRight; float yawVel = angVel * currentUp; // find the current height of the vehicle idVec3 futureContribution = velocity * 1.0f; futureContribution.z = 0.0f; float futureContributionLength = futureContribution.Length(); if ( futureContributionLength > 2000.0f ) { futureContribution = futureContribution * ( 2000.0f / futureContributionLength ); } idVec3 futureSpot = origin + futureContribution; futureSpot.z -= HOVER_DOWNCAST_LENGTH; trace_t trace; gameLocal.clip.TraceBounds( CLIP_DEBUG_PARMS trace, origin, futureSpot, GetPhysics()->GetBounds(), axis, MASK_SOLID | MASK_OPAQUE, this ); futureSpot = trace.endpos; // shift the ahead point based on the trace float currentHeight = origin.z - futureSpot.z; if ( currentHeight < HOVER_DOWNCAST_LENGTH ) { aheadPoint.z = origin.z - currentHeight + HOVER_HEIGHT_AIM; } else { aheadPoint.z = origin.z - HOVER_DOWNCAST_LENGTH + HOVER_HEIGHT_AIM; } // sys.debugCircle( g_colorRed, origin, '0 0 1', 16, 8, 0 ); // sys.debugArrow( g_colorRed, origin, futureSpot, 256, 0 ); // sys.debugCircle( g_colorRed, futureSpot, '0 0 1', 16, 8, 0 ); // sys.debugCircle( '0 1 0', aheadPoint, '0 0 1', 256.0f, 16, 0 ); idVec3 point; float lookaheadFactor; { // generate a cubic spline between the two points idVec3 x0 = origin; idVec3 x1 = aheadPoint; idVec3 dx0 = velocity * 3.0f; // maintaining our current velocity is more important idVec3 dx1 = aheadPointDir * pathSpeed * 1.0f; // than matching the destination vector // calculate coefficients idVec3 D = x0; idVec3 C = dx0; idVec3 B = 3*x1 - dx1 - 2*C - 3*D; idVec3 A = x1 - B - C - D; float distanceLeft = ( endPoint - origin ).Length(); lookaheadFactor = ( distanceLeft / 6096.0f ) * 0.5f; lookaheadFactor = idMath::ClampFloat( 0.2f, 0.5f, lookaheadFactor ); if ( !slowNearEnd ) { lookaheadFactor = 0.5f; } point = ( A * lookaheadFactor + B )*lookaheadFactor*lookaheadFactor + C*lookaheadFactor + D; } // // Follower logic // idVec3 delta = point - origin; idVec3 aheadDelta = aheadPoint - origin; idVec3 newVelocity = vec3_origin; // // Z axis // // figure out what Z velocity is needed to get where we want to go within a frame float Zvel = aheadDelta.z / frameTime; Zvel = idMath::ClampFloat( -maxZVel, maxZVel, Zvel ); // figure out what Z acceleration is neccessary float ZAccel = ( Zvel - velocity.z ) / frameTime; ZAccel = idMath::ClampFloat( -maxZAccel, maxZAccel, ZAccel ); // chop the Z acceleration when its nearing the end - helps to avoid settling issues if ( lookaheadFactor < 0.5f ) { ZAccel *= idMath::Sqrt( lookaheadFactor * 2.0f ); } Zvel = velocity.z + ZAccel * frameTime; // rapidly prevent acceleration downwards when its below the target if ( aheadDelta.z > 0.0f && Zvel < 0.0f ) { Zvel *= 0.9f; } // // X & Y // // ignore Z delta.z = 0.0f; aheadDelta.z = 0.0f; idVec3 flatVelocity = velocity; flatVelocity.z = 0.0f; float distance = delta.Length(); idVec3 direction; if ( distance > idMath::FLT_EPSILON ) { direction = delta / distance; } else { direction = vec3_origin; } // figure out how fast it needs to go to get there in time float vel = distance / 0.5f; vel = idMath::ClampFloat( -pathSpeed, pathSpeed, vel ); idVec3 vecVel = vel * direction; // figure out what acceleration is neccessary idVec3 velDelta = vecVel - flatVelocity; idVec3 velDeltaDir = velDelta; float velDeltaLength = velDeltaDir.Normalize(); float accel = velDeltaLength / frameTime; accel = idMath::ClampFloat( -600.0f, 600.0f, accel ); idVec3 vecAccel = accel * frameTime * velDeltaDir; newVelocity = flatVelocity + vecAccel; newVelocity.z = Zvel; // // Angles // idVec3 velDir = velocity; float velLength = velDir.Normalize(); // calculate what acceleration we are undergoing idVec3 velAccel = ( newVelocity - velocity ) / frameTime; // calculate a component due to air resistance float speed = InchesToMetres( velLength ); float rho = 1.2f; float sideArea = InchesToMetres( 650.0f ) * InchesToMetres( 650.0f ); float Cd = 0.6f; float dragForceMagnitude = MetresToInches( 0.5 * Cd * sideArea * rho * speed * speed ); // assume mass is 10,000 -> I know this works nicely idVec3 dragAccel = ( dragForceMagnitude / 10000.f ) * velDir; idVec3 desiredAccel = velAccel + dragAccel; desiredAccel *= 0.4f; desiredAccel.z += MetresToInches( 9.8f ); // ok, so we desire to be looking at the target idVec3 forwards = endPoint - origin; forwards.z = 0.0f; forwards.Normalize(); if ( orientToEnd ) { idAngles targetAngles = ang_zero; targetAngles.yaw = idMath::AngleNormalize180( itemRotation ); forwards = targetAngles.ToForward(); } // figure out the axes corresponding to this orientation idVec3 up = desiredAccel; up.Normalize(); idVec3 right = up.Cross( forwards ); right.Normalize(); forwards = right.Cross( up ); forwards.Normalize(); // convert that to an angles idAngles desiredAngles = ( idMat3( forwards, right, up ) ).ToAngles(); if ( clampRoll ) { desiredAngles.roll = idMath::ClampFloat( -9.0f, 9.0f, desiredAngles.roll ); } else { desiredAngles.roll = idMath::ClampFloat( -30.0f, 30.0f, desiredAngles.roll ); } desiredAngles.pitch = idMath::ClampFloat( -30.0f, 30.0f, desiredAngles.pitch ); // find the diff between that and what we currently have idAngles diffAngles = ( desiredAngles - angles ).Normalize180(); diffAngles = diffAngles * 0.1f; diffAngles = diffAngles / frameTime; diffAngles *= 0.1f; // translate the old angular velocity back to an angle diff style value idAngles oldDiffAngles; oldDiffAngles.pitch = angVel * currentRight; oldDiffAngles.yaw = angVel * currentUp; oldDiffAngles.roll = angVel * currentFwd; // blend the old and the new to soften the quick changes diffAngles = oldDiffAngles * 0.9f + diffAngles * 0.1f; // figure out how much we're trying to change by in a single frame idAngles angleAccel = diffAngles - oldDiffAngles; float maxAngleAccel = 45.0f * frameTime; float maxYawAccel = maxAngleAccel * maxYawScale; angleAccel.pitch = idMath::ClampFloat( -maxAngleAccel, maxAngleAccel, angleAccel.pitch ); angleAccel.yaw = idMath::ClampFloat( -maxYawAccel, maxYawAccel, angleAccel.yaw ); angleAccel.roll = idMath::ClampFloat( -maxAngleAccel, maxAngleAccel, angleAccel.roll ); diffAngles = oldDiffAngles + angleAccel; idVec3 newAngVel = diffAngles.pitch * currentRight + diffAngles.yaw * currentUp + diffAngles.roll * currentFwd; // HACK: ensure it never gets below the minimum height if ( currentHeight < HOVER_HEIGHT_MIN ) { idVec3 newOrigin = origin; newOrigin.z = origin.z - currentHeight + HOVER_HEIGHT_MIN; GetPhysics()->SetOrigin( newOrigin ); } else if ( currentHeight < HOVER_HEIGHT_RESCUE ) { float oldNewVelLength = newVelocity.Length(); float scale = ( HOVER_HEIGHT_RESCUE - currentHeight ) / ( HOVER_HEIGHT_RESCUE - HOVER_HEIGHT_MIN ); scale = idMath::Sqrt( scale ); float rescueVelocity = scale * ( HOVER_HEIGHT_RESCUE - HOVER_HEIGHT_MIN ) / 0.5f; float rescueAcceleration = ( rescueVelocity - velocity.z ) / frameTime; rescueAcceleration = idMath::ClampFloat( 0.0f, 1800.0f, rescueAcceleration ); rescueVelocity = velocity.z + rescueAcceleration * frameTime; if ( rescueVelocity > newVelocity.z ) { newVelocity.z = rescueVelocity; } newVelocity.Normalize(); newVelocity *= oldNewVelLength; } GetPhysics()->SetLinearVelocity( newVelocity ); GetPhysics()->SetAxis( angles.ToMat3() ); GetPhysics()->SetAngularVelocity( newAngVel ); }
/* ================ idMoveable::Spawn ================ */ void idMoveable::Spawn( void ) { idTraceModel trm; float density, friction, bouncyness, mass; int clipShrink; idStr clipModelName; // check if a clip model is set spawnArgs.GetString( "clipmodel", "", clipModelName ); if ( !clipModelName[0] ) { clipModelName = spawnArgs.GetString( "model" ); // use the visual model } if ( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) { gameLocal.Error( "idMoveable '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() ); return; } // if the model should be shrinked clipShrink = spawnArgs.GetInt( "clipshrink" ); if ( clipShrink != 0 ) { trm.Shrink( clipShrink * CM_CLIP_EPSILON ); } // get rigid body properties spawnArgs.GetFloat( "density", "0.5", density ); density = idMath::ClampFloat( 0.001f, 1000.0f, density ); spawnArgs.GetFloat( "friction", "0.05", friction ); friction = idMath::ClampFloat( 0.0f, 1.0f, friction ); spawnArgs.GetFloat( "bouncyness", "0.6", bouncyness ); bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness ); explode = spawnArgs.GetBool( "explode" ); unbindOnDeath = spawnArgs.GetBool( "unbindondeath" ); fxCollide = spawnArgs.GetString( "fx_collide" ); nextCollideFxTime = 0; fl.takedamage = true; damage = spawnArgs.GetString( "def_damage", "" ); canDamage = spawnArgs.GetBool( "damageWhenActive" ) ? false : true; minDamageVelocity = spawnArgs.GetFloat( "minDamageVelocity", "100" ); maxDamageVelocity = spawnArgs.GetFloat( "maxDamageVelocity", "200" ); nextDamageTime = 0; nextSoundTime = 0; health = spawnArgs.GetInt( "health", "0" ); spawnArgs.GetString( "broken", "", brokenModel ); if ( health ) { if ( brokenModel != "" && !renderModelManager->CheckModel( brokenModel ) ) { gameLocal.Error( "idMoveable '%s' at (%s): cannot load broken model '%s'", name.c_str(), GetPhysics()->GetOrigin().ToString(0), brokenModel.c_str() ); } } // setup the physics physicsObj.SetSelf( this ); physicsObj.SetClipModel( new idClipModel( trm ), density ); physicsObj.GetClipModel()->SetMaterial( GetRenderModelMaterial() ); physicsObj.SetOrigin( GetPhysics()->GetOrigin() ); physicsObj.SetAxis( GetPhysics()->GetAxis() ); physicsObj.SetBouncyness( bouncyness ); physicsObj.SetFriction( 0.6f, 0.6f, friction ); physicsObj.SetGravity( gameLocal.GetGravity() ); physicsObj.SetContents( CONTENTS_SOLID ); physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP ); SetPhysics( &physicsObj ); if ( spawnArgs.GetFloat( "mass", "10", mass ) ) { physicsObj.SetMass( mass ); } if ( spawnArgs.GetBool( "nodrop" ) ) { physicsObj.PutToRest(); } else { physicsObj.DropToFloor(); } if ( spawnArgs.GetBool( "noimpact" ) || spawnArgs.GetBool( "notPushable" ) ) { physicsObj.DisableImpact(); } if ( spawnArgs.GetBool( "nonsolid" ) ) { BecomeNonSolid(); } allowStep = spawnArgs.GetBool( "allowStep", "1" ); PostEventMS( &EV_SetOwnerFromSpawnArgs, 0 ); }