My friend has struggled with this for months, and I thought she was just bad at programming, thinking the issue is simple, so I asked to look at the problem, and I can't solve it either after a day of trying. It's something which on the face of it seems like it should be trivially simple, yet no method I've tried works. The issue is...

How do you code movement like the geemer's there?
Basically we want this behavior:
Move right if you're on the floor. Move up if you come to a wall. Move on the ceiling if you come to that. Move down if you come to another wall.
E.g. If a geemer is surrounded in a cage, it would go around the inside of that cage in a counter-clockwise manner.
E.g. If a geemer is on a block floating in space, it would go around that block in a clockwise manner.
We've tried various methods, some of which seem to work but fail for some special cases. Here is one method. The code is GML but you should be able to work it out regardless.
if sprite_index == spr_geemer_top
if not place_free(x, y+1)
{
if not place_free(x+1, y)
sprite_index = spr_geemer_left
x += 1;
} else sprite_index = spr_geemer_right
if sprite_index == spr_geemer_right
if not place_free(x-1, y)
{
if not place_free(x, y+1)
sprite_index = spr_geemer_top
y += 1;
} else sprite_index = spr_geemer_bottom
and etc. for the other directions. This is her (komera's) method. This works for three directions but fails for one -- always the direction that's placed first in the script. I conceptually understand why one of the four must always fail, but can't put it into words.
Another method:
move_contact_solid(direction-90, -1);
if ((old_x == x) and (old_y == y))
direction += 90;
speed = 1;
old_x = x; old_y = y;
switch (direction)
{
case 180: sprite_index = spr_geemer_bottom; break;
case 0: sprite_index = spr_geemer_top; break;
case 270: sprite_index = spr_geemer_right; break;
case 90: sprite_index = spr_geemer_left; break;
}
I thought that would work, but it doesn't. They never change direction.
Another method:
if not place_free(x,y-1) direction=180;
if not place_free(x,y+1) direction=0;
if not place_free(x-1,y) direction=270;
if not place_free(x+1,y) direction=90;
speed=1;
if (vspeed>0 and not place_free(x,y+vspeed))
move_contact_solid(270,-1);
if (vspeed<0 and not place_free(x,y-vspeed))
move_contact_solid(90,-1);
if (hspeed>0 and not place_free(x+hspeed,y))
move_contact_solid(180,-1);
if (hspeed<0 and not place_free(x-hspeed,y))
move_contact_solid(0,-1);
switch (direction)
{
case 180: sprite_index = spr_geemer_bottom; break;
case 0: sprite_index = spr_geemer_top; break;
case 270: sprite_index = spr_geemer_right; break;
case 90: sprite_index = spr_geemer_left; break;
}
This one works for the inside of cages, but doesn't for the outside of blocks. They never change direction when on the outside of a block, but it works perfectly for the inside of cages.
Help! This problem is crazy! It should be simple to do this, I mean, Metroid did it, so why can't we figure it out?