local function move_towards_center() end
local function move_towards_crush_point() end
local function rotate_randomly() end
local function set_crush_point() end
local function go_towards() end

local T = fbrawl.T
local rock_particles = {
	{
		name = "fbrawl_dirt_particle_1.png",
		scale_tween = {{x = 1, y = 1}, {x = 0.5, y = 0.5}}
	},
	{
		name = "fbrawl_dirt_particle_2.png",
		scale_tween = {{x = 1, y = 1}, {x = 0.5, y = 0.5}}
	},
	{
		name = "fbrawl_dirt_particle_3.png",
		scale_tween = {{x = 1, y = 1}, {x = 0.5, y = 0.5}}
	},
	{
		name = "fbrawl_grass_particle_1.png",
		scale_tween = {{x = 1, y = 1}, {x = 0.5, y = 0.5}}
	},
	{
		name = "fbrawl_grass_particle_2.png",
		scale_tween = {{x = 1, y = 1}, {x = 0.5, y = 0.5}}
	},
	{
		name = "fbrawl_grass_particle_3.png",
		scale_tween = {{x = 1, y = 1}, {x = 0.5, y = 0.5}}
	},
	{
		name = "fbrawl_stone_particle.png",
		scale_tween = {{x = 1, y = 1}, {x = 0.5, y = 0.5}}
	},
}



skills.register_skill("fbrawl:gaia_fist", {
   name = T("Gaia's Fist"),
	icon = "fbrawl_gaia_fist.png",
	cooldown = 10.5,
	description = T("Throw a rock against the enemy and push them away!"),
   slot = 4,
   sounds = {
      cast = {name = "fbrawl_rock_rising", max_hear_distance = 46}
   },
	chat_warnings = {
		cooldown = false
	},
	get_rock_center = function(self)
		local look_dir = self.player:get_look_dir()
		local offset = {x = look_dir.x*3, y = 3.5, z = look_dir.z*3}
		self.data.rock_center = self.data.rock_center or vector.add(offset, self.player:get_pos())

		return self.data.rock_center
	end,
   cast = function(self)
		local look_dir = self.player:get_look_dir()
		local rock_pos = {x = look_dir.x*2, y = -2, z = look_dir.z*2}

		self.data.rock_center = nil

		minetest.add_entity(vector.add(rock_pos, self.player:get_pos()), "fantasy_brawl:rock", self.pl_name)
   end
})



-- The rock entity declaration.
local tex = "fbrawl_rock_entity.png"
local rock = {
   initial_properties = {
      hp_max = 999,
      physical = false,
      collide_with_objects = false,
      visual = "cube",
      visual_size = {x = 1, y = 1},
      textures = {tex,tex,tex,tex,tex,tex},
		automatic_face_movement_dir = false,
      range = 3,
      damage = 7.5,
		push_force = 20,
   },
	_speed = 7,
   _pl_name = "",
	_positioned = false,
	_crush_point = {},
	_time_passed = 0,
	_throw_speed_multiplier = 8
}



-- staticdata = player's username.
function rock:on_activate(staticdata, dtime_s)
   local obj = self.object

   if staticdata then
      self._pl_name = staticdata
      local player = minetest.get_player_by_name(self._pl_name)
		local skill = self._pl_name:get_skill("fbrawl:gaia_fist")

      if not player then
         obj:remove()
         return
      end

		if not set_crush_point(self) then return end

		go_towards(self, skill:get_rock_center(), self._speed)

		--fbrawl.camera_shake(self._pl_name, 10, 0.4)
   else
      obj:remove()
      return
   end

   minetest.add_particlespawner({
		amount = 80,
		time = 0,
		minpos = {x = -1, y = 1, z = -1},
		maxpos = {x = 1, y = -1, z = 1},
		minvel = {x = 0, y = -2, z = 0},
		maxvel = {x = 0, y = -4, z = 0},
		minsize = 1,
		maxsize = 3,
		texpool = rock_particles,
		collisiondetection = true,
		collision_removal = true,
		minexptime = 2,
		maxexptime = 3,
		attached = obj
  })
