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

char_skill.cpp