Advertisement
Guest User

hi

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