Files
Sun1602/Server/GameServer/Npcai/HelpState.cpp
T
2022-10-26 12:25:11 +08:00

168 lines
3.9 KiB
C++

#include "stdafx.h"
#include <Timer.h>
#include "HelpState.h"
#include "GameField.h"
#include "AITypes.h"
#include <PacketStruct_CG.h>
#include "Const.h"
#include "AIParamParser.h"
#include "TargetManager.h"
#include "StatusManager.h"
#include "Skill.h"
HelpState::HelpState()
{
}
HelpState::~HelpState()
{
}
void
HelpState::Init()
{
}
void
HelpState::OnEnter(LPARAM param1, LPARAM param2, LPARAM param3)
{
State::OnEnter(param1, param2, param3);
GameField* pField = m_pNPC->GetField();
if (pField)
{
// Help상태로 전환되었음을 주변에 알려준다.
MSG_CG_STATUS_NPC_STATE_CHANGE_CMD sendMsg;
sendMsg.m_dwObjectKey = m_pNPC->GetObjectKey();
sendMsg.m_byState = eNPC_STATE_HELP_RESPONSE;
m_pNPC->SendPacketAround(&sendMsg, sizeof(sendMsg));
}
m_pNPC->GetStatusManager()->AllocStatus(eCHAR_STATE_ETC_HELP);
// Help상태에서는 기존의 BattleRecord 정보를 초기화하고, Help를 요청하게 만든 타겟만 설정한다.
Character* pTarget = m_pNPC->GetTargetChar();
m_pNPC->GetTargetManager()->ClearBattleRecord();
m_pNPC->SetTargetChar(pTarget);
m_HelpTimer.SetTimer(m_pAITypeInfo->m_wSEARCH_PERIOD);
// 공격 방법 선택되어 있지 않으면 선택
if (m_pNPC->GetSelectedSkill() == SKILLCODE_INVALID)
{
m_pNPC->SelectSkill();
}
}
void
HelpState::OnExit()
{
State::OnExit();
m_pNPC->GetStatusManager()->Remove(eCHAR_STATE_ETC_HELP);
}
BOOL
HelpState::OnUpdate(DWORD dwDeltaTick)
{
__UNUSED(dwDeltaTick);
ASSERT(NULL != m_pNPC->GetTargetChar());
Character* target = m_pNPC->GetTargetChar();
if (target == NULL)
{
m_pNPC->SetTargetChar(NULL);
m_pNPC->ChangeState(STATE_ID_IDLE);
return true;
}
// 타겟과의 거리 구하기
const float fDistToTarget = m_pNPC->GetDist(target);
// 타겟이 시야 범위를 벗어나면 방황 상태로 전이
if (m_pNPC->IsGroupMember() == false) {
float sight_range = m_pNPC->GetSightRange();
; sight_range *= AIParamParser::AICommonInfo.m_fHELP_SIGHTRANGE_RATIO;
if (fDistToTarget > sight_range) {
m_pNPC->SetTargetChar(NULL);
m_pNPC->ChangeState(STATE_ID_IDLE);
return true;
}
}
// 타겟이 공격 사거리 내에 들어있으면 공격 상태로 전이
if (fDistToTarget <= m_pNPC->GetAttackRange())
{
m_pNPC->ChangeState(STATE_ID_ATTACK);
return true;
}
if (m_pNPC->IsMoving())
{
// 1초마다 타겟의 좌표로 다시 한번 길찾기
if (m_HelpTimer.IsExpired())
{
DoTrack();
}
}
else
{
// 타겟이 공격 사거리 내에 들어있지 않으면 다시 길찾기
DoTrack();
}
return true;
}
void
HelpState::DoTrack()
{
Character* target = m_pNPC->GetTargetChar();
ASSERT(NULL != target);
if (target == NULL)
{
m_pNPC->SetTargetChar(NULL);
m_pNPC->ChangeState(STATE_ID_IDLE);
return;
}
GameField* pField = m_pNPC->GetField();
if (pField == NULL)
return;
if (m_pNPC->IsSamePositionWithTarget())
{
// 플레이어 위치와 정확히 같다면 상태 전이
m_pNPC->ChangeState(STATE_ID_ATTACK);
return;
}
// 새로운 Track Position을 찾는다.
// (NOTE) thinking... relation with target position
WzVector vTrackPos;
m_pNPC->GetTrackPos(vTrackPos);
// 길찾기..실패시 상태 전이
if (!m_pNPC->MoveAndBroadcast(&vTrackPos, CMS_RUN))
{
m_pNPC->SetTargetChar(NULL);
m_pNPC->ChangeState(STATE_ID_IDLE);
}
}
void
HelpState::OnMsgForceAttack(const AI_MSG* pMsg)
{
const AI_MSG_FORCE_ATTACK* pAttackMsg = static_cast<const AI_MSG_FORCE_ATTACK*>(pMsg);
// 현재 공격하고 있는 대상이라면 원래상태를 유지한다.
Character* pCurTarget = m_pNPC->GetTargetChar();
if (pCurTarget && pCurTarget->GetObjectKey() == pAttackMsg->dwTargetKey)
{
return;
}
State::OnMsgForceAttack(pMsg);
}