Mensajes recientes

#1
Tutoriales / Tutorial de Script C++ World o...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM
Todos los créditos a mariodanny91 por su publicación original en WoWCreador
Tutorial de Script C++ World of Warcraft 3:

En esta guía, enseñaré una de las maneras de hacer un script C++ para el emulador JadeCore que está basado en TrinityCore antiguo. Les servirá de conocimiento base para otros emuladores más actualizados y motivarlos a investigar mas sobre el tema. Vale aclarar que todo lo planteado aquí es de manera autodidacta no soy programador, solo comparto lo que he aprendido.

Para esta guia deben tener instalado Visual Studio, Cmake y otras dependencias que exija el core ya sea OpenSSL,Boost,Mysql en sus versiones x86 o x64.


Tutoriales anteriores:
You are not allowed to view links. Register or Login
You are not allowed to view links. Register or Login

Punto sobre los cuales hablare:
-Como hacer un Areatrigger en C++.

Estructura del Script.
Esta es una plantilla de Script de la cual partiremos:

* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptPCH.h"
enum Npc
{
};
enum Movie
{
};
enum Quest
{
   
};
class AreaTrigger_tutorial: public AreaTriggerScript
{
public:
    AreaTrigger_tutorial() : AreaTriggerScript("AreaTrigger_tutorial")
    {
       
    }
};
void AddSC_tutorial()
{
    new AreaTrigger_tutorial();
}

1-Enumerar los datos que vamos a utilizar:
enum Npc
{
    NPC_KILLCREDIT = 123,
};
enum Movie
{
    MOVIE = 321,
};
enum Quest
{
    QUEST_X    = 12345,
};

2-Explicar cada funcion:

-Cuando el player entra área y se activa el areatrigger.

bool OnTrigger(Player* player, AreaTriggerEntry const* trigger)    {return false;}
3-Le agregamos una condicion:
if (player->GetQuestStatus(QUEST_X) == QUEST_STATUS_INCOMPLETE)
{
   
}

El Script deberia ir quedando asi:

/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptPCH.h"
enum Npc
{
    NPC_KILLCREDIT = 123,
};
enum Movie
{
    MOVIE = 321,
};
enum Quest
{
    QUEST_X    = 12345,
};
class AreaTrigger_tutorial : public AreaTriggerScript
{
public:
    AreaTrigger_tutorial() : AreaTriggerScript("AreaTrigger_tutorial")
    {
    }
    bool OnTrigger(Player* player, AreaTriggerEntry const* trigger)
    {
       
        if (player->GetQuestStatus(QUEST_X) == QUEST_STATUS_INCOMPLETE)
        {
            player->KilledMonsterCredit(NPC_KILLCREDIT, 0);
            player->SendMovieStart(MOVIE);
        }
       
        return false;
    }
};
   
void AddSC_tutorial()
{
    new AreaTrigger_tutorial();
}

Explico que hace el AreaTrigger_tutorial sencillo:

Si el player tiene la mision X incompleta, cuando entre al área se activa el areatrigger y

le cumple un objectivo de la mision X y le muestra un video.
*(no se debe hacer con misiones de mas de un objectivo, puede generar bucle o crash ya que mientra el player

tenga la mision incompleta y este en el area se va a seguir ejecutando el areatrigger).


*El ID del video lo encontramos en Movie.dbc y podemos ir mirando cuales son con el comando
.debug play movie

Syntax: .debug play movie #movieid (Play movie #movieid for you.)


*El killcredit esta definido en creature_template, columna KillCredit1 o KillCredit2 y tiene relacion con el objectivo de la mision en quest_template,
columna RequiredNpcOrGo1-10.



Ahora vamos a la parte de SQL:

Este script debemos vincularlo con la base de datos en la tabla areatrigger_scripts, la entry del areatrigger se encuentra en Areatrigger.dbc.
Para saber cual es utilizamos el comando (solo funciona estando en GM ON):

.debug areatriggers
Syntax: .debug areatriggers (Toggle debug mode for areatriggers. In debug mode GM will be notified if reaching an areatrigger)

Nos ira mostrando en el chat el id del areatrigger a medida que entremos y salgamos de las areas, escojemos el que necesitamos y ese será el entry.

En ScriptName es el nombre del script AreaTrigger_tutorial.

DELETE FROM areatrigger_scripts WHERE entry=1234;
INSERT INTO `areatrigger_scripts`(`entry`, `ScriptName`) VALUES
(1234, 'AreaTrigger_tutorial');

*No ejecuten este ejemplo en su base de datos, puede que no coincida con ningun areatrigger.


Compilamos y que lo disfruten.
#2
Tutoriales / Tutorial de Script C++ World o...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM
Todos los créditos a mariodanny91 por su publicación original en WoWCreador
En esta guía, enseñaré una de las maneras de hacer un script C++ para el emulador JadeCore que está basado en TrinityCore antiguo. Les servirá de conocimiento base para otros emuladores más actualizados y motivarlos a investigar mas sobre el tema. Vale aclarar que todo lo planteado aquí es de manera autodidacta no soy programador, solo comparto lo que he aprendido.

Para esta guia deben tener instalado Visual Studio, Cmake y otras dependencias que exija el core ya sea OpenSSL,Boost,Mysql en sus versiones x86 o x64.


Tutorial anterior:

You are not allowed to view links. Register or Login

Tutorial de Script C++ World of Warcraft 1:  En esta guía, enseñaré una de las maneras de hacer un script C++ para el emulador JadeCore  que está basado en TrinityCore antiguo.  Les servirá de conocimiento base para otros emuladores más actualizados y motivarlos a investigar mas sobre el tema...


Punto sobre los cuales hablaré:

-Fases.
-Como hacer un Intro.

-Controlar invocaciones.


-Primero vamos a repasar algunos conceptos basicos de C++ y detalles referente al core:


Operadores Logicos:

        C++:
&&  And ó Y 
||  Or ó O
!    Not ó No

Operadores Relacionales:

        C++:
==    Igual que
<    menor que
>    mayor que
<=    menor o igual que
>=    mayor o igual que
!=    no es igual o desigual
=    asignacion(no confundir con igual que)

Operadores Matematicos:

        C++:
-    restar
+    sumar
*    multiplicar
/    dividir
%    modulus(devuelve el resto de una division)

-Tipos de variables mas utilizadas:

        C++:

Tipo        Valores
bool        true o false
float        los llamados numeros con coma.(1.2f)
int            numeros enteros incluye positivos y negativos.
uint32        numeros enteros solo positivos.
uint64        numeros enteros solo positivos.
uint significa unsigned int

*La diferencia entre uint8, uint16, uint32, uint64 son los valores que pueden almacenar en memoria.



        C++:

Tipo    Valores
uint8     0 a 32 768
uint16    0 a 65 535
uint32    0 a 4 294 836 225
uint64    0 a 8 589 672 450

-Como declarar una variable:
Los nombres de las variables no pueden tener espacios y no puede coincidir con las palabras claves utilizadas por el compilador:

Ej: auto, else, new, true, case, class, if, return, void, default, break...

        C++:
tipo espacio variable punto y coma
uint32 timer intro; (MAL)
uint32 break; (MAL)
uint32 timer_intro; (BIEN)
uint32 timerintro; (BIEN)

-Despues de declarar le damos un valor a las variables:

        C++:

timerintro = 0;
-Algunos detalles del core que se deben conocer:


-Constantes de Tiempo:
(Los tiempos se declaran en milisegundos)


        C++:

MINUTE          = IN_MILLISECONDS * 60,
HOUR            = MINUTE*60,
DAY             = HOUR*24,
WEEK            = DAY*7,
MONTH           = DAY*30,
YEAR            = MONTH*12,
IN_MILLISECONDS = 1000

1000 milisegundos equivale a 1 segundo.
Seria igual decir 1 * IN_MILLISECONS, es 1 multiplicado por la constante de tiempo IN_MILLISECONDS = 1000.

-Que es urand:


        C++:

urand(uint32 min, uint32 max);
urand(tiempo minimo, tiempo maximo);
urand(15000, 20000)
urand(15, 20) * IN_MILLISECONDS
*El evento va a ocurrir de manera randon en un tiempo entre 15 segundos y 20 segundos.

-Podemos hacer el casteo de una magia tanto con el ID de la magia, como con una asignacion del enum Spell:

* Los enum no son mas que declaraciones constantes con las cuales trabajaremos un poco mas organizado ya que es mas facil
reconocer en el codigo el nombre de la magia que el ID.


        C++:

enum Spell
{
    SPELL_PRESENCIA_DE_ESCARCHA        = 48266,
}
me->CastSpell(me, SPELL_PRESENCIA_DE_ESCARCHA, 0);
me->CastSpell(me, 48266, 0);

*Tambien se aplica a invocaciones, textos, fases,..


-Estructura de los eventos:

        C++:

events.ScheduleEvent(uint32 eventId, uint32 time, uint32 groupId = 0, uint32 phase = 0);
events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 5000, 0, PHASE_LICH_KING);
events.SetPhase(uint32 phase);
events.SetPhase(PHASE_LICH_KING);
events.IsInPhase(uint8 phase);
events.IsInPhase(PHASE_DK);

Despues de repasar estos detalles referente al core y a C++.

Comenzaremos enumerando los datos que vamos a utilizar:


        C++:

enum Npc
{
    NPC_SUMMON_DK = 31325,
    NPC_SUMMON_LK = 31754,       
};
enum Texts
{
    SAY_INTRO                = 0,
    SAY_PHASE_DK            = 1,       
    SAY_SUMMON_DK            = 2,
    SAY_SUMMON_LK            = 3,       
    SAY_PHASE_LICH_KING        = 4,
    SAY_SLAY                = 5,
    SAY_DEATH                = 6,
};
enum Spells
{           
    SPELL_PRESENCIA_DE_ESCARCHA            = 48266,
    //DK   
    SPELL_EXPLOSION_AULLANTE            = 61061,
    SPELL_GOLPE_DE_ESCARCHA                = 79895,
    SPELL_INVIERNO_SIN_REMORDIMIENTO    = 108200,                   
    //LICH_KING
    SPELL_SOUL_REAPER                    = 69409,
    SPELL_PAIN_AND_SUFFERING            = 72133,
};
enum Events
{
    EVENT_INTRO                            = 1,
    EVENT_SUMMON_DK                        = 2,
    EVENT_SUMMON_LK                        = 3,
    //DK
    EVENT_EXPLOSION_AULLANTE            = 4,
    EVENT_GOLPE_DE_ESCARCHA                = 5,
         
    //LICH_KING
    EVENT_INVIERNO_SIN_REMORDIMIENTO    = 6,
    EVENT_SOUL_REAPER                    = 7,
    EVENT_PAIN_AND_SUFFERING            = 8,
};
         
enum Phases
{
    PHASE_INTRO            = 1,
    PHASE_DK            = 2,       
    PHASE_LICH_KING        = 3,       
};

-Agregar los eventos con sus respectivos tiempos:
Al declararse en la funcion void EnterCombat empezaran a contar el tiempo en el momento que empiece el combate y tambien empezara la fase PHASE_DK.


        C++:

void EnterCombat(Unit* who)
{
    events.SetPhase(PHASE_DK);
    events.ScheduleEvent(EVENT_SUMMON_DK, 30000, 0, PHASE_DK);
    events.ScheduleEvent(EVENT_EXPLOSION_AULLANTE, urand(10, 15) * IN_MILLISECONDS, 0, PHASE_DK);
    events.ScheduleEvent(EVENT_GOLPE_DE_ESCARCHA, 8000, 0, PHASE_DK);
}

-Crear los eventos con sus respectivos spell, summon, textos, etc:

        C++:

while (uint32 eventId = events.ExecuteEvent())
                    {
                        switch (eventId)
                        {
                        case EVENT_SUMMON_DK:
                            Talk(SAY_SUMMON_DK);
                            me->SummonCreature(NPC_SUMMON_DK, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN);
                            events.ScheduleEvent(EVENT_SUMMON_DK, 30000, 0, PHASE_DK);
                            break;                   
                        case EVENT_EXPLOSION_AULLANTE:
                            if (Unit * target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, false))
                                DoCast(target, SPELL_EXPLOSION_AULLANTE);
                            events.ScheduleEvent(EVENT_EXPLOSION_AULLANTE, 10000, 0, PHASE_DK);
                            break;
                        case EVENT_GOLPE_DE_ESCARCHA:
                            DoCastVictim(SPELL_GOLPE_DE_ESCARCHA);
                            events.ScheduleEvent(EVENT_GOLPE_DE_ESCARCHA, 8000, 0, PHASE_DK);
                            break;
                         
                        case EVENT_SUMMON_LK:
                            Talk(SAY_SUMMON_LK);
                            me->SummonCreature(NPC_SUMMON_LK, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN);
                            events.ScheduleEvent(EVENT_SUMMON_LK, 30000, 0, PHASE_LICH_KING);
                            break;
                        case EVENT_SOUL_REAPER:
                            DoCastVictim(SPELL_SOUL_REAPER);
                            events.ScheduleEvent(EVENT_SOUL_REAPER, urand(15000, 20000), 0, PHASE_LICH_KING);
                            break;
                        case EVENT_PAIN_AND_SUFFERING:
                            DoCastToAllHostilePlayers(SPELL_PAIN_AND_SUFFERING);
                            events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 5000, 0, PHASE_LICH_KING);
                            break;
                        default:
                            break;
                        }
                    }

-Crear condicion para cambio de fase:

        C++:

if (events.IsInPhase(PHASE_DK) && HealthBelowPct(50))
                    {       
                        events.SetPhase(PHASE_LICH_KING);
                        Talk(SAY_PHASE_LICH_KING);
                        me->CastSpell(me, SPELL_INVIERNO_SIN_REMORDIMIENTO, 0);
                        me->SetDisplayId(30721);
                        events.ScheduleEvent(EVENT_SUMMON_LK, 30*IN_MILLISECONDS, 0, PHASE_LICH_KING);
                        events.ScheduleEvent(EVENT_SOUL_REAPER, urand(15, 20)*IN_MILLISECONDS, 0, PHASE_LICH_KING);
                        events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 5000, 0, PHASE_LICH_KING);                   
                    }

*Si los evento estan en PHASE_DK y los puntos de vida estan por dejajo del 50% cambiar a fase PHASE_LICH_KING y empezar a ejecutar los eventos de esa fase.


Nota:Las condiciones son un tema delicado en C++ ya que deben estar bien especificadas para no generar errores:
Ej:

 
 
        C++:
 
if (player->GetQuestStatus(12345) == QUEST_STATUS_COMPLETE)
{
    Talk(0);
}

Si el jugador tiene la mision 12345 completada, el npc hablara.
Es decir que mientras el jugador tenga la mision completada el npc hablara y hablara y hablara indefinidamente y obtendriamos esto:

Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login



