🤔 Para Refletir :
"Por que tão sérios? Não... eu diria: por que tão perfeccionistas?"
- Eliyud

RPG2kTools - Focado em quebrar alguns limites da engine

DevWithCoffee

Cidadão
Membro
Membro
Juntou-se
02 de Abril de 2019
Postagens
134
Bravecoins
216
Como alguns poucos devem saber existem diferenças bem grandes entre o RPG Maker 2003 e 2000, mas após as atualizações da empresa que detém os direitos ambas engines receberam melhorias, mas ao contrário da versão 2003 a 2000 ficou com varias limitações que não existem mais na versão 2003, como por exemplo:
  • Pular a tela de título (Entrada do jogo)
  • Abrir o LoadGame (Para auxiliar na criação de uma tela de título personalizada)
  • Modo janela se tornou o padrão
  • Modo tela cheia não muda mais a resolução do jogo (O que gerava erro em computadores que nunca rodaram um jogo feito com Rm2k ou 2k3)
  • O renderizador padrão não é mais o DirectDraw
  • O jogador pode modificar configurações gráficas e volume do audio por um menu direto no jogo
  • O desenvolvedor pode abrir a edição do projeto direto por um arquivo dentro da pasta

E deve ter mais coisas que não me lembro, todas essas modificações em geral foram feitas pelo Cherry, o mesmo quem criou várias ferramentas e Patchers para Rm2k e 2k3, e parte do que consegui até agora foi graças ao PPCOMP que ele criou.

Sobre o meu projeto:
Como não é um jogo não vi motivos pra postar em outro lugar se não aqui.
Vale lembrar que não estou tentando salvar a engine que é totalmente obsoleta, o meu propósito é torna ela mais interessante para que ainda usa ou que teve um projeto parado por conta das mudanças nas ultimas versões do Windows mas não quer migrar para Rm2k3 ou EasyRPG.

O que por que estou fazendo um software que modifica o jogo externamente ao invés de editar o próprio ou criar um executável novo como o EasyRPG que é feito totalmente do zero? Simples, existe uma licença e que ao fazer isso é quebrada, isso não chega à violar leis, mas te limita na comunidade oficial.

Vamos a parte que eu considero à mais legal, o que eu já consegui fazer, em principio eu descobri que era possível ler as informações de dentro do jogo por conta de uma ferramenta que está disponível na comunidade oficial, ela era capaz de ler e gravar as Switches e Variaveis do jogo, mas que o intuído era monitorar sem precisar ficar abrindo a tela do Debug (F9), algo que era muito útil, e além de não quebrar a licença funcionava nas versões mais comuns do Rm2000 e Rm2003, ele também disponibilizou o código fonte.

Então eu fui estudar sobre o assunto, como eu não sou programador não entendi nada, então eu comecei com coisas simples, por conta do tempo e do meu computador um pouco fraco eu preferi fazer isso com uma ferramenta leve e que compilasse instantaneamente, como eu já tinha experiência com o AHK (V1.1) eu comecei por aí, pois eu já tinha feito duas ferramentas para o Rm2000 porém sem o conhecimento em como mexer na memória de um processo tudo foi meio que simulado com bastante gambiarra.

Após meses tentando encontrar tutoriais e exemplos que me fizessem entender exatamente o que era isso um usuário no Discord me passou um vídeo onde um cara ensinava como criar cheats para jogos (sem a parte da programação), usando uma ferramenta chamada CheatEngine, com um pouco do meu conhecimento em ResHacker eu retirei dessa ferramenta a requisição administrativa, já que os jogos de Rm2k e 2k3 não necessitam disso o CheatEngine deveria trabalhar no mesmo nível deles, por que o meu código futuro também precisaria.

Através do método ensinado eu achei os endereços na memória e os ponteiros que levavam à eles, para poder achar outras coisas que eu não conseguia eu usei o PPComp.exe criado pelo Cherry, aqui segue uma sequencia de vídeos dos testes e começo do projeto usando CheatEngine:
https://www.youtube.com/playlist?list=PLj0HSLYd4udE4hwyIQUuGVQe5e-YOIEYZ

