In this document:
a: Flag indicating whether the Boulder is currently considered to be "falling" or "stationary". The flag is set (1) when falling, clear (0) when stationary. It is recommended that all boulders begin life as stationary boulders.
If a boulder is discovered to have a stationary, rounded object (stationary boulder, stationary diamond, brick wall) below it, then the boulder will attempt to roll off the object below. Note that falling boulders and diamonds can roll off things too; they don't have to come to a halt first.
In order for a boulder or diamond to roll, not only must the object below be a brick wall, stationary boulder or stationary diamond, but the objects to the left and diagonally left/down (or right and diagonally right/down) must both be space. Preference is given to rolling to the left over rolling to the right. If these criteria are satisfied, the boulder or diamond is moved one space immediately to the side (not diagonally down) and is changes state to be falling (if it wasn't already).
If the boulder is not able to roll, it remains where it is, and changes state into a stationary boulder (if it wasn't already).
procedure ScanStationaryBoulder(in positionType boulderPosition)
# Local variables
positionType NewPosition;
objectType theObjectBelow;
# If the boulder can fall, move it down and mark it as falling.
NewPosition := GetRelativePosition(boulderPosition, down1);
theObjectBelow := GetObjectAtPosition(NewPosition);
if (theObjectBelow == objSpace) then
PlaceObject(objBoulder, attribFalling, NewPosition);
PlaceObject(objSpace, attribNone, boulderPosition);
RequestSound(boulderSound); # yes, even when it starts falling. This applies to diamonds too (requests diamondSound).
else
# Failing that, see if the boulder can roll
if (CanRollOff(theObjectBelow)) then
# Try rolling left
NewPosition := GetRelativePosition(boulderPosition, left1);
if ((GetObjectAtPosition(NewPosition) == objSpace) and (GetObjectAtPosition(GetRelativePosition(boulderPosition, down1left)) == objSpace)) then
PlaceObject(objBoulder, attribFalling, NewPosition);
PlaceObject(objSpace, attribNone, boulderPosition);
else
# Try rolling right
NewPosition := GetRelativePosition(boulderPosition, right1);
if ((GetObjectAtPosition(NewPosition) == objSpace) and (GetObjectAtPosition(GetRelativePosition(boulderPosition, down1right)) == objSpace)) then
PlaceObject(objBoulder, attribFalling, NewPosition);
PlaceObject(objSpace, attribNone, boulderPosition);
endif
endif
endif
endif
endprocedure
##
procedure ScanFallingBoulder(in positionType boulderPosition;
in/out magicWallStatusType magicWallStatus)
# Local variables
positionType NewPosition;
objectType theObjectBelow;
# If the boulder can continue to fall, move it down.
NewPosition := GetRelativePosition(boulderPosition, down1);
theObjectBelow := GetObjectAtPosition(NewPosition);
if (theObjectBelow == objSpace) then
PlaceObject(objBoulder, attribFalling, NewPosition);
PlaceObject(objSpace, attribNone, boulderPosition); # ie old position
# If the object below is a magic wall, we activate it (if it's off), and
# morph into a diamond two spaces below if it's now active. If the wall
# is expired, we just disappear (with a sound still though).
elsif (theObjectBelow == objMagicWall) then
if (magicWallStatus == kMagicWallOff) then
magicWallStatus := kMagicWallOn);
endif
if (magicWallStatus == kMagicWallOn) then
NewPosition := GetRelativePosition(boulderPositon, down2);
if (GetObjectAtPosition(NewPosition) == objSpace) then
PlaceObject(objDiamond, attribFalling, NewPosition);
endif
endif
PlaceObject(objSpace, attribNone, boulderPosition);
RequestSound(diamondSound); # note: Diamond sound
endif
# Failing that, we've hit something, so we play a sound and see if we can roll.
else
RequestSound(boulderSound);
if (CanRollOff(theObjectBelow)) then
# Try rolling left
NewPosition := GetRelativePosition(boulderPosition, left1);
if ((GetObjectAtPosition(NewPosition) == objSpace) and (GetObjectAtPosition(GetRelativePosition(boulderPosition, down1left)) == objSpace)) then
PlaceObject(objBoulder, attribFalling, NewPosition);
PlaceObject(objSpace, attribNone, boulderPosition);
else
# Try rolling right
NewPosition := GetRelativePosition(boulderPosition, right1);
if ((GetObjectAtPosition(NewPosition) == objSpace) and (GetObjectAtPosition(GetRelativePosition(boulderPosition, down1right)) == objSpace)) then
PlaceObject(objBoulder, attribFalling, NewPosition);
PlaceObject(objSpace, attribNone, boulderPosition);
# The boulder is sitting on an object which it could roll off, but it can't
# roll, so it comes to a stop.
else
PlaceObject(objBoulder, attribStationary, boulderPosition);
endif
endif
# Failing all that, we see whether we've hit something explosive
elsif (ImpactExplosive(theObjectBelow) then
Explode(NewPosition, GetExplosionType(theObjectBelow));
# And lastly, failing everything, the boulder comes to a stop.
else
PlaceObject(objBoulder, attribStationary, boulderPosition);
endif
endif
endprocedure
##
function CanRollOff(in objectType anObjectBelow):Boolean
# If the specified object is one which a boulder or diamond can roll off,
# return true otherwise return false.
# First of all, only objects which have the property of being "rounded" are
# are ones which things can roll off. Secondly, if the object is a boulder
# or diamond, the boulder or diamond must be stationary, not falling.
# We're going to assume that GetObjectProperty() automatically returns "true"
# for objBoulderStationary, objDiamondStationary, objBrickWall, and returns "false"
# for everything else (including objBoulderFalling and objDiamondFalling).
return (GetObjectProperty(anObjectBelow, propertyRounded));
endfunction
##
function ImpactExplosive(in objectType anObject):Boolean
# If the specified object has the property of being something that can
# explode, return true otherwise return false.
# ImpactExplosive objects are: Rockford, Firefly, Butterfly.
return (GetObjectProperty(anObject, propertyImpactExplosive)); # true/false
endfunction
##
function GetExplosionType(in objectType anObject):explosionType;
# Assuming that the specified object is in fact explosive, returns the type
# of explosion (explodeToSpace or explodeToDiamonds)
# Explosive objects are: Rockford, Firefly, Butterfly.
ASSERT (Explosive(anObjectBelow));
return (GetObjectProperty(anObject, propertyExplosionType));
endfunction
##