Pero si agregamos una variable de tipo booleana (bool):

 
 
        C++:
 
if (player->GetQuestStatus(12345) == QUEST_STATUS_COMPLETE) && (!talk)
{
    Talk(0);
    talk = true;
}

(!talk es lo mismo que decir talk=false)
En este caso la condicion dice si el jugador tiene la mision 12345 completada y la variable talk es false, el npc hablara y talk sera true.

Al ser talk true se deja de cumplir la condicion y solo hablara una sola vez.


2-Como hacer un intro:


Con estas lineas crearemos un intro de manera practica:
 
 
        C++:
 
std::list playerList;
            GetPlayerListInGrid(playerList, me, 30.0f);
            for (auto player : playerList)
            {
             
            }

*El npc creara una lista de los player que esten a su alrededor en un rango de 30 metros, algo asi como un radar.
Se ejecutara una accion si un player entra en ese rango.

-Quedaria asi:

 
 
        C++:
 
std::list playerList;
            GetPlayerListInGrid(playerList, me, 30.0f);
            for (auto player : playerList)
            {
                events.Update(diff);
                while (uint32 eventId = events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                    case EVENT_INTRO:
                    {
                        timerintro++;
                        if (timerintro == 1)
                        {
                            Talk(SAY_INTRO);
                        }
                        if (timerintro == 11)
                        {
                            me->CastSpell(me, 127511, 0);
                        }
                        if (timerintro == 12)
                        {
                            me->SetDisplayId(22235);
                            me->SetObjectScale(2.0f);
                        }
                        if (timerintro == 14)
                        {
                            Talk(SAY_PHASE_DK);
                            me->setFaction(14);
                            me->CastSpell(me, SPELL_PRESENCIA_DE_ESCARCHA, 0);
                            SetEquipmentSlots(false, 33475);
                        }
                        if (timerintro == 18)
                        {
                            AttackStart(player);
                        }
                        events.ScheduleEvent(EVENT_INTRO, 1000);
                        break;
                    }
                    }
                }
            }

*Si un player entra en el rango de 30 metros empezara el EVENT_INTRO y la variable timerintro incrementara su valor a medida que pase el tiempo con timerintro++.
Con las siguientes condiciones a medida que el valor de timerintro incremente se ejecutara el intro.

si timerintro es igual que 1

Hablara


si timerintro es igual que 11
casteara una magia

si timerintro es igual que 12

cambiara su displayID, el modelo visual del npc
cambiara su escala a 2

si timerintro es igual que 14

Hablara
cambiara su faccion a 14(Hostil)

casteara una magia
equipara un arma

si timerintro es igual que 18

comenzara a atacar al player


3-Controlar invocaciones:
Hasta el momento las invocaciones atacan por que son hostiles pero las controla el core.

Controlaremos invocaciones con la funcion void JustSummoned.


 
 
        C++:
 
void JustSummoned(Creature* summon)
        {
            if (summon->GetEntry() == NPC_SUMMON_DK)
            {
                summon->CastSpell(summon, 48265, false);
                if (Unit * target = SelectTarget(SELECT_TARGET_RANDOM, 0))
                    summon->AI()->AttackStart(target);
            }
            if (summon->GetEntry() == NPC_SUMMON_LK)
            {
                summon->CastSpell(summon, 49222, false);
                if (Unit * target = SelectTarget(SELECT_TARGET_BOTTOMAGGRO, 0))
                    summon->AI()->AttackStart(target);
            }
        }

*Si la criatura invocada(summon) es NPC_SUMMON_DK o NPC_SUMMON_LK, castera una magia y seleccionara un objetico para atacar.
Cada invocacion casteara una magia, seleccionara un objetivo diferente y atacara en cuanto sea invocada.

La funcion solamente ejecutara cualquier accion en el momento de la invocacion no despues de invocado el npc.
Podemos hacer que castee una magia, que hable, que camine hacia un lugar, etc..

 
 
        C++:
 
summon->GetMotionMaster()->MovePoint(0, 966.20f, 3602.97f, 196.58f);//se mueva hacia un punto.
summon->CastSpell(summon, 49222, false);//castee una magia.
summon->DespawnOrUnsummon(10*IN_MILLISECONDS);//desaparesca en un tiempo x.
summon->ApplySpellImmune(0, IMMUNITY_SCHOOL, SPELL_SCHOOL_MASK_FROST, true); //aplicar una inmunidad a la magia de tipo frio.
summon->setFaction(14);//cambiarle la faccion.
summon->SetLevel(80);// cambiarle el nivel.
summon->SetFlag(UNIT_FIELD_FLAGS, UNIT_FLAG_DISABLE_MOVE);//agregarle una flag.
Talk(TEXTO);//Hablar.

-Finalmente con la funcion void JustReachedHome() reseteamos el npc:
*Cuando el npc llegue a su posicion inicial antes del combate.

 
 
        C++:
 
void JustReachedHome()
        {
            ScriptedAI::Reset();
        }

Llamara a la funcion void Reset():
 
 
        C++:
 
void Reset()
        {               
            me->setFaction(35);
            me->SetDisplayId(24949);
            me->SetObjectScale(1.0f);
            timerintro = 0;
            SetEquipmentSlots(false, 0);
        }

*Con ella devolveremos los valores iniciales del npc:
faccion, modelo visual, escala, arma equipada y vuelve a 0 la variable timerintro, asi el npc esta disponible nuevamente.

El Script deberia ir quedando asi:

 
 
        C++:
 
/*
* Copyright (C) 2008-2012 TrinityCore
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see .
*/
#include "ScriptMgr.h"
#include "ScriptPCH.h"
//NPC_TUTORIAL
class npc_tutorial : public CreatureScript
{
public:
    npc_tutorial() : CreatureScript("npc_tutorial") { }
    struct npc_tutorialAI : public ScriptedAI
    {
        npc_tutorialAI(Creature* creature) : ScriptedAI(creature)
        {   
            events.ScheduleEvent(EVENT_INTRO, 600);       
        }
        uint32 timerintro;
             
        enum Npc
        {
            NPC_SUMMON_DK = 31325,
            NPC_SUMMON_LK = 31754,       
        };
        enum Texts
        {
            SAY_INTRO                = 0,
            SAY_PHASE_DK            = 1,       
            SAY_SUMMON_DK            = 2,
            SAY_SUMMON_LK            = 3,       
            SAY_PHASE_LICH_KING        = 4,
            SAY_SLAY                = 5,
            SAY_DEATH                = 6,
        };
        enum Spells
        {           
            SPELL_PRESENCIA_DE_ESCARCHA        = 48266,
            //DK   
            SPELL_EXPLOSION_AULLANTE            = 61061,
            SPELL_GOLPE_DE_ESCARCHA                = 79895,
            SPELL_INVIERNO_SIN_REMORDIMIENTO    = 108200,                   
            //LICH_KING
            SPELL_SOUL_REAPER                = 69409,
            SPELL_PAIN_AND_SUFFERING        = 72133,
        };
        enum Events
        {
            EVENT_INTRO                            = 1,
            EVENT_SUMMON_DK                        = 2,
            EVENT_SUMMON_LK                        = 3,
            //DK
            EVENT_EXPLOSION_AULLANTE            = 4,
            EVENT_GOLPE_DE_ESCARCHA                = 5,
         
            //LICH_KING
            EVENT_INVIERNO_SIN_REMORDIMIENTO    = 6,
            EVENT_SOUL_REAPER                    = 7,
            EVENT_PAIN_AND_SUFFERING            = 8,
        };
         
