Guest User

Untitled

a guest
Apr 13th, 2019
188
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 103.14 KB | None | 0 0
  1. #include "stdafx.h"
  2. #include "constants.h"
  3. #include "config.h"
  4. #include "utils.h"
  5. #include "desc_client.h"
  6. #include "desc_manager.h"
  7. #include "buffer_manager.h"
  8. #include "packet.h"
  9. #include "protocol.h"
  10. #include "char.h"
  11. #include "char_manager.h"
  12. #include "item.h"
  13. #include "item_manager.h"
  14. #include "cmd.h"
  15. #include "shop.h"
  16. #include "shop_manager.h"
  17. #include "safebox.h"
  18. #include "regen.h"
  19. #include "battle.h"
  20. #include "exchange.h"
  21. #include "questmanager.h"
  22. #include "profiler.h"
  23. #include "messenger_manager.h"
  24. #include "party.h"
  25. #include "p2p.h"
  26. #include "affect.h"
  27. #include "guild.h"
  28. #include "guild_manager.h"
  29. #include "log.h"
  30. #include "banword.h"
  31. #include "empire_text_convert.h"
  32. #include "unique_item.h"
  33. #include "building.h"
  34. #include "locale_service.h"
  35. #include "gm.h"
  36. #include "spam.h"
  37. #include "ani.h"
  38. #include "motion.h"
  39. #include "OXEvent.h"
  40. #include "locale_service.h"
  41. #include "HackShield.h"
  42. #include "XTrapManager.h"
  43. #include "DragonSoul.h"
  44. #include "offline_shop.h"
  45. #include "offlineshop_manager.h"
  46. #include "New_PetSystem.h"
  47. #include "../common/VnumHelper.h"
  48.  
  49. extern void SendShout(const char * szText, BYTE bEmpire);
  50. extern int g_nPortalLimitTime;
  51.  
  52. static int __deposit_limit()
  53. {
  54. return (1000*10000);
  55. }
  56.  
  57. void CInputMain::TargetInfoLoad(LPCHARACTER ch, const char* c_pData)
  58. {
  59. TPacketCGTargetInfoLoad* p = (TPacketCGTargetInfoLoad*)c_pData;
  60. TPacketGCTargetInfo pInfo;
  61. pInfo.header = HEADER_GC_TARGET_INFO;
  62. static std::vector<LPITEM> s_vec_item;
  63. s_vec_item.clear();
  64. LPITEM pkInfoItem;
  65. LPCHARACTER m_pkChrTarget = CHARACTER_MANAGER::instance().Find(p->dwVID);
  66.  
  67. if (!ch || !m_pkChrTarget)
  68. return;
  69.  
  70. if (ITEM_MANAGER::instance().CreateDropItemVector(m_pkChrTarget, ch, s_vec_item) && (m_pkChrTarget->IsMonster() || m_pkChrTarget->IsStone()))
  71. {
  72. if (s_vec_item.size() == 0);
  73. else if (s_vec_item.size() == 1)
  74. {
  75. pkInfoItem = s_vec_item[0];
  76. pInfo.dwVID = m_pkChrTarget->GetVID();
  77. pInfo.race = m_pkChrTarget->GetRaceNum();
  78. pInfo.dwVnum = pkInfoItem->GetVnum();
  79. pInfo.count = pkInfoItem->GetCount();
  80. ch->GetDesc()->Packet(&pInfo, sizeof(TPacketGCTargetInfo));
  81. }
  82. else
  83. {
  84. int iItemIdx = s_vec_item.size() - 1;
  85. while (iItemIdx >= 0)
  86. {
  87. pkInfoItem = s_vec_item[iItemIdx--];
  88.  
  89. if (!pkInfoItem)
  90. {
  91. sys_err("pkInfoItem null in vector idx %d", iItemIdx + 1);
  92. continue;
  93. }
  94.  
  95. pInfo.dwVID = m_pkChrTarget->GetVID();
  96. pInfo.race = m_pkChrTarget->GetRaceNum();
  97. pInfo.dwVnum = pkInfoItem->GetVnum();
  98. pInfo.count = pkInfoItem->GetCount();
  99. ch->GetDesc()->Packet(&pInfo, sizeof(TPacketGCTargetInfo));
  100. }
  101. }
  102. }
  103. }
  104.  
  105. void SendBlockChatInfo(LPCHARACTER ch, int sec)
  106. {
  107. if (sec <= 0)
  108. {
  109. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("채팅 금지 상태입니다."));
  110. return;
  111. }
  112.  
  113. long hour = sec / 3600;
  114. sec -= hour * 3600;
  115.  
  116. long min = (sec / 60);
  117. sec -= min * 60;
  118.  
  119. char buf[128+1];
  120.  
  121. if (hour > 0 && min > 0)
  122. snprintf(buf, sizeof(buf), LC_TEXT("%d 시간 %d 분 %d 초 동안 채팅금지 상태입니다"), hour, min, sec);
  123. else if (hour > 0 && min == 0)
  124. snprintf(buf, sizeof(buf), LC_TEXT("%d 시간 %d 초 동안 채팅금지 상태입니다"), hour, sec);
  125. else if (hour == 0 && min > 0)
  126. snprintf(buf, sizeof(buf), LC_TEXT("%d 분 %d 초 동안 채팅금지 상태입니다"), min, sec);
  127. else
  128. snprintf(buf, sizeof(buf), LC_TEXT("%d 초 동안 채팅금지 상태입니다"), sec);
  129.  
  130. ch->ChatPacket(CHAT_TYPE_INFO, buf);
  131. }
  132.  
  133. EVENTINFO(spam_event_info)
  134. {
  135. char host[MAX_HOST_LENGTH+1];
  136.  
  137. spam_event_info()
  138. {
  139. ::memset( host, 0, MAX_HOST_LENGTH+1 );
  140. }
  141. };
  142.  
  143. typedef boost::unordered_map<std::string, std::pair<unsigned int, LPEVENT> > spam_score_of_ip_t;
  144. spam_score_of_ip_t spam_score_of_ip;
  145.  
  146. EVENTFUNC(block_chat_by_ip_event)
  147. {
  148. spam_event_info* info = dynamic_cast<spam_event_info*>( event->info );
  149.  
  150. if ( info == NULL )
  151. {
  152. sys_err( "block_chat_by_ip_event> <Factor> Null pointer" );
  153. return 0;
  154. }
  155.  
  156. const char * host = info->host;
  157.  
  158. spam_score_of_ip_t::iterator it = spam_score_of_ip.find(host);
  159.  
  160. if (it != spam_score_of_ip.end())
  161. {
  162. it->second.first = 0;
  163. it->second.second = NULL;
  164. }
  165.  
  166. return 0;
  167. }
  168.  
  169. bool SpamBlockCheck(LPCHARACTER ch, const char* const buf, const size_t buflen)
  170. {
  171. extern int g_iSpamBlockMaxLevel;
  172.  
  173. if (ch->GetLevel() < g_iSpamBlockMaxLevel)
  174. {
  175. spam_score_of_ip_t::iterator it = spam_score_of_ip.find(ch->GetDesc()->GetHostName());
  176.  
  177. if (it == spam_score_of_ip.end())
  178. {
  179. spam_score_of_ip.insert(std::make_pair(ch->GetDesc()->GetHostName(), std::make_pair(0, (LPEVENT) NULL)));
  180. it = spam_score_of_ip.find(ch->GetDesc()->GetHostName());
  181. }
  182.  
  183. if (it->second.second)
  184. {
  185. SendBlockChatInfo(ch, event_time(it->second.second) / passes_per_sec);
  186. return true;
  187. }
  188.  
  189. unsigned int score;
  190. const char * word = SpamManager::instance().GetSpamScore(buf, buflen, score);
  191.  
  192. it->second.first += score;
  193.  
  194. if (word)
  195. sys_log(0, "SPAM_SCORE: %s text: %s score: %u total: %u word: %s", ch->GetName(), buf, score, it->second.first, word);
  196.  
  197. extern unsigned int g_uiSpamBlockScore;
  198. extern unsigned int g_uiSpamBlockDuration;
  199.  
  200. if (it->second.first >= g_uiSpamBlockScore)
  201. {
  202. spam_event_info* info = AllocEventInfo<spam_event_info>();
  203. strlcpy(info->host, ch->GetDesc()->GetHostName(), sizeof(info->host));
  204.  
  205. it->second.second = event_create(block_chat_by_ip_event, info, PASSES_PER_SEC(g_uiSpamBlockDuration));
  206. sys_log(0, "SPAM_IP: %s for %u seconds", info->host, g_uiSpamBlockDuration);
  207.  
  208. LogManager::instance().CharLog(ch, 0, "SPAM", word);
  209.  
  210. SendBlockChatInfo(ch, event_time(it->second.second) / passes_per_sec);
  211.  
  212. return true;
  213. }
  214. }
  215.  
  216. return false;
  217. }
  218.  
  219. enum
  220. {
  221. TEXT_TAG_PLAIN,
  222. TEXT_TAG_TAG, // ||
  223. TEXT_TAG_COLOR, // |cffffffff
  224. TEXT_TAG_HYPERLINK_START, // |H
  225. TEXT_TAG_HYPERLINK_END, // |h ex) |Hitem:1234:1:1:1|h
  226. TEXT_TAG_RESTORE_COLOR,
  227. };
  228.  
  229. int GetTextTag(const char * src, int maxLen, int & tagLen, std::string & extraInfo)
  230. {
  231. tagLen = 1;
  232.  
  233. if (maxLen < 2 || *src != '|')
  234. return TEXT_TAG_PLAIN;
  235.  
  236. const char * cur = ++src;
  237.  
  238. if (*cur == '|') // ||는 |로 표시한다.
  239. {
  240. tagLen = 2;
  241. return TEXT_TAG_TAG;
  242. }
  243. else if (*cur == 'c') // color |cffffffffblahblah|r
  244. {
  245. tagLen = 2;
  246. return TEXT_TAG_COLOR;
  247. }
  248. else if (*cur == 'H') // hyperlink |Hitem:10000:0:0:0:0|h[이름]|h
  249. {
  250. tagLen = 2;
  251. return TEXT_TAG_HYPERLINK_START;
  252. }
  253. else if (*cur == 'h') // end of hyperlink
  254. {
  255. tagLen = 2;
  256. return TEXT_TAG_HYPERLINK_END;
  257. }
  258.  
  259. return TEXT_TAG_PLAIN;
  260. }
  261.  
  262. void GetTextTagInfo(const char * src, int src_len, int & hyperlinks, bool & colored)
  263. {
  264. colored = false;
  265. hyperlinks = 0;
  266.  
  267. int len;
  268. std::string extraInfo;
  269.  
  270. for (int i = 0; i < src_len;)
  271. {
  272. int tag = GetTextTag(&src[i], src_len - i, len, extraInfo);
  273.  
  274. if (tag == TEXT_TAG_HYPERLINK_START)
  275. ++hyperlinks;
  276.  
  277. if (tag == TEXT_TAG_COLOR)
  278. colored = true;
  279.  
  280. i += len;
  281. }
  282. }
  283.  
  284. int ProcessTextTag(LPCHARACTER ch, const char * c_pszText, size_t len)
  285. {
  286. //2012.05.17 김용욱
  287. //0 : 정상적으로 사용
  288. //1 : 금강경 부족
  289. //2 : 금강경이 있으나, 개인상점에서 사용중
  290. //3 : 교환중
  291. //4 : 에러
  292. int hyperlinks;
  293. bool colored;
  294.  
  295. GetTextTagInfo(c_pszText, len, hyperlinks, colored);
  296.  
  297. if (colored == true && hyperlinks == 0)
  298. return 4;
  299.  
  300. if (ch->GetExchange())
  301. {
  302. if (hyperlinks == 0)
  303. return 0;
  304. else
  305. return 3;
  306. }
  307.  
  308. int nPrismCount = ch->CountSpecifyItem(ITEM_PRISM);
  309.  
  310. if (nPrismCount < hyperlinks)
  311. return 1;
  312.  
  313.  
  314. if (!ch->GetMyShop())
  315. {
  316. ch->RemoveSpecifyItem(ITEM_PRISM, hyperlinks);
  317. return 0;
  318. } else
  319. {
  320. int sellingNumber = ch->GetMyShop()->GetNumberByVnum(ITEM_PRISM);
  321. if(nPrismCount - sellingNumber < hyperlinks)
  322. {
  323. return 2;
  324. } else
  325. {
  326. ch->RemoveSpecifyItem(ITEM_PRISM, hyperlinks);
  327. return 0;
  328. }
  329. }
  330.  
  331. return 4;
  332. }
  333.  
  334. int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes)
  335. {
  336. const TPacketCGWhisper* pinfo = reinterpret_cast<const TPacketCGWhisper*>(data);
  337.  
  338. if (uiBytes < pinfo->wSize)
  339. return -1;
  340.  
  341. int iExtraLen = pinfo->wSize - sizeof(TPacketCGWhisper);
  342.  
  343. if (iExtraLen < 0)
  344. {
  345. sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->wSize, uiBytes);
  346. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  347. return -1;
  348. }
  349.  
  350. if (ch->GetLastPMPulse() < thecore_pulse())
  351. ch->ClearPMCounter();
  352.  
  353. if (ch->GetPMCounter() > 3 && ch->GetLastPMPulse() > thecore_pulse())
  354. {
  355. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  356. return -1;
  357. }
  358.  
  359. /* if (ch->IncreaseChatCounter() >= 10)
  360. {
  361. ch->GetDesc()->DelayedDisconnect(0);
  362. return (iExtraLen);
  363. }*/
  364.  
  365. if (ch->FindAffect(AFFECT_BLOCK_CHAT))
  366. {
  367. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("채팅 금지 상태입니다."));
  368. return (iExtraLen);
  369. }
  370.  
  371. LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindPC(pinfo->szNameTo);
  372.  
  373. if (pkChr == ch)
  374. return (iExtraLen);
  375.  
  376. ch->IncreasePMCounter();
  377. ch->SetLastPMPulse();
  378.  
  379. LPDESC pkDesc = NULL;
  380.  
  381. BYTE bOpponentEmpire = 0;
  382.  
  383. if (test_server)
  384. {
  385. if (!pkChr)
  386. sys_log(0, "Whisper to %s(%s) from %s", "Null", pinfo->szNameTo, ch->GetName());
  387. else
  388. sys_log(0, "Whisper to %s(%s) from %s", pkChr->GetName(), pinfo->szNameTo, ch->GetName());
  389. }
  390.  
  391. if (ch->IsBlockMode(BLOCK_WHISPER))
  392. {
  393. if (ch->GetDesc())
  394. {
  395. TPacketGCWhisper pack;
  396. pack.bHeader = HEADER_GC_WHISPER;
  397. pack.bType = WHISPER_TYPE_SENDER_BLOCKED;
  398. pack.wSize = sizeof(TPacketGCWhisper);
  399. strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom));
  400. ch->GetDesc()->Packet(&pack, sizeof(pack));
  401. }
  402. return iExtraLen;
  403. }
  404.  
  405. if (!pkChr)
  406. {
  407. CCI * pkCCI = P2P_MANAGER::instance().Find(pinfo->szNameTo);
  408.  
  409. if (pkCCI)
  410. {
  411. pkDesc = pkCCI->pkDesc;
  412. pkDesc->SetRelay(pinfo->szNameTo);
  413. bOpponentEmpire = pkCCI->bEmpire;
  414.  
  415. if (test_server)
  416. sys_log(0, "Whisper to %s from %s (Channel %d Mapindex %d)", "Null", ch->GetName(), pkCCI->bChannel, pkCCI->lMapIndex);
  417. }
  418. }
  419. else
  420. {
  421. pkDesc = pkChr->GetDesc();
  422. bOpponentEmpire = pkChr->GetEmpire();
  423. }
  424.  
  425. if (!pkDesc)
  426. {
  427. if (ch->GetDesc())
  428. {
  429. TPacketGCWhisper pack;
  430.  
  431. pack.bHeader = HEADER_GC_WHISPER;
  432. pack.bType = WHISPER_TYPE_NOT_EXIST;
  433. pack.wSize = sizeof(TPacketGCWhisper);
  434. strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom));
  435. ch->GetDesc()->Packet(&pack, sizeof(TPacketGCWhisper));
  436. sys_log(0, "WHISPER: no player");
  437. }
  438. }
  439. else
  440. {
  441. if (ch->IsBlockMode(BLOCK_WHISPER))
  442. {
  443. if (ch->GetDesc())
  444. {
  445. TPacketGCWhisper pack;
  446. pack.bHeader = HEADER_GC_WHISPER;
  447. pack.bType = WHISPER_TYPE_SENDER_BLOCKED;
  448. pack.wSize = sizeof(TPacketGCWhisper);
  449. strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom));
  450. ch->GetDesc()->Packet(&pack, sizeof(pack));
  451. }
  452. }
  453. else if (pkChr && pkChr->IsBlockMode(BLOCK_WHISPER))
  454. {
  455. if (ch->GetDesc())
  456. {
  457. TPacketGCWhisper pack;
  458. pack.bHeader = HEADER_GC_WHISPER;
  459. pack.bType = WHISPER_TYPE_TARGET_BLOCKED;
  460. pack.wSize = sizeof(TPacketGCWhisper);
  461. strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom));
  462. ch->GetDesc()->Packet(&pack, sizeof(pack));
  463. }
  464. }
  465. else
  466. {
  467. BYTE bType = WHISPER_TYPE_NORMAL;
  468.  
  469. char buf[CHAT_MAX_LEN + 1];
  470. strlcpy(buf, data + sizeof(TPacketCGWhisper), MIN(iExtraLen + 1, sizeof(buf)));
  471. const size_t buflen = strlen(buf);
  472.  
  473. if (true == SpamBlockCheck(ch, buf, buflen))
  474. {
  475. if (!pkChr)
  476. {
  477. CCI * pkCCI = P2P_MANAGER::instance().Find(pinfo->szNameTo);
  478.  
  479. if (pkCCI)
  480. {
  481. pkDesc->SetRelay("");
  482. }
  483. }
  484. return iExtraLen;
  485. }
  486.  
  487. if (LC_IsCanada() == false)
  488. {
  489. CBanwordManager::instance().ConvertString(buf, buflen);
  490. }
  491.  
  492. if (g_bEmpireWhisper)
  493. if (!ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
  494. if (!(pkChr && pkChr->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)))
  495. if (bOpponentEmpire != ch->GetEmpire() && ch->GetEmpire() && bOpponentEmpire
  496. && ch->GetGMLevel() == GM_PLAYER && gm_get_level(pinfo->szNameTo) == GM_PLAYER)
  497. {
  498. if (!pkChr)
  499. bType = ch->GetEmpire() << 4;
  500. }
  501.  
  502. int processReturn = ProcessTextTag(ch, buf, buflen);
  503. if (0!=processReturn)
  504. {
  505. if (ch->GetDesc())
  506. {
  507. TItemTable * pTable = ITEM_MANAGER::instance().GetTable(ITEM_PRISM);
  508.  
  509. if (pTable)
  510. {
  511. char buf[128];
  512. int len;
  513. if (3==processReturn) //교환중
  514. len = snprintf(buf, sizeof(buf), LC_TEXT("다른 거래중(창고,교환,상점)에는 개인상점을 사용할 수 없습니다."), pTable->szLocaleName);
  515. else
  516. len = snprintf(buf, sizeof(buf), LC_TEXT("%s이 필요합니다."), pTable->szLocaleName);
  517.  
  518.  
  519. if (len < 0 || len >= (int) sizeof(buf))
  520. len = sizeof(buf) - 1;
  521.  
  522. ++len; // \0 문자 포함
  523.  
  524. TPacketGCWhisper pack;
  525.  
  526. pack.bHeader = HEADER_GC_WHISPER;
  527. pack.bType = WHISPER_TYPE_ERROR;
  528. pack.wSize = sizeof(TPacketGCWhisper) + len;
  529. strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom));
  530.  
  531. ch->GetDesc()->BufferedPacket(&pack, sizeof(pack));
  532. ch->GetDesc()->Packet(buf, len);
  533.  
  534. sys_log(0, "WHISPER: not enough %s: char: %s", pTable->szLocaleName, ch->GetName());
  535. }
  536. }
  537.  
  538. // 릴래이 상태일 수 있으므로 릴래이를 풀어준다.
  539. pkDesc->SetRelay("");
  540. return (iExtraLen);
  541. }
  542.  
  543. if (ch->IsGM())
  544. bType = (bType & 0xF0) | WHISPER_TYPE_GM;
  545.  
  546. if (buflen > 0)
  547. {
  548. TPacketGCWhisper pack;
  549.  
  550. pack.bHeader = HEADER_GC_WHISPER;
  551. pack.wSize = sizeof(TPacketGCWhisper) + buflen;
  552. pack.bType = bType;
  553. strlcpy(pack.szNameFrom, ch->GetName(), sizeof(pack.szNameFrom));
  554.  
  555. // desc->BufferedPacket을 하지 않고 버퍼에 써야하는 이유는
  556. // P2P relay되어 패킷이 캡슐화 될 수 있기 때문이다.
  557. TEMP_BUFFER tmpbuf;
  558.  
  559. tmpbuf.write(&pack, sizeof(pack));
  560. tmpbuf.write(buf, buflen);
  561.  
  562. pkDesc->Packet(tmpbuf.read_peek(), tmpbuf.size());
  563.  
  564. if (LC_IsEurope() != true)
  565. {
  566. sys_log(0, "WHISPER: %s -> %s : %s", ch->GetName(), pinfo->szNameTo, buf);
  567. }
  568. }
  569. }
  570. }
  571. if(pkDesc)
  572. pkDesc->SetRelay("");
  573.  
  574. return (iExtraLen);
  575. }
  576.  
  577. struct RawPacketToCharacterFunc
  578. {
  579. const void * m_buf;
  580. int m_buf_len;
  581.  
  582. RawPacketToCharacterFunc(const void * buf, int buf_len) : m_buf(buf), m_buf_len(buf_len)
  583. {
  584. }
  585.  
  586. void operator () (LPCHARACTER c)
  587. {
  588. if (!c->GetDesc())
  589. return;
  590.  
  591. c->GetDesc()->Packet(m_buf, m_buf_len);
  592. }
  593. };
  594.  
  595. struct FEmpireChatPacket
  596. {
  597. packet_chat& p;
  598. const char* orig_msg;
  599. int orig_len;
  600. char converted_msg[CHAT_MAX_LEN+1];
  601.  
  602. BYTE bEmpire;
  603. int iMapIndex;
  604. int namelen;
  605.  
  606. FEmpireChatPacket(packet_chat& p, const char* chat_msg, int len, BYTE bEmpire, int iMapIndex, int iNameLen)
  607. : p(p), orig_msg(chat_msg), orig_len(len), bEmpire(bEmpire), iMapIndex(iMapIndex), namelen(iNameLen)
  608. {
  609. memset( converted_msg, 0, sizeof(converted_msg) );
  610. }
  611.  
  612. void operator () (LPDESC d)
  613. {
  614. if (!d->GetCharacter())
  615. return;
  616.  
  617. if (d->GetCharacter()->GetMapIndex() != iMapIndex)
  618. return;
  619.  
  620. d->BufferedPacket(&p, sizeof(packet_chat));
  621.  
  622. if (d->GetEmpire() == bEmpire ||
  623. bEmpire == 0 ||
  624. d->GetCharacter()->GetGMLevel() > GM_PLAYER ||
  625. d->GetCharacter()->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
  626. {
  627. d->Packet(orig_msg, orig_len);
  628. }
  629. else
  630. {
  631. d->Packet(orig_msg, orig_len);
  632. }
  633. }
  634. };
  635.  
  636. struct FYmirChatPacket
  637. {
  638. packet_chat& packet;
  639. const char* m_szChat;
  640. size_t m_lenChat;
  641. const char* m_szName;
  642.  
  643. int m_iMapIndex;
  644. BYTE m_bEmpire;
  645. bool m_ring;
  646.  
  647. char m_orig_msg[CHAT_MAX_LEN+1];
  648. int m_len_orig_msg;
  649. char m_conv_msg[CHAT_MAX_LEN+1];
  650. int m_len_conv_msg;
  651.  
  652. FYmirChatPacket(packet_chat& p, const char* chat, size_t len_chat, const char* name, size_t len_name, int iMapIndex, BYTE empire, bool ring)
  653. : packet(p),
  654. m_szChat(chat), m_lenChat(len_chat),
  655. m_szName(name),
  656. m_iMapIndex(iMapIndex), m_bEmpire(empire),
  657. m_ring(ring)
  658. {
  659. m_len_orig_msg = snprintf(m_orig_msg, sizeof(m_orig_msg), "%s : %s", m_szName, m_szChat) + 1; // 널 문자 포함
  660.  
  661. if (m_len_orig_msg < 0 || m_len_orig_msg >= (int) sizeof(m_orig_msg))
  662. m_len_orig_msg = sizeof(m_orig_msg) - 1;
  663.  
  664. m_len_conv_msg = snprintf(m_conv_msg, sizeof(m_conv_msg), "??? : %s", m_szChat) + 1; // 널 문자 미포함
  665.  
  666. if (m_len_conv_msg < 0 || m_len_conv_msg >= (int) sizeof(m_conv_msg))
  667. m_len_conv_msg = sizeof(m_conv_msg) - 1;
  668.  
  669. ConvertEmpireText(m_bEmpire, m_conv_msg + 6, m_len_conv_msg - 6, 10); // 6은 "??? : "의 길이
  670. }
  671.  
  672. void operator() (LPDESC d)
  673. {
  674. if (!d->GetCharacter())
  675. return;
  676.  
  677. if (d->GetCharacter()->GetMapIndex() != m_iMapIndex)
  678. return;
  679.  
  680. if (m_ring ||
  681. d->GetEmpire() == m_bEmpire ||
  682. d->GetCharacter()->GetGMLevel() > GM_PLAYER ||
  683. d->GetCharacter()->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))
  684. {
  685. packet.size = m_len_orig_msg + sizeof(TPacketGCChat);
  686.  
  687. d->BufferedPacket(&packet, sizeof(packet_chat));
  688. d->Packet(m_orig_msg, m_len_orig_msg);
  689. }
  690. else
  691. {
  692. packet.size = m_len_conv_msg + sizeof(TPacketGCChat);
  693.  
  694. d->BufferedPacket(&packet, sizeof(packet_chat));
  695. d->Packet(m_conv_msg, m_len_conv_msg);
  696. }
  697. }
  698. };
  699.  
  700. void CInputMain::BraveRequestPetName(LPCHARACTER ch, const char* c_pData)
  701. {
  702. if (!ch->GetDesc())
  703. return;
  704.  
  705. int vid = ch->GetEggVid();
  706. if (vid == 0)
  707. return;
  708.  
  709. TPacketCGRequestPetName* p = (TPacketCGRequestPetName*)c_pData;
  710.  
  711. if (ch->GetGold() < 100000)
  712. ch->ChatPacket(CHAT_TYPE_INFO, "[PetSystem] Ai nevoie de 100.000 yang");
  713.  
  714. if (ch->CountSpecifyItem(vid) > 0 && check_name(p->petname) != 0)
  715. {
  716. DBManager::instance().SendMoneyLog(MONEY_LOG_QUEST, ch->GetPlayerID(), -100000);
  717. ch->PointChange(POINT_GOLD, -100000, true);
  718. ch->RemoveSpecifyItem(vid, 1);
  719. LPITEM item = ch->AutoGiveItem(vid + 300, 1);
  720. int tmpslot = number(1, 3);
  721. int tmpskill[3] = { 0, 0, 0 };
  722. for (int i = 0; i < 3; ++i)
  723. {
  724. if (i > tmpslot - 1)
  725. tmpskill[i] = -1;
  726. }
  727. int tmpdur = number(1, 14) * 24 * 60;
  728. char szQuery1[1024];
  729. snprintf(szQuery1, sizeof(szQuery1), "INSERT INTO new_petsystem VALUES(%d,'%s', 1, 0, 0, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d, %d)", item->GetID(), p->petname, number(1, 23), number(1, 23), number(1, 23), tmpskill[0], 0, tmpskill[1], 0, tmpskill[2], 0, tmpdur, tmpdur);
  730. std::auto_ptr<SQLMsg> pmsg2(DBManager::instance().DirectQuery(szQuery1));
  731. }
  732. else
  733. ch->ChatPacket(CHAT_TYPE_INFO, "[PetSystem]Eroare in setarea numelui");
  734. }
  735.  
  736. int CInputMain::Chat(LPCHARACTER ch, const char * data, size_t uiBytes)
  737. {
  738. const TPacketCGChat* pinfo = reinterpret_cast<const TPacketCGChat*>(data);
  739.  
  740. if (uiBytes < pinfo->size)
  741. return -1;
  742.  
  743. const int iExtraLen = pinfo->size - sizeof(TPacketCGChat);
  744.  
  745. if (iExtraLen < 0)
  746. {
  747. sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->size, uiBytes);
  748. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  749. return -1;
  750. }
  751.  
  752. char buf[CHAT_MAX_LEN - (CHARACTER_NAME_MAX_LEN + 3) + 1];
  753. strlcpy(buf, data + sizeof(TPacketCGChat), MIN(iExtraLen + 1, sizeof(buf)));
  754. const size_t buflen = strlen(buf);
  755.  
  756. if (buflen > 1 && *buf == '/')
  757. {
  758. interpret_command(ch, buf + 1, buflen - 1);
  759. return iExtraLen;
  760. }
  761.  
  762. if (ch->IncreaseChatCounter() >= 10)
  763. {
  764. if (ch->GetChatCounter() == 10)
  765. {
  766. sys_log(0, "CHAT_HACK: %s", ch->GetName());
  767. ch->GetDesc()->DelayedDisconnect(5);
  768. }
  769.  
  770. return iExtraLen;
  771. }
  772.  
  773. // 채팅 금지 Affect 처리
  774. const CAffect* pAffect = ch->FindAffect(AFFECT_BLOCK_CHAT);
  775.  
  776. if (pAffect != NULL)
  777. {
  778. SendBlockChatInfo(ch, pAffect->lDuration);
  779. return iExtraLen;
  780. }
  781.  
  782. if (true == SpamBlockCheck(ch, buf, buflen))
  783. {
  784. return iExtraLen;
  785. }
  786.  
  787. char chatbuf[CHAT_MAX_LEN + 1];
  788. int len = snprintf(chatbuf, sizeof(chatbuf), "%s : %s", ch->GetName(), buf);
  789.  
  790. if (CHAT_TYPE_SHOUT == pinfo->type)
  791. {
  792. LogManager::instance().ShoutLog(g_bChannel, ch->GetEmpire(), chatbuf);
  793. }
  794.  
  795. if (LC_IsCanada() == false)
  796. {
  797. CBanwordManager::instance().ConvertString(buf, buflen);
  798. }
  799.  
  800. if (len < 0 || len >= (int) sizeof(chatbuf))
  801. len = sizeof(chatbuf) - 1;
  802.  
  803. int processReturn = ProcessTextTag(ch, chatbuf, len);
  804. if (0!=processReturn)
  805. {
  806. const TItemTable* pTable = ITEM_MANAGER::instance().GetTable(ITEM_PRISM);
  807.  
  808. if (NULL != pTable)
  809. {
  810. if (3==processReturn) //교환중
  811. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중(창고,교환,상점)에는 개인상점을 사용할 수 없습니다."), pTable->szLocaleName);
  812. else
  813. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s이 필요합니다."), pTable->szLocaleName);
  814.  
  815. }
  816.  
  817. return iExtraLen;
  818. }
  819.  
  820. if (pinfo->type == CHAT_TYPE_SHOUT)
  821. {
  822. const int SHOUT_LIMIT_LEVEL = g_iUseLocale ? 15 : 3;
  823.  
  824. if (ch->GetLevel() < SHOUT_LIMIT_LEVEL)
  825. {
  826. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("외치기는 레벨 %d 이상만 사용 가능 합니다."), SHOUT_LIMIT_LEVEL);
  827. return (iExtraLen);
  828. }
  829.  
  830. if (thecore_heart->pulse - (int) ch->GetLastShoutPulse() < passes_per_sec * 15)
  831. return (iExtraLen);
  832.  
  833. ch->SetLastShoutPulse(thecore_heart->pulse);
  834.  
  835. TPacketGGShout p;
  836.  
  837. p.bHeader = HEADER_GG_SHOUT;
  838. p.bEmpire = ch->GetEmpire();
  839. strlcpy(p.szText, chatbuf, sizeof(p.szText));
  840.  
  841. P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShout));
  842.  
  843. SendShout(chatbuf, ch->GetEmpire());
  844.  
  845. return (iExtraLen);
  846. }
  847.  
  848. TPacketGCChat pack_chat;
  849.  
  850. pack_chat.header = HEADER_GC_CHAT;
  851. pack_chat.size = sizeof(TPacketGCChat) + len;
  852. pack_chat.type = pinfo->type;
  853. pack_chat.id = ch->GetVID();
  854.  
  855. switch (pinfo->type)
  856. {
  857. case CHAT_TYPE_TALKING:
  858. {
  859. const DESC_MANAGER::DESC_SET & c_ref_set = DESC_MANAGER::instance().GetClientSet();
  860.  
  861. if (false)
  862. {
  863. std::for_each(c_ref_set.begin(), c_ref_set.end(),
  864. FYmirChatPacket(pack_chat,
  865. buf,
  866. strlen(buf),
  867. ch->GetName(),
  868. strlen(ch->GetName()),
  869. ch->GetMapIndex(),
  870. ch->GetEmpire(),
  871. ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)));
  872. }
  873. else
  874. {
  875. std::for_each(c_ref_set.begin(), c_ref_set.end(),
  876. FEmpireChatPacket(pack_chat,
  877. chatbuf,
  878. len,
  879. (ch->GetGMLevel() > GM_PLAYER ||
  880. ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) ? 0 : ch->GetEmpire(),
  881. ch->GetMapIndex(), strlen(ch->GetName())));
  882. }
  883. }
  884. break;
  885.  
  886. case CHAT_TYPE_PARTY:
  887. {
  888. if (!ch->GetParty())
  889. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("파티 중이 아닙니다."));
  890. else
  891. {
  892. TEMP_BUFFER tbuf;
  893.  
  894. tbuf.write(&pack_chat, sizeof(pack_chat));
  895. tbuf.write(chatbuf, len);
  896.  
  897. RawPacketToCharacterFunc f(tbuf.read_peek(), tbuf.size());
  898. ch->GetParty()->ForEachOnlineMember(f);
  899. }
  900. }
  901. break;
  902.  
  903. case CHAT_TYPE_GUILD:
  904. {
  905. if (!ch->GetGuild())
  906. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("길드에 가입하지 않았습니다."));
  907. else
  908. ch->GetGuild()->Chat(chatbuf);
  909. }
  910. break;
  911.  
  912. default:
  913. sys_err("Unknown chat type %d", pinfo->type);
  914. break;
  915. }
  916.  
  917. return (iExtraLen);
  918. }
  919.  
  920. void CInputMain::ItemUse(LPCHARACTER ch, const char * data)
  921. {
  922. ch->UseItem(((struct command_item_use *) data)->Cell);
  923. }
  924.  
  925. void CInputMain::ItemToItem(LPCHARACTER ch, const char * pcData)
  926. {
  927. TPacketCGItemUseToItem * p = (TPacketCGItemUseToItem *) pcData;
  928. if (ch)
  929. ch->UseItem(p->Cell, p->TargetCell);
  930. }
  931.  
  932. void CInputMain::ItemDrop(LPCHARACTER ch, const char * data)
  933. {
  934. struct command_item_drop * pinfo = (struct command_item_drop *) data;
  935.  
  936. //MONARCH_LIMIT
  937. //if (ch->IsMonarch())
  938. // return;
  939. //END_MONARCH_LIMIT
  940. if (!ch)
  941. return;
  942.  
  943. // 엘크가 0보다 크면 엘크를 버리는 것 이다.
  944. if (pinfo->gold > 0)
  945. ch->DropGold(pinfo->gold);
  946. else
  947. ch->DropItem(pinfo->Cell);
  948. }
  949.  
  950. void CInputMain::ItemDrop2(LPCHARACTER ch, const char * data)
  951. {
  952. //MONARCH_LIMIT
  953. //if (ch->IsMonarch())
  954. // return;
  955. //END_MONARCH_LIMIT
  956.  
  957. TPacketCGItemDrop2 * pinfo = (TPacketCGItemDrop2 *) data;
  958.  
  959. if (!ch)
  960. return;
  961. if (pinfo->gold > 0)
  962. ch->DropGold(pinfo->gold);
  963. else
  964. ch->DropItem(pinfo->Cell, pinfo->count);
  965. }
  966.  
  967. void CInputMain::ItemDestroy(LPCHARACTER ch, const char * data)
  968. {
  969. struct command_item_destroy * pinfo = (struct command_item_destroy *) data;
  970. if (ch)
  971. ch->DestroyItem(pinfo->Cell);
  972. }
  973.  
  974. void CInputMain::ItemMove(LPCHARACTER ch, const char * data)
  975. {
  976. struct command_item_move * pinfo = (struct command_item_move *) data;
  977.  
  978. if (ch)
  979. ch->MoveItem(pinfo->Cell, pinfo->CellTo, pinfo->count);
  980. }
  981.  
  982. void CInputMain::ItemPickup(LPCHARACTER ch, const char * data)
  983. {
  984. struct command_item_pickup * pinfo = (struct command_item_pickup*) data;
  985. if (ch)
  986. ch->PickupItem(pinfo->vid);
  987. }
  988.  
  989. void CInputMain::QuickslotAdd(LPCHARACTER ch, const char * data)
  990. {
  991. struct command_quickslot_add * pinfo = (struct command_quickslot_add *) data;
  992. if(pinfo->slot.type == QUICKSLOT_TYPE_ITEM)
  993. {
  994. LPITEM item = NULL;
  995.  
  996. TItemPos srcCell(INVENTORY, pinfo->slot.pos);
  997.  
  998. if (!(item = ch->GetItem(srcCell)))
  999. return;
  1000.  
  1001. if (item->GetType() != ITEM_USE && item->GetType() != ITEM_QUEST)
  1002. return;
  1003. }
  1004.  
  1005. ch->SetQuickslot(pinfo->pos, pinfo->slot);
  1006. }
  1007.  
  1008. void CInputMain::QuickslotDelete(LPCHARACTER ch, const char * data)
  1009. {
  1010. struct command_quickslot_del * pinfo = (struct command_quickslot_del *) data;
  1011. ch->DelQuickslot(pinfo->pos);
  1012. }
  1013.  
  1014. void CInputMain::QuickslotSwap(LPCHARACTER ch, const char * data)
  1015. {
  1016. struct command_quickslot_swap * pinfo = (struct command_quickslot_swap *) data;
  1017. ch->SwapQuickslot(pinfo->pos, pinfo->change_pos);
  1018. }
  1019.  
  1020. int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes)
  1021. {
  1022. TPacketCGMessenger* p = (TPacketCGMessenger*) c_pData;
  1023.  
  1024. if (uiBytes < sizeof(TPacketCGMessenger))
  1025. return -1;
  1026.  
  1027. c_pData += sizeof(TPacketCGMessenger);
  1028. uiBytes -= sizeof(TPacketCGMessenger);
  1029.  
  1030. switch (p->subheader)
  1031. {
  1032. case MESSENGER_SUBHEADER_CG_ADD_BY_VID:
  1033. {
  1034. if (uiBytes < sizeof(TPacketCGMessengerAddByVID))
  1035. return -1;
  1036.  
  1037. TPacketCGMessengerAddByVID * p2 = (TPacketCGMessengerAddByVID *) c_pData;
  1038. LPCHARACTER ch_companion = CHARACTER_MANAGER::instance().Find(p2->vid);
  1039.  
  1040. if (!ch_companion)
  1041. return sizeof(TPacketCGMessengerAddByVID);
  1042.  
  1043. if (ch->IsObserverMode())
  1044. return sizeof(TPacketCGMessengerAddByVID);
  1045.  
  1046. if (ch_companion->IsBlockMode(BLOCK_MESSENGER_INVITE))
  1047. {
  1048. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 메신져 추가 거부 상태입니다."));
  1049. return sizeof(TPacketCGMessengerAddByVID);
  1050. }
  1051.  
  1052. LPDESC d = ch_companion->GetDesc();
  1053.  
  1054. if (!d)
  1055. return sizeof(TPacketCGMessengerAddByVID);
  1056.  
  1057. if (ch->GetGMLevel() == GM_PLAYER && ch_companion->GetGMLevel() != GM_PLAYER)
  1058. {
  1059. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<메신져> 운영자는 메신져에 추가할 수 없습니다."));
  1060. return sizeof(TPacketCGMessengerAddByVID);
  1061. }
  1062.  
  1063. if (ch->GetDesc() == d) // 자신은 추가할 수 없다.
  1064. return sizeof(TPacketCGMessengerAddByVID);
  1065.  
  1066. MessengerManager::instance().RequestToAdd(ch, ch_companion);
  1067. //MessengerManager::instance().AddToList(ch->GetName(), ch_companion->GetName());
  1068. }
  1069. return sizeof(TPacketCGMessengerAddByVID);
  1070.  
  1071. case MESSENGER_SUBHEADER_CG_ADD_BY_NAME:
  1072. {
  1073. if (uiBytes < CHARACTER_NAME_MAX_LEN)
  1074. return -1;
  1075.  
  1076. char name[CHARACTER_NAME_MAX_LEN + 1];
  1077. strlcpy(name, c_pData, sizeof(name));
  1078.  
  1079. if (ch->GetGMLevel() == GM_PLAYER && gm_get_level(name) != GM_PLAYER)
  1080. {
  1081. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<메신져> 운영자는 메신져에 추가할 수 없습니다."));
  1082. return CHARACTER_NAME_MAX_LEN;
  1083. }
  1084.  
  1085. LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(name);
  1086.  
  1087. if (!tch)
  1088. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님은 접속되 있지 않습니다."), name);
  1089. else
  1090. {
  1091. if (tch == ch) // 자신은 추가할 수 없다.
  1092. return CHARACTER_NAME_MAX_LEN;
  1093.  
  1094. if (tch->IsBlockMode(BLOCK_MESSENGER_INVITE) == true)
  1095. {
  1096. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 메신져 추가 거부 상태입니다."));
  1097. }
  1098. else
  1099. {
  1100. // 메신저가 캐릭터단위가 되면서 변경
  1101. MessengerManager::instance().RequestToAdd(ch, tch);
  1102. //MessengerManager::instance().AddToList(ch->GetName(), tch->GetName());
  1103. }
  1104. }
  1105. }
  1106. return CHARACTER_NAME_MAX_LEN;
  1107.  
  1108. case MESSENGER_SUBHEADER_CG_REMOVE:
  1109. {
  1110. if (uiBytes < CHARACTER_NAME_MAX_LEN)
  1111. return -1;
  1112.  
  1113. char char_name[CHARACTER_NAME_MAX_LEN + 1];
  1114. strlcpy(char_name, c_pData, sizeof(char_name));
  1115. MessengerManager::instance().RemoveFromList(ch->GetName(), char_name);
  1116. }
  1117. return CHARACTER_NAME_MAX_LEN;
  1118.  
  1119. default:
  1120. sys_err("CInputMain::Messenger : Unknown subheader %d : %s", p->subheader, ch->GetName());
  1121. break;
  1122. }
  1123.  
  1124. return 0;
  1125. }
  1126.  
  1127. int CInputMain::Shop(LPCHARACTER ch, const char * data, size_t uiBytes)
  1128. {
  1129. TPacketCGShop * p = (TPacketCGShop *) data;
  1130.  
  1131. if (uiBytes < sizeof(TPacketCGShop))
  1132. return -1;
  1133.  
  1134. if (test_server)
  1135. sys_log(0, "CInputMain::Shop() ==> SubHeader %d", p->subheader);
  1136.  
  1137. const char * c_pData = data + sizeof(TPacketCGShop);
  1138. uiBytes -= sizeof(TPacketCGShop);
  1139.  
  1140. switch (p->subheader)
  1141. {
  1142. case SHOP_SUBHEADER_CG_END:
  1143. sys_log(1, "INPUT: %s SHOP: END", ch->GetName());
  1144. CShopManager::instance().StopShopping(ch);
  1145. return 0;
  1146.  
  1147. case SHOP_SUBHEADER_CG_BUY:
  1148. {
  1149. if (uiBytes < sizeof(BYTE) + sizeof(BYTE))
  1150. return -1;
  1151.  
  1152. BYTE bPos = *(c_pData + 1);
  1153. sys_log(1, "INPUT: %s SHOP: BUY %d", ch->GetName(), bPos);
  1154. CShopManager::instance().Buy(ch, bPos);
  1155. return (sizeof(BYTE) + sizeof(BYTE));
  1156. }
  1157.  
  1158. case SHOP_SUBHEADER_CG_SELL:
  1159. {
  1160. if (uiBytes < sizeof(BYTE))
  1161. return -1;
  1162.  
  1163. BYTE pos = *c_pData;
  1164.  
  1165. sys_log(0, "INPUT: %s SHOP: SELL", ch->GetName());
  1166. CShopManager::instance().Sell(ch, pos);
  1167. return sizeof(BYTE);
  1168. }
  1169.  
  1170. case SHOP_SUBHEADER_CG_SELL2:
  1171. {
  1172. if (uiBytes < sizeof(BYTE) + sizeof(BYTE))
  1173. return -1;
  1174.  
  1175. BYTE pos = *(c_pData++);
  1176. BYTE count = *(c_pData);
  1177.  
  1178. sys_log(0, "INPUT: %s SHOP: SELL2", ch->GetName());
  1179. CShopManager::instance().Sell(ch, pos, count);
  1180. return sizeof(BYTE) + sizeof(BYTE);
  1181. }
  1182.  
  1183. default:
  1184. sys_err("CInputMain::Shop : Unknown subheader %d : %s", p->subheader, ch->GetName());
  1185. break;
  1186. }
  1187.  
  1188. return 0;
  1189. }
  1190.  
  1191. int CInputMain::OfflineShop(LPCHARACTER ch, const char * data, size_t uiBytes)
  1192. {
  1193. TPacketCGShop * p = (TPacketCGShop *)data;
  1194.  
  1195. if (uiBytes < sizeof(TPacketCGShop))
  1196. return -1;
  1197.  
  1198. if (test_server)
  1199. sys_log(0, "CInputMain::OfflineShop ==> SubHeader %d", p->subheader);
  1200.  
  1201. const char * c_pData = data + sizeof(TPacketCGShop);
  1202. uiBytes -= sizeof(TPacketCGShop);
  1203.  
  1204. switch (p->subheader)
  1205. {
  1206. case SHOP_SUBHEADER_CG_END:
  1207. sys_log(1, "INPUT: %s OFFLINE_SHOP: END", ch->GetName());
  1208. COfflineShopManager::instance().StopShopping(ch);
  1209. return 0;
  1210. case SHOP_SUBHEADER_CG_BUY:
  1211. {
  1212. if (uiBytes < sizeof(BYTE) + sizeof(BYTE))
  1213. return -1;
  1214.  
  1215. BYTE bPos = *(c_pData + 1);
  1216. sys_log(1, "INPUT: %s OFFLINE_SHOP: BUY %d", ch->GetName(), bPos);
  1217. COfflineShopManager::instance().Buy(ch, bPos);
  1218. return (sizeof(BYTE) + sizeof(BYTE));
  1219. }
  1220. case SHOP_SUBHEADER_CG_CHANGE_EDIT_TIME:
  1221. {
  1222. if (uiBytes < sizeof(BYTE))
  1223. return -1;
  1224.  
  1225. BYTE bTime = *c_pData;
  1226. sys_log(0, "INPUT: %s EDIT_OFFLINE_SHOP_TIME", ch->GetName());
  1227. COfflineShopManager::instance().ChangeOfflineShopTime(ch, bTime);
  1228. return sizeof(BYTE);
  1229. }
  1230. case SHOP_SUBHEADER_CG_DESTROY_OFFLINE_SHOP:
  1231. sys_log(1, "INPUT: %s OFFLINE_SHOP_DESTROY", ch->GetName());
  1232. COfflineShopManager::instance().DestroyOfflineShop(ch, ch->GetOfflineShopVID(), true);
  1233. return 0;
  1234. case SHOP_SUBHEADER_CG_ADD_ITEM:
  1235. {
  1236. if (ch->GetOfflineShopStatus() == 0 || ch->GetOfflineShopStatus() == 1)
  1237. {
  1238. ch->ChatPacket(CHAT_TYPE_INFO, "Nu poti folosi aceasta fereastra!");
  1239. return 0;
  1240. }
  1241.  
  1242. if (uiBytes < sizeof(TOfflineShopItemTable2))
  1243. return -1;
  1244.  
  1245. TOfflineShopItemTable2 * pTable = (TOfflineShopItemTable2 *)(c_pData);
  1246. COfflineShopManager::instance().AddItem(ch, pTable->bDisplayPos, pTable->bPos, pTable->llPrice);
  1247. return (sizeof(TOfflineShopItemTable2));
  1248. }
  1249. case SHOP_SUBHEADER_CG_REMOVE_ITEM:
  1250. {
  1251. if (ch->GetOfflineShopStatus() == 0 || ch->GetOfflineShopStatus() == 1)
  1252. {
  1253. ch->ChatPacket(CHAT_TYPE_INFO, "Nu poti folosi aceasta fereastra!");
  1254. return 0;
  1255. }
  1256.  
  1257. if (uiBytes < sizeof(BYTE))
  1258. return -1;
  1259.  
  1260. BYTE bPos = *c_pData;
  1261. sys_log(0, "INPUT: %s REMOVE_ITEM : %d", ch->GetName(), bPos);
  1262. COfflineShopManager::instance().RemoveItem(ch, bPos);
  1263. return (sizeof(BYTE));
  1264. }
  1265. case SHOP_SUBHEADER_CG_CHANGE_PRICE:
  1266. {
  1267. if (ch->GetOfflineShopStatus() == 0 || ch->GetOfflineShopStatus() == 1)
  1268. {
  1269. ch->ChatPacket(CHAT_TYPE_INFO, "Nu poti folosi aceasta fereastra!");
  1270. return 0;
  1271. }
  1272.  
  1273. if (uiBytes < sizeof(TOfflineShopItemTable2))
  1274. return -1;
  1275.  
  1276. TOfflineShopItemTable2 * pTable = (TOfflineShopItemTable2 *)(c_pData);
  1277. sys_log(0, "INPUT: %s OFFLINE_CHANGE_PRICE(%lld)", ch->GetName(), pTable->bDisplayPos);
  1278. COfflineShopManager::instance().ChangePrice(ch, pTable->bDisplayPos, pTable->llPrice);
  1279. return (sizeof(TOfflineShopItemTable2));
  1280. }
  1281. case SHOP_SUBHEADER_CG_REFRESH:
  1282. if (ch->GetOfflineShopStatus() == 0 || ch->GetOfflineShopStatus() == 1)
  1283. return 0;
  1284.  
  1285. sys_log(0, "INPUT: %s OFFLINE_SHOP_REFRESH_ITEM", ch->GetName());
  1286. COfflineShopManager::instance().Refresh(ch);
  1287. return 0;
  1288. case SHOP_SUBHEADER_CG_REFRESH_MONEY:
  1289. {
  1290. sys_log(0, "INPUT: %s OFFLINE_SHOP_REFRESH_MONEY", ch->GetName());
  1291. COfflineShopManager::instance().RefreshMoney(ch);
  1292. return 0;
  1293. }
  1294. case SHOP_SUBHEADER_CG_WITHDRAW_MONEY:
  1295. {
  1296. if (uiBytes < sizeof(long long))
  1297. return -1;
  1298.  
  1299. const long long gold = *reinterpret_cast<const long long*>(c_pData);
  1300. sys_log(0, "INPUT: %s(%lld) OFFLINE_SHOP_WITHDRAW_MONEY", ch->GetName(), gold);
  1301. COfflineShopManager::instance().WithdrawMoney(ch, gold);
  1302. return (sizeof(long long));
  1303. }
  1304. case SHOP_SUBHEADER_CG_REFRESH_UNSOLD_ITEMS:
  1305. {
  1306. sys_log(0, "INPUT: %s OFFLINE_SHOP_REFRESH_UNSOLD_ITEMS", ch->GetName());
  1307. COfflineShopManager::instance().RefreshUnsoldItems(ch);
  1308. return 0;
  1309. }
  1310. case SHOP_SUBHEADER_CG_TAKE_ITEM:
  1311. {
  1312. if (uiBytes < sizeof(BYTE))
  1313. return -1;
  1314.  
  1315. BYTE bPos = *c_pData;
  1316. sys_log(0, "INPUT: %s OFFLINE_SHOP_TAKE_ITEM", ch->GetName());
  1317. COfflineShopManager::instance().TakeItem(ch, bPos);
  1318. return (sizeof(BYTE));
  1319. }
  1320. case SHOP_SUBHEADER_CG_CHECK:
  1321. COfflineShopManager::instance().HasOfflineShop(ch);
  1322. return 0;
  1323. default:
  1324. sys_err("CInputMain::OfflineShop : Unknown subheader %d : %s", p->subheader, ch->GetName());
  1325. break;
  1326. }
  1327.  
  1328. return 0;
  1329. }
  1330.  
  1331. void CInputMain::OnClick(LPCHARACTER ch, const char * data)
  1332. {
  1333. struct command_on_click * pinfo = (struct command_on_click *) data;
  1334. LPCHARACTER victim;
  1335.  
  1336. if ((victim = CHARACTER_MANAGER::instance().Find(pinfo->vid)))
  1337. victim->OnClick(ch);
  1338. else if (test_server)
  1339. {
  1340. sys_err("CInputMain::OnClick %s.Click.NOT_EXIST_VID[%d]", ch->GetName(), pinfo->vid);
  1341. }
  1342. }
  1343.  
  1344. void CInputMain::Exchange(LPCHARACTER ch, const char * data)
  1345. {
  1346. struct command_exchange * pinfo = (struct command_exchange *) data;
  1347. LPCHARACTER to_ch = NULL;
  1348.  
  1349. if (!ch->CanHandleItem())
  1350. return;
  1351.  
  1352. int iPulse = thecore_pulse();
  1353.  
  1354. if ((to_ch = CHARACTER_MANAGER::instance().Find(pinfo->arg1)))
  1355. {
  1356. if (iPulse - to_ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  1357. {
  1358. to_ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래 후 %d초 이내에 창고를 열수 없습니다."), g_nPortalLimitTime);
  1359. return;
  1360. }
  1361.  
  1362. if( true == to_ch->IsDead() )
  1363. {
  1364. return;
  1365. }
  1366. }
  1367.  
  1368. sys_log(0, "CInputMain()::Exchange() SubHeader %d ", pinfo->sub_header);
  1369.  
  1370. if (iPulse - ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  1371. {
  1372. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래 후 %d초 이내에 창고를 열수 없습니다."), g_nPortalLimitTime);
  1373. return;
  1374. }
  1375.  
  1376.  
  1377. switch (pinfo->sub_header)
  1378. {
  1379. case EXCHANGE_SUBHEADER_CG_START: // arg1 == vid of target character
  1380. if (!ch->GetExchange())
  1381. {
  1382. if ((to_ch = CHARACTER_MANAGER::instance().Find(pinfo->arg1)))
  1383. {
  1384. //MONARCH_LIMIT
  1385. /*
  1386. if (to_ch->IsMonarch() || ch->IsMonarch())
  1387. {
  1388. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주와는 거래를 할수가 없습니다"), g_nPortalLimitTime);
  1389. return;
  1390. }
  1391. //END_MONARCH_LIMIT
  1392. */
  1393. if (iPulse - ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  1394. {
  1395. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고를 연후 %d초 이내에는 거래를 할수 없습니다."), g_nPortalLimitTime);
  1396.  
  1397. if (test_server)
  1398. ch->ChatPacket(CHAT_TYPE_INFO, "[TestOnly][Safebox]Pulse %d LoadTime %d PASS %d", iPulse, ch->GetSafeboxLoadTime(), PASSES_PER_SEC(g_nPortalLimitTime));
  1399. return;
  1400. }
  1401.  
  1402. if (iPulse - to_ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime))
  1403. {
  1404. to_ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고를 연후 %d초 이내에는 거래를 할수 없습니다."), g_nPortalLimitTime);
  1405.  
  1406.  
  1407. if (test_server)
  1408. to_ch->ChatPacket(CHAT_TYPE_INFO, "[TestOnly][Safebox]Pulse %d LoadTime %d PASS %d", iPulse, to_ch->GetSafeboxLoadTime(), PASSES_PER_SEC(g_nPortalLimitTime));
  1409. return;
  1410. }
  1411.  
  1412. if (ch->GetGold() >= GOLD_MAX)
  1413. {
  1414. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("액수가 20억 냥을 초과하여 거래를 할수가 없습니다.."));
  1415.  
  1416. sys_err("[OVERFLOG_GOLD] START (%lld) id %u name %s ", ch->GetGold(), ch->GetPlayerID(), ch->GetName());
  1417. return;
  1418. }
  1419.  
  1420. if (to_ch->IsPC())
  1421. {
  1422. if (quest::CQuestManager::instance().GiveItemToPC(ch->GetPlayerID(), to_ch))
  1423. {
  1424. sys_log(0, "Exchange canceled by quest %s %s", ch->GetName(), to_ch->GetName());
  1425. return;
  1426. }
  1427. }
  1428.  
  1429.  
  1430. if (ch->GetMyShop() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->GetOfflineShopOwner())
  1431. {
  1432. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중일경우 개인상점을 열수가 없습니다."));
  1433. return;
  1434. }
  1435.  
  1436. ch->ExchangeStart(to_ch);
  1437. }
  1438. }
  1439. break;
  1440.  
  1441. case EXCHANGE_SUBHEADER_CG_ITEM_ADD: // arg1 == position of item, arg2 == position in exchange window
  1442. if (ch->GetExchange())
  1443. {
  1444. if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true)
  1445. ch->GetExchange()->AddItem(pinfo->Pos, pinfo->arg2);
  1446. }
  1447. break;
  1448.  
  1449. case EXCHANGE_SUBHEADER_CG_ITEM_DEL: // arg1 == position of item
  1450. if (ch->GetExchange())
  1451. {
  1452. if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true)
  1453. ch->GetExchange()->RemoveItem(pinfo->arg1);
  1454. }
  1455. break;
  1456.  
  1457. case EXCHANGE_SUBHEADER_CG_ELK_ADD: // arg1 == amount of gold
  1458. if (ch->GetExchange())
  1459. {
  1460. const long long nTotalGold = static_cast<long long>(ch->GetExchange()->GetCompany()->GetOwner()->GetGold()) + static_cast<long long>(pinfo->arg1);
  1461.  
  1462. if (GOLD_MAX <= nTotalGold)
  1463. {
  1464. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방의 총금액이 20억 냥을 초과하여 거래를 할수가 없습니다.."));
  1465.  
  1466. sys_err("[OVERFLOW_GOLD] ELK_ADD (%lld) id %u name %s ",
  1467. ch->GetExchange()->GetCompany()->GetOwner()->GetGold(),
  1468. ch->GetExchange()->GetCompany()->GetOwner()->GetPlayerID(),
  1469. ch->GetExchange()->GetCompany()->GetOwner()->GetName());
  1470.  
  1471. return;
  1472. }
  1473.  
  1474. if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true)
  1475. ch->GetExchange()->AddGold(pinfo->arg1);
  1476. }
  1477. break;
  1478.  
  1479. case EXCHANGE_SUBHEADER_CG_ACCEPT: // arg1 == not used
  1480. if (ch->GetExchange())
  1481. {
  1482. sys_log(0, "CInputMain()::Exchange() ==> ACCEPT ");
  1483. ch->GetExchange()->Accept(true);
  1484. }
  1485.  
  1486. break;
  1487.  
  1488. case EXCHANGE_SUBHEADER_CG_CANCEL: // arg1 == not used
  1489. if (ch->GetExchange())
  1490. ch->GetExchange()->Cancel();
  1491. break;
  1492. }
  1493. }
  1494.  
  1495. void CInputMain::Position(LPCHARACTER ch, const char * data)
  1496. {
  1497. struct command_position * pinfo = (struct command_position *) data;
  1498.  
  1499. switch (pinfo->position)
  1500. {
  1501. case POSITION_GENERAL:
  1502. ch->Standup();
  1503. break;
  1504.  
  1505. case POSITION_SITTING_CHAIR:
  1506. ch->Sitdown(0);
  1507. break;
  1508.  
  1509. case POSITION_SITTING_GROUND:
  1510. ch->Sitdown(1);
  1511. break;
  1512. }
  1513. }
  1514.  
  1515. static const int ComboSequenceBySkillLevel[3][8] =
  1516. {
  1517. // 0 1 2 3 4 5 6 7
  1518. { 14, 15, 16, 17, 0, 0, 0, 0 },
  1519. { 14, 15, 16, 18, 20, 0, 0, 0 },
  1520. { 14, 15, 16, 18, 19, 17, 0, 0 },
  1521. };
  1522.  
  1523. #define COMBO_HACK_ALLOWABLE_MS 100
  1524.  
  1525. // [2013 09 11 CYH]
  1526. DWORD ClacValidComboInterval( LPCHARACTER ch, BYTE bArg )
  1527. {
  1528. int nInterval = 300;
  1529. float fAdjustNum = 1.5f; // 일반 유저가 speed hack 에 걸리는 것을 막기 위해. 2013.09.10 CYH
  1530.  
  1531. if( !ch )
  1532. {
  1533. sys_err( "ClacValidComboInterval() ch is NULL");
  1534. return nInterval;
  1535. }
  1536.  
  1537. if( bArg == 13 )
  1538. {
  1539. float normalAttackDuration = CMotionManager::instance().GetNormalAttackDuration(ch->GetRaceNum());
  1540. nInterval = (int) (normalAttackDuration / (((float) ch->GetPoint(POINT_ATT_SPEED) / 100.f) * 900.f) + fAdjustNum );
  1541. }
  1542. else if( bArg == 14 )
  1543. {
  1544. nInterval = (int)(ani_combo_speed(ch, 1 ) / ((ch->GetPoint(POINT_ATT_SPEED) / 100.f) + fAdjustNum) );
  1545. }
  1546. else if( bArg > 14 && bArg << 22 )
  1547. {
  1548. nInterval = (int)(ani_combo_speed(ch, bArg - 13 ) / ((ch->GetPoint(POINT_ATT_SPEED) / 100.f) + fAdjustNum) );
  1549. }
  1550. else
  1551. {
  1552. sys_err( "ClacValidComboInterval() Invalid bArg(%d) ch(%s)", bArg, ch->GetName() );
  1553. }
  1554.  
  1555. return nInterval;
  1556. }
  1557.  
  1558. bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack)
  1559. {
  1560. if (ch->IsStun() || ch->IsDead())
  1561. return false;
  1562.  
  1563. CItem * pCostumeWeapon = ch->GetWear(WEAR_COSTUME_WEAPON);
  1564. if(pCostumeWeapon)
  1565. return false;
  1566.  
  1567. int ComboInterval = dwTime - ch->GetLastComboTime();
  1568. int HackScalar = 0; // 기본 스칼라 단위 1
  1569.  
  1570. // [2013 09 11 CYH] debugging log
  1571. /*sys_log(0, "COMBO_TEST_LOG: %s arg:%u interval:%d valid:%u atkspd:%u riding:%s",
  1572. ch->GetName(),
  1573. bArg,
  1574. ComboInterval,
  1575. ch->GetValidComboInterval(),
  1576. ch->GetPoint(POINT_ATT_SPEED),
  1577. ch->IsRiding() ? "yes" : "no");*/
  1578.  
  1579. #if 0
  1580. sys_log(0, "COMBO: %s arg:%u seq:%u delta:%d checkspeedhack:%d",
  1581. ch->GetName(), bArg, ch->GetComboSequence(), ComboInterval - ch->GetValidComboInterval(), CheckSpeedHack);
  1582. #endif
  1583.  
  1584. if (bArg == 14)
  1585. {
  1586. if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS)
  1587. {
  1588. // FIXME 첫번째 콤보는 이상하게 빨리 올 수가 있어서 300으로 나눔 -_-;
  1589. // 다수의 몬스터에 의해 다운되는 상황에서 공격을 하면
  1590. // 첫번째 콤보가 매우 적은 인터벌로 들어오는 상황 발생.
  1591. // 이로 인해 콤보핵으로 튕기는 경우가 있어 다음 코드 비 활성화.
  1592. //HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 300;
  1593.  
  1594. //sys_log(0, "COMBO_HACK: 2 %s arg:%u interval:%d valid:%u atkspd:%u riding:%s",
  1595. // ch->GetName(),
  1596. // bArg,
  1597. // ComboInterval,
  1598. // ch->GetValidComboInterval(),
  1599. // ch->GetPoint(POINT_ATT_SPEED),
  1600. // ch->IsRiding() ? "yes" : "no");
  1601. }
  1602.  
  1603. ch->SetComboSequence(1);
  1604. // 2013 09 11 CYH edited
  1605. //ch->SetValidComboInterval((int) (ani_combo_speed(ch, 1) / (ch->GetPoint(POINT_ATT_SPEED) / 100.f)));
  1606. ch->SetValidComboInterval( ClacValidComboInterval(ch, bArg) );
  1607. ch->SetLastComboTime(dwTime);
  1608. }
  1609. else if (bArg > 14 && bArg < 22)
  1610. {
  1611. int idx = MIN(2, ch->GetComboIndex());
  1612.  
  1613. if (ch->GetComboSequence() > 5) // 현재 6콤보 이상은 없다.
  1614. {
  1615. HackScalar = 1;
  1616. ch->SetValidComboInterval(300);
  1617. sys_log(0, "COMBO_HACK: 5 %s combo_seq:%d", ch->GetName(), ch->GetComboSequence());
  1618. }
  1619. // 자객 쌍수 콤보 예외처리
  1620. else if (bArg == 21 &&
  1621. idx == 2 &&
  1622. ch->GetComboSequence() == 5 &&
  1623. ch->GetJob() == JOB_ASSASSIN &&
  1624. ch->GetWear(WEAR_WEAPON) &&
  1625. ch->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER)
  1626. ch->SetValidComboInterval(300);
  1627. else if (ComboSequenceBySkillLevel[idx][ch->GetComboSequence()] != bArg)
  1628. {
  1629. HackScalar = 1;
  1630. ch->SetValidComboInterval(300);
  1631.  
  1632. sys_log(0, "COMBO_HACK: 3 %s arg:%u valid:%u combo_idx:%d combo_seq:%d",
  1633. ch->GetName(),
  1634. bArg,
  1635. ComboSequenceBySkillLevel[idx][ch->GetComboSequence()],
  1636. idx,
  1637. ch->GetComboSequence());
  1638. }
  1639. else
  1640. {
  1641. if (CheckSpeedHack && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS)
  1642. {
  1643. HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 100;
  1644.  
  1645. sys_log(0, "COMBO_HACK: 2 %s arg:%u interval:%d valid:%u atkspd:%u riding:%s",
  1646. ch->GetName(),
  1647. bArg,
  1648. ComboInterval,
  1649. ch->GetValidComboInterval(),
  1650. ch->GetPoint(POINT_ATT_SPEED),
  1651. ch->IsRiding() ? "yes" : "no");
  1652. }
  1653.  
  1654. // 말을 탔을 때는 15번 ~ 16번을 반복한다
  1655. //if (ch->IsHorseRiding())
  1656. if (ch->IsRiding())
  1657. ch->SetComboSequence(ch->GetComboSequence() == 1 ? 2 : 1);
  1658. else
  1659. ch->SetComboSequence(ch->GetComboSequence() + 1);
  1660.  
  1661. // 2013 09 11 CYH edited
  1662. //ch->SetValidComboInterval((int) (ani_combo_speed(ch, bArg - 13) / (ch->GetPoint(POINT_ATT_SPEED) / 100.f)));
  1663. ch->SetValidComboInterval( ClacValidComboInterval(ch, bArg) );
  1664. ch->SetLastComboTime(dwTime);
  1665. }
  1666. }
  1667. else if (bArg == 13) // 기본 공격 (둔갑(Polymorph)했을 때 온다)
  1668. {
  1669. if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS)
  1670. {
  1671. // 다수의 몬스터에 의해 다운되는 상황에서 공격을 하면
  1672. // 첫번째 콤보가 매우 적은 인터벌로 들어오는 상황 발생.
  1673. // 이로 인해 콤보핵으로 튕기는 경우가 있어 다음 코드 비 활성화.
  1674. //HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 100;
  1675.  
  1676. //sys_log(0, "COMBO_HACK: 6 %s arg:%u interval:%d valid:%u atkspd:%u",
  1677. // ch->GetName(),
  1678. // bArg,
  1679. // ComboInterval,
  1680. // ch->GetValidComboInterval(),
  1681. // ch->GetPoint(POINT_ATT_SPEED));
  1682. }
  1683.  
  1684. if (ch->GetRaceNum() >= MAIN_RACE_MAX_NUM)
  1685. {
  1686. // POLYMORPH_BUG_FIX
  1687.  
  1688. // DELETEME
  1689. /*
  1690. const CMotion * pkMotion = CMotionManager::instance().GetMotion(ch->GetRaceNum(), MAKE_MOTION_KEY(MOTION_MODE_GENERAL, MOTION_NORMAL_ATTACK));
  1691.  
  1692. if (!pkMotion)
  1693. sys_err("cannot find motion by race %u", ch->GetRaceNum());
  1694. else
  1695. {
  1696. // 정상적 계산이라면 1000.f를 곱해야 하지만 클라이언트가 애니메이션 속도의 90%에서
  1697. // 다음 애니메이션 블렌딩을 허용하므로 900.f를 곱한다.
  1698. int k = (int) (pkMotion->GetDuration() / ((float) ch->GetPoint(POINT_ATT_SPEED) / 100.f) * 900.f);
  1699. ch->SetValidComboInterval(k);
  1700. ch->SetLastComboTime(dwTime);
  1701. }
  1702. */
  1703.  
  1704. // 2013 09 11 CYH edited
  1705. //float normalAttackDuration = CMotionManager::instance().GetNormalAttackDuration(ch->GetRaceNum());
  1706. //int k = (int) (normalAttackDuration / ((float) ch->GetPoint(POINT_ATT_SPEED) / 100.f) * 900.f);
  1707. //ch->SetValidComboInterval(k);
  1708. ch->SetValidComboInterval( ClacValidComboInterval(ch, bArg) );
  1709. ch->SetLastComboTime(dwTime);
  1710. // END_OF_POLYMORPH_BUG_FIX
  1711. }
  1712. else
  1713. {
  1714. // 말이 안되는 콤보가 왔다 해커일 가능성?
  1715. //if (ch->GetDesc()->DelayedDisconnect(number(2, 9)))
  1716. //{
  1717. // LogManager::instance().HackLog("Hacker", ch);
  1718. // sys_log(0, "HACKER: %s arg %u", ch->GetName(), bArg);
  1719. //}
  1720.  
  1721. // 위 코드로 인해, 폴리모프를 푸는 중에 공격 하면,
  1722. // 가끔 핵으로 인식하는 경우가 있다.
  1723.  
  1724. // 자세히 말혀면,
  1725. // 서버에서 poly 0를 처리했지만,
  1726. // 클라에서 그 패킷을 받기 전에, 몹을 공격. <- 즉, 몹인 상태에서 공격.
  1727. //
  1728. // 그러면 클라에서는 서버에 몹 상태로 공격했다는 커맨드를 보내고 (arg == 13)
  1729. //
  1730. // 서버에서는 race는 인간인데 공격형태는 몹인 놈이다! 라고 하여 핵체크를 했다.
  1731.  
  1732. // 사실 공격 패턴에 대한 것은 클라이언트에서 판단해서 보낼 것이 아니라,
  1733. // 서버에서 판단해야 할 것인데... 왜 이렇게 해놨을까...
  1734. // by rtsummit
  1735. }
  1736. }
  1737. else
  1738. {
  1739. // 말이 안되는 콤보가 왔다 해커일 가능성?
  1740. if (ch->GetDesc()->DelayedDisconnect(number(2, 9)))
  1741. {
  1742. LogManager::instance().HackLog("Hacker", ch);
  1743. sys_log(0, "HACKER: %s arg %u", ch->GetName(), bArg);
  1744. }
  1745.  
  1746. HackScalar = 10;
  1747. ch->SetValidComboInterval(300);
  1748. }
  1749.  
  1750. if (HackScalar)
  1751. {
  1752. // 말에 타거나 내렸을 때 1.5초간 공격은 핵으로 간주하지 않되 공격력은 없게 하는 처리
  1753. if (get_dword_time() - ch->GetLastMountTime() > 1500)
  1754. ch->IncreaseComboHackCount(1 + HackScalar);
  1755.  
  1756. ch->SkipComboAttackByTime(ch->GetValidComboInterval());
  1757. }
  1758.  
  1759. return HackScalar;
  1760. }
  1761.  
  1762. void CInputMain::Move(LPCHARACTER ch, const char * data)
  1763. {
  1764. if (!ch->CanMove())
  1765. return;
  1766.  
  1767. struct command_move * pinfo = (struct command_move *) data;
  1768.  
  1769. if (pinfo->bFunc >= FUNC_MAX_NUM && !(pinfo->bFunc & 0x80))
  1770. {
  1771. sys_err("invalid move type: %s", ch->GetName());
  1772. return;
  1773. }
  1774.  
  1775. //enum EMoveFuncType
  1776. //{
  1777. // FUNC_WAIT,
  1778. // FUNC_MOVE,
  1779. // FUNC_ATTACK,
  1780. // FUNC_COMBO,
  1781. // FUNC_MOB_SKILL,
  1782. // _FUNC_SKILL,
  1783. // FUNC_MAX_NUM,
  1784. // FUNC_SKILL = 0x80,
  1785. //};
  1786.  
  1787. // 텔레포트 핵 체크
  1788.  
  1789. // if (!test_server) //2012.05.15 김용욱 : 테섭에서 (무적상태로) 다수 몬스터 상대로 다운되면서 공격시 콤보핵으로 죽는 문제가 있었다.
  1790. {
  1791. const float fDist = DISTANCE_SQRT((ch->GetX() - pinfo->lX) / 100, (ch->GetY() - pinfo->lY) / 100);
  1792.  
  1793. if (((false == ch->IsRiding() && fDist > 25) || fDist > 40) && OXEVENT_MAP_INDEX != ch->GetMapIndex())
  1794. {
  1795. if( false == LC_IsEurope() )
  1796. {
  1797. const PIXEL_POSITION & warpPos = ch->GetWarpPosition();
  1798.  
  1799. if (warpPos.x == 0 && warpPos.y == 0)
  1800. LogManager::instance().HackLog("Teleport", ch); // 부정확할 수 있음
  1801. }
  1802.  
  1803. sys_log(0, "MOVE: %s trying to move too far (dist: %.1fm) Riding(%d)", ch->GetName(), fDist, ch->IsRiding());
  1804.  
  1805. ch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ());
  1806. ch->Stop();
  1807. return;
  1808. }
  1809.  
  1810. DWORD dwCurTime = get_dword_time();
  1811. bool CheckSpeedHack = (false == ch->GetDesc()->IsHandshaking() && dwCurTime - ch->GetDesc()->GetClientTime() > 7000);
  1812.  
  1813. // if (CheckSpeedHack)
  1814. // {
  1815. // int iDelta = (int) (pinfo->dwTime - ch->GetDesc()->GetClientTime());
  1816. // int iServerDelta = (int) (dwCurTime - ch->GetDesc()->GetClientTime());
  1817. //
  1818. // iDelta = (int) (dwCurTime - pinfo->dwTime);
  1819. //
  1820. // if (iDelta >= 30000)
  1821. // {
  1822. // sys_log(0, "SPEEDHACK: slow timer name %s delta %d", ch->GetName(), iDelta);
  1823. // ch->GetDesc()->DelayedDisconnect(3);
  1824. // }
  1825. // else if (iDelta < -(iServerDelta / 50))
  1826. // {
  1827. // sys_log(0, "SPEEDHACK: DETECTED! %s (delta %d %d)", ch->GetName(), iDelta, iServerDelta);
  1828. // ch->GetDesc()->DelayedDisconnect(3);
  1829. // }
  1830. // }
  1831.  
  1832. if (pinfo->bFunc == FUNC_COMBO && g_bCheckMultiHack)
  1833. {
  1834. CheckComboHack(ch, pinfo->bArg, pinfo->dwTime, CheckSpeedHack); // 콤보 체크
  1835. }
  1836. }
  1837.  
  1838. if (pinfo->bFunc == FUNC_MOVE)
  1839. {
  1840. if (ch->GetLimitPoint(POINT_MOV_SPEED) == 0)
  1841. return;
  1842.  
  1843. ch->SetRotation(pinfo->bRot * 5); // 중복 코드
  1844. ch->ResetStopTime(); // ""
  1845.  
  1846. ch->Goto(pinfo->lX, pinfo->lY);
  1847. }
  1848. else
  1849. {
  1850. if (pinfo->bFunc == FUNC_ATTACK || pinfo->bFunc == FUNC_COMBO)
  1851. ch->OnMove(true);
  1852. else if (pinfo->bFunc & FUNC_SKILL)
  1853. {
  1854. const int MASK_SKILL_MOTION = 0x7F;
  1855. unsigned int motion = pinfo->bFunc & MASK_SKILL_MOTION;
  1856.  
  1857. if (!ch->IsUsableSkillMotion(motion))
  1858. {
  1859. const char* name = ch->GetName();
  1860. unsigned int job = ch->GetJob();
  1861. unsigned int group = ch->GetSkillGroup();
  1862.  
  1863. char szBuf[256];
  1864. snprintf(szBuf, sizeof(szBuf), "SKILL_HACK: name=%s, job=%d, group=%d, motion=%d", name, job, group, motion);
  1865. LogManager::instance().HackLog(szBuf, ch->GetDesc()->GetAccountTable().login, ch->GetName(), ch->GetDesc()->GetHostName());
  1866. sys_log(0, "%s", szBuf);
  1867.  
  1868. if (test_server)
  1869. {
  1870. ch->GetDesc()->DelayedDisconnect(number(2, 8));
  1871. ch->ChatPacket(CHAT_TYPE_INFO, szBuf);
  1872. }
  1873. else
  1874. {
  1875. ch->GetDesc()->DelayedDisconnect(number(150, 500));
  1876. }
  1877. }
  1878.  
  1879. ch->OnMove();
  1880. }
  1881.  
  1882. ch->SetRotation(pinfo->bRot * 5); // 중복 코드
  1883. ch->ResetStopTime(); // ""
  1884.  
  1885. ch->Move(pinfo->lX, pinfo->lY);
  1886. ch->Stop();
  1887. ch->StopStaminaConsume();
  1888. }
  1889.  
  1890. TPacketGCMove pack;
  1891.  
  1892. pack.bHeader = HEADER_GC_MOVE;
  1893. pack.bFunc = pinfo->bFunc;
  1894. pack.bArg = pinfo->bArg;
  1895. pack.bRot = pinfo->bRot;
  1896. pack.dwVID = ch->GetVID();
  1897. pack.lX = pinfo->lX;
  1898. pack.lY = pinfo->lY;
  1899. pack.dwTime = pinfo->dwTime;
  1900. pack.dwDuration = (pinfo->bFunc == FUNC_MOVE) ? ch->GetCurrentMoveDuration() : 0;
  1901.  
  1902. ch->PacketAround(&pack, sizeof(TPacketGCMove), ch);
  1903. /*
  1904. if (pinfo->dwTime == 10653691) // 디버거 발견
  1905. {
  1906. if (ch->GetDesc()->DelayedDisconnect(number(15, 30)))
  1907. LogManager::instance().HackLog("Debugger", ch);
  1908.  
  1909. }
  1910. else if (pinfo->dwTime == 10653971) // Softice 발견
  1911. {
  1912. if (ch->GetDesc()->DelayedDisconnect(number(15, 30)))
  1913. LogManager::instance().HackLog("Softice", ch);
  1914. }
  1915. */
  1916. /*
  1917. sys_log(0,
  1918. "MOVE: %s Func:%u Arg:%u Pos:%dx%d Time:%u Dist:%.1f",
  1919. ch->GetName(),
  1920. pinfo->bFunc,
  1921. pinfo->bArg,
  1922. pinfo->lX / 100,
  1923. pinfo->lY / 100,
  1924. pinfo->dwTime,
  1925. fDist);
  1926. */
  1927. }
  1928.  
  1929. void CInputMain::Attack(LPCHARACTER ch, const BYTE header, const char* data)
  1930. {
  1931. if (NULL == ch)
  1932. return;
  1933.  
  1934. struct type_identifier
  1935. {
  1936. BYTE header;
  1937. BYTE type;
  1938. };
  1939.  
  1940. const struct type_identifier* const type = reinterpret_cast<const struct type_identifier*>(data);
  1941.  
  1942. if (type->type > 0)
  1943. {
  1944. if (false == ch->CanUseSkill(type->type))
  1945. {
  1946. return;
  1947. }
  1948.  
  1949. switch (type->type)
  1950. {
  1951. case SKILL_GEOMPUNG:
  1952. case SKILL_SANGONG:
  1953. case SKILL_YEONSA:
  1954. case SKILL_KWANKYEOK:
  1955. case SKILL_HWAJO:
  1956. case SKILL_GIGUNG:
  1957. case SKILL_PABEOB:
  1958. case SKILL_MARYUNG:
  1959. case SKILL_TUSOK:
  1960. case SKILL_MAHWAN:
  1961. case SKILL_BIPABU:
  1962. case SKILL_NOEJEON:
  1963. case SKILL_CHAIN:
  1964. case SKILL_HORSE_WILDATTACK_RANGE:
  1965. if (HEADER_CG_SHOOT != type->header)
  1966. {
  1967. if (test_server)
  1968. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Attack :name[%s] Vnum[%d] can't use skill by attack(warning)"), type->type);
  1969. return;
  1970. }
  1971. break;
  1972. }
  1973. }
  1974.  
  1975. switch (header)
  1976. {
  1977. case HEADER_CG_ATTACK:
  1978. {
  1979. if (NULL == ch->GetDesc())
  1980. return;
  1981.  
  1982. const TPacketCGAttack* const packMelee = reinterpret_cast<const TPacketCGAttack*>(data);
  1983.  
  1984. ch->GetDesc()->AssembleCRCMagicCube(packMelee->bCRCMagicCubeProcPiece, packMelee->bCRCMagicCubeFilePiece);
  1985.  
  1986. LPCHARACTER victim = CHARACTER_MANAGER::instance().Find(packMelee->dwVID);
  1987.  
  1988. if (NULL == victim || ch == victim)
  1989. return;
  1990.  
  1991. switch (victim->GetCharType())
  1992. {
  1993. case CHAR_TYPE_NPC:
  1994. case CHAR_TYPE_WARP:
  1995. case CHAR_TYPE_GOTO:
  1996. return;
  1997. }
  1998.  
  1999. if (packMelee->bType > 0)
  2000. {
  2001. if (false == ch->CheckSkillHitCount(packMelee->bType, victim->GetVID()))
  2002. {
  2003. return;
  2004. }
  2005. }
  2006.  
  2007. ch->Attack(victim, packMelee->bType);
  2008. }
  2009. break;
  2010.  
  2011. case HEADER_CG_SHOOT:
  2012. {
  2013. const TPacketCGShoot* const packShoot = reinterpret_cast<const TPacketCGShoot*>(data);
  2014.  
  2015. ch->Shoot(packShoot->bType);
  2016. }
  2017. break;
  2018. }
  2019. }
  2020.  
  2021. int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiBytes)
  2022. {
  2023. const TPacketCGSyncPosition* pinfo = reinterpret_cast<const TPacketCGSyncPosition*>( c_pcData );
  2024.  
  2025. if (uiBytes < pinfo->wSize)
  2026. return -1;
  2027.  
  2028. int iExtraLen = pinfo->wSize - sizeof(TPacketCGSyncPosition);
  2029.  
  2030. if (iExtraLen < 0)
  2031. {
  2032. sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->wSize, uiBytes);
  2033. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  2034. return -1;
  2035. }
  2036.  
  2037. if (0 != (iExtraLen % sizeof(TPacketCGSyncPositionElement)))
  2038. {
  2039. sys_err("invalid packet length %d (name: %s)", pinfo->wSize, ch->GetName());
  2040. return iExtraLen;
  2041. }
  2042.  
  2043. int iCount = iExtraLen / sizeof(TPacketCGSyncPositionElement);
  2044.  
  2045. if (iCount <= 0)
  2046. return iExtraLen;
  2047.  
  2048. static const int nCountLimit = 16;
  2049.  
  2050. if( iCount > nCountLimit )
  2051. {
  2052. //LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch );
  2053. sys_err( "Too many SyncPosition Count(%d) from Name(%s)", iCount, ch->GetName() );
  2054. //ch->GetDesc()->SetPhase(PHASE_CLOSE);
  2055. //return -1;
  2056. iCount = nCountLimit;
  2057. }
  2058.  
  2059. TEMP_BUFFER tbuf;
  2060. LPBUFFER lpBuf = tbuf.getptr();
  2061.  
  2062. TPacketGCSyncPosition * pHeader = (TPacketGCSyncPosition *) buffer_write_peek(lpBuf);
  2063. buffer_write_proceed(lpBuf, sizeof(TPacketGCSyncPosition));
  2064.  
  2065. const TPacketCGSyncPositionElement* e =
  2066. reinterpret_cast<const TPacketCGSyncPositionElement*>(c_pcData + sizeof(TPacketCGSyncPosition));
  2067.  
  2068. timeval tvCurTime;
  2069. gettimeofday(&tvCurTime, NULL);
  2070.  
  2071. for (int i = 0; i < iCount; ++i, ++e)
  2072. {
  2073. LPCHARACTER victim = CHARACTER_MANAGER::instance().Find(e->dwVID);
  2074.  
  2075. if (!victim)
  2076. continue;
  2077.  
  2078. switch (victim->GetCharType())
  2079. {
  2080. case CHAR_TYPE_NPC:
  2081. case CHAR_TYPE_WARP:
  2082. case CHAR_TYPE_GOTO:
  2083. continue;
  2084. }
  2085.  
  2086. // 소유권 검사
  2087. if (!victim->SetSyncOwner(ch))
  2088. continue;
  2089.  
  2090. const float fDistWithSyncOwner = DISTANCE_SQRT( (victim->GetX() - ch->GetX()) / 100, (victim->GetY() - ch->GetY()) / 100 );
  2091. static const float fLimitDistWithSyncOwner = 2500.f + 1000.f;
  2092. // victim과의 거리가 2500 + a 이상이면 핵으로 간주.
  2093. // 거리 참조 : 클라이언트의 __GetSkillTargetRange, __GetBowRange 함수
  2094. // 2500 : 스킬 proto에서 가장 사거리가 긴 스킬의 사거리, 또는 활의 사거리
  2095. // a = POINT_BOW_DISTANCE 값... 인데 실제로 사용하는 값인지는 잘 모르겠음. 아이템이나 포션, 스킬, 퀘스트에는 없는데...
  2096. // 그래도 혹시나 하는 마음에 버퍼로 사용할 겸해서 1000.f 로 둠...
  2097. if (fDistWithSyncOwner > fLimitDistWithSyncOwner)
  2098. {
  2099. // g_iSyncHackLimitCount번 까지는 봐줌.
  2100. if (ch->GetSyncHackCount() < g_iSyncHackLimitCount)
  2101. {
  2102. ch->SetSyncHackCount(ch->GetSyncHackCount() + 1);
  2103. continue;
  2104. }
  2105. else
  2106. {
  2107. LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch );
  2108.  
  2109. sys_err( "Too far SyncPosition DistanceWithSyncOwner(%f)(%s) from Name(%s) CH(%d,%d) VICTIM(%d,%d) SYNC(%d,%d)",
  2110. fDistWithSyncOwner, victim->GetName(), ch->GetName(), ch->GetX(), ch->GetY(), victim->GetX(), victim->GetY(),
  2111. e->lX, e->lY );
  2112.  
  2113. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  2114.  
  2115. return -1;
  2116. }
  2117. }
  2118.  
  2119. const float fDist = DISTANCE_SQRT( (victim->GetX() - e->lX) / 100, (victim->GetY() - e->lY) / 100 );
  2120. static const long g_lValidSyncInterval = 50 * 1000; // 100ms -> 50ms 2013 09 11 CYH
  2121. const timeval &tvLastSyncTime = victim->GetLastSyncTime();
  2122. timeval *tvDiff = timediff(&tvCurTime, &tvLastSyncTime);
  2123.  
  2124. // SyncPosition을 악용하여 타유저를 이상한 곳으로 보내는 핵 방어하기 위하여,
  2125. // 같은 유저를 g_lValidSyncInterval ms 이내에 다시 SyncPosition하려고 하면 핵으로 간주.
  2126. if (tvDiff->tv_sec == 0 && tvDiff->tv_usec < g_lValidSyncInterval)
  2127. {
  2128. // g_iSyncHackLimitCount번 까지는 봐줌.
  2129. if (ch->GetSyncHackCount() < g_iSyncHackLimitCount)
  2130. {
  2131. ch->SetSyncHackCount(ch->GetSyncHackCount() + 1);
  2132. continue;
  2133. }
  2134. else
  2135. {
  2136. LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch );
  2137.  
  2138. sys_err( "Too often SyncPosition Interval(%ldms)(%s) from Name(%s) VICTIM(%d,%d) SYNC(%d,%d)",
  2139. tvDiff->tv_sec * 1000 + tvDiff->tv_usec / 1000, victim->GetName(), ch->GetName(), victim->GetX(), victim->GetY(),
  2140. e->lX, e->lY );
  2141.  
  2142. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  2143.  
  2144. return -1;
  2145. }
  2146. }
  2147. else if( fDist > 25.0f )
  2148. {
  2149. LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch );
  2150.  
  2151. sys_err( "Too far SyncPosition Distance(%f)(%s) from Name(%s) CH(%d,%d) VICTIM(%d,%d) SYNC(%d,%d)",
  2152. fDist, victim->GetName(), ch->GetName(), ch->GetX(), ch->GetY(), victim->GetX(), victim->GetY(),
  2153. e->lX, e->lY );
  2154.  
  2155. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  2156.  
  2157. return -1;
  2158. }
  2159. else
  2160. {
  2161. victim->SetLastSyncTime(tvCurTime);
  2162. victim->Sync(e->lX, e->lY);
  2163. buffer_write(lpBuf, e, sizeof(TPacketCGSyncPositionElement));
  2164. }
  2165. }
  2166.  
  2167. if (buffer_size(lpBuf) != sizeof(TPacketGCSyncPosition))
  2168. {
  2169. pHeader->bHeader = HEADER_GC_SYNC_POSITION;
  2170. pHeader->wSize = buffer_size(lpBuf);
  2171.  
  2172. ch->PacketAround(buffer_read_peek(lpBuf), buffer_size(lpBuf), ch);
  2173. }
  2174.  
  2175. return iExtraLen;
  2176. }
  2177.  
  2178. void CInputMain::FlyTarget(LPCHARACTER ch, const char * pcData, BYTE bHeader)
  2179. {
  2180. TPacketCGFlyTargeting * p = (TPacketCGFlyTargeting *) pcData;
  2181. ch->FlyTarget(p->dwTargetVID, p->x, p->y, bHeader);
  2182. }
  2183.  
  2184. void CInputMain::UseSkill(LPCHARACTER ch, const char * pcData)
  2185. {
  2186. TPacketCGUseSkill * p = (TPacketCGUseSkill *) pcData;
  2187. ch->UseSkill(p->dwVnum, CHARACTER_MANAGER::instance().Find(p->dwVID));
  2188. }
  2189.  
  2190. void CInputMain::ScriptButton(LPCHARACTER ch, const void* c_pData)
  2191. {
  2192. TPacketCGScriptButton * p = (TPacketCGScriptButton *) c_pData;
  2193. sys_log(0, "QUEST ScriptButton pid %d idx %u", ch->GetPlayerID(), p->idx);
  2194.  
  2195. quest::PC* pc = quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID());
  2196. if (pc && pc->IsConfirmWait())
  2197. {
  2198. quest::CQuestManager::instance().Confirm(ch->GetPlayerID(), quest::CONFIRM_TIMEOUT);
  2199. }
  2200. else if (p->idx & 0x80000000)
  2201. {
  2202. quest::CQuestManager::Instance().QuestInfo(ch->GetPlayerID(), p->idx & 0x7fffffff);
  2203. }
  2204. else
  2205. {
  2206. quest::CQuestManager::Instance().QuestButton(ch->GetPlayerID(), p->idx);
  2207. }
  2208. }
  2209.  
  2210. void CInputMain::ScriptAnswer(LPCHARACTER ch, const void* c_pData)
  2211. {
  2212. TPacketCGScriptAnswer * p = (TPacketCGScriptAnswer *) c_pData;
  2213. sys_log(0, "QUEST ScriptAnswer pid %d answer %d", ch->GetPlayerID(), p->answer);
  2214.  
  2215. if (p->answer > 250) // 다음 버튼에 대한 응답으로 온 패킷인 경우
  2216. {
  2217. quest::CQuestManager::Instance().Resume(ch->GetPlayerID());
  2218. }
  2219. else // 선택 버튼을 골라서 온 패킷인 경우
  2220. {
  2221. quest::CQuestManager::Instance().Select(ch->GetPlayerID(), p->answer);
  2222. }
  2223. }
  2224.  
  2225.  
  2226. // SCRIPT_SELECT_ITEM
  2227. void CInputMain::ScriptSelectItem(LPCHARACTER ch, const void* c_pData)
  2228. {
  2229. TPacketCGScriptSelectItem* p = (TPacketCGScriptSelectItem*) c_pData;
  2230. sys_log(0, "QUEST ScriptSelectItem pid %d answer %d", ch->GetPlayerID(), p->selection);
  2231. quest::CQuestManager::Instance().SelectItem(ch->GetPlayerID(), p->selection);
  2232. }
  2233. // END_OF_SCRIPT_SELECT_ITEM
  2234.  
  2235. void CInputMain::QuestInputString(LPCHARACTER ch, const void* c_pData)
  2236. {
  2237. TPacketCGQuestInputString * p = (TPacketCGQuestInputString*) c_pData;
  2238.  
  2239. char msg[65];
  2240. strlcpy(msg, p->msg, sizeof(msg));
  2241. sys_log(0, "QUEST InputString pid %u msg %s", ch->GetPlayerID(), msg);
  2242.  
  2243. quest::CQuestManager::Instance().Input(ch->GetPlayerID(), msg);
  2244. }
  2245.  
  2246. void CInputMain::QuestConfirm(LPCHARACTER ch, const void* c_pData)
  2247. {
  2248. TPacketCGQuestConfirm* p = (TPacketCGQuestConfirm*) c_pData;
  2249. LPCHARACTER ch_wait = CHARACTER_MANAGER::instance().FindByPID(p->requestPID);
  2250. if (p->answer)
  2251. p->answer = quest::CONFIRM_YES;
  2252. sys_log(0, "QuestConfirm from %s pid %u name %s answer %d", ch->GetName(), p->requestPID, (ch_wait)?ch_wait->GetName():"", p->answer);
  2253. if (ch_wait)
  2254. {
  2255. quest::CQuestManager::Instance().Confirm(ch_wait->GetPlayerID(), (quest::EQuestConfirmType) p->answer, ch->GetPlayerID());
  2256. }
  2257. }
  2258.  
  2259. void CInputMain::Target(LPCHARACTER ch, const char * pcData)
  2260. {
  2261. TPacketCGTarget * p = (TPacketCGTarget *) pcData;
  2262.  
  2263. building::LPOBJECT pkObj = building::CManager::instance().FindObjectByVID(p->dwVID);
  2264.  
  2265. if (pkObj)
  2266. {
  2267. TPacketGCTarget pckTarget;
  2268. pckTarget.header = HEADER_GC_TARGET;
  2269. pckTarget.dwVID = p->dwVID;
  2270. ch->GetDesc()->Packet(&pckTarget, sizeof(TPacketGCTarget));
  2271. }
  2272. else
  2273. ch->SetTarget(CHARACTER_MANAGER::instance().Find(p->dwVID));
  2274. }
  2275.  
  2276. void CInputMain::Warp(LPCHARACTER ch, const char * pcData)
  2277. {
  2278. ch->WarpEnd();
  2279. }
  2280.  
  2281. void CInputMain::SafeboxCheckin(LPCHARACTER ch, const char * c_pData)
  2282. {
  2283. if (quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID())->IsRunning() == true)
  2284. return;
  2285.  
  2286. TPacketCGSafeboxCheckin * p = (TPacketCGSafeboxCheckin *) c_pData;
  2287.  
  2288. if (!ch->CanHandleItem())
  2289. return;
  2290.  
  2291. CSafebox * pkSafebox = ch->GetSafebox();
  2292. LPITEM pkItem = ch->GetItem(p->ItemPos);
  2293.  
  2294. if (!pkSafebox || !pkItem)
  2295. return;
  2296.  
  2297. if (pkItem->IsEquipped())
  2298. return;
  2299.  
  2300. if (ITEM_BELT == pkItem->GetType() && pkItem->IsEquipped())
  2301. {
  2302. ch->ChatPacket(CHAT_TYPE_INFO, "Goleste inventarul curelei intai.");
  2303. return;
  2304. }
  2305.  
  2306. if (pkItem->GetCell() >= INVENTORY_MAX_NUM && IS_SET(pkItem->GetFlag(), ITEM_FLAG_IRREMOVABLE))
  2307. {
  2308. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 창고로 옮길 수 없는 아이템 입니다."));
  2309. return;
  2310. }
  2311.  
  2312. if (!pkSafebox->IsEmpty(p->bSafePos, pkItem->GetSize()))
  2313. {
  2314. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다."));
  2315. return;
  2316. }
  2317.  
  2318. if (pkItem->GetVnum() == UNIQUE_ITEM_SAFEBOX_EXPAND)
  2319. {
  2320. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 이 아이템은 넣을 수 없습니다."));
  2321. return;
  2322. }
  2323.  
  2324. if( IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_SAFEBOX))
  2325. {
  2326. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 이 아이템은 넣을 수 없습니다."));
  2327. return;
  2328. }
  2329.  
  2330. if (true == pkItem->isLocked())
  2331. {
  2332. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 이 아이템은 넣을 수 없습니다."));
  2333. return;
  2334. }
  2335.  
  2336. pkItem->RemoveFromCharacter();
  2337. if (!pkItem->IsDragonSoul())
  2338. ch->SyncQuickslot(QUICKSLOT_TYPE_ITEM, p->ItemPos.cell, 255);
  2339. pkSafebox->Add(p->bSafePos, pkItem);
  2340.  
  2341. char szHint[128];
  2342. snprintf(szHint, sizeof(szHint), "%s %u", pkItem->GetName(), pkItem->GetCount());
  2343. LogManager::instance().ItemLog(ch, pkItem, "SAFEBOX PUT", szHint);
  2344. }
  2345.  
  2346. void CInputMain::SafeboxCheckout(LPCHARACTER ch, const char * c_pData, bool bMall)
  2347. {
  2348. TPacketCGSafeboxCheckout * p = (TPacketCGSafeboxCheckout *) c_pData;
  2349.  
  2350. if (!ch->CanHandleItem())
  2351. return;
  2352.  
  2353. CSafebox * pkSafebox;
  2354.  
  2355. if (bMall)
  2356. pkSafebox = ch->GetMall();
  2357. else
  2358. pkSafebox = ch->GetSafebox();
  2359.  
  2360. if (!pkSafebox)
  2361. return;
  2362.  
  2363. LPITEM pkItem = pkSafebox->Get(p->bSafePos);
  2364.  
  2365. if (!pkItem)
  2366. return;
  2367.  
  2368. if (!ch->IsEmptyItemGrid(p->ItemPos, pkItem->GetSize()))
  2369. return;
  2370.  
  2371. for (WORD belt_index = BELT_INVENTORY_SLOT_START; belt_index < BELT_INVENTORY_SLOT_END; ++belt_index)
  2372. {
  2373. if (pkItem->GetType() != 3 && p->ItemPos.cell == belt_index)
  2374. {
  2375. if(pkItem->GetSubType() != 0 || pkItem->GetSubType() != 11 || pkItem->GetSubType() != 7)
  2376. {
  2377. ch->ChatPacket(CHAT_TYPE_INFO, "Nu poti face asta.");
  2378. return;
  2379. }
  2380. }
  2381. }
  2382.  
  2383. if (pkItem->IsDragonSoul())
  2384. {
  2385. if (bMall)
  2386. {
  2387. DSManager::instance().DragonSoulItemInitialize(pkItem);
  2388. }
  2389.  
  2390. if (DRAGON_SOUL_INVENTORY != p->ItemPos.window_type)
  2391. {
  2392. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다."));
  2393. return;
  2394. }
  2395.  
  2396. TItemPos DestPos = p->ItemPos;
  2397. if (!DSManager::instance().IsValidCellForThisItem(pkItem, DestPos))
  2398. {
  2399. int iCell = ch->GetEmptyDragonSoulInventory(pkItem);
  2400. if (iCell < 0)
  2401. {
  2402. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다."));
  2403. return ;
  2404. }
  2405. DestPos = TItemPos (DRAGON_SOUL_INVENTORY, iCell);
  2406. }
  2407.  
  2408. pkSafebox->Remove(p->bSafePos);
  2409. pkItem->AddToCharacter(ch, DestPos);
  2410. ITEM_MANAGER::instance().FlushDelayedSave(pkItem);
  2411. }
  2412. else
  2413. {
  2414. if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type)
  2415. {
  2416. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다."));
  2417. return;
  2418. }
  2419.  
  2420. pkSafebox->Remove(p->bSafePos);
  2421. if (bMall)
  2422. {
  2423. if (NULL == pkItem->GetProto())
  2424. {
  2425. sys_err ("pkItem->GetProto() == NULL (id : %d)",pkItem->GetID());
  2426. return ;
  2427. }
  2428. // 100% 확률로 속성이 붙어야 하는데 안 붙어있다면 새로 붙힌다. ...............
  2429. if (100 == pkItem->GetProto()->bAlterToMagicItemPct && 0 == pkItem->GetAttributeCount())
  2430. {
  2431. pkItem->AlterToMagicItem();
  2432. }
  2433. }
  2434. pkItem->AddToCharacter(ch, p->ItemPos);
  2435. ITEM_MANAGER::instance().FlushDelayedSave(pkItem);
  2436. }
  2437.  
  2438. DWORD dwID = pkItem->GetID();
  2439. db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_FLUSH, 0, sizeof(DWORD));
  2440. db_clientdesc->Packet(&dwID, sizeof(DWORD));
  2441.  
  2442. char szHint[128];
  2443. snprintf(szHint, sizeof(szHint), "%s %u", pkItem->GetName(), pkItem->GetCount());
  2444. if (bMall)
  2445. LogManager::instance().ItemLog(ch, pkItem, "MALL GET", szHint);
  2446. else
  2447. LogManager::instance().ItemLog(ch, pkItem, "SAFEBOX GET", szHint);
  2448. }
  2449.  
  2450. void CInputMain::SafeboxItemMove(LPCHARACTER ch, const char * data)
  2451. {
  2452. struct command_item_move * pinfo = (struct command_item_move *) data;
  2453.  
  2454. if (!ch->CanHandleItem())
  2455. return;
  2456.  
  2457. if (!ch->GetSafebox())
  2458. return;
  2459.  
  2460. ch->GetSafebox()->MoveItem(pinfo->Cell.cell, pinfo->CellTo.cell, pinfo->count);
  2461. }
  2462.  
  2463. // PARTY_JOIN_BUG_FIX
  2464. void CInputMain::PartyInvite(LPCHARACTER ch, const char * c_pData)
  2465. {
  2466. if (ch->GetArena())
  2467. {
  2468. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다."));
  2469. return;
  2470. }
  2471.  
  2472. TPacketCGPartyInvite * p = (TPacketCGPartyInvite*) c_pData;
  2473.  
  2474. LPCHARACTER pInvitee = CHARACTER_MANAGER::instance().Find(p->vid);
  2475.  
  2476. if (!pInvitee || !ch->GetDesc() || !pInvitee->GetDesc())
  2477. {
  2478. sys_err("PARTY Cannot find invited character");
  2479. return;
  2480. }
  2481.  
  2482. ch->PartyInvite(pInvitee);
  2483. }
  2484.  
  2485. void CInputMain::PartyInviteAnswer(LPCHARACTER ch, const char * c_pData)
  2486. {
  2487. if (ch->GetArena())
  2488. {
  2489. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다."));
  2490. return;
  2491. }
  2492.  
  2493. TPacketCGPartyInviteAnswer * p = (TPacketCGPartyInviteAnswer*) c_pData;
  2494.  
  2495. LPCHARACTER pInviter = CHARACTER_MANAGER::instance().Find(p->leader_vid);
  2496.  
  2497. // pInviter 가 ch 에게 파티 요청을 했었다.
  2498.  
  2499. if (!pInviter)
  2500. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티요청을 한 캐릭터를 찾을수 없습니다."));
  2501. else if (!p->accept)
  2502. pInviter->PartyInviteDeny(ch->GetPlayerID());
  2503. else
  2504. pInviter->PartyInviteAccept(ch);
  2505. }
  2506. // END_OF_PARTY_JOIN_BUG_FIX
  2507.  
  2508. void CInputMain::PartySetState(LPCHARACTER ch, const char* c_pData)
  2509. {
  2510. if (!CPartyManager::instance().IsEnablePCParty())
  2511. {
  2512. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다."));
  2513. return;
  2514. }
  2515.  
  2516. TPacketCGPartySetState* p = (TPacketCGPartySetState*) c_pData;
  2517.  
  2518. if (!ch->GetParty())
  2519. return;
  2520.  
  2521. if (ch->GetParty()->GetLeaderPID() != ch->GetPlayerID())
  2522. {
  2523. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 리더만 변경할 수 있습니다."));
  2524. return;
  2525. }
  2526.  
  2527. if (!ch->GetParty()->IsMember(p->pid))
  2528. {
  2529. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 상태를 변경하려는 사람이 파티원이 아닙니다."));
  2530. return;
  2531. }
  2532.  
  2533. DWORD pid = p->pid;
  2534. sys_log(0, "PARTY SetRole pid %d to role %d state %s", pid, p->byRole, p->flag ? "on" : "off");
  2535.  
  2536. switch (p->byRole)
  2537. {
  2538. case PARTY_ROLE_NORMAL:
  2539. break;
  2540.  
  2541. case PARTY_ROLE_ATTACKER:
  2542. case PARTY_ROLE_TANKER:
  2543. case PARTY_ROLE_BUFFER:
  2544. case PARTY_ROLE_SKILL_MASTER:
  2545. case PARTY_ROLE_HASTE:
  2546. case PARTY_ROLE_DEFENDER:
  2547. if (ch->GetParty()->SetRole(pid, p->byRole, p->flag))
  2548. {
  2549. TPacketPartyStateChange pack;
  2550. pack.dwLeaderPID = ch->GetPlayerID();
  2551. pack.dwPID = p->pid;
  2552. pack.bRole = p->byRole;
  2553. pack.bFlag = p->flag;
  2554. db_clientdesc->DBPacket(HEADER_GD_PARTY_STATE_CHANGE, 0, &pack, sizeof(pack));
  2555. }
  2556. /* else
  2557. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 어태커 설정에 실패하였습니다.")); */
  2558. break;
  2559.  
  2560. default:
  2561. sys_err("wrong byRole in PartySetState Packet name %s state %d", ch->GetName(), p->byRole);
  2562. break;
  2563. }
  2564. }
  2565.  
  2566. void CInputMain::PartyRemove(LPCHARACTER ch, const char* c_pData)
  2567. {
  2568. if (ch->GetArena())
  2569. {
  2570. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다."));
  2571. return;
  2572. }
  2573.  
  2574. if (!CPartyManager::instance().IsEnablePCParty())
  2575. {
  2576. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다."));
  2577. return;
  2578. }
  2579.  
  2580. if (ch->GetDungeon())
  2581. {
  2582. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던전 안에서는 파티에서 추방할 수 없습니다."));
  2583. return;
  2584. }
  2585.  
  2586. TPacketCGPartyRemove* p = (TPacketCGPartyRemove*) c_pData;
  2587.  
  2588. if (!ch->GetParty())
  2589. return;
  2590.  
  2591. LPPARTY pParty = ch->GetParty();
  2592. if (pParty->GetLeaderPID() == ch->GetPlayerID())
  2593. {
  2594. if (ch->GetDungeon())
  2595. {
  2596. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던젼내에서는 파티원을 추방할 수 없습니다."));
  2597. }
  2598. else
  2599. {
  2600. // leader can remove any member
  2601. if (p->pid == ch->GetPlayerID() || pParty->GetMemberCount() == 2)
  2602. {
  2603. // party disband
  2604. CPartyManager::instance().DeleteParty(pParty);
  2605. }
  2606. else
  2607. {
  2608. LPCHARACTER B = CHARACTER_MANAGER::instance().FindByPID(p->pid);
  2609. if (B)
  2610. {
  2611. //pParty->SendPartyRemoveOneToAll(B);
  2612. B->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티에서 추방당하셨습니다."));
  2613. //pParty->Unlink(B);
  2614. //CPartyManager::instance().SetPartyMember(B->GetPlayerID(), NULL);
  2615. }
  2616. pParty->Quit(p->pid);
  2617. }
  2618. }
  2619. }
  2620. else
  2621. {
  2622. // otherwise, only remove itself
  2623. if (p->pid == ch->GetPlayerID())
  2624. {
  2625. if (ch->GetDungeon())
  2626. {
  2627. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던젼내에서는 파티를 나갈 수 없습니다."));
  2628. }
  2629. else
  2630. {
  2631. if (pParty->GetMemberCount() == 2)
  2632. {
  2633. // party disband
  2634. CPartyManager::instance().DeleteParty(pParty);
  2635. }
  2636. else
  2637. {
  2638. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티에서 나가셨습니다."));
  2639. //pParty->SendPartyRemoveOneToAll(ch);
  2640. pParty->Quit(ch->GetPlayerID());
  2641. //pParty->SendPartyRemoveAllToOne(ch);
  2642. //CPartyManager::instance().SetPartyMember(ch->GetPlayerID(), NULL);
  2643. }
  2644. }
  2645. }
  2646. else
  2647. {
  2648. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 다른 파티원을 탈퇴시킬 수 없습니다."));
  2649. }
  2650. }
  2651. }
  2652.  
  2653. void CInputMain::AnswerMakeGuild(LPCHARACTER ch, const char* c_pData)
  2654. {
  2655. TPacketCGAnswerMakeGuild* p = (TPacketCGAnswerMakeGuild*) c_pData;
  2656.  
  2657. if (ch->GetGold() < 200000)
  2658. return;
  2659.  
  2660. if (ch->GetLevel() < 40)
  2661. return;
  2662.  
  2663. if (get_global_time() - ch->GetQuestFlag("guild_manage.new_disband_time") <
  2664. CGuildManager::instance().GetDisbandDelay())
  2665. {
  2666. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 해산한 후 %d일 이내에는 길드를 만들 수 없습니다."),
  2667. quest::CQuestManager::instance().GetEventFlag("guild_disband_delay"));
  2668. return;
  2669. }
  2670.  
  2671. if (get_global_time() - ch->GetQuestFlag("guild_manage.new_withdraw_time") <
  2672. CGuildManager::instance().GetWithdrawDelay())
  2673. {
  2674. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 탈퇴한 후 %d일 이내에는 길드를 만들 수 없습니다."),
  2675. quest::CQuestManager::instance().GetEventFlag("guild_withdraw_delay"));
  2676. return;
  2677. }
  2678.  
  2679. if (ch->GetGuild())
  2680. return;
  2681.  
  2682. CGuildManager& gm = CGuildManager::instance();
  2683.  
  2684. TGuildCreateParameter cp;
  2685. memset(&cp, 0, sizeof(cp));
  2686.  
  2687. cp.master = ch;
  2688. strlcpy(cp.name, p->guild_name, sizeof(cp.name));
  2689.  
  2690. if (cp.name[0] == 0 || !check_name(cp.name))
  2691. {
  2692. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("적합하지 않은 길드 이름 입니다."));
  2693. return;
  2694. }
  2695.  
  2696. DWORD dwGuildID = gm.CreateGuild(cp);
  2697.  
  2698. if (dwGuildID)
  2699. {
  2700. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> [%s] 길드가 생성되었습니다."), cp.name);
  2701.  
  2702. int GuildCreateFee;
  2703.  
  2704. if (LC_IsBrazil())
  2705. {
  2706. GuildCreateFee = 500000;
  2707. }
  2708. else
  2709. {
  2710. GuildCreateFee = 200000;
  2711. }
  2712.  
  2713. ch->PointChange(POINT_GOLD, -GuildCreateFee);
  2714. DBManager::instance().SendMoneyLog(MONEY_LOG_GUILD, ch->GetPlayerID(), -GuildCreateFee);
  2715.  
  2716. char Log[128];
  2717. snprintf(Log, sizeof(Log), "GUILD_NAME %s MASTER %s", cp.name, ch->GetName());
  2718. LogManager::instance().CharLog(ch, 0, "MAKE_GUILD", Log);
  2719.  
  2720. if (g_iUseLocale)
  2721. ch->RemoveSpecifyItem(GUILD_CREATE_ITEM_VNUM, 1);
  2722. //ch->SendGuildName(dwGuildID);
  2723. }
  2724. else
  2725. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드 생성에 실패하였습니다."));
  2726. }
  2727.  
  2728. void CInputMain::PartyUseSkill(LPCHARACTER ch, const char* c_pData)
  2729. {
  2730. TPacketCGPartyUseSkill* p = (TPacketCGPartyUseSkill*) c_pData;
  2731. if (!ch->GetParty())
  2732. return;
  2733.  
  2734. if (ch->GetPlayerID() != ch->GetParty()->GetLeaderPID())
  2735. {
  2736. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티 기술은 파티장만 사용할 수 있습니다."));
  2737. return;
  2738. }
  2739.  
  2740. switch (p->bySkillIndex)
  2741. {
  2742. case PARTY_SKILL_HEAL:
  2743. ch->GetParty()->HealParty();
  2744. break;
  2745. case PARTY_SKILL_WARP:
  2746. {
  2747. LPCHARACTER pch = CHARACTER_MANAGER::instance().Find(p->vid);
  2748. if (pch)
  2749. ch->GetParty()->SummonToLeader(pch->GetPlayerID());
  2750. else
  2751. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 소환하려는 대상을 찾을 수 없습니다."));
  2752. }
  2753. break;
  2754. }
  2755. }
  2756.  
  2757. void CInputMain::PartyParameter(LPCHARACTER ch, const char * c_pData)
  2758. {
  2759. TPacketCGPartyParameter * p = (TPacketCGPartyParameter *) c_pData;
  2760.  
  2761. if (ch->GetParty())
  2762. ch->GetParty()->SetParameter(p->bDistributeMode);
  2763. }
  2764.  
  2765. size_t GetSubPacketSize(const GUILD_SUBHEADER_CG& header)
  2766. {
  2767. switch (header)
  2768. {
  2769. case GUILD_SUBHEADER_CG_DEPOSIT_MONEY: return sizeof(int);
  2770. case GUILD_SUBHEADER_CG_WITHDRAW_MONEY: return sizeof(int);
  2771. case GUILD_SUBHEADER_CG_ADD_MEMBER: return sizeof(DWORD);
  2772. case GUILD_SUBHEADER_CG_REMOVE_MEMBER: return sizeof(DWORD);
  2773. case GUILD_SUBHEADER_CG_CHANGE_GRADE_NAME: return 10;
  2774. case GUILD_SUBHEADER_CG_CHANGE_GRADE_AUTHORITY: return sizeof(BYTE) + sizeof(BYTE);
  2775. case GUILD_SUBHEADER_CG_OFFER: return sizeof(DWORD);
  2776. case GUILD_SUBHEADER_CG_CHARGE_GSP: return sizeof(int);
  2777. case GUILD_SUBHEADER_CG_POST_COMMENT: return 1;
  2778. case GUILD_SUBHEADER_CG_DELETE_COMMENT: return sizeof(DWORD);
  2779. case GUILD_SUBHEADER_CG_REFRESH_COMMENT: return 0;
  2780. case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GRADE: return sizeof(DWORD) + sizeof(BYTE);
  2781. case GUILD_SUBHEADER_CG_USE_SKILL: return sizeof(TPacketCGGuildUseSkill);
  2782. case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GENERAL: return sizeof(DWORD) + sizeof(BYTE);
  2783. case GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER: return sizeof(DWORD) + sizeof(BYTE);
  2784. }
  2785.  
  2786. return 0;
  2787. }
  2788.  
  2789. int CInputMain::Guild(LPCHARACTER ch, const char * data, size_t uiBytes)
  2790. {
  2791. if (uiBytes < sizeof(TPacketCGGuild))
  2792. return -1;
  2793.  
  2794. const TPacketCGGuild* p = reinterpret_cast<const TPacketCGGuild*>(data);
  2795. const char* c_pData = data + sizeof(TPacketCGGuild);
  2796.  
  2797. uiBytes -= sizeof(TPacketCGGuild);
  2798.  
  2799. const GUILD_SUBHEADER_CG SubHeader = static_cast<GUILD_SUBHEADER_CG>(p->subheader);
  2800. const size_t SubPacketLen = GetSubPacketSize(SubHeader);
  2801.  
  2802. if (uiBytes < SubPacketLen)
  2803. {
  2804. return -1;
  2805. }
  2806.  
  2807. CGuild* pGuild = ch->GetGuild();
  2808.  
  2809. if (NULL == pGuild)
  2810. {
  2811. if (SubHeader != GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER)
  2812. {
  2813. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드에 속해있지 않습니다."));
  2814. return SubPacketLen;
  2815. }
  2816. }
  2817.  
  2818. switch (SubHeader)
  2819. {
  2820. case GUILD_SUBHEADER_CG_DEPOSIT_MONEY:
  2821. {
  2822. // by mhh : 길드자금은 당분간 넣을 수 없다.
  2823. return SubPacketLen;
  2824.  
  2825. const int gold = MIN(*reinterpret_cast<const int*>(c_pData), __deposit_limit());
  2826.  
  2827. if (gold < 0)
  2828. {
  2829. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다."));
  2830. return SubPacketLen;
  2831. }
  2832.  
  2833. if (ch->GetGold() < gold)
  2834. {
  2835. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 가지고 있는 돈이 부족합니다."));
  2836. return SubPacketLen;
  2837. }
  2838.  
  2839. pGuild->RequestDepositMoney(ch, gold);
  2840. }
  2841. return SubPacketLen;
  2842.  
  2843. case GUILD_SUBHEADER_CG_WITHDRAW_MONEY:
  2844. {
  2845. // by mhh : 길드자금은 당분간 뺄 수 없다.
  2846. return SubPacketLen;
  2847.  
  2848. const int gold = MIN(*reinterpret_cast<const int*>(c_pData), 500000);
  2849.  
  2850. if (gold < 0)
  2851. {
  2852. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다."));
  2853. return SubPacketLen;
  2854. }
  2855.  
  2856. pGuild->RequestWithdrawMoney(ch, gold);
  2857. }
  2858. return SubPacketLen;
  2859.  
  2860. case GUILD_SUBHEADER_CG_ADD_MEMBER:
  2861. {
  2862. const DWORD vid = *reinterpret_cast<const DWORD*>(c_pData);
  2863. LPCHARACTER newmember = CHARACTER_MANAGER::instance().Find(vid);
  2864.  
  2865. if (!newmember)
  2866. {
  2867. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다."));
  2868. return SubPacketLen;
  2869. }
  2870.  
  2871. if (!ch->IsPC())
  2872. return SubPacketLen;
  2873.  
  2874. if (!newmember->IsPC())
  2875. return SubPacketLen;
  2876.  
  2877. if (LC_IsCanada() == true)
  2878. {
  2879. if (newmember->GetQuestFlag("change_guild_master.be_other_member") > get_global_time())
  2880. {
  2881. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 아직 가입할 수 없는 캐릭터입니다"));
  2882. return SubPacketLen;
  2883. }
  2884. }
  2885.  
  2886. pGuild->Invite(ch, newmember);
  2887. }
  2888. return SubPacketLen;
  2889.  
  2890. case GUILD_SUBHEADER_CG_REMOVE_MEMBER:
  2891. {
  2892. if (pGuild->UnderAnyWar() != 0)
  2893. {
  2894. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전 중에는 길드원을 탈퇴시킬 수 없습니다."));
  2895. return SubPacketLen;
  2896. }
  2897.  
  2898. const DWORD pid = *reinterpret_cast<const DWORD*>(c_pData);
  2899. const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID());
  2900.  
  2901. if (NULL == m)
  2902. return -1;
  2903.  
  2904. LPCHARACTER member = CHARACTER_MANAGER::instance().FindByPID(pid);
  2905.  
  2906. if (member)
  2907. {
  2908. if (member->GetGuild() != pGuild)
  2909. {
  2910. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방이 같은 길드가 아닙니다."));
  2911. return SubPacketLen;
  2912. }
  2913.  
  2914. if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER))
  2915. {
  2916. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다."));
  2917. return SubPacketLen;
  2918. }
  2919.  
  2920. member->SetQuestFlag("guild_manage.new_withdraw_time", get_global_time());
  2921. pGuild->RequestRemoveMember(member->GetPlayerID());
  2922.  
  2923. if (LC_IsBrazil() == true)
  2924. {
  2925. DBManager::instance().Query("REPLACE INTO guild_invite_limit VALUES(%d, %d)", pGuild->GetID(), get_global_time());
  2926. }
  2927. }
  2928. else
  2929. {
  2930. if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER))
  2931. {
  2932. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다."));
  2933. return SubPacketLen;
  2934. }
  2935.  
  2936. if (pGuild->RequestRemoveMember(pid))
  2937. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시켰습니다."));
  2938. else
  2939. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다."));
  2940. }
  2941. }
  2942. return SubPacketLen;
  2943.  
  2944. case GUILD_SUBHEADER_CG_CHANGE_GRADE_NAME:
  2945. {
  2946. char gradename[GUILD_GRADE_NAME_MAX_LEN + 1];
  2947. strlcpy(gradename, c_pData + 1, sizeof(gradename));
  2948.  
  2949. const TGuildMember * m = pGuild->GetMember(ch->GetPlayerID());
  2950.  
  2951. if (NULL == m)
  2952. return -1;
  2953.  
  2954. if (m->grade != GUILD_LEADER_GRADE)
  2955. {
  2956. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 이름을 변경할 권한이 없습니다."));
  2957. }
  2958. else if (*c_pData == GUILD_LEADER_GRADE)
  2959. {
  2960. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위 이름은 변경할 수 없습니다."));
  2961. }
  2962. else if (!check_name(gradename))
  2963. {
  2964. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 적합하지 않은 직위 이름 입니다."));
  2965. }
  2966. else
  2967. {
  2968. pGuild->ChangeGradeName(*c_pData, gradename);
  2969. }
  2970. }
  2971. return SubPacketLen;
  2972.  
  2973. case GUILD_SUBHEADER_CG_CHANGE_GRADE_AUTHORITY:
  2974. {
  2975. const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID());
  2976.  
  2977. if (NULL == m)
  2978. return -1;
  2979.  
  2980. if (m->grade != GUILD_LEADER_GRADE)
  2981. {
  2982. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 권한을 변경할 권한이 없습니다."));
  2983. }
  2984. else if (*c_pData == GUILD_LEADER_GRADE)
  2985. {
  2986. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 권한은 변경할 수 없습니다."));
  2987. }
  2988. else
  2989. {
  2990. pGuild->ChangeGradeAuth(*c_pData, *(c_pData + 1));
  2991. }
  2992. }
  2993. return SubPacketLen;
  2994.  
  2995. case GUILD_SUBHEADER_CG_OFFER:
  2996. {
  2997. DWORD offer = *reinterpret_cast<const DWORD*>(c_pData);
  2998.  
  2999. if (pGuild->GetLevel() >= GUILD_MAX_LEVEL && LC_IsHongKong() == false)
  3000. {
  3001. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드가 이미 최고 레벨입니다."));
  3002. }
  3003. else
  3004. {
  3005. offer /= 100;
  3006. offer *= 100;
  3007.  
  3008. if (pGuild->OfferExp(ch, offer))
  3009. {
  3010. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> %u의 경험치를 투자하였습니다."), offer);
  3011. }
  3012. else
  3013. {
  3014. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 경험치 투자에 실패하였습니다."));
  3015. }
  3016. }
  3017. }
  3018. return SubPacketLen;
  3019.  
  3020. case GUILD_SUBHEADER_CG_CHARGE_GSP:
  3021. {
  3022. const int offer = *reinterpret_cast<const int*>(c_pData);
  3023. const int gold = offer * 100;
  3024.  
  3025. if (offer < 0 || gold < offer || gold < 0 || ch->GetGold() < gold)
  3026. {
  3027. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 돈이 부족합니다."));
  3028. return SubPacketLen;
  3029. }
  3030.  
  3031. if (!pGuild->ChargeSP(ch, offer))
  3032. {
  3033. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 용신력 회복에 실패하였습니다."));
  3034. }
  3035. }
  3036. return SubPacketLen;
  3037.  
  3038. case GUILD_SUBHEADER_CG_POST_COMMENT:
  3039. {
  3040. const size_t length = *c_pData;
  3041.  
  3042. if (length > GUILD_COMMENT_MAX_LEN)
  3043. {
  3044. // 잘못된 길이.. 끊어주자.
  3045. sys_err("POST_COMMENT: %s comment too long (length: %u)", ch->GetName(), length);
  3046. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  3047. return -1;
  3048. }
  3049.  
  3050. if (uiBytes < 1 + length)
  3051. return -1;
  3052.  
  3053. const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID());
  3054.  
  3055. if (NULL == m)
  3056. return -1;
  3057.  
  3058. if (length && !pGuild->HasGradeAuth(m->grade, GUILD_AUTH_NOTICE) && *(c_pData + 1) == '!')
  3059. {
  3060. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 공지글을 작성할 권한이 없습니다."));
  3061. }
  3062. else
  3063. {
  3064. std::string str(c_pData + 1, length);
  3065. pGuild->AddComment(ch, str);
  3066. }
  3067.  
  3068. return (1 + length);
  3069. }
  3070.  
  3071. case GUILD_SUBHEADER_CG_DELETE_COMMENT:
  3072. {
  3073. const DWORD comment_id = *reinterpret_cast<const DWORD*>(c_pData);
  3074.  
  3075. pGuild->DeleteComment(ch, comment_id);
  3076. }
  3077. return SubPacketLen;
  3078.  
  3079. case GUILD_SUBHEADER_CG_REFRESH_COMMENT:
  3080. pGuild->RefreshComment(ch);
  3081. return SubPacketLen;
  3082.  
  3083. case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GRADE:
  3084. {
  3085. const DWORD pid = *reinterpret_cast<const DWORD*>(c_pData);
  3086. const BYTE grade = *(c_pData + sizeof(DWORD));
  3087. const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID());
  3088.  
  3089. if (NULL == m)
  3090. return -1;
  3091.  
  3092. if (m->grade != GUILD_LEADER_GRADE)
  3093. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위를 변경할 권한이 없습니다."));
  3094. else if (ch->GetPlayerID() == pid)
  3095. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위는 변경할 수 없습니다."));
  3096. else if (grade == 1)
  3097. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장으로 직위를 변경할 수 없습니다."));
  3098. else
  3099. pGuild->ChangeMemberGrade(pid, grade);
  3100. }
  3101. return SubPacketLen;
  3102.  
  3103. case GUILD_SUBHEADER_CG_USE_SKILL:
  3104. {
  3105. const TPacketCGGuildUseSkill* p = reinterpret_cast<const TPacketCGGuildUseSkill*>(c_pData);
  3106.  
  3107. pGuild->UseSkill(p->dwVnum, ch, p->dwPID);
  3108. }
  3109. return SubPacketLen;
  3110.  
  3111. case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GENERAL:
  3112. {
  3113. const DWORD pid = *reinterpret_cast<const DWORD*>(c_pData);
  3114. const BYTE is_general = *(c_pData + sizeof(DWORD));
  3115. const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID());
  3116.  
  3117. if (NULL == m)
  3118. return -1;
  3119.  
  3120. if (m->grade != GUILD_LEADER_GRADE)
  3121. {
  3122. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 장군을 지정할 권한이 없습니다."));
  3123. }
  3124. else
  3125. {
  3126. if (!pGuild->ChangeMemberGeneral(pid, is_general))
  3127. {
  3128. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 더이상 장수를 지정할 수 없습니다."));
  3129. }
  3130. }
  3131. }
  3132. return SubPacketLen;
  3133.  
  3134. case GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER:
  3135. {
  3136. const DWORD guild_id = *reinterpret_cast<const DWORD*>(c_pData);
  3137. const BYTE accept = *(c_pData + sizeof(DWORD));
  3138.  
  3139. CGuild * g = CGuildManager::instance().FindGuild(guild_id);
  3140.  
  3141. if (g)
  3142. {
  3143. if (accept)
  3144. g->InviteAccept(ch);
  3145. else
  3146. g->InviteDeny(ch->GetPlayerID());
  3147. }
  3148. }
  3149. return SubPacketLen;
  3150.  
  3151. }
  3152.  
  3153. return 0;
  3154. }
  3155.  
  3156. void CInputMain::Fishing(LPCHARACTER ch, const char* c_pData)
  3157. {
  3158. TPacketCGFishing* p = (TPacketCGFishing*)c_pData;
  3159. ch->SetRotation(p->dir * 5);
  3160. ch->fishing();
  3161. return;
  3162. }
  3163.  
  3164. void CInputMain::ItemGive(LPCHARACTER ch, const char* c_pData)
  3165. {
  3166. TPacketCGGiveItem* p = (TPacketCGGiveItem*) c_pData;
  3167. LPCHARACTER to_ch = CHARACTER_MANAGER::instance().Find(p->dwTargetVID);
  3168.  
  3169. if (to_ch)
  3170. ch->GiveItem(to_ch, p->ItemPos);
  3171. else
  3172. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아이템을 건네줄 수 없습니다."));
  3173. }
  3174.  
  3175. void CInputMain::Hack(LPCHARACTER ch, const char * c_pData)
  3176. {
  3177. TPacketCGHack * p = (TPacketCGHack *) c_pData;
  3178.  
  3179. char buf[sizeof(p->szBuf)];
  3180. strlcpy(buf, p->szBuf, sizeof(buf));
  3181.  
  3182. sys_err("HACK_DETECT: %s %s", ch->GetName(), buf);
  3183.  
  3184. // 현재 클라이언트에서 이 패킷을 보내는 경우가 없으므로 무조건 끊도록 한다
  3185. ch->GetDesc()->SetPhase(PHASE_CLOSE);
  3186. }
  3187.  
  3188. int CInputMain::MyShop(LPCHARACTER ch, const char * c_pData, size_t uiBytes)
  3189. {
  3190. TPacketCGMyShop * p = (TPacketCGMyShop *) c_pData;
  3191. int iExtraLen = p->bCount * sizeof(TShopItemTable);
  3192.  
  3193. if (uiBytes < sizeof(TPacketCGMyShop) + iExtraLen)
  3194. return -1;
  3195.  
  3196. if (ch->GetGold() >= GOLD_MAX)
  3197. {
  3198. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소유 돈이 20억냥을 넘어 거래를 핼수가 없습니다."));
  3199. sys_log(0, "MyShop ==> OverFlow Gold id %u name %s ", ch->GetPlayerID(), ch->GetName());
  3200. return (iExtraLen);
  3201. }
  3202.  
  3203. if (ch->IsStun() || ch->IsDead())
  3204. return (iExtraLen);
  3205.  
  3206. if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->GetOfflineShopOwner())
  3207. {
  3208. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중일경우 개인상점을 열수가 없습니다."));
  3209. return (iExtraLen);
  3210. }
  3211.  
  3212. sys_log(0, "MyShop count %d", p->bCount);
  3213. ch->OpenMyShop(p->szSign, (TShopItemTable *) (c_pData + sizeof(TPacketCGMyShop)), p->bCount);
  3214. return (iExtraLen);
  3215. }
  3216.  
  3217. int CInputMain::MyOfflineShop(LPCHARACTER ch, const char * c_pData, size_t uiBytes)
  3218. {
  3219. TPacketCGMyOfflineShop * p = (TPacketCGMyOfflineShop *)c_pData;
  3220. int iExtraLen = p->bCount * sizeof(TOfflineShopItemTable);
  3221.  
  3222. if (uiBytes < sizeof(TPacketCGMyOfflineShop) + iExtraLen)
  3223. return -1;
  3224.  
  3225. if (ch->IsStun() || ch->IsDead())
  3226. return (iExtraLen);
  3227.  
  3228. if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->GetOfflineShopOwner())
  3229. {
  3230. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중일경우 개인상점을 열수가 없습니다."));
  3231. return (iExtraLen);
  3232. }
  3233.  
  3234. sys_log(0, "MyOfflineShop count %d", p->bCount);
  3235. ch->OpenMyOfflineShop(p->szSign, (TOfflineShopItemTable *)(c_pData + sizeof(TPacketCGMyOfflineShop)), p->bCount, p->bTime, p->bNpcType);
  3236. return (iExtraLen);
  3237. }
  3238.  
  3239. void CInputMain::Refine(LPCHARACTER ch, const char* c_pData)
  3240. {
  3241. const TPacketCGRefine* p = reinterpret_cast<const TPacketCGRefine*>(c_pData);
  3242.  
  3243. if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->GetMyShop() || ch->IsCubeOpen() || ch->GetOfflineShopOwner())
  3244. {
  3245. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고,거래창등이 열린 상태에서는 개량을 할수가 없습니다"));
  3246. ch->ClearRefineMode();
  3247. return;
  3248. }
  3249.  
  3250. if (p->type == 255)
  3251. {
  3252. // DoRefine Cancel
  3253. ch->ClearRefineMode();
  3254. return;
  3255. }
  3256.  
  3257. if (p->pos >= INVENTORY_MAX_NUM)
  3258. {
  3259. ch->ClearRefineMode();
  3260. return;
  3261. }
  3262.  
  3263. LPITEM item = ch->GetInventoryItem(p->pos);
  3264.  
  3265. if (!item)
  3266. {
  3267. ch->ClearRefineMode();
  3268. return;
  3269. }
  3270.  
  3271. ch->SetRefineTime();
  3272.  
  3273. if (p->type == REFINE_TYPE_NORMAL)
  3274. {
  3275. sys_log (0, "refine_type_noraml");
  3276. ch->DoRefine(item);
  3277. }
  3278. else if (p->type == REFINE_TYPE_SCROLL || p->type == REFINE_TYPE_HYUNIRON || p->type == REFINE_TYPE_MUSIN || p->type == REFINE_TYPE_BDRAGON)
  3279. {
  3280. sys_log (0, "refine_type_scroll, ...");
  3281. ch->DoRefineWithScroll(item);
  3282. }
  3283. else if (p->type == REFINE_TYPE_MONEY_ONLY)
  3284. {
  3285. const LPITEM item = ch->GetInventoryItem(p->pos);
  3286.  
  3287. if (NULL != item)
  3288. {
  3289. if (500 <= item->GetRefineSet())
  3290. {
  3291. LogManager::instance().HackLog("DEVIL_TOWER_REFINE_HACK", ch);
  3292. }
  3293. else
  3294. {
  3295. if (ch->GetQuestFlag("deviltower_zone.can_refine"))
  3296. {
  3297. ch->DoRefine(item, true);
  3298. ch->SetQuestFlag("deviltower_zone.can_refine", 0);
  3299. }
  3300. else
  3301. {
  3302. ch->ChatPacket(CHAT_TYPE_INFO, "사귀 타워 완료 보상은 한번까지 사용가능합니다.");
  3303. }
  3304. }
  3305. }
  3306. }
  3307.  
  3308. ch->ClearRefineMode();
  3309. }
  3310.  
  3311. void CInputMain::SoulStoneUse(LPCHARACTER ch, const char* c_pData)
  3312. {
  3313. TPacketCGSoulStoneUse* p = (TPacketCGSoulStoneUse*)c_pData;
  3314.  
  3315. // check general data
  3316. const DWORD* c_adwAvailSkillVnums = ch->GetUsableSkillList();
  3317. if (!c_adwAvailSkillVnums)
  3318. return;
  3319.  
  3320. bool bFoundVnum = false;
  3321. for (int i = 0; i < CHARACTER_SKILL_COUNT; ++i)
  3322. {
  3323. if (!c_adwAvailSkillVnums[i])
  3324. continue;
  3325.  
  3326. if (c_adwAvailSkillVnums[i] == p->skillIndex)
  3327. {
  3328. bFoundVnum = true;
  3329. break;
  3330. }
  3331. }
  3332. if (!bFoundVnum)
  3333. return;
  3334.  
  3335. if (ch->GetSkillMasterType(p->skillIndex) != SKILL_GRAND_MASTER)
  3336. return;
  3337.  
  3338. if (!p->Cell.IsDefaultInventoryPosition())
  3339. return;
  3340.  
  3341. // check item
  3342. LPITEM pkItem = ch->GetInventoryItem(p->Cell.cell);
  3343. if (!pkItem || !CItemVnumHelper::IsSoulStone(pkItem->GetVnum()))
  3344. return;
  3345.  
  3346. if (pkItem->IsExchanging())
  3347. return;
  3348.  
  3349. if (ch->GetRaceNum() >= MAIN_RACE_MAX_NUM)
  3350. return;
  3351.  
  3352. // use soulstones
  3353. BYTE bCount = p->all ? pkItem->GetCount() : 1;
  3354. BYTE bUseCount = 0;
  3355. BYTE bSuccessCount = 0;
  3356.  
  3357. for (int i = 0; i < bCount; ++i)
  3358. {
  3359. ++bUseCount;
  3360.  
  3361. if (ch->LearnGrandMasterSkill(p->skillIndex))
  3362. {
  3363. ++bSuccessCount;
  3364. if (ch->GetSkillMasterType(p->skillIndex) > SKILL_GRAND_MASTER)
  3365. break;
  3366. }
  3367. }
  3368.  
  3369. pkItem->SetCount(pkItem->GetCount() - bUseCount);
  3370.  
  3371. if (bSuccessCount == 0)
  3372. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Egitim basarisiz oldu."));
  3373. else if (ch->GetSkillMasterType(p->skillIndex) > SKILL_GRAND_MASTER)
  3374. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Grandmaster seviyesinde basarili oldunuz."));
  3375. else if (bCount == 1)
  3376. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Egitim basarili oldu."));
  3377. else if (bCount == bSuccessCount)
  3378. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Tum ruh taslari basariyla kullanildi."));
  3379. else
  3380. ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%d/%d ruh taslari basariyla kullanildi."), bSuccessCount, bCount);
  3381. }
  3382.  
  3383. #ifdef __SASH_SYSTEM__
  3384. void CInputMain::Sash(LPCHARACTER pkChar, const char* c_pData)
  3385. {
  3386. quest::PC * pPC = quest::CQuestManager::instance().GetPCForce(pkChar->GetPlayerID());
  3387. if (pPC->IsRunning())
  3388. return;
  3389.  
  3390. TPacketSash * sPacket = (TPacketSash*) c_pData;
  3391. switch (sPacket->subheader)
  3392. {
  3393. case SASH_SUBHEADER_CG_CLOSE:
  3394. {
  3395. pkChar->CloseSash();
  3396. }
  3397. break;
  3398. case SASH_SUBHEADER_CG_ADD:
  3399. {
  3400. pkChar->AddSashMaterial(sPacket->tPos, sPacket->bPos);
  3401. }
  3402. break;
  3403. case SASH_SUBHEADER_CG_REMOVE:
  3404. {
  3405. pkChar->RemoveSashMaterial(sPacket->bPos);
  3406. }
  3407. break;
  3408. case SASH_SUBHEADER_CG_REFINE:
  3409. {
  3410. pkChar->RefineSashMaterials();
  3411. }
  3412. break;
  3413. default:
  3414. break;
  3415. }
  3416. }
  3417. #endif
  3418.  
  3419. int CInputMain::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
  3420. {
  3421. LPCHARACTER ch;
  3422.  
  3423. if (!(ch = d->GetCharacter()))
  3424. {
  3425. sys_err("no character on desc");
  3426. d->SetPhase(PHASE_CLOSE);
  3427. return (0);
  3428. }
  3429.  
  3430. int iExtraLen = 0;
  3431.  
  3432. if (test_server && bHeader != HEADER_CG_MOVE)
  3433. sys_log(0, "CInputMain::Analyze() ==> Header [%d] ", bHeader);
  3434.  
  3435. switch (bHeader)
  3436. {
  3437. case HEADER_CG_PONG:
  3438. Pong(d);
  3439. break;
  3440.  
  3441. case HEADER_CG_TIME_SYNC:
  3442. Handshake(d, c_pData);
  3443. break;
  3444.  
  3445. case HEADER_CG_CHAT:
  3446. if (test_server)
  3447. {
  3448. char* pBuf = (char*)c_pData;
  3449. sys_log(0, "%s", pBuf + sizeof(TPacketCGChat));
  3450. }
  3451.  
  3452. if ((iExtraLen = Chat(ch, c_pData, m_iBufferLeft)) < 0)
  3453. return -1;
  3454. break;
  3455.  
  3456. case HEADER_CG_WHISPER:
  3457. if ((iExtraLen = Whisper(ch, c_pData, m_iBufferLeft)) < 0)
  3458. return -1;
  3459. break;
  3460.  
  3461. case HEADER_CG_MOVE:
  3462. Move(ch, c_pData);
  3463.  
  3464. if (LC_IsEurope())
  3465. {
  3466. if (g_bCheckClientVersion)
  3467. {
  3468. int version = atoi(g_stClientVersion.c_str());
  3469. int date = atoi(d->GetClientVersion());
  3470.  
  3471. //if (0 != g_stClientVersion.compare(d->GetClientVersion()))
  3472. if (version > date)
  3473. {
  3474. ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요."));
  3475. d->DelayedDisconnect(10);
  3476. LogManager::instance().HackLog("VERSION_CONFLICT", d->GetAccountTable().login, ch->GetName(), d->GetHostName());
  3477. }
  3478. }
  3479. }
  3480. else
  3481. {
  3482. if (!*d->GetClientVersion())
  3483. {
  3484. sys_err("Version not recieved name %s", ch->GetName());
  3485. d->SetPhase(PHASE_CLOSE);
  3486. }
  3487. }
  3488. break;
  3489.  
  3490. case HEADER_CG_CHARACTER_POSITION:
  3491. Position(ch, c_pData);
  3492. break;
  3493.  
  3494. case HEADER_CG_ITEM_USE:
  3495. if (!ch->IsObserverMode())
  3496. ItemUse(ch, c_pData);
  3497. break;
  3498.  
  3499. case HEADER_CG_ITEM_DROP:
  3500. if (!ch->IsObserverMode())
  3501. {
  3502. ItemDrop(ch, c_pData);
  3503. }
  3504. break;
  3505.  
  3506. case HEADER_CG_ITEM_DROP2:
  3507. if (!ch->IsObserverMode())
  3508. ItemDrop2(ch, c_pData);
  3509. break;
  3510.  
  3511. case HEADER_CG_ITEM_DESTROY:
  3512. if (!ch->IsObserverMode())
  3513. ItemDestroy(ch, c_pData);
  3514. break;
  3515.  
  3516. case HEADER_CG_ITEM_MOVE:
  3517. if (!ch->IsObserverMode())
  3518. ItemMove(ch, c_pData);
  3519. break;
  3520.  
  3521. case HEADER_CG_ITEM_PICKUP:
  3522. if (!ch->IsObserverMode())
  3523. ItemPickup(ch, c_pData);
  3524. break;
  3525.  
  3526. case HEADER_CG_ITEM_USE_TO_ITEM:
  3527. if (!ch->IsObserverMode())
  3528. ItemToItem(ch, c_pData);
  3529. break;
  3530.  
  3531. case HEADER_CG_ITEM_GIVE:
  3532. if (!ch->IsObserverMode())
  3533. ItemGive(ch, c_pData);
  3534. break;
  3535.  
  3536. case HEADER_CG_EXCHANGE:
  3537. if (!ch->IsObserverMode())
  3538. Exchange(ch, c_pData);
  3539. break;
  3540.  
  3541. case HEADER_CG_ATTACK:
  3542. case HEADER_CG_SHOOT:
  3543. if (!ch->IsObserverMode())
  3544. {
  3545. Attack(ch, bHeader, c_pData);
  3546. }
  3547. break;
  3548.  
  3549. case HEADER_CG_USE_SKILL:
  3550. if (!ch->IsObserverMode())
  3551. UseSkill(ch, c_pData);
  3552. break;
  3553.  
  3554. case HEADER_CG_QUICKSLOT_ADD:
  3555. QuickslotAdd(ch, c_pData);
  3556. break;
  3557.  
  3558. case HEADER_CG_QUICKSLOT_DEL:
  3559. QuickslotDelete(ch, c_pData);
  3560. break;
  3561.  
  3562. case HEADER_CG_QUICKSLOT_SWAP:
  3563. QuickslotSwap(ch, c_pData);
  3564. break;
  3565.  
  3566. case HEADER_CG_SHOP:
  3567. if ((iExtraLen = Shop(ch, c_pData, m_iBufferLeft)) < 0)
  3568. return -1;
  3569. break;
  3570.  
  3571. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  3572. case HEADER_CG_OFFLINE_SHOP:
  3573. if ((iExtraLen = OfflineShop(ch, c_pData, m_iBufferLeft)) < 0)
  3574. return -1;
  3575. break;
  3576. #endif
  3577.  
  3578. case HEADER_CG_MESSENGER:
  3579. if ((iExtraLen = Messenger(ch, c_pData, m_iBufferLeft))<0)
  3580. return -1;
  3581. break;
  3582.  
  3583. case HEADER_CG_ON_CLICK:
  3584. OnClick(ch, c_pData);
  3585. break;
  3586.  
  3587. case HEADER_CG_SYNC_POSITION:
  3588. if ((iExtraLen = SyncPosition(ch, c_pData, m_iBufferLeft)) < 0)
  3589. return -1;
  3590. break;
  3591.  
  3592. case HEADER_CG_ADD_FLY_TARGETING:
  3593. case HEADER_CG_FLY_TARGETING:
  3594. FlyTarget(ch, c_pData, bHeader);
  3595. break;
  3596.  
  3597. case HEADER_CG_SCRIPT_BUTTON:
  3598. ScriptButton(ch, c_pData);
  3599. break;
  3600.  
  3601. // SCRIPT_SELECT_ITEM
  3602. case HEADER_CG_SCRIPT_SELECT_ITEM:
  3603. ScriptSelectItem(ch, c_pData);
  3604. break;
  3605. // END_OF_SCRIPT_SELECT_ITEM
  3606.  
  3607. case HEADER_CG_SCRIPT_ANSWER:
  3608. ScriptAnswer(ch, c_pData);
  3609. break;
  3610.  
  3611. case HEADER_CG_QUEST_INPUT_STRING:
  3612. QuestInputString(ch, c_pData);
  3613. break;
  3614.  
  3615. case HEADER_CG_QUEST_CONFIRM:
  3616. QuestConfirm(ch, c_pData);
  3617. break;
  3618.  
  3619. case HEADER_CG_TARGET:
  3620. Target(ch, c_pData);
  3621. break;
  3622.  
  3623. case HEADER_CG_WARP:
  3624. Warp(ch, c_pData);
  3625. break;
  3626.  
  3627. case HEADER_CG_SAFEBOX_CHECKIN:
  3628. SafeboxCheckin(ch, c_pData);
  3629. break;
  3630.  
  3631. case HEADER_CG_SAFEBOX_CHECKOUT:
  3632. SafeboxCheckout(ch, c_pData, false);
  3633. break;
  3634.  
  3635. case HEADER_CG_SAFEBOX_ITEM_MOVE:
  3636. SafeboxItemMove(ch, c_pData);
  3637. break;
  3638.  
  3639. case HEADER_CG_MALL_CHECKOUT:
  3640. SafeboxCheckout(ch, c_pData, true);
  3641. break;
  3642.  
  3643. case HEADER_CG_PARTY_INVITE:
  3644. PartyInvite(ch, c_pData);
  3645. break;
  3646.  
  3647. case HEADER_CG_PARTY_REMOVE:
  3648. PartyRemove(ch, c_pData);
  3649. break;
  3650.  
  3651. case HEADER_CG_PARTY_INVITE_ANSWER:
  3652. PartyInviteAnswer(ch, c_pData);
  3653. break;
  3654.  
  3655. case HEADER_CG_PARTY_SET_STATE:
  3656. PartySetState(ch, c_pData);
  3657. break;
  3658.  
  3659. case HEADER_CG_PARTY_USE_SKILL:
  3660. PartyUseSkill(ch, c_pData);
  3661. break;
  3662.  
  3663. case HEADER_CG_PARTY_PARAMETER:
  3664. PartyParameter(ch, c_pData);
  3665. break;
  3666.  
  3667. case HEADER_CG_ANSWER_MAKE_GUILD:
  3668. AnswerMakeGuild(ch, c_pData);
  3669. break;
  3670.  
  3671. case HEADER_CG_GUILD:
  3672. if ((iExtraLen = Guild(ch, c_pData, m_iBufferLeft)) < 0)
  3673. return -1;
  3674. break;
  3675.  
  3676. case HEADER_CG_FISHING:
  3677. Fishing(ch, c_pData);
  3678. break;
  3679.  
  3680. case HEADER_CG_HACK:
  3681. Hack(ch, c_pData);
  3682. break;
  3683.  
  3684. case HEADER_CG_PetSetName:
  3685. BraveRequestPetName(ch, c_pData);
  3686. break;
  3687.  
  3688. case HEADER_CG_MYSHOP:
  3689. if ((iExtraLen = MyShop(ch, c_pData, m_iBufferLeft)) < 0)
  3690. return -1;
  3691. break;
  3692.  
  3693. #ifdef ENABLE_OFFLINE_SHOP_SYSTEM
  3694. case HEADER_CG_MY_OFFLINE_SHOP:
  3695. if ((iExtraLen = MyOfflineShop(ch, c_pData, m_iBufferLeft)) < 0)
  3696. return -1;
  3697. break;
  3698. #endif
  3699.  
  3700. case HEADER_CG_REFINE:
  3701. Refine(ch, c_pData);
  3702. break;
  3703.  
  3704. #ifdef __SASH_SYSTEM__
  3705. case HEADER_CG_SASH:
  3706. Sash(ch, c_pData);
  3707. break;
  3708. #endif
  3709.  
  3710. case HEADER_CG_CLIENT_VERSION:
  3711. Version(ch, c_pData);
  3712. break;
  3713.  
  3714. case HEADER_CG_HS_ACK:
  3715. if (isHackShieldEnable)
  3716. {
  3717. CHackShieldManager::instance().VerifyAck(d->GetCharacter(), c_pData);
  3718. }
  3719. break;
  3720.  
  3721. case HEADER_CG_XTRAP_ACK:
  3722. {
  3723. TPacketXTrapCSVerify* p = reinterpret_cast<TPacketXTrapCSVerify*>((void*)c_pData);
  3724. CXTrapManager::instance().Verify_CSStep3(d->GetCharacter(), p->bPacketData);
  3725. }
  3726. break;
  3727. case HEADER_CG_SOULSTONE_USE:
  3728. SoulStoneUse(ch, c_pData);
  3729. break;
  3730. case HEADER_CG_TARGET_INFO_LOAD:
  3731. {
  3732. TargetInfoLoad(ch, c_pData);
  3733. }
  3734. break;
  3735. case HEADER_CG_DRAGON_SOUL_REFINE:
  3736. {
  3737. TPacketCGDragonSoulRefine* p = reinterpret_cast <TPacketCGDragonSoulRefine*>((void*)c_pData);
  3738. switch(p->bSubType)
  3739. {
  3740. case DS_SUB_HEADER_CLOSE:
  3741. ch->DragonSoul_RefineWindow_Close();
  3742. break;
  3743. case DS_SUB_HEADER_DO_REFINE_GRADE:
  3744. {
  3745. DSManager::instance().DoRefineGrade(ch, p->ItemGrid);
  3746. }
  3747. break;
  3748. case DS_SUB_HEADER_DO_REFINE_STEP:
  3749. {
  3750. DSManager::instance().DoRefineStep(ch, p->ItemGrid);
  3751. }
  3752. break;
  3753. case DS_SUB_HEADER_DO_REFINE_STRENGTH:
  3754. {
  3755. DSManager::instance().DoRefineStrength(ch, p->ItemGrid);
  3756. }
  3757. break;
  3758. }
  3759. }
  3760. break;
  3761. #ifdef __TITLE_SYSTEM__
  3762. case HEADER_CG_TITLE_CHOOSE:
  3763. {
  3764. TPacketGGTitleInfo* p = reinterpret_cast <TPacketGGTitleInfo*>((void*)c_pData);
  3765. if (ch)
  3766. ch->pChooseTitle(p->iTitle);
  3767. }
  3768. break;
  3769. #endif
  3770. }
  3771. return (iExtraLen);
  3772. }
  3773.  
  3774. int CInputDead::Analyze(LPDESC d, BYTE bHeader, const char * c_pData)
  3775. {
  3776. LPCHARACTER ch;
  3777.  
  3778. if (!(ch = d->GetCharacter()))
  3779. {
  3780. sys_err("no character on desc");
  3781. return 0;
  3782. }
  3783.  
  3784. int iExtraLen = 0;
  3785.  
  3786. switch (bHeader)
  3787. {
  3788. case HEADER_CG_PONG:
  3789. Pong(d);
  3790. break;
  3791.  
  3792. case HEADER_CG_TIME_SYNC:
  3793. Handshake(d, c_pData);
  3794. break;
  3795.  
  3796. case HEADER_CG_CHAT:
  3797. if ((iExtraLen = Chat(ch, c_pData, m_iBufferLeft)) < 0)
  3798. return -1;
  3799.  
  3800. break;
  3801.  
  3802. case HEADER_CG_WHISPER:
  3803. if ((iExtraLen = Whisper(ch, c_pData, m_iBufferLeft)) < 0)
  3804. return -1;
  3805.  
  3806. break;
  3807.  
  3808. case HEADER_CG_HACK:
  3809. Hack(ch, c_pData);
  3810. break;
  3811.  
  3812. default:
  3813. return (0);
  3814. }
  3815.  
  3816. return (iExtraLen);
  3817. }
Advertisement
Add Comment
Please, Sign In to add comment