/* 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/GameSwingDoor.h" #include "hpl1/engine/engine.h" #include "hpl1/penumbra-overture/EffectHandler.h" #include "hpl1/penumbra-overture/Init.h" #include "hpl1/penumbra-overture/MapHandler.h" #include "hpl1/penumbra-overture/Player.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); /////////////////////////////////// // 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; i < mvBodies.size(); ++i) { if (mvBodies[i]) { mvBodies[i]->SetUserData((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; i < mvJoints.size(); ++i) { iPhysicsJoint *pJoint = mvJoints[i]; /////////////////////////////////// // Create Stop controller iPhysicsController *pController = pPhysicsWorld->CreateController("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; // 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; mpInit->mpPlayer->SetPushBody(mpInit->mpPlayer->GetPickedBody()); mpInit->mpPlayer->ChangeState(ePlayerState_Move); } //----------------------------------------------------------------------- void cGameSwingDoor::Update(float afTimeStep) { } //----------------------------------------------------------------------- void cGameSwingDoor::SetLocked(bool abX) { if (mbLocked == abX) return; mbLocked = abX; for (size_t i = 0; i < mvJoints.size(); ++i) { iPhysicsJoint *pJoint = mvJoints[i]; iPhysicsJointHinge *pHingeJoint = static_cast(pJoint); if (mbLocked) { if (ABS(pHingeJoint->GetMinAngle()) > 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; i < mvBodies.size(); ++i) { iPhysicsBody *pBody = mvBodies[i]; pBody->SetEnabled(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); } //----------------------------------------------------------------------- //-----------------------------------------------------------------------