1114 lines
29 KiB
C++
1114 lines
29 KiB
C++
#include "stdafx.h"
|
||
#include "Map.h"
|
||
#include "MagicInstance.h"
|
||
#include "../shared/DateTime.h"
|
||
|
||
using namespace std;
|
||
|
||
CNpc::CNpc() : Unit(UnitNPC)
|
||
{
|
||
Initialize();
|
||
}
|
||
|
||
|
||
CNpc::~CNpc()
|
||
{
|
||
}
|
||
|
||
/**
|
||
* @brief Initializes this object.
|
||
*/
|
||
void CNpc::Initialize()
|
||
{
|
||
cubeisactive = 0;
|
||
Unit::Initialize();
|
||
m_bIsEventNpc = false;
|
||
m_sSid = 0;
|
||
m_sPid = 0; // MONSTER(NPC) Picture ID
|
||
m_sSize = 100; // MONSTER(NPC) Size
|
||
m_strName.clear(); // MONSTER(NPC) Name
|
||
m_iMaxHP = 0; // <20>ִ<EFBFBD> HP
|
||
m_iHP = 0; // <20><><EFBFBD><EFBFBD> HP
|
||
m_byState = 0; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> (NPC) <20><><EFBFBD><EFBFBD><EFBFBD>̻<EFBFBD>
|
||
m_tNpcType = 0; // NPC Type
|
||
// 0 : Normal Monster
|
||
// 1 : NPC
|
||
// 2 : <20><> <20>Ա<EFBFBD>,<2C>ⱸ NPC
|
||
// 3 : <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
m_iSellingGroup = 0;
|
||
//m_dwStepDelay = 0;
|
||
|
||
m_byDirection = 0; // npc<70><63> <20><><EFBFBD><EFBFBD>,,
|
||
m_iWeapon_1 = 0;
|
||
m_iWeapon_2 = 0;
|
||
m_NpcState = NPC_LIVE;
|
||
m_byGateOpen = true;
|
||
m_byObjectType = NORMAL_OBJECT;
|
||
m_JuraidGateOpen = 1;
|
||
m_byTrapNumber = 0;
|
||
m_oSocketID = -1;
|
||
m_bEventRoom = 0;
|
||
|
||
nIsPet = false;
|
||
strPetName = "";
|
||
strUserName = "";
|
||
nSerial = 0;
|
||
UserId = -1;
|
||
InitType3();
|
||
InitType4(true);
|
||
}
|
||
|
||
/**
|
||
* @brief Adds the NPC to the region.
|
||
*
|
||
* @param new_region_x The new region x coordinate.
|
||
* @param new_region_z The new region z coordinate.
|
||
*/
|
||
void CNpc::AddToRegion(int16 new_region_x, int16 new_region_z)
|
||
{
|
||
if(GetMap() == nullptr)
|
||
return;
|
||
|
||
if(GetMap()->GetXRegionMax() < new_region_x
|
||
|| GetMap()->GetZRegionMax() < new_region_z)
|
||
return;
|
||
|
||
GetRegion()->Remove(this);
|
||
SetRegion(new_region_x, new_region_z);
|
||
|
||
GetRegion()->Add(this);
|
||
}
|
||
|
||
/**
|
||
* @brief Sends the movement packet for the NPC.
|
||
*
|
||
* @param fPosX The position x coordinate.
|
||
* @param fPosY The position y coordinate.
|
||
* @param fPosZ The position z coordinate.
|
||
* @param fSpeed The speed.
|
||
*/
|
||
void CNpc::MoveResult(float fPosX, float fPosY, float fPosZ, float fSpeed)
|
||
{
|
||
if(nIsPet)
|
||
return;
|
||
|
||
/*Packet result(WIZ_NPC_MOVE);
|
||
|
||
SetPosition(fPosX, fPosY, fPosZ);
|
||
RegisterRegion();
|
||
#if __VERSION >= 1950
|
||
result << uint8(fSpeed);
|
||
#endif
|
||
result << GetID() << GetSPosX() << GetSPosZ() << GetSPosY() << uint16(1);
|
||
SendToRegion(&result);*/
|
||
|
||
Packet result(WIZ_NPC_MOVE, uint8(SUCCESS));
|
||
SetPosition(fPosX, fPosY, fPosZ);
|
||
RegisterRegion();
|
||
result << GetID() << GetSPosX() << GetSPosZ() << GetSPosY();
|
||
if(m_bIceSpeedAmount > 0)
|
||
result << fSpeed / float(m_bIceSpeedAmount);
|
||
else
|
||
result << fSpeed * float(85.99F);
|
||
SendToRegion(&result);
|
||
}
|
||
|
||
/**
|
||
* @brief Constructs an in/out packet for the NPC.
|
||
*
|
||
* @param result The packet buffer the constructed packet will be stored in.
|
||
* @param bType The type (in or out).
|
||
*/
|
||
void CNpc::GetInOut(Packet & result, uint8 bType)
|
||
{
|
||
result.Initialize(WIZ_NPC_INOUT);
|
||
result << bType << GetID();
|
||
if (bType != INOUT_OUT)
|
||
GetNpcInfo(result);
|
||
|
||
if (bType == INOUT_IN)
|
||
OnRespawn();
|
||
}
|
||
|
||
/**
|
||
* @brief Constructs and sends an in/out packet for the NPC.
|
||
*
|
||
* @param bType The type (in or out).
|
||
* @param fX The x coordinate.
|
||
* @param fZ The z coordinate.
|
||
* @param fY The y coordinate.
|
||
*/
|
||
void CNpc::SendInOut(uint8 bType, float fX, float fZ, float fY)
|
||
{
|
||
if (GetRegion() == nullptr)
|
||
{
|
||
SetRegion(GetNewRegionX(), GetNewRegionZ());
|
||
if (GetRegion() == nullptr)
|
||
return;
|
||
}
|
||
|
||
if (bType == INOUT_OUT)
|
||
{
|
||
GetRegion()->Remove(this);
|
||
}
|
||
else
|
||
{
|
||
GetRegion()->Add(this);
|
||
SetPosition(fX, fY, fZ);
|
||
}
|
||
|
||
Packet result;
|
||
GetInOut(result, bType);
|
||
SendToRegion(&result);
|
||
|
||
if (nIsPet)
|
||
{
|
||
Packet result3;
|
||
CUser *pUser = g_pMain->GetUserPtr(UserId);
|
||
CPet *mPet = g_pMain->GetPetPtr(nSerial);
|
||
|
||
if (mPet == nullptr
|
||
|| pUser == nullptr)
|
||
return;
|
||
|
||
if(pUser->LastWarpTime > (UNIXTIME - 2))
|
||
return;
|
||
|
||
result3.Initialize(WIZ_OBJECT_EVENT);
|
||
result3 << uint8(0x0B) << uint8(0x01) << GetID() << uint32(30403);
|
||
SendToRegion(&result3);
|
||
|
||
g_pMain->m_LivingPetArray.insert(std::make_pair(mPet->m_Serial, mPet));
|
||
|
||
Packet pet(WIZ_PET);
|
||
pet.DByte();
|
||
|
||
pet << uint8(0x01) << uint8(0x05) << uint8(0x01) << uint8(0x01) << uint8(0x00)
|
||
<< uint32(mPet->SpecialPetID)
|
||
<< mPet->GetName()
|
||
<< mPet->m_sClass
|
||
<< mPet->m_bLevel << uint16((mPet->m_iExp* 10000) / g_pMain->GetPetExpByLevel(mPet->m_bLevel))
|
||
<< uint16(mPet->m_sMaxHp) << uint16(mPet->m_sHp)
|
||
<< uint16(mPet->m_sMaxMp) << uint16(mPet->m_sMp)
|
||
<< uint16(mPet->m_sSatisfaction)
|
||
<< uint16(mPet->m_sAttack) << uint16(mPet->m_sAc)
|
||
<< uint8(mPet->m_sFireR) << uint8(mPet->m_sColdR) << uint8(mPet->m_sLightningR)
|
||
<< uint8(mPet->m_sMagicR) << uint8(mPet->m_sDiseaseR) << uint8(mPet->m_sPoisonR);
|
||
|
||
for (int i = 0; i < PET_MAX; i++) // pet cıkar görürsün de ne sorcaksan sor cıkıcam valla kanka 2 minik sorum var :D
|
||
{
|
||
_ITEM_DATA * pItem = &mPet->m_sItemArray[i];
|
||
|
||
//if(pItem->nNum > 0)
|
||
pet << pItem->nNum << pItem->sDuration << pItem->sCount << pItem->bFlag << uint16(0) << uint32(0) << pItem->nExpirationTime;
|
||
//else
|
||
//pet << uint32(0) << uint16(0) << uint16(0) << uint8(0) << uint16(0) << uint32(0) << uint32(0);
|
||
}
|
||
|
||
pUser->Send(&pet);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Gets NPC information for use in various NPC packets.
|
||
*
|
||
* @param pkt The packet the information will be stored in.
|
||
*/
|
||
void CNpc::GetNpcInfo(Packet & pkt, uint8 myNation)
|
||
{
|
||
if(nIsPet)
|
||
{
|
||
pkt.SByte();
|
||
CUser *pUser = g_pMain->GetUserPtr(UserId);
|
||
if(!pUser)
|
||
return;
|
||
_ITEM_DATA *pItem = nullptr;
|
||
|
||
if ((pItem = pUser->GetItem(SHOULDER)) == nullptr)
|
||
return;
|
||
|
||
CPet *newPet = g_pMain->GetPetPtr(pItem->nSerialNum);
|
||
if(newPet == nullptr || newPet->pSession == nullptr)
|
||
return;
|
||
|
||
pkt << uint16(0) << uint8(newPet->isMonster() ? 1:2) << m_sPid << m_iSellingGroup
|
||
<< uint8(15) << uint32(0)
|
||
<< newPet->m_sSize << uint32(m_iWeapon_1) << uint32(m_iWeapon_2)
|
||
<< pUser->GetName() << newPet->m_strPetID
|
||
<< pUser->GetNation() << newPet->m_bLevel
|
||
<< newPet->GetSPosX() << newPet->GetSPosZ() << newPet->GetSPosY()
|
||
<< uint32(0) << uint8(0) << uint32(0) << int16(newPet->m_byDirection);
|
||
|
||
}
|
||
pkt.SByte();
|
||
#if (__VERSION >= 1950)
|
||
pkt << GetProtoID()
|
||
<< uint8(isMonster() ? 1 : 2) // Monster = 1, NPC = 2 (need to use a better flag)
|
||
<< m_sPid
|
||
<< m_iSellingGroup;
|
||
if (nIsPet && !m_bIsEventNpc)
|
||
pkt << uint8(64);
|
||
else
|
||
pkt << GetType();
|
||
pkt << uint32(0)
|
||
<< m_sSize
|
||
<< uint32(m_iWeapon_1) << uint32(m_iWeapon_2); // isPet() ? string
|
||
if (nIsPet && m_bIsEventNpc)
|
||
pkt << strUserName << strPetName;
|
||
if(myNation == uint8(-1))
|
||
pkt << uint8(isMonster() ? 0 : GetNation());
|
||
else
|
||
pkt << uint8(myNation);
|
||
|
||
pkt << GetLevel()
|
||
<< GetSPosX() << GetSPosZ() << GetSPosY();
|
||
if(GetProtoID() == 8110)
|
||
pkt << uint32(m_JuraidGateOpen);
|
||
else
|
||
pkt << uint32(m_byGateOpen);
|
||
pkt << m_byObjectType
|
||
<< uint16(0) << uint16(0) // unknown
|
||
<< int16(m_byDirection);
|
||
#endif
|
||
#if (__VERSION < 1950)
|
||
pkt << GetProtoID()
|
||
<< uint8(isMonster() ? 1 : 2) // Monster = 1, NPC = 2 (need to use a better flag)
|
||
<< m_sPid
|
||
<< GetType()
|
||
<< m_iSellingGroup
|
||
<< m_sSize
|
||
<< m_iWeapon_1 << m_iWeapon_2
|
||
// Monsters require 0 regardless, otherwise they'll act as NPCs.
|
||
<< uint8(isMonster() ? 0 : GetNation())
|
||
<< GetLevel()
|
||
<< GetSPosX() << GetSPosZ() << GetSPosY()
|
||
<< uint32(isGateOpen())
|
||
<< m_byObjectType
|
||
<< uint16(0) << uint16(0) // unknown
|
||
<< int16(m_byDirection);
|
||
#endif
|
||
}
|
||
|
||
/**
|
||
* @brief Sends a gate status.
|
||
*
|
||
* @param ObjectType object type
|
||
* @param bFlag The flag (open or shut).
|
||
* @param bSendAI true to update the AI server.
|
||
*/
|
||
void CNpc::SendGateFlag(uint8 bFlag /*= -1*/, bool bSendAI /*= true*/)
|
||
{
|
||
uint8 objectType = OBJECT_FLAG_LEVER;
|
||
|
||
_OBJECT_EVENT * pObjectEvent = GetMap()->GetObjectEvent(GetProtoID());
|
||
|
||
if (pObjectEvent)
|
||
objectType = (uint8)pObjectEvent->sType;
|
||
|
||
if (GetProtoID() == 8110)
|
||
objectType = OBJECT_GATE;
|
||
|
||
|
||
Packet result(WIZ_OBJECT_EVENT, objectType);
|
||
|
||
if (GetProtoID() == 8110)
|
||
{
|
||
m_JuraidGateOpen = bFlag;
|
||
|
||
result << uint8(1) << GetID() << bFlag;
|
||
SendToRegion(&result);
|
||
}
|
||
else
|
||
{
|
||
|
||
// If there's a flag to set, set it now.
|
||
if (bFlag >= 0)
|
||
m_byGateOpen = (bFlag == 1);
|
||
|
||
// Tell everyone nearby our new status.
|
||
result << uint8(1) << GetID() << m_byGateOpen;
|
||
SendToRegion(&result);
|
||
|
||
// Tell the AI server our new status
|
||
if (bSendAI)
|
||
{
|
||
result.Initialize(AG_NPC_GATE_OPEN);
|
||
result << GetID() << GetProtoID() << m_byGateOpen;
|
||
Send_AIServer(&result);
|
||
}
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Changes an NPC's hitpoints.
|
||
*
|
||
* @param amount The amount to adjust the HP by.
|
||
* @param pAttacker The attacker.
|
||
* @param bSendToAI true to update the AI server.
|
||
*/
|
||
void CNpc::HpChange(int amount, Unit *pAttacker /*= nullptr*/, bool bSendToAI /*= true*/)
|
||
{
|
||
uint16 tid = (pAttacker != nullptr ? pAttacker->GetID() : -1);
|
||
|
||
if(GetType() == NPC_FOSSIL && tid < NPC_BAND && amount != -1)
|
||
return;
|
||
|
||
if(GetType() == NPC_TREE && tid < NPC_BAND && amount != -20)
|
||
return;
|
||
|
||
// Implement damage/HP cap.
|
||
if (amount < -MAX_DAMAGE)
|
||
amount = -MAX_DAMAGE;
|
||
else if (amount > MAX_DAMAGE)
|
||
amount = MAX_DAMAGE;
|
||
|
||
// Glorious copypasta.
|
||
if (amount < 0 && -amount > m_iHP)
|
||
m_iHP = 0;
|
||
else if (amount >= 0 && m_iHP + amount > m_iMaxHP)
|
||
m_iHP = m_iMaxHP;
|
||
else
|
||
m_iHP += amount;
|
||
|
||
if(nIsPet && nSerial > 0)
|
||
{
|
||
CPet * pPet = g_pMain->GetPetPtr(nSerial);
|
||
|
||
if(pPet != nullptr)
|
||
pPet->HpChange(amount,pAttacker,false);
|
||
}
|
||
|
||
// NOTE: This will handle the death notification/looting.
|
||
if (bSendToAI)
|
||
SendHpChangeToAI(tid, nIsPet && nSerial > 0 && isDead() ? -50000 : amount);
|
||
|
||
if (pAttacker != nullptr
|
||
&& pAttacker->isPlayer())
|
||
TO_USER(pAttacker)->SendTargetHP(0, GetID(), amount);
|
||
}
|
||
|
||
void CNpc::HpChangeMagic(int amount, Unit *pAttacker /*= nullptr*/, AttributeType attributeType /*= AttributeNone*/)
|
||
{
|
||
uint16 tid = (pAttacker != nullptr ? pAttacker->GetID() : -1);
|
||
|
||
if(GetType() == NPC_FOSSIL || GetType() == NPC_TREE)
|
||
return;
|
||
|
||
// Implement damage/HP cap.
|
||
if (amount < -MAX_DAMAGE)
|
||
amount = -MAX_DAMAGE;
|
||
else if (amount > MAX_DAMAGE)
|
||
amount = MAX_DAMAGE;
|
||
|
||
HpChange(amount, pAttacker, false);
|
||
SendHpChangeToAI(tid, amount, attributeType);
|
||
}
|
||
|
||
void CNpc::SendHpChangeToAI(uint16 sTargetID, int amount, AttributeType attributeType /*= AttributeNone*/)
|
||
{
|
||
Packet result(AG_NPC_HP_CHANGE);
|
||
result << GetID() << sTargetID << m_iHP << amount << uint8(attributeType);
|
||
Send_AIServer(&result);
|
||
}
|
||
|
||
/**
|
||
* @brief Changes an NPC's mana.
|
||
*
|
||
* @param amount The amount to adjust the mana by.
|
||
*/
|
||
void CNpc::MSpChange(int amount)
|
||
{
|
||
|
||
}
|
||
|
||
bool CNpc::CastSkill(Unit * pTarget, uint32 nSkillID)
|
||
{
|
||
if (pTarget == nullptr)
|
||
return false;
|
||
|
||
MagicInstance instance;
|
||
|
||
instance.bSendFail = false;
|
||
instance.nSkillID = nSkillID;
|
||
instance.sCasterID = GetID();
|
||
instance.sTargetID = pTarget->GetID();
|
||
|
||
instance.Run();
|
||
|
||
return (instance.bSkillSuccessful);
|
||
}
|
||
|
||
float CNpc::GetRewardModifier(uint8 byLevel)
|
||
{
|
||
int iLevelDifference = GetLevel() - byLevel;
|
||
|
||
if (iLevelDifference <= -14)
|
||
return 0.2f;
|
||
else if (iLevelDifference <= -8 && iLevelDifference >= -13)
|
||
return 0.5f;
|
||
else if (iLevelDifference <= -2 && iLevelDifference >= -7)
|
||
return 0.8f;
|
||
|
||
return 1.0f;
|
||
}
|
||
|
||
float CNpc::GetPartyRewardModifier(uint32 nPartyLevel, uint32 nPartyMembers)
|
||
{
|
||
int iLevelDifference = GetLevel() - (nPartyLevel / nPartyMembers);
|
||
|
||
if (iLevelDifference >= 8)
|
||
return 1.3f;// was 2.0f edited byBrate
|
||
else if (iLevelDifference >= 5)
|
||
return 1.2f;// was 1.5f edited byBrate
|
||
else if (iLevelDifference >= 2)
|
||
return 1.1f;// was 1.2f edited byBrate
|
||
|
||
return 1.0f;
|
||
}
|
||
|
||
/**
|
||
* @brief Executes the death action.
|
||
*
|
||
* @param pKiller The killer.
|
||
*/
|
||
void CNpc::OnDeath(Unit *pKiller)
|
||
{
|
||
if (m_NpcState == NPC_DEAD || pKiller == nullptr)
|
||
return;
|
||
|
||
ASSERT(GetMap() != nullptr);
|
||
ASSERT(GetRegion() != nullptr);
|
||
|
||
m_NpcState = NPC_DEAD;
|
||
m_sACPercent = 100;
|
||
|
||
if (m_byObjectType == SPECIAL_OBJECT)
|
||
{
|
||
_OBJECT_EVENT *pEvent = GetMap()->GetObjectEvent(GetProtoID());
|
||
if (pEvent != nullptr)
|
||
pEvent->byLife = 0;
|
||
}
|
||
if (GetProtoID() != 31527
|
||
|| GetProtoID() != 31528
|
||
|| GetProtoID() != 31529
|
||
|| GetProtoID() != 31530)
|
||
Unit::OnDeath(pKiller);
|
||
OnDeathProcess(pKiller);
|
||
|
||
GetRegion()->Remove(TO_NPC(this));
|
||
SetRegion();
|
||
|
||
if(nIsPet && nSerial > 0)
|
||
{
|
||
CPet * pPet = g_pMain->GetPetPtr(nSerial);
|
||
|
||
if(pPet != nullptr)
|
||
pPet->Dead();
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Executes the death process.
|
||
*
|
||
* @param pKiller The killer.
|
||
*/
|
||
void CNpc::OnDeathProcess(Unit *pKiller)
|
||
{
|
||
if ((TO_NPC(this) == nullptr
|
||
|| pKiller == nullptr))
|
||
return;
|
||
|
||
if (pKiller->GetID() > NPC_BAND)
|
||
return;
|
||
|
||
CUser * pUser = TO_USER(pKiller);
|
||
|
||
if (pUser == nullptr)
|
||
return;
|
||
|
||
if (!m_bMonster)
|
||
{
|
||
switch (m_tNpcType)
|
||
{
|
||
case NPC_BIFROST_MONUMENT:
|
||
pUser->BifrostProcess(pUser);
|
||
break;
|
||
case NPC_CZ_MONUMENT:
|
||
CZMonumentProcess(pUser);
|
||
break;
|
||
case NPC_PVP_MONUMENT:
|
||
PVPMonumentProcess(pUser);
|
||
break;
|
||
case NPC_BATTLE_MONUMENT:
|
||
BattleMonumentProcess(pUser);
|
||
break;
|
||
case NPC_HUMAN_MONUMENT:
|
||
NationMonumentProcess(pUser);
|
||
break;
|
||
case NPC_KARUS_MONUMENT:
|
||
NationMonumentProcess(pUser);
|
||
break;
|
||
case NPC_DESTROYED_ARTIFACT:
|
||
pUser->CastleSiegeWarProcess(pUser);
|
||
break;
|
||
}
|
||
}
|
||
else if (m_bMonster)
|
||
{
|
||
if (GetProtoID() == 700 || GetProtoID() == 750 || GetProtoID() == 701 || GetProtoID() == 751)
|
||
{
|
||
if (pUser->V3_CheckExistEvent(STARTER_SEED_QUEST, 1))
|
||
{
|
||
_QUEST_HELPER * pQuestHelper ;
|
||
if (pUser->GetNation() == ELMORAD)
|
||
pQuestHelper = g_pMain->m_QuestHelperArray.GetData(5005);
|
||
else
|
||
pQuestHelper = g_pMain->m_QuestHelperArray.GetData(5002);
|
||
|
||
pUser->V3_QuestRunEvent(pQuestHelper,pQuestHelper->nEventTriggerIndex);
|
||
}
|
||
}
|
||
|
||
else if (g_pMain->m_MonsterRespawnListArray.GetData(GetProtoID()) != nullptr && pUser->isInPKZone())
|
||
{
|
||
g_pMain->SpawnEventNpc(g_pMain->m_MonsterRespawnListArray.GetData(GetProtoID())->sSid, true, GetZoneID(), GetX(), GetY(), GetZ(), g_pMain->m_MonsterRespawnListArray.GetData(GetProtoID())->sCount);
|
||
|
||
}
|
||
else if (g_pMain->pTempleEvent.ActiveEvent == TEMPLE_EVENT_JURAD_MOUNTAIN)
|
||
{
|
||
if (JuraidTempleEventZone())
|
||
{
|
||
if (g_pMain->m_MonsterRespawnListArray.GetData(GetProtoID()) != nullptr)
|
||
g_pMain->SpawnEventNpc(g_pMain->m_MonsterRespawnListArray.GetData(GetProtoID())->sSid, true, GetZoneID(), GetX(), GetY(), GetZ(), g_pMain->m_MonsterRespawnListArray.GetData(GetProtoID())->sCount,5,60*60,GetNation(),pUser->GetSocketID(),pUser->GetEventRoom());
|
||
|
||
|
||
if (GetProtoID() == 8100 || GetProtoID() == 8102)
|
||
{
|
||
pUser->GetNation() == KARUS ? g_pMain->pTempleEvent.KarusDeathRoom1[pUser->GetEventRoom()]++ : g_pMain->pTempleEvent.ElmoDeathRoom1[pUser->GetEventRoom()]++;
|
||
|
||
if ((g_pMain->pTempleEvent.KarusDeathRoom1[pUser->GetEventRoom()] > 3 && pUser->GetNation() == KARUS)
|
||
|| (g_pMain->pTempleEvent.ElmoDeathRoom1[pUser->GetEventRoom()] > 3 && pUser->GetNation() == ELMORAD))
|
||
{
|
||
if (pUser->GetNation() == KARUS)
|
||
{
|
||
g_pMain->pTempleEvent.KarusDeathRoom2[pUser->GetEventRoom()] = 0;
|
||
CNpc * pNpc = g_pMain->GetNpcPtr(g_pMain->pTempleEvent.JuraidKarusGateID1[pUser->GetEventRoom()]);
|
||
|
||
if(pNpc == nullptr)
|
||
printf("Bulunamadi... K 1\n");
|
||
return;
|
||
pNpc->SendGateFlag(2);
|
||
}
|
||
else
|
||
{
|
||
g_pMain->pTempleEvent.ElmoDeathRoom2[pUser->GetEventRoom()] = 0;
|
||
CNpc * pNpc = g_pMain->GetNpcPtr(g_pMain->pTempleEvent.JuraidElmoGateID1[pUser->GetEventRoom()]);
|
||
|
||
if(pNpc == nullptr)
|
||
printf("Bulunamadi... E 1\n");
|
||
return;
|
||
pNpc->SendGateFlag(2);
|
||
}
|
||
}
|
||
}
|
||
else if (GetProtoID () == 8101 || GetProtoID () == 8104)
|
||
{
|
||
pUser->GetNation() == KARUS ? g_pMain->pTempleEvent.KarusDeathRoom2[pUser->GetEventRoom()]++ : g_pMain->pTempleEvent.ElmoDeathRoom2[pUser->GetEventRoom()]++;
|
||
|
||
if ((g_pMain->pTempleEvent.KarusDeathRoom2[pUser->GetEventRoom()] > 3 && pUser->GetNation() == KARUS)
|
||
|| (g_pMain->pTempleEvent.ElmoDeathRoom2[pUser->GetEventRoom()] > 3 && pUser->GetNation() == ELMORAD))
|
||
{
|
||
if (pUser->GetNation() == KARUS)
|
||
{
|
||
g_pMain->pTempleEvent.KarusDeathRoom3[pUser->GetEventRoom()] = 0;
|
||
CNpc * pNpc = g_pMain->GetNpcPtr(g_pMain->pTempleEvent.JuraidKarusGateID2[pUser->GetEventRoom()]);
|
||
|
||
if(pNpc == nullptr)
|
||
printf("Bulunamadi... K 2\n");
|
||
return;
|
||
pNpc->SendGateFlag(2);
|
||
}
|
||
else
|
||
{
|
||
g_pMain->pTempleEvent.ElmoDeathRoom3[pUser->GetEventRoom()] = 0;
|
||
CNpc * pNpc = g_pMain->GetNpcPtr(g_pMain->pTempleEvent.JuraidElmoGateID2[pUser->GetEventRoom()]);
|
||
|
||
if(pNpc == nullptr)
|
||
printf("Bulunamadi... E 2\n");
|
||
return;
|
||
pNpc->SendGateFlag(2);
|
||
}
|
||
}
|
||
}
|
||
else if (GetProtoID () == 8103 || GetProtoID () == 8105)
|
||
{
|
||
pUser->GetNation() == KARUS ? g_pMain->pTempleEvent.KarusDeathRoom3[pUser->GetEventRoom()]++ : g_pMain->pTempleEvent.ElmoDeathRoom3[pUser->GetEventRoom()]++;
|
||
|
||
if ((g_pMain->pTempleEvent.KarusDeathRoom3[pUser->GetEventRoom()] > 3 && pUser->GetNation() == KARUS)
|
||
|| (g_pMain->pTempleEvent.ElmoDeathRoom3[pUser->GetEventRoom()] > 3 && pUser->GetNation() == ELMORAD))
|
||
{
|
||
if (pUser->GetNation() == KARUS)
|
||
{
|
||
CNpc * pNpc = g_pMain->GetNpcPtr(g_pMain->pTempleEvent.JuraidKarusGateID3[pUser->GetEventRoom()]);
|
||
|
||
if(pNpc == nullptr)
|
||
printf("Bulunamadi... K 3\n");
|
||
return;
|
||
pNpc->SendGateFlag(2);
|
||
}
|
||
else
|
||
{
|
||
CNpc * pNpc = g_pMain->GetNpcPtr(g_pMain->pTempleEvent.JuraidElmoGateID3[pUser->GetEventRoom()]);
|
||
|
||
if(pNpc == nullptr)
|
||
printf("Bulunamadi... E 3\n");
|
||
return;
|
||
pNpc->SendGateFlag(2);
|
||
}
|
||
}
|
||
}
|
||
else if (GetProtoID () == 8106)// Deva
|
||
{
|
||
g_pMain->pTempleEvent.isDevaControl[GetEventRoom()] = true;
|
||
g_pMain->pTempleEvent.isDevaFlag[GetEventRoom()] = true;
|
||
g_pMain->pTempleEvent.DevaNation[GetEventRoom()] = pUser->GetNation();
|
||
}
|
||
|
||
}
|
||
}
|
||
else if (m_tNpcType == NPC_CHAOS_STONE && pUser->isInPKZone())
|
||
{
|
||
ChaosStoneProcess(pUser,5);
|
||
}else if((m_sSid == g_pMain->Zone1Boss[GetEventRoom()] || m_sSid == g_pMain->Zone2Boss[GetEventRoom()] || m_sSid == g_pMain->Zone3Boss[GetEventRoom()]) && (GetZoneID() == ZONE_STONE1 || GetZoneID() == ZONE_STONE2 || GetZoneID() == ZONE_STONE3))
|
||
{
|
||
Packet dresult(WIZ_EVENT);
|
||
dresult << uint8(TEMPLE_EVENT_FINISH)
|
||
<< uint8(0) << uint8(0)
|
||
<< uint8(1) << uint8(20) << uint32(0);
|
||
TO_USER(pKiller)->Send(&dresult);
|
||
TO_USER(pKiller)->m_TimeMonsterStone = UNIXTIME + 20;
|
||
}
|
||
|
||
if (g_pMain->m_bForgettenTempleIsActive && GetZoneID() == ZONE_FORGOTTEN_TEMPLE)
|
||
g_pMain->m_ForgettenTempleMonsterList.erase(m_sNid);
|
||
|
||
if (pUser->isInParty())
|
||
{
|
||
_PARTY_GROUP *pParty = g_pMain->GetPartyPtr(pUser->GetPartyID());
|
||
if (pParty != nullptr)
|
||
{
|
||
for (int i = 0; i < 8; i++)
|
||
{
|
||
if (pParty->uid[i] >= 0)
|
||
{
|
||
CUser * pUserRange = g_pMain->GetUserPtr(pParty->uid[i]);
|
||
if (!isInRangeSlow(pUserRange, 50.0f) || pUserRange == nullptr)
|
||
continue;
|
||
|
||
CUser * pUserParty = g_pMain->GetUserPtr(pParty->uid[i]);
|
||
pUserParty->V3_MonsterCount(GetProtoID());
|
||
pUserParty->AchieveType2(this);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
pUser->V3_MonsterCount(GetProtoID());
|
||
pUser->AchieveType2(this);
|
||
}
|
||
}
|
||
|
||
DateTime time;
|
||
string pKillerPartyUsers;
|
||
|
||
if (pUser->isInParty())
|
||
{
|
||
CUser *pPartyUser;
|
||
_PARTY_GROUP *pParty = g_pMain->GetPartyPtr(pUser->GetPartyID());
|
||
if (pParty)
|
||
{
|
||
for (int i = 0; i < MAX_PARTY_USERS; i++)
|
||
{
|
||
pPartyUser = g_pMain->GetUserPtr(pParty->uid[i]);
|
||
if (pPartyUser)
|
||
pKillerPartyUsers += string_format("%s,",pPartyUser->GetName().c_str());
|
||
}
|
||
}
|
||
|
||
if (!pKillerPartyUsers.empty())
|
||
pKillerPartyUsers = pKillerPartyUsers.substr(0,pKillerPartyUsers.length() - 1);
|
||
}
|
||
|
||
if (pKillerPartyUsers.empty())
|
||
g_pMain->WriteDeathNpcLogFile(string_format("[ %s - %d:%d:%d ] Killer=%s,SID=%d,Target=%s,Zone=%d,X=%d,Z=%d\n",m_bMonster ? "MONSTER" : "NPC",time.GetHour(),time.GetMinute(),time.GetSecond(),pKiller->GetName().c_str(),GetProtoID(),GetName().c_str(),GetZoneID(),uint16(GetX()),uint16(GetZ())));
|
||
else
|
||
g_pMain->WriteDeathNpcLogFile(string_format("[ %s - %d:%d:%d ] Killer=%s,KillerParty=%s,SID=%d,Target=%s,Zone=%d,X=%d,Z=%d\n",m_bMonster ? "MONSTER" : "NPC",time.GetHour(),time.GetMinute(),time.GetSecond(),pKiller->GetName().c_str(),pKillerPartyUsers.c_str(),GetProtoID(),GetName().c_str(),GetZoneID(),uint16(GetX()),uint16(GetZ())));
|
||
|
||
InitType3();
|
||
InitType4(false);
|
||
}
|
||
|
||
void CNpc::InitType3()
|
||
{
|
||
for (int i = 0; i < MAX_TYPE3_REPEAT; i++)
|
||
m_durationalSkills[i].Reset();
|
||
|
||
m_bType3Flag = false;
|
||
}
|
||
|
||
void CNpc::InitType4(bool bRemoveSavedMagic /*= false*/, uint8 buffType /* = 0 */)
|
||
{
|
||
Type4BuffMap buffMap = m_buffMap; // copy the map
|
||
|
||
for (auto itr = buffMap.begin(); itr != buffMap.end(); itr++)
|
||
{
|
||
#ifdef GAMESERVER
|
||
if (buffType > 0 && itr->second.m_bBuffType != buffType)
|
||
continue;
|
||
|
||
CMagicProcess::RemoveType4Buff(itr->first, this, bRemoveSavedMagic, buffType > 0 ? true : false);
|
||
#endif
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @brief Executes the Npc respawn.
|
||
*/
|
||
void CNpc::OnRespawn()
|
||
{
|
||
if (GetProtoID() == BORDER_WAR_MONUMENT_SID
|
||
|| (g_pMain->m_byBattleOpen == NATION_BATTLE
|
||
&& (GetProtoID() == ELMORAD_MONUMENT_SID
|
||
|| GetProtoID() == ASGA_VILLAGE_MONUMENT_SID
|
||
|| GetProtoID() == RAIBA_VILLAGE_MONUMENT_SID
|
||
|| GetProtoID() == DODO_CAMP_MONUMENT_SID
|
||
|| GetProtoID() == LUFERSON_MONUMENT_SID
|
||
|| GetProtoID() == LINATE_MONUMENT_SID
|
||
|| GetProtoID() == BELLUA_MONUMENT_SID
|
||
|| GetProtoID() == LAON_CAMP_MONUMENT_SID)))
|
||
{
|
||
_MONUMENT_INFORMATION * pData = new _MONUMENT_INFORMATION();
|
||
pData->sSid = GetProtoID();
|
||
pData->sNid = m_sNid;
|
||
pData->RepawnedTime = int32(UNIXTIME);
|
||
|
||
if (GetProtoID() == DODO_CAMP_MONUMENT_SID || GetProtoID() == LAON_CAMP_MONUMENT_SID)
|
||
g_pMain->m_bMiddleStatueNation = m_bNation;
|
||
|
||
if (!g_pMain->m_NationMonumentInformationArray.PutData(pData->sSid, pData))
|
||
delete pData;
|
||
}
|
||
else if (g_pMain->m_bForgettenTempleIsActive && GetZoneID() == ZONE_FORGOTTEN_TEMPLE)
|
||
g_pMain->m_ForgettenTempleMonsterList.insert(std::make_pair(m_sNid, GetProtoID()));
|
||
}
|
||
|
||
/**
|
||
* @brief Executes the death process.
|
||
*
|
||
* @param pUser The User.
|
||
* @param MonsterCount The Respawn boss count.
|
||
*/
|
||
void CNpc::ChaosStoneProcess(CUser *pUser, uint16 MonsterCount)
|
||
{
|
||
if (pUser == nullptr)
|
||
return;
|
||
|
||
g_pMain->SendNotice<CHAOS_STONE_ENEMY_NOTICE>("",GetZoneID(), Nation::ALL);
|
||
|
||
std::vector<uint32> MonsterSpawned;
|
||
std::vector<uint32> MonsterSpawnedFamily;
|
||
bool bLoopBack = true;
|
||
|
||
for (uint8 i = 0; i < MonsterCount;i++)
|
||
{
|
||
uint32 nMonsterNum = myrand(0, g_pMain->m_MonsterSummonListZoneArray.GetSize());
|
||
_MONSTER_SUMMON_LIST_ZONE * pMonsterSummonListZone = g_pMain->m_MonsterSummonListZoneArray.GetData(nMonsterNum);
|
||
|
||
if (pMonsterSummonListZone != nullptr)
|
||
{
|
||
if (pMonsterSummonListZone->ZoneID == GetZoneID())
|
||
{
|
||
if (std::find(MonsterSpawned.begin(),MonsterSpawned.end(),nMonsterNum) == MonsterSpawned.end())
|
||
{
|
||
if (std::find(MonsterSpawnedFamily.begin(),MonsterSpawnedFamily.end(),pMonsterSummonListZone->byFamily) == MonsterSpawnedFamily.end())
|
||
{
|
||
g_pMain->SpawnEventNpc(pMonsterSummonListZone->sSid, true,GetZoneID(), GetX(), GetY(), GetZ(), 1, CHAOS_STONE_MONSTER_RESPAWN_RADIUS, CHAOS_STONE_MONSTER_LIVE_TIME);
|
||
MonsterSpawned.push_back(nMonsterNum);
|
||
MonsterSpawnedFamily.push_back(pMonsterSummonListZone->byFamily);
|
||
bLoopBack = false;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bLoopBack)
|
||
i--;
|
||
else
|
||
bLoopBack = true;
|
||
}
|
||
}
|
||
|
||
/*
|
||
* @brief Executes the pvp monument process.
|
||
*
|
||
* @param pUser The User.
|
||
*/
|
||
void CNpc::PVPMonumentProcess(CUser *pUser)
|
||
{
|
||
if (pUser == nullptr)
|
||
return;
|
||
|
||
std::string sKillMonuPvP;
|
||
std::string sKillMonuEvent;
|
||
std::string sMonuNation;
|
||
|
||
Packet result(WIZ_CHAT, uint8(MONUMENT_NOTICE));
|
||
result << uint8(FORCE_CHAT) << pUser->GetNation() << pUser->GetName().c_str();
|
||
g_pMain->Send_Zone(&result, GetZoneID(), nullptr, Nation::ALL);
|
||
|
||
if (pUser->GetNation() == KARUS)
|
||
sMonuNation = "Karus";
|
||
else
|
||
sMonuNation = "Human";
|
||
|
||
sKillMonuPvP = string_format("%s has destroyed the %s. %s nation get +5 NPs per kill!",pUser->GetName().c_str(),GetName().c_str(),sMonuNation.c_str());
|
||
sKillMonuEvent = string_format("%s has destroyed the %s. %s nation get +10 NPs per kill!",pUser->GetName().c_str(),GetName().c_str(),sMonuNation.c_str());
|
||
|
||
if (GetZoneID() == ZONE_RONARK_LAND)
|
||
{
|
||
g_pMain->m_nPVPMonumentNation[GetZoneID()] = pUser->GetNation();
|
||
g_pMain->SendAnnouncement(sKillMonuPvP.c_str());
|
||
}
|
||
else
|
||
{
|
||
g_pMain->m_nEventMonumentNation[GetZoneID()] = pUser->GetNation();
|
||
g_pMain->SendAnnouncement(sKillMonuEvent.c_str());
|
||
}
|
||
|
||
g_pMain->NpcUpdate(GetProtoID(), m_bMonster, pUser->GetNation(), pUser->GetNation() == KARUS ? MONUMENT_KARUS_SPID : MONUMENT_ELMORAD_SPID);
|
||
pUser->GiveItem(BLUE_TREASURE_CHEST,1);
|
||
}
|
||
|
||
/*
|
||
* @brief Executes the battle monument process.
|
||
*
|
||
* @param pUser The User.
|
||
*/
|
||
void CNpc::BattleMonumentProcess(CUser *pUser)
|
||
{
|
||
if (pUser && g_pMain->m_byBattleOpen == NATION_BATTLE)
|
||
{
|
||
g_pMain->NpcUpdate(GetProtoID(), m_bMonster, pUser->GetNation(), pUser->GetNation() == KARUS ? MONUMENT_KARUS_SPID : MONUMENT_ELMORAD_SPID);
|
||
g_pMain->Announcement(DECLARE_BATTLE_MONUMENT_STATUS, Nation::ALL, m_byTrapNumber, pUser);
|
||
|
||
if (pUser->GetNation() == KARUS)
|
||
{
|
||
g_pMain->m_sKarusMonumentPoint +=2;
|
||
g_pMain->m_sKarusMonuments++;
|
||
|
||
if (g_pMain->m_sElmoMonuments != 0)
|
||
g_pMain->m_sElmoMonuments--;
|
||
|
||
if (g_pMain->m_sKarusMonuments >= 7){
|
||
g_pMain->m_sKarusMonumentPoint +=10;
|
||
Packet result(WIZ_MAP_EVENT);
|
||
result << uint8(3) << uint8(1) << short(15);
|
||
g_pMain->Send_Zone(&result,ZONE_BATTLE4);
|
||
}
|
||
|
||
if (g_pMain->m_sKilledElmoNpc == 3 && g_pMain->m_sKarusMonuments >= 7)
|
||
g_pMain->BattleZoneResult(pUser->GetNation());
|
||
|
||
}
|
||
else
|
||
{
|
||
g_pMain->m_sElmoMonumentPoint += 2;
|
||
g_pMain->m_sElmoMonuments++;
|
||
|
||
if (g_pMain->m_sKarusMonuments != 0)
|
||
g_pMain->m_sKarusMonuments--;
|
||
|
||
if (g_pMain->m_sElmoMonuments >= 7){
|
||
g_pMain->m_sElmoMonumentPoint +=10;
|
||
Packet result(WIZ_MAP_EVENT);
|
||
result << uint8(3) << uint8(2) << short(15);
|
||
g_pMain->Send_Zone(&result,ZONE_BATTLE4);
|
||
}
|
||
|
||
if (g_pMain->m_sKilledKarusNpc == 3 && g_pMain->m_sElmoMonuments >= 7)
|
||
g_pMain->BattleZoneResult(pUser->GetNation());
|
||
}
|
||
|
||
g_pMain->NereidsMonumentEvent(m_byTrapNumber,pUser->GetNation(),nullptr);
|
||
|
||
}
|
||
}
|
||
|
||
/*
|
||
* @brief Executes the nation monument process.
|
||
*
|
||
* @param pUser The User.
|
||
*/
|
||
void CNpc::NationMonumentProcess(CUser *pUser)
|
||
{
|
||
if (!pUser)
|
||
return;
|
||
|
||
if (g_pMain->m_byBattleOpen == NATION_BATTLE)
|
||
{
|
||
g_pMain->NpcUpdate(GetProtoID(), m_bMonster, pUser->GetNation());
|
||
g_pMain->Announcement(DECLARE_NATION_MONUMENT_STATUS, Nation::ALL, GetProtoID(), pUser);
|
||
|
||
uint16 sSid = 0;
|
||
|
||
foreach_stlmap (itr, g_pMain->m_NationMonumentInformationArray)
|
||
if (itr->second->sSid == (pUser->GetNation() == KARUS ? GetProtoID() + 10000 : GetProtoID() - 10000))
|
||
sSid = itr->second->sSid;
|
||
|
||
if (sSid != 0)
|
||
g_pMain->m_NationMonumentInformationArray.DeleteData(sSid);
|
||
}
|
||
else
|
||
{
|
||
g_pMain->NpcUpdate(GetProtoID(), m_bMonster, pUser->GetNation());
|
||
|
||
uint16 sSid = 0;
|
||
|
||
foreach_stlmap (itr, g_pMain->m_NationMonumentInformationArray)
|
||
if (itr->second->sSid == (pUser->GetNation() == KARUS ? GetProtoID() + 10000 : GetProtoID() - 10000))
|
||
sSid = itr->second->sSid;
|
||
|
||
if (sSid != 0)
|
||
g_pMain->m_NationMonumentInformationArray.DeleteData(sSid);
|
||
}
|
||
}
|
||
|
||
/*
|
||
* @brief Executes the Cz monument process.
|
||
*
|
||
* @param pUser The User.
|
||
*/
|
||
void CNpc::CZMonumentProcess(CUser *pUser)
|
||
{
|
||
if (pUser == nullptr)
|
||
return;
|
||
|
||
std::string sKillMonu;
|
||
std::string sRecoMonu;
|
||
|
||
sKillMonu = string_format("%s has destroyed the %s at Ronark Land!",pUser->GetName().c_str(),GetName().c_str());
|
||
sRecoMonu = string_format("%s has recovered the %s at Ronark Land!",pUser->GetName().c_str(),GetName().c_str());
|
||
|
||
g_pMain->NpcUpdate(GetProtoID(), m_bMonster, pUser->GetNation());
|
||
|
||
if (pUser->GetNation() == KARUS)
|
||
{
|
||
if (GetSpid() == 30092)
|
||
{
|
||
g_pMain->SendAnnouncement(sKillMonu.c_str());
|
||
pUser->GiveItem(BLUE_TREASURE_CHEST,1);
|
||
pUser->SendLoyaltyChange(150);
|
||
}
|
||
else
|
||
{
|
||
g_pMain->SendAnnouncement(sRecoMonu.c_str());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (GetSpid() == 30091)
|
||
{
|
||
g_pMain->SendAnnouncement(sKillMonu.c_str());
|
||
pUser->GiveItem(BLUE_TREASURE_CHEST,1);
|
||
pUser->SendLoyaltyChange(150);
|
||
}
|
||
else
|
||
{
|
||
g_pMain->SendAnnouncement(sRecoMonu.c_str());
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void CNpc::HPTimeChangeType3()
|
||
{
|
||
if (isDead()
|
||
|| !m_bType3Flag || isPlayer())
|
||
return;
|
||
|
||
uint16 totalActiveDurationalSkills = 0,
|
||
totalActiveDOTSkills = 0;
|
||
|
||
bool bIsDOT = false;
|
||
for (int i = 0; i < MAX_TYPE3_REPEAT; i++)
|
||
{
|
||
MagicType3 * pEffect = &m_durationalSkills[i];
|
||
if (!pEffect->m_byUsed)
|
||
continue;
|
||
|
||
// Has the required interval elapsed before using this skill?
|
||
if ((UNIXTIME - pEffect->m_tHPLastTime) >= pEffect->m_bHPInterval)
|
||
{
|
||
Unit * pUnit = g_pMain->GetUnitPtr(pEffect->m_sSourceID);
|
||
|
||
if (pUnit == nullptr)
|
||
continue;
|
||
|
||
if (!isInRangeSlow(pUnit, 50.0f))
|
||
m_bType3Flag = false;
|
||
|
||
// Reduce the HP
|
||
HpChange(pEffect->m_sHPAmount, pUnit); // do we need to specify the source of the DOT?
|
||
pEffect->m_tHPLastTime = UNIXTIME;
|
||
|
||
if (pEffect->m_sHPAmount < 0)
|
||
bIsDOT = true;
|
||
|
||
// Has the skill expired yet?
|
||
if (++pEffect->m_bTickCount == pEffect->m_bTickLimit)
|
||
{
|
||
Packet result(WIZ_MAGIC_PROCESS, uint8(MAGIC_DURATION_EXPIRED));
|
||
|
||
// Healing-over-time skills require the type 100
|
||
if (pEffect->m_sHPAmount > 0)
|
||
result << uint8(100);
|
||
else // Damage-over-time requires 200.
|
||
result << uint8(200);
|
||
|
||
Send_AIServer(&result);
|
||
|
||
pEffect->Reset();
|
||
}
|
||
}
|
||
|
||
if (pEffect->m_byUsed)
|
||
{
|
||
totalActiveDurationalSkills++;
|
||
if (pEffect->m_sHPAmount < 0)
|
||
totalActiveDOTSkills++;
|
||
}
|
||
}
|
||
|
||
// Have all the skills expired?
|
||
if (totalActiveDurationalSkills == 0)
|
||
m_bType3Flag = false;
|
||
}
|
||
|
||
void CNpc::Type4Duration()
|
||
{
|
||
Guard lock(m_buffLock);
|
||
if (m_buffMap.empty())
|
||
return;
|
||
|
||
foreach (itr, m_buffMap)
|
||
{
|
||
if (itr->second.m_tEndTime > UNIXTIME)
|
||
continue;
|
||
|
||
CMagicProcess::RemoveType4Buff(itr->first, this, true, false);
|
||
break; // only ever handle one at a time with the current logic
|
||
}
|
||
}
|
||
|