server/game/src/char_battle.cpp

3649 lines
82 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#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;
}
}
}