Implement a box object that can be picked up and put down

/// @function playerCollision
/// @description Handles the player's collision code
function playerCollision() {
    var scale = 64/500; // The scale factor of the player object

    // Floor
    var mySolid = instance_place(x, y + global.yspeed, objSolid);
    if (mySolid >= 0 && global.yspeed >= 0) {
        var spriteOffsetY = sprite_get_yoffset(sprite_index) * scale;
        var spriteHeight = sprite_get_height(sprite_index) * scale;
        y = mySolid.bbox_top - (spriteHeight - spriteOffsetY);
        ground = true;
        global.yspeed = 0;
        
        // Ensure the player stays grounded
        while (!place_meeting(x, y + 1, objSolid)) {
            y += 1;
        }
    }

    // Wall
    mySolid = instance_place(x + global.xspeed, y, objSolid);
    if (mySolid >= 0 && global.xspeed != 0) {
        var spriteOffsetX = sprite_get_xoffset(sprite_index) * scale;
        var spriteWidth = sprite_get_width(sprite_index) * scale;
        
        if (global.xspeed < 0) {
            x = mySolid.bbox_right + spriteOffsetX;
        } else {
            x = mySolid.bbox_left - (spriteWidth - spriteOffsetX);
        }
        
        // Force player out of the wall if clipping occurs
        while (place_meeting(x, y, objSolid)) {
            x += sign(global.xspeed) * -1;
        }
        
        global.xspeed = 0;
    }

    // Ceiling
    mySolid = instance_place(x, y + global.yspeed, objSolid);
    if (mySolid >= 0 && global.yspeed < 0) {
        var spriteOffsetY = sprite_get_yoffset(sprite_index) * scale;
        y = mySolid.bbox_bottom + spriteOffsetY;
        // Force player out of the ceiling if clipping occurs
        while (place_meeting(x, y, mySolid)) {
            y += 1;
        }
        global.yspeed = 0;
    }

    mySolid = instance_place(x, y + global.yspeed, objTopSolid);
    if (mySolid >= 0 && global.yspeed >= 0) {
        if (bbox_bottom <= mySolid.bbox_top + global.yspeed) {  // Check if actually above the platform
            var spriteOffsetY = sprite_get_yoffset(sprite_index) * scale;
            var spriteHeight = sprite_get_height(sprite_index) * scale;
            y = mySolid.bbox_top - (spriteHeight - spriteOffsetY);
            ground = true;
            global.yspeed = 0;
        }
    }

    // Ensure ground state and yspeed are consistent
    if (ground) {
        global.yspeed = 0;
        // Double-check ground state
        if (!place_meeting(x, y + 1, objSolid) && !place_meeting(x, y + 1, objTopSolid)) {
            ground = false;
        }
    }
}

