Guest User

Untitled

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