412 lines
10 KiB
Plaintext
412 lines
10 KiB
Plaintext
|
{
|
|||
|
ReverseDirection makes the actor to go in the opposite direction,
|
|||
|
it only works when the actor is moving left or right
|
|||
|
}
|
|||
|
PROCEDURE ReverseDirection(VAR a : ActorType);
|
|||
|
BEGIN
|
|||
|
CASE a.Dir OF
|
|||
|
LEFT : a.Dir := RIGHT;
|
|||
|
RIGHT : a.Dir := LEFT;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
OnSolid returns true if standing on something solid i.e. Floor,
|
|||
|
Disappearing floor or a Ladder
|
|||
|
}
|
|||
|
FUNCTION OnSolid(a : ActorType) : BOOLEAN;
|
|||
|
BEGIN
|
|||
|
OnSolid := (m.Field[a.Y + 1][a.X] IN ['=', '-', 'H', '|'])
|
|||
|
OR (m.Field[a.Y][a.X] = 'H');
|
|||
|
END;
|
|||
|
|
|||
|
FUNCTION EmptySpace(x, y : INTEGER) : BOOLEAN;
|
|||
|
BEGIN
|
|||
|
IF (x < 1) OR (x > LevelCols) THEN
|
|||
|
EmptySpace := TRUE
|
|||
|
ELSE
|
|||
|
EmptySpace := NOT (m.Field[y][x] IN ['|', '=']);
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
AboveLadder returns true when the actor is a above a Ladder
|
|||
|
}
|
|||
|
FUNCTION AboveLadder(a : ActorType) : BOOLEAN;
|
|||
|
BEGIN
|
|||
|
AboveLadder := m.Field[a.Y + 1][a.X] = 'H';
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
OnEater returns true when the actor is standing on a Eater
|
|||
|
}
|
|||
|
FUNCTION OnEater(a : ActorType) : BOOLEAN;
|
|||
|
BEGIN
|
|||
|
OnEater := m.Field[a.Y][a.X] = '*';
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
ClampToPlayfield makes sure that if the actor tries to walk or jump off
|
|||
|
the playfield edges the actor stays inside the playfield and starts falling
|
|||
|
}
|
|||
|
PROCEDURE ClampToPlayfield(VAR a : ActorType);
|
|||
|
BEGIN
|
|||
|
IF a.Dir IN [LEFT, JUMPLEFT] THEN BEGIN
|
|||
|
IF a.X < 1 THEN BEGIN
|
|||
|
a.X := 1;
|
|||
|
a.Dir := STOPPED;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
IF a.Dir IN [RIGHT, JUMPRIGHT] THEN BEGIN
|
|||
|
IF a.X > LevelCols THEN BEGIN
|
|||
|
a.X := LevelCols;
|
|||
|
a.Dir := STOPPED;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
InitActor set the fields of an Actor type to reasonable
|
|||
|
initial values
|
|||
|
}
|
|||
|
PROCEDURE InitActor(VAR a : ActorType; t : KindType; xy : XYtype);
|
|||
|
BEGIN
|
|||
|
a.AType := t;
|
|||
|
a.X := xy.x;
|
|||
|
a.Y := xy.y;
|
|||
|
a.Ch := 'X';
|
|||
|
a.JumpStep := 0;
|
|||
|
CASE t OF
|
|||
|
ALAD:
|
|||
|
BEGIN
|
|||
|
a.Ch := 'g';
|
|||
|
a.Dir := STOPPED;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END;
|
|||
|
AROCK:
|
|||
|
BEGIN
|
|||
|
a.Ch := 'o';
|
|||
|
a.Dir := PENDING;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
Set the Lad's character based on their current direction
|
|||
|
}
|
|||
|
PROCEDURE UpdateLadChar(VAR a : ActorType);
|
|||
|
BEGIN
|
|||
|
WITH a DO
|
|||
|
CASE Dir OF
|
|||
|
STOPPED: Ch := 'g';
|
|||
|
RIGHT, JUMPRIGHT: Ch := 'p';
|
|||
|
LEFT, JUMPLEFT: Ch := 'q';
|
|||
|
FALLING: Ch := 'b';
|
|||
|
UP, DOWN: Ch := 'p';
|
|||
|
JUMP:
|
|||
|
CASE a.DirRequest OF
|
|||
|
NONE, STOPPED: Ch := 'g';
|
|||
|
RIGHT, JUMPRIGHT: Ch := 'p';
|
|||
|
LEFT, JUMPLEFT: Ch := 'q';
|
|||
|
END;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
Update an actor's direction to the latest's request
|
|||
|
}
|
|||
|
PROCEDURE UpdateDir(VAR a : ActorType);
|
|||
|
BEGIN
|
|||
|
a.Dir := a.DirRequest;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END;
|
|||
|
|
|||
|
{
|
|||
|
MoveActor handles the movements of an Actor
|
|||
|
}
|
|||
|
PROCEDURE MoveActor(VAR a : ActorType);
|
|||
|
LABEL
|
|||
|
loopAgain;
|
|||
|
VAR
|
|||
|
jd : ActionType;
|
|||
|
i : INTEGER;
|
|||
|
dispenser : DispenserPointerType;
|
|||
|
BEGIN
|
|||
|
|
|||
|
loopAgain: { If just started falling we need to retest all conditions }
|
|||
|
|
|||
|
{ A STONE can only be LEFT/RIGHT/DOWN/FALLING or PENDING }
|
|||
|
IF a.AType = AROCK THEN BEGIN
|
|||
|
IF (a.Dir = PENDING) AND (a.DirRequest = NONE) THEN
|
|||
|
EXIT;
|
|||
|
|
|||
|
{ If stopped select a random direction }
|
|||
|
IF a.Dir = STOPPED THEN BEGIN
|
|||
|
CASE Random(2) OF
|
|||
|
0: IF (a.X > 1) THEN
|
|||
|
IF EmptySpace(a.X - 1, a.Y) THEN
|
|||
|
a.DirRequest := LEFT
|
|||
|
ELSE
|
|||
|
a.DirRequest := RIGHT
|
|||
|
ELSE
|
|||
|
a.DirRequest := RIGHT;
|
|||
|
1: IF (a.X < LevelCols) THEN
|
|||
|
IF EmptySpace(a.X + 1, a.Y) THEN
|
|||
|
a.DirRequest := RIGHT
|
|||
|
ELSE
|
|||
|
a.DirRequest := LEFT
|
|||
|
ELSE
|
|||
|
a.DirRequest := LEFT;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
{ Just reverse direction if at the playfield edge }
|
|||
|
IF (a.X = 1) OR (a.X = LevelCols) THEN
|
|||
|
ReverseDirection(a);
|
|||
|
|
|||
|
{ Start to fall if not on solid ground }
|
|||
|
IF (a.Dir <> FALLING) AND NOT OnSolid(a) THEN
|
|||
|
a.DirRequest := FALLING;
|
|||
|
|
|||
|
{ If Der rock just rolled over the top of a ladder then randomize direction }
|
|||
|
IF AboveLadder(a) AND (a.Dir IN [LEFT, RIGHT]) THEN
|
|||
|
CASE Random(4) OF
|
|||
|
0: a.DirRequest := LEFT;
|
|||
|
1: a.DirRequest := RIGHT;
|
|||
|
ELSE a.DirRequest := DOWN;
|
|||
|
END;
|
|||
|
|
|||
|
{ If on an Eater kill the stone }
|
|||
|
IF OnEater(a) THEN BEGIN
|
|||
|
dispenser := dispensers;
|
|||
|
IF numDispensers > 1 THEN BEGIN
|
|||
|
FOR i := 1 TO Random(numDispensers) DO
|
|||
|
dispenser := dispenser^.next;
|
|||
|
END;
|
|||
|
InitActor(a, AROCK, dispenser^.xy);
|
|||
|
m.AnyRocksPending := TRUE;
|
|||
|
END;
|
|||
|
END; { of stone only handling --------------------- }
|
|||
|
|
|||
|
{ If stopped or going left or going right and }
|
|||
|
{ request to do something else, then try to do it }
|
|||
|
IF (a.DirRequest <> NONE) THEN BEGIN
|
|||
|
CASE a.Dir OF
|
|||
|
STOPPED, PENDING:
|
|||
|
IF a.DirRequest IN [LEFT, RIGHT, UP, DOWN, FALLING] THEN
|
|||
|
UpdateDir(a);
|
|||
|
|
|||
|
JUMPUP:
|
|||
|
IF a.DirRequest = LEFT THEN
|
|||
|
a.Dir := JUMPLEFT
|
|||
|
ELSE IF a.DirRequest = RIGHT THEN
|
|||
|
a.Dir := JUMPRIGHT;
|
|||
|
|
|||
|
RIGHT:
|
|||
|
IF a.DirRequest IN [LEFT, STOPPED] THEN
|
|||
|
UpdateDir(a);
|
|||
|
|
|||
|
LEFT:
|
|||
|
IF a.DirRequest IN [RIGHT, STOPPED] THEN
|
|||
|
UpdateDir(a);
|
|||
|
|
|||
|
UP, DOWN:
|
|||
|
IF a.DirRequest IN [STOPPED, UP, DOWN, RIGHT, LEFT] THEN
|
|||
|
UpdateDir(a);
|
|||
|
|
|||
|
JUMPUP:
|
|||
|
IF a.DirRequest = LEFT THEN
|
|||
|
a.Dir := JUMPLEFT
|
|||
|
ELSE
|
|||
|
a.Dir := JUMPRIGHT;
|
|||
|
|
|||
|
JUMPRIGHT, JUMPLEFT:
|
|||
|
IF a.DirRequest = STOPPED THEN
|
|||
|
UpdateDir(a);
|
|||
|
|
|||
|
PENDING:
|
|||
|
UpdateDir(a);
|
|||
|
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
{ Handle starting of jumps }
|
|||
|
IF (a.DirRequest = JUMP) THEN BEGIN
|
|||
|
IF OnSolid(a) THEN BEGIN
|
|||
|
CASE a.Dir OF
|
|||
|
|
|||
|
STOPPED, FALLING: BEGIN
|
|||
|
a.DirRequest := STOPPED;
|
|||
|
a.Dir := JUMPUP;
|
|||
|
a.JumpStep := 1;
|
|||
|
END;
|
|||
|
|
|||
|
LEFT: BEGIN
|
|||
|
a.DirRequest := a.Dir;
|
|||
|
a.Dir := JUMPLEFT;
|
|||
|
a.JumpStep := 1;
|
|||
|
END;
|
|||
|
|
|||
|
JUMPLEFT: BEGIN
|
|||
|
a.DirRequest := LEFT;
|
|||
|
a.Dir := JUMPLEFT;
|
|||
|
a.JumpStep := 1;
|
|||
|
END;
|
|||
|
|
|||
|
RIGHT: BEGIN
|
|||
|
a.DirRequest := a.Dir;
|
|||
|
a.Dir := JUMPRIGHT;
|
|||
|
a.JumpStep := 1;
|
|||
|
END;
|
|||
|
|
|||
|
JUMPRIGHT: BEGIN
|
|||
|
a.DirRequest := RIGHT;
|
|||
|
a.Dir := JumpRIGHT;
|
|||
|
a.JumpStep := 1;
|
|||
|
END;
|
|||
|
END
|
|||
|
END ELSE BEGIN
|
|||
|
CASE a.Dir OF
|
|||
|
JUMPUP, FALLING: a.DirRequest := STOPPED;
|
|||
|
JUMPRIGHT: a.DirRequest := RIGHT;
|
|||
|
JUMPLEFT: a.DirRequest := LEFT;
|
|||
|
END;
|
|||
|
END;
|
|||
|
END ELSE IF (a.DirRequest = UP) AND (m.Field[a.Y][a.X] = 'H') THEN BEGIN
|
|||
|
{ If at a ladder and want to go up }
|
|||
|
a.Dir := UP;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END ELSE IF(a.DirRequest = DOWN) AND
|
|||
|
((m.Field[a.Y][a.X] = 'H') OR (m.Field[a.Y + 1][a.X] = 'H')) THEN BEGIN
|
|||
|
a.Dir := DOWN;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END;
|
|||
|
|
|||
|
CASE a.Dir OF
|
|||
|
|
|||
|
JUMPUP, JUMPLEFT, JUMPRIGHT: BEGIN
|
|||
|
{ Do the jumping }
|
|||
|
jd := jumpPaths[a.Dir, a.JumpStep];
|
|||
|
IF (a.X + dirs[jd].x >= 1) AND (a.X + dirs[jd].x <= LevelCols) THEN BEGIN
|
|||
|
CASE m.Field[a.Y + dirs[jd].y][a.X + dirs[jd].x] OF
|
|||
|
|
|||
|
'=', '|', '-' : BEGIN
|
|||
|
{ If bumped into something try falling }
|
|||
|
IF OnSolid(a) THEN BEGIN
|
|||
|
a.Dir := a.DirRequest;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END ELSE BEGIN
|
|||
|
CASE a.Dir OF
|
|||
|
JUMPUP: a.DirRequest := STOPPED;
|
|||
|
JUMPRIGHT: a.DirRequest := RIGHT;
|
|||
|
JUMPLEFT: a.DirRequest := LEFT;
|
|||
|
END;
|
|||
|
a.Dir := FALLING;
|
|||
|
END;
|
|||
|
a.JumpStep := 0;
|
|||
|
END;
|
|||
|
|
|||
|
'H': BEGIN { Jumping onto a ladder }
|
|||
|
a.Y := a.Y + dirs[jd].y;
|
|||
|
a.X := a.X + dirs[jd].x;
|
|||
|
a.Dir := STOPPED;
|
|||
|
a.DirRequest := NONE;
|
|||
|
a.JumpStep := 0;
|
|||
|
END;
|
|||
|
|
|||
|
ELSE BEGIN
|
|||
|
{ Just jumping in air }
|
|||
|
a.X := a.X + dirs[jd].x;
|
|||
|
a.Y := a.Y + dirs[jd].y;
|
|||
|
a.JumpStep := SUCC(a.JumpStep);
|
|||
|
IF (a.JumpStep > JumpsLen) THEN BEGIN
|
|||
|
UpdateDir(a);
|
|||
|
a.JumpStep := 0;
|
|||
|
END ELSE IF (jumpPaths[a.Dir][a.JumpStep] = ACTIONEND) THEN BEGIN
|
|||
|
UpdateDir(a);
|
|||
|
a.JumpStep := 0;
|
|||
|
END;
|
|||
|
END;
|
|||
|
END;
|
|||
|
END ELSE BEGIN
|
|||
|
IF OnSolid(a) THEN BEGIN
|
|||
|
a.Dir := a.DirRequest;
|
|||
|
a.DirRequest := NONE;
|
|||
|
END ELSE BEGIN
|
|||
|
a.Dir := FALLING;
|
|||
|
a.DirRequest := STOPPED;
|
|||
|
a.JumpStep := 0;
|
|||
|
END;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
STOPPED:
|
|||
|
IF NOT OnSolid(a) THEN
|
|||
|
a.Dir := FALLING;
|
|||
|
|
|||
|
FALLING: BEGIN
|
|||
|
{ If falling then continue doing that until not in free space anymore, }
|
|||
|
{ then continue the previous direction (if any) }
|
|||
|
IF OnSolid(a) THEN
|
|||
|
IF a.DirRequest = NONE THEN
|
|||
|
a.DirRequest := STOPPED
|
|||
|
ELSE
|
|||
|
a.Dir := a.DirRequest
|
|||
|
ELSE
|
|||
|
a.Y := Succ(a.Y);
|
|||
|
END;
|
|||
|
|
|||
|
UP:
|
|||
|
{ Climb up until ladder is no more }
|
|||
|
IF m.Field[a.Y - 1][a.X] IN ['H', '&', '$'] THEN
|
|||
|
a.Y := Pred(a.Y)
|
|||
|
ELSE
|
|||
|
a.Dir := STOPPED;
|
|||
|
|
|||
|
DOWN:
|
|||
|
{ Climb down until ladder is no more }
|
|||
|
IF a.Dir = DOWN THEN
|
|||
|
IF m.Field[a.Y + 1][a.X] IN ['H', '&', '$', ' ', '^', '.'] THEN
|
|||
|
a.Y := Succ(a.Y)
|
|||
|
ELSE
|
|||
|
a.Dir := STOPPED;
|
|||
|
|
|||
|
LEFT: BEGIN
|
|||
|
{ Stepped out into the void? Then start falling, }
|
|||
|
{ but remember the previous direction }
|
|||
|
IF NOT OnSolid(a) THEN BEGIN
|
|||
|
a.DirRequest := a.Dir;
|
|||
|
a.Dir := FALLING;
|
|||
|
GOTO loopAgain;
|
|||
|
END;
|
|||
|
IF EmptySpace(a.X - 1, a.Y) THEN
|
|||
|
a.X := Pred(a.X)
|
|||
|
ELSE
|
|||
|
a.DirRequest := STOPPED;
|
|||
|
END;
|
|||
|
|
|||
|
RIGHT: BEGIN
|
|||
|
{ Stepped out into the void? Then start falling, }
|
|||
|
{ but remember the previous direction }
|
|||
|
IF NOT OnSolid(a) THEN BEGIN
|
|||
|
a.DirRequest := a.Dir;
|
|||
|
a.Dir := FALLING;
|
|||
|
GOTO loopAgain;
|
|||
|
END;
|
|||
|
IF EmptySpace(a.X + 1, a.Y) THEN
|
|||
|
a.X := Succ(a.X)
|
|||
|
ELSE
|
|||
|
a.DirRequest := STOPPED;
|
|||
|
END;
|
|||
|
END;
|
|||
|
|
|||
|
{ Don't allow actor to end up outside of the playfield }
|
|||
|
ClampToPlayfield(a);
|
|||
|
IF a.AType = ALAD THEN
|
|||
|
UpdateLadChar(a);
|
|||
|
END;
|
|||
|
|