Registrarse

[Parche] FR | ASM | Nuevas funciones estandarizadas para msgbox

Dr. Seuss

Loco Peligroso
Miembro del equipo
Moderador/a
Quizás a la primera no capten de que trata este aporte. Bueno les explico. En las Roms de tercera generación existe una tabla de funciones estandarizadas que sirven a la ROM para llamar scripts predefinidos para evitar que el sistema cargue un montón de comandos cada que se hace un script determinado.

Los scripts estandarizados en FR se usan para los distintos msgbox existentes. La tabla de funciones estandarizadas es la siguiente, junto a su equivalente en XSE:

Código:
0x0: MSG_OBTAIN
0x1: MSG_FIND
0x2: MSG_FACE
0x3: MSG_SIGN
0x4: MSG_KEEPOPEN
0x5: MSG_YESNO
0x6: MSG_NORMAL
0x7: MSG_ADDDECORATION
0x8: MSG_ADDPOKENAV (Solo Emerald,  Duplicado de 0x0 en Ruby/FR)
0x9: Mensaje con fanfare (Solo Emerald, Duplicado de 0x0 en Ruby/FR)
0xA: MSG_POKENAV (Solo Emerald)
El punto es que dichas funciones son fácilmente expandibles y de esta manera agregar más msgboxes para lo que necesitemos. En este caso he agregado tres nuevas funciones para Fire Red, las cuales son las siguientes:

Código:
0xA: MSG_MINIBOX (Para cargar l¿una minicaja con el nombre de quien habla)
0xB: Función para ocultar la minicaja.
0xC: MSG_TRANSPARENT (Para caja de texto transparente)
Para expandir y agregar estas nuevas funciones, lo que deben hacer es simplemente aplicar el parche que está al final del tutorial. Este parche ocupa los bytes 0x89F0000 hasta 0x89F04B0.

Tras aplicar el parche debes de pegar el archivo "std.rbh" en la carpeta donde tienes tu XSE 1.1.1 guardado. Debes de sustituir el que tienes por este. Y listo, con eso ya has expandido las funciones estandarizadas.

================================
Tutorial de Uso de nuevas funciones
================================
Uasar las nuevas funciones es relativamente sencillo. Es cuestión solamente de hacer un script donde se llame dichas rutinas y estas se mostrarán. Aqui dejo un script de ejemplopara las funciones agregadas:

0xA y 0xB: Minicaja de texto para nombres:
Código:
#Dynamic 0xC00000
#org @start
lock
faceplayer
msgbox @nombre MSG_MINIBOX //Cargará una minicaja de texto donde podemos poner el nombre del personaje hablando. Puede reemplazarse por 0xA
msgbox @texto //Aqui va el texto común y corriente
callstd 0xB //Llama la función que esconde la minicaja secundaria. Si no se pone este comando la caja no desaparece
release
end

#org @nombre
= Prof. Elm

#org @texto
= Come on, [player]! Choose a Pokémon
Resultado final:


0xC: Caja transparente:
Código:
#Dynamic 0xC00000
#org @start
lock
faceplayer
msgbox @texto MSG_TRANSPARENT //Carga la transparencia de las cajas de texto normales. Puede reemplazarse por 0xC
release
end

#org @texto
= Come on, [player]! Choose a Pokémon
Y el resultado de el script:



Y eso sería todo. Siempre tengan en cuenta que la caja solo soporta 10 carácteres para el nombre. Aunque hay que tener en cuenta que usualmente los nombres no suelen pasar los 10 carácteres, lo cual debería ser suficiente.

>>>Click aquí para descargar parche ips<<<

=====================================
Extra - Aplicando manualmente cambios
=====================================

Si tienes el problema de @darkeon75 y no puedes poner esto manualmente, deberás de descargar estos archivos que contienen lo que he hecho. Las instrucciones para plicarlo manualmente so las siguientes:

1. Habrá que repuntear la tabla de comandos estandarizados, la tabla se encuentra en 0x08160450. Debes copiar todas las entradas de la tabla y ponerla en un espacio libre donde quepan más punteros. Puedes tambien solo abrir el archivo stdfunc_table.bin del archivo anterior que tiene la tabla ya seleccionada. Es muy importante que no modifiques estas entradas, pues varios comandos usan dichas funciones en varios procesos.

2. Ya que pegues la tabla debes de calcular cuantas entradas nuevas vas a poner en la tabla. Cada entrada es un puntero común, osea 0x4 bytes. Debes apuntar el offset donde empieza la tabla y tambien el offset donde termina la tabla +1 (Esto se refiere al último byte de la tabla sumado, que debe ser siempre un 08). ya con esa información anotada deberás cambiar los siguientes punteros, todos en formato little endian.

Punteros donde inicia la tabla: 0x0806A178, 0x0806A1A8, 0x0806A1F4 y 0x0806A240
Punteros donde acaba la tabla: 0x0806A17C, 0x0806A1AC, 0x0806A1F8 y 0x0806A244

Guarda y con eso ya has repunteado la tabla de funciones estandarizadas. Todos los msgbox deberían funcionarte sin problemas.

3. Ahora agregaremos las nuevas funciones. Para agregar la función MSG_MINIBOX:

Abre el archivo routine_minibox.bin, copia su contenido y pégalo en tu Rom en una offset libre alineada, apunta la dirección donde la pegaste.

Ahora abre el archivo std_minibox_0xA.bin, copia todo su contenido en una offset libre (no importa si no está alineada), apunta la offset donde lo pusiste y agrega el puntero de la misma como nueva entrada. Al final del archivo .bin se leen los datos FF FF FF 08. Deben reemplazar esos FF's con el puntero de la offset de la rutina que carga la minicaja +1, que es la que previamente pusimos en una offset alineada, ya que cargamos una rutina asm THUMB. Si agregas este comando justo después de donde acaba la tabla original, esta se convierte en la función 0xA.

Finalmente solo queda abrir el archivo std_unload_minibox_0xB.bin, copian su contenido y lo pegan en una offset libre, apunten la offset y agreguen su puntero a la tabla de funciones. Si lo pones justo después de la función que carga la minicaja, la función toma el iD 0xB.

Para agregar la función MSG_TRANSPARENT:

