Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local npcId = 70000;
- local minionId = 70001;
- local minion2Id = 70002;
- local portalId = 70005;
- local CREATURE_EVENT_ON_ENTER_COMBAT = 1;
- local CREATURE_EVENT_ON_LEAVE_COMBAT = 2;
- local CREATURE_EVENT_ON_DIED = 4;
- local CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE = 19;
- local CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED = 21;
- local CREATURE_EVENT_ON_SUMMONED = 22;
- local CREATURE_EVENT_ON_RESET = 23;
- local ACTION_MOVE_HOME = 1;
- local ACTION_SPAWN_LIGHT_ZONE = 2;
- local ACTION_ZONE_EXPLOSION = 3;
- local ACTION_SPAWN_LIGHT_MINION = 4;
- local ACTION_PREPARE_DARK_ZONE = 5;
- local ACTION_DESTROY_DARK_ZONE = 6;
- local VOID_ZONE_LIGHT = 40670;
- local VOID_ZONE_DARK = 40672;
- local VOID_ZONE_LIGHT_VISUAL = 74629;
- local VOID_ZONE_DARK_VISUAL = 74803;
- local VOID_ZONE_DARK_DAMAGE = 75874;
- local SPELL_BEAM_OF_LIGHT = 46822;
- local SPELL_ROOT = 38505;
- local SPELL_SHADOW_AURA = 72523;
- local SPELL_SHROUD_OF_SORROW = 70985;
- local SPELL_SHADOW_EXPLOSION = 74799;
- local SPELL_HOLY_NOVA = 35740;
- local DISPLAY_ID_SHADOW_FORM = 25452;
- local OBJECT_END = 0x0006;
- local UNIT_FIELD_FLAGS = OBJECT_END + 0x0035;
- local UNIT_FLAG_NOT_SELECTABLE = 0x02000000;
- --local UNIT_FLAG_NOT_ATTACKABLE = 0x00000002;
- local creatureSpells = {
- -- Light phase
- ["SMITE"] = {id = 71778, cooldown = 12},
- ["HOLY_FIRE"] = {id = 66538, cooldown = 15},
- ["DISARM"] = {id = 27581, cooldown = 20},
- -- Dark phase
- ["SHADOW_CLEAVE"] = {id = 70670, cooldown = 3},
- ["SHADOW_STRIKE"] = {id = 40685, cooldown = 18},
- ["DEATH_AND_DECAY"] = {id = 61603, cooldown = 15},
- ["DARK_SHELL"] = {id = 38759, cooldown = 30},
- ["SHADOW_BOLT"] = {id = 55851, cooldown = 10}
- };
- local arthura = {};
- local function getClass(pUnit, AIFunc)
- local guid = pUnit:GetGUIDLow();
- if arthura[guid] == nil then
- arthura[guid] = AIFunc(pUnit);
- end
- return arthura[guid];
- end
- local function tableFind(tbl, value)
- for _, v in pairs(tbl) do
- if tostring(v) == tostring(value) then
- return true;
- end
- end
- return false;
- end
- -- Creature class ( sort of .. )
- local function arthuraAI(pUnit)
- -- Private
- local phase = 1;
- local eventTimer = 0;
- local actionInProgress = false;
- local darkMinion;
- local cooldown = {};
- local function hasCooldown(name)
- if not cooldown[name] then
- return false;
- end
- if os.time() > cooldown[name] then
- return false;
- end
- return true;
- end
- local function setCooldown(name)
- cooldown[name] = os.time() + creatureSpells[name].cooldown;
- end
- local function getEntry(name)
- return creatureSpells[name].id;
- end
- local function getRandomPlayer()
- local targetList = pUnit:GetPlayersInRange();
- return targetList[math.random(#targetList)];
- end
- -- public
- local self = {};
- function self.onReset()
- phase = 1;
- actionInProgress = false;
- eventTimer = 0;
- pUnit:RemoveEvents();
- end
- function self.onCombatStart()
- pUnit:SendUnitYell("You were fools to come here, you will never walk out of here alive!", 0);
- pUnit:RegisterEvent(self.onAIUpdate, 1000, 0);
- end
- function self.onLeaveCombat()
- local unitDarkMinion = getClass(darkMinion, darkMinionAI);
- unitDarkMinion.onDestroy();
- local portal = pUnit:GetNearObject(50, 0, portalId)
- local voidZone = pUnit:GetNearObject(50, 0, VOID_ZONE_DARK)
- if portal then
- portal:DespawnOrUnsummon();
- end
- if voidZone then
- voidZone:DespawnOrUnsummon();
- end
- end
- function self.onJustDied(pKiller)
- pUnit:SendUnitYell("You beaten the combination of shadow and light! How?", 0)
- end
- function self.onJustSummoned(_, pSummoned)
- darkMinion = pSummoned;
- end
- function self.onAIUpdate()
- eventTimer = eventTimer + 1;
- -- :MoveTo() roots the boss, so I had to come up
- -- with something.
- if not actionInProgress then
- pUnit:MoveChase(pUnit:GetVictim(), 0, 0);
- end
- local healthPct = pUnit:GetHealthPct();
- if phase == 1 then
- if not pUnit:IsFullHealth() then
- pUnit:SetHealth(pUnit:GetHealth() + (pUnit:GetMaxHealth() * 0.001)); -- about 10000 a second.
- end
- if eventTimer % 30 == 0 and not actionInProgress then
- self.doAction(ACTION_MOVE_HOME);
- elseif actionInProgress and not pUnit:GetNearObject(50, 0, VOID_ZONE_LIGHT) then
- local x, y = pUnit:GetHomePosition();
- if pUnit:GetX() == x and pUnit:GetY() == y then
- self.doAction(ACTION_SPAWN_LIGHT_ZONE);
- CreateLuaEvent(function() self.doAction(ACTION_ZONE_EXPLOSION); end, 10000, 1);
- end
- end
- if eventTimer % 20 == 0 and not pUnit:GetNearObject(50, 0, minionId) then
- self.doAction(ACTION_SPAWN_LIGHT_MINION);
- end
- if not actionInProgress and not pUnit:GetCurrentSpell(1) then
- if not hasCooldown("SMITE") then
- local target = getRandomPlayer();
- pUnit:CastSpell(target, getEntry("SMITE"));
- setCooldown("SMITE");
- elseif not hasCooldown("HOLY_FIRE") then
- local targets = {};
- local targetList = pUnit:GetPlayersInRange();
- while #targets < 3 do
- local target = targetList[math.random(#targetList)];
- if not tableFind(targets, target) then
- table.insert(targets, target);
- end
- if #targetList == #targets then break; end -- In case of < 3 targets.
- end
- for _, v in pairs(targets) do
- pUnit:CastSpell(v, getEntry("HOLY_FIRE"), true);
- end
- setCooldown("HOLY_FIRE");
- elseif not hasCooldown("DISARM") then
- pUnit:CastSpell(pUnit:GetVictim(), getEntry("DISARM"));
- setCooldown("DISARM");
- end
- end
- if not actionInProgress and healthPct <= 50then
- pUnit:SendUnitYell("Weak is the light, I cannot ... control ... ARRGGGH!", 0);
- pUnit:CastSpell(pUnit, SPELL_SHADOW_EXPLOSION );
- pUnit:SetDisplayId(DISPLAY_ID_SHADOW_FORM);
- phase = 2;
- end
- elseif phase == 2 then
- if eventTimer % 5 == 0 then
- pUnit:CastSpell(pUnit, SPELL_SHROUD_OF_SORROW);
- end
- if eventTimer % 30 == 0 and not actionInProgress then
- self.doAction(ACTION_PREPARE_DARK_ZONE);
- end
- if not pUnit:GetCurrentSpell(1) then
- if not hasCooldown("SHADOW_CLEAVE") then
- pUnit:CastSpell(pUnit:GetVictim(), getEntry("SHADOW_CLEAVE"));
- setCooldown("SHADOW_CLEAVE");
- elseif not hasCooldown("SHADOW_STRIKE") then
- pUnit:CastSpell(pUnit:GetVictim(), getEntry("SHADOW_STRIKE"));
- setCooldown("SHADOW_STRIKE");
- elseif not hasCooldown("DEATH_AND_DECAY") then
- local target = getRandomPlayer();
- pUnit:CastSpell(target, getEntry("DEATH_AND_DECAY"));
- setCooldown("DEATH_AND_DECAY");
- elseif not hasCooldown("DARK_SHELL") then
- if not pUnit:HasAura(getEntry("DARK_SHELL")) then
- pUnit:CastSpell(pUnit, getEntry("DARK_SHELL"))
- end
- setCooldown("DARK_SHELL");
- elseif not hasCooldown("SHADOW_BOLT") then
- pUnit:CastSpell(pUnit, getEntry("SHADOW_BOLT"));
- setCooldown("SHADOW_BOLT");
- end
- end
- end
- end
- function self.doAction(action)
- local function getRandomCoords()
- local x, y, z = pUnit:GetHomePosition();
- x = math.random(2) == 1 and x-25 or x+25;
- y = y + math.random(-25, 25);
- return x, y, z;
- end
- if action == ACTION_MOVE_HOME then
- local x, y, z = pUnit:GetHomePosition();
- pUnit:MoveTo(1, x, y, z, false);
- actionInProgress = true;
- elseif action == ACTION_SPAWN_LIGHT_ZONE then
- local x, y, z = pUnit:GetHomePosition();
- pUnit:SpawnCreature(VOID_ZONE_LIGHT, x+20, y+20, z, 0, 1, 20000);
- pUnit:SpawnCreature(VOID_ZONE_LIGHT, x-20, y-20, z, 0, 1, 20000);
- pUnit:SendUnitYell("Prepare for the true power of light!", 0)
- elseif action == ACTION_ZONE_EXPLOSION then
- pUnit:CastSpell(pUnit, SPELL_BEAM_OF_LIGHT);
- CreateLuaEvent(function() pUnit:RemoveAura(SPELL_BEAM_OF_LIGHT); end, 1000, 1);
- local targets = {};
- for _, v in pairs(pUnit:GetNearObjects(40, 0, VOID_ZONE_LIGHT)) do
- for _, target in pairs(pUnit:GetPlayersInRange()) do
- local inTable = tableFind(targets, target);
- if v:GetDistance(target) > 3 and inTable then
- pUnit:Kill(target);
- elseif v:GetDistance(target) > 3 and not inTable then
- table.insert(targets, target);
- end
- end
- end
- eventTimer = 0;
- actionInProgress = false;
- elseif action == ACTION_SPAWN_LIGHT_MINION then
- local x, y, z = getRandomCoords();
- pUnit:SpawnCreature(minionId, x, y, z, 0, 1, 20000);
- elseif action == ACTION_PREPARE_DARK_ZONE then
- local target = getRandomPlayer();
- pUnit:SpawnCreature(VOID_ZONE_DARK, target:GetX(), target:GetY(), target:GetZ(), 0, 1, 200000);
- local x, y, z = getRandomCoords();
- pUnit:SpawnCreature(portalId, x, y, z, 0, 1, 200000);
- x, y, z = pUnit:GetHomePosition();
- pUnit:SpawnCreature(minion2Id, x, y, z, 0, 1, 200000);
- actionInProgress = true;
- elseif action == ACTION_DESTROY_DARK_ZONE then
- local darkZone = pUnit:GetNearObject(50, 0, VOID_ZONE_DARK)
- if darkZone then
- darkZone:DespawnOrUnsummon();
- end
- eventTimer = 0;
- actionInProgress = false;
- end
- end
- return self;
- end
- local function handleArthuraAI(event, pUnit, ...)
- local self = getClass(pUnit, arthuraAI);
- if event == CREATURE_EVENT_ON_ENTER_COMBAT then
- self.onCombatStart();
- elseif event == CREATURE_EVENT_ON_LEAVE_COMBAT then
- self.onLeaveCombat();
- elseif event == CREATURE_EVENT_ON_DIED then
- local pKiller = select(1, ...);
- self.onJustDied(pKiller);
- elseif event == CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE then
- local pSummoned = select(1, ...);
- self.onJustSummoned(pUnit, pSummoned);
- elseif event == CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED then
- local pSummoned = select(1, ...);
- local pKiller = select(2, ...);
- self.onSummonedCreatureDied(pUnit, pSummoned, pKiller);
- elseif event == CREATURE_EVENT_ON_RESET then
- self.onReset();
- end
- end
- RegisterCreatureEvent(npcId, CREATURE_EVENT_ON_ENTER_COMBAT, handleArthuraAI);
- RegisterCreatureEvent(npcId, CREATURE_EVENT_ON_LEAVE_COMBAT, handleArthuraAI);
- RegisterCreatureEvent(npcId, CREATURE_EVENT_ON_DIED, handleArthuraAI);
- RegisterCreatureEvent(npcId, CREATURE_EVENT_ON_JUST_SUMMONED_CREATURE, handleArthuraAI);
- --RegisterCreatureEvent(npcId, CREATURE_EVENT_ON_SUMMONED_CREATURE_DIED, handleArthuraAI);
- RegisterCreatureEvent(npcId, CREATURE_EVENT_ON_RESET, handleArthuraAI);
- local function lightZoneAI(pUnit)
- -- private
- local summoner;
- local function getDamage()
- local damage = 50000;
- local vZone = pUnit:GetNearObject(60, 0, VOID_ZONE_LIGHT)
- for _, v in pairs(vZone:GetPlayersInRange()) do
- if vZone:GetDistance(v) <= 3 then
- return damage;
- end
- end
- return damage * 5;
- end
- local function handleVoidZone()
- if not summoner:IsAlive() then
- return pUnit:DespawnOrUnsummon();
- end
- local players = {}
- for _, v in pairs(pUnit:GetPlayersInRange()) do
- if pUnit:GetDistance(v) <= 3 then
- table.insert(players, v);
- end
- end
- local damage = getDamage() / #players;
- for _, v in pairs(players) do
- pUnit:DealDamage(v, damage);
- end
- pUnit:DespawnOrUnsummon(2000);
- end
- -- public
- local self = {};
- function self.onJustSummoned(pSummoner)
- summoner = pSummoner;
- pUnit:SetFaction(35);
- pUnit:CastSpell(pUnit, VOID_ZONE_LIGHT_VISUAL);
- pUnit:SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- pUnit:RegisterEvent(handleVoidZone, 10000, 1);
- end
- return self;
- end
- local function handleLightZoneAI(event, pUnit, ...)
- local self = getClass(pUnit, lightZoneAI);
- if event == CREATURE_EVENT_ON_SUMMONED then
- local pSummoner = select(1, ...);
- self.onJustSummoned(pSummoner);
- end
- end
- RegisterCreatureEvent(VOID_ZONE_LIGHT, CREATURE_EVENT_ON_SUMMONED, handleLightZoneAI);
- local function lightMinionAI(pUnit)
- -- private
- local summoner;
- -- public
- local self = {};
- function self.onJustSummoned(pSummoner)
- summoner = pSummoner;
- pUnit:RegisterEvent(self.onAIUpdate, 1000, 0);
- end
- function self.onJustDied(pKiller)
- pUnit:DespawnOrUnsummon();
- end
- function self.onAIUpdate()
- pUnit:MoveChase(summoner, 0, 0);
- if pUnit:GetDistance(summoner) <= 2 then
- local maxHealth = summoner:GetMaxHealth();
- local mMaxHealth = summoner:GetHealth()+(maxHealth/20);
- if mMaxHealth > maxHealth then
- summoner:SetHealth(maxHealth);
- else
- summoner:SetHealth(mMaxHealth);
- end
- summoner:CastSpell(summoner, SPELL_HOLY_NOVA);
- pUnit:DespawnOrUnsummon();
- end
- end
- return self;
- end
- local function handleLightMinionAI(event, pUnit, ...)
- local self = getClass(pUnit, lightMinionAI);
- if event == CREATURE_EVENT_ON_SUMMONED then
- local pSummoner = select(1, ...);
- self.onJustSummoned(pSummoner);
- elseif event == CREATURE_EVENT_ON_DIED then
- local pKiller = select(1, ...);
- self.onJustDied(pKiller);
- end
- end
- RegisterCreatureEvent(minionId, CREATURE_EVENT_ON_SUMMONED, handleLightMinionAI);
- RegisterCreatureEvent(minionId, CREATURE_EVENT_ON_DIED, handleLightMinionAI);
- local function darkZoneAI(pUnit)
- -- private
- local summoner;
- local scale = 1;
- local function onDamageTick()
- local unitArthura = pUnit:GetNearObject(50, 0, npcId)
- if not unitArthura then return; end
- for _, v in pairs(pUnit:GetPlayersInRange()) do
- if pUnit:GetDistance(v) <= scale*3 then
- unitArthura:CastSpell(v, VOID_ZONE_DARK_DAMAGE);
- end
- end
- end
- -- public
- local self = {};
- function self.onJustSummoned(pSummoner)
- summoner = pSummoner;
- pUnit:SetFaction(35);
- pUnit:CastSpell(pUnit, VOID_ZONE_DARK_VISUAL);
- pUnit:SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- pUnit:RegisterEvent(self.onAIUpdate, 100, 0);
- pUnit:RegisterEvent(onDamageTick, 1000, 0);
- end
- function self.onAIUpdate()
- if not summoner:IsAlive() then
- return pUnit:DespawnOrUnsummon();
- end
- scale = scale + 0.02;
- pUnit:SetScale(scale);
- if scale >= 10 then
- pUnit:DespawnOrUnsummon();
- end
- end
- return self;
- end
- local function handleDarkZoneAI(event, pUnit, ...)
- local self = getClass(pUnit, darkZoneAI);
- if event == CREATURE_EVENT_ON_SUMMONED then
- local pSummoner = select(1, ...);
- self.onJustSummoned(pSummoner);
- end
- end
- RegisterCreatureEvent(VOID_ZONE_DARK, CREATURE_EVENT_ON_SUMMONED, handleDarkZoneAI);
- local function portalAI(pUnit)
- -- private
- local summoner;
- -- public.
- local self = {};
- function self.onJustSummoned(pSummoner)
- summoner = pSummoner;
- pUnit:SetUInt32Value(UNIT_FIELD_FLAGS, UNIT_FLAG_NOT_SELECTABLE);
- pUnit:RegisterEvent(self.onAIUpdate, 1000, 0);
- end
- function self.onAIUpdate()
- if not summoner:IsAlive() then
- return pUnit:DespawnOrUnsummon();
- end
- for _, v in pairs(pUnit:GetPlayersInRange()) do
- if pUnit:GetDistance(v) <= 3 then
- v:SetPhaseMask(4);
- return pUnit:DespawnOrUnsummon();
- end
- end
- end
- return self;
- end
- local function handlePortalAI(event, pUnit, ...)
- local self = getClass(pUnit, portalAI);
- if event == CREATURE_EVENT_ON_SUMMONED then
- local pSummoner = select(1, ...);
- self.onJustSummoned(pSummoner);
- end
- end
- RegisterCreatureEvent(portalId, CREATURE_EVENT_ON_SUMMONED, handlePortalAI);
- local function darkMinionAI(pUnit)
- -- private
- local summoner;
- -- public
- local self = {};
- function self.onJustSummoned(pSummoner)
- summoner = pSummoner;
- pUnit:SetPhaseMask(4);
- pUnit:RegisterEvent(self.onAIUpdate, 1000, 0);
- end
- function self.onJustDied(pKiller)
- pKiller:SetPhaseMask(1);
- local unitArthura = getClass(summoner, arthuraAI);
- unitArthura.doAction(ACTION_DESTROY_DARK_ZONE);
- pUnit:DespawnOrUnsummon();
- end
- function self.onAIUpdate()
- if not summoner:IsAlive() then
- for _, v in pairs(pUnit:GetPlayersInRange()) do
- v:SetPhaseMask(1);
- end
- return pUnit:DespawnOrUnsummon();
- end
- if not pUnit:HasSpell(SPELL_ROOT) then
- pUnit:CastSpell(pUnit, SPELL_ROOT); pUnit:CastSpell(pUnit, SPELL_SHADOW_AURA);
- end
- end
- function self.onDestroy()
- for _, v in pairs(pUnit:GetPlayersInRange()) do
- v:SetPhaseMask(1);
- end
- pUnit:DespawnOrUnsummon();
- end
- return self;
- end
- local function handleDarkMinionAI(event, pUnit, ...)
- local self = getClass(pUnit, darkMinionAI);
- if event == CREATURE_EVENT_ON_SUMMONED then
- local pSummoner = select(1, ...);
- self.onJustSummoned(pSummoner);
- elseif event == CREATURE_EVENT_ON_DIED then
- local pKiller = select(1, ...);
- self.onJustDied(pKiller);
- end
- end
- RegisterCreatureEvent(minion2Id, CREATURE_EVENT_ON_SUMMONED, handleDarkMinionAI);
- RegisterCreatureEvent(minion2Id, CREATURE_EVENT_ON_DIED, handleDarkMinionAI);
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement