X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=ea346bfd599ddbd287013bf79259c1aa7517bfcd;hb=4be46f1030df4cb7db0ce7c46d2518334861731a;hp=eb11ae1dd3ab48305474d6dde21e2371cf31b088;hpb=234748b5eb0bc4fe29a36fd25a1d25658f53858a;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index eb11ae1d..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]; @@ -292,6 +332,8 @@ static void InitField(int x, int y, boolean init_game) Feld[x][y] = EL_SP_MURPHY_CLONE; break; } + + Feld[x][y] = EL_PLAYER1; } /* no break! */ case EL_PLAYER1: @@ -485,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); @@ -515,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++; } } @@ -794,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; } } @@ -818,6 +890,8 @@ void InitGame() } } + InitBeltMovement(); + game.emulation = (emulate_bd ? EMU_BOULDERDASH : emulate_sb ? EMU_SOKOBAN : emulate_sp ? EMU_SUPAPLEX : EMU_NONE); @@ -957,7 +1031,6 @@ void InitGame() DrawLevel(); DrawAllPlayers(); - FadeToFront(); /* after drawing the level, correct some elements */ if (game.timegate_time_left == 0) @@ -967,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(pix[PIX_DOOR], drawto, + BlitBitmap(new_graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); if (level_nr < 100) @@ -978,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, @@ -996,7 +1070,7 @@ void InitGame() MapTapeButtons(); /* copy actual game door content to door double buffer for OpenDoor() */ - BlitBitmap(drawto, pix[PIX_DB_DOOR], + BlitBitmap(drawto, bitmap_db_door, DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1); OpenDoor(DOOR_OPEN_ALL); @@ -1152,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); @@ -1325,16 +1402,23 @@ int NewHiScore() void InitMovingField(int x, int y, int direction) { + int element = Feld[x][y]; 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; if (Feld[newx][newy] == EL_EMPTY) Feld[newx][newy] = EL_BLOCKED; - GfxAction[x][y] = GFX_ACTION_MOVING; + if (direction == MV_DOWN && CAN_FALL(element)) + GfxAction[x][y] = GFX_ACTION_FALLING; + else + GfxAction[x][y] = GFX_ACTION_MOVING; } void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y) @@ -1640,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; } @@ -1656,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) { @@ -1700,15 +1784,13 @@ void Explode(int ex, int ey, int phase, int mode) if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present) StorePlayer[x][y] = 0; } - else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) { - int graphic = IMG_EXPLOSION; - int frame = (phase / delay - 1); - - if (game.emulation == EMU_SUPAPLEX) - graphic = (Store[x][y] == EL_SP_INFOTRON ? - IMG_SP_EXPLOSION_INFOTRON : - IMG_SP_EXPLOSION); + int stored = Store[x][y]; + int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION : + stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON : + IMG_SP_EXPLOSION); + int frame = getGraphicAnimationFrame(graphic, phase - delay); if (phase == delay) DrawCrumbledSand(SCREENX(x), SCREENY(y)); @@ -1875,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 %d\n", MovDir[x][y]); +#endif TurnRound(x, y); - +#if 0 + if (element == EL_SPRING) + printf("2--> %d\n", MovDir[x][y]); +#endif if (MovDelay[x][y] && (element == EL_BUG || element == EL_SPACESHIP || element == EL_SP_SNIKSNAK || @@ -2962,7 +3162,7 @@ void StartMoving(int x, int y) } } else if (element == EL_SP_ELECTRON) - DrawGraphicAnimation(x, y, IMG_SP_ELECTRON); + DrawLevelElementAnimation(x, y, element); else if (element == EL_DRAGON) { int i; @@ -3220,11 +3420,11 @@ void StartMoving(int x, int y) element == EL_SP_SNIKSNAK || element == EL_MOLE) DrawLevelField(x, y); else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY) - DrawGraphicAnimation(x, y, el2img(element)); + DrawLevelElementAnimation(x, y, element); else if (element == EL_SATELLITE) - DrawGraphicAnimation(x, y, IMG_SATELLITE); + DrawLevelElementAnimation(x, y, element); else if (element == EL_SP_ELECTRON) - DrawGraphicAnimation(x, y, IMG_SP_ELECTRON); + DrawLevelElementAnimation(x, y, element); if (DONT_TOUCH(element)) TestIfBadThingTouchesHero(x, y); @@ -3249,7 +3449,7 @@ void ContinueMoving(int x, int y) int direction = MovDir[x][y]; int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0); int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0); - int horiz_move = (dx!=0); + int horiz_move = (dx != 0); int newx = x + dx, newy = y + dy; int step = (horiz_move ? dx : dy) * TILEX / 8; @@ -3266,8 +3466,8 @@ void ContinueMoving(int x, int y) else if (CAN_FALL(element) && horiz_move && y < lev_fieldy-1 && IS_BELT_ACTIVE(Feld[x][y+1])) step /= 2; - else if (element == EL_SPRING_MOVING) - step*=2; + else if (element == EL_SPRING && horiz_move) + step *= 2; #if OLD_GAME_BEHAVIOUR else if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element)) @@ -3362,8 +3562,19 @@ void ContinueMoving(int x, int y) GfxAction[newx][newy] = GfxAction[x][y]; /* keep action one frame */ GfxAction[x][y] = GFX_ACTION_DEFAULT; +#if 0 if (!CAN_MOVE(element)) MovDir[newx][newy] = 0; +#else + /* + if (CAN_FALL(element) && MovDir[newx][newy] == MV_DOWN) + MovDir[newx][newy] = 0; + */ + + if (!CAN_MOVE(element) || + (element == EL_SPRING && MovDir[newx][newy] == MV_DOWN)) + MovDir[newx][newy] = 0; +#endif DrawLevelField(x, y); DrawLevelField(newx, newy); @@ -3386,8 +3597,14 @@ void ContinueMoving(int x, int y) } else /* still moving on */ { +#if 0 if (GfxAction[x][y] == GFX_ACTION_DEFAULT) + { + printf("reset GfxAction...\n"); + GfxAction[x][y] = GFX_ACTION_MOVING; + } +#endif DrawLevelField(x, y); } @@ -3882,14 +4099,15 @@ void RobotWheel(int x, int y) DrawGraphic(SCREENX(x), SCREENY(y), IMG_ROBOT_WHEEL_ACTIVE, frame); } - if (!(MovDelay[x][y]%4)) - PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE); + PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE); + return; } } Feld[x][y] = EL_ROBOT_WHEEL; DrawLevelField(x, y); + if (ZX == x && ZY == y) ZX = ZY = -1; } @@ -3911,23 +4129,20 @@ void TimegateWheel(int x, int y) DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_SWITCH_ACTIVE, frame); } - if (!(MovDelay[x][y]%4)) - PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE); + PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE); + return; } } Feld[x][y] = EL_TIMEGATE_SWITCH; DrawLevelField(x, y); + + /* !!! THIS LOOKS WRONG !!! */ if (ZX == x && ZY == y) ZX = ZY = -1; } -void Blubber(int x, int y) -{ - DrawGraphicAnimation(x, y, IMG_ACID); -} - void NussKnacken(int x, int y) { if (!MovDelay[x][y]) /* next animation frame */ @@ -3936,20 +4151,22 @@ void NussKnacken(int x, int y) 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))) + if (MovDelay[x][y]) { - int frame = getGraphicAnimationFrame(IMG_NUT_CRACKING, - 6 - MovDelay[x][y]); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + int frame = getGraphicAnimationFrame(IMG_NUT_CRACKING, + 6 - MovDelay[x][y]); - DrawGraphic(SCREENX(x), SCREENY(y), IMG_NUT_CRACKING, frame); - } + DrawGraphic(SCREENX(x), SCREENY(y), IMG_NUT_CRACKING, frame); + } - if (!MovDelay[x][y]) - { - Feld[x][y] = EL_EMERALD; - DrawLevelField(x, y); + return; } } + + Feld[x][y] = EL_EMERALD; + DrawLevelField(x, y); } void BreakingPearl(int x, int y) @@ -3960,27 +4177,29 @@ void BreakingPearl(int x, int y) 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))) + if (MovDelay[x][y]) { - int frame = getGraphicAnimationFrame(IMG_PEARL_BREAKING, - 8 - MovDelay[x][y]); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + int frame = getGraphicAnimationFrame(IMG_PEARL_BREAKING, + 8 - MovDelay[x][y]); - DrawGraphic(SCREENX(x), SCREENY(y), IMG_PEARL_BREAKING, frame); - } + DrawGraphic(SCREENX(x), SCREENY(y), IMG_PEARL_BREAKING, frame); + } - if (!MovDelay[x][y]) - { - Feld[x][y] = EL_EMPTY; - DrawLevelField(x, y); + return; } } + + Feld[x][y] = EL_EMPTY; + DrawLevelField(x, y); } void SiebAktivieren(int x, int y, int type) { int graphic = (type == 1 ? IMG_MAGIC_WALL_FULL : IMG_BD_MAGIC_WALL_FULL); - DrawGraphicAnimation(x, y, graphic); + DrawLevelGraphicAnimation(x, y, graphic); } void AusgangstuerPruefen(int x, int y) @@ -4025,26 +4244,25 @@ void AusgangstuerOeffnen(int x, int y) int tuer; MovDelay[x][y]--; - tuer = MovDelay[x][y]/delay; - if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + tuer = MovDelay[x][y] / delay; + + if (!(MovDelay[x][y] % delay)) { - int frame = getGraphicAnimationFrame(IMG_EXIT_OPENING, - 29 - MovDelay[x][y]); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + int frame = getGraphicAnimationFrame(IMG_EXIT_OPENING, + 29 - MovDelay[x][y]); - DrawGraphic(SCREENX(x), SCREENY(y), IMG_EXIT_OPENING, frame); + DrawGraphic(SCREENX(x), SCREENY(y), IMG_EXIT_OPENING, frame); + } } - if (!MovDelay[x][y]) - { - Feld[x][y] = EL_EXIT_OPEN; - DrawLevelField(x, y); - } + if (MovDelay[x][y]) + return; } -} -void AusgangstuerBlinken(int x, int y) -{ - DrawGraphicAnimation(x, y, IMG_EXIT_OPEN); + Feld[x][y] = EL_EXIT_OPEN; + DrawLevelField(x, y); } void OpenSwitchgate(int x, int y) @@ -4058,20 +4276,23 @@ void OpenSwitchgate(int x, int y) { MovDelay[x][y]--; - if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + if (!(MovDelay[x][y] % delay)) { - int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_OPENING, - 29 - MovDelay[x][y]); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_OPENING, + 29 - MovDelay[x][y]); - DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_OPENING, frame); + DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_OPENING, frame); + } } - if (!MovDelay[x][y]) - { - Feld[x][y] = EL_SWITCHGATE_OPEN; - DrawLevelField(x, y); - } + if (MovDelay[x][y]) + return; } + + Feld[x][y] = EL_SWITCHGATE_OPEN; + DrawLevelField(x, y); } void CloseSwitchgate(int x, int y) @@ -4085,20 +4306,23 @@ void CloseSwitchgate(int x, int y) { MovDelay[x][y]--; - if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + if (!(MovDelay[x][y] % delay)) { - int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_CLOSING, - 29 - MovDelay[x][y]); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + int frame = getGraphicAnimationFrame(IMG_SWITCHGATE_CLOSING, + 29 - MovDelay[x][y]); - DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_CLOSING, frame); + DrawGraphic(SCREENX(x), SCREENY(y), IMG_SWITCHGATE_CLOSING, frame); + } } - if (!MovDelay[x][y]) - { - Feld[x][y] = EL_SWITCHGATE_CLOSED; - DrawLevelField(x, y); - } + if (MovDelay[x][y]) + return; } + + Feld[x][y] = EL_SWITCHGATE_CLOSED; + DrawLevelField(x, y); } void OpenTimegate(int x, int y) @@ -4112,20 +4336,23 @@ void OpenTimegate(int x, int y) { MovDelay[x][y]--; - if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + if (!(MovDelay[x][y] % delay)) { - int frame = getGraphicAnimationFrame(IMG_TIMEGATE_OPENING, - 29 - MovDelay[x][y]); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + int frame = getGraphicAnimationFrame(IMG_TIMEGATE_OPENING, + 29 - MovDelay[x][y]); - DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_OPENING, frame); + DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_OPENING, frame); + } } - if (!MovDelay[x][y]) - { - Feld[x][y] = EL_TIMEGATE_OPEN; - DrawLevelField(x, y); - } + if (MovDelay[x][y]) + return; } + + Feld[x][y] = EL_TIMEGATE_OPEN; + DrawLevelField(x, y); } void CloseTimegate(int x, int y) @@ -4139,20 +4366,23 @@ void CloseTimegate(int x, int y) { MovDelay[x][y]--; - if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + if (!(MovDelay[x][y] % delay)) { - int frame = getGraphicAnimationFrame(IMG_TIMEGATE_CLOSING, - 29 - MovDelay[x][y]); + if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) + { + int frame = getGraphicAnimationFrame(IMG_TIMEGATE_CLOSING, + 29 - MovDelay[x][y]); - DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_CLOSING, frame); + DrawGraphic(SCREENX(x), SCREENY(y), IMG_TIMEGATE_CLOSING, frame); + } } - if (!MovDelay[x][y]) - { - Feld[x][y] = EL_TIMEGATE_CLOSED; - DrawLevelField(x, y); - } + if (MovDelay[x][y]) + return; } + + Feld[x][y] = EL_TIMEGATE_CLOSED; + DrawLevelField(x, y); } static void CloseAllOpenTimegates() @@ -4180,7 +4410,7 @@ void EdelsteinFunkeln(int x, int y) return; if (Feld[x][y] == EL_BD_DIAMOND) - DrawGraphicAnimation(x, y, IMG_BD_DIAMOND); + DrawLevelElementAnimation(x, y, el2img(Feld[x][y])); else { if (!MovDelay[x][y]) /* next animation frame */ @@ -4193,7 +4423,11 @@ void EdelsteinFunkeln(int x, int y) if (setup.direct_draw && MovDelay[x][y]) SetDrawtoField(DRAW_BUFFERED); +#if 0 DrawGraphic(SCREENX(x), SCREENY(y), el2img(Feld[x][y]), 0); +#else + DrawLevelElementAnimation(x, y, Feld[x][y]); +#endif if (MovDelay[x][y]) { @@ -4417,67 +4651,109 @@ void CheckForDragon(int x, int y) } } +static void InitBuggyBase(int x, int y) +{ + int element = Feld[x][y]; + int activating_delay = FRAMES_PER_SECOND / 4; + + MovDelay[x][y] = + (element == EL_SP_BUGGY_BASE ? + 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND) - activating_delay : + element == EL_SP_BUGGY_BASE_ACTIVATING ? + activating_delay : + element == EL_SP_BUGGY_BASE_ACTIVE ? + 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND) : 1); +} + +static void WarnBuggyBase(int x, int y) +{ + int i; + static int xy[4][2] = + { + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } + }; + + 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_BUGGY_BASE_ACTIVE); + + break; + } + } +} + static void CheckBuggyBase(int x, int y) { int element = Feld[x][y]; if (element == EL_SP_BUGGY_BASE) { - if (!MovDelay[x][y]) /* wait some time before activating base */ - MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); + if (MovDelay[x][y] == 0) /* wait some time before activating base */ + { + GfxFrame[x][y] = 0; - if (MovDelay[x][y]) + InitBuggyBase(x, y); + } + + MovDelay[x][y]--; + + if (MovDelay[x][y] != 0) { - MovDelay[x][y]--; - if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y))) - DrawGraphic(SCREENX(x), SCREENY(y), IMG_SP_BUGGY_BASE, 0); - if (MovDelay[x][y]) - return; + DrawLevelElementAnimation(x, y, element); + } + else + { + Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVATING; + DrawLevelField(x, y); + } + } + else if (element == EL_SP_BUGGY_BASE_ACTIVATING) + { + if (MovDelay[x][y] == 0) /* display activation warning of buggy base */ + { + GfxFrame[x][y] = 0; + + InitBuggyBase(x, y); + } + + MovDelay[x][y]--; + if (MovDelay[x][y] != 0) + { + DrawLevelElementAnimation(x, y, element); + } + else + { Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVE; + DrawLevelField(x, y); } } else if (element == EL_SP_BUGGY_BASE_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]) + if (MovDelay[x][y] == 0) /* start activating buggy 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))) - { - int graphic = IMG_SP_BUGGY_BASE_ACTIVE; - int frame = getGraphicAnimationFrame(graphic, SimpleRND(100)); - - DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); - } + GfxFrame[x][y] = 0; - for (i=0; i<4; i++) - { - int xx = x + xy[i][0], yy = y + xy[i][1]; + InitBuggyBase(x, y); + } - if (IS_PLAYER(xx, yy)) - { - PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVE); - break; - } - } + MovDelay[x][y]--; - return; - } + if (MovDelay[x][y] != 0) + { + DrawLevelElementAnimation(x, y, element); + WarnBuggyBase(x, y); + } + else + { Feld[x][y] = EL_SP_BUGGY_BASE; DrawLevelField(x, y); } @@ -4490,15 +4766,17 @@ static void CheckTrap(int x, int y) if (element == EL_TRAP) { - if (!MovDelay[x][y]) /* wait some time before activating trap */ + if (MovDelay[x][y] == 0) /* wait some time before activating trap */ MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); - if (MovDelay[x][y]) - { - MovDelay[x][y]--; - if (MovDelay[x][y]) - return; + MovDelay[x][y]--; + if (MovDelay[x][y] != 0) + { + /* do nothing while waiting */ + } + else + { Feld[x][y] = EL_TRAP_ACTIVE; PlaySoundLevel(x, y, SND_TRAP_ACTIVATING); } @@ -4508,36 +4786,28 @@ static void CheckTrap(int x, int y) int delay = 4; int num_frames = 8; - if (!MovDelay[x][y]) /* start activating trap */ - MovDelay[x][y] = num_frames * delay; - - if (MovDelay[x][y]) + if (MovDelay[x][y] == 0) /* start activating trap */ { - MovDelay[x][y]--; - - if (MovDelay[x][y]) - { - if (!(MovDelay[x][y] % delay)) - { - if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) - { - int graphic = IMG_TRAP_ACTIVE; - int frame = getGraphicAnimationFrame(graphic, 31 - MovDelay[x][y]); - - DrawGraphic(SCREENX(x),SCREENY(y), graphic, frame); - DrawCrumbledSand(SCREENX(x), SCREENY(y)); - } - } + MovDelay[x][y] = num_frames * delay; + GfxFrame[x][y] = 0; + } - return; - } + MovDelay[x][y]--; + if (MovDelay[x][y] != 0) + { + if (DrawLevelElementAnimation(x, y, element)) + DrawCrumbledSand(SCREENX(x), SCREENY(y)); + } + else + { Feld[x][y] = EL_TRAP; DrawLevelField(x, y); } } } +#if 0 static void DrawBeltAnimation(int x, int y, int element) { int belt_nr = getBeltNrFromBeltActiveElement(element); @@ -4545,12 +4815,43 @@ static void DrawBeltAnimation(int x, int y, int element) if (belt_dir != MV_NO_MOVING) { - int graphic = el2img(element); - - DrawGraphicAnimation(x, y, graphic); + DrawLevelElementAnimation(x, y, element); if (!(FrameCounter % 2)) - PlaySoundLevel(x, y, SND_CONVEYOR_BELT_ACTIVE); + PlaySoundLevelAction(x, y, SND_ACTION_ACTIVE); + } +} +#endif + +static void ChangeElement(int x, int y) +{ + int element = Feld[x][y]; + + if (MovDelay[x][y] == 0) /* initialize element change */ + { + MovDelay[x][y] = changing_element[element].change_delay + 1; + GfxFrame[x][y] = 0; + + if (changing_element[element].pre_change_function) + changing_element[element].pre_change_function(x, y); + } + + MovDelay[x][y]--; + + if (MovDelay[x][y] != 0) /* continue element change */ + { + DrawLevelElementAnimation(x, y, element); + + if (changing_element[element].change_function) + changing_element[element].change_function(x, y); + } + else /* finish element change */ + { + Feld[x][y] = changing_element[element].next_element; + DrawLevelField(x, y); + + if (changing_element[element].post_change_function) + changing_element[element].post_change_function(x, y); } } @@ -4700,7 +5001,7 @@ void GameActions() static unsigned long action_delay = 0; unsigned long action_delay_value; int sieb_x = 0, sieb_y = 0; - int i, x, y, element; + int i, x, y, element, graphic; byte *recorded_player_action; byte summarized_player_action = 0; @@ -4804,8 +5105,6 @@ void GameActions() #endif #endif - - FrameCounter++; TimeFrames++; @@ -4815,6 +5114,8 @@ void GameActions() if (JustStopped[x][y] > 0) JustStopped[x][y]--; + GfxFrame[x][y]++; + #if DEBUG if (IS_BLOCKED(x, y)) { @@ -4835,24 +5136,54 @@ void GameActions() for (y=0; y 1) + DrawLevelGraphicAnimation(x, y, graphic); +#endif + continue; + } if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element))) { StartMoving(x, y); +#if 1 + if (Feld[x][y] == EL_EMERALD && + new_graphic_info[graphic].anim_frames > 1 && + !IS_MOVING(x, y)) + DrawLevelGraphicAnimation(x, y, graphic); +#endif + if (IS_GEM(element) || element == EL_SP_INFOTRON) EdelsteinFunkeln(x, y); } + +#if 1 + else if ((element == EL_ACID || + element == EL_EXIT_OPEN || + element == EL_SP_EXIT_OPEN || + element == EL_SP_TERMINAL || + element == EL_SP_TERMINAL_ACTIVE || + element == EL_EXTRA_TIME || + element == EL_SHIELD_NORMAL || + element == EL_SHIELD_DEADLY) && + new_graphic_info[graphic].anim_frames > 1) + DrawLevelGraphicAnimation(x, y, graphic); +#endif + else if (IS_MOVING(x, y)) ContinueMoving(x, y); else if (IS_ACTIVE_BOMB(element)) 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); @@ -4870,25 +5201,23 @@ void GameActions() RobotWheel(x, y); else if (element == EL_TIMEGATE_SWITCH_ACTIVE) TimegateWheel(x, y); - else if (element == EL_ACID) - Blubber(x, y); 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); - else if (element == EL_EXIT_OPEN) - AusgangstuerBlinken(x, y); - else if (element == EL_SP_EXIT_OPEN) - ; /* !!! ADD SOME (OPTIONAL) ANIMATIONS HERE !!! */ +#endif else if (element == EL_WALL_GROWING_ACTIVE) MauerWaechst(x, y); else if (element == EL_WALL_GROWING || @@ -4898,21 +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); - else if (element == EL_SP_TERMINAL) - DrawGraphicAnimation(x, y, IMG_SP_TERMINAL); - else if (element == EL_SP_TERMINAL_ACTIVE) - { - DrawGraphicAnimation(x, y, IMG_SP_TERMINAL_ACTIVE); - #if 0 - if (!(FrameCounter % 4)) - PlaySoundLevel(x, y, SND_SP_TERMINAL_ACTIVE); -#endif - } else if (IS_BELT_ACTIVE(element)) DrawBeltAnimation(x, y, element); else if (element == EL_SWITCHGATE_OPENING) @@ -4923,26 +5244,18 @@ void GameActions() OpenTimegate(x, y); else if (element == EL_TIMEGATE_CLOSING) CloseTimegate(x, y); - else if (element == EL_EXTRA_TIME) - DrawGraphicAnimation(x, y, IMG_EXTRA_TIME); - else if (element == EL_SHIELD_NORMAL) - { - DrawGraphicAnimation(x, y, IMG_SHIELD_NORMAL); - -#if 0 - if (!(FrameCounter % 4)) - PlaySoundLevel(x, y, SND_SHIELD_PASSIVE_ACTIVATED); #endif - } - else if (element == EL_SHIELD_DEADLY) - { - DrawGraphicAnimation(x, y, IMG_SHIELD_DEADLY); -#if 0 - if (!(FrameCounter % 4)) - PlaySoundLevel(x, y, SND_SHIELD_DEADLY_ACTIVE); + else if (IS_AUTO_CHANGING(element)) + ChangeElement(x, y); + +#if 1 + else if (new_graphic_info[graphic].anim_frames > 1) + DrawLevelGraphicAnimation(x, y, graphic); #endif - } + + if (IS_BELT_ACTIVE(element)) + PlaySoundLevelAction(x, y, SND_ACTION_ACTIVE); if (game.magic_wall_active) { @@ -5024,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; } @@ -5354,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 */ @@ -5940,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; @@ -6044,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; } @@ -6062,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; } @@ -6218,13 +6533,13 @@ int DigField(struct PlayerInfo *player, else { RemoveField(x, y); - Feld[x+dx][y+dy] = element; + Feld[x + dx][y + dy] = element; } if (element == EL_SPRING) { - Feld[x+dx][y+dy] = EL_SPRING_MOVING; - MovDir[x+dx][y+dy] = move_direction; + Feld[x + dx][y + dy] = EL_SPRING; + MovDir[x + dx][y + dy] = move_direction; } player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8)); @@ -6810,7 +7125,7 @@ void CreateGameButtons() for (i=0; i