+ if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
+ return;
+
+#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 (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);
+
+ if (player->is_waiting)
+ move_dir = player->dir_waiting;
+
+ InitPlayerGfxAnimation(player, action, move_dir);
+
+ /* ----------------------------------------------------------------------- */
+ /* draw things in the field the player is leaving, if needed */
+ /* ----------------------------------------------------------------------- */
+
+ if (player->is_moving)
+ {
+ if (Back[last_jx][last_jy] && IS_DRAWABLE(last_element))
+ {
+ DrawLevelElement(last_jx, last_jy, Back[last_jx][last_jy]);
+
+ if (last_element == EL_DYNAMITE_ACTIVE ||
+ last_element == EL_EM_DYNAMITE_ACTIVE ||
+ last_element == EL_SP_DISK_RED_ACTIVE)
+ DrawDynamite(last_jx, last_jy);
+ else
+ DrawLevelFieldThruMask(last_jx, last_jy);
+ }
+ else if (last_element == EL_DYNAMITE_ACTIVE ||
+ 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);
+ }
+
+ if (!IN_SCR_FIELD(sx, sy))
+ return;
+
+ /* ----------------------------------------------------------------------- */
+ /* draw things behind the player, if needed */
+ /* ----------------------------------------------------------------------- */
+
+ 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];
+ int old_graphic = el_act_dir2img(old_element, action, move_dir);
+ int frame = getGraphicAnimationFrame(old_graphic, player->StepFrame);
+
+ if (GFX_CRUMBLED(old_element))
+ DrawLevelFieldCrumbledDigging(jx, jy, move_dir, player->StepFrame);
+ else
+ DrawGraphic(sx, sy, old_graphic, frame);
+
+ if (graphic_info[old_graphic].anim_mode & ANIM_OPAQUE_PLAYER)
+ player_is_opaque = TRUE;
+ }
+ else
+ {
+ GfxElement[jx][jy] = EL_UNDEFINED;
+
+ /* make sure that pushed elements are drawn with correct frame rate */
+#if 1
+ 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;
+#else
+ if (player->is_pushing && player->is_moving)
+ GfxFrame[jx][jy] = player->StepFrame;
+#endif
+
+ 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 (!setup.soft_scrolling && ScreenMovPos)
+ sxx = syy = 0;
+
+ 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)
+ {
+ 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 */
+ /* ----------------------------------------------------------------------- */
+
+#if 0
+ printf("::: %d, %d [%d, %d] [%d]\n",
+ player->is_pushing, player_is_moving, player->GfxAction,
+ player->is_moving, player_is_moving);
+#endif
+
+#if 1
+ 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);
+
+#if 1
+ sync_frame = (IS_ANIM_MODE_CE(graphic) ? gfx_frame : player->StepFrame);
+ frame = getGraphicAnimationFrame(graphic, sync_frame);
+#else
+ frame = getGraphicAnimationFrame(graphic, player->StepFrame);
+#endif
+
+ /* draw background element under pushed element (like the Sokoban field) */
+#if 1
+ if (game.use_masked_pushing && IS_MOVING(jx, jy))
+ {
+ /* this allows transparent pushing animation over non-black background */
+
+ if (Back[jx][jy])
+ DrawLevelElement(jx, jy, Back[jx][jy]);
+ else
+ DrawLevelElement(jx, jy, EL_EMPTY);
+
+ if (Back[next_jx][next_jy])
+ DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
+ else
+ DrawLevelElement(next_jx, next_jy, EL_EMPTY);
+ }
+ else if (Back[next_jx][next_jy])
+ DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
+#else
+ if (Back[next_jx][next_jy])
+ DrawLevelElement(next_jx, next_jy, Back[next_jx][next_jy]);
+#endif
+
+#if 0
+ printf("::: %d, %d, %d, %d [%d] [%d, %d, %d] [%d] [%d, %d] [%d, %d]\n",
+ jx, px, player->GfxPos, player->StepFrame,
+ player->is_pushing,
+ dx, sxx, pxx,
+ IS_MOVING(jx, jy),
+ graphic, frame,
+ GfxFrame[jx][jy], GfxFrame[next_jx][next_jy]);
+#endif
+
+#if 1
+ /* do not draw (EM style) pushing animation when pushing is finished */
+ /* (two-tile animations usually do not contain start and end frame) */
+ if (graphic_info[graphic].double_movement && !IS_MOVING(jx, jy))
+ DrawLevelElement(next_jx, next_jy, Feld[next_jx][next_jy]);
+ else
+ DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
+#else
+ /* masked drawing is needed for EMC style (double) movement graphics */
+ /* !!! (ONLY WHEN DRAWING PUSHED ELEMENT OVER THE PLAYER) !!! */
+ DrawGraphicShiftedThruMask(px, py, pxx, pyy, graphic, frame, NO_CUTTING);
+#endif
+ }
+#endif
+
+#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 (!setup.soft_scrolling && ScreenMovPos)
+ sxx = syy = 0;
+
+ 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
+
+ /* ----------------------------------------------------------------------- */
+ /* draw things in front of player (active dynamite or dynabombs) */
+ /* ----------------------------------------------------------------------- */
+
+ if (IS_ACTIVE_BOMB(element))
+ {
+ graphic = el2img(element);
+ frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
+
+ if (game.emulation == EMU_SUPAPLEX)
+ DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
+ else
+ DrawGraphicThruMask(sx, sy, graphic, frame);
+ }
+
+ 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);
+ }
+
+ /* ----------------------------------------------------------------------- */
+ /* draw elements the player is just walking/passing through/under */
+ /* ----------------------------------------------------------------------- */
+
+ 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);
+ }
+
+ /* 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);
+ }
+
+ MarkTileDirty(sx, sy);
+}
+
+/* ------------------------------------------------------------------------- */
+
+void WaitForEventToContinue()
+{
+ boolean still_wait = TRUE;
+
+ /* simulate releasing mouse button over last gadget, if still pressed */
+ if (button_status)
+ HandleGadgets(-1, -1, 0);
+
+ button_status = MB_RELEASED;
+
+#if 1
+ ClearEventQueue();
+#endif
+
+ while (still_wait)
+ {
+ if (PendingEvent())
+ {
+ Event event;
+
+ NextEvent(&event);
+
+ switch (event.type)
+ {
+ case EVENT_BUTTONPRESS:
+ case EVENT_KEYPRESS:
+ still_wait = FALSE;
+ break;
+
+ case EVENT_KEYRELEASE:
+ ClearPlayerAction();
+ break;
+
+ default:
+ HandleOtherEvents(&event);
+ break;
+ }
+ }
+ else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
+ {
+ still_wait = FALSE;
+ }
+
+ DoAnimation();
+
+ /* don't eat all CPU time */
+ Delay(10);
+ }
+}
+
+#define MAX_REQUEST_LINES 13
+#define MAX_REQUEST_LINE_FONT1_LEN 7
+#define MAX_REQUEST_LINE_FONT2_LEN 10
+
+#if 1
+
+static int RequestHandleEvents(unsigned int req_state)
+{
+ int last_game_status = game_status; /* save current game status */
+ int result;
+ int mx, my;
+
+ button_status = MB_RELEASED;
+
+ request_gadget_id = -1;
+ result = -1;
+
+ while (result < 0)
+ {
+ if (PendingEvent())
+ {
+ Event event;
+
+ NextEvent(&event);
+
+ switch (event.type)
+ {
+ case EVENT_BUTTONPRESS:
+ case EVENT_BUTTONRELEASE:
+ case EVENT_MOTIONNOTIFY:
+ {
+ if (event.type == EVENT_MOTIONNOTIFY)
+ {
+ if (!PointerInWindow(window))
+ continue; /* window and pointer are on different screens */
+
+ if (!button_status)
+ continue;
+
+ motion_status = TRUE;
+ mx = ((MotionEvent *) &event)->x;
+ my = ((MotionEvent *) &event)->y;
+ }
+ else
+ {
+ motion_status = FALSE;
+ mx = ((ButtonEvent *) &event)->x;
+ my = ((ButtonEvent *) &event)->y;
+ if (event.type == EVENT_BUTTONPRESS)
+ button_status = ((ButtonEvent *) &event)->button;
+ else
+ button_status = MB_RELEASED;
+ }
+
+ /* this sets 'request_gadget_id' */
+ HandleGadgets(mx, my, button_status);
+
+ switch (request_gadget_id)
+ {
+ case TOOL_CTRL_ID_YES:
+ result = TRUE;
+ break;
+ case TOOL_CTRL_ID_NO:
+ result = FALSE;
+ break;
+ case TOOL_CTRL_ID_CONFIRM:
+ result = TRUE | FALSE;
+ break;
+
+ case TOOL_CTRL_ID_PLAYER_1:
+ result = 1;
+ break;
+ case TOOL_CTRL_ID_PLAYER_2:
+ result = 2;
+ break;
+ case TOOL_CTRL_ID_PLAYER_3:
+ result = 3;
+ break;
+ case TOOL_CTRL_ID_PLAYER_4:
+ result = 4;
+ break;