Guest User

Untitled

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