/*
* 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 "GameSwingDoor.h"
#include "Init.h"
#include "MapHandler.h"
#include "Player.h"
#include "EffectHandler.h"
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// LOADER
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cEntityLoader_GameSwingDoor::cEntityLoader_GameSwingDoor(const tString &asName, cInit *apInit)
: cEntityLoader_Object(asName)
{
mpInit = apInit;
}
cEntityLoader_GameSwingDoor::~cEntityLoader_GameSwingDoor()
{
}
//-----------------------------------------------------------------------
void cEntityLoader_GameSwingDoor::BeforeLoad(TiXmlElement *apRootElem, const cMatrixf &a_mtxTransform,
cWorld3D *apWorld)
{
}
//-----------------------------------------------------------------------
void cEntityLoader_GameSwingDoor::AfterLoad(TiXmlElement *apRootElem, const cMatrixf &a_mtxTransform,
cWorld3D *apWorld)
{
cGameSwingDoor *pObject = hplNew( cGameSwingDoor, (mpInit,mpEntity->GetName()) );
pObject->msFileName = msFileName;
pObject->m_mtxOnLoadTransform = a_mtxTransform;
// Set the engine objects to the object
pObject->SetBodies(mvBodies);
pObject->SetJoints(mvJoints);
pObject->SetMeshEntity(mpEntity);
pObject->SetHapticShapes(mvHapticShapes);
///////////////////////////////////
// Load game properties
TiXmlElement *pGameElem = apRootElem->FirstChildElement("GAME");
if(pGameElem)
{
pObject->mfHealth = cString::ToFloat(pGameElem->Attribute("Health"),0);
pObject->mlToughness = cString::ToInt(pGameElem->Attribute("Toughness"),0);
pObject->msBreakSound = cString::ToString(pGameElem->Attribute("BreakSound"),"");
pObject->msBreakEntity = cString::ToString(pGameElem->Attribute("BreakEntity"),"");
pObject->msBreakPS = cString::ToString(pGameElem->Attribute("BreakPS"),"");
}
else
{
Error("Couldn't find game element for entity '%s'\n",mpEntity->GetName().c_str());
}
///////////////////////////////////
// Add a the object as user data to the body, to get the obejct later on.
for(size_t i=0; iSetUserData((void*)pObject);
}
}
pObject->SetupPhysics(apWorld);
pObject->SetupBreakObject();
/////////////////////////////////
// Add to map handler
mpInit->mpMapHandler->AddGameEntity(pObject);
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// CONSTRUCTORS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
cGameSwingDoor::cGameSwingDoor(cInit *apInit,const tString& asName) : iGameEntity(apInit,asName)
{
mType = eGameEntityType_SwingDoor;
mbHasInteraction = true;
mbPauseControllers = true;
mbPauseGravity = true;
mbLocked = false;
mfHealth = 100.0f;
}
//-----------------------------------------------------------------------
cGameSwingDoor::~cGameSwingDoor(void)
{
iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld();
//for(size_t i=0; iDestroyController(mvStopControllers[i]);
//}
}
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// PUBLIC METHODS
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
void cGameSwingDoor::SetupPhysics(cWorld3D *apWorld)
{
mvJointDefaults.resize(mvJoints.size());
iPhysicsWorld *pPhysicsWorld = apWorld->GetPhysicsWorld();
for(size_t i=0; iCreateController("Stop");
//pController->SetBody(pJoint->GetChildBody());
//pController->SetJoint(pJoint);
pController->SetActive(true);
pController->SetType(ePhysicsControllerType_Pid);
pController->SetA(1.5f);
pController->SetB(1.0f);
pController->SetC(0.0f);
pController->SetPidIntegralSize(20);
pController->SetInputType(ePhysicsControllerInput_AngularSpeed,ePhysicsControllerAxis_Y);
pController->SetDestValue(.0f);
pController->SetOutputType(ePhysicsControllerOutput_Torque,ePhysicsControllerAxis_Y);
pController->SetMaxOutput(0.0f);
pController->SetMulMassWithOutput(true);
pJoint->AddController(pController);
mvStopControllers.push_back(pController);
///////////////////////////////////
//Set defaults
iPhysicsJointHinge *pHingeJoint = static_cast(pJoint);
mvJointDefaults[i].mfMin = pHingeJoint->GetMinAngle();
mvJointDefaults[i].mfMax = pHingeJoint->GetMaxAngle();
}
}
//-----------------------------------------------------------------------
void cGameSwingDoor::OnPlayerPick()
{
}
//-----------------------------------------------------------------------
void cGameSwingDoor::OnPlayerInteract()
{
float fDist = mpInit->mpPlayer->GetPickedDist();
if(fDist > mfMaxInteractDist) return;
if(mpInit->mbHasHaptics && mpInit->mpPlayer->mbProxyTouching==false) return;
//Set some properties
mpInit->mpPlayer->mfForwardUpMul = 1.0f;
mpInit->mpPlayer->mfForwardRightMul = 1.0f;
mpInit->mpPlayer->mfUpMul = 1.0f;
mpInit->mpPlayer->mfRightMul = 1.0f;
mpInit->mpPlayer->mfCurrentMaxInteractDist = mfMaxInteractDist;
if(!mpInit->mbHasHaptics)
{
mpInit->mpPlayer->SetPushBody(mpInit->mpPlayer->GetPickedBody());
mpInit->mpPlayer->ChangeState(ePlayerState_Move);
}
else
{
mpInit->mpPlayer->mbPickAtPoint = true;
mpInit->mpPlayer->mbRotateWithPlayer = false;
mpInit->mpPlayer->mbUseNormalMass = false;
mpInit->mpPlayer->mfGrabMassMul = 1;
mpInit->mpPlayer->mfHapticTorqueMul = 1.0f;
mpInit->mpPlayer->mbCanBeThrown = true;
mpInit->mpPlayer->mbGrabbingMoveBody = true;
mpInit->mpPlayer->SetPushBody(mpInit->mpPlayer->GetPickedBody());
mpInit->mpPlayer->ChangeState(ePlayerState_Grab);
}
}
//-----------------------------------------------------------------------
void cGameSwingDoor::Update(float afTimeStep)
{
}
//-----------------------------------------------------------------------
void cGameSwingDoor::SetLocked(bool abX)
{
if(mbLocked == abX) return;
mbLocked = abX;
for(size_t i=0; i(pJoint);
if(mbLocked)
{
if(std::abs(pHingeJoint->GetMinAngle()) > std::abs(pHingeJoint->GetMaxAngle()))
pHingeJoint->SetMinAngle(cMath::ToRad(-1));
else
pHingeJoint->SetMaxAngle(cMath::ToRad(1));
}
else
{
pHingeJoint->SetMinAngle(mvJointDefaults[i].mfMin);
pHingeJoint->SetMaxAngle(mvJointDefaults[i].mfMax);
}
}
for(size_t i=0; iSetEnabled(true);
}
}
//-----------------------------------------------------------------------
void cGameSwingDoor::OnDamage(float afDamage)
{
}
//-----------------------------------------------------------------------
void cGameSwingDoor::OnDeath(float afDamage)
{
if(msBreakSound != "")
{
cSoundEntity *pSound = mpInit->mpGame->GetScene()->GetWorld3D()->CreateSoundEntity("Break",msBreakSound,true);
if(pSound)
pSound->SetPosition(mvBodies[0]->GetWorldPosition());
}
if(msBreakEntity == "")
{
///////////////////////////
//Break all joints.
for(size_t i=0; i< mvJoints.size();++i)
{
mvJoints[i]->Break();
}
mvJoints.clear();
}
else
{
Break();
}
}
//-----------------------------------------------------------------------
void cGameSwingDoor::BreakAction()
{
if(mvBodies.empty()) return;
iPhysicsBody *pDynBody = NULL;
iPhysicsBody *pStaticBody = NULL;
for(size_t i=0; i < mvBodies.size();++i)
{
if(mvBodies[i]->GetMass()!=0) pDynBody = mvBodies[i];
if(mvBodies[i]->GetMass()==0) pStaticBody = mvBodies[i];
}
if(pDynBody==NULL && pStaticBody==NULL) return;
//////////////////
//Script
if(mvCallbackScripts[eGameEntityScriptType_OnBreak])
{
tString sCommand = GetScriptCommand(eGameEntityScriptType_OnBreak);
mpInit->RunScriptCommand(sCommand);
}
cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D();
//////////////////
//Check if player os holding object
if( (mpInit->mpPlayer->GetState()==ePlayerState_Grab ||
mpInit->mpPlayer->GetState()==ePlayerState_Move ||
mpInit->mpPlayer->GetState()==ePlayerState_Push)
&&
(mpInit->mpPlayer->GetPushBody() == pDynBody ||
mpInit->mpPlayer->GetPushBody() == pStaticBody))
{
mpInit->mpPlayer->ChangeState(ePlayerState_Normal);
}
cBoundingVolume *pBV = mpMeshEntity->GetBoundingVolume();
//////////////////
//Particle System
if(msBreakPS!="")
{
cParticleSystem3D *pPS = pWorld->CreateParticleSystem("Break",msBreakPS,cVector3f(1,1,1),
pDynBody->GetWorldMatrix());
}
//////////////////
//Entity
if(msBreakEntity != "")
{
iEntity3D * pEntity = pWorld->CreateEntity(mpMeshEntity->GetName() + "_broken",
pDynBody->GetWorldMatrix(),
msBreakEntity, true);
if(pEntity)
{
iGameEntity *pGameEntity = mpInit->mpMapHandler->GetLatestEntity();
cVector3f vImpulse = mvLastImpulse * 2;// / (float)pGameEntity->GetBodyNum();
for(int i=0; i< pGameEntity->GetBodyNum(); ++i)
{
//Add the object velocity
iPhysicsBody *pNewBody = pGameEntity->GetBody(i);
if(pNewBody->GetMass()==0 && pStaticBody)
{
pNewBody->SetMatrix(pStaticBody->GetWorldMatrix());
}
//pNewBody->SetLinearVelocity(pBody->GetLinearVelocity());
pNewBody->AddImpulse(vImpulse);
}
}
}
mpInit->mpGame->ResetLogicTimer();
}
//-----------------------------------------------------------------------
void cGameSwingDoor::SetupBreakObject()
{
if(msBreakEntity!="") PreloadModel(msBreakEntity);
if(msBreakPS!="")
{
cParticleSystem3D *pPS = mpInit->mpGame->GetResources()->GetParticleManager()->CreatePS3D(
"",msBreakPS,1,cMatrixf::Identity);
hplDelete( pPS );
}
if(msBreakSound!="")
{
mpInit->PreloadSoundEntityData(msBreakSound);
}
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------
//////////////////////////////////////////////////////////////////////////
// SAVE OBJECT STUFF
//////////////////////////////////////////////////////////////////////////
//-----------------------------------------------------------------------
kBeginSerialize(cGameSwingDoor_SaveData,iGameEntity_SaveData)
kSerializeVar(mbLocked, eSerializeType_Bool)
kSerializeVar(msBreakSound, eSerializeType_String)
kSerializeVar(msBreakEntity, eSerializeType_String)
kSerializeVar(msBreakPS, eSerializeType_String)
kEndSerialize()
//-----------------------------------------------------------------------
iGameEntity* cGameSwingDoor_SaveData::CreateEntity()
{
return NULL;
}
//-----------------------------------------------------------------------
iGameEntity_SaveData* cGameSwingDoor::CreateSaveData()
{
return hplNew( cGameSwingDoor_SaveData, () );
}
//-----------------------------------------------------------------------
void cGameSwingDoor::SaveToSaveData(iGameEntity_SaveData *apSaveData)
{
__super::SaveToSaveData(apSaveData);
cGameSwingDoor_SaveData *pData = static_cast(apSaveData);
kCopyToVar(pData,mbLocked);
kCopyToVar(pData,msBreakSound);
kCopyToVar(pData,msBreakEntity);
kCopyToVar(pData,msBreakPS);
}
//-----------------------------------------------------------------------
void cGameSwingDoor::LoadFromSaveData(iGameEntity_SaveData *apSaveData)
{
__super::LoadFromSaveData(apSaveData);
cGameSwingDoor_SaveData *pData = static_cast(apSaveData);
kCopyFromVar(pData,msBreakSound);
kCopyFromVar(pData,msBreakEntity);
kCopyFromVar(pData,msBreakPS);
SetLocked(pData->mbLocked);
}
//-----------------------------------------------------------------------
//-----------------------------------------------------------------------