Jump to content
Close

Search the Community

Showing results for tags 'c++'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • Community
    • Rules
    • Portal
    • Resources
    • Commerce
    • Clubs
  • OTServers
    • Discussion
    • Support
    • Tutorial
    • Download
    • Code Development
    • Contests and Events
    • Form Team
    • Advertise your Server
  • Tibia and Bots
    • Discussion
  • Others
    • Playground (Off-topic)
    • Other Games
    • Advertising
    • Graphics and Design
    • Development and Programming
  • League of Legends's Geral
  • League of Legends's Suporte
  • Nto New Season's Tópicos
  • Fakes's Fakes
  • Tibia's Geral
  • Tibia's Notícias
  • Tibia's Media
  • Tibia's Life Thread
  • Computação's Geral
  • Computação's Dicas e Tutoriais
  • Computação's Suporte
  • Roleplaying's Roleplaying
  • Academia de Mapping's Quadro da Clopin
  • Academia de Mapping's Dev Area
  • Academia de Mapping's Quadro do Nolis
  • Academia de Mapping's Quadro do Namikaze
  • Styller's Tópicos

Calendars

  • Official Calendar
  • OTServs Calendar
  • Several Calendars

Product Groups

  • Advertisements in Top
  • Advertisements In Signatures
  • Advertisements in Topics
  • Others Advertisements

Categories

  • Sales Section
    • Scripting Sales
    • Codes Sales
    • Mapping Sales
    • Websites Sales
    • Design/Sprites Sales
    • Bots Sales
  • Look Jobs
  • Looking for Freelancers
  • Team Formation

Find results in...

Find results that contain...


Date Created

  • Start

    End


Last Updated

  • Start

    End


Filter by number of...

Joined

  • Start

    End


Group


Localization


My character


Favorite OTServ


Bot preferred


Interests

