#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_NEW_CONTINUOUS_SNAPPING (USE_NEW_STUFF * 1)
#define USE_QUICKSAND_IMPACT_BUGFIX (USE_NEW_STUFF * 0)
#define DX_TIME2 (DX + XX_TIME2)
#define DY_TIME (DY + YY_TIME)
+/* values for delayed check of falling and moving elements and for collision */
+#define CHECK_DELAY_MOVING 3
+#define CHECK_DELAY_FALLING 3
+#define CHECK_DELAY_COLLISION 2
+
/* values for initial player move delay (initial delay counter value) */
#define INITIAL_MOVE_DELAY_OFF -1
#define INITIAL_MOVE_DELAY_ON 0
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_CUSTOM_VALUE(e) ( (element_info[e].ce_value_fixed_initial) +\
+#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 GET_CHANGE_DELAY(c) ( ((c)->delay_fixed * (c)->delay_frames) + \
RND((c)->delay_random * (c)->delay_frames))
#define GET_CE_DELAY_VALUE(c) ( ((c)->delay_fixed) + \
RND((c)->delay_random))
-#define GET_TARGET_ELEMENT(e, ch) \
- ((e) == EL_TRIGGER_ELEMENT ? (ch)->actual_trigger_element : \
- (e) == EL_TRIGGER_PLAYER ? (ch)->actual_trigger_player : (e))
+
+#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, cv, cs) \
+ ((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) == EL_TRIGGER_CE_SCORE ? (ch)->actual_trigger_ce_score : \
+ (e) == EL_CURRENT_CE_VALUE ? (cv) : \
+ (e) == EL_CURRENT_CE_SCORE ? (cs) : (e))
#define CAN_GROW_INTO(e) \
((e) == EL_SAND || (IS_DIGGABLE(e) && level.grow_into_diggable))
#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)
(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) && \
#endif
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) \
static void MapGameButtons();
static void HandleGameButtons(struct GadgetInfo *);
+int AmoebeNachbarNr(int, int);
+void AmoebeUmwandeln(int, int);
+void ContinueMoving(int, int);
+void Bang(int, int);
+void InitMovDir(int, int);
+void InitAmoebaNr(int, int);
+int NewHiScore(void);
+
+void TestIfGoodThingHitsBadThing(int, int, int);
+void TestIfBadThingHitsGoodThing(int, int, int);
+void TestIfPlayerTouchesBadThing(int, int);
+void TestIfPlayerRunsIntoBadThing(int, int, int);
+void TestIfBadThingTouchesPlayer(int, int);
+void TestIfBadThingRunsIntoPlayer(int, int, int);
+void TestIfFriendTouchesBadThing(int, int);
+void TestIfBadThingTouchesFriend(int, int);
+void TestIfBadThingTouchesOtherBadThing(int, int);
+
+void KillPlayer(struct PlayerInfo *);
+void BuryPlayer(struct PlayerInfo *);
+void RemovePlayer(struct PlayerInfo *);
+
+boolean SnapField(struct PlayerInfo *, int, int);
+boolean DropElement(struct PlayerInfo *);
+
+
static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
static void InitMagicBallDelay(int, int);
static void ActivateMagicBall(int, int);
-static void InitAndroid(int, int);
+static void InitDiagonalMovingElement(int, int);
struct ChangingElementInfo
{
NULL
},
{
- EL_EMC_ANDROID_SHRINKING,
- EL_EMPTY,
- 8,
+ EL_DIAGONAL_SHRINKING,
+ EL_UNDEFINED,
+ 0,
NULL,
NULL,
NULL
},
{
- EL_EMC_ANDROID_GROWING,
- EL_EMC_ANDROID,
- 8,
+ EL_DIAGONAL_GROWING,
+ EL_UNDEFINED,
+ 0,
NULL,
NULL,
- InitAndroid
+ InitDiagonalMovingElement
},
{
(x) >= 0 && (x) <= lev_fieldx - 1; \
(x) += playfield_scan_delta_x) \
+#ifdef DEBUG
+void DEBUG_SetMaximumDynamite()
+{
+ int i;
+
+ for (i = 0; i < MAX_INVENTORY_SIZE; i++)
+ if (local_player->inventory_size < MAX_INVENTORY_SIZE)
+ local_player->inventory_element[local_player->inventory_size++] =
+ EL_DYNAMITE;
+}
+#endif
+
static void InitPlayfieldScanModeVars()
{
if (game.use_reverse_scan_direction)
return belt_move_dir[belt_dir_nr];
}
+static int get_element_from_group_element(int element)
+{
+ if (IS_GROUP_ELEMENT(element))
+ {
+ struct ElementGroupInfo *group = element_info[element].group;
+ int last_anim_random_frame = gfx.anim_random_frame;
+ int element_pos;
+
+ if (group->choice_mode == ANIM_RANDOM)
+ gfx.anim_random_frame = RND(group->num_elements_resolved);
+
+ element_pos = getAnimationFrame(group->num_elements_resolved, 1,
+ group->choice_mode, 0,
+ group->choice_pos);
+
+ if (group->choice_mode == ANIM_RANDOM)
+ gfx.anim_random_frame = last_anim_random_frame;
+
+ group->choice_pos++;
+
+ element = group->element_resolved[element_pos];
+ }
+
+ return element;
+}
+
static void InitPlayerField(int x, int y, int element, boolean init_game)
{
if (element == EL_SP_MURPHY)
else
{
stored_player[0].use_murphy = TRUE;
+
+ if (!level.use_artwork_element[0])
+ stored_player[0].artwork_element = EL_SP_MURPHY;
}
Feld[x][y] = EL_PLAYER_1;
Feld[x][y] = EL_ACID_POOL_BOTTOMRIGHT;
break;
+ case EL_BUG:
case EL_BUG_RIGHT:
case EL_BUG_UP:
case EL_BUG_LEFT:
case EL_BUG_DOWN:
- case EL_BUG:
+ case EL_SPACESHIP:
case EL_SPACESHIP_RIGHT:
case EL_SPACESHIP_UP:
case EL_SPACESHIP_LEFT:
case EL_SPACESHIP_DOWN:
- case EL_SPACESHIP:
+ case EL_BD_BUTTERFLY:
case EL_BD_BUTTERFLY_RIGHT:
case EL_BD_BUTTERFLY_UP:
case EL_BD_BUTTERFLY_LEFT:
case EL_BD_BUTTERFLY_DOWN:
- case EL_BD_BUTTERFLY:
+ case EL_BD_FIREFLY:
case EL_BD_FIREFLY_RIGHT:
case EL_BD_FIREFLY_UP:
case EL_BD_FIREFLY_LEFT:
case EL_BD_FIREFLY_DOWN:
- case EL_BD_FIREFLY:
case EL_PACMAN_RIGHT:
case EL_PACMAN_UP:
case EL_PACMAN_LEFT:
case EL_PACMAN_DOWN:
case EL_YAMYAM:
+ case EL_YAMYAM_LEFT:
+ case EL_YAMYAM_RIGHT:
+ case EL_YAMYAM_UP:
+ case EL_YAMYAM_DOWN:
case EL_DARK_YAMYAM:
case EL_ROBOT:
case EL_PACMAN:
case EL_SP_SNIKSNAK:
case EL_SP_ELECTRON:
+ case EL_MOLE:
case EL_MOLE_LEFT:
case EL_MOLE_RIGHT:
case EL_MOLE_UP:
case EL_MOLE_DOWN:
- case EL_MOLE:
InitMovDir(x, y);
break;
MovDelay[x][y] = 96;
break;
+ case EL_EM_DYNAMITE_ACTIVE:
+ MovDelay[x][y] = 32;
+ break;
+
case EL_LAMP:
local_player->lights_still_needed++;
break;
#if USE_NEW_CUSTOM_VALUE
if (!element_info[element].use_last_ce_value || init_game)
- CustomValue[x][y] = GET_NEW_CUSTOM_VALUE(Feld[x][y]);
+ CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]);
#endif
}
#else
#endif
else if (IS_GROUP_ELEMENT(element))
{
+#if 1
+ Feld[x][y] = get_element_from_group_element(element);
+
+ InitField(x, y, init_game);
+#else
struct ElementGroupInfo *group = element_info[element].group;
int last_anim_random_frame = gfx.anim_random_frame;
int element_pos;
Feld[x][y] = group->element_resolved[element_pos];
InitField(x, y, init_game);
+#endif
}
break;
}
#if USE_NEW_CUSTOM_VALUE
#if 1
- CustomValue[x][y] = GET_NEW_CUSTOM_VALUE(Feld[x][y]);
+ CustomValue[x][y] = GET_NEW_CE_VALUE(Feld[x][y]);
#else
CustomValue[x][y] = element_info[Feld[x][y]].custom_value_initial;
#endif
inline void DrawGameValue_Keys(int key[MAX_NUM_KEYS])
{
+ int base_key_graphic = EL_KEY_1;
int i;
+ if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+ base_key_graphic = EL_EM_KEY_1;
+
/* currently only 4 of 8 possible keys are displayed */
for (i = 0; i < STD_NUM_KEYS; i++)
{
if (key[i])
DrawMiniGraphicExt(drawto, DX_KEYS + i * MINI_TILEX, DY_KEYS,
- el2edimg(EL_KEY_1 + i));
+ el2edimg(base_key_graphic + i));
else
BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
DOOR_GFX_PAGEX5 + XX_KEYS + i * MINI_TILEX, YY_KEYS,
void DrawGameDoorValues()
{
- int i;
+ int dynamite_state = 0;
+ int key_bits = 0;
+ int i, j;
if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
{
return;
}
+#if 0
DrawGameValue_Level(level_nr);
DrawGameValue_Emeralds(local_player->gems_still_needed);
DrawGameValue_Score(local_player->score);
DrawGameValue_Time(TimeLeft);
- for (i = 0; i < MAX_PLAYERS; i++)
+#else
+
+ if (game.centered_player_nr == -1)
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ for (j = 0; j < MAX_NUM_KEYS; j++)
+ if (stored_player[i].key[j])
+ key_bits |= (1 << j);
+
+ dynamite_state += stored_player[i].inventory_size;
+ }
+
+#if 0
DrawGameValue_Keys(stored_player[i].key);
+#endif
+ }
+ else
+ {
+ int player_nr = game.centered_player_nr;
+
+ for (i = 0; i < MAX_NUM_KEYS; i++)
+ if (stored_player[player_nr].key[i])
+ key_bits |= (1 << i);
+
+ dynamite_state = stored_player[player_nr].inventory_size;
+ }
+
+ DrawAllGameValues(local_player->gems_still_needed, dynamite_state,
+ local_player->score, TimeLeft, key_bits);
+#endif
}
+#if 0
static void resolve_group_element(int group_element, int recursion_depth)
{
static int group_nr;
}
}
}
-
+#endif
/*
=============================================================================
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 --------------------- */
ei->change_page[j].actual_trigger_player = EL_PLAYER_1;
ei->change_page[j].actual_trigger_side = CH_SIDE_NONE;
ei->change_page[j].actual_trigger_ce_value = 0;
+ ei->change_page[j].actual_trigger_ce_score = 0;
}
}
break;
}
+#if 0
+ printf("::: %d->%d: %d\n", action_first, action_last, num_special_action);
+#endif
+
return num_special_action;
}
player->is_pushing = FALSE;
player->is_switching = FALSE;
player->is_dropping = FALSE;
+ player->is_dropping_pressed = FALSE;
player->is_bored = FALSE;
player->is_sleeping = FALSE;
player->anim_delay_counter = 0;
player->post_delay_counter = 0;
+ player->dir_waiting = MV_NONE;
player->action_waiting = ACTION_DEFAULT;
player->last_action_waiting = ACTION_DEFAULT;
player->special_action_bored = ACTION_DEFAULT;
player->special_action_sleeping = ACTION_DEFAULT;
+#if 1
+ /* cannot be set here -- could be modified in Init[Player]Field() below */
+#else
/* set number of special actions for bored and sleeping animation */
player->num_special_action_bored =
get_num_special_action(player->artwork_element,
player->num_special_action_sleeping =
get_num_special_action(player->artwork_element,
ACTION_SLEEPING_1, ACTION_SLEEPING_LAST);
+#endif
player->switch_x = -1;
player->switch_y = -1;
player->push_delay_value = game.initial_push_delay_value;
player->drop_delay = 0;
+ player->drop_pressed_delay = 0;
player->last_jx = player->last_jy = 0;
player->jx = player->jy = 0;
game.envelope_active = FALSE;
+ /* set focus to local player for network games, else to all players */
+ game.centered_player_nr = (network_playing ? local_player->index_nr : -1);
+ game.centered_player_nr_next = game.centered_player_nr;
+ game.set_centered_player = FALSE;
+
+ if (network_playing && tape.recording)
+ {
+ /* store client dependent player focus when recording network games */
+ tape.centered_player_nr_next = game.centered_player_nr_next;
+ tape.set_centered_player = TRUE;
+ }
+
+#if 0
+ printf("::: focus set to player %d [%d]\n",
+ game.centered_player_nr, local_player->index_nr);
+#endif
+
for (i = 0; i < NUM_BELTS; i++)
{
game.belt_dir[i] = MV_NONE;
InitBeltMovement();
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+
+#if 1
+ /* set number of special actions for bored and sleeping animation */
+ player->num_special_action_bored =
+ get_num_special_action(player->artwork_element,
+ ACTION_BORING_1, ACTION_BORING_LAST);
+ player->num_special_action_sleeping =
+ get_num_special_action(player->artwork_element,
+ ACTION_SLEEPING_1, ACTION_SLEEPING_LAST);
+#endif
+
+ }
+
game.emulation = (emulate_bd ? EMU_BOULDERDASH :
emulate_sb ? EMU_SOKOBAN :
emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
if (tape.playing)
{
- /* when playing a tape, eliminate all players which do not participate */
+ /* when playing a tape, eliminate all players who do not participate */
for (i = 0; i < MAX_PLAYERS; i++)
{
MovDir[x][y] = direction[0][element - EL_PACMAN_RIGHT];
break;
+ case EL_YAMYAM_LEFT:
+ case EL_YAMYAM_RIGHT:
+ case EL_YAMYAM_UP:
+ case EL_YAMYAM_DOWN:
+ Feld[x][y] = EL_YAMYAM;
+ MovDir[x][y] = direction[2][element - EL_YAMYAM_LEFT];
+ break;
+
case EL_SP_SNIKSNAK:
MovDir[x][y] = MV_UP;
break;
BackToFront();
+#if 0
+ if (tape.playing)
+ printf("::: TAPE PLAYING -> DO NOT SAVE SCORE\n");
+ else
+ printf("::: NO TAPE PLAYING -> SAVING SCORE\n");
+#endif
+
if (tape.playing)
return;
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 */
Bang(x, y);
}
-void DrawRelocatePlayer(struct PlayerInfo *player)
+#if 1
+
+static void setMinimalPlayerBoundaries(int *sx1, int *sy1, int *sx2, int *sy2)
+{
+ boolean num_checked_players = 0;
+ int i;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ if (stored_player[i].active)
+ {
+ int sx = stored_player[i].jx;
+ int sy = stored_player[i].jy;
+
+ if (num_checked_players == 0)
+ {
+ *sx1 = *sx2 = sx;
+ *sy1 = *sy2 = sy;
+ }
+ else
+ {
+ *sx1 = MIN(*sx1, sx);
+ *sy1 = MIN(*sy1, sy);
+ *sx2 = MAX(*sx2, sx);
+ *sy2 = MAX(*sy2, sy);
+ }
+
+ num_checked_players++;
+ }
+ }
+}
+
+static boolean checkIfAllPlayersFitToScreen_RND()
+{
+ int sx1 = 0, sy1 = 0, sx2 = 0, sy2 = 0;
+
+ setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+ return (sx2 - sx1 < SCR_FIELDX &&
+ sy2 - sy1 < SCR_FIELDY);
+}
+
+static void setScreenCenteredToAllPlayers(int *sx, int *sy)
+{
+ int sx1 = scroll_x, sy1 = scroll_y, sx2 = scroll_x, sy2 = scroll_y;
+
+ setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+ *sx = (sx1 + sx2) / 2;
+ *sy = (sy1 + sy2) / 2;
+}
+
+#if 0
+static void setMaxCenterDistanceForAllPlayers(int *max_dx, int *max_dy,
+ int center_x, int center_y)
+{
+ int sx1 = center_x, sy1 = center_y, sx2 = center_x, sy2 = center_y;
+
+ setMinimalPlayerBoundaries(&sx1, &sy1, &sx2, &sy2);
+
+ *max_dx = MAX(ABS(sx1 - center_x), ABS(sx2 - center_x));
+ *max_dy = MAX(ABS(sy1 - center_y), ABS(sy2 - center_y));
+}
+
+static boolean checkIfAllPlayersAreVisible(int center_x, int center_y)
+{
+ int max_dx, max_dy;
+
+ setMaxCenterDistanceForAllPlayers(&max_dx, &max_dy, center_x, center_y);
+
+ return (max_dx <= SCR_FIELDX / 2 &&
+ max_dy <= SCR_FIELDY / 2);
+}
+#endif
+
+#endif
+
+#if 1
+
+void DrawRelocateScreen(int x, int y, int move_dir, boolean center_screen,
+ boolean quick_relocation)
+{
+ boolean ffwd_delay = (tape.playing && tape.fast_forward);
+ boolean no_delay = (tape.warp_forward);
+ int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+ int wait_delay_value = (no_delay ? 0 : frame_delay_value);
+
+ if (quick_relocation)
+ {
+ int offset = (setup.scroll_delay ? 3 : 0);
+
+#if 0
+ if (center_screen)
+ offset = 0;
+#endif
+
+ if (!IN_VIS_FIELD(SCREENX(x), SCREENY(y)) || center_screen)
+ {
+ scroll_x = (x < SBX_Left + MIDPOSX ? SBX_Left :
+ x > SBX_Right + MIDPOSX ? SBX_Right :
+ x - MIDPOSX);
+
+ scroll_y = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
+ y > SBY_Lower + MIDPOSY ? SBY_Lower :
+ y - MIDPOSY);
+ }
+ else
+ {
+ if ((move_dir == MV_LEFT && scroll_x > x - MIDPOSX + offset) ||
+ (move_dir == MV_RIGHT && scroll_x < x - MIDPOSX - offset))
+ scroll_x = x - MIDPOSX + (scroll_x < x - MIDPOSX ? -offset : +offset);
+
+ if ((move_dir == MV_UP && scroll_y > y - MIDPOSY + offset) ||
+ (move_dir == MV_DOWN && scroll_y < y - MIDPOSY - offset))
+ scroll_y = y - MIDPOSY + (scroll_y < y - MIDPOSY ? -offset : +offset);
+
+ /* don't scroll over playfield boundaries */
+ if (scroll_x < SBX_Left || scroll_x > SBX_Right)
+ scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
+
+ /* don't scroll over playfield boundaries */
+ if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
+ scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
+ }
+
+ RedrawPlayfield(TRUE, 0,0,0,0);
+ }
+ else
+ {
+ int scroll_xx = (x < SBX_Left + MIDPOSX ? SBX_Left :
+ x > SBX_Right + MIDPOSX ? SBX_Right :
+ x - MIDPOSX);
+
+ int scroll_yy = (y < SBY_Upper + MIDPOSY ? SBY_Upper :
+ y > SBY_Lower + MIDPOSY ? SBY_Lower :
+ y - MIDPOSY);
+
+ ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */
+
+ while (scroll_x != scroll_xx || scroll_y != scroll_yy)
+ {
+ int dx = 0, dy = 0;
+ int fx = FX, fy = FY;
+
+ dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
+ dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
+
+ if (dx == 0 && dy == 0) /* no scrolling needed at all */
+ break;
+
+ scroll_x -= dx;
+ scroll_y -= dy;
+
+ fx += dx * TILEX / 2;
+ fy += dy * TILEY / 2;
+
+ ScrollLevel(dx, dy);
+ DrawAllPlayers();
+
+ /* scroll in two steps of half tile size to make things smoother */
+ BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+ FlushDisplay();
+ Delay(wait_delay_value);
+
+ /* scroll second step to align at full tile size */
+ BackToFront();
+ Delay(wait_delay_value);
+ }
+
+ DrawAllPlayers();
+ BackToFront();
+ Delay(wait_delay_value);
+ }
+}
+
+#else
+
+void DrawRelocatePlayer(struct PlayerInfo *player, boolean quick_relocation)
{
boolean ffwd_delay = (tape.playing && tape.fast_forward);
boolean no_delay = (tape.warp_forward);
int jx = player->jx;
int jy = player->jy;
- if (level.instant_relocation)
+ if (quick_relocation)
{
int offset = (setup.scroll_delay ? 3 : 0);
if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
{
- scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left :
- local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
- local_player->jx - MIDPOSX);
+ scroll_x = (player->jx < SBX_Left + MIDPOSX ? SBX_Left :
+ player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+ player->jx - MIDPOSX);
- scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
- local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
- local_player->jy - MIDPOSY);
+ scroll_y = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+ player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+ player->jy - MIDPOSY);
}
else
{
}
else
{
- int scroll_xx = -999, scroll_yy = -999;
+ int scroll_xx = (player->jx < SBX_Left + MIDPOSX ? SBX_Left :
+ player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+ player->jx - MIDPOSX);
+
+ int scroll_yy = (player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+ player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+ player->jy - MIDPOSY);
ScrollScreen(NULL, SCROLL_GO_ON); /* scroll last frame to full tile */
- while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+ while (scroll_x != scroll_xx || scroll_y != scroll_yy)
{
int dx = 0, dy = 0;
int fx = FX, fy = FY;
- scroll_xx = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left :
- local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
- local_player->jx - MIDPOSX);
-
- scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
- local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
- local_player->jy - MIDPOSY);
-
dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
}
}
+#endif
+
void RelocatePlayer(int jx, int jy, int el_player_raw)
{
int el_player = GET_PLAYER_ELEMENT(el_player_raw);
InitField(jx, jy, FALSE);
}
+#if 1
+ /* only visually relocate centered player */
+#if 1
+ DrawRelocateScreen(player->jx, player->jy, player->MovDir, FALSE,
+ level.instant_relocation);
+#else
+ if (player->index_nr == game.centered_player_nr)
+ DrawRelocatePlayer(player, level.instant_relocation);
+#endif
+#else
if (player == local_player) /* only visually relocate local player */
- DrawRelocatePlayer(player);
+ DrawRelocatePlayer(player, level.instant_relocation);
+#endif
TestIfPlayerTouchesBadThing(jx, jy);
TestIfPlayerTouchesCustomElement(jx, jy);
Feld[x][y] = EL_EXPLOSION;
GfxElement[x][y] = artwork_element;
+#if 0
+ printf(":: setting gfx(%d,%d) to %d ['%s']\n",
+ x, y, artwork_element, EL_NAME(artwork_element));
+#endif
+
ExplodePhase[x][y] = 1;
ExplodeDelay[x][y] = last_phase;
#endif
#if 1
+#if 1
+ /* this can happen if the player leaves an explosion just in time */
+ if (GfxElement[x][y] == EL_UNDEFINED)
+ GfxElement[x][y] = EL_EMPTY;
+#else
if (GfxElement[x][y] == EL_UNDEFINED)
{
printf("\n\n");
GfxElement[x][y] = EL_EMPTY;
}
+#endif
+
#endif
border_element = Store2[x][y];
{ -1, +1, MV_LEFT | MV_DOWN },
{ -1, 0, MV_LEFT },
};
- int check_order = (RND(2) ? -1 : +1);
- int start_pos = check_pos[MovDir[x][y] & 0x0f];
+ int start_pos, check_order;
+ boolean can_clone = FALSE;
int i;
- MovDelay[x][y] = level.android_move_time * 8 + 1;
+ /* 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 (start_pos < 0) /* (should never happen) */
+ 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++)
{
- int pos_raw = start_pos + (i == 0 ? 0 : i == 1 ? 1 : -1) * check_order;
+ /* 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))
- return;
+ break;
if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
{
MovDir[x][y] = new_move_dir;
+ MovDelay[x][y] = level.android_move_time * 8 + 1;
- return;
+ break;
}
}
}
static void TurnRound(int x, int y)
{
int direction = MovDir[x][y];
+#if 1
+ int element, graphic;
+#endif
TurnRoundExt(x, y);
if (MovDelay[x][y])
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 (element == EL_EMC_ANDROID && IN_LEV_FIELD(newx, newy))
{
- if (MovDir[x][y] & MV_HORIZONTAL && MovDir[x][y] & MV_VERTICAL &&
- ANDROID_CAN_ENTER_FIELD(element, newx, newy))
+ if (Store[x][y] != EL_EMPTY)
{
- /* android is moving diagonally */
+ boolean can_clone = FALSE;
+ int xx, yy;
- CreateField(x, y, EL_EMC_ANDROID_SHRINKING);
+ /* 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;
-#if 0
- CheckTriggeredElementChangeBySide(x, y, element,
- CE_MOVE_OF_X, new_move_dir);
+ 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;
+ }
- TestIfElementTouchesCustomElement(x, y); /* empty or new element */
+ 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;
- TestIfElementHitsCustomElement(newx, newy, new_move_dir);
- TestIfElementTouchesCustomElement(newx, newy);
-#endif
+ /* android is moving diagonally */
- CreateField(newx, newy, EL_EMC_ANDROID_GROWING);
+ CreateField(x, y, EL_DIAGONAL_SHRINKING);
- return;
- }
- else if (ANDROID_CAN_ENTER_FIELD(element, newx, newy))
- {
- Feld[newx][newy] = EL_EMPTY;
- DrawLevelField(newx, newy);
+ 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);
+ PlayLevelSoundAction(x, y, ACTION_DIGGING);
+ }
}
else if (!IS_FREE(newx, newy))
{
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 &&
int nextx = newx + dx, nexty = newy + dy;
boolean check_collision_again = IN_LEV_FIELD_AND_IS_FREE(nextx, nexty);
- WasJustMoving[newx][newy] = 3;
+ WasJustMoving[newx][newy] = CHECK_DELAY_MOVING;
if (CAN_FALL(element) && direction == MV_DOWN)
- WasJustFalling[newx][newy] = 3;
+ WasJustFalling[newx][newy] = CHECK_DELAY_FALLING;
if ((!CAN_FALL(element) || direction == MV_DOWN) && check_collision_again)
- CheckCollision[newx][newy] = 2;
+ CheckCollision[newx][newy] = CHECK_DELAY_COLLISION;
}
if (DONT_TOUCH(element)) /* object may be nasty to player or others */
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);
game.ball_content_nr = (game.ball_content_nr + 1) % level.num_ball_contents;
}
-static void InitAndroid(int x, int y)
+static void InitDiagonalMovingElement(int x, int y)
{
+#if 0
MovDelay[x][y] = level.android_move_time;
+#endif
}
void CheckExit(int x, int y)
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);
{
struct ElementInfo *ei = &element_info[element];
struct ElementChangeInfo *change = &ei->change_page[page];
+ int target_element = change->target_element;
int action_type = change->action_type;
int action_mode = change->action_mode;
int action_arg = change->action_arg;
action_type == CA_SET_LEVEL_GEMS ? 999 :
action_type == CA_SET_LEVEL_TIME ? 9999 :
action_type == CA_SET_LEVEL_SCORE ? 99999 :
- action_type == CA_SET_CE_SCORE ? 9999 :
action_type == CA_SET_CE_VALUE ? 9999 :
+ action_type == CA_SET_CE_SCORE ? 9999 :
CA_ARG_MAX);
int action_arg_number_reset =
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_type == CA_SET_CE_SCORE ? 0 :
#if 1
- action_type == CA_SET_CE_VALUE ? GET_NEW_CUSTOM_VALUE(element) :
+ action_type == CA_SET_CE_VALUE ? GET_NEW_CE_VALUE(element) :
#else
action_type == CA_SET_CE_VALUE ? ei->custom_value_initial :
#endif
+ action_type == CA_SET_CE_SCORE ? 0 :
0);
int action_arg_number =
action_arg == CA_ARG_NUMBER_MIN ? action_arg_number_min :
action_arg == CA_ARG_NUMBER_MAX ? action_arg_number_max :
action_arg == CA_ARG_NUMBER_RESET ? action_arg_number_reset :
- action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score :
#if USE_NEW_CUSTOM_VALUE
action_arg == CA_ARG_NUMBER_CE_VALUE ? CustomValue[x][y] :
#else
action_arg == CA_ARG_NUMBER_CE_VALUE ? ei->custom_value_initial :
#endif
+ action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score :
action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CE_DELAY_VALUE(change) :
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_CE_VALUE(target_element):
+ action_arg == CA_ARG_ELEMENT_CV_TRIGGER ? change->actual_trigger_ce_value:
+ action_arg == CA_ARG_ELEMENT_CS_TARGET ? GET_CE_SCORE(target_element) :
+ action_arg == CA_ARG_ELEMENT_CS_TRIGGER ? change->actual_trigger_ce_score:
+ 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 =
(action_type == CA_SET_LEVEL_GEMS ? local_player->gems_still_needed :
action_type == CA_SET_LEVEL_TIME ? TimeLeft :
action_type == CA_SET_LEVEL_SCORE ? local_player->score :
- action_type == CA_SET_CE_SCORE ? ei->collect_score :
action_type == CA_SET_CE_VALUE ? CustomValue[x][y] :
+ action_type == CA_SET_CE_SCORE ? ei->collect_score :
0);
int action_arg_number_new =
{
stored_player[i].key[KEY_NR(element)] = key_state;
+#if 1
+ DrawGameDoorValues();
+#else
DrawGameValue_Keys(stored_player[i].key);
+#endif
redraw_mask |= REDRAW_DOOR_1;
}
/* ---------- CE actions ---------------------------------------------- */
- case CA_SET_CE_SCORE:
- {
- ei->collect_score = action_arg_number_new;
-
- break;
- }
-
case CA_SET_CE_VALUE:
{
#if USE_NEW_CUSTOM_VALUE
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;
}
+ case CA_SET_CE_SCORE:
+ {
+ ei->collect_score = action_arg_number_new;
+
+ break;
+ }
+
/* ---------- engine actions ------------------------------------------ */
case CA_SET_ENGINE_SCAN_MODE:
static void CreateFieldExt(int x, int y, int element, boolean is_change)
{
+ int old_element = Feld[x][y];
+ int new_element = get_element_from_group_element(element);
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(element) &&
- IS_WALKABLE(Feld[x][y]));
+ boolean add_player = (ELEM_IS_PLAYER(new_element) &&
+ IS_WALKABLE(old_element));
+#if 0
/* 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(element))
+ IS_ACCESSIBLE(old_element) && !IS_ACCESSIBLE(new_element))
{
Bang(x, y);
return;
}
+#endif
if (!add_player)
{
else
RemoveField(x, y);
- Feld[x][y] = element;
+ Feld[x][y] = new_element;
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
- if (element_info[Feld[x][y]].move_direction_initial == MV_START_PREVIOUS)
+ if (element_info[new_element].move_direction_initial == MV_START_PREVIOUS)
MovDir[x][y] = previous_move_direction;
#if USE_NEW_CUSTOM_VALUE
- if (element_info[Feld[x][y]].use_last_ce_value)
+ if (element_info[new_element].use_last_ce_value)
CustomValue[x][y] = last_ce_value;
#endif
InitField_WithBug1(x, y, FALSE);
+ new_element = Feld[x][y]; /* element may have changed */
+
DrawLevelField(x, y);
- if (GFX_CRUMBLED(Feld[x][y]))
+ if (GFX_CRUMBLED(new_element))
DrawLevelFieldCrumbledSandNeighbours(x, y);
}
+#if 1
+ /* 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(old_element) && !IS_ACCESSIBLE(new_element))
+ {
+ Bang(x, y);
+
+ return;
+ }
+#endif
+
/* "ChangeCount" not set yet to allow "entered by player" change one time */
- if (ELEM_IS_PLAYER(element))
- RelocatePlayer(x, y, element);
+ if (ELEM_IS_PLAYER(new_element))
+ RelocatePlayer(x, y, new_element);
if (is_change)
ChangeCount[x][y]++; /* count number of changes in the same frame */
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];
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementChangeInfo *change = &ei->change_page[page];
+ int ce_value = CustomValue[x][y];
+ int ce_score = ei->collect_score;
int target_element;
int old_element = Feld[x][y];
change->actual_trigger_player = EL_PLAYER_1;
change->actual_trigger_side = CH_SIDE_NONE;
change->actual_trigger_ce_value = 0;
+ change->actual_trigger_ce_score = 0;
}
/* do not change elements more than a specified maximum number of changes */
ChangeEvent[ex][ey] = ChangeEvent[x][y];
content_element = change->target_content.e[xx][yy];
- target_element = GET_TARGET_ELEMENT(content_element, change);
+ target_element = GET_TARGET_ELEMENT(content_element, change,
+ ce_value, ce_score);
CreateElementFromChange(ex, ey, target_element);
}
else
{
- target_element = GET_TARGET_ELEMENT(change->target_element, change);
+ target_element = GET_TARGET_ELEMENT(change->target_element, change,
+ ce_value, ce_score);
+
+ if (element == EL_DIAGONAL_GROWING ||
+ element == EL_DIAGONAL_SHRINKING)
+ {
+ target_element = Store[x][y];
+
+ Store[x][y] = EL_EMPTY;
+ }
CreateElementFromChange(x, y, target_element);
change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
change->actual_trigger_side = trigger_side;
change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y];
+ change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
if ((change->can_change && !change_done) || 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++)
{
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_score = GET_CE_SCORE(trigger_element);
/* special case: trigger element not at (x,y) position for some events */
if (check_trigger_element)
int yy = y + move_xy[MV_DIR_OPPOSITE(trigger_side)].dy;
change->actual_trigger_ce_value = CustomValue[xx][yy];
+ change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element);
}
if (change->can_change && !change_done)
boolean last_waiting = player->is_waiting;
int move_dir = player->MovDir;
+ player->dir_waiting = move_dir;
player->last_action_waiting = player->action_waiting;
if (is_waiting)
game.player_sleeping_delay_fixed +
SimpleRND(game.player_sleeping_delay_random);
+#if 1
+ InitPlayerGfxAnimation(player, ACTION_WAITING, move_dir);
+#else
InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir);
+#endif
}
if (game.player_sleeping_delay_fixed +
player->is_bored ? ACTION_BORING :
ACTION_WAITING);
+#if 1
+ if (player->is_sleeping && player->use_murphy)
+ {
+ /* 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 &&
+ !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 &&
+ !IS_MOVING(player->jx + 1, player->jy)))
+ move_dir = MV_RIGHT;
+ else
+ player->is_sleeping = FALSE;
+
+ player->dir_waiting = move_dir;
+ }
+#endif
+
if (player->is_sleeping)
{
if (player->num_special_action_sleeping > 0)
player->anim_delay_counter = 0;
player->post_delay_counter = 0;
+ player->dir_waiting = player->MovDir;
player->action_waiting = ACTION_DEFAULT;
player->special_action_bored = ACTION_DEFAULT;
int down = player_action & JOY_DOWN;
int button1 = player_action & JOY_BUTTON_1;
int button2 = player_action & JOY_BUTTON_2;
- int dx = (left ? -1 : right ? 1 : 0);
- int dy = (up ? -1 : down ? 1 : 0);
+ int dx = (left ? -1 : right ? 1 : 0);
+ int dy = (up ? -1 : down ? 1 : 0);
if (!player->active || tape.pausing)
return 0;
player->is_moving = FALSE;
player->is_dropping = FALSE;
+ player->is_dropping_pressed = FALSE;
+ player->drop_pressed_delay = 0;
return 0;
}
}
+static void CheckLevelTime()
+{
+ int i;
+
+ if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+ {
+ if (level.native_em_level->lev->home == 0) /* all players at home */
+ {
+ local_player->LevelSolved = TRUE;
+ AllPlayersGone = TRUE;
+
+ level.native_em_level->lev->home = -1;
+ }
+
+ if (level.native_em_level->ply[0]->alive == 0 &&
+ level.native_em_level->ply[1]->alive == 0 &&
+ level.native_em_level->ply[2]->alive == 0 &&
+ level.native_em_level->ply[3]->alive == 0) /* all dead */
+ AllPlayersGone = TRUE;
+ }
+
+ if (TimeFrames >= FRAMES_PER_SECOND)
+ {
+ TimeFrames = 0;
+ TapeTime++;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+
+ if (SHIELD_ON(player))
+ {
+ player->shield_normal_time_left--;
+
+ if (player->shield_deadly_time_left > 0)
+ player->shield_deadly_time_left--;
+ }
+ }
+
+ if (!level.use_step_counter)
+ {
+ TimePlayed++;
+
+ if (TimeLeft > 0)
+ {
+ TimeLeft--;
+
+ if (TimeLeft <= 10 && setup.time_limit)
+ PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
+
+ DrawGameValue_Time(TimeLeft);
+
+ if (!TimeLeft && setup.time_limit)
+ {
+ if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+ level.native_em_level->lev->killed_out_of_time = TRUE;
+ else
+ for (i = 0; i < MAX_PLAYERS; i++)
+ KillPlayer(&stored_player[i]);
+ }
+ }
+ else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
+ DrawGameValue_Time(TimePlayed);
+
+ level.native_em_level->lev->time =
+ (level.time == 0 ? TimePlayed : TimeLeft);
+ }
+
+ if (tape.recording || tape.playing)
+ DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
+ }
+}
+
void AdvanceFrameAndPlayerCounters(int player_nr)
{
int i;
+#if 0
+ Error(ERR_NETWORK_CLIENT, "advancing frame counter from %d to %d",
+ FrameCounter, FrameCounter + 1);
+#endif
+
/* advance frame counters (global frame counter and time frame counter) */
FrameCounter++;
TimeFrames++;
if (stored_player[i].drop_delay > 0)
stored_player[i].drop_delay--;
+
+ if (stored_player[i].is_dropping_pressed)
+ stored_player[i].drop_pressed_delay++;
+ }
+}
+
+void StartGameActions(boolean init_network_game, boolean record_tape,
+ long random_seed)
+{
+ unsigned long new_random_seed = InitRND(random_seed);
+
+ if (record_tape)
+ TapeStartRecording(new_random_seed);
+
+#if defined(NETWORK_AVALIABLE)
+ if (init_network_game)
+ {
+ SendToServer_StartPlaying();
+
+ return;
+ }
+#endif
+
+ StopAnimation();
+
+ game_status = GAME_MODE_PLAYING;
+
+ InitGame();
+}
+
+void GameActions()
+{
+ static unsigned long game_frame_delay = 0;
+ unsigned long game_frame_delay_value;
+ byte *recorded_player_action;
+ byte summarized_player_action = 0;
+ byte tape_action[MAX_PLAYERS];
+ int i;
+
+ if (game.restart_level)
+ StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE);
+
+ if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+ {
+ if (level.native_em_level->lev->home == 0) /* all players at home */
+ {
+ local_player->LevelSolved = TRUE;
+ AllPlayersGone = TRUE;
+
+ level.native_em_level->lev->home = -1;
+ }
+
+ if (level.native_em_level->ply[0]->alive == 0 &&
+ level.native_em_level->ply[1]->alive == 0 &&
+ level.native_em_level->ply[2]->alive == 0 &&
+ level.native_em_level->ply[3]->alive == 0) /* all dead */
+ AllPlayersGone = TRUE;
}
-}
-void GameActions()
-{
- static unsigned long game_frame_delay = 0;
- unsigned long game_frame_delay_value;
- int magic_wall_x = 0, magic_wall_y = 0;
- int i, x, y, element, graphic;
- byte *recorded_player_action;
- byte summarized_player_action = 0;
- byte tape_action[MAX_PLAYERS];
+ if (local_player->LevelSolved)
+ GameWon();
- if (game_status != GAME_MODE_PLAYING)
+ if (AllPlayersGone && !TAPE_IS_STOPPED(tape))
+ TapeStop();
+
+ if (game_status != GAME_MODE_PLAYING) /* status might have changed */
return;
game_frame_delay_value =
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 (!network_player_action_received)
return; /* failed to get network player actions in time */
+
+ /* do not yet reset "network_player_action_received" (for tape.pausing) */
}
if (tape.pausing)
return;
- recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
+ /* at this point we know that we really continue executing the game */
#if 1
- /* !!! CHECK THIS (tape.pausing is always FALSE here!) !!! */
- if (recorded_player_action == NULL && tape.pausing)
- return;
+ network_player_action_received = FALSE;
#endif
+ recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
+
+ if (tape.set_centered_player)
+ {
+ game.centered_player_nr_next = tape.centered_player_nr_next;
+ game.set_centered_player = TRUE;
+ }
+
for (i = 0; i < MAX_PLAYERS; i++)
{
summarized_player_action |= stored_player[i].action;
if (!options.network && !setup.team_mode)
local_player->effective_action = summarized_player_action;
+ if (setup.team_mode && setup.input_on_focus && game.centered_player_nr != -1)
+ {
+ for (i = 0; i < MAX_PLAYERS; i++)
+ stored_player[i].effective_action =
+ (i == game.centered_player_nr ? summarized_player_action : 0);
+ }
+
if (recorded_player_action != NULL)
for (i = 0; i < MAX_PLAYERS; i++)
stored_player[i].effective_action = recorded_player_action[i];
{
tape_action[i] = stored_player[i].effective_action;
+ /* (this can only happen in the R'n'D game engine) */
if (tape.recording && tape_action[i] && !tape.player_participates[i])
tape.player_participates[i] = TRUE; /* player just appeared from CE */
}
- /* only save actions from input devices, but not programmed actions */
+ /* only record actions from input devices, but not programmed actions */
if (tape.recording)
TapeRecordAction(tape_action);
+ if (level.game_engine_type == GAME_ENGINE_TYPE_EM)
+ {
+ GameActions_EM_Main();
+ }
+ else
+ {
+ GameActions_RND();
+ }
+}
+
+void GameActions_EM_Main()
+{
+ 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);
+
+ CheckLevelTime();
+
+ AdvanceFrameAndPlayerCounters(-1); /* advance counters for all players */
+}
+
+void GameActions_RND()
+{
+ int magic_wall_x = 0, magic_wall_y = 0;
+ int i, x, y, element, graphic;
+
+ 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 1
+ if (game.set_centered_player)
+ {
+ boolean all_players_fit_to_screen = checkIfAllPlayersFitToScreen_RND();
+
+ /* switching to "all players" only possible if all players fit to screen */
+ if (game.centered_player_nr_next == -1 && !all_players_fit_to_screen)
+ {
+ game.centered_player_nr_next = game.centered_player_nr;
+ game.set_centered_player = FALSE;
+ }
+
+ /* do not switch focus to non-existing (or non-active) player */
+ if (game.centered_player_nr_next >= 0 &&
+ !stored_player[game.centered_player_nr_next].active)
+ {
+ game.centered_player_nr_next = game.centered_player_nr;
+ game.set_centered_player = FALSE;
+ }
+ }
+
+ if (game.set_centered_player &&
+ ScreenMovPos == 0) /* screen currently aligned at tile position */
+ {
+ int sx, sy;
+
+ if (game.centered_player_nr_next == -1)
+ {
+ setScreenCenteredToAllPlayers(&sx, &sy);
+ }
+ else
+ {
+ sx = stored_player[game.centered_player_nr_next].jx;
+ sy = stored_player[game.centered_player_nr_next].jy;
+ }
+
+ game.centered_player_nr = game.centered_player_nr_next;
+ game.set_centered_player = FALSE;
+
+ DrawRelocateScreen(sx, sy, MV_NONE, TRUE, setup.quick_switch);
+ DrawGameDoorValues();
+ }
+#endif
+
for (i = 0; i < MAX_PLAYERS; i++)
{
int actual_player_action = stored_player[i].effective_action;
ScrollPlayer(&stored_player[i], SCROLL_GO_ON);
}
+#if 0
network_player_action_received = FALSE;
+#endif
ScrollScreen(NULL, SCROLL_GO_ON);
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]);
}
}
- if (TimeFrames >= FRAMES_PER_SECOND)
- {
- TimeFrames = 0;
- TapeTime++;
-
- for (i = 0; i < MAX_PLAYERS; i++)
- {
- struct PlayerInfo *player = &stored_player[i];
-
- if (SHIELD_ON(player))
- {
- player->shield_normal_time_left--;
-
- if (player->shield_deadly_time_left > 0)
- player->shield_deadly_time_left--;
- }
- }
-
- if (!level.use_step_counter)
- {
- TimePlayed++;
-
- if (TimeLeft > 0)
- {
- TimeLeft--;
-
- if (TimeLeft <= 10 && setup.time_limit)
- PlaySoundStereo(SND_GAME_RUNNING_OUT_OF_TIME, SOUND_MIDDLE);
-
- DrawGameValue_Time(TimeLeft);
-
- if (!TimeLeft && setup.time_limit)
- for (i = 0; i < MAX_PLAYERS; i++)
- KillPlayer(&stored_player[i]);
- }
- else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
- DrawGameValue_Time(TimePlayed);
- }
-
- if (tape.recording || tape.playing)
- DrawVideoDisplay(VIDEO_STATE_TIME_ON, TapeTime);
- }
+ CheckLevelTime();
DrawAllPlayers();
PlayAllPlayersSound();
#endif
}
+#if 1
+ if (!options.network && game.centered_player_nr == -1 &&
+ !AllPlayersInSight(player, new_jx, new_jy))
+ return MP_NO_ACTION;
+#else
if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
return MP_NO_ACTION;
+#endif
#if !USE_FIXED_DONT_RUN_INTO
element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy);
jx = player->jx;
jy = player->jy;
+#if 1
+ if (moved & MP_MOVING && !ScreenMovPos &&
+ (player->index_nr == game.centered_player_nr ||
+ game.centered_player_nr == -1))
+#else
if (moved & MP_MOVING && !ScreenMovPos &&
(player == local_player || !options.network))
+#endif
{
int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
int offset = (setup.scroll_delay ? 3 : 0);
if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
{
+#if 1
+ if (!options.network && game.centered_player_nr == -1 &&
+ !AllPlayersInVisibleScreen())
+ {
+ scroll_x = old_scroll_x;
+ scroll_y = old_scroll_y;
+ }
+ else
+#else
if (!options.network && !AllPlayersInVisibleScreen())
{
scroll_x = old_scroll_x;
scroll_y = old_scroll_y;
}
else
+#endif
{
ScrollScreen(player, SCROLL_INIT);
ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
player->is_snapping = FALSE;
player->is_switching = FALSE;
player->is_dropping = FALSE;
+ player->is_dropping_pressed = FALSE;
+ player->drop_pressed_delay = 0;
}
else
{
}
}
+#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);
if (element == EL_SHIELD_DEADLY)
player->shield_deadly_time_left += level.shield_deadly_time;
}
- else if (element == EL_DYNAMITE || element == EL_SP_DISK_RED)
+ else if (element == EL_DYNAMITE ||
+ element == EL_EM_DYNAMITE ||
+ element == EL_SP_DISK_RED)
{
if (player->inventory_size < MAX_INVENTORY_SIZE)
player->inventory_element[player->inventory_size++] = element;
+#if 1
+ DrawGameDoorValues();
+#else
DrawGameValue_Dynamite(local_player->inventory_size);
+#endif
}
else if (element == EL_DYNABOMB_INCREASE_NUMBER)
{
{
player->key[KEY_NR(element)] = TRUE;
+#if 1
+ DrawGameDoorValues();
+#else
DrawGameValue_Keys(player->key);
+#endif
redraw_mask |= REDRAW_DOOR_1;
}
if (player->inventory_size < MAX_INVENTORY_SIZE)
player->inventory_element[player->inventory_size++] = element;
+#if 1
+ DrawGameDoorValues();
+#else
DrawGameValue_Dynamite(local_player->inventory_size);
+#endif
}
else if (collect_count > 0)
{
dx == +1 ? MV_RIGHT :
dy == -1 ? MV_UP :
dy == +1 ? MV_DOWN : MV_NONE);
+ boolean can_continue_snapping = (level.continuous_snapping &&
+ WasJustFalling[x][y] < CHECK_DELAY_FALLING);
if (player->MovPos != 0 && game.engine_version >= VERSION_IDENT(2,2,0,0))
return FALSE;
return FALSE;
}
+#if USE_NEW_CONTINUOUS_SNAPPING
+ /* prevent snapping with already pressed snap key when not allowed */
+ if (player->is_snapping && !can_continue_snapping)
+ return FALSE;
+#else
if (player->is_snapping)
return FALSE;
+#endif
player->MovDir = snap_direction;
}
player->is_dropping = FALSE;
+ player->is_dropping_pressed = FALSE;
+ player->drop_pressed_delay = 0;
if (DigField(player, jx, jy, x, y, 0, 0, DF_SNAP) == MP_NO_ACTION)
return FALSE;
EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr :
EL_UNDEFINED);
+ player->is_dropping_pressed = TRUE;
+
/* do not drop an element on top of another element; when holding drop key
pressed without moving, dropped element must move away before the next
element can be dropped (this is especially important if the next element
if (new_element == EL_UNDEFINED)
return FALSE;
+ /* check if drop key was pressed long enough for EM style dynamite */
+ if (new_element == EL_EM_DYNAMITE && player->drop_pressed_delay < 40)
+ return FALSE;
+
/* check if anything can be dropped at the current position */
if (IS_ACTIVE_BOMB(old_element) || old_element == EL_EXPLOSION)
return FALSE;
{
player->inventory_size--;
+#if 1
+ DrawGameDoorValues();
+#else
DrawGameValue_Dynamite(local_player->inventory_size);
+#endif
if (new_element == EL_DYNAMITE)
new_element = EL_DYNAMITE_ACTIVE;
+ else if (new_element == EL_EM_DYNAMITE)
+ new_element = EL_EM_DYNAMITE_ACTIVE;
else if (new_element == EL_SP_DISK_RED)
new_element = EL_SP_DISK_RED_ACTIVE;
}
nexty = dropy + GET_DY_FROM_DIR(move_direction);
ChangeCount[dropx][dropy] = 0; /* allow at least one more change */
- CheckCollision[dropx][dropy] = 2;
+ CheckCollision[dropx][dropy] = CHECK_DELAY_COLLISION;
}
player->drop_delay = GET_NEW_DROP_DELAY(drop_element);
player->is_dropping = TRUE;
+ player->drop_pressed_delay = 0;
+ player->is_dropping_pressed = FALSE;
+
player->drop_x = dropx;
player->drop_y = dropy;
break;
case SAMPLE_slurp:
- PlayLevelSoundElementAction(x, y, element, ACTION_SLURPED_BY_SPRING);
+ PlayLevelSoundElementAction(x, y, element, ACTION_EATING);
break;
case SAMPLE_eater:
RaiseScore(level.score[SC_NUT]);
break;
case EL_DYNAMITE:
+ case EL_EM_DYNAMITE:
case EL_SP_DISK_RED:
case EL_DYNABOMB_INCREASE_NUMBER:
case EL_DYNABOMB_INCREASE_SIZE:
{
#if defined(NETWORK_AVALIABLE)
if (options.network)
- SendToServer_StopPlaying();
+ SendToServer_StopPlaying(NETWORK_STOP_BY_PLAYER);
else
#endif
{
switch (id)
{
case GAME_CTRL_ID_STOP:
- RequestQuitGame(TRUE);
+ if (tape.playing)
+ TapeStop();
+ else
+ RequestQuitGame(TRUE);
break;
case GAME_CTRL_ID_PAUSE:
#endif
{
tape.pausing = FALSE;
- DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
+ DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF, 0);
}
}
break;