/* * Copyright (C) 2006-2010 - Frictional Games * * This file is part of Penumbra Overture. * * Penumbra Overture 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. * * Penumbra Overture 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 Penumbra Overture. If not, see . */ #include "StdAfx.h" #include "GameStickArea.h" #include "Init.h" #include "MapHandler.h" #include "Player.h" #include "PlayerState.h" #include "GlobalInit.h" ////////////////////////////////////////////////////////////////////////// // LOADER ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- cAreaLoader_GameStickArea::cAreaLoader_GameStickArea(const tString &asName, cInit *apInit) : iArea3DLoader(asName) { mpInit = apInit; } cAreaLoader_GameStickArea::~cAreaLoader_GameStickArea() { } //----------------------------------------------------------------------- iEntity3D* cAreaLoader_GameStickArea::Load(const tString &asName, const cVector3f &avSize, const cMatrixf &a_mtxTransform,cWorld3D *apWorld) { cGameStickArea *pArea = hplNew( cGameStickArea, (mpInit,asName) ); pArea->m_mtxOnLoadTransform = a_mtxTransform; //Create physics data iPhysicsWorld *pPhysicsWorld = apWorld->GetPhysicsWorld(); iCollideShape* pShape = pPhysicsWorld->CreateBoxShape(avSize,NULL); std::vector vBodies; vBodies.push_back(pPhysicsWorld->CreateBody(asName,pShape)); vBodies[0]->SetCollide(false); vBodies[0]->SetCollideCharacter(false); vBodies[0]->SetMatrix(a_mtxTransform); vBodies[0]->SetUserData(pArea); pArea->SetBodies(vBodies); mpInit->mpMapHandler->AddGameEntity(pArea); mpInit->mpMapHandler->AddStickArea(pArea); //Return something else later perhaps. return NULL; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// bool cGameStickArea::mbAllowAttachment = false; //----------------------------------------------------------------------- cGameStickArea::cGameStickArea(cInit *apInit,const tString& asName) : iGameEntity(apInit,asName) { mType = eGameEntityType_StickArea; mpAttachedBody = NULL; mpLastAttachedBody = NULL; msAttachFunction = ""; msDetachFunction = ""; msAttachSound = ""; msDetachFunction = ""; msAttachSound = ""; msDetachSound = ""; mbMoveBody = true; mbRotateBody = true; mbCheckCenterInArea = true; mfPoseTime = 0.2f; mbCanDeatch = true; mfSetMtxTime = 1.0f; } //----------------------------------------------------------------------- cGameStickArea::~cGameStickArea(void) { mpInit->mpMapHandler->RemoveStickArea(this); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void cGameStickArea::OnPlayerPick() { } //----------------------------------------------------------------------- void cGameStickArea::Update(float afTimeStep) { iPhysicsBody *pAreaBody = mvBodies[0]; cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); if(mpAttachedBody && mfSetMtxTime < 1) { if(mbMoveBody && mbRotateBody) { if(mfPoseTime==0) mfSetMtxTime = 1.0f; else mfSetMtxTime += afTimeStep / mfPoseTime; cMatrixf mtxGoal = pAreaBody->GetWorldMatrix(); mtxGoal.SetTranslation(pAreaBody->GetWorldPosition() - mpAttachedBody->GetMassCentre()); cMatrixf mtxNew = cMath::MatrixSlerp(mfSetMtxTime,mtxAttachedStart,mtxGoal,true); mpAttachedBody->SetMatrix(mtxNew); } else if(mbMoveBody && !mbRotateBody) { if(mfPoseTime==0) mfSetMtxTime = 1.0f; else mfSetMtxTime += afTimeStep / mfPoseTime; cVector3f vGoal = pAreaBody->GetWorldPosition() - mpAttachedBody->GetMassCentre(); cVector3f vNew = mtxAttachedStart.GetTranslation()* (1-mfSetMtxTime) + vGoal *mfSetMtxTime; mpAttachedBody->SetPosition(vNew); } else if(!mbMoveBody && mbRotateBody) { if(mfPoseTime==0) mfSetMtxTime = 1.0f; else mfSetMtxTime += afTimeStep / mfPoseTime; cMatrixf mtxGoal = pAreaBody->GetWorldMatrix(); cMatrixf mtxNew = cMath::MatrixSlerp(mfSetMtxTime,mtxAttachedStart,mtxGoal,true); mtxNew.SetTranslation(mpAttachedBody->GetWorldPosition()); mpAttachedBody->SetMatrix(mtxNew); } else { mfSetMtxTime = 1.0f; } if(mfSetMtxTime >= 1) { //Sound if(msAttachSound!="") { cSoundEntity *pSound = pWorld->CreateSoundEntity("AttachSound",msAttachSound,true); if(pSound) pSound->SetPosition(pAreaBody->GetWorldPosition()); } //Particle System if(msAttachPS!="") { pWorld->CreateParticleSystem("AttachPS",msAttachPS,1,pAreaBody->GetWorldMatrix()); } } } if(mpAttachedBody) return; iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); iPhysicsBody *pAttachBody = NULL; //////////////////////////////////////////////////////// //Iterate all bodies in world and check for intersection cPhysicsBodyIterator bodyIt = pPhysicsWorld->GetBodyIterator(); while(bodyIt.HasNext()) { iPhysicsBody *pBody = bodyIt.Next(); /*if( mpInit->mpPlayer->GetPickedBody() == pBody && ( mpInit->mpPlayer->GetState() == ePlayerState_Grab || mpInit->mpPlayer->GetState() == ePlayerState_Move || mpInit->mpPlayer->GetState() == ePlayerState_Push) ) { continue; }*/ if( pBody->IsActive() && pBody->GetCollide() && pBody->GetMass()>0 && pBody->IsCharacter()==false) { //Bounding volume check //if(cMath::CheckCollisionBV(*pBody->GetBV(), *pAreaBody->GetBV())==false) continue; bool bCheck = false; if(mbCheckCenterInArea) { cVector3f vPos = pBody->GetLocalPosition() + cMath::MatrixMul( pBody->GetLocalMatrix().GetRotation(), pBody->GetMassCentre()); bCheck = cMath::PointBVCollision(vPos,*pAreaBody->GetBV()); } else { bCheck = cMath::CheckCollisionBV(*pBody->GetBV(),*pAreaBody->GetBV()); } if(bCheck==false) { if(pBody == mpLastAttachedBody) { mpLastAttachedBody = NULL; } continue; } if(pBody == mpLastAttachedBody) continue; //Shape collision check. cCollideData collideData; collideData.SetMaxSize(1); bool bCollide = pPhysicsWorld->CheckShapeCollision(pAreaBody->GetShape(), pAreaBody->GetLocalMatrix(), pBody->GetShape(), pBody->GetLocalMatrix(), collideData,1); if(bCollide) { if(msAttachFunction!="") { mbAllowAttachment = false; tString sCommand = GetCallbackFunc(msAttachFunction,pBody); mpInit->RunScriptCommand(sCommand); if(mbAllowAttachment==false) continue; } pAttachBody = pBody; } } } //////////////////////////////////////////////////////// // Do some stuff with the body to be attached. if(pAttachBody) { //Log("Attaching body %s\n", pAttachBody->GetName().c_str()); ///////////////////////// //If in an interact state, set the previous state if( mpInit->mpPlayer->GetPushBody() == pAttachBody && ( mpInit->mpPlayer->GetState() == ePlayerState_Grab || mpInit->mpPlayer->GetState() == ePlayerState_Move || mpInit->mpPlayer->GetState() == ePlayerState_Push) ) { //Log(" Setting a prev state\n"); ePlayerState state = mpInit->mpPlayer->GetState(); ePlayerState prev = mpInit->mpPlayer->GetStateData(state)->mPreviuosState; if(prev == ePlayerState_InteractMode) mpInit->mpPlayer->ChangeState(ePlayerState_InteractMode); else mpInit->mpPlayer->ChangeState(ePlayerState_Normal); } ///////////////////////// //Snap it into place. //pAttachBody->SetMatrix(pAreaBody->GetWorldMatrix()); //pAttachBody->SetPosition(pAreaBody->GetWorldPosition() - pAttachBody->GetMassCentre()); mtxAttachedStart = pAttachBody->GetLocalMatrix(); mfSetMtxTime = 0; pAttachBody->SetLinearVelocity(0); pAttachBody->SetAngularVelocity(0); mbBodyGravity = pAttachBody->GetGravity(); pAttachBody->SetGravity(false); mfBodyMass = pAttachBody->GetMass(); pAttachBody->SetMass(0); mpAttachedBody = pAttachBody; mpLastAttachedBody = mpAttachedBody; //Log("Attaching body!\n"); } } //----------------------------------------------------------------------- void cGameStickArea::DetachBody() { if(mpAttachedBody) { //Log("Dettached body %s\n", mpAttachedBody->GetName().c_str()); cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); iPhysicsBody *pAreaBody = mvBodies[0]; //Callback function if(msDetachFunction!="") { tString sCommand = GetCallbackFunc(msDetachFunction,mpAttachedBody); mpInit->RunScriptCommand(sCommand); } //Sound if(msDetachSound!="") { cSoundEntity *pSound = pWorld->CreateSoundEntity("DetachSound",msDetachSound,true); if(pSound) pSound->SetPosition(pAreaBody->GetWorldPosition()); } //Particle System if(msDetachPS!="") { pWorld->CreateParticleSystem("DetachPS",msDetachPS,1,pAreaBody->GetWorldMatrix()); } mpAttachedBody->SetGravity(true); mpAttachedBody->SetMass(mfBodyMass); mpAttachedBody->SetEnabled(true); //Log("Body mass: %f\n",mpAttachedBody->GetMass()); mpAttachedBody = NULL; } } //----------------------------------------------------------------------- bool cGameStickArea::GetCanDeatch() { if(mfSetMtxTime < 1) return false; return mbCanDeatch; } //----------------------------------------------------------------------- tString cGameStickArea::GetCallbackFunc(const tString &asFunc,iPhysicsBody *apBody) { return asFunc + "(\"" + msName + "\",\"" + apBody->GetName() + "\")"; } //----------------------------------------------------------------------- void cGameStickArea::OnPostSceneDraw() { //iPhysicsBody *pAreaBody = mvBodies[0]; //pAreaBody->RenderDebugGeometry(mpInit->mpGame->GetGraphics()->GetLowLevel(),cColor(1,1)); } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PRIVATE METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // SAVE OBJECT STUFF ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- kBeginSerialize(cGameStickArea_SaveData,iGameEntity_SaveData) kSerializeVar(mvSize,eSerializeType_Vector3f) kSerializeVar(msAttachFunction,eSerializeType_String) kSerializeVar(msDetachFunction,eSerializeType_String) kSerializeVar(msAttachSound,eSerializeType_String) kSerializeVar(msDetachSound,eSerializeType_String) kSerializeVar(msAttachPS,eSerializeType_String) kSerializeVar(msDetachPS,eSerializeType_String) kSerializeVar(mbCanDeatch,eSerializeType_Bool) kSerializeVar(msAttachedBody,eSerializeType_String) kSerializeVar(mfSetMtxTime,eSerializeType_Float32) kSerializeVar(mbCheckCenterInArea,eSerializeType_Bool) kSerializeVar(mfPoseTime,eSerializeType_Float32) kEndSerialize() //----------------------------------------------------------------------- iGameEntity* cGameStickArea_SaveData::CreateEntity() { return NULL; } //----------------------------------------------------------------------- iGameEntity_SaveData* cGameStickArea::CreateSaveData() { return hplNew( cGameStickArea_SaveData, () ); } //----------------------------------------------------------------------- void cGameStickArea::SaveToSaveData(iGameEntity_SaveData *apSaveData) { __super::SaveToSaveData(apSaveData); cGameStickArea_SaveData *pData = static_cast(apSaveData); kCopyToVar(pData,msAttachFunction); kCopyToVar(pData,msDetachFunction); kCopyToVar(pData,msAttachSound); kCopyToVar(pData,msDetachSound); kCopyToVar(pData,msAttachPS); kCopyToVar(pData,msDetachPS); kCopyToVar(pData,mbCanDeatch); kCopyToVar(pData,mbCheckCenterInArea); kCopyToVar(pData,mfPoseTime); kCopyToVar(pData,mfSetMtxTime); pData->mvSize = mvBodies[0]->GetShape()->GetSize(); if(mpAttachedBody) { pData->msAttachedBody = mpAttachedBody->GetName(); } } //----------------------------------------------------------------------- void cGameStickArea::LoadFromSaveData(iGameEntity_SaveData *apSaveData) { __super::LoadFromSaveData(apSaveData); cGameStickArea_SaveData *pData = static_cast(apSaveData); kCopyFromVar(pData,msAttachFunction); kCopyFromVar(pData,msDetachFunction); kCopyFromVar(pData,msAttachSound); kCopyFromVar(pData,msDetachSound); kCopyFromVar(pData,msAttachPS); kCopyFromVar(pData,msDetachPS); kCopyFromVar(pData,mbCanDeatch); kCopyFromVar(pData,mbCheckCenterInArea); kCopyFromVar(pData,mfPoseTime); kCopyFromVar(pData,mfSetMtxTime); } //----------------------------------------------------------------------- void cGameStickArea::SetupSaveData(iGameEntity_SaveData *apSaveData) { __super::SetupSaveData(apSaveData); cGameStickArea_SaveData *pData = static_cast(apSaveData); if(pData->msAttachedBody!="") { iPhysicsWorld *pWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); mpAttachedBody = pWorld->GetBody(pData->msAttachedBody); mpLastAttachedBody = mpAttachedBody; } } //-----------------------------------------------------------------------