Quantcast
--[[--------------------------------------------------------------------
	Copyright (C) 2006-2007 Nymbia

	This program is free software; you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation; either version 2 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License along
	with this program; if not, write to the Free Software Foundation, Inc.,
	51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

	Modified for Ovale.

    Copyright (C) 2009, 2011, 2012 Sidoine
    Copyright (C) 2012, 2013 Johnny C. Lam

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License in the LICENSE
    file accompanying this program.
--]]--------------------------------------------------------------------

local _, Ovale = ...
local OvaleSwing = Ovale:NewModule("OvaleSwing", "AceEvent-3.0")
Ovale.OvaleSwing = OvaleSwing

--<private-static-properties>
local math_abs = math.abs
local unpack = unpack
local API_GetSpellInfo = GetSpellInfo
local API_GetTime = GetTime
local API_IsDualWielding = IsDualWielding
local API_UnitAttackSpeed = UnitAttackSpeed
local API_UnitGUID = UnitGUID
local API_UnitRangedDamage = UnitRangedDamage
local BOOKTYPE_SPELL = BOOKTYPE_SPELL

-- Player's GUID.
local self_guid = nil

local OVALE_AUTOSHOT_NAME = API_GetSpellInfo(75)
local OVALE_RESET_SPELLS = {}
local OVALE_DELAY_SPELLS = {
	[API_GetSpellInfo(1464)] = true, -- Slam
}
local OVALE_RESET_AUTOSHOT_SPELLS = {}
--</private-static-properties>

--<public-static-properties>
OvaleSwing.ohNext = nil
OvaleSwing.dual = false
OvaleSwing.starttime = nil
OvaleSwing.duration = nil
OvaleSwing.ohStartTime = nil
OvaleSwing.ohDuration = nil
OvaleSwing.delay = nil
OvaleSwing.startdelay = nil
OvaleSwing.swingmode = nil
--</public-static-properties>

--<public-static-methods>
function OvaleSwing:OnEnable()
	self_guid = API_UnitGUID("player")
	self.ohNext = false
	-- fired when autoattack is enabled/disabled.
	self:RegisterEvent("PLAYER_ENTER_COMBAT")
	self:RegisterEvent("PLAYER_LEAVE_COMBAT")
	-- fired when autoshot (or autowand) is enabled/disabled
	self:RegisterEvent("START_AUTOREPEAT_SPELL")
	self:RegisterEvent("STOP_AUTOREPEAT_SPELL")

	self:RegisterEvent("COMBAT_LOG_EVENT_UNFILTERED")

	self:RegisterEvent("UNIT_SPELLCAST_START")
	self:RegisterEvent("UNIT_SPELLCAST_SUCCEEDED")
	self:RegisterEvent("UNIT_SPELLCAST_FAILED", "UNIT_SPELLCAST_INTERRUPTED")
	self:RegisterEvent("UNIT_SPELLCAST_INTERRUPTED")

	self:RegisterEvent("UNIT_ATTACK")
end

function OvaleSwing:OnDisable()
end

function OvaleSwing:PLAYER_ENTER_COMBAT()
	self.dual = API_IsDualWielding()
	--print("Enter combat")
end

function OvaleSwing:PLAYER_LEAVE_COMBAT()
	self.ohNext = false
	self.ohStartTime = nil
	self.ohDuration = nil
	self.duration = nil
	self.starttime = nil
	self.delay = 0
end

function OvaleSwing:START_AUTOREPEAT_SPELL()
end

function OvaleSwing:STOP_AUTOREPEAT_SPELL()
end

function OvaleSwing:COMBAT_LOG_EVENT_UNFILTERED(event, timestamp, eventName, srcGUID, srcName, srcFlags, dstName, dstGUID, dstFlags, ...)
	if srcGUID == self_guid then
		if eventName == "SWING_DAMAGE" or eventName == "SWING_MISSED" then
			local now = API_GetTime()
			self:MeleeSwing(now)
		end
	end
end

function OvaleSwing:UNIT_SPELLCAST_START(event, unit, spell)
	if OVALE_DELAY_SPELLS[spell] and unit=="player" then
		self.startdelay = API_GetTime()
		local name, rank, icon, cost, isFunnel, powerType, castTime, minRange, maxRange = API_GetSpellInfo(spell)
		self.delay = castTime
	end
end

function OvaleSwing:UNIT_SPELLCAST_INTERRUPTED(event, unit, spell)
	if unit == "player" and OVALE_DELAY_SPELLS[spell] and self.startdelay then
		local now = API_GetTime()
		self.delay = now - self.startdelay
	end
end

function OvaleSwing:UNIT_SPELLCAST_SUCCEEDED(event, unit, spell)
	if unit == "player" then
		local now = API_GetTime()
		if OVALE_RESET_SPELLS[spell] then
			self:MeleeSwing(now)
		end
		if OVALE_DELAY_SPELLS[spell] and self.startdelay then
			self.delay = now - self.startdelay
		end
		if spell == OVALE_AUTOSHOT_NAME then
			self:Shoot()
		end
		if OVALE_RESET_AUTOSHOT_SPELLS[spell] then
			self:Shoot()
		end
	end
end

function OvaleSwing:UNIT_ATTACK(event, unit)
	--[[if unit == 'player' then
		if not self.swingmode then
			return
		elseif self.swingmode == 0 then
			self.duration = API_UnitAttackSpeed('player')
		else
			self.duration = API_UnitRangedDamage('player')
		end
	end]]
end

function OvaleSwing:MeleeSwing(timestamp)
	if self.dual and self.ohNext then
		--[[if self.ohDuration then
			local prediction = self.ohDuration+self.ohStartTime+self.delay
			print("Prediction oh = "  .. prediction .. " diff=" .. (timestamp-prediction))
		end]]
		self.ohDuration = API_UnitAttackSpeed('player')
		self.ohStartTime = timestamp
		--print("MeleeSwing oh = " .. self.ohStartTime)
		self.ohNext = false
	else
		--[[if self.duration then
			local prediction = self.duration+self.starttime+self.delay
			print("Prediction mh = " .. prediction .. " diff=" .. (timestamp-prediction))
		end]]
		self.duration = API_UnitAttackSpeed('player')
		self.starttime = timestamp
		--print("MeleeSwing mh = " .. self.starttime)
		self.ohNext = true
		if self.ohStartTime == nil then
			self.ohStartTime = self.starttime - self.duration/2
			self.ohDuration = self.duration
		end
	end
	self.delay = 0
end

function OvaleSwing:Shoot()
	--[[if self.duration then
		print("Prediction = " ..(self.duration+self.starttime))
	end]]
	self.duration = API_UnitRangedDamage('player')
	self.starttime = API_GetTime()
	--print("Shoot " .. self.starttime)
end

function OvaleSwing:GetLast(which)
	if not self.duration then
		return nil
	end
	if which == "main" then
		return self.starttime
	elseif which == "off" then
		return self.ohStartTime
	else
		if self.dual and self.ohNext then
			return self.starttime
		else
			return self.ohStartTime
		end
	end
end

function OvaleSwing:GetNext(which)
	if not self.duration then
		return nil
	end
	if which == "main" then
		return self.duration + self.starttime + self.delay
	elseif which == "off" then
		return self.ohDuration + self.ohStartTime + self.delay
	else
		if self.dual and self.ohNext then
			return self.ohDuration + self.ohStartTime + self.delay
		else
			return self.duration + self.starttime + self.delay
		end
	end
end
--</public-static-methods>