Found 62 results

  1. #Introdução Bom hoje estarei trazendo aqui o sistema de Ping feito pelo Mock, com uma pequena adaptação feita por mim para funcionar em TFS 0.4(talvez podendo funcionar em outras) Pois o que ele disponibilizou foi apenas para TFS 0.3.6 e nem foi muito utilizado pela comunidade. Muitos servidores daqui para download tem script no talk mas a lib está totalmente errada e não tem o code nas sources. Esse sistema tem varias utilizades, podendo usar o comando !ping para verificar seu ms ou até mesmo por para kikar jogadores com ms muito alto... Se você não sabe o cliente já tem um sistema de ping, e getOtsystime é como os.time () + os.clock (), você tem ano, mês, dia, hora, minutos, segundos, milisegundos... Enfim chega de enrolação e vamos lá! Code para TFS 0.4 e OTX: Code para TFS 0.3.6 LIB: Prontinho, agora seu servidor está pronto para utilizar as funções de Ping. Seja criativo! Ahh você é daqueles que quer tudo na mão né? Aqui vai um talkactions para ver o ping. Em talkactions/scripts crie um arquivo chamado playerping.lua, cole isto dentro: -- Script by Yan Liima(Night for tibiaking.com) function onSay(cid, words, param, channel) local ms = ping.CheckPing(cid) doPlayerSendTextMessage(cid,22,"Ping aproximado --> ["..ms.."].") return true end Em talkactions.xml <talkaction words="!ping" event="script" value="playerping.lua"/>
  2. Depois de milhões de anos sem programar porcaria nenhuma... Eu desenvolvi este sistema como um método de estudo. (C++) Este sistema foi inspirado no Auto Loot System por @psychonaut. (OTland) Criei o mesmo na versão mais recente do tfs. Auto Loot System for TFS 1.3 Como funciona? Simples, quando você mata um monstro e abre o corpo (você precisa clicar no corpo), os itens vão para o seu personagem. Instalando em actions.cpp, encontre: if (corpseOwner != 0 && !player->canOpenCorpse(corpseOwner)) { return RETURNVALUE_YOUARENOTTHEOWNER; } e mude isso para: if (corpseOwner != 0 && !player->canOpenCorpse(corpseOwner)) { return RETURNVALUE_YOUARENOTTHEOWNER; } else { if (player->canOpenCorpse(corpseOwner) && player->autoLootList.size() != 0) { if (player->getCapacity() > 100 * 100) { //Minimum of Capacity for autoloot works. (100 CAP) for (Item* item : container->getItemList()) { if (player->getItemFromAutoLoot(item->getID())) { std::ostringstream msgAutoLoot; msgAutoLoot << "You looted a " << item->getItemCount() << "x " << item->getName() << "."; g_game.internalMoveItem(container, player, CONST_SLOT_WHEREEVER, item, item->getItemCount(), nullptr); player->sendTextMessage(MESSAGE_INFO_DESCR, msgAutoLoot.str()); } } } else { player->sendTextMessage(MESSAGE_INFO_DESCR, "Sorry, you don't have enough capacity to use auto loot, so it has been disabled. (100+ capacity is required)"); } } } em player.h, abaixo de: std::unordered_set<uint32_t> VIPList; adicione isso: std::set<uint32_t> autoLootList; ainda em player.h encontre: bool hasLearnedInstantSpell(const std::string& spellName) const; adicione em baixo: void addItemToAutoLoot(uint16_t itemId); void removeItemFromAutoLoot(uint16_t itemId); bool getItemFromAutoLoot(uint16_t itemId); em player.cpp no final do arquivo, adicione: void Player::addItemToAutoLoot(uint16_t itemId) { autoLootList.insert(itemId); } void Player::removeItemFromAutoLoot(uint16_t itemId) { autoLootList.erase(itemId); } bool Player::getItemFromAutoLoot(const uint16_t itemId) { return autoLootList.find(itemId) != autoLootList.end(); } em luascript.cpp encontre: registerMethod("Player", "getFightMode", LuaScriptInterface::luaPlayerGetFightMode); e adicione em baixo: registerMethod("Player", "addItemToAutoLoot", LuaScriptInterface::luaPlayerAddItemToAutoLoot); registerMethod("Player", "removeItemFromAutoLoot", LuaScriptInterface::luaPlayerRemoveItemFromAutoLoot); registerMethod("Player", "getItemFromAutoLoot", LuaScriptInterface::luaPlayerGetItemFromAutoLoot); registerMethod("Player", "getAutoLootList", LuaScriptInterface::luaPlayerGetAutoLootList); ainda em luascript.cpp encontre essa função: int LuaScriptInterface::luaPlayerGetFightMode(lua_State* L) { // player:getFightMode() Player* player = getUserdata<Player>(L, 1); if (player) { lua_pushnumber(L, player->fightMode); } else { lua_pushnil(L); } return 1; } abaixo dela, adicione: int LuaScriptInterface::luaPlayerAddItemToAutoLoot(lua_State* L) { // player:addItemToAutoLoot(itemId) Player* player = getUserdata<Player>(L, 1); if (!player) { lua_pushnil(L); return 1; } uint16_t itemId; if (isNumber(L, 2)) { itemId = getNumber<uint16_t>(L, 2); } else { itemId = Item::items.getItemIdByName(getString(L, 2)); if (itemId == 0) { lua_pushnil(L); return 1; } } player->addItemToAutoLoot(itemId); pushBoolean(L, true); return 1; } int LuaScriptInterface::luaPlayerRemoveItemFromAutoLoot(lua_State* L) { // player:removeItemFromAutoLoot(itemId) Player* player = getUserdata<Player>(L, 1); if (!player) { lua_pushnil(L); return 1; } uint16_t itemId; if (isNumber(L, 2)) { itemId = getNumber<uint16_t>(L, 2); } else { itemId = Item::items.getItemIdByName(getString(L, 2)); if (itemId == 0) { lua_pushnil(L); return 1; } } player->removeItemFromAutoLoot(itemId); pushBoolean(L, true); return 1; } int LuaScriptInterface::luaPlayerGetItemFromAutoLoot(lua_State* L) { // player:getItemFromAutoLoot(itemId) Player* player = getUserdata<Player>(L, 1); if (!player) { lua_pushnil(L); return 1; } uint16_t itemId; if (isNumber(L, 2)) { itemId = getNumber<uint16_t>(L, 2); } else { itemId = Item::items.getItemIdByName(getString(L, 2)); if (itemId == 0) { lua_pushnil(L); return 1; } } if (player->getItemFromAutoLoot(itemId)) { pushBoolean(L, true); } else { pushBoolean(L, false); } return 1; } int LuaScriptInterface::luaPlayerGetAutoLootList(lua_State* L) { // player:getAutoLootList() Player* player = getUserdata<Player>(L, 1); if (player) { std::set<uint32_t> value = player->autoLootList; if (value.size() == 0) { lua_pushnil(L); return 1; } int index = 0; lua_createtable(L, value.size(), 0); for(auto i : value) { lua_pushnumber(L, i); lua_rawseti(L, -2, ++index); } } else { lua_pushnil(L); } return 1; } em luascript.h encontre: static int luaPlayerGetFightMode(lua_State* L); adicione a baixo: static int luaPlayerAddItemToAutoLoot(lua_State* L); static int luaPlayerRemoveItemFromAutoLoot(lua_State* L); static int luaPlayerGetItemFromAutoLoot(lua_State* L); static int luaPlayerGetAutoLootList(lua_State* L); em iologindata.cpp encontre: //load storage map query.str(std::string()); query << "SELECT `key`, `value` FROM `player_storage` WHERE `player_id` = " << player->getGUID(); if ((result = db.storeQuery(query.str()))) { do { player->addStorageValue(result->getNumber<uint32_t>("key"), result->getNumber<int32_t>("value"), true); } while (result->next()); } e adicione em baixo: query.str(std::string()); query << "SELECT `autoloot_list` FROM `player_autoloot` WHERE `player_id` = " << player->getGUID(); if ((result = db.storeQuery(query.str()))) { unsigned long lootlistSize; const char* autolootlist = result->getStream("autoloot_list", lootlistSize); PropStream propStreamList; propStreamList.init(autolootlist, lootlistSize); int16_t value; int16_t item = propStreamList.read<int16_t>(value); while (item) { player->addItemToAutoLoot(value); item = propStreamList.read<int16_t>(value); } } acima de: //save inbox items adicione: query.str(std::string()); query << "DELETE FROM `player_autoloot` WHERE `player_id` = " << player->getGUID(); if (!db.executeQuery(query.str())) { return false; } PropWriteStream propWriteStreamAutoLoot; for (auto i : player->autoLootList) { propWriteStreamAutoLoot.write<uint16_t>(i); } size_t lootlistSize; const char* autolootlist = propWriteStreamAutoLoot.getStream(lootlistSize); query.str(std::string()); DBInsert autolootQuery("INSERT INTO `player_autoloot` (`player_id`, `autoloot_list`) VALUES "); query << player->getGUID() << ',' << db.escapeBlob(autolootlist, lootlistSize); if (!autolootQuery.addRow(query)) { return false; } if (!autolootQuery.execute()) { return false; } em sua database, execute esta query CREATE TABLE player_autoloot ( id int NOT NULL AUTO_INCREMENT, player_id int NOT NULL, autoloot_list blob, PRIMARY KEY (id) ); agora vá em data/scripts/talkactions e crie esse arquivo LUA autoloot.lua local talk = TalkAction("!autoloot") function talk.onSay(player, words, param) local i = player:getAutoLootList() local cache = "Check your loot list: " local split = param:split(",") local action = split[1] if param == "list" then if i then for _, item in ipairs(i) do cache = cache .. (ItemType(item)):getName() .. ", " end else player:sendTextMessage(MESSAGE_INFO_DESCR, "Your list is empty! Add some item and try again.") return false end player:sendTextMessage(MESSAGE_INFO_DESCR, cache:sub(1, -3)) return false end if action == "add" then local item = split[2]:gsub("%s+", "", 1) local itemType = ItemType(item) if itemType:getId() == 0 then itemType = ItemType(tonumber(item)) if itemType:getName() == '' then player:sendCancelMessage("There is no item with that id or name.") return false end end if player:getItemFromAutoLoot(itemType:getId()) then player:sendCancelMessage("You're already autolooting this item.") return false end player:addItemToAutoLoot(itemType:getId()) player:sendTextMessage(MESSAGE_INFO_DESCR, "You're now auto looting " .. itemType:getName()) return false elseif action == "remove" then local item = split[2]:gsub("%s+", "", 1) local itemType = ItemType(item) if itemType:getId() == 0 then itemType = ItemType(tonumber(item)) if itemType:getName() == '' then player:sendCancelMessage("There is no item with that id or name.") return false end end if player:getItemFromAutoLoot(itemType:getId()) then player:removeItemFromAutoLoot(itemType:getId()) player:sendTextMessage(MESSAGE_INFO_DESCR, "You removed the " .. itemType:getName() .. " from your loot list.") else player:sendCancelMessage("This item does not exist in your loot list.") end return false end player:sendTextMessage(MESSAGE_EVENT_ORANGE, "Auto Loot commands (items are automatically moved to your bp if you open monster corpse):"..'\n'.."!addloot add, nameItem - add item to auto loot by name"..'\n'.."!autoloot remove, itemName - remove item from auto loot by name"..'\n'.."!autoloot list - list your current auto loot items") return false end talk:separator(" ") talk:register() É isso, espero que gostem do sisteminha Se você encontrar algum bug, deixe-me saber. Falta fazer: Optimizar a mensagem de loot. Adicionar ModalWindow. Cheers~
  3. Boa noite gostaria de saber se alguem sabe mudar versao do Item.otbm 7.60 para 8.54 ?
  4. Visualizar Anúncio Procuro programador experiente Preço a combinar dependendo do seu trabalho. Se tiver interesse mande mensagem para: email: marcelomcolchete@gmail.com wpp: 21983242505 Não precisa ter formalidade nenhuma, pode ser direto Anunciante Goren Date 26/11/2019 Preço Categoria Procura-se Freelancers  
  5. Time Left: 5 months and 9 days

    • Looking for Freelancers
    • 25% before delivery

    Preço a combinar dependendo do seu trabalho. Se tiver interesse mande mensagem para: email: marcelomcolchete@gmail.com wpp: 21983242505 Não precisa ter formalidade nenhuma, pode ser direto

    NO VALUE SPECIFIED

  6. Push Cruzado Como prometido, hoje eu vou ensinar como implementar o push cruzado. Este tutorial é feito especificamente para a versão 2 do OTX, porem, devido a simplicidade do código (sério, é muito simples, você vai se surpreender), acredito que possa ser implementado em qualquer source code disponível atualmente. Antes do tutorial vou falar sobre como surgiu o "sistema" e de como o mesmo ficou popular entre os jogadores de Baiak, então senta que lá vem história. Se você não tem interesse na história de como surgiu e se popularizou e só está aqui pelo tutorial de como implementar, pule para o final do tópico. História Familiar para alguns e desconhecido para muitos outros, o que afinal é esse tal de push cruzado que alguns tanto falam? Para entender como surgiu, teremos que voltar alguns anos no tempo, em uma época que OTX não existia e o TFS 1.x ainda era um sonho distante, época essa em que a maioria dos servidores com protocolo 8.60 utilizavam como engine a velha TFS 0.3.6. Foi neste período que alguns jogadores de enforced descobriram este bug, isso mesmo que você leu, o push cruzado é na verdade um bug! Mas calma! é apenas um bug inofensivo, mesmo assim, não deixa de ser um bug, que hoje em dia é divulgado como feature nos servidores. Antes de entrar mais a fundo nessa questão, vou terminar de explicar como ele foi descoberto, como ele pode ser utilizado e as vantagens que ele concede aos jogadores que sabem como utiliza-lo. Nos saudosos dias em que o protocolo 8.60 estava no seu auge na comunidade OpenTibia (70% da Otserv List era composta por servidores 8.60), poucos tinham acesso para a até então recente TFS 0.4 (nesta época TFS 0.4 não era pública, e só podia ser obtida doando uma quantia aos desenvolvedores). Até então, era raro encontrar servidores rodando com TFS 0.4, mais raro ainda um servidor enforced/war, mas assim como uma agulha no palheiro, ele estava lá, Mega-War, o que eu acredito que tenha sido o primeiro servidor de war 8.60 a usar a recente distro. OTServList em 2011 E foi neste servidor que o push cruzado foi descoberto, por jogadores dedicados a se aperfeiçoarem no PvP, estes foram os primeiros e os que deram origem ao que hoje se conhece como enforcedeiros (jogadores assíduos de servidores de war, com uma habilidade surreal no PvP). Mas algumas questões ficam no ar, TFS 0.4 era realmente recente, porem o protocolo 8.60 já existia há um bom tempo no TFS 0.3, então porque este bug não foi descoberto antes? porque neste servidor em especifico se outros servidores de war 8.60 já existiam? A resposta é: este bug surgiu justamente no TFS 0.4, para ser mais especifico na rev 3777, tanto é que a versão anterior do TFS (0.3) não continha este bug e nas revisões seguintes do TFS 0.4 ele foi corrigido, com isto o push cruzado se "perdeu", existindo somente no TFS 0.4 (Rev 3777). Devido a isto, os servidores privados de enforced (onde se encontra a maioria dos enforcedeiros hoje em dia) e alguns servidores baiaks utilizam TFS 0.4 até hoje, mesmo existindo opções excelentes em comparação, como TFS 1.x e OTX, tudo devido a este bugzinho que se popularizou muito entre alguns jogadores ao longo do anos. Mas como o push cruzado se popularizou tanto a ponto de chegar ao que é hoje? Os enforcedeiros tinham um estilo único de PvP, fazendo jogadas que para muitos até hoje não é possível sem o uso de bot. Com o tempo, estes jogadores foram gravando e postando vídeos no Youtube de suas jogadas, para muitos dos que assistiam, tal nível de habilidade só podia ser atingido com auxílio do bot, os mais humildes, aqueles que aceitavam que aquilo era possível sem o uso de bot, entravam nestes servidores de war com a intenção de aprender, não só o push cruzado, mas o push a distancia, a velocidade para realizar jogadas e a visão de jogo num geral. Alguns dos vídeos antigos da época do Mega-War. Neste ultimo vídeo em especial, é possivel ver o push cruzado sendo realizado por volta de 1:22 e 3:20 de vídeo. No inicio de 2013, sem motivo aparente o Mega-War simplesmente fechou. Mas onde há demanda, sempre haverá oferta, com isso surge o ainda mais famoso Total-War. O Mega-War foi o inicio para essas estrelas do PvP, mas foi no Total-War que a coisa realmente cresceu. Com cada vez mais vídeos de jogadores exibindo jogadas espetaculares, mais aparecia os chamados novatos (jogadores que admiravam os enforcedeiros e tinham interesse em aprender e praticar as técnicas usadas), na época do Mega-War, dava pra contar nos dedos a quantidade de pessoas que sabiam fazer o push cruzado, afinal, era uma coisa totalmente nova, com poucos meses do Total-War online esse numero cresceu exponencialmente, o servidor ficou no seu auge por cerca de 1 ano e alguns meses. Alguns vídeos de enforcedeiros no Total-War (incluindo o meu 😊). Poucos sabem disso, mas eu era GM no Total-War, ajudei no servidor por alguns meses até ter um desentendimento com o dono, nesse momento eu decidi abrir o meu próprio servidor enforced. Eu acompanho a comunidade brasileira de OpenTibia desde 2010, mas nunca tinha levado a sério a ideia de ter meu próprio servidor até então, foi nessa época que eu criei a minha conta aqui no TibiaKing, pois o antigo XTibia (lugar onde eu conheci o que era OpenTibia) havia fechado. No ano de 2014 encontrar as sources do TFS 0.4 já não era mais problema, estavam por todo lugar. Eu peguei um datapack com mapa de venore (assim como o Mega e Total-War) e coloquei online, nesse período eu comecei a estudar a fundo como funcionava OTServers. Devido a testes de diversas versões diferentes de source, já na época eu percebi que push cruzado era algo exclusivo do TFS 0.4 (isso explica porque o dono do Total-War se recusava a fazer um upgrade), era também tempo do inicio do repositório do OTX que se mostrava promissor em relação ao TFS 0.4. Cerca de 1 ano depois da abertura do meu servidor eu decidi tentar adicionar o cruzado nas sources do OTX2, uma pessoa dedicada com um objetivo, mas sem saber de nada, por semanas eu comparei o código de ambas as sources, arquivo por arquivo (haja dedicação), e por fim consegui adicionar ao OTX (quando eu descobri o que era, eu confesso que de imediato me arrependi de ter gasto tanto tempo com isso). Com essa alteração eu resetei e reinaugurei meu servidor, o servidor era chamado de Ultra-War, mas ficou mais conhecido por todos como Sv2 porque o servidor era hosteado em 3 locais diferentes, e 1 dos locais era aqui no Brasil, este era conhecido como Sv2. O Ultra-War foi o primeiro servidor a ter o push cruzado sem utilizar do TFS 0.4, na época OTX já estava se tornando muito popular pois dava uma sensação de ping menor ao jogar, rodando o servidor com OTX e em 3 hosts diferentes, os poucos players que sobraram no Total-War migraram para o Ultra-War, e assim como o Total-War ocupou o lugar do Mega-War no seu fim, o Sv2 passou a segurar esta tocha. Alem dos já antigos enforcedeiros, jogadores novos não paravam de vir de todos os lugares, muitos deles quando aprendiam e aperfeiçoavam as técnicas iam logo aplicar em servidores UP Level (principalmente Baiaks), foi ai que o push cruzado se popularizou fora do enforced, com os jogadores pedindo aos administradores para adicionarem algo que eles sequer tinham noção do que era. Vídeos do jogador que eu acredito ser o maior responsável pela popularidade do PvP no estilo enforced nos Baiaks. Enfim... a história acaba por aqui (até porque ficou longa pra kct), no final das contas a história não foi sobre o push cruzado em si, mas sobre o enforced e os enforcedeiros num geral. Agora vamos para a parte que todos querem ver. O que é e como utilizar O push cruzado nada mais é do que permitir que o jogador empurre (push) outros jogadores e criaturas enquanto se movimenta ao mesmo tempo, basicamente é apenas isso. O que isso proporciona ao jogador, ai já é outra historia (brincadeira, depois dessa ultima, chega de história), isso permite ao jogador executar jogadas que sem o push cruzado seriam executadas de maneira bem mais lenta, e até mesmo jogadas que seriam impossíveis de serem realizadas sem o uso do famoso cruzado. Veja abaixo alguns exemplos. Tutorial Como eu mencionei antes, o push cruzado é na verdade um bug, caso implementado, isso possibilita aos jogadores realizarem jogadas que sem ele seriam impossíveis. Se mesmo ciente disto você deseja seguir em frente, basta seguir os passos abaixo. Pronto, com isso você pode habilitar ou desabilitar o push cruzado diretamente pelo config.lua, sem a necessidade de recompilar a source. Créditos Me, myself and I.
  7. REV3884 TFS 0.4 OTC 0.6.6 OBSERVAÇÃO: Bom galera hoje vim trazer um código de expansão de visão para o otclient alterado por mim, usado somente para rev3884 e então se você usa um tfs 0.3.6 ou tfs 1.0 não vai dar certo, *Esse código foi alterado por mim para ser usado apenas para rev3884, procolo 8.60 e TFS 0.4 que no caso não achei e resolvi compartilhar essas alterações. 1° TUTORIAL 1 SOURCE DO SEU SERVIDOR. Abra Protocollgame.cpp 1 Ache ((x >= myPos.x - 8 + offsetz) && (x <= myPos.x + 9 + offsetz) && //(y >= myPos.y - 6 + offsetz) && (y <= myPos.y + 7 + offsetz)); ALTERE PARA: ((x >= myPos.x - Map::maxClientViewportX + offsetz) && (x <= myPos.x + (Map::maxClientViewportX+1) + offsetz) && (y >= myPos.y - Map::maxClientViewportY + offsetz) && (y <= myPos.y + (Map::maxClientViewportY+1) + offsetz)); 2 Ache: GetMapDescription(pos.x - 8, pos.y - 6, pos.z, 18, 14, msg); ALTERE PARA: GetMapDescription(pos.x - Map::maxClientViewportX, pos.y - Map::maxClientViewportY, pos.z, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, msg); 3 Ache: if(oldPos.y > newPos.y) // north, for old x { msg->put<char>(0x65); GetMapDescription(oldPos.x - 8, newPos.y - 6, newPos.z, 18, 1, msg); } else if(oldPos.y < newPos.y) // south, for old x { msg->put<char>(0x67); GetMapDescription(oldPos.x - 8, newPos.y + 7, newPos.z, 18, 1, msg); } if(oldPos.x < newPos.x) // east, [with new y] { msg->put<char>(0x66); GetMapDescription(newPos.x + 9, newPos.y - 6, newPos.z, 1, 14, msg); } else if(oldPos.x > newPos.x) // west, [with new y] { msg->put<char>(0x68); GetMapDescription(newPos.x - 8, newPos.y - 6, newPos.z, 1, 14, msg); } ALTERE PARA: if (oldPos.y > newPos.y) { // north, for old x msg->put<char>(0x65); GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, 1, msg); } else if (oldPos.y < newPos.y) { // south, for old x msg->put<char>(0x67); GetMapDescription(oldPos.x - Map::maxClientViewportX, newPos.y + (Map::maxClientViewportY+1), newPos.z, (Map::maxClientViewportX+1)*2, 1, msg); } if (oldPos.x < newPos.x) { // east, [with new y] msg->put<char>(0x66); GetMapDescription(newPos.x + (Map::maxClientViewportX+1), newPos.y - Map::maxClientViewportY, newPos.z, 1, (Map::maxClientViewportY+1)*2, msg); } else if (oldPos.x > newPos.x) { // west, [with new y] msg->put<char>(0x68); GetMapDescription(newPos.x - Map::maxClientViewportX, newPos.y - Map::maxClientViewportY, newPos.z, 1, (Map::maxClientViewportY+1)*2, msg); } 4 ache GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 5, 18, 14, 3, skip); //(floor 7 and 6 already set) GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 4, 18, 14, 4, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 3, 18, 14, 5, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 2, 18, 14, 6, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 1, 18, 14, 7, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, 0, 18, 14, 8, skip); Altere para GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 5, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 3, skip); //(floor 7 and 6 already set) GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 4, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 4, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 3, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 5, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 6, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 1, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 7, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, 0, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 8, skip); 5 ache GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, oldPos.z - 3, 18, 14, 3, skip); ALTERE PARA GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, oldPos.z - 3, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, 3, skip); 6 ACHE GetMapDescription(oldPos.x - 8, oldPos.y + 1 - 6, newPos.z, 1, 14, msg); ALTERE PARA GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - (Map::maxClientViewportY-1), newPos.z, 1, (Map::maxClientViewportY+1)*2, msg); 7 ACHE GetMapDescription(oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 1, msg); ALTERE PARA GetMapDescription(oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, 1, msg); 8 Ache GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z, 18, 14, -1, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 1, 18, 14, -2, skip); GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip); Altere para GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -1, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 1, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -2, skip); GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -3, skip); 9 ache GetFloorDescription(msg, oldPos.x - 8, oldPos.y - 6, newPos.z + 2, 18, 14, -3, skip); Altere para GetFloorDescription(msg, oldPos.x - Map::maxClientViewportX, oldPos.y - Map::maxClientViewportY, newPos.z + 2, (Map::maxClientViewportX+1)*2, (Map::maxClientViewportY+1)*2, -3, skip); 10 ache GetMapDescription(oldPos.x + 9, oldPos.y - 1 - 6, newPos.z, 1, 14, msg); Altere para GetMapDescription(oldPos.x + Map::maxClientViewportX+1, oldPos.y - (Map::maxClientViewportY+1), newPos.z, 1, ((Map::maxClientViewportY+1)*2), msg); AGORA EM MAP.H ache static const int32_t maxViewportX = 11; //min value: maxClientViewportX + 1 static const int32_t maxViewportY = 11; //min value: maxClientViewportY + 1 static const int32_t maxClientViewportX = 8; static const int32_t maxClientViewportY = 6; altere para: static const int32_t maxViewportX = 18; //min value: maxClientViewportX + 1 static const int32_t maxViewportY = 18; //min value: maxClientViewportY + 1 static const int32_t maxClientViewportX = 14; static const int32_t maxClientViewportY = 12; Pronto agora é só compilar a source do seu servidor 8.60 rev3884 PARTE 2 OTCLIENT 0.6.6 abra o map.cpp da source do otclient ache void Map::resetAwareRange() { AwareRange range; range.left = 8; range.top = 6; range.bottom = 7; range.right = 9; setAwareRange(range); } ALTERE PARA void Map::resetAwareRange() { AwareRange range; range.left = 14; //Change this to = maxClientViewportX range.top = 12; //Change this to = maxClientViewportY range.bottom = range.top+1; range.right = range.left+1; setAwareRange(range); } COMPILE A SOURCE DO OTCLIENT E PRONTO!!! ESPERO TER SANADO VÁRIAS DÚVIDAS DE AUMENTAR TELA DO OTCLIENT EM REV3884. CRÉDITOS: Pra mim pela alterações funcionais. e pelo Flatlander por disponibilizar para tfs 0.3.6 e 1.0 pois esse está alterado pra tfs 0.4
  8. Galera não sei se ta na área correta, 😕 estou com um problema a tenta compilar Source Obs: A primeira vez que estou Tentando, e olhei alguns tutoriais mesmo fazendo tudo certinho sempre da esse erro.
  9. 0.3.6 Estou montando um servidor, já está 80% concluído falta poucos detalhes. mais não estou conseguindo por level System no meu servidor, já estudei algumas base que contem level system, tentando entender como funciona, mais fracassei. depois pensei em muda para uma base PDA mais literalmente não valeria apena, jogaria quase 1 ano de trabalho fora. bom quero um level System com pelo menos o básico. EX: level 10 mais vida e ataque do que level 9. passaria de level ao receber quantia X de XP enquanto elimina outros pokemon. O que posso oferecer em troca são apenas eventos que bolei com o tempo, Quest's diferenciadas. gostaria de saber pelo menos o que estudar para conseguir montar meu level system mesmo que demore afinal estou nessa luta a quase 3 anos, o que seria mais alguns meses. C++ é o suficiente ? Obrigado pelo atenção.
  10. Pessoal estou com um erro ao compilar meu servidor: Alguem pode me ajudar? er -Wno-array-bounds -pthread -pipe -MT scheduler.o -MD -MP -MF .deps/scheduler.Tpo -c -o scheduler.o scheduler.cpp In file included from protocol.h:20:0, from protocolhttp.h:20, from protocolhttp.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/protocolhttp.Tpo .deps/protocolhttp.Po g++ -DHAVE_CONFIG_H -I. -I/usr/include/libxml2 -I/usr/include/lua5.1 -O2 -fomit-frame-pointer -D__USE_MYSQL__ -D__WAR_SYSTEM__ -D__ROOT_PERMISSION__ -D_THREAD_SAFE -D_REENTRANT -Wall -Wextra -Wno-strict-aliasing -Wno-unused-parameter -Wno-array-bounds -pthread -pipe -MT scriptmanager.o -MD -MP -MF .deps/scriptmanager.Tpo -c -o scriptmanager.o scriptmanager.cpp In file included from rsa.h:21:0, from rsa.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/rsa.Tpo .deps/rsa.Po g++ -DHAVE_CONFIG_H -I. -I/usr/include/libxml2 -I/usr/include/lua5.1 -O2 -fomit-frame-pointer -D__USE_MYSQL__ -D__WAR_SYSTEM__ -D__ROOT_PERMISSION__ -D_THREAD_SAFE -D_REENTRANT -Wall -Wextra -Wno-strict-aliasing -Wno-unused-parameter -Wno-array-bounds -pthread -pipe -MT server.o -MD -MP -MF .deps/server.Tpo -c -o server.o server.cpp In file included from luascript.h:20:0, from luascript.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] luascript.cpp:741:3: erro: stray ‘\357’ in program luascript.cpp:741:3: erro: stray ‘\273’ in program luascript.cpp:741:3: erro: stray ‘\277’ in program luascript.cpp:741:3: erro: stray ‘\357’ in program luascript.cpp:741:3: erro: stray ‘\273’ in program luascript.cpp:741:3: erro: stray ‘\277’ in program make[1]: ** [luascript.o] Erro 1 make[1]: ** Esperando que outros processos terminem. In file included from scheduler.h:20:0, from scheduler.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/scheduler.Tpo .deps/scheduler.Po In file included from quests.h:20:0, from quests.cpp:19: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/quests.Tpo .deps/quests.Po In file included from protocol.h:20:0, from protocollogin.h:20, from protocollogin.cpp:20: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] In file included from protocol.h:20:0, from protocolold.h:20, from protocolold.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/protocollogin.Tpo .deps/protocollogin.Po mv -f .deps/protocolold.Tpo .deps/protocolold.Po In file included from raids.h:20:0, from raids.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/raids.Tpo .deps/raids.Po In file included from scriptmanager.h:20:0, from scriptmanager.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] scriptmanager.cpp:130:3: erro: stray ‘\357’ in program scriptmanager.cpp:130:3: erro: stray ‘\273’ in program scriptmanager.cpp:130:3: erro: stray ‘\277’ in program scriptmanager.cpp:130:3: erro: stray ‘\357’ in program scriptmanager.cpp:130:3: erro: stray ‘\273’ in program scriptmanager.cpp:130:3: erro: stray ‘\277’ in program make[1]: ** [scriptmanager.o] Erro 1 In file included from otserv.cpp:18:0: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/otserv.Tpo .deps/otserv.Po In file included from server.h:20:0, from server.cpp:18: otsystem.h:128:7: aviso: símbolo extra ao fim da diretriz #endif [habilitado por padrão] mv -f .deps/server.Tpo .deps/server.Po make[1]: Saindo do diretório `/home/Servidor/sources' make: ** [all] Erro 2
  11. Versão 8.54 version 0.3.6 (Crying Damson) Ae galera estou compartilhando com vocês o código para quem for aumentar o limite de magic effects no servidor é trabalhoso então para ajudar a galera a não ficar horas fazendo resolvi trazer os códigos prontos xD Tópico atualizado 04/08/2018 as 23:57 # Atualização Códigos atualizados do 427 para o 700 const.h Tools.cpp 000-constant.lua Espero que ajude alguém xD
  12. Not completely tested and not all features are working but I am releasing this so that it is considered to be fixed and merged with the official branch. Sql INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `skull`, `skulltime`, `lastlogout`, `blessings`, `onlinetime`, `deletion`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`) VALUES (1, 'Account Manager', 1, 1, 1, 1, 150, 150, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, '', 40000, 1, 1535311649, 16777343, 1, 0, 0, 1535311709, 0, 2958, 0, 0, 43200, -1, 2520, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0); INSERT INTO `accounts` (`id`, `name`, `password`, `secret`, `type`, `premdays`, `lastday`, `vippoints`, `email`, `creation`) VALUES (1, '1', '356a192b7913b04c54574d18c28d46e6395428ab', NULL, 1, 365, 1535263046, '', '', 0); configmanager.cpp // account manager boolean[ACCOUNT_MANAGER] = getGlobalBoolean(L, "accountManager", true); integer[AM_LEVEL] = getGlobalNumber(L, "startLevel", 1); integer[AM_EXPERIENCE] = getGlobalNumber(L, "experience", 0); integer[AM_MAGLEVEL] = getGlobalNumber(L, "level", 0); integer[AM_FIST] = getGlobalNumber(L, "fist", 10); integer[AM_CLUB] = getGlobalNumber(L, "club", 10); integer[AM_SWORD] = getGlobalNumber(L, "sword", 10); integer[AM_AXE] = getGlobalNumber(L, "axe", 10); integer[AM_SHIELD] = getGlobalNumber(L, "shield", 10); integer[AM_DIST] = getGlobalNumber(L, "distance", 10); integer[AM_FISH] = getGlobalNumber(L, "fish", 10); integer[AM_SOUL] = getGlobalNumber(L, "soul", 100); integer[AM_BALANCE] = getGlobalNumber(L, "balance", 0); integer[AM_OFFLINE_TRAIN] = getGlobalNumber(L, "offlineTrainingTime", 0); integer[AM_STAMINA] = getGlobalNumber(L, "stamina", 0); integer[AM_LOOK_ADDONS] = getGlobalNumber(L, "lookAddons", 0); integer[AM_MOUNT_ID] = getGlobalNumber(L, "mountId", 0); integer[AM_TOWN_ID] = getGlobalNumber(L, "startTownId", 1); integer[AM_SPAWNPOS_X] = getGlobalNumber(L, "temple_x", 0); integer[AM_SPAWNPOS_Y] = getGlobalNumber(L, "temple_y", 0); integer[AM_SPAWNPOS_Z] = getGlobalNumber(L, "temple_z", 0); integer[AM_MAX_HP] = getGlobalNumber(L, "baseHP", 150); integer[AM_MAX_MP] = getGlobalNumber(L, "baseMP", 0); integer[AM_MAX_CAP] = getGlobalNumber(L, "baseCAP", 400); integer[AM_MALE] = getGlobalNumber(L, "maleOutfit", 128); integer[AM_FEMALE] = getGlobalNumber(L, "femaleOutfit", 136); boolean[AM_CHOOSEVOC] = getGlobalBoolean(L, "chooseVocation", false); boolean[AM_GENERATE_ACCOUNT_NUMBER] = getGlobalBoolean(L, "generateAccountNumber", false); // xml or lua boolean[USE_XML] = getGlobalBoolean(L, "useXml", false); configmanager.h booleans // account manager ACCOUNT_MANAGER, NAMELOCK_MANAGER, AM_CHOOSEVOC, AM_GENERATE_ACCOUNT_NUMBER, // -- // lua or xml USE_XML, integers // account manager AM_LEVEL, AM_EXPERIENCE, AM_MAGLEVEL, AM_FIST, AM_CLUB, AM_SWORD, AM_AXE, AM_SHIELD, AM_DIST, AM_FISH, AM_SOUL, AM_BALANCE, AM_OFFLINE_TRAIN, AM_STAMINA, AM_LOOK_ADDONS, AM_MOUNT_ID, AM_TOWN_ID, AM_SPAWNPOS_X, AM_SPAWNPOS_Y, AM_SPAWNPOS_Z, AM_MAX_HP, AM_MAX_MP, AM_MAX_CAP, AM_MALE, AM_FEMALE, // -- creature.h // account manager virtual bool isAccountManager() const { return false; } // -- game.cpp find this inside of Game:playerSay uint32_t muteTime = player->isMuted(); if (muteTime > 0) { std::ostringstream ss; ss << "You are still muted for " << muteTime << " seconds."; player->sendTextMessage(MESSAGE_STATUS_SMALL, ss.str()); return; } and place this right underneath // account manager if(player->isAccountManager()) { player->removeMessageBuffer(); internalCreatureSay(player, TALKTYPE_SAY, text, false); return; } // -- find this in Game::internalCreatureSay if (text.empty()) { return false; } and place this above it // account manager Player* player = creature->getPlayer(); if(player && player->isAccountManager()) { player->manageAccount(text); return true; } // -- add this to house.cpp // account manager void House::updateDoorDescription(std::string _name/* = ""*/) { std::string tmp = "house"; /* no isGuild method (atm) if(isGuild()) tmp = "hall"; */ char houseDescription[200]; const int32_t housePrice = g_config.getNumber(ConfigManager::HOUSE_PRICE); if(owner) { /* if(isGuild()) IOGuild::getInstance()->getGuildById(_name, owner); */ if(_name.empty()) IOLoginData::getInstance()->getNameByGuid(owner, _name); sprintf(houseDescription, "It belongs to %s '%s'. %s owns this %s.", tmp.c_str(), houseName.c_str(), _name.c_str(), tmp.c_str()); } else sprintf(houseDescription, "It belongs to %s '%s'. Nobody owns this %s. It costs %lu gold coins.", tmp.c_str(), houseName.c_str(), tmp.c_str(), ( housePrice != -1 ? (houseTiles.size() * housePrice) : 0 ) ); for (const auto& it : doorSet) { it->setSpecialDescription(houseDescription); } } // -- house.h find this void updateDoorDescription() const; and place this right underneath it void updateDoorDescription(std::string _name = ""); iologindata.cpp find this #include "game.h" and add this below it // account manager #include "vocation.h" // -- find this extern Game g_game; and add this below it // account manager extern Vocation g_vocations; // -- inside of this IOLoginData::loginserverAuthentication find this result = db.storeQuery(query.str()); if (result) { do { if (result->getNumber<uint64_t>("deletion") == 0) { account.characters.push_back(result->getString("name")); } } while (result->next()); std::sort(account.characters.begin(), account.characters.end()); } return true; and replace it with this result = db.storeQuery(query.str()); // account manager if(!result){ // give the account the account manager to use if they have no account account.characters.push_back("Account Manager"); return true; } // -- if (result) { // allow them to access the account manager if there are players on the account if (account.id != 1){ account.characters.push_back("Account Manager"); } do { if (result->getNumber<uint64_t>("deletion") == 0) { account.characters.push_back(result->getString("name")); } } while (result->next()); std::sort(account.characters.begin(), account.characters.end()); } return true; add this // account manager bool IOLoginData::getAccountId(const std::string& name, uint32_t& number) { if(!name.length()) return false; Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `name` LIKE " << db.escapeString(name) << " LIMIT 1;"; DBResult_ptr result; if(!(result = db.storeQuery(query.str()))) return false; number = result->getNumber<uint32_t>("id"); return true; } // -- find this in IOLoginData::updateOnlineStatus if (g_config.getBoolean(ConfigManager::ALLOW_CLONES)) { return; } and add this // account manager if(g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)){ return; } // -- add this // account manager bool IOLoginData::getNameByGuid(uint32_t guid, std::string& name) { std::ostringstream query; query << "SELECT `name` FROM `players` WHERE `id` = " << guid << " AND `deleted` = 0 LIMIT 1;"; DBResult_ptr result = Database::getInstance().storeQuery(query.str()); if (!result) { return false; } name = result->getString("name"); nameCacheMap[guid] = name; return true; } // -- Now add all these // account manager bool IOLoginData::accountIdExists(uint32_t accountId) { Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `id` = " << accountId << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; return true; } bool IOLoginData::accountNameExists(const std::string& name) { Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `name` LIKE " << db.escapeString(name) << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; return true; } bool IOLoginData::getPassword(uint32_t accountId, std::string& password, std::string name/* = ""*/) { Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `password` FROM `accounts` WHERE `id` = " << accountId << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; if(name.empty() || name == "Account Manager") { password = result->getString("password"); return true; } std::string tmpPassword = result->getString("password"); query.str(""); query << "SELECT `name` FROM `players` WHERE `account_id` = " << accountId; result = db.storeQuery(query.str()); if(!result) return false; do { if(result->getString("name") != name) continue; password = tmpPassword; return true; } while(result->next()); return false; } // accountId should be id because the server references the index and not the actual account data bool IOLoginData::setPassword(uint32_t accountId, std::string newPassword) { std::string ePassword = transformToSHA1(newPassword); Database& db = Database::getInstance(); std::ostringstream query; query << "UPDATE `accounts` SET `password` = " << db.escapeString(ePassword) << " WHERE `id` = " << accountId << ";"; return db.executeQuery(query.str()); } // not using recovery key atm but still good to have bool IOLoginData::validRecoveryKey(uint32_t accountId, std::string recoveryKey) { std::string nRecoveryKey = transformToSHA1(recoveryKey); Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `id` = " << accountId << " AND `recoverykey` "; query << "LIKE " << db.escapeString(nRecoveryKey) << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; return true; } bool IOLoginData::setRecoveryKey(uint32_t accountId, std::string newRecoveryKey) { std::string nRecoveryKey = transformToSHA1(newRecoveryKey); Database& db = Database::getInstance(); std::ostringstream query; std::cout << "account id " << accountId << std::endl; query << "UPDATE `accounts` SET `recoverykey` = " << db.escapeString(nRecoveryKey) << " WHERE `name` = " << accountId << ";"; return db.executeQuery(query.str()); } uint64_t IOLoginData::createAccount(std::string name, std::string password) { std::string ePassword = transformToSHA1(password); Database& db = Database::getInstance(); std::ostringstream query; query << "INSERT INTO `accounts` (`id`, `name`, `password`) VALUES (NULL, " << db.escapeString(name) << ", " << db.escapeString(ePassword) << ")"; if(!db.executeQuery(query.str())) return 0; return db.getLastInsertId(); } // not tested yet bool IOLoginData::changeName(uint32_t guid, std::string newName, std::string oldName) { Database& db = Database::getInstance(); std::ostringstream query; query << "INSERT INTO `player_namelocks` (`player_id`, `name`, `new_name`, `date`) VALUES ("<< guid << ", " << db.escapeString(oldName) << ", " << db.escapeString(newName) << ", " << time(NULL) << ")"; DBResult_ptr result = db.storeQuery(query.str()); if (!result) { return false; } query.str(""); query << "UPDATE `players` SET `name` = " << db.escapeString(newName) << " WHERE `id` = " << guid << " LIMIT 1"; result = db.storeQuery(query.str()); if (!result) { return false; } GuidCacheMap::iterator it = guidCacheMap.find(oldName); if(it != guidCacheMap.end()) { guidCacheMap.erase(it); guidCacheMap[newName] = guid; } nameCacheMap[guid] = newName; return true; } bool IOLoginData::createCharacter(uint32_t accountId, std::string characterName, uint32_t vocationId /*int32_t vocationId */, uint16_t sex) { if(playerExists(characterName)){ return false; } // a little bulky but whatever lol uint32_t healthMax = g_config.getNumber(ConfigManager::AM_MAX_HP); uint32_t manaMax = g_config.getNumber(ConfigManager::AM_MAX_MP); uint32_t capMax = g_config.getNumber(ConfigManager::AM_MAX_CAP); uint16_t lookType = (sex % 2) ? g_config.getNumber(ConfigManager::AM_MALE) : g_config.getNumber(ConfigManager::AM_FEMALE); uint16_t lookAddons = g_config.getNumber(ConfigManager::AM_LOOK_ADDONS); uint16_t magLevel = g_config.getNumber(ConfigManager::AM_MAGLEVEL); uint16_t townId = g_config.getNumber(ConfigManager::AM_TOWN_ID); uint16_t spawnX = g_config.getNumber(ConfigManager::AM_SPAWNPOS_X); uint16_t spawnY = g_config.getNumber(ConfigManager::AM_SPAWNPOS_Y); uint16_t spawnZ = g_config.getNumber(ConfigManager::AM_SPAWNPOS_Z); uint32_t level = g_config.getNumber(ConfigManager::AM_LEVEL); uint64_t exp = g_config.getNumber(ConfigManager::AM_EXPERIENCE); uint32_t fist = g_config.getNumber(ConfigManager::AM_FIST); uint32_t club = g_config.getNumber(ConfigManager::AM_CLUB); uint32_t sword = g_config.getNumber(ConfigManager::AM_SWORD); uint32_t axe = g_config.getNumber(ConfigManager::AM_AXE); uint32_t shield = g_config.getNumber(ConfigManager::AM_SHIELD); uint32_t dist = g_config.getNumber(ConfigManager::AM_DIST); uint32_t fish = g_config.getNumber(ConfigManager::AM_FISH); uint32_t soul = g_config.getNumber(ConfigManager::AM_SOUL); uint64_t balance = g_config.getNumber(ConfigManager::AM_BALANCE); int32_t offlineTrainingTime = g_config.getNumber(ConfigManager::AM_OFFLINE_TRAIN); uint16_t stamina = g_config.getNumber(ConfigManager::AM_STAMINA); if(level > 1){ exp += Player::getExpForLevel(level); healthMax *= level; manaMax *= level; capMax *= level; } Database& db = Database::getInstance(); std::string name = db.escapeString(characterName); std::ostringstream query, initialQuery, lastQuery, selectChar; // since character creation wants to use the account name when it setups up the player as the account id // we'll ask the database to get the id of the account since that is how the players are listed in the character list selectChar << "SELECT `id` FROM `accounts` WHERE `name` = " << accountId << ";"; DBResult_ptr result = db.storeQuery(selectChar.str()); if (!result){ return false; } accountId = result->getNumber<uint32_t>("id"); // this is to counteract the foreign key issue initialQuery << "SET FOREIGN_KEY_CHECKS=0;"; lastQuery << "SET FOREIGN_KEY_CHECKS=1;"; db.executeQuery(initialQuery.str()); query << "INSERT INTO `players` (`name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `skull`, `skulltime`, `lastlogout`, `blessings`, `onlinetime`, `deletion`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries`) VALUES (" << name << ", 1, " << accountId << ", " << level << ", " << vocationId << ", " << healthMax << ", " << healthMax << ", " << exp << ", 0, 0, 0, 0, " << lookType << ", " << lookAddons << ", " << magLevel << ", " << manaMax << ", " << manaMax << ", 0, " << soul << ", " << townId << ", " << spawnX << ", " << spawnY << ", " << spawnZ << ", 0x0, " << capMax << ", " << sex << ", 0, 0, 1, 0, 0, 0, 0, 0, 0, " << balance << ", " << offlineTrainingTime << ", -1, " << stamina << ", " << fist << ", 0, " << club << ", 0, " << sword << ", 0, " << axe << ", 0, " << dist << ", 0, " << shield << ", 0, " << fish << ", 0);"; if(db.executeQuery(query.str())){ db.executeQuery(lastQuery.str()); return true; } db.executeQuery(lastQuery.str()); return false; } // not tested DeleteCharacter_t IOLoginData::deleteCharacter(uint32_t accountId, const std::string characterName) { if(g_game.getPlayerByName(characterName)) return DELETE_ONLINE; Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `players` WHERE `name` LIKE " << db.escapeString(characterName) << " AND `account_id` = " << accountId << " AND `deleted` = 0 LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return DELETE_INTERNAL; uint32_t id = result->getNumber<uint32_t>("id"); House* house = g_game.map.houses.getHouseByPlayerId(id); if(house) return DELETE_HOUSE; /* if(IOGuild::getInstance()->getGuildLevel(id) == 3) return DELETE_LEADER; */ query.str(""); query << "UPDATE `players` SET `deleted` = 1 WHERE `id` = " << id << ";"; if(!db.executeQuery(query.str())) return DELETE_INTERNAL; query.str(""); query << "DELETE FROM `guild_invites` WHERE `player_id` = " << id; db.executeQuery(query.str()); query.str(""); query << "DELETE FROM `player_viplist` WHERE `vip_id` = " << id; db.executeQuery(query.str()); /* for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { VIPListSet::iterator it_ = it->second->VIPList.find(id); if(it_ != it->second->VIPList.end()) it->second->VIPList.erase(it_); } */ return DELETE_SUCCESS; } bool IOLoginData::playerExists(uint32_t guid, bool multiworld /*= false*/, bool checkCache /*= true*/) { if(checkCache) { NameCacheMap::iterator it = nameCacheMap.find(guid); if(it != nameCacheMap.end()) return true; } Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `name` FROM `players` WHERE `id` = " << guid << " AND `deleted` = 0"; query << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; const std::string name = result->getString("name"); nameCacheMap[guid] = name; return true; } bool IOLoginData::playerExists(std::string& name, bool multiworld /*= false*/, bool checkCache /*= true*/) { if(checkCache) { GuidCacheMap::iterator it = guidCacheMap.find(name); if(it != guidCacheMap.end()) { name = it->first; return true; } } Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id`, `name` FROM `players` WHERE `name` LIKE " << db.escapeString(name); /*<< " AND `deleted` = 0"; */ query << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; name = result->getString("name"); guidCacheMap[name] = result->getNumber<int32_t>("id"); return true; } // -- iologindata.h find this #include "database.h" and place this right underneath // account manager enum DeleteCharacter_t { DELETE_INTERNAL, DELETE_LEADER, DELETE_HOUSE, DELETE_ONLINE, DELETE_SUCCESS }; // -- find this class IOLoginData { public: and add this under it // account manager virtual ~IOLoginData() {} static IOLoginData* getInstance() { static IOLoginData instance; return &instance; } // -- find this static AccountType_t getAccountType(uint32_t accountId); and place this right below it // account manager bool accountIdExists(uint32_t accountId); bool accountNameExists(const std::string& name); bool getAccountId(const std::string& name, uint32_t& number); bool getNameByGuid(uint32_t guid, std::string& name); bool playerExists(uint32_t guid, bool multiworld = false, bool checkCache = true); bool playerExists(std::string& name, bool multiworld = false, bool checkCache = true); bool changeName(uint32_t guid, std::string newName, std::string oldName); bool createCharacter(uint32_t accountId, std::string characterName, uint32_t vocationId /* int32_t vocationId */, uint16_t sex); DeleteCharacter_t deleteCharacter(uint32_t accountId, const std::string characterName); bool getPassword(uint32_t accountId, std::string& password, std::string name = ""); bool setPassword(uint32_t accountId, std::string newPassword); bool validRecoveryKey(uint32_t accountId, std::string recoveryKey); bool setRecoveryKey(uint32_t accountId, std::string newRecoveryKey); uint64_t createAccount(std::string name, std::string password); // -- find this static void removePremiumDays(uint32_t accountId, int32_t removeDays); and place this right below it // account manager protected: struct StringCompareCase { bool operator()(const std::string& l, const std::string& r) const { return strcasecmp(l.c_str(), r.c_str()) < 0; } }; typedef std::map<std::string, uint32_t, StringCompareCase> GuidCacheMap; GuidCacheMap guidCacheMap; typedef std::map<uint32_t, std::string> NameCacheMap; NameCacheMap nameCacheMap; // -- luascript.cpp find this registerEnum(ZONE_NORMAL) and place this underneath // account manager registerEnum(MANAGER_NONE) registerEnum(MANAGER_NEW) registerEnum(MANAGER_ACCOUNT) registerEnum(MANAGER_NAMELOCK) // -- find this registerMethod("Player", "getLastLogout", LuaScriptInterface::luaPlayerGetLastLogout); and place this right underneath // account manager registerMethod("Player", "getAccountManager", LuaScriptInterface::luaGetPlayerAccountManager); // -- find this int LuaScriptInterface::luaPlayerGetLastLogout(lua_State* L) { // player:getLastLogout() Player* player = getUserdata<Player>(L, 1); if (player) { lua_pushnumber(L, player->getLastLogout()); } else { lua_pushnil(L); } return 1; } and place this under it int32_t LuaScriptInterface::luaGetPlayerAccountManager(lua_State* L) { // player:getAccountManager() Player* player = getUserdata<Player>(L, 1); if (player) { lua_pushnumber(L, player->accountManager); } else { lua_pushnil(L); } return 1; } luascript.h find this static int luaPlayerGetLastLogout(lua_State* L); and place this under it // account manager static int luaGetPlayerAccountManager(lua_State* L); // -- map.cpp look for bool Map:placeCreature(const Position& centerPos, Creature* creature, bool extendedPos/* = false*/, bool forceLogin/* = false*/) look for this Tile* tile = getTile(centerPos.x, centerPos.y, centerPos.z); if (tile) { placeInPZ = tile->hasFlag(TILESTATE_PROTECTIONZONE); ReturnValue ret = tile->queryAdd(0, *creature, 1, FLAG_IGNOREBLOCKITEM); foundTile = forceLogin || ret == RETURNVALUE_NOERROR || ret == RETURNVALUE_PLAYERISNOTINVITED; } else { placeInPZ = false; foundTile = false; } and replace it with this Tile* tile = getTile(centerPos.x, centerPos.y, centerPos.z); if (tile) { placeInPZ = tile->hasFlag(TILESTATE_PROTECTIONZONE); // account manager uint32_t flags = FLAG_IGNOREBLOCKITEM; if(creature->isAccountManager()) flags |= FLAG_IGNOREBLOCKCREATURE; // -- ReturnValue ret = tile->queryAdd(0, *creature, 1, flags); foundTile = forceLogin || ret == RETURNVALUE_NOERROR || ret == RETURNVALUE_PLAYERISNOTINVITED; } else { placeInPZ = false; foundTile = false; } player.cpp find this #include <bitset> and place this under it // account manager #include "ban.h" // -- look for this Player::Player(ProtocolGame_ptr p) : Creature(), lastPing(OTSYS_TIME()), lastPong(lastPing), inbox(new Inbox(ITEM_INBOX)), client(std::move(p)) { inbox->incrementReferenceCounter(); } and replace it with this Player::Player(ProtocolGame_ptr p) : Creature(), lastPing(OTSYS_TIME()), lastPong(lastPing), inbox(new Inbox(ITEM_INBOX)), client(std::move(p)) { // account manager for(int8_t i = 0; i <= states; i++) { talkState[i] = false; } accountManager = MANAGER_NONE; // -- inbox->incrementReferenceCounter(); } add this // account manager void Player::manageAccount(const std::string &text) { std::stringstream msg; msg << "Account Manager: "; bool noSwap = true; switch(accountManager) { case MANAGER_NAMELOCK: { if(!talkState[1]) { managerString = text; trimString(managerString); if(managerString.length() < 4) msg << "Your name you want is too short, please select a longer name."; else if(managerString.length() > 20) msg << "The name you want is too long, please select a shorter name."; else if(!isValidName(managerString)) msg << "That name seems to contain invalid symbols, please choose another name."; else if(IOLoginData::getInstance()->playerExists(managerString, true)) msg << "A player with that name already exists, please choose another name."; else { std::string tmp = asLowerCaseString(managerString); if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "cm " && tmp.substr(0, 3) != "gm ") { talkState[1] = true; talkState[2] = true; msg << managerString << ", are you sure?"; } else msg << "Your character is not a staff member, please tell me another name!"; } } else if(checkText(text, "no") && talkState[2]) { talkState[1] = talkState[2] = false; msg << "What else would you like to name your character?"; } else if(checkText(text, "yes") && talkState[2]) { if(!IOLoginData::getInstance()->playerExists(managerString, true)) { uint32_t tmp = IOLoginData::getInstance()->getGuidByName(managerString2); if(tmp != 0 && IOLoginData::getInstance()->changeName(tmp, managerString, managerString2) && IOBan::isPlayerNamelocked(tmp)) { if(House* house = g_game.map.houses.getHouseByPlayerId(tmp)) house->updateDoorDescription(managerString); talkState[1] = true; talkState[2] = false; msg << "Your character has been successfully renamed, you should now be able to login at it without any problems."; } else { talkState[1] = talkState[2] = false; msg << "Failed to change your name, please try again."; } } else { talkState[1] = talkState[2] = false; msg << "A player with that name already exists, please choose another name."; } } else msg << "Sorry, but I can't understand you, please try to repeat that!"; break; } case MANAGER_ACCOUNT: { // pr(" manage account case ", managerNumber); Account account = IOLoginData::getInstance()->loadAccount(managerNumber); if(checkText(text, "cancel") || (checkText(text, "account") && !talkState[1])) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Do you want to change your 'password', add a 'character', or 'delete' a character?"; } else if(checkText(text, "delete") && talkState[1]) { talkState[1] = false; talkState[2] = true; msg << "Which character would you like to delete?"; } else if(talkState[2]) { std::string tmp = text; trimString(tmp); if(!isValidName(tmp, false)) msg << "That name contains invalid characters, try to say your name again, you might have typed it wrong."; else { talkState[2] = false; talkState[3] = true; managerString = tmp; msg << "Do you really want to delete the character named " << managerString << "?"; } } else if(checkText(text, "yes") && talkState[3]) { switch(IOLoginData::getInstance()->deleteCharacter(managerNumber, managerString)) { case DELETE_INTERNAL: msg << "An error occured while deleting your character. Either the character does not belong to you or it doesn't exist."; break; case DELETE_SUCCESS: msg << "Your character has been deleted."; break; case DELETE_HOUSE: msg << "Your character owns a house. To make sure you really want to lose your house by deleting your character, you have to login and leave the house or pass it to someone else first."; break; case DELETE_LEADER: msg << "Your character is the leader of a guild. You need to disband or pass the leadership someone else to delete your character."; break; case DELETE_ONLINE: msg << "A character with that name is currently online, to delete a character it has to be offline."; break; } talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else if(checkText(text, "no") && talkState[3]) { talkState[1] = true; talkState[3] = false; msg << "Tell me what character you want to delete."; } else if(checkText(text, "password") && talkState[1]) { talkState[1] = false; talkState[4] = true; msg << "Tell me your new password please."; } else if(talkState[4]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 6) msg << "That password is too short, at least 6 digits are required. Please select a longer password."; else if(!isValidPassword(tmp)) msg << "Your password contains invalid characters... please tell me another one."; else { talkState[4] = false; talkState[5] = true; managerString = tmp; msg << "Should '" << managerString << "' be your new password?"; } } else if(checkText(text, "yes") && talkState[5]) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; IOLoginData::getInstance()->setPassword(managerNumber, managerString); msg << "Your password has been changed."; } else if(checkText(text, "no") && talkState[5]) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Then not."; } else if(checkText(text, "character") && talkState[1]) { if(account.characters.size() <= 15) { talkState[1] = false; talkState[6] = true; msg << "What would you like as your character name?"; } else { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Your account reach the limit of 15 players, you can 'delete' a character if you want to create a new one."; } } else if(talkState[6]) { managerString = text; trimString(managerString); if(managerString.length() < 4) msg << "Your name you want is too short, please select a longer name."; else if(managerString.length() > 20) msg << "The name you want is too long, please select a shorter name."; else if(!isValidName(managerString)) msg << "That name seems to contain invalid symbols, please choose another name."; else if(IOLoginData::getInstance()->playerExists(managerString, true)) msg << "A player with that name already exists, please choose another name."; else { std::string tmp = asLowerCaseString(managerString); if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "cm " && tmp.substr(0, 3) != "gm ") { talkState[6] = false; talkState[7] = true; msg << managerString << ", are you sure?"; } else msg << "Your character is not a staff member, please tell me another name!"; } } else if(checkText(text, "no") && talkState[7]) { talkState[6] = true; talkState[7] = false; msg << "What else would you like to name your character?"; } else if(checkText(text, "yes") && talkState[7]) { talkState[7] = false; talkState[8] = true; msg << "Should your character be a 'male' or a 'female'."; } else if(talkState[8] && (checkText(text, "female") || checkText(text, "male"))) { talkState[8] = false; talkState[9] = true; if(checkText(text, "female")) { msg << "A female, are you sure?"; managerSex = PLAYERSEX_FEMALE; } else { msg << "A male, are you sure?"; managerSex = PLAYERSEX_MALE; } } else if(checkText(text, "no") && talkState[9]) { talkState[8] = true; talkState[9] = false; msg << "Tell me... would you like to be a 'male' or a 'female'?"; } else if(checkText(text, "yes") && talkState[9]) { if(g_config.getBoolean(ConfigManager::AM_CHOOSEVOC)) { talkState[9] = false; talkState[11] = true; bool firstPart = true; g_vocations.getVocationMap(firstPart, msg); } else if(!IOLoginData::getInstance()->playerExists(managerString, true)) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex)) msg << "Your character has been created."; else msg << "Your character couldn't be created, please try again."; } else { talkState[6] = true; talkState[9] = false; msg << "A player with that name already exists, please choose another name."; } } else if(talkState[11]) { g_vocations.getVocationConfirmation(text, talkState[11], talkState[12], managerNumber2, msg); if(msg.str().length() == 17) msg << "I don't understand what vocation you would like to be... could you please repeat it?"; } else if(checkText(text, "yes") && talkState[12]) { if(!IOLoginData::getInstance()->playerExists(managerString, true)) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex)) msg << "Your character has been created."; else msg << "Your character couldn't be created, please try again."; } else { talkState[6] = true; talkState[9] = false; msg << "A player with that name already exists, please choose another name."; } } else if(checkText(text, "no") && talkState[12]) { talkState[11] = true; talkState[12] = false; msg << "No? Then what would you like to be?"; } else if(checkText(text, "recovery key") && talkState[1]) { talkState[1] = false; talkState[10] = true; msg << "Would you like a recovery key?"; } else if(checkText(text, "yes") && talkState[10]) { // std::cout << "recovery key " << account.recoveryKey << " empty? " << account.recoveryKey.empty() <<std::endl; /* if(!account.recoveryKey.empty()) msg << "Sorry, you already have a recovery key, for security reasons I may not give you a new one."; else { managerString = generateRecoveryKey(4, 4); IOLoginData::getInstance()->setRecoveryKey(managerNumber, managerString); msg << "Your recovery key is: " << managerString << "."; } */ talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else if(checkText(text, "no") && talkState[10]) { msg << "Then not."; talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else msg << "Please read the latest message that I have specified, I don't understand the current requested action."; break; } case MANAGER_NEW: { if(checkText(text, "account") && !talkState[1]) { msg << "What would you like your password to be?"; talkState[1] = true; talkState[2] = true; } else if(talkState[2]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 6) msg << "That password is too short, at least 6 digits are required. Please select a longer password."; else if(!isValidPassword(tmp)) msg << "Your password contains invalid characters... please tell me another one."; else { talkState[3] = true; talkState[2] = false; managerString = tmp; msg << managerString << " is it? 'yes' or 'no'?"; } } else if(checkText(text, "yes") && talkState[3]) { if(g_config.getBoolean(ConfigManager::AM_GENERATE_ACCOUNT_NUMBER)) { do sprintf(managerChar, "%d%d%d%d%d%d%d", random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9)); while(IOLoginData::getInstance()->accountNameExists(managerChar)); uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString); if(id) { accountManager = MANAGER_ACCOUNT; managerNumber = id; noSwap = talkState[1] = false; msg << "Your account has been created, you may manage it now, but remember your account name: '" << managerChar << "' and password: '" << managerString << "'! If the account name is too hard to remember, please note it somewhere."; } else msg << "Your account could not be created, please try again."; for(int8_t i = 2; i <= 5; i++) talkState[i] = false; } else { msg << "What would you like your account name to be?"; talkState[3] = false; talkState[4] = true; } } else if(checkText(text, "no") && talkState[3]) { talkState[2] = true; talkState[3] = false; msg << "What would you like your password to be then?"; } else if(talkState[4]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 3) msg << "That account name is too short, at least 3 digits are required. Please select a longer account name."; else if(tmp.length() > 25) msg << "That account name is too long, not more than 25 digits are required. Please select a shorter account name."; else if(!isValidAccountName(tmp)) msg << "Your account name contains invalid characters, please choose another one."; else if(asLowerCaseString(tmp) == asLowerCaseString(managerString)) msg << "Your account name cannot be same as password, please choose another one."; else { sprintf(managerChar, "%s", tmp.c_str()); msg << managerChar << ", are you sure?"; talkState[4] = false; talkState[5] = true; } } else if(checkText(text, "yes") && talkState[5]) { if(!IOLoginData::getInstance()->accountNameExists(managerChar)) { uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString); if(id) { accountManager = MANAGER_ACCOUNT; managerNumber = id; noSwap = talkState[1] = false; msg << "Your account has been created, you may manage it now, but remember your account name: '" << managerChar << "' and password: '" << managerString << "'!"; } else msg << "Your account could not be created, please try again."; for(int8_t i = 2; i <= 5; i++) talkState[i] = false; } else { msg << "An account with that name already exists, please try another account name."; talkState[4] = true; talkState[5] = false; } } else if(checkText(text, "no") && talkState[5]) { talkState[5] = false; talkState[4] = true; msg << "What else would you like as your account name?"; } else if(checkText(text, "recover") && !talkState[6]) { talkState[6] = true; talkState[7] = true; msg << "What was your account name?"; } else if(talkState[7]) { managerString = text; if(IOLoginData::getInstance()->getAccountId(managerString, (uint32_t&)managerNumber)) { talkState[7] = false; talkState[8] = true; msg << "What was your recovery key?"; } else { msg << "Sorry, but account with such name doesn't exists."; talkState[6] = talkState[7] = false; } } else if(talkState[8]) { managerString2 = text; if(IOLoginData::getInstance()->validRecoveryKey(managerNumber, managerString2) && managerString2 != "0") { sprintf(managerChar, "%s%d", g_config.getString(ConfigManager::SERVER_NAME).c_str(), random_range(100, 999)); IOLoginData::getInstance()->setPassword(managerNumber, managerChar); msg << "Correct! Your new password is: " << managerChar << "."; } else msg << "Sorry, but this key doesn't match to account you gave me."; talkState[7] = talkState[8] = false; } else msg << "Sorry, but I can't understand you, please try to repeat that."; break; } default: return; break; } sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, msg.str().c_str()); if(!noSwap) sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Hint: Type 'account' to manage your account and if you want to start over then type 'cancel'."); } // -- player.h find class Guild; and add this below it // account manager enum AccountManager_t { MANAGER_NONE, MANAGER_NEW, MANAGER_ACCOUNT, MANAGER_NAMELOCK }; // -- next find this void addList() override; and add this below // account manager void manageAccount(const std::string& text); bool isAccountManager() const {return (accountManager != MANAGER_NONE);} template <typename T> inline void pr(std::string s, T const& v) { std::cout << s << v << std::endl; }; // -- find this void disconnect() { if (client) { client->disconnect(); } } place this under it // account manager bool isVirtual() const { return (getID() == 0); } // -- find this int32_t idleTime = 0; and place this below it // account manager int32_t managerNumber; uint32_t managerNumber2; std::string managerString, managerString2; int8_t states = 13; bool talkState[13]; // -- find this OperatingSystem_t operatingSystem = CLIENTOS_NONE; and place this below it // account manager AccountManager_t accountManager = MANAGER_NONE; PlayerSex_t managerSex; char managerChar[100]; // -- protocolgame.cpp find this void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem) find this void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem) { //dispatcher thread Player* foundPlayer = g_game.getPlayerByName(name); if (!foundPlayer || g_config.getBoolean(ConfigManager::ALLOW_CLONES)) { player = new Player(getThis()); player->setName(name); player->incrementReferenceCounter(); player->setID(); if (!IOLoginData::preloadPlayer(player, name)) { disconnectClient("Your character could not be loaded."); return; } if (IOBan::isPlayerNamelocked(player->getGUID())) { disconnectClient("Your character has been namelocked."); return; } and replace it with this void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem) { //dispatcher thread Player* foundPlayer = g_game.getPlayerByName(name); if(!foundPlayer || name == "Account Manager" || g_config.getBoolean(ConfigManager::ALLOW_CLONES) ) { player = new Player(getThis()); player->setName(name); player->incrementReferenceCounter(); player->setID(); if (!IOLoginData::preloadPlayer(player, name)) { disconnectClient("Your character could not be loaded."); return; } if (IOBan::isPlayerNamelocked(player->getGUID()) && accountId != 1) { if(g_config.getBoolean(ConfigManager::NAMELOCK_MANAGER)) { player->name = "Account Manager"; player->accountManager = MANAGER_NAMELOCK; player->managerNumber = accountId; player->managerString2 = name; } else { disconnectClient("Your character has been namelocked."); return; } }else if(player->getName() == "Account Manager" && g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)) { if(accountId != 1) { player->accountManager = MANAGER_ACCOUNT; player->managerNumber = accountId; } else { player->accountManager = MANAGER_NEW; } } in that same method underneath this if (g_game.getGameState() == GAME_STATE_CLOSING && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("The game is just going down.\nPlease try again later."); return; } if (g_game.getGameState() == GAME_STATE_CLOSED && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("Server is currently closed.\nPlease try again later."); return; } place this // account manager if (g_config.getBoolean(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && !player->isAccountManager() && player->getAccountType() < ACCOUNT_TYPE_GAMEMASTER && g_game.getPlayerByAccount(player->getAccount())) { bool found = false; std::vector<Player*> tmp; tmp.push_back(g_game.getPlayerByAccount(accountId)); for(std::vector<Player*>::iterator it = tmp.begin(); it != tmp.end(); ++it) { if((*it)->getName() != name) continue; found = true; break; } if(tmp.size() > 0 && !found) { disconnectClient("You may only login with one character\nof your account at the same time."); return; } } // -- find this void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg) inside of there you are going to look for this std::string& token = sessionArgs[2]; uint32_t tokenTime = 0; try { tokenTime = std::stoul(sessionArgs[3]); } catch (const std::invalid_argument&) { disconnectClient("Malformed token packet."); return; } catch (const std::out_of_range&) { disconnectClient("Token time is too long."); return; } if (accountName.empty()) { disconnectClient("You must enter your account name."); return; } replace it with this // account manager if (accountName.empty()) { accountName = "1"; } if (password.empty()) { password = "1"; } // -- within that same method you will look for this uint32_t accountId = IOLoginData::gameworldAuthentication(accountName, password, characterName, token, tokenTime); if (accountId == 0) { disconnectClient("Account name or password is not correct."); return; } g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem))); } and replace it with this uint32_t accountId = atoi(accountName.c_str()); g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem))); } this whole method you are going to replace void ProtocolGame::parsePacket(NetworkMessage& msg) void ProtocolGame::parsePacket(NetworkMessage& msg) { if (!acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getLength() <= 0) { return; } uint8_t recvbyte = msg.getByte(); if (!player) { if (recvbyte == 0x0F) { disconnect(); } return; } //a dead player can not performs actions if (player->isRemoved() || player->getHealth() <= 0) { if (recvbyte == 0x0F) { disconnect(); return; } if (recvbyte != 0x14) { return; } } // account manager if(player->isAccountManager()) { switch(recvbyte) { case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break; break; case 0x96: parseSay(msg); break; default: sendCancelWalk(); break; } } else { // -- switch (recvbyte) { case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break; case 0x1D: addGameTask(&Game::playerReceivePingBack, player->getID()); break; case 0x1E: addGameTask(&Game::playerReceivePing, player->getID()); break; case 0x32: parseExtendedOpcode(msg); break; //otclient extended opcode case 0x64: parseAutoWalk(msg); break; case 0x65: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); break; case 0x66: addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); break; case 0x67: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); break; case 0x68: addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); break; case 0x69: addGameTask(&Game::playerStopAutoWalk, player->getID()); break; case 0x6A: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); break; case 0x6B: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); break; case 0x6C: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); break; case 0x6D: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); break; case 0x6F: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_NORTH); break; case 0x70: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_EAST); break; case 0x71: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_SOUTH); break; case 0x72: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_WEST); break; case 0x77: parseEquipObject(msg); break; case 0x78: parseThrow(msg); break; case 0x79: parseLookInShop(msg); break; case 0x7A: parsePlayerPurchase(msg); break; case 0x7B: parsePlayerSale(msg); break; case 0x7C: addGameTask(&Game::playerCloseShop, player->getID()); break; case 0x7D: parseRequestTrade(msg); break; case 0x7E: parseLookInTrade(msg); break; case 0x7F: addGameTask(&Game::playerAcceptTrade, player->getID()); break; case 0x80: addGameTask(&Game::playerCloseTrade, player->getID()); break; case 0x82: parseUseItem(msg); break; case 0x83: parseUseItemEx(msg); break; case 0x84: parseUseWithCreature(msg); break; case 0x85: parseRotateItem(msg); break; case 0x87: parseCloseContainer(msg); break; case 0x88: parseUpArrowContainer(msg); break; case 0x89: parseTextWindow(msg); break; case 0x8A: parseHouseWindow(msg); break; case 0x8C: parseLookAt(msg); break; case 0x8D: parseLookInBattleList(msg); break; case 0x8E: /* join aggression */ break; case 0x96: parseSay(msg); break; case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break; case 0x98: parseOpenChannel(msg); break; case 0x99: parseCloseChannel(msg); break; case 0x9A: parseOpenPrivateChannel(msg); break; case 0x9E: addGameTask(&Game::playerCloseNpcChannel, player->getID()); break; case 0xA0: parseFightModes(msg); break; case 0xA1: parseAttack(msg); break; case 0xA2: parseFollow(msg); break; case 0xA3: parseInviteToParty(msg); break; case 0xA4: parseJoinParty(msg); break; case 0xA5: parseRevokePartyInvite(msg); break; case 0xA6: parsePassPartyLeadership(msg); break; case 0xA7: addGameTask(&Game::playerLeaveParty, player->getID()); break; case 0xA8: parseEnableSharedPartyExperience(msg); break; case 0xAA: addGameTask(&Game::playerCreatePrivateChannel, player->getID()); break; case 0xAB: parseChannelInvite(msg); break; case 0xAC: parseChannelExclude(msg); break; case 0xBE: addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); break; case 0xC9: /* update tile */ break; case 0xCA: parseUpdateContainer(msg); break; case 0xCB: parseBrowseField(msg); break; case 0xCC: parseSeekInContainer(msg); break; case 0xD2: addGameTask(&Game::playerRequestOutfit, player->getID()); break; case 0xD3: parseSetOutfit(msg); break; case 0xD4: parseToggleMount(msg); break; case 0xDC: parseAddVip(msg); break; case 0xDD: parseRemoveVip(msg); break; case 0xDE: parseEditVip(msg); break; case 0xE6: parseBugReport(msg); break; case 0xE7: /* thank you */ break; case 0xE8: parseDebugAssert(msg); break; case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break; case 0xF1: parseQuestLine(msg); break; case 0xF2: parseRuleViolationReport(msg); break; case 0xF3: /* get object info */ break; case 0xF4: parseMarketLeave(); break; case 0xF5: parseMarketBrowse(msg); break; case 0xF6: parseMarketCreateOffer(msg); break; case 0xF7: parseMarketCancelOffer(msg); break; case 0xF8: parseMarketAcceptOffer(msg); break; case 0xF9: parseModalWindowAnswer(msg); break; default: // std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl; break; } } // end of else if (msg.isOverrun()) { disconnect(); } } protocollogin.cpp within this method void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) find this std::string accountName = msg.getString(); if (accountName.empty()) { disconnectClient("Invalid account name.", version); return; } std::string password = msg.getString(); if (password.empty()) { disconnectClient("Invalid password.", version); return; } replace it with this std::string accountName = msg.getString(); if (accountName.empty()) { // account manager if(!g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)){ disconnectClient("Invalid account name.", version); return; } accountName = "1"; } std::string password = msg.getString(); if (password.empty()) { // account manager if(!g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)){ disconnectClient("Invalid password.", version); return; } password = "1"; // sha1 "356a192b7913b04c54574d18c28d46e6395428ab" } tools.cpp add this to the bottom of the file // account manager int32_t round(float v) { int32_t t = (int32_t)std::floor(v); if((v - t) > 0.5) return t + 1; return t; } uint32_t rand24b() { return ((rand() << 12) ^ (rand())) & (0xFFFFFF); } float box_muller(float m, float s) { // normal random variate generator // mean m, standard deviation s float x1, x2, w, y1; static float y2; static bool useLast = false; if(useLast) // use value from previous call { y1 = y2; useLast = false; return (m + y1 * s); } do { double r1 = (((float)(rand()) / RAND_MAX)); double r2 = (((float)(rand()) / RAND_MAX)); x1 = 2.0 * r1 - 1.0; x2 = 2.0 * r2 - 1.0; w = x1 * x1 + x2 * x2; } while(w >= 1.0); w = sqrt((-2.0 * log(w)) / w); y1 = x1 * w; y2 = x2 * w; useLast = true; return (m + y1 * s); } int32_t random_range(int32_t lowestNumber, int32_t highestNumber, DistributionType_t type /*= DISTRO_UNIFORM*/) { if(highestNumber == lowestNumber) return lowestNumber; if(lowestNumber > highestNumber) std::swap(lowestNumber, highestNumber); switch(type) { case DISTRO_UNIFORM: return (lowestNumber + ((int32_t)rand24b() % (highestNumber - lowestNumber + 1))); case DISTRO_NORMAL: return (lowestNumber + int32_t(float(highestNumber - lowestNumber) * (float)std::min((float)1, std::max((float)0, box_muller(0.5, 0.25))))); default: break; } const float randMax = 16777216; return (lowestNumber + int32_t(float(highestNumber - lowestNumber) * float(1.f - sqrt((1.f * rand24b()) / randMax)))); } bool isLowercaseLetter(char character) { return (character >= 97 && character <= 122); } bool isUppercaseLetter(char character) { return (character >= 65 && character <= 90); } bool isNumber(char character) { return (character >= 48 && character <= 57); } bool isNumbers(std::string text) { uint32_t textLength = text.length(); for(uint32_t size = 0; size < textLength; size++) { if(!isNumber(text[size])) return false; } return true; } bool checkText(std::string text, std::string str) { trimString(text); return asLowerCaseString(text) == str; } std::string generateRecoveryKey(int32_t fieldCount, int32_t fieldLenght) { std::stringstream key; int32_t i = 0, j = 0, lastNumber = 99, number = 0; char character = 0, lastCharacter = 0; bool madeNumber = false, madeCharacter = false; do { do { madeNumber = madeCharacter = false; if((bool)random_range(0, 1)) { number = random_range(2, 9); if(number != lastNumber) { key << number; lastNumber = number; madeNumber = true; } } else { character = (char)random_range(65, 90); if(character != lastCharacter) { key << character; lastCharacter = character; madeCharacter = true; } } } while((!madeCharacter && !madeNumber) ? true : (++j && j < fieldLenght)); lastCharacter = character = number = j = 0; lastNumber = 99; if(i < fieldCount - 1) key << "-"; } while(++i && i < fieldCount); return key.str(); } bool isValidAccountName(std::string text) { toLowerCaseString(text); uint32_t textLength = text.length(); for(uint32_t size = 0; size < textLength; size++) { if(!isLowercaseLetter(text[size]) && !isNumber(text[size])) return false; } return true; } bool isValidPassword(std::string text) { toLowerCaseString(text); uint32_t textLength = text.length(); for(uint32_t size = 0; size < textLength; size++) { if(!isLowercaseLetter(text[size]) && !isNumber(text[size]) && !isPasswordCharacter(text[size])) return false; } return true; } bool isPasswordCharacter(char character) { return ((character >= 33 && character <= 47) || (character >= 58 && character <= 64) || (character >= 91 && character <= 96) || (character >= 123 && character <= 126)); } bool isValidName(std::string text, bool forceUppercaseOnFirstLetter/* = true*/) { uint32_t textLength = text.length(), lenBeforeSpace = 1, lenBeforeQuote = 1, lenBeforeDash = 1, repeatedCharacter = 0; char lastChar = 32; if(forceUppercaseOnFirstLetter) { if(!isUppercaseLetter(text[0])) return false; } else if(!isLowercaseLetter(text[0]) && !isUppercaseLetter(text[0])) return false; for(uint32_t size = 1; size < textLength; size++) { if(text[size] != 32) { lenBeforeSpace++; if(text[size] != 39) lenBeforeQuote++; else { if(lenBeforeQuote <= 1 || size == textLength - 1 || text[size + 1] == 32) return false; lenBeforeQuote = 0; } if(text[size] != 45) lenBeforeDash++; else { if(lenBeforeDash <= 1 || size == textLength - 1 || text[size + 1] == 32) return false; lenBeforeDash = 0; } if(text[size] == lastChar) { repeatedCharacter++; if(repeatedCharacter > 2) return false; } else repeatedCharacter = 0; lastChar = text[size]; } else { if(lenBeforeSpace <= 1 || size == textLength - 1 || text[size + 1] == 32) return false; lenBeforeSpace = lenBeforeQuote = lenBeforeDash = 0; } if(!(isLowercaseLetter(text[size]) || text[size] == 32 || text[size] == 39 || text[size] == 45 || (isUppercaseLetter(text[size]) && text[size - 1] == 32))) return false; } return true; } // -- tools.h find this #include "enums.h" and place this under it // account manager enum DistributionType_t { DISTRO_UNIFORM, DISTRO_SQUARE, DISTRO_NORMAL }; enum FileType_t { FILE_TYPE_XML, FILE_TYPE_LOG, FILE_TYPE_OTHER, FILE_TYPE_CONFIG, FILE_TYPE_MOD }; // -- find this std::string ucfirst(std::string str); std::string ucwords(std::string str); bool booleanString(const std::string& str); place this under it // account manager bool isValidAccountName(std::string text); bool isValidPassword(std::string text); bool isValidName(std::string text, bool forceUppercaseOnFirstLetter = true); bool isNumber(char character); bool isNumbers(std::string text); bool isPasswordCharacter(char character); bool checkText(std::string text, std::string str); std::string generateRecoveryKey(int32_t fieldCount, int32_t fieldLength); int32_t random_range(int32_t lowest_number, int32_t highest_number, DistributionType_t type = DISTRO_UNIFORM); int32_t round(float v); uint32_t rand24b(); float box_muller(float m, float s); // -- vocation.cpp // account manager void Vocations::getVocationMap(bool &firstPart, std::stringstream &msg) { for(auto it = vocationsMap.begin(); it != vocationsMap.end(); ++it) { bool isXml = g_config.getBoolean(ConfigManager::USE_XML); if(it->first == ((isXml) ? it->second.getFromVocation() : it->second.getId()) && it->first != 0) { if(firstPart) { msg << "What do you want to be... " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()); firstPart = false; } else if(it->first - 1 != 0){ msg << ", " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()); } else{ msg << " or " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()) << "."; } } } } // needs to set the proper vocation id void Vocations::getVocationConfirmation(std::string text, bool &talkState1, bool &talkState2, uint32_t &number /* int32_t &number */, std::stringstream &msg) { for(auto it = vocationsMap.begin(); it != vocationsMap.end(); ++it) { bool isXml = g_config.getBoolean(ConfigManager::USE_XML); std::string tmp = asLowerCaseString(it->second.getVocName()); if(checkText(text, tmp) && it != vocationsMap.end() && it->first == ((isXml) ? it->second.getFromVocation() : it->second.getId()) && it->first != 0) { msg << "So you would like to be " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()) << "... are you sure?"; number = it->first; talkState1 = false; talkState2 = true; } } } vocation.h find uint16_t getPromotedVocation(uint16_t vocationId) const; and place this underneath // account manager void getVocationMap(bool &firstPart, std::stringstream &msg); void getVocationConfirmation(std::string, bool&, bool&, uint32_t& /* int32_t& */, std::stringstream&); // -- modify your login.lua function onLogin(player) local accountManager = player:getAccountManager() if(accountManager == MANAGER_NONE) then local loginStr = "Welcome to " .. configManager.getString(configKeys.SERVER_NAME) .. "!" if player:getLastLoginSaved() <= 0 then loginStr = loginStr .. " Please choose your outfit." player:sendOutfitWindow() else if loginStr ~= "" then player:sendTextMessage(MESSAGE_STATUS_DEFAULT, loginStr) end loginStr = string.format("Your last visit was on %s.", os.date("%a %b %d %X %Y", player:getLastLoginSaved())) end player:sendTextMessage(MESSAGE_STATUS_DEFAULT, loginStr) elseif(accountManager == MANAGER_NAMELOCK) then player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Hello, it appears that your character has been namelocked, what would you like as your new name?") elseif(accountManager == MANAGER_ACCOUNT) then player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Hello, type 'account' to manage your account and if you want to start over then type 'cancel'.") elseif(accountManager == MANAGER_NEW) then player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Hello, type 'account' to create an account or type 'recover' to recover an account.") end and finally add this to your config.lua -- Account Manager accountManager = true -- how many points do you want to give each account -- this applies only when they create the account vipPoints = 0 -- the default stats to start with experience = 0 -- uint64_t level = 1 soul = 100 -- uint8_t magic = 0 fist = 10 club = 10 sword = 10 axe = 10 shield = 10 distance = 10 fish = 10 -- incase you want to give the player a little starter money in their bank :) balance = 0 -- uint64_t offlineTrainingTime = 43200 -- int32_t stamina = 2520 -- uint16_t startTownId = 1 -- uint32_t temple_x = 0 temple_y = 0 temple_z = 0 baseHP = 150 baseMP = 0 baseCAP = 400 maleOutfit = 128 femaleOutfit = 136 -- give the player addons for their corresponding outfit if any lookAddons = 0 -- start the player off with a mount mountId = 0 chooseVocation = true generateAccountNumber = false useXML = true Here is a video demonstration of it working in OTX3 8.6, I have not made a video for it in TFS 1.3 because I added somethings to after making this video
  13. Olá venho por meio deste tópico, apresentar um pouquinho do meu trabalho! Gostaria de informa-los que não estou desenvolvendo com intuito de deixar o game online, estou cursando engenharia de software e preciso treinar POO, SQL entre outras tecnologias que estão presentes no Tibia. A Primeira etapa foi escolher um tema minha preferência é derivado, pokémon é a melhor opção pelo simples fato de já existir uma grande variedade de sprites disponíveis na internet. A segunda etapa foi escolher quais sources utilizar, as escolhas foram: OTClient (10.98) Commits on Apr 28, 2019. TheForgottenServer Commits on Apr 26, 2019. Estou utilizando a versão mais atualizada disponível até a data citada. IMPORTANTE: Todo sistema apresentado é de minha autoria, não utilizo base de terceiros até porque meu intuito aqui é desenvolver meus conhecimentos. Obs: trabalho com Linux. Primeiro print do projeto (start): Adicionado balls:
  14. Boa tarde meus queridos! A muito tempo não jogo e não participo de criação de OtServers. A minha dúvida hoje é: é possível criar os códigos em PYTHON 3.0 OU C++ ? Muito obrigado pela atenção!
  15. Nao sei se estou postando na area correta mas.... vamo la Um player esta visitando quase todos os server e derrubando por um sistema de party (ele se dá auto-party) com o bot fazendo enviar pacotes inválidos que acabam crashando a sua distro: depois que fiz isso, meu server voltou ao normal (ja esta 7 dias online, desde seu ultimo nuke) procurei e achei em outro forum, e vi um cidadão de deus que encontrou a solução. (Creditos: Gesior.pl) ele diz que o codigo é pra TFS 0.4 r3777 vamos ao que interessa: Em game.cpp (nas sources) , procure por: adicione isso daqui A CIMA dessa linha
  16. Um código simples para fazer o global server save, e logo após reiniciar o servidor. Adicione no Config.Lua shutdownAtGlobalSave = true globalSaveEnabled = true No Game.cpp adicione uma nova função bool Game::isRunning(const char* name) { PROCESSENTRY32 proc32; HANDLE hSnapshot; hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); proc32.dwSize = sizeof(PROCESSENTRY32); bool isRunning = false; if(Process32First(hSnapshot, &proc32)) { while(Process32Next(hSnapshot, &proc32)) { std::string filename_str = std::string(proc32.szExeFile); if(filename_str == name) { isRunning = true; break; } } } CloseHandle(hSnapshot); return isRunning; } Adicione em game.h bool isRunning(const char* name); Em Game.cpp procure por void Game::setGameState(GameState_t newState) E adicione logo a baixo. Scheduler::getInstance().stop(); Dispatcher::getInstance().stop(); E abaixo disso adicione const char* name = "AutoRun.exe"; if(!isRunning(name)) WinExec(name, SW_SHOWNORMAL); Em otsystem.h adicione um novo include #include <windows.h> Agora vamos anexar isso #include <tlhelp32.h> Esta feito agora basta compilar um programa chamado autorun.exe com o código a baixo. Após a compilação coloque o exe na pasta do servidor e inicie. #include <windows.h> #include <tlhelp32.h> #include <iostream> const int _time = 10; char* name = "Nazwa serwera.exe"; bool isRunning() { PROCESSENTRY32 proc32; HANDLE hSnapshot; hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); proc32.dwSize = sizeof(PROCESSENTRY32); std::cout << "Check the server is running." << std::endl; bool isRunning = false; if(Process32First(hSnapshot, &proc32)) { while(Process32Next(hSnapshot, &proc32)) { std::string filename_str = std::string(proc32.szExeFile); if(filename_str == name) { isRunning = true; break; } } } CloseHandle(hSnapshot); return isRunning; } bool checkServer() { while(true) { Sleep(_time * 1000); if(!isRunning()) { std::cout << "Run the server." << std::endl; WinExec(name, SW_SHOWNORMAL); return true; } } return false; } int main() { if(checkServer()) return 0; return 1; } Cade minhas badges? @Matk Creditos: Underewar,Osk
  17. Olá Reparei Que muitos Está Procurando essa alteração , em todo fórum só acha a versão 0.3.6. . e vim trazer 0.4 E OTX. OTX 2.1 procure por: Player.cpp if((!_weapon->hasExhaustion() || !hasCondition(CONDITION_EXHAUST)) && _weapon->useWeapon(this, weapon, attackedCreature)) Altere por: if(!_weapon->hasExhaustion() && _weapon->useWeapon(this, weapon, attackedCreature)) Usar runa enquanto corre. Em player.cpp, remova essa linha setNextAction(OTSYS_TIME() + getStepDuration(dir)); - TFS 0.4 Procure por: Player.cpp if((!_weapon->hasExhaustion() || !hasCondition(CONDITION_EXHAUST, EXHAUST_COMBAT)) && _weapon->useWeapon(this, item, attackedCreature)) Altere por : if(!_weapon->hasExhaustion() && _weapon->useWeapon(this, item, attackedCreature)) Usar runa enquanto corre. Em player.cpp, remova essa linha setNextAction(OTSYS_TIME() + getStepDuration(dir)); Créditos Usar Runa Enquanto corre - Xellath alterar para 0.4/otx 2.1 Eu !! As 2 Versão foi testado !!!
  18. Caso alguem precise desse sistema atualizado mande um email para underewar@gmail.com
  19. bom resolvi mexer um pouco com a rev 3884 e encontrei com um bug na que estou mexendo, que seria o seguinte, tudo que vc dar target ao cancelar vc toma DC, seja em monstros ou npc pra resolver segue essas alterações na source: protocollgame.cpp ache: void ProtocolGame::sendCancelTarget() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->put<char>(0xA3); msg->put<uint32_t>(0); //? creatureId? } } altere para: void ProtocolGame::sendCancelTarget() { NetworkMessage_ptr msg = getOutputBuffer(); if(msg) { TRACK_MESSAGE(msg); msg->put<char>(0xA3); } } de rebuild e compile.. problema resolvido
  20. Em luascript.cpp Em luascript.cpp getPlayerSecureMode (CID) Vamos criar esse comando Código C++: getPlayerFightMode (CID) Vamos criar esse comando Código C++: Simples e fácil vou deixar um exemplo para os leigos. Exemplo em lua: qual quer duvida poste aqui ,script é bem simples.
  21. Caso precise desse sistema atualizado entre em contato por email underewar@gmail.com
  22. Introdução : Muta um jogador no canal HELP por meio de um comando. game.cpp Procure por Game::playerSay, abaixo de player->setIdleTime(0) adicione : if (channelId == CHANNEL_HELP) { std::string helpmute = "0"; player->getStorage("455010", helpmute); time_t now = time(NULL); time_t seconds = atoi(helpmute.c_str()) - now; if (seconds > 0) { std::stringstream sec; sec << "You are muted for " << seconds << " seconds on this channel."; player->sendTextMessage(MSG_STATUS_SMALL, sec.str()); return false; } } data/talkactions/scripts/helpmute.lua : function onSay(cid, words, param) if param == '' then return doPlayerSendCancel(cid, 'Informe o nome do jogador e o tempo em segundos.') end local default = 600 local tmp = string.explode(param, ',') if not isCreature(getCreatureByName(tmp[1])) then return doPlayerSendCancel(cid, 'Jogador inexistente ou off-line.') end setPlayerStorageValue(getCreatureByName(tmp[1]), 455010, os.time() + (tonumber(tmp[2]) or default)) doPlayerSendCancel(cid, 'O jogador ' .. tmp[1] .. ' foi mutado.') return true end data/talkactions/talkactions.xml : <talkaction log="yes" group="4" access="3" words="/helpmute" event="script" value="helpmute.lua"/> Como utilizar? Para impedir um jogador de falar no Channel Help, utilize o comando /helpmute Playername, segundos. Para resetar os segundos, utilize o mesmo comando só que em segundos, coloque 0. Comando disponível apenas para a acessos superiores, configuração disponível no XML talkactions.xml. Versão do TFS: 0.4 Créditos: Lyu
  23. Estou com erro ao tentar acessar a aba Opções de Projetos no DevCpp. Acessei um tópico antigo e baixei os arquivos necessários, tentei com x64 e x32 mas ambos da erro: Li que, o DevCpp antigos não reconhecem mais certas funções então tentei também com a versão mais recente mas, da erro (Versão recente 5.11). collect2.exe: error: ld returned 1 exit status LEMBRANDO QUE: O erro no 5.11 é relacionado a esta linha: ${RM} $(OBJ) $(BIN) Makefile: (LINHA 23) ARQUIVOS BAIXADOS: DevCpp 5.11~ e 4.9~ Source trunk.r3884(Do tópico) Source ~~~(deste link) Estou fazendo algo de errado, caso sim, o que seria?
  24. Not tested but I wrote them anyway... this is a means of adding the missing stat information in TFS 1.3 & OTX 3 for 10.98 & up. This is the previous code protocolgame.cpp in TFS 1.3 void ProtocolGame::AddPlayerStats(NetworkMessage& msg) { msg.addByte(0xA0); msg.add<uint16_t>(std::min<int32_t>(player->getHealth(), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(std::min<int32_t>(player->getMaxHealth(), std::numeric_limits<uint16_t>::max())); msg.add<uint32_t>(player->getFreeCapacity()); msg.add<uint32_t>(player->getCapacity()); msg.add<uint64_t>(player->getExperience()); msg.add<uint16_t>(player->getLevel()); msg.addByte(player->getLevelPercent()); msg.add<uint16_t>(100); // base xp gain rate msg.add<uint16_t>(0); // xp voucher msg.add<uint16_t>(0); // low level bonus msg.add<uint16_t>(0); // xp boost msg.add<uint16_t>(100); // stamina multiplier (100 = x1.0) msg.add<uint16_t>(std::min<int32_t>(player->getMana(), std::numeric_limits<uint16_t>::max())); msg.add<uint16_t>(std::min<int32_t>(player->getMaxMana(), std::numeric_limits<uint16_t>::max())); msg.addByte(std::min<uint32_t>(player->getMagicLevel(), std::numeric_limits<uint8_t>::max())); msg.addByte(std::min<uint32_t>(player->getBaseMagicLevel(), std::numeric_limits<uint8_t>::max())); msg.addByte(player->getMagicLevelPercent()); msg.addByte(player->getSoul()); msg.add<uint16_t>(player->getStaminaMinutes()); msg.add<uint16_t>(player->getBaseSpeed() / 2); Condition* condition = player->getCondition(CONDITION_REGENERATION); msg.add<uint16_t>(condition ? condition->getTicks() / 1000 : 0x00); msg.add<uint16_t>(player->getOfflineTrainingTime() / 60 / 1000); msg.add<uint16_t>(0); // xp boost time (seconds) msg.addByte(0); // enables exp boost in the store } The focus of what we want to change here is this msg.add<uint16_t>(100); // base xp gain rate msg.add<uint16_t>(0); // xp voucher msg.add<uint16_t>(0); // low level bonus msg.add<uint16_t>(0); // xp boost msg.add<uint16_t>(100); // stamina multiplier (100 = x1.0) and this msg.add<uint16_t>(0); // xp boost time (seconds) msg.addByte(0); // enables exp boost in the store To do this we'll use storage values that are referenced via methods of the player class. Our new code will look something like this. // base xp gain rate msg.add<uint16_t>(player->getBaseXpGain()); // xp voucher msg.add<uint16_t>(player->getVoucherXpBoost()); // low level bonus msg.add<uint16_t>(player->getGrindingXpBoost()); // xp boost msg.add<uint16_t>(player->getStoreXpBoost()); // stamina multiplier (100 = x1.0) msg.add<uint16_t>(player->getStaminaXpBoost()); and this // xp boost time (seconds) msg.add<uint16_t>(player->getExpBoostStamina()); // enables exp boost in the store msg.addByte(1); In player.h Under #include "mounts.h" place this #include "configmanager.h" Under class Guild; place this extern ConfigManager g_config; Under bool hasLearnedInstantSpell(const std::string& spellName) const; place this uint16_t getBaseXpGain() const { uint32_t key = g_config.getNumber(ConfigManager::BASEXPGAIN_STORAGE); int32_t value; getStorageValue(key, value); return (value < 0 ? 100 : (uint16_t)value); } uint16_t getVoucherXpBoost() const { uint32_t key = g_config.getNumber(ConfigManager::VOUCHERXPBOOST_STORAGE); int32_t value; getStorageValue(key, value); return (value < 0 ? 100 : (uint16_t)value); } uint16_t getGrindingXpBoost() const { uint32_t key = g_config.getNumber(ConfigManager::GRINDINGXPBOOST_STORAGE); int32_t value; getStorageValue(key, value); return (value < 0 ? 100 : (uint16_t)value); } uint16_t getStoreXpBoost() const { uint32_t key = g_config.getNumber(ConfigManager::STOREXPBOOST_STORAGE); int32_t value; getStorageValue(key, value); return (value < 0 ? 100 : (uint16_t)value); } uint16_t getStaminaXpBoost() const { uint32_t key = g_config.getNumber(ConfigManager::STATMINAXPBOOST_STORAGE); int32_t value; getStorageValue(key, value); return (value < 0 ? 100 : (uint16_t)value); } uint16_t getExpBoostStamina() { uint32_t key = g_config.getNumber(ConfigManager::EXPBOOSTSTAMINA_STORAGE); int32_t value; getStorageValue(key, value); return (value < 0 ? 100 : (uint16_t)value); } Next we'll go into configmanger.cpp and find integer[MAX_PACKETS_PER_SECOND] = getGlobalNumber(L, "maxPacketsPerSecond", 25); and place this under it integer[BASEXPGAIN_STORAGE] = getGlobalNumber(L, "baseXpGain", 18000); integer[VOUCHERXPBOOST_STORAGE] = getGlobalNumber(L, "voucherXpBoost", 18001); integer[GRINDINGXPBOOST_STORAGE] = getGlobalNumber(L, "grindingXpBoost", 18002); integer[STOREXPBOOST_STORAGE] = getGlobalNumber(L, "storeXpBoost", 18003); integer[STATMINAXPBOOST_STORAGE] = getGlobalNumber(L, "staminaXpBoost", 18004); integer[EXPBOOSTSTAMINA_STORAGE] = getGlobalNumber(L, "expBoostStamina", 18005); Then open up configmanager.h and find MAX_PACKETS_PER_SECOND, and place these under it BASEXPGAIN_STORAGE, VOUCHERXPBOOST_STORAGE, GRINDINGXPBOOST_STORAGE, STOREXPBOOST_STORAGE, STATMINAXPBOOST_STORAGE, EXPBOOSTSTAMINA_STORAGE, Then add this to your config.lua -- storages for player stats baseXpGain = 18000 voucherXpBoost = 18001 grindingXpBoost = 18002 storeXpBoost = 18003 staminaXpBoost = 18004 expBoostStamina = 18005 Since it is just storage values then its just a matter of setting the correct storages to set the bonuses. if no value is set then it is set to a default of 100. Here is a screen shot to show you that this works This code is incomplete I will update it when I have time. :)
  25. Não sei se estou no topico correto, por favor mover se for o caso. Gostaria de personalizar alguns elementos no cliente, posições de botoes, algumas janelas mas sem tirar o nativo do cliente. Devo fazer isso descompilando a Source do Servidor ou Cliente ? Algum tutorial relacionado ?

Open Tibia Server

Quer aprender a criar seu próprio servidor de Tibia? Então está no lugar certo, aqui você encontrará milhares de tutorias, scripts, códigos, mapas e utilitários para que você possa fazer o seu próprio servidor de Tibia começando do zero.

Redes Sociais

Anuncie no Tibia King

Precisa de mais visibilidade em seus projetos? Quer fazer um plano publicitário para o seu servidor? Anuncie no Tibia King e faça sua divulgação, possuímos centenas de acessos simultâneos e milhares diários, com certeza será a sua solução!

×
×
  • Create New...