Registrarse

FR | [En proceso] [ASM] Cronometro.

Invert

why so serious?


Cronometro


Explicación

El cronometro es una rutina hecha para medir el valor del tiempo real y almacenarla en variables.

¿Recibe Parámetros?: Sí.
  • var 8001: Resetea los segundos.
  • var 8002: Resetea los minutos.

¿Devuelve Parámetros?: Sí.
  • var 8001: Guarda los segundos.
  • var 8002: Guarda los minutos.

Instalación

Instalar los 3 siguientes codigos en distintos offsets:

CRONOMETRO
Código:
.thumb
.global stop_watch
.thumb_func 

PUSH    {R4-R6,LR}
add1:
lsl r0, #0x18
lsr r0, #0x18
ldr r2, =0x03005090 @task
lsl r1, r0, #2
add r1, r0
lsl r1, #3
add r2, r1
ldrh r0, [r2, #8] @args
add r0, #1
cmp r0, #0x3c
BEQ add_var
b return

add_var:
ldr r3, =0x020370bA @var 8001 @Seg
mov r4, r3
ldrh r3, [r3]
cmp r3, #0x3c @Compara 60 seg.
BEQ add_var2 @Si paso un un minuto salta a la funcion @add_var2
add r3, #1 @Añade 1 segundo a la var 8001
strh r3, [r4] @Se guardan los segundos en la var 8001
mov r0, #0
b return

add_var2:
ldr r3, =0x020370bC @var 8002 @Min
mov r4, r3
ldrh r3, [r3]
add r3, #1 @Añade 1 minuto a la var 8002
strh r3, [r4] @Se guardan los minutos en la var 8002
mov r0, #0

return:
strh r0, [r2, #8]
POP     {r4-r6,PC}

START_CRONOMETRO
Código:
.thumb
.global stop_watch
.thumb_func 

PUSH    {R4-R6,LR}
ldr r0, =0x08xxxxxx @rutina_task
mov r1, #1
ldr r2, =0x0807741D @task_add
bl bx_r2
POP     {r4-r6,PC}

.ltorg
bx_r2: bx r2
STOP_CRONOMETRO
Código:
.thumb
.global stop_watch
.thumb_func 

PUSH    {R4-R6,LR}
ldr r0, =0x08xxxxxx @rutina_task
ldr r2, =0x08077689 @task_find
bl bx_r2
ldr r2, =0x8077509 @task_find
bl bx_r2
POP     {r4-r6,PC}

.ltorg
bx_r2: bx r2
Nota:En los espacios (xxxxxx) irá el offset permutada de la rutina llamada "CRONOMETRO".

Instruciones de uso


EJEMPLO DE INICIO
Código:
#dynamic 0x800000
//---------------
#org @inicio
setvar 0x8001 0x0 @Setea los segundos del cronometro en 0
setvar 0x8002 0x0 @Setea los minutos del cronometro en 0
callasm 0x900000 @Aqui va el offset de la rutina llamada "Start_watch"
end
EJEMPLO DE DETENCION
Código:
#dynamic 0x800000
//---------------
#org @inicio
callasm 0x900000 @Aqui va el offset de la rutina llamada "Stop_Watch"
setvar 0x8001 0x0 @Setea los segundos del cronometro en 0
setvar 0x8002 0x0 @Setea los minutos del cronometro en 0
end
Nota:
Cuando inicies el valor de la variable 0x8001 se irá incrementando de 1 en 1 por cada segundo que pase hasta llegar a 60 segundos, en ese punto el valor de la variable 8002 pasa a ser 1 lo que significa que va transcurrido 1 minuto.

Nota 2:
La rutina no esta para nada completada y tiene un montón de cosas por mejorar, aún así no está demás sus comentarios e ideas para poder añadirlas.


 

Kaiser de Emperana

Called in hand
Está buena, pero tiene un pequeño enorme bug. Cuando los segundos llegan a 60, se le suma 1 a los minutos,pero nunca se vuelve a poner la variable de los segundos en 0.
Además para ser más precisos, la comparación del contador de frames debería de hacerse con 59, y el incremento de los segundos debería hacerse antes de la comparación. Pero vamos, que tampoco es tan importante...

Sobre recomendaciones... Hacela en C(?

Pero agregando las dos líneas que arreglan el bug, la verdad que es una rutina muy útil :)

EDIT: Ahora que lo pienso, la comparación de los frames está bien. Silly me.
 
Última edición:

Inferno

Personer
Gran idea, un cronometro es algo que da muchísimo juego en un hack, si no recuerdo mal he visto algo de Javi4315 de este estilo, pero a simple vista las rutinas no son las mismas, eso me intriga y, aunque no me he puesto a mirarlas a fondo de lo que hace cada una, estaría bien mirar cual está mejor optimizada en relación a calidad de uso.

Cualquier aporte/investigación que tenga relación con el ASM va a ser de mi agrado, es el área que más lo necesita actualmente. Me gusta que gente con conocimientos se anime a compartir por aquí lo que va descubriendo y va intentando hacer a base de la investigación.
 
Con lo que tiene que ver con rutinas en general no soy muy bueno, pero esto me llama mucho la atención porque tengo entendido que Fire red no posee reloj?
Ahora mi duda mas grande, esto se podria usar como reloj? tiene algun limite de tiempo?
Esto se podria usar como reloj interno del juego? y que cada 24 horas se reinicie el cronometro?, como tu dijiste "no esta completo todavia" pero aun asi le veo mucho potencial, que buen aporte, espero mas actualizaciones.

Saludos!!
 

Invert

why so serious?
Respuesta: Re: FR | [En proceso] [ASM] Cronometro.

Está buena, pero tiene un pequeño enorme bug. Cuando los segundos llegan a 60, se le suma 1 a los minutos,pero nunca se vuelve a poner la variable de los segundos en 0.
Además para ser más precisos, la comparación del contador de frames debería de hacerse con 59, y el incremento de los segundos debería hacerse antes de la comparación. Pero vamos, que tampoco es tan importante...

Sobre recomendaciones... Hacela en C(?

Pero agregando las dos líneas que arreglan el bug, la verdad que es una rutina muy útil :)

EDIT: Ahora que lo pienso, la comparación de los frames está bien. Silly me.
Si es cierto lo del reinicio Kaiser, veré que puedo hacer.
Y lo de C..... Nahhh xD
 

Samu

Usuario de Oro
Veo que ya te han comentado el problema del reinicio. Por si tuvieras algún problema te dejo un ejemplo de como podría quedar:
Código:
.thumb
.align 2

main:
	push {r4-r6, lr}
	lsl r0, #0x18
	lsr r0, #0x18
	ldr r2, STEPS_TASK  @task
	lsl r1, r0, #0x2
	add r1, r0
	lsl r1, #0x3
	add r2, r1
	ldrh r0, [r2, #8] @args
	add r0, #0x1
	cmp r0, #0x3C
	beq add_sec
	b return

add_sec:
	ldr r3, VAR_8001
	mov r4, r3
	ldrh r3, [r3]
	cmp r3, 0x3B @Lo comparas con 59, no con 60.
	beq reset_sec
	add r3, #0x1
	strh r3, [r4]
	mov r0, #0x0
	b return
	
reset_sec:
	mov r3, #0x0 @resetea el valor de la var (8001)
	strh r3, [r4]
	mov r0, #0x0
	
add_min:
	ldr r3, VAR_8002
	mov r4, r3
	ldrh r3, [r3]
	add r3, #0x1
	strh r3, [r4]
	mov r0, #0x0
	
return:
	strh r0, [r2, #0x8]
	pop {r4-r6, pc}
	
.align 2
STEPS_TASK:
	.word 0x03005090
VAR_8001:
	.word 0x020370BA
VAR_8002:
	.word 0x020370BC

Me gustaría preguntarte para qué quieres esta rutina. Puede parecer una tontería pero tal y como la has construido tiene un problema. El valor de las variables 8001 y 8002 no se guardan en el .sav por lo que al apagar la consola se perderá la información.

Si lo que quieres por ejemplo es cronometrar lo que una persona tarde en desplazarse desde el punto "x" al punto "y". Si en el trayecto decidiese guardar la partida y dejarlo para otro rato, cuando volviese el valor del cronómetro sería 0 (quitando de que se habría cortado la ejecución de la rutina). Y claro, si querías que ocurriese algo en función del tiempo que se tardase... pues no va a funcionar.

Sin embargo, si lo que quieres es por ejemplo cronometrar cuanto tiempo se tarda en terminar un combate no habría ningún problema ya que no es posible guardar. Se me ocurren varias cosas interesantes que se podría hacer con esto último integrando alguna que otra cosa más.

PD: Otro problema que he detectado es que si por lo que sea se puede ejecutar más de una vez el script @start (y con ello la rutina) el cronómetro se reiniciará, pero comenzará a funcionar de forma errática ya que hay varios procesos calculando el tiempo del cronómetro a la vez.
Es decir, que para resetear el cronómetro es necesario hacer @stop- @start y hay que evitar que el jugador pueda activar dos veces o más @start.
 

Inferno

Personer
Re: Respuesta: FR | [En proceso] [ASM] Cronometro.

Veo que ya te han comentado el problema del reinicio. Por si tuvieras algún problema te dejo un ejemplo de como podría quedar:
Código:
.thumb
.align 2

main:
	push {r4-r6, lr}
	lsl r0, #0x18
	lsr r0, #0x18
	ldr r2, STEPS_TASK  @task
	lsl r1, r0, #0x2
	add r1, r0
	lsl r1, #0x3
	add r2, r1
	ldrh r0, [r2, #8] @args
	add r0, #0x1
	cmp r0, #0x3C
	beq add_sec
	b return

add_sec:
	ldr r3, VAR_8001
	mov r4, r3
	ldrh r3, [r3]
	cmp r3, 0x3B @Lo comparas con 59, no con 60.
	beq reset_sec
	add r3, #0x1
	strh r3, [r4]
	mov r0, #0x0
	b return
	
reset_sec:
	mov r3, #0x0 @resetea el valor de la var (8001)
	strh r3, [r4]
	mov r0, #0x0
	
add_min:
	ldr r3, VAR_8002
	mov r4, r3
	ldrh r3, [r3]
	add r3, #0x1
	strh r3, [r4]
	mov r0, #0x0
	
return:
	strh r0, [r2, #0x8]
	pop {r4-r6, pc}
	
.align 2
STEPS_TASK:
	.word 0x03005090
VAR_8001:
	.word 0x020370BA
VAR_8002:
	.word 0x020370BC

Me gustaría preguntarte para qué quieres esta rutina. Puede parecer una tontería pero tal y como la has construido tiene un problema. El valor de las variables 8001 y 8002 no se guardan en el .sav por lo que al apagar la consola se perderá la información.

Si lo que quieres por ejemplo es cronometrar lo que una persona tarde en desplazarse desde el punto "x" al punto "y". Si en el trayecto decidiese guardar la partida y dejarlo para otro rato, cuando volviese el valor del cronómetro sería 0 (quitando de que se habría cortado la ejecución de la rutina). Y claro, si querías que ocurriese algo en función del tiempo que se tardase... pues no va a funcionar.

Sin embargo, si lo que quieres es por ejemplo cronometrar cuanto tiempo se tarda en terminar un combate no habría ningún problema ya que no es posible guardar. Se me ocurren varias cosas interesantes que se podría hacer con esto último integrando alguna que otra cosa más.

PD: Otro problema que he detectado es que si por lo que sea se puede ejecutar más de una vez el script @start (y con ello la rutina) el cronómetro se reiniciará, pero comenzará a funcionar de forma errática ya que hay varios procesos calculando el tiempo del cronómetro a la vez.
Es decir, que para resetear el cronómetro es necesario hacer @stop- @start y hay que evitar que el jugador pueda activar dos veces o más @start.

Concuerdo contigo en el fallo de que los valores se guardan en unas variables que no nos sirven pues no se quedan en el .sav, una manera que se me ocurre para arreglar esto sería haciendo un copyvar hacia las variables seguras para que así no se perdiese ese valor.
 

Samu

Usuario de Oro
Madre mía, es la tercera vez que tengo que escribir esto. El foro se empeña en darme por culo y fallar cada vez que le doy a enviar mensajes.

A ver, tal y como lo entiendo, tendrías que hacer el copyvar cada vez que guardas partida, cosa que... sinceramente, yo al menos no caigo en como puedo hacerlo.

A parte, aunque hicieses el copyvar, necesitarías hacer un script de nivel para que al entrar al mundo, si el cronómetro estaba en funcionamiento cuando guardaste la partida, comience a ejecutar la rutina del cronómetro (ya que su ejecución paró al apagar). Esto es un problema, teniendo en cuenta que tendrías que poner ese script de nivel en cada uno de los mapas a los que pudieses ir con el cronómetro activado.

Lo que se me ocurre es integrar la rutina como una subrutina del main loop. Para controlar la ejecución o no de esta subrutina utilizaríamos un flag, si está activado se habilita la ejecución del cronómetro y si no lo está, se ejecuta el main loop con normalidad. La subrutina del cronómetro guardaría los valores de los segundos y los minutos en variables seguras.
Con esto conseguiríamos que la ejecución del cronómetro solo se detenga por la desactivación del flag, no viendose afectada por el reinicio del juego.

PD: La desactivación del flag podríamos acompañarla de un reseteo del valor de las variables en las que guardamos los datos.
 
Última edición:

Invert

why so serious?
Veo que ya te han comentado el problema del reinicio. Por si tuvieras algún problema te dejo un ejemplo de como podría quedar:
Código:
.thumb
.align 2

main:
	push {r4-r6, lr}
	lsl r0, #0x18
	lsr r0, #0x18
	ldr r2, STEPS_TASK  @task
	lsl r1, r0, #0x2
	add r1, r0
	lsl r1, #0x3
	add r2, r1
	ldrh r0, [r2, #8] @args
	add r0, #0x1
	cmp r0, #0x3C
	beq add_sec
	b return

add_sec:
	ldr r3, VAR_8001
	mov r4, r3
	ldrh r3, [r3]
	cmp r3, 0x3B @Lo comparas con 59, no con 60.
	beq reset_sec
	add r3, #0x1
	strh r3, [r4]
	mov r0, #0x0
	b return
	
reset_sec:
	mov r3, #0x0 @resetea el valor de la var (8001)
	strh r3, [r4]
	mov r0, #0x0
	
add_min:
	ldr r3, VAR_8002
	mov r4, r3
	ldrh r3, [r3]
	add r3, #0x1
	strh r3, [r4]
	mov r0, #0x0
	
return:
	strh r0, [r2, #0x8]
	pop {r4-r6, pc}
	
.align 2
STEPS_TASK:
	.word 0x03005090
VAR_8001:
	.word 0x020370BA
VAR_8002:
	.word 0x020370BC

Me gustaría preguntarte para qué quieres esta rutina. Puede parecer una tontería pero tal y como la has construido tiene un problema. El valor de las variables 8001 y 8002 no se guardan en el .sav por lo que al apagar la consola se perderá la información.

Si lo que quieres por ejemplo es cronometrar lo que una persona tarde en desplazarse desde el punto "x" al punto "y". Si en el trayecto decidiese guardar la partida y dejarlo para otro rato, cuando volviese el valor del cronómetro sería 0 (quitando de que se habría cortado la ejecución de la rutina). Y claro, si querías que ocurriese algo en función del tiempo que se tardase... pues no va a funcionar.

Sin embargo, si lo que quieres es por ejemplo cronometrar cuanto tiempo se tarda en terminar un combate no habría ningún problema ya que no es posible guardar. Se me ocurren varias cosas interesantes que se podría hacer con esto último integrando alguna que otra cosa más.

PD: Otro problema que he detectado es que si por lo que sea se puede ejecutar más de una vez el script @start (y con ello la rutina) el cronómetro se reiniciará, pero comenzará a funcionar de forma errática ya que hay varios procesos calculando el tiempo del cronómetro a la vez.
Es decir, que para resetear el cronómetro es necesario hacer @stop- @start y hay que evitar que el jugador pueda activar dos veces o más @start.
¡Bravo! Me ahorraste el tiempo para editar la rutina xD
Lo de las variables es cierto, lo hice asi porque quería usarlo solo para eventos secundarios y no para enredos de cabeza como lo que muchos están pensando xD.
 
Hey, this is really cool! It would be made better if you broke out of the task system however. The tasks are reset once warping or entering battle making it unreliable to track time outside of a single map and short event (with no battle inbetween).

The solution is to log the current playtime in integer format into a variable/RAM location of choice in your clock start routine. Then on the pause portion, you will want to fetch the current time at pausing and compute the time passed and return that instead. The entire algorithm would only take 2 bytes, and isn't as expensive as running a task.
I hope this tip helps you fix the issue in this routine, awesome to see this kind of work!
 

Asmodeo Leviatan

¿La Iglesia inventó el Infierno? O es lo contrario
.... sin palabras, eso seria muy bueno para que quedara de forma prof...pero, no mucho le prestamos atencion a esa pequeña parte.... aun asy esta genial!
 
Arriba