/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . * */ /* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of Penumbra Overture. */ #include "hpl1/penumbra-overture/PlayerHelper.h" #include "hpl1/penumbra-overture/DeathMenu.h" #include "hpl1/penumbra-overture/GameArea.h" #include "hpl1/penumbra-overture/GameEnemy.h" #include "hpl1/penumbra-overture/GameEntity.h" #include "hpl1/penumbra-overture/GameMusicHandler.h" #include "hpl1/penumbra-overture/GameObject.h" #include "hpl1/penumbra-overture/Init.h" #include "hpl1/penumbra-overture/Inventory.h" #include "hpl1/penumbra-overture/MapHandler.h" #include "hpl1/penumbra-overture/Notebook.h" #include "hpl1/penumbra-overture/NumericalPanel.h" #include "hpl1/penumbra-overture/Player.h" #include "hpl1/penumbra-overture/PlayerHands.h" ////////////////////////////////////////////////////////////////////////// // HIT GROUND CALLBACK ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerBodyCallback::cPlayerBodyCallback(cPlayer *apPlayer) { mpPlayer = apPlayer; cInit *pInit = apPlayer->GetInit(); mfFallSpeed_Min = pInit->mpGameConfig->GetFloat("Player", "FallSpeed_Min", 0); mfFallDamage_Min = pInit->mpGameConfig->GetFloat("Player", "FallDamage_Min", 0); msFallSound_Min = pInit->mpGameConfig->GetString("Player", "FallSound_Min", ""); mfFallSpeed_Med = pInit->mpGameConfig->GetFloat("Player", "FallSpeed_Med", 0); mfFallDamage_Med = pInit->mpGameConfig->GetFloat("Player", "FallDamage_Med", 0); msFallSound_Med = pInit->mpGameConfig->GetString("Player", "FallSound_Med", ""); mfFallSpeed_Max = pInit->mpGameConfig->GetFloat("Player", "FallSpeed_Max", 0); mfFallDamage_Max = pInit->mpGameConfig->GetFloat("Player", "FallDamage_Max", 0); msFallSound_Max = pInit->mpGameConfig->GetString("Player", "FallSound_Max", ""); } //----------------------------------------------------------------------- void cPlayerBodyCallback::OnHitGround(iCharacterBody *apCharBody, const cVector3f &avVel) { // if(avVel.y < -5.5f) // mpPlayer->FootStep(1.0f,"run",true); if (mpPlayer->GetMoveState() == ePlayerMoveState_Jump) { if (avVel.y < 0) { if (avVel.y < -3.5f) { mpPlayer->FootStep(1.0f, "run", true); } mpPlayer->SetLandedFromJump(true); } } else if (avVel.y < -8.5f) { mpPlayer->FootStep(1.0f, "run", true); } tString sSound = ""; float fVol = 1.0f; cSoundHandler *pSoundHandler = mpPlayer->GetInit()->mpGame->GetSound()->GetSoundHandler(); // Log("Speed: %f\n",avVel.y); ///////////////////// // Fall damage // Hard if (avVel.y < mfFallSpeed_Max) { sSound = msFallSound_Max; fVol = 1.0f; mpPlayer->Damage(mfFallDamage_Max, ePlayerDamageType_BloodSplash); pSoundHandler->PlayGui("player_fall_damage", false, 1); // Log("Hard\n"); } // Medium else if (avVel.y < mfFallSpeed_Med) { sSound = msFallSound_Med; fVol = 1.0f; mpPlayer->Damage(mfFallDamage_Med, ePlayerDamageType_BloodSplash); pSoundHandler->PlayGui("player_fall_damage", false, 0.75f); // Log("Medium\n"); } // Light else if (avVel.y < mfFallSpeed_Min) { sSound = msFallSound_Min; fVol = 1.0f; mpPlayer->Damage(mfFallDamage_Min, ePlayerDamageType_BloodSplash); pSoundHandler->PlayGui("player_fall_damage", false, 0.5f); // Log("Light\n"); } if (sSound != "") { cWorld3D *pWorld = mpPlayer->GetInit()->mpGame->GetScene()->GetWorld3D(); cSoundEntity *pSound = pWorld->CreateSoundEntity("HitGround", sSound, true); if (pSound) { iCharacterBody *pCharBody = mpPlayer->GetCharacterBody(); pSound->SetVolume(fVol * pSound->GetVolume()); pSound->SetPosition(pCharBody->GetPosition() - cVector3f(0, pCharBody->GetSize().y / 2 - 0.2f, 0)); } } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // GROUND RAY CALLBACK ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerGroundRayCallback::cPlayerGroundRayCallback() { mpMaterial = NULL; mbOnGround = false; } //----------------------------------------------------------------------- void cPlayerGroundRayCallback::Clear() { mfMinDist = 1000; mpMaterial = NULL; } //----------------------------------------------------------------------- void cPlayerGroundRayCallback::OnWorldExit() { mpMaterial = NULL; } void cPlayerGroundRayCallback::Reset() { mpMaterial = NULL; } //----------------------------------------------------------------------- bool cPlayerGroundRayCallback::OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams) { mbOnGround = true; if (apParams->mfDist < mfMinDist && pBody->GetMaterial()->GetSurfaceData() && pBody->GetMaterial()->GetSurfaceData()->GetStepType() != "") { mpMaterial = pBody->GetMaterial(); mfMinDist = apParams->mfDist; } return true; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PICK RAY CALLBACK ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerPickRayCallback::cPlayerPickRayCallback() { mfMaxDistance = 10.0f; mpPickedBody = NULL; mLastEntityType = eGameEntityType_LastEnum; } //----------------------------------------------------------------------- void cPlayerPickRayCallback::Clear() { mfPickedDist = mfMaxDistance + 10.0f; mfPickedAreaDist = mfMaxDistance + 10.0f; mpPickedBody = NULL; mpPickedAreaBody = NULL; mfMinStaticDist = mfMaxDistance + 10.0f; } //----------------------------------------------------------------------- void cPlayerPickRayCallback::OnWorldExit() { mpPickedBody = NULL; } //----------------------------------------------------------------------- bool cPlayerPickRayCallback::OnIntersect(iPhysicsBody *apBody, cPhysicsRayParams *apParams) { float &fDist = apParams->mfDist; // Must be positive if (fDist <= 0) return true; // Must be below max distance if (fDist > mfMaxDistance) return true; // No characters allowed if (apBody->IsCharacter()) return true; // Check if is below current picked dist iGameEntity *pEntity = NULL; if (apBody->GetUserData()) pEntity = (iGameEntity *)apBody->GetUserData(); ////////////////////////////// // Entity if (pEntity) { // Skip stick area if (pEntity->GetType() == eGameEntityType_StickArea) return true; // Area if (pEntity->GetType() == eGameEntityType_Area || pEntity->GetType() == eGameEntityType_StickArea || pEntity->GetType() == eGameEntityType_DamageArea || pEntity->GetType() == eGameEntityType_ForceArea) { if (mfPickedAreaDist > fDist && (pEntity->GetDescription() != _W("") || pEntity->GetCallbackScript(eGameEntityScriptType_PlayerInteract) != NULL || pEntity->GetCallbackScript(eGameEntityScriptType_PlayerExamine) != NULL || pEntity->GetHasInteraction())) { mfPickedAreaDist = fDist; mvPickedAreaPos = apParams->mvPoint; mpPickedAreaBody = apBody; } } // Other entity else { if (mfPickedDist > fDist) { mfPickedDist = fDist; mvPickedPos = apParams->mvPoint; mpPickedBody = apBody; } } } /////////////////////////////// // Non Entity else { if (mfPickedDist > fDist) { mfPickedDist = fDist; mpPickedBody = NULL; } } return true; } void cPlayerPickRayCallback::CalculateResults() { // Check if an area is closer than the closest normal body if (mpPickedAreaBody && mfPickedAreaDist < mfPickedDist) { bool bUseArea = false; if (mpPickedBody) { iGameEntity *pEntity = (iGameEntity *)mpPickedBody->GetUserData(); // cGameArea *pArea = (cGameArea *)mpPickedAreaBody->GetUserData(); if (pEntity) { // Too for from object if (pEntity->GetMaxExamineDist() < mfPickedDist) bUseArea = true; // No description for object and it is not possible to interact with it else if (pEntity->GetDescription() == _W("")) { if (mpPickedBody->GetMass() == 0) bUseArea = true; else if (pEntity->GetType() == eGameEntityType_Object) { cGameObject *pObject = static_cast(pEntity); if (pObject->GetInteractMode() == eObjectInteractMode_Static) bUseArea = true; } } } else { bUseArea = true; } } else { bUseArea = true; } if (bUseArea) { mpPickedBody = mpPickedAreaBody; mfPickedDist = mfPickedAreaDist; mvPickedPos = mvPickedAreaPos; } } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // HEAD MOVE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerHeadMove::cPlayerHeadMove(cPlayer *apPlayer) { mfAdd = 0; mfPos = 0; mbActive = false; mpPlayer = apPlayer; mbFootStepped = false; mbWasActive = false; mfClimbCount = 0; mfClimbPos = 0; } //----------------------------------------------------------------------- void cPlayerHeadMove::Update(float afTimeStep) { /////////////////////////////// // Climb count iCharacterBody *pBody = mpPlayer->GetCharacterBody(); /*float fUpVel = (pBody->GetPosition().y - pBody->GetLastPosition().y) / afTimeStep;*/ if (pBody->IsClimbing() && mfClimbCount == 0) { mfClimbCount = 0.5f; mfClimbPos = mfPos; } else if (mfClimbCount > 0) { mfClimbCount -= afTimeStep; if (mfClimbCount < 0) { mfClimbCount = 0; mfPos = mfClimbPos; mfAdd = mfHeadMoveSpeed; } } /////////////////////////////// // Head movement if (mbActive) { mbWasActive = true; mfPos += mfAdd * afTimeStep * mpPlayer->GetHeadMoveSpeedMul(); if (mfAdd < 0) { if (mfPos <= mfMinHeadMove * mpPlayer->GetHeadMoveSpeedMul()) { mfPos = mfMinHeadMove * mpPlayer->GetHeadMoveSpeedMul(); mfAdd = mfHeadMoveSpeed; // Create a footstep. if (mfFootStepMul > 0) mpPlayer->FootStep(mfFootStepMul); mbFootStepped = true; } } else { if (mfPos >= mfMaxHeadMove * mpPlayer->GetHeadMoveSpeedMul()) { mfPos = mfMaxHeadMove * mpPlayer->GetHeadMoveSpeedMul(); mfAdd = -mfHeadMoveSpeed; } } } else { if (mbWasActive == true && (mbFootStepped == false || (mfPos < 0 && mfAdd < 0))) { if (mfFootStepMul > 0) mpPlayer->FootStep(mfFootStepMul * 0.6f); } mbFootStepped = false; mbWasActive = false; if (mfPos == 0) return; if (mfPos < 0) { mfPos += mfHeadMoveBackSpeed * afTimeStep; if (mfPos > 0) { mfPos = 0; } } else { mfPos -= mfHeadMoveBackSpeed * afTimeStep; if (mfPos < 0) { mfPos = 0; } } } } //----------------------------------------------------------------------- void cPlayerHeadMove::Start() { if (mbActive == false) { mbActive = true; } if (fabs(fabs(mfAdd) - mfHeadMoveSpeed) > 0.001f) { mfAdd = mfHeadMoveSpeed; } } void cPlayerHeadMove::Stop() { mbActive = false; } //----------------------------------------------------------------------- float cPlayerHeadMove::GetPos() { if (mfClimbCount > 0) return mfClimbPos; return mfPos; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // HEALTH ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerHealth::cPlayerHealth(cInit *apInit) { mpInit = apInit; mfTimeCount = 0; mpDrawer = mpInit->mpGame->GetGraphics()->GetDrawer(); mpDamageGfx = mpDrawer->CreateGfxObject("player_hurt.bmp", "diffalpha2d"); mfGfxAlpha = 0; mfGfxAlphaAdd = 0; mfGfxGlobalAlpha = 0; mfTerrorCheckCount = 0; mpSoundEntry = NULL; } //----------------------------------------------------------------------- void cPlayerHealth::Reset() { mfTerrorCheckCount = 0; if (mpSoundEntry) mpSoundEntry->mpSound->Stop(); mpSoundEntry = NULL; mlTerrorLevel = 0; } //----------------------------------------------------------------------- void cPlayerHealth::Update(float afTimeStep) { cPlayer *pPlayer = mpInit->mpPlayer; if (pPlayer->GetHealth() <= 0) { if (mpSoundEntry) mpSoundEntry->mpSound->Stop(); mpSoundEntry = NULL; mfGfxAlpha -= afTimeStep * 2.0f; return; } //////////////////////////// // ALpha mfGfxAlpha += mfGfxAlphaAdd * afTimeStep; if (mfGfxAlphaAdd < 0 && mfGfxAlpha < 0) mfGfxAlpha = 0; if (mfGfxAlphaAdd > 0 && mfGfxAlpha >= 1.0f) { mfGfxAlpha = 1.0f; mfGfxAlphaAdd = -1.5; } //////////////////////////// // Heart timer if (mfTimeCount <= 0) { if (pPlayer->GetHealth() > 50) { pPlayer->SetHealthSpeedMul(1.0f); mfGfxGlobalAlpha = 0; } else { float fVolume = 0.5; if (pPlayer->GetHealth() > 25) { mfTimeCount = 1.7f; pPlayer->SetHealthSpeedMul(0.8f); mfGfxGlobalAlpha = 0.5f; } else if (pPlayer->GetHealth() > 10) { mfTimeCount = 1.0; fVolume = 0.75f; pPlayer->SetHealthSpeedMul(0.6f); mfGfxGlobalAlpha = 0.75f; } else { mfTimeCount = 0.7f; fVolume = 1.0f; pPlayer->SetHealthSpeedMul(0.4f); mfGfxGlobalAlpha = 1.0f; } mpInit->mpGame->GetSound()->GetSoundHandler()->PlayGui("player_heartbeat", false, fVolume); mfGfxAlphaAdd = 3.5f; } } else { mfTimeCount -= afTimeStep; } //////////////////////////// // Increase health over time: switch (mpInit->mDifficulty) { case eGameDifficulty_Easy: pPlayer->AddHealth(afTimeStep * 1.4f); break; case eGameDifficulty_Normal: pPlayer->AddHealth(afTimeStep * 0.4f); break; case eGameDifficulty_Hard: pPlayer->AddHealth(afTimeStep * 0.14f); break; case eGameDifficulty_LastEnum: break; } } void cPlayerHealth::Draw() { if (mfGfxAlpha <= 0) return; mpDrawer->DrawGfxObject(mpDamageGfx, cVector3f(0, 0, 50), cVector2f(800, 600), cColor(1, mfGfxGlobalAlpha * mfGfxAlpha)); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // EAR RING ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerEarRing::cPlayerEarRing(cInit *apInit, cPlayer *apPlayer) { mpInit = apInit; mpPlayer = apPlayer; mpSoundEntry = NULL; mfTimeCount = 0; mbDeaf = false; } //----------------------------------------------------------------------- void cPlayerEarRing::Reset() { cSoundHandler *pSoundHandler = mpInit->mpGame->GetSound()->GetSoundHandler(); if (mpSoundEntry) mpSoundEntry->mpSound->Stop(); pSoundHandler->SetVolume(1.0f, 0.1f, eSoundDest_World); mpSoundEntry = NULL; mfTimeCount = 0; mbDeaf = false; } //----------------------------------------------------------------------- void cPlayerEarRing::Update(float afTimeStep) { if (mfTimeCount > 0) { cSoundHandler *pSoundHandler = mpInit->mpGame->GetSound()->GetSoundHandler(); mfTimeCount -= afTimeStep; mfDeafTime -= afTimeStep; if (mbDeaf && mfDeafTime <= 0) { mbDeaf = false; pSoundHandler->SetVolume(0.2f, 1.5f, eSoundDest_World); } if (mfTimeCount <= 0) { mfTimeCount = 0; pSoundHandler->SetVolume(1.0f, 3.5f, eSoundDest_World); if (mpSoundEntry) { mpSoundEntry->mfNormalVolumeFadeDest = 0; mpSoundEntry->mfNormalVolumeFadeSpeed = -0.25f; mpSoundEntry = NULL; } } } } //----------------------------------------------------------------------- void cPlayerEarRing::Start(float afTime) { if (mpInit->mpPlayer->GetHealth() <= 0) return; if (mfTimeCount > 0) { } else { cSoundHandler *pSoundHandler = mpInit->mpGame->GetSound()->GetSoundHandler(); iSoundChannel *pChannel = pSoundHandler->PlayGui("player_ear_ring", true, 0.5f); pChannel->SetPriority(200); mpSoundEntry = pSoundHandler->GetEntryFromSound(pChannel); mpSoundEntry->mfNormalVolumeMul = 0; mpSoundEntry->mfNormalVolumeFadeDest = 1; mpSoundEntry->mfNormalVolumeFadeSpeed = 0.55f; pSoundHandler->SetVolume(0.0f, 1.2f, eSoundDest_World); } mfTimeCount = afTime; mbDeaf = true; mfDeafTime = afTime * 0.3f; } //----------------------------------------------------------------------- void cPlayerEarRing::Stop(bool abStopDirectly) { cSoundHandler *pSoundHandler = mpInit->mpGame->GetSound()->GetSoundHandler(); if (abStopDirectly) { if (mpSoundEntry) mpSoundEntry->mpSound->Stop(); mpSoundEntry = NULL; pSoundHandler->SetVolume(1, 5, eSoundDest_World); } else { mfTimeCount = 0; pSoundHandler->SetVolume(1.0f, 3.5f, eSoundDest_World); if (mpSoundEntry) { mpSoundEntry->mfNormalVolumeFadeDest = 0; mpSoundEntry->mfNormalVolumeFadeSpeed = -0.25f; mpSoundEntry = NULL; } } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // LEAN ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerLean::cPlayerLean(cInit *apInit, cPlayer *apPlayer) { mpPlayer = apPlayer; mpInit = apInit; mfMaxMovement = 0.5f; mfMaxRotation = cMath::ToRad(15); mpHeadShape = NULL; } void cPlayerLean::Reset() { mfDir = 0; mfMaxTime = 0.8f; mfMovement = 0; mfRotation = 0; mfMoveSpeed = 0; mbPressed = false; } //----------------------------------------------------------------------- void cPlayerLean::OnWorldLoad() { iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); float fRadius = mpInit->mpPlayer->GetSize().x / 2 * 0.63f; float fHeight = mpInit->mpPlayer->GetCameraHeightAdd() * 2; if (fHeight < 0) fHeight = fHeight * -1; cMatrixf mtxOffset = cMath::MatrixRotateZ(kPi2f); mpHeadShape = pPhysicsWorld->CreateCylinderShape(fRadius, fHeight, &mtxOffset); } //----------------------------------------------------------------------- void cPlayerLean::Update(float afTimeStep) { //////////////////////////////// // If pressed move in direction if (mbPressed) { mbPressed = false; float fGoalPos = mfMaxMovement * mfDir; float fGoalRot = mfMaxRotation * -mfDir; ////////////// // Position float fPrevMovement = mfMovement; float fMoveSpeed = (fGoalPos - mfMovement); if (fabsf(fMoveSpeed) < 0.1f) fMoveSpeed = 0.1f * mfDir; mfMovement += fMoveSpeed * afTimeStep * 3; if (fGoalPos < 0 && mfMovement < fGoalPos) mfMovement = fGoalPos; if (fGoalPos > 0 && mfMovement > fGoalPos) mfMovement = fGoalPos; ////////////// // Rotation float fPrevRotation = mfRotation; float fRotSpeed = fGoalRot - mfRotation; if (fabsf(fRotSpeed) < 0.13f) fRotSpeed = 0.13f * -mfDir; mfRotation += fRotSpeed * afTimeStep * 2; if (fGoalRot < 0 && mfRotation < fGoalRot) mfRotation = fGoalRot; if (fGoalRot > 0 && mfRotation > fGoalRot) mfRotation = fGoalRot; //////////////////// // Check collision cCamera3D *pCam = mpInit->mpPlayer->GetCamera(); iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); float fReverseMov = fPrevMovement - mfMovement; float fReverseRot = fPrevRotation - mfRotation; iCharacterBody *pCharBody = mpPlayer->GetCharacterBody(); float fHeightAdd = mpPlayer->GetSize().y + mpPlayer->GetHeightAdd() + mpPlayer->GetCameraHeightAdd(); cVector3f vStartPos = pCharBody->GetFeetPosition() + cVector3f(0, fHeightAdd, 0); cVector3f vPos = vStartPos + pCam->GetRight() * mfMovement; int lCount = 0; while (pPhysicsWorld->CheckShapeWorldCollision(NULL, mpHeadShape, cMath::MatrixTranslate(vPos), NULL, false, true, NULL, false)) { mfMovement += fReverseMov; mfRotation += fReverseRot; if (fReverseMov < 0 && mfMovement < 0) { mfMovement = 0; mfRotation = 0; break; } if (fReverseMov > 0 && mfMovement > 0) { mfMovement = 0; mfRotation = 0; break; } vPos = vStartPos + pCam->GetRight() * mfMovement; lCount++; if (lCount > 10) { mfMovement = 0; mfRotation = 0; break; } } } //////////////////////////// // Not pressed move back else { float fMoveSpeed = (0 - mfMovement); mfMovement += fMoveSpeed * afTimeStep * 6; float fRotSpeed = 0 - mfRotation; mfRotation += fRotSpeed * afTimeStep * 3; } mpPlayer->GetCamera()->AddRoll(mfRotation); } //----------------------------------------------------------------------- bool cPlayerLean::OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams) { if (pBody == mpPlayer->GetCharacterBody()->GetBody()) return true; mbIntersect = true; return false; } //----------------------------------------------------------------------- void cPlayerLean::Lean(float afMul, float afTimeStep) { mbPressed = true; mfDir = afMul; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // DAMAGE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerDamage::cPlayerDamage(cInit *apInit) { mpInit = apInit; mpDrawer = mpInit->mpGame->GetGraphics()->GetDrawer(); mpPostEffects = mpInit->mpGame->GetGraphics()->GetRendererPostEffects(); mbActive = false; mType = ePlayerDamageType_BloodSplash; mvHitGfx[ePlayerDamageType_BloodSplash] = mpDrawer->CreateGfxObject("player_hit_blood_splash.bmp", "diffalpha2d"); mvHitGfx[ePlayerDamageType_Ice] = mpDrawer->CreateGfxObject("player_hit_ice.bmp", "diffalpha2d"); mvHeadSwingAcc = cVector2f(17.0f, 17.0f); } cPlayerDamage::~cPlayerDamage() { for (int i = 0; i < ePlayerDamageType_LastEnum; ++i) mpDrawer->DestroyGfxObject(mvHitGfx[i]); } //----------------------------------------------------------------------- void cPlayerDamage::Start(float afSize, ePlayerDamageType aType) { if (mbActive) return; mfSize = afSize; mType = aType; mfAlpha = 0; mfAlphaAdd = 4.3f; mbActive = true; if (!mpInit->mpPlayer->GetFearFilter()->IsActive()) { mpPostEffects->SetImageTrailActive(true); mpPostEffects->SetImageTrailAmount(0); } mvHeadSwingSpeed = cVector2f(cMath::RandRectf(-1, 1), cMath::RandRectf(0, 0.5f)); if (mvHeadSwingSpeed.x == 0 && mvHeadSwingSpeed.y == 0) mvHeadSwingSpeed.x = 1; else mvHeadSwingSpeed.Normalise(); mvHeadSwingSpeed = mvHeadSwingSpeed * afSize * 1.5f; mpInit->mpPlayer->GetCharacterBody()->SetMoveSpeed(eCharDir_Forward, 0); mpInit->mpPlayer->GetCharacterBody()->SetMoveSpeed(eCharDir_Right, 0); } //----------------------------------------------------------------------- void cPlayerDamage::Update(float afTimeStep) { if (mbActive == false) return; // Alpha update mfAlpha += mfAlphaAdd * afTimeStep; if (mfAlphaAdd > 0) { if (mfAlpha >= 1) { mfAlpha = 1; mfAlphaAdd = -2.2f; } } else if (mfAlphaAdd < 0) { if (mfAlpha <= 0) { mfAlpha = 0; } } // Update swing mpInit->mpPlayer->GetCamera()->AddYaw(mvHeadSwingSpeed.x * afTimeStep); mpInit->mpPlayer->GetCamera()->AddPitch(mvHeadSwingSpeed.y * afTimeStep); if (mvHeadSwingSpeed.x > 0) { mvHeadSwingSpeed.x -= (mvHeadSwingAcc.x / mfSize) * afTimeStep * 2.2f; if (mvHeadSwingSpeed.x < 0) mvHeadSwingSpeed.x = 0; } else { mvHeadSwingSpeed.x += (mvHeadSwingAcc.x / mfSize) * afTimeStep * 2.2f; if (mvHeadSwingSpeed.x > 0) mvHeadSwingSpeed.x = 0; } if (mvHeadSwingSpeed.y > 0) { mvHeadSwingSpeed.y -= (mvHeadSwingAcc.x / mfSize) * afTimeStep * 2.2f; if (mvHeadSwingSpeed.y < 0) mvHeadSwingSpeed.y = 0; } else { mvHeadSwingSpeed.y += (mvHeadSwingAcc.x / mfSize) * afTimeStep * 2.2f; if (mvHeadSwingSpeed.y > 0) mvHeadSwingSpeed.y = 0; } // Blur update if (mpInit->mpPlayer->IsDead() == false) { if (!mpInit->mpPlayer->GetFearFilter()->IsActive()) { mpPostEffects->SetImageTrailAmount(mfAlpha * 0.92f); } } // Has it ended? if (mvHeadSwingSpeed.x == 0 && mvHeadSwingSpeed.y == 0 && mfAlpha == 0) { mbActive = false; if (mpInit->mpPlayer->IsDead() == false) { if (!mpInit->mpPlayer->GetFearFilter()->IsActive()) { mpPostEffects->SetImageTrailActive(false); mpPostEffects->SetImageTrailAmount(0); } } } } //----------------------------------------------------------------------- void cPlayerDamage::Draw() { if (mbActive == false) return; mpDrawer->DrawGfxObject(mvHitGfx[mType], cVector3f(0, 0, 3), cVector2f(800, 600), cColor(1, mfAlpha * 0.6f)); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // DEATH ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerDeath::cPlayerDeath(cInit *apInit) { mpInit = apInit; mpDrawer = mpInit->mpGame->GetGraphics()->GetDrawer(); mpPostEffects = mpInit->mpGame->GetGraphics()->GetRendererPostEffects(); mpFadeGfx = mpDrawer->CreateGfxObject("player_death_fade.bmp", "smoke2d"); mpBlackGfx = mpDrawer->CreateGfxObject("player_death_black.bmp", "smoke2d"); } cPlayerDeath::~cPlayerDeath() { mpDrawer->DestroyGfxObject(mpFadeGfx); } //----------------------------------------------------------------------- void cPlayerDeath::Reset() { mbActive = false; mfHeightAdd = 0; mfRoll = 0; mpPostEffects->SetImageTrailActive(false); } //----------------------------------------------------------------------- void cPlayerDeath::Start() { if (mbActive) return; if (mpInit->mpInventory->IsActive()) mpInit->mpInventory->SetActive(false); if (mpInit->mpNotebook->IsActive()) mpInit->mpNotebook->SetActive(false); if (mpInit->mpNumericalPanel->IsActive()) mpInit->mpNumericalPanel->SetActive(false); mpInit->mpPlayer->GetFlashLight()->SetActive(false); mpInit->mpPlayer->GetGlowStick()->SetActive(false); mpInit->mpPlayer->GetFlare()->SetActive(false); mpInit->mpPlayerHands->SetCurrentModel(0, ""); mpInit->mpPlayerHands->SetCurrentModel(1, ""); mpInit->mpPlayer->ChangeState(ePlayerState_Normal); mfHeightAdd = 0; mfRoll = 0; mfMinHeightAdd = -1.3f; if (mpInit->mpPlayer->GetMoveState() == ePlayerMoveState_Crouch) mfMinHeightAdd = -0.7f; mbActive = true; mbStartFade = false; mfFadeAlpha = 0; mfBlackAlpha = 0; mpPostEffects->SetImageTrailActive(true); mpPostEffects->SetImageTrailAmount(0.7f); mpInit->mpPlayer->GetEarRing()->Stop(false); for (int i = 0; i <= 10; ++i) { mpInit->mpMusicHandler->Stop(0.2f, i); } } //----------------------------------------------------------------------- void cPlayerDeath::Update(float afTimeStep) { if (mbActive == false) return; mfHeightAdd -= 0.95f * afTimeStep; if (mfHeightAdd < mfMinHeightAdd) { mfHeightAdd = mfMinHeightAdd; mbStartFade = true; mpInit->mpDeathMenu->SetActive(true); } mfRoll += cMath::ToRad(40.0f) * afTimeStep; if (mfRoll > cMath::ToRad(65.0f)) mfRoll = cMath::ToRad(65.0f); mpInit->mpPlayer->GetCamera()->AddRoll(mfRoll); if (mbStartFade) { mfFadeAlpha += 0.7f * afTimeStep; if (mfFadeAlpha > 1) mfFadeAlpha = 1; if (mfFadeAlpha > 0.6f) { mfBlackAlpha += 0.45f * afTimeStep; if (mfBlackAlpha > 1) mfBlackAlpha = 1; } } } //----------------------------------------------------------------------- void cPlayerDeath::Draw() { if (mbActive == false) return; cVector3f vPos(-mfFadeAlpha * 400 - mfBlackAlpha * 200, -mfFadeAlpha * 400 - mfBlackAlpha * 200, 4); cVector2f vSize(800 + mfFadeAlpha * 800 + mfBlackAlpha * 400, 600 + mfFadeAlpha * 800 + mfBlackAlpha * 400); mpDrawer->DrawGfxObject(mpFadeGfx, vPos, vSize, cColor(mfFadeAlpha, 0)); mpDrawer->DrawGfxObject(mpBlackGfx, cVector3f(0, 0, 5), cVector2f(800, 600), cColor(mfBlackAlpha, 0)); } //----------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////// // FLASHLIGHT ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerFlashLight::cPlayerFlashLight(cInit *apInit) { mpInit = apInit; mpInit->mpPlayerHands->AddModelFromFile("hud_object_flashlight.hud"); Reset(); } //----------------------------------------------------------------------- cPlayerFlashLight::~cPlayerFlashLight() { } //----------------------------------------------------------------------- void cPlayerFlashLight::Reset() { mbActive = false; mfAlpha = 0; mfFlickerTime = 0; mfRayCastTime = 0; mpClosestBody = NULL; mfClosestDist = 10000.0f; mbDisabled = false; } //----------------------------------------------------------------------- bool cPlayerFlashLight::OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams) { if (pBody->GetCollide() == false) return true; if (pBody->IsCharacter() && pBody == mpInit->mpPlayer->GetCharacterBody()->GetBody()) return true; if (apParams->mfDist < mfClosestDist) { mfClosestDist = apParams->mfDist; mpClosestBody = pBody; } return true; } //----------------------------------------------------------------------- void cPlayerFlashLight::OnWorldLoad() { } //----------------------------------------------------------------------- void cPlayerFlashLight::Update(float afTimeStep) { if (mbActive) { ////////////////////////// // Hits enemy if (mfRayCastTime >= 1) // 1.0f/20.0f) { mfRayCastTime = 0; cCamera3D *pCam = mpInit->mpPlayer->GetCamera(); iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); iHudModel *pHudModel = mpInit->mpPlayerHands->GetModel("Flashlight"); cVector3f vForward = pCam->GetForward(); if (pHudModel && pHudModel->GetEntity()) { vForward = cMath::MatrixMul( pHudModel->GetEntity()->GetWorldMatrix().GetRotation(), cVector3f(0, -1, 0)); } if (pHudModel == mpInit->mpPlayerHands->GetCurrentModel(0)) { tGameEnemyIterator it = mpInit->mpMapHandler->GetGameEnemyIterator(); while (it.HasNext()) { iGameEnemy *pEnemy = it.Next(); if (pEnemy->GetHealth() <= 0 || pEnemy->IsActive() == false) continue; cVector3f vToEnemy = pEnemy->GetMover()->GetCharBody()->GetPosition() - mpInit->mpPlayer->GetCharacterBody()->GetPosition(); float fSqrDist = vToEnemy.SqrLength(); vToEnemy.Normalise(); if (fSqrDist < 100.0f) { float fAngle = cMath::Vector3Angle(vToEnemy, vForward); if (fAngle < cMath::ToRad(25)) { cVector3f vStart = pCam->GetPosition(); cVector3f vEnd = pEnemy->GetMover()->GetCharBody()->GetPosition(); mvStart = vStart; mvEnd = vEnd; mpClosestBody = NULL; mfClosestDist = 10000.0f; pPhysicsWorld->CastRay(this, vStart, vEnd, true, false, false, false); if (mpClosestBody == NULL || mpClosestBody->IsCharacter() == true) { if (pEnemy->GetUsesTriggers()) { pEnemy->OnFlashlight(pCam->GetPosition()); } } } } } } } else { mfRayCastTime += afTimeStep; } } iHudModel *pHudModel = mpInit->mpPlayerHands->GetCurrentModel(0); ////////////////////////// // Player power if (mbActive && mpInit->mpInventory->IsActive() == false && mpInit->mpNotebook->IsActive() == false && mpInit->mpNumericalPanel->IsActive() == false) { mpInit->mpPlayer->AddPower(-0.1f * afTimeStep); if (mpInit->mpPlayer->GetPower() == 0) { SetActive(false); } } ////////////////////////// // Flicker at low energy if (mbActive && mpInit->mpInventory->IsActive() == false && pHudModel->msName == "Flashlight") { if (mpInit->mpPlayer->GetPower() < 3.0f) { if (mfFlickerTime <= 0) { if (pHudModel->mvLights[0]->IsVisible()) { pHudModel->mvLights[0]->SetVisible(false); pHudModel->mvBillboards[0]->SetVisible(false); mfFlickerTime = cMath::RandRectf(0.04f, 0.15f); cSoundHandler *pSoundHanlder = mpInit->mpGame->GetSound()->GetSoundHandler(); pSoundHanlder->PlayGui("item_flashlight_flicker", false, 1); } else { pHudModel->mvLights[0]->SetVisible(true); pHudModel->mvBillboards[0]->SetVisible(true); mfFlickerTime = cMath::RandRectf(0.05f, 1.5f); } } else { mfFlickerTime -= afTimeStep; } } } } //----------------------------------------------------------------------- void cPlayerFlashLight::SetActive(bool abX) { cSoundHandler *pSoundHanlder = mpInit->mpGame->GetSound()->GetSoundHandler(); if (abX && (mpInit->mpPlayer->GetPower() == 0 || mbDisabled)) { pSoundHanlder->PlayGui("item_flashlight_nopower", false, 1); return; } if (mbActive == abX) return; mbActive = abX; ///////////////////////////// // Active if (mbActive) { mpInit->mpPlayerHands->SetCurrentModel(0, "Flashlight"); // pSoundHanlder->PlayGui("item_flashlight_on",false,1); } ///////////////////////////// // Not active else if (mpInit->mpPlayerHands->GetCurrentModel(0) && mpInit->mpPlayerHands->GetCurrentModel(0)->msName == "Flashlight" && mpInit->mpPlayerHands->GetCurrentModel(0)->GetState() != eHudModelState_Unequip) { mpInit->mpPlayerHands->SetCurrentModel(0, ""); if (mpInit->mpPlayer->GetPower() == 0) pSoundHanlder->PlayGui("item_flashlight_nopower", false, 1); // else // pSoundHanlder->PlayGui("item_flashlight_off",false,1); } } //----------------------------------------------------------------------- void cPlayerFlashLight::SetDisabled(bool abX) { if (abX == true) SetActive(false); mbDisabled = abX; } //----------------------------------------------------------------------- void cPlayerFlashLight::OnPostSceneDraw() { /*iLowLevelGraphics *mpLowGfx = mpInit->mpGame->GetGraphics()->GetLowLevel(); mpLowGfx->DrawLine(mvStart,mvEnd,cColor(1,0,1));*/ } //----------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////// // GLOW STICK ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerGlowStick::cPlayerGlowStick(cInit *apInit) { mpInit = apInit; mpInit->mpPlayerHands->AddModelFromFile("hud_object_glowstick.hud"); Reset(); } //----------------------------------------------------------------------- cPlayerGlowStick::~cPlayerGlowStick() { } //----------------------------------------------------------------------- void cPlayerGlowStick::Reset() { mbActive = false; } //----------------------------------------------------------------------- void cPlayerGlowStick::OnWorldLoad() { } //----------------------------------------------------------------------- void cPlayerGlowStick::Destroy() { } //----------------------------------------------------------------------- void cPlayerGlowStick::Update(float afTimeStep) { } //----------------------------------------------------------------------- void cPlayerGlowStick::SetActive(bool abX) { if (mbActive == abX) return; mbActive = abX; /*cSoundHandler *pSoundHanlder = */ mpInit->mpGame->GetSound()->GetSoundHandler(); if (mbActive) { // Log("Setting the glowstick to TRUE\n"); mpInit->mpPlayerHands->SetCurrentModel(0, "Glowstick"); // pSoundHanlder->PlayGui("item_glowstick_on",false,1); } else if (mpInit->mpPlayerHands->GetCurrentModel(0) && mpInit->mpPlayerHands->GetCurrentModel(0)->msName == "Glowstick" && mpInit->mpPlayerHands->GetCurrentModel(0)->GetState() != eHudModelState_Unequip) { // Log("Setting the glowstick to FALSE\n"); mpInit->mpPlayerHands->SetCurrentModel(0, ""); // pSoundHanlder->PlayGui("item_glowstick_off",false,1); } } //----------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////// // FLARE ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerFlare::cPlayerFlare(cInit *apInit) { mpInit = apInit; mpInit->mpPlayerHands->AddModelFromFile("hud_object_flare.hud"); mfTime = mpInit->mpGameConfig->GetFloat("Items", "FlareGlowTime", 1); mfLightPulse = 1.0f; mfLightPulseAdd = 0.88f; mpLight = NULL; Reset(); } //----------------------------------------------------------------------- cPlayerFlare::~cPlayerFlare() { } //----------------------------------------------------------------------- void cPlayerFlare::Reset() { mbActive = false; mpLight = NULL; } //----------------------------------------------------------------------- void cPlayerFlare::OnWorldLoad() { mpLight = NULL; } //----------------------------------------------------------------------- void cPlayerFlare::Update(float afTimeStep) { if (mbActive) { ////////////////////////////////////// // Model entities are loaded and light gotten if (mpLight) { ////////////////////// // Fade at end if (mfTime <= 30) { mfLightRadius = (mfTime / 30.0f) * mfMaxLightRadius; } float fRadius = mfLightRadius; ////////////////////// // Pulse mfLightPulse += mfLightPulseAdd * afTimeStep; if (mfLightPulseAdd > 0 && mfLightPulse >= 1.0f) { mfLightPulse = 1.0f; mfLightPulseAdd = -mfLightPulseAdd; } if (mfLightPulseAdd < 0 && mfLightPulse <= 0.0f) { mfLightPulse = 0.0f; mfLightPulseAdd = -mfLightPulseAdd; } fRadius = (mfLightPulse * 0.4f + 0.8f) * mfLightRadius; if (mpLight) mpLight->SetFarAttenuation(fRadius); ////////////////////// // Time if (mpInit->mpInventory->IsActive() == false && mpInit->mpNotebook->IsActive() == false && mpInit->mpNumericalPanel->IsActive() == false) { mfTime -= afTimeStep; if (mfTime <= 0) { SetActive(false); } } } ////////////////////////////////////// // Model entities not loaded yet else { if (mpModel == mpInit->mpPlayerHands->GetCurrentModel(0)) { if (mpModel->mvLights.empty() == false) { mpLight = mpModel->mvLights[0]; mfMaxLightRadius = mpLight->GetFarAttenuation(); mfLightRadius = mfMaxLightRadius; } else { Warning("No lights in flare!\n"); } } } } } //----------------------------------------------------------------------- void cPlayerFlare::SetActive(bool abX) { if (mbActive == abX) return; mbActive = abX; /*cSoundHandler *pSoundHanlder = */ mpInit->mpGame->GetSound()->GetSoundHandler(); if (mbActive) { mpInit->mpPlayerHands->SetCurrentModel(0, "Flare"); if (mpInit->mpPlayer->GetFlashLight()->IsActive()) mpInit->mpPlayer->GetFlashLight()->SetActive(false); if (mpInit->mpPlayer->GetGlowStick()->IsActive()) mpInit->mpPlayer->GetGlowStick()->SetActive(false); mfTime = mpInit->mpGameConfig->GetFloat("Items", "FlareGlowTime", 1); mpModel = mpInit->mpPlayerHands->GetModel("Flare"); mpLight = NULL; } else { /////////////////////////////// // Check if hud model should be put down. if (mpInit->mpPlayerHands->GetCurrentModel(0) && mpInit->mpPlayerHands->GetCurrentModel(0)->msName == "Flare" && mpInit->mpPlayerHands->GetCurrentModel(0)->GetState() != eHudModelState_Unequip) { mpInit->mpPlayerHands->SetCurrentModel(0, ""); } /////////////////////////////// // Create entity cCamera3D *pCam = mpInit->mpPlayer->GetCamera(); cVector3f vRot = cVector3f(pCam->GetPitch(), pCam->GetYaw(), pCam->GetRoll()); cMatrixf mtxStart = cMath::MatrixRotate(vRot, eEulerRotationOrder_XYZ); mtxStart.SetTranslation(pCam->GetPosition()); iEntity3D *pEntity = mpInit->mpGame->GetScene()->GetWorld3D()->CreateEntity("Throw", mtxStart, "items_flare_thrown.ent", true); if (pEntity) { iGameEntity *pEntity2 = mpInit->mpMapHandler->GetLatestEntity(); cVector3f vRot2 = cMath::MatrixMul(mtxStart.GetRotation(), cVector3f(1, 0.3f, 0)); for (int i = 0; i < pEntity2->GetBodyNum(); ++i) { iPhysicsBody *pBody = pEntity2->GetBody(i); pBody->AddImpulse(pCam->GetForward() * 3.0f); pBody->AddTorque(vRot2); } // setup light if (mfTime <= 30) { float fRadius = (mfTime / 30.0f); if (fRadius < 0) fRadius = 0; for (int i = 0; i < pEntity2->GetLightNum(); ++i) { iLight3D *pLight = pEntity2->GetLight(i); pLight->SetFarAttenuation(pLight->GetFarAttenuation() * fRadius); } } } } } //----------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////// // NOISE FILTER ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerNoiseFilter::cPlayerNoiseFilter(cInit *apInit) { mpInit = apInit; mpDrawer = mpInit->mpGame->GetGraphics()->GetDrawer(); mlAmount = 6; for (int i = 0; i < mlAmount; ++i) { tString sFileName = "effect_noise0" + cString::ToString(i); cGfxObject *pObject = mpDrawer->CreateGfxObject(sFileName, "smoke2d"); if (pObject == NULL) { error("Error loading noise filter"); } mvGfxNoise.push_back(pObject); } Hpl1::resizeAndFill(mvCurrentGfx, 20 * 15, cMath::RandRectl(0, mlAmount - 1)); mfAlpha = 0.3f; mfTimeCount = 0; mbActive = mpInit->mpConfig->GetBool("Graphics", "NoiseFilter", true); } //----------------------------------------------------------------------- cPlayerNoiseFilter::~cPlayerNoiseFilter() { mpInit->mpConfig->SetBool("Graphics", "NoiseFilter", mbActive); for (size_t i = 0; i < mvGfxNoise.size(); ++i) { mpDrawer->DestroyGfxObject(mvGfxNoise[i]); } } //----------------------------------------------------------------------- void cPlayerNoiseFilter::Draw() { if (mbActive == false) return; for (int x = 0; x < 20; ++x) for (int y = 0; y < 15; ++y) { cVector3f vPos((float)x * 40, (float)y * 40, 0); mpDrawer->DrawGfxObject(mvGfxNoise[mvCurrentGfx[x * y]], vPos, 40, cColor(mfAlpha, 0)); // mpDrawer->DrawGfxObject(mvGfxNoise[0],vPos,40,cColor(mfAlpha,mfAlpha)); } } //----------------------------------------------------------------------- void cPlayerNoiseFilter::Update(float afTimeStep) { if (mbActive == false) return; if (mfTimeCount <= 0) { for (int x = 0; x < 20; ++x) for (int y = 0; y < 15; ++y) { // Change the image int lCurrent = mvCurrentGfx[x * y]; int lRand = cMath::RandRectl(0, mlAmount - 1); if (lRand == lCurrent) { ++lRand; if (lRand >= mlAmount) lRand = 0; } mvCurrentGfx[x * y] = lRand; } mfTimeCount = 1 / 15.0f; } else { mfTimeCount -= afTimeStep; } } //----------------------------------------------------------------------- void cPlayerNoiseFilter::SetActive(bool abX) { mbActive = abX; } //----------------------------------------------------------------------- //////////////////////////////////////////////////////////////////////// // FEAR FILTER ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerFearFilter::cPlayerFearFilter(cInit *apInit) { mpInit = apInit; Reset(); } //----------------------------------------------------------------------- cPlayerFearFilter::~cPlayerFearFilter() { } //----------------------------------------------------------------------- void cPlayerFearFilter::Draw() { } //----------------------------------------------------------------------- void cPlayerFearFilter::Update(float afTimeStep) { if (mpInit->mpPlayer->IsDead()) return; if (mbActive) { mfAlpha += afTimeStep * 0.5f; if (mfAlpha > mfMaxAlpha) mfAlpha = mfMaxAlpha; mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailAmount(mfAlpha); } else if (mfAlpha > 0) { mfAlpha -= afTimeStep * 0.15f; if (mfAlpha < 0) { mfAlpha = 0; mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailActive(false); } else { mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailAmount(mfAlpha); } } } //----------------------------------------------------------------------- void cPlayerFearFilter::Reset() { mbActive = false; mfAlpha = 0; mfMaxAlpha = 0.58f; } //----------------------------------------------------------------------- void cPlayerFearFilter::SetActive(bool abX) { if (mbActive == abX) return; mbActive = abX; mfAlpha = 0; mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailActive(true); mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailAmount(0); } //----------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////// // LOOK AT ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerLookAt::cPlayerLookAt(cPlayer *apPlayer) { mpPlayer = apPlayer; Reset(); } //----------------------------------------------------------------------- cPlayerLookAt::~cPlayerLookAt() { } //----------------------------------------------------------------------- void cPlayerLookAt::Update(float afTimeStep) { if (mbActive == false) return; cCamera3D *pCam = mpPlayer->GetCamera(); cVector3f vGoalAngle = cMath::GetAngleFromPoints3D(pCam->GetPosition(), mvTargetPos); // Get distance to goal cVector3f vDist; vDist.x = cMath::GetAngleDistanceRad(pCam->GetPitch(), vGoalAngle.x); vDist.y = cMath::GetAngleDistanceRad(pCam->GetYaw(), vGoalAngle.y); // Get the Speed cVector3f vSpeed; vSpeed.x = cMath::Min(vDist.x * mfSpeedMul, mfMaxSpeed); vSpeed.y = cMath::Min(vDist.y * mfSpeedMul, mfMaxSpeed); // Add Pitch pCam->AddPitch(vSpeed.x * afTimeStep); // Add yaw pCam->AddYaw(vSpeed.y * afTimeStep); mpPlayer->GetCharacterBody()->SetYaw(pCam->GetYaw()); } void cPlayerLookAt::Reset() { mbActive = false; mfMaxSpeed = 9999.0f; mfSpeedMul = 1.0f; mvTargetPos = cVector3f(0, 1, 0); } void cPlayerLookAt::SetTarget(const cVector3f &avTargetPos, float afSpeedMul, float afMaxSpeed) { mvTargetPos = avTargetPos; mfSpeedMul = afSpeedMul; mfMaxSpeed = afMaxSpeed; } void cPlayerLookAt::SetActive(bool abX) { mbActive = abX; } //----------------------------------------------------------------------- ///////////////////////////////////////////////////////////////////////// // HIDDEN ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cPlayerHidden::cPlayerHidden(cInit *apInit) { mpInit = apInit; mpRenderer = mpInit->mpGame->GetGraphics()->GetRenderer3D(); mpDrawer = mpInit->mpGame->GetGraphics()->GetDrawer(); mpSoundHandler = mpInit->mpGame->GetSound()->GetSoundHandler(); mfUpdateCount = 1.0f / 3.0f; cVector2f vScreenSize = mpInit->mpGame->GetGraphics()->GetLowLevel()->GetScreenSize(); mfStartEffectOffset = 40; mfHiddenEffectOffset = 0; mfEffectOffsetAdd = mfStartEffectOffset - mfHiddenEffectOffset; mfStartAspect = vScreenSize.x / vScreenSize.y; mfHiddenAspect = mfStartAspect * 0.82f; mfAspectAdd = mfStartAspect - mfHiddenAspect; mfStartFov = cMath::ToRad(70); mfHiddenFov = cMath::ToRad(78); mfFovAdd = mfHiddenFov - mfStartFov; mfEnemyTooCloseMax = 4.5f; mfCloseEffectFovMax = cMath::ToRad(2); mfCloseEffectFovMin = cMath::ToRad(-11); Reset(); // Get images mpInShadowGfx = mpDrawer->CreateGfxObject("player_in_shadow.jpg", "diffadditive2d"); // Get font mpFont = mpInit->mpGame->GetResources()->GetFontManager()->CreateFontData("verdana.fnt"); } //----------------------------------------------------------------------- cPlayerHidden::~cPlayerHidden() { } //----------------------------------------------------------------------- void cPlayerHidden::OnWorldLoad() { cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); mpLight = pWorld->CreateLightPoint("HiddenLight"); mpLight->SetFarAttenuation(13); mpLight->SetDiffuseColor(cColor(0, 0, 0, 0)); mpLight->SetVisible(false); mpLight->SetCastShadows(false); } void cPlayerHidden::OnWorldExit() { } //----------------------------------------------------------------------- void cPlayerHidden::Draw() { // Draw in shadow effect if (mfInShadowAlpha > 0) { float fAlpha = (mfInShadowPulse * 0.5f + 0.5f) * mfInShadowAlpha * 0.85f; mpDrawer->DrawGfxObject(mpInShadowGfx, cVector3f(-mfEffectOffset, -mfEffectOffset, 0), cVector2f(800 + mfEffectOffset * 2, 600 + mfEffectOffset * 2), cColor(fAlpha, fAlpha)); } } //----------------------------------------------------------------------- void cPlayerHidden::UnHide() { if (mbHidden) { mpLight->FadeTo(cColor(0, 0, 0, 0), mpLight->GetFarAttenuation(), mfHiddenOffTime); if (mfHiddenOnCount > 2) mpSoundHandler->PlayGui("player_hidden_off", false, 1); } mbHidden = false; mfHiddenCount = 0; mfHiddenOnCount = 0; if (mbEnemyTooClose) { mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailActive(false); } mfEnemyTooCloseCount = 0; mbEnemyTooClose = false; } //----------------------------------------------------------------------- bool cPlayerHidden::InShadows() { if (mfLight <= mfMaxLight) return true; return false; } //----------------------------------------------------------------------- static float GetMaxRGB(const cColor &aCol) { float fAmount = aCol.r; if (fAmount < aCol.g) fAmount = aCol.g; if (fAmount < aCol.b) fAmount = aCol.b; return fAmount; } void cPlayerHidden::Update(float afTimeStep) { iCharacterBody *pCharBody = mpInit->mpPlayer->GetCharacterBody(); bool bIsCrouching = false; if (mpInit->mpPlayer->GetMoveState() == ePlayerMoveState_Crouch) bIsCrouching = true; /////////////////////////////////// // Update Hidden effect if (mbHidden) { // Aspect if (mfAspect > mfHiddenAspect) { mfAspect -= afTimeStep * mfAspectAdd * (1 / mfHiddenOnTime); if (mfAspect < mfHiddenAspect) mfAspect = mfHiddenAspect; mpInit->mpPlayer->GetCamera()->SetAspect(mfAspect); } // FOV if (mfFov < mfHiddenFov) { mfFov += afTimeStep * mfFovAdd * (1 / mfHiddenOnTime); if (mfFov > mfHiddenFov) mfFov = mfHiddenFov; mpInit->mpPlayer->GetCamera()->SetFOV(mfFov); } // Effect offset if (mfEffectOffset > mfHiddenEffectOffset) { mfEffectOffset -= afTimeStep * mfEffectOffsetAdd * (1 / mfHiddenOnTime); if (mfEffectOffset < mfHiddenEffectOffset) mfEffectOffset = mfHiddenEffectOffset; } } else { // Aspect if (mfAspect < mfStartAspect) { mfAspect += afTimeStep * mfAspectAdd * (1 / mfHiddenOffTime); if (mfAspect > mfStartAspect) mfAspect = mfStartAspect; mpInit->mpPlayer->GetCamera()->SetAspect(mfAspect); } // FOV if (mfFov > mfStartFov) { mfFov -= afTimeStep * mfFovAdd * (1 / mfHiddenOffTime); if (mfFov < mfStartFov) mfFov = mfStartFov; mpInit->mpPlayer->GetCamera()->SetFOV(mfFov); } // Effect offset if (mfEffectOffset < mfStartEffectOffset) { mfEffectOffset += afTimeStep * mfEffectOffsetAdd * (1 / mfHiddenOffTime); if (mfEffectOffset > mfStartEffectOffset) mfEffectOffset = mfStartEffectOffset; } } /////////////////////////////////// // Update In Shadow effect // Alpha if (mfLight <= mfMaxLight && bIsCrouching) { mfInShadowAlpha += afTimeStep; if (mfInShadowAlpha > 1) mfInShadowAlpha = 1; } else { mfInShadowAlpha -= afTimeStep; if (mfInShadowAlpha < 0) mfInShadowAlpha = 0; } // Pulse mfInShadowPulse += afTimeStep * mfInShadowPulseAdd; if (mfInShadowPulseAdd < 0 && mfInShadowPulse < 0) { mfInShadowPulse = 0; mfInShadowPulseAdd = -mfInShadowPulseAdd; } else if (mfInShadowPulseAdd > 0 && mfInShadowPulse > 1) { mfInShadowPulse = 1; mfInShadowPulseAdd = -mfInShadowPulseAdd; } if (mbInShadows) mpLight->SetPosition(mpInit->mpPlayer->GetCamera()->GetPosition()); ////////////////////////////////////////// // Check if the player is hidden if (mfLight <= mfMaxLight && bIsCrouching && mpInit->mpPlayer->GetHealth() > 0) { cVector3f vDiff = pCharBody->GetLastPosition() - pCharBody->GetPosition(); if (fabsf(vDiff.x) < 0.01f && fabsf(vDiff.y) < 0.01f && fabsf(vDiff.z) < 0.01f) { if (!mbHidden) { if (mfHiddenCount >= mfHiddenTime) { mbInShadows = false; mbHidden = true; mpLight->SetVisible(true); mpLight->SetPosition(mpInit->mpPlayer->GetCamera()->GetPosition()); mpLight->FadeTo(cColor(0.1f, 0.1f, 0.6f, 0), 12, mfHiddenOnTime); mpSoundHandler->PlayGui("player_hidden_on", false, 1); } else { mfHiddenCount += afTimeStep; } } else { mfHiddenOnCount += afTimeStep; } } else { UnHide(); } if (!mbHidden) { if (!mbInShadows) { mpLight->FadeTo(cColor(0.09f, 0.09f, 0.28f, 0), 6, 1); mpLight->SetVisible(true); } mbInShadows = true; } } else { if (mbInShadows) { mbInShadows = false; mpLight->FadeTo(cColor(0, 0, 0, 0), 8, 1); } UnHide(); } //////////////////////////////////////////7 // Update the current light level if (mfUpdateCount <= 0) { mfUpdateCount = 1.0f / 2.0f; mfLight = GetMaxRGB(mpInit->mpGame->GetGraphics()->GetRenderer3D()->GetAmbientColor()); cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); if (pWorld == NULL) return; iPhysicsWorld *pPhysicsWorld = pWorld->GetPhysicsWorld(); cBoundingVolume *pPlayerBV = pCharBody->GetBody()->GetBV(); // Just to be sure... if (mpInit->mpPlayer->GetFlashLight()->IsActive()) mfLight += 0.5; // Iterate lights cLight3DListIterator lightIt = pWorld->GetLightIterator(); while (lightIt.HasNext()) { iLight3D *pLight = lightIt.Next(); if (pLight == mpLight) continue; if (pLight->IsActive() == false || pLight->IsVisible() == false) continue; if (cMath::CheckCollisionBV(*pPlayerBV, *pLight->GetBoundingVolume())) { // Check line of sight if (HasLineOfSight(pLight, pPhysicsWorld) == false) continue; // Get highest value of rg b float fAmount = GetMaxRGB(pLight->GetDiffuseColor()); // Get distance to the light float fDist = cMath::Vector3Dist(pLight->GetWorldPosition(), pPlayerBV->GetWorldCenter()); // Calculate attenuation float fT = 1 - fDist / pLight->GetFarAttenuation(); if (fT < 0) fT = 0; fAmount *= fT; mfLight += fAmount; } } } else { mfUpdateCount -= afTimeStep; } //////////////////////////////////////////////////// // Check if enemy is too close and act accordingly. UpdateEnemyTooClose(afTimeStep); } //----------------------------------------------------------------------- bool cPlayerHidden::OnIntersect(iPhysicsBody *pBody, cPhysicsRayParams *apParams) { // bool bDebug = pBody->GetName() == "polySurface76"; if (pBody->IsCharacter() || pBody->GetCollide() == false || pBody->GetBlocksLight() == false) { // if(bDebug)Log("Out on first!\n"); return true; } iGameEntity *pEntity = (iGameEntity *)pBody->GetUserData(); if (pEntity && pEntity->GetMeshEntity()) { cMeshEntity *pMeshEntity = pEntity->GetMeshEntity(); if (pMeshEntity->IsShadowCaster() == false) return true; bool bFoundSolid = false; for (int i = 0; i < pMeshEntity->GetSubMeshEntityNum(); ++i) { iMaterial *pMaterial = pMeshEntity->GetSubMeshEntity(i)->GetMaterial(); if (pMaterial && (pMaterial->IsTransperant() == false && pMaterial->HasAlpha() == false)) { bFoundSolid = true; break; } } if (bFoundSolid == false) { // if(bDebug)Log("Out on non solid!\n"); return true; } } mbIntersected = true; // if(bDebug)Log("Intersection!!\n"); return false; } //----------------------------------------------------------------------- bool cPlayerHidden::HasLineOfSight(iLight3D *pLight, iPhysicsWorld *pPhysicsWorld) { if (pLight->GetCastShadows() == false) return true; if (mpRenderer->GetShowShadows() == eRendererShowShadows_None) return true; iCharacterBody *pCharBody = mpInit->mpPlayer->GetCharacterBody(); cVector3f vPlayerPos = pCharBody->GetPosition(); // Check frustum of spotlight if (pLight->GetLightType() == eLight3DType_Spot) { cLight3DSpot *pSpotLight = static_cast(pLight); if (pSpotLight->GetFrustum()->CollideBoundingVolume(pLight->GetBoundingVolume()) == eFrustumCollision_Outside) { return false; } } int lCount = 0; cVector3f vPosAdd[5]; int lPosAddNum = 5; // Centre vPosAdd[0] = cVector3f(0, 0, 0); // Head vPosAdd[1] = cVector3f(0, pCharBody->GetSize().y / 2 - 0.1f, 0); // Feet vPosAdd[2] = cVector3f(0, -(pCharBody->GetSize().y / 2 + 0.1f), 0); cVector3f vRight = cMath::Vector3Cross(cMath::Vector3Normalize(pLight->GetWorldPosition() - vPlayerPos), cVector3f(0, 1, 0)); // Right vPosAdd[3] = vRight * (pCharBody->GetSize().x * 0.4f); // Left vPosAdd[4] = vRight * (pCharBody->GetSize().x * -0.4f); for (int i = 0; i < lPosAddNum; ++i) { mbIntersected = false; pPhysicsWorld->CastRay(this, vPlayerPos + vPosAdd[i], pLight->GetWorldPosition(), false, false, false, false); if (mbIntersected) ++lCount; else { break; } } return lCount < lPosAddNum; } //----------------------------------------------------------------------- void cPlayerHidden::UpdateEnemyTooClose(float afTimeStep) { cCamera3D *pCam = mpInit->mpPlayer->GetCamera(); cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); if (pWorld == NULL) return; ///////////////////////////// // Update too close effect if (mbEnemyTooClose && mfEnemyTooCloseCount > 1.2f) { if (mfCloseEffectFovAdd > 0) { mfCloseEffectFov += mfCloseEffectFovAdd * afTimeStep; if (mfCloseEffectFov >= mfCloseEffectFovMax) { mfCloseEffectFovAdd = -mfCloseEffectFovAdd; mfCloseEffectFov = mfCloseEffectFovMax; if (mfEnemyTooCloseCount > mfEnemyTooCloseMax * 0.4f) mpSoundHandler->PlayGui("player_scare_mid", false, 1); else mpSoundHandler->PlayGui("player_scare_low", false, 1); } } else { mfCloseEffectFov += mfCloseEffectFovAdd * afTimeStep; if (mfCloseEffectFov <= mfCloseEffectFovMin) { mfCloseEffectFovAdd = -mfCloseEffectFovAdd; mfCloseEffectFov = mfCloseEffectFovMin; // if(mfEnemyTooCloseCount > mfEnemyTooCloseMax*0.6f) // mpSoundHandler->PlayGui("player_scare_mid",false,1); // else // mpSoundHandler->PlayGui("player_scare_low",false,1); } } float fAdd = 0; if (mfCloseEffectFov >= 0) { float fT = mfCloseEffectFov / mfCloseEffectFovMax; fAdd = sin(fT * kPi2f) * mfCloseEffectFovMax; } else { float fT = mfCloseEffectFov / mfCloseEffectFovMin; fAdd = sin(fT * kPi2f) * mfCloseEffectFovMin; } pCam->SetFOV(mfFov + fAdd); mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailActive(true); mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailAmount(0.8f); } else if (mfCloseEffectFov != 0) { mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailActive(false); if (mfCloseEffectFov < 0) { mfCloseEffectFov += afTimeStep * cMath::ToRad(7); if (mfCloseEffectFov > 0) mfCloseEffectFov = 0; } else { mfCloseEffectFov -= afTimeStep * cMath::ToRad(7); if (mfCloseEffectFov < 0) mfCloseEffectFov = 0; } float fAdd = 0; if (mfCloseEffectFov >= 0) { float fT = mfCloseEffectFov / mfCloseEffectFovMax; fAdd = sin(fT * kPi2f) * mfCloseEffectFovMax; } else { float fT = mfCloseEffectFov / mfCloseEffectFovMin; fAdd = sin(fT * kPi2f) * mfCloseEffectFovMin; } pCam->SetFOV(mfFov + fAdd); } ///////////////////////////// // Update the count if (InShadows()) // mbHidden) { if (mfCheckEnemyCloseCount <= 0) { // FIXME: Change value of FMaxDist when hidden? // float fMaxDist = mbHidden ? 11.0f : 11.0f; float fMaxDist = 11.0f; float fMaxDistSqr = fMaxDist * fMaxDist; // Reset variables mbEnemyTooClose = false; mfCheckEnemyCloseCount = 0.3f; /// Get needed data iPhysicsWorld *pPhysicsWorld = pWorld->GetPhysicsWorld(); // Iterate enemies tGameEnemyIterator enemyIt = mpInit->mpMapHandler->GetGameEnemyIterator(); while (enemyIt.HasNext()) { iGameEnemy *pEnemy = enemyIt.Next(); if (pEnemy->GetHealth() <= 0 || pEnemy->IsActive() == false) continue; iCharacterBody *pCharBody = pEnemy->GetMover()->GetCharBody(); // Check if the enemy is close enough float fDistSqr = cMath::Vector3DistSqr(pCam->GetPosition(), pCharBody->GetPosition()); if (fDistSqr > fMaxDistSqr) continue; // Check if enemy is in FOV cVector3f vDir = pCharBody->GetPosition() - pCam->GetPosition(); vDir.Normalise(); float fAngle = cMath::Vector3Angle(pCam->GetForward(), vDir); if (fAngle > pCam->GetFOV() * 0.5f) continue; // Check if there is a line of sight mbIntersected = false; pPhysicsWorld->CastRay(this, pCam->GetPosition(), pCharBody->GetPosition(), false, false, false, false); if (mbIntersected == false) { mbEnemyTooClose = true; break; } } } else { mfCheckEnemyCloseCount -= afTimeStep; } //////////////////////////////// // Update the count if enemy is near if (mbEnemyTooClose) { mfEnemyTooCloseCount += afTimeStep; // Do some effect // Check if limit is reached if (mfEnemyTooCloseCount > mfEnemyTooCloseMax) { UnHide(); mpInit->mpPlayer->ChangeMoveState(ePlayerMoveState_Walk); mpSoundHandler->PlayGui("player_scare_high", false, 1); cSoundEntity *pSound = pWorld->CreateSoundEntity("Scare", "player_scare_high", true); if (pSound) { pSound->SetPosition(pCam->GetPosition()); } // Show player to nearby enemies. tGameEnemyIterator enemyIt = mpInit->mpMapHandler->GetGameEnemyIterator(); while (enemyIt.HasNext()) { iGameEnemy *pEnemy = enemyIt.Next(); if (pEnemy->GetHealth() <= 0 || pEnemy->IsActive() == false) continue; iCharacterBody *pCharBody = pEnemy->GetMover()->GetCharBody(); // Check if the enemy is close enough float fDist = cMath::Vector3Dist(pCam->GetPosition(), pCharBody->GetPosition()); if (fDist <= 8) { pEnemy->ShowPlayer(mpInit->mpPlayer->GetCharacterBody()->GetFeetPosition()); } } } } else if (mfEnemyTooCloseCount > 0) { mfEnemyTooCloseCount -= afTimeStep; mpInit->mpGame->GetGraphics()->GetRendererPostEffects()->SetImageTrailActive(false); } } } //----------------------------------------------------------------------- void cPlayerHidden::Reset() { mpLight = NULL; mfHiddenOnTime = 1; mfHiddenOffTime = 0.5f; mfHiddenOnCount = 0; mfEffectOffset = mfStartEffectOffset; mfAspect = mfStartAspect; mfFov = mfStartFov; mbInShadows = false; mfLight = 1.0f; mfMaxLight = 0.25f; mfHiddenCount = 0; mfHiddenTime = 1.4f; mbHidden = false; mfInShadowAlpha = 0; mfInShadowPulse = 0; mfInShadowPulseAdd = 1; mfCheckEnemyCloseCount = 0; mfEnemyTooCloseCount = 0; mbEnemyTooClose = false; mfCloseEffectFovAdd = cMath::ToRad(15); mfCloseEffectFov = 0; } //-----------------------------------------------------------------------