        enum Phases
        {
            PHASE_INTRO            = 1,
            PHASE_DK            = 2,       
            PHASE_LICH_KING        = 3,       
        };
        void Reset()
        {               
            me->setFaction(35);
            me->SetDisplayId(24949);
            me->SetObjectScale(1.0f);
            timerintro = 0;
            SetEquipmentSlots(false, 0);
        }       
        void JustReachedHome()
        {
            ScriptedAI::Reset();
        }
     
        void EnterCombat(Unit* who)
        {
            events.SetPhase(PHASE_DK);
            events.ScheduleEvent(EVENT_SUMMON_DK, 30000, 0, PHASE_DK);
            events.ScheduleEvent(EVENT_EXPLOSION_AULLANTE, urand(10, 15) * IN_MILLISECONDS, 0, PHASE_DK);
            events.ScheduleEvent(EVENT_GOLPE_DE_ESCARCHA, 8000, 0, PHASE_DK);
        }
        void KilledUnit(Unit* victim)
        {
            Talk(SAY_SLAY);
        }
        void JustDied(Unit* victim)
        {
            Talk(SAY_DEATH);
        }       
     
        void JustSummoned(Creature* summon)
        {
            if (summon->GetEntry() == NPC_SUMMON_DK)
            {
                summon->CastSpell(summon, 48265, false);
                if (Unit * target = SelectTarget(SELECT_TARGET_RANDOM, 0))
                    summon->AI()->AttackStart(target);
            }
            if (summon->GetEntry() == NPC_SUMMON_LK)
            {
                summon->CastSpell(summon, 48265, false);
                if (Unit * target = SelectTarget(SELECT_TARGET_BOTTOMAGGRO, 0))
                    summon->AI()->AttackStart(target);
            }
        }       
        void UpdateAI(uint32 const diff)
        {
            std::list playerList;
            GetPlayerListInGrid(playerList, me, 30.0f);
            for (auto player : playerList)
            {
                events.Update(diff);
                while (uint32 eventId = events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                    case EVENT_INTRO:
                    {
                        timerintro++;
                        if (timerintro == 1)
                        {
                            Talk(SAY_INTRO);
                        }
                        if (timerintro == 11)
                        {
                            me->CastSpell(me, 127511, 0);
                        }
                        if (timerintro == 12)
                        {
                            me->SetDisplayId(22235);
                            me->SetObjectScale(2.0f);
                        }
                        if (timerintro == 14)
                        {
                            Talk(SAY_PHASE_DK);
                            me->setFaction(14);
                            me->CastSpell(me, SPELL_PRESENCIA_DE_ESCARCHA, 0);
                            SetEquipmentSlots(false, 33475);
                        }
                        if (timerintro == 18)
                        {
                            AttackStart(player);
                        }
                        events.ScheduleEvent(EVENT_INTRO, 1000);
                        break;
                    }
                    }
                }
            }
                if (!UpdateVictim())
                    return;
                events.Update(diff);
                if (me->HasUnitState(UNIT_STATE_CASTING))
                    return;
                if (events.IsInPhase(PHASE_DK) && HealthBelowPct(50))
                {
                    events.SetPhase(PHASE_LICH_KING);
                    Talk(SAY_PHASE_LICH_KING);
                    me->CastSpell(me, SPELL_INVIERNO_SIN_REMORDIMIENTO, 0);
                    me->SetDisplayId(30721);
                    events.ScheduleEvent(EVENT_SUMMON_LK, 30 * IN_MILLISECONDS, 0, PHASE_LICH_KING);
                    events.ScheduleEvent(EVENT_SOUL_REAPER, urand(15, 20) * IN_MILLISECONDS, 0, PHASE_LICH_KING);
                    events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 5000, 0, PHASE_LICH_KING);
                }
                while (uint32 eventId = events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                    case EVENT_SUMMON_DK:
                        Talk(SAY_SUMMON_DK);
                        me->SummonCreature(NPC_SUMMON_DK, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN);
                        events.ScheduleEvent(EVENT_SUMMON_DK, 30000, 0, PHASE_DK);
                        break;
                    case EVENT_EXPLOSION_AULLANTE:
                        if (Unit * target = SelectTarget(SELECT_TARGET_RANDOM, 0, 30.0f, false))
                            DoCast(target, SPELL_EXPLOSION_AULLANTE);
                        events.ScheduleEvent(EVENT_EXPLOSION_AULLANTE, 10000, 0, PHASE_DK);
                        break;
                    case EVENT_GOLPE_DE_ESCARCHA:
                        DoCastVictim(SPELL_GOLPE_DE_ESCARCHA);
                        events.ScheduleEvent(EVENT_GOLPE_DE_ESCARCHA, 8000, 0, PHASE_DK);
                        break;
                    case EVENT_SUMMON_LK:
                        Talk(SAY_SUMMON_LK);
                        me->SummonCreature(NPC_SUMMON_LK, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN);
                        events.ScheduleEvent(EVENT_SUMMON_LK, 30000, 0, PHASE_LICH_KING);
                        break;
                    case EVENT_SOUL_REAPER:
                        DoCastVictim(SPELL_SOUL_REAPER);
                        events.ScheduleEvent(EVENT_SOUL_REAPER, urand(15000, 20000), 0, PHASE_LICH_KING);
                        break;
                    case EVENT_PAIN_AND_SUFFERING:
                        DoCastToAllHostilePlayers(SPELL_PAIN_AND_SUFFERING);
                        events.ScheduleEvent(EVENT_PAIN_AND_SUFFERING, 5000, 0, PHASE_LICH_KING);
                        break;
                    default:
                        break;
                    }
                }   
                         
            DoMeleeAttackIfReady();
        }
    };
    CreatureAI* GetAI(Creature* creature) const
    {
        return new npc_tutorialAI(creature);
    }
};
void AddSC_tutorial()
{
    new npc_tutorial();
}

Ahora vamos a la parte de SQL:
Crear el NPC con el nombre del script en la columna `ScriptName`:

 
 
        SQL:
 
