+void TestIfGoodThingHitsBadThing(int goodx, int goody)
+{
+ int i, killx = goodx, killy = goody;
+ 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 = goodx + xy[i][0];
+ y = goody + xy[i][1];
+ if (!IN_LEV_FIELD(x, y))
+ continue;
+
+#if 0
+ element = Feld[x][y];
+#else
+ element = MovingOrBlocked2ElementIfNotLeaving(x, y);
+#endif
+
+ if (DONT_TOUCH(element))
+ {
+ if (MovDir[x][y] == harmless[i])
+ continue;
+
+ killx = x;
+ killy = y;
+ break;
+ }
+ }
+
+ if (killx != goodx || killy != goody)
+ {
+ if (IS_PLAYER(goodx, goody))
+ KillHero(PLAYERINFO(goodx, goody));
+ else
+ Bang(goodx, goody);
+ }
+}
+
+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->active)
+ 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->active)
+ 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->present = FALSE;
+ player->active = FALSE;
+
+ StorePlayer[jx][jy] = 0;
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ if (stored_player[i].active)
+ 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 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)
+ player->Pushing = FALSE;
+
+ if (mode == DF_NO_PUSH)
+ {
+ player->Switching = FALSE;
+ 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:
+ case EL_SAND_INVISIBLE:
+ 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);
+ player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_ENVELOPE:
+ Feld[x][y] = EL_LEERRAUM;
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNAMITE_INACTIVE:
+ case EL_SP_DISK_RED:
+ RemoveField(x, y);
+ player->dynamite++;
+ RaiseScoreElement(EL_DYNAMITE_INACTIVE);
+ 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_DYNAMITE_INACTIVE);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_SZ:
+ RemoveField(x, y);
+ player->dynabomb_size++;
+ RaiseScoreElement(EL_DYNAMITE_INACTIVE);
+ PlaySoundLevel(x, y, SND_PONG);
+ break;
+
+ case EL_DYNABOMB_XL:
+ RemoveField(x, y);
+ player->dynabomb_xl = TRUE;
+ RaiseScoreElement(EL_DYNAMITE_INACTIVE);
+ 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_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;
+ 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_BELT1_SWITCH_L:
+ case EL_BELT1_SWITCH_M:
+ case EL_BELT1_SWITCH_R:
+ case EL_BELT2_SWITCH_L:
+ case EL_BELT2_SWITCH_M:
+ case EL_BELT2_SWITCH_R:
+ case EL_BELT3_SWITCH_L:
+ case EL_BELT3_SWITCH_M:
+ case EL_BELT3_SWITCH_R:
+ case EL_BELT4_SWITCH_L:
+ case EL_BELT4_SWITCH_M:
+ case EL_BELT4_SWITCH_R:
+ {
+ static int belt_base_element[4] =
+ {
+ EL_BELT1_SWITCH_L,
+ EL_BELT2_SWITCH_L,
+ EL_BELT3_SWITCH_L,
+ EL_BELT4_SWITCH_L
+ };
+ static int belt_move_dir[4] =
+ {
+ MV_LEFT,
+ MV_NO_MOVING,
+ MV_RIGHT,
+ MV_NO_MOVING,
+ };
+
+ int belt_nr = getBeltNrFromSwitchElement(element);
+ int belt_dir_nr = (game.belt_dir_nr[belt_nr] + 1) % 4;
+ int belt_dir = belt_move_dir[belt_dir_nr];
+ int xx, yy;
+
+ if (player->Switching)
+ return MF_ACTION;
+
+ player->Switching = TRUE;
+
+ game.belt_dir_nr[belt_nr] = belt_dir_nr;
+ game.belt_dir[belt_nr] = belt_dir;
+
+ if (belt_dir_nr == 3)
+ belt_dir_nr = 1;
+
+ for (yy=0; yy<lev_fieldy; yy++)
+ {
+ for (xx=0; xx<lev_fieldx; xx++)
+ {
+ int element = Feld[xx][yy];
+
+ if (IS_BELT_SWITCH(element))
+ {
+ int e_belt_nr = getBeltNrFromSwitchElement(element);
+
+ if (e_belt_nr == belt_nr)
+ {
+ Feld[xx][yy] = belt_base_element[belt_nr] + belt_dir_nr;
+ DrawLevelField(xx, yy);
+ }
+ }
+ else if (belt_dir == MV_NO_MOVING && IS_BELT(element))
+ {
+ int e_belt_nr = getBeltNrFromElement(element);
+
+ if (e_belt_nr == belt_nr)
+ DrawLevelField(xx, yy); /* set belt to parking position */
+ }
+ }
+ }
+
+ return MF_ACTION;
+ }
+ break;
+
+ case EL_SWITCHGATE_SWITCH_1:
+ case EL_SWITCHGATE_SWITCH_2:
+ {
+ int xx, yy;
+
+ if (player->Switching)
+ return MF_ACTION;
+
+ player->Switching = TRUE;
+
+ game.switchgate_pos = !game.switchgate_pos;
+
+ for (yy=0; yy<lev_fieldy; yy++)
+ {
+ for (xx=0; xx<lev_fieldx; xx++)
+ {
+ int element = Feld[xx][yy];
+
+ if (element == EL_SWITCHGATE_SWITCH_1 ||
+ element == EL_SWITCHGATE_SWITCH_2)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_SWITCH_1 + game.switchgate_pos;
+ DrawLevelField(xx, yy);
+ }
+ else if (element == EL_SWITCHGATE_OPEN ||
+ element == EL_SWITCHGATE_OPENING)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_CLOSING;
+ PlaySoundLevel(xx, yy, SND_OEFFNEN);
+ }
+ else if (element == EL_SWITCHGATE_CLOSED ||
+ element == EL_SWITCHGATE_CLOSING)
+ {
+ Feld[xx][yy] = EL_SWITCHGATE_OPENING;
+ PlaySoundLevel(xx, yy, SND_OEFFNEN);
+ }
+ }
+ }
+
+ return MF_ACTION;
+ }
+ break;
+
+ case EL_LIGHT_SWITCH_OFF:
+ case EL_LIGHT_SWITCH_ON:
+ {
+ int xx, yy;
+
+ if (player->Switching)
+ return MF_ACTION;
+
+ player->Switching = TRUE;
+
+ game.light_time_left =
+ (element == EL_LIGHT_SWITCH_OFF ? 10 * FRAMES_PER_SECOND : 0);
+
+ for (yy=0; yy<lev_fieldy; yy++)
+ {
+ for (xx=0; xx<lev_fieldx; xx++)
+ {
+ int element = Feld[xx][yy];
+
+ if (element == EL_LIGHT_SWITCH_OFF &&
+ game.light_time_left > 0)
+ {
+ Feld[xx][yy] = EL_LIGHT_SWITCH_ON;
+ DrawLevelField(xx, yy);
+ }
+ else if (element == EL_LIGHT_SWITCH_ON &&
+ game.light_time_left == 0)
+ {
+ Feld[xx][yy] = EL_LIGHT_SWITCH_OFF;
+ DrawLevelField(xx, yy);
+ }
+
+ if (element == EL_INVISIBLE_STEEL ||
+ element == EL_UNSICHTBAR ||
+ element == EL_SAND_INVISIBLE)
+ DrawLevelField(xx, yy);
+ }
+ }
+
+ 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_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);
+
+ PlaySoundLevel(x, y, SND_GATE);
+
+ 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);
+
+ PlaySoundLevel(x, y, SND_GATE);
+
+ break;
+
+ case EL_SWITCHGATE_OPEN:
+ 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);
+
+ PlaySoundLevel(x, y, SND_GATE);
+
+ 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);
+
+ PlaySoundLevel(x, y, SND_GATE);
+
+ 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);
+
+ 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->active || !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->active || player->MovPos)
+ return FALSE;
+
+ element = Feld[jx][jy];
+
+ if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
+ IS_ACTIVE_BOMB(element) || element == EL_EXPLODING)
+ return FALSE;
+
+ if (element != EL_LEERRAUM)
+ Store[jx][jy] = element;
+
+ 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)))
+ {
+ 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_ACTIVE_1 + (player->element_nr - EL_SPIELER1);
+ 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_DYNAMITE_INACTIVE:
+ RaiseScore(level.score[SC_DYNAMIT]);
+ break;
+ case EL_SCHLUESSEL:
+ RaiseScore(level.score[SC_SCHLUESSEL]);
+ break;
+ default:
+ 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; i<NUM_GAME_BUTTONS; i++)
+ {
+ Pixmap gd_pixmap = pix[PIX_DOOR];
+ struct GadgetInfo *gi;
+ int button_type;
+ boolean checked;
+ unsigned long event_mask;
+ int gd_xoffset, gd_yoffset;
+ int gd_x1, gd_x2, gd_y1, gd_y2;
+ int id = i;
+
+ gd_xoffset = gamebutton_info[i].x;
+ gd_yoffset = gamebutton_info[i].y;
+ gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
+ gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
+
+ if (id == GAME_CTRL_ID_STOP ||
+ id == GAME_CTRL_ID_PAUSE ||
+ id == GAME_CTRL_ID_PLAY)
+ {
+ button_type = GD_TYPE_NORMAL_BUTTON;
+ checked = FALSE;
+ event_mask = GD_EVENT_RELEASED;
+ gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
+ gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
+ }
+ else
+ {
+ button_type = GD_TYPE_CHECK_BUTTON;
+ checked =
+ ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
+ (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
+ (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
+ event_mask = GD_EVENT_PRESSED;
+ gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset;
+ gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
+ }
+
+ gi = CreateGadget(GDI_CUSTOM_ID, id,
+ GDI_INFO_TEXT, gamebutton_info[i].infotext,
+ GDI_X, DX + gd_xoffset,
+ GDI_Y, DY + gd_yoffset,
+ GDI_WIDTH, GAME_BUTTON_XSIZE,
+ GDI_HEIGHT, GAME_BUTTON_YSIZE,
+ GDI_TYPE, button_type,
+ GDI_STATE, GD_BUTTON_UNPRESSED,
+ GDI_CHECKED, checked,
+ GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
+ GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
+ GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
+ GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
+ GDI_EVENT_MASK, event_mask,
+ GDI_CALLBACK_ACTION, HandleGameButtons,
+ GDI_END);
+
+ if (gi == NULL)
+ Error(ERR_EXIT, "cannot create gadget");
+
+ game_gadget[id] = gi;
+ }
+}
+
+static void MapGameButtons()
+{
+ int i;
+
+ for (i=0; i<NUM_GAME_BUTTONS; i++)
+ MapGadget(game_gadget[i]);
+}
+
+void UnmapGameButtons()
+{
+ int i;
+
+ for (i=0; i<NUM_GAME_BUTTONS; i++)
+ UnmapGadget(game_gadget[i]);
+}
+
+static void HandleGameButtons(struct GadgetInfo *gi)
+{
+ int id = gi->custom_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;
+ }