Advertisement
Guest User

Untitled

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