Guest User

Untitled

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