Advertisement
Guest User

Untitled

a guest
Nov 10th, 2019
166
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 97.53 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include <sstream>
  3.  
  4. #include "utils.h"
  5. #include "config.h"
  6. #include "vector.h"
  7. #include "char.h"
  8. #include "char_manager.h"
  9. #include "battle.h"
  10. #include "desc.h"
  11. #include "desc_manager.h"
  12. #include "packet.h"
  13. #include "affect.h"
  14. #include "item.h"
  15. #include "sectree_manager.h"
  16. #include "mob_manager.h"
  17. #include "start_position.h"
  18. #include "party.h"
  19. #include "buffer_manager.h"
  20. #include "guild.h"
  21. #include "log.h"
  22. #include "unique_item.h"
  23. #include "questmanager.h"
  24.  
  25. extern int test_server;
  26.  
  27. static const DWORD s_adwSubSkillVnums[] =
  28. {
  29.     SKILL_LEADERSHIP,
  30.     SKILL_COMBO,
  31.     SKILL_MINING,
  32.     SKILL_LANGUAGE1,
  33.     SKILL_LANGUAGE2,
  34.     SKILL_LANGUAGE3,
  35.     SKILL_POLYMORPH,
  36.     SKILL_HORSE,
  37.     SKILL_HORSE_SUMMON,
  38.     SKILL_HORSE_WILDATTACK,
  39.     SKILL_HORSE_CHARGE,
  40.     SKILL_HORSE_ESCAPE,
  41.     SKILL_HORSE_WILDATTACK_RANGE,
  42.     SKILL_ADD_HP,
  43.     SKILL_RESIST_PENETRATE
  44. };
  45.  
  46. time_t CHARACTER::GetSkillNextReadTime(DWORD dwVnum) const
  47. {
  48.     if (dwVnum >= SKILL_MAX_NUM)
  49.     {
  50.         sys_err("vnum overflow (vnum: %u)", dwVnum);
  51.         return 0;
  52.     }
  53.  
  54.     return m_pSkillLevels ? m_pSkillLevels[dwVnum].tNextRead : 0;
  55. }
  56.  
  57. void CHARACTER::SetSkillNextReadTime(DWORD dwVnum, time_t time)
  58. {
  59.     if (m_pSkillLevels && dwVnum < SKILL_MAX_NUM)
  60.         m_pSkillLevels[dwVnum].tNextRead = time;
  61. }
  62.  
  63. bool TSkillUseInfo::HitOnce(DWORD dwVnum)
  64. {
  65.     // ¾²Áöµµ¾Ê¾ÒÀ¸¸é ¶§¸®Áöµµ ¸øÇÑ´Ù.
  66.     if (!bUsed)
  67.         return false;
  68.  
  69.     sys_log(1, "__HitOnce NextUse %u current %u count %d scount %d", dwNextSkillUsableTime, get_dword_time(), iHitCount, iSplashCount);
  70.  
  71.     if (dwNextSkillUsableTime && dwNextSkillUsableTime<get_dword_time() && dwVnum != SKILL_MUYEONG && dwVnum != SKILL_HORSE_WILDATTACK)
  72.     {
  73.         sys_log(1, "__HitOnce can't hit");
  74.  
  75.         return false;
  76.     }
  77.  
  78.     if (iHitCount == -1)
  79.     {
  80.         sys_log(1, "__HitOnce OK %d %d %d", dwNextSkillUsableTime, get_dword_time(), iHitCount);
  81.         return true;
  82.     }
  83.  
  84.     if (iHitCount)
  85.     {
  86.         sys_log(1, "__HitOnce OK %d %d %d", dwNextSkillUsableTime, get_dword_time(), iHitCount);
  87.         iHitCount--;
  88.         return true;
  89.     }
  90.     return false;
  91. }
  92.  
  93.  
  94.  
  95. bool TSkillUseInfo::UseSkill(bool isGrandMaster, DWORD vid, DWORD dwCooltime, int splashcount, int hitcount, int range)
  96. {
  97.     this->isGrandMaster = isGrandMaster;
  98.     DWORD dwCur = get_dword_time();
  99.  
  100.     // ¾ÆÁ÷ ÄðŸÀÓÀÌ ³¡³ªÁö ¾Ê¾Ò´Ù.
  101.     if (bUsed && dwNextSkillUsableTime > dwCur)
  102.     {
  103.         sys_log(0, "cooltime is not over delta %u", dwNextSkillUsableTime - dwCur);
  104.         iHitCount = 0;
  105.         return false;
  106.     }
  107.  
  108.     bUsed = true;
  109.  
  110.     if (dwCooltime)
  111.         dwNextSkillUsableTime = dwCur + dwCooltime;
  112.     else
  113.         dwNextSkillUsableTime = 0;
  114.  
  115.     iRange = range;
  116.     iMaxHitCount = iHitCount = hitcount;
  117.  
  118.     if (test_server)
  119.         sys_log(0, "UseSkill NextUse %u  current %u cooltime %d hitcount %d/%d", dwNextSkillUsableTime, dwCur, dwCooltime, iHitCount, iMaxHitCount);
  120.  
  121.     dwVID = vid;
  122.     iSplashCount = splashcount;
  123.     return true;
  124. }
  125.  
  126. int CHARACTER::GetChainLightningMaxCount() const
  127. {
  128.     return aiChainLightningCountBySkillLevel[MIN(SKILL_MAX_LEVEL, GetSkillLevel(SKILL_CHAIN))];
  129. }
  130.  
  131. void CHARACTER::SetAffectedEunhyung()
  132. {
  133.     m_dwAffectedEunhyungLevel = GetSkillPower(SKILL_EUNHYUNG);
  134. }
  135.  
  136. void CHARACTER::SetSkillGroup(BYTE bSkillGroup)
  137. {
  138.     if (bSkillGroup > 2)
  139.         return;
  140.  
  141.     if (GetLevel() < 5)
  142.         return;
  143.  
  144.     m_points.skill_group = bSkillGroup;
  145.  
  146.     TPacketGCChangeSkillGroup p;
  147.     p.header = HEADER_GC_SKILL_GROUP;
  148.     p.skill_group = m_points.skill_group;
  149.  
  150.     GetDesc()->Packet(&p, sizeof(TPacketGCChangeSkillGroup));
  151. }
  152.  
  153. int CHARACTER::ComputeCooltime(int time)
  154. {
  155.     return CalculateDuration(GetPoint(POINT_CASTING_SPEED), time);
  156. }
  157.  
  158. void CHARACTER::SkillLevelPacket()
  159. {
  160.     if (!GetDesc())
  161.         return;
  162.  
  163.     TPacketGCSkillLevel pack;
  164.  
  165.     pack.bHeader = HEADER_GC_SKILL_LEVEL;
  166.     thecore_memcpy(&pack.skills, m_pSkillLevels, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  167.     GetDesc()->Packet(&pack, sizeof(TPacketGCSkillLevel));
  168. }
  169.  
  170. void CHARACTER::SetSkillLevel(DWORD dwVnum, BYTE bLev)
  171. {
  172.     if (NULL == m_pSkillLevels)
  173.         return;
  174.  
  175.     if (dwVnum >= SKILL_MAX_NUM)
  176.     {
  177.         sys_err("vnum overflow (vnum %u)", dwVnum);
  178.         return;
  179.     }
  180.  
  181.     m_pSkillLevels[dwVnum].bLevel = MIN(40, bLev);
  182.  
  183.     if (bLev >= 40)
  184.         m_pSkillLevels[dwVnum].bMasterType = SKILL_PERFECT_MASTER;
  185.     else if (bLev >= 30)
  186.         m_pSkillLevels[dwVnum].bMasterType = SKILL_GRAND_MASTER;
  187.     else if (bLev >= 20)
  188.         m_pSkillLevels[dwVnum].bMasterType = SKILL_MASTER;
  189.     else
  190.         m_pSkillLevels[dwVnum].bMasterType = SKILL_NORMAL;
  191. }
  192.  
  193. bool CHARACTER::IsLearnableSkill(DWORD dwSkillVnum) const
  194. {
  195.     const CSkillProto * pkSkill = CSkillManager::instance().Get(dwSkillVnum);
  196.  
  197.     if (!pkSkill)
  198.         return false;
  199.  
  200.     if (GetSkillLevel(dwSkillVnum) >= SKILL_MAX_LEVEL)
  201.         return false;
  202.  
  203.     if (pkSkill->dwType == 0)
  204.     {
  205.         if (GetSkillLevel(dwSkillVnum) >= pkSkill->bMaxLevel)
  206.             return false;
  207.  
  208.         return true;
  209.     }
  210.  
  211.     if (pkSkill->dwType == 5)
  212.     {
  213.         if (dwSkillVnum == SKILL_HORSE_WILDATTACK_RANGE && GetJob() != JOB_ASSASSIN)
  214.             return false;
  215.  
  216.         return true;
  217.     }
  218.  
  219.     if (GetSkillGroup() == 0)
  220.         return false;
  221.  
  222.     if (pkSkill->dwType - 1 == GetJob())
  223.         return true;
  224.  
  225.     if (6 == pkSkill->dwType)
  226.     {
  227.         if (SKILL_7_A_ANTI_TANHWAN <= dwSkillVnum && dwSkillVnum <= SKILL_7_D_ANTI_YONGBI)
  228.         {
  229.             for (int i=0 ; i < 4 ; i++)
  230.             {
  231.                 if (unsigned(SKILL_7_A_ANTI_TANHWAN + i) != dwSkillVnum)
  232.                 {
  233.                     if (0 != GetSkillLevel(SKILL_7_A_ANTI_TANHWAN + i))
  234.                     {
  235.                         return false;
  236.                     }
  237.                 }
  238.             }
  239.  
  240.             return true;
  241.         }
  242.  
  243.         if (SKILL_8_A_ANTI_GIGONGCHAM <= dwSkillVnum && dwSkillVnum <= SKILL_8_D_ANTI_BYEURAK)
  244.         {
  245.             for (int i=0 ; i < 4 ; i++)
  246.             {
  247.                 if (unsigned(SKILL_8_A_ANTI_GIGONGCHAM + i) != dwSkillVnum)
  248.                 {
  249.                     if (0 != GetSkillLevel(SKILL_8_A_ANTI_GIGONGCHAM + i))
  250.                         return false;
  251.                 }
  252.             }
  253.            
  254.             return true;
  255.         }
  256.     }
  257.  
  258.     return false;
  259. }
  260.  
  261. // ADD_GRANDMASTER_SKILL
  262. bool CHARACTER::LearnGrandMasterSkill(DWORD dwSkillVnum)
  263. {
  264.     CSkillProto * pkSk = CSkillManager::instance().Get(dwSkillVnum);
  265.  
  266.     if (!pkSk)
  267.         return false;
  268.  
  269.     if (!IsLearnableSkill(dwSkillVnum))
  270.     {
  271.         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"¼ö·ÃÇÒ ¼ö ¾ø´Â ½ºÅ³ÀÔ´Ï´Ù."));
  272.         return false;
  273.     }
  274.  
  275.     sys_log(0, "learn grand master skill[%d] cur %d, next %d", dwSkillVnum, get_global_time(), GetSkillNextReadTime(dwSkillVnum));
  276.  
  277.     /*
  278.        if (get_global_time() < GetSkillNextReadTime(dwSkillVnum))
  279.        {
  280.        if (!(test_server && quest::CQuestManager::instance().GetEventFlag("no_read_delay")))
  281.        {
  282.        if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
  283.        {
  284.     // Á־ȼú¼­ »ç¿ëÁß¿¡´Â ½Ã°£ Á¦ÇÑ ¹«½Ã
  285.     RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
  286.     ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Á־ȼú¼­¸¦ ÅëÇØ ÁÖÈ­ÀÔ¸¶¿¡¼­ ºüÁ®³ª¿Ô½À´Ï´Ù."));
  287.     }
  288.     else        
  289.     {
  290.     SkillLearnWaitMoreTimeMessage(GetSkillNextReadTime(dwSkillVnum) - get_global_time());
  291.     return false;
  292.     }
  293.     }
  294.     }
  295.      */
  296.  
  297.     // bTypeÀÌ 0À̸é óÀ½ºÎÅÍ Ã¥À¸·Î ¼ö·Ã °¡´É
  298.     if (pkSk->dwType == 0)
  299.     {
  300.         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"±×·£µå ¸¶½ºÅÍ ¼ö·ÃÀ» ÇÒ ¼ö ¾ø´Â ½ºÅ³ÀÔ´Ï´Ù."));
  301.         return false;
  302.     }
  303.  
  304.     if (GetSkillMasterType(dwSkillVnum) != SKILL_GRAND_MASTER)
  305.     {
  306.         if (GetSkillMasterType(dwSkillVnum) > SKILL_GRAND_MASTER)
  307.             ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"ÆÛÆåÆ® ¸¶½ºÅÍµÈ ½ºÅ³ÀÔ´Ï´Ù. ´õ ÀÌ»ó ¼ö·Ã ÇÒ ¼ö ¾ø½À´Ï´Ù."));
  308.         else
  309.             ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"ÀÌ ½ºÅ³Àº ¾ÆÁ÷ ±×·£µå ¸¶½ºÅÍ ¼ö·ÃÀ» ÇÒ °æÁö¿¡ À̸£Áö ¾Ê¾Ò½À´Ï´Ù."));
  310.         return false;
  311.     }
  312.  
  313.     std::string strTrainSkill;
  314.     {
  315.         std::ostringstream os;
  316.         os << "training_grandmaster_skill.skill" << dwSkillVnum;
  317.         strTrainSkill = os.str();
  318.     }
  319.  
  320.     // ¿©±â¼­ È®·üÀ» °è»êÇÕ´Ï´Ù.
  321.     BYTE bLastLevel = GetSkillLevel(dwSkillVnum);
  322.  
  323.     int idx = MIN(9, GetSkillLevel(dwSkillVnum) - 30);
  324.  
  325.     sys_log(0, "LearnGrandMasterSkill %s table idx %d value %d", GetName(), idx, aiGrandMasterSkillBookCountForLevelUp[idx]);
  326.  
  327.     int iTotalReadCount = GetQuestFlag(strTrainSkill) + 1;
  328.     SetQuestFlag(strTrainSkill, iTotalReadCount);
  329.  
  330.     int iMinReadCount = aiGrandMasterSkillBookMinCount[idx];
  331.     int iMaxReadCount = aiGrandMasterSkillBookMaxCount[idx];
  332.  
  333.     int iBookCount = aiGrandMasterSkillBookCountForLevelUp[idx];
  334.  
  335.     if ( LC_IsYMIR() == true || LC_IsKorea() == true )
  336.     {
  337.         const int aiGrandMasterSkillBookCountForLevelUp_euckr[10] =
  338.         {
  339.             3, 3, 4, 5, 6, 7, 8, 9, 10, 15,
  340.         };
  341.  
  342.         const int aiGrandMasterSkillBookMinCount_euckr[10] =
  343.         {
  344.             1, 1, 1, 2, 2, 2, 3, 3, 4, 5
  345.         };
  346.  
  347.         const int aiGrandMasterSkillBookMaxCount_euckr[10] =
  348.         {
  349.             5, 7, 9, 11, 13, 15, 18, 23, 25, 30
  350.         };
  351.  
  352.         iMinReadCount = aiGrandMasterSkillBookMinCount_euckr[idx];
  353.         iMaxReadCount = aiGrandMasterSkillBookMaxCount_euckr[idx];
  354.         iBookCount = aiGrandMasterSkillBookCountForLevelUp_euckr[idx];
  355.     }
  356.  
  357.     if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
  358.     {
  359.         if (iBookCount&1)
  360.             iBookCount = iBookCount / 2 + 1;
  361.         else
  362.             iBookCount = iBookCount / 2;
  363.  
  364.         RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
  365.     }
  366.  
  367.     int n = number(1, iBookCount);
  368.     sys_log(0, "Number(%d)", n);
  369.  
  370.     DWORD nextTime = get_global_time() + number(28800, 43200);
  371.  
  372.     sys_log(0, "GrandMaster SkillBookCount min %d cur %d max %d (next_time=%d)", iMinReadCount, iTotalReadCount, iMaxReadCount, nextTime);
  373.  
  374.     bool bSuccess = n == 2;
  375.  
  376.     if (iTotalReadCount < iMinReadCount)
  377.         bSuccess = false;
  378.     if (iTotalReadCount > iMaxReadCount)
  379.         bSuccess = true;
  380.  
  381.     if (bSuccess)
  382.     {
  383.         SkillLevelUp(dwSkillVnum, SKILL_UP_BY_QUEST);
  384.     }
  385.  
  386.     SetSkillNextReadTime(dwSkillVnum, nextTime);
  387.  
  388.     if (bLastLevel == GetSkillLevel(dwSkillVnum))
  389.     {
  390.         ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("Å©À¹, ±â°¡ ¿ª·ùÇÏ°í ÀÖ¾î! ÀÌ°Å ¼³¸¶ ÁÖÈ­ÀÔ¸¶Àΰ¡!? Á¨Àå!"));
  391.         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"¼ö·ÃÀÌ ½ÇÆзΠ³¡³µ½À´Ï´Ù. ´Ù½Ã µµÀüÇØÁֽñ⠹ٶø´Ï´Ù."));
  392.         LogManager::instance().CharLog(this, dwSkillVnum, "GM_READ_FAIL", "");
  393.         return false;
  394.     }
  395.  
  396.     ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("¸ö¿¡¼­ ¹º°¡ ÈûÀÌ ÅÍÁ® ³ª¿À´Â ±âºÐÀ̾ß!"));
  397.     ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("¶ß°Å¿î ¹«¾ùÀÌ °è¼Ó ¿ë¼ÚÀ½Ä¡°í ÀÖ¾î! ÀÌ°Ç, ÀÌ°ÍÀº!"));
  398.     ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"´õ ³ôÀº °æÁöÀÇ ¼ö·ÃÀ» ¼º°øÀûÀ¸·Î ³¡³»¼Ì½À´Ï´Ù."));
  399.     LogManager::instance().CharLog(this, dwSkillVnum, "GM_READ_SUCCESS", "");
  400.     return true;
  401. }
  402. // END_OF_ADD_GRANDMASTER_SKILL
  403.  
  404. static bool FN_should_check_exp(LPCHARACTER ch)
  405. {
  406.     if (LC_IsCanada())
  407.         return ch->GetLevel() < gPlayerMaxLevel;
  408.  
  409.     if (!LC_IsYMIR())
  410.         return true;
  411.  
  412.     return false;
  413. }
  414.  
  415.  
  416. bool CHARACTER::LearnSkillByBook(DWORD dwSkillVnum, BYTE bProb)
  417. {
  418.     const CSkillProto* pkSk = CSkillManager::instance().Get(dwSkillVnum);
  419.  
  420.     if (!pkSk)
  421.         return false;
  422.  
  423.     if (!IsLearnableSkill(dwSkillVnum))
  424.     {
  425.         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"¼ö·ÃÇÒ ¼ö ¾ø´Â ½ºÅ³ÀÔ´Ï´Ù."));
  426.         return false;
  427.     }
  428.  
  429.     DWORD need_exp = 0;
  430.  
  431.     if (FN_should_check_exp(this))
  432.     {
  433.         need_exp = 0;
  434.  
  435.         if ( GetExp() < need_exp )
  436.         {
  437.             ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"°æÇèÄ¡°¡ ºÎÁ·ÇÏ¿© Ã¥À» ÀÐÀ» ¼ö ¾ø½À´Ï´Ù."));
  438.             return false;
  439.         }
  440.     }
  441.  
  442.     // bTypeÀÌ 0À̸é óÀ½ºÎÅÍ Ã¥À¸·Î ¼ö·Ã °¡´É
  443.     if (pkSk->dwType != 0)
  444.     {
  445.         if (GetSkillMasterType(dwSkillVnum) != SKILL_MASTER)
  446.         {
  447.             if (GetSkillMasterType(dwSkillVnum) > SKILL_MASTER)
  448.                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"ÀÌ ½ºÅ³Àº Ã¥À¸·Î ´õÀÌ»ó ¼ö·ÃÇÒ ¼ö ¾ø½À´Ï´Ù."));
  449.             else
  450.                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"ÀÌ ½ºÅ³Àº ¾ÆÁ÷ Ã¥À¸·Î ¼ö·ÃÇÒ °æÁö¿¡ À̸£Áö ¾Ê¾Ò½À´Ï´Ù."));
  451.             return false;
  452.         }
  453.     }
  454.  
  455.     if (get_global_time() < GetSkillNextReadTime(dwSkillVnum))
  456.     {
  457.         if (!(test_server && quest::CQuestManager::instance().GetEventFlag("no_read_delay")))
  458.         {
  459.             if (FindAffect(AFFECT_SKILL_NO_BOOK_DELAY))
  460.             {
  461.                 // Á־ȼú¼­ »ç¿ëÁß¿¡´Â ½Ã°£ Á¦ÇÑ ¹«½Ã
  462.                 RemoveAffect(AFFECT_SKILL_NO_BOOK_DELAY);
  463.                 ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"Á־ȼú¼­¸¦ ÅëÇØ ÁÖÈ­ÀÔ¸¶¿¡¼­ ºüÁ®³ª¿Ô½À´Ï´Ù."));
  464.             }
  465.             else        
  466.             {
  467.                 SkillLearnWaitMoreTimeMessage(GetSkillNextReadTime(dwSkillVnum) - get_global_time());
  468.                 return false;
  469.             }
  470.         }
  471.     }
  472.  
  473.     // ¿©±â¼­ È®·üÀ» °è»êÇÕ´Ï´Ù.
  474.     BYTE bLastLevel = GetSkillLevel(dwSkillVnum);
  475.  
  476.     if (bProb != 0)
  477.     {
  478.         // SKILL_BOOK_BONUS
  479.         if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
  480.         {
  481.             bProb += bProb / 2;
  482.             RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
  483.         }
  484.         // END_OF_SKILL_BOOK_BONUS
  485.  
  486.         sys_log(0, "LearnSkillByBook Pct %u prob %d", dwSkillVnum, bProb);
  487.  
  488.         if (number(1, 100) <= bProb)
  489.         {
  490.             if (test_server)
  491.                 sys_log(0, "LearnSkillByBook %u SUCC", dwSkillVnum);
  492.  
  493.             SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
  494.         }
  495.         else
  496.         {
  497.             if (test_server)
  498.                 sys_log(0, "LearnSkillByBook %u FAIL", dwSkillVnum);
  499.         }
  500.     }
  501.     else
  502.     {
  503.         int idx = MIN(9, GetSkillLevel(dwSkillVnum) - 20);
  504.  
  505.         sys_log(0, "LearnSkillByBook %s table idx %d value %d", GetName(), idx, aiSkillBookCountForLevelUp[idx]);
  506.  
  507.         if (!LC_IsYMIR())
  508.         {
  509.             int need_bookcount = GetSkillLevel(dwSkillVnum) - 20;
  510.  
  511.             PointChange(POINT_EXP, -need_exp);
  512.  
  513.             quest::CQuestManager& q = quest::CQuestManager::instance();
  514.             quest::PC* pPC = q.GetPC(GetPlayerID());
  515.  
  516.             if (pPC)
  517.             {
  518.                 char flag[128+1];
  519.                 memset(flag, 0, sizeof(flag));
  520.                 snprintf(flag, sizeof(flag), "traning_master_skill.%u.read_count", dwSkillVnum);
  521.  
  522.                 int read_count = pPC->GetFlag(flag);
  523.                 int percent = 65;
  524.  
  525.                 if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
  526.                 {
  527.                     percent = 0;
  528.                     RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
  529.                 }
  530.  
  531.                 if (number(1, 100) > percent)
  532.                 {
  533.                     // Ã¥Àб⿡ ¼º°ø
  534.                     if (read_count >= need_bookcount)
  535.                     {
  536.                         SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
  537.                         pPC->SetFlag(flag, 0);
  538.  
  539.                         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"Ã¥À¸·Î ´õ ³ôÀº °æÁöÀÇ ¼ö·ÃÀ» ¼º°øÀûÀ¸·Î ³¡³»¼Ì½À´Ï´Ù."));
  540.                         LogManager::instance().CharLog(this, dwSkillVnum, "READ_SUCCESS", "");
  541.                         return true;
  542.                     }
  543.                     else
  544.                     {
  545.                         pPC->SetFlag(flag, read_count + 1);
  546.  
  547.                         switch (number(1, 3))
  548.                         {
  549.                             case 1:
  550.                                 ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("¾î´ÀÁ¤µµ ÀÌ ±â¼ú¿¡ ´ëÇØ ÀÌÇØ°¡ µÇ¾úÁö¸¸ Á¶±Ý ºÎÁ·Çѵí Çѵ¥.."));
  551.                                 break;
  552.                                            
  553.                             case 2:
  554.                                 ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("µåµð¾î ³¡ÀÌ º¸ÀÌ´Â °Ç°¡...  ÀÌ ±â¼úÀº ÀÌÇØÇϱⰡ ³Ê¹« Èûµé¾î.."));
  555.                                 break;
  556.  
  557.                             case 3:
  558.                             default:
  559.                                 ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("¿­½ÉÈ÷ ÇÏ´Â ¹è¿òÀ» °¡Áö´Â °Í¸¸ÀÌ ±â¼úÀ» ¹è¿ï¼ö ÀÖ´Â À¯ÀÏÇÑ ±æÀÌ´Ù.."));
  560.                                 break;
  561.                         }
  562.  
  563.                         ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d ±ÇÀ» ´õ Àоî¾ß ¼ö·ÃÀ» ¿Ï·á ÇÒ ¼ö ÀÖ½À´Ï´Ù."), need_bookcount - read_count);
  564.                         return true;
  565.                     }
  566.                 }
  567.             }
  568.             else
  569.             {
  570.                 // »ç¿ëÀÚÀÇ Äù½ºÆ® Á¤º¸ ·Îµå ½ÇÆÐ
  571.             }
  572.         }
  573.         // INTERNATIONAL_VERSION
  574.         else
  575.         {
  576.             int iBookCount = 99;
  577.  
  578.             if (LC_IsYMIR() == true)
  579.             {
  580.                 const int aiSkillBookCountForLevelUp_euckr[10] =
  581.                 {
  582.                     2, 2, 3, 3, 3, 3, 3, 3, 4, 5
  583.                 };
  584.  
  585.                 iBookCount = aiSkillBookCountForLevelUp_euckr[idx];
  586.             }
  587.             else
  588.                 iBookCount = aiSkillBookCountForLevelUp[idx];
  589.  
  590.             if (FindAffect(AFFECT_SKILL_BOOK_BONUS))
  591.             {
  592.                 if (iBookCount & 1) // iBookCount % 2
  593.                     iBookCount = iBookCount / 2 + 1;
  594.                 else
  595.                     iBookCount = iBookCount / 2;
  596.  
  597.                 RemoveAffect(AFFECT_SKILL_BOOK_BONUS);
  598.             }
  599.  
  600.             if (number(1, iBookCount) == 2)
  601.                 SkillLevelUp(dwSkillVnum, SKILL_UP_BY_BOOK);
  602.         }
  603.         // END_OF_INTERNATIONAL_VERSION
  604.     }
  605.  
  606.     if (bLastLevel != GetSkillLevel(dwSkillVnum))
  607.     {
  608.         ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("¸ö¿¡¼­ ¹º°¡ ÈûÀÌ ÅÍÁ® ³ª¿À´Â ±âºÐÀ̾ß!"));
  609.         ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("¶ß°Å¿î ¹«¾ùÀÌ °è¼Ó ¿ë¼ÚÀ½Ä¡°í ÀÖ¾î! ÀÌ°Ç, ÀÌ°ÍÀº!"));
  610.         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"Ã¥À¸·Î ´õ ³ôÀº °æÁöÀÇ ¼ö·ÃÀ» ¼º°øÀûÀ¸·Î ³¡³»¼Ì½À´Ï´Ù."));
  611.         LogManager::instance().CharLog(this, dwSkillVnum, "READ_SUCCESS", "");
  612.     }
  613.     else
  614.     {
  615.         ChatPacket(CHAT_TYPE_TALKING, LC_TEXT("Å©À¹, ±â°¡ ¿ª·ùÇÏ°í ÀÖ¾î! ÀÌ°Å ¼³¸¶ ÁÖÈ­ÀÔ¸¶Àΰ¡!? Á¨Àå!"));
  616.         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"¼ö·ÃÀÌ ½ÇÆзΠ³¡³µ½À´Ï´Ù. ´Ù½Ã µµÀüÇØÁֽñ⠹ٶø´Ï´Ù."));
  617.         LogManager::instance().CharLog(this, dwSkillVnum, "READ_FAIL", "");
  618.     }
  619.  
  620.     return true;
  621. }
  622.  
  623. bool CHARACTER::SkillLevelDown(DWORD dwVnum)
  624. {
  625.     if (NULL == m_pSkillLevels)
  626.         return false;
  627.  
  628.     if (g_bSkillDisable)
  629.         return false;
  630.  
  631.     if (IsPolymorphed())
  632.         return false;
  633.  
  634.     CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
  635.  
  636.     if (!pkSk)
  637.     {
  638.         sys_err("There is no such skill by number %u", dwVnum);
  639.         return false;
  640.     }
  641.  
  642.     if (!IsLearnableSkill(dwVnum))
  643.         return false;
  644.  
  645.     if (GetSkillMasterType(pkSk->dwVnum) != SKILL_NORMAL)
  646.         return false;
  647.  
  648.     if (!GetSkillGroup())
  649.         return false;
  650.  
  651.     if (pkSk->dwVnum >= SKILL_MAX_NUM)
  652.         return false;
  653.  
  654.     if (m_pSkillLevels[pkSk->dwVnum].bLevel == 0)
  655.         return false;
  656.  
  657.     int idx = POINT_SKILL;
  658.     switch (pkSk->dwType)
  659.     {
  660.         case 0:
  661.             idx = POINT_SUB_SKILL;
  662.             break;
  663.         case 1:
  664.         case 2:
  665.         case 3:
  666.         case 4:
  667.         case 6:
  668.             idx = POINT_SKILL;
  669.             break;
  670.         case 5:
  671.             idx = POINT_HORSE_SKILL;
  672.             break;
  673.         default:
  674.             sys_err("Wrong skill type %d skill vnum %d", pkSk->dwType, pkSk->dwVnum);
  675.             return false;
  676.  
  677.     }
  678.  
  679.     PointChange(idx, +1);
  680.     SetSkillLevel(pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bLevel - 1);
  681.  
  682.     sys_log(0, "SkillDown: %s %u %u %u type %u", GetName(), pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bMasterType, m_pSkillLevels[pkSk->dwVnum].bLevel, pkSk->dwType);
  683.     Save();
  684.  
  685.     ComputePoints();
  686.     SkillLevelPacket();
  687.     return true;
  688. }
  689.  
  690. void CHARACTER::SkillLevelUp(DWORD dwVnum, BYTE bMethod)
  691. {
  692.     if (NULL == m_pSkillLevels)
  693.         return;
  694.  
  695.     if (g_bSkillDisable)
  696.         return;
  697.  
  698.     if (IsPolymorphed())
  699.     {
  700.         ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"µÐ°© Áß¿¡´Â ´É·ÂÀ» ¿Ã¸± ¼ö ¾ø½À´Ï´Ù."));
  701.         return;
  702.     }
  703.  
  704.     if (SKILL_7_A_ANTI_TANHWAN <= dwVnum && dwVnum <= SKILL_8_D_ANTI_BYEURAK)
  705.     {
  706.         if (0 == GetSkillLevel(dwVnum))
  707.             return;
  708.     }
  709.  
  710.     const CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum);
  711.  
  712.     if (!pkSk)
  713.     {
  714.         sys_err("There is no such skill by number (vnum %u)", dwVnum);
  715.         return;
  716.     }
  717.  
  718.     if (pkSk->dwVnum >= SKILL_MAX_NUM)
  719.     {
  720.         sys_err("Skill Vnum overflow (vnum %u)", dwVnum);
  721.         return;
  722.     }
  723.  
  724.     if (!IsLearnableSkill(dwVnum))
  725.         return;
  726.  
  727.     // ±×·£µå ¸¶½ºÅÍ´Â Äù½ºÆ®·Î¸¸ ¼öÇà°¡´É
  728.     if (pkSk->dwType != 0)
  729.     {
  730.         switch (GetSkillMasterType(pkSk->dwVnum))
  731.         {
  732.             case SKILL_GRAND_MASTER:
  733.                 if (bMethod != SKILL_UP_BY_QUEST)
  734.                     return;
  735.                 break;
  736.  
  737.             case SKILL_PERFECT_MASTER:
  738.                 return;
  739.         }
  740.     }
  741.  
  742.     if (bMethod == SKILL_UP_BY_POINT)
  743.     {
  744.         // ¸¶½ºÅÍ°¡ ¾Æ´Ñ »óÅ¿¡¼­¸¸ ¼ö·Ã°¡´É
  745.         if (GetSkillMasterType(pkSk->dwVnum) != SKILL_NORMAL)
  746.             return;
  747.  
  748.         if (IS_SET(pkSk->dwFlag, SKILL_FLAG_DISABLE_BY_POINT_UP))
  749.             return;
  750.     }
  751.     else if (bMethod == SKILL_UP_BY_BOOK)
  752.     {
  753.         if (pkSk->dwType != 0) // Á÷¾÷¿¡ ¼ÓÇÏÁö ¾Ê¾Ò°Å³ª Æ÷ÀÎÆ®·Î ¿Ã¸±¼ö ¾ø´Â ½ºÅ³Àº óÀ½ºÎÅÍ Ã¥À¸·Î ¹è¿ï ¼ö ÀÖ´Ù.
  754.             if (GetSkillMasterType(pkSk->dwVnum) != SKILL_MASTER)
  755.                 return;
  756.     }
  757.  
  758.     if (GetLevel() < pkSk->bLevelLimit)
  759.         return;
  760.  
  761.     if (pkSk->preSkillVnum)
  762.         if (GetSkillMasterType(pkSk->preSkillVnum) == SKILL_NORMAL &&
  763.             GetSkillLevel(pkSk->preSkillVnum) < pkSk->preSkillLevel)
  764.             return;
  765.  
  766.     if (!GetSkillGroup())
  767.         return;
  768.  
  769.     if (bMethod == SKILL_UP_BY_POINT)
  770.     {
  771.         int idx;
  772.  
  773.         switch (pkSk->dwType)
  774.         {
  775.             case 0:
  776.                 idx = POINT_SUB_SKILL;
  777.                 break;
  778.  
  779.             case 1:
  780.             case 2:
  781.             case 3:
  782.             case 4:
  783.             case 6:
  784.                 idx = POINT_SKILL;
  785.                 break;
  786.  
  787.             case 5:
  788.                 idx = POINT_HORSE_SKILL;
  789.                 break;
  790.  
  791.             default:
  792.                 sys_err("Wrong skill type %d skill vnum %d", pkSk->dwType, pkSk->dwVnum);
  793.                 return;
  794.         }
  795.  
  796.         if (GetPoint(idx) < 1)
  797.             return;
  798.  
  799.         PointChange(idx, -1);
  800.     }
  801.  
  802.     int SkillPointBefore = GetSkillLevel(pkSk->dwVnum);
  803.     SetSkillLevel(pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bLevel + 1);
  804.  
  805.     if (pkSk->dwType != 0)
  806.     {
  807.         // °©Àڱ⠱׷¹ÀÌµå ¾÷ÇÏ´Â ÄÚµù
  808.         switch (GetSkillMasterType(pkSk->dwVnum))
  809.         {
  810.             case SKILL_NORMAL:
  811.                 // ¹ø¼·Àº ½ºÅ³ ¾÷±×·¹À̵å 17~20 »çÀÌ ·£´ý ¸¶½ºÅÍ ¼ö·Ã
  812.                 if (GetSkillLevel(pkSk->dwVnum) >= 17)
  813.                 {
  814.                     if (GetQuestFlag("reset_scroll.force_to_master_skill") > 0)
  815.                     {
  816.                         SetSkillLevel(pkSk->dwVnum, 20);
  817.                         SetQuestFlag("reset_scroll.force_to_master_skill", 0);
  818.                     }
  819.                     else
  820.                     {
  821.                         SetSkillLevel(pkSk->dwVnum, 20);
  822.                     }
  823.                 }
  824.                 break;
  825.  
  826.             case SKILL_MASTER:
  827.                 if (GetSkillLevel(pkSk->dwVnum) >= 30)
  828.                 {
  829.                     if (number(1, 31 - MIN(30, GetSkillLevel(pkSk->dwVnum))) == 1)
  830.                         SetSkillLevel(pkSk->dwVnum, 30);
  831.                 }
  832.                 break;
  833.  
  834.             case SKILL_GRAND_MASTER:
  835.                 if (GetSkillLevel(pkSk->dwVnum) >= 40)
  836.                 {
  837.                     SetSkillLevel(pkSk->dwVnum, 40);
  838.                 }
  839.                 break;
  840.         }
  841.     }
  842.  
  843.     char szSkillUp[1024];
  844.  
  845.     snprintf(szSkillUp, sizeof(szSkillUp), "SkillUp: %s %u %d %d[Before:%d] type %u",
  846.             GetName(), pkSk->dwVnum, m_pSkillLevels[pkSk->dwVnum].bMasterType, m_pSkillLevels[pkSk->dwVnum].bLevel, SkillPointBefore, pkSk->dwType);
  847.  
  848.     sys_log(0, "%s", szSkillUp);
  849.  
  850.     LogManager::instance().CharLog(this, pkSk->dwVnum, "SKILLUP", szSkillUp);
  851.     Save();
  852.  
  853.     ComputePoints();
  854.     SkillLevelPacket();
  855. }
  856.  
  857. void CHARACTER::ComputeSkillPoints()
  858. {
  859.     if (g_bSkillDisable)
  860.         return;
  861. }
  862.  
  863. void CHARACTER::ResetSkill()
  864. {
  865.     if (NULL == m_pSkillLevels)
  866.         return;
  867.  
  868.     // º¸Á¶ ½ºÅ³Àº ¸®¼Â½ÃÅ°Áö ¾Ê´Â´Ù
  869.     std::vector<std::pair<DWORD, TPlayerSkill> > vec;
  870.     size_t count = sizeof(s_adwSubSkillVnums) / sizeof(s_adwSubSkillVnums[0]);
  871.  
  872.     for (size_t i = 0; i < count; ++i)
  873.     {
  874.         if (s_adwSubSkillVnums[i] >= SKILL_MAX_NUM)
  875.             continue;
  876.  
  877.         vec.push_back(std::make_pair(s_adwSubSkillVnums[i], m_pSkillLevels[s_adwSubSkillVnums[i]]));
  878.     }
  879.  
  880.     memset(m_pSkillLevels, 0, sizeof(TPlayerSkill) * SKILL_MAX_NUM);
  881.  
  882.     auto iter = vec.begin();
  883.  
  884.     while (iter != vec.end())
  885.     {
  886.         const std::pair<DWORD, TPlayerSkill>& pair = *(iter++);
  887.         m_pSkillLevels[pair.first] = pair.second;
  888.     }
  889.  
  890.     ComputePoints();
  891.     SkillLevelPacket();
  892. }
  893.  
  894. void CHARACTER::ComputePassiveSkill(DWORD dwVnum)
  895. {
  896.     if (g_bSkillDisable)
  897.         return;
  898.  
  899.     if (GetSkillLevel(dwVnum) == 0)
  900.         return;
  901.  
  902.     CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
  903.     pkSk->SetPointVar("k", GetSkillLevel(dwVnum));
  904.     int iAmount = (int) pkSk->kPointPoly.Eval();
  905.  
  906.     sys_log(2, "%s passive #%d on %d amount %d", GetName(), dwVnum, pkSk->bPointOn, iAmount);
  907.     PointChange(pkSk->bPointOn, iAmount);
  908. }
  909.  
  910. struct FFindNearVictim
  911. {
  912.     FFindNearVictim(LPCHARACTER center, LPCHARACTER attacker, const CHARACTER_SET& excepts_set = empty_set_)
  913.         : m_pkChrCenter(center),
  914.     m_pkChrNextTarget(NULL),
  915.     m_pkChrAttacker(attacker),
  916.     m_count(0),
  917.     m_excepts_set(excepts_set)
  918.     {
  919.     }
  920.  
  921.     void operator ()(LPENTITY ent)
  922.     {
  923.         if (!ent->IsType(ENTITY_CHARACTER))
  924.             return;
  925.  
  926.         LPCHARACTER pkChr = (LPCHARACTER) ent;
  927.  
  928.         if (!m_excepts_set.empty()) {
  929.             if (m_excepts_set.find(pkChr) != m_excepts_set.end())
  930.                 return;
  931.         }
  932.  
  933.         if (m_pkChrCenter == pkChr)
  934.             return;
  935.  
  936.         if (!battle_is_attackable(m_pkChrAttacker, pkChr))
  937.         {
  938.             return;
  939.         }
  940.  
  941.         if (abs(m_pkChrCenter->GetX() - pkChr->GetX()) > 1000 || abs(m_pkChrCenter->GetY() - pkChr->GetY()) > 1000)
  942.             return;
  943.  
  944.         float fDist = DISTANCE_APPROX(m_pkChrCenter->GetX() - pkChr->GetX(), m_pkChrCenter->GetY() - pkChr->GetY());
  945.  
  946.         if (fDist < 1000)
  947.         {
  948.             ++m_count;
  949.  
  950.             if ((m_count == 1) || number(1, m_count) == 1)
  951.                 m_pkChrNextTarget = pkChr;
  952.         }
  953.     }
  954.  
  955.     LPCHARACTER GetVictim()
  956.     {
  957.         return m_pkChrNextTarget;
  958.     }
  959.  
  960.     LPCHARACTER m_pkChrCenter;
  961.     LPCHARACTER m_pkChrNextTarget;
  962.     LPCHARACTER m_pkChrAttacker;
  963.     int     m_count;
  964.     const CHARACTER_SET & m_excepts_set;
  965. private:
  966.     static CHARACTER_SET empty_set_;
  967. };
  968.  
  969. CHARACTER_SET FFindNearVictim::empty_set_;
  970.  
  971. EVENTINFO(chain_lightning_event_info)
  972. {
  973.     DWORD           dwVictim;
  974.     DWORD           dwChr;
  975.  
  976.     chain_lightning_event_info()
  977.     : dwVictim(0)
  978.     , dwChr(0)
  979.     {
  980.     }
  981. };
  982.  
  983. EVENTFUNC(ChainLightningEvent)
  984. {
  985.     chain_lightning_event_info * info = dynamic_cast<chain_lightning_event_info *>( event->info );
  986.  
  987.     LPCHARACTER pkChrVictim = CHARACTER_MANAGER::instance().Find(info->dwVictim);
  988.     LPCHARACTER pkChr = CHARACTER_MANAGER::instance().Find(info->dwChr);
  989.     LPCHARACTER pkTarget = NULL;
  990.  
  991.     if (!pkChr || !pkChrVictim)
  992.     {
  993.         sys_log(1, "use chainlighting, but no character");
  994.         return 0;
  995.     }
  996.  
  997.     sys_log(1, "chainlighting event %s", pkChr->GetName());
  998.  
  999.     if (pkChrVictim->GetParty()) // ÆÄƼ ¸ÕÀú
  1000.     {
  1001.         pkTarget = pkChrVictim->GetParty()->GetNextOwnership(NULL, pkChrVictim->GetX(), pkChrVictim->GetY());
  1002.         if (pkTarget == pkChrVictim || !number(0, 2) || pkChr->GetChainLightingExcept().find(pkTarget) != pkChr->GetChainLightingExcept().end())
  1003.             pkTarget = NULL;
  1004.     }
  1005.  
  1006.     if (!pkTarget)
  1007.     {
  1008.         // 1. Find Next victim
  1009.         FFindNearVictim f(pkChrVictim, pkChr, pkChr->GetChainLightingExcept());
  1010.  
  1011.         if (pkChrVictim->GetSectree())
  1012.         {
  1013.             pkChrVictim->GetSectree()->ForEachAround(f);
  1014.             // 2. If exist, compute it again
  1015.             pkTarget = f.GetVictim();
  1016.         }
  1017.     }
  1018.  
  1019.     if (pkTarget)
  1020.     {
  1021.         pkChrVictim->CreateFly(FLY_CHAIN_LIGHTNING, pkTarget);
  1022.         pkChr->ComputeSkill(SKILL_CHAIN, pkTarget);
  1023.         pkChr->AddChainLightningExcept(pkTarget);
  1024.     }
  1025.     else
  1026.     {
  1027.         sys_log(1, "%s use chainlighting, but find victim failed near %s", pkChr->GetName(), pkChrVictim->GetName());
  1028.     }
  1029.  
  1030.     return 0;
  1031. }
  1032.  
  1033. void SetPolyVarForAttack(LPCHARACTER ch, CSkillProto * pkSk, LPITEM pkWeapon)
  1034. {
  1035.     if (ch->IsPC())
  1036.     {
  1037.         if (pkWeapon && pkWeapon->GetType() == ITEM_WEAPON)
  1038.         {
  1039.             int iWep = number(pkWeapon->GetValue(3), pkWeapon->GetValue(4));
  1040.             iWep += pkWeapon->GetValue(5);
  1041.  
  1042.             int iMtk = number(pkWeapon->GetValue(1), pkWeapon->GetValue(2));
  1043.             iMtk += pkWeapon->GetValue(5);
  1044.  
  1045.             pkSk->SetPointVar("wep", iWep);
  1046.             pkSk->SetPointVar("mtk", iMtk);
  1047.             pkSk->SetPointVar("mwep", iMtk);
  1048.         }
  1049.         else
  1050.         {
  1051.             pkSk->SetPointVar("wep", 0);
  1052.             pkSk->SetPointVar("mtk", 0);
  1053.             pkSk->SetPointVar("mwep", 0);
  1054.         }
  1055.     }
  1056.     else
  1057.     {
  1058.         int iWep = number(ch->GetMobDamageMin(), ch->GetMobDamageMax());
  1059.         pkSk->SetPointVar("wep", iWep);
  1060.         pkSk->SetPointVar("mwep", iWep);
  1061.         pkSk->SetPointVar("mtk", iWep);
  1062.     }
  1063. }
  1064.  
  1065. struct FuncSplashDamage
  1066. {
  1067.     FuncSplashDamage(int x, int y, CSkillProto * pkSk, LPCHARACTER pkChr, int iAmount, int iAG, int iMaxHit, LPITEM pkWeapon, bool bDisableCooltime, TSkillUseInfo* pInfo, BYTE bUseSkillPower)
  1068.         :
  1069.         m_x(x), m_y(y), m_pkSk(pkSk), m_pkChr(pkChr), m_iAmount(iAmount), m_iAG(iAG), m_iCount(0), m_iMaxHit(iMaxHit), m_pkWeapon(pkWeapon), m_bDisableCooltime(bDisableCooltime), m_pInfo(pInfo), m_bUseSkillPower(bUseSkillPower)
  1070.         {
  1071.         }
  1072.  
  1073.     void operator () (LPENTITY ent)
  1074.     {
  1075.         if (!ent->IsType(ENTITY_CHARACTER))
  1076.         {
  1077.             //if (m_pkSk->dwVnum == SKILL_CHAIN) sys_log(0, "CHAIN target not character %s", m_pkChr->GetName());
  1078.             return;
  1079.         }
  1080.  
  1081.         LPCHARACTER pkChrVictim = (LPCHARACTER) ent;
  1082.  
  1083.         if (DISTANCE_APPROX(m_x - pkChrVictim->GetX(), m_y - pkChrVictim->GetY()) > m_pkSk->iSplashRange)
  1084.         {
  1085.             if(test_server)
  1086.                 sys_log(0, "XXX target too far %s", m_pkChr->GetName());
  1087.             return;
  1088.         }
  1089.  
  1090.         if (!battle_is_attackable(m_pkChr, pkChrVictim))
  1091.         {
  1092.             if(test_server)
  1093.                 sys_log(0, "XXX target not attackable %s", m_pkChr->GetName());
  1094.             return;
  1095.         }
  1096.  
  1097.         if (m_pkChr->IsPC())
  1098.             // ±æµå ½ºÅ³Àº ÄðŸÀÓ Ã³¸®¸¦ ÇÏÁö ¾Ê´Â´Ù.
  1099.             if (!(m_pkSk->dwVnum >= GUILD_SKILL_START && m_pkSk->dwVnum <= GUILD_SKILL_END))
  1100.                 if (!m_bDisableCooltime && m_pInfo && !m_pInfo->HitOnce(m_pkSk->dwVnum) && m_pkSk->dwVnum != SKILL_MUYEONG)
  1101.                 {
  1102.                     if(test_server)
  1103.                         sys_log(0, "check guild skill %s", m_pkChr->GetName());
  1104.                     return;
  1105.                 }
  1106.  
  1107.         ++m_iCount;
  1108.  
  1109.         int iDam;
  1110.  
  1111.         ////////////////////////////////////////////////////////////////////////////////
  1112.         //float k = 1.0f * m_pkChr->GetSkillPower(m_pkSk->dwVnum) * m_pkSk->bMaxLevel / 100;
  1113.         //m_pkSk->kPointPoly2.SetVar("k", 1.0 * m_bUseSkillPower * m_pkSk->bMaxLevel / 100);
  1114.         m_pkSk->SetPointVar("k", 1.0 * m_bUseSkillPower * m_pkSk->bMaxLevel / 100);
  1115.         m_pkSk->SetPointVar("lv", m_pkChr->GetLevel());
  1116.         m_pkSk->SetPointVar("iq", m_pkChr->GetPoint(POINT_IQ));
  1117.         m_pkSk->SetPointVar("str", m_pkChr->GetPoint(POINT_ST));
  1118.         m_pkSk->SetPointVar("dex", m_pkChr->GetPoint(POINT_DX));
  1119.         m_pkSk->SetPointVar("con", m_pkChr->GetPoint(POINT_HT));
  1120.         m_pkSk->SetPointVar("def", m_pkChr->GetPoint(POINT_DEF_GRADE));
  1121.         m_pkSk->SetPointVar("odef", m_pkChr->GetPoint(POINT_DEF_GRADE) - m_pkChr->GetPoint(POINT_DEF_GRADE_BONUS));
  1122.         m_pkSk->SetPointVar("horse_level", m_pkChr->GetHorseLevel());
  1123.  
  1124.         //int iPenetratePct = (int)(1 + k*4);
  1125.         bool bIgnoreDefense = false;
  1126.  
  1127.         if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_PENETRATE))
  1128.         {
  1129.             int iPenetratePct = (int) m_pkSk->kPointPoly2.Eval();
  1130.  
  1131.             if (number(1, 100) <= iPenetratePct)
  1132.                 bIgnoreDefense = true;
  1133.         }
  1134.  
  1135.         bool bIgnoreTargetRating = false;
  1136.  
  1137.         if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_IGNORE_TARGET_RATING))
  1138.         {
  1139.             int iPct = (int) m_pkSk->kPointPoly2.Eval();
  1140.  
  1141.             if (number(1, 100) <= iPct)
  1142.                 bIgnoreTargetRating = true;
  1143.         }
  1144.  
  1145.         m_pkSk->SetPointVar("ar", CalcAttackRating(m_pkChr, pkChrVictim, bIgnoreTargetRating));
  1146.  
  1147.         if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_USE_MELEE_DAMAGE))
  1148.             m_pkSk->SetPointVar("atk", CalcMeleeDamage(m_pkChr, pkChrVictim, true, bIgnoreTargetRating));
  1149.         else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_USE_ARROW_DAMAGE))
  1150.         {
  1151.             LPITEM pkBow, pkArrow;
  1152.  
  1153.             if (1 == m_pkChr->GetArrowAndBow(&pkBow, &pkArrow, 1))
  1154.                 m_pkSk->SetPointVar("atk", CalcArrowDamage(m_pkChr, pkChrVictim, pkBow, pkArrow, true));
  1155.             else
  1156.                 m_pkSk->SetPointVar("atk", 0);
  1157.         }
  1158.  
  1159.         if (m_pkSk->bPointOn == POINT_MOV_SPEED)
  1160.             m_pkSk->kPointPoly.SetVar("maxv", pkChrVictim->GetLimitPoint(POINT_MOV_SPEED));
  1161.  
  1162.         m_pkSk->SetPointVar("maxhp", pkChrVictim->GetMaxHP());
  1163.         m_pkSk->SetPointVar("maxsp", pkChrVictim->GetMaxSP());
  1164.  
  1165.         m_pkSk->SetPointVar("chain", m_pkChr->GetChainLightningIndex());
  1166.         m_pkChr->IncChainLightningIndex();
  1167.  
  1168.         bool bUnderEunhyung = m_pkChr->GetAffectedEunhyung() > 0; // ÀÌ°Ç ¿Ö ¿©±â¼­ ÇÏÁö??
  1169.  
  1170.         m_pkSk->SetPointVar("ek", m_pkChr->GetAffectedEunhyung()*1./100);
  1171.         //m_pkChr->ClearAffectedEunhyung();
  1172.         SetPolyVarForAttack(m_pkChr, m_pkSk, m_pkWeapon);
  1173.  
  1174.         int iAmount = 0;
  1175.  
  1176.         if (m_pkChr->GetUsedSkillMasterType(m_pkSk->dwVnum) >= SKILL_GRAND_MASTER)
  1177.         {
  1178.             iAmount = (int) m_pkSk->kMasterBonusPoly.Eval();
  1179.         }
  1180.         else
  1181.         {
  1182.             iAmount = (int) m_pkSk->kPointPoly.Eval();
  1183.         }
  1184.  
  1185.         if (test_server && iAmount == 0 && m_pkSk->bPointOn != POINT_NONE)
  1186.         {
  1187.             m_pkChr->ChatPacket(CHAT_TYPE_INFO, "È¿°ú°¡ ¾ø½À´Ï´Ù. ½ºÅ³ °ø½ÄÀ» È®ÀÎÇϼ¼¿ä");
  1188.         }
  1189.         ////////////////////////////////////////////////////////////////////////////////
  1190.         iAmount = -iAmount;
  1191.  
  1192.         if (m_pkSk->dwVnum == SKILL_AMSEOP)
  1193.         {
  1194.             float fDelta = GetDegreeDelta(m_pkChr->GetRotation(), pkChrVictim->GetRotation());
  1195.             float adjust;
  1196.  
  1197.             if (fDelta < 35.0f)
  1198.             {
  1199.                 adjust = 1.5f;
  1200.  
  1201.                 if (bUnderEunhyung)
  1202.                     adjust += 0.5f;
  1203.  
  1204.                 if (m_pkChr->GetWear(WEAR_WEAPON) && m_pkChr->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER)
  1205.                 {
  1206.                     //if (!g_iUseLocale)
  1207.                     if ( LC_IsYMIR() )
  1208.                         adjust += 1.0f;
  1209.                     else
  1210.                         adjust += 0.5f;
  1211.                 }
  1212.             }
  1213.             else
  1214.             {
  1215.                 adjust = 1.0f;
  1216.  
  1217.                 if ( !LC_IsYMIR() )
  1218.                 {
  1219.                     if (bUnderEunhyung)
  1220.                         adjust += 0.5f;
  1221.  
  1222.                     if (m_pkChr->GetWear(WEAR_WEAPON) && m_pkChr->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER)
  1223.                         adjust += 0.5f;
  1224.                 }
  1225.             }
  1226.  
  1227.             iAmount = (int) (iAmount * adjust);
  1228.         }
  1229.         else if (m_pkSk->dwVnum == SKILL_GUNGSIN)
  1230.         {
  1231.             float adjust = 1.0;
  1232.  
  1233.             if (m_pkChr->GetWear(WEAR_WEAPON) && m_pkChr->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER)
  1234.             {
  1235.                 //if (!g_iUseLocale)
  1236.                 if ( LC_IsYMIR() )
  1237.                     adjust = 1.4f;
  1238.                 else
  1239.                     adjust = 1.35f;
  1240.             }
  1241.  
  1242.             iAmount = (int) (iAmount * adjust);
  1243.         }
  1244.         ////////////////////////////////////////////////////////////////////////////////
  1245.         //sys_log(0, "name: %s skill: %s amount %d to %s", m_pkChr->GetName(), m_pkSk->szName, iAmount, pkChrVictim->GetName());
  1246.  
  1247.         iDam = CalcBattleDamage(iAmount, m_pkChr->GetLevel(), pkChrVictim->GetLevel());
  1248.  
  1249.         if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() != (DWORD) pkChrVictim->GetVID())
  1250.         {
  1251.             // µ¥¹ÌÁö °¨¼Ò
  1252.             iDam = (int) (iDam * m_pkSk->kSplashAroundDamageAdjustPoly.Eval());
  1253.         }
  1254.  
  1255.         // TODO ½ºÅ³¿¡ µû¸¥ µ¥¹ÌÁö ŸÀÔ ±â·ÏÇؾßÇÑ´Ù.
  1256.         EDamageType dt = DAMAGE_TYPE_NONE;
  1257.  
  1258.         switch (m_pkSk->bSkillAttrType)
  1259.         {
  1260.             case SKILL_ATTR_TYPE_NORMAL:
  1261.                 break;
  1262.  
  1263.             case SKILL_ATTR_TYPE_MELEE:
  1264.                 {
  1265.                     dt = DAMAGE_TYPE_MELEE;
  1266.  
  1267.                     LPITEM pkWeapon = m_pkChr->GetWear(WEAR_WEAPON);
  1268.  
  1269.                     if (pkWeapon)
  1270.                         switch (pkWeapon->GetSubType())
  1271.                         {
  1272.                             case WEAPON_SWORD:
  1273.                                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_SWORD)) / 100;
  1274.                                 break;
  1275.  
  1276.                             case WEAPON_TWO_HANDED:
  1277.                                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_TWOHAND)) / 100;
  1278.                                 // ¾ç¼Õ°Ë Æä³ÎƼ 10%
  1279.                                 //iDam = iDam * 95 / 100;
  1280.  
  1281.                                 break;
  1282.  
  1283.                             case WEAPON_DAGGER:
  1284.                                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_DAGGER)) / 100;
  1285.                                 break;
  1286.  
  1287.                             case WEAPON_BELL:
  1288.                                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BELL)) / 100;
  1289.                                 break;
  1290.  
  1291.                             case WEAPON_FAN:
  1292.                                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BELL)) / 100;
  1293.                                 break;
  1294.                         }
  1295.  
  1296.                     if (!bIgnoreDefense)
  1297.                         iDam -= pkChrVictim->GetPoint(POINT_DEF_GRADE);
  1298.                 }
  1299.                 break;
  1300.  
  1301.             case SKILL_ATTR_TYPE_RANGE:
  1302.                 dt = DAMAGE_TYPE_RANGE;
  1303.                 // À¸¾Æ¾Æ¾Æ¾Ç
  1304.                 // ¿¹Àü¿¡ Àû¿ë¾ÈÇß´ø ¹ö±×°¡ À־ ¹æ¾î·Â °è»êÀ» ´Ù½ÃÇϸé À¯Àú°¡ ³­¸®³²
  1305.                 //iDam -= pkChrVictim->GetPoint(POINT_DEF_GRADE);
  1306.                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_BOW)) / 100;
  1307.                 break;
  1308.  
  1309.             case SKILL_ATTR_TYPE_MAGIC:
  1310.                 dt = DAMAGE_TYPE_MAGIC;
  1311.                 iDam = CalcAttBonus(m_pkChr, pkChrVictim, iDam);
  1312.                 // À¸¾Æ¾Æ¾Æ¾Ç
  1313.                 // ¿¹Àü¿¡ Àû¿ë¾ÈÇß´ø ¹ö±×°¡ À־ ¹æ¾î·Â °è»êÀ» ´Ù½ÃÇϸé À¯Àú°¡ ³­¸®³²
  1314.                 //iDam -= pkChrVictim->GetPoint(POINT_MAGIC_DEF_GRADE);
  1315.                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_MAGIC)) / 100;
  1316.                 break;
  1317.  
  1318.             default:
  1319.                 sys_err("Unknown skill attr type %u vnum %u", m_pkSk->bSkillAttrType, m_pkSk->dwVnum);
  1320.                 break;
  1321.         }
  1322.  
  1323.         //
  1324.         // 20091109 µ¶ÀÏ ½ºÅ³ ¼Ó¼º ¿äû ÀÛ¾÷
  1325.         // ±âÁ¸ ½ºÅ³ Å×ÀÌºí¿¡ SKILL_FLAG_WIND, SKILL_FLAG_ELEC, SKILL_FLAG_FIRE¸¦ °¡Áø ½ºÅ³ÀÌ
  1326.         // ÀüÇô ¾ø¾úÀ¸¹Ç·Î ¸ó½ºÅÍÀÇ RESIST_WIND, RESIST_ELEC, RESIST_FIREµµ »ç¿ëµÇÁö ¾Ê°í ÀÖ¾ú´Ù.
  1327.         //
  1328.         // PvP¿Í PvE¹ë·±½º ºÐ¸®¸¦ À§ÇØ ÀǵµÀûÀ¸·Î NPC¸¸ Àû¿ëÇϵµ·Ï ÇßÀ¸¸ç ±âÁ¸ ¹ë·±½º¿Í Â÷ÀÌÁ¡À»
  1329.         // ´À³¢Áö ¸øÇϱâ À§ÇØ mob_protoÀÇ RESIST_MAGICÀ» RESIST_WIND, RESIST_ELEC, RESIST_FIRE·Î
  1330.         // º¹»çÇÏ¿´´Ù.
  1331.         //
  1332.         if (pkChrVictim->IsNPC())
  1333.         {
  1334.             if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_WIND))
  1335.             {
  1336.                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_WIND)) / 100;
  1337.             }
  1338.  
  1339.             if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_ELEC))
  1340.             {
  1341.                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_ELEC)) / 100;
  1342.             }
  1343.  
  1344.             if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_FIRE))
  1345.             {
  1346.                 iDam = iDam * (100 - pkChrVictim->GetPoint(POINT_RESIST_FIRE)) / 100;
  1347.             }
  1348.         }
  1349.  
  1350.         if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_COMPUTE_MAGIC_DAMAGE))
  1351.             dt = DAMAGE_TYPE_MAGIC;
  1352.  
  1353.         if (pkChrVictim->CanBeginFight())
  1354.             pkChrVictim->BeginFight(m_pkChr);
  1355.  
  1356.         if (m_pkSk->dwVnum == SKILL_CHAIN)
  1357.             sys_log(0, "%s CHAIN INDEX %d DAM %d DT %d", m_pkChr->GetName(), m_pkChr->GetChainLightningIndex() - 1, iDam, dt);
  1358.  
  1359.         {
  1360.             BYTE AntiSkillID = 0;
  1361.  
  1362.             switch (m_pkSk->dwVnum)
  1363.             {
  1364.                 case SKILL_TANHWAN:     AntiSkillID = SKILL_7_A_ANTI_TANHWAN;       break;
  1365.                 case SKILL_AMSEOP:      AntiSkillID = SKILL_7_B_ANTI_AMSEOP;        break;
  1366.                 case SKILL_SWAERYUNG:   AntiSkillID = SKILL_7_C_ANTI_SWAERYUNG;     break;
  1367.                 case SKILL_YONGBI:      AntiSkillID = SKILL_7_D_ANTI_YONGBI;        break;
  1368.                 case SKILL_GIGONGCHAM:  AntiSkillID = SKILL_8_A_ANTI_GIGONGCHAM;    break;
  1369.                 case SKILL_YEONSA:      AntiSkillID = SKILL_8_B_ANTI_YEONSA;        break;
  1370.                 case SKILL_MAHWAN:      AntiSkillID = SKILL_8_C_ANTI_MAHWAN;        break;
  1371.                 case SKILL_BYEURAK:     AntiSkillID = SKILL_8_D_ANTI_BYEURAK;       break;
  1372.             }
  1373.  
  1374.             if (0 != AntiSkillID)
  1375.             {
  1376.                 BYTE AntiSkillLevel = pkChrVictim->GetSkillLevel(AntiSkillID);
  1377.  
  1378.                 if (0 != AntiSkillLevel)
  1379.                 {
  1380.                     CSkillProto* pkSk = CSkillManager::instance().Get(AntiSkillID);
  1381.                     if (!pkSk)
  1382.                     {
  1383.                         sys_err ("There is no anti skill(%d) in skill proto", AntiSkillID);
  1384.                     }
  1385.                     else
  1386.                     {
  1387.                         pkSk->SetPointVar("k", 1.0f * pkChrVictim->GetSkillPower(AntiSkillID) * pkSk->bMaxLevel / 100);
  1388.  
  1389.                         double ResistAmount = pkSk->kPointPoly.Eval();
  1390.  
  1391.                         sys_log(0, "ANTI_SKILL: Resist(%lf) Orig(%d) Reduce(%d)", ResistAmount, iDam, int(iDam * (ResistAmount/100.0)));
  1392.  
  1393.                         iDam -= iDam * (ResistAmount/100.0);
  1394.                     }
  1395.                 }
  1396.             }
  1397.         }
  1398.  
  1399.         if (!pkChrVictim->Damage(m_pkChr, iDam, dt) && !pkChrVictim->IsStun())
  1400.         {
  1401.             if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_REMOVE_GOOD_AFFECT))
  1402.             {
  1403.                 int iAmount2 = (int) m_pkSk->kPointPoly2.Eval();
  1404.                 int iDur2 = (int) m_pkSk->kDurationPoly2.Eval();
  1405.                 iDur2 += m_pkChr->GetPoint(POINT_PARTY_BUFFER_BONUS);
  1406.  
  1407.                 if (number(1, 100) <= iAmount2)
  1408.                 {
  1409.                     pkChrVictim->RemoveGoodAffect();
  1410.                     pkChrVictim->AddAffect(m_pkSk->dwVnum, POINT_NONE, 0, AFF_PABEOP, iDur2, 0, true);
  1411.                 }
  1412.             }
  1413.  
  1414.             if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_SLOW | SKILL_FLAG_STUN | SKILL_FLAG_FIRE_CONT | SKILL_FLAG_POISON))
  1415.             {
  1416.                 int iPct = (int) m_pkSk->kPointPoly2.Eval();
  1417.                 int iDur = (int) m_pkSk->kDurationPoly2.Eval();
  1418.  
  1419.                 iDur += m_pkChr->GetPoint(POINT_PARTY_BUFFER_BONUS);
  1420.  
  1421.                 if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_STUN))
  1422.                 {
  1423.                     SkillAttackAffect(pkChrVictim, iPct, IMMUNE_STUN, AFFECT_STUN, POINT_NONE, 0, AFF_STUN, iDur, m_pkSk->szName);
  1424.                 }
  1425.                 else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_SLOW))
  1426.                 {
  1427.                     SkillAttackAffect(pkChrVictim, iPct, IMMUNE_SLOW, AFFECT_SLOW, POINT_MOV_SPEED, -30, AFF_SLOW, iDur, m_pkSk->szName);
  1428.                 }
  1429.                 else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_FIRE_CONT))
  1430.                 {
  1431.                     m_pkSk->SetDurationVar("k", 1.0 * m_bUseSkillPower * m_pkSk->bMaxLevel / 100);
  1432.                     m_pkSk->SetDurationVar("iq", m_pkChr->GetPoint(POINT_IQ));
  1433.  
  1434.                     iDur = (int)m_pkSk->kDurationPoly2.Eval();
  1435.                     int bonus = m_pkChr->GetPoint(POINT_PARTY_BUFFER_BONUS);
  1436.  
  1437.                     if (bonus != 0)
  1438.                     {
  1439.                         iDur += bonus / 2;
  1440.                     }
  1441.  
  1442.                     if (number(1, 100) <= iDur)
  1443.                     {
  1444.                         pkChrVictim->AttackedByFire(m_pkChr, iPct, 5);
  1445.                     }
  1446.                 }
  1447.                 else if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_POISON))
  1448.                 {
  1449.                     if (number(1, 100) <= iPct)
  1450.                         pkChrVictim->AttackedByPoison(m_pkChr);
  1451.                 }
  1452.             }
  1453.  
  1454.             if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH | SKILL_FLAG_CRUSH_LONG) &&
  1455.                 !IS_SET(pkChrVictim->GetAIFlag(), AIFLAG_NOMOVE))
  1456.             {
  1457.                 float fCrushSlidingLength = 200;
  1458.  
  1459.                 if (m_pkChr->IsNPC())
  1460.                     fCrushSlidingLength = 400;
  1461.  
  1462.                 if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_CRUSH_LONG))
  1463.                     fCrushSlidingLength *= 2;
  1464.  
  1465.                 float fx, fy;
  1466.                 float degree = GetDegreeFromPositionXY(m_pkChr->GetX(), m_pkChr->GetY(), pkChrVictim->GetX(), pkChrVictim->GetY());
  1467.  
  1468.                 if (m_pkSk->dwVnum == SKILL_HORSE_WILDATTACK)
  1469.                 {
  1470.                     degree -= m_pkChr->GetRotation();
  1471.                     degree = fmod(degree, 360.0f) - 180.0f;
  1472.  
  1473.                     if (degree > 0)
  1474.                         degree = m_pkChr->GetRotation() + 90.0f;
  1475.                     else
  1476.                         degree = m_pkChr->GetRotation() - 90.0f;
  1477.                 }
  1478.  
  1479.                 GetDeltaByDegree(degree, fCrushSlidingLength, &fx, &fy);
  1480.                 sys_log(0, "CRUSH! %s -> %s (%d %d) -> (%d %d)", m_pkChr->GetName(), pkChrVictim->GetName(), pkChrVictim->GetX(), pkChrVictim->GetY(), (long)(pkChrVictim->GetX()+fx), (long)(pkChrVictim->GetY()+fy));
  1481.                 long tx = (long)(pkChrVictim->GetX()+fx);
  1482.                 long ty = (long)(pkChrVictim->GetY()+fy);
  1483.  
  1484.                 pkChrVictim->Sync(tx, ty);
  1485.                 pkChrVictim->Goto(tx, ty);
  1486.                 pkChrVictim->CalculateMoveDuration();
  1487.  
  1488.                 if (m_pkChr->IsPC() && m_pkChr->m_SkillUseInfo[m_pkSk->dwVnum].GetMainTargetVID() == (DWORD) pkChrVictim->GetVID())
  1489.                 {
  1490.                     //if (!g_iUseLocale)
  1491.                     if (LC_IsYMIR())
  1492.                         SkillAttackAffect(pkChrVictim, 1000, IMMUNE_STUN, m_pkSk->dwVnum, POINT_NONE, 0, AFF_STUN, 3, m_pkSk->szName);
  1493.                     else
  1494.                         SkillAttackAffect(pkChrVictim, 1000, IMMUNE_STUN, m_pkSk->dwVnum, POINT_NONE, 0, AFF_STUN, 4, m_pkSk->szName);
  1495.                 }
  1496.                 else
  1497.                 {
  1498.                     pkChrVictim->SyncPacket();
  1499.                 }
  1500.             }
  1501.         }
  1502.  
  1503.         if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_HP_ABSORB))
  1504.         {
  1505.             int iPct = (int) m_pkSk->kPointPoly2.Eval();
  1506.             m_pkChr->PointChange(POINT_HP, iDam * iPct / 100);
  1507.         }
  1508.  
  1509.         if (IS_SET(m_pkSk->dwFlag, SKILL_FLAG_SP_ABSORB))
  1510.         {
  1511.             int iPct = (int) m_pkSk->kPointPoly2.Eval();
  1512.             m_pkChr->PointChange(POINT_SP, iDam * iPct / 100);
  1513.         }
  1514.  
  1515.         if (m_pkSk->dwVnum == SKILL_CHAIN && m_pkChr->GetChainLightningIndex() < m_pkChr->GetChainLightningMaxCount())
  1516.         {
  1517.             chain_lightning_event_info* info = AllocEventInfo<chain_lightning_event_info>();
  1518.  
  1519.             info->dwVictim = pkChrVictim->GetVID();
  1520.             info->dwChr = m_pkChr->GetVID();
  1521.  
  1522.             event_create(ChainLightningEvent, info, passes_per_sec / 5);
  1523.         }
  1524.         if(test_server)
  1525.             sys_log(0, "FuncSplashDamage End :%s ", m_pkChr->GetName());
  1526.     }
  1527.  
  1528.     int     m_x;
  1529.     int     m_y;
  1530.     CSkillProto * m_pkSk;
  1531.     LPCHARACTER m_pkChr;
  1532.     int     m_iAmount;
  1533.     int     m_iAG;
  1534.     int     m_iCount;
  1535.     int     m_iMaxHit;
  1536.     LPITEM  m_pkWeapon;
  1537.     bool m_bDisableCooltime;
  1538.     TSkillUseInfo* m_pInfo;
  1539.     BYTE m_bUseSkillPower;
  1540. };
  1541.  
  1542. struct FuncSplashAffect
  1543. {
  1544.     FuncSplashAffect(LPCHARACTER ch, int x, int y, int iDist, DWORD dwVnum, BYTE bPointOn, int iAmount, DWORD dwAffectFlag, int iDuration, int iSPCost, bool bOverride, int iMaxHit)
  1545.     {
  1546.         m_x = x;
  1547.         m_y = y;
  1548.         m_iDist = iDist;
  1549.         m_dwVnum = dwVnum;
  1550.         m_bPointOn = bPointOn;
  1551.         m_iAmount = iAmount;
  1552.         m_dwAffectFlag = dwAffectFlag;
  1553.         m_iDuration = iDuration;
  1554.         m_iSPCost = iSPCost;
  1555.         m_bOverride = bOverride;
  1556.         m_pkChrAttacker = ch;
  1557.         m_iMaxHit = iMaxHit;
  1558.         m_iCount = 0;
  1559.     }
  1560.  
  1561.     void operator () (LPENTITY ent)
  1562.     {
  1563.         if (m_iMaxHit && m_iMaxHit <= m_iCount)
  1564.             return;
  1565.  
  1566.         if (ent->IsType(ENTITY_CHARACTER))
  1567.         {
  1568.             LPCHARACTER pkChr = (LPCHARACTER) ent;
  1569.  
  1570.             if (test_server)
  1571.                 sys_log(0, "FuncSplashAffect step 1 : name:%s vnum:%d iDur:%d", pkChr->GetName(), m_dwVnum, m_iDuration);
  1572.             if (DISTANCE_APPROX(m_x - pkChr->GetX(), m_y - pkChr->GetY()) < m_iDist)
  1573.             {
  1574.                 if (test_server)
  1575.                     sys_log(0, "FuncSplashAffect step 2 : name:%s vnum:%d iDur:%d", pkChr->GetName(), m_dwVnum, m_iDuration);
  1576.                 if (m_dwVnum == SKILL_TUSOK)
  1577.                     if (pkChr->CanBeginFight())
  1578.                         pkChr->BeginFight(m_pkChrAttacker);
  1579.  
  1580.                 if (pkChr->IsPC() && m_dwVnum == SKILL_TUSOK)
  1581.                     pkChr->AddAffect(m_dwVnum, m_bPointOn, m_iAmount, m_dwAffectFlag, m_iDuration/3, m_iSPCost, m_bOverride);
  1582.                 else
  1583.                     pkChr->AddAffect(m_dwVnum, m_bPointOn, m_iAmount, m_dwAffectFlag, m_iDuration, m_iSPCost, m_bOverride);
  1584.  
  1585.                 m_iCount ++;
  1586.             }
  1587.         }
  1588.     }
  1589.  
  1590.     LPCHARACTER m_pkChrAttacker;
  1591.     int     m_x;
  1592.     int     m_y;
  1593.     int     m_iDist;
  1594.     DWORD   m_dwVnum;
  1595.     BYTE    m_bPointOn;
  1596.     int     m_iAmount;
  1597.     DWORD   m_dwAffectFlag;
  1598.     int     m_iDuration;
  1599.     int     m_iSPCost;
  1600.     bool    m_bOverride;
  1601.     int         m_iMaxHit;
  1602.     int         m_iCount;
  1603. };
  1604.  
  1605. EVENTINFO(skill_gwihwan_info)
  1606. {
  1607.     DWORD pid;
  1608.     BYTE bsklv;
  1609.  
  1610.     skill_gwihwan_info()
  1611.     : pid( 0 )
  1612.     , bsklv( 0 )
  1613.     {
  1614.     }
  1615. };
  1616.  
  1617. EVENTFUNC(skill_gwihwan_event)
  1618. {
  1619.     skill_gwihwan_info* info = dynamic_cast<skill_gwihwan_info*>( event->info );
  1620.  
  1621.     if ( info == NULL )
  1622.     {
  1623.         sys_err( "skill_gwihwan_event> <Factor> Null pointer" );
  1624.         return 0;
  1625.     }
  1626.  
  1627.     DWORD pid = info->pid;
  1628.     BYTE sklv= info->bsklv;
  1629.     LPCHARACTER ch = CHARACTER_MANAGER::instance().FindByPID(pid);
  1630.  
  1631.     if (!ch)
  1632.         return 0;
  1633.  
  1634.     int percent = 20 * sklv - 1;
  1635.  
  1636.     if (number(1, 100) <= percent)
  1637.     {
  1638.         PIXEL_POSITION pos;
  1639.  
  1640.         // ¼º°ø
  1641.         if (SECTREE_MANAGER::instance().GetRecallPositionByEmpire(ch->GetMapIndex(), ch->GetEmpire(), pos))
  1642.         {
  1643.             sys_log(1, "Recall: %s %d %d -> %d %d", ch->GetName(), ch->GetX(), ch->GetY(), pos.x, pos.y);
  1644.             ch->WarpSet(pos.x, pos.y);
  1645.         }
  1646.         else
  1647.         {
  1648.             sys_err("CHARACTER::UseItem : cannot find spawn position (name %s, %d x %d)", ch->GetName(), ch->GetX(), ch->GetY());
  1649.             ch->WarpSet(EMPIRE_START_X(ch->GetEmpire()), EMPIRE_START_Y(ch->GetEmpire()));
  1650.         }
  1651.     }
  1652.     else
  1653.     {
  1654.         //½ÇÆÐ
  1655.         ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(ch->GetLanguage(),"±Íȯ¿¡ ½ÇÆÐÇÏ¿´½À´Ï´Ù."));
  1656.     }
  1657.     return 0;
  1658. }
  1659.  
  1660. int CHARACTER::ComputeSkillAtPosition(DWORD dwVnum, const PIXEL_POSITION& posTarget, BYTE bSkillLevel)
  1661. {
  1662.     if (GetMountVnum())
  1663.         return BATTLE_NONE;
  1664.  
  1665.     if (IsPolymorphed())
  1666.         return BATTLE_NONE;
  1667.  
  1668.     if (g_bSkillDisable)
  1669.         return BATTLE_NONE;
  1670.  
  1671.     CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
  1672.  
  1673.     if (!pkSk)
  1674.         return BATTLE_NONE;
  1675.  
  1676.     if (test_server)
  1677.     {
  1678.         sys_log(0, "ComputeSkillAtPosition %s vnum %d x %d y %d level %d",
  1679.                 GetName(), dwVnum, posTarget.x, posTarget.y, bSkillLevel);
  1680.     }
  1681.  
  1682.     // ³ª¿¡°Ô ¾²´Â ½ºÅ³Àº ³» À§Ä¡¸¦ ¾´´Ù.
  1683.     //if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
  1684.     //  posTarget = GetXYZ();
  1685.  
  1686.     // ½ºÇ÷¡½¬°¡ ¾Æ´Ñ ½ºÅ³Àº ÁÖÀ§À̸é ÀÌ»óÇÏ´Ù
  1687.     if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  1688.         return BATTLE_NONE;
  1689.  
  1690.     if (0 == bSkillLevel)
  1691.     {
  1692.         if ((bSkillLevel = GetSkillLevel(pkSk->dwVnum)) == 0)
  1693.         {
  1694.             return BATTLE_NONE;
  1695.         }
  1696.     }
  1697.  
  1698.     const float k = 1.0 * GetSkillPower(pkSk->dwVnum, bSkillLevel) * pkSk->bMaxLevel / 100;
  1699.  
  1700.     pkSk->SetPointVar("k", k);
  1701.     pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);
  1702.  
  1703.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MELEE_DAMAGE))
  1704.     {
  1705.         pkSk->SetPointVar("atk", CalcMeleeDamage(this, this, true, false));
  1706.     }
  1707.     else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MAGIC_DAMAGE))
  1708.     {
  1709.         pkSk->SetPointVar("atk", CalcMagicDamage(this, this));
  1710.     }
  1711.     else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_ARROW_DAMAGE))
  1712.     {
  1713.         LPITEM pkBow, pkArrow;
  1714.         if (1 == GetArrowAndBow(&pkBow, &pkArrow, 1))
  1715.         {
  1716.             pkSk->SetPointVar("atk", CalcArrowDamage(this, this, pkBow, pkArrow, true));
  1717.         }
  1718.         else
  1719.         {
  1720.             pkSk->SetPointVar("atk", 0);
  1721.         }
  1722.     }
  1723.  
  1724.     if (pkSk->bPointOn == POINT_MOV_SPEED)
  1725.     {
  1726.         pkSk->SetPointVar("maxv", this->GetLimitPoint(POINT_MOV_SPEED));
  1727.     }
  1728.  
  1729.     pkSk->SetPointVar("lv", GetLevel());
  1730.     pkSk->SetPointVar("iq", GetPoint(POINT_IQ));
  1731.     pkSk->SetPointVar("str", GetPoint(POINT_ST));
  1732.     pkSk->SetPointVar("dex", GetPoint(POINT_DX));
  1733.     pkSk->SetPointVar("con", GetPoint(POINT_HT));
  1734.     pkSk->SetPointVar("maxhp", this->GetMaxHP());
  1735.     pkSk->SetPointVar("maxsp", this->GetMaxSP());
  1736.     pkSk->SetPointVar("chain", 0);
  1737.     pkSk->SetPointVar("ar", CalcAttackRating(this, this));
  1738.     pkSk->SetPointVar("def", GetPoint(POINT_DEF_GRADE));
  1739.     pkSk->SetPointVar("odef", GetPoint(POINT_DEF_GRADE) - GetPoint(POINT_DEF_GRADE_BONUS));
  1740.     pkSk->SetPointVar("horse_level", GetHorseLevel());
  1741.  
  1742.     if (pkSk->bSkillAttrType != SKILL_ATTR_TYPE_NORMAL)
  1743.         OnMove(true);
  1744.  
  1745.     LPITEM pkWeapon = GetWear(WEAR_WEAPON);
  1746.  
  1747.     SetPolyVarForAttack(this, pkSk, pkWeapon);
  1748.  
  1749.     pkSk->SetDurationVar("k", k/*bSkillLevel*/);
  1750.  
  1751.     int iAmount = (int) pkSk->kPointPoly.Eval();
  1752.     int iAmount2 = (int) pkSk->kPointPoly2.Eval();
  1753.  
  1754.     // ADD_GRANDMASTER_SKILL
  1755.     int iAmount3 = (int) pkSk->kPointPoly3.Eval();
  1756.  
  1757.     if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
  1758.     {
  1759.         /*
  1760.            if (iAmount >= 0)
  1761.            iAmount += (int) m_pkSk->kMasterBonusPoly.Eval();
  1762.            else
  1763.            iAmount -= (int) m_pkSk->kMasterBonusPoly.Eval();
  1764.          */
  1765.         iAmount = (int) pkSk->kMasterBonusPoly.Eval();
  1766.     }
  1767.  
  1768.     if (test_server && iAmount == 0 && pkSk->bPointOn != POINT_NONE)
  1769.     {
  1770.         ChatPacket(CHAT_TYPE_INFO, "È¿°ú°¡ ¾ø½À´Ï´Ù. ½ºÅ³ °ø½ÄÀ» È®ÀÎÇϼ¼¿ä");
  1771.     }
  1772.  
  1773.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_REMOVE_BAD_AFFECT))
  1774.     {
  1775.         if (number(1, 100) <= iAmount2)
  1776.         {
  1777.             RemoveBadAffect();
  1778.         }
  1779.     }
  1780.     // END_OF_ADD_GRANDMASTER_SKILL
  1781.  
  1782.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK | SKILL_FLAG_USE_MELEE_DAMAGE | SKILL_FLAG_USE_MAGIC_DAMAGE))
  1783.     {
  1784.         //
  1785.         // °ø°Ý ½ºÅ³ÀÏ °æ¿ì
  1786.         //
  1787.         bool bAdded = false;
  1788.  
  1789.         if (pkSk->bPointOn == POINT_HP && iAmount < 0)
  1790.         {
  1791.             int iAG = 0;
  1792.  
  1793.             FuncSplashDamage f(posTarget.x, posTarget.y, pkSk, this, iAmount, iAG, pkSk->lMaxHit, pkWeapon, m_bDisableCooltime, IsPC()?&m_SkillUseInfo[dwVnum]:NULL, GetSkillPower(dwVnum, bSkillLevel));
  1794.  
  1795.             if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  1796.             {
  1797.                 if (GetSectree())
  1798.                     GetSectree()->ForEachAround(f);
  1799.             }
  1800.             else
  1801.             {
  1802.                 //if (dwVnum == SKILL_CHAIN) sys_log(0, "CHAIN skill call FuncSplashDamage %s", GetName());
  1803.                 f(this);
  1804.             }
  1805.         }
  1806.         else
  1807.         {
  1808.             //if (dwVnum == SKILL_CHAIN) sys_log(0, "CHAIN skill no damage %d %s", iAmount, GetName());
  1809.             int iDur = (int) pkSk->kDurationPoly.Eval();
  1810.  
  1811.             if (IsPC())
  1812.                 if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // ±æµå ½ºÅ³Àº ÄðŸÀÓ Ã³¸®¸¦ ÇÏÁö ¾Ê´Â´Ù.
  1813.                     if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
  1814.                     {
  1815.                         //if (dwVnum == SKILL_CHAIN) sys_log(0, "CHAIN skill cannot hit %s", GetName());
  1816.                         return BATTLE_NONE;
  1817.                     }
  1818.  
  1819.  
  1820.             if (iDur > 0)
  1821.             {
  1822.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  1823.  
  1824.                 if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  1825.                     AddAffect(pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true);
  1826.                 else
  1827.                 {
  1828.                     if (GetSectree())
  1829.                     {
  1830.                         FuncSplashAffect f(this, posTarget.x, posTarget.y, pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true, pkSk->lMaxHit);
  1831.                         GetSectree()->ForEachAround(f);
  1832.                     }
  1833.                 }
  1834.                 bAdded = true;
  1835.             }
  1836.         }
  1837.  
  1838.         if (pkSk->bPointOn2 != POINT_NONE)
  1839.         {
  1840.             int iDur = (int) pkSk->kDurationPoly2.Eval();
  1841.  
  1842.             sys_log(1, "try second %u %d %d", pkSk->dwVnum, pkSk->bPointOn2, iDur);
  1843.  
  1844.             if (iDur > 0)
  1845.             {
  1846.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  1847.  
  1848.                 if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  1849.                     AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded);
  1850.                 else
  1851.                 {
  1852.                     if (GetSectree())
  1853.                     {
  1854.                         FuncSplashAffect f(this, posTarget.x, posTarget.y, pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded, pkSk->lMaxHit);
  1855.                         GetSectree()->ForEachAround(f);
  1856.                     }
  1857.                 }
  1858.                 bAdded = true;
  1859.             }
  1860.             else
  1861.             {
  1862.                 PointChange(pkSk->bPointOn2, iAmount2);
  1863.             }
  1864.         }
  1865.  
  1866.         // ADD_GRANDMASTER_SKILL
  1867.         if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER && pkSk->bPointOn3 != POINT_NONE)
  1868.         {
  1869.             int iDur = (int) pkSk->kDurationPoly3.Eval();
  1870.  
  1871.             if (iDur > 0)
  1872.             {
  1873.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  1874.  
  1875.                 if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  1876.                     AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, 0 /*pkSk->dwAffectFlag3*/, iDur, 0, !bAdded);
  1877.                 else
  1878.                 {
  1879.                     if (GetSectree())
  1880.                     {
  1881.                         FuncSplashAffect f(this, posTarget.x, posTarget.y, pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn3, iAmount3, 0 /*pkSk->dwAffectFlag3*/, iDur, 0, !bAdded, pkSk->lMaxHit);
  1882.                         GetSectree()->ForEachAround(f);
  1883.                     }
  1884.                 }
  1885.             }
  1886.             else
  1887.             {
  1888.                 PointChange(pkSk->bPointOn3, iAmount3);
  1889.             }
  1890.         }
  1891.         // END_OF_ADD_GRANDMASTER_SKILL
  1892.  
  1893.         return BATTLE_DAMAGE;
  1894.     }
  1895.     else
  1896.     {
  1897.         bool bAdded = false;
  1898.         int iDur = (int) pkSk->kDurationPoly.Eval();
  1899.  
  1900.         if (iDur > 0)
  1901.         {
  1902.             iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  1903.             // AffectFlag°¡ ¾ø°Å³ª, toggle ÇÏ´Â °ÍÀÌ ¾Æ´Ï¶ó¸é..
  1904.             pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);
  1905.  
  1906.             AddAffect(pkSk->dwVnum,
  1907.                       pkSk->bPointOn,
  1908.                       iAmount,
  1909.                       pkSk->dwAffectFlag,
  1910.                       iDur,
  1911.                       (long) pkSk->kDurationSPCostPoly.Eval(),
  1912.                       !bAdded);
  1913.  
  1914.             bAdded = true;
  1915.         }
  1916.         else
  1917.         {
  1918.             PointChange(pkSk->bPointOn, iAmount);
  1919.         }
  1920.  
  1921.         if (pkSk->bPointOn2 != POINT_NONE)
  1922.         {
  1923.             int iDur = (int) pkSk->kDurationPoly2.Eval();
  1924.  
  1925.             if (iDur > 0)
  1926.             {
  1927.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  1928.                 AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded);
  1929.                 bAdded = true;
  1930.             }
  1931.             else
  1932.             {
  1933.                 PointChange(pkSk->bPointOn2, iAmount2);
  1934.             }
  1935.         }
  1936.  
  1937.         // ADD_GRANDMASTER_SKILL
  1938.         if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER && pkSk->bPointOn3 != POINT_NONE)
  1939.         {
  1940.             int iDur = (int) pkSk->kDurationPoly3.Eval();
  1941.  
  1942.             if (iDur > 0)
  1943.             {
  1944.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  1945.                 AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, 0 /*pkSk->dwAffectFlag3*/, iDur, 0, !bAdded);
  1946.             }
  1947.             else
  1948.             {
  1949.                 PointChange(pkSk->bPointOn3, iAmount3);
  1950.             }
  1951.         }
  1952.         // END_OF_ADD_GRANDMASTER_SKILL
  1953.  
  1954.         return BATTLE_NONE;
  1955.     }
  1956. }
  1957.  
  1958. // bSkillLevel ÀÎÀÚ°¡ 0ÀÌ ¾Æ´Ò °æ¿ì¿¡´Â m_abSkillLevels¸¦ »ç¿ëÇÏÁö ¾Ê°í °­Á¦·Î
  1959. // bSkillLevel·Î °è»êÇÑ´Ù.
  1960. int CHARACTER::ComputeSkill(DWORD dwVnum, LPCHARACTER pkVictim, BYTE bSkillLevel)
  1961. {
  1962.     const bool bCanUseHorseSkill = CanUseHorseSkill();
  1963.  
  1964.     // ¸»À» Ÿ°íÀÖÁö¸¸ ½ºÅ³Àº »ç¿ëÇÒ ¼ö ¾ø´Â »óŶó¸é return
  1965.     if (false == bCanUseHorseSkill && true == IsRiding())
  1966.         return BATTLE_NONE;
  1967.  
  1968.     if (IsPolymorphed())
  1969.         return BATTLE_NONE;
  1970.  
  1971.     if (g_bSkillDisable)
  1972.         return BATTLE_NONE;
  1973.  
  1974.     CSkillProto* pkSk = CSkillManager::instance().Get(dwVnum);
  1975.  
  1976.     if (!pkSk)
  1977.         return BATTLE_NONE;
  1978.  
  1979.     if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE)
  1980.         return BATTLE_NONE;
  1981.  
  1982.     if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE)
  1983.         return BATTLE_NONE;
  1984.    
  1985.  
  1986.     // »ó´ë¹æ¿¡°Ô ¾²´Â °ÍÀÌ ¾Æ´Ï¸é ³ª¿¡°Ô ½á¾ß ÇÑ´Ù.
  1987.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
  1988.         pkVictim = this;
  1989.  
  1990.     if (!pkVictim)
  1991.     {
  1992.         if (test_server)
  1993.             sys_log(0, "ComputeSkill: %s Victim == null, skill %d", GetName(), dwVnum);
  1994.  
  1995.         return BATTLE_NONE;
  1996.     }
  1997.  
  1998.     if (pkSk->dwTargetRange && DISTANCE_SQRT(GetX() - pkVictim->GetX(), GetY() - pkVictim->GetY()) >= pkSk->dwTargetRange + 50)
  1999.     {
  2000.         if (test_server)
  2001.             sys_log(0, "ComputeSkill: Victim too far, skill %d : %s to %s (distance %u limit %u)",
  2002.                     dwVnum,
  2003.                     GetName(),
  2004.                     pkVictim->GetName(),
  2005.                     (long)DISTANCE_SQRT(GetX() - pkVictim->GetX(), GetY() - pkVictim->GetY()),
  2006.                     pkSk->dwTargetRange);
  2007.  
  2008.         return BATTLE_NONE;
  2009.     }
  2010.  
  2011.     if (0 == bSkillLevel)
  2012.     {
  2013.         if ((bSkillLevel = GetSkillLevel(pkSk->dwVnum)) == 0)
  2014.         {
  2015.             if (test_server)
  2016.                 sys_log(0, "ComputeSkill : name:%s vnum:%d  skillLevelBySkill : %d ", GetName(), pkSk->dwVnum, bSkillLevel);
  2017.             return BATTLE_NONE;
  2018.         }
  2019.     }
  2020.  
  2021.     if (pkVictim->IsAffectFlag(AFF_PABEOP) && pkVictim->IsGoodAffect(dwVnum))
  2022.     {
  2023.         return BATTLE_NONE;
  2024.     }
  2025.  
  2026.     const float k = 1.0 * GetSkillPower(pkSk->dwVnum, bSkillLevel) * pkSk->bMaxLevel / 100;
  2027.  
  2028.     pkSk->SetPointVar("k", k);
  2029.     pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);
  2030.  
  2031.     if (pkSk->dwType == SKILL_TYPE_HORSE)
  2032.     {
  2033.         LPITEM pkBow, pkArrow;
  2034.         if (1 == GetArrowAndBow(&pkBow, &pkArrow, 1))
  2035.         {
  2036.             pkSk->SetPointVar("atk", CalcArrowDamage(this, pkVictim, pkBow, pkArrow, true));
  2037.         }
  2038.         else
  2039.         {
  2040.             pkSk->SetPointVar("atk", CalcMeleeDamage(this, pkVictim, true, false));
  2041.         }
  2042.     }
  2043.     else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MELEE_DAMAGE))
  2044.     {
  2045.         pkSk->SetPointVar("atk", CalcMeleeDamage(this, pkVictim, true, false));
  2046.     }
  2047.     else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_MAGIC_DAMAGE))
  2048.     {
  2049.         pkSk->SetPointVar("atk", CalcMagicDamage(this, pkVictim));
  2050.     }
  2051.     else if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_ARROW_DAMAGE))
  2052.     {
  2053.         LPITEM pkBow, pkArrow;
  2054.         if (1 == GetArrowAndBow(&pkBow, &pkArrow, 1))
  2055.         {
  2056.             pkSk->SetPointVar("atk", CalcArrowDamage(this, pkVictim, pkBow, pkArrow, true));
  2057.         }
  2058.         else
  2059.         {
  2060.             pkSk->SetPointVar("atk", 0);
  2061.         }
  2062.     }
  2063.  
  2064.     if (pkSk->bPointOn == POINT_MOV_SPEED)
  2065.     {
  2066.         pkSk->SetPointVar("maxv", pkVictim->GetLimitPoint(POINT_MOV_SPEED));
  2067.     }
  2068.  
  2069.     pkSk->SetPointVar("lv", GetLevel());
  2070.     pkSk->SetPointVar("iq", GetPoint(POINT_IQ));
  2071.     pkSk->SetPointVar("str", GetPoint(POINT_ST));
  2072.     pkSk->SetPointVar("dex", GetPoint(POINT_DX));
  2073.     pkSk->SetPointVar("con", GetPoint(POINT_HT));
  2074.     pkSk->SetPointVar("maxhp", pkVictim->GetMaxHP());
  2075.     pkSk->SetPointVar("maxsp", pkVictim->GetMaxSP());
  2076.     pkSk->SetPointVar("chain", 0);
  2077.     pkSk->SetPointVar("ar", CalcAttackRating(this, pkVictim));
  2078.     pkSk->SetPointVar("def", GetPoint(POINT_DEF_GRADE));
  2079.     pkSk->SetPointVar("odef", GetPoint(POINT_DEF_GRADE) - GetPoint(POINT_DEF_GRADE_BONUS));
  2080.     pkSk->SetPointVar("horse_level", GetHorseLevel());
  2081.  
  2082.     if (pkSk->bSkillAttrType != SKILL_ATTR_TYPE_NORMAL)
  2083.         OnMove(true);
  2084.  
  2085.     LPITEM pkWeapon = GetWear(WEAR_WEAPON);
  2086.  
  2087.     SetPolyVarForAttack(this, pkSk, pkWeapon);
  2088.  
  2089.     pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
  2090.     pkSk->kDurationPoly2.SetVar("k", k/*bSkillLevel*/);
  2091.  
  2092.     int iAmount = (int) pkSk->kPointPoly.Eval();
  2093.     int iAmount2 = (int) pkSk->kPointPoly2.Eval();
  2094.     int iAmount3 = (int) pkSk->kPointPoly3.Eval();
  2095.  
  2096.     if (test_server && IsPC())
  2097.         sys_log(0, "iAmount: %d %d %d , atk:%f skLevel:%f k:%f GetSkillPower(%d) MaxLevel:%d Per:%f",
  2098.                 iAmount, iAmount2, iAmount3,
  2099.                 pkSk->kPointPoly.GetVar("atk"),
  2100.                 pkSk->kPointPoly.GetVar("k"),
  2101.                 k,
  2102.                 GetSkillPower(pkSk->dwVnum, bSkillLevel),
  2103.                 pkSk->bMaxLevel,
  2104.                 pkSk->bMaxLevel/100
  2105.                 );
  2106.  
  2107.     // ADD_GRANDMASTER_SKILL
  2108.     if (GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
  2109.     {
  2110.         iAmount = (int) pkSk->kMasterBonusPoly.Eval();
  2111.     }
  2112.  
  2113.     if (test_server && iAmount == 0 && pkSk->bPointOn != POINT_NONE)
  2114.     {
  2115.         ChatPacket(CHAT_TYPE_INFO, "È¿°ú°¡ ¾ø½À´Ï´Ù. ½ºÅ³ °ø½ÄÀ» È®ÀÎÇϼ¼¿ä");
  2116.     }
  2117.     // END_OF_ADD_GRANDMASTER_SKILL
  2118.  
  2119.     //sys_log(0, "XXX SKILL Calc %d Amount %d", dwVnum, iAmount);
  2120.  
  2121.     // REMOVE_BAD_AFFECT_BUG_FIX
  2122.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_REMOVE_BAD_AFFECT))
  2123.     {
  2124.         if (number(1, 100) <= iAmount2)
  2125.         {
  2126.             pkVictim->RemoveBadAffect();
  2127.         }
  2128.     }
  2129.     // END_OF_REMOVE_BAD_AFFECT_BUG_FIX
  2130.  
  2131.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK | SKILL_FLAG_USE_MELEE_DAMAGE | SKILL_FLAG_USE_MAGIC_DAMAGE) &&
  2132.         !(pkSk->dwVnum == SKILL_MUYEONG && pkVictim == this) && !(pkSk->IsChargeSkill() && pkVictim == this))
  2133.     {
  2134.         bool bAdded = false;
  2135.  
  2136.         if (pkSk->bPointOn == POINT_HP && iAmount < 0)
  2137.         {
  2138.             int iAG = 0;
  2139.            
  2140.  
  2141.             FuncSplashDamage f(pkVictim->GetX(), pkVictim->GetY(), pkSk, this, iAmount, iAG, pkSk->lMaxHit, pkWeapon, m_bDisableCooltime, IsPC()?&m_SkillUseInfo[dwVnum]:NULL, GetSkillPower(dwVnum, bSkillLevel));
  2142.             if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  2143.             {
  2144.                 if (pkVictim->GetSectree())
  2145.                     pkVictim->GetSectree()->ForEachAround(f);
  2146.             }
  2147.             else
  2148.             {
  2149.                 f(pkVictim);
  2150.             }
  2151.         }
  2152.         else
  2153.         {
  2154.             pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
  2155.             int iDur = (int) pkSk->kDurationPoly.Eval();
  2156.            
  2157.  
  2158.             if (IsPC())
  2159.                 if (!(dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)) // ±æµå ½ºÅ³Àº ÄðŸÀÓ Ã³¸®¸¦ ÇÏÁö ¾Ê´Â´Ù.
  2160.                     if (!m_bDisableCooltime && !m_SkillUseInfo[dwVnum].HitOnce(dwVnum) && dwVnum != SKILL_MUYEONG)
  2161.                     {
  2162.                         return BATTLE_NONE;
  2163.                     }
  2164.  
  2165.             if (iDur > 0)
  2166.             {
  2167.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2168.  
  2169.                 if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  2170.                     pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true);
  2171.                 else
  2172.                 {
  2173.                     if (pkVictim->GetSectree())
  2174.                     {
  2175.                         FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn, iAmount, pkSk->dwAffectFlag, iDur, 0, true, pkSk->lMaxHit);
  2176.                         pkVictim->GetSectree()->ForEachAround(f);
  2177.                     }
  2178.                 }
  2179.                 bAdded = true;
  2180.             }
  2181.         }
  2182.  
  2183.         if (pkSk->bPointOn2 != POINT_NONE && !pkSk->IsChargeSkill())
  2184.         {
  2185.             pkSk->kDurationPoly2.SetVar("k", k/*bSkillLevel*/);
  2186.             int iDur = (int) pkSk->kDurationPoly2.Eval();
  2187.  
  2188.             if (iDur > 0)
  2189.             {
  2190.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2191.  
  2192.                 if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  2193.                     pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded);
  2194.                 else
  2195.                 {
  2196.                     if (pkVictim->GetSectree())
  2197.                     {
  2198.                         FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur, 0, !bAdded, pkSk->lMaxHit);
  2199.                         pkVictim->GetSectree()->ForEachAround(f);
  2200.                     }
  2201.                 }
  2202.  
  2203.                 bAdded = true;
  2204.             }
  2205.             else
  2206.             {
  2207.                 pkVictim->PointChange(pkSk->bPointOn2, iAmount2);
  2208.             }
  2209.         }
  2210.  
  2211.         // ADD_GRANDMASTER_SKILL
  2212.         if (pkSk->bPointOn3 != POINT_NONE && !pkSk->IsChargeSkill() && GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
  2213.         {
  2214.             pkSk->kDurationPoly3.SetVar("k", k/*bSkillLevel*/);
  2215.             int iDur = (int) pkSk->kDurationPoly3.Eval();
  2216.  
  2217.  
  2218.             if (iDur > 0)
  2219.             {
  2220.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2221.  
  2222.                 if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  2223.                     pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded);
  2224.                 else
  2225.                 {
  2226.                     if (pkVictim->GetSectree())
  2227.                     {
  2228.                         FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded, pkSk->lMaxHit);
  2229.                         pkVictim->GetSectree()->ForEachAround(f);
  2230.                     }
  2231.                 }
  2232.  
  2233.                 bAdded = true;
  2234.             }
  2235.             else
  2236.             {
  2237.                 pkVictim->PointChange(pkSk->bPointOn3, iAmount3);
  2238.             }
  2239.         }
  2240.         // END_OF_ADD_GRANDMASTER_SKILL
  2241.  
  2242.         return BATTLE_DAMAGE;
  2243.     }
  2244.     else
  2245.     {
  2246.         if (dwVnum == SKILL_MUYEONG)
  2247.         {
  2248.             pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
  2249.             pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);
  2250.  
  2251.             int iDur = (long) pkSk->kDurationPoly.Eval();
  2252.             iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2253.  
  2254.             if (pkVictim == this)
  2255.                 AddAffect(dwVnum,
  2256.                         POINT_NONE, 0,
  2257.                         AFF_MUYEONG,
  2258.                         iDur,
  2259.                         (long) pkSk->kDurationSPCostPoly.Eval(),
  2260.                         true);
  2261.  
  2262.             return BATTLE_NONE;
  2263.         }
  2264.  
  2265.         bool bAdded = false;
  2266.         pkSk->kDurationPoly.SetVar("k", k/*bSkillLevel*/);
  2267.         int iDur = (int) pkSk->kDurationPoly.Eval();
  2268.  
  2269.         if (iDur > 0)
  2270.         {
  2271.             iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2272.             // AffectFlag°¡ ¾ø°Å³ª, toggle ÇÏ´Â °ÍÀÌ ¾Æ´Ï¶ó¸é..
  2273.             pkSk->kDurationSPCostPoly.SetVar("k", k/*bSkillLevel*/);
  2274.  
  2275.             if (pkSk->bPointOn2 != POINT_NONE)
  2276.             {
  2277.                 pkVictim->RemoveAffect(pkSk->dwVnum);
  2278.  
  2279.                 int iDur2 = (int) pkSk->kDurationPoly2.Eval();
  2280.  
  2281.                 if (iDur2 > 0)
  2282.                 {
  2283.                     if (test_server)
  2284.                         sys_log(0, "SKILL_AFFECT: %s %s Dur:%d To:%d Amount:%d",
  2285.                                 GetName(),
  2286.                                 pkSk->szName,
  2287.                                 iDur2,
  2288.                                 pkSk->bPointOn2,
  2289.                                 iAmount2);
  2290.  
  2291.                     iDur2 += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2292.                     pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur2, 0, false);
  2293.                 }
  2294.                 else
  2295.                 {
  2296.                     pkVictim->PointChange(pkSk->bPointOn2, iAmount2);
  2297.                 }
  2298.  
  2299.                 DWORD affact_flag = pkSk->dwAffectFlag;
  2300.  
  2301.                 // ADD_GRANDMASTER_SKILL
  2302.                 //if (g_iUseLocale)
  2303.                 if ( !LC_IsYMIR() )
  2304.                 {
  2305.                     if ((pkSk->dwVnum == SKILL_CHUNKEON && GetUsedSkillMasterType(pkSk->dwVnum) < SKILL_GRAND_MASTER))
  2306.                         affact_flag = AFF_CHEONGEUN_WITH_FALL;
  2307.                 }
  2308.                 else
  2309.                 {
  2310.                     if ((pkSk->dwVnum == SKILL_CHUNKEON && GetUsedSkillMasterType(pkSk->dwVnum) < SKILL_MASTER))
  2311.                         affact_flag = AFF_CHEONGEUN_WITH_FALL;
  2312.                 }
  2313.                 // END_OF_ADD_GRANDMASTER_SKILL
  2314.  
  2315.                 pkVictim->AddAffect(pkSk->dwVnum,
  2316.                         pkSk->bPointOn,
  2317.                         iAmount,
  2318.                         affact_flag,
  2319.                         iDur,
  2320.                         (long) pkSk->kDurationSPCostPoly.Eval(),
  2321.                         false);
  2322.             }
  2323.             else
  2324.             {
  2325.                 if (test_server)
  2326.                     sys_log(0, "SKILL_AFFECT: %s %s Dur:%d To:%d Amount:%d",
  2327.                             GetName(),
  2328.                             pkSk->szName,
  2329.                             iDur,
  2330.                             pkSk->bPointOn,
  2331.                             iAmount);
  2332.  
  2333.                 pkVictim->AddAffect(pkSk->dwVnum,
  2334.                         pkSk->bPointOn,
  2335.                         iAmount,
  2336.                         pkSk->dwAffectFlag,
  2337.                         iDur,
  2338.                         (long) pkSk->kDurationSPCostPoly.Eval(),
  2339.                         // ADD_GRANDMASTER_SKILL
  2340.                         !bAdded);
  2341.                 // END_OF_ADD_GRANDMASTER_SKILL
  2342.             }
  2343.  
  2344.             bAdded = true;
  2345.         }
  2346.         else
  2347.         {
  2348.             if (!pkSk->IsChargeSkill())
  2349.                 pkVictim->PointChange(pkSk->bPointOn, iAmount);
  2350.  
  2351.             if (pkSk->bPointOn2 != POINT_NONE)
  2352.             {
  2353.                 pkVictim->RemoveAffect(pkSk->dwVnum);
  2354.  
  2355.                 int iDur2 = (int) pkSk->kDurationPoly2.Eval();
  2356.  
  2357.                 if (iDur2 > 0)
  2358.                 {
  2359.                     iDur2 += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2360.  
  2361.                     if (pkSk->IsChargeSkill())
  2362.                         pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, AFF_TANHWAN_DASH, iDur2, 0, false);
  2363.                     else
  2364.                         pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn2, iAmount2, pkSk->dwAffectFlag2, iDur2, 0, false);
  2365.                 }
  2366.                 else
  2367.                 {
  2368.                     pkVictim->PointChange(pkSk->bPointOn2, iAmount2);
  2369.                 }
  2370.  
  2371.             }
  2372.         }
  2373.  
  2374.         // ADD_GRANDMASTER_SKILL
  2375.         if (pkSk->bPointOn3 != POINT_NONE && !pkSk->IsChargeSkill() && GetUsedSkillMasterType(pkSk->dwVnum) >= SKILL_GRAND_MASTER)
  2376.         {
  2377.  
  2378.             pkSk->kDurationPoly3.SetVar("k", k/*bSkillLevel*/);
  2379.             int iDur = (int) pkSk->kDurationPoly3.Eval();
  2380.  
  2381.             sys_log(0, "try third %u %d %d %d 1894", pkSk->dwVnum, pkSk->bPointOn3, iDur, iAmount3);
  2382.  
  2383.             if (iDur > 0)
  2384.             {
  2385.                 iDur += GetPoint(POINT_PARTY_BUFFER_BONUS);
  2386.  
  2387.                 if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_SPLASH))
  2388.                     pkVictim->AddAffect(pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded);
  2389.                 else
  2390.                 {
  2391.                     if (pkVictim->GetSectree())
  2392.                     {
  2393.                         FuncSplashAffect f(this, pkVictim->GetX(), pkVictim->GetY(), pkSk->iSplashRange, pkSk->dwVnum, pkSk->bPointOn3, iAmount3, /*pkSk->dwAffectFlag3*/ 0, iDur, 0, !bAdded, pkSk->lMaxHit);
  2394.                         pkVictim->GetSectree()->ForEachAround(f);
  2395.                     }
  2396.                 }
  2397.  
  2398.                 bAdded = true;
  2399.             }
  2400.             else
  2401.             {
  2402.                 pkVictim->PointChange(pkSk->bPointOn3, iAmount3);
  2403.             }
  2404.         }
  2405.         // END_OF_ADD_GRANDMASTER_SKILL
  2406.  
  2407.         return BATTLE_NONE;
  2408.     }
  2409. }
  2410.  
  2411. bool CHARACTER::UseSkill(DWORD dwVnum, LPCHARACTER pkVictim, bool bUseGrandMaster)
  2412. {
  2413.     if (false == CanUseSkill(dwVnum))
  2414.         return false;
  2415.  
  2416.     // NO_GRANDMASTER
  2417.     if (test_server)
  2418.     {
  2419.         if (quest::CQuestManager::instance().GetEventFlag("no_grand_master"))
  2420.         {
  2421.             bUseGrandMaster = false;
  2422.         }
  2423.     }
  2424.     // END_OF_NO_GRANDMASTER
  2425.  
  2426.     if (g_bSkillDisable)
  2427.         return false;
  2428.  
  2429.     if (IsObserverMode())
  2430.         return false;
  2431.  
  2432.     if (!CanMove())
  2433.         return false;
  2434.  
  2435.     if (IsPolymorphed())
  2436.         return false;
  2437.  
  2438.     const bool bCanUseHorseSkill = CanUseHorseSkill();
  2439.  
  2440.  
  2441.     if (dwVnum == SKILL_HORSE_SUMMON)
  2442.     {
  2443.         if (GetSkillLevel(dwVnum) == 0)
  2444.             return false;
  2445.  
  2446.         if (GetHorseLevel() <= 0)
  2447.             ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"¸»ÀÌ ¾ø½À´Ï´Ù. ¸¶±Â°£ °æºñº´À» ã¾Æ°¡¼¼¿ä."));
  2448.         else
  2449.             ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"¸» ¼Òȯ ¾ÆÀÌÅÛÀ» »ç¿ëÇϼ¼¿ä."));
  2450.  
  2451.         return true;
  2452.     }
  2453.  
  2454.     // ¸»À» Ÿ°íÀÖÁö¸¸ ½ºÅ³Àº »ç¿ëÇÒ ¼ö ¾ø´Â »óŶó¸é return false
  2455.     if (false == bCanUseHorseSkill && true == IsRiding())
  2456.         return false;
  2457.  
  2458.     CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
  2459.     sys_log(0, "%s: USE_SKILL: %d pkVictim %p", GetName(), dwVnum, get_pointer(pkVictim));
  2460.  
  2461.     if (!pkSk)
  2462.         return false;
  2463.  
  2464.     if (bCanUseHorseSkill && pkSk->dwType != SKILL_TYPE_HORSE)
  2465.         return BATTLE_NONE;
  2466.  
  2467.     if (!bCanUseHorseSkill && pkSk->dwType == SKILL_TYPE_HORSE)
  2468.         return BATTLE_NONE;
  2469.  
  2470.     if (GetSkillLevel(dwVnum) == 0)
  2471.         return false;
  2472.    
  2473.  
  2474.     // NO_GRANDMASTER
  2475.     if (GetSkillMasterType(dwVnum) < SKILL_GRAND_MASTER)
  2476.         bUseGrandMaster = false;
  2477.     // END_OF_NO_GRANDMASTER
  2478.  
  2479.     // MINING
  2480.     if (GetWear(WEAR_WEAPON) && (GetWear(WEAR_WEAPON)->GetType() == ITEM_ROD || GetWear(WEAR_WEAPON)->GetType() == ITEM_PICK))
  2481.         return false;
  2482.     // END_OF_MINING
  2483.  
  2484.     m_SkillUseInfo[dwVnum].TargetVIDMap.clear();
  2485.  
  2486.     if (pkSk->IsChargeSkill())
  2487.     {
  2488.         if (IsAffectFlag(AFF_TANHWAN_DASH) || pkVictim && pkVictim != this)
  2489.         {
  2490.             if (!pkVictim)
  2491.                 return false;
  2492.  
  2493.             if (!IsAffectFlag(AFF_TANHWAN_DASH))
  2494.             {
  2495.                 if (!UseSkill(dwVnum, this))
  2496.                     return false;
  2497.             }
  2498.  
  2499.             m_SkillUseInfo[dwVnum].SetMainTargetVID(pkVictim->GetVID());
  2500.             // DASH »óÅÂÀÇ ÅºÈ¯°ÝÀº °ø°Ý±â¼ú
  2501.             ComputeSkill(dwVnum, pkVictim);
  2502.             RemoveAffect(dwVnum);
  2503.             return true;
  2504.         }
  2505.     }
  2506.  
  2507.     if (dwVnum == SKILL_COMBO)
  2508.     {
  2509.         if (m_bComboIndex)
  2510.             m_bComboIndex = 0;
  2511.         else
  2512.             m_bComboIndex = GetSkillLevel(SKILL_COMBO);
  2513.  
  2514.         ChatPacket(CHAT_TYPE_COMMAND, "combo %d", m_bComboIndex);
  2515.         return true;
  2516.     }
  2517.  
  2518.     // Toggle ÇÒ ¶§´Â SP¸¦ ¾²Áö ¾ÊÀ½ (SelfOnly·Î ±¸ºÐ)
  2519.     if ((0 != pkSk->dwAffectFlag || pkSk->dwVnum == SKILL_MUYEONG) && (pkSk->dwFlag & SKILL_FLAG_TOGGLE) && RemoveAffect(pkSk->dwVnum))
  2520.     {
  2521.         return true;
  2522.     }
  2523.  
  2524.     if (IsAffectFlag(AFF_REVIVE_INVISIBLE))
  2525.         RemoveAffect(AFFECT_REVIVE_INVISIBLE);
  2526.  
  2527.     const float k = 1.0 * GetSkillPower(pkSk->dwVnum) * pkSk->bMaxLevel / 100;
  2528.  
  2529.     pkSk->SetPointVar("k", k);
  2530.     pkSk->kSplashAroundDamageAdjustPoly.SetVar("k", k);
  2531.  
  2532.     // ÄðŸÀÓ Ã¼Å©
  2533.     pkSk->kCooldownPoly.SetVar("k", k);
  2534.     int iCooltime = (int) pkSk->kCooldownPoly.Eval();
  2535.     int lMaxHit = pkSk->lMaxHit ? pkSk->lMaxHit : -1;
  2536.  
  2537.     pkSk->SetSPCostVar("k", k);
  2538.  
  2539.     DWORD dwCur = get_dword_time();
  2540.  
  2541.     if (dwVnum == SKILL_TERROR && m_SkillUseInfo[dwVnum].bUsed && m_SkillUseInfo[dwVnum].dwNextSkillUsableTime > dwCur )
  2542.     {
  2543.         sys_log(0, " SKILL_TERROR's Cooltime is not delta over %u", m_SkillUseInfo[dwVnum].dwNextSkillUsableTime  - dwCur );
  2544.         return false;
  2545.     }
  2546.  
  2547.     int iNeededSP = 0;
  2548.  
  2549.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_USE_HP_AS_COST))
  2550.     {
  2551.         pkSk->SetSPCostVar("maxhp", GetMaxHP());
  2552.         pkSk->SetSPCostVar("v", GetHP());
  2553.         iNeededSP = (int) pkSk->kSPCostPoly.Eval();
  2554.  
  2555.         // ADD_GRANDMASTER_SKILL
  2556.         if (GetSkillMasterType(dwVnum) >= SKILL_GRAND_MASTER && bUseGrandMaster)
  2557.         {
  2558.             iNeededSP = (int) pkSk->kGrandMasterAddSPCostPoly.Eval();
  2559.         }
  2560.         // END_OF_ADD_GRANDMASTER_SKILL
  2561.  
  2562.         if (GetHP() < iNeededSP)
  2563.             return false;
  2564.  
  2565.         PointChange(POINT_HP, -iNeededSP);
  2566.     }
  2567.     else
  2568.     {
  2569.         // SKILL_FOMULA_REFACTORING
  2570.         pkSk->SetSPCostVar("maxhp", GetMaxHP());
  2571.         pkSk->SetSPCostVar("maxv", GetMaxSP());
  2572.         pkSk->SetSPCostVar("v", GetSP());
  2573.  
  2574.         iNeededSP = (int) pkSk->kSPCostPoly.Eval();
  2575.  
  2576.         if (GetSkillMasterType(dwVnum) >= SKILL_GRAND_MASTER && bUseGrandMaster)
  2577.         {
  2578.             iNeededSP = (int) pkSk->kGrandMasterAddSPCostPoly.Eval();
  2579.         }
  2580.         // END_OF_SKILL_FOMULA_REFACTORING
  2581.  
  2582.         if (GetSP() < iNeededSP)
  2583.             return false;
  2584.  
  2585.         if (test_server)
  2586.             ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s SP¼Ò¸ð: %d"), pkSk->szName, iNeededSP);
  2587.  
  2588.         PointChange(POINT_SP, -iNeededSP);
  2589.     }
  2590.  
  2591.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
  2592.         pkVictim = this;
  2593.  
  2594.     if (pkSk->dwVnum == SKILL_MUYEONG || pkSk->IsChargeSkill() && !IsAffectFlag(AFF_TANHWAN_DASH) && !pkVictim)
  2595.     {
  2596.         // óÀ½ »ç¿ëÇÏ´Â ¹«¿µÁøÀº Àڽſ¡°Ô Affect¸¦ ºÙÀδÙ.
  2597.         pkVictim = this;
  2598.     }
  2599.  
  2600.     int iSplashCount = 1;
  2601.  
  2602.     if (false == m_bDisableCooltime)
  2603.     {
  2604.         if (false ==
  2605.                 m_SkillUseInfo[dwVnum].UseSkill(
  2606.                     bUseGrandMaster,
  2607.                     (NULL != pkVictim && SKILL_HORSE_WILDATTACK != dwVnum) ? pkVictim->GetVID() : 0,
  2608.                     ComputeCooltime(iCooltime * 1000),
  2609.                     iSplashCount,
  2610.                     lMaxHit))
  2611.         {
  2612.             if (test_server)
  2613.                 ChatPacket(CHAT_TYPE_NOTICE, "cooltime not finished %s %d", pkSk->szName, iCooltime);
  2614.  
  2615.             return false;
  2616.         }
  2617.     }
  2618.  
  2619.     if (dwVnum == SKILL_CHAIN)
  2620.     {
  2621.         ResetChainLightningIndex();
  2622.         AddChainLightningExcept(pkVictim);
  2623.     }
  2624.    
  2625.  
  2626.     if (IS_SET(pkSk->dwFlag, SKILL_FLAG_SELFONLY))
  2627.         ComputeSkill(dwVnum, this);
  2628.     else if (!IS_SET(pkSk->dwFlag, SKILL_FLAG_ATTACK))
  2629.         ComputeSkill(dwVnum, pkVictim);
  2630.     else if (dwVnum == SKILL_BYEURAK)
  2631.         ComputeSkill(dwVnum, pkVictim);
  2632.     else if (dwVnum == SKILL_MUYEONG || pkSk->IsChargeSkill())
  2633.         ComputeSkill(dwVnum, pkVictim);
  2634.  
  2635.     m_dwLastSkillTime = get_dword_time();
  2636.  
  2637.     return true;
  2638. }
  2639.  
  2640. int CHARACTER::GetUsedSkillMasterType(DWORD dwVnum)
  2641. {
  2642.     const TSkillUseInfo& rInfo = m_SkillUseInfo[dwVnum];
  2643.  
  2644.     if (GetSkillMasterType(dwVnum) < SKILL_GRAND_MASTER)
  2645.         return GetSkillMasterType(dwVnum);
  2646.  
  2647.     if (rInfo.isGrandMaster)
  2648.         return GetSkillMasterType(dwVnum);
  2649.  
  2650.     return MIN(GetSkillMasterType(dwVnum), SKILL_MASTER);
  2651. }
  2652.  
  2653. int CHARACTER::GetSkillMasterType(DWORD dwVnum) const
  2654. {
  2655.     if (!IsPC())
  2656.         return 0;
  2657.  
  2658.     if (dwVnum >= SKILL_MAX_NUM)
  2659.     {
  2660.         sys_err("%s skill vnum overflow %u", GetName(), dwVnum);
  2661.         return 0;
  2662.     }
  2663.  
  2664.     return m_pSkillLevels ? m_pSkillLevels[dwVnum].bMasterType:SKILL_NORMAL;
  2665. }
  2666.  
  2667. int CHARACTER::GetSkillPower(DWORD dwVnum, BYTE bLevel) const
  2668. {
  2669.     // Àξî¹ÝÁö ¾ÆÀÌÅÛ
  2670.     if (dwVnum >= SKILL_LANGUAGE1 && dwVnum <= SKILL_LANGUAGE3 && IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
  2671.     {
  2672.         return 100;
  2673.     }
  2674.  
  2675.     if (dwVnum >= GUILD_SKILL_START && dwVnum <= GUILD_SKILL_END)
  2676.     {
  2677.         if (GetGuild())
  2678.             return 100 * GetGuild()->GetSkillLevel(dwVnum) / 7 / 7;
  2679.         else
  2680.             return 0;
  2681.     }
  2682.  
  2683.     if (bLevel)
  2684.     {
  2685.         //SKILL_POWER_BY_LEVEL
  2686.         return GetSkillPowerByLevel(bLevel, true);
  2687.         //END_SKILL_POWER_BY_LEVEL;
  2688.     }
  2689.  
  2690.     if (dwVnum >= SKILL_MAX_NUM)
  2691.     {
  2692.         sys_err("%s skill vnum overflow %u", GetName(), dwVnum);
  2693.         return 0;
  2694.     }
  2695.  
  2696.     //SKILL_POWER_BY_LEVEL
  2697.     return GetSkillPowerByLevel(GetSkillLevel(dwVnum));
  2698.     //SKILL_POWER_BY_LEVEL
  2699. }
  2700.  
  2701. int CHARACTER::GetSkillLevel(DWORD dwVnum) const
  2702. {
  2703.     if (dwVnum >= SKILL_MAX_NUM)
  2704.     {
  2705.         sys_err("%s skill vnum overflow %u", GetName(), dwVnum);
  2706.         sys_log(0, "%s skill vnum overflow %u", GetName(), dwVnum);
  2707.         return 0;
  2708.     }
  2709.  
  2710.     return MIN(SKILL_MAX_LEVEL, m_pSkillLevels ? m_pSkillLevels[dwVnum].bLevel : 0);
  2711. }
  2712.  
  2713. EVENTFUNC(skill_muyoung_event)
  2714. {
  2715.     char_event_info* info = dynamic_cast<char_event_info*>( event->info );
  2716.  
  2717.     if ( info == NULL )
  2718.     {
  2719.         sys_err( "skill_muyoung_event> <Factor> Null pointer" );
  2720.         return 0;
  2721.     }
  2722.  
  2723.     LPCHARACTER ch = info->ch;
  2724.  
  2725.     if (ch == NULL) { // <Factor>
  2726.         return 0;
  2727.     }
  2728.  
  2729.     if (!ch->IsAffectFlag(AFF_MUYEONG))
  2730.     {
  2731.         ch->StopMuyeongEvent();
  2732.         return 0;
  2733.     }
  2734.  
  2735.     // 1. Find Victim
  2736.     FFindNearVictim f(ch, ch);
  2737.     if (ch->GetSectree())
  2738.     {
  2739.         ch->GetSectree()->ForEachAround(f);
  2740.         // 2. Shoot!
  2741.         if (f.GetVictim())
  2742.         {
  2743.             ch->CreateFly(FLY_SKILL_MUYEONG, f.GetVictim());
  2744.             ch->ComputeSkill(SKILL_MUYEONG, f.GetVictim());
  2745.         }
  2746.     }
  2747.  
  2748.     return PASSES_PER_SEC(3);
  2749. }
  2750.  
  2751. void CHARACTER::StartMuyeongEvent()
  2752. {
  2753.     if (m_pkMuyeongEvent)
  2754.         return;
  2755.  
  2756.     char_event_info* info = AllocEventInfo<char_event_info>();
  2757.  
  2758.     info->ch = this;
  2759.     m_pkMuyeongEvent = event_create(skill_muyoung_event, info, PASSES_PER_SEC(1));
  2760. }
  2761.  
  2762. void CHARACTER::StopMuyeongEvent()
  2763. {
  2764.     event_cancel(&m_pkMuyeongEvent);
  2765. }
  2766.  
  2767. void CHARACTER::SkillLearnWaitMoreTimeMessage(DWORD ms)
  2768. {
  2769.     //const char* str = "";
  2770.     //
  2771.     if (ms < 3 * 60)
  2772.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("¸ö ¼ÓÀÌ ¶ß°Ì±º. ÇÏÁö¸¸ ¾ÆÁÖ Æí¾ÈÇØ. ÀÌ´ë·Î ±â¸¦ ¾ÈÁ¤½ÃÅ°ÀÚ."));
  2773.     else if (ms < 5 * 60)
  2774.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("±×·¡, õõÈ÷. Á»´õ õõÈ÷, ±×·¯³ª ¸·Èû ¾øÀÌ ºü¸£°Ô!"));
  2775.     else if (ms < 10 * 60) // 10ºÐ
  2776.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("±×·¡, ÀÌ ´À³¦À̾ß. ü³»¿¡ ±â°¡ ¾ÆÁÖ Ã游ÇØ."));
  2777.     else if (ms < 30 * 60) // 30ºÐ
  2778.     {
  2779.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("´Ù Àоú´Ù! ÀÌÁ¦ ºñ±Þ¿¡ ÀûÇôÀÖ´Â ´ë·Î Àü½Å¿¡ ±â¸¦ µ¹¸®±â¸¸ Çϸé,"));
  2780.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("±×°ÍÀ¸·Î ¼ö·ÃÀº ³¡³­ °Å¾ß!"));
  2781.     }
  2782.     else if (ms < 1 * 3600) // 1½Ã°£
  2783.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("ÀÌÁ¦ Ã¥ÀÇ ¸¶Áö¸· ÀåÀ̾ß! ¼ö·ÃÀÇ ³¡ÀÌ ´«¿¡ º¸ÀÌ°í ÀÖ¾î!"));
  2784.     else if (ms < 2 * 3600) // 2½Ã°£
  2785.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("¾ó¸¶ ¾È ³²¾Ò¾î! Á¶±Ý¸¸ ´õ!"));
  2786.     else if (ms < 3 * 3600)
  2787.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("ÁÁ¾Ò¾î! Á¶±Ý¸¸ ´õ ÀÐÀ¸¸é ³¡ÀÌ´Ù!"));
  2788.     else if (ms < 6 * 3600)
  2789.     {
  2790.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("Ã¥Àåµµ ÀÌÁ¦ ¾ó¸¶ ³²Áö ¾Ê¾Ò±º."));
  2791.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("¹º°¡ ¸ö ¾È¿¡ ÈûÀÌ »ý±â´Â ±âºÐÀÎ °É."));
  2792.     }
  2793.     else if (ms < 12 * 3600)
  2794.     {
  2795.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("ÀÌÁ¦ Á» ½½½½ °¡´ÚÀÌ ÀâÈ÷´Â °Í °°Àºµ¥."));
  2796.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("ÁÁ¾Æ, ÀÌ ±â¼¼·Î °è¼Ó ³ª°£´Ù!"));
  2797.     }
  2798.     else if (ms < 18 * 3600)
  2799.     {
  2800.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("¾Æ´Ï ¾î¶»°Ô µÈ °Ô Á¾ÀÏ Àо ¸Ó¸®¿¡ ¾È µé¾î¿À³Ä."));
  2801.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("°øºÎÇϱ⠽ȾîÁö³×."));
  2802.     }
  2803.     else //if (ms < 2 * 86400)
  2804.     {
  2805.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("»ý°¢¸¸Å­ ÀбⰡ ½±Áö°¡ ¾Ê±º. ÀÌÇصµ ¾î·Æ°í ³»¿ëµµ ³­ÇØÇØ."));
  2806.         ChatPacket(CHAT_TYPE_TALKING, "%s", LC_TEXT("ÀÌ·¡¼­¾ß °øºÎ°¡ ¾ÈµÈ´Ù±¸."));
  2807.     }
  2808.     /*
  2809.        str = "30%";
  2810.        else if (ms < 3 * 86400)
  2811.        str = "10%";
  2812.        else if (ms < 4 * 86400)
  2813.        str = "5%";
  2814.        else
  2815.        str = "0%";*/
  2816.  
  2817.     //ChatPacket(CHAT_TYPE_TALKING, "%s", str);
  2818. }
  2819.  
  2820. void CHARACTER::DisableCooltime()
  2821. {
  2822.     m_bDisableCooltime = true;
  2823. }
  2824.  
  2825. bool CHARACTER::HasMobSkill() const
  2826. {
  2827.     return CountMobSkill() > 0;
  2828. }
  2829.  
  2830. size_t CHARACTER::CountMobSkill() const
  2831. {
  2832.     if (!m_pkMobData)
  2833.         return 0;
  2834.  
  2835.     size_t c = 0;
  2836.  
  2837.     for (size_t i = 0; i < MOB_SKILL_MAX_NUM; ++i)
  2838.         if (m_pkMobData->m_table.Skills[i].dwVnum)
  2839.             ++c;
  2840.  
  2841.     return c;
  2842. }
  2843.  
  2844. const TMobSkillInfo* CHARACTER::GetMobSkill(unsigned int idx) const
  2845. {
  2846.     if (idx >= MOB_SKILL_MAX_NUM)
  2847.         return NULL;
  2848.  
  2849.     if (!m_pkMobData)
  2850.         return NULL;
  2851.  
  2852.     if (0 == m_pkMobData->m_table.Skills[idx].dwVnum)
  2853.         return NULL;
  2854.  
  2855.     return &m_pkMobData->m_mobSkillInfo[idx];
  2856. }
  2857.  
  2858. bool CHARACTER::CanUseMobSkill(unsigned int idx) const
  2859. {
  2860.     const TMobSkillInfo* pInfo = GetMobSkill(idx);
  2861.  
  2862.     if (!pInfo)
  2863.         return false;
  2864.  
  2865.     if (m_adwMobSkillCooltime[idx] > get_dword_time())
  2866.         return false;
  2867.  
  2868.     if (number(0, 1))
  2869.         return false;
  2870.  
  2871.     return true;
  2872. }
  2873.  
  2874. EVENTINFO(mob_skill_event_info)
  2875. {
  2876.     DynamicCharacterPtr ch;
  2877.     PIXEL_POSITION pos;
  2878.     DWORD vnum;
  2879.     int index;
  2880.     BYTE level;
  2881.  
  2882.     mob_skill_event_info()
  2883.     : ch()
  2884.     , pos()
  2885.     , vnum(0)
  2886.     , index(0)
  2887.     , level(0)
  2888.     {
  2889.     }
  2890. };
  2891.  
  2892. EVENTFUNC(mob_skill_hit_event)
  2893. {
  2894.     mob_skill_event_info * info = dynamic_cast<mob_skill_event_info *>( event->info );
  2895.  
  2896.     if ( info == NULL )
  2897.     {
  2898.         sys_err( "mob_skill_event_info> <Factor> Null pointer" );
  2899.         return 0;
  2900.     }
  2901.  
  2902.     // <Factor>
  2903.     LPCHARACTER ch = info->ch;
  2904.     if (ch == NULL) {
  2905.         return 0;
  2906.     }
  2907.  
  2908.     ch->ComputeSkillAtPosition(info->vnum, info->pos, info->level);
  2909.     ch->m_mapMobSkillEvent.erase(info->index);
  2910.  
  2911.     return 0;
  2912. }
  2913.  
  2914. bool CHARACTER::UseMobSkill(unsigned int idx)
  2915. {
  2916.     if (IsPC())
  2917.         return false;
  2918.  
  2919.     const TMobSkillInfo* pInfo = GetMobSkill(idx);
  2920.  
  2921.     if (!pInfo)
  2922.         return false;
  2923.  
  2924.     DWORD dwVnum = pInfo->dwSkillVnum;
  2925.     CSkillProto * pkSk = CSkillManager::instance().Get(dwVnum);
  2926.  
  2927.     if (!pkSk)
  2928.         return false;
  2929.  
  2930.     const float k = 1.0 * GetSkillPower(pkSk->dwVnum, pInfo->bSkillLevel) * pkSk->bMaxLevel / 100;
  2931.  
  2932.     pkSk->kCooldownPoly.SetVar("k", k);
  2933.     int iCooltime = (int) (pkSk->kCooldownPoly.Eval() * 1000);
  2934.  
  2935.     m_adwMobSkillCooltime[idx] = get_dword_time() + iCooltime;
  2936.  
  2937.     sys_log(0, "USE_MOB_SKILL: %s idx %d vnum %u cooltime %d", GetName(), idx, dwVnum, iCooltime);
  2938.  
  2939.     if (m_pkMobData->m_mobSkillInfo[idx].vecSplashAttack.empty())
  2940.     {
  2941.         sys_err("No skill hit data for mob %s index %d", GetName(), idx);
  2942.         return false;
  2943.     }
  2944.  
  2945.     for (size_t i = 0; i < m_pkMobData->m_mobSkillInfo[idx].vecSplashAttack.size(); i++)
  2946.     {
  2947.         PIXEL_POSITION pos = GetXYZ();
  2948.         const TMobSplashAttackInfo& rInfo = m_pkMobData->m_mobSkillInfo[idx].vecSplashAttack[i];
  2949.  
  2950.         if (rInfo.dwHitDistance)
  2951.         {
  2952.             float fx, fy;
  2953.             GetDeltaByDegree(GetRotation(), rInfo.dwHitDistance, &fx, &fy);
  2954.             pos.x += (long) fx;
  2955.             pos.y += (long) fy;
  2956.         }
  2957.  
  2958.         if (rInfo.dwTiming)
  2959.         {
  2960.             if (test_server)
  2961.                 sys_log(0, "               timing %ums", rInfo.dwTiming);
  2962.  
  2963.             mob_skill_event_info* info = AllocEventInfo<mob_skill_event_info>();
  2964.  
  2965.             info->ch = this;
  2966.             info->pos = pos;
  2967.             info->level = pInfo->bSkillLevel;
  2968.             info->vnum = dwVnum;
  2969.             info->index = i;
  2970.  
  2971.             // <Factor> Cancel existing event first
  2972.             auto it = m_mapMobSkillEvent.find(i);
  2973.             if (it != m_mapMobSkillEvent.end()) {
  2974.                 LPEVENT existing = it->second;
  2975.                 event_cancel(&existing);
  2976.                 m_mapMobSkillEvent.erase(it);
  2977.             }
  2978.  
  2979.             m_mapMobSkillEvent.insert(std::make_pair(i, event_create(mob_skill_hit_event, info, PASSES_PER_SEC(rInfo.dwTiming) / 1000)));
  2980.         }
  2981.         else
  2982.         {
  2983.             ComputeSkillAtPosition(dwVnum, pos, pInfo->bSkillLevel);
  2984.         }
  2985.     }
  2986.  
  2987.     return true;
  2988. }
  2989.  
  2990. void CHARACTER::ResetMobSkillCooltime()
  2991. {
  2992.     memset(m_adwMobSkillCooltime, 0, sizeof(m_adwMobSkillCooltime));
  2993. }
  2994.  
  2995. bool CHARACTER::IsUsableSkillMotion(DWORD dwMotionIndex) const
  2996. {
  2997.     DWORD selfJobGroup = (GetJob()+1) * 10 + GetSkillGroup();
  2998.  
  2999.     const DWORD SKILL_NUM = 158;
  3000.     static DWORD s_anSkill2JobGroup[SKILL_NUM] = {
  3001.         0, // common_skill 0
  3002.         11, // job_skill 1
  3003.         11, // job_skill 2
  3004.         11, // job_skill 3
  3005.         11, // job_skill 4
  3006.         11, // job_skill 5
  3007.         11, // job_skill 6
  3008.         0, // common_skill 7
  3009.         0, // common_skill 8
  3010.         0, // common_skill 9
  3011.         0, // common_skill 10
  3012.         0, // common_skill 11
  3013.         0, // common_skill 12
  3014.         0, // common_skill 13
  3015.         0, // common_skill 14
  3016.         0, // common_skill 15
  3017.         12, // job_skill 16
  3018.         12, // job_skill 17
  3019.         12, // job_skill 18
  3020.         12, // job_skill 19
  3021.         12, // job_skill 20
  3022.         12, // job_skill 21
  3023.         0, // common_skill 22
  3024.         0, // common_skill 23
  3025.         0, // common_skill 24
  3026.         0, // common_skill 25
  3027.         0, // common_skill 26
  3028.         0, // common_skill 27
  3029.         0, // common_skill 28
  3030.         0, // common_skill 29
  3031.         0, // common_skill 30
  3032.         21, // job_skill 31
  3033.         21, // job_skill 32
  3034.         21, // job_skill 33
  3035.         21, // job_skill 34
  3036.         21, // job_skill 35
  3037.         21, // job_skill 36
  3038.         0, // common_skill 37
  3039.         0, // common_skill 38
  3040.         0, // common_skill 39
  3041.         0, // common_skill 40
  3042.         0, // common_skill 41
  3043.         0, // common_skill 42
  3044.         0, // common_skill 43
  3045.         0, // common_skill 44
  3046.         0, // common_skill 45
  3047.         22, // job_skill 46
  3048.         22, // job_skill 47
  3049.         22, // job_skill 48
  3050.         22, // job_skill 49
  3051.         22, // job_skill 50
  3052.         22, // job_skill 51
  3053.         0, // common_skill 52
  3054.         0, // common_skill 53
  3055.         0, // common_skill 54
  3056.         0, // common_skill 55
  3057.         0, // common_skill 56
  3058.         0, // common_skill 57
  3059.         0, // common_skill 58
  3060.         0, // common_skill 59
  3061.         0, // common_skill 60
  3062.         31, // job_skill 61
  3063.         31, // job_skill 62
  3064.         31, // job_skill 63
  3065.         31, // job_skill 64
  3066.         31, // job_skill 65
  3067.         31, // job_skill 66
  3068.         0, // common_skill 67
  3069.         0, // common_skill 68
  3070.         0, // common_skill 69
  3071.         0, // common_skill 70
  3072.         0, // common_skill 71
  3073.         0, // common_skill 72
  3074.         0, // common_skill 73
  3075.         0, // common_skill 74
  3076.         0, // common_skill 75
  3077.         32, // job_skill 76
  3078.         32, // job_skill 77
  3079.         32, // job_skill 78
  3080.         32, // job_skill 79
  3081.         32, // job_skill 80
  3082.         32, // job_skill 81
  3083.         0, // common_skill 82
  3084.         0, // common_skill 83
  3085.         0, // common_skill 84
  3086.         0, // common_skill 85
  3087.         0, // common_skill 86
  3088.         0, // common_skill 87
  3089.         0, // common_skill 88
  3090.         0, // common_skill 89
  3091.         0, // common_skill 90
  3092.         41, // job_skill 91
  3093.         41, // job_skill 92
  3094.         41, // job_skill 93
  3095.         41, // job_skill 94
  3096.         41, // job_skill 95
  3097.         41, // job_skill 96
  3098.         0, // common_skill 97
  3099.         0, // common_skill 98
  3100.         0, // common_skill 99
  3101.         0, // common_skill 100
  3102.         0, // common_skill 101
  3103.         0, // common_skill 102
  3104.         0, // common_skill 103
  3105.         0, // common_skill 104
  3106.         0, // common_skill 105
  3107.         42, // job_skill 106
  3108.         42, // job_skill 107
  3109.         42, // job_skill 108
  3110.         42, // job_skill 109
  3111.         42, // job_skill 110
  3112.         42, // job_skill 111
  3113.         0, // common_skill 112
  3114.         0, // common_skill 113
  3115.         0, // common_skill 114
  3116.         0, // common_skill 115
  3117.         0, // common_skill 116
  3118.         0, // common_skill 117
  3119.         0, // common_skill 118
  3120.         0, // common_skill 119
  3121.         0, // common_skill 120
  3122.         0, // common_skill 121
  3123.         0, // common_skill 122
  3124.         0, // common_skill 123
  3125.         0, // common_skill 124
  3126.         0, // common_skill 125
  3127.         0, // common_skill 126
  3128.         0, // common_skill 127
  3129.         0, // common_skill 128
  3130.         0, // common_skill 129
  3131.         0, // common_skill 130
  3132.         0, // common_skill 131
  3133.         0, // common_skill 132
  3134.         0, // common_skill 133
  3135.         0, // common_skill 134
  3136.         0, // common_skill 135
  3137.         0, // common_skill 136
  3138.         0, // job_skill 137
  3139.         0, // job_skill 138
  3140.         0, // job_skill 139
  3141.         0, // job_skill 140
  3142.         0, // common_skill 141
  3143.         0, // common_skill 142
  3144.         0, // common_skill 143
  3145.         0, // common_skill 144
  3146.         0, // common_skill 145
  3147.         0, // common_skill 146
  3148.         0, // common_skill 147
  3149.         0, // common_skill 148
  3150.         0, // common_skill 149
  3151.         0, // common_skill 150
  3152.         0, // common_skill 151
  3153.         0, // job_skill 152
  3154.         0, // job_skill 153
  3155.         0, // job_skill 154
  3156.         0, // job_skill 155
  3157.         0, // job_skill 156
  3158.         0, // job_skill 157
  3159.     }; // s_anSkill2JobGroup
  3160.  
  3161.     const DWORD MOTION_MAX_NUM  = 124;
  3162.     const DWORD SKILL_LIST_MAX_COUNT    = 5;
  3163.  
  3164.     static DWORD s_anMotion2SkillVnumList[MOTION_MAX_NUM][SKILL_LIST_MAX_COUNT] =
  3165.     {
  3166.         // ½ºÅ³¼ö   ¹«»ç½ºÅ³ID  ÀÚ°´½ºÅ³ID  ¼ö¶ó½ºÅ³ID  ¹«´ç½ºÅ³ID
  3167.         {   0,      0,          0,          0,          0       }, //  0
  3168.  
  3169.         // 1¹ø Á÷±º ±âº» ½ºÅ³
  3170.         {   4,      1,          31,         61,         91      }, //  1
  3171.         {   4,      2,          32,         62,         92      }, //  2
  3172.         {   4,      3,          33,         63,         93      }, //  3
  3173.         {   4,      4,          34,         64,         94      }, //  4
  3174.         {   4,      5,          35,         65,         95      }, //  5
  3175.         {   4,      6,          36,         66,         96      }, //  6
  3176.         {   0,      0,          0,          0,          0       }, //  7
  3177.         {   0,      0,          0,          0,          0       }, //  8
  3178.         // 1¹ø Á÷±º ±âº» ½ºÅ³ ³¡
  3179.  
  3180.         // ¿©À¯ºÐ
  3181.         {   0,      0,          0,          0,          0       }, //  9
  3182.         {   0,      0,          0,          0,          0       }, //  10
  3183.         {   0,      0,          0,          0,          0       }, //  11
  3184.         {   0,      0,          0,          0,          0       }, //  12
  3185.         {   0,      0,          0,          0,          0       }, //  13
  3186.         {   0,      0,          0,          0,          0       }, //  14
  3187.         {   0,      0,          0,          0,          0       }, //  15
  3188.         // ¿©À¯ºÐ ³¡
  3189.  
  3190.         // 2¹ø Á÷±º ±âº» ½ºÅ³
  3191.         {   4,      16,         46,         76,         106     }, //  16
  3192.         {   4,      17,         47,         77,         107     }, //  17
  3193.         {   4,      18,         48,         78,         108     }, //  18
  3194.         {   4,      19,         49,         79,         109     }, //  19
  3195.         {   4,      20,         50,         80,         110     }, //  20
  3196.         {   4,      21,         51,         81,         111     }, //  21
  3197.         {   0,      0,          0,          0,          0       }, //  22
  3198.         {   0,      0,          0,          0,          0       }, //  23
  3199.         // 2¹ø Á÷±º ±âº» ½ºÅ³ ³¡
  3200.  
  3201.         // ¿©À¯ºÐ
  3202.         {   0,      0,          0,          0,          0       }, //  24
  3203.         {   0,      0,          0,          0,          0       }, //  25
  3204.         // ¿©À¯ºÐ ³¡
  3205.  
  3206.         // 1¹ø Á÷±º ¸¶½ºÅÍ ½ºÅ³
  3207.         {   4,      1,          31,         61,         91      }, //  26
  3208.         {   4,      2,          32,         62,         92      }, //  27
  3209.         {   4,      3,          33,         63,         93      }, //  28
  3210.         {   4,      4,          34,         64,         94      }, //  29
  3211.         {   4,      5,          35,         65,         95      }, //  30
  3212.         {   4,      6,          36,         66,         96      }, //  31
  3213.         {   0,      0,          0,          0,          0       }, //  32
  3214.         {   0,      0,          0,          0,          0       }, //  33
  3215.         // 1¹ø Á÷±º ¸¶½ºÅÍ ½ºÅ³ ³¡
  3216.  
  3217.         // ¿©À¯ºÐ
  3218.         {   0,      0,          0,          0,          0       }, //  34
  3219.         {   0,      0,          0,          0,          0       }, //  35
  3220.         {   0,      0,          0,          0,          0       }, //  36
  3221.         {   0,      0,          0,          0,          0       }, //  37
  3222.         {   0,      0,          0,          0,          0       }, //  38
  3223.         {   0,      0,          0,          0,          0       }, //  39
  3224.         {   0,      0,          0,          0,          0       }, //  40
  3225.         // ¿©À¯ºÐ ³¡
  3226.  
  3227.         // 2¹ø Á÷±º ¸¶½ºÅÍ ½ºÅ³
  3228.         {   4,      16,         46,         76,         106     }, //  41
  3229.         {   4,      17,         47,         77,         107     }, //  42
  3230.         {   4,      18,         48,         78,         108     }, //  43
  3231.         {   4,      19,         49,         79,         109     }, //  44
  3232.         {   4,      20,         50,         80,         110     }, //  45
  3233.         {   4,      21,         51,         81,         111     }, //  46
  3234.         {   0,      0,          0,          0,          0       }, //  47
  3235.         {   0,      0,          0,          0,          0       }, //  48
  3236.         // 2¹ø Á÷±º ¸¶½ºÅÍ ½ºÅ³ ³¡
  3237.  
  3238.         // ¿©À¯ºÐ
  3239.         {   0,      0,          0,          0,          0       }, //  49
  3240.         {   0,      0,          0,          0,          0       }, //  50
  3241.         // ¿©À¯ºÐ ³¡
  3242.  
  3243.         // 1¹ø Á÷±º ±×·£µå ¸¶½ºÅÍ ½ºÅ³
  3244.         {   4,      1,          31,         61,         91      }, //  51
  3245.         {   4,      2,          32,         62,         92      }, //  52
  3246.         {   4,      3,          33,         63,         93      }, //  53
  3247.         {   4,      4,          34,         64,         94      }, //  54
  3248.         {   4,      5,          35,         65,         95      }, //  55
  3249.         {   4,      6,          36,         66,         96      }, //  56
  3250.         {   0,      0,          0,          0,          0       }, //  57
  3251.         {   0,      0,          0,          0,          0       }, //  58
  3252.         // 1¹ø Á÷±º ±×·£µå ¸¶½ºÅÍ ½ºÅ³ ³¡
  3253.  
  3254.         // ¿©À¯ºÐ
  3255.         {   0,      0,          0,          0,          0       }, //  59
  3256.         {   0,      0,          0,          0,          0       }, //  60
  3257.         {   0,      0,          0,          0,          0       }, //  61
  3258.         {   0,      0,          0,          0,          0       }, //  62
  3259.         {   0,      0,          0,          0,          0       }, //  63
  3260.         {   0,      0,          0,          0,          0       }, //  64
  3261.         {   0,      0,          0,          0,          0       }, //  65
  3262.         // ¿©À¯ºÐ ³¡
  3263.  
  3264.         // 2¹ø Á÷±º ±×·£µå ¸¶½ºÅÍ ½ºÅ³
  3265.         {   4,      16,         46,         76,         106     }, //  66
  3266.         {   4,      17,         47,         77,         107     }, //  67
  3267.         {   4,      18,         48,         78,         108     }, //  68
  3268.         {   4,      19,         49,         79,         109     }, //  69
  3269.         {   4,      20,         50,         80,         110     }, //  70
  3270.         {   4,      21,         51,         81,         111     }, //  71
  3271.         {   0,      0,          0,          0,          0       }, //  72
  3272.         {   0,      0,          0,          0,          0       }, //  73
  3273.         // 2¹ø Á÷±º ±×·£µå ¸¶½ºÅÍ ½ºÅ³ ³¡
  3274.  
  3275.         //¿©À¯ºÐ
  3276.         {   0,      0,          0,          0,          0       }, //  74
  3277.         {   0,      0,          0,          0,          0       }, //  75
  3278.         // ¿©À¯ºÐ ³¡
  3279.  
  3280.         // 1¹ø Á÷±º ÆÛÆåÆ® ¸¶½ºÅÍ ½ºÅ³
  3281.         {   4,      1,          31,         61,         91      }, //  76
  3282.         {   4,      2,          32,         62,         92      }, //  77
  3283.         {   4,      3,          33,         63,         93      }, //  78
  3284.         {   4,      4,          34,         64,         94      }, //  79
  3285.         {   4,      5,          35,         65,         95      }, //  80
  3286.         {   4,      6,          36,         66,         96      }, //  81
  3287.         {   0,      0,          0,          0,          0       }, //  82
  3288.         {   0,      0,          0,          0,          0       }, //  83
  3289.         // 1¹ø Á÷±º ÆÛÆåÆ® ¸¶½ºÅÍ ½ºÅ³ ³¡
  3290.  
  3291.         // ¿©À¯ºÐ
  3292.         {   0,      0,          0,          0,          0       }, //  84
  3293.         {   0,      0,          0,          0,          0       }, //  85
  3294.         {   0,      0,          0,          0,          0       }, //  86
  3295.         {   0,      0,          0,          0,          0       }, //  87
  3296.         {   0,      0,          0,          0,          0       }, //  88
  3297.         {   0,      0,          0,          0,          0       }, //  89
  3298.         {   0,      0,          0,          0,          0       }, //  90
  3299.         // ¿©À¯ºÐ ³¡
  3300.  
  3301.         // 2¹ø Á÷±º ÆÛÆåÆ® ¸¶½ºÅÍ ½ºÅ³
  3302.         {   4,      16,         46,         76,         106     }, //  91
  3303.         {   4,      17,         47,         77,         107     }, //  92
  3304.         {   4,      18,         48,         78,         108     }, //  93
  3305.         {   4,      19,         49,         79,         109     }, //  94
  3306.         {   4,      20,         50,         80,         110     }, //  95
  3307.         {   4,      21,         51,         81,         111     }, //  96
  3308.         {   0,      0,          0,          0,          0       }, //  97
  3309.         {   0,      0,          0,          0,          0       }, //  98
  3310.         // 2¹ø Á÷±º ÆÛÆåÆ® ¸¶½ºÅÍ ½ºÅ³ ³¡
  3311.  
  3312.         // ¿©À¯ºÐ
  3313.         {   0,      0,          0,          0,          0       }, //  99
  3314.         {   0,      0,          0,          0,          0       }, //  100
  3315.         // ¿©À¯ºÐ ³¡
  3316.  
  3317.         // ±æµå ½ºÅ³
  3318.         {   1,  152,    0,    0,    0}, //  101
  3319.         {   1,  153,    0,    0,    0}, //  102
  3320.         {   1,  154,    0,    0,    0}, //  103
  3321.         {   1,  155,    0,    0,    0}, //  104
  3322.         {   1,  156,    0,    0,    0}, //  105
  3323.         {   1,  157,    0,    0,    0}, //  106
  3324.         // ±æµå ½ºÅ³ ³¡
  3325.  
  3326.         // ¿©À¯ºÐ
  3327.         {   0,    0,    0,    0,    0}, //  107
  3328.         {   0,    0,    0,    0,    0}, //  108
  3329.         {   0,    0,    0,    0,    0}, //  109
  3330.         {   0,    0,    0,    0,    0}, //  110
  3331.         {   0,    0,    0,    0,    0}, //  111
  3332.         {   0,    0,    0,    0,    0}, //  112
  3333.         {   0,    0,    0,    0,    0}, //  113
  3334.         {   0,    0,    0,    0,    0}, //  114
  3335.         {   0,    0,    0,    0,    0}, //  115
  3336.         {   0,    0,    0,    0,    0}, //  116
  3337.         {   0,    0,    0,    0,    0}, //  117
  3338.         {   0,    0,    0,    0,    0}, //  118
  3339.         {   0,    0,    0,    0,    0}, //  119
  3340.         {   0,    0,    0,    0,    0}, //  120
  3341.         // ¿©À¯ºÐ ³¡
  3342.  
  3343.         // ½Â¸¶ ½ºÅ³
  3344.         {   2,  137,  140,    0,    0}, //  121
  3345.         {   1,  138,    0,    0,    0}, //  122
  3346.         {   1,  139,    0,    0,    0}, //  123
  3347.         // ½Â¸¶ ½ºÅ³ ³¡
  3348.     };
  3349.  
  3350.     if (dwMotionIndex >= MOTION_MAX_NUM)
  3351.     {
  3352.         sys_err("OUT_OF_MOTION_VNUM: name=%s, motion=%d/%d", GetName(), dwMotionIndex, MOTION_MAX_NUM);
  3353.         return false;
  3354.     }
  3355.  
  3356.     DWORD* skillVNums = s_anMotion2SkillVnumList[dwMotionIndex];
  3357.  
  3358.     DWORD skillCount = *skillVNums++;
  3359.     if (skillCount >= SKILL_LIST_MAX_COUNT)
  3360.     {
  3361.         sys_err("OUT_OF_SKILL_LIST: name=%s, count=%d/%d", GetName(), skillCount, SKILL_LIST_MAX_COUNT);
  3362.         return false;
  3363.     }
  3364.  
  3365.     for (DWORD skillIndex = 0; skillIndex != skillCount; ++skillIndex)
  3366.     {
  3367.         if (skillIndex >= SKILL_MAX_NUM)
  3368.         {
  3369.             sys_err("OUT_OF_SKILL_VNUM: name=%s, skill=%d/%d", GetName(), skillIndex, SKILL_MAX_NUM);
  3370.             return false;
  3371.         }
  3372.  
  3373.         DWORD eachSkillVNum = skillVNums[skillIndex];
  3374.         if ( eachSkillVNum != 0 )
  3375.         {
  3376.             DWORD eachJobGroup = s_anSkill2JobGroup[eachSkillVNum];
  3377.  
  3378.             if (0 == eachJobGroup || eachJobGroup == selfJobGroup)
  3379.             {
  3380.                 // GUILDSKILL_BUG_FIX
  3381.                 DWORD eachSkillLevel = 0;
  3382.  
  3383.                 if (eachSkillVNum >= GUILD_SKILL_START && eachSkillVNum <= GUILD_SKILL_END)
  3384.                 {
  3385.                     if (GetGuild())
  3386.                         eachSkillLevel = GetGuild()->GetSkillLevel(eachSkillVNum);
  3387.                     else
  3388.                         eachSkillLevel = 0;
  3389.                 }
  3390.                 else
  3391.                 {
  3392.                     eachSkillLevel = GetSkillLevel(eachSkillVNum);
  3393.                 }
  3394.  
  3395.                 if (eachSkillLevel > 0)
  3396.                 {
  3397.                     return true;
  3398.                 }
  3399.                 // END_OF_GUILDSKILL_BUG_FIX
  3400.             }
  3401.         }
  3402.     }
  3403.  
  3404.     return false;
  3405. }
  3406.  
  3407. void CHARACTER::ClearSkill()
  3408. {
  3409.     PointChange(POINT_SKILL, 4 + (GetLevel() - 5) - GetPoint(POINT_SKILL));
  3410.  
  3411.     ResetSkill();
  3412. }
  3413.  
  3414. void CHARACTER::ClearSubSkill()
  3415. {
  3416.     PointChange(POINT_SUB_SKILL, GetLevel() < 10 ? 0 : (GetLevel() - 9) - GetPoint(POINT_SUB_SKILL));
  3417.  
  3418.     if (m_pSkillLevels == NULL)
  3419.     {
  3420.         sys_err("m_pSkillLevels nil (name: %s)", GetName());
  3421.         return;
  3422.     }
  3423.  
  3424.     TPlayerSkill CleanSkill;
  3425.     memset(&CleanSkill, 0, sizeof(TPlayerSkill));
  3426.  
  3427.     size_t count = sizeof(s_adwSubSkillVnums) / sizeof(s_adwSubSkillVnums[0]);
  3428.  
  3429.     for (size_t i = 0; i < count; ++i)
  3430.     {
  3431.         if (s_adwSubSkillVnums[i] >= SKILL_MAX_NUM)
  3432.             continue;
  3433.  
  3434.         m_pSkillLevels[s_adwSubSkillVnums[i]] = CleanSkill;
  3435.     }
  3436.  
  3437.     ComputePoints();
  3438.     SkillLevelPacket();
  3439. }
  3440.  
  3441. bool CHARACTER::ResetOneSkill(DWORD dwVnum)
  3442. {
  3443.     if (NULL == m_pSkillLevels)
  3444.     {
  3445.         sys_err("m_pSkillLevels nil (name %s, vnum %u)", GetName(), dwVnum);
  3446.         return false;
  3447.     }
  3448.  
  3449.     if (dwVnum >= SKILL_MAX_NUM)
  3450.     {
  3451.         sys_err("vnum overflow (name %s, vnum %u)", GetName(), dwVnum);
  3452.         return false;
  3453.     }
  3454.  
  3455.     BYTE level = m_pSkillLevels[dwVnum].bLevel;
  3456.  
  3457.     m_pSkillLevels[dwVnum].bLevel = 0;
  3458.     m_pSkillLevels[dwVnum].bMasterType = 0;
  3459.     m_pSkillLevels[dwVnum].tNextRead = 0;
  3460.  
  3461.     if (level > 17)
  3462.         level = 17;
  3463.  
  3464.     PointChange(POINT_SKILL, level);
  3465.  
  3466.     LogManager::instance().CharLog(this, dwVnum, "ONE_SKILL_RESET_BY_SCROLL", "");
  3467.  
  3468.     ComputePoints();
  3469.     SkillLevelPacket();
  3470.  
  3471.     return true;
  3472. }
  3473.  
  3474. bool CHARACTER::CanUseSkill(DWORD dwSkillVnum) const
  3475. {
  3476.     if (0 == dwSkillVnum) return false;
  3477.  
  3478.     if (0 < GetSkillGroup())
  3479.     {
  3480.         const int SKILL_COUNT = 6;
  3481.         static const DWORD SkillList[JOB_MAX_NUM][SKILL_GROUP_MAX_NUM][SKILL_COUNT] =
  3482.         {
  3483.             { { 123456   }, {    16, 17, 18, 19, 20, 21  } },
  3484.             { { 31, 32, 33, 34, 35, 36  }, {    46, 47, 48, 49, 50, 51  } },
  3485.             { { 61, 62, 63, 64, 65, 66  }, {    76, 77, 78, 79, 80, 81  } },
  3486.             { { 91, 92, 93, 94, 95, 96  }, {    106,107,108,109,110,111 } },
  3487.         };
  3488.  
  3489.         const DWORD* pSkill = SkillList[ GetJob() ][ GetSkillGroup()-1 ];
  3490.  
  3491.         for (int i=0 ; i < SKILL_COUNT ; ++i)
  3492.         {
  3493.             if (pSkill[i] == dwSkillVnum) return true;
  3494.         }
  3495.     }
  3496.    
  3497.     //if (true == IsHorseRiding())
  3498.  
  3499.     if (true == IsRiding())
  3500.     {
  3501.         //¸¶¿îÆ® Å»°ÍÁß °í±Þ¸»¸¸ ½ºÅ³ »ç¿ë°¡´É
  3502.         //if(GetMountVnum())
  3503.         //{
  3504.         //  if( GetMountVnum() < 20209 && GetMountVnum() > 20212)
  3505.         //      if (GetMountVnum() != 20215 || GetMountVnum() != 20218 || GetMountVnum() != 20220)
  3506.         //          return false;
  3507.         //}
  3508.  
  3509.         switch(dwSkillVnum)
  3510.         {
  3511.             case SKILL_HORSE_WILDATTACK:
  3512.             case SKILL_HORSE_CHARGE:
  3513.             case SKILL_HORSE_ESCAPE:
  3514.             case SKILL_HORSE_WILDATTACK_RANGE:
  3515.                 return true;
  3516.         }
  3517.     }
  3518.    
  3519.     //¸¶¿îÆ® Å»°ÍÁß °í±Þ¸»¸¸ ½ºÅ³ »ç¿ë°¡´É
  3520.     if(GetMountVnum())
  3521.     {
  3522.         if( GetMountVnum() > 20110)
  3523.             return true;
  3524.         //Spells Fix Mount System
  3525.         //if( GetMountVnum() > 20109 && GetMountVnum() < 20200)
  3526.         //{
  3527.         //  ChatPacket(CHAT_TYPE_INFO, LC_TEXT_LANGUAGE(GetLanguage(),"¸»ÀÌ ¾ø½À´Ï´Ù. ¸¶±Â°£ °æºñº´À» ã¾Æ°¡¼¼¿ä."));
  3528.         //  return true;
  3529.         //}
  3530.     }
  3531.  
  3532.     switch( dwSkillVnum )
  3533.     {
  3534.         case 121: case 122: case 124: case 126: case 127: case 128: case 129: case 130:
  3535.         case 131:
  3536.         case 151: case 152: case 153: case 154: case 155: case 156: case 157: case 158: case 159:
  3537.             return true;
  3538.     }
  3539.  
  3540.     return false;
  3541. }
  3542.  
  3543. bool CHARACTER::CheckSkillHitCount(const BYTE SkillID, const VID TargetVID)
  3544. {
  3545.     auto iter = m_SkillUseInfo.find(SkillID);
  3546.  
  3547.     if (iter == m_SkillUseInfo.end())
  3548.     {
  3549.         sys_log(0, "SkillHack: Skill(%u) is not in container", SkillID);
  3550.         return false;
  3551.     }
  3552.  
  3553.     TSkillUseInfo& rSkillUseInfo = iter->second;
  3554.  
  3555.     if (false == rSkillUseInfo.bUsed)
  3556.     {
  3557.         sys_log(0, "SkillHack: not used skill(%u)", SkillID);
  3558.         return false;
  3559.     }
  3560.  
  3561.     switch (SkillID)
  3562.     {
  3563.         case SKILL_YONGKWON:
  3564.         case SKILL_HWAYEOMPOK:
  3565.         case SKILL_DAEJINGAK:
  3566.         case SKILL_PAERYONG:
  3567.             sys_log(0, "SkillHack: cannot use attack packet for skill(%u)", SkillID);
  3568.             return false;
  3569.     }
  3570.  
  3571.     auto iterTargetMap = rSkillUseInfo.TargetVIDMap.find(TargetVID);
  3572.  
  3573.     if (rSkillUseInfo.TargetVIDMap.end() != iterTargetMap)
  3574.     {
  3575.         size_t MaxAttackCountPerTarget = 1;
  3576.  
  3577.         switch (SkillID)
  3578.         {
  3579.             case SKILL_SAMYEON:
  3580.             case SKILL_CHARYUN:
  3581.                 MaxAttackCountPerTarget = 3;
  3582.                 break;
  3583.  
  3584.             case SKILL_HORSE_WILDATTACK_RANGE:
  3585.                 MaxAttackCountPerTarget = 5;
  3586.                 break;
  3587.  
  3588.             case SKILL_YEONSA:
  3589.                 MaxAttackCountPerTarget = 7;
  3590.                 break;
  3591.  
  3592.             case SKILL_HORSE_ESCAPE:
  3593.                 MaxAttackCountPerTarget = 10;
  3594.                 break;
  3595.         }
  3596.  
  3597.         if (iterTargetMap->second >= MaxAttackCountPerTarget)
  3598.         {
  3599.             sys_log(0, "SkillHack: Too Many Hit count from SkillID(%u) count(%u)", SkillID, iterTargetMap->second);
  3600.             return false;
  3601.         }
  3602.  
  3603.         iterTargetMap->second++;
  3604.     }
  3605.     else
  3606.     {
  3607.         rSkillUseInfo.TargetVIDMap.insert( std::make_pair(TargetVID, 1) );
  3608.     }
  3609.  
  3610.     return true;
  3611. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement