Files
Sun1602/Client/GameClient/State/StateAttackJump.cpp
T
2022-10-26 12:25:11 +08:00

302 lines
8.4 KiB
C++

//------------------------------------------------------------------------------
// StateAttackJump.cpp
// (C) 2005 Webzen Sunstudio
//------------------------------------------------------------------------------
#include "SunClientPrecompiledHeader.h"
#include "statebase.h"
#include "StateAttackJump.h"
#include "character.h"
#include "monster.h"
#include "InterfaceManager.h"
#include "GlobalFunc.h"
#include "Application.h"
#include "Hero.h"
#include "HeroActionInput.h"
// 중력가속도
const int GRAVITY = 20;
// 점프하는 높이
const float UP_HEIGHT = 2.5f;
const int X_ACCELERATION = 20;
//------------------------------------------------------------------------------
/**
*/
StateAttackJump::StateAttackJump(void)
{
}
//------------------------------------------------------------------------------
/**
*/
StateAttackJump::~StateAttackJump(void)
{
}
//------------------------------------------------------------------------------
/**
점프는 MOVE 로 반드시 돌아가야한다.
죽지도 않아요~
*/
BOOL StateAttackJump::CanTransite(Object* pOwner, DWORD CurTime, StateBase* pToTransiteState)
{
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
STATECHANGE::TYPE StateAttackJump::OnStart(Object* pOwner, DWORD CurTime)
{
Character* pChr = (Character*)pOwner;
//Character * pTarget = (Character *)pChr->GetTargetObject();
pChr->SetFreeMove(TRUE);
DWORD dwAttackSerial = pChr->GetNextActionAttackSerial();
pChr->SetCurrentAttackSerial(dwAttackSerial);
pChr->SetNextAttackSerial(dwAttackSerial);
ATTACK_JUMP_INFO * pAttackJump = &pChr->m_AttackJumpInfo;
// 공격 애니메이션 세팅
WzID animationID = pChr->GetCurrentAttackJumpAnimation();
assert(animationID);
pChr->StopBlendAnimation();
pChr->SetAnimation(animationID,FALSE);
pChr->SetCurrentFrame(0.0f);
// 히트수 처리를 위한 임시변수
pChr->m_iHitEvent = 0;
pChr->m_iHitCount = 0;
pChr->m_bRightHit = FALSE;
pAttackJump->m_dwTotalTime =
pChr->GetCurrentAction()->ATTACKJUMP.dwEndTime -
pChr->GetCurrentAction()->ATTACKJUMP.dwStartTime;
// 아래로 내려가야 하는 높이
pAttackJump->m_fDestHeight =
pChr->GetCurrentAction()->ATTACKJUMP.vDestPos.wvPos.z -
pChr->GetCurrentAction()->ATTACKJUMP.vCurPos.wvPos.z;
// 목적지 좌표와 현재 좌표간의 차이
pAttackJump->m_vDist =
pChr->GetCurrentAction()->ATTACKJUMP.vDestPos.wvPos -
pChr->GetCurrentAction()->ATTACKJUMP.vCurPos.wvPos;
//pAttackJump->m_vDist.z = 0;
// 캐릭터 방향 설정
pChr->SetAngle( Math_GetAngleFromVector(&pAttackJump->m_vDist), TRUE );
if (UP_HEIGHT == 0 && pAttackJump->m_fDestHeight == 0)
{
return STATECHANGE::FAILED;
}
// 점프를 시작할 때의 초기 속도
float fDestLength = VectorLength( &pAttackJump->m_vDist );
float fUpHeight = max( UP_HEIGHT, pAttackJump->m_fDestHeight );
pAttackJump->m_fVelocity_Y = sqrt( 2 * GRAVITY * fUpHeight );
if( pAttackJump->m_fDestHeight >= UP_HEIGHT )
{
pAttackJump->m_fVelocity_X = fDestLength * GRAVITY / pAttackJump->m_fVelocity_Y;
}
else
{
pAttackJump->m_fVelocity_X = fDestLength * GRAVITY /
(
pAttackJump->m_fVelocity_Y +
sqrt( pAttackJump->m_fVelocity_Y * pAttackJump->m_fVelocity_Y - 2*GRAVITY*pAttackJump->m_fDestHeight )
);
}
if ( !GENERALPARAM->IsNet() && g_pHero)
{
MSG_CG_SYNC_NPC_JUMPRESULT_BRD SendPacket;
SendPacket.m_dwObjectKey = g_HeroInput.GetCurrentTarget();
SendPacket.m_dwTargetObjectKey = g_pHero->GetObjectKey();
SendPacket.m_byAttackType = 0;
SendPacket.m_wvCurPos = g_pHero->GetPosition();
SendPacket.m_wDamage = 1;
SendPacket.m_wTargetHP = 5;
SendPacket.m_byEffect = 0; // 공격 결과에 대한 특수 이펙트(크리티컬이 터졌다...)
g_pApplication->AddVirtualPacket(
CI_GAMESERVERIDX, (BYTE *)&SendPacket, sizeof(SendPacket));
}
return STATECHANGE::SUCCESS;
}
//------------------------------------------------------------------------------
/**
*/
STATEPROCESS::TYPE StateAttackJump::OnProcess(Object* pOwner, DWORD CurTime,DWORD dwTick)
{
STATEPROCESS::TYPE ret = STATEPROCESS::HOLD;
Character* pChr = (Character*)pOwner;
ATTACK_JUMP_INFO * pAttackJump = &pChr->m_AttackJumpInfo;
float fRet = 0.f;
WzEvent event;
ZeroMemory(&event, sizeof(event));
DWORD dwRunTime = g_CurTime - pChr->GetCurrentAction()->ATTACKJUMP.dwStartTime ;
float fMoveRate = (float)dwRunTime / (float)pChr->m_AttackJumpInfo.m_dwTotalTime;
if (fMoveRate >= 1.0f)
{
fMoveRate = 1.0f;
}
// 평면(x,y)상으로 이동한 거리
float fMoveLength = VectorLength( &( pAttackJump->m_vDist * fMoveRate ) );
float fVecLength = VectorLength( &pAttackJump->m_vDist );
// fMoveLength를 기준으로 현재 높이 값을 계산한다.
float fResult_Delta_Z =
( 2*pAttackJump->m_fVelocity_X*pAttackJump->m_fVelocity_Y-GRAVITY*fMoveLength ) /
( 2*pAttackJump->m_fVelocity_X*pAttackJump->m_fVelocity_X ) * fMoveLength;
// 최종적인 현재 좌표를 셋팅한다.
WzVector vResultPos;
if ( 0 == fVecLength )
{
vResultPos =
pChr->GetCurrentAction()->ATTACKJUMP.vCurPos.wvPos;
}
else
{
vResultPos =
pChr->GetCurrentAction()->ATTACKJUMP.vCurPos.wvPos + pAttackJump->m_vDist * fMoveRate;
vResultPos.z = fResult_Delta_Z + pChr->GetCurrentAction()->ATTACKJUMP.vCurPos.wvPos.z;
}
float fTotalFrame = pChr->GetTotalFrame();
if (fMoveRate <= 0.45f)
{
//float fNewFrame = (fTotalFrame * 0.2f) * (fMoveRate / 0.2f);
float fNewFrame = fTotalFrame * fMoveRate;
pChr->SetCurrentFrame(fNewFrame);
fRet = pChr->ProcessAnimation(0, &event);
}
else if (fMoveRate >= 0.8f)
{
fRet = pChr->ProcessAnimation(dwTick, &event);
}
else
{
fRet = pChr->ProcessAnimation(0, NULL);
}
pChr->ProcessInterpolation(dwTick);
// 타격점 타이밍
if (event.m_iNumCustom)
{
for (int a = 0; a < event.m_iNumCustom; a++)
{
// 타격점에 오른쪽치기인지 왼쪽치기인지 결정한다.
switch(event.m_Custom[a].m_iaParam3[0])
{
// 1번 event는 공격 타이밍
case 1:
{
pChr->m_iHitEvent++;
if (event.m_Custom[a].m_iaParam3[1] == 1)
{
pChr->m_bRightHit = FALSE;
}
else
{
pChr->m_bRightHit = TRUE;
}
if( pChr->m_iHitCount < 1 )
{
if( pChr->ProcessAttackResult( pChr->GetCurrentAttackSerial(), FALSE, pChr->m_bRightHit ) )
{
pChr->m_iHitCount++;
}
}
}
break;
}
}
}
// process interpolation 다음에renderpart위치를 set하므로 유효하다.
pChr->GetBasePart()->SetPosition(vResultPos);
pChr->UpdateOctree();
if (fMoveRate >= 1.0f)
{
pChr->SetPosition(vResultPos);
pChr->SetVisiblePos(vResultPos);
if ( fRet >= 100.f )
{
if (pChr->ProcessNextAction())
{
return STATEPROCESS::SUSPEND;
}
else
{
return STATEPROCESS::END;
}
}
}
return ret;
}
//------------------------------------------------------------------------------
/**
*/
STATECHANGE::TYPE StateAttackJump::OnEnd(Object* pOwner, DWORD CurTime)
{
Character* pChr = (Character*)pOwner;
pChr->SetJumpFlag(FALSE);
pChr->m_fHeight = 0.0f;
if (pChr->m_iHitCount < pChr->GetShotCount())
{
#if defined( _DEBUG )
TCHAR szMessage[INTERFACE_STRING_LENGTH], szText[INTERFACE_STRING_LENGTH];
// 오브젝트 %d의 공격 타격점이 없거나 공격이 취소되었습니다.
g_InterfaceManager.GetInterfaceString( eST_STATE_ATTACK_FAIL, szText, INTERFACE_STRING_LENGTH );
_stprintf( szMessage, szText, pChr->GetObjectKey() );
GlobalFunc::OutputMsg_Notice(eOUTPUT_MSG_CHAT, szMessage );
#endif
pChr->ProcessAttackResult( pChr->GetCurrentAttackSerial(), TRUE );
}
pChr->m_iHitCount = 0;
pChr->AddNextAttackSerial();
pChr->SetAttackStandTime(ATTACK_STAND_TIME);
pChr->SetFreeMove(FALSE);
return STATECHANGE::SUCCESS;
}