/// @function playerStep
/// @description Handles general step event code for the player
function playerStep() {

    //Check for ground
    if place_meeting(x, y+global.yspeed+1, objSolid) || (place_meeting(x, y+global.yspeed+1, objTopSolid) && global.yspeed >= 0)
    {
        var endCheck = false;
        
        if place_meeting(x, y+global.yspeed+1, objSolid)
        {
            ground = true;
            endCheck = true;
        }
		
		if keyboard_check(vk_down) && place_meeting(x, bbox_bottom+1, objTopSolid)
		{
			y += 1;
		}
        
        if place_meeting(x, y+global.yspeed+1, objTopSolid) && !endCheck
        {
            var topSolid = instance_place(x, y+global.yspeed+1, objTopSolid);
            if (bbox_bottom <= topSolid.bbox_top)
            {
                ground = true;
            }
            else
            {
                ground = false;
            }
            endCheck = true;
        }
        
        if !endCheck
        {
            ground = false;
        }
    }
    else
    {
        ground = false;
        if prevGround == true
            y += 1; //To make Mega Man able to fall through 1-block wide gaps
    }

    //Can we do a short hop? (Placed earlier in the code to fix the 'jump on the frame you land and you can't do a short hop' bug
    if !(ground == false && canGravity == true)
        canMinJump = true;

    //Movement (includes initializing sidestep while on the ground)
    if canMove == true
    {
        if ground == true
        {
            if keyboard_check(vk_left) && !keyboard_check(vk_right)
            {
                if canInitStep == true
                {
                    canInitStep = false;
                    isStep = true;
                    image_xscale = 64/500;
                }
                else if isStep == false
                {
                    if !(place_meeting(x, y+1, objIce) && global.xspeed > 0)
                    {
                        //Normal physics
                        if !place_meeting(x-1, y, objSolid)
                            global.xspeed = -walkSpeed;
                    }
                    else
                    {
                        //Ice physics
                        if !place_meeting(x-1, y, objSolid)
                            global.xspeed -= iceDecWalk;
                    }
                    
                    image_xscale = -abs(image_xscale);
                            
                    if canSpriteChange == true
                    {
                        sprite_index = sprWalk;
                        image_speed = 0.15;
                    }
                }
            }
            else if keyboard_check(vk_right) && !keyboard_check(vk_left)
            {
                if canInitStep == true
                {
                    canInitStep = false;
                    isStep = true;
                    image_xscale = 64/500;
                }
                else if isStep == false
                {
                    if !(place_meeting(x, y+1, objIce) && global.xspeed < 0)
                    {
                        //Normal physics
                        if !place_meeting(x-1, y, objSolid)
                            global.xspeed = walkSpeed;
                    }
                    else
                    {
                        //Ice physics
                        if !place_meeting(x-1, y, objSolid)
                            global.xspeed += iceDecWalk;
                    }
                    
                    image_xscale = abs(image_xscale);
                
                    if canSpriteChange == true
                    {
                        sprite_index = sprWalk;
                        image_speed = 0.15;
                    }
                }
            }
            else
            {
                if !(place_meeting(x, y+1, objIce) && global.xspeed != 0)
                {
                    //Normal physics
                    global.xspeed = 0;
                    canInitStep = true;
                }
                else
                {
                    //Ice physics
                    if global.xspeed > 0
                        global.xspeed -= iceDec;
                    else if global.xspeed < 0
                        global.xspeed += iceDec;
                    
                    if global.xspeed > -iceDec && global.xspeed < iceDec
                        global.xspeed = 0;
                }
            
                if keyboard_check(vk_left) && !keyboard_check(vk_right)
                    image_xscale = -abs(image_xscale);
                else if keyboard_check(vk_right) && !keyboard_check(vk_left)
                    image_xscale = abs(image_xscale);
            
                if canSpriteChange == true
                {
                    sprite_index = sprStep;
                    image_speed = 0;
                }
            }
        }
        else
        {
            canInitStep = false;
            isStep = false;
        
            if canSpriteChange == true
                sprite_index = sprJump;
            
            if keyboard_check(vk_left) && !keyboard_check(vk_right) && !place_meeting(x-1, y, objSolid)
            {
                global.xspeed = -walkSpeed;
                image_xscale = -abs(image_xscale);
            }
            else if keyboard_check(vk_right) && !keyboard_check(vk_left) && !place_meeting(x+1 + (prevXScale == -64/500), y, objSolid) //For some reason, while on the left of the wall and facing left, then jumping and holding right would clip you through it. Prevented by checking if the player was facing left on the previous frame, and if so, disallow Mega Man to move if 2 pixels away from the wall instead of 1
            {
                global.xspeed = walkSpeed;
                image_xscale = abs(image_xscale);
            }
            else
            {
                global.xspeed = 0;
            
                if keyboard_check(vk_left) && !keyboard_check(vk_right)
                    image_xscale = -abs(image_xscale);
                else if keyboard_check(vk_right) && !keyboard_check(vk_left)
                    image_xscale = abs(image_xscale);
            }
        }
    }
    else if canSpriteChange == true
    {
        //Even if canMove is false, we should still be able to change sprites
        if ground == true
        {
            if global.xspeed == 0
            {
                sprite_index = sprStep;
                image_speed = 0;
            }
            else
            {
                sprite_index = sprWalk;
                image_speed = 0.15;
            }
        }
        else
        {
            sprite_index = sprJump;
        }
    }

    //Sidestepping
    if isStep == true
    {
        if !place_meeting(x+image_xscale * 500/64, y, objSolid)
            global.xspeed = stepSpeed * image_xscale * 500/64;
    
        if canSpriteChange == true
            sprite_index = sprStep;
    
        stepTimer += 1;
        if stepTimer >= stepFrames
        {
            isStep = false;
            stepTimer = 0;
        }
    }

    //Allow movement
    x += global.xspeed;
    y += global.yspeed;

    //Stop movement at section borders
    if x > sectionRight-6 && !place_meeting(x+6, y, objSectionArrowRight) && !place_meeting(x-global.xspeed, y, objSectionArrowRight)
    {
        x = sectionRight-6;
        global.xspeed = 0;
    }
    else if x < sectionLeft+6 && !place_meeting(x-6, y, objSectionArrowLeft) && !place_meeting(x-global.xspeed, y, objSectionArrowLeft)
    {
        x = sectionLeft+6;
        global.xspeed = 0;
    }
    
    if y < sectionTop-32
        y = sectionTop-32;
    
    //Stop movement at room borders
    if x > room_width-6
        x = room_width-6;
    else if x < 6
        x = 6;
    
    if y < -32
        y = -32;

    //Jumping
    if canMove == true && ground == true && keyboard_check_pressed(ord("Z")) && !keyboard_check(vk_down)
    { 
        canSpriteChange = true;
        global.yspeed = -currentJumpSpeed;
        ground = false;
        y -= 10; //To negate the prevGround y += 1
        sprite_index = sprJump;
    }

    //Minjumping (lowering jump when the jump button is released)
    if ground == false && global.yspeed < 0 && !keyboard_check(ord("Z")) && canMinJump == true
    {
        canMinJump = false;
        global.yspeed = 0;
    }

    //Climbing
    var ladder = collision_rectangle(sprite_get_xcenter()-3, bbox_top, sprite_get_xcenter()+3, bbox_bottom-1, objLadder, false, false);
    var ladderDown = collision_rectangle(sprite_get_xcenter()-3, bbox_bottom+1, sprite_get_xcenter()+3, bbox_bottom+2, objLadder, false, false);
    
    if (((ladder >= 0 && keyboard_check(vk_up) && !keyboard_check(vk_down))
        || (ladderDown >= 0 && ground == true && keyboard_check(vk_down) && !keyboard_check(vk_up) && !place_meeting(x, y, objLadder)))
        && canMove == true)
    {  
        climbing = true;
        canMove = false;
        canSpriteChange = false;
        canGravity = false;
        
        global.xspeed = 0;
        global.yspeed = 0;
        
        if ladder >= 0
        {
            x = ladder.x + 32;
        }
        else if ladderDown >= 0
        {
            x = ladderDown.x + 32;
            y += climbSpeed;
            ground = false;
        }
        
        sprite_index = sprClimb;
        image_speed = 0;
        
        ladderXScale = image_xscale;
    }

    //While climbing
    if climbing == true
    {
        isStep = false;
        canInitStep = false;
    
        //Movement
        if keyboard_check(vk_up) && !keyboard_check(vk_down)
        {
            climbSpriteTimer += 1;
            global.yspeed = -climbSpeed;
        }
        else if keyboard_check(vk_down) && !keyboard_check(vk_up)
        {
            climbSpriteTimer += 1;
            global.yspeed = climbSpeed;
        }
        else
        {
            global.yspeed = 0;
        }
    
        if climbSpriteTimer >= 32 && sprite_index == sprClimb
        {
            climbSpriteTimer = 0;
            image_xscale = -image_xscale;
        }
    
        //Getup sprite
        if !position_meeting(x, bbox_top+1, objLadder) && position_meeting(x, bbox_bottom+1, objLadder) //The second check is to make sure the getup animation is not shown when on the BOTTOM of a ladder that's placed in the air
        {
            sprite_index = sprGetup;
        }
        else
        {
            sprite_index = sprClimb;
        }
    
        //Releasing the ladder
        if (ground == true && !keyboard_check(vk_up)) 
            || (keyboard_check_pressed(ord("Z")) && !keyboard_check(vk_up)) 
            || !position_meeting(x, bbox_top+43, objLadder) 
            || !place_meeting(x, y, objLadder)
            || (keyboard_check(vk_down) && place_meeting(x, bbox_bottom+1, objTopSolid))
        {
            climbing = false;
            canMove = true;
            canSpriteChange = true;
            canGravity = true;
            image_xscale = ladderXScale;
            global.yspeed = 0;
        
            if position_meeting(x, bbox_bottom+15, objTopSolid) || ground == true
            {
                if !ground
                {
                    y = floor(y);
                    while !place_meeting(x, y + 1, objTopSolid) && y < y + 2
                    {
                        y += 1;
                    }
                    ground = true;
                }

                if (keyboard_check(vk_right) && !keyboard_check(vk_left)) || (keyboard_check(vk_left) && !keyboard_check(vk_right))
                {
                    sprite_index = sprWalk;
                
                    if keyboard_check(vk_right)
                    {
                        global.xspeed = walkSpeed;
                        image_xscale = 64/500;
                    }
                    else if keyboard_check(vk_left)
                    {
                        global.xspeed = -walkSpeed;
                        image_xscale = -abs(image_xscale);
                    }
                }
                else
                    sprite_index = sprStep;
            }
            else
                sprite_index = sprJump;

            if !position_meeting(x, bbox_top+43, objLadder)
            {
                y -= 16;
                // Ensure ground is checked after adjusting y position
                if place_meeting(x, y+1, objSolid) || place_meeting(x, y+1, objTopSolid)
                {
                    ground = true;
                    sprite_index = sprStep;
                }
            }
        }
    }

    //Water
    if place_meeting(x, y, objWater) && inWater == false
    {
        inWater = true;
        playSFX(sfxSplash);
    
        var currentWater;
        currentWater = instance_place(x, y, objWater);
        instance_create(x, currentWater.bbox_top+1, objSplash);
    }

    if inWater == true
    {
        currentGrav = gravWater;
        currentJumpSpeed = jumpSpeedWater;
    
        bubbleTimer += 1;
        if bubbleTimer >= 10
        {
            bubbleTimer = 0;
            if !instance_exists(objAirBubble)
                instance_create(x, y, objAirBubble);
        }
    }
    else
    {
        currentGrav = grav;
        currentJumpSpeed = jumpSpeed;
        bubbleTimer = 0;
    }

    //Leaving the water
    if inWater == true
    {
        var wtr;
        wtr = instance_place(x, y-global.yspeed, objWater);
        if wtr >= 0
        {
            if bbox_bottom < wtr.bbox_top
            {
                instance_create(x, wtr.bbox_top+1, objSplash);
                inWater = false;
                playSFX(sfxSplash);
            }
        }
    }

    //Gravity
    if ground == false && canGravity == true
    {
        global.yspeed += currentGrav;
        if global.yspeed > maxVspeed
            global.yspeed = maxVspeed;
    }

    //Variables on the previous frame
    prevGround = ground;
    prevXScale = image_xscale;
}