/* ================ 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 ); }
/* ================ idMoveable::Event_BecomeNonSolid ================ */ void idMoveable::Event_BecomeNonSolid( void ) { BecomeNonSolid(); }
/* ================ idMoveable::Spawn ================ */ void idMoveable::Spawn( void ) { idTraceModel trm; float density, friction, bouncyness, mass, air_friction_linear, air_friction_angular; int clipShrink; idStr clipModelName; idVec3 maxForce, maxTorque; // check if a clip model is set spawnArgs.GetString( "clipmodel", "", clipModelName ); if( !clipModelName[0] ) { clipModelName = spawnArgs.GetString( "model" ); // use the visual model } // tels: support "model" "" with "noclipmodel" "0" - do not attempt to load // the clipmodel from the non-existing model name in this case: if( clipModelName.Length() ) { if( !collisionModelManager->TrmFromModel( clipModelName, trm ) ) { gameLocal.Error( "idMoveable '%s': cannot load collision model %s", name.c_str(), clipModelName.c_str() ); return; } // angua: check if the cm is valid if( idMath::Fabs( trm.bounds[0].x ) == idMath::INFINITY ) { gameLocal.Error( "idMoveable '%s': invalid collision model %s", name.c_str(), clipModelName.c_str() ); } // if the model should be shrunk 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( "bouncyness", "0.6", bouncyness ); bouncyness = idMath::ClampFloat( 0.0f, 1.0f, bouncyness ); explode = spawnArgs.GetBool( "explode" ); unbindOnDeath = spawnArgs.GetBool( "unbindondeath" ); spawnArgs.GetFloat( "friction", "0.05", friction ); // reverse compatibility, new contact_friction key replaces friction only if present if( spawnArgs.FindKey( "contact_friction" ) ) { spawnArgs.GetFloat( "contact_friction", "0.05", friction ); } spawnArgs.GetFloat( "linear_friction", "0.6", air_friction_linear ); spawnArgs.GetFloat( "angular_friction", "0.6", air_friction_angular ); fxCollide = spawnArgs.GetString( "fx_collide" ); nextCollideFxTime = 0; // tels: m_scriptCollide = spawnArgs.GetString( "script_collide" ); m_nextCollideScriptTime = 0; m_collideScriptCounter = spawnArgs.GetInt( "collide_script_counter", "1" ); // override the default of 1 with 0 if no script is defined if( m_scriptCollide == "" ) { m_collideScriptCounter = 0; } m_minScriptVelocity = spawnArgs.GetFloat( "min_script_velocity", "5.0" ); damage = spawnArgs.GetString( "def_damage", "" ); canDamage = spawnArgs.GetBool( "damageWhenActive" ) ? false : true; minDamageVelocity = spawnArgs.GetFloat( "minDamageVelocity", "-1" ); if( minDamageVelocity == -1 ) { // grayman #2816 minDamageVelocity = MIN_DAMAGE_VELOCITY; } maxDamageVelocity = spawnArgs.GetFloat( "maxDamageVelocity", "-1" ); if( maxDamageVelocity == -1 ) { // grayman #2816 maxDamageVelocity = MAX_DAMAGE_VELOCITY; } nextDamageTime = 0; nextSoundTime = 0; health = spawnArgs.GetInt( "health", "0" ); // tels: load a visual model, as well as an optional brokenModel LoadModels(); // 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( air_friction_linear, air_friction_angular, friction ); physicsObj.SetGravity( gameLocal.GetGravity() ); int contents = CONTENTS_SOLID | CONTENTS_OPAQUE; // ishtvan: overwrite with custom contents, if present if( m_CustomContents != -1 ) { contents = m_CustomContents; } // greebo: Set the frobable contents flag if the spawnarg says so if( spawnArgs.GetBool( "frobable", "0" ) ) { contents |= CONTENTS_FROBABLE; } physicsObj.SetContents( contents ); physicsObj.SetClipMask( MASK_SOLID | CONTENTS_BODY | CONTENTS_CORPSE | CONTENTS_MOVEABLECLIP ); SetPhysics( &physicsObj ); if( spawnArgs.GetFloat( "mass", "10", mass ) ) { physicsObj.SetMass( mass ); } // tels if( spawnArgs.GetVector( "max_force", "", maxForce ) ) { physicsObj.SetMaxForce( maxForce ); } if( spawnArgs.GetVector( "max_torque", "", maxTorque ) ) { physicsObj.SetMaxTorque( maxTorque ); } if( spawnArgs.GetBool( "nodrop" ) ) { physicsObj.PutToRest(); } else { physicsObj.DropToFloor(); } if( spawnArgs.GetBool( "noimpact" ) || spawnArgs.GetBool( "notpushable" ) ) { physicsObj.DisableImpact(); } if( !spawnArgs.GetBool( "solid" ) ) { BecomeNonSolid(); } // SR CONTENTS_RESPONSE FIX if( m_StimResponseColl->HasResponse() ) { physicsObj.SetContents( physicsObj.GetContents() | CONTENTS_RESPONSE ); } m_preHideContents = physicsObj.GetContents(); m_preHideClipMask = physicsObj.GetClipMask(); allowStep = spawnArgs.GetBool( "allowStep", "1" ); // parse LOD spawnargs if( ParseLODSpawnargs( &spawnArgs, gameLocal.random.RandomFloat() ) ) { // Have to start thinking if we're distance dependent BecomeActive( TH_THINK ); } // grayman #2820 - don't queue EV_SetOwnerFromSpawnArgs if it's going to // end up doing nothing. Queuing this for every moveable causes a lot // of event posting during frame 0. If extra work is added to // EV_SetOwnerFromSpawnArgs, then that must be accounted for here, to // make sure it has a chance of getting done. idStr owner; if( spawnArgs.GetString( "owner", "", owner ) ) { PostEventMS( &EV_SetOwnerFromSpawnArgs, 0 ); } }
bool ResolveMovementBlockTask::PerformBlockingAI(idAI* owner) { if (owner->AI_MOVE_DONE && !owner->movementSubsystem->IsWaiting()) // grayman #2345 - if already waiting, no need to do this section { idVec3 ownerRight, ownerForward; _initialAngles.ToVectors(&ownerForward, &ownerRight); owner->StopMove(MOVE_STATUS_WAITING); owner->TurnToward(owner->GetPhysics()->GetOrigin() - ownerRight); if (owner->FacingIdeal() && _preTaskContents == -1) { // grayman #2345 - don't become non-solid if your alert index is > ERelaxed. This is because // AI tend to bunch together when agitated, and it doesn't look good if one goes non-solid // and the others repeatedly walk through it. // If there's no room to get around you, become non-solid if ((owner->AI_AlertIndex == ERelaxed) && !Room2Pass(owner)) { BecomeNonSolid(owner); } else { bool solid = true; owner->movementSubsystem->SetWaiting(solid); } } } if (owner->movementSubsystem->IsWaiting()) // grayman #2345 { // We are waiting for the other AI to pass by idVec3 dist = _blockingEnt->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin(); if (dist.LengthSqr() > Square(60)) { // other AI has passed by, end the task return true; } if (_blockingEnt->IsType(idAI::Type)) { // grayman #2345 - check to see if the other AI is standing still. // If they are, end the task. idAI *_blockingEntAI = static_cast<idAI*>(_blockingEnt); if (_blockingEntAI && !_blockingEntAI->AI_FORWARD) { return true; // end the task } // If we're EWaitingSolid, change to EWaitingNonSolid if the other AI is barely moving. // grayman #2422 - but not if the other AI is searching if ( !_blockingEntAI->IsSearching() ) { if (owner->movementSubsystem->IsWaitingSolid()) { float traveledPrev = _blockingEntAI->movementSubsystem->GetPrevTraveled(); if (traveledPrev < 0.1) // grayman #2345 { BecomeNonSolid(owner); } } } } if (ai_showObstacleAvoidance.GetBool()) { // waiting AI is watching blocking AI gameRenderWorld->DebugLine(colorPink,owner->GetPhysics()->GetOrigin() + idVec3(0,0,72),_blockingEnt->GetPhysics()->GetOrigin() + idVec3(0,0,64),100); } } return false; }
bool ResolveMovementBlockTask::PerformBlockingAI( idAI *owner ) { idVec3 right, forward; if( owner->AI_MOVE_DONE && !_turning && !owner->movementSubsystem->IsWaiting() ) { // grayman #2345 - if already waiting, no need to do this section // grayman #3725 - turn perpendicular to the direction // _blockingEnt is looking idAngles angles; if( _blockingEnt->IsType( idAI::Type ) ) { angles = static_cast<idAI *>( _blockingEnt )->viewAxis.ToAngles(); } else { angles = _initialAngles; } angles.ToVectors( &forward, &right ); owner->StopMove( MOVE_STATUS_WAITING ); owner->TurnToward( owner->GetPhysics()->GetOrigin() + right ); _turning = true; // grayman #3725 } if( _turning ) { // grayman #3725 if( !owner->FacingIdeal() ) { return false; } _turning = false; if( _preTaskContents == -1 ) { // grayman #2345 - don't become non-solid if your alert index is > ERelaxed. This is because // AI tend to bunch together when agitated, and it doesn't look good if one goes non-solid // and the others repeatedly walk through it. // If there's no room to get around you, become non-solid if( ( owner->AI_AlertIndex == ERelaxed ) && !Room2Pass( owner ) ) { BecomeNonSolid( owner ); } else { bool solid = true; owner->movementSubsystem->SetWaiting( solid ); } } } if( owner->movementSubsystem->IsWaiting() ) { // grayman #2345 // We are waiting for the other AI to pass by idVec3 dist = _blockingEnt->GetPhysics()->GetOrigin() - owner->GetPhysics()->GetOrigin(); if( dist.LengthSqr() > Square( 60 ) ) { // other AI has passed by, end the task // Be sure no one else is touching you when you want to return to being solid. // If there is, remain non-solid and let them pass by before you return to solid. // (This might not matter, but let's be safe.) idClipModel *clipModels[ MAX_GENTITIES ]; idPhysics *phys = owner->GetPhysics(); int num = gameLocal.clip.ClipModelsTouchingBounds( phys->GetAbsBounds(), phys->GetClipMask(), clipModels, MAX_GENTITIES ); bool foundNeighbor = false; for( int i = 0 ; i < num ; i++ ) { idClipModel *cm = clipModels[ i ]; // don't check render entities if( cm->IsRenderModel() ) { continue; } idEntity *hit = cm->GetEntity(); if( hit == owner ) { continue; } if( !phys->ClipContents( cm ) ) { continue; } // touching if( hit->IsType( idActor::Type ) ) { _blockingEnt = hit; foundNeighbor = true; break; } } if( !foundNeighbor ) { // grayman #3725 - Return to your initial facing angle. This will // only matter if you were initially standing. If you were moving, // ending this task will return you to that, overriding this turn. _initialAngles.ToVectors( &forward, &right ); owner->TurnToward( owner->GetPhysics()->GetOrigin() + forward ); return true; } } if( _blockingEnt->IsType( idAI::Type ) ) { // grayman #2345 - check to see if the other AI is standing still. // If they are, end the task. idAI *_blockingEntAI = static_cast<idAI *>( _blockingEnt ); if( _blockingEntAI && !_blockingEntAI->AI_FORWARD ) { // grayman #3725 - turn back to your initial facing angle _initialAngles.ToVectors( &forward, &right ); owner->TurnToward( owner->GetPhysics()->GetOrigin() + forward ); return true; // end the task } // If we're EWaitingSolid, change to EWaitingNonSolid if the other AI is barely moving. // grayman #2422 - but not if the other AI is searching if( !_blockingEntAI->IsSearching() ) { if( owner->movementSubsystem->IsWaitingSolid() ) { float traveledPrev = _blockingEntAI->movementSubsystem->GetPrevTraveled( false ).LengthFast(); // grayman #3647 if( traveledPrev < 0.1 ) { // grayman #2345 BecomeNonSolid( owner ); } } } } if( ai_showObstacleAvoidance.GetBool() ) { // waiting AI is watching blocking AI gameRenderWorld->DebugLine( colorPink, owner->GetPhysics()->GetOrigin() + idVec3( 0, 0, 72 ), _blockingEnt->GetPhysics()->GetOrigin() + idVec3( 0, 0, 64 ), 100 ); } } return false; }
/* ================ idMoveable::Spawn ================ */ void idMoveable::Spawn( void ) { idTraceModel trm; float density, friction, bouncyness; int clipShrink; idStr clipModelName; bool setClipModel = false; idBounds bounds; // check if a clip model is set spawnArgs.GetString( "clipmodel", "", clipModelName ); if ( !clipModelName[0] ) { idVec3 size; if ( spawnArgs.GetVector( "mins", NULL, bounds[0] ) && spawnArgs.GetVector( "maxs", NULL, bounds[1] ) ) { setClipModel = true; if ( bounds[0][0] > bounds[1][0] || bounds[0][1] > bounds[1][1] || bounds[0][2] > bounds[1][2] ) { gameLocal.Error( "Invalid bounds '%s'-'%s' on moveable '%s'", bounds[0].ToString(), bounds[1].ToString(), name.c_str() ); } } else if ( spawnArgs.GetVector( "size", NULL, size ) ) { if ( ( size.x < 0.0f ) || ( size.y < 0.0f ) || ( size.z < 0.0f ) ) { gameLocal.Error( "Invalid size '%s' on moveable '%s'", size.ToString(), name.c_str() ); } bounds[0].Set( size.x * -0.5f, size.y * -0.5f, 0.0f ); bounds[1].Set( size.x * 0.5f, size.y * 0.5f, size.z ); setClipModel = true; } } if ( setClipModel ) { trm.SetupBox( bounds ); } else { if ( !clipModelName[0] ) { clipModelName = spawnArgs.GetString ( "model" ); // use the visual model } clipModelName.BackSlashesToSlashes(); if ( !collisionModelManager->TrmFromModel( gameLocal.GetMapName(), 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 ); unbindOnDeath = spawnArgs.GetBool( "unbindondeath" ); nextCollideFxTime = 0; damage = spawnArgs.GetString( "def_damage", "" ); canDamage = spawnArgs.GetBool( "damageWhenActive" ) ? false : true; 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() ); } } fl.takedamage = (health > 0 ); // setup the physics physicsObj.SetSelf( this ); // RAVEN BEGIN // mwhitlock: Dynamic memory consolidation RV_PUSH_HEAP_MEM( this ); // RAVEN END physicsObj.SetClipModel( new idClipModel( trm, GetRenderModelMaterial() ), density ); // RAVEN BEGIN // mwhitlock: Dynamic memory consolidation RV_POP_HEAP(); // RAVEN END 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 | CONTENTS_WATER ); SetPhysics( &physicsObj ); 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" ); // RAVEN BEGIN // cdr: Obstacle Avoidance fl.isAIObstacle = !physicsObj.IsPushable(); // RAVEN END PostEventMS( &EV_SetOwnerFromSpawnArgs, 0 ); }