Guest User

Untitled

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