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

221 lines
7.4 KiB
C++

#include "StdAfx.h"
#include "SummonAbility.h"
#include "SummonedNPCs.h"
#include "SummonManager.h"
#include "GroupParser.h"
#include "Summoned.h"
#include "MovingPlanner.h"
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
#include "Skill.h"
#endif //_NA_007667_20141001_WITCHBLADE_SKILL
bool SummonAbility::ExecuteEffect(BYTE* /*msg*/, WORD& /*msg_size*/)
{
Character* const attacker = GetAttacker();
if (attacker == NULL)
{
return false;
}
GameField *pField = attacker->GetField();
if (!pField)
return false;
// 플레이어가 사용한 소환스킬인지 몬스터가 사용한 스킬인지에 따라서 소환몬스터 종류가 달라진다.
BOOL bPlayerSkill = attacker->IsEqualObjectKind(PLAYER_OBJECT);
// 파라미터 셋팅
const BASE_ABILITYINFO* const ability_info = GetBaseAbilityInfo();
BYTE bySummonGroupType = ability_info->m_iOption1; // 몬스터(0), 그룹(0)
DWORD dwSummonID = ability_info->m_iOption2; // 몬스터ID, 그룹ID
BYTE bySummonedNum = ability_info->m_iParam[0];
if (!bySummonedNum || bySummonedNum > MAX_SUMMONED_NUM) return false;
// 소환 NPC 리스트를 찾거나 없으면 생성한다.
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
SummonedNPCs *pOwnerSummonNPCs = NULL;
Player* player = NULL;
if (bPlayerSkill == true) {
player = reinterpret_cast<Player*>(attacker);
}
if (player != NULL && player->GetCharType() == eCHAR_WITCHBLADE)
{
pOwnerSummonNPCs = SummonManager::Instance()->AllocSummonNPCs(attacker, bPlayerSkill,
ability_info->m_wAbilityID);
}
else
{
pOwnerSummonNPCs = SummonManager::Instance()->AllocSummonNPCs(attacker, bPlayerSkill);
}
#else
SummonedNPCs *pOwnerSummonNPCs = SummonManager::Instance()->AllocSummonNPCs(attacker, bPlayerSkill);
#endif //_NA_007667_20141001_WITCHBLADE_SKILL
if (!pOwnerSummonNPCs)
return false;
// 소환대상이 그룹인 경우
if (bySummonGroupType == 1)
{
BASE_GROUPINFO *pGroupInfo = GroupParser::Instance()->GetGroupInfo((WORD)dwSummonID);
// 일단 보류...
}
// NPC를 생성한다.
if (bPlayerSkill)
{
CreateSummoned(attacker, pOwnerSummonNPCs, dwSummonID, bySummonedNum);
}
else
{
CreateSummonNPC(attacker, pOwnerSummonNPCs, dwSummonID, bySummonedNum);
}
#if !defined(_NA_000000_20140224_SUMMONER_REFACTORING)
attacker->SetSummonerKey(pOwnerSummonNPCs->GetSummonerKey());
#endif //_NA_000000_20140224_SUMMONER_REFACTORING
return false; // 의도된 false : msg 를 사용 하지 않는다. Effect 를 클라에 주지 않는다.
}
void SummonAbility::CreateSummoned(Character *pSummoner, SummonedNPCs *pOwnerSummonNPCs, DWORD dwCode, DWORD dwNumberOfNPCs)
{
GameField *pField = pSummoner->GetField();
if (!pField)
return;
int iCurTile = pSummoner->GetPathExplorer()->GetTile();
if (iCurTile < 0)
{
WzVector wvSummonerPos; pSummoner->GetPos(&wvSummonerPos);
SUNLOG(eCRITICAL_LOG,
"[CreateSummoned] Summoner "
"Key[%d] Type[%d] CurTile[%d]"
"FCode[%d] pos[%d,%d,%d]",
pSummoner->GetObjectKey(), pSummoner->GetObjectType(), iCurTile,
pField->GetFieldCode(), wvSummonerPos.x, wvSummonerPos.y, wvSummonerPos.z);
return;
}
DWORD dwExpireTime = GetBaseAbilityInfo()->m_iParam[2];
WzVector wvSummonerPos; pSummoner->GetPos(&wvSummonerPos);
WzVector wvSummonPos; float fMoveLength2 = 0;
// (WAVERIX)(080926)(NOTE)
// - thinking... 사용 사례로 봐서는 regen될 위치 결정시 타일 고려가 필요하게 될 듯. 애구 할 일 많아지넹.
nsAI::MovingPlanner* const pMovingPlanner = pField->GetMovingPlanner();
// 몬스터 생성
bool is_pos_input=false;
for (DWORD i = 0; i < dwNumberOfNPCs; ++i)
{
#ifdef _NA_007667_20141001_WITCHBLADE_SKILL
//고정형 소환수일 경우 main_target_pos 위치로 소환시킨다.
//그 외엔 기존처럼 자기주위에 소환
is_pos_input=false;
if (GetAbilityID() == eABILITY_SUMMON_IMMOVABLE)
{
Skill* skill = GetSKill();
if (skill != NULL)
{
SkillInfo* skill_info = skill->GetSkillInfo();
if(skill_info != NULL)
{
wvSummonPos = skill_info->main_target_pos_;
is_pos_input = true;
}
}
}
if (is_pos_input == false)
{
// 소환체의 위치결정(소환자와 너무 멀리 떨어지지 않도록 한다.)
for (int iPosTrial = 0; iPosTrial < 51; ++iPosTrial)
{
wvSummonPos = pMovingPlanner->GetRandomPosInTile(iCurTile);
fMoveLength2 = VectorLength2(&(wvSummonerPos - wvSummonPos));
if (fMoveLength2 >= 4.0 && fMoveLength2 <= 16.0)
break;
// 50번을 도는 동안에도 소환체 위치를 결정하지 못했는가?
if (iPosTrial >= 50)
{
SUNLOG(eFULL_LOG, "[Ability::CreateSummoned] Can't Find wvSummonPos whithin 50 Times");
break;
}
}
}
#else
// 소환체의 위치결정(소환자와 너무 멀리 떨어지지 않도록 한다.)
for (int iPosTrial = 0; iPosTrial < 51; ++iPosTrial)
{
wvSummonPos = pMovingPlanner->GetRandomPosInTile(iCurTile);
fMoveLength2 = VectorLength2(&(wvSummonerPos - wvSummonPos));
if (fMoveLength2 >= 4.0 && fMoveLength2 <= 16.0)
break;
// 50번을 도는 동안에도 소환체 위치를 결정하지 못했는가?
if (iPosTrial >= 50)
{
SUNLOG(eFULL_LOG, "[Ability::CreateSummoned] Can't Find wvSummonPos whithin 50 Times");
break;
}
}
#endif //_NA_007667_20141001_WITCHBLADE_SKILL
// 소환체 생성
Summoned* pSummoned = pField->CreateSummonByPlayer(dwCode, &wvSummonPos, pSummoner, pOwnerSummonNPCs, dwExpireTime, GetSkillCode(), NULL);
if (pSummoned)
{
MSG_CG_SUMMON_CURRENT_HP_CMD summonMsg;
summonMsg.m_dwSummonedObjKey = pSummoned->GetObjectKey();
summonMsg.m_dwMaxHP = pSummoned->GetMaxHP();
summonMsg.m_dwHP = pSummoned->GetHP();
summonMsg.m_dwSpeedRatio = pSummoned->GetMoveSpeedRatio();
pSummoner->SendPacket(&summonMsg, sizeof(MSG_CG_SUMMON_CURRENT_HP_CMD));
}
}
}
void SummonAbility::CreateSummonNPC(Character *pSummoner, SummonedNPCs *pOwnerSummonNPCs, DWORD dwCode, DWORD dwNumberOfNPCs)
{
GameField *pField = pSummoner->GetField();
if (!pField) return;
int iCurTile = pSummoner->GetPathExplorer()->GetTile();
if (iCurTile < 0)
{
SUNLOG(eCRITICAL_LOG, "[CreateSummonNPC] pSummoner Key[%d] Type[%d] CurTile[%d]", pSummoner->GetObjectKey(), pSummoner->GetObjectType(), iCurTile);
return;
}
WzVector wvSummonPos;
// (WAVERIX)(080926)(NOTE)
// - thinking... 사용 사례로 봐서는 regen될 위치 결정시 타일 고려가 필요하게 될 듯. 애구 할 일 많아지넹.
nsAI::MovingPlanner* const pMovingPlanner = pField->GetMovingPlanner();
// 몬스터 생성
for (DWORD i = 0; i < dwNumberOfNPCs; ++i)
{
// 위치 결정
wvSummonPos = pMovingPlanner->GetRandomPosInTile(iCurTile);
// 소환체 생성
pField->CreateSummonByNPC(dwCode, &wvSummonPos, pSummoner, pOwnerSummonNPCs);
}
}