Jump to content

Recommended Posts

¡Hola a todos de nuevo!

 

Este será un tutorial sobre los timers en una dung. Ojo, solo en las dungs.

Tutorial nivel intermedio

 

Existen dos tipos de timers:

Timers globales:

Estos timers son a nivel de la dung. Tenemos:

server_timer()
server_loop_timer()

 

Timers personales:

Estos timers son a nivel de personaje. Tenemos:

timer()
loop_timer()

 

server_timer()

 

server_timer() es generalmente utilizado para tiempos globales en las dungs. Un tiempo global quiero decir, por ejemplo, cuando entras a la dung y te dice: "Te quedan 45 minutos para matar al jefe". Y es fácil de identificarlo porque ese tiempo es el mismo para todos. server_timer() es una función y también es un disparador (when) que se activa cuando pasa el tiempo determinado.

Pero no siempre se usa para poner un anuncio de tiempo, sino que hay muchas funciones que se pueden usar. Y ojo a lo siguiente que es donde más se cometen errores:

Al ser una función global, no puedes poner funciones personales

Funciones que NO puedes poner en un server_timer():

- say(), chat(), syschat(), notice() o derivadas.
- pc.mount(), y cualquiera que tenga pc... ya que "pc" es "personal character", no es global
- game.drop_item() porque el objeto cae bajo el pj

Funciones que puedes usar dentro de un server_timer():

- d.notice(), notice_all(), notice_multiline(), 
- clear_server_timer()
- game.set_event_flag(), game.get_event_flag()
- server_loop_timer()
- Todas las que sean de dung, o sea, las que empiecen por d., ejemplo d.count_monster()
- Todas las que no tengan que ver con afectar a algún carácter, ejemplo tonumber(), table.getn(), string.len(), etc.

 

Estructura de un server_timer()

Para crearlo:

En el nombre, es el mismo nombre que le vas a poner al when.

En tiempo, procura ponerlo en esta estructura, 60*60*2 (2 horas), por ejemplo.

Si el server_timer no está dentro de otro, se pone en el 3° parámetro el index del mapa. Yo pongo d.get_map_index() pero es igual que con pc.get_map_index(). Esto mismo se aplica para la función clear_server_timer().

server_timer("nombre", tiempo, d.get_map_index())

Si el server_timer está dentro de otro, se pone get_server_timer_arg(), así:

server_timer("nombre", tiempo, get_server_timer_arg())

 

Cuerpo de un server_timer():

		when nombre.server_timer begin
			if d.select(get_server_timer_arg()) then
				-- aquí pones tu contenido con las funciones válidas
			end
		end

En nombre, puse el mismo de cuando lo creé. Luego, en vez de poner use, chat, y esas cosas, puse server_timer.

Sí o sí para dungs hay que poner ese bloque if así tal cual está. Esto es para identificar la dung.

 

Pongo los dos casos a continuación:

when login begin
	server_timer("nombre", 60, d.get_map_index()) --cuando pongo un server_timer() en un when normal
end

when nombre.server_timer begin
	if d.select(get_server_timer_arg()) then
		server_timer("nombre2", 30, get_server_timer_arg()) --cuando pongo un server_timer() en un when server_timer
	end
end

 

Parar un server_timer:

En el caso de que esté en un when distinto a un server_timer:

clear_server_timer("nombre", d.get_map_index())

En el caso de que esté dentro de un when server_timer:

clear_server_timer("nombre", get_server_timer_arg())

Cuándo se detiene un server_timer?

- Cuando necesitas parar un server_loop_timer
- Cuando necesites detenerlo y crear otro con diferente tiempo. Como en el caso de Catacumbas cuando destruyes a Caronte, te crea un nuevo tiempo para matar a Azrael.
- Cuando terminas la dung y antes de transportar a todos, limpias todos los server_timer.

Cómo crear un server_timer imitando un ciclo:

when login begin
	server_timer("nombre", 60, d.get_map_index())
end

when nombre.server_timer begin
	if d.select(get_server_timer_arg()) then
		server_timer("nombre2", 30, get_server_timer_arg())
	end
end

when nombre2.server_timer begin
	if d.select(get_server_timer_arg()) then
		server_timer("nombre", 1, get_server_timer_arg()) --llamo al server_timer anterior en 30 seg, y éste llamará de nuevo al server_timer y así...
	end
end

 

Esta estructura sirve como ciclo, en este caso para que cada 30 segundos haga algo.

 

