Files
2026-06-01 12:46:52 +02:00

1442 lines
36 KiB
C++

#include "stdafx.h"
#include "KPrimitiveSprite.h"
#include "KUIControlDamage.h"
#include "KResourceManager.h"
//#define _DAMAGE_TEST
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KDamageTextProcess Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class KDamageTextProcess
{
public:
KDamageTextProcess()
{
m_bIsValid = true;
m_pParent = NULL;
m_curTime = m_startTime = 0;
}
virtual ~KDamageTextProcess()
{
m_pParent = NULL;
}
void SetParent(KUIControlDamageText* pParent)
{
m_pParent = pParent;
}
bool GetIsValid() { return m_bIsValid; }
virtual bool DoProcess(DWORD dwTime) = 0;
protected:
KUIControlDamageText* m_pParent;
bool m_bIsValid;
DWORD m_curTime;
DWORD m_startTime;
};
class KDamageTextProcessScale : public KDamageTextProcess
{
public:
KDamageTextProcessScale(float fScaleFactor = 4.f, DWORD scaleTime = 600)
{
m_fScaleFactor = fScaleFactor;
m_scaleTime = scaleTime;
}
virtual bool DoProcess(DWORD dwTime)
{
m_curTime = dwTime;
if(m_startTime == 0)
{
m_startTime = m_curTime;
return true;
}
DWORD timeDiff = m_curTime - m_startTime;
float fRatio = getClampRatio(timeDiff, m_scaleTime);
float fScaleFactor = 1.f + (m_fScaleFactor - 1.f) * fRatio;
m_pParent->ChangeScale(fScaleFactor);
return fRatio < 1.f;
}
private:
float m_fScaleFactor;
DWORD m_scaleTime;
};
class KDamageTextProcessVisi : public KDamageTextProcess
{
public:
KDamageTextProcessVisi(DWORD visiTime = 600)
{
m_visiTime = visiTime;
}
virtual bool DoProcess(DWORD dwTime)
{
m_curTime = dwTime;
if(m_startTime == 0)
{
m_startTime = m_curTime;
return true;
}
DWORD timeDiff = m_curTime - m_startTime;
float fRatio = getClampRatio(timeDiff, m_visiTime);
m_pParent->ChangePrimitiveAlpha(1.f - fRatio);
return fRatio < 1.f;
}
private:
DWORD m_visiTime;
};
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlDamageText Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#include "KUIWndManager.h"
namespace CONTROL_DAMAGE_TEXT
{
KUIWnd* DamageTextCreator()
{
return new KUIControlDamageText;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageTextCreator, "damage_text");
KUIControlDamageText* CreateDamageText(KUIWnd* pParent, KUIWndManager* pManager, LPCSTR aniName, int x, int y)
{
KUIWND_CREATE_ARG arg;
arg.lpszAniName = aniName;
arg.lpszClassName = "damage_text";
arg.pParent = pParent;
arg.rcRect = KRect(x,y,-1,-1);
arg.lpszID = "_damage_text_id";
arg.lpszSprName = pParent->GetSprName();
return static_cast<KUIControlDamageText*>( pManager->CreateControl(arg) );
}
}
KUIControlDamageText::KUIControlDamageText()
{
}
KUIControlDamageText::~KUIControlDamageText()
{
SAFE_DELETE_VECTOR(m_vtProcess);
}
void KUIControlDamageText::Process(DWORD dwTime)
{
if(IsActivate() )
{
bool isValid = m_vtProcess.empty();
for(size_t i = 0; i < m_vtProcess.size(); ++i)
{
isValid |= m_vtProcess.at(i)->DoProcess(dwTime);
}
if(false == isValid)
{
SetActivate(false);
SetDestroy(true);
}
}
}
void KUIControlDamageText::Render(KViewportObject * pViewport, bool isFront)
{
if(IsActivate())
{
KUIControl::Render(pViewport, isFront);
}
}
void KUIControlDamageText::OnAlphaChangeNotify(float fAlpha)
{
KUIWnd::OnAlphaChangeNotify(fAlpha);
}
void KUIControlDamageText::ChangePrimitiveAlpha(float fAlpha)
{
for(int i = 0; i < m_nPieceCount; ++i)
m_pSpriteList[i].SetVisibility( m_fAlpha * fAlpha);
}
void KUIControlDamageText::ChangeScale(float fScaleFactor)
{
for(int i = 0; i < m_nPieceCount; ++i)
{
m_pSpriteList[i].GetTransform()._11 = fScaleFactor;
m_pSpriteList[i].GetTransform()._22 = fScaleFactor;
}
}
void KUIControlDamageText::AddProcess(KDamageTextProcess* pProcess)
{
pProcess->SetParent(this);
m_vtProcess.push_back(pProcess);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlNumberEffectBase Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
KUIControlNumberEffectBase::KUIControlNumberEffectBase(const DWORD* pStateTime, int beginState, int maxState)
{
m_pStateTime = pStateTime;
m_dwEffectStartTime = m_dwTime = 0;
m_nState = beginState;
m_nMaxState = maxState;
}
void KUIControlNumberEffectBase::OnAlphaChangeNotify(float fAlpha)
{
// 외부에서 Sprite Primitive의 Visibility 조절을 막기 위해서
KUIWnd::OnAlphaChangeNotify(fAlpha);
}
void KUIControlNumberEffectBase::SetActivateChildAll(bool bActive)
{
std::list< KUIWnd* >::iterator it = m_listChild.begin();
for ( ; it != m_listChild.end() ; ++it )
{
(*it)->SetActivate(bActive);
}
}
void KUIControlNumberEffectBase::_CheckNextState(DWORD dwTimeDiff)
{
if(m_nState < m_nMaxState && dwTimeDiff >= m_pStateTime[m_nState])
{
m_dwEffectStartTime = m_dwTime;
m_nState++;
m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top );
}
}
void KUIControlNumberEffectBase::_ChangeAlpha(float fAlpha)
{
for(size_t i = 0; i < m_vtPrNumberAdoptor.size(); ++i)
{
m_vtPrNumberAdoptor.at(i)->SetVisibility(m_fAlpha * fAlpha);
}
}
// Child 한테 notify 안가고 Mover에만 Notify를 주기 위해서
void KUIControlNumberEffectBase::_MovePos(int x, int y)
{
int offsetx = x - m_rcRegion.left;
int offsety = y - m_rcRegion.top;
m_rcRegion.left += offsetx; m_rcRegion.top += offsety;
m_rcRegion.right += offsetx; m_rcRegion.bottom += offsety;
for(size_t i = 0; i < m_vtSprite.size(); ++i)
m_vtPrNumberAdoptor.at(i)->SetAddPosition(offsetx,offsety);
for(size_t i = 0; i < m_vtAdditionalControlMover.size(); ++i)
m_vtAdditionalControlMover.at(i)->OnParentPosChangeNotify(offsetx,offsety);
}
void KUIControlNumberEffectBase::_CheckDestroy()
{
if(false == m_bDestroy && m_nMaxState == m_nState)
{
bool bDestroy = true;
std::list< KUIWnd* >::iterator it = m_listChild.begin();
for ( ; it != m_listChild.end() ; ++it )
{
bDestroy &= (*it)->IsDestroy();
}
SetDestroy(bDestroy);
if(bDestroy)
{
int x = 5;
}
}
}
void KUIControlNumberEffectBase::_initControl()
{
KUIControlNumber::_initControl();
m_vtStartTiemPerObject.resize(m_vtPrNumberAdoptor.size(), 0);
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlDamageExtra Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
class KUIControlDamageExtra : public KUIControlDamage
{
public:
virtual void Process(DWORD dwTime)
{
if(IsActivate())
KUIControlDamage::Process(dwTime);
}
virtual void Render(KViewportObject * pViewport, bool isFront /* = false */)
{
if(IsActivate())
KUIControlDamage::Render(pViewport,isFront);
}
void AddPlusMark(LPCSTR plusMarkAniName)
{
KResSprite* pRes = KSpriteManager::GetManager()->GetResSprite(m_sSprName.c_str(), plusMarkAniName, 0);
KSpritePrimitive* pPlusMark = new KSpritePrimitive;
pPlusMark->SetRenderEnable(true);
pPlusMark->SetRes(pRes);
pPlusMark->SetPosition(m_rcRegion.left, m_rcRegion.top, m_fZPos);
for(size_t i = 0; i < m_vtPrNumberAdoptor.size(); ++i)
{
m_vtPrNumberAdoptor.at(i)->SetAddPosition(pRes->GetSizeX(), 0, 0);
}
m_vtPrNumberAdoptor.push_back(pPlusMark);
m_vtStartTiemPerObject.push_back(0);
_registerSprite(pPlusMark);
}
};
/*
namespace CONTROL_DAMAGE_EXTRA
{
KUIWnd* DamageExtraCreator()
{
return new KUIControlDamageExtra;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageExtraCreator, "damage_extra");
KUIControlDamageExtra* CreateExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damage, KUIWnd* pParent, KUIWndManager* pManager)
{
KUIWND_CREATE_ARG arg;
arg.lpszAniName = aniName;
arg.lpszClassName = "damage_extra";
arg.pParent = pParent;
// AziaMafia FixSkill
//arg.rcRect = KRect(pParent->GetRect().right, pParent->GetRect().top, -1, -1);
arg.rcRect = KRect(pParent->GetRect().right, pParent->GetRect().top + 10, -1, -1);
arg.lpszID = "_damage_extra_id";
arg.lpszSprName = pParent->GetSprName();
arg.lpszCaption = damage;
KUIControlDamageExtra* pExtraDamage = static_cast<KUIControlDamageExtra*>( pManager->CreateControl(arg) );
pExtraDamage->AddPlusMark(plusAniName);
return pExtraDamage;
}
}
*/
namespace CONTROL_DAMAGE_EXTRA
{
KUIWnd* DamageExtraCreator()
{
return new KUIControlDamageExtra;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator(DamageExtraCreator, "damage_extra");
KUIControlDamageExtra* CreateExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damage, KUIWnd* pParent, KUIWndManager* pManager)
{
KUIWND_CREATE_ARG arg;
arg.lpszAniName = aniName;
arg.lpszClassName = "damage_extra";
arg.pParent = pParent;
arg.rcRect = KRect(pParent->GetRect().right, pParent->GetRect().top, -1, -1);
arg.lpszID = "_damage_extra_id";
arg.lpszSprName = pParent->GetSprName();
arg.lpszCaption = damage;
KUIControlDamageExtra* pExtraDamage = static_cast<KUIControlDamageExtra*>(pManager->CreateControl(arg));
pExtraDamage->AddPlusMark(plusAniName);
return pExtraDamage;
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlDamage Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace CONTROL_DAMAGE
{
KUIWnd* DamageCreator()
{
return new KUIControlDamage;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageCreator, "damage");
enum DAMAGE_STATE
{
STATE_BEGIN = 0 , // 맨처음 시작할때
STATE_POPUP, // 숫자 하나 하나가 Scale 되는 상태
STATE_NORMAL, // 그냥 떠있는 상태
STATE_POPDOWN, // 점점 사라짐.
TOTAL_STATE,
};
DWORD STATE_TIME[TOTAL_STATE] =
{
0,
0,
150,
750,
};
struct SCALE_INFO
{
SCALE_INFO()
{
POPUP_SCALE_UP_TIME = 150;
POPUP_SCALE_DOWN_TIME = 140;
NEXT_POPUP_TIME = 80;
SCALE_UP_FACTOR = 1.4f;
SCALE_DOWN_FACTOR = 0.7f;
}
DWORD POPUP_SCALE_UP_TIME;
DWORD POPUP_SCALE_DOWN_TIME;
DWORD NEXT_POPUP_TIME;
float SCALE_UP_FACTOR;
float SCALE_DOWN_FACTOR;
};
const SCALE_INFO DAMAGE_SCALE_INFO;
const float MOVE_PER_SEC_IN_Y_AXIS = -0.15f;
void scalePerObject(DWORD time, size_t size, KSpritePrimitive** ppAdoptorArray, DWORD* pTimeArray, const SCALE_INFO& info, float baseAlpha)
{
if(size == 0 || pTimeArray == NULL )
return;
// 끝에 있는 녀석이 앞에 나오는 놈이다.
bool bPopupFlag = true; // 다음번 숫자를 Popup시켜야 하는지를 Check
for(int i = static_cast<int>( size - 1 ); i >= 0; --i)
{
if(pTimeArray[i] == 0)
{
if(false == bPopupFlag)
break;
pTimeArray[i] = time;
KSpritePrimitive* pPrimitive = ppAdoptorArray[i];
pPrimitive->GetTransform()._11 = info.SCALE_DOWN_FACTOR;
pPrimitive->GetTransform()._22 = info.SCALE_DOWN_FACTOR;
pPrimitive->SetRenderEnable( true );
break;
}
DWORD timeDiff = time - pTimeArray[i];
float fScaleFactor = 1.f;
bPopupFlag = timeDiff > info.NEXT_POPUP_TIME;
if(timeDiff > info.POPUP_SCALE_UP_TIME)
{
timeDiff -= info.POPUP_SCALE_UP_TIME;
float fRatio = getClampRatio(timeDiff, info.POPUP_SCALE_DOWN_TIME);
fScaleFactor = info.SCALE_UP_FACTOR- (info.SCALE_UP_FACTOR - 1.f) * fRatio; // 줄어들기
}
else
{
float fRatio = getClampRatio(timeDiff, info.POPUP_SCALE_UP_TIME);
fScaleFactor = info.SCALE_DOWN_FACTOR + (info.SCALE_UP_FACTOR - info.SCALE_DOWN_FACTOR) * fRatio; // 작은데서 늘어나기
}
KSpritePrimitive* pPrimitive = ppAdoptorArray[i];
pPrimitive->GetTransform()._11 = fScaleFactor;
pPrimitive->GetTransform()._22 = fScaleFactor;
pPrimitive->SetVisibility(baseAlpha);
}
}
}
KUIControlDamage::KUIControlDamage()
: KUIControlNumberEffectBase(CONTROL_DAMAGE::STATE_TIME, CONTROL_DAMAGE::STATE_BEGIN, CONTROL_DAMAGE::TOTAL_STATE)
{
SetGap(-3);
}
KUIControlDamage::~KUIControlDamage()
{
}
void KUIControlDamage::Process(DWORD dwTime)
{
if( m_vtPrNumberAdoptor.empty() )
{
// assert(false == m_vtPrNumberAdoptor.empty() );
SetDestroy( true );
return;
}
using namespace CONTROL_DAMAGE;
KUIControlNumberEffectBase::Process( dwTime );
m_dwTime = dwTime;
DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime;
DWORD dwTimeDiffClamp = std::min(dwTimeDiff, STATE_TIME[m_nState] );
switch(m_nState)
{
case STATE_BEGIN:
break;
case STATE_POPUP:
{
// popup은 갯수별로 계산되어야 하므로
_MovePos( m_ptOldPos.x , m_ptOldPos.y + MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiff);
scalePerObject(m_dwTime, m_vtPrNumberAdoptor.size(), &m_vtPrNumberAdoptor.front(), &m_vtStartTiemPerObject.front(), DAMAGE_SCALE_INFO, m_fAlpha);
}
break;
case STATE_NORMAL:
{
_MovePos( m_ptOldPos.x, m_ptOldPos.y + MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiffClamp);
}
break;
case STATE_POPDOWN:
{
float fStateInc = getClampRatio(dwTimeDiff, STATE_TIME[m_nState]);
_ChangeAlpha( 1 - fStateInc);
_MovePos( m_ptOldPos.x, m_ptOldPos.y + MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiffClamp);
}
break;
}
_CheckDestroy();
_CheckNextState(dwTimeDiff);
}
void KUIControlDamage::AddDamageEtcText(LPCSTR aniName, LPCSTR perfectAni)
{
KUIWND_CREATE_ARG arg;
arg.lpszAniName = aniName;
arg.lpszClassName = "damage_etc";
arg.pParent = this;
arg.rcRect = KRect(m_rcRegion.left, m_rcRegion.top, -1, -1);
arg.lpszID = "_damage_etc_id";
arg.lpszSprName = GetSprName();
KUIControlDamageEtc* pPerfect = static_cast<KUIControlDamageEtc*>( m_pManager->CreateControl(arg) );
if(NULL != perfectAni)
{
pPerfect->AddPerfectText(perfectAni);
}
}
void KUIControlDamage::AddExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damageText)
{
_RegisterMover( CONTROL_DAMAGE_EXTRA::CreateExtraDamage(plusAniName,aniName,damageText, this, m_pManager) );
}
void KUIControlDamage::_initControl()
{
KUIControlNumberEffectBase::_initControl();
size_t numberCount = m_vtPrNumberAdoptor.size();
for(size_t i = 0; i < numberCount; ++i)
m_vtPrNumberAdoptor.at(i)->SetRenderEnable(false);
#ifdef _DAMAGE_TEST
if(m_sID != "_damage_extra_id")
AddDamageEtcText("font_white_resist00");
if(m_sID != "_damage_extra_id")
AddExtraDamage("font_add_red_plus", "font_addnumber_red", m_sCaption.c_str());
#endif
}
void KUIControlDamage::_CheckNextState(DWORD dwTimeDiff)
{
using namespace CONTROL_DAMAGE;
if(m_nState != STATE_POPUP)
{
KUIControlNumberEffectBase::_CheckNextState(dwTimeDiff);
}
else
{
if(m_vtStartTiemPerObject.empty() )
return ;
DWORD lastTime = m_vtStartTiemPerObject.front();
if( lastTime != 0 && (m_dwTime - lastTime) > DAMAGE_SCALE_INFO.POPUP_SCALE_DOWN_TIME + DAMAGE_SCALE_INFO.POPUP_SCALE_UP_TIME)
{
m_dwEffectStartTime = m_dwTime;
m_nState++;
m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top );
// Extra Damage Active
SetActivateChildAll(true);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlDamageCritical Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace CONTROL_DAMAGE_CRITICAL
{
KUIWnd* DamageCriticalCreator()
{
return new KUIControlDamageCritical;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageCriticalCreator, "damage_critical");
enum DAMAGE_STATE
{
STATE_BEGIN = 0 , // 맨처음 시작할때
STATE_POPUP, // 숫자 하나 하나가 Scale 되는 상태
STATE_POPDOWN, // Alpha 사라짐
TOTAL_STATE,
};
DWORD STATE_TIME[TOTAL_STATE] =
{
0,
0,
600,
};
struct POPUP_INFO
{
POPUP_INFO()
{
POPUP_TIME = 360;
NEXT_POPUP_TIME = 120;
POPUP_SCALE_FACTOR = 3.3f;
POPUP_MOVE_FACTOR = 30;
}
DWORD POPUP_TIME;
DWORD NEXT_POPUP_TIME;
float POPUP_SCALE_FACTOR;
int POPUP_MOVE_FACTOR;
};
CONTROL_DAMAGE::SCALE_INFO CRITICAL_SCALE_INFO;
POPUP_INFO CRITICAL_POPUP_INFO;
struct NULL_OPERATOR
{
bool operator()(size_t idx) const
{
return true;
}
};
NULL_OPERATOR* NULL_OP = NULL;
template <typename T>
void popupPerObject(DWORD time, size_t size, KSpritePrimitive** ppAdoptorArray, DWORD* pTimeArray, int* pXPosArray,
const POPUP_INFO& info, float baseAlpha, T* pPopupStartOperator)
{
if( size <= 0 ) return;
float fHalfSize = static_cast<float>(size) / 2.f;
// 끝에 있는 녀석이 앞에 나오는 놈이다.
bool bPopupFlag = true; // 다음번 숫자를 Popup시켜야 하는지를 Check
size_t rightOffsetSize = 0;
for(int i = static_cast<int>(size - 1); i >= 0; --i)
{
if(pPopupStartOperator)
bPopupFlag &= pPopupStartOperator->operator()(i);
if(pTimeArray[i] == 0 )
{
if(bPopupFlag == false)
break;
pTimeArray[i] = time;
ppAdoptorArray[i]->SetRenderEnable(true);
break;
}
DWORD timeDiff = time - pTimeArray[i];
bPopupFlag = timeDiff > info.NEXT_POPUP_TIME;
float fRatio = getClampRatio(timeDiff, info.POPUP_TIME);
float fScaleFactor = 1.f + (info.POPUP_SCALE_FACTOR - 1.f) * fRatio;
KSpritePrimitive* pPrimitive = ppAdoptorArray[i];
pPrimitive->GetTransform()._11 = fScaleFactor;
pPrimitive->GetTransform()._22 = fScaleFactor;
pPrimitive->SetVisibility( (1.f - fRatio) * baseAlpha);
if(fRatio == 1.f)
pPrimitive->SetRenderEnable( false );
float fOrder = fHalfSize - i - 1;
int moveFactor = fOrder * info.POPUP_MOVE_FACTOR * fRatio;
// 늘어난 녀석들의 길이 관리.
if(i < fHalfSize)
{
moveFactor = rightOffsetSize + info.POPUP_MOVE_FACTOR * .5f * fRatio;
rightOffsetSize += info.POPUP_MOVE_FACTOR * fRatio;
}
pPrimitive->GetTransform()._41 = pXPosArray[i] + moveFactor;
}
}
}
KUIControlDamageCritical::KUIControlDamageCritical()
: KUIControlNumberEffectBase(CONTROL_DAMAGE_CRITICAL::STATE_TIME, CONTROL_DAMAGE_CRITICAL::STATE_BEGIN, CONTROL_DAMAGE_CRITICAL::TOTAL_STATE)
{
SetGap(-5);
}
void KUIControlDamageCritical::Process(DWORD dwTime)
{
if( m_vtPrNumberAdoptor.empty() )
{
// assert(false == m_vtPrNumberAdoptor.empty() );
SetDestroy( true );
return;
}
using namespace CONTROL_DAMAGE_CRITICAL;
KUIControlNumberEffectBase::Process( dwTime );
m_dwTime = dwTime;
DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime;
DWORD dwTimeDiffClamp = std::min(dwTimeDiff, STATE_TIME[m_nState] );
float fRatio = getClampRatio(dwTimeDiff, STATE_TIME[m_nState] );
size_t halfSize = m_vtPrNumberAdoptor.size() / 2;
switch(m_nState)
{
case STATE_BEGIN:
break;
case STATE_POPUP:
CRITICAL_SCALE_INFO.NEXT_POPUP_TIME = 120;
CRITICAL_SCALE_INFO.POPUP_SCALE_UP_TIME = 185;
CRITICAL_SCALE_INFO.POPUP_SCALE_DOWN_TIME = 175;
_MovePos( m_ptOldPos.x, m_ptOldPos.y + CONTROL_DAMAGE::MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiff);
CONTROL_DAMAGE::scalePerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.front(),&m_vtStartTiemPerObject.front(), CRITICAL_SCALE_INFO, m_fAlpha);
popupPerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.at(halfSize),&m_vtStartTiemPerObject.at(halfSize), &m_vtXPosPerObject.front(),
CRITICAL_POPUP_INFO, m_fAlpha, NULL_OP);
break;
case STATE_POPDOWN:
_MovePos( m_ptOldPos.x, m_ptOldPos.y + CONTROL_DAMAGE::MOVE_PER_SEC_IN_Y_AXIS * dwTimeDiffClamp);
_ChangeAlpha(1.f - fRatio);
break;
}
_CheckDestroy();
_CheckNextState(dwTimeDiff);
}
void KUIControlDamageCritical::OnPosChangeNofity(int XOffset, int YOffset)
{
KUIControlNumberEffectBase::OnPosChangeNofity(XOffset,YOffset);
size_t count = m_vtXPosPerObject.size();
for(size_t i = 0; i < count; ++i)
{
KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at(i );
m_vtXPosPerObject.at(i) = pSource->GetTransform()._41;
}
}
void KUIControlDamageCritical::AddCriticalText(LPCSTR aniName)
{
KUIControlDamageText *pText = CONTROL_DAMAGE_TEXT::CreateDamageText(this, m_pManager, aniName, m_rcRegion.left, m_rcRegion.top);
pText->AddProcess(new KDamageTextProcessScale);
pText->AddProcess(new KDamageTextProcessVisi);
pText->SetActivate(true);
int offset = - ( pText->GetRect().GetWidth() - m_rcRegion.GetWidth() ) / 2;
pText->MovePosOffset(offset,0);
}
void KUIControlDamageCritical::AddExtraDamage(LPCSTR plusAniName, LPCSTR aniName, LPCSTR damageText)
{
_RegisterMover( CONTROL_DAMAGE_EXTRA::CreateExtraDamage(plusAniName,aniName,damageText, this, m_pManager) );
}
void KUIControlDamageCritical::_initControl()
{
KUIControlNumberEffectBase::_initControl();
size_t numberCount = m_vtPrNumberAdoptor.size();
for(size_t i = 0; i < numberCount; ++i)
{
KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at(i );
pSource->SetRenderEnable(false);
m_vtXPosPerObject.push_back(pSource->GetTransform()._41 );
// 여분의 양을 복사
KSpritePrimitive* pClone = new KSpritePrimitive;
pClone->SetRenderEnable(false);
pClone->SetRes(pSource->GetRes());
pClone->SetPosition(pSource->GetPosition() );
m_vtPrNumberAdoptor.push_back(pClone);
_registerSprite(pClone);
}
// 이것도 다시 설정
m_vtStartTiemPerObject.resize(m_vtPrNumberAdoptor.size(), 0);
#ifdef _DAMAGE_TEST
AddCriticalText("font_red_critical00");
if(m_sID != "_damage_extra_id")
AddExtraDamage("font_add_red_plus", "font_addnumber_red", m_sCaption.c_str());
#endif
}
void KUIControlDamageCritical::_CheckNextState(DWORD dwTimeDiff)
{
using namespace CONTROL_DAMAGE_CRITICAL;
if(m_nState != STATE_POPUP)
{
KUIControlNumberEffectBase::_CheckNextState(dwTimeDiff);
}
else
{
if(m_vtStartTiemPerObject.empty() )
return ;
DWORD lastTime = m_vtStartTiemPerObject.front();
if( lastTime != 0 && (m_dwTime - lastTime) > CRITICAL_POPUP_INFO.POPUP_TIME)
{
m_dwEffectStartTime = m_dwTime;
m_nState++;
m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top );
// Extra Damage Activate
SetActivateChildAll(true);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlHealing Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace CONTROL_HEALING
{
KUIWnd* HealingCreator()
{
return new KUIControlHealing;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( HealingCreator, "healing");
enum HEALING_STATE
{
STATE_BEGIN , // 맨처음 시작할때
STATE_POPUP, // 숫자 하나 하나가 올라갔다가 내려오는 상태
STATE_POPDOWN, // 점점 사라짐.
TOTAL_STATE,
};
DWORD STATE_TIME[TOTAL_STATE] =
{
0,
0,
750,
};
enum MOVE_TIME
{
MOVE_UP =0,
MOVE_DOWN,
SHAKE_UP,
SHAKE_DOWN,
TOTAL_TIME,
};
int getCurMoveTypeByTimeDiff(DWORD* pTimeDiff, DWORD* pMoveTimeTable)
{
int tableIndex = 3;
DWORD timeSum = 0;
for(int i = 0; i < TOTAL_TIME; ++i)
{
if(*pTimeDiff < timeSum)
{
tableIndex = i - 1;
*pTimeDiff -= (timeSum - pMoveTimeTable[i - 1]);
return tableIndex;
}
timeSum += pMoveTimeTable[i];
}
*pTimeDiff = pMoveTimeTable[TOTAL_TIME - 1];
return tableIndex;
}
int getHeightOffsetByType(int type, int* pMoveHeightTable)
{
int sum = 0;
for(int i = 0; i < type; ++i)
sum += pMoveHeightTable[i];
return sum;
}
struct JUMP_INFO
{
JUMP_INFO(DWORD* pTimeTable, int* pHeightTable, DWORD nextPopupTime)
{
MOVE_TIME_TABLE = pTimeTable;
MOVE_HEIGHT_TABLE = pHeightTable;
NEXT_POPUP_TIME = nextPopupTime;
}
DWORD* MOVE_TIME_TABLE;
int* MOVE_HEIGHT_TABLE;
DWORD NEXT_POPUP_TIME;
};
DWORD MOVE_TIME_TABLE[TOTAL_TIME] =
{
150,
250,
100,
100,
};
int MOVE_HEIGHT_TABLE[TOTAL_TIME] =
{
-40,
67,
-12,
12,
};
const DWORD POPUP_MOVE_TOTAL_TIME = MOVE_TIME_TABLE[MOVE_UP] + MOVE_TIME_TABLE[MOVE_DOWN];
const DWORD POPUP_SHAKE_TOTAL_TIME = MOVE_TIME_TABLE[SHAKE_UP] + MOVE_TIME_TABLE[SHAKE_DOWN];
const DWORD POPUP_TOTAL_TIME = POPUP_MOVE_TOTAL_TIME + POPUP_SHAKE_TOTAL_TIME;
JUMP_INFO HEALING_JUMP_INFO(MOVE_TIME_TABLE, MOVE_HEIGHT_TABLE, 50);
void jumpPerObject(DWORD time, size_t size, KSpritePrimitive** ppAdoptorArray, DWORD* pTimeArray, int topPosition, const JUMP_INFO& info)
{
if(size == 0)
return ;
// 끝에 있는 녀석이 앞에 나오는 놈이다.
bool bPopupFlag = true; // 다음번 숫자를 Popup시켜야 하는지를 Check
for(int i = static_cast<int>( size - 1); i >= 0; --i)
{
if(pTimeArray[i] == 0)
{
if(false == bPopupFlag)
break;
pTimeArray[i] = time;
break;
}
DWORD timeDiff = time - pTimeArray[i];
bPopupFlag = timeDiff > info.NEXT_POPUP_TIME;
int moveOffset = 0;
int moveType = getCurMoveTypeByTimeDiff(&timeDiff, info.MOVE_TIME_TABLE);
int startOffset = getHeightOffsetByType(moveType, info.MOVE_HEIGHT_TABLE);
int height = info.MOVE_HEIGHT_TABLE[moveType];
switch(moveType)
{
case MOVE_UP:
moveOffset = height * getClampRatioSqrt(timeDiff, info.MOVE_TIME_TABLE[moveType] );
break;
case SHAKE_UP:
moveOffset = height * getClampRatio(timeDiff, info.MOVE_TIME_TABLE[moveType] );
break;
case MOVE_DOWN:
moveOffset = height * getClampRatioPow(timeDiff, info.MOVE_TIME_TABLE[moveType] );
break;
case SHAKE_DOWN:
moveOffset = height * getClampRatio(timeDiff, info.MOVE_TIME_TABLE[moveType] );
break;
}
const K3DMatrix& mat = ppAdoptorArray[i]->GetTransform();
ppAdoptorArray[i]->SetPosition(mat._41, topPosition + startOffset + moveOffset, mat._43 );
}
}
}
KUIControlHealing::KUIControlHealing()
: KUIControlNumberEffectBase(CONTROL_HEALING::STATE_TIME, CONTROL_HEALING::STATE_BEGIN, CONTROL_DAMAGE_CRITICAL::TOTAL_STATE)
{
SetGap(-3);
}
KUIControlHealing::~KUIControlHealing()
{
}
void KUIControlHealing::Process(DWORD dwTime)
{
if( m_vtPrNumberAdoptor.empty() )
{
// assert(false == m_vtPrNumberAdoptor.empty() );
SetDestroy( true );
return;
}
//using namespace CONTROL_HEALING;
KUIControlNumberEffectBase::Process( dwTime );
m_dwTime = dwTime;
DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime;
switch(m_nState)
{
case CONTROL_HEALING::STATE_BEGIN:
break;
case CONTROL_HEALING::STATE_POPUP:
{
CONTROL_HEALING::jumpPerObject(m_dwTime, m_vtPrNumberAdoptor.size(), &m_vtPrNumberAdoptor.front(), &m_vtStartTiemPerObject.front(), m_rcRegion.top,
CONTROL_HEALING::HEALING_JUMP_INFO);
}
break;
case CONTROL_HEALING::STATE_POPDOWN:
{
float fStateInc = getClampRatio(dwTimeDiff, CONTROL_HEALING::STATE_TIME[m_nState]);
_ChangeAlpha( 1 - fStateInc);
}
break;
}
_CheckDestroy();
_CheckNextState(dwTimeDiff);
}
int KUIControlHealing::GetEachNumberState(size_t idx)
{
using namespace CONTROL_HEALING;
DWORD timeDiff = m_dwTime - m_vtStartTiemPerObject.at(idx);
return getCurMoveTypeByTimeDiff(&timeDiff, HEALING_JUMP_INFO.MOVE_TIME_TABLE);
}
void KUIControlHealing::_CheckNextState(DWORD dwTimeDiff)
{
using namespace CONTROL_HEALING;
if(m_nState != STATE_POPUP)
{
KUIControlNumberEffectBase::_CheckNextState(dwTimeDiff);
}
else
{
if(m_vtStartTiemPerObject.empty() )
return ;
DWORD lastTime = m_vtStartTiemPerObject.front();
if( lastTime != 0 && (m_dwTime - lastTime) > POPUP_TOTAL_TIME)
{
m_dwEffectStartTime = m_dwTime;
m_nState++;
m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top );
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlHealingMaximize Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace CONTROL_HEALING_MAXIMIZE
{
KUIWnd* HealingCreator()
{
return new KUIControlHealingMaximize;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( HealingCreator, "healing_maximize");
struct POPUP_OP
{
POPUP_OP(KUIControlHealingMaximize* pParent)
{
_pParent = pParent;
}
bool operator()(size_t idx) const
{
int state = _pParent->GetEachNumberState(idx);
return state == CONTROL_HEALING::SHAKE_DOWN || state == CONTROL_HEALING::SHAKE_UP ;
}
KUIControlHealingMaximize* _pParent;
};
}
KUIControlHealingMaximize::KUIControlHealingMaximize()
{
}
KUIControlHealingMaximize::~KUIControlHealingMaximize()
{
}
void KUIControlHealingMaximize::Process(DWORD dwTime)
{
if( m_vtPrNumberAdoptor.empty() )
{
// assert(false == m_vtPrNumberAdoptor.empty() );
SetDestroy( true );
return;
}
if(m_nState == CONTROL_HEALING::STATE_POPUP)
{
KUIControlNumberEffectBase::Process( dwTime );
m_dwTime = dwTime;
size_t halfSize = m_vtPrNumberAdoptor.size() / 2;
CONTROL_HEALING::jumpPerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.front(), &m_vtStartTiemPerObject.front(), m_rcRegion.top,
CONTROL_HEALING::HEALING_JUMP_INFO);
CONTROL_HEALING_MAXIMIZE::POPUP_OP op(this);
static CONTROL_DAMAGE_CRITICAL::POPUP_INFO info;
info.NEXT_POPUP_TIME = 80;
CONTROL_DAMAGE_CRITICAL::popupPerObject(m_dwTime, halfSize, &m_vtPrNumberAdoptor.at(halfSize), &m_vtStartTiemPerObject.at(halfSize),
&m_vtXPosPerObject.front(), info, m_fAlpha, &op);
_CheckNextState(m_dwTime);
}
else
{
KUIControlHealing::Process( dwTime );
}
}
void KUIControlHealingMaximize::OnPosChangeNofity(int XOffset, int YOffset)
{
KUIControlNumberEffectBase::OnPosChangeNofity(XOffset,YOffset);
size_t count = m_vtXPosPerObject.size();
for(size_t i = 0; i < count; ++i)
{
KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at(i );
m_vtXPosPerObject.at(pSource->GetTransform()._41 );
}
}
void KUIControlHealingMaximize::AddMaxHealText(LPCSTR aniName)
{
KUIControlDamageText *pText = CONTROL_DAMAGE_TEXT::CreateDamageText(this, m_pManager, aniName, m_rcRegion.left, m_rcRegion.top - 20);
pText->AddProcess(new KDamageTextProcessScale(2.5f, 375));
pText->AddProcess(new KDamageTextProcessVisi(450));
int offset = - ( pText->GetRect().GetWidth() - m_rcRegion.GetWidth() ) / 2;
pText->MovePosOffset(offset,0);
}
void KUIControlHealingMaximize::_initControl()
{
KUIControlHealing::_initControl();
size_t numberCount = m_vtPrNumberAdoptor.size();
for(size_t i = 0; i < numberCount; ++i)
{
KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at (i );
m_vtXPosPerObject.push_back(pSource->GetTransform()._41 );
// 여분의 양을 복사
KSpritePrimitive* pClone = new KSpritePrimitive;
pClone->SetRenderEnable( false );
pClone->SetRes(pSource->GetRes());
pClone->SetPosition(pSource->GetPosition() );
m_vtPrNumberAdoptor.push_back(pClone);
_registerSprite(pClone);
}
size_t halfSize = m_vtPrNumberAdoptor.size() / 2;
for(size_t i = halfSize; i < m_vtPrNumberAdoptor.size(); ++i)
{
KSpritePrimitive* pSource = m_vtPrNumberAdoptor.at (i );
K3DVector pos = pSource->GetPosition();
pos.y += CONTROL_HEALING::MOVE_HEIGHT_TABLE[CONTROL_HEALING::MOVE_UP] + CONTROL_HEALING::MOVE_HEIGHT_TABLE[CONTROL_HEALING::MOVE_DOWN];
pSource->SetPosition(pos);
}
// 이것도 다시 설정
m_vtStartTiemPerObject.resize(m_vtPrNumberAdoptor.size(), 0);
AddMaxHealText("font_green_maxheal00");
}
void KUIControlHealingMaximize::_CheckNextState(DWORD dwTimeDiff)
{
if(m_nState != CONTROL_HEALING::STATE_POPUP)
{
KUIControlHealing::_CheckNextState(dwTimeDiff);
}
else
{
if(m_vtStartTiemPerObject.empty() )
return ;
// Time 및 Object는 반대로 배열되어 있다. 즉
// "369" 라는 숫자가 있으면 각 실제로 배열에는 [9,6,3] 의 data가 들어 있다.
DWORD lastTime = m_vtStartTiemPerObject.front();
DWORD halfTime = m_vtStartTiemPerObject.at( m_vtStartTiemPerObject.size() / 2 );
DWORD firstJumpTime = m_vtStartTiemPerObject.at( m_vtStartTiemPerObject.size() / 2 - 1 );
// Popup과 Jump가 전부 끝났음..
if( lastTime != 0 && (m_dwTime - lastTime) > CONTROL_HEALING::POPUP_TOTAL_TIME &&
halfTime != 0 && (m_dwTime - halfTime) > CONTROL_DAMAGE_CRITICAL::CRITICAL_POPUP_INFO.POPUP_TIME )
{
m_dwEffectStartTime = m_dwTime;
m_nState++;
m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top );
}
// 첫번째 놈이 Jump하고 나서 적정 시간이 지나면 MaxHeal 출력
if( firstJumpTime != 0 && (m_dwTime - firstJumpTime) >= CONTROL_HEALING::POPUP_MOVE_TOTAL_TIME - 100)
{
SetActivateChildAll(true);
}
}
}
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// KUIControlDamageEtc Implement
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
namespace CONTROL_DAMAGE_ETC
{
KUIWnd* DamageEtcCreator()
{
return new KUIControlDamageEtc;
}
bool bRegister = KUIFactory::GetInstance()->RegisterCreator( DamageEtcCreator, "damage_etc");
enum DAMAGE_ETC_STATE
{
STATE_BEGIN , // 맨처음 시작할때
STATE_MOVEUP, // 시작해서 올라갈때
STATE_MOVEDOWN, // 시작해서 떨어질때
STATE_SHAKEUP, // 튕겨서 올라감
STATE_SHAKEDOWN, // 튕겼다가 내려감
STATE_POPDOWN, // 알파로 사라짐
TOTAL_STATE,
};
DWORD TIME_TABLE[TOTAL_STATE] =
{
0,
100,
200,
50,
50,
750,
};
int MOVE_HEIGHT_TABLE[TOTAL_STATE] =
{
0,
-40,
80,
-12,
12,
0,
};
}
KUIControlDamageEtc::KUIControlDamageEtc()
{
m_nState = CONTROL_DAMAGE_ETC::STATE_BEGIN;
m_dwEffectStartTime = 0;
m_dwTime = 0;
m_delayTime = 0;
}
KUIControlDamageEtc::~KUIControlDamageEtc()
{
}
void KUIControlDamageEtc::Process(DWORD dwTime)
{
using namespace CONTROL_DAMAGE_ETC;
KUIControl::Process( dwTime );
m_dwTime = dwTime;
DWORD dwTimeDiff = m_dwTime - m_dwEffectStartTime;
if(m_dwEffectStartTime == 0)
{
m_dwEffectStartTime = m_dwTime;
return;
}
if(m_delayTime != 0)
{
if( dwTimeDiff > m_delayTime )
m_delayTime = 0;
return;
}
int height = MOVE_HEIGHT_TABLE[m_nState];
switch(m_nState)
{
case STATE_BEGIN:
#ifdef _DAMAGE_TEST
if( m_sID != "_damage_perfect_id")
AddPerfectText("font_white_perfect00");
#endif
break;
case STATE_MOVEUP:
case STATE_SHAKEUP:
_MovePos(m_ptOldPos.x, m_ptOldPos.y + height * getClampRatioSqrt(dwTimeDiff, TIME_TABLE[m_nState] ) );
break;
case STATE_MOVEDOWN:
case STATE_SHAKEDOWN:
_MovePos(m_ptOldPos.x, m_ptOldPos.y + height * getClampRatioPow(dwTimeDiff, TIME_TABLE[m_nState] ) );
break;
case STATE_POPDOWN:
_ChangeAlpha(1.f - getClampRatio(dwTimeDiff, TIME_TABLE[m_nState]) );
break;
}
_CheckNextState(dwTimeDiff);
}
void KUIControlDamageEtc::Render(KViewportObject * pViewport, bool isFront)
{
if(m_delayTime == 0)
KUIControl::Render(pViewport,isFront);
}
void KUIControlDamageEtc::OnAlphaChangeNotify(float fAlpha)
{
// 외부에서 Sprite Primitive의 Visibility 조절을 막기 위해서
KUIWnd::OnAlphaChangeNotify(fAlpha);
}
void KUIControlDamageEtc::AddPerfectText(LPCSTR aniName)
{
KUIWND_CREATE_ARG arg;
arg.lpszAniName = aniName;
arg.lpszClassName = "damage_etc";
arg.pParent = this;
arg.rcRect = KRect(m_rcRegion.left + 40, m_rcRegion.top + 15, -1, -1);
arg.lpszID = "_damage_perfect_id";
arg.lpszSprName = GetSprName();
KUIControlDamageEtc* pPerfect = static_cast<KUIControlDamageEtc*>( m_pManager->CreateControl(arg) );
pPerfect->SetDelayTime(200);
}
void KUIControlDamageEtc::_ChangeAlpha(float fAlpha)
{
for(int i = 0; i < m_nPieceCount; ++i)
m_pSpriteList[i].SetVisibility( m_fAlpha * fAlpha);
}
void KUIControlDamageEtc::_MovePos(int x, int y)
{
int offsetx = x - m_rcRegion.left;
int offsety = y - m_rcRegion.top;
m_rcRegion.left += offsetx; m_rcRegion.top += offsety;
m_rcRegion.right += offsetx; m_rcRegion.bottom += offsety;
for(int i = 0; i < m_nPieceCount; ++i)
m_pSpriteList[i].SetAddPosition( offsetx, offsety);
}
void KUIControlDamageEtc::_CheckNextState(DWORD dwTimeDiff)
{
if(false == m_bDestroy && CONTROL_DAMAGE_ETC::TOTAL_STATE == m_nState)
{
bool bDestroy = true;
std::list< KUIWnd* >::iterator it = m_listChild.begin();
for ( ; it != m_listChild.end() ; ++it )
{
bDestroy &= (*it)->IsDestroy();
}
SetDestroy(bDestroy);
}
if(m_nState < CONTROL_DAMAGE_ETC::TOTAL_STATE && dwTimeDiff >= CONTROL_DAMAGE_ETC::TIME_TABLE[m_nState] )
{
m_dwEffectStartTime = m_dwTime;
m_nState++;
m_ptOldPos = KPoint( m_rcRegion.left, m_rcRegion.top );
}
}