DELETE FROM `creature_template` WHERE entry=1000000;
INSERT INTO `creature_template`(`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `difficulty_entry_4`, `difficulty_entry_5`, `difficulty_entry_6`, `difficulty_entry_7`, `difficulty_entry_8`, `difficulty_entry_9`, `difficulty_entry_10`, `difficulty_entry_11`, `difficulty_entry_12`, `difficulty_entry_13`, `difficulty_entry_14`, `difficulty_entry_15`, `KillCredit1`, `KillCredit2`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `exp_unk`, `faction_A`, `faction_H`, `npcflag`, `npcflag2`, `speed_walk`, `speed_run`, `speed_fly`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `type_flags2`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `spell5`, `spell6`, `spell7`, `spell8`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `Health_mod`, `Mana_mod`, `Mana_mod_extra`, `Armor_mod`, `RacialLeader`, `questItem1`, `questItem2`, `questItem3`, `questItem4`, `questItem5`, `questItem6`, `movementId`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `WDBVerified`) VALUES
(1000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30721, 0, 0, 0, 'Tutorial', NULL, NULL, 0, 90, 90, 4, 0, 14, 14, 0, 0, 1, 1.14286, 1.14286, 1, 1, 1000, 2000, 0, 1000, 20, 2000, 2000, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 2000, 1000, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 100, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 'npc_tutorial', 1);

Textos del NPC:
 
 
        SQL:
 
DELETE FROM `creature_text` WHERE entry=1000000;
INSERT INTO `creature_text`(`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`) VALUES
(1000000, 0, 0, 'SAY_INTRO', 14, 0, 100, 1, 0, 12732, ''),
(1000000, 1, 0, 'SAY_PHASE_DK', 14, 0, 100, 15, 0, 14685, ''),
(1000000, 2, 0, 'SAY_SUMMON_DK', 14, 0, 100, 25, 0, 14693, ''),
(1000000, 3, 0, 'SAY_SUMMON_LK', 14, 0, 100, 25, 0, 17222, ''),
(1000000, 4, 0, 'SAY_PHASE_LICH_KING', 14, 0, 100, 0, 0, 17352, ''),
(1000000, 5, 0, 'SAY_SLAY', 14, 0, 100, 0, 0, 17214, ''),
(1000000, 6, 0, 'SAY_DEATH', 14, 0, 100, 0, 0, 17374, '');

Compilamos y que lo disfruten.
#3
Tutoriales / Tutorial de Script C++ World o...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM
Todos los créditos a mariodanny91 por su publicación original en WoWCreador

Tutorial de Script C++ World of Warcraft 1:

En esta guía, enseñaré una de las maneras de hacer un script C++ para el emulador JadeCore  que está basado en TrinityCore antiguo.  Les servirá de conocimiento base para otros emuladores más actualizados y motivarlos a investigar mas sobre el tema. Vale aclarar que todo lo planteado aquí es de manera autodidacta no soy programador, solo comparto lo que he aprendido.

Para esta guia deben tener instalado Visual Studio, Cmake y otras dependencias que exija el core ya sea OpenSSL,Boost,Mysql en sus versiones x86 o x64.


Punto sobre los cuales hablaré:
-Comenzare con el link del source  You are not allowed to view links. Register or Login

-Como agregar el script C++ al source.
-Estructura del Script.

-Casteo de magias.
-Textos.

-Invocación de Npc.


Como agregar el script C++ al source.
Creamos un archivo en blanco ya sea con bloc de notas o con notepad++, en la carpeta \JadeCore548-patched\src\server\scripts\Custom, con extension .cpp

Yo voy a crear tutorial.cpp.
En el archivo CMakeLists.txt agregamos el script, en caso de no tenerlo lo pueden crear, debe quedar asi:

 
 
      C++:
 
# Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
#
# This file is free software; as a special exception the author gives
# unlimited permission to copy and/or distribute it, with or without
# modifications, as long as this notice is preserved.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY, to the extent permitted by law; without even the
# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
set(scripts_STAT_SRCS
  ${scripts_STAT_SRCS}
  Custom/tutorial.cpp
)
message("  -> Prepared: Custom")


Pasamos el source por Cmake.


En Visual Studio buscamos en archivo ScriptLoader.cpp (\JadeCore548-patched\src\server\game\Scripting\ScriptLoader.cpp)
Se dede declarar en dos lugares:

 
 
      C++:
 
1:
// Customs
void AddSC_npc_tutorial();
2:
void AddCustomScripts()
{
#ifdef SCRIPTS
    AddSC_npc_tutorial();
#endif
}


Estructura del Script.
Esta es una plantilla de Script de la cual partiremos:

 
 
      C++:
 
/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptPCH.h"
enum Npc
{
};
enum Texts
{
};
enum Spells
{
};
enum Events
{
};
class npc_tutorial : public CreatureScript
{
    public:
        npc_tutorial() : CreatureScript("npc_tutorial") { }
        struct npc_tutorialAI : public ScriptedAI
        {
            npc_tutorialAI(Creature* creature) : ScriptedAI(creature)
            {
            }
            void Reset()
            {            
            }
         
            void EnterCombat(Unit* who)
            {
            }
         
            void KilledUnit(Unit * victim)
            {
            }
         
            void JustDied(Unit * victim)
            {
            }
            void UpdateAI(uint32 const diff)
            {
                if (!UpdateVictim())
                    return;
                 
                events.Update(diff);
                if (me->HasUnitState(UNIT_STATE_CASTING))
                    return;
                 
                while (uint32 eventId = events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                        default:
                            break;
                    }
                }
             
                DoMeleeAttackIfReady();
            }
        };
        CreatureAI* GetAI(Creature* creature) const
        {
            return new npc_tutorialAI(creature);
        }
};
void AddSC_tutorial()
{
    new npc_tutorial();
}


1-Enumerar los datos que vamos a utilizar:
(pueden utilizar la palabra que deseen (xxxxx) pero debe quedar asi)

 
 
      C++:
 
enum xxxxx
{
};


Para los npc:+
 
 
      C++:
 
enum Npc
{
    NPC_SUMMON = 32467,
};


Para los textos:
 
 
      C++:
 
enum Texts
{
    SAY_AGGRO       = 0,
    SAY_SUMMON      = 1,
    SAY_SLAY        = 2,
    SAY_DEATH       = 3,
};


Para las magias:
 
 
      C++:
 
enum Spells
{    
    SPELL_NUBE_ENFERMISA    = 28156,
    SPELL_DESGARRAR         = 59239,
    SPELL_RAJAR                = 40504,
    SPELL_TORBELLINO         = 24236,
};


Para los eventos:
 
 
      C++:
 
enum Events
{
    EVENT_DESGARRAR     = 1,
    EVENT_RAJAR         = 2,
    EVENT_TORBELLINO     = 3,
    EVENT_SUMMON         = 4,
};


2-Explicar cada funcion:

-Cuando la criatura se resetee es decir respanee.

 
 
      C++:
 
void Reset()
    {
 
    }


-Cuando la criatura entre en combate.

 
 
      C++:
 
void EnterCombat(Unit* who)
    {
     
    }


-Cuando la criatura mate, ya sea player o npc.
 
 
      C++:
 
void KilledUnit(Unit * victim)
    {
     
    }


-Cuando la criatura muera.
 
 
      C++:
 
void JustDied(Unit * victim)
    {
    }
   


3-Agregar los eventos con sus respectivos tiempos:
Al declararse en la funcion void EnterCombat empezara a contar el tiempo en el momento que empiece el combate.

 
 
      C++:
 
void EnterCombat(Unit* who)
    {
        Talk(SAY_AGGRO);
     
        me->CastSpell(me, SPELL_NUBE_ENFERMISA, true);
     
        events.ScheduleEvent(EVENT_DESGARRAR, 15000, 0);
        events.ScheduleEvent(EVENT_RAJAR, 5000, 0);
        events.ScheduleEvent(EVENT_TORBELLINO, 10000, 0);
        events.ScheduleEvent(EVENT_SUMMON, 20000, 0);
 
    }
   


4-Crear los eventos con sus respectivos spell, summon, textos, etc:
 
 
      C++:
 
void UpdateAI(uint32 const diff)
            {
                if (!UpdateVictim())
                    return;
                 
                events.Update(diff);
                if (me->HasUnitState(UNIT_STATE_CASTING))
                    return;
                 
                while (uint32 eventId = events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                        case EVENT_DESGARRAR:
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, false))
                            DoCast(target, (SPELL_DESGARRAR));
                        events.ScheduleEvent(EVENT_DESGARRAR, 15000, 0);
                            break;
                    case EVENT_RAJAR:
                        DoCastVictim(SPELL_RAJAR);
                        events.ScheduleEvent(EVENT_RAJAR, 5000, 0);
                            break;
                    case EVENT_TORBELLINO:
                        DoCast(me, SPELL_TORBELLINO);
                        events.ScheduleEvent(EVENT_TORBELLINO, 10000, 0);
                            break;
                    case EVENT_SUMMON:
                        me->SummonCreature(NPC_SUMMON, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN);
                        events.ScheduleEvent(EVENT_SUMMON, 20000, 0);
                            break;
                         
                        default:
                            break;
                    }
                }
             
                DoMeleeAttackIfReady();
            }
        };
       


 
 
      Codigo:
 
   SELECT_TARGET_RANDOM                     //Selecciona objetivo aleatorios.
    SELECT_TARGET_TOPAGGRO                   //Selecciona objetivo desde mayor a menos amenaza.
    SELECT_TARGET_BOTTOMAGGRO                 //Selecciona objetivo desde menor a mayor amenaza.
    SELECT_TARGET_NEAREST                     //Selecciona objetivo mas cerca.
    SELECT_TARGET_FARTHEST                     //Selecciona objetivo mas lejos.
    TEMPSUMMON_TIMED_OR_DEAD_DESPAWN                    // despawns despues de un tiempo especificado o cuando la criatura desaparesca.
    TEMPSUMMON_TIMED_OR_CORPSE_DESPAWN                  // despawns despues de un tiempo especificado o cuando la criatura muera.
    TEMPSUMMON_TIMED_DESPAWN                            // despawns despues de un tiempo especificado.
    TEMPSUMMON_TIMED_DESPAWN_OUT_OF_COMBAT              // despawns despues de un tiempo cuando la criatura salga de combate.
    TEMPSUMMON_CORPSE_DESPAWN                           // despawns instantaneamente despues de morir.
    TEMPSUMMON_CORPSE_TIMED_DESPAWN                     // despawns despues de un tiempo especificado cuando muere.
    TEMPSUMMON_DEAD_DESPAWN                             // despawns cuando la criatura desaparece.
    TEMPSUMMON_MANUAL_DESPAWN
   


El Script deberia ir quedando asi:

 
 
      C++:
 
/*
* Copyright (C) 2008-2012 TrinityCore <http://www.trinitycore.org/>
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
* Free Software Foundation; either version 2 of the License, or (at your
* option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "ScriptMgr.h"
#include "ScriptPCH.h"
enum Npc
{
    NPC_SUMMON = 32467,
};
enum Texts
{
    SAY_AGGRO        = 0,
    SAY_SUMMON        = 1,
    SAY_SLAY        = 2,
    SAY_DEATH        = 3,
};
enum Spells
{
    SPELL_NUBE_ENFERMISA    = 28156,
    SPELL_DESGARRAR            = 59239,
    SPELL_RAJAR                = 40504,
    SPELL_TORBELLINO        = 24236,
};
enum Events
{
    EVENT_DESGARRAR        = 1,
    EVENT_RAJAR            = 2,
    EVENT_TORBELLINO    = 3,
    EVENT_SUMMON        = 4,
};
class npc_tutorial : public CreatureScript
{
    public:
        npc_tutorial() : CreatureScript("npc_tutorial") { }
        struct npc_tutorialAI : public ScriptedAI
        {
            npc_tutorialAI(Creature* creature) : ScriptedAI(creature)
            {
            }
            void Reset()
            {
            }
         
            void EnterCombat(Unit* who)
            {
                Talk(SAY_AGGRO);
             
                me->CastSpell(me, SPELL_NUBE_ENFERMISA, true);
             
                events.ScheduleEvent(EVENT_DESGARRAR, 15000, 0);
                events.ScheduleEvent(EVENT_RAJAR, 5000, 0);
                events.ScheduleEvent(EVENT_TORBELLINO, 10000, 0);
                events.ScheduleEvent(EVENT_SUMMON, 20000, 0);        
            }
         
            void KilledUnit(Unit * victim)
            {            
                Talk(SAY_SLAY);            
            }
            void JustDied(Unit * victim)
            {
                Talk(SAY_DEATH);
            }
            void UpdateAI(uint32 const diff)
            {
                if (!UpdateVictim())
                    return;
                 
                events.Update(diff);
                if (me->HasUnitState(UNIT_STATE_CASTING))
                    return;
                 
                while (uint32 eventId = events.ExecuteEvent())
                {
                    switch (eventId)
                    {
                    case EVENT_DESGARRAR:
                        if (Unit* target = SelectTarget(SELECT_TARGET_RANDOM, 0, 20.0f, false))
                            DoCast(target, (SPELL_DESGARRAR));
                        events.ScheduleEvent(EVENT_DESGARRAR, 15000, 0);
                            break;
                    case EVENT_RAJAR:
                        DoCastVictim(SPELL_RAJAR);
                        events.ScheduleEvent(EVENT_RAJAR, 5000, 0);
                            break;
                    case EVENT_TORBELLINO:
                        DoCast(me, SPELL_TORBELLINO);
                        events.ScheduleEvent(EVENT_TORBELLINO, 10000, 0);
                            break;
                    case EVENT_SUMMON:
                        Talk(SAY_SUMMON);
                        me->SummonCreature(NPC_SUMMON, 0.0f, 0.0f, 0.0f, 0.0f, TEMPSUMMON_CORPSE_DESPAWN);
                        events.ScheduleEvent(EVENT_SUMMON, 20000, 0);
                            break;
                 
                        default:
                            break;
                    }
                }
             
                DoMeleeAttackIfReady();
            }
        };
        CreatureAI* GetAI(Creature* creature) const
        {
            return new npc_tutorialAI(creature);
        }
};
void AddSC_tutorial()
{
    new npc_tutorial();
}


Explico que hace el npc sencillo:


Cuando entre en combate dirá un texto, se casteara una magia y :
cada 15 segundos casteara desgarrar a un objetivo aleatorio que este en un rango de 20 metros.

cada 10 segundos casteara rajar al objetivo con mas amenaza.
cada 5 segundos casteara torbellino en el lugar.

cada 20 segundos invocara un NPC en su posicion y dirá un texto.


Cuando mate dirá un texto.


Cuando muera dirá un texto.


Ahora vamos a la parte de SQL:

Crear el NPC con el nombre del script en la columna `ScriptName`:
 
 
      SQL:
 
INSERT INTO `creature_template`(`entry`, `difficulty_entry_1`, `difficulty_entry_2`, `difficulty_entry_3`, `difficulty_entry_4`, `difficulty_entry_5`, `difficulty_entry_6`, `difficulty_entry_7`, `difficulty_entry_8`, `difficulty_entry_9`, `difficulty_entry_10`, `difficulty_entry_11`, `difficulty_entry_12`, `difficulty_entry_13`, `difficulty_entry_14`, `difficulty_entry_15`, `KillCredit1`, `KillCredit2`, `modelid1`, `modelid2`, `modelid3`, `modelid4`, `name`, `subname`, `IconName`, `gossip_menu_id`, `minlevel`, `maxlevel`, `exp`, `exp_unk`, `faction_A`, `faction_H`, `npcflag`, `npcflag2`, `speed_walk`, `speed_run`, `speed_fly`, `scale`, `rank`, `mindmg`, `maxdmg`, `dmgschool`, `attackpower`, `dmg_multiplier`, `baseattacktime`, `rangeattacktime`, `unit_class`, `unit_flags`, `unit_flags2`, `dynamicflags`, `family`, `trainer_type`, `trainer_spell`, `trainer_class`, `trainer_race`, `minrangedmg`, `maxrangedmg`, `rangedattackpower`, `type`, `type_flags`, `type_flags2`, `lootid`, `pickpocketloot`, `skinloot`, `resistance1`, `resistance2`, `resistance3`, `resistance4`, `resistance5`, `resistance6`, `spell1`, `spell2`, `spell3`, `spell4`, `spell5`, `spell6`, `spell7`, `spell8`, `PetSpellDataId`, `VehicleId`, `mingold`, `maxgold`, `AIName`, `MovementType`, `InhabitType`, `HoverHeight`, `Health_mod`, `Mana_mod`, `Mana_mod_extra`, `Armor_mod`, `RacialLeader`, `questItem1`, `questItem2`, `questItem3`, `questItem4`, `questItem5`, `questItem6`, `movementId`, `RegenHealth`, `equipment_id`, `mechanic_immune_mask`, `flags_extra`, `ScriptName`, `WDBVerified`) VALUES
(1000000, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 30721, 0, 0, 0, 'Tutorial', NULL, NULL, 0, 90, 90, 4, 0, 14, 14, 0, 0, 1, 1.14286, 1.14286, 1, 1, 1000, 2000, 0, 1000, 20, 2000, 2000, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1000, 2000, 1000, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '', 0, 3, 1, 100, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 'npc_tutorial', 1);


Textos del NPC:
 
 
      SQL:
 
INSERT INTO `creature_text`(`entry`, `groupid`, `id`, `text`, `type`, `language`, `probability`, `emote`, `duration`, `sound`, `comment`) VALUES
(1000000, 0, 0, 'SAY AGGRO', 14, 0, 100, 0, 0, 17223, ''),
(1000000, 1, 0, 'SAY_SUMMON', 14, 0, 100, 25, 0, 17222, ''),
(1000000, 2, 0, 'SAY_SLAY', 14, 0, 100, 21, 0, 17214, ''),
(1000000, 3, 0, 'SAY_DEATH', 14, 0, 100, 16, 0, 17374, '');


Compilamos y que lo disfruten.
#4
DB/SQL / Crear MiniMapa a nuestro Mapa ...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM
Todos los créditos a Reiner por su publicación original en WoWCreador
Buenas gente! Este es mi primer video tutorial y espero que puedan aprender. Este vídeo lo hago para aquellos que logran crear su mapa custom pero que aún no saben colocarle su minimapa correspondiente. Cualquier duda no duden en comentar :)


You are not allowed to view links. Register or Login

You are not allowed to view links. Register or Login
#5
Tutoriales / Cómo crear un Npc Teleport (Tr...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM

Todos los créditos a Nekro por su publicación original en WoWCreador


Este es un tutorial para crear tu propio npc teleport desde cero.

Paso 1: Crear nuestro Npc teleport en la base de datos "world" tabla "creature_template"

              Los datos obligatorios que debe ingresar son:                                                                                         

              gossip_menu_id =  60000 (Se recomienda usar un numero >= 60000)
              npcflag = 1

 
 
        SQL:
 
INSERT INTO creature_template (entry, modelid1, NAME, subname, gossip_menu_id, faction, npcflag, AIName) VALUES
(100000, 987, "Teleport", "Tutorial Npc Teleport", 60000, 35, 1, "SmartAI");

Referencia: You are not allowed to view links. Register or Login

Paso 2: Agregar opciones a nuestro Teleport Npc en la tabla "gossip_menu_option".

              Los datos que debe ingresar son:

              MenuID = 60000 (Id que usamos en gossip_menu_id al crear nuestro Npc)
              OptionID = 0 (este id irá aumentando + 1 si crea mas opciones para el menú)

              OptionText = Teleport Isla GM (Puede poner el nombre de la zona.)
              OptionType = 1 (obligatorio)

              OptionNpcFlag = 1 (obligatorio)
 
 
        SQL:
 
INSERT INTO gossip_menu_option (MenuID, OptionID, OptionText, OptionType, OptionNpcFlag) VALUES
(60000, 0, "Teleport Isla GM", 1, 1);

Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login



Referencia: You are not allowed to view links. Register or Login


Paso 3: Agregar coordenadas en la tabla "smart_scripts"

Entender esto a detalle es algo complejo si eres principiante, por eso te dejo este script para que puedas añadir tus coordenadas.

 
 
        SQL:
 
SET
@NpcEntry = 100000, /*ID de tu npc teleport*/
@id = 0, /*ID único agrear + 1 si añade otras coordenadas*/
@GossipMenuOption = 60000, /* "MenuID" sacado de gossip_menu_option*/
@GossipMenuID = 0, /*Id único "OptionID" sacado de gossip_menu_option, hace referencia a la opcion del teleport que creamos (Teleport Isla GM) */
@Map = 1, /* Id Mapa*/
@x = 16226.2, /* Coordenada x*/
@y = 16257, /* Coordenada y*/
@z = 13.2022, /* Coordenada z*/
@o = 1.65007, /*orientación*/
@Comentario = "IslaGM";
INSERT INTO `smart_scripts` (`entryorguid`, `source_type`, `id`, `event_type`, `event_param1`, `event_param2`, `action_type`, `action_param1`, `target_type`, `target_x`, `target_y`, `target_z`, `target_o`, `comment`) VALUES
(@NpcEntry,'0',@id,'62',@GossipMenuOption,@GossipMenuID,'62',@Map,'7',@x,@y,@z,@o,@Comentario);

Referencia: You are not allowed to view links. Register or Login


Paso Final: Reiniciar servidor

Con todo esto ya tenemos listo el Npc Teleport con una sola opcion (Isla Gm). Estudia bien los pasos y añade mas opciones para las zonas que quieras :)

Si tienes dudas o problemas no dudes en preguntar, tambien puedes unirte a nuestro Canal en Discord de Customizadores Wow.


You are not allowed to view links. Register or Login
#6
DB/SQL / Añade títulos a tu wow!
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM
Todos los créditos a keepalive por su publicación original en WoWCreador
BUENAS A TODOS WOWCREADOR!

Veamos como simplemente una edición de DBC que permite al usuario agregar títulos personalizados a su servidor.



En primer lugar, debe tener al menos un reempaquetado que requiera que obtenga sus propios archivos .dbc. Utilizo mis propios servidores compilados, por lo que no estoy seguro de si los repacks extraen .dbc o no.


De todos modos, ¡comencemos oficialmente!


Herramientas necesarias:


     MyDBCEditor


     Editor MPQ de Ladrik


Paso uno:

Esta es la parte fácil, abra su carpeta .dbc y busque un archivo llamado CharTitles.dbc. Hágase un favor y copie este .dbc y colóquelo en algún lugar en caso de que se equivoque y tenga que volver a intentarlo. O si simplemente desea "hacer una copia de seguridad" y reiniciar desde cero. Normalmente coloco el mío en mi escritorio.



Segundo paso:

¡Esto puede complicarse! Estoy bromeando, este es un tutorial fácil que no requiere mucho.

Vas a tomar CharTitles.dbc y arrastrarlo a tu MyDBCEditor.exe.



Paso tres:


¡Lo estamos haciendo bien hasta ahora! ¡Pero aquí está la parte divertida! Verás que debajo de ID 177 está el título de Wrathful Gladiator, ¿verdad? Correcto. Haz clic derecho en eso, ve a la opción que dice "copiar línea a ..." y escribe 178. Esto debería hacer una copia del título Wrathful Gladiator. ¿Guay, verdad? Bueno, necesitamos cambiar un par de cosas aquí ...


1º - Cambia Wrathful Gladiator% s por el título que quieras.


2nd -% s significa "cadena" o, en este caso, el nombre de un personaje. Así que "Gladiador colérico% s" sería "Gladiador colérico Valtorei". Coloque el% s donde lo necesite.


3º - Cambie el título en ambas ubicaciones, deje todo lo demás en paz.


Cuarto - Al final de la línea en la columna 37, debe haber un número "142". Por cada título que agregue, aumente esto en uno. En este caso, debes convertirlo en el número 143.


4º - ¡Guárdalo y ciérralo!




Paso quinto:


¡Buen trabajo! ¡Repare el archivo .dbc, asegúrese de que esté ubicado en su carpeta de datos, borre su caché y reinicie su servidor! (¡Asegúrese de que el .dbc actualizado también esté en su carpeta dbc!)
#7
Tutoriales / Bases de datos / Buscadores út...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM
Todos los créditos a AlKamel por su publicación original en WoWCreador
Hola a todos...

Algunas veces se hace necesario buscar datos o características del juego y los sitios más adecuados son los buscadores.

Acá les comparto los que más uso y que aún estan activos.

3.3.5 (WOTLK) en español

Wowhead (obvio): You are not allowed to view links. Register or Login
Ultimowow: You are not allowed to view links. Register or Login

Wowgaming: You are not allowed to view links. Register or Login
Evowow: You are not allowed to view links. Register or Login

Wotkl database: You are not allowed to view links. Register or Login


Cataclismo (en inglés)

Mmo4ever: You are not allowed to view links. Register or Login


Mists of Pandaria (en inglés)

mop-twinhead: You are not allowed to view links. Register or Login


Legion (en inglés)

Wowdb: You are not allowed to view links. Register or Login


Classic-Vanilla (en inglés)

ClasssicDB: You are not allowed to view links. Register or Login
Wow classic database: You are not allowed to view links. Register or Login      **Tiene opción adicional para TBC y WOTLK



Espero que les sea de utilidad... Y si conocen para otras expansiones, u otras buenas alternativas, no duden en compartirlos.
#8
Tutoriales / Crear un bot de Discord para r...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM

Todos los créditos a Elperro por su publicación original en WoWCreador


Introducción

DiscordWowRegister solo está disponible para Azerothcore/Trinitycore 3.3.5a. Se espera que en las próximas versiones soporte a todos los emuladores existentes.

Funciones


  • Registra cuentas para tu servidor a través de Discord.

  • Comando /register: Retorna un botón para registro de cuentas.

  • Comando /realmlist: Consulta el reamlist de tu servidor.

  • Comando /who: Consulta cuantos personajes están en línea.

  • Comando /topkill: Consulta los jugadores con mayor número de asesinatos.

Proximas funciones


  • Comando /top2v2: Consulta los mejores equipos de arena 2v2.

  • Comando /top3v3: Consulta los mejores equipos de arena 3v3.

  • Comando /top5v5: Consulta los mejores equipos de arena 5v5.

  • Comunicación por Soap para gestionar el servidor a través de Discord.

  • Registro para diferentes emuladores.

Requisitos


  • Obtener un Token.

  • You are not allowed to view links. Register or Login >= v16.14.0

Instalación

Pasos para crear un BOT:


  • Dirígete a You are not allowed to view links. Register or Login

  • Pulsa en "New Aplication".


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login



  • Ingresa el nombre y pulsa en "Create".


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login



  • Puedes cambiar el nombre, descripción y la foto de perfil.

  • Para terminar de crear el bot y obtener el Token que servirá para mas adelante pulsa en "Bot" y después en "Add Bot".


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login




  • Copia y guarda tu Token (servirá para mas adelante).


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login



Pasos para invitar al bot a tu servidor de Discord.


  • Presionar en "OAuth2" y luego en "URL Generator".

  • En SCOPES marcar "bot" y ''applications.commands" (muy importante marcar ambas opciones, ignore la imagen que solo marca una.)

  • En BOT PERMISSIONS marcar "Administrator".


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login




  • Copia el enlace que se genera en GENERATED URL y pega en tu navegador.


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login




  • Selecciona tu servidor y pulsa en "Continuar" seguido de "Autorizar".

  • Verifica que el bot haya ingresado a tu servidor.

Como instalar:


  • Instala You are not allowed to view links. Register or Login >= v16.14.0

  • Clona o descarga el codigo fuente del bot: You are not allowed to view links. Register or Login

  • Abrir el archivo config.json y configurar con tus datos.


 
 
        JSON:
 
"token": "Token que guardaste.",
"prefix": "!",
"clientId": "ID del bot en tu servidor.",
"guildId": "ID del servidor.",
"mysql": {
    "auth": {
        "host": "127.0.0.1",
        "user": "root",
        "password": "ascent",
        "database": "auth"
    },
    "characters": {
        "host": "127.0.0.1",
        "user": "root",
        "password": "ascent",
        "database": "characters"
    }
},
"realmlist": "logon.wowregister.com"

  • Para obtener clientId, guildId es necesario You are not allowed to view links. Register or Login en tu cuenta.


Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login




  • Instalar dependecias, abrir una consola en la carpeta principal y ejecutar el comando:


 
 
        Bash:
 
npm install

  • Una vez configurado e instalado las dependicias, correr el bot con el siguiente comando.


 
 
        Bash:
 
node index.js
El bot estará conectado y listo para crear cuentas.

Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login



Para crear una cuenta, cualquier usuario puede usar el comando /register y seguir los pasos.

Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login



Nota: Para recibir soporte únete a este canal de Discord: You are not allowed to view links. Register or Login
#9
DB/SQL / Acceder al modo Consola de WoW...
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM

Todos los créditos a AlKamel por su publicación original en WoWCreador


Una característica que no tan frecuentemente se usa es el modo consola del WoW.exe

Comparto unas instrucciones sencillas para poder extraer los archivos UI (Interfaz de usuario)

1. Crear un acceso directo al archivo wow.exe

2. Click derecho al acceso directo y seleccionar Propiedades
3. Editar el directorio "Destino" y agregar -console al final, después de WoW.exe (Aplicar y aceptar)

 ejemplo:
D:\Legion\Legion_SPP_V2Y2\Client\SPP_Wow-64.exe -console

Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login

4. Abrir el juego desde el acceso directo editado.

5. En la pantalla de autenticación o de selección de personaje oprimir la tecla con el caracter " ` "

    Se debe habilitar la consola, lista para escribir los comandos.
Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login


6. Escribir los siguientes comandos (uno a la vez).
exportInterfaceFiles code

exportInterfaceFiles art

7. Los archivos serán extraídos en la carpeta "Interface" del cliente, Hay que tener en cuenta que tardarán un buen tiempo en extraerse.


Nota: El caracter " ` " debe estar asignado a una tecla. No sirven ni código ASCII, copiar y pegar, ni combinaciones de teclas.

Orientación para Dummies: Una forma sencilla para poder utilizar el caracter " ` " es cambiando el idioma de teclado a inglés.

Los visitantes no pueden visualizar imágenes en los mensajes, por favor You are not allowed to view links. Register or Login o You are not allowed to view links. Register or Login

En el formato del teclado inglés, este caracter esta asignado por defecto a la tecla a la izquierda de "1", debajo de "Esc".
#10
Tutoriales / Crear Sistema V.I.P | Lua
Último mensaje por Nuzak - Abr 20, 2025, 02:29 PM
Todos los créditos a TrinityTools por su publicación original en WoWCreador
Hola gente!

Acá les comparto una nueva guía que estaré subiendo, sobre como crear un sistema vip para sus servidores.

El sistema vip en esta guía será creada usando puntos de Donación y Votación que el usuario podrá comprar en sus sitios webs de sus servidores.

Aquí les dejaré el enlace a mi video para que estén atentos a los próximos que estaré subiendo.