X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=e259a0251a9b80531b01f47657abbd4bba2ccf58;hb=caf3da0a0e3af75eb8d10f83e5105581402b387e;hp=25e138060311fa14b1ebca089bd154b2c7dc68db;hpb=fbe0eaa3234fb6a69a65136f764922e24943501d;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 25e13806..e259a025 100644 --- a/src/game.c +++ b/src/game.c @@ -154,38 +154,144 @@ struct ChangingElementInfo static struct ChangingElementInfo changing_element_list[] = { - { EL_NUT_BREAKING, EL_EMERALD, 6, NULL, NULL, NULL }, - { EL_PEARL_BREAKING, EL_EMPTY, 8, NULL, NULL, NULL }, - { EL_EXIT_OPENING, EL_EXIT_OPEN, 29, NULL, NULL, NULL }, - - { EL_SWITCHGATE_OPENING, EL_SWITCHGATE_OPEN, 29, NULL, NULL, NULL }, - { EL_SWITCHGATE_CLOSING, EL_SWITCHGATE_CLOSED, 29, NULL, NULL, NULL }, - - { EL_TIMEGATE_OPENING, EL_TIMEGATE_OPEN, 29, NULL, NULL, NULL }, - { EL_TIMEGATE_CLOSING, EL_TIMEGATE_CLOSED, 29, NULL, NULL, NULL }, - - { EL_ACID_SPLASH_LEFT, EL_EMPTY, 8, NULL, NULL, NULL }, - { EL_ACID_SPLASH_RIGHT, EL_EMPTY, 8, NULL, NULL, NULL }, - - { EL_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVATING, 0, - InitBuggyBase, NULL, NULL }, - { EL_SP_BUGGY_BASE_ACTIVATING,EL_SP_BUGGY_BASE_ACTIVE, 0, - InitBuggyBase, NULL, NULL }, - { EL_SP_BUGGY_BASE_ACTIVE, EL_SP_BUGGY_BASE, 0, - InitBuggyBase, WarnBuggyBase, NULL }, - - { EL_TRAP, EL_TRAP_ACTIVE, 0, - InitTrap, NULL, ActivateTrap }, - { EL_TRAP_ACTIVE, EL_TRAP, 31, - NULL, ChangeActiveTrap, NULL }, - - { EL_ROBOT_WHEEL_ACTIVE, EL_ROBOT_WHEEL, 0, - InitRobotWheel, RunRobotWheel, StopRobotWheel }, + { + EL_NUT_BREAKING, + EL_EMERALD, + 6, + NULL, + NULL, + NULL + }, + { + EL_PEARL_BREAKING, + EL_EMPTY, + 8, + NULL, + NULL, + NULL + }, + { + EL_EXIT_OPENING, + EL_EXIT_OPEN, + 29, + NULL, + NULL, + NULL + }, + { + EL_SWITCHGATE_OPENING, + EL_SWITCHGATE_OPEN, + 29, + NULL, + NULL, + NULL + }, + { + EL_SWITCHGATE_CLOSING, + EL_SWITCHGATE_CLOSED, + 29, + NULL, + NULL, + NULL + }, + { + EL_TIMEGATE_OPENING, + EL_TIMEGATE_OPEN, + 29, + NULL, + NULL, + NULL + }, + { + EL_TIMEGATE_CLOSING, + EL_TIMEGATE_CLOSED, + 29, + NULL, + NULL, + NULL + }, - { EL_TIMEGATE_SWITCH_ACTIVE, EL_TIMEGATE_SWITCH, 0, - InitTimegateWheel, RunTimegateWheel, NULL }, + { + EL_ACID_SPLASH_LEFT, + EL_EMPTY, + 8, + NULL, + NULL, + NULL + }, + { + EL_ACID_SPLASH_RIGHT, + EL_EMPTY, + 8, + NULL, + NULL, + NULL + }, + { + EL_SP_BUGGY_BASE, + EL_SP_BUGGY_BASE_ACTIVATING, + 0, + InitBuggyBase, + NULL, + NULL + }, + { + EL_SP_BUGGY_BASE_ACTIVATING, + EL_SP_BUGGY_BASE_ACTIVE, + 0, + InitBuggyBase, + NULL, + NULL + }, + { + EL_SP_BUGGY_BASE_ACTIVE, + EL_SP_BUGGY_BASE, + 0, + InitBuggyBase, + WarnBuggyBase, + NULL + }, + { + EL_TRAP, + EL_TRAP_ACTIVE, + 0, + InitTrap, + NULL, + ActivateTrap + }, + { + EL_TRAP_ACTIVE, + EL_TRAP, + 31, + NULL, + ChangeActiveTrap, + NULL + }, + { + EL_ROBOT_WHEEL_ACTIVE, + EL_ROBOT_WHEEL, + 0, + InitRobotWheel, + RunRobotWheel, + StopRobotWheel + }, + { + EL_TIMEGATE_SWITCH_ACTIVE, + EL_TIMEGATE_SWITCH, + 0, + InitTimegateWheel, + RunTimegateWheel, + NULL + }, - { EL_UNDEFINED, EL_UNDEFINED, -1, NULL } + { + EL_UNDEFINED, + EL_UNDEFINED, + -1, + NULL, + NULL, + NULL + } }; static struct ChangingElementInfo changing_element[MAX_NUM_ELEMENTS]; @@ -561,6 +667,7 @@ static void InitGameEngine() changing_element[i].post_change_function = NULL; } + /* add changing elements from pre-defined list */ i = 0; while (changing_element_list[i].base_element != EL_UNDEFINED) { @@ -576,6 +683,30 @@ static void InitGameEngine() i++; } + + /* add changing elements from custom element configuration */ + for (i=0; i < NUM_CUSTOM_ELEMENTS; i++) + { + struct CustomElementChangeInfo *change = &level.custom_element[i].change; + int element = EL_CUSTOM_START + i; + + /* only add custom elements that change after fixed/random frame delay */ + if (!IS_CHANGEABLE(element) || + (!HAS_CHANGE_EVENT(element, CE_DELAY_FIXED) && + !HAS_CHANGE_EVENT(element, CE_DELAY_RANDOM))) + continue; + + changing_element[element].base_element = element; + changing_element[element].next_element = change->successor; + changing_element[element].change_delay = 0; + + if (HAS_CHANGE_EVENT(element, CE_DELAY_FIXED)) + changing_element[element].change_delay += + change->delay_fixed * change->delay_frames; + + if (HAS_CHANGE_EVENT(element, CE_DELAY_RANDOM)); + /* random frame delay added at runtime for each element individually */ + } } @@ -705,7 +836,7 @@ void InitGame() AllPlayersGone = FALSE; - game.yam_content_nr = 0; + game.yamyam_content_nr = 0; game.magic_wall_active = FALSE; game.magic_wall_time_left = 0; game.light_time_left = 0; @@ -947,8 +1078,7 @@ void InitGame() if (setup.sound_music) PlayMusic(level_nr); - if (!tape.playing) - KeyboardAutoRepeatOff(); + KeyboardAutoRepeatOffUnlessAutoplay(); if (options.debug) { @@ -1183,7 +1313,7 @@ void GameWon() if ((hi_pos = NewHiScore()) >= 0) { - game_status = HALLOFFAME; + game_status = GAME_MODE_SCORES; DrawHallOfFame(hi_pos); if (raise_level) { @@ -1193,7 +1323,7 @@ void GameWon() } else { - game_status = MAINMENU; + game_status = GAME_MODE_MAIN; if (raise_level) { level_nr++; @@ -1524,7 +1654,7 @@ void Explode(int ex, int ey, int phase, int mode) Feld[ex][ey] = center_element; } - for (y=ey-1; y<=ey+1; y++) for(x=ex-1; x<=ex+1; x++) + for (y = ey - 1; y <= ey + 1; y++) for(x = ex - 1; x <= ex + 1; x++) { int element; @@ -1604,10 +1734,14 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = EL_BD_DIAMOND; else if (center_element == EL_SP_ELECTRON) Store[x][y] = EL_SP_INFOTRON; - else if (center_element == EL_YAMYAM) - Store[x][y] = level.yam_content[game.yam_content_nr][x-ex+1][y-ey+1]; 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][x - ex + 1][y - ey + 1]; + else if (IS_CUSTOM_ELEMENT(center_element)) + Store[x][y] = + CUSTOM_ELEMENT_INFO(center_element).content[x - ex + 1][y - ey + 1]; else if (element == EL_WALL_EMERALD) Store[x][y] = EL_EMERALD; else if (element == EL_WALL_DIAMOND) @@ -1649,7 +1783,8 @@ void Explode(int ex, int ey, int phase, int mode) } if (center_element == EL_YAMYAM) - game.yam_content_nr = (game.yam_content_nr + 1) % level.num_yam_contents; + game.yamyam_content_nr = + (game.yamyam_content_nr + 1) % level.num_yamyam_contents; return; } @@ -1679,7 +1814,7 @@ void Explode(int ex, int ey, int phase, int mode) if (IS_PLAYER(x, y)) KillHeroUnlessProtected(x, y); - else if (IS_EXPLOSIVE(element)) + else if (CAN_EXPLODE(element)) { Feld[x][y] = Store2[x][y]; Store2[x][y] = 0; @@ -1702,7 +1837,7 @@ void Explode(int ex, int ey, int phase, int mode) MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0; InitField(x, y, FALSE); - if (CAN_MOVE(element) || COULD_MOVE(element)) + if (CAN_MOVE(element)) InitMovDir(x, y); DrawLevelField(x, y); @@ -1720,7 +1855,7 @@ void Explode(int ex, int ey, int phase, int mode) if (phase == delay) DrawLevelFieldCrumbledSand(x, y); - if (IS_WALKABLE_OVER(Back[x][y])) + if (IS_WALKABLE_OVER(Back[x][y]) && Back[x][y] != EL_EMPTY) { DrawLevelElement(x, y, Back[x][y]); DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame); @@ -2230,7 +2365,7 @@ void Impact(int x, int y) if (!lastline && object_hit) /* check which object was hit */ { - if (CAN_CHANGE(element) && + if (CAN_PASS_MAGIC_WALL(element) && (smashed == EL_MAGIC_WALL || smashed == EL_BD_MAGIC_WALL)) { @@ -2519,13 +2654,13 @@ void TurnRound(int x, int y) int rnd = RND(rnd_value); if (IN_LEV_FIELD(left_x, left_y) && - (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y]))) + (IS_FREE(left_x, left_y) || IS_FOOD_PIG(Feld[left_x][left_y]))) can_turn_left = TRUE; if (IN_LEV_FIELD(right_x, right_y) && - (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y]))) + (IS_FREE(right_x, right_y) || IS_FOOD_PIG(Feld[right_x][right_y]))) can_turn_right = TRUE; if (IN_LEV_FIELD(move_x, move_y) && - (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y]))) + (IS_FREE(move_x, move_y) || IS_FOOD_PIG(Feld[move_x][move_y]))) can_move_on = TRUE; if (can_turn_left && @@ -2577,7 +2712,7 @@ void TurnRound(int x, int y) MovDir[x][y] = back_dir; if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) && - !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y])) + !IS_FOOD_PIG(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y])) MovDir[x][y] = old_move_dir; MovDelay[x][y] = 0; @@ -2804,7 +2939,7 @@ static boolean JustBeingPushed(int x, int y) void StartMoving(int x, int y) { - static boolean use_spring_bug = TRUE; + boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0)); boolean started_moving = FALSE; /* some elements can fall _and_ move */ int element = Feld[x][y]; @@ -2927,7 +3062,7 @@ void StartMoving(int x, int y) Store[x][y] = 0; } } - else if (CAN_CHANGE(element) && + else if (CAN_PASS_MAGIC_WALL(element) && (Feld[x][y+1] == EL_MAGIC_WALL_ACTIVE || Feld[x][y+1] == EL_BD_MAGIC_WALL_ACTIVE)) { @@ -3110,20 +3245,14 @@ void StartMoving(int x, int y) int sx = SCREENX(xx), sy = SCREENY(yy); int flame_graphic = graphic + (i - 1); -#if 1 if (!IN_LEV_FIELD(xx, yy) || IS_DRAGONFIRE_PROOF(Feld[xx][yy])) break; -#else - if (!IN_LEV_FIELD(xx, yy) || - IS_HISTORIC_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLOSION) - break; -#endif if (MovDelay[x][y]) { int flamed = MovingOrBlocked2Element(xx, yy); - if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed)) + if (IS_ENEMY(flamed) || CAN_EXPLODE(flamed)) Bang(xx, yy); else RemoveMovingField(xx, yy); @@ -3212,7 +3341,7 @@ void StartMoving(int x, int y) } else if (element == EL_PIG && IN_LEV_FIELD(newx, newy)) { - if (IS_GEM(Feld[newx][newy])) + if (IS_FOOD_PIG(Feld[newx][newy])) { if (IS_MOVING(newx, newy)) RemoveMovingField(newx, newy); @@ -4429,10 +4558,23 @@ static void ChangeElement(int x, int y) { int element = Feld[x][y]; + if (IS_MOVING(x, y)) /* never change a running system :-) */ + return; + if (MovDelay[x][y] == 0) /* initialize element change */ { MovDelay[x][y] = changing_element[element].change_delay + 1; + if (IS_CUSTOM_ELEMENT(element) && + HAS_CHANGE_EVENT(element, CE_DELAY_RANDOM)) + { + int i = element - EL_CUSTOM_START; + int max_random_delay = level.custom_element[i].change.delay_random; + int delay_frames = level.custom_element[i].change.delay_frames; + + MovDelay[x][y] += RND(max_random_delay * delay_frames); + } + ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); @@ -4457,6 +4599,11 @@ static void ChangeElement(int x, int y) ResetGfxAnimation(x, y); ResetRandomAnimationValue(x, y); +#if 1 + InitField(x, y, FALSE); + if (CAN_MOVE(element)) + InitMovDir(x, y); +#endif DrawLevelField(x, y); if (changing_element[element].post_change_function) @@ -4543,7 +4690,7 @@ void GameActions() byte *recorded_player_action; byte summarized_player_action = 0; - if (game_status != PLAYING) + if (game_status != GAME_MODE_PLAYING) return; action_delay_value = @@ -4569,7 +4716,7 @@ void GameActions() HandleNetworking(); #endif - if (game_status != PLAYING) + if (game_status != GAME_MODE_PLAYING) return; if (!network_player_action_received) @@ -4660,6 +4807,15 @@ void GameActions() element = Feld[x][y]; graphic = el2img(element); +#if 0 + if (element == -1) + { + printf("::: %d,%d: %d [%d]\n", x, y, element, FrameCounter); + + element = graphic = 0; + } +#endif + if (graphic_info[graphic].anim_global_sync) GfxFrame[x][y] = FrameCounter; @@ -4736,13 +4892,21 @@ void GameActions() MauerAbleger(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); +#if 0 else if (IS_AUTO_CHANGING(element)) ChangeElement(x, y); +#endif else if (element == EL_EXPLOSION) ; /* drawing of correct explosion animation is handled separately */ - else if (IS_ANIMATED(graphic)) + else if (IS_ANIMATED(graphic) && !IS_AUTO_CHANGING(element)) DrawLevelGraphicAnimationIfNeeded(x, y, graphic); +#if 1 + /* this may take place after moving, therefore element may have changed */ + if (IS_AUTO_CHANGING(Feld[x][y])) + ChangeElement(x, y); +#endif + if (IS_BELT_ACTIVE(element)) PlaySoundLevelAction(x, y, ACTION_ACTIVE); @@ -5711,7 +5875,6 @@ void RemoveHero(struct PlayerInfo *player) static boolean checkDiagonalPushing(struct PlayerInfo *player, int x, int y, int real_dx, int real_dy) { -#if 1 int jx, jy, dx, dy, xx, yy; if (real_dx == 0 || real_dy == 0) /* no diagonal direction => push */ @@ -5725,32 +5888,7 @@ static boolean checkDiagonalPushing(struct PlayerInfo *player, xx = jx + (dx == 0 ? real_dx : 0); yy = jy + (dy == 0 ? real_dy : 0); - return (!IN_LEV_FIELD(xx, yy) || IS_SOLID(Feld[xx][yy])); -#else - - if (real_dx && real_dy) /* diagonal direction input => do check */ - { - /* diagonal direction: check alternative direction */ - int jx = player->jx, jy = player->jy; - int dx = x - jx, dy = y - jy; - int xx = jx + (dx == 0 ? real_dx : 0); - int yy = jy + (dy == 0 ? real_dy : 0); - - if (IN_LEV_FIELD(xx, yy)) - { - int element = Feld[xx][yy]; - - if (game.engine_version < VERSION_IDENT(2,2,0)) - return IS_HISTORIC_SOLID(element); - else - return !(IS_WALKABLE(element) || - IS_DIGGABLE(element) || - IS_COLLECTIBLE(element)); - } - } - - return TRUE; /* no diagonal direction input => push object */ -#endif + return (!IN_LEV_FIELD(xx, yy) || IS_SOLID_FOR_PUSHING(Feld[xx][yy])); } /* @@ -5784,6 +5922,7 @@ int DigField(struct PlayerInfo *player, { player->Switching = FALSE; player->push_delay = 0; + return MF_NO_ACTION; } @@ -5828,6 +5967,12 @@ int DigField(struct PlayerInfo *player, element = Feld[x][y]; +#if 1 + if (mode == DF_SNAP && !IS_SNAPPABLE(element) && + game.engine_version >= VERSION_IDENT(2,2,0)) + return MF_NO_ACTION; +#endif + switch (element) { case EL_EMPTY: @@ -6103,20 +6248,17 @@ int DigField(struct PlayerInfo *player, player->Pushing = TRUE; +#if 0 + if (element == EL_ROCK) + printf("::: wanna push [%d] [%d]\n", + FrameCounter, player->push_delay_value); +#endif + if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy)) return MF_NO_ACTION; -#if 1 if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) return MF_NO_ACTION; -#else - if (real_dy) - { - if (IN_LEV_FIELD(jx, jy+real_dy) && - !IS_HISTORIC_SOLID(Feld[jx][jy+real_dy])) - return MF_NO_ACTION; - } -#endif if (player->push_delay == 0) player->push_delay = FrameCounter; @@ -6358,23 +6500,8 @@ int DigField(struct PlayerInfo *player, || !IS_SB_ELEMENT(element)))) return MF_NO_ACTION; -#if 1 if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) return MF_NO_ACTION; -#else - if (dx && real_dy) - { - if (IN_LEV_FIELD(jx, jy+real_dy) && - !IS_HISTORIC_SOLID(Feld[jx][jy+real_dy])) - return MF_NO_ACTION; - } - else if (dy && real_dx) - { - if (IN_LEV_FIELD(jx+real_dx, jy) && - !IS_HISTORIC_SOLID(Feld[jx+real_dx][jy])) - return MF_NO_ACTION; - } -#endif if (player->push_delay == 0) player->push_delay = FrameCounter; @@ -6461,7 +6588,41 @@ int DigField(struct PlayerInfo *player, break; default: - if (IS_PUSHABLE(element)) + + if (IS_WALKABLE(element)) + { + break; + } + else if (IS_DIGGABLE(element)) + { + RemoveField(x, y); +#if 1 + if (mode != DF_SNAP) + { + GfxElement[x][y] = + (CAN_BE_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element)); + player->is_digging = TRUE; + } +#endif + PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING); + + break; + } + else if (IS_COLLECTIBLE(element)) + { + RemoveField(x, y); +#if 1 + if (mode != DF_SNAP) + { + GfxElement[x][y] = element; + player->is_collecting = TRUE; + } +#endif + PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING); + + break; + } + else if (IS_PUSHABLE(element)) { if (mode == DF_SNAP) return MF_NO_ACTION; @@ -6474,23 +6635,8 @@ int DigField(struct PlayerInfo *player, if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy)) return MF_NO_ACTION; -#if 1 if (!checkDiagonalPushing(player, x, y, real_dx, real_dy)) return MF_NO_ACTION; -#else - if (dx && real_dy) - { - if (IN_LEV_FIELD(jx, jy+real_dy) && - !IS_HISTORIC_SOLID(Feld[jx][jy+real_dy])) - return MF_NO_ACTION; - } - else if (dy && real_dx) - { - if (IN_LEV_FIELD(jx+real_dx, jy) && - !IS_HISTORIC_SOLID(Feld[jx+real_dx][jy])) - return MF_NO_ACTION; - } -#endif if (player->push_delay == 0) player->push_delay = FrameCounter; @@ -6526,6 +6672,9 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) int jx = player->jx, jy = player->jy; int x = jx + dx, y = jy + dy; + if (player->MovPos && game.engine_version >= VERSION_IDENT(2,2,0)) + return FALSE; + if (!player->active || !IN_LEV_FIELD(x, y)) return FALSE; @@ -6556,7 +6705,7 @@ boolean SnapField(struct PlayerInfo *player, int dx, int dy) dy < 0 ? MV_UP : dy > 0 ? MV_DOWN : MV_NO_MOVING); - if (!DigField(player, x, y, 0, 0, DF_SNAP)) + if (DigField(player, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION) return FALSE; player->snapped = TRUE; @@ -6812,7 +6961,7 @@ void RequestQuitGame(boolean ask_if_really_quit) else #endif { - game_status = MAINMENU; + game_status = GAME_MODE_MAIN; DrawMainMenu(); } } @@ -6973,7 +7122,7 @@ static void HandleGameButtons(struct GadgetInfo *gi) { int id = gi->custom_id; - if (game_status != PLAYING) + if (game_status != GAME_MODE_PLAYING) return; switch (id)