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

415 lines
9.3 KiB
C++

//------------------------------------------------------------------------------
// StateAttack.cpp
// (C) 2005 Webzen Sunstudio
//------------------------------------------------------------------------------
#include "SunClientPrecompiledHeader.h"
#include "statebase.h"
#include "stateattack.h"
#include "character.h"
#include "player.h"
#include "soundeffect.h"
#include "InterfaceManager.h"
#include "monster.h"
#include "objectmanager.h"
#include "ProjectileManagerEx.h"
#include "hero.h"
#include "heroactioninput.h"
#include "ChatDialog.h"
#include "NumericValues.h"
#include "globalfunc.h"
#include "PlayerMonster.h"
//------------------------------------------------------------------------------
/**
*/
StateAttack::StateAttack(void)
{
}
//------------------------------------------------------------------------------
/**
*/
StateAttack::~StateAttack(void)
{
}
//------------------------------------------------------------------------------
/**
*/
BOOL StateAttack::CanTransite(Object* pOwner, DWORD CurTime, StateBase* pToTransiteState)
{
return TRUE;
}
//------------------------------------------------------------------------------
/**
*/
STATECHANGE::TYPE StateAttack::OnStart(Object* pOwner, DWORD CurTime)
{
Character *pChr = (Character *)pOwner;
Character *pTarget = (Character *)pChr->GetTargetObject();
DWORD dwAttackSerial = pChr->GetNextActionAttackSerial();
pChr->SetCurrentAttackSerial(dwAttackSerial);
pChr->SetNextAttackSerial(dwAttackSerial);
// 타겟이 설정되어 있지 않으면
if( pTarget == NULL )
{
return STATECHANGE::FAILED;
}
// 방향 설정
WzVector wvTarget = pTarget->GetPosition();
if (pChr->IsKindOfObject(MONSTER_OBJECT))
{
Monster * pMonster = (Monster *)pChr;
if ( MONSTER_TYPE_SETTING_MAPOBJECT != pMonster->GetMonsterType() )
{
// 설치형 몬스터가 아닌 몬스터만 방향설정을 해라.
pChr->SetDirection( wvTarget );
}
}
else
{
pChr->SetDirection( wvTarget );
}
// 공격 애니메이션 세팅
WzID animationID = pChr->GetCurrentAttackAnimation();
assert(animationID);
pChr->SetAnimation(animationID,FALSE);
if (pChr->IsRangedNormalAttack() )
{
pChr->OnShotStart();
}
// 이동하면서 하는 공격일경우
if (pChr->m_bAttackMove)
{
pChr->Move(pChr->m_vAttackStartPos.wvPos,pChr->m_vAttackEndPos.wvPos,CMS_RUN,TRUE,pChr->m_vAttackStartPos.wTile,pChr->m_vAttackEndPos.wTile);
}
// 히트수 처리를 위한 임시변수
pChr->m_iHitEvent = 0;
pChr->m_iHitCount = 0;
pChr->m_bRightHit = FALSE;
if (pChr->IsKindOfObject(PLAYER_OBJECT) || pChr->IsKindOfObject(SSQMONSTER_OBJECT))
{
pChr->StopBlendAnimation();
}
m_bCriAttkAni = TRUE;
#ifdef _YJ_MOD_BLOW_MOTION_001188
m_bHit = FALSE;
if(pChr->IsKindOfObject(PLAYER_OBJECT))
{
Player* pPlayer = (Player*)pChr;
eWEAPONTYPE eWType = (eWEAPONTYPE)pPlayer->GetWeaponKind();
switch(eWType)
{
case eWEAPONTYPE_TWOHANDAXE:
m_dwStopTime = 240;
break;
case eWEAPONTYPE_TWOHANDSWORD:
m_dwStopTime = 190;
break;
case eWEAPONTYPE_SPEAR:
m_dwStopTime = 240;
break;
default:
m_dwStopTime = 0;
break;
}
}
#endif //_YJ_MOD_BLOW_MOTION_001188
return STATECHANGE::SUCCESS;
}
STATEPROCESS::TYPE StateAttack::OnProcess(Object* pOwner, DWORD CurTime , DWORD dwTick)
{
Character* pChr = (Character*)pOwner;
assert(pChr);
Character *pTarget = (Character *)pChr->GetTargetObject();
WzEvent event;
pChr->ProcessInterpolation(dwTick);
float fGguoMultiplier = 1.0f;
DWORD dwAttkSpd = DWORD( (float)dwTick * pChr->GetAttackSpeedModifier() * fGguoMultiplier );
#ifdef _YJ_MOD_BLOW_MOTION_001188
//////////////////////////////////////////////////////////////////////////
if(pChr->IsKindOfObject(PLAYER_OBJECT))
{
Player* pPlayer = (Player*)pChr;
WzID wiAni = pPlayer->GetCurrentAttackAnimation();
if((1 == pPlayer->GetbtCriAttkAni()) && m_bCriAttkAni && eCHAR_SHADOW == pPlayer->GetClass())
{
WzID wiAni = pPlayer->GetCurrentAttackAnimation();
CHAR szAniID[4] = {0,};
WzIDToString(szAniID, wiAni);
szAniID[2] = '1';
WzAnimationInfo *pInfo = pChr->GetAnimationInfo(StrToWzID(szAniID));
if(pInfo &&
INVALID_HANDLE_VALUE != pInfo->m_hWzdAni &&
StrToWzID("N001") != pInfo->m_wiAction)
{
pPlayer->SetAnimation(StrToWzID(szAniID));
}
m_bCriAttkAni = FALSE;
}
if((2 != pPlayer->GetbtCriAttkAni()) && TRUE == m_bHit)
{
if(0 != m_dwStopTime)
dwAttkSpd = (DWORD)((float)dwAttkSpd / ((float)m_dwStopTime/(float)dwTick));
if(dwTick < m_dwStopTime)
m_dwStopTime -= dwTick;
else
m_dwStopTime = dwTick;
if(100 > m_dwStopTime)
m_bHit = FALSE;
}
}
//////////////////////////////////////////////////////////////////////////
#endif _YJ_MOD_BLOW_MOTION_001188
float fRet = pChr->ProcessAnimation( dwAttkSpd, &event);
WzAnimationInfo *pInfo = pChr->GetAnimationInfo(StrToWzID("A001"));
// 타격점 타이밍
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;
}
}
break;
}
}
}
// 사망등 기본적인 상태 전이 조건 체크
if (pChr->CommonStateProcess())
{
// hero에대한 하드코딩이 너무많음 소스코드를 적당히 공유하면서도
// hero를 커스터마이즈할 방법을 찾자.
if (pChr == g_pHero)
{
g_HeroInput.SetCanDoNextAttack(TRUE);
}
return STATEPROCESS::SUSPEND;
}
// 이동속도
const float fMoveSpeed = GetBaseMoveSpeedAsState(CMS_SWIPE) ;
// 이동처리
if (pChr->m_bAttackMove)
{
if (pChr->GetPathExplorer()->IsMoving())
{
SUNPROCESSPROFILE_BEGIN(_T("PathFinding"));
g_pSunTerrain->PathExp_Progress(pChr->GetPathExplorer(), fMoveSpeed * dwTick, NULL);
SUNPROCESSPROFILE_END(_T("PathFinding"));
}
}
// 타격점 처리
SUNPROCESSPROFILE_BEGIN(_T("ProcessAttack"));
if( pTarget )
{
if( pChr->m_iHitEvent > pChr->m_iHitCount )
{
// 원거리 화살발사
if (pChr->IsRangedNormalAttack() )
{
if (pChr->m_iHitCount < pChr->GetShotCount() )
{
if (pChr->GetShotCount() == 1)
{
int iRt=0;
if (pTarget)
{
iRt=pChr->CreateProjectile(pTarget,pChr->m_iHitCount);
}
pChr->OnShotFire(pChr->m_iHitCount);
if(iRt)
pChr->m_iHitCount++;
}
// 발키리 공격 특별처리~~ 사실은 총알이 없는놈이 이쪽으로 와야한다.
else
{
pChr->OnShotFire(pChr->m_iHitCount);
if( pChr->ProcessAttackResult(pChr->GetCurrentAttackSerial(), FALSE, pChr->m_bRightHit ) )
{
pChr->OnShotFire(pChr->m_iHitCount);
pChr->m_iHitCount++;
}
}
}
}
if( pChr->m_iHitCount < 1 )
{
if( pChr->ProcessAttackResult_Group( pChr->GetCurrentAttackSerial(), pChr->m_bRightHit ) )
{
pChr->m_iHitCount++;
#ifdef _YJ_MOD_BLOW_MOTION_001188
m_bHit = TRUE;
#endif //_YJ_MOD_BLOW_MOTION_001188
}
}
}
}
BOOL bEndCondition = FALSE;
if (pChr == g_pHero)
{
BOOL bAttackEnd = FALSE;
if (GENERALPARAM->GetSpecialMode() == eSPECIAL_MODE_STEP3)
{
if (fRet >= 100.0f)
{
bAttackEnd = TRUE;
}
if (fRet >= 80.0f && g_HeroInput.GetKeyboardQueueAttack())
{
bAttackEnd = TRUE;
}
}
else
{
if (fRet >= 100.0f)
{
bAttackEnd = TRUE;
}
}
if (bAttackEnd)
{
// 다음 공격 입력이 있고 Ready를 받았으면
if (GENERALPARAM->IsNet())
{
if (g_pHero && !g_pHero->GetCannotMoveFlag())
{
bEndCondition = TRUE;
}
}
// 싱글모드에서는 그냥 다음공격으로 넘어갈수있다.
else
{
bEndCondition = TRUE;
}
}
}
else
{
if (fRet >= 100.0f)
{
bEndCondition = TRUE;
}
}
SUNPROCESSPROFILE_END(_T("ProcessAttack"));
// 공격 동작이 다 끝났으면 다음 액션을 수행한답!
if( bEndCondition)
{
// hero에대한 하드코딩이 너무많음 소스코드를 적당히 공유하면서도
// hero를 커스터마이즈할 방법을 찾자.
if (pChr == g_pHero)
{
g_HeroInput.SetCanDoNextAttack(TRUE);
}
if (pChr->ProcessNextAction())
{
return STATEPROCESS::SUSPEND;
}
else
{
return STATEPROCESS::END;
}
}
return STATEPROCESS::HOLD;
}
//------------------------------------------------------------------------------
/**
*/
STATECHANGE::TYPE StateAttack::OnEnd(Object* pOwner, DWORD CurTime)
{
Character* pChr = (Character *)pOwner;
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);
}
if (pChr->IsRangedNormalAttack())
{
pChr->OnShotEnd();
}
pChr->m_iHitCount = 0;
pChr->AddNextAttackSerial();
pChr->SetAttackStandTime(ATTACK_STAND_TIME);
if (pChr->IsKindOfObject(SSQMONSTER_OBJECT))
{
PlayerMonster* pMon = (PlayerMonster*)pChr;
pMon->SetComboDelay(10000);
}
if (pChr->IsKindOfObject(PLAYER_OBJECT))
{
Player* pPlayer = (Player*)pChr;
pPlayer->SetbtCriAttkAni(0);
}
return STATECHANGE::SUCCESS;
}