Guest User

Untitled

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