Jump to content

Mário.

Members
  • Posts

    82
  • Joined

  • Days Won

    1

Mário. last won the day on March 24

Mário. had the most liked content!

Recent Profile Visitors

5,995 profile views

Mário.'s Achievements

Newbie

Newbie (1/14)

224

Reputation

  1. error: 'struct TItemPriceInfo' has no member named 'dwCheque' error: 'const struct SItemPriceInfo' has no member named 'dwCheque' common/tables.h Procura por: typedef struct SItemPriceInfo { DWORD dwVnum; ///< ¾ÆÀÌÅÛ vnum DWORD dwPrice; ///< °¡°Ý } TItemPriceInfo; Substitui por: typedef struct SItemPriceInfo { DWORD dwVnum; ///< ¾ÆÀÌÅÛ vnum DWORD dwPrice; ///< °¡°Ý DWORD dwCheque; /// ENABLE_CHEQUE_SYSTEM } TItemPriceInfo; 3688: error: duplicate case value 3570: error: previously used here char.cpp Na linha 3688, existe um case que já foi definido acima na linha 3570: // exemplo: case TLTHINGS: // linha 3570 ação; break; case TLTHINGS: // linha 3688 ação; break; Remove o último case e estará resolvido.
  2. 1º Tens que fornecer o sistema para estarmos a par de qual o erro, não somos bruxos para saber qual é a linha que está errada. 2º Se isso acontece ao teleportar, significa que sempre que a personagem altera/teleporta, os valores do gaya resetam, por isso vê o que se passa no input_main.cpp, se existe algum ch->SetGaya ou algo do gênero (o meu conhecimento desse sistema é 0, tens que fornecer o sistema no total para conseguirmos ajudar).
  3. Isso é algo bastante relativo, mas antes de começar com algo, deixa-me explicar-te a diferença entre um backdoor e um exploit no cenário do Metin2. Um backdoor dá-se quando um pedaço de código é deixado propositadamente na source para o criador/malfeitor tomar proveito do mesmo Um exploit é quando um pedaço de código está mal feito/otimizado, permitindo que qualquer pessoa possa tomar proveito do mesmo Agora, respondendo a tua dúvida, em termos de backdoor é muito comum estar presente nos cmd_general.cpp | cmd_gm.cpp | cmd.cpp, com comandos como a que tu disseste "/twix /byebye /full_item, etc." MAS não podemos excluir a complexidade da mesma. Ele poderá ter posto, por exemplo, ao iniciar com o nome "ABC", enviar uma mensagem com os dados do servidor, por isso nada melhor que perderes um dia e analisares todos os ficheiros e vê se vês algo de suspeito. OBS: Confirma no cmd.cpp os poderes de certos comandos, poderá existir algum comando como "/full_set /shutdown /n" com GM_PLAYER. O de exploit, toma especialmente atento a funções/comandos que utilizam queries diretamente. Poderão conseguir utilizar comandos como "DROP" para prejudicar o teu servidor.
  4. Retire a parte onde diz if (ModoBatalha) bPKMode = PK_MODE_BATALHA; else e diga-me se resolveu. Isso é um novo modo que não está presente no cliente.
  5. Muito provavelmente o erro está no source do game. Se nesse mapa não consegues mudar o modo pvp, é porque algo não o permite. Mostra-nos a parte completa disto, que está no char_battle.cpp: void CHARACTER::SetPKMode(BYTE bPKMode) { if (bPKMode >= PK_MODE_MAX_NUM) return; if (m_bPKMode == bPKMode) return; if (bPKMode == PK_MODE_GUILD && !GetGuild()) bPKMode = PK_MODE_FREE; m_bPKMode = bPKMode; UpdatePacket(); sys_log(0, "PK_MODE: %s %d", GetName(), m_bPKMode); } Vê se o teu está desta forma. Se não estiver, utiliza, compila e diz-nos o resultado.
  6. Utilize uma das três: mob_proto.sql <- Estrutura oficial datada a 03/02/2018 | Não contêm nenhuma informação [5 kb] mob_proto_.sql <- Estrutura oficial datada a 03/02/2018 | Contém todo o mob_proto oficial [751 kb] mob_proto.txt <- Estrutura oficial em txt datada a 03/02/2018 [352 kb]
  7. Procura por: PACK * Adiciona depois: metin2_patch_6th_armor pack/ metin2_patch_monster_card pack/ Em primeiro lugar é o nome do ficheiro seguidamente pelo diretório da pasta.
  8. messenger_manager.cpp: void MessengerManager::Login(MessengerManager::keyA account) { if (m_set_loginAccount.find(account) != m_set_loginAccount.end()) return; DBManager::instance().FuncQuery(std::bind1st(std::mem_fun(&MessengerManager::LoadList), this), "SELECT account, companion FROM messenger_list%s WHERE account='%s'", get_table_postfix(), __account); #ifdef ENABLE_MESSENGER_TEAM DBManager::instance().FuncQuery(std::bind1st(std::mem_fun(&MessengerManager::LoadTeamList), this), "SELECT '%s' as account, mName as companion FROM common.gmlist", account.c_str()); #endif m_set_loginAccount.insert(account); } #ifdef ENABLE_MESSENGER_TEAM void MessengerManager::LoadTeamList(SQLMsg * msg) { if (NULL == msg or NULL == msg->Get() or msg->Get()->uiNumRows == 0) return; std::string account; for (uint i = 0; i < msg->Get()->uiNumRows; ++i) { MYSQL_ROW row = mysql_fetch_row(msg->Get()->pSQLResult); if (row[0] && row[1]) { if (account.length() == 0) account = row[0]; m_TeamRelation[row[0]].insert(row[1]); m_InverseTeamRelation[row[1]].insert(row[0]); } } SendTeamList(account); std::set<MessengerManager::keyT>::iterator it; for (it = m_InverseTeamRelation[account].begin(); it != m_InverseTeamRelation[account].end(); ++it) SendTeamLogin(*it, account); } void MessengerManager::SendTeamList(MessengerManager::keyA account) { LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str()); if (!ch) return; LPDESC d = ch->GetDesc(); if (!d) return; TPacketGCMessenger pack; pack.header = HEADER_GC_MESSENGER; pack.subheader = MESSENGER_SUBHEADER_GC_TEAM_LIST; pack.size = sizeof(TPacketGCMessenger); TPacketGCMessengerTeamListOffline pack_offline; TPacketGCMessengerTeamListOnline pack_online; TEMP_BUFFER buf(128 * 1024); itertype(m_TeamRelation[account]) it = m_TeamRelation[account].begin(), eit = m_TeamRelation[account].end(); while (it != eit) { if (m_set_loginAccount.find(*it) != m_set_loginAccount.end()) { pack_online.connected = 1; pack_online.length = it->size(); buf.write(&pack_online, sizeof(TPacketGCMessengerTeamListOnline)); buf.write(it->c_str(), it->size()); } else { pack_offline.connected = 0; pack_offline.length = it->size(); buf.write(&pack_offline, sizeof(TPacketGCMessengerTeamListOffline)); buf.write(it->c_str(), it->size()); } ++it; } pack.size += buf.size(); d->BufferedPacket(&pack, sizeof(TPacketGCMessenger)); d->Packet(buf.read_peek(), buf.size()); } void MessengerManager::SendTeamLogin(MessengerManager::keyA account, MessengerManager::keyA companion) { LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str()); LPDESC d = ch ? ch->GetDesc() : NULL; if (!d) return; if (!d->GetCharacter()) return; BYTE bLen = companion.size(); TPacketGCMessenger pack; pack.header = HEADER_GC_MESSENGER; pack.subheader = MESSENGER_SUBHEADER_GC_TEAM_LOGIN; pack.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + bLen; d->BufferedPacket(&pack, sizeof(TPacketGCMessenger)); d->BufferedPacket(&bLen, sizeof(BYTE)); d->Packet(companion.c_str(), companion.size()); } void MessengerManager::SendTeamLogout(MessengerManager::keyA account, MessengerManager::keyA companion) { if (!companion.size()) return; LPCHARACTER ch = CHARACTER_MANAGER::instance().FindPC(account.c_str()); LPDESC d = ch ? ch->GetDesc() : NULL; if (!d) return; BYTE bLen = companion.size(); TPacketGCMessenger pack; pack.header = HEADER_GC_MESSENGER; pack.subheader = MESSENGER_SUBHEADER_GC_TEAM_LOGOUT; pack.size = sizeof(TPacketGCMessenger) + sizeof(BYTE) + bLen; d->BufferedPacket(&pack, sizeof(TPacketGCMessenger)); d->BufferedPacket(&bLen, sizeof(BYTE)); d->Packet(companion.c_str(), companion.size()); } #endif void MessengerManager::Logout(MessengerManager::keyA account) { if (m_set_loginAccount.find(account) == m_set_loginAccount.end()) return; m_set_loginAccount.erase(account); std::set<MessengerManager::keyT>::iterator it; for (it = m_InverseRelation[account].begin(); it != m_InverseRelation[account].end(); ++it) { SendLogout(*it, account); } std::map<keyT, std::set<keyT> >::iterator it2 = m_Relation.begin(); while (it2 != m_Relation.end()) { it2->second.erase(account); ++it2; } #ifdef ENABLE_MESSENGER_TEAM std::set<MessengerManager::keyT>::iterator it5; for (it5 = m_InverseTeamRelation[account].begin(); it5 != m_InverseTeamRelation[account].end(); ++it5) { SendTeamLogout(*it5, account); } std::map<keyT, std::set<keyT> >::iterator it6 = m_TeamRelation.begin(); while (it6 != m_TeamRelation.end()) { it6->second.erase(account); ++it6; } m_TeamRelation.erase(account); #endif m_Relation.erase(account); //m_map_stMobile.erase(account); }
  9. Quem puder testar que dê feedback pls: questlua_global.cpp: int _set_quest_state_other (lua_State* L) { if (!lua_isstring(L, 1) || !lua_isstring(L, 2) || !lua_isstring(L, 3)) return 0; CQuestManager& q = CQuestManager::instance(); PC* pPC = q.GetCurrentNPC(); QuestState * pqs = q.GetCurrentState(); const string stPlayerName(lua_tostring(L, 1)); if (L!=pqs->co) { luaL_error(L, "running thread != current thread???"); sys_log(0,"running thread != current thread???"); return -1; } if (pPC) { const string stQuestName(lua_tostring(L, 2)); const string stStateName(lua_tostring(L, 3)); if (pPC->GetPlayerName(stPlayerName)) { if ( test_server ) sys_log(0,"set_state %s %s ", stQuestName.c_str(), stStateName.c_str() ); if (pPC->GetCurrentQuestName() == stQuestName) { pqs->st = q.GetQuestStateIndex(pPC->GetCurrentQuestName(), lua_tostring(L, -1)); pPC->SetCurrentQuestStateName(lua_tostring(L,-1)); } else { pPC->SetQuestState(stQuestName, stStateName); } } } return 0; } { "set_quest_state_other", _set_quest_state_other }, questpc.h: // Procurar por: const string & GetCurrentQuestName() const; // Adicionar abaixo: const string & GetPlayerName() const; questluapc.cpp: const string & PC::GetPlayerName() const char * name { LPCHARACTER npc = CHARACTER_MANAGER::instance().FindPC(name); return npc->GetName(); } questmanager.h: // Procurar por: LPCHARACTER m_pCurrentNPCCharacter; // Substituir por: PC* m_pCurrentNPCCharacter; // Procurar por: PC * GetCurrentPC() { return m_pCurrentPC; } // Adicionar abaixo: PC * GetCurrentNPC() { return m_pCurrentNPCCharacter; } A utilização dele é como o @Tierri Lopes disse: set_quest_state_other("Tierri", "quest_test", "run") -- Nome do jogador | quest | state
  10. https://metin2dev.org/board/index.php?/topic/11941-small-release-blocking-ip-address-to-killings/
  11. Obrigado, fiz a quest à pressa e nem reparei nisso E sim, tens razão, será melhor utilizar um ficheiro externo: when login begin a = io.open(get_locale_base_path().."/admin_whisper.txt", "r") this = a:read() cmdchat(string.format("admin_whisper %s %s",this,this)) end Desta forma ficaria o ficheiro ficaria: mário paci Resultado: O @Marco e o Daryl (GalaxyMT2) deram a ideia da mensagem ser enviada de X a X tempos de acordo com a hora que eles queriam, então para isso é só utilizar esta quest: quest admin_whisper begin state start begin when login begin -- Desta forma, todas as segundas e terças às 15:30, será enviado um PM a cada jogador online durante esse tempo local data = {"Monday 15:30","Tuesday 15:30"} for index, datetime in ipairs(data) do if datetime == os.date("%A %H:%M") then if game.get_event_flag("admin_whisper") == 1 then cmdchat(string.format("admin_whisper %s %s",whisper.admin,whisper.text)) end end end end end end
  12. Em baixo estão cerca 9 quests totalmente otimizados para droparem itens do biólogo em jogador. Alguns extras: Tem verificação vs IP (Jogadores com o mesmo IP não irão dropar itens); Com um pet, terão mais possibilidade de droparem ou não o item; As quests estão interligadas uma com a outra, ou seja, assim que acabam uma missão a outra é logo ativada (se tiverem o nível requerido); Possibilidade de saberem vários detalhes de cada morte (logs): O jogador, o adversário, em que canal, em qual missão e a hora; Se o jogador matar a mesma pessoa 5x, a mesma é posta a parte para ser analisado pela equipa. Estes dois últimos têm como o nome biólogo e biólogo_farm Se algum jogador aparecer no biólogo_farm é porque o mesmo matou mais que 5x a mesma pessoa. Com o biólogo, analisas se é farm ou não (pelas horas/minutos/segundos) e depois apagas o nome da pessoa nessa tabela, foi desta forma que eu fiz no pvp e correu-me bastante bem. Está tudo identificado de forma a conseguires entender o que cada coisa significa: sistema.biologo.lv75_inicial = 75 -- Nível inicial para começarem a missão sistema.biologo.lv75_item = 30006 -- item que será dropado assim que matarem os jogadores [a base de probabilidade, linha 67] sistema.biologo.lv75_quantidade = 1 -- quantidade do item a ser dado. sistema.biologo.lv75_minquantidade = 1 -- mínimo de quantidade para poderem entregar o item [recomendado 1, visto que poderão entregar sempre, desde que o tenham] sistema.biologo.lv75_maxquantidade = 15 -- quantidade máxima que precisam de ter para aparecer o aviso de onde terão que voltar para o biólogo sistema.biologo.lv75_pet = 34001 -- ID do pet que dará mais % no biólogo sistema.biologo.lv75_percentagem = 20 -- percentagem sem pet sistema.biologo.lv75_percentagempet = 50 -- percentagem se possuirem determinado pet Alguns avisos: É necessário ter pc.get_ip e npc.get_ip implementados; É necessário adicionar dofile(get_locale_base_path().."/quest/sistema.lua") no questlib.lua; É necessário colocar o sistema.lua na pasta /quest. Recomendo apenas a mexeres nas quests principais somente para alterar os bónus sistema biologo.rar
  13. Antes de começar com o tópico, se esperam algo complexo deste sistema, então poderão voltar para trás porque isto foi em apenas 1 hora de trabalho. Têm todo o direito de melhorar isto à vontade. Bem, eu ando a fazer alguns testes no que toca a performance entre quest-client e game-client e sendo sincero, quase ou pouco noto a diferença (já deu para entender que sou fanboy de lua certo?), apenas há 1 ~ 3 comandos extras a serem feitos. O que é este sistema? Isto dá-se como o nome de Admin Whisper (Mensagens de Equipa em português) e tem como objetivo enviar uma mensagem a todos os jogadores assim que entram pela primeira vez no jogo. Para que serve? Tal como disse acima, todos os jogadores (independentemente do canal - ou seja, poderão estar no CH1 como no CH2 -) irão receber sem qualquer tipo de problema ou latência. (Mensagem a ser enviada - No print não tem como ser visível mas ela pisca) (Conteúdo da mensagem) Requisitos: Python LUA Client Procurem (game.py) por: "PlayMusic" : self.__PlayMusic, Em baixo, adicionem: "admin_whisper" : self.AdminWhisper, Procurem por: def __PlayMusic(self, flag, filename): flag = int(flag) if flag: snd.FadeOutAllMusic() musicInfo.SaveLastPlayFieldMusic() snd.FadeInMusic("BGM/" + filename) else: snd.FadeOutAllMusic() musicInfo.LoadLastPlayFieldMusic() snd.FadeInMusic("BGM/" + musicInfo.fieldMusic) Por baixo adicionem: def AdminWhisper(self, admin, text): # Nome a ser chamado txt = str(text) # A mensagem em si show = txt.replace("_", " ") # Os _ são substituidos por espaço name = "|cFFFF8C00|H|h[%s]|h|r" % (admin) # Cor semelhante a de um Game Master + o nome proveniente do servidor chat.AppendWhisper(chat.WHISPER_TYPE_GM, name, show) # É enviado a mensagem com carácter GM self.interface.RecvWhisper(name) # É anúnciado da mesma forma que uma mensagem normal Adicionem isto no questlib.lua: dofile(get_locale_base_path().."/admin_whisper.lua") SERVER Criem no diretório do locale um ficheiro chamado admin_whisper.lua com isto lá dentro: --[[ De forma a que as mensagens tenham espaço uma da outra, é necessário utilizarem o uso da _ de forma a que o client consiga substituir. O motivo deve-se ao facto do comando cmdchat - ou CHAT_TYPE_COMMAND - ignorar tudo o que venha depois de um espaço (corrigem-me se estiver mal), por isso decidi que isto poderia ser a melhor forma disponível para que os espaços sejam visto visualmente. OBS: Repito, se queres algo complexo, podes usar isto como base ou simplesmente não usar, não obrigo ninguém a utiliza-lo. PS: Também poderão mandar mensagem a cada um dos jogadores de acordo com a sua linguagem (se tiverem multilinguagens instalado). ]] whisper = {} -- Abre a clásula para a palavra whisper whisper.admin = "MÁRIO" -- Nome do sistema a aparecer -- Mensagem a ser exibida | Se quiserem enviar mais que uma, poderão faze-lo perfeitamente dando alguns retoques no código whisper.text = "Olá_a_todos,_só_queria_dizer_que_este_´tutorial´_foi_criado_pelo_Mário_por_isso_se_quiserem_meter_os_créditos_quando_forem_meter_em_um_outro_sítio,_metam_os_meus_e_não_os_vossos_^^ " Utilizem a seguinte quest como um teste: quest admin_whisper begin state start begin when login begin if game.get_event_flag("admin_whisper) == 0 then return else cmdchat(string.format("admin_whisper %s %s",whisper.admin,whisper.text)) end end end end /e admin_whisper 1 - O sistema estará ativo e todos irão receber as mensagens /e admin_whisper 0 - O sistema estará desativo e ninguém irá receber as mensagens
  14. 1. Procura por (game.py): onPressKeyDict[app.DIK_X] = lambda : 2. Comenta/Apaga: #onPressKeyDict[app.DIK_X] = lambda : self.__OpenBonus() <- Isto é um exemplo, não é igual ao que tens 3. Procura por: (uitooltip.py): if isCostumeSash: 4. Substitui por: if itemVnum >= 85001 and itemVnum <= 85024: # São os IDs das faixas, se tens de outra forma, substitui
  15. O default encontra-se em inglês de momento. De momento utilizo a opção de reiniciar o cliente por motivos de estética até conseguir ter um código perfeitamente aceitável. - Utilizo somente alguns ficheiros para a parte /locale/country sendo que o resto fica no default que é o pt. A ideia do item_names e de meter nas opções é muito bem vinda mesmo, é algo que irei adaptar para o sistema. O locale_string foi totalmente complicado para mim mas deixo já um obrigado ao @Sil3nce por me ter salvado. Tens razão, a parte da quest não causa problemas nenhuns e torna-se super acessível para futuros usos.
×
×
  • Create New...