Ir para conteúdo

Neeg

Membro
  • Registro em

  • Última visita

Histórico de Curtidas

  1. Curtir
    Neeg deu reputação a WooX em Tutorial - Push cruzado e sua história   
    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.
  2. Gostei
    Neeg recebeu reputação de Kramer em Dragon Ball Kai Adventure - Show Off   
    Tá muito legal irmão, deu vontade de jogar KKK. Quando estiver online irei jogar com certeza!
  3. Curtir
    Neeg deu reputação a Kramer em Dragon Ball Kai Adventure - Show Off   
    O servidor foi criado para jogadores que já estão entediados com projetos deixados sem supervisão, atualizações e todo tipo de inovação. 
    Nosso servidor foi baseado na versão do DBKO 3.11 (8.0) porém está na versão 8.60, está não é uma cópia 100% fiel do OLD DBKO, é uma versão editada com novas atualizações totalmente diferente do atual.
    Nosso servidor requer treinamento de personagens e conta com uma ampla diversidade de skills, então qualquer personagem poderá ficar forte, sem o famoso PvP de atacar primeiro ganha.
     
    SISTEMA DE SKILLS
     
     
    PERSONAGENS / VOCAÇÕES
     
     
    SKINS/DUNGEONS
     
    AUTO-UPDATER/LAUNCHER
     
     
    ║ Lista/Info dos personagens no site
    ║ Cliente Próprio
    ║ Planetas completos, entre outros...
    ║ 90% dos itens podem ser adquiridos em quests.
    ║ Guild War System
    ║ Dungeon System
    ║ Aura System, customize o efeito do seu personagem.
    ║ Transformações alternativas
    ║ Sagas 100%, ganhe EXP/ITEMS
    ║Esferas do dragão, possível chamar o Shenlong
    ║ Arena PVP
    ║ Area premium nova feita do 0, todas areas premium antigas são free, algumas areas premium free-account poderá acessar porém precisará de fazer o acesso
    ║ Respawns Próprios e personalizados
    ║ Monstros baseados no DBO & DBKO
    ║ Site organizado
    ║ E muito mais!
     
    ◄Rates►
    • Exp Stage Inicial: 30x (Exp Própria)
    • Skill: 5x
    • Magic: 15x
    • Loot: 5x (Rate Loot própria em cada monstro).
    • Protection level: 100 - Porém contamos com um script de anti power abuse.
    • Reborn Mínimo: LvL 250
    • Reborn Máximo: LvL 600

     
    O TÓPICO SERÁ ATUALIZADO COM AS PRÓXIMAS MUDANÇAS ATÉ O FUTURO LANÇAMENTO
     
     
     
  4. Curtir
    Neeg recebeu reputação de Capitao wyz em Os melhores packs 860 Antigos e Atuais ...   
    Achei isso desnecessário mano, creio eu que o dono do tópico está com boas intenções. se você não vai ajudar apenas não comente, nem todo mundo e tão mercenário a ponto de cobrar por tudo.
  5. Gostei
    Neeg deu reputação a Ments em Yurots 11x — Formação de Equipe   
    @luanluciano93

    Não, desisti infelizmente. Eu não estava tão determinado assim a abrir esse servidor, não arrumei nenhum programador .Lua para me auxiliar no desenvolvimento e apenas a parte de mapa com quests não julgo ser algo que os consumidores iriam dar tanta importância.

    Desencanei depois de dobrar o tamanho do mapa que foi apresentado nesse tópico, passei para um amigo e simplesmente deletei do meu computador, fiquei muito bravo com a minha incompetência e iniciei os estudos na programação, depois disso passei por lógica da programação, c/c++ básico e .Lua.
     
    Ainda sou ignorante, hoje sei muito mais do que sabia, em passos de formiga talvez algum dia eu chegue em um ponto onde eu possa desenvolver algo do meu agrado sozinho, porém o mais provável é que simplesmente abandone isso afinal trato como Hobbie e um dia simplesmente a responsabilidade bate tão forte que você perde todo seu tempo livre.
  6. Gostei
    BaiakStyller Sodoma
     
    E aí rapaziada do TibiaKing, tranquilos?
    Andei procurando alguns OTs para passar o tempo, e encontrei um legal para quem curte Styller e Baiak, ou os dois misturados.
    O Servidor e gringo, mas não e nada demais!
     
    Informações:
    · Offline Trainer
    · Refine System
    · War System
    · Castle 24Horas
    · Voc Bal
    · VIP System
    · Stages [1-300] High [300-+] Low
    · Novos Monstros
    · Zombie Event
    · Ice Cube Event
    · Tibia Quest
    · Custom Quests
    · Todas as 4 vocações possuem Set
    · Cast System
    · E muito mais!
     
    Algumas imagens do Servidor:




     
    - Download: https://www.mediafire.com/file/29u0bm1yi151p9h/Baiak_Styller_Sodoma_8.6.zip/file
    - Scan:https://www.virustotal.com/#/file/cde216aec0fa5b667ecbe41232b2deeec0b3c733b4a026cd47b235b62e8ccfaa/detection
     
    O Scan está acusando vírus, mas e por conta do executável (utilizado para ligar o servidor). Baixem por sua propiá conta e risco!
  7. Gostei
    Neeg deu reputação a Cat em Novo Release v3.5 - Remere's Map Editor   
    Novo Release v3.5 - Remere's Map Editor
     
    Publicado a pouco menos de um mês, o novo release divulgado por Mignari no GitHub do Projeto trás novas funções e correções do editor de mapas 3.5. Algumas interessantes como a ferramenta de transformar mapa em minimap, Veja o que mudou:
     
    - Implemento de preenchimento no Terrain Brush.
    - Wall Brushes atualizados para 10.98.
    - Adicionado menu "Mostrar como minimap"
    - Tornar spawns visíveis ao colocar um novo spawn.
    - Bug de Container Item Crash corrigido.
    Veja também! Lista de funções .lua do RME para utilizar em seu server.
     
    Vote na enquete e comente, o que você gostaria que melhorasse no Remere's Map Editor?
     
     
  8. Haha
    Neeg deu reputação a Kickyr em REVIVER O NOSSO TIBIA !   
    -Reviver o Tibia!-

     
    -Voces devem estar pensando o por que desse titulo... Eu vim aqui escrever esse texto ja que eu ainda tenho esperança no TIBIA e nos Servidores dele, Tentar dar uma dica para todos aqueles que estao desanimados com a quantidade de jogadores no seu servidor ou com comunidade do tibia , E tambem me ajudar ja que eu amo tanto esse jogo e quero que ele nao simplesmente suma..
    -Como?-

     
    -vou usar o GLA (Gland Line Adventures) como um exemplo um servidor com novas ideias unicas e um estilo de jogo unico .. Mas voce deve ta perguntando o porque merda estou usando um jogo que nao tem nada a ver com aquele nosso tibia old como exemplo se o intuito é reviver o tibia ? Simples o GLA foi um dos servidores alternativos de tibia que criaram seu proprio estilo de jogo e trouxeram mais de 1000 jogadores diariamente em um servidor alternativo.. Sendo assim uma das formas da gente reviver o tibia seria criando servidores unicos e nao imitações do tibia... Ai voce em fala "Mas Kickyr fazer servidores unicos que fujam da proposta do tibia não traz aquela velha mecanica do tibia old!" ... Sobre isso na minha opnião existem mais de 500 servidores de tibia .. A metade com menos de 10 players online ...O que a comunidade de tibia precisa é de novos estilos unicos.. Tambem tem as milhares de copias mal feitas de DBO e NTO (Nenhum que me anime .. Ja que parece mais um jogo feito para quem sabe mexer mais com bot ou uma criança de 9 anos que quer bate com a cabeça no teclado e da insta kill) .
    ( por favor comente sua opnião .. Assim debatemos e chegamos a uma conclusão melhor ja que eu sou um cabeça de vento)
     
    -Servidores Unicos..-

     
    -Eu com minha ideia estou fazendo meu proprio estilo de servidor ats que o tibia deveria ter .. Obviamente se eu vim propor isso para voces devo pelo menos ter um laço com o assunto.. O estilo que eu criei foi um servidor com rpg completo com inumeras classes(Tipo umas 40) E com o balancemento completo de todas as classes ..
    (É um exemplo de servidor , Se voce tem um bote aqui na publicação como e seu estilo unico!)
     
     
     

  9. Curtir
    Neeg recebeu reputação de dimiot em Os melhores packs 860 Antigos e Atuais ...   
    Achei isso desnecessário mano, creio eu que o dono do tópico está com boas intenções. se você não vai ajudar apenas não comente, nem todo mundo e tão mercenário a ponto de cobrar por tudo.
  10. Gostei
    Neeg deu reputação a DdJs em Dark Complex | Cave Hunt | 8.60   
    Cave hunt - Dark Complex.
     
    Download: Here
     
    Scan: Here

    Imagens:
     

     
     

     
     

     
     

     

     

     
     

     

     

     

  11. Curtir
    Neeg deu reputação a Pro Jota em Os melhores packs 860 Antigos e Atuais ...   
    Bom galera nao so muito bom em escrever nao , me descupa os erros mais bom bora la vamos comecar durante 5 anos da minha vida eu me dediquei a open server tibia 8.60 nesse tempo juntei varias coisas consegui varias coisas , que sao os sonhos de varias pessoas nesse mundo lixo de baiak vo começar postando os servidores mais antigos mais no fim estarei postando servidores atuais ex: baiak-perfect.com  , Real Baiak full e meu servidor q ta 100 % ... A e o principal nao vo da suporte a nda cada um usa e faz o que bem entender ja vo posta isso tudo por que nao quero nunca mais nem ver fala de tibia   .. A cada semana irei posta um pack nova ate chega no ultimo que sera meu servidor q trabalho nele a 4 anos sistemas inovadores ....Espero ajudar muita gente que ja foi roubado passado para trais como eu , irei posta coisas exclusivas que so os grandes da ot serv list tem. Mais agora toda a comunidade do TK vai poder ter .... 
     
    BOM QUERO ACABAR COM ESSA PALHACADA DE VCS TEREM QUE PAGA PARA TER SERVIDOR SEM BUG VÁRIOS SERVIDORES QUE VOU POSTA ESTAO 100% PRONTO PARA RODAR EM LINUX TENHO A DISTRO DO REAL BAIAK A ORIGINAL  UMAS DAS MELHORES SOUCER QUE EXISTE ESTAREI POSTANDO TBM DOIS SITES Q TENHO O DO REAL BAIAK E DO BAIAKINHO ACOMPANHE MEUS POST TEM MUITA COISA BOA GALERA . SONHO DE VARIAS PESSOAS COISA EXCLUSIVAS !!!!
     
    Creditos:
    Todos os Creditos sao a mim por posta a comunidade sao meus entao faço e que bem entender com eles ...
     
    
    https://www.virustotal.com/#/url/71216ea7e98991af2c7f6226d581d2ba513e14cc585f8e8d0f6cf04bf112f755/detection
     

    https://mega.nz/#!4bplVICD!ZuLMP73j14OFwKqOsIGwdaDqJSIGl73d_symvW5Vtf0
     
    Algumas imagens 



  12. Gostei
    BaiakStyller Sodoma
     
    E aí rapaziada do TibiaKing, tranquilos?
    Andei procurando alguns OTs para passar o tempo, e encontrei um legal para quem curte Styller e Baiak, ou os dois misturados.
    O Servidor e gringo, mas não e nada demais!
     
    Informações:
    · Offline Trainer
    · Refine System
    · War System
    · Castle 24Horas
    · Voc Bal
    · VIP System
    · Stages [1-300] High [300-+] Low
    · Novos Monstros
    · Zombie Event
    · Ice Cube Event
    · Tibia Quest
    · Custom Quests
    · Todas as 4 vocações possuem Set
    · Cast System
    · E muito mais!
     
    Algumas imagens do Servidor:




     
    - Download: https://www.mediafire.com/file/29u0bm1yi151p9h/Baiak_Styller_Sodoma_8.6.zip/file
    - Scan:https://www.virustotal.com/#/file/cde216aec0fa5b667ecbe41232b2deeec0b3c733b4a026cd47b235b62e8ccfaa/detection
     
    O Scan está acusando vírus, mas e por conta do executável (utilizado para ligar o servidor). Baixem por sua propiá conta e risco!
  13. Curtir
    BaiakStyller Sodoma
     
    E aí rapaziada do TibiaKing, tranquilos?
    Andei procurando alguns OTs para passar o tempo, e encontrei um legal para quem curte Styller e Baiak, ou os dois misturados.
    O Servidor e gringo, mas não e nada demais!
     
    Informações:
    · Offline Trainer
    · Refine System
    · War System
    · Castle 24Horas
    · Voc Bal
    · VIP System
    · Stages [1-300] High [300-+] Low
    · Novos Monstros
    · Zombie Event
    · Ice Cube Event
    · Tibia Quest
    · Custom Quests
    · Todas as 4 vocações possuem Set
    · Cast System
    · E muito mais!
     
    Algumas imagens do Servidor:




     
    - Download: https://www.mediafire.com/file/29u0bm1yi151p9h/Baiak_Styller_Sodoma_8.6.zip/file
    - Scan:https://www.virustotal.com/#/file/cde216aec0fa5b667ecbe41232b2deeec0b3c733b4a026cd47b235b62e8ccfaa/detection
     
    O Scan está acusando vírus, mas e por conta do executável (utilizado para ligar o servidor). Baixem por sua propiá conta e risco!
  14. Curtir
    BaiakStyller Sodoma
     
    E aí rapaziada do TibiaKing, tranquilos?
    Andei procurando alguns OTs para passar o tempo, e encontrei um legal para quem curte Styller e Baiak, ou os dois misturados.
    O Servidor e gringo, mas não e nada demais!
     
    Informações:
    · Offline Trainer
    · Refine System
    · War System
    · Castle 24Horas
    · Voc Bal
    · VIP System
    · Stages [1-300] High [300-+] Low
    · Novos Monstros
    · Zombie Event
    · Ice Cube Event
    · Tibia Quest
    · Custom Quests
    · Todas as 4 vocações possuem Set
    · Cast System
    · E muito mais!
     
    Algumas imagens do Servidor:




     
    - Download: https://www.mediafire.com/file/29u0bm1yi151p9h/Baiak_Styller_Sodoma_8.6.zip/file
    - Scan:https://www.virustotal.com/#/file/cde216aec0fa5b667ecbe41232b2deeec0b3c733b4a026cd47b235b62e8ccfaa/detection
     
    O Scan está acusando vírus, mas e por conta do executável (utilizado para ligar o servidor). Baixem por sua propiá conta e risco!
  15. Obrigado
    Neeg deu reputação a Ackerzin em Characters.php (Outfit, Skills & EQ+info)   
    Salve galera hoje vou postar pra vocês esse characters.php que esta na image a baixo.
    "FUNCIONA EM GESIOR 2012"
     


     
    1º Coloque as imagens de "Itens,Skills,Addons" dentro da pasta
    \images\equipment
     

     

    2º Baixe o arquivo basic.css <Clique aqui para baixar, e coloque dentro de
    \layouts\tibiacom

    3º Você baixa o characters.php <Clique aqui para baixar, jogue na pasta principal do seu Site.
     
    Creditos: 
    @Fabio Leandro
    @Rusherzin
     
     
     
     
  16. Gostei
    Neeg recebeu reputação de AlexThe Black em Opiniões para um novo projeto   
    Tá faltando Baiak Raiz, um server sem tanto system, um estilo rox... Tem muito publico esse tipo de Baiak, vi um Baiak 8.60 sem site, com erros, e varios bugs pegar 80 online sem divulgação. Se alguém criar um server desse tipo, PvP Totalmente balanceado, sem Castle48Hrs, Cave Exclusiva é etc.. bata uma boa quantidade online!
  17. Obrigado
    Neeg deu reputação a Codex NG em In Game Account Manager TFS 1.3 / OTX3   
    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
     
  18. Gostei
    Neeg deu reputação a Kamity em Kamity Maping   
    E ai galera do TK , estou começando nessa vida de Mapper pois estou montando um projeto e no caso estou trabalhando nele sozinho, meu intuito é que as cidades desse projeto sejam todas produzidas por mim, hunts e quests eu teria algumas editadas e outras do global. Então meu intuito ao criar esse tópico é ir jogando as fotos das cidades,hunts,quest criadas por mim.
    Caso o tópico esteja em um lugar errado, me desculpe e agradeço se mover ele para o local correto.
     
    Regulamentos:                                                                                                                                                                                                                                                                                                                                                    
    1 - Os mapas postados aqui serão todos de minha autoria.                                                                                                                                                                                                                       
    2 - Aceito criticas e sugestoes (afinal sou noob no mapping).                                                                                                                                                                                                                                                          
    3 - Espero que eu me divirta.                                                                                                                                                                                                                                                                           
     
    Cidade Volk - Templo  
    Cidade Volk - Primeiro Construto  
    Cidade Volk - Casa  
  19. Gostei
    Neeg deu reputação a KOLISAO em [show-off] Classic Yurots   
    Classic Yurots - Patch 0.30

     
     
    Arrumado hitChance dos paladinos
    Agora eles ganharam óculos para enxergar rs
    Arrumado recompensa por level
    Em algumas ocasiões, ele não estava checando a arma do knight para adicionar uma de nível maior.
    Arrumado Magic Wall e Growth Rune
    Agora é possível usá-lo sobre Fire/Poison/Energy.
    Arrumado Pot por alavancas
    Antes só era possível comprar BP's. Agora o sistema checa se possui CAP ou MONEY, caso contrário, ele comprar de 100.
    Removido efeito ao receber Free Bless
    Apenas a mensagem vai aparecer no Default.
     
    Adicionado comando EmoteSpells
    O jogador pode ativar ou desativar (spells em laranja ou normal: amarelo no default)
    - Só funciona para seu personagem. Os outros personagens ficam normais, a não ser que também utilizem o comando


    Adicionado alguns npcs essenciais para o servidor
    NPC's que vendem/compram equipamentos, amuletos, rings, etc...
    Adicionado Free Bless
    Até o level 49.
    Adicionado recompensa por level
    Até level 30, os jogadores ganham recompensa e atualizam de armas/wands/rods/distance automaticamente.
    Level 30 e 50, os jogadores recebem uma quantia significativa de golds para ajudar em sua jornada.
    Adicionado Aura System
    O sistema recupera seu hp/mana caso você sofra dano no hp ou mana.
    - Essa aura só poderá ser adquirida em QUEST (ainda não implementada)


    Adicionado nome de quem usou Magic Wall ou Wild Growth rune


     
     
    Revisando todos os monstros (em analise)
    (drops, itens, atks, defs, hp, speeds, etc...)
     
     
    OBS: Sei que o tópico deve ter ficado um pouco estranho, mas foi por conta do novo visual do fórum. Ele mostra as bordas das imagens e corta as bordas dos BOX.
  20. Gostei
    Neeg recebeu reputação de Hudsonlemos em Pasta de ot sem dll/distro não abre   
    Irmão, acho que seu erro aí e algo com a database..
     
    "MySQL Error Message : Access denied for user 'root'@'localhost' <using password:no>
    >ERROR: Failed to connect to database.
    >>No services running. The server is NOT online"
     
    Arrume seu config.lua e tente novamente!
  21. Gostei
    Neeg deu reputação a KOLISAO em [show-off] Classic Yurots   
    Muito obrigado pelo comentário!
    Também penso em mudar o templo, faz o servidor parecer meio confuso de fato. Meu problema era saber como mudar e, você me deu sugestões de como fazer. Obrigado!
     
    Muito obrigado pelo comentário maninho  
  22. Curtir
    Neeg recebeu reputação de KOLISAO em [show-off] Classic Yurots   
    Tá bonito mano! kkk deu vontade de jogar.
  23. Gostei
    Neeg deu reputação a LeoTK em [NTO NS] Source 0.3.6 8.54 OTX Windows/Linux   
    Fala galera, bom eu vi que é difícil achar uma source 0.3.6 sem bugs, então resolvi disponibilizar a source do meu servidor 0.3.6 8.54
    1- Magic Effects e ShotyEffect Extendido 2- Magic Effect até 700+ / Shoty Effect até 150 se não me engano 3- Sistema de Dupla Empunhadura 4- Tem a função doplayeropenchannel para abrir os chats ao logar 5- Todos os danos de elementos estão configurado para o magiceffect 131 que no meu client é vazio 6- Auto Stacking ao jogar item que se junta por quantidade ele junta automaticamente 7- No Blocking Respawn o monstro da respawn mesmo tendo jogadores perto e com magic effect (não lembro o número do magic effect) 8- Novo Elemento Wind Adicionado 9- Algumas modificações que não lembro
     
    Linux Compile
    Tem um arquivo.txt que tem os códigos para compilar no linux lá tem o nome da biblioteca e o código.
     
    Windows Compile
     
    Software necessário : Stian's_Repack_Dev-Cpp_0.2,_64bit.rar    Scan
     
    Use a pasta Dev-Cpp/test esqueça do conteúdo da pasta dev-cpp e use o projeto criado na pasta test a diferença é o parâmetro usado para compilar a source.
     
    OBS: Caso tiver erros ou problemas abra um tópico na área de Suporte. 
     
    DOWNLOADS:
    [NTO_NS]_Source_0.3.6_8.54.rar
    SCAN
  24. Gostei
    Neeg deu reputação a Cat em O que você colocaria na porta de level 999?   
    É um assunto meio velho já eu sei, já entraram na porta de lvl 999 e tal. Mas concordamos que os Tibianos, principalmente os mais antigos esperam algo mais chocante!
    Então eu pergunto, se você fosse uma Cipsoft da vida e voltasse no tempo, o que você colocaria depois da porta lvl 999?
     
    Minha resposta: O portal levaria o jogador para outra dimensão, onde todo o mapa tibiano seria copiado, porém com sprites diferentes (tipo o universo de stranger things) e algumas partes do mapa corrompidas ou totalmente sinistras (tipo uma thais destruída por raízes do mal, ou uma ab'dendriel desértica, ou darashia congelada, já pensou?? kk). E nesse continente todo parecido com o real teriam criaturas bizarras e assustadoras, itens novos que poderiam ser levados ao mundo Tibiano original, novos outfits, as mesmas quests porém com novas complicações, mounts sinistras, etc...
     
    E você? O que faria?
  25. Gostei
    Neeg deu reputação a Ackerzin em QUEST DIARIA   
    Tenta essa
    <action uniqueid="7865" script="testeeee.lua" /> testeeee.lua
     
    local t = { storage = 678678, -- storage, so mude se tiver usando pra outra coisa. tempo = 24, -- Tempo em horas. qt = 250, -- quatidade. itemidxx = 6527 -- Item que ira ganhar. } function onUse(cid, item, fromPos, itemEx, toPos) if getPlayerStorageValue(cid, t.storage) < os.time() then doPlayerSendTextMessage(cid, 25, "Voce ganhou "..t.qt.." "..t.itemidxx.." diário, espere dar 24 horas para pegar novamente.") doPlayerAddItem(cid,t.itemidxx,t.qt) setPlayerStorageValue(cid, t.storage, os.time() + t.tempo * 60 * 60) else doPlayerSendTextMessage(cid, 25, "Você precisa esperar ".. getPlayerStorageValue(cid, t.storage) - os.time() .." segundos para coletar novamente.") end return true end  

Informação Importante

Confirmação de Termo