Advertisement
Guest User

GLOBAL CHAT

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