X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=e259a0251a9b80531b01f47657abbd4bba2ccf58;hb=caf3da0a0e3af75eb8d10f83e5105581402b387e;hp=d42afb32fab152c537e090c8a08feb90ee26f826;hpb=d5224fde97c235c903f631a4eccb9904c2ddf9c3;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index d42afb32..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) { @@ -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,11 +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 1 if (CAN_MOVE(element)) -#else - if (CAN_MOVE(element) || COULD_MOVE(element)) -#endif InitMovDir(x, y); DrawLevelField(x, y); @@ -1724,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); @@ -2234,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)) { @@ -2523,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 && @@ -2581,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; @@ -2931,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)) { @@ -3121,7 +3252,7 @@ void StartMoving(int x, int 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); @@ -3210,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); @@ -4427,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); @@ -4455,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) @@ -4658,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; @@ -4734,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); @@ -5756,6 +5922,7 @@ int DigField(struct PlayerInfo *player, { player->Switching = FALSE; player->push_delay = 0; + return MF_NO_ACTION; } @@ -5800,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: @@ -6075,6 +6248,12 @@ 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; @@ -6409,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; @@ -6459,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; @@ -6489,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;