La siguiente estructura es para anunciar los tiempos de duración de la dung:

when login begin
	server_timer("nombre", 10, d.get_map_index()) --en 10 segundos empezará a avisar que faltan 60 min
end

when nombre.server_timer begin
	if d.select(get_server_timer_arg()) then
		d.notice("Quedan 60 minutos")
  		server_timer("nombre2", 60*30, get_server_timer_arg()) --en 30 min avisará que quedan 30 min
	end
end

when nombre2.server_timer begin
	if d.select(get_server_timer_arg()) then
		d.notice("Quedan 30 minutos")
  		server_timer("nombre3", 60*20, get_server_timer_arg()) --en 20 min avisará que quedan 10 min
	end
end

when nombre3.server_timer begin
	if d.select(get_server_timer_arg()) then
		d.notice("Quedan 10 minutos")
  		server_timer("nombre4", 60*5, get_server_timer_arg()) --en 5 min avisará que quedan 5 min
	end
end

when nombre4.server_timer begin
	if d.select(get_server_timer_arg()) then
		d.notice("Quedan 5 minutos")
  		server_timer("nombre5", 60*5, get_server_timer_arg()) --en 5 min transportará a todos
	end
end

when nombre5.server_timer begin
	if d.select(get_server_timer_arg()) then
  		d.exit_all()
	end
end

 

server_loop_timer()

 

server_loop_timer() es igual al server_timer() pero cíclico. Loop significa ciclo, repeticiones cada cierto tiempo. Mientras que server_timer() hace algo una vez en x tiempo, server_loop_timer() hace algo cada x tiempo (en segundos) hasta que lo detengas forzosamente.

Las funciones que se utilizan son las mismas que en el server_timer().

 

Estructura de un server_loop_timer()

Para crearlo:

Se crea exactamente igual que el server_timer(), solo cambia el tiempo. Si pones 5, cada 5 segundos hará lo que pongas dentro del when.

 

Cuerpo de un server_loop_timer():

La única diferencia es que el when es el mismo.

Veamos:

when login begin
	server_loop_timer("nombre", 5, d.get_map_index())
end

when nombre.server_timer begin --aquí se pone server_timer
	if d.select(get_server_timer_arg()) then
		-- aquí pones lo que va a hacer cada 5 seg
	end
end

Los server_loop_timer se detienen igual que un server_timer.

 

Combinar server_loop_timer con server_timer:

El tiempo de un server_loop_timer debe ser mayor al de un server_timer anidado. Anidado significa que está dentro, o sea, el server_timer dentro del server_loop_timer.

Veamos qué sucede si NO cumplo con esta regla:

when login begin
	server_loop_timer("nombre", 5, d.get_map_index())
end

when nombre.server_timer begin
	if d.select(get_server_timer_arg()) then
		server_timer("nombre2", 10, get_server_timer_arg())
	end
end

El ciclo cada 5 segundos va a ejecutar un ciclo de 10 segundos. Entra al ciclo, ejecuta el server_timer(), y en el segundo 5 vuelve a entrar al ciclo, impidiéndole cumplir sus 10 segundos para entrar al server_timer. Así que la regla es no poner un server_timer() con un tiempo mayor al del server_loop_timer().

Pero toda regla tiene sus excepciones, así que vamos con esta:

Si el ciclo tiene una condición que permite que el server_timer() cumpla con su tiempo, entonces sí es válido. Como en el siguiente ejemplo:

when login begin
	server_loop_timer("nombre", 5, d.get_map_index())
end

when nombre.server_timer begin
	if d.select(get_server_timer_arg()) then
		if d.getf("bloqueo") == 0 then
			server_timer("nombre2", 10, get_server_timer_arg())
  			d.setf("bloqueo", 1)
  		end
	end
end

Puse un d.getf() que cuando entra y ejecuta el server_timer(), solo lo hace una vez porque le cambié el valor al d.getf() al final.

Es claro que el código así como lo tenemos no va a funcionar, tendríamos que hacer que el personaje logre cambiar de nuevo el valor del d.getf("bloqueo") a 0 para que se ejecute de nuevo el ciclo (si es lo que buscamos). Digamos que, cuando mate al jefe, ponga d.setf("bloqueo", 0) y se ejecutará de nuevo el ciclo.

 

 

timer()

 

Los timer() se usan cuando necesitas ejecutar funciones a nivel de personaje. La ventaja es que son más sencillas de usar, incluso puedes usar cualquier función, hasta las globales.

