Guest User

Untitled

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