virtual void ProcessEvent( EFlowEvent event, SActivationInfo *pActInfo ) { switch (event) { case eFE_Activate: const int nDrawPlayer = GetPortInt(pActInfo, EIP_DrawPlayer); if (IsPortActive(pActInfo, EIP_Link)) { IEntity* pEntity = gEnv->pEntitySystem->GetEntity(GetPortEntityId(pActInfo, EIP_Target)); if (pEntity) { CActor *pPlayerActor = static_cast<CActor*>(gEnv->pGame->GetIGameFramework()->GetClientActor()); if (pPlayerActor) { SActorStats* pActorStats = pPlayerActor->GetActorStats(); if (pActorStats) { if (nDrawPlayer == -1) pActorStats->isHidden = true; else if (nDrawPlayer == 1) pActorStats->isHidden = false; } m_Position = pEntity->GetWorldPos(); m_Rotation = pEntity->GetWorldRotation(); pPlayerActor->LinkToEntity(pEntity->GetId()); ActivateOutput(pActInfo, EOP_Linked, true); } } } if (IsPortActive(pActInfo, EIP_Unlink)) { CActor *pPlayerActor = static_cast<CActor*>(gEnv->pGame->GetIGameFramework()->GetClientActor()); if (pPlayerActor) { SActorStats* pActorStats = pPlayerActor->GetActorStats(); if (pActorStats) { if (nDrawPlayer == -1) pActorStats->isHidden = true; else if (nDrawPlayer == 1) pActorStats->isHidden = false; } bool keepTransform = GetPortBool(pActInfo, EIP_KeepTransform); pPlayerActor->LinkToEntity(0, keepTransform); if(!keepTransform) { pPlayerActor->GetEntity()->SetPos(m_Position); pPlayerActor->GetEntity()->SetRotation(m_Rotation); } ActivateOutput(pActInfo, EOP_Unlinked, true); } } break; } }
//------------------------------------------------------------------------ void CItem::UpdateFPPosition(float frameTime) { CActor* pActor = GetOwnerActor(); if (!pActor) return; SPlayerStats *pStats = static_cast<SPlayerStats *>(pActor->GetActorStats()); if (!pStats) return; Matrix34 tm = Matrix33::CreateRotationXYZ(pStats->FPWeaponAngles); Vec3 offset(0.0f,0.0f,0.0f); float right(g_pGameCVars->i_offset_right); float front(g_pGameCVars->i_offset_front); float up(g_pGameCVars->i_offset_up); if (front!=0.0f || up!=0.0f || right!=0.0f) { offset += tm.GetColumn(0).GetNormalized() * right; offset += tm.GetColumn(1).GetNormalized() * front; offset += tm.GetColumn(2).GetNormalized() * up; } tm.SetTranslation(pStats->FPWeaponPos + offset); GetEntity()->SetWorldTM(tm); //CryLogAlways("weaponpos: %.3f,%.3f,%.3f // weaponrot: %.3f,%.3f,%.3f", tm.GetTranslation().x,tm.GetTranslation().y,tm.GetTranslation().z, pStats->FPWeaponAngles.x, pStats->FPWeaponAngles.y, pStats->FPWeaponAngles.z); }
//------------------------------------------------------------------------ float CGameRulesCommonDamageHandling::GetAIPlayerAgainstColliderEnergyScale(const IEntity& collider) const { const float energyScaleAgainstNonActor = 10.0f; const float energyScaleAgainstRagdoll = 50.0f; CActor* pColliderActor = static_cast<CActor*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(collider.GetId())); if (pColliderActor) { uint8 physicsAspectProfile = pColliderActor->GetGameObject()->GetAspectProfile(eEA_Physics) ; if ((physicsAspectProfile == eAP_Ragdoll) || (physicsAspectProfile == eAP_Sleep)) { return energyScaleAgainstRagdoll; } if (pColliderActor->GetActorClass() == CPlayer::GetActorClassType()) { SPlayerStats* pColliderStats = static_cast<SPlayerStats*>(pColliderActor->GetActorStats()); if (pColliderStats != NULL && pColliderStats->followCharacterHead) { return 0.0f; } } } return energyScaleAgainstNonActor; }
//----------------------------------------------------------------------- void CSpectacularKill::End(bool bKillerDied/* = false*/) { CRY_ASSERT_MESSAGE(IsBusy(), "spectacular kill cannot be stopped if it is not in progress"); if (!IsBusy()) return; ICooperativeAnimationManager* pCooperativeAnimationManager = gEnv->pGame->GetIGameFramework()->GetICooperativeAnimationManager(); CActor* pTarget = GetTarget(); CRY_ASSERT(pTarget); if(pTarget) { pCooperativeAnimationManager->StopCooperativeAnimationOnActor(m_pOwner->GetAnimatedCharacter(), pTarget->GetAnimatedCharacter()); // Enable AI again (for what it's worth - this helps editor) if (!pTarget->IsPlayer() && pTarget->GetEntity()->GetAI()) pTarget->GetEntity()->GetAI()->Event(AIEVENT_ENABLE, 0); if (bKillerDied && (m_deathBlowState == eDBS_None) && static_cast<CPlayer*> (pTarget)->CanFall()) { // Enable Fall n Play on target if killer dies before death blowing it pTarget->Fall(); } else if (m_deathBlowState != eDBS_Done) { DeathBlow(*pTarget); // Call this in case the notification from the animation system got skipped or missed for some reason } SActorStats* pTargetStats = pTarget->GetActorStats(); pTargetStats->spectacularKillPartner = 0; } else { pCooperativeAnimationManager->StopCooperativeAnimationOnActor(m_pOwner->GetAnimatedCharacter()); } // Enable AI again (for what it's worth - this helps editor) if (m_pOwner && m_pOwner->GetEntity()->GetAI()) m_pOwner->GetEntity()->GetAI()->Event(AIEVENT_ENABLE, 0); ClearState(); assert(m_pOwner); SActorStats* pStats = m_pOwner->GetActorStats(); if(pStats) pStats->spectacularKillPartner = 0; }
/** * Turn the grabbed AnimatedCharacter on/off if necessary. If the grabbed thing * has an AC, it's necessary to turn it off during the grab to prevent it from * interfering and messing with its Entity's transformation. */ void CBaseGrabHandler::DisableGrabbedAnimatedCharacter (bool enable) const { CActor *pGrabbedActor = (CActor *)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_grabStats.grabId); if ( ! pGrabbedActor) return; IAnimatedCharacter * pGrabbedAC = pGrabbedActor->GetAnimatedCharacter(); if (pGrabbedAC) pGrabbedAC->SetNoMovementOverride (enable); // SActorStats *stats = static_cast<SActorStats*>(pGrabbedActor->GetActorStats()); // stats->isGrabbed = enable; if(pGrabbedActor->IsClient()) { if(SActorStats *stats = static_cast<SActorStats*>(pGrabbedActor->GetActorStats())) stats->isGrabbed = enable; } }
//------------------------------------------------------------------------ float CGameRulesCommonDamageHandling::GetPlayerAgainstColliderEnergyScale(const IEntity& collider) const { CActor* pColliderActor = static_cast<CActor*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(collider.GetId())); if (pColliderActor) { if (pColliderActor->GetActorClass() == CPlayer::GetActorClassType()) { SPlayerStats* pColliderStats = static_cast<SPlayerStats*>(pColliderActor->GetActorStats()); if (pColliderStats != NULL && pColliderStats->followCharacterHead) { return 0.0f; } } } return 1.0f; }
//---------------------------------------------------------------------- void CSingleTG::UpdateFPView(float frameTime) { CSingle::UpdateFPView(frameTime); //Weapon can not be fired if there's not a target locked if(!m_bLocked) { m_pWeapon->LowerWeapon(true); if(!m_bLocking) { CActor *pPlayer = m_pWeapon->GetOwnerActor(); SPlayerStats *stats = pPlayer?static_cast<SPlayerStats *>(pPlayer->GetActorStats()):NULL; if(stats && !gEnv->bMultiplayer) stats->bLookingAtFriendlyAI = true; } } }
bool CPlant::PlayerStanceOK() const { bool ok = true; if(m_plantparams.need_to_crouch && m_pWeapon->GetOwnerActor()) { CActor* pActor = (CActor*)m_pWeapon->GetOwnerActor(); ok = (pActor->GetStance() == STANCE_CROUCH); if(ok) { ok &= (pActor->GetActorStats()->velocity.GetLengthSquared() < 0.1f); if(ok) { // also fire a ray forwards to check the placement position is nearby Vec3 pos; Vec3 dir(FORWARD_DIRECTION); Vec3 vel(0,0,0); ok &= GetPlantingParameters(pos, dir, vel); } } } return ok; }
//------------------------------------------------------------------------ void CMelee::Impulse(const Vec3 &pt, const Vec3 &dir, const Vec3 &normal, IPhysicalEntity *pCollider, int partId, int ipart, int surfaceIdx, float impulseScale) { if(m_noImpulse) { m_noImpulse = false; return; } if (pCollider && m_pShared->meleeparams.impulse > 0.001f) { bool strengthMode = false; CPlayer *pPlayer = (CPlayer *)m_pWeapon->GetOwnerActor(); pe_status_dynamics dyn; if (!pCollider->GetStatus(&dyn)) { if(strengthMode) { impulseScale *= 3.0f; } } else { impulseScale *= clamp((dyn.mass * 0.01f), 1.0f, 15.0f); } //[kirill] add impulse to phys proxy - to make sure it's applied to cylinder as well (not only skeleton) - so that entity gets pushed // if no pEntity - do it old way IEntity *pEntity = (IEntity *) pCollider->GetForeignData(PHYS_FOREIGN_ID_ENTITY); if(gEnv->bMultiplayer && pEntity) { if(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pEntity->GetId()) == NULL) { impulseScale *= 0.33f; } } if(pEntity) { bool crapDollFilter = false; #ifdef CRAPDOLLS static IEntityClass *pDeadBodyClass = gEnv->pEntitySystem->GetClassRegistry()->FindClass("DeadBody"); if (pEntity->GetClass() == pDeadBodyClass) { crapDollFilter = true; } #endif //CRAPDOLLS if (!crapDollFilter) { IEntityPhysicalProxy *pPhysicsProxy = (IEntityPhysicalProxy *)pEntity->GetProxy(ENTITY_PROXY_PHYSICS); CActor *pActor = (CActor *)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(pEntity->GetId()); if (pActor) { SActorStats *pAS = pActor->GetActorStats(); if (pAS && pAS->isRagDoll) { //marcok: talk to me before touching this impulseScale = 1.0f; //jan: melee impulses were scaled down, I made sure it still "barely moves" #ifdef CRAPDOLLS crapDollFilter = true; #endif //CRAPDOLLS } } // scale impulse up a bit for player if (!crapDollFilter) { pPhysicsProxy->AddImpulse(partId, pt, dir * m_pShared->meleeparams.impulse * impulseScale * m_meleeScale, true, 1.f); } } } else { pe_action_impulse ai; ai.partid = partId; ai.ipart = ipart; ai.point = pt; ai.iApplyTime = 0; ai.impulse = dir * (m_pShared->meleeparams.impulse * impulseScale * m_meleeScale); pCollider->Action(&ai); } ISurfaceTypeManager *pSurfaceTypeManager = gEnv->p3DEngine->GetMaterialManager()->GetSurfaceTypeManager(); int invId = pSurfaceTypeManager->GetSurfaceTypeByName("mat_invulnerable")->GetId(); // create a physical collision to break trees pe_action_register_coll_event collision; collision.collMass = 0.005f; // this is actually ignored collision.partid[1] = partId; // collisions involving partId<-1 are to be ignored by game's damage calculations // usually created articially to make stuff break. collision.partid[0] = -2; collision.idmat[1] = surfaceIdx; collision.idmat[0] = invId; collision.n = normal; collision.pt = pt; // scar bullet // m = 0.0125 // v = 800 // energy: 4000 // in this case the mass of the active collider is a player part // so we must solve for v given the same energy as a scar bullet Vec3 v = dir; float speed = cry_sqrtf(4000.0f / (80.0f * 0.5f)); // 80.0f is the mass of the player // [marco] Check if an object. Should take lots of time to break stuff if not in nanosuit strength mode; // and still creates a very low impulse for stuff that might depend on receiving an impulse. IRenderNode *pBrush = (IRenderNode *)pCollider->GetForeignData(PHYS_FOREIGN_ID_STATIC); collision.vSelf = (v.normalized() * speed * m_meleeScale); collision.v = Vec3(0, 0, 0); collision.pCollider = pCollider; IEntity *pOwner = m_pWeapon->GetOwner(); if (pOwner && pOwner->GetCharacter(0) && pOwner->GetCharacter(0)->GetISkeletonPose()->GetCharacterPhysics()) { if (ISkeletonPose *pSkeletonPose = pOwner->GetCharacter(0)->GetISkeletonPose()) { if (pSkeletonPose && pSkeletonPose->GetCharacterPhysics()) { pSkeletonPose->GetCharacterPhysics()->Action(&collision); } } } } }
void CMelee::StartFire() { if (!CanFire()) { return; } //Prevent fists melee exploit if ((m_pWeapon->GetEntity()->GetClass() == CItem::sFistsClass) && m_pWeapon->IsBusy()) { return; } CActor *pOwner = m_pWeapon->GetOwnerActor(); if(pOwner) { if(pOwner->GetStance() == STANCE_PRONE) { return; } if(SPlayerStats *stats = static_cast<SPlayerStats *>(pOwner->GetActorStats())) { if(stats->bLookingAtFriendlyAI) { return; } } } m_attacking = true; m_attacked = false; m_pWeapon->RequireUpdate(eIUS_FireMode); m_pWeapon->ExitZoom(); bool isClient = pOwner ? pOwner->IsClient() : false; if (g_pGameCVars->bt_end_melee && isClient) { g_pGame->GetBulletTime()->Activate(false); } float speedOverride = -1.0f; if(pOwner) { CPlayer *pPlayer = (CPlayer *)pOwner; pPlayer->PlaySound(CPlayer::ESound_Melee); } m_pWeapon->PlayAction(m_pShared->meleeactions.attack.c_str(), 0, false, CItem::eIPAF_Default | CItem::eIPAF_CleanBlending, speedOverride); m_pWeapon->SetBusy(true); m_beginPos = m_pWeapon->GetSlotHelperPos( eIGS_FirstPerson, m_pShared->meleeparams.helper.c_str(), true); m_pWeapon->GetScheduler()->TimerAction(m_pWeapon->GetCurrentAnimationTime( eIGS_FirstPerson), CSchedulerAction<StopAttackingAction>::Create(this), true); m_delayTimer = m_pShared->meleeparams.delay; if (g_pGameCVars->dt_enable && m_delayTimer < g_pGameCVars->dt_time) { m_delayTimer = g_pGameCVars->dt_time; } m_durationTimer = m_pShared->meleeparams.duration; m_pWeapon->OnMelee(m_pWeapon->GetOwnerId()); m_pWeapon->RequestStartMeleeAttack(m_pWeapon->GetMeleeFireMode() == this, false); }
bool CGameRulesMPDamageHandling::SvOnHitScaled( const HitInfo &hitInfo ) { bool bReturnDied = false; IEntity *pTarget = gEnv->pEntitySystem->GetEntity(hitInfo.targetId); CActor *pActor = static_cast<CActor*>(g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(hitInfo.targetId)); if(!pActor) { IVehicle* pVictimVehicle = g_pGame->GetIGameFramework()->GetIVehicleSystem()->GetVehicle(hitInfo.targetId); if(pVictimVehicle) { float vehicleDamageMultiplier = 1.f; //Additional damage scaling check for vehicles with associated body damage files CBodyDamageManager *pBodyDamageManager = g_pGame->GetBodyDamageManager(); TBodyDamageProfileId bodyDamageProfileId; TVehicleBodyDamageMap::const_iterator iter = m_vehicleBodyDamageMap.find( hitInfo.targetId ); if( iter != m_vehicleBodyDamageMap.end() ) { bodyDamageProfileId = iter->second; } else { bodyDamageProfileId = pBodyDamageManager->GetBodyDamage( *pTarget ); m_vehicleBodyDamageMap[hitInfo.targetId] = bodyDamageProfileId; } if(bodyDamageProfileId != INVALID_BODYDAMAGEPROFILEID) { vehicleDamageMultiplier *= pBodyDamageManager->GetDamageMultiplier(bodyDamageProfileId, *pTarget, hitInfo); } float fPreviousHealth = pVictimVehicle->GetStatus().health; // for vehicles, no need to call lua any more, we can just apply the hit directly to the vehicle { HitInfo hitInfoTemp = hitInfo; hitInfoTemp.damage *= vehicleDamageMultiplier; hitInfoTemp.explosion = false; pVictimVehicle->OnHit(hitInfoTemp); } float fNewHealth = pVictimVehicle->GetStatus().health; //Hit indicator for driver // Health check is required to take into account damage removal due to friendly fire. if(fNewHealth != fPreviousHealth) { if(IActor* pDriver = pVictimVehicle->GetDriver()) { if(IEntity* pShooterEntity = gEnv->pEntitySystem->GetEntity(hitInfo.shooterId)) { Vec3 shooterPos = pShooterEntity->GetWorldPos(); if(pDriver->IsClient()) { SHUDEvent hitEvent(eHUDEvent_OnShowHitIndicatorPlayerUpdated); hitEvent.ReserveData(3); hitEvent.AddData(shooterPos.x); hitEvent.AddData(shooterPos.y); hitEvent.AddData(shooterPos.z); CHUDEventDispatcher::CallEvent(hitEvent); } else { m_pGameRules->GetGameObject()->InvokeRMI( CGameRules::ClActivateHitIndicator(), CGameRules::ActivateHitIndicatorParams(shooterPos), eRMI_ToClientChannel, pDriver->GetChannelId() ); } } } } // no need for further processing, or calling OnEntityKilled, so just return early. if(pVictimVehicle->GetDamageRatio() >= 1.f) { if(fNewHealth != fPreviousHealth) { SVehicleDestroyedParams params(hitInfo.targetId, hitInfo.weaponId, hitInfo.type, hitInfo.projectileClassId); if(hitInfo.shooterId == g_pGame->GetClientActorId()) { CPersistantStats::GetInstance()->OnClientDestroyedVehicle(params); } else if(IGameObject * pShooterGameObject = g_pGame->GetIGameFramework()->GetGameObject(hitInfo.shooterId)) { m_pGameRules->GetGameObject()->InvokeRMIWithDependentObject(CGameRules::ClVehicleDestroyed(), params, eRMI_ToClientChannel, hitInfo.shooterId, pShooterGameObject->GetChannelId()); } } m_pGameRules->OnEntityKilled(hitInfo); return true; } else { return false; } } } if (pTarget) { IScriptTable *pTargetScript = pTarget->GetScriptTable(); if (pTargetScript) { m_pGameRules->CreateScriptHitInfo(m_scriptHitInfo, hitInfo); bool isDead = false; if (pActor) { if (pActor->IsDead()) { isDead = true; // Target is already dead HSCRIPTFUNCTION pfnOnDeadHit = 0; if (pActor->GetActorStats()->isRagDoll && pTargetScript->GetValue("OnDeadHit", pfnOnDeadHit)) { Script::CallMethod(pTargetScript, pfnOnDeadHit, m_scriptHitInfo); gEnv->pScriptSystem->ReleaseFunc(pfnOnDeadHit); } } } if (!isDead) { SmartScriptTable targetServerScript; if (pTargetScript->GetValue("Server", targetServerScript)) { HSCRIPTFUNCTION pfnOnHit = 0; if (targetServerScript->GetValue("OnHit", pfnOnHit)) { if (Script::CallReturn(gEnv->pScriptSystem, pfnOnHit, pTargetScript, m_scriptHitInfo, bReturnDied)) { if (bReturnDied) { if (pActor) { ProcessDeath(hitInfo, *pActor); } else { m_pGameRules->OnEntityKilled(hitInfo); } } } gEnv->pScriptSystem->ReleaseFunc(pfnOnHit); } } } } } return bReturnDied; }
void CAnimatedGrabHandler::UpdatePosVelRot(float frameTime) { IEntity *pGrab = gEnv->pEntitySystem->GetEntity(m_grabStats.grabId); if ( !pGrab) return; IEntity *pEnt = m_pActor->GetEntity(); if (m_grabStats.grabDelay<0.001f) { Vec3 grabWPos (GetGrabBoneWorldTM ().t); // NOTE Aug 3, 2007: <pvl> the second part of this test means don't enable // the correction if animation/ik wasn't used for grabbing in the first place if (m_grabStats.readIkInaccuracyCorrection && m_grabStats.grabAnimGraphSignal[0]) { // NOTE Aug 2, 2007: <pvl> executed the first time this function is called // for a particular grabbing action m_grabStats.ikInaccuracyCorrection = grabWPos - (pGrab->GetWorldTM().GetTranslation() + m_grabStats.entityGrabSpot); m_grabStats.readIkInaccuracyCorrection = false; // FIXME Sep 13, 2007: <pvl> only putting it here because it's called just // once, at the instant when the object is grabbed - rename readIkInaccuracyCorrection // to make this clearer, or put this somewhere else DisableGrabbedAnimatedCharacter (true); } else { // NOTE Aug 2, 2007: <pvl> phase it out gradually m_grabStats.ikInaccuracyCorrection *= 0.9f; if (m_grabStats.ikInaccuracyCorrection.len2 () < 0.01f) m_grabStats.ikInaccuracyCorrection = Vec3 (0.0f, 0.0f, 0.0f); } // NOTE Sep 13, 2007: <pvl> this should prevent us from calling SetWPos() // later so that the IK "release" phase can take over m_grabStats.IKActive = false; Matrix34 tm(pGrab->GetWorldTM()); tm.SetTranslation(grabWPos - (m_grabStats.ikInaccuracyCorrection + pGrab->GetRotation() * m_grabStats.entityGrabSpot)); pGrab->SetWorldTM(tm,ENTITY_XFORM_USER); } //update IK for (int i=0;i<m_grabStats.limbNum;++i) { SIKLimb *pLimb = m_pActor->GetIKLimb(m_grabStats.limbId[i]); // NOTE Dez 14, 2006: <pvl> this class is always supposed to have // m_grabStats.usingAnimation == true if (m_grabStats.usingAnimation && m_grabStats.releaseIKTime>0.001f && m_grabStats.IKActive) { // NOTE Dez 15, 2006: <pvl> use IK to constantly offset the // animation so that the difference between where the animation // expects the object to be and where the object really is is taken // into account. Vec3 animPos = pEnt->GetSlotWorldTM(0) * pLimb->lAnimPos; Vec3 assumedGrabPos = pEnt->GetSlotWorldTM(0) * m_grabStats.grabbedObjOfs; Vec3 actualGrabPos = pGrab->GetWorldPos() + m_grabStats.entityGrabSpot; Vec3 adjustment = actualGrabPos - assumedGrabPos; pLimb->SetWPos(pEnt,animPos + adjustment,ZERO,0.5f,2.0f,1000); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere(pGrab->GetWorldPos() + m_grabStats.entityGrabSpot, 0.5f, ColorB(0,255,0,100)); } //if there are multiple limbs, only the first one sets the rotation of the object. if (m_grabStats.useIKRotation && i == 0 && m_grabStats.grabDelay<0.001f) { // NOTE Aug 8, 2007: <pvl> the idea here is to store current world // rotations of both the object being grabbed and the end bone of // a grabbing limb. Then track how the end bone rotates with respect // to the stored original rotation and rotate the grabbed object // the same way. That way, the grabbed object rotates the same as // the limb and appears to be "stabbed" by it. QuatT endBoneWorldRot = GetGrabBoneWorldTM (); endBoneWorldRot.q.Normalize(); // may not be necessary - just to be safe if ( ! m_grabStats.origRotationsValid) { m_grabStats.origRotation = pGrab->GetRotation(); m_grabStats.origRotation.Normalize(); // may not be necessary - just to be safe m_grabStats.origEndBoneWorldRot = endBoneWorldRot; m_grabStats.origRotationsValid = true; } Quat grabQuat( (endBoneWorldRot*m_grabStats.origEndBoneWorldRot.GetInverted()).q * m_grabStats.origRotation); grabQuat.Normalize(); // NOTE Dez 14, 2006: <pvl> this code sets up and look vectors for the grabbed // entity in case it's an Actor (the player, mostly) so that the player always // looks roughly at the grabber. The grabber is supposed to be the Hunter here // so this code is somewhat Hunter-specific. // UPDATE Aug 7, 2007: <pvl> do the above for the player only // UPDATE Sep 13, 2007: <pvl> don't do it for anybody ATM, it doesn't seem useful CActor *pGrabbedActor = (CActor *)g_pGame->GetIGameFramework()->GetIActorSystem()->GetActor(m_grabStats.grabId); if (false && pGrabbedActor && pGrabbedActor->IsClient() && pGrabbedActor->GetActorStats()) { Vec3 upVec(Quat(endBoneWorldRot.q * m_grabStats.additionalRotation).GetColumn2()); upVec.z = fabs_tpl(upVec.z) * 2.0f; upVec.NormalizeSafe(Vec3(0,0,1)); SActorStats *pAS = pGrabbedActor->GetActorStats(); if (pAS) { pAS->forceUpVector = upVec; pAS->forceLookVector = (pEnt->GetSlotWorldTM(0) * m_pActor->GetLocalEyePos(0)) - pGrabbedActor->GetEntity()->GetWorldPos(); float lookLen(pAS->forceLookVector.len()); pAS->forceLookVector *= (1.0f/lookLen)*0.33f; //pAS->forceLookVector = -Quat(boneRot * m_grabStats.additionalRotation).GetColumn1();//boneRot.GetColumn2(); } } else { pGrab->SetRotation(grabQuat,ENTITY_XFORM_USER); } } } if (m_grabStats.grabDelay<0.001f) { // NOTE Sep 16, 2007: <pvl> now that grabbed entity rotation coming from // a grabbing bone (if any) is computed, bone-space offset can be applied Matrix34 tm(pGrab->GetWorldTM()); tm.AddTranslation(GetGrabBoneWorldTM().q * m_grabStats.boneGrabOffset); pGrab->SetWorldTM(tm,ENTITY_XFORM_USER); /* { // debug draw for the grab bone QuatT grabBoneWorldTM = GetGrabBoneWorldTM(); Vec3 start = grabBoneWorldTM.t; Vec3 end = start + grabBoneWorldTM.q * Vec3 (1,0,0) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (255,0,0), end, ColorB (0,0,255), 6.0f); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere (start, 0.5f, ColorB (255,128,0)); } */ /* { // draw complete coord systems for both the end bone and the grabbed thing QuatT grabBoneWorldTM = GetGrabBoneWorldTM(); Vec3 start = grabBoneWorldTM.t; Vec3 end = start + grabBoneWorldTM.q * Vec3 (1,0,0) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (128,0,0), end, ColorB (128,0,0), 6.0f); end = start + grabBoneWorldTM.q * Vec3 (0,1,0) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (0,128,0), end, ColorB (0,128,0), 6.0f); end = start + grabBoneWorldTM.q * Vec3 (0,0,1) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (0,0,128), end, ColorB (0,0,128), 6.0f); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere (start, 0.2f, ColorB (255,255,255)); start = pGrab->GetWorldTM().GetTranslation(); end = start + pGrab->GetRotation() * Vec3 (1,0,0) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (128,0,0), end, ColorB (128,0,0), 6.0f); end = start + pGrab->GetRotation() * Vec3 (0,1,0) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (0,128,0), end, ColorB (0,128,0), 6.0f); end = start + pGrab->GetRotation() * Vec3 (0,0,1) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (0,0,128), end, ColorB (0,0,128), 6.0f); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere (start, 0.2f, ColorB (64,64,64)); } */ } /* { // debug draw for the grabbed object Vec3 start = pGrab->GetWorldTM().GetTranslation(); Vec3 end = start + pGrab->GetRotation() * Vec3 (0,0,1) * 3; gEnv->pRenderer->GetIRenderAuxGeom()->DrawLine (start, ColorB (255,0,0), end, ColorB (0,0,255), 6.0f); gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere (start, 0.2f, ColorB (255,128,0)); } */ }