g1->anim_mode == g2->anim_mode);
}
-void DrawAllPlayers(void)
+#define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
+
+enum
{
- int i;
+ DRAW_PLAYER_STAGE_INIT = 0,
+ DRAW_PLAYER_STAGE_LAST_FIELD,
+ DRAW_PLAYER_STAGE_FIELD_UNDER_PLAYER,
+#if DRAW_PLAYER_OVER_PUSHED_ELEMENT
+ DRAW_PLAYER_STAGE_ELEMENT_PUSHED,
+ DRAW_PLAYER_STAGE_PLAYER,
+#else
+ DRAW_PLAYER_STAGE_PLAYER,
+ DRAW_PLAYER_STAGE_ELEMENT_PUSHED,
+#endif
+ DRAW_PLAYER_STAGE_ELEMENT_OVER_PLAYER,
+ DRAW_PLAYER_STAGE_FIELD_OVER_PLAYER,
- for (i = 0; i < MAX_PLAYERS; i++)
- if (stored_player[i].active)
- DrawPlayer(&stored_player[i]);
-}
+ NUM_DRAW_PLAYER_STAGES
+};
-void DrawPlayerField(int x, int y)
+static void DrawPlayerExt(struct PlayerInfo *player, int drawing_stage)
{
- if (!IS_PLAYER(x, y))
+ static int static_last_player_graphic[MAX_PLAYERS];
+ static int static_last_player_frame[MAX_PLAYERS];
+ static boolean static_player_is_opaque[MAX_PLAYERS];
+ static boolean draw_player[MAX_PLAYERS];
+ int pnr = player->index_nr;
+
+ if (drawing_stage == DRAW_PLAYER_STAGE_INIT)
+ {
+ static_last_player_graphic[pnr] = getPlayerGraphic(player, player->MovDir);
+ static_last_player_frame[pnr] = player->Frame;
+ static_player_is_opaque[pnr] = FALSE;
+
+ draw_player[pnr] = TRUE;
+ }
+
+ if (!draw_player[pnr])
return;
- DrawPlayer(PLAYERINFO(x, y));
-}
+#if DEBUG
+ if (!IN_LEV_FIELD(player->jx, player->jy))
+ {
+ printf("DrawPlayerField(): x = %d, y = %d\n", player->jx, player->jy);
+ printf("DrawPlayerField(): This should never happen!\n");
-#define DRAW_PLAYER_OVER_PUSHED_ELEMENT 1
+ draw_player[pnr] = FALSE;
+
+ return;
+ }
+#endif
+
+ int last_player_graphic = static_last_player_graphic[pnr];
+ int last_player_frame = static_last_player_frame[pnr];
+ boolean player_is_opaque = static_player_is_opaque[pnr];
-void DrawPlayer(struct PlayerInfo *player)
-{
int jx = player->jx;
int jy = player->jy;
- int move_dir = player->MovDir;
+ int move_dir = (player->is_waiting ? player->dir_waiting : player->MovDir);
int dx = (move_dir == MV_LEFT ? -1 : move_dir == MV_RIGHT ? +1 : 0);
int dy = (move_dir == MV_UP ? -1 : move_dir == MV_DOWN ? +1 : 0);
int last_jx = (player->is_moving ? jx - dx : jx);
int last_jy = (player->is_moving ? jy - dy : jy);
int next_jx = jx + dx;
int next_jy = jy + dy;
- boolean player_is_moving = (player->MovPos ? TRUE : FALSE);
- boolean player_is_opaque = FALSE;
- int sx = SCREENX(jx), sy = SCREENY(jy);
- int sxx = 0, syy = 0;
- int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
- int graphic;
- int action = ACTION_DEFAULT;
- int last_player_graphic = getPlayerGraphic(player, move_dir);
- int last_player_frame = player->Frame;
- int frame = 0;
+ boolean player_is_moving = (player->MovPos != 0 ? TRUE : FALSE);
+ int sx = SCREENX(jx);
+ int sy = SCREENY(jy);
+ int sxx = (move_dir == MV_LEFT || move_dir == MV_RIGHT ? player->GfxPos : 0);
+ int syy = (move_dir == MV_UP || move_dir == MV_DOWN ? player->GfxPos : 0);
+ int element = Feld[jx][jy];
+ int last_element = Feld[last_jx][last_jy];
+ int action = (player->is_pushing ? ACTION_PUSHING :
+ player->is_digging ? ACTION_DIGGING :
+ player->is_collecting ? ACTION_COLLECTING :
+ player->is_moving ? ACTION_MOVING :
+ player->is_snapping ? ACTION_SNAPPING :
+ player->is_dropping ? ACTION_DROPPING :
+ player->is_waiting ? player->action_waiting :
+ ACTION_DEFAULT);
+
+ if (drawing_stage == DRAW_PLAYER_STAGE_INIT)
+ {
+ // ------------------------------------------------------------------------
+ // initialize drawing the player
+ // ------------------------------------------------------------------------
- // GfxElement[][] is set to the element the player is digging or collecting;
- // remove also for off-screen player if the player is not moving anymore
- if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
- GfxElement[jx][jy] = EL_UNDEFINED;
+ draw_player[pnr] = FALSE;
- if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
- return;
+ // GfxElement[][] is set to the element the player is digging or collecting;
+ // remove also for off-screen player if the player is not moving anymore
+ if (IN_LEV_FIELD(jx, jy) && !player_is_moving)
+ GfxElement[jx][jy] = EL_UNDEFINED;
-#if DEBUG
- if (!IN_LEV_FIELD(jx, jy))
- {
- printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
- printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
- printf("DrawPlayerField(): This should never happen!\n");
- return;
- }
-#endif
+ if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
+ return;
- if (element == EL_EXPLOSION)
- return;
+ if (element == EL_EXPLOSION)
+ return;
- action = (player->is_pushing ? ACTION_PUSHING :
- player->is_digging ? ACTION_DIGGING :
- player->is_collecting ? ACTION_COLLECTING :
- player->is_moving ? ACTION_MOVING :
- player->is_snapping ? ACTION_SNAPPING :
- player->is_dropping ? ACTION_DROPPING :
- player->is_waiting ? player->action_waiting : ACTION_DEFAULT);
+ InitPlayerGfxAnimation(player, action, move_dir);
- if (player->is_waiting)
- move_dir = player->dir_waiting;
+ draw_player[pnr] = TRUE;
+ }
+ else if (drawing_stage == DRAW_PLAYER_STAGE_LAST_FIELD)
+ {
+ // ------------------------------------------------------------------------
+ // draw things in the field the player is leaving, if needed
+ // ------------------------------------------------------------------------
- InitPlayerGfxAnimation(player, action, move_dir);
+ if (!IN_SCR_FIELD(sx, sy))
+ draw_player[pnr] = FALSE;
- // --------------------------------------------------------------------------
- // draw things in the field the player is leaving, if needed
- // --------------------------------------------------------------------------
+ if (!player->is_moving)
+ return;
- if (player->is_moving)
- {
if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
{
DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
last_element == EL_EM_DYNAMITE_ACTIVE ||
last_element == EL_SP_DISK_RED_ACTIVE)
DrawDynamite(last_jx, last_jy);
-#if 0
- /* !!! this is not enough to prevent flickering of players which are
- moving next to each others without a free tile between them -- this
- can only be solved by drawing all players layer by layer (first the
- background, then the foreground etc.) !!! => TODO */
- else if (!IS_PLAYER(last_jx, last_jy))
- DrawLevelField(last_jx, last_jy);
-#else
else
DrawLevelField(last_jx, last_jy);
-#endif
if (player->is_pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
DrawLevelElement(next_jx, next_jy, EL_EMPTY);
}
+ else if (drawing_stage == DRAW_PLAYER_STAGE_FIELD_UNDER_PLAYER)
+ {
+ // ------------------------------------------------------------------------
+ // draw things behind the player, if needed
+ // ------------------------------------------------------------------------
- if (!IN_SCR_FIELD(sx, sy))
- return;
+ if (Back[jx][jy])
+ {
+ DrawLevelElement(jx, jy, Back[jx][jy]);
- // --------------------------------------------------------------------------
- // draw things behind the player, if needed
- // --------------------------------------------------------------------------
+ return;
+ }
+
+ if (IS_ACTIVE_BOMB(element))
+ {
+ DrawLevelElement(jx, jy, EL_EMPTY);
+
+ return;
+ }
- if (Back[jx][jy])
- DrawLevelElement(jx, jy, Back[jx][jy]);
- else if (IS_ACTIVE_BOMB(element))
- DrawLevelElement(jx, jy, EL_EMPTY);
- else
- {
if (player_is_moving && GfxElement[jx][jy] != EL_UNDEFINED)
{
int old_element = GfxElement[jx][jy];
DrawGraphic(sx, sy, old_graphic, frame);
if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
- player_is_opaque = TRUE;
+ static_player_is_opaque[pnr] = TRUE;
}
else
{
GfxElement[jx][jy] = EL_UNDEFINED;
// make sure that pushed elements are drawn with correct frame rate
- graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
+ int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
if (player->is_pushing && player->is_moving && !IS_ANIM_MODE_CE(graphic))
GfxFrame[jx][jy] = player->StepFrame;
DrawLevelField(jx, jy);
}
}
-
-#if !DRAW_PLAYER_OVER_PUSHED_ELEMENT
- // -----------------------------------------------------------------------
- // draw player himself
- // -----------------------------------------------------------------------
-
- graphic = getPlayerGraphic(player, move_dir);
-
- // in the case of changed player action or direction, prevent the current
- // animation frame from being restarted for identical animations
- if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
- player->Frame = last_player_frame;
-
- frame = getGraphicAnimationFrame(graphic, player->Frame);
-
- if (player->GfxPos)
- {
- if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
- sxx = player->GfxPos;
- else
- syy = player->GfxPos;
- }
-
- if (player_is_opaque)
- DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
- else
- DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
-
- if (SHIELD_ON(player))
- {
- int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
- IMG_SHIELD_NORMAL_ACTIVE);
- int frame = getGraphicAnimationFrame(graphic, -1);
-
- DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
- }
-#endif
-
-#if DRAW_PLAYER_OVER_PUSHED_ELEMENT
- if (player->GfxPos)
+ else if (drawing_stage == DRAW_PLAYER_STAGE_ELEMENT_PUSHED)
{
- if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
- sxx = player->GfxPos;
- else
- syy = player->GfxPos;
- }
-#endif
+ // ------------------------------------------------------------------------
+ // draw things the player is pushing, if needed
+ // ------------------------------------------------------------------------
- // --------------------------------------------------------------------------
- // draw things the player is pushing, if needed
- // --------------------------------------------------------------------------
+ if (!player->is_pushing || !player->is_moving)
+ return;
- if (player->is_pushing && player->is_moving)
- {
- int px = SCREENX(jx), py = SCREENY(jy);
- int pxx = (TILEX - ABS(sxx)) * dx;
- int pyy = (TILEY - ABS(syy)) * dy;
int gfx_frame = GfxFrame[jx][jy];
- int graphic;
- int sync_frame;
- int frame;
-
if (!IS_MOVING(jx, jy)) // push movement already finished
{
element = Feld[next_jx][next_jy];
gfx_frame = GfxFrame[next_jx][next_jy];
}
- graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
-
- sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
- frame = getGraphicAnimationFrame(graphic, sync_frame);
+ int graphic = el_act_dir2img(element, ACTION_PUSHING, move_dir);
+ int sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
+ int frame = getGraphicAnimationFrame(graphic, sync_frame);
// draw background element under pushed element (like the Sokoban field)
if (game.use_masked_pushing && IS_MOVING(jx, jy))
else if (Back[next_jx][next_jy])
DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
+ int px = SCREENX(jx), py = SCREENY(jy);
+ int pxx = (TILEX - ABS(sxx)) * dx;
+ int pyy = (TILEY - ABS(syy)) * dy;
+
#if 1
// do not draw (EM style) pushing animation when pushing is finished
// (two-tile animations usually do not contain start and end frame)
DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
#endif
}
+ else if (drawing_stage == DRAW_PLAYER_STAGE_PLAYER)
+ {
+ // ------------------------------------------------------------------------
+ // draw player himself
+ // ------------------------------------------------------------------------
-#if DRAW_PLAYER_OVER_PUSHED_ELEMENT
- // -----------------------------------------------------------------------
- // draw player himself
- // -----------------------------------------------------------------------
-
- graphic = getPlayerGraphic(player, move_dir);
+ int graphic = getPlayerGraphic(player, move_dir);
- // in the case of changed player action or direction, prevent the current
- // animation frame from being restarted for identical animations
- if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
- player->Frame = last_player_frame;
+ // in the case of changed player action or direction, prevent the current
+ // animation frame from being restarted for identical animations
+ if (player->Frame == 0 && equalGraphics(graphic, last_player_graphic))
+ player->Frame = last_player_frame;
- frame = getGraphicAnimationFrame(graphic, player->Frame);
+ int frame = getGraphicAnimationFrame(graphic, player->Frame);
- if (player->GfxPos)
- {
- if (move_dir == MV_LEFT || move_dir == MV_RIGHT)
- sxx = player->GfxPos;
+ if (player_is_opaque)
+ DrawGraphicShifted(sx,sy, sxx,syy, graphic, frame, NO_CUTTING,NO_MASKING);
else
- syy = player->GfxPos;
- }
+ DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
- if (player_is_opaque)
- DrawGraphicShifted(sx, sy, sxx, syy, graphic, frame,NO_CUTTING,NO_MASKING);
- else
- DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
+ if (SHIELD_ON(player))
+ {
+ graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
+ IMG_SHIELD_NORMAL_ACTIVE);
+ frame = getGraphicAnimationFrame(graphic, -1);
- if (SHIELD_ON(player))
+ DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
+ }
+ }
+ else if (drawing_stage == DRAW_PLAYER_STAGE_ELEMENT_OVER_PLAYER)
{
- int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
- IMG_SHIELD_NORMAL_ACTIVE);
- int frame = getGraphicAnimationFrame(graphic, -1);
+ // ------------------------------------------------------------------------
+ // draw things in front of player (active dynamite or dynabombs)
+ // ------------------------------------------------------------------------
- DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
- }
-#endif
+ if (IS_ACTIVE_BOMB(element))
+ {
+ int graphic = el2img(element);
+ int frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
- // --------------------------------------------------------------------------
- // draw things in front of player (active dynamite or dynabombs)
- // --------------------------------------------------------------------------
+ if (game.emulation == EMU_SUPAPLEX)
+ DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
+ else
+ DrawGraphicThruMask(sx, sy, graphic, frame);
+ }
- if (IS_ACTIVE_BOMB(element))
+ if (player_is_moving && last_element == EL_EXPLOSION)
+ {
+ int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
+ GfxElement[last_jx][last_jy] : EL_EMPTY);
+ int graphic = el_act2img(element, ACTION_EXPLODING);
+ int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
+ int phase = ExplodePhase[last_jx][last_jy] - 1;
+ int frame = getGraphicAnimationFrame(graphic, phase - delay);
+
+ if (phase >= delay)
+ DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
+ }
+ }
+ else if (drawing_stage == DRAW_PLAYER_STAGE_FIELD_OVER_PLAYER)
{
- graphic = el2img(element);
- frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
+ // ------------------------------------------------------------------------
+ // draw elements the player is just walking/passing through/under
+ // ------------------------------------------------------------------------
- if (game.emulation == EMU_SUPAPLEX)
- DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
- else
- DrawGraphicThruMask(sx, sy, graphic, frame);
- }
+ if (player_is_moving)
+ {
+ // handle the field the player is leaving ...
+ if (IS_ACCESSIBLE_INSIDE(last_element))
+ DrawLevelField(last_jx, last_jy);
+ else if (IS_ACCESSIBLE_UNDER(last_element))
+ DrawLevelFieldThruMask(last_jx, last_jy);
+ }
- if (player_is_moving && last_element == EL_EXPLOSION)
- {
- int element = (GfxElement[last_jx][last_jy] != EL_UNDEFINED ?
- GfxElement[last_jx][last_jy] : EL_EMPTY);
- int graphic = el_act2img(element, ACTION_EXPLODING);
- int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
- int phase = ExplodePhase[last_jx][last_jy] - 1;
- int frame = getGraphicAnimationFrame(graphic, phase - delay);
+ // do not redraw accessible elements if the player is just pushing them
+ if (!player_is_moving || !player->is_pushing)
+ {
+ // ... and the field the player is entering
+ if (IS_ACCESSIBLE_INSIDE(element))
+ DrawLevelField(jx, jy);
+ else if (IS_ACCESSIBLE_UNDER(element))
+ DrawLevelFieldThruMask(jx, jy);
+ }
- if (phase >= delay)
- DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
+ MarkTileDirty(sx, sy);
}
+}
+
+void DrawPlayer(struct PlayerInfo *player)
+{
+ int i;
- // --------------------------------------------------------------------------
- // draw elements the player is just walking/passing through/under
- // --------------------------------------------------------------------------
+ for (i = 0; i < NUM_DRAW_PLAYER_STAGES; i++)
+ DrawPlayerExt(player, i);
+}
- if (player_is_moving)
- {
- // handle the field the player is leaving ...
- if (IS_ACCESSIBLE_INSIDE(last_element))
- DrawLevelField(last_jx, last_jy);
- else if (IS_ACCESSIBLE_UNDER(last_element))
- DrawLevelFieldThruMask(last_jx, last_jy);
- }
+void DrawAllPlayers(void)
+{
+ int i, j;
- // do not redraw accessible elements if the player is just pushing them
- if (!player_is_moving || !player->is_pushing)
- {
- // ... and the field the player is entering
- if (IS_ACCESSIBLE_INSIDE(element))
- DrawLevelField(jx, jy);
- else if (IS_ACCESSIBLE_UNDER(element))
- DrawLevelFieldThruMask(jx, jy);
- }
+ for (i = 0; i < NUM_DRAW_PLAYER_STAGES; i++)
+ for (j = 0; j < MAX_PLAYERS; j++)
+ if (stored_player[j].active)
+ DrawPlayerExt(&stored_player[j], i);
+}
+
+void DrawPlayerField(int x, int y)
+{
+ if (!IS_PLAYER(x, y))
+ return;
- MarkTileDirty(sx, sy);
+ DrawPlayer(PLAYERINFO(x, y));
}
// ----------------------------------------------------------------------------