Advertisement
Guest User

input

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