forked from ornfelt/azerothcore_lua_scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathXT-Turret.lua
More file actions
220 lines (187 loc) · 11.5 KB
/
XT-Turret.lua
File metadata and controls
220 lines (187 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
-- We create a 'box' (aka 'namespace') to keep all our code for this NPC in one place.
-- We appropriately call this box 'TurretBoi'.
local TurretBoi = {}
-- We tell the game which NPC this script is for by specifying its ID number.
-- Since we'll be using TurretBoi.NPC_ID in mulitple parts of the script, we want to define it.
-- This also makes it much easier to change later on if we need to do so since all we need to change is one npcid.
TurretBoi.NPC_ID = 832350
-- We make a list of spells this NPC will use. Right now, it's just one spell.
TurretBoi.SPELL_IDS = {
SPELL_TO_CAST = 38083 -- The spell this NPC will cast.
-- You can put more spells here:
-- SECOND_SPELL_TO_CAST = 123456
}
-- When this NPC needs to cast a spell, this function gets called.
-- Don't worry about the 'eventId', 'delay', and 'repeats' stuff, they are just placeholders we have to include.
-- See notes below.
function TurretBoi.CastSpell(eventId, delay, repeats, creature)
-- The NPC casts the spell on whomever it's fighting.
-- 'creature:GetVictim' means that the creature is attacking it's current (highest threat) target
-- The 'true' statement at the end tells the creature to cast this spell instantly and free (0 mana, energy, etc).
---- If you have more than one spell being cast in combat, this is the easiest way to prevent the npc from interrupting itself.
---- You can of course work around this to ensure no other spell is being cast, but then it will skip over said spell.
---- The better alternative is create a que system which allows the first cast to go through, puts the second cast on standby, and casts it after some time has passed.
---- For the purposes of this guide, that's way too complicated. I've included an example at the very bottom of the script though.
creature:CastSpell(creature:GetVictim(), TurretBoi.SPELL_IDS.SPELL_TO_CAST, true)
end
-- *If you wanted a second spell to cast, you'd define it the same way as above:
--function TurretBoi.CastSecondSpell(eventId, delay, repeats, creature)
-- creature:CastSpell(creature:GetVictim(), TurretBoi.SPELL_IDS.SECOND_SPELL_TO_CAST, true)
--end
-- This function runs when the NPC starts fighting.
function TurretBoi.OnEnterCombat(event, creature)
-- We set up the NPC to cast its spell every 3 seconds in milliseconds.
-- 0 means it repeats over and over. Setting this number to 1 would make it happen only once, for example.
creature:RegisterEvent(TurretBoi.CastSpell, 3000, 0)
-- *Here's also where you'd add an event to cast a second spell
-- creature:RegisterEvent(TurretBoi.CastSecondSpell, 7000, 0)
end
-- This function runs when the NPC stops fighting.
function TurretBoi.OnLeaveCombat(event, creature)
-- We tell the NPC to forget any special actions we set up earlier.
-- This is important for saving memory and making sure events don't just keep happning.
-- It's basically telling the script 'Hey, we're done!'
creature:RemoveEvents()
end
-- This function runs when the NPC dies.
function TurretBoi.OnDied(event, creature)
-- Again, we tell the NPC to forget any special actions we set up earlier.
creature:RemoveEvents()
end
-- We tell the game to use the above functions when certain things happen to the NPC.
-- You can find these 'hooks' in modules/mod-eluna/src/LuaEngine/Hooks.h
-- Basically when A happens, make B happen too.
RegisterCreatureEvent(TurretBoi.NPC_ID, 1, TurretBoi.OnEnterCombat)
RegisterCreatureEvent(TurretBoi.NPC_ID, 2, TurretBoi.OnLeaveCombat)
RegisterCreatureEvent(TurretBoi.NPC_ID, 4, TurretBoi.OnDied)
--------------------------------
--------------------------------
-- ADDITIONAL NOTES
--------------------------------
--------------------------------
-- Question: Why do we need to include placeholders (arguments) like 'eventId', 'delay', and 'repeats' even if we don't use them?
-- Think of it like a handshake. Both sides expect it to go a certain way.
-- If we leave out any part, the handshake fails, and the game might act weird or crash.
-- Question: How do you know what placeholders ('eventId', 'delay', etc.) to include in the first place?
-- This comes from reading the manual, looking at examples, and sometimes asking other people who know.
-- If we get it wrong, the game will usually give us a hint about what's missing.
-- Question: What's the deal with this 'TurretBoi' box we keep everything in?
-- Putting all related things in one 'box' (we call it a namespace) helps keep our script tidy and makes sure it doesn't mess with other scripts.
-- It's like giving it its own room with a nameplate.
-- Question: Any downsides to using these 'boxes' or namespaces?
-- Yes, if you're new, this can look confusing.
-- Also, if you're not careful, you could end up using more computer memory.
-- Lastly, if you put everything in separate 'boxes', it might be hard to make them talk to each other.
---------------------------------
---------------------------------
-- CUSTOM MAGMADAR FIGHT EXAMPLE
---------------------------------
---------------------------------
--[[
-- Defines a table to store functions and variables for Magmadar throughout the fight
local Magmadar = {}
-- Initialize a table to store a queue of spells.
-- This is a system I came up with so that bosses won't interrupt themselves with their own spell casts and skip certain spells.
-- If you have skipcheck set to true on spell casts,
-- hen you do not need a spell que system since all spells will be cast instantly and not interrupt eachother.
Magmadar.spellQueue = {}
-- Defines a list of spells. You can always call these directly with the ID number instead directly in the cast functions.
local SPELL_FRENZY = 19451
local SPELL_PANIC = 19408
local SPELL_LAVA_BOMB = 19411
local SPELL_LAVA_BOMB_RANGED = 20474
local SPELL_SUMMON_CORE_HOUND = 364726 -- this is a custom spell i made to summon core hounds
local SPELL_ENRAGE = 27680
-- Defines a range to look up the distance necessary to cast "ranged" Lava Bomb as he targets melee and ranged seperately.
local MELEE_TARGET_LOOKUP_DIST = 10.0
-- Periodically casts frenzy on self with the emote broadcast to players to be more blizzlike
function Magmadar.CastFrenzy(eventId, delay, calls, creature)
table.insert(Magmadar.spellQueue, {spell = SPELL_FRENZY, targetType = 'self', emote = "Magmadar goes into a killing Frenzy!"})
end
-- Casts panic, an aoe spell. You could have this spell target anyone since it's aoe so I just decided to have it cast on the current victim to make things simple
function Magmadar.CastPanic(eventId, delay, calls, creature)
table.insert(Magmadar.spellQueue, {spell = SPELL_PANIC, targetType = 'victim'})
end
-- This is the function for melee lava bomb. Selects from a random pool of ai targets, which will include bots. ai targets are threat targets on Magmadar's table. Alternatively could have set this to only cast on players.
function Magmadar.CastLavaBomb(eventId, delay, calls, creature)
table.insert(Magmadar.spellQueue, {spell = SPELL_LAVA_BOMB, targetType = 'random', range = MELEE_TARGET_LOOKUP_DIST, maxRange = false}) -- this is set to false so that Magmadar does not check range of players prior to casting.
end
-- Ranged lavabomb function
function Magmadar.CastLavaBombRanged(eventId, delay, calls, creature)
table.insert(Magmadar.spellQueue, {spell = SPELL_LAVA_BOMB_RANGED, targetType = 'random', range = MELEE_TARGET_LOOKUP_DIST, maxRange = true}) -- this is set to true to cast lava bomb on ranged targets.
end
-- periodically summons corehounds. Any spells that are flagged as unit target caster should be cast on the creature itself
function Magmadar.CastSummonCoreHound(eventId, delay, calls, creature)
table.insert(Magmadar.spellQueue, {spell = SPELL_SUMMON_CORE_HOUND, targetType = 'self'})
end
-- This is an enrage funciton i put on magmadar as a dps check that will cast after 3 minutes
function Magmadar.CastEnrage(eventId, delay, calls, creature)
table.insert(Magmadar.spellQueue, {spell = SPELL_ENRAGE, targetType = 'self', emote = "Magmadar becomes enraged, significantly increasing attack speed and damage!"})
end
-- This is the actual spell que system
-- Determine's target based on the targetType property
-- 'self' targets the creature itself
-- 'victim' targets the creature's current target (its victim)
-- 'random' targets a random entity within the range, or outside of it if maxRange is set to true
-- The target is determined using the creature's AI targets, which includes both players and NPCs
-- If there are multiple targets in range, one is selected randomly
-- If a target is determined, the creature casts the spell at the target.
-- If the spell in the queue has an emote associated with it, the creature also sends that emote.
function Magmadar.ProcessSpellQueue(eventId, delay, calls, creature)
if not creature:IsCasting() and #Magmadar.spellQueue > 0 then
local nextSpell = table.remove(Magmadar.spellQueue, 1)
local target
if nextSpell.targetType == 'self' then
target = creature
elseif nextSpell.targetType == 'victim' then
target = creature:GetVictim()
elseif nextSpell.targetType == 'random' then
local targets = creature:GetAITargets(nextSpell.range or 0)
if #targets > 0 then
if nextSpell.maxRange then
for _, t in pairs(targets) do
if t:GetDistance(creature) > nextSpell.range then
target = t
break
end
end
else
target = targets[math.random(1, #targets)]
end
end
end
if target then
creature:CastSpell(target, nextSpell.spell, false)
if nextSpell.emote then
creature:SendUnitEmote(nextSpell.emote)
end
end
end
end
-- Enter combat functions, registering defined spell-casting events with random intervals.
-- Additionally, Magmadar regularly checks its spell queue.
function Magmadar.OnEnterCombat(event, creature, target)
creature:RegisterEvent(Magmadar.CastFrenzy, math.random(12000, 16000), 0) -- example: casts frenzy between 12-16 seconds if is not casting, otherwise casts it directly afterwards
creature:RegisterEvent(Magmadar.CastPanic, math.random(20000, 25000), 0)
creature:RegisterEvent(Magmadar.CastLavaBomb, math.random(8000, 10000), 0)
creature:RegisterEvent(Magmadar.CastLavaBombRanged, math.random(9000, 12000), 0)
creature:RegisterEvent(Magmadar.CastSummonCoreHound, 55000, 0)
creature:RegisterEvent(Magmadar.CastEnrage, 300000, 1) -- 5 minute enrage timer
creature:RegisterEvent(Magmadar.ProcessSpellQueue, 2000, 0)
end
-- When the creature leaves combat, it removes all its events and clears the spell queue, otherwise he continues to cast and process functions
function Magmadar.OnLeaveCombat(event, creature)
creature:RemoveEvents()
Magmadar.spellQueue = {}
end
-- When the creature dies, it removes all its events and clears the spell queue, otherwise he continues to cast even while died lol
function Magmadar.OnDied(event, creature, killer)
creature:RemoveEvents()
Magmadar.spellQueue = {}
end
-- Registers events with the Magmadar based on its creature_template ID (11982)
-- The numbers correspond to: 1 - when the creature enters combat, 2 - when the creature leaves combat, 4 - when the creature dies.
RegisterCreatureEvent(11982, 1, Magmadar.OnEnterCombat)
RegisterCreatureEvent(11982, 2, Magmadar.OnLeaveCombat)
RegisterCreatureEvent(11982, 4, Magmadar.OnDied)
]]--