Crear un timer:

timer("nombre", tiempo)

 

Cuerpo de un timer:

when login begin
	timer("nombre", 10)
end

when nombre.timer begin
	-- 
end

En el when solo pones nombre.timer

Ya no hay que poner el if 😄

 

Detener un timer:

cleartimer("nombre")

Prácticamente no se usa en las dungs porque generalmente cualquier acción en las dungs afectan a todos los personajes que están ahí. Por lo tanto, si usas un timer() en una dung, y el personaje se desconecta antes de pase el tiempo, no se ejecutará el when timer. El timer() se muere cuando lo detengas o cuando el personaje se desconecta. A diferencia del server_timer o server_loop_timer que se sigue ejecutando sin importar si los personajes se desconectaron. Un ejemplo crítico para esto, es que mates un jefe y te ponga un timer() donde los lleve a todos a una sala, pues si el pj se desconecta antes de que ocurra el timer, nadie se transportará a la sala.

Los timer() se pueden anidar en los server_timer() y server_loop_timer(). Así que la regla es, si las funciones son a nivel personaje debes usar timer(), si son a nivel global (a nivel dung, de hecho) se usan los server_timer() y server_loop_timer().

Un posible uso es que cuando mates a un jefe, en un determinado tiempo te de algo (a ti solo) pero no le veo mucho sentido.

 

loop_timer()

Llegamos al nivel más complejo del tutorial.

Un loop_timer() es como un server_loop_timer() pero a nivel personaje.

Crear un loop_timer:

loop_timer("nombre", tiempo)

 

Cuerpo de un loop_timer:

when login begin
	loop_timer("nombre", 5)
end

when nombre.timer begin
	--
end

 

Detener un loop_timer:

Se detiene igual que un timer.

 

Un loop_timer famoso es el de cuando el personaje se muere y haga algo

when login begin
	loop_timer("muerto", 5)
end

when muerto.timer begin
	if pc.get_hp() <= 0 then
		chat("Se murióooo (8)")
	end
end

El tiempo del loop_timer() debe ser menor al tiempo en que hace respawn el pj o sino no aparece cuando le de al botón de respawn cuando ya pueda aparecer.

Cuando el pj muere, en pocos segundos aparecerá en el chat ese mensaje, y si sigue muerto, cada 5 segundos seguirá apareciendo.

Pero bueno, en una dung no le veo mucho sentido usar un loop_timer() independiente porque vuelvo y repito, las funciones de las dung afectan a todos los personajes salvo la creatividad que quieras darle que necesite de algo más exclusivo...

 

Combinar loop_timer() con server_timer() y server_loop_timer():

 

El objetivo es usar funciones personales con funciones globales, así hacemos más diversa la dung. El problema está en que es no es tan sencillo combinarlas y menos cuando vamos a meter un loop_timer(), así que vamos a ver lo que yo llamo semáforos, que básicamente es usar los d.getf() y d.setf() como banderas.

Vamos a hacer que el personaje cuando muera (loop_timer() porque la muerte es personal y además debe evaluar cada ciertos segundos porque no es when) lo lleve a city:

when login begin
	loop_timer("muerto", 3)
end

when muerto.timer begin
	if pc.get_hp() <= 0 then
		timer("enviar_a_city", 1)               
	end
end

when enviar_a_city.timer begin
	warp_to_village()
end

Puse un timer de 1 segundo para que al morir no transporte de una vez (se ve horrible).

Ahora haré que cuando no hayan monstruos, invoque otros monstruos más después de 60 segundos:

when login begin
	d.spawn_mob(blablabla) --aquí invoco los primeros mobs
	loop_timer("muerto", 3)
	server_loop_timer("timer_inv", 3, d.get_map_index()) --ciclo cada 3 segundos para evaluar si hay monstruos
end

when muerto.timer begin
	if pc.get_hp() <= 0 then
		timer("enviar_a_city", 1)               
	end
end

when enviar_a_city.timer begin
	warp_to_village()
end

when timer_inv.server_timer begin
	if d.select(get_server_timer_arg()) then
		if d.count_monster() <= 0 and d.getf("bloqueo") == 0 then --si no hay monstruos, entonces... y de una vez pongo mi bloqueo que expliqué antes
			server_timer("invocar", 60, get_server_timer_arg()) --en 60 seg invocará de nuevo
			d.setf("bloqueo", 1) --fin bloqueo
		end
	end
end

when invocar.server_timer begin
	d.spawn_mob(blablabla) --aquí invoca de nuevo
	d.setf("bloqueo", 0) --pongo bloqueo en 0 para que pueda volver a invocar por el server_loop_timer
end

Ahora buscaré la manera de hacer que en cada oleada se monten automáticamente los personajes en alguna montura. Aquí aplicaré una función personal (pc.mount()) pero a todos.

 

when login begin
	d.spawn_mob(blablabla)
	loop_timer("muerto", 3)
	server_loop_timer("timer_inv", 3, d.get_map_index()) 
end

when muerto.timer begin
	if d.getf("montar_todos") == 1 then --esta es la bandera que les decía
		d.setf("montar_todos", 0) --toca bloquearla para que no se repita de nuevo hasta que se lance de nuevo la oleada
		quest.montarTodos() --aquí va a la function...
	end
	if pc.get_hp() <= 0 then
		timer("enviar_a_city", 1)               
	end
end

when enviar_a_city.timer begin
	warp_to_village()
end

when timer_inv.server_timer begin
	if d.select(get_server_timer_arg()) then
		if d.count_monster() <= 0 and d.getf("bloqueo") == 0 then 
			server_timer("invocar", 60, get_server_timer_arg()) 
			d.setf("bloqueo", 1) 
		end
	end
end

when invocar.server_timer begin
	d.spawn_mob(blablabla) o
	d.setf("bloqueo", 0)
	d.setf("montar_todos", 1) --pongo en 1 esta bandera para que arriba en el loop_timer entre a la condición que hace que todos monten
end

function montarTodos()
	-- aquí se usa el partyMembers y todo eso de las dungs...
	pc.mount() --lo que quiero que entiendan acá es que ese pc.mount() se aplicará en todos los pjs con q.begin_other_pc_block() y q.end_other_pc_block()
end

El resumen de esta parte es que utilicé los d.setf y d.getf para poder activar y desactivar las entradas a ciertas condiciones de los server_timer o server_loop_timer. Así que si necesitas usar una función personal en un server_loop_timer debes activar una bandera, en el loop_timer poner la condición, desactivar la bandera y luego hacer las funciones.

 

Notas:

- Se puede usar funciones dungeon (las que empiezan por d.) dentro de cualquier when (timers globales, personales, use, chat, todo eso)
- Las líneas de código se ejecutan inmediatamente. No hay que esperar x tiempo del timer para que se ejecute las siguientes líneas.
- El /rel q, mata todos los timers del mapa. Así que al testear debes cambiar de pj.

 

Y bueno, esto solo se entiende practicando xD

Si no entendiste ni madres, estás bien. Probablemente en dos semanas no entenderé lo que puse acá

Esto lo apliqué en mi quest de "Arena Mob" que es una mazmorra infinita. Y al agregarle complejidad a la mazmo, había funciones que sí o sí debía poner en el server_loop_timer algunas funciones que eran personales, como pc.give_item2(), pues al pasar de cada ciertas oleadas tenía que dar unos premios y no podía usar pc.give_item2() en el server_loop_timer, así que me tocó en el loop_timer. Tampoco quería que reclamaran los premios dándole clic al NPC, yo quería que se dieran automáticamente y ahí está la complejidad.

 

Arena Mob

Consiste en una mazmorra de gremio donde se entra en grupo (la idea es que vayan los 8 mejores del gremio) y deben vencer las oleadas de monstruos que aparecen. Una vez dentro del mapa, aparecerá en anuncio que el gremio x se está enfrentando a la Arena Mob. Personaje que muere, será transportado a la ciudad y aparecerá un anuncio diciendo que x persona del gremio y murió en la oleada z.
En cada oleada los monstruos se vuelven más fuertes y más resistentes. Cada ciertas oleadas todos los personajes que sigan vivos en la dung van a recibir un premio. En cada ciertas oleadas aparecerá un jefe un poco más fuerte. Cuando destruyan la oleada, pueden hacer aparecer otra inmediatamente, pero si no lo hacen, en 60 segundos aparecerá.
Cuando muera el último personaje, aparecerá en anuncio que el gremio x terminó la Arena Mob en la oleada y. Luego, hay un ranking donde aparecerá la lista de gremios que llegaron a la oleada más alta.

Precio de la quest: 15 usd

 

Discord: Camilo#0869

Un gusto ayudarlos, ¡saludos amigos!

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Sign in to follow this  

  • Recently Browsing   0 members

    No registered users viewing this page.

×
×
  • Create New...