Para quem acha isso estranho garanto que não é, foi muito emocionante quanto consegui acessar ou modificar tantas coisas do jogo em tempo real além de imaginar o que poderia fazer com essas coisas.
Aqui vai estar listado na ordem o que eu consegui encontrar:
  • Leitura: Se o modo janela está em 320x240 (false) ou 640x480 (true)
  • Escrita: Onde começa e onde termina a tela do jogo dentro do ecrã, isso será usado para mudança de resolução da tela
  • Escrita: Brilho da tela (porcentagem), sendo zero totalmente escuro (0x0) e 200 totalmente branco
  • Escrita: O brilho da tela quando chega aos números negativos ou passa de 200 troca a paleta de cores criando vários efeitos diferentes na imagem conforme muda esse número
  • Escrita: Controle do timer do jogo, aquele usado para puzzles com tempo
  • Escrita: Controle da tonalidade da tela (mesmo do comando de evento), isso poderia servir para criar um sistema de período em base do relógio do jogador sem precisar criar várias IFs
  • Escrita: Tonalidade da caixa de dialogo, algo que nem imaginava existir, provavelmente foi inspirado no Final Fantasy 5 mas não foi incluído o acesso na engine ou jogo
  • Escrita: BGM da tela de título, imagine poder trocar a música inicial após um evento importante do jogo
  • Escrita: Gráfico da tela de título, mesma possibilidade do anterior
  • Escrita: Gráfico da tela de Gameover, imagine poder colocar uma tela aleatória ou em condição à uma situação do jogo, ou horário do computador
  • Escrita: Gráfico do Systemset inicial (O novo tem que ter a mesma quantidade de digitos)
  • Escrita: BGM memorizada por comando de evento
  • Escrita: BGM que estiver tocando durante o jogo
  • Leitura: Saber a ID do grupo de inimigos em batalha
  • Escrita: ID do ultimo grupo de inimigos que o jogador enfrentou
  • Escrita: Tempo de jogo em em frames (30 por segundo), isso pode ser usado pra criar um visualizador de fps
  • Escrita: Se o jogador estiver parado ou um evento automático estiver acontecendo
  • Leitura: ID do mapa
  • Escrita: Coordenadas do jogador
  • Escrita: Direção real e gráfico da direção
  • Leitura: Frame da animação "andando"
  • Leitura: Se o jogador estiver andando constante (O numero ainda não fez sentido)
  • Escrita: Deixar o jogador invisível (mesmo do comando de evento)
  • Escrita: Gold/Dinheiro atual do jogador
  • Escrita: Cena atual, se está na tela de gameover, load, save, menu, loja, titulo (com isso é possivel pular a tela de titulo)
  • Escrita: Permissão para acessar o menu ou salvar o jogo (mesmos dos comandos de eventos)
  • Leitura: Cena do menu do jogador, item, skills, não tenho planos pra isso ainda
  • Escrita: Slot selecionado em Save/Load, não perceptivel ao jogador, mas ao apertar confimar vai funcionar
  • Escrita: Ultimo save acessado para salvar ou carregar, volta para 1 ao voltar pro titulo
  • Escrita: Útil apenas para leitura, pode causar conflitos no jogo
  • Escrita: Passos durante o jogo, zera ao voltar pro titulo, mas salva junto do progresso
  • Escrita: Quantidade de Switches iniciadas, com isso é possível controlar o intervalo das que estão acessíveis pra não mover algum endereço errado na memória e dar erro no jogo
  • Escrita: Controlar uma Switch especifica como no menu Debug (F9), isso pode ser usado pra criar um loadgame personalizado
  • Escrita: Quantidade das variáveis, como das Switches
  • Escrita: Controlar uma variável especifica, o quanto de coisa que não podemos fazer com isso?

Agora sobre o mapeamento de teclas, imagine poder desabilitar as teclas inconvenientes ou mudar as teclas para o jogador, sendo que cada função/comando do jogador tem em torno de 2 ou 4 teclas, sendo possível incluir mais teclas para cada função.
Então, com isso podemos alterar as teclas de direcionais para W, S, A, D ou desabilitar aquelas que nunca usamos como H, J, K, L (direcionais) e a C, V, B, N que são as mesma função da X, Esc e Num0.
Essa foi uma das partes mais complexas de entender, já que não era fácil encontrar as IDs das teclas, vale lembrar que existe um Patch que faz isso no Rm2k3 que não viola a licença atual, porém não acontece com o Rm2k.

