X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=fcaedf73e391e6c0882991de5811ecfc1e1968c7;hb=78ec772d11cb8823d8dca05c227b472da8708a07;hp=a48ad78bad3944432795406b1fae03677445dbe4;hpb=3dc317d10b44cc6b75db10ac194966ad8114d390;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index a48ad78b..fcaedf73 100644 --- a/src/game.c +++ b/src/game.c @@ -23,13 +23,100 @@ #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) + +/* values for player movement speed (which is in fact a delay value) */ +#define MOVE_DELAY_NORMAL_SPEED 8 +#define MOVE_DELAY_HIGH_SPEED 4 + +#define DOUBLE_MOVE_DELAY(x) (x = (x <= MOVE_DELAY_HIGH_SPEED ? x * 2 : x)) +#define HALVE_MOVE_DELAY(x) (x = (x >= MOVE_DELAY_HIGH_SPEED ? x / 2 : x)) +#define DOUBLE_PLAYER_SPEED(p) (HALVE_MOVE_DELAY((p)->move_delay_value)) +#define HALVE_PLAYER_SPEED(p) (DOUBLE_MOVE_DELAY((p)->move_delay_value)) + +/* game button identifiers */ +#define GAME_CTRL_ID_STOP 0 +#define GAME_CTRL_ID_PAUSE 1 +#define GAME_CTRL_ID_PLAY 2 +#define SOUND_CTRL_ID_MUSIC 3 +#define SOUND_CTRL_ID_LOOPS 4 +#define SOUND_CTRL_ID_SIMPLE 5 + +#define NUM_GAME_BUTTONS 6 + +/* forward declaration for internal use */ +static void CheckGravityMovement(struct PlayerInfo *); + +static void MapGameButtons(); +static void HandleGameButtons(struct GadgetInfo *); + +static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; + + + #ifdef DEBUG +#if 0 static unsigned int getStateCheckSum(int counter) { int x, y; unsigned int mult = 1; unsigned int checksum = 0; + /* static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY]; + */ static boolean first_game = TRUE; for (y=0; yjx, jy = player->jy; + + player->present = TRUE; + + 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; + + case EL_EM_KEY_1_FILE: + Feld[x][y] = EL_EM_KEY_1; + break; + case EL_EM_KEY_2_FILE: + Feld[x][y] = EL_EM_KEY_2; + break; + case EL_EM_KEY_3_FILE: + Feld[x][y] = EL_EM_KEY_3; + break; + case EL_EM_KEY_4_FILE: + Feld[x][y] = EL_EM_KEY_4; + 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); @@ -106,9 +346,10 @@ void InitGame() player->action = 0; player->effective_action = 0; + player->programmed_action = 0; player->score = 0; - player->gems_still_needed = level.edelsteine; + player->gems_still_needed = level.gems_needed; player->sokobanfields_still_needed = 0; player->lights_still_needed = 0; player->friends_still_needed = 0; @@ -138,9 +379,10 @@ void InitGame() player->move_delay = 0; player->last_move_dir = MV_NO_MOVING; - player->snapped = FALSE; + player->move_delay_value = + (level.double_speed ? MOVE_DELAY_HIGH_SPEED : MOVE_DELAY_NORMAL_SPEED); - player->gone = FALSE; + player->snapped = FALSE; player->last_jx = player->last_jy = 0; player->jx = player->jy = 0; @@ -154,22 +396,29 @@ void InitGame() network_player_action_received = FALSE; +#ifndef MSDOS /* initial null action */ if (network_playing) SendToServer_MovePlayer(MV_NO_MOVING); +#endif ZX = ZY = -1; - MampferNr = 0; + game.yam_content_nr = 0; FrameCounter = 0; TimeFrames = 0; + TimePlayed = 0; TimeLeft = level.time; ScreenMovDir = MV_NO_MOVING; ScreenMovPos = 0; ScreenGfxPos = 0; - AllPlayersGone = SiebAktiv = FALSE; + ScrollStepSize = 0; /* will be correctly initialized by ScrollScreen() */ + + AllPlayersGone = FALSE; + game.magic_wall_active = FALSE; + game.magic_wall_time_left = 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; + 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); } } @@ -340,20 +481,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; @@ -363,32 +522,68 @@ void InitGame() } } - for (i=0; ipresent, + player->connected, + player->active); + if (local_player == player) + printf("Player %d is local player.\n", i+1); + } + } - printf("Player %d: present == %d, connected == %d, active == %d.\n", - i+1, - player->present, - 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 : + emulate_sp ? EMU_SUPAPLEX : EMU_NONE); + + /* determine border element for this level */ + SetBorderElement(); + + if (BorderElement == EL_LEERRAUM) + { + SBX_Left = 0; + SBX_Right = lev_fieldx - SCR_FIELDX; + SBY_Upper = 0; + SBY_Lower = lev_fieldy - SCR_FIELDY; + } + else + { + SBX_Left = -1; + SBX_Right = lev_fieldx - SCR_FIELDX + 1; + SBY_Upper = -1; + SBY_Lower = lev_fieldy - SCR_FIELDY + 1; } + if (lev_fieldx + (SBX_Left == -1 ? 2 : 0) <= SCR_FIELDX) + SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2; - game_emulation = (emulate_bd ? EMU_BOULDERDASH : - emulate_sb ? EMU_SOKOBAN : EMU_NONE); + if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY) + SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2; - scroll_x = scroll_y = -1; - if (local_player->jx >= MIDPOSX-1) - scroll_x = (local_player->jx <= lev_fieldx-MIDPOSX ? + scroll_x = SBX_Left; + scroll_y = SBY_Upper; + if (local_player->jx >= SBX_Left + MIDPOSX) + scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ? local_player->jx - MIDPOSX : - lev_fieldx - SCR_FIELDX + 1); - if (local_player->jy >= MIDPOSY-1) - scroll_y = (local_player->jy <= lev_fieldy-MIDPOSY ? + SBX_Right); + if (local_player->jy >= SBY_Upper + MIDPOSY) + scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ? local_player->jy - MIDPOSY : - lev_fieldy - SCR_FIELDY + 1); + SBY_Lower); CloseDoor(DOOR_CLOSE_1); @@ -396,49 +591,45 @@ void InitGame() DrawAllPlayers(); FadeToFront(); - XCopyArea(display, pix[PIX_DOOR], pix[PIX_DB_DOOR], gc, - DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, - DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); - DrawTextExt(pix[PIX_DB_DOOR], gc, - DOOR_GFX_PAGEX1 + XX_LEVEL, DOOR_GFX_PAGEY1 + YY_LEVEL, - int2str(level_nr, 2), FS_SMALL, FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR], gc, - DOOR_GFX_PAGEX1 + XX_EMERALDS, DOOR_GFX_PAGEY1 + YY_EMERALDS, - int2str(local_player->gems_still_needed,3), FS_SMALL, FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR], gc, - DOOR_GFX_PAGEX1 + XX_DYNAMITE, DOOR_GFX_PAGEY1 + YY_DYNAMITE, - int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR], gc, - DOOR_GFX_PAGEX1 + XX_SCORE, DOOR_GFX_PAGEY1 + YY_SCORE, - int2str(local_player->score, 5), FS_SMALL, FC_YELLOW); - DrawTextExt(pix[PIX_DB_DOOR], gc, - DOOR_GFX_PAGEX1 + XX_TIME, DOOR_GFX_PAGEY1 + YY_TIME, - int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); - - DrawGameButton(BUTTON_GAME_STOP); - DrawGameButton(BUTTON_GAME_PAUSE); - DrawGameButton(BUTTON_GAME_PLAY); - DrawSoundDisplay(BUTTON_SOUND_MUSIC | (setup.sound_music ? BUTTON_ON : 0)); - DrawSoundDisplay(BUTTON_SOUND_LOOPS | (setup.sound_loops ? BUTTON_ON : 0)); - DrawSoundDisplay(BUTTON_SOUND_SIMPLE | (setup.sound_simple ? BUTTON_ON : 0)); + /* copy default game door content to main double buffer */ + XCopyArea(display, pix[PIX_DOOR], drawto, gc, + DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); + + DrawText(DX + XX_LEVEL, DY + YY_LEVEL, + int2str(level_nr, 2), FS_SMALL, FC_YELLOW); + DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS, + int2str(local_player->gems_still_needed,3), FS_SMALL, FC_YELLOW); + DrawText(DX + XX_DYNAMITE, DY + YY_DYNAMITE, + int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW); + DrawText(DX + XX_SCORE, DY + YY_SCORE, + int2str(local_player->score, 5), FS_SMALL, FC_YELLOW); + DrawText(DX + XX_TIME, DY + YY_TIME, + int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); + + UnmapGameButtons(); + game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music; + game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops; + game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple; + MapGameButtons(); + MapTapeButtons(); + + /* copy actual game door content to door double buffer for OpenDoor() */ XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc, - DX + GAME_CONTROL_XPOS, DY + GAME_CONTROL_YPOS, - GAME_CONTROL_XSIZE, 2 * GAME_CONTROL_YSIZE, - DOOR_GFX_PAGEX1 + GAME_CONTROL_XPOS, - DOOR_GFX_PAGEY1 + GAME_CONTROL_YPOS); + DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); - OpenDoor(DOOR_OPEN_1); + OpenDoor(DOOR_OPEN_ALL); if (setup.sound_music) PlaySoundLoop(background_loop[level_nr % num_bg_loops]); 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("Player %d %sactive.\n", + i + 1, (stored_player[i].active ? "" : "not ")); + } } void InitMovDir(int x, int y) @@ -466,6 +657,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: @@ -473,6 +665,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: @@ -480,6 +673,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: @@ -487,6 +681,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: @@ -494,6 +689,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 && @@ -514,7 +718,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; @@ -566,7 +771,7 @@ void GameWon() { if (!setup.sound_loops) PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT); - if (TimeLeft && !(TimeLeft % 10)) + if (TimeLeft > 0 && !(TimeLeft % 10)) RaiseScore(level.score[SC_ZEITBONUS]); if (TimeLeft > 100 && !(TimeLeft % 10)) TimeLeft -= 10; @@ -580,6 +785,29 @@ void GameWon() if (setup.sound_loops) StopSound(SND_SIRR); } + else if (level.time == 0) /* level without time limit */ + { + if (setup.sound_loops) + PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP); + + while(TimePlayed < 999) + { + if (!setup.sound_loops) + PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT); + if (TimePlayed < 999 && !(TimePlayed % 10)) + RaiseScore(level.score[SC_ZEITBONUS]); + if (TimePlayed < 900 && !(TimePlayed % 10)) + TimePlayed += 10; + else + TimePlayed++; + DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW); + BackToFront(); + Delay(10); + } + + if (setup.sound_loops) + StopSound(SND_SIRR); + } FadeSounds(); @@ -616,22 +844,22 @@ void GameWon() BackToFront(); } -boolean NewHiScore() +int NewHiScore() { int k, l; int position = -1; 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; kscore > highscore[k].Score) { - /* Spieler kommt in Highscore-Liste */ + /* player has made it to the hall of fame */ if (k < MAX_SCORE_ENTRIES - 1) { @@ -641,7 +869,7 @@ boolean NewHiScore() for (l=k; ljx, jy = player->jy; - if (!player->active || player->gone) + if (!player->active) continue; if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y)) @@ -1639,8 +1947,7 @@ static boolean JustBeingPushed(int x, int y) { struct PlayerInfo *player = &stored_player[i]; - if (player->active && !player->gone && - player->Pushing && player->MovPos) + if (player->active && player->Pushing && player->MovPos) { int next_jx = player->jx + (player->jx - player->last_jx); int next_jy = player->jy + (player->jy - player->last_jy); @@ -1747,7 +2054,7 @@ void StartMoving(int x, int y) Store2[x][y] = 0; } } - else if (SiebAktiv && CAN_CHANGE(element) && + else if (CAN_CHANGE(element) && (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER)) { InitMovingField(x, y, MV_DOWN); @@ -1783,7 +2090,7 @@ void StartMoving(int x, int y) if (left || right) { - if (left && right && game_emulation != EMU_BOULDERDASH) + if (left && right && game.emulation != EMU_BOULDERDASH) left = !(right = RND(2)); InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT); @@ -1797,26 +2104,27 @@ void StartMoving(int x, int y) if (element == EL_SONDE && JustBeingPushed(x, y)) return; - if (!MovDelay[x][y]) /* neuer Schritt / noch nicht gewartet */ + if (!MovDelay[x][y]) /* start new movement phase */ { - /* Alle Figuren, die nach jeden Schritt die Richtung wechseln können. - * (MAMPFER, MAMPFER2 und PACMAN laufen bis zur nächsten Wand.) - */ + /* all objects that can change their move direction after each step */ + /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall */ if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN) { TurnRound(x, y); - if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER)) + if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER || + element == EL_SP_SNIKSNAK || + element == EL_SP_ELECTRON)) DrawLevelField(x, y); } } - if (MovDelay[x][y]) /* neuer Schritt / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next movement */ { MovDelay[x][y]--; - if (element == EL_ROBOT || element == EL_MAMPFER || - element == EL_MAMPFER2) + if (element == EL_ROBOT || + element == EL_MAMPFER || element == EL_MAMPFER2) { int phase = MovDelay[x][y] % 8; @@ -1830,6 +2138,8 @@ void StartMoving(int x, int y) && MovDelay[x][y]%4 == 3) PlaySoundLevel(x, y, SND_NJAM); } + else if (element == EL_SP_ELECTRON) + DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL); else if (element == EL_DRACHE) { int i; @@ -1886,13 +2196,13 @@ void StartMoving(int x, int y) PlaySoundLevel(x, y, SND_ROEHR); } - /* neuer Schritt / Wartezustand beendet */ + /* now make next step */ - Moving2Blocked(x, y, &newx, &newy); /* wohin soll's gehen? */ + Moving2Blocked(x, y, &newx, &newy); /* get next screen position */ if (IS_ENEMY(element) && IS_PLAYER(newx, newy)) { - /* Spieler erwischt */ + /* enemy got the player */ MovDir[x][y] = 0; KillHero(PLAYERINFO(newx, newy)); return; @@ -2046,15 +2356,20 @@ void StartMoving(int x, int y) DrawLevelField(newx, newy); } else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy)) - { /* gegen Wand gelaufen */ + { + /* object was running against a wall */ + TurnRound(x, y); - if (element == EL_KAEFER || element == EL_FLIEGER) + if (element == EL_KAEFER || element == EL_FLIEGER || + element == EL_SP_SNIKSNAK) DrawLevelField(x, y); else if (element == EL_BUTTERFLY || element == EL_FIREFLY) DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL); else if (element == EL_SONDE) DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL); + else if (element == EL_SP_ELECTRON) + DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL); return; } @@ -2079,7 +2394,7 @@ void ContinueMoving(int x, int y) int newx = x + dx, newy = y + dy; int step = (horiz_move ? dx : dy) * TILEX/8; - if (CAN_FALL(element) && horiz_move) + if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element)) step*=2; else if (element == EL_TROPFEN) step/=2; @@ -2088,7 +2403,7 @@ void ContinueMoving(int x, int y) MovPos[x][y] += step; - if (ABS(MovPos[x][y])>=TILEX) /* Zielfeld erreicht */ + if (ABS(MovPos[x][y])>=TILEX) /* object reached its destination */ { Feld[x][y] = EL_LEERRAUM; Feld[newx][newy] = element; @@ -2107,22 +2422,24 @@ void ContinueMoving(int x, int y) else if (Store[x][y] == EL_SIEB_VOLL) { Store[x][y] = 0; - element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT); + element = Feld[newx][newy] = + (game.magic_wall_active ? EL_SIEB_VOLL : EL_SIEB_TOT); } else if (Store[x][y] == EL_SIEB_LEER) { Store[x][y] = Store2[x][y] = 0; - Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT); + Feld[x][y] = (game.magic_wall_active ? EL_SIEB_LEER : EL_SIEB_TOT); } else if (Store[x][y] == EL_SIEB2_VOLL) { Store[x][y] = 0; - element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT); + element = Feld[newx][newy] = + (game.magic_wall_active ? EL_SIEB2_VOLL : EL_SIEB2_TOT); } else if (Store[x][y] == EL_SIEB2_LEER) { Store[x][y] = Store2[x][y] = 0; - Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT); + Feld[x][y] = (game.magic_wall_active ? EL_SIEB2_LEER : EL_SIEB2_TOT); } else if (Store[x][y] == EL_SALZSAEURE) { @@ -2148,7 +2465,7 @@ void ContinueMoving(int x, int y) Stop[newx][newy] = TRUE; JustHit[x][newy] = 3; - if (DONT_TOUCH(element)) /* Käfer oder Flieger */ + if (DONT_TOUCH(element)) /* object may be nasty to player or others */ { TestIfBadThingHitsHero(newx, newy); TestIfBadThingHitsFriend(newx, newy); @@ -2161,7 +2478,7 @@ void ContinueMoving(int x, int y) (newy == lev_fieldy-1 || !IS_FREE(x, newy+1))) Impact(x, newy); } - else /* noch in Bewegung */ + else /* still moving on */ DrawLevelField(x, y); } @@ -2180,13 +2497,13 @@ int AmoebeNachbarNr(int ax, int ay) for (i=0; i<4; i++) { - int x = ax+xy[i%4][0]; - int y = ay+xy[i%4][1]; + int x = ax + xy[i][0]; + int y = ay + xy[i][1]; if (!IN_LEV_FIELD(x, y)) continue; - if (Feld[x][y] == element && AmoebaNr[x][y]>0) + if (Feld[x][y] == element && AmoebaNr[x][y] > 0) group_nr = AmoebaNr[x][y]; } @@ -2205,13 +2522,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; @@ -2223,14 +2540,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 || newaylife[1]) { @@ -2513,7 +2878,7 @@ void Life(int ax, int ay) } } else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH) - { /* Randfeld ohne Amoebe */ + { /* free border field */ if (nachbarn>=life[2] && nachbarn<=life[3]) { Feld[xx][yy] = element; @@ -2528,10 +2893,10 @@ void Life(int ax, int ay) void Ablenk(int x, int y) { - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ - MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND; + if (!MovDelay[x][y]) /* next animation frame */ + MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (MovDelay[x][y]) @@ -2552,10 +2917,10 @@ void Ablenk(int x, int y) void Birne(int x, int y) { - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ + if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 800; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (MovDelay[x][y]) @@ -2589,10 +2954,10 @@ void Blubber(int x, int y) void NussKnacken(int x, int y) { - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ + if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 7; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) @@ -2608,10 +2973,9 @@ void NussKnacken(int x, int y) void SiebAktivieren(int x, int y, int typ) { - if (!(SiebAktiv % 4) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) - DrawGraphic(SCREENX(x), SCREENY(y), - (typ == 1 ? GFX_SIEB_VOLL : - GFX_SIEB2_VOLL) + 3 - (SiebAktiv % 16) / 4); + int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3; + + DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE); } void AusgangstuerPruefen(int x, int y) @@ -2634,10 +2998,10 @@ void AusgangstuerOeffnen(int x, int y) { int delay = 6; - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ + if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 5*delay; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { int tuer; @@ -2668,10 +3032,10 @@ void EdelsteinFunkeln(int x, int y) DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE); else { - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ + if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 11 * !SimpleRND(500); - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { MovDelay[x][y]--; @@ -2709,10 +3073,10 @@ void MauerWaechst(int x, int y) { int delay = 6; - if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */ + if (!MovDelay[x][y]) /* next animation frame */ MovDelay[x][y] = 3*delay; - if (MovDelay[x][y]) /* neue Phase / in Wartezustand */ + if (MovDelay[x][y]) /* wait some time before next frame */ { int phase; @@ -2764,10 +3128,10 @@ void MauerAbleger(int ax, int ay) boolean oben_massiv = FALSE, unten_massiv = FALSE; boolean links_massiv = FALSE, rechts_massiv = FALSE; - if (!MovDelay[ax][ay]) /* neue Mauer / noch nicht gewartet */ + if (!MovDelay[ax][ay]) /* start building new wall */ MovDelay[ax][ay] = 6; - if (MovDelay[ax][ay]) /* neue Mauer / in Wartezustand */ + if (MovDelay[ax][ay]) /* wait some time before building new wall */ { MovDelay[ax][ay]--; if (MovDelay[ax][ay]) @@ -2878,16 +3242,78 @@ void CheckForDragon(int x, int y) { for (j=0; j<3; j++) { - int xx = x + j*xy[i][0], yy = y + j*xy[i][1]; - - if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING) - { - Feld[xx][yy] = EL_LEERRAUM; - DrawLevelField(xx, yy); - } - else - break; + int xx = x + j*xy[i][0], yy = y + j*xy[i][1]; + + if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING) + { + Feld[xx][yy] = EL_LEERRAUM; + DrawLevelField(xx, yy); + } + else + break; + } + } + } +} + +static void CheckBuggyBase(int x, int y) +{ + int element = Feld[x][y]; + + if (element == EL_SP_BUG) + { + if (!MovDelay[x][y]) /* start activating buggy base */ + MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); + + if (MovDelay[x][y]) /* wait some time before activating base */ + { + MovDelay[x][y]--; + if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING); + if (MovDelay[x][y]) + return; + + Feld[x][y] = EL_SP_BUG_ACTIVE; + } + } + else if (element == EL_SP_BUG_ACTIVE) + { + if (!MovDelay[x][y]) /* start activating buggy base */ + MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND); + + if (MovDelay[x][y]) /* wait some time before activating base */ + { + MovDelay[x][y]--; + if (MovDelay[x][y]) + { + int i; + static int xy[4][2] = + { + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } + }; + + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4)); + + for (i=0; i<4; i++) + { + int xx = x + xy[i][0], yy = y + xy[i][1]; + + if (IS_PLAYER(xx, yy)) + { + PlaySoundLevel(x, y, SND_SP_BUG); + break; + } + } + + return; } + + Feld[x][y] = EL_SP_BUG; + DrawLevelField(x, y); } } } @@ -2911,7 +3337,7 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) stored_player_action[player->index_nr] = 0; num_stored_actions++; - if (!player->active || player->gone || tape.pausing) + if (!player->active || tape.pausing) return; if (player_action) @@ -2934,25 +3360,19 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) player_action &= JOY_BUTTON; stored_player_action[player->index_nr] = player_action; - -#if 0 - /* this allows cycled sequences of PlayerActions() */ - if (num_stored_actions >= MAX_PLAYERS) - { - TapeRecordAction(stored_player_action); - num_stored_actions = 0; - } -#endif - } else if (tape.playing && snapped) SnapField(player, 0, 0); /* stop snapping */ } else { + /* no actions for this player (no input at player's configured device) */ + DigField(player, 0, 0, 0, 0, DF_NO_PUSH); SnapField(player, 0, 0); - if (++player->frame_reset_delay > MoveSpeed) + CheckGravityMovement(player); + + if (++player->frame_reset_delay > player->move_delay_value) player->Frame = 0; } @@ -2992,8 +3412,8 @@ static void PlayerActions(struct PlayerInfo *player, byte player_action) void GameActions() { - static long action_delay = 0; - long action_delay_value; + static unsigned long action_delay = 0; + unsigned long action_delay_value; int sieb_x = 0, sieb_y = 0; int i, x, y, element; byte *recorded_player_action; @@ -3005,7 +3425,8 @@ void GameActions() action_delay_value = (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay); - /* main game synchronization point */ + /* ---------- main game synchronization point ---------- */ + WaitUntilDelayReached(&action_delay, action_delay_value); if (network_playing && !network_player_action_received) @@ -3016,8 +3437,10 @@ void GameActions() #endif */ +#ifndef MSDOS /* last chance to get network player actions without main loop delay */ HandleNetworking(); +#endif if (game_status != PLAYING) return; @@ -3033,14 +3456,6 @@ void GameActions() } } - - /* - if (tape.pausing || (tape.playing && !TapePlayDelay())) - return; - else if (tape.recording) - TapeRecordDelay(); - */ - if (tape.pausing) return; @@ -3059,8 +3474,10 @@ void GameActions() stored_player[i].effective_action = stored_player[i].action; } +#ifndef MSDOS if (network_playing) SendToServer_MovePlayer(summarized_player_action); +#endif if (!options.network && !setup.team_mode) local_player->effective_action = summarized_player_action; @@ -3069,6 +3486,9 @@ void GameActions() { int actual_player_action = stored_player[i].effective_action; + if (stored_player[i].programmed_action) + actual_player_action = stored_player[i].programmed_action; + if (recorded_player_action) actual_player_action = recorded_player_action[i]; @@ -3081,37 +3501,25 @@ void GameActions() ScrollScreen(NULL, SCROLL_GO_ON); - /* - if (tape.pausing || (tape.playing && !TapePlayDelay())) - return; - else if (tape.recording) - TapeRecordDelay(); - */ - - - - #ifdef DEBUG - if (TimeFrames == 0 && !local_player->gone) +#if 0 + if (TimeFrames == 0 && local_player->active) { extern unsigned int last_RND(); printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n", - level.time - TimeLeft, - last_RND(), - getStateCheckSum(level.time - TimeLeft)); + TimePlayed, last_RND(), getStateCheckSum(TimePlayed)); } #endif - - +#endif #ifdef DEBUG +#if 0 if (GameFrameDelay >= 500) printf("FrameCounter == %d\n", FrameCounter); #endif - - +#endif @@ -3132,7 +3540,7 @@ void GameActions() Blocked2Moving(x, y, &oldx, &oldy); if (!IS_MOVING(oldx, oldy)) { - printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n"); + printf("GameActions(): (BLOCKED => MOVING) context corrupted!\n"); printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y); printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy); printf("GameActions(): This should never happen!\n"); @@ -3190,8 +3598,14 @@ void GameActions() MauerAbleger(x, y); else if (element == EL_BURNING) CheckForDragon(x, y); - - if (SiebAktiv) + else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE) + CheckBuggyBase(x, y); + else if (element == EL_SP_TERMINAL) + DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL); + else if (element == EL_SP_TERMINAL_ACTIVE) + DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL); + + if (game.magic_wall_active) { boolean sieb = FALSE; int jx = local_player->jx, jy = local_player->jy; @@ -3218,46 +3632,59 @@ void GameActions() } } - if (SiebAktiv) + if (game.magic_wall_active) { - if (!(SiebAktiv%4)) + if (!(game.magic_wall_time_left % 4)) PlaySoundLevel(sieb_x, sieb_y, SND_MIEP); - SiebAktiv--; - if (!SiebAktiv) + + if (game.magic_wall_time_left > 0) { - for (y=0; y0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing) + if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing) { TimeFrames = 0; - TimeLeft--; + TimePlayed++; if (tape.recording || tape.playing) - DrawVideoDisplay(VIDEO_STATE_TIME_ON, level.time-TimeLeft); + DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed); - if (TimeLeft<=10) - PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT); + if (TimeLeft > 0) + { + TimeLeft--; - DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW); + if (TimeLeft <= 10) + PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT); - if (!TimeLeft) - for (i=0; iprogrammed_action) + { + int move_dir_vertical = player->action & (MV_UP | MV_DOWN); + int move_dir_horizontal = player->action & (MV_LEFT | MV_RIGHT); + int move_dir = + (player->last_move_dir & (MV_LEFT | MV_RIGHT) ? + (move_dir_vertical ? move_dir_vertical : move_dir_horizontal) : + (move_dir_horizontal ? move_dir_horizontal : move_dir_vertical)); + int jx = player->jx, jy = player->jy; + int dx = (move_dir & MV_LEFT ? -1 : move_dir & MV_RIGHT ? +1 : 0); + int dy = (move_dir & MV_UP ? -1 : move_dir & MV_DOWN ? +1 : 0); + int new_jx = jx + dx, new_jy = jy + dy; + boolean field_under_player_is_free = + (IN_LEV_FIELD(jx, jy + 1) && IS_FREE(jx, jy + 1)); + boolean player_is_moving_to_valid_field = + (IN_LEV_FIELD(new_jx, new_jy) && + (Feld[new_jx][new_jy] == EL_SP_BASE || + Feld[new_jx][new_jy] == EL_ERDREICH)); + + if (field_under_player_is_free && !player_is_moving_to_valid_field) + player->programmed_action = MV_DOWN; + } +} + boolean MoveFigureOneStep(struct PlayerInfo *player, int dx, int dy, int real_dx, int real_dy) { @@ -3340,7 +3792,7 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, int element; int can_move; - if (player->gone || (!dx && !dy)) + if (!player->active || (!dx && !dy)) return MF_NO_ACTION; player->MovDir = (dx < 0 ? MV_LEFT : @@ -3354,7 +3806,11 @@ boolean MoveFigureOneStep(struct PlayerInfo *player, if (!options.network && !AllPlayersInSight(player, new_jx, new_jy)) return MF_NO_ACTION; +#if 0 element = MovingOrBlocked2Element(new_jx, new_jy); +#else + element = MovingOrBlocked2ElementIfNotLeaving(new_jx, new_jy); +#endif if (DONT_GO_TO(element)) { @@ -3384,7 +3840,8 @@ 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 / player->move_delay_value); ScrollFigure(player, SCROLL_INIT); @@ -3397,21 +3854,30 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) int old_jx = jx, old_jy = jy; int moved = MF_NO_ACTION; - if (player->gone || (!dx && !dy)) + if (!player->active || (!dx && !dy)) return FALSE; - if (!FrameReached(&player->move_delay, MoveSpeed) && !tape.playing) + if (!FrameReached(&player->move_delay, player->move_delay_value) && + !tape.playing) return FALSE; + /* remove the last programmed player action */ + player->programmed_action = 0; + 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 original_move_delay_value = player->move_delay_value; + #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 */ + player->move_delay_value = MOVE_DELAY_NORMAL_SPEED; + while (player->MovPos) { ScrollFigure(player, SCROLL_GO_ON); @@ -3420,6 +3886,8 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) DrawAllPlayers(); BackToFront(); } + + player->move_delay_value = original_move_delay_value; } if (player->last_move_dir & (MV_LEFT | MV_RIGHT)) @@ -3454,13 +3922,13 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) { if (jx != old_jx) /* player has moved horizontally */ { - if ((player->MovDir == MV_LEFT && scroll_x > jx-MIDPOSX+offset) || - (player->MovDir == MV_RIGHT && scroll_x < jx-MIDPOSX-offset)) + if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) || + (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset)) scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset); /* don't scroll over playfield boundaries */ - if (scroll_x < -1 || scroll_x > lev_fieldx - SCR_FIELDX + 1) - scroll_x = (scroll_x < -1 ? -1 : lev_fieldx - SCR_FIELDX + 1); + if (scroll_x < SBX_Left || scroll_x > SBX_Right) + scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right); /* don't scroll more than one field at a time */ scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x); @@ -3472,13 +3940,13 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) } else /* player has moved vertically */ { - if ((player->MovDir == MV_UP && scroll_y > jy-MIDPOSY+offset) || - (player->MovDir == MV_DOWN && scroll_y < jy-MIDPOSY-offset)) + if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) || + (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset)) scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset); /* don't scroll over playfield boundaries */ - if (scroll_y < -1 || scroll_y > lev_fieldy - SCR_FIELDY + 1) - scroll_y = (scroll_y < -1 ? -1 : lev_fieldy - SCR_FIELDY + 1); + if (scroll_y < SBY_Upper || scroll_y > SBY_Lower) + scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower); /* don't scroll more than one field at a time */ scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y); @@ -3517,16 +3985,20 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) else if (old_jx == jx && old_jy != jy) player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP); - DrawLevelField(jx, jy); /* für "ErdreichAnbroeckeln()" */ + DrawLevelField(jx, jy); /* for "ErdreichAnbroeckeln()" */ player->last_move_dir = player->MovDir; } else + { + CheckGravityMovement(player); + player->last_move_dir = MV_NO_MOVING; + } TestIfHeroHitsBadThing(jx, jy); - if (player->gone) + if (!player->active) RemoveHero(player); return moved; @@ -3536,14 +4008,15 @@ void ScrollFigure(struct PlayerInfo *player, int mode) { int jx = player->jx, jy = player->jy; int last_jx = player->last_jx, last_jy = player->last_jy; + int move_stepsize = TILEX / player->move_delay_value; - if (!player->active || player->gone || !player->MovPos) + if (!player->active || !player->MovPos) return; if (mode == SCROLL_INIT) { player->actual_frame_counter = FrameCounter; - player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize); + player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); if (Feld[last_jx][last_jy] == EL_LEERRAUM) Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING; @@ -3554,16 +4027,29 @@ 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->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize); + player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize; + player->GfxPos = move_stepsize * (player->MovPos / move_stepsize); if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING) Feld[last_jx][last_jy] = EL_LEERRAUM; + /* before DrawPlayer() to draw correct player graphic for this case */ + if (player->MovPos == 0) + CheckGravityMovement(player); + DrawPlayer(player); - if (!player->MovPos) + if (player->MovPos == 0) { + if (IS_QUICK_GATE(Feld[last_jx][last_jy])) + { + /* continue with normal speed after quickly moving through gate */ + HALVE_PLAYER_SPEED(player); + + /* be able to make the next move without delay */ + player->move_delay = 0; + } + player->last_jx = jx; player->last_jy = jy; @@ -3579,10 +4065,13 @@ 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) { + /* set scrolling step size according to actual player's moving speed */ + ScrollStepSize = TILEX / player->move_delay_value; + screen_frame_counter = FrameCounter; ScreenMovDir = player->MovDir; ScreenMovPos = player->MovPos; @@ -3594,7 +4083,7 @@ void ScrollScreen(struct PlayerInfo *player, int mode) if (ScreenMovPos) { - ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8; + ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * ScrollStepSize; ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize); redraw_mask |= REDRAW_FIELD; } @@ -3629,7 +4118,11 @@ void TestIfGoodThingHitsBadThing(int goodx, int goody) if (!IN_LEV_FIELD(x, y)) continue; +#if 0 element = Feld[x][y]; +#else + element = MovingOrBlocked2ElementIfNotLeaving(x, y); +#endif if (DONT_TOUCH(element)) { @@ -3764,7 +4257,7 @@ void KillHero(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; - if (player->gone) + if (!player->active) return; if (IS_PFORTE(Feld[jx][jy])) @@ -3778,7 +4271,7 @@ void BuryHero(struct PlayerInfo *player) { int jx = player->jx, jy = player->jy; - if (player->gone) + if (!player->active) return; PlaySoundLevel(jx, jy, SND_AUTSCH); @@ -3793,11 +4286,13 @@ void RemoveHero(struct PlayerInfo *player) int jx = player->jx, jy = player->jy; int i, found = FALSE; - player->gone = TRUE; + player->present = FALSE; + player->active = FALSE; + StorePlayer[jx][jy] = 0; for (i=0; ijx, jy = player->jy; int dx = x - jx, dy = y - jy; + int move_direction = (dx == -1 ? MV_LEFT : + dx == +1 ? MV_RIGHT : + dy == -1 ? MV_UP : + dy == +1 ? MV_DOWN : MV_NO_MOVING); int element; if (!player->MovPos) @@ -3831,10 +4330,18 @@ int DigField(struct PlayerInfo *player, switch(element) { case EL_LEERRAUM: + PlaySoundLevel(x, y, SND_EMPTY); break; case EL_ERDREICH: Feld[x][y] = EL_LEERRAUM; + PlaySoundLevel(x, y, SND_SCHLURF); + break; + + case EL_SP_BASE: + case EL_SP_BUG: + Feld[x][y] = EL_LEERRAUM; + PlaySoundLevel(x, y, SND_SP_BASE); break; case EL_EDELSTEIN: @@ -3843,6 +4350,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) @@ -3851,17 +4359,30 @@ int DigField(struct PlayerInfo *player, DrawText(DX_EMERALDS, DY_EMERALDS, int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW); + if (element == EL_SP_INFOTRON) + PlaySoundLevel(x, y, SND_SP_INFOTRON); + else + PlaySoundLevel(x, y, SND_PONG); + break; + + case EL_SPEED_PILL: + RemoveField(x, y); + player->move_delay_value = MOVE_DELAY_HIGH_SPEED; PlaySoundLevel(x, y, SND_PONG); break; case EL_DYNAMIT_AUS: + case EL_SP_DISK_RED: RemoveField(x, y); player->dynamite++; RaiseScoreElement(EL_DYNAMIT); DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW); - PlaySoundLevel(x, y, SND_PONG); + if (element == EL_SP_DISK_RED) + PlaySoundLevel(x, y, SND_SP_INFOTRON); + else + PlaySoundLevel(x, y, SND_PONG); break; case EL_DYNABOMB_NR: @@ -3891,7 +4412,27 @@ int DigField(struct PlayerInfo *player, case EL_SCHLUESSEL3: case EL_SCHLUESSEL4: { - int key_nr = element-EL_SCHLUESSEL1; + int key_nr = element - EL_SCHLUESSEL1; + + RemoveField(x, y); + player->key[key_nr] = TRUE; + RaiseScoreElement(EL_SCHLUESSEL); + DrawMiniGraphicExt(drawto, gc, + DX_KEYS+key_nr*MINI_TILEX, DY_KEYS, + GFX_SCHLUESSEL1+key_nr); + DrawMiniGraphicExt(window, gc, + DX_KEYS+key_nr*MINI_TILEX, DY_KEYS, + GFX_SCHLUESSEL1+key_nr); + PlaySoundLevel(x, y, SND_PONG); + break; + } + + case EL_EM_KEY_1: + case EL_EM_KEY_2: + case EL_EM_KEY_3: + case EL_EM_KEY_4: + { + int key_nr = element - EL_EM_KEY_1; RemoveField(x, y); player->key[key_nr] = TRUE; @@ -3914,10 +4455,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; + PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT); + 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; @@ -3948,6 +4518,8 @@ int DigField(struct PlayerInfo *player, PlaySoundLevel(x+dx, y+dy, SND_PUSCH); else if (element == EL_KOKOSNUSS) PlaySoundLevel(x+dx, y+dy, SND_KNURK); + else if (IS_SP_ELEMENT(element)) + PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH); else PlaySoundLevel(x+dx, y+dy, SND_KLOPF); break; @@ -3956,7 +4528,7 @@ int DigField(struct PlayerInfo *player, case EL_PFORTE2: case EL_PFORTE3: case EL_PFORTE4: - if (!player->key[element-EL_PFORTE1]) + if (!player->key[element - EL_PFORTE1]) return MF_NO_ACTION; break; @@ -3964,13 +4536,84 @@ int DigField(struct PlayerInfo *player, case EL_PFORTE2X: case EL_PFORTE3X: case EL_PFORTE4X: - if (!player->key[element-EL_PFORTE1X]) + if (!player->key[element - EL_PFORTE1X]) + return MF_NO_ACTION; + break; + + case EL_EM_GATE_1: + case EL_EM_GATE_2: + case EL_EM_GATE_3: + case EL_EM_GATE_4: + if (!player->key[element - EL_EM_GATE_1]) + return MF_NO_ACTION; + 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); + + break; + + case EL_EM_GATE_1X: + case EL_EM_GATE_2X: + case EL_EM_GATE_3X: + case EL_EM_GATE_4X: + if (!player->key[element - EL_EM_GATE_1X]) + return MF_NO_ACTION; + 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); + + 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; + + /* automatically move to the next field with double speed */ + player->programmed_action = move_direction; + DOUBLE_PLAYER_SPEED(player); + break; case EL_AUSGANG_ZU: case EL_AUSGANG_ACT: - /* Tür ist (noch) nicht offen! */ + /* door is not (yet) open */ return MF_NO_ACTION; break; @@ -3980,14 +4623,6 @@ int DigField(struct PlayerInfo *player, PlaySoundLevel(x, y, SND_BUING); - /* - player->gone = TRUE; - PlaySoundLevel(x, y, SND_BUING); - - if (!local_player->friends_still_needed) - player->LevelSolved = player->GameOver = TRUE; - */ - break; case EL_BIRNE_AUS: @@ -4013,6 +4648,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; @@ -4075,7 +4711,7 @@ int DigField(struct PlayerInfo *player, if (IS_SB_ELEMENT(element) && local_player->sokobanfields_still_needed == 0 && - game_emulation == EMU_SOKOBAN) + game.emulation == EMU_SOKOBAN) { player->LevelSolved = player->GameOver = TRUE; PlaySoundLevel(x, y, SND_BUING); @@ -4091,7 +4727,6 @@ int DigField(struct PlayerInfo *player, default: return MF_NO_ACTION; - break; } player->push_delay = 0; @@ -4104,7 +4739,7 @@ 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->gone || !IN_LEV_FIELD(x, y)) + if (!player->active || !IN_LEV_FIELD(x, y)) return FALSE; if (dx && dy) @@ -4139,7 +4774,7 @@ boolean PlaceBomb(struct PlayerInfo *player) int jx = player->jx, jy = player->jy; int element; - if (player->gone || player->MovPos) + if (!player->active || player->MovPos) return FALSE; element = Feld[jx][jy]; @@ -4160,7 +4795,12 @@ boolean PlaceBomb(struct PlayerInfo *player) DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW); if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) - DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT); + { + if (game.emulation == EMU_SUPAPLEX) + DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED); + else + DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT); + } } else { @@ -4193,19 +4833,21 @@ void PlaySoundLevel(int x, int y, int sound_nr) volume = PSND_MAX_VOLUME; #ifndef MSDOS - stereo = (sx-SCR_FIELDX/2)*12; + stereo = (sx - SCR_FIELDX/2) * 12; #else - stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5; - if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT; - if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT; + stereo = PSND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5; + if (stereo > PSND_MAX_RIGHT) + stereo = PSND_MAX_RIGHT; + if (stereo < PSND_MAX_LEFT) + stereo = PSND_MAX_LEFT; #endif if (!IN_SCR_FIELD(sx, sy)) { - int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2; - int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2; + int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2; + int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2; - volume -= volume*(dx > dy ? dx : dy)/silence_distance; + volume -= volume * (dx > dy ? dx : dy) / silence_distance; } PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP); @@ -4263,3 +4905,238 @@ void RaiseScoreElement(int element) break; } } + +/* ---------- new game button stuff ---------------------------------------- */ + +/* graphic position values for game buttons */ +#define GAME_BUTTON_XSIZE 30 +#define GAME_BUTTON_YSIZE 30 +#define GAME_BUTTON_XPOS 5 +#define GAME_BUTTON_YPOS 215 +#define SOUND_BUTTON_XPOS 5 +#define SOUND_BUTTON_YPOS (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE) + +#define GAME_BUTTON_STOP_XPOS (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE) +#define GAME_BUTTON_PAUSE_XPOS (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE) +#define GAME_BUTTON_PLAY_XPOS (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE) +#define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE) +#define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE) +#define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE) + +static struct +{ + int x, y; + int gadget_id; + char *infotext; +} gamebutton_info[NUM_GAME_BUTTONS] = +{ + { + GAME_BUTTON_STOP_XPOS, GAME_BUTTON_YPOS, + GAME_CTRL_ID_STOP, + "stop game" + }, + { + GAME_BUTTON_PAUSE_XPOS, GAME_BUTTON_YPOS, + GAME_CTRL_ID_PAUSE, + "pause game" + }, + { + GAME_BUTTON_PLAY_XPOS, GAME_BUTTON_YPOS, + GAME_CTRL_ID_PLAY, + "play game" + }, + { + SOUND_BUTTON_MUSIC_XPOS, SOUND_BUTTON_YPOS, + SOUND_CTRL_ID_MUSIC, + "background music on/off" + }, + { + SOUND_BUTTON_LOOPS_XPOS, SOUND_BUTTON_YPOS, + SOUND_CTRL_ID_LOOPS, + "sound loops on/off" + }, + { + SOUND_BUTTON_SIMPLE_XPOS, SOUND_BUTTON_YPOS, + SOUND_CTRL_ID_SIMPLE, + "normal sounds on/off" + } +}; + +void CreateGameButtons() +{ + int i; + + for (i=0; icustom_id; + + if (game_status != PLAYING) + return; + + switch (id) + { + case GAME_CTRL_ID_STOP: + if (AllPlayersGone) + { + CloseDoor(DOOR_CLOSE_1); + game_status = MAINMENU; + DrawMainMenu(); + break; + } + + if (level_editor_test_game || + Request("Do you really want to quit the game ?", + REQ_ASK | REQ_STAY_CLOSED)) + { +#ifndef MSDOS + if (options.network) + SendToServer_StopPlaying(); + else +#endif + { + game_status = MAINMENU; + DrawMainMenu(); + } + } + else + OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK); + break; + + case GAME_CTRL_ID_PAUSE: + if (options.network) + { +#ifndef MSDOS + if (tape.pausing) + SendToServer_ContinuePlaying(); + else + SendToServer_PausePlaying(); +#endif + } + else + TapeTogglePause(); + break; + + case GAME_CTRL_ID_PLAY: + if (tape.pausing) + { +#ifndef MSDOS + if (options.network) + SendToServer_ContinuePlaying(); + else +#endif + { + tape.pausing = FALSE; + DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0); + } + } + break; + + case SOUND_CTRL_ID_MUSIC: + if (setup.sound_music) + { + setup.sound_music = FALSE; + FadeSound(background_loop[level_nr % num_bg_loops]); + } + else if (sound_loops_allowed) + { + setup.sound = setup.sound_music = TRUE; + PlaySoundLoop(background_loop[level_nr % num_bg_loops]); + } + break; + + case SOUND_CTRL_ID_LOOPS: + if (setup.sound_loops) + setup.sound_loops = FALSE; + else if (sound_loops_allowed) + setup.sound = setup.sound_loops = TRUE; + break; + + case SOUND_CTRL_ID_SIMPLE: + if (setup.sound_simple) + setup.sound_simple = FALSE; + else if (sound_status==SOUND_AVAILABLE) + setup.sound = setup.sound_simple = TRUE; + break; + + default: + break; + } +}