#include "StdAfx.h" #include "Projectile.h" #include "SceneManager.h" #include "EffectManager.h" #include "ClientApp.h" #include "ObjectManager.h" #include "ResourceManager.h" #include "trail.h" #include "Console.h" ProjectileEffect::ProjectileEffect(void) { m_ProjectileModel = NULL; // m_CurLife = 0.0f; // m_MaxLife = 0.0f; m_MakeTrail = 1; m_Billboard = 0; m_bTrackObject = 0; m_bExploded = 0; m_ExplorsionModel[0] = 0; m_fVelocity = 0.0f; m_fExpScale = 0.0f; m_CurVelocity = NiPoint3::ZERO; m_kOldRotation.MakeIdentity(); m_bSelfMissle = false; m_bNeedTarget = true; m_iProjectileType = 1; m_fProjectileT = 0.f; m_fSelfMisiileTime = 0.65f; m_bIsSelfMissle = false; m_bTriggerEP = false; m_pkTrail = 0; m_pkPS = NiNew NiPropertyState; NiAlphaProperty* pkAlpha = NiNew NiAlphaProperty; NiZBufferProperty* pkZ = NiNew NiZBufferProperty; NiMaterialProperty* pkM = NiNew NiMaterialProperty; pkM->SetAlpha(1.0f); pkM->SetAmbientColor(NiColor(1, 1, 1)); pkM->SetDiffuseColor(NiColor(1, 1, 1)); pkM->SetEmittance(NiColor(1, 1, 1)); m_pkPS->SetProperty(pkM); pkAlpha->SetAlphaBlending(true); pkAlpha->SetSrcBlendMode(NiAlphaProperty::ALPHA_ONE); pkAlpha->SetDestBlendMode(NiAlphaProperty::ALPHA_ONE); m_pkPS->SetProperty(pkAlpha); } ProjectileEffect::~ProjectileEffect(void) { g_ResMgr->FreeNif(m_ProjectileModel); m_ProjectileModel = NULL; if (m_pkTrail) { m_pkTrail->Deactivate(); m_pkTrail = 0; } } void replacepropertry(NiAVObject* pkObject, NiPropertyState* pkProp) { if (!pkObject) return; if (NiIsKindOf(NiNode, pkObject)) { NiNode* pkNode = (NiNode*)pkObject; for (unsigned int ui = 0; ui < pkNode->GetArrayCount(); ui++) { replacepropertry(pkNode->GetAt(ui), pkProp); } } else if (NiIsKindOf(NiGeometry, pkObject)) { NiGeometry* pkGeometry = (NiGeometry*)pkObject; pkGeometry->SetPropertyState(pkProp); } } BOOL ProjectileEffect::Create(const PROJECTILE_DESC* EntityDesc, const NiPoint3& StartPos) { NIASSERT(EntityDesc); if (EntityDesc->ProjectileModel[0] == '\0') { return FALSE; } NiAVObjectPtr ProjObj = g_ResMgr->LoadNif(EntityDesc->ProjectileModel); NiNode* ProjNode = NiDynamicCast(NiNode, ProjObj); if (ProjNode == NULL) return FALSE; ProjObj->Update(0.0f, false); ProjObj->UpdateEffects(); ProjObj->UpdateProperties(); if (EntityDesc->iProjectileType == 2) { m_pkTrail = NiNew TrailEffect; NiAVObject* pkTop = ProjObj->GetObjectByName("Arms01"); if (pkTop && m_pkTrail) { float fTrailWidth = 0.7f; NiFloatExtraData* pkED = NiStaticCast(NiFloatExtraData, pkTop->GetExtraData("trailwidth")); if (pkED) { fTrailWidth = pkED->GetValue(); } m_pkTrail->BindObject(pkTop, fTrailWidth, 0.17f, 999.0f); m_pkTrail->SetTexture("./Texture/Effect/trackblue.dds"); } replacepropertry(ProjObj, m_pkPS); } g_ResMgr->FreeNif(m_ProjectileModel); m_ProjectileModel = ProjNode; m_MakeTrail = EntityDesc->MakeTrail ? 1 : 0; m_Billboard = EntityDesc->Billboard ? 1 : 0; m_bIsSelfMissle = EntityDesc->bSelfMissile; m_bNeedTarget = EntityDesc->bNeedTarget; m_fSelfMisiileTime = EntityDesc->fSelfMissileTime; m_iProjectileType = EntityDesc->iProjectileType; m_fVelocity = EntityDesc->fFlySpeed; m_fExpScale = EntityDesc->ExpScale; m_ProjectileModel->SetTranslate(StartPos); m_OldPos = StartPos; m_kOldRotation.MakeIdentity(); m_ProjectileModel->UpdateWorldData(); if (EntityDesc->ExplosionModel[0] != 0) { NiStrcpy(m_ExplorsionModel, MAX_PATH,EntityDesc->ExplosionModel ); } if ( EntityDesc->ExpSound[0] != 0 ) { NiStrcpy(m_ExpSound, MAX_PATH,EntityDesc->ExpSound ); } return TRUE; } void ProjectileEffect::ActivateEffect(float fTime) { if (m_pkTrail) m_pkTrail->Activate(fTime, true); } void ProjectileEffect::UpdateEffect(float fTimeLine, float fDeltaTime) { if (!m_ProjectileModel) return; NiTransform kTransform; bool selfmissle = m_bIsSelfMissle; float fT = m_fProjectileT > 0.0f?(GetElapsed() / m_fProjectileT):1.0f; fT = NiClamp(fT, 0.0, 1.0f); if (fT <= m_fSelfMisiileTime) selfmissle = false; if (!selfmissle) { ProcessCurTransform(kTransform, fT); m_kPath = m_TargetPos - kTransform.m_Translate; m_kPath.Unitize(); if (fT >= 1.0f && !m_bSelfMissle) { OnCollison(fTimeLine); return; } } else { if ( m_bNeedTarget ) { CGameObject* pkObject = (CGameObject*)ObjectMgr->GetObject(m_TargetObject); if (!pkObject) { Deactivate(); return; } ProcessSelfMissile(fDeltaTime, m_OldPos, m_kOldRotation, pkObject, kTransform); } } NiPoint3 kRealPos; if (CheckCollision(m_OldPos, kTransform.m_Translate, m_TargetPos)) { m_ProjectileModel->SetLocalTransform(kTransform); OnCollison(fTimeLine); return; } m_ProjectileModel->SetLocalTransform(kTransform); float fscale = 1.f; if ( m_bNoAutoScal ) { fscale = m_fEffScale; } else fscale = kTransform.m_fScale*m_fEffScale; m_ProjectileModel->SetScale( fscale ); m_ProjectileModel->Update(GetElapsed()); m_kOldRotation = kTransform.m_Rotate; m_OldPos = kTransform.m_Translate; } void ProjectileEffect::CalcProjectileInfo(const NiPoint3& initPos, const NiPoint3& targetPos) { m_InitPos = initPos; m_TargetPos = targetPos; m_kPath = m_TargetPos - m_InitPos; float fDist = m_kPath.Unitize(); if (m_fVelocity > 0) m_fProjectileT = fDist/m_fVelocity; else { m_TargetPos = m_InitPos; } m_CurVelocity = m_kPath * m_fVelocity; } void ProjectileEffect::ProcessSelfMissile(float fDeltaT, const NiPoint3& curPos, const NiMatrix3& kCurRotation, CGameObject* pkObject, NiTransform& kTransform) { NiPoint3 kRealTargetPos; if (!GetTargetHitPosition(pkObject, kRealTargetPos)) return; NiMatrix3 kRot = kCurRotation; if (m_TargetPos != kRealTargetPos) { m_TargetPos = kRealTargetPos; CalcProjectileInfo(curPos, kRealTargetPos); NiPoint3 xvec = m_CurVelocity; xvec.Unitize(); NiPoint3 yvec = xvec.UnitCross(NiPoint3::UNIT_Z); NiPoint3 zvec = xvec.UnitCross(yvec); kRot.SetCol(0, xvec); kRot.SetCol(1, yvec); kRot.SetCol(2, zvec); } kTransform.m_Rotate = kRot; kTransform.m_Translate = curPos + m_CurVelocity * fDeltaT; kTransform.m_fScale = 1.0f; } bool ProjectileEffect::GetTargetHitPosition(SYObjID objectID, NiPoint3& hitPos, bool bMiss /*= false*/) { CGameObject* pkObject = (CGameObject*)ObjectMgr->GetObject(m_TargetObject); if (!pkObject) { return false; } return GetTargetHitPosition(pkObject, hitPos, bMiss); } bool ProjectileEffect::GetTargetHitPosition(CGameObject* pkObject, NiPoint3& hitPos, bool bMiss/*=false*/) { if (!pkObject) return false; NiNode* pkNode = pkObject->GetSceneNode(); NIASSERT(pkNode != NULL); if (!pkNode) return false; NiAVObject* pkHitNode = pkNode->GetObjectByName("Effect_Chest"); NIASSERT(pkHitNode); if (!pkHitNode) { hitPos = pkObject->GetPosition(); hitPos.z += 0.75; } else { hitPos = pkHitNode->GetWorldTranslate(); } return true; } float ProjectileEffect::ProcessCurTransform(NiTransform& kTransform, float fT) { NiPoint3 ptCurPos; NiMatrix3 kMat; // float fT = m_fProjectileT > 0.0f?(GetElapsed() / m_fProjectileT):1.0f; fT = NiClamp(fT, 0.0, 1.0f); NiPoint3 d, u, r; d = m_CurVelocity; d.Unitize(); u = d.UnitCross(NiPoint3::UNIT_Z); r = d.UnitCross(u); float fScale = 1.0f; if (m_iProjectileType == 0) // linear { ptCurPos = NiLerp(fT, m_InitPos, m_TargetPos); kMat.SetCol(0, d); kMat.SetCol(1, u); kMat.SetCol(2, r); } else if (m_iProjectileType == 1) // curve sin wave { ptCurPos = NiLerp(fT, m_InitPos, m_TargetPos); float fInterpolate = NiSin(fT * NI_PI); ptCurPos.z += fInterpolate * m_fProjectileT * 1.3333f; NiMatrix3 kRotRight; kRotRight.MakeXRotation(fT * NI_PI); kMat.SetCol(0, d); kMat.SetCol(1, u); kMat.SetCol(2, r); kMat = kMat * kRotRight; } else if (m_iProjectileType == 2) { ptCurPos = NiLerp(fT, m_InitPos, m_TargetPos); static float rad; rad -= 0.5f; if (rad <= -NI_TWO_PI) rad = 0.0f; NiMatrix3 kRotRight; kRotRight.MakeYRotation(rad); kMat.SetCol(0, r); kMat.SetCol(1, u); kMat.SetCol(2, d); fScale = 1.5f; kMat = kMat * kRotRight; } else if ( m_iProjectileType == 3 ) { ptCurPos = NiLerp(fT, m_InitPos, m_TargetPos); float fDistance = (m_TargetPos - m_InitPos).Length(); fDistance *= 0.5f; float fGravity = NiLerp(fT, 0.0, fDistance); NiPoint3 kPosHeigh = NiPoint3(ptCurPos.x, ptCurPos.y, ptCurPos.z + fGravity); ptCurPos = NiLerp(fT, kPosHeigh, ptCurPos); kMat.SetCol(0, d); kMat.SetCol(1, u); kMat.SetCol(2, r); } else { NIASSERT(0 && "unkown projectile path type"); } kTransform.m_fScale = fScale; kTransform.m_Rotate = kMat; kTransform.m_Translate = ptCurPos; return fT; } bool ProjectileEffect::CheckCollision(const NiPoint3& oldPos, const NiPoint3& newPos, const NiPoint3& targetPos) { NiPoint3 kVecOld, kVecNew; kVecOld = targetPos - oldPos; kVecNew = targetPos - newPos; kVecOld.Unitize(); kVecNew.Unitize(); if (kVecOld.Dot(kVecNew) < 0.001f) return true; return false; } void ProjectileEffect::AddEP(const SpellEffectEmit::EmitParam& ep) { m_bTriggerEP = true; m_triggerEP = ep; } void ProjectileEffect::RenderEffect(const NiCamera* pkCamera) { if (!m_ProjectileModel) return; SceneMgr->RenderObject(m_ProjectileModel); } void ProjectileEffect::OnCollison(float fTime) { if (m_bTriggerEP) { std::vector results; SpellEffectEmit::Get()->Emit(m_triggerEP, results, false); } if (m_ExplorsionModel[0] != 0) { CSceneEffect* pSceneEffect = (CSceneEffect*)EffectMgr->CreateSceneEffect(m_ExplorsionModel, true, true); NiPoint3 ExpPos = m_ProjectileModel->GetWorldTranslate(); NiAVObjectPtr ExpObj = pSceneEffect->GetAVObject(); NiNode* ExpNode = NiDynamicCast(NiNode, ExpObj); if (ExpNode == NULL) return; float ExpTime = 0.0f; CGameObject::GetMaxAnimTime(ExpObj, ExpTime, NULL); pSceneEffect->SetMaxLife(ExpTime); pSceneEffect->SetEffScale( m_fExpScale ); pSceneEffect->SetTranslate( ExpPos ); if ( m_ExpSound[0] != 0 ) { ALAudioSource* pkSound = (ALAudioSource*)AudioSystem::GetAudioSystem()->CreateSource(AudioSource::TYPE_3D); if (!pkSound) return; pSceneEffect->GetEffectNode()->AttachChild(pkSound); pkSound->SetMinMaxDistance(5.0f, 100.0f); pkSound->SetGain(1.f); pkSound->SetLoopCount( 1 ); SYState()->IAudio->PlaySound(pkSound, m_ExpSound ); } // NiPoint3 ExpPos = m_ProjectileModel->GetWorldTranslate(); // NiAVObjectPtr ExpObj = g_ResMgr->LoadNif(m_ExplorsionModel); // NiNode* ExpNode = NiDynamicCast(NiNode, ExpObj); // if (ExpNode == NULL) // return; // // float ExpTime = 0.0F; // CGameObject::GetMaxAnimTime(ExpObj, ExpTime, NULL); //// m_MaxLife = ExpTime; // m_bExploded = 1; // // CSceneEffect* pkExpEffect = NiNew CSceneEffect(ExpNode); // NIASSERT(pkExpEffect); // // if (pkExpEffect) // { // pkExpEffect->SetMaxLifeByEffectLife(); // pkExpEffect->AttachToScene(ExpPos); // pkExpEffect->Activate(fTime); // } } Deactivate(); } void ProjectileEffect::UnRegister() { Detach(); g_ResMgr->FreeNif(m_ProjectileModel); m_ProjectileModel = NULL; CEffectBase::UnRegister(); } bool ProjectileEffect::TrackObject(SYObjID TargetID, bool bMiss /*= false*/) { m_bTrackObject = 1; m_TargetObject = TargetID; CGameObject* pkObject = (CGameObject*)ObjectMgr->GetObject(m_TargetObject); if (!pkObject) { Deactivate(); return false; } NiPoint3 kCurPos = m_ProjectileModel->GetWorldTranslate(); NiPoint3 kTargetPos;// = pkObject->GetPosition(); if (!GetTargetHitPosition(TargetID, kTargetPos, bMiss)) return false; CalcProjectileInfo(kCurPos, kTargetPos); return true; } bool ProjectileEffect::TrackTarget(NiPoint3& kTarget, bool bMiss) { m_bTrackObject = 0; m_TargetObject = 0; NiPoint3 kCurPos = m_ProjectileModel->GetWorldTranslate(); CalcProjectileInfo(kCurPos, kTarget); return true; }