
Results 1 to 5 of 5
Threaded View
-
17-03-10, 09:50 PM #4
- 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:{}
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"}
Code:print(t[1])
Code:Neglected
Code:Neglected, Alvanaar and OnyxiaKing are pwn
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
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
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")
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
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
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)
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)
Code:Unit:SetUInt32Value(58, 26)
To make him attackable again, you use this code:
Code:Unit:SetUInt32Value(58, 0)
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
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
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