static void TestIfPlayerTouchesCustomElement(int, int);
static void TestIfElementTouchesCustomElement(int, int);
+static void ChangeElement(int, int, int);
static boolean CheckTriggeredElementSideChange(int, int, int, int, int);
static boolean CheckTriggeredElementChange(int, int, int, int);
static boolean CheckElementSideChange(int, int, int, int, int, int);
NULL,
NULL
},
+ {
+ EL_SP_EXIT_OPENING,
+ EL_SP_EXIT_OPEN,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_SP_EXIT_CLOSING,
+ EL_SP_EXIT_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
{
EL_SWITCHGATE_OPENING,
EL_SWITCHGATE_OPEN,
for (j=0; j < ei->num_change_pages; j++)
{
- if (!ei->change_page->can_change)
+ if (!ei->change_page[j].can_change)
continue;
if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION))
game.timegate_time_left = 0;
game.switchgate_pos = 0;
game.balloon_dir = MV_NO_MOVING;
+ game.gravity = level.initial_gravity;
game.explosions_delayed = TRUE;
game.envelope_active = FALSE;
Feld[x][y] = level.field[x][y];
MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
ChangeDelay[x][y] = 0;
+ ChangePage[x][y] = -1;
Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
AmoebaNr[x][y] = 0;
JustStopped[x][y] = 0;
}
/* close exit door after last player */
- if (Feld[ExitX][ExitY] == EL_EXIT_OPEN && AllPlayersGone)
+ if ((Feld[ExitX][ExitY] == EL_EXIT_OPEN ||
+ Feld[ExitX][ExitY] == EL_SP_EXIT_OPEN) && AllPlayersGone)
{
- Feld[ExitX][ExitY] = EL_EXIT_CLOSING;
+ int element = Feld[ExitX][ExitY];
+
+ Feld[ExitX][ExitY] = (element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
+ EL_SP_EXIT_CLOSING);
- PlaySoundLevelElementAction(ExitX, ExitY, EL_EXIT_OPEN, ACTION_CLOSING);
+ PlaySoundLevelElementAction(ExitX, ExitY, element, ACTION_CLOSING);
}
/* Hero disappears */
AmoebaNr[x][y] = 0;
ChangeDelay[x][y] = 0;
+ ChangePage[x][y] = -1;
Pushed[x][y] = FALSE;
GfxElement[x][y] = EL_UNDEFINED;
{
struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1];
+#if 1
+ RemoveField(x, y);
+ DrawLevelField(x, y);
+#endif
+
if (player->present)
{
while (player->MovPos)
ScrollFigure(player, SCROLL_GO_ON);
ScrollScreen(NULL, SCROLL_GO_ON);
FrameCounter++;
+
DrawAllPlayers();
+
BackToFront();
+ Delay(GAME_FRAME_DELAY);
}
+ player->is_moving = FALSE;
+
+#if 0
RemoveField(player->jx, player->jy);
+#endif
+
DrawLevelField(player->jx, player->jy);
}
+ Feld[x][y] = element;
InitPlayerField(x, y, element, TRUE);
if (player == local_player)
ScrollLevel(dx, dy);
DrawAllPlayers();
- /* scroll in to steps of half tile size to make things smoother */
+ /* scroll in two steps of half tile size to make things smoother */
BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
FlushDisplay();
Delay(GAME_FRAME_DELAY);
element = Feld[x][y] = Back[x][y];
Back[x][y] = 0;
- MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = ChangeDelay[x][y] = 0;
+ MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
+ ChangeDelay[x][y] = 0;
+ ChangePage[x][y] = -1;
+
InitField(x, y, FALSE);
if (CAN_MOVE(element))
InitMovDir(x, y);
element1 != EL_DRAGON && element2 != EL_DRAGON &&
element1 != EL_FLAMES && element2 != EL_FLAMES)
{
+#if 1
+ ResetGfxAnimation(x, y);
+ GfxAction[x][y] = ACTION_ATTACKING;
+#endif
+
if (IS_PLAYER(x, y))
DrawPlayerField(x, y);
else
Feld[newx1][newy1] = EL_FLAMES;
if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
Feld[newx2][newy2] = EL_FLAMES;
+
return;
}
}
/* copy element change control values to new field */
ChangeDelay[newx][newy] = ChangeDelay[x][y];
+ ChangePage[newx][newy] = ChangePage[x][y];
Changed[newx][newy] = Changed[x][y];
ChangeEvent[newx][newy] = ChangeEvent[x][y];
ChangeDelay[x][y] = 0;
+ ChangePage[x][y] = -1;
Changed[x][y] = CE_BITMASK_DEFAULT;
ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
(newy == lev_fieldy - 1 || !IS_FREE(x, newy + 1)))
Impact(x, newy);
- if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
- CheckElementSideChange(newx, newy, element, direction, CE_COLLISION, -1);
-
#if 1
TestIfElementTouchesCustomElement(x, y); /* for empty space */
#endif
+#if 0
+ if (ChangePage[newx][newy] != -1) /* delayed change */
+ ChangeElement(newx, newy, ChangePage[newx][newy]);
+#endif
+
+ if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
+ CheckElementSideChange(newx, newy, Feld[newx][newy], direction,
+ CE_COLLISION, -1);
+
TestIfPlayerTouchesCustomElement(newx, newy);
TestIfElementTouchesCustomElement(newx, newy);
}
return;
}
- Feld[x][y] = EL_SP_EXIT_OPEN;
+ if (AllPlayersGone) /* do not re-open exit door closed after last player */
+ return;
+
+ Feld[x][y] = EL_SP_EXIT_OPENING;
PlaySoundLevelNearest(x, y, SND_CLASS_SP_EXIT_OPENING);
}
static void ChangeElement(int x, int y, int page)
{
int element = MovingOrBlocked2Element(x, y);
- struct ElementChangeInfo *change = &element_info[element].change_page[page];
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementChangeInfo *change = &ei->change_page[page];
#if 0
#ifdef DEBUG
}
else /* finish element change */
{
+ if (ChangePage[x][y] != -1) /* remember page from delayed change */
+ {
+ page = ChangePage[x][y];
+ ChangePage[x][y] = -1;
+ }
+
if (IS_MOVING(x, y)) /* never change a running system ;-) */
{
ChangeDelay[x][y] = 1; /* try change after next move step */
+ ChangePage[x][y] = page; /* remember page to use for change */
return;
}
{
struct ElementChangeInfo *change = &element_info[element].change_page[j];
- if (change->sides & trigger_side &&
+ if (change->can_change &&
+ change->sides & trigger_side &&
change->trigger_element == trigger_element)
{
change_element = TRUE;
Changed[x][y] = CE_BITMASK_DEFAULT;
ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
+#if DEBUG
+ if (ChangePage[x][y] != -1 && ChangeDelay[x][y] != 1)
+ {
+ printf("GameActions(): x = %d, y = %d: ChangePage != -1\n", x, y);
+ printf("GameActions(): This should never happen!\n");
+
+ ChangePage[x][y] = -1;
+ }
+#endif
+
Stop[x][y] = FALSE;
if (JustStopped[x][y] > 0)
JustStopped[x][y]--;
/* this may take place after moving, so 'element' may have changed */
if (IS_CHANGING(x, y))
{
+#if 0
+ ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] :
+ element_info[element].event_page_nr[CE_DELAY]);
+#else
ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]);
+#endif
+
element = Feld[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
}
}
}
- if (TimeFrames >= (1000 / GameFrameDelay))
+ if (TimeFrames >= FRAMES_PER_SECOND)
{
TimeFrames = 0;
TimePlayed++;
static void CheckGravityMovement(struct PlayerInfo *player)
{
- if (level.gravity && !player->programmed_action)
+ if (game.gravity && !player->programmed_action)
{
int move_dir_vertical = player->action & (MV_UP | MV_DOWN);
int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT);
ScrollFigure(player, SCROLL_INIT);
-#if 1
+#if 0
if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
{
CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy], leave_side,
#if 1
player->Switching = FALSE;
#endif
+
+
+#if 1
+ {
+ static int change_sides[4][2] =
+ {
+ /* enter side leave side */
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */
+ };
+ int move_direction = player->MovDir;
+ int enter_side = change_sides[MV_DIR_BIT(move_direction)][0];
+ int leave_side = change_sides[MV_DIR_BIT(move_direction)][1];
+
+#if 1
+ if (IS_CUSTOM_ELEMENT(Feld[old_jx][old_jy]))
+ {
+ CheckTriggeredElementSideChange(old_jx, old_jy, Feld[old_jx][old_jy],
+ leave_side, CE_OTHER_GETS_LEFT);
+ CheckElementSideChange(old_jx, old_jy, Feld[old_jx][old_jy],
+ leave_side, CE_LEFT_BY_PLAYER, -1);
+ }
+
+ if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
+ {
+ CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy],
+ enter_side, CE_OTHER_GETS_ENTERED);
+ CheckElementSideChange(jx, jy, Feld[jx][jy],
+ enter_side, CE_ENTERED_BY_PLAYER, -1);
+ }
+#endif
+
+ }
+#endif
+
+
}
else
{
player->last_jy = jy;
if (Feld[jx][jy] == EL_EXIT_OPEN ||
- Feld[jx][jy] == EL_SP_EXIT_OPEN)
+ Feld[jx][jy] == EL_SP_EXIT_OPEN ||
+ Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */
{
DrawPlayer(player); /* needed here only to cleanup last field */
RemoveHero(player);
if (local_player->friends_still_needed == 0 ||
- Feld[jx][jy] == EL_SP_EXIT_OPEN)
+ IS_SP_ELEMENT(Feld[jx][jy]))
player->LevelSolved = player->GameOver = TRUE;
}
{ CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */
{ CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */
};
+ static int touch_dir[4] =
+ {
+ MV_LEFT | MV_RIGHT,
+ MV_UP | MV_DOWN,
+ MV_UP | MV_DOWN,
+ MV_LEFT | MV_RIGHT
+ };
boolean change_center_element = FALSE;
int center_element_change_page = 0;
- int center_element = Feld[x][y];
+#if 0
+ int center_element = MovingOrBlocked2Element(x, y);
+#else
+ int center_element = Feld[x][y]; /* should always be non-moving! */
+#endif
int i, j;
+#if 0
+ if (center_element == EL_CUSTOM_START + 244)
+ printf("::: checking element %d at %d,%d... [%d]\n",
+ center_element, x, y, Feld[x][y + 1]);
+#endif
+
#if 0
if (check_changing) /* prevent this function from running into a loop */
return;
if (!IN_LEV_FIELD(xx, yy))
continue;
- border_element = Feld[xx][yy];
+#if 0
+ if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
+ border_element = Feld[xx][yy];
+ else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */
+ {
+#if 0
+ printf("::: moving && touching...\n");
+#endif
+
+ border_element = MovingOrBlocked2Element(xx, yy);
+ }
+ else
+ {
+#if 0
+ printf("::: moving && NOT touching...\n");
+#endif
+
+ continue; /* center and border element do not touch */
+ }
+#else
+
+#if 0
+ border_element = MovingOrBlocked2Element(xx, yy);
+#else
+ border_element = Feld[xx][yy]; /* may be moving! */
+#endif
+
+#endif
/* check for change of center element (but change it only once) */
if (IS_CUSTOM_ELEMENT(center_element) &&
struct ElementChangeInfo *change =
&element_info[center_element].change_page[j];
- if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ if (change->can_change &&
+ change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
change->sides & border_side &&
change->trigger_element == border_element)
{
struct ElementChangeInfo *change =
&element_info[border_element].change_page[j];
- if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ if (change->can_change &&
+ change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
change->sides & center_side &&
change->trigger_element == center_element)
{
+#if 0
+ printf("::: changing border element %d at %d,%d\n",
+ border_element, xx, yy);
+#endif
+
CheckElementSideChange(xx, yy, border_element, CH_SIDE_ANY,
CE_OTHER_IS_TOUCHING, j);
break;
}
if (change_center_element)
+ {
+#if 0
+ printf("::: changing center element %d at %d,%d\n",
+ center_element, x, y);
+#endif
+
CheckElementSideChange(x, y, center_element, CH_SIDE_ANY,
CE_OTHER_IS_TOUCHING, center_element_change_page);
+ }
#if 0
check_changing = FALSE;
element == EL_SP_GRAVITY_PORT_RIGHT ||
element == EL_SP_GRAVITY_PORT_UP ||
element == EL_SP_GRAVITY_PORT_DOWN)
- level.gravity = !level.gravity;
+ game.gravity = !game.gravity;
/* automatically move to the next field with double speed */
player->programmed_action = move_direction;
if (!player->key[element - EL_GATE_1_GRAY])
return MF_NO_ACTION;
}
- else if (element == EL_EXIT_OPEN || element == EL_SP_EXIT_OPEN)
+ else if (element == EL_EXIT_OPEN ||
+ element == EL_SP_EXIT_OPEN ||
+ element == EL_SP_EXIT_OPENING)
{
sound_action = ACTION_PASSING; /* player is passing exit */
}