Quantcast
local AceGUI = LibStub('AceGUI-3.0');
local lsm = LibStub('AceGUISharedMediaWidgets-1.0');
local media = LibStub('LibSharedMedia-3.0');

MaxDps = LibStub('AceAddon-3.0'):NewAddon('MaxDps', 'AceConsole-3.0', 'AceEvent-3.0', 'AceTimer-3.0');

MaxDps.Textures = {
	['Ping'] = 'Interface\\Cooldown\\ping4',
	['Star'] = 'Interface\\Cooldown\\star4',
	['Starburst'] = 'Interface\\Cooldown\\starburst',
};
MaxDps.FinalTexture = nil;

MaxDps.Colors = {
	Info = '|cFF1394CC',
	Error = '|cFFF0563D',
	Success = '|cFFBCCF02',
}

MaxDps.Classes = {
	[1] = 'Warrior',
	[2] = 'Paladin',
	[3] = 'Hunter',
	[4] = 'Rogue',
	[5] = 'Priest',
	[6] = 'DeathKnight',
	[7] = 'Shaman',
	[8] = 'Mage',
	[9] = 'Warlock',
	[10] = 'Monk',
	[11] = 'Druid',
	[12] = 'DemonHunter',
}

local defaultOptions = {
	global = {
		enabled = true,
		disabledInfo = false,
		debugMode = false,
		disableButtonGlow = false,
		onCombatEnter = true,
		texture = '',
		customTexture = '',
		highlightColor = {
			r = 1, g = 1, b = 1, a = 1
		},
		interval = 0.15
	}
}

local options = {
	type = 'group',
	name = 'MaxDps Options',
	inline = false,
	args = {
		enable = {
			name = 'Enable',
			desc = 'Enables / disables the addon',
			type = 'toggle',
			width = 'full',
			set = function(info, val)
				MaxDps.db.global.enabled = val;
			end,
			get = function(info) return MaxDps.db.global.enabled end
		},
		disabledInfo = {
			name = 'Disable info messages',
			desc = 'Enables / disables info messages, if you have issues with addon, make sure to deselect this.',
			type = 'toggle',
			width = 'full',
			set = function(info, val)
				MaxDps.db.global.disabledInfo = val;
			end,
			get = function(info) return MaxDps.db.global.disabledInfo end
		},
		debugMode = {
			name = 'Enable debug mode',
			desc = 'Enables spammy chat messages (use this when addon does not work for you)',
			type = 'toggle',
			width = 'full',
			set = function(info, val)
				MaxDps.db.global.debugMode = val;
			end,
			get = function(info) return MaxDps.db.global.debugMode end
		},
		disableButtonGlow = {
			name = 'Dissable blizzard button glow (experimental)',
			desc = 'Disables original blizzard button glow',
			type = 'toggle',
			width = 'full',
			set = function(info, val)
				MaxDps.db.global.disableButtonGlow = val;
				MaxDps:UpdateButtonGlow();
			end,
			get = function(info) return MaxDps.db.global.disableButtonGlow end
		},
		onCombatEnter = {
			name = 'Enable upon entering combat',
			desc = 'Automatically enables helper upon entering combat',
			type = 'toggle',
			width = 'full',
			set = function(info, val)
				MaxDps.db.global.onCombatEnter = val;
			end,
			get = function(info) return MaxDps.db.global.onCombatEnter end
		},
		customTexture = {
			name = 'Custom Texture',
			desc = 'Sets Highlight texture, has priority over selected one (changing this requires UI Reload)',
			type = 'input',
			set = function(info, val) MaxDps.db.global.customTexture = strtrim(val or ''); end,
			get = function(info) return strtrim(MaxDps.db.global.customTexture or '') end
		},
		texture = {
			type = 'select',
			dialogControl = 'LSM30_Background',
			name = 'Texture',
			desc = 'Sets Highlight texture (changing this requires UI Reload)',
			values = function()
				return MaxDps.Textures;
			end,
			get = function()
				return MaxDps.db.global.texture;
			end,
			set = function(self, val)
				MaxDps.db.global.texture = val;
			end,
		},
		highlightColor = {
			name = 'Highlight color',
			desc = 'Sets Highlight color',
			type = 'color',
			set = function(info, r, g, b, a)
				MaxDps.db.global.highlightColor.r = r;
				MaxDps.db.global.highlightColor.g = g;
				MaxDps.db.global.highlightColor.b = b;
				MaxDps.db.global.highlightColor.a = a;
			end,
			get = function(info)
				return MaxDps.db.global.highlightColor.r, MaxDps.db.global.highlightColor.g, MaxDps.db.global.highlightColor.b, MaxDps.db.global.highlightColor.a;
			end,
			hasAlpha = true
		},
		interval = {
			name = 'Interval in seconds',
			desc = 'Sets how frequent rotation updates will be. Low value will result in fps drops.',
			type = 'range',
			min = 0.01,
			max = 2,
			set = function(info,val) MaxDps.db.global.interval = val end,
			get = function(info) return MaxDps.db.global.interval end
		},
		sizeMult = {
			name = 'Overlay size multiplier',
			desc = 'Sets how big will be overlay on the button. 1 = exactly the same as button',
			type = 'range',
			min = 0.5,
			max = 2,
			set = function(info,val) MaxDps.db.global.sizeMult = val end,
			get = function(info) return MaxDps.db.global.sizeMult or 1.4 end
		},
	},
}

