-- Skirmisher, a class for Tales of Maj'Eyal 1.1.5
--
-- 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 3 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, see <http://www.gnu.org/licenses/>.

local sling_equipped = function(self, silent)
	if not self:hasArcheryWeapon("sling") then
		if not silent then
			game.logPlayer(self, "You must wield a sling!")
		end
		return false
	end
	return true
end

-- Currently just a copy of Sling Mastery.
newTalent {
	short_name = "SKIRMISHER_SLING_SUPREMACY",
	name = "Sling Supremacy",
	image = "talents/sling_mastery.png",
	type = {"technique/skirmisher-slings", 1},
	points = 5,
	require = { stat = { dex=function(level) return 12 + level * 6 end }, },
	mode = "passive",
	getDamage = function(self, t) return self:getTalentLevel(t) * 10 end,
	getPercentInc = function(self, t) return math.sqrt(self:getTalentLevel(t) / 5) / 2 end,
	ammo_mastery_reload = function(self, t)
		return math.floor(self:combatTalentScale(t, 0, 2.7, "log"))
	end,
	passives = function(self, t, p)
		self:talentTemporaryValue(p, 'ammo_mastery_reload', t.ammo_mastery_reload(self, t))
	end,
	info = function(self, t)
		local damage = t.getDamage(self, t)
		local inc = t.getPercentInc(self, t)
		local reloads = t.ammo_mastery_reload(self, t)
		return ([[Increases Physical Power by %d and increases weapon damage by %d%% when using slings.
		Also, increases your reload rate by %d.]]):format(damage, inc * 100, reloads)
	end,
}

newTalent {
	short_name = "SKIRMISHER_SWIFT_SHOT",
	name = "Swift Shot",
	type = {"technique/skirmisher-slings", 2},
	require = techs_dex_req2,
	points = 5,
	no_energy = "fake",
	random_ego = "attack",
	tactical = {ATTACK = {weapon = 2}},
	range = archery_range,
	cooldown = 5,
	stamina = 15,
	on_pre_use = function(self, t, silent) return sling_equipped(self, silent) end,
	getDamage = function(self, t)
		return self:combatTalentWeaponDamage(t, 0.4, 1.6)
	end,
	callbackOnMove = function(self, t, moved, force, ox, oy)
		local cooldown = self.talents_cd[t.id] or 0
		if cooldown > 0 then
			self.talents_cd[t.id] = math.max(cooldown - 1, 0)
		end
	end,
	action = function(self, t)
		local old_speed = self.combat_physspeed
		self.combat_physspeed = old_speed * 2

		local targets = self:archeryAcquireTargets(nil, {one_shot=true})
		if not targets then
			self.combat_physspeed = old_speed
			return
		end

		self:archeryShoot(targets, t, nil, {mult=t.getDamage(self, t)})

		-- Cooldown Hurricane Shot by 1.
		local hurricane_cd = self.talents_cd["T_SKIRMISHER_HURRICANE_SHOT"]
		if hurricane_cd then
			self.talents_cd["T_SKIRMISHER_HURRICANE_SHOT"] = math.max(0, hurricane_cd - 1)
		end

		self.combat_physspeed = old_speed
		return true
	end,
	info = function(self, t)
		return ([[Fire off a quick sling bullet for %d%% damage, at double your normal attack speed. Moving lowers the cooldown by 1.]])
			:format(t.getDamage(self, t) * 100)
	end,
}

newTalent {
	short_name = "SKIRMISHER_HURRICANE_SHOT",
	name = "Hurricane Shot",
	type = {"technique/skirmisher-slings", 3},
	require = techs_dex_req3,
	points = 5,
	no_energy = "fake",
	random_ego = "attack",
	tactical = {ATTACKALL = {weapon = 3}},
	range = 0,
	radius = archery_range,
	cooldown = 7,
	stamina = 45,
	target = function(self, t)
		return {
			type = "cone",
			range = self:getTalentRange(t),
			radius = self:getTalentRadius(t),
			selffire = false,
			talent = t,
			--cone_angle = 50, -- degrees
		}
	end,
	on_pre_use = function(self, t, silent) return sling_equipped(self, silent) end,
	damage_multiplier = function(self, t)
		return self:combatTalentWeaponDamage(t, 0.2, 0.8)
	end,
	-- Maximum number of shots fired.
	limit_shots = function(self, t)
		return math.floor(self:combatTalentScale(t, 6, 11, "log"))
	end,
	action = function(self, t)
		-- Get list of possible targets, possibly doubled.
		local double = self:getTalentLevel(t) >= 3
		local tg = self:getTalentTarget(t)
		local x, y = self:getTarget(tg)
		if not x or not y then return end
		local targets = {}
		local add_target = function(x, y)
			local target = game.level.map(x, y, game.level.map.ACTOR)
			if target and self:reactionToward(target) < 0 and self:canSee(target) then
				targets[#targets + 1] = target
				if double then targets[#targets + 1] = target end
			end
		end
		self:project(tg, x, y, add_target)
		if #targets == 0 then return end

		table.shuffle(targets)

		-- Fire each shot individually.
		local old_target_forced = game.target.forced
		local limit_shots = t.limit_shots(self, t)
		local shot_params_base = {mult = t.damage_multiplier(self, t), phasing = true}
		local fired = nil -- If we've fired at least one shot.
		for i = 1, math.min(limit_shots, #targets) do
			local target = targets[i]
			game.target.forced = {target.x, target.y, target}
			local targets = self:archeryAcquireTargets({type = "hit", speed = 200}, {one_shot=true, no_energy = fired})
			if targets then
				local params = table.clone(shot_params_base)
				local target = targets.dual and targets.main[1] or targets[1]
				params.phase_target = game.level.map(target.x, target.y, game.level.map.ACTOR)
				self:archeryShoot(targets, t, {type = "hit", speed = 200}, params)
				fired = true
			else
				-- If no target that means we're out of ammo.
				break
			end
		end

		game.target.forced = old_target_forced
		return fired
	end,
	info = function(self, t)
		return ([[Take aim and unload up to %d shots for %d%% weapon damage each against random enemies inside a cone. Each enemy can only be hit once (twice for talent level 3 and higher). Using Swift Shot lowers the cooldown by 1.]])
			:format(t.limit_shots(self, t),
							t.damage_multiplier(self, t) * 100)
	end,
}

-- The cost on this is extreme because its a completely ridiculous talent
-- We don't have any other talents like this, really, that are incredibly hard to use for much of anything until late.  Should be interesting.
newTalent {
	short_name = "SKIRMISHER_BOMBARDMENT",
	name = "Bombardment",
	type = {"technique/skirmisher-slings", 4},
	require = techs_dex_req4,
	points = 5,
	mode = "sustained",
	no_energy = true,
	tactical = { BUFF = 2 },
	on_pre_use = function(self, t, silent) return sling_equipped(self, silent) end,
	cooldown = function(self, t)
		return 10
	end,
	bullet_count = function(self, t)
		return 3
	end,
	shot_stamina = function(self, t)
		return 25 * (1 + self:combatFatigue() * 0.01)
	end,
	damage_multiplier = function(self, t)
		return self:combatTalentWeaponDamage(t, 0.1, 0.6)
	end,
	activate = function(self, t) return {} end,
	deactivate = function(self, t, p) return true end,
	info = function(self, t)
		return ([[While activated, your basic Shot talent now fires %d sling bullets, each dealing %d%% Ranged damage, at a cost of %d Stamina per attack.]])
		:format(t.bullet_count(self, t), t.damage_multiplier(self, t) * 100, t.shot_stamina(self, t))
	end,
}