Hello & Welcome to our community. Is this your first visit? Register
Follow us on
Follow us on Facebook Follow us on Twitter Watch us on YouTube


MMOCoin

Likes Likes:  0
Results 1 to 5 of 5
  1. #1
    Banned

    Join Date
    Jan 2010
    Location
    Baltimore,Maryland
    Posts
    260
    Post Thanks / Like
    Rep Power
    0
    Reputation
    87

    (Share)[Lua] The Ultimate Tutorial: For beginners and advanced users alike.


    Register to remove this ad

    The Ultimate Lua Tutorial


    Introduction.
    Hello everyone, and welcome to my Ultimate Lua Tutorial. This tutorial is aimed at those of you that wish to learn Lua but cannot seem to find a way to do it easily and reliably. Make no mistakes, however, this tutorial will also cover some advanced features of the programming language.

    WARNING. THIS THREAD SPANS 5 POSTS. IF YOU DO NOT LIKE WALL OF TEXTS, PLEASE FIND ANOTHER TUTORIAL. TO BE EXACT, THIS TUTORIAL CONTAINS 40223 CHARACTERS.

    Introduction to Lua.
    Presumably you have come to learn about Lua, and as such you already have a keen understanding of what Lua is capable of. If you're able to script Lua, you are probably going to able to apply for high-ranked jobs in Private Servers, notably Developer spots, as Lua is a very powerful, lightweight language. With the addition of certain Lua Engines (Notably, LuaHypArc, created by 'hypersniper' of WoW-V.com), Lua can almost do as much as C++, and it's much, much easier to understand and write.

    Pros and Cons of learning Lua.
    Whilst things have their upside, everything has a downside.

    Pros

    • Lightweight.
    • Powerful.
    • Simple.
    • Supported by all ArcEmu servers by default.
    • It's power is limitless.

    "It's power is limitless" - Well, yes it is. Before you smart-asses decide to say "No it's not, <insert reason about C here>", allow me to point out that Lua's coding is based on C. So, as long as you code it in C beforehand, you can do it in Lua.

    Cons
    • Limits you only to ArcEmu servers (Unless Mangos and Trinitycore decide to support Lua, god forbid.)
    • Although I said it is limitless, you are limited by what has been coded.
    • It has a C base, so you're better off learning C in the end.

    Lua makes for a great first programming language, as it's simple heirachy (Structure) allows for easy construction of complex scripts. The reason I learnt Lua instead of jumping the gun for C++ is that it is easier to learn Lua and then C++ due to the fact that... well, let's consider Lua as pre-school books. It introduces you to the basics of programming and computer interpretation. It's not great, but at the same time, it's a good supplement for HTML.

    The Basics.
    This Topic is the lowest level you can get inside this forum topic. This topic consists of:
    • Low-level functions
    • Arguments
    • Gossip NPCs
    • If statements
    • Else & Elseif
    • Commenting
    • Variables

    This tutorial assumes you are looking for ArcEmu placements, and therefore we will be focusing on the ArcEmu way of scripting. In this tutorial, I will teach you how to make a Gossip NPC. Before I start, I believe you should have these things before setting off to learn Lua:

    • A repack/custom compiled core that supports LuaHypArc.
    • Notepad++.
    • Some good music (I'm not talking about Miley Cyrus here. I mean AFI, All That Remains, Three Days Grace; etc).
    • The ArcEmu command list loaded up as a reference.

    If you do not have any of these, do not worry! It is not necessary to learn Lua, but it sure will make it a heck of a lot easier. You can find Notepad++ and the ArcEmu command list by pressing the links below.

    ArcEmu Default Lua Command List.
    Notepad++ Installer

    Don't be alarmed! Both of these items are open source and free (As in "Free Speech" and "Free Beer"), which means you cannot be sued (At least, by the creators) for downloading them.

    Setting out into the wilderness.
    The first thing I always add to my script is a block comment. This allows me to place, at the top of the script (So it is easily readable) what was on my mind when I was creating the script, what I want it to be able to do, and what needs to be done to fix it.

    Comments are lines of the code that are not read by the Lua Engine. It completely and utterly ignores them. There are two types of comments; a single line comment, and a block comment.

    Single Line comments
    A single line comment does what it says on the tin; it blocks out the rest of the line (from where you used the comment identifier). Anything after the so-called comment identifier is completely ignored by the Lua Engine, and subsequently, ArcEmu-World. A single line comment is indentified by two hyphens placed right next to each other. An example can be seen below.

    Code:
    Stuff() -- This is a comment!
    What this does, is that it ensures that anything after the -- is ignored by the Lua Engine. Anything placed after it is considered white space by the handler. This is a great method for ensuring that your thoughts are placed on paper.. er, virtual paper, so that you remember them later. It's all very well creating the best script known to man (Good luck with that ^^), but it's useless if you cannot remember what it does.
    But what if this comment spans more than one line? Surely, it'd be messy to do this;



    Code:
    -- This
    	-- Needs
    	-- To 
    	-- Be
    	-- Neater
    	-- ...!
    So what in the world do we do? Well..

    Block comments
    A block comment is a comment that spans multiple lines until you add the closing symbol. Anything between the opening and closing identifiers are completely ignored. This is great for introductory paragraphs at the top of a script or generally indicating a gap in date/time of thought.

    A block comment looks like this:


    Code:
    --[[
    This is a block comment
    It can span multiple lines! 
    :D
    ]]
    You may see some scripts use this:

    Code:
    --]]
    Instead of

    Code:
    ]]

    Please note that this is purely aesthetical and has no effect whatsoever on the code.

    Anywho, knowing how to comment things is great!... right? Well, yes, but you may as well just make a text file with no symbols in it if you're just going to make a text filled lua file. So, we move onto the actual beef of the script.

    Functions.

    Functions are the bit (In ArcEmu) that make the script work. It's like petrol to a car. It's the meat of your script. OK, enough analogies. A function is started with the keyword function and ended with the keyword end. After the word 'function', there is a space and there you can put your function name, followed by a pair of parenthesis - (). The parenthesis are known as arguments. They basically decide which bit of the data has been passed onto us from ArcEmu-World. Here is a sample function;


    Code:
    function FunctionName(Unit, Event)
    	-- This is a function!
    end
    Note that the keyword 'function' is case-sensitive. Using a capital 'f' (or any other letter, for that matter) will make the compiler not recognise that it is, indeed, a function. Same goes for Function Names, Arguments and.. er, pretty much everything, really.

    So, what are these bracketty things..? Well, as mentioned before, they are arguments. In pretty much every function you use as a Lua Scripter, you will have stuff inside these parenthesis. There are different arguements for different events. Here are the most common:


    Code:
    GeneralCreatureEvent(Unit, Event[, pMisc])
    GossipOnTalkEvent(Unit, Event, player)
    GossipOnSelectEvent(Unit, Event, player, id, intid, code, pMisc)

    Code:
    function HelloWorld()
    	print("Hello, World!")
    	print("This is my first Lua Script!")
    end
    
    HelloWorld()
    Wait, what did I just do there? Well, first of all, I created the function HelloWorld with no arguments. Note that I still added a pair of parenthesis. This is mandatory for every function you create. The first line, function HelloWorld() does nothing more than tell the Lua Engine that we are beginning a new function, which we have designated to be called 'HelloWorld', and that it has no arguments.

    The print statement is followed by an opening bracket, and then quotation marks (Unless you want to print a variable). Inside these quotation marks, you type whatever you want to be printed.

    If you save this code as HelloWorld.lua and place it inside your /scripts/ folder, and then open up ArcEmu-World, it will print this to the console:


    Code:
    Hello, World!
    This is my first Lua Script!
    Kinda boring huh? Oh yeah, and it gets better. It'll loop itself over and over and o-.. You get the idea. It's not helpful, so we'll move onto something a bit more.. productive.

    Your first Gossip Script.

    Whoa, gossip?


    Code:
    WTF is Gossip!?
    Well, you know in WoW, when you talk to an NPC it gives you options? Such as, 'Yes, I'm ready', etcetera? Well, that is gossip. And that is what we are going to create now. First of all, you need to create an NPC... go on, I'll wait.

    Done? OK, set it's flags to 1. This is the 'Gossip' flag, and enables the NPC to use Gossip. Oh, you don't know how to do that? Just hop on over to
    WoW-V and create an account, and then select the 'Create' option, and then the 'Mob/NPC' option. Follow the instructions, hit the 'Advanced' section and enable gossip. Then import it into your server and, at the ArcEmu-World console, type in 'reload creature_names' and 'reload creature_proto'.

    Now, create a new file and at the top of it, write this:


    Code:
    --[[
    	My First Gossip Script!
    	Tutorial by Neglected
    ]]
    
    -- Variables
    local NPC_ID = YourEntryID
    
    -- On Triggers
    
    -- RegisterUnitEvents
    Replace 'YourEntryID' with the entry ID you used when you created your NPC. Note that the only bit the Lua Engine will pay attention to, at the moment, is the local NPC_ID = YourEntryID bit. Everything else is just comments!

    But wait.. what is this local NPC_ID bit anyway? Well, that brings us onto our new section. A section within a section.. handy, huh?



    › See More: (Share)[Lua] The Ultimate Tutorial: For beginners and advanced users alike.

  2. #2
    Banned

    Join Date
    Jan 2010
    Location
    Baltimore,Maryland
    Posts
    260
    Post Thanks / Like
    Rep Power
    0
    Reputation
    87
    Variables.

    A variable is a byte of data, represented by a name, that stores a defined piece of data. Unlike C++, there are no variable types in Lua. Also, there is no need to worry about unsigned/signed variables.

    A variable is created by typing a string into the script. This string can be almost anything; however, it cannot be keywords or function names (You'll know if it is a keyword if you're using Notepad++, as it'll be highlighted a bold blue).

    Furthermore, variables can only be alphanumeric and have underscores and/or hyphens in them. You can use these characters:

    Code:
    a b c d e f g h i j k l m n o p q r s t u v w x y z 
    	A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
    	1 2 3 4 5 6 7 8 9 0
    	_
    Note that variables are case sensitive. MY_VAR is not the same as my_var or My_VaR.

    Variables can be declared with no identifier (Global) or with local infront of them. A global variable can pass from script to script, so it can cause problems. It's best to use local variables, which stay inside the current script, to reduce interference.

    Good Variable Names:


    Code:
    My_Var = 1
    	myVar = 2
    Invalid Variable Names:

    Code:
    %MyVar = 1 -- PHP Users may be used to this.
    	My.Var = 2
    	My&Var = 3
    It's always a good idea to name your variables after what they are being used for.

    Code:
    local Var983
    Is not as easy to know what it does as this is:

    Code:
     
    local Npc_Id
    Anyhow, back to your first Gossip NPC!

    Back to your First Gossip NPC.


    Code:
    --[[
    	My First Gossip Script!
    	Tutorial by Neglected
    ]]
    
    -- Variables
    local NPC_ID = 133713
    
    -- On Triggers
    
    -- RegisterUnitEvents
    So, this is the code we have so far. We know what the local NPC_ID line does now, so we can start coding.
    First off, let's create a new function called 'exampleGossipOnTalk(Unit, Event, player)'. These arguments are the standard ones for the OnTalk gossip event. The OnTalk gossip event is the first menu/dialog you see when you talk to the NPC.


    Code:
    --[[
    My First Gossip Script!
    Tutorial by Neglected
    ]]
    
    -- Variables
    local NPC_ID = YourEntryID
    
    -- On Triggers
    function exampleGossipOnTalk(Unit, Event, player)
    end
    
    -- RegisterUnitEvents

    Note that I added an end below the function. We need to end every function that is created, or the Lua Engine will chuck up errors. Now that we have created our function, let's add a RegisterUnitEvent. Usually, if you are created a boss, you will use RegisterUnitEvent(), but since we are making a Gossip NPC, we use RegisterUnitGossipEvent. Note that this is case-sensitive. Add this underneath the appropriate section;

    Code:
    RegisterUnitGossipEvent(NPC_ID, 1, "exampleGossipOnTalk")
    RegisterUnitGossipEvent() has four arguments; ID, Event ID, and Function Name. The Function Name section is in quotation marks; Don't forget that. You can use Variables for the ID and Event ID, which is why I added the NPC_ID variable in place of the ID field.

    Code:
    RegisterUnitGossipEvent(ID, EVENT_ID, FUNCTION_NAME)
    Right now, this script will register an empty function whenever you talk to the NPC. It's something, but it's useless. It's just a placeholder, in many respects. So let's start fleshing it out.


    Code:
    function exampleGossipOnTalk(Unit, Event, player)
    end
    As we saw earlier, the statements go between the function header and terminator (Posh words for function and end), like so.

    Code:
    function exampleGossipOnTalk(Unit, Event, player)
    	-- Statements go here
    end
    To start creating a Gossip Menu, Lua needs to know we are creating the menu; we create a shell using the :GossipCreateMenu() statement.

    Code:
     
    :GossipCreateMenu(TEXT_ID, player, INTID)
    Note that the :GossipCreateMenu() statement has a colon before it; this means it requires a Unit. By Default, the Unit is 'Unit'. This doesn't need to change unless we are dealing with multiple NPCs in one script; We'll come onto that later. Let's add our statement to the function.

    Code:
    function exampleGossipOnTalk(Unit, Event, player)
    	Unit:GossipCreateMenu(100, player, 0)
    end
    You'll see that I used '100' for the text ID. This is the default, "Hi, <name>. How can I help you?". It can be changed by looking in the appropriate table inside your Database. I set the Intid at '0' because that is what all first menus are set at; 0. It makes logical sense, too.

    So now we've created a menu that displays 'Hi, <name>. How can I help you?'. It's still pretty impractical and won't help anyone in any shape, or form (Unless they want a pick-me-up). To make this NPC useful, let's add a few options to our menu by using the :GossipMenuAddItem() statement.



    Code:
    :GossipMenuAddItem(ICON_ID, MENU_CONTENT, INTID[, CODE])
    This statement may confuse you; INTID? CODE? ICON_ID? What the heck are these? Well, the ICON_IDs are the bit you see next to the text when you open the menu. There are a few different icons, the IDs are listed below;

    Code:
    0 = Chat bubble
    	1 = Bag
    	2 = Wings
    	3 = Book
    	4 = Cog/Gear
    	5 = Cog/Gear
    	6 = Bag with coin
    	7 = Chat bubble with "..."
    When you are writing in the MENU_CONTENT, you can actually colour it. You use it by putting |cf######, where the #s are your hexidecimal colour (Web Color Chart - Hexadecimal - by VisiBone for more info), at the start of your string, and adding |r at the end.

    Code:
    :GossipMenuAddItem(0, "|cfFFFFFF White! |r", 1, 0)

    INTID? Well, when you use the OnSelect function later, the INTID is used to determine which menu was opened. Therefore, you have to use unique IntIDs for each Menu selection, or the script will not work. Also, the IntID is in numerical form and not string.

    CODE is an optional... option.. that can be omitted. It is only used when you want to load up a codebox. This will not be explained in this tutorial, and you will have to experiment to get it completely correct. Needless to say, leave it at 0 (False) unless you want it to load up, then set it to 1 (True).

    I'll add a few options to our Gossip Menu..



    Code:
     
    function exampleGossipOnTalk(Unit, Event, player)
    Unit:GossipCreateMenu(100, player, 0)
    Unit:GossipMenuAddItem(0, "Teleport me to the mall.", 1, 0)
    Unit:GossipMenuAddItem(0, "Remove Resurrection Sickness.", 2, 0)
    Unit:GossipMenuAddItem(0, "Never mind.", 3, 0)
    end
    This adds three options to our menu; a mall teleport option, a remove resurrection sickness option, and an option to close the menu. However, this won't work. We've created the menu, but as far as ArcEmu is concerned, we haven't sent it to the player yet. For this, we add the :GossipSendMenu() command. This one has one argument; the target. The Target is the person we are sending the menu to; this is the reason we have the 'player' argument in this function. We are sending the menu to the player, so we add this to our code:

    Code:
    Unit:GossipSendMenu(player)
    Which makes our function this:

    Code:
    function exampleGossipOnTalk(Unit, Event, player)
    	Unit:GossipCreateMenu(100, player, 0)
    	Unit:GossipMenuAddItem(0, "Teleport me to the mall.", 1, 0)
    	Unit:GossipMenuAddItem(0, "Remove Resurrection Sickness.", 2, 0)
    	Unit:GossipMenuAddItem(0, "Never mind.", 3, 0)
    	Unit:GossipSendMenu(player)
    end
    Let's add this to the rest of our code, leaving us with this:

    Code:
    --[[
    	My First Gossip Script!
    	Tutorial by Neglected
    ]]
    
    -- Variables
    local NPC_ID = 133713
    
    -- On Triggers
    function exampleGossipOnTalk(Unit, Event, player)
    	Unit:GossipCreateMenu(100, player, 0)
    	Unit:GossipMenuAddItem(0, "Teleport me to the mall.", 1, 0)
    	Unit:GossipMenuAddItem(0, "Remove Resurrection Sickness.", 2, 0)
    	Unit:GossipMenuAddItem(0, "Never mind.", 3, 0)
    	Unit:GossipSendMenu(player)
    end
    
    -- RegisterUnitEvents
    RegisterUnitGossipEvent(NPC_ID, 1, "exampleGossipOnTalk")
    We're getting there! However, this just shows the menu. The options won't work, you'll be able to see them; but if you click them, nothing will happen. You see, ArcEmu (sadly) doesn't 'detect' your functions for you. You need to tell it what to do. And we do this with our second function; the OnSelect function.

    Code:
    exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    This means nothing to you at the moment, right? Fair enough. Let's create another function underneath our first one.

    Code:
    --[[
    	My First Gossip Script!
    	Tutorial by Neglected
    ]]
    
    -- Variables
    local NPC_ID = 133713
    
    -- On Triggers
    function exampleGossipOnTalk(Unit, Event, player)
    	Unit:GossipCreateMenu(100, player, 0)
    	Unit:GossipMenuAddItem(0, "Teleport me to the mall.", 1, 0)
    	Unit:GossipMenuAddItem(0, "Remove Resurrection Sickness.", 2, 0)
    	Unit:GossipMenuAddItem(0, "Never mind.", 3, 0)
    	Unit:GossipSendMenu(player)
    end
    
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    end
    
    -- RegisterUnitEvents
    RegisterUnitGossipEvent(NPC_ID, 1, "exampleGossipOnTalk")
    And add the RegisterUnitGossipEvent hook underneath the OnTalk one.

    Code:
    --[[
    	My First Gossip Script!
    	Tutorial by Neglected
    ]]
    
    -- Variables
    local NPC_ID = 133713
    
    -- On Triggers
    function exampleGossipOnTalk(Unit, Event, player)
    	Unit:GossipCreateMenu(100, player, 0)
    	Unit:GossipMenuAddItem(0, "Teleport me to the mall.", 1, 0)
    	Unit:GossipMenuAddItem(0, "Remove Resurrection Sickness.", 2, 0)
    	Unit:GossipMenuAddItem(0, "Never mind.", 3, 0)
    	Unit:GossipSendMenu(player)
    end
    
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    end
    
    -- RegisterUnitEvents
    RegisterUnitGossipEvent(NPC_ID, 1, "exampleGossipOnTalk")
    RegisterUnitGossipEvent(NPC_ID, 2, "exampleGossipOnSelect
    OK, so our new function has some unknown arguments; id, code, and pMisc. Well, I'll tell you what each one does.
    ID; Not a clue. :3
    code; This is used if you enabled code in the Previous menu.
    pMisc; this is the name of the person who started the Gossip (?).

    None of these are much use to you, because you probably won't use them. At least, not in this tutorial. So, let's add the first option (of the 3) to our new function.



    Code:
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    	if (intid == 1) then
    		player:Teleport(MapID, x, y, z)
    		player:GossipComplete()
    	end
    end
    Wait, what? player:Teleport()? player:GossipComplete()? This makes no sense right? And what's with this 'if' thing-a-majig?!

    BRAIN FREEEZE!



    Err.. OK then, panic moment over. Let's work through this.. deep breaths.. in.. out..

  3. #3
    Banned

    Join Date
    Jan 2010
    Location
    Baltimore,Maryland
    Posts
    260
    Post Thanks / Like
    Rep Power
    0
    Reputation
    87
    Code:
     
    if (intid == 1) then
    Well, this is your new best friend, the 'if' statement. It is used to check if a certain condition is met. The thing within the brackets is the bit we are checking. I'm sure 'intid' shall come as a.. annoying, reminder to you. Remember when we added options, and we had to define a unique number? That was an intid. So, if the intid that the player selected is equal to 1 ('Teleport me to the mall.'), then we run this part of the script. Get it?

    Code:
    player:Teleport(MapID, x, y, z)
    This is a statement, similar to the Gossip Ones a few lines up. The :Teleport() statement does what it says on the box. It teleports the Unit in question to the specified MapID, x co-ordinate, y co-ordinate and z co-ordinate. These can be found by going to the designated place you want your mall to be in, and typing '.gps' in game. For sake of example, I shall use the Undeveloped half of Ahn'Qiraj. The Co-ords for this is as follows;

    Code:
    MapID: 1 
    	X: -9101.980469 
    	Y: 1612.902832 
    	Z: 21
    So our statement will read

    Code:
    player:Teleport(1, -9101.980469, 1612.902832, 21)
    So now we know what this does, we'll move onto the next statement; player:GossipComplete(). This one is quite simple and it doesn't need a whole paragraph to explain it. It simply closes the gossip menu. Easy. Right?

    Code:
    end

    Wait, we have two ends? Yes, we do, well done, you can count. The 'if' statement requires an end, since it is a loop, and Lua cannot determine when it has ended on it's own.

    Let's see what our function looks like now;



    Code:
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    	if (intid == 1) then
    		player:Teleport(1, -9101.980469, 1612.902832, 21)
    		player:GossipComplete()
    	end
    end
    So, we understand what this all does? Good. Let's move onto the other intid; Remove Resurrection Sickness.

    Code:
     
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    if (intid == 1) then
    player:Teleport(1, -9101.980469, 1612.902832, 21)
    player:GossipComplete()
    end
    if (intid == 2) then
    end
    end
    As you can see, we've created another if loop. This time, it only works if the intid is 2. So, in this function we want to remove the Resurrection Sickness aura ID. Well.. we don't know that, so it's time to hit our all-time friend, wowhead.com. We search in the spell we want, cut off the 5-digit number at the end of the URL and.. we have the ID: 15007. It's all good and well having the ID, but if we don't know the function to remove it, we're stuck. So let's hit the ArcEmu Wiki, using the link I provided above. We're looking for one that will check if the player has the aura, and then if he does, remove it.. hmm.. :HasAura() and :RemoveAura() look like they'll do the job. Let's try them out.


    Code:
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    	if (intid == 1) then
    		player:Teleport(1, -9101.980469, 1612.902832, 21)
    		player:GossipComplete()
    	end
    	if (intid == 2) then
    		if (player:HasAura(15007) == true) then
    			player:SendBroadcastMessage("Resurrection Sickness has been removed. Be careful next time!")
    			player:RemoveAura(15007)
    			player:GossipComplete()
    		else
    			player:SendBroadcastMessage("You do not have Resurrection Sickness!")
    			player:GossipComplete()
    		end
    	end
    end
    Eh what? :SendBroadcastMessage()? else? But you said we only needed :HasAura() and :RemoveAura()! And you haven't even explained what the arguments for them are either!

    Well, I thought it would be self explanatory, but there we go. OK, I'll guide you through it.



    Code:
    :HasAura(SpellID)
    :RemoveAura(SpellID)
    OK, so they are easy.

    Code:
    :SendBroadcastMessage("message")
    This one sends a message (Like the ones you see when you get an addon error, in the chat box) to the Unit specified.


    Code:
    else
    Aha. This is part of the 'if' loop. The else operator is used to make Lua do things if the conditions are not met. It's basically saying this:

    Code:
    If the value of intid is 2, and the player has the aura '15007', then do this. If he doesn't have that aura, then do this.
    Of course, you still need the end for the 'if' and 'function'.

    So, now we have two intids, lets look at our function now, and add the last one.


    Code:
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    	if (intid == 1) then
    		player:Teleport(1, -9101.980469, 1612.902832, 21)
    		player:GossipComplete()
    	end
    	if (intid == 2) then
    		if (player:HasAura(15007) == true) then
    			player:SendBroadcastMessage("Resurrection Sickness has been removed. Be careful next time!")
    			player:RemoveAura(15007)
    			player:GossipComplete()
    		else
    			player:SendBroadcastMessage("You do not have Resurrection Sickness!")
    			player:GossipComplete()
    		end
    	end
    	if (intid == 3) then
    		player:GossipComplete()
    	end
    end
    We just add a player:GossipComplete() because the option was to close the window, effectively.

    The complete script:


    Code:
    --[[
    	My First Gossip Script!
    	Tutorial by Neglected
    ]]
    
    -- Variables
    local NPC_ID = 133713
    
    -- On Triggers
    function exampleGossipOnTalk(Unit, Event, player)
    	Unit:GossipCreateMenu(100, player, 0)
    	Unit:GossipMenuAddItem(0, "Teleport me to the mall.", 1, 0)
    	Unit:GossipMenuAddItem(0, "Remove Resurrection Sickness.", 2, 0)
    	Unit:GossipMenuAddItem(0, "Never mind.", 3, 0)
    	Unit:GossipSendMenu(player)
    end
    
    function exampleGossipOnSelect(Unit, Event, player, id, intid, code, pMisc)
    	if (intid == 1) then
    		player:Teleport(1, -9101.980469, 1612.902832, 21)
    		player:GossipComplete()
    	end
    	if (intid == 2) then
    		if (player:HasAura(15007) == true) then
    			player:SendBroadcastMessage("Resurrection Sickness has been removed. Be careful next time!")
    			player:RemoveAura(15007)
    			player:GossipComplete()
    		else
    			player:SendBroadcastMessage("You do not have Resurrection Sickness!")
    			player:GossipComplete()
    		end
    	end
    	if (intid == 3) then
    		player:GossipComplete()
    	end
    end
    
    -- RegisterUnitEvents
    RegisterUnitGossipEvent(NPC_ID, 1, "exampleGossipOnTalk")
    RegisterUnitGossipEvent(NPC_ID, 2, "exampleGossipOnSelect")

    Well done! You've created your first ever functioning script. Or at least, using this tutorial. Save it as TeleporterNPC.lua and place it in your /scripts/ folder. Spawn your mob and restart your server (Or type in #reload if you are using Alvanaar's Reload Chat Command script), and enjoy talking to your first script!

    Ifs and Elseifs.

    So you know how to use ifs and elses.. but, using the following is quite hard to read and monotonous;



    Code:
     
     
    if (var == true) then
    Weee()
    end
    if (var == false) then
    Awww()
    end
    if (var == nil) then
    WTFITSHOULDNTBENIL()
    end
    Instead, you can replace this with an elseif, depending on the situation. An elseif basically removes the subsequent ifs and ends so that they are easy to read and are inside one if loop. Sound confusing? Here's a visual example.


    Code:
    if (var == true) then
    	Wee()
    elseif (var == false) then
    	Awww()
    elseif (var == nil) then
    	WTFITSHOULDNTBENIL()
    end
    As you can see, this is much easier to read than the previous ones. Quite a snappy topic, really

  4. #4
    Banned

    Join Date
    Jan 2010
    Location
    Baltimore,Maryland
    Posts
    260
    Post Thanks / Like
    Rep Power
    0
    Reputation
    87
    Higher-Tier Lua
    This topic is comprised of some Higher-Tier features, such as tables and boss encounters. Please do not proceed unless you fully understand the previous topics.

    This topic consists of:

    • Tables
    • Boss Encounters
    • Nil Checks
    • Changing the Unit

    Tables

    Tables are awesome. No, really. They are. I use them a lot, and I love them. They are very helpful and will probably be used in most (if not all) of your advanced scripts. They are used lots inside the Guild Housing Script (Alvanaar) and my Party v Party, Raid v Raid and Guild v Guild script (Still in development phase as of this writing).

    Tables are actually used for a few statements in fact, so don't think they are useless, because they are not. They are used in such functions as :GetInRangePlayers(), :GetInRangePlayersCount, GetPlayersInWorld(), and so on, so forth. Tables are returned in two columns; Value and Key. The Key is like a unique identifier to the value. Imagine a MySQL table. The Key is the Entry ID, and the Value is the input.


    Code:
    |      Key		|		Value		|
    |_______________|___________________|
    |		1		|		Neglected	|
    |		2		|		Alvanaar	|
    |		3		|		Paradox		|


    ^ Crappy visual example. ^^,

    Tables are defined by using curly braces. These are above the square bracket key on a QWERTY keyboard, and look like this;


    Code:
    {}
    To define our first table, we'll name it 't'. Note that tables are defined in the same way as variables; They can be local or global.


    Code:
    local t = {}

    Inside this table we can place anything; strings, integers, decimals, variables and even other tables. I'll start off by doing a simple name print. We'll add 3 names to our table;

    Code:
    local t = {"Neglected", "Alvanaar", "OnyxiaKing"}
    Take note that each value is seperated by a comma (','). The keys are generated automatically. We can represent a value of a table by writing in the table name and then the key inside square brackets. For example, t[1] would refer to "Neglected". Therefore, doing the following:

    Code:
    print(t[1])
    Will print the following to the console

    Code:
    Neglected
    Likewise, doing print(t[1]..", "..t[2]..", and "..t[3].." are pwn.") will print the following to the console

    Code:
    Neglected, Alvanaar and OnyxiaKing are pwn
    Note: You can only have 60 upvalues (t[1], t[2] etc) in a function. I learnt this the hard way whilst making my teleporter NPC..

    But wait; what are these full stops for? Well, they are conatecation operators. If you place two of them, either side of a variable, they automatically become inserted into the string. For example, t[1]..", " will make t[1] become part of the string, and thus the string becomes "Neglected, ". It's a very powerful thing.

    Anyway, back on to tables. Some statements are returned as tables in Lua. To use these, we need to arrange them into keys and values. How do we do this? Well,



    Code:
    for k, v in pairs(t) do
    	print(v)
    end
    Wait, what?! We just did this.. 'for'.. thing.

    Yes, we did. The 'for' keyword is a loop, like the 'if' one. 'k, v' organises the table into keys and values, and assigns them k and v. So, all values inside the table are assigned to v, and all keys inside the table are assigned to k. This means, that if we use print(v), that all of the values in the 't' table will be printed to the console.

    Because the 'for' keyword is a loop, we have to end it with the keyword end.

    A few other notes before we move on from tables; You can change the "k, v" to anything. Just remember the first value will return as the keys and the second will return as values. "lol, rofl" would work, for example. But, print(rofl) doesn't exactly.. seem professional, does it?

    Here is an example of a function that returns as a table; GetPlayersInWorld()



    Code:
    function GetPlayersInWorldAndKill(Unit, Event)
    	local plrs = GetPlayersInWorld() -- assign the table to plrs
    	for k, v in pairs(plrs) do -- Sort 'plrs' into keys and values (k and v)
    		v:CastSpell(7) -- make v (the values of plrs) cast 7 (suicide) on themselves.
    	end
    end
    Easy? I thought so too. It all goes downhill from here (;

    Boss Encounters.
    Oh goody, boss encounters! The bit everyone aspires to do! (/glare at Xyolexus)

    Creating Boss Encounters is easy. Creating decent ones.. now, that's a challenge. However, they all follow the same structure; OnCombat, OnKilledTarget, OnLeaveCombat, and OnDeath. Sometimes you'll have OnSpawn, but that is only if people are using multiple mobs in one script. Here is the basic structure of a boss fight;



    Code:
    --[[
    	Boss Fight Structure
    	Ultimate Lua Tutorial
    	Neglected
    ]]
    
    local NPC_ID = 133713
    
    function NPC_OnSpawn(Unit, Event)
    end
    
    function NPC_OnCombat(Unit, Event)
    end
    
    function NPC_OnLeaveCombat(Unit, Event)
    	Unit:RemoveEvents()
    end
    
    function NPC_OnKilledTarget(Unit, Event)
    end
    
    function NPC_OnDeath(Unit, Event)
    	Unit:RemoveEvents()
    end
    
    RegisterUnitEvent(NPC_ID, 1, "NPC_OnCombat")
    RegisterUnitEvent(NPC_ID, 2, "NPC_OnLeaveCombat")
    RegisterUnitEvent(NPC_ID, 3, "NPC_OnKilledTarget")
    RegisterUnitEvent(NPC_ID, 4, "NPC_OnDeath")
    RegisterUnitEvent(NPC_ID, 18, "NPC_OnSpawn")
    Now since you understand the concepts of functions and registering events, and NPC_IDs, and variables, I don't think I'll need to explain much to you, apart from that one statement, :RemoveEvents(). This statement removes every event from the NPC in question, which means it no longer executes OnCombat, it never Cast Spells; until you respawn it, of course. It is used in OnLeaveCombat and OnDeath.. because, well, it wouldn't exactly be a good thing if, after players killed the mob, the mob killed them with a Holy Nova.

    The hunter becomes the hunted. Heh.

    A key thing in Bosses is phasing. It's all well having a boss, but it's really monotonous (boring, plain) if you just have it casting a spell over and over and over again with no variation in it's spells in relation to it's health. Luckily, the 'if' loop comes to the rescue here! We can construct a condition that will only allow it to go into another phase if it has x amount of health, or even x% of health.



    Code:
    if (Unit:GetHealthPct() <= 50) then
    		Unit:RegisterEvent("NPC_UFiftyPct", 1, 1)
    	end
    This is good, but it needs to be attached to a function. It's pretty self explanatory what it does. But the problem is, unless we attach it to it's own function and then register that function every second or so, it'll only run once. And then the Phase will probably never get a chance to register itself.

    Code:
    function NPC_OnCombat(Unit, Event)
    Unit:RegisterEvent("NPC_CheckIfUnderFiftyPct", 1000, 0)
    end
    
    function NPC_CheckIfUnderFiftyPct(Unit, Event)
    if (Unit:GetHealthPct() <= 50) then
    Unit:RegisterEvent("NPC_UFiftyPct", 1, 1)
    end
    end
    
    function NPC_UFiftyPct(Unit, Event)
    local plrs = Unit:GetInRangePlayers()
    for k, v in pairs(plrs) do
    Unit:CastSpellOnTarget(5, v)
    end
    end
    This code will do that purpose. When combat is started, it will register an event every 1000ms (1 Second). Since the repeat is set to 0, it will keep on repeating.

    Code:
     
     
    :RegisterEvent(FUNCTION_NAME, DELAY, REPEAT)

    Every second, we will check if the Unit's Health Percent is under 50. If it is, we will register NPC_UFiftyPct. If it isn't, then the function ends.

    When NPC_UFiftyPct is registered, then every player is range is killed by Death Touch


    Code:
    :CastSpellOnTarget(SPELL_ID, TARGET)
    This is a very brief overview, because most of Boss Encounters can only be found out via Trial and Error. However, I will spare another feature with you.

    Making an NPC unattackable.
    What this code does is that it sets the NPC to be unattackable (but still displays it as hostile).



    Code:
    Unit:SetUInt32Value(58, 2)
    This bit sets the NPC as unattackable. If you click him, he is displayed as hostile, but you won't see the sword when you mouse-over. You won't be able to attack him, at all.

    Code:
    Unit:SetUInt32Value(58, 26)
    The above code will make the NPC unselectable from the client.
    To make him attackable again, you use this code:


    Code:
    Unit:SetUInt32Value(58, 0)
    Quite simple eh? It's certainly not the most ideal solution, but it is the only way to do this in Lua as of this writing.

    So, to recap. SetUInt32Value(58, 2) will set the NPC as unattackable, SetUInt32Value(52, 0) will set the NPC as attackable.

    Furthermore, here are all of the Unit flags (That are known as of r2850)



    Code:
    2 -- Client won't let you attack the mob
    4 -- Makes players & NPCs attackable/unattackable
    256 -- Changes attackable status
    13 -- Sets PVP Flag
    14 -- Silenced
    15 -- Dead
    17 -- Alive
    18 -- Pacified
    19 -- Stunned
    20 -- Sets Combat Flag
    21 -- Sets the same flag as mounted on a taxi (Can't cast spells)
    22 -- Disarmed
    23 -- Confused
    24 -- Fleeing/Fear
    25 -- Makes players & NPCs attackable/unattackable
    26 -- Unselectable
    27 -- Skinnable
    30 -- Feign Death
    Nil Checks.
    Although nil checks are considered 'Medium-Level Lua', they are just a matter of adding another if statement to the code. Therefore, this topic will be pretty short. (Cue, "That's what she said")

    A nil check is used to fool-proof a spell cast in order to make sure the script doesn't bug. It simply checks if the Unit we are aiming at exists (or is not nil) before it does anything. It's just two bits of extra code; an if statement, and an end.


    Code:
    function KillRandomPlayer(Unit, Event)
    	local tar = Unit:GetRandomPlayer(0)
    	if (tar ~= nil) then
    		Unit:CastSpellOnTarget(5, tar)
    	end
    end
    Too easy, yeah?

    Changing the/Adding Units.
    This is where the confusion sets in, haha. Defining Units can (and will) get very confusing, if you're a beginner at doing it. But, once you can do it, it's like riding a bike. It's simple (In fact, you're just defining a variable), but some times you can mess up and go back to the old way of things (Which you aren't allowed to do).

    Remember I said earlier, in the Boss Encounter section, that OnSpawn events are only really included to define Units? Well, this is because this is the only place you can really do it. Especially for boss encounters. The thing with Defining a Unit, is that once you define a Unit, you cannot go back to using Unit:. You have to use the Unit you defined. That's the downside to it. The upside to it, is that you can have more than one mob in one script. And make them interact, of course. To define a unit, you add the following line of code to the OnSpawn event;


    Code:
    	InsertUnitHere = Unit

  5. #5
    Banned

    Join Date
    Jan 2010
    Location
    Baltimore,Maryland
    Posts
    260
    Post Thanks / Like
    Rep Power
    0
    Reputation
    87

    Register to remove this ad
    Credits go to neglected from ac-web thxs man this helped me a little and im glad i msharing with others from other places to help them too

    This is a share if ure gonna flame or QQ plz dont even psot if u dont got noting nice to say or helpful plz jsut leave enless ure a mod or admin thank you




  6. Related Threads - Scroll Down after related threads if you are only interested to view replies for above post/thread

 

 

Visitors found this page by searching for:

how to open gossip-menu wow

k-means in lua

trinity tuto créer pnj gossip learn spell

SEO Blog

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  
All times are GMT -5. The time now is 08:07 PM.
Powered by vBulletin® Copyright ©2000-2024, Jelsoft Enterprises Ltd.
See More links by ForumSetup.net. Feedback Buttons provided by Advanced Post Thanks / Like (Lite) - vBulletin Mods & Addons Copyright © 2024 DragonByte Technologies Ltd.
vBulletin Licensed to: MMOPro.org