Registrarse

[ASM] Nivel dinámico de los pokemon rivales

Samu

Miembro insignia
Miembro insignia
Bueno, pues por fin os traigo está rutina. Resumiendo un poco lo que hace es cambiar los niveles de los pokemon enemigos, tanto los salvajes como de los entrenadores, en función del nivel máximo de los pokemon de tu equipo. Adicionalmente, si hacéis algún givepokemon, su nivel también se verá afectado por la rutina.

Decir que @eing ya hizo algo parecido hace tiempo (Me lo comentó @Mr. Nanren cuando ya tenía la rutina prácticamente acabada).
No obstante al probar su rutina, no me funcionaba (probablemente porque sea parte de un sistema de rutinas) y en vez de dedicarme a ver que fallaba simplemente terminé la mía.

Por lo que he podido ver ahora mismo, la rutina de Eing solo estaba pensada para pokemon salvajes. De hecho, estoy casi seguro, que de utilizarla para un pokemon con movimientos custom (los de casitodos los trainer) iba a crashear el juego. Su función pisa el registro 7 antes de pushearlo (que si bien no se usa para los pokemon salvajes, si se usa para los pokes con custom moves).

El que quiera ver su rutina: [PD: es para ruby]:
Código:
.align 2
.thumb

main:
	push {r4-r7,lr}
	mov r7,r8
	push {r7}
	add sp,#0x1c @-#0x1c
	push {r0-r5}
	ldr r0,.var_lvl
	ldrh r0,[r0,#0x0]
	cmp r0,#0x0
	beq fin2
	cmp r0,#0x1
	beq avg
	sub r0,#0x1
	mov r7,r0
	b fin
	
	
avg: @Mismo nivel +fuerte equipo
	mov r10,lr
	ldr r0,.pkamount @Cargamos pointer pokemon encima
	ldrb r0,[r0,#0x0] @Cantidad pk
	cmp r0,#0x0 @Comparamos si son 0
	beq nopoke @Si son 0;Nivel 5
	mov r1, #0x0 @posicion en el equipo
	mov r2, #0x0 @nivel máximo
	ldr r3, .lvl @Pointer nivel equipo
	mov r4,#0x0 @Contador
	bl bucle @BL a bucle
	mov r0,r2 @Movemos nivel a r0
	b fin @Vamos a fin
	
addlevel:
	mov r2,r5 @Añadimos nivel
	add r1,#0x1 @Añadimos 1 a posicion
	mov r4,#0x64 @Añadimos 64 al contador
	cmp r1, r0 @Comparamos si no es pkamount
	bne bucle @Si no bucle
	bx lr

bucle: @Bucle para determinar cual nivel es el mas alto
	add r3,r4 @Sumamos Pointer+posicion
	ldrb r5,[r3,#0x0] @Cargamos lvl
	cmp r5,r2 @Comparamos nivel poke con nivel actual máximo
	bgt addlevel @Si es mayor; ponemos el nuevo nivel
	add r1,#0x1 @Añadimos 1 a posicion
	mov r4,#0x64 @Añadimos 64 al contador
	cmp r1, r0 @Comparamos si no es pkamount
	bne bucle @Si no bucle
	bx lr @Volvemos al BL
	
nopoke:         [MENTION=25868]sin[/MENTION] pokemon; Nivel 5
	mov r0,#0x5
	b fin
	
fin: @Fin rutina
	mov r7,r0 @Movemos nivel a r7
	pop {r0-r5} @Popeamos registros
	mov r2,r7 @Movemos nivel a r2
	ldr r4, .fin @Vamos al punto donde estaba la rutina
	bx r4
	
fin2:
	pop {r0-r5}
	ldr r4, .fin @Vamos al punto donde estaba la rutina
	bx r4
	
.align 2
.pkamount: .word 0x03004350 @Pointer pk_amount
.segundos: .word 0x02024EB5 @Segundos
.lvl: .word 0x030043B4 @Pointer nivel
.fin: .word 0x0803a7a1  @Rutina de retorno
.var_lvl: .word 0x02026c52 @Var decide lvl
El registro r7 lo pisa en el hook (ldr r7, bx r7).


SetEnemyPokeLevel??
La rutina que os traigo es una "plantilla" que tiene lo básico, para que podáis personalizarla según vuestras necesidades o dejarla tal cual está (de no hacerlo así tendría que subir 200 versiones distintas de la rutina. Yo creo que es mejor subir una "base" con lo "difícil", y ya cada uno que cambie 4 números distintos para hacer lo que quiera).

Aquí la rutina para cada uno de los rom.

Código:
.thumb
.align 2

/********** setEnemyLevel = maxPartyLevel |@RUBY|********
Establece el nivel de los pokemon enemigos (salvajes y entrenadores) de forma
dinámica, igualándolo al nivel máximo existente entre los pokemon de tu equipo
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Instrucciones de uso:
-Ir a la dirección 0x0803A798 (función CreateMon) 
-Cambiar "F0 B5 47 46 80 B4 87 B0" por "80 B4 01 4F 38 47 C0 46 XX+1 XX XX 08" 
siendo "XX+1 XX XX 08" el pointer permutado a esta rutina. y el resto las instrucciones:
********************
	push {r7}
	ldr r7, =08XXXXXX+1
	bx r7
	nop
********************
-Elige un flag para controlar la rutina.
-Resta (o suma) la cantidad de niveles de diferencia deseado
-Compilar esta rutina e insertarla en "08 XX XX XX+1".
*/
/**********************
El juego crea todos los pokemon con la función "CreateMon" (@pokegba) en 08067B4C,
uno de los argumentos pasados a esta función es el nivel del pokemon, que es pasado
por el registro r2. Esta rutina modifica según nuestra conveniencia el valor de r2,
dejando el resto intacto y modificando así el nivel de los pokemon generados por el
juego.
***********************/
no_crash:				
	pop {r7}
	@Instrucciones de la rutina original
	push {r4-r7, r14}
	mov r7, r8
	push {r7}
	add sp, #-0x1C
	mov r8, r0
	mov r6, r1
	
flag_check:				@Se encarga de comprobar si hemos activado el flag
	push {r0-r2}
	ldr r0, flag_number
	ldr r2, flag_routine
	push {r1-r3}
	bl linker
	pop {r1-r3}
	cmp r0, #0x1
	bne routine_off
	pop {r0-r2}
	
main:				
	push {r3-r5}		
	ldr r3, party_lvl	@carga el puntero al nivel de los pokemon en r3
	ldrb r2, [r3]		@Carga el nivel del pokemon en r2
	mov r5, #0x5		@Establece el contador a 5 en r5
	
loop:
	add r3, #0x64		@Suma 0x64 al puntero para pasar al siguiente nivel
	ldrb r4, [r3]		@Carga el valor del segundo nivel en r4
	cmp r4, r2			@Compara ambos niveles
	ble continue		@Si el nivel de r4 es menor al de r2 lo deja tal cual está
	mov r2, r4			@Si el nivel de r4 es mayor lo escribe en r2-r5
	
continue:
	sub r5, r5, #0x1	@Resta uno al contador
	cmp r5, #0x0		@compara el contador con 0	
	bne loop			@Si el contador no ha llegado a 0 sigue ejecutando el bucle

ajuste:
	sub r2, r2, #0x0    @ Cambiar #0x0 por la cantidad de niveles a restar (cambiar la instrucción por add si queremos sumar)
	cmp r2, #0x0
	beq fixed_min
	cmp r2, #0x64
	bge fixed_max
	
end:
	pop {r3-r5}			@Popea los registros utilizados	
	
return:
	ldr r4, return_dir	@Vuelve a la rutina original
	bx r4
	
routine_off:
	pop {r0-r2}
	b return

linker:
	bx r2

fixed_max:				@Evita pokemon con nivel superior al 100
	mov r2, #0x64
	b end
	
fixed_min:				@Evita pokemon con niveles inferiores a 1
	mov r2, #0x1
	b end


.align 2
party_lvl:				@Puntero a los niveles del equipo
	.word 0x03004360 + 0x54
return_dir:				@Dirección de retorno de la rutina
	.word 0x0803A7A5
flag_routine:			@Dirección de la rutina que checkea el flag
	.word 0x08069340 +1
flag_number:			@Número del flag utilizado en la rutina
	.word 0x00000[XXX]	@Pon aquí el número de flag que desees, EJ: 406
Código:
.thumb
.align 2

/********** setEnemyLevel = maxPartyLevel |@FRED|********
Establece el nivel de los pokemon enemigos (salvajes y entrenadores) de forma
dinámica, igualándolo al nivel máximo existente entre los pokemon de tu equipo
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Instrucciones de uso:
-Ir a la dirección 0x0803DA54 (función CreateMon) 
-Cambiar "F0 B5 47 46 80 B4 87 B0" por "80 B4 01 4F 38 47 C0 46 XX+1 XX XX 08" 
siendo "XX+1 XX XX 08" el pointer permutado a esta rutina. y el resto las instrucciones:
********************
	push {r7}
	ldr r7, =08XXXXXX+1
	bx r7
	nop
********************
-Compilar esta rutina e insertarla en "08 XX XX XX+1".
*/
/**********************
El juego crea todos los pokemon con la función "CreateMon" (@pokegba) en 0803DA54,
uno de los argumentos pasados a esta función es el nivel del pokemon, que es pasado
por el registro r2. Esta rutina modifica según nuestra conveniencia el valor de r2,
dejando el resto intacto y modificando así el nivel de los pokemon generados por el
juego.
***********************/


no_crash:				
	pop {r7}
	@Instrucciones de la rutina original
	push {r4-r7, r14}
	mov r7, r8
	push {r7}
	add sp, #-0x1C
	mov r8, r0
	mov r6, r1
	
flag_check:				@Se encarga de comprobar si hemos activado el flag
	push {r0-r2}
	ldr r0, flag_number
	ldr r2, flag_routine
	push {r1-r3}
	bl linker
	pop {r1-r3}
	cmp r0, #0x1
	bne routine_off
	pop {r0-r2}
	
main:				
	push {r3-r5}		
	ldr r3, party_lvl	@carga el puntero al nivel de los pokemon en r3
	ldrb r2, [r3]		@Carga el nivel del pokemon en r2
	mov r5, #0x5		@Establece el contador a 5 en r5
	
loop:
	add r3, #0x64		@Suma 0x64 al puntero para pasar al siguiente nivel
	ldrb r4, [r3]		@Carga el valor del segundo nivel en r4
	cmp r4, r2			@Compara ambos niveles
	ble continue		@Si el nivel de r4 es menor al de r2 lo deja tal cual está
	mov r2, r4			@Si el nivel de r4 es mayor lo escribe en r2-r5
	
continue:
	sub r5, r5, #0x1	@Resta uno al contador
	cmp r5, #0x0		@compara el contador con 0	
	bne loop			@Si el contador no ha llegado a 0 sigue ejecutando el bucle

ajuste:
	sub r2, r2, #0x0        @ Cambiar #0x0 por la cantidad de niveles a restar (cambiar la instrucción por add si queremos sumar)
	cmp r2, #0x0
	beq fixed_min
	cmp r2, #0x64
	bge fixed_max
	
end:
	pop {r3-r5}			@Popea los registros utilizados	
	
return:
	ldr r4, return_dir	@Vuelve a la rutina original
	bx r4
	
routine_off:
	pop {r0-r2}
	b return

linker:
	bx r2

fixed_max:				@Evita pokemon con nivel superior al 100
	mov r2, #0x64
	b end
	
fixed_min:				@Evita pokemon con niveles inferiores a 1
	mov r2, #0x1
	b end

	
.align 2
party_lvl:				@Puntero a los niveles del equipo
	.word 0x02024284 + 0x54
return_dir:				@Dirección de retorno de la rutina
	.word 0x0803DA60 + 1
flag_routine:			@Dirección de la rutina que checkea el flag
	.word 0x0806E6D0 + 1
flag_number:			@Número del flag utilizado en la rutina
	.word 0x00000[XXX]	@Pon aquí el número de flag que desees, EJ: 406
Código:
.thumb
.align 2

/********** setEnemyLevel = maxPartyLevel |@EMERALD|********
Establece el nivel de los pokemon enemigos (salvajes y entrenadores) de forma
dinámica, igualándolo al nivel máximo existente entre los pokemon de tu equipo
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Instrucciones de uso:
-Ir a la dirección 0x08067B4C (función CreateMon) 
-Cambiar "F0 B5 47 46 80 B4 87 B0" por "80 B4 01 4F 38 47 C0 46 XX+1 XX XX 08" 
siendo "XX+1 XX XX 08" el pointer permutado a esta rutina. y el resto las instrucciones:
********************
	push {r7}
	ldr r7, =08XXXXXX+1
	bx r7
	nop
********************
-Elige un flag para controlar la rutina.
-Resta (o suma) la cantidad de niveles de diferencia deseado
-Compilar esta rutina e insertarla en "08 XX XX XX+1".
*/
/**********************
El juego crea todos los pokemon con la función "CreateMon" (@pokegba) en 08067B4C,
uno de los argumentos pasados a esta función es el nivel del pokemon, que es pasado
por el registro r2. Esta rutina modifica según nuestra conveniencia el valor de r2,
dejando el resto intacto y modificando así el nivel de los pokemon generados por el
juego.
***********************/
no_crash:				
	pop {r7}
	@Instrucciones de la rutina original
	push {r4-r7, r14}
	mov r7, r8
	push {r7}
	add sp, #-0x1C
	mov r8, r0
	mov r6, r1
	
flag_check:				@Se encarga de comprobar si hemos activado el flag
	push {r0-r2}
	ldr r0, flag_number
	ldr r2, flag_routine
	push {r1-r3}
	bl linker
	pop {r1-r3}
	cmp r0, #0x1
	bne routine_off
	pop {r0-r2}
	
main:				
	push {r3-r5}		
	ldr r3, party_lvl	@carga el puntero al nivel de los pokemon en r3
	ldrb r2, [r3]		@Carga el nivel del pokemon en r2
	mov r5, #0x5		@Establece el contador a 5 en r5
	
loop:
	add r3, #0x64		@Suma 0x64 al puntero para pasar al siguiente nivel
	ldrb r4, [r3]		@Carga el valor del segundo nivel en r4
	cmp r4, r2			@Compara ambos niveles
	ble continue		@Si el nivel de r4 es menor al de r2 lo deja tal cual está
	mov r2, r4			@Si el nivel de r4 es mayor lo escribe en r2-r5
	
continue:
	sub r5, r5, #0x1	@Resta uno al contador
	cmp r5, #0x0		@compara el contador con 0	
	bne loop			@Si el contador no ha llegado a 0 sigue ejecutando el bucle

ajuste:
	sub r2, r2, #0x0                @ Cambiar #0x0 por la cantidad de niveles a restar (cambiar la instrucción por add si queremos sumar)
	cmp r2, #0x0
	beq fixed_min
	cmp r2, #0x64
	bge fixed_max
	
end:
	pop {r3-r5}			@Popea los registros utilizados	
	
return:
	ldr r4, return_dir	@Vuelve a la rutina original
	bx r4
	
routine_off:
	pop {r0-r2}
	b return

linker:
	bx r2

fixed_max:				@Evita pokemon con nivel superior al 100
	mov r2, #0x64
	b end
	
fixed_min:				@Evita pokemon con niveles inferiores a 1
	mov r2, #0x1
	b end

	
.align 2
party_lvl:				@Puntero a los niveles del equipo
	.word 0x020244EC + 0x54
return_dir:				@Dirección de retorno de la rutina
	.word 0x08067B59
flag_routine:			@Dirección de la rutina que checkea el flag
	.word 0x0809D790 +1
flag_number:			@Número del flag utilizado en la rutina
	.word 0x00000[XXX]	@Pon aquí el número de flag que desees, EJ: 406

Funcionamiento de la rutina:
La rutina irá comparando el nivel de cada uno de los pokemon de vuestro equipo para quedarse con el nivel máximo del mismo. Una vez tenga este dato, lo utilizará para alterar el nivel del pokemon enemigo. La rutina puede activarse o desactivarse utilizando un flag.

En primer abrimos el rom con HxD y vamos a "0803DA54" (FRED) o "08067B4C" (EM) y escribimos los siguientes bytes:
Código:
80 B4 01 4F 38 47 C0 46 XX+1 XX XX 08
@XX+1 XX XX 08 es el offset permutado +1 donde vayáis a insertar la rutina

Una vez realizados estos cambios dentro del rom, vamos a modificar la rutina ASM según nuestras necesidades:
-Colocar el Flag que deseamos utilizar para activar/desactivar la rutina
Código:
flag_number:			
	.word 0x00000[XXX]	@En XXX escribir el número del flag EJ: 406

-Elegir la cantidad de niveles por debajo (o por encima) a los que debe encontrarse el pokemon rival.
Código:
sub r2, r2, #0x0         [MENTION=26827]Camb[/MENTION]iar #0x0 por la cantidad de niveles a restar (cambiar la instrucción por add si queremos sumar)

-Compilamos la rutina y la insertamos en "08XXXXXX". Cuando el flag seleccionado este activado (setflag 0x???) la rutina modificará el nivel de los pokemon generados por el juego.
Como ya os he dicho, esta rutina es una base que podéis hacer crecer para cumplir vuestras necesidades, sin tener que saber prácticamente nada de ASM (solo lo más básico). Algunas de las posibles modificaciones que se me ocurren (algunas las he llevado a cabo yo en mi propia rutina) son las siguientes:
  • -Utilizar el nivel medio de tu equipo para calcular el nivel de los pokemon salvajes en lugar del nivel máximo del equipo. (Tan fácil como sumar los niveles de todos los pokemon del equipo, dividirlo entre el número de pokemon y pasar el resultado a r2). Para dividir utilizar la instrucción "SWI 0xC" que realizará la operación r0/r1 dando el resultado en r0.
  • -Introducir un factor aleatorio que le sume o le reste algo a los niveles.(como generador de números aleatorios podéis utilizar los milisegundos del reloj del juego).
  • Hacer distintas cosas en función del tipo de pokemon que se va a generar (el número del pokemon en HEX está en el r1)

Si alguien tiene algún problema modificando la rutina tiene alguna duda que lo ponga por aquí e intentaré ayudarle.
Al final se me ha hecho muy tarde, pero dije que lo subía y lo subo. Aunque solo sea por lo poco que queda de mi orgullo. Y puede que también porque llevo un mes sin postear¿?¿?¿?.

Decir que he puesto el flag a petición de @kakarotto y creo que nada más. Mañana subo el otro tutorial que dije que iba a subir este fin de semana (xD). Ah si, también summonear a @Ωmega que dijo que quería verlo.

Edit: Me gustaría saber porque el foro se empeña en dar por culo y joderme las tabulaciones del notepad++.
Edit2: De verdad tenía que haber un usuario llamado @Camb que me joda los comentarios del ASM por que pilla @ cambiar como una mención? Mi bida es miserable. Cuando sea anciano crearé a dark Miutu y dejaré huérfano a alguien.


EDIT: Añadida versión para ruby.
 
Última edición:

KevinXDE

Usuario mítico
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Uff, que aportazo! Para Fire Red y Emerald >.<, asi nadie se puede quejar x'D

Últimamente me ha dado el gusanillo de ROM Hackear y me preguntaba sobre aquella rutina que yo usaba para subir el nivel de los Pokémon salvajes, y no me acababa de convencer... Viendo esto, y suponiendo que no es solo para Pokémon salvajes, pues facilita mucho las cosas! Cambiando la parte de 'ajuste' se puede adaptar la rutina facilmente.

Bravo, muy buen trabajo ^^. La probaré en unos días cuando me decida a retomar mi trabajo xD
 

MichaKing

Grafista avanzado
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

¡Esto es INCREÍBLE!

Un aportazo sin duda alguna, no había visto a profundidad la rutina de eing por lo que desconocía si tenía errores, además en un alivio saberlo, ya que usaré la tuya 100% seguro. Me parece algo realmente muy útil, puesto que le da más equilibrio, dificultad y competitividad al juego, ya que muchos al no saber esto, y optan por poner muchos niveles de más, cosa que lo hace muy aburrido por tener que levelear y demás. Poco más puedo decir, ya la probaré cuando sea el momento :heart:

Se despide, MichaKing~
 

kakarotto

Leyenda de WaH
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Nada que objetar @Samu ... tus aportes siempre tienen una calidad exquisita y me hiciste caso lo cual se agradece. Espero darle un gran uso a tu mecánica.
 

Samu

Miembro insignia
Miembro insignia
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Lo siento por preguntarlo, pero, ¿podría usted pasarme esa rutina( Pokémon Emerald) sin los comentarios que tiene en ella?
Sí claro... por poder sin problema..

Código:
.thumb
.align 2

no_crash:				
	pop {r7}
	push {r4-r7, r14}
	mov r7, r8
	push {r7}
	add sp, #-0x1C
	mov r8, r0
	mov r6, r1
	
flag_check:				
	push {r0-r2}
	ldr r0, flag_number
	ldr r2, flag_routine
	push {r1-r3}
	bl linker
	pop {r1-r3}
	cmp r0, #0x1
	bne routine_off
	pop {r0-r2}
	
main:				
	push {r3-r5}		
	ldr r3, party_lvl	
	ldrb r2, [r3]		
	mov r5, #0x5		
	
loop:
	add r3, #0x64		 
	ldrb r4, [r3]		
	cmp r4, r2			
	ble continue		
	mov r2, r4			
	
continue:
	sub r5, r5, #0x1	
	cmp r5, #0x0			
	bne loop			

ajuste:
	sub r2, r2, #0x0                
	cmp r2, #0x0
	beq fixed_min
	cmp r2, #0x64
	bge fixed_max
	
end:
	pop {r3-r5}				
	
return:
	ldr r4, return_dir	
	bx r4
	
routine_off:
	pop {r0-r2}
	b return

linker:
	bx r2

fixed_max:				
	mov r2, #0x64
	b end
	
fixed_min:				
	mov r2, #0x1
	b end

	
.align 2
party_lvl:				
	.word 0x020244EC + 0x54
return_dir:				
	.word 0x08067B59
flag_routine:			
	.word 0x0809D790 +1
flag_number:			
	.word 0x00000[XXX]

Por curiosidad, ¿Cuál es el problema con los comentarios? xD. Y una última cosa y sin intención de ser demasiado borde, ¿Tan difícil era quitarlos? xDDDDD.
 

Benny el gato pokemon

En camino a ser el Amo :v?
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Esto es un excelente aporte a la comunidad, de seguro me servir para hacer mi hack rom mas difícil, aunque si voy a la liga con Pokemon nivel 6 el campeón tendrá Pokemons nivel 6 xD, de seguro lo usare

Salu2
 

Acosta

The Wolf~
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Sin duda esto es un excelente tutorial, bastante bueno y muy completo para estas 2 Roms, que le puede servir a muchos de aquí. Hiciste un gran esfuerzo de tú parte, sigue así! ;)

-Acosta
 

Samu

Miembro insignia
Miembro insignia
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Debido a que me lo han pedido un par de personas, he añadido la versión para ruby de la rutina. Todo lo dicho y explicado para las rutinas de emerald/fred se aplica también para la rutina de ruby.

Código:
.thumb
.align 2

/********** setEnemyLevel = maxPartyLevel |@RUBY|********
Establece el nivel de los pokemon enemigos (salvajes y entrenadores) de forma
dinámica, igualándolo al nivel máximo existente entre los pokemon de tu equipo
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Instrucciones de uso:
-Ir a la dirección 0x0803A798 (función CreateMon) 
-Cambiar "F0 B5 47 46 80 B4 87 B0" por "80 B4 01 4F 38 47 C0 46 XX+1 XX XX 08" 
siendo "XX+1 XX XX 08" el pointer permutado a esta rutina. y el resto las instrucciones:
********************
	push {r7}
	ldr r7, =08XXXXXX+1
	bx r7
	nop
********************
-Elige un flag para controlar la rutina.
-Resta (o suma) la cantidad de niveles de diferencia deseado
-Compilar esta rutina e insertarla en "08 XX XX XX+1".
*/
/**********************
El juego crea todos los pokemon con la función "CreateMon" (@pokegba) en 08067B4C,
uno de los argumentos pasados a esta función es el nivel del pokemon, que es pasado
por el registro r2. Esta rutina modifica según nuestra conveniencia el valor de r2,
dejando el resto intacto y modificando así el nivel de los pokemon generados por el
juego.
***********************/
no_crash:				
	pop {r7}
	@Instrucciones de la rutina original
	push {r4-r7, r14}
	mov r7, r8
	push {r7}
	add sp, #-0x1C
	mov r8, r0
	mov r6, r1
	
flag_check:				@Se encarga de comprobar si hemos activado el flag
	push {r0-r2}
	ldr r0, flag_number
	ldr r2, flag_routine
	push {r1-r3}
	bl linker
	pop {r1-r3}
	cmp r0, #0x1
	bne routine_off
	pop {r0-r2}
	
main:				
	push {r3-r5}		
	ldr r3, party_lvl	@carga el puntero al nivel de los pokemon en r3
	ldrb r2, [r3]		@Carga el nivel del pokemon en r2
	mov r5, #0x5		@Establece el contador a 5 en r5
	
loop:
	add r3, #0x64		@Suma 0x64 al puntero para pasar al siguiente nivel
	ldrb r4, [r3]		@Carga el valor del segundo nivel en r4
	cmp r4, r2			@Compara ambos niveles
	ble continue		@Si el nivel de r4 es menor al de r2 lo deja tal cual está
	mov r2, r4			@Si el nivel de r4 es mayor lo escribe en r2-r5
	
continue:
	sub r5, r5, #0x1	@Resta uno al contador
	cmp r5, #0x0		@compara el contador con 0	
	bne loop			@Si el contador no ha llegado a 0 sigue ejecutando el bucle

ajuste:
	sub r2, r2, #0x0    @ Cambiar #0x0 por la cantidad de niveles a restar (cambiar la instrucción por add si queremos sumar)
	cmp r2, #0x0
	beq fixed_min
	cmp r2, #0x64
	bge fixed_max
	
end:
	pop {r3-r5}			@Popea los registros utilizados	
	
return:
	ldr r4, return_dir	@Vuelve a la rutina original
	bx r4
	
routine_off:
	pop {r0-r2}
	b return

linker:
	bx r2

fixed_max:				@Evita pokemon con nivel superior al 100
	mov r2, #0x64
	b end
	
fixed_min:				@Evita pokemon con niveles inferiores a 1
	mov r2, #0x1
	b end


.align 2
party_lvl:				@Puntero a los niveles del equipo
	.word 0x03004360 + 0x54
return_dir:				@Dirección de retorno de la rutina
	.word 0x0803A7A5
flag_routine:			@Dirección de la rutina que checkea el flag
	.word 0x08069340 +1
flag_number:			@Número del flag utilizado en la rutina
	.word 0x00000[XXX]	@Pon aquí el número de flag que desees, EJ: 406
 
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Sin duda un muy buen tutorial, y bastante completo en verdad, seguro les sirve a muchos, y lo traes para las 3 roms asi nadie se puede quejar xD, muy buen trabajo de tu parte.

Un saludo!!
 

Dani_SR_17

¡Pokémon LionHeart!
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

Me hacía falta que el nivel del Pokémon pudiera variar, me explico, que no fuera siempre el mismo que el de tu Pokémon más fuerte, o siempre tres niveles por encima, sino que según la situación fuera más o menos niveles por encima.
Así que he modificado un poco la rutina para que haga lo que yo quería.

Como bien sabréis, controlo de scripting, no de ASM, así que no descarto que sea optimizable o tenga algo mal.
La he probado y ha funcionado de lujo, el funcionamiento es sencillo, antes del combate hacer un setvar 0x8000 0xPlus, donde Plus es el número de niveles extra que queráis sumarle.

Código:
.thumb
.align 2

/********** setEnemyLevel = maxPartyLevel |@FRED|********
Establece el nivel de los pokemon enemigos (salvajes y entrenadores) de forma
dinámica, igualándolo al nivel máximo existente entre los pokemon de tu equipo
------------------------------------------------------------------------------
------------------------------------------------------------------------------
Instrucciones de uso:
-Ir a la dirección 0x0803DA54 (función CreateMon) 
-Cambiar "F0 B5 47 46 80 B4 87 B0" por "80 B4 01 4F 38 47 C0 46 XX+1 XX XX 08" 
siendo "XX+1 XX XX 08" el pointer permutado a esta rutina. y el resto las instrucciones:
********************
	push {r7}
	ldr r7, =08XXXXXX+1
	bx r7
	nop
********************
-Compilar esta rutina e insertarla en "08 XX XX XX+1".
*/
/**********************
El juego crea todos los pokemon con la función "CreateMon" (@pokegba) en 0803DA54,
uno de los argumentos pasados a esta función es el nivel del pokemon, que es pasado
por el registro r2. Esta rutina modifica según nuestra conveniencia el valor de r2,
dejando el resto intacto y modificando así el nivel de los pokemon generados por el
juego.
***********************/


no_crash:				
	pop {r7}
	@Instrucciones de la rutina original
	push {r4-r7, r14}
	mov r7, r8
	push {r7}
	add sp, #-0x1C
	mov r8, r0
	mov r6, r1
	
flag_check:				@Se encarga de comprobar si hemos activado el flag
	push {r0-r2}
	ldr r0, flag_number
	ldr r2, flag_routine
	push {r1-r3}
	bl linker
	pop {r1-r3}
	cmp r0, #0x1
	bne routine_off
	pop {r0-r2}
	
main:				
	push {r3-r5}		
	ldr r3, party_lvl	@carga el puntero al nivel de los pokemon en r3
	ldrb r2, [r3]		@Carga el nivel del pokemon en r2
	mov r5, #0x5		@Establece el contador a 5 en r5
	
loop:
	add r3, #0x64		@Suma 0x64 al puntero para pasar al siguiente nivel
	ldrb r4, [r3]		@Carga el valor del segundo nivel en r4
	cmp r4, r2			@Compara ambos niveles
	ble continue		@Si el nivel de r4 es menor al de r2 lo deja tal cual está
	mov r2, r4			@Si el nivel de r4 es mayor lo escribe en r2-r5
	
continue:
	sub r5, r5, #0x1	@Resta uno al contador
	cmp r5, #0x0		@compara el contador con 0	
	bne loop			@Si el contador no ha llegado a 0 sigue ejecutando el bucle

ajuste:
	ldr r3, .Variable @Esta es la parte que he añadido, junto a las dos siguientes líneas
	ldrh r3, [r3]
	add r2, r2, r3
	cmp r2, #0x0
	beq fixed_min
	cmp r2, #0x64
	bge fixed_max
	
end:
	pop {r3-r5}			@Popea los registros utilizados	
	
return:
	ldr r4, return_dir	@Vuelve a la rutina original
	bx r4
	
routine_off:
	pop {r0-r2}
	b return

linker:
	bx r2

fixed_max:				@Evita pokemon con nivel superior al 100
	mov r2, #0x64
	b end
	
fixed_min:				@Evita pokemon con niveles inferiores a 1
	mov r2, #0x1
	b end

	
.align 2
party_lvl:				@Puntero a los niveles del equipo
	.word 0x02024284 + 0x54
return_dir:				@Dirección de retorno de la rutina
	.word 0x0803DA60 + 1
flag_routine:			@Dirección de la rutina que checkea el flag
	.word 0x0806E6D0 + 1
flag_number:			@Número del flag utilizado en la rutina
	.word 0x00000[XXX]	@Pon aquí el número de flag que desees, EJ: 406
.Variable:
	.word 0x020270B8 + (0x8000 * 2) @Podéis cambiar esta variable por otra de las variables dinámicas
 

RCgrandmasters

Usuario de platino
Respuesta: [ASM] Nivel dinámico de los pokemon rivales

se prodria tener la rutina sin tener que activarlo, que este siempre activa, igual muy buen aporte.
 

MetalKaktus

A la luz del quinto día, mira al este
Miembro insignia
Re: Respuesta: [ASM] Nivel dinámico de los pokemon rivales

se prodria tener la rutina sin tener que activarlo, que este siempre activa, igual muy buen aporte.
Simplemente escoge una flag y mantenla siempre activada. De esta forma todos los rivales te saldrán con el mismo nivel que el de los pokes de tu equipo.

Imagina que en la rutina has cambiado ese XXX donde pone flag number por 200. Pues si desde el principio haces un script donde actives esa flag, y no la vuelves a tocar, la rutina estará siempre activada.
 

RCgrandmasters

Usuario de platino
Respuesta: Re: Respuesta: [ASM] Nivel dinámico de los pokemon rivales

xd ahhh ya veo, buena idea gracias por responder tan rapido
 

2107Y

El Yagami
Re: GBA | ASM | Nivel dinámico de los pokemon rivales

No conozco mucho acerca de ASM, manejo mejor el Scripting, se como se ve una rutina normal, pero asi como la escribes para Fire Red, me confunden los textos

Asi es como debe quedar para compilar?

.thumb
.align 2

no_crash:
pop {r7}
@Instrucciones de la rutina original
push {r4-r7, r14}
mov r7, r8
push {r7}
add sp, #-0x1C
mov r8, r0
mov r6, r1

flag_check:
push {r0-r2}
ldr r0, flag_number
ldr r2, flag_routine
push {r1-r3}
bl linker
pop {r1-r3}
cmp r0, #0x1
bne routine_off
pop {r0-r2}

main:
push {r3-r5}
ldr r3, party_lvl
ldrb r2, [r3]
mov r5, #0x5

loop:
add r3, #0x64
ldrb r4, [r3]
cmp r4, r2
ble continue
mov r2, r4

continue:
sub r5, r5, #0x1
cmp r5, #0x0
bne loop

ajuste:
sub r2, r2, #0x0
cmp r2, #0x0
beq fixed_min
cmp r2, #0x64
bge fixed_max

end:
pop {r3-r5}

return:
ldr r4, return_dir
bx r4

routine_off:
pop {r0-r2}
b return

linker:
bx r2

fixed_max:
mov r2, #0x64
b end

fixed_min:
mov r2, #0x1
b end


.align 2
party_lvl:
.word 0x02024284 + 0x54
return_dir:
.word 0x0803DA60 + 1
flag_routine:
.word 0x0806E6D0 + 1
flag_number:
.word 0x00000[406]
 

MetalKaktus

A la luz del quinto día, mira al este
Miembro insignia
Re: GBA | ASM | Nivel dinámico de los pokemon rivales

No conozco mucho acerca de ASM, manejo mejor el Scripting, se como se ve una rutina normal, pero asi como la escribes para Fire Red, me confunden los textos

Asi es como debe quedar para compilar?

.thumb
.align 2

no_crash:
pop {r7}
@Instrucciones de la rutina original
push {r4-r7, r14}
mov r7, r8
push {r7}
add sp, #-0x1C
mov r8, r0
mov r6, r1

flag_check:
push {r0-r2}
ldr r0, flag_number
ldr r2, flag_routine
push {r1-r3}
bl linker
pop {r1-r3}
cmp r0, #0x1
bne routine_off
pop {r0-r2}

main:
push {r3-r5}
ldr r3, party_lvl
ldrb r2, [r3]
mov r5, #0x5

loop:
add r3, #0x64
ldrb r4, [r3]
cmp r4, r2
ble continue
mov r2, r4

continue:
sub r5, r5, #0x1
cmp r5, #0x0
bne loop

ajuste:
sub r2, r2, #0x0
cmp r2, #0x0
beq fixed_min
cmp r2, #0x64
bge fixed_max

end:
pop {r3-r5}

return:
ldr r4, return_dir
bx r4

routine_off:
pop {r0-r2}
b return

linker:
bx r2

fixed_max:
mov r2, #0x64
b end

fixed_min:
mov r2, #0x1
b end


.align 2
party_lvl:
.word 0x02024284 + 0x54
return_dir:
.word 0x0803DA60 + 1
flag_routine:
.word 0x0806E6D0 + 1
flag_number:
.word 0x00000[406]
Así:

Código:
.thumb
.align 2

no_crash:
pop {r7}
push {r4-r7, r14}
mov r7, r8
push {r7}
add sp, #-0x1C
mov r8, r0
mov r6, r1

flag_check:
push {r0-r2}
ldr r0, flag_number
ldr r2, flag_routine
push {r1-r3}
bl linker
pop {r1-r3}
cmp r0, #0x1
bne routine_off
pop {r0-r2}

main:
push {r3-r5}
ldr r3, party_lvl
ldrb r2, [r3]
mov r5, #0x5

loop:
add r3, #0x64
ldrb r4, [r3]
cmp r4, r2
ble continue
mov r2, r4

continue:
sub r5, r5, #0x1
cmp r5, #0x0
bne loop

ajuste:
sub r2, r2, #0x0
cmp r2, #0x0
beq fixed_min
cmp r2, #0x64
bge fixed_max

end:
pop {r3-r5}

return:
ldr r4, return_dir
bx r4

routine_off:
pop {r0-r2}
b return

linker:
bx r2

fixed_max:
mov r2, #0x64
b end

fixed_min:
mov r2, #0x1
b end


.align 2
party_lvl:
.word 0x02024284 + 0x54
return_dir:
.word 0x0803DA60 + 1
flag_routine:
.word 0x0806E6D0 + 1
flag_number:
.word 0x00000200
Te he cambiado la flag porque la que has puesto no es valida.
 

Rubire4

Usuario mítico
esto es valido para Pokemon RUby version española?
Dudo mucho que los offsets tanto de las referencias de la rutina como de la inserción de esta sirvan para Rubí, porque estos están hechos para la versión inglesa. Si quieres usarla deberías empezar una investigación sobre dónde se encuentran dichos offsets en la ROM española.
 

PyerreIA12

Usuario de oro
hola ¿alguien sabe si hay una manera de aplicar el nivel dinámico solo a los entrenadores y dejar los salvajes como de costumbre?
 

Samu

Miembro insignia
Miembro insignia
Solo prendelo en combates y apágalo después de ganar
La única pega que le veo a esto, es que si pierdes un combate contra un entrenador no estarías apagando el sistema, quedándose encendido hasta que ganes un combate.

La rutina ASM que hice está inyectada al comienzo de la función CreateMon y lo que hace es modificar el valor de r2, parámetro que se pasa a la función como nivel.
Código:
void CreateMon(struct Pokemon *mon, u16 species, u8 level, u8 fixedIV, u8 hasFixedPersonality, u32 fixedPersonality, u8 otIdType, u32 fixedOtId)
{
    u32 arg;
    ZeroMonData(mon);
    CreateBoxMon(&mon->box, species, level, fixedIV, hasFixedPersonality, fixedPersonality, otIdType, fixedOtId);
    SetMonData(mon, MON_DATA_LEVEL, &level);
    arg = 255;
    SetMonData(mon, MON_DATA_MAIL, &arg);
    CalculateMonStats(mon);
}
Como se puede ver ahí, otro de los parámetros es OtIdType, que contiene el ID del entrenador. En el caso de los pokémon salvajes este parámetro es 0, por lo que comprobar el valor de dicho parámetro parece la mejor forma de saber si es salvaje o un combate.

Es difícil saber en que registro está otIdType sin ver el ASM desde el depurador (no lo tengo instalado ahora mismo), pero sabiendo el registro en el que está solo hay que añadir este código ASM antes de la etiqueta "main":

Código:
check_wild:
    cmp rX, #0x0
    beq routine_off

main:
.
.
.
 
Arriba