Advertisement
Guest User

Untitled

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