X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=451c167fffe2cbd25c86fd8ad349912e123e7a47;hb=7992b03de18aad8527835dfa03375f3a30a7e673;hp=71d83bbc815de1eea134facc57cec36018580851;hpb=3f336329750dff46fe1634f317eee24515cd9d11;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 71d83bbc..451c167f 100644 --- a/src/game.c +++ b/src/game.c @@ -59,10 +59,13 @@ #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_DELAYED_GFX_REDRAW (USE_NEW_STUFF * 0) #if USE_DELAYED_GFX_REDRAW #define TEST_DrawLevelField(x, y) \ @@ -1126,6 +1129,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 +1784,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 = FALSE; /* if player was just killed, reanimate him */ + } +#endif } static void InitField(int x, int y, boolean init_game) @@ -3665,6 +3680,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; @@ -3710,10 +3730,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 +3755,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 +3779,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 +3812,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); @@ -5140,7 +5180,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 +6475,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 +6489,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 +8990,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 +10156,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) @@ -10119,6 +10172,7 @@ static void ExecuteCustomElementAction(int x, int y, int element, int page) (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 : EL_EMPTY); int action_arg_direction = @@ -10176,10 +10230,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 = @@ -10209,6 +10266,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 -------------------------------------------- */ @@ -11096,6 +11154,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 +11169,12 @@ static boolean CheckTriggeredElementChangeExt(int trigger_x, int trigger_y, { if (change->can_change && !change_done) { + +#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 +11183,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 +11216,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 + } } } @@ -12561,6 +12652,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 +12756,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 +12772,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 +13682,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 +14003,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 +14034,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 +14064,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); @@ -14059,7 +14217,13 @@ void KillPlayer(struct PlayerInfo *player) 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)