1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-98 Artsoft Entertainment *
8 * phone: ++49 +521 290471 *
9 * email: aeglos@valinor.owl.de *
10 *----------------------------------------------------------*
12 ***********************************************************/
31 /* for MoveFigure() */
32 #define MF_NO_ACTION 0
36 /* for ScrollFigure() */
38 #define SCROLL_GO_ON 1
41 #define EX_PHASE_START 0
46 /* special positions in the game control window (relative to control window) */
49 #define XX_EMERALDS 29
50 #define YY_EMERALDS 54
51 #define XX_DYNAMITE 29
52 #define YY_DYNAMITE 89
60 /* special positions in the game control window (relative to main window) */
61 #define DX_LEVEL (DX + XX_LEVEL)
62 #define DY_LEVEL (DY + YY_LEVEL)
63 #define DX_EMERALDS (DX + XX_EMERALDS)
64 #define DY_EMERALDS (DY + YY_EMERALDS)
65 #define DX_DYNAMITE (DX + XX_DYNAMITE)
66 #define DY_DYNAMITE (DY + YY_DYNAMITE)
67 #define DX_KEYS (DX + XX_KEYS)
68 #define DY_KEYS (DY + YY_KEYS)
69 #define DX_SCORE (DX + XX_SCORE)
70 #define DY_SCORE (DY + YY_SCORE)
71 #define DX_TIME (DX + XX_TIME)
72 #define DY_TIME (DY + YY_TIME)
74 #define IS_LOOP_SOUND(s) ((s)==SND_KLAPPER || (s)==SND_ROEHR || \
75 (s)==SND_NJAM || (s)==SND_MIEP)
76 #define IS_MUSIC_SOUND(s) ((s)==SND_ALCHEMY || (s)==SND_CHASE || \
77 (s)==SND_NETWORK || (s)==SND_CZARDASZ || \
78 (s)==SND_TYGER || (s)==SND_VOYAGER || \
81 /* score for elements */
82 #define SC_EDELSTEIN 0
89 #define SC_KOKOSNUSS 7
91 #define SC_SCHLUESSEL 9
92 #define SC_ZEITBONUS 10
94 /* game button identifiers */
95 #define GAME_CTRL_ID_STOP 0
96 #define GAME_CTRL_ID_PAUSE 1
97 #define GAME_CTRL_ID_PLAY 2
98 #define SOUND_CTRL_ID_MUSIC 3
99 #define SOUND_CTRL_ID_LOOPS 4
100 #define SOUND_CTRL_ID_SIMPLE 5
102 #define NUM_GAME_BUTTONS 6
104 /* forward declaration for internal use */
105 static void MapGameButtons();
106 static void HandleGameButtons(struct GadgetInfo *);
108 static struct GadgetInfo *game_gadget[NUM_GAME_BUTTONS];
114 static unsigned int getStateCheckSum(int counter)
117 unsigned int mult = 1;
118 unsigned int checksum = 0;
120 static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
122 static boolean first_game = TRUE;
124 for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
130 lastFeld[x][y] = Feld[x][y];
131 else if (lastFeld[x][y] != Feld[x][y])
132 printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
133 x, y, lastFeld[x][y], Feld[x][y]);
137 checksum += mult++ * Ur[x][y];
138 checksum += mult++ * Feld[x][y];
141 checksum += mult++ * MovPos[x][y];
142 checksum += mult++ * MovDir[x][y];
143 checksum += mult++ * MovDelay[x][y];
144 checksum += mult++ * Store[x][y];
145 checksum += mult++ * Store2[x][y];
146 checksum += mult++ * StorePlayer[x][y];
147 checksum += mult++ * Frame[x][y];
148 checksum += mult++ * AmoebaNr[x][y];
149 checksum += mult++ * JustHit[x][y];
150 checksum += mult++ * Stop[x][y];
154 if (counter == 3 && first_game)
165 void GetPlayerConfig()
167 if (sound_status == SOUND_OFF)
170 if (!sound_loops_allowed)
172 setup.sound_loops = FALSE;
173 setup.sound_music = FALSE;
176 setup.sound_simple = setup.sound;
181 static void InitField(int x, int y, boolean init_game)
188 Feld[x][y] = EL_SPIELER1;
196 struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
197 int jx = player->jx, jy = player->jy;
199 player->present = TRUE;
202 if (!network_playing || player->connected)
205 if (!options.network || player->connected)
207 player->active = TRUE;
209 /* remove potentially duplicate players */
210 if (StorePlayer[jx][jy] == Feld[x][y])
211 StorePlayer[jx][jy] = 0;
213 StorePlayer[x][y] = Feld[x][y];
217 printf("Player %d activated.\n", player->element_nr);
218 printf("[Local player is %d and currently %s.]\n",
219 local_player->element_nr,
220 local_player->active ? "active" : "not active");
224 Feld[x][y] = EL_LEERRAUM;
225 player->jx = player->last_jx = x;
226 player->jy = player->last_jy = y;
231 if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
232 Feld[x][y] = EL_BADEWANNE1;
233 else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
234 Feld[x][y] = EL_BADEWANNE2;
235 else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
236 Feld[x][y] = EL_BADEWANNE3;
237 else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
238 Feld[x][y] = EL_BADEWANNE4;
239 else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
240 Feld[x][y] = EL_BADEWANNE5;
282 if (y == lev_fieldy - 1)
284 Feld[x][y] = EL_AMOEBING;
285 Store[x][y] = EL_AMOEBE_NASS;
294 local_player->lights_still_needed++;
297 case EL_SOKOBAN_FELD_LEER:
298 local_player->sokobanfields_still_needed++;
303 local_player->friends_still_needed++;
308 MovDir[x][y] = 1 << RND(4);
312 Feld[x][y] = EL_LEERRAUM;
323 boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */
324 boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */
325 boolean emulate_sp = TRUE; /* unless non-SUPAPLEX elements found */
327 /* don't play tapes over network */
328 network_playing = (options.network && !tape.playing);
330 for (i=0; i<MAX_PLAYERS; i++)
332 struct PlayerInfo *player = &stored_player[i];
334 player->index_nr = i;
335 player->element_nr = EL_SPIELER1 + i;
337 player->present = FALSE;
338 player->active = FALSE;
341 player->effective_action = 0;
344 player->gems_still_needed = level.edelsteine;
345 player->sokobanfields_still_needed = 0;
346 player->lights_still_needed = 0;
347 player->friends_still_needed = 0;
350 player->key[j] = FALSE;
352 player->dynamite = 0;
353 player->dynabomb_count = 0;
354 player->dynabomb_size = 0;
355 player->dynabombs_left = 0;
356 player->dynabomb_xl = FALSE;
358 player->MovDir = MV_NO_MOVING;
360 player->Pushing = FALSE;
364 player->actual_frame_counter = 0;
366 player->frame_reset_delay = 0;
368 player->push_delay = 0;
369 player->push_delay_value = 5;
371 player->move_delay = 0;
372 player->last_move_dir = MV_NO_MOVING;
374 player->snapped = FALSE;
376 player->gone = FALSE;
378 player->last_jx = player->last_jy = 0;
379 player->jx = player->jy = 0;
381 DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
382 SnapField(player, 0, 0);
384 player->LevelSolved = FALSE;
385 player->GameOver = FALSE;
388 network_player_action_received = FALSE;
391 /* initial null action */
393 SendToServer_MovePlayer(MV_NO_MOVING);
402 TimeLeft = level.time;
404 ScreenMovDir = MV_NO_MOVING;
408 MoveSpeed = (level.double_speed ? 4 : 8);
409 ScrollStepSize = TILEX / MoveSpeed;
411 AllPlayersGone = FALSE;
415 for (i=0; i<MAX_NUM_AMOEBA; i++)
416 AmoebaCnt[i] = AmoebaCnt2[i] = 0;
418 for (x=0; x<lev_fieldx; x++)
420 for (y=0; y<lev_fieldy; y++)
422 Feld[x][y] = Ur[x][y];
423 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
424 Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
432 for(y=0; y<lev_fieldy; y++)
434 for(x=0; x<lev_fieldx; x++)
436 if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
438 if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
440 if (emulate_sp && !IS_SP_ELEMENT(Feld[x][y]))
443 InitField(x, y, TRUE);
447 /* check if any connected player was not found in playfield */
448 for (i=0; i<MAX_PLAYERS; i++)
450 struct PlayerInfo *player = &stored_player[i];
452 if (player->connected && !player->present)
454 for (j=0; j<MAX_PLAYERS; j++)
456 struct PlayerInfo *some_player = &stored_player[j];
457 int jx = some_player->jx, jy = some_player->jy;
459 /* assign first free player found that is present in the playfield */
460 if (some_player->present && !some_player->connected)
462 player->present = TRUE;
463 player->active = TRUE;
464 some_player->present = FALSE;
466 StorePlayer[jx][jy] = player->element_nr;
467 player->jx = player->last_jx = jx;
468 player->jy = player->last_jy = jy;
478 /* when playing a tape, eliminate all players who do not participate */
480 for (i=0; i<MAX_PLAYERS; i++)
482 if (stored_player[i].active && !tape.player_participates[i])
484 struct PlayerInfo *player = &stored_player[i];
485 int jx = player->jx, jy = player->jy;
487 player->active = FALSE;
488 StorePlayer[jx][jy] = 0;
489 Feld[jx][jy] = EL_LEERRAUM;
493 else if (!options.network && !setup.team_mode) /* && !tape.playing */
495 /* when in single player mode, eliminate all but the first active player */
497 for (i=0; i<MAX_PLAYERS; i++)
499 if (stored_player[i].active)
501 for (j=i+1; j<MAX_PLAYERS; j++)
503 if (stored_player[j].active)
505 struct PlayerInfo *player = &stored_player[j];
506 int jx = player->jx, jy = player->jy;
508 player->active = FALSE;
509 StorePlayer[jx][jy] = 0;
510 Feld[jx][jy] = EL_LEERRAUM;
517 /* when recording the game, store which players take part in the game */
520 for (i=0; i<MAX_PLAYERS; i++)
521 if (stored_player[i].active)
522 tape.player_participates[i] = TRUE;
527 for (i=0; i<MAX_PLAYERS; i++)
529 struct PlayerInfo *player = &stored_player[i];
531 printf("Player %d: present == %d, connected == %d, active == %d.\n",
536 if (local_player == player)
537 printf("Player %d is local player.\n", i+1);
541 game_emulation = (emulate_bd ? EMU_BOULDERDASH :
542 emulate_sb ? EMU_SOKOBAN :
543 emulate_sp ? EMU_SUPAPLEX : EMU_NONE);
545 /* determine border element for this level */
548 if (BorderElement == EL_LEERRAUM)
551 SBX_Right = lev_fieldx - SCR_FIELDX;
553 SBY_Lower = lev_fieldy - SCR_FIELDY;
558 SBX_Right = lev_fieldx - SCR_FIELDX + 1;
560 SBY_Lower = lev_fieldy - SCR_FIELDY + 1;
563 if (lev_fieldx < SCR_FIELDX)
564 SBX_Left = SBX_Right = -1 * (SCR_FIELDX - lev_fieldx) / 2;
566 if (lev_fieldy < SCR_FIELDY)
567 SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
570 scroll_y = SBY_Upper;
571 if (local_player->jx >= SBX_Left + MIDPOSX)
572 scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
573 local_player->jx - MIDPOSX :
575 if (local_player->jy >= SBY_Upper + MIDPOSY)
576 scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
577 local_player->jy - MIDPOSY :
580 CloseDoor(DOOR_CLOSE_1);
586 XCopyArea(display, pix[PIX_DOOR], pix[PIX_DB_DOOR], gc,
587 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
588 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
589 DrawTextExt(pix[PIX_DB_DOOR], gc,
590 DOOR_GFX_PAGEX1 + XX_LEVEL, DOOR_GFX_PAGEY1 + YY_LEVEL,
591 int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
592 DrawTextExt(pix[PIX_DB_DOOR], gc,
593 DOOR_GFX_PAGEX1 + XX_EMERALDS, DOOR_GFX_PAGEY1 + YY_EMERALDS,
594 int2str(local_player->gems_still_needed,3), FS_SMALL, FC_YELLOW);
595 DrawTextExt(pix[PIX_DB_DOOR], gc,
596 DOOR_GFX_PAGEX1 + XX_DYNAMITE, DOOR_GFX_PAGEY1 + YY_DYNAMITE,
597 int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
598 DrawTextExt(pix[PIX_DB_DOOR], gc,
599 DOOR_GFX_PAGEX1 + XX_SCORE, DOOR_GFX_PAGEY1 + YY_SCORE,
600 int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
601 DrawTextExt(pix[PIX_DB_DOOR], gc,
602 DOOR_GFX_PAGEX1 + XX_TIME, DOOR_GFX_PAGEY1 + YY_TIME,
603 int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
608 DrawGameButton(BUTTON_GAME_STOP);
609 DrawGameButton(BUTTON_GAME_PAUSE);
610 DrawGameButton(BUTTON_GAME_PLAY);
611 DrawSoundDisplay(BUTTON_SOUND_MUSIC | (setup.sound_music ? BUTTON_ON : 0));
612 DrawSoundDisplay(BUTTON_SOUND_LOOPS | (setup.sound_loops ? BUTTON_ON : 0));
613 DrawSoundDisplay(BUTTON_SOUND_SIMPLE | (setup.sound_simple ? BUTTON_ON : 0));
616 game_gadget[SOUND_CTRL_ID_MUSIC]->checked = setup.sound_music;
617 game_gadget[SOUND_CTRL_ID_LOOPS]->checked = setup.sound_loops;
618 game_gadget[SOUND_CTRL_ID_SIMPLE]->checked = setup.sound_simple;
622 XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
623 DX + GAME_CONTROL_XPOS, DY + GAME_CONTROL_YPOS,
624 GAME_CONTROL_XSIZE, 2 * GAME_CONTROL_YSIZE,
625 DOOR_GFX_PAGEX1 + GAME_CONTROL_XPOS,
626 DOOR_GFX_PAGEY1 + GAME_CONTROL_YPOS);
630 OpenDoor(DOOR_OPEN_ALL);
632 if (setup.sound_music)
633 PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
635 XAutoRepeatOff(display);
640 printf("Spieler %d %saktiv.\n",
641 i+1, (stored_player[i].active ? "" : "nicht "));
645 void InitMovDir(int x, int y)
647 int i, element = Feld[x][y];
648 static int xy[4][2] =
655 static int direction[2][4] =
657 { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN },
658 { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }
667 Feld[x][y] = EL_KAEFER;
668 MovDir[x][y] = direction[0][element - EL_KAEFER_R];
675 Feld[x][y] = EL_FLIEGER;
676 MovDir[x][y] = direction[0][element - EL_FLIEGER_R];
683 Feld[x][y] = EL_BUTTERFLY;
684 MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R];
691 Feld[x][y] = EL_FIREFLY;
692 MovDir[x][y] = direction[0][element - EL_FIREFLY_R];
699 Feld[x][y] = EL_PACMAN;
700 MovDir[x][y] = direction[0][element - EL_PACMAN_R];
704 MovDir[x][y] = MV_UP;
708 MovDir[x][y] = MV_LEFT;
712 MovDir[x][y] = 1 << RND(4);
713 if (element != EL_KAEFER &&
714 element != EL_FLIEGER &&
715 element != EL_BUTTERFLY &&
716 element != EL_FIREFLY)
721 int x1 = x + xy[i][0];
722 int y1 = y + xy[i][1];
724 if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
726 if (element == EL_KAEFER || element == EL_BUTTERFLY)
728 MovDir[x][y] = direction[0][i];
731 else if (element == EL_FLIEGER || element == EL_FIREFLY ||
732 element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
734 MovDir[x][y] = direction[1][i];
743 void InitAmoebaNr(int x, int y)
746 int group_nr = AmoebeNachbarNr(x, y);
750 for (i=1; i<MAX_NUM_AMOEBA; i++)
752 if (AmoebaCnt[i] == 0)
760 AmoebaNr[x][y] = group_nr;
761 AmoebaCnt[group_nr]++;
762 AmoebaCnt2[group_nr]++;
768 int bumplevel = FALSE;
770 if (local_player->MovPos)
773 local_player->LevelSolved = FALSE;
777 if (setup.sound_loops)
778 PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
782 if (!setup.sound_loops)
783 PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
784 if (TimeLeft > 0 && !(TimeLeft % 10))
785 RaiseScore(level.score[SC_ZEITBONUS]);
786 if (TimeLeft > 100 && !(TimeLeft % 10))
790 DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
795 if (setup.sound_loops)
798 else if (level.time == 0) /* level without time limit */
800 if (setup.sound_loops)
801 PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
803 while(TimePlayed < 999)
805 if (!setup.sound_loops)
806 PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
807 if (TimePlayed < 999 && !(TimePlayed % 10))
808 RaiseScore(level.score[SC_ZEITBONUS]);
809 if (TimePlayed < 900 && !(TimePlayed % 10))
813 DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
818 if (setup.sound_loops)
824 /* Hero disappears */
825 DrawLevelField(ExitX, ExitY);
831 CloseDoor(DOOR_CLOSE_1);
836 SaveTape(tape.level_nr); /* Ask to save tape */
839 if ((hi_pos = NewHiScore()) >= 0)
841 game_status = HALLOFFAME;
842 DrawHallOfFame(hi_pos);
843 if (bumplevel && TAPE_IS_EMPTY(tape))
848 game_status = MAINMENU;
849 if (bumplevel && TAPE_IS_EMPTY(tape))
864 if (strcmp(setup.player_name, EMPTY_PLAYER_NAME) == 0 ||
865 local_player->score < highscore[MAX_SCORE_ENTRIES - 1].Score)
868 for (k=0; k<MAX_SCORE_ENTRIES; k++)
870 if (local_player->score > highscore[k].Score)
872 /* player has made it to the hall of fame */
874 if (k < MAX_SCORE_ENTRIES - 1)
876 int m = MAX_SCORE_ENTRIES - 1;
879 for (l=k; l<MAX_SCORE_ENTRIES; l++)
880 if (!strcmp(setup.player_name, highscore[l].Name))
882 if (m == k) /* player's new highscore overwrites his old one */
888 strcpy(highscore[l].Name, highscore[l - 1].Name);
889 highscore[l].Score = highscore[l - 1].Score;
896 strncpy(highscore[k].Name, setup.player_name, MAX_NAMELEN - 1);
897 highscore[k].Name[MAX_NAMELEN - 1] = '\0';
898 highscore[k].Score = local_player->score;
904 else if (!strncmp(setup.player_name, highscore[k].Name, MAX_NAMELEN - 1))
905 break; /* player already there with a higher score */
916 void InitMovingField(int x, int y, int direction)
918 int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
919 int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
921 MovDir[x][y] = direction;
922 MovDir[newx][newy] = direction;
923 if (Feld[newx][newy] == EL_LEERRAUM)
924 Feld[newx][newy] = EL_BLOCKED;
927 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
929 int direction = MovDir[x][y];
930 int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
931 int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
937 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
939 int oldx = x, oldy = y;
940 int direction = MovDir[x][y];
942 if (direction == MV_LEFT)
944 else if (direction == MV_RIGHT)
946 else if (direction == MV_UP)
948 else if (direction == MV_DOWN)
951 *comes_from_x = oldx;
952 *comes_from_y = oldy;
955 int MovingOrBlocked2Element(int x, int y)
957 int element = Feld[x][y];
959 if (element == EL_BLOCKED)
963 Blocked2Moving(x, y, &oldx, &oldy);
964 return Feld[oldx][oldy];
970 static void RemoveField(int x, int y)
972 Feld[x][y] = EL_LEERRAUM;
978 void RemoveMovingField(int x, int y)
980 int oldx = x, oldy = y, newx = x, newy = y;
982 if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y))
987 Moving2Blocked(x, y, &newx, &newy);
988 if (Feld[newx][newy] != EL_BLOCKED)
991 else if (Feld[x][y] == EL_BLOCKED)
993 Blocked2Moving(x, y, &oldx, &oldy);
994 if (!IS_MOVING(oldx, oldy))
998 if (Feld[x][y] == EL_BLOCKED &&
999 (Store[oldx][oldy] == EL_MORAST_LEER ||
1000 Store[oldx][oldy] == EL_SIEB_LEER ||
1001 Store[oldx][oldy] == EL_SIEB2_LEER ||
1002 Store[oldx][oldy] == EL_AMOEBE_NASS))
1004 Feld[oldx][oldy] = Store[oldx][oldy];
1005 Store[oldx][oldy] = Store2[oldx][oldy] = 0;
1008 Feld[oldx][oldy] = EL_LEERRAUM;
1010 Feld[newx][newy] = EL_LEERRAUM;
1011 MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
1012 MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
1014 DrawLevelField(oldx, oldy);
1015 DrawLevelField(newx, newy);
1018 void DrawDynamite(int x, int y)
1020 int sx = SCREENX(x), sy = SCREENY(y);
1021 int graphic = el2gfx(Feld[x][y]);
1024 if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
1028 DrawGraphic(sx, sy, el2gfx(Store[x][y]));
1030 if (Feld[x][y] == EL_DYNAMIT)
1032 if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
1037 if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3)
1041 if (game_emulation == EMU_SUPAPLEX)
1042 DrawGraphic(sx, sy, GFX_SP_DISK_RED);
1043 else if (Store[x][y])
1044 DrawGraphicThruMask(sx, sy, graphic + phase);
1046 DrawGraphic(sx, sy, graphic + phase);
1049 void CheckDynamite(int x, int y)
1051 if (MovDelay[x][y]) /* dynamite is still waiting to explode */
1056 if (!(MovDelay[x][y] % 12))
1057 PlaySoundLevel(x, y, SND_ZISCH);
1059 if (Feld[x][y] == EL_DYNAMIT && !(MovDelay[x][y] % 12))
1061 else if (Feld[x][y] == EL_DYNABOMB && !(MovDelay[x][y] % 6))
1068 StopSound(SND_ZISCH);
1072 void Explode(int ex, int ey, int phase, int mode)
1075 int num_phase = 9, delay = 2;
1076 int last_phase = num_phase * delay;
1077 int half_phase = (num_phase / 2) * delay;
1079 if (phase == EX_PHASE_START) /* initialize 'Store[][]' field */
1081 int center_element = Feld[ex][ey];
1083 if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
1085 center_element = MovingOrBlocked2Element(ex, ey);
1086 RemoveMovingField(ex, ey);
1089 for (y=ey-1; y<ey+2; y++) for(x=ex-1; x<ex+2; x++)
1091 int element = Feld[x][y];
1093 if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
1095 element = MovingOrBlocked2Element(x, y);
1096 RemoveMovingField(x, y);
1099 if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(element) || element == EL_BURNING)
1102 if ((mode!=EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
1106 if (element == EL_EXPLODING)
1107 element = Store2[x][y];
1109 if (IS_PLAYER(ex, ey))
1111 switch(StorePlayer[ex][ey])
1114 Store[x][y] = EL_EDELSTEIN_ROT;
1117 Store[x][y] = EL_EDELSTEIN;
1120 Store[x][y] = EL_EDELSTEIN_LILA;
1124 Store[x][y] = EL_EDELSTEIN_GELB;
1128 if (game_emulation == EMU_SUPAPLEX)
1129 Store[x][y] = EL_LEERRAUM;
1131 else if (center_element == EL_MAULWURF)
1132 Store[x][y] = EL_EDELSTEIN_ROT;
1133 else if (center_element == EL_PINGUIN)
1134 Store[x][y] = EL_EDELSTEIN_LILA;
1135 else if (center_element == EL_KAEFER)
1136 Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
1137 else if (center_element == EL_BUTTERFLY)
1138 Store[x][y] = EL_EDELSTEIN_BD;
1139 else if (center_element == EL_SP_ELECTRON)
1140 Store[x][y] = EL_SP_INFOTRON;
1141 else if (center_element == EL_MAMPFER)
1142 Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
1143 else if (center_element == EL_AMOEBA2DIAM)
1144 Store[x][y] = level.amoebe_inhalt;
1145 else if (element == EL_ERZ_EDEL)
1146 Store[x][y] = EL_EDELSTEIN;
1147 else if (element == EL_ERZ_DIAM)
1148 Store[x][y] = EL_DIAMANT;
1149 else if (element == EL_ERZ_EDEL_BD)
1150 Store[x][y] = EL_EDELSTEIN_BD;
1151 else if (element == EL_ERZ_EDEL_GELB)
1152 Store[x][y] = EL_EDELSTEIN_GELB;
1153 else if (element == EL_ERZ_EDEL_ROT)
1154 Store[x][y] = EL_EDELSTEIN_ROT;
1155 else if (element == EL_ERZ_EDEL_LILA)
1156 Store[x][y] = EL_EDELSTEIN_LILA;
1157 else if (!IS_PFORTE(Store[x][y]))
1158 Store[x][y] = EL_LEERRAUM;
1160 if (x != ex || y != ey ||
1161 center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
1162 Store2[x][y] = element;
1164 if (AmoebaNr[x][y] &&
1165 (element == EL_AMOEBE_VOLL ||
1166 element == EL_AMOEBE_BD ||
1167 element == EL_AMOEBING))
1169 AmoebaCnt[AmoebaNr[x][y]]--;
1170 AmoebaCnt2[AmoebaNr[x][y]]--;
1173 Feld[x][y] = EL_EXPLODING;
1174 MovDir[x][y] = MovPos[x][y] = 0;
1180 if (center_element == EL_MAMPFER)
1181 MampferNr = (MampferNr + 1) % MampferMax;
1192 Frame[x][y] = (phase<last_phase ? phase+1 : 0);
1194 if (phase == half_phase)
1196 int element = Store2[x][y];
1198 if (IS_PLAYER(x, y))
1199 KillHero(PLAYERINFO(x, y));
1200 else if (IS_EXPLOSIVE(element))
1202 Feld[x][y] = Store2[x][y];
1206 else if (element == EL_AMOEBA2DIAM)
1207 AmoebeUmwandeln(x, y);
1210 if (phase == last_phase)
1214 element = Feld[x][y] = Store[x][y];
1215 Store[x][y] = Store2[x][y] = 0;
1216 MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
1217 InitField(x, y, FALSE);
1218 if (CAN_MOVE(element) || COULD_MOVE(element))
1220 DrawLevelField(x, y);
1222 else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1224 int graphic = GFX_EXPLOSION;
1226 if (game_emulation == EMU_SUPAPLEX)
1227 graphic = (Store[x][y] == EL_SP_INFOTRON ?
1228 GFX_SP_EXPLODE_INFOTRON :
1229 GFX_SP_EXPLODE_EMPTY);
1232 ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
1234 DrawGraphic(SCREENX(x), SCREENY(y), graphic + (phase / delay - 1));
1238 void DynaExplode(int ex, int ey)
1241 struct PlayerInfo *player = &stored_player[Store2[ex][ey] - EL_SPIELER1];
1242 static int xy[4][2] =
1250 Store2[ex][ey] = 0; /* delete player information */
1252 Explode(ex, ey, EX_PHASE_START, EX_CENTER);
1256 for (j=1; j<=player->dynabomb_size; j++)
1258 int x = ex+j*xy[i%4][0];
1259 int y = ey+j*xy[i%4][1];
1262 if (!IN_LEV_FIELD(x, y) || IS_MASSIVE(Feld[x][y]))
1265 element = Feld[x][y];
1266 Explode(x, y, EX_PHASE_START, EX_BORDER);
1268 if (element != EL_LEERRAUM &&
1269 element != EL_ERDREICH &&
1270 element != EL_EXPLODING &&
1271 !player->dynabomb_xl)
1276 player->dynabombs_left++;
1279 void Bang(int x, int y)
1281 int element = Feld[x][y];
1283 if (game_emulation == EMU_SUPAPLEX)
1284 PlaySoundLevel(x, y, SND_SP_BOOOM);
1286 PlaySoundLevel(x, y, SND_ROAAAR);
1288 if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
1289 element = EL_LEERRAUM;
1301 RaiseScoreElement(element);
1302 Explode(x, y, EX_PHASE_START, EX_NORMAL);
1305 case EL_DYNABOMB_NR:
1306 case EL_DYNABOMB_SZ:
1307 case EL_DYNABOMB_XL:
1314 Explode(x, y, EX_PHASE_START, EX_CENTER);
1317 Explode(x, y, EX_PHASE_START, EX_NORMAL);
1322 void Blurb(int x, int y)
1324 int element = Feld[x][y];
1326 if (element != EL_BLURB_LEFT && element != EL_BLURB_RIGHT) /* start */
1328 PlaySoundLevel(x, y, SND_BLURB);
1329 if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
1330 (!IN_LEV_FIELD(x-1, y-1) ||
1331 !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
1333 Feld[x-1][y] = EL_BLURB_LEFT;
1335 if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
1336 (!IN_LEV_FIELD(x+1, y-1) ||
1337 !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
1339 Feld[x+1][y] = EL_BLURB_RIGHT;
1344 int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1346 if (!MovDelay[x][y]) /* initialize animation counter */
1349 if (MovDelay[x][y]) /* continue animation */
1352 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1353 DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
1355 if (!MovDelay[x][y])
1357 Feld[x][y] = EL_LEERRAUM;
1358 DrawLevelField(x, y);
1364 void Impact(int x, int y)
1366 boolean lastline = (y == lev_fieldy-1);
1367 boolean object_hit = FALSE;
1368 int element = Feld[x][y];
1371 if (!lastline) /* check if element below was hit */
1373 if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1376 object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1377 MovDir[x][y+1]!=MV_DOWN ||
1378 MovPos[x][y+1]<=TILEY/2));
1380 smashed = MovingOrBlocked2Element(x, y+1);
1383 if (!lastline && smashed == EL_SALZSAEURE) /* element falls into acid */
1389 if ((element == EL_BOMBE || element == EL_SP_DISK_ORANGE) &&
1390 (lastline || object_hit)) /* element is bomb */
1396 if (element == EL_TROPFEN && (lastline || object_hit)) /* acid drop */
1398 if (object_hit && IS_PLAYER(x, y+1))
1399 KillHero(PLAYERINFO(x, y+1));
1400 else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN))
1404 Feld[x][y] = EL_AMOEBING;
1405 Store[x][y] = EL_AMOEBE_NASS;
1410 if (!lastline && object_hit) /* check which object was hit */
1412 if (CAN_CHANGE(element) &&
1413 (smashed == EL_SIEB_INAKTIV || smashed == EL_SIEB2_INAKTIV))
1416 int activated_magic_wall =
1417 (smashed == EL_SIEB_INAKTIV ? EL_SIEB_LEER : EL_SIEB2_LEER);
1419 /* activate magic wall / mill */
1421 for (y=0; y<lev_fieldy; y++)
1422 for (x=0; x<lev_fieldx; x++)
1423 if (Feld[x][y] == smashed)
1424 Feld[x][y] = activated_magic_wall;
1426 SiebCount = level.dauer_sieb * FRAMES_PER_SECOND;
1430 if (IS_PLAYER(x, y+1))
1432 KillHero(PLAYERINFO(x, y+1));
1435 else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN)
1440 else if (element == EL_EDELSTEIN_BD)
1442 if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1448 else if (element == EL_FELSBROCKEN || element == EL_SP_ZONK)
1450 if (IS_ENEMY(smashed) ||
1451 smashed == EL_BOMBE || smashed == EL_SP_DISK_ORANGE ||
1452 smashed == EL_SONDE || smashed == EL_SCHWEIN || smashed == EL_DRACHE)
1457 else if (!IS_MOVING(x, y+1))
1459 if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1464 else if (smashed == EL_KOKOSNUSS)
1466 Feld[x][y+1] = EL_CRACKINGNUT;
1467 PlaySoundLevel(x, y, SND_KNACK);
1468 RaiseScoreElement(EL_KOKOSNUSS);
1471 else if (smashed == EL_DIAMANT)
1473 Feld[x][y+1] = EL_LEERRAUM;
1474 PlaySoundLevel(x, y, SND_QUIRK);
1481 /* play sound of magic wall / mill */
1483 (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1485 PlaySoundLevel(x, y, SND_QUIRK);
1489 /* play sound of object that hits the ground */
1490 if (lastline || object_hit)
1497 case EL_EDELSTEIN_BD:
1498 case EL_EDELSTEIN_GELB:
1499 case EL_EDELSTEIN_ROT:
1500 case EL_EDELSTEIN_LILA:
1502 case EL_SP_INFOTRON:
1508 case EL_FELSBROCKEN:
1512 sound = SND_SP_ZONKDOWN;
1515 case EL_SCHLUESSEL1:
1516 case EL_SCHLUESSEL2:
1517 case EL_SCHLUESSEL3:
1518 case EL_SCHLUESSEL4:
1531 PlaySoundLevel(x, y, sound);
1535 void TurnRound(int x, int y)
1547 { 0, 0 }, { 0, 0 }, { 0, 0 },
1552 int left, right, back;
1556 { MV_DOWN, MV_UP, MV_RIGHT },
1557 { MV_UP, MV_DOWN, MV_LEFT },
1559 { MV_LEFT, MV_RIGHT, MV_DOWN },
1560 { 0,0,0 }, { 0,0,0 }, { 0,0,0 },
1561 { MV_RIGHT, MV_LEFT, MV_UP }
1564 int element = Feld[x][y];
1565 int old_move_dir = MovDir[x][y];
1566 int left_dir = turn[old_move_dir].left;
1567 int right_dir = turn[old_move_dir].right;
1568 int back_dir = turn[old_move_dir].back;
1570 int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1571 int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1572 int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1573 int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1575 int left_x = x+left_dx, left_y = y+left_dy;
1576 int right_x = x+right_dx, right_y = y+right_dy;
1577 int move_x = x+move_dx, move_y = y+move_dy;
1579 if (element == EL_KAEFER || element == EL_BUTTERFLY)
1581 TestIfBadThingHitsOtherBadThing(x, y);
1583 if (IN_LEV_FIELD(right_x, right_y) &&
1584 IS_FREE_OR_PLAYER(right_x, right_y))
1585 MovDir[x][y] = right_dir;
1586 else if (!IN_LEV_FIELD(move_x, move_y) ||
1587 !IS_FREE_OR_PLAYER(move_x, move_y))
1588 MovDir[x][y] = left_dir;
1590 if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
1592 else if (element == EL_BUTTERFLY) /* && MovDir[x][y] == left_dir) */
1595 else if (element == EL_FLIEGER || element == EL_FIREFLY ||
1596 element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1598 TestIfBadThingHitsOtherBadThing(x, y);
1600 if (IN_LEV_FIELD(left_x, left_y) &&
1601 IS_FREE_OR_PLAYER(left_x, left_y))
1602 MovDir[x][y] = left_dir;
1603 else if (!IN_LEV_FIELD(move_x, move_y) ||
1604 !IS_FREE_OR_PLAYER(move_x, move_y))
1605 MovDir[x][y] = right_dir;
1607 if ((element == EL_FLIEGER ||
1608 element == EL_SP_SNIKSNAK || element == EL_SP_ELECTRON)
1609 && MovDir[x][y] != old_move_dir)
1611 else if (element == EL_FIREFLY) /* && MovDir[x][y] == right_dir) */
1614 else if (element == EL_MAMPFER)
1616 boolean can_turn_left = FALSE, can_turn_right = FALSE;
1618 if (IN_LEV_FIELD(left_x, left_y) &&
1619 (IS_FREE_OR_PLAYER(left_x, left_y) ||
1620 Feld[left_x][left_y] == EL_DIAMANT))
1621 can_turn_left = TRUE;
1622 if (IN_LEV_FIELD(right_x, right_y) &&
1623 (IS_FREE_OR_PLAYER(right_x, right_y) ||
1624 Feld[right_x][right_y] == EL_DIAMANT))
1625 can_turn_right = TRUE;
1627 if (can_turn_left && can_turn_right)
1628 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1629 else if (can_turn_left)
1630 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1631 else if (can_turn_right)
1632 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1634 MovDir[x][y] = back_dir;
1636 MovDelay[x][y] = 16+16*RND(3);
1638 else if (element == EL_MAMPFER2)
1640 boolean can_turn_left = FALSE, can_turn_right = FALSE;
1642 if (IN_LEV_FIELD(left_x, left_y) &&
1643 (IS_FREE_OR_PLAYER(left_x, left_y) ||
1644 IS_MAMPF2(Feld[left_x][left_y])))
1645 can_turn_left = TRUE;
1646 if (IN_LEV_FIELD(right_x, right_y) &&
1647 (IS_FREE_OR_PLAYER(right_x, right_y) ||
1648 IS_MAMPF2(Feld[right_x][right_y])))
1649 can_turn_right = TRUE;
1651 if (can_turn_left && can_turn_right)
1652 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1653 else if (can_turn_left)
1654 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1655 else if (can_turn_right)
1656 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1658 MovDir[x][y] = back_dir;
1660 MovDelay[x][y] = 16+16*RND(3);
1662 else if (element == EL_PACMAN)
1664 boolean can_turn_left = FALSE, can_turn_right = FALSE;
1666 if (IN_LEV_FIELD(left_x, left_y) &&
1667 (IS_FREE_OR_PLAYER(left_x, left_y) ||
1668 IS_AMOEBOID(Feld[left_x][left_y])))
1669 can_turn_left = TRUE;
1670 if (IN_LEV_FIELD(right_x, right_y) &&
1671 (IS_FREE_OR_PLAYER(right_x, right_y) ||
1672 IS_AMOEBOID(Feld[right_x][right_y])))
1673 can_turn_right = TRUE;
1675 if (can_turn_left && can_turn_right)
1676 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1677 else if (can_turn_left)
1678 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1679 else if (can_turn_right)
1680 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1682 MovDir[x][y] = back_dir;
1684 MovDelay[x][y] = 6+RND(40);
1686 else if (element == EL_SCHWEIN)
1688 boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1689 boolean should_turn_left = FALSE, should_turn_right = FALSE;
1690 boolean should_move_on = FALSE;
1692 int rnd = RND(rnd_value);
1694 if (IN_LEV_FIELD(left_x, left_y) &&
1695 (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
1696 can_turn_left = TRUE;
1697 if (IN_LEV_FIELD(right_x, right_y) &&
1698 (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
1699 can_turn_right = TRUE;
1700 if (IN_LEV_FIELD(move_x, move_y) &&
1701 (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
1704 if (can_turn_left &&
1706 (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
1707 !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
1708 should_turn_left = TRUE;
1709 if (can_turn_right &&
1711 (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
1712 !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
1713 should_turn_right = TRUE;
1715 (!can_turn_left || !can_turn_right ||
1716 (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
1717 !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
1718 (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
1719 !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
1720 should_move_on = TRUE;
1722 if (should_turn_left || should_turn_right || should_move_on)
1724 if (should_turn_left && should_turn_right && should_move_on)
1725 MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1726 rnd < 2*rnd_value/3 ? right_dir :
1728 else if (should_turn_left && should_turn_right)
1729 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1730 else if (should_turn_left && should_move_on)
1731 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1732 else if (should_turn_right && should_move_on)
1733 MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1734 else if (should_turn_left)
1735 MovDir[x][y] = left_dir;
1736 else if (should_turn_right)
1737 MovDir[x][y] = right_dir;
1738 else if (should_move_on)
1739 MovDir[x][y] = old_move_dir;
1741 else if (can_move_on && rnd > rnd_value/8)
1742 MovDir[x][y] = old_move_dir;
1743 else if (can_turn_left && can_turn_right)
1744 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1745 else if (can_turn_left && rnd > rnd_value/8)
1746 MovDir[x][y] = left_dir;
1747 else if (can_turn_right && rnd > rnd_value/8)
1748 MovDir[x][y] = right_dir;
1750 MovDir[x][y] = back_dir;
1752 if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
1753 !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1754 MovDir[x][y] = old_move_dir;
1758 else if (element == EL_DRACHE)
1760 boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1762 int rnd = RND(rnd_value);
1764 if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
1765 can_turn_left = TRUE;
1766 if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
1767 can_turn_right = TRUE;
1768 if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
1771 if (can_move_on && rnd > rnd_value/8)
1772 MovDir[x][y] = old_move_dir;
1773 else if (can_turn_left && can_turn_right)
1774 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1775 else if (can_turn_left && rnd > rnd_value/8)
1776 MovDir[x][y] = left_dir;
1777 else if (can_turn_right && rnd > rnd_value/8)
1778 MovDir[x][y] = right_dir;
1780 MovDir[x][y] = back_dir;
1782 if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
1783 MovDir[x][y] = old_move_dir;
1787 else if (element == EL_ROBOT || element == EL_SONDE ||
1788 element == EL_MAULWURF || element == EL_PINGUIN)
1790 int attr_x = -1, attr_y = -1;
1801 for (i=0; i<MAX_PLAYERS; i++)
1803 struct PlayerInfo *player = &stored_player[i];
1804 int jx = player->jx, jy = player->jy;
1806 if (!player->active || player->gone)
1809 if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
1817 if (element == EL_ROBOT && ZX>=0 && ZY>=0)
1823 if (element == EL_MAULWURF || element == EL_PINGUIN)
1826 static int xy[4][2] =
1836 int ex = x + xy[i%4][0];
1837 int ey = y + xy[i%4][1];
1839 if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1848 MovDir[x][y] = MV_NO_MOVING;
1850 MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
1852 MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
1854 MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
1856 MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
1858 if (element == EL_ROBOT)
1862 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1863 MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1864 Moving2Blocked(x, y, &newx, &newy);
1866 if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
1867 MovDelay[x][y] = 8+8*!RND(3);
1869 MovDelay[x][y] = 16;
1877 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1879 boolean first_horiz = RND(2);
1880 int new_move_dir = MovDir[x][y];
1883 new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1884 Moving2Blocked(x, y, &newx, &newy);
1886 if (IN_LEV_FIELD(newx, newy) &&
1887 (IS_FREE(newx, newy) ||
1888 Feld[newx][newy] == EL_SALZSAEURE ||
1889 ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1890 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1891 IS_MAMPF3(Feld[newx][newy])))))
1895 new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1896 Moving2Blocked(x, y, &newx, &newy);
1898 if (IN_LEV_FIELD(newx, newy) &&
1899 (IS_FREE(newx, newy) ||
1900 Feld[newx][newy] == EL_SALZSAEURE ||
1901 ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1902 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1903 IS_MAMPF3(Feld[newx][newy])))))
1906 MovDir[x][y] = old_move_dir;
1913 static boolean JustBeingPushed(int x, int y)
1917 for (i=0; i<MAX_PLAYERS; i++)
1919 struct PlayerInfo *player = &stored_player[i];
1921 if (player->active && !player->gone &&
1922 player->Pushing && player->MovPos)
1924 int next_jx = player->jx + (player->jx - player->last_jx);
1925 int next_jy = player->jy + (player->jy - player->last_jy);
1927 if (x == next_jx && y == next_jy)
1935 void StartMoving(int x, int y)
1937 int element = Feld[x][y];
1942 if (CAN_FALL(element) && y<lev_fieldy-1)
1944 if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
1945 if (JustBeingPushed(x, y))
1948 if (element == EL_MORAST_VOLL)
1950 if (IS_FREE(x, y+1))
1952 InitMovingField(x, y, MV_DOWN);
1953 Feld[x][y] = EL_FELSBROCKEN;
1954 Store[x][y] = EL_MORAST_LEER;
1956 else if (Feld[x][y+1] == EL_MORAST_LEER)
1958 if (!MovDelay[x][y])
1959 MovDelay[x][y] = TILEY + 1;
1968 Feld[x][y] = EL_MORAST_LEER;
1969 Feld[x][y+1] = EL_MORAST_VOLL;
1972 else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
1974 InitMovingField(x, y, MV_DOWN);
1975 Store[x][y] = EL_MORAST_VOLL;
1977 else if (element == EL_SIEB_VOLL)
1979 if (IS_FREE(x, y+1))
1981 InitMovingField(x, y, MV_DOWN);
1982 Feld[x][y] = EL_CHANGED(Store2[x][y]);
1983 Store[x][y] = EL_SIEB_LEER;
1985 else if (Feld[x][y+1] == EL_SIEB_LEER)
1987 if (!MovDelay[x][y])
1988 MovDelay[x][y] = TILEY/4 + 1;
1997 Feld[x][y] = EL_SIEB_LEER;
1998 Feld[x][y+1] = EL_SIEB_VOLL;
1999 Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
2003 else if (element == EL_SIEB2_VOLL)
2005 if (IS_FREE(x, y+1))
2007 InitMovingField(x, y, MV_DOWN);
2008 Feld[x][y] = EL_CHANGED2(Store2[x][y]);
2009 Store[x][y] = EL_SIEB2_LEER;
2011 else if (Feld[x][y+1] == EL_SIEB2_LEER)
2013 if (!MovDelay[x][y])
2014 MovDelay[x][y] = TILEY/4 + 1;
2023 Feld[x][y] = EL_SIEB2_LEER;
2024 Feld[x][y+1] = EL_SIEB2_VOLL;
2025 Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
2029 else if (CAN_CHANGE(element) &&
2030 (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
2032 InitMovingField(x, y, MV_DOWN);
2034 (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
2035 Store2[x][y+1] = element;
2037 else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
2040 InitMovingField(x, y, MV_DOWN);
2041 Store[x][y] = EL_SALZSAEURE;
2043 else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED && JustHit[x][y])
2047 else if (IS_FREE(x, y+1))
2049 InitMovingField(x, y, MV_DOWN);
2051 else if (element == EL_TROPFEN)
2053 Feld[x][y] = EL_AMOEBING;
2054 Store[x][y] = EL_AMOEBE_NASS;
2056 else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
2058 boolean left = (x>0 && IS_FREE(x-1, y) &&
2059 (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
2060 boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
2061 (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
2065 if (left && right && game_emulation != EMU_BOULDERDASH)
2066 left = !(right = RND(2));
2068 InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
2072 else if (CAN_MOVE(element))
2076 if (element == EL_SONDE && JustBeingPushed(x, y))
2079 if (!MovDelay[x][y]) /* start new movement phase */
2081 /* all objects that can change their move direction after each step */
2082 /* (MAMPFER, MAMPFER2 and PACMAN go straight until they hit a wall */
2084 if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
2087 if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER ||
2088 element == EL_SP_SNIKSNAK ||
2089 element == EL_SP_ELECTRON))
2090 DrawLevelField(x, y);
2094 if (MovDelay[x][y]) /* wait some time before next movement */
2098 if (element == EL_ROBOT ||
2099 element == EL_MAMPFER || element == EL_MAMPFER2)
2101 int phase = MovDelay[x][y] % 8;
2106 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2107 DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
2109 if ((element == EL_MAMPFER || element == EL_MAMPFER2)
2110 && MovDelay[x][y]%4 == 3)
2111 PlaySoundLevel(x, y, SND_NJAM);
2113 else if (element == EL_SP_ELECTRON)
2114 DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2115 else if (element == EL_DRACHE)
2118 int dir = MovDir[x][y];
2119 int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
2120 int dy = (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
2121 int graphic = (dir == MV_LEFT ? GFX_FLAMMEN_LEFT :
2122 dir == MV_RIGHT ? GFX_FLAMMEN_RIGHT :
2123 dir == MV_UP ? GFX_FLAMMEN_UP :
2124 dir == MV_DOWN ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
2125 int phase = FrameCounter % 2;
2127 for (i=1; i<=3; i++)
2129 int xx = x + i*dx, yy = y + i*dy;
2130 int sx = SCREENX(xx), sy = SCREENY(yy);
2132 if (!IN_LEV_FIELD(xx, yy) ||
2133 IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
2138 int flamed = MovingOrBlocked2Element(xx, yy);
2140 if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
2143 RemoveMovingField(xx, yy);
2145 Feld[xx][yy] = EL_BURNING;
2146 if (IN_SCR_FIELD(sx, sy))
2147 DrawGraphic(sx, sy, graphic + phase*3 + i-1);
2151 if (Feld[xx][yy] == EL_BURNING)
2152 Feld[xx][yy] = EL_LEERRAUM;
2153 DrawLevelField(xx, yy);
2162 if (element == EL_KAEFER || element == EL_BUTTERFLY)
2164 PlaySoundLevel(x, y, SND_KLAPPER);
2166 else if (element == EL_FLIEGER || element == EL_FIREFLY)
2168 PlaySoundLevel(x, y, SND_ROEHR);
2171 /* now make next step */
2173 Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
2175 if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
2177 /* enemy got the player */
2179 KillHero(PLAYERINFO(newx, newy));
2182 else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
2183 element == EL_ROBOT || element == EL_SONDE) &&
2184 IN_LEV_FIELD(newx, newy) &&
2185 MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
2188 Store[x][y] = EL_SALZSAEURE;
2190 else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
2191 IN_LEV_FIELD(newx, newy))
2193 if (Feld[newx][newy] == EL_AUSGANG_AUF)
2195 Feld[x][y] = EL_LEERRAUM;
2196 DrawLevelField(x, y);
2198 PlaySoundLevel(newx, newy, SND_BUING);
2199 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
2200 DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
2202 local_player->friends_still_needed--;
2203 if (!local_player->friends_still_needed &&
2204 !local_player->GameOver && AllPlayersGone)
2205 local_player->LevelSolved = local_player->GameOver = TRUE;
2209 else if (IS_MAMPF3(Feld[newx][newy]))
2211 if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
2212 DrawLevelField(newx, newy);
2214 MovDir[x][y] = MV_NO_MOVING;
2216 else if (!IS_FREE(newx, newy))
2218 if (IS_PLAYER(x, y))
2219 DrawPlayerField(x, y);
2221 DrawLevelField(x, y);
2225 else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
2227 if (IS_GEM(Feld[newx][newy]))
2229 if (IS_MOVING(newx, newy))
2230 RemoveMovingField(newx, newy);
2233 Feld[newx][newy] = EL_LEERRAUM;
2234 DrawLevelField(newx, newy);
2237 else if (!IS_FREE(newx, newy))
2239 if (IS_PLAYER(x, y))
2240 DrawPlayerField(x, y);
2242 DrawLevelField(x, y);
2246 else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
2248 if (!IS_FREE(newx, newy))
2250 if (IS_PLAYER(x, y))
2251 DrawPlayerField(x, y);
2253 DrawLevelField(x, y);
2258 boolean wanna_flame = !RND(10);
2259 int dx = newx - x, dy = newy - y;
2260 int newx1 = newx+1*dx, newy1 = newy+1*dy;
2261 int newx2 = newx+2*dx, newy2 = newy+2*dy;
2262 int element1 = (IN_LEV_FIELD(newx1, newy1) ?
2263 MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
2264 int element2 = (IN_LEV_FIELD(newx2, newy2) ?
2265 MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
2267 if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
2268 element1 != EL_DRACHE && element2 != EL_DRACHE &&
2269 element1 != EL_BURNING && element2 != EL_BURNING)
2271 if (IS_PLAYER(x, y))
2272 DrawPlayerField(x, y);
2274 DrawLevelField(x, y);
2276 MovDelay[x][y] = 50;
2277 Feld[newx][newy] = EL_BURNING;
2278 if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
2279 Feld[newx1][newy1] = EL_BURNING;
2280 if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
2281 Feld[newx2][newy2] = EL_BURNING;
2286 else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2287 Feld[newx][newy] == EL_DIAMANT)
2289 if (IS_MOVING(newx, newy))
2290 RemoveMovingField(newx, newy);
2293 Feld[newx][newy] = EL_LEERRAUM;
2294 DrawLevelField(newx, newy);
2297 else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2298 IS_MAMPF2(Feld[newx][newy]))
2300 if (AmoebaNr[newx][newy])
2302 AmoebaCnt2[AmoebaNr[newx][newy]]--;
2303 if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2304 Feld[newx][newy] == EL_AMOEBE_BD)
2305 AmoebaCnt[AmoebaNr[newx][newy]]--;
2308 if (IS_MOVING(newx, newy))
2309 RemoveMovingField(newx, newy);
2312 Feld[newx][newy] = EL_LEERRAUM;
2313 DrawLevelField(newx, newy);
2316 else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) &&
2317 IS_AMOEBOID(Feld[newx][newy]))
2319 if (AmoebaNr[newx][newy])
2321 AmoebaCnt2[AmoebaNr[newx][newy]]--;
2322 if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2323 Feld[newx][newy] == EL_AMOEBE_BD)
2324 AmoebaCnt[AmoebaNr[newx][newy]]--;
2327 Feld[newx][newy] = EL_LEERRAUM;
2328 DrawLevelField(newx, newy);
2330 else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2332 /* object was running against a wall */
2336 if (element == EL_KAEFER || element == EL_FLIEGER ||
2337 element == EL_SP_SNIKSNAK)
2338 DrawLevelField(x, y);
2339 else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2340 DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2341 else if (element == EL_SONDE)
2342 DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2343 else if (element == EL_SP_ELECTRON)
2344 DrawGraphicAnimation(x, y, GFX2_SP_ELECTRON, 8, 2, ANIM_NORMAL);
2349 if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2350 PlaySoundLevel(x, y, SND_SCHLURF);
2352 InitMovingField(x, y, MovDir[x][y]);
2356 ContinueMoving(x, y);
2359 void ContinueMoving(int x, int y)
2361 int element = Feld[x][y];
2362 int direction = MovDir[x][y];
2363 int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2364 int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
2365 int horiz_move = (dx!=0);
2366 int newx = x + dx, newy = y + dy;
2367 int step = (horiz_move ? dx : dy) * TILEX/8;
2369 if (CAN_FALL(element) && horiz_move && !IS_SP_ELEMENT(element))
2371 else if (element == EL_TROPFEN)
2373 else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2376 MovPos[x][y] += step;
2378 if (ABS(MovPos[x][y])>=TILEX) /* object reached its destination */
2380 Feld[x][y] = EL_LEERRAUM;
2381 Feld[newx][newy] = element;
2383 if (Store[x][y] == EL_MORAST_VOLL)
2386 Feld[newx][newy] = EL_MORAST_VOLL;
2387 element = EL_MORAST_VOLL;
2389 else if (Store[x][y] == EL_MORAST_LEER)
2392 Feld[x][y] = EL_MORAST_LEER;
2394 else if (Store[x][y] == EL_SIEB_VOLL)
2397 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT);
2399 else if (Store[x][y] == EL_SIEB_LEER)
2401 Store[x][y] = Store2[x][y] = 0;
2402 Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT);
2404 else if (Store[x][y] == EL_SIEB2_VOLL)
2407 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2409 else if (Store[x][y] == EL_SIEB2_LEER)
2411 Store[x][y] = Store2[x][y] = 0;
2412 Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2414 else if (Store[x][y] == EL_SALZSAEURE)
2417 Feld[newx][newy] = EL_SALZSAEURE;
2418 element = EL_SALZSAEURE;
2420 else if (Store[x][y] == EL_AMOEBE_NASS)
2423 Feld[x][y] = EL_AMOEBE_NASS;
2426 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2427 MovDelay[newx][newy] = 0;
2429 if (!CAN_MOVE(element))
2430 MovDir[newx][newy] = 0;
2432 DrawLevelField(x, y);
2433 DrawLevelField(newx, newy);
2435 Stop[newx][newy] = TRUE;
2436 JustHit[x][newy] = 3;
2438 if (DONT_TOUCH(element)) /* object may be nasty to player or others */
2440 TestIfBadThingHitsHero(newx, newy);
2441 TestIfBadThingHitsFriend(newx, newy);
2442 TestIfBadThingHitsOtherBadThing(newx, newy);
2444 else if (element == EL_PINGUIN)
2445 TestIfFriendHitsBadThing(newx, newy);
2447 if (CAN_SMASH(element) && direction == MV_DOWN &&
2448 (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
2451 else /* still moving on */
2452 DrawLevelField(x, y);
2455 int AmoebeNachbarNr(int ax, int ay)
2458 int element = Feld[ax][ay];
2460 static int xy[4][2] =
2470 int x = ax + xy[i][0];
2471 int y = ay + xy[i][1];
2473 if (!IN_LEV_FIELD(x, y))
2476 if (Feld[x][y] == element && AmoebaNr[x][y] > 0)
2477 group_nr = AmoebaNr[x][y];
2483 void AmoebenVereinigen(int ax, int ay)
2485 int i, x, y, xx, yy;
2486 int new_group_nr = AmoebaNr[ax][ay];
2487 static int xy[4][2] =
2495 if (new_group_nr == 0)
2503 if (!IN_LEV_FIELD(x, y))
2506 if ((Feld[x][y] == EL_AMOEBE_VOLL ||
2507 Feld[x][y] == EL_AMOEBE_BD ||
2508 Feld[x][y] == EL_AMOEBE_TOT) &&
2509 AmoebaNr[x][y] != new_group_nr)
2511 int old_group_nr = AmoebaNr[x][y];
2513 if (old_group_nr == 0)
2516 AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
2517 AmoebaCnt[old_group_nr] = 0;
2518 AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
2519 AmoebaCnt2[old_group_nr] = 0;
2521 for (yy=0; yy<lev_fieldy; yy++)
2523 for (xx=0; xx<lev_fieldx; xx++)
2525 if (AmoebaNr[xx][yy] == old_group_nr)
2526 AmoebaNr[xx][yy] = new_group_nr;
2533 void AmoebeUmwandeln(int ax, int ay)
2537 if (Feld[ax][ay] == EL_AMOEBE_TOT)
2539 int group_nr = AmoebaNr[ax][ay];
2544 printf("AmoebeUmwandeln(): ax = %d, ay = %d\n", ax, ay);
2545 printf("AmoebeUmwandeln(): This should never happen!\n");
2550 for (y=0; y<lev_fieldy; y++)
2552 for (x=0; x<lev_fieldx; x++)
2554 if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
2557 Feld[x][y] = EL_AMOEBA2DIAM;
2565 static int xy[4][2] =
2578 if (!IN_LEV_FIELD(x, y))
2581 if (Feld[x][y] == EL_AMOEBA2DIAM)
2587 void AmoebeUmwandelnBD(int ax, int ay, int new_element)
2590 int group_nr = AmoebaNr[ax][ay];
2591 boolean done = FALSE;
2596 printf("AmoebeUmwandelnBD(): ax = %d, ay = %d\n", ax, ay);
2597 printf("AmoebeUmwandelnBD(): This should never happen!\n");
2602 for (y=0; y<lev_fieldy; y++)
2604 for (x=0; x<lev_fieldx; x++)
2606 if (AmoebaNr[x][y] == group_nr &&
2607 (Feld[x][y] == EL_AMOEBE_TOT ||
2608 Feld[x][y] == EL_AMOEBE_BD ||
2609 Feld[x][y] == EL_AMOEBING))
2612 Feld[x][y] = new_element;
2613 InitField(x, y, FALSE);
2614 DrawLevelField(x, y);
2621 PlaySoundLevel(ax, ay,
2622 (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
2625 void AmoebeWaechst(int x, int y)
2627 static unsigned long sound_delay = 0;
2628 static unsigned long sound_delay_value = 0;
2630 if (!MovDelay[x][y]) /* start new growing cycle */
2634 if (DelayReached(&sound_delay, sound_delay_value))
2636 PlaySoundLevel(x, y, SND_AMOEBE);
2637 sound_delay_value = 30;
2641 if (MovDelay[x][y]) /* wait some time before growing bigger */
2644 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2645 DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING + 3 - MovDelay[x][y]/2);
2647 if (!MovDelay[x][y])
2649 Feld[x][y] = Store[x][y];
2651 DrawLevelField(x, y);
2656 void AmoebeAbleger(int ax, int ay)
2659 int element = Feld[ax][ay];
2660 int newax = ax, neway = ay;
2661 static int xy[4][2] =
2669 if (!level.tempo_amoebe)
2671 Feld[ax][ay] = EL_AMOEBE_TOT;
2672 DrawLevelField(ax, ay);
2676 if (!MovDelay[ax][ay]) /* start making new amoeba field */
2677 MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25 / (1 + level.tempo_amoebe));
2679 if (MovDelay[ax][ay]) /* wait some time before making new amoeba */
2682 if (MovDelay[ax][ay])
2686 if (element == EL_AMOEBE_NASS) /* object is an acid / amoeba drop */
2689 int x = ax + xy[start][0];
2690 int y = ay + xy[start][1];
2692 if (!IN_LEV_FIELD(x, y))
2695 if (IS_FREE(x, y) ||
2696 Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2702 if (newax == ax && neway == ay)
2705 else /* normal or "filled" (BD style) amoeba */
2708 boolean waiting_for_player = FALSE;
2712 int j = (start + i) % 4;
2713 int x = ax + xy[j][0];
2714 int y = ay + xy[j][1];
2716 if (!IN_LEV_FIELD(x, y))
2719 if (IS_FREE(x, y) ||
2720 Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2726 else if (IS_PLAYER(x, y))
2727 waiting_for_player = TRUE;
2730 if (newax == ax && neway == ay) /* amoeba cannot grow */
2732 if (i == 4 && (!waiting_for_player || game_emulation == EMU_BOULDERDASH))
2734 Feld[ax][ay] = EL_AMOEBE_TOT;
2735 DrawLevelField(ax, ay);
2736 AmoebaCnt[AmoebaNr[ax][ay]]--;
2738 if (AmoebaCnt[AmoebaNr[ax][ay]] <= 0) /* amoeba is completely dead */
2740 if (element == EL_AMOEBE_VOLL)
2741 AmoebeUmwandeln(ax, ay);
2742 else if (element == EL_AMOEBE_BD)
2743 AmoebeUmwandelnBD(ax, ay, level.amoebe_inhalt);
2748 else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
2750 /* amoeba gets larger by growing in some direction */
2752 int new_group_nr = AmoebaNr[ax][ay];
2755 if (new_group_nr == 0)
2757 printf("AmoebeAbleger(): newax = %d, neway = %d\n", newax, neway);
2758 printf("AmoebeAbleger(): This should never happen!\n");
2763 AmoebaNr[newax][neway] = new_group_nr;
2764 AmoebaCnt[new_group_nr]++;
2765 AmoebaCnt2[new_group_nr]++;
2767 /* if amoeba touches other amoeba(s) after growing, unify them */
2768 AmoebenVereinigen(newax, neway);
2770 if (element == EL_AMOEBE_BD && AmoebaCnt2[new_group_nr] >= 200)
2772 AmoebeUmwandelnBD(newax, neway, EL_FELSBROCKEN);
2778 if (element != EL_AMOEBE_NASS || neway < ay || !IS_FREE(newax, neway) ||
2779 (neway == lev_fieldy - 1 && newax != ax))
2781 Feld[newax][neway] = EL_AMOEBING;
2782 Store[newax][neway] = element;
2784 else if (neway == ay)
2785 Feld[newax][neway] = EL_TROPFEN;
2788 InitMovingField(ax, ay, MV_DOWN);
2789 Feld[ax][ay] = EL_TROPFEN;
2790 Store[ax][ay] = EL_AMOEBE_NASS;
2791 ContinueMoving(ax, ay);
2795 DrawLevelField(newax, neway);
2798 void Life(int ax, int ay)
2801 static int life[4] = { 2, 3, 3, 3 }; /* parameters for "game of life" */
2803 int element = Feld[ax][ay];
2808 if (!MovDelay[ax][ay]) /* start new "game of life" cycle */
2809 MovDelay[ax][ay] = life_time;
2811 if (MovDelay[ax][ay]) /* wait some time before next cycle */
2814 if (MovDelay[ax][ay])
2818 for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
2820 int xx = ax+x1, yy = ay+y1;
2823 if (!IN_LEV_FIELD(xx, yy))
2826 for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
2828 int x = xx+x2, y = yy+y2;
2830 if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
2833 if (((Feld[x][y] == element ||
2834 (element == EL_LIFE && IS_PLAYER(x, y))) &&
2836 (IS_FREE(x, y) && Stop[x][y]))
2840 if (xx == ax && yy == ay) /* field in the middle */
2842 if (nachbarn<life[0] || nachbarn>life[1])
2844 Feld[xx][yy] = EL_LEERRAUM;
2846 DrawLevelField(xx, yy);
2847 Stop[xx][yy] = TRUE;
2850 else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
2851 { /* free border field */
2852 if (nachbarn>=life[2] && nachbarn<=life[3])
2854 Feld[xx][yy] = element;
2855 MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
2857 DrawLevelField(xx, yy);
2858 Stop[xx][yy] = TRUE;
2864 void Ablenk(int x, int y)
2866 if (!MovDelay[x][y]) /* next animation frame */
2867 MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
2869 if (MovDelay[x][y]) /* wait some time before next frame */
2874 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2875 DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
2876 if (!(MovDelay[x][y]%4))
2877 PlaySoundLevel(x, y, SND_MIEP);
2882 Feld[x][y] = EL_ABLENK_AUS;
2883 DrawLevelField(x, y);
2884 if (ZX == x && ZY == y)
2888 void Birne(int x, int y)
2890 if (!MovDelay[x][y]) /* next animation frame */
2891 MovDelay[x][y] = 800;
2893 if (MovDelay[x][y]) /* wait some time before next frame */
2898 if (!(MovDelay[x][y]%5))
2900 if (!(MovDelay[x][y]%10))
2901 Feld[x][y]=EL_ABLENK_EIN;
2903 Feld[x][y]=EL_ABLENK_AUS;
2904 DrawLevelField(x, y);
2905 Feld[x][y]=EL_ABLENK_EIN;
2911 Feld[x][y]=EL_ABLENK_AUS;
2912 DrawLevelField(x, y);
2913 if (ZX == x && ZY == y)
2917 void Blubber(int x, int y)
2919 if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
2920 DrawLevelField(x, y-1);
2922 DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2925 void NussKnacken(int x, int y)
2927 if (!MovDelay[x][y]) /* next animation frame */
2930 if (MovDelay[x][y]) /* wait some time before next frame */
2933 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2934 DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2936 if (!MovDelay[x][y])
2938 Feld[x][y] = EL_EDELSTEIN;
2939 DrawLevelField(x, y);
2944 void SiebAktivieren(int x, int y, int typ)
2946 int graphic = (typ == 1 ? GFX_SIEB_VOLL : GFX_SIEB2_VOLL) + 3;
2948 DrawGraphicAnimation(x, y, graphic, 4, 4, ANIM_REVERSE);
2951 void AusgangstuerPruefen(int x, int y)
2953 if (!local_player->gems_still_needed &&
2954 !local_player->sokobanfields_still_needed &&
2955 !local_player->lights_still_needed)
2957 Feld[x][y] = EL_AUSGANG_ACT;
2959 PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
2960 (x > LEVELX(BX2) ? LEVELX(BX2) : x),
2961 y < LEVELY(BY1) ? LEVELY(BY1) :
2962 (y > LEVELY(BY2) ? LEVELY(BY2) : y),
2967 void AusgangstuerOeffnen(int x, int y)
2971 if (!MovDelay[x][y]) /* next animation frame */
2972 MovDelay[x][y] = 5*delay;
2974 if (MovDelay[x][y]) /* wait some time before next frame */
2979 tuer = MovDelay[x][y]/delay;
2980 if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2981 DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
2983 if (!MovDelay[x][y])
2985 Feld[x][y] = EL_AUSGANG_AUF;
2986 DrawLevelField(x, y);
2991 void AusgangstuerBlinken(int x, int y)
2993 DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
2996 void EdelsteinFunkeln(int x, int y)
2998 if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
3001 if (Feld[x][y] == EL_EDELSTEIN_BD)
3002 DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
3005 if (!MovDelay[x][y]) /* next animation frame */
3006 MovDelay[x][y] = 11 * !SimpleRND(500);
3008 if (MovDelay[x][y]) /* wait some time before next frame */
3012 if (setup.direct_draw && MovDelay[x][y])
3013 SetDrawtoField(DRAW_BUFFERED);
3015 DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
3019 int phase = (MovDelay[x][y]-1)/2;
3024 DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
3026 if (setup.direct_draw)
3030 dest_x = FX + SCREENX(x)*TILEX;
3031 dest_y = FY + SCREENY(y)*TILEY;
3033 XCopyArea(display, drawto_field, window, gc,
3034 dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
3035 SetDrawtoField(DRAW_DIRECT);
3042 void MauerWaechst(int x, int y)
3046 if (!MovDelay[x][y]) /* next animation frame */
3047 MovDelay[x][y] = 3*delay;
3049 if (MovDelay[x][y]) /* wait some time before next frame */
3054 phase = 2-MovDelay[x][y]/delay;
3055 if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3056 DrawGraphic(SCREENX(x), SCREENY(y),
3057 (MovDir[x][y] == MV_LEFT ? GFX_MAUER_LEFT :
3058 MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
3059 MovDir[x][y] == MV_UP ? GFX_MAUER_UP :
3060 GFX_MAUER_DOWN ) + phase);
3062 if (!MovDelay[x][y])
3064 if (MovDir[x][y] == MV_LEFT)
3066 if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
3067 DrawLevelField(x-1, y);
3069 else if (MovDir[x][y] == MV_RIGHT)
3071 if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
3072 DrawLevelField(x+1, y);
3074 else if (MovDir[x][y] == MV_UP)
3076 if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
3077 DrawLevelField(x, y-1);
3081 if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
3082 DrawLevelField(x, y+1);
3085 Feld[x][y] = Store[x][y];
3087 MovDir[x][y] = MV_NO_MOVING;
3088 DrawLevelField(x, y);
3093 void MauerAbleger(int ax, int ay)
3095 int element = Feld[ax][ay];
3096 boolean oben_frei = FALSE, unten_frei = FALSE;
3097 boolean links_frei = FALSE, rechts_frei = FALSE;
3098 boolean oben_massiv = FALSE, unten_massiv = FALSE;
3099 boolean links_massiv = FALSE, rechts_massiv = FALSE;
3101 if (!MovDelay[ax][ay]) /* start building new wall */
3102 MovDelay[ax][ay] = 6;
3104 if (MovDelay[ax][ay]) /* wait some time before building new wall */
3107 if (MovDelay[ax][ay])
3111 if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
3113 if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
3115 if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
3117 if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
3120 if (element == EL_MAUER_Y || element == EL_MAUER_XY)
3124 Feld[ax][ay-1] = EL_MAUERND;
3125 Store[ax][ay-1] = element;
3126 MovDir[ax][ay-1] = MV_UP;
3127 if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
3128 DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
3132 Feld[ax][ay+1] = EL_MAUERND;
3133 Store[ax][ay+1] = element;
3134 MovDir[ax][ay+1] = MV_DOWN;
3135 if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
3136 DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
3140 if (element == EL_MAUER_X || element == EL_MAUER_XY ||
3141 element == EL_MAUER_LEBT)
3145 Feld[ax-1][ay] = EL_MAUERND;
3146 Store[ax-1][ay] = element;
3147 MovDir[ax-1][ay] = MV_LEFT;
3148 if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
3149 DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
3153 Feld[ax+1][ay] = EL_MAUERND;
3154 Store[ax+1][ay] = element;
3155 MovDir[ax+1][ay] = MV_RIGHT;
3156 if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
3157 DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
3161 if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
3162 DrawLevelField(ax, ay);
3164 if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
3166 if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
3167 unten_massiv = TRUE;
3168 if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
3169 links_massiv = TRUE;
3170 if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
3171 rechts_massiv = TRUE;
3173 if (((oben_massiv && unten_massiv) ||
3174 element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
3175 ((links_massiv && rechts_massiv) ||
3176 element == EL_MAUER_Y))
3177 Feld[ax][ay] = EL_MAUERWERK;
3180 void CheckForDragon(int x, int y)
3183 boolean dragon_found = FALSE;
3184 static int xy[4][2] =
3196 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3198 if (IN_LEV_FIELD(xx, yy) &&
3199 (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
3201 if (Feld[xx][yy] == EL_DRACHE)
3202 dragon_found = TRUE;
3215 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
3217 if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
3219 Feld[xx][yy] = EL_LEERRAUM;
3220 DrawLevelField(xx, yy);
3229 static void CheckBuggyBase(int x, int y)
3231 int element = Feld[x][y];
3233 if (element == EL_SP_BUG)
3235 if (!MovDelay[x][y]) /* start activating buggy base */
3236 MovDelay[x][y] = 2 * FRAMES_PER_SECOND + RND(5 * FRAMES_PER_SECOND);
3238 if (MovDelay[x][y]) /* wait some time before activating base */
3241 if (MovDelay[x][y] < 5 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3242 DrawGraphic(SCREENX(x), SCREENY(y), GFX_SP_BUG_WARNING);
3246 Feld[x][y] = EL_SP_BUG_ACTIVE;
3249 else if (element == EL_SP_BUG_ACTIVE)
3251 if (!MovDelay[x][y]) /* start activating buggy base */
3252 MovDelay[x][y] = 1 * FRAMES_PER_SECOND + RND(1 * FRAMES_PER_SECOND);
3254 if (MovDelay[x][y]) /* wait some time before activating base */
3260 static int xy[4][2] =
3268 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
3269 DrawGraphic(SCREENX(x),SCREENY(y), GFX_SP_BUG_ACTIVE + SimpleRND(4));
3273 int xx = x + xy[i][0], yy = y + xy[i][1];
3275 if (IS_PLAYER(xx, yy))
3277 PlaySoundLevel(x, y, SND_SP_BUG);
3285 Feld[x][y] = EL_SP_BUG;
3286 DrawLevelField(x, y);
3291 static void PlayerActions(struct PlayerInfo *player, byte player_action)
3293 static byte stored_player_action[MAX_PLAYERS];
3294 static int num_stored_actions = 0;
3295 static boolean save_tape_entry = FALSE;
3296 boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
3297 int jx = player->jx, jy = player->jy;
3298 int left = player_action & JOY_LEFT;
3299 int right = player_action & JOY_RIGHT;
3300 int up = player_action & JOY_UP;
3301 int down = player_action & JOY_DOWN;
3302 int button1 = player_action & JOY_BUTTON_1;
3303 int button2 = player_action & JOY_BUTTON_2;
3304 int dx = (left ? -1 : right ? 1 : 0);
3305 int dy = (up ? -1 : down ? 1 : 0);
3307 stored_player_action[player->index_nr] = 0;
3308 num_stored_actions++;
3310 if (!player->active || player->gone || tape.pausing)
3315 save_tape_entry = TRUE;
3316 player->frame_reset_delay = 0;
3319 snapped = SnapField(player, dx, dy);
3323 bombed = PlaceBomb(player);
3324 moved = MoveFigure(player, dx, dy);
3327 if (tape.recording && (moved || snapped || bombed))
3329 if (bombed && !moved)
3330 player_action &= JOY_BUTTON;
3332 stored_player_action[player->index_nr] = player_action;
3335 /* this allows cycled sequences of PlayerActions() */
3336 if (num_stored_actions >= MAX_PLAYERS)
3338 TapeRecordAction(stored_player_action);
3339 num_stored_actions = 0;
3344 else if (tape.playing && snapped)
3345 SnapField(player, 0, 0); /* stop snapping */
3349 DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
3350 SnapField(player, 0, 0);
3351 if (++player->frame_reset_delay > MoveSpeed)
3355 if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
3357 TapeRecordAction(stored_player_action);
3358 num_stored_actions = 0;
3359 save_tape_entry = FALSE;
3362 if (tape.playing && !tape.pausing && !player_action &&
3363 tape.counter < tape.length)
3366 tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
3368 if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
3369 (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
3371 int dx = (next_joy == JOY_LEFT ? -1 : +1);
3373 if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
3375 int el = Feld[jx+dx][jy];
3376 int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10);
3378 if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
3380 player->MovDir = next_joy;
3381 player->Frame = FrameCounter % 4;
3382 player->Pushing = TRUE;
3391 static unsigned long action_delay = 0;
3392 unsigned long action_delay_value;
3393 int sieb_x = 0, sieb_y = 0;
3394 int i, x, y, element;
3395 byte *recorded_player_action;
3396 byte summarized_player_action = 0;
3398 if (game_status != PLAYING)
3401 action_delay_value =
3402 (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
3405 if (tape.playing && tape.fast_forward)
3409 sprintf(buf, "FFWD: %ld ms", action_delay_value);
3415 /* main game synchronization point */
3421 WaitUntilDelayReached(&action_delay, action_delay_value);
3424 while (!DelayReached(&action_delay, action_delay_value))
3428 sprintf(buf, "%ld %ld %ld",
3429 Counter(), action_delay, action_delay_value);
3432 print_debug("done");
3439 if (network_playing && !network_player_action_received)
3443 printf("DEBUG: try to get network player actions in time\n");
3448 /* last chance to get network player actions without main loop delay */
3452 if (game_status != PLAYING)
3455 if (!network_player_action_received)
3459 printf("DEBUG: failed to get network player actions in time\n");
3468 if (tape.pausing || (tape.playing && !TapePlayDelay()))
3470 else if (tape.recording)
3479 else if (tape.recording)
3482 recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
3484 for (i=0; i<MAX_PLAYERS; i++)
3486 summarized_player_action |= stored_player[i].action;
3488 if (!network_playing)
3489 stored_player[i].effective_action = stored_player[i].action;
3493 if (network_playing)
3494 SendToServer_MovePlayer(summarized_player_action);
3497 if (!options.network && !setup.team_mode)
3498 local_player->effective_action = summarized_player_action;
3500 for (i=0; i<MAX_PLAYERS; i++)
3502 int actual_player_action = stored_player[i].effective_action;
3504 if (recorded_player_action)
3505 actual_player_action = recorded_player_action[i];
3507 PlayerActions(&stored_player[i], actual_player_action);
3508 ScrollFigure(&stored_player[i], SCROLL_GO_ON);
3511 network_player_action_received = FALSE;
3513 ScrollScreen(NULL, SCROLL_GO_ON);
3517 if (tape.pausing || (tape.playing && !TapePlayDelay()))
3519 else if (tape.recording)
3529 if (TimeFrames == 0 && !local_player->gone)
3531 extern unsigned int last_RND();
3533 printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
3536 getStateCheckSum(TimePlayed));
3545 if (GameFrameDelay >= 500)
3546 printf("FrameCounter == %d\n", FrameCounter);
3557 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3560 if (JustHit[x][y]>0)
3564 if (IS_BLOCKED(x, y))
3568 Blocked2Moving(x, y, &oldx, &oldy);
3569 if (!IS_MOVING(oldx, oldy))
3571 printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
3572 printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
3573 printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
3574 printf("GameActions(): This should never happen!\n");
3580 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3582 element = Feld[x][y];
3584 if (IS_INACTIVE(element))
3587 if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
3591 if (IS_GEM(element))
3592 EdelsteinFunkeln(x, y);
3594 else if (IS_MOVING(x, y))
3595 ContinueMoving(x, y);
3596 else if (element == EL_DYNAMIT || element == EL_DYNABOMB)
3597 CheckDynamite(x, y);
3598 else if (element == EL_EXPLODING)
3599 Explode(x, y, Frame[x][y], EX_NORMAL);
3600 else if (element == EL_AMOEBING)
3601 AmoebeWaechst(x, y);
3602 else if (IS_AMOEBALIVE(element))
3603 AmoebeAbleger(x, y);
3604 else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
3606 else if (element == EL_ABLENK_EIN)
3608 else if (element == EL_SALZSAEURE)
3610 else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
3612 else if (element == EL_CRACKINGNUT)
3614 else if (element == EL_AUSGANG_ZU)
3615 AusgangstuerPruefen(x, y);
3616 else if (element == EL_AUSGANG_ACT)
3617 AusgangstuerOeffnen(x, y);
3618 else if (element == EL_AUSGANG_AUF)
3619 AusgangstuerBlinken(x, y);
3620 else if (element == EL_MAUERND)
3622 else if (element == EL_MAUER_LEBT ||
3623 element == EL_MAUER_X ||
3624 element == EL_MAUER_Y ||
3625 element == EL_MAUER_XY)
3627 else if (element == EL_BURNING)
3628 CheckForDragon(x, y);
3629 else if (element == EL_SP_BUG || element == EL_SP_BUG_ACTIVE)
3630 CheckBuggyBase(x, y);
3631 else if (element == EL_SP_TERMINAL)
3632 DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL, 7, 12, ANIM_NORMAL);
3633 else if (element == EL_SP_TERMINAL_ACTIVE)
3634 DrawGraphicAnimation(x, y, GFX2_SP_TERMINAL_ACTIVE, 7, 4, ANIM_NORMAL);
3638 boolean sieb = FALSE;
3639 int jx = local_player->jx, jy = local_player->jy;
3641 if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
3642 Store[x][y] == EL_SIEB_LEER)
3644 SiebAktivieren(x, y, 1);
3647 else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
3648 Store[x][y] == EL_SIEB2_LEER)
3650 SiebAktivieren(x, y, 2);
3654 /* play the element sound at the position nearest to the player */
3655 if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
3665 if (!(SiebCount % 4))
3666 PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
3673 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3675 element = Feld[x][y];
3676 if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
3678 Feld[x][y] = EL_SIEB_TOT;
3679 DrawLevelField(x, y);
3681 else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
3683 Feld[x][y] = EL_SIEB2_TOT;
3684 DrawLevelField(x, y);
3693 if (TimeFrames >= (1000 / GameFrameDelay) && !tape.pausing)
3698 if (tape.recording || tape.playing)
3699 DrawVideoDisplay(VIDEO_STATE_TIME_ON, TimePlayed);
3706 PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
3708 DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
3711 for (i=0; i<MAX_PLAYERS; i++)
3712 KillHero(&stored_player[i]);
3714 else if (level.time == 0) /* level without time limit */
3715 DrawText(DX_TIME, DY_TIME, int2str(TimePlayed, 3), FS_SMALL, FC_YELLOW);
3721 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
3723 int min_x = x, min_y = y, max_x = x, max_y = y;
3726 for (i=0; i<MAX_PLAYERS; i++)
3728 int jx = stored_player[i].jx, jy = stored_player[i].jy;
3730 if (!stored_player[i].active || stored_player[i].gone ||
3731 &stored_player[i] == player)
3734 min_x = MIN(min_x, jx);
3735 min_y = MIN(min_y, jy);
3736 max_x = MAX(max_x, jx);
3737 max_y = MAX(max_y, jy);
3740 return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3743 static boolean AllPlayersInVisibleScreen()
3747 for (i=0; i<MAX_PLAYERS; i++)
3749 int jx = stored_player[i].jx, jy = stored_player[i].jy;
3751 if (!stored_player[i].active || stored_player[i].gone)
3754 if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3761 void ScrollLevel(int dx, int dy)
3763 int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
3766 XCopyArea(display, drawto_field, drawto_field, gc,
3767 FX + TILEX*(dx == -1) - softscroll_offset,
3768 FY + TILEY*(dy == -1) - softscroll_offset,
3769 SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3770 SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3771 FX + TILEX*(dx == 1) - softscroll_offset,
3772 FY + TILEY*(dy == 1) - softscroll_offset);
3776 x = (dx == 1 ? BX1 : BX2);
3777 for (y=BY1; y<=BY2; y++)
3778 DrawScreenField(x, y);
3782 y = (dy == 1 ? BY1 : BY2);
3783 for (x=BX1; x<=BX2; x++)
3784 DrawScreenField(x, y);
3787 redraw_mask |= REDRAW_FIELD;
3790 boolean MoveFigureOneStep(struct PlayerInfo *player,
3791 int dx, int dy, int real_dx, int real_dy)
3793 int jx = player->jx, jy = player->jy;
3794 int new_jx = jx+dx, new_jy = jy+dy;
3798 if (player->gone || (!dx && !dy))
3799 return MF_NO_ACTION;
3801 player->MovDir = (dx < 0 ? MV_LEFT :
3804 dy > 0 ? MV_DOWN : MV_NO_MOVING);
3806 if (!IN_LEV_FIELD(new_jx, new_jy))
3807 return MF_NO_ACTION;
3809 if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
3810 return MF_NO_ACTION;
3812 element = MovingOrBlocked2Element(new_jx, new_jy);
3814 if (DONT_GO_TO(element))
3816 if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
3819 Feld[jx][jy] = EL_SPIELFIGUR;
3820 InitMovingField(jx, jy, MV_DOWN);
3821 Store[jx][jy] = EL_SALZSAEURE;
3822 ContinueMoving(jx, jy);
3831 can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
3832 if (can_move != MF_MOVING)
3835 StorePlayer[jx][jy] = 0;
3836 player->last_jx = jx;
3837 player->last_jy = jy;
3838 jx = player->jx = new_jx;
3839 jy = player->jy = new_jy;
3840 StorePlayer[jx][jy] = player->element_nr;
3842 player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / MoveSpeed);
3844 ScrollFigure(player, SCROLL_INIT);
3849 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
3851 int jx = player->jx, jy = player->jy;
3852 int old_jx = jx, old_jy = jy;
3853 int moved = MF_NO_ACTION;
3855 if (player->gone || (!dx && !dy))
3858 if (!FrameReached(&player->move_delay, MoveSpeed) && !tape.playing)
3863 /* should only happen if pre-1.2 tape recordings are played */
3864 /* this is only for backward compatibility */
3866 int old_move_speed = MoveSpeed;
3869 printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.2 LEVEL TAPES.\n");
3872 /* scroll remaining steps with finest movement resolution */
3875 while (player->MovPos)
3877 ScrollFigure(player, SCROLL_GO_ON);
3878 ScrollScreen(NULL, SCROLL_GO_ON);
3884 MoveSpeed = old_move_speed;
3887 if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
3889 if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
3890 moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
3894 if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
3895 moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
3901 if (moved & MF_MOVING && !ScreenMovPos &&
3902 (player == local_player || !options.network))
3904 int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
3905 int offset = (setup.scroll_delay ? 3 : 0);
3907 if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3909 /* actual player has left the screen -- scroll in that direction */
3910 if (jx != old_jx) /* player has moved horizontally */
3911 scroll_x += (jx - old_jx);
3912 else /* player has moved vertically */
3913 scroll_y += (jy - old_jy);
3917 if (jx != old_jx) /* player has moved horizontally */
3919 if ((player->MovDir == MV_LEFT && scroll_x > jx - MIDPOSX + offset) ||
3920 (player->MovDir == MV_RIGHT && scroll_x < jx - MIDPOSX - offset))
3921 scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
3923 /* don't scroll over playfield boundaries */
3924 if (scroll_x < SBX_Left || scroll_x > SBX_Right)
3925 scroll_x = (scroll_x < SBX_Left ? SBX_Left : SBX_Right);
3927 /* don't scroll more than one field at a time */
3928 scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3930 /* don't scroll against the player's moving direction */
3931 if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3932 (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3933 scroll_x = old_scroll_x;
3935 else /* player has moved vertically */
3937 if ((player->MovDir == MV_UP && scroll_y > jy - MIDPOSY + offset) ||
3938 (player->MovDir == MV_DOWN && scroll_y < jy - MIDPOSY - offset))
3939 scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
3941 /* don't scroll over playfield boundaries */
3942 if (scroll_y < SBY_Upper || scroll_y > SBY_Lower)
3943 scroll_y = (scroll_y < SBY_Upper ? SBY_Upper : SBY_Lower);
3945 /* don't scroll more than one field at a time */
3946 scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3948 /* don't scroll against the player's moving direction */
3949 if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3950 (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3951 scroll_y = old_scroll_y;
3955 if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3957 if (!options.network && !AllPlayersInVisibleScreen())
3959 scroll_x = old_scroll_x;
3960 scroll_y = old_scroll_y;
3964 ScrollScreen(player, SCROLL_INIT);
3965 ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3970 if (!(moved & MF_MOVING) && !player->Pushing)
3973 player->Frame = (player->Frame + 1) % 4;
3975 if (moved & MF_MOVING)
3977 if (old_jx != jx && old_jy == jy)
3978 player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
3979 else if (old_jx == jx && old_jy != jy)
3980 player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
3982 DrawLevelField(jx, jy); /* for "ErdreichAnbroeckeln()" */
3984 player->last_move_dir = player->MovDir;
3987 player->last_move_dir = MV_NO_MOVING;
3989 TestIfHeroHitsBadThing(jx, jy);
3997 void ScrollFigure(struct PlayerInfo *player, int mode)
3999 int jx = player->jx, jy = player->jy;
4000 int last_jx = player->last_jx, last_jy = player->last_jy;
4002 if (!player->active || player->gone || !player->MovPos)
4005 if (mode == SCROLL_INIT)
4007 player->actual_frame_counter = FrameCounter;
4008 player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
4010 if (Feld[last_jx][last_jy] == EL_LEERRAUM)
4011 Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
4016 else if (!FrameReached(&player->actual_frame_counter, 1))
4019 player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX / MoveSpeed;
4020 player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
4022 if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
4023 Feld[last_jx][last_jy] = EL_LEERRAUM;
4027 if (!player->MovPos)
4029 player->last_jx = jx;
4030 player->last_jy = jy;
4032 if (Feld[jx][jy] == EL_AUSGANG_AUF)
4036 if (!local_player->friends_still_needed)
4037 player->LevelSolved = player->GameOver = TRUE;
4042 void ScrollScreen(struct PlayerInfo *player, int mode)
4044 static unsigned long screen_frame_counter = 0;
4046 if (mode == SCROLL_INIT)
4048 screen_frame_counter = FrameCounter;
4049 ScreenMovDir = player->MovDir;
4050 ScreenMovPos = player->MovPos;
4051 ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4054 else if (!FrameReached(&screen_frame_counter, 1))
4059 ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX / MoveSpeed;
4060 ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
4061 redraw_mask |= REDRAW_FIELD;
4064 ScreenMovDir = MV_NO_MOVING;
4067 void TestIfGoodThingHitsBadThing(int goodx, int goody)
4069 int i, killx = goodx, killy = goody;
4070 static int xy[4][2] =
4077 static int harmless[4] =
4089 x = goodx + xy[i][0];
4090 y = goody + xy[i][1];
4091 if (!IN_LEV_FIELD(x, y))
4094 element = Feld[x][y];
4096 if (DONT_TOUCH(element))
4098 if (MovDir[x][y] == harmless[i])
4107 if (killx != goodx || killy != goody)
4109 if (IS_PLAYER(goodx, goody))
4110 KillHero(PLAYERINFO(goodx, goody));
4116 void TestIfBadThingHitsGoodThing(int badx, int bady)
4118 int i, killx = badx, killy = bady;
4119 static int xy[4][2] =
4126 static int harmless[4] =
4138 x = badx + xy[i][0];
4139 y = bady + xy[i][1];
4140 if (!IN_LEV_FIELD(x, y))
4143 element = Feld[x][y];
4145 if (IS_PLAYER(x, y))
4151 else if (element == EL_PINGUIN)
4153 if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
4162 if (killx != badx || killy != bady)
4164 if (IS_PLAYER(killx, killy))
4165 KillHero(PLAYERINFO(killx, killy));
4171 void TestIfHeroHitsBadThing(int x, int y)
4173 TestIfGoodThingHitsBadThing(x, y);
4176 void TestIfBadThingHitsHero(int x, int y)
4178 TestIfBadThingHitsGoodThing(x, y);
4181 void TestIfFriendHitsBadThing(int x, int y)
4183 TestIfGoodThingHitsBadThing(x, y);
4186 void TestIfBadThingHitsFriend(int x, int y)
4188 TestIfBadThingHitsGoodThing(x, y);
4191 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
4193 int i, killx = badx, killy = bady;
4194 static int xy[4][2] =
4208 if (!IN_LEV_FIELD(x, y))
4211 element = Feld[x][y];
4212 if (IS_AMOEBOID(element) || element == EL_LIFE ||
4213 element == EL_AMOEBING || element == EL_TROPFEN)
4221 if (killx != badx || killy != bady)
4225 void KillHero(struct PlayerInfo *player)
4227 int jx = player->jx, jy = player->jy;
4232 if (IS_PFORTE(Feld[jx][jy]))
4233 Feld[jx][jy] = EL_LEERRAUM;
4239 void BuryHero(struct PlayerInfo *player)
4241 int jx = player->jx, jy = player->jy;
4246 PlaySoundLevel(jx, jy, SND_AUTSCH);
4247 PlaySoundLevel(jx, jy, SND_LACHEN);
4249 player->GameOver = TRUE;
4253 void RemoveHero(struct PlayerInfo *player)
4255 int jx = player->jx, jy = player->jy;
4256 int i, found = FALSE;
4258 player->gone = TRUE;
4259 StorePlayer[jx][jy] = 0;
4261 for (i=0; i<MAX_PLAYERS; i++)
4262 if (stored_player[i].active && !stored_player[i].gone)
4266 AllPlayersGone = TRUE;
4272 int DigField(struct PlayerInfo *player,
4273 int x, int y, int real_dx, int real_dy, int mode)
4275 int jx = player->jx, jy = player->jy;
4276 int dx = x - jx, dy = y - jy;
4279 if (!player->MovPos)
4280 player->Pushing = FALSE;
4282 if (mode == DF_NO_PUSH)
4284 player->push_delay = 0;
4285 return MF_NO_ACTION;
4288 if (IS_MOVING(x, y) || IS_PLAYER(x, y))
4289 return MF_NO_ACTION;
4291 element = Feld[x][y];
4296 PlaySoundLevel(x, y, SND_EMPTY);
4300 Feld[x][y] = EL_LEERRAUM;
4301 PlaySoundLevel(x, y, SND_SCHLURF);
4306 Feld[x][y] = EL_LEERRAUM;
4307 PlaySoundLevel(x, y, SND_SP_BASE);
4311 case EL_EDELSTEIN_BD:
4312 case EL_EDELSTEIN_GELB:
4313 case EL_EDELSTEIN_ROT:
4314 case EL_EDELSTEIN_LILA:
4316 case EL_SP_INFOTRON:
4318 local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
4319 if (local_player->gems_still_needed < 0)
4320 local_player->gems_still_needed = 0;
4321 RaiseScoreElement(element);
4322 DrawText(DX_EMERALDS, DY_EMERALDS,
4323 int2str(local_player->gems_still_needed, 3),
4324 FS_SMALL, FC_YELLOW);
4325 if (element == EL_SP_INFOTRON)
4326 PlaySoundLevel(x, y, SND_SP_INFOTRON);
4328 PlaySoundLevel(x, y, SND_PONG);
4334 ScrollStepSize = TILEX/4;
4335 PlaySoundLevel(x, y, SND_PONG);
4338 case EL_DYNAMIT_AUS:
4339 case EL_SP_DISK_RED:
4342 RaiseScoreElement(EL_DYNAMIT);
4343 DrawText(DX_DYNAMITE, DY_DYNAMITE,
4344 int2str(local_player->dynamite, 3),
4345 FS_SMALL, FC_YELLOW);
4346 if (element == EL_SP_DISK_RED)
4347 PlaySoundLevel(x, y, SND_SP_INFOTRON);
4349 PlaySoundLevel(x, y, SND_PONG);
4352 case EL_DYNABOMB_NR:
4354 player->dynabomb_count++;
4355 player->dynabombs_left++;
4356 RaiseScoreElement(EL_DYNAMIT);
4357 PlaySoundLevel(x, y, SND_PONG);
4360 case EL_DYNABOMB_SZ:
4362 player->dynabomb_size++;
4363 RaiseScoreElement(EL_DYNAMIT);
4364 PlaySoundLevel(x, y, SND_PONG);
4367 case EL_DYNABOMB_XL:
4369 player->dynabomb_xl = TRUE;
4370 RaiseScoreElement(EL_DYNAMIT);
4371 PlaySoundLevel(x, y, SND_PONG);
4374 case EL_SCHLUESSEL1:
4375 case EL_SCHLUESSEL2:
4376 case EL_SCHLUESSEL3:
4377 case EL_SCHLUESSEL4:
4379 int key_nr = element-EL_SCHLUESSEL1;
4382 player->key[key_nr] = TRUE;
4383 RaiseScoreElement(EL_SCHLUESSEL);
4384 DrawMiniGraphicExt(drawto, gc,
4385 DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4386 GFX_SCHLUESSEL1+key_nr);
4387 DrawMiniGraphicExt(window, gc,
4388 DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
4389 GFX_SCHLUESSEL1+key_nr);
4390 PlaySoundLevel(x, y, SND_PONG);
4395 Feld[x][y] = EL_ABLENK_EIN;
4398 DrawLevelField(x, y);
4402 case EL_SP_TERMINAL:
4406 for (yy=0; yy<lev_fieldy; yy++)
4408 for (xx=0; xx<lev_fieldx; xx++)
4410 if (Feld[xx][yy] == EL_SP_DISK_YELLOW)
4412 else if (Feld[xx][yy] == EL_SP_TERMINAL)
4413 Feld[xx][yy] = EL_SP_TERMINAL_ACTIVE;
4422 if (local_player->gems_still_needed > 0)
4423 return MF_NO_ACTION;
4425 player->LevelSolved = player->GameOver = TRUE;
4426 PlaySoundStereo(SND_SP_EXIT, PSND_MAX_RIGHT);
4429 case EL_FELSBROCKEN:
4434 case EL_SP_DISK_ORANGE:
4435 if (dy || mode == DF_SNAP)
4436 return MF_NO_ACTION;
4438 player->Pushing = TRUE;
4440 if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
4441 return MF_NO_ACTION;
4445 if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4446 return MF_NO_ACTION;
4449 if (player->push_delay == 0)
4450 player->push_delay = FrameCounter;
4451 if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4453 return MF_NO_ACTION;
4456 Feld[x+dx][y+dy] = element;
4458 player->push_delay_value = 2+RND(8);
4460 DrawLevelField(x+dx, y+dy);
4461 if (element == EL_FELSBROCKEN)
4462 PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4463 else if (element == EL_KOKOSNUSS)
4464 PlaySoundLevel(x+dx, y+dy, SND_KNURK);
4465 else if (IS_SP_ELEMENT(element))
4466 PlaySoundLevel(x+dx, y+dy, SND_SP_ZONKPUSH);
4468 PlaySoundLevel(x+dx, y+dy, SND_KLOPF);
4475 if (!player->key[element-EL_PFORTE1])
4476 return MF_NO_ACTION;
4483 if (!player->key[element-EL_PFORTE1X])
4484 return MF_NO_ACTION;
4487 case EL_SP_PORT1_LEFT:
4488 case EL_SP_PORT2_LEFT:
4489 case EL_SP_PORT1_RIGHT:
4490 case EL_SP_PORT2_RIGHT:
4491 case EL_SP_PORT1_UP:
4492 case EL_SP_PORT2_UP:
4493 case EL_SP_PORT1_DOWN:
4494 case EL_SP_PORT2_DOWN:
4499 element != EL_SP_PORT1_LEFT &&
4500 element != EL_SP_PORT2_LEFT &&
4501 element != EL_SP_PORT_X &&
4502 element != EL_SP_PORT_XY) ||
4504 element != EL_SP_PORT1_RIGHT &&
4505 element != EL_SP_PORT2_RIGHT &&
4506 element != EL_SP_PORT_X &&
4507 element != EL_SP_PORT_XY) ||
4509 element != EL_SP_PORT1_UP &&
4510 element != EL_SP_PORT2_UP &&
4511 element != EL_SP_PORT_Y &&
4512 element != EL_SP_PORT_XY) ||
4514 element != EL_SP_PORT1_DOWN &&
4515 element != EL_SP_PORT2_DOWN &&
4516 element != EL_SP_PORT_Y &&
4517 element != EL_SP_PORT_XY) ||
4518 !IN_LEV_FIELD(x + dx, y + dy) ||
4519 !IS_FREE(x + dx, y + dy))
4520 return MF_NO_ACTION;
4524 case EL_AUSGANG_ACT:
4525 /* door is not (yet) open */
4526 return MF_NO_ACTION;
4529 case EL_AUSGANG_AUF:
4530 if (mode == DF_SNAP)
4531 return MF_NO_ACTION;
4533 PlaySoundLevel(x, y, SND_BUING);
4536 player->gone = TRUE;
4537 PlaySoundLevel(x, y, SND_BUING);
4539 if (!local_player->friends_still_needed)
4540 player->LevelSolved = player->GameOver = TRUE;
4546 Feld[x][y] = EL_BIRNE_EIN;
4547 local_player->lights_still_needed--;
4548 DrawLevelField(x, y);
4549 PlaySoundLevel(x, y, SND_DENG);
4554 Feld[x][y] = EL_ZEIT_LEER;
4556 DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4557 DrawLevelField(x, y);
4558 PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4562 case EL_SOKOBAN_FELD_LEER:
4565 case EL_SOKOBAN_FELD_VOLL:
4566 case EL_SOKOBAN_OBJEKT:
4568 case EL_SP_DISK_YELLOW:
4569 if (mode == DF_SNAP)
4570 return MF_NO_ACTION;
4572 player->Pushing = TRUE;
4574 if (!IN_LEV_FIELD(x+dx, y+dy)
4575 || (!IS_FREE(x+dx, y+dy)
4576 && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
4577 || !IS_SB_ELEMENT(element))))
4578 return MF_NO_ACTION;
4582 if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4583 return MF_NO_ACTION;
4585 else if (dy && real_dx)
4587 if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
4588 return MF_NO_ACTION;
4591 if (player->push_delay == 0)
4592 player->push_delay = FrameCounter;
4593 if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4595 return MF_NO_ACTION;
4597 if (IS_SB_ELEMENT(element))
4599 if (element == EL_SOKOBAN_FELD_VOLL)
4601 Feld[x][y] = EL_SOKOBAN_FELD_LEER;
4602 local_player->sokobanfields_still_needed++;
4607 if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
4609 Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
4610 local_player->sokobanfields_still_needed--;
4611 if (element == EL_SOKOBAN_OBJEKT)
4612 PlaySoundLevel(x, y, SND_DENG);
4615 Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
4620 Feld[x+dx][y+dy] = element;
4623 player->push_delay_value = 2;
4625 DrawLevelField(x, y);
4626 DrawLevelField(x+dx, y+dy);
4627 PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4629 if (IS_SB_ELEMENT(element) &&
4630 local_player->sokobanfields_still_needed == 0 &&
4631 game_emulation == EMU_SOKOBAN)
4633 player->LevelSolved = player->GameOver = TRUE;
4634 PlaySoundLevel(x, y, SND_BUING);
4646 return MF_NO_ACTION;
4649 player->push_delay = 0;
4654 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
4656 int jx = player->jx, jy = player->jy;
4657 int x = jx + dx, y = jy + dy;
4659 if (player->gone || !IN_LEV_FIELD(x, y))
4667 player->snapped = FALSE;
4671 if (player->snapped)
4674 player->MovDir = (dx < 0 ? MV_LEFT :
4677 dy > 0 ? MV_DOWN : MV_NO_MOVING);
4679 if (!DigField(player, x, y, 0, 0, DF_SNAP))
4682 player->snapped = TRUE;
4683 DrawLevelField(x, y);
4689 boolean PlaceBomb(struct PlayerInfo *player)
4691 int jx = player->jx, jy = player->jy;
4694 if (player->gone || player->MovPos)
4697 element = Feld[jx][jy];
4699 if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
4700 element == EL_DYNAMIT || element == EL_DYNABOMB ||
4701 element == EL_EXPLODING)
4704 if (element != EL_LEERRAUM)
4705 Store[jx][jy] = element;
4707 if (player->dynamite)
4709 Feld[jx][jy] = EL_DYNAMIT;
4710 MovDelay[jx][jy] = 96;
4712 DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
4713 FS_SMALL, FC_YELLOW);
4714 if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4716 if (game_emulation == EMU_SUPAPLEX)
4717 DrawGraphic(SCREENX(jx), SCREENY(jy), GFX_SP_DISK_RED);
4719 DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
4724 Feld[jx][jy] = EL_DYNABOMB;
4725 Store2[jx][jy] = player->element_nr; /* for DynaExplode() */
4726 MovDelay[jx][jy] = 96;
4727 player->dynabombs_left--;
4728 if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4729 DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
4735 void PlaySoundLevel(int x, int y, int sound_nr)
4737 int sx = SCREENX(x), sy = SCREENY(y);
4739 int silence_distance = 8;
4741 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
4742 (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
4745 if (!IN_LEV_FIELD(x, y) ||
4746 sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
4747 sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
4750 volume = PSND_MAX_VOLUME;
4753 stereo = (sx-SCR_FIELDX/2)*12;
4755 stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
4756 if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
4757 if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
4760 if (!IN_SCR_FIELD(sx, sy))
4762 int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
4763 int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
4765 volume -= volume*(dx > dy ? dx : dy)/silence_distance;
4768 PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
4771 void RaiseScore(int value)
4773 local_player->score += value;
4774 DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
4775 FS_SMALL, FC_YELLOW);
4778 void RaiseScoreElement(int element)
4783 case EL_EDELSTEIN_BD:
4784 case EL_EDELSTEIN_GELB:
4785 case EL_EDELSTEIN_ROT:
4786 case EL_EDELSTEIN_LILA:
4787 RaiseScore(level.score[SC_EDELSTEIN]);
4790 RaiseScore(level.score[SC_DIAMANT]);
4794 RaiseScore(level.score[SC_KAEFER]);
4798 RaiseScore(level.score[SC_FLIEGER]);
4802 RaiseScore(level.score[SC_MAMPFER]);
4805 RaiseScore(level.score[SC_ROBOT]);
4808 RaiseScore(level.score[SC_PACMAN]);
4811 RaiseScore(level.score[SC_KOKOSNUSS]);
4814 RaiseScore(level.score[SC_DYNAMIT]);
4817 RaiseScore(level.score[SC_SCHLUESSEL]);
4824 /* ---------- new game button stuff ---------------------------------------- */
4826 /* graphic position values for game buttons */
4827 #define GAME_BUTTON_XSIZE 30
4828 #define GAME_BUTTON_YSIZE 30
4829 #define GAME_BUTTON_XPOS 5
4830 #define GAME_BUTTON_YPOS 215
4831 #define SOUND_BUTTON_XPOS 5
4832 #define SOUND_BUTTON_YPOS (GAME_BUTTON_YPOS + GAME_BUTTON_YSIZE)
4834 #define GAME_BUTTON_STOP_XPOS (GAME_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
4835 #define GAME_BUTTON_PAUSE_XPOS (GAME_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
4836 #define GAME_BUTTON_PLAY_XPOS (GAME_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
4837 #define SOUND_BUTTON_MUSIC_XPOS (SOUND_BUTTON_XPOS + 0 * GAME_BUTTON_XSIZE)
4838 #define SOUND_BUTTON_LOOPS_XPOS (SOUND_BUTTON_XPOS + 1 * GAME_BUTTON_XSIZE)
4839 #define SOUND_BUTTON_SIMPLE_XPOS (SOUND_BUTTON_XPOS + 2 * GAME_BUTTON_XSIZE)
4846 } gamebutton_info[NUM_GAME_BUTTONS] =
4849 GAME_BUTTON_STOP_XPOS, GAME_BUTTON_YPOS,
4854 GAME_BUTTON_PAUSE_XPOS, GAME_BUTTON_YPOS,
4859 GAME_BUTTON_PLAY_XPOS, GAME_BUTTON_YPOS,
4864 SOUND_BUTTON_MUSIC_XPOS, SOUND_BUTTON_YPOS,
4865 SOUND_CTRL_ID_MUSIC,
4866 "background music on/off"
4869 SOUND_BUTTON_LOOPS_XPOS, SOUND_BUTTON_YPOS,
4870 SOUND_CTRL_ID_LOOPS,
4871 "sound loops on/off"
4874 SOUND_BUTTON_SIMPLE_XPOS, SOUND_BUTTON_YPOS,
4875 SOUND_CTRL_ID_SIMPLE,
4876 "normal sounds on/off"
4880 void CreateGameButtons()
4884 for (i=0; i<NUM_GAME_BUTTONS; i++)
4886 Pixmap gd_pixmap = pix[PIX_DOOR];
4887 struct GadgetInfo *gi;
4890 unsigned long event_mask;
4891 int gd_xoffset, gd_yoffset;
4892 int gd_x1, gd_x2, gd_y1, gd_y2;
4895 gd_xoffset = gamebutton_info[i].x;
4896 gd_yoffset = gamebutton_info[i].y;
4897 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
4898 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
4900 if (id == GAME_CTRL_ID_STOP ||
4901 id == GAME_CTRL_ID_PAUSE ||
4902 id == GAME_CTRL_ID_PLAY)
4904 button_type = GD_TYPE_NORMAL_BUTTON;
4906 event_mask = GD_EVENT_RELEASED;
4907 gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
4908 gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
4912 button_type = GD_TYPE_CHECK_BUTTON;
4914 ((id == SOUND_CTRL_ID_MUSIC && setup.sound_music) ||
4915 (id == SOUND_CTRL_ID_LOOPS && setup.sound_loops) ||
4916 (id == SOUND_CTRL_ID_SIMPLE && setup.sound_simple) ? TRUE : FALSE);
4917 event_mask = GD_EVENT_PRESSED;
4918 gd_y1 = DOOR_GFX_PAGEY1 + gd_yoffset;
4919 gd_y2 = DOOR_GFX_PAGEY1 + gd_yoffset - GAME_BUTTON_YSIZE;
4922 gi = CreateGadget(GDI_CUSTOM_ID, id,
4923 GDI_INFO_TEXT, gamebutton_info[i].infotext,
4924 GDI_X, DX + gd_xoffset,
4925 GDI_Y, DY + gd_yoffset,
4926 GDI_WIDTH, GAME_BUTTON_XSIZE,
4927 GDI_HEIGHT, GAME_BUTTON_YSIZE,
4928 GDI_TYPE, button_type,
4929 GDI_STATE, GD_BUTTON_UNPRESSED,
4930 GDI_CHECKED, checked,
4931 GDI_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y1,
4932 GDI_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y1,
4933 GDI_ALT_DESIGN_UNPRESSED, gd_pixmap, gd_x1, gd_y2,
4934 GDI_ALT_DESIGN_PRESSED, gd_pixmap, gd_x2, gd_y2,
4935 GDI_EVENT_MASK, event_mask,
4936 GDI_CALLBACK_ACTION, HandleGameButtons,
4940 Error(ERR_EXIT, "cannot create gadget");
4942 game_gadget[id] = gi;
4946 static void MapGameButtons()
4950 for (i=0; i<NUM_GAME_BUTTONS; i++)
4951 MapGadget(game_gadget[i]);
4954 void UnmapGameButtons()
4958 for (i=0; i<NUM_GAME_BUTTONS; i++)
4959 UnmapGadget(game_gadget[i]);
4962 static void HandleGameButtons(struct GadgetInfo *gi)
4964 int id = gi->custom_id;
4966 if (game_status != PLAYING)
4971 case GAME_CTRL_ID_STOP:
4974 CloseDoor(DOOR_CLOSE_1);
4975 game_status = MAINMENU;
4980 if (Request("Do you really want to quit the game ?",
4981 REQ_ASK | REQ_STAY_CLOSED))
4984 if (options.network)
4985 SendToServer_StopPlaying();
4989 game_status = MAINMENU;
4994 OpenDoor(DOOR_OPEN_1 | DOOR_COPY_BACK);
4997 case GAME_CTRL_ID_PAUSE:
4998 if (options.network)
5002 SendToServer_ContinuePlaying();
5004 SendToServer_PausePlaying();
5011 case GAME_CTRL_ID_PLAY:
5015 if (options.network)
5016 SendToServer_ContinuePlaying();
5020 tape.pausing = FALSE;
5021 DrawVideoDisplay(VIDEO_STATE_PAUSE_OFF,0);
5026 case SOUND_CTRL_ID_MUSIC:
5027 if (setup.sound_music)
5029 setup.sound_music = FALSE;
5030 FadeSound(background_loop[level_nr % num_bg_loops]);
5032 else if (sound_loops_allowed)
5034 setup.sound = setup.sound_music = TRUE;
5035 PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
5039 case SOUND_CTRL_ID_LOOPS:
5040 if (setup.sound_loops)
5041 setup.sound_loops = FALSE;
5042 else if (sound_loops_allowed)
5043 setup.sound = setup.sound_loops = TRUE;
5046 case SOUND_CTRL_ID_SIMPLE:
5047 if (setup.sound_simple)
5048 setup.sound_simple = FALSE;
5049 else if (sound_status==SOUND_AVAILABLE)
5050 setup.sound = setup.sound_simple = TRUE;