Advertisement
Guest User

input_main.cpp

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