Logo após eu tive o desafio de aprender à programar como ler e escrever direto na memória do processo, até algumas semanas eu tinha tentado entender vários exemplo, acabou que quase todos estavam errados, então no antigo e desativado fórum do AHK eu achei um exemplo bem simples e lógico então tudo fez sentido.

Vale lembrar que desde então já havia passado quase um ano e eu não podia mexer nessas coisas por conta do meu trabalho e coisas da rotina que precisava sempre resolver, e realmente para aprender isso tem que estar totalmente focado e fazer testes por muitas horas seguidas, enfim finalmente entrei de férias e pude colocar o pouco que aprendi sobre o assunto em prática pra funcionar com um jogo feito no Rm2k.

Aqui vai estar listado na ordem o que eu já fiz com leitura e escrita da memória do processo:
  • Modificar o tamanho da tela do jogo, sendo que a mudança do tamanho da janela é por um método nativo no AHK
  • Escurecer a tela e clarear de 20 em 20 por centro ao mudar a escala no modo Fullscreen para não ficar mostrando imagens repetidas
  • Controle do volume do áudio master (isso é notado no mixer de volume na barra de tarefas)
  • Extrair imagem da tela pela memória
  • Recolorir pixels de qualquer Picture que exista na tela
  • Modificar as fontes de texto 1 e 2 (RPG2000 e RPG2000G)





Apesar de ter duas coisas apenas, era o que eu precisava no momento, mas não vou ter dificuldade de implementar as outras coisas, o que me tomou muito tempo foi aprender como usar a biblioteca gráfica GDI+ pra AHK (que usa WinAPI), que apesar de já ter usado não é algo que consegui entender bem quando usei da primeira vez.

Isso para não precisar usar software de terceiro, a parte de converter em 256 cores deu bastante trabalho, ninguém na comunidade conseguiu me ajudar.

Veja nessa Playlist o progresso do projeto:
https://www.youtube.com/playlist?list=PLj0HSLYd4udF2Z78toxHjod1PVmN_FyBq

  • Trocar as funções das teclas F4 (Alterna para Fullscreen) e F5 (muda a escala) para funcionar somente quando a tela do jogo estiver ativa
  • Centralizar a janela do jogo ao mudar a escala em modo janela
  • Centralizar a tela do jogo dentro do ecrã ao mudar a escala
  • Controlar o volume do áudio do jogo, inclusive tirar o mudo, não foi usado o classMemory, agradeço ao Argentino Flipeador pelas funções, a parte do mudo eu fiz por conta
  • Capturar a tela e salvar em PNG 8-Bit e redimensionar sem misturar os pixels
  • Fazer a captura de tela funcionar no Windows 7
  • Definir no arranque do jogo a escala da tela e se vai estar em tela cheia ou não
  • Executar o RPG_RT com outra extensão para que o desenvolvedor inicie a aplicação AHK quando iniciar o teste dentro do editor







 
Última edição:
Nem sei o que dizer. Parece um verdadeiro trabalho de engenharia e que lhe tomou muito tempo e dedicação. Meus parabéns. Vou precisar estudar o assunto para entender melhor tudo isso e como aproveitar tanta modificação interessante. Acho que o @Dr.XGB vai gostar dessa postagem.
 
Vou precisar estudar o assunto para entender melhor tudo isso e como aproveitar tanta modificação interessante.
Se você assistir os vídeos na sequencia vai entender bem melhor do que ficar lendo esse texto enorme e é bem intuitivo.

Ao meu ver foi o texto seria desnecessário em grande parte, mas pra fins de registro eu preferi contar a minha jornada ao invés do que apenas ficar falando de termos técnicos.
 
Última edição:
Uma atualização, eu pretendia criar o ajuste de configurações dentro do jogo com Pictures e variáveis do próprio jogo, mas pensei bastante sobre isso e decidi criar primeiro com um janela como no Rm2k3 para estudos:
 