function MaxDps:GetTexture()
	if self.db.global.customTexture ~= '' and self.db.global.customTexture ~= nil then
		self.FinalTexture = self.db.global.customTexture;
		return self.FinalTexture;
	end

	self.FinalTexture = self.Textures[self.db.global.texture];
	if self.FinalTexture == '' or self.FinalTexture == nil then
		self.FinalTexture = 'Interface\\Cooldown\\ping4';
	end

	return self.FinalTexture;
end

function MaxDps:OnInitialize()
	LibStub('AceConfig-3.0'):RegisterOptionsTable('MaxDps', options, {'/maxdps'});
	self.db = LibStub('AceDB-3.0'):New('MaxDpsOptions', defaultOptions);
	self.optionsFrame = LibStub('AceConfigDialog-3.0'):AddToBlizOptions('MaxDps', 'MaxDps');
	self:RegisterChatCommand('maxdps', 'ShowCustomWindow');

	if not self.db.global.customRotations then
		self.db.global.customRotations = {};
	end
end

MaxDps.DefaultPrint = MaxDps.Print;
function MaxDps:Print(...)
	if self.db.global.disabledInfo then
		return;
	end
	MaxDps:DefaultPrint(...);
end

function MaxDps:EnableRotation()
	self:Print(self.Colors.Info .. 'Enabling');

	if self.NextSpell == nil or self.rotationEnabled then
		self:Print(self.Colors.Error .. 'Failed to enable addon!');
		return;
	end
	self:Print(self.Colors.Info .. 'Fetching');
	self.Fetch();

	MaxDps:CheckTalents();
	if self.ModuleOnEnable then
		self.ModuleOnEnable();
	end

	self:EnableRotationTimer();

	self.rotationEnabled = true;
	self:Print(self.Colors.Success .. 'Enabled');
end

function MaxDps:EnableRotationTimer()
	self.RotationTimer = self:ScheduleRepeatingTimer('InvokeNextSpell', self.db.global.interval);
end

function MaxDps:DisableRotation()
	if not self.rotationEnabled then
		return;
	end

	self:DisableRotationTimer();

	self:DestroyAllOverlays();
	self:Print(self.Colors.Info .. 'Disabling');

	self.Spell = nil;
	self.rotationEnabled = false;
end

function MaxDps:DisableRotationTimer()
	if self.RotationTimer then
		self:CancelTimer(self.RotationTimer);
	end
end

function MaxDps:OnEnable()
	self:RegisterEvent('PLAYER_TARGET_CHANGED');
	self:RegisterEvent('PLAYER_TALENT_UPDATE');
	self:RegisterEvent('ACTIONBAR_SLOT_CHANGED');
	self:RegisterEvent('PLAYER_REGEN_DISABLED');
	self:RegisterEvent('PLAYER_ENTERING_WORLD');

	self:RegisterEvent('ACTIONBAR_HIDEGRID');
	self:RegisterEvent('ACTIONBAR_PAGE_CHANGED');
	self:RegisterEvent('LEARNED_SPELL_IN_TAB');
	self:RegisterEvent('CHARACTER_POINTS_CHANGED');
	self:RegisterEvent('ACTIVE_TALENT_GROUP_CHANGED');
	self:RegisterEvent('PLAYER_SPECIALIZATION_CHANGED');
	self:RegisterEvent('UPDATE_MACROS');
	self:RegisterEvent('VEHICLE_UPDATE');

	self:RegisterEvent('UNIT_ENTERED_VEHICLE');
	self:RegisterEvent('UNIT_EXITED_VEHICLE');
	--	self:RegisterEvent('PLAYER_REGEN_ENABLED');

	self:Print(self.Colors.Info .. 'Initialized');
end

