Jump to content

fuuton97

Miembro
  • Contador contenido

    177
  • Ingreso

  • Última visita

  • Días ganados

    10

Actividad de reputación

  1. Me Gusta
    fuuton97 reacted to ElRaulxX in [Minicurso] MySQL en quest   
    He visto que muchos preguntáis como utilizar querys de sql en quest. Le dije a keko que haría este mini tutorial, y aquí lo tenéis.

    Primero de todo decir que esta función no viene por defecto en el metin y es por eso que algunos usuarios la han hecho ellos mismos, pues la utilidad de esta función es muy grande.
    Tengo contado tres personas que han publicado esta función: Hanashi, mijago y yuko. Quizá han sido publicadas más, pero solamente recuerdo estas.
    A mi parecer, la más practica que he visto hasta ahora es la última versión de mijago y es la que utilizaremos en este Minicurso.


    Primero de todo, debemos declarar estas dos funciones en nuestro questlib.lua



    ATENCION! Si en nuestro servidor tenemos instalado la versión 5.5 de MySQL debemos borrar esto:
    os.execute('mysql '..pre..' --e='..string.format('%q',query)..' > '..fi) -- für MySQL51 y quitar las -- de aquí:
    --os.execute('mysql '..pre..' -e'..string.format('%q',query)..' > '..fi) -- für MySQL55 La razón es simple, la sintaxis de esta versión de MySQL es distinta.

    Ahora tenemos que añadir en quest_functions la función:
    mysql_query La función split no hace falta añadirla en este archivo ya que se utiliza internamente en mysql_query.

    Bien, ahora ya tenemos instalada la función de mysql.
    Ahora lo más importante: ¿cómo se usa?

    Tenemos esta tabla:

    Como vemos, la tabla se llama 'tablatest' y se encuentra en la db 'test'. Esta tabla posee tres campos, que son 'campo1', 'campo2' y 'campo3'.
    Con la función mysql_query llamaremos, añadiremos o modificaremos valores de esta tabla. La sintaxis de mysql_query es la misma que cualquier otra query de mysql que utilicemos (de navicat, php...). Sino sabéis la sintaxis os aconsejo que miréis cursos para aprender. La sintaxis es muy sencilla y no tiene complicación, solo se necesita mirar un poco y lo dominaréis perfectamente. Existen miles de cursos y tutoriales por internet de mysql, tan solo debéis buscarlos.

    ATENCION: Para utilizar sentencias que retornen algún tipo de valor (select) debemos asignar la función a una variable. Las demás (update, insert into...) tan solo tenemos que utilizarla como cualquier otra función.

    Bien, empecemos. Comenzaremos llamando toda la tabla.
    local read = mysql_query("SELECT * FROM test.tablatest") Esto almacenará en la variable la siguiente tabla:
    local read = {[campo1] = {"texto1","texto2","texto3"},[campo2] = {"texto4","texto5","texto6"},[campo3] = {"texto7","texto8","texto9"}} Teniendo esto en cuenta, y sabiendo un poco de tablas y arrays en lua está todo solucionado.
    Queremos mostrar en pantalla 'texto5' que está almacenado en nuestra tabla. Lo llamaremos de esta manera.
    local read = mysql_query("SELECT * FROM test.tablatest")say(read.campo2[2])--esto muestra texto5 Ahora queremos llamar 'texto9':
    local read = mysql_query("SELECT * FROM test.tablatest")say(read.campo3[3])--esto muestra texto9 Ahora queremos llamar 'texto1':
    local read = mysql_query("SELECT * FROM test.tablatest")say(read.campo1[1])--esto muestra texto1 Aquí no voy a ponerme a explicar arrays porqué no trata de eso el curso, pero creo que mirando los ejemplos y pensando un poco lo entenderéis.

    Ahora también podemos añadir una condición:
    local read = mysql_query("SELECT * FROM test.tablatest WHERE campo2 = 'texto5'") Esto almacenará en la variable la siguiente tabla:
    local read = {[campo2] = {"texto4","texto5","texto6"}} Y ahora podemos llamarlo de la misma manera que en el ejemplo anterior.
    Esto nos mostrará 'texto6' en pantalla.
    local read = mysql_query("SELECT * FROM test.tablatest WHERE campo2 = 'texto5'")say(read.campo2[3])--esto muestra texto6 Y para hacerla verdaderamente útil podemos llamar a variables o funciones.
    local var = "texto5"local read = mysql_query("SELECT * FROM test.tablatest WHERE campo2 = '"..var.."'")say(read.campo2[3])--esto muestra texto6 Algo importante que hay que decir es que esta función siempre crea tablas y por lo tanto siempre deberemos llamarlo de la misma manera, aunque haya seleccionado un solo valor.
    local read = mysql_query("SELECT campo1 FROM test.tablatest WHERE campo1 = 'texto1'")say(read.campo1[1])--esto muestra texto1 Creo que con estos ejemplos ya podéis ver como funciona un select (la verdad es que es bastante difícil explicarlo teniendo en cuenta que no tenéis conocimientos de tablas, pero al menos lo he intentado xd). La mejor manera que veáis su uso es que vayáis haciendo pruebas en navicat y luego trasladarlo a una quest.

    Y ahora la segunda parte.
    Si queremos añadir nuevos valores lo hacemos de esta manera:
    mysql_query("INSERT INTO test.tablatest VALUES ('texto10','texto11','texto12')") o como hemos hecho antes:
    local v1 = "texto10"local v2 = "texto11"local v3 = "texto12"mysql_query("INSERT INTO test.tablatest VALUES ('"..v1.."','"..v2.."','"..v3.."')") Y nos quedará la tabla así:


    Y si queremos modificar valores:
    mysql_query("UPDATE test.tablatest SET campo1='prueba' WHERE campo1='texto10'") local x = "prueba"local y = "texto10"mysql_query("UPDATE test.tablatest SET campo1='"..x.."' WHERE campo1='"..y.."'") Y nos quedaría esto:


    Sabiendo de mysql no debería ser ninguna complicación, el problema es que no sepáis
    Cuando publiquemos el capítulo de arrays y tablas lo entenderéis todo mejor, no os preocupéis.

    Y creo que eso es todo. Saludos!
  2. Me Gusta
    fuuton97 got a reaction from Rinnegan in [SCRIPT] Borrar quest individualmente.   
    Jaajaja, Rinnega me da risa lo que dices, Discrimina? osea T____________T, acaso que discrimina te recomendante ir a google y busca el significado de discriminación.
  3. Me Gusta
    fuuton97 reacted to KeKo in Capitulo VII - El uso del pc.setqf y pc.getqf   
    Buenas zoneros y zoneras, aqui estoi de nuevo con una nueva leccion del curso de creacion de quests dedicada a mi colega akroma y a sema que tenen problemillas con los qfs
     
    Pc.setqf, pc.getqf... pc.set... pc.geee.... De que estabamos hablando?
     
    Uno de los comandos que mas utilizareis cuando os esteis haciendo/revisando quests serán los famosos:
     

    pc.setqf pc.getqf Para explicaros como funcionan estos tan problematicos comandos recurrire de nuevo al bonito simil que utilice cuando mi buen amigo Jordan me pidio una explicacion sencilla para entender de una vez estos comandos. Antes de hacerlo, quiero recordaros un dato muy importante: estos dos comandos llevan pc.algo así que tened muy en mente que afectan siempre a un jugador, que es el que active el qf en la quest y NO ningun otro.
     
    Bien, ahora pensad en un posit (esas notitas de colores que puedes pegar donde quieras) y pensad en una pared en la que podemos pegar nuestro posit. Ahora convirtamos esto a lua, nuestro posit es el pc.setqf y el pc.getqf y nuestra pared es el jugador que activara el qf.
     
    Que narices tiene que ver un posit en todo esto keko?
     
    Esta claro que en lua no hay posits, pero lo que busco con esta comparacion es que pilleis el concepto del qf. Bueno volvamos a donde lo dejamos: tenemos nuestro pj al que le queremos pegar un posit (es decir ponerle un qf) así que cojemos un boli y pensamos algo que poner en nuestro posit, es decir, pensamos que valor le vamos a dar al qf si pensamos en lua.
     
    Una vez ya lo hemos pensando, escribimos lo que queriamos y lo pegamos en la pared, lo que en lua corresponderia con darle un valor al qf y asignarselo al personaje.
     
    Pero esto no se para aquí, para que sirve un posit? Para acordarnos de algo!! Por lo tanto si seguimos con la comparacion al lua, habra veces que necesitemos comprobar que valor tiene nuestro qf para hacer condiciones con el. Además, si queremos cambiar lo que pone el posit, simplemente lo tachamos y ponemos otra cosa; en lua también podemos modificar el valor que tiene el qf de nuestro personaje.
     
    No me he enterao de una mierda , que hago con el posit?
     
    Aver, eso fue una comparación, para los que aun esteis buscando un boli pa escribir algo en el posit os haré un resumen de todo lo que os he estado intentando explicar hasta ahora:
     
    El comando pc.setqf nos permite asignar un determinado valor a un personaje de modo que podamos usar el comando pc.getqf para crear condiciones que impliquen que el personaje tenga ese valor concreto para activarse.
     
    Bueno, ahoara que ya lo he explicado en plan posit y en plan redactado vamos a profundizar un poquito en el uso de estos dos comandos.
     
    Ummm, como decias que le asignaba el valor a eso?
     
    Pues es muy sencillo, lo primero es distinguir entre:
     

    pc.setqf
    pc.getqf El pc.setqf siempre se usará para ASIGNAR un valor, mientras que el pc.getqf se encargará de CHEQUEAR cuál es el valor que tiene el qf que hemos puesto con el setqf.
     
    Bien, una vez sabemos esto procederé a explicaros cual es la sintaxis de un pc.setqf:
     

    pc.setqf("nombredelqf", valor) Del que seria un ejemplo este:
     

    pc.setqf("kekomola", 5) En este caso el jugador tendra asignado el valor "kekomola" con una cantidad igual a 5. El nombre que tenga el qf es el que vosotros querais!
     
    Me gustaria discernir entre dos tipos de setqfs:
     

    pc.setqf("kekomola", 2) pc.setqf("kekomola", pc.getqf("kekomola") + 1) El primero de ellos es un setqf que se utiliza cuando la cantidad que le vamos a dar al valor es fija, mientras que el segundo se utliza cuando la cantidad va a ir aumentando cada vez que utilicemos el setqf.
     
    Por lo tanto, en el primer caso siempre que activemos esa parte de la quest el valor kekomola sera igual a 2. Sin embargo, cada vez que activemos el segundo caso el valor kekomola irá aumentando en 1 (es decir la primera vez que lo usemos la cantidad sera 1, lo volveremos a usar y sera 2, luego 3, etc).
     
    Y por no faltar ahora os explicaré la sintaxis del pc.getqf: como este comando solo se utiliza en condiciones (ya que su funcion es la de chequear) no tiene la misma sintaxis que el setqf:
     

    if pc.getqf("kekomola") == 5 then Este comando lo usareis combinado con el estructurador if, por lo que ira escrito el pc.getqf("nombre") y luego el doble simbolo de igualdad (tipico de las comparaciones) y la cantidad del valor.
     
    Vale ya se asignar valores, ahora de que me sirve esto?
     
    Pues los setqf son unos de los comandos mas utilizados en las quests ya que permiten crear condiciones que van cambiando segun lo que va haciendo el personaje. Veamos un ejemplo:
     

    quest item begin state start begin when 70045.use begin pc.setqf("buenas", pc.getqf("buenas") + 1) if pc.getqf("buenas") == 1 then chat("buenas") elseif pc.getqf("buenas") == 2 then chat("que tal") elseif pc.getqf("buenas") >= 3 then chat("me aburro") end end end end En esta cada vez que usas el item te auemnta en 1 el qf:
     

    pc.setqf("buenas", pc.getqf("buenas") + 1) Por lo tanto ponemos una condicion para diferentes del mismo:
     

    if pc.getqf("buenas") == 1 then elseif pc.getqf("buenas") == 2 then elseif pc.getqf("buenas") >= 3 then De ese modo, dependiendo de cuantas veces hayamos usado el item dira algo diferente cada vez.
     
    Subamos la dificultad, convirtamos funciones en qfs:
     
    Bien, ahora que habeis visto un ejemplo de los qfs me toca enseñaros un paso mas, que seria utilizar funciones que recojen un dato del personaje y asignar el valor de ese dato a un qf. Para ello haremos lo siguiente:
     

    quest prueba begin state start begin when 70044.use begin local cabanivel = horse.get_level() pc.setqf("nivelcaballo", cabanivel) chat("El nivel de tu caballo se ha guardado") end end end Puede que a alguno le suene eso, ya que es la base del sistema de mascotas que cuando le das a control+h se sube al caballo en vez de subirse a la mascota. Pero lo importante para nuestra explicacion es el hecho de que si creamos un local que recoja un dato mediante una funcion:
     

    local cabanivel = horse.get_level() Luego podemos asingar ese valor al qf:
     

    pc.setqf("nivelcaballo", cabanivel) Entonces vamos a seguir desarrolando esa mini quest de sistema de mascotas, metiendo mas qfs:
     

    quest prueba begin state start begin when 70044.use begin if pc.getqf("keko") == 0 then local cabanivel = horse.get_level() pc.setqf("nivelcaballo", cabanivel) pc.setqf("keko", 1) horse.set_level("22") horse.unsummon() horse.summon() chat("Acabas de invocar a tu mascota") return end local volvernivel = pc.getqf("nivelcaballo") horse.set_level(volvernivel) pc.setqf("keko", 0) horse.unsummon() chat("Acabas de guardar tu mascota") end end end Bien, que ha pasado aqui? Pues varias cosas la verdad, vayamos de una en una:
     

    if pc.getqf("keko") == 0 then Aqui ponemos una condicion de que este qf sea igual y a 0, es decir, que aun no hayas usado nunca el item ya que cuando lo uses pondras cantidad 1 a ese valor:
     

    pc.setqf("keko", 1) Ahora como ya has usado el item el qf se ha vuelto 1, por lo que si vuelves a usar el item ya no estaras cumpliendo la condicion de que sea igual a 0, y la otra parte de la condicion (lo que va despues del return+end) se activa. Una vez se activo eso volvemos a poner cantidad 0 al qf:
     

    pc.setqf("keko", 0) Por lo tanto os habreis dado cuenta de que este objeto va alternando dos cosas: lo usas una vez y hace la primera, lo usas otra vez y hace la segunda, lo usas una tercera y vuelve a la primera y así constantemente.
     
    Además, aqui tambien hemos jugado con el nivel del caballo:
     

    local cabanivel = horse.get_level() pc.setqf("nivelcaballo", cabanivel) Primero miramos cual es con el local, y luego se lo asignamos al qf. Una vez asignado lo cambiamos con el comando horse.set_level e invocamos la mascota. Pero que pasa cuando guardamos la mascota? Queremos que el caballo vuelva a estar a su nivel, asi que hacemos lo siguiente: como ya tenemos nuestro qf con el nivel del caballo antes de cambiarlo, cogemos el valor de ese qf y lo convertimos en un local que luego damos de valor al horse.set_level
     

    local volvernivel = pc.getqf("nivelcaballo") horse.set_level(volvernivel) Vale, pues a otra cosa no?
     
    Ahora que ya entendeis como mezclar una funcion que recoje datos con un qf ya solo me quedaria explicaros como podeis hacer para mostrar la cantidad de un qf en una quest:
     

    quest muertes begin state start begin when kill with not npc.is_pc() begin pc.setqf("mobs", pc.getqf("mobs) + 1") chat("LLevas "..pc.getqf("mobs").." matados en tu juego") end end end Esta sencilla quest lo que hace es que cada vez que matas un mob suma un punto al qf mobs, y ademas por el chat te muestra cuantos puntos lleva ese qf:
     

    "..pc.getqf("mobs").." Para ello lo mete entre ".. .." como cuando os enseñé a mostrar el valor de un local en una quest.
     
    Por supuesto no tenemos xq mostrar el valor del qf en el mismo when ni en la misma quest que en la que le damos un valor, ya que el juego almacena para siempre el valor que tiene un qf.
     

    quest muertes begin state start begin when kill with not npc.is_pc() begin pc.setqf("mobs", pc.getqf("mobs") + 1) end when 20094.chat."Mobs" begin say("LLevas "..pc.getqf("mobs").." derrotados") end end end Y bueno eso es todo, espero que os haya sido útil este capítulo para todos aquellos que teniais dudas utilizando los pc.setqf y pc.getqf
  4. Me Gusta
    fuuton97 reacted to DryUz in Web muy hermosa   
    Descarga: Debes iniciar sesión para ver el contenido del enlace en esta publicación.
  5. Me Gusta
    fuuton97 reacted to KeKo in [Guia Definitiva] Implementar Armaduras   
    Buenas zoneros y zoneras sé que esto es mucho textos para algunos pero si teneis dudas implementando armors os recomiendo que hagais un esfuerzo y la leais entera, y si copias esta guia a otros foros por favor respetad los créditos.
     
    Después de un tiempo el foro off se me ocurrio hacer una guía útil como regalo de perdón por el tiempo que estuvo el foro indispuesto y como sé que mucha gente tiene problemas a la hora de implementar armaduras y las guías actuales no explican todo lo relativo a la implementacion de armaduras en un único post pues me voi a poner a explicaros como implementar armaduras sin morir en el intento:
     
    1 - Antes de nada: Qué es una armadura de metin2?
     
    Creo que la respuesta es muy obvia: una armadura es eso que se pone por encima del cuerpo el pj. Hasta aquí bien, pero a lo que me refiero es a que archivos forman una armadura?
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    A la hora de implementar un armor nos vamos a encontrar con dos tipos de archivos:
     
    1.1 - Los archivos gr2:
     
    Un modelo de una armadura será siempre un archivo gr2, que es el que contiene la armadura en sí
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    1.2 - Las texturas:
     
    Cada armadura tiene su propia textura, que es el archivo que permite que veamos los colores de la armadura tal y como tienen que ser. Las texturas que se utilizan en los clientes de metin2 suelen ser de estos tres formatos: .jpg .tga o .dds
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
     
    2 - Vale, ya sé que archivos necesito. Qué hago con ellos?
     
    Las armaduras se implementan por defecto en la ruta d:/ymir work/pc, que corresponde en el cliente al pc.eix y pc.epk, si son de:
     
    + Guerrero hombre
    + Sura hombre
    + Ninja mujer
    + Chamán mujer
     
    Las armaduras se implementan por defecto en la ruta d:/ymir work/pc2, que corresponde en el cliente al pc.eix y pc.epk, si son de:
     
    + Guerrera mujer
    + Sura mujer
    + Ninja hombre
    + Chamán hombre
     
    Segun la raza hay cuatro carpetas estandar:
     
    + Warrior - guerrero
    + Assasssin - ninja
    + Sura - sura
    + Shaman - chamán
     
    Por lo tanto deberemos meter nuestro modelo gr2 en la carpeta pc/pc - warrior/sura/assasin/shaman dependiendo de la raza y el sexo para el que sea.
     
    Sin embargo, las texturas de las armors que implementamos pueden no ir en la misma ruta que el modelo en sí. Para ello debemos abrir el gr2 con el granny model viewer
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Una vez hecho pincharemos donde pone texture inspection y ahi nos fijaremos en la ruta que pone donde dice texture:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    En esta imagen que os acabo de poner, al ser un armor de guerrero masculino la textura va en la carpeta d:/ymir work/pc/warrior.
     
    Sin embargo, esa ruta no es siempre la misma, ya que la gente a veces pone otras rutas:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Como veis la ruta está cambiada Pero no os preocupeis esto tiene muy fácil solucion, debemos crear en la carpeta de nuestro descompilador una carpeta con ese nombre del siguiente modo:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Una vez hecha metemos dentro la textura del armor problematica quedando la ruta en nuestro ordena de este modo:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
     
     
     
    Y cuando hagais el xml del armor tendreis que poner esa ruta:
     

    <File archivedPath="d:/ymir work/textures/minoarmorset/nombretextu.dds" type="0"><![CDATA[nombreepk_descompilado\ymir work\textures\minoarmorset\nombretextu.dds]]></File> Haciendo xmls:
     
    Doi por sentado en esta guía que ya sabeis hacer los xmls para un armor:
     

    <File archivedPath="d:/ymir work/pc/warrior/warrior_4-1.gr2" type="0"><![CDATA[PC_descompilado\ymir work\pc\warrior\warrior_4-1.gr2]]></File> Pero, si no sabeis, un xml se compone de dos partes:
     

    File archivedPath="d:/ymir work/pc/warrior/warrior_4-1.gr2" Esta es la ruta en la que el juego meterá el modelo o la textura (o cualquier otro archivo) que estemos implementando. Si ahi pone d:/ymir work/pc/warrior esa será la ruta a la que vaya el archivo llamado warrior_4-1.gr2.
     

    [CDATA[PC_descompilado\ymir work\pc\warrior\warrior_4-1.gr2]] Esta segunda parte contiene la ruta en nuestro ordenador en la que se encuentra el modelo. Lo más habitual es que la pongamos de estas maneras, dependiendo de la raza y sexo del armor:
     

    nombreepk_descompilado\ymir work\pc nombreepk_descompilado\ymir work\pc2 nombreepk_descompilado\ymir work\pc\warrior nombreepk_descompilado\ymir work\pc2\warrior Sin embargo, tanto la primera parte como la segunda pueden editarse:
     

    File archivedPath="d:/ymir work/item/kekomola/armorkeko.gr2
    [CDATA[Desktop\guia_armors\armorkeko.gr2 Como veis, la ruta en la que yo quiero meter el armor puede no ser pc o pc2 (algunas armors van en otras) y no tengo xq tener el archivo dentro de la carpeta del descompilador en una carpeta con el nombre ymir work y luego otra con el nombre pc y tal.
     
    Sin embargo, os recomiendo que lo hagais de esta manera, pa evitaros lios de: Dónde estaba el armor?
     

    [CDATA[PC_descompilado\ymir work\pc\warrior\warrior_4-1.gr2]] Y además si usais una ruta que no sea ymir work/pc o pc2 como en este caso:
     

    File archivedPath="d:/ymir work/item/kekomola/armorkeko.gr2 Luego tendreis que añadir la linea de abajo en el msm del armor, aunque eso lo explicare cuando lleguemos a los msms:
     

    SpecialPath Una vez hayais metido vuestros modelos y texturas en sus rutas correspondientes y hayas compilado los epks necesarios podemos pasar al siguiente paso:
     
    3 - La gente habla mucho de los ms... um... msalgo.... como eran?
     
    Bueno, una vez tenemos nuestra armor ya implementada llega la hora de hacerle su msm correspondiente, así que descompilemos el root.epk y busquemos estos archivos:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Hay dos para cada raza, diferenciando aquellos que llevan:
     

    _m.msm -- Para hombre _w.msm -- Para mujer Bien, como sabeis hay un armor para cada raza y sexo así que tendremos que hacerle un msm para cada uno. Para ellos abrimos cada uno de los msms y buscamos esto:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Y ahi ponemos un número alto, como 99 o más, que será el máximo de armaduras que vamos poder meter en este msm.
     
    Una vez hecho vamos a añadir nuestra armor al msm, para ello vamos hasta el final del archivo y miramos que numero tiene el ultimo armor antes de que ponga:
     

    Group AttachingData Al lado de:
     

    Group ShapeData
    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Para añadir nuestra nueva armor podemos copiar una ya anterior, como por ejemplo:
     

    Group ShapeData33 { SpecialPath "d:/ymir Work/pc/warrior/" ShapeIndex 42 Model "warriorm1002.gr2" } Y como os dije antes que miraramos el número que tenia en el ShapeData, a nuestra nueva armor le pondremos un número mas alto que ese y que no se repita a lo largo del msm:
     

    Group ShapeData34 { SpecialPath "d:/ymir Work/pc/warrior/" ShapeIndex 42 Model "warriorm1002.gr2" } Así por ejemplo serviria
     
    Una vez ya tenemos nuestras lineas, con el shapedata cambiado vamos a editarlas de la siguiente manera:
     

    Group ShapeData34 { SpecialPath "d:/ymir Work/pc/warrior/" -- esto solo se pone si la ruta no es esa, asi que podeis quitarlo si quereis ShapeIndex 43 Model "armorkeko.gr2" } Bien, vayamos paso a paso:
     

    ShapeIndex 43 *El ShapeIndex es el tan famoso numero que siempre da tantos problemas implementando armors. Pues bien, lo que hay que poner es un número que sea menor que el número que os he dicho antes que pongais:
     
    Y que no se puede repetir en ningun ShapeIndex que haya en el msm. La funcion de este numerito es enlazar el msm con el item_proto del cliente, de modo que el cliente sepa que armor estás metiendo.
     
    Y como se relacionan os estareis preguntando? Pues el numero que habeis puesto en el ShapeIndex será el que pondreis en el item_proto del cliente donde dice valu3 = numero.
     
    *Model, aqui tendreis que poner el nombre del gr2 de la armadura (con el .gr2 incluido).
     
    Y en estos momentos algun espabilado se estará preguntando: vaya pero yo suelo ver msm que tenen algo que pone SourceSkin y TargetSkin
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Bien, esa es buen ejemplo para explicaros: como explique mas arriba en esta guia cada armor tiene sus texturas, que vemos dentro del modelo y esas son las que usara el juego si simplemente ponemos el msm asi:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Sin embargo, hay muchísimos casos de armaduras a las que queremos ponerles texturas que no son las que vemos en el gr2, si no que son texturas modificadas como en el caso de las negras o empes de colores. En esos casos tenemos a nuestra disposicion estos dos elementos:
     
    * El SourceSkin siempre es la textura original del armor, es decir la que vemos en el gr2.
    * El TargetSkin siempre es la textura modificada, la que añadimos nosotros en vez de la que usaria el armor si solo leyera el gr2.
     
    Por lo tanto si tengo mi textura negra_verde.dds y quiero que las negras usen esa textura, tendre que buscar el msm de las negras:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Y deberemos añadirle el Source y Target, para ello miraremos cual es la textura de las negras (warrior_4-1.dds) y se la pondremos en el SourceSkin y luego la nuestra en el TargetSkin.
     
    Por supuesto deberemos cambiar el shapeindex porque ahora es un armor nueva, pero dejaremos el mismo model porque solo hemos cambiado la textura:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Y claro, este proceso lo repetimos con los 8 msms, por cada raza y sexo. Una vez hecho ya podemos hacerle el item_proto del cliente a nuestra armor.
     
    4 - Buf, ya hice los msm, queda mucho?
     
    4.1: Item_proto del cliente
     
    Tranquilos que ya casi se acaba. Como os he comentado antes hablando del shapeindex:
     
    Por lo tanto, si nuestra armor NO tiene item_proto del cliente NO se verá así que vamos a ver donde ponemos el shapeindex:
     

    <Item vnum="11690" name="È渶°©+0" gb2312name="Arm. Placas Mágica +0" type="2" subtype="0" weight="0" size="2" antiflag="44" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="120000" limittype0="1" limitvalue0="66" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967281" applytype1="37" applyvalue1="2" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="0" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11691" refine_set="181" magic_pct="15" specular="0" socket_pct="3" /> <Item vnum="11691" name="È渶°©+1" gb2312name="Arm. Placas Mágica +1" type="2" subtype="0" weight="0" size="2" antiflag="44" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="130000" limittype0="1" limitvalue0="66" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967282" applytype1="37" applyvalue1="3" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="3" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11692" refine_set="182" magic_pct="15" specular="0" socket_pct="3" /> <Item vnum="11692" name="È渶°©+2" gb2312name="Arm. Placas Mágica +2" type="2" subtype="0" weight="0" size="2" antiflag="44" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="145000" limittype0="1" limitvalue0="66" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967283" applytype1="37" applyvalue1="4" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="6" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11693" refine_set="183" magic_pct="15" specular="0" socket_pct="3" /> <Item vnum="11693" name="È渶°©+3" gb2312name="Arm. Placas Mágica +3" type="2" subtype="0" weight="0" size="2" antiflag="44" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="165000" limittype0="1" limitvalue0="67" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967284" applytype1="37" applyvalue1="5" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="9" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11694" refine_set="184" magic_pct="15" specular="0" socket_pct="3" /> <Item vnum="11694" name="È渶°©+4" gb2312name="Arm. Placas Mágica +4" type="2" subtype="0" weight="0" size="2" antiflag="300" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="190000" limittype0="1" limitvalue0="67" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967285" applytype1="37" applyvalue1="6" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="12" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11695" refine_set="185" magic_pct="15" specular="30" socket_pct="3" /> <Item vnum="11695" name="È渶°©+5" gb2312name="Arm. Placas Mágica +5" type="2" subtype="0" weight="0" size="2" antiflag="300" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="220000" limittype0="1" limitvalue0="68" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967286" applytype1="37" applyvalue1="7" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="15" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11696" refine_set="186" magic_pct="15" specular="40" socket_pct="3" /> <Item vnum="11696" name="È渶°©+6" gb2312name="Arm. Placas Mágica +6" type="2" subtype="0" weight="0" size="2" antiflag="300" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="265000" limittype0="1" limitvalue0="68" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967287" applytype1="37" applyvalue1="9" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="18" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11697" refine_set="187" magic_pct="15" specular="50" socket_pct="3" /> <Item vnum="11697" name="È渶°©+7" gb2312name="Arm. Placas Mágica +7" type="2" subtype="0" weight="0" size="2" antiflag="300" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="325000" limittype0="1" limitvalue0="69" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967288" applytype1="37" applyvalue1="12" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="21" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11698" refine_set="188" magic_pct="15" specular="65" socket_pct="3" /> <Item vnum="11698" name="È渶°©+8" gb2312name="Arm. Placas Mágica +8" type="2" subtype="0" weight="0" size="2" antiflag="300" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="405000" limittype0="1" limitvalue0="69" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967289" applytype1="37" applyvalue1="15" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="24" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="11699" refine_set="189" magic_pct="15" specular="80" socket_pct="3" /> <Item vnum="11699" name="È渶°©+9" gb2312name="Arm. Placas Mágica +9" type="2" subtype="0" weight="0" size="2" antiflag="300" flag="1" wearflag="1" immuneflag="0" gold="120000" buy_price="515000" limittype0="1" limitvalue0="70" limittype1="0" limitvalue1="0" applytype0="8" applyvalue0="4294967290" applytype1="37" applyvalue1="20" applytype2="0" applyvalue2="0" value0="0" value1="90" value2="0" value3="12" value4="0" value5="27" socket0="0" socket1="0" socket2="0" socket3="0" socket4="0" socket5="0" refine_vnum="12030" refine_set="530" magic_pct="15" specular="100" socket_pct="3" /> El item_proto de nuestra armor suele tener de +0 a +9 (aunque no tiene por que ser así), y en el queria remarcar los siguientes datos:
     

    Item vnum="11690" Ahi pondremos la id que vamos a ponerle al item.
     

    gb2312name="Arm. Placas Mágica +0" Ahi se pone el nombre que el armor tendrá en el juego.
     

    value3="12" Y ahi esta el famoso value3!! Le pondremos en cada una de las ids del armor (es decir de +0 a +9) el numero que pusimos en el shapeindex.
     
    Y ya estaría esta parte, por supuesto cada uno deberá hacer el item_proto con los valores que veas convenientes, para eso hay bastantes herramientas como creadores de querys e item_proto que os ayudaran a hacerlo.
     
    4.2: Icono del armor:
     
    Como a la gente le suele gustar que las armors tenga su iconito os diré como meterlo (partiendo de que ya teneis uno hecho, hay guias para hacerlos si no lo teneis):
     
    4.2.1: El icono:
     
    Descompilamos nuestro icon.epk, metemos el icono en icon/item y luego lo añadimos al xml y compilamos. Por supuesto para los que haceis esto en epks aparte recordad que la linea del xml debe llevar icon/item/idicono.tga en la primera parte del xml (lo que explique antes)
     
    4.2.2: Item_list:
     
    Descompilamos nuestro locale y vamos al archivo item_list. De ahi cojemos las lineas de +0 a +9 de otra armor cualquier y las editamos de la siguiente manera:
     

    idarmor ARMOR icon/item/idicono.tga Ojo! Las separaciones entre el texto deben ser con la tecla de tabulador (esa que esta encima del bloq mayusculas xd)
     
    4.3: La query del armor
     
    Una vez hecho todo esto, simplemente nos quedará hacer una query para nuestra armor con la misma id que le pusimos en el item_proto del cliente, para ello teneis muchos programas que os ayudarán a hacerla con los valores que prefirais
     
    Recordad que en la query el value3 da igual, por si alguno lo duda xd
     
    Y bueno, eso es todo por hoy espero que os sea útil esta guía
  6. Me Gusta
    fuuton97 reacted to KeKo in [Recopilacion] Mis quests en Metin2Zone   
    Buenas zoneros, a peticion de un usuario hace un par de dias haré una recopilacion de todas mis quests para metin2zone por si estais buscando alguna dellas y no la dais encontrado
     
    Recopilacion de Quests:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
     
     
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Ire actualizando con quests que tengo hecho en las secciones de peticion y correcion de quests
     
    Y eso seria todo, espero que os sirvan
  7. Me Gusta
    fuuton97 reacted to Serex in Instalar webiste en FreeBSD - Apache + PHP   
    Hola chicos, os voy a explicar como colocar vuestro sitio web en vuestro dedicado instalado apache y php.

    Primero comenzaremos con la instalación de apache:

    1- Nos dirigimos a la ruta de apache e instalamos el modulo.


    cd /usr/ports/www/apache22 make install clean
    2- Agregamos el modulo apache en nuestro archivo de configuración.


    ee /etc/rc.conf
    Y agregamos la siguiente lí­nea al final del archivo:


    apache22_enable="YES"

    Listo ya tenemos apache instalado, ahora procedemos a la instalación de php.

    1- Nos dirigimos hasta la ruta del modulo php.


    cd /usr/ports/lang/php5
    2- Configuramos el módulo con el siguiente comando, y marcamos con la X la extensión para apache, después pulsamos OK.


    make config
    3- Ahora procedemos a instalarlo:


    make install clean
    **Si tenemos, y solo si tenemos el siguiente error en este paso:

    pkgconf-0.8.5 conflicts with installed package(s): pkg-config-0.25_1[/color] [color=#ffa07a] They install files into the same place. You may want to stop build with Ctrl + C.
    Debemos ejecutar este comando, y volver a hacer el paso 3:


    pkg_delete -f pkg-config-0.25_1
    **Repito esto solo lo hacemos si nos da ese error, sino continuamos con el paso 4.

    4 - Instalamos las extensiones para php.


    cd /usr/ports/lang/php5-extensions make config
    5 - Seleccionamos con una X la extensión para MYSQL pulsamos OK y continuamos con el siguiente comando:



    make install clean
    Una vez instalados php y apache pasamos a la configuración de estos para ponerlos en funcionamiento:

    1 - Nos dirigimos a la siguiente ruta y creamos el archivo:


    ee /usr/local/etc/apache22/Includes/php.conf
    2 - Introducimos este texto en el archivo y guardamos:


    <IfModule mime_module> <IfModule php4_module> AddType application/x-httpd-php .php </IfModule> <IfModule php5_module> AddType application/x-httpd-php .php </IfModule> </IfModule>
    3 - Nos dirigimos a la siguiente ruta:


    ee /usr/local/etc/apache22/httpd.conf
    Una vez en este archivo buscamos las siguientes líneas:


    <IfModule dir_module> DirectoryIndex index.html </IfModule>
    Y las reemplazamos por estas:


    <IfModule dir_module> <IfModule php5_module> DirectoryIndex index.php index.html </IfModule> <IfModule !php5_module> <IfModule php4_module> DirectoryIndex index.php index.html </IfModule> <IfModule !php4_module> DirectoryIndex index.html </IfModule> </IfModule> </IfModule>
    Guardamos el archivo y listo.

    5 - Reiniciamos el servidor e iniciamos el módulo apache:


    /usr/local/etc/rc.d/apache22 start shutdown -r now
    Ahora ya tenemos instalado y listo nuestro sitio web en el dedicado, podremos subir los archivos de nuestra web en la siguiente ruta:


    /usr/local/www/apache22/data
    Y ahora os explicare que ventajas y desventajas tiene instalar nuestro sitio web en nuestro dedicado.

    Ventajas:
    -No pagas hosting.
    -La conexion entre base de datos y web es muchísimo mas rápida que con un hosting normal.
    -La velocidad de carga de la web mejora considerablemente.
    -Tienes mayor transferencia y ancho de banda.

    Desventajas:
    -Consumes mas recursos en el dedicado (Si tienes un dedicado con mas de 3 gb de ram apenas se nota)
    -Si se cae el servidor se cae la web.
  8. Me Gusta
    fuuton97 got a reaction from stein20 in [TIP]Arreglar error de Flush Hosts (SERVER-WEB).   
    Hola, hoy les vengo a dar un TIP de como arreglar el error de FLUSH HOTS, este es presentado en la web como un error del servidor de las máximas conexiones que hallan en cierto servidor.
     
    Hay miles maneras de arreglar este problema, pero hay una con la que podrán arreglarla en su totalidad, si quieren hacer por el tipo de aumentar los errores de conexiones y permitirlas, lo pueden hacer, pero no les prometo nada puesto que estas conexiones de errores son echas por intento de saturar la web al servidor y caiga la web en su error.
     
    El error que les saldr­a a futuras es este (claro, si no les ha salido todaví­a):

    Host 'ejemplo' is blocked because of many connection errors; unblock with 'mysqladmin flush-hosts' in /home/tuweb/public_html/index.php En el mismo error les sale la solución, hacer un flushs de hosts. La variable que controla el número máximo de errores de conexión que puede causar un cliente es max_connect_errors. Un host puede conectar normalmente siempre que lo haga con menos errores consecutivos que el valor de dicha variable. Pero si un host llega a este valor queda bloqueado hasta que se desbloquee con FLUSH HOSTS;.
     
     
    Las variables relacionadas con errores en la conexión cliente son:
     
    Aborted_clients: Clientes que cierran la conexión incorrectamente (pero se han conectado bien)
    Aborted_connects: Errores de conexión al MySQL totales
     
     
    Ahora para poder ver las variables mediante SHOW STATUS SEGUIRáN ESTE PASO:
     
    -Entramos al Putty de tu servidor.
    - Hacemos el comando siguiente:
    # mysql -p
    (introducen su password de mysql)
    # mysql> show status like '%abo%';
     
    Verán que les saldrá algo parecido a esto:
     
     

    +------------------+-------+ | Variable_name | Value | +------------------+-------+ | Aborted_clients | 2071 | | Aborted_connects | 13748 | +------------------+-------+ 2 rows in set (0.00 sec) luego dan con este comando:
     
    mysql> quit
     
    Ahora procedemos con este comando: Este comando es por telnet, telnet es como otra máquina virutal remota.
     
    # telnet systemadmin.es 3306
     
    Una ves hecho esto usamos el mismo comando para ver que si aumentaron las conexiones de los clientes.
     
    Bien, ahora como lo decia hagamos el comando de FLUSH HOSTS.
     
    mysql> mysql -p
    mysql> flush hosts;
    mysql> quit
     
    Y listo, verán que su web funciona 100%, si les sigue dando el error al pasar horas hagan el mismo paso al aumentar las conexiones del cliente.
     
    Si quieren la guÃía por el método de aumentar las conexiones de los clientes, díganmelos que se las hago.
     
    Esta guía está hecho por mi, fue recopilación de tanto buscar y buscar.
  9. Me Gusta
    fuuton97 got a reaction from Noob6969 in Seguridad Básica para Consola FreeBSD.   
    Buenas, hace rato sin entrar por este forillo, y ver las nuevas secciones me decidí a postear una seguridad básica de FreeBSD para cualquier versión existente, coste decir que es un manual de FreeBSD escrita por David Barbero.
     
    Todas las funciones las he probado en un dedicado de prueba y funcionan.
     
     
    Seguridad en el sistema de Ficheros
     
    El sistema de ficheros que monta FreeBSD es UFS 4.2BSD compatible con todos los BSD. Dentro de el UFS de Freebsd hay dos tipos:
     
    El primero es UFS, lo usa las ramas anteriores a 4.x (4.x incluida) y tiene la seguridad de siempre sin mejoras y soporta quotas.
     
    El Segundo es UFS2, se usa apartir de la rama 5,x y tiene mejoras significativas en seguridad. Sus más significativas son Mandatory Access Control (MAC), File System Access Control List, snapshots y quotas.
     
    No comentare más sobre los tipos de sistemas de ficheros, pero si haré unas recomendaciones para mejorar la seguridad desde el sistema de ficheros.
     
    Hay que considerar que el usuario root debemos usarlo SOLO y EXCLUSIVAMENTE para fines de administración, por lo cual usaremos los usuarios normales. Teniendo esto en cuenta, es de lógica que separemos la partición /home de su posicion original (/usr/home). Con esto también evitamos en parte de fragmentación ya que nuestra partición /usr no tendrá que ser tan grande.
     
    Tambien pondremos los flags NOSUID y NODEV a las particiones /tmp y /usr/home, asi nos aseguraremos que nadie podra usar programas potencialmente peligrosos en esas particiones.
     
    NOSUID No permite la Ejecución de programas con el bit suid, es decir, que se ejecutan como root y son potencialmente peligrosos para el sistema.
     
    NODEV no permite la creación de dispositivos de sistema en esa partición librandonos así de la posible instalación de programas potencialmente peligrosos para el sistema.
     
    Para Configurar esto es necesario mofificar el fichero /etc/fstab e incluir NODUID y NODEV en la sección Options quedando de una forma parecida a esto:
     
    # Device Mountpoint FStype Options Dump Pass#
    /dev/ad0s1b none swap sw 0 0
    /dev/ad0s1a / ufs rw 1 1
    /dev/ad0s1e /tmp ufs rw,noatime,nosuid,nodev 2 2
    /dev/ad0s1g /usr ufs rw,noatime 2 2
    /dev/ad0s1h /usr/home ufs rw,noatime,nosuid,nodev 2 2
    /dev/ad0s1f /var ufs rw,noatime 2 2
    /dev/ad2s1h /data ufs rw,noatime 2 2
    /dev/acd0c /cdrom cd9660 ro,noauto 0 0
    /dev/acd1c /cdrom1 cd9660 ro,noauto 0 0
    proc /proc procfs rw 0 0
    Una vez montado el sistema de ficheros si ejecutamos la orden mount veremos que efectivamente están las opciones que queriamos:
     
    hellen#mount
    /dev/ad0s1a on / (ufs, local)
    /dev/ad0s1e on /tmp (ufs, local, noatime, nosuid, nodev, soft-updates)
    /dev/ad0s1g on /usr (ufs, local, noatime, soft-updates)
    /dev/ad0s1h on /usr/home (ufs, local, noatime, nosuid, nodev, soft-updates)
    /dev/ad0s1f on /var (ufs, local, noatime, soft-updates)
    /dev/ad2s1h on /data (ufs, local, noatime, soft-updates)
    procfs on /proc (procfs, local)
    Para más información consultar fstab(5), fsck(8), mount(8), umount(8)
     
    Seguridad en las contraseñas
     
    Empezaremos aplicando una buena política de contraseñas, para lo cual debemos pensar cual será el máximo tiempo que un usuario estará con la misma contraseñ y de cuantos caracteres será como mínimo.
     
    Yo he decidido usar un mínimo de 8 caracteres para las contraseñas y un máximo de 30 días por contraseña. Tambien he decidido cambiar el sistema de cifrado de las contraseñas, que por defecto es md5, por uno más seguro, Blowfish.
     
    Para configurar estas opciones necesitamos que editar el archivo /etc/login.conf
     
    hellen# vi /etc/login.conf
    Para cambiar el cifrado tenemos que buscar la línea
     
    default:
    :passwd_format=md5:
    Una vez modificada quedaría de la siguiente forma:
     
    default:
    :passwd_format=blf:
    Con este cambio ya tendriamos configurado el sistema de cifrado usando Blowfish.
     
    Ahora vamos a cambiar la longitud mínima de caracteres para cada contraseña y hacer que cada usuario cambie su contraseña cada 30 días, Para ello pondremos lo siguiente al final de el apartado default:
     
    :umask=022:
    :minpasswordlen=8:
    :passwordtime=30d:
    Con esto lo que estamos haciendo es obligar a que la contraseña tenga un mínimo de 8 caracteres y que sea obligarorio cambiarla antes de 30 días. Esto influye en todos los usuarios del sistema, pero nosotros queremos que el usuario root tenga un minimo de 11 caracteres, por lo cual nos vamos a la sección root: y hacemos que quede de la siguiente forma:
     
    root:
    :ignorenologin:
    :minpasswordlen=11:
    :tc=default:
    Con esto hemos forzado que la contraseña de root tenga un mínimo de 11 caracteres.
     
    Una vez realizados estos cambios, tenemos que decirle al sistema que rehaga la base de datos del sistema de contraseñas, esto lo hacemos con la orden cap_mkdb de la siguiente manera:
     
    hellen# cap_mkdb /etc/login.conf
    Una vez ejecutado el comando para actualizar el sistema de contraseñas solo nos quedaría cambiar la contraseña para que el sistema la cifre con Blowfish, procedemos a ello:
     
    login: sico
    Password:
     
    passwd
    Changing local password for sico.
    Old password:
    New password:
    Please enter a password at least 8 characters in length.
    New password:
    Retype new password:
    passwd: updating the database...
    passwd: done
    Ya hemos visto que funciona correctamente, ahora solo nos queda con el usuario root, precedemos a ello:
     
    su
    Password:
     
    passwd root
    Changing local password for root.
    New password:
    Please enter a password at least 11 characters in length.
    New password:
    Retype new password:
    passwd: updating the database...
    passwd: done
    Un último cambio más, nos queda modificar un archivo para que cuando demos de alta un nuevo usuario en el sistema la contraseña se cibre con Blowfish, este achivo es /etc/auth.conf y en el hay que buscar la línea
     
    # crypt_default = md5 des
    y sustituirla por:
     
    crypt_default = blf
    Seguridad en el servidor ssh
     
    El Servidor SSH se instala por defecto con una configuración no demasiado propicia para la seguridad, hay que decir que es buena, pero se puede mejorar.
     
    Lo primero que tenemos que hacer es configurar el servidor SSH para que solo acepte conexiones por el protocolo 2 que es bastante más seguro que el protocolo 1, para lo cual modificaremos el archivo /etc/ssh/sshd_config
     
    hellen#vi /etc/ssh/sshd_config
    En el cual buscamos las siguiente línas:
     
    #Port 22
    #Protocol 1 2
    #ListenAddress 0.0.0.0
    #Banner /some/path
    Y las sustituimos por:
     
    Port 22
    Protocol 2
    ListenAddress 192.168.10.1
    Banner /etc/ssh/banner
    La explicación de estos cambios son muy sencillos:
     
    Port nos indica el puerto por el cual los clientes se van a conectar.
     
    Protocol nos indica el protocolo que vamos a usar, nosotros elegimos el protocolo 2 por que es mucho más seguro.
     
    ListenAddress indica la ip de la tarjeta de red por la que queremos que escuche, 192.168.10.1 es un ejemplo que habría que sustituir por la vuestra IP.
     
    Banner que realmente no es una opción de seguridad, pero si lo es de advertencia, cuando el cliente se conecta al servidor, este pondra el banner antes de poder loguearse en nuestro FreeBSD.
     
    Como seguramente /etc/ssh/banner no exista lo tendremos que crear, este es el contenido que tengo yo:
     
    hellen# cat /etc/ssh/banner
    ************************************************************************
     
    This is a private system!!! All connection attempts are logged and
    monitored. All unauthorized connection attempts will be investigated and
    handed over to the proper authorities.
     
    ************************************************************************
    hellen#
    Una vez que ya teneis el banner ya tenemos casi configurado el servidor ssh, solo nos faltaría decidir que usuarios pueden conectar por SSH a nuestra máquina. Dentro de esta situación tenemos dos posibilidades, Filtrar por la IP del cliente, o filtrar por Usuario, La primera Opción muchas veces no es posible ya que tenemos que tener un firewall instalado en la máquina y ademas de esto, muchos clientes utilizan conexiones por rtb (Modem Analógico en Línea analógica) en las cuales no disponen de IP fija y cada conexión tienen una diferente, asi que vamos a filtrar por Usuarios.
     
    La opción para filtrar por usuarios es muy fácil, es AllowUsers y tambien hay que ponerla dentro de /etc/ssh/sshd_config
     
    Una vez decididos que usuarios van a poder conectar, vamos a configurarlo
     
    hellen# echo AllowUsers [email protected] syvic toni >> /etc/ssh/sshd_config
    hellen# cat /etc/ssh/sshd_config
    Port 22
    Protocol 2
    ListenAddress 192.168.10.1
    ...
    ...
    # override default of no subsystems
    Subsystem sftp /usr/libexec/sftp-server
     
    AllowUsers [email protected] syvic toni
    hellen#
    Como veis he añadido a tres usuarios, el primero a sico que ademas le he dicho desde que IP puede conectar, es decir, sico podria conectar desde 192.168.10.2 y despues he puesto a los usuarios syvic y toni que pueden conectar desde cualquier lugar.
     
    Seguridad en Consola
     
    La seguridad en Consola es bastante importante puesto que álguien podría arrancar nuestra máquina en modo mono-usuario y trastear en ella con privilegios de root, o simplemente podriamos dejar una consola con una sesión iniciada, ausentarnos y álguien podría usar nuestra sesión para hacer algo que a nadie nos gustase.
     
    Primero vamos a configurar el sistema para que si arranca en modo mono-usuario nos pida las contraseña de root para poder usar la máaquina. Para ello tenemos que editar el archivo /etc/ttys y localizar la línea que pone:
     
    console none unknown off secure
    Esta línea tenemos que modificarla dejandola de la siguiente manera.
     
    console none unknown off insecure
    De esta manera nadie que no posea la contraseña de root podra iniciar sesión si arranca la máquina en modo mono-usuario.
     
    Una vez que tenemos el modo mono-usuario vamos a explicar como bloquear una consola por si nos tenemos que ausentar de la máquina y no podemos cerrar la sesión.
     
    Para bloquear la sesión disponemos de una orden del propio sistema, esta orden se llama lock y bloquea la consola en la que estemos trabajando, por defecto la bloquea durante 15 minutos, pero podemos indicarle que este más tiempo ejecutando lock -n, otra peculiaridad que tiene esta orden es que te pide que pongas una contraseña que no tiene nada que ver con la del sistema, pero si prefieres usar la contraseña sistema puedes ejecutar el comando lock -p
     
    hellen# lock
    Key:
    Again:
    lock: /dev/ttyp0 root timeout in 15 minutes
    time now is Thu Jan 30 03:00:34 CET 2003
    Key:
    Aunque yo personalmente prefiero usar vlock que aunque no se encuentra en la base del sistema está en los ports y su uso es muy fácil.
     
    hellen# cd /usr/ports/security/vlock && make install clean
    Una vez instalado su funcionamiento es muy fácil, simplemente se ejecuta vlock y tenemos bloqueada la consola en la que nos encontremos, tambien se puede usar vlock -a y bloqueariamos todas las consolas.
     
    hellen# vlock -a
    The entire console display is now completely locked.
    You will not be able to switch to another virtual console.
    Please enter the password to unlock.
    root's password:
    Esto es todo en la sección sobre Consolas.
     
    Cerrando Puertos
     
    Lo primero que tenemos que saber es que cuando instalamos el sistema por defecto solemos arrancar servicios que realmente no usamos, por lo cual vamos a ir localizando y cerrando estos servicios que mas de una vez pueden comprometer nuestro sistema.
     
    Vamos a empezar usando la orden sockstat -4 el cual nos va a decir que puertos tenemos abiertos.
     
    hellen# sockstat -4
    USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
    root sshd 873 3 tcp4 *:22 *:*
    root inetd 92 4 tcp4 *:21 *:*
    root syslogd 77 4 udp4 *:514 *:*
    root X_SERV 234 4 tcp4 *:6000 *:*
    root sendmail 92 4 tcp4 *:25 *:*
    root submission 245 4 tcp4 *:587 *:*
     
    hellen#
    Como veis hay ciertos puertos que están abiertos y que realmente no voy a usar nunca, es el caso del 587 (Submission), el 25 (SMTP) puesto que yo no tengo en esta máquina un servidor de correo, el 6000 tampoco lo vamos a usar puesto que sirve para conexiones remotas a un servidor X-window, el 21 que es el puerto del ftp tampoco voy a usarlos, asi que vamos a ir cerrando puertos y asegurando el sistema.
     
    Lo que vamos a cerrar primero es el puerto 6000 ya que nosotros no vamos a servir entorno grafico a nadie, para esto necesitamos editar el archivo /usr/X11R6/bin/startx Y lo calizar la linea
     
    serverargs=""
    Modificarla hasta que quede de la siguiente forma:
     
    serverargs="-nolisten tcp"
    Con esto ya tenemos un puerto menos abierto, ahora vamos a cerrar el 587 (Submission), este puerto no se necesita para mandar ni recibir correo, pero pertenece al sendmail, para cerrarlo necesitamos editar el archivo /etc/mail/sendmail.cf y buscar la línea
     
    O DaemonPortOptions=Port=587, Name=MSA, M=E
    Es ta línea hay que comentarla para que sendmail no la cargue por defecto.
     
    #O DaemonPortOptions=Port=587, Name=MSA, M=E
    Ahora vamos a cerrar el puerto 25 ya que por norma general los correos nos los descargamos desde otro servidor y no los recibe directamente mi máquina, por lo cual voy a hacer que no arranque sendmail.
     
    Para esto necesitamos editar el archivo /etc/rc.conf y añadir la siguiente línea dependiendo de la versión de nuestro FreeBSD.
     
    Si tenemos una versión de FreeBSD inferior a una 4.6-RELEASE:
     
    sendmail_enable="NO"
    Si es superior o Igual a 4.6-RELEASE:
     
    sendmail_enable="NONE"
    En mi ejemplo no ha salido el puerto 111 (sunrpc) pero es muy habitual que este puerto salga, para eliminar este puerto tenemos que seguir editando /etc/rc.conf y poner dentro
     
    nfs_server_enable="NO"
    nfs_client_enable="NO"
    portmap_enable="NO"
    otro puerto de los que tenemos abierto es el 514 que pertenece al syslogd y esta a la espera de poder brindar la oportunidad de logear remotamente, como realmente lo que nos interesa es que registre lo que ocurre en nuestra máquina, vamos a poner lo siguiente en /etc/rc.conf
     
    syslogd_enable="YES"
    syslogd_flags="-ss"
    Luego por último teniamos abierto el puerto 21 que corresponde al servidor ftp, el cual en esta máquina no me va a servir de nada, por lo cual lo voy a cerrar, como se ve en la salida de sockstat -4 estaba ejecutandose desde el inetd, asi que vamos a cortar el inetd para que no arranque el ftp y otros servicios que no nos interesan, para ello ponemos lo siguiente en /etc/rc.conf
     
    inetd_enable="NO"
    Ahora despues de esto solo nos queda pasar el sistema a monopuesto y volverlo a multipuesto para que recargue las variables modificadas, otra solución es reiniciar la máquina, yo prefiero pasar a monopusuario:
     
    shutdown now
    Una vez que ya hemos pasado a multiusuario ejecutamos sockstat -4 y comprobamos que esta a nuestro gusto.
     
    hellen# sockstat -4
    USER COMMAND PID FD PROTO LOCAL ADDRESS FOREIGN ADDRESS
    root sshd 873 3 tcp4 *:22 *:*
     
    hellen#
    Otra sección acabada ;o)
     
    Seguridad con los usuarios
     
    Una vez llegado a este punto lo siguiente que haremos es activar el acconuting para tener un cierto control sobre los usuarios, para hacer esto tenemos que editar el archivo /etc/rc.conf y añadirle la siguiente línea:
     
    accounting_enable="YES"
    Para ver las opciones que tiene la opción de accouting te aconsejo ver el manual de sa y de lastcomm
     
    hellen# man sa
    hellen# man lastcomm
    En el sistema existe un usuario llamado toor que tiene privilegios de root, este usuario nunca se usa, por lo cual vamos a eliminarlo para dejar el sistema lo más limpio posible.
     
    hellen# vipw
    # $FreeBSD: src/etc/master.passwd,v 1.25.2.6 2002/06/30 17:57:17 des Exp $
    #
    root:$2a$04$i/o8gD2EdrL8BVw2VXumpuXxXxXxXxXxu0xijdQPPewnWDM2bjr2m:0:0::0:0:Charlie &:/root:/bin/csh
    toor:*:0:0::0:0:Bourne-again Superuser:/root:
    daemon:*:1:1::0:0:Owner of many system processes:/root:/sbin/nologin
    Como vemos el usuario toor existe, lo borramos, y ya que estamos vamos tambien a cambiar el nombre del root que por defecto está puesto en Charlie &, para ello dejamos la configuración de la siguiente manera:
     
    # $FreeBSD: src/etc/master.passwd,v 1.25.2.6 2002/06/30 17:57:17 des Exp $
    #
    root:$2a$04$i/o8gD2EdrL8BVw2VXumpuXxXxXxXxXxdQPPewnWDM2bjr2m:0:0::0:0:Sico:/root:/bin/csh
    daemon:*:1:1::0:0:Owner of many system processes:/root:/sbin/nologin
    Yo en el nombre de root he puesto sico, pero lo podeis sustituir por vuestro nombre o lo que querais.
     
    Ahora vamos a decidir que usuarios pueden hacerse root usando la orden su, estos usuarios para poder usar dicha orden deben estar dentro del grupo wheel, si no lo están no podran hacerse root.
     
    hellen# vi /etc/group
    # $FreeBSD: src/etc/group,v 1.19.2.3 2002/06/30 17:57:17 des Exp $
    #
    wheel:*:0:root
    daemon:*:1:daemon
    Como vemos ahora mismo solo está root dentro del grupo, si intentamos hacernos root desde un usuario nos dirá lo siguiente:
     
    %su
    su: you are not in the correct group (wheel) to su root.
    %
    Para permitir que nos deje hacernos root debemos dejar la línea de la siguiente manera:
     
    # $FreeBSD: src/etc/group,v 1.19.2.3 2002/06/30 17:57:17 des Exp $
    #
    wheel:*:0:root,sico
    daemon:*:1:daemon
    Yo he decidido que el usuario sico se va a poder hacerse root, guardamos los cambios y comprobamos que funciona:
     
    hellen:~> su -
    Password:
    hellen#
    Una ultima opción para controlar que ningún usuario mal intencionado pueda dejar algun programa en los directorios temporales es aconsejable poner en /etc/rc.conf la siguiente línea:
     
    clear_tmp_enable="YES"
    Bueno, Pues esto es todo, aun se podrian introducir un par de cosas más para mejorar la seguridad, pero las dejare para la futura actualización de este documento.
     
    Saludos, cualquier duda hacerla saber.
     
    PD: Es copiada del Manual Original de FreeBSD.
  10. Me Gusta
    fuuton97 got a reaction from APRENDIZ in Php Code: Poner Música en tu Web.   
    Buenas.
     
    Tanto tiempo sin aportar nada a Metin2 Zone, pues bien hoy me dedicaré a postear cosas en cada sección si es posible, hoy comienzo con un Php code de poner música a tu web, este va a un directorio donde tienes la música (.mp3) y la lee al inicio de tu web, este solo tiene para una selección alterna de una solo nota de música.
     
    Donde dice ''radio/Gangnam Style.mp3'', es la dirección donde está la canción.
     
    Espero que les sirva, saludos.
  11. Me Gusta
    fuuton97 reacted to Serex in [Quest] Ranking in-game   
    Bueno chicos hoy os traigo una sencilla quest para que podais ver hasta el top 15 en el juego clickando solo a 1 npc.
     

    quest raking begin state start begin when 20095.chat."Ranking" begin local rangliste = mysql_query("SELECT * FROM player.player WHERE player.name NOT LIKE '[%]%' ORDER BY player.level DESC, player.exp DESC","root","rootpw","player","rootip") say_title("Top 15") say("#: Nombre Nivel ") say("Top 1: "..rangliste.name[1].." "..rangliste.level[1].." ") say("Top 2: "..rangliste.name[2].." "..rangliste.level[2].." ") say("Top 3: "..rangliste.name[3].." "..rangliste.level[3].." ") say("Top 4: "..rangliste.name[4].." "..rangliste.level[4].." ") say("Top 5: "..rangliste.name[5].." "..rangliste.level[5].." ") say("Top 6: "..rangliste.name[6].." "..rangliste.level[6].." ") say("Top 7: "..rangliste.name[7].." "..rangliste.level[7].." ") say("Top 8: "..rangliste.name[8].." "..rangliste.level[8].." ") say("Top 9: "..rangliste.name[9].." "..rangliste.level[9].." ") say("Top 10: "..rangliste.name[10].." "..rangliste.level[10].." ") say("Top 11: "..rangliste.name[11].." "..rangliste.level[11].." ") say("Top 12: "..rangliste.name[12].." "..rangliste.level[12].." ") say("Top 13: "..rangliste.name[13].." "..rangliste.level[13].." ") say("Top 14: "..rangliste.name[14].." "..rangliste.level[14].." ") say("Top 15: "..rangliste.name[15].." "..rangliste.level[15].." ") local s = select("Salir") elseif s == 1 then return end end end
  12. Me Gusta
    fuuton97 got a reaction from caanmasu in [GUIA]Como crear archivos Server_Attr para su Mapa.   
    Buenas gentes de Metin2 Zone, hoy les vengo a hacer esta pequeña guía donde les mostraré como crear su propio server_attr, que es aquel que debe ir en la parte del servidor vía FTP, los que han posteado mapa se han dado cuenta que no viene la cierta parte del mapa que es la de server_attr, esta guía no esta en EPVP, solo el programa que lo postearon, y yo se los vengo a explicar con detalles y lujos. Algunas personas lo que hacen es coger otro server_Attr de otro mapa, pero al meterlo les dará ciertos bug's lo cual es muy molesto, sigan al pie de al letra.
     
    *Programas a Utilizar:
    - SAttr_Tool_v1.
     
    Luego de haber descargado el programa nos dirigimos a descomprimirlo, y seguidamente a abrirlo, verán algo así:

     
    Ahora vamos a la carpeta de ''example_map'', la abren y verán que hay ciertos archivos como estos:

     
     
    Ahora procedemos a borrar todo el contenido de la carpeta dentro, de ''example_map''.
     
    Una vez ya borrado buscamos nuestro mapa, solo la parte del cliente, en este casi sería este: map_limbo, sacado de los de Next.

     
     
    Lo que haremos ahora será copiar los archivos del mapa seleccionado, en este caso el ''map_limbo'', coger sus archivos y pegarlo en la carpeta ''example_map''.
     
    Ya hecho esto procedemos abrir el .xml llamado ''example_map.xml'', verán algo así:

     
    Ahora editamos el ''x="2" y="2", cómo verán el para crear el server_attr solo sirve para mapas hasta 9x9, en este caso mi mapa es de 1x1, cómo mirarlo?, fácil abren el setting.txt y se van en MapSize, y hay se darán cuenta, una ves cambiar el intervalo X y Y, les quedará así:

     
     
    Una ves ya cambiado, procedemos a guardar, OJO: No cambien más nada.
     
    Ahora vamos a la raíz de al carpeta del SAttr_Tool_Release_V1, y cogemos el: ''example_map'' y lo arrastramos al SAttr.exe, les saldrá algo así:

     
     
    Cómo verán les puede que salga este error, que quiere decir este error?, pues que no se encuentra en la ruta que es, entonces lo que tienen que hacer es coger la carpeta, solo la carpeta, ''example_map'' y llevarla al directorio que dice, en este caso sería: C:/ Documents And Senttings/Jaller/example_map/00000/attr.atr' . Cogen su carpeta de example_map y la llevan a esa ruta que les dice, OJO: si no les dice ese error entonces es por que ya pueden hacerlo, y/o omiten este paso.
     
    Ya una vez hecho lo de arriba nos saldrá así, ya arrastrando en example_map.xml al SAttr.exe.

     
     
    Cuando aparezca esto solo dan la tecla enter y listo.
     
    Ahora vamos a la carpeta donde la pusimos para el paso anterior, en mi caso fue este: C:/ Documents And Senttings/Jaller/example_map y vemos si se creo el server_attr, deberá salirle:

     
    Como verán ya se crearon, y se creo el: server_attr.bmp, que es lo que te muestra el mapa, osea todo en cámara hacia arriba:

     
     
    Y listo ya tienen su server_attr creado, solo falta crear la carpeta del mapa para la parte del server, meter elserver_attr y listo ya tendrán todo bien.
     
    Esta guía está hecha por mi 100%, solo sacada de Epvp el programa.
     
    Descarga:
    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Saludes, y cualquier duda enviarme Mp, o escribir aquí.
  13. Me Gusta
    fuuton97 got a reaction from mebe in [GUIA]Como crear archivos Server_Attr para su Mapa.   
    Buenas gentes de Metin2 Zone, hoy les vengo a hacer esta pequeña guía donde les mostraré como crear su propio server_attr, que es aquel que debe ir en la parte del servidor vía FTP, los que han posteado mapa se han dado cuenta que no viene la cierta parte del mapa que es la de server_attr, esta guía no esta en EPVP, solo el programa que lo postearon, y yo se los vengo a explicar con detalles y lujos. Algunas personas lo que hacen es coger otro server_Attr de otro mapa, pero al meterlo les dará ciertos bug's lo cual es muy molesto, sigan al pie de al letra.
     
    *Programas a Utilizar:
    - SAttr_Tool_v1.
     
    Luego de haber descargado el programa nos dirigimos a descomprimirlo, y seguidamente a abrirlo, verán algo así:

     
    Ahora vamos a la carpeta de ''example_map'', la abren y verán que hay ciertos archivos como estos:

     
     
    Ahora procedemos a borrar todo el contenido de la carpeta dentro, de ''example_map''.
     
    Una vez ya borrado buscamos nuestro mapa, solo la parte del cliente, en este casi sería este: map_limbo, sacado de los de Next.

     
     
    Lo que haremos ahora será copiar los archivos del mapa seleccionado, en este caso el ''map_limbo'', coger sus archivos y pegarlo en la carpeta ''example_map''.
     
    Ya hecho esto procedemos abrir el .xml llamado ''example_map.xml'', verán algo así:

     
    Ahora editamos el ''x="2" y="2", cómo verán el para crear el server_attr solo sirve para mapas hasta 9x9, en este caso mi mapa es de 1x1, cómo mirarlo?, fácil abren el setting.txt y se van en MapSize, y hay se darán cuenta, una ves cambiar el intervalo X y Y, les quedará así:

     
     
    Una ves ya cambiado, procedemos a guardar, OJO: No cambien más nada.
     
    Ahora vamos a la raíz de al carpeta del SAttr_Tool_Release_V1, y cogemos el: ''example_map'' y lo arrastramos al SAttr.exe, les saldrá algo así:

     
     
    Cómo verán les puede que salga este error, que quiere decir este error?, pues que no se encuentra en la ruta que es, entonces lo que tienen que hacer es coger la carpeta, solo la carpeta, ''example_map'' y llevarla al directorio que dice, en este caso sería: C:/ Documents And Senttings/Jaller/example_map/00000/attr.atr' . Cogen su carpeta de example_map y la llevan a esa ruta que les dice, OJO: si no les dice ese error entonces es por que ya pueden hacerlo, y/o omiten este paso.
     
    Ya una vez hecho lo de arriba nos saldrá así, ya arrastrando en example_map.xml al SAttr.exe.

     
     
    Cuando aparezca esto solo dan la tecla enter y listo.
     
    Ahora vamos a la carpeta donde la pusimos para el paso anterior, en mi caso fue este: C:/ Documents And Senttings/Jaller/example_map y vemos si se creo el server_attr, deberá salirle:

     
    Como verán ya se crearon, y se creo el: server_attr.bmp, que es lo que te muestra el mapa, osea todo en cámara hacia arriba:

     
     
    Y listo ya tienen su server_attr creado, solo falta crear la carpeta del mapa para la parte del server, meter elserver_attr y listo ya tendrán todo bien.
     
    Esta guía está hecha por mi 100%, solo sacada de Epvp el programa.
     
    Descarga:
    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    Saludes, y cualquier duda enviarme Mp, o escribir aquí.
  14. Me Gusta
    fuuton97 reacted to ElRaulxX in Capí­tulo V - Los states   
    Buenas foreros de Metin2 Zone!
    Os vengo a traer la quinta entrega de nuestro fantástico curso de quests. En este capítulo trataremos los states, algo básico que tenéis que tener en cuenta a la hora de crear una quest. La verdad es que esto formaría parte del capítulo II, pues los states estructuran las quests, pero hemos aplazado este capítulo para que lo podáis entender mejor ahora que ya habéis avanzado un poco.

    Supongo que habréis visto ya en todas las quests la estructura state start begin. Efectivamente, eso es un state. Pero antes de todo debemos entender qué es realmente un state.


    1 - ¿Qué es un state?

    Podríamos decir que un state es la "división" de una quest. Las acciones de cada quest se dividen en bloques independientes: los states.
    Cuando el usuario inicia la quest empezará en el state inicial (start). A partir de entonces el creador de la quest puede ir cambiando de states a su conveniencia. De esta manera podemos hacer que el usuario sufra diferentes acciones en cada uno de los states.
    Algo importante a saber es que los states son totalmente independientes los unos de los otros. Las acciones que ocurren dentro de un state sólo ocurrirán en este state, es decir, cuando el usuario se encuentre dentro de este state.

    Un ejemplo, para que lo entendáis, son las misiones de búsqueda de un npc o de matar un determinado mob, las misiones de toda la vida que utiliza ymir. Cuando empieza la quest aparece un determinado pergamino. Conforme vamos avanzando la quest, este pergamino irá cambiando; en un state podemos abrir un determinado texto en un npc, en otro no. Esto no lo podríamos hacer sin nuestros states.
     
    Podemos entender mejor los states si los comparamos con un conjunto de habitaciones unidas a través de puertas.
    Empezamos entrando a la primera habitación (state start - inicio de la quest). En ella nos encontramos una alfombra y una silla. Por lo tanto podemos caminar sobre la alfombra y sentarnos en la silla. Ahora decidimos ir a una segunda habitación.
    En esta segunda habitación nos encontramos un sillón y una mesa. En esta habitación podemos sentarnos en el sillón y poner una baso sobre la mesa, pero no podemos caminar sobre la alfombra ni sentarnos en la silla ya que eso pertenece a la habitación anterior.
    De esta manera podemos entender los states. Cada state es independiente de los otros; podemos realizar las acciones que se encuentran dentro de un state independientemente de los otros. Para cambiar de state deberemos atravesar una puerta que, en términos de quest, correspondería a una función para cambiar el state en que se encuentra el usuario.

    Una quest puede tener un número indeterminado de states. Eso, como ya dije, va a conveniencia del creador de la quest.
    Cuando compilemos la quest (implementamos en el servidor) aparecerá en object la quest dividida/fragmentada. Esa división será en función de los states. Por ejemplo, si implementamos la quest tutorial.quest que contiene los states start, run y final, en object nos aparecerán los archivos tutorial.start, tutorial.run y tutorial.final (todo dividido en mobs, timers..., claro está). Esto lo trataremos a fondo en otro capítulo.


    2 - ¿Cómo cambiamos de state?
     
    El state del jugador puede cambiarse a partir de funciones creadas para ello.
    Los states se almacenan en la db y permanecerán hasta que sea modificado con cualquiera de las funciones creadas para ello.
    Existen dos maneras de cambiar un state: internamente o remotamente.
     
    Internamente:
    La función de cambio de state principal es la función set_state() o setstate(). Su uso es muy sencillo: tan solo debemos introducir como único argumento el nombre del state al que queremos cambiar cuando queramos realizar el cambio de state interno de la quest (por si no se entiende, entre paréntesis tenemos que poner el nombre del state al que queremos ir).
    set_state(string $state) Ejemplo:
    quest tutorial begin state start begin when 9012.chat."Aprendamos los states 1" begin say("Actualmente te encuentras en el state start") say("¿Quieres cambiar de state?") local s = select("Si","No") if s == 1 then say("Has cambiado de state correctamente") set_state("run") end end end state run begin when 9012.chat."Aprendamos los states 2" begin say("Actualmente te encuentras en el state run") say("¿Quieres cambiar de state?") local s = select("Si","No") if s == 1 then say("Has cambiado de state correctamente") set_state("start") end end endend Como veis en el ejemplo, cada state es independiente de los otros.
    También debo recordar que TODOS los states se cierran con un end.
    Los states pueden tener cualquier nombre, el que queramos. Aún así, para evitar cualquier tipo de error, es aconsejable utilizar nombres sencillos sin caracteres especiales.

    Remotamente:
    Los states de una quest también podemos cambiarlos remotamente, es decir, desde otra quest ajena. ¿Cómo hacemos eso? Pues con la función: set_quest_state(). Esta función toma dos argumentos: el primer argumento debe ser el nombre de la quest a la que queramos cambiar el state (IMPORTANTE: el nombre de la quest es el definido en la primera línea quest x begin donde x es el nombre de la quest; no confundir con el nombre del archivo quest) y el segundo el nuevo state al que queremos ir.
    set_quest_state(string $quest, string $state) Ejemplo:
     
    Quest1:
    quest tutorial1 begin state start begin when 9012.chat."Aprendamos los states 1" begin say("Actualmente te encuentras en el state start") end end state run begin when 9012.chat."Aprendamos los states 2" begin say("Actualmente te encuentras en el state run") end endend Quest2:
    quest tutorial2 begin state start begin when 9012.chat."Aprendamos los states - cambiar state" begin say("¿A que state quieres cambiar?") local s = select("start","run") if s == 1 then say("Has cambiado de state correctamente") set_quest_state("tutorial1", "start") elseif s == 2 then say("Has cambiado de state correctamente") set_quest_state("tutorial1", "run") end end endend 3 - States en los when - enter y leave
     
    Existen dos maneras de activar un when a través de los states: enter y leave.
    Enter: Se ejecutará el when cuando entremos en el state. Leave: Se ejecutará el when cuando salgamos del state. A través de estos dos whens podemos aumentar mucho la funcionalidad de una quest en las ocasiones en que podamos cambiar los states.
    He visto programadores quest que utilizan mucho esta táctica para conseguir solucionar problemas que de otra manera serían mucho más difíciles de solucionar, ¡incluso lo utiliza nuestra madre ymir!
     
    Aquí tenéis un ejemplo explicativo:
    quest tutorial begin state start begin when 9012.chat."Aprendamos los states - 1" begin say("¿Realmente quieres cambiar de state?") local s = select("si","no") if s == 1 then say("Has cambiado de state correctamente") set_state("run") end end end state run begin when enter begin chat("Has entrado al state.") end when leave begin chat("Has salido del state.") end when 9012.chat."Aprendamos los states - 2" begin say("¿Realmente quieres cambiar de state?") local s = select("si","no") if s == 1 then say("Has cambiado de state correctamente") set_state("start") end end endend Cuando entremos al state run se ejecutará chat("Has entrado al state.") y cuando salgamos del mismo chat("Has salido del state."). Este ejemplo es muy sencillo pero estoy seguro que de aquí os pueden salir grandes ideas que mejorarán mucho vuestro código.
     
     
     
    Con todo esto podemos ir jugando con los states y hacer miles de cosas.
    Algo muy útil es poner un state sin ninguna acción. Así podemos dar por finalizada la quest, ¡muy útil para quests con recorrido!
    Recordar que los states es lo principal de las quest. Si sabéis utilizarlos serán buenos aliados, sino tan solo serán neutrales. Siempre es mejor tener aliados, ¿no creéis?
     
     
    Changelog
    31/07/12 20:18 - Primera publicación oficial del capítulo. 04/09/13 11:35 - Correcciones varias. 04/09/13 14:33 - Correcciones varias. 04/09/13 15:31 - Correcciones varias, Añadida sección 3 - States en los when - enter y leave
  15. Me Gusta
    fuuton97 reacted to Akroma in Desencriptar CUALQUIER CLIENTE   
    Bueno querida comunidad de MZ, aqui les traigo un desencriptador que algunos ia conoceran, la diferencia es que este esta reparado, para ser usado en todas las versiones de Windows i en distribuciones linux.
    PD: El index reader si funciona en WXP
    aqui teneis:
    Debes iniciar sesión para ver el contenido del enlace en esta publicación. PD2: si el cliente lleva antiijectors os dira que la extraccion ha fallado, conforme que debereis usar otro metodo.
    PD3: El que quiera desencriptar algun cliente que use el antihack de anghios que me avise i lo ayudo.
    PD4: Dentro del archivo ai una pekeña explicacion sobre como usar dicho desencriptador.
    PD5: Si ejecutais el FuerzaBruta.exe i presionais F9 en el cliente del mt2, os dara la primera LZO, la primera !!, i como todas van pegadas, con que busqueis la primera encontrareis lo demas .
     
    Creditos: EPVP
     

    http-~~-//www.youtube.com/watch?v=90Cr-au_fd0&feature=player_embedded#t=0s
     
    Bueno aqui os ire dejando XML, echos para sacar todas las cosas de los diferentes arxivos, para que la extraccion sea rapida.
    ROOT:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    LOCALE_IT:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    LOCALE_DE:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    SEASON1:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    SEASON2:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    SEASON3:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    TERRAIN:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    TREE

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    UILOADING:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    UISCRIPT:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    ZONE:

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.
  16. Me Gusta
    fuuton97 reacted to KeKo in Capitulo IV - Profundicemos en las condiciones   
    Buenas zone!
    De nuevo tras otro emocionante capítulo del curso brindado por el gran raul es mi turno de seguir con el curso. El capítulo de hoy tratará sobre las condiciones en las quests, lo que popularmente conoceis todos como usar if en una quest.
     
    Esta vez también nos vamos a centrar en el cuerpo de una quest, y como mi colega raul empezare con la estructura básica de un if. Recordad esto primero:
     
    De nuevo la idea es la misma que con los whens:
     
     
     
    Por lo tanto la estructura es asi:
     

    if [X] then accion end Como veis cada if le corresponde un end y para que nos os de error al cargar tiene que ir un then al final del if, si no os saltara este error:
     

     
    Bien si ya tenemos claro la estructura vamos a profundizar un poco en el uso de las condiciones. Lo primero de todo me gustaría hacer una pequeña distinción entre varios tipos de condiciones:
     
    - Condiciones simples: Son aquellas que solo tienen un unico if (con sus posibles elseifs).
     
    - Condiciones compuestas: Son aquellas que se dan en las quests en las que si superamos la primera condicion se nos pone otra condición. Ojo! Son 2 condiciones diferentes, que llevan dos if y dos ends.
     
    - Condiciones opuestas: Que son las que usan habitualmente un else, o si no un return+end (ya os explicare como funcionan en el capi), y que son aquellas en las que ponemos una condicion y lo que pasara si se cumple lo contrario a esa condicion.
     
    Bueno vamos aver un pequeño ejemplo de una quest que usa una condicion:
     

    quest capicuatro begin state start begin when login with pc.get_map_index() == 41 begin if pc.get_empire() == 1 then say("No estas en el mapa de tu reino") end end end end Hasta aquí todo bien no? Como veis es una quest que se activa si te logeas en el mapa de city1 de jinno, pero te pone la condicion de que si eres del reino 1 (shinsoo) te aparece un mensaje diciendo que no estas en el mapa de tu reino.
     
    Respecto a los ends, como hay un if lleva un end y los otros tres son del when y de la apertura.
     
    Por lo tanto hagamos un resumen: cuando quieres poner una condicion en una quest primero pones el when [X] begin al que queremos ponerle la condicion, luego escribimos la condicion en si, la accion que se realiza una vez cumplida la condicion y el end.
     

    if [X] then accion end  
    Ahora pongamos otro ejemplo con esta misma mision pero ya con algunos elseif:
     

    quest capicuatro begin state start begin when login with pc.get_map_index() == 41 begin if pc.get_empire() == 1 then say("No estas en el mapa de tu reino") elseif pc.get_empire() == 2 then say("No estas en el mapa de tu reino") elseif pc.get_empire() == 3 then say("Estas en el mapa de tu reino!") end end end end Ahora ya tenemos 3 condiciones, pero como os fijais solo 1 lleva if, ya que son continuacion de la primera y por lo tanto solo llevan un end por las tres.
     
    Y también otro ejemplo del uso de un elseif, con un local select que es cuando mas vais a ver un elseif:
     

    quest capicuatro begin state start begin when 70042.use begin say_title("Tienda portatil") say("Con este objeto podras comprar") say("Potas donde quiera que estes.") say_reward("Quieres algunas?") local tienda = select ("Potas rojas" , "Potas azules" , "Superpotas" , "Cerrar") if tienda == 1 then say("Toma 200 potas rojas") pc.give_item2("27003", 200) pc.change_money(-30000) elseif tienda == 2 then say("Toma 200 potas azules") pc.give_item2("27006", 200) pc.change_money(-45000) elseif tienda == 3 then say(" Usted ha sido trolleado") say("no hay superpotas") elseif tienda == 4 then return end end end end  
     
    A estas alturas ya os habreis dado cuenta de como funciona el uso de un elseif:
     

    if [X] then accion elseif [X] then accion elseif [X] then accion end Al igual que cuando usabamos un solo if, ponemos el when [X] begin, luego la condicion if [X] then y esta vez las otras posibilidades que queremos que haya unidas al primer if [X] then (podemos poner las que queramos) con la estructura elseif [X] then. Por último cerramos el if con un end.
     
    Vayamos ahora a un caso de condicion compuesta, por ejemplo un teletransportador para un mapa:
     

    quest capicuatro begin state start begin when 20095.chat."Teleporter" begin if pc.get_level() < 50 then say("Lo siento eres muy bajo") say("vuelve cuando seas mas lvl") return end if pc.count_item("50084") == 0 then say("Valla, no tienes sello") say("Asi que no puedes entrar") return end if pc.get_map_index() == 190 then say("No puedes ir al mapa nuevo") say("Si ya estas en el") return end say("Pues lo siento ahora no quiero") say(" llevarte al mapa nuevo.") end end end Ahora en vez de usar condiciones unidas a la primera (el if [X] then) ponemos diferentes condiciones, cada una de estilo if [X] then y con su respectivo end.
     
    Usando las condiciones compuestas conseguimos que para llegar a la accion propia del when [X] begin haya que ir cumpliendo cada una de las condiciones. Es decir, si cumplimos la primera condicion el juego mirará aver si cumplimos la segunda.
     
    Si no cumplimos la segunda no se ejecutará, y si la cumplimos mirará aver si cumplimos la tercera. Si cumplimos todas las condiciones, la accion principal se ejecutará.
     
    Otra cosa a tener en cuenta es que podemos meter condiciones dentro de otras condiciones, y para eso os pondré un ejemplo en el que mezclaré condiciones simples con condiciones opuestas (hare mas compleja la quest de antes de las potas):
     

    quest capicuatro begin state start begin when 70042.use begin say_title("Tienda portatil") say("Con este objeto podras comprar") say("Potas donde quiera que estes.") say_reward("Quieres algunas?") local tienda = select ("Potas rojas" , "Potas azules" , "Superpotas" , "Cerrar") if tienda == 1 then if pc.gold < 30000 then say("Vaya no tienes suficiente dinero") return end say("Toma 200 potas rojas") pc.give_item2("27003", 200) pc.change_money(-30000) elseif tienda == 2 then if pc.gold < 45000 then say("Vaya no tienes suficiente dinero") return end say("Toma 200 potas azules") pc.give_item2("27006", 200) pc.change_money(-45000) elseif tienda == 3 then say(" Usted ha sido trolleado") say("no hay superpotas") elseif tienda == 4 then return end end end end end Ahora hemos metido una condición dentro de otra: primero metemos la condicion de elegir la opcion 1 (la de potas rojas) y luego dentro de esa hacemos que el juego mire si tenemos 30k para comprar las potas.
     
    Os habreis fijado que ahi usamos una condición opuesta:
     

    if pc.gold < 45000 then say("Vaya no tienes suficiente dinero") return end say("Toma 200 potas azules") pc.give_item2("27006", 200) pc.change_money(-45000) Ponemos la condicion:
     

    if pc.gold < 45000 then Luego lo que pasa si la cumplimos:
     

    say("Vaya no tienes suficiente dinero") Y para cerrar la condicion ponemos:
     

    return end De esta manera, lo siguiente que pongamos se cumplirá EN CUALQUIER CASO EN EL QUE NO CUMPLAMOS LA CONDICION ANTERIOR. Y como veis si tenemos mas de 45k de yang (es decir, no cumplimos la condicion) pues nos da las potas:
     

    say("Toma 200 potas azules") pc.give_item2("27006", 200) pc.change_money(-45000) Para acabar me gustaría hablarlos de la palabra else. Esta palabra se utiliza para hacer una condicion opuesta, ya que implica que si la cumplimos estará pasando cualquier cosa contraria a la de la condicion anterior. Veamos un ejemplillo, y os recalco que UN ELSE NO TIENE QUE LLEVAR SU CORRESPONDIENTE END.
     

    quest capicuatro begin state start begin when 70044.use begin if pc.count_item("70042") == 0 then pc.give_item2("70024", 1) chat("Toma un 5o bonus") pc.remove_item("70024" , 1) else say("Lo siento pero ya tienes") say("el 5o bonus") end end end end En este caso la condicion primera es que no tengamos ningun 5o bonus en el inventario, y si no la cumplimos (es decir, si que tenemos 5o bonus) pues nos dice que ya lo tenemos. Como usamos un else no especificamos una cantidad de bonus que tenemos que tener, si no que en cualquier caso contrario a que no tengamos ninguno nos dirá que sí lo tenemos.
     
    Y bueno eso es todo en el capítulo de hoy, espero que lo hayais disfrutado y que os ayude a la hora de hacer nuevas quests .
  17. Me Gusta
    fuuton97 reacted to KeKo in Capítulo II - Estructura de una quest   
    Buenas zone!
     
    Llega el segundo capítulo del esperado curso de creacion de quests. Tras un primer episodio lleno de aventuras, romance e intriga en esta entrega os voi a explicar como se estructura una quest.
     
    Antes de nada recordaré las palabras de un sabio llamado raul sobre: qué es una quest? Y además tened esto en mente siempre durante este capítulo.
     
     
    Lo primero de todo cuando vas a hacer una quest es crear el archivo de la quest en si. Como es un archivo de una quest debe tener la extension .quest, para lo que le damos a boton derecho -> nuevo -> documento de texto y una vez creado el archivo. txt le cambiamos el nombre a .quest.
     
    Bueno, después de esta ardua tarea nos encontraremos cara a cara con un archivo en blanco en el que tendremos que vertir nuestras ideas para que se convierta en una quest hecha y derecha. Voi entonces a explicaros como se estructura una quest estándar para que sepais como enfrentaros a nuestro terrible enemigo durante todo el curso: la quest en blanco.
     
    Una quest se divide en 3 partes que podreis distinguir fácilmente:
     
    - Apertura: Son siempre las 2 primeras lineas de una quest.
     
    - Cuerpo: Es lo que podriamos llamar la quest en si, ya que es la parte de la quest que contiene todas las cosas que queremos que haga la quest.
     
    - Cierre: Son siempre ends (a los que dedicare un apartado especial en este capitulo) que hacen que nuestra quest acabe correctamente.
     
    Vamos a hablar ahora en profundidad de cada una de estas partes:
     
    1 - La apertura:
     
    La primera parte de una quest es la que llamaremos apertura a lo largo del curso (ya parezco un profesor ) y que como dije arriba son siempre las dos primeras lineas de una quest.
     
    Veamos un ejemplo de como se debe hacer una apertura:
     

    quest capidos begin state start begin Bien, ahora vamos a centrarnos en qué hace cada una de esas dos líneas:
     

    quest capidos begin La linea más básica de toda una quest, simplemente manda la orden de que comience la quest.
     
    *Desmitificando las quests v1: Se que mucha gente tiene la creencia pagana de que el nombre que va despues de quest en la primera linea de la apertura tiene que ser el mismo que el nombre del archivo .quest PERO ES MENTIRA!!
     
    El nombre que ponemos ahi puede ser el que nos apetezca, ya que simplemente es lo que el juego al cargar la quest para ver que está empezando una.
     
    Bien, ahora la segunda linea:
     

    state start begin Esta linea lo que hace es que comience el estado "start" , es decir: que podemos empezar a escribir nuestra quest.
     
    *Es muy importante que sepais que este estado va a continuar activo hasta el final de la quest, a expecion de casos en los que usemos otros estados aparte del inicial (en lo que profundizará raul en el capítulo de los estados).
    Esto es todo sobre la apertura, espero aver resuelto dudas y enseñado algo que no sepais, y si no lo habreis leido pa na
     
     
    2 - El cuerpo de una quest:
     
    Ahora que ya hemos mandado la orden de que la quest comience (primera linea de la apertura) y hemos activo el estado de start (para poder empezar a escribir quest) nos toca elaborar nuestra quest para hacer eso que queríamos hacer para dejar de ver la temible quest en blanco.
     

    quest capidos begin state start begin De momento tenemos esto, pero ahora queremos hacerlo más digo yo, no? Pues sí! Me remitiré de nuevo a la cita de mi colega raul:
     
    Como veis, cuando pensamos en lenguaje de quest nos planteamos hacer una acción y por lo tanto en el cuerpo de una quest puede suceder varias cosas:
     
    - Que una accion comience.
    - Que pongamos una condicion para que una accion se desarrolle.
    - Que una accion se desarrole.
    - Que comprobemos que una accion se esta desarrolando.
    - Que una accion termine.
     
    Es por eso que en el cuerpo de una quest vamos a usar una serie de operadores logísticos que nos permitiran desarrollar nuestra quest, y que son los siguientes:
     

    when while with and or if elseif else > < >= <= == ~= De ellos:
     
    * when y while sirven para comenzar acciones.
    * with and or if elseif y else sirven para poner condiciones.
    * > < >= <= == ~= sirven para hacer comprobaciones entre acciones.
     
    Primero veremos un ejemplo sencillo de quest que te pone un mensaje en la barra de chat cuando te logeas:
     

    quest capìdos begin state start begin when login begin chat("Bienvenido al servidor, pasalo bien") Como veis tenemos apertura, la orden de que comience una accion cuando nos logeemos y luego la accion que se desarrola cuando nos logeamos.
     
    Vamos a ver ahora mas fondo esto con un ejemplo de quest que envia un mensaje a todos cuando un nuevo pj comienza el juego:
     

    quest capidos begin --- Lineas de apertura state start begin when login with pc.get_level() == 1 begin ---- Linea con orden de comienzo, condicion y comprobacion notice_all("Hay un nuevo personaje en nuestro servidor") --- Linea con la accion Como veis empieza con la apertura.
     
    Luego tenemos una orden para comnenzar una accion: en este caso la accion comenzará cuando nos logeemos con un personaje.
     

    when login Y este comienzo además tiene una comprobación antes de que se desarrolle la accion:
     

    with pc.get_level() == 1 En este caso no solo llega con que nos logeemos con un personaje, ya que tiene que además ser nivel 1, porque tenemos una orden de login, pero con la orden with seguida de una funcion: pc.get_level() y como veis un == que sirve para comprobar que el valor del nivel del personaje es igual a 1.
     

    when login with pc.get_level() == 1 begin Y ahi ya está todo entero. Como veis una vez echa la orden de comenzar la accion cuando nos logeemos, con la condicion de que el personaje sea nivel 1 ponemos la orden begin, para que comience la accion.
     
    Por último simplemente ponemos la accion que se va a desarrollar:
     

    notice_all("Hay un nuevo personaje en nuestro servidor") Bien, creo que ahora ya vais entendiendo como va el cuerpo de una quest, quedaros con el dato de que siempre habrá una orden que haga que comience una mision, ya sea con el when, while, if.... y luego despues de especificar que tiene que pasar para que comience la accion usaremos funciones de quest para desarrolar esa acción.
     
    Bueno pues ahora ya tenemos nuestra accion desarrolandose, pero que hacemos con ella? Como las acciones no pueden ser eternas tenemos que acabarla, y para eso usaremos la palabra end, que indica que la accion termina.
     
    ----------------------------------------------------------------------------------------------------------------------------------------------------------------
    *Apartado especial, nuestros amigos los ends:
     
    Como muchos sabeis uno de los errores más comunes a la hora de hacer quests es poner o bien ends de más o bien ends de menos, lo que hará que nuestras quests no funcionen. Por lo tanto antes de nada parémonos a pensar en que es lo que es un end.
     
    Procediente del inglés la palabra end es un verbo que significa terminar, lo que no nos puede dejar más claro cual es su función en una quest: terminar una acción.
     
    Por lo tanto cada vez que tengamos una accion tendremos que ponerle un end al final para acabarla. Y de que manera vamos a hacer eso? Os lo diremos en el proximo capitulo , na en serio, asi funcionan los ends:
     
    - Por cada begin que tengamos en nuestra quest nosotros le colocaremos un end.
    - Por cada if que haya en la quest pondremos un end.
     
    Veamos algunos ejemplos:
     

    when login begin chat("Hola") end when 105.kill begin say("Has matado un lobo") end when 20095.chat."Hola" begin say("Buenas") end Por cada begin corresponde a un end
     

    if pc.count_item("50084") == 1 then say("Veo que tienes la llave") end En este caso hay un if asi que ponemos un end
     
    *Desmitificando las quest v2: Mucha gente comete el error de pensar que si ves un elseif como lleva la palabra if pues debe tener un end también, pero NO!!! Y es porque un elseif es una continuacion de una condición y no una nueva condicion
     
    Ejemplo:
     

    local s = select ("opcion1" , "opcion2" , "opcion3) if s == 1 then say("Has clickado en la opcion 1") elseif s == 2 then say("Has clickado en la opcion 2") elseif s == 3 then say("Has clickado en la opcion 3") end Como veis solo hay un end, el correspondiente al primer if.
     
    ------------------------------------------------------------------------------------------------------------------------------------------------------------------
     
    Bien ahora que ya conocemos mejor a los ends (de los cuales os seguiremos hablando en posteriores capitulos) ya podemos acabar el cuerpo de nuestra quest, cerrando la accion que habeis comenzado.
     
     

    quest capidos begin --- Lineas de apertura state start begin when login with pc.get_level() == 1 begin ---- Linea con orden de comienzo, condicion y comprobacion notice_all("Hay un nuevo personaje en nuestro servidor") --- Linea con la accion end --- End correspondiente al begin de la linea 3  
    Pero los listos os habreis dado cuenta de que en nuestra quest quedan 2 begins (de la apertura) que no tienen su end y eso lo voi a explicar ahora en la ultima parte de la estructura de una quest.
     
    3 - Cierre de una quest:
     
    Cada vez que acabemos una quest vamos a tener que poner dos ends para cerrar la quest, y os estareis preguntando, y porque??? Pues la explicacion es esta:
     

    state start begin Os acordais de la apertura? Si lo haceis os acordareis de que para hacer una quest tenemos que hacer un estado de comienzo (state start), que logicamente acabara cuando acabe la quest. De ahi viene el primer end del cierre de una quest.
     
    *Detalle importante: algún espabilado habrá visto quests en los que se usan otros states aparte del start. En eses casos el cierre solo lleva un end (el que explico abajo) ya que acabaremos el start antes de lo normal para poner nuestro nuevo estado (para mas info sobre estado atentos al capítulo dedicado a ellos que hará raul).
     
    Y ahora el segundo end del cierre:
     

    quest capidos begin De nuevo dire si os acordais de la apertura (que espero que os acordeis ) sabreis que cada quest empieza con esa orden, y como os fijareis tiene un begin al final por lo que le corresponde un end, pero no se lo podemos poner en cualquier momento, ya que (me quoteo a mi mismo):
     
    Es decir, si acabamos la accion de que comience la quest, acabamos la quest (genial deduccion). Siguiendo este hilo de deduccion os habreis dado cuenta de que es por eso por lo que el end correspondiente al begin del quest nombre begin siempre va al final de la quest.
     
    Y ahora ya podemos ver nuestra quest completa y lista para cargar
     

    quest capidos begin --- Lineas state start begin ----- de apertura when login with pc.get_level() == 1 begin ---- Cuerpo de la quest notice_all("Hay un nuevo personaje en nuestro servidor") --- Cuerpo de la quest end --- End correspondiente al begin de la linea 3 --- Cuerpo de la quest (end correspondiente el when login begin) end --- Cierre del state end --- Cierre del quest begin Y eso es todo por el capítulo de hoy, espero que lo hayas disfrutado y pronto llegará el 3er episodio de manos de raul.
  18. Me Gusta
    fuuton97 reacted to Santy!. in Quest de inicio estilo panamera!   
    Hola hoy les traigo esta quest hecha por mi es de cuando inicias sea como panamera que te aparece 1 mision y te da los items:
     

    ---------------------------------------------- -- Quest creada por santy -- para Debes iniciar sesión para ver el contenido del enlace en esta publicación. ---------------------------------------------- quest portmap begin state start begin when login with pc.get_level() == 1 begin set_state(info) end end state info begin when letter begin send_letter("equipo de inicio") end when button or info begin say_title("Bienvenido") pc . give_exp2 ( ) set_quest_state ( "levelup" , "run" ) pc . change_money ( 10000 ) pc . give_item2 ( "27003" , 200 ) pc . give_item2 ( "27003" , 200 ) pc . give_item2 ( "27003" , 200 ) pc . give_item2 ( "27003" , 200 ) pc . give_item2 ( "27003" , 200 ) pc . give_item2 ( "27006" , 200 ) pc . give_item2 ( "27006" , 200 ) pc . give_item2 ( "71050" , 200 ) pc . give_item2 ( "72702" , 1 ) pc . give_item2 ( "50051" , 1 ) pc . give_item2 ( "72701" , 1 ) say ( "Recibes level 1." ) say ( "Recibes 10000 yang." ) say ( "Recibes 1000 Pociones Rojas(G)." ) say ( "Recibes 400 Pociones Azules(G)." ) say ( "Recibes Equipo basico." ) say ( "Recibes varios cabos valor" ) say ( "Recibes zapatos de velocidad" ) if pc . job == 0 then pc . give_item2 ( "19" , 1 ) pc . give_item2 ( "3009" , 1 ) pc . give_item2 ( "11209" , 1 ) pc . give_item2 ( "12209" , 1 ) pc . give_item2 ( "13009" , 1 ) pc . give_item2 ( "14009" , 1 ) pc . give_item2 ( "15009" , 1 ) pc . give_item2 ( "16009" , 1 ) pc . give_item2 ( "17009" , 1 ) say_reward ( "Has Recibido Set de Guerrero!" ) elseif pc . job == 1 then pc . give_item2 ( "1009" , 1 ) pc . give_item2 ( "19" , 1 ) pc . give_item2 ( "2009" , 1 ) pc . give_item2 ( "8009" , 200 ) pc . give_item2 ( "8009" , 200 ) pc . give_item2 ( "8009" , 200 ) pc . give_item2 ( "8009" , 200 ) pc . give_item2 ( "11409" , 1 ) pc . give_item2 ( "12349" , 1 ) pc . give_item2 ( "13009" , 1 ) pc . give_item2 ( "14009" , 1 ) pc . give_item2 ( "15009" , 1 ) pc . give_item2 ( "16009" , 1 ) pc . give_item2 ( "17009" , 1 ) say_reward ( "Has Recibido Set de Ninja!" ) elseif pc . job == 2 then pc . give_item2 ( "19" , 1 ) pc . give_item2 ( "11609" , 1 ) pc . give_item2 ( "12489" , 1 ) pc . give_item2 ( "13009" , 1 ) pc . give_item2 ( "14009" , 1 ) pc . give_item2 ( "15009" , 1 ) pc . give_item2 ( "16009" , 1 ) pc . give_item2 ( "17009" , 1 ) say_reward ( "Has Recibido Set de Sura!" ) elseif pc . job == 3 then pc . give_item2 ( "5009" , 1 ) pc . give_item2 ( "7009" , 1 ) pc . give_item2 ( "11809" , 1 ) pc . give_item2 ( "12629" , 1 ) pc . give_item2 ( "13009" , 1 ) pc . give_item2 ( "14009" , 1 ) pc . give_item2 ( "15009" , 1 ) pc . give_item2 ( "16009" , 1 ) pc . give_item2 ( "17009" , 1 ) say_reward ( "Has Recibido Set de Chaman!" ) end end end state __COMPLETE__ begin when enter begin q.done() end end end espero que la disfruten y den mi gracias.
  19. Me Gusta
    fuuton97 got a reaction from Predator77 in [QUEST]Actualización en pergamino (información).   
    Hola, hoy les traigo esta quest de Metin2, esta es creada por mi, y es la primera que hago. La quest tiene la función de que cuando inicias a un lvl 1 o cuando entras al login te saldrá un pergamino donde te mostrará como cierta información del server o actualizaciones, y/o lo que quieras anunciar, sin más rodeos dejo la quest:
     

    ---------------------------------------------- -- Quest creada por Fuuton97 -- www.metin2skill.com ---------------------------------------------- quest notice_server begin state start begin when login begin set_state(gotoinfomation) end end state gotoinfomation begin when letter begin send_letter("NOTICIAS DEL SERVER!") end when button or info begin say("Próxima actualizaciones en el server van a hacer enumeradas:") say_title("1- Actualización de Catacumbas:") say_title("-Se implementará catacumbas al 100%.") say_title("-Se pondrán los Jefes de cada mapa de catacumbas.") say_title("-Habrán dropes único en los mob's/Jefes.") say_title("2- Actualización de Mapa BOSS:") say_title("-En este mapa serán puestos Mob's nuevos.") say_title("-Se les colocará un drop a todos diferentes a los mob's normales.") say_title("3- Mapa de Jefes (Menores)") say_title("- Este es una mapa donde estarán todos los Jefes.") say_title("- Este mapa es para que los user'entren y disfruten.") say_title("ESTARá PRONTO EN NUESTRO SERVER!!") set_state(gotoinfomation) end end state __COMPLETE__ begin end end Esta quest es creada por mi 100%, y es la primera que hago, así que recibo sugerencias o críticas que sean constructivas.
     
    Otro punto que no hice fue la que saliera el login, pues metería por el método como la que tiene guabina, que cada ves que inicies el login en tu pj o te telestrasporte aparecerá siempre este mensaje, entonces y lo hice en pergamino.
     
    Saludos.
  20. Me Gusta
    fuuton97 reacted to KeKo in [Guia] Implementar mobs sin morir en el intento   
    Buenas zoneros y zoneras, hoy os traigo esta guía que me habían pedido que hiciera para implementar mobs, cosa que hay gente a la que le da bastantes problemas a veces.
     
    ESTA GUIA ES EXCLUSIVA DE METIN2ZONE, NO LA POSTEEIS EN OTRO FOROS
     
    Ire paso por paso explicando el proceso de implementación de un mob:
     
    1 - Qué es lo que trae la carpeta de un mob?
     
    Cuandos nos bajamos un mob nuevo para meter en nuestro servidor vemos que el mob consiste en una carpeta con una serie de archivos dentro, que pueden ser de diferentes tipos y que tienen diferentes funciones.
     

     
     
    Esos archivos pueden ser:
     
    -Archivos .gr2: Son los archivos que contienen el modelo del mob y sus movimientos. Para que un gr2 funcione debe ir siempre a unido a un archivo, que puede ser un .msm o un .msa
     
    Podeis abrirlos usando el granny viewer, y tendreis una vista así del mob:
     

     
    -Archivos msm y msa: Son aquellos que sirven para que el juego pueda leer un archivo .gr2, por lo que siempre tienen la ruta del modelo al que van unidos. Los msm son para el modelo del mob en si y los msa para animaciones.
     
    -Archivos .mse: Estos archivos se usan para meter efectos a los mobs, por lo que los renocereis viendo que al final del archivo siempre saldra el nombre de un .dds o otro archivo de textura, que es el efecto en si.
     
    -Motlist.txt: En cada carpeta de un mob debe aver un archivo con este nombre, ya que es el que le dije al juego a que movimiento se corresponde cada uno de los gr2 de animaciones del mob.
     
    Explicacion del motlist:
     

     
    -Cada linea lleva GENERAL luego el nombre del movimiento, que puede ser WAIT, RUNT, DIE, ATTACK, etc (nombres en ingles de las acciones de los mobs) y luego el nombre del .msa que enlaza con esa animacion. El numero despues del nombre del msa poned el mismo que en otra linea.
     
     
    -Texturas: Pueden presentarse en varios formatos, siendo .jpeg .dds y .tga los mas comunes. La ruta en la que deben ir estos archivos va especificada en el .gr2 del mob asi:
     

     
     
    *Nota: la ruta mas normal para un mob suele ser monster/monster2/npc/npc2 pero puede haber mobs con rutas diferentes como en el zone o carpetas nuevas.
     
    2 - Vale ya se como va la carpeta del mob, ahora que hago con ella?
     
    Bien, ahora que ya tenemos la carpeta de nuestro mob y entendemos como funciona tenemos que implementarlo en nuestro cliente. Pero en que archivo lo hacemos?
     
    A la hora de ver en que ruta poner la carpeta de nuestro mob tenemos que ir a la susodicha carpeta y abrir el msm que lleve el nombre del mob. Una vez lo abramos veremos un apartado donde pone: BaseModelFileName y en esa ruta pondremos la carpeta del mob.
     

     
    Una vez tengamos metido la carpeta en su sitio, añadiremos al xml del archivo que estemos modificando las lineas correspondientes al nuevo mob, ya sea a mano o usando un creador de xml.
     
    *Se pueden dar casos de mobs en los que la ruta en la que tenga la textura sea diferente a la ruta en la que tenga que ir la carpeta del mob, así que si se da el caso tendreis que meter la carpeta del mob en la ruta del msm y el archivo de la textura en su ruta correspondiente.
     
    3 - Ya compile el archivo, que és lo siguiente?
     
    Una vez compilado el archivo el siguiente paso es decompilar el root de nuestro cliente y abrir un archivo llamado npclist.txt, en el que relacionaremos cada mob nuevo con una id en el cliente.
     
    *Detalle: cuando escribais en el npclist debereis usar la tecla tabulador en vez de espacios, para que no os de errores al cargar el juego.
     
    Una vez abrais el npclist, vais a cualquier parte del archivo, le dais a enter para dejar una linea vacia y escribis lo siguiente:
     
    1º La id que quereis que tenga el mob.
     
    2º Le dais a tab
     
    3º El nombre del msm del mob.
     

    idmob [tab] nombremsm El resultado tiene que ser algo asi:
     

     
    3.1: Casos especiales: mobs duplicados:
     
    Hay veces que un mismo mob con diferentes texturas, por lo que recurrirmos a duplicar el mob. Por no alargar la guia demasiado podeis ver mi post de duplicar mobs para aprender a hacerlo:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    En esos casos (resumiendo la parte del root) tendreis que poner primero una linea que sea asi, ya que cuando duplicais un mob haceis otro msm con un nombre diferente al del mob original en el que haceis que tenga otra textura.
     

    0 [tab] nombredelmsmnuevo [tab] nombredelmsmviejo
     
    4 - Es todo? Ya implemente mi mob?
     
    Casi Casi. Ya lo ultimo que queda para implementar a vuestro mob es meterle una query en el mob_proto del navicat, que puede ser igual a la de otro mob o podeis modificarla como os plazca.
     
    *Detalle: Aunque un mob no tenga query si está implementado en el cliente podeis hacer /poly iddelmob para probarlo antes de meterle query.
     
    Para que el mob sea el mismo que acabamos de meter, la query debe llevar la misma id que pusimos en el npclist.txt del root.
     
    *Opcional: Si ademas queremos que nuestro mob lleve encima el nombre deberemos añadir una linea con la id npclist.txt en el mob_proto del cliente: vamos al locale de nuestro servidor, buscamos el mob_proto y lo decompilamos. Una vez hecho eso añadimos una linea nueva:
     

    <Mob vnum="idmob" name="????" gb2312name="Nombremob" type="0" rank="1" battle_type="0" level="125" event_type="0" mob_color="0" /> Y listo ya tendreis vuestro nuevo mob implementado y funcionando
     

     
    (Os pongo una foto de un mob cualquiera xd, esta porq la chami sale toda sexy )
     
     
    5 - Errores frecuentes, soluciones y truquillos varios:
     
    Toda esta teoría está muy bien, pero a mucha gente le pasa que implementa un mob perfectamente y luego no le va, hay una serie de cosas tipicas que suelen causar eso:
     
    5.1: Invoco al mob, veo que me baja la vida pero no hay ningun monstruo, que hago
     
    Este es el error mas tipico de todos, y que tiene muchas soluciones diferentes:
     
    1 - Pusiste mal el nombre del mob en el npclist, así que revisa que el nombre que tiene el msm del mob sea el mismo que pusiste en el npclist, puede que lo hayas escrito mal. (Se que es muy básico pero nunca se sabe).
     
    2 - Problema de ruta: A veces puede pasar que implementes un mob y metas la carpeta del mob en otra ruta diferente a la que tiene en el msm así que debereis cambiarlo de carpeta a la que ponga el msm.
     
    3- El problema de las mayúsuclas y minúsculas: Aunque no lo parezca esto es algo que causa muchos problemas con los mobs, ya que es algo que muchos no saben.
     
    Esto es muy importante: NUNCA PUEDE HABER MAYUSCULAS EN EL XML DE UN MOB, YA SEA EL NOMBRE DEL GR2 O DE LA TEXTURA, PORQUE DARA ERROR.
     
    Como la gran mayoria usamos el creador de xml, cuando meteis la carpeta del mob en su archivo correspondiente teneis que fijaros que el nombre del gr2 del mob estea escrito en minusculas:
     
    Así mal
     

     
     
    Así bien
     

     
     
    También teneis que abrir el msm del mob y ver que el .gr2 de ahi esté en minus también:
     
    Asi mal
     

     
     
    Asi bien
     

     
    Ademas comprobad también que esta en minusculas en el xml. De esta manera al usar el creador de xml ya saldra en minusculas el nombre del gr2.
     
    Por ultimo en lo referente a las minusculas fijaros que el nombre del mob, de la textura o cualquier otra cosa del xml este en minusculas, por ejemplo:
     

    d:/ymir work/monster2/mob_nuevo/Mob.gr2 d:/ymir work/monster2/mob_nuevo/Textura_Mob.tga Esas dos lineas estarían mal, ya que aunque el .gr2 esta en minusculas hay letras en mayuscula (la M de mob y la T de textura) asi que recordad siempre que todo debe estar en minusculas para que el juego lo lea bien
     

    d:/ymir work/monster2/mob_nuevo/mob.gr2 d:/ymir work/monster2/mob_nuevo/textura_Mob.tga  
    4 - El problema de las ids: A la hora de poner ids a los mobs nuevos que hayais implementado teneis que tener en cuenta que hay una serie de ids que se corresponde a monster/monster2/npc/npc2 así que a la hora de poner id os aconsejo que useis esta numeración:
     
    * Si el mob es del monster, ponedle id de 210 en adelante.
     
    * Si el mob es del monster2, ponedle id de 3000 en adelante.
     
    * Si el mob es de npc/npc2, ponedle id de 18000 en adelante (a menos que sean montus que peguen o mascota que tienen que tener una id concreta).
     
    Eso sí, si no quereis poner esas ids no significa que el mob no vaya a ir, pero con esas no os dará problema por la id nunca.
     
    5.2: Cuando descargo un mob viene sin los gr2 de las animaciones, que hago???
     

     
    Los mobs nuevos que implementeis no siempre tendrán animaciones propias, así que en muchos casos usarán las de otros mobs que tengan su mismo esqueleto (por lo que sus animaciones seran compatibles). En ese caso llevaran el mse con la ruta de la animacion del otro mob.
     
    Si solo teneis el gr2 y msm de un mob y quereis usarlo tendreis que copiar de otro mob compatible con el sus mse (lo que es dificil de ver a veces ya que hay que fijarse en como es el mob fisicamente y buscar uno parecido) y pegarlos en la carpeta de vuestro mob.
     

     
    5.3: Tengo un mob sin motlist, que hago??
     
    Si os falta el motlist de un mob solo teneis que cojer el de otro mob y editarlo con los nombres de las animaciones que tenga vuestro mob. Para saber que gr2 es cada animacion (si el 00 es WAIT por ejemplo) tendreis que abrir el gr2 del mob cn el granny, darle a animation list, ahi a load new animation. Una vez os diga que gr2 abrir vais a la carpeta del mob abris un gr2, por ejemplo el 00 y veis que hace el mob, si corre sería RUN, si se muere pues DEAD y así.
     

     
     
    Y eso es todo zoneros, espero que os sirva la guía
  21. Me Gusta
    fuuton97 reacted to KeKo in [Quest+cliente] El sistema de logros   
    Buenasss zoneros y zoneras, hoy os voi a explicar como implementar en vuestro servidores el sistema de logros que meti en Metin2Extasis, hasta con mi querida quest de canjes xd (aunque en elite hay una mas completa la mia es mas sencillita).
     
    ESTA GUIA ES EXCLUSIVA DE METIN2ZONE, QUE NADIE LA COPY PASTEE A OTROS FOROS
     
    1 - Qué es el sistema de logros?
     
    Este sistema consiste en una quest y una edicion del cliente que hace que cada vez que un jugador alcance un objetivo concreto, que tu fijas en la quest, le da los puntos correspondientes al logro que haya alcanzando. Si un jugador acumula puntos luego los puede canjear por premios.
     
    Aqui teneis algunas fotos del resultado final (son antiguas del extasis xd):
     

     

     
     
     
    2 - Como meto yo esto?
     
    El sistema de logros consiste en una quest y en editar unos archivos en el cliente, así que vamos a ir paso por paso:
     
     
    2.1: Parte del cliente:
     
    *Todos los archivos que tengais que meter estan en esta descarga:
     

    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
    2.1.1 - Que archivos vamos a editar? En el cliente editaremos los siguientes archivos:
     
    -Root: dentro de el los archivos game.py y uiachievement.py (este lo meteremos nosotros).
    -Etc: donde meteremos los archivos achievement_small.sub y achievement_small.dds
    -Uiscript: aqui meteremos el archivo achievementboard.py y warteschleife.py
     
    2.1.2 - Manos a la obra, a implementar!
     
     
    2.1.2.1: Primero empezaremos con el root. Decompilad vuestro root, abrid el archivo game.py y buscad esto:
     

    def __ServerCommand_Build(self): Una vez esteis ahi, vais hasta donde pone "CloseSafeBox" y cuando esteis en esa linea le dais a a enter y pegais esto:
     

    # Achievement System START "achievement" : self.__AchievementTest, "achievementpoints" : self.__ShowAchievementPoints, # Achievement System END Quedandoos asi:
     

     
    (Las -------------------- las pongo solo para que distingais la parte que acabamos de añadir, no hay que ponerlas)
     
    Ahora vais al final del archivo, le dais a enter para dejar algo de espacio y pegais esto:
     

    # Achievement System START def __ShowAchievementPoints(self, points): import uiAchievement import uiTaskbar self.uiAchievement = uiAchievement.AchievementDialog() uiAchievement.AchievementPoints = int(points) def __AchievementTest(self, archivement): import uiAchievement self.uiAchievement = uiAchievement.AchievementDialog() self.uiAchievement.Show(1, str(archivement)) self.uiAchievement.SetTop() # Achievement System END Quedará asi:
     

     
     
    *Siguiente paso: metemos en la carpeta root el archivo uiachievement.py y lo añadimos al xml
     

    <File archivedPath="uiachievement.py" type="2"><![CDATA[Sourceuiachievement.py]]></File> Listo el root! Sigamos con el etc.
     
    2.1.2.2: Decompilamos nuestro etc, vamos a la carpeta ymir work/ui y metemos el achievement_small.dds. Despues vamos a la carpeta ymir work/ui/public y metemos el achievement_small.sub. Por ultimo agregamos ambos al xml:
     

    <File archivedPath="d:/ymir work/ui/public/achievement_small.sub" type="0"><![CDATA[Sourceymir workuipublicachievement_small.sub]]></File> <File archivedPath="d:/ymir work/ui/achievement_small.dds" type="0"><![CDATA[Sourceymir workuiachievement_small.dds]]></File> 2.1.2.3: El ultimo paso en el cliente es decompilar nuestro uiscript y meter el archivo achievementboard.py y el warteschleife.py: en la carpeta. Los añadimos al xml y compilamos:
     

    <File archivedPath="uiscript/achievementboard.py" type="2"><![CDATA[Sourceuiscriptachievementboard.py]]></File> <File archivedPath="uiscript/warteschleife.py" type="2"><![CDATA[Sourceuiscriptwarteschleife.py]]></File> Y listo ya tenemos todo lo del cliente
     
     
    2.1: Parte del server:
     
    Bueno ahora ya solo nos queda meter nuestra quest del sistema de logros en la carpeta /home/game/quest (o la ruta en la que tengais la carpeta quest). Aqui os dejo la mia, con los nombres en español, algunos logros añadidos, canje, un item que te da logros (pa quien lo quiera xd), una opcion que te dice tus logros, etc
     

    quest logros_keko begin state start begin --LOGIN when login begin local actual_achievement_points = pc.getqf("achievement_points") if pc.getqf("firstlogin") != 1 then local Reward = 1 pc.setqf("firstlogin", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Primer_login%".. actual_achievement_points + Reward .."") else cmdchat("achievementpoints ".. pc.getqf("achievement_points")) end end --BOSSE when 691.kill begin local Reward = 2 local Achievement = "Jefe_Orco" local killcount = pc.getqf("691") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("691", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 791.kill begin local Reward = 3 local Achievement = "Lider_esoterico" local killcount = pc.getqf("791") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("791", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 2493.kill begin local Reward = 100 local Achievement = "Dragon_azul" local killcount = pc.getqf("2493") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("2493", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 2492.kill begin local Reward = 20 local Achievement = "Comandante_Setaou" local killcount = pc.getqf("2492") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("2492", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 1091.kill begin local Reward = 5 local Achievement = "Rey_demonio" local killcount = pc.getqf("1091") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("1091", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 2597.kill begin local Reward = 20 local Achievement = "Muerte" local killcount = pc.getqf("2597") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("2597", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 1192.kill begin local Reward = 12 local Achievement = "Bruja_de_hielo" local killcount = pc.getqf("1192") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("1192", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 1304.kill begin local Reward = 5 local Achievement = "Tigre_fantasma" local killcount = pc.getqf("1304") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("1304", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 1901.kill begin local Reward = 4 local Achievement = "9_colas" local killcount = pc.getqf("1901") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("1901", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 2091.kill begin local Reward = 3 local Achievement = "Reina_araña" local killcount = pc.getqf("2091") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("2091", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 2206.kill begin local Reward = 4 local Achievement = "Jefe_logros" local killcount = pc.getqf("2206") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("2206", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 2191.kill begin local Reward = 5 local Achievement = "Tortuga_del_desierto" local killcount = pc.getqf("2191") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("2191", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 692.kill begin local Reward = 3 local Achievement = "Orco_elite" local killcount = pc.getqf("692") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("692", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 693.kill begin local Reward = 5 local Achievement = "Orco_renacido" local killcount = pc.getqf("693") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("693", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end --Item shop--- when 50129.use begin say_title ( "Obten puntos logro") local actual_achievement_points = pc . getqf ( "achievement_points" ) local p = select ( "Obten 200 puntos logro" ) if p == 1 then local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points + 200 ) say ( "Enorabuena tienes 200 logros mas" ) say ( "Disfrutalos!" ) item.remove ( "50129", 1 ) end end when 50130.use begin say_title ( "Obten puntos logro") local actual_achievement_points = pc . getqf ( "achievement_points" ) local p = select ( "Obten 100 puntos logro" ) if p == 1 then local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points + 100 ) say ( "Enorabuena tienes 100 logros mas" ) say ( "Disfrutalos!" ) item.remove ( "50130", 1 ) end end when 50131.use begin say_title ( "Obten puntos logro") local actual_achievement_points = pc . getqf ( "achievement_points" ) local p = select ( "Obten 50 puntos logro" ) if p == 1 then local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points + 50 ) say ( "Enorabuena tienes 50 logros mas" ) say ( "Disfrutalos!" ) item.remove ( "50131", 1 ) end end when 50132.use begin say_title ( "Obten puntos logro") local actual_achievement_points = pc . getqf ( "achievement_points" ) local p = select ( "Obten 25 puntos logro" ) if p == 1 then local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points + 25 ) say ( "Enorabuena tienes 25 logros mas" ) say ( "Disfrutalos!" ) item.remove ( "50132", 1 ) end end --CANJES-- when 50115.use begin say_title ( "Canjea tus puntos logro" ) local actual_achievement_points = pc . getqf ( "achievement_points" ) local p = select ( "Caballo armado - 5 puntos" , "Caballo militar - 30 puntos" , "Bonus mediohumanos +20% por 30min - 50 puntos" , "Bonus HP +5000 por 30min - 60 puntos" , "Armadura divina - 400 logros" , "Mascota de ataque - 30 puntos" , "Mas" ) if p == 1 then if pc . getqf ( "achievement_points" ) <= 4 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 5 ) say ( "Has recibido un caballo armado" ) horse . set_level ( "11" ) horse . unsummon ( ) horse . summon ( ) pc . give_item2 ( "50052" , 1 ) return elseif p == 2 then if pc . getqf ( "achievement_points" ) <= 29 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 30 ) say ( "Has recibido un caballo militar" ) horse . set_level ( "21" ) horse . unsummon ( ) horse . summon ( ) pc . give_item2 ( "50053" , 1 ) return elseif p == 3 then if pc . getqf ( "achievement_points" ) <= 49 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 50 ) say ( "Has recibido 20% fuerza contra mediohumanos por 30min" ) affect . add_collect ( apply . ATTBONUS_HUMAN , 20 , 60 * 30 ) return elseif p == 4 then if pc . getqf ( "achievement_points" ) <= 59 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 60 ) say ( "Has recibido 5000hp por 30min" ) affect . add_collect ( apply . MAX_HP , 5000 , 60 * 30 ) return elseif p == 5 then if pc. getqf ( "achievement_points" ) <= 399 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 399 ) local armor = select ( "Armd. divina (G)" , "Armd. divina (N)" , "Armd. divina (S)" , "Armd. divina (C)" ) if armor == 1 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "42080" , 1 ) return elseif armor == 2 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "44080" , 1 ) return elseif armor == 3 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "46080" , 1 ) return elseif armor == 4 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "48080" , 1 ) return end elseif p == 6 then if pc . getqf ( "achievement_points" ) <= 29 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 29 ) say ( "Has recibido la mascota de ataque" ) pc . give_item2 ( "30312" , 1 ) return elseif p == 7 then local p2 = select ( "Leon Blanco - 40 puntos" , "Anillo experiencia - 5 puntos" , "Fuerza monstruo +20% 30min - 15 puntos" , "Velocidad movimiento +25% 30min - 10 puntos" , "Mascota de defensa - 25 puntos" , "Cuantos logros tengo?" , "Cerrar" ) if p2 == 1 then if pc . getqf ( "achievement_points" ) <= 39 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 40 ) say ( "Has recibido un leon blanco disfrtualo, no se acaba" ) pc . give_item2 ( "50110" , 1 ) return elseif p2 == 2 then if pc . getqf ( "achievement_points" ) <= 4 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 5 ) say ( "Disfruta de un anillo de experiencia" ) pc . give_item2 ( "71015" , 1 ) return elseif p2 == 3 then if pc . getqf ( "achievement_points" ) <= 14 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 15 ) say ( "Has recibido 20% fuerza monstruo por 30min" ) affect . add_collect ( apply . ATTBONUS_MONSTER , 20 , 60 * 30 ) return elseif p2 == 4 then if pc . getqf ( "achievement_points" ) <= 9 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 10 ) say ( "Has recibido 25% velo.movimiento por 30min" ) affect . add_collect ( apply . MOV_SPEED , 25 , 60 * 30 ) return elseif p2 == 5 then if pc . getqf ( "achievement_points" ) <= 24 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 25 ) say ( "Has recibido la mascota de defensa" ) pc . give_item2 ( "71124" , 1 ) return elseif p2 == 6 then local Reward = 0 local Achievement = "Ver_tus_logros" local killcount = pc.getqf("logros") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") elseif p2 == 7 then return end end end --METINS when 8013.kill begin local Reward = 8 local Achievement = "Metin_muerte" local killcount = pc.getqf("8013") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("8013", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_destruido#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 8016.kill begin local Reward = 5 local Achievement = "Metin_demonio" local killcount = pc.getqf("8016") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("8016", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_destruido#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 8012.kill begin local Reward = 6 local Achievement = "Metin_caida" local killcount = pc.getqf("8012") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("8012", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_destruido#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 8015.kill begin local Reward = 5 local Achievement = "Metin_dureza" local killcount = pc.getqf("8015") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("8015", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_destruido#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 8026.kill begin local Reward = 2 local Achievement = "Metin_85" local killcount = pc.getqf("8026") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("8026", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_destruido#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end when 8027.kill begin local Reward = 3 local Achievement = "Metin_90" local killcount = pc.getqf("8027") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("8027", killcount + 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_destruido#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") end --LEVELS when login or levelup with pc.get_level() >= 15 and pc.getqf("Level15") != 1 begin local Reward = 2 local Achievement = "Level_15" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level15", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 30 and pc.getqf("Level30") != 1 begin local Reward = 2 local Achievement = "Level_30" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level30", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 40 and pc.getqf("Level40") != 1 begin local Reward = 3 local Achievement = "Level_40" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level40", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 50 and pc.getqf("Level50") != 1 begin local Reward = 4 local Achievement = "Level_50" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level50", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 75 and pc.getqf("Level75") != 1 begin local Reward = 5 local Achievement = "Level_75" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level75", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 85 and pc.getqf("Level85") != 1 begin local Reward = 10 local Achievement = "Level_85" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level85", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 90 and pc.getqf("Level90") != 1 begin local Reward = 25 local Achievement = "Level_90" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level90", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 95 and pc.getqf("Level95") != 1 begin local Reward = 50 local Achievement = "Level_95" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level95", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end when login or levelup with pc.get_level() >= 99 and pc.getqf("Level99") != 1 begin local Reward = 100 local Achievement = "Level_99" local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("Level99", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_alcanzado%".. actual_achievement_points + Reward .."") end --CHECK EQUIP when login begin loop_timer("check_eq", 10) end when check_eq.timer begin local russi = pc.get_armor() local waffe = pc.get_weapon() local actual_achievement_points = pc.getqf("achievement_points") local Reward = 5 if russi==11299 and pc.getqf("achievement_ssp") != 1 then pc.setqf("achievement_ssp", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Armadura negra+9%".. actual_achievement_points + Reward .."") elseif russi==11499 and pc.getqf("achievement_swa") != 1 then pc.setqf("achievement_swa", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Armadura negra+9%".. actual_achievement_points + Reward .."") elseif russi==11699 and pc.getqf("achievement_mpp") != 1 then pc.setqf("achievement_mpp", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Armadura negra+9%".. actual_achievement_points + Reward .."") elseif russi==11899 and pc.getqf("achievement_sk") != 1 then pc.setqf("achievement_sk", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Armadura negra+9%".. actual_achievement_points + Reward .."") elseif waffe==189 and pc.getqf("achievement_gifti") != 1 then pc.setqf("achievement_gifti", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Giftschwert+9%".. actual_achievement_points + Reward .."") elseif waffe==199 and pc.getqf("achievement_lowenschw.") != 1 then pc.setqf("achievement_lowenschw.", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Löwenschwert+9%".. actual_achievement_points + Reward .."") elseif waffe==5129 and pc.getqf("achievement_orchiglocke") != 1 then pc.setqf("achievement_orchiglocke", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Orchideenglocke+9%".. actual_achievement_points + Reward .."") elseif waffe==2179 and pc.getqf("achievement_krahenstahl") != 1 then pc.setqf("achievement_krahenstahl", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Krähenstahlbogen+9%".. actual_achievement_points + Reward .."") elseif waffe==1139 and pc.getqf("achievement_teufelsflugenchak") != 1 then pc.setqf("achievement_teufelsflugenchak", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Teufelsflügel-Chakram+9%".. actual_achievement_points + Reward .."") elseif waffe==3169 and pc.getqf("achievement_Grolli") != 1 then pc.setqf("achievement_Grolli", 1) pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement Grollschwert+9%".. actual_achievement_points + Reward .."") end end end end Y para que no os quedeis simplemente metiendo la quest y ya ta os voi a explicar como funciona:
     
    1 - Lo mas importante de los logros es que cuando alcanzas uno (por ejemplo matar al jefe orco) te suma puntos mediante un pc.setqf:
     

    when 691.kill begin local Reward = 2 pc.setqf("achievement_points", actual_achievement_points + Reward) Como veis ahí al jefe orco (mob de id 691) le asigna los puntos que vale con local Reward = 2 y luego te suma 2 puntos con el pc.setqf("achievement_points", actual_achievement_points + Reward (el reward en este caso seria un +2).
     
    Por lo tanto si quereis añadir otro mob a la lista de logros solo tendreis que hacer lo siguiente:
     

    when idmob.kill begin local Reward = puntos -- Poneis cuantos puntos quereis que os de local Achievement = "Nombre del mob que saldra en el cliente" local killcount = pc.getqf("idmob") -- Se usa para que el juego lleve la cuenta de cuantas veces lo mataste local actual_achievement_points = pc.getqf("achievement_points") -- Calcula cuantos puntos tenes pc.setqf("693", killcount + 1) -- Aqui os suma 1 al numero de ese mob que llevais pc.setqf("achievement_points", actual_achievement_points + Reward) -- aqui te suma tus puntos por matarlo cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") -- Con esto te saldra la ventana en el cliente diciendo que lo mataste y cuantos puntos tenes end Ahora os enseñare como hacer los canjes. En mi caso los canjes se hacen mediante un item, pero vosotros podeis hacerlo como querais simplement cambiando el when iditem.use por un when npc.chat."Canje de Logros" o como os apetezca.
     
    Veamos como tengo yo los canjes:
     

    when 50115.use begin say_title ( "Canjea tus puntos logro" ) local actual_achievement_points = pc . getqf ( "achievement_points" ) local p = select ( "Caballo armado - 5 puntos" , "Caballo militar - 30 puntos" , "Bonus mediohumanos +20% por 30min - 50 puntos" , "Bonus HP +5000 por 30min - 60 puntos" , "Armadura divina - 400 logros" , "Mascota de ataque - 30 puntos" , "Mas" ) if p == 1 then if pc . getqf ( "achievement_points" ) <= 4 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 5 ) say ( "Has recibido un caballo armado" ) horse . set_level ( "11" ) horse . unsummon ( ) horse . summon ( ) pc . give_item2 ( "50052" , 1 ) return elseif p == 2 then if pc . getqf ( "achievement_points" ) <= 29 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 30 ) say ( "Has recibido un caballo militar" ) horse . set_level ( "21" ) horse . unsummon ( ) horse . summon ( ) pc . give_item2 ( "50053" , 1 ) return elseif p == 3 then if pc . getqf ( "achievement_points" ) <= 49 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 50 ) say ( "Has recibido 20% fuerza contra mediohumanos por 30min" ) affect . add_collect ( apply . ATTBONUS_HUMAN , 20 , 60 * 30 ) return elseif p == 4 then if pc . getqf ( "achievement_points" ) <= 59 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 60 ) say ( "Has recibido 5000hp por 30min" ) affect . add_collect ( apply . MAX_HP , 5000 , 60 * 30 ) return elseif p == 5 then if pc. getqf ( "achievement_points" ) <= 399 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 399 ) local armor = select ( "Armd. divina (G)" , "Armd. divina (N)" , "Armd. divina (S)" , "Armd. divina (C)" ) if armor == 1 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "42080" , 1 ) return elseif armor == 2 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "44080" , 1 ) return elseif armor == 3 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "46080" , 1 ) return elseif armor == 4 then say ( "Has recibido la Armadura divina" ) pc . give_item2 ( "48080" , 1 ) return end elseif p == 6 then if pc . getqf ( "achievement_points" ) <= 29 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 29 ) say ( "Has recibido la mascota de ataque" ) pc . give_item2 ( "30312" , 1 ) return elseif p == 7 then local p2 = select ( "Leon Blanco - 40 puntos" , "Anillo experiencia - 5 puntos" , "Fuerza monstruo +20% 30min - 15 puntos" , "Velocidad movimiento +25% 30min - 10 puntos" , "Mascota de defensa - 25 puntos" , "Cuantos logros tengo?" , "Cerrar" ) if p2 == 1 then if pc . getqf ( "achievement_points" ) <= 39 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 40 ) say ( "Has recibido un leon blanco disfrtualo, no se acaba" ) pc . give_item2 ( "50110" , 1 ) return elseif p2 == 2 then if pc . getqf ( "achievement_points" ) <= 4 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 5 ) say ( "Disfruta de un anillo de experiencia" ) pc . give_item2 ( "71015" , 1 ) return elseif p2 == 3 then if pc . getqf ( "achievement_points" ) <= 14 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 15 ) say ( "Has recibido 20% fuerza monstruo por 30min" ) affect . add_collect ( apply . ATTBONUS_MONSTER , 20 , 60 * 30 ) return elseif p2 == 4 then if pc . getqf ( "achievement_points" ) <= 9 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 10 ) say ( "Has recibido 25% velo.movimiento por 30min" ) affect . add_collect ( apply . MOV_SPEED , 25 , 60 * 30 ) return elseif p2 == 5 then if pc . getqf ( "achievement_points" ) <= 24 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 25 ) say ( "Has recibido la mascota de defensa" ) pc . give_item2 ( "71124" , 1 ) return elseif p2 == 6 then local Reward = 0 local Achievement = "Ver_tus_logros" local killcount = pc.getqf("logros") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") elseif p2 == 7 then return end end end *Si os fijais la ultima opcion de la tienda de canjes te permite ver tus logros, para ello le hice un logro que te sume 0 puntos pero que te enseña cuantos tienes:
     

    elseif p2 == 6 then local Reward = 0 local Achievement = "Ver_tus_logros" local killcount = pc.getqf("logros") local actual_achievement_points = pc.getqf("achievement_points") pc.setqf("achievement_points", actual_achievement_points + Reward) cmdchat("achievement ".. Achievement .."_derrotado#".. killcount + 1 .."%".. actual_achievement_points + Reward .."") Asi que si necesitais hacer vuestra opcion de ver logros ahi teneis
     
    Tal como eso son todos los canjes, si quereis hacer vuestros propios canjes os hago aqui un pequeño script de canje para explicaros como seria:
     
     

    when 20095.chat."Canjear mis logros" begin say_title("Canjear mis logros") say("") say("Hola jugador, si tienes logros") say("yo te los puedo cambiar por cositas.") say("") say("Si no tienes intenta conseguir alguno") say("porque merece la pena") say("") say_reward("Quieres canjear tus punots?") local canje = select ("Si" , "No") if canje == 1 then say_title("Canjes de logros") say("") say("Elige lo que quieras") local elegir = select ("Quinto bonus - 3 logros" , "Añadir 6-7 bonus - 4 logros" , "Cambiar 6-7 bonus - 5 logros" , "Caballo armado - 6 logros" , "Caballo militar - 8 logros" , "Cerrar") if elegir == 1 then if pc . getqf ( "achievement_points" ) <= 2 then chat( "Lo siento necesitas mas puntos" ) return end pc.give_item2("70024", 1) local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 3 ) return elseif elegir == 2 then if pc . getqf ( "achievement_points" ) <= 3 then chat( "Lo siento necesitas mas puntos" ) return end pc.give_item2("71051", 1) local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 4 ) return elseif elegir == 3 then if pc . getqf ( "achievement_points" ) <= 4 then say ( "Lo siento necesitas mas puntos" ) return end pc.give_item2("71052", 1) local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 5 ) return elseif elegir == 4 then if pc . getqf ( "achievement_points" ) <= 5 then chat( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 6 ) chat ( "Has recibido un caballo armado" ) horse . set_level ( "11" ) horse . unsummon ( ) horse . summon ( ) pc . give_item2 ( "50052" , 1 ) return elseif elegir == 5 then elseif p == 2 then if pc . getqf ( "achievement_points" ) <= 7 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 8 ) chat( "Has recibido un caballo militar" ) horse . set_level ( "21" ) horse . unsummon ( ) horse . summon ( ) pc . give_item2 ( "50053" , 1 ) return elseif elegir == 6 then return end elseif canje == 2 then return end end Este script es un pequeño regalo para vosotros, lo hice ahora para que podais usar otro si no quereis el que tenia en el extasis.
     
    *Para meterla en vuestra quest podeis quitar mi tienda de canjes y pegar esta si quereis, o hacerla como quest separada.
     
    Por ultimo os explicare como funcionan los canjes con un ejemplo:
     

    local p = select ( "Caballo armado - 5 logros") if p == 1 then if pc . getqf ( "achievement_points" ) <= 4 then say ( "Lo siento necesitas mas puntos" ) return end local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 5 ) say ( "Has recibido un caballo armado" ) horse . set_level ( "11" ) horse . unsummon ( ) horse . summon ( ) pc . give_item2 ( "50052" , 1 ) return Empieza con un local = select para que escojais vuestro premio y os aconsejo que pongais ahi cuantos logros cuesta como hice yo.
     
    Luego puse una restriccion para que si teneis menos puntos que los que pide el item no os deje comprarlo:
     

    if pc . getqf ( "achievement_points" ) <= 2 then chat( "Lo siento necesitas mas puntos" ) return end Funciona de la siguiente manera: donde pone <= 2 teneis que poner un punto menos que los que pide, ya que eso dice que si tienes esos puntos o menos no te deje comprar.
     
    Despues del return end ya solo teneis que poner el comando para que os quite los puntos que es este:
     

    local actual_achievement_points = pc . getqf ( "achievement_points" ) pc . setqf ( "achievement_points" , actual_achievement_points - 5 ) --Poneis ahi los que quereis que quite Y lo que quereis que os dea justo debajo de esas dos lineas:
     

    pc.give_item2("71052", 1) --- Ahi poned lo que quereis que dea Y eso es todo zoneros, que disfruteis del sistema de logros !!!
     
    Creditos: al creador del sistema (que no es mio xd) y a mi por la parte de la quest mia y la traduccion de la original.
  22. Me Gusta
    fuuton97 reacted to cristianvar in Función para evitar inyecciones SQl con PHP   
    Bueno, muchas veces me he topado con un monton de webs con una pequeña vulnerabilidad que permite realizar inyecciones de código SQL por medio de un formulario (ya sea el de registro, el de login u otros) o utilizando la barra de direcciones (osea, el método GET). Esto permite al atacante, acceder a la base de datos y modificar (editar, eliminar, etc) cualquier contenido que haya en ella.
     
    Para evitar este tipo de ataques vamos a utilizar una pequeña función que sustituye todos los carácteres especiales para ejecutar sentencias SQL y, ya que estamos, también eliminamos cualquier tipo de etiqueta HTML que haya de por medio.
     
    Vamos a ver la función:
     
    #Edito: el código estaba mal, la función es mysql_real_escape_string(), no mysql_real_string(). Pequeño error, pero ya lo corregí.
     

    <?php function limpiar($contenido) { $contenido = strip_tags($contenido); $contenido = mysql_real_escape_string($contenido); return $contenido; } ?> Para ponerlo a funcionar podríamos utilizar este ejemplo:
     

    <?php $usuario = limpiar($_POST['usuario']); ?> O, si utlizamos el método GET, podemos usar este código:
     

    <?php $usuario = limpiar($_GET['usuario']); ?>  
    Todo el tema de seguridad es muy importante a la hora de crear una página web, y aún más si es para un servidor de Metin2, ya que hay mucha gente ociosa a la que le divierte fastidiar.
     
    A los que les interese todo el tema de seguridad, pueden ver esta guía en PDF bastante útil:
    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
     
     
    Espero que os sirva esto y si teneis alguna duda, estaré encantado de intentar ayudaros en lo que pueda.
     
     
    Saludos.
  23. Me Gusta
    fuuton97 got a reaction from dur metin2 in [NEW]Cliente By Gherusio 2012 v.3.   
    Buenas, pasando por inforge me encontré con el cliente de Gherusio 2012 en su versión 3, yo ya habia posteado su cliente versión 1, en fin este trae texturas de catatumbas, item nuevos, monturas, efectos de habilidades nuevos, entre otras cosas.
     
    Datos tecnicos del Cliente ~
     
    Cliente optimizado exclusivamente para el archivo de 2010/2011 con un juego rev2089.
    Servidores dedicados para los clientes, bueno para los que quieren ser un estilo antiguo servidor.
    Las implementaciones de cliente que TODOS los servidores oficiales.
    Louncher 4 MB, uno de los mejores, ya que tiene el PONG: 1234abcd5678efgh
    Pvt. de chat con los clientes y sbuggati.
    Cliente llega a 702MB comprimido y descomprimido 893MB alcances.
    Para iniciar sesión en el servidor, por supuesto, usted puede descomprimir root.epk / eix situado en los parches y serverinfo.py modding (dentro de la serverinfo.py entra en una pequeña gui­a, sencilla para modding).
    Moddando asi serverinfo.py también puede entrar en host de servidores dedicados que no.
     
    ~Nuevo Levelup Effect~

     
    ~The Devils Catacomb~


     
    Los comandos de los mapas de las catacumbas (Debes tener el mapa implementado).
     
    Warp: 3072 12032
    Comandos de mapas :
    1º /go 80 60
    2° /go 545 43
    3° /go 500 728
    4° /go 297 322
    5° /go 845 899
    6° /go 1300 700
    7° /go 74 1110
     
    ~Nuevos Item's~

     
    Armadura de la misma del él .es con su brillo correspondiente:

     
    Monturas:
     







     
    Cliente REUPLOAD BY SEREX (METIN2 ELEMENTS HOST)
    Descarga:
    Debes iniciar sesión para ver el contenido del enlace en esta publicación.  
     
    Este cliente es perfecto para aquellos que quieren hacer un sever como el .es pero mejor, tal y como @Metin2Panamera.
     
    Créditos:

     
     
     
    Saludes!
×
×
  • Crear nuevo...