X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=ea346bfd599ddbd287013bf79259c1aa7517bfcd;hb=4be46f1030df4cb7db0ce7c46d2518334861731a;hp=06edf65091e2acd9dac24734fd34eb66e3d3b586;hpb=632b8ce3e7c946dc6d5e9d1f93a1a8dcb38e510c;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 06edf650..ea346bfd 100644 --- a/src/game.c +++ b/src/game.c @@ -100,6 +100,7 @@ #define NUM_GAME_BUTTONS 6 /* forward declaration for internal use */ +static void InitBeltMovement(void); static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); static void KillHeroUnlessProtected(int, int); @@ -113,6 +114,11 @@ static void HandleGameButtons(struct GadgetInfo *); static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; + +/* ------------------------------------------------------------------------- */ +/* sound definitions */ +/* ------------------------------------------------------------------------- */ + #define SND_ACTION_UNKNOWN 0 #define SND_ACTION_WAITING 1 #define SND_ACTION_MOVING 2 @@ -156,6 +162,40 @@ static boolean is_loop_sound[NUM_SOUND_FILES]; #define IS_LOOP_SOUND(x) (is_loop_sound[x]) +/* ------------------------------------------------------------------------- + definition of elements that automatically change to other elements after + a specified time, eventually calling a function when changing + ------------------------------------------------------------------------- */ + +struct ChangingElementInfo +{ + int base_element; + int next_element; + int change_delay; + void (*pre_change_function)(int x, int y); + void (*change_function)(int x, int y); + void (*post_change_function)(int x, int y); +}; + +static struct ChangingElementInfo changing_element_list[] = +{ + { EL_NUT_CRACKING, EL_EMERALD, 6, NULL, NULL, NULL }, + { EL_PEARL_BREAKING, EL_EMPTY, 8, NULL, NULL, NULL }, + { EL_EXIT_OPENING, EL_EXIT_OPEN, 29, NULL, NULL, NULL }, + { EL_SWITCHGATE_OPENING, EL_SWITCHGATE_OPEN, 29, NULL, NULL, NULL }, + { EL_SWITCHGATE_CLOSING, EL_SWITCHGATE_CLOSED, 29, NULL, NULL, NULL }, + { EL_TIMEGATE_OPENING, EL_TIMEGATE_OPEN, 29, NULL, NULL, NULL }, + { EL_TIMEGATE_CLOSING, EL_TIMEGATE_CLOSED, 29, NULL, NULL, NULL }, + + { EL_UNDEFINED, EL_UNDEFINED, -1, NULL } +}; + +static struct ChangingElementInfo changing_element[MAX_NUM_ELEMENTS]; + +#define IS_AUTO_CHANGING(e) (changing_element[e].base_element != EL_UNDEFINED) + + + #ifdef DEBUG #if 0 static unsigned int getStateCheckSum(int counter) @@ -191,7 +231,7 @@ static unsigned int getStateCheckSum(int counter) checksum += mult++ * Store[x][y]; checksum += mult++ * Store2[x][y]; checksum += mult++ * StorePlayer[x][y]; - checksum += mult++ * Frame[x][y]; + checksum += mult++ * ExplodePhase[x][y]; checksum += mult++ * AmoebaNr[x][y]; checksum += mult++ * JustStopped[x][y]; checksum += mult++ * Stop[x][y]; @@ -487,7 +527,7 @@ void DrawGameDoorValues() for (j=0; j<4; j++) if (stored_player[i].key[j]) DrawMiniGraphicExt(drawto, DX_KEYS + j * MINI_TILEX, DY_KEYS, - GFX_SCHLUESSEL1 + j); + IMG_KEY1 + j); DrawText(DX + XX_EMERALDS, DY + YY_EMERALDS, int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW); @@ -517,6 +557,7 @@ void InitGameSound() debug_print_timestamp(0, NULL); #endif + /* initialize sound effect for all elements to "no sound" */ for (i=0; i VERSION_IDENT(2,0,1)) - Elementeigenschaften2[EL_WALL_GROWING_ACTIVE] |= EP_BIT_EM_SLIPPERY_WALL; + Properties2[EL_WALL_GROWING_ACTIVE] |= EP_BIT_EM_SLIPPERY_WALL; else - Elementeigenschaften2[EL_WALL_GROWING_ACTIVE] &=~EP_BIT_EM_SLIPPERY_WALL; + Properties2[EL_WALL_GROWING_ACTIVE] &=~EP_BIT_EM_SLIPPERY_WALL; + } + + /* initialize changing elements information */ + for (i=0; ibase_element; + + changing_element[element].base_element = ce->base_element; + changing_element[element].next_element = ce->next_element; + changing_element[element].change_delay = ce->change_delay; + changing_element[element].pre_change_function = ce->pre_change_function; + changing_element[element].change_function = ce->change_function; + changing_element[element].post_change_function = ce->post_change_function; + + i++; } } @@ -796,12 +864,14 @@ void InitGame() Feld[x][y] = Ur[x][y]; MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0; Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0; - Frame[x][y] = 0; - GfxAction[x][y] = GFX_ACTION_DEFAULT; AmoebaNr[x][y] = 0; JustStopped[x][y] = 0; Stop[x][y] = FALSE; + ExplodePhase[x][y] = 0; ExplodeField[x][y] = EX_NO_EXPLOSION; + + GfxFrame[x][y] = 0; + GfxAction[x][y] = GFX_ACTION_DEFAULT; } } @@ -820,6 +890,8 @@ void InitGame() } } + InitBeltMovement(); + game.emulation = (emulate_bd ? EMU_BOULDERDASH : emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); @@ -959,7 +1031,6 @@ void InitGame() DrawLevel(); DrawAllPlayers(); - FadeToFront(); /* after drawing the level, correct some elements */ if (game.timegate_time_left == 0) @@ -969,9 +1040,10 @@ void InitGame() BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY); redraw_mask |= REDRAW_FROM_BACKBUFFER; + FadeToFront(); /* copy default game door content to main double buffer */ - BlitBitmap(new_graphic_info[IMG_MENU_DOOR].bitmap, drawto, + BlitBitmap(new_graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); if (level_nr < 100) @@ -980,7 +1052,7 @@ void InitGame() else { DrawTextExt(drawto, DX + XX_EMERALDS, DY + YY_EMERALDS, - int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3); + int2str(level_nr, 3), FS_SMALL, FC_SPECIAL3, FONT_OPAQUE); BlitBitmap(drawto, drawto, DX + XX_EMERALDS, DY + YY_EMERALDS + 1, FONT5_XSIZE * 3, FONT5_YSIZE - 1, @@ -1154,6 +1226,9 @@ void GameWon() if (local_player->MovPos) return; + if (tape.playing && tape.auto_play) + tape.auto_play_level_solved = TRUE; + local_player->LevelSolved = FALSE; PlaySoundStereo(SND_GAME_WINNING, SOUND_MAX_RIGHT); @@ -1331,6 +1406,9 @@ void InitMovingField(int x, int y, int direction) int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); + if (!JustStopped[x][y] || direction != MovDir[x][y]) + GfxFrame[x][y] = 0; + MovDir[x][y] = direction; MovDir[newx][newy] = direction; @@ -1646,7 +1724,7 @@ void Explode(int ex, int ey, int phase, int mode) Feld[x][y] = EL_EXPLOSION; MovDir[x][y] = MovPos[x][y] = 0; AmoebaNr[x][y] = 0; - Frame[x][y] = 1; + ExplodePhase[x][y] = 1; Stop[x][y] = TRUE; } @@ -1662,7 +1740,7 @@ void Explode(int ex, int ey, int phase, int mode) x = ex; y = ey; - Frame[x][y] = (phase < last_phase ? phase + 1 : 0); + ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0); if (phase == first_phase_after_start) { @@ -1879,6 +1957,67 @@ void Blurb(int x, int y) } } +static void InitBeltMovement() +{ + static int belt_base_element[4] = + { + EL_CONVEYOR_BELT1_LEFT, + EL_CONVEYOR_BELT2_LEFT, + EL_CONVEYOR_BELT3_LEFT, + EL_CONVEYOR_BELT4_LEFT + }; + static int belt_base_active_element[4] = + { + EL_CONVEYOR_BELT1_LEFT_ACTIVE, + EL_CONVEYOR_BELT2_LEFT_ACTIVE, + EL_CONVEYOR_BELT3_LEFT_ACTIVE, + EL_CONVEYOR_BELT4_LEFT_ACTIVE + }; + + int x, y, i, j; + + /* set frame order for belt animation graphic according to belt direction */ + for (i=0; i<4; i++) + { + int belt_nr = i; + + for (j=0; j<3; j++) + { + int element = belt_base_active_element[belt_nr] + j; + int graphic = el2img(element); + + if (game.belt_dir[i] == MV_LEFT) + new_graphic_info[graphic].anim_mode &= ~ANIM_REVERSE; + else + new_graphic_info[graphic].anim_mode |= ANIM_REVERSE; + } + } + + for(y=0; y0 && IS_PLAYER(x-1, y)) || (x 0) JustStopped[x][y]--; + GfxFrame[x][y]++; + #if DEBUG if (IS_BLOCKED(x, y)) { @@ -4898,7 +5143,7 @@ void GameActions() #if 1 if (new_graphic_info[graphic].anim_frames > 1) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + DrawLevelGraphicAnimation(x, y, graphic); #endif continue; @@ -4912,7 +5157,7 @@ void GameActions() if (Feld[x][y] == EL_EMERALD && new_graphic_info[graphic].anim_frames > 1 && !IS_MOVING(x, y)) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + DrawLevelGraphicAnimation(x, y, graphic); #endif if (IS_GEM(element) || element == EL_SP_INFOTRON) @@ -4929,7 +5174,7 @@ void GameActions() element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) && new_graphic_info[graphic].anim_frames > 1) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + DrawLevelGraphicAnimation(x, y, graphic); #endif else if (IS_MOVING(x, y)) @@ -4938,7 +5183,7 @@ void GameActions() CheckDynamite(x, y); #if 0 else if (element == EL_EXPLOSION && !game.explosions_delayed) - Explode(x, y, Frame[x][y], EX_NORMAL); + Explode(x, y, ExplodePhase[x][y], EX_NORMAL); #endif else if (element == EL_AMOEBA_CREATING) AmoebeWaechst(x, y); @@ -4959,16 +5204,20 @@ void GameActions() else if (element == EL_ACID_SPLASH_LEFT || element == EL_ACID_SPLASH_RIGHT) Blurb(x, y); +#if 0 else if (element == EL_NUT_CRACKING) NussKnacken(x, y); else if (element == EL_PEARL_BREAKING) BreakingPearl(x, y); +#endif else if (element == EL_EXIT_CLOSED) AusgangstuerPruefen(x, y); else if (element == EL_SP_EXIT_CLOSED) AusgangstuerPruefen_SP(x, y); +#if 0 else if (element == EL_EXIT_OPENING) AusgangstuerOeffnen(x, y); +#endif else if (element == EL_WALL_GROWING_ACTIVE) MauerWaechst(x, y); else if (element == EL_WALL_GROWING || @@ -4978,10 +5227,13 @@ void GameActions() MauerAbleger(x, y); else if (element == EL_FLAMES) CheckForDragon(x, y); - else if (element == EL_SP_BUGGY_BASE || element == EL_SP_BUGGY_BASE_ACTIVE) + else if (element == EL_SP_BUGGY_BASE || + element == EL_SP_BUGGY_BASE_ACTIVATING || + element == EL_SP_BUGGY_BASE_ACTIVE) CheckBuggyBase(x, y); else if (element == EL_TRAP || element == EL_TRAP_ACTIVE) CheckTrap(x, y); +#if 0 else if (IS_BELT_ACTIVE(element)) DrawBeltAnimation(x, y, element); else if (element == EL_SWITCHGATE_OPENING) @@ -4992,12 +5244,19 @@ void GameActions() OpenTimegate(x, y); else if (element == EL_TIMEGATE_CLOSING) CloseTimegate(x, y); +#endif + + else if (IS_AUTO_CHANGING(element)) + ChangeElement(x, y); #if 1 else if (new_graphic_info[graphic].anim_frames > 1) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + DrawLevelGraphicAnimation(x, y, graphic); #endif + if (IS_BELT_ACTIVE(element)) + PlaySoundLevelAction(x, y, SND_ACTION_ACTIVE); + if (game.magic_wall_active) { boolean sieb = FALSE; @@ -5078,7 +5337,7 @@ void GameActions() if (ExplodeField[x][y]) Explode(x, y, EX_PHASE_START, ExplodeField[x][y]); else if (element == EL_EXPLOSION) - Explode(x, y, Frame[x][y], EX_NORMAL); + Explode(x, y, ExplodePhase[x][y], EX_NORMAL); ExplodeField[x][y] = EX_NO_EXPLOSION; } @@ -5408,7 +5667,8 @@ boolean MoveFigure(struct PlayerInfo *player, int dx, int dy) int original_move_delay_value = player->move_delay_value; #if DEBUG - printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n"); + printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES. [%ld]\n", + tape.counter); #endif /* scroll remaining steps with finest movement resolution */ @@ -5994,6 +6254,7 @@ int DigField(struct PlayerInfo *player, case EL_TRAP: case EL_SP_BASE: case EL_SP_BUGGY_BASE: + case EL_SP_BUGGY_BASE_ACTIVATING: RemoveField(x, y); PlaySoundLevelElementAction(x, y, element, SND_ACTION_DIGGING); break; @@ -6098,9 +6359,9 @@ int DigField(struct PlayerInfo *player, player->key[key_nr] = TRUE; RaiseScoreElement(element); DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS, - GFX_SCHLUESSEL1 + key_nr); + IMG_KEY1 + key_nr); DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS, - GFX_SCHLUESSEL1 + key_nr); + IMG_KEY1 + key_nr); PlaySoundLevel(x, y, SND_KEY_COLLECTING); break; } @@ -6116,9 +6377,9 @@ int DigField(struct PlayerInfo *player, player->key[key_nr] = TRUE; RaiseScoreElement(element); DrawMiniGraphicExt(drawto, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS, - GFX_SCHLUESSEL1 + key_nr); + IMG_KEY1 + key_nr); DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS, - GFX_SCHLUESSEL1 + key_nr); + IMG_KEY1 + key_nr); PlaySoundLevel(x, y, SND_KEY_COLLECTING); break; } @@ -6864,7 +7125,7 @@ void CreateGameButtons() for (i=0; i