+ DrawGameValue_Keys(player->key);
+
+ redraw_mask |= REDRAW_DOOR_1;
+ }
+ else if (IS_ENVELOPE(element))
+ {
+#if 1
+ player->show_envelope = element;
+#else
+ ShowEnvelope(element - EL_ENVELOPE_1);
+#endif
+ }
+ else if (IS_DROPPABLE(element) ||
+ IS_THROWABLE(element)) /* can be collected and dropped */
+ {
+ int i;
+
+ if (element_info[element].collect_count == 0)
+ player->inventory_infinite_element = element;
+ else
+ for (i = 0; i < element_info[element].collect_count; i++)
+ if (player->inventory_size < MAX_INVENTORY_SIZE)
+ player->inventory_element[player->inventory_size++] = element;
+
+ DrawGameValue_Dynamite(local_player->inventory_size);
+ }
+ else if (element_info[element].collect_count > 0)
+ {
+ local_player->gems_still_needed -=
+ element_info[element].collect_count;
+ if (local_player->gems_still_needed < 0)
+ local_player->gems_still_needed = 0;
+
+ DrawGameValue_Emeralds(local_player->gems_still_needed);
+ }
+
+ RaiseScoreElement(element);
+ PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
+
+ if (is_player)
+ CheckTriggeredElementChangeByPlayer(x, y, element,
+ CE_PLAYER_COLLECTS_X,
+ player->index_bit, dig_side);
+
+#if 1
+ if (mode == DF_SNAP)
+ TestIfElementTouchesCustomElement(x, y); /* for empty space */
+#endif
+
+ break;
+ }
+ else if (IS_PUSHABLE(element))
+ {
+ if (mode == DF_SNAP && element != EL_BD_ROCK)
+ return MF_NO_ACTION;
+
+ if (CAN_FALL(element) && dy)
+ return MF_NO_ACTION;
+
+ if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
+ !(element == EL_SPRING && level.use_spring_bug))
+ return MF_NO_ACTION;
+
+#if 1
+ if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 &&
+ ((move_direction & MV_VERTICAL &&
+ ((element_info[element].move_pattern & MV_LEFT &&
+ IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y)) ||
+ (element_info[element].move_pattern & MV_RIGHT &&
+ IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y)))) ||
+ (move_direction & MV_HORIZONTAL &&
+ ((element_info[element].move_pattern & MV_UP &&
+ IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) ||
+ (element_info[element].move_pattern & MV_DOWN &&
+ IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))))
+ return MF_NO_ACTION;
+#endif
+
+#if 1
+ /* do not push elements already moving away faster than player */
+ if (CAN_MOVE(element) && MovDir[x][y] == move_direction &&
+ ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL)
+ return MF_NO_ACTION;
+#else
+ if (element == EL_SPRING && MovDir[x][y] != MV_NO_MOVING)
+ return MF_NO_ACTION;
+#endif
+
+#if 1
+
+#if 1
+ if (game.engine_version >= VERSION_IDENT(3,1,0,0))
+ {
+ if (player->push_delay_value == -1 || !player_was_pushing)
+ player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+ }
+ else if (game.engine_version >= VERSION_IDENT(3,0,7,1))
+ {
+ if (player->push_delay_value == -1)
+ player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+ }
+#else
+ if (game.engine_version >= VERSION_IDENT(3,0,7,1))
+ {
+ if (player->push_delay_value == -1 || !player_was_pushing)
+ player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+ }
+#endif
+ else if (game.engine_version >= VERSION_IDENT(2,2,0,7))
+ {
+ if (!player->is_pushing)
+ player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+ }
+
+ /*
+ if (game.engine_version >= VERSION_IDENT(2,2,0,7) &&
+ (game.engine_version < VERSION_IDENT(3,0,7,1) ||
+ !player_is_pushing))
+ player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+ */
+#else
+ if (!player->is_pushing &&
+ game.engine_version >= VERSION_IDENT(2,2,0,7))
+ player->push_delay_value = GET_NEW_PUSH_DELAY(element);
+#endif
+
+#if 0
+ printf("::: push delay: %ld -> %ld [%d, %d] [%d / %d] [%d '%s': %d]\n",
+ player->push_delay, player->push_delay_value,
+ FrameCounter, game.engine_version,
+ player_was_pushing, player->is_pushing,
+ element, element_info[element].token_name,
+ GET_NEW_PUSH_DELAY(element));
+#endif
+
+ player->is_pushing = TRUE;
+
+ if (!(IN_LEV_FIELD(nextx, nexty) &&
+ (IS_FREE(nextx, nexty) ||
+ (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY &&
+ IS_SB_ELEMENT(element)))))
+ return MF_NO_ACTION;
+
+ if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
+ return MF_NO_ACTION;
+
+#if USE_NEW_PUSH_DELAY
+
+#if 0
+ if ( (player->push_delay == -1) != (player->push_delay2 == 0) )
+ printf("::: ALERT: %d, %d [%d / %d]\n",
+ player->push_delay, player->push_delay2,
+ FrameCounter, FrameCounter / 50);
+#endif
+
+ if (player->push_delay == -1) /* new pushing; restart delay */
+ player->push_delay = 0;
+#else
+ if (player->push_delay == 0) /* new pushing; restart delay */
+ player->push_delay = FrameCounter;
+#endif
+
+#if USE_NEW_PUSH_DELAY
+#if 0
+ if ( (player->push_delay > 0) != (!xxx_fr) )
+ printf("::: PUSH BUG! %d, (%d -> %d) %d [%d / %d]\n",
+ player->push_delay,
+ xxx_pdv2, player->push_delay2, player->push_delay_value,
+ FrameCounter, FrameCounter / 50);
+#endif
+
+#if 0
+ if (player->push_delay > 0 &&
+ !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+ element != EL_SPRING && element != EL_BALLOON)
+#else
+ /* !!! */
+ if (player->push_delay < player->push_delay_value &&
+ !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+ element != EL_SPRING && element != EL_BALLOON)
+#endif
+
+#else
+ if (!FrameReached(&player->push_delay, player->push_delay_value) &&
+ !(tape.playing && tape.file_version < FILE_VERSION_2_0) &&
+ element != EL_SPRING && element != EL_BALLOON)
+#endif
+ {
+ /* make sure that there is no move delay before next try to push */
+#if USE_NEW_MOVE_DELAY
+ if (game.engine_version >= VERSION_IDENT(3,0,7,1))
+ player->move_delay = 0;
+#else
+ if (game.engine_version >= VERSION_IDENT(3,0,7,1))
+ player->move_delay = INITIAL_MOVE_DELAY_OFF;
+#endif
+
+ return MF_NO_ACTION;
+ }
+
+#if 0
+ printf("::: NOW PUSHING... [%d]\n", FrameCounter);
+#endif