#define USE_FIX_KILLED_BY_NON_WALKABLE (USE_NEW_STUFF * 1)
#define USE_FIX_IMPACT_COLLISION (USE_NEW_STUFF * 1)
+#define USE_FIX_CE_ACTION_WITH_PLAYER (USE_NEW_STUFF * 1)
+
+#define USE_PLAYER_REANIMATION (USE_NEW_STUFF * 1)
#define USE_GFX_RESET_WHEN_NOT_MOVING (USE_NEW_STUFF * 1)
-#define USE_DELAYED_GFX_REDRAW (USE_NEW_STUFF * 1)
+#define USE_DELAYED_GFX_REDRAW (USE_NEW_STUFF * 0)
#if USE_DELAYED_GFX_REDRAW
#define TEST_DrawLevelField(x, y) \
void TestIfFriendTouchesBadThing(int, int);
void TestIfBadThingTouchesFriend(int, int);
void TestIfBadThingTouchesOtherBadThing(int, int);
+void TestIfGoodThingGetsHitByBadThing(int, int, int);
void KillPlayer(struct PlayerInfo *);
void BuryPlayer(struct PlayerInfo *);
}
else
{
+ stored_player[0].initial_element = element;
stored_player[0].use_murphy = TRUE;
if (!level.use_artwork_element[0])
player->jx = player->last_jx = x;
player->jy = player->last_jy = y;
}
+
+#if USE_PLAYER_REANIMATION
+ if (!init_game)
+ {
+ int player_nr = GET_PLAYER_NR(element);
+ struct PlayerInfo *player = &stored_player[player_nr];
+
+ if (player->active)
+ player->killed = FALSE; /* if player was just killed, reanimate him */
+ }
+#endif
}
static void InitField(int x, int y, boolean init_game)
player->Frame = 0;
player->StepFrame = 0;
- player->use_murphy = FALSE;
+ player->initial_element = player->element_nr;
player->artwork_element =
(level.use_artwork_element[i] ? level.artwork_element[i] :
player->element_nr);
+ player->use_murphy = FALSE;
player->block_last_field = FALSE; /* initialized in InitPlayerField() */
player->block_delay_adjustment = 0; /* initialized in InitPlayerField() */
some_player->present = FALSE;
some_player->active = FALSE;
+ player->initial_element = some_player->initial_element;
player->artwork_element = some_player->artwork_element;
player->block_last_field = some_player->block_last_field;
GfxElement[x][y] = EL_UNDEFINED;
GfxAction[x][y] = ACTION_DEFAULT;
GfxDir[x][y] = MV_NONE;
+#if 0
+ /* !!! this would prevent the removed tile from being redrawn !!! */
GfxRedraw[x][y] = GFX_REDRAW_NONE;
+#endif
}
void RemoveMovingField(int x, int y)
{
struct PlayerInfo *player = PLAYERINFO(x, y);
+#if USE_FIX_CE_ACTION_WITH_PLAYER
+ element = Feld[x][y] = player->initial_element;
+#else
element = Feld[x][y] = (player->use_murphy ? EL_SP_MURPHY :
player->element_nr);
+#endif
if (level.use_explosion_element[player->index_nr])
{
element - EL_EM_GATE_1_GRAY + EL_EM_GATE_1_GRAY_ACTIVE :
IS_EMC_GATE_GRAY(element) ?
element - EL_EMC_GATE_5_GRAY + EL_EMC_GATE_5_GRAY_ACTIVE :
+ IS_DC_GATE_GRAY(element) ?
+ EL_DC_GATE_WHITE_GRAY_ACTIVE :
element);
TEST_DrawLevelField(x, y);
}
element - EL_EM_GATE_1_GRAY_ACTIVE + EL_EM_GATE_1_GRAY :
IS_EMC_GATE_GRAY_ACTIVE(element) ?
element - EL_EMC_GATE_5_GRAY_ACTIVE + EL_EMC_GATE_5_GRAY :
+ IS_DC_GATE_GRAY_ACTIVE(element) ?
+ EL_DC_GATE_WHITE_GRAY :
element);
TEST_DrawLevelField(x, y);
}
else if (element == EL_PENGUIN)
TestIfFriendTouchesBadThing(newx, newy);
+ if (DONT_GET_HIT_BY(element))
+ {
+ TestIfGoodThingGetsHitByBadThing(newx, newy, direction);
+ }
+
/* give the player one last chance (one more frame) to move away */
if (CAN_FALL(element) && direction == MV_DOWN &&
(last_line || (!IS_FREE(x, newy + 1) &&
GfxRedraw[x][y] != GFX_REDRAW_NONE)
#endif
{
+ /* !!! PROBLEM: THIS REDRAWS THE PLAYFIELD _AFTER_ THE SCAN, BUT TILES
+ !!! MAY HAVE CHANGED AFTER BEING DRAWN DURING PLAYFIELD SCAN !!! */
+
if (GfxRedraw[x][y] & GFX_REDRAW_TILE)
DrawLevelField(x, y);
void ScrollLevel(int dx, int dy)
{
-#if 1
+#if 0
+ /* (directly solved in BlitBitmap() now) */
static Bitmap *bitmap_db_field2 = NULL;
int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
int x, y;
#else
- int i, x, y;
+ int x, y;
#endif
#if 0
return;
#endif
-#if 1
+#if 0
+ /* (directly solved in BlitBitmap() now) */
if (bitmap_db_field2 == NULL)
bitmap_db_field2 = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH);
CE_PLAYER_ENTERS_X,
player->index_bit, enter_side);
+#if USE_FIX_CE_ACTION_WITH_PLAYER
+ CheckTriggeredElementChangeBySide(jx, jy, player->initial_element,
+ CE_MOVE_OF_X, move_direction);
+#else
CheckTriggeredElementChangeBySide(jx, jy, player->element_nr,
CE_MOVE_OF_X, move_direction);
+#endif
}
if (game.engine_version >= VERSION_IDENT(3,0,7,0))
if (!IN_LEV_FIELD(xx, yy))
continue;
- if (IS_PLAYER(x, y))
+ if (IS_PLAYER(x, y)) /* player found at center element */
{
struct PlayerInfo *player = PLAYERINFO(x, y);
CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
CE_PLAYER_TOUCHES_X,
player->index_bit, border_side);
+
+#if USE_FIX_CE_ACTION_WITH_PLAYER
+ {
+ /* use player element that is initially defined in the level playfield,
+ not the player element that corresponds to the runtime player number
+ (example: a level that contains EL_PLAYER_3 as the only player would
+ incorrectly give EL_PLAYER_1 for "player->element_nr") */
+ int player_element = PLAYERINFO(x, y)->initial_element;
+
+ CheckElementChangeBySide(xx, yy, border_element, player_element,
+ CE_TOUCHING_X, border_side);
+ }
+#endif
}
- else if (IS_PLAYER(xx, yy))
+ else if (IS_PLAYER(xx, yy)) /* player found at border element */
{
struct PlayerInfo *player = PLAYERINFO(xx, yy);
CheckTriggeredElementChangeByPlayer(x, y, center_element,
CE_PLAYER_TOUCHES_X,
player->index_bit, center_side);
+
+#if USE_FIX_CE_ACTION_WITH_PLAYER
+ {
+ /* use player element that is initially defined in the level playfield,
+ not the player element that corresponds to the runtime player number
+ (example: a level that contains EL_PLAYER_3 as the only player would
+ incorrectly give EL_PLAYER_1 for "player->element_nr") */
+ int player_element = PLAYERINFO(xx, yy)->initial_element;
+
+ CheckElementChangeBySide(x, y, center_element, player_element,
+ CE_TOUCHING_X, center_side);
+ }
+#endif
+
break;
}
}
/* check for change of border element */
CheckElementChangeBySide(xx, yy, border_element, center_element,
CE_TOUCHING_X, center_side);
+
+ /* (center element cannot be player, so we dont have to check this here) */
}
for (i = 0; i < NUM_DIRECTIONS; i++)
{
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
int border_side = trigger_sides[i][1];
int border_element = border_element_old[i];
change_center_element =
CheckElementChangeBySide(x, y, center_element, border_element,
CE_TOUCHING_X, border_side);
+
+#if USE_FIX_CE_ACTION_WITH_PLAYER
+ if (IS_PLAYER(xx, yy))
+ {
+ /* use player element that is initially defined in the level playfield,
+ not the player element that corresponds to the runtime player number
+ (example: a level that contains EL_PLAYER_3 as the only player would
+ incorrectly give EL_PLAYER_1 for "player->element_nr") */
+ int player_element = PLAYERINFO(xx, yy)->initial_element;
+
+ CheckElementChangeBySide(x, y, center_element, player_element,
+ CE_TOUCHING_X, border_side);
+ }
+#endif
}
}
CheckElementChangeBySide(x, y, hitting_element, touched_element,
CE_HITTING_X, touched_side);
- CheckElementChangeBySide(hitx, hity, touched_element,
- hitting_element, CE_HIT_BY_X, hitting_side);
+ CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
+ CE_HIT_BY_X, hitting_side);
CheckElementChangeBySide(hitx, hity, touched_element, hitting_element,
CE_HIT_BY_SOMETHING, opposite_direction);
+
+#if USE_FIX_CE_ACTION_WITH_PLAYER
+ if (IS_PLAYER(hitx, hity))
+ {
+ /* use player element that is initially defined in the level playfield,
+ not the player element that corresponds to the runtime player number
+ (example: a level that contains EL_PLAYER_3 as the only player would
+ incorrectly give EL_PLAYER_1 for "player->element_nr") */
+ int player_element = PLAYERINFO(hitx, hity)->initial_element;
+
+ CheckElementChangeBySide(x, y, hitting_element, player_element,
+ CE_HITTING_X, touched_side);
+ }
+#endif
}
}
test_x = bad_x + test_xy[i][0];
test_y = bad_y + test_xy[i][1];
+
if (!IN_LEV_FIELD(test_x, test_y))
continue;
kill_x = test_x;
kill_y = test_y;
+
break;
}
else if (test_element == EL_PENGUIN)
{
kill_x = test_x;
kill_y = test_y;
+
break;
}
}
}
}
+void TestIfGoodThingGetsHitByBadThing(int bad_x, int bad_y, int bad_move_dir)
+{
+ int bad_element = Feld[bad_x][bad_y];
+ int dx = (bad_move_dir == MV_LEFT ? -1 : bad_move_dir == MV_RIGHT ? +1 : 0);
+ int dy = (bad_move_dir == MV_UP ? -1 : bad_move_dir == MV_DOWN ? +1 : 0);
+ int test_x = bad_x + dx, test_y = bad_y + dy;
+ int test_move_dir, test_element;
+ int kill_x = -1, kill_y = -1;
+
+ if (!IN_LEV_FIELD(test_x, test_y))
+ return;
+
+ test_move_dir =
+ (IS_MOVING(test_x, test_y) ? MovDir[test_x][test_y] : MV_NONE);
+
+ test_element = Feld[test_x][test_y];
+
+ if (test_move_dir != bad_move_dir)
+ {
+ /* good thing can be player or penguin that does not move away */
+ if (IS_PLAYER(test_x, test_y))
+ {
+ struct PlayerInfo *player = PLAYERINFO(test_x, test_y);
+
+ /* (note: in comparison to DONT_RUN_TO and DONT_TOUCH, also handle the
+ player as being hit when he is moving towards the bad thing, because
+ the "get hit by" condition would be lost after the player stops) */
+ if (player->MovPos != 0 && player->MovDir == bad_move_dir)
+ return; /* player moves away from bad thing */
+
+ kill_x = test_x;
+ kill_y = test_y;
+ }
+ else if (test_element == EL_PENGUIN)
+ {
+ kill_x = test_x;
+ kill_y = test_y;
+ }
+ }
+
+ if (kill_x != -1 || kill_y != -1)
+ {
+ if (IS_PLAYER(kill_x, kill_y))
+ {
+ struct PlayerInfo *player = PLAYERINFO(kill_x, kill_y);
+
+ if (player->shield_deadly_time_left > 0 &&
+ !IS_INDESTRUCTIBLE(bad_element))
+ Bang(bad_x, bad_y);
+ else if (!PLAYER_ENEMY_PROTECTED(kill_x, kill_y))
+ KillPlayer(player);
+ }
+ else
+ Bang(kill_x, kill_y);
+ }
+}
+
void TestIfPlayerTouchesBadThing(int x, int y)
{
TestIfGoodThingHitsBadThing(x, y, MV_NONE);
player->shield_deadly_time_left = 0;
Bang(jx, jy);
+
+#if USE_PLAYER_REANIMATION
+ if (player->killed) /* player may have been reanimated */
+ BuryPlayer(player);
+#else
BuryPlayer(player);
+#endif
}
static void KillPlayerUnlessEnemyProtected(int x, int y)