Advertisement
Guest User

Untitled

a guest
May 29th, 2015
361
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 24.69 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include "utils.h"
  3. #include "config.h"
  4. #include "desc.h"
  5. #include "char.h"
  6. #include "char_manager.h"
  7. #include "battle.h"
  8. #include "item.h"
  9. #include "item_manager.h"
  10. #include "mob_manager.h"
  11. #include "vector.h"
  12. #include "packet.h"
  13. #include "pvp.h"
  14. #include "profiler.h"
  15. #include "guild.h"
  16. #include "affect.h"
  17. #include "unique_item.h"
  18. #include "lua_incl.h"
  19. #include "arena.h"
  20. #include "castle.h"
  21. #include "sectree.h"
  22. #include "ani.h"
  23. #include "locale_service.h"
  24. #ifdef ENABLE_WAITHACK_DETECT
  25. #include "db.h"
  26. #endif
  27. int battle_hit(LPCHARACTER ch, LPCHARACTER victim, int & iRetDam);
  28.  
  29. bool battle_distance_valid_by_xy(long x, long y, long tx, long ty)
  30. {
  31.     long distance = DISTANCE_APPROX(x - tx, y - ty);
  32.  
  33.     if (distance > 170)
  34.         return false;
  35.  
  36.     return true;
  37. }
  38.  
  39. bool battle_distance_valid(LPCHARACTER ch, LPCHARACTER victim)
  40. {
  41.     return battle_distance_valid_by_xy(ch->GetX(), ch->GetY(), victim->GetX(), victim->GetY());
  42. }
  43.  
  44. bool timed_event_cancel(LPCHARACTER ch)
  45. {
  46.     if (ch->m_pkTimedEvent)
  47.     {
  48.         event_cancel(&ch->m_pkTimedEvent);
  49.         return true;
  50.     }
  51.  
  52.     /* RECALL_DELAY
  53.        차후 전투로 인해 귀환부 딜레이가 취소 되어야 할 경우 주석 해제
  54.        if (ch->m_pk_RecallEvent)
  55.        {
  56.        event_cancel(&ch->m_pkRecallEvent);
  57.        return true;
  58.        }
  59.        END_OF_RECALL_DELAY */
  60.  
  61.     return false;
  62. }
  63.  
  64. bool battle_is_attackable(LPCHARACTER ch, LPCHARACTER victim)
  65. {
  66.     //DAMAGE SOLO CON AFFECT
  67.     int DamageFlag = victim->GetDamAff();
  68.     if (DamageFlag > 0)
  69.     {
  70.         if (!ch->IsAffectFlag(DamageFlag))
  71.         {
  72.             return false;
  73.         }
  74.     }
  75.  
  76.  
  77.     int race = ch->GetJob();
  78.     int RaceFlag = victim->GetDamRace();
  79.  
  80.     if (RaceFlag > 0)
  81.     {
  82.         if(race!=RaceFlag-1)
  83.         {
  84.             return false;
  85.         }
  86.     }
  87.  
  88.     // 상대방이 죽었으면 중단한다.
  89.     if (victim->IsDead())
  90.         return false;
  91.  
  92.     // 안전지대면 중단
  93.     {
  94.         SECTREE *sectree = NULL;
  95.  
  96.         sectree = ch->GetSectree();
  97.         if (sectree && sectree->IsAttr(ch->GetX(), ch->GetY(), ATTR_BANPK))
  98.             return false;
  99.  
  100.         sectree = victim->GetSectree();
  101.         if (sectree && sectree->IsAttr(victim->GetX(), victim->GetY(), ATTR_BANPK))
  102.             return false;
  103.     }
  104.  
  105.  
  106.     // 내가 죽었으면 중단한다.
  107.     if (ch->IsStun() || ch->IsDead())
  108.         return false;
  109.  
  110.     if (ch->IsPC() && victim->IsPC())
  111.     {
  112.         CGuild* g1 = ch->GetGuild();
  113.         CGuild* g2 = victim->GetGuild();
  114.  
  115.         if (g1 && g2)
  116.         {
  117.             if (g1->UnderWar(g2->GetID()))
  118.                 return true;
  119.         }
  120.     }
  121.  
  122.     if (IS_CASTLE_MAP(ch->GetMapIndex()) && false==castle_can_attack(ch, victim))
  123.             return false;
  124.  
  125.     if (CArenaManager::instance().CanAttack(ch, victim) == true)
  126.         return true;
  127.  
  128.     return CPVPManager::instance().CanAttack(ch, victim);
  129. }
  130.  
  131. int battle_melee_attack(LPCHARACTER ch, LPCHARACTER victim)
  132. {
  133.     if (test_server&&ch->IsPC())
  134.         sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName());
  135.  
  136.     if (!victim || ch == victim)
  137.         return BATTLE_NONE;
  138.  
  139.     if (test_server&&ch->IsPC())
  140.         sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName());
  141.  
  142.     if (!battle_is_attackable(ch, victim))
  143.         return BATTLE_NONE;
  144.  
  145.     if (test_server&&ch->IsPC())
  146.         sys_log(0, "battle_melee_attack : [%s] attack to [%s]", ch->GetName(), victim->GetName());
  147.  
  148.     // 거리 체크
  149.     int distance = DISTANCE_APPROX(ch->GetX() - victim->GetX(), ch->GetY() - victim->GetY());
  150.  
  151.     if (!victim->IsBuilding())
  152.     {
  153.         int max = 300;
  154.  
  155.         if (false == ch->IsPC())
  156.         {
  157.             // 몬스터의 경우 몬스터 공격 거리를 사용
  158.             max = (int) (ch->GetMobAttackRange() * 1.15f);
  159.         }
  160.         else
  161.         {
  162.             // PC일 경우 상대가 melee 몹일 경우 몹의 공격 거리가 최대 공격 거리
  163.             if (false == victim->IsPC() && BATTLE_TYPE_MELEE == victim->GetMobBattleType())
  164.                 max = MAX(300, (int) (victim->GetMobAttackRange() * 1.15f));
  165.         }
  166.  
  167.         if (distance > max)
  168.         {
  169.             if (test_server)
  170.                 sys_log(0, "VICTIM_FAR: %s distance: %d max: %d", ch->GetName(), distance, max);
  171.  
  172.             return BATTLE_NONE;
  173.         }
  174.     }
  175.  
  176.     if (timed_event_cancel(ch))
  177.         ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("전투가 시작 되어 취소 되었습니다."));
  178.  
  179.     if (timed_event_cancel(victim))
  180.         victim->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("전투가 시작 되어 취소 되었습니다."));
  181.  
  182.     ch->SetPosition(POS_FIGHTING);
  183.     ch->SetVictim(victim);
  184.  
  185.     const PIXEL_POSITION & vpos = victim->GetXYZ();
  186.     ch->SetRotationToXY(vpos.x, vpos.y);
  187.  
  188.     int dam;
  189.     int ret = battle_hit(ch, victim, dam);
  190.     return (ret);
  191. }
  192.  
  193. // 실제 GET_BATTLE_VICTIM을 NULL로 만들고 이벤트를 캔슬 시킨다.
  194. void battle_end_ex(LPCHARACTER ch)
  195. {
  196.     if (ch->IsPosition(POS_FIGHTING))
  197.         ch->SetPosition(POS_STANDING);
  198. }
  199.  
  200. void battle_end(LPCHARACTER ch)
  201. {
  202.     battle_end_ex(ch);
  203. }
  204.  
  205. // AG = Attack Grade
  206. // AL = Attack Limit
  207. int CalcBattleDamage(int iDam, int iAttackerLev, int iVictimLev)
  208. {
  209.     if (iDam < 3)
  210.         iDam = number(1, 5);
  211.  
  212.     //return CALCULATE_DAMAGE_LVDELTA(iAttackerLev, iVictimLev, iDam);
  213.     return iDam;
  214. }
  215.  
  216. int CalcMagicDamageWithValue(int iDam, LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
  217. {
  218.     return CalcBattleDamage(iDam, pkAttacker->GetLevel(), pkVictim->GetLevel());
  219. }
  220.  
  221. int CalcMagicDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
  222. {
  223.     int iDam = 0;
  224.  
  225.     if (pkAttacker->IsNPC())
  226.     {
  227.         iDam = CalcMeleeDamage(pkAttacker, pkVictim, false, false);
  228.     }
  229.  
  230.     iDam += pkAttacker->GetPoint(POINT_PARTY_ATTACKER_BONUS);
  231.  
  232.     return CalcMagicDamageWithValue(iDam, pkAttacker, pkVictim);
  233. }
  234.  
  235. float CalcAttackRating(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnoreTargetRating)
  236. {
  237.     int iARSrc;
  238.     int iERSrc;
  239.  
  240.     if (LC_IsYMIR()) // 천마
  241.     {
  242.         iARSrc = MIN(90, pkAttacker->GetPolymorphPoint(POINT_DX));
  243.         iERSrc = MIN(90, pkVictim->GetPolymorphPoint(POINT_DX));
  244.     }
  245.     else
  246.     {
  247.         int attacker_dx = pkAttacker->GetPolymorphPoint(POINT_DX);
  248.         int attacker_lv = pkAttacker->GetLevel();
  249.  
  250.         int victim_dx = pkVictim->GetPolymorphPoint(POINT_DX);
  251.         int victim_lv = pkAttacker->GetLevel();
  252.  
  253.         iARSrc = MIN(90, (attacker_dx * 4   + attacker_lv * 2) / 6);
  254.         iERSrc = MIN(90, (victim_dx   * 4   + victim_lv   * 2) / 6);
  255.     }
  256.  
  257.     float fAR = ((float) iARSrc + 210.0f) / 300.0f; // fAR = 0.7 ~ 1.0
  258.  
  259.     if (bIgnoreTargetRating)
  260.         return fAR;
  261.  
  262.     // ((Edx * 2 + 20) / (Edx + 110)) * 0.3
  263.     float fER = ((float) (iERSrc * 2 + 5) / (iERSrc + 95)) * 3.0f / 10.0f;
  264.  
  265.     return fAR - fER;
  266. }
  267.  
  268. int CalcAttBonus(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, int iAtk)
  269. {
  270.     // PvP에는 적용하지않음
  271.     if (!pkVictim->IsPC())
  272.         iAtk += pkAttacker->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_ATTACK_BONUS);
  273.  
  274.     // PvP에는 적용하지않음
  275.     if (!pkAttacker->IsPC())
  276.     {
  277.         int iReduceDamagePct = pkVictim->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_TRANSFER_DAMAGE);
  278.         iAtk = iAtk * (100 + iReduceDamagePct) / 100;
  279.     }
  280.  
  281.     if (pkAttacker->IsNPC() && pkVictim->IsPC())
  282.     {
  283.         iAtk = (iAtk * CHARACTER_MANAGER::instance().GetMobDamageRate(pkAttacker)) / 100;
  284.     }
  285.  
  286.     if (pkVictim->IsNPC())
  287.     {
  288.         if (pkVictim->IsRaceFlag(RACE_FLAG_ANIMAL))
  289.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ANIMAL)) / 100;
  290.         else if (pkVictim->IsRaceFlag(RACE_FLAG_UNDEAD))
  291.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_UNDEAD)) / 100;
  292.         else if (pkVictim->IsRaceFlag(RACE_FLAG_DEVIL))
  293.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_DEVIL)) / 100;
  294.         else if (pkVictim->IsRaceFlag(RACE_FLAG_HUMAN))
  295.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_HUMAN)) / 100;
  296.         else if (pkVictim->IsRaceFlag(RACE_FLAG_ORC))
  297.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ORC)) / 100;
  298.         else if (pkVictim->IsRaceFlag(RACE_FLAG_MILGYO))
  299.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_MILGYO)) / 100;
  300.         else if (pkVictim->IsRaceFlag(RACE_FLAG_INSECT))
  301.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_INSECT)) / 100;
  302.         else if (pkVictim->IsRaceFlag(RACE_FLAG_FIRE))
  303.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_FIRE)) / 100;
  304.         else if (pkVictim->IsRaceFlag(RACE_FLAG_ICE))
  305.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ICE)) / 100;
  306.         else if (pkVictim->IsRaceFlag(RACE_FLAG_DESERT))
  307.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_DESERT)) / 100;
  308.         else if (pkVictim->IsRaceFlag(RACE_FLAG_TREE))
  309.             iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_TREE)) / 100;
  310.  
  311.         iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_MONSTER)) / 100;
  312.     }
  313.     else if (pkVictim->IsPC())
  314.     {
  315.         iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_HUMAN)) / 100;
  316.  
  317.         switch (pkVictim->GetJob())
  318.         {
  319.             case JOB_WARRIOR:
  320.                 iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_WARRIOR)) / 100;
  321.                 break;
  322.  
  323.             case JOB_ASSASSIN:
  324.                 iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_ASSASSIN)) / 100;
  325.                 break;
  326.  
  327.             case JOB_SURA:
  328.                 iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_SURA)) / 100;
  329.                 break;
  330.  
  331.             case JOB_SHAMAN:
  332.                 iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_SHAMAN)) / 100;
  333.                 break;
  334. #ifdef ENABLE_WOLFMAN
  335.             case JOB_WOLFMAN:
  336.                 iAtk += (iAtk * pkAttacker->GetPoint(POINT_ATTBONUS_WOLFMAN)) / 100;
  337.                 break;
  338. #endif
  339.         }
  340.     }
  341.  
  342.     if (pkAttacker->IsPC() == true)
  343.     {
  344.         switch (pkAttacker->GetJob())
  345.         {
  346.             case JOB_WARRIOR:
  347.                 iAtk -= (iAtk * pkVictim->GetPoint(POINT_RESIST_WARRIOR)) / 100;
  348.                 break;
  349.  
  350.             case JOB_ASSASSIN:
  351.                 iAtk -= (iAtk * pkVictim->GetPoint(POINT_RESIST_ASSASSIN)) / 100;
  352.                 break;
  353.  
  354.             case JOB_SURA:
  355.                 iAtk -= (iAtk * pkVictim->GetPoint(POINT_RESIST_SURA)) / 100;
  356.                 break;
  357.  
  358.             case JOB_SHAMAN:
  359.                 iAtk -= (iAtk * pkVictim->GetPoint(POINT_RESIST_SHAMAN)) / 100;
  360.                 break;
  361. #ifdef ENABLE_WOLFMAN
  362.             case JOB_WOLFMAN:
  363.                 iAtk -= (iAtk * pkVictim->GetPoint(POINT_RESIST_WOLFMAN)) / 100;
  364.                 break;
  365. #endif
  366.         }
  367.     }
  368.  
  369.     //[ mob -> PC ] 원소 속성 방어 적용
  370.     //2013/01/17
  371.     //몬스터 속성공격 데미지의 30%에 해당하는 수치에만 저항이 적용됨.
  372.     if (pkAttacker->IsNPC() && pkVictim->IsPC())
  373.     {
  374.         if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_ELEC))
  375.             iAtk -= (iAtk * 30 * pkVictim->GetPoint(POINT_RESIST_ELEC))     / 10000;
  376.         else if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_FIRE))
  377.             iAtk -= (iAtk * 30 * pkVictim->GetPoint(POINT_RESIST_FIRE))     / 10000;
  378.         else if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_ICE))
  379.             iAtk -= (iAtk * 30 * pkVictim->GetPoint(POINT_RESIST_ICE))      / 10000;
  380.         else if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_WIND))
  381.             iAtk -= (iAtk * 30 * pkVictim->GetPoint(POINT_RESIST_WIND))     / 10000;
  382.         else if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_EARTH))
  383.             iAtk -= (iAtk * 30 * pkVictim->GetPoint(POINT_RESIST_EARTH))    / 10000;
  384.         else if (pkAttacker->IsRaceFlag(RACE_FLAG_ATT_DARK))
  385.             iAtk -= (iAtk * 30 * pkVictim->GetPoint(POINT_RESIST_DARK))     / 10000;
  386.     }
  387.  
  388.  
  389.     return iAtk;
  390. }
  391.  
  392. void Item_GetDamage(LPITEM pkItem, int* pdamMin, int* pdamMax)
  393. {
  394.     *pdamMin = 0;
  395.     *pdamMax = 1;
  396.  
  397.     if (!pkItem)
  398.         return;
  399.  
  400.     switch (pkItem->GetType())
  401.     {
  402.         case ITEM_ROD:
  403.         case ITEM_PICK:
  404.             return;
  405.     }
  406.  
  407.     if (pkItem->GetType() != ITEM_WEAPON)
  408.         sys_err("Item_GetDamage - !ITEM_WEAPON vnum=%d, type=%d", pkItem->GetOriginalVnum(), pkItem->GetType());
  409.  
  410.     *pdamMin = pkItem->GetValue(3);
  411.     *pdamMax = pkItem->GetValue(4);
  412. }
  413.  
  414. int CalcMeleeDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, bool bIgnoreDefense, bool bIgnoreTargetRating)
  415. {
  416.     LPITEM pWeapon = pkAttacker->GetWear(WEAR_WEAPON);
  417.     bool bPolymorphed = pkAttacker->IsPolymorphed();
  418.  
  419.     if (pWeapon && !(bPolymorphed && !pkAttacker->IsPolyMaintainStat()))
  420.     {
  421.         if (pWeapon->GetType() != ITEM_WEAPON)
  422.             return 0;
  423.  
  424.         switch (pWeapon->GetSubType())
  425.         {
  426.             case WEAPON_SWORD:
  427.             case WEAPON_DAGGER:
  428.             case WEAPON_TWO_HANDED:
  429.             case WEAPON_BELL:
  430.             case WEAPON_FAN:
  431.             case WEAPON_MOUNT_SPEAR:
  432. #ifdef ENABLE_WOLFMAN
  433.             case WEAPON_CLAW:
  434. #endif
  435.                 break;
  436.  
  437.             case WEAPON_BOW:
  438.                 sys_err("CalcMeleeDamage should not handle bows (name: %s)", pkAttacker->GetName());
  439.                 return 0;
  440.  
  441.             default:
  442.                 return 0;
  443.         }
  444.     }
  445.  
  446.     int iDam = 0;
  447.     float fAR = CalcAttackRating(pkAttacker, pkVictim, bIgnoreTargetRating);
  448.     int iDamMin = 0, iDamMax = 0;
  449.  
  450.     // TESTSERVER_SHOW_ATTACKINFO
  451.     int DEBUG_iDamCur = 0;
  452.     int DEBUG_iDamBonus = 0;
  453.     // END_OF_TESTSERVER_SHOW_ATTACKINFO
  454.  
  455.     if (bPolymorphed && !pkAttacker->IsPolyMaintainStat())
  456.     {
  457.         // MONKEY_ROD_ATTACK_BUG_FIX
  458.         Item_GetDamage(pWeapon, &iDamMin, &iDamMax);
  459.         // END_OF_MONKEY_ROD_ATTACK_BUG_FIX
  460.  
  461.         DWORD dwMobVnum = pkAttacker->GetPolymorphVnum();
  462.         const CMob * pMob = CMobManager::instance().Get(dwMobVnum);
  463.  
  464.         if (pMob)
  465.         {
  466.             int iPower = pkAttacker->GetPolymorphPower();
  467.             iDamMin += pMob->m_table.dwDamageRange[0] * iPower / 100;
  468.             iDamMax += pMob->m_table.dwDamageRange[1] * iPower / 100;
  469.         }
  470.     }
  471.     else if (pWeapon)
  472.     {
  473.         // MONKEY_ROD_ATTACK_BUG_FIX
  474.         Item_GetDamage(pWeapon, &iDamMin, &iDamMax);
  475.         // END_OF_MONKEY_ROD_ATTACK_BUG_FIX
  476.     }
  477.     else if (pkAttacker->IsNPC())
  478.     {
  479.         iDamMin = pkAttacker->GetMobDamageMin();
  480.         iDamMax = pkAttacker->GetMobDamageMax();
  481.     }
  482.  
  483.     iDam = number(iDamMin, iDamMax) * 2;
  484.  
  485.     // TESTSERVER_SHOW_ATTACKINFO
  486.     DEBUG_iDamCur = iDam;
  487.     // END_OF_TESTSERVER_SHOW_ATTACKINFO
  488.     //
  489.     int iAtk = 0;
  490.  
  491.     // level must be ignored when multiply by fAR, so subtract it before calculation.
  492.     iAtk = pkAttacker->GetPoint(POINT_ATT_GRADE) + iDam - (pkAttacker->GetLevel() * 2);
  493.     iAtk = (int) (iAtk * fAR);
  494.     iAtk += pkAttacker->GetLevel() * 2; // and add again
  495.  
  496.     if (pWeapon)
  497.     {
  498.         iAtk += pWeapon->GetValue(5) * 2;
  499.  
  500.         // 2004.11.12.myevan.TESTSERVER_SHOW_ATTACKINFO
  501.         DEBUG_iDamBonus = pWeapon->GetValue(5) * 2;
  502.         ///////////////////////////////////////////////
  503.     }
  504.  
  505.     iAtk += pkAttacker->GetPoint(POINT_PARTY_ATTACKER_BONUS); // party attacker role bonus
  506.     iAtk = (int) (iAtk * (100 + (pkAttacker->GetPoint(POINT_ATT_BONUS) + pkAttacker->GetPoint(POINT_MELEE_MAGIC_ATT_BONUS_PER))) / 100);
  507.  
  508.     iAtk = CalcAttBonus(pkAttacker, pkVictim, iAtk);
  509.  
  510.     int iDef = 0;
  511.  
  512.     if (!bIgnoreDefense)
  513.     {
  514.         iDef = (pkVictim->GetPoint(POINT_DEF_GRADE) * (100 + pkVictim->GetPoint(POINT_DEF_BONUS)) / 100);
  515.  
  516.         if (!pkAttacker->IsPC())
  517.             iDef += pkVictim->GetMarriageBonus(UNIQUE_ITEM_MARRIAGE_DEFENSE_BONUS);
  518.     }
  519.  
  520.     if (pkAttacker->IsNPC())
  521.         iAtk = (int) (iAtk * pkAttacker->GetMobDamageMultiply());
  522.  
  523.     iDam = MAX(0, iAtk - iDef);
  524.  
  525.     if (test_server)
  526.     {
  527.         int DEBUG_iLV = pkAttacker->GetLevel()*2;
  528.         int DEBUG_iST = int((pkAttacker->GetPoint(POINT_ATT_GRADE) - DEBUG_iLV) * fAR);
  529.         int DEBUG_iPT = pkAttacker->GetPoint(POINT_PARTY_ATTACKER_BONUS);
  530.         int DEBUG_iWP = 0;
  531.         int DEBUG_iPureAtk = 0;
  532.         int DEBUG_iPureDam = 0;
  533.         char szRB[32] = "";
  534.         char szGradeAtkBonus[32] = "";
  535.  
  536.         DEBUG_iWP = int(DEBUG_iDamCur * fAR);
  537.         DEBUG_iPureAtk = DEBUG_iLV + DEBUG_iST + DEBUG_iWP+DEBUG_iDamBonus;
  538.         DEBUG_iPureDam = iAtk - iDef;
  539.  
  540.         if (pkAttacker->IsNPC())
  541.         {
  542.             snprintf(szGradeAtkBonus, sizeof(szGradeAtkBonus), "=%d*%.1f", DEBUG_iPureAtk, pkAttacker->GetMobDamageMultiply());
  543.             DEBUG_iPureAtk = int(DEBUG_iPureAtk * pkAttacker->GetMobDamageMultiply());
  544.         }
  545.  
  546.         if (DEBUG_iDamBonus != 0)
  547.             snprintf(szRB, sizeof(szRB), "+RB(%d)", DEBUG_iDamBonus);
  548.  
  549.         char szPT[32] = "";
  550.  
  551.         if (DEBUG_iPT != 0)
  552.             snprintf(szPT, sizeof(szPT), ", PT=%d", DEBUG_iPT);
  553.  
  554.         char szUnknownAtk[32] = "";
  555.  
  556.         if (iAtk != DEBUG_iPureAtk)
  557.             snprintf(szUnknownAtk, sizeof(szUnknownAtk), "+?(%d)", iAtk-DEBUG_iPureAtk);
  558.  
  559.         char szUnknownDam[32] = "";
  560.  
  561.         if (iDam != DEBUG_iPureDam)
  562.             snprintf(szUnknownDam, sizeof(szUnknownDam), "+?(%d)", iDam-DEBUG_iPureDam);
  563.  
  564.         char szMeleeAttack[128];
  565.  
  566.         snprintf(szMeleeAttack, sizeof(szMeleeAttack),
  567.                 "%s(%d)-%s(%d)=%d%s, ATK=LV(%d)+ST(%d)+WP(%d)%s%s%s, AR=%.3g%s",
  568.                 pkAttacker->GetName(),
  569.                 iAtk,
  570.                 pkVictim->GetName(),
  571.                 iDef,
  572.                 iDam,
  573.                 szUnknownDam,
  574.                 DEBUG_iLV,
  575.                 DEBUG_iST,
  576.                 DEBUG_iWP,
  577.                 szRB,
  578.                 szUnknownAtk,
  579.                 szGradeAtkBonus,
  580.                 fAR,
  581.                 szPT);
  582.  
  583.         pkAttacker->ChatPacket(CHAT_TYPE_TALKING, "%s", szMeleeAttack);
  584.         pkVictim->ChatPacket(CHAT_TYPE_TALKING, "%s", szMeleeAttack);
  585.     }
  586.  
  587.     return CalcBattleDamage(iDam, pkAttacker->GetLevel(), pkVictim->GetLevel());
  588. }
  589.  
  590. int CalcArrowDamage(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, LPITEM pkBow, LPITEM pkArrow, bool bIgnoreDefense)
  591. {
  592.     if (!pkBow || pkBow->GetType() != ITEM_WEAPON || pkBow->GetSubType() != WEAPON_BOW)
  593.         return 0;
  594.  
  595.     if (!pkArrow)
  596.         return 0;
  597.  
  598.     // 타격치 계산부
  599.     int iDist = (int) (DISTANCE_SQRT(pkAttacker->GetX() - pkVictim->GetX(), pkAttacker->GetY() - pkVictim->GetY()));
  600.     //int iGap = (iDist / 100) - 5 - pkBow->GetValue(5) - pkAttacker->GetPoint(POINT_BOW_DISTANCE);
  601.     int iGap = (iDist / 100) - 5 - pkAttacker->GetPoint(POINT_BOW_DISTANCE);
  602.     int iPercent = 100 - (iGap * 5);
  603.  
  604.     if (iPercent <= 0)
  605.         return 0;
  606.     else if (iPercent > 100)
  607.         iPercent = 100;
  608.  
  609.     int iDam = 0;
  610.  
  611.     float fAR = CalcAttackRating(pkAttacker, pkVictim, false);
  612.     iDam = number(pkBow->GetValue(3), pkBow->GetValue(4)) * 2 + pkArrow->GetValue(3);
  613.     int iAtk;
  614.  
  615.     // level must be ignored when multiply by fAR, so subtract it before calculation.
  616.     iAtk = pkAttacker->GetPoint(POINT_ATT_GRADE) + iDam - (pkAttacker->GetLevel() * 2);
  617.     iAtk = (int) (iAtk * fAR);
  618.     iAtk += pkAttacker->GetLevel() * 2; // and add again
  619.  
  620.     // Refine Grade
  621.     iAtk += pkBow->GetValue(5) * 2;
  622.  
  623.     iAtk += pkAttacker->GetPoint(POINT_PARTY_ATTACKER_BONUS);
  624.     iAtk = (int) (iAtk * (100 + (pkAttacker->GetPoint(POINT_ATT_BONUS) + pkAttacker->GetPoint(POINT_MELEE_MAGIC_ATT_BONUS_PER))) / 100);
  625.  
  626.     iAtk = CalcAttBonus(pkAttacker, pkVictim, iAtk);
  627.  
  628.     int iDef = 0;
  629.  
  630.     if (!bIgnoreDefense)
  631.         iDef = (pkVictim->GetPoint(POINT_DEF_GRADE) * (100 + pkAttacker->GetPoint(POINT_DEF_BONUS)) / 100);
  632.  
  633.     if (pkAttacker->IsNPC())
  634.         iAtk = (int) (iAtk * pkAttacker->GetMobDamageMultiply());
  635.  
  636.     iDam = MAX(0, iAtk - iDef);
  637.  
  638.     int iPureDam = iDam;
  639.  
  640.     iPureDam = (iPureDam * iPercent) / 100;
  641.  
  642.     if (test_server)
  643.     {
  644.         pkAttacker->ChatPacket(CHAT_TYPE_INFO, "ARROW %s -> %s, DAM %d DIST %d GAP %d %% %d",
  645.                 pkAttacker->GetName(),
  646.                 pkVictim->GetName(),
  647.                 iPureDam,
  648.                 iDist, iGap, iPercent);
  649.     }
  650.  
  651.     return iPureDam;
  652.     //return iDam;
  653. }
  654.  
  655.  
  656. void NormalAttackAffect(LPCHARACTER pkAttacker, LPCHARACTER pkVictim)
  657. {
  658.     // 독 공격은 특이하므로 특수 처리
  659.     if (pkAttacker->GetPoint(POINT_POISON_PCT) && !pkVictim->IsAffectFlag(AFF_POISON)
  660. #ifdef ENABLE_WOLFMAN
  661. && !pkVictim->IsAffectFlag(AFF_BLEEDING)
  662. #endif
  663. )
  664.     {
  665.         if (number(1, 100) <= pkAttacker->GetPoint(POINT_POISON_PCT))
  666.             pkVictim->AttackedByPoison(pkAttacker);
  667.     }
  668.  
  669. #ifdef ENABLE_WOLFMAN
  670.     // BLEED
  671.     if (pkAttacker->GetPoint(POINT_BLEEDING_PCT) && !pkVictim->IsAffectFlag(AFF_BLEEDING) && !pkVictim->IsAffectFlag(AFF_POISON))
  672.     {
  673.         if (number(1, 100) <= pkAttacker->GetPoint(POINT_BLEEDING_PCT))
  674.             pkVictim->AttackedByBleeding(pkAttacker);
  675.     }
  676. #endif
  677.     int iStunDuration = 2;
  678.     if (pkAttacker->IsPC() && !pkVictim->IsPC())
  679.         iStunDuration = 4;
  680.  
  681.     AttackAffect(pkAttacker, pkVictim, POINT_STUN_PCT, IMMUNE_STUN,  AFFECT_STUN, POINT_NONE,        0, AFF_STUN, iStunDuration, "STUN");
  682.     AttackAffect(pkAttacker, pkVictim, POINT_SLOW_PCT, IMMUNE_SLOW,  AFFECT_SLOW, POINT_MOV_SPEED, -30, AFF_SLOW, 20,       "SLOW");
  683. }
  684.  
  685. int battle_hit(LPCHARACTER pkAttacker, LPCHARACTER pkVictim, int & iRetDam)
  686. {
  687.     //PROF_UNIT puHit("Hit");
  688.     if (test_server)
  689.         sys_log(0, "battle_hit : [%s] attack to [%s] : dam :%d type :%d", pkAttacker->GetName(), pkVictim->GetName(), iRetDam);
  690.  
  691.     int iDam = CalcMeleeDamage(pkAttacker, pkVictim);
  692.  
  693.     if (iDam <= 0)
  694.         return (BATTLE_DAMAGE);
  695.  
  696.     NormalAttackAffect(pkAttacker, pkVictim);
  697.  
  698.     // 데미지 계산
  699.     //iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST)) / 100;
  700.     LPITEM pkWeapon = pkAttacker->GetWear(WEAR_WEAPON);
  701.  
  702.     if (pkWeapon)
  703.         switch (pkWeapon->GetSubType())
  704.         {
  705.             case WEAPON_SWORD:
  706.                 iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_SWORD)) / 100;
  707.                 break;
  708.  
  709.             case WEAPON_TWO_HANDED:
  710.                 iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_TWOHAND)) / 100;
  711.                 break;
  712.  
  713.             case WEAPON_DAGGER:
  714.                 iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_DAGGER)) / 100;
  715.                 break;
  716.  
  717.             case WEAPON_BELL:
  718.                 iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_BELL)) / 100;
  719.                 break;
  720.  
  721.             case WEAPON_FAN:
  722.                 iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_FAN)) / 100;
  723.                 break;
  724.  
  725.             case WEAPON_BOW:
  726.                 iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_BOW)) / 100;
  727.                 break;
  728. #ifdef ENABLE_WOLFMAN
  729.             case WEAPON_CLAW:
  730.                 iDam = iDam * (100 - pkVictim->GetPoint(POINT_RESIST_CLAW)) / 100;
  731.                 break;
  732. #endif
  733.         }
  734.  
  735.  
  736.     //최종적인 데미지 보정. (2011년 2월 현재 대왕거미에게만 적용.)
  737.     float attMul = pkAttacker->GetAttMul();
  738.     float tempIDam = iDam;
  739.     iDam = attMul * tempIDam + 0.5f;
  740.  
  741.     iRetDam = iDam;
  742.  
  743.     //PROF_UNIT puDam("Dam");
  744.     if (pkVictim->Damage(pkAttacker, iDam, DAMAGE_TYPE_NORMAL))
  745.         return (BATTLE_DEAD);
  746.  
  747.     return (BATTLE_DAMAGE);
  748. }
  749.  
  750. DWORD GET_ATTACK_SPEED(LPCHARACTER ch)
  751. {
  752.     if (NULL == ch)
  753.         return 1000;
  754.  
  755.     LPITEM item = ch->GetWear(WEAR_WEAPON);
  756.     DWORD default_bonus = SPEEDHACK_LIMIT_BONUS;    // 유두리 공속(기본 80)
  757.     DWORD riding_bonus = 0;
  758.  
  759.     if (ch->IsRiding())
  760.     {
  761.         // 뭔가를 탔으면 추가공속 50
  762.         riding_bonus = 50;
  763.     }
  764.  
  765.     DWORD ani_speed = ani_attack_speed(ch);
  766.     DWORD real_speed = (ani_speed * 100) / (default_bonus + ch->GetPoint(POINT_ATT_SPEED) + riding_bonus);
  767.  
  768.     // 단검의 경우 공속 2배
  769.     if (item && item->GetSubType() == WEAPON_DAGGER)
  770.         real_speed /= 2;
  771. #ifdef ENABLE_WOLFMAN
  772.     else if (item && item->GetSubType() == WEAPON_CLAW)
  773.         real_speed /= 2;
  774. #endif
  775.     return real_speed;
  776.  
  777. }
  778.  
  779. void SET_ATTACK_TIME(LPCHARACTER ch, LPCHARACTER victim, DWORD current_time)
  780. {
  781.     if (NULL == ch || NULL == victim)
  782.         return;
  783.  
  784.     if (!ch->IsPC())
  785.         return;
  786.  
  787.     ch->m_kAttackLog.dwVID = victim->GetVID();
  788.     ch->m_kAttackLog.dwTime = current_time;
  789. }
  790.  
  791. void SET_ATTACKED_TIME(LPCHARACTER ch, LPCHARACTER victim, DWORD current_time)
  792. {
  793.     if (NULL == ch || NULL == victim)
  794.         return;
  795.  
  796.     if (!ch->IsPC())
  797.         return;
  798.  
  799.     victim->m_AttackedLog.dwPID         = ch->GetPlayerID();
  800.     victim->m_AttackedLog.dwAttackedTime= current_time;
  801. }
  802.  
  803. bool IS_SPEED_HACK(LPCHARACTER ch, LPCHARACTER victim, DWORD current_time)
  804. {
  805.     if(!gHackCheckEnable) return false;
  806.     if (ch->m_kAttackLog.dwVID == victim->GetVID())
  807.     {
  808.         if (current_time - ch->m_kAttackLog.dwTime < GET_ATTACK_SPEED(ch))
  809.         {
  810.             INCREASE_SPEED_HACK_COUNT(ch);
  811.  
  812.             if (test_server)
  813.             {
  814.                 sys_log(0, "%s attack hack! time (delta, limit)=(%u, %u) hack_count %d",
  815.                         ch->GetName(),
  816.                         current_time - ch->m_kAttackLog.dwTime,
  817.                         GET_ATTACK_SPEED(ch),
  818.                         ch->m_speed_hack_count);
  819.  
  820.                 ch->ChatPacket(CHAT_TYPE_INFO, "%s attack hack! time (delta, limit)=(%u, %u) hack_count %d",
  821.                         ch->GetName(),
  822.                         current_time - ch->m_kAttackLog.dwTime,
  823.                         GET_ATTACK_SPEED(ch),
  824.                         ch->m_speed_hack_count);
  825.             }
  826.  
  827.             SET_ATTACK_TIME(ch, victim, current_time);
  828.             SET_ATTACKED_TIME(ch, victim, current_time);
  829.             return true;
  830.         }
  831.     }
  832.  
  833.     SET_ATTACK_TIME(ch, victim, current_time);
  834.  
  835.     if (victim->m_AttackedLog.dwPID == ch->GetPlayerID())
  836.     {
  837.         if (current_time - victim->m_AttackedLog.dwAttackedTime < GET_ATTACK_SPEED(ch))
  838.         {
  839.             INCREASE_SPEED_HACK_COUNT(ch);
  840. #if ENABLE_WAITHACK_DETECT
  841.             if (ch->m_speed_hack_count > 50)
  842.             {
  843.                 DBManager::instance().Query("INSERT INTO log.wait_hack SET login='%s', nickname='%s', ip='%s', time=NOW(), map_index=%d, server='%s';",ch->GetDesc()->GetAccountTable().login, ch->GetName(), ch->GetDesc()->GetHostName(), ch->GetMapIndex(), g_stHostname.c_str());
  844. #endif
  845.                 if(test_server){
  846.                     sys_log(0, "%s Attack Speed HACK! time (delta, limit)=(%u, %u), hack_count = %d",
  847.                             ch->GetName(),
  848.                             current_time - victim->m_AttackedLog.dwAttackedTime,
  849.                             GET_ATTACK_SPEED(ch),
  850.                             ch->m_speed_hack_count);
  851.                     ch->ChatPacket(CHAT_TYPE_INFO, "Attack Speed Hack(%s), (delta, limit)=(%u, %u), hack_count = %d",
  852.                             ch->GetName(),
  853.                             current_time - victim->m_AttackedLog.dwAttackedTime,
  854.                             GET_ATTACK_SPEED(ch),
  855.                             ch->m_speed_hack_count);
  856.                 }
  857. #if defined(ENABLE_BAN_WAITHACK)&&defined(ENABLE_WAITHACK_DETECT)
  858.                 std::auto_ptr<SQLMsg> msg(DBManager::instance().DirectQuery("UPDATE account.account SET status= 'BLOCK' WHERE id = %d", ch->GetDesc()->GetAccountTable().id));
  859. #endif
  860. #ifdef ENABLE_WAITHACK_DETECT
  861.                 ch->GetDesc()->DelayedDisconnect(3);
  862.                 }
  863. #endif
  864.             SET_ATTACKED_TIME(ch, victim, current_time);
  865.             return true;
  866.         }
  867.     }
  868.  
  869.     SET_ATTACKED_TIME(ch, victim, current_time);
  870.     return false;
  871. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement