Saltar al contenido

Más en DLAN: Nuestras Traducciones | Otras Traducciones | Mods y modding | Revisiones y Guías | Videojuegos | Arte | Literatura | Rol y Rol por foro e IRC | Mapa de la web
Foto

Mundos Persistentes, ¿tutorial?


71 respuestas al tema

#1 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 28 June 2005 - 10:49 PM

Saludos.

Bien, tengo por aquí y alla retazos de instrucciones de como hacer un modulo más o menos. La información proviene de mí (fuente nada fiable ???) y gente y destripes de scripts del never y enseñanzas de la gente (fuente fiable). Según vaya terminando iré pegandolo por aquí, salvo que moleste a los administradores, que en ese caso me den un toque (Puede llegar a ser mucha letra).

Txibi.

#2 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 28 June 2005 - 10:50 PM

1.0 - Las Ideas claras, nomenclatura.

Antes de nada hay que tener muy claro como organizar el asunto, a los viejos usuarios de MS-DOS lo pillarán fácil, ya que la lista de nombres a la izquierda con pocas palabras y en orden alfabético les puede sonar.

De entrada toda etiqueta como MÁXIMO puede tener 16 letras o conjunto de letras y/o caracteres soportados.

Algo muy común es poner una etiqueta y olvidarse del resref, malo, posiblemente fuente de estúpidos errores tontos en el futuro

Es decir si creais un área y la llamais Bosque del los Enanos Zapadores I,

Nombre: Bosque de los Enanos Zapadores I
Etiqueta: BosquedelosEnanosZapadoresI
resref: bosquedelosenano


Si ahora creais una segunda área y la llamais Bosque del los Enanos Zapadores II sería...

Nombre: Bosque de los Enanos Zapadores II
Etiqueta: BosquedelosEnanosZapadoresII
resref: bosquedelosen001


Esto pasa si lo hace uno, ¿pero qué pasa si una de esas áreas la hubiese hecho una persona diferente?

Aurora A:

Nombre: Bosque de los Enanos Zapadores I
Etiqueta: BosquedelosEnanosZapadoresI
resref: bosquedelosenano


Aurora B:

Nombre: Bosque de los Enanos Zapadores II
Etiqueta: BosquedelosEnanosZapadoresII
resref: bosquedelosenano


Ordenador Destino Server, Aurora C:

Nombre: Bosque de los Enanos Zapadores I
Etiqueta: BosquedelosEnanosZapadoresI
resref: bosquedelosenano
Nombre: Bosque de los Enanos Zapadores II
Etiqueta: BosquedelosEnanosZapadoresII
resref: bosquedelosenano ==> NOMBRE RESREF EXISTENTE, PETARDAZO, ERROR GRAVE DE AURORA Y JALEOS VARIOS.

En este caso, mínimo hay que rehacer áreas, eso si se sabe por que casca el aurora.

Coger como costumbre al EMPEZAR cualquier cosa que tenga etiqueta y resref, máximo 16 letras, y las tres o cuatro primeras reservadas para el autor; por ejemplo que Gutierrez hace el bosque dichoso de arriba, pues pone cuando le pide el nombre de area: gut_bos_zap_1 con lo cual incialmente queda:

Nombre: gut_bos_zap_1
Etiqueta: gut_bos_zap_1
resref: gut_bos_zap_1


Luego tranquilamente edita el nombre que se muestra (pestaña basico, nombre, encima de con. bald.) y pone por ejemplo Bosque de los Enanos Zapadores I.

Nombre: Bosque de los Enanos Zapadores I.
Etiqueta: gut_bos_zap_1
resref: gut_bos_zap_1


Que hace Ali Baba la segunda área, pues que ponga por ejemplo en nombre al empezar el área ali_bos_zap_2

Código:
Nombre: ali_bos_zap_2
Etiqueta: ali_bos_zap_2
resref: ali_bos_zap_2

Luego edita el nombre y listo.

Código:
Nombre: Bosque de los Enaos Zapadores II.
Etiqueta: ali_bos_zap_2
resref: ali_bos_zap_2

Asi se deberían evitar todos los problemas de resref defectuosas porque se corta el nombre y de duplicados que causan caida del aurora.

Con los objetos lo mismo, cuando os pida el NOMBRE, poner lo que será el resref y etiqueta, porque por defecto lo pone para nombre, etiqueta y resref. Luego podeis cambiar el nombre y la etiqueta, pero no podeis cambiar la resref, salvo que creeis una copia.

Ahora no modifiqueis todo, pero para lo que se haga a partir de ahora ir implantandolo poco a poco, el lag del server os lo agradecerá.

Veamos, para notación se puede dejar provisionalmente así, luego los autores que escogan la "firma" que quieran, pero no reserveis más de 4 letras para marcar vuestras áreas u objetos o no quedará casi nada para nombrar el resto de la etiqueta o resref.

Posibles ejemplos de notación de scripters:

Misi => misi_
Txibi => tx_
Devil => dev_
Celsum => cel_
Dommino=> dom_
Colt=> colt_
Jhonny=> jhon_
Solemmgar => sol_
Zooky => zok_
Neverwinter => nw_

Luego seguiremos con notas de áreas básicas.

Txibi.

Editado por Txibi, 02 February 2011 - 03:08 PM.


#3 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 28 June 2005 - 10:51 PM

1.1 Empezando el módulo, creando el área inicial

Bien, vamos a empezar a utilizar el aurora. Ya tenemos pensado que vamos a hacer y un boceto en papel, también hemos tenido en cuenta la nomenclatura (1.0 - Las Ideas claras, nomenclatura.) así que haremos los pasos previos para el área inicial.

Los que hayan trasteado en el aurora, encontrarán esto, tal vez, sencillo. Que le echen un ojo rápido y que pasen al punto 1.2 El Esqueleto.

Empezando. Abres el aurora, le dices que quieres crear un nuevo módulo...
mod_ini_01.jpg
Borramos el nombre por defecto del aurora y ponemos algo más sugerente, vamos a llamarle brujería, escribimos tx_brujería (hala, mirar nomenclatura, por si alguna se pregunta el porque del tx_ delante de brujería).
mod_ini_02.jpg
Creamos una nueva área que llamaremos inicio, en mi caso, pondré tx_inicio, pero vosotros podeis llamarla como os salga mientras mantengais un orden.
mod_ini_03.jpg
El área inicial,siempre interesan que sea pequeña, porque es lo primero que se cargará junto con el resto del módulo. No es agradable que tarde una eternidad en cargar el servidor cuando entramos por primera vez.
mod_ini_04.JPG
Vale, tenemos nuestra área inicial, pero observamos que se llama tx_inicio, así que lo primero que haremos es ponerle un nombre más amigable, por ejemplo, le llamaremos al ára inicial, El Descenso.
Seleccionamos Editar, Propiedades de Área:
mod_ini_05.JPG
Y le cambiamos el nombre, agruparemos todas las área "básicas" empezando primera letra por un número o carácter idéntico para tenerlas en un bloque, yo pondré un cero.
mod_ini_06.JPG
En caso de que no guste el nombre elegido para el modulo, pues se guarda con otro nombre y listo. Vamos ha llamarlo ahora Las Runas de La Profecía, mmm nombre largo, posiblemente la gente conozca el server como el server de "Las Runas". Si es posible, darle un nombre corto al server o módulo. Y así la gente no le buscará diminutivos.
Nos quedaría posiblemente así.
mod_ini_07.JPG

Ahora se podría pensar que hay que diseñar áreas, comerciantes, monstruos y tenderos.

Pues no.

El siguiente paso es el más temido de un server, vamos a por El Esqueleto..

Txibi.


Editado por Txibi, 05 February 2015 - 03:35 PM.


#4 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 28 June 2005 - 10:52 PM

1.2 El Esqueleto.

Bien, vamos poco a poco a ir perfilando el esqueleto. No haremos ninguna maravilla, pero intentaremos hacer una serie de puntos básicos.

Para ello retocaremos los guiones o scripts generales del módulo. Para ello nos toca Editar, Propiedades del Módulo, Sucesos.

Más o menos empezaremos con este conjunto de scripts (o guiones).
mod_esq_01.jpg
Y terminaremos con este otro conjunto, más o menos.
mod_esq_02.jpg

Haremos un pequeño limbo, para que cuando mueran nuestros sufridos jugadores y le den a regenerar no se levanten sin más del suelo.
También crearemos un libro de habilidades para que puedan utilizar sus habilidades.
Añadiremos un sistema simple de comida y sueño, para que tengan que esperar 8 horas entre descanso y descanso.
Daremos un equipo básico al jugador que entre por primera vez y le subiremos a nivel tres, al tiempo que lo dejaremos sin el equipo por defecto.
Y llevaremos la cuenta de sus puntos de vida, por si se cae y vuelve a entrar esté con la vida que tenía. Así como un sistema básico de desangrado.

Y todo con los jodíos scripst, lo que es la vida.

Descanso y luego empezamos.

Txibi.


Editado por Txibi, 05 February 2015 - 03:36 PM.


#5 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 28 June 2005 - 10:53 PM

...El Esqueleto...

Bien, vamos a empezar con el área del limbo, aunque por ahora nuestro módulo está muerto, ya que el esqueleto o motor interno aún no ha sido definido.

Creamos un área que inicialmente llamaré tx_limbo y luego le cambio el nombre a 0 - El Limbo. Podría servirnos un área tipo interior de ciudad para este pequeño limbo. Ya que algunos jugadores se pasan más tiempo arriba que abajo, haremos una pequeña taberna espectral.

Necesitaremos un punto de ruta al que mandar a los muertos, escogeremos uno y le llamaremos tx_limbo, acordaros de que no podrá haber dos puntos de ruta iguales en el módulo. Por ahora ya nos vale, luego volveremos aquí.

También crearemos dos pequeñas áreas iniciales.

La primera será un área que sólo visitarán una vez, en la que serán equipados con lo básico según su profesión y en el que se les dará algo de nivel, está área en las visitas posteriores no será visitada.

La segunda será el área inicial donde ya están en el módulo propiamente dicho, para empezar nos bastará una bucólica llanura con un edificio de madera. La Posada (un clásico de las partidas de mesa, jeje).

Para el equipo, tx_equipo (otros podrían poner iniciacion, etc...), mapa pequeño. Luego cambio el nombre a 0 - Equipo.

La siguiente área será la llanura que recibe a los PJs en tierra (tx_llanura) que llamaremos 0 - Las llanuras fronterizas. Aquí escogeremos mapa medio. En grupos cogemos una posada y la plantamos.

Creamos el área de la posada, será una posada simple, de un piso. Mapa pequeño, interior ciudad, tx_posada, renombrada luego a 0 - Posada Colmillo Rojo.

Bien. Ya tenemos 5 áreas mínimas para empezar a trabajar en el esqueleto.

Txibi.

#6 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 28 June 2005 - 10:54 PM

...El Esqueleto...

Vamos alla, salva el módulo si no lo has hecho todavía y continuemos.

Editar, propiedades del módulo, sucesos.

Seleccionamos OnHeartBeat, pinchamos en editar, automáticamente se abré el guión estandar.

sinttulo
void main()
{

}

Que cambiaremos por este, yo lo llamo 0_tx_guarda pero tu como quieras mientras te aclares. Este pequeño script cada cierto tiempo guarda las fichas de los jugadores del módulo sin tener que estar soportando la pantalla de "guardando" (vamos no se enteran). No consume casi recursos.

Un script en OnHeartBeat se dispara cada 6 segundos por lo cual mirar que sean cosas que no chupen apenas recursos.

/*
script 0_tx_guarda a colocar en OnHeartbeat de propiedades del módulo.
*/

void main()
{
    //Guarda las fichas cada cierto tiempo.
    int nTiempo = GetLocalInt(OBJECT_SELF, "Tiempo");
    SetLocalInt (OBJECT_SELF, "Tiempo", ++ nTiempo);

    if (nTiempo >=200)
    {
        //Como el OnHeartBeat lanza un envento cada 6 segundos, se pone un contador...
        SetLocalInt (OBJECT_SELF, "Tiempo", 0);
        ExportAllCharacters(); //Salvamos las fichas...
    }
}

Bien, aparte queremos tener un control básico sobre las entradas y salidas de nuestros PJs, en salidas vamos a colocar un script que guarde su vida aunque se reinice el server. Editamos OnClientLeave.

/*
script 0_tx_saliendo a colocar en OnClientLeave
*/
void main()
{
    object oJugador = GetExitingObject();
    string sRIP = ObjectToString(GetModule());
    RemoveEffect(oJugador, EffectPolymorph(SPELL_POLYMORPH_SELF));
    SetCampaignInt(sRIP, GetName(oJugador), GetCurrentHitPoints(oJugador));
}//Fin Cuerpo Principal.

Y también vamos a crear un control de entradas, ¡OJO! Este esta bastante más abultado, porque se han colocado varias cosas que serán necesarias más adelante. En el script de entrada en donde se validan los personajes, por eso mirará su inventario y según lo que tengan o no tengan sucederán varias cosas.

/*
script 0_tx_entrando a colocar en OnClientEnter
*/

int IsInInventory(object oContainer, string sItemTag)
{
object oItem;

if (GetHasInventory(oContainer))
{
    oItem = GetFirstItemInInventory(oContainer);
    while ( OBJECT_INVALID != oItem )
    {
        if (GetTag(oItem) == sItemTag)
        { return TRUE; }
        oItem = GetNextItemInInventory(oContainer);
    } // end while
} // endif
return FALSE;
} // end IsInInventory

#include "nw_i0_plot"

void main()
{
    object oJugador = GetEnteringObject();
    int iVidaMaxima = GetMaxHitPoints(oJugador);
    string sRIP = ObjectToString(GetModule());
    int iVidaActual = GetCampaignInt(sRIP, GetName(oJugador));

    string sSubRaza = GetSubRace(oJugador);
    int iNivel = GetHitDice(oJugador);

    //Por si tienen mas vida que la permitida, por bugs de transformaciones.
    if (iVidaActual >= iVidaMaxima)
    {
        RemoveEffect(oJugador, EffectTemporaryHitpoints(EFFECT_TYPE_TEMPORARY_HITPOINTS));

    }//fin de disipacion de puntos de vida por encima de lo normal.


    if ((iVidaActual>0) || (iVidaActual<0))
    {
        effect eActualizarVida = EffectDamage((iVidaMaxima-iVidaActual), DAMAGE_TYPE_MAGICAL, DAMAGE_POWER_ENERGY);
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eActualizarVida, oJugador);

    }//fin actualizar vida.




    //ZONA DE TESTEO DE OBJETOS DE ENTRADA.

    //----------------------------------------------------------------------
    //Si el jugador esta muerto en el ultimo reinicio, hala, al limbo.
    if (IsInInventory(oJugador,"tx_muerto"))
    {
        AssignCommand(oJugador, JumpToObject(GetObjectByTag("tx_Limbo")));
        SendMessageToPC(oJugador,"Estas muerto todavia, tu lugar es el Limbo");
    }//fin libro de mirar si esta muerto.
    //----------------------------------------------------------------------
    //Libro de habilidades.
    if (!IsInInventory(oJugador,"tx_librohab_1"))
    {
        CreateItemOnObject("tx_librohab_1", oJugador);//Crea el libro en el jugador.
        SendMessageToPC(oJugador,"Se te ha dado un libro para que uses tus habilidades");
    }//fin libro de habilidades.
    //----------------------------------------------------------------------
    //Excomulgacion General.
    if (IsInInventory(oJugador,"tx_excomulgacion"))
    {
        ExecuteScript("tx_excomulgacion", oJugador);
    }
    //----------------------------------------------------------------------
    //Crucifijo del Paladin.
    if (GetLevelByClass(CLASS_TYPE_PALADIN, oJugador) >= 1)
    {
        if (!IsInInventory(oJugador,"tx_crucifijo"))
        {
            CreateItemOnObject("tx_crucifijo", oJugador);
            SendMessageToPC(oJugador,"Se te ha dado un simbolo sagrado para detectar el mal.");
        }
    }//fin crucifijo del paladin..
    //----------------------------------------------------------------------
    //Guarda mas informacion en el LOG.
    //Si es un jugador extrae la informacion adicional.
    if (GetIsPC(oJugador) == TRUE)
    {
        string Jugador_IP = GetPCIPAddress(oJugador); // Direccion IP.
        string Jugador_CDKey = GetPCPublicCDKey(oJugador); // CDKey publica.
        string Jugador_Nombre = GetPCPlayerName(oJugador); // Nombre del jugador.
        int Jugador_Nivel_1 = GetLevelByPosition(1, oJugador); // Nivel de la clase 1.
        int Jugador_Nivel_2 = GetLevelByPosition(2, oJugador); // Nivel de la clase 2.
        int Jugador_Nivel_3 = GetLevelByPosition(3, oJugador); // Nivel de la clase 3.
        int Jugador_Nivel_Total = Jugador_Nivel_1 + Jugador_Nivel_2 + Jugador_Nivel_3; //Nivel total.
        int Jugador_XP = GetXP(oJugador); // Coge los puntos de experiencia acumulados.

        //Saca al archivo logs.0 la informacion.
        WriteTimestampedLogEntry("ENTRADA DEL JUGADOR -> Jugador: " + Jugador_Nombre +
        " / Direccion IP: " + Jugador_IP +  " / CDKey Publica : " + Jugador_CDKey + " / Nivel de la ficha: "
        + IntToString(Jugador_Nivel_1) + "/"
        + IntToString(Jugador_Nivel_2) + "/"
        + IntToString(Jugador_Nivel_3) + " Total: "
        + IntToString(Jugador_Nivel_Total) + " XP: " +  IntToString(Jugador_XP));
    }//fin de guarda de informacion en el LOG.
    //----------------------------------------------------------------------
}//fin cuerpo principal.

Bien por ahora descansaremos, luego tendremos que mirar el sistema de desangre, de descanso, de muerte y de profesión, paciencia...

Txibi.

#7 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 28 June 2005 - 11:36 PM

...El Esqueleto...

Continuemos, vamos a redefinir el comando de activación. Mi forma de hacerlo es obsoleta, ya que alguién inteligente se dio cuenta de que la mejor forma de conseguir y distinguir que script-objeto lanzar es que el script y el objeto tenga la misma etiqueta y con la orden de "ejecuta el script que coincida con la etiqueta del objeto" se soluciono un buen cacao, que es lo que trata el sistema de etiquetas de bioware.

Yo colocaré como lo hacía antes, pero al final también ejecutaremos el script-librería de bioware que salió a partir de la segunda expansión.

Primero vamos a Sucesos del Módulo, OnActivateItem, borramos lo que pone (x2_mod_def_act, no preocuparse que al final lo añadimos otra vez) y creamos un script que llamamos tx_activando (o como gusten).

/*
script 0_tx_activando a colocar en OnActivateItem
*/

void main()
{
    //--------------------------------------------------------------------------

    //Recordamos quiene es el jugador "activador"
    object oJugador = GetItemActivator();
    //Tambien controlamos que objeto estamos activando.
    object oArtefacto = GetItemActivated();
    //El objetivo para aquellos objetos que necesiten un "target", una diana.
    object oObjetivo = GetItemActivatedTarget();
    //El lugar destino de es una localizacion en vez de una criatura.
    location locDestino = GetItemActivatedTargetLocation();

    //--------------------------------------------------------------------------
    //Libro de Emociones.
    if(GetTag(oArtefacto) == "tx_librohab_1")
    {
        //Asignamos la orden de su uso, normalmente una conversacion o efecto.
        AssignCommand(oJugador, ActionStartConversation(oJugador, "tx_librohab_1", TRUE));
        return;
    }
    //--------------------------------------------------------------------------
    //Crucifijo del Paladin.
    if(GetTag(oArtefacto) == "tx_crucifijo")
    {
        //Asignamos la orden de su uso, utilizar la habilidad de paladin..
        ExecuteScript("tx_detectarelmal", oJugador);
        return;
    }
    //--------------------------------------------------------------------------
    //Madera.
    if(GetTag(oArtefacto) == "tx_madera")
    {
        //Asignamos la orden de su uso, crear una hoguera.
        CreateObject(OBJECT_TYPE_PLACEABLE, "tx_fogata", locDestino, TRUE);
        return;
    }
    //--------------------------------------------------------------------------

    //Otros bloques...

    //--------------------------------------------------------------------------

    //Ejecutamos tambien el script original de bioware.
    ExecuteScript("x2_mod_def_act", oJugador);

}//Fin del Cuerpo Principal.

Aquí miramos en los bloques que si coincide la etiqueta ejecute cierto script o ciertas líneas de código.

Nos queda el descanso y la muerte.

La muerte la dejamos para más abajo, ahora cogeremos el script subyacente a el descanso, que también se las trae.

Solo con el script del descanso no hacemos nada, (estamos haciendo sólo el esqueleto), más adelante habrá que crear el desencadenante del descanso y la comida.

Este script es tamaño medio ya.

Borramos lo que tengamos en OnPlayerRest y añadimos este script.

/*
script 0_tx_descanso a colocar en OnPlayerRest
*/

#include "nw_i0_tool"

void main()
{
    //Poniendo el Script de descanso por zonas.
    object oDescansemos = GetLastPCRested();

    int iDescansar = GetLocalInt(oDescansemos,"descansando");

    if (iDescansar != 1) //Si no esta a 1, anula el descanso.
    {
        AssignCommand(oDescansemos, ClearAllActions());
    }//fin del descanso por zonas.

    if (iDescansar==1)
    {//Cuerpo Central.

        //Inicializando las variables.
        int iHorasCadaDescanso = 8;
        object oModulo = GetModule();
        object oPJ = GetLastPCRested();
        int nVidaDormir = GetCurrentHitPoints(oPJ);
        string sPJNombre = GetName(oPJ);
        string sCDKey= GetPCPublicCDKey(oPJ);

        //Preparando el descanso.
        if (GetLastRestEventType() ==REST_EVENTTYPE_REST_STARTED)
        {
            SetLocalInt(oModulo,"Vida_Al_Dormir_" + sPJNombre + sCDKey, nVidaDormir);
            effect eDormir = EffectVisualEffect(VFX_IMP_SLEEP); //Efecto visual de dormir.
            //Si no ha pasado suficiente tiempo lo avisa.
            string sTextoDescanso = GetName(oPJ) + " no esta cansado aun.";
            //Mira cuando fue la ultima vez que descanso y activa las variables de tiempo.
            int iUltimaHoraDescanso = GetLocalInt(oModulo, ("UltimaHoraDescanso" + sPJNombre + sCDKey));
            int iUltimoDiaDescanso = GetLocalInt(oModulo, ("UltimoDiaDescanso" + sPJNombre + sCDKey));
            int iUltimoMesDescanso = GetLocalInt(oModulo, ("UltimoMesDescanso" + sPJNombre + sCDKey));
            int iUltimoAnualDescanso = GetLocalInt(oModulo, ("UltimoAnualDescanso" + sPJNombre + sCDKey));
            int iHora = GetTimeHour();
            int iDia = GetCalendarDay();
            int iMes = GetCalendarMonth();
            int iAnual = GetCalendarYear();
            int iNoDescansoDesde = 0;

            //Inicializa variables para la comida, objeto comestible que tenga come_ como comienzo de etiqueta.
            //Y para la bebida tambien, objeto ingerible que tenga bebe_ como comienzo de etiqueta.
            int nTieneComida;
            //int nTieneBebida;
            object oComida;
            //object oBebida;

            /*
               Prepara el calendario, para el never, todos los meses tienen 28 dias y todos los ciclos
            anuales son de 12 meses.
            */
            if (iUltimoAnualDescanso != iAnual)
            {
                iMes = iMes + 12;
            }
            if (iUltimoMesDescanso != iMes)
            {
                iDia = iDia + 28;
            }
            if (iDia != iUltimoDiaDescanso)
            {
                iHora = iHora + 24 * (iDia - iUltimoDiaDescanso);
            }

            //Comprueba cuanto tiempo hace desde el ultimo descanso.
            iNoDescansoDesde = iHora - iUltimaHoraDescanso;
            if(1)
            {
                //Comprobamos que hay comida.
                object oEquipo = GetFirstItemInInventory(oPJ);
                while(GetIsObjectValid(oEquipo))
                {
                    if(!FindSubString(GetTag(oEquipo),"come_"))
                    {
                        nTieneComida = 1;
                        oComida = oEquipo;
                        break;
                    }
                    oEquipo=GetNextItemInInventory(oPJ);
                }//fin while
            }//fin if(1)

            //Si no ha pasado el tiempo suficiene lo avisa con un mensaje.
            if (iNoDescansoDesde < iHorasCadaDescanso)
            {
                AssignCommand(oPJ, ClearAllActions());
                FloatingTextStringOnCreature(sTextoDescanso + " Intentalo otra vez en " + IntToString(iHorasCadaDescanso - iNoDescansoDesde) + " horas.", oPJ, FALSE);
            }

            //Si  no hay comida el hambre no deja dormir y avisa con un texto.
            else if (!nTieneComida)
            {
                AssignCommand(oPJ, ClearAllActions());
                SendMessageToPC(oPJ, "No puedes irte a dormir con el estomago vacio.");
            }
            else
            {
                //Actualizando variables, para empezar destruye una pieza de comida.
                int iComida =0;
                DestroyObject(oComida);
                SendMessageToPC(oPJ, "Has comido un poco.");

                //A Dormir, tomamos nota de la vida y la comida.
                SetLocalInt(oPJ,"Durmiendo",1);
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDormir, oPJ, 7.0);

                //Actualizando calendario.
                SetLocalInt(oModulo, ("UltimaHoraDescanso" + sPJNombre + sCDKey), GetTimeHour());
                SetLocalInt(oModulo, ("UltimoDiaDescanso" + sPJNombre + sCDKey), GetCalendarDay());
                SetLocalInt(oModulo, ("UltimoMesDescanso" + sPJNombre + sCDKey), GetCalendarMonth());
                SetLocalInt(oModulo, ("UltimoAnualDescanso" + sPJNombre + sCDKey), GetCalendarYear());

                //Introducir los efectos visuales del descanso.
                effect eCiego = SupernaturalEffect(EffectBlindness());
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eCiego, oPJ, 30.0);
                ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDormir, oPJ, 30.0);
                DelayCommand(7.0, ApplyEffectToObject(DURATION_TYPE_TEMPORARY, eDormir, oPJ, 30.0));
                RemoveEffect(oPJ, EffectBlindness());
            }// fin else
        }//fin if preparando el descanso.

        //Si ha descansado sin problemas, ponemos todo de nuevo a cero para la siguiente vez.
        int nUltimoDescanso = GetLastRestEventType();
        if (nUltimoDescanso == REST_EVENTTYPE_REST_FINISHED || nUltimoDescanso == REST_EVENTTYPE_REST_CANCELLED)
        {
            SetLocalInt(oPJ,"Durmiendo",0);
        }

    }//fin cuerpo central.

    else
    {
        SendMessageToPC(oDescansemos,"Este lugar no parece apropiado para descansar");
    }

}//fin void main()


Vale, un descanso más.

Txibi.

#8 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 29 June 2005 - 12:12 AM

...El Esqueleto...

Saludos.

Bien, vamos a continuar.

Desangrado (Agonizando), Muerte (Muerto), Regeneración (Resurrección).

Empecemos por el script de OnPlayerDying, que es el que controla el suceso que ocurre desde que el jugador cae a 0 puntos de vida hasta que se muere, por defecto cuando una ficha llega a 0 de vida se muere. Haremos un sistema de desangrado para que vaya agonizando poco a poco hasta -10 momento en el que sí, morirá, o tal vez consiga estabilizarse... y quedarse moribundo en el bosque hasta que alguién lo sane inmobilizado pero sin morir... ???

/*
Script 0_tx_jug_semuere.
Script que controla el desangrado antes del lamentable (o no) final.
*/

//Subprograma Desangrado.
void Desangrado(int iSangreVa)
{
    object oMeMuero = GetLocalObject(OBJECT_SELF, "PJ_Nombre");
    int iDesangrado = GetLocalInt(oMeMuero, "iPJ_Desangrado");
    iDesangrado = iDesangrado + 1;
    int iDificultad;
    int iDificultadBase = 15;
    iDificultad = iDificultadBase;

    if (iDificultad > iDificultadBase)
    {
        iDificultad = iDificultadBase;
    }//fin comparativa de iDificultad

    effect eDesangrado;
    //Este bucle se repite hasta que la ficha muere o llega a +1 de vida.
    if (GetCurrentHitPoints() <= 0)
    {
        if (iSangreVa > 0)
        {
            eDesangrado = EffectDamage(iSangreVa);
        }//fin if iSangreVa.
        else
        {
            eDesangrado = EffectHeal(-iSangreVa);
        }//fin else iSangreVa.
        ApplyEffectToObject(DURATION_TYPE_INSTANT, eDesangrado, oMeMuero);

        // A -10 puntos de vida la ficha muere.
        if (GetCurrentHitPoints() <= -11)
        {
            PlayVoiceChat(VOICE_CHAT_DEATH); //Lanza un gemido lastimero.
            ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DEATH), OBJECT_SELF);
            ApplyEffectToObject(DURATION_TYPE_INSTANT, EffectDeath(), oMeMuero);
            return;
        }//fin if de chungo pj.
        if (iSangreVa > 0) //Solo si la ficha no se estabiliza.
        {
            int iConBonus = GetAbilityModifier(ABILITY_CONSTITUTION, oMeMuero);
            int iTiradaEstabiliza = d20() + iConBonus;
            if (iTiradaEstabiliza >= iDificultad)
            {
                iSangreVa = -iSangreVa; //Revertimos el proceso. Desactivar para estancar.
                PlayVoiceChat(VOICE_CHAT_LAUGH); //Librada por esta vez.
                SendMessageToPC (oMeMuero, "Te has estabilizado. Tus heridas empiezan a sanar.");
            }//fin if de estabilizado.
            else
            {
                SendMessageToPC(oMeMuero, "No te has estabilizado.");
                switch (d6())
                {
                    case 1: PlayVoiceChat(VOICE_CHAT_PAIN1); break;
                    case 2: PlayVoiceChat(VOICE_CHAT_PAIN2); break;
                    case 3: PlayVoiceChat(VOICE_CHAT_PAIN3); break;
                    case 4: PlayVoiceChat(VOICE_CHAT_HEALME); break;
                    case 5: PlayVoiceChat(VOICE_CHAT_NEARDEATH); break;
                    case 6: PlayVoiceChat(VOICE_CHAT_HELP);
                }//fin switch de llamada de auxilio.
            }//fin else de no estabilizado.
        }//fin ciclo de desangrado/estabilizacion.
        if (GetCurrentHitPoints() <= 0)
        {
            SetLocalInt(oMeMuero, "iPJ_Desangrado", iDificultad);
            DelayCommand(13.0, Desangrado(iSangreVa)); //Repetimos Ronda.
        }//fin if de Siguiente Ronda de Estabilizacion
    }//fin de if sanamos vida.
}//fin Subprograma Desangrado.


//CUERPO PRINCIPAL.
void main()
{
    object oMeMuero = GetLastPlayerDying();
    SetLocalObject(oMeMuero, "PJ_Nombre", oMeMuero);
    SetLocalInt(oMeMuero, "iPJ_Desangrado", 0);
    AssignCommand(oMeMuero, Desangrado(1));
}//Fin Cuerpo Principal.

Supongamos el terrible final, nuestro héroe se muere. Pues en ese momento se ejecuta el evento OnPlayerDeath, borramos el script que tiene y añadimos este.

Este programa básicamente aplica el penalizador por morir y saca el cartel dando opción a regenerar o esperar a que sea resucitado (hay que tener en cuenta que por morir le hacemos perder xp y oro si queremos, pero por bajar del limbo puede perder más aún que evita si es resucitado-rescatado por un clérigo).

/*
Script: 0_tx_jug_muere
Script de Muerte, aplica el penalizador al morir, en vez de al regenerar.
Para evitar tramposos.
*/

#include "nw_i0_plot"

// Aplica penalizador al Jugador que regenera.

//SUBPROGRAMA AplicaPenalizador.
void AplicaPenalizador(object oMuerto)
{
    int iXP = GetXP(oMuerto);
    //200 es el penalizador en experiencia por cada nivel del muerto.
    int iPenalizador = 200 * GetHitDice(oMuerto);
    int iNivel = GetHitDice(oMuerto);
    // Tu no puedes perder un nivel de esta forma.
    int nMin = ((iNivel * (iNivel - 1)) / 2) * 1000;
    int iNuevaXP = iXP - iPenalizador;
    if (iNuevaXP < nMin)
       iNuevaXP = nMin;
    SetXP(oMuerto, iNuevaXP);
    //0.50 es el % de oro perdido, 50% significa que perdera la mitad de su oro.
    int nGoldToTake = FloatToInt(0.50 * GetGold(oMuerto));
    AssignCommand(oMuerto, TakeGoldFromCreature(nGoldToTake, oMuerto, TRUE));
    //Las lineas habituales del juego indicando que mueres, pierdes tanta xp, etc...
    DelayCommand(4.0, FloatingTextStrRefOnCreature(58299, oMuerto, FALSE));
    DelayCommand(4.8, FloatingTextStrRefOnCreature(58300, oMuerto, FALSE));
}//Fin Subprograma AplicaPenalizador.

//CUERPO PRINCIPAL
void main()
{
    object oJugador = GetLastPlayerDied();
    //Aplicamos el subprograma AplicaPenalizador al Jugador.
    AplicaPenalizador(oJugador);
    //Esperamos 3 segundos y sacamos el panel que da opcion a regenerar.
    DelayCommand(3.0, PopUpGUIPanel(oJugador, GUI_PANEL_PLAYER_DEATH));
}//Fin del Cuerpo Principal.

Bien, ahora nos queda ejecutar el programa que sucede cuando se pulsa regenerar en el cartelito que sale cuando morimos. Básicamente creamos un pequeño subprograma que nos sana y elimina todos los efectos dañinos y pega un salto al punto de ruta del limbo, que nosotros hemos llamado tx_limbo.

Este Script se coloca en OnRespawn, hala borramos lo que hay y colocamos el nuestro.

/*
Script: 0_tx_regenera
*/

#include "nw_i0_plot"

//SUBPROGRAMA Resucitar.
void Resucitar(object oPJ)
{
    //Cogemos el primer efecto negativo del PJ.
    effect eEfectoNegativo = GetFirstEffect(oPJ);
    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectResurrection(),oPJ);
    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectHeal(GetMaxHitPoints(oPJ)), oPJ);

    //Buscamos los efectos negativos
    while(GetIsEffectValid(eEfectoNegativo))
    {
        if (GetEffectType(eEfectoNegativo) == EFFECT_TYPE_ABILITY_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_AC_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_ATTACK_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_DAMAGE_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_DAMAGE_IMMUNITY_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_SAVING_THROW_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_SPELL_RESISTANCE_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_SKILL_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_BLINDNESS ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_DEAF ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_PARALYZE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_NEGATIVELEVEL ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_MOVEMENT_SPEED_DECREASE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_CURSE ||
            GetEffectType(eEfectoNegativo) == EFFECT_TYPE_SLOW)
            {
                //Si el efecto es negativo se elimina
                RemoveEffect(oPJ, eEfectoNegativo);
            }//fin de remover efecto.

        //Examinamos el siguiente efecto negativo y asi hasta todos.
        eEfectoNegativo = GetNextEffect(oPJ);

    }//fin del while de busqueda de efectos negativos.

    //Curamos el cuerpo del muerto.
    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectHeal(GetMaxHitPoints(oPJ)), oPJ);

}//fin del subprograma Resucitar.


//CUERPO PRINCIPAL.
void main()
{
    //Script para tratar la muerte de un jugador
    object oJugador = GetLastRespawnButtonPresser();
    location locMuertePC = GetLocation(oJugador);

    //Recordamos en una variable local su muerte.
    SetLocalInt (GetModule(), "Muerto_" + GetName(oJugador) + GetPCPlayerName(oJugador) , 1);

    //Le hacemos saltar al punto de ruta marcado en el limbo.
    object oJumpTarget = GetObjectByTag("tx_limbo");
    location locDestino = GetLocation(oJumpTarget);

    //Un poco de efecto visual, 3 segundos y salto al limbo.
    ApplyEffectAtLocation(DURATION_TYPE_INSTANT, EffectVisualEffect(VFX_IMP_DEATH), locMuertePC,3.0f);
    DelayCommand(3.0,AssignCommand(oJugador, ClearAllActions()));
    AssignCommand(oJugador, JumpToLocation(locDestino));
    ApplyEffectAtLocation(DURATION_TYPE_TEMPORARY, EffectVisualEffect(VFX_IMP_RESTORATION), GetLocation(oJugador),5.0f);

    //Ejecutamos el subprograma Resucitar sobre el jugador.
    Resucitar(oJugador);

    //Creamos una Calavera de Trama en su inventario para que a partir de los siguientes reinicios vaya al Limbo.
    //Por si se desconecta desde el limbo esperando el siguiente día entrar sin pagar el coste de bajar del Limbo.
    CreateItemOnObject("tx_muerto", oJugador, 1);

 }//Fin Cuerpo Principal.

Vale, tenemos controlado el sistema base de la muerte y resurrección.

Con esto tenemos el esqueleto base montado, ahora sería crear el motor que nos enlaza todo y da algo de cosistencia y cuando terminemos el motor que mueve el esqueleto, ya podemos empezar a crear áreas, monstruos y villanos ???

Txibi.

PD: Siguiente paso, El Motor.

#9 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 15 July 2005 - 09:07 AM

...El Motor...

Saludos.

Bueno, hora de finalizar la base del mundo persistente. Tenemos un conjunto de guiones o script que nos dan el esqueleto base en las propiedades del módulo y unas pocas áreas base.

Vamos a seguir creando los scripts, objetos y áreas que entrelacen y den algo de consistencia al invento.

Tenemos el inicio, un jugador nuevo a entrado al módulo. Se le puede dejar tal cual, pero se le va a dar un nuevo equipo y unos pocos niveles.

Vamos a pintar desencadenantes, estándar, desencadenante genérico, nuevo genérico. Creamos uno que rodee el punto de entrada.

A este conjunto de scripts que son parte del sistema pero no de la base, yo los voy a etiquetar comenzando todos por 1_tx_ para llevar un orden.

Imagen posteada

Y aquí esta el script que nos realiza la comprobación del nivel del jugador, su estado (muerto o vivo). Y en caso de ficha nueva, se procede a su limpieza de equipo inicial como paso previo a su reequipación.

/*
Script 1_tx_pj_nuevo. Colocar en el OnEnter del Desencadenante que lo alberga.

Se crea un desencadenante generico. En OnEnter se coloca el script.
Cuando entre al desencadenante (andando, teleportado o mandado por punto ruta)
Se le quita todo y le envia a un punto de ruta prefijado.
Esto solo ocurrira si es nivel 1 con 0 puntos de experiencia.
Vamos, ficha nueva.
*/

//Subprograma de Bioware para mirar todos los objetos de su inventario.
int IsInInventory(object oContainer, string sItemTag)
{
object oItem;

if (GetHasInventory(oContainer))
{
    oItem = GetFirstItemInInventory(oContainer);
    while ( OBJECT_INVALID != oItem )
    {
        if (GetTag(oItem) == sItemTag)
        { return TRUE; }
        oItem = GetNextItemInInventory(oContainer);
    } // end while
} // endif
return FALSE;
} // end IsInInventory
//Fin Subprograma de mirar inventario.

#include "nw_i0_plot"

//Cuerpo Principal.
void main()
{
    //La victima que aparece en el desencadenante.
    object oJugador = GetEnteringObject();
    /*
    Se mira si tiene el objeto de etiqueta tx_muerto, si lo tiene, esta muerto.
    Eso significa que se ha desconectado para no bajar del limbo (o se ha caido
    la conexion). Lo enviamos al reino de los muertos, donde debe de estar.
    */
    if (IsInInventory(oJugador,"tx_muerto"))
    {
        AssignCommand(oJugador, JumpToObject(GetObjectByTag("tx_limbo")));
    }//fin de mirar si esta muerto.

    //Si tiene menos de nivel 2, se ejecuta el bloque central del script.
    int iNivel = GetHitDice(oJugador);
    if (iNivel <2 )
    {
        //Miramos su primer objeto del equipo y lo marcamos.
        object oObjetoEquipo = GetFirstItemInInventory(oJugador);
        //Este bucle cerrado seguira mientras tenga objetos no invalidos.
        //Es decir mientras tenga objetos.
        while (oObjetoEquipo != OBJECT_INVALID)
       {
           //Destruye el objeto.
           DestroyObject(oObjetoEquipo);
           //Coge el siguiente objeto.
           oObjetoEquipo = GetNextItemInInventory(oJugador);
       }//fin bucle while.
       //Pero no nos olvidamos de los objetos equipados.
       //Esta lista destruye todo lo puesto "manualmente"
       object oEquipo1 = GetItemInSlot(INVENTORY_SLOT_ARMS , oJugador);
       object oEquipo2 = GetItemInSlot(INVENTORY_SLOT_ARROWS , oJugador);
       object oEquipo3 = GetItemInSlot(INVENTORY_SLOT_BELT , oJugador);
       object oEquipo4 = GetItemInSlot(INVENTORY_SLOT_BOLTS , oJugador);
       object oEquipo5 = GetItemInSlot(INVENTORY_SLOT_BULLETS , oJugador);
       object oEquipo6 = GetItemInSlot(INVENTORY_SLOT_CARMOUR , oJugador);
       object oEquipo7 = GetItemInSlot(INVENTORY_SLOT_CLOAK , oJugador);
       object oEquipo8 = GetItemInSlot(INVENTORY_SLOT_CWEAPON_B , oJugador);
       object oEquipo9 = GetItemInSlot(INVENTORY_SLOT_CWEAPON_L , oJugador);
       object oEquipo10 = GetItemInSlot(INVENTORY_SLOT_CWEAPON_R , oJugador);
       object oEquipo11 = GetItemInSlot(INVENTORY_SLOT_CHEST , oJugador);
       object oEquipo12 = GetItemInSlot(INVENTORY_SLOT_HEAD , oJugador);
       object oEquipo13 = GetItemInSlot(INVENTORY_SLOT_LEFTHAND , oJugador);
       object oEquipo14 = GetItemInSlot(INVENTORY_SLOT_LEFTRING , oJugador);
       object oEquipo15 = GetItemInSlot(INVENTORY_SLOT_NECK , oJugador);
       object oEquipo16 = GetItemInSlot(INVENTORY_SLOT_RIGHTHAND , oJugador);
       object oEquipo17 = GetItemInSlot(INVENTORY_SLOT_RIGHTRING , oJugador);
       object oEquipo18 = GetItemInSlot(INVENTORY_SLOT_BOOTS , oJugador);
       DestroyObject(oEquipo1);
       DestroyObject(oEquipo2);
       DestroyObject(oEquipo3);
       DestroyObject(oEquipo4);
       DestroyObject(oEquipo5);
       DestroyObject(oEquipo6);
       DestroyObject(oEquipo7);
       DestroyObject(oEquipo8);
       DestroyObject(oEquipo9);
       DestroyObject(oEquipo10);
       DestroyObject(oEquipo11);
       DestroyObject(oEquipo12);
       DestroyObject(oEquipo13);
       DestroyObject(oEquipo14);
       DestroyObject(oEquipo15);
       DestroyObject(oEquipo16);
       DestroyObject(oEquipo17);
       DestroyObject(oEquipo18);
       //Ya esta, en pelota picada.
    }//fin if de comprobar si es nivel 1.
    else
    {
        //En caso de que sea nivel 2 o superior nada.
    }//fin del else.
}//fin void.

Claro que esto es opcional, puedes dejarlo tal cual empieza, pero si sería interesante que se comprobase si murió o no. Algunos jugadores, gustan de la trampa de tener media docena de fichas clones, y si se muere su ficha clon 1, la dejan en el limbo y cogen otra. Así cuando se reinicie el server no pagan la penalización por bajar del limbio, ha diferencia de los jugadores honestos.

Hora de enlazar con nuestro mundo. Creamos un Avatar para la bajada de los jugadores, así mismo, en este área, coloca los carteles de aviso que consideres necesarios para informar sobre el módulo.

Como avatar escoge lo que quieras pero ponlo de trama, en mi módulo mi avatar es una gallina ??? pero muchos gustan de avatares espectaculares, como elementales de fuego, dragones o gigantes, como termino medio, colocaré un golem escudo para este ejemplo. Ponlo de trama y cambia su facción hostil a defensor por ejemplo.

En ese golem creamos la conversación de bienvenida (las letras de las conversaciones encasilladas entre <StartAction></Start> son verdes, si no le coloca el cierre coge toda la conversación a partir de esa línea).

En la conversación de bienvenida creamos para el DUEÑO (el golem pnj) dos líneas, sólo leerá una a la vez, por eso en la primera ponemos la comprobación de que sólo aparezca si es nivel 1 su hablante. Si lo es. Se ejecuta la primera e ignora la segunda, si es superior a 1, se salta la primera y ejecuta la segunda.

La conversación puede ser parecido a esto.

[DUEÑO]<StartAction> Saludos, viajero, si deseas entrar. Acepta y continua. Para más detalles, visita http://www.paginawebdelmundo.com
Acepto.[FINALIZAR DIÁLOGO]
No, quizá en otra ocasión.[FINALIZAR DIÁLOGO]

[DUEÑO]<StartAction>Saludos de nuevo <FullName>, ¿deseas bajar de nuevo al mundo que nos rodea? Ya sabes que puedes recabar información en http://www.paginawebdelmundo.com
Si, vamos abajo otra vez.[FINALIZAR DIÁLOGO]
No todavía no, calma y tranquilidad.[FINALIZAR DIÁLOGO]


El script de testeo de nivel se colocara en El texto aparece cuando... de la primera opción de diálogo del pnj (dueño).

/*
script 1_tx_nivel_1.
*/
int StartingConditional()
{
    int iNivelUno =0;

    if (GetHitDice(GetPCSpeaker()) == 1)
        iNivelUno=1;

    if (iNivelUno == 0)
        return FALSE;

    return TRUE;
}//fin condicional de testeo de nivel 1.

Y en las confirmaciones de bajada creamos dos scripts de salto, en Acciones Emprendidas.

En Acepto (PJ de nivel 1 que está sin nada.)
/*
script: 1_tx_al_equipo
*/
void main()
{
    AssignCommand(GetPCSpeaker(), ClearAllActions());
    AssignCommand(GetPCSpeaker(), ActionJumpToObject(GetObjectByTag("1_zona_equipo")));
}

Y en "Si, vamos abajo otra vez", que el jugador ya se equipó y cogio sus nivelillos va directamente a la zona del mundo donde se inician las aventuras.

/*
script: 1_tx_al_mundo
*/
void main()
{
    AssignCommand(GetPCSpeaker(), ClearAllActions());
    AssignCommand(GetPCSpeaker(), ActionJumpToObject(GetObjectByTag("1_mundo_inicio")));
}

Bien, vamos a tomarnos un descanso. Lo siguiente va a ser crear la sala de equipo inicial, enlazar el limbo con la tierra, una pequeña área inicial y poco más.

Txibi.

Editado por Txibi, 16 October 2010 - 11:07 AM.


#10 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 15 July 2005 - 09:57 AM

... El Motor ...

Saludos.

Bueno, vamos a por el equipo. Tenemos una sala creada para tal fin, le ponemos un punto de ruta, el que hemos llamado en el script anterior 1_zona_equipo y le ponemos esta etiqueta, claro.

Creamos un avatar cualquiera para que nos de el equipo, facción defensor y de trama.

Aquí dos opciones, puedes crear una tienda y dar algo de oro al pj cuando entra aquí y que se compre lo que quiera o se lo das por script.

Yo pondré por script, aunque una tienda da más flexibilidad.

La conversación tipo:



En Acciones Emprendidas (Finalizar Diálogo) colocar el script que lanza el evento de equipamiento.

Este script puede ser mucho mas corto, yo sencillamente me he liado distinguiendo cada clase y recompensando a aquellas clases que se hacen una ficha más alla de su atributo primario.

/*
  Script: 1_tx_dar_equipo
  Equipo inicial del aventurero.
*/

//Cuerpo Principal.
void main()
{
    object oPJ = GetPCSpeaker();

    //Cogemos los bonos de las habilidades.
    int iEsaFUE = GetAbilityModifier(ABILITY_STRENGTH, oPJ);
    int iEsaCON = GetAbilityModifier(ABILITY_CONSTITUTION, oPJ);
    int iEsaDES = GetAbilityModifier(ABILITY_DEXTERITY, oPJ);
    int iEsaINT = GetAbilityModifier(ABILITY_INTELLIGENCE, oPJ);
    int iEsaSAB = GetAbilityModifier(ABILITY_WISDOM, oPJ);
    int iEsaCAR = GetAbilityModifier(ABILITY_CHARISMA, oPJ);


    /*
    Dar un poco de oro al Aventurero.
    Alguien carismatico empezara con algo de oro extra.
    */
    int iDineroPJ = GetGold(oPJ);
    if (iDineroPJ<500)
    {
        int iOroInicial = (500 + (iEsaCAR * 100));
        if (iOroInicial < 100) {iOroInicial = 50;}
        GiveGoldToCreature(oPJ, iOroInicial);
    }
    else //Si por lo que sea tiene oro (vuelve aqui por un bug) no recibe nada.
    {
        SendMessageToPC(oPJ, "No has recibido mas oro, tienes el suficiente");
    }

    /*
    Dar algunos PX al Aventurero.
    Recibe un extra de su inteligencia y sabiduria combinadas.
    */

    int iExperienciaInicial = (20000 + ((iEsaINT + iEsaSAB) * 1000));
    SetXP(oPJ, iExperienciaInicial);

    /*
    Damos unos pocos objetos estandar al aventurero.
    */
    CreateItemOnObject("come_trucha", oPJ);
    CreateItemOnObject("come_tortaviaje", oPJ);
    CreateItemOnObject("come_frutossecos", oPJ);
    CreateItemOnObject("come_fruta_1", oPJ);
    CreateItemOnObject("tx_gen_garrote", oPJ);


    /*
    Ahora, dependiendo de la clase del aventurero, recibira otros objetos.
    Especificos para cada profesion.
    */

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_BARBARIAN, oPJ) >= 1)
    {
        //Generico Barbaro.
        CreateItemOnObject("tx_gen_barbaro", oPJ);
        CreateItemOnObject("bebe_grog", oPJ);
        CreateItemOnObject("bebe_orujo", oPJ);

        if(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HALFORC)
        {

            DestroyObject(GetObjectByTag("tx_gen_barbaro"));
            CreateItemOnObject("tx_coraza_01", oPJ);
        }

        if (iEsaINT>=0)
        {
            CreateItemOnObject("nw_it_mpotion020", oPJ, 3);
            CreateItemOnObject("tx_gen_hachabat", oPJ);
        }//Barbaro Listo.

        if (iEsaSAB>0)
        {
            if(GetRacialType(oPJ)==IP_CONST_RACIALTYPE_HALFORC)
            {
                CreateItemOnObject("tx_esc_paves_02", oPJ);
            }

        }//Barbaro Astuto.

        if (iEsaCAR>0)
        {

        }//Barbaro Carismatico.
    }//fin barbaro.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_BARD, oPJ) >= 1)
    {
        CreateItemOnObject("NW_IT_MPOTION001", oPJ, 10);
        CreateItemOnObject("nw_it_mpotion020", oPJ, 6);
        CreateItemOnObject("NW_IT_MPOTION002", oPJ, 1);
        CreateItemOnObject("NW_IT_MPOTION006", oPJ, 1);
        CreateItemOnObject("NW_IT_MPOTION011", oPJ, 1);
        CreateItemOnObject("nw_it_mpotion020", oPJ, 1);

        CreateItemOnObject("tx_gen_bardo", oPJ);
        if (iEsaINT>0)
        {
            CreateItemOnObject("tx_cetroescarcha", oPJ);
            CreateItemOnObject("tx_gen_virote", oPJ, 99);
            CreateItemOnObject("tx_gen_virote", oPJ, 99);
            CreateItemOnObject("tx_gen_virote", oPJ, 99);
            CreateItemOnObject("tx_gen_virote", oPJ, 99);
            CreateItemOnObject("tx_gen_ball_leve", oPJ);
        }//Listo.
        if ((iEsaINT>0)&&(iEsaFUE>0))
        {
            DestroyObject(GetObjectByTag("tx_gen_ball_leve"));
            CreateItemOnObject("tx_gen_ball_pesa",oPJ);
        }//Listo y Fuerte.
        if (iEsaSAB>0)
        {
            CreateItemOnObject("tx_gen_daga", oPJ);
            CreateItemOnObject("tx_gen_estoque", oPJ);
        }//Astuto.
        if (iEsaCAR>0)
        {
            CreateItemOnObject("come_huevos",oPJ);
            CreateItemOnObject("come_jamon",oPJ);
            CreateItemOnObject("come_trucha",oPJ);
            CreateItemOnObject("come_platobueno1",oPJ);
            CreateItemOnObject("come_platobueno2",oPJ);
            CreateItemOnObject("bebe_hidromiel",oPJ, 4);
            CreateItemOnObject("bebe_sidra",oPJ, 4);
        }//Carismatico.
    }//fin bardo.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_CLERIC, oPJ) >= 1)
    {
        CreateItemOnObject("tx_gen_clerigo", oPJ);
        CreateItemOnObject("tx_escudo", oPJ);
        CreateItemOnObject("tx_gen_maza", oPJ);
        CreateItemOnObject("NW_IT_MPOTION001", oPJ);
        if (iEsaINT>0)
        {
            CreateItemOnObject("bebe_zarzaparri1", oPJ, 6);
            CreateItemOnObject("NW_IT_MPOTION020", oPJ, 10);
        }//Listo.
        if (iEsaCAR>0)
        {
            CreateItemOnObject("NW_IT_MPOTION009", oPJ, 10);
        }//Carismatico.
    }//fin clerigo.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_DRUID, oPJ) >= 1)
    {
        CreateItemOnObject("tx_gen_druida", oPJ);
        CreateItemOnObject("tx_gen_lanza", oPJ);
        CreateItemOnObject("NW_IT_MPOTION009", oPJ, 10);
        if (iEsaINT>0)
        {
            CreateItemOnObject("NW_IT_MPOTION002", oPJ, 10);
            CreateItemOnObject("NW_IT_MPOTION006", oPJ, 10);
            CreateItemOnObject("bebe_sidra", oPJ, 10);
            CreateItemOnObject("NW_IT_MPOTION005", oPJ, 10);
        }//Listo.
        if (iEsaCAR>0)
        {
            CreateItemOnObject("tx_gen_honda", oPJ);
            CreateItemOnObject("tx_gen_piedra", oPJ, 99);
            CreateItemOnObject("tx_gen_piedra", oPJ, 99);
            CreateItemOnObject("tx_gen_piedra", oPJ, 99);
            CreateItemOnObject("tx_gen_piedra", oPJ, 99);
            CreateItemOnObject("tx_gen_baston", oPJ);
            CreateItemOnObject("NW_IT_MPOTION020",oPJ, 10);
        }//Carismatico.
    }//fin druida.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_FIGHTER, oPJ) >= 1)
    {

        CreateItemOnObject("tx_esc_grande", oPJ);
        CreateItemOnObject("tx_cotamallas_01", oPJ);
        CreateItemOnObject("tx_gen_daga", oPJ);
        CreateItemOnObject("tx_gen_esp_corta", oPJ);
        //Armadura para mediano
        if(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HALFLING)
        {

            DestroyObject(GetObjectByTag("tx_cotamallas_01"));
            CreateItemOnObject("tx_cuero_01", oPJ);
        }

        //Bloque Arma Primaria.
        string sNombre = GetName(oPJ);
        string sJugador = GetPCPlayerName(oPJ);
        int iArmaPrimaria = GetLocalInt(oPJ, "arma_"+sNombre+"_"+sJugador);
        //Miramos Comprobacion.
        switch(iArmaPrimaria)
        {
            case 1: //Alabarda.
            {
                CreateItemOnObject("tx_gen_alabarda", oPJ);
                break;
            }//Fin Alabarda.
            case 2: //Guadaña.
            {
                CreateItemOnObject("tx_gen_guada", oPJ);
                break;
            }//Fin Guadaña.
            case 3: //Lanza
            {
                CreateItemOnObject("tx_gen_lanza", oPJ);
                break;
            }//Fin Lanza.
            case 4: //Mangual Pesado.
            {
                CreateItemOnObject("tx_gen_man_pesa", oPJ);
                break;
            }//Fin Mangual Pesado.
            case 5: ////Martillo de Guerra
            {
                CreateItemOnObject("tx_gen_marti_pes", oPJ);
                break;
            }//Fin //Fin Martillo de Guerra..
            case 6://Maza.
            {
                CreateItemOnObject("tx_gen_maza", oPJ);
                break;
            }//Fin Maza.
            case 7: //Maza de Armas.
            {
                CreateItemOnObject("tx_gen_baston", oPJ);
                break;
            }//Fin Maza de Armas.
            case 8: //Bastón.
            {
                CreateItemOnObject("tx_gen_doshojas", oPJ);
                break;
            }//Fin Bastón.
            case 9: //Espada de Doble Hoja.
            {
                CreateItemOnObject("tx_gen_alabarda", oPJ);
                break;
            }//Fin Espada de Doble Hoja.
            case 10: //Hacha Doble.
            {
                CreateItemOnObject("tx_gen_hacha_dos", oPJ);
                break;
            }//Fin Hacha Doble.
            case 11: //Espada Corta.
            {
                CreateItemOnObject("tx_gen_esp_corta", oPJ);
                break;
            }//Fin Espada Corta.
            case 12: //Espada Larga.
            {
                CreateItemOnObject("tx_gen_esp_larga ", oPJ);
                break;
            }//Fin Espada Larga.
            case 13: //Cimitarra.
            {
                CreateItemOnObject("tx_gen_cimitarra", oPJ);
                break;
            }//Fin Cimitarra.
            case 14: //Estoque.
            {
                CreateItemOnObject("tx_gen_estoque", oPJ);
                break;
            }//Fin Estoque.
            case 15: //Katana.
            {
                CreateItemOnObject("tx_gen_katana", oPJ);
                break;
            }//Fin Katana.
            case 16: //Hacha de Batalla.
            {
                CreateItemOnObject("tx_gen_hachabat", oPJ);
                break;
            }//Fin Hacha de Batalla.
            case 17: //Gran Hacha.
            {
                CreateItemOnObject("tx_gen_granhacha", oPJ);
                break;
            }//Fin Gran Hacha.
            case 18: //Hoz.
            {
                CreateItemOnObject("tx_gen_hoz", oPJ);
                break;
            }//Fin Hoz.
            case 19: //Kama.
            {
                CreateItemOnObject("tx_gen_kama", oPJ);
                break;
            }//Fin Kama.
            case 20: //Kukri.
            {
                CreateItemOnObject("tx_gen_kukri", oPJ);
                break;
            }//Fin Kukri.
            case 21: //Látigo.
            {
                CreateItemOnObject("tx_gen_latigo", oPJ);
                break;
            }//Fin Látigo.
            case 22: //Espadón.
            {
                CreateItemOnObject("tx_gen_espadon", oPJ);
                break;
            }//Fin Espadón.
            case 23: //Espada Bastarda.
            {
                CreateItemOnObject("tx_gen_bastarda", oPJ);
                break;
            }//Fin Espada Bastarda.
            case 24: //Hacha Enana.
            {
                CreateItemOnObject("tx_gen_hac_enana", oPJ);
                break;
            }//Fin Hacha Enana.
        }//fin switch de comprobacion de arma primaria.

        if ((iEsaINT>0)&&((GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HUMAN)||(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HALFELF)))
        {
            DestroyObject(GetObjectByTag("tx_esc_grande"));
            DestroyObject(GetObjectByTag("tx_cotamallas_01"));
            CreateItemOnObject("tx_esc_paves", oPJ);
            CreateItemOnObject("tx_completa_1", oPJ);
            CreateItemOnObject("tx_cuero_01", oPJ);

        }//Listo.
        if (iEsaSAB>0)
        {
            CreateItemOnObject("tx_gen_arcolargo", oPJ);
            if ((GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HALFLING)||(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_DWARF)||(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_GNOME))
            {
                DestroyObject(GetObjectByTag("tx_gen_arcolargo"));
                CreateItemOnObject("tx_gen_arcocorto", oPJ);
            }
            CreateItemOnObject("tx_gen_fecha", oPJ, 99);
            CreateItemOnObject("tx_gen_fecha", oPJ, 99);
            CreateItemOnObject("tx_gen_fecha", oPJ, 99);
            CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        }//Astuto.
        if (iEsaCAR>0)
        {
            CreateItemOnObject("nw_it_mpotion020", oPJ, 10);
            CreateItemOnObject("nw_it_mpotion020", oPJ, 10);
            CreateItemOnObject("come_fruta_1", oPJ);
            CreateItemOnObject("come_huevos", oPJ);
            CreateItemOnObject("come_platobueno1", oPJ);
            CreateItemOnObject("come_platobueno2", oPJ);
            CreateItemOnObject("come_tarta", oPJ);
            CreateItemOnObject("bebe_grog", oPJ, 10);
        }//Carismatico.
        if ((iEsaINT>0)&&(iEsaSAB>0)&&(iEsaCAR>0)&&(GetRacialType(oPJ)==IP_CONST_RACIALTYPE_DWARF))
        {
            DestroyObject(GetObjectByTag("tx_esc_grande"));
            DestroyObject(GetObjectByTag("tx_cotamallas_01"));
            CreateItemOnObject("tx_completa_02", oPJ);
            CreateItemOnObject("tx_esc_grande_02", oPJ);
            CreateItemOnObject("tx_cuero_01", oPJ);
            iExperienciaInicial = iExperienciaInicial + 5000;
            SetXP(oPJ, iExperienciaInicial);
        }//fin de un enano como dios manda.
    }//fin guerrero.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_MONK, oPJ) >= 1)
    {
        CreateItemOnObject("tx_gen_monje", oPJ);
        CreateItemOnObject("tx_gen_kama", oPJ);
        CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
        CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
        CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
        CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
        if (iEsaINT>0)
        {
            CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
            CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
            CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
            CreateItemOnObject("tx_gen_shuriken", oPJ, 50);
        }//Listo.
        if (iEsaCAR>0)
        {
            CreateItemOnObject("NW_IT_MPOTION020", oPJ, 10);
            CreateItemOnObject("NW_IT_MPOTION020", oPJ, 10);
        }//Carismatico.
    }//fin monje.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_PALADIN, oPJ) >= 1)
    {
        CreateItemOnObject("tx_esc_grande", oPJ);
        CreateItemOnObject("tx_cotamallas_01", oPJ);
        CreateItemOnObject("tx_gen_daga", oPJ);
        CreateItemOnObject("tx_gen_esp_corta", oPJ);
        CreateItemOnObject("tx_gen_esp_larga", oPJ);
        if ((iEsaINT>0)&&((GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HUMAN)||(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HALFELF)))
        {
            DestroyObject(GetObjectByTag("tx_esc_grande"));
            DestroyObject(GetObjectByTag("tx_cotamallas_01"));
            CreateItemOnObject("tx_esc_paves", oPJ);
            CreateItemOnObject("tx_gen_guerrero", oPJ);
            CreateItemOnObject("tx_cuero_01", oPJ);
        }//Listo.
        if (iEsaSAB>0)
        {
            CreateItemOnObject("tx_gen_espadon", oPJ);
            if ((GetRacialType(oPJ)== IP_CONST_RACIALTYPE_HALFLING)||(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_DWARF)||(GetRacialType(oPJ)== IP_CONST_RACIALTYPE_GNOME))
            {
                DestroyObject(GetObjectByTag("tx_gen_espadon"));
                CreateItemOnObject("tx_gen_estoque");
            }
        }//Astuto.
        if (iEsaCAR>2)
        {
            DestroyObject(GetObjectByTag("tx_cotamallas_01"));
            DestroyObject(GetObjectByTag("tx_gen_guerrero"));
            CreateItemOnObject("tx_gen_paladin", oPJ);
        }//Carismatico.
    }//fin paladin.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_RANGER, oPJ) >= 1)
    {
        CreateItemOnObject("tx_gen_arcolargo", oPJ);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        CreateItemOnObject("tx_gen_explora", oPJ);
        CreateItemOnObject("tx_gen_lanza", oPJ);
        if (iEsaINT>0)
        {
            CreateItemOnObject("tx_gen_estoque", oPJ);
            CreateItemOnObject("tx_gen_esp_corta", oPJ);
            CreateItemOnObject("tx_gen_esp_larga", oPJ);
            CreateItemOnObject("NW_IT_MPOTION020", oPJ, 10);
            CreateItemOnObject("NW_IT_MPOTION002", oPJ, 10);
        }//Listo.
        if (iEsaSAB>0)
        {
            CreateItemOnObject("come_fruta_1",oPJ);
            CreateItemOnObject("come_frutossecos",oPJ);
            CreateItemOnObject("come_fruta_1",oPJ);
            CreateItemOnObject("come_frutossecos",oPJ);
            CreateItemOnObject("come_trucha",oPJ);
            CreateItemOnObject("come_trucha",oPJ);
            CreateItemOnObject("bebe_sidra", oPJ, 10);
        }//Astuto.
        if (iEsaCAR>0)
        {
            CreateItemOnObject("NW_IT_MPOTION011", oPJ, 5);
            CreateItemOnObject("NW_IT_MPOTION006", oPJ, 5);
        }//Carismatico.
    }//fin explorador.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_ROGUE, oPJ) >= 1)
    {
        CreateItemOnObject("tx_gen_daga", oPJ);
        CreateItemOnObject("tx_gen_esp_corta", oPJ);
        CreateItemOnObject("tx_cuero_01", oPJ);
        CreateItemOnObject("tx_gen_arcocorto", oPJ);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        CreateItemOnObject("tx_gen_fecha", oPJ, 99);
        if (iEsaINT>0)
        {
            CreateItemOnObject("NW_IT_MPOTION001", oPJ, 10);
            CreateItemOnObject("NW_IT_MPOTION020", oPJ, 10);
            CreateItemOnObject("NW_IT_MPOTION002", oPJ, 10);
        }//Listo.
        if (iEsaSAB>0)
        {
            CreateItemOnObject("tx_gen_dg_ladron", oPJ);
            CreateItemOnObject("NW_IT_MPOTION005", oPJ, 10);
            CreateItemOnObject("NW_IT_MPOTION004", oPJ, 10);
        }//Astuto.
        if (iEsaCAR>0)
        {
            DestroyObject(GetObjectByTag("tx_cuero_01"));
            CreateItemOnObject("tx_gen_ladron", oPJ);
            CreateItemOnObject("NW_IT_MPOTION011", oPJ, 3);
            CreateItemOnObject("bebe_diablorojo", oPJ, 10);
        }//Carismatico.
    }//fin picaro.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_SORCERER, oPJ) >= 1)
    {
        CreateItemOnObject("tx_gen_hechicero", oPJ);
        CreateItemOnObject("tx_gen_maz_hechi", oPJ);
        CreateItemOnObject("tx_gen_ball_leve", oPJ);
        CreateItemOnObject("tx_gen_virote", oPJ, 99);
        CreateItemOnObject("tx_gen_virote", oPJ, 99);
        CreateItemOnObject("tx_gen_virote", oPJ, 99);
        CreateItemOnObject("tx_gen_virote", oPJ, 99);
        if (iEsaINT>0)
        {
            CreateItemOnObject("tx_cetroescarcha", oPJ);
            CreateItemOnObject("NW_IT_MPOTION002", oPJ, 10);
        }//Listo.
        if (iEsaSAB>0)
        {
            CreateItemOnObject("NW_IT_MPOTION011", oPJ, 3);
            CreateItemOnObject("NW_IT_MPOTION006", oPJ, 3);
        }//Astuto.
    }//fin hechicero.

    //--------------------------------------------------------------------->
    if (GetLevelByClass(CLASS_TYPE_WIZARD, oPJ) >= 1)
    {
        CreateItemOnObject("tx_gen_mago", oPJ);
        CreateItemOnObject("tx_gen_dg_mago", oPJ);
        CreateItemOnObject("tx_gen_baston", oPJ);
        CreateItemOnObject("tx_cetroescarcha", oPJ);
        if (iEsaCAR>0)
        {
            CreateItemOnObject("NW_IT_MPOTION020", oPJ, 10);
        }//Carismatico.
    }//fin mago.
    //--------------------------------------------------------------------->

    //Identificamos el equipo inicial del aventurero.
    object oPiezaEquipo = GetFirstItemInInventory(oPJ);
    while (GetIsObjectValid(oPiezaEquipo))
    {
        SetIdentified(oPiezaEquipo, IP_CONST_CASTSPELL_IDENTIFY_3);
        oPiezaEquipo = GetNextItemInInventory(oPJ);
    }//fin del while de identificacion de equipo.

    // Saltar al punto de inicio.
    AssignCommand(GetPCSpeaker(), ClearAllActions());
    AssignCommand(GetPCSpeaker(), JumpToObject(GetObjectByTag("1_mundo_inicio")));

}//Fin del Cuerpo Principal.

Evidentemente si no se le va a dar equipo genérico del módulo, hay que personalizar los objetos, los objetos de ejemplo de ese script son estos.

También hay que crear un objeto de muerte, nuestra famosa calavera.

Coger un objeto que tenga forma de calavera, ponerle etiqueta y resref tx_muerto, de trama, y en propiedades pinchar la casilla de "no se puede dejar". Ya que la única forma de perderla una vez muerto es bajando del limbo.

En la lista de objetos de ahí arriba hemos incluído un "crucifijo". Es para el detectar el mal del paladín.

Un descanso. Luego continuamos.

Txibi.

Editado por Txibi, 16 October 2010 - 11:08 AM.


#11 albgarcor

albgarcor

    Neonato

  • Miembro
  • PipPip
  • 146 posts

Posteado 20 July 2005 - 07:45 AM

Txibi, eres el mejor tio, no te doy besos porque estaria feo. Mil gracias por enseñarnos cosas que nos hacen falta como el comer.

#12 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 20 July 2005 - 01:29 PM

Er... gracias ???

#13 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 20 July 2005 - 01:29 PM

saludos.

Se me pasó un detalle del scritp de armas. Cuando te va a dar el equipo, si eres guerrero tiene que preguntarte que arma tienes y le tienes que responder, sería algo así:

Imagen posteada

Bien en Acciones Emprendidas de cada respuesta hay que poner un script recordando el arma, en Alabarda, la primera opción, guardamos una variable local en el PJ a 1 para que sepa que hay que entregarle ese arma en concreto.

/*
Script: 2_tx_alabarda
*/
//Cuerpo Principal.

void main()
{
    object oPJ = GetPCSpeaker();
    string sNombre = GetName(oPJ);
    string sJugador = GetPCPlayerName(oPJ);
    //Le damos el valor numerico del arma en orden de opcion listada.
    SetLocalInt(oPJ, "arma_"+sNombre+"_"+sJugador, 1);
}//Fin del cuerpo principal.

Los demas serán iguales, la opción 16 hacha de batalla sería:

/*
Script: 2_tx_hacha_bat
*/
//Cuerpo Principal.
void main()
{
    object oPJ = GetPCSpeaker();
    string sNombre = GetName(oPJ);
    string sJugador = GetPCPlayerName(oPJ);
    //Le damos el valor numerico del arma en orden de opcion listada.
    SetLocalInt(oPJ, "arma_"+sNombre+"_"+sJugador, 16);
}//Fin del cuerpo principal.

Después de elegir el arma se enlaza con dar equipo la conversación (sabeis como ¿no?, copias la línea-respuesta que da el equipo normal y en las respuestas después de elegir arma las pegáis con pegar como vínculo)

Para saber si es un guerrero, en la conversación de equipo en El Texto Aparece Cuando... (como pone en la imagen de arriba) colocar este script tx_es_guerrero

/*
Script: tx_es_guerrero
*/
int StartingConditional()
{

    // Restricción basada en la clase de personaje (guerrero en nuestro caso)
    int iGuerrero = 0;
    if(GetLevelByClass(CLASS_TYPE_FIGHTER, GetPCSpeaker()) >= 1)
        iGuerrero = 1; //Es guerrero, adelante.
    if(iGuerrero == 0) //No es guerrero, no ejecuta esta linea.
        return FALSE;

    return TRUE;
}

Por cierto, recordareis de que en su momento abultamos el script que testeaba la entrada del Pj, por si tenía o dejaba de tener ciertos objetos, entre esas secciones estaba esta.

//Crucifijo del Paladin.
    if (GetLevelByClass(CLASS_TYPE_PALADIN, oJugador) >= 1)
    {
        if (!IsInInventory(oJugador,"tx_crucifijo"))
        {
            CreateItemOnObject("tx_crucifijo", oJugador);
            SendMessageToPC(oJugador,"Se te ha dado un simbolo sagrado para detectar el mal.");
        }
    }//fin crucifijo del paladin..


Bien, cuando tenga el equipo, en cuanto entre la segunda vez al módulo recibirá un crucifijo de paladín, que esta en objetos de trama como Símbolo Sagrado (Al menos estará si habéis descargado el pequeño paquete erf de objetos importables que comentaba arriba). Realmente es una habilidad innata del Paladín, crearemos el script asociado. No lo hice yo, lo separé y retoque de las HCR (Hard Core Rules) Un conjunto de reglas que se hicieron en su día para conseguir que fuera lo más parecido a rol de mesa posible el Neverwinter.