end



function rock:crush()
   local sound = {name = "fbrawl_rock_hit", pos = self.object:get_pos(), max_hear_distance = 46}

   minetest.sound_play(sound, sound, true)

	minetest.add_particlespawner({
		amount = 300,
		time = 0.5,
		pos = {
			min = vector.add(self.object:get_pos(), -1),
			max = vector.add(self.object:get_pos(), 1),
		},
		minvel = {x = -5,y = -3, z = -5},
		maxvel = {x = 5, y = 3, z = 5},
		minsize = 1,
		maxsize = 4,
		texpool = rock_particles,
		collisiondetection = true,
		collision_removal = true,
		minexptime = 0.5,
		maxexptime = 0.7,
	})

	--fbrawl.camera_shake(self._pl_name, 6, 0.4)

   self.object:remove()
end



function rock:on_step(dtime)
   local player = minetest.get_player_by_name(self._pl_name)
   local props = self.initial_properties

	if not player then
      self.object:remove()
      return
   end

	if not self._positioned then
		move_towards_center(self)
	else
		local is_arrived = move_towards_crush_point(self, dtime)
		local knockback = vector.normalize(self.object:get_velocity()) * props.push_force
		local hit = false

		fbrawl.damage_players_near(player, self.object:get_pos(), props.range, props.damage, knockback, function ()
			hit = true
		end)
		
		if hit then
			self:crush()
			return
		end

		if is_arrived or fbrawl.are_there_nodes_in_area(self.object:get_pos(), 1) then 		
			self:crush()
			return
		end
	end

	rotate_randomly(self, dtime)
end



minetest.register_entity("fantasy_brawl:rock", rock)



function move_towards_center(rock) 
	local skill = rock._pl_name:get_skill("fbrawl:gaia_fist")
	local obj = rock.object

	local is_positioned = vector.distance(obj:get_pos(), skill:get_rock_center()) <= 2

	if is_positioned then
		obj:set_velocity({x = 0, y = 0, z = 0})
		rock._positioned = true

		local sound = {name = "fbrawl_rock_thrown", pos = obj:get_pos(), max_hear_distance = 46}
		minetest.sound_play(sound, sound, true)
	else
		go_towards(rock, skill:get_rock_center(), rock._speed)
	end
end



function move_towards_crush_point(rock, dtime)
	local obj = rock.object
	local distance = vector.distance(obj:get_pos(), rock._crush_point)
	local is_arrived = distance <= 0.8

	if not is_arrived then
		rock._time_passed = rock._time_passed + dtime
		if rock._time_passed < 0.1 then return end

		if distance <= 3 then
			rock._throw_speed_multiplier = 0.7
		end
		
		go_towards(rock, rock._crush_point, rock._speed * rock._throw_speed_multiplier)
	else
		return "is_arrived"
	end
end



function rotate_randomly(rock, dtime)
	local random_speed = PseudoRandom(minetest.get_us_time()):next(10, 15) / 10
	rock._rot_speed = rock._rot_speed or random_speed * dtime

	rock.object:set_rotation(vector.add(rock.object:get_rotation(), rock._rot_speed))
end



function set_crush_point(rock)
	local player = minetest.get_player_by_name(rock._pl_name)
	local pl_pos = vector.add(player:get_pos(), {x=0, y=1, z=0})

	local ray = fbrawl.look_raycast(player, 200)
	local crush_point = ray:next() or {}
	rock._crush_point = crush_point.above
	
	if not rock._crush_point then
		rock.object:remove()
		return false
	end

	return true
end



function go_towards(rock, pos, speed)
	local dir = vector.direction(rock.object:get_pos(), pos)

	rock.object:set_velocity({
		x=(dir.x * speed),
		y=(dir.y * speed),
		z=(dir.z * speed),
	})
end