// (c) 1995-2014 by Artsoft Entertainment
// Holger Schemel
// info@artsoft.org
-// http://www.artsoft.org/
+// https://www.artsoft.org/
// ----------------------------------------------------------------------------
// game.c
// ============================================================================
RND(element_info[e].move_delay_random))
#define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \
(element_info[e].move_delay_random))
+#define GET_NEW_STEP_DELAY(e) ( (element_info[e].step_delay_fixed) + \
+ RND(element_info[e].step_delay_random))
+#define GET_MAX_STEP_DELAY(e) ( (element_info[e].step_delay_fixed) + \
+ (element_info[e].step_delay_random))
#define GET_NEW_CE_VALUE(e) ( (element_info[e].ce_value_fixed_initial) +\
RND(element_info[e].ce_value_random_initial))
#define GET_CE_SCORE(e) ( (element_info[e].collect_score))
#define ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
(CAN_MOVE_INTO_ACID(e) && \
- Feld[x][y] == EL_ACID) || \
+ Tile[x][y] == EL_ACID) || \
(condition)))
#define ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \
(CAN_MOVE_INTO_ACID(e) && \
- Feld[x][y] == EL_ACID) || \
+ Tile[x][y] == EL_ACID) || \
(condition)))
#define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition) \
(IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \
(condition) || \
(CAN_MOVE_INTO_ACID(e) && \
- Feld[x][y] == EL_ACID) || \
+ Tile[x][y] == EL_ACID) || \
(DONT_COLLIDE_WITH(e) && \
IS_PLAYER(x, y) && \
!PLAYER_ENEMY_PROTECTED(x, y))))
ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0)
#define ANDROID_CAN_ENTER_FIELD(e, x, y) \
- ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Feld[x][y] == EL_EMC_PLANT)
+ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, Tile[x][y] == EL_EMC_PLANT)
#define ANDROID_CAN_CLONE_FIELD(x, y) \
- (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[x][y]) || \
+ (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Tile[x][y]) || \
CAN_BE_CLONED_BY_ANDROID(EL_TRIGGER_ELEMENT)))
#define ENEMY_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
#define YAMYAM_CAN_ENTER_FIELD(e, x, y) \
- ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND)
+ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Tile[x][y] == EL_DIAMOND)
#define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \
- ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y]))
+ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Tile[x][y]))
#define PACMAN_CAN_ENTER_FIELD(e, x, y) \
- ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y]))
+ ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Tile[x][y]))
#define PIG_CAN_ENTER_FIELD(e, x, y) \
- ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y]))
+ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Tile[x][y]))
#define PENGUIN_CAN_ENTER_FIELD(e, x, y) \
- ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN || \
- Feld[x][y] == EL_EM_EXIT_OPEN || \
- Feld[x][y] == EL_STEEL_EXIT_OPEN || \
- Feld[x][y] == EL_EM_STEEL_EXIT_OPEN || \
- IS_FOOD_PENGUIN(Feld[x][y])))
+ ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Tile[x][y] == EL_EXIT_OPEN || \
+ Tile[x][y] == EL_EM_EXIT_OPEN || \
+ Tile[x][y] == EL_STEEL_EXIT_OPEN || \
+ Tile[x][y] == EL_EM_STEEL_EXIT_OPEN || \
+ IS_FOOD_PENGUIN(Tile[x][y])))
#define DRAGON_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0)
#define SPRING_CAN_BUMP_FROM_FIELD(x, y) \
- (IN_LEV_FIELD(x, y) && (Feld[x][y] == EL_EMC_SPRING_BUMPER || \
- Feld[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE))
+ (IN_LEV_FIELD(x, y) && (Tile[x][y] == EL_EMC_SPRING_BUMPER || \
+ Tile[x][y] == EL_EMC_SPRING_BUMPER_ACTIVE))
#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
- IS_EQUAL_OR_IN_GROUP(Feld[x][y], MOVE_ENTER_EL(e)))
+ IS_EQUAL_OR_IN_GROUP(Tile[x][y], MOVE_ENTER_EL(e)))
#define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \
ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y))
static void KillPlayerUnlessEnemyProtected(int, int);
static void KillPlayerUnlessExplosionProtected(int, int);
+static void CheckNextToConditions(int, int);
+static void TestIfPlayerNextToCustomElement(int, int);
static void TestIfPlayerTouchesCustomElement(int, int);
+static void TestIfElementNextToCustomElement(int, int);
static void TestIfElementTouchesCustomElement(int, int);
static void TestIfElementHitsCustomElement(int, int, int);
CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1)
#define CheckTriggeredElementChangeByPage(x, y, e, ev, p) \
CheckTriggeredElementChangeExt(x,y,e,ev, CH_PLAYER_ANY, CH_SIDE_ANY, p)
+#define CheckTriggeredElementChangeByMouse(x, y, e, ev, s) \
+ CheckTriggeredElementChangeExt(x, y, e, ev, CH_PLAYER_ANY, s, -1)
static boolean CheckElementChangeExt(int, int, int, int, int, int, int);
#define CheckElementChange(x, y, e, te, ev) \
CheckElementChangeExt(x, y, e, EL_EMPTY, ev, p, s)
#define CheckElementChangeBySide(x, y, e, te, ev, s) \
CheckElementChangeExt(x, y, e, te, ev, CH_PLAYER_ANY, s)
+#define CheckElementChangeByMouse(x, y, e, ev, s) \
+ CheckElementChangeExt(x, y, e, EL_UNDEFINED, ev, CH_PLAYER_ANY, s)
static void PlayLevelSound(int, int, int);
static void PlayLevelSoundNearest(int, int, int);
static void HandleGameButtons(struct GadgetInfo *);
-int AmoebeNachbarNr(int, int);
-void AmoebeUmwandeln(int, int);
+int AmoebaNeighbourNr(int, int);
+void AmoebaToDiamond(int, int);
void ContinueMoving(int, int);
void Bang(int, int);
void InitMovDir(int, int);
void InitAmoebaNr(int, int);
-int NewHiScore(int);
+void NewHighScore(int, boolean);
void TestIfGoodThingHitsBadThing(int, int, int);
void TestIfBadThingHitsGoodThing(int, int, int);
static int getInvisibleActiveFromInvisibleElement(int);
static int getInvisibleFromInvisibleActiveElement(int);
+static void TestFieldAfterSnapping(int, int, int, int, int);
+
static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
// for detection of endless loops, caused by custom element programming
{ EL_UNDEFINED, MV_NONE }
};
+static struct XY xy_topdown[] =
+{
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+};
+
static boolean trigger_events[MAX_NUM_ELEMENTS][NUM_CHANGE_EVENTS];
#define IS_AUTO_CHANGING(e) (element_info[e].has_change_event[CE_DELAY])
#define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0)
-#define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \
+#define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Tile[x][y]) || \
IS_JUST_CHANGING(x, y))
#define CE_PAGE(e, ce) (element_info[e].event_page[ce])
{
if (stored_player[0].present)
{
- Feld[x][y] = EL_SP_MURPHY_CLONE;
+ Tile[x][y] = EL_SP_MURPHY_CLONE;
return;
}
stored_player[0].artwork_element = EL_SP_MURPHY;
}
- Feld[x][y] = EL_PLAYER_1;
+ Tile[x][y] = EL_PLAYER_1;
}
}
if (init_game)
{
- struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
+ struct PlayerInfo *player = &stored_player[Tile[x][y] - EL_PLAYER_1];
int jx = player->jx, jy = player->jy;
player->present = TRUE;
player->active = TRUE;
// remove potentially duplicate players
- if (StorePlayer[jx][jy] == Feld[x][y])
+ if (IN_LEV_FIELD(jx, jy) && StorePlayer[jx][jy] == Tile[x][y])
StorePlayer[jx][jy] = 0;
- StorePlayer[x][y] = Feld[x][y];
+ StorePlayer[x][y] = Tile[x][y];
#if DEBUG_INIT_PLAYER
- if (options.debug)
- {
- printf("- player element %d activated", player->element_nr);
- printf(" (local player is %d and currently %s)\n",
- local_player->element_nr,
- local_player->active ? "active" : "not active");
- }
+ Debug("game:init:player", "- player element %d activated",
+ player->element_nr);
+ Debug("game:init:player", " (local player is %d and currently %s)",
+ local_player->element_nr,
+ local_player->active ? "active" : "not active");
}
#endif
- Feld[x][y] = EL_EMPTY;
+ Tile[x][y] = EL_EMPTY;
player->jx = player->last_jx = x;
player->jy = player->last_jy = y;
static void InitField(int x, int y, boolean init_game)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
switch (element)
{
break;
case EL_SOKOBAN_FIELD_PLAYER:
- element = Feld[x][y] = EL_PLAYER_1;
+ element = Tile[x][y] = EL_PLAYER_1;
InitField(x, y, init_game);
- element = Feld[x][y] = EL_SOKOBAN_FIELD_EMPTY;
+ element = Tile[x][y] = EL_SOKOBAN_FIELD_EMPTY;
InitField(x, y, init_game);
break;
break;
case EL_STONEBLOCK:
- if (x < lev_fieldx-1 && Feld[x+1][y] == EL_ACID)
- Feld[x][y] = EL_ACID_POOL_TOPLEFT;
- else if (x > 0 && Feld[x-1][y] == EL_ACID)
- Feld[x][y] = EL_ACID_POOL_TOPRIGHT;
- else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPLEFT)
- Feld[x][y] = EL_ACID_POOL_BOTTOMLEFT;
- else if (y > 0 && Feld[x][y-1] == EL_ACID)
- Feld[x][y] = EL_ACID_POOL_BOTTOM;
- else if (y > 0 && Feld[x][y-1] == EL_ACID_POOL_TOPRIGHT)
- Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
+ if (x < lev_fieldx - 1 && Tile[x + 1][y] == EL_ACID)
+ Tile[x][y] = EL_ACID_POOL_TOPLEFT;
+ else if (x > 0 && Tile[x - 1][y] == EL_ACID)
+ Tile[x][y] = EL_ACID_POOL_TOPRIGHT;
+ else if (y > 0 && Tile[x][y - 1] == EL_ACID_POOL_TOPLEFT)
+ Tile[x][y] = EL_ACID_POOL_BOTTOMLEFT;
+ else if (y > 0 && Tile[x][y - 1] == EL_ACID)
+ Tile[x][y] = EL_ACID_POOL_BOTTOM;
+ else if (y > 0 && Tile[x][y - 1] == EL_ACID_POOL_TOPRIGHT)
+ Tile[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
break;
case EL_BUG:
case EL_AMOEBA_DROP:
if (y == lev_fieldy - 1)
{
- Feld[x][y] = EL_AMOEBA_GROWING;
+ Tile[x][y] = EL_AMOEBA_GROWING;
Store[x][y] = EL_AMOEBA_WET;
}
break;
case EL_CONVEYOR_BELT_4_SWITCH_RIGHT:
if (init_game)
{
- int belt_nr = getBeltNrFromBeltSwitchElement(Feld[x][y]);
- int belt_dir = getBeltDirFromBeltSwitchElement(Feld[x][y]);
- int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Feld[x][y]);
+ int belt_nr = getBeltNrFromBeltSwitchElement(Tile[x][y]);
+ int belt_dir = getBeltDirFromBeltSwitchElement(Tile[x][y]);
+ int belt_dir_nr = getBeltDirNrFromBeltSwitchElement(Tile[x][y]);
if (game.belt_dir_nr[belt_nr] == 3) // initial value
{
}
else // more than one switch -- set it like the first switch
{
- Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
+ Tile[x][y] = Tile[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr];
}
}
break;
case EL_INVISIBLE_SAND:
if (game.light_time_left > 0 ||
game.lenses_time_left > 0)
- Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+ Tile[x][y] = getInvisibleActiveFromInvisibleElement(element);
break;
case EL_EMC_MAGIC_BALL:
if (game.ball_active)
- Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE;
+ Tile[x][y] = EL_EMC_MAGIC_BALL_ACTIVE;
break;
case EL_EMC_MAGIC_BALL_SWITCH:
if (game.ball_active)
- Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE;
+ Tile[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE;
break;
case EL_TRIGGER_PLAYER:
case EL_NEXT_CE_7:
case EL_NEXT_CE_8:
// reference elements should not be used on the playfield
- Feld[x][y] = EL_EMPTY;
+ Tile[x][y] = EL_EMPTY;
break;
default:
InitMovDir(x, y);
if (!element_info[element].use_last_ce_value || init_game)
- CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]);
+ CustomValue[x][y] = GET_NEW_CE_VALUE(Tile[x][y]);
}
else if (IS_GROUP_ELEMENT(element))
{
- Feld[x][y] = GetElementFromGroupElement(element);
+ Tile[x][y] = GetElementFromGroupElement(element);
InitField(x, y, init_game);
}
+ else if (IS_EMPTY_ELEMENT(element))
+ {
+ GfxElementEmpty[x][y] = element;
+ Tile[x][y] = EL_EMPTY;
+
+ if (element_info[element].use_gfx_element)
+ game.use_masked_elements = TRUE;
+ }
break;
}
// not needed to call InitMovDir() -- already done by InitField()!
if (game.engine_version < VERSION_IDENT(3,1,0,0) &&
- CAN_MOVE(Feld[x][y]))
+ CAN_MOVE(Tile[x][y]))
InitMovDir(x, y);
}
static void InitField_WithBug2(int x, int y, boolean init_game)
{
- int old_element = Feld[x][y];
+ int old_element = Tile[x][y];
InitField(x, y, init_game);
if (nr != i)
{
- Error(ERR_INFO, "'game_panel_controls' structure corrupted at %d", i);
- Error(ERR_EXIT, "this should not happen -- please debug");
+ Error("'game_panel_controls' structure corrupted at %d", i);
+
+ Fail("this should not happen -- please debug");
}
// force update of game controls after initialization
SCAN_PLAYFIELD(x, y)
{
- element_info[Feld[x][y]].element_count++;
+ element_info[Tile[x][y]].element_count++;
}
for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
game_sp.time_played :
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
game_mm.energy_left :
- game.no_time_limit ? TimePlayed : TimeLeft);
+ game.no_level_time_limit ? TimePlayed : TimeLeft);
int score = (game.LevelSolved ?
game.LevelSolved_CountingScore :
level.game_engine_type == GAME_ENGINE_TYPE_EM ?
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
MM_HEALTH(game_mm.laser_overload_value) :
game.health);
+ int sync_random_frame = INIT_GFX_RANDOM(); // random, but synchronized
UpdatePlayfieldElementCount();
stored_player[player_nr].num_white_keys;
}
+ // re-arrange keys on game panel, if needed or if defined by style settings
+ for (i = 0; i < MAX_NUM_KEYS + 1; i++) // all normal keys + white key
+ {
+ int nr = GAME_PANEL_KEY_1 + i;
+ struct GamePanelControlInfo *gpc = &game_panel_controls[nr];
+ struct TextPosInfo *pos = gpc->pos;
+
+ // skip check if key is not in the player's inventory
+ if (gpc->value == EL_EMPTY)
+ continue;
+
+ // check if keys should be arranged on panel from left to right
+ if (pos->style == STYLE_LEFTMOST_POSITION)
+ {
+ // check previous key positions (left from current key)
+ for (k = 0; k < i; k++)
+ {
+ int nr_new = GAME_PANEL_KEY_1 + k;
+
+ if (game_panel_controls[nr_new].value == EL_EMPTY)
+ {
+ game_panel_controls[nr_new].value = gpc->value;
+ gpc->value = EL_EMPTY;
+
+ break;
+ }
+ }
+ }
+
+ // check if "undefined" keys can be placed at some other position
+ if (pos->x == -1 && pos->y == -1)
+ {
+ int nr_new = GAME_PANEL_KEY_1 + i % STD_NUM_KEYS;
+
+ // 1st try: display key at the same position as normal or EM keys
+ if (game_panel_controls[nr_new].value == EL_EMPTY)
+ {
+ game_panel_controls[nr_new].value = gpc->value;
+ }
+ else
+ {
+ // 2nd try: display key at the next free position in the key panel
+ for (k = 0; k < STD_NUM_KEYS; k++)
+ {
+ nr_new = GAME_PANEL_KEY_1 + k;
+
+ if (game_panel_controls[nr_new].value == EL_EMPTY)
+ {
+ game_panel_controls[nr_new].value = gpc->value;
+
+ break;
+ }
+ }
+ }
+ }
+ }
+
for (i = 0; i < NUM_PANEL_INVENTORY; i++)
{
game_panel_controls[GAME_PANEL_INVENTORY_FIRST_1 + i].value =
}
game_panel_controls[GAME_PANEL_SCORE].value = score;
- game_panel_controls[GAME_PANEL_HIGHSCORE].value = highscore[0].Score;
+ game_panel_controls[GAME_PANEL_HIGHSCORE].value = scores.entry[0].score;
game_panel_controls[GAME_PANEL_TIME].value = time;
int last_anim_random_frame = gfx.anim_random_frame;
int element = gpc->value;
int graphic = el2panelimg(element);
+ int init_gfx_random = (graphic_info[graphic].anim_global_sync ?
+ sync_random_frame :
+ graphic_info[graphic].anim_global_anim_sync ?
+ getGlobalAnimSyncFrame() : INIT_GFX_RANDOM());
if (gpc->value != gpc->last_value)
{
gpc->gfx_frame = 0;
- gpc->gfx_random = INIT_GFX_RANDOM();
+ gpc->gfx_random = init_gfx_random;
}
else
{
if (ANIM_MODE(graphic) == ANIM_RANDOM &&
IS_NEXT_FRAME(gpc->gfx_frame, graphic))
- gpc->gfx_random = INIT_GFX_RANDOM();
+ gpc->gfx_random = init_gfx_random;
}
if (ANIM_MODE(graphic) == ANIM_RANDOM)
if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
gpc->gfx_frame = element_info[element].collect_score;
- gpc->frame = getGraphicAnimationFrame(el2panelimg(gpc->value),
- gpc->gfx_frame);
+ gpc->frame = getGraphicAnimationFrame(graphic, gpc->gfx_frame);
if (ANIM_MODE(graphic) == ANIM_RANDOM)
gfx.anim_random_frame = last_anim_random_frame;
{
int last_anim_random_frame = gfx.anim_random_frame;
int graphic = gpc->graphic;
+ int init_gfx_random = (graphic_info[graphic].anim_global_sync ?
+ sync_random_frame :
+ graphic_info[graphic].anim_global_anim_sync ?
+ getGlobalAnimSyncFrame() : INIT_GFX_RANDOM());
if (gpc->value != gpc->last_value)
{
gpc->gfx_frame = 0;
- gpc->gfx_random = INIT_GFX_RANDOM();
+ gpc->gfx_random = init_gfx_random;
}
else
{
if (ANIM_MODE(graphic) == ANIM_RANDOM &&
IS_NEXT_FRAME(gpc->gfx_frame, graphic))
- gpc->gfx_random = INIT_GFX_RANDOM();
+ gpc->gfx_random = init_gfx_random;
}
if (ANIM_MODE(graphic) == ANIM_RANDOM)
if (PANEL_DEACTIVATED(pos))
continue;
+ if (pos->class == get_hash_from_key("extra_panel_items") &&
+ !setup.prefer_extra_panel_items)
+ continue;
+
gpc->last_value = value;
gpc->last_frame = frame;
if (type == TYPE_INTEGER)
{
if (nr == GAME_PANEL_LEVEL_NUMBER ||
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_SCORE ||
+ nr == GAME_PANEL_HIGHSCORE ||
nr == GAME_PANEL_TIME)
{
boolean use_dynamic_size = (size == -1 ? TRUE : FALSE);
if (use_dynamic_size) // use dynamic number of digits
{
- int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 : 1000);
- int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 : 3);
- int size2 = size1 + 1;
+ int value_change = (nr == GAME_PANEL_LEVEL_NUMBER ? 100 :
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_TIME ? 1000 : 100000);
+ int size_add = (nr == GAME_PANEL_LEVEL_NUMBER ||
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_TIME ? 1 : 2);
+ int size1 = (nr == GAME_PANEL_LEVEL_NUMBER ? 2 :
+ nr == GAME_PANEL_INVENTORY_COUNT ||
+ nr == GAME_PANEL_TIME ? 3 : 5);
+ int size2 = size1 + size_add;
int font1 = pos->font;
int font2 = pos->font_alt;
element = value;
graphic = el2panelimg(value);
- // printf("::: %d, '%s' [%d]\n", element, EL_NAME(element), size);
+#if 0
+ Debug("game:DisplayGameControlValues", "%d, '%s' [%d]",
+ element, EL_NAME(element), size);
+#endif
if (element >= EL_GRAPHIC_1 && element <= EL_GRAPHIC_8 && size == 0)
size = TILESIZE;
DisplayGameControlValues();
}
-#if 0
-static void UpdateGameDoorValues(void)
+void UpdateGameDoorValues(void)
{
UpdateGameControlValues();
}
-#endif
void DrawGameDoorValues(void)
{
}
#if 0
- printf("level %d: level.game_version == %06d\n", level_nr,
- level.game_version);
- printf(" tape.file_version == %06d\n",
- tape.file_version);
- printf(" tape.game_version == %06d\n",
- tape.game_version);
- printf(" tape.engine_version == %06d\n",
- tape.engine_version);
- printf(" => game.engine_version == %06d [tape mode: %s]\n",
- game.engine_version, (tape.playing ? "PLAYING" : "RECORDING"));
+ Debug("game:init:level", "level %d: level.game_version == %06d", level_nr,
+ level.game_version);
+ Debug("game:init:level", " tape.file_version == %06d",
+ tape.file_version);
+ Debug("game:init:level", " tape.game_version == %06d",
+ tape.game_version);
+ Debug("game:init:level", " tape.engine_version == %06d",
+ tape.engine_version);
+ Debug("game:init:level", " => game.engine_version == %06d [tape mode: %s]",
+ game.engine_version, (tape.playing ? "PLAYING" : "RECORDING"));
#endif
// --------------------------------------------------------------------------
2.0.1
Bug was fixed in version:
- 4.1.4.2
+ 4.2.0.0
Description:
In version 2.0.1, a new run-time element "EL_AMOEBA_DROPPING" was added,
but the property "can fall" was missing, which caused some levels to be
- unsolvable. This was fixed in version 4.1.4.2.
+ unsolvable. This was fixed in version 4.2.0.0.
Affected levels/tapes:
An example for a tape that was fixed by this bugfix is tape 029 from the
boolean use_amoeba_dropping_cannot_fall_bug =
((game.engine_version >= VERSION_IDENT(2,0,1,0) &&
- game.engine_version <= VERSION_IDENT(4,1,4,1)) ||
+ game.engine_version < VERSION_IDENT(4,2,0,0)) ||
(tape.playing &&
tape.game_version >= VERSION_IDENT(2,0,1,0) &&
- tape.game_version <= VERSION_IDENT(4,1,4,1)));
+ tape.game_version < VERSION_IDENT(4,2,0,0)));
/*
Summary of bugfix/change:
The second condition is an exception from the above case and is needed for
the special case of tapes recorded with game (not engine!) version 2.0.1 or
above, but before it was known that this change would break tapes like the
- above and was fixed in 4.1.4.2, so that the changed behaviour was active
+ above and was fixed in 4.2.0.0, so that the changed behaviour was active
although the engine version while recording maybe was before 2.0.1. There
are a lot of tapes that are affected by this exception, like tape 006 from
the level set "rnd_conor_mancone".
(game.engine_version < VERSION_IDENT(2,0,1,0) &&
!(tape.playing &&
tape.game_version >= VERSION_IDENT(2,0,1,0) &&
- tape.game_version < VERSION_IDENT(4,1,4,2)));
+ tape.game_version < VERSION_IDENT(4,2,0,0)));
/*
Summary of bugfix/change:
game_em.use_snap_key_bug =
(game.engine_version < VERSION_IDENT(4,0,1,0));
- game_em.use_old_explosions =
- (game.engine_version < VERSION_IDENT(4,1,4,2));
+ game_em.use_random_bug =
+ (tape.property_bits & TAPE_PROPERTY_EM_RANDOM_BUG);
+
+ boolean use_old_em_engine = (game.engine_version < VERSION_IDENT(4,2,0,0));
- game_em.use_wrap_around =
- (game.engine_version > VERSION_IDENT(4,1,4,1));
+ game_em.use_old_explosions = use_old_em_engine;
+ game_em.use_old_android = use_old_em_engine;
+ game_em.use_old_push_elements = use_old_em_engine;
+ game_em.use_old_push_into_acid = use_old_em_engine;
+
+ game_em.use_wrap_around = !use_old_em_engine;
// --------------------------------------------------------------------------
// ---------- initialize special element properties -------------------------
- // "EL_AMOEBA_DROPPING" missed property "can fall" between 2.0.1 and 4.1.4.1
+ // "EL_AMOEBA_DROPPING" missed property "can fall" in older game versions
if (use_amoeba_dropping_cannot_fall_bug)
SET_PROPERTY(EL_AMOEBA_DROPPING, EP_CAN_FALL, FALSE);
if (!options.debug)
return;
- printf("%s:\n", message);
+ Debug("game:init:player", "%s:", message);
for (i = 0; i < MAX_PLAYERS; i++)
{
struct PlayerInfo *player = &stored_player[i];
- printf("- player %d: present == %d, connected == %d [%d/%d], active == %d",
- i + 1,
- player->present,
- player->connected,
- player->connected_locally,
- player->connected_network,
- player->active);
-
- if (local_player == player)
- printf(" (local player)");
-
- printf("\n");
+ Debug("game:init:player",
+ "- player %d: present == %d, connected == %d [%d/%d], active == %d%s",
+ i + 1,
+ player->present,
+ player->connected,
+ player->connected_locally,
+ player->connected_network,
+ player->active,
+ (local_player == player ? " (local player)" : ""));
}
}
#endif
int fade_mask = REDRAW_FIELD;
boolean emulate_bd = TRUE; // unless non-BOULDERDASH elements found
- boolean emulate_sb = TRUE; // unless non-SOKOBAN elements found
boolean emulate_sp = TRUE; // unless non-SUPAPLEX elements found
int initial_move_dir = MV_DOWN;
int i, j, x, y;
InitGameEngine();
InitGameControlValues();
- // initialize tape actions from game when recording tape
if (tape.recording)
{
+ // initialize tape actions from game when recording tape
tape.use_key_actions = game.use_key_actions;
tape.use_mouse_actions = game.use_mouse_actions;
+
+ // initialize visible playfield size when recording tape (for team mode)
+ tape.scr_fieldx = SCR_FIELDX;
+ tape.scr_fieldy = SCR_FIELDY;
}
// don't play tapes over network
player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr);
- player->actual_frame_counter = 0;
+ player->actual_frame_counter.count = 0;
+ player->actual_frame_counter.value = 1;
player->step_counter = 0;
player->shield_normal_time_left = 0;
player->shield_deadly_time_left = 0;
+ player->last_removed_element = EL_UNDEFINED;
+
player->inventory_infinite_element = EL_UNDEFINED;
player->inventory_size = 0;
game.panel.active = TRUE;
- game.no_time_limit = (level.time == 0);
+ game.no_level_time_limit = (level.time == 0);
+ game.time_limit = (leveldir_current->time_limit && setup.time_limit);
game.yamyam_content_nr = 0;
game.robot_wheel_active = FALSE;
game.switchgate_pos = 0;
game.wind_direction = level.wind_direction_initial;
+ game.time_final = 0;
+ game.score_time_final = 0;
+
game.score = 0;
game.score_final = 0;
game.envelope_active = FALSE;
+ // special case: set custom artwork setting to initial value
+ game.use_masked_elements = game.use_masked_elements_initial;
+
for (i = 0; i < NUM_BELTS; i++)
{
game.belt_dir[i] = MV_NONE;
SCAN_PLAYFIELD(x, y)
{
- Feld[x][y] = Last[x][y] = level.field[x][y];
+ Tile[x][y] = Last[x][y] = level.field[x][y];
MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
GfxFrame[x][y] = 0;
GfxRandom[x][y] = INIT_GFX_RANDOM();
+ GfxRandomStatic[x][y] = INIT_GFX_RANDOM();
GfxElement[x][y] = EL_UNDEFINED;
+ GfxElementEmpty[x][y] = EL_EMPTY;
GfxAction[x][y] = ACTION_DEFAULT;
GfxDir[x][y] = MV_NONE;
GfxRedraw[x][y] = GFX_REDRAW_NONE;
SCAN_PLAYFIELD(x, y)
{
- if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
+ if (emulate_bd && !IS_BD_ELEMENT(Tile[x][y]))
emulate_bd = FALSE;
- if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
- emulate_sb = FALSE;
- if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
+ if (emulate_sp && !IS_SP_ELEMENT(Tile[x][y]))
emulate_sp = FALSE;
InitField(x, y, TRUE);
}
game.emulation = (emulate_bd ? EMU_BOULDERDASH :
- emulate_sb ? EMU_SOKOBAN :
emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
// initialize type of slippery elements
#endif
#if DEBUG_INIT_PLAYER
- if (options.debug)
- printf("Reassigning players ...\n");
+ Debug("game:init:player", "Reassigning players ...");
#endif
// check if any connected player was not found in playfield
struct PlayerInfo *field_player = NULL;
#if DEBUG_INIT_PLAYER
- if (options.debug)
- printf("- looking for field player for player %d ...\n", i + 1);
+ Debug("game:init:player",
+ "- looking for field player for player %d ...", i + 1);
#endif
// assign first free player found that is present in the playfield
int jx = field_player->jx, jy = field_player->jy;
#if DEBUG_INIT_PLAYER
- if (options.debug)
- printf("- found player %d\n", field_player->index_nr + 1);
+ Debug("game:init:player", "- found player %d",
+ field_player->index_nr + 1);
#endif
player->present = FALSE;
field_player->mapped = TRUE;
#if DEBUG_INIT_PLAYER
- if (options.debug)
- printf("- map_player_action[%d] == %d\n",
- field_player->index_nr + 1, i + 1);
+ Debug("game:init:player", "- map_player_action[%d] == %d",
+ field_player->index_nr + 1, i + 1);
#endif
}
}
#endif
#if 0
- printf("::: local_player->present == %d\n", local_player->present);
+ Debug("game:init:player", "local_player->present == %d",
+ local_player->present);
#endif
// set focus to local player for network games, else to all players
int jx = player->jx, jy = player->jy;
#if DEBUG_INIT_PLAYER
- if (options.debug)
- printf("Removing player %d at (%d, %d)\n", i + 1, jx, jy);
+ Debug("game:init:player", "Removing player %d at (%d, %d)",
+ i + 1, jx, jy);
#endif
player->active = FALSE;
StorePlayer[jx][jy] = 0;
- Feld[jx][jy] = EL_EMPTY;
+ Tile[jx][jy] = EL_EMPTY;
}
}
}
player->active = FALSE;
StorePlayer[jx][jy] = 0;
- Feld[jx][jy] = EL_EMPTY;
+ Tile[jx][jy] = EL_EMPTY;
}
}
#endif
player->present = FALSE;
StorePlayer[jx][jy] = 0;
- Feld[jx][jy] = EL_EMPTY;
+ Tile[jx][jy] = EL_EMPTY;
}
}
}
SCAN_PLAYFIELD(x, y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int content;
int xx, yy;
boolean is_player;
{
// check for player created from custom element as single target
content = element_info[element].change_page[i].target_element;
- is_player = ELEM_IS_PLAYER(content);
+ is_player = IS_PLAYER_ELEMENT(content);
if (is_player && (found_rating < 3 ||
(found_rating == 3 && element < found_element)))
{
// check for player created from custom element as explosion content
content = element_info[element].content.e[xx][yy];
- is_player = ELEM_IS_PLAYER(content);
+ is_player = IS_PLAYER_ELEMENT(content);
if (is_player && (found_rating < 2 ||
(found_rating == 2 && element < found_element)))
content =
element_info[element].change_page[i].target_content.e[xx][yy];
- is_player = ELEM_IS_PLAYER(content);
+ is_player = IS_PLAYER_ELEMENT(content);
if (is_player && (found_rating < 1 ||
(found_rating == 1 && element < found_element)))
game.restart_level = FALSE;
game.restart_game_message = NULL;
+
game.request_active = FALSE;
+ game.request_active_or_moving = FALSE;
if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
InitGameActions_MM();
if (setup.sound_music)
PlayLevelMusic();
}
+
+ SetPlayfieldMouseCursorEnabled(!game.use_mouse_actions);
}
void UpdateEngineValues(int actual_scroll_x, int actual_scroll_y,
void InitMovDir(int x, int y)
{
- int i, element = Feld[x][y];
+ int i, element = Tile[x][y];
static int xy[4][2] =
{
{ 0, +1 },
case EL_BUG_UP:
case EL_BUG_LEFT:
case EL_BUG_DOWN:
- Feld[x][y] = EL_BUG;
+ Tile[x][y] = EL_BUG;
MovDir[x][y] = direction[0][element - EL_BUG_RIGHT];
break;
case EL_SPACESHIP_UP:
case EL_SPACESHIP_LEFT:
case EL_SPACESHIP_DOWN:
- Feld[x][y] = EL_SPACESHIP;
+ Tile[x][y] = EL_SPACESHIP;
MovDir[x][y] = direction[0][element - EL_SPACESHIP_RIGHT];
break;
case EL_BD_BUTTERFLY_UP:
case EL_BD_BUTTERFLY_LEFT:
case EL_BD_BUTTERFLY_DOWN:
- Feld[x][y] = EL_BD_BUTTERFLY;
+ Tile[x][y] = EL_BD_BUTTERFLY;
MovDir[x][y] = direction[0][element - EL_BD_BUTTERFLY_RIGHT];
break;
case EL_BD_FIREFLY_UP:
case EL_BD_FIREFLY_LEFT:
case EL_BD_FIREFLY_DOWN:
- Feld[x][y] = EL_BD_FIREFLY;
+ Tile[x][y] = EL_BD_FIREFLY;
MovDir[x][y] = direction[0][element - EL_BD_FIREFLY_RIGHT];
break;
case EL_PACMAN_UP:
case EL_PACMAN_LEFT:
case EL_PACMAN_DOWN:
- Feld[x][y] = EL_PACMAN;
+ Tile[x][y] = EL_PACMAN;
MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
break;
case EL_YAMYAM_RIGHT:
case EL_YAMYAM_UP:
case EL_YAMYAM_DOWN:
- Feld[x][y] = EL_YAMYAM;
+ Tile[x][y] = EL_YAMYAM;
MovDir[x][y] = direction[2][element - EL_YAMYAM_LEFT];
break;
case EL_MOLE_RIGHT:
case EL_MOLE_UP:
case EL_MOLE_DOWN:
- Feld[x][y] = EL_MOLE;
+ Tile[x][y] = EL_MOLE;
MovDir[x][y] = direction[2][element - EL_MOLE_LEFT];
break;
case EL_SPRING_LEFT:
case EL_SPRING_RIGHT:
- Feld[x][y] = EL_SPRING;
+ Tile[x][y] = EL_SPRING;
MovDir[x][y] = direction[2][element - EL_SPRING_LEFT];
break;
void InitAmoebaNr(int x, int y)
{
int i;
- int group_nr = AmoebeNachbarNr(x, y);
+ int group_nr = AmoebaNeighbourNr(x, y);
if (group_nr == 0)
{
AmoebaCnt2[group_nr]++;
}
-static void LevelSolved(void)
+static void LevelSolved_SetFinalGameValues(void)
{
- if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
- game.players_still_needed > 0)
- return;
-
- game.LevelSolved = TRUE;
- game.GameOver = TRUE;
+ game.time_final = (game.no_level_time_limit ? TimePlayed : TimeLeft);
+ game.score_time_final = (level.use_step_counter ? TimePlayed :
+ TimePlayed * FRAMES_PER_SECOND + TimeFrames);
game.score_final = (level.game_engine_type == GAME_ENGINE_TYPE_EM ?
game_em.lev->score :
level.game_engine_type == GAME_ENGINE_TYPE_MM ?
game_mm.score :
game.score);
+
game.health_final = (level.game_engine_type == GAME_ENGINE_TYPE_MM ?
MM_HEALTH(game_mm.laser_overload_value) :
game.health);
- game.LevelSolved_CountingTime = (game.no_time_limit ? TimePlayed : TimeLeft);
+ game.LevelSolved_CountingTime = game.time_final;
game.LevelSolved_CountingScore = game.score_final;
game.LevelSolved_CountingHealth = game.health_final;
}
+static void LevelSolved_DisplayFinalGameValues(int time, int score, int health)
+{
+ game.LevelSolved_CountingTime = time;
+ game.LevelSolved_CountingScore = score;
+ game.LevelSolved_CountingHealth = health;
+
+ game_panel_controls[GAME_PANEL_TIME].value = time;
+ game_panel_controls[GAME_PANEL_SCORE].value = score;
+ game_panel_controls[GAME_PANEL_HEALTH].value = health;
+
+ DisplayGameControlValues();
+}
+
+static void LevelSolved(void)
+{
+ if (level.game_engine_type == GAME_ENGINE_TYPE_RND &&
+ game.players_still_needed > 0)
+ return;
+
+ game.LevelSolved = TRUE;
+ game.GameOver = TRUE;
+
+ tape.solved = TRUE;
+
+ // needed here to display correct panel values while player walks into exit
+ LevelSolved_SetFinalGameValues();
+}
+
void GameWon(void)
{
static int time_count_steps;
static int time, time_final;
- static int score, score_final;
+ static float score, score_final; // needed for time score < 10 for 10 seconds
static int health, health_final;
static int game_over_delay_1 = 0;
static int game_over_delay_2 = 0;
static int game_over_delay_3 = 0;
- int game_over_delay_value_1 = 50;
- int game_over_delay_value_2 = 25;
- int game_over_delay_value_3 = 50;
+ int time_score_base = MIN(MAX(1, level.time_score_base), 10);
+ float time_score = (float)level.score[SC_TIME_BONUS] / time_score_base;
if (!game.LevelSolved_GameWon)
{
if (local_player->active && local_player->MovPos)
return;
+ // calculate final game values after player finished walking into exit
+ LevelSolved_SetFinalGameValues();
+
game.LevelSolved_GameWon = TRUE;
game.LevelSolved_SaveTape = tape.recording;
game.LevelSolved_SaveScore = !tape.playing;
TapeStop();
- game_over_delay_1 = 0;
- game_over_delay_2 = 0;
- game_over_delay_3 = game_over_delay_value_3;
+ game_over_delay_1 = FRAMES_PER_SECOND; // delay before counting time
+ game_over_delay_2 = FRAMES_PER_SECOND / 2; // delay before counting health
+ game_over_delay_3 = FRAMES_PER_SECOND; // delay before ending the game
- time = time_final = (game.no_time_limit ? TimePlayed : TimeLeft);
+ time = time_final = game.time_final;
score = score_final = game.score_final;
health = health_final = game.health_final;
- if (level.score[SC_TIME_BONUS] > 0)
+ // update game panel values before (delayed) counting of score (if any)
+ LevelSolved_DisplayFinalGameValues(time, score, health);
+
+ // if level has time score defined, calculate new final game values
+ if (time_score > 0)
{
+ int time_final_max = 999;
+ int time_frames_final_max = time_final_max * FRAMES_PER_SECOND;
+ int time_frames = 0;
+ int time_frames_left = TimeLeft * FRAMES_PER_SECOND - TimeFrames;
+ int time_frames_played = TimePlayed * FRAMES_PER_SECOND + TimeFrames;
+
if (TimeLeft > 0)
{
time_final = 0;
- score_final += TimeLeft * level.score[SC_TIME_BONUS];
+ time_frames = time_frames_left;
}
- else if (game.no_time_limit && TimePlayed < 999)
+ else if (game.no_level_time_limit && TimePlayed < time_final_max)
{
- time_final = 999;
- score_final += (999 - TimePlayed) * level.score[SC_TIME_BONUS];
+ time_final = time_final_max;
+ time_frames = time_frames_final_max - time_frames_played;
}
- time_count_steps = MAX(1, ABS(time_final - time) / 100);
+ score_final += time_score * time_frames / FRAMES_PER_SECOND + 0.5;
- game_over_delay_1 = game_over_delay_value_1;
+ time_count_steps = MAX(1, ABS(time_final - time) / 100);
if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
{
health_final = 0;
- score_final += health * level.score[SC_TIME_BONUS];
-
- game_over_delay_2 = game_over_delay_value_2;
+ score_final += health * time_score;
}
game.score_final = score_final;
game.health_final = health_final;
}
- if (level_editor_test_game)
+ // if not counting score after game, immediately update game panel values
+ if (level_editor_test_game || !setup.count_score_after_game)
{
time = time_final;
score = score_final;
- game.LevelSolved_CountingTime = time;
- game.LevelSolved_CountingScore = score;
-
- game_panel_controls[GAME_PANEL_TIME].value = time;
- game_panel_controls[GAME_PANEL_SCORE].value = score;
-
- DisplayGameControlValues();
+ LevelSolved_DisplayFinalGameValues(time, score, health);
}
if (level.game_engine_type == GAME_ENGINE_TYPE_RND)
{
int x = game.exit_x;
int y = game.exit_y;
- int element = Feld[x][y];
+ int element = Tile[x][y];
// close exit door after last player
if ((game.all_players_gone &&
element == EL_EM_STEEL_EXIT_OPEN)
{
- Feld[x][y] =
+ Tile[x][y] =
(element == EL_EXIT_OPEN ? EL_EXIT_CLOSING :
element == EL_EM_EXIT_OPEN ? EL_EM_EXIT_CLOSING :
element == EL_SP_EXIT_OPEN ? EL_SP_EXIT_CLOSING:
PlaySound(SND_GAME_WINNING);
}
- if (game_over_delay_1 > 0)
- {
- game_over_delay_1--;
-
- return;
- }
-
- if (time != time_final)
+ if (setup.count_score_after_game)
{
- int time_to_go = ABS(time_final - time);
- int time_count_dir = (time < time_final ? +1 : -1);
+ if (time != time_final)
+ {
+ if (game_over_delay_1 > 0)
+ {
+ game_over_delay_1--;
- if (time_to_go < time_count_steps)
- time_count_steps = 1;
+ return;
+ }
- time += time_count_steps * time_count_dir;
- score += time_count_steps * level.score[SC_TIME_BONUS];
+ int time_to_go = ABS(time_final - time);
+ int time_count_dir = (time < time_final ? +1 : -1);
- game.LevelSolved_CountingTime = time;
- game.LevelSolved_CountingScore = score;
+ if (time_to_go < time_count_steps)
+ time_count_steps = 1;
- game_panel_controls[GAME_PANEL_TIME].value = time;
- game_panel_controls[GAME_PANEL_SCORE].value = score;
+ time += time_count_steps * time_count_dir;
+ score += time_count_steps * time_score;
- DisplayGameControlValues();
+ // set final score to correct rounding differences after counting score
+ if (time == time_final)
+ score = score_final;
- if (time == time_final)
- StopSound(SND_GAME_LEVELTIME_BONUS);
- else if (setup.sound_loops)
- PlaySoundLoop(SND_GAME_LEVELTIME_BONUS);
- else
- PlaySound(SND_GAME_LEVELTIME_BONUS);
+ LevelSolved_DisplayFinalGameValues(time, score, health);
- return;
- }
-
- if (game_over_delay_2 > 0)
- {
- game_over_delay_2--;
+ if (time == time_final)
+ StopSound(SND_GAME_LEVELTIME_BONUS);
+ else if (setup.sound_loops)
+ PlaySoundLoop(SND_GAME_LEVELTIME_BONUS);
+ else
+ PlaySound(SND_GAME_LEVELTIME_BONUS);
- return;
- }
+ return;
+ }
- if (health != health_final)
- {
- int health_count_dir = (health < health_final ? +1 : -1);
+ if (health != health_final)
+ {
+ if (game_over_delay_2 > 0)
+ {
+ game_over_delay_2--;
- health += health_count_dir;
- score += level.score[SC_TIME_BONUS];
+ return;
+ }
- game.LevelSolved_CountingHealth = health;
- game.LevelSolved_CountingScore = score;
+ int health_count_dir = (health < health_final ? +1 : -1);
- game_panel_controls[GAME_PANEL_HEALTH].value = health;
- game_panel_controls[GAME_PANEL_SCORE].value = score;
+ health += health_count_dir;
+ score += time_score;
- DisplayGameControlValues();
+ LevelSolved_DisplayFinalGameValues(time, score, health);
- if (health == health_final)
- StopSound(SND_GAME_LEVELTIME_BONUS);
- else if (setup.sound_loops)
- PlaySoundLoop(SND_GAME_LEVELTIME_BONUS);
- else
- PlaySound(SND_GAME_LEVELTIME_BONUS);
+ if (health == health_final)
+ StopSound(SND_GAME_LEVELTIME_BONUS);
+ else if (setup.sound_loops)
+ PlaySoundLoop(SND_GAME_LEVELTIME_BONUS);
+ else
+ PlaySound(SND_GAME_LEVELTIME_BONUS);
- return;
+ return;
+ }
}
game.panel.active = FALSE;
{
// used instead of "level_nr" (needed for network games)
int last_level_nr = levelset.level_nr;
- int hi_pos;
+ boolean tape_saved = FALSE;
game.LevelSolved_GameEnd = TRUE;
- if (game.LevelSolved_SaveTape)
+ if (game.LevelSolved_SaveTape && !score_info_tape_play)
{
// make sure that request dialog to save tape does not open door again
if (!global.use_envelope_request)
CloseDoor(DOOR_CLOSE_1);
- SaveTapeChecked_LevelSolved(tape.level_nr); // ask to save tape
+ // ask to save tape
+ tape_saved = SaveTapeChecked_LevelSolved(tape.level_nr);
+
+ // set unique basename for score tape (also saved in high score table)
+ strcpy(tape.score_tape_basename, getScoreTapeBasename(setup.player_name));
}
// if no tape is to be saved, close both doors simultaneously
CloseDoor(DOOR_CLOSE_ALL);
- if (level_editor_test_game)
+ if (level_editor_test_game || score_info_tape_play)
{
SetGameStatus(GAME_MODE_MAIN);
SaveLevelSetup_SeriesInfo();
}
+ // save score and score tape before potentially erasing tape below
+ NewHighScore(last_level_nr, tape_saved);
+
if (setup.increment_levels &&
level_nr < leveldir_current->last_level &&
!network_playing)
if (setup.auto_play_next_level)
{
+ scores.continue_playing = TRUE;
+ scores.next_level_nr = level_nr;
+
LoadLevel(level_nr);
SaveLevelSetup_SeriesInfo();
}
}
- hi_pos = NewHiScore(last_level_nr);
-
- if (hi_pos >= 0 && !setup.skip_scores_after_game)
+ if (scores.last_added >= 0 && setup.show_scores_after_game)
{
SetGameStatus(GAME_MODE_SCORES);
- DrawHallOfFame(last_level_nr, hi_pos);
+ DrawHallOfFame(last_level_nr);
}
- else if (setup.auto_play_next_level && setup.increment_levels &&
- last_level_nr < leveldir_current->last_level &&
- !network_playing)
+ else if (scores.continue_playing)
{
StartGameActions(network.enabled, setup.autorecord, level.random_seed);
}
}
}
-int NewHiScore(int level_nr)
+static int addScoreEntry(struct ScoreInfo *list, struct ScoreEntry *new_entry,
+ boolean one_score_entry_per_name)
{
- int k, l;
- int position = -1;
- boolean one_score_entry_per_name = !program.many_scores_per_name;
-
- LoadScore(level_nr);
+ int i;
- if (strEqual(setup.player_name, EMPTY_PLAYER_NAME) ||
- game.score_final < highscore[MAX_SCORE_ENTRIES - 1].Score)
+ if (strEqual(new_entry->name, EMPTY_PLAYER_NAME))
return -1;
- for (k = 0; k < MAX_SCORE_ENTRIES; k++)
+ for (i = 0; i < MAX_SCORE_ENTRIES; i++)
{
- if (game.score_final > highscore[k].Score)
+ struct ScoreEntry *entry = &list->entry[i];
+ boolean score_is_better = (new_entry->score > entry->score);
+ boolean score_is_equal = (new_entry->score == entry->score);
+ boolean time_is_better = (new_entry->time < entry->time);
+ boolean time_is_equal = (new_entry->time == entry->time);
+ boolean better_by_score = (score_is_better ||
+ (score_is_equal && time_is_better));
+ boolean better_by_time = (time_is_better ||
+ (time_is_equal && score_is_better));
+ boolean is_better = (level.rate_time_over_score ? better_by_time :
+ better_by_score);
+ boolean entry_is_empty = (entry->score == 0 &&
+ entry->time == 0);
+
+ // prevent adding server score entries if also existing in local score file
+ // (special case: historic score entries have an empty tape basename entry)
+ if (strEqual(new_entry->tape_basename, entry->tape_basename) &&
+ !strEqual(new_entry->tape_basename, UNDEFINED_FILENAME))
+ {
+ // add fields from server score entry not stored in local score entry
+ // (currently, this means setting platform, version and country fields;
+ // in rare cases, this may also correct an invalid score value, as
+ // historic scores might have been truncated to 16-bit values locally)
+ *entry = *new_entry;
+
+ return -1;
+ }
+
+ if (is_better || entry_is_empty)
{
// player has made it to the hall of fame
- if (k < MAX_SCORE_ENTRIES - 1)
+ if (i < MAX_SCORE_ENTRIES - 1)
{
int m = MAX_SCORE_ENTRIES - 1;
+ int l;
if (one_score_entry_per_name)
{
- for (l = k; l < MAX_SCORE_ENTRIES; l++)
- if (strEqual(setup.player_name, highscore[l].Name))
+ for (l = i; l < MAX_SCORE_ENTRIES; l++)
+ if (strEqual(list->entry[l].name, new_entry->name))
m = l;
- if (m == k) // player's new highscore overwrites his old one
+ if (m == i) // player's new highscore overwrites his old one
goto put_into_list;
}
- for (l = m; l > k; l--)
- {
- strcpy(highscore[l].Name, highscore[l - 1].Name);
- highscore[l].Score = highscore[l - 1].Score;
- }
+ for (l = m; l > i; l--)
+ list->entry[l] = list->entry[l - 1];
}
put_into_list:
- strncpy(highscore[k].Name, setup.player_name, MAX_PLAYER_NAME_LEN);
- highscore[k].Name[MAX_PLAYER_NAME_LEN] = '\0';
- highscore[k].Score = game.score_final;
- position = k;
+ *entry = *new_entry;
- break;
+ return i;
}
else if (one_score_entry_per_name &&
- !strncmp(setup.player_name, highscore[k].Name,
- MAX_PLAYER_NAME_LEN))
- break; // player already there with a higher score
+ strEqual(entry->name, new_entry->name))
+ {
+ // player already in high score list with better score or time
+
+ return -1;
+ }
}
- if (position >= 0)
- SaveScore(level_nr);
+ // special case: new score is beyond the last high score list position
+ return MAX_SCORE_ENTRIES;
+}
+
+void NewHighScore(int level_nr, boolean tape_saved)
+{
+ struct ScoreEntry new_entry = {{ 0 }}; // (prevent warning from GCC bug 53119)
+ boolean one_per_name = FALSE;
+
+ strncpy(new_entry.tape_basename, tape.score_tape_basename, MAX_FILENAME_LEN);
+ strncpy(new_entry.name, setup.player_name, MAX_PLAYER_NAME_LEN);
+
+ new_entry.score = game.score_final;
+ new_entry.time = game.score_time_final;
+
+ LoadScore(level_nr);
+
+ scores.last_added = addScoreEntry(&scores, &new_entry, one_per_name);
+
+ if (scores.last_added >= MAX_SCORE_ENTRIES)
+ {
+ scores.last_added = MAX_SCORE_ENTRIES - 1;
+ scores.force_last_added = TRUE;
+
+ scores.entry[scores.last_added] = new_entry;
+
+ // store last added local score entry (before merging server scores)
+ scores.last_added_local = scores.last_added;
+
+ return;
+ }
+
+ if (scores.last_added < 0)
+ return;
+
+ SaveScore(level_nr);
+
+ // store last added local score entry (before merging server scores)
+ scores.last_added_local = scores.last_added;
+
+ if (!game.LevelSolved_SaveTape)
+ return;
+
+ SaveScoreTape(level_nr);
+
+ if (setup.ask_for_using_api_server)
+ {
+ setup.use_api_server =
+ Request("Upload your score and tape to the high score server?", REQ_ASK);
+
+ if (!setup.use_api_server)
+ Request("Not using high score server! Use setup menu to enable again!",
+ REQ_CONFIRM);
+
+ runtime.use_api_server = setup.use_api_server;
+
+ // after asking for using API server once, do not ask again
+ setup.ask_for_using_api_server = FALSE;
+
+ SaveSetup_ServerSetup();
+ }
+
+ SaveServerScore(level_nr, tape_saved);
+}
+
+void MergeServerScore(void)
+{
+ struct ScoreEntry last_added_entry;
+ boolean one_per_name = FALSE;
+ int i;
+
+ if (scores.last_added >= 0)
+ last_added_entry = scores.entry[scores.last_added];
+
+ for (i = 0; i < server_scores.num_entries; i++)
+ {
+ int pos = addScoreEntry(&scores, &server_scores.entry[i], one_per_name);
+
+ if (pos >= 0 && pos <= scores.last_added)
+ scores.last_added++;
+ }
+
+ if (scores.last_added >= MAX_SCORE_ENTRIES)
+ {
+ scores.last_added = MAX_SCORE_ENTRIES - 1;
+ scores.force_last_added = TRUE;
- return position;
+ scores.entry[scores.last_added] = last_added_entry;
+ }
}
static int getElementMoveStepsizeExt(int x, int y, int direction)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
int horiz_move = (dx != 0);
if (horiz_move)
{
if (CAN_FALL(element) &&
- y < lev_fieldy - 1 && IS_BELT_ACTIVE(Feld[x][y + 1]))
+ y < lev_fieldy - 1 && IS_BELT_ACTIVE(Tile[x][y + 1]))
step = sign * MOVE_STEPSIZE_NORMAL / 2;
else if (element == EL_SPRING)
step = sign * MOVE_STEPSIZE_NORMAL * 2;
if (DrawingDeactivatedField())
return;
- int element = Feld[x][y];
+ int element = Tile[x][y];
int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
if (graphic_info[graphic].anim_global_sync)
GfxFrame[x][y] = FrameCounter;
+ else if (graphic_info[graphic].anim_global_anim_sync)
+ GfxFrame[x][y] = getGlobalAnimSyncFrame();
else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
GfxFrame[x][y] = CustomValue[x][y];
else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
static void InitMovingField(int x, int y, int direction)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
int newx = x + dx;
if (is_moving_after)
{
- if (Feld[newx][newy] == EL_EMPTY)
- Feld[newx][newy] = EL_BLOCKED;
+ if (Tile[newx][newy] == EL_EMPTY)
+ Tile[newx][newy] = EL_BLOCKED;
MovDir[newx][newy] = MovDir[x][y];
static int MovingOrBlocked2Element(int x, int y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (element == EL_BLOCKED)
{
int oldx, oldy;
Blocked2Moving(x, y, &oldx, &oldy);
- return Feld[oldx][oldy];
+ return Tile[oldx][oldy];
}
else
return element;
// like MovingOrBlocked2Element(), but if element is moving
// and (x,y) is the field the moving element is just leaving,
// return EL_BLOCKED instead of the element value
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (IS_MOVING(x, y))
{
int oldx, oldy;
Blocked2Moving(x, y, &oldx, &oldy);
- return Feld[oldx][oldy];
+ return Tile[oldx][oldy];
}
else
return EL_BLOCKED;
static void RemoveField(int x, int y)
{
- Feld[x][y] = EL_EMPTY;
+ Tile[x][y] = EL_EMPTY;
MovPos[x][y] = 0;
MovDir[x][y] = 0;
static void RemoveMovingField(int x, int y)
{
int oldx = x, oldy = y, newx = x, newy = y;
- int element = Feld[x][y];
+ int element = Tile[x][y];
int next_element = EL_UNDEFINED;
if (element != EL_BLOCKED && !IS_MOVING(x, y))
{
Moving2Blocked(x, y, &newx, &newy);
- if (Feld[newx][newy] != EL_BLOCKED)
+ if (Tile[newx][newy] != EL_BLOCKED)
{
// element is moving, but target field is not free (blocked), but
// already occupied by something different (example: acid pool);
}
if (element == EL_BLOCKED &&
- (Feld[oldx][oldy] == EL_QUICKSAND_EMPTYING ||
- Feld[oldx][oldy] == EL_QUICKSAND_FAST_EMPTYING ||
- Feld[oldx][oldy] == EL_MAGIC_WALL_EMPTYING ||
- Feld[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING ||
- Feld[oldx][oldy] == EL_DC_MAGIC_WALL_EMPTYING ||
- Feld[oldx][oldy] == EL_AMOEBA_DROPPING))
- next_element = get_next_element(Feld[oldx][oldy]);
+ (Tile[oldx][oldy] == EL_QUICKSAND_EMPTYING ||
+ Tile[oldx][oldy] == EL_QUICKSAND_FAST_EMPTYING ||
+ Tile[oldx][oldy] == EL_MAGIC_WALL_EMPTYING ||
+ Tile[oldx][oldy] == EL_BD_MAGIC_WALL_EMPTYING ||
+ Tile[oldx][oldy] == EL_DC_MAGIC_WALL_EMPTYING ||
+ Tile[oldx][oldy] == EL_AMOEBA_DROPPING))
+ next_element = get_next_element(Tile[oldx][oldy]);
RemoveField(oldx, oldy);
RemoveField(newx, newy);
Store[oldx][oldy] = Store2[oldx][oldy] = 0;
if (next_element != EL_UNDEFINED)
- Feld[oldx][oldy] = next_element;
+ Tile[oldx][oldy] = next_element;
TEST_DrawLevelField(oldx, oldy);
TEST_DrawLevelField(newx, newy);
void DrawDynamite(int x, int y)
{
int sx = SCREENX(x), sy = SCREENY(y);
- int graphic = el2img(Feld[x][y]);
+ int graphic = el2img(Tile[x][y]);
int frame;
if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
return;
if (Back[x][y])
- DrawGraphic(sx, sy, el2img(Back[x][y]), 0);
+ DrawLevelElement(x, y, Back[x][y]);
else if (Store[x][y])
- DrawGraphic(sx, sy, el2img(Store[x][y]), 0);
+ DrawLevelElement(x, y, Store[x][y]);
+ else if (game.use_masked_elements)
+ DrawLevelElement(x, y, EL_EMPTY);
- frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+ frame = getGraphicAnimationFrameXY(graphic, x, y);
- if (Back[x][y] || Store[x][y])
+ if (Back[x][y] || Store[x][y] || game.use_masked_elements)
DrawGraphicThruMask(sx, sy, graphic, frame);
else
DrawGraphic(sx, sy, graphic, frame);
*sy = (sy1 + sy2) / 2;
}
-static void DrawRelocateScreen(int old_x, int old_y, int x, int y, int move_dir,
+static void DrawRelocateScreen(int old_x, int old_y, int x, int y,
boolean center_screen, boolean quick_relocation)
{
unsigned int frame_delay_value_old = GetVideoFrameDelay();
int wait_delay_value = (no_delay ? 0 : frame_delay_value);
int old_jx = player->jx;
int old_jy = player->jy;
- int old_element = Feld[old_jx][old_jy];
- int element = Feld[jx][jy];
+ int old_element = Tile[old_jx][old_jy];
+ int element = Tile[jx][jy];
boolean player_relocated = (old_jx != jx || old_jy != jy);
int move_dir_horiz = (jx < old_jx ? MV_LEFT : jx > old_jx ? MV_RIGHT : 0);
CE_PLAYER_LEAVES_X,
player->index_bit, leave_side);
- Feld[jx][jy] = el_player;
+ Tile[jx][jy] = el_player;
InitPlayerField(jx, jy, el_player, TRUE);
- /* "InitPlayerField()" above sets Feld[jx][jy] to EL_EMPTY, but it may be
+ /* "InitPlayerField()" above sets Tile[jx][jy] to EL_EMPTY, but it may be
possible that the relocation target field did not contain a player element,
but a walkable element, to which the new player was relocated -- in this
case, restore that (already initialized!) element on the player field */
- if (!ELEM_IS_PLAYER(element)) // player may be set on walkable element
+ if (!IS_PLAYER_ELEMENT(element)) // player may be set on walkable element
{
- Feld[jx][jy] = element; // restore previously existing element
+ Tile[jx][jy] = element; // restore previously existing element
}
// only visually relocate centered player
- DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy, player->MovDir,
+ DrawRelocateScreen(old_jx, old_jy, player->jx, player->jy,
FALSE, level.instant_relocation);
TestIfPlayerTouchesBadThing(jx, jy);
if (phase == EX_PHASE_START) // initialize 'Store[][]' field
{
- int center_element = Feld[ex][ey];
+ int center_element = Tile[ex][ey];
int artwork_element, explosion_element; // set these values later
// remove things displayed in background while burning dynamite
// put moving element to center field (and let it explode there)
center_element = MovingOrBlocked2Element(ex, ey);
RemoveMovingField(ex, ey);
- Feld[ex][ey] = center_element;
+ Tile[ex][ey] = center_element;
}
// now "center_element" is finally determined -- set related values now
(mode == EX_TYPE_CROSS && (x != ex && y != ey)))
continue;
- element = Feld[x][y];
+ element = Tile[x][y];
if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
{
if (IS_ACTIVE_BOMB(element))
{
// re-activate things under the bomb like gate or penguin
- Feld[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY);
+ Tile[x][y] = (Back[x][y] ? Back[x][y] : EL_EMPTY);
Back[x][y] = 0;
}
// !!! check this case -- currently needed for rnd_rado_negundo_v,
// !!! levels 015 018 019 020 021 022 023 026 027 028 !!!
- else if (ELEM_IS_PLAYER(center_element))
+ else if (IS_PLAYER_ELEMENT(center_element))
Store[x][y] = EL_EMPTY;
else if (center_element == EL_YAMYAM)
Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
center_element == EL_AMOEBA_TO_DIAMOND)
Store2[x][y] = element;
- Feld[x][y] = EL_EXPLOSION;
+ Tile[x][y] = EL_EXPLOSION;
GfxElement[x][y] = artwork_element;
ExplodePhase[x][y] = 1;
}
else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
{
- Feld[x][y] = Store2[x][y];
+ Tile[x][y] = Store2[x][y];
Store2[x][y] = 0;
Bang(x, y);
border_explosion = TRUE;
}
else if (border_element == EL_AMOEBA_TO_DIAMOND)
{
- AmoebeUmwandeln(x, y);
+ AmoebaToDiamond(x, y);
Store2[x][y] = 0;
border_explosion = TRUE;
}
return;
}
+ // this can happen if the player was just killed by an explosion
+ if (GfxElement[x][y] == EL_UNDEFINED)
+ GfxElement[x][y] = EL_EMPTY;
+
if (phase == last_phase)
{
int element;
- element = Feld[x][y] = Store[x][y];
+ element = Tile[x][y] = Store[x][y];
Store[x][y] = Store2[x][y] = 0;
GfxElement[x][y] = EL_UNDEFINED;
if (level.use_explosion_element[player_nr])
explosion_element = level.explosion_element[player_nr];
- Feld[x][y] = (stored_player[player_nr].active ? EL_EMPTY :
+ Tile[x][y] = (stored_player[player_nr].active ? EL_EMPTY :
element_info[explosion_element].content.e[xx][yy]);
}
// restore probably existing indestructible background element
if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
- element = Feld[x][y] = Back[x][y];
+ element = Tile[x][y] = Back[x][y];
Back[x][y] = 0;
MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
if (IS_PLAYER(x, y) && !PLAYERINFO(x, y)->present)
StorePlayer[x][y] = 0;
- if (ELEM_IS_PLAYER(element))
+ if (IS_PLAYER_ELEMENT(element))
RelocatePlayer(x, y, element);
}
else if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
- int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+ int frame = getGraphicAnimationFrameXY(graphic, x, y);
if (phase == delay)
TEST_DrawLevelFieldCrumbled(x, y);
}
else if (IS_WALKABLE_UNDER(Back[x][y]))
{
- DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ DrawLevelGraphic(x, y, graphic, frame);
DrawLevelElementThruMask(x, y, Back[x][y]);
}
else if (!IS_WALKABLE_INSIDE(Back[x][y]))
- DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ DrawLevelGraphic(x, y, graphic, frame);
}
}
static void DynaExplode(int ex, int ey)
{
int i, j;
- int dynabomb_element = Feld[ex][ey];
+ int dynabomb_element = Tile[ex][ey];
int dynabomb_size = 1;
boolean dynabomb_xl = FALSE;
struct PlayerInfo *player;
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
if (IS_ACTIVE_BOMB(dynabomb_element))
{
{
for (j = 1; j <= dynabomb_size; j++)
{
- int x = ex + j * xy[i][0];
- int y = ey + j * xy[i][1];
+ int x = ex + j * xy[i].x;
+ int y = ey + j * xy[i].y;
int element;
- if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Feld[x][y]))
+ if (!IN_LEV_FIELD(x, y) || IS_INDESTRUCTIBLE(Tile[x][y]))
break;
- element = Feld[x][y];
+ element = Tile[x][y];
// do not restart explosions of fields with active bombs
if (element == EL_EXPLOSION && IS_ACTIVE_BOMB(Store2[x][y]))
{
struct PlayerInfo *player = PLAYERINFO(x, y);
- element = Feld[x][y] = player->initial_element;
+ element = Tile[x][y] = player->initial_element;
if (level.use_explosion_element[player->index_nr])
{
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;
+ Tile[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;
+ Tile[x + 1][y - 1] = EL_ACID_SPLASH_RIGHT;
PlayLevelSound(x, y, SND_ACID_SPLASHING);
}
SCAN_PLAYFIELD(x, y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
for (i = 0; i < NUM_BELTS; i++)
{
if (e_belt_nr == belt_nr)
{
- int belt_part = Feld[x][y] - belt_base_element[belt_nr];
+ int belt_part = Tile[x][y] - belt_base_element[belt_nr];
- Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
+ Tile[x][y] = belt_base_active_element[belt_nr] + belt_part;
}
}
}
MV_NONE,
};
- int element = Feld[x][y];
+ int element = Tile[x][y];
int belt_nr = getBeltNrFromBeltSwitchElement(element);
int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
int belt_dir = belt_move_dir[belt_dir_nr];
SCAN_PLAYFIELD(xx, yy)
{
- int element = Feld[xx][yy];
+ int element = Tile[xx][yy];
if (IS_BELT_SWITCH(element))
{
if (e_belt_nr == belt_nr)
{
- Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
+ Tile[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
TEST_DrawLevelField(xx, yy);
}
}
if (e_belt_nr == belt_nr)
{
- int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
+ int belt_part = Tile[xx][yy] - belt_base_element[belt_nr];
- Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
+ Tile[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
TEST_DrawLevelField(xx, yy);
}
}
if (e_belt_nr == belt_nr)
{
- int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
+ int belt_part = Tile[xx][yy] - belt_base_active_element[belt_nr];
- Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
+ Tile[xx][yy] = belt_base_element[belt_nr] + belt_part;
TEST_DrawLevelField(xx, yy);
}
}
}
}
-static void ToggleSwitchgateSwitch(int x, int y)
+static void ToggleSwitchgateSwitch(void)
{
int xx, yy;
SCAN_PLAYFIELD(xx, yy)
{
- int element = Feld[xx][yy];
+ int element = Tile[xx][yy];
if (element == EL_SWITCHGATE_SWITCH_UP)
{
- Feld[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN;
+ Tile[xx][yy] = EL_SWITCHGATE_SWITCH_DOWN;
TEST_DrawLevelField(xx, yy);
}
else if (element == EL_SWITCHGATE_SWITCH_DOWN)
{
- Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP;
+ Tile[xx][yy] = EL_SWITCHGATE_SWITCH_UP;
TEST_DrawLevelField(xx, yy);
}
else if (element == EL_DC_SWITCHGATE_SWITCH_UP)
{
- Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_DOWN;
+ Tile[xx][yy] = EL_DC_SWITCHGATE_SWITCH_DOWN;
TEST_DrawLevelField(xx, yy);
}
else if (element == EL_DC_SWITCHGATE_SWITCH_DOWN)
{
- Feld[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP;
+ Tile[xx][yy] = EL_DC_SWITCHGATE_SWITCH_UP;
TEST_DrawLevelField(xx, yy);
}
else if (element == EL_SWITCHGATE_OPEN ||
element == EL_SWITCHGATE_OPENING)
{
- Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
+ Tile[xx][yy] = EL_SWITCHGATE_CLOSING;
PlayLevelSoundAction(xx, yy, ACTION_CLOSING);
}
else if (element == EL_SWITCHGATE_CLOSED ||
element == EL_SWITCHGATE_CLOSING)
{
- Feld[xx][yy] = EL_SWITCHGATE_OPENING;
+ Tile[xx][yy] = EL_SWITCHGATE_OPENING;
PlayLevelSoundAction(xx, yy, ACTION_OPENING);
}
SCAN_PLAYFIELD(x, y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (element == EL_LIGHT_SWITCH &&
game.light_time_left > 0)
{
- Feld[x][y] = EL_LIGHT_SWITCH_ACTIVE;
+ Tile[x][y] = EL_LIGHT_SWITCH_ACTIVE;
TEST_DrawLevelField(x, y);
}
else if (element == EL_LIGHT_SWITCH_ACTIVE &&
game.light_time_left == 0)
{
- Feld[x][y] = EL_LIGHT_SWITCH;
+ Tile[x][y] = EL_LIGHT_SWITCH;
TEST_DrawLevelField(x, y);
}
else if (element == EL_EMC_DRIPPER &&
game.light_time_left > 0)
{
- Feld[x][y] = EL_EMC_DRIPPER_ACTIVE;
+ Tile[x][y] = EL_EMC_DRIPPER_ACTIVE;
TEST_DrawLevelField(x, y);
}
else if (element == EL_EMC_DRIPPER_ACTIVE &&
game.light_time_left == 0)
{
- Feld[x][y] = EL_EMC_DRIPPER;
+ Tile[x][y] = EL_EMC_DRIPPER;
TEST_DrawLevelField(x, y);
}
else if (element == EL_INVISIBLE_STEELWALL ||
element == EL_INVISIBLE_SAND)
{
if (game.light_time_left > 0)
- Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+ Tile[x][y] = getInvisibleActiveFromInvisibleElement(element);
TEST_DrawLevelField(x, y);
element == EL_INVISIBLE_SAND_ACTIVE)
{
if (game.light_time_left == 0)
- Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
+ Tile[x][y] = getInvisibleFromInvisibleActiveElement(element);
TEST_DrawLevelField(x, y);
SCAN_PLAYFIELD(x, y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (element == EL_EMC_DRIPPER &&
game.lenses_time_left > 0)
{
- Feld[x][y] = EL_EMC_DRIPPER_ACTIVE;
+ Tile[x][y] = EL_EMC_DRIPPER_ACTIVE;
TEST_DrawLevelField(x, y);
}
else if (element == EL_EMC_DRIPPER_ACTIVE &&
game.lenses_time_left == 0)
{
- Feld[x][y] = EL_EMC_DRIPPER;
+ Tile[x][y] = EL_EMC_DRIPPER;
TEST_DrawLevelField(x, y);
}
else if (element == EL_INVISIBLE_STEELWALL ||
element == EL_INVISIBLE_SAND)
{
if (game.lenses_time_left > 0)
- Feld[x][y] = getInvisibleActiveFromInvisibleElement(element);
+ Tile[x][y] = getInvisibleActiveFromInvisibleElement(element);
TEST_DrawLevelField(x, y);
element == EL_INVISIBLE_SAND_ACTIVE)
{
if (game.lenses_time_left == 0)
- Feld[x][y] = getInvisibleFromInvisibleActiveElement(element);
+ Tile[x][y] = getInvisibleFromInvisibleActiveElement(element);
TEST_DrawLevelField(x, y);
SCAN_PLAYFIELD(x, y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (element == EL_EMC_FAKE_GRASS &&
game.magnify_time_left > 0)
{
- Feld[x][y] = EL_EMC_FAKE_GRASS_ACTIVE;
+ Tile[x][y] = EL_EMC_FAKE_GRASS_ACTIVE;
TEST_DrawLevelField(x, y);
}
else if (element == EL_EMC_FAKE_GRASS_ACTIVE &&
game.magnify_time_left == 0)
{
- Feld[x][y] = EL_EMC_FAKE_GRASS;
+ Tile[x][y] = EL_EMC_FAKE_GRASS;
TEST_DrawLevelField(x, y);
}
else if (IS_GATE_GRAY(element) &&
game.magnify_time_left > 0)
{
- Feld[x][y] = (IS_RND_GATE_GRAY(element) ?
+ Tile[x][y] = (IS_RND_GATE_GRAY(element) ?
element - EL_GATE_1_GRAY + EL_GATE_1_GRAY_ACTIVE :
IS_EM_GATE_GRAY(element) ?
element - EL_EM_GATE_1_GRAY + EL_EM_GATE_1_GRAY_ACTIVE :
else if (IS_GATE_GRAY_ACTIVE(element) &&
game.magnify_time_left == 0)
{
- Feld[x][y] = (IS_RND_GATE_GRAY_ACTIVE(element) ?
+ Tile[x][y] = (IS_RND_GATE_GRAY_ACTIVE(element) ?
element - EL_GATE_1_GRAY_ACTIVE + EL_GATE_1_GRAY :
IS_EM_GATE_GRAY_ACTIVE(element) ?
element - EL_EM_GATE_1_GRAY_ACTIVE + EL_EM_GATE_1_GRAY :
static void ToggleLightSwitch(int x, int y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
game.light_time_left =
(element == EL_LIGHT_SWITCH ?
SCAN_PLAYFIELD(xx, yy)
{
- int element = Feld[xx][yy];
+ int element = Tile[xx][yy];
if (element == EL_TIMEGATE_CLOSED ||
element == EL_TIMEGATE_CLOSING)
{
- Feld[xx][yy] = EL_TIMEGATE_OPENING;
+ Tile[xx][yy] = EL_TIMEGATE_OPENING;
PlayLevelSound(xx, yy, SND_CLASS_TIMEGATE_OPENING);
}
/*
else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
{
- Feld[xx][yy] = EL_TIMEGATE_SWITCH;
+ Tile[xx][yy] = EL_TIMEGATE_SWITCH;
TEST_DrawLevelField(xx, yy);
}
*/
}
- Feld[x][y] = (Feld[x][y] == EL_TIMEGATE_SWITCH ? EL_TIMEGATE_SWITCH_ACTIVE :
+ Tile[x][y] = (Tile[x][y] == EL_TIMEGATE_SWITCH ? EL_TIMEGATE_SWITCH_ACTIVE :
EL_DC_TIMEGATE_SWITCH_ACTIVE);
}
boolean last_line = (y == lev_fieldy - 1);
boolean object_hit = FALSE;
boolean impact = (last_line || object_hit);
- int element = Feld[x][y];
+ int element = Tile[x][y];
int smashed = EL_STEELWALL;
if (!last_line) // check if element below was hit
{
- if (Feld[x][y + 1] == EL_PLAYER_IS_LEAVING)
+ if (Tile[x][y + 1] == EL_PLAYER_IS_LEAVING)
return;
object_hit = (!IS_FREE(x, y + 1) && (!IS_MOVING(x, y + 1) ||
object_hit = FALSE;
#if USE_QUICKSAND_IMPACT_BUGFIX
- if (Feld[x][y + 1] == EL_QUICKSAND_EMPTYING && object_hit == FALSE)
+ if (Tile[x][y + 1] == EL_QUICKSAND_EMPTYING && object_hit == FALSE)
{
RemoveMovingField(x, y + 1);
- Feld[x][y + 1] = EL_QUICKSAND_EMPTY;
- Feld[x][y + 2] = EL_ROCK;
+ Tile[x][y + 1] = EL_QUICKSAND_EMPTY;
+ Tile[x][y + 2] = EL_ROCK;
TEST_DrawLevelField(x, y + 2);
object_hit = TRUE;
}
- if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTYING && object_hit == FALSE)
+ if (Tile[x][y + 1] == EL_QUICKSAND_FAST_EMPTYING && object_hit == FALSE)
{
RemoveMovingField(x, y + 1);
- Feld[x][y + 1] = EL_QUICKSAND_FAST_EMPTY;
- Feld[x][y + 2] = EL_ROCK;
+ Tile[x][y + 1] = EL_QUICKSAND_FAST_EMPTY;
+ Tile[x][y + 2] = EL_ROCK;
TEST_DrawLevelField(x, y + 2);
object_hit = TRUE;
{
ResetGfxAnimation(x, y);
- Feld[x][y] = EL_PEARL_BREAKING;
+ Tile[x][y] = EL_PEARL_BREAKING;
PlayLevelSound(x, y, SND_PEARL_BREAKING);
return;
}
Bang(x, y + 1);
else
{
- Feld[x][y] = EL_AMOEBA_GROWING;
+ Tile[x][y] = EL_AMOEBA_GROWING;
Store[x][y] = EL_AMOEBA_WET;
ResetRandomAnimationValue(x, y);
// activate magic wall / mill
SCAN_PLAYFIELD(xx, yy)
{
- if (Feld[xx][yy] == smashed)
- Feld[xx][yy] = activated_magic_wall;
+ if (Tile[xx][yy] == smashed)
+ Tile[xx][yy] = activated_magic_wall;
}
game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
}
else if (smashed == EL_NUT)
{
- Feld[x][y + 1] = EL_NUT_BREAKING;
+ Tile[x][y + 1] = EL_NUT_BREAKING;
PlayLevelSound(x, y, SND_NUT_BREAKING);
RaiseScoreElement(EL_NUT);
return;
{
ResetGfxAnimation(x, y);
- Feld[x][y + 1] = EL_PEARL_BREAKING;
+ Tile[x][y + 1] = EL_PEARL_BREAKING;
PlayLevelSound(x, y, SND_PEARL_BREAKING);
return;
}
else if (smashed == EL_DIAMOND)
{
- Feld[x][y + 1] = EL_DIAMOND_BREAKING;
+ Tile[x][y + 1] = EL_DIAMOND_BREAKING;
PlayLevelSound(x, y, SND_DIAMOND_BREAKING);
return;
}
smashed == EL_DC_SWITCHGATE_SWITCH_UP ||
smashed == EL_DC_SWITCHGATE_SWITCH_DOWN)
{
- ToggleSwitchgateSwitch(x, y + 1);
+ ToggleSwitchgateSwitch();
}
else if (smashed == EL_LIGHT_SWITCH ||
smashed == EL_LIGHT_SWITCH_ACTIVE)
// play sound of magic wall / mill
if (!last_line &&
- (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
- Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE ||
- Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE))
+ (Tile[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
+ Tile[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE ||
+ Tile[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE))
{
- if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
+ if (Tile[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
PlayLevelSound(x, y, SND_MAGIC_WALL_FILLING);
- else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
+ else if (Tile[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
PlayLevelSound(x, y, SND_BD_MAGIC_WALL_FILLING);
- else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)
+ else if (Tile[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)
PlayLevelSound(x, y, SND_DC_MAGIC_WALL_FILLING);
return;
{ MV_RIGHT, MV_LEFT, MV_UP }
};
- int element = Feld[x][y];
+ int element = Tile[x][y];
int move_pattern = element_info[element].move_pattern;
int old_move_dir = MovDir[x][y];
yy = y + move_xy[MovDir[x][y]].dy;
if (!IN_LEV_FIELD(xx, yy) ||
- (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Feld[xx][yy])))
+ (!IS_FREE(xx, yy) && !IS_FOOD_PIG(Tile[xx][yy])))
MovDir[x][y] = old_move_dir;
MovDelay[x][y] = 0;
{
boolean can_move_on =
(MOLE_CAN_ENTER_FIELD(element, move_x, move_y,
- IS_AMOEBOID(Feld[move_x][move_y]) ||
- Feld[move_x][move_y] == EL_AMOEBA_SHRINKING));
+ IS_AMOEBOID(Tile[move_x][move_y]) ||
+ Tile[move_x][move_y] == EL_AMOEBA_SHRINKING));
if (!can_move_on)
{
boolean can_turn_left =
(MOLE_CAN_ENTER_FIELD(element, left_x, left_y,
- IS_AMOEBOID(Feld[left_x][left_y])));
+ IS_AMOEBOID(Tile[left_x][left_y])));
boolean can_turn_right =
(MOLE_CAN_ENTER_FIELD(element, right_x, right_y,
- IS_AMOEBOID(Feld[right_x][right_y])));
+ IS_AMOEBOID(Tile[right_x][right_y])));
if (can_turn_left && can_turn_right)
MovDir[x][y] = (RND(2) ? left_dir : right_dir);
if (SPRING_CAN_BUMP_FROM_FIELD(move_x, move_y) &&
!SPRING_CAN_ENTER_FIELD(element, x, y + 1))
{
- Feld[move_x][move_y] = EL_EMC_SPRING_BUMPER_ACTIVE;
+ Tile[move_x][move_y] = EL_EMC_SPRING_BUMPER_ACTIVE;
ResetGfxAnimation(move_x, move_y);
TEST_DrawLevelField(move_x, move_y);
if (element == EL_ROBOT &&
game.robot_wheel_x >= 0 &&
game.robot_wheel_y >= 0 &&
- (Feld[game.robot_wheel_x][game.robot_wheel_y] == EL_ROBOT_WHEEL_ACTIVE ||
+ (Tile[game.robot_wheel_x][game.robot_wheel_y] == EL_ROBOT_WHEEL_ACTIVE ||
game.engine_version < VERSION_IDENT(3,1,0,0)))
{
attr_x = game.robot_wheel_x;
if (element == EL_PENGUIN)
{
int i;
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int ex = x + xy[i][0];
- int ey = y + xy[i][1];
+ int ex = x + xy[i].x;
+ int ey = y + xy[i].y;
- if (IN_LEV_FIELD(ex, ey) && (Feld[ex][ey] == EL_EXIT_OPEN ||
- Feld[ex][ey] == EL_EM_EXIT_OPEN ||
- Feld[ex][ey] == EL_STEEL_EXIT_OPEN ||
- Feld[ex][ey] == EL_EM_STEEL_EXIT_OPEN))
+ if (IN_LEV_FIELD(ex, ey) && (Tile[ex][ey] == EL_EXIT_OPEN ||
+ Tile[ex][ey] == EL_EM_EXIT_OPEN ||
+ Tile[ex][ey] == EL_STEEL_EXIT_OPEN ||
+ Tile[ex][ey] == EL_EM_STEEL_EXIT_OPEN))
{
attr_x = ex;
attr_y = ey;
element_info[element].move_leave_type = LEAVE_TYPE_LIMITED;
element_info[element].move_leave_element = EL_TRIGGER_ELEMENT;
- Store[x][y] = Feld[newx][newy];
+ Store[x][y] = Tile[newx][newy];
can_clone = TRUE;
}
else if (move_pattern & MV_MAZE_RUNNER_STYLE)
{
- static int test_xy[7][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 },
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- };
- static int test_dir[7] =
+ struct XY *test_xy = xy_topdown;
+ static int test_dir[4] =
{
MV_UP,
MV_LEFT,
MV_RIGHT,
- MV_DOWN,
- MV_UP,
- MV_LEFT,
- MV_RIGHT,
+ MV_DOWN
};
boolean hunter_mode = (move_pattern == MV_MAZE_HUNTER);
int move_preference = -1000000; // start with very low preference
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int move_dir = test_dir[start_test + i];
+ int j = (start_test + i) % 4;
+ int move_dir = test_dir[j];
int move_dir_preference;
- xx = x + test_xy[start_test + i][0];
- yy = y + test_xy[start_test + i][1];
+ xx = x + test_xy[j].x;
+ yy = y + test_xy[j].y;
if (hunter_mode && IN_LEV_FIELD(xx, yy) &&
- (IS_PLAYER(xx, yy) || Feld[xx][yy] == EL_PLAYER_IS_LEAVING))
+ (IS_PLAYER(xx, yy) || Tile[xx][yy] == EL_PLAYER_IS_LEAVING))
{
new_move_dir = move_dir;
static void StartMoving(int x, int y)
{
boolean started_moving = FALSE; // some elements can fall _and_ move
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (Stop[x][y])
return;
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] = EL_QUICKSAND_EMPTYING;
+ Tile[x][y] = EL_QUICKSAND_EMPTYING;
#if USE_QUICKSAND_BD_ROCK_BUGFIX
if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK)
Store[x][y] = EL_ROCK;
PlayLevelSoundAction(x, y, ACTION_EMPTYING);
}
- else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
+ else if (Tile[x][y + 1] == EL_QUICKSAND_EMPTY)
{
if (!MovDelay[x][y])
{
return;
}
- Feld[x][y] = EL_QUICKSAND_EMPTY;
- Feld[x][y + 1] = EL_QUICKSAND_FULL;
+ Tile[x][y] = EL_QUICKSAND_EMPTY;
+ Tile[x][y + 1] = EL_QUICKSAND_FULL;
Store[x][y + 1] = Store[x][y];
Store[x][y] = 0;
PlayLevelSoundAction(x, y, ACTION_FILLING);
}
- else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY)
+ else if (Tile[x][y + 1] == EL_QUICKSAND_FAST_EMPTY)
{
if (!MovDelay[x][y])
{
return;
}
- Feld[x][y] = EL_QUICKSAND_EMPTY;
- Feld[x][y + 1] = EL_QUICKSAND_FAST_FULL;
+ Tile[x][y] = EL_QUICKSAND_EMPTY;
+ Tile[x][y + 1] = EL_QUICKSAND_FAST_FULL;
Store[x][y + 1] = Store[x][y];
Store[x][y] = 0;
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] = EL_QUICKSAND_FAST_EMPTYING;
+ Tile[x][y] = EL_QUICKSAND_FAST_EMPTYING;
#if USE_QUICKSAND_BD_ROCK_BUGFIX
if (Store[x][y] != EL_ROCK && Store[x][y] != EL_BD_ROCK)
Store[x][y] = EL_ROCK;
PlayLevelSoundAction(x, y, ACTION_EMPTYING);
}
- else if (Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY)
+ else if (Tile[x][y + 1] == EL_QUICKSAND_FAST_EMPTY)
{
if (!MovDelay[x][y])
{
return;
}
- Feld[x][y] = EL_QUICKSAND_FAST_EMPTY;
- Feld[x][y + 1] = EL_QUICKSAND_FAST_FULL;
+ Tile[x][y] = EL_QUICKSAND_FAST_EMPTY;
+ Tile[x][y + 1] = EL_QUICKSAND_FAST_FULL;
Store[x][y + 1] = Store[x][y];
Store[x][y] = 0;
PlayLevelSoundAction(x, y, ACTION_FILLING);
}
- else if (Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
+ else if (Tile[x][y + 1] == EL_QUICKSAND_EMPTY)
{
if (!MovDelay[x][y])
{
return;
}
- Feld[x][y] = EL_QUICKSAND_FAST_EMPTY;
- Feld[x][y + 1] = EL_QUICKSAND_FULL;
+ Tile[x][y] = EL_QUICKSAND_FAST_EMPTY;
+ Tile[x][y + 1] = EL_QUICKSAND_FULL;
Store[x][y + 1] = Store[x][y];
Store[x][y] = 0;
}
}
else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
- Feld[x][y + 1] == EL_QUICKSAND_EMPTY)
+ Tile[x][y + 1] == EL_QUICKSAND_EMPTY)
{
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] = EL_QUICKSAND_FILLING;
+ Tile[x][y] = EL_QUICKSAND_FILLING;
Store[x][y] = element;
PlayLevelSoundAction(x, y, ACTION_FILLING);
}
else if ((element == EL_ROCK || element == EL_BD_ROCK) &&
- Feld[x][y + 1] == EL_QUICKSAND_FAST_EMPTY)
+ Tile[x][y + 1] == EL_QUICKSAND_FAST_EMPTY)
{
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] = EL_QUICKSAND_FAST_FILLING;
+ Tile[x][y] = EL_QUICKSAND_FAST_FILLING;
Store[x][y] = element;
PlayLevelSoundAction(x, y, ACTION_FILLING);
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] = EL_MAGIC_WALL_EMPTYING;
+ Tile[x][y] = EL_MAGIC_WALL_EMPTYING;
Store[x][y] = EL_CHANGED(Store[x][y]);
}
- else if (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
+ else if (Tile[x][y + 1] == EL_MAGIC_WALL_ACTIVE)
{
if (!MovDelay[x][y])
MovDelay[x][y] = TILEY / 4 + 1;
return;
}
- Feld[x][y] = EL_MAGIC_WALL_ACTIVE;
- Feld[x][y + 1] = EL_MAGIC_WALL_FULL;
+ Tile[x][y] = EL_MAGIC_WALL_ACTIVE;
+ Tile[x][y + 1] = EL_MAGIC_WALL_FULL;
Store[x][y + 1] = EL_CHANGED(Store[x][y]);
Store[x][y] = 0;
}
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
+ Tile[x][y] = EL_BD_MAGIC_WALL_EMPTYING;
Store[x][y] = EL_CHANGED_BD(Store[x][y]);
}
- else if (Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
+ else if (Tile[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)
{
if (!MovDelay[x][y])
MovDelay[x][y] = TILEY / 4 + 1;
return;
}
- Feld[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
- Feld[x][y + 1] = EL_BD_MAGIC_WALL_FULL;
+ Tile[x][y] = EL_BD_MAGIC_WALL_ACTIVE;
+ Tile[x][y + 1] = EL_BD_MAGIC_WALL_FULL;
Store[x][y + 1] = EL_CHANGED_BD(Store[x][y]);
Store[x][y] = 0;
}
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] = EL_DC_MAGIC_WALL_EMPTYING;
+ Tile[x][y] = EL_DC_MAGIC_WALL_EMPTYING;
Store[x][y] = EL_CHANGED_DC(Store[x][y]);
}
- else if (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)
+ else if (Tile[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)
{
if (!MovDelay[x][y])
MovDelay[x][y] = TILEY / 4 + 1;
return;
}
- Feld[x][y] = EL_DC_MAGIC_WALL_ACTIVE;
- Feld[x][y + 1] = EL_DC_MAGIC_WALL_FULL;
+ Tile[x][y] = EL_DC_MAGIC_WALL_ACTIVE;
+ Tile[x][y + 1] = EL_DC_MAGIC_WALL_FULL;
Store[x][y + 1] = EL_CHANGED_DC(Store[x][y]);
Store[x][y] = 0;
}
}
else if ((CAN_PASS_MAGIC_WALL(element) &&
- (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
- Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) ||
+ (Tile[x][y + 1] == EL_MAGIC_WALL_ACTIVE ||
+ Tile[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE)) ||
(CAN_PASS_DC_MAGIC_WALL(element) &&
- (Feld[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)))
+ (Tile[x][y + 1] == EL_DC_MAGIC_WALL_ACTIVE)))
{
InitMovingField(x, y, MV_DOWN);
started_moving = TRUE;
- Feld[x][y] =
- (Feld[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
- Feld[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE ? EL_BD_MAGIC_WALL_FILLING :
+ Tile[x][y] =
+ (Tile[x][y + 1] == EL_MAGIC_WALL_ACTIVE ? EL_MAGIC_WALL_FILLING :
+ Tile[x][y + 1] == EL_BD_MAGIC_WALL_ACTIVE ? EL_BD_MAGIC_WALL_FILLING :
EL_DC_MAGIC_WALL_FILLING);
Store[x][y] = element;
}
- else if (CAN_FALL(element) && Feld[x][y + 1] == EL_ACID)
+ else if (CAN_FALL(element) && Tile[x][y + 1] == EL_ACID)
{
SplashAcid(x, y + 1);
CheckImpact[x][y] && !IS_FREE(x, y + 1)) ||
(game.engine_version >= VERSION_IDENT(3,0,7,0) &&
CAN_FALL(element) && WasJustFalling[x][y] &&
- (Feld[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
+ (Tile[x][y + 1] == EL_BLOCKED || IS_PLAYER(x, y + 1))) ||
(game.engine_version < VERSION_IDENT(2,2,0,7) &&
CAN_FALL(element) && WasJustMoving[x][y] && !Pushed[x][y + 1] &&
- (Feld[x][y + 1] == EL_BLOCKED)))
+ (Tile[x][y + 1] == EL_BLOCKED)))
{
/* this is needed for a special case not covered by calling "Impact()"
from "ContinueMoving()": if an element moves to a tile directly below
started_moving = TRUE;
}
}
- else if (IS_FREE(x, y + 1) || Feld[x][y + 1] == EL_DIAMOND_BREAKING)
+ else if (IS_FREE(x, y + 1) || Tile[x][y + 1] == EL_DIAMOND_BREAKING)
{
if (WasJustFalling[x][y]) // prevent animation from being restarted
MovDir[x][y] = MV_DOWN;
}
else if (element == EL_AMOEBA_DROP)
{
- Feld[x][y] = EL_AMOEBA_GROWING;
+ Tile[x][y] = EL_AMOEBA_GROWING;
Store[x][y] = EL_AMOEBA_WET;
}
- else if (((IS_SLIPPERY(Feld[x][y + 1]) && !IS_PLAYER(x, y + 1)) ||
- (IS_EM_SLIPPERY_WALL(Feld[x][y + 1]) && IS_GEM(element))) &&
+ else if (((IS_SLIPPERY(Tile[x][y + 1]) && !IS_PLAYER(x, y + 1)) ||
+ (IS_EM_SLIPPERY_WALL(Tile[x][y + 1]) && IS_GEM(element))) &&
!IS_FALLING(x, y + 1) && !WasJustMoving[x][y + 1] &&
element != EL_DX_SUPABOMB && element != EL_SP_DISK_ORANGE)
{
boolean can_fall_left = (x > 0 && IS_FREE(x - 1, y) &&
(IS_FREE(x - 1, y + 1) ||
- Feld[x - 1][y + 1] == EL_ACID));
+ Tile[x - 1][y + 1] == EL_ACID));
boolean can_fall_right = (x < lev_fieldx - 1 && IS_FREE(x + 1, y) &&
(IS_FREE(x + 1, y + 1) ||
- Feld[x + 1][y + 1] == EL_ACID));
+ Tile[x + 1][y + 1] == EL_ACID));
boolean can_fall_any = (can_fall_left || can_fall_right);
boolean can_fall_both = (can_fall_left && can_fall_right);
- int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
+ int slippery_type = element_info[Tile[x][y + 1]].slippery_type;
if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM)
{
started_moving = TRUE;
}
}
- else if (IS_BELT_ACTIVE(Feld[x][y + 1]))
+ else if (IS_BELT_ACTIVE(Tile[x][y + 1]))
{
boolean left_is_free = (x > 0 && IS_FREE(x - 1, y));
boolean right_is_free = (x < lev_fieldx - 1 && IS_FREE(x + 1, y));
- int belt_nr = getBeltNrFromBeltActiveElement(Feld[x][y + 1]);
+ int belt_nr = getBeltNrFromBeltActiveElement(Tile[x][y + 1]);
int belt_dir = game.belt_dir[belt_nr];
if ((belt_dir == MV_LEFT && left_is_free) ||
TestIfElementHitsCustomElement(x, y, MovDir[x][y]);
- if (Feld[x][y] != element) // element has changed
+ if (Tile[x][y] != element) // element has changed
return;
}
dir == MV_RIGHT ? IMG_FLAMES_1_RIGHT :
dir == MV_UP ? IMG_FLAMES_1_UP :
dir == MV_DOWN ? IMG_FLAMES_1_DOWN : IMG_EMPTY);
- int frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]);
+ int frame = getGraphicAnimationFrameXY(graphic, x, y);
GfxAction[x][y] = ACTION_ATTACKING;
int sy = SCREENY(yy);
int flame_graphic = graphic + (i - 1);
- if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Feld[xx][yy]))
+ if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Tile[xx][yy]))
break;
if (MovDelay[x][y])
ChangeDelay[xx][yy] = 0;
- Feld[xx][yy] = EL_FLAMES;
+ Tile[xx][yy] = EL_FLAMES;
if (IN_SCR_FIELD(sx, sy))
{
TEST_DrawLevelFieldCrumbled(xx, yy);
- DrawGraphic(sx, sy, flame_graphic, frame);
+ DrawScreenGraphic(sx, sy, flame_graphic, frame);
}
}
else
{
- if (Feld[xx][yy] == EL_FLAMES)
- Feld[xx][yy] = EL_EMPTY;
+ if (Tile[xx][yy] == EL_FLAMES)
+ Tile[xx][yy] = EL_EMPTY;
TEST_DrawLevelField(xx, yy);
}
}
}
else if (CAN_MOVE_INTO_ACID(element) &&
- IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID &&
+ IN_LEV_FIELD(newx, newy) && Tile[newx][newy] == EL_ACID &&
!IS_MV_DIAGONAL(MovDir[x][y]) &&
(MovDir[x][y] == MV_DOWN ||
game.engine_version >= VERSION_IDENT(3,1,0,0)))
}
else if (element == EL_PENGUIN && IN_LEV_FIELD(newx, newy))
{
- if (Feld[newx][newy] == EL_EXIT_OPEN ||
- Feld[newx][newy] == EL_EM_EXIT_OPEN ||
- Feld[newx][newy] == EL_STEEL_EXIT_OPEN ||
- Feld[newx][newy] == EL_EM_STEEL_EXIT_OPEN)
+ if (Tile[newx][newy] == EL_EXIT_OPEN ||
+ Tile[newx][newy] == EL_EM_EXIT_OPEN ||
+ Tile[newx][newy] == EL_STEEL_EXIT_OPEN ||
+ Tile[newx][newy] == EL_EM_STEEL_EXIT_OPEN)
{
RemoveField(x, y);
TEST_DrawLevelField(x, y);
return;
}
- else if (IS_FOOD_PENGUIN(Feld[newx][newy]))
+ else if (IS_FOOD_PENGUIN(Tile[newx][newy]))
{
if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING)
TEST_DrawLevelField(newx, newy);
}
else if (element == EL_PIG && IN_LEV_FIELD(newx, newy))
{
- if (IS_FOOD_PIG(Feld[newx][newy]))
+ if (IS_FOOD_PIG(Tile[newx][newy]))
{
if (IS_MOVING(newx, newy))
RemoveMovingField(newx, newy);
else
{
- Feld[newx][newy] = EL_EMPTY;
+ Tile[newx][newy] = EL_EMPTY;
TEST_DrawLevelField(newx, newy);
}
// check if element to clone is still there
for (yy = y - 1; yy <= y + 1; yy++) for (xx = x - 1; xx <= x + 1; xx++)
{
- if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == Store[x][y])
+ if (IN_LEV_FIELD(xx, yy) && Tile[xx][yy] == Store[x][y])
{
can_clone = TRUE;
GfxDir[x][y] = diagonal_move_dir;
ChangeDelay[x][y] = change_delay;
+ if (Store[x][y] == EL_EMPTY)
+ Store[x][y] = GfxElementEmpty[x][y];
+
graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],
GfxDir[x][y]);
DrawLevelGraphicAnimation(x, y, graphic);
PlayLevelSoundAction(x, y, ACTION_SHRINKING);
- if (Feld[newx][newy] == EL_ACID)
+ if (Tile[newx][newy] == EL_ACID)
{
SplashAcid(newx, newy);
}
else
{
- Feld[newx][newy] = EL_EMPTY;
+ Tile[newx][newy] = EL_EMPTY;
TEST_DrawLevelField(newx, newy);
PlayLevelSoundAction(x, y, ACTION_DIGGING);
MovDelay[x][y] = 50;
- Feld[newx][newy] = EL_FLAMES;
- if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_EMPTY)
- Feld[newx1][newy1] = EL_FLAMES;
- if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_EMPTY)
- Feld[newx2][newy2] = EL_FLAMES;
+ Tile[newx][newy] = EL_FLAMES;
+ if (IN_LEV_FIELD(newx1, newy1) && Tile[newx1][newy1] == EL_EMPTY)
+ Tile[newx1][newy1] = EL_FLAMES;
+ if (IN_LEV_FIELD(newx2, newy2) && Tile[newx2][newy2] == EL_EMPTY)
+ Tile[newx2][newy2] = EL_FLAMES;
return;
}
}
}
else if (element == EL_YAMYAM && IN_LEV_FIELD(newx, newy) &&
- Feld[newx][newy] == EL_DIAMOND)
+ Tile[newx][newy] == EL_DIAMOND)
{
if (IS_MOVING(newx, newy))
RemoveMovingField(newx, newy);
else
{
- Feld[newx][newy] = EL_EMPTY;
+ Tile[newx][newy] = EL_EMPTY;
TEST_DrawLevelField(newx, newy);
}
PlayLevelSound(x, y, SND_YAMYAM_DIGGING);
}
else if (element == EL_DARK_YAMYAM && IN_LEV_FIELD(newx, newy) &&
- IS_FOOD_DARK_YAMYAM(Feld[newx][newy]))
+ IS_FOOD_DARK_YAMYAM(Tile[newx][newy]))
{
if (AmoebaNr[newx][newy])
{
AmoebaCnt2[AmoebaNr[newx][newy]]--;
- if (Feld[newx][newy] == EL_AMOEBA_FULL ||
- Feld[newx][newy] == EL_BD_AMOEBA)
+ if (Tile[newx][newy] == EL_AMOEBA_FULL ||
+ Tile[newx][newy] == EL_BD_AMOEBA)
AmoebaCnt[AmoebaNr[newx][newy]]--;
}
}
else
{
- Feld[newx][newy] = EL_EMPTY;
+ Tile[newx][newy] = EL_EMPTY;
TEST_DrawLevelField(newx, newy);
}
PlayLevelSound(x, y, SND_DARK_YAMYAM_DIGGING);
}
else if ((element == EL_PACMAN || element == EL_MOLE)
- && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Feld[newx][newy]))
+ && IN_LEV_FIELD(newx, newy) && IS_AMOEBOID(Tile[newx][newy]))
{
if (AmoebaNr[newx][newy])
{
AmoebaCnt2[AmoebaNr[newx][newy]]--;
- if (Feld[newx][newy] == EL_AMOEBA_FULL ||
- Feld[newx][newy] == EL_BD_AMOEBA)
+ if (Tile[newx][newy] == EL_AMOEBA_FULL ||
+ Tile[newx][newy] == EL_BD_AMOEBA)
AmoebaCnt[AmoebaNr[newx][newy]]--;
}
if (element == EL_MOLE)
{
- Feld[newx][newy] = EL_AMOEBA_SHRINKING;
+ Tile[newx][newy] = EL_AMOEBA_SHRINKING;
PlayLevelSound(x, y, SND_MOLE_DIGGING);
ResetGfxAnimation(x, y);
}
else // element == EL_PACMAN
{
- Feld[newx][newy] = EL_EMPTY;
+ Tile[newx][newy] = EL_EMPTY;
TEST_DrawLevelField(newx, newy);
PlayLevelSound(x, y, SND_PACMAN_DIGGING);
}
}
else if (element == EL_MOLE && IN_LEV_FIELD(newx, newy) &&
- (Feld[newx][newy] == EL_AMOEBA_SHRINKING ||
- (Feld[newx][newy] == EL_EMPTY && Stop[newx][newy])))
+ (Tile[newx][newy] == EL_AMOEBA_SHRINKING ||
+ (Tile[newx][newy] == EL_EMPTY && Stop[newx][newy])))
{
// wait for shrinking amoeba to completely disappear
return;
void ContinueMoving(int x, int y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
struct ElementInfo *ei = &element_info[element];
int direction = MovDir[x][y];
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
boolean pushed_by_player = (Pushed[x][y] && IS_PLAYER(x, y));
boolean pushed_by_conveyor = (Pushed[x][y] && !IS_PLAYER(x, y));
boolean last_line = (newy == lev_fieldy - 1);
+ boolean use_step_delay = (GET_MAX_STEP_DELAY(element) != 0);
- MovPos[x][y] += getElementMoveStepsize(x, y);
-
- if (pushed_by_player) // 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));
+ }
+ else if (use_step_delay) // special case: moving object has step delay
+ {
+ if (!MovDelay[x][y])
+ MovPos[x][y] += getElementMoveStepsize(x, y);
+
+ if (MovDelay[x][y])
+ MovDelay[x][y]--;
+ else
+ MovDelay[x][y] = GET_NEW_STEP_DELAY(element);
+
+ if (MovDelay[x][y])
+ {
+ TEST_DrawLevelField(x, y);
+
+ return; // element is still waiting
+ }
+ }
+ else // normal case: generically moving object
+ {
+ MovPos[x][y] += getElementMoveStepsize(x, y);
+ }
if (ABS(MovPos[x][y]) < TILEX)
{
// element reached destination field
- Feld[x][y] = EL_EMPTY;
- Feld[newx][newy] = element;
+ Tile[x][y] = EL_EMPTY;
+ Tile[newx][newy] = element;
MovPos[x][y] = 0; // force "not moving" for "crumbled sand"
if (Store[x][y] == EL_ACID) // element is moving into acid pool
{
- element = Feld[newx][newy] = EL_ACID;
+ element = Tile[newx][newy] = EL_ACID;
}
else if (element == EL_MOLE)
{
- Feld[x][y] = EL_SAND;
+ Tile[x][y] = EL_SAND;
TEST_DrawLevelFieldCrumbledNeighbours(x, y);
}
else if (element == EL_QUICKSAND_FILLING)
{
- element = Feld[newx][newy] = get_next_element(element);
+ element = Tile[newx][newy] = get_next_element(element);
Store[newx][newy] = Store[x][y];
}
else if (element == EL_QUICKSAND_EMPTYING)
{
- Feld[x][y] = get_next_element(element);
- element = Feld[newx][newy] = Store[x][y];
+ Tile[x][y] = get_next_element(element);
+ element = Tile[newx][newy] = Store[x][y];
}
else if (element == EL_QUICKSAND_FAST_FILLING)
{
- element = Feld[newx][newy] = get_next_element(element);
+ element = Tile[newx][newy] = get_next_element(element);
Store[newx][newy] = Store[x][y];
}
else if (element == EL_QUICKSAND_FAST_EMPTYING)
{
- Feld[x][y] = get_next_element(element);
- element = Feld[newx][newy] = Store[x][y];
+ Tile[x][y] = get_next_element(element);
+ element = Tile[newx][newy] = Store[x][y];
}
else if (element == EL_MAGIC_WALL_FILLING)
{
- element = Feld[newx][newy] = get_next_element(element);
+ element = Tile[newx][newy] = get_next_element(element);
if (!game.magic_wall_active)
- element = Feld[newx][newy] = EL_MAGIC_WALL_DEAD;
+ element = Tile[newx][newy] = EL_MAGIC_WALL_DEAD;
Store[newx][newy] = Store[x][y];
}
else if (element == EL_MAGIC_WALL_EMPTYING)
{
- Feld[x][y] = get_next_element(element);
+ Tile[x][y] = get_next_element(element);
if (!game.magic_wall_active)
- Feld[x][y] = EL_MAGIC_WALL_DEAD;
- element = Feld[newx][newy] = Store[x][y];
+ Tile[x][y] = EL_MAGIC_WALL_DEAD;
+ element = Tile[newx][newy] = Store[x][y];
InitField(newx, newy, FALSE);
}
else if (element == EL_BD_MAGIC_WALL_FILLING)
{
- element = Feld[newx][newy] = get_next_element(element);
+ element = Tile[newx][newy] = get_next_element(element);
if (!game.magic_wall_active)
- element = Feld[newx][newy] = EL_BD_MAGIC_WALL_DEAD;
+ element = Tile[newx][newy] = EL_BD_MAGIC_WALL_DEAD;
Store[newx][newy] = Store[x][y];
}
else if (element == EL_BD_MAGIC_WALL_EMPTYING)
{
- Feld[x][y] = get_next_element(element);
+ Tile[x][y] = get_next_element(element);
if (!game.magic_wall_active)
- Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
- element = Feld[newx][newy] = Store[x][y];
+ Tile[x][y] = EL_BD_MAGIC_WALL_DEAD;
+ element = Tile[newx][newy] = Store[x][y];
InitField(newx, newy, FALSE);
}
else if (element == EL_DC_MAGIC_WALL_FILLING)
{
- element = Feld[newx][newy] = get_next_element(element);
+ element = Tile[newx][newy] = get_next_element(element);
if (!game.magic_wall_active)
- element = Feld[newx][newy] = EL_DC_MAGIC_WALL_DEAD;
+ element = Tile[newx][newy] = EL_DC_MAGIC_WALL_DEAD;
Store[newx][newy] = Store[x][y];
}
else if (element == EL_DC_MAGIC_WALL_EMPTYING)
{
- Feld[x][y] = get_next_element(element);
+ Tile[x][y] = get_next_element(element);
if (!game.magic_wall_active)
- Feld[x][y] = EL_DC_MAGIC_WALL_DEAD;
- element = Feld[newx][newy] = Store[x][y];
+ Tile[x][y] = EL_DC_MAGIC_WALL_DEAD;
+ element = Tile[newx][newy] = Store[x][y];
InitField(newx, newy, FALSE);
}
else if (element == EL_AMOEBA_DROPPING)
{
- Feld[x][y] = get_next_element(element);
- element = Feld[newx][newy] = Store[x][y];
+ Tile[x][y] = get_next_element(element);
+ element = Tile[newx][newy] = Store[x][y];
}
else if (element == EL_SOKOBAN_OBJECT)
{
if (Back[x][y])
- Feld[x][y] = Back[x][y];
+ Tile[x][y] = Back[x][y];
if (Back[newx][newy])
- Feld[newx][newy] = EL_SOKOBAN_FIELD_FULL;
+ Tile[newx][newy] = EL_SOKOBAN_FIELD_FULL;
Back[x][y] = Back[newx][newy] = 0;
}
if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored);
- Feld[x][y] = move_leave_element;
+ Tile[x][y] = move_leave_element;
- if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
+ if (element_info[Tile[x][y]].move_direction_initial == MV_START_PREVIOUS)
MovDir[x][y] = direction;
InitField(x, y, FALSE);
- if (GFX_CRUMBLED(Feld[x][y]))
+ if (GFX_CRUMBLED(Tile[x][y]))
TEST_DrawLevelFieldCrumbledNeighbours(x, y);
- if (ELEM_IS_PLAYER(move_leave_element))
+ if (IS_PLAYER_ELEMENT(move_leave_element))
RelocatePlayer(x, y, move_leave_element);
}
MV_DIR_OPPOSITE(direction));
}
-int AmoebeNachbarNr(int ax, int ay)
+int AmoebaNeighbourNr(int ax, int ay)
{
int i;
- int element = Feld[ax][ay];
+ int element = Tile[ax][ay];
int group_nr = 0;
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int x = ax + xy[i][0];
- int y = ay + xy[i][1];
+ int x = ax + xy[i].x;
+ int y = ay + xy[i].y;
if (!IN_LEV_FIELD(x, y))
continue;
- if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
+ if (Tile[x][y] == element && AmoebaNr[x][y] > 0)
group_nr = AmoebaNr[x][y];
}
return group_nr;
}
-static void AmoebenVereinigen(int ax, int ay)
+static void AmoebaMerge(int ax, int ay)
{
int i, x, y, xx, yy;
int new_group_nr = AmoebaNr[ax][ay];
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
if (new_group_nr == 0)
return;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- x = ax + xy[i][0];
- y = ay + xy[i][1];
+ x = ax + xy[i].x;
+ y = ay + xy[i].y;
if (!IN_LEV_FIELD(x, y))
continue;
- if ((Feld[x][y] == EL_AMOEBA_FULL ||
- Feld[x][y] == EL_BD_AMOEBA ||
- Feld[x][y] == EL_AMOEBA_DEAD) &&
+ if ((Tile[x][y] == EL_AMOEBA_FULL ||
+ Tile[x][y] == EL_BD_AMOEBA ||
+ Tile[x][y] == EL_AMOEBA_DEAD) &&
AmoebaNr[x][y] != new_group_nr)
{
int old_group_nr = AmoebaNr[x][y];
}
}
-void AmoebeUmwandeln(int ax, int ay)
+void AmoebaToDiamond(int ax, int ay)
{
int i, x, y;
- if (Feld[ax][ay] == EL_AMOEBA_DEAD)
+ if (Tile[ax][ay] == EL_AMOEBA_DEAD)
{
int group_nr = AmoebaNr[ax][ay];
#ifdef DEBUG
if (group_nr == 0)
{
- printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
- printf("AmoebeUmwandeln(): This should never happen!\n");
+ Debug("game:playing:AmoebaToDiamond", "ax = %d, ay = %d", ax, ay);
+ Debug("game:playing:AmoebaToDiamond", "This should never happen!");
+
return;
}
#endif
SCAN_PLAYFIELD(x, y)
{
- if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
+ if (Tile[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
{
AmoebaNr[x][y] = 0;
- Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
+ Tile[x][y] = EL_AMOEBA_TO_DIAMOND;
}
}
}
else
{
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- x = ax + xy[i][0];
- y = ay + xy[i][1];
+ x = ax + xy[i].x;
+ y = ay + xy[i].y;
if (!IN_LEV_FIELD(x, y))
continue;
- if (Feld[x][y] == EL_AMOEBA_TO_DIAMOND)
+ if (Tile[x][y] == EL_AMOEBA_TO_DIAMOND)
{
PlayLevelSound(x, y, (IS_GEM(level.amoeba_content) ?
SND_AMOEBA_TURNING_TO_GEM :
}
}
-static void AmoebeUmwandelnBD(int ax, int ay, int new_element)
+static void AmoebaToDiamondBD(int ax, int ay, int new_element)
{
int x, y;
int group_nr = AmoebaNr[ax][ay];
#ifdef DEBUG
if (group_nr == 0)
{
- printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
- printf("AmoebeUmwandelnBD(): This should never happen!\n");
+ Debug("game:playing:AmoebaToDiamondBD", "ax = %d, ay = %d", ax, ay);
+ Debug("game:playing:AmoebaToDiamondBD", "This should never happen!");
+
return;
}
#endif
SCAN_PLAYFIELD(x, y)
{
if (AmoebaNr[x][y] == group_nr &&
- (Feld[x][y] == EL_AMOEBA_DEAD ||
- Feld[x][y] == EL_BD_AMOEBA ||
- Feld[x][y] == EL_AMOEBA_GROWING))
+ (Tile[x][y] == EL_AMOEBA_DEAD ||
+ Tile[x][y] == EL_BD_AMOEBA ||
+ Tile[x][y] == EL_AMOEBA_GROWING))
{
AmoebaNr[x][y] = 0;
- Feld[x][y] = new_element;
+ Tile[x][y] = new_element;
InitField(x, y, FALSE);
TEST_DrawLevelField(x, y);
done = TRUE;
SND_BD_AMOEBA_TURNING_TO_GEM));
}
-static void AmoebeWaechst(int x, int y)
+static void AmoebaGrowing(int x, int y)
{
- static unsigned int sound_delay = 0;
- static unsigned int sound_delay_value = 0;
+ static DelayCounter sound_delay = { 0 };
if (!MovDelay[x][y]) // start new growing cycle
{
MovDelay[x][y] = 7;
- if (DelayReached(&sound_delay, sound_delay_value))
+ if (DelayReached(&sound_delay))
{
PlayLevelSoundElementAction(x, y, Store[x][y], ACTION_GROWING);
- sound_delay_value = 30;
+ sound_delay.value = 30;
}
}
int frame = getGraphicAnimationFrame(IMG_AMOEBA_GROWING,
6 - MovDelay[x][y]);
- DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_GROWING, frame);
+ DrawLevelGraphic(x, y, IMG_AMOEBA_GROWING, frame);
}
if (!MovDelay[x][y])
{
- Feld[x][y] = Store[x][y];
+ Tile[x][y] = Store[x][y];
Store[x][y] = 0;
TEST_DrawLevelField(x, y);
}
}
}
-static void AmoebaDisappearing(int x, int y)
+static void AmoebaShrinking(int x, int y)
{
- static unsigned int sound_delay = 0;
- static unsigned int sound_delay_value = 0;
+ static DelayCounter sound_delay = { 0 };
if (!MovDelay[x][y]) // start new shrinking cycle
{
MovDelay[x][y] = 7;
- if (DelayReached(&sound_delay, sound_delay_value))
- sound_delay_value = 30;
+ if (DelayReached(&sound_delay))
+ sound_delay.value = 30;
}
if (MovDelay[x][y]) // wait some time before shrinking
int frame = getGraphicAnimationFrame(IMG_AMOEBA_SHRINKING,
6 - MovDelay[x][y]);
- DrawGraphic(SCREENX(x), SCREENY(y), IMG_AMOEBA_SHRINKING, frame);
+ DrawLevelGraphic(x, y, IMG_AMOEBA_SHRINKING, frame);
}
if (!MovDelay[x][y])
{
- Feld[x][y] = EL_EMPTY;
+ Tile[x][y] = EL_EMPTY;
TEST_DrawLevelField(x, y);
// don't let mole enter this field in this cycle;
}
}
-static void AmoebeAbleger(int ax, int ay)
+static void AmoebaReproduce(int ax, int ay)
{
int i;
- int element = Feld[ax][ay];
+ int element = Tile[ax][ay];
int graphic = el2img(element);
int newax = ax, neway = ay;
boolean can_drop = (element == EL_AMOEBA_WET || element == EL_EMC_DRIPPER);
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
if (!level.amoeba_speed && element != EL_EMC_DRIPPER)
{
- Feld[ax][ay] = EL_AMOEBA_DEAD;
+ Tile[ax][ay] = EL_AMOEBA_DEAD;
TEST_DrawLevelField(ax, ay);
return;
}
if (can_drop) // EL_AMOEBA_WET or EL_EMC_DRIPPER
{
int start = RND(4);
- int x = ax + xy[start][0];
- int y = ay + xy[start][1];
+ int x = ax + xy[start].x;
+ int y = ay + xy[start].y;
if (!IN_LEV_FIELD(x, y))
return;
if (IS_FREE(x, y) ||
- CAN_GROW_INTO(Feld[x][y]) ||
- Feld[x][y] == EL_QUICKSAND_EMPTY ||
- Feld[x][y] == EL_QUICKSAND_FAST_EMPTY)
+ CAN_GROW_INTO(Tile[x][y]) ||
+ Tile[x][y] == EL_QUICKSAND_EMPTY ||
+ Tile[x][y] == EL_QUICKSAND_FAST_EMPTY)
{
newax = x;
neway = y;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
int j = (start + i) % 4;
- int x = ax + xy[j][0];
- int y = ay + xy[j][1];
+ int x = ax + xy[j].x;
+ int y = ay + xy[j].y;
if (!IN_LEV_FIELD(x, y))
continue;
if (IS_FREE(x, y) ||
- CAN_GROW_INTO(Feld[x][y]) ||
- Feld[x][y] == EL_QUICKSAND_EMPTY ||
- Feld[x][y] == EL_QUICKSAND_FAST_EMPTY)
+ CAN_GROW_INTO(Tile[x][y]) ||
+ Tile[x][y] == EL_QUICKSAND_EMPTY ||
+ Tile[x][y] == EL_QUICKSAND_FAST_EMPTY)
{
newax = x;
neway = y;
{
if (i == 4 && (!waiting_for_player || element == EL_BD_AMOEBA))
{
- Feld[ax][ay] = EL_AMOEBA_DEAD;
+ Tile[ax][ay] = EL_AMOEBA_DEAD;
TEST_DrawLevelField(ax, ay);
AmoebaCnt[AmoebaNr[ax][ay]]--;
if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) // amoeba is completely dead
{
if (element == EL_AMOEBA_FULL)
- AmoebeUmwandeln(ax, ay);
+ AmoebaToDiamond(ax, ay);
else if (element == EL_BD_AMOEBA)
- AmoebeUmwandelnBD(ax, ay, level.amoeba_content);
+ AmoebaToDiamondBD(ax, ay, level.amoeba_content);
}
}
return;
#ifdef DEBUG
if (new_group_nr == 0)
{
- printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
- printf("AmoebeAbleger(): This should never happen!\n");
+ Debug("game:playing:AmoebaReproduce", "newax = %d, neway = %d",
+ newax, neway);
+ Debug("game:playing:AmoebaReproduce", "This should never happen!");
+
return;
}
#endif
AmoebaCnt2[new_group_nr]++;
// if amoeba touches other amoeba(s) after growing, unify them
- AmoebenVereinigen(newax, neway);
+ AmoebaMerge(newax, neway);
if (element == EL_BD_AMOEBA && AmoebaCnt2[new_group_nr] >= 200)
{
- AmoebeUmwandelnBD(newax, neway, EL_BD_ROCK);
+ AmoebaToDiamondBD(newax, neway, EL_BD_ROCK);
return;
}
}
if (!can_drop || neway < ay || !IS_FREE(newax, neway) ||
(neway == lev_fieldy - 1 && newax != ax))
{
- Feld[newax][neway] = EL_AMOEBA_GROWING; // creation of new amoeba
+ Tile[newax][neway] = EL_AMOEBA_GROWING; // creation of new amoeba
Store[newax][neway] = element;
}
else if (neway == ay || element == EL_EMC_DRIPPER)
{
- Feld[newax][neway] = EL_AMOEBA_DROP; // drop left/right of amoeba
+ Tile[newax][neway] = EL_AMOEBA_DROP; // drop left/right of amoeba
PlayLevelSoundAction(newax, neway, ACTION_GROWING);
}
else
{
InitMovingField(ax, ay, MV_DOWN); // drop dripping from amoeba
- Feld[ax][ay] = EL_AMOEBA_DROPPING;
+ Tile[ax][ay] = EL_AMOEBA_DROPPING;
Store[ax][ay] = EL_AMOEBA_DROP;
ContinueMoving(ax, ay);
return;
{
int x1, y1, x2, y2;
int life_time = 40;
- int element = Feld[ax][ay];
+ int element = Tile[ax][ay];
int graphic = el2img(element);
int *life_parameter = (element == EL_GAME_OF_LIFE ? level.game_of_life :
level.biomaze);
for (y1 = -1; y1 < 2; y1++) for (x1 = -1; x1 < 2; x1++)
{
int xx = ax+x1, yy = ay+y1;
- int old_element = Feld[xx][yy];
+ int old_element = Tile[xx][yy];
int num_neighbours = 0;
if (!IN_LEV_FIELD(xx, yy))
if (level.use_life_bugs)
is_neighbour =
- (((Feld[x][y] == element || is_player_cell) && !Stop[x][y]) ||
+ (((Tile[x][y] == element || is_player_cell) && !Stop[x][y]) ||
(IS_FREE(x, y) && Stop[x][y]));
else
is_neighbour =
if (num_neighbours < life_parameter[0] ||
num_neighbours > life_parameter[1])
{
- Feld[xx][yy] = EL_EMPTY;
- if (Feld[xx][yy] != old_element)
+ Tile[xx][yy] = EL_EMPTY;
+ if (Tile[xx][yy] != old_element)
TEST_DrawLevelField(xx, yy);
Stop[xx][yy] = TRUE;
changed = TRUE;
}
}
- else if (is_free || CAN_GROW_INTO(Feld[xx][yy]))
+ else if (is_free || CAN_GROW_INTO(Tile[xx][yy]))
{ // free border field
if (num_neighbours >= life_parameter[2] &&
num_neighbours <= life_parameter[3])
{
- Feld[xx][yy] = element;
- MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time-1);
- if (Feld[xx][yy] != old_element)
+ Tile[xx][yy] = element;
+ MovDelay[xx][yy] = (element == EL_GAME_OF_LIFE ? 0 : life_time - 1);
+ if (Tile[xx][yy] != old_element)
TEST_DrawLevelField(xx, yy);
Stop[xx][yy] = TRUE;
changed = TRUE;
x = bx - 1 + xx;
y = by - 1 + yy;
- if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY)
+ if (IN_LEV_FIELD(x, y) && Tile[x][y] == EL_EMPTY)
CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]);
}
else
int xx = x - bx + 1;
int yy = y - by + 1;
- if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY)
+ if (IN_LEV_FIELD(x, y) && Tile[x][y] == EL_EMPTY)
CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]);
}
}
game.sokoban_objects_still_needed > 0 ||
game.lights_still_needed > 0)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int graphic = el2img(element);
if (IS_ANIMATED(graphic))
if (game.all_players_gone)
return;
- Feld[x][y] = EL_EXIT_OPENING;
+ Tile[x][y] = EL_EXIT_OPENING;
PlayLevelSoundNearest(x, y, SND_CLASS_EXIT_OPENING);
}
game.sokoban_objects_still_needed > 0 ||
game.lights_still_needed > 0)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int graphic = el2img(element);
if (IS_ANIMATED(graphic))
if (game.all_players_gone)
return;
- Feld[x][y] = EL_EM_EXIT_OPENING;
+ Tile[x][y] = EL_EM_EXIT_OPENING;
PlayLevelSoundNearest(x, y, SND_CLASS_EM_EXIT_OPENING);
}
game.sokoban_objects_still_needed > 0 ||
game.lights_still_needed > 0)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int graphic = el2img(element);
if (IS_ANIMATED(graphic))
if (game.all_players_gone)
return;
- Feld[x][y] = EL_STEEL_EXIT_OPENING;
+ Tile[x][y] = EL_STEEL_EXIT_OPENING;
PlayLevelSoundNearest(x, y, SND_CLASS_STEEL_EXIT_OPENING);
}
game.sokoban_objects_still_needed > 0 ||
game.lights_still_needed > 0)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int graphic = el2img(element);
if (IS_ANIMATED(graphic))
if (game.all_players_gone)
return;
- Feld[x][y] = EL_EM_STEEL_EXIT_OPENING;
+ Tile[x][y] = EL_EM_STEEL_EXIT_OPENING;
PlayLevelSoundNearest(x, y, SND_CLASS_EM_STEEL_EXIT_OPENING);
}
{
if (game.gems_still_needed > 0)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int graphic = el2img(element);
if (IS_ANIMATED(graphic))
if (game.all_players_gone)
return;
- Feld[x][y] = EL_SP_EXIT_OPENING;
+ Tile[x][y] = EL_SP_EXIT_OPENING;
PlayLevelSoundNearest(x, y, SND_CLASS_SP_EXIT_OPENING);
}
SCAN_PLAYFIELD(x, y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
{
- Feld[x][y] = EL_TIMEGATE_CLOSING;
+ Tile[x][y] = EL_TIMEGATE_CLOSING;
PlayLevelSoundAction(x, y, ACTION_CLOSING);
}
if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
return;
- if (Feld[x][y] == EL_BD_DIAMOND)
+ if (Tile[x][y] == EL_BD_DIAMOND)
return;
if (MovDelay[x][y] == 0) // next animation frame
{
MovDelay[x][y]--;
- DrawLevelElementAnimation(x, y, Feld[x][y]);
+ DrawLevelElementAnimation(x, y, Tile[x][y]);
if (MovDelay[x][y] != 0)
{
}
}
-static void MauerWaechst(int x, int y)
+static void WallGrowing(int x, int y)
{
int delay = 6;
if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
- int graphic = el_dir2img(Feld[x][y], GfxDir[x][y]);
+ int graphic = el_dir2img(Tile[x][y], GfxDir[x][y]);
int frame = getGraphicAnimationFrame(graphic, 17 - MovDelay[x][y]);
- DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
+ DrawLevelGraphic(x, y, graphic, frame);
}
if (!MovDelay[x][y])
{
if (MovDir[x][y] == MV_LEFT)
{
- if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Feld[x - 1][y]))
+ if (IN_LEV_FIELD(x - 1, y) && IS_WALL(Tile[x - 1][y]))
TEST_DrawLevelField(x - 1, y);
}
else if (MovDir[x][y] == MV_RIGHT)
{
- if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Feld[x + 1][y]))
+ if (IN_LEV_FIELD(x + 1, y) && IS_WALL(Tile[x + 1][y]))
TEST_DrawLevelField(x + 1, y);
}
else if (MovDir[x][y] == MV_UP)
{
- if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Feld[x][y - 1]))
+ if (IN_LEV_FIELD(x, y - 1) && IS_WALL(Tile[x][y - 1]))
TEST_DrawLevelField(x, y - 1);
}
else
{
- if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Feld[x][y + 1]))
+ if (IN_LEV_FIELD(x, y + 1) && IS_WALL(Tile[x][y + 1]))
TEST_DrawLevelField(x, y + 1);
}
- Feld[x][y] = Store[x][y];
+ Tile[x][y] = Store[x][y];
Store[x][y] = 0;
GfxDir[x][y] = MovDir[x][y] = MV_NONE;
TEST_DrawLevelField(x, y);
}
}
-static void MauerAbleger(int ax, int ay)
+static void CheckWallGrowing(int ax, int ay)
{
- int element = Feld[ax][ay];
+ int element = Tile[ax][ay];
int graphic = el2img(element);
- boolean oben_frei = FALSE, unten_frei = FALSE;
- boolean links_frei = FALSE, rechts_frei = FALSE;
- boolean oben_massiv = FALSE, unten_massiv = FALSE;
- boolean links_massiv = FALSE, rechts_massiv = FALSE;
- boolean new_wall = FALSE;
+ boolean free_top = FALSE;
+ boolean free_bottom = FALSE;
+ boolean free_left = FALSE;
+ boolean free_right = FALSE;
+ boolean stop_top = FALSE;
+ boolean stop_bottom = FALSE;
+ boolean stop_left = FALSE;
+ boolean stop_right = FALSE;
+ boolean new_wall = FALSE;
+
+ boolean is_steelwall = (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
+ element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
+ element == EL_EXPANDABLE_STEELWALL_ANY);
+
+ boolean grow_vertical = (element == EL_EXPANDABLE_WALL_VERTICAL ||
+ element == EL_EXPANDABLE_WALL_ANY ||
+ element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
+ element == EL_EXPANDABLE_STEELWALL_ANY);
+
+ boolean grow_horizontal = (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
+ element == EL_EXPANDABLE_WALL_ANY ||
+ element == EL_EXPANDABLE_WALL ||
+ element == EL_BD_EXPANDABLE_WALL ||
+ element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
+ element == EL_EXPANDABLE_STEELWALL_ANY);
+
+ boolean stop_vertical = (element == EL_EXPANDABLE_WALL_VERTICAL ||
+ element == EL_EXPANDABLE_STEELWALL_VERTICAL);
+
+ boolean stop_horizontal = (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
+ element == EL_EXPANDABLE_WALL ||
+ element == EL_EXPANDABLE_STEELWALL_HORIZONTAL);
+
+ int wall_growing = (is_steelwall ?
+ EL_EXPANDABLE_STEELWALL_GROWING :
+ EL_EXPANDABLE_WALL_GROWING);
+
+ int gfx_wall_growing_up = (is_steelwall ?
+ IMG_EXPANDABLE_STEELWALL_GROWING_UP :
+ IMG_EXPANDABLE_WALL_GROWING_UP);
+ int gfx_wall_growing_down = (is_steelwall ?
+ IMG_EXPANDABLE_STEELWALL_GROWING_DOWN :
+ IMG_EXPANDABLE_WALL_GROWING_DOWN);
+ int gfx_wall_growing_left = (is_steelwall ?
+ IMG_EXPANDABLE_STEELWALL_GROWING_LEFT :
+ IMG_EXPANDABLE_WALL_GROWING_LEFT);
+ int gfx_wall_growing_right = (is_steelwall ?
+ IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT :
+ IMG_EXPANDABLE_WALL_GROWING_RIGHT);
if (IS_ANIMATED(graphic))
DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
return;
}
- if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
- oben_frei = TRUE;
- if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
- unten_frei = TRUE;
- if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
- links_frei = TRUE;
- if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
- rechts_frei = TRUE;
+ if (IN_LEV_FIELD(ax, ay - 1) && IS_FREE(ax, ay - 1))
+ free_top = TRUE;
+ if (IN_LEV_FIELD(ax, ay + 1) && IS_FREE(ax, ay + 1))
+ free_bottom = TRUE;
+ if (IN_LEV_FIELD(ax - 1, ay) && IS_FREE(ax - 1, ay))
+ free_left = TRUE;
+ if (IN_LEV_FIELD(ax + 1, ay) && IS_FREE(ax + 1, ay))
+ free_right = TRUE;
- if (element == EL_EXPANDABLE_WALL_VERTICAL ||
- element == EL_EXPANDABLE_WALL_ANY)
+ if (grow_vertical)
{
- if (oben_frei)
- {
- Feld[ax][ay-1] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax][ay-1] = element;
- GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
- IMG_EXPANDABLE_WALL_GROWING_UP, 0);
- new_wall = TRUE;
- }
- if (unten_frei)
+ if (free_top)
{
- Feld[ax][ay+1] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax][ay+1] = element;
- GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
- IMG_EXPANDABLE_WALL_GROWING_DOWN, 0);
- new_wall = TRUE;
- }
- }
+ Tile[ax][ay - 1] = wall_growing;
+ Store[ax][ay - 1] = element;
+ GfxDir[ax][ay - 1] = MovDir[ax][ay - 1] = MV_UP;
- if (element == EL_EXPANDABLE_WALL_HORIZONTAL ||
- element == EL_EXPANDABLE_WALL_ANY ||
- element == EL_EXPANDABLE_WALL ||
- element == EL_BD_EXPANDABLE_WALL)
- {
- if (links_frei)
- {
- Feld[ax-1][ay] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax-1][ay] = element;
- GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
- if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
- IMG_EXPANDABLE_WALL_GROWING_LEFT, 0);
- new_wall = TRUE;
- }
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay - 1)))
+ DrawLevelGraphic(ax, ay - 1, gfx_wall_growing_up, 0);
- if (rechts_frei)
- {
- Feld[ax+1][ay] = EL_EXPANDABLE_WALL_GROWING;
- Store[ax+1][ay] = element;
- GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
- if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
- IMG_EXPANDABLE_WALL_GROWING_RIGHT, 0);
new_wall = TRUE;
}
- }
-
- if (element == EL_EXPANDABLE_WALL && (links_frei || rechts_frei))
- TEST_DrawLevelField(ax, ay);
-
- if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1]))
- oben_massiv = TRUE;
- if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1]))
- unten_massiv = TRUE;
- if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay]))
- links_massiv = TRUE;
- if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay]))
- rechts_massiv = TRUE;
-
- if (((oben_massiv && unten_massiv) ||
- element == EL_EXPANDABLE_WALL_HORIZONTAL ||
- element == EL_EXPANDABLE_WALL) &&
- ((links_massiv && rechts_massiv) ||
- element == EL_EXPANDABLE_WALL_VERTICAL))
- Feld[ax][ay] = EL_WALL;
-
- if (new_wall)
- PlayLevelSoundAction(ax, ay, ACTION_GROWING);
-}
-
-static void MauerAblegerStahl(int ax, int ay)
-{
- int element = Feld[ax][ay];
- int graphic = el2img(element);
- boolean oben_frei = FALSE, unten_frei = FALSE;
- boolean links_frei = FALSE, rechts_frei = FALSE;
- boolean oben_massiv = FALSE, unten_massiv = FALSE;
- boolean links_massiv = FALSE, rechts_massiv = FALSE;
- boolean new_wall = FALSE;
-
- if (IS_ANIMATED(graphic))
- DrawLevelGraphicAnimationIfNeeded(ax, ay, graphic);
-
- if (!MovDelay[ax][ay]) // start building new wall
- MovDelay[ax][ay] = 6;
- if (MovDelay[ax][ay]) // wait some time before building new wall
- {
- MovDelay[ax][ay]--;
- if (MovDelay[ax][ay])
- return;
- }
+ if (free_bottom)
+ {
+ Tile[ax][ay + 1] = wall_growing;
+ Store[ax][ay + 1] = element;
+ GfxDir[ax][ay + 1] = MovDir[ax][ay + 1] = MV_DOWN;
- if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
- oben_frei = TRUE;
- if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
- unten_frei = TRUE;
- if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
- links_frei = TRUE;
- if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
- rechts_frei = TRUE;
+ if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay + 1)))
+ DrawLevelGraphic(ax, ay + 1, gfx_wall_growing_down, 0);
- if (element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
- element == EL_EXPANDABLE_STEELWALL_ANY)
- {
- if (oben_frei)
- {
- Feld[ax][ay-1] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax][ay-1] = element;
- GfxDir[ax][ay-1] = MovDir[ax][ay-1] = MV_UP;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay - 1),
- IMG_EXPANDABLE_STEELWALL_GROWING_UP, 0);
- new_wall = TRUE;
- }
- if (unten_frei)
- {
- Feld[ax][ay+1] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax][ay+1] = element;
- GfxDir[ax][ay+1] = MovDir[ax][ay+1] = MV_DOWN;
- if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
- DrawGraphic(SCREENX(ax), SCREENY(ay + 1),
- IMG_EXPANDABLE_STEELWALL_GROWING_DOWN, 0);
new_wall = TRUE;
}
}
- if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
- element == EL_EXPANDABLE_STEELWALL_ANY)
+ if (grow_horizontal)
{
- if (links_frei)
+ if (free_left)
{
- Feld[ax-1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax-1][ay] = element;
- GfxDir[ax-1][ay] = MovDir[ax-1][ay] = MV_LEFT;
- if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax - 1), SCREENY(ay),
- IMG_EXPANDABLE_STEELWALL_GROWING_LEFT, 0);
+ Tile[ax - 1][ay] = wall_growing;
+ Store[ax - 1][ay] = element;
+ GfxDir[ax - 1][ay] = MovDir[ax - 1][ay] = MV_LEFT;
+
+ if (IN_SCR_FIELD(SCREENX(ax - 1), SCREENY(ay)))
+ DrawLevelGraphic(ax - 1, ay, gfx_wall_growing_left, 0);
+
new_wall = TRUE;
}
- if (rechts_frei)
+ if (free_right)
{
- Feld[ax+1][ay] = EL_EXPANDABLE_STEELWALL_GROWING;
- Store[ax+1][ay] = element;
- GfxDir[ax+1][ay] = MovDir[ax+1][ay] = MV_RIGHT;
- if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
- DrawGraphic(SCREENX(ax + 1), SCREENY(ay),
- IMG_EXPANDABLE_STEELWALL_GROWING_RIGHT, 0);
+ Tile[ax + 1][ay] = wall_growing;
+ Store[ax + 1][ay] = element;
+ GfxDir[ax + 1][ay] = MovDir[ax + 1][ay] = MV_RIGHT;
+
+ if (IN_SCR_FIELD(SCREENX(ax + 1), SCREENY(ay)))
+ DrawLevelGraphic(ax + 1, ay, gfx_wall_growing_right, 0);
+
new_wall = TRUE;
}
}
- if (!IN_LEV_FIELD(ax, ay-1) || IS_WALL(Feld[ax][ay-1]))
- oben_massiv = TRUE;
- if (!IN_LEV_FIELD(ax, ay+1) || IS_WALL(Feld[ax][ay+1]))
- unten_massiv = TRUE;
- if (!IN_LEV_FIELD(ax-1, ay) || IS_WALL(Feld[ax-1][ay]))
- links_massiv = TRUE;
- if (!IN_LEV_FIELD(ax+1, ay) || IS_WALL(Feld[ax+1][ay]))
- rechts_massiv = TRUE;
+ if (element == EL_EXPANDABLE_WALL && (free_left || free_right))
+ TEST_DrawLevelField(ax, ay);
+
+ if (!IN_LEV_FIELD(ax, ay - 1) || IS_WALL(Tile[ax][ay - 1]))
+ stop_top = TRUE;
+ if (!IN_LEV_FIELD(ax, ay + 1) || IS_WALL(Tile[ax][ay + 1]))
+ stop_bottom = TRUE;
+ if (!IN_LEV_FIELD(ax - 1, ay) || IS_WALL(Tile[ax - 1][ay]))
+ stop_left = TRUE;
+ if (!IN_LEV_FIELD(ax + 1, ay) || IS_WALL(Tile[ax + 1][ay]))
+ stop_right = TRUE;
- if (((oben_massiv && unten_massiv) ||
- element == EL_EXPANDABLE_STEELWALL_HORIZONTAL) &&
- ((links_massiv && rechts_massiv) ||
- element == EL_EXPANDABLE_STEELWALL_VERTICAL))
- Feld[ax][ay] = EL_STEELWALL;
+ if (((stop_top && stop_bottom) || stop_horizontal) &&
+ ((stop_left && stop_right) || stop_vertical))
+ Tile[ax][ay] = (is_steelwall ? EL_STEELWALL : EL_WALL);
if (new_wall)
PlayLevelSoundAction(ax, ay, ACTION_GROWING);
{
int i, j;
boolean dragon_found = FALSE;
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
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].x;
+ int yy = y + j * xy[i].y;
if (IN_LEV_FIELD(xx, yy) &&
- (Feld[xx][yy] == EL_FLAMES || Feld[xx][yy] == EL_DRAGON))
+ (Tile[xx][yy] == EL_FLAMES || Tile[xx][yy] == EL_DRAGON))
{
- if (Feld[xx][yy] == EL_DRAGON)
+ if (Tile[xx][yy] == EL_DRAGON)
dragon_found = TRUE;
}
else
{
for (j = 0; j < 3; j++)
{
- int xx = x + j * xy[i][0], yy = y + j * xy[i][1];
-
- if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_FLAMES)
+ int xx = x + j * xy[i].x;
+ int yy = y + j * xy[i].y;
+
+ if (IN_LEV_FIELD(xx, yy) && Tile[xx][yy] == EL_FLAMES)
{
- Feld[xx][yy] = EL_EMPTY;
+ Tile[xx][yy] = EL_EMPTY;
TEST_DrawLevelField(xx, yy);
}
else
static void InitBuggyBase(int x, int y)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
int activating_delay = FRAMES_PER_SECOND / 4;
ChangeDelay[x][y] =
static void WarnBuggyBase(int x, int y)
{
int i;
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy))
{
DisplayGameControlValues();
- if (!TimeLeft && setup.time_limit)
+ if (!TimeLeft && game.time_limit)
for (i = 0; i < MAX_PLAYERS; i++)
KillPlayer(&stored_player[i]);
}
*/
SCAN_PLAYFIELD(xx, yy)
{
- if (Feld[xx][yy] == element)
+ if (Tile[xx][yy] == element)
CheckElementChange(xx, yy, element, EL_UNDEFINED,
CE_SCORE_GETS_ZERO);
}
SCAN_PLAYFIELD(xx, yy)
{
- if (Feld[xx][yy] == element)
+ if (Tile[xx][yy] == element)
{
if (reset_frame)
{
static void CreateFieldExt(int x, int y, int element, boolean is_change)
{
- int old_element = Feld[x][y];
+ int old_element = Tile[x][y];
int new_element = GetElementFromGroupElement(element);
int previous_move_direction = MovDir[x][y];
int last_ce_value = CustomValue[x][y];
boolean player_explosion_protected = PLAYER_EXPLOSION_PROTECTED(x, y);
- boolean new_element_is_player = ELEM_IS_PLAYER(new_element);
+ boolean new_element_is_player = IS_PLAYER_ELEMENT(new_element);
boolean add_player_onto_element = (new_element_is_player &&
new_element != EL_SOKOBAN_FIELD_PLAYER &&
IS_WALKABLE(old_element));
else
RemoveField(x, y);
- Feld[x][y] = new_element;
+ Tile[x][y] = new_element;
if (element_info[new_element].move_direction_initial == MV_START_PREVIOUS)
MovDir[x][y] = previous_move_direction;
InitField_WithBug1(x, y, FALSE);
- new_element = Feld[x][y]; // element may have changed
+ new_element = Tile[x][y]; // element may have changed
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
if (game.engine_version >= VERSION_IDENT(3,2,0,7))
{
- int old_element = Feld[x][y];
+ int old_element = Tile[x][y];
// prevent changed element from moving in same engine frame
// unless both old and new element can either fall or move
int ce_value = CustomValue[x][y];
int ce_score = ei->collect_score;
int target_element;
- int old_element = Feld[x][y];
+ int old_element = Tile[x][y];
// always use default change event to prevent running into a loop
if (ChangeEvent[x][y] == -1)
continue;
}
- e = Feld[ex][ey];
+ e = Tile[ex][ey];
if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
e = MovingOrBlocked2Element(ex, ey);
(change->replace_when == CP_WHEN_COLLECTIBLE && is_collectible) ||
(change->replace_when == CP_WHEN_REMOVABLE && is_removable) ||
(change->replace_when == CP_WHEN_DESTRUCTIBLE && is_destructible)) &&
- !(IS_PLAYER(ex, ey) && ELEM_IS_PLAYER(content_element)));
+ !(IS_PLAYER(ex, ey) && IS_PLAYER_ELEMENT(content_element)));
if (!can_replace[xx][yy])
complete_replace = FALSE;
Store[x][y] = EL_EMPTY;
}
+ // special case: element changes to player (and may be kept if walkable)
+ if (IS_PLAYER_ELEMENT(target_element) && !level.keep_walkable_ce)
+ CreateElementFromChange(x, y, EL_EMPTY);
+
CreateElementFromChange(x, y, target_element);
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
if (!CAN_CHANGE_OR_HAS_ACTION(element) &&
!CAN_CHANGE_OR_HAS_ACTION(Back[x][y]))
{
- printf("\n\n");
- printf("HandleElementChange(): %d,%d: element = %d ('%s')\n",
- x, y, element, element_info[element].token_name);
- printf("HandleElementChange(): This should never happen!\n");
- printf("\n\n");
+ Debug("game:playing:HandleElementChange", "%d,%d: element = %d ('%s')",
+ x, y, element, element_info[element].token_name);
+ Debug("game:playing:HandleElementChange", "This should never happen!");
}
#endif
SCAN_PLAYFIELD(x, y)
{
- if (Feld[x][y] == element)
+ if (Tile[x][y] == element)
{
if (change->can_change && !change_done)
{
!HAS_ANY_CHANGE_EVENT(element, trigger_event))
return FALSE;
- if (Feld[x][y] == EL_BLOCKED)
+ if (Tile[x][y] == EL_BLOCKED)
{
Blocked2Moving(x, y, &x, &y);
- element = Feld[x][y];
+ element = Tile[x][y];
}
// check if element has already changed or is about to change after moving
if ((game.engine_version < VERSION_IDENT(3,2,0,7) &&
- Feld[x][y] != element) ||
+ Tile[x][y] != element) ||
(game.engine_version >= VERSION_IDENT(3,2,0,7) &&
(ChangeCount[x][y] >= game.max_num_changes_per_frame ||
different to element changes that affect other elements to change on the
whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */
boolean check_trigger_element =
- (trigger_event == CE_TOUCHING_X ||
+ (trigger_event == CE_NEXT_TO_X ||
+ trigger_event == CE_TOUCHING_X ||
trigger_event == CE_HITTING_X ||
trigger_event == CE_HIT_BY_X ||
trigger_event == CE_DIGGING_X); // this one was forgotten until 3.2.3
// special case for sleeping Murphy when leaning against non-free tile
if (!IN_LEV_FIELD(player->jx - 1, player->jy) ||
- (Feld[player->jx - 1][player->jy] != EL_EMPTY &&
+ (Tile[player->jx - 1][player->jy] != EL_EMPTY &&
!IS_MOVING(player->jx - 1, player->jy)))
move_dir = MV_LEFT;
else if (!IN_LEV_FIELD(player->jx + 1, player->jy) ||
- (Feld[player->jx + 1][player->jy] != EL_EMPTY &&
+ (Tile[player->jx + 1][player->jy] != EL_EMPTY &&
!IS_MOVING(player->jx + 1, player->jy)))
move_dir = MV_RIGHT;
else
if (!player->is_dropping)
player->was_dropping = FALSE;
}
+
+ static struct MouseActionInfo mouse_action_last = { 0 };
+ struct MouseActionInfo mouse_action = player->effective_mouse_action;
+ boolean new_released = (!mouse_action.button && mouse_action_last.button);
+
+ if (new_released)
+ CheckSaveEngineSnapshotToList();
+
+ mouse_action_last = mouse_action;
}
static void CheckSingleStepMode(struct PlayerInfo *player)
{
if (tape.single_step && tape.recording && !tape.pausing)
{
- /* as it is called "single step mode", just return to pause mode when the
- player stopped moving after one tile (or never starts moving at all) */
- if (!player->is_moving &&
- !player->is_pushing &&
- !player->is_dropping_pressed)
- TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+ // as it is called "single step mode", just return to pause mode when the
+ // player stopped moving after one tile (or never starts moving at all)
+ // (reverse logic needed here in case single step mode used in team mode)
+ if (player->is_moving ||
+ player->is_pushing ||
+ player->is_dropping_pressed ||
+ player->effective_mouse_action.button)
+ game.enter_single_step_mode = FALSE;
}
CheckSaveEngineSnapshot(player);
}
}
+static void CheckLevelTime_StepCounter(void)
+{
+ int i;
+
+ TimePlayed++;
+
+ if (TimeLeft > 0)
+ {
+ TimeLeft--;
+
+ if (TimeLeft <= 10 && game.time_limit && !game.LevelSolved)
+ PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
+
+ game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
+
+ DisplayGameControlValues();
+
+ if (!TimeLeft && game.time_limit && !game.LevelSolved)
+ for (i = 0; i < MAX_PLAYERS; i++)
+ KillPlayer(&stored_player[i]);
+ }
+ else if (game.no_level_time_limit && !game.all_players_gone)
+ {
+ game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
+
+ DisplayGameControlValues();
+ }
+}
+
static void CheckLevelTime(void)
{
int i;
{
TimeLeft--;
- if (TimeLeft <= 10 && setup.time_limit)
+ if (TimeLeft <= 10 && game.time_limit)
PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
/* this does not make sense: game_panel_controls[GAME_PANEL_TIME].value
game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
- if (!TimeLeft && setup.time_limit)
+ if (!TimeLeft && game.time_limit)
{
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
game_em.lev->killed_out_of_time = TRUE;
KillPlayer(&stored_player[i]);
}
}
- else if (game.no_time_limit && !game.all_players_gone)
+ else if (game.no_level_time_limit && !game.all_players_gone)
{
game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
}
- game_em.lev->time = (game.no_time_limit ? TimePlayed : TimeLeft);
+ game_em.lev->time = (game.no_level_time_limit ? TimePlayed : TimeLeft);
}
if (tape.recording || tape.playing)
}
}
+void AdvanceFrameCounter(void)
+{
+ FrameCounter++;
+}
+
+void AdvanceGfxFrame(void)
+{
+ int x, y;
+
+ SCAN_PLAYFIELD(x, y)
+ {
+ GfxFrame[x][y]++;
+ }
+}
+
void StartGameActions(boolean init_network_game, boolean record_tape,
int random_seed)
{
if (record_tape)
TapeStartRecording(new_random_seed);
+ if (setup.auto_pause_on_start && !tape.pausing)
+ TapeTogglePause(TAPE_TOGGLE_MANUAL);
+
if (init_network_game)
{
SendToServer_LevelFile();
EL_NAME(recursion_loop_element),
" caused endless loop! Quit the game?");
- Error(ERR_WARN, "element '%s' caused endless loop in game engine",
- EL_NAME(recursion_loop_element));
+ Warn("element '%s' caused endless loop in game engine",
+ EL_NAME(recursion_loop_element));
- RequestQuitGameExt(FALSE, level_editor_test_game, message);
+ RequestQuitGameExt(program.headless, level_editor_test_game, message);
recursion_loop_detected = FALSE; // if game should be continued
int skip = WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value);
- printf("::: skip == %d\n", skip);
+ Debug("game:playing:skip", "skip == %d", skip);
#else
// ---------- main game synchronization point ----------
byte mapped_action[MAX_PLAYERS];
#if DEBUG_PLAYER_ACTIONS
- printf(":::");
for (i = 0; i < MAX_PLAYERS; i++)
- printf(" %d, ", stored_player[i].effective_action);
+ DebugContinued("", "%d, ", stored_player[i].effective_action);
#endif
for (i = 0; i < MAX_PLAYERS; i++)
stored_player[i].effective_action = mapped_action[i];
#if DEBUG_PLAYER_ACTIONS
- printf(" =>");
+ DebugContinued("", "=> ");
for (i = 0; i < MAX_PLAYERS; i++)
- printf(" %d, ", stored_player[i].effective_action);
- printf("\n");
+ DebugContinued("", "%d, ", stored_player[i].effective_action);
+ DebugContinued("game:playing:player", "\n");
#endif
}
#if DEBUG_PLAYER_ACTIONS
else
{
- printf(":::");
for (i = 0; i < MAX_PLAYERS; i++)
- printf(" %d, ", stored_player[i].effective_action);
- printf("\n");
+ DebugContinued("", "%d, ", stored_player[i].effective_action);
+ DebugContinued("game:playing:player", "\n");
}
#endif
#endif
void GameActions_EM_Main(void)
{
byte effective_action[MAX_PLAYERS];
- boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
int i;
for (i = 0; i < MAX_PLAYERS; i++)
effective_action[i] = stored_player[i].effective_action;
- GameActions_EM(effective_action, warp_mode);
+ GameActions_EM(effective_action);
}
void GameActions_SP_Main(void)
{
byte effective_action[MAX_PLAYERS];
- boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
int i;
for (i = 0; i < MAX_PLAYERS; i++)
effective_action[i] = stored_player[i].effective_action;
- GameActions_SP(effective_action, warp_mode);
+ GameActions_SP(effective_action);
for (i = 0; i < MAX_PLAYERS; i++)
{
void GameActions_MM_Main(void)
{
- boolean warp_mode = (tape.playing && tape.warp_forward && !tape.pausing);
+ AdvanceGfxFrame();
- GameActions_MM(local_player->effective_mouse_action, warp_mode);
+ GameActions_MM(local_player->effective_mouse_action);
}
void GameActions_RND_Main(void)
game.centered_player_nr = game.centered_player_nr_next;
game.set_centered_player = FALSE;
- DrawRelocateScreen(0, 0, sx, sy, MV_NONE, TRUE, setup.quick_switch);
+ DrawRelocateScreen(0, 0, sx, sy, TRUE, setup.quick_switch);
DrawGameDoorValues();
}
+ // check single step mode (set flag and clear again if any player is active)
+ game.enter_single_step_mode =
+ (tape.single_step && tape.recording && !tape.pausing);
+
for (i = 0; i < MAX_PLAYERS; i++)
{
int actual_player_action = stored_player[i].effective_action;
ScrollPlayer(&stored_player[i], SCROLL_GO_ON);
}
+ // single step pause mode may already have been toggled by "ScrollPlayer()"
+ if (game.enter_single_step_mode && !tape.pausing)
+ TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
+
ScrollScreen(NULL, SCROLL_GO_ON);
/* for backwards compatibility, the following code emulates a fixed bug that
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))
+ Tile[x][y] == EL_SPRING))
{
ContinueMoving(x, y);
SCAN_PLAYFIELD(x, y)
{
- Last[x][y] = Feld[x][y];
+ Last[x][y] = Tile[x][y];
ChangeCount[x][y] = 0;
ChangeEvent[x][y] = -1;
// this must be handled before main playfield loop
- if (Feld[x][y] == EL_PLAYER_IS_LEAVING)
+ if (Tile[x][y] == EL_PLAYER_IS_LEAVING)
{
MovDelay[x][y]--;
if (MovDelay[x][y] <= 0)
RemoveField(x, y);
}
- if (Feld[x][y] == EL_ELEMENT_SNAPPING)
+ if (Tile[x][y] == EL_ELEMENT_SNAPPING)
{
MovDelay[x][y]--;
if (MovDelay[x][y] <= 0)
{
+ int element = Store[x][y];
+ int move_direction = MovDir[x][y];
+ int player_index_bit = Store2[x][y];
+
+ Store[x][y] = 0;
+ Store2[x][y] = 0;
+
RemoveField(x, y);
TEST_DrawLevelField(x, y);
- TestIfElementTouchesCustomElement(x, y); // for empty space
+ TestFieldAfterSnapping(x, y, element, move_direction, player_index_bit);
+
+ if (IS_ENVELOPE(element))
+ local_player->show_envelope = element;
}
}
#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");
+ Debug("game:playing:GameActions_RND", "x = %d, y = %d: ChangePage != -1",
+ x, y);
+ Debug("game:playing:GameActions_RND", "This should never happen!");
ChangePage[x][y] = -1;
}
Blocked2Moving(x, y, &oldx, &oldy);
if (!IS_MOVING(oldx, oldy))
{
- printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n");
- printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
- printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
- printf("GameActions(): This should never happen!\n");
+ Debug("game:playing:GameActions_RND", "(BLOCKED => MOVING) context corrupted!");
+ Debug("game:playing:GameActions_RND", "BLOCKED: x = %d, y = %d", x, y);
+ Debug("game:playing:GameActions_RND", "!MOVING: oldx = %d, oldy = %d", oldx, oldy);
+ Debug("game:playing:GameActions_RND", "This should never happen!");
}
}
#endif
if (mouse_action.button)
{
int new_button = (mouse_action.button && mouse_action_last.button == 0);
+ int ch_button = CH_SIDE_FROM_BUTTON(mouse_action.button);
x = mouse_action.lx;
y = mouse_action.ly;
- element = Feld[x][y];
+ element = Tile[x][y];
if (new_button)
{
- CheckElementChange(x, y, element, EL_UNDEFINED, CE_CLICKED_BY_MOUSE);
- CheckTriggeredElementChange(x, y, element, CE_MOUSE_CLICKED_ON_X);
+ CheckElementChangeByMouse(x, y, element, CE_CLICKED_BY_MOUSE, ch_button);
+ CheckTriggeredElementChangeByMouse(x, y, element, CE_MOUSE_CLICKED_ON_X,
+ ch_button);
}
- CheckElementChange(x, y, element, EL_UNDEFINED, CE_PRESSED_BY_MOUSE);
- CheckTriggeredElementChange(x, y, element, CE_MOUSE_PRESSED_ON_X);
+ CheckElementChangeByMouse(x, y, element, CE_PRESSED_BY_MOUSE, ch_button);
+ CheckTriggeredElementChangeByMouse(x, y, element, CE_MOUSE_PRESSED_ON_X,
+ ch_button);
+
+ if (level.use_step_counter)
+ {
+ boolean counted_click = FALSE;
+
+ // element clicked that can change when clicked/pressed
+ if (CAN_CHANGE_OR_HAS_ACTION(element) &&
+ (HAS_ANY_CHANGE_EVENT(element, CE_CLICKED_BY_MOUSE) ||
+ HAS_ANY_CHANGE_EVENT(element, CE_PRESSED_BY_MOUSE)))
+ counted_click = TRUE;
+
+ // element clicked that can trigger change when clicked/pressed
+ if (trigger_events[element][CE_MOUSE_CLICKED_ON_X] ||
+ trigger_events[element][CE_MOUSE_PRESSED_ON_X])
+ counted_click = TRUE;
+
+ if (new_button && counted_click)
+ CheckLevelTime_StepCounter();
+ }
}
SCAN_PLAYFIELD(x, y)
{
- element = Feld[x][y];
+ element = Tile[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
last_gfx_frame = GfxFrame[x][y];
+ if (element == EL_EMPTY)
+ graphic = el2img(GfxElementEmpty[x][y]);
+
ResetGfxFrame(x, y);
if (GfxFrame[x][y] != last_gfx_frame && !Stop[x][y])
HandleElementChange(x, y, page);
- element = Feld[x][y];
+ element = Tile[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
}
+ CheckNextToConditions(x, y);
+
if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
{
StartMoving(x, y);
- element = Feld[x][y];
+ element = Tile[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
if (IS_ANIMATED(graphic) &&
else if (IS_ACTIVE_BOMB(element))
CheckDynamite(x, y);
else if (element == EL_AMOEBA_GROWING)
- AmoebeWaechst(x, y);
+ AmoebaGrowing(x, y);
else if (element == EL_AMOEBA_SHRINKING)
- AmoebaDisappearing(x, y);
+ AmoebaShrinking(x, y);
#if !USE_NEW_AMOEBA_CODE
else if (IS_AMOEBALIVE(element))
- AmoebeAbleger(x, y);
+ AmoebaReproduce(x, y);
#endif
else if (element == EL_GAME_OF_LIFE || element == EL_BIOMAZE)
CheckExitSP(x, y);
else if (element == EL_EXPANDABLE_WALL_GROWING ||
element == EL_EXPANDABLE_STEELWALL_GROWING)
- MauerWaechst(x, y);
+ WallGrowing(x, y);
else if (element == EL_EXPANDABLE_WALL ||
element == EL_EXPANDABLE_WALL_HORIZONTAL ||
element == EL_EXPANDABLE_WALL_VERTICAL ||
element == EL_EXPANDABLE_WALL_ANY ||
- element == EL_BD_EXPANDABLE_WALL)
- MauerAbleger(x, y);
- else if (element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
+ element == EL_BD_EXPANDABLE_WALL ||
+ element == EL_EXPANDABLE_STEELWALL_HORIZONTAL ||
element == EL_EXPANDABLE_STEELWALL_VERTICAL ||
element == EL_EXPANDABLE_STEELWALL_ANY)
- MauerAblegerStahl(x, y);
+ CheckWallGrowing(x, y);
else if (element == EL_FLAMES)
CheckForDragon(x, y);
else if (element == EL_EXPLOSION)
{
x = RND(lev_fieldx);
y = RND(lev_fieldy);
- element = Feld[x][y];
+ element = Tile[x][y];
if (!IS_PLAYER(x,y) &&
(element == EL_EMPTY ||
element == EL_ACID_SPLASH_LEFT ||
element == EL_ACID_SPLASH_RIGHT))
{
- if ((IN_LEV_FIELD(x, y-1) && Feld[x][y-1] == EL_AMOEBA_WET) ||
- (IN_LEV_FIELD(x-1, y) && Feld[x-1][y] == EL_AMOEBA_WET) ||
- (IN_LEV_FIELD(x+1, y) && Feld[x+1][y] == EL_AMOEBA_WET) ||
- (IN_LEV_FIELD(x, y+1) && Feld[x][y+1] == EL_AMOEBA_WET))
- Feld[x][y] = EL_AMOEBA_DROP;
+ if ((IN_LEV_FIELD(x, y - 1) && Tile[x][y - 1] == EL_AMOEBA_WET) ||
+ (IN_LEV_FIELD(x - 1, y) && Tile[x - 1][y] == EL_AMOEBA_WET) ||
+ (IN_LEV_FIELD(x + 1, y) && Tile[x + 1][y] == EL_AMOEBA_WET) ||
+ (IN_LEV_FIELD(x, y + 1) && Tile[x][y + 1] == EL_AMOEBA_WET))
+ Tile[x][y] = EL_AMOEBA_DROP;
}
random = random * 129 + 1;
SCAN_PLAYFIELD(x, y)
{
- element = Feld[x][y];
+ element = Tile[x][y];
if (ExplodeField[x][y])
Explode(x, y, EX_PHASE_START, ExplodeField[x][y]);
{
if (!(game.magic_wall_time_left % 4))
{
- int element = Feld[magic_wall_x][magic_wall_y];
+ int element = Tile[magic_wall_x][magic_wall_y];
if (element == EL_BD_MAGIC_WALL_FULL ||
element == EL_BD_MAGIC_WALL_ACTIVE ||
{
SCAN_PLAYFIELD(x, y)
{
- element = Feld[x][y];
+ element = Tile[x][y];
if (element == EL_MAGIC_WALL_ACTIVE ||
element == EL_MAGIC_WALL_FULL)
{
- Feld[x][y] = EL_MAGIC_WALL_DEAD;
+ Tile[x][y] = EL_MAGIC_WALL_DEAD;
TEST_DrawLevelField(x, y);
}
else if (element == EL_BD_MAGIC_WALL_ACTIVE ||
element == EL_BD_MAGIC_WALL_FULL)
{
- Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
+ Tile[x][y] = EL_BD_MAGIC_WALL_DEAD;
TEST_DrawLevelField(x, y);
}
else if (element == EL_DC_MAGIC_WALL_ACTIVE ||
element == EL_DC_MAGIC_WALL_FULL)
{
- Feld[x][y] = EL_DC_MAGIC_WALL_DEAD;
+ Tile[x][y] = EL_DC_MAGIC_WALL_DEAD;
TEST_DrawLevelField(x, y);
}
}
static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
{
int min_x = x, min_y = y, max_x = x, max_y = y;
+ int scr_fieldx = getScreenFieldSizeX();
+ int scr_fieldy = getScreenFieldSizeY();
int i;
for (i = 0; i < MAX_PLAYERS; i++)
max_y = MAX(max_y, jy);
}
- return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
+ return (max_x - min_x < scr_fieldx && max_y - min_y < scr_fieldy);
}
static boolean AllPlayersInVisibleScreen(void)
return (IN_LEV_FIELD(jx, jy + 1) &&
(IS_FREE(jx, jy + 1) ||
- (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
- IS_WALKABLE_FROM(Feld[jx][jy], MV_DOWN) &&
- !IS_WALKABLE_INSIDE(Feld[jx][jy]));
+ (Tile[jx][jy + 1] == EL_ACID && player->can_fall_into_acid)) &&
+ IS_WALKABLE_FROM(Tile[jx][jy], MV_DOWN) &&
+ !IS_WALKABLE_INSIDE(Tile[jx][jy]));
}
static boolean canPassField(int x, int y, int move_dir)
int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0);
int nextx = x + dx;
int nexty = y + dy;
- int element = Feld[x][y];
+ int element = Tile[x][y];
return (IS_PASSABLE_FROM(element, opposite_dir) &&
!CAN_MOVE(element) &&
IN_LEV_FIELD(nextx, nexty) && !IS_PLAYER(nextx, nexty) &&
- IS_WALKABLE_FROM(Feld[nextx][nexty], move_dir) &&
+ IS_WALKABLE_FROM(Tile[nextx][nexty], move_dir) &&
(level.can_pass_to_walkable || IS_FREE(nextx, nexty)));
}
int newy = y + dy;
return (IN_LEV_FIELD(newx, newy) && !IS_FREE_OR_PLAYER(newx, newy) &&
- IS_GRAVITY_REACHABLE(Feld[newx][newy]) &&
- (IS_DIGGABLE(Feld[newx][newy]) ||
- IS_WALKABLE_FROM(Feld[newx][newy], opposite_dir) ||
+ IS_GRAVITY_REACHABLE(Tile[newx][newy]) &&
+ (IS_DIGGABLE(Tile[newx][newy]) ||
+ IS_WALKABLE_FROM(Tile[newx][newy], opposite_dir) ||
canPassField(newx, newy, move_dir)));
}
boolean field_under_player_is_free =
(IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1));
boolean player_is_standing_on_valid_field =
- (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
- (IS_WALKABLE(Feld[jx][jy]) &&
- !(element_info[Feld[jx][jy]].access_direction & MV_DOWN)));
+ (IS_WALKABLE_INSIDE(Tile[jx][jy]) ||
+ (IS_WALKABLE(Tile[jx][jy]) &&
+ !(element_info[Tile[jx][jy]].access_direction & MV_DOWN)));
if (field_under_player_is_free && !player_is_standing_on_valid_field)
player->programmed_action = MV_DOWN;
int original_move_delay_value = player->move_delay_value;
#if DEBUG
- printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%d]\n",
- tape.counter);
+ Debug("game:playing:MovePlayer",
+ "THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%d]",
+ tape.counter);
#endif
// scroll remaining steps with finest movement resolution
if (mode == SCROLL_INIT)
{
- player->actual_frame_counter = FrameCounter;
+ player->actual_frame_counter.count = FrameCounter;
player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
if ((player->block_last_field || player->block_delay_adjustment > 0) &&
- Feld[last_jx][last_jy] == EL_EMPTY)
+ Tile[last_jx][last_jy] == EL_EMPTY)
{
int last_field_block_delay = 0; // start with no blocking at all
int block_delay_adjustment = player->block_delay_adjustment;
// add block delay adjustment (also possible when not blocking)
last_field_block_delay += block_delay_adjustment;
- Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
+ Tile[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
MovDelay[last_jx][last_jy] = last_field_block_delay + 1;
}
if (player->MovPos != 0) // player has not yet reached destination
return;
}
- else if (!FrameReached(&player->actual_frame_counter, 1))
+ else if (!FrameReached(&player->actual_frame_counter))
return;
if (player->MovPos != 0)
}
}
- player->last_jx = jx;
- player->last_jy = jy;
-
- if (Feld[jx][jy] == EL_EXIT_OPEN ||
- Feld[jx][jy] == EL_EM_EXIT_OPEN ||
- Feld[jx][jy] == EL_EM_EXIT_OPENING ||
- Feld[jx][jy] == EL_STEEL_EXIT_OPEN ||
- Feld[jx][jy] == EL_EM_STEEL_EXIT_OPEN ||
- Feld[jx][jy] == EL_EM_STEEL_EXIT_OPENING ||
- Feld[jx][jy] == EL_SP_EXIT_OPEN ||
- Feld[jx][jy] == EL_SP_EXIT_OPENING) // <-- special case
+ if (Tile[jx][jy] == EL_EXIT_OPEN ||
+ Tile[jx][jy] == EL_EM_EXIT_OPEN ||
+ Tile[jx][jy] == EL_EM_EXIT_OPENING ||
+ Tile[jx][jy] == EL_STEEL_EXIT_OPEN ||
+ Tile[jx][jy] == EL_EM_STEEL_EXIT_OPEN ||
+ Tile[jx][jy] == EL_EM_STEEL_EXIT_OPENING ||
+ Tile[jx][jy] == EL_SP_EXIT_OPEN ||
+ Tile[jx][jy] == EL_SP_EXIT_OPENING) // <-- special case
{
ExitPlayer(player);
if (game.players_still_needed == 0 &&
(game.friends_still_needed == 0 ||
- IS_SP_ELEMENT(Feld[jx][jy])))
+ IS_SP_ELEMENT(Tile[jx][jy])))
LevelSolved();
}
+ player->last_jx = jx;
+ player->last_jy = jy;
+
// this breaks one level: "machine", level 000
{
int move_direction = player->MovDir;
int leave_side = move_direction;
int old_jx = last_jx;
int old_jy = last_jy;
- int old_element = Feld[old_jx][old_jy];
- int new_element = Feld[jx][jy];
+ int old_element = Tile[old_jx][old_jy];
+ int new_element = Tile[jx][jy];
if (IS_CUSTOM_ELEMENT(old_element))
CheckElementChangeByPlayer(old_jx, old_jy, old_element,
if (!player->is_pushing)
TestIfElementTouchesCustomElement(jx, jy); // for empty space
- if (!player->active)
- RemovePlayer(player);
- }
-
- if (!game.LevelSolved && level.use_step_counter)
- {
- int i;
-
- TimePlayed++;
-
- if (TimeLeft > 0)
+ if (level.finish_dig_collect &&
+ (player->is_digging || player->is_collecting))
{
- TimeLeft--;
-
- if (TimeLeft <= 10 && setup.time_limit)
- PlaySound(SND_GAME_RUNNING_OUT_OF_TIME);
+ int last_element = player->last_removed_element;
+ int move_direction = player->MovDir;
+ int enter_side = MV_DIR_OPPOSITE(move_direction);
+ int change_event = (player->is_digging ? CE_PLAYER_DIGS_X :
+ CE_PLAYER_COLLECTS_X);
- game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
-
- DisplayGameControlValues();
+ CheckTriggeredElementChangeByPlayer(jx, jy, last_element, change_event,
+ player->index_bit, enter_side);
- if (!TimeLeft && setup.time_limit)
- for (i = 0; i < MAX_PLAYERS; i++)
- KillPlayer(&stored_player[i]);
+ player->last_removed_element = EL_UNDEFINED;
}
- else if (game.no_time_limit && !game.all_players_gone)
- {
- game_panel_controls[GAME_PANEL_TIME].value = TimePlayed;
- DisplayGameControlValues();
- }
+ if (!player->active)
+ RemovePlayer(player);
}
+ if (level.use_step_counter)
+ CheckLevelTime_StepCounter();
+
if (tape.single_step && tape.recording && !tape.pausing &&
!player->programmed_action)
TapeTogglePause(TAPE_TOGGLE_AUTOMATIC);
void ScrollScreen(struct PlayerInfo *player, int mode)
{
- static unsigned int screen_frame_counter = 0;
+ static DelayCounter screen_frame_counter = { 0 };
if (mode == SCROLL_INIT)
{
// set scrolling step size according to actual player's moving speed
ScrollStepSize = TILEX / player->move_delay_value;
- screen_frame_counter = FrameCounter;
+ screen_frame_counter.count = FrameCounter;
+ screen_frame_counter.value = 1;
+
ScreenMovDir = player->MovDir;
ScreenMovPos = player->MovPos;
ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
return;
}
- else if (!FrameReached(&screen_frame_counter, 1))
+ else if (!FrameReached(&screen_frame_counter))
return;
if (ScreenMovPos)
ScreenMovDir = MV_NONE;
}
-void TestIfPlayerTouchesCustomElement(int x, int y)
+void CheckNextToConditions(int x, int y)
{
- static int xy[4][2] =
+ int element = Tile[x][y];
+
+ if (IS_PLAYER(x, y))
+ TestIfPlayerNextToCustomElement(x, y);
+
+ if (CAN_CHANGE_OR_HAS_ACTION(element) &&
+ HAS_ANY_CHANGE_EVENT(element, CE_NEXT_TO_X))
+ TestIfElementNextToCustomElement(x, y);
+}
+
+void TestIfPlayerNextToCustomElement(int x, int y)
+{
+ struct XY *xy = xy_topdown;
+ static int trigger_sides[4][2] =
{
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
+ // center side border side
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, // check top
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, // check left
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, // check right
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP } // check bottom
};
+ int i;
+
+ if (!IS_PLAYER(x, y))
+ return;
+
+ struct PlayerInfo *player = PLAYERINFO(x, y);
+
+ if (player->is_moving)
+ return;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+ continue; // center and border element not connected
+
+ border_element = Tile[xx][yy];
+
+ CheckElementChangeByPlayer(xx, yy, border_element, CE_NEXT_TO_PLAYER,
+ player->index_bit, border_side);
+ CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+ CE_PLAYER_NEXT_TO_X,
+ player->index_bit, border_side);
+
+ /* use player element that is initially defined in the level playfield,
+ not the player element that corresponds to the runtime player number
+ (example: a level that contains EL_PLAYER_3 as the only player would
+ incorrectly give EL_PLAYER_1 for "player->element_nr") */
+
+ CheckElementChangeBySide(xx, yy, border_element, player->initial_element,
+ CE_NEXT_TO_X, border_side);
+ }
+}
+
+void TestIfPlayerTouchesCustomElement(int x, int y)
+{
+ struct XY *xy = xy_topdown;
static int trigger_sides[4][2] =
{
// center side border side
MV_UP | MV_DOWN,
MV_LEFT | MV_RIGHT
};
- int center_element = Feld[x][y]; // should always be non-moving!
+ int center_element = Tile[x][y]; // should always be non-moving!
int i;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int center_side = trigger_sides[i][0];
int border_side = trigger_sides[i][1];
int border_element;
struct PlayerInfo *player = PLAYERINFO(x, y);
if (game.engine_version < VERSION_IDENT(3,0,7,0))
- border_element = Feld[xx][yy]; // may be moving!
+ border_element = Tile[xx][yy]; // may be moving!
else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
- border_element = Feld[xx][yy];
+ border_element = Tile[xx][yy];
else if (MovDir[xx][yy] & touch_dir[i]) // elements are touching
border_element = MovingOrBlocked2Element(xx, yy);
else
}
}
-void TestIfElementTouchesCustomElement(int x, int y)
+void TestIfElementNextToCustomElement(int x, int y)
{
- static int xy[4][2] =
+ struct XY *xy = xy_topdown;
+ static int trigger_sides[4][2] =
{
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
+ // center side border side
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, // check top
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, // check left
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, // check right
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP } // check bottom
};
+ int center_element = Tile[x][y]; // should always be non-moving!
+ int i;
+
+ if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+ return;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+ continue; // center and border element not connected
+
+ border_element = Tile[xx][yy];
+
+ // check for change of center element (but change it only once)
+ if (CheckElementChangeBySide(x, y, center_element, border_element,
+ CE_NEXT_TO_X, border_side))
+ break;
+ }
+}
+
+void TestIfElementTouchesCustomElement(int x, int y)
+{
+ struct XY *xy = xy_topdown;
static int trigger_sides[4][2] =
{
// center side border side
MV_LEFT | MV_RIGHT
};
boolean change_center_element = FALSE;
- int center_element = Feld[x][y]; // should always be non-moving!
+ int center_element = Tile[x][y]; // should always be non-moving!
int border_element_old[NUM_DIRECTIONS];
int i;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int border_element;
border_element_old[i] = -1;
continue;
if (game.engine_version < VERSION_IDENT(3,0,7,0))
- border_element = Feld[xx][yy]; // may be moving!
+ border_element = Tile[xx][yy]; // may be moving!
else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
- border_element = Feld[xx][yy];
+ border_element = Tile[xx][yy];
else if (MovDir[xx][yy] & touch_dir[i]) // elements are touching
border_element = MovingOrBlocked2Element(xx, yy);
else
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int center_side = trigger_sides[i][0];
int border_element = border_element_old[i];
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
+ int xx = x + xy[i].x;
+ int yy = y + xy[i].y;
int border_side = trigger_sides[i][1];
int border_element = border_element_old[i];
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
int hitx = x + dx, hity = y + dy;
- int hitting_element = Feld[x][y];
+ int hitting_element = Tile[x][y];
int touched_element;
if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
int i, kill_x = -1, kill_y = -1;
int bad_element = -1;
- static int test_xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *test_xy = xy_topdown;
static int test_dir[4] =
{
MV_UP,
{
int test_x, test_y, test_move_dir, test_element;
- test_x = good_x + test_xy[i][0];
- test_y = good_y + test_xy[i][1];
+ test_x = good_x + test_xy[i].x;
+ test_y = good_y + test_xy[i].y;
if (!IN_LEV_FIELD(test_x, test_y))
continue;
void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir)
{
int i, kill_x = -1, kill_y = -1;
- int bad_element = Feld[bad_x][bad_y];
- static int test_xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ int bad_element = Tile[bad_x][bad_y];
+ struct XY *test_xy = xy_topdown;
static int touch_dir[4] =
{
MV_LEFT | MV_RIGHT,
{
int test_x, test_y, test_move_dir, test_element;
- test_x = bad_x + test_xy[i][0];
- test_y = bad_y + test_xy[i][1];
+ test_x = bad_x + test_xy[i].x;
+ test_y = bad_y + test_xy[i].y;
if (!IN_LEV_FIELD(test_x, test_y))
continue;
test_move_dir =
(IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE);
- test_element = Feld[test_x][test_y];
+ test_element = Tile[test_x][test_y];
/* 1st case: good thing is moving towards DONT_RUN_INTO style bad thing;
2nd case: DONT_TOUCH style bad thing does not move away from good thing
void TestIfGoodThingGetsHitByBadThing(int bad_x, int bad_y, int bad_move_dir)
{
- int bad_element = Feld[bad_x][bad_y];
+ int bad_element = Tile[bad_x][bad_y];
int dx = (bad_move_dir == MV_LEFT ? -1 : bad_move_dir == MV_RIGHT ? +1 : 0);
int dy = (bad_move_dir == MV_UP ? -1 : bad_move_dir == MV_DOWN ? +1 : 0);
int test_x = bad_x + dx, test_y = bad_y + dy;
test_move_dir =
(IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE);
- test_element = Feld[test_x][test_y];
+ test_element = Tile[test_x][test_y];
if (test_move_dir != bad_move_dir)
{
void TestIfBadThingTouchesOtherBadThing(int bad_x, int bad_y)
{
int i, kill_x = bad_x, kill_y = bad_y;
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
+ struct XY *xy = xy_topdown;
for (i = 0; i < NUM_DIRECTIONS; i++)
{
int x, y, element;
- x = bad_x + xy[i][0];
- y = bad_y + xy[i][1];
+ x = bad_x + xy[i].x;
+ y = bad_y + xy[i].y;
if (!IN_LEV_FIELD(x, y))
continue;
- element = Feld[x][y];
+ element = Tile[x][y];
if (IS_AMOEBOID(element) || element == EL_GAME_OF_LIFE ||
element == EL_AMOEBA_GROWING || element == EL_AMOEBA_DROP)
{
return;
#if 0
- printf("::: 0: killed == %d, active == %d, reanimated == %d\n",
- player->killed, player->active, player->reanimated);
+ Debug("game:playing:KillPlayer",
+ "0: killed == %d, active == %d, reanimated == %d",
+ player->killed, player->active, player->reanimated);
#endif
/* the following code was introduced to prevent an infinite loop when calling
player->killed = TRUE;
// remove accessible field at the player's position
- Feld[jx][jy] = EL_EMPTY;
+ Tile[jx][jy] = EL_EMPTY;
// deactivate shield (else Bang()/Explode() would not work right)
player->shield_normal_time_left = 0;
player->shield_deadly_time_left = 0;
#if 0
- printf("::: 1: killed == %d, active == %d, reanimated == %d\n",
- player->killed, player->active, player->reanimated);
+ Debug("game:playing:KillPlayer",
+ "1: killed == %d, active == %d, reanimated == %d",
+ player->killed, player->active, player->reanimated);
#endif
Bang(jx, jy);
#if 0
- printf("::: 2: killed == %d, active == %d, reanimated == %d\n",
- player->killed, player->active, player->reanimated);
+ Debug("game:playing:KillPlayer",
+ "2: killed == %d, active == %d, reanimated == %d",
+ player->killed, player->active, player->reanimated);
#endif
if (player->reanimated) // killed player may have been reanimated
game.players_still_needed--;
}
-static void setFieldForSnapping(int x, int y, int element, int direction)
+static void SetFieldForSnapping(int x, int y, int element, int direction,
+ int player_index_bit)
{
struct ElementInfo *ei = &element_info[element];
int direction_bit = MV_DIR_TO_BIT(direction);
int action = (graphic_snapping != IMG_EMPTY_SPACE ? ACTION_SNAPPING :
IS_DIGGABLE(element) ? ACTION_DIGGING : ACTION_COLLECTING);
- Feld[x][y] = EL_ELEMENT_SNAPPING;
+ Tile[x][y] = EL_ELEMENT_SNAPPING;
MovDelay[x][y] = MOVE_DELAY_NORMAL_SPEED + 1 - 1;
+ MovDir[x][y] = direction;
+ Store[x][y] = element;
+ Store2[x][y] = player_index_bit;
ResetGfxAnimation(x, y);
GfxFrame[x][y] = -1;
}
+static void TestFieldAfterSnapping(int x, int y, int element, int direction,
+ int player_index_bit)
+{
+ TestIfElementTouchesCustomElement(x, y); // for empty space
+
+ if (level.finish_dig_collect)
+ {
+ int dig_side = MV_DIR_OPPOSITE(direction);
+ int change_event = (IS_DIGGABLE(element) ? CE_PLAYER_DIGS_X :
+ CE_PLAYER_COLLECTS_X);
+
+ CheckTriggeredElementChangeByPlayer(x, y, element, change_event,
+ player_index_bit, dig_side);
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
+ player_index_bit, dig_side);
+ }
+}
+
/*
=============================================================================
checkDiagonalPushing()
xx = jx + (dx == 0 ? real_dx : 0);
yy = jy + (dy == 0 ? real_dy : 0);
- return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Feld[xx][yy]));
+ return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Tile[xx][yy]));
}
/*
dy == +1 ? MV_DOWN : MV_NONE);
int opposite_direction = MV_DIR_OPPOSITE(move_direction);
int dig_side = MV_DIR_OPPOSITE(move_direction);
- int old_element = Feld[jx][jy];
+ int old_element = Tile[jx][jy];
int element = MovingOrBlocked2ElementIfNotLeaving(x, y);
int collect_count;
return MP_NO_ACTION;
}
}
-
if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
old_element = Back[jx][jy];
{
SplashAcid(x, y);
- Feld[jx][jy] = player->artwork_element;
+ Tile[jx][jy] = player->artwork_element;
InitMovingField(jx, jy, MV_DOWN);
Store[jx][jy] = EL_ACID;
ContinueMoving(jx, jy);
if (element == EL_DC_LANDMINE)
Bang(x, y);
- if (Feld[x][y] != element) // field changed by snapping
+ if (Tile[x][y] != element) // field changed by snapping
return MP_ACTION;
return MP_NO_ACTION;
PlayLevelSoundElementAction(x, y, element, ACTION_DIGGING);
- CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X,
- player->index_bit, dig_side);
+ // use old behaviour for old levels (digging)
+ if (!level.finish_dig_collect)
+ {
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_DIGS_X,
+ player->index_bit, dig_side);
+
+ // if digging triggered player relocation, finish digging tile
+ if (mode == DF_DIG && (player->jx != jx || player->jy != jy))
+ SetFieldForSnapping(x, y, element, move_direction, player->index_bit);
+ }
if (mode == DF_SNAP)
{
if (level.block_snap_field)
- setFieldForSnapping(x, y, element, move_direction);
+ SetFieldForSnapping(x, y, element, move_direction, player->index_bit);
else
- TestIfElementTouchesCustomElement(x, y); // for empty space
+ TestFieldAfterSnapping(x, y, element, move_direction, player->index_bit);
- CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
- player->index_bit, dig_side);
+ // use old behaviour for old levels (snapping)
+ if (!level.finish_dig_collect)
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
+ player->index_bit, dig_side);
}
}
else if (player_can_move_or_snap && IS_COLLECTIBLE(element))
}
else if (element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY)
{
- player->shield_normal_time_left += level.shield_normal_time;
+ int shield_time = (element == EL_SHIELD_DEADLY ?
+ level.shield_deadly_time :
+ level.shield_normal_time);
+
+ player->shield_normal_time_left += shield_time;
if (element == EL_SHIELD_DEADLY)
- player->shield_deadly_time_left += level.shield_deadly_time;
+ player->shield_deadly_time_left += shield_time;
}
else if (element == EL_DYNAMITE ||
element == EL_EM_DYNAMITE ||
}
else if (IS_ENVELOPE(element))
{
- player->show_envelope = element;
+ boolean wait_for_snapping = (mode == DF_SNAP && level.block_snap_field);
+
+ if (!wait_for_snapping)
+ player->show_envelope = element;
}
else if (element == EL_EMC_LENSES)
{
RaiseScoreElement(element);
PlayLevelSoundElementAction(x, y, element, ACTION_COLLECTING);
- if (is_player)
+ // use old behaviour for old levels (collecting)
+ if (!level.finish_dig_collect && is_player)
+ {
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_COLLECTS_X,
player->index_bit, dig_side);
+ // if collecting triggered player relocation, finish collecting tile
+ if (mode == DF_DIG && (player->jx != jx || player->jy != jy))
+ SetFieldForSnapping(x, y, element, move_direction, player->index_bit);
+ }
+
if (mode == DF_SNAP)
{
if (level.block_snap_field)
- setFieldForSnapping(x, y, element, move_direction);
+ SetFieldForSnapping(x, y, element, move_direction, player->index_bit);
else
- TestIfElementTouchesCustomElement(x, y); // for empty space
+ TestFieldAfterSnapping(x, y, element, move_direction, player->index_bit);
- CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
- player->index_bit, dig_side);
+ // use old behaviour for old levels (snapping)
+ if (!level.finish_dig_collect)
+ CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_SNAPS_X,
+ player->index_bit, dig_side);
}
}
else if (player_can_move_or_snap && IS_PUSHABLE(element))
if (!(IN_LEV_FIELD(nextx, nexty) &&
(IS_FREE(nextx, nexty) ||
(IS_SB_ELEMENT(element) &&
- Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) ||
+ Tile[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY) ||
(IS_CUSTOM_ELEMENT(element) &&
CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, nextx, nexty)))))
return MP_NO_ACTION;
IncrementSokobanObjectsNeeded();
}
- if (Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY)
+ if (Tile[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY)
{
Back[nextx][nexty] = EL_SOKOBAN_FIELD_EMPTY;
sokoban_task_solved = TRUE;
}
- Feld[x][y] = EL_SOKOBAN_OBJECT;
+ Tile[x][y] = EL_SOKOBAN_OBJECT;
if (Back[x][y] == Back[nextx][nexty])
PlayLevelSoundAction(x, y, ACTION_PUSHING);
if (sokoban_task_solved &&
game.sokoban_fields_still_needed == 0 &&
game.sokoban_objects_still_needed == 0 &&
- (game.emulation == EMU_SOKOBAN || level.auto_exit_sokoban))
+ level.auto_exit_sokoban)
{
game.players_still_needed = 0;
if (element == EL_ROBOT_WHEEL)
{
- Feld[x][y] = EL_ROBOT_WHEEL_ACTIVE;
+ Tile[x][y] = EL_ROBOT_WHEEL_ACTIVE;
game.robot_wheel_x = x;
game.robot_wheel_y = y;
SCAN_PLAYFIELD(xx, yy)
{
- if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
+ if (Tile[xx][yy] == EL_SP_DISK_YELLOW)
{
Bang(xx, yy);
}
- else if (Feld[xx][yy] == EL_SP_TERMINAL)
+ else if (Tile[xx][yy] == EL_SP_TERMINAL)
{
- Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
+ Tile[xx][yy] = EL_SP_TERMINAL_ACTIVE;
ResetGfxAnimation(xx, yy);
TEST_DrawLevelField(xx, yy);
element == EL_DC_SWITCHGATE_SWITCH_UP ||
element == EL_DC_SWITCHGATE_SWITCH_DOWN)
{
- ToggleSwitchgateSwitch(x, y);
+ ToggleSwitchgateSwitch();
}
else if (element == EL_LIGHT_SWITCH ||
element == EL_LIGHT_SWITCH_ACTIVE)
}
else if (element == EL_LAMP)
{
- Feld[x][y] = EL_LAMP_ACTIVE;
+ Tile[x][y] = EL_LAMP_ACTIVE;
game.lights_still_needed--;
ResetGfxAnimation(x, y);
}
else if (element == EL_TIME_ORB_FULL)
{
- Feld[x][y] = EL_TIME_ORB_EMPTY;
+ Tile[x][y] = EL_TIME_ORB_EMPTY;
if (level.time > 0 || level.use_time_orb_bug)
{
TimeLeft += level.time_orb_time;
- game.no_time_limit = FALSE;
+ game.no_level_time_limit = FALSE;
game_panel_controls[GAME_PANEL_TIME].value = TimeLeft;
SCAN_PLAYFIELD(xx, yy)
{
- int e = Feld[xx][yy];
+ int e = Tile[xx][yy];
if (game.ball_active)
{
if (is_player) // function can also be called by EL_PENGUIN
{
- if (Feld[x][y] != element) // really digged/collected something
+ if (Tile[x][y] != element) // really digged/collected something
{
player->is_collecting = !player->is_digging;
player->is_active = TRUE;
+
+ player->last_removed_element = element;
}
}
static boolean DigFieldByCE(int x, int y, int digging_element)
{
- int element = Feld[x][y];
+ int element = Tile[x][y];
if (!IS_FREE(x, y))
{
pressed without moving, dropped element must move away before the next
element can be dropped (this is especially important if the next element
is dynamite, which can be placed on background for historical reasons) */
- if (PLAYER_DROPPING(player, dropx, dropy) && Feld[dropx][dropy] != EL_EMPTY)
+ if (PLAYER_DROPPING(player, dropx, dropy) && Tile[dropx][dropy] != EL_EMPTY)
return MP_ACTION;
if (IS_THROWABLE(drop_element))
return FALSE;
}
- old_element = Feld[dropx][dropy]; // old element at dropping position
+ old_element = Tile[dropx][dropy]; // old element at dropping position
new_element = drop_element; // default: no change when dropping
// check if player is active, not moving and ready to drop
new_element = EL_SP_DISK_RED_ACTIVE;
}
- Feld[dropx][dropy] = new_element;
+ Tile[dropx][dropy] = new_element;
if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
- el2img(Feld[dropx][dropy]), 0);
+ el2img(Tile[dropx][dropy]), 0);
PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
{
player->dynabombs_left--;
- Feld[dropx][dropy] = new_element;
+ Tile[dropx][dropy] = new_element;
if (IN_SCR_FIELD(SCREENX(dropx), SCREENY(dropy)))
DrawGraphicThruMask(SCREENX(dropx), SCREENY(dropy),
- el2img(Feld[dropx][dropy]), 0);
+ el2img(Tile[dropx][dropy]), 0);
PlayLevelSoundAction(dropx, dropy, ACTION_DROPPING);
}
- if (Feld[dropx][dropy] == new_element) // uninitialized unless CE change
+ if (Tile[dropx][dropy] == new_element) // uninitialized unless CE change
InitField_WithBug1(dropx, dropy, FALSE);
- new_element = Feld[dropx][dropy]; // element might have changed
+ new_element = Tile[dropx][dropy]; // element might have changed
if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) &&
element_info[new_element].move_pattern == MV_WHEN_DROPPED)
static void PlayLevelSoundAction(int x, int y, int action)
{
- PlayLevelSoundElementAction(x, y, Feld[x][y], action);
+ PlayLevelSoundElementAction(x, y, Tile[x][y], action);
}
static void PlayLevelSoundElementAction(int x, int y, int element, int action)
static void PlayLevelSoundActionIfLoop(int x, int y, int action)
{
- int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
+ int sound_effect = element_info[SND_ELEMENT(Tile[x][y])].sound[action];
if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
PlayLevelSound(x, y, sound_effect);
static void StopLevelSoundActionIfLoop(int x, int y, int action)
{
- int sound_effect = element_info[SND_ELEMENT(Feld[x][y])].sound[action];
+ int sound_effect = element_info[SND_ELEMENT(Tile[x][y])].sound[action];
if (sound_effect != SND_UNDEFINED && IS_LOOP_SOUND(sound_effect))
StopSound(sound_effect);
{
if (skip_request || Request(message, REQ_ASK | REQ_STAY_CLOSED))
{
- // closing door required in case of envelope style request dialogs
- if (!skip_request)
+ if (!quick_quit)
{
// prevent short reactivation of overlay buttons while closing door
SetOverlayActive(FALSE);
+ UnmapGameButtons();
- CloseDoor(DOOR_CLOSE_1);
+ // door may still be open due to skipped or envelope style request
+ CloseDoor(score_info_tape_play ? DOOR_CLOSE_ALL : DOOR_CLOSE_1);
}
if (network.enabled)
}
}
-void RequestQuitGame(boolean ask_if_really_quit)
+void RequestQuitGame(boolean escape_key_pressed)
{
- boolean quick_quit = (!ask_if_really_quit || level_editor_test_game);
- boolean skip_request = game.all_players_gone || quick_quit;
+ boolean ask_on_escape = (setup.ask_on_escape && setup.ask_on_quit_game);
+ boolean quick_quit = ((escape_key_pressed && !ask_on_escape) ||
+ level_editor_test_game);
+ boolean skip_request = (game.all_players_gone || !setup.ask_on_quit_game ||
+ quick_quit || score_info_tape_play);
RequestQuitGameExt(skip_request, quick_quit,
"Do you really want to quit the game?");
}
else
{
+ // needed in case of envelope request to close game panel
+ CloseDoor(DOOR_CLOSE_1);
+
SetGameStatus(GAME_MODE_MAIN);
DrawMainMenu();
if (game.num_random_calls != num_random_calls)
{
- Error(ERR_INFO, "number of random calls out of sync");
- Error(ERR_INFO, "number of random calls should be %d", num_random_calls);
- Error(ERR_INFO, "number of random calls is %d", game.num_random_calls);
- Error(ERR_EXIT, "this should not happen -- please debug");
+ Error("number of random calls out of sync");
+ Error("number of random calls should be %d", num_random_calls);
+ Error("number of random calls is %d", game.num_random_calls);
+
+ Fail("this should not happen -- please debug");
}
}
if (level.game_engine_type == GAME_ENGINE_TYPE_SP)
SaveEngineSnapshotValues_SP(&buffers);
if (level.game_engine_type == GAME_ENGINE_TYPE_MM)
- SaveEngineSnapshotValues_MM(&buffers);
+ SaveEngineSnapshotValues_MM();
// save values stored in special snapshot structure
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(AmoebaCnt2));
- SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Feld));
+ SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(Tile));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovPos));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDir));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(MovDelay));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxFrame));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandom));
+ SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxRandomStatic));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxElement));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxAction));
SaveSnapshotBuffer(&buffers, ARGS_ADDRESS_AND_SIZEOF(GfxDir));
node = node->next;
}
- printf("::: size of engine snapshot: %d bytes\n", num_bytes);
+ Debug("game:playing:SaveEngineSnapshotBuffers",
+ "size of engine snapshot: %d bytes", num_bytes);
#endif
return buffers;
int y = (is_touch_button ? pos->y : GDI_ACTIVE_POS(pos->y));
int id = i;
+ // do not use touch buttons if overlay touch buttons are disabled
+ if (is_touch_button && !setup.touch.overlay_buttons)
+ continue;
+
if (gfx->bitmap == NULL)
{
game_gadget[id] = NULL;
GDI_END);
if (gi == NULL)
- Error(ERR_EXIT, "cannot create gadget");
+ Fail("cannot create gadget");
game_gadget[id] = gi;
}
static void UnmapGameButtonsAtSamePosition_All(void)
{
- if (setup.show_snapshot_buttons)
+ if (setup.show_load_save_buttons)
{
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_SAVE);
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE2);
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_LOAD);
}
+ else if (setup.show_undo_redo_buttons)
+ {
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_PAUSE2);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO);
+ }
else
{
UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_STOP);
}
}
-static void MapGameButtonsAtSamePosition(int id)
+void MapLoadSaveButtons(void)
{
- int i;
-
- for (i = 0; i < NUM_GAME_BUTTONS; i++)
- if (i != id &&
- gamebutton_info[i].pos->x == gamebutton_info[id].pos->x &&
- gamebutton_info[i].pos->y == gamebutton_info[id].pos->y)
- MapGadget(game_gadget[i]);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_LOAD);
+ UnmapGameButtonsAtSamePosition(GAME_CTRL_ID_SAVE);
- UnmapGameButtonsAtSamePosition_All();
+ MapGadget(game_gadget[GAME_CTRL_ID_LOAD]);
+ MapGadget(game_gadget[GAME_CTRL_ID_SAVE]);
}
void MapUndoRedoButtons(void)
MapGadget(game_gadget[GAME_CTRL_ID_REDO]);
}
-void UnmapUndoRedoButtons(void)
-{
- UnmapGadget(game_gadget[GAME_CTRL_ID_UNDO]);
- UnmapGadget(game_gadget[GAME_CTRL_ID_REDO]);
-
- MapGameButtonsAtSamePosition(GAME_CTRL_ID_UNDO);
- MapGameButtonsAtSamePosition(GAME_CTRL_ID_REDO);
-}
-
void ModifyPauseButtons(void)
{
static int ids[] =
int i;
for (i = 0; i < NUM_GAME_BUTTONS; i++)
- if ((!on_tape || gamebutton_info[i].allowed_on_tape) &&
- i != GAME_CTRL_ID_UNDO &&
- i != GAME_CTRL_ID_REDO)
+ {
+ if ((i == GAME_CTRL_ID_UNDO ||
+ i == GAME_CTRL_ID_REDO) &&
+ game_status != GAME_MODE_PLAYING)
+ continue;
+
+ if (!on_tape || gamebutton_info[i].allowed_on_tape)
MapGadget(game_gadget[i]);
+ }
UnmapGameButtonsAtSamePosition_All();
DrawVideoDisplay(VIDEO_STATE_FRAME_ON, FrameCounter);
DrawVideoDisplay(VIDEO_STATE_1STEP(tape.single_step), 0);
+ ModifyPauseButtons();
+
BackToFront();
}
if (!CheckEngineSnapshotList())
return;
+ int tape_property_bits = tape.property_bits;
+
LoadEngineSnapshot_Undo(steps);
+ tape.property_bits |= tape_property_bits | TAPE_PROPERTY_SNAPSHOT;
+
GameUndoRedoExt();
}
if (!CheckEngineSnapshotList())
return;
+ int tape_property_bits = tape.property_bits;
+
LoadEngineSnapshot_Redo(steps);
+ tape.property_bits |= tape_property_bits | TAPE_PROPERTY_SNAPSHOT;
+
GameUndoRedoExt();
}
case GAME_CTRL_ID_STOP:
case GAME_CTRL_ID_PANEL_STOP:
case GAME_CTRL_ID_TOUCH_STOP:
- if (game_status == GAME_MODE_MAIN)
- break;
-
- if (tape.playing)
- TapeStop();
- else
- RequestQuitGame(TRUE);
+ TapeStopGame();
break;