void CWaterPuddle::ZapEnemiesOnPuddle(int ownTeam, EntityId shooterId, EntityId weaponId, float damage, int hitTypeId, IParticleEffect* hitEffect) { IGameVolumes::VolumeInfo volumeInfo; if (!GetVolumeInfoForEntity(GetEntityId(), &volumeInfo)) return; IEntity* pEntity = GetEntity(); Matrix34 worldTM = pEntity->GetWorldTM(); float waterLevel = worldTM.GetTranslation().z + volumeInfo.volumeHeight * 0.5f; CActorManager* pActorManager = CActorManager::GetActorManager(); const int numberOfActors = pActorManager->GetNumActors(); for(int i = 0; i < numberOfActors; i++) { SActorData actorData; pActorManager->GetNthActorData(i, actorData); bool isActorAlive = (actorData.health > 0.0f); bool isActorEnemy = (actorData.teamId != ownTeam); bool isActorInsidevolume = IsActorInsideVolume(worldTM, volumeInfo, actorData.entityId); if (isActorAlive && isActorEnemy && isActorInsidevolume) ApplyHit(actorData, shooterId, weaponId, damage, hitTypeId, waterLevel, hitEffect); } }
void CGameVolume_Water::DebugDrawVolume() { IGameVolumes::VolumeInfo volumeInfo; if (GetVolumeInfoForEntity(GetEntityId(), volumeInfo) == false) return; if (volumeInfo.verticesCount < 3) return; const Matrix34 worldTM = GetEntity()->GetWorldTM(); const Vec3 depthOffset = worldTM.GetColumn2().GetNormalized() * - m_volumeDepth; IRenderAuxGeom* pRenderAux = gEnv->pRenderer->GetIRenderAuxGeom(); for (uint32 i = 0; i < volumeInfo.verticesCount - 1; ++i) { const Vec3 point1 = worldTM.TransformPoint(volumeInfo.pVertices[i]); const Vec3 point2 = worldTM.TransformPoint(volumeInfo.pVertices[i + 1]); pRenderAux->DrawLine( point1, Col_SlateBlue, point1 + depthOffset, Col_SlateBlue, 2.0f ); pRenderAux->DrawLine( point1 + depthOffset, Col_SlateBlue, point2 + depthOffset, Col_SlateBlue, 2.0f ); } const Vec3 firstPoint = worldTM.TransformPoint(volumeInfo.pVertices[0]); const Vec3 lastPoint = worldTM.TransformPoint(volumeInfo.pVertices[volumeInfo.verticesCount - 1]); pRenderAux->DrawLine( lastPoint, Col_SlateBlue, lastPoint + depthOffset, Col_SlateBlue, 2.0f ); pRenderAux->DrawLine( lastPoint + depthOffset, Col_SlateBlue, firstPoint + depthOffset, Col_SlateBlue, 2.0f ); }
void CGameVolume_Water::SetupVolume() { IGameVolumes::VolumeInfo volumeInfo; if (GetVolumeInfoForEntity(GetEntityId(), volumeInfo) == false) return; if (volumeInfo.verticesCount < 3) return; WaterProperties waterProperties(GetEntity()); if(waterProperties.isRiver) { if(volumeInfo.verticesCount < 4 || volumeInfo.verticesCount % 2 != 0) return; int numSegments = (volumeInfo.verticesCount / 2) - 1; m_segments.resize(numSegments); for(int i = 0; i < numSegments; ++i) { SetupVolumeSegment(waterProperties, i, &volumeInfo.pVertices[0], volumeInfo.verticesCount); } } else { SetupVolumeSegment(waterProperties, 0, &volumeInfo.pVertices[0], volumeInfo.verticesCount); } #if CRY_PLATFORM_WINDOWS && !defined(_RELEASE) { if (gEnv->IsEditor()) { IEntity* pEnt = GetEntity(); IMaterial* pMat = pEnt ? pEnt->GetMaterial() : 0; if (pMat) { const SShaderItem& si = pMat->GetShaderItem(); if (si.m_pShader && si.m_pShader->GetShaderType() != eST_Water) { CryWarning(VALIDATOR_MODULE_3DENGINE, VALIDATOR_ERROR, "Incorrect shader set for water / water fog volume \"%s\"!", pEnt->GetName()); } } } } #endif m_baseMatrix = GetEntity()->GetWorldTM(); m_initialMatrix = m_baseMatrix; m_volumeDepth = waterProperties.depth; m_streamSpeed = waterProperties.streamSpeed; m_awakeAreaWhenMoving = waterProperties.awakeAreaWhenMoving; m_isRiver = waterProperties.isRiver; }
void CGameVolume_Water::HandleEvent( const SGameObjectEvent& gameObjectEvent ) { if ((gameObjectEvent.event == eGFE_ScriptEvent) && (gameObjectEvent.param != NULL)) { const char* eventName = static_cast<const char*>(gameObjectEvent.param); if (strcmp(eventName, "PhysicsEnable") == 0) { IGameVolumes::VolumeInfo volumeInfo; if (GetVolumeInfoForEntity(GetEntityId(), volumeInfo)) { for(uint32 i = 0; i < m_segments.size(); ++i) { SWaterSegment& segment = m_segments[i]; if ((segment.m_pWaterArea == NULL) && (segment.m_pWaterRenderNode != NULL)) { if(!m_isRiver) { CreatePhysicsArea(i, m_baseMatrix, &volumeInfo.pVertices[0], volumeInfo.verticesCount, false, m_streamSpeed); } else { Vec3 vertices[4]; FillOutRiverSegment(i, &volumeInfo.pVertices[0], volumeInfo.verticesCount, &vertices[0]); CreatePhysicsArea(i, m_baseMatrix, vertices, 4, true, m_streamSpeed); } segment.m_pWaterRenderNode->SetMatrix( m_baseMatrix ); } } AwakeAreaIfRequired( true ); m_lastAwakeCheckPosition.zero(); } } else if (strcmp(eventName, "PhysicsDisable") == 0) { DestroyPhysicsAreas(); } } }
CWaterPuddle* CWaterPuddleManager::FindWaterPuddle(Vec3 point) { size_t numPuddles = m_waterPuddles.size(); for (size_t i = 0; i < numPuddles; ++i) { EntityId puddle = m_waterPuddles[i].m_entityId; IEntity* pEntity = gEnv->pEntitySystem->GetEntity(puddle); if (!pEntity) continue; IGameVolumes::VolumeInfo volumeInfo; if (!GetVolumeInfoForEntity(puddle, &volumeInfo)) continue; if (IsPointInsideVolume(pEntity->GetWorldTM(), volumeInfo, point, 0.0f)) return m_waterPuddles[i].m_pPuddle; } return 0; }
void CGameVolume_Water::ProcessEvent( SEntityEvent& event) { switch(event.event) { case ENTITY_EVENT_EDITOR_PROPERTY_CHANGED: { SetupVolume(); } break; case ENTITY_EVENT_RESET: { // Only when exiting game mode if ((gEnv->IsEditor()) && (event.nParam[0] == 0)) { if ( Matrix34::IsEquivalent( m_baseMatrix,m_initialMatrix ) == false) { GetEntity()->SetWorldTM( m_initialMatrix ); } } } break; case ENTITY_EVENT_XFORM: { // Rotation requires to setup again // Internally the shape vertices are projected to a plane, and rotating changes that plane // Only allow rotations in the editor, at run time can be expensive if ((gEnv->IsEditing()) && (event.nParam[0] & ENTITY_XFORM_ROT)) { SetupVolume(); } else if (event.nParam[0] & ENTITY_XFORM_POS) { const Matrix34 entityWorldTM = GetEntity()->GetWorldTM(); m_baseMatrix.SetTranslation(entityWorldTM.GetTranslation()); for(uint32 i = 0; i < m_segments.size(); ++i) { SWaterSegment& segment = m_segments[i]; UpdateRenderNode( segment.m_pWaterRenderNode, m_baseMatrix ); if( segment.m_pWaterArea ) { const Vec3 newAreaPosition = m_baseMatrix.GetTranslation() + ((Quat(m_baseMatrix) * segment.m_physicsLocalAreaCenter) - segment.m_physicsLocalAreaCenter); pe_params_pos position; position.pos = newAreaPosition; segment.m_pWaterArea->SetParams( &position ); pe_params_buoyancy pb; pb.waterPlane.origin = newAreaPosition; segment.m_pWaterArea->SetParams( &pb ); //gEnv->pRenderer->GetIRenderAuxGeom()->DrawSphere( areaPos.pos, 0.5f, ColorB(255, 0, 0)); } } AwakeAreaIfRequired( false ); } } break; case ENTITY_EVENT_HIDE: { AwakeAreaIfRequired( true ); WaterSegments::iterator iter = m_segments.begin(); WaterSegments::iterator end = m_segments.end(); while(iter != end) { if (iter->m_pWaterRenderNode) { iter->m_pWaterRenderNode->Hide(true); } ++iter; } DestroyPhysicsAreas(); } break; case ENTITY_EVENT_UNHIDE: { IGameVolumes::VolumeInfo volumeInfo; if (GetVolumeInfoForEntity(GetEntityId(), volumeInfo)) { for(uint32 i = 0; i < m_segments.size(); ++i) { SWaterSegment& segment = m_segments[i]; if (segment.m_pWaterRenderNode) { segment.m_pWaterRenderNode->Hide(false); if(!m_isRiver) { CreatePhysicsArea(i, m_baseMatrix, &volumeInfo.pVertices[0], volumeInfo.verticesCount, false, m_streamSpeed); } else { Vec3 vertices[4]; FillOutRiverSegment(i, &volumeInfo.pVertices[0], volumeInfo.verticesCount, &vertices[0]); CreatePhysicsArea(i, m_baseMatrix, vertices, 4, true, m_streamSpeed); } segment.m_pWaterRenderNode->SetMatrix( m_baseMatrix ); } } AwakeAreaIfRequired( true ); m_lastAwakeCheckPosition.zero(); //After unhide, next movement will awake the area } } break; } }