Enfim consegui localizar o ponteiro que leva ao endereço da imagem da Picture 1 na tela, ou seja, eu posso modificar uma imagem inteira desde que o tamanho não ultrapasse a quantidade de pixels existentes. Eu bloquei a visão do mouse, mas o momento em que os números se movem sou eu digitando rapidamente no teclado os valores em hexadecimal das cores:

Exemplos das cores em formato hexadecimal:
Branco: 0xFF
Preto: 0x00 (Não aparece no primeiro exemplo por que era a cor transparente)
Vermelho: 0x4F
Amarelo: 0xFB

Mas qual a utilidade disso? Imagine que ao invés de criar várias IFs (Conditions Branch) por eventos eu crie apenas um chamado de comando externo que permita ler os dados de um arquivo e passe por cima do que consta na memória no momento, como uma barra de progresso ou de vida.
Mas o meu principal intuito seria criar caixas de texto flutuantes geradas dinamicamente por uma única imagem, como aquelas que mostram o nome do mapa que o jogador acessa pelo Overworld em um JRPG clássico ou mesmo criar uma caixa de dialogo com fontes personalizadas.

Essa parte não vai pra lista por que ainda estou estudando como realmente poderia desenhar algo em uma Picture de maneira dinâmica, já que eu provavelmente teria de criar uma Classe com AHK só para edição gráfica, algo que eu não tenho muito conhecimento.
 
Última edição:
Eu estava tentando criar um sistema de captura de tela que extraísse os dados diretamente da memória.
Demorei muito pra descobrir como interpretava os pixels na tela do jogo...
Na verdade o endereço 0x0 é o Pixel da coordenada X:0,Y:239 ao invés de X:0,Y:0, sendo assim, uma tela de 320x240 o ultimo pixel fica na coordenada X:319,Y:0 sendo o endereço 0x257FE.
Isso totaliza 153598 bytes, só que 320*240 seria a metade, 76800, sendo então o último endereço 76799 (0x12BFF). Isso por que diferente das Pictures que usam um Byte por Pixel com limite de 256 cores, de 0 à 255 (0x0~0xFF) a tela usa 2 Bytes. Por exemplo a cor branca 0xFFFF a cor verde grama 0x3481.

Então surgiu outro desafio, eu não sabia converter cores de 1 bytes pra RGB, mas a fórmula não foi difícil de encontrar, o problema foi encontrar a fórmula que convertesse cores 16-Bit (2 bytes) para RGB, eu tive que procurar por uma versão Javascript e reescrever em AHK.

Então eis que surge outro problema, ler memória como String era a única opção que eu tinha de extrair sem causar delay no Script, o problema é que qualquer 0x0 na caminho para a leitura por que é considerado "fim da string" já que é um caractere nulo.

Eu tentei vários métodos, todos tomavam entre 9~11 segundo para cada execução mesmo em um processador melhor, foi então que consegui encontrar uma solução essa madrugada:
AHK Boards: p297901

Em seguida eu precisava que essa operação funcionasse para ler apenas os bytes em ponteiros impar (1, 3, 5, 7...), por fim consegui resolver:
AHK Boards: t124719
Por exemplo, se tiver uma sequencia 31083481FFFF a função retornava 3108 0834 3481 81FF FFFF
Assim ao invés de ler do 1 para o 2 e do 2 para o 3, ele vai ler 1 para o 2, do 3 para o 4 e assim por diante 3108 3481 FFFF

Vejam o vídeo com o resultado:
Youtube

Pode não parecer fazer sentido, mas capturar a imagem direto dos dados evita muitas execuções do GDI+ para AHK, por que em cada modo de janela isso pode gerar algum problema, tela cheia em modo esticado é o mais complicado de ajustar após a captura.

Agora por fim eu vou dar um tempo disso e vou concluir as funções que já estão quase prontas, como a janela de ajustes de escala, modo de janela e volume que precisam apenas serem integradas ao Script atual. E logo mais complementar o sistema de comandos de eventos adicionais (uma variável vai sinalizar o comando pro Script, sendo que cada valor dos dois primeiros dígitos vão significar os comandos e os quatro últimos dígitos a ID da variavel algo para retornar algum valor se for a função do comando)
 
Voltar
Topo Inferior