Abre los archivos routine_transparent_boxes.bin y routine_unload_transparent_boxes.bin. Copia su contenido y pegalo en tu Rom en cualquier offset libre alineada. Tambien copia y pega el contenido del archivo pallete_transparent_boxes.bin . Copia el puntero de ambas rutinas y del tercer archivo. Si te das cuenta al final de la rutina routine_transparent_boxes.bin esta acaba con los bytes FF FF FF 08, Este es el puntero de donde pusiste el archivo pallete_transparent_boxes.bin, cambia los FF's por el puntero donde pusiste el arvhibo anterior. No hay que sumar nada. Guarda. Ten en cuenta que el archivo pallete_transparent_boxes.bin es una paleta que es editable con APE, Cambialo a tu gusto si quieres colores distintos para las cajas transparentes

Finalmente agregaremos la última función estandarizada, para ello abre el archivo std_msgbox_transparent_0xC.bin. Copia y pega su contenido en tu Rom, guarda el puntero donde lo has puesto. Notarás que en el archivo hay un grupo de bytes que contiene FE FE FE 08 y FF FF FF 08, Debes de reemplazar primero los FE's por el puntero donde pusiste el archivo routine_transparent_boxes.bin +1, ya que es una rutina ASM. Del mismo modo reemplazar los FF's por el puntero donde pusiste el archivo routine_unload_transparent_boxes.bin +1. Tras haber hecho esto solo queda tomar el puntero de la función y agregarlo a la tabla de funciones estandarizadas. Guarda tu ROM.

Si has seguido correctamente los anteriores pasos, las tres funciones deberían funcionarte sin problema. Solo queda que edites el archivo "std.rbh" en tu carpeta de XSE para que el compilador tome las nuevas entradas (O usar el que puse en el enlace del parche si usaste los mismos iD de las nuevas funciones)

====================================================

Bugs y/o rarezas:
* La minicaja secundaria es incapaz de leer cadenas de texto guardadas en búfer, por ende no les mostrará el nombre de su rival o cualquier nombre guardado en un búfer. Es un bug de la rutina original.
* La textbox transparente no reconoce colores de texto, todos los textos quedan blancos.
* Por el momento la caja transparente solo funciona como MSG_NORMAL

Créditos:
*Misingyep por la rutina original de caja secundaria
*ep!c por la rutina original de caja transparente
*Gold/Ruki (Osea yo) por expandir las funciones estandarizadas y arreglar el problema de la rutina original de textbox transparente que solo funcionaba en la offset 0x8750000.
 
Última edición:

darkeon75

Un vaso es un vaso y un plato es un plato -M.Rajoy
¿Habría alguna manera de hacerlo manualmente sin necesidad de parche?
Esas direcciones las tengo ocupadas.
 
Última edición por un moderador:

KERBEROS

Usuario de Platino
Uyuyui!
Esto me viene muy bien!
Y aunque podría hacerlo Manualmente!
Tengo esos offset vacios Para parchar.
¿Casualidad?
¡ NO LO CREO!
 

Robiuwu

SPRITER AYUDANTE &#936;(&#8807;&#969;&#8806;)&#936
me parece super wapo el aporte, pero tengo una pregunta con respecto a la caja de texto transparente.
se pude colocar en algun pito especifico (abajo, arriba, el centro de la pantalla)? ya que he visto algunas rutinas de la textbox transparente que hacen esto y me preguntaba si esto lo tiene
 

Dr. Seuss

Loco Peligroso
Miembro del equipo
Moderador/a
me parece super wapo el aporte, pero tengo una pregunta con respecto a la caja de texto transparente.
se pude colocar en algun pito especifico (abajo, arriba, el centro de la pantalla)? ya que he visto algunas rutinas de la textbox transparente que hacen esto y me preguntaba si esto lo tiene
https://whackahack.com/foro/t-43356/fr-textbox-transparente-tutorial-educativo

Incluso en ese tuto hay información de como ponerlo en pantalla oscuro para hacer efecto flashback
 

Ayman

