





local function apply_mech_scope(player, mech)
    if not player or not mech then return end

    -- Apply FULLSCREEN HUD overlay (scope effect)
    local hud_id = player:hud_add({
        hud_elem_type = "image",
        position = {x = 0.4974, y = 0.5025},
        offset = {x = 0, y = 0},
        text = mech.scope_texture,
        alignment = {x = 0, y = 0},
        scale = {x = -100, y = -100},
    })

    player:get_meta():set_int("mech_hud_id", hud_id)
end

local function remove_mech_scope(player)
    if not player then return end

    local hud_id = player:get_meta():get_int("mech_hud_id")
    if hud_id and hud_id > 0 then
        player:hud_remove(hud_id)
    end
end







local function play_step_sound(self, mech)
    if self.driver then
        minetest.sound_play(mech.step_sound, {pos = self.object:get_pos(), gain = 0.5})

        
        local step_interval = self.driver:get_player_control().sneak and (mech.step_interval * 0.5) or mech.step_interval

        minetest.after(step_interval, function()
            if self.driver and (self.object:get_velocity().x ~= 0 or self.object:get_velocity().z ~= 0) then
                play_step_sound(self, mech)
            end
        end)
    end
end








 -- the word "assorted" implies three or more of something.

local mechs = {
    {
        name = "mech1",
        collisionbox = {-1.5, -0.1, -1.5, 1.5, 4.8, 1.5},
        speed = 4,
    driver_visible = false,
        scope_texture = "mecha_static.png^scope_1.png",
	inventory_image = "spider_spawn.png",
        stepheight = 3.2,
        player_attach_offset = {x=0, y=1, z=0},
        player_eye_offset = {x=0, y=20, z=16.2},
        visual_size = {x=17.5, y=17.5, z=17.5},

        description = "(Walking Cannon)\nCategory: (4 Legged Stomper)\n\nControls:\nW-A-S-D - Walk\nShift - Sprint\nE - Fire Cannon",


        mesh = "mecha_spider_legs.x",
        step_sound = "mech1_step",
        turn_speed = 2,
        walk_animation = {x=25, y=60},
        reverse_walk_animation = {x=61, y=97},
        stand_animation = {x=1, y=1}, 
        walk_frame_interval = 0.1,
        texture = "mecha_head_gun.png",
        jump_height = 10,
        spawn_height = 0.5,
        player_attach_sound = "mech_attach",
        player_detach_sound = "mech_detach",
        jump_sound = "mech_jump",
        head_name = "assorted_mecha:head_spider",
        head_offset = {x=0, y=4.75, z=0},

        has_craftitem = true,
        step_interval = 0.5,
    },

    {
        name = "mech2",
        collisionbox = {-1.4, -0.1, -1.4, 1.4, 4.8, 1.4},
        speed = 3,
    driver_visible = false,
        scope_texture = "mecha_static.png^scope_1.png",
	inventory_image = "fang_spawn.png",
        stepheight = 1.2,
        player_attach_offset = {x=0, y=1, z=0},
        player_eye_offset = {x=0, y=23, z=12},
        visual_size = {x=30, y=30, z=30},

        description = "(Fang)\nCategory: (Bipedal Walker)\n\nControls:\nW-A-S-D - Walk\nShift - Sprint\nE - Rapidfire",



        mesh = "mecha1_legs.x",
        step_sound = "mech1_step",
        turn_speed = 1,
        walk_animation = {x=0, y=45},
        reverse_walk_animation = {x=45, y=90},
        stand_animation = {x=92, y=92},
        walk_frame_interval = 0.1,
        texture = "fang_mecha.png",
        jump_height = 10,
        air_animation = {x=1, y=5},
        spawn_height = 0.5,
        player_attach_sound = "mech_attach",
        player_detach_sound = "mech_detach",
        jump_sound = "mech_jump",
        head_name = "assorted_mecha:head_2",
        head_offset = {x=0, y=4.75, z=0},

        has_craftitem = true,
        step_interval = 0.75,
    },








    {
        name = "mech3",
        collisionbox = {-1.5, -0.1, -1.5, 1.5, 4.8, 1.5},
        speed = 3,
    driver_visible = false,
        scope_texture = "mecha_static.png^scope_2.png",
	inventory_image = "mecha_icon_default.png",
        stepheight = 1.2,
        player_attach_offset = {x=0, y=1, z=0},
        player_eye_offset = {x=0, y=28, z=25},
        visual_size = {x=14.5, y=14.5, z=14.5},

        description = "(new mecha)\nCategory: ( category )\n\nControls:\n WASD or something.\nShift - Sprint\nE - activate head function",


        mesh = "mecha_spider_legs.x",
        step_sound = "mech1_step",
        turn_speed = 1,
        walk_animation = {x=25, y=60},
        reverse_walk_animation = {x=61, y=97},
        stand_animation = {x=1, y=1}, 
        walk_frame_interval = 0.1,
        texture = "mecha_head_gun.png",
        jump_height = 10,
        air_animation = {x=1, y=5},
        spawn_height = 0.5,
        player_attach_sound = "mech_attach",
        player_detach_sound = "mech_detach",
        jump_sound = "mech_jump",
        head_name = "assorted_mecha:head_2",
        head_offset = {x=0, y=3.5, z=0},

        
        has_craftitem = false,
        step_interval = 0.5,
    },




}

