Stepping into C++ by Mager1794
Table of Contents
1. Introduction to C++ or Introduction to Suicide
2. Writing Gossip Scripts
3. Game Object AI...
4. Artificial Intelligence
5. Playing with Hooks... Is it dangerous?
6. C++ Command info
7. Credits
1. Introduction to C++ or Introduction to Suicide
In this guide im gonna help you learn C++. C++ is an easy language just
everyone needs there stepping stone into it. So here is where i come in
im teaching everything that i learned on my own to step into C++ and makin
it easier for you.
Follow this tutorial to make a project [Only registered and activated users can see links. ]
dont do the DLL compiling part just get your self a project file fully set up with the Setup.h and Setup.cpp
2. Writing Gossip Scripts
Now C++ Gossip Scripts is kinda like LUA Gossip scripts only im good at the C++
ones lol
well lets start with a basic Gossip Script a simple WarpNPC
Ok well every Gossip Script must begin like this
notice "class SCRIPT_DECL GlobalNPC : public" creates a new class if yourCode:#include "StdAfx.h" #include "Setup.h" #ifdef WIN32 #pragma warning(disable:4305) #endif class SCRIPT_DECL GlobalNPC : public GossipScript { public: void GossipHello(Object * pObject, Player* Plr, bool AutoSend); void GossipSelectOption(Object * pObject, Player* Plr, uint32 Id, uint32 IntId, const char * Code); void GossipEnd(Object * pObject, Player* Plr); void Destroy() { delete this; } };
using a C++ editor programm you can probably click a"-" button that hides it
every gossip script requires this code above but note the "GlobalNPC" thats the
name of it you can change that to what ever you wish as long as you change the
setup at the bottom which we will get to later
now lets add this to our script
now i know thats practically completely empty this si the part where we get toCode:void GlobalNPC::GossipHello(Object * pObject, Player* Plr, bool AutoSend) { GossipMenu *Menu; objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr); if(AutoSend) Menu->SendTo(Plr); }
add choices to our script lets make it look like this
Note how that looks think do you think you understand it good..im telling youCode:void GlobalNPC::GossipHello(Object * pObject, Player* Plr, bool AutoSend) { GossipMenu *Menu; objmgr.CreateGossipMenuForPlayer(&Menu, pObject->GetGUID(), 1, Plr); Menu->AddItem(5, "Shattrath", 1); if(AutoSend) Menu->SendTo(Plr); }
what it means anyway
Menu->AddItem([Put a random number between 1 and 10 this doesn't matter], "[Name of the Selection], [What case it activates when click])
Dont edit anything until we finish this section
ok lets make it look like thisCode:void GlobalNPC::GossipSelectOption(Object * pObject, Player* Plr, uint32 Id, uint32 IntId, const char * Code) { Creature * pCreature = (pObject->GetTypeId()==TYPEID_UNIT)?((Creature*)pObject):NULL; if(pCreature==NULL) return; GossipMenu * Menu; switch(IntId) { case 0: GossipHello(pObject, Plr, true); break; } }
the Plr is basically saying "Person who clicked it"Code:void GlobalNPC::GossipSelectOption(Object * pObject, Player* Plr, uint32 Id, uint32 IntId, const char * Code) { Creature * pCreature = (pObject->GetTypeId()==TYPEID_UNIT)?((Creature*)pObject):NULL; if(pCreature==NULL) return; GossipMenu * Menu; switch(IntId) { case 0: GossipHello(pObject, Plr, true); break; case 1: // Add some random comment after a // Plr-> break; } }
now Add this after it [no spaces] EventTeleport(mapid, x, y, z);
now change out the (mapid, x, y, z,); with what ever you wish
or to make it shattrath do this (530, -1887.510010, 5359.379883, -12.427300);
Great now were only learning so write now what i want you to do is go out and write your own script for a warp NPC
close the NPC Script off like this
look at "void SetupGlobalNPC(ScriptMgr * mgr)" you should have those setup files made for this to work if not in setup.cppCode:void GlobalNPC::GossipEnd(Object * pObject, Player* Plr) { GossipScript::GossipEnd(pObject, Plr); } void SetupGlobalNPC(ScriptMgr * mgr) { GossipScript * gs = (GossipScript*) new GlobalNPC(); mgr->register_gossip_script([NPCID], gs); }
make it like this
void SetupGlobalNPC(ScriptMgr * mgr)
and setup.h like this
SetupGlobalNPC(mgr)
that ends our gossip NPC scripts chapter remember theres so much more you can
do with gossip scripts just play around with it
3. Game Object AI...
Game Object AI isn't quite as long as Gossip Script and well truly not much
more advanced
im gonna give you a full gameobject script and i want you to study it and then
i will show you how to make them
now you see where pPlayer->SafeTeleport(1, 0, 4627.442383, -3831.523438, 943.386353, 1.220509); isCode:class TutorialPortal : public GameObjectAIScript { public: TutorialPortal(GameObject* goinstance) : GameObjectAIScript(goinstance) {} void OnActivate(Player * Plr) { Plr->SafeTeleport(1, 0, 4627.442383, -3831.523438, 943.386353, 1.220509); } static GameObjectAIScript *Create(GameObject * GO) { return new TutorialPortal(GO); } }; GameObjectAIScript * create_go[GOID](GameObject * GO) { return new TutorialPortal(GO); } void SetupPortalHandler(ScriptMgr * mgr) { mgr->register_gameobject_script([GOID], &TutorialPortal::Create); }
simply edit that to the (1, 0, 4627.442383, -3831.523438, 943.386353, 1.220509); to your custom portals
(map, zone, x, y, z, o)
now say you want to limit things to certain people like maybe make guild house compile
you can easily make if functions like this
[COLOR=DeepSkyBlue]after the "{"Code:if(Plr->GetGUID() == 1) {
simple start writing code like Plr->SafeTeleport
and stuff
lets look at the registering
its a gameobject script this time so its not gossip scripts like the last oneCode:void SetupPortalHandler(ScriptMgr * mgr) { mgr->register_gameobject_script([GOID], &TutorialPortal::Create); }
as long as you do the setups right and the base of the script right then the chances of errors will be highly slim
in setup.h add this under the one in there already
SetupGlobalNPC(mgr)
do the same with setup.cpp
void SetupGlobalNPC(ScriptMgr * mgr)
and whala your done with a gameobject script
4. Artificial Intelligence
This really isn't going to be much indepth but it will give you the right idea when your writing your AI Scripts
Heres a script i wrote for a server i used to have that went down
chances are you don't fully understand that, well that just means your in the same position i was in when i first started
lets set up a small little template for you to useCode:class MafiaProtectorAI : CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(MafiaProtectorAI); MafiaProtectorAI(Creature* pCreature) : CreatureAIScript(pCreature) { m_strike = m_fury = true; infostrike = dbcSpell.LookupEntry(STORMSTRIKE); infofury = dbcSpell.LookupEntry(WINDFURY); } void OnCombatStart(Unit* mTarget) { RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME)); _unit->CastSpell(mTarget, infofury, false); m_fury = false; int randAnnounce; randAnnounce=rand()%4; switch (randAnnounce) { case 0:///Edit this message _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Intruder!!!!!!!!!!!!!"); break; case 1://Edit this message _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "They're After the Jewels Stop them"); break; } } void OnCombatStop(Unit *mTarget) { _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); _unit->GetAIInterface()->SetAIState(STATE_IDLE); RemoveAIUpdateEvent(); } void OnDied(Unit * mKiller) { RemoveAIUpdateEvent(); } void AIUpdate() { uint32 val = RandomUInt(1000); SpellCast(val); } void SpellCast(uint32 val) { if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())//_unit->getAttackTarget()) { if(m_fury) { _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), infofury, false); m_fury = false; return; } if(m_strike) { _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), infostrike, false); m_strike = false; return; } if(val >= 100 && val <= 225) { _unit->setAttackTimer(2000, false); m_fury = true; } if(val >= 790 && val <= 900) { _unit->setAttackTimer(4000, false); m_strike = true; } } } protected: bool m_strike; bool m_fury; SpellEntry *infofury, *infostrike; };
thats our all magical template, now we need functions in it such as OnCombat etc.Code:class TemplateAI : CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(TemplateAI); TemplateAI(Creature* pCreature) : CreatureAIScript(pCreature) { } protected: };
in this script were gonna add
- OnCombatStart
- OnCombatStop
- OnDied
- AIUpdate
- SpellCast
those are our basics so enter this under
Enter thisCode:class TemplateAI : CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(TemplateAI); TemplateAI(Creature* pCreature) : CreatureAIScript(pCreature) { }
Code:void OnCombatStart(Unit* mTarget) { } void OnCombatStop(Unit *mTarget) { } void OnDied(Unit * mKiller) { } void AIUpdate() { } void SpellCast(uint32 val) { }
Now that we have that lets start scripting what to happen on combat start
now with me one thing i hate is anything thats practically garunteed and predictable i hate when there is a lack of options in anything so i like to randomize things and thats exactly what were gonna do for the Chat Messages on combatCode:void OnCombatStart(Unit* mTarget) { .... }
were gonna give a 1/4 chance for messages
2 of them will actually be messages while the other 2 will be nothing but silence
so its 1/2 chance to speak 1/4 chance to say a certain message, pretty unpredictable right?
how were gonna do this though is first we'll declare our integer
now we'll use the rand() function to randomize 1-4 and then use the switch function to let it decide the messagesCode:void OnCombatStart(Unit* mTarget) { int chatMessage; }
if you have yet to notice we are recreating the script from aboveCode:void OnCombatStart(Unit* mTarget) { int chatMessage; randAnnounce=rand()%4; switch (randAnnounce) { case 0:///Edit this message _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Intruder!!!!!!!!!!!!!"); break; case 1://Edit this message _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "They're After the Jewels Stop them"); break; }
but the most important part of the OnCombatStart function is this is
where we Register our AI Update Event
so make the code look like this
notice we registered it to the units BaseAttackTime, basically stating that our AIUpdateEvent is our attackCode:void OnCombatStart(Unit* mTarget) { RegisterAIUpdateEvent(_unit->GetUInt32Value(UNIT_FIELD_BASEATTACKTIME)); int randAnnounce; randAnnounce=rand()%4; switch (randAnnounce) { case 0:///Edit this message _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "Intruder!!!!!!!!!!!!!"); break; case 1://Edit this message _unit->SendChatMessage(CHAT_MSG_MONSTER_YELL, LANG_UNIVERSAL, "They're After the Jewels Stop them"); break; case 2://Edit this Message break; case 3://Edit this message break; } }
now that we have that registered most importantly we need to set when it stops
Which is
OnCombatStop
OnDied
so those will be the next functions to script
make the code look like thatCode:void OnCombatStop(Unit *mTarget) { _unit->GetAIInterface()->setCurrentAgent(AGENT_NULL); _unit->GetAIInterface()->SetAIState(STATE_IDLE); RemoveAIUpdateEvent(); } void OnDied(Unit * mKiller) { RemoveAIUpdateEvent(); }
to explain this is pretty much it removes the AIUpdateEvent
and then it sets it to where no AIAgents are on it and its in an
Idle state, rather than attacking
Now in AIUpdate were gonna do some spell casting so lets set up the SpellCast function now
okay first lets go to the top of our file and defineCode:void SpellCast(uint32 val) { ... }
our attacks
okay now down toCode:[COLOR=DeepSkyBlue] //Protector #define CN_PROTECTOR 100020//Character Entry ID #define WINDFURY 25584 #define STORMSTRIKE 32175
and make it look like thisCode:class MafiaProtectorAI : CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(MafiaProtectorAI); MafiaProtectorAI(Creature* pCreature) : CreatureAIScript(pCreature) { }
and also down to the bottom under where it saysCode:class MafiaProtectorAI : CreatureAIScript { public: ADD_CREATURE_FACTORY_FUNCTION(MafiaProtectorAI); MafiaProtectorAI(Creature* pCreature) : CreatureAIScript(pCreature) { m_strike = m_fury = true; infostrike = dbcSpell.LookupEntry(STORMSTRIKE); infofury = dbcSpell.LookupEntry(WINDFURY); }
"protected:"
enter this
basically what we just did is define everything that we will be using in thisCode:bool m_strike; bool m_fury; SpellEntry *infofury, *infostrike;
script now lets move to the actual SpellCast function
lets start by checking if its not casting a spell at that moment and make sure it has a target selectedCode:void SpellCast(uint32 val) { ... }
Code:if(_unit->GetCurrentSpell() == NULL && _unit->GetAIInterface()->GetNextTarget())//_unit->getAttackTarget()) {
thats good now next were gonna use some boolean checks to make it check if its supposed to cast the spells or not like this
Code:if(m_fury) { _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), infofury, false); m_fury = false; } if(m_strike) { _unit->CastSpell(_unit->GetAIInterface()->GetNextTarget(), infostrike, false); m_strike = false; }
when it says
"if(m_fury)"
its basically saying
"if(m_fury == true)"
now as you can see it cast the spell then sets the booleans as false, it does that to make sure it doesn't cast a spell way more than it should
now we need to set its ability to turn the booleans true
now whats it does is check if the uint32 val is in between certain numbers and if it is then it sets the attack time to a certain time, then setting the boolean to true allowing the spell to be used againCode:if(val >= 100 && val <= 225) { _unit->setAttackTimer(2000, false); m_fury = true; } if(val >= 790 && val <= 900) { _unit->setAttackTimer(4000, false); m_strike = true; }
now to actually define the value we do this in AIUpdate
what it does is each time it performs an AIUpdate it randomizes a number between 1-1000 and then uses that number for the val in SpellCastCode:void AIUpdate() { uint32 val = RandomUInt(1000); SpellCast(val); }
last but not least add this to the very bottom of the full script under the very last "}"
well thats the AI Part of this guideCode:void SetupMyInstance(ScriptMgr * mgr) { mgr->register_creature_script(CN_PROTECTOR, &MafiaProtectorAI::Create); }
please note this isn't exactly the most professional way to perform spell casting, and i know that but this is a really simple way to teach beginners
how to program this
5. Playing with Hooks... Is it dangerous?
ok well server hooks are where most people get all there cool stuff like insta 70 and gold on startup and more so
im gonna give you a server hook script taht i wrote and give you every server hook there is for you to look at
[in the C++ Commands chapter]
ok lets begin
now that name trully has no effect whatso ever other than thats what i wil register it asCode:void OnLoginForFirstTime(Player* plr) {
what really matters is the server hook it gets registered as lets continue make it like this
high chance you understand that except maybe the %s. what the %s does is uses that function i added to the endCode:void OnLoginForFirstTime(Player* plr) { plr->BroadcastMessage(" Welcome to [Server name] %s", plr->GetName() }
of function and gets the players name its fairly simple
now lets do the setup
in setup.h add this under the one in there alreadyCode:void SetupFirstLogon(ScriptMgr * mgr) { mgr->register_hook(SERVER_HOOK_EVENT_ON_FIRST_ENTER_WORLD, (void*)OnLoginForFirstTime); }
SetupFirstLogon(mgr)
do the same with setup.cpp
void SetupFirstLogon(ScriptMgr * mgr)
and whala your done with a gameobject script
6. C++ Command info
SERVER HOOKS:
SERVER_HOOK_EVENT_ON_NEW_CHARACTER
SERVER_HOOK_EVENT_ON_KILL_PLAYER
SERVER_HOOK_EVENT_ON_FIRST_ENTER_WORLD
SERVER_HOOK_EVENT_ON_ENTER_WORLD
SERVER_HOOK_EVENT_ON_GUILD_JOIN
SERVER_HOOK_EVENT_ON_DEATH
SERVER_HOOK_EVENT_ON_REPOP
SERVER_HOOK_EVENT_ON_EMOTE
SERVER_HOOK_EVENT_ON_ENTER_COMBAT
SERVER_HOOK_EVENT_ON_CAST_SPELL
SERVER_HOOK_EVENT_ON_TICK
SERVER_HOOK_EVENT_ON_LOGOUT_REQUEST
SERVER_HOOK_EVENT_ON_LOGOUT
SERVER_HOOK_EVENT_ON_QUEST_ACCEPT
SERVER_HOOK_EVENT_ON_ZONE
SERVER_HOOK_EVENT_ON_CHAT
SERVER_HOOK_EVENT_ON_LOOT
SERVER_HOOK_EVENT_ON_GUILD_CREATE
SERVER_HOOK_EVENT_ON_ENTER_WORLD_2
SERVER_HOOK_EVENT_ON_CHARACTER_CREATE
SERVER_HOOK_EVENT_ON_QUEST_CANCELLED
SERVER_HOOK_EVENT_ON_QUEST_FINISHED
SERVER_HOOK_EVENT_ON_HONORABLE_KILL
SERVER_HOOK_EVENT_ON_ARENA_FINISH
SERVER_HOOK_EVENT_ON_OBJECTLOOT
SERVER_HOOK_EVENT_ON_AREATRIGGER
SERVER_HOOK_EVENT_ON_POST_LEVELUP
SERVER_HOOK_EVENT_ON_PRE_DIE - general unit die, not only based on players
SERVER_HOOK_EVENT_ON_ADVANCE_SKILLLINE
You get the C++ info by user Plr->
most the time it brings up a box and lets you choose a command comes in handy alot
7. Final Tips
Get the SVN for Sun++ and AspireDev and study there scripts all have great quality and use alot of functions
Guide is Fully Written by me - Mager1794



LinkBack URL
About LinkBacks


Reply With Quote




Bookmarks