Cazador Sin Recompensa
Sinceramente bravó!
Este parche es perfectamente perfecto, y te aseguro que le va a servir a todo aquel que lo vea, muchas gracias por hacer este tipo de tutorial!
Pero hay una cosa que no me queda muy clara, si yo añado un mini, como sabrá el script como se llama el mini?, O donde pone @nombre es donde lo tengo que poner?( Aunque en teoría eso no tiene nada que ver por qué al igual que en un msgbox el @es un pointer)(creo?
Gracias por este tuto Goldo
 

Rubire4

Moderador Global
Miembro del equipo
Moderador Global
Sinceramente bravó!
Este parche es perfectamente perfecto, y te aseguro que le va a servir a todo aquel que lo vea, muchas gracias por hacer este tipo de tutorial!
Pero hay una cosa que no me queda muy clara, si yo añado un mini, como sabrá el script como se llama el mini?, O donde pone @nombre es donde lo tengo que poner?( Aunque en teoría eso no tiene nada que ver por qué al igual que en un msgbox el @es un pointer)(creo?
Gracias por este tuto Goldo
El @nombre es una dirección dinámica hacia el texto, el cual puedes ver en la última parte del script de ejemplo:

Código:
#Dynamic 0xC00000
#org @start
lock
faceplayer
msgbox @nombre MSG_MINIBOX //Cargará una minicaja de texto donde podemos poner el nombre del personaje hablando. Puede reemplazarse por 0xA
msgbox @texto //Aqui va el texto común y corriente
callstd 0xB //Llama la función que esconde la minicaja secundaria. Si no se pone este comando la caja no desaparece
release
end

[B][U]#org @nombre
= Prof. Elm[/U][/B]

#org @texto
= Come on, [player]! Choose a Pokémon
 

eMMe97

Usuario de Bronce
Great Post! With your information I created new callstd. The guide is in Italian, but honestly I think it is understandable (Italian and Spanish are not that different LOL).

:pacman: [size=large]Aggiornamento callstd 0x0: Messaggio Oggetto Ottenuto 2.0[/size] + [size=large]Aggiornamento callstd 0x1: Messaggio Oggetto Trovato 2.0[/size]

Questa funzione è stata già sviluppata tempo fa da Andrea, potete reperire il post originale qui.

Penso che questa versione sia un aggiornamento della routine di Andrea, poiché permette di estendere la funzione ad entrambe le categorie (trovato/ottenuto), e sfrutta gli oam per la visualizzazione dell'oggetto, che permettono una resa grafica migliore. Non pensiate che non abbia richiesto aiuto ad Andrea per lo sviluppo della funzione. Il Maestro è onnipresente xD
Queste sono le routine che servono per entrambe le versioni:

Routine1:

Código:
.align 2
.thumb

main:
push {r0-r3, lr}
ldrh r0, =(0x020370C0)
ldrh r0, [r0]
mov r2, #0x8
mul r0, r0, r2
ldr r3, =(0x083D4294) @tabellaITEM
add r0, r0, r3
ldr r2, [r0] @valore
ldr r1, =(0x0202402C) @ram_table
str r2, [r1]
ldr r2, [r0, #0x4]
str r2, [r1, #0x4]
ldr r2, =(0x0000000F)
str r2, [r1, #0x8]
pop {r0-r3, pc}

.align 2

Routine2:

Código:
.align 2
.thumb

.equ TABLE, 0x0202402C
.equ DEST, 0x06014000
.equ BUFFER, 0x020377F8
.equ CREATEOAM, 0x08006F8D
.equ OAMNUM, 0x0203C000
.equ OAMBUFFER, 0x0202063C

READING:
push {r0-r7, lr}
mov r0, #0x0
mov r5, #0x0
mov r2, #0xC
mul r5, r2
ldr r1, =TABLE
add r5, r5, r1
ldr r6, [r5] @/*R5=TABLE
mov r0, #0x0
mov r7, r0 @/*SLOT#
mov r2, #0x80
lsl r2, r2, #0x4
mul r0, r0, r2
ldr r3, =(0x0202403C)
add r3, r3, r0
mov r0, r6
mov r1, r3
swi 0x12
mov r3, #0x0

loop:
ldr r0, = 0x0202403C
mov r4, #0x60
mul r4, r3
add r0, r0, r4
ldr r1, =DEST
lsl r4, r3, #0x7
add r1, r1, r4
mov r2, #0x30
push {r0-r3}
swi 0xB
pop {r0-r3}
add r3, r3, #0x1
cmp r3, #0x3
bne loop
add r5, r5, #0x4 @/*PALETTE
ldr r0, [r5]
ldr r1, =(0x020379d8) @paletta15
swi 0x12
mov r0, r1
add r5, r5, #0x4
ldrb r1, [r5]
ldr r5, =OAMNUM @/*PAL# IN R7
add r5, r5, #0x4F
strb r1, [r5]
mov r2, #0x20
mul r1, r2
ldr r3, =BUFFER
add r1, r1, r3
lsr r2, r2, #0x2
swi 0xC

LOADOBJ:
ldr r0, DATA
mov r3, #0xA0
mov r5, #0x30
add r1, r5, r3
mov r2, #0x8B
mov r3, #0x0
ldr r4, =CREATEOAM
bl EXECUTE
ldr r1, =OAMNUM
add r1, r1, r7
strb r0, [r1]
ldr r2, =OAMBUFFER
mov r1, #0x44
mul r0, r0, r1
add r0, r0, r2
add r0, r0, #0x5
ldr r3, =OAMNUM
add r3, r3, #0x4F
ldrb r1, [r3]
lsl r1, r1, #0x4
strb r1, [r0]
pop {r0-r7}
pop {pc}

EXECUTE:
bx r4

.align 2
DATA: .word BUFFERDATA + 0x08[offset]
BUFFERDATA:
.hword 0x2
.hword 0x1
.word OAMDATA + 0x08[offset]
.word ANIMATION + 0x08[offset]
.word 0x0
.word 0x08231CFC
.word 0x080EE4DD
.byte 0xFF

.align 2
ANIMATION: .word OAMANIM + 0x08[offset]
OAMANIM:
.hword 0x201
.hword 0xA
.hword 0xFFFE
.hword 0x0

.align 2
OAMDATA:
.byte 0x0
.byte 0x0
.byte 0x0
.byte 0xa0
.hword 0x1
.hword 0x0
Nel campo [offset] dovete inserire l'offset di dove inserite la Seconda Routine, mi raccomando SENZA il +1!

Routine3:

Código:
.text
.align 2
.thumb
.thumb_func

push {r0-r3, lr}
ldr r0, =0x06014000
mov r1, #0x80
mov r2, #0

loop:
str r2, [r0]
add r0, #4
sub r1, r1, #1
bpl loop
pop {r0-r3, pc}

Compiliamo adesso questi due script, cioè i nuovi script di ottenimento e ritrovamento. Sta a voi sostituire le voci indicate con routine, con gli offset di dove le avete inserite, stavolta aggiungendo il +1!

Script Ottieni:

Código:
#dynamic 0x800000
#org @inizio
copyvar 0x8013 0x8012
copyvar 0x8004 0x8000
copyvar 0x8005 0x8001
textcolor 0x3
additem 0x8000 0x8001
copyvar 0x8007 LASTRESULT
call @primo
copyvar 0x8012 0x8013
return

'---------------
#org @primo
bufferitems 0x1 0x8000 0x8001
checkitemtype 0x8000
call @secondo
compare 0x8007 0x1
if 0x1 call @terzo
compare 0x8007 0x0
if 0x1 call @quinto
return

'---------------
#org @secondo
copyvar 0x8000 LASTRESULT
compare 0x8000 0x1
if 0x1 goto [MENTION=28119]Quar[/MENTION]to
compare 0x8000 0x2
if 0x1 goto @sesto
compare 0x8000 0x3
if 0x1 goto @settimo
compare 0x8000 0x4
if 0x1 goto @ottavo
compare 0x8000 0x5
if 0x1 goto @nono
end

'---------------
#org @terzo
callasm 0x[Prima_Routine]+1
pause 0x1
callasm 0x[Seconda_Routine]+1
compare 0x8005 0x1
if 0x3 call @decimo
compare 0x8005 0x1
if 0x2 call [MENTION=39865]Undi[/MENTION]cesimo
waitfanfare
waitmsg
callasm 0x[Seconda_Routine]+1
msgbox @mess1 MSG_KEEPOPEN
setvar LASTRESULT 0x1
callasm 0x[Terza_Routine]+1
return

'---------------
#org @quinto
setvar LASTRESULT 0x0
return

'---------------
#org [MENTION=28119]Quar[/MENTION]to
bufferstd 0x2 0x18
compare 0x8007 0x1
if 0x1 call @dodicesimo
return

'---------------
#org @sesto
bufferstd 0x2 0x19
compare 0x8007 0x1
if 0x1 call @dodicesimo
return

'---------------
#org @settimo
bufferstd 0x2 0x1A
compare 0x8007 0x1
if 0x1 call @dodicesimo
return

'---------------
#org @ottavo
bufferstd 0x2 0x1B
compare 0x8007 0x1
if 0x1 call @tredicesimo
return

'---------------
#org @nono
bufferstd 0x2 0x1C
compare 0x8007 0x1
if 0x1 call @dodicesimo
return

'---------------
#org @decimo
special2 LASTRESULT 0x196
compare LASTRESULT 0x0
if 0x1 call @quattordici
compare LASTRESULT 0x1
if 0x1 call @quindici
return

'---------------
#org [MENTION=39865]Undi[/MENTION]cesimo
buffernumber 0x0 0x8005
preparemsg @mess2
return

'---------------
#org @dodicesimo
fanfare 0x101
return

'---------------
#org @tredicesimo
fanfare 0x101
return

'---------------
#org @quattordici
preparemsg @mess3
return

'---------------
#org @quindici
preparemsg @mess4
return


'---------
' Strings
'---------
#org @mess1
= [player] mette [buffer2]\nin [buffer3].

#org @mess2
= Ottiene [buffer1] [buffer2]!

#org @mess3
= Ottiene [buffer2]!

#org @mess4
= [player] ottiene [buffer2]!\nContiene [buffer1].

Script Trova:

Código:
#dynamic 0x800000
#org @inizio
lock
faceplayer
callasm 0x[Prima_Routine]+1
checksound
copyvar 0x8004 0x8000
copyvar 0x8005 0x8001
checkitemroom 0x8000 0x8001
copyvar 0x8007 LASTRESULT
bufferitem 0x1 0x8000
checkitemtype 0x8000
call @primo
compare 0x8007 0x1
if 0x1 call @secondo
compare 0x8007 0x0
if 0x1 call @terzo
release
return

'---------------
#org @primo
copyvar 0x8000 LASTRESULT
compare 0x8000 0x1
if 0x1 goto [MENTION=28119]Quar[/MENTION]to
compare 0x8000 0x2
if 0x1 goto @quinto
compare 0x8000 0x3
if 0x1 goto @sesto
compare 0x8000 0x4
if 0x1 goto @settimo
compare 0x8000 0x5
if 0x1 goto @ottavo
end

'---------------
#org @secondo
hidesprite LASTTALKED
callasm 0x[Seconda_Routine]+1
additem 0x8004 0x8005
special2 LASTRESULT 0x196
copyvar 0x8008 LASTRESULT
compare 0x8008 0x1
if 0x1 call @nono
compare 0x8008 0x0
if 0x1 call @decimo
waitfanfare
waitmsg
msgbox @mess1 MSG_KEEPOPEN
callasm 0x[Terza_Routine]+1
return

'---------------
#org @terzo
callasm 0x[Seconda_Routine]+1
msgbox @mess2 MSG_KEEPOPEN
callasm 0x[Terza_Routine]+1
msgbox @mess3 MSG_KEEPOPEN
setvar LASTRESULT 0x0
return

'---------------
#org [MENTION=28119]Quar[/MENTION]to
bufferstd 0x2 0x18
compare 0x8007 0x1
if 0x1 call [MENTION=39865]Undi[/MENTION]ci
return

'---------------
#org @quinto
bufferstd 0x2 0x19
compare 0x8007 0x1
if 0x1 call [MENTION=39865]Undi[/MENTION]ci
return

'---------------
#org @sesto
bufferstd 0x2 0x1A
compare 0x8007 0x1
if 0x1 call [MENTION=39865]Undi[/MENTION]ci
return

'---------------
#org @settimo
bufferstd 0x2 0x1B
compare 0x8007 0x1
if 0x1 call @dodici
return

'---------------
#org @ottavo
bufferstd 0x2 0x1C
compare 0x8007 0x1
if 0x1 call [MENTION=39865]Undi[/MENTION]ci
return

'---------------
#org @nono
preparemsg @mess4 '"[player] found a [buffer2]!\nIt co..."
return

'---------------
#org @decimo
preparemsg @mess5 '"[player] found one [buffer2]!"
return

'---------------
#org [MENTION=39865]Undi[/MENTION]ci
fanfare 0x101
return

'---------------
#org @dodici
fanfare 0x101
return


'---------
' Strings
'---------
#org @mess1
= [player] mette [buffer2]\ndentro [buffer3].

#org @mess2
= Hai trovato [buffer2]!

#org @mess3
= Oh no!\nLo Zaino è pieno[.]

#org @mess4
= [player] trova [buffer2]!\nContiene [buffer1].

#org @mess5
= [player] trova [buffer2]!

NB. Se volete potete ulteriormente personalizzare gli script come più vi piace, aggiungendo suoni o immagini, cambiare testi, insomma fate vobis!

A questo punto abbiamo quasi finito. Rechiamoci all'offset 0x08160450 dove è presente la table con i pointer dei vari callstd. Andiamo al primo e secondo pointer (sarebbero lo 0x0 0x1) e cambiamoli con il pointer di dove abbiamo inserito gli script (il primo DEVE essere quello di ottenimento e dopo quello di ritrovamento), ma stavolta NON aggiungete il +1!

***** Variante di Skeli *****

Un hacker che sta prendendo molto campo negli ultimi tempi, ha presentato un Upgrade totale di Pokémon Fire Red. Tra le novità vi è anche una sua versione del giveitem. Ho analizzato per bene le routine e ho estrapolato le parti che mi interessavano per riproporle qui. Penso che non gli dispiacerà se gli "rubo" qualcosina, dato che ha fatto lo stesso lui con questo forum, non ci tando neanche Andrea nei crediti :p

In questa variante avremo solo 2 routine (in pratica Seconda_Routine e Terza_Routine, negli script dovrete cancellare tutti i callasm Prima_Routine) con degli effetti simili, ma risultati più interessanti. Infatti se l'oggetto sarà un oggetto chiave, una mt o simili, questi non compariranno nella textbox ma al centro dello schermo con dimensioni raddoppiate.

Seconda Routine:

Código:
.align 2
.thumb

main:
push {r4, r5, r6, lr}
ldr r1, =0xfdf3
ldr r4, =0x20370c0
mov r0, r1
ldrh r2, [r4]
ldr r3, =0x8098759
bl fcn.09b71a32
mov r6, r0
cmp r0, #0x40
beq primo
ldrh r0, [r4]
ldr r3, =0x809a9d9
bl fcn.09b71a32
mov r3, #0x44
sub r5, r0, #0x2
mov r0, #0xfd
mov r4, r3
mul r4, r6, r4
ldr r3, =0x202063c
and r5, r0
add r4, r4, r3
cmp r5, #0x0
bne secondo
mov r3, #0x3
ldrb r2, [r4, #0x1]
orr r3, r2
strb r3, [r4, #0x1]
ldr r3, =0x8008595
bl fcn.09b71a32
mov r3, #0x1f
movs r1, #0x3e
and r0, r3
ldrb r3, [r4, #0x3]
lsl r2, r0, #0x1
bic r3, r1
orr r3, r2
mov r2, #0x80
lsl r2, r2, #0x2
strb r3, [r4, #0x3]
mov r1, r2
mov r3, r5
ldr r5, =0x800865d
bl fcn.09b71a36
mov r3, #0x40
mov r2, #0x70

terzo:
strh r2, [r4, #0x24]
mov r2, #0xc
strh r3, [r4, #0x26]
ldrb r3, [r4, #0x5]
bic r3, r2
strb r3, [r4, #0x5]

primo:
ldr r3, =0x20370c4
strh r6, [r3]
pop {r4, r5, r6, pc}

secondo:
mov r3, #0x8c
mov r2, #0xd5
b terzo

fcn.09b71a32:
bx r3

fcn.09b71a36:
bx r5

.align 2

Terza Routine:

Código:
.align 2
.thumb

main:

push {r4, r5, r6, lr}
ldr r4, =0xfdf3
ldr r3, =0x800874d
mov r0, r4
bl fcn.09b71a32
mov r0, r4
mov r4, #0x44
ldr r5, =0x20370c4
ldr r3, =0x8008a31
bl fcn.09b71a32
ldrh r3, [r5]
mov r0, r3
mul r0, r4, r0
ldr r6, =0x202063c
ldr r3, =0x80077d9
add r0, r0, r6
bl fcn.09b71a32
ldrh r3, [r5]
mov r0, r3
mul r0, r4, r0
ldr r3, =0x8007281
add r0, r0, r6
bl fcn.09b71a32
pop {r4, r5, r6, pc}

fcn.09b71a32:
bx r3

.align 2


:pacman: [size=large]Nuovo callstd 0x7: Textbox Trasparente.[/size]

Una delle implementazioni grafiche che solitamente piacciono è sicuramente quella della textbox trasparente. Tuttavia è un po' macchinosa da realizzare, anche perché viene di solito utilizzata una routine molto lunga che non ho ben capito. Ho quindi riscritto la routine ed automatizzato tutto. Adesso basterà mettere il numero 0x7 ed avrete la textbox trasparente, che non richiederà altre attenzioni. Nessun callasm e niente altro. Se in uno script inserirete 0x7 allora la textbox sarà trasparente, altrimenti, inserendo 0x6, per esempio, avrete la vostra solita textbox.

Vediamo come procedere per l'inserimento. Lascio una patch infondo alla guida. La patch NON occupa spazio ulteriore, quindi non ci saranno problemi di compatibilità!

Routine 1: cambio trasparenza e colore palette.

Código:
.align 2
.thumb

push {r0-r2, lr}

ldr r1, = 0x02037ac0
mov r0, #0x80
strb r0, [r1]

ldr r0, = 0x08FFFFFF
ldr r1, = 0x050001e0
mov r2, #0x10
svc 0xb

ldr r0, = 0x04000048
ldrh r1, = 0x1F3F
strh r1, [r0]

ldr r0, = 0x04000050
ldrh r1, = 0x3F41
strh r1, [r0]

ldr r0, = 0x04000052
ldrh r1, = 0x0B1F
strh r1, [r0]

ldr r0, = 0x08FFFFFF
ldr r1, = 0x020377D8
mov r2, #0x10
swi 0xB

pop {r0-r2, pc}

.align 2

Al posto di FF FF FF dovrete mettere l'offset di dove inserirete la paletta alternativa, se volete potete utilizzare questa:

Código:
00 00 00 00 FF FF 00 00 10 FF FF FF FF FF FF FF FF FF FF FF 00 00 00 00 00 00 00 00 00 00 00 00
Se la applicata, le donne avranno il testo rosso, mentre gli uomini bianco (purtroppo per ora non so come non rendere trasparente il blu...).

Potete diminuire o aumentare il livello di trasparenza agendo su questo valore ldrh r1, = 0x0B1F in particolare cambiate 0B con valori che vanno da 00 a 1F.

Routine 2: ripristino valori

Código:
.align 2
.thumb

push {r0-r2, lr}

ldr r1, = 0x02037ac0
mov r0, #0x40
strb r0, [r1]

ldr r0, = 0x0841F1C8
ldr r1, = 0x050001e0
mov r2, #0x10
svc 0xb

ldr r0, = 0x04000048
ldrh r1, = 0x1F1F
strh r1, [r0]

ldr r0, = 0x04000050
ldrh r1, = 0x1E40
strh r1, [r0]

ldr r0, = 0x04000052
ldrh r1, = 0x1000
strh r1, [r0]

ldr r0, = 0x0841F1C8
ldr r1, = 0x020377D8
mov r2, #0x10
swi 0xb

pop {r0-r2, pc}

.align 2

Inserite tutto in spazi liberi della ROM. Adesso inserire anche questo script:

Código:
#dynamic 0x800000
#org @inizio
callasm 0x8[Prima Routine+1]
preparemsg 0x0
waitmsg
waitkeypress
release
callasm 0x8[Seconda Routine+1]
return

Se volete una versione già compilata:

[code]23 FF FF FF 08 67 00 00 00 00 66 6D 6C 23 EE EE EE 08 03
dove al posto di FF FF FF inserite il pointer della prima routine+1 ed al posto di EE EE EE inserite il pointer della seconda routine+1.

Rechiamoci adesso all'offset 0x08160450 dove è presente la table con i pointer dei vari callstd. Andiamo all'ottavo pointer (sarebbe lo 0x7) e cambiamolo con il pointer di dove abbiamo inserito lo script che richiama le altre due, ma stavolta NON aggiungete il +1! Infatti, grazie alla ricerca di Andrea, questa table rimanda a semplici script e non routine![/code]

Salvate tutto ed avete finito.

Patch:
Callstd 0x7: Textbox Trasparente


:pacman: [size=large]Nuovo callstd 0x8: Textbox Plus.[/size]

Penso che un'immagine valga più di mille parole, poi spiegher tutto.



Questo callstd è in grado di visualizzare oltre alla solita textbox anche una etichetta in altro di dimensioni e posizione variabili con un testo personalizzato da noi. Si possono inserire varie colorazioni del testo ed anche i buffer (risolve un problema con una targhetta diversa utilizzata da altri hackers).
Inoltre è possibile inserire accanto alla textbox lo sprite di un pokémon o un allenatore in perfetto stile La Vendetta di Mew, pescando lo sprite da quelli già presenti nelle rom. Non è finita qui però. Nel caso si visualizzi un pokémon è possibile sceglierne la colorazione se normale o shiny, mentre per l'allenatore è possibile scegliere se visualizzarlo normalmente o solo una sagoma nera (utile nel caso non si conosca l'identità dell'allenatore prima di una presentazione ufficiale no?).
Le routine sono 5, come al solito lascerò tutte le istruzioni.

Routine_PKMNTRNR1:

Código:
.align 2
.thumb

main:
push {r0-r7, lr}
ldrh r0, =(0x020370C0) @var8004
ldrh r0, [r0]
mov r2, #0x8
mul r0, r0, r2
ldr r7, =(0x020370C2) @var8005
ldrb r7, [r7]
cmp r7, #0x1
beq pokemon
ldr r3, =(0x0823957C) @tabellaTRAINER
add r4, r0, r3
ldr r2, [r4] @valore
ldr r5, =(0x020370C4) @var8006
ldrb r5, [r5]
cmp r5, #0x1
beq nero
ldr r5, =(0x08239A1C)
add r6, r0, r5
ldr r7, [r6] @valorePALETTE
b tabella

nero:
ldr r5, =(0x0823957C)
add r6, r0, r5
ldr r7, [r6] @valorePALETTE
b tabella

pokemon:
ldr r3, =(0x082350AC) @tabellaPOKEMON
add r4, r0, r3
ldr r2, [r4] @valore
ldr r5, =(0x020370C4) @var8006
ldrb r5, [r5]
cmp r5, #0x1
beq shiny
ldr r5, =(0x0823730C)
add r6, r0, r5
ldr r7, [r6] @valorePALETTE
b tabella

shiny:
ldr r5, =(0x082380CC)
add r6, r0, r5
ldr r7, [r6] @valorePALETTEshiny

tabella:
ldr r1, =(0x0202402C) @ram_table
str r2, [r1]
str r7, [r1, #0x4]
ldr r2, =(0x0000000F)
str r2, [r1, #0x8]
pop {r0-r7, pc}

.align 2
Routine_PKMNTRNR2:

Código:
.align 2
.thumb

.equ TABLE, 0x0202402C
.equ DEST, 0x06014000
.equ BUFFER, 0x020377F8
.equ CREATEOAM, 0x08006F8D
.equ OAMNUM, 0x0203C000
.equ OAMBUFFER, 0x0202063C

READING:
push {r0-r7, lr}
mov r0, #0x0
mov r5, #0x0
mov r2, #0xC
mul r5, r2
ldr r1, =TABLE
add r5, r5, r1
ldr r6, [r5] @/*R5=TABLE
mov r0, #0x0
mov r7, r0 @/*SLOT#
mov r2, #0x80
lsl r2, r2, #0x4
mul r0, r0, r2
ldr r3, =DEST
add r3, r3, r0
mov r0, r6
mov r1, r3
swi 0x12
add r5, r5, #0x4 @/*PALETTE
ldr r0, [r5]
ldr r1, =(0x020379d8) @paletta15
swi 0x12
mov r0, r1
add r5, r5, #0x4
ldrb r1, [r5]
ldr r5, =OAMNUM @/*PAL# IN R7
add r5, r5, #0x4F
strb r1, [r5]
mov r2, #0x20
mul r1, r2
ldr r3, =BUFFER
add r1, r1, r3
lsr r2, r2, #0x2
swi 0xC

LOADOBJ:
ldr r0, DATA
mov r3, #[color=#FF0000]0x9A[/color]
mov r5, #0x30
add r1, r5, r3
mov r2, #[color=#FF0000]0x7B[/color]
mov r3, #0x0
ldr r4, =CREATEOAM
bl EXECUTE
ldr r1, =OAMNUM
add r1, r1, r7
strb r0, [r1]
ldr r2, =OAMBUFFER
mov r1, #0x44
mul r0, r0, r1
add r0, r0, r2
add r0, r0, #0x5
ldr r3, =OAMNUM
add r3, r3, #0x4F
ldrb r1, [r3]
lsl r1, r1, #0x4
strb r1, [r0]
pop {r0-r7}
pop {pc}

EXECUTE:
bx r4

.align 2
DATA: .word BUFFERDATA + 0x08[offset]
BUFFERDATA:
.hword 0x2
.hword 0x1
.word OAMDATA + 0x08[offset]
.word ANIMATION + 0x08[offset]
.word 0x0
.word 0x08231CFC
.word 0x080EE4DD
.byte 0xFF

.align 2
ANIMATION: .word OAMANIM + 0x08[offset]
OAMANIM:
.hword 0x201
.hword 0xA
.hword 0xFFFE
.hword 0x0

.align 2
OAMDATA:
.byte 0x0
.byte 0x0
.byte 0x0
.byte 0xC0
.hword 0x1
.hword 0x0
N.B. i valori in rosso sono i valori x e y dello sprite, potete cambiare la posizione a vostro piacimento.

Routine_rimozionePKMNTRNR: possiamo utilizzare la stessa Routine3 del callstd 0x0, la riporto per praticità.

Código:
.text
.align 2
.thumb
.thumb_func

push {r0-r3, lr}
ldr r0, =0x06014000
mov r1, #0x80
mov r2, #0

loop:
str r2, [r0]
add r0, #4
sub r1, r1, #1
bpl loop
pop {r0-r3, pc}
Routine_minibox:

Código:
.text
.align 2
.thumb
.thumb_func

box_func:
push {r4, lr}
ldr r4, =0x2037101 @spazio libero ram
LDR R0, =0x0202403C @spazio_table_ram
mov r2, #0
strb r2, [r0]
LDRH R2, [R1]
STRB R2, [R0, #0x1] @X
LDRH R2, [R1, #0x2]
STRB R2, [R0, #0x2] @Y
LDRH R2, [R1, #0x4]
STRB R2, [R0, #0x3] @W
LDRH R2, [R1, #0x6]
STRB R2, [R0, #0x4] @H
mov r2, #0xe
STRB R2, [R0, #0x5]
mov r2, #0x8
STRB R2, [R0, #0x6]
mov r2, #0x0
STRB R2, [R0, #0x7]
mov r2, #76
STRB R2, [R0, #0x8]
mov r2, #0x9f
STRB R2, [R0, #0x9]
mov r2, #0x41
STRB R2, [R0, #0xa]
mov r2, #0x8
STRB R2, [R0, #0xb]
ldr r3, =0x8003ce5
bl call_r3
strb r0, [r4]
ldr r3, =0x8003fa1
bl call_r3
ldrb r0, [r4]
mov r1, #0
ldr r3, =0x80F6F1D @Something with BGs
bl call_r3
bl print_string
ldr r0, =(0x8[offset] + print_string)
mov r1, #2
pop {r4, pc}

print_string:
push {r4-r7, lr}
sub sp, sp, #0xC
add r7, r0, #0
ldr r5, =0x2021D18 @displayed_string
ldr r1, =0x3000F14 @loader 0x0
ldr r1, [r1]
mov r0, r5
ldr r3, =0x8008FCD @body_string_loader
bl call_r3
ldr r0, =0x2037101 @spazio libero ram
ldrb r0, [r0]
mov r1, #3
str r1, [sp]
mov r1, #0xff
str r1, [sp, #4]
mov r1, #0
str r1, [sp, #8]
mov r1, #2
add r2, r5, #0
mov r3, #4
ldr r4, =0x8002C49 @writeTextToTilemap
bl call_r4
ldr r0, =0x2037101 @spazio libero ram
ldrb r0, [r0]
mov r1, #2
ldr r3, =0x8003F21 @writeBoxesToTilemap
bl call_r3
add sp, sp, #0xC
pop {r4-r7, pc}

call_r3:
bx r3

call_r4:
bx r4

.align 2

Routine_RIMOZIONEminibox:

Código:
.text
.align 2
.thumb
.thumb_func

push {r0-r3, lr}
ldr r0, =0x02001840
ldr r3, =0x0600F800
mov r1, #0xFF
mov r2, #0

loop:
str r2, [r0]
str r2, [r3]
add r0, #4
sub r1, r1, #1
bpl loop
pop {r0-r3, pc}

Inseriamo tutte le routine segnando i relativi offset, quindi procediamo alla compilazione dello script:

Código:
#dynamic 0x800000
#org @inizio
callasm 0x8[Routine_PKMNTRNR1+1]
pause 0x1
callasm 0x8[Routine_PKMNTRNR2+1]
pause 0x1
callasm 0x8[Routine_minibox+1]
preparemsg 0x0
waitmsg
waitkeypress
callasm 0x8[Routine_rimuoviPKMNTRNR+1]
pause 0x1
callasm 0x8[Routine_RIMUOVIminibox+1]
return

Rechiamoci adesso all'offset 0x08160450 dove è presente la table con i pointer dei vari callstd. Andiamo al nono pointer (sarebbe lo 0x8) e cambiamolo con il pointer di dove abbiamo inserito lo script che richiama le altre due, ma stavolta NON aggiungete il +1! Infatti, grazie alla ricerca di Andrea, questa table rimanda a semplici script e non routine![/code]

Ed infine lo script:

Código:
#dynamic 0x800000
#org @inizio
faceplayer
setvar 0x8000 0x[posizione x del minibox]
setvar 0x8001 0x[posizione y del minibox]
setvar 0x8002 0x[larghezza minibox]
setvar 0x8003 0x[altezza minibox]
setvar 0x8004 0x[ID Allenatore/Pokémon]
setvar 0x8005 0x[00 per Allenatore, 01 per Pokémon]
setvar 0x8006 0x[00 per colori normali, 01 sagoma allenatore/pokémon shiny]
loadpointer 0x0 @mess0 //testo interno alla minibox
msgbox @mess1 0x8
release
end

#org @mess0
= Testo minibox\nsi può andare a capo

#org @mess1
= Normale testo della textbox

:pacman: [size=large]Nuovo callstd 0x9: Givepokemon.[/size]



Per l'ultimo callstd utile (è sempre possibile ingrandire la table, la mini guida è nelle premesse in alto), ho pensato di creare una specie di abbellimento del give pokémon: nel messaggio adesso apparirà a lato lo sprite del pokémon scelto, ovviamente lo sprite sarà animato!. Metterò 2 script alternativi. Uno dove sia possibile scegliere il pokémon da visualizzare tramite la var 8004 ed uno tramite la var 4001. Questo perché? Semplicemente perché nel gioco (ad eccezione degli starter, ma nella seconda versione risolver il problema nello script), prima di un qualsiasi givepokemon viene salvato l'ID anche nella var 4001, così nel gioco sarà tutto automatico, basterà cambiare il callstd.
Per ottenere questo effetto mi servirò sempre di 3 routine:

Prima_Routine:
Código:
.align 2
.thumb

main:
push {r0-r4, lr}
ldrh r0, =(0x020370C0)
ldrh r0, [r0]
mov r4, r0
mov r2, #0x4
mul r0, r0, r2
ldr r3, =(0x083D37A0) @tabellaPKMN
add r0, r0, r3
ldr r2, [r0] @valore
ldr r1, =(0x0202402C) @ram_table
str r2, [r1]
ldr r3, =(0x083D3E80) @tabellaVALORIpalette
add r3, r3, r4
ldrb r3, [r3]
cmp r3, #0x0
beq zero
cmp r3, #0x1
beq uno
ldr r2, =(0x083D3780)
b dopo

zero:
ldr r2, =(0x083D3740)
b dopo

uno:
ldr r2, =(0x083D3760)

dopo:
str r2, [r1, #0x4]
ldr r2, =(0x0000000F)
str r2, [r1, #0x8]
pop {r0-r4, pc}

.align 2

Seconda_Routine:

Código:
.align 2
.thumb

.equ TABLE, 0x0202402C @ram_table
.equ DEST, 0x06014000
.equ BUFFER, 0x020377F8
.equ CREATEOAM, 0x08006F8D
.equ OAMNUM, 0x0203C000
.equ OAMBUFFER, 0x0202063C

READING:
push {r0-r7, lr}
mov r0, #0x0
mov r5, #0x0
mov r2, #0xC
mul r5, r2
ldr r1, =TABLE
add r5, r5, r1
ldr r6, [r5] @/*R5=TABLE
mov r0, #0x0
mov r7, r0 @/*SLOT#   
mov r2, #0x20
lsl r2, r2, #0x4
mul r0, r0, r2
ldr r3, =DEST
add r3, r3, r0
mov r0, r6
mov r1, r3
swi 0xb
add r5, r5, #0x4   
ldr r0, [r5]
add r5, r5, #0x4
ldrb r1, [r5]
ldr r5, =OAMNUM    
add r5, r5, #0x4F
strb r1, [r5]
mov r2, #0x20
mul r1, r2
ldr r3, =BUFFER
add r1, r1, r3
lsr r2, r2, #0x2
swi 0xC

LOADOBJ:
ldr r0, DATA
mov r3, #0xA0
mov r5, #0x30
add r1, r5, r3
mov r2, #0x85
mov r3, #0x0
ldr r4, =CREATEOAM
bl EXECUTE
ldr r1, =OAMNUM
add r1, r1, r7
strb r0, [r1]
ldr r2, =OAMBUFFER
mov r1, #0x44
mul r0, r0, r1
add r0, r0, r2
add r0, r0, #0x5
ldr r3, =OAMNUM
add r3, r3, #0x4F
ldrb r1, [r3]
lsl r1, r1, #0x4
strb r1, [r0]
pop {r0-r7}
pop {pc}

EXECUTE:
bx r4

.align 2
DATA: .word BUFFERDATA + 0x08[offset]
BUFFERDATA:
.hword 0x2
.hword 0x1
.word OAMDATA + 0x08[offset]
.word ANIMATION + 0x08[offset]
.word 0x0
.word 0x08231CFC
.word 0x080EE4DD
.byte 0xFF

.align 2
ANIMATION: .word OAMANIM + 0x08[offset]
OAMANIM:
.hword 0x201
.hword 0xf
.hword 0x211
.hword 0xf
.hword 0xFFFE
.hword 0x0

.align 2
OAMDATA:
.byte 0x0
.byte 0x0
.byte 0x0
.byte 0xB0
.hword 0x1
.hword 0x0

Terza_Routine: (sempre le stessa per cancellare gli sprite, potete anche non reinserirla se lo avete già fatto in precedenza)

Código:
.text
.align 2
.thumb
.thumb_func

push {r0-r3, lr}
ldr r0, =0x06014000
mov r1, #0x80
mov r2, #0

loop:
str r2, [r0]
add r0, #4
sub r1, r1, #1
bpl loop
pop {r0-r3, pc}
Adesso gli script:

VAR 8004:
Código:
#dynamic 0x800000
#org @inizio
callasm 0x8[Prima Routine+1]
pause 0x1
callasm 0x8[Seconda Routine+1]
preparemsg 0x0
waitmsg
waitkeypress
release
callasm 0x8[Terza Routine+1]
return
VARIANTE PER LA COMPATIBILITÀ CON LA ROM:
Código:
#dynamic 0x800000
#org @inizio
compare 0x4002 0x0
if 0x0 call @copia
compare 0x4003 0x0
if 0x0 call @2copia
pause 0x1
copyvar 0x8004 0x4001
callasm 0x8[Prima Routine+1]
pause 0x1
callasm 0x8[Seconda Routine+1]
preparemsg 0x0
waitmsg
waitkeypress
release
callasm 0x8[Terza Routine+1]
return

#org @copia
copyvar 0x4001 0x4002
return

#org @2copia
copyvar 0x4001 0x4003
return
Rechiamoci adesso all'offset 0x08160450 dove è presente la table con i pointer dei vari callstd. Andiamo al decimo pointer (sarebbe lo 0x9) e cambiamolo con il pointer di dove abbiamo inserito lo script che richiama le altre due, ma stavolta NON aggiungete il +1! Infatti, grazie alla ricerca di Andrea, questa table rimanda a semplici script e non routine!

Lo script sarà molto semplice, basterà utilizzare la var 8004 nel primo caso e la var 4001 nel secondo, per scegliere quale pokémon visualizzare nella textbox.
 
Hola
Intenté el tutorial queriendo solo la parte "MSG_MINIBOX" que no obtengo, soy de Brasil, tengo un poco de dificultad y el traductor de Google no ayuda mucho.
Me pregunto si FORO tiene algún canal en YOUTUBE con estos videos tutoriales?
 

Sparky

¿Decomper?
Hmmm, el parche está muy bueno. Aunque lo que más me sorprende es que no sabía que se podían crear nuevos comandos para scripts mediante ASM :)
 
Arriba