2022-03-05 12:44:06 +02:00
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
#include "config.h"
|
|
|
|
|
#include "utils.h"
|
|
|
|
|
#include "vector.h"
|
|
|
|
|
#include "char.h"
|
|
|
|
|
#include "battle.h"
|
|
|
|
|
#include "char_manager.h"
|
|
|
|
|
#include "packet.h"
|
|
|
|
|
#include "motion.h"
|
|
|
|
|
#include "party.h"
|
|
|
|
|
#include "affect.h"
|
|
|
|
|
#include "buffer_manager.h"
|
|
|
|
|
#include "questmanager.h"
|
|
|
|
|
#include "p2p.h"
|
|
|
|
|
#include "item_manager.h"
|
|
|
|
|
#include "mob_manager.h"
|
|
|
|
|
#include "exchange.h"
|
|
|
|
|
#include "sectree_manager.h"
|
|
|
|
|
#include "xmas_event.h"
|
|
|
|
|
#include "guild_manager.h"
|
|
|
|
|
#include "war_map.h"
|
|
|
|
|
#include "locale_service.h"
|
|
|
|
|
#include "BlueDragon.h"
|
|
|
|
|
|
2022-03-05 19:59:39 +02:00
|
|
|
|
#include <common/VnumHelper.h>
|
2022-03-05 12:44:06 +02:00
|
|
|
|
|
|
|
|
|
BOOL g_test_server;
|
|
|
|
|
extern LPCHARACTER FindVictim(LPCHARACTER pkChr, int iMaxDistance);
|
|
|
|
|
|
|
|
|
|
namespace
|
|
|
|
|
{
|
|
|
|
|
class FuncFindChrForFlag
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FuncFindChrForFlag(LPCHARACTER pkChr) :
|
|
|
|
|
m_pkChr(pkChr), m_pkChrFind(NULL), m_iMinDistance(INT_MAX)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void operator () (LPENTITY ent)
|
|
|
|
|
{
|
|
|
|
|
if (!ent->IsType(ENTITY_CHARACTER))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (ent->IsObserverMode())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
LPCHARACTER pkChr = (LPCHARACTER) ent;
|
|
|
|
|
|
|
|
|
|
if (!pkChr->IsPC())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!pkChr->GetGuild())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (pkChr->IsDead())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int iDist = DISTANCE_APPROX(pkChr->GetX()-m_pkChr->GetX(), pkChr->GetY()-m_pkChr->GetY());
|
|
|
|
|
|
|
|
|
|
if (iDist <= 500 && m_iMinDistance > iDist &&
|
|
|
|
|
!pkChr->IsAffectFlag(AFF_WAR_FLAG1) &&
|
|
|
|
|
!pkChr->IsAffectFlag(AFF_WAR_FLAG2) &&
|
|
|
|
|
!pkChr->IsAffectFlag(AFF_WAR_FLAG3))
|
|
|
|
|
{
|
|
|
|
|
// <20>츮<EFBFBD><ECB8AE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
if ((DWORD) m_pkChr->GetPoint(POINT_STAT) == pkChr->GetGuild()->GetID())
|
|
|
|
|
{
|
|
|
|
|
CWarMap * pMap = pkChr->GetWarMap();
|
|
|
|
|
BYTE idx;
|
|
|
|
|
|
|
|
|
|
if (!pMap || !pMap->GetTeamIndex(pkChr->GetGuild()->GetID(), idx))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// <20>츮<EFBFBD><ECB8AE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>̴´<CCB4>. <20>ȱ<C8B1><D7B7><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ִ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ΰ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>..
|
|
|
|
|
if (!pMap->IsFlagOnBase(idx))
|
|
|
|
|
{
|
|
|
|
|
m_pkChrFind = pkChr;
|
|
|
|
|
m_iMinDistance = iDist;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>̴´<CCB4>.
|
|
|
|
|
m_pkChrFind = pkChr;
|
|
|
|
|
m_iMinDistance = iDist;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPCHARACTER m_pkChr;
|
|
|
|
|
LPCHARACTER m_pkChrFind;
|
|
|
|
|
int m_iMinDistance;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class FuncFindChrForFlagBase
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FuncFindChrForFlagBase(LPCHARACTER pkChr) : m_pkChr(pkChr)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void operator () (LPENTITY ent)
|
|
|
|
|
{
|
|
|
|
|
if (!ent->IsType(ENTITY_CHARACTER))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (ent->IsObserverMode())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
LPCHARACTER pkChr = (LPCHARACTER) ent;
|
|
|
|
|
|
|
|
|
|
if (!pkChr->IsPC())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
CGuild * pkGuild = pkChr->GetGuild();
|
|
|
|
|
|
|
|
|
|
if (!pkGuild)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int iDist = DISTANCE_APPROX(pkChr->GetX()-m_pkChr->GetX(), pkChr->GetY()-m_pkChr->GetY());
|
|
|
|
|
|
|
|
|
|
if (iDist <= 500 &&
|
|
|
|
|
(pkChr->IsAffectFlag(AFF_WAR_FLAG1) ||
|
|
|
|
|
pkChr->IsAffectFlag(AFF_WAR_FLAG2) ||
|
|
|
|
|
pkChr->IsAffectFlag(AFF_WAR_FLAG3)))
|
|
|
|
|
{
|
|
|
|
|
CAffect * pkAff = pkChr->FindAffect(AFFECT_WAR_FLAG);
|
|
|
|
|
|
|
|
|
|
sys_log(0, "FlagBase %s dist %d aff %p flag gid %d chr gid %u",
|
|
|
|
|
pkChr->GetName(), iDist, pkAff, m_pkChr->GetPoint(POINT_STAT),
|
|
|
|
|
pkChr->GetGuild()->GetID());
|
|
|
|
|
|
|
|
|
|
if (pkAff)
|
|
|
|
|
{
|
|
|
|
|
if ((DWORD) m_pkChr->GetPoint(POINT_STAT) == pkGuild->GetID() &&
|
|
|
|
|
m_pkChr->GetPoint(POINT_STAT) != pkAff->lApplyValue)
|
|
|
|
|
{
|
|
|
|
|
CWarMap * pMap = pkChr->GetWarMap();
|
|
|
|
|
BYTE idx;
|
|
|
|
|
|
|
|
|
|
if (!pMap || !pMap->GetTeamIndex(pkGuild->GetID(), idx))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
//if (pMap->IsFlagOnBase(idx))
|
|
|
|
|
{
|
|
|
|
|
BYTE idx_opp = idx == 0 ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
SendGuildWarScore(m_pkChr->GetPoint(POINT_STAT), pkAff->lApplyValue, 1);
|
|
|
|
|
//SendGuildWarScore(pkAff->lApplyValue, m_pkChr->GetPoint(POINT_STAT), -1);
|
|
|
|
|
|
|
|
|
|
pMap->ResetFlag();
|
|
|
|
|
//pMap->AddFlag(idx_opp);
|
|
|
|
|
//pkChr->RemoveAffect(AFFECT_WAR_FLAG);
|
|
|
|
|
|
|
|
|
|
char buf[256];
|
|
|
|
|
snprintf(buf, sizeof(buf), LC_TEXT("%s <20><><EFBFBD>尡 %s <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>Ѿҽ<D1BE><D2BD>ϴ<EFBFBD>!"), pMap->GetGuild(idx)->GetName(), pMap->GetGuild(idx_opp)->GetName());
|
|
|
|
|
pMap->Notice(buf);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPCHARACTER m_pkChr;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class FuncFindGuardVictim
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
FuncFindGuardVictim(LPCHARACTER pkChr, int iMaxDistance) :
|
|
|
|
|
m_pkChr(pkChr),
|
|
|
|
|
m_iMinDistance(INT_MAX),
|
|
|
|
|
m_iMaxDistance(iMaxDistance),
|
|
|
|
|
m_lx(pkChr->GetX()),
|
|
|
|
|
m_ly(pkChr->GetY()),
|
|
|
|
|
m_pkChrVictim(NULL)
|
|
|
|
|
{
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
void operator () (LPENTITY ent)
|
|
|
|
|
{
|
|
|
|
|
if (!ent->IsType(ENTITY_CHARACTER))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
LPCHARACTER pkChr = (LPCHARACTER) ent;
|
|
|
|
|
|
|
|
|
|
// <20>ϴ<EFBFBD> PC <20><><EFBFBD>ݾ<EFBFBD><DDBE><EFBFBD>
|
|
|
|
|
if (pkChr->IsPC())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (pkChr->IsNPC() && !pkChr->IsMonster())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (pkChr->IsDead())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (pkChr->IsAffectFlag(AFF_EUNHYUNG) ||
|
|
|
|
|
pkChr->IsAffectFlag(AFF_INVISIBILITY) ||
|
|
|
|
|
pkChr->IsAffectFlag(AFF_REVIVE_INVISIBLE))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// <20>ֱ<EFBFBD><D6B1><EFBFBD> <20>н<EFBFBD>
|
|
|
|
|
if (pkChr->GetRaceNum() == 5001)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
int iDistance = DISTANCE_APPROX(m_lx - pkChr->GetX(), m_ly - pkChr->GetY());
|
|
|
|
|
|
|
|
|
|
if (iDistance < m_iMinDistance && iDistance <= m_iMaxDistance)
|
|
|
|
|
{
|
|
|
|
|
m_pkChrVictim = pkChr;
|
|
|
|
|
m_iMinDistance = iDistance;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPCHARACTER GetVictim()
|
|
|
|
|
{
|
|
|
|
|
return (m_pkChrVictim);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
LPCHARACTER m_pkChr;
|
|
|
|
|
|
|
|
|
|
int m_iMinDistance;
|
|
|
|
|
int m_iMaxDistance;
|
2022-03-12 11:39:41 +02:00
|
|
|
|
int m_lx;
|
|
|
|
|
int m_ly;
|
2022-03-05 12:44:06 +02:00
|
|
|
|
|
|
|
|
|
LPCHARACTER m_pkChrVictim;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsAggressive() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_AGGRESSIVE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::SetAggressive()
|
|
|
|
|
{
|
|
|
|
|
SET_BIT(m_pointsInstant.dwAIFlag, AIFLAG_AGGRESSIVE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsCoward() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_COWARD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::SetCoward()
|
|
|
|
|
{
|
|
|
|
|
SET_BIT(m_pointsInstant.dwAIFlag, AIFLAG_COWARD);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsBerserker() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_BERSERK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsStoneSkinner() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_STONESKIN);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsGodSpeeder() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_GODSPEED);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsDeathBlower() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_DEATHBLOW);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsReviver() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_REVIVE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::CowardEscape()
|
|
|
|
|
{
|
|
|
|
|
int iDist[4] = {500, 1000, 3000, 5000};
|
|
|
|
|
|
|
|
|
|
for (int iDistIdx = 2; iDistIdx >= 0; --iDistIdx)
|
|
|
|
|
for (int iTryCount = 0; iTryCount < 8; ++iTryCount)
|
|
|
|
|
{
|
|
|
|
|
SetRotation(number(0, 359)); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
float fx, fy;
|
|
|
|
|
float fDist = number(iDist[iDistIdx], iDist[iDistIdx+1]);
|
|
|
|
|
|
|
|
|
|
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
|
|
|
|
|
|
|
|
|
|
bool bIsWayBlocked = false;
|
|
|
|
|
for (int j = 1; j <= 100; ++j)
|
|
|
|
|
{
|
|
|
|
|
if (!SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx*j/100, GetY() + (int) fy*j/100))
|
|
|
|
|
{
|
|
|
|
|
bIsWayBlocked = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bIsWayBlocked)
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(1);
|
|
|
|
|
|
|
|
|
|
int iDestX = GetX() + (int) fx;
|
|
|
|
|
int iDestY = GetY() + (int) fy;
|
|
|
|
|
|
|
|
|
|
if (Goto(iDestX, iDestY))
|
|
|
|
|
SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
sys_log(0, "WAEGU move to %d %d (far)", iDestX, iDestY);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::SetNoAttackShinsu()
|
|
|
|
|
{
|
|
|
|
|
SET_BIT(m_pointsInstant.dwAIFlag, AIFLAG_NOATTACKSHINSU);
|
|
|
|
|
}
|
|
|
|
|
bool CHARACTER::IsNoAttackShinsu() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOATTACKSHINSU);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::SetNoAttackChunjo()
|
|
|
|
|
{
|
|
|
|
|
SET_BIT(m_pointsInstant.dwAIFlag, AIFLAG_NOATTACKCHUNJO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsNoAttackChunjo() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOATTACKCHUNJO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::SetNoAttackJinno()
|
|
|
|
|
{
|
|
|
|
|
SET_BIT(m_pointsInstant.dwAIFlag, AIFLAG_NOATTACKJINNO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsNoAttackJinno() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOATTACKJINNO);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::SetAttackMob()
|
|
|
|
|
{
|
|
|
|
|
SET_BIT(m_pointsInstant.dwAIFlag, AIFLAG_ATTACKMOB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool CHARACTER::IsAttackMob() const
|
|
|
|
|
{
|
|
|
|
|
return IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_ATTACKMOB);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// STATE_IDLE_REFACTORING
|
|
|
|
|
void CHARACTER::StateIdle()
|
|
|
|
|
{
|
|
|
|
|
if (IsStone())
|
|
|
|
|
{
|
|
|
|
|
__StateIdle_Stone();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
else if (IsWarp() || IsGoto())
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>̺<EFBFBD>Ʈ<EFBFBD><C6AE> ó<><C3B3>
|
|
|
|
|
m_dwStateDuration = 60 * passes_per_sec;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsPC())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// NPC ó<><C3B3>
|
|
|
|
|
if (!IsMonster())
|
|
|
|
|
{
|
|
|
|
|
__StateIdle_NPC();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__StateIdle_Monster();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::__StateIdle_Stone()
|
|
|
|
|
{
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(1);
|
|
|
|
|
|
|
|
|
|
int iPercent = (GetHP() * 100) / GetMaxHP();
|
|
|
|
|
DWORD dwVnum = number(MIN(GetMobTable().sAttackSpeed, GetMobTable().sMovingSpeed ), MAX(GetMobTable().sAttackSpeed, GetMobTable().sMovingSpeed));
|
|
|
|
|
|
|
|
|
|
if (iPercent <= 10 && GetMaxSP() < 10)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(10);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 500, GetY() - 500, GetX() + 500, GetY() + 500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1500, GetY() - 1500, GetX() + 1500, GetY() + 1500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 20 && GetMaxSP() < 9)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(9);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 500, GetY() - 500, GetX() + 500, GetY() + 500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1500, GetY() - 1500, GetX() + 1500, GetY() + 1500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 30 && GetMaxSP() < 8)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(8);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 500, GetY() - 500, GetX() + 500, GetY() + 500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 40 && GetMaxSP() < 7)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(7);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 50 && GetMaxSP() < 6)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(6);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 60 && GetMaxSP() < 5)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(5);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 500, GetY() - 500, GetX() + 500, GetY() + 500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 70 && GetMaxSP() < 4)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(4);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 500, GetY() - 500, GetX() + 500, GetY() + 500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 80 && GetMaxSP() < 3)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(3);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 90 && GetMaxSP() < 2)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(2);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 500, GetY() - 500, GetX() + 500, GetY() + 500);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else if (iPercent <= 99 && GetMaxSP() < 1)
|
|
|
|
|
{
|
|
|
|
|
SetMaxSP(1);
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0);
|
|
|
|
|
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(this);
|
|
|
|
|
CHARACTER_MANAGER::instance().SpawnGroup(dwVnum, GetMapIndex(), GetX() - 1000, GetY() - 1000, GetX() + 1000, GetY() + 1000);
|
|
|
|
|
CHARACTER_MANAGER::instance().SelectStone(NULL);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
UpdatePacket();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::__StateIdle_NPC()
|
|
|
|
|
{
|
|
|
|
|
MonsterChat(MONSTER_CHAT_WAIT);
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(5);
|
|
|
|
|
|
|
|
|
|
// <20><> <20>ý<EFBFBD><C3BD><EFBFBD><EFBFBD><EFBFBD> Idle ó<><C3B3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ij<><C4B3><EFBFBD>͵<EFBFBD><CDB5><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD> <20><><EFBFBD>¸ӽ<C2B8><D3BD><EFBFBD> <20>ƴ<EFBFBD> CPetActor::Update<74><65><EFBFBD><EFBFBD> ó<><C3B3><EFBFBD><EFBFBD>.
|
|
|
|
|
if (IsPet())
|
|
|
|
|
return;
|
|
|
|
|
else if (IsGuardNPC())
|
|
|
|
|
{
|
|
|
|
|
if (!quest::CQuestManager::instance().GetEventFlag("noguard"))
|
|
|
|
|
{
|
|
|
|
|
FuncFindGuardVictim f(this, 50000);
|
|
|
|
|
|
|
|
|
|
if (GetSectree())
|
|
|
|
|
GetSectree()->ForEachAround(f);
|
|
|
|
|
|
|
|
|
|
LPCHARACTER victim = f.GetVictim();
|
|
|
|
|
|
|
|
|
|
if (victim)
|
|
|
|
|
{
|
|
|
|
|
m_dwStateDuration = passes_per_sec/2;
|
|
|
|
|
|
|
|
|
|
if (CanBeginFight())
|
|
|
|
|
BeginFight(victim);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (GetRaceNum() == xmas::MOB_SANTA_VNUM) // <20><>Ÿ
|
|
|
|
|
{
|
|
|
|
|
if (get_dword_time() > m_dwPlayStartTime)
|
|
|
|
|
{
|
|
|
|
|
int next_warp_time = 2 * 1000; // 2<><32>
|
|
|
|
|
|
|
|
|
|
m_dwPlayStartTime = get_dword_time() + next_warp_time;
|
|
|
|
|
|
|
|
|
|
// <20>ð<EFBFBD><C3B0><EFBFBD> <20>Ѿ<EFBFBD><D1BE><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>սô<D5BD>.
|
|
|
|
|
/*
|
|
|
|
|
* <EFBFBD><EFBFBD>Ÿ<EFBFBD><EFBFBD>
|
|
|
|
|
const int WARP_MAP_INDEX_NUM = 4;
|
2022-03-12 11:39:41 +02:00
|
|
|
|
static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = {61, 62, 63, 64};
|
2022-03-05 12:44:06 +02:00
|
|
|
|
*/
|
|
|
|
|
// <20>ż<EFBFBD><C5BC><EFBFBD> <20><><EFBFBD>ؿ<EFBFBD>
|
|
|
|
|
const int WARP_MAP_INDEX_NUM = 7;
|
2022-03-12 11:39:41 +02:00
|
|
|
|
static const int c_lWarpMapIndexs[WARP_MAP_INDEX_NUM] = { 61, 62, 63, 64, 3, 23, 43 };
|
|
|
|
|
int lNextMapIndex;
|
2022-03-05 12:44:06 +02:00
|
|
|
|
lNextMapIndex = c_lWarpMapIndexs[number(1, WARP_MAP_INDEX_NUM) - 1];
|
|
|
|
|
|
|
|
|
|
if (map_allow_find(lNextMapIndex))
|
|
|
|
|
{
|
|
|
|
|
// <20>̰<EFBFBD><CCB0>Դϴ<D4B4>.
|
|
|
|
|
M2_DESTROY_CHARACTER(this);
|
|
|
|
|
int iNextSpawnDelay = 0;
|
|
|
|
|
if (LC_IsYMIR())
|
|
|
|
|
iNextSpawnDelay = 20 * 60;
|
|
|
|
|
else
|
|
|
|
|
iNextSpawnDelay = 50 * 60;
|
|
|
|
|
|
|
|
|
|
xmas::SpawnSanta(lNextMapIndex, iNextSpawnDelay);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// <20>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>Դϴ<D4B4>.
|
|
|
|
|
TPacketGGXmasWarpSanta p;
|
|
|
|
|
p.bHeader = HEADER_GG_XMAS_WARP_SANTA;
|
|
|
|
|
p.bChannel = g_bChannel;
|
|
|
|
|
p.lMapIndex = lNextMapIndex;
|
|
|
|
|
P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGXmasWarpSanta));
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
|
|
|
|
|
{
|
|
|
|
|
//
|
|
|
|
|
// <20><> <20><> <20><> <20><> <20>̵<EFBFBD><CCB5>Ѵ<EFBFBD>.
|
|
|
|
|
//
|
|
|
|
|
LPCHARACTER pkChrProtege = GetProtege();
|
|
|
|
|
|
|
|
|
|
if (pkChrProtege)
|
|
|
|
|
{
|
|
|
|
|
if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 500)
|
|
|
|
|
{
|
|
|
|
|
if (Follow(pkChrProtege, number(100, 300)))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!number(0, 6))
|
|
|
|
|
{
|
|
|
|
|
SetRotation(number(0, 359)); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
float fx, fy;
|
|
|
|
|
float fDist = number(200, 400);
|
|
|
|
|
|
|
|
|
|
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD> üũ; <20><><EFBFBD><EFBFBD> <20><>ġ<EFBFBD><C4A1> <20>߰<EFBFBD> <20><>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
|
|
|
|
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
|
|
|
|
|
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx / 2, GetY() + (int) fy / 2)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
SetNowWalking(true);
|
|
|
|
|
|
|
|
|
|
if (Goto(GetX() + (int) fx, GetY() + (int) fy))
|
|
|
|
|
SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::__StateIdle_Monster()
|
|
|
|
|
{
|
|
|
|
|
if (IsStun())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!CanMove())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsCoward())
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ٴմϴ<D5B4>.
|
|
|
|
|
if (!IsDead())
|
|
|
|
|
CowardEscape();
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsBerserker())
|
|
|
|
|
if (IsBerserk())
|
|
|
|
|
SetBerserk(false);
|
|
|
|
|
|
|
|
|
|
if (IsGodSpeeder())
|
|
|
|
|
if (IsGodSpeed())
|
|
|
|
|
SetGodSpeed(false);
|
|
|
|
|
|
|
|
|
|
LPCHARACTER victim = GetVictim();
|
|
|
|
|
|
|
|
|
|
if (!victim || victim->IsDead())
|
|
|
|
|
{
|
|
|
|
|
SetVictim(NULL);
|
|
|
|
|
victim = NULL;
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!victim || victim->IsBuilding())
|
|
|
|
|
{
|
|
|
|
|
// <20><> <20><>ȣ ó<><C3B3>
|
|
|
|
|
if (m_pkChrStone)
|
|
|
|
|
{
|
|
|
|
|
victim = m_pkChrStone->GetNearestVictim(m_pkChrStone);
|
|
|
|
|
}
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ó<><C3B3>
|
|
|
|
|
else if (!no_wander && IsAggressive())
|
|
|
|
|
{
|
|
|
|
|
if (GetMapIndex() == 61 && quest::CQuestManager::instance().GetEventFlag("xmas_tree"));
|
|
|
|
|
// <20><><EFBFBD>ѻ꿡<D1BB><EABFA1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʴ´<CAB4>.
|
|
|
|
|
else
|
|
|
|
|
victim = FindVictim(this, m_pkMobData->m_table.wAggressiveSight);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (victim && !victim->IsDead())
|
|
|
|
|
{
|
|
|
|
|
if (CanBeginFight())
|
|
|
|
|
BeginFight(victim);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsAggressive() && !victim)
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(number(1, 3));
|
|
|
|
|
else
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(number(3, 5));
|
|
|
|
|
|
|
|
|
|
LPCHARACTER pkChrProtege = GetProtege();
|
|
|
|
|
|
|
|
|
|
// <20><>ȣ<EFBFBD><C8A3> <20><>(<28><>, <20><>Ƽ<EFBFBD><C6BC>)<29><><EFBFBD>Է<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ִٸ<D6B4> <20><><EFBFBD><EFBFBD>.
|
|
|
|
|
if (pkChrProtege)
|
|
|
|
|
{
|
|
|
|
|
if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000)
|
|
|
|
|
{
|
|
|
|
|
if (Follow(pkChrProtege, number(150, 400)))
|
|
|
|
|
{
|
|
|
|
|
MonsterLog("[IDLE] <20><><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><CEBA><EFBFBD> <20>ʹ<EFBFBD> <20>ָ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>! <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// <20>׳<EFBFBD> <20>Դٸ<D4B4> <20><><EFBFBD>ٸ<EFBFBD> <20>Ѵ<EFBFBD>.
|
|
|
|
|
//
|
|
|
|
|
if (!no_wander && !IS_SET(m_pointsInstant.dwAIFlag, AIFLAG_NOMOVE))
|
|
|
|
|
{
|
|
|
|
|
if (!number(0, 6))
|
|
|
|
|
{
|
|
|
|
|
SetRotation(number(0, 359)); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
float fx, fy;
|
|
|
|
|
float fDist = number(300, 700);
|
|
|
|
|
|
|
|
|
|
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD> üũ; <20><><EFBFBD><EFBFBD> <20><>ġ<EFBFBD><C4A1> <20>߰<EFBFBD> <20><>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
|
|
|
|
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
|
|
|
|
|
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
// NOTE: <20><><EFBFBD><EFBFBD><EFBFBD>Ͱ<EFBFBD> IDLE <20><><EFBFBD>¿<EFBFBD><C2BF><EFBFBD> <20>ֺ<EFBFBD><D6BA><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ÿ<EFBFBD> <20><>, <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>پ<D9BE><EEB0A1> <20>Ǿ<EFBFBD> <20><><EFBFBD><EFBFBD>. (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>)
|
|
|
|
|
// <20><EFBFBD><D7B7><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ͱ<EFBFBD> <20>ȴ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ʹٰ<CDB4> <20>ؼ<EFBFBD> <20>ӽ÷<D3BD> Ư<><C6AF>Ȯ<EFBFBD><C8AE><EFBFBD><EFBFBD> <20>Ȱų<C8B0> <20>ٰ<EFBFBD> <20><>. (<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Ʋ<><C6B2><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ϴ<EFBFBD> <20><EFBFBD>Ʈ <20><><EFBFBD>忡<EFBFBD><E5BFA1><EFBFBD><EFBFBD> <20>۵<EFBFBD>)
|
|
|
|
|
if (g_test_server)
|
|
|
|
|
{
|
|
|
|
|
if (number(0, 100) < 60)
|
|
|
|
|
SetNowWalking(false);
|
|
|
|
|
else
|
|
|
|
|
SetNowWalking(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (Goto(GetX() + (int) fx, GetY() + (int) fy))
|
|
|
|
|
SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
MonsterChat(MONSTER_CHAT_WAIT);
|
|
|
|
|
}
|
|
|
|
|
// END_OF_STATE_IDLE_REFACTORING
|
|
|
|
|
|
|
|
|
|
bool __CHARACTER_GotoNearTarget(LPCHARACTER self, LPCHARACTER victim)
|
|
|
|
|
{
|
|
|
|
|
if (IS_SET(self->GetAIFlag(), AIFLAG_NOMOVE))
|
|
|
|
|
return false;
|
|
|
|
|
|
|
|
|
|
switch (self->GetMobBattleType())
|
|
|
|
|
{
|
|
|
|
|
case BATTLE_TYPE_RANGE:
|
|
|
|
|
case BATTLE_TYPE_MAGIC:
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>糪 <20>ü<EFBFBD><C3BC><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ÿ<EFBFBD><C5B8><EFBFBD> 80%<25><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
|
|
|
|
if (self->Follow(victim, self->GetMobAttackRange() * 8 / 10))
|
|
|
|
|
return true;
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 90%?
|
|
|
|
|
if (self->Follow(victim, self->GetMobAttackRange() * 9 / 10))
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::StateMove()
|
|
|
|
|
{
|
|
|
|
|
DWORD dwElapsedTime = get_dword_time() - m_dwMoveStartTime;
|
|
|
|
|
float fRate = (float) dwElapsedTime / (float) m_dwMoveDuration;
|
|
|
|
|
|
|
|
|
|
if (fRate > 1.0f)
|
|
|
|
|
fRate = 1.0f;
|
|
|
|
|
|
|
|
|
|
int x = (int) ((float) (m_posDest.x - m_posStart.x) * fRate + m_posStart.x);
|
|
|
|
|
int y = (int) ((float) (m_posDest.y - m_posStart.y) * fRate + m_posStart.y);
|
|
|
|
|
|
|
|
|
|
Move(x, y);
|
|
|
|
|
|
|
|
|
|
if (IsPC() && (thecore_pulse() & 15) == 0)
|
|
|
|
|
{
|
|
|
|
|
UpdateSectree();
|
|
|
|
|
|
|
|
|
|
if (GetExchange())
|
|
|
|
|
{
|
|
|
|
|
LPCHARACTER victim = GetExchange()->GetCompany()->GetOwner();
|
|
|
|
|
int iDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
|
|
|
|
|
|
|
|
|
|
// <20>Ÿ<EFBFBD> üũ
|
|
|
|
|
if (iDist >= EXCHANGE_MAX_DISTANCE)
|
|
|
|
|
{
|
|
|
|
|
GetExchange()->Cancel();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD>̳<D7B9><CCB3><EFBFBD> 0 <20>̻<EFBFBD><CCBB>̾<EFBFBD><CCBE><EFBFBD> <20>Ѵ<EFBFBD>.
|
|
|
|
|
if (IsPC())
|
|
|
|
|
{
|
|
|
|
|
if (IsWalking() && GetStamina() < GetMaxStamina())
|
|
|
|
|
{
|
|
|
|
|
// 5<><35> <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>̳<D7B9> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
if (get_dword_time() - GetWalkStartTime() > 5000)
|
|
|
|
|
PointChange(POINT_STAMINA, GetMaxStamina() / 1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD≯鼭 <20>ٴ<EFBFBD> <20><><EFBFBD≯<EFBFBD>
|
|
|
|
|
if (!IsWalking() && !IsRiding())
|
|
|
|
|
if ((get_dword_time() - GetLastAttackTime()) < 20000)
|
|
|
|
|
{
|
|
|
|
|
StartAffectEvent();
|
|
|
|
|
|
|
|
|
|
if (IsStaminaHalfConsume())
|
|
|
|
|
{
|
|
|
|
|
if (thecore_pulse()&1)
|
|
|
|
|
PointChange(POINT_STAMINA, -STAMINA_PER_STEP);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
PointChange(POINT_STAMINA, -STAMINA_PER_STEP);
|
|
|
|
|
|
|
|
|
|
StartStaminaConsume();
|
|
|
|
|
|
|
|
|
|
if (GetStamina() <= 0)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD>̳<D7B9><CCB3><EFBFBD> <20><><EFBFBD>ڶ<EFBFBD> <20>ɾ<EFBFBD><C9BE><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
SetStamina(0);
|
|
|
|
|
SetNowWalking(true);
|
|
|
|
|
StopStaminaConsume();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else if (IsStaminaConsume())
|
|
|
|
|
{
|
|
|
|
|
StopStaminaConsume();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// XXX AGGRO
|
|
|
|
|
if (IsMonster() && GetVictim())
|
|
|
|
|
{
|
|
|
|
|
LPCHARACTER victim = GetVictim();
|
|
|
|
|
UpdateAggrPoint(victim, DAMAGE_TYPE_NORMAL, -(victim->GetLevel() / 3 + 1));
|
|
|
|
|
|
|
|
|
|
if (g_test_server)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>Ͱ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ѿư<D1BE><C6B0><EFBFBD> <20><><EFBFBD≯<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>پ<D9BE><EEB0A3>.
|
|
|
|
|
SetNowWalking(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsMonster() && GetMobRank() >= MOB_RANK_BOSS && GetVictim())
|
|
|
|
|
{
|
|
|
|
|
LPCHARACTER victim = GetVictim();
|
|
|
|
|
|
|
|
|
|
// <20>Ŵ<EFBFBD> <20>ź<EFBFBD>
|
|
|
|
|
if (GetRaceNum() == 2191 && number(1, 20) == 1 && get_dword_time() - m_pkMobInst->m_dwLastWarpTime > 1000)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20><EFBFBD>Ʈ
|
|
|
|
|
float fx, fy;
|
|
|
|
|
GetDeltaByDegree(victim->GetRotation(), 400, &fx, &fy);
|
2022-03-12 11:39:41 +02:00
|
|
|
|
int new_x = victim->GetX() + (int)fx;
|
|
|
|
|
int new_y = victim->GetY() + (int)fy;
|
2022-03-05 12:44:06 +02:00
|
|
|
|
SetRotation(GetDegreeFromPositionXY(new_x, new_y, victim->GetX(), victim->GetY()));
|
|
|
|
|
Show(victim->GetMapIndex(), new_x, new_y, 0, true);
|
|
|
|
|
GotoState(m_stateBattle);
|
|
|
|
|
m_dwStateDuration = 1;
|
|
|
|
|
ResetMobSkillCooltime();
|
|
|
|
|
m_pkMobInst->m_dwLastWarpTime = get_dword_time();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// TODO <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȯ<EFBFBD><C8AF> <20>ؼ<EFBFBD> <20><> <20>ٺ<EFBFBD><D9BA><EFBFBD> <20><><EFBFBD><EFBFBD>!
|
|
|
|
|
if (number(0, 3) == 0)
|
|
|
|
|
{
|
|
|
|
|
if (__CHARACTER_GotoNearTarget(this, victim))
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (1.0f == fRate)
|
|
|
|
|
{
|
|
|
|
|
if (IsPC())
|
|
|
|
|
{
|
|
|
|
|
sys_log(1, "<EFBFBD><EFBFBD><EFBFBD><EFBFBD> %s %d %d", GetName(), x, y);
|
|
|
|
|
GotoState(m_stateIdle);
|
|
|
|
|
StopStaminaConsume();
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (GetVictim() && !IsCoward())
|
|
|
|
|
{
|
|
|
|
|
if (!IsState(m_stateBattle))
|
|
|
|
|
MonsterLog("[BATTLE] <20><>ó<EFBFBD><C3B3> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ݽ<EFBFBD><DDBD><EFBFBD> %s", GetVictim()->GetName());
|
|
|
|
|
|
|
|
|
|
GotoState(m_stateBattle);
|
|
|
|
|
m_dwStateDuration = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
if (!IsState(m_stateIdle))
|
|
|
|
|
MonsterLog("[IDLE] <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>");
|
|
|
|
|
|
|
|
|
|
GotoState(m_stateIdle);
|
|
|
|
|
|
|
|
|
|
LPCHARACTER rider = GetRider();
|
|
|
|
|
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(number(1, 3));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::StateBattle()
|
|
|
|
|
{
|
|
|
|
|
if (IsStone())
|
|
|
|
|
{
|
|
|
|
|
sys_err("Stone must not use battle state (name %s)", GetName());
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsPC())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!CanMove())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (IsStun())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
LPCHARACTER victim = GetVictim();
|
|
|
|
|
|
|
|
|
|
if (IsCoward())
|
|
|
|
|
{
|
|
|
|
|
if (IsDead())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
SetVictim(NULL);
|
|
|
|
|
|
|
|
|
|
if (number(1, 50) != 1)
|
|
|
|
|
{
|
|
|
|
|
GotoState(m_stateIdle);
|
|
|
|
|
m_dwStateDuration = 1;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
CowardEscape();
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!victim || (victim->IsStun() && IsGuardNPC()) || victim->IsDead())
|
|
|
|
|
{
|
|
|
|
|
if (victim && victim->IsDead() &&
|
|
|
|
|
!no_wander && IsAggressive() && (!GetParty() || GetParty()->GetLeader() == this))
|
|
|
|
|
{
|
|
|
|
|
LPCHARACTER new_victim = FindVictim(this, m_pkMobData->m_table.wAggressiveSight);
|
|
|
|
|
|
|
|
|
|
SetVictim(new_victim);
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(1);
|
|
|
|
|
|
|
|
|
|
if (!new_victim)
|
|
|
|
|
{
|
|
|
|
|
switch (GetMobBattleType())
|
|
|
|
|
{
|
|
|
|
|
case BATTLE_TYPE_MELEE:
|
|
|
|
|
case BATTLE_TYPE_SUPER_POWER:
|
|
|
|
|
case BATTLE_TYPE_SUPER_TANKER:
|
|
|
|
|
case BATTLE_TYPE_POWER:
|
|
|
|
|
case BATTLE_TYPE_TANKER:
|
|
|
|
|
{
|
|
|
|
|
float fx, fy;
|
|
|
|
|
float fDist = number(400, 1500);
|
|
|
|
|
|
|
|
|
|
GetDeltaByDegree(number(0, 359), fDist, &fx, &fy);
|
|
|
|
|
|
|
|
|
|
if (SECTREE_MANAGER::instance().IsMovablePosition(victim->GetMapIndex(),
|
|
|
|
|
victim->GetX() + (int) fx,
|
|
|
|
|
victim->GetY() + (int) fy) &&
|
|
|
|
|
SECTREE_MANAGER::instance().IsMovablePosition(victim->GetMapIndex(),
|
|
|
|
|
victim->GetX() + (int) fx/2,
|
|
|
|
|
victim->GetY() + (int) fy/2))
|
|
|
|
|
{
|
|
|
|
|
float dx = victim->GetX() + fx;
|
|
|
|
|
float dy = victim->GetY() + fy;
|
|
|
|
|
|
|
|
|
|
SetRotation(GetDegreeFromPosition(dx, dy));
|
|
|
|
|
|
2022-03-12 11:39:41 +02:00
|
|
|
|
if (Goto((int) dx, (int) dy))
|
2022-03-05 12:44:06 +02:00
|
|
|
|
{
|
|
|
|
|
sys_log(0, "KILL_AND_GO: %s distance %.1f", GetName(), fDist);
|
|
|
|
|
SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SetVictim(NULL);
|
|
|
|
|
|
|
|
|
|
if (IsGuardNPC())
|
|
|
|
|
Return();
|
|
|
|
|
|
|
|
|
|
m_dwStateDuration = PASSES_PER_SEC(1);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsSummonMonster() && !IsDead() && !IsStun())
|
|
|
|
|
{
|
|
|
|
|
if (!GetParty())
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD> ä<><C3A4><EFBFBD><EFBFBD> <20><>Ƽ<EFBFBD><C6BC> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ӵϴ<D3B4>.
|
|
|
|
|
CPartyManager::instance().CreateParty(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPPARTY pParty = GetParty();
|
|
|
|
|
bool bPct = !number(0, 3);
|
|
|
|
|
|
|
|
|
|
if (bPct && pParty->CountMemberByVnum(GetSummonVnum()) < SUMMON_MONSTER_COUNT)
|
|
|
|
|
{
|
|
|
|
|
MonsterLog("<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȯ!");
|
|
|
|
|
// <20><><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD> <20>༮<EFBFBD><E0BCAE> <20>ҷ<EFBFBD><D2B7><EFBFBD> ä<><C3A4><EFBFBD>ô<EFBFBD>.
|
|
|
|
|
int sx = GetX() - 300;
|
|
|
|
|
int sy = GetY() - 300;
|
|
|
|
|
int ex = GetX() + 300;
|
|
|
|
|
int ey = GetY() + 300;
|
|
|
|
|
|
|
|
|
|
LPCHARACTER tch = CHARACTER_MANAGER::instance().SpawnMobRange(GetSummonVnum(), GetMapIndex(), sx, sy, ex, ey, true, true);
|
|
|
|
|
|
|
|
|
|
if (tch)
|
|
|
|
|
{
|
|
|
|
|
pParty->Join(tch->GetVID());
|
|
|
|
|
pParty->Link(tch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
LPCHARACTER pkChrProtege = GetProtege();
|
|
|
|
|
|
|
|
|
|
float fDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
|
|
|
|
|
|
|
|
|
|
if (fDist >= 4000.0f) // 40<34><30><EFBFBD><EFBFBD> <20>̻<EFBFBD> <20>־<EFBFBD><D6BE><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
{
|
|
|
|
|
MonsterLog("Ÿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>־ <20><><EFBFBD><EFBFBD>");
|
|
|
|
|
SetVictim(NULL);
|
|
|
|
|
|
|
|
|
|
// <20><>ȣ<EFBFBD><C8A3> <20><>(<28><>, <20><>Ƽ<EFBFBD><C6BC>) <20>ֺ<EFBFBD><D6BA><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>.
|
|
|
|
|
if (pkChrProtege)
|
|
|
|
|
if (DISTANCE_APPROX(GetX() - pkChrProtege->GetX(), GetY() - pkChrProtege->GetY()) > 1000)
|
|
|
|
|
Follow(pkChrProtege, number(150, 400));
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (fDist >= GetMobAttackRange() * 1.15)
|
|
|
|
|
{
|
|
|
|
|
__CHARACTER_GotoNearTarget(this, victim);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (m_pkParty)
|
|
|
|
|
m_pkParty->SendMessage(this, PM_ATTACKED_BY, 0, 0);
|
|
|
|
|
|
|
|
|
|
if (2493 == m_pkMobData->m_table.dwVnum)
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD>(2493) Ư<><C6AF> ó<><C3B3>
|
|
|
|
|
m_dwStateDuration = BlueDragon_StateBattle(this);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD dwCurTime = get_dword_time();
|
|
|
|
|
DWORD dwDuration = CalculateDuration(GetLimitPoint(POINT_ATT_SPEED), 2000);
|
|
|
|
|
|
|
|
|
|
if ((dwCurTime - m_dwLastAttackTime) < dwDuration) // 2<><32> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؾ<EFBFBD> <20>Ѵ<EFBFBD>.
|
|
|
|
|
{
|
|
|
|
|
m_dwStateDuration = MAX(1, (passes_per_sec * (dwDuration - (dwCurTime - m_dwLastAttackTime)) / 1000));
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (IsBerserker() == true)
|
|
|
|
|
if (GetHPPct() < m_pkMobData->m_table.bBerserkPoint)
|
|
|
|
|
if (IsBerserk() != true)
|
|
|
|
|
SetBerserk(true);
|
|
|
|
|
|
|
|
|
|
if (IsGodSpeeder() == true)
|
|
|
|
|
if (GetHPPct() < m_pkMobData->m_table.bGodSpeedPoint)
|
|
|
|
|
if (IsGodSpeed() != true)
|
|
|
|
|
SetGodSpeed(true);
|
|
|
|
|
|
|
|
|
|
//
|
|
|
|
|
// <20><> <20><>ų ó<><C3B3>
|
|
|
|
|
//
|
|
|
|
|
if (HasMobSkill())
|
|
|
|
|
{
|
|
|
|
|
for (unsigned int iSkillIdx = 0; iSkillIdx < MOB_SKILL_MAX_NUM; ++iSkillIdx)
|
|
|
|
|
{
|
|
|
|
|
if (CanUseMobSkill(iSkillIdx))
|
|
|
|
|
{
|
|
|
|
|
SetRotationToXY(victim->GetX(), victim->GetY());
|
|
|
|
|
|
|
|
|
|
if (UseMobSkill(iSkillIdx))
|
|
|
|
|
{
|
|
|
|
|
SendMovePacket(FUNC_MOB_SKILL, iSkillIdx, GetX(), GetY(), 0, dwCurTime);
|
|
|
|
|
|
|
|
|
|
float fDuration = CMotionManager::instance().GetMotionDuration(GetRaceNum(), MAKE_MOTION_KEY(MOTION_MODE_GENERAL, MOTION_SPECIAL_1 + iSkillIdx));
|
|
|
|
|
m_dwStateDuration = (DWORD) (fDuration == 0.0f ? PASSES_PER_SEC(2) : PASSES_PER_SEC(fDuration));
|
|
|
|
|
|
|
|
|
|
if (test_server)
|
|
|
|
|
sys_log(0, "USE_MOB_SKILL: %s idx %u motion %u duration %.0f", GetName(), iSkillIdx, MOTION_SPECIAL_1 + iSkillIdx, fDuration);
|
|
|
|
|
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!Attack(victim)) // <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ж<EFBFBD><D0B6><EFBFBD>? <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>? TODO
|
|
|
|
|
m_dwStateDuration = passes_per_sec / 2;
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD> <20>ٶ<D9B6> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
|
|
|
SetRotationToXY(victim->GetX(), victim->GetY());
|
|
|
|
|
|
|
|
|
|
SendMovePacket(FUNC_ATTACK, 0, GetX(), GetY(), 0, dwCurTime);
|
|
|
|
|
|
|
|
|
|
float fDuration = CMotionManager::instance().GetMotionDuration(GetRaceNum(), MAKE_MOTION_KEY(MOTION_MODE_GENERAL, MOTION_NORMAL_ATTACK));
|
|
|
|
|
m_dwStateDuration = (DWORD) (fDuration == 0.0f ? PASSES_PER_SEC(2) : PASSES_PER_SEC(fDuration));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::StateFlag()
|
|
|
|
|
{
|
|
|
|
|
m_dwStateDuration = (DWORD) PASSES_PER_SEC(0.5);
|
|
|
|
|
|
|
|
|
|
CWarMap * pMap = GetWarMap();
|
|
|
|
|
|
|
|
|
|
if (!pMap)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
FuncFindChrForFlag f(this);
|
|
|
|
|
GetSectree()->ForEachAround(f);
|
|
|
|
|
|
|
|
|
|
if (!f.m_pkChrFind)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (NULL == f.m_pkChrFind->GetGuild())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
char buf[256];
|
|
|
|
|
BYTE idx;
|
|
|
|
|
|
|
|
|
|
if (!pMap->GetTeamIndex(GetPoint(POINT_STAT), idx))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
f.m_pkChrFind->AddAffect(AFFECT_WAR_FLAG, POINT_NONE, GetPoint(POINT_STAT), idx == 0 ? AFF_WAR_FLAG1 : AFF_WAR_FLAG2, INFINITE_AFFECT_DURATION, 0, false);
|
|
|
|
|
f.m_pkChrFind->AddAffect(AFFECT_WAR_FLAG, POINT_MOV_SPEED, 50 - f.m_pkChrFind->GetPoint(POINT_MOV_SPEED), 0, INFINITE_AFFECT_DURATION, 0, false);
|
|
|
|
|
|
|
|
|
|
pMap->RemoveFlag(idx);
|
|
|
|
|
|
|
|
|
|
snprintf(buf, sizeof(buf), LC_TEXT("%s <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %s <20><><EFBFBD><EFBFBD> ȹ<><C8B9><EFBFBD>Ͽ<EFBFBD><CFBF><EFBFBD><EFBFBD>ϴ<EFBFBD>."), pMap->GetGuild(idx)->GetName(), f.m_pkChrFind->GetName());
|
|
|
|
|
pMap->Notice(buf);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::StateFlagBase()
|
|
|
|
|
{
|
|
|
|
|
m_dwStateDuration = (DWORD) PASSES_PER_SEC(0.5);
|
|
|
|
|
|
|
|
|
|
FuncFindChrForFlagBase f(this);
|
|
|
|
|
GetSectree()->ForEachAround(f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void CHARACTER::StateHorse()
|
|
|
|
|
{
|
|
|
|
|
float START_FOLLOW_DISTANCE = 400.0f; // <20><> <20>Ÿ<EFBFBD> <20>̻<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ѿư<D1BE><C6B0><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
float START_RUN_DISTANCE = 700.0f; // <20><> <20>Ÿ<EFBFBD> <20>̻<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>پ <20>Ѿư<D1BE>.
|
|
|
|
|
int MIN_APPROACH = 150; // <20>ּ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ÿ<EFBFBD>
|
|
|
|
|
int MAX_APPROACH = 300; // <20>ִ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ÿ<EFBFBD>
|
|
|
|
|
|
|
|
|
|
DWORD STATE_DURATION = (DWORD)PASSES_PER_SEC(0.5); // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ð<EFBFBD>
|
|
|
|
|
|
|
|
|
|
bool bDoMoveAlone = true; // ij<><C4B3><EFBFBD>Ϳ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> ȥ<><C8A5> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϰ<EFBFBD><CFB0><EFBFBD> <20><><EFBFBD><EFBFBD> -_-;
|
|
|
|
|
bool bRun = true; // <20>پ<EFBFBD><D9BE><EFBFBD> <20>ϳ<EFBFBD>?
|
|
|
|
|
|
|
|
|
|
if (IsDead())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
m_dwStateDuration = STATE_DURATION;
|
|
|
|
|
|
|
|
|
|
LPCHARACTER victim = GetRider();
|
|
|
|
|
|
|
|
|
|
// ! <20>ƴ<EFBFBD> // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>ȯ<EFBFBD>ڰ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> Ŭ<><C5AC><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
if (!victim)
|
|
|
|
|
{
|
|
|
|
|
M2_DESTROY_CHARACTER(this);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_pkMobInst->m_posLastAttacked = GetXYZ();
|
|
|
|
|
|
|
|
|
|
float fDist = DISTANCE_APPROX(GetX() - victim->GetX(), GetY() - victim->GetY());
|
|
|
|
|
|
|
|
|
|
if (fDist >= START_FOLLOW_DISTANCE)
|
|
|
|
|
{
|
|
|
|
|
if (fDist > START_RUN_DISTANCE)
|
|
|
|
|
SetNowWalking(!bRun); // NOTE: <20>Լ<EFBFBD> <20≯<EFBFBD><CCB8><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ߴ°<DFB4><C2B0><EFBFBD> <20>˾Ҵµ<D2B4> SetNowWalking(false) <20>ϸ<EFBFBD> <20>ٴ°<D9B4><C2B0><EFBFBD>.. -_-;
|
|
|
|
|
|
|
|
|
|
Follow(victim, number(MIN_APPROACH, MAX_APPROACH));
|
|
|
|
|
|
|
|
|
|
m_dwStateDuration = STATE_DURATION;
|
|
|
|
|
}
|
|
|
|
|
else if (bDoMoveAlone && (get_dword_time() > m_dwLastAttackTime))
|
|
|
|
|
{
|
|
|
|
|
// wondering-.-
|
|
|
|
|
m_dwLastAttackTime = get_dword_time() + number(5000, 12000);
|
|
|
|
|
|
|
|
|
|
SetRotation(number(0, 359)); // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
|
|
|
|
|
|
|
|
|
float fx, fy;
|
|
|
|
|
float fDist = number(200, 400);
|
|
|
|
|
|
|
|
|
|
GetDeltaByDegree(GetRotation(), fDist, &fx, &fy);
|
|
|
|
|
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD> üũ; <20><><EFBFBD><EFBFBD> <20><>ġ<EFBFBD><C4A1> <20>߰<EFBFBD> <20><>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
|
|
|
|
if (!(SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx, GetY() + (int) fy)
|
|
|
|
|
&& SECTREE_MANAGER::instance().IsMovablePosition(GetMapIndex(), GetX() + (int) fx/2, GetY() + (int) fy/2)))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
SetNowWalking(true);
|
|
|
|
|
|
|
|
|
|
if (Goto(GetX() + (int) fx, GetY() + (int) fy))
|
|
|
|
|
SendMovePacket(FUNC_WAIT, 0, 0, 0, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|