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