X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=3471f671a8e145e01f08d994ff138154a085540c;hb=e6856beb007b3f09036a04290c6b162953ddfece;hp=8b5d2a79f7a5cc4bc6e2f5305540b9c45ad61c51;hpb=0a87fde47bcff35f196024766f8d0d00319a28d1;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 8b5d2a79..3471f671 100644 --- a/src/game.c +++ b/src/game.c @@ -95,12 +95,14 @@ #define EMU_NONE 0 #define EMU_BOULDERDASH 1 #define EMU_SOKOBAN 2 +#define EMU_SUPAPLEX 3 /* to control special behaviour of certain game elements */ int game_emulation = EMU_NONE; + #ifdef DEBUG #if 0 static unsigned int getStateCheckSum(int counter) @@ -153,6 +155,7 @@ static unsigned int getStateCheckSum(int counter) + void GetPlayerConfig() { if (sound_status == SOUND_OFF) @@ -169,11 +172,151 @@ void GetPlayerConfig() InitJoysticks(); } +static void InitField(int x, int y, boolean init_game) +{ + switch (Feld[x][y]) + { + case EL_SPIELFIGUR: + case EL_SP_MURPHY: + if (init_game) + Feld[x][y] = EL_SPIELER1; + /* no break! */ + case EL_SPIELER1: + case EL_SPIELER2: + case EL_SPIELER3: + case EL_SPIELER4: + if (init_game) + { + struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1]; + int jx = player->jx, jy = player->jy; + + player->present = TRUE; + + /* + if (!network_playing || player->connected) + */ + + if (!options.network || player->connected) + { + player->active = TRUE; + + /* remove potentially duplicate players */ + if (StorePlayer[jx][jy] == Feld[x][y]) + StorePlayer[jx][jy] = 0; + + StorePlayer[x][y] = Feld[x][y]; + + if (options.verbose) + { + printf("Player %d activated.\n", player->element_nr); + printf("[Local player is %d and currently %s.]\n", + local_player->element_nr, + local_player->active ? "active" : "not active"); + } + } + + Feld[x][y] = EL_LEERRAUM; + player->jx = player->last_jx = x; + player->jy = player->last_jy = y; + } + break; + + case EL_BADEWANNE: + if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE) + Feld[x][y] = EL_BADEWANNE1; + else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE) + Feld[x][y] = EL_BADEWANNE2; + else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1) + Feld[x][y] = EL_BADEWANNE3; + else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE) + Feld[x][y] = EL_BADEWANNE4; + else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2) + 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: + case EL_FLIEGER_R: + case EL_FLIEGER_O: + case EL_FLIEGER_L: + case EL_FLIEGER_U: + case EL_FLIEGER: + case EL_BUTTERFLY_R: + case EL_BUTTERFLY_O: + case EL_BUTTERFLY_L: + case EL_BUTTERFLY_U: + case EL_BUTTERFLY: + case EL_FIREFLY_R: + case EL_FIREFLY_O: + case EL_FIREFLY_L: + case EL_FIREFLY_U: + case EL_FIREFLY: + case EL_PACMAN_R: + case EL_PACMAN_O: + case EL_PACMAN_L: + case EL_PACMAN_U: + case EL_MAMPFER: + case EL_MAMPFER2: + case EL_ROBOT: + case EL_PACMAN: + case EL_SP_SNIKSNAK: + case EL_SP_ELECTRON: + InitMovDir(x, y); + break; + + case EL_AMOEBE_VOLL: + case EL_AMOEBE_BD: + InitAmoebaNr(x, y); + break; + + case EL_TROPFEN: + if (y == lev_fieldy - 1) + { + Feld[x][y] = EL_AMOEBING; + Store[x][y] = EL_AMOEBE_NASS; + } + break; + + case EL_DYNAMIT: + MovDelay[x][y] = 96; + break; + + case EL_BIRNE_AUS: + local_player->lights_still_needed++; + break; + + case EL_SOKOBAN_FELD_LEER: + local_player->sokobanfields_still_needed++; + break; + + case EL_MAULWURF: + case EL_PINGUIN: + local_player->friends_still_needed++; + break; + + case EL_SCHWEIN: + case EL_DRACHE: + MovDir[x][y] = 1 << RND(4); + break; + + case EL_SP_EMPTY: + Feld[x][y] = EL_LEERRAUM; + break; + + default: + break; + } +} + void InitGame() { int i, j, x, y; boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */ boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */ + boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */ /* don't play tapes over network */ network_playing = (options.network && !tape.playing); @@ -255,7 +398,20 @@ void InitGame() ScreenMovPos = 0; ScreenGfxPos = 0; - AllPlayersGone = SiebAktiv = FALSE; + if (level.high_speed) + { + MoveSpeed = 4; + ScrollStepSize = TILEX/4; + } + else + { + MoveSpeed = 8; + ScrollStepSize = TILEX/8; + } + + AllPlayersGone = FALSE; + SiebAktiv = FALSE; + SiebCount = 0; for (i=0; ijx, jy = player->jy; - - player->present = TRUE; - - /* - if (!network_playing || player->connected) - */ - - if (!options.network || player->connected) - { - player->active = TRUE; - - /* remove potentially duplicate players */ - if (StorePlayer[jx][jy] == Feld[x][y]) - StorePlayer[jx][jy] = 0; - - StorePlayer[x][y] = Feld[x][y]; - - if (options.verbose) - { - printf("Player %d activated.\n", player->element_nr); - printf("[Local player is %d and currently %s.]\n", - local_player->element_nr, - local_player->active ? "active" : "not active"); - } - } - - Feld[x][y] = EL_LEERRAUM; - player->jx = player->last_jx = x; - player->jy = player->last_jy = y; - - break; - } - case EL_BADEWANNE: - if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE) - Feld[x][y] = EL_BADEWANNE1; - else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE) - Feld[x][y] = EL_BADEWANNE2; - else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1) - Feld[x][y] = EL_BADEWANNE3; - else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE) - Feld[x][y] = EL_BADEWANNE4; - else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2) - 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: - case EL_FLIEGER_R: - case EL_FLIEGER_O: - case EL_FLIEGER_L: - case EL_FLIEGER_U: - case EL_FLIEGER: - case EL_BUTTERFLY_R: - case EL_BUTTERFLY_O: - case EL_BUTTERFLY_L: - case EL_BUTTERFLY_U: - case EL_BUTTERFLY: - case EL_FIREFLY_R: - case EL_FIREFLY_O: - case EL_FIREFLY_L: - case EL_FIREFLY_U: - case EL_FIREFLY: - case EL_PACMAN_R: - case EL_PACMAN_O: - case EL_PACMAN_L: - case EL_PACMAN_U: - case EL_MAMPFER: - case EL_MAMPFER2: - case EL_ROBOT: - case EL_PACMAN: - InitMovDir(x, y); - break; - case EL_AMOEBE_VOLL: - case EL_AMOEBE_BD: - InitAmoebaNr(x, y); - break; - case EL_TROPFEN: - if (y == lev_fieldy - 1) - { - Feld[x][y] = EL_AMOEBING; - Store[x][y] = EL_AMOEBE_NASS; - } - break; - case EL_DYNAMIT: - MovDelay[x][y] = 96; - break; - case EL_BIRNE_AUS: - local_player->lights_still_needed++; - break; - case EL_SOKOBAN_FELD_LEER: - local_player->sokobanfields_still_needed++; - break; - case EL_MAULWURF: - case EL_PINGUIN: - local_player->friends_still_needed++; - break; - case EL_SCHWEIN: - case EL_DRACHE: - MovDir[x][y] = 1 << RND(4); - break; - default: - break; + if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y])) + emulate_bd = FALSE; + if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y])) + emulate_sb = FALSE; + if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y])) + emulate_sp = FALSE; + + InitField(x, y, TRUE); } } @@ -495,7 +540,8 @@ void InitGame() } game_emulation = (emulate_bd ? EMU_BOULDERDASH : - emulate_sb ? EMU_SOKOBAN : EMU_NONE); + emulate_sb ? EMU_SOKOBAN : + emulate_sp ? EMU_SUPAPLEX : EMU_NONE); scroll_x = scroll_y = -1; if (local_player->jx >= MIDPOSX-1) @@ -584,6 +630,7 @@ void InitMovDir(int x, int y) Feld[x][y] = EL_KAEFER; MovDir[x][y] = direction[0][element - EL_KAEFER_R]; break; + case EL_FLIEGER_R: case EL_FLIEGER_O: case EL_FLIEGER_L: @@ -591,6 +638,7 @@ void InitMovDir(int x, int y) Feld[x][y] = EL_FLIEGER; MovDir[x][y] = direction[0][element - EL_FLIEGER_R]; break; + case EL_BUTTERFLY_R: case EL_BUTTERFLY_O: case EL_BUTTERFLY_L: @@ -598,6 +646,7 @@ void InitMovDir(int x, int y) Feld[x][y] = EL_BUTTERFLY; MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R]; break; + case EL_FIREFLY_R: case EL_FIREFLY_O: case EL_FIREFLY_L: @@ -605,6 +654,7 @@ void InitMovDir(int x, int y) Feld[x][y] = EL_FIREFLY; MovDir[x][y] = direction[0][element - EL_FIREFLY_R]; break; + case EL_PACMAN_R: case EL_PACMAN_O: case EL_PACMAN_L: @@ -612,6 +662,15 @@ void InitMovDir(int x, int y) Feld[x][y] = EL_PACMAN; MovDir[x][y] = direction[0][element - EL_PACMAN_R]; break; + + case EL_SP_SNIKSNAK: + MovDir[x][y] = MV_UP; + break; + + case EL_SP_ELECTRON: + MovDir[x][y] = MV_LEFT; + break; + default: MovDir[x][y] = 1 << RND(4); if (element != EL_KAEFER && @@ -632,7 +691,8 @@ void InitMovDir(int x, int y) MovDir[x][y] = direction[0][i]; break; } - else if (element == EL_FLIEGER || element == EL_FIREFLY) + else if (element == EL_FLIEGER || element == EL_FIREFLY || + element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON) { MovDir[x][y] = direction[1][i]; break; @@ -1002,6 +1062,9 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = EL_EDELSTEIN_GELB; break; } + + if (game_emulation == EMU_SUPAPLEX) + Store[x][y] = EL_LEERRAUM; } else if (center_element == EL_MAULWURF) Store[x][y] = EL_EDELSTEIN_ROT; @@ -1011,6 +1074,8 @@ void Explode(int ex, int ey, int phase, int mode) Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN); else if (center_element == EL_BUTTERFLY) Store[x][y] = EL_EDELSTEIN_BD; + else if (center_element == EL_SP_ELECTRON) + Store[x][y] = EL_SP_INFOTRON; else if (center_element == EL_MAMPFER) Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1]; else if (center_element == EL_AMOEBA2DIAM) @@ -1051,7 +1116,7 @@ void Explode(int ex, int ey, int phase, int mode) } if (center_element == EL_MAMPFER) - MampferNr = (MampferNr+1) % 4; + MampferNr = (MampferNr + 1) % MampferMax; return; } @@ -1087,16 +1152,24 @@ void Explode(int ex, int ey, int phase, int mode) element = Feld[x][y] = Store[x][y]; Store[x][y] = Store2[x][y] = 0; MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0; + InitField(x, y, FALSE); if (CAN_MOVE(element) || COULD_MOVE(element)) InitMovDir(x, y); DrawLevelField(x, y); } - else if (!(phase%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { + int graphic = GFX_EXPLOSION; + + if (game_emulation == EMU_SUPAPLEX) + graphic = (Store[x][y] == EL_SP_INFOTRON ? + GFX_SP_EXPLODE_INFOTRON : + GFX_SP_EXPLODE_EMPTY); + if (phase == delay) ErdreichAnbroeckeln(SCREENX(x), SCREENY(y)); - DrawGraphic(SCREENX(x), SCREENY(y), GFX_EXPLOSION+(phase/delay-1)); + DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1)); } } @@ -1248,7 +1321,8 @@ void Impact(int x, int y) return; } - if (element == EL_BOMBE && (lastline || object_hit)) /* element is bomb */ + if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) && + (lastline || object_hit)) /* element is bomb */ { Bang(x, y); return; @@ -1271,8 +1345,22 @@ void Impact(int x, int y) if (!lastline && object_hit) /* check which object was hit */ { if (CAN_CHANGE(element) && - (smashed == EL_SIEB_LEER || smashed == EL_SIEB2_LEER) && !SiebAktiv) - SiebAktiv = level.dauer_sieb * FRAMES_PER_SECOND; + (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV)) + { + int x, y; + int activated_magic_wall = + (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER); + + /* activate magic wall / mill */ + + for (y=0; y0) + if (Feld[x][y] == element && AmoebaNr[x][y] > 0) group_nr = AmoebaNr[x][y]; } @@ -2324,13 +2423,13 @@ void AmoebenVereinigen(int ax, int ay) { 0, +1 } }; - if (!new_group_nr) + if (new_group_nr == 0) return; for (i=0; i<4; i++) { - x = ax+xy[i%4][0]; - y = ay+xy[i%4][1]; + x = ax + xy[i][0]; + y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; @@ -2342,14 +2441,22 @@ void AmoebenVereinigen(int ax, int ay) { int old_group_nr = AmoebaNr[x][y]; + if (old_group_nr == 0) + return; + AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr]; AmoebaCnt[old_group_nr] = 0; AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr]; AmoebaCnt2[old_group_nr] = 0; - for (yy=0; yy= 200 && element == EL_AMOEBE_BD) + if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200) { - AmoebeUmwandeln2(newax, neway, EL_FELSBROCKEN); + AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN); return; } } } - if (element!=EL_AMOEBE_NASS || neway 0) { - for (y=0; y0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing) + if (TimeLeft > 0 && TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing) { TimeFrames = 0; TimeLeft--; @@ -3547,7 +3699,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, jy = player->jy = new_jy; StorePlayer[jx][jy] = player->element_nr; - player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8; + player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / MoveSpeed); ScrollFigure(player, SCROLL_INIT); @@ -3571,10 +3723,15 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) /* should only happen if pre-1.2 tape recordings are played */ /* this is only for backward compatibility */ + int old_move_speed = MoveSpeed; + #if DEBUG printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n"); #endif + /* scroll remaining steps with finest movement resolution */ + MoveSpeed = 8; + while (player->MovPos) { ScrollFigure(player, SCROLL_GO_ON); @@ -3583,6 +3740,8 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) DrawAllPlayers(); BackToFront(); } + + MoveSpeed = old_move_speed; } if (player->last_move_dir & (MV_LEFT | MV_RIGHT)) @@ -3717,7 +3876,7 @@ void ScrollFigure(struct PlayerInfo *player, int mode) else if (!FrameReached(&player->actual_frame_counter, 1)) return; - player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX/8; + player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX / MoveSpeed; player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize); if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING) @@ -3742,7 +3901,7 @@ void ScrollFigure(struct PlayerInfo *player, int mode) void ScrollScreen(struct PlayerInfo *player, int mode) { - static long screen_frame_counter = 0; + static unsigned long screen_frame_counter = 0; if (mode == SCROLL_INIT) { @@ -3757,7 +3916,7 @@ void ScrollScreen(struct PlayerInfo *player, int mode) if (ScreenMovPos) { - ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8; + ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX / MoveSpeed; ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); redraw_mask |= REDRAW_FIELD; } @@ -4006,6 +4165,7 @@ int DigField(struct PlayerInfo *player, case EL_EDELSTEIN_ROT: case EL_EDELSTEIN_LILA: case EL_DIAMANT: + case EL_SP_INFOTRON: RemoveField(x, y); local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1); if (local_player->gems_still_needed < 0) @@ -4017,7 +4177,15 @@ int DigField(struct PlayerInfo *player, PlaySoundLevel(x, y, SND_PONG); break; + case EL_SPEED_PILL: + RemoveField(x, y); + MoveSpeed = 4; + ScrollStepSize = TILEX/4; + PlaySoundLevel(x, y, SND_PONG); + break; + case EL_DYNAMIT_AUS: + case EL_SP_DISK_RED: RemoveField(x, y); player->dynamite++; RaiseScoreElement(EL_DYNAMIT); @@ -4077,10 +4245,39 @@ int DigField(struct PlayerInfo *player, return MF_ACTION; break; + case EL_SP_TERMINAL: + { + int xx, yy; + + for (yy=0; yygems_still_needed > 0) + return MF_NO_ACTION; + + player->LevelSolved = player->GameOver = TRUE; + PlaySoundLevel(x, y, SND_BUING); + break; + case EL_FELSBROCKEN: case EL_BOMBE: case EL_KOKOSNUSS: case EL_ZEIT_LEER: + case EL_SP_ZONK: + case EL_SP_DISK_ORANGE: if (dy || mode == DF_SNAP) return MF_NO_ACTION; @@ -4131,6 +4328,42 @@ int DigField(struct PlayerInfo *player, return MF_NO_ACTION; break; + case EL_SP_PORT1_LEFT: + case EL_SP_PORT2_LEFT: + case EL_SP_PORT1_RIGHT: + case EL_SP_PORT2_RIGHT: + case EL_SP_PORT1_UP: + case EL_SP_PORT2_UP: + case EL_SP_PORT1_DOWN: + case EL_SP_PORT2_DOWN: + case EL_SP_PORT_X: + case EL_SP_PORT_Y: + case EL_SP_PORT_XY: + if ((dx == -1 && + element != EL_SP_PORT1_LEFT && + element != EL_SP_PORT2_LEFT && + element != EL_SP_PORT_X && + element != EL_SP_PORT_XY) || + (dx == +1 && + element != EL_SP_PORT1_RIGHT && + element != EL_SP_PORT2_RIGHT && + element != EL_SP_PORT_X && + element != EL_SP_PORT_XY) || + (dy == -1 && + element != EL_SP_PORT1_UP && + element != EL_SP_PORT2_UP && + element != EL_SP_PORT_Y && + element != EL_SP_PORT_XY) || + (dy == +1 && + element != EL_SP_PORT1_DOWN && + element != EL_SP_PORT2_DOWN && + element != EL_SP_PORT_Y && + element != EL_SP_PORT_XY) || + !IN_LEV_FIELD(x + dx, y + dy) || + !IS_FREE(x + dx, y + dy)) + return MF_NO_ACTION; + break; + case EL_AUSGANG_ZU: case EL_AUSGANG_ACT: /* door is not (yet) open */ @@ -4176,6 +4409,7 @@ int DigField(struct PlayerInfo *player, case EL_SOKOBAN_FELD_VOLL: case EL_SOKOBAN_OBJEKT: case EL_SONDE: + case EL_SP_DISK_YELLOW: if (mode == DF_SNAP) return MF_NO_ACTION; @@ -4253,7 +4487,11 @@ int DigField(struct PlayerInfo *player, break; default: - return MF_NO_ACTION; + if (IS_EATABLE(element)) /* other kinds of 'dirt' */ + Feld[x][y] = EL_LEERRAUM; + else + return MF_NO_ACTION; + break; }