254 lines
5.5 KiB
C++
254 lines
5.5 KiB
C++
#include "StructNPC.h"
|
|
#include "StructPlayer.h"
|
|
#include "StructSummon.h"
|
|
#include "GameAllocator.h"
|
|
#include "SendMessage.h"
|
|
|
|
|
|
StructNPC::StructNPC( const NPCBase * npc_base )
|
|
{
|
|
m_nArObjectType = ArObject::MOVABLE_OBJECT;
|
|
|
|
m_hHandle = AllocMiscHandle( this );
|
|
|
|
m_bHasQuest = false;
|
|
|
|
m_pBaseInfo = npc_base;
|
|
|
|
std::string name = GameContent::GetString( m_pBaseInfo->text_id );
|
|
name += " ";
|
|
name += GameContent::GetString( m_pBaseInfo->name_text_id );
|
|
|
|
s_strcpy( m_szName, _countof( m_szName ), name.c_str() );
|
|
|
|
m_pRoamer = NULL;
|
|
|
|
m_pDeadHandler = NULL;
|
|
|
|
m_nStatus = STATUS_NORMAL;
|
|
|
|
m_bComeBackHome = false;
|
|
|
|
m_nLastEnemyDistance = 0;
|
|
|
|
m_nLastTrackTime = 0;
|
|
|
|
m_RespawnX = npc_base->x;
|
|
m_RespawnY = npc_base->y;
|
|
|
|
if( !IsAttackableNPC() )
|
|
SetInvincible( true );
|
|
|
|
#ifdef _MEM_USAGE_DEBUG
|
|
XSEH::IncreaseAllocCount( "StructNPC" );
|
|
#endif
|
|
}
|
|
|
|
AR_UNIT StructNPC::GetChaseRange() const
|
|
{
|
|
return m_pBaseInfo->chase_range * GameRule::DEFAULT_UNIT_SIZE;
|
|
}
|
|
|
|
StructNPC::NPC_STATUS StructNPC::GetStatus() const
|
|
{
|
|
return static_cast< NPC_STATUS >( m_nStatus );
|
|
}
|
|
|
|
void StructNPC::SetStatus( NPC_STATUS status )
|
|
{
|
|
if( m_nStatus != status && status != STATUS_DEAD )
|
|
{
|
|
BroadcastStatusMessage( this );
|
|
}
|
|
|
|
m_nStatus = status;
|
|
}
|
|
|
|
StructNPC::~StructNPC()
|
|
{
|
|
FreeMiscHandle( m_hHandle );
|
|
|
|
#ifdef _MEM_USAGE_DEBUG
|
|
XSEH::DecreaseAllocCount( "StructNPC" );
|
|
#endif
|
|
}
|
|
|
|
const CreatureStat & StructNPC::GetBaseStat() const
|
|
{
|
|
return GameContent::GetStatInfo( m_pBaseInfo->stat_id );
|
|
}
|
|
|
|
void StructNPC::LinkQuest( const QuestLink & quest_link_info )
|
|
{
|
|
if( quest_link_info.bLF_Start ) m_vQuestLink_Start.push_back( quest_link_info );
|
|
if( quest_link_info.bLF_Progress ) m_vQuestLink_Progress.push_back( quest_link_info );
|
|
if( quest_link_info.bLF_End ) m_vQuestLink_End.push_back( quest_link_info );
|
|
}
|
|
|
|
void StructNPC::DoEachStartableQuest( struct StructPlayer * pPlayer,QuestFunctor & _fo )
|
|
{
|
|
std::vector< QuestLink >::iterator it;
|
|
|
|
for( it = m_vQuestLink_Start.begin(); it != m_vQuestLink_Start.end(); ++it )
|
|
{
|
|
if( pPlayer->IsStartableQuest( (*it).code ) )
|
|
{
|
|
_fo( pPlayer, (*it) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructNPC::DoEachInProgressQuest( struct StructPlayer * pPlayer,QuestFunctor & _fo )
|
|
{
|
|
std::vector< QuestLink >::iterator it;
|
|
|
|
for( it = m_vQuestLink_Progress.begin(); it != m_vQuestLink_Progress.end(); ++it )
|
|
{
|
|
if( pPlayer->IsInProgressQuest( (*it).code ) )
|
|
{
|
|
_fo( pPlayer, (*it) );
|
|
}
|
|
}
|
|
}
|
|
|
|
void StructNPC::DoEachFinishableQuest( struct StructPlayer * pPlayer, QuestFunctor & _fo )
|
|
{
|
|
std::vector< QuestLink >::iterator it;
|
|
|
|
for( it = m_vQuestLink_End.begin(); it != m_vQuestLink_End.end(); ++it )
|
|
{
|
|
if( pPlayer->IsFinishableQuest( (*it).code ) )
|
|
{
|
|
_fo( pPlayer, (*it) );
|
|
}
|
|
}
|
|
}
|
|
|
|
bool StructNPC::HasStartableQuest( const struct StructPlayer * pPlayer )
|
|
{
|
|
std::vector< QuestLink >::iterator it;
|
|
|
|
bool bHasStartableRandom = false;
|
|
bool bHasProgressRandom = false;
|
|
|
|
for( it = m_vQuestLink_Start.begin(); it != m_vQuestLink_Start.end(); ++it )
|
|
{
|
|
const QuestBase & rQuestBase = StructQuest::GetQuestBase( (*it).code );
|
|
|
|
if( rQuestBase.nType == QuestBase::QUEST_RANDOM_KILL_INDIVIDUAL || rQuestBase.nType == QuestBase::QUEST_RANDOM_COLLECT )
|
|
{
|
|
if( pPlayer->IsInProgressQuest( (*it).code ) || pPlayer->IsFinishableQuest( (*it).code ) )
|
|
{
|
|
bHasProgressRandom = true;
|
|
}
|
|
else if( pPlayer->IsStartableQuest( (*it).code ) ) bHasStartableRandom = true;
|
|
|
|
continue;
|
|
}
|
|
|
|
if( pPlayer->IsStartableQuest( (*it).code ) ) return true;
|
|
}
|
|
|
|
if( bHasStartableRandom && !bHasProgressRandom )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
bool StructNPC::HasInProgressQuest( const struct StructPlayer * pPlayer )
|
|
{
|
|
std::vector< QuestLink >::iterator it;
|
|
|
|
for( it = m_vQuestLink_Progress.begin(); it != m_vQuestLink_Progress.end(); ++it )
|
|
{
|
|
if( pPlayer->IsInProgressQuest( (*it).code ) ) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool StructNPC::HasFinishableQuest( const struct StructPlayer * pPlayer )
|
|
{
|
|
std::vector< QuestLink >::iterator it;
|
|
|
|
for( it = m_vQuestLink_End.begin(); it != m_vQuestLink_End.end(); ++it )
|
|
{
|
|
if( pPlayer->IsFinishableQuest( (*it).code ) ) return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
int StructNPC::GetQuestTextId( QuestBase::QuestCode code, int progress )
|
|
{
|
|
std::vector< QuestLink >::iterator it;
|
|
|
|
if( progress == ::QUEST_IS_FINISHABLE )
|
|
{
|
|
for( it = m_vQuestLink_End.begin(); it != m_vQuestLink_End.end(); ++it )
|
|
{
|
|
if( (*it).code != code ) continue;
|
|
|
|
return (*it).nEndTextId;
|
|
}
|
|
}
|
|
else if( progress == ::QUEST_IS_IN_PROGRESS )
|
|
{
|
|
for( it = m_vQuestLink_Progress.begin(); it != m_vQuestLink_Progress.end(); ++it )
|
|
{
|
|
if( (*it).code != code ) continue;
|
|
|
|
return (*it).nInProgressTextId;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
for( it = m_vQuestLink_Start.begin(); it != m_vQuestLink_Start.end(); ++it )
|
|
{
|
|
if( (*it).code != code ) continue;
|
|
|
|
return (*it).nStartTextId;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
bool StructNPC::IsEnemy( StructCreature* pTarget, bool bIncludeHiding )
|
|
{
|
|
if( !StructCreature::IsEnemy( pTarget, bIncludeHiding ) )
|
|
return false;
|
|
|
|
if( pTarget->IsMonster() )
|
|
return false;
|
|
|
|
StructPlayer * pPlayer = NULL;
|
|
if( pTarget->IsPlayer() )
|
|
{
|
|
pPlayer = static_cast< StructPlayer * >( pTarget );
|
|
}
|
|
else if( pTarget->IsSummon() )
|
|
{
|
|
pPlayer = static_cast< StructSummon * >( pTarget )->GetMaster();
|
|
}
|
|
|
|
if( pPlayer && ( pPlayer->IsPKOn() || pPlayer->IsDemoniacCharacter() || pPlayer->IsBloodyCharacter() ) )
|
|
{
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
bool StructNPC::IsAttackableNPC() const
|
|
{
|
|
return m_pBaseInfo->attackable;
|
|
}
|
|
|
|
void StructNPC::onDead( StructCreature *pFrom, bool decreaseEXPOnDead )
|
|
{
|
|
StructCreature::onDead( pFrom, decreaseEXPOnDead );
|
|
|
|
SetStatus( STATUS_DEAD );
|
|
}
|