#include "driver_derby_base.lua"

-- ===================================
IS_TICK		= true

function init()
	PostInit()
	ChangeState(DRIVER_STATES.wait)

	RegisterListenerTo(EVENTS.COUNTDOWN_OVER, "OnRaceStart")
	RegisterListenerTo(EVENTS.VEHICLE_SCORE, "CheckIfHitTarget")
	RegisterListenerTo(EVENTS.PLAYER_HUNT, "SetHuntToPlayer")
	RegisterListenerTo(EVENTS.STATS_FILLED, "StatsFilled")
	random_ram_timer = math.random(6,20)
end

function update(dt)
	timer_manager:Tick(dt)

	if current_state == DRIVER_STATES.wait or current_state == DRIVER_STATES.dead or not IS_TICK then 
		return
	end

	vehicle:Tick(dt)
	if is_hunter and GetInt("level.playerhunt") ~= vehicle.id then
		is_hunter = false
	end
	TIME_TO_RESPAWN = TIME_TO_RESPAWN - dt

	if current_state == DRIVER_STATES.wreck then
		if tickStates(dt) then return end

		target:Tick(dt)
		if not is_hunter then
			timer_before_move_to = timer_before_move_to - dt
			timer_to_next_target = timer_to_next_target - dt
			NextTarget()
		end
		IsTargetDead()		-- Change target if current is dead
		if IsCanAvoid() then return end

		local forward_blocked, dist, normal, shape = CheckForwardBlocks(true)
		if forward_blocked then
			StartGadget()
			if time_to_taran > MAX_TIME_TO_TARAN then
				ChangeState(DRIVER_STATES.departure)
				time_to_taran = 0.0
				return
			end
			time_to_taran = time_to_taran + dt
		end

		SetVehicleControls(PRESSING_ON_GAS, 0, target.preemption_pos)

	elseif current_state == DRIVER_STATES.move_to then
		if tickStates(dt) then return end

		if IsCanAvoid() then return end
		SetVehicleControls(PRESSING_ON_GAS, 0, move_to_pos)

		if math:Near2Vec(vehicle.t.pos, move_to_pos, 15) then
			counter_of_move_to = counter_of_move_to + 1
			if counter_of_move_to >= current_max_counter then
				timer_before_move_to = TIME_BEFORE_MOVE_TO_LOC
				timer_to_next_target = -1
				NextTarget()
				ChangeState(DRIVER_STATES.wreck)
			else
				local next_id 	= move_to_index % #all_map_points + 1
				local prev_id 	= move_to_index == 1 and #all_map_points or move_to_index - 1
				local next_pos 	= all_map_points[next_id]
				local prev_pos 	= all_map_points[prev_id]
				if VecDot(vehicle.forward_vec, next_pos) >= VecDot(vehicle.forward_vec, prev_pos) then
					move_to_index 	= next_id
					move_to_pos 	= next_pos
				else
					move_to_index 	= prev_id
					move_to_pos 	= prev_pos
				end
			end
		end

	elseif current_state == DRIVER_STATES.move_back then
		if tickStates(dt) then return end

		FindDirectionToEscape(-1.0)
		time_to_move_back = time_to_move_back - dt
		if time_to_move_back < 0 then
			ChangeState(DRIVER_STATES.wreck)
		end

	elseif current_state == DRIVER_STATES.avoid then
		if tickStates(dt) then return end

		-- Try to avoid blocking if AI not smasher
		local forward_blocked, dist, normal, shape = CheckForwardBlocks(false)
		time_to_avoid = time_to_avoid + dt
		if time_to_avoid > MAX_TIME_TO_TRY_AVOID or not forward_blocked then
			ChangeState(DRIVER_STATES.wreck)
		end

	elseif current_state == DRIVER_STATES.departure then
		if tickStates(dt) then return end

		if ForwardDirIsClear() then
			ChangeState(DRIVER_STATES.wreck)
		end

		time_to_departure = time_to_departure + dt
		FindDirectionToEscape(-1.0)
		if time_to_departure > MAX_TIME_BEFORE_STUCK then
			ChangeState(DRIVER_STATES.stuck)
		end

	elseif current_state == DRIVER_STATES.stuck then
		if vehicle:GetVehicleVelocity() > 20.0 then
			ChangeState(DRIVER_STATES.wreck)
		end

		if current_try > MAX_TRIES_TO_ESCAPE then
			NeedRespawn()
			return
		end

		if time_to_avoid < MAX_TIME_TO_TRY_ESCAPE then
			time_to_avoid = time_to_avoid + dt
		else
			current_try = current_try + 1
			NextDirByTry()
			time_to_avoid = 0.0
		end

	elseif current_state == DRIVER_STATES.return_to_bndr then
		if IsVehicleStuck(dt) then return end
		SetVehicleControls(PRESSING_ON_GAS, 0, move_to_pos)

		if IsVehicleInBoundary() then
			ChangeState(DRIVER_STATES.wreck)
		end
	end

	if GetVehicleHealth(vehicle.id) == 0 then
		ChangeState(DRIVER_STATES.dead)
	end
end

function tick()
    if current_state == DRIVER_STATES.dead or not IS_TICK then
        return
    end
	DriveAI()
end

-- ===================================
-- Timer, events and options functions
-- ===================================

function SetHuntToPlayer(handle)
	if tonumber(handle) == vehicle.id then
		is_hunter = true
		target.id = player_handle or GetPlayerVehicle()
		ChangeState(DRIVER_STATES.wreck)
	end
end

function DeleteAllListeners()
	UnregisterListener(EVENTS.COUNTDOWN_OVER, "OnRaceStart")
	UnregisterListener(EVENTS.VEHICLE_SCORE, "CheckIfHitTarget")
	UnregisterListener(EVENTS.PLAYER_HUNT, "SetHuntToPlayer")
	UnregisterListener(EVENTS.STATS_FILLED, "StatsFilled")
    UnregisterListener(EVENTS.VEHICLE_DESTROYED, "RemoveVehicleFromList")
end
