#include "../../common/service.h" #include "stdafx.h" #include "constants.h" #include "config.h" #include "utils.h" #include "desc_client.h" #include "desc_manager.h" #include "buffer_manager.h" #include "packet.h" #include "protocol.h" #include "char.h" #include "char_manager.h" #include "item.h" #include "item_manager.h" #include "cmd.h" #include "shop.h" #include "shop_manager.h" #include "safebox.h" #include "regen.h" #include "battle.h" #include "exchange.h" #include "questmanager.h" #include "profiler.h" #include "messenger_manager.h" #include "party.h" #include "p2p.h" #include "affect.h" #include "guild.h" #include "guild_manager.h" #include "log.h" #include "banword.h" #include "empire_text_convert.h" #include "unique_item.h" #include "building.h" #include "locale_service.h" #include "gm.h" #include "spam.h" #include "ani.h" #include "motion.h" #include "OXEvent.h" #include "locale_service.h" #include "DragonSoul.h" #include "belt_inventory_helper.h" #ifdef ENABLE_SWITCHBOT #include "new_switchbot.h" #endif #ifdef ENABLE_ATTENDANCE_EVENT #include "minigame.h" #endif #if defined(ENABLE_COMBAT_ZONE) #include "combat_zone.h" #endif #ifdef ENABLE_NEW_PET_SYSTEM #include "New_PetSystem.h" #endif #ifdef ENABLE_WHISPER_ADMIN_SYSTEM #include "whisper_admin.h" #endif #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM #include "offline_shop.h" #include "offlineshop_manager.h" #endif #ifdef ENABLE_BATTLE_PASS #include "battle_pass.h" #endif #ifdef ENABLE_RENEW_MESSENGER_WHISPER #include "profile.h" #endif #ifdef ENABLE_PRIVATE_SHOP_SEARCH_SYSTEM #include "entity.h" #include bool CompareItemVnumAcPriceAC(COfflineShop::OFFLINE_SHOP_ITEM i, COfflineShop::OFFLINE_SHOP_ITEM j) { return (i.vnum < j.vnum) && (i.price < j.price); } #endif #ifdef ENABLE_NEW_CHAT_VIEW const char* ConvertEmpireIndexToStr(int32_t empireIndex) { #define EMPIRE_RED 1 #define EMPIRE_YELLOW 2 #define EMPIRE_BLUE 3 switch (empireIndex) { case EMPIRE_RED: return "a"; case EMPIRE_YELLOW: return "b"; case EMPIRE_BLUE: return "c"; default: return ""; } } #endif extern void SendShout(const char * szText, BYTE bEmpire); extern int g_nPortalLimitTime; static int __deposit_limit() { return (1000*10000); // 1천만 } #ifdef ENABLE_SEND_TARGET_INFO void CInputMain::TargetInfoLoad(LPCHARACTER ch, const char* c_pData) { TPacketCGTargetInfoLoad* p = (TPacketCGTargetInfoLoad*)c_pData; TPacketGCTargetInfo pInfo; pInfo.header = HEADER_GC_TARGET_INFO; static std::vector s_vec_item; s_vec_item.clear(); LPITEM pkInfoItem; LPCHARACTER m_pkChrTarget = CHARACTER_MANAGER::instance().Find(p->dwVID); if (!ch || !m_pkChrTarget) return; if (ITEM_MANAGER::instance().CreateDropItemVector(m_pkChrTarget, ch, s_vec_item) && (m_pkChrTarget->IsMonster() || m_pkChrTarget->IsStone())) { if (s_vec_item.size() == 0); else if (s_vec_item.size() == 1) { pkInfoItem = s_vec_item[0]; pInfo.dwVID = m_pkChrTarget->GetVID(); pInfo.race = m_pkChrTarget->GetRaceNum(); pInfo.dwVnum = pkInfoItem->GetVnum(); pInfo.count = pkInfoItem->GetCount(); ch->GetDesc()->Packet(&pInfo, sizeof(TPacketGCTargetInfo)); } else { int iItemIdx = s_vec_item.size() - 1; while (iItemIdx >= 0) { pkInfoItem = s_vec_item[iItemIdx--]; if (!pkInfoItem) { sys_err("pkInfoItem null in vector idx %d", iItemIdx + 1); continue; } pInfo.dwVID = m_pkChrTarget->GetVID(); pInfo.race = m_pkChrTarget->GetRaceNum(); pInfo.dwVnum = pkInfoItem->GetVnum(); pInfo.count = pkInfoItem->GetCount(); ch->GetDesc()->Packet(&pInfo, sizeof(TPacketGCTargetInfo)); } } } } #endif void SendBlockChatInfo(LPCHARACTER ch, int sec) { if (sec <= 0) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("채팅 금지 상태입니다.")); return; } long hour = sec / 3600; sec -= hour * 3600; long min = (sec / 60); sec -= min * 60; char buf[128 + 1]; if (hour > 0 && min > 0) snprintf(buf, sizeof(buf), LC_TEXT("%d 시간 %d 분 %d 초 동안 채팅금지 상태입니다"), hour, min, sec); else if (hour > 0 && min == 0) snprintf(buf, sizeof(buf), LC_TEXT("%d 시간 %d 초 동안 채팅금지 상태입니다"), hour, sec); else if (hour == 0 && min > 0) snprintf(buf, sizeof(buf), LC_TEXT("%d 분 %d 초 동안 채팅금지 상태입니다"), min, sec); else snprintf(buf, sizeof(buf), LC_TEXT("%d 초 동안 채팅금지 상태입니다"), sec); ch->ChatPacket(CHAT_TYPE_INFO, buf); } EVENTINFO(spam_event_info) { char host[MAX_HOST_LENGTH+1]; spam_event_info() { ::memset( host, 0, MAX_HOST_LENGTH+1 ); } }; typedef boost::unordered_map > spam_score_of_ip_t; spam_score_of_ip_t spam_score_of_ip; EVENTFUNC(block_chat_by_ip_event) { spam_event_info* info = dynamic_cast( event->info ); if ( info == NULL ) { sys_err( "block_chat_by_ip_event> Null pointer" ); return 0; } const char * host = info->host; spam_score_of_ip_t::iterator it = spam_score_of_ip.find(host); if (it != spam_score_of_ip.end()) { it->second.first = 0; it->second.second = NULL; } return 0; } bool SpamBlockCheck(LPCHARACTER ch, const char* const buf, const size_t buflen) { extern int g_iSpamBlockMaxLevel; if (ch->GetLevel() < g_iSpamBlockMaxLevel) { spam_score_of_ip_t::iterator it = spam_score_of_ip.find(ch->GetDesc()->GetHostName()); if (it == spam_score_of_ip.end()) { spam_score_of_ip.insert(std::make_pair(ch->GetDesc()->GetHostName(), std::make_pair(0, (LPEVENT) NULL))); it = spam_score_of_ip.find(ch->GetDesc()->GetHostName()); } if (it->second.second) { SendBlockChatInfo(ch, event_time(it->second.second) / passes_per_sec); return true; } unsigned int score; const char * word = SpamManager::instance().GetSpamScore(buf, buflen, score); it->second.first += score; if (word) sys_log(0, "SPAM_SCORE: %s text: %s score: %u total: %u word: %s", ch->GetName(), buf, score, it->second.first, word); extern unsigned int g_uiSpamBlockScore; extern unsigned int g_uiSpamBlockDuration; if (it->second.first >= g_uiSpamBlockScore) { spam_event_info* info = AllocEventInfo(); strlcpy(info->host, ch->GetDesc()->GetHostName(), sizeof(info->host)); it->second.second = event_create(block_chat_by_ip_event, info, PASSES_PER_SEC(g_uiSpamBlockDuration)); sys_log(0, "SPAM_IP: %s for %u seconds", info->host, g_uiSpamBlockDuration); LogManager::instance().CharLog(ch, 0, "SPAM", word); SendBlockChatInfo(ch, event_time(it->second.second) / passes_per_sec); return true; } } return false; } enum { TEXT_TAG_PLAIN, TEXT_TAG_TAG, // || TEXT_TAG_COLOR, // |cffffffff TEXT_TAG_HYPERLINK_START, // |H TEXT_TAG_HYPERLINK_END, // |h ex) |Hitem:1234:1:1:1|h TEXT_TAG_RESTORE_COLOR, }; int GetTextTag(const char * src, int maxLen, int & tagLen, std::string & extraInfo) { tagLen = 1; if (maxLen < 2 || *src != '|') return TEXT_TAG_PLAIN; const char * cur = ++src; if (*cur == '|') // ||는 |로 표시한다. { tagLen = 2; return TEXT_TAG_TAG; } else if (*cur == 'c') // color |cffffffffblahblah|r { tagLen = 2; return TEXT_TAG_COLOR; } else if (*cur == 'H') // hyperlink |Hitem:10000:0:0:0:0|h[이름]|h { tagLen = 2; return TEXT_TAG_HYPERLINK_START; } else if (*cur == 'h') // end of hyperlink { tagLen = 2; return TEXT_TAG_HYPERLINK_END; } return TEXT_TAG_PLAIN; } void GetTextTagInfo(const char * src, int src_len, int & hyperlinks, bool & colored) { colored = false; hyperlinks = 0; int len; std::string extraInfo; for (int i = 0; i < src_len;) { int tag = GetTextTag(&src[i], src_len - i, len, extraInfo); if (tag == TEXT_TAG_HYPERLINK_START) ++hyperlinks; if (tag == TEXT_TAG_COLOR) colored = true; i += len; } } int ProcessTextTag(LPCHARACTER ch, const char * c_pszText, size_t len) { return 0; //Bvural41 itemsiz yansitma int hyperlinks; bool colored; GetTextTagInfo(c_pszText, len, hyperlinks, colored); if (colored == true && hyperlinks == 0) return 4; if (ch->GetExchange()) { if (hyperlinks == 0) return 0; else return 3; } int nPrismCount = ch->CountSpecifyItem(ITEM_PRISM); if (nPrismCount < hyperlinks) return 1; if (!ch->GetMyShop()) { ch->RemoveSpecifyItem(ITEM_PRISM, hyperlinks); return 0; } else { int sellingNumber = ch->GetMyShop()->GetNumberByVnum(ITEM_PRISM); if(nPrismCount - sellingNumber < hyperlinks) { return 2; } else { ch->RemoveSpecifyItem(ITEM_PRISM, hyperlinks); return 0; } } return 4; } int CInputMain::Whisper(LPCHARACTER ch, const char * data, size_t uiBytes) { const TPacketCGWhisper* pinfo = reinterpret_cast(data); if (uiBytes < pinfo->wSize) return -1; int iExtraLen = pinfo->wSize - sizeof(TPacketCGWhisper); if (iExtraLen < 0) { sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->wSize, uiBytes); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } if (ch->FindAffect(AFFECT_BLOCK_CHAT)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("채팅 금지 상태입니다.")); return (iExtraLen); } #if defined(ENABLE_COMBAT_ZONE) && defined(WJ_COMBAT_ZONE_HIDE_INFO_USER) if (CCombatZoneManager::Instance().IsCombatZoneMap(ch->GetMapIndex()) && (ch->GetGMLevel() < GM_IMPLEMENTOR)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("cz_cannot_use_whisper")); return (iExtraLen); } #endif LPCHARACTER pkChr = CHARACTER_MANAGER::instance().FindPC(pinfo->szNameTo); if (pkChr == ch) return (iExtraLen); LPDESC pkDesc = NULL; BYTE bOpponentEmpire = 0; if (test_server) { if (!pkChr) sys_log(0, "Whisper to %s(%s) from %s", "Null", pinfo->szNameTo, ch->GetName()); else sys_log(0, "Whisper to %s(%s) from %s", pkChr->GetName(), pinfo->szNameTo, ch->GetName()); } if (ch->IsBlockMode(BLOCK_WHISPER)) { if (ch->GetDesc()) { TPacketGCWhisper pack; pack.bHeader = HEADER_GC_WHISPER; pack.bType = WHISPER_TYPE_SENDER_BLOCKED; pack.wSize = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(pack)); } return iExtraLen; } if (!pkChr) { CCI * pkCCI = P2P_MANAGER::instance().Find(pinfo->szNameTo); if (pkCCI) { pkDesc = pkCCI->pkDesc; pkDesc->SetRelay(pinfo->szNameTo); bOpponentEmpire = pkCCI->bEmpire; if (test_server) sys_log(0, "Whisper to %s from %s (Channel %d Mapindex %d)", "Null", ch->GetName(), pkCCI->bChannel, pkCCI->lMapIndex); } } else { pkDesc = pkChr->GetDesc(); bOpponentEmpire = pkChr->GetEmpire(); } if (!pkDesc) { if (ch->GetDesc()) { TPacketGCWhisper pack; pack.bHeader = HEADER_GC_WHISPER; pack.bType = WHISPER_TYPE_NOT_EXIST; pack.wSize = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(TPacketGCWhisper)); sys_log(0, "WHISPER: no player"); } } else { if (ch->IsBlockMode(BLOCK_WHISPER)) { if (ch->GetDesc()) { TPacketGCWhisper pack; pack.bHeader = HEADER_GC_WHISPER; pack.bType = WHISPER_TYPE_SENDER_BLOCKED; pack.wSize = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(pack)); } } else if (pkChr && pkChr->IsBlockMode(BLOCK_WHISPER)) { if (ch->GetDesc()) { TPacketGCWhisper pack; pack.bHeader = HEADER_GC_WHISPER; pack.bType = WHISPER_TYPE_TARGET_BLOCKED; pack.wSize = sizeof(TPacketGCWhisper); strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->Packet(&pack, sizeof(pack)); } } #ifdef ENABLE_MESSENGER_BLOCK else if (pkChr && MessengerManager::instance().CheckMessengerList(ch->GetName(), pkChr->GetName(), SYST_BLOCK)) { if (ch->GetDesc()) { TPacketGCWhisper pack; char msg_2[CHAT_MAX_LEN + 1]; snprintf(msg_2, sizeof(msg_2), LC_TEXT("%s'yi blokladim"), pkChr->GetName()); int len = MIN(CHAT_MAX_LEN, strlen(msg_2) + 1); pack.bHeader = HEADER_GC_WHISPER; pack.wSize = sizeof(TPacketGCWhisper) + len; pack.bType = WHISPER_TYPE_SYSTEM; strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); TEMP_BUFFER buf; buf.write(&pack, sizeof(TPacketGCWhisper)); buf.write(msg_2, len); ch->GetDesc()->Packet(buf.read_peek(), buf.size()); } } #endif else { BYTE bType = WHISPER_TYPE_NORMAL; char buf[CHAT_MAX_LEN + 1]; strlcpy(buf, data + sizeof(TPacketCGWhisper), MIN(iExtraLen + 1, sizeof(buf))); const size_t buflen = strlen(buf); if (true == SpamBlockCheck(ch, buf, buflen)) { if (!pkChr) { CCI * pkCCI = P2P_MANAGER::instance().Find(pinfo->szNameTo); if (pkCCI) { pkDesc->SetRelay(""); } } return iExtraLen; } CBanwordManager::instance().ConvertString(buf, buflen); if (g_bEmpireWhisper) if (!ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) if (!(pkChr && pkChr->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))) if (bOpponentEmpire != ch->GetEmpire() && ch->GetEmpire() && bOpponentEmpire && ch->GetGMLevel() == GM_PLAYER && gm_get_level(pinfo->szNameTo) == GM_PLAYER) { if (!pkChr) { bType = ch->GetEmpire() << 4; } else { ConvertEmpireText(ch->GetEmpire(), buf, buflen, 10 + 2 * pkChr->GetSkillPower(SKILL_LANGUAGE1 + ch->GetEmpire() - 1)/*변환확률*/); } } int processReturn = ProcessTextTag(ch, buf, buflen); if (0!=processReturn) { if (ch->GetDesc()) { TItemTable * pTable = ITEM_MANAGER::instance().GetTable(ITEM_PRISM); if (pTable) { char buf[128]; int len; if (3==processReturn) len = snprintf(buf, sizeof(buf), LC_TEXT("다른 거래중(창고,교환,상점)에는 개인상점을 사용할 수 없습니다."), pTable->szLocaleName); else len = snprintf(buf, sizeof(buf), LC_TEXT("%s이 필요합니다."), pTable->szLocaleName); if (len < 0 || len >= (int) sizeof(buf)) len = sizeof(buf) - 1; ++len; TPacketGCWhisper pack; pack.bHeader = HEADER_GC_WHISPER; pack.bType = WHISPER_TYPE_ERROR; pack.wSize = sizeof(TPacketGCWhisper) + len; strlcpy(pack.szNameFrom, pinfo->szNameTo, sizeof(pack.szNameFrom)); ch->GetDesc()->BufferedPacket(&pack, sizeof(pack)); ch->GetDesc()->Packet(buf, len); sys_log(0, "WHISPER: not enough %s: char: %s", pTable->szLocaleName, ch->GetName()); } } pkDesc->SetRelay(""); return (iExtraLen); } if (ch->IsGM()) bType = (bType & 0xF0) | WHISPER_TYPE_GM; if (buflen > 0) { TPacketGCWhisper pack; pack.bHeader = HEADER_GC_WHISPER; pack.wSize = sizeof(TPacketGCWhisper) + buflen; pack.bType = bType; strlcpy(pack.szNameFrom, ch->GetName(), sizeof(pack.szNameFrom)); #ifdef ENABLE_RENEW_MESSENGER_WHISPER std::auto_ptr pMsg(DBManager::instance().DirectQuery("SELECT status, location, year, month, day FROM player.player WHERE id = '%u'", ch->GetPlayerID())); MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult); pack.job = ch->GetJob(); pack.level = ch->GetLevel(); pack.empire = ch->GetEmpire(); strlcpy(pack.guild, (ch->GetGuild()) ? ch->GetGuild()->GetName() : EMPTY_GUILD, sizeof(pack.guild)); strlcpy(pack.language, LANGUAGE_DEFAULT, sizeof(pack.language)); strlcpy(pack.status, row[0], sizeof(pack.status)); strlcpy(pack.location, row[1], sizeof(pack.location)); strlcpy(pack.year, row[2], sizeof(pack.year)); strlcpy(pack.month, row[3], sizeof(pack.month)); strlcpy(pack.day, row[4], sizeof(pack.day)); #endif TEMP_BUFFER tmpbuf; tmpbuf.write(&pack, sizeof(pack)); tmpbuf.write(buf, buflen); pkDesc->Packet(tmpbuf.read_peek(), tmpbuf.size()); if (LC_IsEurope() != true) { sys_log(0, "WHISPER: %s -> %s : %s", ch->GetName(), pinfo->szNameTo, buf); } } } } if(pkDesc) pkDesc->SetRelay(""); return (iExtraLen); } struct RawPacketToCharacterFunc { const void * m_buf; int m_buf_len; RawPacketToCharacterFunc(const void * buf, int buf_len) : m_buf(buf), m_buf_len(buf_len) { } void operator () (LPCHARACTER c) { if (!c->GetDesc()) return; c->GetDesc()->Packet(m_buf, m_buf_len); } }; struct FEmpireChatPacket { packet_chat& p; const char* orig_msg; int orig_len; char converted_msg[CHAT_MAX_LEN+1]; BYTE bEmpire; int iMapIndex; int namelen; FEmpireChatPacket(packet_chat& p, const char* chat_msg, int len, BYTE bEmpire, int iMapIndex, int iNameLen) : p(p), orig_msg(chat_msg), orig_len(len), bEmpire(bEmpire), iMapIndex(iMapIndex), namelen(iNameLen) { memset( converted_msg, 0, sizeof(converted_msg) ); } void operator () (LPDESC d) { if (!d->GetCharacter()) return; if (d->GetCharacter()->GetMapIndex() != iMapIndex) return; d->BufferedPacket(&p, sizeof(packet_chat)); if (d->GetEmpire() == bEmpire || bEmpire == 0 || d->GetCharacter()->GetGMLevel() > GM_PLAYER || d->GetCharacter()->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) { d->Packet(orig_msg, orig_len); } else { // 사람마다 스킬레벨이 다르니 매번 해야합니다 size_t len = strlcpy(converted_msg, orig_msg, sizeof(converted_msg)); if (len >= sizeof(converted_msg)) len = sizeof(converted_msg) - 1; ConvertEmpireText(bEmpire, converted_msg + namelen, len - namelen, 10 + 2 * d->GetCharacter()->GetSkillPower(SKILL_LANGUAGE1 + bEmpire - 1)); d->Packet(converted_msg, orig_len); } } }; struct FYmirChatPacket { packet_chat& packet; const char* m_szChat; size_t m_lenChat; const char* m_szName; int m_iMapIndex; BYTE m_bEmpire; bool m_ring; char m_orig_msg[CHAT_MAX_LEN+1]; int m_len_orig_msg; char m_conv_msg[CHAT_MAX_LEN+1]; int m_len_conv_msg; FYmirChatPacket(packet_chat& p, const char* chat, size_t len_chat, const char* name, size_t len_name, int iMapIndex, BYTE empire, bool ring) : packet(p), m_szChat(chat), m_lenChat(len_chat), m_szName(name), m_iMapIndex(iMapIndex), m_bEmpire(empire), m_ring(ring) { m_len_orig_msg = snprintf(m_orig_msg, sizeof(m_orig_msg), "%s : %s", m_szName, m_szChat) + 1; // 널 문자 포함 if (m_len_orig_msg < 0 || m_len_orig_msg >= (int) sizeof(m_orig_msg)) m_len_orig_msg = sizeof(m_orig_msg) - 1; m_len_conv_msg = snprintf(m_conv_msg, sizeof(m_conv_msg), "??? : %s", m_szChat) + 1; // 널 문자 미포함 if (m_len_conv_msg < 0 || m_len_conv_msg >= (int) sizeof(m_conv_msg)) m_len_conv_msg = sizeof(m_conv_msg) - 1; ConvertEmpireText(m_bEmpire, m_conv_msg + 6, m_len_conv_msg - 6, 10); // 6은 "??? : "의 길이 } void operator() (LPDESC d) { if (!d->GetCharacter()) return; if (d->GetCharacter()->GetMapIndex() != m_iMapIndex) return; if (m_ring || d->GetEmpire() == m_bEmpire || d->GetCharacter()->GetGMLevel() > GM_PLAYER || d->GetCharacter()->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) { packet.size = m_len_orig_msg + sizeof(TPacketGCChat); d->BufferedPacket(&packet, sizeof(packet_chat)); d->Packet(m_orig_msg, m_len_orig_msg); } else { packet.size = m_len_conv_msg + sizeof(TPacketGCChat); d->BufferedPacket(&packet, sizeof(packet_chat)); d->Packet(m_conv_msg, m_len_conv_msg); } } }; #ifdef ENABLE_NEW_PET_SYSTEM void CInputMain::BraveRequestPetName(LPCHARACTER ch, const char* c_pData) { if (!ch->GetDesc()) { return; } int vid = ch->GetEggVid(); if (vid == 0) { return; } if (quest::CQuestManager::instance().GetEventFlag("pet_kapat") == 1) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("PET_SYSTEM_DISABLED")); return; } TPacketCGRequestPetName* p = (TPacketCGRequestPetName*)c_pData; if (ch->GetGold() < 100000) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[PetSystem] Ai nevoie de 100.000 yang")); return; } if (!check_name(p->petname)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("[Pet-Kulucka] Hatali isim girdiniz")); return; } if (ch->CountSpecifyItem(vid) > 0) { DBManager::instance().SendMoneyLog(MONEY_LOG_QUEST, ch->GetPlayerID(), -100000); ch->PointChange(POINT_GOLD, -100000, true); ch->RemoveSpecifyItem(vid, 1); LPITEM item = ch->AutoGiveItem(vid + 300, 1); if (!item) return; int tmpslot = number(3, 3); int tmpskill[3] = { 0, 0, 0 }; for (int i = 0; i < 3; ++i) { if (i > tmpslot - 1) tmpskill[i] = -1; } int pet_type = number(1, 8); int totaldur = number(1, 14) * 24 * 60 * 60; int tmpdur = time(0) + totaldur; int tmpagedur = time(0) - 86400; DWORD dwArtis1 = 0; DWORD dwArtis2 = 0; DWORD dwArtis3 = 0; if (pet_type == 1) { dwArtis1 = number(1, 2); dwArtis2 = number(1, 2); dwArtis3 = number(1, 2); } else if (pet_type == 2) { dwArtis1 = number(2, 3); dwArtis2 = number(2, 3); dwArtis3 = number(2, 3); } else if (pet_type == 3) { dwArtis1 = number(3, 4); dwArtis2 = number(3, 4); dwArtis3 = number(3, 4); } else if (pet_type == 4) { dwArtis1 = number(4, 5); dwArtis2 = number(4, 5); dwArtis3 = number(4, 5); } else if (pet_type == 5) { dwArtis1 = number(6, 7); dwArtis2 = number(6, 7); dwArtis3 = number(6, 7); } else if (pet_type == 6) { dwArtis1 = number(7, 8); dwArtis2 = number(7, 8); dwArtis3 = number(7, 8); } else if (pet_type == 7) { dwArtis1 = number(8, 9); dwArtis2 = number(8, 9); dwArtis3 = number(8, 9); } else if (pet_type == 8) { dwArtis1 = number(9, 10); dwArtis2 = number(9, 10); dwArtis3 = number(9, 10); } char szQuery1[1024]; 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, %d, %d, %d, %d)", item->GetID(), p->petname, number(1, 30), number(1, 30), number(1, 30), tmpskill[0], 0, tmpskill[1], 0, tmpskill[2], 0, tmpdur, totaldur, tmpagedur, pet_type, dwArtis1, dwArtis2, dwArtis3); std::unique_ptr pmsg2(DBManager::instance().DirectQuery(szQuery1)); } } #endif int CInputMain::Chat(LPCHARACTER ch, const char* data, size_t uiBytes) { const TPacketCGChat* pinfo = reinterpret_cast(data); if (uiBytes < pinfo->size) return -1; const int iExtraLen = pinfo->size - sizeof(TPacketCGChat); if (iExtraLen < 0) { sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->size, uiBytes); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } #ifdef ENABLE_OX_CHAT_BLOCK if (quest::CQuestManager::instance().GetEventFlag("ox_chat_engel") == 1) { if(ch->GetMapIndex() == 113 && (pinfo->type == CHAT_TYPE_TALKING || pinfo->type == CHAT_TYPE_PARTY || pinfo->type == CHAT_TYPE_GUILD || pinfo->type == CHAT_TYPE_SHOUT)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ox_chat_block")); return iExtraLen; } } #endif char buf[CHAT_MAX_LEN - (CHARACTER_NAME_MAX_LEN + 3) + 1]; strlcpy(buf, data + sizeof(TPacketCGChat), MIN(iExtraLen + 1, sizeof(buf))); const size_t buflen = strlen(buf); if (buflen > 1 && *buf == '/') { interpret_command(ch, buf + 1, buflen - 1); return iExtraLen; } #ifdef CHAT_PM #define ENABLE_WAIT_TIME #define WAIT_PM 5 #define WAIT_QUEST "chat.message" std::string findstr(buf); if (findstr.at(0) == '@') { findstr = findstr.substr(1); // or findstr.erase(0,1); int pos = findstr.find(" "); std::string message = findstr.substr(pos + 1), chname = findstr.substr(0,pos); LPCHARACTER stch = CHARACTER_MANAGER::instance().FindPC(chname.c_str()); #ifdef ENABLE_WAIT_TIME if (get_global_time() - ch->GetQuestFlag(WAIT_QUEST) < WAIT_PM) { ch->ChatPacket(CHAT_TYPE_INFO, "Spam checker %d seconds", (WAIT_PM + ch->GetQuestFlag("chat.message")) - get_global_time()); return (iExtraLen); } #endif stch ? stch != ch ? stch->ChatPacket(CHAT_TYPE_WHISPER, "%s sent a message: %s", ch->GetName(), message.c_str()), ch->SetQuestFlag(WAIT_QUEST, get_global_time()) : ch->ChatPacket(CHAT_TYPE_INFO, "target is you") : ch->ChatPacket(CHAT_TYPE_INFO, "%s isn't exist.", chname.c_str()); return (iExtraLen); } #endif if (ch->IncreaseChatCounter() >= 10) { if (ch->GetChatCounter() == 10) { sys_log(0, "CHAT_HACK: %s", ch->GetName()); // ch->GetDesc()->DelayedDisconnect(5); } return iExtraLen; } const CAffect* pAffect = ch->FindAffect(AFFECT_BLOCK_CHAT); if (pAffect != NULL) { SendBlockChatInfo(ch, pAffect->lDuration); return iExtraLen; } if (true == SpamBlockCheck(ch, buf, buflen)) { return iExtraLen; } // @fixme133 begin CBanwordManager::instance().ConvertString(buf, buflen); int processReturn = ProcessTextTag(ch, buf, buflen); if (0 != processReturn) { const TItemTable* pTable = ITEM_MANAGER::instance().GetTable(ITEM_PRISM); if (NULL != pTable) { if (3 == processReturn) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("사용할수 없습니다."), pTable->szLocaleName); else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s이 필요합니다."), pTable->szLocaleName); } return iExtraLen; } // @fixme133 end #if defined(ENABLE_COMBAT_ZONE) && defined(WJ_COMBAT_ZONE_HIDE_INFO_USER) if (CCombatZoneManager::Instance().IsCombatZoneMap(ch->GetMapIndex()) && (ch->GetGMLevel() < GM_IMPLEMENTOR)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("cz_cannot_use_chat")); return iExtraLen; } #endif char chatbuf[CHAT_MAX_LEN + 1]; #ifndef ENABLE_NEW_CHAT_VIEW static const char* colorbuf[] = { "|cFFffa200|H|h[Staff]|h|r", "|cFFff0000|H|h[Shinsoo]|h|r", "|cFFffc700|H|h[Chunjo]|h|r", "|cFF000bff|H|h[Jinno]|h|r" }; int len = snprintf(chatbuf, sizeof(chatbuf), "%s %s : %s", (ch->IsGM() ? colorbuf[0] : colorbuf[MINMAX(0, ch->GetEmpire(), 3)]), ch->GetName(), buf); #else int len = snprintf(chatbuf, sizeof(chatbuf), "%s : %s", ch->GetName(), buf); #endif #ifdef ENABLE_CONQUEROR_LEVEL if (CHAT_TYPE_SHOUT == pinfo->type) { if (ch->GetConquerorLevel() >= 1) { #ifdef ENABLE_NEW_CHAT_VIEW len = snprintf(chatbuf, sizeof(chatbuf), "/empire/%s/%s |H%s%s|h(#)|h |cFF0AC8FF|H|h - Lv %d|h|r : %s", ConvertEmpireIndexToStr(ch->GetEmpire()), ch->GetName(), "whisper:", ch->GetName(), ch->GetConquerorLevel(), buf); #endif } else { #ifdef ENABLE_NEW_CHAT_VIEW len = snprintf(chatbuf, sizeof(chatbuf), "/empire/%s/%s |H%s%s|h(#)|h|r - Lv %d|h|r : %s", ConvertEmpireIndexToStr(ch->GetEmpire()), ch->GetName(), "whisper:", ch->GetName(), ch->GetLevel(), buf); #endif } LogManager::instance().ShoutLog(g_bChannel, ch->GetEmpire(), chatbuf); } #else if (CHAT_TYPE_SHOUT == pinfo->type) { #ifdef ENABLE_NEW_CHAT_VIEW len = snprintf(chatbuf, sizeof(chatbuf), "/empire/%s/%s |H%s%s|h(#)|h|r - Lv %d|h|r : %s", ConvertEmpireIndexToStr(ch->GetEmpire()), ch->GetName(), "whisper:", ch->GetName(), ch->GetLevel(), buf); #endif LogManager::instance().ShoutLog(g_bChannel, ch->GetEmpire(), chatbuf); } #endif if (len < 0 || len >= (int) sizeof(chatbuf)) len = sizeof(chatbuf) - 1; if (pinfo->type == CHAT_TYPE_SHOUT) { const int SHOUT_LIMIT_LEVEL = 15; if (ch->GetLevel() < SHOUT_LIMIT_LEVEL) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("BAGIRMA_LEVELI"), SHOUT_LIMIT_LEVEL); return (iExtraLen); } if (thecore_heart->pulse - (int)ch->GetLastShoutPulse() < passes_per_sec * 15) return (iExtraLen); ch->SetLastShoutPulse(thecore_heart->pulse); TPacketGGShout p; p.bHeader = HEADER_GG_SHOUT; p.bEmpire = ch->GetEmpire(); strlcpy(p.szText, chatbuf, sizeof(p.szText)); P2P_MANAGER::instance().Send(&p, sizeof(TPacketGGShout)); SendShout(chatbuf, ch->GetEmpire()); return (iExtraLen); } TPacketGCChat pack_chat; pack_chat.header = HEADER_GC_CHAT; pack_chat.size = sizeof(TPacketGCChat) + len; pack_chat.type = pinfo->type; pack_chat.id = ch->GetVID(); switch (pinfo->type) { case CHAT_TYPE_TALKING: { const DESC_MANAGER::DESC_SET& c_ref_set = DESC_MANAGER::instance().GetClientSet(); if (false) { std::for_each(c_ref_set.begin(), c_ref_set.end(), FYmirChatPacket(pack_chat, buf, strlen(buf), ch->GetName(), strlen(ch->GetName()), ch->GetMapIndex(), ch->GetEmpire(), ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE))); } else { std::for_each(c_ref_set.begin(), c_ref_set.end(), FEmpireChatPacket(pack_chat, chatbuf, len, (ch->GetGMLevel() > GM_PLAYER || ch->IsEquipUniqueGroup(UNIQUE_GROUP_RING_OF_LANGUAGE)) ? 0 : ch->GetEmpire(), ch->GetMapIndex(), strlen(ch->GetName()))); } } break; case CHAT_TYPE_PARTY: { if (!ch->GetParty()) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("파티 중이 아닙니다.")); else { TEMP_BUFFER tbuf; tbuf.write(&pack_chat, sizeof(pack_chat)); tbuf.write(chatbuf, len); RawPacketToCharacterFunc f(tbuf.read_peek(), tbuf.size()); ch->GetParty()->ForEachOnlineMember(f); } } break; case CHAT_TYPE_GUILD: { if (!ch->GetGuild()) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("길드에 가입하지 않았습니다.")); else { ch->GetGuild()->Chat(chatbuf); } } break; default: sys_err("Unknown chat type %d", pinfo->type); break; } return (iExtraLen); } void CInputMain::ItemUse(LPCHARACTER ch, const char * data) { ch->UseItem(((struct command_item_use *) data)->Cell); } void CInputMain::ItemToItem(LPCHARACTER ch, const char * pcData) { TPacketCGItemUseToItem * p = (TPacketCGItemUseToItem *) pcData; if (ch) ch->UseItem(p->Cell, p->TargetCell); } void CInputMain::ItemDrop(LPCHARACTER ch, const char * data) { struct command_item_drop * pinfo = (struct command_item_drop *) data; if (!ch) return; if (pinfo->gold > 0) ch->DropGold(pinfo->gold); #ifdef ENABLE_CHEQUE_SYSTEM else if (pinfo->cheque > 0) ch->DropCheque(pinfo->cheque); #endif else ch->DropItem(pinfo->Cell); } void CInputMain::ItemDrop2(LPCHARACTER ch, const char * data) { //MONARCH_LIMIT //if (ch->IsMonarch()) // return; //END_MONARCH_LIMIT TPacketCGItemDrop2 * pinfo = (TPacketCGItemDrop2 *) data; // 엘크가 0보다 크면 엘크를 버리는 것 이다. if (!ch) return; if (pinfo->gold > 0) ch->DropGold(pinfo->gold); #ifdef ENABLE_CHEQUE_SYSTEM else if (pinfo->cheque > 0) ch->DropCheque(pinfo->cheque); #endif else ch->DropItem(pinfo->Cell, pinfo->count); } #ifdef ENABLE_DELETE_ITEMS_SYSTEM void CInputMain::ItemDestroy(LPCHARACTER ch, const char * data) { struct command_item_destroy * pinfo = (struct command_item_destroy *) data; if (ch) ch->DestroyItem(pinfo->Cell); } #endif void CInputMain::ItemSell(LPCHARACTER ch, const char * data) { struct command_item_sell * pinfo = (struct command_item_sell *) data; if (ch) ch->SellItem(pinfo->Cell); } #ifdef ENABLE_EXTEND_INVEN_SYSTEM void CInputMain::ExInventory(CHARACTER * ch, const char * data) { struct command_extend_inventory * pinfo = (struct command_extend_inventory *) data; if (!ch->CanHandleItem()) return; switch (pinfo->sub_header) { case 0: // upgrade Extend Inventory { sys_log(0, "CInputMain()::ExInventory() ==> UpgradeExInventory"); ch->UpgradeExInventory(ch); } break; case 1: // Button Click Extend Inventory { sys_log(0, "CInputMain()::ExInventory() ==> ButtonClick"); ch->ExtendInventoryItemUse(ch); } break; } } #endif #ifdef ENABLE_PRIVATE_SHOP_SEARCH_SYSTEM void CInputMain::ShopSearch(LPCHARACTER ch, const char* data, bool bName) { TPacketCGShopSearch* pinfo = (TPacketCGShopSearch*)data; if (!ch) return; if (!data) return; if (ch->IsOpenSafebox() || ch->GetShop() || ch->IsCubeOpen() || ch->IsDead() || ch->GetExchange() || ch->GetMyShop() #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM || ch->GetOfflineShop() #endif ) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("CANT_DO_THIS_BECAUSE_OTHER_WINDOW_OPEN")); return; } #ifdef ENABLE_PRIVATE_SHOP_SEARCH_NEED_ITEM if (!ch->FindSpecifyItem(60004) && !ch->FindSpecifyItem(60005)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("PRIVATE_SHOP_SEARCH_NEED_ITEM")); return; } #endif int32_t Race = pinfo->Race; int32_t Cat = pinfo->ItemCat; int32_t SubCat = pinfo->SubCat; int32_t MinLevel = pinfo->MinLevel; int32_t MaxLevel = pinfo->MaxLevel; int32_t MinRefine = pinfo->MinRefine; int32_t MaxRefine = pinfo->MaxRefine; uint64_t MinGold = pinfo->MinGold; uint64_t MaxGold = pinfo->MaxGold; #ifdef ENABLE_CHEQUE_SYSTEM uint64_t MinCheque = pinfo->MinCheque; uint64_t MaxCheque = pinfo->MaxCheque; #endif std::string itemName = ""; //Checks if (Race < JOB_WARRIOR || Race > #ifdef ENABLE_WOLFMAN_CHARACTER JOB_WOLFMAN #else JOB_SHAMAN #endif ) return; if (Cat < ITEM_NONE || Cat > ITEM_PASSIVE) // @ enum EItemTypes common/item_length.h return; if (SubCat < USE_POTION || SubCat > USE_COSTUME_TRANSFORM) return; if (MinLevel < 0 || MinLevel > PLAYER_MAX_LEVEL_CONST) return; if (MaxLevel < 0 || MaxLevel > PLAYER_MAX_LEVEL_CONST) return; if (MinRefine < 0 || MinRefine > 15) return; if (MaxRefine < 0 || MaxRefine > 15) return; if (MinGold < 0 || MinGold > GOLD_MAX) return; if (MaxGold < 0 || MaxGold > GOLD_MAX) return; #ifdef ENABLE_CHEQUE_SYSTEM if (MinCheque < 0 || MinCheque > CHEQUE_MAX) return; if (MaxCheque < 0 || MaxCheque > CHEQUE_MAX) return; #endif if (MinLevel > MaxLevel) return; if (MinRefine > MaxRefine) return; if (MinGold > MaxGold) return; #ifdef ENABLE_CHEQUE_SYSTEM if (MinCheque > MaxCheque) return; #endif if (bName) { itemName = pinfo->ItemName; std::replace(itemName.begin(), itemName.end(), '_', ' '); } quest::PC* pPC = quest::CQuestManager::instance().GetPC(ch->GetPlayerID()); if (!pPC) return; DWORD dwShopSearchSecCycle = 2; // 1 sec DWORD dwNowSec = get_global_time(); DWORD dwLastShopSearchAttrSec = pPC->GetFlag("ShopSearch.LastShopSearchSecAttr"); if (dwLastShopSearchAttrSec + dwShopSearchSecCycle > dwNowSec) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("PRIVATE_SHOP_SEARCH_NEED_WAIT_%d_LEFT_(%d)"), dwShopSearchSecCycle, dwShopSearchSecCycle - (dwNowSec - dwLastShopSearchAttrSec)); return; } pPC->SetFlag("ShopSearch.LastShopSearchSecAttr", dwNowSec); std::vector sendItems; std::vector shop_items; std::vector::iterator item; char szQuery[1024]; if (bName) { sprintf(szQuery, "select of.*,(case when of.vnum in(50300,70037) then (select concat(convert(sp.szName using latin5),' ',convert(ip.locale_name using latin5)) from skill_proto sp where sp.dwVnum = of.socket0) else convert(ip.locale_name using latin5) end) as item_name from offline_shop_item of inner join item_proto ip on ip.vnum = of.vnum where (case when of.vnum in(50300,70037) then (select concat(convert(sp.szName using latin5),' ',convert(ip.locale_name using latin5)) from skill_proto sp where sp.dwVnum = of.socket0) else convert(ip.locale_name using latin5) end) like CONCAT('%%%%', '%s', '%%%%') limit 100", itemName.c_str()); } else { sprintf(szQuery, "select of.*,(case when of.vnum in(50300,70037) then (select concat(convert(sp.szName using latin5),' ',convert(ip.locale_name using latin5)) from skill_proto sp where sp.dwVnum = of.socket0) else convert(ip.locale_name using latin5) end) as item_name from offline_shop_item of inner join item_proto ip on ip.vnum = of.vnum limit 100"); } SQLMsg* pSearchQuery(DBManager::instance().DirectQuery(szQuery)); if (pSearchQuery->uiSQLErrno != 0) { sys_err("Item Search Query Failed, Error code: %ld", pSearchQuery->uiSQLErrno); return; } if (!pSearchQuery->Get()->uiNumRows) return; int i = 0; while (MYSQL_ROW row = mysql_fetch_row(pSearchQuery->Get()->pSQLResult)) { shop_items.resize(i + 1); const TItemTable* item_table; DWORD vnum = 0; str_to_number(vnum, row[4]); item_table = ITEM_MANAGER::instance().GetTable(vnum); if (!item_table) { sys_err("OfflineShop: no item table by item vnum #%d", vnum); continue; } COfflineShop::OFFLINE_SHOP_ITEM& item = shop_items[i]; str_to_number(item.id, row[0]); // 0 str_to_number(item.owner_id, row[1]); // 1 str_to_number(item.pos, row[2]); // 2 str_to_number(item.count, row[3]); // 3 str_to_number(item.vnum, row[4]); // 4 str_to_number(item.alSockets[0], row[5]); // 5 str_to_number(item.alSockets[1], row[6]); // 6 str_to_number(item.alSockets[2], row[7]); // 7 str_to_number(item.alSockets[3], row[8]); // 8 str_to_number(item.alSockets[4], row[9]); // 9 str_to_number(item.alSockets[5], row[10]); // 10 str_to_number(item.aAttr[0].bType, row[11]); // 11 ~ 8 str_to_number(item.aAttr[0].sValue, row[12]); // 12 ~ 9 str_to_number(item.aAttr[1].bType, row[13]); // 13 ~ 10 str_to_number(item.aAttr[1].sValue, row[14]); // 14 ~ 11 str_to_number(item.aAttr[2].bType, row[15]); // 15 ~ 12 str_to_number(item.aAttr[2].sValue, row[16]); // 16 ~ 13 str_to_number(item.aAttr[3].bType, row[17]); // 17 ~ 14 str_to_number(item.aAttr[3].sValue, row[18]); // 18 ~ 15 str_to_number(item.aAttr[4].bType, row[19]); // 19 ~ 16 str_to_number(item.aAttr[4].sValue, row[20]); // 20 ~ 17 str_to_number(item.aAttr[5].bType, row[21]); // 21 ~ 18 str_to_number(item.aAttr[5].sValue, row[22]); // 22 ~ 19 str_to_number(item.aAttr[6].bType, row[23]); // 23 ~ 20 str_to_number(item.aAttr[6].sValue, row[24]); // 24 ~ 21 str_to_number(item.aAttr[7].bType, row[25]); // 25 ~ 22 str_to_number(item.aAttr[7].sValue, row[26]); // 26 ~ 23 str_to_number(item.aAttr[8].bType, row[27]); // 27 ~ 24 str_to_number(item.aAttr[8].sValue, row[28]); // 28 ~ 25 str_to_number(item.aAttr[9].bType, row[29]); // 29 ~ 26 str_to_number(item.aAttr[9].sValue, row[30]); // 30 ~ 27 str_to_number(item.aAttr[10].bType, row[31]); // 31 ~ 28 str_to_number(item.aAttr[10].sValue, row[32]); // 32 ~ 29 str_to_number(item.aAttr[11].bType, row[33]); // 33 ~ 30 str_to_number(item.aAttr[11].sValue, row[34]); // 34 ~ 31 str_to_number(item.aAttr[12].bType, row[35]); // 35 ~ 32 str_to_number(item.aAttr[12].sValue, row[36]); // 36 ~ 33 str_to_number(item.aAttr[13].bType, row[37]); // 37 ~ 34 str_to_number(item.aAttr[13].sValue, row[38]); // 38 ~ 35 str_to_number(item.aAttr[14].bType, row[39]); // 39 ~ 36 str_to_number(item.aAttr[14].sValue, row[40]); // 40 ~ 37 str_to_number(item.price, row[41]); // 41 ~ 38 #ifdef ENABLE_CHEQUE_SYSTEM str_to_number(item.price_cheque, row[42]); // 42 ~ 39 #endif str_to_number(item.status, row[43]); // 43 ~ 40 strlcpy(item.szBuyerName, row[44], sizeof(item.szBuyerName)); // 44 ~ 41 #ifdef ENABLE_CHANGELOOK_SYSTEM str_to_number(item.transmutation, row[45]); // 45 ~ 42 #endif #ifdef ENABLE_EVOLUTION_SYSTEM str_to_number(item.evolution, row[46]); // 46 ~ 43 #endif strlcpy(item.szName, row[47], sizeof(item.szName)); // 47 ~ 44 str_to_number(item.refine_level, row[48]); // 48 ~ 45 i++; } for (item = shop_items.begin(); item != shop_items.end(); ++item) { bool bLimit = false; if (item->status != 0 || item->vnum == 0) continue; TItemTable* itemTable = ITEM_MANAGER::instance().GetTable(item->vnum); if (!itemTable) continue; if (!bName) { if (itemTable->bType == Cat && (itemTable->bSubType == SubCat || itemTable->bSubType == 99)) { if (itemTable->bType == ITEM_WEAPON || itemTable->bType == ITEM_ARMOR) { if (!(item->refine_level >= MinRefine && item->refine_level <= MaxRefine)) continue; } } else { continue; } } for (int i = 0; i < ITEM_LIMIT_MAX_NUM; ++i) { long lLimit = itemTable->aLimits[i].lValue; switch (itemTable->aLimits[i].bType) { case LIMIT_LEVEL: if (!(lLimit >= MinLevel && lLimit <= MaxLevel)) bLimit = true; break; case LIMIT_REAL_TIME: if (lLimit == 0) bLimit = true; break; } } if (bLimit) continue; if (!(item->price >= MinGold && item->price <= MaxGold)) continue; #ifdef ENABLE_CHEQUE_SYSTEM if (!(item->price_cheque >= MinCheque && item->price_cheque <= MaxCheque)) continue; #endif bool skillBook = false; DWORD bkType = 0; if ((itemTable->bType == ITEM_SKILLBOOK) || (itemTable->bType == ITEM_SKILLFORGET)) { CSkillProto* pkSk = CSkillManager::instance().Get(item->alSockets[0]); bkType = pkSk->dwType; skillBook = false; } bool cont = false; if (skillBook) { switch (Race) { case JOB_WARRIOR: if (bkType != JOB_WARRIOR + 1) { cont = true; } break; case JOB_ASSASSIN: if (bkType != JOB_ASSASSIN + 1) { cont = true; } break; case JOB_SURA: if (bkType != JOB_SURA + 1) { cont = true; } break; case JOB_SHAMAN: if (bkType != JOB_SHAMAN + 1) { cont = true; } break; #ifdef ENABLE_WOLFMAN_CHARACTER case JOB_WOLFMAN: if (bkType != JOB_WOLFMAN + 1) { cont = true; } break; #endif } } // else // { // switch (Race) // { // case JOB_WARRIOR: // if (IS_SET(itemTable->dwAntiFlags, ITEM_ANTIFLAG_WARRIOR)) // cont = true; // break; // case JOB_ASSASSIN: // if (IS_SET(itemTable->dwAntiFlags, ITEM_ANTIFLAG_ASSASSIN)) // cont = true; // break; // case JOB_SURA: // if (IS_SET(itemTable->dwAntiFlags, ITEM_ANTIFLAG_SURA)) // cont = true; // break; // case JOB_SHAMAN: // if (IS_SET(itemTable->dwAntiFlags, ITEM_ANTIFLAG_SHAMAN)) // cont = true; // break; // #ifdef ENABLE_WOLFMAN_CHARACTER // case JOB_WOLFMAN: // if (IS_SET(itemTable->dwAntiFlags, ITEM_ANTIFLAG_WOLFMAN)) // cont = true; // break; // #endif // } // } // if (cont) // continue; sendItems.push_back(*item); } std::stable_sort(sendItems.begin(), sendItems.end(), CompareItemVnumAcPriceAC); for (item = sendItems.begin(); item != sendItems.end(); ++item) { if (item->status != 0 || item->vnum == 0) continue; TItemTable* itemTable = ITEM_MANAGER::instance().GetTable(item->vnum); LPCHARACTER offlineShopNpc = CHARACTER_MANAGER::instance().Find(COfflineShopManager::instance().FindMyOfflineShop(item->owner_id)); if (!offlineShopNpc || !pPC) return; if (itemTable) { LPDESC d = ch->GetDesc(); if (!d) return; TPacketGCShopSearchItemSet pack; pack.header = HEADER_GC_SHOPSEARCH_SET; pack.count = static_cast(item->count); pack.vnum = item->vnum; pack.flags = itemTable->dwFlags; pack.anti_flags = itemTable->dwAntiFlags; pack.price = item->price; #ifdef ENABLE_CHEQUE_SYSTEM pack.price_cheque = item->price_cheque; #endif pack.vid = offlineShopNpc->GetVID(); #ifdef ENABLE_CHANGELOOK_SYSTEM pack.transmutation = item->transmutation; #endif #ifdef ENABLE_EVOLUTION_SYSTEM strlcpy(pack.itemName, item->szName, sizeof(pack.itemName)); pack.evolution = item->evolution; #endif pack.Cell = item->pos; thecore_memcpy(pack.alSockets, item->alSockets, sizeof(pack.alSockets)); thecore_memcpy(pack.aAttr, item->aAttr, sizeof(pack.aAttr)); d->LargePacket(&pack, sizeof(TPacketGCShopSearchItemSet)); } } } void CInputMain::ShopSearchBuy(LPCHARACTER ch, const char* data) { TPacketCGShopSearchBuy* pinfo = (TPacketCGShopSearchBuy*)data; int32_t shopVid = pinfo->shopVid; int32_t shopItemPos = pinfo->shopItemPos; if (!ch) return; if (0 == quest::CQuestManager::instance().GetEventFlag("enable_shop_search")) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("PRIVATE_SHOP_SEARCH_SYSTEM_DISABLED")); return; } #ifdef ENABLE_PRIVATE_SHOP_SEARCH_NEED_ITEM if (!ch->FindSpecifyItem(60005)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("PRIVATE_SHOP_SEARCH_NEED_ITEM")); return; } #endif LPCHARACTER pkChrShop = CHARACTER_MANAGER::instance().Find(shopVid); if (!pkChrShop) return; LPOFFLINESHOP pkShop = pkChrShop->GetOfflineShop(); if (!pkShop) return; // if (DISTANCE_APPROX(ch->GetX() - pkChrShop->GetX(), ch->GetY() - pkChrShop->GetY()) > VIEW_RANGE) // { // ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상점과의 거리가 너무 멀어 물건을 살 수 없습니다.")); // return; // } // if (ch->GetMapIndex() != pkChrShop->GetMapIndex()) // { // ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("YOU_CANNOT_BUY_THIS_BECAUSE_NOT_IN_SAME_MAP")); // return; // } ch->SetOfflineShopOwner(pkChrShop); pkShop->SetGuestMap(ch); int32_t returnHeader = pkShop->Buy(ch, shopItemPos); if (SHOP_SUBHEADER_GC_OK == returnHeader) { ch->ChatPacket(CHAT_TYPE_COMMAND, "ShopSearchBuy"); ch->SetOfflineShop(NULL); ch->SetOfflineShopOwner(NULL); pkShop->RemoveGuestMap(ch); } else { ch->ChatPacket(CHAT_TYPE_COMMAND, "ShopSearchError %d", returnHeader); ch->SetOfflineShop(NULL); ch->SetOfflineShopOwner(NULL); pkShop->RemoveGuestMap(ch); } } #endif void CInputMain::ItemMove(LPCHARACTER ch, const char * data) { struct command_item_move * pinfo = (struct command_item_move *) data; if (ch) ch->MoveItem(pinfo->Cell, pinfo->CellTo, pinfo->count); } void CInputMain::ItemPickup(LPCHARACTER ch, const char * data) { struct command_item_pickup * pinfo = (struct command_item_pickup*) data; if (ch) ch->PickupItem(pinfo->vid); } void CInputMain::QuickslotAdd(LPCHARACTER ch, const char* data) { struct command_quickslot_add* pinfo = (struct command_quickslot_add*) data; if (pinfo->slot.type == QUICKSLOT_TYPE_ITEM)// @fixme182 { LPITEM item = NULL; TItemPos srcCell(INVENTORY, pinfo->slot.pos); if (!(item = ch->GetItem(srcCell))) return; if (item->GetType() != ITEM_USE && item->GetType() != ITEM_QUEST) return; } ch->SetQuickslot(pinfo->pos, pinfo->slot); } void CInputMain::QuickslotDelete(LPCHARACTER ch, const char * data) { struct command_quickslot_del * pinfo = (struct command_quickslot_del *) data; ch->DelQuickslot(pinfo->pos); } void CInputMain::QuickslotSwap(LPCHARACTER ch, const char * data) { struct command_quickslot_swap * pinfo = (struct command_quickslot_swap *) data; ch->SwapQuickslot(pinfo->pos, pinfo->change_pos); } int CInputMain::Messenger(LPCHARACTER ch, const char* c_pData, size_t uiBytes) { TPacketCGMessenger* p = (TPacketCGMessenger*) c_pData; if (uiBytes < sizeof(TPacketCGMessenger)) return -1; c_pData += sizeof(TPacketCGMessenger); uiBytes -= sizeof(TPacketCGMessenger); switch (p->subheader) { #ifdef ENABLE_MESSENGER_BLOCK case MESSENGER_SUBHEADER_CG_ADD_BLOCK_BY_VID: { if (uiBytes < sizeof(TPacketCGMessengerAddBlockByVID)) return -1; TPacketCGMessengerAddBlockByVID * p2 = (TPacketCGMessengerAddBlockByVID *) c_pData; LPCHARACTER ch_companion = CHARACTER_MANAGER::instance().Find(p2->vid); if (!ch_companion) return sizeof(TPacketCGMessengerAddBlockByVID); if (ch->IsObserverMode()) return sizeof(TPacketCGMessengerAddBlockByVID); LPDESC d = ch_companion->GetDesc(); if (!d) return sizeof(TPacketCGMessengerAddByVID); if (ch_companion->GetGuild() == ch->GetGuild() && ch->GetGuild() != NULL && ch_companion->GetGuild() != NULL) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("lonca olmaz")); return sizeof(TPacketCGMessengerAddBlockByVID); } if (MessengerManager::instance().CheckMessengerList(ch->GetName(), ch_companion->GetName(), SYST_FRIEND)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("arkadas ekleyemezsin.")); return sizeof(TPacketCGMessengerAddBlockByVID); } if (MessengerManager::instance().CheckMessengerList(ch->GetName(), ch_companion->GetName(), SYST_BLOCK)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("zaten bloklu")); return sizeof(TPacketCGMessengerAddBlockByVID); } if (ch->GetGMLevel() == GM_PLAYER && ch_companion->GetGMLevel() != GM_PLAYER) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("gm'ye bu yanlis yapilmaz.")); return sizeof(TPacketCGMessengerAddByVID); } if (ch->GetDesc() == d) // 자신은 추가할 수 없다. return sizeof(TPacketCGMessengerAddBlockByVID); MessengerManager::instance().AddToBlockList(ch->GetName(), ch_companion->GetName()); } return sizeof(TPacketCGMessengerAddBlockByVID); case MESSENGER_SUBHEADER_CG_ADD_BLOCK_BY_NAME: { if (uiBytes < CHARACTER_NAME_MAX_LEN) return -1; char name[CHARACTER_NAME_MAX_LEN + 1]; strlcpy(name, c_pData, sizeof(name)); if (gm_get_level(name) != GM_PLAYER) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("gm'ye bu yanlis yapilmaz.")); return CHARACTER_NAME_MAX_LEN; } LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(name); if (!tch) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s yok ki."), name); else { if (tch == ch) // 자신은 추가할 수 없다. return CHARACTER_NAME_MAX_LEN; if (tch->GetGuild() == ch->GetGuild() && ch->GetGuild() != NULL && tch->GetGuild() != NULL) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("lonca olmaz")); return CHARACTER_NAME_MAX_LEN; } if (MessengerManager::instance().CheckMessengerList(ch->GetName(), tch->GetName(), SYST_FRIEND)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("arkadas ekleyemezsin.")); return CHARACTER_NAME_MAX_LEN; } MessengerManager::instance().AddToBlockList(ch->GetName(), tch->GetName()); } } return CHARACTER_NAME_MAX_LEN; case MESSENGER_SUBHEADER_CG_REMOVE_BLOCK: { if (uiBytes < CHARACTER_NAME_MAX_LEN) return -1; char char_name[CHARACTER_NAME_MAX_LEN + 1]; strlcpy(char_name, c_pData, sizeof(char_name)); if (!MessengerManager::instance().CheckMessengerList(ch->GetName(), char_name, SYST_BLOCK)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("bloklu degil")); return CHARACTER_NAME_MAX_LEN; } MessengerManager::instance().RemoveFromBlockList(ch->GetName(), char_name); } return CHARACTER_NAME_MAX_LEN; #endif case MESSENGER_SUBHEADER_CG_ADD_BY_VID: { if (uiBytes < sizeof(TPacketCGMessengerAddByVID)) return -1; TPacketCGMessengerAddByVID * p2 = (TPacketCGMessengerAddByVID *) c_pData; LPCHARACTER ch_companion = CHARACTER_MANAGER::instance().Find(p2->vid); if (!ch_companion) return sizeof(TPacketCGMessengerAddByVID); if (ch->IsObserverMode()) return sizeof(TPacketCGMessengerAddByVID); if (ch_companion->IsBlockMode(BLOCK_MESSENGER_INVITE)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 메신져 추가 거부 상태입니다.")); return sizeof(TPacketCGMessengerAddByVID); } LPDESC d = ch_companion->GetDesc(); if (!d) return sizeof(TPacketCGMessengerAddByVID); if (ch->GetGMLevel() == GM_PLAYER && ch_companion->GetGMLevel() != GM_PLAYER) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<메신져> 운영자는 메신져에 추가할 수 없습니다.")); return sizeof(TPacketCGMessengerAddByVID); } if (ch->GetDesc() == d) // 자신은 추가할 수 없다. return sizeof(TPacketCGMessengerAddByVID); if (MessengerManager::instance().CheckMessengerList(ch->GetName(), ch_companion->GetName(), SYST_FRIEND)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("zaten arkadas.")); return sizeof(TPacketCGMessengerAddByVID); } if (MessengerManager::instance().CheckMessengerList(ch->GetName(), ch_companion->GetName(), SYST_BLOCK)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("blok ekleyemezsin")); return sizeof(TPacketCGMessengerAddByVID); } MessengerManager::instance().RequestToAdd(ch, ch_companion); } return sizeof(TPacketCGMessengerAddByVID); case MESSENGER_SUBHEADER_CG_ADD_BY_NAME: { if (uiBytes < CHARACTER_NAME_MAX_LEN) return -1; char name[CHARACTER_NAME_MAX_LEN + 1]; strlcpy(name, c_pData, sizeof(name)); if (ch->GetGMLevel() == GM_PLAYER && gm_get_level(name) != GM_PLAYER) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<메신져> 운영자는 메신져에 추가할 수 없습니다.")); return CHARACTER_NAME_MAX_LEN; } LPCHARACTER tch = CHARACTER_MANAGER::instance().FindPC(name); if (!tch) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s 님은 접속되 있지 않습니다."), name); else { if (tch == ch) // 자신은 추가할 수 없다. return CHARACTER_NAME_MAX_LEN; if (tch->IsBlockMode(BLOCK_MESSENGER_INVITE) == true) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방이 메신져 추가 거부 상태입니다.")); } else { if (MessengerManager::instance().CheckMessengerList(ch->GetName(), tch->GetName(), SYST_FRIEND)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("zaten arkadas.")); return CHARACTER_NAME_MAX_LEN; } if (MessengerManager::instance().CheckMessengerList(ch->GetName(), tch->GetName(), SYST_BLOCK)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("blok ekleyemezsin")); return CHARACTER_NAME_MAX_LEN; } // 메신저가 캐릭터단위가 되면서 변경 MessengerManager::instance().RequestToAdd(ch, tch); } } } return CHARACTER_NAME_MAX_LEN; case MESSENGER_SUBHEADER_CG_REMOVE: { if (uiBytes < CHARACTER_NAME_MAX_LEN) return -1; char char_name[CHARACTER_NAME_MAX_LEN + 1]; strlcpy(char_name, c_pData, sizeof(char_name)); if (!MessengerManager::instance().CheckMessengerList(ch->GetName(), char_name, SYST_FRIEND)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("arkadas degil")); return CHARACTER_NAME_MAX_LEN; } MessengerManager::instance().RemoveFromList(ch->GetName(), char_name); MessengerManager::instance().RemoveFromList(char_name, ch->GetName());// @fixme183 } return CHARACTER_NAME_MAX_LEN; default: sys_err("CInputMain::Messenger : Unknown subheader %d : %s", p->subheader, ch->GetName()); break; } return 0; } #ifdef ENABLE_SOUL_ROULETTE_SYSTEM void CInputMain::SoulRoulette(LPCHARACTER ch, const char* data) { if (!ch) return; const TPacketCGSoulRoulette* pinfo = reinterpret_cast(data); enum { CLOSE, TURN, GIVE }; switch (pinfo->option) { case CLOSE: if (ch->GetSoulRoulette()) { if (ch->GetSoulRoulette()->GetGiftVnum()) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Please wait, is active now.")); else { ch->GetSoulRoulette()->SendPacket(CSoulRoulette::Packet::CLOSE); ch->SetSoulRoulette(NULL); } } break; case TURN: if (ch->GetSoulRoulette()) ch->GetSoulRoulette()->TurnWheel(); break; case GIVE: if (ch->GetSoulRoulette()) ch->GetSoulRoulette()->GiveGift(); break; default: sys_err("CInputMain::SoulRoulette : Unknown option %d : %s", pinfo->option, ch->GetName()); break; } } #endif #ifdef ENABLE_BATTLE_PASS int CInputMain::BattlePass(LPCHARACTER ch, const char* data, size_t uiBytes) { TPacketCGBattlePassAction * p = (TPacketCGBattlePassAction *) data; if (uiBytes < sizeof(TPacketCGBattlePassAction)) return -1; const char * c_pData = data + sizeof(TPacketCGBattlePassAction); uiBytes -= sizeof(TPacketCGBattlePassAction); switch(p->bAction) { case 1: CBattlePass::instance().BattlePassRequestOpen(ch); break; case 2: CBattlePass::instance().BattlePassRequestReward(ch); break; case 3: { DWORD dwPlayerId = ch->GetPlayerID(); BYTE bIsGlobal = 0; db_clientdesc->DBPacketHeader(HEADER_GD_BATTLE_PASS_RANKING, ch->GetDesc()->GetHandle(), sizeof(DWORD) + sizeof(BYTE)); db_clientdesc->Packet(&dwPlayerId, sizeof(DWORD)); db_clientdesc->Packet(&bIsGlobal, sizeof(BYTE)); } break; default: break; } return 0; } #endif int CInputMain::Shop(LPCHARACTER ch, const char * data, size_t uiBytes) { TPacketCGShop * p = (TPacketCGShop *) data; if (uiBytes < sizeof(TPacketCGShop)) return -1; if (test_server) sys_log(0, "CInputMain::Shop() ==> SubHeader %d", p->subheader); const char * c_pData = data + sizeof(TPacketCGShop); uiBytes -= sizeof(TPacketCGShop); switch (p->subheader) { case SHOP_SUBHEADER_CG_END: sys_log(1, "INPUT: %s SHOP: END", ch->GetName()); CShopManager::instance().StopShopping(ch); return 0; case SHOP_SUBHEADER_CG_BUY: { if (uiBytes < sizeof(BYTE) + sizeof(BYTE)) return -1; BYTE bPos = *(c_pData + 1); sys_log(1, "INPUT: %s SHOP: BUY %d", ch->GetName(), bPos); CShopManager::instance().Buy(ch, bPos); return (sizeof(BYTE) + sizeof(BYTE)); } case SHOP_SUBHEADER_CG_SELL: { if (uiBytes < sizeof(BYTE)) return -1; BYTE pos = *c_pData; sys_log(0, "INPUT: %s SHOP: SELL", ch->GetName()); CShopManager::instance().Sell(ch, pos); return sizeof(BYTE); } case SHOP_SUBHEADER_CG_SELL2: { #ifdef __EXTENDED_ITEM_COUNT__ if (uiBytes < sizeof(BYTE) + sizeof(short)) return -1; BYTE pos = *(c_pData++); short count = *(c_pData); sys_log(0, "INPUT: %s SHOP: SELL2", ch->GetName()); CShopManager::instance().Sell(ch, pos, count); return sizeof(BYTE) + sizeof(short); #else if (uiBytes < sizeof(BYTE) + sizeof(BYTE)) return -1; BYTE pos = *(c_pData++); BYTE count = *(c_pData); sys_log(0, "INPUT: %s SHOP: SELL2", ch->GetName()); CShopManager::instance().Sell(ch, pos, count); return sizeof(BYTE) + sizeof(BYTE); #endif } default: sys_err("CInputMain::Shop : Unknown subheader %d : %s", p->subheader, ch->GetName()); break; } return 0; } #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM int CInputMain::OfflineShop(LPCHARACTER ch, const char* data, size_t uiBytes) { TPacketCGOfflineShop* p = (TPacketCGOfflineShop*)data; if (uiBytes < sizeof(TPacketCGOfflineShop)) return -1; if (test_server) sys_log(0, "CInputMain::OfflineShop ==> SubHeader %d", p->subheader); const char* c_pData = data + sizeof(TPacketCGOfflineShop); uiBytes -= sizeof(TPacketCGOfflineShop); switch (p->subheader) { case SHOP_SUBHEADER_CG_END: { sys_log(1, "INPUT: %s OFFLINE_SHOP: END", ch->GetName()); COfflineShopManager::instance().StopShopping(ch); return 0; } case SHOP_SUBHEADER_CG_BUY: { if (uiBytes < sizeof(BYTE) + sizeof(BYTE)) return -1; BYTE bPos = *(c_pData + 1); sys_log(1, "INPUT: %s OFFLINE_SHOP: BUY %d", ch->GetName(), bPos); COfflineShopManager::instance().Buy(ch, bPos); return (sizeof(BYTE) + sizeof(BYTE)); } case SHOP_SUBHEADER_CG_DESTROY_OFFLINE_SHOP: { sys_log(1, "INPUT: %s OFFLINE_SHOP_DESTROY", ch->GetName()); COfflineShopManager::instance().DestroyOfflineShop(ch, ch->GetOfflineShopVID(), true); return 0; } case SHOP_SUBHEADER_CG_ADD_ITEM: { if (uiBytes < sizeof(TOfflineShopItemTable2)) return -1; TOfflineShopItemTable2* pTable = (TOfflineShopItemTable2*)(c_pData); #ifdef ENABLE_CHEQUE_SYSTEM COfflineShopManager::instance().AddItem(ch, pTable->bDisplayPos, pTable->bPos, pTable->dwPrice, pTable->dwPriceCheque); #else COfflineShopManager::instance().AddItem(ch, pTable->bDisplayPos, pTable->bPos, pTable->dwPrice); #endif return (sizeof(TOfflineShopItemTable2)); } case SHOP_SUBHEADER_CG_REMOVE_ITEM: { if (uiBytes < sizeof(BYTE)) return -1; BYTE bPos = *c_pData; sys_log(0, "INPUT: %s REMOVE_ITEM : %d", ch->GetName(), bPos); COfflineShopManager::instance().RemoveItem(ch, bPos); return (sizeof(BYTE)); } case SHOP_SUBHEADER_CG_REFRESH: { sys_log(0, "INPUT: %s OFFLINE_SHOP_REFRESH_ITEM", ch->GetName()); COfflineShopManager::instance().Refresh(ch); return 0; } case SHOP_SUBHEADER_CG_REFRESH_MONEY: { sys_log(0, "INPUT: %s OFFLINE_SHOP_REFRESH_MONEY", ch->GetName()); COfflineShopManager::instance().RefreshMoney(ch); return 0; } case SHOP_SUBHEADER_CG_WITHDRAW_MONEY: { if (uiBytes < sizeof(DWORD)) return -1; const DWORD gold = *reinterpret_cast(c_pData); sys_log(0, "INPUT: %s(%d) OFFLINE_SHOP_WITHDRAW_MONEY", ch->GetName(), gold); COfflineShopManager::instance().WithdrawMoney(ch, gold); return (sizeof(DWORD)); } #ifdef ENABLE_CHEQUE_SYSTEM case SHOP_SUBHEADER_CG_WITHDRAW_CHEQUE: { if (uiBytes < sizeof(DWORD)) return -1; const DWORD cheque = *reinterpret_cast(c_pData); sys_log(0, "INPUT: %s(%d) SHOP_SUBHEADER_CG_WITHDRAW_CHEQUE", ch->GetName(), cheque); COfflineShopManager::instance().WithdrawCheque(ch, cheque); return (sizeof(DWORD)); } #endif case SHOP_SUBHEADER_CG_REFRESH_UNSOLD_ITEMS: { sys_log(0, "INPUT: %s OFFLINE_SHOP_REFRESH_UNSOLD_ITEMS", ch->GetName()); COfflineShopManager::instance().RefreshUnsoldItems(ch); return 0; } case SHOP_SUBHEADER_CG_TAKE_ITEM: { if (uiBytes < sizeof(BYTE)) return -1; BYTE bPos = *c_pData; sys_log(0, "INPUT: %s OFFLINE_SHOP_TAKE_ITEM", ch->GetName()); COfflineShopManager::instance().TakeItem(ch, bPos); return (sizeof(BYTE)); } case SHOP_SUBHEADER_CG_CHECK: { COfflineShopManager::instance().HasOfflineShop(ch); return 0; } default: { sys_err("CInputMain::OfflineShop : Unknown subheader %d : %s", p->subheader, ch->GetName()); break; } } return 0; } #endif void CInputMain::OnClick(LPCHARACTER ch, const char * data) { struct command_on_click * pinfo = (struct command_on_click *) data; LPCHARACTER victim; if ((victim = CHARACTER_MANAGER::instance().Find(pinfo->vid))) victim->OnClick(ch); else if (test_server) { sys_err("CInputMain::OnClick %s.Click.NOT_EXIST_VID[%d]", ch->GetName(), pinfo->vid); } } int CInputMain::FishEvent(LPCHARACTER ch, const char * data, size_t uiBytes) { TPacketCGFishEvent * p = (TPacketCGFishEvent *) data; if (uiBytes < sizeof(TPacketCGFishEvent)) return -1; const char * c_pData = data + sizeof(TPacketCGFishEvent); uiBytes -= sizeof(TPacketCGFishEvent); switch (p->bSubheader) { case FISH_EVENT_SUBHEADER_BOX_USE: { if (uiBytes < sizeof(BYTE) + sizeof(WORD)) return -1; BYTE bWindow = *(c_pData++); WORD wCell = *(c_pData); sys_log(0, "INPUT: %s FISH_EVENT: USE_BOX", ch->GetName()); ch->FishEventUseBox(TItemPos(bWindow, wCell)); return (sizeof(BYTE) + sizeof(WORD)); } case FISH_EVENT_SUBHEADER_SHAPE_ADD: { if (uiBytes < sizeof(BYTE)) return -1; BYTE shapePos = *c_pData; sys_log(0, "INPUT: %s FISH_EVENT: ADD_SHAPE", ch->GetName()); ch->FishEventAddShape(shapePos); return sizeof(BYTE); } default: sys_err("CInputMain::FishEvent : Unknown subheader %d : %s", p->bSubheader, ch->GetName()); break; } return 0; } #ifdef ENABLE_ATTR_6TH_7TH_SYSTEM int GetMaterialVnum(BYTE bItemLevel) { if (bItemLevel < 19) return 39070; else if (bItemLevel < 29) return 39071; else if (bItemLevel < 39) return 39072; else if (bItemLevel < 49) return 39073; else if (bItemLevel < 59) return 39074; else if (bItemLevel < 69) return 39075; else if (bItemLevel < 79) return 39076; else if (bItemLevel < 89) return 39077; else if (bItemLevel < 99) return 39078; else if (bItemLevel < 109) return 39079; else if (bItemLevel < 120) return 39080; else return -1; } int GetSupportSuccesCount(int vnum) { switch(vnum) { case 72064: return 5; case 72065: return 10; case 72066: return 20; case 72067: return 50; default: return 0; } } void CInputMain::Attr67Add(LPCHARACTER ch, const char * data) { TPacketCGAttr67Add * p = (TPacketCGAttr67Add *) data; LPITEM item = ch->GetItem(TItemPos(p->bWindowType, p->wSlotIndex)); LPITEM item2 = ch->GetItem(TItemPos(p->bSupportWindowType, p->wSupportSlotIndex)); if (!item) return; if (p->bSupportCount && !item2) return; if (item2 && ch->CountSpecifyItem(item2->GetVnum()) < p->bSupportCount) return; int iMaterialVnum = GetMaterialVnum(item->GetLevelLimit()); if (ch->CountSpecifyItem(iMaterialVnum) < p->bMaterialCount) return; int iProb = p->bMaterialCount * 2; ch->RemoveSpecifyItem(iMaterialVnum, p->bMaterialCount); if (item2) { iProb += p->bSupportCount * GetSupportSuccesCount(item2->GetVnum()); ch->RemoveSpecifyItem(item2->GetVnum(), p->bSupportCount); } if (number(1, 100) <= iProb) { item->AddRareAttribute(); // ch->ChatPacket(CHAT_TYPE_COMMAND, "Attr67Add 1"); } ch->ChatPacket(CHAT_TYPE_COMMAND, "Attr67Add"); } #endif void CInputMain::Exchange(LPCHARACTER ch, const char * data) { struct command_exchange * pinfo = (struct command_exchange *) data; LPCHARACTER to_ch = NULL; if (!ch->CanHandleItem()) return; int iPulse = thecore_pulse(); if ((to_ch = CHARACTER_MANAGER::instance().Find(pinfo->arg1))) { if (iPulse - to_ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime)) { to_ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래 후 %d초 이내에 창고를 열수 없습니다."), g_nPortalLimitTime); return; } if( true == to_ch->IsDead() ) { return; } } sys_log(0, "CInputMain()::Exchange() SubHeader %d ", pinfo->sub_header); if (iPulse - ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("거래 후 %d초 이내에 창고를 열수 없습니다."), g_nPortalLimitTime); return; } switch (pinfo->sub_header) { case EXCHANGE_SUBHEADER_CG_START: // arg1 == vid of target character if (!ch->GetExchange()) { if ((to_ch = CHARACTER_MANAGER::instance().Find(pinfo->arg1))) { //MONARCH_LIMIT /* if (to_ch->IsMonarch() || ch->IsMonarch()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("군주와는 거래를 할수가 없습니다"), g_nPortalLimitTime); return; } //END_MONARCH_LIMIT */ if (iPulse - ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고를 연후 %d초 이내에는 거래를 할수 없습니다."), g_nPortalLimitTime); if (test_server) ch->ChatPacket(CHAT_TYPE_INFO, "[TestOnly][Safebox]Pulse %d LoadTime %d PASS %d", iPulse, ch->GetSafeboxLoadTime(), PASSES_PER_SEC(g_nPortalLimitTime)); return; } if (iPulse - to_ch->GetSafeboxLoadTime() < PASSES_PER_SEC(g_nPortalLimitTime)) { to_ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고를 연후 %d초 이내에는 거래를 할수 없습니다."), g_nPortalLimitTime); if (test_server) to_ch->ChatPacket(CHAT_TYPE_INFO, "[TestOnly][Safebox]Pulse %d LoadTime %d PASS %d", iPulse, to_ch->GetSafeboxLoadTime(), PASSES_PER_SEC(g_nPortalLimitTime)); return; } if (ch->GetGold() >= GOLD_MAX) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("액수가 20억 냥을 초과하여 거래를 할수가 없습니다..")); sys_err("[OVERFLOG_GOLD] START (%u) id %u name %s ", ch->GetGold(), ch->GetPlayerID(), ch->GetName()); return; } #ifdef ENABLE_CHEQUE_SYSTEM if (ch->GetCheque() > CHEQUE_MAX) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("??? 20? ?? ???? ??? ??? ????..")); sys_err("[OVERFLOW_CHEQUE] START (%lld) id %u name %s ", ch->GetCheque(), ch->GetPlayerID(), ch->GetName()); //ch->SetGold(CHEQUE_MAX); return; } #endif if (to_ch->IsPC()) { if (quest::CQuestManager::instance().GiveItemToPC(ch->GetPlayerID(), to_ch)) { sys_log(0, "Exchange canceled by quest %s %s", ch->GetName(), to_ch->GetName()); return; } } #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM if (ch->GetMyShop() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->IsAttrTransferOpen() || ch->GetOfflineShopOwner()) #else if (ch->GetMyShop() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->IsAttrTransferOpen()) #endif { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중일경우 개인상점을 열수가 없습니다.")); return; } ch->ExchangeStart(to_ch); } } break; case EXCHANGE_SUBHEADER_CG_ITEM_ADD: // arg1 == position of item, arg2 == position in exchange window if (ch->GetExchange()) { if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true) #ifdef ENABLE_ITEM_CHECKINOUT_UPDATE ch->GetExchange()->AddItem(pinfo->Pos, pinfo->arg2, pinfo->SelectPosAuto); #else ch->GetExchange()->AddItem(pinfo->Pos, pinfo->arg2); #endif } break; case EXCHANGE_SUBHEADER_CG_ITEM_DEL: // arg1 == position of item if (ch->GetExchange()) { if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true) ch->GetExchange()->RemoveItem(pinfo->arg1); } break; case EXCHANGE_SUBHEADER_CG_ELK_ADD: // arg1 == amount of gold if (ch->GetExchange()) { const int64_t nTotalGold = static_cast(ch->GetExchange()->GetCompany()->GetOwner()->GetGold()) + static_cast(pinfo->arg1); if (GOLD_MAX <= nTotalGold) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("상대방의 총금액이 20억 냥을 초과하여 거래를 할수가 없습니다..")); sys_err("[OVERFLOW_GOLD] ELK_ADD (%u) id %u name %s ", ch->GetExchange()->GetCompany()->GetOwner()->GetGold(), ch->GetExchange()->GetCompany()->GetOwner()->GetPlayerID(), ch->GetExchange()->GetCompany()->GetOwner()->GetName()); return; } if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true) ch->GetExchange()->AddGold(pinfo->arg1); } break; #ifdef ENABLE_CHEQUE_SYSTEM case EXCHANGE_SUBHEADER_CG_WON_ADD: // arg1 == amount of cheque if (ch->GetExchange()) { const int64_t nTotalCheque = static_cast(ch->GetExchange()->GetCompany()->GetOwner()->GetCheque()) + static_cast(pinfo->arg1); if (CHEQUE_MAX <= nTotalCheque) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("???? ???? 20? ?? ???? ??? ??? ????..")); sys_err("[OVERFLOW_CHEQUE] WON_ADD (%u) id %u name %s ", ch->GetExchange()->GetCompany()->GetOwner()->GetCheque(), ch->GetExchange()->GetCompany()->GetOwner()->GetPlayerID(), ch->GetExchange()->GetCompany()->GetOwner()->GetName()); return; } if (ch->GetExchange()->GetCompany()->GetAcceptStatus() != true) ch->GetExchange()->AddCheque(pinfo->arg1); } break; #endif case EXCHANGE_SUBHEADER_CG_ACCEPT: // arg1 == not used if (ch->GetExchange()) { sys_log(0, "CInputMain()::Exchange() ==> ACCEPT "); ch->GetExchange()->Accept(true); } break; case EXCHANGE_SUBHEADER_CG_CANCEL: // arg1 == not used if (ch->GetExchange()) ch->GetExchange()->Cancel(); break; } } void CInputMain::Position(LPCHARACTER ch, const char * data) { struct command_position * pinfo = (struct command_position *) data; switch (pinfo->position) { case POSITION_GENERAL: ch->Standup(); break; case POSITION_SITTING_CHAIR: ch->Sitdown(0); break; case POSITION_SITTING_GROUND: ch->Sitdown(1); break; } } static const int ComboSequenceBySkillLevel[3][8] = { // 0 1 2 3 4 5 6 7 { 14, 15, 16, 17, 0, 0, 0, 0 }, { 14, 15, 16, 18, 20, 0, 0, 0 }, { 14, 15, 16, 18, 19, 17, 0, 0 }, }; #define COMBO_HACK_ALLOWABLE_MS 100 bool CheckComboHack(LPCHARACTER ch, BYTE bArg, DWORD dwTime, bool CheckSpeedHack) { if (ch->IsStun() || ch->IsDead()) return false; int ComboInterval = dwTime - ch->GetLastComboTime(); int HackScalar = 0; #if 0 sys_log(0, "COMBO: %s arg:%u seq:%u delta:%d checkspeedhack:%d", ch->GetName(), bArg, ch->GetComboSequence(), ComboInterval - ch->GetValidComboInterval(), CheckSpeedHack); #endif if (bArg == 14) { if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS) { //HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 300; //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"); } ch->SetComboSequence(1); ch->SetValidComboInterval((int) (ani_combo_speed(ch, 1) / (ch->GetPoint(POINT_ATT_SPEED) / 100.f))); ch->SetLastComboTime(dwTime); } else if (bArg > 14 && bArg < 22) { int idx = MIN(2, ch->GetComboIndex()); if (ch->GetComboSequence() > 5) { HackScalar = 1; ch->SetValidComboInterval(300); sys_log(0, "COMBO_HACK: 5 %s combo_seq:%d", ch->GetName(), ch->GetComboSequence()); } else if (bArg == 21 && idx == 2 && ch->GetComboSequence() == 5 && ch->GetJob() == JOB_ASSASSIN && ch->GetWear(WEAR_WEAPON) && ch->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_DAGGER) ch->SetValidComboInterval(300); else if (bArg == 21 && idx == 2 && ch->GetComboSequence() == 5 && ch->GetJob() == JOB_WOLFMAN && ch->GetWear(WEAR_WEAPON)->GetSubType() == WEAPON_CLAW) ch->SetValidComboInterval(100); else if (ComboSequenceBySkillLevel[idx][ch->GetComboSequence()] != bArg) { if (ch->GetJob() == JOB_WOLFMAN && bArg >= 16 && bArg <= 20) { return false; } if (ch->GetJob() == JOB_ASSASSIN && bArg >= 16 && bArg <= 20) { return false; } HackScalar = 1; ch->SetValidComboInterval(300); 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()); } else { if (CheckSpeedHack && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS) { int Calc = ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS; if (ch->GetJob() == JOB_WOLFMAN && Calc - ComboInterval < 400) { return false; } if (ch->GetJob() == JOB_ASSASSIN && Calc - ComboInterval < 400) { return false; } HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 100; 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"); } if (ch->IsRiding()) ch->SetComboSequence(ch->GetComboSequence() == 1 ? 2 : 1); else ch->SetComboSequence(ch->GetComboSequence() + 1); ch->SetValidComboInterval((int) (ani_combo_speed(ch, bArg - 13) / (ch->GetPoint(POINT_ATT_SPEED) / 100.f))); ch->SetLastComboTime(dwTime); } } else if (bArg == 13) { if (CheckSpeedHack && ComboInterval > 0 && ComboInterval < ch->GetValidComboInterval() - COMBO_HACK_ALLOWABLE_MS) { //HackScalar = 1 + (ch->GetValidComboInterval() - ComboInterval) / 100; //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)); } if (ch->GetRaceNum() >= MAIN_RACE_MAX_NUM) { float normalAttackDuration = CMotionManager::instance().GetNormalAttackDuration(ch->GetRaceNum()); int k = (int) (normalAttackDuration / ((float) ch->GetPoint(POINT_ATT_SPEED) / 100.f) * 900.f); ch->SetValidComboInterval(k); ch->SetLastComboTime(dwTime); } else { //if (ch->GetDesc()->DelayedDisconnect(number(2, 9))) //{ // LogManager::instance().HackLog("Hacker", ch); // sys_log(0, "HACKER: %s arg %u", ch->GetName(), bArg); //} } } else { // if (ch->GetDesc()->DelayedDisconnect(number(2, 9))) // { // LogManager::instance().HackLog("Hacker", ch); // sys_log(0, "HACKER: %s arg %u", ch->GetName(), bArg); // } HackScalar = 10; ch->SetValidComboInterval(300); } if (HackScalar) { if (get_dword_time() - ch->GetLastMountTime() > 1500) ch->IncreaseComboHackCount(1 + HackScalar); ch->SkipComboAttackByTime(ch->GetValidComboInterval()); } return HackScalar ? true : false; } void CInputMain::Move(LPCHARACTER ch, const char * data) { if (!ch->CanMove()) return; struct command_move * pinfo = (struct command_move *) data; if (pinfo->bFunc >= FUNC_MAX_NUM && !(pinfo->bFunc & 0x80)) { sys_err("invalid move type: %s", ch->GetName()); return; } //enum EMoveFuncType //{ // FUNC_WAIT, // FUNC_MOVE, // FUNC_ATTACK, // FUNC_COMBO, // FUNC_MOB_SKILL, // _FUNC_SKILL, // FUNC_MAX_NUM, // FUNC_SKILL = 0x80, //}; // 텔레포트 핵 체크 // if (!test_server) //2012.05.15 김용욱 : 테섭에서 (무적상태로) 다수 몬스터 상대로 다운되면서 공격시 콤보핵으로 죽는 문제가 있었다. { const float fDist = DISTANCE_SQRT((ch->GetX() - pinfo->lX) / 100, (ch->GetY() - pinfo->lY) / 100); if (((false == ch->IsRiding() && fDist > 100) || fDist > 160) && OXEVENT_MAP_INDEX != ch->GetMapIndex()) { sys_log(0, "MOVE: %s trying to move too far (dist: %.1fm) Riding(%d)", ch->GetName(), fDist, ch->IsRiding()); ch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ()); ch->Stop(); return; } DWORD dwCurTime = get_dword_time(); bool CheckSpeedHack = (false == ch->GetDesc()->IsHandshaking() && dwCurTime - ch->GetDesc()->GetClientTime() > 7000); #ifdef ENABLE_FIX_PRO_DAMAGE if (OXEVENT_MAP_INDEX != ch->GetMapIndex() && ch->CheckSyncPosition(true)) { sys_log(0, "#(HACK)# (%s) sync_check error", ch->GetName()); ch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ()); ch->Stop(); return; } #endif if (CheckSpeedHack) { int iDelta = (int) (pinfo->dwTime - ch->GetDesc()->GetClientTime()); int iServerDelta = (int) (dwCurTime - ch->GetDesc()->GetClientTime()); iDelta = (int) (dwCurTime - pinfo->dwTime); // 시간이 늦게간다. 일단 로그만 해둔다. 진짜 이런 사람들이 많은지 체크해야함. TODO if (iDelta >= 30000) { sys_log(0, "SPEEDHACK: slow timer name %s delta %d", ch->GetName(), iDelta); // ch->GetDesc()->DelayedDisconnect(3); } // 1초에 20msec 빨리 가는거 까지는 이해한다. else if (iDelta < -(iServerDelta / 50)) { sys_log(0, "SPEEDHACK: DETECTED! %s (delta %d %d)", ch->GetName(), iDelta, iServerDelta); // ch->GetDesc()->DelayedDisconnect(3); } } // // 콤보핵 및 스피드핵 체크 // if (pinfo->bFunc == FUNC_COMBO && g_bCheckMultiHack) { CheckComboHack(ch, pinfo->bArg, pinfo->dwTime, CheckSpeedHack); // 콤보 체크 } } if (pinfo->bFunc == FUNC_MOVE) { if (ch->GetLimitPoint(POINT_MOV_SPEED) == 0) return; ch->SetRotation(pinfo->bRot * 5); // 중복 코드 ch->ResetStopTime(); // "" ch->Goto(pinfo->lX, pinfo->lY); #ifdef ENABLE_NEW_EMOTION if (ch->isOnEmotion) { ch->isOnEmotion = false; event_cancel(&ch->m_emotionEvent); } #endif } else { if (pinfo->bFunc == FUNC_ATTACK || pinfo->bFunc == FUNC_COMBO) ch->OnMove(true); else if (pinfo->bFunc & FUNC_SKILL) { const int MASK_SKILL_MOTION = 0x7F; unsigned int motion = pinfo->bFunc & MASK_SKILL_MOTION; if (!ch->IsUsableSkillMotion(motion)) { const char* name = ch->GetName(); unsigned int job = ch->GetJob(); unsigned int group = ch->GetSkillGroup(); char szBuf[256]; snprintf(szBuf, sizeof(szBuf), "SKILL_HACK: name=%s, job=%d, group=%d, motion=%d", name, job, group, motion); LogManager::instance().HackLog(szBuf, ch->GetDesc()->GetAccountTable().login, ch->GetName(), ch->GetDesc()->GetHostName()); //sys_log(0, "%s", szBuf); // if (test_server) // { // ch->GetDesc()->DelayedDisconnect(number(2, 8)); // ch->ChatPacket(CHAT_TYPE_INFO, szBuf); // } // else // { // ch->GetDesc()->DelayedDisconnect(number(150, 500)); // } } ch->OnMove(); } ch->SetRotation(pinfo->bRot * 5); // 중복 코드 ch->ResetStopTime(); // "" #ifdef ENABLE_FIX_PRO_DAMAGE if (OXEVENT_MAP_INDEX != ch->GetMapIndex()) { int fDist = DISTANCE_SQRT((ch->GetX() - pinfo->lX) / 100, (ch->GetY() - pinfo->lY) / 100); ch->SetSyncPosition(pinfo->lX, pinfo->lY); if (((false == ch->IsRiding() && fDist > 25) || fDist > 40)) { sys_log(0, "#(HACK)# (%s) sync fDist = %d, limit = 16", ch->GetName(), fDist); ch->Show(ch->GetMapIndex(), ch->GetX(), ch->GetY(), ch->GetZ()); ch->Stop(); return; } int il = 0; if (((false == ch->IsRiding() && fDist > 20) || fDist > 35)) { il = DISTANCE_SQRT((ch->GetX() - pinfo->lX) / 100, (ch->GetY() - pinfo->lY) / 100) * 3; } ch->CheckSyncPosition() ? il += 1 : il += 3; ch->SetSyncCount(il); } #endif ch->Move(pinfo->lX, pinfo->lY); ch->Stop(); ch->StopStaminaConsume(); #ifdef ENABLE_NEW_EMOTION if (ch->isOnEmotion) { ch->isOnEmotion = false; event_cancel(&ch->m_emotionEvent); } #endif } TPacketGCMove pack; pack.bHeader = HEADER_GC_MOVE; pack.bFunc = pinfo->bFunc; pack.bArg = pinfo->bArg; pack.bRot = pinfo->bRot; pack.dwVID = ch->GetVID(); pack.lX = pinfo->lX; pack.lY = pinfo->lY; pack.dwTime = pinfo->dwTime; pack.dwDuration = (pinfo->bFunc == FUNC_MOVE) ? ch->GetCurrentMoveDuration() : 0; ch->PacketAround(&pack, sizeof(TPacketGCMove), ch); /* if (pinfo->dwTime == 10653691) // 디버거 발견 { if (ch->GetDesc()->DelayedDisconnect(number(15, 30))) LogManager::instance().HackLog("Debugger", ch); } else if (pinfo->dwTime == 10653971) // Softice 발견 { if (ch->GetDesc()->DelayedDisconnect(number(15, 30))) LogManager::instance().HackLog("Softice", ch); } */ /* sys_log(0, "MOVE: %s Func:%u Arg:%u Pos:%dx%d Time:%u Dist:%.1f", ch->GetName(), pinfo->bFunc, pinfo->bArg, pinfo->lX / 100, pinfo->lY / 100, pinfo->dwTime, fDist); */ } void CInputMain::Attack(LPCHARACTER ch, const BYTE header, const char* data) { if (NULL == ch) return; struct type_identifier { BYTE header; BYTE type; }; const struct type_identifier* const type = reinterpret_cast(data); if (type->type > 0) { if (false == ch->CanUseSkill(type->type)) { return; } switch (type->type) { case SKILL_GEOMPUNG: case SKILL_SANGONG: case SKILL_YEONSA: case SKILL_KWANKYEOK: case SKILL_HWAJO: case SKILL_GIGUNG: case SKILL_PABEOB: case SKILL_MARYUNG: case SKILL_TUSOK: case SKILL_MAHWAN: case SKILL_BIPABU: case SKILL_NOEJEON: case SKILL_CHAIN: #ifdef ENABLE_CONQUEROR_LEVEL case SKILL_ILGWANGPYO: case SKILL_MABEOBAGGWI: case SKILL_METEO: #endif case SKILL_HORSE_WILDATTACK_RANGE: if (HEADER_CG_SHOOT != type->header) { if (test_server) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Attack :name[%s] Vnum[%d] can't use skill by attack(warning)"), type->type); return; } break; } } switch (header) { case HEADER_CG_ATTACK: { if (NULL == ch->GetDesc()) return; const TPacketCGAttack* const packMelee = reinterpret_cast(data); ch->GetDesc()->AssembleCRCMagicCube(packMelee->bCRCMagicCubeProcPiece, packMelee->bCRCMagicCubeFilePiece); LPCHARACTER victim = CHARACTER_MANAGER::instance().Find(packMelee->dwVID); if (NULL == victim || ch == victim) return; switch (victim->GetCharType()) { case CHAR_TYPE_NPC: case CHAR_TYPE_WARP: case CHAR_TYPE_GOTO: return; } if (packMelee->bType > 0) { if (false == ch->CheckSkillHitCount(packMelee->bType, victim->GetVID())) { return; } } ch->Attack(victim, packMelee->bType); } break; case HEADER_CG_SHOOT: { const TPacketCGShoot* const packShoot = reinterpret_cast(data); ch->Shoot(packShoot->bType); } break; #ifdef ENABLE_ATTENDANCE_EVENT case HEADER_CG_ATTENDANCE_REWARD: CMiniGame::instance().AttendanceEventRequestReward(ch); break; #endif } } int CInputMain::SyncPosition(LPCHARACTER ch, const char * c_pcData, size_t uiBytes) { const TPacketCGSyncPosition* pinfo = reinterpret_cast( c_pcData ); if (uiBytes < pinfo->wSize) return -1; int iExtraLen = pinfo->wSize - sizeof(TPacketCGSyncPosition); if (iExtraLen < 0) { sys_err("invalid packet length (len %d size %u buffer %u)", iExtraLen, pinfo->wSize, uiBytes); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } if (0 != (iExtraLen % sizeof(TPacketCGSyncPositionElement))) { sys_err("invalid packet length %d (name: %s)", pinfo->wSize, ch->GetName()); return iExtraLen; } int iCount = iExtraLen / sizeof(TPacketCGSyncPositionElement); if (iCount <= 0) return iExtraLen; static const int nCountLimit = 16; if( iCount > nCountLimit ) { //LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch ); sys_err( "Too many SyncPosition Count(%d) from Name(%s)", iCount, ch->GetName() ); //ch->GetDesc()->SetPhase(PHASE_CLOSE); //return -1; iCount = nCountLimit; } TEMP_BUFFER tbuf; LPBUFFER lpBuf = tbuf.getptr(); TPacketGCSyncPosition * pHeader = (TPacketGCSyncPosition *) buffer_write_peek(lpBuf); buffer_write_proceed(lpBuf, sizeof(TPacketGCSyncPosition)); const TPacketCGSyncPositionElement* e = reinterpret_cast(c_pcData + sizeof(TPacketCGSyncPosition)); timeval tvCurTime; gettimeofday(&tvCurTime, NULL); for (int i = 0; i < iCount; ++i, ++e) { LPCHARACTER victim = CHARACTER_MANAGER::instance().Find(e->dwVID); if (!victim) continue; switch (victim->GetCharType()) { case CHAR_TYPE_NPC: case CHAR_TYPE_WARP: case CHAR_TYPE_GOTO: continue; } // 소유권 검사 if (!victim->SetSyncOwner(ch)) continue; const float fDistWithSyncOwner = DISTANCE_SQRT( (victim->GetX() - ch->GetX()) / 100, (victim->GetY() - ch->GetY()) / 100 ); static const float fLimitDistWithSyncOwner = 2500.f + 1000.f; // victim과의 거리가 2500 + a 이상이면 핵으로 간주. // 거리 참조 : 클라이언트의 __GetSkillTargetRange, __GetBowRange 함수 // 2500 : 스킬 proto에서 가장 사거리가 긴 스킬의 사거리, 또는 활의 사거리 // a = POINT_BOW_DISTANCE 값... 인데 실제로 사용하는 값인지는 잘 모르겠음. 아이템이나 포션, 스킬, 퀘스트에는 없는데... // 그래도 혹시나 하는 마음에 버퍼로 사용할 겸해서 1000.f 로 둠... if (fDistWithSyncOwner > fLimitDistWithSyncOwner) { // g_iSyncHackLimitCount번 까지는 봐줌. //if (ch->GetSyncHackCount() < g_iSyncHackLimitCount) //{ // ch->SetSyncHackCount(ch->GetSyncHackCount() + 1); // continue; //} //else //{ LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch ); sys_err( "Too far SyncPosition DistanceWithSyncOwner(%f)(%s) from Name(%s) CH(%d,%d) VICTIM(%d,%d) SYNC(%d,%d)", fDistWithSyncOwner, victim->GetName(), ch->GetName(), ch->GetX(), ch->GetY(), victim->GetX(), victim->GetY(), e->lX, e->lY ); // ch->GetDesc()->SetPhase(PHASE_CLOSE); // return -1; //} } const float fDist = DISTANCE_SQRT( (victim->GetX() - e->lX) / 100, (victim->GetY() - e->lY) / 100 ); static const long g_lValidSyncInterval = 100 * 1000; // 100ms const timeval &tvLastSyncTime = victim->GetLastSyncTime(); timeval *tvDiff = timediff(&tvCurTime, &tvLastSyncTime); // SyncPosition을 악용하여 타유저를 이상한 곳으로 보내는 핵 방어하기 위하여, // 같은 유저를 g_lValidSyncInterval ms 이내에 다시 SyncPosition하려고 하면 핵으로 간주. if (tvDiff->tv_sec == 0 && tvDiff->tv_usec < g_lValidSyncInterval) { // g_iSyncHackLimitCount번 까지는 봐줌. if (ch->GetSyncHackCount() < g_iSyncHackLimitCount) { ch->SetSyncHackCount(ch->GetSyncHackCount() + 1); continue; } else { LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch ); sys_err( "Too often SyncPosition Interval(%ldms)(%s) from Name(%s) VICTIM(%d,%d) SYNC(%d,%d)", tvDiff->tv_sec * 1000 + tvDiff->tv_usec / 1000, victim->GetName(), ch->GetName(), victim->GetX(), victim->GetY(), e->lX, e->lY ); //ch->GetDesc()->SetPhase(PHASE_CLOSE); //return -1; } } else if( fDist > 25.0f ) { LogManager::instance().HackLog( "SYNC_POSITION_HACK", ch ); sys_err( "Too far SyncPosition Distance(%f)(%s) from Name(%s) CH(%d,%d) VICTIM(%d,%d) SYNC(%d,%d)", fDist, victim->GetName(), ch->GetName(), ch->GetX(), ch->GetY(), victim->GetX(), victim->GetY(), e->lX, e->lY ); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } else { victim->SetLastSyncTime(tvCurTime); victim->Sync(e->lX, e->lY); buffer_write(lpBuf, e, sizeof(TPacketCGSyncPositionElement)); } } if (buffer_size(lpBuf) != sizeof(TPacketGCSyncPosition)) { pHeader->bHeader = HEADER_GC_SYNC_POSITION; pHeader->wSize = buffer_size(lpBuf); ch->PacketAround(buffer_read_peek(lpBuf), buffer_size(lpBuf), ch); } return iExtraLen; } void CInputMain::FlyTarget(LPCHARACTER ch, const char * pcData, BYTE bHeader) { TPacketCGFlyTargeting * p = (TPacketCGFlyTargeting *) pcData; ch->FlyTarget(p->dwTargetVID, p->x, p->y, bHeader); } void CInputMain::UseSkill(LPCHARACTER ch, const char * pcData) { TPacketCGUseSkill * p = (TPacketCGUseSkill *) pcData; ch->UseSkill(p->dwVnum, CHARACTER_MANAGER::instance().Find(p->dwVID)); } void CInputMain::ScriptButton(LPCHARACTER ch, const void* c_pData) { TPacketCGScriptButton * p = (TPacketCGScriptButton *) c_pData; sys_log(0, "QUEST ScriptButton pid %d idx %u", ch->GetPlayerID(), p->idx); quest::PC* pc = quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID()); if (pc && pc->IsConfirmWait()) { quest::CQuestManager::instance().Confirm(ch->GetPlayerID(), quest::CONFIRM_TIMEOUT); } else if (p->idx & 0x80000000) { quest::CQuestManager::Instance().QuestInfo(ch->GetPlayerID(), p->idx & 0x7fffffff); } else { quest::CQuestManager::Instance().QuestButton(ch->GetPlayerID(), p->idx); } } void CInputMain::ScriptAnswer(LPCHARACTER ch, const void* c_pData) { TPacketCGScriptAnswer * p = (TPacketCGScriptAnswer *) c_pData; sys_log(0, "QUEST ScriptAnswer pid %d answer %d", ch->GetPlayerID(), p->answer); if (p->answer > 250) // 다음 버튼에 대한 응답으로 온 패킷인 경우 { quest::CQuestManager::Instance().Resume(ch->GetPlayerID()); } else // 선택 버튼을 골라서 온 패킷인 경우 { quest::CQuestManager::Instance().Select(ch->GetPlayerID(), p->answer); } } // SCRIPT_SELECT_ITEM void CInputMain::ScriptSelectItem(LPCHARACTER ch, const void* c_pData) { TPacketCGScriptSelectItem* p = (TPacketCGScriptSelectItem*) c_pData; sys_log(0, "QUEST ScriptSelectItem pid %d answer %d", ch->GetPlayerID(), p->selection); quest::CQuestManager::Instance().SelectItem(ch->GetPlayerID(), p->selection); } // END_OF_SCRIPT_SELECT_ITEM void CInputMain::QuestInputString(LPCHARACTER ch, const void* c_pData) { TPacketCGQuestInputString * p = (TPacketCGQuestInputString*) c_pData; char msg[65]; strlcpy(msg, p->msg, sizeof(msg)); sys_log(0, "QUEST InputString pid %u msg %s", ch->GetPlayerID(), msg); quest::CQuestManager::Instance().Input(ch->GetPlayerID(), msg); } #ifdef ENABLE_OX_RENEWAL void CInputMain::QuestInputLongString(LPCHARACTER ch, const void* c_pData) { TPacketCGQuestInputLongString * p = (TPacketCGQuestInputLongString*)c_pData; char msg[129]; strlcpy(msg, p->msg, sizeof(msg)); sys_log(0, "QUEST InputLongString pid %u msg %s", ch->GetPlayerID(), msg); quest::CQuestManager::Instance().Input(ch->GetPlayerID(), msg); } #endif void CInputMain::QuestConfirm(LPCHARACTER ch, const void* c_pData) { TPacketCGQuestConfirm* p = (TPacketCGQuestConfirm*) c_pData; LPCHARACTER ch_wait = CHARACTER_MANAGER::instance().FindByPID(p->requestPID); if (p->answer) p->answer = quest::CONFIRM_YES; sys_log(0, "QuestConfirm from %s pid %u name %s answer %d", ch->GetName(), p->requestPID, (ch_wait)?ch_wait->GetName():"", p->answer); if (ch_wait) { quest::CQuestManager::Instance().Confirm(ch_wait->GetPlayerID(), (quest::EQuestConfirmType) p->answer, ch->GetPlayerID()); } } void CInputMain::Target(LPCHARACTER ch, const char * pcData) { TPacketCGTarget * p = (TPacketCGTarget *) pcData; building::LPOBJECT pkObj = building::CManager::instance().FindObjectByVID(p->dwVID); if (pkObj) { TPacketGCTarget pckTarget; pckTarget.header = HEADER_GC_TARGET; pckTarget.dwVID = p->dwVID; ch->GetDesc()->Packet(&pckTarget, sizeof(TPacketGCTarget)); } else ch->SetTarget(CHARACTER_MANAGER::instance().Find(p->dwVID)); } void CInputMain::Warp(LPCHARACTER ch, const char * pcData) { ch->WarpEnd(); } #ifdef ENABLE_ADMIN_BAN_MANAGER enum ETypeActionBan { ACTION_BAN_PERMANENTLY = 0, ACTION_BAN_IP = 1 , ACTION_BAN_TIME = 2, }; bool CheckIsStaffAdmin(LPCHARACTER ch) { if (ch->GetGMLevel() >= GM_LOW_WIZARD) return true; return false; } bool CheckIsBlocked(LPCHARACTER ch, const char* c_szName) { std::unique_ptr pMsg(DBManager::instance().DirectQuery("SELECT account_id FROM player.player WHERE name = '%s'", c_szName)); MYSQL_ROW row_id = mysql_fetch_row(pMsg->Get()->pSQLResult); if (pMsg->uiSQLErrno != 0 || !pMsg->Get()->uiNumRows) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_error_cannot_find_user"), c_szName); return false; } int account_id = 0; str_to_number(account_id, row_id[0]); std::unique_ptr pMsg2(DBManager::instance().DirectQuery("SELECT status FROM account.account WHERE id = '%d'", account_id)); MYSQL_ROW row_inf = mysql_fetch_row(pMsg2->Get()->pSQLResult); const char* c_szStatus = row_inf[0]; if (!strcmp(c_szStatus, "BLOCK")) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_error_is_blocked"), c_szName); return true; } return false; } void InsertLogsBan(const char* c_pszWho, const char* c_pszAction, const char* c_pszVictim, const char* c_pszReason) { DBManager::Instance().DirectQuery("INSERT INTO log.tool_ban (who, action, victim, reason, date) VALUES('%s', '%s', '%s', '%s', NOW())", c_pszWho, c_pszAction, c_pszVictim, c_pszReason); } void CInputMain::SendAdminBanManager(LPCHARACTER ch, const char* c_pData) { const TPacketCGAdminBanManger* p = reinterpret_cast(c_pData); if (!ch) return; if (!CheckIsStaffAdmin(ch)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_error_implementor")); return; } char szEscapedUserName[CHAT_MAX_LEN * 2 + 1]; DBManager::instance().EscapeString(szEscapedUserName, sizeof(szEscapedUserName), p->user_name, strlen(p->user_name)); char szEscapedReason[CHAT_MAX_LEN * 2 + 1]; DBManager::instance().EscapeString(szEscapedReason, sizeof(szEscapedReason), p->reason, strlen(p->reason)); if (!strcmp(szEscapedUserName, ch->GetName())) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_error_yourself")); return; } if (CheckIsBlocked(ch, szEscapedUserName)) return; switch (p->action) { case ACTION_BAN_PERMANENTLY: case ACTION_BAN_TIME: { std::unique_ptr pMsg(DBManager::instance().DirectQuery("SELECT name, account_id FROM player.player WHERE name = '%s'", szEscapedUserName)); MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult); if (pMsg->uiSQLErrno != 0 || !pMsg->Get()->uiNumRows) return; int account_id = 0; str_to_number(account_id, row[1]); if (p->action == ACTION_BAN_PERMANENTLY) { DBManager::Instance().DirectQuery("UPDATE account.account SET status = 'BLOCK', ban_reason = '%s' WHERE id = '%d'", p->reason, account_id); InsertLogsBan(ch->GetName(), "ACTION_BAN_PERMANENTLY", szEscapedUserName, p->reason); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_succes_ban_permanently"), szEscapedUserName); } else { if (p->duration < 300) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_error_timer")); return; } DBManager::Instance().DirectQuery("UPDATE account.account SET availDt = FROM_UNIXTIME(UNIX_TIMESTAMP(CURRENT_TIMESTAMP()) + %i), ban_reason = '%s' WHERE id = %d", p->duration, p->reason, account_id); InsertLogsBan(ch->GetName(), "ACTION_BAN_TIME", szEscapedUserName, p->reason); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_succes_ban_time"), szEscapedUserName); } } break; case ACTION_BAN_IP: { if (ch->GetGMLevel() == GM_HIGH_WIZARD or ch->GetGMLevel() == GM_IMPLEMENTOR) { std::unique_ptr pMsg(DBManager::instance().DirectQuery("SELECT name, ip FROM player.player WHERE name = '%s'", szEscapedUserName)); MYSQL_ROW row = mysql_fetch_row(pMsg->Get()->pSQLResult); if (pMsg->uiSQLErrno != 0 || !pMsg->Get()->uiNumRows) return; std::unique_ptr pMsg2(DBManager::Instance().DirectQuery("UPDATE account.account INNER JOIN player.player ON player.account_id = account.id SET status = 'BLOCK', ban_reason = '%s' WHERE player.ip = '%s'", p->reason, row[1])); InsertLogsBan(ch->GetName(), "ACTION_BAN_IP", szEscapedUserName, p->reason); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_succes_ban_ip"), szEscapedUserName, pMsg2->Get()->uiAffectedRows); } if (ch->GetGMLevel() == GM_GOD or ch->GetGMLevel() == GM_LOW_WIZARD) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("admin_manager_error_implementor")); return; } } break; default: return; } } #endif void CInputMain::SafeboxCheckin(LPCHARACTER ch, const char * c_pData) { if (quest::CQuestManager::instance().GetPCForce(ch->GetPlayerID())->IsRunning() == true) return; TPacketCGSafeboxCheckin * p = (TPacketCGSafeboxCheckin *) c_pData; if (!ch->CanHandleItem()) return; CSafebox * pkSafebox = ch->GetSafebox(); LPITEM pkItem = ch->GetItem(p->ItemPos); if (!pkSafebox || !pkItem) return; if (ITEM_BELT == pkItem->GetType() && pkItem->IsEquipped() && CBeltInventoryHelper::IsExistItemInBeltInventory(ch)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("once_kemer_envanterini_bosalt")); return; } if (true == pkItem->IsEquipped()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("depo_giyili_item")); return; } #ifdef ENABLE_EXTEND_INVEN_SYSTEM if (pkItem->GetCell() >= ch->GetExtendInvenMax() && IS_SET(pkItem->GetFlag(), ITEM_FLAG_IRREMOVABLE)) #else if (pkItem->GetCell() >= INVENTORY_MAX_NUM && IS_SET(pkItem->GetFlag(), ITEM_FLAG_IRREMOVABLE)) #endif { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 창고로 옮길 수 없는 아이템 입니다.")); return; } if (!pkSafebox->IsEmpty(p->bSafePos, pkItem->GetSize())) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } if (pkItem->GetVnum() == UNIQUE_ITEM_SAFEBOX_EXPAND) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 이 아이템은 넣을 수 없습니다.")); return; } if( IS_SET(pkItem->GetAntiFlag(), ITEM_ANTIFLAG_SAFEBOX) ) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 이 아이템은 넣을 수 없습니다.")); return; } if (true == pkItem->isLocked()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 이 아이템은 넣을 수 없습니다.")); return; } // @fixme140 BEGIN if (ITEM_BELT == pkItem->GetType() && CBeltInventoryHelper::IsExistItemInBeltInventory(ch)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("벨트 인벤토리에 아이템이 존재하면 해제할 수 없습니다.")); return; } // @fixme140 END pkItem->RemoveFromCharacter(); if (!pkItem->IsDragonSoul()) ch->SyncQuickslot(QUICKSLOT_TYPE_ITEM, p->ItemPos.cell, 1000); pkSafebox->Add(p->bSafePos, pkItem); char szHint[128]; snprintf(szHint, sizeof(szHint), "%s %u", pkItem->GetName(), pkItem->GetCount()); LogManager::instance().ItemLog(ch, pkItem, "SAFEBOX PUT", szHint); } void CInputMain::SafeboxCheckout(LPCHARACTER ch, const char * c_pData, bool bMall) { TPacketCGSafeboxCheckout * p = (TPacketCGSafeboxCheckout *) c_pData; if (!ch->CanHandleItem()) return; CSafebox * pkSafebox; if (bMall) pkSafebox = ch->GetMall(); else pkSafebox = ch->GetSafebox(); if (!pkSafebox) return; LPITEM pkItem = pkSafebox->Get(p->bSafePos); if (!pkItem) return; if (!ch->IsEmptyItemGrid(p->ItemPos, pkItem->GetSize())) return; for (WORD belt_index = BELT_INVENTORY_SLOT_START; belt_index < BELT_INVENTORY_SLOT_END; ++belt_index) { if (pkItem->GetType() != 3 && p->ItemPos.cell == belt_index) { if(pkItem->GetSubType() != 0 || pkItem->GetSubType() != 11 || pkItem->GetSubType() != 7) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("depodan_kemer_envanterine_nesne_koyamazsın")); return; } } } // 아이템 몰에서 인벤으로 옮기는 부분에서 용혼석 특수 처리 // (몰에서 만드는 아이템은 item_proto에 정의된대로 속성이 붙기 때문에, // 용혼석의 경우, 이 처리를 하지 않으면 속성이 하나도 붙지 않게 된다.) if (pkItem->IsDragonSoul()) { if (bMall) { DSManager::instance().DragonSoulItemInitialize(pkItem); } if (DRAGON_SOUL_INVENTORY != p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } TItemPos DestPos = p->ItemPos; if (!DSManager::instance().IsValidCellForThisItem(pkItem, DestPos)) { int iCell = ch->GetEmptyDragonSoulInventory(pkItem); if (iCell < 0) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return ; } DestPos = TItemPos (DRAGON_SOUL_INVENTORY, iCell); } pkSafebox->Remove(p->bSafePos); pkItem->AddToCharacter(ch, DestPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } #ifdef ENABLE_SPLIT_INVENTORY_SYSTEM else if (pkItem->IsSkillBook()) { if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } if (p->ItemPos.IsSkillBookInventoryPosition() == false) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("CANNOT_MOVE_ITEM_THIS_WINDOW")); return; } pkSafebox->Remove(p->bSafePos); pkItem->AddToCharacter(ch, p->ItemPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } else if (pkItem->IsUpgradeItem()) { if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } if (p->ItemPos.IsUpgradeItemsInventoryPosition() == false) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("CANNOT_MOVE_ITEM_THIS_WINDOW")); return; } pkSafebox->Remove(p->bSafePos); pkItem->AddToCharacter(ch, p->ItemPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } else if (pkItem->IsStone()) { if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } if (p->ItemPos.IsStoneInventoryPosition() == false) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("CANNOT_MOVE_ITEM_THIS_WINDOW")); return; } pkSafebox->Remove(p->bSafePos); pkItem->AddToCharacter(ch, p->ItemPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } else if (pkItem->IsBox()) { if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } if (p->ItemPos.IsBoxInventoryPosition() == false) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("CANNOT_MOVE_ITEM_THIS_WINDOW")); return; } pkSafebox->Remove(p->bSafePos); pkItem->AddToCharacter(ch, p->ItemPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } else if (pkItem->IsEfsun()) { if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } if (p->ItemPos.IsEfsunInventoryPosition() == false) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("CANNOT_MOVE_ITEM_THIS_WINDOW")); return; } pkSafebox->Remove(p->bSafePos); pkItem->AddToCharacter(ch, p->ItemPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } else if (pkItem->IsCicek()) { if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } if (p->ItemPos.IsCicekInventoryPosition() == false) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("CANNOT_MOVE_ITEM_THIS_WINDOW")); return; } pkSafebox->Remove(p->bSafePos); pkItem->AddToCharacter(ch, p->ItemPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } #endif else { if (DRAGON_SOUL_INVENTORY == p->ItemPos.window_type) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } // @fixme119 if (p->ItemPos.IsBeltInventoryPosition() && false == CBeltInventoryHelper::CanMoveIntoBeltInventory(pkItem)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<창고> 옮길 수 없는 위치입니다.")); return; } pkSafebox->Remove(p->bSafePos); if (bMall) { if (NULL == pkItem->GetProto()) { sys_err ("pkItem->GetProto() == NULL (id : %d)",pkItem->GetID()); return ; } // 100% 확률로 속성이 붙어야 하는데 안 붙어있다면 새로 붙힌다. ............... if (100 == pkItem->GetProto()->bAlterToMagicItemPct && 0 == pkItem->GetAttributeCount()) { pkItem->AlterToMagicItem(); } } pkItem->AddToCharacter(ch, p->ItemPos); ITEM_MANAGER::instance().FlushDelayedSave(pkItem); } DWORD dwID = pkItem->GetID(); db_clientdesc->DBPacketHeader(HEADER_GD_ITEM_FLUSH, 0, sizeof(DWORD)); db_clientdesc->Packet(&dwID, sizeof(DWORD)); char szHint[128]; snprintf(szHint, sizeof(szHint), "%s %u", pkItem->GetName(), pkItem->GetCount()); if (bMall) LogManager::instance().ItemLog(ch, pkItem, "MALL GET", szHint); else LogManager::instance().ItemLog(ch, pkItem, "SAFEBOX GET", szHint); } void CInputMain::SafeboxItemMove(LPCHARACTER ch, const char * data) { struct command_item_move * pinfo = (struct command_item_move *) data; if (!ch->CanHandleItem()) return; if (!ch->GetSafebox()) return; ch->GetSafebox()->MoveItem(pinfo->Cell.cell, pinfo->CellTo.cell, pinfo->count); } // PARTY_JOIN_BUG_FIX void CInputMain::PartyInvite(LPCHARACTER ch, const char * c_pData) { if (ch->GetArena()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다.")); return; } TPacketCGPartyInvite * p = (TPacketCGPartyInvite*) c_pData; LPCHARACTER pInvitee = CHARACTER_MANAGER::instance().Find(p->vid); if (!pInvitee || !ch->GetDesc() || !pInvitee->GetDesc()) { sys_err("PARTY Cannot find invited character"); return; } #ifdef ENABLE_MESSENGER_BLOCK if (MessengerManager::instance().CheckMessengerList(ch->GetName(), pInvitee->GetName(), SYST_BLOCK)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s blokkk"), pInvitee->GetName()); return; } #endif ch->PartyInvite(pInvitee); } void CInputMain::PartyInviteAnswer(LPCHARACTER ch, const char * c_pData) { if (ch->GetArena()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다.")); return; } TPacketCGPartyInviteAnswer * p = (TPacketCGPartyInviteAnswer*) c_pData; LPCHARACTER pInviter = CHARACTER_MANAGER::instance().Find(p->leader_vid); // pInviter 가 ch 에게 파티 요청을 했었다. if (!pInviter) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티요청을 한 캐릭터를 찾을수 없습니다.")); else if (!p->accept) pInviter->PartyInviteDeny(ch->GetPlayerID()); else pInviter->PartyInviteAccept(ch); } // END_OF_PARTY_JOIN_BUG_FIX void CInputMain::PartySetState(LPCHARACTER ch, const char* c_pData) { if (!CPartyManager::instance().IsEnablePCParty()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다.")); return; } TPacketCGPartySetState* p = (TPacketCGPartySetState*) c_pData; if (!ch->GetParty()) return; if (ch->GetParty()->GetLeaderPID() != ch->GetPlayerID()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 리더만 변경할 수 있습니다.")); return; } if (!ch->GetParty()->IsMember(p->pid)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 상태를 변경하려는 사람이 파티원이 아닙니다.")); return; } DWORD pid = p->pid; sys_log(0, "PARTY SetRole pid %d to role %d state %s", pid, p->byRole, p->flag ? "on" : "off"); switch (p->byRole) { case PARTY_ROLE_NORMAL: break; case PARTY_ROLE_ATTACKER: case PARTY_ROLE_TANKER: case PARTY_ROLE_BUFFER: case PARTY_ROLE_SKILL_MASTER: case PARTY_ROLE_HASTE: case PARTY_ROLE_DEFENDER: if (ch->GetParty()->SetRole(pid, p->byRole, p->flag)) { TPacketPartyStateChange pack; pack.dwLeaderPID = ch->GetPlayerID(); pack.dwPID = p->pid; pack.bRole = p->byRole; pack.bFlag = p->flag; db_clientdesc->DBPacket(HEADER_GD_PARTY_STATE_CHANGE, 0, &pack, sizeof(pack)); } /* else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 어태커 설정에 실패하였습니다.")); */ break; default: sys_err("wrong byRole in PartySetState Packet name %s state %d", ch->GetName(), p->byRole); break; } } void CInputMain::PartyRemove(LPCHARACTER ch, const char* c_pData) { if (ch->GetArena()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("대련장에서 사용하실 수 없습니다.")); return; } if (!CPartyManager::instance().IsEnablePCParty()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 서버 문제로 파티 관련 처리를 할 수 없습니다.")); return; } if (ch->GetDungeon()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던전 안에서는 파티에서 추방할 수 없습니다.")); return; } #ifdef ENABLE_12ZI if (ch->GetZodiac() || (ch->GetMapIndex() >= 3580000 && ch->GetMapIndex() < 3590000)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("Zodyak tapinaginda grubu bozamazsin.")); return; } #endif TPacketCGPartyRemove* p = (TPacketCGPartyRemove*) c_pData; if (!ch->GetParty()) return; LPPARTY pParty = ch->GetParty(); if (pParty->GetLeaderPID() == ch->GetPlayerID()) { if (ch->GetDungeon()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던젼내에서는 파티원을 추방할 수 없습니다.")); } else { // leader can remove any member if (p->pid == ch->GetPlayerID() || pParty->GetMemberCount() == 2) { // party disband CPartyManager::instance().DeleteParty(pParty); } else { LPCHARACTER B = CHARACTER_MANAGER::instance().FindByPID(p->pid); if (B) { //pParty->SendPartyRemoveOneToAll(B); B->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티에서 추방당하셨습니다.")); //pParty->Unlink(B); //CPartyManager::instance().SetPartyMember(B->GetPlayerID(), NULL); } pParty->Quit(p->pid); } } } else { // otherwise, only remove itself if (p->pid == ch->GetPlayerID()) { if (ch->GetDungeon()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 던젼내에서는 파티를 나갈 수 없습니다.")); } else { if (pParty->GetMemberCount() == 2) { // party disband CPartyManager::instance().DeleteParty(pParty); } else { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티에서 나가셨습니다.")); //pParty->SendPartyRemoveOneToAll(ch); pParty->Quit(ch->GetPlayerID()); //pParty->SendPartyRemoveAllToOne(ch); //CPartyManager::instance().SetPartyMember(ch->GetPlayerID(), NULL); } } } else { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 다른 파티원을 탈퇴시킬 수 없습니다.")); } } } void CInputMain::AnswerMakeGuild(LPCHARACTER ch, const char* c_pData) { TPacketCGAnswerMakeGuild* p = (TPacketCGAnswerMakeGuild*) c_pData; if (ch->GetGold() < 200000 || ch->GetLevel() < 40)//@fixme241 return; if (get_global_time() - ch->GetQuestFlag("guild_manage.new_disband_time") < CGuildManager::instance().GetDisbandDelay()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 해산한 후 %d일 이내에는 길드를 만들 수 없습니다."), quest::CQuestManager::instance().GetEventFlag("guild_disband_delay")); return; } if (get_global_time() - ch->GetQuestFlag("guild_manage.new_withdraw_time") < CGuildManager::instance().GetWithdrawDelay()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 탈퇴한 후 %d일 이내에는 길드를 만들 수 없습니다."), quest::CQuestManager::instance().GetEventFlag("guild_withdraw_delay")); return; } if (ch->GetGuild()) return; CGuildManager& gm = CGuildManager::instance(); TGuildCreateParameter cp; memset(&cp, 0, sizeof(cp)); cp.master = ch; strlcpy(cp.name, p->guild_name, sizeof(cp.name)); if (cp.name[0] == 0 || !check_name(cp.name)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("적합하지 않은 길드 이름 입니다.")); return; } DWORD dwGuildID = gm.CreateGuild(cp); if (dwGuildID) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> [%s] 길드가 생성되었습니다."), cp.name); int GuildCreateFee = 200000; ch->PointChange(POINT_GOLD, -GuildCreateFee); DBManager::instance().SendMoneyLog(MONEY_LOG_GUILD, ch->GetPlayerID(), -GuildCreateFee); char Log[128]; snprintf(Log, sizeof(Log), "GUILD_NAME %s MASTER %s", cp.name, ch->GetName()); LogManager::instance().CharLog(ch, 0, "MAKE_GUILD", Log); ch->RemoveSpecifyItem(GUILD_CREATE_ITEM_VNUM, 1); //ch->SendGuildName(dwGuildID); } else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드 생성에 실패하였습니다.")); } void CInputMain::PartyUseSkill(LPCHARACTER ch, const char* c_pData) { TPacketCGPartyUseSkill* p = (TPacketCGPartyUseSkill*) c_pData; if (!ch->GetParty()) return; if (ch->GetPlayerID() != ch->GetParty()->GetLeaderPID()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 파티 기술은 파티장만 사용할 수 있습니다.")); return; } switch (p->bySkillIndex) { case PARTY_SKILL_HEAL: ch->GetParty()->HealParty(); break; case PARTY_SKILL_WARP: { LPCHARACTER pch = CHARACTER_MANAGER::instance().Find(p->vid); if (pch) ch->GetParty()->SummonToLeader(pch->GetPlayerID()); else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<파티> 소환하려는 대상을 찾을 수 없습니다.")); } break; } } void CInputMain::PartyParameter(LPCHARACTER ch, const char * c_pData) { TPacketCGPartyParameter * p = (TPacketCGPartyParameter *) c_pData; if (ch->GetParty()) ch->GetParty()->SetParameter(p->bDistributeMode); } size_t GetSubPacketSize(const GUILD_SUBHEADER_CG& header) { switch (header) { case GUILD_SUBHEADER_CG_DEPOSIT_MONEY: return sizeof(int); case GUILD_SUBHEADER_CG_WITHDRAW_MONEY: return sizeof(int); case GUILD_SUBHEADER_CG_ADD_MEMBER: return sizeof(DWORD); case GUILD_SUBHEADER_CG_REMOVE_MEMBER: return sizeof(DWORD); case GUILD_SUBHEADER_CG_CHANGE_GRADE_NAME: return 10; case GUILD_SUBHEADER_CG_CHANGE_GRADE_AUTHORITY: return sizeof(BYTE) + sizeof(BYTE); case GUILD_SUBHEADER_CG_OFFER: return sizeof(DWORD); case GUILD_SUBHEADER_CG_CHARGE_GSP: return sizeof(int); case GUILD_SUBHEADER_CG_POST_COMMENT: return 1; case GUILD_SUBHEADER_CG_DELETE_COMMENT: return sizeof(DWORD); case GUILD_SUBHEADER_CG_REFRESH_COMMENT: return 0; case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GRADE: return sizeof(DWORD) + sizeof(BYTE); case GUILD_SUBHEADER_CG_USE_SKILL: return sizeof(TPacketCGGuildUseSkill); case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GENERAL: return sizeof(DWORD) + sizeof(BYTE); case GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER: return sizeof(DWORD) + sizeof(BYTE); } return 0; } int CInputMain::Guild(LPCHARACTER ch, const char * data, size_t uiBytes) { if (uiBytes < sizeof(TPacketCGGuild)) return -1; const TPacketCGGuild* p = reinterpret_cast(data); const char* c_pData = data + sizeof(TPacketCGGuild); uiBytes -= sizeof(TPacketCGGuild); const GUILD_SUBHEADER_CG SubHeader = static_cast(p->subheader); const size_t SubPacketLen = GetSubPacketSize(SubHeader); if (uiBytes < SubPacketLen) { return -1; } CGuild* pGuild = ch->GetGuild(); if (NULL == pGuild) { if (SubHeader != GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드에 속해있지 않습니다.")); return SubPacketLen; } } switch (SubHeader) { case GUILD_SUBHEADER_CG_DEPOSIT_MONEY: { // by mhh : 길드자금은 당분간 넣을 수 없다. return SubPacketLen; const int gold = MIN(*reinterpret_cast(c_pData), __deposit_limit()); if (gold < 0) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다.")); return SubPacketLen; } if (ch->GetGold() < gold) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 가지고 있는 돈이 부족합니다.")); return SubPacketLen; } pGuild->RequestDepositMoney(ch, gold); } return SubPacketLen; case GUILD_SUBHEADER_CG_WITHDRAW_MONEY: { // by mhh : 길드자금은 당분간 뺄 수 없다. return SubPacketLen; const int gold = MIN(*reinterpret_cast(c_pData), 500000); if (gold < 0) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 잘못된 금액입니다.")); return SubPacketLen; } pGuild->RequestWithdrawMoney(ch, gold); } return SubPacketLen; case GUILD_SUBHEADER_CG_ADD_MEMBER: { const DWORD vid = *reinterpret_cast(c_pData); LPCHARACTER newmember = CHARACTER_MANAGER::instance().Find(vid); if (!newmember) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다.")); return SubPacketLen; } // @fixme145 BEGIN (+newmember ispc check) if (!ch->IsPC() || !newmember->IsPC()) return SubPacketLen; // @fixme145 END #ifdef ENABLE_MESSENGER_BLOCK if (MessengerManager::instance().CheckMessengerList(ch->GetName(), newmember->GetName(), SYST_BLOCK)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("%s blokkk"), newmember->GetName()); return SubPacketLen; } #endif pGuild->Invite(ch, newmember); } return SubPacketLen; case GUILD_SUBHEADER_CG_REMOVE_MEMBER: { if (pGuild->UnderAnyWar() != 0) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드전 중에는 길드원을 탈퇴시킬 수 없습니다.")); return SubPacketLen; } const DWORD pid = *reinterpret_cast(c_pData); const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); if (NULL == m) return -1; LPCHARACTER member = CHARACTER_MANAGER::instance().FindByPID(pid); if (member) { if (member->GetGuild() != pGuild) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 상대방이 같은 길드가 아닙니다.")); return SubPacketLen; } if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다.")); return SubPacketLen; } member->SetQuestFlag("guild_manage.new_withdraw_time", get_global_time()); pGuild->RequestRemoveMember(member->GetPlayerID()); if (LC_IsBrazil() == true) { DBManager::instance().Query("REPLACE INTO guild_invite_limit VALUES(%d, %d)", pGuild->GetID(), get_global_time()); } } else { if (!pGuild->HasGradeAuth(m->grade, GUILD_AUTH_REMOVE_MEMBER)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시킬 권한이 없습니다.")); return SubPacketLen; } if (pGuild->RequestRemoveMember(pid)) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드원을 강제 탈퇴 시켰습니다.")); else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 그러한 사람을 찾을 수 없습니다.")); } } return SubPacketLen; case GUILD_SUBHEADER_CG_CHANGE_GRADE_NAME: { char gradename[GUILD_GRADE_NAME_MAX_LEN + 1]; strlcpy(gradename, c_pData + 1, sizeof(gradename)); const TGuildMember * m = pGuild->GetMember(ch->GetPlayerID()); if (NULL == m) return -1; if (m->grade != GUILD_LEADER_GRADE) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 이름을 변경할 권한이 없습니다.")); } else if (*c_pData == GUILD_LEADER_GRADE) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위 이름은 변경할 수 없습니다.")); } else if (!check_name(gradename)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 적합하지 않은 직위 이름 입니다.")); } else { pGuild->ChangeGradeName(*c_pData, gradename); } } return SubPacketLen; case GUILD_SUBHEADER_CG_CHANGE_GRADE_AUTHORITY: { const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); if (NULL == m) return -1; if (m->grade != GUILD_LEADER_GRADE) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위 권한을 변경할 권한이 없습니다.")); } else if (*c_pData == GUILD_LEADER_GRADE) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 권한은 변경할 수 없습니다.")); } else { pGuild->ChangeGradeAuth(*c_pData, *(c_pData + 1)); } } return SubPacketLen; case GUILD_SUBHEADER_CG_OFFER: { #ifdef ENABLE_BLOCK_EXP if (ch->IsBlockMode(BLOCK_POINT_EXP)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("exp_bloklu_hacim")); return SubPacketLen; } else; #endif DWORD offer = *reinterpret_cast(c_pData); if (pGuild->GetLevel() >= GUILD_MAX_LEVEL) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드가 이미 최고 레벨입니다.")); } else { offer /= 100; offer *= 100; if (pGuild->OfferExp(ch, offer)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> %u의 경험치를 투자하였습니다."), offer); } else { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 경험치 투자에 실패하였습니다.")); } } } return SubPacketLen; case GUILD_SUBHEADER_CG_CHARGE_GSP: { const int offer = *reinterpret_cast(c_pData); const int gold = offer * 100; if (offer < 0 || gold < offer || gold < 0 || ch->GetGold() < gold) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 돈이 부족합니다.")); return SubPacketLen; } if (!pGuild->ChargeSP(ch, offer)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 용신력 회복에 실패하였습니다.")); } } return SubPacketLen; case GUILD_SUBHEADER_CG_POST_COMMENT: { const size_t length = *c_pData; if (length > GUILD_COMMENT_MAX_LEN) { // 잘못된 길이.. 끊어주자. sys_err("POST_COMMENT: %s comment too long (length: %u)", ch->GetName(), length); ch->GetDesc()->SetPhase(PHASE_CLOSE); return -1; } if (uiBytes < 1 + length) return -1; const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); if (NULL == m) return -1; if (length && !pGuild->HasGradeAuth(m->grade, GUILD_AUTH_NOTICE) && *(c_pData + 1) == '!') { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 공지글을 작성할 권한이 없습니다.")); } else { std::string str(c_pData + 1, length); pGuild->AddComment(ch, str); } return (1 + length); } case GUILD_SUBHEADER_CG_DELETE_COMMENT: { const DWORD comment_id = *reinterpret_cast(c_pData); pGuild->DeleteComment(ch, comment_id); } return SubPacketLen; case GUILD_SUBHEADER_CG_REFRESH_COMMENT: pGuild->RefreshComment(ch); return SubPacketLen; case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GRADE: { const DWORD pid = *reinterpret_cast(c_pData); const BYTE grade = *(c_pData + sizeof(DWORD)); const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); if (NULL == m) return -1; if (m->grade != GUILD_LEADER_GRADE) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 직위를 변경할 권한이 없습니다.")); else if (ch->GetPlayerID() == pid) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장의 직위는 변경할 수 없습니다.")); else if (grade == 1) ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 길드장으로 직위를 변경할 수 없습니다.")); else pGuild->ChangeMemberGrade(pid, grade); } return SubPacketLen; case GUILD_SUBHEADER_CG_USE_SKILL: { const TPacketCGGuildUseSkill* p = reinterpret_cast(c_pData); pGuild->UseSkill(p->dwVnum, ch, p->dwPID); } return SubPacketLen; case GUILD_SUBHEADER_CG_CHANGE_MEMBER_GENERAL: { const DWORD pid = *reinterpret_cast(c_pData); const BYTE is_general = *(c_pData + sizeof(DWORD)); const TGuildMember* m = pGuild->GetMember(ch->GetPlayerID()); if (NULL == m) return -1; if (m->grade != GUILD_LEADER_GRADE) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 장군을 지정할 권한이 없습니다.")); } else { if (!pGuild->ChangeMemberGeneral(pid, is_general)) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("<길드> 더이상 장수를 지정할 수 없습니다.")); } } } return SubPacketLen; case GUILD_SUBHEADER_CG_GUILD_INVITE_ANSWER: { const DWORD guild_id = *reinterpret_cast(c_pData); const BYTE accept = *(c_pData + sizeof(DWORD)); CGuild * g = CGuildManager::instance().FindGuild(guild_id); if (g) { if (accept) g->InviteAccept(ch); else g->InviteDeny(ch->GetPlayerID()); } } return SubPacketLen; } return 0; } void CInputMain::Fishing(LPCHARACTER ch, const char* c_pData) { TPacketCGFishing* p = (TPacketCGFishing*)c_pData; ch->SetRotation(p->dir * 5); ch->fishing(); return; } void CInputMain::ItemGive(LPCHARACTER ch, const char* c_pData) { TPacketCGGiveItem* p = (TPacketCGGiveItem*) c_pData; LPCHARACTER to_ch = CHARACTER_MANAGER::instance().Find(p->dwTargetVID); if (to_ch) ch->GiveItem(to_ch, p->ItemPos); else ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("아이템을 건네줄 수 없습니다.")); } void CInputMain::Hack(LPCHARACTER ch, const char * c_pData) { TPacketCGHack * p = (TPacketCGHack *) c_pData; char buf[sizeof(p->szBuf)]; strlcpy(buf, p->szBuf, sizeof(buf)); sys_err("HACK_DETECT: %s %s", ch->GetName(), buf); ch->GetDesc()->SetPhase(PHASE_CLOSE); } int CInputMain::MyShop(LPCHARACTER ch, const char * c_pData, size_t uiBytes) { TPacketCGMyShop * p = (TPacketCGMyShop *) c_pData; int iExtraLen = p->bCount * sizeof(TShopItemTable); if (uiBytes < sizeof(TPacketCGMyShop) + iExtraLen) return -1; if (strstr(p->szSign, ("|c")) || strstr(p->szSign, ("|C"))) { LogManager::instance().HackLog("COLORFUL_SHOP", ch); return (iExtraLen); } if (ch->GetGold() >= GOLD_MAX) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("소유 돈이 20억냥을 넘어 거래를 핼수가 없습니다.")); sys_log(0, "MyShop ==> OverFlow Gold id %u name %s ", ch->GetPlayerID(), ch->GetName()); return (iExtraLen); } #ifdef ENABLE_CHEQUE_SYSTEM if (ch->GetCheque() >= CHEQUE_MAX) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("?? ?? 20??? ?? ??? ??? ????.")); sys_log(0, "MyShop ==> OverFlow Cheque id %u name %s ", ch->GetPlayerID(), ch->GetName()); return (iExtraLen); } #endif if (ch->IsStun() || ch->IsDead()) return (iExtraLen); #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->IsAttrTransferOpen() || ch->GetOfflineShopOwner()) #else if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->IsAttrTransferOpen()) #endif { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중일경우 개인상점을 열수가 없습니다.")); return (iExtraLen); } sys_log(0, "MyShop count %d", p->bCount); ch->OpenMyShop(p->szSign, (TShopItemTable *) (c_pData + sizeof(TPacketCGMyShop)), p->bCount); return (iExtraLen); } #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM int CInputMain::MyOfflineShop(LPCHARACTER ch, const char* c_pData, size_t uiBytes) { TPacketCGMyOfflineShop* p = (TPacketCGMyOfflineShop*)c_pData; int iExtraLen = p->bCount * sizeof(TOfflineShopItemTable); if (uiBytes < sizeof(TPacketCGMyOfflineShop) + iExtraLen) return -1; if (ch->IsStun() || ch->IsDead()) return (iExtraLen); if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->IsCubeOpen() || ch->GetOfflineShopOwner()) { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("다른 거래중일경우 개인상점을 열수가 없습니다.")); return (iExtraLen); } sys_log(0, "MyOfflineShop count %d", p->bCount); ch->OpenMyOfflineShop(p->szSign, (TOfflineShopItemTable*)(c_pData + sizeof(TPacketCGMyOfflineShop)), p->bCount, p->iTime, p->bNpcType); return (iExtraLen); } #endif #ifdef ENABLE_SHOW_CHEST_DROP void CInputMain::ChestDropInfo(LPCHARACTER ch, const char* c_pData) { TPacketCGChestDropInfo* p = (TPacketCGChestDropInfo*) c_pData; if(p->wInventoryCell >= INVENTORY_AND_EQUIP_SLOT_MAX) return; LPITEM pkItem = ch->GetInventoryItem(p->wInventoryCell); if (!pkItem) return; std::vector vec_ItemList; ITEM_MANAGER::instance().GetChestItemList(pkItem->GetVnum(), vec_ItemList); TPacketGCChestDropInfo packet; packet.bHeader = HEADER_GC_CHEST_DROP_INFO; packet.wSize = sizeof(packet) + sizeof(TChestDropInfoTable) * vec_ItemList.size(); packet.dwChestVnum = pkItem->GetVnum(); ch->GetDesc()->BufferedPacket(&packet, sizeof(packet)); ch->GetDesc()->Packet(&vec_ItemList[0], sizeof(TChestDropInfoTable) * vec_ItemList.size()); } #endif void CInputMain::Refine(LPCHARACTER ch, const char* c_pData) { const TPacketCGRefine* p = reinterpret_cast(c_pData); #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->GetMyShop() || ch->IsCubeOpen() || ch->IsAttrTransferOpen() || ch->GetOfflineShopOwner()) #else if (ch->GetExchange() || ch->IsOpenSafebox() || ch->GetShopOwner() || ch->GetMyShop() || ch->IsCubeOpen() || ch->IsAttrTransferOpen()) #endif { ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("창고,거래창등이 열린 상태에서는 개량을 할수가 없습니다")); ch->ClearRefineMode(); return; } if (p->type == 255) { // DoRefine Cancel ch->ClearRefineMode(); return; } #ifdef ENABLE_EXTEND_INVEN_SYSTEM if (p->pos >= (unsigned int)(ch->GetExtendInvenMax())) #else if (p->pos >= INVENTORY_MAX_NUM) #endif { ch->ClearRefineMode(); return; } LPITEM item = ch->GetInventoryItem(p->pos); if (!item) { ch->ClearRefineMode(); return; } #ifdef ENABLE_SOULBIND_SYSTEM if (item->IsBind() || item->IsUntilBind()) { ch->ClearRefineMode(); ch->ChatPacket(CHAT_TYPE_INFO, LC_TEXT("ruha_bagli_nesneyi_yukseltemezsin")); return; } #endif ch->SetRefineTime(); if (p->type == REFINE_TYPE_NORMAL) { sys_log (0, "refine_type_noraml"); ch->DoRefine(item); } else if (p->type == REFINE_TYPE_SCROLL || p->type == REFINE_TYPE_HYUNIRON || p->type == REFINE_TYPE_MUSIN || p->type == REFINE_TYPE_BDRAGON #ifdef ENABLE_RITUALS_SCROLL || p->type == REFINE_TYPE_RITUALS_SCROLL #endif #ifdef ENABLE_ANCIENT_METAL || p->type == REFINE_TYPE_ANCIENT_METAL #endif #ifdef ENABLE_SOUL_SYSTEM || p->type == REFINE_TYPE_SOUL_EVOLVE || p->type == REFINE_TYPE_SOUL_AWAKE #endif ) { sys_log (0, "refine_type_scroll, ..."); ch->DoRefineWithScroll(item); } else if (p->type == REFINE_TYPE_MONEY_ONLY) { const LPITEM item = ch->GetInventoryItem(p->pos); if (NULL != item) { if (500 <= item->GetRefineSet()) { LogManager::instance().HackLog("DEVIL_TOWER_REFINE_HACK", ch); } else { if (ch->GetQuestFlag("deviltower_zone.can_refine")) { if (ch->DoRefine(item, true)) { ch->SetQuestFlag("deviltower_zone.can_refine", 0); } } else { ch->ChatPacket(CHAT_TYPE_INFO, "사귀 타워 완료 보상은 한번까지 사용가능합니다."); } } } } ch->ClearRefineMode(); } #ifdef ENABLE_SASH_SYSTEM void CInputMain::Sash(LPCHARACTER pkChar, const char* c_pData) { quest::PC * pPC = quest::CQuestManager::instance().GetPCForce(pkChar->GetPlayerID()); if (pPC->IsRunning()) return; TPacketSash * sPacket = (TPacketSash*) c_pData; switch (sPacket->subheader) { case SASH_SUBHEADER_CG_CLOSE: { pkChar->CloseSash(); } break; case SASH_SUBHEADER_CG_ADD: { pkChar->AddSashMaterial(sPacket->tPos, sPacket->bPos); } break; case SASH_SUBHEADER_CG_REMOVE: { pkChar->RemoveSashMaterial(sPacket->bPos); } break; case SASH_SUBHEADER_CG_REFINE: { pkChar->RefineSashMaterials(); } break; default: break; } } #endif #ifdef ENABLE_MAIL_BOX_SYSTEM void CInputMain::SendMail(LPCHARACTER ch, const char * c_pData) { TPacketCGMailBox* p = (TPacketCGMailBox*) c_pData; if (!ch) return; LPITEM pkItem = ch->GetItem(p->item_pos); DWORD dwGold = p->dwGold; WORD wCheque = p->wCheque; if (pkItem) ch->SendMail(p->szName, p->szTitle, p->szPost, dwGold, wCheque, pkItem); else ch->SendMail(p->szName, p->szTitle, p->szPost, dwGold, wCheque, NULL); } #endif #ifdef ENABLE_CHANGELOOK_SYSTEM void CInputMain::ChangeLook(LPCHARACTER pkChar, const char* c_pData) { quest::PC * pPC = quest::CQuestManager::instance().GetPCForce(pkChar->GetPlayerID()); if (pPC->IsRunning()) return; TPacketChangeLook * sPacket = (TPacketChangeLook*) c_pData; switch (sPacket->subheader) { case CL_SUBHEADER_CLOSE: { pkChar->ChangeLookWindow(false); } break; case CL_SUBHEADER_ADD: { pkChar->AddClMaterial(sPacket->tPos, sPacket->bPos); } break; case CL_SUBHEADER_REMOVE: { pkChar->RemoveClMaterial(sPacket->bPos); } break; case CL_SUBHEADER_REFINE: { pkChar->RefineClMaterials(); } break; default: break; } } #endif #ifdef ENABLE_AURA_SYSTEM void CInputMain::Aura(LPCHARACTER pkChar, const char* c_pData) { quest::PC* pPC = quest::CQuestManager::instance().GetPCForce(pkChar->GetPlayerID()); if (pPC->IsRunning()) return; TPacketAura* sPacket = (TPacketAura*)c_pData; switch (sPacket->subheader) { case AURA_SUBHEADER_CG_CLOSE: { pkChar->CloseAura(); } break; case AURA_SUBHEADER_CG_ADD: { pkChar->AddAuraMaterial(sPacket->tPos, sPacket->bPos); } break; case AURA_SUBHEADER_CG_REMOVE: { pkChar->RemoveAuraMaterial(sPacket->bPos); } break; case AURA_SUBHEADER_CG_REFINE: { pkChar->RefineAuraMaterials(); } break; default: break; } } #endif #ifdef ENABLE_CUBE_RENEWAL void CInputMain::CubeRenewalSend(LPCHARACTER ch, const char* data) { struct packet_send_cube_renewal * pinfo = (struct packet_send_cube_renewal *) data; switch (pinfo->subheader) { case CUBE_RENEWAL_SUB_HEADER_MAKE_ITEM: { int index_item = pinfo->index_item; int count_item = pinfo->count_item; int index_item_improve = pinfo->index_item_improve; Cube_Make(ch,index_item,count_item,index_item_improve); } break; case CUBE_RENEWAL_SUB_HEADER_CLOSE: { Cube_close(ch); } break; } } #endif #ifdef ENABLE_WON_EXCHANGE_WINDOW void CInputMain::WonExchange(LPCHARACTER ch, const char* pcData) { const TPacketCGWonExchange* p = reinterpret_cast(pcData); const EWonExchangeCGSubHeader SubHeader = static_cast(p->bSubHeader); switch (SubHeader) { case WON_EXCHANGE_CG_SUBHEADER_SELL: case WON_EXCHANGE_CG_SUBHEADER_BUY: ch->WonExchange(SubHeader, p->wValue); break; default: sys_err("invalid won exchange subheader: %u value: %u", SubHeader, p->wValue); break; } } #endif int CInputMain::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) { LPCHARACTER ch; if (!(ch = d->GetCharacter())) { sys_err("no character on desc"); d->SetPhase(PHASE_CLOSE); return (0); } int iExtraLen = 0; if (test_server && bHeader != HEADER_CG_MOVE) sys_log(0, "CInputMain::Analyze() ==> Header [%d] ", bHeader); if (ch->GetDesc()->GetPhase() != PHASE_GAME && ch->GetDesc()->GetPhase() != PHASE_DEAD) { sys_err("no character in game"); sys_log(0, "no character in game %u %u %u", ch->GetPlayerID(), ch->GetDesc()->GetPhase(), bHeader); d->SetPhase(PHASE_CLOSE); return (0); } switch (bHeader) { case HEADER_CG_PONG: Pong(d); break; case HEADER_CG_TIME_SYNC: Handshake(d, c_pData); break; case HEADER_CG_CHAT: if (test_server) { char* pBuf = (char*)c_pData; sys_log(0, "%s", pBuf + sizeof(TPacketCGChat)); } if ((iExtraLen = Chat(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_WHISPER: if ((iExtraLen = Whisper(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_MOVE: Move(ch, c_pData); if (LC_IsEurope()) { if (g_bCheckClientVersion) { int version = atoi(g_stClientVersion.c_str()); int date = atoi(d->GetClientVersion()); //if (0 != g_stClientVersion.compare(d->GetClientVersion())) if (version != date) { ch->ChatPacket(CHAT_TYPE_NOTICE, LC_TEXT("클라이언트 버전이 틀려 로그아웃 됩니다. 정상적으로 패치 후 접속하세요.")); // d->DelayedDisconnect(10); LogManager::instance().HackLog("VERSION_CONFLICT", d->GetAccountTable().login, ch->GetName(), d->GetHostName()); } } } else { if (!*d->GetClientVersion()) { sys_err("Version not recieved name %s", ch->GetName()); d->SetPhase(PHASE_CLOSE); } } break; case HEADER_CG_CHARACTER_POSITION: Position(ch, c_pData); break; case HEADER_CG_ITEM_USE: if (!ch->IsObserverMode()) ItemUse(ch, c_pData); break; case HEADER_CG_ITEM_DROP: if (!ch->IsObserverMode()) { ItemDrop(ch, c_pData); } break; case HEADER_CG_ITEM_DROP2: if (!ch->IsObserverMode()) ItemDrop2(ch, c_pData); break; case HEADER_CG_ITEM_SELL: if (!ch->IsObserverMode()) ItemSell(ch, c_pData); break; case HEADER_CG_ITEM_MOVE: if (!ch->IsObserverMode()) ItemMove(ch, c_pData); break; case HEADER_CG_ITEM_PICKUP: if (!ch->IsObserverMode()) ItemPickup(ch, c_pData); break; case HEADER_CG_ITEM_USE_TO_ITEM: if (!ch->IsObserverMode()) ItemToItem(ch, c_pData); break; case HEADER_CG_ITEM_GIVE: if (!ch->IsObserverMode()) ItemGive(ch, c_pData); break; case HEADER_CG_EXCHANGE: if (!ch->IsObserverMode()) Exchange(ch, c_pData); break; case HEADER_CG_ATTACK: case HEADER_CG_SHOOT: if (!ch->IsObserverMode()) { Attack(ch, bHeader, c_pData); } break; case HEADER_CG_USE_SKILL: if(!ch || ch == NULL) break; if(!c_pData || c_pData == NULL) break; if (!ch->IsObserverMode()) UseSkill(ch, c_pData); break; case HEADER_CG_QUICKSLOT_ADD: QuickslotAdd(ch, c_pData); break; case HEADER_CG_QUICKSLOT_DEL: QuickslotDelete(ch, c_pData); break; case HEADER_CG_QUICKSLOT_SWAP: QuickslotSwap(ch, c_pData); break; case HEADER_CG_SHOP: if ((iExtraLen = Shop(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_FISH_EVENT_SEND: if ((iExtraLen = FishEvent(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_MESSENGER: if ((iExtraLen = Messenger(ch, c_pData, m_iBufferLeft))<0) return -1; break; case HEADER_CG_ON_CLICK: OnClick(ch, c_pData); break; case HEADER_CG_SYNC_POSITION: if ((iExtraLen = SyncPosition(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_ADD_FLY_TARGETING: case HEADER_CG_FLY_TARGETING: FlyTarget(ch, c_pData, bHeader); break; case HEADER_CG_SCRIPT_BUTTON: ScriptButton(ch, c_pData); break; // SCRIPT_SELECT_ITEM case HEADER_CG_SCRIPT_SELECT_ITEM: ScriptSelectItem(ch, c_pData); break; // END_OF_SCRIPT_SELECT_ITEM case HEADER_CG_SCRIPT_ANSWER: ScriptAnswer(ch, c_pData); break; case HEADER_CG_QUEST_INPUT_STRING: QuestInputString(ch, c_pData); break; case HEADER_CG_QUEST_CONFIRM: QuestConfirm(ch, c_pData); break; case HEADER_CG_TARGET: Target(ch, c_pData); break; case HEADER_CG_WARP: Warp(ch, c_pData); break; case HEADER_CG_SAFEBOX_CHECKIN: SafeboxCheckin(ch, c_pData); break; case HEADER_CG_SAFEBOX_CHECKOUT: SafeboxCheckout(ch, c_pData, false); break; case HEADER_CG_SAFEBOX_ITEM_MOVE: SafeboxItemMove(ch, c_pData); break; case HEADER_CG_MALL_CHECKOUT: SafeboxCheckout(ch, c_pData, true); break; case HEADER_CG_PARTY_INVITE: PartyInvite(ch, c_pData); break; case HEADER_CG_PARTY_REMOVE: PartyRemove(ch, c_pData); break; case HEADER_CG_PARTY_INVITE_ANSWER: PartyInviteAnswer(ch, c_pData); break; case HEADER_CG_PARTY_SET_STATE: PartySetState(ch, c_pData); break; case HEADER_CG_PARTY_USE_SKILL: if(!ch || ch == NULL) break; if(!c_pData || c_pData == NULL) break; PartyUseSkill(ch, c_pData); break; case HEADER_CG_PARTY_PARAMETER: PartyParameter(ch, c_pData); break; case HEADER_CG_ANSWER_MAKE_GUILD: AnswerMakeGuild(ch, c_pData); break; case HEADER_CG_GUILD: if ((iExtraLen = Guild(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_FISHING: Fishing(ch, c_pData); break; case HEADER_CG_HACK: Hack(ch, c_pData); break; case HEADER_CG_MYSHOP: if ((iExtraLen = MyShop(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_REFINE: Refine(ch, c_pData); break; case HEADER_CG_CLIENT_VERSION: Version(ch, c_pData); break; #ifdef ENABLE_SOUL_ROULETTE_SYSTEM case HEADER_CG_SOUL_ROULETTE: if (!ch->IsObserverMode()) SoulRoulette(ch, c_pData); break; #endif #ifdef ENABLE_RENEW_MESSENGER_WHISPER case HEADER_CG_CONTACT_PROFILE_MANAGER: CProfileManager::instance().Manager(ch, c_pData); break; #endif #ifdef ENABLE_BATTLE_PASS case HEADER_CG_BATTLE_PASS: if ((iExtraLen = BattlePass(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; #endif #ifdef ENABLE_NEW_PET_SYSTEM case HEADER_CG_PetSetName: BraveRequestPetName(ch, c_pData); break; #endif #ifdef ENABLE_DELETE_ITEMS_SYSTEM case HEADER_CG_ITEM_DESTROY: if (!ch->IsObserverMode()) ItemDestroy(ch, c_pData); break; #endif #ifdef ENABLE_OX_RENEWAL case HEADER_CG_QUEST_INPUT_LONG_STRING: QuestInputLongString(ch, c_pData); break; #endif #ifdef ENABLE_SEND_TARGET_INFO case HEADER_CG_TARGET_INFO_LOAD: { TargetInfoLoad(ch, c_pData); } break; #endif #ifdef ENABLE_WHISPER_ADMIN_SYSTEM case HEADER_CG_WHISPER_ADMIN: CWhisperAdmin::instance().Manager(ch, c_pData); break; #endif #ifdef ENABLE_ATTR_6TH_7TH_SYSTEM case HEADER_CG_ATTR67_ADD: Attr67Add(ch, c_pData); break; #endif #ifdef ENABLE_ADMIN_BAN_MANAGER case HEADER_CG_ADMIN_BAN_MANAGER: SendAdminBanManager(ch, c_pData); break; #endif #ifdef ENABLE_SHOW_CHEST_DROP case HEADER_CG_CHEST_DROP_INFO: ChestDropInfo(ch, c_pData); break; #endif #if defined(ENABLE_COMBAT_ZONE) case HEADER_CG_COMBAT_ZONE_REQUEST_ACTION: CCombatZoneManager::instance().RequestAction(ch, c_pData); break; #endif #ifdef ENABLE_CUBE_RENEWAL case HEADER_CG_CUBE_RENEWAL: CubeRenewalSend(ch, c_pData); break; #endif #ifdef ENABLE_SASH_SYSTEM case HEADER_CG_SASH: { Sash(ch, c_pData); } break; #endif #ifdef ENABLE_EXTEND_INVEN_SYSTEM case HEADER_CG_EXTEND_INVENTORY: if (!ch->IsObserverMode()) ExInventory(ch, c_pData); break; #endif #ifdef ENABLE_CHANGELOOK_SYSTEM case HEADER_CG_CL: { ChangeLook(ch, c_pData); } break; #endif #ifdef ENABLE_MINI_GAME_CATCH_KING case HEADER_CG_MINI_GAME_CATCH_KING: if ((iExtraLen = CMiniGame::instance().MiniGameCatchKing(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; #endif #ifdef ENABLE_OFFLINE_PRIVATE_SHOP_SYSTEM case HEADER_CG_OFFLINE_SHOP: if ((iExtraLen = OfflineShop(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_MY_OFFLINE_SHOP: if ((iExtraLen = MyOfflineShop(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; #endif #ifdef ENABLE_PRIVATE_SHOP_SEARCH_SYSTEM case HEADER_CG_SHOP_SEARCH: if (!ch->IsObserverMode()) ShopSearch(ch, c_pData, false); break; case HEADER_CG_SHOP_SEARCH_SUB: if (!ch->IsObserverMode()) ShopSearch(ch, c_pData, true); break; case HEADER_CG_SHOP_SEARCH_BUY: if (!ch->IsObserverMode()) ShopSearchBuy(ch, c_pData); break; #endif #ifdef ENABLE_WON_EXCHANGE_WINDOW case HEADER_CG_WON_EXCHANGE: WonExchange(ch, c_pData); break; #endif #ifdef ENABLE_ATTENDANCE_EVENT case HEADER_CG_ATTENDANCE_REWARD: CMiniGame::instance().AttendanceEventRequestReward(ch); break; #endif #ifdef ENABLE_MAIL_BOX_SYSTEM case HEADER_CG_SEND_MAIL: SendMail(ch, c_pData); break; #endif #ifdef ENABLE_AURA_SYSTEM case HEADER_CG_AURA: Aura(ch, c_pData); break; #endif case HEADER_CG_DRAGON_SOUL_REFINE: { TPacketCGDragonSoulRefine* p = reinterpret_cast ((void*)c_pData); switch(p->bSubType) { case DS_SUB_HEADER_CLOSE: ch->DragonSoul_RefineWindow_Close(); break; case DS_SUB_HEADER_DO_REFINE_GRADE: { DSManager::instance().DoRefineGrade(ch, p->ItemGrid); } break; case DS_SUB_HEADER_DO_REFINE_STEP: { DSManager::instance().DoRefineStep(ch, p->ItemGrid); } break; case DS_SUB_HEADER_DO_REFINE_STRENGTH: { DSManager::instance().DoRefineStrength(ch, p->ItemGrid); } break; } } break; #ifdef ENABLE_SWITCHBOT case HEADER_CG_SWITCHBOT: if ((iExtraLen = Switchbot(ch, c_pData, m_iBufferLeft)) < 0) { return -1; } break; #endif } return (iExtraLen); } int CInputDead::Analyze(LPDESC d, BYTE bHeader, const char * c_pData) { LPCHARACTER ch; if (!(ch = d->GetCharacter())) { sys_err("no character on desc"); return 0; } int iExtraLen = 0; switch (bHeader) { case HEADER_CG_PONG: Pong(d); break; case HEADER_CG_TIME_SYNC: Handshake(d, c_pData); break; case HEADER_CG_CHAT: if ((iExtraLen = Chat(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_WHISPER: if ((iExtraLen = Whisper(ch, c_pData, m_iBufferLeft)) < 0) return -1; break; case HEADER_CG_HACK: Hack(ch, c_pData); break; default: return (0); } return (iExtraLen); } #ifdef ENABLE_SWITCHBOT int CInputMain::Switchbot(LPCHARACTER ch, const char* data, size_t uiBytes) { const TPacketCGSwitchbot* p = reinterpret_cast(data); if (uiBytes < sizeof(TPacketCGSwitchbot)) { return -1; } const char* c_pData = data + sizeof(TPacketCGSwitchbot); uiBytes -= sizeof(TPacketCGSwitchbot); switch (p->subheader) { case SUBHEADER_CG_SWITCHBOT_START: { size_t extraLen = sizeof(TSwitchbotAttributeAlternativeTable) * SWITCHBOT_ALTERNATIVE_COUNT; if (uiBytes < extraLen) { return -1; } std::vector vec_alternatives; for (BYTE alternative = 0; alternative < SWITCHBOT_ALTERNATIVE_COUNT; ++alternative) { const TSwitchbotAttributeAlternativeTable* pAttr = reinterpret_cast(c_pData); c_pData += sizeof(TSwitchbotAttributeAlternativeTable); vec_alternatives.emplace_back(*pAttr); } CSwitchbotManager::Instance().Start(ch->GetPlayerID(), p->slot, vec_alternatives); return extraLen; } case SUBHEADER_CG_SWITCHBOT_STOP: { CSwitchbotManager::Instance().Stop(ch->GetPlayerID(), p->slot); return 0; } } return 0; } #endif