#define YY_KEYS 123
#define XX_SCORE 15
#define YY_SCORE 159
-#define XX_TIME 29
+#define XX_TIME1 29
+#define XX_TIME2 30
#define YY_TIME 194
/* special positions in the game control window (relative to main window) */
#define DY_KEYS (DY + YY_KEYS)
#define DX_SCORE (DX + XX_SCORE)
#define DY_SCORE (DY + YY_SCORE)
-#define DX_TIME (DX + XX_TIME)
+#define DX_TIME1 (DX + XX_TIME1)
+#define DX_TIME2 (DX + XX_TIME2)
#define DY_TIME (DY + YY_TIME)
/* values for initial player move delay (initial delay counter value) */
#define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \
(element_info[e].move_delay_random))
-#if 1
+#define ELEMENT_CAN_ENTER_FIELD_BASE(e, x, y, condition) \
+ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
+ (CAN_MOVE_INTO_ACID(e) && \
+ Feld[x][y] == EL_ACID) || \
+ (condition)))
+
+#if 0
#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
(condition) || \
#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
(condition) || \
+ (CAN_MOVE_INTO_ACID(e) && \
+ Feld[x][y] == EL_ACID) || \
(DONT_COLLIDE_WITH(e) && \
- IS_FREE_OR_PLAYER(x, y))))
+ IS_PLAYER(x, y) && \
+ !PLAYER_ENEMY_PROTECTED(x, y))))
#endif
#define ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, condition) \
#define ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(x, y) \
ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, (Feld[x][y] == EL_ACID))
-#define ENEMY_CAN_ENTER_FIELD(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
+#if 0
+#define ENEMY_CAN_ENTER_FIELD(e, x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
+#else
+#define ENEMY_CAN_ENTER_FIELD(e, x, y) ELEMENT_CAN_ENTER_FIELD_BASE(e, x, y, 0)
+#endif
#define YAMYAM_CAN_ENTER_FIELD(x, y) \
(IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \
+ (CAN_MOVE_INTO_ACID(EL_YAMYAM) && \
+ Feld[x][y] == EL_ACID) || \
Feld[x][y] == EL_DIAMOND))
#define DARK_YAMYAM_CAN_ENTER_FIELD(x, y) \
(IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \
+ (CAN_MOVE_INTO_ACID(EL_DARK_YAMYAM) &&\
+ Feld[x][y] == EL_ACID) || \
IS_FOOD_DARK_YAMYAM(Feld[x][y])))
#define PACMAN_CAN_ENTER_FIELD(x, y) \
(IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \
+ (CAN_MOVE_INTO_ACID(EL_PACMAN) && \
+ Feld[x][y] == EL_ACID) || \
IS_AMOEBOID(Feld[x][y])))
#define PIG_CAN_ENTER_FIELD(x, y) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
+ (CAN_MOVE_INTO_ACID(EL_PIG) && \
+ Feld[x][y] == EL_ACID) || \
IS_FOOD_PIG(Feld[x][y])))
#define PENGUIN_CAN_ENTER_FIELD(x, y) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
+ (CAN_MOVE_INTO_ACID(EL_PENGUIN) && \
+ Feld[x][y] == EL_ACID) || \
IS_FOOD_PENGUIN(Feld[x][y]) || \
- Feld[x][y] == EL_EXIT_OPEN || \
- Feld[x][y] == EL_ACID))
+ Feld[x][y] == EL_EXIT_OPEN))
-#if 0
-#if 1
-#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \
- (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
-#else
-#define MAZE_RUNNER_CAN_ENTER_FIELD(x, y) \
+#define DRAGON_CAN_ENTER_FIELD(x, y) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
- IS_FOOD_DARK_YAMYAM(Feld[x][y])))
-#endif
-#endif
+ (CAN_MOVE_INTO_ACID(EL_DRAGON) && \
+ Feld[x][y] == EL_ACID)))
+
+#define MOLE_CAN_ENTER_FIELD(x, y, condition) \
+ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
+ (CAN_MOVE_INTO_ACID(EL_MOLE) && \
+ Feld[x][y] == EL_ACID) || \
+ (condition)))
+
+#define SPRING_CAN_ENTER_FIELD(x, y) \
+ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
+ (CAN_MOVE_INTO_ACID(EL_SPRING) && \
+ Feld[x][y] == EL_ACID)))
#define GROUP_NR(e) ((e) - EL_GROUP_START)
#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define IS_EQUAL_OR_IN_GROUP(e, ge) \
(IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
-#if 1
+#if 0
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
(Feld[x][y] == EL_ACID || \
#else
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
- (Feld[x][y] == EL_ACID || \
- Feld[x][y] == MOVE_ENTER_EL(e) || \
- (IS_GROUP_ELEMENT(MOVE_ENTER_EL(e)) && \
- IS_IN_GROUP_EL(Feld[x][y], MOVE_ENTER_EL(e)))))
+ IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))
#endif
#define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, CE_ENTER_FIELD_COND(e, x, y))
-#define MOLE_CAN_ENTER_FIELD(x, y, condition) \
- (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || (condition)))
-
#define IN_LEV_FIELD_AND_IS_FREE(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y))
#define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y))
}
}
+static inline void InitField_WithBug1(int x, int y, boolean init_game)
+{
+ InitField(x, y, init_game);
+
+ /* not needed to call InitMovDir() -- already done by InitField()! */
+ if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+ CAN_MOVE(Feld[x][y]))
+ InitMovDir(x, y);
+}
+
+static inline void InitField_WithBug2(int x, int y, boolean init_game)
+{
+ int old_element = Feld[x][y];
+
+ InitField(x, y, init_game);
+
+ /* not needed to call InitMovDir() -- already done by InitField()! */
+ if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+ CAN_MOVE(old_element) &&
+ (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN))
+ InitMovDir(x, y);
+
+ /* this case is in fact a combination of not less than three bugs:
+ first, it calls InitMovDir() for elements that can move, although this is
+ already done by InitField(); then, it checks the element that was at this
+ field _before_ the call to InitField() (which can change it)
+
+ */
+}
+
+inline void DrawGameValue_Emeralds(int value)
+{
+ DrawText(DX_EMERALDS, DY_EMERALDS, int2str(value, 3), FONT_TEXT_2);
+}
+
+inline void DrawGameValue_Dynamite(int value)
+{
+ DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(value, 3), FONT_TEXT_2);
+}
+
+inline void DrawGameValue_Keys(struct PlayerInfo *player)
+{
+ int i;
+
+ for (i = 0; i < MAX_KEYS; i++)
+ if (player->key[i])
+ DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
+ el2edimg(EL_KEY_1 + i));
+}
+
+inline void DrawGameValue_Score(int value)
+{
+ DrawText(DX_SCORE, DY_SCORE, int2str(value, 5), FONT_TEXT_2);
+}
+
+inline void DrawGameValue_Time(int value)
+{
+ if (value < 1000)
+ DrawText(DX_TIME1, DY_TIME, int2str(value, 3), FONT_TEXT_2);
+ else
+ DrawText(DX_TIME2, DY_TIME, int2str(value, 4), FONT_LEVEL_NUMBER);
+}
+
+inline void DrawGameValue_Level(int value)
+{
+ if (level_nr < 100)
+ DrawText(DX_LEVEL, DY_LEVEL, int2str(value, 2), FONT_TEXT_2);
+ else
+ {
+ /* misuse area for displaying emeralds to draw bigger level number */
+ DrawTextExt(drawto, DX_EMERALDS, DY_EMERALDS,
+ int2str(value, 3), FONT_LEVEL_NUMBER, BLIT_OPAQUE);
+
+ /* now copy it to the area for displaying level number */
+ BlitBitmap(drawto, drawto,
+ DX_EMERALDS, DY_EMERALDS + 1,
+ getFontWidth(FONT_LEVEL_NUMBER) * 3,
+ getFontHeight(FONT_LEVEL_NUMBER) - 1,
+ DX_LEVEL - 1, DY_LEVEL + 1);
+
+ /* restore the area for displaying emeralds */
+ DrawGameValue_Emeralds(local_player->gems_still_needed);
+
+ /* yes, this is all really ugly :-) */
+ }
+}
+
void DrawGameDoorValues()
{
- int i, j;
+ int i;
+
+ DrawGameValue_Level(level_nr);
for (i = 0; i < MAX_PLAYERS; i++)
- for (j = 0; j < 4; j++)
- if (stored_player[i].key[j])
- DrawMiniGraphicExt(drawto, DX_KEYS + j * MINI_TILEX, DY_KEYS,
- el2edimg(EL_KEY_1 + j));
+ DrawGameValue_Keys(&stored_player[i]);
- DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS,
- int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
- DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE,
- int2str(local_player->inventory_size, 3), FONT_TEXT_2);
- DrawText(DX + XX_SCORE, DY + YY_SCORE,
- int2str(local_player->score, 5), FONT_TEXT_2);
- DrawText(DX + XX_TIME, DY + YY_TIME,
- int2str(TimeLeft, 3), FONT_TEXT_2);
+ DrawGameValue_Emeralds(local_player->gems_still_needed);
+ DrawGameValue_Dynamite(local_player->inventory_size);
+ DrawGameValue_Score(local_player->score);
+ DrawGameValue_Time(TimeLeft);
}
static void resolve_group_element(int group_element, int recursion_depth)
player->lights_still_needed = 0;
player->friends_still_needed = 0;
- for (j = 0; j < 4; j++)
+ for (j = 0; j < MAX_KEYS; j++)
player->key[j] = FALSE;
player->dynabomb_count = 0;
game.envelope_active = FALSE;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_BELTS; i++)
{
game.belt_dir[i] = MV_NO_MOVING;
game.belt_dir_nr[i] = 3; /* not moving, next moving left */
}
/* correct non-moving belts to start moving left */
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_BELTS; i++)
if (game.belt_dir[i] == MV_NO_MOVING)
game.belt_dir_nr[i] = 3; /* not moving, next moving left */
BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
- if (level_nr < 100)
- DrawText(DX + XX_LEVEL, DY + YY_LEVEL, int2str(level_nr, 2), FONT_TEXT_2);
- else
- {
- DrawTextExt(drawto, DX + XX_EMERALDS, DY + YY_EMERALDS,
- int2str(level_nr, 3), FONT_LEVEL_NUMBER, BLIT_OPAQUE);
- BlitBitmap(drawto, drawto,
- DX + XX_EMERALDS, DY + YY_EMERALDS + 1,
- getFontWidth(FONT_LEVEL_NUMBER) * 3,
- getFontHeight(FONT_LEVEL_NUMBER) - 1,
- DX + XX_LEVEL - 1, DY + YY_LEVEL + 1);
- }
-
DrawGameDoorValues();
UnmapGameButtons();
if (options.debug)
{
- for (i = 0; i < 4; i++)
+ for (i = 0; i < MAX_PLAYERS; i++)
printf("Player %d %sactive.\n",
i + 1, (stored_player[i].active ? "" : "not "));
}
else if (move_pattern == MV_ALONG_LEFT_SIDE ||
move_pattern == MV_ALONG_RIGHT_SIDE)
{
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int x1 = x + xy[i][0];
int y1 = y + xy[i][1];
element != EL_BD_FIREFLY)
break;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int x1 = x + xy[i][0];
int y1 = y + xy[i][1];
TimeLeft -= 10;
else
TimeLeft--;
- DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+
+ DrawGameValue_Time(TimeLeft);
+
BackToFront();
if (!tape.playing)
TimePlayed += 10;
else
TimePlayed++;
- DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2);
+
+ DrawGameValue_Time(TimePlayed);
+
BackToFront();
if (!tape.playing)
if (IS_MOVING(x, y))
{
Moving2Blocked(x, y, &newx, &newy);
+#if 0
if (Feld[newx][newy] != EL_BLOCKED)
return;
+#else
+ if (Feld[newx][newy] != EL_BLOCKED)
+ {
+ /* element is moving, but target field is not free (blocked), but
+ already occupied by something different (example: acid pool);
+ in this case, only remove the moving field, but not the target */
+
+ RemoveField(oldx, oldy);
+
+ Store[oldx][oldy] = Store2[oldx][oldy] = 0;
+
+ DrawLevelField(oldx, oldy);
+
+ return;
+ }
+#endif
}
else if (element == EL_BLOCKED)
{
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
+#if 1
+ InitField_WithBug2(x, y, FALSE);
+#else
InitField(x, y, FALSE);
#if 1
/* !!! not needed !!! */
+#if 1
+ if (game.engine_version < VERSION_IDENT(3,0,9,0) &&
+ CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE)
+ InitMovDir(x, y);
+#else
if (CAN_MOVE(element))
InitMovDir(x, y);
+#endif
+#endif
#endif
DrawLevelField(x, y);
Explode(ex, ey, EX_PHASE_START, EX_CENTER);
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
for (j = 1; j <= dynabomb_size; j++)
{
- int x = ex + j * xy[i % 4][0];
- int y = ey + j * xy[i % 4][1];
+ int x = ex + j * xy[i][0];
+ int y = ey + j * xy[i][1];
int element;
if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y]))
void SplashAcid(int x, int y)
{
+#if 1
+ if (IN_LEV_FIELD(x - 1, y - 1) && IS_FREE(x - 1, y - 1) &&
+ (!IN_LEV_FIELD(x - 1, y - 2) ||
+ !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 2))))
+ Feld[x - 1][y - 1] = EL_ACID_SPLASH_LEFT;
+
+ if (IN_LEV_FIELD(x + 1, y - 1) && IS_FREE(x + 1, y - 1) &&
+ (!IN_LEV_FIELD(x + 1, y - 2) ||
+ !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 2))))
+ Feld[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT;
+
+ PlayLevelSound(x, y, SND_ACID_SPLASHING);
+#else
+ /* input: position of element entering acid (obsolete) */
+
int element = Feld[x][y];
+ if (!IN_LEV_FIELD(x, y + 1) || Feld[x][y + 1] != EL_ACID)
+ return;
+
if (element != EL_ACID_SPLASH_LEFT &&
element != EL_ACID_SPLASH_RIGHT)
{
PlayLevelSound(x, y, SND_ACID_SPLASHING);
- if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
- (!IN_LEV_FIELD(x-1, y-1) ||
- !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
- Feld[x-1][y] = EL_ACID_SPLASH_LEFT;
+ if (IN_LEV_FIELD(x - 1, y) && IS_FREE(x - 1, y) &&
+ (!IN_LEV_FIELD(x - 1, y - 1) ||
+ !CAN_FALL(MovingOrBlocked2Element(x - 1, y - 1))))
+ Feld[x - 1][y] = EL_ACID_SPLASH_LEFT;
- if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
- (!IN_LEV_FIELD(x+1, y-1) ||
- !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
- Feld[x+1][y] = EL_ACID_SPLASH_RIGHT;
+ if (IN_LEV_FIELD(x + 1, y) && IS_FREE(x + 1, y) &&
+ (!IN_LEV_FIELD(x + 1, y - 1) ||
+ !CAN_FALL(MovingOrBlocked2Element(x + 1, y - 1))))
+ Feld[x + 1][y] = EL_ACID_SPLASH_RIGHT;
}
+#endif
}
static void InitBeltMovement()
int x, y, i, j;
/* set frame order for belt animation graphic according to belt direction */
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_BELTS; i++)
{
int belt_nr = i;
- for (j = 0; j < 3; j++)
+ for (j = 0; j < NUM_BELT_PARTS; j++)
{
int element = belt_base_active_element[belt_nr] + j;
int graphic = el2img(element);
{
int element = Feld[x][y];
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_BELTS; i++)
{
if (IS_BELT(element) && game.belt_dir[i] != MV_NO_MOVING)
{
belt_dir_nr = 1;
/* set frame order for belt animation graphic according to belt direction */
- for (i = 0; i < 3; i++)
+ for (i = 0; i < NUM_BELT_PARTS; i++)
{
int element = belt_base_active_element[belt_nr] + i;
int graphic = el2img(element);
if (!lastline && smashed == EL_ACID) /* element falls into acid */
{
- SplashAcid(x, y);
+ SplashAcid(x, y + 1);
return;
}
{
TestIfBadThingTouchesOtherBadThing(x, y);
- if (ENEMY_CAN_ENTER_FIELD(right_x, right_y))
+ if (ENEMY_CAN_ENTER_FIELD(element, right_x, right_y))
MovDir[x][y] = right_dir;
- else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
MovDir[x][y] = left_dir;
if (element == EL_BUG && MovDir[x][y] != old_move_dir)
{
TestIfBadThingTouchesOtherBadThing(x, y);
- if (ENEMY_CAN_ENTER_FIELD(left_x, left_y))
+ if (ENEMY_CAN_ENTER_FIELD(element, left_x, left_y))
MovDir[x][y] = left_dir;
- else if (!ENEMY_CAN_ENTER_FIELD(move_x, move_y))
+ else if (!ENEMY_CAN_ENTER_FIELD(element, move_x, move_y))
MovDir[x][y] = right_dir;
if ((element == EL_SPACESHIP ||
}
else if (element == EL_DRAGON)
{
- boolean can_turn_left = IN_LEV_FIELD_AND_IS_FREE(left_x, left_y);
- boolean can_turn_right = IN_LEV_FIELD_AND_IS_FREE(right_x, right_y);
- boolean can_move_on = IN_LEV_FIELD_AND_IS_FREE(move_x, move_y);
+ boolean can_turn_left = DRAGON_CAN_ENTER_FIELD(left_x, left_y);
+ boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(right_x, right_y);
+ boolean can_move_on = DRAGON_CAN_ENTER_FIELD(move_x, move_y);
int rnd_value = 24;
int rnd = RND(rnd_value);
}
else if (element == EL_SPRING)
{
+#if 0
+ if (MovDir[x][y] & MV_HORIZONTAL &&
+ !SPRING_CAN_ENTER_FIELD(move_x, move_y))
+ MovDir[x][y] = MV_NO_MOVING;
+#else
if (MovDir[x][y] & MV_HORIZONTAL &&
- (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y) ||
- IN_LEV_FIELD_AND_IS_FREE(x, y + 1)))
+ (!SPRING_CAN_ENTER_FIELD(move_x, move_y) ||
+ SPRING_CAN_ENTER_FIELD(x, y + 1)))
MovDir[x][y] = MV_NO_MOVING;
+#endif
MovDelay[x][y] = 0;
}
{ 0, +1 }
};
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int ex = x + xy[i % 4][0];
- int ey = y + xy[i % 4][1];
+ int ex = x + xy[i][0];
+ int ey = y + xy[i][1];
if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_EXIT_OPEN)
{
else if (move_pattern == MV_WHEN_PUSHED ||
move_pattern == MV_WHEN_DROPPED)
{
- if (!IN_LEV_FIELD_AND_IS_FREE(move_x, move_y))
+ if (!CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, move_x, move_y))
MovDir[x][y] = MV_NO_MOVING;
MovDelay[x][y] = 0;
int start_test = RND(4);
int i;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int move_dir = test_dir[start_test + i];
int move_dir_preference;
void StartMoving(int x, int y)
{
+#if 0
boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
+#endif
boolean started_moving = FALSE; /* some elements can fall _and_ move */
int element = Feld[x][y];
else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
#endif
{
- SplashAcid(x, y);
+ SplashAcid(x, y + 1);
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
Impact(x, y);
}
- else if (IS_FREE(x, y + 1) && element == EL_SPRING && use_spring_bug)
+ else if (IS_FREE(x, y + 1) && element == EL_SPRING && level.use_spring_bug)
{
if (MovDir[x][y] == MV_NO_MOVING)
{
#endif
}
+#if 1
+#if 1
+ else if (CAN_MOVE_INTO_ACID(element) &&
+ IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
+ (MovDir[x][y] == MV_DOWN ||
+ game.engine_version > VERSION_IDENT(3,0,8,0)))
+#else
+ else if (CAN_MOVE_INTO_ACID(element) && MovDir[x][y] == MV_DOWN &&
+ IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID)
+#endif
+#else
+
else if ((element == EL_PENGUIN ||
element == EL_ROBOT ||
element == EL_SATELLITE ||
IS_CUSTOM_ELEMENT(element)) &&
IN_LEV_FIELD(newx, newy) &&
MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_ACID)
+#endif
{
- SplashAcid(x, y);
+ SplashAcid(newx, newy);
Store[x][y] = EL_ACID;
}
else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
PlayLevelSoundAction(x, y, action);
}
- if (new_element == element_info[element].move_enter_element)
+ if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
element_info[element].can_leave_element = TRUE;
if (move_pattern & MV_MAZE_RUNNER_STYLE)
AmoebaCnt[AmoebaNr[newx][newy]]--;
}
+#if 0
+ /* !!! test !!! */
+ if (IS_MOVING(newx, newy) || IS_BLOCKED(newx, newy))
+#else
if (IS_MOVING(newx, newy))
+#endif
+ {
RemoveMovingField(newx, newy);
+ }
else
{
Feld[newx][newy] = EL_EMPTY;
int nextx = newx + dx, nexty = newy + dy;
#endif
#if 1
- boolean pushed = (Pushed[x][y] && IS_PLAYER(x, y));
+ boolean pushed_by_player = (Pushed[x][y] && IS_PLAYER(x, y));
boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y));
#else
- boolean pushed = Pushed[x][y];
+ boolean pushed_by_player = Pushed[x][y];
#endif
MovPos[x][y] += getElementMoveStepsize(x, y);
#if 0
- if (pushed && IS_PLAYER(x, y))
+ if (pushed_by_player && IS_PLAYER(x, y))
{
/* special case: moving object pushed by player */
MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
}
#else
- if (pushed) /* special case: moving object pushed by player */
+ if (pushed_by_player) /* special case: moving object pushed by player */
MovPos[x][y] = SIGN(MovPos[x][y]) * (TILEX - ABS(PLAYERINFO(x,y)->MovPos));
#endif
Stop[newx][newy] = TRUE; /* ignore this element until the next frame */
/* prevent pushed element from moving on in pushed direction */
- if (pushed && CAN_MOVE(element) &&
+ if (pushed_by_player && CAN_MOVE(element) &&
element_info[element].move_pattern & MV_ANY_DIRECTION &&
!(element_info[element].move_pattern & direction))
TurnRound(newx, newy);
MovDir[newx][newy] = 0;
#endif
- if (!pushed) /* special case: moving object pushed by player */
+ if (!pushed_by_player)
{
WasJustMoving[newx][newy] = 3;
{ 0, +1 }
};
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int x = ax + xy[i][0];
int y = ay + xy[i][1];
if (new_group_nr == 0)
return;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
x = ax + xy[i][0];
y = ay + xy[i][1];
{ 0, +1 }
};
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
x = ax + xy[i][0];
y = ay + xy[i][1];
int start = RND(4);
boolean waiting_for_player = FALSE;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int j = (start + i) % 4;
int x = ax + xy[j][0];
{ 0, +1 }
};
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
for (j = 0; j < 4; j++)
{
- int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+ int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
if (IN_LEV_FIELD(xx, yy) &&
(Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
if (!dragon_found)
{
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
for (j = 0; j < 3; j++)
{
- int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
+ int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
{
{ 0, +1 }
};
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int xx = x + xy[i][0], yy = y + xy[i][1];
if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
MovDir[x][y] = previous_move_direction;
+#if 1
+ InitField_WithBug1(x, y, FALSE);
+#else
InitField(x, y, FALSE);
if (CAN_MOVE(Feld[x][y]))
InitMovDir(x, y);
+#endif
DrawLevelField(x, y);
#endif
#if 1
+ /* for downwards compatibility, the following code emulates a fixed bug that
+ occured when pushing elements (causing elements that just made their last
+ pushing step to already (if possible) make their first falling step in the
+ same game frame, which is bad); this code is also needed to use the famous
+ "spring push bug" which is used in older levels and might be wanted to be
+ used also in newer levels, but in this case the buggy pushing code is only
+ affecting the "spring" element and no other elements */
+
+#if 1
+ if (game.engine_version < VERSION_IDENT(2,2,0,7) || level.use_spring_bug)
+#else
if (game.engine_version < VERSION_IDENT(2,2,0,7))
+#endif
{
for (i = 0; i < MAX_PLAYERS; i++)
{
int x = player->jx;
int y = player->jy;
+#if 1
+ if (player->active && player->is_pushing && player->is_moving &&
+ IS_MOVING(x, y) &&
+ (game.engine_version < VERSION_IDENT(2,2,0,7) ||
+ Feld[x][y] == EL_SPRING))
+#else
if (player->active && player->is_pushing && player->is_moving &&
IS_MOVING(x, y))
+#endif
{
ContinueMoving(x, y);
if (TimeLeft <= 10 && setup.time_limit)
PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
- DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+ DrawGameValue_Time(TimeLeft);
if (!TimeLeft && setup.time_limit)
for (i = 0; i < MAX_PLAYERS; i++)
KillHero(&stored_player[i]);
}
else if (level.time == 0 && !AllPlayersGone) /* level without time limit */
- DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FONT_TEXT_2);
+ DrawGameValue_Time(TimePlayed);
}
DrawAllPlayers();
{
if (element == EL_ACID && dx == 0 && dy == 1)
{
- SplashAcid(jx, jy);
+ SplashAcid(new_jx, new_jy);
Feld[jx][jy] = EL_PLAYER_1;
InitMovingField(jx, jy, MV_DOWN);
Store[jx][jy] = EL_ACID;
int center_element = Feld[x][y]; /* should always be non-moving! */
int i;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int xx = x + xy[i][0];
int yy = y + xy[i][1];
int center_element = Feld[x][y]; /* should always be non-moving! */
int i, j;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int xx = x + xy[i][0];
int yy = y + xy[i][1];
MV_DOWN
};
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int test_x, test_y, test_move_dir, test_element;
if (bad_element == EL_EXPLOSION) /* skip just exploding bad things */
return;
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int test_x, test_y, test_move_dir, test_element;
{ 0, +1 }
};
- for (i = 0; i < 4; i++)
+ for (i = 0; i < NUM_DIRECTIONS; i++)
{
int x, y, element;
CH_SIDE_BOTTOM, /* moving up */
CH_SIDE_TOP, /* moving down */
};
+#if 0
boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0,0));
+#endif
int jx = oldx, jy = oldy;
int dx = x - jx, dy = y - jy;
int nextx = x + dx, nexty = y + dy;
else if (element == EL_EXTRA_TIME && level.time > 0)
{
TimeLeft += 10;
- DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+ DrawGameValue_Time(TimeLeft);
}
else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
{
if (player->inventory_size < MAX_INVENTORY_SIZE)
player->inventory_element[player->inventory_size++] = element;
- DrawText(DX_DYNAMITE, DY_DYNAMITE,
- int2str(local_player->inventory_size, 3), FONT_TEXT_2);
+ DrawGameValue_Dynamite(local_player->inventory_size);
}
else if (element == EL_DYNABOMB_INCREASE_NUMBER)
{
player->key[key_nr] = TRUE;
- DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
- el2edimg(EL_KEY_1 + key_nr));
+ DrawGameValue_Keys(player);
+
redraw_mask |= REDRAW_DOOR_1;
}
else if (IS_ENVELOPE(element))
if (player->inventory_size < MAX_INVENTORY_SIZE)
player->inventory_element[player->inventory_size++] = element;
- DrawText(DX_DYNAMITE, DY_DYNAMITE,
- int2str(local_player->inventory_size, 3), FONT_TEXT_2);
+ DrawGameValue_Dynamite(local_player->inventory_size);
}
else if (element_info[element].collect_count > 0)
{
if (local_player->gems_still_needed < 0)
local_player->gems_still_needed = 0;
- DrawText(DX_EMERALDS, DY_EMERALDS,
- int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
+ DrawGameValue_Emeralds(local_player->gems_still_needed);
}
RaiseScoreElement(element);
return MF_NO_ACTION;
if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
- !(element == EL_SPRING && use_spring_bug))
+ !(element == EL_SPRING && level.use_spring_bug))
return MF_NO_ACTION;
#if 1
{
Feld[x][y] = EL_TIME_ORB_EMPTY;
TimeLeft += 10;
- DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
+ DrawGameValue_Time(TimeLeft);
DrawLevelField(x, y);
Feld[jx][jy] = new_element;
- DrawText(DX_DYNAMITE, DY_DYNAMITE,
- int2str(local_player->inventory_size, 3), FONT_TEXT_2);
+ DrawGameValue_Dynamite(local_player->inventory_size);
if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
if (Feld[jx][jy] == new_element) /* uninitialized unless CE change */
{
+#if 1
+ InitField_WithBug1(jx, jy, FALSE);
+#else
InitField(jx, jy, FALSE);
if (CAN_MOVE(Feld[jx][jy]))
InitMovDir(jx, jy);
+#endif
}
new_element = Feld[jx][jy];
void RaiseScore(int value)
{
local_player->score += value;
- DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5), FONT_TEXT_2);
+
+ DrawGameValue_Score(local_player->score);
}
void RaiseScoreElement(int element)