function MaxDps:PLAYER_TALENT_UPDATE()
	self:DisableRotation();
end

function MaxDps:UNIT_ENTERED_VEHICLE(event, unit)
	if unit == 'player' and self.rotationEnabled then
		self:DisableRotation();
	end
end

function MaxDps:UNIT_EXITED_VEHICLE(event, unit)
	if unit == 'player' then
		self:InitRotations();
		self:EnableRotation();
	end
end

function MaxDps:PLAYER_ENTERING_WORLD()
	self:UpdateButtonGlow();
end

function MaxDps:PLAYER_TARGET_CHANGED()
	if self.rotationEnabled then
		if (UnitIsFriend('player', 'target')) then
			return;
		else
			self:InvokeNextSpell();
		end
	end
end

function MaxDps:PLAYER_REGEN_DISABLED()
	if self.db.global.onCombatEnter and not self.rotationEnabled then
		self:Print(self.Colors.Success .. 'Auto enable on combat!');
		self:InitRotations();
		self:EnableRotation();
	end
end

function MaxDps:ButtonFetch()
	if self.rotationEnabled then
		if self.fetchTimer then
			self:CancelTimer(self.fetchTimer);
		end
		self.fetchTimer = self:ScheduleTimer('Fetch', 0.5);
	end
end

MaxDps.ACTIONBAR_SLOT_CHANGED = MaxDps.ButtonFetch;
MaxDps.ACTIONBAR_HIDEGRID = MaxDps.ButtonFetch;
MaxDps.ACTIONBAR_PAGE_CHANGED = MaxDps.ButtonFetch;
MaxDps.LEARNED_SPELL_IN_TAB = MaxDps.ButtonFetch;
MaxDps.CHARACTER_POINTS_CHANGED = MaxDps.ButtonFetch;
MaxDps.ACTIVE_TALENT_GROUP_CHANGED = MaxDps.ButtonFetch;
MaxDps.PLAYER_SPECIALIZATION_CHANGED = MaxDps.ButtonFetch;
MaxDps.UPDATE_MACROS = MaxDps.ButtonFetch;
MaxDps.VEHICLE_UPDATE = MaxDps.ButtonFetch;

function MaxDps:InvokeNextSpell()
	-- invoke spell check
	local oldSkill = self.Spell;

	local timeShift, currentSpell, gcd = MaxDps:EndCast();
	self.Spell = self:NextSpell(timeShift, currentSpell, gcd, self.PlayerTalents);

	if (oldSkill ~= self.Spell or oldSkill == nil) and self.Spell ~= nil then
		self:GlowNextSpellId(self.Spell);
		if WeakAuras then
			WeakAuras.ScanEvents('MAXDPS_SPELL_UPDATE', self.Spell);
		end
	end
	if self.Spell == nil and oldSkill ~= nil then
		self:GlowClear();
		if WeakAuras then
			WeakAuras.ScanEvents('MAXDPS_SPELL_UPDATE', nil);
		end
	end
end

function MaxDps:InitRotations()
	self:Print(self.Colors.Info .. 'Initializing rotations');

	local _, _, classId = UnitClass('player');
	local spec = GetSpecialization();
	self.ClassId = classId;
	self.Spec = spec;

	self:LoadCustomRotations();
	if self.CustomRotations[classId] and self.CustomRotations[classId][spec] then
		self.CurrentRotation = self.CustomRotations[classId][spec];
		self.NextSpell = self.CurrentRotation.fn;
		self:Print(self.Colors.Success .. 'Loaded Custom Rotation: ' .. self.CurrentRotation.name);
	else
		self:LoadModule();
	end
end

function MaxDps:LoadModule()
	if self.Classes[self.ClassId] == nil then
		self:Print(self.Colors.Error .. 'Invalid player class, please contact author of addon.');
		return;
	end

	local module = 'MaxDps_' .. self.Classes[self.ClassId];
	local _, _, _, loadable, reason = GetAddOnInfo(module);

	if IsAddOnLoaded(module) then
		self:Print(self.Colors.Info .. self.Description);
		self:EnableRotationModule(self.Spec);
		self:Print(self.Colors.Info .. 'Finished Loading class module');
		return;
	end

	if reason == 'MISSING' or reason == 'DISABLED' then
		self:Print(self.Colors.Error .. 'Could not find class module ' .. module .. ' or it was disabled.');
		return;
	end

	LoadAddOn(module);

	self:EnableRotationModule(self.Spec);
	self:Print(self.Colors.Info .. self.Description);
	self:Print(self.Colors.Info .. 'Finished Loading class module');
end