#define USE_NEW_PLAYER_SPEED (USE_NEW_STUFF * 1)
#define USE_NEW_DELAYED_ACTION (USE_NEW_STUFF * 1)
#define USE_NEW_SNAP_DELAY (USE_NEW_STUFF * 1)
-#define USE_ONLY_ONE_CHANGE_PER_FRAME (USE_NEW_STUFF * 0)
+#define USE_ONLY_ONE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1)
+#define USE_ONE_MORE_CHANGE_PER_FRAME (USE_NEW_STUFF * 1)
+#define USE_FIXED_DONT_RUN_INTO (USE_NEW_STUFF * 1)
+#define USE_NEW_SPRING_BUMPER (USE_NEW_STUFF * 1)
+#define USE_STOP_CHANGED_ELEMENTS (USE_NEW_STUFF * 1)
+#define USE_ELEMENT_TOUCHING_BUGFIX (USE_NEW_STUFF * 1)
+
#define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0)
/* for DigField() */
#define DF_SNAP 2
/* for MovePlayer() */
-#define MF_NO_ACTION 0
-#define MF_MOVING 1
-#define MF_ACTION 2
+#define MP_NO_ACTION 0
+#define MP_MOVING 1
+#define MP_ACTION 2
+#define MP_DONT_RUN_INTO (MP_MOVING | MP_ACTION)
/* for ScrollPlayer() */
#define SCROLL_INIT 0
#define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \
RND((c)->delay_random))
+#if 1
+#define GET_VALID_RUNTIME_ELEMENT(e) \
+ ((e) >= NUM_RUNTIME_ELEMENTS ? EL_UNKNOWN : (e))
+#else
+#define GET_VALID_FILE_ELEMENT(e) \
+ ((e) >= NUM_FILE_ELEMENTS ? EL_UNKNOWN : (e))
+#endif
+
#define GET_TARGET_ELEMENT(e, ch) \
- ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
- (e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : (e))
+ ((e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : \
+ (e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
+ (e) == EL_TRIGGER_CE_VALUE ? (ch)->actual_trigger_ce_value : (e))
#define CAN_GROW_INTO(e) \
((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
#define SATELLITE_CAN_ENTER_FIELD(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)
+
+#define ANDROID_CAN_CLONE_FIELD(x, y) \
+ (IN_LEV_FIELD(x, y) && (CAN_BE_CLONED_BY_ANDROID(Feld[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 SPRING_CAN_ENTER_FIELD(e, x, y) \
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))
+
+#if 0
#define GROUP_NR(e) ((e) - EL_GROUP_START)
-#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE)
#define IS_IN_GROUP_EL(e, ge) (IS_IN_GROUP(e, (ge) - EL_GROUP_START))
#define IS_EQUAL_OR_IN_GROUP(e, ge) \
(IS_GROUP_ELEMENT(ge) ? IS_IN_GROUP(e, GROUP_NR(ge)) : (e) == (ge))
+#endif
+
+#define MOVE_ENTER_EL(e) (element_info[e].move_enter_element)
#define CE_ENTER_FIELD_COND(e, x, y) \
(!IS_PLAYER(x, y) && \
/* forward declaration for internal use */
+static void CreateField(int, int, int);
+
static void SetPlayerWaiting(struct PlayerInfo *, boolean);
static void AdvanceFrameAndPlayerCounters(int);
static void TestIfElementSmashesCustomElement(int, int, int);
#endif
-static void ChangeElement(int, int, int);
+static void HandleElementChange(int, int, int);
+static void ExecuteCustomElementAction(int, int, int, int);
+static boolean ChangeElement(int, int, int, int);
static boolean CheckTriggeredElementChangeExt(int, int, int, int, int,int,int);
#define CheckTriggeredElementChange(x, y, e, ev) \
/* ------------------------------------------------------------------------- */
/* forward declaration for changer functions */
-static void InitBuggyBase(int x, int y);
-static void WarnBuggyBase(int x, int y);
+static void InitBuggyBase(int, int);
+static void WarnBuggyBase(int, int);
+
+static void InitTrap(int, int);
+static void ActivateTrap(int, int);
+static void ChangeActiveTrap(int, int);
+
+static void InitRobotWheel(int, int);
+static void RunRobotWheel(int, int);
+static void StopRobotWheel(int, int);
-static void InitTrap(int x, int y);
-static void ActivateTrap(int x, int y);
-static void ChangeActiveTrap(int x, int y);
+static void InitTimegateWheel(int, int);
+static void RunTimegateWheel(int, int);
-static void InitRobotWheel(int x, int y);
-static void RunRobotWheel(int x, int y);
-static void StopRobotWheel(int x, int y);
+static void InitMagicBallDelay(int, int);
+static void ActivateMagicBall(int, int);
-static void InitTimegateWheel(int x, int y);
-static void RunTimegateWheel(int x, int y);
+static void InitDiagonalMovingElement(int, int);
struct ChangingElementInfo
{
RunTimegateWheel,
NULL
},
+ {
+ EL_EMC_MAGIC_BALL_ACTIVE,
+ EL_EMC_MAGIC_BALL_ACTIVE,
+ 0,
+ InitMagicBallDelay,
+ NULL,
+ ActivateMagicBall
+ },
+ {
+ EL_EMC_SPRING_BUMPER_ACTIVE,
+ EL_EMC_SPRING_BUMPER,
+ 8,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_DIAGONAL_SHRINKING,
+ EL_UNDEFINED,
+ 0,
+ NULL,
+ NULL,
+ NULL
+ },
+ {
+ EL_DIAGONAL_GROWING,
+ EL_UNDEFINED,
+ 0,
+ NULL,
+ NULL,
+ InitDiagonalMovingElement
+ },
{
EL_UNDEFINED,
#define CE_PAGE(e, ce) (element_info[e].event_page[ce])
+/* static variables for playfield scan mode (scanning forward or backward) */
+static int playfield_scan_start_x = 0;
+static int playfield_scan_start_y = 0;
+static int playfield_scan_delta_x = 1;
+static int playfield_scan_delta_y = 1;
+
+#define SCAN_PLAYFIELD(x, y) for ((y) = playfield_scan_start_y; \
+ (y) >= 0 && (y) <= lev_fieldy - 1; \
+ (y) += playfield_scan_delta_y) \
+ for ((x) = playfield_scan_start_x; \
+ (x) >= 0 && (x) <= lev_fieldx - 1; \
+ (x) += playfield_scan_delta_x) \
+
+static void InitPlayfieldScanModeVars()
+{
+ if (game.use_reverse_scan_direction)
+ {
+ playfield_scan_start_x = lev_fieldx - 1;
+ playfield_scan_start_y = lev_fieldy - 1;
+
+ playfield_scan_delta_x = -1;
+ playfield_scan_delta_y = -1;
+ }
+ else
+ {
+ playfield_scan_start_x = 0;
+ playfield_scan_start_y = 0;
+
+ playfield_scan_delta_x = 1;
+ playfield_scan_delta_y = 1;
+ }
+}
+
+static void InitPlayfieldScanMode(int mode)
+{
+ game.use_reverse_scan_direction =
+ (mode == CA_ARG_SCAN_MODE_REVERSE ? TRUE : FALSE);
+
+ InitPlayfieldScanModeVars();
+}
+
+static int get_move_delay_from_stepsize(int move_stepsize)
+{
+ move_stepsize =
+ MIN(MAX(MOVE_STEPSIZE_MIN, move_stepsize), MOVE_STEPSIZE_MAX);
+
+ /* make sure that stepsize value is always a power of 2 */
+ move_stepsize = (1 << log_2(move_stepsize));
+
+ return TILEX / move_stepsize;
+}
+
+static void SetPlayerMoveSpeed(struct PlayerInfo *player, int move_stepsize,
+ boolean init_game)
+{
+ int move_delay = get_move_delay_from_stepsize(move_stepsize);
+ boolean cannot_move = (move_stepsize == STEPSIZE_NOT_MOVING ? TRUE : FALSE);
+
+ /* do no immediately change move delay -- the player might just be moving */
+ player->move_delay_value_next = move_delay;
+
+ /* information if player can move must be set separately */
+ player->cannot_move = cannot_move;
+
+ if (init_game)
+ {
+ player->move_delay = game.initial_move_delay;
+ player->move_delay_value = game.initial_move_delay_value;
+
+ player->move_delay_value_next = -1;
+
+ player->move_delay_reset_counter = 0;
+ }
+}
void GetPlayerConfig()
{
game.light_time_left = level.time_light * FRAMES_PER_SECOND;
break;
+ case EL_EMC_MAGIC_BALL:
+ if (game.ball_state)
+ Feld[x][y] = EL_EMC_MAGIC_BALL_ACTIVE;
+ break;
+
+ case EL_EMC_MAGIC_BALL_SWITCH:
+ if (game.ball_state)
+ Feld[x][y] = EL_EMC_MAGIC_BALL_SWITCH_ACTIVE;
+ break;
+
default:
#if 1
if (IS_CUSTOM_ELEMENT(element))
break;
}
+#if 1
+ if (!init_game)
+ CheckTriggeredElementChange(x, y, element, CE_CREATION_OF_X);
+#endif
+
#if 0
#if USE_NEW_CUSTOM_VALUE
DrawGameValue_Keys(stored_player[i].key);
}
+#if 0
static void resolve_group_element(int group_element, int recursion_depth)
{
static int group_nr;
}
}
}
-
+#endif
/*
=============================================================================
/* ---------------------------------------------------------------------- */
+ /* default scan direction: scan playfield from top/left to bottom/right */
+ InitPlayfieldScanMode(CA_ARG_SCAN_MODE_NORMAL);
+
/* dynamically adjust element properties according to game engine version */
InitElementPropertiesEngine(game.engine_version);
printf(" => game.engine_version == %06d\n", game.engine_version);
#endif
+#if 0
/* ---------- recursively resolve group elements ------------------------- */
for (i = 0; i < MAX_NUM_ELEMENTS; i++)
for (i = 0; i < NUM_GROUP_ELEMENTS; i++)
resolve_group_element(EL_GROUP_START + i, 0);
+#endif
/* ---------- initialize player's initial move delay --------------------- */
+#if 1
+ /* dynamically adjust player properties according to level information */
+ game.initial_move_delay_value =
+ get_move_delay_from_stepsize(level.initial_player_stepsize);
+#else
/* dynamically adjust player properties according to level information */
game.initial_move_delay_value =
(level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED);
+#endif
/* dynamically adjust player properties according to game engine version */
game.initial_move_delay = (game.engine_version <= VERSION_IDENT(2,0,1,0) ?
player->is_bored = FALSE;
player->is_sleeping = FALSE;
- player->cannot_move = FALSE;
-
player->frame_counter_bored = -1;
player->frame_counter_sleeping = -1;
player->show_envelope = 0;
+#if 1
+ SetPlayerMoveSpeed(player, level.initial_player_stepsize, TRUE);
+#else
player->move_delay = game.initial_move_delay;
player->move_delay_value = game.initial_move_delay_value;
player->move_delay_reset_counter = 0;
+ player->cannot_move = FALSE;
+#endif
+
player->push_delay = -1; /* initialized when pushing starts */
player->push_delay_value = game.initial_push_delay_value;
game.lenses_time_left = 0;
game.magnify_time_left = 0;
+ game.ball_state = level.ball_state_initial;
+ game.ball_content_nr = 0;
+
game.envelope_active = FALSE;
for (i = 0; i < NUM_BELTS; i++)
for (i = 0; i < MAX_NUM_AMOEBA; i++)
AmoebaCnt[i] = AmoebaCnt2[i] = 0;
- for (x = 0; x < lev_fieldx; x++)
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (x = 0; x < lev_fieldx; x++) for (y = 0; y < lev_fieldy; y++)
+#endif
{
- for (y = 0; y < lev_fieldy; y++)
- {
- Feld[x][y] = level.field[x][y];
- MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
- ChangeDelay[x][y] = 0;
- ChangePage[x][y] = -1;
+ Feld[x][y] = level.field[x][y];
+ MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
+ ChangeDelay[x][y] = 0;
+ ChangePage[x][y] = -1;
#if USE_NEW_CUSTOM_VALUE
- CustomValue[x][y] = 0; /* initialized in InitField() */
+ CustomValue[x][y] = 0; /* initialized in InitField() */
#endif
- Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
- AmoebaNr[x][y] = 0;
- WasJustMoving[x][y] = 0;
- WasJustFalling[x][y] = 0;
- CheckCollision[x][y] = 0;
- Stop[x][y] = FALSE;
- Pushed[x][y] = FALSE;
+ Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
+ AmoebaNr[x][y] = 0;
+ WasJustMoving[x][y] = 0;
+ WasJustFalling[x][y] = 0;
+ CheckCollision[x][y] = 0;
+ Stop[x][y] = FALSE;
+ Pushed[x][y] = FALSE;
- ChangeCount[x][y] = 0;
- ChangeEvent[x][y] = -1;
+ ChangeCount[x][y] = 0;
+ ChangeEvent[x][y] = -1;
- ExplodePhase[x][y] = 0;
- ExplodeDelay[x][y] = 0;
- ExplodeField[x][y] = EX_TYPE_NONE;
+ ExplodePhase[x][y] = 0;
+ ExplodeDelay[x][y] = 0;
+ ExplodeField[x][y] = EX_TYPE_NONE;
- RunnerVisit[x][y] = 0;
- PlayerVisit[x][y] = 0;
+ RunnerVisit[x][y] = 0;
+ PlayerVisit[x][y] = 0;
- GfxFrame[x][y] = 0;
- GfxRandom[x][y] = INIT_GFX_RANDOM();
- GfxElement[x][y] = EL_UNDEFINED;
- GfxAction[x][y] = ACTION_DEFAULT;
- GfxDir[x][y] = MV_NONE;
- }
+ GfxFrame[x][y] = 0;
+ GfxRandom[x][y] = INIT_GFX_RANDOM();
+ GfxElement[x][y] = EL_UNDEFINED;
+ GfxAction[x][y] = ACTION_DEFAULT;
+ GfxDir[x][y] = MV_NONE;
}
- for (y = 0; y < lev_fieldy; y++)
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
- for (x = 0; x < lev_fieldx; x++)
- {
- if (emulate_bd && !IS_BD_ELEMENT(Feld[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]))
- emulate_sp = FALSE;
+ if (emulate_bd && !IS_BD_ELEMENT(Feld[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]))
+ emulate_sp = FALSE;
- InitField(x, y, TRUE);
- }
+ InitField(x, y, TRUE);
}
InitBeltMovement();
int found_element = EL_UNDEFINED;
int player_nr = local_player->index_nr;
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
int element = Feld[x][y];
int content;
static void ResetGfxAnimation(int x, int y)
{
+#if 0
+ int element, graphic;
+#endif
+
GfxFrame[x][y] = 0;
GfxAction[x][y] = ACTION_DEFAULT;
GfxDir[x][y] = MovDir[x][y];
+
+#if 0
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
void InitMovingField(int x, int y, int direction)
{
int element = Feld[x][y];
+#if 0
+ int graphic;
+#endif
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;
GfxAction[x][y] = (direction == MV_DOWN && CAN_FALL(element) ?
ACTION_FALLING : ACTION_MOVING);
+#if 0
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
+
/* this is needed for CEs with property "can move" / "not moving" */
if (getElementMoveStepsize(x, y) != 0) /* moving or being moved */
void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
{
int direction = MovDir[x][y];
+#if 1
+ int newx = x + (direction & MV_LEFT ? -1 : direction & MV_RIGHT ? +1 : 0);
+ int newy = y + (direction & MV_UP ? -1 : direction & MV_DOWN ? +1 : 0);
+#else
int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
+#endif
*goes_to_x = newx;
*goes_to_y = newy;
if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */
{
int center_element = Feld[ex][ey];
- int artwork_element = center_element; /* for custom player artwork */
- int explosion_element = center_element; /* for custom player artwork */
-
- if (IS_PLAYER(ex, ey))
- {
- int player_nr = GET_PLAYER_NR(StorePlayer[ex][ey]);
-
- artwork_element = stored_player[player_nr].artwork_element;
-
- if (level.use_explosion_element[player_nr])
- {
- explosion_element = level.explosion_element[player_nr];
- artwork_element = explosion_element;
- }
- }
+ int artwork_element, explosion_element; /* set these values later */
#if 0
/* --- This is only really needed (and now handled) in "Impact()". --- */
return;
#endif
+#if 0
+ /* !!! at this place, the center element may be EL_BLOCKED !!! */
if (mode == EX_TYPE_NORMAL ||
mode == EX_TYPE_CENTER ||
mode == EX_TYPE_CROSS)
PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING);
+#endif
/* remove things displayed in background while burning dynamite */
if (Back[ex][ey] != EL_EMPTY && !IS_INDESTRUCTIBLE(Back[ex][ey]))
Feld[ex][ey] = center_element;
}
+ /* now "center_element" is finally determined -- set related values now */
+ artwork_element = center_element; /* for custom player artwork */
+ explosion_element = center_element; /* for custom player artwork */
+
+ if (IS_PLAYER(ex, ey))
+ {
+ int player_nr = GET_PLAYER_NR(StorePlayer[ex][ey]);
+
+ artwork_element = stored_player[player_nr].artwork_element;
+
+ if (level.use_explosion_element[player_nr])
+ {
+ explosion_element = level.explosion_element[player_nr];
+ artwork_element = explosion_element;
+ }
+ }
+
+#if 1
+ if (mode == EX_TYPE_NORMAL ||
+ mode == EX_TYPE_CENTER ||
+ mode == EX_TYPE_CROSS)
+ PlayLevelSoundElementAction(ex, ey, artwork_element, ACTION_EXPLODING);
+#endif
+
+#if 1
last_phase = element_info[explosion_element].explosion_delay + 1;
+#else
+ last_phase = element_info[center_element].explosion_delay + 1;
+#endif
for (y = ey - 1; y <= ey + 1; y++) for (x = ex - 1; x <= ex + 1; x++)
{
if (IS_PLAYER(ex, ey) && !PLAYER_EXPLOSION_PROTECTED(ex, ey))
{
+#if 1
int player_nr = StorePlayer[ex][ey] - EL_PLAYER_1;
Store[x][y] = EL_PLAYER_IS_EXPLODING_1 + player_nr;
-
-#if 0
+#else
switch(StorePlayer[ex][ey])
{
case EL_PLAYER_2:
Store[x][y] = EL_EMPTY;
}
#if 1
+ /* !!! 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))
+ Store[x][y] = EL_EMPTY;
else if (center_element == EL_YAMYAM)
Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
else if (element_info[center_element].content.e[xx][yy] != EL_EMPTY)
if (element >= EL_PLAYER_IS_EXPLODING_1 &&
element <= EL_PLAYER_IS_EXPLODING_4)
{
- static int player_death_elements[] =
- {
- EL_EMERALD_YELLOW,
- EL_EMERALD_RED,
- EL_EMERALD,
- EL_EMERALD_PURPLE
- };
int player_nr = element - EL_PLAYER_IS_EXPLODING_1;
- int player_death_element = player_death_elements[player_nr];
+ int explosion_element = EL_PLAYER_1 + player_nr;
+ int xx = MIN(MAX(0, x - stored_player[player_nr].jx + 1), 2);
+ int yy = MIN(MAX(0, y - stored_player[player_nr].jy + 1), 2);
if (level.use_explosion_element[player_nr])
- {
- int explosion_element = level.explosion_element[player_nr];
- int xx = MIN(MAX(0, x - stored_player[player_nr].jx + 1), 2);
- int yy = MIN(MAX(0, y - stored_player[player_nr].jy + 1), 2);
-
- player_death_element =
- element_info[explosion_element].content.e[xx][yy];
- }
+ explosion_element = level.explosion_element[player_nr];
Feld[x][y] = (stored_player[player_nr].active ? EL_EMPTY :
- player_death_element);
+ element_info[explosion_element].content.e[xx][yy]);
}
/* restore probably existing indestructible background element */
}
}
- for (y = 0; y < lev_fieldy; y++)
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
- for (x = 0; x < lev_fieldx; x++)
- {
- int element = Feld[x][y];
+ int element = Feld[x][y];
- for (i = 0; i < NUM_BELTS; i++)
+ for (i = 0; i < NUM_BELTS; i++)
+ {
+ if (IS_BELT(element) && game.belt_dir[i] != MV_NONE)
{
- if (IS_BELT(element) && game.belt_dir[i] != MV_NONE)
- {
- int e_belt_nr = getBeltNrFromBeltElement(element);
- int belt_nr = i;
+ int e_belt_nr = getBeltNrFromBeltElement(element);
+ int belt_nr = i;
- if (e_belt_nr == belt_nr)
- {
- int belt_part = Feld[x][y] - belt_base_element[belt_nr];
+ if (e_belt_nr == belt_nr)
+ {
+ int belt_part = Feld[x][y] - belt_base_element[belt_nr];
- Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
- }
+ Feld[x][y] = belt_base_active_element[belt_nr] + belt_part;
}
}
}
graphic_info[graphic].anim_mode |= ANIM_REVERSE;
}
- for (yy = 0; yy < lev_fieldy; yy++)
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
{
- for (xx = 0; xx < lev_fieldx; xx++)
+ int element = Feld[xx][yy];
+
+ if (IS_BELT_SWITCH(element))
{
- int element = Feld[xx][yy];
+ int e_belt_nr = getBeltNrFromBeltSwitchElement(element);
- if (IS_BELT_SWITCH(element))
+ if (e_belt_nr == belt_nr)
{
- int e_belt_nr = getBeltNrFromBeltSwitchElement(element);
-
- if (e_belt_nr == belt_nr)
- {
- Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
- DrawLevelField(xx, yy);
- }
+ Feld[xx][yy] = belt_base_switch_element[belt_nr] + belt_dir_nr;
+ DrawLevelField(xx, yy);
}
- else if (IS_BELT(element) && belt_dir != MV_NONE)
- {
- int e_belt_nr = getBeltNrFromBeltElement(element);
+ }
+ else if (IS_BELT(element) && belt_dir != MV_NONE)
+ {
+ int e_belt_nr = getBeltNrFromBeltElement(element);
- if (e_belt_nr == belt_nr)
- {
- int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
+ if (e_belt_nr == belt_nr)
+ {
+ int belt_part = Feld[xx][yy] - belt_base_element[belt_nr];
- Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
- DrawLevelField(xx, yy);
- }
+ Feld[xx][yy] = belt_base_active_element[belt_nr] + belt_part;
+ DrawLevelField(xx, yy);
}
- else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE)
- {
- int e_belt_nr = getBeltNrFromBeltActiveElement(element);
+ }
+ else if (IS_BELT_ACTIVE(element) && belt_dir == MV_NONE)
+ {
+ int e_belt_nr = getBeltNrFromBeltActiveElement(element);
- if (e_belt_nr == belt_nr)
- {
- int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
+ if (e_belt_nr == belt_nr)
+ {
+ int belt_part = Feld[xx][yy] - belt_base_active_element[belt_nr];
- Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
- DrawLevelField(xx, yy);
- }
+ Feld[xx][yy] = belt_base_element[belt_nr] + belt_part;
+ DrawLevelField(xx, yy);
}
}
}
game.switchgate_pos = !game.switchgate_pos;
- for (yy = 0; yy < lev_fieldy; yy++)
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
{
- for (xx = 0; xx < lev_fieldx; xx++)
- {
- int element = Feld[xx][yy];
+ int element = Feld[xx][yy];
- if (element == EL_SWITCHGATE_SWITCH_UP ||
- element == EL_SWITCHGATE_SWITCH_DOWN)
- {
- Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
- DrawLevelField(xx, yy);
- }
- else if (element == EL_SWITCHGATE_OPEN ||
- element == EL_SWITCHGATE_OPENING)
- {
- Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
+ if (element == EL_SWITCHGATE_SWITCH_UP ||
+ element == EL_SWITCHGATE_SWITCH_DOWN)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_SWITCH_UP + game.switchgate_pos;
+ DrawLevelField(xx, yy);
+ }
+ else if (element == EL_SWITCHGATE_OPEN ||
+ element == EL_SWITCHGATE_OPENING)
+ {
+ Feld[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;
+ PlayLevelSoundAction(xx, yy, ACTION_CLOSING);
+ }
+ else if (element == EL_SWITCHGATE_CLOSED ||
+ element == EL_SWITCHGATE_CLOSING)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_OPENING;
- PlayLevelSoundAction(xx, yy, ACTION_OPENING);
- }
+ PlayLevelSoundAction(xx, yy, ACTION_OPENING);
}
}
}
{
int x, y;
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
int element = Feld[x][y];
{
int x, y;
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
int element = Feld[x][y];
{
int x, y;
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
int element = Feld[x][y];
game.timegate_time_left = level.time_timegate * FRAMES_PER_SECOND;
- for (yy = 0; yy < lev_fieldy; yy++)
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
{
- for (xx = 0; xx < lev_fieldx; xx++)
- {
- int element = Feld[xx][yy];
-
- if (element == EL_TIMEGATE_CLOSED ||
- element == EL_TIMEGATE_CLOSING)
- {
- Feld[xx][yy] = EL_TIMEGATE_OPENING;
- PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING);
- }
+ int element = Feld[xx][yy];
- /*
- else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
- {
- Feld[xx][yy] = EL_TIMEGATE_SWITCH;
- DrawLevelField(xx, yy);
- }
- */
+ if (element == EL_TIMEGATE_CLOSED ||
+ element == EL_TIMEGATE_CLOSING)
+ {
+ Feld[xx][yy] = EL_TIMEGATE_OPENING;
+ PlayLevelSound(xx, yy, SND_TIMEGATE_OPENING);
+ }
+ /*
+ else if (element == EL_TIMEGATE_SWITCH_ACTIVE)
+ {
+ Feld[xx][yy] = EL_TIMEGATE_SWITCH;
+ DrawLevelField(xx, yy);
}
+ */
+
}
Feld[x][y] = EL_TIMEGATE_SWITCH_ACTIVE;
EL_BD_MAGIC_WALL_ACTIVE);
/* activate magic wall / mill */
- for (yy = 0; yy < lev_fieldy; yy++)
- for (xx = 0; xx < lev_fieldx; xx++)
- if (Feld[xx][yy] == smashed)
- Feld[xx][yy] = activated_magic_wall;
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
+ if (Feld[xx][yy] == smashed)
+ Feld[xx][yy] = activated_magic_wall;
game.magic_wall_time_left = level.time_magic_wall * FRAMES_PER_SECOND;
game.magic_wall_active = TRUE;
}
else if (element == EL_SPRING)
{
+#if USE_NEW_SPRING_BUMPER
+ if (MovDir[x][y] & MV_HORIZONTAL)
+ {
+ 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;
+ ResetGfxAnimation(move_x, move_y);
+ DrawLevelField(move_x, move_y);
+
+ MovDir[x][y] = back_dir;
+ }
+ else if (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
+ SPRING_CAN_ENTER_FIELD(element, x, y + 1))
+ MovDir[x][y] = MV_NONE;
+ }
+#else
if (MovDir[x][y] & MV_HORIZONTAL &&
(!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) ||
SPRING_CAN_ENTER_FIELD(element, x, y + 1)))
MovDir[x][y] = MV_NONE;
+#endif
MovDelay[x][y] = 0;
}
else if (element == EL_ROBOT ||
element == EL_SATELLITE ||
- element == EL_PENGUIN)
+ element == EL_PENGUIN ||
+ element == EL_EMC_ANDROID)
{
int attr_x = -1, attr_y = -1;
new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
Moving2Blocked(x, y, &newx, &newy);
- if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+ if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy))
return;
MovDir[x][y] =
new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL);
Moving2Blocked(x, y, &newx, &newy);
- if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy))
+ if (PENGUIN_CAN_ENTER_FIELD(element, newx, newy))
return;
MovDir[x][y] = old_move_dir;
return;
}
}
- else /* (element == EL_SATELLITE) */
+ else if (element == EL_SATELLITE)
{
int newx, newy;
return;
}
}
+ else if (element == EL_EMC_ANDROID)
+ {
+ static int check_pos[16] =
+ {
+ -1, /* 0 => (invalid) */
+ 7, /* 1 => MV_LEFT */
+ 3, /* 2 => MV_RIGHT */
+ -1, /* 3 => (invalid) */
+ 1, /* 4 => MV_UP */
+ 0, /* 5 => MV_LEFT | MV_UP */
+ 2, /* 6 => MV_RIGHT | MV_UP */
+ -1, /* 7 => (invalid) */
+ 5, /* 8 => MV_DOWN */
+ 6, /* 9 => MV_LEFT | MV_DOWN */
+ 4, /* 10 => MV_RIGHT | MV_DOWN */
+ -1, /* 11 => (invalid) */
+ -1, /* 12 => (invalid) */
+ -1, /* 13 => (invalid) */
+ -1, /* 14 => (invalid) */
+ -1, /* 15 => (invalid) */
+ };
+ static struct
+ {
+ int dx, dy;
+ int dir;
+ } check_xy[8] =
+ {
+ { -1, -1, MV_LEFT | MV_UP },
+ { 0, -1, MV_UP },
+ { +1, -1, MV_RIGHT | MV_UP },
+ { +1, 0, MV_RIGHT },
+ { +1, +1, MV_RIGHT | MV_DOWN },
+ { 0, +1, MV_DOWN },
+ { -1, +1, MV_LEFT | MV_DOWN },
+ { -1, 0, MV_LEFT },
+ };
+ int start_pos, check_order;
+ boolean can_clone = FALSE;
+ int i;
+
+ /* check if there is any free field around current position */
+ for (i = 0; i < 8; i++)
+ {
+ int newx = x + check_xy[i].dx;
+ int newy = y + check_xy[i].dy;
+
+ if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+ {
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+
+ if (can_clone) /* randomly find an element to clone */
+ {
+ can_clone = FALSE;
+
+ start_pos = check_pos[RND(8)];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 8; i++)
+ {
+ int pos_raw = start_pos + i * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+
+ if (ANDROID_CAN_CLONE_FIELD(newx, newy))
+ {
+ element_info[element].move_leave_type = LEAVE_TYPE_LIMITED;
+ element_info[element].move_leave_element = EL_TRIGGER_ELEMENT;
+
+ Store[x][y] = Feld[newx][newy];
+
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (can_clone) /* randomly find a direction to move */
+ {
+ can_clone = FALSE;
+
+ start_pos = check_pos[RND(8)];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 8; i++)
+ {
+ int pos_raw = start_pos + i * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+ int new_move_dir = check_xy[pos].dir;
+
+ if (IN_LEV_FIELD_AND_IS_FREE(newx, newy))
+ {
+ MovDir[x][y] = new_move_dir;
+ MovDelay[x][y] = level.android_clone_time * 8 + 1;
+
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+ }
+
+ if (can_clone) /* cloning and moving successful */
+ return;
+
+ /* cannot clone -- try to move towards player */
+
+ start_pos = check_pos[MovDir[x][y] & 0x0f];
+ check_order = (RND(2) ? -1 : +1);
+
+ for (i = 0; i < 3; i++)
+ {
+ /* first check start_pos, then previous/next or (next/previous) pos */
+ int pos_raw = start_pos + (i < 2 ? i : -1) * check_order;
+ int pos = (pos_raw + 8) % 8;
+ int newx = x + check_xy[pos].dx;
+ int newy = y + check_xy[pos].dy;
+ int new_move_dir = check_xy[pos].dir;
+
+ if (IS_PLAYER(newx, newy))
+ break;
+
+ if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ {
+ MovDir[x][y] = new_move_dir;
+ MovDelay[x][y] = level.android_move_time * 8 + 1;
+
+ break;
+ }
+ }
+ }
}
else if (move_pattern == MV_TURNING_LEFT ||
move_pattern == MV_TURNING_RIGHT ||
static void TurnRound(int x, int y)
{
int direction = MovDir[x][y];
+#if 1
+ int element, graphic;
+#endif
TurnRoundExt(x, y);
GfxFrame[x][y] = 0;
if (MovDelay[x][y])
- GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_BIT(direction);
+ GfxAction[x][y] = ACTION_TURNING_FROM_LEFT + MV_DIR_TO_BIT(direction);
+
+#if 1
+ element = Feld[x][y];
+ graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (graphic_info[graphic].anim_global_sync)
+ GfxFrame[x][y] = FrameCounter;
+ else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
+ GfxFrame[x][y] = CustomValue[x][y];
+ else if (ANIM_MODE(graphic) == ANIM_CE_SCORE)
+ GfxFrame[x][y] = element_info[element].collect_score;
+#endif
}
static boolean JustBeingPushed(int x, int y)
else if (CAN_MOVE_INTO_ACID(element) &&
IN_LEV_FIELD(newx, newy) && Feld[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 (IS_FOOD_PENGUIN(Feld[newx][newy]))
{
- if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MF_MOVING)
+ if (DigField(local_player, x, y, newx, newy, 0,0, DF_DIG) == MP_MOVING)
DrawLevelField(newx, newy);
else
GfxDir[x][y] = MovDir[x][y] = MV_NONE;
return;
}
}
+ else if (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy))
+ {
+ if (Store[x][y] != EL_EMPTY)
+ {
+ boolean can_clone = FALSE;
+ int xx, yy;
+
+ /* 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])
+ {
+ can_clone = TRUE;
+
+ break;
+ }
+ }
+
+ /* cannot clone or target field not free anymore -- do not clone */
+ if (!can_clone || !ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ Store[x][y] = EL_EMPTY;
+ }
+
+ if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ {
+ if (IS_MV_DIAGONAL(MovDir[x][y]))
+ {
+ int diagonal_move_dir = MovDir[x][y];
+ int stored = Store[x][y];
+ int change_delay = 8;
+ int graphic;
+
+ /* android is moving diagonally */
+
+ CreateField(x, y, EL_DIAGONAL_SHRINKING);
+
+ Store[x][y] = (stored == EL_ACID ? EL_EMPTY : stored);
+ GfxElement[x][y] = EL_EMC_ANDROID;
+ GfxAction[x][y] = ACTION_SHRINKING;
+ GfxDir[x][y] = diagonal_move_dir;
+ ChangeDelay[x][y] = change_delay;
+
+ 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)
+ {
+ SplashAcid(newx, newy);
+
+ return;
+ }
+
+ CreateField(newx, newy, EL_DIAGONAL_GROWING);
+
+ Store[newx][newy] = EL_EMC_ANDROID;
+ GfxElement[newx][newy] = EL_EMC_ANDROID;
+ GfxAction[newx][newy] = ACTION_GROWING;
+ GfxDir[newx][newy] = diagonal_move_dir;
+ ChangeDelay[newx][newy] = change_delay;
+
+ graphic = el_act_dir2img(GfxElement[newx][newy],
+ GfxAction[newx][newy], GfxDir[newx][newy]);
+
+ DrawLevelGraphicAnimation(newx, newy, graphic);
+ PlayLevelSoundAction(newx, newy, ACTION_GROWING);
+
+ return;
+ }
+ else
+ {
+ Feld[newx][newy] = EL_EMPTY;
+ DrawLevelField(newx, newy);
+
+ PlayLevelSoundAction(x, y, ACTION_DIGGING);
+ }
+ }
+ else if (!IS_FREE(newx, newy))
+ {
+#if 0
+ if (IS_PLAYER(x, y))
+ DrawPlayerField(x, y);
+ else
+ DrawLevelField(x, y);
+#endif
+
+ return;
+ }
+ }
else if (IS_CUSTOM_ELEMENT(element) &&
CUSTOM_ELEMENT_CAN_ENTER_FIELD(element, newx, newy))
{
}
Store[newx][newy] = EL_EMPTY;
+#if 1
+ /* this makes it possible to leave the removed element again */
+ if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
+ Store[newx][newy] = new_element;
+#else
if (IS_EQUAL_OR_IN_GROUP(new_element, MOVE_ENTER_EL(element)))
{
int move_leave_element = element_info[element].move_leave_element;
Store[newx][newy] = (move_leave_element == EL_TRIGGER_ELEMENT ?
new_element : move_leave_element);
}
+#endif
if (move_pattern & MV_MAZE_RUNNER_STYLE)
{
void ContinueMoving(int x, int y)
{
int element = Feld[x][y];
- int stored = Store[x][y];
struct ElementInfo *ei = &element_info[element];
int direction = MovDir[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, newy = y + dy;
+ int stored = Store[x][y];
+ int stored_new = Store[newx][newy];
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);
Pushed[x][y] = Pushed[newx][newy] = FALSE;
/* some elements can leave other elements behind after moving */
+#if 1
+ if (ei->move_leave_element != EL_EMPTY &&
+ (ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
+ (!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
+#else
if (IS_CUSTOM_ELEMENT(element) && ei->move_leave_element != EL_EMPTY &&
(ei->move_leave_type == LEAVE_TYPE_UNLIMITED || stored != EL_EMPTY) &&
(!IS_PLAYER(x, y) || IS_WALKABLE(ei->move_leave_element)))
+#endif
{
int move_leave_element = ei->move_leave_element;
+#if 1
+#if 1
+ /* this makes it possible to leave the removed element again */
+ if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
+ move_leave_element = (stored == EL_ACID ? EL_EMPTY : stored);
+#else
+ /* this makes it possible to leave the removed element again */
+ if (ei->move_leave_element == EL_TRIGGER_ELEMENT)
+ move_leave_element = stored;
+#endif
+#else
/* this makes it possible to leave the removed element again */
if (ei->move_leave_type == LEAVE_TYPE_LIMITED &&
ei->move_leave_element == EL_TRIGGER_ELEMENT)
move_leave_element = stored;
+#endif
Feld[x][y] = move_leave_element;
player->index_bit, push_side);
}
+ if (element == EL_EMC_ANDROID && pushed_by_player) /* make another move */
+ MovDelay[newx][newy] = 1;
+
CheckTriggeredElementChangeBySide(x, y, element, CE_MOVE_OF_X, direction);
TestIfElementTouchesCustomElement(x, y); /* empty or new element */
+#if 0
+ if (ChangePage[newx][newy] != -1) /* delayed change */
+ {
+ int page = ChangePage[newx][newy];
+ struct ElementChangeInfo *change = &ei->change_page[page];
+
+ ChangePage[newx][newy] = -1;
+
+ if (change->can_change)
+ {
+ if (ChangeElement(newx, newy, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(newx, newy);
+ }
+ }
+
+ if (change->has_action)
+ ExecuteCustomElementAction(newx, newy, element, page);
+ }
+#endif
+
TestIfElementHitsCustomElement(newx, newy, direction);
TestIfPlayerTouchesCustomElement(newx, newy);
TestIfElementTouchesCustomElement(newx, newy);
+
+#if 1
+ if (IS_CUSTOM_ELEMENT(element) && ei->move_enter_element != EL_EMPTY &&
+ IS_EQUAL_OR_IN_GROUP(stored_new, ei->move_enter_element))
+ CheckElementChangeBySide(newx, newy, element, stored_new, CE_DIGGING_X,
+ MV_DIR_OPPOSITE(direction));
+#endif
}
int AmoebeNachbarNr(int ax, int ay)
AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
AmoebaCnt2[old_group_nr] = 0;
- for (yy = 0; yy < lev_fieldy; yy++)
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
{
- for (xx = 0; xx < lev_fieldx; xx++)
- {
- if (AmoebaNr[xx][yy] == old_group_nr)
- AmoebaNr[xx][yy] = new_group_nr;
- }
+ if (AmoebaNr[xx][yy] == old_group_nr)
+ AmoebaNr[xx][yy] = new_group_nr;
}
}
}
}
#endif
- for (y = 0; y < lev_fieldy; y++)
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
- for (x = 0; x < lev_fieldx; x++)
+ if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
{
- if (Feld[x][y] == EL_AMOEBA_DEAD && AmoebaNr[x][y] == group_nr)
- {
- AmoebaNr[x][y] = 0;
- Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
- }
+ AmoebaNr[x][y] = 0;
+ Feld[x][y] = EL_AMOEBA_TO_DIAMOND;
}
}
+
PlayLevelSound(ax, ay, (IS_GEM(level.amoeba_content) ?
SND_AMOEBA_TURNING_TO_GEM :
SND_AMOEBA_TURNING_TO_ROCK));
}
#endif
- for (y = 0; y < lev_fieldy; y++)
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
- for (x = 0; x < lev_fieldx; x++)
+ if (AmoebaNr[x][y] == group_nr &&
+ (Feld[x][y] == EL_AMOEBA_DEAD ||
+ Feld[x][y] == EL_BD_AMOEBA ||
+ Feld[x][y] == EL_AMOEBA_GROWING))
{
- if (AmoebaNr[x][y] == group_nr &&
- (Feld[x][y] == EL_AMOEBA_DEAD ||
- Feld[x][y] == EL_BD_AMOEBA ||
- Feld[x][y] == EL_AMOEBA_GROWING))
- {
- AmoebaNr[x][y] = 0;
- Feld[x][y] = new_element;
- InitField(x, y, FALSE);
- DrawLevelField(x, y);
- done = TRUE;
- }
+ AmoebaNr[x][y] = 0;
+ Feld[x][y] = new_element;
+ InitField(x, y, FALSE);
+ DrawLevelField(x, y);
+ done = TRUE;
}
}
int element = Feld[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 },
{ 0, +1 }
};
- if (!level.amoeba_speed)
+ if (!level.amoeba_speed && element != EL_EMC_DRIPPER)
{
Feld[ax][ay] = EL_AMOEBA_DEAD;
DrawLevelField(ax, ay);
return;
}
- if (element == EL_AMOEBA_WET) /* object is an acid / amoeba drop */
+ if (can_drop) /* EL_AMOEBA_WET or EL_EMC_DRIPPER */
{
int start = RND(4);
int x = ax + xy[start][0];
}
}
- if (element != EL_AMOEBA_WET || neway < ay || !IS_FREE(newax, neway) ||
+ 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 */
Store[newax][neway] = element;
}
- else if (neway == ay)
+ else if (neway == ay || element == EL_EMC_DRIPPER)
{
Feld[newax][neway] = EL_AMOEBA_DROP; /* drop left/right of amoeba */
ChangeDelay[x][y] = level.time_timegate * FRAMES_PER_SECOND;
}
-static void RunTimegateWheel(int x, int y)
+static void RunTimegateWheel(int x, int y)
+{
+ PlayLevelSound(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
+}
+
+static void InitMagicBallDelay(int x, int y)
+{
+#if 1
+ ChangeDelay[x][y] = (level.ball_time + 1) * 8 + 1;
+#else
+ ChangeDelay[x][y] = level.ball_time * FRAMES_PER_SECOND + 1;
+#endif
+}
+
+static void ActivateMagicBall(int bx, int by)
+{
+ int x, y;
+
+ if (level.ball_random)
+ {
+ int pos_border = RND(8); /* select one of the eight border elements */
+ int pos_content = (pos_border > 3 ? pos_border + 1 : pos_border);
+ int xx = pos_content % 3;
+ int yy = pos_content / 3;
+
+ x = bx - 1 + xx;
+ y = by - 1 + yy;
+
+ if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY)
+ CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]);
+ }
+ else
+ {
+ for (y = by - 1; y <= by + 1; y++) for (x = bx - 1; x <= bx + 1; x++)
+ {
+ int xx = x - bx + 1;
+ int yy = y - by + 1;
+
+ if (IN_LEV_FIELD(x, y) && Feld[x][y] == EL_EMPTY)
+ CreateField(x, y, level.ball_content[game.ball_content_nr].e[xx][yy]);
+ }
+ }
+
+ game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents;
+}
+
+static void InitDiagonalMovingElement(int x, int y)
{
- PlayLevelSound(x, y, SND_TIMEGATE_SWITCH_ACTIVE);
+#if 0
+ MovDelay[x][y] = level.android_move_time;
+#endif
}
void CheckExit(int x, int y)
{
int x, y;
- for (y = 0; y < lev_fieldy; y++)
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
+ for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
- for (x = 0; x < lev_fieldx; x++)
- {
- int element = Feld[x][y];
+ int element = Feld[x][y];
- if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
- {
- Feld[x][y] = EL_TIMEGATE_CLOSING;
+ if (element == EL_TIMEGATE_OPEN || element == EL_TIMEGATE_OPENING)
+ {
+ Feld[x][y] = EL_TIMEGATE_CLOSING;
- PlayLevelSoundAction(x, y, ACTION_CLOSING);
- }
+ PlayLevelSoundAction(x, y, ACTION_CLOSING);
}
}
}
for (i = 0; i < NUM_DIRECTIONS; i++)
{
- int xx = x + xy[i][0], yy = y + xy[i][1];
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
- if (IS_PLAYER(xx, yy))
+ if (IN_LEV_FIELD(xx, yy) && IS_PLAYER(xx, yy))
{
PlayLevelSound(x, y, SND_SP_BUGGY_BASE_ACTIVE);
MV_NONE);
int action_arg_number_min =
- (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MIN :
+ (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_NOT_MOVING :
CA_ARG_MIN);
int action_arg_number_max =
- (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MAX :
+ (action_type == CA_SET_PLAYER_SPEED ? STEPSIZE_EVEN_FASTER :
action_type == CA_SET_LEVEL_GEMS ? 999 :
action_type == CA_SET_LEVEL_TIME ? 9999 :
action_type == CA_SET_LEVEL_SCORE ? 99999 :
CA_ARG_MAX);
int action_arg_number_reset =
- (action_type == CA_SET_PLAYER_SPEED ? TILEX/game.initial_move_delay_value :
+ (action_type == CA_SET_PLAYER_SPEED ? level.initial_player_stepsize :
action_type == CA_SET_LEVEL_GEMS ? level.gems_needed :
action_type == CA_SET_LEVEL_TIME ? level.time :
action_type == CA_SET_LEVEL_SCORE ? 0 :
action_arg == CA_ARG_NUMBER_LEVEL_TIME ? level_time_value :
action_arg == CA_ARG_NUMBER_LEVEL_GEMS ? local_player->gems_still_needed :
action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score :
- action_arg == CA_ARG_ELEMENT_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) :
- action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_ce_value :
+ action_arg == CA_ARG_ELEMENT_CV_TARGET ? GET_NEW_CUSTOM_VALUE(change->target_element) :
+ action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value:
+ action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element :
+ action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element :
-1);
int action_arg_number_old =
{
int move_stepsize = TILEX / stored_player[i].move_delay_value;
- if (action_arg == CA_ARG_SPEED_SLOWER ||
- action_arg == CA_ARG_SPEED_FASTER)
+ if (action_arg == CA_ARG_SPEED_FASTER &&
+ stored_player[i].cannot_move)
+ {
+ action_arg_number = STEPSIZE_VERY_SLOW;
+ }
+ else if (action_arg == CA_ARG_SPEED_SLOWER ||
+ action_arg == CA_ARG_SPEED_FASTER)
{
action_arg_number = 2;
action_mode = (action_arg == CA_ARG_SPEED_SLOWER ? CA_MODE_DIVIDE :
action_arg_number_min,
action_arg_number_max);
+#if 1
+ SetPlayerMoveSpeed(&stored_player[i], move_stepsize, FALSE);
+#else
/* make sure that value is power of 2 */
move_stepsize = (1 << log_2(move_stepsize));
stored_player[i].cannot_move =
(action_arg == CA_ARG_SPEED_NOT_MOVING ? TRUE : FALSE);
+#endif
}
}
CheckElementChange(x, y, element, EL_UNDEFINED, CE_VALUE_GETS_ZERO);
CheckTriggeredElementChange(x, y, element, CE_VALUE_GETS_ZERO_OF_X);
+
+#if 0
+ printf("::: RESULT: %d, %d\n", Feld[x][y], ChangePage[x][y]);
+#endif
}
#endif
break;
}
+ /* ---------- engine actions ------------------------------------------ */
+
+ case CA_SET_ENGINE_SCAN_MODE:
+ {
+ InitPlayfieldScanMode(action_arg);
+
+ break;
+ }
+
default:
break;
}
}
-static void ChangeElementNowExt(struct ElementChangeInfo *change,
- int x, int y, int target_element)
+static void CreateFieldExt(int x, int y, int element, boolean is_change)
{
int previous_move_direction = MovDir[x][y];
#if USE_NEW_CUSTOM_VALUE
int last_ce_value = CustomValue[x][y];
#endif
- boolean add_player = (ELEM_IS_PLAYER(target_element) &&
+ boolean add_player = (ELEM_IS_PLAYER(element) &&
IS_WALKABLE(Feld[x][y]));
/* check if element under player changes from accessible to unaccessible
(needed for special case of dropping element which then changes) */
if (IS_PLAYER(x, y) && !PLAYER_EXPLOSION_PROTECTED(x, y) &&
- IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element))
+ IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(element))
{
Bang(x, y);
+
return;
}
else
RemoveField(x, y);
- Feld[x][y] = target_element;
+ Feld[x][y] = element;
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
}
/* "ChangeCount" not set yet to allow "entered by player" change one time */
- if (ELEM_IS_PLAYER(target_element))
- RelocatePlayer(x, y, target_element);
+ if (ELEM_IS_PLAYER(element))
+ RelocatePlayer(x, y, element);
- ChangeCount[x][y]++; /* count number of changes in the same frame */
+ if (is_change)
+ ChangeCount[x][y]++; /* count number of changes in the same frame */
TestIfBadThingTouchesPlayer(x, y);
TestIfPlayerTouchesCustomElement(x, y);
TestIfElementTouchesCustomElement(x, y);
}
-static boolean ChangeElementNow(int x, int y, int element, int page)
+static void CreateField(int x, int y, int element)
+{
+ CreateFieldExt(x, y, element, FALSE);
+}
+
+static void CreateElementFromChange(int x, int y, int element)
+{
+ element = GET_VALID_RUNTIME_ELEMENT(element);
+
+#if USE_STOP_CHANGED_ELEMENTS
+ if (game.engine_version >= VERSION_IDENT(3,2,0,7))
+ {
+ int old_element = Feld[x][y];
+
+ /* prevent changed element from moving in same engine frame
+ unless both old and new element can either fall or move */
+ if ((!CAN_FALL(old_element) || !CAN_FALL(element)) &&
+ (!CAN_MOVE(old_element) || !CAN_MOVE(element)))
+ Stop[x][y] = TRUE;
+ }
+#endif
+
+ CreateFieldExt(x, y, element, TRUE);
+}
+
+static boolean ChangeElement(int x, int y, int element, int page)
{
struct ElementChangeInfo *change = &element_info[element].change_page[page];
int target_element;
content_element = change->target_content.e[xx][yy];
target_element = GET_TARGET_ELEMENT(content_element, change);
- ChangeElementNowExt(change, ex, ey, target_element);
+ CreateElementFromChange(ex, ey, target_element);
something_has_changed = TRUE;
{
target_element = GET_TARGET_ELEMENT(change->target_element, change);
- ChangeElementNowExt(change, x, y, target_element);
+ if (element == EL_DIAGONAL_GROWING ||
+ element == EL_DIAGONAL_SHRINKING)
+ {
+ target_element = Store[x][y];
+
+ Store[x][y] = EL_EMPTY;
+ }
+
+ CreateElementFromChange(x, y, target_element);
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page);
#if USE_NEW_DELAYED_ACTION
-static void ChangeElement(int x, int y, int page)
+static void HandleElementChange(int x, int y, int page)
{
int element = MovingOrBlocked2Element(x, y);
struct ElementInfo *ei = &element_info[element];
!CAN_CHANGE_OR_HAS_ACTION(Back[x][y]))
{
printf("\n\n");
- printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
+ printf("HandleElementChange(): %d,%d: element = %d ('%s')\n",
x, y, element, element_info[element].token_name);
- printf("ChangeElement(): This should never happen!\n");
+ printf("HandleElementChange(): This should never happen!\n");
printf("\n\n");
}
#endif
if (change->can_change)
{
- if (ChangeElementNow(x, y, element, page))
+ if (ChangeElement(x, y, element, page))
{
if (change->post_change_function)
change->post_change_function(x, y);
#else
-static void ChangeElement(int x, int y, int page)
+static void HandleElementChange(int x, int y, int page)
{
int element = MovingOrBlocked2Element(x, y);
struct ElementInfo *ei = &element_info[element];
if (!CAN_CHANGE(element) && !CAN_CHANGE(Back[x][y]))
{
printf("\n\n");
- printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
+ printf("HandleElementChange(): %d,%d: element = %d ('%s')\n",
x, y, element, element_info[element].token_name);
- printf("ChangeElement(): This should never happen!\n");
+ printf("HandleElementChange(): This should never happen!\n");
printf("\n\n");
}
#endif
return;
}
- if (ChangeElementNow(x, y, element, page))
+ if (ChangeElement(x, y, element, page))
{
if (change->post_change_function)
change->post_change_function(x, y);
#endif
-static boolean CheckTriggeredElementChangeExt(int x, int y,
+static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y,
int trigger_element,
int trigger_event,
int trigger_player,
change->actual_trigger_element = trigger_element;
change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
change->actual_trigger_side = trigger_side;
- change->actual_trigger_ce_value = CustomValue[x][y];
+ change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y];
if ((change->can_change && !change_done) || change->has_action)
{
int x, y;
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
if (Feld[x][y] == element)
{
{
ChangeDelay[x][y] = 1;
ChangeEvent[x][y] = trigger_event;
- ChangeElement(x, y, p);
+
+ HandleElementChange(x, y, p);
}
#if USE_NEW_DELAYED_ACTION
else if (change->has_action)
element = Feld[x][y];
}
- if (Feld[x][y] != element) /* check if element has already changed */
+#if 0
+ /* check if element has already changed */
+ if (Feld[x][y] != element)
+ return FALSE;
+#else
+ /* 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) ||
+
+ (game.engine_version >= VERSION_IDENT(3,2,0,7) &&
+ (ChangeCount[x][y] >= game.max_num_changes_per_frame ||
+ ChangePage[x][y] != -1)))
return FALSE;
+#endif
for (p = 0; p < element_info[element].num_change_pages; p++)
{
{
ChangeDelay[x][y] = 1;
ChangeEvent[x][y] = trigger_event;
- ChangeElement(x, y, p);
+
+ HandleElementChange(x, y, p);
change_done = TRUE;
}
WaitUntilDelayReached(&game_frame_delay, game_frame_delay_value);
+ InitPlayfieldScanModeVars();
+
+#if USE_ONE_MORE_CHANGE_PER_FRAME
+ if (game.engine_version >= VERSION_IDENT(3,2,0,7))
+ {
+ SCAN_PLAYFIELD(x, y)
+ {
+ ChangeCount[x][y] = 0;
+ ChangeEvent[x][y] = -1;
+ }
+ }
+#endif
+
if (network_playing && !network_player_action_received)
{
/* try to get network player actions in time */
}
}
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
ChangeCount[x][y] = 0;
ChangeEvent[x][y] = -1;
GfxFrame[x][y]++;
/* reset finished pushing action (not done in ContinueMoving() to allow
- continous pushing animation for elements with zero push delay) */
+ continuous pushing animation for elements with zero push delay) */
if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y))
{
ResetGfxAnimation(x, y);
#endif
}
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
element = Feld[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+#if 0
+ printf("::: %d,%d\n", x, y);
+
+ if (element == EL_ROCK)
+ printf("::: Yo man! Rocks can fall!\n");
+#endif
+
if (graphic_info[graphic].anim_global_sync)
GfxFrame[x][y] = FrameCounter;
else if (ANIM_MODE(graphic) == ANIM_CE_VALUE)
{
int page = element_info[element].event_page_nr[CE_DELAY];
#if 0
- ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page);
+ HandleElementChange(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page);
#else
#if 0
#endif
#if 1
- ChangeElement(x, y, page);
+ HandleElementChange(x, y, page);
#else
if (CAN_CHANGE(element))
- ChangeElement(x, y, page);
+ HandleElementChange(x, y, page);
if (HAS_ACTION(element))
ExecuteCustomElementAction(x, y, element, page);
CheckForDragon(x, y);
else if (element == EL_EXPLOSION)
; /* drawing of correct explosion animation is handled separately */
- else if (element == EL_ELEMENT_SNAPPING)
+ else if (element == EL_ELEMENT_SNAPPING ||
+ element == EL_DIAGONAL_SHRINKING ||
+ element == EL_DIAGONAL_GROWING)
{
#if 1
graphic = el_act_dir2img(GfxElement[x][y], GfxAction[x][y],GfxDir[x][y]);
{
game.explosions_delayed = FALSE;
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
element = Feld[x][y];
game.magic_wall_time_left--;
if (!game.magic_wall_time_left)
{
+#if 1
+ SCAN_PLAYFIELD(x, y)
+#else
for (y = 0; y < lev_fieldy; y++) for (x = 0; x < lev_fieldx; x++)
+#endif
{
element = Feld[x][y];
{
int jx = player->jx, jy = player->jy;
int new_jx = jx + dx, new_jy = jy + dy;
+#if !USE_FIXED_DONT_RUN_INTO
int element;
+#endif
int can_move;
+ boolean player_can_move = !player->cannot_move;
if (!player->active || (!dx && !dy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
player->MovDir = (dx < 0 ? MV_LEFT :
dx > 0 ? MV_RIGHT :
dy > 0 ? MV_DOWN : MV_NONE);
if (!IN_LEV_FIELD(new_jx, new_jy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
- if (player->cannot_move)
+ if (!player_can_move)
{
#if 1
if (player->MovPos == 0)
SnapField(player, 0, 0);
#endif
- return MF_NO_ACTION;
+#if 0
+ return MP_NO_ACTION;
+#endif
}
if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
+#if !USE_FIXED_DONT_RUN_INTO
element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
- if (DONT_RUN_INTO(element))
+ /* (moved to DigField()) */
+ if (player_can_move && DONT_RUN_INTO(element))
{
if (element == EL_ACID && dx == 0 && dy == 1)
{
else
TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
- return MF_MOVING;
+ return MP_MOVING;
}
+#endif
can_move = DigField(player, jx, jy, new_jx, new_jy, real_dx,real_dy, DF_DIG);
- if (can_move != MF_MOVING)
+#if 0
+#if USE_FIXED_DONT_RUN_INTO
+ if (can_move == MP_DONT_RUN_INTO)
+ return MP_MOVING;
+#endif
+#endif
+ if (can_move != MP_MOVING)
return can_move;
+#if USE_FIXED_DONT_RUN_INTO
+#endif
+
/* check if DigField() has caused relocation of the player */
if (player->jx != jx || player->jy != jy)
- return MF_NO_ACTION; /* <-- !!! CHECK THIS [-> MF_ACTION ?] !!! */
+ return MP_NO_ACTION; /* <-- !!! CHECK THIS [-> MP_ACTION ?] !!! */
StorePlayer[jx][jy] = 0;
player->last_jx = jx;
ScrollPlayer(player, SCROLL_INIT);
- return MF_MOVING;
+ return MP_MOVING;
}
boolean MovePlayer(struct PlayerInfo *player, int dx, int dy)
{
int jx = player->jx, jy = player->jy;
int old_jx = jx, old_jy = jy;
- int moved = MF_NO_ACTION;
+ int moved = MP_NO_ACTION;
if (!player->active)
return FALSE;
jx = player->jx;
jy = player->jy;
- if (moved & MF_MOVING && !ScreenMovPos &&
+ if (moved & MP_MOVING && !ScreenMovPos &&
(player == local_player || !options.network))
{
int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
player->StepFrame = 0;
- if (moved & MF_MOVING)
+ if (moved & MP_MOVING)
{
if (old_jx != jx && old_jy == jy)
player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
}
}
+#if USE_ELEMENT_TOUCHING_BUGFIX
+
void TestIfElementTouchesCustomElement(int x, int y)
+{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int trigger_sides[4][2] =
+ {
+ /* 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 */
+ };
+ static int touch_dir[4] =
+ {
+ MV_LEFT | MV_RIGHT,
+ MV_UP | MV_DOWN,
+ MV_UP | MV_DOWN,
+ MV_LEFT | MV_RIGHT
+ };
+ boolean change_center_element = FALSE;
+ int center_element = Feld[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 border_element;
+
+ border_element_old[i] = -1;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (game.engine_version < VERSION_IDENT(3,0,7,0))
+ border_element = Feld[xx][yy]; /* may be moving! */
+ else if (!IS_MOVING(xx, yy) && !IS_BLOCKED(xx, yy))
+ border_element = Feld[xx][yy];
+ else if (MovDir[xx][yy] & touch_dir[i]) /* elements are touching */
+ border_element = MovingOrBlocked2Element(xx, yy);
+ else
+ continue; /* center and border element do not touch */
+
+ border_element_old[i] = border_element;
+ }
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int center_side = trigger_sides[i][0];
+ int border_element = border_element_old[i];
+
+ if (border_element == -1)
+ continue;
+
+ /* check for change of border element */
+ CheckElementChangeBySide(xx, yy, border_element, center_element,
+ CE_TOUCHING_X, center_side);
+ }
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int border_side = trigger_sides[i][1];
+ int border_element = border_element_old[i];
+
+ if (border_element == -1)
+ continue;
+
+ /* check for change of center element (but change it only once) */
+ if (!change_center_element)
+ change_center_element =
+ CheckElementChangeBySide(x, y, center_element, border_element,
+ CE_TOUCHING_X, border_side);
+ }
+}
+
+#else
+
+void TestIfElementTouchesCustomElement_OLD(int x, int y)
{
static int xy[4][2] =
{
}
}
+#endif
+
void TestIfElementHitsCustomElement(int x, int y, int direction)
{
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
{
int i, kill_x = -1, kill_y = -1;
+
int bad_element = -1;
static int test_xy[4][2] =
{
static void setFieldForSnapping(int x, int y, int element, int direction)
{
struct ElementInfo *ei = &element_info[element];
- int direction_bit = MV_DIR_BIT(direction);
+ int direction_bit = MV_DIR_TO_BIT(direction);
int graphic_snapping = ei->direction_graphic[ACTION_SNAPPING][direction_bit];
int action = (graphic_snapping != IMG_EMPTY_SPACE ? ACTION_SNAPPING :
IS_DIGGABLE(element) ? ACTION_DIGGING : ACTION_COLLECTING);
{
boolean is_player = (IS_PLAYER(oldx, oldy) || mode != DF_DIG);
boolean player_was_pushing = player->is_pushing;
+ boolean player_can_move = (!player->cannot_move && mode != DF_SNAP);
+ boolean player_can_move_or_snap = (!player->cannot_move || mode == DF_SNAP);
int jx = oldx, jy = oldy;
int dx = x - jx, dy = y - jy;
int nextx = x + dx, nexty = y + dy;
int opposite_direction = MV_DIR_OPPOSITE(move_direction);
int dig_side = MV_DIR_OPPOSITE(move_direction);
int old_element = Feld[jx][jy];
+#if USE_FIXED_DONT_RUN_INTO
+ int element = MovingOrBlocked2ElementIfNotLeaving(x, y);
+#else
int element;
+#endif
int collect_count;
if (is_player) /* function can also be called by EL_PENGUIN */
player->is_switching = FALSE;
player->push_delay = -1;
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
}
+#if !USE_FIXED_DONT_RUN_INTO
if (IS_MOVING(x, y) || IS_PLAYER(x, y))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
+#endif
if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
old_element = Back[jx][jy];
game.engine_version >= VERSION_IDENT(2,2,0,0))
old_element = Back[jx][jy];
+#if 0
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && DONT_RUN_INTO(element))
+ {
+ if (element == EL_ACID && dx == 0 && dy == 1)
+ {
+ SplashAcid(x, y);
+ Feld[jx][jy] = EL_PLAYER_1;
+ InitMovingField(jx, jy, MV_DOWN);
+ Store[jx][jy] = EL_ACID;
+ ContinueMoving(jx, jy);
+ BuryPlayer(player);
+ }
+ else
+ TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+ return MP_DONT_RUN_INTO;
+ }
+#endif
+#endif
+
+#if 1
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && DONT_RUN_INTO(element))
+ {
+ TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+ return MP_DONT_RUN_INTO;
+ }
+#endif
+#endif
+
if (IS_WALKABLE(old_element) && !ACCESS_FROM(old_element, move_direction))
- return MF_NO_ACTION; /* field has no opening in this direction */
+ return MP_NO_ACTION; /* field has no opening in this direction */
if (IS_PASSABLE(old_element) && !ACCESS_FROM(old_element,opposite_direction))
- return MF_NO_ACTION; /* field has no opening in this direction */
-
- element = Feld[x][y];
-#if USE_NEW_CUSTOM_VALUE
+ return MP_NO_ACTION; /* field has no opening in this direction */
#if 1
- collect_count = element_info[element].collect_count_initial;
-#else
- collect_count = CustomValue[x][y];
-#endif
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && element == EL_ACID && move_direction == MV_DOWN)
+ {
+ SplashAcid(x, y);
+ Feld[jx][jy] = EL_PLAYER_1;
+ InitMovingField(jx, jy, MV_DOWN);
+ Store[jx][jy] = EL_ACID;
+ ContinueMoving(jx, jy);
+ BuryPlayer(player);
-#else
- collect_count = element_info[element].collect_count_initial;
+ return MP_DONT_RUN_INTO;
+ }
+#endif
#endif
#if 0
- if (element != EL_BLOCKED &&
- CustomValue[x][y] != element_info[element].collect_count_initial)
- printf("::: %d: %d != %d\n",
- element,
- CustomValue[x][y],
- element_info[element].collect_count_initial);
+#if USE_FIXED_DONT_RUN_INTO
+ if (player_can_move && DONT_RUN_INTO(element))
+ {
+ if (element == EL_ACID && dx == 0 && dy == 1)
+ {
+ SplashAcid(x, y);
+ Feld[jx][jy] = EL_PLAYER_1;
+ InitMovingField(jx, jy, MV_DOWN);
+ Store[jx][jy] = EL_ACID;
+ ContinueMoving(jx, jy);
+ BuryPlayer(player);
+ }
+ else
+ TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
+
+ return MP_DONT_RUN_INTO;
+ }
+#endif
+#endif
+
+#if USE_FIXED_DONT_RUN_INTO
+ if (IS_MOVING(x, y) || IS_PLAYER(x, y))
+ return MP_NO_ACTION;
+#endif
+
+#if !USE_FIXED_DONT_RUN_INTO
+ element = Feld[x][y];
#endif
+ collect_count = element_info[element].collect_count_initial;
+
if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
+
+ if (game.engine_version < VERSION_IDENT(2,2,0,0))
+ player_can_move = player_can_move_or_snap;
if (mode == DF_SNAP && !IS_SNAPPABLE(element) &&
game.engine_version >= VERSION_IDENT(2,2,0,0))
player->index_bit, dig_side);
if (Feld[x][y] != element) /* field changed by snapping */
- return MF_ACTION;
+ return MP_ACTION;
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
if (game.gravity && is_player && !player->is_auto_moving &&
canFallDown(player) && move_direction != MV_DOWN &&
!canMoveToValidFieldWithGravity(jx, jy, move_direction))
- return MF_NO_ACTION; /* player cannot walk here due to gravity */
+ return MP_NO_ACTION; /* player cannot walk here due to gravity */
- if (IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
+ if (player_can_move &&
+ IS_WALKABLE(element) && ACCESS_FROM(element, opposite_direction))
{
int sound_element = SND_ELEMENT(element);
int sound_action = ACTION_WALKING;
if (IS_RND_GATE(element))
{
if (!player->key[RND_GATE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_RND_GATE_GRAY(element))
{
if (!player->key[RND_GATE_GRAY_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_RND_GATE_GRAY_ACTIVE(element))
{
if (!player->key[RND_GATE_GRAY_ACTIVE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (element == EL_EXIT_OPEN ||
element == EL_SP_EXIT_OPEN ||
else
PlayLevelSoundElementAction(x, y, player->artwork_element, sound_action);
}
- else if (IS_PASSABLE(element) && canPassField(x, y, move_direction))
+ else if (player_can_move &&
+ IS_PASSABLE(element) && canPassField(x, y, move_direction))
{
if (!ACCESS_FROM(element, opposite_direction))
- return MF_NO_ACTION; /* field not accessible from this direction */
+ return MP_NO_ACTION; /* field not accessible from this direction */
if (CAN_MOVE(element)) /* only fixed elements can be passed! */
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (IS_EM_GATE(element))
{
if (!player->key[EM_GATE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_EM_GATE_GRAY(element))
{
if (!player->key[EM_GATE_GRAY_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_EM_GATE_GRAY_ACTIVE(element))
{
if (!player->key[EM_GATE_GRAY_ACTIVE_NR(element)])
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
else if (IS_SP_PORT(element))
{
PlayLevelSoundAction(x, y, ACTION_PASSING);
}
- else if (IS_DIGGABLE(element))
+ else if (player_can_move_or_snap && IS_DIGGABLE(element))
{
RemoveField(x, y);
player->index_bit, dig_side);
}
}
- else if (IS_COLLECTIBLE(element))
+ else if (player_can_move_or_snap && IS_COLLECTIBLE(element))
{
RemoveField(x, y);
player->index_bit, dig_side);
}
}
- else if (IS_PUSHABLE(element))
+ else if (player_can_move_or_snap && IS_PUSHABLE(element))
{
if (mode == DF_SNAP && element != EL_BD_ROCK)
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (CAN_FALL(element) && dy)
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (CAN_FALL(element) && IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1) &&
!(element == EL_SPRING && level.use_spring_bug))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (CAN_MOVE(element) && GET_MAX_MOVE_DELAY(element) == 0 &&
((move_direction & MV_VERTICAL &&
IN_LEV_FIELD(x, y - 1) && IS_FREE(x, y - 1)) ||
(element_info[element].move_pattern & MV_DOWN &&
IN_LEV_FIELD(x, y + 1) && IS_FREE(x, y + 1))))))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
/* do not push elements already moving away faster than player */
if (CAN_MOVE(element) && MovDir[x][y] == move_direction &&
ABS(getElementMoveStepsize(x, y)) > MOVE_STEPSIZE_NORMAL)
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (game.engine_version >= VERSION_IDENT(3,1,0,0))
{
(IS_FREE(nextx, nexty) ||
(Feld[nextx][nexty] == EL_SOKOBAN_FIELD_EMPTY &&
IS_SB_ELEMENT(element)))))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (!checkDiagonalPushing(player, x, y, real_dx, real_dy))
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
if (player->push_delay == -1) /* new pushing; restart delay */
player->push_delay = 0;
if (game.engine_version >= VERSION_IDENT(3,0,7,1))
player->move_delay = 0;
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
if (IS_SB_ELEMENT(element))
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
- return MF_ACTION;
+ return MP_ACTION;
}
player->is_switching = TRUE;
{
int xx, yy;
- for (yy = 0; yy < lev_fieldy; yy++) for (xx=0; xx < lev_fieldx; xx++)
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
{
if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
Bang(xx, yy);
ResetGfxAnimation(x, y);
DrawLevelField(x, y);
}
+ else if (element == EL_EMC_MAGIC_BALL_SWITCH ||
+ element == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE)
+ {
+ int xx, yy;
+
+ game.ball_state = !game.ball_state;
+
+#if 1
+ SCAN_PLAYFIELD(xx, yy)
+#else
+ for (yy = 0; yy < lev_fieldy; yy++) for (xx = 0; xx < lev_fieldx; xx++)
+#endif
+ {
+ int e = Feld[xx][yy];
+
+ if (game.ball_state)
+ {
+ if (e == EL_EMC_MAGIC_BALL)
+ CreateField(xx, yy, EL_EMC_MAGIC_BALL_ACTIVE);
+ else if (e == EL_EMC_MAGIC_BALL_SWITCH)
+ CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH_ACTIVE);
+ }
+ else
+ {
+ if (e == EL_EMC_MAGIC_BALL_ACTIVE)
+ CreateField(xx, yy, EL_EMC_MAGIC_BALL);
+ else if (e == EL_EMC_MAGIC_BALL_SWITCH_ACTIVE)
+ CreateField(xx, yy, EL_EMC_MAGIC_BALL_SWITCH);
+ }
+ }
+ }
CheckTriggeredElementChangeByPlayer(x, y, element, CE_SWITCH_OF_X,
player->index_bit, dig_side);
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
- return MF_ACTION;
+ return MP_ACTION;
}
else
{
CheckTriggeredElementChangeByPlayer(x, y, element, CE_PLAYER_PRESSES_X,
player->index_bit, dig_side);
- return MF_NO_ACTION;
+ return MP_NO_ACTION;
}
player->push_delay = -1;
player->is_collecting = !player->is_digging;
}
- return MF_MOVING;
+ return MP_MOVING;
}
boolean SnapField(struct PlayerInfo *player, int dx, int dy)
player->is_dropping = FALSE;
- if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
+ if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MP_NO_ACTION)
return FALSE;
player->is_snapping = TRUE;
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)
- return MF_ACTION;
+ return MP_ACTION;
if (IS_THROWABLE(drop_element))
{
break;
case SAMPLE_slurp:
- PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
+ PlayLevelSoundElementAction(x, y, element, ACTION_SLURPING);
break;
case SAMPLE_eater: