Ir para conteúdo
Close

REFORMULAMOS A SEÇÃO DE CLASSIFICADOS! - Crie grátis os seus anúncios de procura e oferta de serviços e produtos relacionados ao OTServ! - Acesse através do nosso menu ou clique aqui e confira já!

Pesquisar na Comunidade

Mostrando resultados para as tags ''C++''.



Mais opções de pesquisa

  • Pesquisar por Tags

    Digite tags separadas por vírgulas
  • Pesquisar por Autor

Tipo de Conteúdo


Fóruns

  • Comunidade
    • Regras
    • Portal
    • Recursos
    • Comércio
    • Clubes
  • OTServers
    • Discussão
    • Suporte
    • Tutorial
    • Download
    • Desenvolvimento de Códigos
    • Concursos e Eventos
    • Formação de Equipe
    • Anuncie seu Servidor
  • Tibia Bots
    • Discussão
  • League of Legends's Geral
  • League of Legends's Suporte
  • Jogos Gerais's Geral
  • Nto New Season's Tópicos
  • Fakes's Fakes
  • Tibia Geral's Geral
  • Tibia Geral's Notícias
  • Tibia Geral's Media
  • Tibia Geral's Life Thread
  • Gráficos's Geral
  • Gráficos's Tutoriais
  • Gráficos's Recursos
  • Gráficos's Aprendizagem & Recursos
  • Gráficos's Galeria
  • Gráficos's Duelos & Batalhas
  • Gráficos's Suporte
  • Desenvolvimento e Programação's Geral
  • Desenvolvimento e Programação's Tutoriais
  • Desenvolvimento e Programação's Trabalhos
  • Desenvolvimento e Programação's Suporte
  • Computação's Geral
  • Computação's Dicas e Tutoriais
  • Computação's Suporte
  • Roleplaying's Roleplaying
  • Playground's Playground (Off-topic)
  • Divulgações's Divulgações

Calendários

  • Calendário Oficial
  • Calendário de OTServs
  • Calendários Diversos

Product Groups

  • Anúncios no Topo
  • Anúncios nas Assinaturas
  • Anúncios nos Tópicos
  • Outros Anúncios

Categorias

  • Seção de Vendas
    • Vendas de Scripts
    • Vendas de Códigos
    • Vendas de Mapas
    • Vendas de Websites
    • Vendas de Design/Sprites
    • Vendas de Bots
  • Procura-se Jobs
  • Procura-se Freelancers
  • Formação de Equipe

Encontrar resultados em...

Encontrar resultados que...


Data de Criação

  • Início

    FIM


Data de Atualização

  • Início

    FIM


Filtrar pelo número de...

Data de Registro

  • Início

    FIM


Grupo


Localização


Meu personagem


OTServ favorito


Bot preferido


Interesses

Encontrado 50 registros

  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. underewarr

    C++ Sistema Mundos

    Em ioaccountsql.cpp nós mudamos. Procure por . Account IOAccountSQL::loadAccount(uint32_t accno) E Substitua toda a função por essa (OBS LEMBRE-SE DE CONFIGURAR OS MUNDOS.). Account IOAccountSQL::loadAccount(uint32_t accno) { Account acc; Database* mysql = Database::instance(); DBQuery query; DBResult result; query << "SELECT id,password FROM accounts WHERE id=" << accno; if(mysql->connect() && mysql->storeQuery(query, result)){ acc.accnumber = result.getDataInt("id"); acc.password = result.getDataString("password"); #ifndef __ROGIER_MULTIWORLD__ query << "SELECT name FROM players WHERE account_id=" << accno; #else //__ROGIER_MULTIWORLD__ query << "SELECT name,worldid FROM players WHERE account_id=" << accno; #endif //__ROGIER_MULTIWORLD__ if(mysql->storeQuery(query, result)){ for(uint32_t i = 0; i < result.getNumRows(); ++i){ std::string ss = result.getDataString("name", i); #ifndef __ROGIER_MULTIWORLD__ acc.charList.push_back(ss.c_str()); #else //__ROGIER_MULTIWORLD__ int worldid = result.getDataInt("worldid", i); query.reset(); result.clear(); query << "SELECT * FROM worlds WHERE worldid=" << worldid; mysql->storeQuery(query, result); struct CharInfo info; info.worldName = result.getDataString("worldname", i); info.worldIp = result.getDataString("worldip", i); info.worldPort = result.getDataInt("worldport", i); acc.charList[ss] = info; #endif //__ROGIER_MULTIWORLD__ } #ifndef __ROGIER_MULTIWORLD__ acc.charList.sort(); #endif //__ROGIER_MULTIWORLD__ } } return acc; } Agora no protocollogin.cpp na função parsefirstpacket nós mudamos. Procure por. std::list<std::string>::iterator it; for(it = account.charList.begin(); it != account.charList.end(); it++){ output->AddString((*it)); output->AddString(g_config.getString(ConfigManager::WORLD _NAME)); output->AddU32(serverip); output->AddU16(g_config.getNumber(ConfigManager::PORT)) ; } Substitua por. #ifndef __ROGIER_MULTIWORLD__ std::list<std::string>::iterator it; for(it = account.charList.begin(); it != account.charList.end(); it++){ output->AddString((*it)); output->AddString(g_config.getString(ConfigManager::WORLD _NAME)); output->AddU32(serverip); output->AddU16(g_config.getNumber(ConfigManager::PORT)) ; } #else //__ROGIER_MULTIWORLD__ std::map<std::string, CharInfo>::iterator it; for(it = account.charList.begin(); it != account.charList.end(); it++){ output->AddString(it->first); output->AddString(it->second.worldName); output->AddU32(inet_addr(it->second.worldIp.c_str())); output->AddU16(it->second.worldPort); } #endif //__ROGIER_MULTIWORLD__ Agora Em account.h. procure. class Account adicione logo a baixo. #ifdef __ROGIER_MULTIWORLD__ #include <map> struct CharInfo { std::string worldIp; std::string worldName; short worldPort; }; #endif //__ROGIER_MULTIWORLD__ Novamente em account.h nós mudamos: Procure std::list<std::string> charList; Substitua #ifdef __ROGIER_MULTIWORLD__ std::list<std::string> charList; #else //__ROGIER_MULTIWORLD__ std::map<std::string, CharInfo> charList; #endif //__ROGIER_MULTIWORLD__ Adicione como parametro o seguinte seguimento para que a compilação encontre todas as alterações a cima -D__ROGIER_MULTIWORLD__ (Igual o mysql/sqlite,console,gui é adicionado) E AGORA OQUE EU FAÇO?
  3. 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.
  4. No otserv.cpp: No config.lua Adicione a tag da propriedade adicionada. Qual é a prioridade para definir o OTS durante o início (normal, alta, mais alta).
  5. 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
  6. 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
  7. 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?
  8. 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. :)
  9. 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
  10. 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 ?
  11. Olá a todos preciso de ajuda quero adicionar uma pokebar estou usando o cliente silcer 1.9 - 2.9 como base mas as portrait de alguns Pokémon não aparecem especificamente da segunda geração pra frente... ai queria saber se a alteração é feita na dll ou no Server e como fazer...
  12. 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
  13. Bom vi em vários tutoriais ai da vida, que se colocar isso no config.lua já removia a xp que o summon ganha. NoShareExpSummonMonster = true MAS NÃO FUNCIONA O correto é ir na sua source e em criature.cpp e editar essa parte aqui. void Creature::addDamagePoints(Creature* attacker, int32_t damagePoints) { if(damagePoints < 0) return; uint32_t attackerId = 0; if(attacker) attackerId = attacker->getID(); CountMap::iterator it = damageMap.find(attackerId); if(it != damageMap.end()) { it->second.ticks = OTSYS_TIME(); if(damagePoints > 0) it->second.total += damagePoints; } else damageMap[attackerId] = CountBlock_t(damagePoints); if(damagePoints > 0) lastHitCreature = attackerId; } por essa aqui. void Creature::addDamagePoints(Creature* attacker, int32_t damagePoints) { uint32_t attackerId = 0; if(attacker) { if(Creature* master = attacker->getMaster()) attacker = master; attackerId = attacker->getID(); } if(attacker->getPlayer()) { CountMap::iterator it = damageMap.find(attackerId); if(it != damageMap.end()) { it->second.ticks = OTSYS_TIME(); if(damagePoints > 0) it->second.total += damagePoints; } else damageMap[attackerId] = CountBlock_t(damagePoints); } if(damagePoints > 0) lastHitCreature = attackerId; } Compila e pronto quando o summon matar a xp vai toda pra você.
  14. Efeito: caractestica da vida, agora indicada como %(percent) Como Usar: Substiruiremos a função inteira de do playerstats dentro do protocolgame.cpp caso seja nas versões e tfs 0.3.6.1. Para tibia 7.6 editaremos o protocol76game.cpp TFS MASTER c++ code TFS 1.0 - 1.2 c++ code TFS 0.3.6.1 Você precisa remover o espaço de PLAYERINFO_MAXMANA se aparecer algum erro, ou algo fora do comun - não é minha culpa c++code para versões 7.6-7.9 Códigos criados em 02/12/2017 Acredito que todas as versões estejam ai. Imagens: Antes : Depois :
  15. 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 !!!
  16. Gabrielcml

    Source

    Preciso de ajuda, como eu troco o executável do meu ot 8.6 para colocar mana e hp por porcentagem com c++
  17. RECRUTA-SE EQUIPE PARA SERVIDOR DE NARUTO[REMUNERADO] Preciso de 1 spriter, um mapper e um programador para trabalhar em um servidor de narutibia. O pagamento seria feito por serviço ou então mensal mas com metas de trabalho. VAGA SPRITER : preciso de um spriter experiente, que já tenha trabalhado em outros projetos. Tenho preferencia por quem gosta e já trabalhou com narutibia. VAGA MAPPER: preciso de um bom mapper, com um portifolio bacana de mapas criados. Tenho preferencia que já tenha trabalhado com narutibia ou pelo menos conheça e tenha assistido o anime VAGA PROGRAMADOR: Preciso de um programador, que entenda de lua, c++, que consiga colocar funções novas no dev e compilar, que saiba fazer npcs bem, funções e libs lua, sistemas lua, que saiba mexer com mysql também, e também saiba editar o cliente do tibia para criação de um novo cliente. Preferência para quem saiba descompilar clientes. meu facebook para mais informações ; https://www.facebook.com/jeanccm1
  18. Jamyn

    Programação Compilar TFS

    VENHO HOJE COM UM TUTORIAL PARA QUEM ESTÁ COM DIFICULDADES EM COMPILAR TFS USANDO O VISUAL STUDIO Como pouca gente sabe, para compilar o TFS é preciso da versão 2015 do Visual Studio e muita gente que baixa agora, vem com a versão 2017. Para quem já baixou, procure por “Visual Studio Installer” no menu iniciar e abra-o. Quem vai baixar agora, já faça esse procedimento. Link: https://www.visualstudio.com/pt-br/ Clique em modificar. Conforme mostra a imagem. Assim que abrir, abrirá essa janela. Se você ainda não instalou nada, prossiga depois daqui. Clique em Desenvolvimento para desktop em C++ Dessa a barra de rolagem e clique em “Conjunto de Ferramentas de VC++ 2015” Baixe, pesa 1 GB e pouco. Agora sim, você está com seu programa pronto para compilar seus servidores. Obrigado!
  19. Gente, estou com duvida em uma coisa: existe algum equivalente em c++ para fazer a mesma coisa que o math.random(x,y) do Lua?
  20. Ola, tenho anos de experiencia com programação de servidores Otserv e derivados (C++). Resolvi fazer um vídeo rápido para ver se tem demanda de tutorial nesse assunto. O vídeo a seguir estou acompanhando, sem detalhar muito, o que mais ou menos acontece no lado do servidor quando tem um login. Aqui esta o resultado: Feedback é bem vindo. Qualquer duvida é so falar.
  21. Quer mais informações do projeto, curta a pagina : https://www.facebook.com/LegendBladeOnline/ Quer mais informações do projeto, curta a pagina : https://www.facebook.com/LegendBladeOnline/ Procurando por mappers e spriters (de preferência com alguma experiência).
  22. 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
  23. Olá pessoal! Estou criando um server de poketibia e procuro ajudantes funcionais(que tenham função efetiva na criação do server) pois tenho muitos GMs, tutores e poucos criadores... A criação está toda por minha conta e estou tendo que aprender tudo no "susto" pois não tenho muito conhecimento sobre isso, principalmente sobre programação. Preciso principalmente de scripter que tenha experiência com lua e C++(principalmente) e web designer que saibam criar sistemas do zero. No início o pagamento será o cargo de administrador no server e mais futuramente pensarei em pagamento monetário se for viável... Tenho várias ideias interessantes, porém não sei como botá-las em prática... Interessados mandem PM que passo meu contato para conversarmos melhor sobre. Obrigado!
  24. Olá galera, DE ANTEMÃO JÁ QUERO PEDIR DESCULPAS SE POSTEI NO LUGAR ERRADO MAS ACHO QUE AQUI É SOBRE PROGRAMAÇÃO NEAH? ENTÃO TA CERTO :D enfim, tenho conhecimento em c++ e tudo mais. mas por fim didático, comecei q querer ler as memórias do tibia (memory inject ) pra conhecimento mesmo. até porque não tenho tempo nem interesse em fazer um bot. mas vejo muitos post em inglês e fico indeciso. Minha dúvida é referente a leitura da battleList. eu preciso realmente ler a memoria baseada na base_memory do tibia + offset? ou apenas a memoria direta do battleList é suficiente?

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 partindo do zero.

Redes Sociais

Anuncie no Tibia King

Precisa de mais visibilidade em seus projetos? Quer publicidade 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! A publicação do seu anuncio é instantânea!

×