dofile("Scripts/utils.lua");
dofile("Scripts/Init/armor.lua");
dofile("Scripts/Init/soldier.lua");

function OnUnload()
	loaded2unit = false;
	ResetIdle();
end

function Main()
	AIparts:Run();
	if unit.GetGroupName() then
		AIparts:AddPeriodic("GroupExchange", group_exchange_timeout, GroupExchange);
	end
end

function CheckDirectDamage(WeaponDamage, Caliber, Point, Distance, ZoneId)
	local damage = Wound(WeaponDamage, Distance);
	CheckDamage(damage * stand_mode.damage_multiplier, Point);
end

function CheckSplashDamageZones(DetonationDamage, Caliber, Zones)
	local damage = 0;
	local point;
	for k,v in pairs(Zones) do
		damage = damage + v.DistanceFactor * 100;
		point = v.Point;
	end
	damage = math.floor(damage / 3);
	CheckDamage(damage, point);
end

function CheckCollision(Object)
	if soldier.IsInTrench() then return end;
-- ignore same player
	local pid1, pid2 = object.GetPlayerId(), object.GetPlayerId(Object);
	if pid1 == pid2 then return end;

	local class = object.GetObjectClass(Object);
	if class == "Tank" or class == "Vehicle" then
		local pos = object.GetPosition();
		CreateObject("Effects/Misc/blood.dsc", pos, object.GetAngle()); 
		PlaySound("human_squash", pos);
		object.SetHealth(0);
		Die();
	end
end

function SetSoldierBehaviour(Behaviour)
	player_move_mode = Behaviour;
	ResetIdle();
--	SetStandMode(Behaviour);
end

function Die()
	ClearGrenadeEvent();
	object.Die();
end

function EventMan()
	ClearGrenadeEvent();
end

function Regen()
	local health = object.GetHealth() + regen_health;
	if health > object.desc.Health then health = object.desc.Health end;
	object.SetHealth(health);
	if health >= blood_line then bleeding = nil end;
end

function Bleed()
	if bleeding then
		if object.IsFlag(object.FlagVisibleByCamera) and not unit.IsStopped() then
			CreateObject("Effects/Misc/blood_on_earth.dsc", GetTerrainPoint(object.GetPosition()));
		end
		AddBleeding();
	end
end

function MoveMan()
	if GetGameTime() < (last_wound_time + wound_recovery_time) then return end;
	SetStandMode(player_move_mode);
end
--[=[
function MoveMan()
	if unconscious then
		if GetGameTime() < (last_wound_time + wound_recovery_time) then return end;
		soldier.SetUnconsciousState(false);
		unconscious = false;
		SetStandMode(unit.Crouch);
	else
		if GetGameTime() < (last_wound_time + wound_recovery_time) then return end;
		SetStandMode(player_move_mode);
	end
	-- changing move mode according to MAI action
--[[
	if object.RandomHalf(100) < crouch_chance[mai_action] then SetStandMode(unit.Crouch);
	else SetStandMode(unit.Stand);
	end
--]]
end
--]=]

function AddBleeding()
	local onetime_name = "Bleed" .. GetGameEpoch();
	AIparts:AddOneTime(onetime_name, bleed_interval + object.RandomInt(bleed_interval), Bleed);
end

function CheckUnderAttack(Damage)
	-- shout "under attack"
	last_wound_time = GetGameTime();
	if stand_modes.active ~= unit.Prone then
		if Damage > damage_step * 3 then
			SetStandMode(unit.Prone);
--[[
			unconscious = true;
			soldier.SetUnconsciousState(true);
--]]
		elseif Damage > damage_step * 2 then
			SetStandMode(unit.Prone);
		elseif Damage > damage_step then
			SetStandMode(unit.Crouch);
		end
	end
end

function CheckDamage(Damage, Point)
	local health = object.GetHealth() - Damage;
	if health < 0 then health = 0 end
	object.SetHealth(health);
	if health <= 0 then
		if Point and object.IsFlag(object.FlagVisibleByCamera) then
			CreateObject("Effects/Misc/blood.dsc", Point, object.GetAngle());
		end
		Die();
	else
--[[
		if health < blood_line then
			bleeding = true;
			AddBleeding();
		end
--]]
		CheckUnderAttack(Damage);
	end
end

function SetStandMode(Mode)
	if stand_modes.active == Mode then return end;
	soldier.SetMovementMode(Mode);
	stand_modes.active = Mode;
	stand_mode = stand_modes[Mode];
