Facebook
From Colorant Pheasant, 3 Years ago, written in C++.
Embed
Download Paste or View Raw
Hits: 176
  1. #include "stdafx.h"
  2. #include "utils.h"
  3. #include "config.h"
  4. #include "desc.h"
  5. #include "desc_manager.h"
  6. #include "char_manager.h"
  7. #include "item.h"
  8. #include "item_manager.h"
  9. #include "mob_manager.h"
  10. #include "battle.h"
  11. #include "pvp.h"
  12. #include "skill.h"
  13. #include "start_position.h"
  14. #include "profiler.h"
  15. #include "cmd.h"
  16. #include "dungeon.h"
  17. #include "log.h"
  18. #include "unique_item.h"
  19. #include "priv_manager.h"
  20. #include "db.h"
  21. #include "vector.h"
  22. #include "marriage.h"
  23. #include "arena.h"
  24. #include "regen.h"
  25. #include "monarch.h"
  26. #include "exchange.h"
  27. #include "shop_manager.h"
  28. #include "castle.h"
  29. #include "dev_log.h"
  30. #include "ani.h"
  31. #include "BattleArena.h"
  32. #include "packet.h"
  33. #include "party.h"
  34. #include "affect.h"
  35. #include "guild.h"
  36. #include "guild_manager.h"
  37. #include "questmanager.h"
  38. #include "questlua.h"
  39. #include "threeway_war.h"
  40. #include "BlueDragon.h"
  41. #include "DragonLair.h"
  42. #ifdef ENABLE_WAR_KILL_NOTICE
  43. #include "war_map.h"
  44. #endif
  45. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  46. #include "offlineshop.h"
  47. #endif
  48. #ifdef ENABLE_NEW_PET_SYSTEM
  49. #include "New_PetSystem.h"
  50. #endif
  51. #ifdef ENABLE_SUPPORT_SHAMAN_SYSTEM
  52. #include "support_shaman.h"
  53. #endif
  54.  
  55. #define ENABLE_EFFECT_PENETRATE
  56. static DWORD __GetPartyExpNP(const DWORD level)
  57. {
  58.         if (!level || level > PLAYER_EXP_TABLE_MAX)
  59.                 return 14000;
  60.         return party_exp_distribute_table[level];
  61. }
  62.  
  63. static int __GetExpLossPerc(const DWORD level)
  64. {
  65.         if (!level || level > PLAYER_EXP_TABLE_MAX)
  66.                 return 1;
  67.         return aiExpLossPercents[level];
  68. }
  69.  
  70. DWORD AdjustExpByLevel(const LPCHARACTER ch, const DWORD exp)
  71. {
  72.         if (PLAYER_MAX_LEVEL_CONST < ch->GetLevel())
  73.         {
  74.                 double ret = 0.95;
  75.                 double factor = 0.1;
  76.  
  77.                 for (ssize_t i = 0; i < ch->GetLevel() - 100; ++i)
  78.                 {
  79.                         if ((i % 10) == 0)
  80.                                 factor /= 2.0;
  81.  
  82.                         ret *= 1.0 - factor;
  83.                 }
  84.  
  85.                 ret = ret * static_cast<double>(exp);
  86.  
  87.                 if (ret < 1.0)
  88.                         return 1;
  89.  
  90.                 return static_cast<DWORD>(ret);
  91.         }
  92.  
  93.         return exp;
  94. }
  95.  
  96. bool CHARACTER::CanBeginFight() const
  97. {
  98.         if (!CanMove())
  99.                 return false;
  100.  
  101.         return m_pointsInstant.position == POS_STANDING && !IsDead() && !IsStun();
  102. }
  103.  
  104. void CHARACTER::BeginFight(LPCHARACTER pkVictim)
  105. {
  106.         SetVictim(pkVictim);
  107.         SetPosition(POS_FIGHTING);
  108.         SetNextStatePulse(1);
  109. }
  110.  
  111. bool CHARACTER::CanFight() const
  112. {
  113.         return m_pointsInstant.position >= POS_FIGHTING ? true : false;
  114. }
  115.  
  116. void CHARACTER::CreateFly(BYTE bType, LPCHARACTER pkVictim)
  117. {
  118.         TPacketGCCreateFly packFly;
  119.  
  120.         packFly.bHeader = HEADER_GC_CREATE_FLY;
  121.         packFly.bType = bType;
  122.         packFly.dwStartVID = GetVID();
  123.         packFly.dwEndVID = pkVictim->GetVID();
  124.  
  125.         PacketAround(&packFly, sizeof(TPacketGCCreateFly));
  126. }
  127.  
  128. void CHARACTER::DistributeSP(LPCHARACTER pkKiller, int iMethod)
  129. {
  130.         if (pkKiller->GetSP() >= pkKiller->GetMaxSP())
  131.                 return;
  132.  
  133.         bool bAttacking = (get_dword_time() - GetLastAttackTime()) < 3000;
  134.         bool bMoving = (get_dword_time() - GetLastMoveTime()) < 3000;
  135.  
  136.         if (iMethod == 1)
  137.         {
  138.                 int num = number(0, 3);
  139.  
  140.                 if (!num)
  141.                 {
  142.                         int iLvDelta = GetLevel() - pkKiller->GetLevel();
  143.                         int iAmount = 0;
  144.  
  145.                         if (iLvDelta >= 5)
  146.                                 iAmount = 10;
  147.                         else if (iLvDelta >= 0)
  148.                                 iAmount = 6;
  149.                         else if (iLvDelta >= -3)
  150.                                 iAmount = 2;
  151.  
  152.                         if (iAmount != 0)
  153.                         {
  154.                                 iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
  155.  
  156.                                 if (iAmount >= 11)
  157.                                         CreateFly(FLY_SP_BIG, pkKiller);
  158.                                 else if (iAmount >= 7)
  159.                                         CreateFly(FLY_SP_MEDIUM, pkKiller);
  160.                                 else
  161.                                         CreateFly(FLY_SP_SMALL, pkKiller);
  162.  
  163.                                 pkKiller->PointChange(POINT_SP, iAmount);
  164.                         }
  165.                 }
  166.         }
  167.         else
  168.         {
  169.                 if (pkKiller->GetJob() == JOB_SHAMAN || (pkKiller->GetJob() == JOB_SURA && pkKiller->GetSkillGroup() == 2))
  170.                 {
  171.                         int iAmount;
  172.  
  173.                         if (bAttacking)
  174.                                 iAmount = 2 + GetMaxSP() / 100;
  175.                         else if (bMoving)
  176.                                 iAmount = 3 + GetMaxSP() * 2 / 100;
  177.                         else
  178.                                 iAmount = 10 + GetMaxSP() * 3 / 100;
  179.  
  180.                         iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
  181.                         pkKiller->PointChange(POINT_SP, iAmount);
  182.                 }
  183.                 else
  184.                 {
  185.                         int iAmount;
  186.  
  187.                         if (bAttacking)
  188.                                 iAmount = 2 + pkKiller->GetMaxSP() / 200;
  189.                         else if (bMoving)
  190.                                 iAmount = 2 + pkKiller->GetMaxSP() / 100;
  191.                         else
  192.                         {
  193.                                 if (pkKiller->GetHP() < pkKiller->GetMaxHP())
  194.                                         iAmount = 2 + (pkKiller->GetMaxSP() / 100);
  195.                                 else
  196.                                         iAmount = 9 + (pkKiller->GetMaxSP() / 100);
  197.                         }
  198.  
  199.                         iAmount += (iAmount * pkKiller->GetPoint(POINT_SP_REGEN)) / 100;
  200.                         pkKiller->PointChange(POINT_SP, iAmount);
  201.                 }
  202.         }
  203. }
  204.  
  205. bool CHARACTER::Attack(LPCHARACTER pkVictim, BYTE bType)
  206. {
  207.         if (pkVictim->GetShopOwner())//@fixme242
  208.                 return false;
  209.         if (test_server)
  210.                 sys_log(0, "[TEST_SERVER] Attack : %s type %d, MobBattleType %d", GetName(), bType, !GetMobBattleType() ? 0 : GetMobAttackRange());
  211.         //PROF_UNIT puAttack("Attack");
  212.         if (!CanMove() || IsObserverMode()) //@fixme232
  213.                 return false;
  214.  
  215. #ifdef ENABLE_PLAYER_SECURITY_SYSTEM
  216.         if (IsPC() && IsActivateSecurity())
  217.         {
  218.                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT("GUVENLIK_KILIDI_ACIKKEN_ATAK_YAPAMASSIN."));
  219.                 return false;
  220.         }
  221.  
  222.         if (pkVictim && pkVictim->IsPC() && pkVictim->IsActivateSecurity())
  223.         {
  224.                 if(IsPC())
  225.                         ChatPacket(CHAT_TYPE_INFO, LC_TEXT("GUVENLIK_KILIDI_ACIK_OLAN_KARAKTERE_ATAK_YAPAMASSIN."));
  226.                 return false;
  227.         }
  228. #endif
  229.  
  230.         // CASTLE
  231.         if (IS_CASTLE_MAP(GetMapIndex()) && false == castle_can_attack(this, pkVictim))
  232.                 return false;
  233.         // CASTLE
  234.  
  235.         // @fixme131
  236.         if (!battle_is_attackable(this, pkVictim))
  237.                 return false;
  238.  
  239.         DWORD dwCurrentTime = get_dword_time();
  240.  
  241.         if (IsPC())
  242.         {
  243.                 if (IS_SPEED_HACK(this, pkVictim, dwCurrentTime))
  244.                         return false;
  245.  
  246.                 if (bType == 0 && dwCurrentTime < GetSkipComboAttackByTime())
  247.                         return false;
  248.         }
  249.         else
  250.         {
  251.                 MonsterChat(MONSTER_CHAT_ATTACK);
  252.         }
  253.  
  254.         pkVictim->SetSyncOwner(this);
  255.  
  256.         if (pkVictim->CanBeginFight())
  257.                 pkVictim->BeginFight(this);
  258.  
  259.         int iRet;
  260.  
  261.         if (bType == 0)
  262.         {
  263.                 //
  264.  
  265.                 //
  266.                 switch (GetMobBattleType())
  267.                 {
  268.                 case BATTLE_TYPE_MELEE:
  269.                 case BATTLE_TYPE_POWER:
  270.                 case BATTLE_TYPE_TANKER:
  271.                 case BATTLE_TYPE_SUPER_POWER:
  272.                 case BATTLE_TYPE_SUPER_TANKER:
  273.                         iRet = battle_melee_attack(this, pkVictim);
  274.                         break;
  275.  
  276.                 case BATTLE_TYPE_RANGE:
  277.                         FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
  278.                         iRet = Shoot(0) ? BATTLE_DAMAGE : BATTLE_NONE;
  279.                         break;
  280.  
  281.                 case BATTLE_TYPE_MAGIC:
  282.                         FlyTarget(pkVictim->GetVID(), pkVictim->GetX(), pkVictim->GetY(), HEADER_CG_FLY_TARGETING);
  283.                         iRet = Shoot(1) ? BATTLE_DAMAGE : BATTLE_NONE;
  284.                         break;
  285.  
  286.                 default:
  287.                         sys_err("Unhandled battle type %d", GetMobBattleType());
  288.                         iRet = BATTLE_NONE;
  289.                         break;
  290.                 }
  291.         }
  292.         else
  293.         {
  294.                 if (IsPC() == true)
  295.                 {
  296.                         if (dwCurrentTime - m_dwLastSkillTime > 1500)
  297.                         {
  298.                                 sys_log(1, "HACK: Too long skill using term. Name(%s) PID(%u) delta(%u)",
  299.                                         GetName(), GetPlayerID(), (dwCurrentTime - m_dwLastSkillTime));
  300.                                 return false;
  301.                         }
  302.                 }
  303.  
  304.                 sys_log(1, "Attack call ComputeSkill %d %s", bType, pkVictim ? pkVictim->GetName() : "");
  305.                 iRet = ComputeSkill(bType, pkVictim);
  306.         }
  307.  
  308.         //if (test_server && IsPC())
  309.         //      sys_log(0, "%s Attack %s type %u ret %d", GetName(), pkVictim->GetName(), bType, iRet);
  310.         if (iRet == BATTLE_DAMAGE || iRet == BATTLE_DEAD)
  311.         {
  312.                 OnMove(true);
  313.                 pkVictim->OnMove();
  314.  
  315.                 // only pc sets victim null. For npc, state machine will reset this.
  316.                 if (BATTLE_DEAD == iRet && IsPC())
  317.                         SetVictim(NULL);
  318.  
  319.                 return true;
  320.         }
  321.  
  322.         return false;
  323. }
  324.  
  325. void CHARACTER::DeathPenalty(BYTE bTown)
  326. {
  327.         sys_log(1, "DEATH_PERNALY_CHECK(%s) town(%d)", GetName(), bTown);
  328.  
  329.         Cube_close(this);
  330. #ifdef ENABLE_ACCE_SYSTEM
  331.         CloseAcce();
  332. #endif
  333. #ifdef ENABLE_AURA_SYSTEM
  334.         if (IsPC())
  335.                 CloseAura();
  336. #endif
  337.         if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
  338.         {
  339.                 return;
  340.         }
  341.  
  342.         if (GetLevel() < 10)
  343.         {
  344.                 sys_log(0, "NO_DEATH_PENALTY_LESS_LV10(%s)", GetName());
  345.                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 가호로 경험치가 떨어지지 않았습니다."));
  346.                 return;
  347.         }
  348.  
  349.         if (number(0, 2))
  350.         {
  351.                 sys_log(0, "NO_DEATH_PENALTY_LUCK(%s)", GetName());
  352.                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 가호로 경험치가 떨어지지 않았습니다."));
  353.                 return;
  354.         }
  355.  
  356.         if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY))
  357.         {
  358.                 REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
  359.  
  360.                 // NO_DEATH_PENALTY_BUG_FIX
  361.                 if (!bTown)
  362.                 {
  363.                         if (FindAffect(AFFECT_NO_DEATH_PENALTY))
  364.                         {
  365.                                 sys_log(0, "NO_DEATH_PENALTY_AFFECT(%s)", GetName());
  366.                                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 가호로 경험치가 떨어지지 않았습니다."));
  367.                                 RemoveAffect(AFFECT_NO_DEATH_PENALTY);
  368.                                 return;
  369.                         }
  370.                 }
  371.                 // END_OF_NO_DEATH_PENALTY_BUG_FIX
  372.  
  373.                 int iLoss = ((GetNextExp() * __GetExpLossPerc(GetLevel())) / 100);
  374.  
  375.                 iLoss = MIN(800000, iLoss);
  376.  
  377.                 if (bTown)
  378.                         iLoss = 0;
  379.  
  380.                 if (IsEquipUniqueItem(UNIQUE_ITEM_TEARDROP_OF_GODNESS))
  381.                         iLoss /= 2;
  382.  
  383.                 sys_log(0, "DEATH_PENALTY(%s) EXP_LOSS: %d percent %d%%", GetName(), iLoss, __GetExpLossPerc(GetLevel()));
  384.  
  385.                 PointChange(POINT_EXP, -iLoss, true);
  386.         }
  387. }
  388.  
  389. bool CHARACTER::IsStun() const
  390. {
  391.         if (IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN))
  392.                 return true;
  393.  
  394.         return false;
  395. }
  396.  
  397. EVENTFUNC(StunEvent)
  398. {
  399.         char_event_info* info = dynamic_cast<char_event_info*>(event->info);
  400.  
  401.         if (info == NULL)
  402.         {
  403.                 sys_err("StunEvent> <Factor> Null pointer");
  404.                 return 0;
  405.         }
  406.  
  407.         LPCHARACTER ch = info->ch;
  408.  
  409.         if (ch == NULL) { // <Factor>
  410.                 return 0;
  411.         }
  412.         ch->m_pkStunEvent = NULL;
  413.         ch->Dead();
  414.         return 0;
  415. }
  416.  
  417. void CHARACTER::Stun()
  418. {
  419.         if (IsStun())
  420.                 return;
  421.  
  422.         if (IsDead())
  423.                 return;
  424.  
  425.         if (!IsPC() && m_pkParty)
  426.         {
  427.                 m_pkParty->SendMessage(this, PM_ATTACKED_BY, 0, 0);
  428.         }
  429.  
  430.         sys_log(1, "%s: Stun %p", GetName(), this);
  431.  
  432.         PointChange(POINT_HP_RECOVERY, -GetPoint(POINT_HP_RECOVERY));
  433.         PointChange(POINT_SP_RECOVERY, -GetPoint(POINT_SP_RECOVERY));
  434.  
  435.         CloseMyShop();
  436.  
  437.         event_cancel(&m_pkRecoveryEvent);
  438.  
  439.         TPacketGCStun pack;
  440.         pack.header = HEADER_GC_STUN;
  441.         pack.vid = m_vid;
  442.         PacketAround(&pack, sizeof(pack));
  443.  
  444.         SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
  445.  
  446.         if (m_pkStunEvent)
  447.                 return;
  448.  
  449.         char_event_info* info = AllocEventInfo<char_event_info>();
  450.  
  451.         info->ch = this;
  452.  
  453.         m_pkStunEvent = event_create(StunEvent, info, PASSES_PER_SEC(3));
  454. }
  455.  
  456. EVENTINFO(SCharDeadEventInfo)
  457. {
  458.         bool isPC;
  459.         uint32_t dwID;
  460.  
  461.         SCharDeadEventInfo()
  462.                 : isPC(0)
  463.                 , dwID(0)
  464.         {
  465.         }
  466. };
  467.  
  468. EVENTFUNC(dead_event)
  469. {
  470.         const SCharDeadEventInfo* info = dynamic_cast<SCharDeadEventInfo*>(event->info);
  471.  
  472.         if (info == NULL)
  473.         {
  474.                 sys_err("dead_event> <Factor> Null pointer");
  475.                 return 0;
  476.         }
  477.  
  478.         LPCHARACTER ch = NULL;
  479.  
  480.         if (true == info->isPC)
  481.         {
  482.                 ch = CHARACTER_MANAGER::instance().FindByPID(info->dwID);
  483.         }
  484.         else
  485.         {
  486.                 ch = CHARACTER_MANAGER::instance().Find(info->dwID);
  487.         }
  488.  
  489.         if (NULL == ch)
  490.         {
  491.                 sys_err("DEAD_EVENT: cannot find char pointer with %s id(%d)", info->isPC ? "PC" : "MOB", info->dwID);
  492.                 return 0;
  493.         }
  494.  
  495.         ch->m_pkDeadEvent = NULL;
  496.  
  497.         if (ch->GetDesc())
  498.         {
  499.                 ch->GetDesc()->SetPhase(PHASE_GAME);
  500.  
  501.                 ch->SetPosition(POS_STANDING);
  502.  
  503.                 PIXEL_POSITION pos;
  504.  
  505.                 if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
  506.                         ch->WarpSet(pos.x, pos.y);
  507.                 else
  508.                 {
  509.                         sys_err("cannot find spawn position (name %s)", ch->GetName());
  510.                         ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
  511.                 }
  512.  
  513.                 ch->PointChange(POINT_HP, (ch->GetMaxHP() / 2) - ch->GetHP(), true);
  514.  
  515.                 ch->DeathPenalty(0);
  516.  
  517.                 ch->StartRecoveryEvent();
  518.  
  519.                 ch->ChatPacket(CHAT_TYPE_COMMAND, "CloseRestartWindow");
  520.         }
  521.         else
  522.         {
  523.                 if (ch->IsMonster() == true)
  524.                 {
  525.                         if (ch->IsRevive() == false && ch->HasReviverInParty() == true)
  526.                         {
  527.                                 ch->SetPosition(POS_STANDING);
  528.                                 ch->SetHP(ch->GetMaxHP());
  529.  
  530.                                 ch->ViewReencode();
  531.  
  532.                                 ch->SetAggressive();
  533.                                 ch->SetRevive(true);
  534.  
  535.                                 return 0;
  536.                         }
  537.                 }
  538.  
  539.                 M2_DESTROY_CHARACTER(ch);
  540.         }
  541.  
  542.         return 0;
  543. }
  544.  
  545. bool CHARACTER::IsDead() const
  546. {
  547.         if (m_pointsInstant.position == POS_DEAD)
  548.                 return true;
  549.  
  550.         return false;
  551. }
  552.  
  553. #ifndef GetGoldMultipler
  554. #define GetGoldMultipler = 1;
  555. #endif
  556. #ifdef ENABLE_GOLD_REWARD_RENEWAL
  557. void CHARACTER::RewardGold(LPCHARACTER pkAttacker)
  558. {
  559.         int iTotalGold = 0;
  560.         int iGoldPercent = MobRankStats[GetMobRank()].iGoldPercent;
  561.  
  562.         if (pkAttacker->IsPC())
  563.                 iGoldPercent = iGoldPercent * (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD_DROP)) / 100;
  564.  
  565.         if (pkAttacker->GetPoint(POINT_MALL_GOLDBONUS))
  566.                 iGoldPercent += (iGoldPercent * pkAttacker->GetPoint(POINT_MALL_GOLDBONUS) / 100);
  567.  
  568.         iGoldPercent = iGoldPercent * CHARACTER_MANAGER::instance().GetMobGoldDropRate(pkAttacker) / 100;
  569.  
  570.         if (pkAttacker->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0 || pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_LUCKY_GOLD))
  571.                 iGoldPercent += iGoldPercent;
  572.  
  573.         if (iGoldPercent > 100)
  574.                 iGoldPercent = 100;
  575.  
  576.         int iPercent;
  577.  
  578.         if (GetMobRank() >= MOB_RANK_BOSS)
  579.                 iPercent = ((iGoldPercent * PERCENT_LVDELTA_BOSS(pkAttacker->GetLevel(), GetLevel())) / 100);
  580.         else
  581.                 iPercent = ((iGoldPercent * PERCENT_LVDELTA(pkAttacker->GetLevel(), GetLevel())) / 100);
  582.  
  583.         if (number(1, 100) > iPercent)
  584.                 return;
  585.  
  586.         int iGoldMultipler = GetGoldMultipler;
  587.  
  588.         if (1 == number(1, 50000))
  589.                 iGoldMultipler *= 10;
  590.         else if (1 == number(1, 10000))
  591.                 iGoldMultipler *= 5;
  592.  
  593.         if (pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
  594.                 if (number(1, 100) <= pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
  595.                         iGoldMultipler *= 2;
  596.  
  597.         if (test_server)
  598.                 pkAttacker->ChatPacket(CHAT_TYPE_PARTY, "gold_mul %d rate %d", iGoldMultipler, CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker));
  599.         int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
  600.         iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
  601.         iGold *= iGoldMultipler;
  602.  
  603.         int iSplitCount;
  604.  
  605.         if (iGold >= 3)
  606.                 iSplitCount = number(1, 3);
  607.         else if (GetMobRank() >= MOB_RANK_BOSS)
  608.         {
  609.                 iSplitCount = number(3, 10);
  610.  
  611.                 if ((iGold / iSplitCount) == 0)
  612.                         iSplitCount = 1;
  613.         }
  614.         else
  615.                 iSplitCount = 1;
  616.  
  617.         if (iGold != 0)
  618.         {
  619.                 iTotalGold += iGold;
  620.  
  621.                 for (int i = 0; i < iSplitCount; ++i)
  622.                 {
  623.                         pkAttacker->GiveGold(iGold / iSplitCount);
  624.                 }
  625.         }
  626.  
  627.         DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER, GetRaceNum(), iTotalGold);
  628. }
  629. #else
  630. #define GetGoldMultipler() (distribution_test_server ? 3 : 1)
  631. void CHARACTER::RewardGold(LPCHARACTER pkAttacker)
  632. {
  633.         // ADD_PREMIUM
  634.         bool isAutoLoot =
  635.                 (pkAttacker->GetPremiumRemainSeconds(PREMIUM_AUTOLOOT) > 0 ||
  636.                         pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_AUTOLOOT))
  637.                 ? true : false;
  638.         // END_OF_ADD_PREMIUM
  639.  
  640.         PIXEL_POSITION pos;
  641.  
  642.         if (!isAutoLoot)
  643.                 if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
  644.                         return;
  645.  
  646.         int iTotalGold = 0;
  647.         //
  648.  
  649.         //
  650.         int iGoldPercent = MobRankStats[GetMobRank()].iGoldPercent;
  651.  
  652.         if (pkAttacker->IsPC())
  653.                 iGoldPercent = iGoldPercent * (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD_DROP)) / 100;
  654.  
  655.         if (pkAttacker->GetPoint(POINT_MALL_GOLDBONUS))
  656.                 iGoldPercent += (iGoldPercent * pkAttacker->GetPoint(POINT_MALL_GOLDBONUS) / 100);
  657.  
  658.         iGoldPercent = iGoldPercent * CHARACTER_MANAGER::instance().GetMobGoldDropRate(pkAttacker) / 100;
  659.  
  660.         // ADD_PREMIUM
  661.         if (pkAttacker->GetPremiumRemainSeconds(PREMIUM_GOLD) > 0 ||
  662.                 pkAttacker->IsEquipUniqueGroup(UNIQUE_GROUP_LUCKY_GOLD))
  663.                 iGoldPercent += iGoldPercent;
  664.         // END_OF_ADD_PREMIUM
  665.  
  666.         if (iGoldPercent > 100)
  667.                 iGoldPercent = 100;
  668.  
  669.         int iPercent;
  670.  
  671.         if (GetMobRank() >= MOB_RANK_BOSS)
  672.                 iPercent = ((iGoldPercent * PERCENT_LVDELTA_BOSS(pkAttacker->GetLevel(), GetLevel())) / 100);
  673.         else
  674.                 iPercent = ((iGoldPercent * PERCENT_LVDELTA(pkAttacker->GetLevel(), GetLevel())) / 100);
  675.         //int iPercent = CALCULATE_VALUE_LVDELTA(pkAttacker->GetLevel(), GetLevel(), iGoldPercent);
  676.  
  677.         if (number(1, 100) > iPercent)
  678.                 return;
  679.  
  680.         int iGoldMultipler = GetGoldMultipler();
  681.  
  682.         if (1 == number(1, 50000))
  683.                 iGoldMultipler *= 10;
  684.         else if (1 == number(1, 10000))
  685.                 iGoldMultipler *= 5;
  686.  
  687.         if (pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
  688.                 if (number(1, 100) <= pkAttacker->GetPoint(POINT_GOLD_DOUBLE_BONUS))
  689.                         iGoldMultipler *= 2;
  690.  
  691.         //
  692.  
  693.         //
  694.         if (test_server)
  695.                 pkAttacker->ChatPacket(CHAT_TYPE_PARTY, "gold_mul %d rate %d", iGoldMultipler, CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker));
  696.  
  697.         //
  698.         // --------- 실제 드롭 처리 -------------
  699.         //
  700.         LPITEM item;
  701.  
  702.         int iGold10DropPct = 100;
  703.         iGold10DropPct = (iGold10DropPct * 100) / (100 + CPrivManager::instance().GetPriv(pkAttacker, PRIV_GOLD10_DROP));
  704.  
  705.         if (GetMobRank() >= MOB_RANK_BOSS && !IsStone() && GetMobTable().dwGoldMax != 0)
  706.         {
  707.                 if (1 == number(1, iGold10DropPct))
  708.                         iGoldMultipler *= 10;
  709.  
  710.                 int iSplitCount = number(25, 35);
  711.  
  712.                 for (int i = 0; i < iSplitCount; ++i)
  713.                 {
  714.                         int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax) / iSplitCount;
  715.                         if (test_server)
  716.                                 sys_log(0, "iGold %d", iGold);
  717.                         iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
  718.                         iGold *= iGoldMultipler;
  719.  
  720.                         if (iGold == 0)
  721.                         {
  722.                                 continue;
  723.                         }
  724.  
  725.                         if (test_server)
  726.                         {
  727.                                 sys_log(0, "Drop Moeny MobGoldAmountRate %d %d", CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker), iGoldMultipler);
  728.                                 sys_log(0, "Drop Money gold %d GoldMin %d GoldMax %d", iGold, GetMobTable().dwGoldMax, GetMobTable().dwGoldMax);
  729.                         }
  730.  
  731.                         if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
  732.                         {
  733.                                 pos.x = GetX() + ((number(-14, 14) + number(-14, 14)) * 23);
  734.                                 pos.y = GetY() + ((number(-14, 14) + number(-14, 14)) * 23);
  735.  
  736.                                 item->AddToGround(GetMapIndex(), pos);
  737.                                 item->StartDestroyEvent();
  738.  
  739.                                 iTotalGold += iGold; // Total gold
  740.                         }
  741.                 }
  742.         }
  743.  
  744.         else if (1 == number(1, iGold10DropPct))
  745.         {
  746.                 //
  747.  
  748.                 //
  749.                 for (int i = 0; i < 10; ++i)
  750.                 {
  751.                         int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
  752.                         iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
  753.                         iGold *= iGoldMultipler;
  754.  
  755.                         if (iGold == 0)
  756.                         {
  757.                                 continue;
  758.                         }
  759.  
  760.                         if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold)))
  761.                         {
  762.                                 pos.x = GetX() + (number(-7, 7) * 20);
  763.                                 pos.y = GetY() + (number(-7, 7) * 20);
  764.  
  765.                                 item->AddToGround(GetMapIndex(), pos);
  766.                                 item->StartDestroyEvent();
  767.  
  768.                                 iTotalGold += iGold; // Total gold
  769.                         }
  770.                 }
  771.         }
  772.         else
  773.         {
  774.                 //
  775.  
  776.                 //
  777.                 int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
  778.                 iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(pkAttacker) / 100;
  779.                 iGold *= iGoldMultipler;
  780.  
  781.                 int iSplitCount;
  782.  
  783.                 if (iGold >= 3)
  784.                         iSplitCount = number(1, 3);
  785.                 else if (GetMobRank() >= MOB_RANK_BOSS)
  786.                 {
  787.                         iSplitCount = number(3, 10);
  788.  
  789.                         if ((iGold / iSplitCount) == 0)
  790.                                 iSplitCount = 1;
  791.                 }
  792.                 else
  793.                         iSplitCount = 1;
  794.  
  795.                 if (iGold != 0)
  796.                 {
  797.                         iTotalGold += iGold; // Total gold
  798.  
  799.                         for (int i = 0; i < iSplitCount; ++i)
  800.                         {
  801.                                 if (isAutoLoot)
  802.                                 {
  803.                                         pkAttacker->GiveGold(iGold / iSplitCount);
  804.                                 }
  805.                                 else if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
  806.                                 {
  807.                                         pos.x = GetX() + (number(-7, 7) * 20);
  808.                                         pos.y = GetY() + (number(-7, 7) * 20);
  809.  
  810.                                         item->AddToGround(GetMapIndex(), pos);
  811.                                         item->StartDestroyEvent();
  812.                                 }
  813.                         }
  814.                 }
  815.         }
  816.  
  817.         DBManager::instance().SendMoneyLog(MONEY_LOG_MONSTER, GetRaceNum(), iTotalGold);
  818. }
  819. #endif
  820. void CHARACTER::Reward(bool bItemDrop)
  821. {
  822.         if (GetRaceNum() == 5001)
  823.         {
  824.                 PIXEL_POSITION pos;
  825.  
  826.                 if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), GetX(), GetY(), pos))
  827.                         return;
  828.  
  829.                 LPITEM item;
  830.                 int iGold = number(GetMobTable().dwGoldMin, GetMobTable().dwGoldMax);
  831.                 iGold = iGold * CHARACTER_MANAGER::instance().GetMobGoldAmountRate(NULL) / 100;
  832.                 iGold *= GetGoldMultipler;
  833.                 int iSplitCount = number(25, 35);
  834.  
  835.                 sys_log(0, "WAEGU Dead gold %d split %d", iGold, iSplitCount);
  836.  
  837.                 for (int i = 1; i <= iSplitCount; ++i)
  838.                 {
  839.                         if ((item = ITEM_MANAGER::instance().CreateItem(1, iGold / iSplitCount)))
  840.                         {
  841.                                 if (i != 0)
  842.                                 {
  843.                                         pos.x = number(-7, 7) * 20;
  844.                                         pos.y = number(-7, 7) * 20;
  845.  
  846.                                         pos.x += GetX();
  847.                                         pos.y += GetY();
  848.                                 }
  849.  
  850.                                 item->AddToGround(GetMapIndex(), pos);
  851.                                 item->StartDestroyEvent();
  852.                         }
  853.                 }
  854.                 return;
  855.         }
  856.  
  857.         //PROF_UNIT puReward("Reward");
  858.         LPCHARACTER pkAttacker = DistributeExp();
  859.  
  860.         if (!pkAttacker)
  861.                 return;
  862.  
  863.         //PROF_UNIT pu1("r1");
  864.         if (pkAttacker->IsPC())
  865.         {
  866.                 if ((GetLevel() - pkAttacker->GetLevel()) >= -10)
  867.                 {
  868.                         if (pkAttacker->GetRealAlignment() < 0)
  869.                         {
  870.                                 if (pkAttacker->IsEquipUniqueItem(UNIQUE_ITEM_FASTER_ALIGNMENT_UP_BY_KILL))
  871.                                         pkAttacker->UpdateAlignment(14);
  872.                                 else
  873.                                         pkAttacker->UpdateAlignment(7);
  874.                         }
  875.                         else
  876.                                 pkAttacker->UpdateAlignment(2);
  877.                 }
  878.  
  879.                 pkAttacker->SetQuestNPCID(GetVID());
  880.                 quest::CQuestManager::instance().Kill(pkAttacker->GetPlayerID(), GetRaceNum());
  881.                 CHARACTER_MANAGER::instance().KillLog(GetRaceNum());
  882.  
  883. #ifdef ENABLE_KILL_NOTICE
  884.                 std::vector<int> monstersList{ 691 , 792 , 2091 , 2191 , 1901 , 1304 , 2206 , 2291, 1192 };
  885.                 const char* MapName = GetMapName(GetMapIndex());
  886.                 for (auto& i : monstersList) {
  887.                         if (GetRaceNum() == i) {
  888.                                 auto pkMob = CMobManager::instance().Get(i);
  889.                                 if (pkMob) {
  890.                                         char szKillNotice[QUERY_MAX_LEN];
  891.                                         snprintf(szKillNotice, sizeof(szKillNotice), LC_TEXT("[CH%d]: %s, Lv.%d %s tarafindan %s'de katledildi!"), g_bChannel, pkMob->m_table.szLocaleName, pkAttacker->GetLevel(), pkAttacker->GetName(), MapName ? MapName : "NULL");
  892.                                         BroadcastNotice(szKillNotice);
  893.                                 }
  894.                         }
  895.                 }
  896. #endif
  897.  
  898.                 if (!number(0, 9))
  899.                 {
  900.                         if (pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY))
  901.                         {
  902.                                 int iHP = pkAttacker->GetMaxHP() * pkAttacker->GetPoint(POINT_KILL_HP_RECOVERY) / 100;
  903.                                 pkAttacker->PointChange(POINT_HP, iHP);
  904.                                 CreateFly(FLY_HP_SMALL, pkAttacker);
  905.                         }
  906.  
  907.                         if (pkAttacker->GetPoint(POINT_KILL_SP_RECOVER))
  908.                         {
  909.                                 int iSP = pkAttacker->GetMaxSP() * pkAttacker->GetPoint(POINT_KILL_SP_RECOVER) / 100;
  910.                                 pkAttacker->PointChange(POINT_SP, iSP);
  911.                                 CreateFly(FLY_SP_SMALL, pkAttacker);
  912.                         }
  913.                 }
  914.         }
  915.         //pu1.Pop();
  916.  
  917.         if (!bItemDrop)
  918.                 return;
  919.  
  920.         PIXEL_POSITION pos = GetXYZ();
  921.  
  922.         if (!SECTREE_MANAGER::instance().GetMovablePosition(GetMapIndex(), pos.x, pos.y, pos))
  923.                 return;
  924.  
  925.         //
  926.  
  927.         //
  928.         //PROF_UNIT pu2("r2");
  929.         if (test_server)
  930.                 sys_log(0, "Drop money : Attacker %s", pkAttacker->GetName());
  931.         RewardGold(pkAttacker);
  932.         //pu2.Pop();
  933.  
  934.         //
  935.  
  936.         //
  937.         //PROF_UNIT pu3("r3");
  938.         LPITEM item;
  939.  
  940.         static std::vector<LPITEM> s_vec_item;
  941.         s_vec_item.clear();
  942.  
  943.         if (ITEM_MANAGER::instance().CreateDropItem(this, pkAttacker, s_vec_item))
  944.         {
  945.                 if (s_vec_item.size() == 0);
  946.                 else if (s_vec_item.size() == 1)
  947.                 {
  948.                         item = s_vec_item[0];
  949.                         item->AddToGround(GetMapIndex(), pos);
  950.  
  951.                         if (CBattleArena::instance().IsBattleArenaMap(pkAttacker->GetMapIndex()) == false)
  952.                         {
  953. #ifdef ENABLE_DICE_SYSTEM
  954.                                 if (pkAttacker->GetParty())
  955.                                 {
  956.                                         FPartyDropDiceRoll f(item, pkAttacker);
  957.                                         f.Process(this);
  958.                                 }
  959.                                 else
  960.                                         item->SetOwnership(pkAttacker);
  961. #else
  962.                                 item->SetOwnership(pkAttacker);
  963. #endif
  964.                         }
  965.  
  966.                         item->StartDestroyEvent();
  967.  
  968.                         pos.x = number(-7, 7) * 20;
  969.                         pos.y = number(-7, 7) * 20;
  970.                         pos.x += GetX();
  971.                         pos.y += GetY();
  972.  
  973.                         sys_log(0, "DROP_ITEM: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
  974.                 }
  975.                 else
  976.                 {
  977.                         int iItemIdx = s_vec_item.size() - 1;
  978.  
  979.                         std::priority_queue<std::pair<int, LPCHARACTER> > pq;
  980.  
  981.                         int total_dam = 0;
  982.  
  983.                         for (TDamageMap::iterator it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
  984.                         {
  985.                                 int iDamage = it->second.iTotalDamage;
  986.                                 if (iDamage > 0)
  987.                                 {
  988.                                         LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
  989.  
  990.                                         if (ch)
  991.                                         {
  992.                                                 pq.push(std::make_pair(iDamage, ch));
  993.                                                 total_dam += iDamage;
  994.                                         }
  995.                                 }
  996.                         }
  997.  
  998.                         std::vector<LPCHARACTER> v;
  999.  
  1000.                         while (!pq.empty() && pq.top().first * 10 >= total_dam)
  1001.                         {
  1002.                                 v.push_back(pq.top().second);
  1003.                                 pq.pop();
  1004.                         }
  1005.  
  1006.                         if (v.empty())
  1007.                         {
  1008.                                 while (iItemIdx >= 0)
  1009.                                 {
  1010.                                         item = s_vec_item[iItemIdx--];
  1011.  
  1012.                                         if (!item)
  1013.                                         {
  1014.                                                 sys_err("item null in vector idx %d", iItemIdx + 1);
  1015.                                                 continue;
  1016.                                         }
  1017.  
  1018.                                         item->AddToGround(GetMapIndex(), pos);
  1019.  
  1020.                                         //item->SetOwnership(pkAttacker);
  1021.                                         item->StartDestroyEvent();
  1022.  
  1023.                                         pos.x = number(-7, 7) * 20;
  1024.                                         pos.y = number(-7, 7) * 20;
  1025.                                         pos.x += GetX();
  1026.                                         pos.y += GetY();
  1027.  
  1028.                                         sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
  1029.                                 }
  1030.                         }
  1031.                         else
  1032.                         {
  1033.                                 std::vector<LPCHARACTER>::iterator it = v.begin();
  1034.  
  1035.                                 while (iItemIdx >= 0)
  1036.                                 {
  1037.                                         item = s_vec_item[iItemIdx--];
  1038.  
  1039.                                         if (!item)
  1040.                                         {
  1041.                                                 sys_err("item null in vector idx %d", iItemIdx + 1);
  1042.                                                 continue;
  1043.                                         }
  1044.  
  1045.                                         item->AddToGround(GetMapIndex(), pos);
  1046.  
  1047.                                         LPCHARACTER ch = *it;
  1048.  
  1049.                                         if (ch->GetParty())
  1050.                                                 ch = ch->GetParty()->GetNextOwnership(ch, GetX(), GetY());
  1051.  
  1052.                                         ++it;
  1053.  
  1054.                                         if (it == v.end())
  1055.                                                 it = v.begin();
  1056.  
  1057.                                         if (CBattleArena::instance().IsBattleArenaMap(ch->GetMapIndex()) == false)
  1058.                                         {
  1059. #ifdef ENABLE_DICE_SYSTEM
  1060.                                                 if (ch->GetParty())
  1061.                                                 {
  1062.                                                         FPartyDropDiceRoll f(item, ch);
  1063.                                                         f.Process(this);
  1064.                                                 }
  1065.                                                 else
  1066.                                                         item->SetOwnership(ch);
  1067. #else
  1068.                                                 item->SetOwnership(ch);
  1069. #endif
  1070.                                         }
  1071.  
  1072.                                         item->StartDestroyEvent();
  1073.  
  1074.                                         pos.x = number(-7, 7) * 20;
  1075.                                         pos.y = number(-7, 7) * 20;
  1076.                                         pos.x += GetX();
  1077.                                         pos.y += GetY();
  1078.  
  1079.                                         sys_log(0, "DROP_ITEM: %s %d %d by %s", item->GetName(), pos.x, pos.y, GetName());
  1080.                                 }
  1081.                         }
  1082.                 }
  1083.         }
  1084.  
  1085.         m_map_kDamage.clear();
  1086. }
  1087.  
  1088. struct TItemDropPenalty
  1089. {
  1090.         int iInventoryPct;              // Range: 1 ~ 1000
  1091.         int iInventoryQty;              // Range: --
  1092.         int iEquipmentPct;              // Range: 1 ~ 100
  1093.         int iEquipmentQty;              // Range: --
  1094. };
  1095.  
  1096. TItemDropPenalty aItemDropPenalty_kor[9] =
  1097. {
  1098.         {   0,   0,  0,  0 },
  1099.         {   0,   0,  0,  0 },
  1100.         {   0,   0,  0,  0 },
  1101.         {   0,   0,  0,  0 },
  1102.         {   0,   0,  0,  0 },
  1103.         {  25,   1,  5,  1 },
  1104.         {  50,   2, 10,  1 },
  1105.         {  75,   4, 15,  1 },
  1106.         { 100,   8, 20,  1 },
  1107. };
  1108.  
  1109. void CHARACTER::ItemDropPenalty(LPCHARACTER pkKiller)
  1110. {
  1111.         if (GetMyShop())
  1112.                 return;
  1113.  
  1114.         if (GetLevel() < 50)
  1115.                 return;
  1116.  
  1117.         if (CBattleArena::instance().IsBattleArenaMap(GetMapIndex()) == true)
  1118.         {
  1119.                 return;
  1120.         }
  1121.  
  1122.         struct TItemDropPenalty* table = &aItemDropPenalty_kor[0];
  1123.  
  1124.         if (GetLevel() < 10)
  1125.                 return;
  1126.  
  1127.         int iAlignIndex;
  1128.  
  1129.         if (GetRealAlignment() >= 120000)
  1130.                 iAlignIndex = 0;
  1131.         else if (GetRealAlignment() >= 80000)
  1132.                 iAlignIndex = 1;
  1133.         else if (GetRealAlignment() >= 40000)
  1134.                 iAlignIndex = 2;
  1135.         else if (GetRealAlignment() >= 10000)
  1136.                 iAlignIndex = 3;
  1137.         else if (GetRealAlignment() >= 0)
  1138.                 iAlignIndex = 4;
  1139.         else if (GetRealAlignment() > -40000)
  1140.                 iAlignIndex = 5;
  1141.         else if (GetRealAlignment() > -80000)
  1142.                 iAlignIndex = 6;
  1143.         else if (GetRealAlignment() > -120000)
  1144.                 iAlignIndex = 7;
  1145.         else
  1146.                 iAlignIndex = 8;
  1147.  
  1148.         std::vector<std::pair<LPITEM, int> > vec_item;
  1149.         LPITEM pkItem;
  1150.         int     i;
  1151.         bool isDropAllEquipments = false;
  1152.  
  1153.         TItemDropPenalty& r = table[iAlignIndex];
  1154.         sys_log(0, "%s align %d inven_pct %d equip_pct %d", GetName(), iAlignIndex, r.iInventoryPct, r.iEquipmentPct);
  1155.  
  1156.         bool bDropInventory = r.iInventoryPct >= number(1, 1000);
  1157.         bool bDropEquipment = r.iEquipmentPct >= number(1, 100);
  1158.         bool bDropAntiDropUniqueItem = false;
  1159.  
  1160.         if ((bDropInventory || bDropEquipment) && IsEquipUniqueItem(UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY))
  1161.         {
  1162.                 bDropInventory = false;
  1163.                 bDropEquipment = false;
  1164.                 bDropAntiDropUniqueItem = true;
  1165.         }
  1166.  
  1167.         if (bDropInventory) // Drop Inventory
  1168.         {
  1169.                 std::vector<BYTE> vec_bSlots;
  1170.  
  1171.                 for (i = 0; i < INVENTORY_MAX_NUM; ++i)
  1172.                         if (GetInventoryItem(i))
  1173.                                 vec_bSlots.push_back(i);
  1174.  
  1175.                 if (!vec_bSlots.empty())
  1176.                 {
  1177.                         random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
  1178.  
  1179.                         int iQty = MIN(vec_bSlots.size(), r.iInventoryQty);
  1180.  
  1181.                         if (iQty)
  1182.                                 iQty = number(1, iQty);
  1183.  
  1184.                         for (i = 0; i < iQty; ++i)
  1185.                         {
  1186.                                 pkItem = GetInventoryItem(vec_bSlots[i]);
  1187.  
  1188.                                 if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
  1189.                                         continue;
  1190. #ifdef ENABLE_ITEM_SEALBIND_SYSTEM
  1191.                                 if (pkItem->IsSealed())
  1192.                                         continue;
  1193. #endif
  1194. #ifdef ENABLE_BASIC_ITEM_SYSTEM
  1195.                                 if (pkItem->IsBasicItem())
  1196.                                         continue;
  1197. #endif
  1198.                                 SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 255);
  1199.                                 vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), INVENTORY));
  1200.                         }
  1201.                 }
  1202.                 else if (iAlignIndex == 8)
  1203.                         isDropAllEquipments = true;
  1204.         }
  1205.  
  1206.         if (bDropEquipment) // Drop Equipment
  1207.         {
  1208.                 std::vector<BYTE> vec_bSlots;
  1209.  
  1210.                 for (i = 0; i < WEAR_MAX_NUM; ++i)
  1211.                         if (GetWear(i))
  1212.                                 vec_bSlots.push_back(i);
  1213.  
  1214.                 if (!vec_bSlots.empty())
  1215.                 {
  1216.                         random_shuffle(vec_bSlots.begin(), vec_bSlots.end());
  1217.                         int iQty;
  1218.  
  1219.                         if (isDropAllEquipments)
  1220.                                 iQty = vec_bSlots.size();
  1221.                         else
  1222.                                 iQty = MIN(vec_bSlots.size(), number(1, r.iEquipmentQty));
  1223.  
  1224.                         if (iQty)
  1225.                                 iQty = number(1, iQty);
  1226.  
  1227.                         for (i = 0; i < iQty; ++i)
  1228.                         {
  1229.                                 pkItem = GetWear(vec_bSlots[i]);
  1230.  
  1231.                                 if (IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_GIVE | ITEM_ANTIFLAG_PKDROP))
  1232.                                         continue;
  1233. #ifdef ENABLE_ITEM_SEALBIND_SYSTEM
  1234.                                 if (pkItem->IsSealed())
  1235.                                         continue;
  1236. #endif
  1237. #ifdef ENABLE_BASIC_ITEM_SYSTEM
  1238.                                 if (pkItem->IsBasicItem())
  1239.                                         continue;
  1240. #endif
  1241.                                 SyncQuickslot(QUICKSLOT_TYPE_ITEM, vec_bSlots[i], 255);
  1242.                                 vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
  1243.                         }
  1244.                 }
  1245.         }
  1246.  
  1247.         if (bDropAntiDropUniqueItem)
  1248.         {
  1249.                 LPITEM pkItem;
  1250.  
  1251.                 pkItem = GetWear(WEAR_UNIQUE1);
  1252.  
  1253.                 if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
  1254.                 {
  1255.                         SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE1, 255);
  1256.                         vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
  1257.                 }
  1258.  
  1259.                 pkItem = GetWear(WEAR_UNIQUE2);
  1260.  
  1261.                 if (pkItem && pkItem->GetVnum() == UNIQUE_ITEM_SKIP_ITEM_DROP_PENALTY)
  1262.                 {
  1263.                         SyncQuickslot(QUICKSLOT_TYPE_ITEM, WEAR_UNIQUE2, 255);
  1264.                         vec_item.push_back(std::make_pair(pkItem->RemoveFromCharacter(), EQUIPMENT));
  1265.                 }
  1266.         }
  1267.  
  1268.         {
  1269.                 PIXEL_POSITION pos;
  1270.                 pos.x = GetX();
  1271.                 pos.y = GetY();
  1272.  
  1273.                 unsigned int i;
  1274.  
  1275.                 for (i = 0; i < vec_item.size(); ++i)
  1276.                 {
  1277.                         LPITEM item = vec_item[i].first;
  1278.                         int window = vec_item[i].second;
  1279.  
  1280.                         item->AddToGround(GetMapIndex(), pos);
  1281.                         item->StartDestroyEvent();
  1282.  
  1283.                         sys_log(0, "DROP_ITEM_PK: %s %d %d from %s", item->GetName(), pos.x, pos.y, GetName());
  1284.                         LogManager::instance().ItemLog(this, item, "DEAD_DROP", (window == INVENTORY) ? "INVENTORY" : ((window == EQUIPMENT) ? "EQUIPMENT" : ""));
  1285.  
  1286.                         pos.x = GetX() + number(-7, 7) * 20;
  1287.                         pos.y = GetY() + number(-7, 7) * 20;
  1288.                 }
  1289.         }
  1290. }
  1291.  
  1292. class FPartyAlignmentCompute
  1293. {
  1294. public:
  1295.         FPartyAlignmentCompute(int iAmount, int x, int y)
  1296.         {
  1297.                 m_iAmount = iAmount;
  1298.                 m_iCount = 0;
  1299.                 m_iStep = 0;
  1300.                 m_iKillerX = x;
  1301.                 m_iKillerY = y;
  1302.         }
  1303.  
  1304.         void operator () (LPCHARACTER pkChr)
  1305.         {
  1306.                 if (DISTANCE_APPROX(pkChr->GetX() - m_iKillerX, pkChr->GetY() - m_iKillerY) < PARTY_DEFAULT_RANGE)
  1307.                 {
  1308.                         if (m_iStep == 0)
  1309.                         {
  1310.                                 ++m_iCount;
  1311.                         }
  1312.                         else
  1313.                         {
  1314.                                 pkChr->UpdateAlignment(m_iAmount / m_iCount);
  1315.                         }
  1316.                 }
  1317.         }
  1318.  
  1319.         int m_iAmount;
  1320.         int m_iCount;
  1321.         int m_iStep;
  1322.  
  1323.         int m_iKillerX;
  1324.         int m_iKillerY;
  1325. };
  1326.  
  1327. void CHARACTER::Dead(LPCHARACTER pkKiller, bool bImmediateDead)
  1328. {
  1329.         if (IsDead())
  1330.                 return;
  1331. #ifndef DISABLE_STOP_RIDING_WHEN_DIE
  1332.         {
  1333.                 if (IsHorseRiding())
  1334.                 {
  1335.                         StopRiding();
  1336.                 }
  1337.                 else if (GetMountVnum())
  1338.                 {
  1339. #ifndef ENABLE_MOUNT_COSTUME_SYSTEM
  1340.                         RemoveAffect(AFFECT_MOUNT_BONUS);
  1341. #endif
  1342.                         m_dwMountVnum = 0;
  1343.                         UnEquipSpecialRideUniqueItem();
  1344.  
  1345.                         UpdatePacket();
  1346.                 }
  1347.         }
  1348. #endif
  1349.  
  1350.         if (!pkKiller && m_dwKillerPID)
  1351.                 pkKiller = CHARACTER_MANAGER::instance().FindByPID(m_dwKillerPID);
  1352.  
  1353.         m_dwKillerPID = 0; // 반드시 초기화 해야함 DO NOT DELETE THIS LINE UNLESS YOU ARE 1000000% SURE
  1354.  
  1355.         bool isAgreedPVP = false;
  1356.         bool isUnderGuildWar = false;
  1357.         bool isDuel = false;
  1358.         bool isForked = false;
  1359.  
  1360.         if (pkKiller && pkKiller->IsPC())
  1361.         {
  1362.                 if (pkKiller->m_pkChrTarget == this)
  1363.                         pkKiller->SetTarget(NULL);
  1364.  
  1365.                 if (!IsPC() && pkKiller->GetDungeon())
  1366.                         pkKiller->GetDungeon()->IncKillCount(pkKiller, this);
  1367.  
  1368. #ifdef ENABLE_WEAPON_RARITY_SYSTEM
  1369.                 LPITEM pkKillerWeapon = pkKiller->GetWear(WEAR_WEAPON);
  1370.                 if (pkKillerWeapon && IS_SET(pkKillerWeapon->GetFlag(), ITEM_FLAG_RARE_ABILITY))
  1371.                         pkKiller->IncreaseRarePoints(pkKillerWeapon, pkKiller, this);
  1372. #endif
  1373.  
  1374.                 isAgreedPVP = CPVPManager::instance().Dead(this, pkKiller->GetPlayerID());
  1375.                 isDuel = CArenaManager::instance().OnDead(pkKiller, this);
  1376.  
  1377.                 if (IsPC())
  1378.                 {
  1379.                         CGuild* g1 = GetGuild();
  1380.                         CGuild* g2 = pkKiller->GetGuild();
  1381.  
  1382.                         if (g1 && g2)
  1383.                                 if (g1->UnderWar(g2->GetID()))
  1384.                                 {
  1385.                                         isUnderGuildWar = true;
  1386. #ifdef ENABLE_WAR_KILL_NOTICE
  1387.                                         CWarMap* pMap = pkKiller->GetWarMap();
  1388.                                         if (pMap)
  1389.                                                 pMap->SendKillNotice(pkKiller->GetName(), GetName(), pkKiller->GetRaceNum(), GetRaceNum());
  1390. #endif
  1391.                                 }
  1392.                         pkKiller->SetQuestNPCID(GetVID());
  1393.                         quest::CQuestManager::instance().Kill(pkKiller->GetPlayerID(), quest::QUEST_NO_NPC);
  1394.                         CGuildManager::instance().Kill(pkKiller, this);
  1395.                 }
  1396.         }
  1397.  
  1398. #ifdef ENABLE_QUEST_DIE_EVENT
  1399.         if (IsPC())
  1400.         {
  1401.                 if (pkKiller)
  1402.                         SetQuestNPCID(pkKiller->GetVID());
  1403.                 // quest::CQuestManager::instance().Die(GetPlayerID(), quest::QUEST_NO_NPC);
  1404.                 quest::CQuestManager::instance().Die(GetPlayerID(), (pkKiller) ? pkKiller->GetRaceNum() : quest::QUEST_NO_NPC);
  1405.         }
  1406. #endif
  1407.  
  1408.         //CHECK_FORKEDROAD_WAR
  1409.         if (IsPC())
  1410.         {
  1411.                 if (CThreeWayWar::instance().IsThreeWayWarMapIndex(GetMapIndex()))
  1412.                         isForked = true;
  1413.         }
  1414.         //END_CHECK_FORKEDROAD_WAR
  1415.  
  1416.         if (pkKiller &&
  1417.                 !isAgreedPVP &&
  1418.                 !isUnderGuildWar &&
  1419.                 IsPC() &&
  1420.                 !isDuel &&
  1421.                 !isForked &&
  1422.                 !IS_CASTLE_MAP(GetMapIndex()))
  1423.         {
  1424.                 if (GetGMLevel() == GM_PLAYER || test_server)
  1425.                 {
  1426.                         ItemDropPenalty(pkKiller);
  1427.                 }
  1428.         }
  1429.  
  1430.         // CASTLE_SIEGE
  1431.         if (IS_CASTLE_MAP(GetMapIndex()))
  1432.         {
  1433.                 if (CASTLE_FROG_VNUM == GetRaceNum())
  1434.                         castle_frog_die(this, pkKiller);
  1435.                 else if (castle_is_guard_vnum(GetRaceNum()))
  1436.                         castle_guard_die(this, pkKiller);
  1437.                 else if (castle_is_tower_vnum(GetRaceNum()))
  1438.                         castle_tower_die(this, pkKiller);
  1439.         }
  1440.         // CASTLE_SIEGE
  1441.  
  1442.         if (true == isForked)
  1443.         {
  1444.                 CThreeWayWar::instance().onDead(this, pkKiller);
  1445.         }
  1446.  
  1447.         SetPosition(POS_DEAD);
  1448.         ClearAffect(true);
  1449.  
  1450.         if (pkKiller && IsPC())
  1451.         {
  1452.                 if (!pkKiller->IsPC())
  1453.                 {
  1454.                         if (!isForked)
  1455.                         {
  1456.                                 sys_log(1, "DEAD: %s %p WITH PENALTY", GetName(), this);
  1457.                                 SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
  1458.                                 LogManager::instance().CharLog(this, pkKiller->GetRaceNum(), "DEAD_BY_NPC", pkKiller->GetName());
  1459.                         }
  1460.                 }
  1461.                 else
  1462.                 {
  1463. #ifdef ENABLE_WEAPON_KILL_SYSTEM
  1464.                         LPITEM item = pkKiller->GetWear(WEAR_WEAPON);
  1465.                         if (item)
  1466.                         {
  1467.                                 if (item->GetType() == ITEM_WEAPON)
  1468.                                 {
  1469.                                         std::map<DWORD, DWORD>::iterator LuiginaKillerIterator;
  1470.                                         LuiginaKillerIterator = pkKiller->LuiginaKillList.find(GetPlayerID());
  1471.                                         bool LuiginaReturn = true;
  1472.                                         if (LuiginaKillerIterator != pkKiller->LuiginaKillList.end())
  1473.                                                         if (LuiginaKillerIterator->second + (60*60) > time(0))
  1474.                                                                 LuiginaReturn = false;
  1475.                                         if (LuiginaReturn)
  1476.                                         {
  1477.                                                 const TPlayerItemAttribute& attrItem = item->GetAttribute(7);
  1478.                                                 item->SetForceAttribute(7, 0, attrItem.sValue+1);
  1479.                                                 pkKiller->LuiginaKillList[GetPlayerID()] = time(0);
  1480.                                         }
  1481.                                         else
  1482.                                         {
  1483.                                                 pkKiller->ChatPacket(CHAT_TYPE_INFO, "Bu rakip'den le puan?zaten ald? 1 saat beklemelisin.");
  1484.                                         }
  1485.                                 }
  1486.                         }
  1487. #endif
  1488. #ifdef ENABLE_GUILD_STATISTICS
  1489.                         if (CWarMapManager::instance().IsWarMap(GetMapIndex()))
  1490.                         {
  1491.                                 SetQuestFlag("loncaistatistik.olum", GetQuestFlag("loncaistatistik.olum")+1);
  1492.                                 pkKiller->SetQuestFlag("loncaistatistik.oldurme", pkKiller->GetQuestFlag("loncaistatistik.oldurme")+1);
  1493.                         }
  1494.                         else
  1495.                         {
  1496.                                 if (test_server)
  1497.                                 {
  1498.                                         SetQuestFlag("loncaistatistik.olum", GetQuestFlag("loncaistatistik.olum")+1);
  1499.                                         pkKiller->SetQuestFlag("loncaistatistik.oldurme", pkKiller->GetQuestFlag("loncaistatistik.oldurme")+1);
  1500.                                 }
  1501.                         }
  1502. #endif
  1503.                         sys_log(1, "DEAD_BY_PC: %s %p KILLER %s %p", GetName(), this, pkKiller->GetName(), get_pointer(pkKiller));
  1504.                         REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
  1505.  
  1506.                         if (GetEmpire() != pkKiller->GetEmpire())
  1507.                         {
  1508.                                 int iEP = MIN(GetPoint(POINT_EMPIRE_POINT), pkKiller->GetPoint(POINT_EMPIRE_POINT));
  1509.  
  1510.                                 PointChange(POINT_EMPIRE_POINT, -(iEP / 10));
  1511.                                 pkKiller->PointChange(POINT_EMPIRE_POINT, iEP / 5);
  1512.  
  1513.                                 if (GetPoint(POINT_EMPIRE_POINT) < 10)
  1514.                                 {
  1515.                                 }
  1516.  
  1517.                                 char buf[256];
  1518.                                 snprintf(buf, sizeof(buf),
  1519.                                         "%d %d %d %s %d %d %d %s",
  1520.                                         GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
  1521.                                         pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
  1522.  
  1523.                                 LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
  1524.                         }
  1525.                         else
  1526.                         {
  1527.                                 if (!isAgreedPVP && !isUnderGuildWar && !IsKillerMode() && GetAlignment() >= 0 && !isDuel && !isForked)
  1528.                                 {
  1529.                                         int iNoPenaltyProb = 0;
  1530.  
  1531.                                         if (pkKiller->GetAlignment() >= 0)      // 1/3 percent down
  1532.                                                 iNoPenaltyProb = 33;
  1533.                                         else                            // 4/5 percent down
  1534.                                                 iNoPenaltyProb = 20;
  1535.  
  1536.                                         if (number(1, 100) < iNoPenaltyProb)
  1537.                                                 pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("용신의 보호로 아이템이 떨어지지 않았습니다."));
  1538.                                         else
  1539.                                         {
  1540.                                                 if (pkKiller->GetParty())
  1541.                                                 {
  1542.                                                         FPartyAlignmentCompute f(-20000, pkKiller->GetX(), pkKiller->GetY());
  1543.                                                         pkKiller->GetParty()->ForEachOnlineMember(f);
  1544.  
  1545.                                                         if (f.m_iCount == 0)
  1546.                                                                 pkKiller->UpdateAlignment(-20000);
  1547.                                                         else
  1548.                                                         {
  1549.                                                                 sys_log(0, "ALIGNMENT PARTY count %d amount %d", f.m_iCount, f.m_iAmount);
  1550.  
  1551.                                                                 f.m_iStep = 1;
  1552.                                                                 pkKiller->GetParty()->ForEachOnlineMember(f);
  1553.                                                         }
  1554.                                                 }
  1555.                                                 else
  1556.                                                         pkKiller->UpdateAlignment(-20000);
  1557.                                         }
  1558.                                 }
  1559.  
  1560.                                 char buf[256];
  1561.                                 snprintf(buf, sizeof(buf),
  1562.                                         "%d %d %d %s %d %d %d %s",
  1563.                                         GetEmpire(), GetAlignment(), GetPKMode(), GetName(),
  1564.                                         pkKiller->GetEmpire(), pkKiller->GetAlignment(), pkKiller->GetPKMode(), pkKiller->GetName());
  1565.  
  1566.                                 LogManager::instance().CharLog(this, pkKiller->GetPlayerID(), "DEAD_BY_PC", buf);
  1567.                         }
  1568.                 }
  1569.         }
  1570.         else
  1571.         {
  1572.                 sys_log(1, "DEAD: %s %p", GetName(), this);
  1573.                 REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_DEATH_PENALTY);
  1574.         }
  1575.  
  1576.         ClearSync();
  1577.  
  1578.         //sys_log(1, "stun cancel %s[%d]", GetName(), (DWORD)GetVID());
  1579.         event_cancel(&m_pkStunEvent);
  1580.  
  1581.         if (IsPC())
  1582.         {
  1583.                 m_dwLastDeadTime = get_dword_time();
  1584.                 SetKillerMode(false);
  1585.                 GetDesc()->SetPhase(PHASE_DEAD);
  1586.         }
  1587.         else
  1588.         {
  1589.                 if (!IS_SET(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD))
  1590.                 {
  1591.                         if (!(pkKiller && pkKiller->IsPC() && pkKiller->GetGuild() && pkKiller->GetGuild()->UnderAnyWar(GUILD_WAR_TYPE_FIELD)))
  1592.                         {
  1593.                                 if (GetMobTable().dwResurrectionVnum)
  1594.                                 {
  1595.                                         // DUNGEON_MONSTER_REBIRTH_BUG_FIX
  1596.                                         LPCHARACTER chResurrect = CHARACTER_MANAGER::instance().SpawnMob(GetMobTable().dwResurrectionVnum, GetMapIndex(), GetX(), GetY(), GetZ(), true, (int)GetRotation());
  1597.                                         if (GetDungeon() && chResurrect)
  1598.                                         {
  1599.                                                 chResurrect->SetDungeon(GetDungeon());
  1600.                                         }
  1601.                                         // END_OF_DUNGEON_MONSTER_REBIRTH_BUG_FIX
  1602.  
  1603.                                         Reward(false);
  1604.                                 }
  1605.                                 else if (IsRevive() == true)
  1606.                                 {
  1607.                                         Reward(false);
  1608.                                 }
  1609.                                 else
  1610.                                 {
  1611.                                         Reward(true); // Drops gold, item, etc..
  1612.                                 }
  1613.                         }
  1614.                         else
  1615.                         {
  1616.                                 if (pkKiller->m_dwUnderGuildWarInfoMessageTime < get_dword_time())
  1617.                                 {
  1618.                                         pkKiller->m_dwUnderGuildWarInfoMessageTime = get_dword_time() + 60000;
  1619.                                         pkKiller->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전중에는 사냥에 따른 이익이 없습니다."));
  1620.                                 }
  1621.                         }
  1622.                 }
  1623.         }
  1624.  
  1625.         // BOSS_KILL_LOG
  1626.         if (GetMobRank() >= MOB_RANK_BOSS && pkKiller && pkKiller->IsPC())
  1627.         {
  1628.                 char buf[51];
  1629.                 snprintf(buf, sizeof(buf), "%d %ld", g_bChannel, pkKiller->GetMapIndex());
  1630.                 if (IsStone())
  1631.                         LogManager::instance().CharLog(pkKiller, GetRaceNum(), "STONE_KILL", buf);
  1632.                 else
  1633.                         LogManager::instance().CharLog(pkKiller, GetRaceNum(), "BOSS_KILL", buf);
  1634.         }
  1635.         // END_OF_BOSS_KILL_LOG
  1636.  
  1637.         TPacketGCDead pack;
  1638.         pack.header = HEADER_GC_DEAD;
  1639.         pack.vid = m_vid;
  1640.         PacketAround(&pack, sizeof(pack));
  1641.  
  1642.         REMOVE_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_STUN);
  1643.  
  1644.         if (GetDesc() != NULL) {
  1645.                 //
  1646.  
  1647.                 //
  1648.                 itertype(m_list_pkAffect) it = m_list_pkAffect.begin();
  1649.  
  1650.                 while (it != m_list_pkAffect.end())
  1651.                         SendAffectAddPacket(GetDesc(), *it++);
  1652.         }
  1653.  
  1654.         //
  1655.  
  1656.         //
  1657.  
  1658.         if (isDuel == false)
  1659.         {
  1660.                 if (m_pkDeadEvent)
  1661.                 {
  1662.                         sys_log(1, "DEAD_EVENT_CANCEL: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
  1663.                         event_cancel(&m_pkDeadEvent);
  1664.                 }
  1665.  
  1666.                 if (IsStone())
  1667.                         ClearStone();
  1668.  
  1669.                 if (GetDungeon())
  1670.                 {
  1671.                         GetDungeon()->DeadCharacter(this);
  1672.                 }
  1673.  
  1674.                 SCharDeadEventInfo* pEventInfo = AllocEventInfo<SCharDeadEventInfo>();
  1675.  
  1676.                 if (IsPC())
  1677.                 {
  1678.                         pEventInfo->isPC = true;
  1679.                         pEventInfo->dwID = this->GetPlayerID();
  1680.  
  1681.                         m_pkDeadEvent = event_create(dead_event, pEventInfo, PASSES_PER_SEC(180));
  1682.                 }
  1683.                 else
  1684.                 {
  1685.                         pEventInfo->isPC = false;
  1686.                         pEventInfo->dwID = this->GetVID();
  1687.  
  1688.                         if (IsRevive() == false && HasReviverInParty() == true)
  1689.                         {
  1690.                                 m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(3));
  1691.                         }
  1692.                         else
  1693.                         {
  1694.                                 m_pkDeadEvent = event_create(dead_event, pEventInfo, bImmediateDead ? 1 : PASSES_PER_SEC(0));// @fixme202
  1695.                         }
  1696.                 }
  1697.  
  1698.                 sys_log(1, "DEAD_EVENT_CREATE: %s %p %p", GetName(), this, get_pointer(m_pkDeadEvent));
  1699.         }
  1700.  
  1701.         if (m_pkExchange != NULL)
  1702.         {
  1703.                 m_pkExchange->Cancel();
  1704.         }
  1705.  
  1706.         if (IsCubeOpen() == true)
  1707.         {
  1708.                 Cube_close(this);
  1709.         }
  1710. #ifdef ENABLE_ACCE_SYSTEM
  1711.         if (IsPC())
  1712.                 CloseAcce();
  1713. #endif
  1714.         CShopManager::instance().StopShopping(this);
  1715.         CloseMyShop();
  1716.         CloseSafebox();
  1717. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  1718.         if (GetOfflineShop())
  1719.         {
  1720.                 GetOfflineShop()->RemoveGuest(this);
  1721.                 SetOfflineShop(NULL);
  1722.         }
  1723. #endif
  1724.  
  1725.         if (true == IsMonster() && 2493 == GetMobTable().dwVnum)
  1726.         {
  1727.                 if (NULL != pkKiller && NULL != pkKiller->GetGuild())
  1728.                 {
  1729.                         CDragonLairManager::instance().OnDragonDead(this, pkKiller->GetGuild()->GetID());
  1730.                 }
  1731.                 else
  1732.                 {
  1733.                         sys_err("DragonLair: Dragon killed by nobody");
  1734.                 }
  1735.         }
  1736. }
  1737.  
  1738. struct FuncSetLastAttacked
  1739. {
  1740.         FuncSetLastAttacked(DWORD dwTime) : m_dwTime(dwTime)
  1741.         {
  1742.         }
  1743.  
  1744.         void operator () (LPCHARACTER ch)
  1745.         {
  1746.                 ch->SetLastAttacked(m_dwTime);
  1747.         }
  1748.  
  1749.         DWORD m_dwTime;
  1750. };
  1751.  
  1752. void CHARACTER::SetLastAttacked(DWORD dwTime)
  1753. {
  1754.         assert(m_pkMobInst != NULL);
  1755.  
  1756.         m_pkMobInst->m_dwLastAttackedTime = dwTime;
  1757.         m_pkMobInst->m_posLastAttacked = GetXYZ();
  1758. }
  1759.  
  1760. void CHARACTER::SendDamagePacket(LPCHARACTER pAttacker, int Damage, BYTE DamageFlag)
  1761. {
  1762.         if (IsPC() == true || (pAttacker->IsPC() == true && pAttacker->GetTarget() == this))
  1763.         {
  1764.                 TPacketGCDamageInfo damageInfo;
  1765.                 memset(&damageInfo, 0, sizeof(TPacketGCDamageInfo));
  1766.  
  1767.                 damageInfo.header = HEADER_GC_DAMAGE_INFO;
  1768.                 damageInfo.dwVID = (DWORD)GetVID();
  1769.                 damageInfo.flag = DamageFlag;
  1770.                 damageInfo.damage = Damage;
  1771.  
  1772.                 if (GetDesc() != NULL)
  1773.                 {
  1774.                         GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
  1775.                 }
  1776.  
  1777.                 if (pAttacker->GetDesc() != NULL)
  1778.                 {
  1779.                         pAttacker->GetDesc()->Packet(&damageInfo, sizeof(TPacketGCDamageInfo));
  1780.                 }
  1781.                 /*
  1782.                    if (GetArenaObserverMode() == false && GetArena() != NULL)
  1783.                    {
  1784.                    GetArena()->SendPacketToObserver(&damageInfo, sizeof(TPacketGCDamageInfo));
  1785.                    }
  1786.                  */
  1787.         }
  1788. }
  1789.  
  1790. //
  1791.  
  1792. //
  1793. // Arguments
  1794. //    pAttacker         : 공격자
  1795.  
  1796. //
  1797. // Return value
  1798. //    true              : dead
  1799. //    false             : not dead yet
  1800. //
  1801.  
  1802. bool CHARACTER::Damage(LPCHARACTER pAttacker, int dam, EDamageType type) // returns true if dead
  1803. {
  1804.         if (!pAttacker)// @fixme203
  1805.                 return false;
  1806. #ifdef ENABLE_NEW_PET_SYSTEM
  1807.         if (IsImmortal())
  1808.                 return false;
  1809. #endif
  1810. #ifdef ENABLE_NEWSTUFF
  1811.         if (pAttacker && IsStone() && pAttacker->IsPC())
  1812.         {
  1813.                 if (GetEmpire() && GetEmpire() == pAttacker->GetEmpire())
  1814.                 {
  1815.                         SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK);
  1816.                         return false;
  1817.                 }
  1818.         }
  1819. #endif
  1820.         if (IsPC() && IsObserverMode())// @fixme204
  1821.                 return false;
  1822. #ifdef ENABLE_PLAYER_SECURITY_SYSTEM
  1823.         if (IsPC() && IsActivateSecurity())
  1824.                 return false;
  1825. #endif
  1826.         if (DAMAGE_TYPE_MAGIC == type)
  1827.         {
  1828.                 dam = (int)((float)dam * (100 + (pAttacker->GetPoint(POINT_MAGIC_ATT_BONUS_PER) + pAttacker->GetPoint(POINT_MELEE_MAGIC_ATT_BONUS_PER))) / 100.f + 0.5f);
  1829.         }
  1830.         if (GetRaceNum() == 5001)
  1831.         {
  1832.                 bool bDropMoney = false;
  1833.  
  1834.                 int iPercent = 0; // @fixme136
  1835.                 if (GetMaxHP() >= 0)
  1836.                         iPercent = (GetHP() * 100) / GetMaxHP();
  1837.  
  1838.                 if (iPercent <= 10 && GetMaxSP() < 5)
  1839.                 {
  1840.                         SetMaxSP(5);
  1841.                         bDropMoney = true;
  1842.                 }
  1843.                 else if (iPercent <= 20 && GetMaxSP() < 4)
  1844.                 {
  1845.                         SetMaxSP(4);
  1846.                         bDropMoney = true;
  1847.                 }
  1848.                 else if (iPercent <= 40 && GetMaxSP() < 3)
  1849.                 {
  1850.                         SetMaxSP(3);
  1851.                         bDropMoney = true;
  1852.                 }
  1853.                 else if (iPercent <= 60 && GetMaxSP() < 2)
  1854.                 {
  1855.                         SetMaxSP(2);
  1856.                         bDropMoney = true;
  1857.                 }
  1858.                 else if (iPercent <= 80 && GetMaxSP() < 1)
  1859.                 {
  1860.                         SetMaxSP(1);
  1861.                         bDropMoney = true;
  1862.                 }
  1863.  
  1864.                 if (bDropMoney)
  1865.                 {
  1866.                         DWORD dwGold = 1000;
  1867.                         int iSplitCount = number(10, 13);
  1868.  
  1869.                         sys_log(0, "WAEGU DropGoldOnHit %d times", GetMaxSP());
  1870.  
  1871.                         for (int i = 1; i <= iSplitCount; ++i)
  1872.                         {
  1873.                                 PIXEL_POSITION pos;
  1874.                                 LPITEM item;
  1875.  
  1876.                                 if ((item = ITEM_MANAGER::instance().CreateItem(1, dwGold / iSplitCount)))
  1877.                                 {
  1878.                                         if (i != 0)
  1879.                                         {
  1880.                                                 pos.x = (number(-14, 14) + number(-14, 14)) * 20;
  1881.                                                 pos.y = (number(-14, 14) + number(-14, 14)) * 20;
  1882.  
  1883.                                                 pos.x += GetX();
  1884.                                                 pos.y += GetY();
  1885.                                         }
  1886.  
  1887.                                         item->AddToGround(GetMapIndex(), pos);
  1888.                                         item->StartDestroyEvent();
  1889.                                 }
  1890.                         }
  1891.                 }
  1892.         }
  1893.  
  1894.         if (type != DAMAGE_TYPE_NORMAL && type != DAMAGE_TYPE_NORMAL_RANGE)
  1895.         {
  1896.                 if (IsAffectFlag(AFF_TERROR))
  1897.                 {
  1898.                         int pct = GetSkillPower(SKILL_TERROR) / 400;
  1899.  
  1900.                         if (number(1, 100) <= pct)
  1901.                                 return false;
  1902.                 }
  1903.         }
  1904.  
  1905.         int iCurHP = GetHP();
  1906.         int iCurSP = GetSP();
  1907.  
  1908.         bool IsCritical = false;
  1909.         bool IsPenetrate = false;
  1910.         bool IsDeathBlow = false;
  1911.  
  1912.         //PROF_UNIT puAttr("Attr");
  1913.  
  1914.         //
  1915.  
  1916.         //
  1917.  
  1918.         //
  1919.  
  1920.         //
  1921.         if (type == DAMAGE_TYPE_MELEE || type == DAMAGE_TYPE_RANGE || type == DAMAGE_TYPE_MAGIC)
  1922.         {
  1923.                 if (pAttacker)
  1924.                 {
  1925.                         int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
  1926.  
  1927.                         if (!IsPC())
  1928.                                 iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
  1929.  
  1930.                         if (iCriticalPct)
  1931.                         {
  1932.                                 if (iCriticalPct >= 10)
  1933.                                         iCriticalPct = 5 + (iCriticalPct - 10) / 4;
  1934.                                 else
  1935.                                         iCriticalPct /= 2;
  1936.  
  1937.                                 iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
  1938.  
  1939.                                 if (number(1, 100) <= iCriticalPct)
  1940.                                 {
  1941.                                         IsCritical = true;
  1942.                                         dam *= 2;
  1943.                                         EffectPacket(SE_CRITICAL);
  1944.  
  1945.                                         if (IsAffectFlag(AFF_MANASHIELD))
  1946.                                         {
  1947.                                                 RemoveAffect(AFF_MANASHIELD);
  1948.                                         }
  1949.                                 }
  1950.                         }
  1951.  
  1952.                         int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
  1953.  
  1954.                         if (!IsPC())
  1955.                                 iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
  1956.  
  1957.                         if (iPenetratePct)
  1958.                         {
  1959.                                 {
  1960.                                         CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
  1961.  
  1962.                                         if (NULL != pkSk)
  1963.                                         {
  1964.                                                 pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
  1965.  
  1966.                                                 iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
  1967.                                         }
  1968.                                 }
  1969.  
  1970.                                 if (iPenetratePct >= 10)
  1971.                                 {
  1972.                                         iPenetratePct = 5 + (iPenetratePct - 10) / 4;
  1973.                                 }
  1974.                                 else
  1975.                                 {
  1976.                                         iPenetratePct /= 2;
  1977.                                 }
  1978.  
  1979.                                 iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
  1980.  
  1981.                                 if (number(1, 100) <= iPenetratePct)
  1982.                                 {
  1983.                                         IsPenetrate = true;
  1984.  
  1985.                                         if (test_server)
  1986.                                                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT("관통 추가 데미지 %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
  1987.  
  1988.                                         dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
  1989.  
  1990.                                         if (IsAffectFlag(AFF_MANASHIELD))
  1991.                                         {
  1992.                                                 RemoveAffect(AFF_MANASHIELD);
  1993.                                         }
  1994. #ifdef ENABLE_EFFECT_PENETRATE
  1995.                                         EffectPacket(SE_PENETRATE);
  1996. #endif
  1997.                                 }
  1998.                         }
  1999.                 }
  2000.         }
  2001.         //
  2002.  
  2003.         //
  2004.         else if (type == DAMAGE_TYPE_NORMAL || type == DAMAGE_TYPE_NORMAL_RANGE)
  2005.         {
  2006.                 if (type == DAMAGE_TYPE_NORMAL)
  2007.                 {
  2008.                         if (GetPoint(POINT_BLOCK) && number(1, 100) <= GetPoint(POINT_BLOCK))
  2009.                         {
  2010.                                 if (test_server)
  2011.                                 {
  2012.                                         pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 블럭! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
  2013.                                         ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 블럭! (%d%%)"), GetName(), GetPoint(POINT_BLOCK));
  2014.                                 }
  2015.  
  2016.                                 SendDamagePacket(pAttacker, 0, DAMAGE_BLOCK);
  2017.                                 return false;
  2018.                         }
  2019.                 }
  2020.                 else if (type == DAMAGE_TYPE_NORMAL_RANGE)
  2021.                 {
  2022.                         if (GetPoint(POINT_DODGE) && number(1, 100) <= GetPoint(POINT_DODGE))
  2023.                         {
  2024.                                 if (test_server)
  2025.                                 {
  2026.                                         pAttacker->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 회피! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
  2027.                                         ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 회피! (%d%%)"), GetName(), GetPoint(POINT_DODGE));
  2028.                                 }
  2029.  
  2030.                                 SendDamagePacket(pAttacker, 0, DAMAGE_DODGE);
  2031.                                 return false;
  2032.                         }
  2033.                 }
  2034.  
  2035.                 if (IsAffectFlag(AFF_JEONGWIHON))
  2036.                         dam = (int)(dam * (100 + GetSkillPower(SKILL_JEONGWI) * 25 / 100) / 100);
  2037.  
  2038.                 if (IsAffectFlag(AFF_TERROR))
  2039.                         dam = (int)(dam * (95 - GetSkillPower(SKILL_TERROR) / 5) / 100);
  2040.  
  2041.                 if (IsAffectFlag(AFF_HOSIN))
  2042.                         dam = dam * (100 - GetPoint(POINT_RESIST_NORMAL_DAMAGE)) / 100;
  2043.  
  2044. #ifdef ENABLE_ITEM_BUFF_SYSTEM
  2045.                 if (IsAffectFlag(AFF_RESIST_BUFF))
  2046.                         dam = dam * (100 - GetPoint(POINT_RESIST_NORMAL_DAMAGE)) / 100;
  2047. #endif
  2048.  
  2049.                 //
  2050.  
  2051.                 //
  2052.                 if (pAttacker)
  2053.                 {
  2054.                         if (type == DAMAGE_TYPE_NORMAL)
  2055.                         {
  2056.                                 if (GetPoint(POINT_REFLECT_MELEE))
  2057.                                 {
  2058.                                         int reflectDamage = dam * GetPoint(POINT_REFLECT_MELEE) / 100;
  2059.  
  2060.                                         if (pAttacker->IsImmune(IMMUNE_REFLECT))
  2061.                                                 reflectDamage = int(reflectDamage / 3.0f + 0.5f);
  2062.  
  2063.                                         pAttacker->Damage(this, reflectDamage, DAMAGE_TYPE_SPECIAL);
  2064.                                 }
  2065.                         }
  2066.  
  2067.                         int iCriticalPct = pAttacker->GetPoint(POINT_CRITICAL_PCT);
  2068.  
  2069.                         if (!IsPC())
  2070.                                 iCriticalPct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_CRITICAL_BONUS);
  2071.  
  2072.                         if (iCriticalPct)
  2073.                         {
  2074.                                 iCriticalPct -= GetPoint(POINT_RESIST_CRITICAL);
  2075.  
  2076.                                 if (number(1, 100) <= iCriticalPct)
  2077.                                 {
  2078.                                         IsCritical = true;
  2079.                                         dam *= 2;
  2080.                                         EffectPacket(SE_CRITICAL);
  2081.                                 }
  2082.                         }
  2083.  
  2084.                         int iPenetratePct = pAttacker->GetPoint(POINT_PENETRATE_PCT);
  2085.  
  2086.                         if (!IsPC())
  2087.                                 iPenetratePct += pAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_PENETRATE_BONUS);
  2088.  
  2089.                         {
  2090.                                 CSkillProto* pkSk = CSkillManager::instance().Get(SKILL_RESIST_PENETRATE);
  2091.  
  2092.                                 if (NULL != pkSk)
  2093.                                 {
  2094.                                         pkSk->SetPointVar("k", 1.0f * GetSkillPower(SKILL_RESIST_PENETRATE) / 100.0f);
  2095.  
  2096.                                         iPenetratePct -= static_cast<int>(pkSk->kPointPoly.Eval());
  2097.                                 }
  2098.                         }
  2099.  
  2100.                         if (iPenetratePct)
  2101.                         {
  2102.                                 iPenetratePct -= GetPoint(POINT_RESIST_PENETRATE);
  2103.  
  2104.                                 if (number(1, 100) <= iPenetratePct)
  2105.                                 {
  2106.                                         IsPenetrate = true;
  2107.  
  2108.                                         if (test_server)
  2109.                                                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT("관통 추가 데미지 %d"), GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100);
  2110.                                         dam += GetPoint(POINT_DEF_GRADE) * (100 + GetPoint(POINT_DEF_BONUS)) / 100;
  2111. #ifdef ENABLE_EFFECT_PENETRATE
  2112.                                         EffectPacket(SE_PENETRATE);
  2113. #endif
  2114.                                 }
  2115.                         }
  2116.  
  2117.                         if (pAttacker->GetPoint(POINT_STEAL_HP))
  2118.                         {
  2119.                                 int pct = 1;
  2120.  
  2121.                                 if (number(1, 10) <= pct)
  2122.                                 {
  2123.                                         int iHP = MIN(dam, MAX(0, iCurHP)) * pAttacker->GetPoint(POINT_STEAL_HP) / 100;
  2124.  
  2125.                                         if (iHP > 0 && GetHP() >= iHP)
  2126.                                         {
  2127.                                                 CreateFly(FLY_HP_SMALL, pAttacker);
  2128.                                                 pAttacker->PointChange(POINT_HP, iHP);
  2129.                                                 PointChange(POINT_HP, -iHP);
  2130.                                         }
  2131.                                 }
  2132.                         }
  2133.  
  2134.                         if (pAttacker->GetPoint(POINT_STEAL_SP))
  2135.                         {
  2136.                                 int pct = 1;
  2137.  
  2138.                                 if (number(1, 10) <= pct)
  2139.                                 {
  2140.                                         int iCur;
  2141.  
  2142.                                         if (IsPC())
  2143.                                                 iCur = iCurSP;
  2144.                                         else
  2145.                                                 iCur = iCurHP;
  2146.  
  2147.                                         int iSP = MIN(dam, MAX(0, iCur)) * pAttacker->GetPoint(POINT_STEAL_SP) / 100;
  2148.  
  2149.                                         if (iSP > 0 && iCur >= iSP)
  2150.                                         {
  2151.                                                 CreateFly(FLY_SP_SMALL, pAttacker);
  2152.                                                 pAttacker->PointChange(POINT_SP, iSP);
  2153.  
  2154.                                                 if (IsPC())
  2155.                                                         PointChange(POINT_SP, -iSP);
  2156.                                         }
  2157.                                 }
  2158.                         }
  2159.  
  2160.                         if (pAttacker->GetPoint(POINT_STEAL_GOLD))
  2161.                         {
  2162.                                 if (number(1, 100) <= pAttacker->GetPoint(POINT_STEAL_GOLD))
  2163.                                 {
  2164.                                         int iAmount = number(1, GetLevel());
  2165.                                         pAttacker->PointChange(POINT_GOLD, iAmount);
  2166.                                         DBManager::instance().SendMoneyLog(MONEY_LOG_MISC, 1, iAmount);
  2167.                                 }
  2168.                         }
  2169.  
  2170.                         if (pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) && number(0, 4) > 0)
  2171.                         {
  2172.                                 int i = ((iCurHP >= 0) ? MIN(dam, iCurHP) : dam) * pAttacker->GetPoint(POINT_HIT_HP_RECOVERY) / 100; //@fixme107
  2173.  
  2174.                                 if (i)
  2175.                                 {
  2176.                                         CreateFly(FLY_HP_SMALL, pAttacker);
  2177.                                         pAttacker->PointChange(POINT_HP, i);
  2178.                                 }
  2179.                         }
  2180.  
  2181.                         if (pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) && number(0, 4) > 0)
  2182.                         {
  2183.                                 int i = ((iCurHP >= 0) ? MIN(dam, iCurHP) : dam) * pAttacker->GetPoint(POINT_HIT_SP_RECOVERY) / 100; //@fixme107
  2184.  
  2185.                                 if (i)
  2186.                                 {
  2187.                                         CreateFly(FLY_SP_SMALL, pAttacker);
  2188.                                         pAttacker->PointChange(POINT_SP, i);
  2189.                                 }
  2190.                         }
  2191.  
  2192.                         if (pAttacker->GetPoint(POINT_MANA_BURN_PCT))
  2193.                         {
  2194.                                 if (number(1, 100) <= pAttacker->GetPoint(POINT_MANA_BURN_PCT))
  2195.                                         PointChange(POINT_SP, -50);
  2196.                         }
  2197.                 }
  2198.         }
  2199.  
  2200.         //
  2201.  
  2202.         //
  2203.         switch (type)
  2204.         {
  2205.         case DAMAGE_TYPE_NORMAL:
  2206.         case DAMAGE_TYPE_NORMAL_RANGE:
  2207.                 if (pAttacker)
  2208.                         if (pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS))
  2209.                                 dam = dam * (100 + pAttacker->GetPoint(POINT_NORMAL_HIT_DAMAGE_BONUS)) / 100;
  2210.  
  2211.                 dam = dam * (100 - MIN(99, GetPoint(POINT_NORMAL_HIT_DEFEND_BONUS))) / 100;
  2212.                 break;
  2213.  
  2214.         case DAMAGE_TYPE_MELEE:
  2215.         case DAMAGE_TYPE_RANGE:
  2216.         case DAMAGE_TYPE_FIRE:
  2217.         case DAMAGE_TYPE_ICE:
  2218.         case DAMAGE_TYPE_ELEC:
  2219.         case DAMAGE_TYPE_MAGIC:
  2220.                 if (pAttacker)
  2221.                         if (pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS))
  2222.                                 dam = dam * (100 + pAttacker->GetPoint(POINT_SKILL_DAMAGE_BONUS)) / 100;
  2223.  
  2224.                 dam = dam * (100 - MIN(99, GetPoint(POINT_SKILL_DEFEND_BONUS))) / 100;
  2225.                 break;
  2226.  
  2227.         default:
  2228.                 break;
  2229.         }
  2230.  
  2231.         //
  2232.  
  2233.         //
  2234.         if (IsAffectFlag(AFF_MANASHIELD))
  2235.         {
  2236.                 int iDamageSPPart = dam / 3;
  2237.                 int iDamageToSP = iDamageSPPart * GetPoint(POINT_MANASHIELD) / 100;
  2238.                 int iSP = GetSP();
  2239.  
  2240.                 if (iDamageToSP <= iSP)
  2241.                 {
  2242.                         PointChange(POINT_SP, -iDamageToSP);
  2243.                         dam -= iDamageSPPart;
  2244.                 }
  2245.                 else
  2246.                 {
  2247.                         PointChange(POINT_SP, -GetSP());
  2248.                         dam -= iSP * 100 / MAX(GetPoint(POINT_MANASHIELD), 1);
  2249.                 }
  2250.         }
  2251.  
  2252.         //
  2253.  
  2254.         //
  2255.         if (GetPoint(POINT_MALL_DEFBONUS) > 0)
  2256.         {
  2257.                 int dec_dam = MIN(200, dam * GetPoint(POINT_MALL_DEFBONUS) / 100);
  2258.                 dam -= dec_dam;
  2259.         }
  2260.  
  2261.         if (pAttacker)
  2262.         {
  2263.                 //
  2264.  
  2265.                 //
  2266.                 if (pAttacker->GetPoint(POINT_MALL_ATTBONUS) > 0)
  2267.                 {
  2268.                         int add_dam = MIN(300, dam * pAttacker->GetLimitPoint(POINT_MALL_ATTBONUS) / 100);
  2269.                         dam += add_dam;
  2270.                 }
  2271.  
  2272.                 if (pAttacker->IsPC())
  2273.                 {
  2274.                         int iEmpire = pAttacker->GetEmpire();
  2275.                         long lMapIndex = pAttacker->GetMapIndex();
  2276.                         int iMapEmpire = SECTREE_MANAGER::instance().GetEmpireFromMapIndex(lMapIndex);
  2277.  
  2278.                         if (iEmpire && iMapEmpire && iEmpire != iMapEmpire)
  2279.                         {
  2280.                                 dam = dam * 9 / 10;
  2281.                         }
  2282.  
  2283.                         if (!IsPC() && GetMonsterDrainSPPoint())
  2284.                         {
  2285.                                 int iDrain = GetMonsterDrainSPPoint();
  2286.  
  2287.                                 if (iDrain <= pAttacker->GetSP())
  2288.                                         pAttacker->PointChange(POINT_SP, -iDrain);
  2289.                                 else
  2290.                                 {
  2291.                                         int iSP = pAttacker->GetSP();
  2292.                                         pAttacker->PointChange(POINT_SP, -iSP);
  2293.                                 }
  2294.                         }
  2295.                 }
  2296.                 else if (pAttacker->IsGuardNPC())
  2297.                 {
  2298.                         SET_BIT(m_pointsInstant.instant_flag, INSTANT_FLAG_NO_REWARD);
  2299.                         Stun();
  2300.                         return true;
  2301.                 }
  2302.  
  2303.                 //
  2304.  
  2305.                 //
  2306.                 if (pAttacker->IsPC() && CMonarch::instance().IsPowerUp(pAttacker->GetEmpire()))
  2307.                 {
  2308.                         dam += dam / 10;
  2309.                 }
  2310.  
  2311.                 if (IsPC() && CMonarch::instance().IsDefenceUp(GetEmpire()))
  2312.                 {
  2313.                         dam -= dam / 10;
  2314.                 }
  2315.         }
  2316.         //puAttr.Pop();
  2317.  
  2318.         if (!GetSectree() || GetSectree()->IsAttr(GetX(), GetY(), ATTR_BANPK))
  2319.                 return false;
  2320.  
  2321.         if (!IsPC())
  2322.         {
  2323.                 if (m_pkParty && m_pkParty->GetLeader())
  2324.                         m_pkParty->GetLeader()->SetLastAttacked(get_dword_time());
  2325.                 else
  2326.                         SetLastAttacked(get_dword_time());
  2327.  
  2328.                 MonsterChat(MONSTER_CHAT_ATTACKED);
  2329.         }
  2330.  
  2331.         if (IsStun())
  2332.         {
  2333.                 Dead(pAttacker);
  2334.                 return true;
  2335.         }
  2336.  
  2337.         if (IsDead())
  2338.                 return true;
  2339.  
  2340.         if (type == DAMAGE_TYPE_POISON)
  2341.         {
  2342.                 if (GetHP() - dam <= 0)
  2343.                 {
  2344.                         dam = GetHP() - 1;
  2345.                 }
  2346.         }
  2347. #ifdef ENABLE_WOLFMAN_CHARACTER
  2348.         else if (type == DAMAGE_TYPE_BLEEDING)
  2349.         {
  2350.                 if (GetHP() - dam <= 0)
  2351.                 {
  2352.                         dam = GetHP();
  2353.                 }
  2354.         }
  2355. #endif
  2356.         // ------------------------
  2357.  
  2358.         // -----------------------
  2359.         if (pAttacker && pAttacker->IsPC())
  2360.         {
  2361.                 int iDmgPct = CHARACTER_MANAGER::instance().GetUserDamageRate(pAttacker);
  2362.                 dam = dam * iDmgPct / 100;
  2363.         }
  2364.  
  2365.         if (IsMonster() && IsStoneSkinner())
  2366.         {
  2367.                 if (GetHPPct() < GetMobTable().bStoneSkinPoint)
  2368.                         dam /= 2;
  2369.         }
  2370.  
  2371.         //PROF_UNIT puRest1("Rest1");
  2372.         if (pAttacker)
  2373.         {
  2374.                 if (pAttacker->IsMonster() && pAttacker->IsDeathBlower())
  2375.                 {
  2376.                         if (pAttacker->IsDeathBlow())
  2377.                         {
  2378.                                 if (number(1, 4) == GetJob())
  2379.                                 {
  2380.                                         IsDeathBlow = true;
  2381.                                         dam = dam * 4;
  2382.                                 }
  2383.                         }
  2384.                 }
  2385.  
  2386.                 dam = BlueDragon_Damage(this, pAttacker, dam);
  2387.  
  2388.                 BYTE damageFlag = 0;
  2389.  
  2390.                 if (type == DAMAGE_TYPE_POISON)
  2391.                         damageFlag = DAMAGE_POISON;
  2392. #if defined(ENABLE_WOLFMAN_CHARACTER) && !defined(USE_MOB_BLEEDING_AS_POISON)
  2393.                 else if (type == DAMAGE_TYPE_BLEEDING)
  2394.                         damageFlag = DAMAGE_BLEEDING;
  2395. #elif defined(ENABLE_WOLFMAN_CHARACTER) && defined(USE_MOB_BLEEDING_AS_POISON)
  2396.                 else if (type == DAMAGE_TYPE_BLEEDING)
  2397.                         damageFlag = DAMAGE_POISON;
  2398. #endif
  2399.                 else
  2400.                         damageFlag = DAMAGE_NORMAL;
  2401.  
  2402.                 if (IsCritical == true)
  2403.                         damageFlag |= DAMAGE_CRITICAL;
  2404.  
  2405.                 if (IsPenetrate == true)
  2406.                         damageFlag |= DAMAGE_PENETRATE;
  2407.  
  2408.                 float damMul = this->GetDamMul();
  2409.                 float tempDam = dam;
  2410.                 dam = tempDam * damMul + 0.5f;
  2411. // @fixme187 BEGIN
  2412.                 if (pAttacker->IsPC())
  2413.                 {
  2414.                         if (pAttacker->IsAffectFlag(AFF_REVIVE_INVISIBLE) || IsAffectFlag(AFF_REVIVE_INVISIBLE))
  2415.                         {
  2416.                                 dam = 0;
  2417.                                 damageFlag = DAMAGE_DODGE;
  2418.                         }
  2419.                 }
  2420. // @fixme187 END
  2421.                 if (pAttacker)
  2422.                         SendDamagePacket(pAttacker, dam, damageFlag);
  2423.  
  2424.                 if (test_server)
  2425.                 {
  2426.                         int iTmpPercent = 0; // @fixme136
  2427.                         if (GetMaxHP() >= 0)
  2428.                                 iTmpPercent = (GetHP() * 100) / GetMaxHP();
  2429.  
  2430.                         if (pAttacker)
  2431.                         {
  2432.                                 pAttacker->ChatPacket(CHAT_TYPE_INFO, "-> %s, DAM %d HP %d(%d%%) %s%s",
  2433.                                         GetName(),
  2434.                                         dam,
  2435.                                         GetHP(),
  2436.                                         iTmpPercent,
  2437.                                         IsCritical ? "crit " : "",
  2438.                                         IsPenetrate ? "pene " : "",
  2439.                                         IsDeathBlow ? "deathblow " : "");
  2440.                         }
  2441.  
  2442.                         ChatPacket(CHAT_TYPE_PARTY, "<- %s, DAM %d HP %d(%d%%) %s%s",
  2443.                                 pAttacker ? pAttacker->GetName() : 0,
  2444.                                 dam,
  2445.                                 GetHP(),
  2446.                                 iTmpPercent,
  2447.                                 IsCritical ? "crit " : "",
  2448.                                 IsPenetrate ? "pene " : "",
  2449.                                 IsDeathBlow ? "deathblow " : "");
  2450.                 }
  2451.  
  2452.                 if (m_bDetailLog)
  2453.                 {
  2454.                         ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s[%d]가 공격 위치: %d %d"), pAttacker->GetName(), (DWORD)pAttacker->GetVID(), pAttacker->GetX(), pAttacker->GetY());
  2455.                 }
  2456.         }
  2457.  
  2458.         //
  2459.  
  2460.         //
  2461.         if (!cannot_dead)
  2462.         {
  2463.                 if (GetHP() - dam <= 0) // @fixme137
  2464.                         dam = GetHP();
  2465.                 PointChange(POINT_HP, -dam, false);
  2466.         }
  2467.  
  2468.         //puRest1.Pop();
  2469.  
  2470.         //PROF_UNIT puRest2("Rest2");
  2471.         if (pAttacker && dam > 0 && IsNPC())
  2472.         {
  2473.                 //PROF_UNIT puRest20("Rest20");
  2474.                 TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
  2475.  
  2476.                 if (it == m_map_kDamage.end())
  2477.                 {
  2478.                         m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(dam, 0)));
  2479.                         it = m_map_kDamage.find(pAttacker->GetVID());
  2480.                 }
  2481.                 else
  2482.                 {
  2483.                         it->second.iTotalDamage += dam;
  2484.                 }
  2485.                 //puRest20.Pop();
  2486.  
  2487.                 //PROF_UNIT puRest21("Rest21");
  2488.                 StartRecoveryEvent();
  2489.                 //puRest21.Pop();
  2490.  
  2491.                 //PROF_UNIT puRest22("Rest22");
  2492. #ifdef ENABLE_POISON_UNAGGR
  2493.                 if (type != DAMAGE_TYPE_POISON)
  2494.                         UpdateAggrPointEx(pAttacker, type, dam, it->second);
  2495. #else
  2496.                 UpdateAggrPointEx(pAttacker, type, dam, it->second);
  2497. #endif
  2498.                 //puRest22.Pop();
  2499.         }
  2500.         //puRest2.Pop();
  2501.  
  2502.         //PROF_UNIT puRest3("Rest3");
  2503.         if (GetHP() <= 0)
  2504.         {
  2505.                 Stun();
  2506.  
  2507.                 if (pAttacker && !pAttacker->IsNPC())
  2508.                         m_dwKillerPID = pAttacker->GetPlayerID();
  2509.                 else
  2510.                         m_dwKillerPID = 0;
  2511.         }
  2512.  
  2513.         return false;
  2514. }
  2515.  
  2516. void CHARACTER::DistributeHP(LPCHARACTER pkKiller)
  2517. {
  2518.         if (pkKiller->GetDungeon())
  2519.                 return;
  2520. }
  2521. #define ENABLE_NEWEXP_CALCULATION
  2522. #ifdef ENABLE_NEWEXP_CALCULATION
  2523. #define NEW_GET_LVDELTA(me, victim) aiPercentByDeltaLev[MINMAX(0, (victim + 15) - me, MAX_EXP_DELTA_OF_LEV - 1)]
  2524. typedef long double rate_t;
  2525. static void GiveExp(LPCHARACTER from, LPCHARACTER to, int iExp)
  2526. {
  2527.         if (test_server && iExp < 0)
  2528.         {
  2529.                 to->ChatPacket(CHAT_TYPE_INFO, "exp(%d) overflow", iExp);
  2530.                 return;
  2531.         }
  2532.         // decrease/increase exp based on player<>mob level
  2533.         rate_t lvFactor = static_cast<rate_t>(NEW_GET_LVDELTA(to->GetLevel(), from->GetLevel())) / 100.0L;
  2534.         iExp *= lvFactor;
  2535.         // start calculating rate exp bonus
  2536.         int iBaseExp = iExp;
  2537.         rate_t rateFactor = 100;
  2538.         if (distribution_test_server)
  2539.                 rateFactor *= 3;
  2540.  
  2541.         rateFactor += CPrivManager::instance().GetPriv(to, PRIV_EXP_PCT);
  2542.         if (to->IsEquipUniqueItem(UNIQUE_ITEM_LARBOR_MEDAL))
  2543.                 rateFactor += 20;
  2544.         if (to->GetMapIndex() >= 660000 && to->GetMapIndex() < 670000)
  2545.                 rateFactor += 20;
  2546.         if (to->GetPoint(POINT_EXP_DOUBLE_BONUS))
  2547.                 if (number(1, 100) <= to->GetPoint(POINT_EXP_DOUBLE_BONUS))
  2548.                         rateFactor += 30;
  2549.         if (to->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_EXP))
  2550.                 rateFactor += 50;
  2551.  
  2552.         switch (to->GetMountVnum())
  2553.         {
  2554.         case 20110:
  2555.         case 20111:
  2556.         case 20112:
  2557.         case 20113:
  2558.                 if (to->IsEquipUniqueItem(71115) || to->IsEquipUniqueItem(71117) || to->IsEquipUniqueItem(71119) ||
  2559.                         to->IsEquipUniqueItem(71121))
  2560.                 {
  2561.                         rateFactor += 10;
  2562.                 }
  2563.                 break;
  2564.  
  2565.         case 20114:
  2566.         case 20120:
  2567.         case 20121:
  2568.         case 20122:
  2569.         case 20123:
  2570.         case 20124:
  2571.         case 20125:
  2572.                 rateFactor += 30;
  2573.                 break;
  2574.         }
  2575.  
  2576.         if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
  2577.                 rateFactor += 50;
  2578.         if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP))
  2579.                 rateFactor += 50;
  2580.         if (to->GetPoint(POINT_PC_BANG_EXP_BONUS) > 0)
  2581.         {
  2582.                 if (to->IsPCBang())
  2583.                         rateFactor += to->GetPoint(POINT_PC_BANG_EXP_BONUS);
  2584.         }
  2585.         rateFactor += to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS);
  2586.         rateFactor += to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP);
  2587.         rateFactor += to->GetPoint(POINT_MALL_EXPBONUS);
  2588.         rateFactor += to->GetPoint(POINT_EXP);
  2589.         // useless (never used except for china intoxication) = always 100
  2590.         rateFactor = rateFactor * static_cast<rate_t>(CHARACTER_MANAGER::instance().GetMobExpRate(to)) / 100.0L;
  2591.         // fix underflow formula
  2592.         iExp = std::max<int>(0, iExp);
  2593.         rateFactor = std::max<rate_t>(100.0L, rateFactor);
  2594.         // apply calculated rate bonus
  2595.         iExp *= (rateFactor / 100.0L);
  2596.         if (test_server)
  2597.                 to->ChatPacket(CHAT_TYPE_INFO, "base_exp(%d) * rate(%Lf) = exp(%d)", iBaseExp, rateFactor / 100.0L, iExp);
  2598.         // you can get at maximum only 10% of the total required exp at once (so, you need to kill at least 10 mobs to level up) (useless)
  2599.         iExp = MIN(to->GetNextExp() / 10, iExp);
  2600.         // it recalculate the given exp if the player level is greater than the exp_table size (useless)
  2601.         iExp = AdjustExpByLevel(to, iExp);
  2602.         if (test_server)
  2603.                 to->ChatPacket(CHAT_TYPE_INFO, "exp+minGNE+adjust(%d)", iExp);
  2604. #ifdef ENABLE_NEW_PET_SYSTEM
  2605.         if (to->GetNewPetSystem())
  2606.         {
  2607.                 if (to->GetNewPetSystem()->IsActivePet() && to->GetNewPetSystem()->GetLevelStep() < 4)
  2608.                 {
  2609.                         int tmpexp = iExp * 9 / 20;
  2610.                         if (to->GetQuestFlag("PetSystems.petfullexp") == 1)
  2611.                                 tmpexp = 0;
  2612.                         iExp = iExp - tmpexp;
  2613.                         to->GetNewPetSystem()->SetExp(tmpexp, 0);
  2614.                 }
  2615.         }
  2616. #endif
  2617. #ifdef ENABLE_SUPPORT_SHAMAN_SYSTEM
  2618.         if (to->GetSupportShaman())
  2619.         {
  2620.                 if (to->GetSupportShaman()->IsActiveSupportShaman() && to->GetSupportShaman()->GetLevel() < 120)
  2621.                 {
  2622.                         int tmpexp = iExp * 9 / 20;
  2623.                         iExp = iExp - tmpexp;
  2624.                         to->GetSupportShaman()->SetExp(tmpexp);
  2625.                 }
  2626.         }
  2627. #endif
  2628. #ifdef EXP_MULTIPLER
  2629.         iExp *= EXP_MULTIPLER;
  2630. #endif
  2631. #ifdef ENABLE_RING_OF_SECRETS
  2632.         if (!to->IsEquipUniqueItem(ITEM_ANTIEXP_RING))
  2633. #endif
  2634.         {
  2635.                 to->PointChange(POINT_EXP, iExp, true);
  2636.                 from->CreateFly(FLY_EXP, to);
  2637.         }
  2638.         {
  2639.                 LPCHARACTER you = to->GetMarryPartner();
  2640.                 if (you)
  2641.                 {
  2642.                         // sometimes, this overflows
  2643.                         DWORD dwUpdatePoint = (2000.0L / to->GetLevel() / to->GetLevel() / 3) * iExp;
  2644.  
  2645.                         if (to->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0 ||
  2646.                                 you->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0)
  2647.                                 dwUpdatePoint *= 3;
  2648.  
  2649.                         marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(to->GetPlayerID());
  2650.  
  2651.                         // DIVORCE_NULL_BUG_FIX
  2652.                         if (pMarriage && pMarriage->IsNear())
  2653.                                 pMarriage->Update(dwUpdatePoint);
  2654.                         // END_OF_DIVORCE_NULL_BUG_FIX
  2655.                 }
  2656.         }
  2657. }
  2658. #else
  2659. static void GiveExp(LPCHARACTER from, LPCHARACTER to, int iExp)
  2660. {
  2661.         iExp = CALCULATE_VALUE_LVDELTA(to->GetLevel(), from->GetLevel(), iExp);
  2662.  
  2663.         if (distribution_test_server)
  2664.                 iExp *= 3;
  2665.  
  2666.         int iBaseExp = iExp;
  2667.  
  2668.         iExp = iExp * (100 + CPrivManager::instance().GetPriv(to, PRIV_EXP_PCT)) / 100;
  2669.  
  2670.         {
  2671.                 if (to->IsEquipUniqueItem(UNIQUE_ITEM_LARBOR_MEDAL))
  2672.                         iExp += iExp * 20 / 100;
  2673.  
  2674.                 if (to->GetMapIndex() >= 660000 && to->GetMapIndex() < 670000)
  2675.                         iExp += iExp * 20 / 100; // 1.2배 (20%)
  2676.  
  2677.                 if (to->GetPoint(POINT_EXP_DOUBLE_BONUS))
  2678.                         if (number(1, 100) <= to->GetPoint(POINT_EXP_DOUBLE_BONUS))
  2679.                                 iExp += iExp * 30 / 100; // 1.3배 (30%)
  2680.  
  2681.                 if (to->IsEquipUniqueItem(UNIQUE_ITEM_DOUBLE_EXP))
  2682.                         iExp += iExp * 50 / 100;
  2683.  
  2684.                 switch (to->GetMountVnum())
  2685.                 {
  2686.                 case 20110:
  2687.                 case 20111:
  2688.                 case 20112:
  2689.                 case 20113:
  2690.                         if (to->IsEquipUniqueItem(71115) || to->IsEquipUniqueItem(71117) || to->IsEquipUniqueItem(71119) ||
  2691.                                 to->IsEquipUniqueItem(71121))
  2692.                         {
  2693.                                 iExp += iExp * 10 / 100;
  2694.                         }
  2695.                         break;
  2696.  
  2697.                 case 20114:
  2698.                 case 20120:
  2699.                 case 20121:
  2700.                 case 20122:
  2701.                 case 20123:
  2702.                 case 20124:
  2703.                 case 20125:
  2704.  
  2705.                         iExp += iExp * 30 / 100;
  2706.                         break;
  2707.                 }
  2708.         }
  2709.  
  2710.         {
  2711.                 if (to->GetPremiumRemainSeconds(PREMIUM_EXP) > 0)
  2712.                 {
  2713.                         iExp += (iExp * 50 / 100);
  2714.                 }
  2715.  
  2716.                 if (to->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_EXP) == true)
  2717.                 {
  2718.                         iExp += (iExp * 50 / 100);
  2719.                 }
  2720.  
  2721.                 if (to->GetPoint(POINT_PC_BANG_EXP_BONUS) > 0)
  2722.                 {
  2723.                         if (to->IsPCBang() == true)
  2724.                                 iExp += (iExp * to->GetPoint(POINT_PC_BANG_EXP_BONUS) / 100);
  2725.                 }
  2726.  
  2727.                 iExp += iExp * to->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_EXP_BONUS) / 100;
  2728.         }
  2729.  
  2730.         iExp += (iExp * to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP) / 100);
  2731.         iExp += (iExp * to->GetPoint(POINT_MALL_EXPBONUS) / 100);
  2732.         iExp += (iExp * to->GetPoint(POINT_EXP) / 100);
  2733.  
  2734.         /*      if (speed_server)
  2735.                 {
  2736.                         iExp += iExp * CSpeedServerManager::ExpBonus();
  2737.                 }
  2738.         */
  2739.         if (test_server)
  2740.         {
  2741.                 sys_log(0, "Bonus Exp : Ramadan Candy: %d MallExp: %d PointExp: %d",
  2742.                         to->GetPoint(POINT_RAMADAN_CANDY_BONUS_EXP),
  2743.                         to->GetPoint(POINT_MALL_EXPBONUS),
  2744.                         to->GetPoint(POINT_EXP)
  2745.                 );
  2746.         }
  2747.  
  2748.         iExp = iExp * CHARACTER_MANAGER::instance().GetMobExpRate(to) / 100;
  2749.  
  2750.         iExp = MIN(to->GetNextExp() / 10, iExp);
  2751.  
  2752.         if (test_server)
  2753.         {
  2754.                 if (quest::CQuestManager::instance().GetEventFlag("exp_bonus_log") && iBaseExp > 0)
  2755.                         to->ChatPacket(CHAT_TYPE_INFO, "exp bonus %d%%", (iExp - iBaseExp) * 100 / iBaseExp);
  2756.                 to->ChatPacket(CHAT_TYPE_INFO, "exp(%d) base_exp(%d)", iExp, iBaseExp);
  2757.         }
  2758.  
  2759.         iExp = AdjustExpByLevel(to, iExp);
  2760.  
  2761.         to->PointChange(POINT_EXP, iExp, true);
  2762.         from->CreateFly(FLY_EXP, to);
  2763.  
  2764.         {
  2765.                 LPCHARACTER you = to->GetMarryPartner();
  2766.  
  2767.                 if (you)
  2768.                 {
  2769.                         // 1억이 100%
  2770.                         DWORD dwUpdatePoint = 2000 * iExp / to->GetLevel() / to->GetLevel() / 3;
  2771.  
  2772.                         if (to->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0 ||
  2773.                                 you->GetPremiumRemainSeconds(PREMIUM_MARRIAGE_FAST) > 0)
  2774.                                 dwUpdatePoint = (DWORD)(dwUpdatePoint * 3);
  2775.  
  2776.                         marriage::TMarriage* pMarriage = marriage::CManager::instance().Get(to->GetPlayerID());
  2777.  
  2778.                         // DIVORCE_NULL_BUG_FIX
  2779.                         if (pMarriage && pMarriage->IsNear())
  2780.                                 pMarriage->Update(dwUpdatePoint);
  2781.                         // END_OF_DIVORCE_NULL_BUG_FIX
  2782.                 }
  2783.         }
  2784. }
  2785. #endif
  2786.  
  2787. namespace NPartyExpDistribute
  2788. {
  2789.         struct FPartyTotaler
  2790.         {
  2791.                 int             total;
  2792.                 int             member_count;
  2793.                 int             x, y;
  2794.  
  2795.                 FPartyTotaler(LPCHARACTER center)
  2796.                         : total(0), member_count(0), x(center->GetX()), y(center->GetY())
  2797.                 {};
  2798.  
  2799.                 void operator () (LPCHARACTER ch)
  2800.                 {
  2801.                         if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
  2802.                         {
  2803.                                 total += __GetPartyExpNP(ch->GetLevel());
  2804.  
  2805.                                 ++member_count;
  2806.                         }
  2807.                 }
  2808.         };
  2809.  
  2810.         struct FPartyDistributor
  2811.         {
  2812.                 int             total;
  2813.                 LPCHARACTER     c;
  2814.                 int             x, y;
  2815.                 DWORD           _iExp;
  2816.                 int             m_iMode;
  2817.                 int             m_iMemberCount;
  2818.  
  2819.                 FPartyDistributor(LPCHARACTER center, int member_count, int total, DWORD iExp, int iMode)
  2820.                         : total(total), c(center), x(center->GetX()), y(center->GetY()), _iExp(iExp), m_iMode(iMode), m_iMemberCount(member_count)
  2821.                 {
  2822.                         if (m_iMemberCount == 0)
  2823.                                 m_iMemberCount = 1;
  2824.                 };
  2825.  
  2826.                 void operator () (LPCHARACTER ch)
  2827.                 {
  2828.                         if (DISTANCE_APPROX(ch->GetX() - x, ch->GetY() - y) <= PARTY_DEFAULT_RANGE)
  2829.                         {
  2830.                                 DWORD iExp2 = 0;
  2831.  
  2832.                                 switch (m_iMode)
  2833.                                 {
  2834.                                 case PARTY_EXP_DISTRIBUTION_NON_PARITY:
  2835.                                         iExp2 = (DWORD)(_iExp * (float)__GetPartyExpNP(ch->GetLevel()) / total);
  2836.                                         break;
  2837.  
  2838.                                 case PARTY_EXP_DISTRIBUTION_PARITY:
  2839.                                         iExp2 = _iExp / m_iMemberCount;
  2840.                                         break;
  2841.  
  2842.                                 default:
  2843.                                         sys_err("Unknown party exp distribution mode %d", m_iMode);
  2844.                                         return;
  2845.                                 }
  2846.  
  2847.                                 GiveExp(c, ch, iExp2);
  2848.                         }
  2849.                 }
  2850.         };
  2851. }
  2852.  
  2853. typedef struct SDamageInfo
  2854. {
  2855.         int iDam;
  2856.         LPCHARACTER pAttacker;
  2857.         LPPARTY pParty;
  2858.  
  2859.         void Clear()
  2860.         {
  2861.                 pAttacker = NULL;
  2862.                 pParty = NULL;
  2863.         }
  2864.  
  2865.         inline void Distribute(LPCHARACTER ch, int iExp)
  2866.         {
  2867.                 if (pAttacker)
  2868.                         GiveExp(ch, pAttacker, iExp);
  2869.                 else if (pParty)
  2870.                 {
  2871.                         NPartyExpDistribute::FPartyTotaler f(ch);
  2872.                         pParty->ForEachOnlineMember(f);
  2873.  
  2874.                         if (pParty->IsPositionNearLeader(ch))
  2875.                                 iExp = iExp * (100 + pParty->GetExpBonusPercent()) / 100;
  2876.  
  2877.                         if (test_server)
  2878.                         {
  2879.                                 if (quest::CQuestManager::instance().GetEventFlag("exp_bonus_log") && pParty->GetExpBonusPercent())
  2880.                                         pParty->ChatPacketToAllMember(CHAT_TYPE_INFO, "exp party bonus %d%%", pParty->GetExpBonusPercent());
  2881.                         }
  2882.  
  2883.                         if (pParty->GetExpCentralizeCharacter())
  2884.                         {
  2885.                                 LPCHARACTER tch = pParty->GetExpCentralizeCharacter();
  2886.  
  2887.                                 if (DISTANCE_APPROX(ch->GetX() - tch->GetX(), ch->GetY() - tch->GetY()) <= PARTY_DEFAULT_RANGE)
  2888.                                 {
  2889.                                         int iExpCenteralize = (int)(iExp * 0.05f);
  2890.                                         iExp -= iExpCenteralize;
  2891.  
  2892.                                         GiveExp(ch, pParty->GetExpCentralizeCharacter(), iExpCenteralize);
  2893.                                 }
  2894.                         }
  2895.  
  2896.                         NPartyExpDistribute::FPartyDistributor fDist(ch, f.member_count, f.total, iExp, pParty->GetExpDistributionMode());
  2897.                         pParty->ForEachOnlineMember(fDist);
  2898.                 }
  2899.         }
  2900. } TDamageInfo;
  2901.  
  2902. LPCHARACTER CHARACTER::DistributeExp()
  2903. {
  2904.         int iExpToDistribute = GetExp();
  2905.  
  2906.         if (iExpToDistribute <= 0)
  2907.                 return NULL;
  2908.  
  2909.         int     iTotalDam = 0;
  2910.         LPCHARACTER pkChrMostAttacked = NULL;
  2911.         int iMostDam = 0;
  2912.  
  2913.         typedef std::vector<TDamageInfo> TDamageInfoTable;
  2914.         TDamageInfoTable damage_info_table;
  2915.         std::map<LPPARTY, TDamageInfo> map_party_damage;
  2916.  
  2917.         damage_info_table.reserve(m_map_kDamage.size());
  2918.  
  2919.         TDamageMap::iterator it = m_map_kDamage.begin();
  2920.  
  2921.         while (it != m_map_kDamage.end())
  2922.         {
  2923.                 const VID& c_VID = it->first;
  2924.                 int iDam = it->second.iTotalDamage;
  2925.  
  2926.                 ++it;
  2927.  
  2928.                 LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
  2929.  
  2930.                 if (!pAttacker || !pAttacker->IsPC() || pAttacker->IsNPC() || DISTANCE_APPROX(GetX() - pAttacker->GetX(), GetY() - pAttacker->GetY()) > 5000)// @fixme205
  2931.                         continue;
  2932.  
  2933.                 iTotalDam += iDam;
  2934.                 if (!pkChrMostAttacked || iDam > iMostDam)
  2935.                 {
  2936.                         pkChrMostAttacked = pAttacker;
  2937.                         iMostDam = iDam;
  2938.                 }
  2939.  
  2940.                 if (pAttacker->GetParty())
  2941.                 {
  2942.                         std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.find(pAttacker->GetParty());
  2943.                         if (it == map_party_damage.end())
  2944.                         {
  2945.                                 TDamageInfo di;
  2946.                                 di.iDam = iDam;
  2947.                                 di.pAttacker = NULL;
  2948.                                 di.pParty = pAttacker->GetParty();
  2949.                                 map_party_damage.insert(std::make_pair(di.pParty, di));
  2950.                         }
  2951.                         else
  2952.                         {
  2953.                                 it->second.iDam += iDam;
  2954.                         }
  2955.                 }
  2956.                 else
  2957.                 {
  2958.                         TDamageInfo di;
  2959.  
  2960.                         di.iDam = iDam;
  2961.                         di.pAttacker = pAttacker;
  2962.                         di.pParty = NULL;
  2963.  
  2964.                         //sys_log(0, "__ pq_damage %s %d", pAttacker->GetName(), iDam);
  2965.                         //pq_damage.push(di);
  2966.                         damage_info_table.push_back(di);
  2967.                 }
  2968.         }
  2969.  
  2970.         for (std::map<LPPARTY, TDamageInfo>::iterator it = map_party_damage.begin(); it != map_party_damage.end(); ++it)
  2971.         {
  2972.                 damage_info_table.push_back(it->second);
  2973.                 //sys_log(0, "__ pq_damage_party [%u] %d", it->second.pParty->GetLeaderPID(), it->second.iDam);
  2974.         }
  2975.  
  2976.         SetExp(0);
  2977.         //m_map_kDamage.clear();
  2978.  
  2979.         if (iTotalDam == 0)
  2980.                 return NULL;
  2981.  
  2982.         if (m_pkChrStone)
  2983.         {
  2984.                 //sys_log(0, "__ Give half to Stone : %d", iExpToDistribute>>1);
  2985.                 int iExp = iExpToDistribute >> 1;
  2986.                 m_pkChrStone->SetExp(m_pkChrStone->GetExp() + iExp);
  2987.                 iExpToDistribute -= iExp;
  2988.         }
  2989.  
  2990.         sys_log(1, "%s total exp: %d, damage_info_table.size() == %d, TotalDam %d",
  2991.                 GetName(), iExpToDistribute, damage_info_table.size(), iTotalDam);
  2992.         //sys_log(1, "%s total exp: %d, pq_damage.size() == %d, TotalDam %d",
  2993.         //GetName(), iExpToDistribute, pq_damage.size(), iTotalDam);
  2994.  
  2995.         if (damage_info_table.empty())
  2996.                 return NULL;
  2997.  
  2998.         DistributeHP(pkChrMostAttacked);
  2999.  
  3000.         {
  3001.                 TDamageInfoTable::iterator di = damage_info_table.begin();
  3002.                 {
  3003.                         TDamageInfoTable::iterator it;
  3004.  
  3005.                         for (it = damage_info_table.begin(); it != damage_info_table.end(); ++it)
  3006.                         {
  3007.                                 if (it->iDam > di->iDam)
  3008.                                         di = it;
  3009.                         }
  3010.                 }
  3011.  
  3012.                 int     iExp = iExpToDistribute / 5;
  3013.                 iExpToDistribute -= iExp;
  3014.  
  3015.                 float fPercent = (float)di->iDam / iTotalDam;
  3016.  
  3017.                 if (fPercent > 1.0f)
  3018.                 {
  3019.                         sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di->pAttacker->GetName());
  3020.                         fPercent = 1.0f;
  3021.                 }
  3022.  
  3023.                 iExp += (int)(iExpToDistribute * fPercent);
  3024.  
  3025.                 //sys_log(0, "%s given exp percent %.1f + 20 dam %d", GetName(), fPercent * 100.0f, di.iDam);
  3026.  
  3027.                 di->Distribute(this, iExp);
  3028.  
  3029.                 if (fPercent == 1.0f)
  3030.                         return pkChrMostAttacked;
  3031.  
  3032.                 di->Clear();
  3033.         }
  3034.  
  3035.         {
  3036.                 TDamageInfoTable::iterator it;
  3037.  
  3038.                 for (it = damage_info_table.begin(); it != damage_info_table.end(); ++it)
  3039.                 {
  3040.                         TDamageInfo& di = *it;
  3041.  
  3042.                         float fPercent = (float)di.iDam / iTotalDam;
  3043.  
  3044.                         if (fPercent > 1.0f)
  3045.                         {
  3046.                                 sys_err("DistributeExp percent over 1.0 (fPercent %f name %s)", fPercent, di.pAttacker->GetName());
  3047.                                 fPercent = 1.0f;
  3048.                         }
  3049.  
  3050.                         //sys_log(0, "%s given exp percent %.1f dam %d", GetName(), fPercent * 100.0f, di.iDam);
  3051.                         di.Distribute(this, (int)(iExpToDistribute * fPercent));
  3052.                 }
  3053.         }
  3054.  
  3055.         return pkChrMostAttacked;
  3056. }
  3057.  
  3058. int CHARACTER::GetArrowAndBow(LPITEM* ppkBow, LPITEM* ppkArrow, int iArrowCount/* = 1 */)
  3059. {
  3060.         LPITEM pkBow;
  3061.  
  3062.         if (!(pkBow = GetWear(WEAR_WEAPON)) || pkBow->GetProto()->bSubType != WEAPON_BOW)
  3063.         {
  3064.                 return 0;
  3065.         }
  3066.  
  3067.         LPITEM pkArrow;
  3068.  
  3069. #ifdef ENABLE_QUIVER_SYSTEM
  3070.         if (!(pkArrow = GetWear(WEAR_ARROW)) || pkArrow->GetType() != ITEM_WEAPON || (pkArrow->GetSubType() != WEAPON_ARROW && pkArrow->GetSubType() != WEAPON_QUIVER))
  3071. #else
  3072.         if (!(pkArrow = GetWear(WEAR_ARROW)) || pkArrow->GetType() != ITEM_WEAPON || pkArrow->GetSubType() != WEAPON_ARROW)
  3073. #endif
  3074.         {
  3075.                 return 0;
  3076.         }
  3077.  
  3078. #ifdef ENABLE_QUIVER_SYSTEM
  3079.         if (pkArrow->GetSubType() == WEAPON_QUIVER)
  3080.                 iArrowCount = MIN(iArrowCount, pkArrow->GetSocket(0) - time(0));
  3081.         else
  3082.                 iArrowCount = MIN(iArrowCount, pkArrow->GetCount());
  3083. #else
  3084.         iArrowCount = MIN(iArrowCount, pkArrow->GetCount());
  3085. #endif
  3086.  
  3087.         *ppkBow = pkBow;
  3088.         *ppkArrow = pkArrow;
  3089.  
  3090.         return iArrowCount;
  3091. }
  3092.  
  3093. void CHARACTER::UseArrow(LPITEM pkArrow, DWORD dwArrowCount)
  3094. {
  3095. #ifdef ENABLE_QUIVER_SYSTEM
  3096.         if (pkArrow->GetSubType() == WEAPON_QUIVER)
  3097.                 return;
  3098. #endif
  3099.         int iCount = pkArrow->GetCount();
  3100.         DWORD dwVnum = pkArrow->GetVnum();
  3101.         iCount = iCount - MIN(iCount, dwArrowCount);
  3102.         pkArrow->SetCount(iCount);
  3103.  
  3104.         if (iCount == 0)
  3105.         {
  3106.                 LPITEM pkNewArrow = FindSpecifyItem(dwVnum);
  3107.  
  3108.                 sys_log(0, "UseArrow : FindSpecifyItem %u %p", dwVnum, get_pointer(pkNewArrow));
  3109.  
  3110.                 if (pkNewArrow)
  3111.                         EquipItem(pkNewArrow);
  3112.         }
  3113. }
  3114.  
  3115. class CFuncShoot
  3116. {
  3117. public:
  3118.         LPCHARACTER     m_me;
  3119.         BYTE            m_bType;
  3120.         bool            m_bSucceed;
  3121.  
  3122.         CFuncShoot(LPCHARACTER ch, BYTE bType) : m_me(ch), m_bType(bType), m_bSucceed(FALSE)
  3123.         {
  3124.         }
  3125.  
  3126.         void operator () (DWORD dwTargetVID)
  3127.         {
  3128.                 if (m_bType > 1)
  3129.                 {
  3130.                         if (g_bSkillDisable)
  3131.                                 return;
  3132.  
  3133.                         m_me->m_SkillUseInfo[m_bType].SetMainTargetVID(dwTargetVID);
  3134.                         /*if (m_bType == SKILL_BIPABU || m_bType == SKILL_KWANKYEOK)
  3135.                           m_me->m_SkillUseInfo[m_bType].ResetHitCount();*/
  3136.                 }
  3137.  
  3138.                 LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
  3139.  
  3140.                 if (!pkVictim)
  3141.                         return;
  3142.  
  3143.                 if (!battle_is_attackable(m_me, pkVictim))
  3144.                         return;
  3145.  
  3146.                 if (m_me->IsNPC())
  3147.                 {
  3148.                         if (DISTANCE_APPROX(m_me->GetX() - pkVictim->GetX(), m_me->GetY() - pkVictim->GetY()) > 5000)
  3149.                                 return;
  3150.                 }
  3151.  
  3152.                 LPITEM pkBow, pkArrow;
  3153.  
  3154.                 switch (m_bType)
  3155.                 {
  3156.                 case 0:
  3157.                 {
  3158.                         int iDam = 0;
  3159.  
  3160.                         if (m_me->IsPC())
  3161.                         {
  3162.                                 if (m_me->GetJob() != JOB_ASSASSIN)
  3163.                                         return;
  3164.  
  3165.                                 if (0 == m_me->GetArrowAndBow(&pkBow, &pkArrow))
  3166.                                         return;
  3167.  
  3168.                                 if (m_me->GetSkillGroup() != 0)
  3169.                                         if (!m_me->IsNPC() && m_me->GetSkillGroup() != 2)
  3170.                                         {
  3171.                                                 if (m_me->GetSP() < 5)
  3172.                                                         return;
  3173.  
  3174.                                                 m_me->PointChange(POINT_SP, -5);
  3175.                                         }
  3176.  
  3177.                                 iDam = CalcArrowDamage(m_me, pkVictim, pkBow, pkArrow);
  3178.                                 m_me->UseArrow(pkArrow, 1);
  3179.  
  3180.                                 // check speed hack
  3181.                                 DWORD   dwCurrentTime = get_dword_time();
  3182.                                 if (IS_SPEED_HACK(m_me, pkVictim, dwCurrentTime))
  3183.                                         iDam = 0;
  3184.                         }
  3185.                         else
  3186.                                 iDam = CalcMeleeDamage(m_me, pkVictim);
  3187.  
  3188.                         NormalAttackAffect(m_me, pkVictim);
  3189.  
  3190. #ifdef ENABLE_PENDANT_SYSTEM
  3191.                         iDam = iDam * (100 - (pkVictim->GetPoint(POINT_RESIST_BOW) - pkVictim->GetPoint(POINT_ATTBONUS_BOW))) / 100;
  3192. #else
  3193.                         iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_BOW)) / 100;
  3194. #endif
  3195.                         //sys_log(0, "%s arrow %s dam %d", m_me->GetName(), pkVictim->GetName(), iDam);
  3196.  
  3197.                         m_me->OnMove(true);
  3198.                         pkVictim->OnMove();
  3199.  
  3200.                         if (pkVictim->CanBeginFight())
  3201.                                 pkVictim->BeginFight(m_me);
  3202.  
  3203.                         pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_NORMAL_RANGE);
  3204.                 }
  3205.                 break;
  3206.  
  3207.                 case 1:
  3208.                 {
  3209.                         int iDam;
  3210.  
  3211.                         if (m_me->IsPC())
  3212.                                 return;
  3213.  
  3214.                         iDam = CalcMagicDamage(m_me, pkVictim);
  3215.  
  3216.                         NormalAttackAffect(m_me, pkVictim);
  3217.  
  3218. #ifdef ENABLE_MAGIC_REDUCTION_SYSTEM
  3219.                         const int resist_magic = MINMAX(0, pkVictim->GetPoint(POINT_RESIST_MAGIC), 100);
  3220.                         const int resist_magic_reduction = MINMAX(0, (m_me->GetJob() == JOB_SURA) ? m_me->GetPoint(POINT_RESIST_MAGIC_REDUCTION) / 2 : m_me->GetPoint(POINT_RESIST_MAGIC_REDUCTION), 50);
  3221.                         const int total_res_magic = MINMAX(0, resist_magic - resist_magic_reduction, 100);
  3222.                         iDam = iDam * (100 - total_res_magic) / 100;
  3223. #else
  3224.                         iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_MAGIC)) / 100;
  3225. #endif
  3226.  
  3227.                         //sys_log(0, "%s arrow %s dam %d", m_me->GetName(), pkVictim->GetName(), iDam);
  3228.  
  3229.                         m_me->OnMove(true);
  3230.                         pkVictim->OnMove();
  3231.  
  3232.                         if (pkVictim->CanBeginFight())
  3233.                                 pkVictim->BeginFight(m_me);
  3234.  
  3235.                         pkVictim->Damage(m_me, iDam, DAMAGE_TYPE_MAGIC);
  3236.                 }
  3237.                 break;
  3238.  
  3239.                 case SKILL_YEONSA:
  3240.                 {
  3241.                         //int iUseArrow = 2 + (m_me->GetSkillPower(SKILL_YEONSA) *6/100);
  3242.                         int iUseArrow = 1;
  3243.  
  3244.                         {
  3245.                                 if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  3246.                                 {
  3247.                                         m_me->OnMove(true);
  3248.                                         pkVictim->OnMove();
  3249.  
  3250.                                         if (pkVictim->CanBeginFight())
  3251.                                                 pkVictim->BeginFight(m_me);
  3252.  
  3253.                                         m_me->ComputeSkill(m_bType, pkVictim);
  3254.                                         m_me->UseArrow(pkArrow, iUseArrow);
  3255.  
  3256.                                         if (pkVictim->IsDead())
  3257.                                                 break;
  3258.                                 }
  3259.                                 else
  3260.                                         break;
  3261.                         }
  3262.                 }
  3263.                 break;
  3264.  
  3265.                 case SKILL_KWANKYEOK:
  3266.                 {
  3267.                         int iUseArrow = 1;
  3268.  
  3269.                         if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  3270.                         {
  3271.                                 m_me->OnMove(true);
  3272.                                 pkVictim->OnMove();
  3273.  
  3274.                                 if (pkVictim->CanBeginFight())
  3275.                                         pkVictim->BeginFight(m_me);
  3276.  
  3277.                                 sys_log(0, "%s kwankeyok %s", m_me->GetName(), pkVictim->GetName());
  3278.                                 m_me->ComputeSkill(m_bType, pkVictim);
  3279.                                 m_me->UseArrow(pkArrow, iUseArrow);
  3280.                         }
  3281.                 }
  3282.                 break;
  3283.  
  3284.                 case SKILL_GIGUNG:
  3285.                 {
  3286.                         int iUseArrow = 1;
  3287.                         if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  3288.                         {
  3289.                                 m_me->OnMove(true);
  3290.                                 pkVictim->OnMove();
  3291.  
  3292.                                 if (pkVictim->CanBeginFight())
  3293.                                         pkVictim->BeginFight(m_me);
  3294.  
  3295.                                 sys_log(0, "%s gigung %s", m_me->GetName(), pkVictim->GetName());
  3296.                                 m_me->ComputeSkill(m_bType, pkVictim);
  3297.                                 m_me->UseArrow(pkArrow, iUseArrow);
  3298.                         }
  3299.                 }
  3300.  
  3301.                 break;
  3302.                 case SKILL_HWAJO:
  3303.                 {
  3304.                         int iUseArrow = 1;
  3305.                         if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  3306.                         {
  3307.                                 m_me->OnMove(true);
  3308.                                 pkVictim->OnMove();
  3309.  
  3310.                                 if (pkVictim->CanBeginFight())
  3311.                                         pkVictim->BeginFight(m_me);
  3312.  
  3313.                                 sys_log(0, "%s hwajo %s", m_me->GetName(), pkVictim->GetName());
  3314.                                 m_me->ComputeSkill(m_bType, pkVictim);
  3315.                                 m_me->UseArrow(pkArrow, iUseArrow);
  3316.                         }
  3317.                 }
  3318.  
  3319.                 break;
  3320.  
  3321.                 case SKILL_HORSE_WILDATTACK_RANGE:
  3322.                 {
  3323.                         int iUseArrow = 1;
  3324.                         if (iUseArrow == m_me->GetArrowAndBow(&pkBow, &pkArrow, iUseArrow))
  3325.                         {
  3326.                                 m_me->OnMove(true);
  3327.                                 pkVictim->OnMove();
  3328.  
  3329.                                 if (pkVictim->CanBeginFight())
  3330.                                         pkVictim->BeginFight(m_me);
  3331.  
  3332.                                 sys_log(0, "%s horse_wildattack %s", m_me->GetName(), pkVictim->GetName());
  3333.                                 m_me->ComputeSkill(m_bType, pkVictim);
  3334.                                 m_me->UseArrow(pkArrow, iUseArrow);
  3335.                         }
  3336.                 }
  3337.  
  3338.                 break;
  3339.  
  3340.                 case SKILL_MARYUNG:
  3341.                         //case SKILL_GUMHWAN:
  3342.                 case SKILL_TUSOK:
  3343.                 case SKILL_BIPABU:
  3344.                 case SKILL_NOEJEON:
  3345.                 case SKILL_GEOMPUNG:
  3346.                 case SKILL_SANGONG:
  3347.                 case SKILL_MAHWAN:
  3348.                 case SKILL_PABEOB:
  3349.                         //case SKILL_CURSE:
  3350.                 {
  3351.                         m_me->OnMove(true);
  3352.                         pkVictim->OnMove();
  3353.  
  3354.                         if (pkVictim->CanBeginFight())
  3355.                                 pkVictim->BeginFight(m_me);
  3356.  
  3357.                         sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
  3358.                         m_me->ComputeSkill(m_bType, pkVictim);
  3359.                 }
  3360.                 break;
  3361.  
  3362.                 case SKILL_CHAIN:
  3363.                 {
  3364.                         m_me->OnMove(true);
  3365.                         pkVictim->OnMove();
  3366.  
  3367.                         if (pkVictim->CanBeginFight())
  3368.                                 pkVictim->BeginFight(m_me);
  3369.  
  3370.                         sys_log(0, "%s - Skill %d -> %s", m_me->GetName(), m_bType, pkVictim->GetName());
  3371.                         m_me->ComputeSkill(m_bType, pkVictim);
  3372.                 }
  3373.                 break;
  3374.  
  3375.                 case SKILL_YONGBI:
  3376.                 {
  3377.                         m_me->OnMove(true);
  3378.                 }
  3379.                 break;
  3380.  
  3381.                 /*case SKILL_BUDONG:
  3382.                   {
  3383.                   m_me->OnMove(true);
  3384.                   pkVictim->OnMove();
  3385.  
  3386.                   DWORD * pdw;
  3387.                   DWORD dwEI = AllocEventInfo(sizeof(DWORD) * 2, &pdw);
  3388.                   pdw[0] = m_me->GetVID();
  3389.                   pdw[1] = pkVictim->GetVID();
  3390.  
  3391.                   event_create(budong_event_func, dwEI, PASSES_PER_SEC(1));
  3392.                   }
  3393.                   break;*/
  3394.  
  3395.                 default:
  3396.                         sys_err("CFuncShoot: I don't know this type [%d] of range attack.", (int)m_bType);
  3397.                         break;
  3398.                 }
  3399.  
  3400.                 m_bSucceed = TRUE;
  3401.         }
  3402. };
  3403.  
  3404. bool CHARACTER::Shoot(BYTE bType)
  3405. {
  3406.         sys_log(1, "Shoot %s type %u flyTargets.size %zu", GetName(), bType, m_vec_dwFlyTargets.size());
  3407.  
  3408.         if (!CanMove())
  3409.         {
  3410.                 return false;
  3411.         }
  3412.  
  3413.         CFuncShoot f(this, bType);
  3414.  
  3415.         if (m_dwFlyTargetID != 0)
  3416.         {
  3417.                 f(m_dwFlyTargetID);
  3418.                 m_dwFlyTargetID = 0;
  3419.         }
  3420.  
  3421.         f = std::for_each(m_vec_dwFlyTargets.begin(), m_vec_dwFlyTargets.end(), f);
  3422.         m_vec_dwFlyTargets.clear();
  3423.  
  3424.         return f.m_bSucceed;
  3425. }
  3426.  
  3427. void CHARACTER::FlyTarget(DWORD dwTargetVID, long x, long y, BYTE bHeader)
  3428. {
  3429.         LPCHARACTER pkVictim = CHARACTER_MANAGER::instance().Find(dwTargetVID);
  3430.         TPacketGCFlyTargeting pack;
  3431.  
  3432.         //pack.bHeader  = HEADER_GC_FLY_TARGETING;
  3433.         pack.bHeader = (bHeader == HEADER_CG_FLY_TARGETING) ? HEADER_GC_FLY_TARGETING : HEADER_GC_ADD_FLY_TARGETING;
  3434.         pack.dwShooterVID = GetVID();
  3435.  
  3436.         if (pkVictim)
  3437.         {
  3438.                 pack.dwTargetVID = pkVictim->GetVID();
  3439.                 pack.x = pkVictim->GetX();
  3440.                 pack.y = pkVictim->GetY();
  3441.  
  3442.                 if (bHeader == HEADER_CG_FLY_TARGETING)
  3443.                         m_dwFlyTargetID = dwTargetVID;
  3444.                 else
  3445.                         m_vec_dwFlyTargets.push_back(dwTargetVID);
  3446.         }
  3447.         else
  3448.         {
  3449.                 pack.dwTargetVID = 0;
  3450.                 pack.x = x;
  3451.                 pack.y = y;
  3452.         }
  3453.  
  3454.         sys_log(1, "FlyTarget %s vid %d x %d y %d", GetName(), pack.dwTargetVID, pack.x, pack.y);
  3455.         PacketAround(&pack, sizeof(pack), this);
  3456. }
  3457.  
  3458. LPCHARACTER CHARACTER::GetNearestVictim(LPCHARACTER pkChr)
  3459. {
  3460.         if (NULL == pkChr)
  3461.                 pkChr = this;
  3462.  
  3463.         float fMinDist = 99999.0f;
  3464.         LPCHARACTER pkVictim = NULL;
  3465.  
  3466.         TDamageMap::iterator it = m_map_kDamage.begin();
  3467.  
  3468.         while (it != m_map_kDamage.end())
  3469.         {
  3470.                 const VID& c_VID = it->first;
  3471.                 ++it;
  3472.  
  3473.                 LPCHARACTER pAttacker = CHARACTER_MANAGER::instance().Find(c_VID);
  3474.  
  3475.                 if (!pAttacker)
  3476.                         continue;
  3477.  
  3478.                 if (pAttacker->IsAffectFlag(AFF_EUNHYUNG) ||
  3479.                         pAttacker->IsAffectFlag(AFF_INVISIBILITY) ||
  3480.                         pAttacker->IsAffectFlag(AFF_REVIVE_INVISIBLE))
  3481.                         continue;
  3482.  
  3483.                 float fDist = DISTANCE_APPROX(pAttacker->GetX() - pkChr->GetX(), pAttacker->GetY() - pkChr->GetY());
  3484.  
  3485.                 if (fDist < fMinDist)
  3486.                 {
  3487.                         pkVictim = pAttacker;
  3488.                         fMinDist = fDist;
  3489.                 }
  3490.         }
  3491.  
  3492.         return pkVictim;
  3493. }
  3494.  
  3495. void CHARACTER::SetVictim(LPCHARACTER pkVictim)
  3496. {
  3497.         if (!pkVictim)
  3498.         {
  3499.                 if (0 != (DWORD)m_kVIDVictim)
  3500.                         MonsterLog("공격 대상을 해제");
  3501.  
  3502.                 m_kVIDVictim.Reset();
  3503.                 battle_end(this);
  3504.         }
  3505.         else
  3506.         {
  3507.                 if (m_kVIDVictim != pkVictim->GetVID())
  3508.                         MonsterLog("공격 대상을 설정: %s", pkVictim->GetName());
  3509.  
  3510.                 m_kVIDVictim = pkVictim->GetVID();
  3511.                 m_dwLastVictimSetTime = get_dword_time();
  3512.         }
  3513. }
  3514.  
  3515. LPCHARACTER CHARACTER::GetVictim() const
  3516. {
  3517.         return CHARACTER_MANAGER::instance().Find(m_kVIDVictim);
  3518. }
  3519.  
  3520. LPCHARACTER CHARACTER::GetProtege() const
  3521. {
  3522.         if (m_pkChrStone)
  3523.                 return m_pkChrStone;
  3524.  
  3525.         if (m_pkParty)
  3526.                 return m_pkParty->GetLeader();
  3527.  
  3528.         return NULL;
  3529. }
  3530.  
  3531. #ifdef ENABLE_TITLE_SYSTEM
  3532. int CHARACTER::GetTitle() const
  3533. {
  3534.         return m_iPrestige;
  3535. }
  3536.  
  3537. int CHARACTER::GetRealTitle() const
  3538. {
  3539.         return m_iRealPrestige;
  3540. }
  3541.  
  3542. void CHARACTER::ShowTitle(bool bShow)
  3543. {
  3544.         if (bShow)
  3545.         {
  3546.                 if (m_iPrestige != m_iRealPrestige)
  3547.                 {
  3548.                         m_iPrestige = m_iRealPrestige;
  3549.                         UpdatePacket();
  3550.                 }
  3551.         }
  3552.         else
  3553.         {
  3554.                 if (m_iPrestige != 0)
  3555.                 {
  3556.                         m_iPrestige = 0;
  3557.                         UpdatePacket();
  3558.                 }
  3559.         }
  3560. }
  3561.  
  3562. void CHARACTER::UpdateTitle(int iAmount)
  3563. {
  3564.         bool bShow = false;
  3565.  
  3566.         if (m_iPrestige == m_iRealPrestige)
  3567.                 bShow = true;
  3568.  
  3569.         int i = m_iPrestige;
  3570.         m_iRealPrestige = MINMAX(0, m_iRealPrestige + iAmount, 19);
  3571.         if (bShow)
  3572.         {
  3573.                 m_iPrestige = m_iRealPrestige;
  3574.                 if (i != m_iPrestige)
  3575.                         UpdatePacket();
  3576.         }
  3577. }
  3578. #endif
  3579.  
  3580. int CHARACTER::GetAlignment() const
  3581. {
  3582.         return m_iAlignment;
  3583. }
  3584.  
  3585. int CHARACTER::GetRealAlignment() const
  3586. {
  3587.         return m_iRealAlignment;
  3588. }
  3589.  
  3590. void CHARACTER::ShowAlignment(bool bShow)
  3591. {
  3592.         if (bShow)
  3593.         {
  3594.                 if (m_iAlignment != m_iRealAlignment)
  3595.                 {
  3596.                         m_iAlignment = m_iRealAlignment;
  3597.                         UpdatePacket();
  3598.                 }
  3599.         }
  3600.         else
  3601.         {
  3602.                 if (m_iAlignment != 0)
  3603.                 {
  3604.                         m_iAlignment = 0;
  3605.                         UpdatePacket();
  3606.                 }
  3607.         }
  3608. }
  3609.  
  3610. void CHARACTER::UpdateAlignment(int iAmount)
  3611. {
  3612.         bool bShow = false;
  3613.  
  3614.         if (m_iAlignment == m_iRealAlignment)
  3615.                 bShow = true;
  3616.  
  3617.         int i = m_iAlignment / 10;
  3618.  
  3619. #ifdef ENABLE_ALIGN_RENEWAL
  3620.         int iOldAlignment = m_iRealAlignment;
  3621.         m_iRealAlignment = MINMAX(-300000, m_iRealAlignment + iAmount, 300000);
  3622.         OnAlignUpdate(iOldAlignment);
  3623. #else
  3624.         m_iRealAlignment = MINMAX(-200000, m_iRealAlignment + iAmount, 200000);
  3625. #endif
  3626.         if (bShow)
  3627.         {
  3628.                 m_iAlignment = m_iRealAlignment;
  3629.  
  3630.                 if (i != m_iAlignment / 10)
  3631.                         UpdatePacket();
  3632.         }
  3633. }
  3634.  
  3635. void CHARACTER::SetKillerMode(bool isOn)
  3636. {
  3637.         if ((isOn ? ADD_CHARACTER_STATE_KILLER : 0) == IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER))
  3638.                 return;
  3639.  
  3640.         if (isOn)
  3641.                 SET_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
  3642.         else
  3643.                 REMOVE_BIT(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
  3644.  
  3645.         m_iKillerModePulse = thecore_pulse();
  3646.         UpdatePacket();
  3647.         sys_log(0, "SetKillerMode Update %s[%d]", GetName(), GetPlayerID());
  3648. }
  3649.  
  3650. bool CHARACTER::IsKillerMode() const
  3651. {
  3652.         return IS_SET(m_bAddChrState, ADD_CHARACTER_STATE_KILLER);
  3653. }
  3654.  
  3655. void CHARACTER::UpdateKillerMode()
  3656. {
  3657.         if (!IsKillerMode())
  3658.                 return;
  3659.  
  3660.         if (thecore_pulse() - m_iKillerModePulse >= PASSES_PER_SEC(30))
  3661.                 SetKillerMode(false);
  3662. }
  3663.  
  3664. void CHARACTER::SetPKMode(BYTE bPKMode)
  3665. {
  3666.  
  3667. #ifdef ENABLE_PLAYER_SECURITY_SYSTEM
  3668.         if (IsActivateSecurity())
  3669.         {
  3670.                 bPKMode = PK_MODE_PROTECT;
  3671.                 return;
  3672.         }
  3673. #endif
  3674.  
  3675.         if (bPKMode >= PK_MODE_MAX_NUM)
  3676.                 return;
  3677.  
  3678.         if (m_bPKMode == bPKMode)
  3679.                 return;
  3680.  
  3681.         if (bPKMode == PK_MODE_GUILD && !GetGuild())
  3682.                 bPKMode = PK_MODE_FREE;
  3683.  
  3684.         m_bPKMode = bPKMode;
  3685.         UpdatePacket();
  3686.  
  3687.         sys_log(0, "PK_MODE: %s %d", GetName(), m_bPKMode);
  3688. }
  3689.  
  3690. BYTE CHARACTER::GetPKMode() const
  3691. {
  3692.         return m_bPKMode;
  3693. }
  3694.  
  3695. struct FuncForgetMyAttacker
  3696. {
  3697.         LPCHARACTER m_ch;
  3698.         FuncForgetMyAttacker(LPCHARACTER ch)
  3699.         {
  3700.                 m_ch = ch;
  3701.         }
  3702.         void operator()(LPENTITY ent)
  3703.         {
  3704.                 if (ent->IsType(ENTITY_CHARACTER))
  3705.                 {
  3706.                         LPCHARACTER ch = (LPCHARACTER)ent;
  3707.                         if (ch->IsPC())
  3708.                                 return;
  3709.                         if (ch->m_kVIDVictim == m_ch->GetVID())
  3710.                                 ch->SetVictim(NULL);
  3711.                 }
  3712.         }
  3713. };
  3714.  
  3715. struct FuncAggregateMonster
  3716. {
  3717.         LPCHARACTER m_ch;
  3718.         FuncAggregateMonster(LPCHARACTER ch)
  3719.         {
  3720.                 m_ch = ch;
  3721.         }
  3722.         void operator()(LPENTITY ent)
  3723.         {
  3724.                 if (ent->IsType(ENTITY_CHARACTER))
  3725.                 {
  3726.                         LPCHARACTER ch = (LPCHARACTER)ent;
  3727.                         if (ch->IsPC())
  3728.                                 return;
  3729.                         if (!ch->IsMonster())
  3730.                                 return;
  3731.                         if (ch->GetVictim())
  3732.                                 return;
  3733.  
  3734.                         if (DISTANCE_APPROX(ch->GetX() - m_ch->GetX(), ch->GetY() - m_ch->GetY()) < 5000)// accelerated.
  3735.                                 if (ch->CanBeginFight())
  3736.                                         ch->BeginFight(m_ch);
  3737.                 }
  3738.         }
  3739. };
  3740.  
  3741. struct FuncAttractRanger
  3742. {
  3743.         LPCHARACTER m_ch;
  3744.         FuncAttractRanger(LPCHARACTER ch)
  3745.         {
  3746.                 m_ch = ch;
  3747.         }
  3748.  
  3749.         void operator()(LPENTITY ent)
  3750.         {
  3751.                 if (ent->IsType(ENTITY_CHARACTER))
  3752.                 {
  3753.                         LPCHARACTER ch = (LPCHARACTER)ent;
  3754.                         if (ch->IsPC())
  3755.                                 return;
  3756.                         if (!ch->IsMonster())
  3757.                                 return;
  3758.                         if (ch->GetVictim() && ch->GetVictim() != m_ch)
  3759.                                 return;
  3760.                         if (ch->GetMobAttackRange() > 150)
  3761.                         {
  3762.                                 int iNewRange = 150;//(int)(ch->GetMobAttackRange() * 0.2);
  3763.                                 if (iNewRange < 150)
  3764.                                         iNewRange = 150;
  3765.  
  3766.                                 ch->AddAffect(AFFECT_BOW_DISTANCE, POINT_BOW_DISTANCE, iNewRange - ch->GetMobAttackRange(), AFF_NONE, 3 * 60, 0, false);
  3767.                         }
  3768.                 }
  3769.         }
  3770. };
  3771.  
  3772. struct FuncPullMonster
  3773. {
  3774.         LPCHARACTER m_ch;
  3775.         int m_iLength;
  3776.         FuncPullMonster(LPCHARACTER ch, int iLength = 300)
  3777.         {
  3778.                 m_ch = ch;
  3779.                 m_iLength = iLength;
  3780.         }
  3781.  
  3782.         void operator()(LPENTITY ent)
  3783.         {
  3784.                 if (ent->IsType(ENTITY_CHARACTER))
  3785.                 {
  3786.                         LPCHARACTER ch = (LPCHARACTER)ent;
  3787.                         if (ch->IsPC())
  3788.                                 return;
  3789.                         if (!ch->IsMonster())
  3790.                                 return;
  3791.                         //if (ch->GetVictim() && ch->GetVictim() != m_ch)
  3792.                         //return;
  3793.                         float fDist = DISTANCE_APPROX(m_ch->GetX() - ch->GetX(), m_ch->GetY() - ch->GetY());
  3794.                         if (fDist > 3000 || fDist < 100)
  3795.                                 return;
  3796.  
  3797.                         float fNewDist = fDist - m_iLength;
  3798.                         if (fNewDist < 100)
  3799.                                 fNewDist = 100;
  3800.  
  3801.                         float degree = GetDegreeFromPositionXY(ch->GetX(), ch->GetY(), m_ch->GetX(), m_ch->GetY());
  3802.                         float fx;
  3803.                         float fy;
  3804.  
  3805.                         GetDeltaByDegree(degree, fDist - fNewDist, &fx, &fy);
  3806.                         long tx = (long)(ch->GetX() + fx);
  3807.                         long ty = (long)(ch->GetY() + fy);
  3808.  
  3809.                         ch->Sync(tx, ty);
  3810.                         ch->Goto(tx, ty);
  3811.                         ch->CalculateMoveDuration();
  3812.  
  3813.                         ch->SyncPacket();
  3814.                 }
  3815.         }
  3816. };
  3817.  
  3818. void CHARACTER::ForgetMyAttacker()
  3819. {
  3820.         LPSECTREE pSec = GetSectree();
  3821.         if (pSec)
  3822.         {
  3823.                 FuncForgetMyAttacker f(this);
  3824.                 pSec->ForEachAround(f);
  3825.         }
  3826.         ReviveInvisible(5);
  3827. }
  3828.  
  3829. void CHARACTER::AggregateMonster()
  3830. {
  3831.         LPSECTREE pSec = GetSectree();
  3832.         if (pSec)
  3833.         {
  3834.                 FuncAggregateMonster f(this);
  3835.                 pSec->ForEachAround(f);
  3836. #ifdef ENABLE_AGGREGATE_MONSTER_EFFECT
  3837.                 EffectPacket(SE_AGGREGATE_MONSTER_EFFECT);
  3838. #endif
  3839.         }
  3840. }
  3841.  
  3842. void CHARACTER::AttractRanger()
  3843. {
  3844.         LPSECTREE pSec = GetSectree();
  3845.         if (pSec)
  3846.         {
  3847.                 FuncAttractRanger f(this);
  3848.                 pSec->ForEachAround(f);
  3849.         }
  3850. }
  3851.  
  3852. void CHARACTER::PullMonster()
  3853. {
  3854.         LPSECTREE pSec = GetSectree();
  3855.         if (pSec)
  3856.         {
  3857.                 FuncPullMonster f(this);
  3858.                 pSec->ForEachAround(f);
  3859.         }
  3860. }
  3861.  
  3862. void CHARACTER::UpdateAggrPointEx(LPCHARACTER pAttacker, EDamageType type, int dam, CHARACTER::TBattleInfo& info)
  3863. {
  3864.         switch (type)
  3865.         {
  3866.         case DAMAGE_TYPE_NORMAL_RANGE:
  3867.                 dam = (int)(dam * 1.2f);
  3868.                 break;
  3869.  
  3870.         case DAMAGE_TYPE_RANGE:
  3871.                 dam = (int)(dam * 1.5f);
  3872.                 break;
  3873.  
  3874.         case DAMAGE_TYPE_MAGIC:
  3875.                 dam = (int)(dam * 1.2f);
  3876.                 break;
  3877.  
  3878.         default:
  3879.                 break;
  3880.         }
  3881.  
  3882.         if (pAttacker == GetVictim())
  3883.                 dam = (int)(dam * 1.2f);
  3884.  
  3885.         info.iAggro += dam;
  3886.  
  3887.         if (info.iAggro < 0)
  3888.                 info.iAggro = 0;
  3889.  
  3890.         //sys_log(0, "UpdateAggrPointEx for %s by %s dam %d total %d", GetName(), pAttacker->GetName(), dam, total);
  3891.         if (GetParty() && dam > 0 && type != DAMAGE_TYPE_SPECIAL)
  3892.         {
  3893.                 LPPARTY pParty = GetParty();
  3894.  
  3895.                 int iPartyAggroDist = dam;
  3896.  
  3897.                 if (pParty->GetLeaderPID() == GetVID())
  3898.                         iPartyAggroDist /= 2;
  3899.                 else
  3900.                         iPartyAggroDist /= 3;
  3901.  
  3902.                 pParty->SendMessage(this, PM_AGGRO_INCREASE, iPartyAggroDist, pAttacker->GetVID());
  3903.         }
  3904.  
  3905. #ifdef ENABLE_POISON_UNAGGR
  3906.         if (type != DAMAGE_TYPE_POISON)
  3907.                 ChangeVictimByAggro(info.iAggro, pAttacker);
  3908. #else
  3909.         ChangeVictimByAggro(info.iAggro, pAttacker);
  3910. #endif
  3911. }
  3912.  
  3913. void CHARACTER::UpdateAggrPoint(LPCHARACTER pAttacker, EDamageType type, int dam)
  3914. {
  3915.         if (IsDead() || IsStun())
  3916.                 return;
  3917.  
  3918.         TDamageMap::iterator it = m_map_kDamage.find(pAttacker->GetVID());
  3919.  
  3920.         if (it == m_map_kDamage.end())
  3921.         {
  3922.                 m_map_kDamage.insert(TDamageMap::value_type(pAttacker->GetVID(), TBattleInfo(0, dam)));
  3923.                 it = m_map_kDamage.find(pAttacker->GetVID());
  3924.         }
  3925.  
  3926.         UpdateAggrPointEx(pAttacker, type, dam, it->second);
  3927. }
  3928.  
  3929. void CHARACTER::ChangeVictimByAggro(int iNewAggro, LPCHARACTER pNewVictim)
  3930. {
  3931.         if (get_dword_time() - m_dwLastVictimSetTime < 3000)
  3932.                 return;
  3933.  
  3934.         if (pNewVictim == GetVictim())
  3935.         {
  3936.                 if (m_iMaxAggro < iNewAggro)
  3937.                 {
  3938.                         m_iMaxAggro = iNewAggro;
  3939.                         return;
  3940.                 }
  3941.  
  3942.                 TDamageMap::iterator it;
  3943.                 TDamageMap::iterator itFind = m_map_kDamage.end();
  3944.  
  3945.                 for (it = m_map_kDamage.begin(); it != m_map_kDamage.end(); ++it)
  3946.                 {
  3947.                         if (it->second.iAggro > iNewAggro)
  3948.                         {
  3949.                                 LPCHARACTER ch = CHARACTER_MANAGER::instance().Find(it->first);
  3950.  
  3951.                                 if (ch && !ch->IsDead() && DISTANCE_APPROX(ch->GetX() - GetX(), ch->GetY() - GetY()) < 5000)
  3952.                                 {
  3953.                                         itFind = it;
  3954.                                         iNewAggro = it->second.iAggro;
  3955.                                 }
  3956.                         }
  3957.                 }
  3958.  
  3959.                 if (itFind != m_map_kDamage.end())
  3960.                 {
  3961.                         m_iMaxAggro = iNewAggro;
  3962.                         SetVictim(CHARACTER_MANAGER::instance().Find(itFind->first));
  3963.                         m_dwStateDuration = 1;
  3964.                 }
  3965.         }
  3966.         else
  3967.         {
  3968.                 if (m_iMaxAggro < iNewAggro)
  3969.                 {
  3970.                         m_iMaxAggro = iNewAggro;
  3971.                         SetVictim(pNewVictim);
  3972.                         m_dwStateDuration = 1;
  3973.                 }
  3974.         }
  3975. }