#define USE_NEW_AMOEBA_CODE FALSE
/* EXPERIMENTAL STUFF */
-#define USE_NEW_STUFF (TRUE * 1)
-
-#define USE_NEW_SP_SLIPPERY (TRUE * USE_NEW_STUFF * 1)
+#define USE_NEW_STUFF ( 1)
+#define USE_NEW_SP_SLIPPERY (USE_NEW_STUFF * 1)
+#define USE_NEW_COLLECT_COUNT (USE_NEW_STUFF * 1)
+#define USE_NEW_PLAYER_ANIM (USE_NEW_STUFF * 1)
+#define USE_NEW_ALL_SLIPPERY (USE_NEW_STUFF * 1)
+#define USE_NEW_PLAYER_SPEED (USE_NEW_STUFF * 1)
+#define USE_NEW_DELAYED_ACTION (USE_NEW_STUFF * 1)
/* for DigField() */
#define DF_NO_PUSH 0
#define INITIAL_MOVE_DELAY_ON 0
/* values for player movement speed (which is in fact a delay value) */
+#define MOVE_DELAY_MIN_SPEED 32
#define MOVE_DELAY_NORMAL_SPEED 8
#define MOVE_DELAY_HIGH_SPEED 4
+#define MOVE_DELAY_MAX_SPEED 1
+#if 0
#define DOUBLE_MOVE_DELAY(x) (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x))
#define HALVE_MOVE_DELAY(x) (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x))
+#else
+#define DOUBLE_MOVE_DELAY(x) (x = (x < MOVE_DELAY_MIN_SPEED ? x * 2 : x))
+#define HALVE_MOVE_DELAY(x) (x = (x > MOVE_DELAY_MAX_SPEED ? x / 2 : x))
+#endif
#define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY((p)->move_delay_value))
#define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value))
/* values for other actions */
#define MOVE_STEPSIZE_NORMAL (TILEX / MOVE_DELAY_NORMAL_SPEED)
+#define MOVE_STEPSIZE_MIN (1)
+#define MOVE_STEPSIZE_MAX (TILEX)
#define GET_DX_FROM_DIR(d) ((d) == MV_LEFT ? -1 : (d) == MV_RIGHT ? 1 : 0)
#define GET_DY_FROM_DIR(d) ((d) == MV_UP ? -1 : (d) == MV_DOWN ? 1 : 0)
static void CloseAllOpenTimegates(void);
static void CheckGravityMovement(struct PlayerInfo *);
static void CheckGravityMovementWhenNotMoving(struct PlayerInfo *);
-static void KillHeroUnlessEnemyProtected(int, int);
-static void KillHeroUnlessExplosionProtected(int, int);
+static void KillPlayerUnlessEnemyProtected(int, int);
+static void KillPlayerUnlessExplosionProtected(int, int);
static void TestIfPlayerTouchesCustomElement(int, int);
static void TestIfElementTouchesCustomElement(int, int);
}
break;
}
+
+#if USE_NEW_COLLECT_COUNT
+ Count[x][y] = element_info[Feld[x][y]].collect_count_initial;
+#endif
}
static inline void InitField_WithBug1(int x, int y, boolean init_game)
ei->change->change_function = ch_delay->change_function;
ei->change->post_change_function = ch_delay->post_change_function;
+ ei->change->can_change = TRUE;
+ ei->change->can_change_or_has_action = TRUE;
+
ei->has_change_event[CE_DELAY] = TRUE;
SET_PROPERTY(ch_delay->element, EP_CAN_CHANGE, TRUE);
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;
player->push_delay = -1; /* initialized when pushing starts */
MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
- Count[x][y] = element_info[Feld[x][y]].collect_count_initial;
+#if USE_NEW_COLLECT_COUNT
+ Count[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;
emulate_sb ? EMU_SOKOBAN :
emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
+#if USE_NEW_ALL_SLIPPERY
+ /* initialize type of slippery elements */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ {
+ if (!IS_CUSTOM_ELEMENT(i))
+ {
+ /* default: elements slip down either to the left or right randomly */
+ element_info[i].slippery_type = SLIPPERY_ANY_RANDOM;
+
+ /* SP style elements prefer to slip down on the left side */
+ if (game.engine_version >= VERSION_IDENT(3,1,1,0) && IS_SP_ELEMENT(i))
+ element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT;
+
+ /* BD style elements prefer to slip down on the left side */
+ if (game.emulation == EMU_BOULDERDASH)
+ element_info[i].slippery_type = SLIPPERY_ANY_LEFT_RIGHT;
+ }
+ }
+#endif
+
/* initialize explosion and ignition delay */
for (i = 0; i < MAX_NUM_ELEMENTS; i++)
{
for (yy = 0; yy < 3; yy++) for (xx = 0; xx < 3; xx++)
{
- content = element_info[element].content[xx][yy];
+ content = element_info[element].content.e[xx][yy];
is_player = ELEM_IS_PLAYER(content);
if (is_player && (found_rating < 2 || element < found_element))
for (i = 0; i < element_info[element].num_change_pages; i++)
{
- content= element_info[element].change_page[i].target_content[xx][yy];
+ content =
+ element_info[element].change_page[i].target_content.e[xx][yy];
+
is_player = ELEM_IS_PLAYER(content);
if (is_player && (found_rating < 1 || element < found_element))
PlayLevelSoundElementAction(ExitX, ExitY, element, ACTION_CLOSING);
}
- /* Hero disappears */
+ /* player disappears */
if (ExitX >= 0 && ExitY >= 0)
DrawLevelField(ExitX, ExitY);
MovDir[newx][newy] = MovDir[x][y];
+#if USE_NEW_COLLECT_COUNT
Count[newx][newy] = Count[x][y];
+#endif
GfxFrame[newx][newy] = GfxFrame[x][y];
GfxRandom[newx][newy] = GfxRandom[x][y];
MovDir[x][y] = 0;
MovDelay[x][y] = 0;
+#if USE_NEW_COLLECT_COUNT
Count[x][y] = 0;
+#endif
AmoebaNr[x][y] = 0;
ChangeDelay[x][y] = 0;
if (player == local_player) /* only visually relocate local player */
DrawRelocatePlayer(player);
- TestIfHeroTouchesBadThing(jx, jy);
+ TestIfPlayerTouchesBadThing(jx, jy);
TestIfPlayerTouchesCustomElement(jx, jy);
if (IS_CUSTOM_ELEMENT(element))
else if (center_element == EL_AMOEBA_TO_DIAMOND)
Store[x][y] = level.amoeba_content;
else if (center_element == EL_YAMYAM)
- Store[x][y] = level.yamyam_content[game.yamyam_content_nr][xx][yy];
+ Store[x][y] = level.yamyam_content[game.yamyam_content_nr].e[xx][yy];
else if (IS_CUSTOM_ELEMENT(center_element) &&
- element_info[center_element].content[xx][yy] != EL_EMPTY)
- Store[x][y] = element_info[center_element].content[xx][yy];
+ element_info[center_element].content.e[xx][yy] != EL_EMPTY)
+ Store[x][y] = element_info[center_element].content.e[xx][yy];
else if (element == EL_WALL_EMERALD)
Store[x][y] = EL_EMERALD;
else if (element == EL_WALL_DIAMOND)
else if (element == EL_WALL_CRYSTAL)
Store[x][y] = EL_CRYSTAL;
else if (IS_CUSTOM_ELEMENT(element) && !CAN_EXPLODE(element))
- Store[x][y] = element_info[element].content[1][1];
+ Store[x][y] = element_info[element].content.e[1][1];
else
Store[x][y] = EL_EMPTY;
if (IS_PLAYER(x, y) && PLAYERINFO(x, y)->present &&
!PLAYER_EXPLOSION_PROTECTED(x, y))
{
- KillHeroUnlessExplosionProtected(x, y);
+ KillPlayerUnlessExplosionProtected(x, y);
border_explosion = TRUE;
}
else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
GfxDir[x][y] = MV_NO_MOVING;
ChangeDelay[x][y] = 0;
ChangePage[x][y] = -1;
+
+#if USE_NEW_COLLECT_COUNT
Count[x][y] = 0;
+#endif
InitField_WithBug2(x, y, FALSE);
if (impact && element == EL_AMOEBA_DROP)
{
if (object_hit && IS_PLAYER(x, y + 1))
- KillHeroUnlessEnemyProtected(x, y + 1);
+ KillPlayerUnlessEnemyProtected(x, y + 1);
else if (object_hit && smashed == EL_PENGUIN)
Bang(x, y + 1);
else
{
if (CAN_SMASH_PLAYER(element))
{
- KillHeroUnlessEnemyProtected(x, y + 1);
+ KillPlayerUnlessEnemyProtected(x, y + 1);
return;
}
}
Feld[x + 1][y + 1] == EL_ACID));
boolean can_fall_any = (can_fall_left || can_fall_right);
boolean can_fall_both = (can_fall_left && can_fall_right);
+ int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
- if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
+#if USE_NEW_ALL_SLIPPERY
+ if (can_fall_any && slippery_type != SLIPPERY_ANY_RANDOM)
{
- int slippery_type = element_info[Feld[x][y + 1]].slippery_type;
+ if (slippery_type == SLIPPERY_ANY_LEFT_RIGHT && can_fall_both)
+ can_fall_right = FALSE;
+ else if (slippery_type == SLIPPERY_ANY_RIGHT_LEFT && can_fall_both)
+ can_fall_left = FALSE;
+ else if (slippery_type == SLIPPERY_ONLY_LEFT)
+ can_fall_right = FALSE;
+ else if (slippery_type == SLIPPERY_ONLY_RIGHT)
+ can_fall_left = FALSE;
+ can_fall_any = (can_fall_left || can_fall_right);
+ can_fall_both = FALSE;
+ }
+#else
+ if (can_fall_any && IS_CUSTOM_ELEMENT(Feld[x][y + 1]))
+ {
if (slippery_type == SLIPPERY_ONLY_LEFT)
can_fall_right = FALSE;
else if (slippery_type == SLIPPERY_ONLY_RIGHT)
can_fall_any = (can_fall_left || can_fall_right);
can_fall_both = (can_fall_left && can_fall_right);
}
+#endif
+#if USE_NEW_ALL_SLIPPERY
+#else
#if USE_NEW_SP_SLIPPERY
/* !!! better use the same properties as for custom elements here !!! */
else if (game.engine_version >= VERSION_IDENT(3,1,1,0) &&
can_fall_both = FALSE;
}
#endif
+#endif
+#if USE_NEW_ALL_SLIPPERY
+ if (can_fall_both)
+ {
+ if (element == EL_BD_ROCK || element == EL_BD_DIAMOND)
+ can_fall_right = FALSE; /* slip down on left side */
+ else
+ can_fall_left = !(can_fall_right = RND(2));
+
+ can_fall_both = FALSE;
+ }
+#else
if (can_fall_both)
{
if (game.emulation == EMU_BOULDERDASH ||
can_fall_both = FALSE;
}
+#endif
if (can_fall_any)
{
IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) &&
!PLAYER_ENEMY_PROTECTED(newx, newy))
{
- TestIfBadThingRunsIntoHero(x, y, MovDir[x][y]);
+ TestIfBadThingRunsIntoPlayer(x, y, MovDir[x][y]);
return;
}
DrawLevelElementAnimation(x, y, element);
if (DONT_TOUCH(element))
- TestIfBadThingTouchesHero(x, y);
+ TestIfBadThingTouchesPlayer(x, y);
return;
}
ContinueMoving(x, y);
}
-/* (emacs is confused here for some reason; this makes it happy again ;-) ) */
-void dummy()
-{
-}
-
void ContinueMoving(int x, int y)
{
int element = Feld[x][y];
if (!game.magic_wall_active)
Feld[x][y] = EL_MAGIC_WALL_DEAD;
element = Feld[newx][newy] = Store[x][y];
+
+#if USE_NEW_COLLECT_COUNT
+ InitField(newx, newy, FALSE);
+#endif
}
else if (element == EL_BD_MAGIC_WALL_FILLING)
{
if (!game.magic_wall_active)
Feld[x][y] = EL_BD_MAGIC_WALL_DEAD;
element = Feld[newx][newy] = Store[x][y];
+
+#if USE_NEW_COLLECT_COUNT
+ InitField(newx, newy, FALSE);
+#endif
}
else if (element == EL_AMOEBA_DROPPING)
{
MovDir[x][y] = 0;
MovDelay[x][y] = 0;
- Count[x][y] = 0;
-
MovDelay[newx][newy] = 0;
if (CAN_CHANGE(element))
ChangePage[newx][newy] = ChangePage[x][y];
Changed[newx][newy] = Changed[x][y];
ChangeEvent[newx][newy] = ChangeEvent[x][y];
+
+#if USE_NEW_COLLECT_COUNT
+ Count[newx][newy] = Count[x][y];
+#endif
}
ChangeDelay[x][y] = 0;
Changed[x][y] = FALSE;
ChangeEvent[x][y] = -1;
+#if USE_NEW_COLLECT_COUNT
+ Count[x][y] = 0;
+#endif
+
/* copy animation control values to new field */
GfxFrame[newx][newy] = GfxFrame[x][y];
GfxRandom[newx][newy] = GfxRandom[x][y]; /* keep same random value */
if (DONT_TOUCH(element)) /* object may be nasty to player or others */
{
- TestIfBadThingTouchesHero(newx, newy);
+ TestIfBadThingTouchesPlayer(newx, newy);
TestIfBadThingTouchesFriend(newx, newy);
if (!IS_CUSTOM_ELEMENT(element))
EL_EMPTY);
}
-static int getModifiedActionNumber(int value_old, int value_min, int value_max,
- int operator, int operand)
+static int getModifiedActionNumber(int value_old, int operator, int operand,
+ int value_min, int value_max)
{
- int value_new = (operator == CA_MODE_ADD ? value_old + operand :
+ int value_new = (operator == CA_MODE_SET ? operand :
+ operator == CA_MODE_ADD ? value_old + operand :
operator == CA_MODE_SUBTRACT ? value_old - operand :
operator == CA_MODE_MULTIPLY ? value_old * operand :
operator == CA_MODE_DIVIDE ? value_old / MAX(1, operand) :
- operator == CA_MODE_SET ? operand :
+ operator == CA_MODE_MODULO ? value_old % MAX(1, operand) :
value_old);
return (value_new < value_min ? value_min :
action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element :
EL_EMPTY);
+ int action_arg_number_min =
+ (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MIN :
+ CA_ARG_MIN);
+
+ int action_arg_number_max =
+ (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_MAX :
+ action_type == CA_SET_GEMS ? 999 :
+ action_type == CA_SET_TIME ? 9999 :
+ action_type == CA_SET_SCORE ? 99999 :
+ action_type == CA_SET_CE_SCORE ? 9999 :
+ action_type == CA_SET_CE_COUNT ? 9999 :
+ CA_ARG_MAX);
+
+ int action_arg_number_reset =
+ (action_type == CA_SET_PLAYER_SPEED ? TILEX/game.initial_move_delay_value :
+ action_type == CA_SET_GEMS ? level.gems_needed :
+ action_type == CA_SET_TIME ? level.time :
+ action_type == CA_SET_SCORE ? 0 :
+ action_type == CA_SET_CE_SCORE ? 0 :
+ action_type == CA_SET_CE_COUNT ? ei->collect_count_initial :
+ 0);
+
+ int action_arg_number_normal =
+ (action_type == CA_SET_PLAYER_SPEED ? MOVE_STEPSIZE_NORMAL :
+ action_arg_number_reset);
+
int action_arg_number =
(action_arg <= CA_ARG_MAX ? action_arg :
- action_arg == CA_ARG_NUMBER_MIN ? CA_ARG_MIN :
- action_arg == CA_ARG_NUMBER_MAX ? CA_ARG_MAX :
+ 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_NORMAL ? action_arg_number_normal :
action_arg == CA_ARG_NUMBER_CE_SCORE ? ei->collect_score :
+#if USE_NEW_COLLECT_COUNT
action_arg == CA_ARG_NUMBER_CE_COUNT ? Count[x][y] :
+#else
+ action_arg == CA_ARG_NUMBER_CE_COUNT ? ei->collect_count_initial :
+#endif
action_arg == CA_ARG_NUMBER_CE_DELAY ? GET_CHANGE_DELAY(change) :
-1);
- /* (for explicit player choice, set invalid value to "no player") */
+ int action_arg_number_old =
+ (action_type == CA_SET_GEMS ? local_player->gems_still_needed :
+ action_type == CA_SET_TIME ? TimeLeft :
+ action_type == CA_SET_SCORE ? local_player->score :
+ action_type == CA_SET_CE_SCORE ? ei->collect_score :
+ action_type == CA_SET_CE_COUNT ? Count[x][y] :
+ 0);
+
+ int action_arg_number_new =
+ getModifiedActionNumber(action_arg_number_old,
+ action_mode, action_arg_number,
+ action_arg_number_min, action_arg_number_max);
+
int action_arg_player_bits =
- (action_arg == CA_ARG_PLAYER_ANY ? action_arg - CA_ARG_PLAYER :
+ (action_arg == CA_ARG_PLAYER_ANY ? PLAYER_BITS_ANY :
action_arg >= CA_ARG_PLAYER_1 &&
action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER :
action_arg >= CA_ARG_1 &&
- action_arg <= CA_ARG_PLAYER_4 ? (1 << (action_arg - 1)) :
+ action_arg <= CA_ARG_PLAYER_4 ? (1 << (action_arg - CA_ARG_1)) :
action_arg_element >= EL_PLAYER_1 &&
action_arg_element <= EL_PLAYER_4 ?
(1 << (action_arg_element - EL_PLAYER_1)) :
- 0);
+ PLAYER_BITS_ANY);
- /* (for implicit player choice, set invalid value to "all players") */
int trigger_player_bits =
(change->actual_trigger_player >= EL_PLAYER_1 &&
change->actual_trigger_player <= EL_PLAYER_4 ?
{
for (i = 0; i < MAX_PLAYERS; i++)
if (action_arg_player_bits & (1 << i))
- KillHero(&stored_player[i]);
+ KillPlayer(&stored_player[i]);
break;
}
{
if (trigger_player_bits & (1 << i))
{
- if (action_arg == CA_ARG_NUMBER_RESET)
- stored_player[i].move_delay_value = game.initial_move_delay_value;
- else if (action_arg == CA_ARG_NUMBER_NORMAL)
- stored_player[i].move_delay_value = MOVE_DELAY_NORMAL_SPEED;
- else if (action_arg == CA_ARG_NUMBER_MIN)
- stored_player[i].move_delay_value = 16;
- else if (action_arg == CA_ARG_NUMBER_MAX)
- stored_player[i].move_delay_value = MOVE_DELAY_HIGH_SPEED;
- else
+ int move_stepsize = TILEX / stored_player[i].move_delay_value;
+
+ if (action_mode == CA_MODE_ADD || action_mode == CA_MODE_SUBTRACT)
{
-#if 0
- if (action_mode == CA_MODE_ADD)
- {
- action_mode = CA_MODE_DIVIDE;
- action_arg_number = (1 << action_arg_number);
- }
- else if (action_mode == CA_MODE_SUBTRACT)
- {
- action_mode = CA_MODE_MULTIPLY;
- action_arg_number = (1 << action_arg_number);
- }
+ /* translate "+" and "-" to "*" and "/" with powers of two */
+ action_arg_number = 1 << action_arg_number;
+ action_mode = (action_mode == CA_MODE_ADD ? CA_MODE_MULTIPLY :
+ CA_MODE_DIVIDE);
+ }
+
+ move_stepsize =
+ getModifiedActionNumber(move_stepsize,
+ action_mode,
+ action_arg_number,
+ action_arg_number_min,
+ action_arg_number_max);
- int mode = (action_mode == CA_MODE_MULTIPLY ? CA_MODE_DIVIDE :
- action_mode == CA_MODE_DIVIDE ? CA_MODE_MULTIPLY :
- action_mode);
+ /* make sure that value is power of 2 */
+ move_stepsize = (1 << log_2(move_stepsize));
- stored_player[i].move_delay_value =
- getModifiedActionNumber(stored_player[i].move_delay_value,
- 1, 16,
- action_mode, action_arg_number);
+ /* do no immediately change -- the player might just be moving */
+ stored_player[i].move_delay_value_next = TILEX / move_stepsize;
+
+#if 0
+ printf("::: move_delay_value == %d [%d]\n",
+ stored_player[i].move_delay_value_next, action_arg_number);
#endif
- }
}
}
case CA_SET_GEMS:
{
- local_player->gems_still_needed =
- getModifiedActionNumber(local_player->gems_still_needed, 0, 999,
- action_mode, action_arg_number);
+ local_player->gems_still_needed = action_arg_number_new;
DrawGameValue_Emeralds(local_player->gems_still_needed);
{
if (level.time > 0) /* only modify limited time value */
{
- TimeLeft = getModifiedActionNumber(TimeLeft, 0, 9999,
- action_mode, action_arg_number);
+ TimeLeft = action_arg_number_new;
DrawGameValue_Time(TimeLeft);
+
+ if (!TimeLeft && setup.time_limit)
+ for (i = 0; i < MAX_PLAYERS; i++)
+ KillPlayer(&stored_player[i]);
}
break;
case CA_SET_SCORE:
{
- local_player->score =
- getModifiedActionNumber(local_player->score, 0, 99999,
- action_mode, action_arg_number);
+ local_player->score = action_arg_number_new;
DrawGameValue_Score(local_player->score);
case CA_SET_CE_SCORE:
{
- ei->collect_score =
- getModifiedActionNumber(ei->collect_score, 0, 9999,
- action_mode, action_arg_number);
+ ei->collect_score = action_arg_number_new;
+
break;
}
case CA_SET_CE_COUNT:
{
+#if USE_NEW_COLLECT_COUNT
int count_last = Count[x][y];
- Count[x][y] = getModifiedActionNumber(Count[x][y], 0, 9999,
- action_mode, action_arg_number);
+ Count[x][y] = action_arg_number_new;
+#if 0
printf("::: Count == %d\n", Count[x][y]);
+#endif
if (Count[x][y] == 0 && count_last > 0)
{
-
+#if 0
printf("::: CE_COUNT_AT_ZERO\n");
+#endif
CheckElementChange(x, y, element, EL_UNDEFINED, CE_COUNT_AT_ZERO);
CheckTriggeredElementChange(element, CE_COUNT_AT_ZERO_OF_X);
}
+#endif
break;
}
Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
#endif
- TestIfBadThingTouchesHero(x, y);
+ TestIfBadThingTouchesPlayer(x, y);
TestIfPlayerTouchesCustomElement(x, y);
TestIfElementTouchesCustomElement(x, y);
}
boolean is_destructible;
int ex = x + xx - 1;
int ey = y + yy - 1;
- int content_element = change->target_content[xx][yy];
+ int content_element = change->target_content.e[xx][yy];
int e;
can_replace[xx][yy] = TRUE;
ChangeEvent[ex][ey] = ChangeEvent[x][y];
- content_element = change->target_content[xx][yy];
+ content_element = change->target_content.e[xx][yy];
target_element = GET_TARGET_ELEMENT(content_element, change);
ChangeElementNowExt(change, ex, ey, target_element);
}
if (something_has_changed)
+ {
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
+ PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page);
+ }
}
}
else
ChangeElementNowExt(change, x, y, target_element);
PlayLevelSoundElementAction(x, y, element, ACTION_CHANGING);
+ PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + page);
}
/* this uses direct change before indirect change */
return TRUE;
}
+#if USE_NEW_DELAYED_ACTION
+
+static void ChangeElement(int x, int y, int page)
+{
+ int element = MovingOrBlocked2Element(x, y);
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementChangeInfo *change = &ei->change_page[page];
+
+#ifdef DEBUG
+ if (!CAN_CHANGE_OR_HAS_ACTION(element) &&
+ !CAN_CHANGE_OR_HAS_ACTION(Back[x][y]))
+ {
+ printf("\n\n");
+ printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
+ x, y, element, element_info[element].token_name);
+ printf("ChangeElement(): This should never happen!\n");
+ printf("\n\n");
+ }
+#endif
+
+ /* this can happen with classic bombs on walkable, changing elements */
+ if (!CAN_CHANGE_OR_HAS_ACTION(element))
+ {
+#if 0
+ if (!CAN_CHANGE(Back[x][y])) /* prevent permanent repetition */
+ ChangeDelay[x][y] = 0;
+#endif
+
+ return;
+ }
+
+ if (ChangeDelay[x][y] == 0) /* initialize element change */
+ {
+ ChangeDelay[x][y] = GET_CHANGE_DELAY(change) + 1;
+
+ if (change->can_change)
+ {
+ ResetGfxAnimation(x, y);
+ ResetRandomAnimationValue(x, y);
+
+ if (change->pre_change_function)
+ change->pre_change_function(x, y);
+ }
+ }
+
+ ChangeDelay[x][y]--;
+
+ if (ChangeDelay[x][y] != 0) /* continue element change */
+ {
+ if (change->can_change)
+ {
+ int graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
+
+ if (IS_ANIMATED(graphic))
+ DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
+
+ if (change->change_function)
+ change->change_function(x, y);
+ }
+ }
+ else /* finish element change */
+ {
+ if (ChangePage[x][y] != -1) /* remember page from delayed change */
+ {
+ page = ChangePage[x][y];
+ ChangePage[x][y] = -1;
+
+ change = &ei->change_page[page];
+ }
+
+ if (IS_MOVING(x, y)) /* never change a running system ;-) */
+ {
+ ChangeDelay[x][y] = 1; /* try change after next move step */
+ ChangePage[x][y] = page; /* remember page to use for change */
+
+ return;
+ }
+
+ if (change->can_change)
+ {
+ if (ChangeElementNow(x, y, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(x, y);
+ }
+ }
+
+ if (change->has_action)
+ ExecuteCustomElementAction(x, y, element, page);
+ }
+}
+
+#else
+
static void ChangeElement(int x, int y, int page)
{
int element = MovingOrBlocked2Element(x, y);
}
}
+#endif
+
static boolean CheckTriggeredElementChangeExt(int trigger_element,
int trigger_event,
int trigger_player,
ChangeDelay[x][y] = 1;
ChangeEvent[x][y] = trigger_event;
ChangeElement(x, y, p);
-
- change_done = TRUE;
- change_done_any = TRUE;
}
-
+#if USE_NEW_DELAYED_ACTION
+ else if (change->has_action)
+ {
+ ExecuteCustomElementAction(x, y, element, p);
+ PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+ }
+#else
if (change->has_action)
+ {
ExecuteCustomElementAction(x, y, element, p);
+ PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+ }
+#endif
}
}
+
+ if (change->can_change)
+ {
+ change_done = TRUE;
+ change_done_any = TRUE;
+ }
}
}
}
change_done = TRUE;
}
-
+#if USE_NEW_DELAYED_ACTION
+ else if (change->has_action)
+ {
+ ExecuteCustomElementAction(x, y, element, p);
+ PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+ }
+#else
if (change->has_action)
+ {
ExecuteCustomElementAction(x, y, element, p);
+ PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p);
+ }
+#endif
}
}
for (i = 0; i < MAX_PLAYERS; i++)
{
boolean advance_player_counters = (player_nr == -1 || player_nr == i);
- int move_frames =
- MOVE_DELAY_NORMAL_SPEED / stored_player[i].move_delay_value;
+ int move_delay_value = stored_player[i].move_delay_value;
+ int move_frames = MOVE_DELAY_NORMAL_SPEED / move_delay_value;
if (!advance_player_counters) /* not all players may be affected */
continue;
+#if USE_NEW_PLAYER_ANIM
+ if (move_frames == 0) /* less than one move per game frame */
+ {
+ int stepsize = TILEX / move_delay_value;
+ int delay = move_delay_value / MOVE_DELAY_NORMAL_SPEED;
+ int count = (stored_player[i].is_moving ?
+ ABS(stored_player[i].MovPos) / stepsize : FrameCounter);
+
+ if (count % delay == 0)
+ move_frames = 1;
+ }
+#endif
+
stored_player[i].Frame += move_frames;
if (stored_player[i].MovPos != 0)
if (IS_CHANGING(x, y) &&
(game.engine_version < VERSION_IDENT(3,0,7,1) || !Stop[x][y]))
{
+ int page = element_info[element].event_page_nr[CE_DELAY];
#if 0
- ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] :
- element_info[element].event_page_nr[CE_DELAY]);
+ ChangeElement(x, y, ChangePage[x][y] != -1 ? ChangePage[x][y] : page);
#else
- ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]);
+
+#if 0
+ printf("::: ChangeDelay == %d\n", ChangeDelay[x][y]);
+#endif
+
+#if 1
+ ChangeElement(x, y, page);
+#else
+ if (CAN_CHANGE(element))
+ ChangeElement(x, y, page);
+
+ if (HAS_ACTION(element))
+ ExecuteCustomElementAction(x, y, element, page);
+#endif
+
#endif
element = Feld[x][y];
if (!TimeLeft && setup.time_limit)
for (i = 0; i < MAX_PLAYERS; i++)
- KillHero(&stored_player[i]);
+ KillPlayer(&stored_player[i]);
}
else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
DrawGameValue_Time(TimePlayed);
InitMovingField(jx, jy, MV_DOWN);
Store[jx][jy] = EL_ACID;
ContinueMoving(jx, jy);
- BuryHero(player);
+ BuryPlayer(player);
}
else
- TestIfHeroRunsIntoBadThing(jx, jy, player->MovDir);
+ TestIfPlayerRunsIntoBadThing(jx, jy, player->MovDir);
return MF_MOVING;
}
player->jy = new_jy;
StorePlayer[new_jx][new_jy] = player->element_nr;
+ if (player->move_delay_value_next != -1)
+ {
+ player->move_delay_value = player->move_delay_value_next;
+ player->move_delay_value_next = -1;
+ }
+
player->MovPos =
(dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
if (game.engine_version < VERSION_IDENT(3,0,7,0))
{
- TestIfHeroTouchesBadThing(jx, jy);
+ TestIfPlayerTouchesBadThing(jx, jy);
TestIfPlayerTouchesCustomElement(jx, jy);
}
if (!player->active)
- RemoveHero(player);
+ RemovePlayer(player);
return moved;
}
int last_jx = player->last_jx, last_jy = player->last_jy;
int move_stepsize = TILEX / player->move_delay_value;
- if (!player->active || !player->MovPos)
+#if USE_NEW_PLAYER_SPEED
+ if (!player->active)
+ return;
+
+ if (player->MovPos == 0 && mode == SCROLL_GO_ON) /* player not moving */
return;
+#else
+ if (!player->active || player->MovPos == 0)
+ return;
+#endif
if (mode == SCROLL_INIT)
{
MovDelay[last_jx][last_jy] = last_field_block_delay + 1;
}
+#if USE_NEW_PLAYER_SPEED
+ if (player->MovPos != 0) /* player has not yet reached destination */
+ return;
+#else
return;
+#endif
}
else if (!FrameReached(&player->actual_frame_counter, 1))
return;
+#if 0
+ printf("::: player->MovPos: %d -> %d\n",
+ player->MovPos,
+ player->MovPos + (player->MovPos > 0 ? -1 : 1) * move_stepsize);
+#endif
+
+#if USE_NEW_PLAYER_SPEED
+ if (player->MovPos != 0)
+ {
+ player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
+ player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
+
+ /* before DrawPlayer() to draw correct player graphic for this case */
+ if (player->MovPos == 0)
+ CheckGravityMovement(player);
+ }
+#else
player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
/* before DrawPlayer() to draw correct player graphic for this case */
if (player->MovPos == 0)
CheckGravityMovement(player);
+#endif
if (player->MovPos == 0) /* player reached destination field */
{
+#if 0
+ printf("::: player reached destination field\n");
+#endif
+
if (player->move_delay_reset_counter > 0)
{
player->move_delay_reset_counter--;
Feld[jx][jy] == EL_SP_EXIT_OPENING) /* <-- special case */
{
DrawPlayer(player); /* needed here only to cleanup last field */
- RemoveHero(player);
+ RemovePlayer(player);
if (local_player->friends_still_needed == 0 ||
IS_SP_ELEMENT(Feld[jx][jy]))
if (game.engine_version >= VERSION_IDENT(3,0,7,0))
{
- TestIfHeroTouchesBadThing(jx, jy);
+ TestIfPlayerTouchesBadThing(jx, jy);
TestIfPlayerTouchesCustomElement(jx, jy);
/* needed because pushed element has not yet reached its destination,
TestIfElementTouchesCustomElement(jx, jy); /* for empty space */
if (!player->active)
- RemoveHero(player);
+ RemovePlayer(player);
}
if (level.use_step_counter)
if (!TimeLeft && setup.time_limit)
for (i = 0; i < MAX_PLAYERS; i++)
- KillHero(&stored_player[i]);
+ KillPlayer(&stored_player[i]);
}
else if (level.time == 0 && !AllPlayersGone) /* level w/o time limit */
DrawGameValue_Time(TimePlayed);
!IS_INDESTRUCTIBLE(bad_element))
Bang(kill_x, kill_y);
else if (!PLAYER_ENEMY_PROTECTED(good_x, good_y))
- KillHero(player);
+ KillPlayer(player);
}
else
Bang(good_x, good_y);
!IS_INDESTRUCTIBLE(bad_element))
Bang(bad_x, bad_y);
else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
- KillHero(player);
+ KillPlayer(player);
}
else
Bang(kill_x, kill_y);
}
}
-void TestIfHeroTouchesBadThing(int x, int y)
+void TestIfPlayerTouchesBadThing(int x, int y)
{
TestIfGoodThingHitsBadThing(x, y, MV_NO_MOVING);
}
-void TestIfHeroRunsIntoBadThing(int x, int y, int move_dir)
+void TestIfPlayerRunsIntoBadThing(int x, int y, int move_dir)
{
TestIfGoodThingHitsBadThing(x, y, move_dir);
}
-void TestIfBadThingTouchesHero(int x, int y)
+void TestIfBadThingTouchesPlayer(int x, int y)
{
TestIfBadThingHitsGoodThing(x, y, MV_NO_MOVING);
}
-void TestIfBadThingRunsIntoHero(int x, int y, int move_dir)
+void TestIfBadThingRunsIntoPlayer(int x, int y, int move_dir)
{
TestIfBadThingHitsGoodThing(x, y, move_dir);
}
Bang(bad_x, bad_y);
}
-void KillHero(struct PlayerInfo *player)
+void KillPlayer(struct PlayerInfo *player)
{
int jx = player->jx, jy = player->jy;
player->shield_deadly_time_left = 0;
Bang(jx, jy);
- BuryHero(player);
+ BuryPlayer(player);
}
-static void KillHeroUnlessEnemyProtected(int x, int y)
+static void KillPlayerUnlessEnemyProtected(int x, int y)
{
if (!PLAYER_ENEMY_PROTECTED(x, y))
- KillHero(PLAYERINFO(x, y));
+ KillPlayer(PLAYERINFO(x, y));
}
-static void KillHeroUnlessExplosionProtected(int x, int y)
+static void KillPlayerUnlessExplosionProtected(int x, int y)
{
if (!PLAYER_EXPLOSION_PROTECTED(x, y))
- KillHero(PLAYERINFO(x, y));
+ KillPlayer(PLAYERINFO(x, y));
}
-void BuryHero(struct PlayerInfo *player)
+void BuryPlayer(struct PlayerInfo *player)
{
int jx = player->jx, jy = player->jy;
PlayLevelSound(jx, jy, SND_GAME_LOSING);
player->GameOver = TRUE;
- RemoveHero(player);
+ RemovePlayer(player);
}
-void RemoveHero(struct PlayerInfo *player)
+void RemovePlayer(struct PlayerInfo *player)
{
int jx = player->jx, jy = player->jy;
int i, found = FALSE;
if (!ExplodeField[jx][jy])
StorePlayer[jx][jy] = 0;
+ if (player->is_moving)
+ DrawLevelField(player->last_jx, player->last_jy);
+
for (i = 0; i < MAX_PLAYERS; i++)
if (stored_player[i].active)
found = TRUE;
return MF_NO_ACTION; /* field has no opening in this direction */
element = Feld[x][y];
+#if USE_NEW_COLLECT_COUNT
collect_count = Count[x][y];
+#else
+ collect_count = element_info[element].collect_count_initial;
+#endif
+
+#if 0
+ if (element != EL_BLOCKED &&
+ Count[x][y] != element_info[element].collect_count_initial)
+ printf("::: %d: %d != %d\n",
+ element,
+ Count[x][y],
+ element_info[element].collect_count_initial);
+#endif
if (!is_player && !IS_COLLECTIBLE(element)) /* penguin cannot collect it */
return MF_NO_ACTION;