+void TestIfBadThingHitsGoodThing(int badx, int bady)
+{
+ int i, killx = badx, killy = bady;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int harmless[4] =
+ {
+ MV_UP,
+ MV_LEFT,
+ MV_RIGHT,
+ MV_DOWN
+ };
+
+ for (i=0; i<4; i++)
+ {
+ int x, y, element;
+
+ x = badx + xy[i][0];
+ y = bady + xy[i][1];
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+ element = Feld[x][y];
+
+ if (IS_PLAYER(x, y))
+ {
+ killx = x;
+ killy = y;
+ break;
+ }
+ else if (element == EL_PINGUIN)
+ {
+ if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
+ continue;
+
+ killx = x;
+ killy = y;
+ break;
+ }
+ }
+
+ if (killx != badx || killy != bady)
+ {
+ if (IS_PLAYER(killx, killy))
+ KillHero(PLAYERINFO(killx, killy));
+ else
+ Bang(killx, killy);
+ }
+}
+
+void TestIfHeroHitsBadThing(int x, int y)
+{
+ TestIfGoodThingHitsBadThing(x, y);
+}
+
+void TestIfBadThingHitsHero(int x, int y)
+{
+ TestIfBadThingHitsGoodThing(x, y);
+}
+
+void TestIfFriendHitsBadThing(int x, int y)
+{
+ TestIfGoodThingHitsBadThing(x, y);
+}
+
+void TestIfBadThingHitsFriend(int x, int y)
+{
+ TestIfBadThingHitsGoodThing(x, y);
+}
+
+void TestIfBadThingHitsOtherBadThing(int badx, int bady)
+{
+ int i, killx = badx, killy = bady;
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
+ for (i=0; i<4; i++)
+ {
+ int x, y, element;
+
+ x=badx + xy[i][0];
+ y=bady + xy[i][1];
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+ element = Feld[x][y];
+ if (IS_AMOEBOID(element) || element == EL_LIFE ||
+ element == EL_AMOEBING || element == EL_TROPFEN)
+ {
+ killx = x;
+ killy = y;
+ break;
+ }
+ }
+
+ if (killx != badx || killy != bady)
+ Bang(badx, bady);
+}
+
+void KillHero(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+
+ if (player->gone)
+ return;
+
+ if (IS_PFORTE(Feld[jx][jy]))
+ Feld[jx][jy] = EL_LEERRAUM;
+
+ Bang(jx, jy);
+ BuryHero(player);
+}
+
+void BuryHero(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+
+ if (player->gone)
+ return;
+
+ PlaySoundLevel(jx, jy, SND_AUTSCH);
+ PlaySoundLevel(jx, jy, SND_LACHEN);
+
+ player->GameOver = TRUE;
+ RemoveHero(player);
+}
+
+void RemoveHero(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+ int i, found = FALSE;
+
+ player->gone = TRUE;
+ StorePlayer[jx][jy] = 0;
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ if (stored_player[i].active && !stored_player[i].gone)
+ found = TRUE;
+
+ if (!found)
+ AllPlayersGone = TRUE;
+
+ ExitX = ZX = jx;
+ ExitY = ZY = jy;
+}
+
+int DigField(struct PlayerInfo *player,
+ int x, int y, int real_dx, int real_dy, int mode)
+{
+ int jx = player->jx, jy = player->jy;
+ int dx = x - jx, dy = y - jy;
+ int element;
+
+ if (!player->MovPos)
+ player->Pushing = FALSE;
+
+ if (mode == DF_NO_PUSH)
+ {
+ player->push_delay = 0;
+ return MF_NO_ACTION;
+ }
+
+ if (IS_MOVING(x, y) || IS_PLAYER(x, y))
+ return MF_NO_ACTION;
+
+ element = Feld[x][y];
+
+ 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:
+ case EL_EDELSTEIN_BD:
+ case EL_EDELSTEIN_GELB:
+ 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)
+ local_player->gems_still_needed = 0;
+ RaiseScoreElement(element);
+ 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);
+ MoveSpeed = 4;
+ ScrollStepSize = TILEX/4;
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNAMIT_AUS:
+ case EL_SP_DISK_RED:
+ RemoveField(x, y);
+ player->dynamite++;
+ RaiseScoreElement(EL_DYNAMIT);
+ DrawText(DX_DYNAMITE, DY_DYNAMITE,
+ int2str(local_player->dynamite, 3),
+ FS_SMALL, FC_YELLOW);
+ if (element == EL_SP_DISK_RED)
+ PlaySoundLevel(x, y, SND_SP_INFOTRON);
+ else
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_NR:
+ RemoveField(x, y);
+ player->dynabomb_count++;
+ player->dynabombs_left++;
+ RaiseScoreElement(EL_DYNAMIT);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_SZ:
+ RemoveField(x, y);
+ player->dynabomb_size++;
+ RaiseScoreElement(EL_DYNAMIT);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_XL:
+ RemoveField(x, y);
+ player->dynabomb_xl = TRUE;
+ RaiseScoreElement(EL_DYNAMIT);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_SCHLUESSEL1:
+ case EL_SCHLUESSEL2:
+ case EL_SCHLUESSEL3:
+ case EL_SCHLUESSEL4:
+ {
+ 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_ABLENK_AUS:
+ Feld[x][y] = EL_ABLENK_EIN;
+ ZX = x;
+ ZY = y;
+ DrawLevelField(x, y);
+ return MF_ACTION;
+ break;
+
+ case EL_SP_TERMINAL:
+ {
+ int xx, yy;
+
+ for (yy=0; yy<lev_fieldy; yy++)
+ {
+ for (xx=0; xx<lev_fieldx; xx++)
+ {
+ if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
+ Bang(xx, yy);
+ else if (Feld[xx][yy] == EL_SP_TERMINAL)
+ Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
+ }
+ }
+
+ return MF_ACTION;
+ }
+ break;
+
+ case EL_SP_EXIT:
+ if (local_player->gems_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;
+
+ player->Pushing = TRUE;
+
+ if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
+ return MF_NO_ACTION;
+
+ if (real_dy)
+ {
+ if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
+ return MF_NO_ACTION;
+ }
+
+ if (player->push_delay == 0)
+ player->push_delay = FrameCounter;
+ if (!FrameReached(&player->push_delay, player->push_delay_value) &&
+ !tape.playing)
+ return MF_NO_ACTION;
+
+ RemoveField(x, y);
+ Feld[x+dx][y+dy] = element;
+
+ player->push_delay_value = 2+RND(8);
+
+ DrawLevelField(x+dx, y+dy);
+ if (element == EL_FELSBROCKEN)
+ 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;
+
+ case EL_PFORTE1:
+ case EL_PFORTE2:
+ case EL_PFORTE3:
+ case EL_PFORTE4:
+ if (!player->key[element-EL_PFORTE1])
+ return MF_NO_ACTION;
+ break;
+
+ case EL_PFORTE1X:
+ case EL_PFORTE2X:
+ case EL_PFORTE3X:
+ case EL_PFORTE4X:
+ if (!player->key[element-EL_PFORTE1X])
+ return MF_NO_ACTION;
+ break;
+
+ case EL_SP_PORT1_LEFT:
+ case EL_SP_PORT2_LEFT:
+ case EL_SP_PORT1_RIGHT:
+ case EL_SP_PORT2_RIGHT:
+ case EL_SP_PORT1_UP:
+ case EL_SP_PORT2_UP:
+ case EL_SP_PORT1_DOWN:
+ case EL_SP_PORT2_DOWN:
+ case EL_SP_PORT_X:
+ case EL_SP_PORT_Y:
+ case EL_SP_PORT_XY:
+ if ((dx == -1 &&
+ element != EL_SP_PORT1_LEFT &&
+ element != EL_SP_PORT2_LEFT &&
+ element != EL_SP_PORT_X &&
+ element != EL_SP_PORT_XY) ||
+ (dx == +1 &&
+ element != EL_SP_PORT1_RIGHT &&
+ element != EL_SP_PORT2_RIGHT &&
+ element != EL_SP_PORT_X &&
+ element != EL_SP_PORT_XY) ||
+ (dy == -1 &&
+ element != EL_SP_PORT1_UP &&
+ element != EL_SP_PORT2_UP &&
+ element != EL_SP_PORT_Y &&
+ element != EL_SP_PORT_XY) ||
+ (dy == +1 &&
+ element != EL_SP_PORT1_DOWN &&
+ element != EL_SP_PORT2_DOWN &&
+ element != EL_SP_PORT_Y &&
+ element != EL_SP_PORT_XY) ||
+ !IN_LEV_FIELD(x + dx, y + dy) ||
+ !IS_FREE(x + dx, y + dy))
+ return MF_NO_ACTION;
+ break;
+
+ case EL_AUSGANG_ZU:
+ case EL_AUSGANG_ACT:
+ /* door is not (yet) open */
+ return MF_NO_ACTION;
+ break;
+
+ case EL_AUSGANG_AUF:
+ if (mode == DF_SNAP)
+ return MF_NO_ACTION;
+
+ 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:
+ Feld[x][y] = EL_BIRNE_EIN;
+ local_player->lights_still_needed--;
+ DrawLevelField(x, y);
+ PlaySoundLevel(x, y, SND_DENG);
+ return MF_ACTION;
+ break;
+
+ case EL_ZEIT_VOLL:
+ Feld[x][y] = EL_ZEIT_LEER;
+ TimeLeft += 10;
+ DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
+ DrawLevelField(x, y);
+ PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
+ return MF_ACTION;
+ break;
+
+ case EL_SOKOBAN_FELD_LEER:
+ break;
+
+ 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;
+
+ player->Pushing = TRUE;
+
+ if (!IN_LEV_FIELD(x+dx, y+dy)
+ || (!IS_FREE(x+dx, y+dy)
+ && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
+ || !IS_SB_ELEMENT(element))))
+ return MF_NO_ACTION;
+
+ if (dx && real_dy)
+ {
+ if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
+ return MF_NO_ACTION;
+ }
+ else if (dy && real_dx)
+ {
+ if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
+ return MF_NO_ACTION;
+ }
+
+ if (player->push_delay == 0)
+ player->push_delay = FrameCounter;
+ if (!FrameReached(&player->push_delay, player->push_delay_value) &&
+ !tape.playing)
+ return MF_NO_ACTION;
+
+ if (IS_SB_ELEMENT(element))
+ {
+ if (element == EL_SOKOBAN_FELD_VOLL)
+ {
+ Feld[x][y] = EL_SOKOBAN_FELD_LEER;
+ local_player->sokobanfields_still_needed++;
+ }
+ else
+ RemoveField(x, y);
+
+ if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
+ {
+ Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
+ local_player->sokobanfields_still_needed--;
+ if (element == EL_SOKOBAN_OBJEKT)
+ PlaySoundLevel(x, y, SND_DENG);
+ }
+ else
+ Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
+ }
+ else
+ {
+ RemoveField(x, y);
+ Feld[x+dx][y+dy] = element;
+ }
+
+ player->push_delay_value = 2;
+
+ DrawLevelField(x, y);
+ DrawLevelField(x+dx, y+dy);
+ PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
+
+ if (IS_SB_ELEMENT(element) &&
+ local_player->sokobanfields_still_needed == 0 &&
+ game_emulation == EMU_SOKOBAN)
+ {
+ player->LevelSolved = player->GameOver = TRUE;
+ PlaySoundLevel(x, y, SND_BUING);
+ }
+
+ break;
+
+ case EL_MAULWURF:
+ case EL_PINGUIN:
+ case EL_SCHWEIN:
+ case EL_DRACHE:
+ break;
+
+ default:
+ return MF_NO_ACTION;
+ }
+
+ player->push_delay = 0;
+
+ return MF_MOVING;
+}
+
+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))
+ return FALSE;
+
+ if (dx && dy)
+ return FALSE;
+
+ if (!dx && !dy)
+ {
+ player->snapped = FALSE;
+ return FALSE;
+ }
+
+ if (player->snapped)
+ return FALSE;
+
+ player->MovDir = (dx < 0 ? MV_LEFT :
+ dx > 0 ? MV_RIGHT :
+ dy < 0 ? MV_UP :
+ dy > 0 ? MV_DOWN : MV_NO_MOVING);
+
+ if (!DigField(player, x, y, 0, 0, DF_SNAP))
+ return FALSE;
+
+ player->snapped = TRUE;
+ DrawLevelField(x, y);
+ BackToFront();
+
+ return TRUE;
+}
+
+boolean PlaceBomb(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+ int element;
+
+ if (player->gone || player->MovPos)
+ return FALSE;
+
+ element = Feld[jx][jy];
+
+ if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
+ element == EL_DYNAMIT || element == EL_DYNABOMB ||
+ element == EL_EXPLODING)
+ return FALSE;
+
+ if (element != EL_LEERRAUM)
+ Store[jx][jy] = element;
+
+ if (player->dynamite)
+ {
+ Feld[jx][jy] = EL_DYNAMIT;
+ 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)))
+ {
+ if (game_emulation == EMU_SUPAPLEX)
+ DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
+ else
+ DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
+ }
+ }
+ else
+ {
+ Feld[jx][jy] = EL_DYNABOMB;
+ Store2[jx][jy] = player->element_nr; /* for DynaExplode() */
+ MovDelay[jx][jy] = 96;
+ player->dynabombs_left--;
+ if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
+ DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
+ }
+
+ return TRUE;
+}
+
+void PlaySoundLevel(int x, int y, int sound_nr)
+{
+ int sx = SCREENX(x), sy = SCREENY(y);
+ int volume, stereo;
+ int silence_distance = 8;
+
+ if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
+ (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
+ return;
+
+ if (!IN_LEV_FIELD(x, y) ||
+ sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
+ sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
+ return;
+
+ volume = PSND_MAX_VOLUME;
+
+#ifndef MSDOS
+ 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;
+#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;
+
+ volume -= volume*(dx > dy ? dx : dy)/silence_distance;
+ }
+
+ PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
+}
+
+void RaiseScore(int value)
+{
+ local_player->score += value;
+ DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
+ FS_SMALL, FC_YELLOW);
+}
+
+void RaiseScoreElement(int element)
+{
+ switch(element)
+ {
+ case EL_EDELSTEIN:
+ case EL_EDELSTEIN_BD:
+ case EL_EDELSTEIN_GELB:
+ case EL_EDELSTEIN_ROT:
+ case EL_EDELSTEIN_LILA:
+ RaiseScore(level.score[SC_EDELSTEIN]);
+ break;
+ case EL_DIAMANT:
+ RaiseScore(level.score[SC_DIAMANT]);
+ break;
+ case EL_KAEFER:
+ case EL_BUTTERFLY:
+ RaiseScore(level.score[SC_KAEFER]);
+ break;
+ case EL_FLIEGER:
+ case EL_FIREFLY:
+ RaiseScore(level.score[SC_FLIEGER]);
+ break;
+ case EL_MAMPFER:
+ case EL_MAMPFER2:
+ RaiseScore(level.score[SC_MAMPFER]);
+ break;
+ case EL_ROBOT:
+ RaiseScore(level.score[SC_ROBOT]);
+ break;
+ case EL_PACMAN:
+ RaiseScore(level.score[SC_PACMAN]);
+ break;
+ case EL_KOKOSNUSS:
+ RaiseScore(level.score[SC_KOKOSNUSS]);
+ break;
+ case EL_DYNAMIT:
+ RaiseScore(level.score[SC_DYNAMIT]);
+ break;
+ case EL_SCHLUESSEL:
+ RaiseScore(level.score[SC_SCHLUESSEL]);
+ break;
+ default:
+ break;
+ }