//------------------------------------------------------------------------ void CVehicleDamageBehaviorBlowTire::Activate(bool activate) { if (activate == m_isActive) return; if (activate && m_pVehicle->IsDestroyed()) return; if (activate) { // NOTE: stance and physics position when getting into vehicles is set wrong if (!gEnv->pSystem->IsSerializingFile()) DamagePlayers(); } IVehicleComponent* pComponent = m_pVehicle->GetComponent(m_component.c_str()); if (!pComponent) return; IVehiclePart* pPart = pComponent->GetPart(0); if (!pPart) return; // if IVehicleWheel available, execute full damage behavior. if null, only apply effects IVehicleWheel* pWheel = pPart->GetIWheel(); if (activate) { IEntity* pEntity = m_pVehicle->GetEntity(); IPhysicalEntity* pPhysics = pEntity->GetPhysics(); const Matrix34& wheelTM = pPart->GetLocalTM(false); const SVehicleStatus& status = m_pVehicle->GetStatus(); if (pWheel) { const pe_cargeomparams* pParams = pWheel->GetCarGeomParams(); // handle destroyed wheel pe_params_wheel wheelParams; wheelParams.iWheel = pWheel->GetWheelIndex(); wheelParams.minFriction = wheelParams.maxFriction = 0.5f * pParams->maxFriction; pPhysics->SetParams(&wheelParams); if (IVehicleMovement* pMovement = m_pVehicle->GetMovement()) { SVehicleMovementEventParams params; params.pComponent = pComponent; params.iValue = pWheel->GetWheelIndex(); pMovement->OnEvent(IVehicleMovement::eVME_TireBlown, params); } if (status.speed > 0.1f) { // add angular impulse pe_action_impulse angImp; float amount = m_pVehicle->GetMass() * status.speed * Random(0.25f, 0.45f) * -sgn(wheelTM.GetTranslation().x); angImp.angImpulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount)); pPhysics->Action(&angImp); } m_aiImmobilizedTimer = m_pVehicle->SetTimer(-1, AI_IMMOBILIZED_TIME*1000, this); } if (!gEnv->pSystem->IsSerializingFile()) { // add linear impulse pe_action_impulse imp; imp.point = pPart->GetWorldTM().GetTranslation(); float amount = m_pVehicle->GetMass() * Random(0.1f, 0.15f); if (pWheel) { amount *= max(0.5f, min(10.f, status.speed)); if (status.speed < 0.1f) amount = -0.5f*amount; } else amount *= 0.5f; imp.impulse = pEntity->GetWorldTM().TransformVector(Vec3(0,0,amount)); pPhysics->Action(&imp); // effect IParticleEffect* pEffect = gEnv->pParticleManager->FindEffect(TIRE_BLOW_EFFECT); if (pEffect) { int slot = pEntity->LoadParticleEmitter(-1, pEffect); if (slot > -1) { float rotation = pWheel ? 0.5f * gf_PI * -sgn(wheelTM.GetTranslation().x) : gf_PI; Matrix34 tm = Matrix34::CreateRotationZ(rotation); tm.SetTranslation(wheelTM.GetTranslation()); pEntity->SetSlotLocalTM(slot, tm); } } // remove affected decals { Vec3 pos = pPart->GetWorldTM().GetTranslation(); AABB aabb = pPart->GetLocalBounds(); float radius = aabb.GetRadius(); Vec3 vRadius(radius,radius,radius); AABB areaBox(pos-vRadius, pos+vRadius); IRenderNode * pRenderNode = NULL; if (IEntityRenderProxy *pRenderProxy = (IEntityRenderProxy*)pEntity->GetProxy(ENTITY_PROXY_RENDER)) pRenderNode = pRenderProxy->GetRenderNode(); gEnv->p3DEngine->DeleteDecalsInRange(&areaBox, pRenderNode); } } } else { if (pWheel) { // restore wheel properties IPhysicalEntity* pPhysics = m_pVehicle->GetEntity()->GetPhysics(); pe_params_wheel wheelParams; for (int i=0; i<m_pVehicle->GetWheelCount(); ++i) { const pe_cargeomparams* pParams = m_pVehicle->GetWheelPart(i)->GetIWheel()->GetCarGeomParams(); wheelParams.iWheel = i; wheelParams.bBlocked = 0; wheelParams.suspLenMax = pParams->lenMax; wheelParams.bDriving = pParams->bDriving; wheelParams.minFriction = pParams->minFriction; wheelParams.maxFriction = pParams->maxFriction; pPhysics->SetParams(&wheelParams); } if (IVehicleMovement* pMovement = m_pVehicle->GetMovement()) { SVehicleMovementEventParams params; params.pComponent = pComponent; params.iValue = pWheel->GetWheelIndex(); // reset the particle status pMovement->OnEvent(IVehicleMovement::eVME_TireRestored, params); } } m_aiImmobilizedTimer = -1; } m_isActive = activate; }
//------------------------------------------------------------------------ bool CVehicleMovementStdBoat::Init(IVehicle* pVehicle, const CVehicleParams& table) { if (!CVehicleMovementBase::Init(pVehicle, table)) return false; MOVEMENT_VALUE("velMax", m_velMax); MOVEMENT_VALUE("velMaxReverse", m_velMaxReverse); MOVEMENT_VALUE("acceleration", m_accel); MOVEMENT_VALUE("accelerationVelMax", m_accelVelMax); MOVEMENT_VALUE("accelerationMultiplier", m_accelCoeff); MOVEMENT_VALUE("pushTilt", m_pushTilt); MOVEMENT_VALUE("turnRateMax", m_turnRateMax); MOVEMENT_VALUE("turnAccel", m_turnAccel); MOVEMENT_VALUE("cornerForce", m_cornerForceCoeff); MOVEMENT_VALUE("cornerTilt", m_cornerTilt); MOVEMENT_VALUE("turnDamping", m_turnDamping); MOVEMENT_VALUE("turnAccelMultiplier", m_turnAccelCoeff); MOVEMENT_VALUE_OPT("rollAccel", m_rollAccel, table); MOVEMENT_VALUE_OPT("pedalLimitReverse", m_pedalLimitReverse, table); MOVEMENT_VALUE_OPT("turnVelocityMult", m_turnVelocityMult, table); MOVEMENT_VALUE_OPT("velLift", m_velLift, table); MOVEMENT_VALUE_OPT("lateralDamping", m_lateralDamping, table); table.getAttr("waveIdleStrength", m_waveIdleStrength); table.getAttr("waveSpeedMult", m_waveSpeedMult); if (table.haveAttr("cornerHelper")) { if (IVehicleHelper* pHelper = m_pVehicle->GetHelper(table.getAttr("cornerHelper"))) m_cornerOffset = pHelper->GetVehicleSpaceTranslation(); } if (table.haveAttr("pushHelper")) { if (IVehicleHelper* pHelper = m_pVehicle->GetHelper(table.getAttr("pushHelper"))) m_pushOffset = pHelper->GetVehicleSpaceTranslation(); } // compute inertia [assumes box] AABB bbox; IVehiclePart* pMassPart = pVehicle->GetPart("mass"); if (!pMassPart) pMassPart = pVehicle->GetPart("massBox"); if (pMassPart) { bbox = pMassPart->GetLocalBounds(); } else { GameWarning("[CVehicleMovementStdBoat]: initialization: No \"mass\" geometry found!"); m_pEntity->GetLocalBounds(bbox); } m_maxSpeed = m_velMax; float mass = pVehicle->GetMass(); float width = bbox.max.x - bbox.min.x; float length = bbox.max.y - bbox.min.y; float height = bbox.max.z - bbox.min.z; m_Inertia.x = mass * (sqr(length)+ sqr(height)) / 12; m_Inertia.y = mass * (sqr(width) + sqr(height)) / 12; m_Inertia.z = mass * (sqr(width) + sqr(length)) / 12; m_massOffset = bbox.GetCenter(); //CryLog("[StdBoat movement]: got mass offset (%f, %f, %f)", m_massOffset.x, m_massOffset.y, m_massOffset.z); m_pSplashPos = m_pVehicle->GetHelper("splashPos"); if (m_pSplashPos) m_lastWakePos = m_pSplashPos->GetWorldSpaceTranslation(); else m_lastWakePos = m_pVehicle->GetEntity()->GetWorldTM().GetTranslation(); const char* waveEffect = ""; MOVEMENT_VALUE_OPT("waveEffect", &waveEffect, table); m_pWaveEffect = gEnv->pParticleManager->FindEffect(waveEffect, "MovementStdBoat"); m_waveTimer = cry_random(0.0f, gf_PI); m_diving = false; m_wakeSlot = -1; m_waveSoundPitch = 0.f; m_rpmPitchDir = 0; m_waveSoundAmount = 0.1f; // AI related m_prevAngle = 0.0f; m_factorMaxSpeed = 1.f; m_factorAccel = 1.f; return true; }