void hhProjectileStickyCrawlerGrenade::BindToCollisionObject( const trace_t* collision ) { if( !collision || collision->fraction > 1.0f ) { return; } //HUMANHEAD PCF rww 05/18/06 - wait until we receive bind info from the server if (gameLocal.isClient) { return; } //HUMANHEAD END idEntity* pEntity = gameLocal.entities[collision->c.entityNum]; HH_ASSERT( pEntity ); // HUMANHEAD PCF pdm 05-20-06: Check for some degenerate cases to combat the server hangs happening if (pEntity == this || this->IsBound()) { assert(0); // Report any of these return; } // HUMANHEAD END jointHandle_t jointHandle = CLIPMODEL_ID_TO_JOINT_HANDLE( collision->c.id ); if ( jointHandle != INVALID_JOINT ) { SetOrigin( collision->endpos ); SetAxis( DetermineCollisionAxis( (-collision->c.normal).ToMat3()) ); BindToJoint( pEntity, jointHandle, true ); } else { SetOrigin( collision->endpos ); SetAxis( DetermineCollisionAxis( (-collision->c.normal).ToMat3()) ); Bind( pEntity, true ); } }
/* ================ idThread::Event_GetTraceJoint ================ */ void idThread::Event_GetTraceJoint( void ) { if ( trace.fraction < 1.0f && trace.c.id < 0 ) { idAFEntity_Base *af = static_cast<idAFEntity_Base *>( gameLocal.entities[ trace.c.entityNum ] ); if ( af && af->IsType( idAFEntity_Base::Type ) && af->IsActiveAF() ) { ReturnString( af->GetAnimator()->GetJointName( CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ) ) ); return; } } ReturnString( "" ); }
/* ================ idAF::BodyForClipModelId ================ */ int idAF::BodyForClipModelId( int id ) const { if ( id >= 0 ) { return id; } else { id = CLIPMODEL_ID_TO_JOINT_HANDLE( id ); if ( id < jointBody.Num() ) { return jointBody[id]; } else { return 0; } } }
/* ============ idPush::ClipRotationalPush Try to push other entities by moving the given entity. ============ */ float idPush::ClipRotationalPush( trace_t &results, idEntity *pusher, const int flags, const idMat3 &newAxis, const idRotation &rotation ) { int i, listedEntities, res; idEntity *check, *entityList[ MAX_GENTITIES ]; idBounds bounds, pushBounds; idRotation clipRotation; idMat3 clipAxis, oldAxis; trace_t pushResults; bool wasEnabled; float totalMass; idClipModel *clipModel; clipModel = pusher->GetPhysics()->GetClipModel(); totalMass = 0.0f; results.fraction = 1.0f; results.endpos = clipModel->GetOrigin(); results.endAxis = newAxis; memset( &results.c, 0, sizeof( results.c ) ); if ( !rotation.GetAngle() ) { return totalMass; } // get bounds for the whole movement bounds = clipModel->GetBounds(); if ( bounds[0].x >= bounds[1].x ) { return totalMass; } pushBounds.FromBoundsRotation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), rotation ); wasEnabled = clipModel->IsEnabled(); // make sure we don't get the pushing clip model in the list clipModel->Disable(); listedEntities = gameLocal.clip.EntitiesTouchingBounds( pushBounds, -1, entityList, MAX_GENTITIES ); // discard entities we cannot or should not push listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher ); if ( flags & PUSHFL_CLIP ) { // can only clip movement of a trace model assert( clipModel->IsTraceModel() ); // disable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[i]->GetPhysics()->DisableClip(); } gameLocal.clip.Rotation( results, clipModel->GetOrigin(), rotation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL ); // enable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[i]->GetPhysics()->EnableClip(); } if ( results.fraction == 0.0f ) { if ( wasEnabled ) { clipModel->Enable(); } return totalMass; } clipRotation = rotation * results.fraction; clipAxis = results.endAxis; } else { clipRotation = rotation; clipAxis = newAxis; } // we have to enable the clip model because we use it during pushing clipModel->Enable(); // save pusher old position oldAxis = clipModel->GetAxis(); // try to push all the entities for ( i = 0; i < listedEntities; i++ ) { check = entityList[ i ]; idPhysics *physics = check->GetPhysics(); // disable the entity for collision detection physics->DisableClip(); res = TryRotatePushEntity( pushResults, check, clipModel, flags, clipAxis, clipRotation ); // enable the entity for collision detection physics->EnableClip(); // if the entity is pushed if ( res == PUSH_OK ) { // set the pusher in the rotated position clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), newAxis ); // the entity might be pushed off the ground physics->EvaluateContacts(); // put pusher back in old position clipModel->Link( gameLocal.clip, clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), oldAxis ); // wake up this object check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), vec3_origin ); // add mass of pushed entity totalMass += physics->GetMass(); } // if the entity is not blocking if ( res != PUSH_BLOCKED ) { continue; } // if the blocking entity is a projectile if ( check->IsType( idProjectile::Type ) ) { check->ProcessEvent( &EV_Explode ); continue; } // if blocking entities should be crushed if ( flags & PUSHFL_CRUSH ) { check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) ); continue; } // if the entity is an active articulated figure and gibs if ( check->IsType( idAFEntity_Base::Type ) && check->spawnArgs.GetBool( "gib" ) ) { if ( static_cast<idAFEntity_Base *>(check)->IsActiveAF() ) { check->ProcessEvent( &EV_Gib, "damage_Gib" ); } } // blocked results = pushResults; results.fraction = 0.0f; results.endAxis = clipModel->GetAxis(); results.endpos = clipModel->GetOrigin(); results.c.entityNum = check->entityNumber; results.c.id = 0; if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; } if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; }
/* ============ idPush::ClipTranslationalPush Try to push other entities by moving the given entity. ============ */ float idPush::ClipTranslationalPush( trace_t &results, idEntity *pusher, const int flags, const idVec3 &newOrigin, const idVec3 &translation ) { int i, listedEntities, res; idEntity *check, *entityList[ MAX_GENTITIES ]; idBounds bounds, pushBounds; idVec3 clipMove, clipOrigin, oldOrigin, dir, impulse; trace_t pushResults; bool wasEnabled; float totalMass; idClipModel *clipModel; clipModel = pusher->GetPhysics()->GetClipModel(); totalMass = 0.0f; results.fraction = 1.0f; results.endpos = newOrigin; results.endAxis = clipModel->GetAxis(); memset( &results.c, 0, sizeof( results.c ) ); if ( translation == vec3_origin ) { return totalMass; } dir = translation; dir.Normalize(); dir.z += 1.0f; dir *= 10.0f; // get bounds for the whole movement bounds = clipModel->GetBounds(); if ( bounds[0].x >= bounds[1].x ) { return totalMass; } pushBounds.FromBoundsTranslation( bounds, clipModel->GetOrigin(), clipModel->GetAxis(), translation ); wasEnabled = clipModel->IsEnabled(); // make sure we don't get the pushing clip model in the list clipModel->Disable(); // RAVEN BEGIN // ddynerman: multiple clip worlds listedEntities = gameLocal.EntitiesTouchingBounds( pusher, pushBounds, -1, entityList, MAX_GENTITIES ); // RAVEN END // discard entities we cannot or should not push listedEntities = DiscardEntities( entityList, listedEntities, flags, pusher ); if ( flags & PUSHFL_CLIP ) { // can only clip movement of a trace model assert( clipModel->IsTraceModel() ); // disable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[i]->GetPhysics()->DisableClip(); } // RAVEN BEGIN // ddynerman: multiple clip worlds gameLocal.Translation( pusher, results, clipModel->GetOrigin(), clipModel->GetOrigin() + translation, clipModel, clipModel->GetAxis(), pusher->GetPhysics()->GetClipMask(), NULL ); // RAVEN END // enable to be pushed entities for collision detection for ( i = 0; i < listedEntities; i++ ) { entityList[i]->GetPhysics()->EnableClip(); } if ( results.fraction == 0.0f ) { if ( wasEnabled ) { clipModel->Enable(); } return totalMass; } clipMove = results.endpos - clipModel->GetOrigin(); clipOrigin = results.endpos; } else { clipMove = translation; clipOrigin = newOrigin; } // we have to enable the clip model because we use it during pushing clipModel->Enable(); // save pusher old position oldOrigin = clipModel->GetOrigin(); // try to push the entities for ( i = 0; i < listedEntities; i++ ) { check = entityList[ i ]; idPhysics *physics = check->GetPhysics(); // disable the entity for collision detection physics->DisableClip(); res = TryTranslatePushEntity( pushResults, check, clipModel, flags, clipOrigin, clipMove ); // enable the entity for collision detection physics->EnableClip(); // if the entity is pushed if ( res == PUSH_OK ) { // set the pusher in the translated position // RAVEN BEGIN // ddynerman: multiple clip worlds clipModel->Link( clipModel->GetEntity(), clipModel->GetId(), newOrigin, clipModel->GetAxis() ); // RAVEN END // the entity might be pushed off the ground physics->EvaluateContacts(); // put pusher back in old position // RAVEN BEGIN // ddynerman: multiple clip worlds clipModel->Link( clipModel->GetEntity(), clipModel->GetId(), oldOrigin, clipModel->GetAxis() ); // RAVEN END // wake up this object if ( flags & PUSHFL_APPLYIMPULSE ) { impulse = physics->GetMass() * dir; } else { impulse.Zero(); } check->ApplyImpulse( clipModel->GetEntity(), clipModel->GetId(), clipModel->GetOrigin(), impulse ); // add mass of pushed entity totalMass += physics->GetMass(); } // if the entity is not blocking if ( res != PUSH_BLOCKED ) { continue; } // if the blocking entity is a projectile // RAVEN BEGIN // jnewquist: Use accessor for static class type if ( check->IsType( idProjectile::GetClassType() ) ) { // RAVEN END check->ProcessEvent( &EV_Explode ); continue; } // if blocking entities should be crushed if ( flags & PUSHFL_CRUSH ) { check->Damage( clipModel->GetEntity(), clipModel->GetEntity(), vec3_origin, "damage_crush", 1.0f, CLIPMODEL_ID_TO_JOINT_HANDLE( pushResults.c.id ) ); continue; } // if the entity is an active articulated figure and gibs // RAVEN BEGIN // jnewquist: Use accessor for static class type if ( check->IsType( idAFEntity_Base::GetClassType() ) && check->spawnArgs.GetBool( "gib" ) ) { // RAVEN END if ( static_cast<idAFEntity_Base *>(check)->IsActiveAF() ) { check->ProcessEvent( &EV_Gib, "damage_Gib" ); } } // if the entity is a moveable item and gibs // RAVEN BEGIN // jnewquist: Use accessor for static class type if ( check->IsType( idMoveableItem::GetClassType() ) && check->spawnArgs.GetBool( "gib" ) ) { // RAVEN END check->ProcessEvent( &EV_Gib, "damage_Gib" ); } // blocked results = pushResults; results.fraction = 0.0f; results.endAxis = clipModel->GetAxis(); results.endpos = clipModel->GetOrigin(); results.c.entityNum = check->entityNumber; results.c.id = 0; if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; } if ( !wasEnabled ) { clipModel->Disable(); } return totalMass; }
/* ============== idDragEntity::Update ============== */ void idDragEntity::Update( idPlayer *player ) { idVec3 viewPoint, origin; idMat3 viewAxis, axis; trace_t trace; idEntity *newEnt; idAngles angles; jointHandle_t newJoint; idStr newBodyName; player->GetViewPos( viewPoint, viewAxis ); // if no entity selected for dragging if ( !dragEnt.GetEntity() ) { if ( player->usercmd.buttons & BUTTON_ATTACK ) { gameLocal.clip.TracePoint( trace, viewPoint, viewPoint + viewAxis[0] * MAX_DRAG_TRACE_DISTANCE, (CONTENTS_SOLID|CONTENTS_RENDERMODEL|CONTENTS_BODY), player ); if ( trace.fraction < 1.0f ) { newEnt = gameLocal.entities[ trace.c.entityNum ]; if ( newEnt ) { if ( newEnt->GetBindMaster() ) { if ( newEnt->GetBindJoint() ) { trace.c.id = JOINT_HANDLE_TO_CLIPMODEL_ID( newEnt->GetBindJoint() ); } else { trace.c.id = newEnt->GetBindBody(); } newEnt = newEnt->GetBindMaster(); } if ( newEnt->IsType( idAFEntity_Base::Type ) && static_cast<idAFEntity_Base *>(newEnt)->IsActiveAF() ) { idAFEntity_Base *af = static_cast<idAFEntity_Base *>(newEnt); // joint being dragged newJoint = CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ); // get the body id from the trace model id which might be a joint handle trace.c.id = af->BodyForClipModelId( trace.c.id ); // get the name of the body being dragged newBodyName = af->GetAFPhysics()->GetBody( trace.c.id )->GetName(); } else if ( !newEnt->IsType( idWorldspawn::Type ) ) { if ( trace.c.id < 0 ) { newJoint = CLIPMODEL_ID_TO_JOINT_HANDLE( trace.c.id ); } else { newJoint = INVALID_JOINT; } newBodyName = ""; } else { newJoint = INVALID_JOINT; newEnt = NULL; } } if ( newEnt ) { dragEnt = newEnt; selected = newEnt; joint = newJoint; id = trace.c.id; bodyName = newBodyName; if ( !cursor ) { cursor = ( idCursor3D * )gameLocal.SpawnEntityType( idCursor3D::Type ); } idPhysics *phys = dragEnt.GetEntity()->GetPhysics(); localPlayerPoint = ( trace.c.point - viewPoint ) * viewAxis.Transpose(); origin = phys->GetOrigin( id ); axis = phys->GetAxis( id ); localEntityPoint = ( trace.c.point - origin ) * axis.Transpose(); cursor->drag.Init( g_dragDamping.GetFloat() ); cursor->drag.SetPhysics( phys, id, localEntityPoint ); cursor->Show(); if ( phys->IsType( idPhysics_AF::Type ) || phys->IsType( idPhysics_RigidBody::Type ) || phys->IsType( idPhysics_Monster::Type ) ) { cursor->BecomeActive( TH_THINK ); } } } } } // if there is an entity selected for dragging idEntity *drag = dragEnt.GetEntity(); if ( drag ) { if ( !( player->usercmd.buttons & BUTTON_ATTACK ) ) { StopDrag(); return; } cursor->SetOrigin( viewPoint + localPlayerPoint * viewAxis ); cursor->SetAxis( viewAxis ); cursor->drag.SetDragPosition( cursor->GetPhysics()->GetOrigin() ); renderEntity_t *renderEntity = drag->GetRenderEntity(); idAnimator *dragAnimator = drag->GetAnimator(); if ( joint != INVALID_JOINT && renderEntity && dragAnimator ) { dragAnimator->GetJointTransform( joint, gameLocal.time, cursor->draggedPosition, axis ); cursor->draggedPosition = renderEntity->origin + cursor->draggedPosition * renderEntity->axis; gameRenderWorld->DrawText( va( "%s\n%s\n%s, %s", drag->GetName(), drag->GetType()->classname, dragAnimator->GetJointName( joint ), bodyName.c_str() ), cursor->GetPhysics()->GetOrigin(), 0.1f, colorWhite, viewAxis, 1 ); } else { cursor->draggedPosition = cursor->GetPhysics()->GetOrigin(); gameRenderWorld->DrawText( va( "%s\n%s\n%s", drag->GetName(), drag->GetType()->classname, bodyName.c_str() ), cursor->GetPhysics()->GetOrigin(), 0.1f, colorWhite, viewAxis, 1 ); } } // if there is a selected entity if ( selected.GetEntity() && g_dragShowSelection.GetBool() ) { // draw the bbox of the selected entity renderEntity_t *renderEntity = selected.GetEntity()->GetRenderEntity(); if ( renderEntity ) { gameRenderWorld->DebugBox( colorYellow, idBox( renderEntity->bounds, renderEntity->origin, renderEntity->axis ) ); } } }