X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=d7fb2368f8536f59501a5dc05cbe86eb6309eda9;hb=f5356588a234e34e349c0b1eba02008655fdee87;hp=ce6ca3ab084668cdfcd63662c5408697270e0fce;hpb=d4665f01d15ba3679f378819710a84d6c2348a9c;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index ce6ca3ab..d7fb2368 100644 --- a/src/game.c +++ b/src/game.c @@ -102,6 +102,7 @@ /* forward declaration for internal use */ static void CheckGravityMovement(struct PlayerInfo *); +static void KillHeroUnlessForceField(struct PlayerInfo *); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); @@ -179,6 +180,50 @@ void GetPlayerConfig() InitJoysticks(); } +static int getBeltNrFromElement(int element) +{ + return (element < EL_BELT2_LEFT ? 0 : + element < EL_BELT3_LEFT ? 1 : + element < EL_BELT4_LEFT ? 2 : 3); +} + +static int getBeltNrFromSwitchElement(int element) +{ + return (element < EL_BELT2_SWITCH_LEFT ? 0 : + element < EL_BELT3_SWITCH_LEFT ? 1 : + element < EL_BELT4_SWITCH_LEFT ? 2 : 3); +} + +static int getBeltDirNrFromSwitchElement(int element) +{ + static int belt_base_element[4] = + { + EL_BELT1_SWITCH_LEFT, + EL_BELT2_SWITCH_LEFT, + EL_BELT3_SWITCH_LEFT, + EL_BELT4_SWITCH_LEFT + }; + + int belt_nr = getBeltNrFromSwitchElement(element); + int belt_dir_nr = element - belt_base_element[belt_nr]; + + return (belt_dir_nr % 3); +} + +static int getBeltDirFromSwitchElement(int element) +{ + static int belt_move_dir[3] = + { + MV_LEFT, + MV_NO_MOVING, + MV_RIGHT + }; + + int belt_dir_nr = getBeltDirNrFromSwitchElement(element); + + return belt_move_dir[belt_dir_nr]; +} + static void InitField(int x, int y, boolean init_game) { switch (Feld[x][y]) @@ -237,36 +282,41 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = EL_BADEWANNE5; break; - case EL_KAEFER_R: - case EL_KAEFER_O: - case EL_KAEFER_L: - case EL_KAEFER_U: + case EL_KAEFER_RIGHT: + case EL_KAEFER_UP: + case EL_KAEFER_LEFT: + case EL_KAEFER_DOWN: case EL_KAEFER: - case EL_FLIEGER_R: - case EL_FLIEGER_O: - case EL_FLIEGER_L: - case EL_FLIEGER_U: + case EL_FLIEGER_RIGHT: + case EL_FLIEGER_UP: + case EL_FLIEGER_LEFT: + case EL_FLIEGER_DOWN: case EL_FLIEGER: - case EL_BUTTERFLY_R: - case EL_BUTTERFLY_O: - case EL_BUTTERFLY_L: - case EL_BUTTERFLY_U: + case EL_BUTTERFLY_RIGHT: + case EL_BUTTERFLY_UP: + case EL_BUTTERFLY_LEFT: + case EL_BUTTERFLY_DOWN: case EL_BUTTERFLY: - case EL_FIREFLY_R: - case EL_FIREFLY_O: - case EL_FIREFLY_L: - case EL_FIREFLY_U: + case EL_FIREFLY_RIGHT: + case EL_FIREFLY_UP: + case EL_FIREFLY_LEFT: + case EL_FIREFLY_DOWN: case EL_FIREFLY: - case EL_PACMAN_R: - case EL_PACMAN_O: - case EL_PACMAN_L: - case EL_PACMAN_U: + case EL_PACMAN_RIGHT: + case EL_PACMAN_UP: + case EL_PACMAN_LEFT: + case EL_PACMAN_DOWN: case EL_MAMPFER: case EL_MAMPFER2: case EL_ROBOT: case EL_PACMAN: case EL_SP_SNIKSNAK: case EL_SP_ELECTRON: + case EL_MOLE_LEFT: + case EL_MOLE_RIGHT: + case EL_MOLE_UP: + case EL_MOLE_DOWN: + case EL_MOLE: InitMovDir(x, y); break; @@ -295,7 +345,6 @@ static void InitField(int x, int y, boolean init_game) local_player->sokobanfields_still_needed++; break; - case EL_MAULWURF: case EL_PINGUIN: local_player->friends_still_needed++; break; @@ -322,6 +371,46 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = EL_EM_KEY_4; break; + case EL_BELT1_SWITCH_LEFT: + case EL_BELT1_SWITCH_MIDDLE: + case EL_BELT1_SWITCH_RIGHT: + case EL_BELT2_SWITCH_LEFT: + case EL_BELT2_SWITCH_MIDDLE: + case EL_BELT2_SWITCH_RIGHT: + case EL_BELT3_SWITCH_LEFT: + case EL_BELT3_SWITCH_MIDDLE: + case EL_BELT3_SWITCH_RIGHT: + case EL_BELT4_SWITCH_LEFT: + case EL_BELT4_SWITCH_MIDDLE: + case EL_BELT4_SWITCH_RIGHT: + if (init_game) + { + int belt_nr = getBeltNrFromSwitchElement(Feld[x][y]); + int belt_dir = getBeltDirFromSwitchElement(Feld[x][y]); + int belt_dir_nr = getBeltDirNrFromSwitchElement(Feld[x][y]); + + if (game.belt_dir_nr[belt_nr] == 3) /* initial value */ + { + game.belt_dir[belt_nr] = belt_dir; + game.belt_dir_nr[belt_nr] = belt_dir_nr; + } + else /* more than one switch -- set it like the first switch */ + { + Feld[x][y] = Feld[x][y] - belt_dir_nr + game.belt_dir_nr[belt_nr]; + } + } + break; + + case EL_SWITCHGATE_SWITCH_2: /* always start with same switch pos */ + if (init_game) + Feld[x][y] = EL_SWITCHGATE_SWITCH_1; + break; + + case EL_LIGHT_SWITCH_ON: + if (init_game) + game.light_time_left = 10 * FRAMES_PER_SECOND; + break; + default: break; } @@ -391,6 +480,9 @@ void InitGame() player->last_jx = player->last_jy = 0; player->jx = player->jy = 0; + player->force_field_passive_time_left = 0; + player->force_field_active_time_left = 0; + DigField(player, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); @@ -423,8 +515,13 @@ void InitGame() AllPlayersGone = FALSE; game.magic_wall_active = FALSE; game.magic_wall_time_left = 0; + game.switchgate_pos = 0; + game.light_time_left = 0; for (i=0; i<4; i++) + { game.belt_dir[i] = MV_NO_MOVING; + game.belt_dir_nr[i] = 3; /* not moving, next moving left */ + } for (i=0; i 0) + { + Feld[xx][yy] = EL_LIGHT_SWITCH_ON; + DrawLevelField(xx, yy); + } + else if (element == EL_LIGHT_SWITCH_ON && + game.light_time_left == 0) + { + Feld[xx][yy] = EL_LIGHT_SWITCH_OFF; + DrawLevelField(xx, yy); + } + + if (element == EL_INVISIBLE_STEEL || + element == EL_UNSICHTBAR || + element == EL_SAND_INVISIBLE) + DrawLevelField(xx, yy); + } + } +} + void Impact(int x, int y) { boolean lastline = (y == lev_fieldy-1); @@ -1464,8 +1720,8 @@ void Impact(int x, int y) if (element == EL_TROPFEN && (lastline || object_hit)) /* acid drop */ { if (object_hit && IS_PLAYER(x, y+1)) - KillHero(PLAYERINFO(x, y+1)); - else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN)) + KillHeroUnlessForceField(PLAYERINFO(x, y+1)); + else if (object_hit && smashed == EL_PINGUIN) Bang(x, y+1); else { @@ -1497,10 +1753,10 @@ void Impact(int x, int y) if (IS_PLAYER(x, y+1)) { - KillHero(PLAYERINFO(x, y+1)); + KillHeroUnlessForceField(PLAYERINFO(x, y+1)); return; } - else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN) + else if (smashed == EL_PINGUIN) { Bang(x, y+1); return; @@ -1517,7 +1773,8 @@ void Impact(int x, int y) { if (IS_ENEMY(smashed) || smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE || - smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE) + smashed == EL_SONDE || smashed == EL_SCHWEIN || + smashed == EL_DRACHE || smashed == EL_MOLE) { Bang(x, y+1); return; @@ -1542,6 +1799,20 @@ void Impact(int x, int y) PlaySoundLevel(x, y, SND_QUIRK); return; } + else if (IS_BELT_SWITCH(smashed)) + { + ToggleBeltSwitch(x, y+1); + } + else if (smashed == EL_SWITCHGATE_SWITCH_1 || + smashed == EL_SWITCHGATE_SWITCH_2) + { + ToggleSwitchgateSwitch(x, y+1); + } + else if (smashed == EL_LIGHT_SWITCH_OFF || + smashed == EL_LIGHT_SWITCH_ON) + { + ToggleLightSwitch(x, y+1); + } } } } @@ -1599,7 +1870,7 @@ void Impact(int x, int y) break; } - if (sound>=0) + if (sound >= 0) PlaySoundLevel(x, y, sound); } } @@ -1653,10 +1924,10 @@ void TurnRound(int x, int y) TestIfBadThingHitsOtherBadThing(x, y); if (IN_LEV_FIELD(right_x, right_y) && - IS_FREE_OR_PLAYER(right_x, right_y)) + IS_FREE(right_x, right_y)) MovDir[x][y] = right_dir; else if (!IN_LEV_FIELD(move_x, move_y) || - !IS_FREE_OR_PLAYER(move_x, move_y)) + !IS_FREE(move_x, move_y)) MovDir[x][y] = left_dir; if (element == EL_KAEFER && MovDir[x][y] != old_move_dir) @@ -1670,10 +1941,10 @@ void TurnRound(int x, int y) TestIfBadThingHitsOtherBadThing(x, y); if (IN_LEV_FIELD(left_x, left_y) && - IS_FREE_OR_PLAYER(left_x, left_y)) + IS_FREE(left_x, left_y)) MovDir[x][y] = left_dir; else if (!IN_LEV_FIELD(move_x, move_y) || - !IS_FREE_OR_PLAYER(move_x, move_y)) + !IS_FREE(move_x, move_y)) MovDir[x][y] = right_dir; if ((element == EL_FLIEGER || @@ -1856,8 +2127,36 @@ void TurnRound(int x, int y) MovDelay[x][y] = 0; } - else if (element == EL_ROBOT || element == EL_SONDE || - element == EL_MAULWURF || element == EL_PINGUIN) + else if (element == EL_MOLE) + { + boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE; + + if (IN_LEV_FIELD(move_x, move_y) && + (IS_FREE(move_x, move_y) || IS_AMOEBOID(Feld[move_x][move_y]) || + Feld[move_x][move_y] == EL_DEAMOEBING)) + can_move_on = TRUE; + + if (!can_move_on) + { + if (IN_LEV_FIELD(left_x, left_y) && + (IS_FREE(left_x, left_y) || IS_AMOEBOID(Feld[left_x][left_y]))) + can_turn_left = TRUE; + if (IN_LEV_FIELD(right_x, right_y) && + (IS_FREE(right_x, right_y) || IS_AMOEBOID(Feld[right_x][right_y]))) + can_turn_right = TRUE; + + if (can_turn_left && can_turn_right) + MovDir[x][y] = (RND(2) ? left_dir : right_dir); + else if (can_turn_left) + MovDir[x][y] = left_dir; + else + MovDir[x][y] = right_dir; + } + + if (MovDir[x][y] != old_move_dir) + MovDelay[x][y] = 9; + } + else if (element == EL_ROBOT || element == EL_SONDE || element == EL_PINGUIN) { int attr_x = -1, attr_y = -1; @@ -1892,7 +2191,7 @@ void TurnRound(int x, int y) attr_y = ZY; } - if (element == EL_MAULWURF || element == EL_PINGUIN) + if (element == EL_PINGUIN) { int i; static int xy[4][2] = @@ -1958,7 +2257,7 @@ void TurnRound(int x, int y) if (IN_LEV_FIELD(newx, newy) && (IS_FREE(newx, newy) || Feld[newx][newy] == EL_SALZSAEURE || - ((element == EL_MAULWURF || element == EL_PINGUIN) && + (element == EL_PINGUIN && (Feld[newx][newy] == EL_AUSGANG_AUF || IS_MAMPF3(Feld[newx][newy]))))) return; @@ -1970,7 +2269,7 @@ void TurnRound(int x, int y) if (IN_LEV_FIELD(newx, newy) && (IS_FREE(newx, newy) || Feld[newx][newy] == EL_SALZSAEURE || - ((element == EL_MAULWURF || element == EL_PINGUIN) && + (element == EL_PINGUIN && (Feld[newx][newy] == EL_AUSGANG_AUF || IS_MAMPF3(Feld[newx][newy]))))) return; @@ -2145,6 +2444,17 @@ void StartMoving(int x, int y) InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT); } } + else if (IS_BELT(Feld[x][y+1])) + { + boolean left_is_free = (x>0 && IS_FREE(x-1, y)); + boolean right_is_free = (x= (1000 / GameFrameDelay) && !tape.pausing) + if (game.light_time_left > 0) + { + game.light_time_left--; + + if (game.light_time_left == 0) + { + for (y=0; y= (1000 / GameFrameDelay)) { TimeFrames = 0; TimePlayed++; + for (i=0; i 0) + stored_player[i].force_field_active_time_left--; + } + } + if (tape.recording || tape.playing) DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed); @@ -3875,7 +4386,14 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, BuryHero(player); } else - KillHero(player); + { +#if 1 + TestIfBadThingHitsHero(new_jx, new_jy); +#else + if (player->force_field_time_left == 0) + KillHero(player); +#endif + } return MF_MOVING; } @@ -4189,7 +4707,14 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) if (killx != goodx || killy != goody) { if (IS_PLAYER(goodx, goody)) - KillHero(PLAYERINFO(goodx, goody)); + { + struct PlayerInfo *player = PLAYERINFO(goodx, goody); + + if (player->force_field_active_time_left > 0) + Bang(killx, killy); + else if (player->force_field_passive_time_left == 0) + KillHero(player); + } else Bang(goodx, goody); } @@ -4244,7 +4769,14 @@ void TestIfBadThingHitsGoodThing(int badx, int bady) if (killx != badx || killy != bady) { if (IS_PLAYER(killx, killy)) - KillHero(PLAYERINFO(killx, killy)); + { + struct PlayerInfo *player = PLAYERINFO(killx, killy); + + if (player->force_field_active_time_left > 0) + Bang(badx, bady); + else if (player->force_field_passive_time_left == 0) + KillHero(player); + } else Bang(killx, killy); } @@ -4314,10 +4846,20 @@ void KillHero(struct PlayerInfo *player) if (IS_PFORTE(Feld[jx][jy])) Feld[jx][jy] = EL_LEERRAUM; + /* deactivate force field (else Bang()/Explode() would not work right) */ + player->force_field_passive_time_left = 0; + player->force_field_active_time_left = 0; + Bang(jx, jy); BuryHero(player); } +static void KillHeroUnlessForceField(struct PlayerInfo *player) +{ + if (!FORCE_FIELD_ON(player)) + KillHero(player); +} + void BuryHero(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; @@ -4386,6 +4928,7 @@ int DigField(struct PlayerInfo *player, break; case EL_ERDREICH: + case EL_SAND_INVISIBLE: Feld[x][y] = EL_LEERRAUM; PlaySoundLevel(x, y, SND_SCHLURF); break; @@ -4423,6 +4966,34 @@ int DigField(struct PlayerInfo *player, PlaySoundLevel(x, y, SND_PONG); break; + case EL_ENVELOPE: + Feld[x][y] = EL_LEERRAUM; + PlaySoundLevel(x, y, SND_PONG); + break; + + case EL_EXTRA_TIME: + RemoveField(x, y); + if (level.time > 0) + { + TimeLeft += 10; + DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); + } + PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT); + break; + + case EL_FORCE_FIELD_PASSIVE: + RemoveField(x, y); + player->force_field_passive_time_left += 10; + PlaySoundLevel(x, y, SND_PONG); + break; + + case EL_FORCE_FIELD_ACTIVE: + RemoveField(x, y); + player->force_field_passive_time_left += 10; + player->force_field_active_time_left += 10; + PlaySoundLevel(x, y, SND_PONG); + break; + case EL_DYNAMITE_INACTIVE: case EL_SP_DISK_RED: RemoveField(x, y); @@ -4526,70 +5097,44 @@ int DigField(struct PlayerInfo *player, } break; - case EL_BELT1_SWITCH_L: - case EL_BELT1_SWITCH_M: - case EL_BELT1_SWITCH_R: - case EL_BELT2_SWITCH_L: - case EL_BELT2_SWITCH_M: - case EL_BELT2_SWITCH_R: - case EL_BELT3_SWITCH_L: - case EL_BELT3_SWITCH_M: - case EL_BELT3_SWITCH_R: - case EL_BELT4_SWITCH_L: - case EL_BELT4_SWITCH_M: - case EL_BELT4_SWITCH_R: + case EL_BELT1_SWITCH_LEFT: + case EL_BELT1_SWITCH_MIDDLE: + case EL_BELT1_SWITCH_RIGHT: + case EL_BELT2_SWITCH_LEFT: + case EL_BELT2_SWITCH_MIDDLE: + case EL_BELT2_SWITCH_RIGHT: + case EL_BELT3_SWITCH_LEFT: + case EL_BELT3_SWITCH_MIDDLE: + case EL_BELT3_SWITCH_RIGHT: + case EL_BELT4_SWITCH_LEFT: + case EL_BELT4_SWITCH_MIDDLE: + case EL_BELT4_SWITCH_RIGHT: + if (!player->Switching) { - static int belt_base_element[4] = - { - EL_BELT1_SWITCH_L, - EL_BELT2_SWITCH_L, - EL_BELT3_SWITCH_L, - EL_BELT4_SWITCH_L - }; - static int belt_move_dir[3] = - { - MV_LEFT, - MV_NO_MOVING, - MV_RIGHT - }; - - int belt_nr = (element < EL_BELT2_SWITCH_L ? 0 : - element < EL_BELT3_SWITCH_L ? 1 : - element < EL_BELT4_SWITCH_L ? 2 : 3); - int belt_dir_nr = element - belt_base_element[belt_nr]; - int belt_dir_nr_next = (belt_dir_nr + 1) % 3; - int belt_dir_next = belt_move_dir[belt_dir_nr_next]; - int xx, yy; - - if (player->Switching) - return MF_ACTION; - - game.belt_dir[belt_nr] = belt_dir_next; - - for (yy=0; yySwitching = TRUE; + ToggleBeltSwitch(x, y); + } + return MF_ACTION; + break; + case EL_SWITCHGATE_SWITCH_1: + case EL_SWITCHGATE_SWITCH_2: + if (!player->Switching) + { player->Switching = TRUE; + ToggleSwitchgateSwitch(x, y); + } + return MF_ACTION; + break; - return MF_ACTION; + case EL_LIGHT_SWITCH_OFF: + case EL_LIGHT_SWITCH_ON: + if (!player->Switching) + { + player->Switching = TRUE; + ToggleLightSwitch(x, y); } + return MF_ACTION; break; case EL_SP_EXIT: @@ -4692,6 +5237,18 @@ int DigField(struct PlayerInfo *player, break; + case EL_SWITCHGATE_OPEN: + if (!IN_LEV_FIELD(x + dx, y + dy) || !IS_FREE(x + dx, y + dy)) + return MF_NO_ACTION; + + /* automatically move to the next field with double speed */ + player->programmed_action = move_direction; + DOUBLE_PLAYER_SPEED(player); + + PlaySoundLevel(x, y, SND_GATE); + + break; + case EL_SP_PORT1_LEFT: case EL_SP_PORT2_LEFT: case EL_SP_PORT1_RIGHT: @@ -4843,7 +5400,6 @@ int DigField(struct PlayerInfo *player, break; - case EL_MAULWURF: case EL_PINGUIN: case EL_SCHWEIN: case EL_DRACHE: