X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=a32fcfa7f5e4111302fe2a814b7363248861660a;hb=9991027ba0e61f105a15d517461614fce184ba48;hp=71d83bbc815de1eea134facc57cec36018580851;hpb=3f336329750dff46fe1634f317eee24515cd9d11;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 71d83bbc..a32fcfa7 100644 --- a/src/game.c +++ b/src/game.c @@ -59,10 +59,15 @@ #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_FIX_NO_ACTION_AFTER_CHANGE (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_NEW_PLAYER_ASSIGNMENTS (USE_NEW_STUFF * 1) + +#define USE_DELAYED_GFX_REDRAW (USE_NEW_STUFF * 0) #if USE_DELAYED_GFX_REDRAW #define TEST_DrawLevelField(x, y) \ @@ -1126,6 +1131,7 @@ void TestIfBadThingRunsIntoPlayer(int, int, int); 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 *); @@ -1780,6 +1786,17 @@ static void InitPlayerField(int x, int y, int element, boolean init_game) 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) + player->reanimated = TRUE; /* if player was just killed, reanimate him */ + } +#endif } static void InitField(int x, int y, boolean init_game) @@ -3436,8 +3453,8 @@ static void InitGameEngine() for (j = 0; j < ei->num_change_pages; j++) { ei->change_page[j].actual_trigger_element = EL_EMPTY; - ei->change_page[j].actual_trigger_player = EL_PLAYER_1; - ei->change_page[j].actual_trigger_player_bits = CH_PLAYER_1; + ei->change_page[j].actual_trigger_player = EL_EMPTY; + ei->change_page[j].actual_trigger_player_bits = CH_PLAYER_NONE; 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; @@ -3665,6 +3682,11 @@ void InitGame() boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ #if 0 boolean do_fading = (game_status == GAME_MODE_MAIN); +#endif +#if 1 + int initial_move_dir = MV_DOWN; +#else + int initial_move_dir = MV_NONE; #endif int i, j, x, y; @@ -3687,6 +3709,7 @@ void InitGame() player->present = FALSE; player->active = FALSE; player->killed = FALSE; + player->reanimated = FALSE; player->action = 0; player->effective_action = 0; @@ -3710,10 +3733,10 @@ void InitGame() player->dynabombs_left = 0; player->dynabomb_xl = FALSE; - player->MovDir = MV_NONE; + player->MovDir = initial_move_dir; player->MovPos = 0; player->GfxPos = 0; - player->GfxDir = MV_NONE; + player->GfxDir = initial_move_dir; player->GfxAction = ACTION_DEFAULT; player->Frame = 0; player->StepFrame = 0; @@ -3735,7 +3758,7 @@ void InitGame() player->step_counter = 0; - player->last_move_dir = MV_NONE; + player->last_move_dir = initial_move_dir; player->is_active = FALSE; @@ -3759,7 +3782,7 @@ void InitGame() player->anim_delay_counter = 0; player->post_delay_counter = 0; - player->dir_waiting = MV_NONE; + player->dir_waiting = initial_move_dir; player->action_waiting = ACTION_DEFAULT; player->last_action_waiting = ACTION_DEFAULT; player->special_action_bored = ACTION_DEFAULT; @@ -3792,6 +3815,26 @@ void InitGame() player->inventory_infinite_element = EL_UNDEFINED; player->inventory_size = 0; + if (level.use_initial_inventory[i]) + { + for (j = 0; j < level.initial_inventory_size[i]; j++) + { + int element = level.initial_inventory_content[i][j]; + int collect_count = element_info[element].collect_count_initial; + int k; + + if (!IS_CUSTOM_ELEMENT(element)) + collect_count = 1; + + if (collect_count == 0) + player->inventory_infinite_element = element; + else + for (k = 0; k < collect_count; k++) + if (player->inventory_size < MAX_INVENTORY_SIZE) + player->inventory_element[player->inventory_size++] = element; + } + } + DigField(player, 0, 0, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); @@ -3997,6 +4040,52 @@ void InitGame() if (game.belt_dir[i] == MV_NONE) game.belt_dir_nr[i] = 3; /* not moving, next moving left */ +#if USE_NEW_PLAYER_ASSIGNMENTS + /* check if any connected player was not found in playfield */ + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + + if (player->connected && !player->present) + { + for (j = 0; j < MAX_PLAYERS; j++) + { + struct PlayerInfo *some_player = &stored_player[j]; + int jx = some_player->jx, jy = some_player->jy; + + /* assign first free player found that is present in the playfield */ + if (some_player->present && !some_player->connected) + { + player->present = FALSE; + player->active = FALSE; + + some_player->present = TRUE; + some_player->active = TRUE; + + /* + player->initial_element = some_player->initial_element; + player->artwork_element = some_player->artwork_element; + + player->block_last_field = some_player->block_last_field; + player->block_delay_adjustment = some_player->block_delay_adjustment; + */ + + StorePlayer[jx][jy] = some_player->element_nr; + + some_player->jx = some_player->last_jx = jx; + some_player->jy = some_player->last_jy = jy; + + if (local_player == player) + local_player = some_player; + + break; + } + } + } + } + +#else + /* check if any connected player was not found in playfield */ for (i = 0; i < MAX_PLAYERS; i++) { @@ -4025,6 +4114,7 @@ void InitGame() player->block_delay_adjustment = some_player->block_delay_adjustment; StorePlayer[jx][jy] = player->element_nr; + player->jx = player->last_jx = jx; player->jy = player->last_jy = jy; @@ -4033,6 +4123,7 @@ void InitGame() } } } +#endif if (tape.playing) { @@ -5140,7 +5231,10 @@ static void RemoveField(int x, int y) 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) @@ -6432,6 +6526,8 @@ static void RedrawAllInvisibleElementsForMagnifier() 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); } @@ -6444,6 +6540,8 @@ static void RedrawAllInvisibleElementsForMagnifier() 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); } @@ -8943,6 +9041,11 @@ void ContinueMoving(int x, int 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) && @@ -10104,6 +10207,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) int action_type = change->action_type; int action_mode = change->action_mode; int action_arg = change->action_arg; + int action_element = change->action_element; int i; if (!change->has_action) @@ -10115,11 +10219,21 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) (level.time > 0 ? TimeLeft : TimePlayed); - int action_arg_element = + int action_arg_element_raw = (action_arg == CA_ARG_PLAYER_TRIGGER ? change->actual_trigger_player : action_arg == CA_ARG_ELEMENT_TRIGGER ? change->actual_trigger_element : action_arg == CA_ARG_ELEMENT_TARGET ? change->target_element : + action_arg == CA_ARG_ELEMENT_ACTION ? change->action_element : + action_arg == CA_ARG_INVENTORY_RM_TRIGGER ? change->actual_trigger_element: + action_arg == CA_ARG_INVENTORY_RM_TARGET ? change->target_element : + action_arg == CA_ARG_INVENTORY_RM_ACTION ? change->action_element : EL_EMPTY); + int action_arg_element = GetElementFromGroupElement(action_arg_element_raw); + +#if 0 + if (action_arg_element_raw == EL_GROUP_START) + printf("::: %d,%d: %d ('%s')\n", x, y, element, EL_NAME(element)); +#endif int action_arg_direction = (action_arg >= CA_ARG_DIRECTION_LEFT && @@ -10176,10 +10290,13 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg == CA_ARG_NUMBER_LEVEL_SCORE ? local_player->score : 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_CV_ACTION ? GET_NEW_CE_VALUE(action_element): 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_CS_ACTION ? GET_CE_SCORE(action_element) : action_arg == CA_ARG_ELEMENT_NR_TARGET ? change->target_element : action_arg == CA_ARG_ELEMENT_NR_TRIGGER ? change->actual_trigger_element : + action_arg == CA_ARG_ELEMENT_NR_ACTION ? change->action_element : -1); int action_arg_number_old = @@ -10196,7 +10313,9 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) action_arg_number_min, action_arg_number_max); #if 1 - int trigger_player_bits = change->actual_trigger_player_bits; + int trigger_player_bits = + (change->actual_trigger_player_bits != CH_PLAYER_NONE ? + change->actual_trigger_player_bits : change->trigger_player); #else int trigger_player_bits = (change->actual_trigger_player >= EL_PLAYER_1 && @@ -10209,6 +10328,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) (action_arg >= CA_ARG_PLAYER_1 && action_arg <= CA_ARG_PLAYER_4 ? action_arg - CA_ARG_PLAYER : action_arg == CA_ARG_PLAYER_TRIGGER ? trigger_player_bits : + action_arg == CA_ARG_PLAYER_ACTION ? 1 << GET_PLAYER_NR(action_element) : PLAYER_BITS_ANY); /* ---------- execute action -------------------------------------------- */ @@ -10310,6 +10430,33 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } + case CA_SET_LEVEL_RANDOM_SEED: + { +#if 1 + /* ensure that setting a new random seed while playing is predictable */ + InitRND(action_arg_number_new ? action_arg_number_new : RND(1000000) + 1); +#else + InitRND(action_arg_number_new); +#endif + +#if 0 + printf("::: %d -> %d\n", action_arg_number_new, RND(10)); +#endif + +#if 0 + { + int i; + + printf("::: "); + for (i = 0; i < 9; i++) + printf("%d, ", RND(2)); + printf("\n"); + } +#endif + + break; + } + /* ---------- player actions ------------------------------------------ */ case CA_MOVE_PLAYER: @@ -10364,6 +10511,10 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) case CA_SET_PLAYER_SPEED: { +#if 0 + printf("::: trigger_player_bits == %d\n", trigger_player_bits); +#endif + for (i = 0; i < MAX_PLAYERS; i++) { if (trigger_player_bits & (1 << i)) @@ -10481,6 +10632,104 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } + case CA_SET_PLAYER_INVENTORY: + { + for (i = 0; i < MAX_PLAYERS; i++) + { + struct PlayerInfo *player = &stored_player[i]; + int j, k; + + if (trigger_player_bits & (1 << i)) + { + int inventory_element = action_arg_element; + + if (action_arg == CA_ARG_ELEMENT_TARGET || + action_arg == CA_ARG_ELEMENT_TRIGGER || + action_arg == CA_ARG_ELEMENT_ACTION) + { + int element = inventory_element; + int collect_count = element_info[element].collect_count_initial; + + if (!IS_CUSTOM_ELEMENT(element)) + collect_count = 1; + + if (collect_count == 0) + player->inventory_infinite_element = element; + else + for (k = 0; k < collect_count; k++) + if (player->inventory_size < MAX_INVENTORY_SIZE) + player->inventory_element[player->inventory_size++] = + element; + } + else if (action_arg == CA_ARG_INVENTORY_RM_TARGET || + action_arg == CA_ARG_INVENTORY_RM_TRIGGER || + action_arg == CA_ARG_INVENTORY_RM_ACTION) + { + if (player->inventory_infinite_element != EL_UNDEFINED && + IS_EQUAL_OR_IN_GROUP(player->inventory_infinite_element, + action_arg_element_raw)) + player->inventory_infinite_element = EL_UNDEFINED; + + for (k = 0, j = 0; j < player->inventory_size; j++) + { + if (!IS_EQUAL_OR_IN_GROUP(player->inventory_element[j], + action_arg_element_raw)) + player->inventory_element[k++] = player->inventory_element[j]; + } + + player->inventory_size = k; + } + else if (action_arg == CA_ARG_INVENTORY_RM_FIRST) + { + if (player->inventory_size > 0) + { + for (j = 0; j < player->inventory_size - 1; j++) + player->inventory_element[j] = player->inventory_element[j + 1]; + + player->inventory_size--; + } + } + else if (action_arg == CA_ARG_INVENTORY_RM_LAST) + { + if (player->inventory_size > 0) + player->inventory_size--; + } + else if (action_arg == CA_ARG_INVENTORY_RM_ALL) + { + player->inventory_infinite_element = EL_UNDEFINED; + player->inventory_size = 0; + } + else if (action_arg == CA_ARG_INVENTORY_RESET) + { + player->inventory_infinite_element = EL_UNDEFINED; + player->inventory_size = 0; + + if (level.use_initial_inventory[i]) + { + for (j = 0; j < level.initial_inventory_size[i]; j++) + { + int element = level.initial_inventory_content[i][j]; + int collect_count = element_info[element].collect_count_initial; + + if (!IS_CUSTOM_ELEMENT(element)) + collect_count = 1; + + if (collect_count == 0) + player->inventory_infinite_element = element; + else + for (k = 0; k < collect_count; k++) + if (player->inventory_size < MAX_INVENTORY_SIZE) + player->inventory_element[player->inventory_size++] = + element; + } + } + } + } + } + + break; + } + /* ---------- CE actions ---------------------------------------------- */ case CA_SET_CE_VALUE: @@ -10549,6 +10798,38 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) break; } + case CA_SET_CE_ARTWORK: + { + int artwork_element = action_arg_element; + boolean reset_frame = FALSE; + int xx, yy; + + if (action_arg == CA_ARG_ELEMENT_RESET) + artwork_element = (ei->use_gfx_element ? ei->gfx_element_initial : + element); + + if (ei->gfx_element != artwork_element) + reset_frame = TRUE; + + ei->gfx_element = artwork_element; + + SCAN_PLAYFIELD(xx, yy) + { + if (Feld[xx][yy] == element) + { + if (reset_frame) + { + ResetGfxAnimation(xx, yy); + ResetRandomAnimationValue(xx, yy); + } + + TEST_DrawLevelField(xx, yy); + } + } + + break; + } + /* ---------- engine actions ------------------------------------------ */ case CA_SET_ENGINE_SCAN_MODE: @@ -10708,8 +10989,8 @@ static boolean ChangeElement(int x, int y, int element, int page) { /* reset actual trigger element, trigger player and action element */ change->actual_trigger_element = EL_EMPTY; - change->actual_trigger_player = EL_PLAYER_1; - change->actual_trigger_player_bits = CH_PLAYER_1; + change->actual_trigger_player = EL_EMPTY; + change->actual_trigger_player_bits = CH_PLAYER_NONE; change->actual_trigger_side = CH_SIDE_NONE; change->actual_trigger_ce_value = 0; change->actual_trigger_ce_score = 0; @@ -10869,6 +11150,7 @@ static void HandleElementChange(int x, int y, int page) int element = MovingOrBlocked2Element(x, y); struct ElementInfo *ei = &element_info[element]; struct ElementChangeInfo *change = &ei->change_page[page]; + boolean handle_action_before_change = FALSE; #ifdef DEBUG if (!CAN_CHANGE_OR_HAS_ACTION(element) && @@ -10951,6 +11233,15 @@ static void HandleElementChange(int x, int y, int page) return; } +#if 1 + /* special case: set new level random seed before changing element */ + if (change->has_action && change->action_type == CA_SET_LEVEL_RANDOM_SEED) + handle_action_before_change = TRUE; + + if (change->has_action && handle_action_before_change) + ExecuteCustomElementAction(x, y, element, page); +#endif + if (change->can_change) { if (ChangeElement(x, y, element, page)) @@ -10960,7 +11251,7 @@ static void HandleElementChange(int x, int y, int page) } } - if (change->has_action) + if (change->has_action && !handle_action_before_change) ExecuteCustomElementAction(x, y, element, page); } } @@ -11096,6 +11387,11 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, change->actual_trigger_ce_value = CustomValue[trigger_x][trigger_y]; change->actual_trigger_ce_score = GET_CE_SCORE(trigger_element); +#if 0 + printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d\n", + element, EL_NAME(element), p); +#endif + if ((change->can_change && !change_done) || change->has_action) { int x, y; @@ -11106,6 +11402,21 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, { if (change->can_change && !change_done) { +#if USE_FIX_NO_ACTION_AFTER_CHANGE + /* if element already changed in this frame, not only prevent + another element change (checked in ChangeElement()), but + also prevent additional element actions for this element */ + + if (ChangeCount[x][y] >= game.max_num_changes_per_frame && + !level.use_action_after_change_bug) + continue; +#endif + +#if 0 + printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- CHANGE\n", + element, EL_NAME(element), p); +#endif + ChangeDelay[x][y] = 1; ChangeEvent[x][y] = trigger_event; @@ -11114,6 +11425,22 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, #if USE_NEW_DELAYED_ACTION else if (change->has_action) { +#if USE_FIX_NO_ACTION_AFTER_CHANGE + /* if element already changed in this frame, not only prevent + another element change (checked in ChangeElement()), but + also prevent additional element actions for this element */ + + if (ChangeCount[x][y] >= game.max_num_changes_per_frame && + !level.use_action_after_change_bug) + continue; +#endif + + +#if 0 + printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- ACTION\n", + element, EL_NAME(element), p); +#endif + ExecuteCustomElementAction(x, y, element, p); PlayLevelSoundElementAction(x, y, element, ACTION_PAGE_1 + p); } @@ -11131,6 +11458,12 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, { change_done = TRUE; change_done_any = TRUE; + +#if 0 + printf("::: TRIGGERED CHANGE FOUND: %d ['%s'], %d -- DONE\n", + element, EL_NAME(element), p); +#endif + } } } @@ -11185,6 +11518,10 @@ static boolean CheckElementChangeExt(int x, int y, RECURSION_LOOP_DETECTION_START(trigger_element, FALSE); +#if 0 + printf("::: X: trigger_player_bits == %d\n", trigger_player); +#endif + for (p = 0; p < element_info[element].num_change_pages; p++) { struct ElementChangeInfo *change = &element_info[element].change_page[p]; @@ -11710,7 +12047,7 @@ void GameActions() } if (game.restart_level) - StartGameActions(options.network, setup.autorecord, NEW_RANDOMIZE); + StartGameActions(options.network, setup.autorecord, level.random_seed); if (level.game_engine_type == GAME_ENGINE_TYPE_EM) { @@ -12561,6 +12898,9 @@ void GameActions_RND() 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); @@ -12662,12 +13002,13 @@ static boolean AllPlayersInVisibleScreen() 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 @@ -12677,7 +13018,8 @@ void ScrollLevel(int dx, int dy) return; #endif -#if 1 +#if 0 + /* (directly solved in BlitBitmap() now) */ if (bitmap_db_field2 == NULL) bitmap_db_field2 = CreateBitmap(FXSIZE, FYSIZE, DEFAULT_DEPTH); @@ -13586,6 +13928,8 @@ void TestIfElementTouchesCustomElement(int x, int y) /* 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++) @@ -13905,6 +14249,7 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) 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; @@ -13935,12 +14280,14 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) kill_x = test_x; kill_y = test_y; + break; } else if (test_element == EL_PENGUIN) { kill_x = test_x; kill_y = test_y; + break; } } @@ -13963,6 +14310,63 @@ void TestIfBadThingHitsGoodThing(int bad_x, int bad_y, int bad_move_dir) } } +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); @@ -14034,6 +14438,11 @@ void KillPlayer(struct PlayerInfo *player) if (!player->active) return; +#if 0 + printf("::: 0: killed == %d, active == %d, reanimated == %d\n", + player->killed, player->active, player->reanimated); +#endif + /* the following code was introduced to prevent an infinite loop when calling -> Bang() -> CheckTriggeredElementChangeExt() @@ -14058,8 +14467,31 @@ void KillPlayer(struct PlayerInfo *player) player->shield_normal_time_left = 0; player->shield_deadly_time_left = 0; +#if 0 + printf("::: 1: killed == %d, active == %d, reanimated == %d\n", + player->killed, player->active, player->reanimated); +#endif + Bang(jx, jy); + +#if 0 + printf("::: 2: killed == %d, active == %d, reanimated == %d\n", + player->killed, player->active, player->reanimated); +#endif + +#if USE_PLAYER_REANIMATION +#if 1 + if (player->reanimated) /* killed player may have been reanimated */ + player->killed = player->reanimated = FALSE; + else + BuryPlayer(player); +#else + if (player->killed) /* player may have been reanimated */ + BuryPlayer(player); +#endif +#else BuryPlayer(player); +#endif } static void KillPlayerUnlessEnemyProtected(int x, int y)