X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=b88998efb9b0f61b1f09e178c53fb5e80483d40f;hb=613ba6c5cd3a99bfcfc25c95083b4f00b2dec584;hp=c5520d4ae89a754d8a5c638726acb0a7f1801afd;hpb=cd56ad175c592ea3047703d57c11d2f3a61f7f37;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index c5520d4a..b88998ef 100644 --- a/src/game.c +++ b/src/game.c @@ -23,7 +23,87 @@ #include "joystick.h" #include "network.h" +/* for DigField() */ +#define DF_NO_PUSH 0 +#define DF_DIG 1 +#define DF_SNAP 2 + +/* for MoveFigure() */ +#define MF_NO_ACTION 0 +#define MF_MOVING 1 +#define MF_ACTION 2 + +/* for ScrollFigure() */ +#define SCROLL_INIT 0 +#define SCROLL_GO_ON 1 + +/* for Explode() */ +#define EX_PHASE_START 0 +#define EX_NORMAL 0 +#define EX_CENTER 1 +#define EX_BORDER 2 + +/* special positions in the game control window (relative to control window) */ +#define XX_LEVEL 37 +#define YY_LEVEL 20 +#define XX_EMERALDS 29 +#define YY_EMERALDS 54 +#define XX_DYNAMITE 29 +#define YY_DYNAMITE 89 +#define XX_KEYS 18 +#define YY_KEYS 123 +#define XX_SCORE 15 +#define YY_SCORE 159 +#define XX_TIME 29 +#define YY_TIME 194 + +/* special positions in the game control window (relative to main window) */ +#define DX_LEVEL (DX + XX_LEVEL) +#define DY_LEVEL (DY + YY_LEVEL) +#define DX_EMERALDS (DX + XX_EMERALDS) +#define DY_EMERALDS (DY + YY_EMERALDS) +#define DX_DYNAMITE (DX + XX_DYNAMITE) +#define DY_DYNAMITE (DY + YY_DYNAMITE) +#define DX_KEYS (DX + XX_KEYS) +#define DY_KEYS (DY + YY_KEYS) +#define DX_SCORE (DX + XX_SCORE) +#define DY_SCORE (DY + YY_SCORE) +#define DX_TIME (DX + XX_TIME) +#define DY_TIME (DY + YY_TIME) + +#define IS_LOOP_SOUND(s) ((s)==SND_KLAPPER || (s)==SND_ROEHR || \ + (s)==SND_NJAM || (s)==SND_MIEP) +#define IS_MUSIC_SOUND(s) ((s)==SND_ALCHEMY || (s)==SND_CHASE || \ + (s)==SND_NETWORK || (s)==SND_CZARDASZ || \ + (s)==SND_TYGER || (s)==SND_VOYAGER || \ + (s)==SND_TWILIGHT) + +/* score for elements */ +#define SC_EDELSTEIN 0 +#define SC_DIAMANT 1 +#define SC_KAEFER 2 +#define SC_FLIEGER 3 +#define SC_MAMPFER 4 +#define SC_ROBOT 5 +#define SC_PACMAN 6 +#define SC_KOKOSNUSS 7 +#define SC_DYNAMIT 8 +#define SC_SCHLUESSEL 9 +#define SC_ZEITBONUS 10 + +/* values for game_emulation */ +#define EMU_NONE 0 +#define EMU_BOULDERDASH 1 +#define EMU_SOKOBAN 2 + +/* to control special behaviour of certain game elements */ +int game_emulation = EMU_NONE; + + + + #ifdef DEBUG +#if 0 static unsigned int getStateCheckSum(int counter) { int x, y; @@ -70,6 +150,10 @@ static unsigned int getStateCheckSum(int counter) return checksum; } #endif +#endif + + + void GetPlayerConfig() { @@ -87,6 +171,145 @@ 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; @@ -156,9 +379,11 @@ void InitGame() network_player_action_received = FALSE; +#ifndef MSDOS /* initial null action */ if (network_playing) SendToServer_MovePlayer(MV_NO_MOVING); +#endif ZX = ZY = -1; @@ -171,7 +396,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]; - - 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; - } + InitField(x, y, TRUE); } /* check if any connected player was not found in playfield */ @@ -342,20 +467,38 @@ void InitGame() } } - /* when in single player mode, eliminate all but the first active player */ - if (!options.network && !setup.team_mode) + if (tape.playing) + { + /* when playing a tape, eliminate all players who do not participate */ + + for (i=0; ijx, jy = player->jy; + + player->active = FALSE; + StorePlayer[jx][jy] = 0; + Feld[jx][jy] = EL_LEERRAUM; + } + } + } + else if (!options.network && !setup.team_mode) /* && !tape.playing */ { + /* when in single player mode, eliminate all but the first active player */ + for (i=0; ijx, jy = player->jy; - - if (player->active) + if (stored_player[j].active) { + struct PlayerInfo *player = &stored_player[j]; + int jx = player->jx, jy = player->jy; + player->active = FALSE; StorePlayer[jx][jy] = 0; Feld[jx][jy] = EL_LEERRAUM; @@ -365,19 +508,29 @@ void InitGame() } } - for (i=0; ipresent, - player->connected, - player->active); - if (local_player == player) - printf("Player %d is local player.\n", i+1); + for (i=0; ipresent, + player->connected, + player->active); + if (local_player == player) + printf("Player %d is local player.\n", i+1); + } + } game_emulation = (emulate_bd ? EMU_BOULDERDASH : emulate_sb ? EMU_SOKOBAN : EMU_NONE); @@ -436,11 +589,12 @@ void InitGame() XAutoRepeatOff(display); - - for (i=0; i<4; i++) - printf("Spieler %d %saktiv.\n", - i+1, (stored_player[i].active ? "" : "nicht ")); - + if (options.verbose) + { + for (i=0; i<4; i++) + printf("Spieler %d %saktiv.\n", + i+1, (stored_player[i].active ? "" : "nicht ")); + } } void InitMovDir(int x, int y) @@ -501,7 +655,9 @@ void InitMovDir(int x, int y) if (element != EL_KAEFER && element != EL_FLIEGER && element != EL_BUTTERFLY && - element != EL_FIREFLY) + element != EL_FIREFLY && + element != EL_SP_SNIKSNAK && + element != EL_SP_ELECTRON) break; for (i=0; i<4; i++) @@ -516,7 +672,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; @@ -625,8 +782,8 @@ boolean NewHiScore() LoadScore(level_nr); - if (!strcmp(setup.player_name, EMPTY_ALIAS) || - local_player->score < highscore[MAX_SCORE_ENTRIES-1].Score) + if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 || + local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score) return -1; for (k=0; k0) + if (Feld[x][y] == element && AmoebaNr[x][y] > 0) group_nr = AmoebaNr[x][y]; } @@ -2208,13 +2388,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; @@ -2226,14 +2406,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 || newayeffective_action = summarized_player_action; @@ -3227,29 +3490,35 @@ void GameActions() if (SiebAktiv) { - if (!(SiebAktiv%4)) + if (!(SiebCount % 4)) PlaySoundLevel(sieb_x, sieb_y, SND_MIEP); - SiebAktiv--; - if (!SiebAktiv) + + if (SiebCount > 0) { - for (y=0; y0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing) + if (TimeLeft > 0 && TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing) { TimeFrames = 0; TimeLeft--; @@ -3391,7 +3660,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); @@ -3412,13 +3681,18 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) if (player->MovPos) { - /* should only happen if pre-1.0 tape recordings are played */ + /* 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.0 LEVEL TAPES.\n"); + 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); @@ -3427,6 +3701,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)) @@ -3561,7 +3837,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) @@ -3586,7 +3862,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) { @@ -3601,7 +3877,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; } @@ -3850,6 +4126,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) @@ -3861,7 +4138,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); @@ -3921,10 +4206,35 @@ 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; @@ -3975,6 +4285,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 */ @@ -4020,6 +4366,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; @@ -4097,7 +4444,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; }