/*
    Script modified by Ceros.
    September 8, 2002

    Modificado por Txibi.
    0:07 del 20 de Diciembre del 2004.

    script: tx_detectarelmal
*/
int FuerzaDelAura(object oMaloso)
{
    int iNivelesClasePrimera = GetLevelByPosition(1,oMaloso);
    int iNivelesClaseSegunda = GetLevelByPosition(2,oMaloso);
    int iNivelesClaseTercera = GetLevelByPosition(3,oMaloso);
    int iTotalClases = iNivelesClasePrimera + iNivelesClaseSegunda + iNivelesClaseTercera;
    int iProfesionPrimera = GetClassByPosition(1,oMaloso);
    int iProfesionSegunda = GetClassByPosition(2,oMaloso);
    int iProfesionTercera = GetClassByPosition(3,oMaloso);
    int iAlineamiento = GetAlignmentGoodEvil(oMaloso);
    int iRaza = GetRacialType(oMaloso);
    int iDadosDeVida = GetHitDice(oMaloso);
    int iAuraMalvada;
    if (iRaza == RACIAL_TYPE_UNDEAD && iAlineamiento == ALIGNMENT_EVIL)
    {
        //iAuraMalvada = iDadosDeVida / 2;
        iAuraMalvada = iDadosDeVida;
    }
    else if (iRaza == RACIAL_TYPE_ELEMENTAL && iAlineamiento == ALIGNMENT_EVIL)
    {
        iAuraMalvada = iDadosDeVida / 2;
    }
    else if (iRaza == RACIAL_TYPE_OUTSIDER && iAlineamiento == ALIGNMENT_EVIL)
    {
        //iAuraMalvada = iDadosDeVida;
        iAuraMalvada = iDadosDeVida * 2;
    }
    else if ((iProfesionPrimera == CLASS_TYPE_CLERIC || iProfesionSegunda == CLASS_TYPE_CLERIC ||
             iProfesionTercera == CLASS_TYPE_CLERIC) && iAlineamiento == ALIGNMENT_EVIL &&
             GetDeity(oMaloso) != "")
    {
        iAuraMalvada = iTotalClases;
    }
    //else iAuraMalvada = iDadosDeVida / 5;
    else iAuraMalvada = iDadosDeVida / 3;
    return iAuraMalvada;
}
//Devuelve un mensaje describiendo el poder del aura.
string PoderDelAura(int iAuraMalvada)
{
    if (iAuraMalvada <= 1)
    {
        return "Sencillo";
    }
    else if (iAuraMalvada >= 2 && iAuraMalvada <= 4)
    {
        return "Moderado";
    }
    else if (iAuraMalvada >= 5 && iAuraMalvada <= 10)
    {
        return "Fuerte";
    }
    else if (iAuraMalvada >= 11)
    {
        return "Apabullante";
    }
    return "";
}
/*
  Author: Big E
  Date:   July 20, 2002
  Given the facing value (0-360), set the compass direction and diplay
  the loction and distance of the evil.
*/
void DireccionDeteccion(float fFacing,object oPaladin,object oCriatura, float nDistancia)
{
    //Corrige el bug de GetFacing (Gracias a Iskander)
    if (fFacing >= 360.0)
        fFacing  =  720.0 - fFacing;
    if (fFacing <    0.0)
        fFacing += (360.0);
    int iFacing = FloatToInt(fFacing);
    /*
      359 -  2  = E
        3 - 45  = NEE
       46 - 87  = NNE
       88 - 92  = N
       93 - 135 = NNW
      136 - 177 = NWW
      178 - 182 = W
      183 - 225 = SWW
      226 - 267 = SSW
      268 - 272 = S
      273 - 315 = SSE
      316 - 358 = SEE
    */
    string sDireccion = "";
    if((iFacing >= 359) && (iFacing <=   2))
        sDireccion = "E";
    if((iFacing >=   3) && (iFacing <=  45))
        sDireccion = "NEE";
    if((iFacing >=  46) && (iFacing <=  87))
        sDireccion = "NNE";
    if((iFacing >=  88) && (iFacing <=  92))
        sDireccion = "N";
    if((iFacing >=  93) && (iFacing <= 135))
        sDireccion = "NNW";
    if((iFacing >= 136) && (iFacing <= 177))
        sDireccion = "NWW";
    if((iFacing >= 178) && (iFacing <= 182))
        sDireccion = "W";
    if((iFacing >= 183) && (iFacing <= 225))
        sDireccion = "SWW";
    if((iFacing >= 226) && (iFacing <= 267))
        sDireccion = "SSW";
    if((iFacing >= 268) && (iFacing <= 272))
        sDireccion = "S";
    if((iFacing >= 273) && (iFacing <= 315))
        sDireccion = "SSE";
    if((iFacing >= 316) && (iFacing <= 358))
        sDireccion = "SEE";
    string sDistancia = IntToString(FloatToInt(nDistancia));
    //Poder Malvado
    string sMalvado = PoderDelAura(FuerzaDelAura(oCriatura));
    SendMessageToPC(oPaladin, sMalvado + " Sientes la presencia del mal a unos" + sDistancia + " metros de ti en la direccion" + sDireccion);
}
//Author: Big E
//Date:   July 20, 2002
object CogerCercano(object oPaladin, int iContador)
{
    return GetNearestObjectToLocation(OBJECT_TYPE_CREATURE,GetLocation(oPaladin),iContador);
}
//Author Big E
//Date:   July 20, 2002
//Inserta tu metodo de alineamiento aqui.
//Devuleve True si el alineamiento de la criatura esta oculto.
int Alineamiento_Oculto(object oCriatura)
{
    //Si tiene un collar de no deteccion, (crear un collar con la etiqueta tx_maloculto).
    if(GetTag(GetItemInSlot(INVENTORY_SLOT_NECK,oCriatura)) == "tx_maloculto" )
       return TRUE;
    return FALSE;
}
//Author: Big E
//Date:   July 20, 2002
//Detect Evil By Round
void Detectar_El_Mal_Por_Ronda(object oPaladin,int iRonda)
{
    float RANGO                      =  40.0;  //Rango en metros.
    //int MAL_MINIMO                   =  29;    //El numero a que el blanco es considerado no bueno.
    int iContadorCriaturasMalvadas   =  0;     //El numero de auras malvadas en rango.
    int iElMasMalvado                =  0;     //El valor mas bajo del eje Bien-Mal.
    int iContador                    =  1;     //Un contador para el ciclo de criaturas.
    float nDistancia                 =  0.0;   //La distancia que hay entre el que detecta y la criatura.
    string sDistancia                =  "";    //Version string de la distancia.
    string sMalvado                  =  "";    //Fuerza del Aura.
    int bMalDetectado                =  FALSE; //Mal hallado?
    location lCriatura;                //Localizacion de la criatura.
    vector vCriatura;                  //Vector de la localizacion de la criatura.
    //Coger la localizacion del Paladin o quien detecte el mal.
    location lPaladin = GetLocation(oPaladin);
    //Coger la primera criatura mas cercana al Paladin.
    object oCriatura = CogerCercano(oPaladin,iContador);
    int iNivelesClasePrimera = GetLevelByPosition(1,oPaladin);
    int iNivelesClaseSegunda = GetLevelByPosition(2,oPaladin);
    int iNivelesClaseTercera = GetLevelByPosition(3,oPaladin);
    int iTotalClases = iNivelesClasePrimera + iNivelesClaseSegunda + iNivelesClaseTercera;
    while((GetIsObjectValid(oCriatura)) && (GetDistanceBetween(oPaladin,oCriatura) <= RANGO))
        {
        nDistancia = GetDistanceBetween(oPaladin,oCriatura);
        if((GetAlignmentGoodEvil(oCriatura) != ALIGNMENT_EVIL) || (Alineamiento_Oculto(oCriatura))) //No malvado o alineamiento oculto.
            {
            //Sigue a la siguiente criatura.
            iContador++;
            oCriatura = CogerCercano(oPaladin,iContador);
            continue;
            }
        bMalDetectado = TRUE; //Mal encontrado.
        lCriatura = GetLocation(oCriatura);
        //Ronda 1 - Presencia del Mal Detectada.
        if (iRonda == 1)
            {
            if(GetLocation(oPaladin) != GetLocalLocation(oPaladin,"lJugador"))
                {
                SendMessageToPC(oPaladin, "Has perdido la concentración al moverte. Tu intento de detectar el mal en las cercanías ha fallado.");
                ClearAllActions();
                return;
                };
            SendMessageToPC(oPaladin,"Sientes una presencia maligna.");
            return;
            }
        //Ronda 2 - Numero de Auras Malvadas.
        if(iRonda == 2)
            {
            if(GetLocation(oPaladin) != GetLocalLocation(oPaladin,"lJugador"))
                {
                SendMessageToPC(oPaladin, "Has perdido la concentración al moverte. Tu intento de detectar el mal en las cercanías ha fallado.");
                ClearAllActions();
                return;
                };
            iContadorCriaturasMalvadas++;
            if (FuerzaDelAura(oCriatura) > iElMasMalvado)
            {
                iElMasMalvado = FuerzaDelAura(oCriatura);
            }
            }
        //Ronda 3
        if(iRonda == 3)
            {
            if(GetLocation(oPaladin) != GetLocalLocation(oPaladin,"lJugador"))
                {
                SendMessageToPC(oPaladin, "Has perdido la concentración al moverte. Tu intento de detectar el mal en las cercanías ha fallado.");
                ClearAllActions();
                return;
                };
            //Coger el vector de la Criatura.
            vCriatura = GetPosition(oCriatura);
            //Distancia de la criatura.
            AssignCommand(oPaladin,SetFacingPoint (vCriatura));
            //Coger con la brujula la direccion de la criatura.
            AssignCommand(oPaladin,DireccionDeteccion(GetFacing(oPaladin),oPaladin,oCriatura,nDistancia));
            }
        iContador++;
        oCriatura = CogerCercano(oPaladin,iContador);
        }
    if((iRonda == 2) && (bMalDetectado))
        {
        SendMessageToPC(oPaladin," Sientes la presencia de " + IntToString(iContadorCriaturasMalvadas) + " criaturas que perturban tu paz interior.");
        if(PoderDelAura(iElMasMalvado) == "Apabullante")
            {
            //If the caster is good, they are stunned by the overwhelming evil
            if(GetAlignmentGoodEvil(oPaladin)==ALIGNMENT_GOOD && iElMasMalvado > (2 * iTotalClases))
                {
                SendMessageToPC(oPaladin,"La criatura que más desazón te produce es " + GetStringLowerCase(PoderDelAura(iElMasMalvado)) + ". ¡El terror te deja momentaneamente paralizado! ");
                if (!GetIsImmune(oPaladin,IMMUNITY_TYPE_MIND_SPELLS))
                {
                    ApplyEffectToObject(DURATION_TYPE_TEMPORARY, EffectStunned(),oPaladin,ROUND);
                }
                else
                {
                    ApplyEffectToObject(DURATION_TYPE_INSTANT,EffectVisualEffect(VFX_IMP_STUN),oPaladin);
                    AssignCommand(oPaladin,ActionPlayAnimation(ANIMATION_LOOPING_PAUSE_TIRED,1.0,ROUND));
                    DelayCommand(0.5,SetCommandable(FALSE,oPaladin));
                    DelayCommand(ROUND,SetCommandable(TRUE,oPaladin));
                }
                return;
                }
            else
                SendMessageToPC(oPaladin,"La criatura que más desazón te produce es " + GetStringLowerCase(PoderDelAura(iElMasMalvado)));
            }
        }
    if ((iRonda == 1) && (!bMalDetectado))
    {
        SendMessageToPC(oPaladin,"No percibes nada que perturbe tu paz interior en este lugar.");
    }
}
//Author: Big E
//Date:   July 20, 2002
void Detectar_El_Mal(object oPaladin)
{
    SetLocalLocation(oPaladin,"lJugador",GetLocation(oPaladin));
    DelayCommand(ROUND,AssignCommand(oPaladin,Detectar_El_Mal_Por_Ronda(oPaladin,1)));
    DelayCommand(ROUND+ROUND,AssignCommand(oPaladin,Detectar_El_Mal_Por_Ronda(oPaladin,2)));
    DelayCommand(ROUND+ROUND+ROUND,AssignCommand(oPaladin,Detectar_El_Mal_Por_Ronda(oPaladin,3)));
}

float ROUND = RoundsToSeconds(6); //Usando 6 segundos para cada ronda.

void main()
{
    //Anulando en las dos lineas de abajo que se vea usar la habilidad de Paladin.
    //effect eHead = EffectVisualEffect(VFX_IMP_HEAD_MIND);
    //ApplyEffectToObject(DURATION_TYPE_INSTANT,eHead,OBJECT_SELF);
    Detectar_El_Mal(OBJECT_SELF);
}

Bueno, que nos queda... poco ya para empezar a mapear. Crearemos un libro de emociones para poder hacer tiradas de persuasión, fuerza, carisma, etc..., como colocar los desencadenantes de descanso... y poca cosa ya.

Un descanso y seguimos.

Txibi.

Editado por Txibi, 16 October 2010 - 11:10 AM.


#14 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 20 July 2005 - 03:12 PM

Saludos.

Libro de Habilidades.

En sí es muy fácil, pero trabajoso. Sencillamente hay que atar un script a cada acción que se quiera hacer.

Por ejemplo si queremos hacer una tirada de abrir cerraduras, en acciones emprendidas de esa frase se coloca:

//Chequeo de habilidades.
void main()
{
    object oJugador = GetLastSpeaker();
    int iDado = d20();
    int iModificador = GetSkillRank (SKILL_OPEN_LOCK, oJugador);
    int iResultado = iDado + iModificador;
    string sTirada = IntToString(iDado);
    string sModificador = IntToString(iModificador);
    string sResultado = IntToString(iResultado);
    string sHabilidad = "Chequeo de ";
    AssignCommand (oJugador, SpeakString(sHabilidad+"Abrir cerraduras, Tirada: "+sTirada+" Modificador: "+sModificador+" = "+sResultado));
}//fin cuerpo principal.

Si se quiere bailar, pues:

//Libro de Habilidades, bailar.
void main()
{
    object oJugador = GetLastSpeaker();
    AssignCommand (oJugador, ActionPlayAnimation (ANIMATION_FIREFORGET_VICTORY2));
    DelayCommand (3.0, AssignCommand (oJugador, ActionPlayAnimation (ANIMATION_LOOPING_TALK_LAUGHING, 3.0, 2.0)));
    DelayCommand (3.0, AssignCommand (oJugador, PlayVoiceChat (VOICE_CHAT_LAUGH)));
    DelayCommand (5.0, AssignCommand (oJugador, ActionPlayAnimation (ANIMATION_FIREFORGET_VICTORY1)));
    DelayCommand (8.5, AssignCommand (oJugador, ActionPlayAnimation (ANIMATION_FIREFORGET_VICTORY3)));
    DelayCommand (11.0, AssignCommand (oJugador, ActionPlayAnimation (ANIMATION_LOOPING_GET_MID, 3.0, 2.0)));
    DelayCommand (14.5, AssignCommand (oJugador, PlayVoiceChat (VOICE_CHAT_LAUGH)));
    DelayCommand (13.0, AssignCommand (oJugador, ActionPlayAnimation (ANIMATION_FIREFORGET_VICTORY3)));
}//fin cuerpo principal.

En el caso de beber sería:

//Libro de Habilidades, beber.
void main()
{
    object oJugador = GetLastSpeaker();
    AssignCommand (oJugador, ActionPlayAnimation (ANIMATION_LOOPING_PAUSE_DRUNK, 1.0, 10000.0));
}//fin cuerpo principal.

Y así con todas las habilidades... lo único es buscar la constante que representa la acción que quieres reproducir o la habilidad a testear.

Podéis bajaros el libro de habilidades que usaremos en el ejemplo desde descargas de txibi.com (disculpa el desastroso aspecto del lugar, pero estoy aprendiendo lo de webs y esas cosas)

Libro de Habilidades

Para que funcione correctamente tiene que tener el siguiente bloque en el script de Sucesos del Módulo, en el de OnActivateItem algo así:

void main()
{
   //--------------------------------------------------------------------------

   //Recordamos quiene es el jugador "activador"
   object oJugador = GetItemActivator();
   //Tambien controlamos que objeto estamos activando.
   object oArtefacto = GetItemActivated();
   //El objetivo para aquellos objetos que necesiten un "target", una diana.
   object oObjetivo = GetItemActivatedTarget();
   //El lugar destino de es una localizacion en vez de una criatura.
   location locDestino = GetItemActivatedTargetLocation();

   //--------------------------------------------------------------------------
   //Libro de Emociones.
   if(GetTag(oArtefacto) == "tx_librohab_1")
   {
       //Asignamos la orden de su uso, normalmente una conversacion o efecto.
       AssignCommand(oJugador, ActionStartConversation(oJugador, "tx_librohab_1", TRUE));
       return;
   }
   //--------------------------------------------------------------------------
}


Para el descanso.

Tal como lo tenemos, no se puede descansar, debemos crear un desencadente de descanso. Sólo se podrá descansar en esos sitios seguros.

Crear uno en cualquier parte para hacer el testeo, coged comida, ya que no descansará sin comida.

Crear un nuevo desencadenante genérico que llamaremos... pues por ejemplo descansando.

En el OnEnter de ese desencadeante colocaremos el Script: zona_segura_on
y en el OnExit de ese desencadeante colocaremos el Script: zona_segura_off

/*
    Script: zona_segura_on
    Colocar la variable "descansando" a 1 para descansar.
*/

//Cuerpo Principal.
void main()
{
    object oJugador = GetEnteringObject();
    if ( GetIsPC(oJugador) )
    {
        FloatingTextStringOnCreature("Este lugar parece seguro para descansar", oJugador);
        SetLocalInt(oJugador,"descansando",1);
    }
}//fin del cuerpo principal.

/*
    Script_ zona_segura_off
    Colocar la variable "descansando" a 0 para impedir el descanso.
*/

//Cuerpo Principal.
void main()
{
    object oJugador = GetExitingObject();
    if ( GetIsPC(oJugador) )
    {
        FloatingTextStringOnCreature("Abandonas la zona de descanso.", oJugador);
        SetLocalInt(oJugador,"descansando",0);
    }
}//fin del cuerpo principal.

Bien. Con esto tenemos el terminado el sistema de descanso. Recuerda, en cada zona que quieras habilitar para descansar debes pintar un desencadenante de descanso.

Para terminar, enlazaremos el limbo con la tierra.

Creamos una calavera de trama para los muertos, nuevo objeto, misceláneo mediano, escogemos una calavera y lo colocamos en objeto de trama. Lo ponemos como de trama y que no se pueda dejar, al preguntar nombre pondremos tx_muerto para que marque esa etiqueta y esa resref. Luego se cambia el nombre por otro, por ejemplo. Estas muerto. Acordaros de ponerlo de trama y pinchar la casilla de No se puede dejar (en propiedades).

Tal como tenemos los scripts, cuando alguién muerto se desconecta, no importa los meses que hayan pasado. Seguira muerto. Y si se desconecta en puntos de vida negativos, también lo recuerda el motor y aparecerá con la misma vida que cuando se marchó.

Creamos en el limbo una puerta de salida, en nuestro ejemplo, peculiaridades, puerta de posada encajará bien. Colocamos una puerta en ese hueco, la hacemos de trama, le ponemos una etiqueta, tal vez tx_bajada_limbo y en transición de área pinchamos punto de ruta. Pulsamos Configurar Transición de Área. Escogemos área objetivo (en el ejemplo será las llanuras fronterizas). En tipo de objetivo pinchamos punto de ruta, aparecerán los qque esten en esas zona, escogemos el de inicio del mundo: 1_mundo_inicio

Ahora cuando mueran tus jugadores y bajen del limbo aparecerán donde se aparece cuando se entra por primera vez al módulo. Si quieres que aparezcan en otra parte, un cementerio, una iglesia, etc... sencillamente cambia la etiqueta 1_mundo_inicio por la de destino.

En el limbo vamos a colocar un script que borre la calavera al bajar y que imponga una penalización extra. (Esos clerigos que resuciten, en vez de regenerar para evitar el camino de vuelta.) Este en concreto quita 500 px por nivel y la mitad del oro, pero podéis poner las penalizaciones que creais oportunas.

El script que hay que atar en la bajada, lo colocamos en guiones en OnAreaTransitionClick y es este:

/*
Script: 1_tx_bajar_limbo
*/

//Cuerpo Principal.
void main()
{
    object oMuerto = GetClickingObject();
    object oDestino = GetTransitionTarget(OBJECT_SELF);
    object oModulo = GetModule();
    int nXP = GetXP(oMuerto);
    int nPenalty = 500 * GetHitDice(oMuerto);
    int nHD = GetHitDice(oMuerto);
    int nMin = ((nHD * (nHD - 1)) / 2) * 1000;
    int nNewXP = nXP - nPenalty;
    if (nNewXP < nMin)
    nNewXP = nMin;
    SetXP(oMuerto, nNewXP);
    int nGoldToTake = 0;
    if (nHD == 1)
        nGoldToTake = FloatToInt(0.50 * GetGold(oMuerto));
    else
        nGoldToTake = FloatToInt(0.50 * GetGold(oMuerto));

    AssignCommand(oMuerto, TakeGoldFromCreature(nGoldToTake, oMuerto, TRUE));


    //Borramos la Calavera de Muerte.
    AssignCommand(oMuerto, DestroyObject(GetObjectByTag("tx_muerto")));

    DelayCommand(4.0, FloatingTextStrRefOnCreature(58299, oMuerto, FALSE));
    DelayCommand(4.8, FloatingTextStrRefOnCreature(58300, oMuerto, FALSE));

    //El Salto al Mundo de Los Vivos.
    SetAreaTransitionBMP(AREA_TRANSITION_RANDOM);
    AssignCommand(oMuerto, JumpToObject(oDestino));
}//fin del cuerpo principal.

Ya tenemos el motor más o menos listo. Esto debería tener una cosistencia básica.

Opcional: Tablon de Anuncios.

Si se quisiera un tablón de anuncios, este lo separé y lo traducí de las Hard Cores Rules. Colocadlo en una zona tranquila (que no este la gente hablando cerca del escriba)

Tablón de Anuncios.

Bien, otra parada.

Ahora quedaría el mapeado de las áreas y generar las misiones.

Como generar misiones.
Como diseñar ayudantes.

Txibi.

Editado por Txibi, 20 July 2005 - 03:14 PM.


#15 Txibi

Txibi

    Antediluvian

  • Miembro DLAN
  • PipPipPipPipPip
  • 4701 posts

Posteado 20 July 2005 - 03:40 PM

Saludos.

Bien vamos a terminar. Ya tenemos creado el sistema de scripts que da una consistencia base. Ahora es cuestión de decorar un poco las áreas con el aurora.

Tenemos un área inicial (El descenso); Un limbo, donde los sufridos PJs (Personajes Jugadores) juegan a las cartas o hacen otras actividades en la espera de ser resucitados o bajados al mundo de los vivos; Una pequeña zona de Equipo para cuando se crea la ficha; El área inicial (Las Llanuras); Una Posada; y también crearemos una mina abandonada para el primer amago de misión.

Mapear con calma esas zonas, añadiendo los ubicados y sonidos que mejor encajen a vuestro gusto.

Se supone que ya sabeis enlazar áreas entre sí, pero si os entran dudas mirar como hicimos el enlace del limbo, aunque en las áreas entrelazadas normalmente no tendrán ningún script asociado.

En nuestra posada o cerca de ella, vamos a colocar un riachuelo. Que se pueda pasar sin riesgo. Pondremos un puente.

Lo del puente es para hacer ver a los jugadores que los accidentes del terreno, en un servidor de rol, pueden ser algo más que simples objetos decorativos. Los jugadores están más que acostumbrados a pegarse a volcanes de lava, cruzar los ríos como si fueran charcos corriendo por encima y detalles similares que son irrelevantes en una arena cuyo único sentido es inflarse a ostias.

Vamos a crear un río de verdad, en el que si te pones a cruzarlo por otro lado que no sea el puente tienes la posibilidad de caerte, mojarte, y sufrir algún daño.

Vamos a crear un desencadenante nuevo, ponerle el nombre que queráis, yo lo llame, tx_cruzar_rios_01. En el OnEnter de ese desencadenante crearemos un script que será; tx_cruzamos_rio

Listo, colocamos el desencadenante en el curso del río.



Y ese script lo que hará será realizar un testeo de reflejos del jugador que cruza el río, si no lo pasa, resbalará y caerá al río recibiendo un poco de daño por frío, un % de su vida de forma que sea justo por igual a niveles bajos y altos y de forma que no pueda morir nadie pero si debilitarse.

/*
Script: tx_cruzamos_rio

   Se comprueba los reflejos del que salta al rio... y si falla se le quitan un
10% de su vida.

   Si falla la tirada eso si, se cae al agua.
*/

//Cuerpo Principal.
void main()
{
    object oPatoso = GetEnteringObject(); //Vemos quien quiere cruzar el rio.
    int iReflejos = GetReflexSavingThrow(oPatoso);//Cogemos su modificador.

    int iSalto = d10();  //Mitico dado de 10.
    iReflejos = iReflejos + iSalto;//El modificador de reflejos + 1D10.

    //string sMensaje = IntToString(iReflejos);
    //SendMessageToPC(oPatoso, sMensaje);

    if (iReflejos >= 10)//Si saca 10 o mas cruza.
    {
        SendMessageToPC (oPatoso, "Vas saltando de piedra en piedra.");
    }
    else  //No lo saca, pues al agua.
    {
        SendMessageToPC (oPatoso, "Caes al agua con un gran estruendo y mojandote todo");
        int iVidaActual = GetCurrentHitPoints(oPatoso);
        int iGolpeCaida = (iVidaActual / 10);

        effect eGolpeCaida = EffectDamage(iGolpeCaida, DAMAGE_TYPE_COLD, DAMAGE_POWER_NORMAL);
        AssignCommand(oPatoso, ClearAllActions());
        ApplyEffectToObject(DURATION_TYPE_INSTANT ,eGolpeCaida, oPatoso);
        AssignCommand (oPatoso ,ActionPlayAnimation (ANIMATION_LOOPING_DEAD_FRONT, 1.0, 10000.0));
    }
}//Fin del cuerpo principal.

Vamos a cambiar de área. Vamos al interior de la posada pero antes no vamos a parar en las puertas. Se supone que los PNJs (Personajes No Jugadores) del módulo regularmente las cierran si las encuentran abiertas, pero no vamos a estar moviendo a los PNJs a cerrarlas. Vamos a colocar un pequeño Script en el guión OnOpen de las puertas, para que, pasado unos segundos se cierren solas.

/*
Script: tx_cierrapuerta
*/

//Cuerpo Principal.
void main()
{
    DelayCommand(10.0, ActionCloseDoor (OBJECT_SELF));
}//Fin del cuerpo pricipal.

Bueno estamos en el interior de la Posada. Lo ideal es que la gente pueda sentarse, así que cogemos una silla cualquiera, editamos copia, ponemos utilizable (y aconsejado de trama por los vándalos), etiqueta al gusto. Y en guiones, en OnUsed colocamos este Script:

/*
Script: tx_sillasentable
*/

//Cuerpo Principal.
void main()
{
   object oJugador = GetLastUsedBy(); // El que usa la silla.
   object oSilla = OBJECT_SELF; // OBJECT_SELF + AssignCommand, no aconsejable.
   AssignCommand(oJugador, ActionSit(oSilla)); // Le ordena sentarse al que la usa.
}//Fin del cuerpo principal.

Ahora ya tenemos en personalizado la silla lista, pintamos la que necesitemos, procurando dejar especio libre delante para que se puedan sentar los PJs.

Luego crearemos al posadero, que será un pequeño comerciante que venda comida, bebida y alguna cosilla. También crearemos una pequeña misión o quest.

Un Descanso.

Txibi.

Editado por Txibi, 16 October 2010 - 11:14 AM.




Responder



  


A Bragol. Tus amigos te echan de menos.