function aom_muskets.get_eyepos(player)
    local eyepos = vector.add(player:get_pos(), vector.multiply(player:get_eye_offset(), 0.1))
    eyepos.y = eyepos.y + player:get_properties().eye_height
    return eyepos
end

function aom_muskets.do_particles(pos, n)
    local va = 0.2
    local vv = 3
    local vl = 5
    n = n or 10
    for i = 1, n do
        minetest.add_particle({
            pos = vector.offset(pos, (math.random() * va)-va/2, (math.random() * va)-va/2, (math.random() * va)-va/2),
            velocity = vector.new(((math.random()-0.5)*vl)^vv,((math.random()-0.5)*vl)^vv,((math.random()-0.5)*vl)^vv),
            expirationtime = (math.random()*0.1)+0.0,
            size = math.random() * 3,
            collisiondetection = false,
            vertical = false,
            texture = "aom_muskets_smoke.png^[colorize:#ffff99:255",
            glow = 14,
        })
    end
end
function aom_muskets.do_smoke_particles(p, n, dir, size, dist)
    local va = (size or 9) / 10
    local vv = (size or 9) / 15
    -- error("\n".."p value is "..dump(p).."\n".."dir value is "..dump(dir))
    for i = 1, n do
        local pos = vector.add(p, vector.multiply(dir, i*(dist or 0.2)))
        minetest.add_particle({
            pos = vector.offset(pos, (math.random() * va)-va/2, (math.random() * va)-va/2, (math.random() * va)-va/2),
            velocity = vector.new((math.random()-0.5)*vv,(math.random()-0.5)*vv,(math.random()-0.5)*vv),
            expirationtime = math.random() * 2,
            size = math.random() * (size or 9),
            collisiondetection = false,
            vertical = false,
            texture = "aom_muskets_smoke.png^[opacity:100",
        })
    end
end

minetest.register_entity("aom_muskets:musket_shot_ENTITY", {
    initial_properties = {
        physical = false,
        textures = {"aom_muskets_shot.png"},
        visual = "sprite",
        visual_size = {x=0.5, y=0.5},
        collisionbox = {-0.2, -0.2, -0.2, 0.2, 0.2, 0.2,},
        use_texture_alpha = true,
        pointable = false,
    },
    _timer = 0,
    _last_pos = false,
    _shooter = nil,
    _dir = nil,
    _speed = 200,
    _lifetime = 1,
    _damage = {projectile = 1},
    _flags = {init = true},
    _bullet_drop = 0,
    on_step = function(self, dtime, moveresult)
        self._timer = self._timer + dtime
        local pos = self.object:get_pos()
        if not self._dir then return end
        if (not self._last_pos) then
            self._last_pos = pos
            self.object:set_velocity(vector.multiply(self._dir, self._speed))
            return
        end
        local vel = self.object:get_velocity()
        vel = vector.multiply(vel, 0.97)
        vel.y = vel.y + dtime * self._bullet_drop
        self.object:set_velocity(vel)

        local collided = false
        local ray = minetest.raycast(self._last_pos, pos, true, false)
        -- local ray = minetest.raycast(vector.add(pos), pos, true, false)
        local obj
        for pointed_thing in ray do
            if pointed_thing.type == "node" then
                local node = minetest.get_node(pointed_thing.under)
                local def = minetest.registered_nodes[node.name]
                if def and def.walkable then
                    collided = true
                    pos = pointed_thing.intersection_point
                    self.object:set_pos(pos)
                    break
                end
            elseif pointed_thing.type == "object" and pointed_thing.ref ~= self._shooter then
                obj = pointed_thing.ref
                local ent = obj:get_luaentity()
                if ent and ent._invulnerable then break end
                pos = pointed_thing.intersection_point
                self.object:set_pos(pos)
                break
            end
        end

        if not collided and obj then
            collided = true
        end

        if obj then
            obj:punch(self._shooter, 1.0, {
                full_punch_interval = 1.0,
                damage_groups = self._damage
            }, vector.normalize(vel))
        end

        if self._timer > self._lifetime then self.object:remove() self._removed = false end
        if collided and not self._removed then
            aom_muskets.do_particles(pos, 10)
            aom_muskets.do_smoke_particles(pos, 10, vector.normalize(vector.multiply(vel, -2)))
            -- minetest.log("hit "..pos.x)
            minetest.sound_play(("aom_muskets_hit_ricochet"), {
                gain = 0.8,
                pos = pos,
                max_hear_distance = 20,
                pitch = (math.random()*0.1) + 0.90
            })
            self._removed = true
            self.object:remove()
            return
        end
        self._last_pos = self.object:get_pos()
    end
})
