/* * 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 "GameEntity.h" #include "Init.h" #include "Player.h" #include "PlayerState.h" #include "PlayerHelper.h" #include "MapHandler.h" #include "GameMessageHandler.h" #include "EffectHandler.h" #include "GameStickArea.h" //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // CONSTRUCTORS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- iGameEntity::iGameEntity(cInit *apInit, const tString &asName) { mpInit = apInit; msName = asName; msFileName = ""; mbActive = true; mbIsSaved = true; mfHealth = 0; mlToughness = 0; mbDestroyMe = false; mbBreakMe = false; mpMeshEntity = NULL; mpCharBody = NULL; mType = eGameEntityType_Unkown; msDescription = _W(""); msGameName = _W(""); mbShowDescritionOnce = false; mfMaxExamineDist = 6.0f; mfMaxInteractDist = 1.5f; if(mpInit->mbHasHaptics) mfMaxInteractDist = mpInit->mfHapticMaxInteractDist; mbHasInteraction = false; mbHasBeenExamined = false; mbPauseControllers = false; mbPauseGravity = false; for(int i=0; i< eGameEntityScriptType_LastEnum; ++i) { mvCallbackScripts[i] = NULL; } mbSaveLights = true; mbUpdatingCollisionCallbacks = false; mbTransActive = false; mvLastImpulse = 0; } //----------------------------------------------------------------------- iGameEntity::~iGameEntity() { cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); ////////////////////////////////////////////// // Remove all references to from all otter //Log("Deleting '%s'\n",msName.c_str()); //Player mpInit->mpPlayer->RemoveCollideScriptWithChildEntity(this); //Other entities (check so not all entities are being destroyed, // in that case it is not needed and might be bad). if(mpInit->mpMapHandler->IsDestroyingAll()==false) { tGameEntityIterator it = mpInit->mpMapHandler->GetGameEntityIterator(); while(it.HasNext()) { iGameEntity *pEntity = it.Next(); pEntity->RemoveCollideScriptWithChildEntity(this); } } //////////////////////////////////////////// // Destroy haptic for(size_t i=0; i< mvHapticShapes.size(); ++i) { if(mvHapticShapes[i]) { mpInit->mpGame->GetHaptic()->GetLowLevel()->DestroyShape(mvHapticShapes[i]); } } ////////////////////////////////////////////// // Destroy all graphics in the entity! if(pWorld && mpInit->mbDestroyGraphics) { for(size_t i=0; impPlayer->GetPickedBody() == mvBodies[i]) mpInit->mpPlayer->GetPickRay()->mpPickedBody = NULL; if(mpInit->mpPlayer->GetPushBody() == mvBodies[i]) { ePlayerState state = mpInit->mpPlayer->GetState(); if( state == ePlayerState_Move || state == ePlayerState_Grab || state == ePlayerState_Push) { ePlayerState prevState = mpInit->mpPlayer->GetStateData(state)->mPreviuosState; if(prevState == ePlayerState_InteractMode) mpInit->mpPlayer->ChangeState(ePlayerState_InteractMode); else mpInit->mpPlayer->ChangeState(ePlayerState_Normal); } mpInit->mpPlayer->SetPushBody(NULL); } pWorld->GetPhysicsWorld()->DestroyBody(mvBodies[i]); } if(mpMeshEntity) pWorld->DestroyMeshEntity(mpMeshEntity); for(size_t i=0; iDestroyLight(mvLights[i]); for(size_t i=0; iKill(); for(size_t i=0; iDestroyBillboard(mvBillboards[i]); for(size_t i=0; iDestroyBeam(mvBeams[i]); for(size_t i=0; iDestroySoundEntity(mvSoundEntities[i]); } if(mpCharBody) pWorld->GetPhysicsWorld()->DestroyCharacterBody(mpCharBody); } //Delete callbacks for(int i=0; i< eGameEntityScriptType_LastEnum; ++i) { if( mvCallbackScripts[i]) hplDelete( mvCallbackScripts[i] ); } STLMapDeleteAll(m_mapCollideCallbacks); STLDeleteAll(mvTransMaterials); for(size_t i=0; impGame->GetResources()->GetMeshManager()->Destroy(mvPreloadedBreakMeshes[i]); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PUBLIC METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- void iGameEntity::SetActive(bool abX) { if(mbActive == abX) return; mbActive =abX; for(size_t i=0; iSetActive(mbActive); mvBodies[i]->SetTransformUpdated(true); } if(mpMeshEntity) { mpMeshEntity->SetVisible(mbActive); mpMeshEntity->SetActive(mbActive); if(mbActive) mpMeshEntity->UpdateLogic(0.01f); } if(mpCharBody) { mpCharBody->SetActive(mbActive); if(mbActive) { //Pre update the character body to make sure it is on ground. //Seems to mess up stuff /*for(int i=0; i<120; ++i) { //mpCharBody->Update(1.0f / 60.0f); }*/ } } for(size_t i=0; iSetVisible(mbActive); if(mvParticleSystems[i]) mvParticleSystems[i]->SetActive(mbActive); } for(size_t i=0; iSetVisible(mbActive); for(size_t i=0; iSetVisible(mbActive); OnSetActive(mbActive); } //----------------------------------------------------------------------- float iGameEntity::GetPickedDistance() { return mpInit->mpPlayer->GetPickedDist(); } //----------------------------------------------------------------------- eCrossHairState iGameEntity::GetPickCrossHairState(iPhysicsBody *apBody) { float fDistance = GetPickedDistance(); ////////////////////////////////////////// //Interaction available cGameStickArea *pStickArea = mpInit->mpMapHandler->GetBodyStickArea(apBody); if(apBody->GetMass()!=0 || mType == eGameEntityType_Area || (pStickArea && pStickArea->GetCanDeatch()) ) { if(mvCallbackScripts[eGameEntityScriptType_PlayerInteract] || mbHasInteraction) { if(fDistance <= mfMaxInteractDist) return eCrossHairState_Active; } } ////////////////////////////////////////// // Examine available if(mvCallbackScripts[eGameEntityScriptType_PlayerExamine] || msDescription!=_W("")) { if(fDistance <= mfMaxExamineDist) return eCrossHairState_Examine; } ////////////////////////////////////////// // Too far if(mvCallbackScripts[eGameEntityScriptType_PlayerInteract] || mbHasInteraction) { //if(fDistance <= mfMaxExamineDist) return eCrossHairState_Invalid; if(apBody->GetMass()==0 && mvCallbackScripts[eGameEntityScriptType_PlayerInteract]==NULL) { return eCrossHairState_None; } else { return eCrossHairState_Invalid; } } return eCrossHairState_None; } //----------------------------------------------------------------------- void iGameEntity::DestroyLight(iLight3D *apLight) { STLFindAndRemove(mvLights,apLight); mpInit->mpGame->GetScene()->GetWorld3D()->DestroyLight(apLight); } void iGameEntity::DestroyParticleSystem(cParticleSystem3D* apPS) { STLFindAndRemove(mvParticleSystems,apPS); mpInit->mpGame->GetScene()->GetWorld3D()->DestroyParticleSystem(apPS); } void iGameEntity::DestroyBillboard(cBillboard* apBillboard) { STLFindAndRemove(mvBillboards,apBillboard); mpInit->mpGame->GetScene()->GetWorld3D()->DestroyBillboard(apBillboard); } void iGameEntity::SetSoundEntity(cSoundEntity* apSound) { STLFindAndRemove(mvSoundEntities,apSound); mpInit->mpGame->GetScene()->GetWorld3D()->DestroySoundEntity(apSound); } //----------------------------------------------------------------------- void iGameEntity::PlayerPick() { ////////////////////// // Script stuff cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); if(mvCallbackScripts[eGameEntityScriptType_PlayerPick]) { tString sCommand = GetScriptCommand(eGameEntityScriptType_PlayerPick); mpInit->RunScriptCommand(sCommand); } OnPlayerPick(); } void iGameEntity::PlayerInteract() { ////////////////////// // Script stuff if(GetPickedDistance() <= mfMaxInteractDist && (mpInit->mbHasHaptics==false || mpInit->mpPlayer->mbProxyTouching || mType == eGameEntityType_Area)) { cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); if(mvCallbackScripts[eGameEntityScriptType_PlayerInteract]) { tString sCommand = GetScriptCommand(eGameEntityScriptType_PlayerInteract); mpInit->RunScriptCommand(sCommand); } } OnPlayerInteract(); } void iGameEntity::PlayerExamine() { ////////////////////// // Script stuff if(GetPickedDistance() <= mfMaxExamineDist) { cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); if(mvCallbackScripts[eGameEntityScriptType_PlayerExamine]) { tString sCommand = GetScriptCommand(eGameEntityScriptType_PlayerExamine); mpInit->RunScriptCommand(sCommand); } } OnPlayerExamine(); } //----------------------------------------------------------------------- void iGameEntity::OnPlayerExamine() { if(mfMaxExamineDist >= mpInit->mpPlayer->GetPickedDist() && msDescription!=_W("")) { mpInit->mpGameMessageHandler->Add(msDescription); //if(mbShowDescritionOnce) msDescription = _W(""); mbHasBeenExamined = true; ////////////////////////////// //Set focus on the object mpInit->mpEffectHandler->GetDepthOfField()->FocusOnBody(mpInit->mpPlayer->GetPickedBody()); mpInit->mpEffectHandler->GetDepthOfField()->SetFocusBody(NULL); mpInit->mpEffectHandler->GetDepthOfField()->SetActive(true,1.2f); mpInit->mpGameMessageHandler->SetFocusIsedUsed(true); } } //----------------------------------------------------------------------- void iGameEntity::Damage(float afDamage, int alStrength) { if(mfHealth > 0) { if(mType == eGameEntityType_Enemy) { //if(mpInit->mDifficulty== eGameDifficulty_Easy) afDamage *= 2.0f; if(mpInit->mDifficulty== eGameDifficulty_Hard) afDamage /= 2.0f; if(mpInit->mbHasHaptics) afDamage *= 2.0f; } int lDiff = mlToughness - alStrength; if(alStrength>=0) { float fDamageMul = 1 - (0.25f * (float)lDiff); if(fDamageMul<0) fDamageMul =0; //Could be 2 here, depends on what you wanna do. This way the damage is never increased. if(fDamageMul>1) fDamageMul =1; afDamage *= fDamageMul; } mfHealth -= std::abs(afDamage); if(mfHealth <=0) { OnDeath(afDamage); } else { OnDamage(afDamage); } } } void iGameEntity::SetHealth(float afHealth) { if(afHealth <=0 && mfHealth >0) { mfHealth = afHealth; OnDeath(0); } else { mfHealth = afHealth; } } //----------------------------------------------------------------------- void iGameEntity::SetUpTransMaterials() { mvNormalMaterials.resize(mpMeshEntity->GetSubMeshEntityNum()); mvTransMaterials.resize(mpMeshEntity->GetSubMeshEntityNum()); mbTransShadow = mpMeshEntity->IsShadowCaster(); for(int i=0; i< mpMeshEntity->GetSubMeshEntityNum(); ++i) { cSubMeshEntity *pSubEntity = mpMeshEntity->GetSubMeshEntity(i); cSubMesh *pSubMesh = mpMeshEntity->GetMesh()->GetSubMesh(i); iMaterial *pNormalMaterial = pSubEntity->GetMaterial(); mvNormalMaterials[i]= pSubEntity->GetCustomMaterial(); //create material for the transperancy iMaterial *pTransMaterial = mpInit->mpGame->GetGraphics()->GetMaterialHandler()->Create( "Trans","Modulative",eMaterialPicture_Texture); //Set texture for the trans material iTexture *pDiffTex = pNormalMaterial->GetTexture(eMaterialTexture_Diffuse); if(pDiffTex) { pDiffTex->IncUserCount(); pTransMaterial->SetTexture(pDiffTex,eMaterialTexture_Diffuse); mvTransMaterials[i] = pTransMaterial; } else { Log("Sub mesh '%s' material '%s' does not have diffuse!\n",pSubMesh->GetName().c_str(), pNormalMaterial->GetName().c_str()); } } } void iGameEntity::SetTransActive(bool abX) { if(mbTransActive == abX) return; mbTransActive = abX; if(mbTransShadow) { //mpMeshEntity->SetForceShadow(mbTransActive); } for(int i=0; i< mpMeshEntity->GetSubMeshEntityNum(); ++i) { cSubMeshEntity *pSubEntity = mpMeshEntity->GetSubMeshEntity(i); if(mbTransActive) { pSubEntity->SetCustomMaterial(mvTransMaterials[i],false); } else { pSubEntity->SetCustomMaterial(mvNormalMaterials[i],false); } } } //----------------------------------------------------------------------- static inline tString GetCollideCommand(const tString &asFuncName,const tString &asParent, const tString &asChild) { return asFuncName + "(\"" + asParent+"\", \""+asChild+"\")"; } //////////////////////////// void iGameEntity::OnUpdate(float afTimeStep) { if(mbActive==false) return; //////////////////////////////////////////// /// Script Collide test stuff iPhysicsWorld *pPhysicsWorld = mpInit->mpGame->GetScene()->GetWorld3D()->GetPhysicsWorld(); cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); //////////////// // If entity has character body add it to the array and then remove. std::vector vTempBodies; if(mpCharBody){ for(size_t i=0; iGetBody()); } cCollideData collideData; collideData.SetMaxSize(1); //if(msName == "liftclose") Log("--- Start collision test\n"); mbUpdatingCollisionCallbacks = true; tGameCollideScriptMapIt CollideIt = m_mapCollideCallbacks.begin(); for(; CollideIt != m_mapCollideCallbacks.end(); ++CollideIt) { cGameCollideScript *pCallback = CollideIt->second; iGameEntity *pEntity = pCallback->mpEntity; if(pEntity->IsActive() ==false)continue; bool bCollide = false; for(size_t i=0; i< mvBodies.size(); ++i) for(size_t j=0; j< pEntity->mvBodies.size(); ++j) { iPhysicsBody *pParentBody = mvBodies[i]; iPhysicsBody *pChildBody = pEntity->mvBodies[j]; //if(msName == "liftclose") Log("Start shape collision...."); if(cMath::CheckCollisionBV( *pParentBody->GetBV(),*pChildBody->GetBV())) { bCollide = pPhysicsWorld->CheckShapeCollision(pParentBody->GetShape(), pParentBody->GetLocalMatrix(), pChildBody->GetShape(), pChildBody->GetLocalMatrix(), collideData,1); } //if(msName == "liftclose") Log("end it\n"); if(bCollide) break; } //Run Collide scripts if(bCollide) { //if(msName == "liftclose") Log("entity %s collided!\n",msName.c_str()); if(pCallback->mbCollides) { if(pCallback->msFuncName[eGameCollideScriptType_During] != "") { tString sCommand = GetCollideCommand( pCallback->msFuncName[eGameCollideScriptType_During], msName, CollideIt->first); mpInit->RunScriptCommand(sCommand); } } else { if(pCallback->msFuncName[eGameCollideScriptType_Enter] != "") { tString sCommand = GetCollideCommand( pCallback->msFuncName[eGameCollideScriptType_Enter], msName, CollideIt->first); mpInit->RunScriptCommand(sCommand); } pCallback->mbCollides = true; } } else { if(pCallback->mbCollides) { if(pCallback->msFuncName[eGameCollideScriptType_Leave] != "") { tString sCommand = GetCollideCommand( pCallback->msFuncName[eGameCollideScriptType_Leave], msName, CollideIt->first); mpInit->RunScriptCommand(sCommand); } pCallback->mbCollides = false; } } } mbUpdatingCollisionCallbacks = false; //////////////// // If entity has character body remove the previuously added. if(mpCharBody){ mvBodies.clear(); for(size_t i=0; isecond; tGameCollideScriptMapIt currentIt = CollideIt; ++CollideIt; if(pCallback->mbDeleteMe) { hplDelete( pCallback ); m_mapCollideCallbacks.erase(currentIt); } } //////////////////////////////////////////// /// Script Update if(mvCallbackScripts[eGameEntityScriptType_OnUpdate]) { tString sCommand = GetScriptCommand(eGameEntityScriptType_OnUpdate); mpInit->RunScriptCommand(sCommand); } /////////////////////////////////////////// //update entity specific stuff. Update(afTimeStep); } //----------------------------------------------------------------------- void iGameEntity::AddCollideScript(eGameCollideScriptType aType,const tString &asFunc, const tString &asEntity) { cGameCollideScript *pCallback; //Check if the function already exist tGameCollideScriptMapIt it = m_mapCollideCallbacks.find(asEntity); if(it != m_mapCollideCallbacks.end()) { pCallback = it->second; } else { pCallback = hplNew( cGameCollideScript, () ); //Get the entity iGameEntity *pEntity = mpInit->mpMapHandler->GetGameEntity(asEntity); if(pEntity==NULL) { Warning("Couldn't find entity '%s'\n",asEntity.c_str()); hplDelete( pCallback ); return; } //Set the entity pCallback->mpEntity = pEntity; //Add to container m_mapCollideCallbacks.insert(tGameCollideScriptMap::value_type(asEntity,pCallback)); } pCallback->msFuncName[aType] = asFunc; } //----------------------------------------------------------------------- void iGameEntity::RemoveCollideScriptWithChildEntity(iGameEntity *apEntity) { tGameCollideScriptMapIt it = m_mapCollideCallbacks.begin(); for(; it != m_mapCollideCallbacks.end(); ) { cGameCollideScript *pCallback = it->second; tGameCollideScriptMapIt currentIt = it; ++it; if(pCallback && pCallback->mpEntity == apEntity) { if(mbUpdatingCollisionCallbacks) { pCallback->mbDeleteMe = true; } else { hplDelete( pCallback ); m_mapCollideCallbacks.erase(currentIt); } } } } //----------------------------------------------------------------------- void iGameEntity::RemoveCollideScript(eGameCollideScriptType aType,const tString &asEntity) { tGameCollideScriptMapIt it = m_mapCollideCallbacks.find(asEntity); if(it != m_mapCollideCallbacks.end()) { cGameCollideScript *pCallback = it->second; pCallback->msFuncName[aType] = ""; //if there are no functions left, erase if(pCallback->msFuncName[0]=="" && pCallback->msFuncName[1]=="" && pCallback->msFuncName[2]=="") { if(mbUpdatingCollisionCallbacks) { pCallback->mbDeleteMe = true; } else { hplDelete( pCallback ); m_mapCollideCallbacks.erase(it); } } } else { Warning("Entity '%s' callback doesn't exist in '%s'\n",asEntity.c_str(),msName.c_str()); } } //----------------------------------------------------------------------- void iGameEntity::AddScript(eGameEntityScriptType aType,const tString &asFunc) { cGameEntityScript *pScript = mvCallbackScripts[aType]; if(pScript==NULL) { pScript = hplNew( cGameEntityScript, () ); mvCallbackScripts[aType] = pScript; } pScript->msScriptFunc = asFunc; } //----------------------------------------------------------------------- void iGameEntity::RemoveScript(eGameEntityScriptType aType) { if(mvCallbackScripts[aType]) { hplDelete( mvCallbackScripts[aType] ); mvCallbackScripts[aType] = NULL; } } //----------------------------------------------------------------------- void iGameEntity::CreateVar(const tString &asName, int alVal) { tGameEntityVarMapIt it = m_mapVars.find(asName); if(it == m_mapVars.end()) { m_mapVars.insert(tGameEntityVarMap::value_type(asName,alVal)); } } void iGameEntity::SetVar(const tString &asName, int alVal) { tGameEntityVarMapIt it = m_mapVars.find(asName); if(it == m_mapVars.end()){ Warning("Entity '%s' var '%s' not found!\n",msName.c_str(), asName.c_str()); return; } it->second = alVal; } void iGameEntity::AddVar(const tString &asName, int alVal) { tGameEntityVarMapIt it = m_mapVars.find(asName); if(it == m_mapVars.end()){ Warning("Entity '%s' var '%s' not found!\n",msName.c_str(), asName.c_str()); return; } it->second += alVal; } int iGameEntity::GetVar(const tString &asName) { tGameEntityVarMapIt it = m_mapVars.find(asName); if(it == m_mapVars.end()){ Warning("Entity '%s' var '%s' not found!\n",msName.c_str(), asName.c_str()); return 0; } return it->second; } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // PROTECTED METHODS ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- tString iGameEntity::GetScriptCommand(eGameEntityScriptType aType) { return mvCallbackScripts[aType]->msScriptFunc + "(\""+msName+"\")"; } //----------------------------------------------------------------------- void iGameEntity::PreloadModel(const tString &asFile) { tString sFileName = cString::SetFileExt(asFile,"ent"); tString sPath = mpInit->mpGame->GetResources()->GetFileSearcher()->GetFilePath(sFileName); if(sPath!="") { TiXmlDocument *pEntityDoc = hplNew( TiXmlDocument, () ); if(pEntityDoc->LoadFile(sPath.c_str())==false) { Error("Couldn't load '%s'!\n",sPath.c_str()); } else { TiXmlElement *pRootElem = pEntityDoc->FirstChildElement(); TiXmlElement *pGraphicsElem = pRootElem->FirstChildElement("GRAPHICS"); tString sModelFile = cString::ToString(pGraphicsElem->Attribute("ModelFile"),""); cMesh *pMesh = mpInit->mpGame->GetResources()->GetMeshManager()->CreateMesh(sModelFile); mvPreloadedBreakMeshes.push_back(pMesh); for(int i=0; i< pMesh->GetReferenceNum();++i) { cMeshReference *pRef = pMesh->GetReference(i); PreloadModel(pRef->msFile); } } hplDelete( pEntityDoc ); } else { Error("Entity file '%s' was not found!\n",sFileName.c_str()); } } //----------------------------------------------------------------------- ////////////////////////////////////////////////////////////////////////// // SAVE DATA STUFF ////////////////////////////////////////////////////////////////////////// //----------------------------------------------------------------------- iGameEntity_SaveData::~iGameEntity_SaveData() { //Log("Deleting save data %d\n",this); } //----------------------------------------------------------------------- cEnginePS_SaveData* iGameEntity_SaveData::GetParticleSystem(cParticleSystem3D* apPS) { for(size_t i=0; i < mvPS.Size(); ++i) { if(mvPS[i].msName == apPS->GetName()) return &mvPS[i]; } return NULL; } cEngineSound_SaveData* iGameEntity_SaveData::GetSoundEntity(cSoundEntity* apSound) { for(size_t i=0; i < mvSounds.Size(); ++i) { if(mvSounds[i].msName == apSound->GetName()) return &mvSounds[i]; } return NULL; } //----------------------------------------------------------------------- kBeginSerializeBase(cGameEntityScript) kSerializeVar(mlNum, eSerializeType_Int32) kSerializeVar(msScriptFunc, eSerializeType_String) kEndSerialize() //----------------------------------------------------------------------- kBeginSerializeBase(cGameEntityAnimation_SaveData) kSerializeVar(mbActive,eSerializeType_Bool) kSerializeVar(mbLoop,eSerializeType_Bool) kSerializeVar(mfWeight,eSerializeType_Float32) kSerializeVar(mfFadeStep,eSerializeType_Float32) kSerializeVar(mfTimePos,eSerializeType_Float32) kSerializeVar(mfSpeed,eSerializeType_Float32) kEndSerialize() //----------------------------------------------------------------------- kBeginSerializeBaseVirtual(iGameEntity_SaveData) kSerializeVar(mbActive,eSerializeType_Bool) kSerializeVar(msFileName,eSerializeType_String) kSerializeVar(msName,eSerializeType_String) kSerializeVar(mfHealth,eSerializeType_Float32) kSerializeVar(mfMaxExamineDist,eSerializeType_Float32) kSerializeVar(mfMaxInteractDist,eSerializeType_Float32) kSerializeVar(msGameName,eSerializeType_WString) kSerializeVar(msDescription,eSerializeType_WString) kSerializeVar(mbHasBeenExamined,eSerializeType_Bool) kSerializeVar(mbShowDescritionOnce,eSerializeType_Bool) kSerializeVar(mType,eSerializeType_Int32) kSerializeVar(m_mtxTransform, eSerializeType_Matrixf) kSerializeClassContainer(mlstCollideCallbacks,cSaveGame_cGameCollideScript,eSerializeType_Class) kSerializeClassContainer(mlstCallbackScripts,cGameEntityScript,eSerializeType_Class) kSerializeClassContainer(mlstVars,cScriptVar,eSerializeType_Class) kSerializeClassContainer(mvBodies,cEngineBody_SaveData,eSerializeType_Class) kSerializeClassContainer(mvPS,cEnginePS_SaveData,eSerializeType_Class) kSerializeClassContainer(mvLights,cEngineLight_SaveData,eSerializeType_Class) kSerializeClassContainer(mvSounds,cEngineSound_SaveData,eSerializeType_Class) kSerializeClassContainer(mvAnimations,cGameEntityAnimation_SaveData,eSerializeType_Class) kEndSerialize() //----------------------------------------------------------------------- void iGameEntity::SaveToSaveData(iGameEntity_SaveData* apSaveData) { //Properties kCopyToVar(apSaveData,mbActive); kCopyToVar(apSaveData,msName); kCopyToVar(apSaveData,msFileName); kCopyToVar(apSaveData,mfHealth); kCopyToVar(apSaveData,mfMaxInteractDist); kCopyToVar(apSaveData,mfMaxExamineDist); kCopyToVar(apSaveData,msGameName); kCopyToVar(apSaveData,msDescription); kCopyToVar(apSaveData,mbShowDescritionOnce); kCopyToVar(apSaveData,mbHasBeenExamined); kCopyToVar(apSaveData,mType); apSaveData->m_mtxTransform = m_mtxOnLoadTransform; cWorld3D *pWorld = mpInit->mpGame->GetScene()->GetWorld3D(); //Collide scripts tGameCollideScriptMapIt colIt = m_mapCollideCallbacks.begin(); for(; colIt != m_mapCollideCallbacks.end(); ++colIt) { cGameCollideScript *pScript = colIt->second; cSaveGame_cGameCollideScript savedScript; savedScript.LoadFrom(pScript); apSaveData->mlstCollideCallbacks.Add(savedScript); } //Script functions for(int i=0; i< eGameEntityScriptType_LastEnum; ++i) { if(mvCallbackScripts[i]) { cGameEntityScript script; script.mlNum = i; script.msScriptFunc = mvCallbackScripts[i]->msScriptFunc; apSaveData->mlstCallbackScripts.Add(script); } } //Script variables tGameEntityVarMapIt varIt = m_mapVars.begin(); for(; varIt != m_mapVars.end(); ++varIt) { cScriptVar scriptVar; scriptVar.mlVal = varIt->second; scriptVar.msName = varIt->first; apSaveData->mlstVars.Add(scriptVar); } //Bodies apSaveData->mvBodies.Resize(mvBodies.size()); for(size_t i=0; imvBodies[i].FromBody(mvBodies[i]); } //Log("Saving particles for %s\n",GetName().c_str()); //Particle Systems apSaveData->mvPS.Resize(mvParticleSystems.size()); for(size_t i=0; iParticleSystemExists(mvParticleSystems[i])==false) { mvParticleSystems[i] = NULL; Warning("particle system %d in %s does not exist anymore!\n",i,GetName().c_str()); } apSaveData->mvPS[i].FromPS(mvParticleSystems[i]); } //Log("Done\n"); //Lights if(mbSaveLights) { apSaveData->mvLights.Resize(mvLights.size()); for(size_t i=0; imvLights[i].FromLight(mvLights[i]); } } //Sounds apSaveData->mvSounds.Resize(mvSoundEntities.size()); for(size_t i=0; imvSounds[i].FromSound(mvSoundEntities[i]); } //Animations if(mpMeshEntity) { apSaveData->mvAnimations.Resize(mpMeshEntity->GetAnimationStateNum()); for(int i=0; i< mpMeshEntity->GetAnimationStateNum(); ++i) { cAnimationState *pAnim = mpMeshEntity->GetAnimationState(i); cGameEntityAnimation_SaveData &saveAnim = apSaveData->mvAnimations[i]; saveAnim.mbActive = pAnim->IsActive(); saveAnim.mbLoop = pAnim->IsLooping(); saveAnim.mfWeight = pAnim->GetWeight(); saveAnim.mfFadeStep = pAnim->GetFadeStep(); saveAnim.mfTimePos = pAnim->GetTimePosition(); saveAnim.mfSpeed = pAnim->GetSpeed(); } } } //----------------------------------------------------------------------- void iGameEntity::LoadFromSaveData(iGameEntity_SaveData* apSaveData) { //Properties kCopyFromVar(apSaveData,msName); kCopyFromVar(apSaveData,msFileName); kCopyFromVar(apSaveData,mfHealth); kCopyFromVar(apSaveData,mfMaxInteractDist); kCopyFromVar(apSaveData,mfMaxExamineDist); kCopyFromVar(apSaveData,msGameName); kCopyFromVar(apSaveData,msDescription); kCopyFromVar(apSaveData,mbShowDescritionOnce); kCopyFromVar(apSaveData,mbHasBeenExamined); kCopyFromVar(apSaveData,mType); SetActive(apSaveData->mbActive); //Script functions cContainerListIterator scriptIt = apSaveData->mlstCallbackScripts.GetIterator(); while(scriptIt.HasNext()) { cGameEntityScript &script = scriptIt.Next(); mvCallbackScripts[script.mlNum] = hplNew( cGameEntityScript, () ); mvCallbackScripts[script.mlNum]->msScriptFunc = script.msScriptFunc; } //Script variables cContainerListIterator scriptVar = apSaveData->mlstVars.GetIterator(); while(scriptVar.HasNext()) { cScriptVar &var = scriptVar.Next(); CreateVar(var.msName,var.mlVal); } //Bodies for(size_t i=0; imvBodies[i].ToBody(mvBodies[i]); } //Lights if(mbSaveLights) { for(size_t i=0; imvLights[i].ToLight(mvLights[i]); } } //Particle Systems int lCount=0; for(std::vector::iterator it = mvParticleSystems.begin(); it != mvParticleSystems.end();) { cParticleSystem3D *pPS = *it; /*if(pPS) Log("Loading particle system %d, %s\n",i,pPS->GetName().c_str()); else Log("Loading particle system %d, NULL\n",i);*/ cEnginePS_SaveData *pSavePS = apSaveData->GetParticleSystem(pPS); if(pSavePS) { pSavePS->ToPS(pPS); ++it; } else { //check if a null was previously saved if(apSaveData->mvPS.Size() == mvParticleSystems.size() && apSaveData->mvPS[lCount].msType == "") { ++it; } //a particle system has been removed. else { mpInit->mpGame->GetScene()->GetWorld3D()->DestroyParticleSystem(pPS); it = mvParticleSystems.erase(it); } } ++lCount; } //Sounds for(std::vector::iterator it = mvSoundEntities.begin(); it != mvSoundEntities.end(); ) { cSoundEntity *pSound = *it; cEngineSound_SaveData *pSaveSound = apSaveData->GetSoundEntity(pSound); if(pSaveSound) { pSaveSound->ToSound(pSound); ++it; } else { mpInit->mpGame->GetScene()->GetWorld3D()->DestroySoundEntity(pSound); it = mvSoundEntities.erase(it); } } //Animations if(mpMeshEntity) { if(mpMeshEntity->GetAnimationStateNum() == apSaveData->mvAnimations.Size()) { for(int i=0; i< mpMeshEntity->GetAnimationStateNum(); ++i) { cAnimationState *pAnim = mpMeshEntity->GetAnimationState(i); cGameEntityAnimation_SaveData &saveAnim = apSaveData->mvAnimations[i]; pAnim->SetActive(saveAnim.mbActive); pAnim->SetLoop(saveAnim.mbLoop); pAnim->SetWeight(saveAnim.mfWeight); pAnim->SetFadeStep(saveAnim.mfFadeStep); pAnim->SetTimePosition(saveAnim.mfTimePos); pAnim->SetSpeed(saveAnim.mfSpeed); } } else { Error("Number of animations in saved entity '%s' of type '%s' does not match!\n", GetName().c_str(), mpMeshEntity->GetName().c_str()); } } } //----------------------------------------------------------------------- void iGameEntity::SetupSaveData(iGameEntity_SaveData *apSaveData) { //Collide scripts cContainerListIterator colIt = apSaveData->mlstCollideCallbacks.GetIterator(); while(colIt.HasNext()) { cSaveGame_cGameCollideScript &savedScript = colIt.Next(); cGameCollideScript *pCallback = hplNew( cGameCollideScript, () ); pCallback->mpEntity = mpInit->mpMapHandler->GetGameEntity(savedScript.msEntity); if(pCallback->mpEntity==NULL) { Warning("Couldn't find entity '%s'\n",savedScript.msEntity.c_str()); hplDelete( pCallback ); continue; } savedScript.SaveTo(pCallback); m_mapCollideCallbacks.insert(tGameCollideScriptMap::value_type(savedScript.msEntity,pCallback)); } //Log("Setup save data!\n"); } //-----------------------------------------------------------------------