#include "joystick.h"
#include "network.h"
+/* for DigField() */
+#define DF_NO_PUSH 0
+#define DF_DIG 1
+#define DF_SNAP 2
+
+/* for MoveFigure() */
+#define MF_NO_ACTION 0
+#define MF_MOVING 1
+#define MF_ACTION 2
+
+/* for ScrollFigure() */
+#define SCROLL_INIT 0
+#define SCROLL_GO_ON 1
+
+/* for Explode() */
+#define EX_PHASE_START 0
+#define EX_NORMAL 0
+#define EX_CENTER 1
+#define EX_BORDER 2
+
+/* special positions in the game control window (relative to control window) */
+#define XX_LEVEL 37
+#define YY_LEVEL 20
+#define XX_EMERALDS 29
+#define YY_EMERALDS 54
+#define XX_DYNAMITE 29
+#define YY_DYNAMITE 89
+#define XX_KEYS 18
+#define YY_KEYS 123
+#define XX_SCORE 15
+#define YY_SCORE 159
+#define XX_TIME 29
+#define YY_TIME 194
+
+/* special positions in the game control window (relative to main window) */
+#define DX_LEVEL (DX + XX_LEVEL)
+#define DY_LEVEL (DY + YY_LEVEL)
+#define DX_EMERALDS (DX + XX_EMERALDS)
+#define DY_EMERALDS (DY + YY_EMERALDS)
+#define DX_DYNAMITE (DX + XX_DYNAMITE)
+#define DY_DYNAMITE (DY + YY_DYNAMITE)
+#define DX_KEYS (DX + XX_KEYS)
+#define DY_KEYS (DY + YY_KEYS)
+#define DX_SCORE (DX + XX_SCORE)
+#define DY_SCORE (DY + YY_SCORE)
+#define DX_TIME (DX + XX_TIME)
+#define DY_TIME (DY + YY_TIME)
+
+#define IS_LOOP_SOUND(s) ((s)==SND_KLAPPER || (s)==SND_ROEHR || \
+ (s)==SND_NJAM || (s)==SND_MIEP)
+#define IS_MUSIC_SOUND(s) ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
+ (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
+ (s)==SND_TYGER || (s)==SND_VOYAGER || \
+ (s)==SND_TWILIGHT)
+
+/* score for elements */
+#define SC_EDELSTEIN 0
+#define SC_DIAMANT 1
+#define SC_KAEFER 2
+#define SC_FLIEGER 3
+#define SC_MAMPFER 4
+#define SC_ROBOT 5
+#define SC_PACMAN 6
+#define SC_KOKOSNUSS 7
+#define SC_DYNAMIT 8
+#define SC_SCHLUESSEL 9
+#define SC_ZEITBONUS 10
+
+/* values for game_emulation */
+#define EMU_NONE 0
+#define EMU_BOULDERDASH 1
+#define EMU_SOKOBAN 2
+#define EMU_SUPAPLEX 3
+
+/* to control special behaviour of certain game elements */
+int game_emulation = EMU_NONE;
+
+
+
+
#ifdef DEBUG
+#if 0
static unsigned int getStateCheckSum(int counter)
{
int x, y;
return checksum;
}
#endif
+#endif
+
+
+
void GetPlayerConfig()
{
InitJoysticks();
}
+static void InitField(int x, int y, boolean init_game)
+{
+ switch (Feld[x][y])
+ {
+ case EL_SPIELFIGUR:
+ case EL_SP_MURPHY:
+ if (init_game)
+ Feld[x][y] = EL_SPIELER1;
+ /* no break! */
+ case EL_SPIELER1:
+ case EL_SPIELER2:
+ case EL_SPIELER3:
+ case EL_SPIELER4:
+ if (init_game)
+ {
+ struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
+ int jx = player->jx, jy = player->jy;
+
+ player->present = TRUE;
+
+ /*
+ if (!network_playing || player->connected)
+ */
+
+ if (!options.network || player->connected)
+ {
+ player->active = TRUE;
+
+ /* remove potentially duplicate players */
+ if (StorePlayer[jx][jy] == Feld[x][y])
+ StorePlayer[jx][jy] = 0;
+
+ StorePlayer[x][y] = Feld[x][y];
+
+ if (options.verbose)
+ {
+ printf("Player %d activated.\n", player->element_nr);
+ printf("[Local player is %d and currently %s.]\n",
+ local_player->element_nr,
+ local_player->active ? "active" : "not active");
+ }
+ }
+
+ Feld[x][y] = EL_LEERRAUM;
+ player->jx = player->last_jx = x;
+ player->jy = player->last_jy = y;
+ }
+ break;
+
+ case EL_BADEWANNE:
+ if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
+ Feld[x][y] = EL_BADEWANNE1;
+ else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
+ Feld[x][y] = EL_BADEWANNE2;
+ else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
+ Feld[x][y] = EL_BADEWANNE3;
+ else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
+ Feld[x][y] = EL_BADEWANNE4;
+ else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
+ Feld[x][y] = EL_BADEWANNE5;
+ break;
+
+ case EL_KAEFER_R:
+ case EL_KAEFER_O:
+ case EL_KAEFER_L:
+ case EL_KAEFER_U:
+ case EL_KAEFER:
+ case EL_FLIEGER_R:
+ case EL_FLIEGER_O:
+ case EL_FLIEGER_L:
+ case EL_FLIEGER_U:
+ case EL_FLIEGER:
+ case EL_BUTTERFLY_R:
+ case EL_BUTTERFLY_O:
+ case EL_BUTTERFLY_L:
+ case EL_BUTTERFLY_U:
+ case EL_BUTTERFLY:
+ case EL_FIREFLY_R:
+ case EL_FIREFLY_O:
+ case EL_FIREFLY_L:
+ case EL_FIREFLY_U:
+ case EL_FIREFLY:
+ case EL_PACMAN_R:
+ case EL_PACMAN_O:
+ case EL_PACMAN_L:
+ case EL_PACMAN_U:
+ case EL_MAMPFER:
+ case EL_MAMPFER2:
+ case EL_ROBOT:
+ case EL_PACMAN:
+ case EL_SP_SNIKSNAK:
+ case EL_SP_ELECTRON:
+ InitMovDir(x, y);
+ break;
+
+ case EL_AMOEBE_VOLL:
+ case EL_AMOEBE_BD:
+ InitAmoebaNr(x, y);
+ break;
+
+ case EL_TROPFEN:
+ if (y == lev_fieldy - 1)
+ {
+ Feld[x][y] = EL_AMOEBING;
+ Store[x][y] = EL_AMOEBE_NASS;
+ }
+ break;
+
+ case EL_DYNAMIT:
+ MovDelay[x][y] = 96;
+ break;
+
+ case EL_BIRNE_AUS:
+ local_player->lights_still_needed++;
+ break;
+
+ case EL_SOKOBAN_FELD_LEER:
+ local_player->sokobanfields_still_needed++;
+ break;
+
+ case EL_MAULWURF:
+ case EL_PINGUIN:
+ local_player->friends_still_needed++;
+ break;
+
+ case EL_SCHWEIN:
+ case EL_DRACHE:
+ MovDir[x][y] = 1 << RND(4);
+ break;
+
+ case EL_SP_EMPTY:
+ Feld[x][y] = EL_LEERRAUM;
+ break;
+
+ default:
+ break;
+ }
+}
+
void InitGame()
{
int i, j, x, y;
boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */
boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */
+ boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */
/* don't play tapes over network */
network_playing = (options.network && !tape.playing);
network_player_action_received = FALSE;
+#ifndef MSDOS
/* initial null action */
if (network_playing)
SendToServer_MovePlayer(MV_NO_MOVING);
+#endif
ZX = ZY = -1;
ScreenMovPos = 0;
ScreenGfxPos = 0;
- AllPlayersGone = SiebAktiv = FALSE;
+ if (level.high_speed)
+ {
+ MoveSpeed = 4;
+ ScrollStepSize = TILEX/4;
+ }
+ else
+ {
+ MoveSpeed = 8;
+ ScrollStepSize = TILEX/8;
+ }
+
+ AllPlayersGone = FALSE;
+ SiebAktiv = FALSE;
+ SiebCount = 0;
for (i=0; i<MAX_NUM_AMOEBA; i++)
AmoebaCnt[i] = AmoebaCnt2[i] = 0;
}
}
- for(y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
+ for(y=0; y<lev_fieldy; y++)
{
- if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
- emulate_bd = FALSE;
- if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
- emulate_sb = FALSE;
-
- switch (Feld[x][y])
+ for(x=0; x<lev_fieldx; x++)
{
- case EL_SPIELFIGUR:
- Feld[x][y] = EL_SPIELER1;
- /* no break! */
- case EL_SPIELER1:
- case EL_SPIELER2:
- case EL_SPIELER3:
- case EL_SPIELER4:
- {
- struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
- int jx = player->jx, jy = player->jy;
-
- player->present = TRUE;
-
- /*
- if (!network_playing || player->connected)
- */
-
- if (!options.network || player->connected)
- {
- player->active = TRUE;
-
- /* remove potentially duplicate players */
- if (StorePlayer[jx][jy] == Feld[x][y])
- StorePlayer[jx][jy] = 0;
-
- StorePlayer[x][y] = Feld[x][y];
-
- printf("Player %d activated.\n", player->element_nr);
- printf("[Local player is %d and currently %s.]\n",
- local_player->element_nr,
- local_player->active ? "active" : "not active");
- }
-
- Feld[x][y] = EL_LEERRAUM;
- player->jx = player->last_jx = x;
- player->jy = player->last_jy = y;
-
- break;
- }
- case EL_BADEWANNE:
- if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
- Feld[x][y] = EL_BADEWANNE1;
- else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
- Feld[x][y] = EL_BADEWANNE2;
- else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
- Feld[x][y] = EL_BADEWANNE3;
- else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
- Feld[x][y] = EL_BADEWANNE4;
- else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
- Feld[x][y] = EL_BADEWANNE5;
- break;
- case EL_KAEFER_R:
- case EL_KAEFER_O:
- case EL_KAEFER_L:
- case EL_KAEFER_U:
- case EL_KAEFER:
- case EL_FLIEGER_R:
- case EL_FLIEGER_O:
- case EL_FLIEGER_L:
- case EL_FLIEGER_U:
- case EL_FLIEGER:
- case EL_BUTTERFLY_R:
- case EL_BUTTERFLY_O:
- case EL_BUTTERFLY_L:
- case EL_BUTTERFLY_U:
- case EL_BUTTERFLY:
- case EL_FIREFLY_R:
- case EL_FIREFLY_O:
- case EL_FIREFLY_L:
- case EL_FIREFLY_U:
- case EL_FIREFLY:
- case EL_PACMAN_R:
- case EL_PACMAN_O:
- case EL_PACMAN_L:
- case EL_PACMAN_U:
- case EL_MAMPFER:
- case EL_MAMPFER2:
- case EL_ROBOT:
- case EL_PACMAN:
- InitMovDir(x, y);
- break;
- case EL_AMOEBE_VOLL:
- case EL_AMOEBE_BD:
- InitAmoebaNr(x, y);
- break;
- case EL_TROPFEN:
- if (y == lev_fieldy - 1)
- {
- Feld[x][y] = EL_AMOEBING;
- Store[x][y] = EL_AMOEBE_NASS;
- }
- break;
- case EL_DYNAMIT:
- MovDelay[x][y] = 96;
- break;
- case EL_BIRNE_AUS:
- local_player->lights_still_needed++;
- break;
- case EL_SOKOBAN_FELD_LEER:
- local_player->sokobanfields_still_needed++;
- break;
- case EL_MAULWURF:
- case EL_PINGUIN:
- local_player->friends_still_needed++;
- break;
- case EL_SCHWEIN:
- case EL_DRACHE:
- MovDir[x][y] = 1 << RND(4);
- break;
- default:
- break;
+ if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
+ emulate_bd = FALSE;
+ if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
+ emulate_sb = FALSE;
+ if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
+ emulate_sp = FALSE;
+
+ InitField(x, y, TRUE);
}
}
}
}
- /* when in single player mode, eliminate all but the first active player */
- if (!options.network && !setup.team_mode)
+ if (tape.playing)
+ {
+ /* when playing a tape, eliminate all players who do not participate */
+
+ for (i=0; i<MAX_PLAYERS; i++)
+ {
+ if (stored_player[i].active && !tape.player_participates[i])
+ {
+ struct PlayerInfo *player = &stored_player[i];
+ int jx = player->jx, jy = player->jy;
+
+ player->active = FALSE;
+ StorePlayer[jx][jy] = 0;
+ Feld[jx][jy] = EL_LEERRAUM;
+ }
+ }
+ }
+ else if (!options.network && !setup.team_mode) /* && !tape.playing */
{
+ /* when in single player mode, eliminate all but the first active player */
+
for (i=0; i<MAX_PLAYERS; i++)
{
if (stored_player[i].active)
{
for (j=i+1; j<MAX_PLAYERS; j++)
{
- struct PlayerInfo *player = &stored_player[j];
- int jx = player->jx, jy = player->jy;
-
- if (player->active)
+ if (stored_player[j].active)
{
+ struct PlayerInfo *player = &stored_player[j];
+ int jx = player->jx, jy = player->jy;
+
player->active = FALSE;
StorePlayer[jx][jy] = 0;
Feld[jx][jy] = EL_LEERRAUM;
}
}
- for (i=0; i<MAX_PLAYERS; i++)
+ /* when recording the game, store which players take part in the game */
+ if (tape.recording)
{
- struct PlayerInfo *player = &stored_player[i];
-
- printf("Player %d: present == %d, connected == %d, active == %d.\n",
- i+1,
- player->present,
- player->connected,
- player->active);
- if (local_player == player)
- printf("Player %d is local player.\n", i+1);
+ for (i=0; i<MAX_PLAYERS; i++)
+ if (stored_player[i].active)
+ tape.player_participates[i] = TRUE;
}
+ if (options.verbose)
+ {
+ for (i=0; i<MAX_PLAYERS; i++)
+ {
+ struct PlayerInfo *player = &stored_player[i];
+
+ printf("Player %d: present == %d, connected == %d, active == %d.\n",
+ i+1,
+ player->present,
+ player->connected,
+ player->active);
+ if (local_player == player)
+ printf("Player %d is local player.\n", i+1);
+ }
+ }
game_emulation = (emulate_bd ? EMU_BOULDERDASH :
- emulate_sb ? EMU_SOKOBAN : EMU_NONE);
+ emulate_sb ? EMU_SOKOBAN :
+ emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
scroll_x = scroll_y = -1;
if (local_player->jx >= MIDPOSX-1)
XAutoRepeatOff(display);
-
- for (i=0; i<4; i++)
- printf("Spieler %d %saktiv.\n",
- i+1, (stored_player[i].active ? "" : "nicht "));
-
+ if (options.verbose)
+ {
+ for (i=0; i<4; i++)
+ printf("Spieler %d %saktiv.\n",
+ i+1, (stored_player[i].active ? "" : "nicht "));
+ }
}
void InitMovDir(int x, int y)
Feld[x][y] = EL_KAEFER;
MovDir[x][y] = direction[0][element - EL_KAEFER_R];
break;
+
case EL_FLIEGER_R:
case EL_FLIEGER_O:
case EL_FLIEGER_L:
Feld[x][y] = EL_FLIEGER;
MovDir[x][y] = direction[0][element - EL_FLIEGER_R];
break;
+
case EL_BUTTERFLY_R:
case EL_BUTTERFLY_O:
case EL_BUTTERFLY_L:
Feld[x][y] = EL_BUTTERFLY;
MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R];
break;
+
case EL_FIREFLY_R:
case EL_FIREFLY_O:
case EL_FIREFLY_L:
Feld[x][y] = EL_FIREFLY;
MovDir[x][y] = direction[0][element - EL_FIREFLY_R];
break;
+
case EL_PACMAN_R:
case EL_PACMAN_O:
case EL_PACMAN_L:
Feld[x][y] = EL_PACMAN;
MovDir[x][y] = direction[0][element - EL_PACMAN_R];
break;
+
+ case EL_SP_SNIKSNAK:
+ MovDir[x][y] = MV_UP;
+ break;
+
+ case EL_SP_ELECTRON:
+ MovDir[x][y] = MV_LEFT;
+ break;
+
default:
MovDir[x][y] = 1 << RND(4);
if (element != EL_KAEFER &&
MovDir[x][y] = direction[0][i];
break;
}
- else if (element == EL_FLIEGER || element == EL_FIREFLY)
+ else if (element == EL_FLIEGER || element == EL_FIREFLY ||
+ element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
{
MovDir[x][y] = direction[1][i];
break;
LoadScore(level_nr);
- if (!strcmp(setup.player_name, EMPTY_ALIAS) ||
- local_player->score < highscore[MAX_SCORE_ENTRIES-1].Score)
+ if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
+ local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score)
return -1;
for (k=0; k<MAX_SCORE_ENTRIES; k++)
Store[x][y] = EL_EDELSTEIN_GELB;
break;
}
+
+ if (game_emulation == EMU_SUPAPLEX)
+ Store[x][y] = EL_LEERRAUM;
}
else if (center_element == EL_MAULWURF)
Store[x][y] = EL_EDELSTEIN_ROT;
Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
else if (center_element == EL_BUTTERFLY)
Store[x][y] = EL_EDELSTEIN_BD;
+ else if (center_element == EL_SP_ELECTRON)
+ Store[x][y] = EL_SP_INFOTRON;
else if (center_element == EL_MAMPFER)
Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
else if (center_element == EL_AMOEBA2DIAM)
}
if (center_element == EL_MAMPFER)
- MampferNr = (MampferNr+1) % 4;
+ MampferNr = (MampferNr + 1) % MampferMax;
return;
}
element = Feld[x][y] = Store[x][y];
Store[x][y] = Store2[x][y] = 0;
MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
+ InitField(x, y, FALSE);
if (CAN_MOVE(element) || COULD_MOVE(element))
InitMovDir(x, y);
DrawLevelField(x, y);
}
- else if (!(phase%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
+ else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
+ int graphic = GFX_EXPLOSION;
+
+ if (game_emulation == EMU_SUPAPLEX)
+ graphic = (Store[x][y] == EL_SP_INFOTRON ?
+ GFX_SP_EXPLODE_INFOTRON :
+ GFX_SP_EXPLODE_EMPTY);
+
if (phase == delay)
ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
- DrawGraphic(SCREENX(x), SCREENY(y), GFX_EXPLOSION+(phase/delay-1));
+ DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
}
}
return;
}
- if (element == EL_BOMBE && (lastline || object_hit)) /* element is bomb */
+ if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) &&
+ (lastline || object_hit)) /* element is bomb */
{
Bang(x, y);
return;
if (!lastline && object_hit) /* check which object was hit */
{
if (CAN_CHANGE(element) &&
- (smashed == EL_SIEB_LEER || smashed == EL_SIEB2_LEER) && !SiebAktiv)
- SiebAktiv = level.dauer_sieb * FRAMES_PER_SECOND;
+ (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
+ {
+ int x, y;
+ int activated_magic_wall =
+ (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
+
+ /* activate magic wall / mill */
+
+ for (y=0; y<lev_fieldy; y++)
+ for (x=0; x<lev_fieldx; x++)
+ if (Feld[x][y] == smashed)
+ Feld[x][y] = activated_magic_wall;
+
+ SiebCount = level.dauer_sieb * FRAMES_PER_SECOND;
+ SiebAktiv = TRUE;
+ }
if (IS_PLAYER(x, y+1))
{
return;
}
}
- else if (element == EL_FELSBROCKEN)
+ else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
{
- if (IS_ENEMY(smashed) || smashed == EL_BOMBE || smashed == EL_SONDE ||
- smashed == EL_SCHWEIN || smashed == EL_DRACHE)
+ if (IS_ENEMY(smashed) ||
+ smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
+ smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE)
{
Bang(x, y+1);
return;
else if (element == EL_BUTTERFLY) /* && MovDir[x][y] == left_dir) */
MovDelay[x][y] = 1;
}
- else if (element == EL_FLIEGER || element == EL_FIREFLY)
+ else if (element == EL_FLIEGER || element == EL_FIREFLY ||
+ element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
{
TestIfBadThingHitsOtherBadThing(x, y);
!IS_FREE_OR_PLAYER(move_x, move_y))
MovDir[x][y] = right_dir;
- if (element == EL_FLIEGER && MovDir[x][y] != old_move_dir)
+ if ((element == EL_FLIEGER ||
+ element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
+ && MovDir[x][y] != old_move_dir)
MovDelay[x][y] = 9;
else if (element == EL_FIREFLY) /* && MovDir[x][y] == right_dir) */
MovDelay[x][y] = 1;
Store2[x][y] = 0;
}
}
- else if (SiebAktiv && CAN_CHANGE(element) &&
+ else if (CAN_CHANGE(element) &&
(Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
{
InitMovingField(x, y, MV_DOWN);
if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
{
TurnRound(x, y);
- if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
+ if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER ||
+ element == EL_SP_SNIKSNAK ||
+ element == EL_SP_ELECTRON))
DrawLevelField(x, y);
}
}
{
MovDelay[x][y]--;
- if (element == EL_ROBOT || element == EL_MAMPFER ||
- element == EL_MAMPFER2)
+ if (element == EL_ROBOT ||
+ element == EL_MAMPFER || element == EL_MAMPFER2)
{
int phase = MovDelay[x][y] % 8;
&& MovDelay[x][y]%4 == 3)
PlaySoundLevel(x, y, SND_NJAM);
}
+ else if (element == EL_SP_ELECTRON)
+ DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
else if (element == EL_DRACHE)
{
int i;
TurnRound(x, y);
- if (element == EL_KAEFER || element == EL_FLIEGER)
+ if (element == EL_KAEFER || element == EL_FLIEGER ||
+ element == EL_SP_SNIKSNAK)
DrawLevelField(x, y);
else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
else if (element == EL_SONDE)
DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
+ else if (element == EL_SP_ELECTRON)
+ DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
return;
}
int newx = x + dx, newy = y + dy;
int step = (horiz_move ? dx : dy) * TILEX/8;
- if (CAN_FALL(element) && horiz_move)
+ if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
step*=2;
else if (element == EL_TROPFEN)
step/=2;
for (i=0; i<4; i++)
{
- int x = ax+xy[i%4][0];
- int y = ay+xy[i%4][1];
+ int x = ax + xy[i][0];
+ int y = ay + xy[i][1];
if (!IN_LEV_FIELD(x, y))
continue;
- if (Feld[x][y] == element && AmoebaNr[x][y]>0)
+ if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
group_nr = AmoebaNr[x][y];
}
{ 0, +1 }
};
- if (!new_group_nr)
+ if (new_group_nr == 0)
return;
for (i=0; i<4; i++)
{
- x = ax+xy[i%4][0];
- y = ay+xy[i%4][1];
+ x = ax + xy[i][0];
+ y = ay + xy[i][1];
if (!IN_LEV_FIELD(x, y))
continue;
{
int old_group_nr = AmoebaNr[x][y];
+ if (old_group_nr == 0)
+ return;
+
AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
AmoebaCnt[old_group_nr] = 0;
AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
AmoebaCnt2[old_group_nr] = 0;
- for (yy=0; yy<lev_fieldy; yy++) for (xx=0; xx<lev_fieldx; xx++)
- if (AmoebaNr[xx][yy] == old_group_nr)
- AmoebaNr[xx][yy] = new_group_nr;
+ for (yy=0; yy<lev_fieldy; yy++)
+ {
+ for (xx=0; xx<lev_fieldx; xx++)
+ {
+ if (AmoebaNr[xx][yy] == old_group_nr)
+ AmoebaNr[xx][yy] = new_group_nr;
+ }
+ }
}
}
}
void AmoebeUmwandeln(int ax, int ay)
{
int i, x, y;
- int group_nr = AmoebaNr[ax][ay];
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
if (Feld[ax][ay] == EL_AMOEBE_TOT)
{
- for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ int group_nr = AmoebaNr[ax][ay];
+
+#ifdef DEBUG
+ if (group_nr == 0)
{
- if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
+ printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
+ printf("AmoebeUmwandeln(): This should never happen!\n");
+ return;
+ }
+#endif
+
+ for (y=0; y<lev_fieldy; y++)
+ {
+ for (x=0; x<lev_fieldx; x++)
{
- AmoebaNr[x][y] = 0;
- Feld[x][y] = EL_AMOEBA2DIAM;
+ if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
+ {
+ AmoebaNr[x][y] = 0;
+ Feld[x][y] = EL_AMOEBA2DIAM;
+ }
}
}
Bang(ax, ay);
}
else
{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+
for (i=0; i<4; i++)
{
- x = ax+xy[i%4][0];
- y = ay+xy[i%4][1];
+ x = ax + xy[i][0];
+ y = ay + xy[i][1];
if (!IN_LEV_FIELD(x, y))
continue;
}
}
-void AmoebeUmwandeln2(int ax, int ay, int new_element)
+void AmoebeUmwandelnBD(int ax, int ay, int new_element)
{
int x, y;
int group_nr = AmoebaNr[ax][ay];
boolean done = FALSE;
- for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+#ifdef DEBUG
+ if (group_nr == 0)
{
- if (AmoebaNr[x][y] == group_nr &&
- (Feld[x][y] == EL_AMOEBE_TOT ||
- Feld[x][y] == EL_AMOEBE_BD ||
- Feld[x][y] == EL_AMOEBING))
+ printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
+ printf("AmoebeUmwandelnBD(): This should never happen!\n");
+ return;
+ }
+#endif
+
+ for (y=0; y<lev_fieldy; y++)
+ {
+ for (x=0; x<lev_fieldx; x++)
{
- AmoebaNr[x][y] = 0;
- Feld[x][y] = new_element;
- DrawLevelField(x, y);
- done = TRUE;
+ if (AmoebaNr[x][y] == group_nr &&
+ (Feld[x][y] == EL_AMOEBE_TOT ||
+ Feld[x][y] == EL_AMOEBE_BD ||
+ Feld[x][y] == EL_AMOEBING))
+ {
+ AmoebaNr[x][y] = 0;
+ Feld[x][y] = new_element;
+ InitField(x, y, FALSE);
+ DrawLevelField(x, y);
+ done = TRUE;
+ }
}
}
void AmoebeWaechst(int x, int y)
{
- static long sound_delay = 0;
- static int sound_delay_value = 0;
+ static unsigned long sound_delay = 0;
+ static unsigned long sound_delay_value = 0;
if (!MovDelay[x][y]) /* start new growing cycle */
{
{
MovDelay[x][y]--;
if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
- DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING+3-MovDelay[x][y]/2);
+ DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
if (!MovDelay[x][y])
{
}
if (!MovDelay[ax][ay]) /* start making new amoeba field */
- MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
+ MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.tempo_amoebe));
if (MovDelay[ax][ay]) /* wait some time before making new amoeba */
{
if (element == EL_AMOEBE_NASS) /* object is an acid / amoeba drop */
{
int start = RND(4);
- int x = ax+xy[start][0];
- int y = ay+xy[start][1];
+ int x = ax + xy[start][0];
+ int y = ay + xy[start][1];
if (!IN_LEV_FIELD(x, y))
return;
if (newax == ax && neway == ay)
return;
}
- else /* normal or "filled" amoeba */
+ else /* normal or "filled" (BD style) amoeba */
{
int start = RND(4);
boolean waiting_for_player = FALSE;
for (i=0; i<4; i++)
{
- int j = (start+i)%4;
- int x = ax+xy[j][0];
- int y = ay+xy[j][1];
+ int j = (start + i) % 4;
+ int x = ax + xy[j][0];
+ int y = ay + xy[j][1];
if (!IN_LEV_FIELD(x, y))
continue;
waiting_for_player = TRUE;
}
- if (newax == ax && neway == ay)
+ if (newax == ax && neway == ay) /* amoeba cannot grow */
{
- if (i == 4 && !waiting_for_player)
+ if (i == 4 && (!waiting_for_player || game_emulation == EMU_BOULDERDASH))
{
Feld[ax][ay] = EL_AMOEBE_TOT;
DrawLevelField(ax, ay);
AmoebaCnt[AmoebaNr[ax][ay]]--;
- if (AmoebaCnt[AmoebaNr[ax][ay]]<=0) /* amoeba is completely dead */
+ if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) /* amoeba is completely dead */
{
if (element == EL_AMOEBE_VOLL)
AmoebeUmwandeln(ax, ay);
else if (element == EL_AMOEBE_BD)
- AmoebeUmwandeln2(ax, ay, level.amoebe_inhalt);
+ AmoebeUmwandelnBD(ax, ay, level.amoebe_inhalt);
}
}
return;
}
else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
{
+ /* amoeba gets larger by growing in some direction */
+
int new_group_nr = AmoebaNr[ax][ay];
+#ifdef DEBUG
+ if (new_group_nr == 0)
+ {
+ printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
+ printf("AmoebeAbleger(): This should never happen!\n");
+ return;
+ }
+#endif
+
AmoebaNr[newax][neway] = new_group_nr;
AmoebaCnt[new_group_nr]++;
AmoebaCnt2[new_group_nr]++;
+
+ /* if amoeba touches other amoeba(s) after growing, unify them */
AmoebenVereinigen(newax, neway);
- if (AmoebaCnt2[new_group_nr] >= 200 && element == EL_AMOEBE_BD)
+ if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
{
- AmoebeUmwandeln2(newax, neway, EL_FELSBROCKEN);
+ AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
return;
}
}
}
- if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax, neway) ||
- (neway == lev_fieldy-1 && newax!=ax))
+ if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
+ (neway == lev_fieldy - 1 && newax != ax))
{
Feld[newax][neway] = EL_AMOEBING;
Store[newax][neway] = element;
void SiebAktivieren(int x, int y, int typ)
{
- if (!(SiebAktiv % 4) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
- DrawGraphic(SCREENX(x), SCREENY(y),
- (typ == 1 ? GFX_SIEB_VOLL :
- GFX_SIEB2_VOLL) + 3 - (SiebAktiv % 16) / 4);
+ int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
+
+ DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
}
void AusgangstuerPruefen(int x, int y)
void GameActions()
{
- static long action_delay = 0;
- long action_delay_value;
+ static unsigned long action_delay = 0;
+ unsigned long action_delay_value;
int sieb_x = 0, sieb_y = 0;
int i, x, y, element;
byte *recorded_player_action;
action_delay_value =
(tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
+ /*
+ if (tape.playing && tape.fast_forward)
+ {
+ char buf[100];
+
+ sprintf(buf, "FFWD: %ld ms", action_delay_value);
+ print_debug(buf);
+ }
+ */
+
+
/* main game synchronization point */
+
+
+
+
+#if 1
WaitUntilDelayReached(&action_delay, action_delay_value);
+#else
+
+ while (!DelayReached(&action_delay, action_delay_value))
+ {
+ char buf[100];
+
+ sprintf(buf, "%ld %ld %ld",
+ Counter(), action_delay, action_delay_value);
+ print_debug(buf);
+ }
+ print_debug("done");
+
+#endif
+
+
+
if (network_playing && !network_player_action_received)
{
#endif
*/
+#ifndef MSDOS
/* last chance to get network player actions without main loop delay */
HandleNetworking();
+#endif
if (game_status != PLAYING)
return;
stored_player[i].effective_action = stored_player[i].action;
}
+#ifndef MSDOS
if (network_playing)
SendToServer_MovePlayer(summarized_player_action);
+#endif
if (!options.network && !setup.team_mode)
local_player->effective_action = summarized_player_action;
MauerAbleger(x, y);
else if (element == EL_BURNING)
CheckForDragon(x, y);
+ else if (element == EL_SP_TERMINAL)
+ DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 10, ANIM_NORMAL);
+ else if (element == EL_SP_TERMINAL_ACTIVE)
+ DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 2, ANIM_NORMAL);
if (SiebAktiv)
{
if (SiebAktiv)
{
- if (!(SiebAktiv%4))
+ if (!(SiebCount % 4))
PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
- SiebAktiv--;
- if (!SiebAktiv)
+
+ if (SiebCount > 0)
{
- for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ SiebCount--;
+ if (!SiebCount)
{
- element = Feld[x][y];
- if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
- {
- Feld[x][y] = EL_SIEB_TOT;
- DrawLevelField(x, y);
- }
- else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
- Feld[x][y] = EL_SIEB2_TOT;
- DrawLevelField(x, y);
+ element = Feld[x][y];
+ if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
+ {
+ Feld[x][y] = EL_SIEB_TOT;
+ DrawLevelField(x, y);
+ }
+ else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
+ {
+ Feld[x][y] = EL_SIEB2_TOT;
+ DrawLevelField(x, y);
+ }
}
+
+ SiebAktiv = FALSE;
}
}
}
- if (TimeLeft>0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing)
+ if (TimeLeft > 0 && TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
{
TimeFrames = 0;
TimeLeft--;
jy = player->jy = new_jy;
StorePlayer[jx][jy] = player->element_nr;
- player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8;
+ player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / MoveSpeed);
ScrollFigure(player, SCROLL_INIT);
if (player->MovPos)
{
- /* should only happen if pre-1.0 tape recordings are played */
+ /* should only happen if pre-1.2 tape recordings are played */
/* this is only for backward compatibility */
+ int old_move_speed = MoveSpeed;
+
#if DEBUG
- printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.0 LEVEL TAPES.\n");
+ printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
#endif
+ /* scroll remaining steps with finest movement resolution */
+ MoveSpeed = 8;
+
while (player->MovPos)
{
ScrollFigure(player, SCROLL_GO_ON);
DrawAllPlayers();
BackToFront();
}
+
+ MoveSpeed = old_move_speed;
}
if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
else if (!FrameReached(&player->actual_frame_counter, 1))
return;
- player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX/8;
+ player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX / MoveSpeed;
player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
void ScrollScreen(struct PlayerInfo *player, int mode)
{
- static long screen_frame_counter = 0;
+ static unsigned long screen_frame_counter = 0;
if (mode == SCROLL_INIT)
{
if (ScreenMovPos)
{
- ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8;
+ ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX / MoveSpeed;
ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
redraw_mask |= REDRAW_FIELD;
}
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)
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);
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;
+ PlaySoundLevel(x, y, SND_BUING);
+ 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;
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 */
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;
break;
default:
- return MF_NO_ACTION;
+ if (IS_EATABLE(element)) /* other kinds of 'dirt' */
+ Feld[x][y] = EL_LEERRAUM;
+ else
+ return MF_NO_ACTION;
+
break;
}