[3.0]Gameobject Events

[3.1] Most Common Gameobject Commands Usage & Events.
You can't do too much with Gameobjects, some people may argue with me but at least on my lua engine, Gameobjects are relatively limited to teleporting.

To make a simple teleport portal. All do you is use the player:teleport command in the registered event.

[NOTE]: Most of these examples are going to be copied and pasted from my server, sorry if some of the coords are messed up

Code:
function Gameobject_OnUse(Unit, Event, player)
    player:Teleport(mapid, x, y, z)
end
 
RegisterGameObjectEvent(GOID, 4, "Gameobject_OnUse")
Now, thats not that interesting. However you can add in a few more things, If the player is in combat, you can make the portal un-usable to them;

Code:
function Gameobject_OnUse(Unit, Event, player)
    if (player:IsInCombat() == true) then
        player:SendAreaTriggerMessage("You are in combat!")
    else
        player:Teleport(mapid, x, y , z)
    end
end
 
RegisterGameObjectEvent(GOID, 4, "Gameobject_OnUse")
Some other things you can do, Is for instance, to avoid people camping where people get ported in in gurubashi, you can write the script with math.random command (I'll add that command in the command list above :X) Ex.

Code:
function GurubashiPortal_OnUse(Unit, Event, player)
local Choice=math.random(1, 5) -- Chooses a random number between 1 and 5, That value is stored as the local variable 'choice' 
    if (player:IsInCombat() == true) then
        player:SendBroadcastMessage("You are in combat!")
    else
        if (Choice == 1) then    -- Depending on what number came out of the math.random command, Choice's value can be equal to any of the below values in the if statements. Teleporting a player randomly to 1 of 5 spots in gurubashi arena.
            player:Teleport(0, -13217, 184, 100)
        elseif (Choice == 2) then
            player:Teleport(0, -13269, 212, 100)
        elseif (Choice == 3) then
            player:Teleport(0, -13294.5, 279, 100)
        elseif (Choice == 4) then
            player:Teleport(0, -13171, 337, 100)
        elseif (Choice == 5) then
            player:Teleport(0, -13148, 226, 100)
        end
    end
end
 
RegisterGameObjectEvent(98815, 4, "GurubashiPortal_OnUse")


[Note]: SQL Below if you're interested. Arcemu structure
Code:
INSERT INTO `gameobject_names` VALUES ('98815', '22', '7849', 'Armory Portal to Gurubashi', '', '', '', '', '', '', '9438', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0', '0');
Something i've done is made certain portals only interactable with GM's / donars. And no i didn't find out a way to check if a player is a GM.

Assuming you don't have over nine thousand Game masters (maybe donars), this shouldn't be too much of a hassle.

Code:
 
function PortalToThinkBox_OnUse(Unit, Event, player)
local Name = player:GetName()
 
    if (Name == nil) then
        player:SendAreaTriggerMessage("You cannot enter through here!")
    elseif (Name == "GM name one") then
        player:Teleport(1, 16227.4, 16403.8, -64)
    elseif (Name == "GM name two") then
        player:Teleport(1, 16227.4, 16403.8, -64)
    elseif (Name == "GM name three") then
        player:Teleport(1, 16227.4, 16403.8, -64)
    elseif (Name == "GM name four") then
        player:Teleport(1, 16227.4, 16403.8, -64)
    elseif (Name == "GM name five") then
        player:Teleport(1, 16227.4, 16403.8, -64)
    else
        player:SendBroadcastMessage("You are not a Game Master.")
        player:Teleport(mapid, x, y, z) -- Mall Location is what i use.
    end
end
 
-- Or of course, you can set GM/Donar names as variables..
 
RegisterGameObjectEvent(98814, 4, "PortalToThinkBox_OnUse")


Remember in the example above, The names must be in string form... (Wrapped in quotations) otherwise it will think GMnamefour is a variable with a nil value!

[3.3] Gameobject Summary and Tips

Gameobjects can not register events. But they can still play a good role in a bossfight, and a big part in your server if you aren't a fan of pocket teleporters (People teleport in combat / bleh) Traditional ports are the way to go IMO =).

/facepalm at this pathetic section =)


[5.0] Generalized Gossip Events


Gossip commands and usage are generally all the same for Gameobjects, NPC's and items.

A gossip script has 2 events that need to be registered. (OnGossip, and OnSelectOption / OnSubMenu)

Code:
RegisterUnitGossipEvent(NPCID, 1, "OnGossip")
RegisterUnitGossipEvent(NPCID, 2, "OnSubMenu")
RegisterGOGossipEvent(GOID, 2, "OnSubMenu")
RegisterGoGossipEvent(GOID, 1, "OnGossip")
RegisterItemGossipEvent(ITEMID, 1, "Item_OnClick")
RegisterItemGossipEvent(ITEMID, 2, "OnSubMenu")
The basics of a Lua Gossip script are as follows:

Code:
function Npc_OnGossip(Unit, Event, player)
 
end
 
function Npc_OnSubMenu(Unit, Event, player, id, intid, code)
 
end
 
[Note]intid, code, will all be explained later
"player" is the player who clicked the npc.
Not sure what id is for
The Gossip commands and usage all go inside, they are as follows;


Code:
function Npc_OnGossip(Unit, Event, player)
    Unit:GossipCreateMenu(100, player, 0)
    Unit:GossipMenuAddItem(0, "Name", 1, 50)
    Unit:GossipSendMenu(player)
end
Those are the three basic commands to create the actual gossip interface. What they do is;

Code:
function Npc_OnGossip(Unit, Event, player)
    Unit:GossipCreateMenu(textid, player, 0) 
end
 
textid: Insert the entryid of the text you want to be displayed before your options: Ex. "Hey there, $N. How can I help you?". You can find the correct entryid in `npc_text` table.
 
player: Who you are creating this menu for.
 
0: No clue. i just know when its set to anything other than 0, the npc generally doesn't respond with any action.
 


Code:
function Npc_OnGossip(Unit, Event, player)
    Unit:GossipMenuAddItem(symbolid, "Name of Option", intid, codeflag)
end
 
symbolid: Sets the ID of the symbol beside the Option Name.
Name of Option: Sets the name of the Option
intid: This is what intid will be set to if this option is selected.
codeflag: Flags triggering this option to open a input box. (1 and 3 are the flags that work.)
[Note]: please remember intid is a variable.


Code:
function Npc_OnGossip(Unit, Event, player)
    Unit:GossipSendMenu(player)
end
 
player: who you are sending the menu too.


Ok, now that you understand what the commands are, lets get started creating an actual gossip script. I will make 3 examples. One of them will be a teleporter, Another one a guessing game.

Teleporter
Code:
function Creature_OnGossip(Unit, Event, player)
    Unit:GossipCreateMenu(100, player, 0) -- Sends a menu to the player with the npc_text entryid of 100.
    Unit:GossipMenuAddItem(0, "Outlands Locations", 1, 0) -- SETS intid to 1!!! And registers Creature_OnSubMenu(If its easier to remember, "OnSelectOption", same thing)
    Unit:GossipSendMenu(player) -- Sends menu to the player.
end
 
function Creature_OnSubMenu(Unit, Event, player, id, intid, code)
 
    if (intid == 1) then    -- This is what will happen if you click outlands locations
        Unit:GossipCreateMenu(100, player, 0)
        Unit:GossipMenuAddItem(0, "Hellfire Penninsula", 2, 0)
        Unit:GossipSendMenu(player)
    end
 
    if (intid == 2) then -- When you click on Hellfire Penninsula you get teleported since intID gets set to 2.
        player:Teleport(530, x, y, z) -- usage = (mapid, x, y, z) full list of player commands with usage will be posted later.
    end
end
 
RegisterUnitGossipEvent(NPCID, 1, "Creature_OnGossip")
RegisterUnitGossipEvent(NPCID, 2, "Creature_OnSubMenu")

NOTE: "Unit:GossipMenuAddItem(0, player, 0, 0)", Just becuase it is in an OnGossip function. (id, intid, code) still apply to their fields. For this reason, 0 sets intid to 0.


Whats happening in the script above, is when you click Outlands Locations, intid gets set to 1, At the point in time you've selected an option, which registers ("Creature_OnSubMenu"), If it doesn't make sense, think of Creature_OnSubMenu as Creature_OnSelectOption. So then that function gets registered. and your send a new menu with outland locations. Upon clicking hellfire penninsula, you clicked an option, which registers Creature_OnSubMenu yet again, and changing intid to 2, Executing the code withing the corresponding If statement.

Now below, i will make a Number guessing gossip script hopefully explaining what almost no Lua Tutorials contain... (Unit, Event, id, intid, code)


Code:
function Creature_OnGossip(Unit, Event, player)
    Unit:GossipCreateMenu(100, player, 0)
    Unit:GossipMenuAddItem(0, "Guess a number between 1 and 10!", 0, 3) -- 3 Flags this menu item to open an input box where a player can enter data (Like you do when redeeming a wow trading card game code for a rocket mount on retail ect ect)
    Unit:GossipSendMenu(player)
end
 
function Creature_OnSubMenu(Unit, Event, player, id, intid, code)
    if (intid == 0) then
        if (code == "5") then -- code is a variable returned as whatever the player entered in the input box. Remember it is returned as a string (in word form) so whatever is it equal to must be in quotations. Having [if (code == 1) then] it will always return false and execute whats inside the 'else', this being due to anything the player types in the box will return as "<what player typed>".
            player:AddItem(29434, 1) -- Adds an item to the player who clicked.  player:AddItem(itemid, quantity)
        else
            player:SendAreaTriggerMessage("You Guessed wrong.") -- inserts a message into the players chat box in yellow.
        end
    end
end
 
RegisterUnitGossipEvent(NPCID, 1, "Creature_OnGossip")
RegisterUnitGossipEvent(NPCID, 2, "Creature_OnSubMenu")
 
"5" Is that value that IF what the player entered in the box is equal to, the statement will add an item to the player.


There wasn't much to explain, so i just threw in what there was to know in comments.

Its been a while since I've updated this, but i thought I'd add this small tip in for gossip scripts;

When creating a gossip scripts, It gets annoying always having to close and re-open the gossip after you've selected a certain option. For example, Say one of your gossip scripts is to give players food, The player does not want to have to re-open the gossip menu everytime he wants to get a new stack of food! So to keep the same menu active after an option has been selected, check out the example below.

Code:
function Unit_OnGossip(Unit, Event, player)
    Unit:GossipCreateMenu(100, player, 0)
    Unit:GossipMenuAddItem(0, "Item Selection", 1, 0)
    Unit:GossipSendMenu(player)
end
 
function Unit_OnSelect(Unit, Event, player, id, intid, code)
if (intid == 1) then
    Unit:GossipCreateMenu(101, player, 0)
    Unit:GossipMenuAddItem(0, "Add Food!", 2, 0)
    Unit:GossipMenuAddItem(0, "Add Water!", 3, 0)
    Unit:GossipSendMenu(player)
end
 
if (intid == 2) then
    player:AddItem(FoodItemID, amount)
    intid = 1
    Unit:GossipSendMenu(player)
end
 
if (intid == 3) then
     player:AddItem(WaterItemID, amount)
    intid = 1
    Unit:GossipSendMenu(player)
end
 
 
end


What this does is adds an item to the players inventory, then sets intid to 1, and sends the menu associated to 1 to the player again. Keep in mind the menu being sent must be the one the player was currently on, otherwise it won't work(There is logic behind this but its late and i forget :S). To have properly working back buttons, i believe you still have to make a replica of the menu you want it to go back to.

Item Gossip

Theres not much difference between regular gossip events, and ones you'd use with an item.

Code:
function Item_OnClick(Item, Event, player)
    Item:GossipCreateMenu(100, player, 0)
    Item:GossipMenuAddItem(0, "hello lets telepert", 0, 0)
    Item:GossipMenuAddItem(0, "hello want an item?", 2, 0)
    Item:GossipSendMenu(player)
end
 
function OnSubMenu(Item, Event, player, id, intid, code)
    if (intid == 0) then
        player:Teleports(mapid, x, y, z)
    end
 
    if (intid == 1) then
        player:AddItem(itemid, 1)
    end
end
 
RegisterItemGossipEvent(ITEMID, 1, "Item_OnClick")
RegisterItemGossipEvent(ITEMID, 2, "OnSelect")
Above, is an example of an item gossip script. You script the exact same as you would with a Npcs gossip. There is almost no difference.


Below is a list of player commands usefull when creating gossip scripts.
Code:
player:AddItem(itemid, quantity) -- Adds item to the players inventory
player:Teleport(mapid, xcoord, ycoord, zcoord)    -- Teleports the player to the selected coordinates.
player:SendAreaTriggerMessage("Message") -- Enters a message in the players chat box.
player:SendBroadcastMessage("Message") -- Enters a message across the players screen, where error messsages are shown
player:GossipSendPOI(player, Xcoord, Ycoord, icon, flags, data, nameofPOI); -- Flags a coordinate on your main map, and mini map, as a Point of Interest, with the assigned name, icon and coordinates. Leave data as 0. (I almost never use this command, so im not the best person to be explaining it)
Aside from those, i don't believe you use many More.

[$.#]3x7r4 1Nf0rNm471on

String Concatenation

Had to add this in here right now. Concatenation is just joining two strings together. Say if you wanted your boss to cast a spell on a certain person, and call out their name. You'd use string Concatenation.

Heres an example of having a boss call out a players name.

Code:
function Creature_OnCombat(Unit, Event)
    Unit:RegisterEvent("Creature_CastSpell", 30000, 0)
end
 
function Creature_CastSpell(Unit, Event)
local name = Unit:GetRandomPlayer(7)
    Unit:FullCastSpellOnTarget(
    Unit:SendChatMessage(14, 0, "Enjoy sum frostbewltz"..name) -- "Enjoy sum frostbewltz" is the first part of the string, and 'name' is the variable your joining together.
end                                               -- The two dots are what is joining them together.
 
RegisterUnitEvent(NPCID, 1, "Creature_OnCombat")
 
Creature yells: Enjoy sum frostbewltz VisionOneThousand


two periods and two alone, are what you use to join two strings together when you want to do something like above. Or when your debugging a stupid script that won't work, and you can't figure out why a certain value even though set, will never be equal to another value.

Code:
local number = 5
 
function Creature_OnCombat(Unit, Event)
    Unit:RegisterEvent("Creature_OnCastSpell", 1000, 1)
end
 
function Creature_OnCastSpell(Unit, Event)
local plr = Unit:GetRandomPlayer(0) -- Gets a random player
local name = plr:GetName()
    Unit:CastSpellOnTarget(11, name)    -- Using CastSpellOnTarget, it was bugged at one point and would ALWAYS cast the spell on itself.
    Unit:SendChatMessage(14, 0, "name is equal to"..name.."Is that who the spell was cast on?") -- If the spell casts on himself, the command is bugged, if it casts on 'name' (Whoever was said ingame) then it works.
end
 
RegisterUnitEvent(NPCID, 1, "Creature_OnCombat")
Debugging.

When making a Lua script for your first time. You are going to get a LOT of errors. Most errors are caught by the lua Engine on startup. But some get printed on the console while your script is running ingame (If your trying to add 1 to a variable with a nil value).
Heres a screenshot of what the errors can look like on startup.


[NOTE]: No i don't use a repack, i just still use the Ac-web folder from when i used to =P
It will tell you what line the error is on, which is usually enough to go find whats wrong, but it also tells you whats wrong. even though sometimes it feels like its always saying the same thing.

Heres a list(that i can remember) of debugging errors i've ran into;

Code:
Forgetting a Left Parethisis to close a Function/Command.
Unit:SendChatMessage(41, 0, "The Lava Around Sarthiron Begins to Churn"
 
Forgetting a comma inside the Parameters of a Command.
Unit:SendChatMessage(41, 0 "The Lava Around Sarthiron Begins to Churn")
 
Concatenating a string with a nil value.
function Creature_OnCombat(Unit, Event)
    local name        -- Nil value, forgot to put player:GetName()
    Unit:SendChatMessage(14, 0, "how come you be agroing me "..name)
end
 
Adding an integer with a nil value.
function Creature_OnCombat(Unit, Event)
    count = count + 1 -- When the creature enters combat, count was never previously given a value, so it is nil, and it is being added to 1. To fix this you'd write 'local count = 0' at the top of the script.
end
 
Adding an integer to a string.
function Npc_OnGossip(Unit, Event, player)
    Unit:GossipCreateMenu(100, player, 0)
    Unit:GossipMenuAddItem(1, "Guessing Game", 0, 3)
    Unit:GossipSendMenu(player)
end
 
function Npc_OnSubMenu(Unit, Event, player, id, intid, code)
    codeplusone = code + 1 -- Code (Whatever the player wrote in the text box) will always return as a string, trying to add it to 1 will give you an error.
    if (code == codeplusone) then
        player:AddItem(29434, 20)
    end
end
 
Forgetting or adding an extra 'end' to a function / if statement.
function Creature_OnCombat(Unit, Event)
    if (Unit = nil) then
        print"awmah gawd this creature doesn't exist and its attacking me!"
    elseif
        if (Unit ~= nil) then
            print"phew this creature exists"
            -- Should be an End here.
    end
end
 
Using lowercase letters.
function Creature_OnCOmbat(Unit, Event)
    unit:SendChatMessage(14, 0, "Why is this not working?") -- Lowercase unit at the start of the command.
end
 


As you can see most of these errors are from spelling mistakes (Where the Lua Engine also tells you what line the error is on), However when a certain phase isn't registering and you can't figure out why or where to look. Use of the print command can come in handy, To give you an idea of where to look.

The usage of the print command is as follors

Code:
print"insert debug message here"
 
print("Insert Message here")
Below is how it could be used when you're having a problem with your script

Code:
local count = 0
 
function Creature_OnCombat(Unit, Event)
    Unit:RegisterEvent("Creature_PhaseOne", 1000, 1)
end
 
function Creature_PhaseOne(Unit, Event)
    count = count + 1
    if (count == 1) then
        Unit:SendChatMessage(14, 0, "Im gonna cast a spell on you.")
    elseif (count == 4) then
        Unit:SendChatMessage(14, 0, "Im gonna send a chat message!")
    elseif (count == 5) then
        Unit:SendChatMessage(14, 0, "Watchout this script is about to break")
    end
 
    if Unit:GetHealthPct <= 80 then
        -- register a new event.
    else
        Unit:RegisterEvent("Creature_PhaseOne", 1000, 1)
        print("count is equal to"..count) -- This will print in the console every second what count is equal to. And then you can figure out why it isn't looping like you want it to.
                          -- The reason is, count was never reset back to 0 when it was equal to 5. so you would've found count would'v continuously went up.
    end
end


If you find you're events are accelerating faster and faster casting a spell inside a function until the server crashes check the interval count on the end of when you register an event; I've done once.

Code:
function Creature_OnCombat(Unit, Event)
local name = player:GetName()
    Unit:SendChatMessage(14, 0, "Why are you agroing me"..name)
    Unit:RegisterEvent("Creature_CastSpell", 1000, 0) -- Put it as infinite, which registered the event when the event was registered.
end
 
function Creature_CastSpell(Unit, Event)
    Unit:CastSpell(insertIDhere)
 
    if Unit:GetHealthPct() <= 80 then
        -- register new event
    else
        Unit:RegisterEvent("Creature_CastSpell", 1000, 1) -- You can guess where this led too
    end
end


If you get an error about Unknown symbol near 'insert line of code here' Just rewrite that line, not really sure what causes it.

================================================== ==================

That brings us to the end of this tutorial, Hopefully you've learned something or had any questions you had answered. And remember, Sometimes just doing the boring work of 15 extra If statements / functions is worth having a move fun boss fight for.

Hopefully you can use what you've learned to be innovative and creative in your scripts.

This tutorial is finished, but i will still be adding things to it. PM me if you are curious how to do certain things or use certain commands. I will PM you back and then add an example and Explanation to this guide! Its win win.