end

function SetGrenadeEvent(TargetId)
	local event_name = "grenade_target_" .. TargetId;
	SetEvent(event_name, object.GetObjectId());
	micro_ai.last_target_event = event_name;
end

function CheckGrenadeEvent(TargetId)
	local event_name = "grenade_target_" .. TargetId;
	return IsEventPresent(event_name);
end

function ClearGrenadeEvent()
	local event_name = micro_ai.last_target_event;
	if event_name then
		-- clearing grenade target protection (target can be now attacked again)
		ClearEvent(event_name);
		micro_ai.last_target_event = nil;
	end
end

do
	local a = object.desc.Armament.Guns;
	local g;
	g = a[0];
	if g then
		micro_ai.deadzone1 = g.DirectDeadZone;
		micro_ai.range1 = g.DirectMaxRadius;
	end
	g = a[1];
	if g then
		micro_ai.deadzone2 = g.BallisticDeadZone;
		micro_ai.range2 = g.BallisticMaxRadius;
	end
end

--[[
micro_ai.UnitInit = micro_ai.Init;
micro_ai.Init = function(self)
	self:UnitInit();
	if self.check_fire then
		self.weapon = nil;
		self.check1 = unit.GetAmmo1() > 0 and unit.IsGunIdle(0);
		self.check2 = unit.GetAmmo2() > 0 and unit.IsGunIdle(1);
	end
end

micro_ai.CheckMove = function(self, target, target_class)
end

micro_ai.CheckFire = function(self, target, target_class)
	local target_id = object.GetObjectId(target);
	local target_distance = unit.GetTargetDistance(target);
	
	if (target_distance > object.desc.AlarmRange) then return end;
	
	local target_angle = unit.GetAimAngle(target);
	local prev_target = 1;
	if target_id == self.prev_target then prev_target = 0.5 end;
	local value, secondary_weapon;
	if self.check1 and target_distance < self.range1 and target_class == "Soldier" then
		value = prev_target * soldier_for_soldier * target_distance * (1 - target_angle * 0.25);
	end
	if self.check2 and target_distance > self.deadzone2 and target_distance < self.range2 then
		if not CheckGrenadeEvent(target_id) then
			local v;
			if target_class == "Tank" then
				v = prev_target * tank_for_soldier * target_distance * (1 - target_angle * 0.125);
			elseif target_class == "Vehicle" then
				v = prev_target * tank_for_soldier * target_distance * (1 - target_angle * 0.125);
			elseif target_class == "Gun" then
				v = prev_target * gun_for_soldier * target_distance * (1 - target_angle * 0.125);
			end
			if v and (not value or (v < value)) then
				value = v;
				secondary_weapon = true;
			end
		end
	end

	if value and (not self.fire_value or (value < self.fire_value)) then
		self.fire_target = target;
		self.fire_value = value;
		self.weapon = secondary_weapon;
	end
end

micro_ai.DoMove = function(self)
	if self.fire_target or not self.move_target then return end;
end

micro_ai.DoFire = function(self)
	if not self.fire_target then return end;
	local target_id = object.GetObjectId(self.fire_target);
	if self.weapon then
		SetGrenadeEvent(target_id);
	end
	unit.AttackObject(self.fire_target);
	self.prev_target = target_id;
end
--]]

micro_ai.CheckIdle = function(self)
	local busy = false;
	for _,_ in pairs(self.enemies) do busy = true end;
	if busy then
		ResetIdle();
	end
end

function MicroAI()
	micro_ai:Run();
end

function ResetIdle()
	SetStandMode(player_move_mode);
	local idle_counter = object.RandomInt(idle_timeout);
	AIparts:UpdatePeriodic("Idle", idle_counter);
end

function Idle()
	local stopped = unit.IsStopped();
	if soldier.IsInTrench() or not stopped or stand_modes.active == unit.Prone then return end;
	if stand_modes.active == unit.Stand then
		SetStandMode(unit.Crouch);
	else
		SetStandMode(unit.Stand);
		local old_position = object.GetPosition();
		local new_position = unit.GetRandomWaypoint(old_position, 5);
		if new_position then
			unit.MoveTo(new_position);
			unit.AppendWaypoint(old_position);
		end
	end
end

function GroupExchange()
--	log("GroupExchange");
end

function Debug()
	object.Debug();
end
