X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame.c;h=533119c92b368df93d484018f33fd3d2b35a7b42;hb=7b47ce7ba0f673f0de5130daf5726104d0b38902;hp=17473731b737bf0b128d41559df8682fb5d84eb5;hpb=14089dac2cbe56e563863e1e5adb8847944fd262;p=rocksndiamonds.git diff --git a/src/game.c b/src/game.c index 17473731..533119c9 100644 --- a/src/game.c +++ b/src/game.c @@ -105,56 +105,87 @@ static void CloseAllOpenTimegates(void); static void CheckGravityMovement(struct PlayerInfo *); static void KillHeroUnlessProtected(int, int); -void PlaySoundLevel(int, int, int); -void PlaySoundLevelAction(int, int, int); -void PlaySoundLevelElementAction(int, int, int, int); +static void PlaySoundLevel(int, int, int); +static void PlaySoundLevelNearest(int, int, int); +static void PlaySoundLevelAction(int, int, int); +static void PlaySoundLevelElementAction(int, int, int, int); static void MapGameButtons(); static void HandleGameButtons(struct GadgetInfo *); static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS]; -#define SND_ACTION_UNKNOWN 0 -#define SND_ACTION_WAITING 1 -#define SND_ACTION_MOVING 2 -#define SND_ACTION_DIGGING 3 -#define SND_ACTION_COLLECTING 4 -#define SND_ACTION_PASSING 5 -#define SND_ACTION_IMPACT 6 -#define SND_ACTION_PUSHING 7 -#define SND_ACTION_ACTIVATING 8 -#define SND_ACTION_ACTIVE 9 +#define IS_ANIMATED(g) (graphic_info[g].anim_frames > 1) +#define IS_LOOP_SOUND(s) (sound_info[s].loop) -#define NUM_SND_ACTIONS 10 -static struct +/* ------------------------------------------------------------------------- + definition of elements that automatically change to other elements after + a specified time, eventually calling a function when changing + ------------------------------------------------------------------------- */ + +/* forward declaration for changer functions */ +static void InitBuggyBase(int x, int y); +static void WarnBuggyBase(int x, int y); + +static void InitTrap(int x, int y); +static void ActivateTrap(int x, int y); +static void ChangeActiveTrap(int x, int y); + +static void InitRobotWheel(int x, int y); +static void RunRobotWheel(int x, int y); +static void StopRobotWheel(int x, int y); + +static void InitTimegateWheel(int x, int y); +static void RunTimegateWheel(int x, int y); + +struct ChangingElementInfo { - char *text; - int value; - boolean is_loop; -} sound_action_properties[] = + 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[] = { - /* insert _all_ loop sound actions here */ - { ".waiting", SND_ACTION_WAITING, TRUE }, - { ".moving", SND_ACTION_MOVING, TRUE }, /* continuos moving */ - { ".active", SND_ACTION_ACTIVE, TRUE }, - { ".growing", SND_ACTION_UNKNOWN, TRUE }, - { ".attacking", SND_ACTION_UNKNOWN, TRUE }, - - /* other (non-loop) sound actions are optional */ - { ".stepping", SND_ACTION_MOVING, FALSE }, /* discrete moving */ - { ".digging", SND_ACTION_DIGGING, FALSE }, - { ".collecting", SND_ACTION_COLLECTING, FALSE }, - { ".passing", SND_ACTION_PASSING, FALSE }, - { ".impact", SND_ACTION_IMPACT, FALSE }, - { ".pushing", SND_ACTION_PUSHING, FALSE }, - { ".activating", SND_ACTION_ACTIVATING, FALSE }, - { NULL, 0, 0 }, + { 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_SP_BUGGY_BASE, EL_SP_BUGGY_BASE_ACTIVATING, 0, + InitBuggyBase, NULL, NULL }, + { EL_SP_BUGGY_BASE_ACTIVATING,EL_SP_BUGGY_BASE_ACTIVE, 0, + InitBuggyBase, NULL, NULL }, + { EL_SP_BUGGY_BASE_ACTIVE, EL_SP_BUGGY_BASE, 0, + InitBuggyBase, WarnBuggyBase, NULL }, + + { EL_TRAP, EL_TRAP_ACTIVE, 0, + InitTrap, NULL, ActivateTrap }, + { EL_TRAP_ACTIVE, EL_TRAP, 31, + NULL, ChangeActiveTrap, NULL }, + + { EL_ROBOT_WHEEL_ACTIVE, EL_ROBOT_WHEEL, 0, + InitRobotWheel, RunRobotWheel, StopRobotWheel }, + + { EL_TIMEGATE_SWITCH_ACTIVE, EL_TIMEGATE_SWITCH, 0, + InitTimegateWheel, RunTimegateWheel, NULL }, + + { EL_UNDEFINED, EL_UNDEFINED, -1, NULL } }; -static int element_action_sound[MAX_NUM_ELEMENTS][NUM_SND_ACTIONS]; -static boolean is_loop_sound[NUM_SOUND_FILES]; -#define IS_LOOP_SOUND(x) (is_loop_sound[x]) +static struct ChangingElementInfo changing_element[MAX_NUM_ELEMENTS]; + +#define IS_AUTO_CHANGING(e) (changing_element[e].base_element != EL_UNDEFINED) + #ifdef DEBUG @@ -192,7 +223,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]; @@ -501,96 +532,6 @@ void DrawGameDoorValues() } -/* - ============================================================================= - InitGameSound() - ----------------------------------------------------------------------------- - initialize sound effect lookup table for element actions - ============================================================================= -*/ - -void InitGameSound() -{ - int sound_effect_properties[NUM_SOUND_FILES]; - int i, j; - -#if 0 - debug_print_timestamp(0, NULL); -#endif - - 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++; } } @@ -797,12 +765,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] = ACTION_DEFAULT; } } @@ -974,7 +944,7 @@ void InitGame() FadeToFront(); /* copy default game door content to main double buffer */ - BlitBitmap(new_graphic_info[IMG_MENU_DOOR].bitmap, drawto, + BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto, DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY); if (level_nr < 100) @@ -1337,6 +1307,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; @@ -1344,9 +1317,9 @@ void InitMovingField(int x, int y, int direction) Feld[newx][newy] = EL_BLOCKED; if (direction == MV_DOWN && CAN_FALL(element)) - GfxAction[x][y] = GFX_ACTION_FALLING; + GfxAction[x][y] = ACTION_FALLING; else - GfxAction[x][y] = GFX_ACTION_MOVING; + GfxAction[x][y] = ACTION_MOVING; } void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y) @@ -1457,7 +1430,7 @@ void RemoveMovingField(int x, int y) Feld[newx][newy] = EL_EMPTY; MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0; MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0; - GfxAction[oldx][oldy] = GfxAction[newx][newy] = GFX_ACTION_DEFAULT; + GfxAction[oldx][oldy] = GfxAction[newx][newy] = ACTION_DEFAULT; DrawLevelField(oldx, oldy); DrawLevelField(newx, newy); @@ -1475,14 +1448,10 @@ void DrawDynamite(int x, int y) if (Store[x][y]) DrawGraphic(sx, sy, el2img(Store[x][y]), 0); - frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[x][y]); - - /* - printf("-> %d: %d [%d]\n", graphic, frame, MovDelay[x][y]); - */ + frame = getGraphicAnimationFrame(graphic, GfxFrame[x][y]); if (game.emulation == EMU_SUPAPLEX) - DrawGraphic(sx, sy, IMG_SP_DISK_RED, 0); + DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame); else if (Store[x][y]) DrawGraphicThruMask(sx, sy, graphic, frame); else @@ -1491,21 +1460,18 @@ void DrawDynamite(int x, int y) void CheckDynamite(int x, int y) { - if (MovDelay[x][y]) /* dynamite is still waiting to explode */ + int element = Feld[x][y]; + + if (MovDelay[x][y] != 0) /* dynamite is still waiting to explode */ { MovDelay[x][y]--; - if (MovDelay[x][y]) - { - if (!(MovDelay[x][y] % 6)) - PlaySoundLevelAction(x, y, SND_ACTION_ACTIVE); - if (IS_ACTIVE_BOMB(Feld[x][y])) - { - int delay = (Feld[x][y] == EL_DYNAMITE_ACTIVE ? 12 : 6); + if (MovDelay[x][y] != 0) + { + if (checkDrawLevelGraphicAnimation(x, y, el2img(element))) + DrawDynamite(x, y); - if (!(MovDelay[x][y] % delay)) - DrawDynamite(x, y); - } + PlaySoundLevelAction(x, y, ACTION_ACTIVE); return; } @@ -1652,7 +1618,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; } @@ -1668,7 +1634,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) { @@ -1915,9 +1881,9 @@ static void InitBeltMovement() int graphic = el2img(element); if (game.belt_dir[i] == MV_LEFT) - new_graphic_info[graphic].anim_mode &= ~ANIM_REVERSE; + graphic_info[graphic].anim_mode &= ~ANIM_REVERSE; else - new_graphic_info[graphic].anim_mode |= ANIM_REVERSE; + graphic_info[graphic].anim_mode |= ANIM_REVERSE; } } @@ -1999,9 +1965,9 @@ static void ToggleBeltSwitch(int x, int y) int graphic = el2img(element); if (belt_dir == MV_LEFT) - new_graphic_info[graphic].anim_mode &= ~ANIM_REVERSE; + graphic_info[graphic].anim_mode &= ~ANIM_REVERSE; else - new_graphic_info[graphic].anim_mode |= ANIM_REVERSE; + graphic_info[graphic].anim_mode |= ANIM_REVERSE; } for (yy=0; yy=0 && ZY>=0) + if (element == EL_ROBOT && ZX >= 0 && ZY >= 0) { attr_x = ZX; attr_y = ZY; @@ -2814,7 +2787,7 @@ void StartMoving(int x, int y) if (Stop[x][y]) return; - GfxAction[x][y] = GFX_ACTION_DEFAULT; + GfxAction[x][y] = ACTION_DEFAULT; if (CAN_FALL(element) && y < lev_fieldy - 1) { @@ -3009,7 +2982,7 @@ void StartMoving(int x, int y) InitMovingField(x, y, belt_dir); started_moving = TRUE; - GfxAction[x][y] = GFX_ACTION_DEFAULT; + GfxAction[x][y] = ACTION_DEFAULT; } } } @@ -3090,7 +3063,7 @@ void StartMoving(int x, int y) } } else if (element == EL_SP_ELECTRON) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_SP_ELECTRON); + DrawLevelElementAnimation(x, y, element); else if (element == EL_DRAGON) { int i; @@ -3137,7 +3110,7 @@ void StartMoving(int x, int y) if (MovDelay[x][y]) /* element still has to wait some time */ { - PlaySoundLevelAction(x, y, SND_ACTION_WAITING); + PlaySoundLevelAction(x, y, ACTION_WAITING); return; } @@ -3348,23 +3321,23 @@ 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(SCREENX(x), SCREENY(y), el2img(element)); + DrawLevelElementAnimation(x, y, element); else if (element == EL_SATELLITE) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_SATELLITE); + DrawLevelElementAnimation(x, y, element); else if (element == EL_SP_ELECTRON) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_SP_ELECTRON); + DrawLevelElementAnimation(x, y, element); if (DONT_TOUCH(element)) TestIfBadThingTouchesHero(x, y); - PlaySoundLevelAction(x, y, SND_ACTION_WAITING); + PlaySoundLevelAction(x, y, ACTION_WAITING); return; } InitMovingField(x, y, MovDir[x][y]); - PlaySoundLevelAction(x, y, SND_ACTION_MOVING); + PlaySoundLevelAction(x, y, ACTION_MOVING); } if (MovDir[x][y]) @@ -3488,7 +3461,7 @@ void ContinueMoving(int x, int y) MovDelay[newx][newy] = 0; GfxAction[newx][newy] = GfxAction[x][y]; /* keep action one frame */ - GfxAction[x][y] = GFX_ACTION_DEFAULT; + GfxAction[x][y] = ACTION_DEFAULT; #if 0 if (!CAN_MOVE(element)) @@ -3526,11 +3499,11 @@ void ContinueMoving(int x, int y) else /* still moving on */ { #if 0 - if (GfxAction[x][y] == GFX_ACTION_DEFAULT) + if (GfxAction[x][y] == ACTION_DEFAULT) { printf("reset GfxAction...\n"); - GfxAction[x][y] = GFX_ACTION_MOVING; + GfxAction[x][y] = ACTION_MOVING; } #endif @@ -4010,6 +3983,23 @@ void Life(int ax, int ay) SND_BIOMAZE_CREATING); } +static void InitRobotWheel(int x, int y) +{ + MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND; +} + +static void RunRobotWheel(int x, int y) +{ + PlaySoundLevel(x, y, SND_ROBOT_WHEEL_ACTIVE); +} + +static void StopRobotWheel(int x, int y) +{ + if (ZX == x && ZY == y) + ZX = ZY = -1; +} + +#if 1 void RobotWheel(int x, int y) { if (!MovDelay[x][y]) /* next animation frame */ @@ -4039,7 +4029,19 @@ void RobotWheel(int x, int y) if (ZX == x && ZY == y) ZX = ZY = -1; } +#endif +static void InitTimegateWheel(int x, int y) +{ + MovDelay[x][y] = level.time_wheel * FRAMES_PER_SECOND; +} + +static void RunTimegateWheel(int x, int y) +{ + PlaySoundLevel(x, y, SND_TIMEGATE_SWITCH_ACTIVE); +} + +#if 1 void TimegateWheel(int x, int y) { if (!MovDelay[x][y]) /* next animation frame */ @@ -4066,11 +4068,17 @@ void TimegateWheel(int x, int y) Feld[x][y] = EL_TIMEGATE_SWITCH; DrawLevelField(x, y); + /* THIS HAS NO EFFECT AT ALL! */ +#if 1 /* !!! THIS LOOKS WRONG !!! */ if (ZX == x && ZY == y) ZX = ZY = -1; +#endif + } +#endif +#if 1 void NussKnacken(int x, int y) { if (!MovDelay[x][y]) /* next animation frame */ @@ -4096,7 +4104,9 @@ void NussKnacken(int x, int y) Feld[x][y] = EL_EMERALD; DrawLevelField(x, y); } +#endif +#if 1 void BreakingPearl(int x, int y) { if (!MovDelay[x][y]) /* next animation frame */ @@ -4122,15 +4132,16 @@ void BreakingPearl(int x, int y) Feld[x][y] = EL_EMPTY; DrawLevelField(x, y); } +#endif void SiebAktivieren(int x, int y, int type) { int graphic = (type == 1 ? IMG_MAGIC_WALL_FULL : IMG_BD_MAGIC_WALL_FULL); - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + DrawLevelGraphicAnimation(x, y, graphic); } -void AusgangstuerPruefen(int x, int y) +void CheckExit(int x, int y) { if (local_player->gems_still_needed > 0 || local_player->sokobanfields_still_needed > 0 || @@ -4139,27 +4150,20 @@ void AusgangstuerPruefen(int x, int y) Feld[x][y] = EL_EXIT_OPENING; - PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) : - (x > LEVELX(BX2) ? LEVELX(BX2) : x), - y < LEVELY(BY1) ? LEVELY(BY1) : - (y > LEVELY(BY2) ? LEVELY(BY2) : y), - SND_EXIT_OPENING); + PlaySoundLevelNearest(x, y, SND_EXIT_OPENING); } -void AusgangstuerPruefen_SP(int x, int y) +void CheckExitSP(int x, int y) { if (local_player->gems_still_needed > 0) return; Feld[x][y] = EL_SP_EXIT_OPEN; - PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) : - (x > LEVELX(BX2) ? LEVELX(BX2) : x), - y < LEVELY(BY1) ? LEVELY(BY1) : - (y > LEVELY(BY2) ? LEVELY(BY2) : y), - SND_SP_EXIT_OPENING); + PlaySoundLevelNearest(x, y, SND_SP_EXIT_OPENING); } +#if 1 void AusgangstuerOeffnen(int x, int y) { int delay = 6; @@ -4192,7 +4196,9 @@ void AusgangstuerOeffnen(int x, int y) Feld[x][y] = EL_EXIT_OPEN; DrawLevelField(x, y); } +#endif +#if 1 void OpenSwitchgate(int x, int y) { int delay = 6; @@ -4222,7 +4228,9 @@ void OpenSwitchgate(int x, int y) Feld[x][y] = EL_SWITCHGATE_OPEN; DrawLevelField(x, y); } +#endif +#if 1 void CloseSwitchgate(int x, int y) { int delay = 6; @@ -4252,7 +4260,9 @@ void CloseSwitchgate(int x, int y) Feld[x][y] = EL_SWITCHGATE_CLOSED; DrawLevelField(x, y); } +#endif +#if 1 void OpenTimegate(int x, int y) { int delay = 6; @@ -4282,7 +4292,9 @@ void OpenTimegate(int x, int y) Feld[x][y] = EL_TIMEGATE_OPEN; DrawLevelField(x, y); } +#endif +#if 1 void CloseTimegate(int x, int y) { int delay = 6; @@ -4312,6 +4324,7 @@ void CloseTimegate(int x, int y) Feld[x][y] = EL_TIMEGATE_CLOSED; DrawLevelField(x, y); } +#endif static void CloseAllOpenTimegates() { @@ -4338,13 +4351,17 @@ void EdelsteinFunkeln(int x, int y) return; if (Feld[x][y] == EL_BD_DIAMOND) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), IMG_BD_DIAMOND); +#if 0 + DrawLevelElementAnimation(x, y, el2img(Feld[x][y])); +#else + return; +#endif else { - if (!MovDelay[x][y]) /* next animation frame */ + if (MovDelay[x][y] == 0) /* next animation frame */ MovDelay[x][y] = 11 * !SimpleRND(500); - if (MovDelay[x][y]) /* wait some time before next frame */ + if (MovDelay[x][y] != 0) /* wait some time before next frame */ { MovDelay[x][y]--; @@ -4354,10 +4371,10 @@ void EdelsteinFunkeln(int x, int y) #if 0 DrawGraphic(SCREENX(x), SCREENY(y), el2img(Feld[x][y]), 0); #else - DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(Feld[x][y])); + DrawLevelElementAnimation(x, y, Feld[x][y]); #endif - if (MovDelay[x][y]) + if (MovDelay[x][y] != 0) { int frame = getGraphicAnimationFrame(IMG_TWINKLE_WHITE, 10 - MovDelay[x][y]); @@ -4579,88 +4596,155 @@ void CheckForDragon(int x, int y) } } -static void CheckBuggyBase(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); +} - if (element == EL_SP_BUGGY_BASE) +static void WarnBuggyBase(int x, int y) +{ + int i; + static int xy[4][2] = { - if (!MovDelay[x][y]) /* wait some time before activating base */ - MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); + { 0, -1 }, + { -1, 0 }, + { +1, 0 }, + { 0, +1 } + }; - if (MovDelay[x][y]) + for (i=0; i<4; i++) + { + int xx = x + xy[i][0], yy = y + xy[i][1]; + + if (IS_PLAYER(xx, yy)) { - 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; + PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVE); - Feld[x][y] = EL_SP_BUGGY_BASE_ACTIVE; + break; } } - else if (element == EL_SP_BUGGY_BASE_ACTIVE) +} + +#if 1 +void CheckBuggyBase(int x, int y) +{ + int element = Feld[x][y]; + + if (element == EL_SP_BUGGY_BASE) { - if (!MovDelay[x][y]) /* start activating buggy base */ - MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * 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]) - { - int i; - static int xy[4][2] = - { - { 0, -1 }, - { -1, 0 }, - { +1, 0 }, - { 0, +1 } - }; + 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; - if (IN_SCR_FIELD(SCREENX(x), SCREENY(y))) - { - int graphic = IMG_SP_BUGGY_BASE_ACTIVE; - int frame = getGraphicAnimationFrame(graphic, SimpleRND(100)); + InitBuggyBase(x, y); + } - DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame); - } + MovDelay[x][y]--; - for (i=0; i<4; i++) - { - int xx = x + xy[i][0], yy = y + xy[i][1]; + 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] == 0) /* start activating buggy base */ + { + GfxFrame[x][y] = 0; - if (IS_PLAYER(xx, yy)) - { - PlaySoundLevel(x, y, SND_SP_BUGGY_BASE_ACTIVE); - break; - } - } + InitBuggyBase(x, y); + } - return; - } + MovDelay[x][y]--; + if (MovDelay[x][y] != 0) + { + DrawLevelElementAnimation(x, y, element); + + WarnBuggyBase(x, y); + } + else + { Feld[x][y] = EL_SP_BUGGY_BASE; DrawLevelField(x, y); } } } +#endif + +static void InitTrap(int x, int y) +{ + MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND); +} + +static void ActivateTrap(int x, int y) +{ + PlaySoundLevel(x, y, SND_TRAP_ACTIVATING); +} -static void CheckTrap(int x, int y) +static void ChangeActiveTrap(int x, int y) +{ + int graphic = IMG_TRAP_ACTIVE; + + /* if animation frame already drawn, correct crumbled sand border */ + if (IS_ANIMATED(graphic)) + if (checkDrawLevelGraphicAnimation(x, y, graphic)) + DrawCrumbledSand(SCREENX(x), SCREENY(y)); +} + +#if 1 +void CheckTrap(int x, int y) { int element = Feld[x][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); } @@ -4670,36 +4754,29 @@ 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); } } } +#endif +#if 1 static void DrawBeltAnimation(int x, int y, int element) { int belt_nr = getBeltNrFromBeltActiveElement(element); @@ -4707,12 +4784,46 @@ static void DrawBeltAnimation(int x, int y, int element) if (belt_dir != MV_NO_MOVING) { - int graphic = el2img(element); - - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + DrawLevelElementAnimation(x, y, element); if (!(FrameCounter % 2)) - PlaySoundLevel(x, y, SND_CONVEYOR_BELT_ACTIVE); + PlaySoundLevelAction(x, y, 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 */ + { + if (IS_ANIMATED(el2img(element))) + 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; + GfxFrame[x][y] = 0; + + DrawLevelField(x, y); + + if (changing_element[element].post_change_function) + changing_element[element].post_change_function(x, y); } } @@ -4975,6 +5086,8 @@ void GameActions() if (JustStopped[x][y] > 0) JustStopped[x][y]--; + GfxFrame[x][y]++; + #if DEBUG if (IS_BLOCKED(x, y)) { @@ -5001,8 +5114,8 @@ void GameActions() { #if 1 - if (new_graphic_info[graphic].anim_frames > 1) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + if (IS_ANIMATED(graphic)) + DrawLevelGraphicAnimation(x, y, graphic); #endif continue; @@ -5013,10 +5126,16 @@ void GameActions() StartMoving(x, y); #if 1 +#if 0 if (Feld[x][y] == EL_EMERALD && - new_graphic_info[graphic].anim_frames > 1 && + IS_ANIMATED(graphic) && + !IS_MOVING(x, y)) + DrawLevelGraphicAnimation(x, y, graphic); +#else + if (IS_ANIMATED(graphic) && !IS_MOVING(x, y)) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + DrawLevelGraphicAnimation(x, y, graphic); +#endif #endif if (IS_GEM(element) || element == EL_SP_INFOTRON) @@ -5032,8 +5151,8 @@ void GameActions() element == EL_EXTRA_TIME || element == EL_SHIELD_NORMAL || element == EL_SHIELD_DEADLY) && - new_graphic_info[graphic].anim_frames > 1) - DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic); + IS_ANIMATED(graphic)) + DrawLevelGraphicAnimation(x, y, graphic); #endif else if (IS_MOVING(x, y)) @@ -5042,7 +5161,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); @@ -5056,23 +5175,29 @@ void GameActions() else if (element == EL_GAMEOFLIFE || element == EL_BIOMAZE) Life(x, y); +#if 0 else if (element == EL_ROBOT_WHEEL_ACTIVE) RobotWheel(x, y); else if (element == EL_TIMEGATE_SWITCH_ACTIVE) TimegateWheel(x, y); +#endif 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); + CheckExit(x, y); else if (element == EL_SP_EXIT_CLOSED) - AusgangstuerPruefen_SP(x, y); + CheckExitSP(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 || @@ -5082,9 +5207,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) +#if 0 + 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) + else if (element == EL_TRAP || + element == EL_TRAP_ACTIVE) CheckTrap(x, y); else if (IS_BELT_ACTIVE(element)) DrawBeltAnimation(x, y, element); @@ -5096,12 +5225,21 @@ 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); + else if (element == EL_EXPLOSION) + ; /* drawing of correct explosion animation is handled separately */ + else if (IS_ANIMATED(graphic)) + DrawLevelGraphicAnimation(x, y, graphic); #endif + if (IS_BELT_ACTIVE(element)) + PlaySoundLevelAction(x, y, ACTION_ACTIVE); + if (game.magic_wall_active) { boolean sieb = FALSE; @@ -5182,7 +5320,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; } @@ -6099,8 +6237,9 @@ 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); + PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING); break; case EL_EMERALD: @@ -6122,7 +6261,7 @@ int DigField(struct PlayerInfo *player, DrawText(DX_EMERALDS, DY_EMERALDS, int2str(local_player->gems_still_needed, 3), FS_SMALL, FC_YELLOW); - PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING); + PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING); break; case EL_SPEED_PILL: @@ -6167,7 +6306,7 @@ int DigField(struct PlayerInfo *player, DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW); - PlaySoundLevelElementAction(x, y, element, SND_ACTION_COLLECTING); + PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING); break; case EL_DYNABOMB_NR: @@ -6389,7 +6528,7 @@ int DigField(struct PlayerInfo *player, player->push_delay_value = (element == EL_SPRING ? 0 : 2 + RND(8)); DrawLevelField(x + dx, y + dy); - PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING); + PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); break; case EL_GATE1: @@ -6449,7 +6588,7 @@ int DigField(struct PlayerInfo *player, player->programmed_action = move_direction; DOUBLE_PLAYER_SPEED(player); - PlaySoundLevelElementAction(x, y, element, SND_ACTION_PASSING); + PlaySoundLevelElementAction(x, y, element, ACTION_PASSING); break; case EL_SP_PORT1_LEFT: @@ -6647,7 +6786,7 @@ int DigField(struct PlayerInfo *player, { RemoveField(x, y); Feld[x+dx][y+dy] = element; - PlaySoundLevelElementAction(x, y, element, SND_ACTION_PUSHING); + PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING); } player->push_delay_value = (element == EL_BALLOON ? 0 : 2); @@ -6734,11 +6873,14 @@ boolean PlaceBomb(struct PlayerInfo *player) if (element != EL_EMPTY) Store[jx][jy] = element; + MovDelay[jx][jy] = 96; + GfxFrame[jx][jy] = 0; + if (player->dynamite) { Feld[jx][jy] = EL_DYNAMITE_ACTIVE; - MovDelay[jx][jy] = 96; player->dynamite--; + DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW); if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) @@ -6755,8 +6897,8 @@ boolean PlaceBomb(struct PlayerInfo *player) { Feld[jx][jy] = EL_DYNABOMB_PLAYER1_ACTIVE + (player->element_nr - EL_PLAYER1); - MovDelay[jx][jy] = 96; player->dynabombs_left--; + if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy))) DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0); @@ -6766,7 +6908,7 @@ boolean PlaceBomb(struct PlayerInfo *player) return TRUE; } -void PlaySoundLevel(int x, int y, int nr) +static void PlaySoundLevel(int x, int y, int nr) { static int loop_sound_frame[NUM_SOUND_FILES]; static int loop_sound_volume[NUM_SOUND_FILES]; @@ -6813,16 +6955,26 @@ void PlaySoundLevel(int x, int y, int nr) PlaySoundExt(nr, volume, stereo_position, type); } -void PlaySoundLevelAction(int x, int y, int sound_action) +static void PlaySoundLevelNearest(int x, int y, int sound_action) +{ + PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) : + x > LEVELX(BX2) ? LEVELX(BX2) : x, + y < LEVELY(BY1) ? LEVELY(BY1) : + y > LEVELY(BY2) ? LEVELY(BY2) : y, + sound_action); +} + +static void PlaySoundLevelAction(int x, int y, int sound_action) { PlaySoundLevelElementAction(x, y, Feld[x][y], sound_action); } -void PlaySoundLevelElementAction(int x, int y, int element, int sound_action) +static void PlaySoundLevelElementAction(int x, int y, int element, + int sound_action) { - int sound_effect = element_action_sound[element][sound_action]; + int sound_effect = element_info[element].sound[sound_action]; - if (sound_effect != -1) + if (sound_effect != SND_UNDEFINED) PlaySoundLevel(x, y, sound_effect); } @@ -6969,7 +7121,7 @@ void CreateGameButtons() for (i=0; i