Files
unitscan-turtle-hc/npcscan.lua
T
2016-02-01 12:56:57 +01:00

524 lines
13 KiB
Lua

local version = '1.0'
local author = 'shirsig'
local BROWN = { .7, .15, .05 }
local YELLOW = { 1, 1, .15 }
local CHECK_INTERVAL = .5
npcscan_targets = {}
npcscan = {}
function npcscan.without_errors(f)
local orig = UIErrorsFrame.AddMessage
UIErrorsFrame.AddMessage = function() end
f()
UIErrorsFrame.AddMessage = orig
end
do
local last_played
function npcscan.play_sound()
if not last_played or GetTime() - last_played > 10 then -- 8
local orig = GetCVar('MasterSoundEffects')
SetCVar('MasterSoundEffects', 0)
SetCVar('MasterSoundEffects', 1)
PlaySoundFile([[Interface\AddOns\npcscan\Event_wardrum_ogre.ogg]], 'Master')
PlaySoundFile([[Interface\AddOns\npcscan\scourge_horn.ogg]], 'Master')
last_played = GetTime()
end
end
end
function npcscan.check_for_targets()
for name, _ in pairs(npcscan_targets) do
-- local original_target = UnitName('target')
if npcscan.target(name) then
-- if UnitPlayerControlled('target') then
-- if original_target then
-- TargetByName(original_target, true)
-- end
-- else
npcscan.remove_target(UnitName('target'))
npcscan.play_sound()
if npcscan.flash.animation:playing() then
npcscan.flash.animation:stop_after(3)
else
npcscan.flash:reset()
npcscan.flash.animation:play()
end
npcscan.button:set_target()
-- end
end
end
end
function npcscan.target(name)
TargetByName(name, true)
return UnitName('target') and strupper(UnitName('target')) == name
end
function npcscan.on_event()
if event == 'VARIABLES_LOADED' then
do
local flash = CreateFrame('Frame')
npcscan.flash = flash
flash:Show()
flash:SetAllPoints()
flash:SetAlpha(0)
flash:SetFrameStrata('FULLSCREEN_DIALOG')
local texture = flash:CreateTexture()
texture:SetBlendMode('ADD')
texture:SetAllPoints()
texture:SetTexture([[Interface\FullScreenTextures\LowHealth]])
function flash:reset()
self:SetAlpha(0)
end
local screen_flash_in = npcscan.alpha_animation(flash, 1, .5)
local screen_flash_out = npcscan.alpha_animation(flash, -1, .5)
local screen_flash_delay = npcscan.delay(.5)
flash.animation = (screen_flash_in..screen_flash_delay..screen_flash_out) * 3
end
local button = CreateFrame('Button', 'npcscan_button', UIParent)
button:Hide()
npcscan.button = button
button:SetPoint('BOTTOM', UIParent, 0, 128)
button:SetWidth(150)
button:SetHeight(42)
button:SetScale(1.25)
button:SetFrameStrata('FULLSCREEN_DIALOG')
button:SetNormalTexture([[Interface\AddOns\npcscan\UI-Achievement-Parchment-Horizontal]])
button:SetBackdrop{
tile = true,
edgeSize = 16,
edgeFile = [[Interface\Tooltips\UI-Tooltip-Border]],
}
button:SetBackdropBorderColor(unpack(BROWN))
button:SetScript('OnEnter', function()
this:SetBackdropBorderColor(unpack(YELLOW))
end)
button:SetScript('OnLeave', function()
this:SetBackdropBorderColor(unpack(BROWN))
end)
button:SetScript('OnClick', function()
TargetByName(this:GetText(), true)
end)
function button:set_target()
self:SetText(UnitName('target'))
self.model:reset()
self.model:SetUnit('target')
self:Show()
self.glow.animation:stop()
self.shine.animation:stop()
self.glow:reset()
self.shine:reset()
self.glow.animation:play()
self.shine.animation:play()
end
do
local background = button:GetNormalTexture()
background:SetDrawLayer('BACKGROUND')
background:ClearAllPoints()
background:SetPoint('BOTTOMLEFT', 3, 3)
background:SetPoint('TOPRIGHT', -3, -3)
background:SetTexCoord(0, 1, 0, 0.25)
end
do
local title_background = button:CreateTexture(nil, 'BORDER')
title_background:SetTexture([[Interface\AddOns\npcscan\UI-Achievement-Title]])
title_background:SetPoint('TOPRIGHT', -5, -5)
title_background:SetPoint('LEFT', 5, 0)
title_background:SetHeight(18)
title_background:SetTexCoord(0, .9765625, 0, .3125)
title_background:SetAlpha(.8)
local title = button:CreateFontString(nil, 'OVERLAY', 'GameFontHighlightMedium')
title:SetPoint('TOPLEFT', title_background, 0, 0)
title:SetPoint('RIGHT', title_background)
button:SetFontString(title)
local subtitle = button:CreateFontString(nil, 'OVERLAY', 'GameFontBlackTiny')
subtitle:SetPoint('TOPLEFT', title, 'BOTTOMLEFT', 0, -4)
subtitle:SetPoint('RIGHT', title )
subtitle:SetText('NPC Found!')
end
do
local model = CreateFrame('PlayerModel', nil, button)
button.model = model
model:SetPoint('BOTTOMLEFT', button, 'TOPLEFT', 0, -4)
model:SetPoint('RIGHT', 0, 0)
model:SetHeight(button:GetWidth() * .6)
do
local last_update, delay
function model:on_update()
this:SetFacing(this:GetFacing() + (GetTime() - last_update) * math.pi / 4)
last_update = GetTime()
end
function model:on_update_model()
if delay > 0 then
delay = delay - 1
return
end
this:SetScript('OnUpdateModel', nil)
this:SetScript('OnUpdate', this.on_update)
this:SetModelScale(.75)
this:SetAlpha(1)
last_update = GetTime()
end
function model:reset()
self:SetAlpha(0)
self:SetFacing(0)
self:SetModelScale(1)
self:ClearModel()
self:SetScript('OnUpdate', nil)
self:SetScript("OnUpdateModel", self.on_update_model)
delay = 10 -- to prevent scaling bugs
end
end
end
do
local close = CreateFrame('Button', nil, button, 'UIPanelCloseButton')
close:SetPoint('TOPRIGHT', 0, 0)
close:SetWidth(32)
close:SetHeight(32)
close:SetScale(.8)
close:SetHitRectInsets(8, 8, 8, 8)
end
do
local glow = button.model:CreateTexture(nil, 'OVERLAY')
button.glow = glow
glow:SetPoint('CENTER', button, 'CENTER')
glow:SetWidth(400 / 300 * button:GetWidth())
glow:SetHeight(171 / 70 * button:GetHeight())
glow:SetTexture([[Interface\AddOns\npcscan\UI-Achievement-Alert-Glow]])
glow:SetBlendMode('ADD')
glow:SetTexCoord(0, .78125, 0, .66796875)
glow:SetAlpha(0)
function glow:reset()
self:SetAlpha(0)
end
local glow_in = npcscan.alpha_animation(glow, 1, .2)
local glow_out = npcscan.alpha_animation(glow, -1, .5)
glow.animation = glow_in..glow_out
end
do
local shine = button:CreateTexture(nil, 'ARTWORK')
button.shine = shine
shine:SetPoint('TOPLEFT', button, 0, 8)
shine:SetWidth(67 / 300 * button:GetWidth())
shine:SetHeight(1.28 * button:GetHeight())
shine:SetTexture([[Interface\AddOns\npcscan\UI-Achievement-Alert-Glow]])
shine:SetBlendMode('ADD')
shine:SetTexCoord(.78125, .912109375, 0, .28125)
shine:SetAlpha(0)
function shine:reset()
self:SetAlpha(0)
self:SetPoint('TOPLEFT', button, 0, 8)
end
local shine_delay1 = npcscan.delay(.3)
local shine_in = npcscan.alpha_animation(shine, 1, 0)
local shine_delay2 = npcscan.delay(.2)
local shine_move = npcscan.translation_animation(shine, button:GetWidth() - shine:GetWidth() + 8, 0, .4)
local shine_out = npcscan.alpha_animation(shine, -1, .2)
shine.animation = (shine_delay1..shine_in)..(shine_move + (shine_delay2..shine_out))
end
end
end
do
npcscan.last_check = GetTime()
function npcscan.on_update()
if GetTime() - npcscan.last_check >= CHECK_INTERVAL then
npcscan.last_check = GetTime()
npcscan.without_errors(npcscan.check_for_targets)
end
end
end
function npcscan.log(msg)
if DEFAULT_CHAT_FRAME then
DEFAULT_CHAT_FRAME:AddMessage('[npcscan] '..msg, 1, 1, 0)
end
end
-- Slash commands
function npcscan.sorted_targets()
local sorted_targets = {}
for key, _ in pairs(npcscan_targets) do
tinsert(sorted_targets, key)
end
sort(sorted_targets, function(key1, key2) return key1 < key2 end)
return sorted_targets
end
function npcscan.add_target(name)
local key = strupper(name)
if key ~= '' and not npcscan_targets[key] then
npcscan_targets[key] = true
npcscan.log(key..' (added)')
end
end
function npcscan.remove_target(name)
local key = strupper(name)
if npcscan_targets[key] then
npcscan_targets[key] = nil
npcscan.log(key..' (removed)')
end
end
SLASH_NPCSCAN1 = '/npcscan'
function SlashCmdList.NPCSCAN(parameter)
local _, _, command, name = strfind(parameter, '%s*(%a*)%s*(.*)')
if command == '' then
for _, key in ipairs(npcscan.sorted_targets()) do
npcscan.log(key)
end
elseif command == 'add' then
npcscan.add_target(name)
elseif command == 'rem' then
npcscan.remove_target(name)
end
end
-- Animation framework
function npcscan.translation_animation(target, x_change, y_change, duration)
return npcscan.animation(
{x_change, y_change},
duration,
function()
local _, _, _, original_x, original_y = target:GetPoint()
return original_x, original_y
end,
function(x, y)
local point, relative_to, relative_point = target:GetPoint()
target:SetPoint(
point,
relative_to,
relative_point,
x,
y
)
end
)
end
function npcscan.alpha_animation(target, change, duration)
return npcscan.animation(
{change},
duration,
function()
return target:GetAlpha()
end,
function(alpha)
target:SetAlpha(alpha)
end
)
end
function npcscan.delay(t)
return npcscan.animation({}, t, function() end, function() end)
end
do
local animation_metamethods = {}
local mul_mt = { __index = {} }
local add_mt = { __index = {} }
local concat_mt = { __index = {} }
local animation_mt = { __index = {} }
function animation_metamethods.__mul(animation, repetitions)
local self = {
_frame = CreateFrame('Frame'),
_repetitions_left = 0,
_repetitions = repetitions,
_animation = animation,
}
setmetatable(self, mul_mt)
self._frame:SetScript('OnUpdate', function()
self:_on_update()
end)
return self
end
function animation_metamethods.__add(lhs, rhs)
local self = {}
setmetatable(self, add_mt)
self._animations = {lhs, rhs}
return self
end
function animation_metamethods.__concat(lhs, rhs)
local self = { _frame = CreateFrame('Frame') }
setmetatable(self, concat_mt)
self._animations = {lhs, rhs}
self._frame:SetScript('OnUpdate', function()
self:_on_update()
end)
return self
end
for _, mt in ipairs({ mul_mt, add_mt, concat_mt, animation_mt }) do
for key, metamethod in pairs(animation_metamethods) do
mt[key] = metamethod
end
end
function mul_mt.__index:play()
self._repetitions_left = self._repetitions
end
function mul_mt.__index:playing()
return self._repetitions_left > 0
end
function mul_mt.__index:stop()
self._repetitions_left = 0
end
function mul_mt.__index:stop_after(repetitions)
self._repetitions_left = self._repetitions
end
function mul_mt.__index:_on_update()
if self._repetitions_left > 0 then
if not self._animation_started then
self._animation:play()
self._animation_started = true
elseif not self._animation:playing() then
self._repetitions_left = self._repetitions_left - 1
self._animation_started = false
end
end
end
function add_mt.__index:play()
for _, animation in ipairs(self._animations) do
animation:play()
end
end
function add_mt.__index:playing()
for _, animation in ipairs(self._animations) do
if animation:playing() then
return true
end
end
end
function add_mt.__index:stop()
for _, animation in ipairs(self._animations) do
animation:stop()
end
end
function concat_mt.__index:play()
self._index = 1
end
function concat_mt.__index:playing()
return self._index ~= nil
end
function concat_mt.__index:stop()
if self._index and self._animations[self._index] then
self._animations[self._index]:stop()
end
self._index = nil
end
function concat_mt.__index:_on_update()
if self._index then
if not self._animations[self._index] then
self._index = nil
elseif not self._animation_started then
self._animations[self._index]:play()
self._animation_started = true
elseif not self._animations[self._index]:playing() then
self._index = self._index + 1
self._animation_started = false
end
end
end
function animation_mt.__index:play()
self._t0 = GetTime()
self._original_values = { self._getter() }
end
function animation_mt.__index:stop()
self._t0 = nil
end
function animation_mt.__index:playing()
return self._t0 ~= nil
end
function animation_mt.__index:_current_changes(factor)
local values = {}
for i, change in ipairs(self._changes) do
tinsert(values, self._original_values[i] + change * factor)
end
return unpack(values)
end
function animation_mt.__index:_on_update(factor)
if self._t0 then
local progress = GetTime() - self._t0
if progress >= self._duration then
self._callback(self:_current_changes(1))
self._t0 = nil
else
self._callback(self:_current_changes(progress / self._duration))
end
end
end
function npcscan.animation(changes, duration, getter, callback)
local self = {
_frame = CreateFrame('Frame'),
_changes = changes,
_duration = duration,
_getter = getter,
_callback = callback,
}
setmetatable(self, animation_mt)
self._frame:SetScript('OnUpdate', function()
self:_on_update()
end)
return self
end
end
-- building the frame structure