local function register_mech(mech)
    local props = {
        physical = true,
        collisionbox = mech.collisionbox,
        visual = "mesh",
        mesh = mech.mesh,
        textures = {mech.texture},
        visual_size = mech.visual_size,
        stepheight = mech.stepheight,
    }

    minetest.register_entity("assorted_mecha:" .. mech.name, {
        initial_properties = props,
        driver = nil,
        head_entity = nil,
        jump_allowed = true,
        animation_timer = 0,

        on_activate = function(self)
        self.object:set_armor_groups({immortal=1})


            if not self.head_entity then
                local pos = self.object:get_pos()
                pos.y = pos.y + mech.head_offset.y
                self.head_entity = minetest.add_entity(pos, mech.head_name)
            end
        end,

        on_step = function(self, dtime)


       
    if not self.initial_animation_set then
        self.object:set_animation(mech.stand_animation, 30, 0)
        self.initial_animation_set = true
    end
    
    
    if not self.initial_yaw_set then
        self.object:set_yaw(0)
        self.initial_yaw_set = true
    end

 
    if not self.initial_step_sound_played then
        minetest.after(0.5, function()
            minetest.sound_play(mech.step_sound, {pos = self.object:get_pos(), gain = 0.5})
        end)
        self.initial_step_sound_played = true
    end


local vel = self.object:get_velocity() or {x=0, y=0, z=0}
vel.y = vel.y - (dtime * 9.8)
self.object:set_velocity(vel)

            if self.driver then
                local control = self.driver:get_player_control()
                local yaw = self.object:get_yaw()

local speed = (control.up and mech.speed or (control.down and -mech.speed or 0))
local animation_speed = 30 -- Default animation speed

-- Apply sprint boost when Shift (sneak) is pressed
if control.sneak then
    speed = speed * 2 -- Double the normal speed
    animation_speed = animation_speed * 2 -- Double animation speed
end


                local vel = self.object:get_velocity() or {x=0, y=0, z=0}

                vel.x = math.sin(yaw) * -speed
                vel.z = math.cos(yaw) * speed
                self.object:set_velocity(vel)

                if control.left then
                    self.object:set_yaw(yaw + mech.turn_speed * dtime)
                elseif control.right then
                    self.object:set_yaw(yaw - mech.turn_speed * dtime)
                end

                
                if speed ~= 0 and not self.is_playing_step_sound then
                    self.is_playing_step_sound = true
                    play_step_sound(self, mech)
                elseif speed == 0 then
                    self.is_playing_step_sound = false
                end



                if control.jump and self.jump_allowed and vel.y >= -1 then
                    self.object:set_velocity({x=vel.x, y=mech.jump_height, z=vel.z})
                    self.jump_allowed = false
                    minetest.after(2, function() self.jump_allowed = true end)
                    minetest.sound_play(mech.jump_sound, {pos = self.object:get_pos(), gain = 0.5})
                end

    if self.driver then
        local control = self.driver:get_player_control()
        local speed = control.up and mech.speed or (control.down and -mech.speed or 0)

       
        self.animation_timer = self.animation_timer + dtime
        local is_moving = speed ~= 0

local moving_backward = control.down
local anim_range = moving_backward and mech.reverse_walk_animation or mech.walk_animation


        if self.animation_timer >= mech.walk_frame_interval then
            self.animation_timer = 0
            if is_moving then
                self.object:set_animation(anim_range, animation_speed, 0)

            else
                self.object:set_animation(mech.stand_animation, 30, 0)

            end
        end
    end
end


            if self.head_entity then
                local mech_pos = self.object:get_pos()
                local head_pos = self.head_entity:get_pos()

                head_pos.x = mech_pos.x
                head_pos.y = mech_pos.y + mech.head_offset.y
                head_pos.z = mech_pos.z

                self.head_entity:set_pos(head_pos)
                self.head_entity:set_yaw(self.head_entity:get_yaw())
            end
        end,

        
on_rightclick = function(self, clicker)
    if self.driver and clicker == self.driver then
        clicker:set_detach()
        clicker:set_eye_offset({x=0, y=0, z=0})
        minetest.sound_play(mech.player_detach_sound, {pos = self.object:get_pos(), gain = 0.5})
        self.driver = nil

        
        clicker:set_properties({visual_size = mech.driver_visible and {x=1, y=1, z=1} or {x=0, y=0, z=0}})


        
        if self.saved_hp then
            clicker:set_hp(self.saved_hp)
            self.saved_hp = nil
        end



clicker:set_properties({visual_size = {x=1, y=1, z=1}})

        
        remove_mech_scope(clicker)
    else
        clicker:set_attach(self.object, "", mech.player_attach_offset, {x=0, y=0, z=0})
        clicker:set_eye_offset(mech.player_eye_offset)
        minetest.sound_play(mech.player_attach_sound, {pos = self.object:get_pos(), gain = 0.5})
        self.driver = clicker



        
        self.saved_hp = clicker:get_hp()

        
        minetest.register_on_player_hpchange(function(player, hp_change)
            if player == clicker and player:get_attach() == self.object then
                player:set_hp(self.saved_hp)
                return 0
            end
            return hp_change
        end, true)



        
        clicker:set_properties({visual_size = mech.driver_visible and {x=1, y=1, z=1} or {x=0, y=0, z=0}})

        
        apply_mech_scope(clicker, mech)
    end
end,

    })
end

for _, mech in ipairs(mechs) do
    if mech.has_craftitem then
        minetest.register_craftitem("assorted_mecha:spawn_" .. mech.name, {
            description = "Name: " .. mech.description,
            inventory_image = mech.inventory_image,
            range = 9,

            on_place = function(itemstack, placer, pointed_thing)
                if pointed_thing.type ~= "node" then return itemstack end
                local pos = pointed_thing.above
                pos.y = pos.y + mech.spawn_height
                local mech_entity = minetest.add_entity(pos, "assorted_mecha:" .. mech.name)
                if mech_entity and placer then
                    mech_entity:set_yaw(placer:get_look_horizontal())
                end
                if not minetest.is_creative_enabled(placer:get_player_name()) then
                    itemstack:take_item()
                end
                return itemstack
            end,
        })
    end

    register_mech(mech)
end
























-----------------------------------------------------------------------------------------------------mecha1







local function rotate_offset(offset, yaw)
    local rotated_x = offset.x * math.cos(yaw) - offset.z * math.sin(yaw)
    local rotated_z = offset.x * math.sin(yaw) + offset.z * math.cos(yaw)
    return {x = rotated_x, y = offset.y, z = rotated_z}
end

local bullet_groups = {
    A = { {x = -1.35, y = 3.772, z = 0.85}, {x = 1.35, y = 3.772, z = 0.85} },
    B = { {x = -1.35, y = 3.92, z = 0.85}, {x = 1.35, y = 3.92, z = 0.85} },
    C = { {x = -1.35, y = 4.067, z = 0.85}, {x = 1.35, y = 4.067, z = 0.85} }
}




local function spawn_bullets(player)
    if not player then return end

    local player_pos = player:get_pos()
    local player_yaw = player:get_look_horizontal()
    local player_dir = player:get_look_dir()  -- Correct movement direction

    -- Randomly select one bullet group (A, B, or C)
    local group_key = math.random(1, 3) == 1 and "A" or (math.random(1, 2) == 1 and "B" or "C")
    local selected_positions = bullet_groups[group_key]

    -- Play sound when a bullet group is picked
    minetest.sound_play("mech_fire2", {pos = player_pos, gain = 1.0})

    -- Spawn bullets from the selected group
    for _, offset in ipairs(selected_positions) do
        local rotated_offset = rotate_offset(offset, player_yaw)
        local bullet_pos = vector.add(player_pos, rotated_offset)
        local bullet = minetest.add_entity(bullet_pos, "assorted_mecha:mecha_bullet")

        if bullet then
            
            local random_x = (math.random() * 0.5) - 0.25
            local random_z = (math.random() * 0.5) - 0.25  

            
            local bullet_velocity = vector.multiply(player_dir, 30)
            bullet_velocity.x = bullet_velocity.x + random_x
            bullet_velocity.z = bullet_velocity.z + random_z

            bullet:set_velocity(bullet_velocity)
            bullet:set_yaw(player:get_look_horizontal())

            
local muzzle_textures = {"muzzle_flash.png", "muzzle_flash2.png"}
local selected_texture = muzzle_textures[math.random(1, #muzzle_textures)]


minetest.add_particlespawner({
    amount = 1,
    time = 0.1,
    minpos = bullet_pos,
    maxpos = bullet_pos,
    minvel = {x=0, y=0, z=0},
    maxvel = {x=0, y=0, z=0},
    minexptime = 0.1,
    maxexptime = 0.1,
    minsize = 6,
    maxsize = 6,
    texture = selected_texture,
    glow = 15,  
})

        end
    end
end











minetest.register_entity("assorted_mecha:head_2", {
    initial_properties = {
        physical = false,
        pointable = false,

        visual = "mesh",
        mesh = "mecha_1.x",
	glow = 0,

        textures = {"fang_mecha_antiglow.png"},
        visual_size = {x=11.4, y=11.4, z=11.4},
        static_save = false,
    },

    on_activate = function(self, staticdata)
        self.object:set_armor_groups({immortal=1})

        
        if not self.glow_entity then
            self.glow_entity = minetest.add_entity(self.object:get_pos(), "assorted_mecha:glow_effect")
            if self.glow_entity then
                self.glow_entity:set_attach(self.object, "", {x=0, y=0, z=0}, {x=0, y=0, z=0})
            end
        end
    end,

    on_step = function(self, dtime)
    local head_pos = self.object:get_pos()
    local target_player = nil

    
    for _, player in ipairs(minetest.get_connected_players()) do
        local player_pos = player:get_pos()
        local height_difference = head_pos.y - player_pos.y
        local horizontal_distance = vector.distance(vector.new(head_pos.x, 0, head_pos.z), vector.new(player_pos.x, 0, player_pos.z))

        if math.abs(height_difference - 4.75) < 0.1 and horizontal_distance <= 1 then
            target_player = player
            break
        end
    end

    
    if target_player then
        self.object:set_yaw(target_player:get_look_horizontal())

       
        local control = target_player:get_player_control()
        if control.aux1 and not self.is_firing then
            self.is_firing = true
            local function fire_loop()
                if self.is_firing and target_player then
                    spawn_bullets(target_player)
                    minetest.after(0.1, fire_loop)
                end
            end
            fire_loop()
        elseif not control.aux1 then
            self.is_firing = false
        end
    end
end,

})


minetest.register_entity("assorted_mecha:glow_effect", {
    initial_properties = {
        physical = false,
        pointable = false,
        visual = "mesh",
        mesh = "mecha_1.x",
	glow = 30,
        textures = {"fang_glow.png"},
        visual_size = {x=1, y=1, z=1},
        static_save = false,
    },


    on_activate = function(self)
        self.object:set_armor_groups({immortal=1})
    end,
})





--------------------------------------------------------------------------------------------------mecha2




local function rotate_offset(offset, yaw)
    local rotated_x = offset.x * math.cos(yaw) - offset.z * math.sin(yaw)
    local rotated_z = offset.x * math.sin(yaw) + offset.z * math.cos(yaw)
    return {x = rotated_x, y = offset.y, z = rotated_z}
end



minetest.register_entity("assorted_mecha:head_spider", {
    initial_properties = {
        physical = false,
        pointable = false,

        visual = "mesh",
        mesh = "mecha_big_gun_head.x",
	glow = 0,

        textures = {"mecha_head_gun_anti.png"},
        visual_size = {x=14, y=14, z=14},
        static_save = false,
    },

    on_activate = function(self, staticdata)
    self.object:set_armor_groups({immortal=1})

    
    if not self.glow_entity then
        self.glow_entity = minetest.add_entity(self.object:get_pos(), "assorted_mecha:spider_glow_effect")
        if self.glow_entity then
            self.glow_entity:set_attach(self.object, "", {x=0, y=0, z=0}, {x=0, y=0, z=0})
        end
    end
end,










on_step = function(self, dtime)
    local head_pos = self.object:get_pos()
    local target_player = nil

    
    for _, player in ipairs(minetest.get_connected_players()) do
        local player_pos = player:get_pos()
        local height_difference = head_pos.y - player_pos.y
        local horizontal_distance = vector.distance(vector.new(head_pos.x, 0, head_pos.z), vector.new(player_pos.x, 0, player_pos.z))

        if math.abs(height_difference - 4.75) < 0.1 and horizontal_distance <= 1 then
            target_player = player
            break
        end
    end

    
    if target_player then
        self.object:set_yaw(target_player:get_look_horizontal())

        
        local control = target_player:get_player_control()
        if control.aux1 and not self.is_firing then
            self.is_firing = true

            
            local shoot_speed = 15
            self.object:set_animation({x=24, y=38}, shoot_speed, 0)

            if self.glow_entity then
                self.glow_entity:set_animation({x=24, y=38}, shoot_speed, 0) -- Sync glow animation
            end

            
            local yaw = target_player:get_look_horizontal()
            local pitch = target_player:get_look_vertical()
            local dir = vector.new(-math.sin(yaw) * math.cos(pitch), -math.sin(pitch), math.cos(yaw) * math.cos(pitch))

            -- **Bullet offset relative to the mech**
            local bullet_offset = {x=0, y=-0.75, z=2.75} -- Adjust positioning
            local rotated_offset = rotate_offset(bullet_offset, yaw)
            local bullet_pos = vector.add(head_pos, rotated_offset)




local bullet = minetest.add_entity(bullet_pos, "assorted_mecha:plasma_bolt")
if bullet then
    bullet:set_velocity(vector.multiply(dir, 40))
    minetest.sound_play("plasma_rifle", {pos = pos, gain = 3.0})
    bullet:set_yaw(target_player:get_look_horizontal())

    -- **Spawn muzzle flash particles at bullet position**
    local muzzle_textures = {"plasma_pop.png"}
    local selected_texture = muzzle_textures[math.random(1, #muzzle_textures)]

    minetest.add_particlespawner({
        amount = 1,
        time = 0.1,
        minpos = bullet_pos,
        maxpos = bullet_pos,
        minvel = {x=0, y=0, z=0},
        maxvel = {x=0, y=0, z=0},
        minexptime = 0.1,
        maxexptime = 0.1,
        minsize = 12,
        maxsize = 12,
        texture = selected_texture,
        glow = 15,  
    })
end




            
            minetest.after(0.6, function() 
                self.object:set_animation({x=0.5, y=0.9}, 1, 0)
                
                if self.glow_entity then
                    self.glow_entity:set_animation({x=0.5, y=0.9}, 1, 0)
                end
            end)

            -- Cooldown of 2 seconds before firing again
            minetest.after(2, function() 
                self.is_firing = false
            end)
        end
    end
end,




})


minetest.register_entity("assorted_mecha:spider_glow_effect", {
    initial_properties = {
        physical = false,
        pointable = false,
        visual = "mesh",
        mesh = "mecha_big_gun_head.x",
	glow = 30,
        textures = {"mecha_head_gun_glow.png"},
        visual_size = {x=1, y=1, z=1},
        static_save = false,
    },


    on_activate = function(self)
        self.object:set_armor_groups({immortal=1})
    end,
})

--------------------------------------------------------------------------------------------------stuff



minetest.register_entity("assorted_mecha:mecha_bullet", {
    initial_properties = {
        physical = true,
        visual_size = {x=0.1, y=0.1, z=0.1},
        visual = "sprite",
        textures = {"mecha_bullet.png"},
        glow = 30, 
        collisionbox = {0, 0, 0, 0, 0, 0},
    },

    on_activate = function(self)
        minetest.after(3, function() self.object:remove() end)
    end,

    on_step = function(self, dtime)
    local pos = self.object:get_pos()

    
    local function is_removable(node_name)
        local keywords = { "dirt", "leaves", "needles", "snow", "grass" }
        for _, keyword in ipairs(keywords) do
            if string.find(node_name, keyword) then
                return true
            end
        end
        return false
    end

    
    local node = minetest.get_node(pos)
    if node.name ~= "air" then

        
        minetest.add_particlespawner({
            amount = 25,
            time = 0.3,
            minpos = pos,
            maxpos = pos,
            minvel = {x=-2, y=1, z=-2},
            maxvel = {x=2, y=3, z=2},
            minexptime = 0.4,
            maxexptime = 0.8,
            minsize = 4,
            maxsize = 6,
            texture = "smoke_puff.png",
            glow = 0,
        })

        
        minetest.add_particlespawner({
            amount = 25,
                    time = 0.3,
                    minpos = pos,
                    maxpos = pos,
                    minvel = {x=-2, y=3, z=-2},
                    maxvel = {x=2, y=5, z=2},
                    minacc = {x=0, y=-15, z=0},
                    maxacc = {x=0, y=-20, z=0},
                    minexptime = 0.3,
                    maxexptime = 0.6,

            minsize = 4,
            maxsize = 4,
            texture = "spark.png",
            glow = 30,
        })

        -- Determine sound based on node type
if is_removable(node.name) then

    minetest.sound_play("bullet", {pos = pos, gain = 3.0})
    minetest.set_node(pos, {name = "air"}) -- Remove the node if it matches the criteria
else
    -- Play alternative impact sound for non-removable nodes
    minetest.sound_play("ting", {pos = pos, gain = 2.0})
end


        self.object:remove()
        return
    end












       -- Damage nearby players instead of all entities
local blood_variants = {"mech_blood_1.png", "mech_blood_2.png", "mech_blood_3.png", "mech_blood_4.png"}

for _, obj in ipairs(minetest.get_objects_inside_radius(pos, 1)) do
    if obj:is_player() then
        obj:set_hp(obj:get_hp() - 2)
        self.object:remove()

        
        minetest.add_particlespawner({
            amount = 15,
            time = 0.3,
            minpos = pos,
            maxpos = pos,
            minvel = {x=-2, y=3, z=-2},
            maxvel = {x=2, y=5, z=2},
            minacc = {x=0, y=-15, z=0},
            maxacc = {x=0, y=-20, z=0},
            minexptime = 1,
            maxexptime = 1,
            minsize = 1,
            maxsize = 1.5,
            glow = 0,
            texture = blood_variants[math.random(1, #blood_variants)],
        })

        return
    end
end


    end,
})















































minetest.register_entity("assorted_mecha:node_shard", {
    initial_properties = {
        physical = true,
        collide_with_objects = false,
        collisionbox = {-0.3, -0.3, -0.3, 0.3, 0.3, 0.3},
        visual = "wielditem",
        visual_size = {x = 0.5, y = 0.5},
        textures = {""},
    },

    on_activate = function(self)
        self.timer = 0
        self.rotation = {x = 0, y = 0, z = 0}
        self.spin_rate = {
            x = math.rad(math.random(-180, 180)),
            y = math.rad(math.random(-180, 180)),
            z = math.rad(math.random(-180, 180)),
        }

        -- gravity
        self.object:set_acceleration({x = 0, y = -3.5, z = 0})
    end,

    on_step = function(self, dtime)
        self.timer = self.timer + dtime

        -- Visual spin
        self.rotation.x = self.rotation.x + self.spin_rate.x * dtime
        self.rotation.y = self.rotation.y + self.spin_rate.y * dtime
        self.rotation.z = self.rotation.z + self.spin_rate.z * dtime
        self.object:set_rotation(self.rotation)

        local pos = self.object:get_pos()
        local radius = 1.2
        local nearby_node_found = false

        for dx = -1, 1 do
            for dy = -1, 0 do
                for dz = -1, 1 do
                    local check_pos = vector.add(pos, {x = dx, y = dy, z = dz})
                    local dist = vector.distance(pos, check_pos)
                    local node = minetest.get_node_or_nil(check_pos)
                    if node and node.name ~= "air" and dist <= radius then
                        nearby_node_found = true
                        break
                    end
                end
                if nearby_node_found then break end
            end
            if nearby_node_found then break end
        end


if nearby_node_found or self.timer >= 8 then
    minetest.add_item(pos, self.original_node or "default:dirt")

    -- **Play original node's place sound before removal**
    if self.original_node then
        local node_def = minetest.registered_nodes[self.original_node]
        if node_def and node_def.sounds and node_def.sounds.place then
            minetest.sound_play(node_def.sounds.place.name, {pos = pos, gain = 0.5})
        end
    end

    self.object:remove()
end


    end,
})










minetest.register_entity("assorted_mecha:plasma_bolt", {
    initial_properties = {
        physical = true,
        visual_size = {x = 0.2, y = 0.2, z = 0.2},
        visual = "sprite",
        textures = {"plasma_bolt.png"},
        glow = 50,
        collisionbox = {0, 0, 0, 0, 0, 0},
    },

    on_activate = function(self)
        minetest.after(3, function()
            if self.object then self.object:remove() end
        end)
    end,

    on_step = function(self, dtime)
        local pos = self.object:get_pos()
        local node = minetest.get_node(pos)

        if node.name ~= "air" then
            -- impact effects
            minetest.add_particlespawner({
                amount = 45,
                time = 0.3,
                minpos = pos,
                maxpos = pos,
                minvel = {x = -4, y = 2, z = -4},
                maxvel = {x = 4, y = 6, z = 4},
                minexptime = 0.8,
                maxexptime = 1.6,
                minsize = 8,
                maxsize = 12,
                texture = "smoke_puff.png",
                glow = 0,
            })

            minetest.add_particlespawner({
                amount = 45,
                time = 0.3,
                minpos = pos,
                maxpos = pos,
                minvel = {x = -4, y = 6, z = -4},
                maxvel = {x = 4, y = 10, z = 4},
                minacc = {x = 0, y = -15, z = 0},
                maxacc = {x = 0, y = -20, z = 0},
                minexptime = 0.6,
                maxexptime = 1.2,
                minsize = 8,
                maxsize = 8,
                texture = "spark.png",
                glow = 30,
            })

            minetest.sound_play("bomber_ex", {pos = pos, gain = 3.0})

            -- blast radius
            local radius = 6
            local keywords = {
                "grass", "leaves", "snow", "wool", "needles", "tree", "wood",
                "lamp", "sand", "bush", "glass", "soil", "stem", "torch",
                "fire", "plant", "wheat", "dirt"
            }
            local groups = {"choppy", "oddly_breakable_by_hand"}

            for dx = -radius, radius do
                for dy = -radius, radius do
                    for dz = -radius, radius do
                        if dx * dx + dy * dy + dz * dz <= radius * radius then
                            local target_pos = vector.add(pos, {x = dx, y = dy, z = dz})
                            local target_node = minetest.get_node(target_pos)

                            
                            local destroy = false

                            
                            for _, keyword in ipairs(keywords) do
                                if string.find(target_node.name, keyword) then
                                    destroy = true
                                    break
                                end
                            end

                            
                            if not destroy then
                                for _, group in ipairs(groups) do
                                    if minetest.get_item_group(target_node.name, group) > 0 then
                                        destroy = true
                                        break
                                    end
                                end
                            end

                            -- shard
                            if destroy then
                                minetest.set_node(target_pos, {name = "air"})
                                local shard_obj = minetest.add_entity(target_pos, "assorted_mecha:node_shard")
                                if shard_obj then
                                    local shard = shard_obj:get_luaentity()
                                    if shard then
                                        shard.original_node = target_node.name
                                        shard_obj:set_properties({textures = {target_node.name}})
                                        shard_obj:set_velocity({
                                            x = (math.random() - 0.5) * 7,
                                            y = 6 + math.random() * 3,
                                            z = (math.random() - 0.5) * 7
                                        })
                                    end
                                end
                            end
                        end
                    end
                end
            end

            -- Player damage
            for _, player in ipairs(minetest.get_connected_players()) do
                local ppos = player:get_pos()
                if vector.distance(pos, ppos) <= radius then
                    player:set_hp(player:get_hp() - 6)
                end
            end

            self.object:remove()
        end
    end,
})































































minetest.register_chatcommand("clear_foliage", {
    params = "",
    description = "Removes all trees, logs, leaves, or saplings within a 40-block radius.",
    privs = {server = true},
    func = function(name)
        local player = minetest.get_player_by_name(name)
        if not player then return end

        local pos = player:get_pos()
        local radius = 40

        
        for x = -radius, radius do
            for y = -radius, radius do
                for z = -radius, radius do
                    local check_pos = vector.add(pos, {x=x, y=y, z=z})
                    local node = minetest.get_node(check_pos)
                    local node_name = node.name

                    -- Remove nodes containing keywords
                    if string.find(node_name, "tree") or 
                       string.find(node_name, "log") or 
                       string.find(node_name, "leaves") or 
                       string.find(node_name, "sapling") then
                        minetest.set_node(check_pos, {name = "air"})
                    end
                end
            end
        end

        minetest.chat_send_player(name, "Cleared all trees, logs, leaves, and saplings within 40 blocks!")
    end
})