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 ***********************************************************/
27 static unsigned int getStateCheckSum(int counter)
30 unsigned int mult = 1;
31 unsigned int checksum = 0;
32 static short lastFeld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
33 static boolean first_game = TRUE;
35 for (y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
41 lastFeld[x][y] = Feld[x][y];
42 else if (lastFeld[x][y] != Feld[x][y])
43 printf("DIFF: [%d][%d]: lastFeld == %d != %d == Feld\n",
44 x, y, lastFeld[x][y], Feld[x][y]);
48 checksum += mult++ * Ur[x][y];
49 checksum += mult++ * Feld[x][y];
52 checksum += mult++ * MovPos[x][y];
53 checksum += mult++ * MovDir[x][y];
54 checksum += mult++ * MovDelay[x][y];
55 checksum += mult++ * Store[x][y];
56 checksum += mult++ * Store2[x][y];
57 checksum += mult++ * StorePlayer[x][y];
58 checksum += mult++ * Frame[x][y];
59 checksum += mult++ * AmoebaNr[x][y];
60 checksum += mult++ * JustHit[x][y];
61 checksum += mult++ * Stop[x][y];
65 if (counter == 3 && first_game)
72 void GetPlayerConfig()
74 if (sound_status == SOUND_OFF)
77 if (!sound_loops_allowed)
79 setup.sound_loops = FALSE;
80 setup.sound_music = FALSE;
83 setup.sound_simple = setup.sound;
91 boolean emulate_bd = TRUE; /* unless non-BOULDERDASH elements found */
92 boolean emulate_sb = TRUE; /* unless non-SOKOBAN elements found */
94 /* don't play tapes over network */
95 network_playing = (options.network && !tape.playing);
97 for (i=0; i<MAX_PLAYERS; i++)
99 struct PlayerInfo *player = &stored_player[i];
101 player->index_nr = i;
102 player->element_nr = EL_SPIELER1 + i;
104 player->present = FALSE;
105 player->active = FALSE;
108 player->effective_action = 0;
111 player->gems_still_needed = level.edelsteine;
112 player->sokobanfields_still_needed = 0;
113 player->lights_still_needed = 0;
114 player->friends_still_needed = 0;
117 player->key[j] = FALSE;
119 player->dynamite = 0;
120 player->dynabomb_count = 0;
121 player->dynabomb_size = 0;
122 player->dynabombs_left = 0;
123 player->dynabomb_xl = FALSE;
125 player->MovDir = MV_NO_MOVING;
127 player->Pushing = FALSE;
131 player->actual_frame_counter = 0;
133 player->frame_reset_delay = 0;
135 player->push_delay = 0;
136 player->push_delay_value = 5;
138 player->move_delay = 0;
139 player->last_move_dir = MV_NO_MOVING;
141 player->snapped = FALSE;
143 player->gone = FALSE;
145 player->last_jx = player->last_jy = 0;
146 player->jx = player->jy = 0;
148 DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
149 SnapField(player, 0, 0);
151 player->LevelSolved = FALSE;
152 player->GameOver = FALSE;
155 network_player_action_received = FALSE;
157 /* initial null action */
159 SendToServer_MovePlayer(MV_NO_MOVING);
166 TimeLeft = level.time;
168 ScreenMovDir = MV_NO_MOVING;
172 AllPlayersGone = SiebAktiv = FALSE;
174 for (i=0; i<MAX_NUM_AMOEBA; i++)
175 AmoebaCnt[i] = AmoebaCnt2[i] = 0;
177 for (x=0; x<lev_fieldx; x++)
179 for (y=0; y<lev_fieldy; y++)
181 Feld[x][y] = Ur[x][y];
182 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
183 Store[x][y] = Store2[x][y] = StorePlayer[x][y] = 0;
191 for(y=0; y<lev_fieldy; y++) for(x=0; x<lev_fieldx; x++)
193 if (emulate_bd && !IS_BD_ELEMENT(Feld[x][y]))
195 if (emulate_sb && !IS_SB_ELEMENT(Feld[x][y]))
201 Feld[x][y] = EL_SPIELER1;
208 struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_SPIELER1];
209 int jx = player->jx, jy = player->jy;
211 player->present = TRUE;
214 if (!network_playing || player->connected)
217 if (!options.network || player->connected)
219 player->active = TRUE;
221 /* remove potentially duplicate players */
222 if (StorePlayer[jx][jy] == Feld[x][y])
223 StorePlayer[jx][jy] = 0;
225 StorePlayer[x][y] = Feld[x][y];
227 printf("Player %d activated.\n", player->element_nr);
228 printf("[Local player is %d and currently %s.]\n",
229 local_player->element_nr,
230 local_player->active ? "active" : "not active");
233 Feld[x][y] = EL_LEERRAUM;
234 player->jx = player->last_jx = x;
235 player->jy = player->last_jy = y;
240 if (x < lev_fieldx-1 && Feld[x+1][y] == EL_SALZSAEURE)
241 Feld[x][y] = EL_BADEWANNE1;
242 else if (x > 0 && Feld[x-1][y] == EL_SALZSAEURE)
243 Feld[x][y] = EL_BADEWANNE2;
244 else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE1)
245 Feld[x][y] = EL_BADEWANNE3;
246 else if (y > 0 && Feld[x][y-1] == EL_SALZSAEURE)
247 Feld[x][y] = EL_BADEWANNE4;
248 else if (y > 0 && Feld[x][y-1] == EL_BADEWANNE2)
249 Feld[x][y] = EL_BADEWANNE5;
286 if (y == lev_fieldy - 1)
288 Feld[x][y] = EL_AMOEBING;
289 Store[x][y] = EL_AMOEBE_NASS;
296 local_player->lights_still_needed++;
298 case EL_SOKOBAN_FELD_LEER:
299 local_player->sokobanfields_still_needed++;
303 local_player->friends_still_needed++;
307 MovDir[x][y] = 1 << RND(4);
314 /* check if any connected player was not found in playfield */
315 for (i=0; i<MAX_PLAYERS; i++)
317 struct PlayerInfo *player = &stored_player[i];
319 if (player->connected && !player->present)
321 for (j=0; j<MAX_PLAYERS; j++)
323 struct PlayerInfo *some_player = &stored_player[j];
324 int jx = some_player->jx, jy = some_player->jy;
326 /* assign first free player found that is present in the playfield */
327 if (some_player->present && !some_player->connected)
329 player->present = TRUE;
330 player->active = TRUE;
331 some_player->present = FALSE;
333 StorePlayer[jx][jy] = player->element_nr;
334 player->jx = player->last_jx = jx;
335 player->jy = player->last_jy = jy;
343 /* when in single player mode, eliminate all but the first active player */
344 if (!options.network && !setup.team_mode)
346 for (i=0; i<MAX_PLAYERS; i++)
348 if (stored_player[i].active)
350 for (j=i+1; j<MAX_PLAYERS; j++)
352 struct PlayerInfo *player = &stored_player[j];
353 int jx = player->jx, jy = player->jy;
357 player->active = FALSE;
358 StorePlayer[jx][jy] = 0;
359 Feld[jx][jy] = EL_LEERRAUM;
366 for (i=0; i<MAX_PLAYERS; i++)
368 struct PlayerInfo *player = &stored_player[i];
370 printf("Player %d: present == %d, connected == %d, active == %d.\n",
375 if (local_player == player)
376 printf("Player %d is local player.\n", i+1);
380 game_emulation = (emulate_bd ? EMU_BOULDERDASH :
381 emulate_sb ? EMU_SOKOBAN : EMU_NONE);
383 scroll_x = scroll_y = -1;
384 if (local_player->jx >= MIDPOSX-1)
385 scroll_x = (local_player->jx <= lev_fieldx-MIDPOSX ?
386 local_player->jx - MIDPOSX :
387 lev_fieldx - SCR_FIELDX + 1);
388 if (local_player->jy >= MIDPOSY-1)
389 scroll_y = (local_player->jy <= lev_fieldy-MIDPOSY ?
390 local_player->jy - MIDPOSY :
391 lev_fieldy - SCR_FIELDY + 1);
393 CloseDoor(DOOR_CLOSE_1);
399 XCopyArea(display, pix[PIX_DOOR], pix[PIX_DB_DOOR], gc,
400 DOOR_GFX_PAGEX5, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
401 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
402 DrawTextExt(pix[PIX_DB_DOOR], gc,
403 DOOR_GFX_PAGEX1 + XX_LEVEL, DOOR_GFX_PAGEY1 + YY_LEVEL,
404 int2str(level_nr, 2), FS_SMALL, FC_YELLOW);
405 DrawTextExt(pix[PIX_DB_DOOR], gc,
406 DOOR_GFX_PAGEX1 + XX_EMERALDS, DOOR_GFX_PAGEY1 + YY_EMERALDS,
407 int2str(local_player->gems_still_needed,3), FS_SMALL, FC_YELLOW);
408 DrawTextExt(pix[PIX_DB_DOOR], gc,
409 DOOR_GFX_PAGEX1 + XX_DYNAMITE, DOOR_GFX_PAGEY1 + YY_DYNAMITE,
410 int2str(local_player->dynamite, 3), FS_SMALL, FC_YELLOW);
411 DrawTextExt(pix[PIX_DB_DOOR], gc,
412 DOOR_GFX_PAGEX1 + XX_SCORE, DOOR_GFX_PAGEY1 + YY_SCORE,
413 int2str(local_player->score, 5), FS_SMALL, FC_YELLOW);
414 DrawTextExt(pix[PIX_DB_DOOR], gc,
415 DOOR_GFX_PAGEX1 + XX_TIME, DOOR_GFX_PAGEY1 + YY_TIME,
416 int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
418 DrawGameButton(BUTTON_GAME_STOP);
419 DrawGameButton(BUTTON_GAME_PAUSE);
420 DrawGameButton(BUTTON_GAME_PLAY);
421 DrawSoundDisplay(BUTTON_SOUND_MUSIC | (setup.sound_music ? BUTTON_ON : 0));
422 DrawSoundDisplay(BUTTON_SOUND_LOOPS | (setup.sound_loops ? BUTTON_ON : 0));
423 DrawSoundDisplay(BUTTON_SOUND_SIMPLE | (setup.sound_simple ? BUTTON_ON : 0));
424 XCopyArea(display, drawto, pix[PIX_DB_DOOR], gc,
425 DX + GAME_CONTROL_XPOS, DY + GAME_CONTROL_YPOS,
426 GAME_CONTROL_XSIZE, 2 * GAME_CONTROL_YSIZE,
427 DOOR_GFX_PAGEX1 + GAME_CONTROL_XPOS,
428 DOOR_GFX_PAGEY1 + GAME_CONTROL_YPOS);
430 OpenDoor(DOOR_OPEN_1);
432 if (setup.sound_music)
433 PlaySoundLoop(background_loop[level_nr % num_bg_loops]);
435 XAutoRepeatOff(display);
439 printf("Spieler %d %saktiv.\n",
440 i+1, (stored_player[i].active ? "" : "nicht "));
444 void InitMovDir(int x, int y)
446 int i, element = Feld[x][y];
447 static int xy[4][2] =
454 static int direction[2][4] =
456 { MV_RIGHT, MV_UP, MV_LEFT, MV_DOWN },
457 { MV_LEFT, MV_DOWN, MV_RIGHT, MV_UP }
466 Feld[x][y] = EL_KAEFER;
467 MovDir[x][y] = direction[0][element - EL_KAEFER_R];
473 Feld[x][y] = EL_FLIEGER;
474 MovDir[x][y] = direction[0][element - EL_FLIEGER_R];
480 Feld[x][y] = EL_BUTTERFLY;
481 MovDir[x][y] = direction[0][element - EL_BUTTERFLY_R];
487 Feld[x][y] = EL_FIREFLY;
488 MovDir[x][y] = direction[0][element - EL_FIREFLY_R];
494 Feld[x][y] = EL_PACMAN;
495 MovDir[x][y] = direction[0][element - EL_PACMAN_R];
498 MovDir[x][y] = 1 << RND(4);
499 if (element != EL_KAEFER &&
500 element != EL_FLIEGER &&
501 element != EL_BUTTERFLY &&
502 element != EL_FIREFLY)
507 int x1 = x + xy[i][0];
508 int y1 = y + xy[i][1];
510 if (!IN_LEV_FIELD(x1, y1) || !IS_FREE(x1, y1))
512 if (element == EL_KAEFER || element == EL_BUTTERFLY)
514 MovDir[x][y] = direction[0][i];
517 else if (element == EL_FLIEGER || element == EL_FIREFLY)
519 MovDir[x][y] = direction[1][i];
528 void InitAmoebaNr(int x, int y)
531 int group_nr = AmoebeNachbarNr(x, y);
535 for (i=1; i<MAX_NUM_AMOEBA; i++)
537 if (AmoebaCnt[i] == 0)
545 AmoebaNr[x][y] = group_nr;
546 AmoebaCnt[group_nr]++;
547 AmoebaCnt2[group_nr]++;
553 int bumplevel = FALSE;
555 if (local_player->MovPos)
558 local_player->LevelSolved = FALSE;
562 if (setup.sound_loops)
563 PlaySoundExt(SND_SIRR, PSND_MAX_VOLUME, PSND_MAX_RIGHT, PSND_LOOP);
567 if (!setup.sound_loops)
568 PlaySoundStereo(SND_SIRR, PSND_MAX_RIGHT);
569 if (TimeLeft && !(TimeLeft % 10))
570 RaiseScore(level.score[SC_ZEITBONUS]);
571 if (TimeLeft > 100 && !(TimeLeft % 10))
575 DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
580 if (setup.sound_loops)
586 /* Hero disappears */
587 DrawLevelField(ExitX, ExitY);
593 CloseDoor(DOOR_CLOSE_1);
598 SaveTape(tape.level_nr); /* Ask to save tape */
601 if ((hi_pos = NewHiScore()) >= 0)
603 game_status = HALLOFFAME;
604 DrawHallOfFame(hi_pos);
605 if (bumplevel && TAPE_IS_EMPTY(tape))
610 game_status = MAINMENU;
611 if (bumplevel && TAPE_IS_EMPTY(tape))
626 if (!strcmp(setup.player_name, EMPTY_ALIAS) ||
627 local_player->score < highscore[MAX_SCORE_ENTRIES-1].Score)
630 for (k=0; k<MAX_SCORE_ENTRIES; k++)
632 if (local_player->score > highscore[k].Score)
634 /* Spieler kommt in Highscore-Liste */
636 if (k < MAX_SCORE_ENTRIES - 1)
638 int m = MAX_SCORE_ENTRIES - 1;
641 for (l=k; l<MAX_SCORE_ENTRIES; l++)
642 if (!strcmp(setup.player_name, highscore[l].Name))
644 if (m == k) /* Spieler überschreibt seine alte Position */
650 strcpy(highscore[l].Name, highscore[l - 1].Name);
651 highscore[l].Score = highscore[l - 1].Score;
658 strncpy(highscore[k].Name, setup.player_name, MAX_NAMELEN - 1);
659 highscore[k].Name[MAX_NAMELEN - 1] = '\0';
660 highscore[k].Score = local_player->score;
666 else if (!strncmp(setup.player_name, highscore[k].Name, MAX_NAMELEN - 1))
667 break; /* Spieler schon mit besserer Punktzahl in der Liste */
678 void InitMovingField(int x, int y, int direction)
680 int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
681 int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
683 MovDir[x][y] = direction;
684 MovDir[newx][newy] = direction;
685 if (Feld[newx][newy] == EL_LEERRAUM)
686 Feld[newx][newy] = EL_BLOCKED;
689 void Moving2Blocked(int x, int y, int *goes_to_x, int *goes_to_y)
691 int direction = MovDir[x][y];
692 int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
693 int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
699 void Blocked2Moving(int x, int y, int *comes_from_x, int *comes_from_y)
701 int oldx = x, oldy = y;
702 int direction = MovDir[x][y];
704 if (direction == MV_LEFT)
706 else if (direction == MV_RIGHT)
708 else if (direction == MV_UP)
710 else if (direction == MV_DOWN)
713 *comes_from_x = oldx;
714 *comes_from_y = oldy;
717 int MovingOrBlocked2Element(int x, int y)
719 int element = Feld[x][y];
721 if (element == EL_BLOCKED)
725 Blocked2Moving(x, y, &oldx, &oldy);
726 return Feld[oldx][oldy];
732 static void RemoveField(int x, int y)
734 Feld[x][y] = EL_LEERRAUM;
740 void RemoveMovingField(int x, int y)
742 int oldx = x, oldy = y, newx = x, newy = y;
744 if (Feld[x][y] != EL_BLOCKED && !IS_MOVING(x, y))
749 Moving2Blocked(x, y, &newx, &newy);
750 if (Feld[newx][newy] != EL_BLOCKED)
753 else if (Feld[x][y] == EL_BLOCKED)
755 Blocked2Moving(x, y, &oldx, &oldy);
756 if (!IS_MOVING(oldx, oldy))
760 if (Feld[x][y] == EL_BLOCKED &&
761 (Store[oldx][oldy] == EL_MORAST_LEER ||
762 Store[oldx][oldy] == EL_SIEB_LEER ||
763 Store[oldx][oldy] == EL_SIEB2_LEER ||
764 Store[oldx][oldy] == EL_AMOEBE_NASS))
766 Feld[oldx][oldy] = Store[oldx][oldy];
767 Store[oldx][oldy] = Store2[oldx][oldy] = 0;
770 Feld[oldx][oldy] = EL_LEERRAUM;
772 Feld[newx][newy] = EL_LEERRAUM;
773 MovPos[oldx][oldy] = MovDir[oldx][oldy] = MovDelay[oldx][oldy] = 0;
774 MovPos[newx][newy] = MovDir[newx][newy] = MovDelay[newx][newy] = 0;
776 DrawLevelField(oldx, oldy);
777 DrawLevelField(newx, newy);
780 void DrawDynamite(int x, int y)
782 int sx = SCREENX(x), sy = SCREENY(y);
783 int graphic = el2gfx(Feld[x][y]);
786 if (!IN_SCR_FIELD(sx, sy) || IS_PLAYER(x, y))
790 DrawGraphic(sx, sy, el2gfx(Store[x][y]));
792 if (Feld[x][y] == EL_DYNAMIT)
794 if ((phase = (96 - MovDelay[x][y]) / 12) > 6)
799 if ((phase = ((96 - MovDelay[x][y]) / 6) % 8) > 3)
804 DrawGraphicThruMask(sx, sy, graphic + phase);
806 DrawGraphic(sx, sy, graphic + phase);
809 void CheckDynamite(int x, int y)
811 if (MovDelay[x][y]) /* neues Dynamit / in Wartezustand */
816 if (!(MovDelay[x][y] % 12))
817 PlaySoundLevel(x, y, SND_ZISCH);
819 if (Feld[x][y] == EL_DYNAMIT && !(MovDelay[x][y] % 12))
821 else if (Feld[x][y] == EL_DYNABOMB && !(MovDelay[x][y] % 6))
828 StopSound(SND_ZISCH);
832 void Explode(int ex, int ey, int phase, int mode)
835 int num_phase = 9, delay = 2;
836 int last_phase = num_phase * delay;
837 int half_phase = (num_phase / 2) * delay;
839 if (phase == 0) /* Feld 'Store' initialisieren */
841 int center_element = Feld[ex][ey];
843 if (IS_MOVING(ex, ey) || IS_BLOCKED(ex, ey))
845 center_element = MovingOrBlocked2Element(ex, ey);
846 RemoveMovingField(ex, ey);
849 for (y=ey-1; y<ey+2; y++) for(x=ex-1; x<ex+2; x++)
851 int element = Feld[x][y];
853 if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
855 element = MovingOrBlocked2Element(x, y);
856 RemoveMovingField(x, y);
859 if (!IN_LEV_FIELD(x, y) || IS_MASSIV(element) || element == EL_BURNING)
862 if ((mode!=EX_NORMAL || center_element == EL_AMOEBA2DIAM) &&
866 if (element == EL_EXPLODING)
867 element = Store2[x][y];
869 if (IS_PLAYER(ex, ey))
871 switch(StorePlayer[ex][ey])
874 Store[x][y] = EL_EDELSTEIN_ROT;
877 Store[x][y] = EL_EDELSTEIN;
880 Store[x][y] = EL_EDELSTEIN_LILA;
884 Store[x][y] = EL_EDELSTEIN_GELB;
888 else if (center_element == EL_MAULWURF)
889 Store[x][y] = EL_EDELSTEIN_ROT;
890 else if (center_element == EL_PINGUIN)
891 Store[x][y] = EL_EDELSTEIN_LILA;
892 else if (center_element == EL_KAEFER)
893 Store[x][y] = ((x == ex && y == ey) ? EL_DIAMANT : EL_EDELSTEIN);
894 else if (center_element == EL_BUTTERFLY)
895 Store[x][y] = EL_EDELSTEIN_BD;
896 else if (center_element == EL_MAMPFER)
897 Store[x][y] = level.mampfer_inhalt[MampferNr][x-ex+1][y-ey+1];
898 else if (center_element == EL_AMOEBA2DIAM)
899 Store[x][y] = level.amoebe_inhalt;
900 else if (element == EL_ERZ_EDEL)
901 Store[x][y] = EL_EDELSTEIN;
902 else if (element == EL_ERZ_DIAM)
903 Store[x][y] = EL_DIAMANT;
904 else if (element == EL_ERZ_EDEL_BD)
905 Store[x][y] = EL_EDELSTEIN_BD;
906 else if (element == EL_ERZ_EDEL_GELB)
907 Store[x][y] = EL_EDELSTEIN_GELB;
908 else if (element == EL_ERZ_EDEL_ROT)
909 Store[x][y] = EL_EDELSTEIN_ROT;
910 else if (element == EL_ERZ_EDEL_LILA)
911 Store[x][y] = EL_EDELSTEIN_LILA;
912 else if (!IS_PFORTE(Store[x][y]))
913 Store[x][y] = EL_LEERRAUM;
915 if (x != ex || y != ey ||
916 center_element == EL_AMOEBA2DIAM || mode == EX_BORDER)
917 Store2[x][y] = element;
919 if (AmoebaNr[x][y] &&
920 (element == EL_AMOEBE_VOLL ||
921 element == EL_AMOEBE_BD ||
922 element == EL_AMOEBING))
924 AmoebaCnt[AmoebaNr[x][y]]--;
925 AmoebaCnt2[AmoebaNr[x][y]]--;
928 Feld[x][y] = EL_EXPLODING;
929 MovDir[x][y] = MovPos[x][y] = 0;
935 if (center_element == EL_MAMPFER)
936 MampferNr = (MampferNr+1) % 4;
947 Frame[x][y] = (phase<last_phase ? phase+1 : 0);
949 if (phase == half_phase)
951 int element = Store2[x][y];
954 KillHero(PLAYERINFO(x, y));
955 else if (IS_EXPLOSIVE(element))
957 Feld[x][y] = Store2[x][y];
961 else if (element == EL_AMOEBA2DIAM)
962 AmoebeUmwandeln(x, y);
965 if (phase == last_phase)
969 element = Feld[x][y] = Store[x][y];
970 Store[x][y] = Store2[x][y] = 0;
971 MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
972 if (CAN_MOVE(element) || COULD_MOVE(element))
974 DrawLevelField(x, y);
976 else if (!(phase%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
979 ErdreichAnbroeckeln(SCREENX(x), SCREENY(y));
981 DrawGraphic(SCREENX(x), SCREENY(y), GFX_EXPLOSION+(phase/delay-1));
985 void DynaExplode(int ex, int ey)
988 struct PlayerInfo *player = &stored_player[Store2[ex][ey] - EL_SPIELER1];
989 static int xy[4][2] =
997 Store2[ex][ey] = 0; /* delete player information */
999 Explode(ex, ey, 0, EX_CENTER);
1003 for (j=1; j<=player->dynabomb_size; j++)
1005 int x = ex+j*xy[i%4][0];
1006 int y = ey+j*xy[i%4][1];
1009 if (!IN_LEV_FIELD(x, y) || IS_MASSIV(Feld[x][y]))
1012 element = Feld[x][y];
1013 Explode(x, y, 0, EX_BORDER);
1015 if (element != EL_LEERRAUM &&
1016 element != EL_ERDREICH &&
1017 element != EL_EXPLODING &&
1018 !player->dynabomb_xl)
1023 player->dynabombs_left++;
1026 void Bang(int x, int y)
1028 int element = Feld[x][y];
1030 PlaySoundLevel(x, y, SND_ROAAAR);
1042 RaiseScoreElement(element);
1043 Explode(x, y, 0, EX_NORMAL);
1046 case EL_DYNABOMB_NR:
1047 case EL_DYNABOMB_SZ:
1048 case EL_DYNABOMB_XL:
1053 Explode(x, y, 0, EX_CENTER);
1056 Explode(x, y, 0, EX_NORMAL);
1061 void Blurb(int x, int y)
1063 int element = Feld[x][y];
1065 if (element!=EL_BLURB_LEFT && element!=EL_BLURB_RIGHT) /* Anfang */
1067 PlaySoundLevel(x, y, SND_BLURB);
1068 if (IN_LEV_FIELD(x-1, y) && IS_FREE(x-1, y) &&
1069 (!IN_LEV_FIELD(x-1, y-1) ||
1070 !CAN_FALL(MovingOrBlocked2Element(x-1, y-1))))
1072 Feld[x-1][y] = EL_BLURB_LEFT;
1074 if (IN_LEV_FIELD(x+1, y) && IS_FREE(x+1, y) &&
1075 (!IN_LEV_FIELD(x+1, y-1) ||
1076 !CAN_FALL(MovingOrBlocked2Element(x+1, y-1))))
1078 Feld[x+1][y] = EL_BLURB_RIGHT;
1083 int graphic = (element==EL_BLURB_LEFT ? GFX_BLURB_LEFT : GFX_BLURB_RIGHT);
1085 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
1088 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
1091 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1092 DrawGraphic(SCREENX(x), SCREENY(y), graphic+4-MovDelay[x][y]/2);
1094 if (!MovDelay[x][y])
1096 Feld[x][y] = EL_LEERRAUM;
1097 DrawLevelField(x, y);
1103 void Impact(int x, int y)
1105 boolean lastline = (y == lev_fieldy-1);
1106 boolean object_hit = FALSE;
1107 int element = Feld[x][y];
1110 /* Element darunter berührt? */
1113 if (Feld[x][y+1] == EL_PLAYER_IS_LEAVING)
1116 object_hit = (!IS_FREE(x, y+1) && (!IS_MOVING(x, y+1) ||
1117 MovDir[x][y+1]!=MV_DOWN ||
1118 MovPos[x][y+1]<=TILEY/2));
1120 smashed = MovingOrBlocked2Element(x, y+1);
1123 /* Auftreffendes Element fällt in Salzsäure */
1124 if (!lastline && smashed == EL_SALZSAEURE)
1130 /* Auftreffendes Element ist Bombe */
1131 if (element == EL_BOMBE && (lastline || object_hit))
1137 /* Auftreffendes Element ist Säuretropfen */
1138 if (element == EL_TROPFEN && (lastline || object_hit))
1140 if (object_hit && IS_PLAYER(x, y+1))
1141 KillHero(PLAYERINFO(x, y+1));
1142 else if (object_hit && (smashed == EL_MAULWURF || smashed == EL_PINGUIN))
1146 Feld[x][y] = EL_AMOEBING;
1147 Store[x][y] = EL_AMOEBE_NASS;
1152 /* Welches Element kriegt was auf die Rübe? */
1153 if (!lastline && object_hit)
1155 if (CAN_CHANGE(element) &&
1156 (smashed == EL_SIEB_LEER || smashed == EL_SIEB2_LEER) && !SiebAktiv)
1157 SiebAktiv = level.dauer_sieb * FRAMES_PER_SECOND;
1159 if (IS_PLAYER(x, y+1))
1161 KillHero(PLAYERINFO(x, y+1));
1164 else if (smashed == EL_MAULWURF || smashed == EL_PINGUIN)
1169 else if (element == EL_EDELSTEIN_BD)
1171 if (IS_ENEMY(smashed) && IS_BD_ELEMENT(smashed))
1177 else if (element == EL_FELSBROCKEN)
1179 if (IS_ENEMY(smashed) || smashed == EL_BOMBE || smashed == EL_SONDE ||
1180 smashed == EL_SCHWEIN || smashed == EL_DRACHE)
1185 else if (!IS_MOVING(x, y+1))
1187 if (smashed == EL_BIRNE_AUS || smashed == EL_BIRNE_EIN)
1192 else if (smashed == EL_KOKOSNUSS)
1194 Feld[x][y+1] = EL_CRACKINGNUT;
1195 PlaySoundLevel(x, y, SND_KNACK);
1196 RaiseScoreElement(EL_KOKOSNUSS);
1199 else if (smashed == EL_DIAMANT)
1201 Feld[x][y+1] = EL_LEERRAUM;
1202 PlaySoundLevel(x, y, SND_QUIRK);
1209 /* Geräusch beim Durchqueren des Siebes */
1211 (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1213 PlaySoundLevel(x, y, SND_QUIRK);
1217 /* Geräusch beim Auftreffen */
1218 if (lastline || object_hit)
1225 case EL_EDELSTEIN_BD:
1226 case EL_EDELSTEIN_GELB:
1227 case EL_EDELSTEIN_ROT:
1228 case EL_EDELSTEIN_LILA:
1235 case EL_FELSBROCKEN:
1239 case EL_SCHLUESSEL1:
1240 case EL_SCHLUESSEL2:
1241 case EL_SCHLUESSEL3:
1242 case EL_SCHLUESSEL4:
1255 PlaySoundLevel(x, y, sound);
1259 void TurnRound(int x, int y)
1271 { 0, 0 }, { 0, 0 }, { 0, 0 },
1276 int left, right, back;
1280 { MV_DOWN, MV_UP, MV_RIGHT },
1281 { MV_UP, MV_DOWN, MV_LEFT },
1283 { MV_LEFT, MV_RIGHT, MV_DOWN },
1284 { 0,0,0 }, { 0,0,0 }, { 0,0,0 },
1285 { MV_RIGHT, MV_LEFT, MV_UP }
1288 int element = Feld[x][y];
1289 int old_move_dir = MovDir[x][y];
1290 int left_dir = turn[old_move_dir].left;
1291 int right_dir = turn[old_move_dir].right;
1292 int back_dir = turn[old_move_dir].back;
1294 int left_dx = move_xy[left_dir].x, left_dy = move_xy[left_dir].y;
1295 int right_dx = move_xy[right_dir].x, right_dy = move_xy[right_dir].y;
1296 int move_dx = move_xy[old_move_dir].x, move_dy = move_xy[old_move_dir].y;
1297 int back_dx = move_xy[back_dir].x, back_dy = move_xy[back_dir].y;
1299 int left_x = x+left_dx, left_y = y+left_dy;
1300 int right_x = x+right_dx, right_y = y+right_dy;
1301 int move_x = x+move_dx, move_y = y+move_dy;
1303 if (element == EL_KAEFER || element == EL_BUTTERFLY)
1305 TestIfBadThingHitsOtherBadThing(x, y);
1307 if (IN_LEV_FIELD(right_x, right_y) &&
1308 IS_FREE_OR_PLAYER(right_x, right_y))
1309 MovDir[x][y] = right_dir;
1310 else if (!IN_LEV_FIELD(move_x, move_y) ||
1311 !IS_FREE_OR_PLAYER(move_x, move_y))
1312 MovDir[x][y] = left_dir;
1314 if (element == EL_KAEFER && MovDir[x][y] != old_move_dir)
1316 else if (element == EL_BUTTERFLY) /* && MovDir[x][y] == left_dir) */
1319 else if (element == EL_FLIEGER || element == EL_FIREFLY)
1321 TestIfBadThingHitsOtherBadThing(x, y);
1323 if (IN_LEV_FIELD(left_x, left_y) &&
1324 IS_FREE_OR_PLAYER(left_x, left_y))
1325 MovDir[x][y] = left_dir;
1326 else if (!IN_LEV_FIELD(move_x, move_y) ||
1327 !IS_FREE_OR_PLAYER(move_x, move_y))
1328 MovDir[x][y] = right_dir;
1330 if (element == EL_FLIEGER && MovDir[x][y] != old_move_dir)
1332 else if (element == EL_FIREFLY) /* && MovDir[x][y] == right_dir) */
1335 else if (element == EL_MAMPFER)
1337 boolean can_turn_left = FALSE, can_turn_right = FALSE;
1339 if (IN_LEV_FIELD(left_x, left_y) &&
1340 (IS_FREE_OR_PLAYER(left_x, left_y) ||
1341 Feld[left_x][left_y] == EL_DIAMANT))
1342 can_turn_left = TRUE;
1343 if (IN_LEV_FIELD(right_x, right_y) &&
1344 (IS_FREE_OR_PLAYER(right_x, right_y) ||
1345 Feld[right_x][right_y] == EL_DIAMANT))
1346 can_turn_right = TRUE;
1348 if (can_turn_left && can_turn_right)
1349 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1350 else if (can_turn_left)
1351 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1352 else if (can_turn_right)
1353 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1355 MovDir[x][y] = back_dir;
1357 MovDelay[x][y] = 16+16*RND(3);
1359 else if (element == EL_MAMPFER2)
1361 boolean can_turn_left = FALSE, can_turn_right = FALSE;
1363 if (IN_LEV_FIELD(left_x, left_y) &&
1364 (IS_FREE_OR_PLAYER(left_x, left_y) ||
1365 IS_MAMPF2(Feld[left_x][left_y])))
1366 can_turn_left = TRUE;
1367 if (IN_LEV_FIELD(right_x, right_y) &&
1368 (IS_FREE_OR_PLAYER(right_x, right_y) ||
1369 IS_MAMPF2(Feld[right_x][right_y])))
1370 can_turn_right = TRUE;
1372 if (can_turn_left && can_turn_right)
1373 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1374 else if (can_turn_left)
1375 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1376 else if (can_turn_right)
1377 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1379 MovDir[x][y] = back_dir;
1381 MovDelay[x][y] = 16+16*RND(3);
1383 else if (element == EL_PACMAN)
1385 boolean can_turn_left = FALSE, can_turn_right = FALSE;
1387 if (IN_LEV_FIELD(left_x, left_y) &&
1388 (IS_FREE_OR_PLAYER(left_x, left_y) ||
1389 IS_AMOEBOID(Feld[left_x][left_y])))
1390 can_turn_left = TRUE;
1391 if (IN_LEV_FIELD(right_x, right_y) &&
1392 (IS_FREE_OR_PLAYER(right_x, right_y) ||
1393 IS_AMOEBOID(Feld[right_x][right_y])))
1394 can_turn_right = TRUE;
1396 if (can_turn_left && can_turn_right)
1397 MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir);
1398 else if (can_turn_left)
1399 MovDir[x][y] = (RND(2) ? left_dir : back_dir);
1400 else if (can_turn_right)
1401 MovDir[x][y] = (RND(2) ? right_dir : back_dir);
1403 MovDir[x][y] = back_dir;
1405 MovDelay[x][y] = 6+RND(40);
1407 else if (element == EL_SCHWEIN)
1409 boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1410 boolean should_turn_left = FALSE, should_turn_right = FALSE;
1411 boolean should_move_on = FALSE;
1413 int rnd = RND(rnd_value);
1415 if (IN_LEV_FIELD(left_x, left_y) &&
1416 (IS_FREE(left_x, left_y) || IS_GEM(Feld[left_x][left_y])))
1417 can_turn_left = TRUE;
1418 if (IN_LEV_FIELD(right_x, right_y) &&
1419 (IS_FREE(right_x, right_y) || IS_GEM(Feld[right_x][right_y])))
1420 can_turn_right = TRUE;
1421 if (IN_LEV_FIELD(move_x, move_y) &&
1422 (IS_FREE(move_x, move_y) || IS_GEM(Feld[move_x][move_y])))
1425 if (can_turn_left &&
1427 (IN_LEV_FIELD(x+back_dx+left_dx, y+back_dy+left_dy) &&
1428 !IS_FREE(x+back_dx+left_dx, y+back_dy+left_dy))))
1429 should_turn_left = TRUE;
1430 if (can_turn_right &&
1432 (IN_LEV_FIELD(x+back_dx+right_dx, y+back_dy+right_dy) &&
1433 !IS_FREE(x+back_dx+right_dx, y+back_dy+right_dy))))
1434 should_turn_right = TRUE;
1436 (!can_turn_left || !can_turn_right ||
1437 (IN_LEV_FIELD(x+move_dx+left_dx, y+move_dy+left_dy) &&
1438 !IS_FREE(x+move_dx+left_dx, y+move_dy+left_dy)) ||
1439 (IN_LEV_FIELD(x+move_dx+right_dx, y+move_dy+right_dy) &&
1440 !IS_FREE(x+move_dx+right_dx, y+move_dy+right_dy))))
1441 should_move_on = TRUE;
1443 if (should_turn_left || should_turn_right || should_move_on)
1445 if (should_turn_left && should_turn_right && should_move_on)
1446 MovDir[x][y] = (rnd < rnd_value/3 ? left_dir :
1447 rnd < 2*rnd_value/3 ? right_dir :
1449 else if (should_turn_left && should_turn_right)
1450 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1451 else if (should_turn_left && should_move_on)
1452 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : old_move_dir);
1453 else if (should_turn_right && should_move_on)
1454 MovDir[x][y] = (rnd < rnd_value/2 ? right_dir : old_move_dir);
1455 else if (should_turn_left)
1456 MovDir[x][y] = left_dir;
1457 else if (should_turn_right)
1458 MovDir[x][y] = right_dir;
1459 else if (should_move_on)
1460 MovDir[x][y] = old_move_dir;
1462 else if (can_move_on && rnd > rnd_value/8)
1463 MovDir[x][y] = old_move_dir;
1464 else if (can_turn_left && can_turn_right)
1465 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1466 else if (can_turn_left && rnd > rnd_value/8)
1467 MovDir[x][y] = left_dir;
1468 else if (can_turn_right && rnd > rnd_value/8)
1469 MovDir[x][y] = right_dir;
1471 MovDir[x][y] = back_dir;
1473 if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y) &&
1474 !IS_GEM(Feld[x+move_xy[MovDir[x][y]].x][y+move_xy[MovDir[x][y]].y]))
1475 MovDir[x][y] = old_move_dir;
1479 else if (element == EL_DRACHE)
1481 boolean can_turn_left = FALSE, can_turn_right = FALSE, can_move_on = FALSE;
1483 int rnd = RND(rnd_value);
1485 if (IN_LEV_FIELD(left_x, left_y) && IS_FREE(left_x, left_y))
1486 can_turn_left = TRUE;
1487 if (IN_LEV_FIELD(right_x, right_y) && IS_FREE(right_x, right_y))
1488 can_turn_right = TRUE;
1489 if (IN_LEV_FIELD(move_x, move_y) && IS_FREE(move_x, move_y))
1492 if (can_move_on && rnd > rnd_value/8)
1493 MovDir[x][y] = old_move_dir;
1494 else if (can_turn_left && can_turn_right)
1495 MovDir[x][y] = (rnd < rnd_value/2 ? left_dir : right_dir);
1496 else if (can_turn_left && rnd > rnd_value/8)
1497 MovDir[x][y] = left_dir;
1498 else if (can_turn_right && rnd > rnd_value/8)
1499 MovDir[x][y] = right_dir;
1501 MovDir[x][y] = back_dir;
1503 if (!IS_FREE(x+move_xy[MovDir[x][y]].x, y+move_xy[MovDir[x][y]].y))
1504 MovDir[x][y] = old_move_dir;
1508 else if (element == EL_ROBOT || element == EL_SONDE ||
1509 element == EL_MAULWURF || element == EL_PINGUIN)
1511 int attr_x = -1, attr_y = -1;
1522 for (i=0; i<MAX_PLAYERS; i++)
1524 struct PlayerInfo *player = &stored_player[i];
1525 int jx = player->jx, jy = player->jy;
1527 if (!player->active || player->gone)
1530 if (attr_x == -1 || ABS(jx-x)+ABS(jy-y) < ABS(attr_x-x)+ABS(attr_y-y))
1538 if (element == EL_ROBOT && ZX>=0 && ZY>=0)
1544 if (element == EL_MAULWURF || element == EL_PINGUIN)
1547 static int xy[4][2] =
1557 int ex = x + xy[i%4][0];
1558 int ey = y + xy[i%4][1];
1560 if (IN_LEV_FIELD(ex, ey) && Feld[ex][ey] == EL_AUSGANG_AUF)
1569 MovDir[x][y] = MV_NO_MOVING;
1571 MovDir[x][y] |= (AllPlayersGone ? MV_RIGHT : MV_LEFT);
1573 MovDir[x][y] |= (AllPlayersGone ? MV_LEFT : MV_RIGHT);
1575 MovDir[x][y] |= (AllPlayersGone ? MV_DOWN : MV_UP);
1577 MovDir[x][y] |= (AllPlayersGone ? MV_UP : MV_DOWN);
1579 if (element == EL_ROBOT)
1583 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1584 MovDir[x][y] &= (RND(2) ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1585 Moving2Blocked(x, y, &newx, &newy);
1587 if (IN_LEV_FIELD(newx, newy) && IS_FREE_OR_PLAYER(newx, newy))
1588 MovDelay[x][y] = 8+8*!RND(3);
1590 MovDelay[x][y] = 16;
1598 if ((MovDir[x][y]&(MV_LEFT|MV_RIGHT)) && (MovDir[x][y]&(MV_UP|MV_DOWN)))
1600 boolean first_horiz = RND(2);
1601 int new_move_dir = MovDir[x][y];
1604 new_move_dir & (first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1605 Moving2Blocked(x, y, &newx, &newy);
1607 if (IN_LEV_FIELD(newx, newy) &&
1608 (IS_FREE(newx, newy) ||
1609 Feld[newx][newy] == EL_SALZSAEURE ||
1610 ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1611 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1612 IS_MAMPF3(Feld[newx][newy])))))
1616 new_move_dir & (!first_horiz ? (MV_LEFT|MV_RIGHT) : (MV_UP|MV_DOWN));
1617 Moving2Blocked(x, y, &newx, &newy);
1619 if (IN_LEV_FIELD(newx, newy) &&
1620 (IS_FREE(newx, newy) ||
1621 Feld[newx][newy] == EL_SALZSAEURE ||
1622 ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1623 (Feld[newx][newy] == EL_AUSGANG_AUF ||
1624 IS_MAMPF3(Feld[newx][newy])))))
1627 MovDir[x][y] = old_move_dir;
1634 static boolean JustBeingPushed(int x, int y)
1638 for (i=0; i<MAX_PLAYERS; i++)
1640 struct PlayerInfo *player = &stored_player[i];
1642 if (player->active && !player->gone &&
1643 player->Pushing && player->MovPos)
1645 int next_jx = player->jx + (player->jx - player->last_jx);
1646 int next_jy = player->jy + (player->jy - player->last_jy);
1648 if (x == next_jx && y == next_jy)
1656 void StartMoving(int x, int y)
1658 int element = Feld[x][y];
1663 if (CAN_FALL(element) && y<lev_fieldy-1)
1665 if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
1666 if (JustBeingPushed(x, y))
1669 if (element == EL_MORAST_VOLL)
1671 if (IS_FREE(x, y+1))
1673 InitMovingField(x, y, MV_DOWN);
1674 Feld[x][y] = EL_FELSBROCKEN;
1675 Store[x][y] = EL_MORAST_LEER;
1677 else if (Feld[x][y+1] == EL_MORAST_LEER)
1679 if (!MovDelay[x][y])
1680 MovDelay[x][y] = TILEY + 1;
1689 Feld[x][y] = EL_MORAST_LEER;
1690 Feld[x][y+1] = EL_MORAST_VOLL;
1693 else if (element == EL_FELSBROCKEN && Feld[x][y+1] == EL_MORAST_LEER)
1695 InitMovingField(x, y, MV_DOWN);
1696 Store[x][y] = EL_MORAST_VOLL;
1698 else if (element == EL_SIEB_VOLL)
1700 if (IS_FREE(x, y+1))
1702 InitMovingField(x, y, MV_DOWN);
1703 Feld[x][y] = EL_CHANGED(Store2[x][y]);
1704 Store[x][y] = EL_SIEB_LEER;
1706 else if (Feld[x][y+1] == EL_SIEB_LEER)
1708 if (!MovDelay[x][y])
1709 MovDelay[x][y] = TILEY/4 + 1;
1718 Feld[x][y] = EL_SIEB_LEER;
1719 Feld[x][y+1] = EL_SIEB_VOLL;
1720 Store2[x][y+1] = EL_CHANGED(Store2[x][y]);
1724 else if (element == EL_SIEB2_VOLL)
1726 if (IS_FREE(x, y+1))
1728 InitMovingField(x, y, MV_DOWN);
1729 Feld[x][y] = EL_CHANGED2(Store2[x][y]);
1730 Store[x][y] = EL_SIEB2_LEER;
1732 else if (Feld[x][y+1] == EL_SIEB2_LEER)
1734 if (!MovDelay[x][y])
1735 MovDelay[x][y] = TILEY/4 + 1;
1744 Feld[x][y] = EL_SIEB2_LEER;
1745 Feld[x][y+1] = EL_SIEB2_VOLL;
1746 Store2[x][y+1] = EL_CHANGED2(Store2[x][y]);
1750 else if (SiebAktiv && CAN_CHANGE(element) &&
1751 (Feld[x][y+1] == EL_SIEB_LEER || Feld[x][y+1] == EL_SIEB2_LEER))
1753 InitMovingField(x, y, MV_DOWN);
1755 (Feld[x][y+1] == EL_SIEB_LEER ? EL_SIEB_VOLL : EL_SIEB2_VOLL);
1756 Store2[x][y+1] = element;
1758 else if (CAN_SMASH(element) && Feld[x][y+1] == EL_SALZSAEURE)
1761 InitMovingField(x, y, MV_DOWN);
1762 Store[x][y] = EL_SALZSAEURE;
1764 else if (CAN_SMASH(element) && Feld[x][y+1] == EL_BLOCKED && JustHit[x][y])
1768 else if (IS_FREE(x, y+1))
1770 InitMovingField(x, y, MV_DOWN);
1772 else if (element == EL_TROPFEN)
1774 Feld[x][y] = EL_AMOEBING;
1775 Store[x][y] = EL_AMOEBE_NASS;
1777 else if (IS_SLIPPERY(Feld[x][y+1]) && !Store[x][y+1])
1779 boolean left = (x>0 && IS_FREE(x-1, y) &&
1780 (IS_FREE(x-1, y+1) || Feld[x-1][y+1] == EL_SALZSAEURE));
1781 boolean right = (x<lev_fieldx-1 && IS_FREE(x+1, y) &&
1782 (IS_FREE(x+1, y+1) || Feld[x+1][y+1] == EL_SALZSAEURE));
1786 if (left && right && game_emulation != EMU_BOULDERDASH)
1787 left = !(right = RND(2));
1789 InitMovingField(x, y, left ? MV_LEFT : MV_RIGHT);
1793 else if (CAN_MOVE(element))
1797 if (element == EL_SONDE && JustBeingPushed(x, y))
1800 if (!MovDelay[x][y]) /* neuer Schritt / noch nicht gewartet */
1802 /* Alle Figuren, die nach jeden Schritt die Richtung wechseln können.
1803 * (MAMPFER, MAMPFER2 und PACMAN laufen bis zur nächsten Wand.)
1806 if (element!=EL_MAMPFER && element!=EL_MAMPFER2 && element!=EL_PACMAN)
1809 if (MovDelay[x][y] && (element == EL_KAEFER || element == EL_FLIEGER))
1810 DrawLevelField(x, y);
1814 if (MovDelay[x][y]) /* neuer Schritt / in Wartezustand */
1818 if (element == EL_ROBOT || element == EL_MAMPFER ||
1819 element == EL_MAMPFER2)
1821 int phase = MovDelay[x][y] % 8;
1826 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1827 DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(element)+phase);
1829 if ((element == EL_MAMPFER || element == EL_MAMPFER2)
1830 && MovDelay[x][y]%4 == 3)
1831 PlaySoundLevel(x, y, SND_NJAM);
1833 else if (element == EL_DRACHE)
1836 int dir = MovDir[x][y];
1837 int dx = (dir == MV_LEFT ? -1 : dir == MV_RIGHT ? +1 : 0);
1838 int dy = (dir == MV_UP ? -1 : dir == MV_DOWN ? +1 : 0);
1839 int graphic = (dir == MV_LEFT ? GFX_FLAMMEN_LEFT :
1840 dir == MV_RIGHT ? GFX_FLAMMEN_RIGHT :
1841 dir == MV_UP ? GFX_FLAMMEN_UP :
1842 dir == MV_DOWN ? GFX_FLAMMEN_DOWN : GFX_LEERRAUM);
1843 int phase = FrameCounter % 2;
1845 for (i=1; i<=3; i++)
1847 int xx = x + i*dx, yy = y + i*dy;
1848 int sx = SCREENX(xx), sy = SCREENY(yy);
1850 if (!IN_LEV_FIELD(xx, yy) ||
1851 IS_SOLID(Feld[xx][yy]) || Feld[xx][yy] == EL_EXPLODING)
1856 int flamed = MovingOrBlocked2Element(xx, yy);
1858 if (IS_ENEMY(flamed) || IS_EXPLOSIVE(flamed))
1861 RemoveMovingField(xx, yy);
1863 Feld[xx][yy] = EL_BURNING;
1864 if (IN_SCR_FIELD(sx, sy))
1865 DrawGraphic(sx, sy, graphic + phase*3 + i-1);
1869 if (Feld[xx][yy] == EL_BURNING)
1870 Feld[xx][yy] = EL_LEERRAUM;
1871 DrawLevelField(xx, yy);
1880 if (element == EL_KAEFER || element == EL_BUTTERFLY)
1882 PlaySoundLevel(x, y, SND_KLAPPER);
1884 else if (element == EL_FLIEGER || element == EL_FIREFLY)
1886 PlaySoundLevel(x, y, SND_ROEHR);
1889 /* neuer Schritt / Wartezustand beendet */
1891 Moving2Blocked(x, y, &newx, &newy); /* wohin soll's gehen? */
1893 if (IS_ENEMY(element) && IS_PLAYER(newx, newy))
1895 /* Spieler erwischt */
1897 KillHero(PLAYERINFO(newx, newy));
1900 else if ((element == EL_MAULWURF || element == EL_PINGUIN ||
1901 element == EL_ROBOT || element == EL_SONDE) &&
1902 IN_LEV_FIELD(newx, newy) &&
1903 MovDir[x][y] == MV_DOWN && Feld[newx][newy] == EL_SALZSAEURE)
1906 Store[x][y] = EL_SALZSAEURE;
1908 else if ((element == EL_MAULWURF || element == EL_PINGUIN) &&
1909 IN_LEV_FIELD(newx, newy))
1911 if (Feld[newx][newy] == EL_AUSGANG_AUF)
1913 Feld[x][y] = EL_LEERRAUM;
1914 DrawLevelField(x, y);
1916 PlaySoundLevel(newx, newy, SND_BUING);
1917 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1918 DrawGraphicThruMask(SCREENX(newx), SCREENY(newy), el2gfx(element));
1920 local_player->friends_still_needed--;
1921 if (!local_player->friends_still_needed &&
1922 !local_player->GameOver && AllPlayersGone)
1923 local_player->LevelSolved = local_player->GameOver = TRUE;
1927 else if (IS_MAMPF3(Feld[newx][newy]))
1929 if (DigField(local_player, newx, newy, 0, 0, DF_DIG) == MF_MOVING)
1930 DrawLevelField(newx, newy);
1932 MovDir[x][y] = MV_NO_MOVING;
1934 else if (!IS_FREE(newx, newy))
1936 if (IS_PLAYER(x, y))
1937 DrawPlayerField(x, y);
1939 DrawLevelField(x, y);
1943 else if (element == EL_SCHWEIN && IN_LEV_FIELD(newx, newy))
1945 if (IS_GEM(Feld[newx][newy]))
1947 if (IS_MOVING(newx, newy))
1948 RemoveMovingField(newx, newy);
1951 Feld[newx][newy] = EL_LEERRAUM;
1952 DrawLevelField(newx, newy);
1955 else if (!IS_FREE(newx, newy))
1957 if (IS_PLAYER(x, y))
1958 DrawPlayerField(x, y);
1960 DrawLevelField(x, y);
1964 else if (element == EL_DRACHE && IN_LEV_FIELD(newx, newy))
1966 if (!IS_FREE(newx, newy))
1968 if (IS_PLAYER(x, y))
1969 DrawPlayerField(x, y);
1971 DrawLevelField(x, y);
1976 boolean wanna_flame = !RND(10);
1977 int dx = newx - x, dy = newy - y;
1978 int newx1 = newx+1*dx, newy1 = newy+1*dy;
1979 int newx2 = newx+2*dx, newy2 = newy+2*dy;
1980 int element1 = (IN_LEV_FIELD(newx1, newy1) ?
1981 MovingOrBlocked2Element(newx1, newy1) : EL_BETON);
1982 int element2 = (IN_LEV_FIELD(newx2, newy2) ?
1983 MovingOrBlocked2Element(newx2, newy2) : EL_BETON);
1985 if ((wanna_flame || IS_ENEMY(element1) || IS_ENEMY(element2)) &&
1986 element1 != EL_DRACHE && element2 != EL_DRACHE &&
1987 element1 != EL_BURNING && element2 != EL_BURNING)
1989 if (IS_PLAYER(x, y))
1990 DrawPlayerField(x, y);
1992 DrawLevelField(x, y);
1994 MovDelay[x][y] = 50;
1995 Feld[newx][newy] = EL_BURNING;
1996 if (IN_LEV_FIELD(newx1, newy1) && Feld[newx1][newy1] == EL_LEERRAUM)
1997 Feld[newx1][newy1] = EL_BURNING;
1998 if (IN_LEV_FIELD(newx2, newy2) && Feld[newx2][newy2] == EL_LEERRAUM)
1999 Feld[newx2][newy2] = EL_BURNING;
2004 else if (element == EL_MAMPFER && IN_LEV_FIELD(newx, newy) &&
2005 Feld[newx][newy] == EL_DIAMANT)
2007 if (IS_MOVING(newx, newy))
2008 RemoveMovingField(newx, newy);
2011 Feld[newx][newy] = EL_LEERRAUM;
2012 DrawLevelField(newx, newy);
2015 else if (element == EL_MAMPFER2 && IN_LEV_FIELD(newx, newy) &&
2016 IS_MAMPF2(Feld[newx][newy]))
2018 if (AmoebaNr[newx][newy])
2020 AmoebaCnt2[AmoebaNr[newx][newy]]--;
2021 if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2022 Feld[newx][newy] == EL_AMOEBE_BD)
2023 AmoebaCnt[AmoebaNr[newx][newy]]--;
2026 if (IS_MOVING(newx, newy))
2027 RemoveMovingField(newx, newy);
2030 Feld[newx][newy] = EL_LEERRAUM;
2031 DrawLevelField(newx, newy);
2034 else if (element == EL_PACMAN && IN_LEV_FIELD(newx, newy) &&
2035 IS_AMOEBOID(Feld[newx][newy]))
2037 if (AmoebaNr[newx][newy])
2039 AmoebaCnt2[AmoebaNr[newx][newy]]--;
2040 if (Feld[newx][newy] == EL_AMOEBE_VOLL ||
2041 Feld[newx][newy] == EL_AMOEBE_BD)
2042 AmoebaCnt[AmoebaNr[newx][newy]]--;
2045 Feld[newx][newy] = EL_LEERRAUM;
2046 DrawLevelField(newx, newy);
2048 else if (!IN_LEV_FIELD(newx, newy) || !IS_FREE(newx, newy))
2049 { /* gegen Wand gelaufen */
2052 if (element == EL_KAEFER || element == EL_FLIEGER)
2053 DrawLevelField(x, y);
2054 else if (element == EL_BUTTERFLY || element == EL_FIREFLY)
2055 DrawGraphicAnimation(x, y, el2gfx(element), 2, 4, ANIM_NORMAL);
2056 else if (element == EL_SONDE)
2057 DrawGraphicAnimation(x, y, GFX_SONDE_START, 8, 2, ANIM_NORMAL);
2062 if (element == EL_ROBOT && IN_SCR_FIELD(x, y))
2063 PlaySoundLevel(x, y, SND_SCHLURF);
2065 InitMovingField(x, y, MovDir[x][y]);
2069 ContinueMoving(x, y);
2072 void ContinueMoving(int x, int y)
2074 int element = Feld[x][y];
2075 int direction = MovDir[x][y];
2076 int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
2077 int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
2078 int horiz_move = (dx!=0);
2079 int newx = x + dx, newy = y + dy;
2080 int step = (horiz_move ? dx : dy) * TILEX/8;
2082 if (CAN_FALL(element) && horiz_move)
2084 else if (element == EL_TROPFEN)
2086 else if (Store[x][y] == EL_MORAST_VOLL || Store[x][y] == EL_MORAST_LEER)
2089 MovPos[x][y] += step;
2091 if (ABS(MovPos[x][y])>=TILEX) /* Zielfeld erreicht */
2093 Feld[x][y] = EL_LEERRAUM;
2094 Feld[newx][newy] = element;
2096 if (Store[x][y] == EL_MORAST_VOLL)
2099 Feld[newx][newy] = EL_MORAST_VOLL;
2100 element = EL_MORAST_VOLL;
2102 else if (Store[x][y] == EL_MORAST_LEER)
2105 Feld[x][y] = EL_MORAST_LEER;
2107 else if (Store[x][y] == EL_SIEB_VOLL)
2110 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB_VOLL : EL_SIEB_TOT);
2112 else if (Store[x][y] == EL_SIEB_LEER)
2114 Store[x][y] = Store2[x][y] = 0;
2115 Feld[x][y] = (SiebAktiv ? EL_SIEB_LEER : EL_SIEB_TOT);
2117 else if (Store[x][y] == EL_SIEB2_VOLL)
2120 element = Feld[newx][newy] = (SiebAktiv ? EL_SIEB2_VOLL : EL_SIEB2_TOT);
2122 else if (Store[x][y] == EL_SIEB2_LEER)
2124 Store[x][y] = Store2[x][y] = 0;
2125 Feld[x][y] = (SiebAktiv ? EL_SIEB2_LEER : EL_SIEB2_TOT);
2127 else if (Store[x][y] == EL_SALZSAEURE)
2130 Feld[newx][newy] = EL_SALZSAEURE;
2131 element = EL_SALZSAEURE;
2133 else if (Store[x][y] == EL_AMOEBE_NASS)
2136 Feld[x][y] = EL_AMOEBE_NASS;
2139 MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
2140 MovDelay[newx][newy] = 0;
2142 if (!CAN_MOVE(element))
2143 MovDir[newx][newy] = 0;
2145 DrawLevelField(x, y);
2146 DrawLevelField(newx, newy);
2148 Stop[newx][newy] = TRUE;
2149 JustHit[x][newy] = 3;
2151 if (DONT_TOUCH(element)) /* Käfer oder Flieger */
2153 TestIfBadThingHitsHero(newx, newy);
2154 TestIfBadThingHitsFriend(newx, newy);
2155 TestIfBadThingHitsOtherBadThing(newx, newy);
2157 else if (element == EL_PINGUIN)
2158 TestIfFriendHitsBadThing(newx, newy);
2160 if (CAN_SMASH(element) && direction == MV_DOWN &&
2161 (newy == lev_fieldy-1 || !IS_FREE(x, newy+1)))
2164 else /* noch in Bewegung */
2165 DrawLevelField(x, y);
2168 int AmoebeNachbarNr(int ax, int ay)
2171 int element = Feld[ax][ay];
2173 static int xy[4][2] =
2183 int x = ax+xy[i%4][0];
2184 int y = ay+xy[i%4][1];
2186 if (!IN_LEV_FIELD(x, y))
2189 if (Feld[x][y] == element && AmoebaNr[x][y]>0)
2190 group_nr = AmoebaNr[x][y];
2196 void AmoebenVereinigen(int ax, int ay)
2198 int i, x, y, xx, yy;
2199 int new_group_nr = AmoebaNr[ax][ay];
2200 static int xy[4][2] =
2216 if (!IN_LEV_FIELD(x, y))
2219 if ((Feld[x][y] == EL_AMOEBE_VOLL ||
2220 Feld[x][y] == EL_AMOEBE_BD ||
2221 Feld[x][y] == EL_AMOEBE_TOT) &&
2222 AmoebaNr[x][y] != new_group_nr)
2224 int old_group_nr = AmoebaNr[x][y];
2226 AmoebaCnt[new_group_nr] += AmoebaCnt[old_group_nr];
2227 AmoebaCnt[old_group_nr] = 0;
2228 AmoebaCnt2[new_group_nr] += AmoebaCnt2[old_group_nr];
2229 AmoebaCnt2[old_group_nr] = 0;
2231 for (yy=0; yy<lev_fieldy; yy++) for (xx=0; xx<lev_fieldx; xx++)
2232 if (AmoebaNr[xx][yy] == old_group_nr)
2233 AmoebaNr[xx][yy] = new_group_nr;
2238 void AmoebeUmwandeln(int ax, int ay)
2241 int group_nr = AmoebaNr[ax][ay];
2242 static int xy[4][2] =
2250 if (Feld[ax][ay] == EL_AMOEBE_TOT)
2252 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
2254 if (Feld[x][y] == EL_AMOEBE_TOT && AmoebaNr[x][y] == group_nr)
2257 Feld[x][y] = EL_AMOEBA2DIAM;
2269 if (!IN_LEV_FIELD(x, y))
2272 if (Feld[x][y] == EL_AMOEBA2DIAM)
2278 void AmoebeUmwandeln2(int ax, int ay, int new_element)
2281 int group_nr = AmoebaNr[ax][ay];
2282 boolean done = FALSE;
2284 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
2286 if (AmoebaNr[x][y] == group_nr &&
2287 (Feld[x][y] == EL_AMOEBE_TOT ||
2288 Feld[x][y] == EL_AMOEBE_BD ||
2289 Feld[x][y] == EL_AMOEBING))
2292 Feld[x][y] = new_element;
2293 DrawLevelField(x, y);
2299 PlaySoundLevel(ax, ay,
2300 (new_element == EL_FELSBROCKEN ? SND_KLOPF : SND_PLING));
2303 void AmoebeWaechst(int x, int y)
2305 static long sound_delay = 0;
2306 static int sound_delay_value = 0;
2308 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2312 if (DelayReached(&sound_delay, sound_delay_value))
2314 PlaySoundLevel(x, y, SND_AMOEBE);
2315 sound_delay_value = 30;
2319 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2322 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2323 DrawGraphic(SCREENX(x), SCREENY(y), GFX_AMOEBING+3-MovDelay[x][y]/2);
2325 if (!MovDelay[x][y])
2327 Feld[x][y] = Store[x][y];
2329 DrawLevelField(x, y);
2334 void AmoebeAbleger(int ax, int ay)
2337 int element = Feld[ax][ay];
2338 int newax = ax, neway = ay;
2339 static int xy[4][2] =
2347 if (!level.tempo_amoebe)
2349 Feld[ax][ay] = EL_AMOEBE_TOT;
2350 DrawLevelField(ax, ay);
2354 if (!MovDelay[ax][ay]) /* neue Amoebe / noch nicht gewartet */
2355 MovDelay[ax][ay] = RND(FRAMES_PER_SECOND * 25/(1+level.tempo_amoebe));
2357 if (MovDelay[ax][ay]) /* neue Amoebe / in Wartezustand */
2360 if (MovDelay[ax][ay])
2364 if (element == EL_AMOEBE_NASS) /* tropfende Amöbe */
2367 int x = ax+xy[start][0];
2368 int y = ay+xy[start][1];
2370 if (!IN_LEV_FIELD(x, y))
2373 if (IS_FREE(x, y) ||
2374 Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2380 if (newax == ax && neway == ay)
2383 else /* normale oder "gefüllte" Amöbe */
2386 boolean waiting_for_player = FALSE;
2390 int j = (start+i)%4;
2391 int x = ax+xy[j][0];
2392 int y = ay+xy[j][1];
2394 if (!IN_LEV_FIELD(x, y))
2397 if (IS_FREE(x, y) ||
2398 Feld[x][y] == EL_ERDREICH || Feld[x][y] == EL_MORAST_LEER)
2404 else if (IS_PLAYER(x, y))
2405 waiting_for_player = TRUE;
2408 if (newax == ax && neway == ay)
2410 if (i == 4 && !waiting_for_player)
2412 Feld[ax][ay] = EL_AMOEBE_TOT;
2413 DrawLevelField(ax, ay);
2414 AmoebaCnt[AmoebaNr[ax][ay]]--;
2416 if (AmoebaCnt[AmoebaNr[ax][ay]]<=0) /* Amöbe vollständig tot */
2418 if (element == EL_AMOEBE_VOLL)
2419 AmoebeUmwandeln(ax, ay);
2420 else if (element == EL_AMOEBE_BD)
2421 AmoebeUmwandeln2(ax, ay, level.amoebe_inhalt);
2426 else if (element == EL_AMOEBE_VOLL || element == EL_AMOEBE_BD)
2428 int new_group_nr = AmoebaNr[ax][ay];
2430 AmoebaNr[newax][neway] = new_group_nr;
2431 AmoebaCnt[new_group_nr]++;
2432 AmoebaCnt2[new_group_nr]++;
2433 AmoebenVereinigen(newax, neway);
2435 if (AmoebaCnt2[new_group_nr] >= 200 && element == EL_AMOEBE_BD)
2437 AmoebeUmwandeln2(newax, neway, EL_FELSBROCKEN);
2443 if (element!=EL_AMOEBE_NASS || neway<ay || !IS_FREE(newax, neway) ||
2444 (neway == lev_fieldy-1 && newax!=ax))
2446 Feld[newax][neway] = EL_AMOEBING;
2447 Store[newax][neway] = element;
2449 else if (neway == ay)
2450 Feld[newax][neway] = EL_TROPFEN;
2453 InitMovingField(ax, ay, MV_DOWN);
2454 Feld[ax][ay] = EL_TROPFEN;
2455 Store[ax][ay] = EL_AMOEBE_NASS;
2456 ContinueMoving(ax, ay);
2460 DrawLevelField(newax, neway);
2463 void Life(int ax, int ay)
2466 static int life[4] = { 2, 3, 3, 3 }; /* "Life"-Parameter */
2468 int element = Feld[ax][ay];
2473 if (!MovDelay[ax][ay]) /* neue Phase / noch nicht gewartet */
2474 MovDelay[ax][ay] = life_time;
2476 if (MovDelay[ax][ay]) /* neue Phase / in Wartezustand */
2479 if (MovDelay[ax][ay])
2483 for (y1=-1; y1<2; y1++) for(x1=-1; x1<2; x1++)
2485 int xx = ax+x1, yy = ay+y1;
2488 if (!IN_LEV_FIELD(xx, yy))
2491 for (y2=-1; y2<2; y2++) for (x2=-1; x2<2; x2++)
2493 int x = xx+x2, y = yy+y2;
2495 if (!IN_LEV_FIELD(x, y) || (x == xx && y == yy))
2498 if (((Feld[x][y] == element ||
2499 (element == EL_LIFE && IS_PLAYER(x, y))) &&
2501 (IS_FREE(x, y) && Stop[x][y]))
2505 if (xx == ax && yy == ay) /* mittleres Feld mit Amoebe */
2507 if (nachbarn<life[0] || nachbarn>life[1])
2509 Feld[xx][yy] = EL_LEERRAUM;
2511 DrawLevelField(xx, yy);
2512 Stop[xx][yy] = TRUE;
2515 else if (IS_FREE(xx, yy) || Feld[xx][yy] == EL_ERDREICH)
2516 { /* Randfeld ohne Amoebe */
2517 if (nachbarn>=life[2] && nachbarn<=life[3])
2519 Feld[xx][yy] = element;
2520 MovDelay[xx][yy] = (element == EL_LIFE ? 0 : life_time-1);
2522 DrawLevelField(xx, yy);
2523 Stop[xx][yy] = TRUE;
2529 void Ablenk(int x, int y)
2531 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2532 MovDelay[x][y] = level.dauer_ablenk * FRAMES_PER_SECOND;
2534 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2539 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2540 DrawGraphic(SCREENX(x), SCREENY(y), GFX_ABLENK+MovDelay[x][y]%4);
2541 if (!(MovDelay[x][y]%4))
2542 PlaySoundLevel(x, y, SND_MIEP);
2547 Feld[x][y] = EL_ABLENK_AUS;
2548 DrawLevelField(x, y);
2549 if (ZX == x && ZY == y)
2553 void Birne(int x, int y)
2555 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2556 MovDelay[x][y] = 800;
2558 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2563 if (!(MovDelay[x][y]%5))
2565 if (!(MovDelay[x][y]%10))
2566 Feld[x][y]=EL_ABLENK_EIN;
2568 Feld[x][y]=EL_ABLENK_AUS;
2569 DrawLevelField(x, y);
2570 Feld[x][y]=EL_ABLENK_EIN;
2576 Feld[x][y]=EL_ABLENK_AUS;
2577 DrawLevelField(x, y);
2578 if (ZX == x && ZY == y)
2582 void Blubber(int x, int y)
2584 if (y > 0 && IS_MOVING(x, y-1) && MovDir[x][y-1] == MV_DOWN)
2585 DrawLevelField(x, y-1);
2587 DrawGraphicAnimation(x, y, GFX_GEBLUBBER, 4, 10, ANIM_NORMAL);
2590 void NussKnacken(int x, int y)
2592 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2595 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2598 if (MovDelay[x][y]/2 && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2599 DrawGraphic(SCREENX(x), SCREENY(y), GFX_CRACKINGNUT+3-MovDelay[x][y]/2);
2601 if (!MovDelay[x][y])
2603 Feld[x][y] = EL_EDELSTEIN;
2604 DrawLevelField(x, y);
2609 void SiebAktivieren(int x, int y, int typ)
2611 if (!(SiebAktiv % 4) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2612 DrawGraphic(SCREENX(x), SCREENY(y),
2613 (typ == 1 ? GFX_SIEB_VOLL :
2614 GFX_SIEB2_VOLL) + 3 - (SiebAktiv % 16) / 4);
2617 void AusgangstuerPruefen(int x, int y)
2619 if (!local_player->gems_still_needed &&
2620 !local_player->sokobanfields_still_needed &&
2621 !local_player->lights_still_needed)
2623 Feld[x][y] = EL_AUSGANG_ACT;
2625 PlaySoundLevel(x < LEVELX(BX1) ? LEVELX(BX1) :
2626 (x > LEVELX(BX2) ? LEVELX(BX2) : x),
2627 y < LEVELY(BY1) ? LEVELY(BY1) :
2628 (y > LEVELY(BY2) ? LEVELY(BY2) : y),
2633 void AusgangstuerOeffnen(int x, int y)
2637 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2638 MovDelay[x][y] = 5*delay;
2640 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2645 tuer = MovDelay[x][y]/delay;
2646 if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2647 DrawGraphic(SCREENX(x), SCREENY(y), GFX_AUSGANG_AUF-tuer);
2649 if (!MovDelay[x][y])
2651 Feld[x][y] = EL_AUSGANG_AUF;
2652 DrawLevelField(x, y);
2657 void AusgangstuerBlinken(int x, int y)
2659 DrawGraphicAnimation(x, y, GFX_AUSGANG_AUF, 4, 4, ANIM_OSCILLATE);
2662 void EdelsteinFunkeln(int x, int y)
2664 if (!IN_SCR_FIELD(SCREENX(x), SCREENY(y)) || IS_MOVING(x, y))
2667 if (Feld[x][y] == EL_EDELSTEIN_BD)
2668 DrawGraphicAnimation(x, y, GFX_EDELSTEIN_BD, 4, 4, ANIM_REVERSE);
2671 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2672 MovDelay[x][y] = 11 * !SimpleRND(500);
2674 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2678 if (setup.direct_draw && MovDelay[x][y])
2679 SetDrawtoField(DRAW_BUFFERED);
2681 DrawGraphic(SCREENX(x), SCREENY(y), el2gfx(Feld[x][y]));
2685 int phase = (MovDelay[x][y]-1)/2;
2690 DrawGraphicThruMask(SCREENX(x), SCREENY(y), GFX_FUNKELN_WEISS + phase);
2692 if (setup.direct_draw)
2696 dest_x = FX + SCREENX(x)*TILEX;
2697 dest_y = FY + SCREENY(y)*TILEY;
2699 XCopyArea(display, drawto_field, window, gc,
2700 dest_x, dest_y, TILEX, TILEY, dest_x, dest_y);
2701 SetDrawtoField(DRAW_DIRECT);
2708 void MauerWaechst(int x, int y)
2712 if (!MovDelay[x][y]) /* neue Phase / noch nicht gewartet */
2713 MovDelay[x][y] = 3*delay;
2715 if (MovDelay[x][y]) /* neue Phase / in Wartezustand */
2720 phase = 2-MovDelay[x][y]/delay;
2721 if (!(MovDelay[x][y]%delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
2722 DrawGraphic(SCREENX(x), SCREENY(y),
2723 (MovDir[x][y] == MV_LEFT ? GFX_MAUER_LEFT :
2724 MovDir[x][y] == MV_RIGHT ? GFX_MAUER_RIGHT :
2725 MovDir[x][y] == MV_UP ? GFX_MAUER_UP :
2726 GFX_MAUER_DOWN ) + phase);
2728 if (!MovDelay[x][y])
2730 if (MovDir[x][y] == MV_LEFT)
2732 if (IN_LEV_FIELD(x-1, y) && IS_MAUER(Feld[x-1][y]))
2733 DrawLevelField(x-1, y);
2735 else if (MovDir[x][y] == MV_RIGHT)
2737 if (IN_LEV_FIELD(x+1, y) && IS_MAUER(Feld[x+1][y]))
2738 DrawLevelField(x+1, y);
2740 else if (MovDir[x][y] == MV_UP)
2742 if (IN_LEV_FIELD(x, y-1) && IS_MAUER(Feld[x][y-1]))
2743 DrawLevelField(x, y-1);
2747 if (IN_LEV_FIELD(x, y+1) && IS_MAUER(Feld[x][y+1]))
2748 DrawLevelField(x, y+1);
2751 Feld[x][y] = Store[x][y];
2753 MovDir[x][y] = MV_NO_MOVING;
2754 DrawLevelField(x, y);
2759 void MauerAbleger(int ax, int ay)
2761 int element = Feld[ax][ay];
2762 boolean oben_frei = FALSE, unten_frei = FALSE;
2763 boolean links_frei = FALSE, rechts_frei = FALSE;
2764 boolean oben_massiv = FALSE, unten_massiv = FALSE;
2765 boolean links_massiv = FALSE, rechts_massiv = FALSE;
2767 if (!MovDelay[ax][ay]) /* neue Mauer / noch nicht gewartet */
2768 MovDelay[ax][ay] = 6;
2770 if (MovDelay[ax][ay]) /* neue Mauer / in Wartezustand */
2773 if (MovDelay[ax][ay])
2777 if (IN_LEV_FIELD(ax, ay-1) && IS_FREE(ax, ay-1))
2779 if (IN_LEV_FIELD(ax, ay+1) && IS_FREE(ax, ay+1))
2781 if (IN_LEV_FIELD(ax-1, ay) && IS_FREE(ax-1, ay))
2783 if (IN_LEV_FIELD(ax+1, ay) && IS_FREE(ax+1, ay))
2786 if (element == EL_MAUER_Y || element == EL_MAUER_XY)
2790 Feld[ax][ay-1] = EL_MAUERND;
2791 Store[ax][ay-1] = element;
2792 MovDir[ax][ay-1] = MV_UP;
2793 if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay-1)))
2794 DrawGraphic(SCREENX(ax), SCREENY(ay-1), GFX_MAUER_UP);
2798 Feld[ax][ay+1] = EL_MAUERND;
2799 Store[ax][ay+1] = element;
2800 MovDir[ax][ay+1] = MV_DOWN;
2801 if (IN_SCR_FIELD(SCREENX(ax), SCREENY(ay+1)))
2802 DrawGraphic(SCREENX(ax), SCREENY(ay+1), GFX_MAUER_DOWN);
2806 if (element == EL_MAUER_X || element == EL_MAUER_XY ||
2807 element == EL_MAUER_LEBT)
2811 Feld[ax-1][ay] = EL_MAUERND;
2812 Store[ax-1][ay] = element;
2813 MovDir[ax-1][ay] = MV_LEFT;
2814 if (IN_SCR_FIELD(SCREENX(ax-1), SCREENY(ay)))
2815 DrawGraphic(SCREENX(ax-1), SCREENY(ay), GFX_MAUER_LEFT);
2819 Feld[ax+1][ay] = EL_MAUERND;
2820 Store[ax+1][ay] = element;
2821 MovDir[ax+1][ay] = MV_RIGHT;
2822 if (IN_SCR_FIELD(SCREENX(ax+1), SCREENY(ay)))
2823 DrawGraphic(SCREENX(ax+1), SCREENY(ay), GFX_MAUER_RIGHT);
2827 if (element == EL_MAUER_LEBT && (links_frei || rechts_frei))
2828 DrawLevelField(ax, ay);
2830 if (!IN_LEV_FIELD(ax, ay-1) || IS_MAUER(Feld[ax][ay-1]))
2832 if (!IN_LEV_FIELD(ax, ay+1) || IS_MAUER(Feld[ax][ay+1]))
2833 unten_massiv = TRUE;
2834 if (!IN_LEV_FIELD(ax-1, ay) || IS_MAUER(Feld[ax-1][ay]))
2835 links_massiv = TRUE;
2836 if (!IN_LEV_FIELD(ax+1, ay) || IS_MAUER(Feld[ax+1][ay]))
2837 rechts_massiv = TRUE;
2839 if (((oben_massiv && unten_massiv) ||
2840 element == EL_MAUER_X || element == EL_MAUER_LEBT) &&
2841 ((links_massiv && rechts_massiv) ||
2842 element == EL_MAUER_Y))
2843 Feld[ax][ay] = EL_MAUERWERK;
2846 void CheckForDragon(int x, int y)
2849 boolean dragon_found = FALSE;
2850 static int xy[4][2] =
2862 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2864 if (IN_LEV_FIELD(xx, yy) &&
2865 (Feld[xx][yy] == EL_BURNING || Feld[xx][yy] == EL_DRACHE))
2867 if (Feld[xx][yy] == EL_DRACHE)
2868 dragon_found = TRUE;
2881 int xx = x + j*xy[i][0], yy = y + j*xy[i][1];
2883 if (IN_LEV_FIELD(xx, yy) && Feld[xx][yy] == EL_BURNING)
2885 Feld[xx][yy] = EL_LEERRAUM;
2886 DrawLevelField(xx, yy);
2895 static void PlayerActions(struct PlayerInfo *player, byte player_action)
2897 static byte stored_player_action[MAX_PLAYERS];
2898 static int num_stored_actions = 0;
2899 static boolean save_tape_entry = FALSE;
2900 boolean moved = FALSE, snapped = FALSE, bombed = FALSE;
2901 int jx = player->jx, jy = player->jy;
2902 int left = player_action & JOY_LEFT;
2903 int right = player_action & JOY_RIGHT;
2904 int up = player_action & JOY_UP;
2905 int down = player_action & JOY_DOWN;
2906 int button1 = player_action & JOY_BUTTON_1;
2907 int button2 = player_action & JOY_BUTTON_2;
2908 int dx = (left ? -1 : right ? 1 : 0);
2909 int dy = (up ? -1 : down ? 1 : 0);
2911 stored_player_action[player->index_nr] = 0;
2912 num_stored_actions++;
2914 if (!player->active || player->gone || tape.pausing)
2919 save_tape_entry = TRUE;
2920 player->frame_reset_delay = 0;
2923 snapped = SnapField(player, dx, dy);
2927 bombed = PlaceBomb(player);
2928 moved = MoveFigure(player, dx, dy);
2931 if (tape.recording && (moved || snapped || bombed))
2933 if (bombed && !moved)
2934 player_action &= JOY_BUTTON;
2936 stored_player_action[player->index_nr] = player_action;
2939 /* this allows cycled sequences of PlayerActions() */
2940 if (num_stored_actions >= MAX_PLAYERS)
2942 TapeRecordAction(stored_player_action);
2943 num_stored_actions = 0;
2948 else if (tape.playing && snapped)
2949 SnapField(player, 0, 0); /* stop snapping */
2953 DigField(player, 0, 0, 0, 0, DF_NO_PUSH);
2954 SnapField(player, 0, 0);
2955 if (++player->frame_reset_delay > MoveSpeed)
2959 if (tape.recording && num_stored_actions >= MAX_PLAYERS && save_tape_entry)
2961 TapeRecordAction(stored_player_action);
2962 num_stored_actions = 0;
2963 save_tape_entry = FALSE;
2966 if (tape.playing && !tape.pausing && !player_action &&
2967 tape.counter < tape.length)
2970 tape.pos[tape.counter].action[player->index_nr] & (JOY_LEFT|JOY_RIGHT);
2972 if ((next_joy == JOY_LEFT || next_joy == JOY_RIGHT) &&
2973 (player->MovDir != JOY_UP && player->MovDir != JOY_DOWN))
2975 int dx = (next_joy == JOY_LEFT ? -1 : +1);
2977 if (IN_LEV_FIELD(jx+dx, jy) && IS_PUSHABLE(Feld[jx+dx][jy]))
2979 int el = Feld[jx+dx][jy];
2980 int push_delay = (IS_SB_ELEMENT(el) || el == EL_SONDE ? 2 : 10);
2982 if (tape.delay_played + push_delay >= tape.pos[tape.counter].delay)
2984 player->MovDir = next_joy;
2985 player->Frame = FrameCounter % 4;
2986 player->Pushing = TRUE;
2995 static long action_delay = 0;
2996 long action_delay_value;
2997 int sieb_x = 0, sieb_y = 0;
2998 int i, x, y, element;
2999 byte *recorded_player_action;
3000 byte summarized_player_action = 0;
3002 if (game_status != PLAYING)
3005 action_delay_value =
3006 (tape.playing && tape.fast_forward ? FfwdFrameDelay : GameFrameDelay);
3008 /* main game synchronization point */
3009 WaitUntilDelayReached(&action_delay, action_delay_value);
3011 if (network_playing && !network_player_action_received)
3015 printf("DEBUG: try to get network player actions in time\n");
3019 /* last chance to get network player actions without main loop delay */
3022 if (game_status != PLAYING)
3025 if (!network_player_action_received)
3029 printf("DEBUG: failed to get network player actions in time\n");
3038 if (tape.pausing || (tape.playing && !TapePlayDelay()))
3040 else if (tape.recording)
3049 else if (tape.recording)
3052 recorded_player_action = (tape.playing ? TapePlayAction() : NULL);
3054 for (i=0; i<MAX_PLAYERS; i++)
3056 summarized_player_action |= stored_player[i].action;
3058 if (!network_playing)
3059 stored_player[i].effective_action = stored_player[i].action;
3062 if (network_playing)
3063 SendToServer_MovePlayer(summarized_player_action);
3065 if (!options.network && !setup.team_mode)
3066 local_player->effective_action = summarized_player_action;
3068 for (i=0; i<MAX_PLAYERS; i++)
3070 int actual_player_action = stored_player[i].effective_action;
3072 if (recorded_player_action)
3073 actual_player_action = recorded_player_action[i];
3075 PlayerActions(&stored_player[i], actual_player_action);
3076 ScrollFigure(&stored_player[i], SCROLL_GO_ON);
3079 network_player_action_received = FALSE;
3081 ScrollScreen(NULL, SCROLL_GO_ON);
3085 if (tape.pausing || (tape.playing && !TapePlayDelay()))
3087 else if (tape.recording)
3096 if (TimeFrames == 0 && !local_player->gone)
3098 extern unsigned int last_RND();
3100 printf("DEBUG: %03d last RND was %d \t [state checksum is %d]\n",
3101 level.time - TimeLeft,
3103 getStateCheckSum(level.time - TimeLeft));
3110 if (GameFrameDelay >= 500)
3111 printf("FrameCounter == %d\n", FrameCounter);
3121 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3124 if (JustHit[x][y]>0)
3128 if (IS_BLOCKED(x, y))
3132 Blocked2Moving(x, y, &oldx, &oldy);
3133 if (!IS_MOVING(oldx, oldy))
3135 printf("GameActions(): (BLOCKED=>MOVING) context corrupted!\n");
3136 printf("GameActions(): BLOCKED: x = %d, y = %d\n", x, y);
3137 printf("GameActions(): !MOVING: oldx = %d, oldy = %d\n", oldx, oldy);
3138 printf("GameActions(): This should never happen!\n");
3144 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3146 element = Feld[x][y];
3148 if (IS_INACTIVE(element))
3151 if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
3155 if (IS_GEM(element))
3156 EdelsteinFunkeln(x, y);
3158 else if (IS_MOVING(x, y))
3159 ContinueMoving(x, y);
3160 else if (element == EL_DYNAMIT || element == EL_DYNABOMB)
3161 CheckDynamite(x, y);
3162 else if (element == EL_EXPLODING)
3163 Explode(x, y, Frame[x][y], EX_NORMAL);
3164 else if (element == EL_AMOEBING)
3165 AmoebeWaechst(x, y);
3166 else if (IS_AMOEBALIVE(element))
3167 AmoebeAbleger(x, y);
3168 else if (element == EL_LIFE || element == EL_LIFE_ASYNC)
3170 else if (element == EL_ABLENK_EIN)
3172 else if (element == EL_SALZSAEURE)
3174 else if (element == EL_BLURB_LEFT || element == EL_BLURB_RIGHT)
3176 else if (element == EL_CRACKINGNUT)
3178 else if (element == EL_AUSGANG_ZU)
3179 AusgangstuerPruefen(x, y);
3180 else if (element == EL_AUSGANG_ACT)
3181 AusgangstuerOeffnen(x, y);
3182 else if (element == EL_AUSGANG_AUF)
3183 AusgangstuerBlinken(x, y);
3184 else if (element == EL_MAUERND)
3186 else if (element == EL_MAUER_LEBT ||
3187 element == EL_MAUER_X ||
3188 element == EL_MAUER_Y ||
3189 element == EL_MAUER_XY)
3191 else if (element == EL_BURNING)
3192 CheckForDragon(x, y);
3196 boolean sieb = FALSE;
3197 int jx = local_player->jx, jy = local_player->jy;
3199 if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL ||
3200 Store[x][y] == EL_SIEB_LEER)
3202 SiebAktivieren(x, y, 1);
3205 else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL ||
3206 Store[x][y] == EL_SIEB2_LEER)
3208 SiebAktivieren(x, y, 2);
3212 /* play the element sound at the position nearest to the player */
3213 if (sieb && ABS(x-jx)+ABS(y-jy) < ABS(sieb_x-jx)+ABS(sieb_y-jy))
3224 PlaySoundLevel(sieb_x, sieb_y, SND_MIEP);
3228 for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
3230 element = Feld[x][y];
3231 if (element == EL_SIEB_LEER || element == EL_SIEB_VOLL)
3233 Feld[x][y] = EL_SIEB_TOT;
3234 DrawLevelField(x, y);
3236 else if (element == EL_SIEB2_LEER || element == EL_SIEB2_VOLL)
3238 Feld[x][y] = EL_SIEB2_TOT;
3239 DrawLevelField(x, y);
3245 if (TimeLeft>0 && TimeFrames>=(1000/GameFrameDelay) && !tape.pausing)
3250 if (tape.recording || tape.playing)
3251 DrawVideoDisplay(VIDEO_STATE_TIME_ON, level.time-TimeLeft);
3254 PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
3256 DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
3259 for (i=0; i<MAX_PLAYERS; i++)
3260 KillHero(&stored_player[i]);
3266 static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
3268 int min_x = x, min_y = y, max_x = x, max_y = y;
3271 for (i=0; i<MAX_PLAYERS; i++)
3273 int jx = stored_player[i].jx, jy = stored_player[i].jy;
3275 if (!stored_player[i].active || stored_player[i].gone ||
3276 &stored_player[i] == player)
3279 min_x = MIN(min_x, jx);
3280 min_y = MIN(min_y, jy);
3281 max_x = MAX(max_x, jx);
3282 max_y = MAX(max_y, jy);
3285 return (max_x - min_x < SCR_FIELDX && max_y - min_y < SCR_FIELDY);
3288 static boolean AllPlayersInVisibleScreen()
3292 for (i=0; i<MAX_PLAYERS; i++)
3294 int jx = stored_player[i].jx, jy = stored_player[i].jy;
3296 if (!stored_player[i].active || stored_player[i].gone)
3299 if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3306 void ScrollLevel(int dx, int dy)
3308 int softscroll_offset = (setup.soft_scrolling ? TILEX : 0);
3311 XCopyArea(display, drawto_field, drawto_field, gc,
3312 FX + TILEX*(dx == -1) - softscroll_offset,
3313 FY + TILEY*(dy == -1) - softscroll_offset,
3314 SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
3315 SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
3316 FX + TILEX*(dx == 1) - softscroll_offset,
3317 FY + TILEY*(dy == 1) - softscroll_offset);
3321 x = (dx == 1 ? BX1 : BX2);
3322 for (y=BY1; y<=BY2; y++)
3323 DrawScreenField(x, y);
3327 y = (dy == 1 ? BY1 : BY2);
3328 for (x=BX1; x<=BX2; x++)
3329 DrawScreenField(x, y);
3332 redraw_mask |= REDRAW_FIELD;
3335 boolean MoveFigureOneStep(struct PlayerInfo *player,
3336 int dx, int dy, int real_dx, int real_dy)
3338 int jx = player->jx, jy = player->jy;
3339 int new_jx = jx+dx, new_jy = jy+dy;
3343 if (player->gone || (!dx && !dy))
3344 return MF_NO_ACTION;
3346 player->MovDir = (dx < 0 ? MV_LEFT :
3349 dy > 0 ? MV_DOWN : MV_NO_MOVING);
3351 if (!IN_LEV_FIELD(new_jx, new_jy))
3352 return MF_NO_ACTION;
3354 if (!options.network && !AllPlayersInSight(player, new_jx, new_jy))
3355 return MF_NO_ACTION;
3357 element = MovingOrBlocked2Element(new_jx, new_jy);
3359 if (DONT_GO_TO(element))
3361 if (element == EL_SALZSAEURE && dx == 0 && dy == 1)
3364 Feld[jx][jy] = EL_SPIELFIGUR;
3365 InitMovingField(jx, jy, MV_DOWN);
3366 Store[jx][jy] = EL_SALZSAEURE;
3367 ContinueMoving(jx, jy);
3376 can_move = DigField(player, new_jx, new_jy, real_dx, real_dy, DF_DIG);
3377 if (can_move != MF_MOVING)
3380 StorePlayer[jx][jy] = 0;
3381 player->last_jx = jx;
3382 player->last_jy = jy;
3383 jx = player->jx = new_jx;
3384 jy = player->jy = new_jy;
3385 StorePlayer[jx][jy] = player->element_nr;
3387 player->MovPos = (dx > 0 || dy > 0 ? -1 : 1) * 7*TILEX/8;
3389 ScrollFigure(player, SCROLL_INIT);
3394 boolean MoveFigure(struct PlayerInfo *player, int dx, int dy)
3396 int jx = player->jx, jy = player->jy;
3397 int old_jx = jx, old_jy = jy;
3398 int moved = MF_NO_ACTION;
3400 if (player->gone || (!dx && !dy))
3403 if (!FrameReached(&player->move_delay, MoveSpeed) && !tape.playing)
3408 /* should only happen if pre-1.0 tape recordings are played */
3409 /* this is only for backward compatibility */
3412 printf("THIS SHOULD ONLY HAPPEN WITH PRE-1.0 LEVEL TAPES.\n");
3415 while (player->MovPos)
3417 ScrollFigure(player, SCROLL_GO_ON);
3418 ScrollScreen(NULL, SCROLL_GO_ON);
3425 if (player->last_move_dir & (MV_LEFT | MV_RIGHT))
3427 if (!(moved |= MoveFigureOneStep(player, 0, dy, dx, dy)))
3428 moved |= MoveFigureOneStep(player, dx, 0, dx, dy);
3432 if (!(moved |= MoveFigureOneStep(player, dx, 0, dx, dy)))
3433 moved |= MoveFigureOneStep(player, 0, dy, dx, dy);
3439 if (moved & MF_MOVING && !ScreenMovPos &&
3440 (player == local_player || !options.network))
3442 int old_scroll_x = scroll_x, old_scroll_y = scroll_y;
3443 int offset = (setup.scroll_delay ? 3 : 0);
3445 if (!IN_VIS_FIELD(SCREENX(jx), SCREENY(jy)))
3447 /* actual player has left the screen -- scroll in that direction */
3448 if (jx != old_jx) /* player has moved horizontally */
3449 scroll_x += (jx - old_jx);
3450 else /* player has moved vertically */
3451 scroll_y += (jy - old_jy);
3455 if (jx != old_jx) /* player has moved horizontally */
3457 if ((player->MovDir == MV_LEFT && scroll_x > jx-MIDPOSX+offset) ||
3458 (player->MovDir == MV_RIGHT && scroll_x < jx-MIDPOSX-offset))
3459 scroll_x = jx-MIDPOSX + (scroll_x < jx-MIDPOSX ? -offset : +offset);
3461 /* don't scroll over playfield boundaries */
3462 if (scroll_x < -1 || scroll_x > lev_fieldx - SCR_FIELDX + 1)
3463 scroll_x = (scroll_x < -1 ? -1 : lev_fieldx - SCR_FIELDX + 1);
3465 /* don't scroll more than one field at a time */
3466 scroll_x = old_scroll_x + SIGN(scroll_x - old_scroll_x);
3468 /* don't scroll against the player's moving direction */
3469 if ((player->MovDir == MV_LEFT && scroll_x > old_scroll_x) ||
3470 (player->MovDir == MV_RIGHT && scroll_x < old_scroll_x))
3471 scroll_x = old_scroll_x;
3473 else /* player has moved vertically */
3475 if ((player->MovDir == MV_UP && scroll_y > jy-MIDPOSY+offset) ||
3476 (player->MovDir == MV_DOWN && scroll_y < jy-MIDPOSY-offset))
3477 scroll_y = jy-MIDPOSY + (scroll_y < jy-MIDPOSY ? -offset : +offset);
3479 /* don't scroll over playfield boundaries */
3480 if (scroll_y < -1 || scroll_y > lev_fieldy - SCR_FIELDY + 1)
3481 scroll_y = (scroll_y < -1 ? -1 : lev_fieldy - SCR_FIELDY + 1);
3483 /* don't scroll more than one field at a time */
3484 scroll_y = old_scroll_y + SIGN(scroll_y - old_scroll_y);
3486 /* don't scroll against the player's moving direction */
3487 if ((player->MovDir == MV_UP && scroll_y > old_scroll_y) ||
3488 (player->MovDir == MV_DOWN && scroll_y < old_scroll_y))
3489 scroll_y = old_scroll_y;
3493 if (scroll_x != old_scroll_x || scroll_y != old_scroll_y)
3495 if (!options.network && !AllPlayersInVisibleScreen())
3497 scroll_x = old_scroll_x;
3498 scroll_y = old_scroll_y;
3502 ScrollScreen(player, SCROLL_INIT);
3503 ScrollLevel(old_scroll_x - scroll_x, old_scroll_y - scroll_y);
3508 if (!(moved & MF_MOVING) && !player->Pushing)
3511 player->Frame = (player->Frame + 1) % 4;
3513 if (moved & MF_MOVING)
3515 if (old_jx != jx && old_jy == jy)
3516 player->MovDir = (old_jx < jx ? MV_RIGHT : MV_LEFT);
3517 else if (old_jx == jx && old_jy != jy)
3518 player->MovDir = (old_jy < jy ? MV_DOWN : MV_UP);
3520 DrawLevelField(jx, jy); /* für "ErdreichAnbroeckeln()" */
3522 player->last_move_dir = player->MovDir;
3525 player->last_move_dir = MV_NO_MOVING;
3527 TestIfHeroHitsBadThing(jx, jy);
3535 void ScrollFigure(struct PlayerInfo *player, int mode)
3537 int jx = player->jx, jy = player->jy;
3538 int last_jx = player->last_jx, last_jy = player->last_jy;
3540 if (!player->active || player->gone || !player->MovPos)
3543 if (mode == SCROLL_INIT)
3545 player->actual_frame_counter = FrameCounter;
3546 player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3548 if (Feld[last_jx][last_jy] == EL_LEERRAUM)
3549 Feld[last_jx][last_jy] = EL_PLAYER_IS_LEAVING;
3554 else if (!FrameReached(&player->actual_frame_counter, 1))
3557 player->MovPos += (player->MovPos > 0 ? -1 : 1) * TILEX/8;
3558 player->GfxPos = ScrollStepSize * (player->MovPos / ScrollStepSize);
3560 if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
3561 Feld[last_jx][last_jy] = EL_LEERRAUM;
3565 if (!player->MovPos)
3567 player->last_jx = jx;
3568 player->last_jy = jy;
3570 if (Feld[jx][jy] == EL_AUSGANG_AUF)
3574 if (!local_player->friends_still_needed)
3575 player->LevelSolved = player->GameOver = TRUE;
3580 void ScrollScreen(struct PlayerInfo *player, int mode)
3582 static long screen_frame_counter = 0;
3584 if (mode == SCROLL_INIT)
3586 screen_frame_counter = FrameCounter;
3587 ScreenMovDir = player->MovDir;
3588 ScreenMovPos = player->MovPos;
3589 ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3592 else if (!FrameReached(&screen_frame_counter, 1))
3597 ScreenMovPos += (ScreenMovPos > 0 ? -1 : 1) * TILEX/8;
3598 ScreenGfxPos = ScrollStepSize * (ScreenMovPos / ScrollStepSize);
3599 redraw_mask |= REDRAW_FIELD;
3602 ScreenMovDir = MV_NO_MOVING;
3605 void TestIfGoodThingHitsBadThing(int goodx, int goody)
3607 int i, killx = goodx, killy = goody;
3608 static int xy[4][2] =
3615 static int harmless[4] =
3627 x = goodx + xy[i][0];
3628 y = goody + xy[i][1];
3629 if (!IN_LEV_FIELD(x, y))
3632 element = Feld[x][y];
3634 if (DONT_TOUCH(element))
3636 if (MovDir[x][y] == harmless[i])
3645 if (killx != goodx || killy != goody)
3647 if (IS_PLAYER(goodx, goody))
3648 KillHero(PLAYERINFO(goodx, goody));
3654 void TestIfBadThingHitsGoodThing(int badx, int bady)
3656 int i, killx = badx, killy = bady;
3657 static int xy[4][2] =
3664 static int harmless[4] =
3676 x = badx + xy[i][0];
3677 y = bady + xy[i][1];
3678 if (!IN_LEV_FIELD(x, y))
3681 element = Feld[x][y];
3683 if (IS_PLAYER(x, y))
3689 else if (element == EL_PINGUIN)
3691 if (MovDir[x][y] == harmless[i] && IS_MOVING(x, y))
3700 if (killx != badx || killy != bady)
3702 if (IS_PLAYER(killx, killy))
3703 KillHero(PLAYERINFO(killx, killy));
3709 void TestIfHeroHitsBadThing(int x, int y)
3711 TestIfGoodThingHitsBadThing(x, y);
3714 void TestIfBadThingHitsHero(int x, int y)
3716 TestIfBadThingHitsGoodThing(x, y);
3719 void TestIfFriendHitsBadThing(int x, int y)
3721 TestIfGoodThingHitsBadThing(x, y);
3724 void TestIfBadThingHitsFriend(int x, int y)
3726 TestIfBadThingHitsGoodThing(x, y);
3729 void TestIfBadThingHitsOtherBadThing(int badx, int bady)
3731 int i, killx = badx, killy = bady;
3732 static int xy[4][2] =
3746 if (!IN_LEV_FIELD(x, y))
3749 element = Feld[x][y];
3750 if (IS_AMOEBOID(element) || element == EL_LIFE ||
3751 element == EL_AMOEBING || element == EL_TROPFEN)
3759 if (killx != badx || killy != bady)
3763 void KillHero(struct PlayerInfo *player)
3765 int jx = player->jx, jy = player->jy;
3770 if (IS_PFORTE(Feld[jx][jy]))
3771 Feld[jx][jy] = EL_LEERRAUM;
3777 void BuryHero(struct PlayerInfo *player)
3779 int jx = player->jx, jy = player->jy;
3784 PlaySoundLevel(jx, jy, SND_AUTSCH);
3785 PlaySoundLevel(jx, jy, SND_LACHEN);
3787 player->GameOver = TRUE;
3791 void RemoveHero(struct PlayerInfo *player)
3793 int jx = player->jx, jy = player->jy;
3794 int i, found = FALSE;
3796 player->gone = TRUE;
3797 StorePlayer[jx][jy] = 0;
3799 for (i=0; i<MAX_PLAYERS; i++)
3800 if (stored_player[i].active && !stored_player[i].gone)
3804 AllPlayersGone = TRUE;
3810 int DigField(struct PlayerInfo *player,
3811 int x, int y, int real_dx, int real_dy, int mode)
3813 int jx = player->jx, jy = player->jy;
3814 int dx = x - jx, dy = y - jy;
3817 if (!player->MovPos)
3818 player->Pushing = FALSE;
3820 if (mode == DF_NO_PUSH)
3822 player->push_delay = 0;
3823 return MF_NO_ACTION;
3826 if (IS_MOVING(x, y) || IS_PLAYER(x, y))
3827 return MF_NO_ACTION;
3829 element = Feld[x][y];
3837 Feld[x][y] = EL_LEERRAUM;
3841 case EL_EDELSTEIN_BD:
3842 case EL_EDELSTEIN_GELB:
3843 case EL_EDELSTEIN_ROT:
3844 case EL_EDELSTEIN_LILA:
3847 local_player->gems_still_needed -= (element == EL_DIAMANT ? 3 : 1);
3848 if (local_player->gems_still_needed < 0)
3849 local_player->gems_still_needed = 0;
3850 RaiseScoreElement(element);
3851 DrawText(DX_EMERALDS, DY_EMERALDS,
3852 int2str(local_player->gems_still_needed, 3),
3853 FS_SMALL, FC_YELLOW);
3854 PlaySoundLevel(x, y, SND_PONG);
3857 case EL_DYNAMIT_AUS:
3860 RaiseScoreElement(EL_DYNAMIT);
3861 DrawText(DX_DYNAMITE, DY_DYNAMITE,
3862 int2str(local_player->dynamite, 3),
3863 FS_SMALL, FC_YELLOW);
3864 PlaySoundLevel(x, y, SND_PONG);
3867 case EL_DYNABOMB_NR:
3869 player->dynabomb_count++;
3870 player->dynabombs_left++;
3871 RaiseScoreElement(EL_DYNAMIT);
3872 PlaySoundLevel(x, y, SND_PONG);
3875 case EL_DYNABOMB_SZ:
3877 player->dynabomb_size++;
3878 RaiseScoreElement(EL_DYNAMIT);
3879 PlaySoundLevel(x, y, SND_PONG);
3882 case EL_DYNABOMB_XL:
3884 player->dynabomb_xl = TRUE;
3885 RaiseScoreElement(EL_DYNAMIT);
3886 PlaySoundLevel(x, y, SND_PONG);
3889 case EL_SCHLUESSEL1:
3890 case EL_SCHLUESSEL2:
3891 case EL_SCHLUESSEL3:
3892 case EL_SCHLUESSEL4:
3894 int key_nr = element-EL_SCHLUESSEL1;
3897 player->key[key_nr] = TRUE;
3898 RaiseScoreElement(EL_SCHLUESSEL);
3899 DrawMiniGraphicExt(drawto, gc,
3900 DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
3901 GFX_SCHLUESSEL1+key_nr);
3902 DrawMiniGraphicExt(window, gc,
3903 DX_KEYS+key_nr*MINI_TILEX, DY_KEYS,
3904 GFX_SCHLUESSEL1+key_nr);
3905 PlaySoundLevel(x, y, SND_PONG);
3910 Feld[x][y] = EL_ABLENK_EIN;
3913 DrawLevelField(x, y);
3917 case EL_FELSBROCKEN:
3921 if (dy || mode == DF_SNAP)
3922 return MF_NO_ACTION;
3924 player->Pushing = TRUE;
3926 if (!IN_LEV_FIELD(x+dx, y+dy) || !IS_FREE(x+dx, y+dy))
3927 return MF_NO_ACTION;
3931 if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
3932 return MF_NO_ACTION;
3935 if (player->push_delay == 0)
3936 player->push_delay = FrameCounter;
3937 if (!FrameReached(&player->push_delay, player->push_delay_value) &&
3939 return MF_NO_ACTION;
3942 Feld[x+dx][y+dy] = element;
3944 player->push_delay_value = 2+RND(8);
3946 DrawLevelField(x+dx, y+dy);
3947 if (element == EL_FELSBROCKEN)
3948 PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
3949 else if (element == EL_KOKOSNUSS)
3950 PlaySoundLevel(x+dx, y+dy, SND_KNURK);
3952 PlaySoundLevel(x+dx, y+dy, SND_KLOPF);
3959 if (!player->key[element-EL_PFORTE1])
3960 return MF_NO_ACTION;
3967 if (!player->key[element-EL_PFORTE1X])
3968 return MF_NO_ACTION;
3972 case EL_AUSGANG_ACT:
3973 /* Tür ist (noch) nicht offen! */
3974 return MF_NO_ACTION;
3977 case EL_AUSGANG_AUF:
3978 if (mode == DF_SNAP)
3979 return MF_NO_ACTION;
3981 PlaySoundLevel(x, y, SND_BUING);
3984 player->gone = TRUE;
3985 PlaySoundLevel(x, y, SND_BUING);
3987 if (!local_player->friends_still_needed)
3988 player->LevelSolved = player->GameOver = TRUE;
3994 Feld[x][y] = EL_BIRNE_EIN;
3995 local_player->lights_still_needed--;
3996 DrawLevelField(x, y);
3997 PlaySoundLevel(x, y, SND_DENG);
4002 Feld[x][y] = EL_ZEIT_LEER;
4004 DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FS_SMALL, FC_YELLOW);
4005 DrawLevelField(x, y);
4006 PlaySoundStereo(SND_GONG, PSND_MAX_RIGHT);
4010 case EL_SOKOBAN_FELD_LEER:
4013 case EL_SOKOBAN_FELD_VOLL:
4014 case EL_SOKOBAN_OBJEKT:
4016 if (mode == DF_SNAP)
4017 return MF_NO_ACTION;
4019 player->Pushing = TRUE;
4021 if (!IN_LEV_FIELD(x+dx, y+dy)
4022 || (!IS_FREE(x+dx, y+dy)
4023 && (Feld[x+dx][y+dy] != EL_SOKOBAN_FELD_LEER
4024 || !IS_SB_ELEMENT(element))))
4025 return MF_NO_ACTION;
4029 if (IN_LEV_FIELD(jx, jy+real_dy) && !IS_SOLID(Feld[jx][jy+real_dy]))
4030 return MF_NO_ACTION;
4032 else if (dy && real_dx)
4034 if (IN_LEV_FIELD(jx+real_dx, jy) && !IS_SOLID(Feld[jx+real_dx][jy]))
4035 return MF_NO_ACTION;
4038 if (player->push_delay == 0)
4039 player->push_delay = FrameCounter;
4040 if (!FrameReached(&player->push_delay, player->push_delay_value) &&
4042 return MF_NO_ACTION;
4044 if (IS_SB_ELEMENT(element))
4046 if (element == EL_SOKOBAN_FELD_VOLL)
4048 Feld[x][y] = EL_SOKOBAN_FELD_LEER;
4049 local_player->sokobanfields_still_needed++;
4054 if (Feld[x+dx][y+dy] == EL_SOKOBAN_FELD_LEER)
4056 Feld[x+dx][y+dy] = EL_SOKOBAN_FELD_VOLL;
4057 local_player->sokobanfields_still_needed--;
4058 if (element == EL_SOKOBAN_OBJEKT)
4059 PlaySoundLevel(x, y, SND_DENG);
4062 Feld[x+dx][y+dy] = EL_SOKOBAN_OBJEKT;
4067 Feld[x+dx][y+dy] = element;
4070 player->push_delay_value = 2;
4072 DrawLevelField(x, y);
4073 DrawLevelField(x+dx, y+dy);
4074 PlaySoundLevel(x+dx, y+dy, SND_PUSCH);
4076 if (IS_SB_ELEMENT(element) &&
4077 local_player->sokobanfields_still_needed == 0 &&
4078 game_emulation == EMU_SOKOBAN)
4080 player->LevelSolved = player->GameOver = TRUE;
4081 PlaySoundLevel(x, y, SND_BUING);
4093 return MF_NO_ACTION;
4097 player->push_delay = 0;
4102 boolean SnapField(struct PlayerInfo *player, int dx, int dy)
4104 int jx = player->jx, jy = player->jy;
4105 int x = jx + dx, y = jy + dy;
4107 if (player->gone || !IN_LEV_FIELD(x, y))
4115 player->snapped = FALSE;
4119 if (player->snapped)
4122 player->MovDir = (dx < 0 ? MV_LEFT :
4125 dy > 0 ? MV_DOWN : MV_NO_MOVING);
4127 if (!DigField(player, x, y, 0, 0, DF_SNAP))
4130 player->snapped = TRUE;
4131 DrawLevelField(x, y);
4137 boolean PlaceBomb(struct PlayerInfo *player)
4139 int jx = player->jx, jy = player->jy;
4142 if (player->gone || player->MovPos)
4145 element = Feld[jx][jy];
4147 if ((player->dynamite == 0 && player->dynabombs_left == 0) ||
4148 element == EL_DYNAMIT || element == EL_DYNABOMB ||
4149 element == EL_EXPLODING)
4152 if (element != EL_LEERRAUM)
4153 Store[jx][jy] = element;
4155 if (player->dynamite)
4157 Feld[jx][jy] = EL_DYNAMIT;
4158 MovDelay[jx][jy] = 96;
4160 DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
4161 FS_SMALL, FC_YELLOW);
4162 if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4163 DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNAMIT);
4167 Feld[jx][jy] = EL_DYNABOMB;
4168 Store2[jx][jy] = player->element_nr; /* for DynaExplode() */
4169 MovDelay[jx][jy] = 96;
4170 player->dynabombs_left--;
4171 if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
4172 DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), GFX_DYNABOMB);
4178 void PlaySoundLevel(int x, int y, int sound_nr)
4180 int sx = SCREENX(x), sy = SCREENY(y);
4182 int silence_distance = 8;
4184 if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
4185 (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
4188 if (!IN_LEV_FIELD(x, y) ||
4189 sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
4190 sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
4193 volume = PSND_MAX_VOLUME;
4196 stereo = (sx-SCR_FIELDX/2)*12;
4198 stereo = PSND_MIDDLE+(2*sx-(SCR_FIELDX-1))*5;
4199 if(stereo > PSND_MAX_RIGHT) stereo = PSND_MAX_RIGHT;
4200 if(stereo < PSND_MAX_LEFT) stereo = PSND_MAX_LEFT;
4203 if (!IN_SCR_FIELD(sx, sy))
4205 int dx = ABS(sx-SCR_FIELDX/2)-SCR_FIELDX/2;
4206 int dy = ABS(sy-SCR_FIELDY/2)-SCR_FIELDY/2;
4208 volume -= volume*(dx > dy ? dx : dy)/silence_distance;
4211 PlaySoundExt(sound_nr, volume, stereo, PSND_NO_LOOP);
4214 void RaiseScore(int value)
4216 local_player->score += value;
4217 DrawText(DX_SCORE, DY_SCORE, int2str(local_player->score, 5),
4218 FS_SMALL, FC_YELLOW);
4221 void RaiseScoreElement(int element)
4226 case EL_EDELSTEIN_BD:
4227 case EL_EDELSTEIN_GELB:
4228 case EL_EDELSTEIN_ROT:
4229 case EL_EDELSTEIN_LILA:
4230 RaiseScore(level.score[SC_EDELSTEIN]);
4233 RaiseScore(level.score[SC_DIAMANT]);
4237 RaiseScore(level.score[SC_KAEFER]);
4241 RaiseScore(level.score[SC_FLIEGER]);
4245 RaiseScore(level.score[SC_MAMPFER]);
4248 RaiseScore(level.score[SC_ROBOT]);
4251 RaiseScore(level.score[SC_PACMAN]);
4254 RaiseScore(level.score[SC_KOKOSNUSS]);
4257 RaiseScore(level.score[SC_DYNAMIT]);
4260 RaiseScore(level.score[SC_SCHLUESSEL]);