forked from metin2/server
3649 lines
82 KiB
C++
3649 lines
82 KiB
C++
#include "stdafx.h"
|
||
#include "utils.h"
|
||
#include "config.h"
|
||
#include "desc.h"
|
||
#include "desc_manager.h"
|
||
#include "char_manager.h"
|
||
#include "item.h"
|
||
#include "item_manager.h"
|
||
#include "mob_manager.h"
|
||
#include "battle.h"
|
||
#include "pvp.h"
|
||
#include "skill.h"
|
||
#include "start_position.h"
|
||
#include "profiler.h"
|
||
#include "cmd.h"
|
||
#include "dungeon.h"
|
||
#include "log.h"
|
||
#include "unique_item.h"
|
||
#include "priv_manager.h"
|
||
#include "db.h"
|
||
#include "vector.h"
|
||
#include "marriage.h"
|
||
#include "arena.h"
|
||
#include "regen.h"
|
||
#include "monarch.h"
|
||
#include "exchange.h"
|
||
#include "shop_manager.h"
|
||
#include "castle.h"
|
||
#include "dev_log.h"
|
||
#include "ani.h"
|
||
#include "BattleArena.h"
|
||
#include "packet.h"
|
||
#include "party.h"
|
||
#include "affect.h"
|
||
#include "guild.h"
|
||
#include "guild_manager.h"
|
||
#include "questmanager.h"
|
||
#include "questlua.h"
|
||
#include "threeway_war.h"
|
||
#include "BlueDragon.h"
|
||
#include "DragonLair.h"
|
||
|
||
DWORD AdjustExpByLevel(const LPCHARACTER ch, const DWORD exp)
|
||
{
|
||
if (PLAYER_EXP_TABLE_MAX < ch->GetLevel())
|
||
{
|
||
double ret = 0.95;
|
||
double factor = 0.1;
|
||
|
||
for (ssize_t i=0 ; i < ch->GetLevel()-100 ; ++i)
|
||
{
|
||
if ( (i%10) == 0)
|
||
factor /= 2.0;
|
||
|
||
ret *= 1.0 - factor;
|
||
}
|
||
|
||
ret = ret * static_cast<double>(exp);
|
||
|
||
if (ret < 1.0)
|
||
return 1;
|
||
|
||
return static_cast<DWORD>(ret);
|
||
}
|
||
|
||
return exp;
|
||
}
|
||
|
||
bool CHARACTER::CanBeginFight() const
|
||
{
|
||
if (!CanMove())
|
||
return false;
|
||
|
||
return m_pointsInstant.position == POS_STANDING && !IsDead() && !IsStun();
|
||
}
|
||
|
||
void CHARACTER::BeginFight(LPCHARACTER pkVictim)
|
||
{
|
||
SetVictim(pkVictim);
|
||
SetPosition(POS_FIGHTING);
|
||
SetNextStatePulse(1);
|
||
}
|
||
|
||
bool CHARACTER::CanFight() const
|
||
{
|
||
return m_pointsInstant.position >= POS_FIGHTING ? true : false;
|
||
}
|
||
|
||
void CHARACTER::CreateFly(BYTE bType, LPCHARACTER pkVictim)
|
||
{
|
||
TPacketGCCreateFly packFly;
|
||
|
||
packFly.bHeader = HEADER_GC_CREATE_FLY;
|
||
packFly.bType = bType;
|
||
packFly.dwStartVID = GetVID();
|
||
packFly.dwEndVID = pkVictim->GetVID();
|
||
|
||
PacketAround(&packFly, sizeof(TPacketGCCreateFly));
|
||
}
|
||
|
||
void CHARACTER::DistributeSP(LPCHARACTER pkKiller, int iMethod)
|
||
{
|
||
if (pkKiller->GetSP() >= pkKiller->GetMaxSP())
|
||
return;
|
||
|
||
bool bAttacking = (get_dword_time() - GetLastAttackTime()) < 3000;
|
||
bool bMoving = (get_dword_time() - GetLastMoveTime()) < 3000;
|
||
|
||
if (iMethod == 1)
|
||
{
|
||
int num = number(0, 3);
|
||
|
||
if (!num)
|
||
{
|
||
int iLvDelta = GetLevel() - pkKiller->GetLevel();
|
||
int iAmount = 0;
|
||
|
||
if (iLvDelta >= 5)
|
||
iAmount = 10;
|
||
else if (iLvDelta >= 0)
|
||
iAmount = 6;
|
||
else if (iLvDelta >= -3)
|
||
iAmount = 2;
|
||
|
||
if (iAmount != 0)
|
||
{
|
||
iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
|
||
|
||
if (iAmount >= 11)
|
||
CreateFly(FLY_SP_BIG, pkKiller);
|
||
else if (iAmount >= 7)
|
||
CreateFly(FLY_SP_MEDIUM, pkKiller);
|
||
else
|
||
CreateFly(FLY_SP_SMALL, pkKiller);
|
||
|
||
pkKiller->PointChange(POINT_SP, iAmount);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (pkKiller->GetJob() == JOB_SHAMAN || (pkKiller->GetJob() == JOB_SURA && pkKiller->GetSkillGroup() == 2))
|
||
{
|
||
int iAmount;
|
||
|
||
if (bAttacking)
|
||
iAmount = 2 + GetMaxSP() / 100;
|
||
else if (bMoving)
|
||
iAmount = 3 + GetMaxSP() * 2 / 100;
|
||
else
|
||
iAmount = 10 + GetMaxSP() * 3 / 100; // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
|
||
iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
|
||
pkKiller->PointChange(POINT_SP, iAmount);
|
||
}
|
||
else
|
||
{
|
||
int iAmount;
|
||
|
||
if (bAttacking)
|
||
iAmount = 2 + pkKiller->GetMaxSP() / 200;
|
||
else if (bMoving)
|
||
iAmount = 2 + pkKiller->GetMaxSP() / 100;
|
||
else
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (pkKiller->GetHP() < pkKiller->GetMaxHP())
|
||
iAmount = 2 + (pkKiller->GetMaxSP() / 100); // <20><> <20><> <20><>á<EFBFBD><C3A1><EFBFBD><EFBFBD>
|
||
else
|
||
iAmount = 9 + (pkKiller->GetMaxSP() / 100); // <20>⺻
|
||
}
|
||
|
||
iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
|
||
pkKiller->PointChange(POINT_SP, iAmount);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
bool CHARACTER::Attack(LPCHARACTER pkVictim, BYTE bType)
|
||
{
|
||
if (test_server)
|
||
sys_log(0, "[TEST_SERVER] Attack : %s type %d, MobBattleType %d", GetName(), bType, !GetMobBattleType() ? 0 : GetMobAttackRange());
|
||
//PROF_UNIT puAttack("Attack");
|
||
if (!CanMove())
|
||
return false;
|
||
|
||
// CASTLE
|
||
if (IS_CASTLE_MAP(GetMapIndex()) && false == castle_can_attack(this, pkVictim))
|
||
return false;
|
||
// CASTLE
|
||
|
||
DWORD dwCurrentTime = get_dword_time();
|
||
|
||
if (IsPC())
|
||
{
|
||
if (IS_SPEED_HACK(this, pkVictim, dwCurrentTime))
|
||
return false;
|
||
|
||
if (bType == 0 && dwCurrentTime < GetSkipComboAttackByTime())
|
||
return false;
|
||
}
|
||
else
|
||
{
|
||
MonsterChat(MONSTER_CHAT_ATTACK);
|
||
}
|
||
|
||
pkVictim->SetSyncOwner(this);
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(this);
|
||
|
||
int iRet;
|
||
|
||
if (bType == 0)
|
||
{
|
||
//
|
||
// <20>Ϲ<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
//
|
||
switch (GetMobBattleType())
|
||
{
|
||
case BATTLE_TYPE_MELEE:
|
||
case BATTLE_TYPE_POWER:
|
||
case BATTLE_TYPE_TANKER:
|
||
case BATTLE_TYPE_SUPER_POWER:
|
||
case BATTLE_TYPE_SUPER_TANKER:
|
||
iRet = battle_melee_attack(this, pkVictim);
|
||
break;
|
||
|
||
case BATTLE_TYPE_RANGE:
|
||
FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
|
||
iRet = Shoot(0) ? BATTLE_DAMAGE : BATTLE_NONE;
|
||
break;
|
||
|
||
case BATTLE_TYPE_MAGIC:
|
||
FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
|
||
iRet = Shoot(1) ? BATTLE_DAMAGE : BATTLE_NONE;
|
||
break;
|
||
|
||
default:
|
||
sys_err("Unhandled battle type %d", GetMobBattleType());
|
||
iRet = BATTLE_NONE;
|
||
break;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (IsPC() == true)
|
||
{
|
||
if (dwCurrentTime - m_dwLastSkillTime > 1500)
|
||
{
|
||
sys_log(1, "HACK: Too long skill using term. Name(%s) PID(%u) delta(%u)",
|
||
GetName(), GetPlayerID(), (dwCurrentTime - m_dwLastSkillTime));
|
||
return false;
|
||
}
|
||
}
|
||
|
||
sys_log(1, "Attack call ComputeSkill %d %s", bType, pkVictim?pkVictim->GetName():"");
|
||
iRet = ComputeSkill(bType, pkVictim);
|
||
}
|
||
|
||
//if (test_server && IsPC())
|
||
// sys_log(0, "%s Attack %s type %u ret %d", GetName(), pkVictim->GetName(), bType, iRet);
|
||
if (iRet == BATTLE_DAMAGE || iRet == BATTLE_DEAD)
|
||
{
|
||
OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
// only pc sets victim null. For npc, state machine will reset this.
|
||
if (BATTLE_DEAD == iRet && IsPC())
|
||
SetVictim(NULL);
|
||
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void CHARACTER::DeathPenalty(BYTE bTown)
|
||
{
|
||
sys_log(1, "DEATH_PERNALY_CHECK(%s) town(%d)", GetName(), bTown);
|
||
|
||
Cube_close(this);
|
||
|
||
if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
|
||
{
|
||
return;
|
||
}
|
||
|
||
if (GetLevel() < 10)
|
||
{
|
||
sys_log(0, "NO_DEATH_PENALTY_LESS_LV10(%s)", GetName());
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȣ<EFBFBD><C8A3> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>."));
|
||
return;
|
||
}
|
||
|
||
if (number(0, 2))
|
||
{
|
||
sys_log(0, "NO_DEATH_PENALTY_LUCK(%s)", GetName());
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȣ<EFBFBD><C8A3> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>."));
|
||
return;
|
||
}
|
||
|
||
if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY))
|
||
{
|
||
REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
|
||
|
||
// NO_DEATH_PENALTY_BUG_FIX
|
||
if (LC_IsYMIR()) // õ<><C3B5> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȣ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> üũ<C3BC>Ѵ<EFBFBD>.
|
||
{
|
||
if (FindAffect(AFFECT_NO_DEATH_PENALTY))
|
||
{
|
||
sys_log(0, "NO_DEATH_PENALTY_AFFECT(%s)", GetName());
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȣ<EFBFBD><C8A3> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>."));
|
||
RemoveAffect(AFFECT_NO_DEATH_PENALTY);
|
||
return;
|
||
}
|
||
}
|
||
else if (!bTown) // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ڸ<EFBFBD> <20><>Ȱ<EFBFBD>ø<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȣ<EFBFBD><C8A3> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>. (<28><><EFBFBD><EFBFBD> <20><><EFBFBD>ͽô<CDBD> <20><><EFBFBD><EFBFBD>ġ <20>г<EFBFBD>Ƽ <20><><EFBFBD><EFBFBD>)
|
||
{
|
||
if (FindAffect(AFFECT_NO_DEATH_PENALTY))
|
||
{
|
||
sys_log(0, "NO_DEATH_PENALTY_AFFECT(%s)", GetName());
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȣ<EFBFBD><C8A3> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>."));
|
||
RemoveAffect(AFFECT_NO_DEATH_PENALTY);
|
||
return;
|
||
}
|
||
}
|
||
// END_OF_NO_DEATH_PENALTY_BUG_FIX
|
||
|
||
int iLoss = ((GetNextExp() * aiExpLossPercents[MINMAX(1, GetLevel(), PLAYER_EXP_TABLE_MAX)]) / 100);
|
||
|
||
if (true == LC_IsYMIR())
|
||
{
|
||
if (PLAYER_EXP_TABLE_MAX < GetLevel())
|
||
{
|
||
iLoss = MIN(500000, iLoss);
|
||
}
|
||
else
|
||
{
|
||
iLoss = MIN(200000, iLoss);
|
||
}
|
||
}
|
||
else if (true == LC_IsEurope())
|
||
{
|
||
iLoss = MIN(800000, iLoss);
|
||
}
|
||
|
||
if (bTown)
|
||
{
|
||
if (g_iUseLocale)
|
||
{
|
||
iLoss = 0;
|
||
}
|
||
else
|
||
{
|
||
iLoss -= iLoss / 3;
|
||
}
|
||
}
|
||
|
||
if (IsEquipUniqueItem(UNIQUE_ITEM_TEARDROP_OF_GODNESS))
|
||
iLoss /= 2;
|
||
|
||
sys_log(0, "DEATH_PENALTY(%s) EXP_LOSS: %d percent %d%%", GetName(), iLoss, aiExpLossPercents[MIN(gPlayerMaxLevel, GetLevel())]);
|
||
|
||
PointChange(POINT_EXP, -iLoss, true);
|
||
}
|
||
}
|
||
|
||
bool CHARACTER::IsStun() const
|
||
{
|
||
if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN))
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
EVENTFUNC(StunEvent)
|
||
{
|
||
char_event_info* info = dynamic_cast<char_event_info*>( event->info );
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "StunEvent> <Factor> Null pointer" );
|
||
return 0;
|
||
}
|
||
|
||
LPCHARACTER ch = info->ch;
|
||
|
||
if (ch == NULL) { // <Factor>
|
||
return 0;
|
||
}
|
||
ch->m_pkStunEvent = NULL;
|
||
ch->Dead();
|
||
return 0;
|
||
}
|
||
|
||
void CHARACTER::Stun()
|
||
{
|
||
if (IsStun())
|
||
return;
|
||
|
||
if (IsDead())
|
||
return;
|
||
|
||
if (!IsPC() && m_pkParty)
|
||
{
|
||
m_pkParty->SendMessage(this, PM_ATTACKED_BY, 0, 0);
|
||
}
|
||
|
||
sys_log(1, "%s: Stun %p", GetName(), this);
|
||
|
||
PointChange(POINT_HP_RECOVERY, -GetPoint(POINT_HP_RECOVERY));
|
||
PointChange(POINT_SP_RECOVERY, -GetPoint(POINT_SP_RECOVERY));
|
||
|
||
CloseMyShop();
|
||
|
||
event_cancel(&m_pkRecoveryEvent); // ȸ<><C8B8> <20>̺<EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD>δ<EFBFBD>.
|
||
|
||
TPacketGCStun pack;
|
||
pack.header = HEADER_GC_STUN;
|
||
pack.vid = m_vid;
|
||
PacketAround(&pack, sizeof(pack));
|
||
|
||
SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
|
||
|
||
if (m_pkStunEvent)
|
||
return;
|
||
|
||
char_event_info* info = AllocEventInfo<char_event_info>();
|
||
|
||
info->ch = this;
|
||
|
||
m_pkStunEvent = event_create(StunEvent, info, PASSES_PER_SEC(3));
|
||
}
|
||
|
||
EVENTINFO(SCharDeadEventInfo)
|
||
{
|
||
bool isPC;
|
||
uint32_t dwID;
|
||
|
||
SCharDeadEventInfo()
|
||
: isPC(0)
|
||
, dwID(0)
|
||
{
|
||
}
|
||
};
|
||
|
||
EVENTFUNC(dead_event)
|
||
{
|
||
const SCharDeadEventInfo* info = dynamic_cast<SCharDeadEventInfo*>(event->info);
|
||
|
||
if ( info == NULL )
|
||
{
|
||
sys_err( "dead_event> <Factor> Null pointer" );
|
||
return 0;
|
||
}
|
||
|
||
LPCHARACTER ch = NULL;
|
||
|
||
if (true == info->isPC)
|
||
{
|
||
ch = CHARACTER_MANAGER::instance().FindByPID( info->dwID );
|
||
}
|
||
else
|
||
{
|
||
ch = CHARACTER_MANAGER::instance().Find( info->dwID );
|
||
}
|
||
|
||
if (NULL == ch)
|
||
{
|
||
sys_err("DEAD_EVENT: cannot find char pointer with %s id(%d)", info->isPC ? "PC" : "MOB", info->dwID );
|
||
return 0;
|
||
}
|
||
|
||
ch->m_pkDeadEvent = NULL;
|
||
|
||
if (ch->GetDesc())
|
||
{
|
||
ch->GetDesc()->SetPhase(PHASE_GAME);
|
||
|
||
ch->SetPosition(POS_STANDING);
|
||
|
||
PIXEL_POSITION pos;
|
||
|
||
if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
|
||
ch->WarpSet(pos.x, pos.y);
|
||
else
|
||
{
|
||
sys_err("cannot find spawn position (name %s)", ch->GetName());
|
||
ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
|
||
}
|
||
|
||
ch->PointChange(POINT_HP, (ch->GetMaxHP() / 2) - ch->GetHP(), true);
|
||
|
||
ch->DeathPenalty(0);
|
||
|
||
ch->StartRecoveryEvent();
|
||
|
||
ch->ChatPacket(CHAT_TYPE_COMMAND, "CloseRestartWindow");
|
||
}
|
||
else
|
||
{
|
||
if (ch->IsMonster() == true)
|
||
{
|
||
if (ch->IsRevive() == false && ch->HasReviverInParty() == true)
|
||
{
|
||
ch->SetPosition(POS_STANDING);
|
||
ch->SetHP(ch->GetMaxHP());
|
||
|
||
ch->ViewReencode();
|
||
|
||
ch->SetAggressive();
|
||
ch->SetRevive(true);
|
||
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
M2_DESTROY_CHARACTER(ch);
|
||
}
|
||
|
||
return 0;
|
||
}
|
||
|
||
bool CHARACTER::IsDead() const
|
||
{
|
||
if (m_pointsInstant.position == POS_DEAD)
|
||
return true;
|
||
|
||
return false;
|
||
}
|
||
|
||
#define GetGoldMultipler() (distribution_test_server ? 3 : 1)
|
||
|
||
void CHARACTER::RewardGold(LPCHARACTER pkAttacker)
|
||
{
|
||
// ADD_PREMIUM
|
||
bool isAutoLoot =
|
||
(pkAttacker->GetPremiumRemainSeconds(PREMIUM_AUTOLOOT) > 0 ||
|
||
pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_AUTOLOOT))
|
||
? true : false; // <20><>3<EFBFBD><33> <20><>
|
||
// END_OF_ADD_PREMIUM
|
||
|
||
PIXEL_POSITION pos;
|
||
|
||
if (!isAutoLoot)
|
||
if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
|
||
return;
|
||
|
||
int iTotalGold = 0;
|
||
//
|
||
// --------- <20><> <20><><EFBFBD><EFBFBD> Ȯ<><C8AE> <20><><EFBFBD><EFBFBD> ----------
|
||
//
|
||
int iGoldPercent = MobRankStats[GetMobRank()].iGoldPercent;
|
||
|
||
if (pkAttacker->IsPC())
|
||
iGoldPercent = iGoldPercent * (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD_DROP)) / 100;
|
||
|
||
if (pkAttacker->GetPoint(POINT_MALL_GOLDBONUS))
|
||
iGoldPercent += (iGoldPercent * pkAttacker->GetPoint(POINT_MALL_GOLDBONUS) / 100);
|
||
|
||
iGoldPercent = iGoldPercent * CHARACTER_MANAGER::instance().GetMobGoldDropRate(pkAttacker) / 100;
|
||
|
||
// ADD_PREMIUM
|
||
if (pkAttacker->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0 ||
|
||
pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_LUCKY_GOLD))
|
||
iGoldPercent += iGoldPercent;
|
||
// END_OF_ADD_PREMIUM
|
||
|
||
if (iGoldPercent > 100)
|
||
iGoldPercent = 100;
|
||
|
||
int iPercent;
|
||
|
||
if (GetMobRank() >= MOB_RANK_BOSS)
|
||
iPercent = ((iGoldPercent * PERCENT_LVDELTA_BOSS(pkAttacker->GetLevel(), GetLevel())) / 100);
|
||
else
|
||
iPercent = ((iGoldPercent * PERCENT_LVDELTA(pkAttacker->GetLevel(), GetLevel())) / 100);
|
||
//int iPercent = CALCULATE_VALUE_LVDELTA(pkAttacker->GetLevel(), GetLevel(), iGoldPercent);
|
||
|
||
if (number(1, 100) > iPercent)
|
||
return;
|
||
|
||
int iGoldMultipler = GetGoldMultipler();
|
||
|
||
if (1 == number(1, 50000)) // 1/50000 Ȯ<><C8AE><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> 10<31><30>
|
||
iGoldMultipler *= 10;
|
||
else if (1 == number(1, 10000)) // 1/10000 Ȯ<><C8AE><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> 5<><35>
|
||
iGoldMultipler *= 5;
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if (pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
|
||
if (number(1, 100) <= pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
|
||
iGoldMultipler *= 2;
|
||
|
||
//
|
||
// --------- <20><> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ----------
|
||
//
|
||
if (test_server)
|
||
pkAttacker->ChatPacket(CHAT_TYPE_PARTY, "gold_mul %d rate %d", iGoldMultipler, CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker));
|
||
|
||
//
|
||
// --------- <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ó<><C3B3> -------------
|
||
//
|
||
LPITEM item;
|
||
|
||
int iGold10DropPct = 100;
|
||
iGold10DropPct = (iGold10DropPct * 100) / (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD10_DROP));
|
||
|
||
// MOB_RANK<4E><4B> BOSS<53><53><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ź
|
||
if (GetMobRank() >= MOB_RANK_BOSS && !IsStone() && GetMobTable().dwGoldMax != 0)
|
||
{
|
||
if (1 == number(1, iGold10DropPct))
|
||
iGoldMultipler *= 10; // 1% Ȯ<><C8AE><EFBFBD><EFBFBD> <20><> 10<31><30>
|
||
|
||
int iSplitCount = number(25, 35);
|
||
|
||
for (int i = 0; i < iSplitCount; ++i)
|
||
{
|
||
int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax) / iSplitCount;
|
||
if (test_server)
|
||
sys_log(0, "iGold %d", iGold);
|
||
iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
|
||
iGold *= iGoldMultipler;
|
||
|
||
if (iGold == 0)
|
||
{
|
||
continue ;
|
||
}
|
||
|
||
if (test_server)
|
||
{
|
||
sys_log(0, "Drop Moeny MobGoldAmountRate %d %d", CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker), iGoldMultipler);
|
||
sys_log(0, "Drop Money gold %d GoldMin %d GoldMax %d", iGold, GetMobTable().dwGoldMax, GetMobTable().dwGoldMax);
|
||
}
|
||
|
||
// NOTE: <20><> <20><>ź<EFBFBD><C5BA> <20><> 3<><33> <20><> ó<><C3B3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
|
||
{
|
||
pos.x = GetX() + ((number(-14, 14) + number(-14, 14)) * 23);
|
||
pos.y = GetY() + ((number(-14, 14) + number(-14, 14)) * 23);
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
item->StartDestroyEvent();
|
||
|
||
iTotalGold += iGold; // Total gold
|
||
}
|
||
}
|
||
}
|
||
// 1% Ȯ<><C8AE><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> 10<31><30> <20><><EFBFBD><EFBFBD> <20>߸<EFBFBD><DFB8><EFBFBD>. (10<31><30> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||
else if (1 == number(1, iGold10DropPct))
|
||
{
|
||
//
|
||
// <20><> <20><>ź<EFBFBD><C5BA> <20><><EFBFBD><EFBFBD>
|
||
//
|
||
for (int i = 0; i < 10; ++i)
|
||
{
|
||
int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
|
||
iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
|
||
iGold *= iGoldMultipler;
|
||
|
||
if (iGold == 0)
|
||
{
|
||
continue;
|
||
}
|
||
|
||
// NOTE: <20><> <20><>ź<EFBFBD><C5BA> <20><> 3<><33> <20><> ó<><C3B3><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
|
||
{
|
||
pos.x = GetX() + (number(-7, 7) * 20);
|
||
pos.y = GetY() + (number(-7, 7) * 20);
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
item->StartDestroyEvent();
|
||
|
||
iTotalGold += iGold; // Total gold
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// <20>Ϲ<EFBFBD><CFB9><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>
|
||
//
|
||
int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
|
||
iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
|
||
iGold *= iGoldMultipler;
|
||
|
||
int iSplitCount;
|
||
|
||
if (iGold >= 3 && !LC_IsYMIR())
|
||
iSplitCount = number(1, 3);
|
||
else if (GetMobRank() >= MOB_RANK_BOSS)
|
||
{
|
||
iSplitCount = number(3, 10);
|
||
|
||
if ((iGold / iSplitCount) == 0)
|
||
iSplitCount = 1;
|
||
}
|
||
else
|
||
iSplitCount = 1;
|
||
|
||
if (iGold != 0)
|
||
{
|
||
iTotalGold += iGold; // Total gold
|
||
|
||
for (int i = 0; i < iSplitCount; ++i)
|
||
{
|
||
if (isAutoLoot)
|
||
{
|
||
pkAttacker->GiveGold(iGold / iSplitCount);
|
||
}
|
||
else if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
|
||
{
|
||
pos.x = GetX() + (number(-7, 7) * 20);
|
||
pos.y = GetY() + (number(-7, 7) * 20);
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
item->StartDestroyEvent();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER, GetRaceNum(), iTotalGold);
|
||
}
|
||
|
||
void CHARACTER::Reward(bool bItemDrop)
|
||
{
|
||
if (GetRaceNum() == 5001) // <20>ֱ<EFBFBD><D6B1><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
{
|
||
PIXEL_POSITION pos;
|
||
|
||
if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
|
||
return;
|
||
|
||
LPITEM item;
|
||
int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
|
||
iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(NULL) / 100;
|
||
iGold *= GetGoldMultipler();
|
||
int iSplitCount = number(25, 35);
|
||
|
||
sys_log(0, "WAEGU Dead gold %d split %d", iGold, iSplitCount);
|
||
|
||
for (int i = 1; i <= iSplitCount; ++i)
|
||
{
|
||
if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
|
||
{
|
||
if (i != 0)
|
||
{
|
||
pos.x = number(-7, 7) * 20;
|
||
pos.y = number(-7, 7) * 20;
|
||
|
||
pos.x += GetX();
|
||
pos.y += GetY();
|
||
}
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
item->StartDestroyEvent();
|
||
}
|
||
}
|
||
return;
|
||
}
|
||
|
||
//PROF_UNIT puReward("Reward");
|
||
LPCHARACTER pkAttacker = DistributeExp();
|
||
|
||
if (!pkAttacker)
|
||
return;
|
||
|
||
//PROF_UNIT pu1("r1");
|
||
if (pkAttacker->IsPC())
|
||
{
|
||
if (GetLevel() - pkAttacker->GetLevel() >= -10)
|
||
if (pkAttacker->GetRealAlignment() < 0)
|
||
{
|
||
if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL))
|
||
pkAttacker->UpdateAlignment(14);
|
||
else
|
||
pkAttacker->UpdateAlignment(7);
|
||
}
|
||
else
|
||
pkAttacker->UpdateAlignment(2);
|
||
|
||
pkAttacker->SetQuestNPCID(GetVID());
|
||
quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum());
|
||
CHARACTER_MANAGER::instance().KillLog(GetRaceNum());
|
||
|
||
if (!number(0, 9))
|
||
{
|
||
if (pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY))
|
||
{
|
||
int iHP = pkAttacker->GetMaxHP() * pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY) / 100;
|
||
pkAttacker->PointChange(POINT_HP, iHP);
|
||
CreateFly(FLY_HP_SMALL, pkAttacker);
|
||
}
|
||
|
||
if (pkAttacker->GetPoint(POINT_KILL_SP_RECOVER))
|
||
{
|
||
int iSP = pkAttacker->GetMaxSP() * pkAttacker->GetPoint(POINT_KILL_SP_RECOVER) / 100;
|
||
pkAttacker->PointChange(POINT_SP, iSP);
|
||
CreateFly(FLY_SP_SMALL, pkAttacker);
|
||
}
|
||
}
|
||
}
|
||
//pu1.Pop();
|
||
|
||
if (!bItemDrop)
|
||
return;
|
||
|
||
PIXEL_POSITION pos = GetXYZ();
|
||
|
||
if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), pos.x, pos.y, pos))
|
||
return;
|
||
|
||
//
|
||
// <20><> <20><><EFBFBD><EFBFBD>
|
||
//
|
||
//PROF_UNIT pu2("r2");
|
||
if (test_server)
|
||
sys_log(0, "Drop money : Attacker %s", pkAttacker->GetName());
|
||
RewardGold(pkAttacker);
|
||
//pu2.Pop();
|
||
|
||
//
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
//
|
||
//PROF_UNIT pu3("r3");
|
||
LPITEM item;
|
||
|
||
static std::vector<LPITEM> s_vec_item;
|
||
s_vec_item.clear();
|
||
|
||
if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item))
|
||
{
|
||
if (s_vec_item.size() == 0);
|
||
else if (s_vec_item.size() == 1)
|
||
{
|
||
item = s_vec_item[0];
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
|
||
if (CBattleArena::instance().IsBattleArenaMap(pkAttacker->GetMapIndex()) == false)
|
||
{
|
||
item->SetOwnership(pkAttacker);
|
||
}
|
||
|
||
item->StartDestroyEvent();
|
||
|
||
pos.x = number(-7, 7) * 20;
|
||
pos.y = number(-7, 7) * 20;
|
||
pos.x += GetX();
|
||
pos.y += GetY();
|
||
|
||
sys_log(0, "DROP_ITEM: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
|
||
}
|
||
else
|
||
{
|
||
int iItemIdx = s_vec_item.size() - 1;
|
||
|
||
std::priority_queue<std::pair<int, LPCHARACTER> > pq;
|
||
|
||
int total_dam = 0;
|
||
|
||
for (TDamageMap::iterator it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
|
||
{
|
||
int iDamage = it->second.iTotalDamage;
|
||
if (iDamage > 0)
|
||
{
|
||
LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
|
||
|
||
if (ch)
|
||
{
|
||
pq.push(std::make_pair(iDamage, ch));
|
||
total_dam += iDamage;
|
||
}
|
||
}
|
||
}
|
||
|
||
std::vector<LPCHARACTER> v;
|
||
|
||
while (!pq.empty() && pq.top().first * 10 >= total_dam)
|
||
{
|
||
v.push_back(pq.top().second);
|
||
pq.pop();
|
||
}
|
||
|
||
if (v.empty())
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> Ư<><C6AF><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
while (iItemIdx >= 0)
|
||
{
|
||
item = s_vec_item[iItemIdx--];
|
||
|
||
if (!item)
|
||
{
|
||
sys_err("item null in vector idx %d", iItemIdx + 1);
|
||
continue;
|
||
}
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
// 10% <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ǿ<EFBFBD><C7BE><EFBFBD>
|
||
//item->SetOwnership(pkAttacker);
|
||
item->StartDestroyEvent();
|
||
|
||
pos.x = number(-7, 7) * 20;
|
||
pos.y = number(-7, 7) * 20;
|
||
pos.x += GetX();
|
||
pos.y += GetY();
|
||
|
||
sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
std::vector<LPCHARACTER>::iterator it = v.begin();
|
||
|
||
while (iItemIdx >= 0)
|
||
{
|
||
item = s_vec_item[iItemIdx--];
|
||
|
||
if (!item)
|
||
{
|
||
sys_err("item null in vector idx %d", iItemIdx + 1);
|
||
continue;
|
||
}
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
|
||
LPCHARACTER ch = *it;
|
||
|
||
if (ch->GetParty())
|
||
ch = ch->GetParty()->GetNextOwnership(ch, GetX(), GetY());
|
||
|
||
++it;
|
||
|
||
if (it == v.end())
|
||
it = v.begin();
|
||
|
||
if (CBattleArena::instance().IsBattleArenaMap(ch->GetMapIndex()) == false)
|
||
{
|
||
item->SetOwnership(ch);
|
||
}
|
||
|
||
item->StartDestroyEvent();
|
||
|
||
pos.x = number(-7, 7) * 20;
|
||
pos.y = number(-7, 7) * 20;
|
||
pos.x += GetX();
|
||
pos.y += GetY();
|
||
|
||
sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
m_map_kDamage.clear();
|
||
}
|
||
|
||
struct TItemDropPenalty
|
||
{
|
||
int iInventoryPct; // Range: 1 ~ 1000
|
||
int iInventoryQty; // Range: --
|
||
int iEquipmentPct; // Range: 1 ~ 100
|
||
int iEquipmentQty; // Range: --
|
||
};
|
||
|
||
TItemDropPenalty aItemDropPenalty_kor[9] =
|
||
{
|
||
{ 0, 0, 0, 0 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 0, 0, 0, 0 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 0, 0, 0, 0 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 0, 0, 0, 0 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 0, 0, 0, 0 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 25, 1, 5, 1 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 50, 2, 10, 1 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 75, 4, 15, 1 }, // <20><><EFBFBD><EFBFBD>
|
||
{ 100, 8, 20, 1 }, // <20>п<EFBFBD>
|
||
};
|
||
|
||
void CHARACTER::ItemDropPenalty(LPCHARACTER pkKiller)
|
||
{
|
||
// <20><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> <20><> <20><><EFBFBD>¿<EFBFBD><C2BF><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
||
if (GetMyShop())
|
||
return;
|
||
|
||
if (false == LC_IsYMIR())
|
||
{
|
||
if (GetLevel() < 50)
|
||
return;
|
||
}
|
||
|
||
if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
|
||
{
|
||
return;
|
||
}
|
||
|
||
struct TItemDropPenalty * table = &aItemDropPenalty_kor[0];
|
||
|
||
if (GetLevel() < 10)
|
||
return;
|
||
|
||
int iAlignIndex;
|
||
|
||
if (GetRealAlignment() >= 120000)
|
||
iAlignIndex = 0;
|
||
else if (GetRealAlignment() >= 80000)
|
||
iAlignIndex = 1;
|
||
else if (GetRealAlignment() >= 40000)
|
||
iAlignIndex = 2;
|
||
else if (GetRealAlignment() >= 10000)
|
||
iAlignIndex = 3;
|
||
else if (GetRealAlignment() >= 0)
|
||
iAlignIndex = 4;
|
||
else if (GetRealAlignment() > -40000)
|
||
iAlignIndex = 5;
|
||
else if (GetRealAlignment() > -80000)
|
||
iAlignIndex = 6;
|
||
else if (GetRealAlignment() > -120000)
|
||
iAlignIndex = 7;
|
||
else
|
||
iAlignIndex = 8;
|
||
|
||
std::vector<std::pair<LPITEM, int> > vec_item;
|
||
LPITEM pkItem;
|
||
int i;
|
||
bool isDropAllEquipments = false;
|
||
|
||
TItemDropPenalty & r = table[iAlignIndex];
|
||
sys_log(0, "%s align %d inven_pct %d equip_pct %d", GetName(), iAlignIndex, r.iInventoryPct, r.iEquipmentPct);
|
||
|
||
bool bDropInventory = r.iInventoryPct >= number(1, 1000);
|
||
bool bDropEquipment = r.iEquipmentPct >= number(1, 100);
|
||
bool bDropAntiDropUniqueItem = false;
|
||
|
||
if ((bDropInventory || bDropEquipment) && IsEquipUniqueItem(UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY))
|
||
{
|
||
bDropInventory = false;
|
||
bDropEquipment = false;
|
||
bDropAntiDropUniqueItem = true;
|
||
}
|
||
|
||
if (bDropInventory) // Drop Inventory
|
||
{
|
||
std::vector<BYTE> vec_bSlots;
|
||
|
||
for (i = 0; i < INVENTORY_MAX_NUM; ++i)
|
||
if (GetInventoryItem(i))
|
||
vec_bSlots.push_back(i);
|
||
|
||
if (!vec_bSlots.empty())
|
||
{
|
||
random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
|
||
|
||
int iQty = MIN(vec_bSlots.size(), r.iInventoryQty);
|
||
|
||
if (iQty)
|
||
iQty = number(1, iQty);
|
||
|
||
for (i = 0; i < iQty; ++i)
|
||
{
|
||
pkItem = GetInventoryItem(vec_bSlots[i]);
|
||
|
||
if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
|
||
continue;
|
||
|
||
SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 255);
|
||
vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), INVENTORY));
|
||
}
|
||
}
|
||
else if (iAlignIndex == 8)
|
||
isDropAllEquipments = true;
|
||
}
|
||
|
||
if (bDropEquipment) // Drop Equipment
|
||
{
|
||
std::vector<BYTE> vec_bSlots;
|
||
|
||
for (i = 0; i < WEAR_MAX_NUM; ++i)
|
||
if (GetWear(i))
|
||
vec_bSlots.push_back(i);
|
||
|
||
if (!vec_bSlots.empty())
|
||
{
|
||
random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
|
||
int iQty;
|
||
|
||
if (isDropAllEquipments)
|
||
iQty = vec_bSlots.size();
|
||
else
|
||
iQty = MIN(vec_bSlots.size(), number(1, r.iEquipmentQty));
|
||
|
||
if (iQty)
|
||
iQty = number(1, iQty);
|
||
|
||
for (i = 0; i < iQty; ++i)
|
||
{
|
||
pkItem = GetWear(vec_bSlots[i]);
|
||
|
||
if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
|
||
continue;
|
||
|
||
SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 255);
|
||
vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
|
||
}
|
||
}
|
||
}
|
||
|
||
if (bDropAntiDropUniqueItem)
|
||
{
|
||
LPITEM pkItem;
|
||
|
||
pkItem = GetWear(WEAR_UNIQUE1);
|
||
|
||
if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
|
||
{
|
||
SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE1, 255);
|
||
vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
|
||
}
|
||
|
||
pkItem = GetWear(WEAR_UNIQUE2);
|
||
|
||
if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
|
||
{
|
||
SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE2, 255);
|
||
vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
|
||
}
|
||
}
|
||
|
||
{
|
||
PIXEL_POSITION pos;
|
||
pos.x = GetX();
|
||
pos.y = GetY();
|
||
|
||
unsigned int i;
|
||
|
||
for (i = 0; i < vec_item.size(); ++i)
|
||
{
|
||
LPITEM item = vec_item[i].first;
|
||
int window = vec_item[i].second;
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
item->StartDestroyEvent();
|
||
|
||
sys_log(0, "DROP_ITEM_PK: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
|
||
LogManager::instance().ItemLog(this, item, "DEAD_DROP", (window == INVENTORY) ? "INVENTORY" : ((window == EQUIPMENT) ? "EQUIPMENT" : ""));
|
||
|
||
pos.x = GetX() + number(-7, 7) * 20;
|
||
pos.y = GetY() + number(-7, 7) * 20;
|
||
}
|
||
}
|
||
}
|
||
|
||
class FPartyAlignmentCompute
|
||
{
|
||
public:
|
||
FPartyAlignmentCompute(int iAmount, int x, int y)
|
||
{
|
||
m_iAmount = iAmount;
|
||
m_iCount = 0;
|
||
m_iStep = 0;
|
||
m_iKillerX = x;
|
||
m_iKillerY = y;
|
||
}
|
||
|
||
void operator () (LPCHARACTER pkChr)
|
||
{
|
||
if (DISTANCE_APPROX(pkChr->GetX() - m_iKillerX, pkChr->GetY() - m_iKillerY) < PARTY_DEFAULT_RANGE)
|
||
{
|
||
if (m_iStep == 0)
|
||
{
|
||
++m_iCount;
|
||
}
|
||
else
|
||
{
|
||
pkChr->UpdateAlignment(m_iAmount / m_iCount);
|
||
}
|
||
}
|
||
}
|
||
|
||
int m_iAmount;
|
||
int m_iCount;
|
||
int m_iStep;
|
||
|
||
int m_iKillerX;
|
||
int m_iKillerY;
|
||
};
|
||
|
||
|
||
|
||
void CHARACTER::Dead(LPCHARACTER pkKiller, bool bImmediateDead)
|
||
{
|
||
if (IsDead())
|
||
return;
|
||
|
||
{
|
||
if (IsHorseRiding())
|
||
{
|
||
StopRiding();
|
||
}
|
||
else if (GetMountVnum())
|
||
{
|
||
RemoveAffect(AFFECT_MOUNT_BONUS);
|
||
m_dwMountVnum = 0;
|
||
UnEquipSpecialRideUniqueItem();
|
||
|
||
UpdatePacket();
|
||
}
|
||
}
|
||
|
||
if (!pkKiller && m_dwKillerPID)
|
||
pkKiller = CHARACTER_MANAGER::instance().FindByPID(m_dwKillerPID);
|
||
|
||
m_dwKillerPID = 0; // <20>ݵ<EFBFBD><DDB5><EFBFBD> <20>ʱ<EFBFBD>ȭ <20>ؾ<EFBFBD><D8BE><EFBFBD> DO NOT DELETE THIS LINE UNLESS YOU ARE 1000000% SURE
|
||
|
||
bool isAgreedPVP = false;
|
||
bool isUnderGuildWar = false;
|
||
bool isDuel = false;
|
||
bool isForked = false;
|
||
|
||
if (pkKiller && pkKiller->IsPC())
|
||
{
|
||
if (pkKiller->m_pkChrTarget == this)
|
||
pkKiller->SetTarget(NULL);
|
||
|
||
if (!IsPC() && pkKiller->GetDungeon())
|
||
pkKiller->GetDungeon()->IncKillCount(pkKiller, this);
|
||
|
||
isAgreedPVP = CPVPManager::instance().Dead(this, pkKiller->GetPlayerID());
|
||
isDuel = CArenaManager::instance().OnDead(pkKiller, this);
|
||
|
||
if (IsPC())
|
||
{
|
||
CGuild * g1 = GetGuild();
|
||
CGuild * g2 = pkKiller->GetGuild();
|
||
|
||
if (g1 && g2)
|
||
if (g1->UnderWar(g2->GetID()))
|
||
isUnderGuildWar = true;
|
||
|
||
pkKiller->SetQuestNPCID(GetVID());
|
||
quest::CQuestManager::instance().Kill(pkKiller->GetPlayerID(), quest::QUEST_NO_NPC);
|
||
CGuildManager::instance().Kill(pkKiller, this);
|
||
}
|
||
}
|
||
|
||
//CHECK_FORKEDROAD_WAR
|
||
if (IsPC())
|
||
{
|
||
if (CThreeWayWar::instance().IsThreeWayWarMapIndex(GetMapIndex()))
|
||
isForked = true;
|
||
}
|
||
//END_CHECK_FORKEDROAD_WAR
|
||
|
||
if (pkKiller &&
|
||
!isAgreedPVP &&
|
||
!isUnderGuildWar &&
|
||
IsPC() &&
|
||
!isDuel &&
|
||
!isForked &&
|
||
!IS_CASTLE_MAP(GetMapIndex()))
|
||
{
|
||
if (GetGMLevel() == GM_PLAYER || test_server)
|
||
{
|
||
ItemDropPenalty(pkKiller);
|
||
}
|
||
}
|
||
|
||
// CASTLE_SIEGE
|
||
if (IS_CASTLE_MAP(GetMapIndex()))
|
||
{
|
||
if (CASTLE_FROG_VNUM == GetRaceNum())
|
||
castle_frog_die(this, pkKiller);
|
||
else if (castle_is_guard_vnum(GetRaceNum()))
|
||
castle_guard_die(this, pkKiller);
|
||
else if (castle_is_tower_vnum(GetRaceNum()))
|
||
castle_tower_die(this, pkKiller);
|
||
}
|
||
// CASTLE_SIEGE
|
||
|
||
if (true == isForked)
|
||
{
|
||
CThreeWayWar::instance().onDead( this, pkKiller );
|
||
}
|
||
|
||
SetPosition(POS_DEAD);
|
||
ClearAffect(true);
|
||
|
||
if (pkKiller && IsPC())
|
||
{
|
||
if (!pkKiller->IsPC())
|
||
{
|
||
if (!isForked)
|
||
{
|
||
sys_log(1, "DEAD: %s %p WITH PENALTY", GetName(), this);
|
||
SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
|
||
LogManager::instance().CharLog(this, pkKiller->GetRaceNum(), "DEAD_BY_NPC", pkKiller->GetName());
|
||
}
|
||
}
|
||
else
|
||
{
|
||
sys_log(1, "DEAD_BY_PC: %s %p KILLER %s %p", GetName(), this, pkKiller->GetName(), get_pointer(pkKiller));
|
||
REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
|
||
|
||
if (GetEmpire() != pkKiller->GetEmpire())
|
||
{
|
||
int iEP = MIN(GetPoint(POINT_EMPIRE_POINT), pkKiller->GetPoint(POINT_EMPIRE_POINT));
|
||
|
||
PointChange(POINT_EMPIRE_POINT, -(iEP / 10));
|
||
pkKiller->PointChange(POINT_EMPIRE_POINT, iEP / 5);
|
||
|
||
if (GetPoint(POINT_EMPIRE_POINT) < 10)
|
||
{
|
||
// TODO : <20>Ա<EFBFBD><D4B1><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ڵ带 <20>־<EFBFBD><D6BE><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
}
|
||
|
||
char buf[256];
|
||
snprintf(buf, sizeof(buf),
|
||
"%d %d %d %s %d %d %d %s",
|
||
GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
|
||
pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
|
||
|
||
LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
|
||
}
|
||
else
|
||
{
|
||
if (!isAgreedPVP && !isUnderGuildWar && !IsKillerMode() && GetAlignment() >= 0 && !isDuel && !isForked)
|
||
{
|
||
int iNoPenaltyProb = 0;
|
||
|
||
if (g_iUseLocale)
|
||
{
|
||
if (pkKiller->GetAlignment() >= 0) // 1/3 percent down
|
||
iNoPenaltyProb = 33;
|
||
else // 4/5 percent down
|
||
iNoPenaltyProb = 20;
|
||
}
|
||
|
||
if (number(1, 100) < iNoPenaltyProb)
|
||
pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ȣ<EFBFBD><C8A3> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ʾҽ<CABE><D2BD>ϴ<EFBFBD>."));
|
||
else
|
||
{
|
||
if (g_iUseLocale && pkKiller->GetParty())
|
||
{
|
||
FPartyAlignmentCompute f(-20000, pkKiller->GetX(), pkKiller->GetY());
|
||
pkKiller->GetParty()->ForEachOnlineMember(f);
|
||
|
||
if (f.m_iCount == 0)
|
||
pkKiller->UpdateAlignment(-20000);
|
||
else
|
||
{
|
||
sys_log(0, "ALIGNMENT PARTY count %d amount %d", f.m_iCount, f.m_iAmount);
|
||
|
||
f.m_iStep = 1;
|
||
pkKiller->GetParty()->ForEachOnlineMember(f);
|
||
}
|
||
}
|
||
else
|
||
pkKiller->UpdateAlignment(-20000);
|
||
}
|
||
}
|
||
|
||
char buf[256];
|
||
snprintf(buf, sizeof(buf),
|
||
"%d %d %d %s %d %d %d %s",
|
||
GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
|
||
pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
|
||
|
||
LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
|
||
}
|
||
}
|
||
}
|
||
else
|
||
{
|
||
sys_log(1, "DEAD: %s %p", GetName(), this);
|
||
REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
|
||
}
|
||
|
||
ClearSync();
|
||
|
||
//sys_log(1, "stun cancel %s[%d]", GetName(), (DWORD)GetVID());
|
||
event_cancel(&m_pkStunEvent); // <20><><EFBFBD><EFBFBD> <20>̺<EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD>δ<EFBFBD>.
|
||
|
||
if (IsPC())
|
||
{
|
||
m_dwLastDeadTime = get_dword_time();
|
||
SetKillerMode(false);
|
||
GetDesc()->SetPhase(PHASE_DEAD);
|
||
}
|
||
else
|
||
{
|
||
// <20><><EFBFBD>忡<EFBFBD><E5BFA1> <20><><EFBFBD>ݹ<EFBFBD><DDB9><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
if (!IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD))
|
||
{
|
||
if (!(pkKiller && pkKiller->IsPC() && pkKiller->GetGuild() && pkKiller->GetGuild()->UnderAnyWar(GUILD_WAR_TYPE_FIELD)))
|
||
{
|
||
// <20><>Ȱ<EFBFBD>ϴ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʴ´<CAB4>.
|
||
if (GetMobTable().dwResurrectionVnum)
|
||
{
|
||
// DUNGEON_MONSTER_REBIRTH_BUG_FIX
|
||
LPCHARACTER chResurrect = CHARACTER_MANAGER::instance().SpawnMob(GetMobTable().dwResurrectionVnum, GetMapIndex(), GetX(), GetY(), GetZ(), true, (int) GetRotation());
|
||
if (GetDungeon() && chResurrect)
|
||
{
|
||
chResurrect->SetDungeon(GetDungeon());
|
||
}
|
||
// END_OF_DUNGEON_MONSTER_REBIRTH_BUG_FIX
|
||
|
||
Reward(false);
|
||
}
|
||
else if (IsRevive() == true)
|
||
{
|
||
Reward(false);
|
||
}
|
||
else
|
||
{
|
||
Reward(true); // Drops gold, item, etc..
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (pkKiller->m_dwUnderGuildWarInfoMessageTime < get_dword_time())
|
||
{
|
||
pkKiller->m_dwUnderGuildWarInfoMessageTime = get_dword_time() + 60000;
|
||
pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<<3C><><EFBFBD><EFBFBD>> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>߿<EFBFBD><DFBF><EFBFBD> <20><><EFBFBD>ɿ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ<EFBFBD>."));
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// BOSS_KILL_LOG
|
||
if (GetMobRank() >= MOB_RANK_BOSS && pkKiller && pkKiller->IsPC())
|
||
{
|
||
char buf[51];
|
||
snprintf(buf, sizeof(buf), "%d %d", g_bChannel, pkKiller->GetMapIndex());
|
||
if (IsStone())
|
||
LogManager::instance().CharLog(pkKiller, GetRaceNum(), "STONE_KILL", buf);
|
||
else
|
||
LogManager::instance().CharLog(pkKiller, GetRaceNum(), "BOSS_KILL", buf);
|
||
}
|
||
// END_OF_BOSS_KILL_LOG
|
||
|
||
TPacketGCDead pack;
|
||
pack.header = HEADER_GC_DEAD;
|
||
pack.vid = m_vid;
|
||
PacketAround(&pack, sizeof(pack));
|
||
|
||
REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
|
||
|
||
// <20>÷<EFBFBD><C3B7>̾<EFBFBD> ij<><C4B3><EFBFBD><EFBFBD><EFBFBD≯<EFBFBD>
|
||
if (GetDesc() != NULL) {
|
||
//
|
||
// Ŭ<><C5AC><EFBFBD>̾<EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD>Ʈ <20><>Ŷ<EFBFBD><C5B6> <20>ٽ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
||
//
|
||
itertype(m_list_pkAffect) it = m_list_pkAffect.begin();
|
||
|
||
while (it != m_list_pkAffect.end())
|
||
SendAffectAddPacket(GetDesc(), *it++);
|
||
}
|
||
|
||
//
|
||
// Dead <20>̺<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD>,
|
||
//
|
||
// Dead <20>̺<EFBFBD>Ʈ<EFBFBD><C6AE><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>Ŀ<EFBFBD> Destroy <20>ǵ<EFBFBD><C7B5><EFBFBD> <20><><EFBFBD>ָ<EFBFBD>,
|
||
// PC<50><43> <20><><EFBFBD><EFBFBD> 3<><33> <20>ִٰ<D6B4> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20>ش<EFBFBD>. 3<><33> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>κ<EFBFBD><CEBA><EFBFBD>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>, <20><><EFBFBD>⼭ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>´<DEB4>.
|
||
if (isDuel == false)
|
||
{
|
||
if (m_pkDeadEvent)
|
||
{
|
||
sys_log(1, "DEAD_EVENT_CANCEL: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
|
||
event_cancel(&m_pkDeadEvent);
|
||
}
|
||
|
||
if (IsStone())
|
||
ClearStone();
|
||
|
||
if (GetDungeon())
|
||
{
|
||
GetDungeon()->DeadCharacter(this);
|
||
}
|
||
|
||
SCharDeadEventInfo* pEventInfo = AllocEventInfo<SCharDeadEventInfo>();
|
||
|
||
if (IsPC())
|
||
{
|
||
pEventInfo->isPC = true;
|
||
pEventInfo->dwID = this->GetPlayerID();
|
||
|
||
m_pkDeadEvent = event_create(dead_event, pEventInfo, PASSES_PER_SEC(180));
|
||
}
|
||
else
|
||
{
|
||
pEventInfo->isPC = false;
|
||
pEventInfo->dwID = this->GetVID();
|
||
|
||
if (IsRevive() == false && HasReviverInParty() == true)
|
||
{
|
||
m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(3));
|
||
}
|
||
else
|
||
{
|
||
m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(10));
|
||
}
|
||
}
|
||
|
||
sys_log(1, "DEAD_EVENT_CREATE: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
|
||
}
|
||
|
||
if (m_pkExchange != NULL)
|
||
{
|
||
m_pkExchange->Cancel();
|
||
}
|
||
|
||
if (IsCubeOpen() == true)
|
||
{
|
||
Cube_close(this);
|
||
}
|
||
|
||
CShopManager::instance().StopShopping(this);
|
||
CloseMyShop();
|
||
CloseSafebox();
|
||
|
||
if (true == IsMonster() && 2493 == GetMobTable().dwVnum)
|
||
{
|
||
if (NULL != pkKiller && NULL != pkKiller->GetGuild())
|
||
{
|
||
CDragonLairManager::instance().OnDragonDead( this, pkKiller->GetGuild()->GetID() );
|
||
}
|
||
else
|
||
{
|
||
sys_err("DragonLair: Dragon killed by nobody");
|
||
}
|
||
}
|
||
}
|
||
|
||
struct FuncSetLastAttacked
|
||
{
|
||
FuncSetLastAttacked(DWORD dwTime) : m_dwTime(dwTime)
|
||
{
|
||
}
|
||
|
||
void operator () (LPCHARACTER ch)
|
||
{
|
||
ch->SetLastAttacked(m_dwTime);
|
||
}
|
||
|
||
DWORD m_dwTime;
|
||
};
|
||
|
||
void CHARACTER::SetLastAttacked(DWORD dwTime)
|
||
{
|
||
assert(m_pkMobInst != NULL);
|
||
|
||
m_pkMobInst->m_dwLastAttackedTime = dwTime;
|
||
m_pkMobInst->m_posLastAttacked = GetXYZ();
|
||
}
|
||
|
||
void CHARACTER::SendDamagePacket(LPCHARACTER pAttacker, int Damage, BYTE DamageFlag)
|
||
{
|
||
if (IsPC() == true || (pAttacker->IsPC() == true && pAttacker->GetTarget() == this))
|
||
{
|
||
TPacketGCDamageInfo damageInfo;
|
||
memset(&damageInfo, 0, sizeof(TPacketGCDamageInfo));
|
||
|
||
damageInfo.header = HEADER_GC_DAMAGE_INFO;
|
||
damageInfo.dwVID = (DWORD)GetVID();
|
||
damageInfo.flag = DamageFlag;
|
||
damageInfo.damage = Damage;
|
||
|
||
if (GetDesc() != NULL)
|
||
{
|
||
GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
|
||
}
|
||
|
||
if (pAttacker->GetDesc() != NULL)
|
||
{
|
||
pAttacker->GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
|
||
}
|
||
/*
|
||
if (GetArenaObserverMode() == false && GetArena() != NULL)
|
||
{
|
||
GetArena()->SendPacketToObserver(&damageInfo, sizeof(TPacketGCDamageInfo));
|
||
}
|
||
*/
|
||
}
|
||
}
|
||
|
||
//
|
||
// CHARACTER::Damage <20>ҵ<DEBC><D2B5><EFBFBD> this<69><73> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
//
|
||
// Arguments
|
||
// pAttacker : <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
// dam : <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
// EDamageType : <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ΰ<EFBFBD>?
|
||
//
|
||
// Return value
|
||
// true : dead
|
||
// false : not dead yet
|
||
//
|
||
bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // returns true if dead
|
||
{
|
||
if (DAMAGE_TYPE_MAGIC == type)
|
||
{
|
||
dam = (int)((float)dam * (100 + (pAttacker->GetPoint(POINT_MAGIC_ATT_BONUS_PER) + pAttacker->GetPoint(POINT_MELEE_MAGIC_ATT_BONUS_PER))) / 100.f + 0.5f);
|
||
}
|
||
if (GetRaceNum() == 5001)
|
||
{
|
||
bool bDropMoney = false;
|
||
int iPercent = (GetHP() * 100) / GetMaxHP();
|
||
|
||
if (iPercent <= 10 && GetMaxSP() < 5)
|
||
{
|
||
SetMaxSP(5);
|
||
bDropMoney = true;
|
||
}
|
||
else if (iPercent <= 20 && GetMaxSP() < 4)
|
||
{
|
||
SetMaxSP(4);
|
||
bDropMoney = true;
|
||
}
|
||
else if (iPercent <= 40 && GetMaxSP() < 3)
|
||
{
|
||
SetMaxSP(3);
|
||
bDropMoney = true;
|
||
}
|
||
else if (iPercent <= 60 && GetMaxSP() < 2)
|
||
{
|
||
SetMaxSP(2);
|
||
bDropMoney = true;
|
||
}
|
||
else if (iPercent <= 80 && GetMaxSP() < 1)
|
||
{
|
||
SetMaxSP(1);
|
||
bDropMoney = true;
|
||
}
|
||
|
||
if (bDropMoney)
|
||
{
|
||
DWORD dwGold = 1000;
|
||
int iSplitCount = number(10, 13);
|
||
|
||
sys_log(0, "WAEGU DropGoldOnHit %d times", GetMaxSP());
|
||
|
||
for (int i = 1; i <= iSplitCount; ++i)
|
||
{
|
||
PIXEL_POSITION pos;
|
||
LPITEM item;
|
||
|
||
if ((item = ITEM_MANAGER::instance().CreateItem(1, dwGold / iSplitCount)))
|
||
{
|
||
if (i != 0)
|
||
{
|
||
pos.x = (number(-14, 14) + number(-14, 14)) * 20;
|
||
pos.y = (number(-14, 14) + number(-14, 14)) * 20;
|
||
|
||
pos.x += GetX();
|
||
pos.y += GetY();
|
||
}
|
||
|
||
item->AddToGround(GetMapIndex(), pos);
|
||
item->StartDestroyEvent();
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
// <20><>Ÿ<EFBFBD><C5B8> <20>ƴ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> ó<><C3B3>
|
||
if (type != DAMAGE_TYPE_NORMAL && type != DAMAGE_TYPE_NORMAL_RANGE)
|
||
{
|
||
if (IsAffectFlag(AFF_TERROR))
|
||
{
|
||
int pct = GetSkillPower(SKILL_TERROR) / 400;
|
||
|
||
if (number(1, 100) <= pct)
|
||
return false;
|
||
}
|
||
}
|
||
|
||
int iCurHP = GetHP();
|
||
int iCurSP = GetSP();
|
||
|
||
bool IsCritical = false;
|
||
bool IsPenetrate = false;
|
||
bool IsDeathBlow = false;
|
||
|
||
enum DamageFlag
|
||
{
|
||
DAMAGE_NORMAL = (1 << 0),
|
||
DAMAGE_POISON = (1 << 1),
|
||
DAMAGE_DODGE = (1 << 2),
|
||
DAMAGE_BLOCK = (1 << 3),
|
||
DAMAGE_PENETRATE= (1 << 4),
|
||
DAMAGE_CRITICAL = (1 << 5),
|
||
};
|
||
|
||
//PROF_UNIT puAttr("Attr");
|
||
|
||
//
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ų<EFBFBD><C5B3>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ų<EFBFBD><C5B3>(<28><><EFBFBD>ڰ<EFBFBD>) ũ<><C5A9>Ƽ<EFBFBD>ð<EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʾƾ<CABE> <20>ϴµ<CFB4> Nerf(<28>ٿ<EFBFBD><D9BF>뷱<EFBFBD><EBB7B1>)<29><>ġ<EFBFBD><C4A1> <20><> <20><> <20><><EFBFBD> ũ<><C5A9>Ƽ<EFBFBD>ð<EFBFBD>
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʰ<EFBFBD>, /2 <20>̻<EFBFBD><CCBB>Ͽ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
||
//
|
||
// <20><><EFBFBD><EFBFBD> <20>̾߱Ⱑ <20><><EFBFBD>Ƽ<EFBFBD> <20>и<EFBFBD> <20><>ų<EFBFBD><C5B3> <20>߰<EFBFBD>
|
||
//
|
||
// 20091109 : <20><><EFBFBD>簡 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>û<EFBFBD><C3BB><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>г<EFBFBD>, <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> 70% <20><><EFBFBD><EFBFBD>
|
||
//
|
||
if (type == DAMAGE_TYPE_MELEE || type == DAMAGE_TYPE_RANGE || type == DAMAGE_TYPE_MAGIC)
|
||
{
|
||
if (pAttacker)
|
||
{
|
||
// ũ<><C5A9>Ƽ<EFBFBD><C6BC>
|
||
int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
|
||
|
||
if (!IsPC())
|
||
iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
|
||
|
||
if (iCriticalPct)
|
||
{
|
||
if (iCriticalPct >= 10) // 10<31><30><EFBFBD><EFBFBD> ũ<><C5A9> 5% + (4<><34><EFBFBD><EFBFBD> 1%<25><> <20><><EFBFBD><EFBFBD>), <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ġ<EFBFBD><C4A1> 50<35≯<EFBFBD> 20%
|
||
iCriticalPct = 5 + (iCriticalPct - 10) / 4;
|
||
else // 10<31><30><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ܼ<EFBFBD><DCBC><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>, 10 = 5%
|
||
iCriticalPct /= 2;
|
||
|
||
//ũ<><C5A9>Ƽ<EFBFBD><C6BC> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>.
|
||
iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
|
||
|
||
if (number(1, 100) <= iCriticalPct)
|
||
{
|
||
IsCritical = true;
|
||
dam *= 2;
|
||
EffectPacket(SE_CRITICAL);
|
||
|
||
if (IsAffectFlag(AFF_MANASHIELD))
|
||
{
|
||
RemoveAffect(AFF_MANASHIELD);
|
||
}
|
||
}
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
|
||
|
||
if (!IsPC())
|
||
iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
|
||
|
||
|
||
if (iPenetratePct)
|
||
{
|
||
{
|
||
CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
|
||
|
||
if (NULL != pkSk)
|
||
{
|
||
pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
|
||
|
||
iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
|
||
}
|
||
}
|
||
|
||
if (iPenetratePct >= 10)
|
||
{
|
||
// 10<31><30><EFBFBD><EFBFBD> ũ<><C5A9> 5% + (4<><34><EFBFBD><EFBFBD> 1%<25><> <20><><EFBFBD><EFBFBD>), <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>ġ<EFBFBD><C4A1> 50<35≯<EFBFBD> 20%
|
||
iPenetratePct = 5 + (iPenetratePct - 10) / 4;
|
||
}
|
||
else
|
||
{
|
||
// 10<31><30><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ܼ<EFBFBD><DCBC><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>, 10 = 5%
|
||
iPenetratePct /= 2;
|
||
}
|
||
|
||
//<2F><><EFBFBD><EFBFBD>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>.
|
||
iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
|
||
|
||
if (number(1, 100) <= iPenetratePct)
|
||
{
|
||
IsPenetrate = true;
|
||
|
||
if (test_server)
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>߰<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
|
||
|
||
dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
|
||
|
||
if (IsAffectFlag(AFF_MANASHIELD))
|
||
{
|
||
RemoveAffect(AFF_MANASHIELD);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
//
|
||
// <20><EFBFBD> <20><><EFBFBD><EFBFBD>, Ȱ <20><><EFBFBD><EFBFBD>, <20><> <20><>Ÿ <20><> <20><><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD><D3BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
//
|
||
else if (type == DAMAGE_TYPE_NORMAL || type == DAMAGE_TYPE_NORMAL_RANGE)
|
||
{
|
||
if (type == DAMAGE_TYPE_NORMAL)
|
||
{
|
||
// <20><><EFBFBD><EFBFBD> <20><>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>
|
||
if (GetPoint(POINT_BLOCK) && number(1, 100) <= GetPoint(POINT_BLOCK))
|
||
{
|
||
if (test_server)
|
||
{
|
||
pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s <20><><EFBFBD><EFBFBD>! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s <20><><EFBFBD><EFBFBD>! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
|
||
}
|
||
|
||
SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK);
|
||
return false;
|
||
}
|
||
}
|
||
else if (type == DAMAGE_TYPE_NORMAL_RANGE)
|
||
{
|
||
// <20><><EFBFBD>Ÿ<EFBFBD> <20><>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>
|
||
if (GetPoint(POINT_DODGE) && number(1, 100) <= GetPoint(POINT_DODGE))
|
||
{
|
||
if (test_server)
|
||
{
|
||
pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ȸ<><C8B8>! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s ȸ<><C8B8>! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
|
||
}
|
||
|
||
SendDamagePacket(pAttacker, 0, DAMAGE_DODGE);
|
||
return false;
|
||
}
|
||
}
|
||
|
||
if (IsAffectFlag(AFF_JEONGWIHON))
|
||
dam = (int) (dam * (100 + GetSkillPower(SKILL_JEONGWI) * 25 / 100) / 100);
|
||
|
||
if (IsAffectFlag(AFF_TERROR))
|
||
dam = (int) (dam * (95 - GetSkillPower(SKILL_TERROR) / 5) / 100);
|
||
|
||
if (IsAffectFlag(AFF_HOSIN))
|
||
dam = dam * (100 - GetPoint(POINT_RESIST_NORMAL_DAMAGE)) / 100;
|
||
|
||
//
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>Ӽ<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
//
|
||
if (pAttacker)
|
||
{
|
||
if (type == DAMAGE_TYPE_NORMAL)
|
||
{
|
||
// <20>ݻ<EFBFBD>
|
||
if (GetPoint(POINT_REFLECT_MELEE))
|
||
{
|
||
int reflectDamage = dam * GetPoint(POINT_REFLECT_MELEE) / 100;
|
||
|
||
// NOTE: <20><><EFBFBD><EFBFBD><EFBFBD>ڰ<EFBFBD> IMMUNE_REFLECT <20>Ӽ<EFBFBD><D3BC><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ִٸ<D6B4> <20>ݻ縦 <20><> <20>ϴ<EFBFBD> <20><>
|
||
// <20>ƴ϶<C6B4> 1/3 <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD> <20><><EFBFBD><EFBFBD><EEB0A1><EFBFBD><EFBFBD> <20><>ȹ<EFBFBD><C8B9><EFBFBD><EFBFBD> <20><>û.
|
||
if (pAttacker->IsImmune(IMMUNE_REFLECT))
|
||
reflectDamage = int(reflectDamage / 3.0f + 0.5f);
|
||
|
||
pAttacker->Damage(this, reflectDamage, DAMAGE_TYPE_SPECIAL);
|
||
}
|
||
}
|
||
|
||
// ũ<><C5A9>Ƽ<EFBFBD><C6BC>
|
||
int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
|
||
|
||
if (!IsPC())
|
||
iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
|
||
|
||
if (iCriticalPct)
|
||
{
|
||
//ũ<><C5A9>Ƽ<EFBFBD><C6BC> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>.
|
||
iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
|
||
|
||
if (number(1, 100) <= iCriticalPct)
|
||
{
|
||
IsCritical = true;
|
||
dam *= 2;
|
||
EffectPacket(SE_CRITICAL);
|
||
}
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
|
||
|
||
if (!IsPC())
|
||
iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
|
||
|
||
{
|
||
CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
|
||
|
||
if (NULL != pkSk)
|
||
{
|
||
pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
|
||
|
||
iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
|
||
}
|
||
}
|
||
|
||
|
||
if (iPenetratePct)
|
||
{
|
||
|
||
//<2F><><EFBFBD><EFBFBD>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD>.
|
||
iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
|
||
|
||
if (number(1, 100) <= iPenetratePct)
|
||
{
|
||
IsPenetrate = true;
|
||
|
||
if (test_server)
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>߰<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
|
||
dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
|
||
}
|
||
}
|
||
|
||
// HP <20><>ƿ
|
||
if (pAttacker->GetPoint(POINT_STEAL_HP))
|
||
{
|
||
int pct = 1;
|
||
|
||
if (number(1, 10) <= pct)
|
||
{
|
||
int iHP = MIN(dam, MAX(0, iCurHP)) * pAttacker->GetPoint(POINT_STEAL_HP) / 100;
|
||
|
||
if (iHP > 0 && GetHP() >= iHP)
|
||
{
|
||
CreateFly(FLY_HP_SMALL, pAttacker);
|
||
pAttacker->PointChange(POINT_HP, iHP);
|
||
PointChange(POINT_HP, -iHP);
|
||
}
|
||
}
|
||
}
|
||
|
||
// SP <20><>ƿ
|
||
if (pAttacker->GetPoint(POINT_STEAL_SP))
|
||
{
|
||
int pct = 1;
|
||
|
||
if (number(1, 10) <= pct)
|
||
{
|
||
int iCur;
|
||
|
||
if (IsPC())
|
||
iCur = iCurSP;
|
||
else
|
||
iCur = iCurHP;
|
||
|
||
int iSP = MIN(dam, MAX(0, iCur)) * pAttacker->GetPoint(POINT_STEAL_SP) / 100;
|
||
|
||
if (iSP > 0 && iCur >= iSP)
|
||
{
|
||
CreateFly(FLY_SP_SMALL, pAttacker);
|
||
pAttacker->PointChange(POINT_SP, iSP);
|
||
|
||
if (IsPC())
|
||
PointChange(POINT_SP, -iSP);
|
||
}
|
||
}
|
||
}
|
||
|
||
// <20><> <20><>ƿ
|
||
if (pAttacker->GetPoint(POINT_STEAL_GOLD))
|
||
{
|
||
if (number(1, 100) <= pAttacker->GetPoint(POINT_STEAL_GOLD))
|
||
{
|
||
int iAmount = number(1, GetLevel());
|
||
pAttacker->PointChange(POINT_GOLD, iAmount);
|
||
DBManager::instance().SendMoneyLog(MONEY_LOG_MISC, 1, iAmount);
|
||
}
|
||
}
|
||
|
||
// ĥ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> HPȸ<50><C8B8>
|
||
if (pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) && number(0, 4) > 0) // 80% Ȯ<><C8AE>
|
||
{
|
||
int i = MIN(dam, iCurHP) * pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) / 100;
|
||
|
||
if (i)
|
||
{
|
||
CreateFly(FLY_HP_SMALL, pAttacker);
|
||
pAttacker->PointChange(POINT_HP, i);
|
||
}
|
||
}
|
||
|
||
// ĥ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> SPȸ<50><C8B8>
|
||
if (pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) && number(0, 4) > 0) // 80% Ȯ<><C8AE>
|
||
{
|
||
int i = MIN(dam, iCurHP) * pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) / 100;
|
||
|
||
if (i)
|
||
{
|
||
CreateFly(FLY_SP_SMALL, pAttacker);
|
||
pAttacker->PointChange(POINT_SP, i);
|
||
}
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ش<EFBFBD>.
|
||
if (pAttacker->GetPoint(POINT_MANA_BURN_PCT))
|
||
{
|
||
if (number(1, 100) <= pAttacker->GetPoint(POINT_MANA_BURN_PCT))
|
||
PointChange(POINT_SP, -50);
|
||
}
|
||
}
|
||
}
|
||
|
||
//
|
||
// <20><>Ÿ <20>Ǵ<EFBFBD> <20><>ų<EFBFBD><C5B3> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ʽ<EFBFBD> <20><><EFBFBD><EFBFBD>/<2F><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
//
|
||
switch (type)
|
||
{
|
||
case DAMAGE_TYPE_NORMAL:
|
||
case DAMAGE_TYPE_NORMAL_RANGE:
|
||
if (pAttacker)
|
||
if (pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS))
|
||
dam = dam * (100 + pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS)) / 100;
|
||
|
||
dam = dam * (100 - MIN(99, GetPoint(POINT_NORMAL_HIT_DEFEND_BONUS))) / 100;
|
||
break;
|
||
|
||
case DAMAGE_TYPE_MELEE:
|
||
case DAMAGE_TYPE_RANGE:
|
||
case DAMAGE_TYPE_FIRE:
|
||
case DAMAGE_TYPE_ICE:
|
||
case DAMAGE_TYPE_ELEC:
|
||
case DAMAGE_TYPE_MAGIC:
|
||
if (pAttacker)
|
||
if (pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS))
|
||
dam = dam * (100 + pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS)) / 100;
|
||
|
||
dam = dam * (100 - MIN(99, GetPoint(POINT_SKILL_DEFEND_BONUS))) / 100;
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
//
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD>ż<EFBFBD>ȣ)
|
||
//
|
||
if (IsAffectFlag(AFF_MANASHIELD))
|
||
{
|
||
// POINT_MANASHIELD <20><> <20>۾<EFBFBD><DBBE><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
int iDamageSPPart = dam / 3;
|
||
int iDamageToSP = iDamageSPPart * GetPoint(POINT_MANASHIELD) / 100;
|
||
int iSP = GetSP();
|
||
|
||
// SP<53><50> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if (iDamageToSP <= iSP)
|
||
{
|
||
PointChange(POINT_SP, -iDamageToSP);
|
||
dam -= iDamageSPPart;
|
||
}
|
||
else
|
||
{
|
||
// <20><><EFBFBD>ŷ<EFBFBD><C5B7><EFBFBD> <20><><EFBFBD>ڶ<EFBFBD><DAB6><EFBFBD> <20>ǰ<EFBFBD> <20><> <20>←<EFBFBD><EFBFA9><EFBFBD><EFBFBD>??
|
||
PointChange(POINT_SP, -GetSP());
|
||
dam -= iSP * 100 / MAX(GetPoint(POINT_MANASHIELD), 1);
|
||
}
|
||
}
|
||
|
||
//
|
||
// <20><>ü <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (<28><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||
//
|
||
if (GetPoint(POINT_MALL_DEFBONUS) > 0)
|
||
{
|
||
int dec_dam = MIN(200, dam * GetPoint(POINT_MALL_DEFBONUS) / 100);
|
||
dam -= dec_dam;
|
||
}
|
||
|
||
if (pAttacker)
|
||
{
|
||
//
|
||
// <20><>ü <20><><EFBFBD>ݷ<EFBFBD> <20><><EFBFBD><EFBFBD> (<28><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||
//
|
||
if (pAttacker->GetPoint(POINT_MALL_ATTBONUS) > 0)
|
||
{
|
||
int add_dam = MIN(300, dam * pAttacker->GetLimitPoint(POINT_MALL_ATTBONUS) / 100);
|
||
dam += add_dam;
|
||
}
|
||
|
||
//
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ʽ<EFBFBD> (<28>ѱ<EFBFBD> <20>õ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>)
|
||
//
|
||
int iEmpire = GetEmpire();
|
||
int lMapIndex = GetMapIndex();
|
||
int iMapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex);
|
||
|
||
if (LC_IsYMIR() == true)
|
||
{
|
||
if (iEmpire && iMapEmpire && iEmpire != iMapEmpire)
|
||
{
|
||
dam += (dam * 30) / 100;
|
||
}
|
||
}
|
||
|
||
if (pAttacker->IsPC())
|
||
{
|
||
iEmpire = pAttacker->GetEmpire();
|
||
lMapIndex = pAttacker->GetMapIndex();
|
||
iMapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex);
|
||
|
||
// <20>ٸ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 10% <20><><EFBFBD><EFBFBD>
|
||
if (iEmpire && iMapEmpire && iEmpire != iMapEmpire)
|
||
{
|
||
int percent = 10;
|
||
|
||
if (184 <= lMapIndex && lMapIndex <= 189)
|
||
{
|
||
if (LC_IsYMIR() == true)
|
||
percent = 7;
|
||
else
|
||
percent = 9;
|
||
}
|
||
else
|
||
{
|
||
if (LC_IsYMIR() == true)
|
||
percent = 8;
|
||
else
|
||
percent = 9;
|
||
}
|
||
|
||
dam = dam * percent / 10;
|
||
}
|
||
|
||
if (!IsPC() && GetMonsterDrainSPPoint())
|
||
{
|
||
int iDrain = GetMonsterDrainSPPoint();
|
||
|
||
if (iDrain <= pAttacker->GetSP())
|
||
pAttacker->PointChange(POINT_SP, -iDrain);
|
||
else
|
||
{
|
||
int iSP = pAttacker->GetSP();
|
||
pAttacker->PointChange(POINT_SP, -iSP);
|
||
}
|
||
}
|
||
|
||
}
|
||
else if (pAttacker->IsGuardNPC())
|
||
{
|
||
SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD);
|
||
Stun();
|
||
return true;
|
||
}
|
||
|
||
//
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ݰ<EFBFBD><DDB0><EFBFBD> & <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
//
|
||
if (pAttacker->IsPC() && CMonarch::instance().IsPowerUp(pAttacker->GetEmpire()))
|
||
{
|
||
// 10% <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
dam += dam / 10;
|
||
}
|
||
|
||
if (IsPC() && CMonarch::instance().IsDefenceUp(GetEmpire()))
|
||
{
|
||
// 10% <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
dam -= dam / 10;
|
||
}
|
||
}
|
||
//puAttr.Pop();
|
||
|
||
if (!GetSectree() || GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
|
||
return false;
|
||
|
||
if (!IsPC())
|
||
{
|
||
if (m_pkParty && m_pkParty->GetLeader())
|
||
m_pkParty->GetLeader()->SetLastAttacked(get_dword_time());
|
||
else
|
||
SetLastAttacked(get_dword_time());
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> : <20><><EFBFBD><EFBFBD> <20><>
|
||
MonsterChat(MONSTER_CHAT_ATTACKED);
|
||
}
|
||
|
||
if (IsStun())
|
||
{
|
||
Dead(pAttacker);
|
||
return true;
|
||
}
|
||
|
||
if (IsDead())
|
||
return true;
|
||
|
||
// <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20>ʵ<EFBFBD><CAB5><EFBFBD> <20><>.
|
||
if (type == DAMAGE_TYPE_POISON)
|
||
{
|
||
if (GetHP() - dam <= 0)
|
||
{
|
||
dam = GetHP() - 1;
|
||
}
|
||
}
|
||
|
||
// ------------------------
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>̾<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
// -----------------------
|
||
if (LC_IsGermany() && pAttacker && pAttacker->IsPC())
|
||
{
|
||
int iDmgPct = CHARACTER_MANAGER::instance().GetUserDamageRate(pAttacker);
|
||
dam = dam * iDmgPct / 100;
|
||
}
|
||
|
||
// STONE SKIN : <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
if (IsMonster() && IsStoneSkinner())
|
||
{
|
||
if (GetHPPct() < GetMobTable().bStoneSkinPoint)
|
||
dam /= 2;
|
||
}
|
||
|
||
//PROF_UNIT puRest1("Rest1");
|
||
if (pAttacker)
|
||
{
|
||
// DEATH BLOW : Ȯ<><C8AE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 4<><34> <20><><EFBFBD><EFBFBD> (!? <20><><EFBFBD><EFBFBD> <20>̺<EFBFBD>Ʈ<EFBFBD><C6AE> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||
if (pAttacker->IsMonster() && pAttacker->IsDeathBlower())
|
||
{
|
||
if (pAttacker->IsDeathBlow())
|
||
{
|
||
if (number(1, 4) == GetJob())
|
||
{
|
||
IsDeathBlow = true;
|
||
dam = dam * 4;
|
||
}
|
||
}
|
||
}
|
||
|
||
dam = BlueDragon_Damage(this, pAttacker, dam);
|
||
|
||
BYTE damageFlag = 0;
|
||
|
||
if (type == DAMAGE_TYPE_POISON)
|
||
damageFlag = DAMAGE_POISON;
|
||
else
|
||
damageFlag = DAMAGE_NORMAL;
|
||
|
||
if (IsCritical == true)
|
||
damageFlag |= DAMAGE_CRITICAL;
|
||
|
||
if (IsPenetrate == true)
|
||
damageFlag |= DAMAGE_PENETRATE;
|
||
|
||
|
||
//<2F><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
float damMul = this->GetDamMul();
|
||
float tempDam = dam;
|
||
dam = tempDam * damMul + 0.5f;
|
||
|
||
|
||
if (pAttacker)
|
||
SendDamagePacket(pAttacker, dam, damageFlag);
|
||
|
||
if (test_server)
|
||
{
|
||
if(pAttacker)
|
||
{
|
||
pAttacker->ChatPacket(CHAT_TYPE_INFO, "-> %s, DAM %d HP %d(%d%%) %s%s",
|
||
GetName(),
|
||
dam,
|
||
GetHP(),
|
||
(GetHP() * 100) / GetMaxHP(),
|
||
IsCritical ? "crit " : "",
|
||
IsPenetrate ? "pene " : "",
|
||
IsDeathBlow ? "deathblow " : "");
|
||
}
|
||
|
||
ChatPacket(CHAT_TYPE_PARTY, "<- %s, DAM %d HP %d(%d%%) %s%s",
|
||
pAttacker ? pAttacker->GetName() : 0,
|
||
dam,
|
||
GetHP(),
|
||
(GetHP() * 100) / GetMaxHP(),
|
||
IsCritical ? "crit " : "",
|
||
IsPenetrate ? "pene " : "",
|
||
IsDeathBlow ? "deathblow " : "");
|
||
}
|
||
|
||
if (m_bDetailLog)
|
||
{
|
||
ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s[%d]<5D><> <20><><EFBFBD><EFBFBD> <20><>ġ: %d %d"), pAttacker->GetName(), (DWORD) pAttacker->GetVID(), pAttacker->GetX(), pAttacker->GetY());
|
||
}
|
||
}
|
||
|
||
//
|
||
// !!!!!!!!! <20><><EFBFBD><EFBFBD> HP<48><50> <20><><EFBFBD>̴<EFBFBD> <20>κ<EFBFBD> !!!!!!!!!
|
||
//
|
||
if (!cannot_dead)
|
||
{
|
||
PointChange(POINT_HP, -dam, false);
|
||
}
|
||
|
||
//puRest1.Pop();
|
||
|
||
//PROF_UNIT puRest2("Rest2");
|
||
if (pAttacker && dam > 0 && IsNPC())
|
||
{
|
||
//PROF_UNIT puRest20("Rest20");
|
||
TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
|
||
|
||
if (it == m_map_kDamage.end())
|
||
{
|
||
m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(dam, 0)));
|
||
it = m_map_kDamage.find(pAttacker->GetVID());
|
||
}
|
||
else
|
||
{
|
||
it->second.iTotalDamage += dam;
|
||
}
|
||
//puRest20.Pop();
|
||
|
||
//PROF_UNIT puRest21("Rest21");
|
||
StartRecoveryEvent(); // <20><><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ȸ<><C8B8><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
||
//puRest21.Pop();
|
||
|
||
//PROF_UNIT puRest22("Rest22");
|
||
UpdateAggrPointEx(pAttacker, type, dam, it->second);
|
||
//puRest22.Pop();
|
||
}
|
||
//puRest2.Pop();
|
||
|
||
//PROF_UNIT puRest3("Rest3");
|
||
if (GetHP() <= 0)
|
||
{
|
||
Stun();
|
||
|
||
if (pAttacker && !pAttacker->IsNPC())
|
||
m_dwKillerPID = pAttacker->GetPlayerID();
|
||
else
|
||
m_dwKillerPID = 0;
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
void CHARACTER::DistributeHP(LPCHARACTER pkKiller)
|
||
{
|
||
if (pkKiller->GetDungeon()) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD>ΰ<EFBFBD><CEB0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʴ´<CAB4>
|
||
return;
|
||
}
|
||
|
||
static void GiveExp(LPCHARACTER from, LPCHARACTER to, int iExp)
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
iExp = CALCULATE_VALUE_LVDELTA(to->GetLevel(), from->GetLevel(), iExp);
|
||
|
||
// <20>ܺ<EFBFBD> <20><EFBFBD>Ʈ <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ġ 3<><33> <20><><EFBFBD>ʽ<EFBFBD>
|
||
if (distribution_test_server)
|
||
iExp *= 3;
|
||
|
||
int iBaseExp = iExp;
|
||
|
||
// <20><><EFBFBD><EFBFBD>, ȸ<><C8B8> <20><><EFBFBD><EFBFBD>ġ <20>̺<EFBFBD>Ʈ <20><><EFBFBD><EFBFBD>
|
||
iExp = iExp * (100 + CPrivManager::instance().GetPriv(to, PRIV_EXP_PCT)) / 100;
|
||
|
||
// <20><><EFBFBD>ӳ<EFBFBD> <20>⺻ <20><><EFBFBD><EFBFBD><EFBFBD>Ǵ<EFBFBD> <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD>ʽ<EFBFBD>
|
||
{
|
||
// <20>뵿<EFBFBD><EBB5BF> <20><EFBFBD>
|
||
if (to->IsEquipUniqueItem(UNIQUE_ITEM_LARBOR_MEDAL))
|
||
iExp += iExp * 20 /100;
|
||
|
||
// <20><><EFBFBD><EFBFBD>Ÿ<EFBFBD><C5B8> <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD>ʽ<EFBFBD>
|
||
if (to->GetMapIndex() >= 660000 && to->GetMapIndex() < 670000)
|
||
iExp += iExp * 20 / 100; // 1.2<EFBFBD><EFBFBD> (20%)
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ġ <20>ι<EFBFBD> <20>Ӽ<EFBFBD>
|
||
if (to->GetPoint(POINT_EXP_DOUBLE_BONUS))
|
||
if (number(1, 100) <= to->GetPoint(POINT_EXP_DOUBLE_BONUS))
|
||
iExp += iExp * 30 / 100; // 1.3<EFBFBD><EFBFBD> (30%)
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> (2<>ð<EFBFBD>¥<EFBFBD><C2A5>)
|
||
if (to->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_EXP))
|
||
iExp += iExp * 50 / 100;
|
||
|
||
switch (to->GetMountVnum())
|
||
{
|
||
case 20110:
|
||
case 20111:
|
||
case 20112:
|
||
case 20113:
|
||
if (to->IsEquipUniqueItem(71115) || to->IsEquipUniqueItem(71117) || to->IsEquipUniqueItem(71119) ||
|
||
to->IsEquipUniqueItem(71121) )
|
||
{
|
||
iExp += iExp * 10 / 100;
|
||
}
|
||
break;
|
||
|
||
case 20114:
|
||
case 20120:
|
||
case 20121:
|
||
case 20122:
|
||
case 20123:
|
||
case 20124:
|
||
case 20125:
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD>ʽ<EFBFBD>
|
||
iExp += iExp * 30 / 100;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20>Ǹ<EFBFBD> <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD>ʽ<EFBFBD>
|
||
if (LC_IsHongKong() || LC_IsEurope() || LC_IsCanada())
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>: <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD><EFBFBD>
|
||
if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
|
||
{
|
||
iExp += (iExp * 50 / 100);
|
||
}
|
||
|
||
if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP) == true)
|
||
{
|
||
iExp += (iExp * 50 / 100);
|
||
}
|
||
|
||
// PC<50><43> <20><><EFBFBD><EFBFBD> <20><>ġ <20><><EFBFBD>ʽ<EFBFBD>
|
||
if (to->GetPoint(POINT_PC_BANG_EXP_BONUS) > 0)
|
||
{
|
||
if (to->IsPCBang() == true)
|
||
iExp += (iExp * to->GetPoint(POINT_PC_BANG_EXP_BONUS)/100);
|
||
}
|
||
|
||
// <20><>ȥ <20><><EFBFBD>ʽ<EFBFBD>
|
||
iExp += iExp * to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS) / 100;
|
||
}
|
||
else if (/*LC_IsNewCIBN() || */LC_IsBrazil())
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>: <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD><EFBFBD>
|
||
if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
|
||
{
|
||
iExp += iExp;
|
||
}
|
||
|
||
if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP) == true)
|
||
{
|
||
iExp += iExp;
|
||
}
|
||
|
||
// PC<50><43> <20><><EFBFBD><EFBFBD> <20><>ġ <20><><EFBFBD>ʽ<EFBFBD>
|
||
if (to->GetPoint(POINT_PC_BANG_EXP_BONUS) > 0)
|
||
{
|
||
if (to->IsPCBang() == true)
|
||
iExp += (iExp * to->GetPoint(POINT_PC_BANG_EXP_BONUS)/100);
|
||
}
|
||
|
||
// <20><>ȥ <20><><EFBFBD>ʽ<EFBFBD>
|
||
iExp += iExp * to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS) / 100;
|
||
}
|
||
else
|
||
{
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>: <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD><EFBFBD>
|
||
if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
|
||
{
|
||
iExp += (iExp * 20 / 100);
|
||
}
|
||
|
||
if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP) == true)
|
||
{
|
||
iExp += (iExp * 20 / 100);
|
||
}
|
||
|
||
// PC<50><43> <20><><EFBFBD><EFBFBD> <20><>ġ <20><><EFBFBD>ʽ<EFBFBD>
|
||
if (to->GetPoint(POINT_PC_BANG_EXP_BONUS) > 0)
|
||
{
|
||
if (to->IsPCBang() == true)
|
||
iExp += (iExp * to->GetPoint(POINT_PC_BANG_EXP_BONUS)/100);
|
||
}
|
||
|
||
// <20><>ȥ <20><><EFBFBD>ʽ<EFBFBD>
|
||
iExp += iExp * to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS) / 100;
|
||
}
|
||
|
||
iExp += (iExp * to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP)/100);
|
||
iExp += (iExp * to->GetPoint(POINT_MALL_EXPBONUS)/100);
|
||
iExp += (iExp * to->GetPoint(POINT_EXP)/100);
|
||
|
||
/* if (speed_server)
|
||
{
|
||
iExp += iExp * CSpeedServerManager::ExpBonus();
|
||
|
||
}
|
||
*/
|
||
if (test_server)
|
||
{
|
||
sys_log(0, "Bonus Exp : Ramadan Candy: %d MallExp: %d PointExp: %d",
|
||
to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP),
|
||
to->GetPoint(POINT_MALL_EXPBONUS),
|
||
to->GetPoint(POINT_EXP)
|
||
);
|
||
}
|
||
|
||
// <20><>ȹ<EFBFBD><C8B9> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> 2005.04.21 <20><><EFBFBD><EFBFBD> 85%
|
||
iExp = iExp * CHARACTER_MANAGER::instance().GetMobExpRate(to) / 100;
|
||
|
||
// <20><><EFBFBD><EFBFBD>ġ <20>ѹ<EFBFBD> ȹ<>淮 <20><><EFBFBD><EFBFBD>
|
||
iExp = MIN(to->GetNextExp() / 10, iExp);
|
||
|
||
if (test_server)
|
||
{
|
||
if (quest::CQuestManager::instance().GetEventFlag("exp_bonus_log") && iBaseExp>0)
|
||
to->ChatPacket(CHAT_TYPE_INFO, "exp bonus %d%%", (iExp-iBaseExp)*100/iBaseExp);
|
||
}
|
||
|
||
iExp = AdjustExpByLevel(to, iExp);
|
||
|
||
to->PointChange(POINT_EXP, iExp, true);
|
||
from->CreateFly(FLY_EXP, to);
|
||
|
||
{
|
||
LPCHARACTER you = to->GetMarryPartner();
|
||
// <20>κΰ<CEBA> <20><><EFBFBD><EFBFBD> <20><>Ƽ<EFBFBD><C6BC><EFBFBD≯<EFBFBD> <20>ݽ<EFBFBD><DDBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||
if (you)
|
||
{
|
||
// 1<><31><EFBFBD><EFBFBD> 100%
|
||
DWORD dwUpdatePoint = 2000*iExp/to->GetLevel()/to->GetLevel()/3;
|
||
|
||
if (to->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0 ||
|
||
you->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0)
|
||
dwUpdatePoint = (DWORD)(dwUpdatePoint * 3);
|
||
|
||
marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(to->GetPlayerID());
|
||
|
||
// DIVORCE_NULL_BUG_FIX
|
||
if (pMarriage && pMarriage->IsNear())
|
||
pMarriage->Update(dwUpdatePoint);
|
||
// END_OF_DIVORCE_NULL_BUG_FIX
|
||
}
|
||
}
|
||
}
|
||
|
||
namespace NPartyExpDistribute
|
||
{
|
||
struct FPartyTotaler
|
||
{
|
||
int total;
|
||
int member_count;
|
||
int x, y;
|
||
|
||
FPartyTotaler(LPCHARACTER center)
|
||
: total(0), member_count(0), x(center->GetX()), y(center->GetY())
|
||
{};
|
||
|
||
void operator () (LPCHARACTER ch)
|
||
{
|
||
if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
|
||
{
|
||
if (LC_IsYMIR())
|
||
total += ch->GetLevel();
|
||
else
|
||
total += party_exp_distribute_table[ch->GetLevel()];
|
||
|
||
++member_count;
|
||
}
|
||
}
|
||
};
|
||
|
||
struct FPartyDistributor
|
||
{
|
||
int total;
|
||
LPCHARACTER c;
|
||
int x, y;
|
||
DWORD _iExp;
|
||
int m_iMode;
|
||
int m_iMemberCount;
|
||
|
||
FPartyDistributor(LPCHARACTER center, int member_count, int total, DWORD iExp, int iMode)
|
||
: total(total), c(center), x(center->GetX()), y(center->GetY()), _iExp(iExp), m_iMode(iMode), m_iMemberCount(member_count)
|
||
{
|
||
if (m_iMemberCount == 0)
|
||
m_iMemberCount = 1;
|
||
};
|
||
|
||
void operator () (LPCHARACTER ch)
|
||
{
|
||
if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
|
||
{
|
||
DWORD iExp2 = 0;
|
||
|
||
switch (m_iMode)
|
||
{
|
||
case PARTY_EXP_DISTRIBUTION_NON_PARITY:
|
||
if (LC_IsYMIR())
|
||
iExp2 = (DWORD) ((_iExp * ch->GetLevel()) / total);
|
||
else
|
||
iExp2 = (DWORD) (_iExp * (float) party_exp_distribute_table[ch->GetLevel()] / total);
|
||
break;
|
||
|
||
case PARTY_EXP_DISTRIBUTION_PARITY:
|
||
iExp2 = _iExp / m_iMemberCount;
|
||
break;
|
||
|
||
default:
|
||
sys_err("Unknown party exp distribution mode %d", m_iMode);
|
||
return;
|
||
}
|
||
|
||
GiveExp(c, ch, iExp2);
|
||
}
|
||
}
|
||
};
|
||
}
|
||
|
||
typedef struct SDamageInfo
|
||
{
|
||
int iDam;
|
||
LPCHARACTER pAttacker;
|
||
LPPARTY pParty;
|
||
|
||
void Clear()
|
||
{
|
||
pAttacker = NULL;
|
||
pParty = NULL;
|
||
}
|
||
|
||
inline void Distribute(LPCHARACTER ch, int iExp)
|
||
{
|
||
if (pAttacker)
|
||
GiveExp(ch, pAttacker, iExp);
|
||
else if (pParty)
|
||
{
|
||
NPartyExpDistribute::FPartyTotaler f(ch);
|
||
pParty->ForEachOnlineMember(f);
|
||
|
||
if (pParty->IsPositionNearLeader(ch))
|
||
iExp = iExp * (100 + pParty->GetExpBonusPercent()) / 100;
|
||
|
||
if (test_server)
|
||
{
|
||
if (quest::CQuestManager::instance().GetEventFlag("exp_bonus_log") && pParty->GetExpBonusPercent())
|
||
pParty->ChatPacketToAllMember(CHAT_TYPE_INFO, "exp party bonus %d%%", pParty->GetExpBonusPercent());
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD>ġ <20><><EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD> (<28><>Ƽ<EFBFBD><C6BC> ȹ<><C8B9><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> 5% <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><>)
|
||
if (pParty->GetExpCentralizeCharacter())
|
||
{
|
||
LPCHARACTER tch = pParty->GetExpCentralizeCharacter();
|
||
|
||
if (DISTANCE_APPROX(ch->GetX() - tch->GetX(), ch->GetY() - tch->GetY()) <= PARTY_DEFAULT_RANGE)
|
||
{
|
||
int iExpCenteralize = (int) (iExp * 0.05f);
|
||
iExp -= iExpCenteralize;
|
||
|
||
GiveExp(ch, pParty->GetExpCentralizeCharacter(), iExpCenteralize);
|
||
}
|
||
}
|
||
|
||
NPartyExpDistribute::FPartyDistributor fDist(ch, f.member_count, f.total, iExp, pParty->GetExpDistributionMode());
|
||
pParty->ForEachOnlineMember(fDist);
|
||
}
|
||
}
|
||
} TDamageInfo;
|
||
|
||
LPCHARACTER CHARACTER::DistributeExp()
|
||
{
|
||
int iExpToDistribute = GetExp();
|
||
|
||
if (iExpToDistribute <= 0)
|
||
return NULL;
|
||
|
||
int iTotalDam = 0;
|
||
LPCHARACTER pkChrMostAttacked = NULL;
|
||
int iMostDam = 0;
|
||
|
||
typedef std::vector<TDamageInfo> TDamageInfoTable;
|
||
TDamageInfoTable damage_info_table;
|
||
std::map<LPPARTY, TDamageInfo> map_party_damage;
|
||
|
||
damage_info_table.reserve(m_map_kDamage.size());
|
||
|
||
TDamageMap::iterator it = m_map_kDamage.begin();
|
||
|
||
// <20>ϴ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ɷ<EFBFBD> <20><><EFBFBD><EFBFBD>. (50m)
|
||
while (it != m_map_kDamage.end())
|
||
{
|
||
const VID & c_VID = it->first;
|
||
int iDam = it->second.iTotalDamage;
|
||
|
||
++it;
|
||
|
||
LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
|
||
|
||
// NPC<50><43> <20><><EFBFBD><EFBFBD><EFBFBD> <20>ϳ<EFBFBD>? -.-;
|
||
if (!pAttacker || pAttacker->IsNPC() || DISTANCE_APPROX(GetX()-pAttacker->GetX(), GetY()-pAttacker->GetY())>5000)
|
||
continue;
|
||
|
||
iTotalDam += iDam;
|
||
if (!pkChrMostAttacked || iDam > iMostDam)
|
||
{
|
||
pkChrMostAttacked = pAttacker;
|
||
iMostDam = iDam;
|
||
}
|
||
|
||
if (pAttacker->GetParty())
|
||
{
|
||
std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.find(pAttacker->GetParty());
|
||
if (it == map_party_damage.end())
|
||
{
|
||
TDamageInfo di;
|
||
di.iDam = iDam;
|
||
di.pAttacker = NULL;
|
||
di.pParty = pAttacker->GetParty();
|
||
map_party_damage.insert(std::make_pair(di.pParty, di));
|
||
}
|
||
else
|
||
{
|
||
it->second.iDam += iDam;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
TDamageInfo di;
|
||
|
||
di.iDam = iDam;
|
||
di.pAttacker = pAttacker;
|
||
di.pParty = NULL;
|
||
|
||
//sys_log(0, "__ pq_damage %s %d", pAttacker->GetName(), iDam);
|
||
//pq_damage.push(di);
|
||
damage_info_table.push_back(di);
|
||
}
|
||
}
|
||
|
||
for (std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.begin(); it != map_party_damage.end(); ++it)
|
||
{
|
||
damage_info_table.push_back(it->second);
|
||
//sys_log(0, "__ pq_damage_party [%u] %d", it->second.pParty->GetLeaderPID(), it->second.iDam);
|
||
}
|
||
|
||
SetExp(0);
|
||
//m_map_kDamage.clear();
|
||
|
||
if (iTotalDam == 0) // <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ذ<EFBFBD> 0<≯<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
return NULL;
|
||
|
||
if (m_pkChrStone) // <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ѱ<EFBFBD><D1B1><EFBFBD>.
|
||
{
|
||
//sys_log(0, "__ Give half to Stone : %d", iExpToDistribute>>1);
|
||
int iExp = iExpToDistribute >> 1;
|
||
m_pkChrStone->SetExp(m_pkChrStone->GetExp() + iExp);
|
||
iExpToDistribute -= iExp;
|
||
}
|
||
|
||
sys_log(1, "%s total exp: %d, damage_info_table.size() == %d, TotalDam %d",
|
||
GetName(), iExpToDistribute, damage_info_table.size(), iTotalDam);
|
||
//sys_log(1, "%s total exp: %d, pq_damage.size() == %d, TotalDam %d",
|
||
//GetName(), iExpToDistribute, pq_damage.size(), iTotalDam);
|
||
|
||
if (damage_info_table.empty())
|
||
return NULL;
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> HP ȸ<><C8B8><EFBFBD><EFBFBD> <20>Ѵ<EFBFBD>.
|
||
DistributeHP(pkChrMostAttacked); // <20><><EFBFBD><EFBFBD> <20>ý<EFBFBD><C3BD><EFBFBD>
|
||
|
||
{
|
||
// <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD>̳<EFBFBD> <20><>Ƽ<EFBFBD><C6BC> <20><> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> 20% + <20>ڱⰡ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ŭ<EFBFBD><C5AD> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> <20>Դ´<D4B4>.
|
||
TDamageInfoTable::iterator di = damage_info_table.begin();
|
||
{
|
||
TDamageInfoTable::iterator it;
|
||
|
||
for (it = damage_info_table.begin(); it != damage_info_table.end();++it)
|
||
{
|
||
if (it->iDam > di->iDam)
|
||
di = it;
|
||
}
|
||
}
|
||
|
||
int iExp = iExpToDistribute / 5;
|
||
iExpToDistribute -= iExp;
|
||
|
||
float fPercent = (float) di->iDam / iTotalDam;
|
||
|
||
if (fPercent > 1.0f)
|
||
{
|
||
sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di->pAttacker->GetName());
|
||
fPercent = 1.0f;
|
||
}
|
||
|
||
iExp += (int) (iExpToDistribute * fPercent);
|
||
|
||
//sys_log(0, "%s given exp percent %.1f + 20 dam %d", GetName(), fPercent * 100.0f, di.iDam);
|
||
|
||
di->Distribute(this, iExp);
|
||
|
||
// 100% <20><> <20>Ծ<EFBFBD><D4BE><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>Ѵ<EFBFBD>.
|
||
if (fPercent == 1.0f)
|
||
return pkChrMostAttacked;
|
||
|
||
di->Clear();
|
||
}
|
||
|
||
{
|
||
// <20><><EFBFBD><EFBFBD> 80%<25><> <20><><EFBFBD><EFBFBD>ġ<EFBFBD><C4A1> <20>й<EFBFBD><D0B9>Ѵ<EFBFBD>.
|
||
TDamageInfoTable::iterator it;
|
||
|
||
for (it = damage_info_table.begin(); it != damage_info_table.end(); ++it)
|
||
{
|
||
TDamageInfo & di = *it;
|
||
|
||
float fPercent = (float) di.iDam / iTotalDam;
|
||
|
||
if (fPercent > 1.0f)
|
||
{
|
||
sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di.pAttacker->GetName());
|
||
fPercent = 1.0f;
|
||
}
|
||
|
||
//sys_log(0, "%s given exp percent %.1f dam %d", GetName(), fPercent * 100.0f, di.iDam);
|
||
di.Distribute(this, (int) (iExpToDistribute * fPercent));
|
||
}
|
||
}
|
||
|
||
return pkChrMostAttacked;
|
||
}
|
||
|
||
// ȭ<><C8AD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>
|
||
int CHARACTER::GetArrowAndBow(LPITEM * ppkBow, LPITEM * ppkArrow, int iArrowCount/* = 1 */)
|
||
{
|
||
LPITEM pkBow;
|
||
|
||
if (!(pkBow = GetWear(WEAR_WEAPON)) || pkBow->GetProto()->bSubType != WEAPON_BOW)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
LPITEM pkArrow;
|
||
|
||
if (!(pkArrow = GetWear(WEAR_ARROW)) || pkArrow->GetType() != ITEM_WEAPON ||
|
||
pkArrow->GetProto()->bSubType != WEAPON_ARROW)
|
||
{
|
||
return 0;
|
||
}
|
||
|
||
iArrowCount = MIN(iArrowCount, pkArrow->GetCount());
|
||
|
||
*ppkBow = pkBow;
|
||
*ppkArrow = pkArrow;
|
||
|
||
return iArrowCount;
|
||
}
|
||
|
||
void CHARACTER::UseArrow(LPITEM pkArrow, DWORD dwArrowCount)
|
||
{
|
||
int iCount = pkArrow->GetCount();
|
||
DWORD dwVnum = pkArrow->GetVnum();
|
||
iCount = iCount - MIN(iCount, dwArrowCount);
|
||
pkArrow->SetCount(iCount);
|
||
|
||
if (iCount == 0)
|
||
{
|
||
LPITEM pkNewArrow = FindSpecifyItem(dwVnum);
|
||
|
||
sys_log(0, "UseArrow : FindSpecifyItem %u %p", dwVnum, get_pointer(pkNewArrow));
|
||
|
||
if (pkNewArrow)
|
||
EquipItem(pkNewArrow);
|
||
}
|
||
}
|
||
|
||
class CFuncShoot
|
||
{
|
||
public:
|
||
LPCHARACTER m_me;
|
||
BYTE m_bType;
|
||
bool m_bSucceed;
|
||
|
||
CFuncShoot(LPCHARACTER ch, BYTE bType) : m_me(ch), m_bType(bType), m_bSucceed(false)
|
||
{
|
||
}
|
||
|
||
void operator () (DWORD dwTargetVID)
|
||
{
|
||
if (m_bType > 1)
|
||
{
|
||
if (g_bSkillDisable)
|
||
return;
|
||
|
||
m_me->m_SkillUseInfo[m_bType].SetMainTargetVID(dwTargetVID);
|
||
/*if (m_bType == SKILL_BIPABU || m_bType == SKILL_KWANKYEOK)
|
||
m_me->m_SkillUseInfo[m_bType].ResetHitCount();*/
|
||
}
|
||
|
||
LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
|
||
|
||
if (!pkVictim)
|
||
return;
|
||
|
||
// <20><><EFBFBD><EFBFBD> <20>Ұ<EFBFBD>
|
||
if (!battle_is_attackable(m_me, pkVictim))
|
||
return;
|
||
|
||
if (m_me->IsNPC())
|
||
{
|
||
if (DISTANCE_APPROX(m_me->GetX() - pkVictim->GetX(), m_me->GetY() - pkVictim->GetY()) > 5000)
|
||
return;
|
||
}
|
||
|
||
LPITEM pkBow, pkArrow;
|
||
|
||
switch (m_bType)
|
||
{
|
||
case 0: // <20>Ϲ<EFBFBD>Ȱ
|
||
{
|
||
int iDam = 0;
|
||
|
||
if (m_me->IsPC())
|
||
{
|
||
if (m_me->GetJob() != JOB_ASSASSIN)
|
||
return;
|
||
|
||
if (0 == m_me->GetArrowAndBow(&pkBow, &pkArrow))
|
||
return;
|
||
|
||
if (m_me->GetSkillGroup() != 0)
|
||
if (!m_me->IsNPC() && m_me->GetSkillGroup() != 2)
|
||
{
|
||
if (m_me->GetSP() < 5)
|
||
return;
|
||
|
||
m_me->PointChange(POINT_SP, -5);
|
||
}
|
||
|
||
iDam = CalcArrowDamage(m_me, pkVictim, pkBow, pkArrow);
|
||
m_me->UseArrow(pkArrow, 1);
|
||
|
||
// check speed hack
|
||
DWORD dwCurrentTime = get_dword_time();
|
||
if (IS_SPEED_HACK(m_me, pkVictim, dwCurrentTime))
|
||
iDam = 0;
|
||
}
|
||
else
|
||
iDam = CalcMeleeDamage(m_me, pkVictim);
|
||
|
||
NormalAttackAffect(m_me, pkVictim);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_BOW)) / 100;
|
||
|
||
//sys_log(0, "%s arrow %s dam %d", m_me->GetName(), pkVictim->GetName(), iDam);
|
||
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_NORMAL_RANGE);
|
||
// Ÿ<><C5B8>ġ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>
|
||
}
|
||
break;
|
||
|
||
case 1: // <20>Ϲ<EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
{
|
||
int iDam;
|
||
|
||
if (m_me->IsPC())
|
||
return;
|
||
|
||
iDam = CalcMagicDamage(m_me, pkVictim);
|
||
|
||
NormalAttackAffect(m_me, pkVictim);
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_MAGIC)) / 100;
|
||
|
||
//sys_log(0, "%s arrow %s dam %d", m_me->GetName(), pkVictim->GetName(), iDam);
|
||
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_MAGIC);
|
||
// Ÿ<><C5B8>ġ <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><>
|
||
}
|
||
break;
|
||
|
||
case SKILL_YEONSA: // <20><><EFBFBD><EFBFBD>
|
||
{
|
||
//int iUseArrow = 2 + (m_me->GetSkillPower(SKILL_YEONSA) *6/100);
|
||
int iUseArrow = 1;
|
||
|
||
// <20><>Ż<EFBFBD><C5BB> <20><><EFBFBD><EFBFBD><EFBFBD>ϴ°<CFB4><C2B0><EFBFBD>
|
||
{
|
||
if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
m_me->ComputeSkill(m_bType, pkVictim);
|
||
m_me->UseArrow(pkArrow, iUseArrow);
|
||
|
||
if (pkVictim->IsDead())
|
||
break;
|
||
|
||
}
|
||
else
|
||
break;
|
||
}
|
||
}
|
||
break;
|
||
|
||
|
||
case SKILL_KWANKYEOK:
|
||
{
|
||
int iUseArrow = 1;
|
||
|
||
if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
sys_log(0, "%s kwankeyok %s", m_me->GetName(), pkVictim->GetName());
|
||
m_me->ComputeSkill(m_bType, pkVictim);
|
||
m_me->UseArrow(pkArrow, iUseArrow);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case SKILL_GIGUNG:
|
||
{
|
||
int iUseArrow = 1;
|
||
if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
sys_log(0, "%s gigung %s", m_me->GetName(), pkVictim->GetName());
|
||
m_me->ComputeSkill(m_bType, pkVictim);
|
||
m_me->UseArrow(pkArrow, iUseArrow);
|
||
}
|
||
}
|
||
|
||
break;
|
||
case SKILL_HWAJO:
|
||
{
|
||
int iUseArrow = 1;
|
||
if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
sys_log(0, "%s hwajo %s", m_me->GetName(), pkVictim->GetName());
|
||
m_me->ComputeSkill(m_bType, pkVictim);
|
||
m_me->UseArrow(pkArrow, iUseArrow);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case SKILL_HORSE_WILDATTACK_RANGE:
|
||
{
|
||
int iUseArrow = 1;
|
||
if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
sys_log(0, "%s horse_wildattack %s", m_me->GetName(), pkVictim->GetName());
|
||
m_me->ComputeSkill(m_bType, pkVictim);
|
||
m_me->UseArrow(pkArrow, iUseArrow);
|
||
}
|
||
}
|
||
|
||
break;
|
||
|
||
case SKILL_MARYUNG:
|
||
//case SKILL_GUMHWAN:
|
||
case SKILL_TUSOK:
|
||
case SKILL_BIPABU:
|
||
case SKILL_NOEJEON:
|
||
case SKILL_GEOMPUNG:
|
||
case SKILL_SANGONG:
|
||
case SKILL_MAHWAN:
|
||
case SKILL_PABEOB:
|
||
//case SKILL_CURSE:
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
|
||
m_me->ComputeSkill(m_bType, pkVictim);
|
||
}
|
||
break;
|
||
|
||
case SKILL_CHAIN:
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
if (pkVictim->CanBeginFight())
|
||
pkVictim->BeginFight(m_me);
|
||
|
||
sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
|
||
m_me->ComputeSkill(m_bType, pkVictim);
|
||
|
||
// TODO <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><> <20><> <20><> <20>ϱ<EFBFBD>
|
||
}
|
||
break;
|
||
|
||
case SKILL_YONGBI:
|
||
{
|
||
m_me->OnMove(true);
|
||
}
|
||
break;
|
||
|
||
/*case SKILL_BUDONG:
|
||
{
|
||
m_me->OnMove(true);
|
||
pkVictim->OnMove();
|
||
|
||
DWORD * pdw;
|
||
DWORD dwEI = AllocEventInfo(sizeof(DWORD) * 2, &pdw);
|
||
pdw[0] = m_me->GetVID();
|
||
pdw[1] = pkVictim->GetVID();
|
||
|
||
event_create(budong_event_func, dwEI, PASSES_PER_SEC(1));
|
||
}
|
||
break;*/
|
||
|
||
default:
|
||
sys_err("CFuncShoot: I don't know this type [%d] of range attack.", (int) m_bType);
|
||
break;
|
||
}
|
||
|
||
m_bSucceed = true;
|
||
}
|
||
};
|
||
|
||
bool CHARACTER::Shoot(BYTE bType)
|
||
{
|
||
sys_log(1, "Shoot %s type %u flyTargets.size %zu", GetName(), bType, m_vec_dwFlyTargets.size());
|
||
|
||
if (!CanMove())
|
||
{
|
||
return false;
|
||
}
|
||
|
||
CFuncShoot f(this, bType);
|
||
|
||
if (m_dwFlyTargetID != 0)
|
||
{
|
||
f(m_dwFlyTargetID);
|
||
m_dwFlyTargetID = 0;
|
||
}
|
||
|
||
f = std::for_each(m_vec_dwFlyTargets.begin(), m_vec_dwFlyTargets.end(), f);
|
||
m_vec_dwFlyTargets.clear();
|
||
|
||
return f.m_bSucceed;
|
||
}
|
||
|
||
void CHARACTER::FlyTarget(DWORD dwTargetVID, int x, int y, BYTE bHeader)
|
||
{
|
||
LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
|
||
TPacketGCFlyTargeting pack;
|
||
|
||
//pack.bHeader = HEADER_GC_FLY_TARGETING;
|
||
pack.bHeader = (bHeader == HEADER_CG_FLY_TARGETING) ? HEADER_GC_FLY_TARGETING : HEADER_GC_ADD_FLY_TARGETING;
|
||
pack.dwShooterVID = GetVID();
|
||
|
||
if (pkVictim)
|
||
{
|
||
pack.dwTargetVID = pkVictim->GetVID();
|
||
pack.x = pkVictim->GetX();
|
||
pack.y = pkVictim->GetY();
|
||
|
||
if (bHeader == HEADER_CG_FLY_TARGETING)
|
||
m_dwFlyTargetID = dwTargetVID;
|
||
else
|
||
m_vec_dwFlyTargets.push_back(dwTargetVID);
|
||
}
|
||
else
|
||
{
|
||
pack.dwTargetVID = 0;
|
||
pack.x = x;
|
||
pack.y = y;
|
||
}
|
||
|
||
sys_log(1, "FlyTarget %s vid %d x %d y %d", GetName(), pack.dwTargetVID, pack.x, pack.y);
|
||
PacketAround(&pack, sizeof(pack), this);
|
||
}
|
||
|
||
LPCHARACTER CHARACTER::GetNearestVictim(LPCHARACTER pkChr)
|
||
{
|
||
if (NULL == pkChr)
|
||
pkChr = this;
|
||
|
||
float fMinDist = 99999.0f;
|
||
LPCHARACTER pkVictim = NULL;
|
||
|
||
TDamageMap::iterator it = m_map_kDamage.begin();
|
||
|
||
// <20>ϴ<EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20>ɷ<EFBFBD> <20><><EFBFBD><EFBFBD>.
|
||
while (it != m_map_kDamage.end())
|
||
{
|
||
const VID & c_VID = it->first;
|
||
++it;
|
||
|
||
LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
|
||
|
||
if (!pAttacker)
|
||
continue;
|
||
|
||
if (pAttacker->IsAffectFlag(AFF_EUNHYUNG) ||
|
||
pAttacker->IsAffectFlag(AFF_INVISIBILITY) ||
|
||
pAttacker->IsAffectFlag(AFF_REVIVE_INVISIBLE))
|
||
continue;
|
||
|
||
float fDist = DISTANCE_APPROX(pAttacker->GetX() - pkChr->GetX(), pAttacker->GetY() - pkChr->GetY());
|
||
|
||
if (fDist < fMinDist)
|
||
{
|
||
pkVictim = pAttacker;
|
||
fMinDist = fDist;
|
||
}
|
||
}
|
||
|
||
return pkVictim;
|
||
}
|
||
|
||
void CHARACTER::SetVictim(LPCHARACTER pkVictim)
|
||
{
|
||
if (!pkVictim)
|
||
{
|
||
if (0 != (DWORD)m_kVIDVictim)
|
||
MonsterLog("<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>");
|
||
|
||
m_kVIDVictim.Reset();
|
||
battle_end(this);
|
||
}
|
||
else
|
||
{
|
||
if (m_kVIDVictim != pkVictim->GetVID())
|
||
MonsterLog("<EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>: %s", pkVictim->GetName());
|
||
|
||
m_kVIDVictim = pkVictim->GetVID();
|
||
m_dwLastVictimSetTime = get_dword_time();
|
||
}
|
||
}
|
||
|
||
LPCHARACTER CHARACTER::GetVictim() const
|
||
{
|
||
return CHARACTER_MANAGER::instance().Find(m_kVIDVictim);
|
||
}
|
||
|
||
LPCHARACTER CHARACTER::GetProtege() const // <20><>ȣ<EFBFBD>ؾ<EFBFBD> <20><> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
{
|
||
if (m_pkChrStone)
|
||
return m_pkChrStone;
|
||
|
||
if (m_pkParty)
|
||
return m_pkParty->GetLeader();
|
||
|
||
return NULL;
|
||
}
|
||
|
||
int CHARACTER::GetAlignment() const
|
||
{
|
||
return m_iAlignment;
|
||
}
|
||
|
||
int CHARACTER::GetRealAlignment() const
|
||
{
|
||
return m_iRealAlignment;
|
||
}
|
||
|
||
void CHARACTER::ShowAlignment(bool bShow)
|
||
{
|
||
if (bShow)
|
||
{
|
||
if (m_iAlignment != m_iRealAlignment)
|
||
{
|
||
m_iAlignment = m_iRealAlignment;
|
||
UpdatePacket();
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (m_iAlignment != 0)
|
||
{
|
||
m_iAlignment = 0;
|
||
UpdatePacket();
|
||
}
|
||
}
|
||
}
|
||
|
||
void CHARACTER::UpdateAlignment(int iAmount)
|
||
{
|
||
bool bShow = false;
|
||
|
||
if (m_iAlignment == m_iRealAlignment)
|
||
bShow = true;
|
||
|
||
int i = m_iAlignment / 10;
|
||
|
||
m_iRealAlignment = MINMAX(-200000, m_iRealAlignment + iAmount, 200000);
|
||
|
||
if (bShow)
|
||
{
|
||
m_iAlignment = m_iRealAlignment;
|
||
|
||
if (i != m_iAlignment / 10)
|
||
UpdatePacket();
|
||
}
|
||
}
|
||
|
||
void CHARACTER::SetKillerMode(bool isOn)
|
||
{
|
||
if ((isOn ? ADD_CHARACTER_STATE_KILLER : 0) == IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER))
|
||
return;
|
||
|
||
if (isOn)
|
||
SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
|
||
else
|
||
REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
|
||
|
||
m_iKillerModePulse = thecore_pulse();
|
||
UpdatePacket();
|
||
sys_log(0, "SetKillerMode Update %s[%d]", GetName(), GetPlayerID());
|
||
}
|
||
|
||
bool CHARACTER::IsKillerMode() const
|
||
{
|
||
return IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
|
||
}
|
||
|
||
void CHARACTER::UpdateKillerMode()
|
||
{
|
||
if (!IsKillerMode())
|
||
return;
|
||
|
||
int iKillerSeconds = ! LC_IsYMIR() ? 30 : 60;
|
||
|
||
if (thecore_pulse() - m_iKillerModePulse >= PASSES_PER_SEC(iKillerSeconds))
|
||
SetKillerMode(false);
|
||
}
|
||
|
||
void CHARACTER::SetPKMode(BYTE bPKMode)
|
||
{
|
||
if (bPKMode >= PK_MODE_MAX_NUM)
|
||
return;
|
||
|
||
if (m_bPKMode == bPKMode)
|
||
return;
|
||
|
||
if (bPKMode == PK_MODE_GUILD && !GetGuild())
|
||
bPKMode = PK_MODE_FREE;
|
||
|
||
m_bPKMode = bPKMode;
|
||
UpdatePacket();
|
||
|
||
sys_log(0, "PK_MODE: %s %d", GetName(), m_bPKMode);
|
||
}
|
||
|
||
BYTE CHARACTER::GetPKMode() const
|
||
{
|
||
return m_bPKMode;
|
||
}
|
||
|
||
struct FuncForgetMyAttacker
|
||
{
|
||
LPCHARACTER m_ch;
|
||
FuncForgetMyAttacker(LPCHARACTER ch)
|
||
{
|
||
m_ch = ch;
|
||
}
|
||
void operator()(LPENTITY ent)
|
||
{
|
||
if (ent->IsType(ENTITY_CHARACTER))
|
||
{
|
||
LPCHARACTER ch = (LPCHARACTER) ent;
|
||
if (ch->IsPC())
|
||
return;
|
||
if (ch->m_kVIDVictim == m_ch->GetVID())
|
||
ch->SetVictim(NULL);
|
||
}
|
||
}
|
||
};
|
||
|
||
struct FuncAggregateMonster
|
||
{
|
||
LPCHARACTER m_ch;
|
||
FuncAggregateMonster(LPCHARACTER ch)
|
||
{
|
||
m_ch = ch;
|
||
}
|
||
void operator()(LPENTITY ent)
|
||
{
|
||
if (ent->IsType(ENTITY_CHARACTER))
|
||
{
|
||
LPCHARACTER ch = (LPCHARACTER) ent;
|
||
if (ch->IsPC())
|
||
return;
|
||
if (!ch->IsMonster())
|
||
return;
|
||
if (ch->GetVictim())
|
||
return;
|
||
|
||
if (number(1, 100) <= 50) // <20>ӽ÷<D3BD> 50% Ȯ<><C8AE><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD>´<EFBFBD>
|
||
if (DISTANCE_APPROX(ch->GetX() - m_ch->GetX(), ch->GetY() - m_ch->GetY()) < 5000)
|
||
if (ch->CanBeginFight())
|
||
ch->BeginFight(m_ch);
|
||
}
|
||
}
|
||
};
|
||
|
||
struct FuncAttractRanger
|
||
{
|
||
LPCHARACTER m_ch;
|
||
FuncAttractRanger(LPCHARACTER ch)
|
||
{
|
||
m_ch = ch;
|
||
}
|
||
|
||
void operator()(LPENTITY ent)
|
||
{
|
||
if (ent->IsType(ENTITY_CHARACTER))
|
||
{
|
||
LPCHARACTER ch = (LPCHARACTER) ent;
|
||
if (ch->IsPC())
|
||
return;
|
||
if (!ch->IsMonster())
|
||
return;
|
||
if (ch->GetVictim() && ch->GetVictim() != m_ch)
|
||
return;
|
||
if (ch->GetMobAttackRange() > 150)
|
||
{
|
||
int iNewRange = 150;//(int)(ch->GetMobAttackRange() * 0.2);
|
||
if (iNewRange < 150)
|
||
iNewRange = 150;
|
||
|
||
ch->AddAffect(AFFECT_BOW_DISTANCE, POINT_BOW_DISTANCE, iNewRange - ch->GetMobAttackRange(), AFF_NONE, 3*60, 0, false);
|
||
}
|
||
}
|
||
}
|
||
};
|
||
|
||
struct FuncPullMonster
|
||
{
|
||
LPCHARACTER m_ch;
|
||
int m_iLength;
|
||
FuncPullMonster(LPCHARACTER ch, int iLength = 300)
|
||
{
|
||
m_ch = ch;
|
||
m_iLength = iLength;
|
||
}
|
||
|
||
void operator()(LPENTITY ent)
|
||
{
|
||
if (ent->IsType(ENTITY_CHARACTER))
|
||
{
|
||
LPCHARACTER ch = (LPCHARACTER) ent;
|
||
if (ch->IsPC())
|
||
return;
|
||
if (!ch->IsMonster())
|
||
return;
|
||
//if (ch->GetVictim() && ch->GetVictim() != m_ch)
|
||
//return;
|
||
float fDist = DISTANCE_APPROX(m_ch->GetX() - ch->GetX(), m_ch->GetY() - ch->GetY());
|
||
if (fDist > 3000 || fDist < 100)
|
||
return;
|
||
|
||
float fNewDist = fDist - m_iLength;
|
||
if (fNewDist < 100)
|
||
fNewDist = 100;
|
||
|
||
float degree = GetDegreeFromPositionXY(ch->GetX(), ch->GetY(), m_ch->GetX(), m_ch->GetY());
|
||
float fx;
|
||
float fy;
|
||
|
||
GetDeltaByDegree(degree, fDist - fNewDist, &fx, &fy);
|
||
int tx = (int)(ch->GetX() + fx);
|
||
int ty = (int)(ch->GetY() + fy);
|
||
|
||
ch->Sync(tx, ty);
|
||
ch->Goto(tx, ty);
|
||
ch->CalculateMoveDuration();
|
||
|
||
ch->SyncPacket();
|
||
}
|
||
}
|
||
};
|
||
|
||
void CHARACTER::ForgetMyAttacker()
|
||
{
|
||
LPSECTREE pSec = GetSectree();
|
||
if (pSec)
|
||
{
|
||
FuncForgetMyAttacker f(this);
|
||
pSec->ForEachAround(f);
|
||
}
|
||
ReviveInvisible(5);
|
||
}
|
||
|
||
void CHARACTER::AggregateMonster()
|
||
{
|
||
LPSECTREE pSec = GetSectree();
|
||
if (pSec)
|
||
{
|
||
FuncAggregateMonster f(this);
|
||
pSec->ForEachAround(f);
|
||
}
|
||
}
|
||
|
||
void CHARACTER::AttractRanger()
|
||
{
|
||
LPSECTREE pSec = GetSectree();
|
||
if (pSec)
|
||
{
|
||
FuncAttractRanger f(this);
|
||
pSec->ForEachAround(f);
|
||
}
|
||
}
|
||
|
||
void CHARACTER::PullMonster()
|
||
{
|
||
LPSECTREE pSec = GetSectree();
|
||
if (pSec)
|
||
{
|
||
FuncPullMonster f(this);
|
||
pSec->ForEachAround(f);
|
||
}
|
||
}
|
||
|
||
void CHARACTER::UpdateAggrPointEx(LPCHARACTER pAttacker, EDamageType type, int dam, CHARACTER::TBattleInfo & info)
|
||
{
|
||
// Ư<><C6AF> <20><><EFBFBD><EFBFBD>Ÿ<EFBFBD>Կ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><> <20>ö<C3B6>
|
||
switch (type)
|
||
{
|
||
case DAMAGE_TYPE_NORMAL_RANGE:
|
||
dam = (int) (dam*1.2f);
|
||
break;
|
||
|
||
case DAMAGE_TYPE_RANGE:
|
||
dam = (int) (dam*1.5f);
|
||
break;
|
||
|
||
case DAMAGE_TYPE_MAGIC:
|
||
dam = (int) (dam*1.2f);
|
||
break;
|
||
|
||
default:
|
||
break;
|
||
}
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD>ڰ<EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ʽ<EFBFBD><CABD><EFBFBD> <20>ش<EFBFBD>.
|
||
if (pAttacker == GetVictim())
|
||
dam = (int) (dam * 1.2f);
|
||
|
||
info.iAggro += dam;
|
||
|
||
if (info.iAggro < 0)
|
||
info.iAggro = 0;
|
||
|
||
//sys_log(0, "UpdateAggrPointEx for %s by %s dam %d total %d", GetName(), pAttacker->GetName(), dam, total);
|
||
if (GetParty() && dam > 0 && type != DAMAGE_TYPE_SPECIAL)
|
||
{
|
||
LPPARTY pParty = GetParty();
|
||
|
||
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD> <20><><EFBFBD>ϴ<EFBFBD>
|
||
int iPartyAggroDist = dam;
|
||
|
||
if (pParty->GetLeaderPID() == GetVID())
|
||
iPartyAggroDist /= 2;
|
||
else
|
||
iPartyAggroDist /= 3;
|
||
|
||
pParty->SendMessage(this, PM_AGGRO_INCREASE, iPartyAggroDist, pAttacker->GetVID());
|
||
}
|
||
|
||
ChangeVictimByAggro(info.iAggro, pAttacker);
|
||
}
|
||
|
||
void CHARACTER::UpdateAggrPoint(LPCHARACTER pAttacker, EDamageType type, int dam)
|
||
{
|
||
if (IsDead() || IsStun())
|
||
return;
|
||
|
||
TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
|
||
|
||
if (it == m_map_kDamage.end())
|
||
{
|
||
m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(0, dam)));
|
||
it = m_map_kDamage.find(pAttacker->GetVID());
|
||
}
|
||
|
||
UpdateAggrPointEx(pAttacker, type, dam, it->second);
|
||
}
|
||
|
||
void CHARACTER::ChangeVictimByAggro(int iNewAggro, LPCHARACTER pNewVictim)
|
||
{
|
||
if (get_dword_time() - m_dwLastVictimSetTime < 3000) // 3<>ʴ<EFBFBD> <20><><EFBFBD>ٷ<EFBFBD><D9B7><EFBFBD><EFBFBD>Ѵ<EFBFBD>
|
||
return;
|
||
|
||
if (pNewVictim == GetVictim())
|
||
{
|
||
if (m_iMaxAggro < iNewAggro)
|
||
{
|
||
m_iMaxAggro = iNewAggro;
|
||
return;
|
||
}
|
||
|
||
// Aggro<72><6F> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD>
|
||
TDamageMap::iterator it;
|
||
TDamageMap::iterator itFind = m_map_kDamage.end();
|
||
|
||
for (it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
|
||
{
|
||
if (it->second.iAggro > iNewAggro)
|
||
{
|
||
LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
|
||
|
||
if (ch && !ch->IsDead() && DISTANCE_APPROX(ch->GetX() - GetX(), ch->GetY() - GetY()) < 5000)
|
||
{
|
||
itFind = it;
|
||
iNewAggro = it->second.iAggro;
|
||
}
|
||
}
|
||
}
|
||
|
||
if (itFind != m_map_kDamage.end())
|
||
{
|
||
m_iMaxAggro = iNewAggro;
|
||
SetVictim(CHARACTER_MANAGER::instance().Find(itFind->first));
|
||
m_dwStateDuration = 1;
|
||
}
|
||
}
|
||
else
|
||
{
|
||
if (m_iMaxAggro < iNewAggro)
|
||
{
|
||
m_iMaxAggro = iNewAggro;
|
||
SetVictim(pNewVictim);
|
||
m_dwStateDuration = 1;
|
||
}
|
||
}
|
||
}
|
||
|