1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
180 BlitBitmap(backbuffer, window,
181 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
185 int fx = FX, fy = FY;
187 if (setup.soft_scrolling)
189 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
190 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
193 if (setup.soft_scrolling ||
194 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
195 ABS(ScreenMovPos) == ScrollStepSize ||
196 redraw_tiles > REDRAWTILES_THRESHOLD)
198 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
202 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
204 (setup.soft_scrolling ?
205 "setup.soft_scrolling" :
206 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
207 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
208 ABS(ScreenGfxPos) == ScrollStepSize ?
209 "ABS(ScreenGfxPos) == ScrollStepSize" :
210 "redraw_tiles > REDRAWTILES_THRESHOLD"));
216 redraw_mask &= ~REDRAW_MAIN;
219 if (redraw_mask & REDRAW_DOORS)
221 if (redraw_mask & REDRAW_DOOR_1)
222 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
223 if (redraw_mask & REDRAW_DOOR_2)
225 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
226 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
229 if (redraw_mask & REDRAW_VIDEO_1)
230 BlitBitmap(backbuffer, window,
231 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
232 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
234 if (redraw_mask & REDRAW_VIDEO_2)
235 BlitBitmap(backbuffer, window,
236 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
237 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
239 if (redraw_mask & REDRAW_VIDEO_3)
240 BlitBitmap(backbuffer, window,
241 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
242 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
246 if (redraw_mask & REDRAW_DOOR_3)
247 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
248 redraw_mask &= ~REDRAW_DOORS;
251 if (redraw_mask & REDRAW_MICROLEVEL)
253 BlitBitmap(backbuffer, window,
254 MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
255 MICROLEV_XPOS, MICROLEV_YPOS);
256 BlitBitmap(backbuffer, window,
257 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
258 SX, MICROLABEL_YPOS);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW, FONT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 new_graphic_info[graphic].bitmap ?
369 new_graphic_info[graphic].bitmap :
370 new_graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 new_graphic_info[graphic].bitmap ?
377 new_graphic_info[graphic].bitmap :
378 new_graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_MASSIVE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 static int getGraphicAnimationPhase(int frames, int delay, int mode)
442 if (mode & ANIM_PINGPONG)
444 int max_anim_frames = 2 * frames - 2;
446 phase = (FrameCounter % (delay * max_anim_frames)) / delay;
447 phase = (phase < frames ? phase : max_anim_frames - phase);
450 phase = (FrameCounter % (delay * frames)) / delay;
452 if (mode & ANIM_REVERSE)
458 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
460 /* animation synchronized with global frame counter, not move position */
461 if (new_graphic_info[graphic].anim_global_sync || sync_frame < 0)
462 sync_frame = FrameCounter;
464 return getAnimationFrame(new_graphic_info[graphic].anim_frames,
465 new_graphic_info[graphic].anim_delay,
466 new_graphic_info[graphic].anim_mode,
467 new_graphic_info[graphic].anim_start_frame,
471 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
472 int graphic, int sync_frame, int mask_mode)
474 int frame = getGraphicAnimationFrame(graphic, sync_frame);
476 if (mask_mode == USE_MASKING)
477 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
479 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
482 inline boolean checkDrawGraphicAnimation(int x, int y, int graphic)
484 int lx = LEVELX(x), ly = LEVELY(y);
486 return (IN_SCR_FIELD(x, y) &&
487 GfxFrame[lx][ly] % new_graphic_info[graphic].anim_delay == 0);
490 inline boolean checkDrawLevelGraphicAnimation(int x, int y, int graphic)
492 return (IN_SCR_FIELD(SCREENX(x), SCREENY(y)) &&
493 GfxFrame[x][y] % new_graphic_info[graphic].anim_delay == 0);
496 inline boolean DrawGraphicAnimation(int x, int y, int graphic)
498 int lx = LEVELX(x), ly = LEVELY(y);
500 if (!checkDrawGraphicAnimation(x, y, graphic))
503 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
504 graphic, GfxFrame[lx][ly], NO_MASKING);
510 boolean DrawLevelGraphicAnimation(int x, int y, int graphic)
512 return DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
515 boolean DrawLevelElementAnimation(int x, int y, int element)
517 return DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
520 void DrawAllPlayers()
524 for(i=0; i<MAX_PLAYERS; i++)
525 if (stored_player[i].active)
526 DrawPlayer(&stored_player[i]);
529 void DrawPlayerField(int x, int y)
531 if (!IS_PLAYER(x, y))
534 DrawPlayer(PLAYERINFO(x, y));
537 void DrawPlayer(struct PlayerInfo *player)
539 int jx = player->jx, jy = player->jy;
540 int last_jx = player->last_jx, last_jy = player->last_jy;
541 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
542 int sx = SCREENX(jx), sy = SCREENY(jy);
543 int sxx = 0, syy = 0;
544 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
547 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
549 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
553 if (!IN_LEV_FIELD(jx,jy))
555 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
556 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
557 printf("DrawPlayerField(): This should never happen!\n");
562 if (element == EL_EXPLOSION)
565 /* draw things in the field the player is leaving, if needed */
567 if (player_is_moving)
569 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
571 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
573 if (last_element == EL_DYNAMITE_ACTIVE)
574 DrawDynamite(last_jx, last_jy);
576 DrawLevelFieldThruMask(last_jx, last_jy);
578 else if (last_element == EL_DYNAMITE_ACTIVE)
579 DrawDynamite(last_jx, last_jy);
581 DrawLevelField(last_jx, last_jy);
583 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
587 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
588 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
590 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
593 DrawLevelField(next_jx, next_jy);
597 if (!IN_SCR_FIELD(sx, sy))
600 if (setup.direct_draw)
601 SetDrawtoField(DRAW_BUFFERED);
603 /* draw things behind the player, if needed */
606 DrawLevelElement(jx, jy, Store[jx][jy]);
607 else if (!IS_ACTIVE_BOMB(element))
608 DrawLevelField(jx, jy);
610 DrawLevelElement(jx, jy, EL_EMPTY);
612 /* draw player himself */
614 if (game.emulation == EMU_SUPAPLEX)
616 static int last_dir = MV_LEFT;
617 int action = (player->programmed_action ? player->programmed_action :
619 boolean action_moving =
621 ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
622 !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
624 graphic = IMG_SP_MURPHY;
628 if (player->MovDir == MV_LEFT)
629 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
630 else if (player->MovDir == MV_RIGHT)
631 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
632 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
633 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
634 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
635 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
637 else if (player->snapped)
639 if (player->MovDir == MV_LEFT)
640 graphic = IMG_SP_MURPHY_LEFT_SNAPPING;
641 else if (player->MovDir == MV_RIGHT)
642 graphic = IMG_SP_MURPHY_RIGHT_SNAPPING;
643 else if (player->MovDir == MV_UP)
644 graphic = IMG_SP_MURPHY_UP_SNAPPING;
645 else if (player->MovDir == MV_DOWN)
646 graphic = IMG_SP_MURPHY_DOWN_SNAPPING;
648 else if (action_moving)
650 if (player->MovDir == MV_LEFT)
651 graphic = IMG_SP_MURPHY_LEFT_MOVING;
652 else if (player->MovDir == MV_RIGHT)
653 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
654 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
655 graphic = IMG_SP_MURPHY_LEFT_MOVING;
656 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
657 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
659 graphic = IMG_SP_MURPHY_LEFT_MOVING;
661 frame = getGraphicAnimationFrame(graphic, -1);
664 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
665 last_dir = player->MovDir;
669 if (player->MovDir == MV_LEFT)
670 graphic = (player->Pushing ? IMG_PLAYER1_LEFT_PUSHING :
671 player->is_moving ? IMG_PLAYER1_LEFT_MOVING :
673 else if (player->MovDir == MV_RIGHT)
674 graphic = (player->Pushing ? IMG_PLAYER1_RIGHT_PUSHING :
675 player->is_moving ? IMG_PLAYER1_RIGHT_MOVING :
677 else if (player->MovDir == MV_UP)
678 graphic = (player->Pushing ? IMG_PLAYER1_UP_PUSHING :
679 player->is_moving ? IMG_PLAYER1_UP_MOVING :
681 else /* MV_DOWN || MV_NO_MOVING */
682 graphic = (player->Pushing ? IMG_PLAYER1_DOWN_PUSHING :
683 player->is_moving ? IMG_PLAYER1_DOWN_MOVING :
686 graphic = PLAYER_NR_GFX(graphic, player->index_nr);
689 frame = player->Frame;
691 frame = getGraphicAnimationFrame(graphic, player->Frame);
697 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
698 sxx = player->GfxPos;
700 syy = player->GfxPos;
703 if (!setup.soft_scrolling && ScreenMovPos)
708 printf("-> %d\n", player->Frame);
711 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
713 if (SHIELD_ON(player))
715 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
716 IMG_SHIELD_NORMAL_ACTIVE);
717 int frame = getGraphicAnimationFrame(graphic, -1);
719 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
723 if (player->Pushing && player->GfxPos)
725 if (player->Pushing && player_is_moving)
728 int px = SCREENX(next_jx), py = SCREENY(next_jy);
731 (element == EL_SOKOBAN_FIELD_EMPTY ||
732 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
733 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
737 int element = Feld[next_jx][next_jy];
738 int graphic = el2img(element);
743 if ((sxx || syy) && IS_PUSHABLE(element))
745 graphic = el_dir_act2img(element, player->MovDir, GFX_ACTION_MOVING);
747 frame = getGraphicAnimationFrame(graphic, player->GfxPos);
749 frame = getGraphicAnimationFrame(graphic, player->Frame);
753 printf("-> %d [%d]\n", player->Frame, player->GfxPos);
758 if (player->MovDir == MV_LEFT)
763 frame = (player->GfxPos / (TILEX / 4));
765 if (player->MovDir == MV_RIGHT)
766 frame = (frame + 4) % 4;
770 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
771 NO_CUTTING, NO_MASKING);
775 /* draw things in front of player (active dynamite or dynabombs) */
777 if (IS_ACTIVE_BOMB(element))
779 graphic = el2img(element);
782 if (element == EL_DYNAMITE_ACTIVE)
784 if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
789 if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
795 frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
797 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
802 if (game.emulation == EMU_SUPAPLEX)
803 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
805 DrawGraphicThruMask(sx, sy, graphic, frame);
808 if (player_is_moving && last_element == EL_EXPLOSION)
810 int stored = Store[last_jx][last_jy];
811 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
812 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
814 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
815 int phase = ExplodePhase[last_jx][last_jy] - 1;
816 int frame = getGraphicAnimationFrame(graphic, phase - delay);
819 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
822 /* draw elements that stay over the player */
823 /* handle the field the player is leaving ... */
824 if (player_is_moving && IS_OVER_PLAYER(last_element))
825 DrawLevelField(last_jx, last_jy);
827 /* ... and the field the player is entering */
828 if (IS_OVER_PLAYER(element))
829 DrawLevelField(jx, jy);
831 if (setup.direct_draw)
833 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
834 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
835 int x_size = TILEX * (1 + ABS(jx - last_jx));
836 int y_size = TILEY * (1 + ABS(jy - last_jy));
838 BlitBitmap(drawto_field, window,
839 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
840 SetDrawtoField(DRAW_DIRECT);
843 MarkTileDirty(sx,sy);
847 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
849 if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
851 *bitmap = graphic_info[graphic].bitmap;
852 *x = graphic_info[graphic].src_x;
853 *y = graphic_info[graphic].src_y;
855 else if (graphic >= GFX_START_ROCKSELEMENTS &&
856 graphic <= GFX_END_ROCKSELEMENTS)
858 graphic -= GFX_START_ROCKSELEMENTS;
859 *bitmap = new_graphic_info[IMG_OLD_PIX_ELEMENTS].bitmap;
860 *x = (graphic % GFX_PER_LINE) * TILEX;
861 *y = (graphic / GFX_PER_LINE) * TILEY;
863 else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
865 graphic -= GFX_START_ROCKSHEROES;
866 *bitmap = new_graphic_info[IMG_OLD_PIX_HEROES].bitmap;
867 *x = (graphic % HEROES_PER_LINE) * TILEX;
868 *y = (graphic / HEROES_PER_LINE) * TILEY;
870 else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
872 graphic -= GFX_START_ROCKSSP;
873 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
874 *x = (graphic % SP_PER_LINE) * TILEX;
875 *y = (graphic / SP_PER_LINE) * TILEY;
877 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
879 graphic -= GFX_START_ROCKSDC;
880 *bitmap = new_graphic_info[IMG_OLD_PIX_DC].bitmap;
881 *x = (graphic % DC_PER_LINE) * TILEX;
882 *y = (graphic / DC_PER_LINE) * TILEY;
884 else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
886 graphic -= GFX_START_ROCKSMORE;
887 *bitmap = new_graphic_info[IMG_OLD_PIX_MORE].bitmap;
888 *x = (graphic % MORE_PER_LINE) * TILEX;
889 *y = (graphic / MORE_PER_LINE) * TILEY;
891 else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
893 graphic -= GFX_START_ROCKSFONT;
894 *bitmap = new_graphic_info[IMG_OLD_PIX_FONT_EM].bitmap;
895 *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
896 *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
900 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
907 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
909 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
910 int offset_x = new_graphic_info[graphic].offset_x;
911 int offset_y = new_graphic_info[graphic].offset_y;
912 int src_x = new_graphic_info[graphic].src_x + frame * offset_x;
913 int src_y = new_graphic_info[graphic].src_y + frame * offset_y;
915 *bitmap = src_bitmap;
920 void DrawGraphic(int x, int y, int graphic, int frame)
923 if (!IN_SCR_FIELD(x, y))
925 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
926 printf("DrawGraphic(): This should never happen!\n");
931 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
936 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
941 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
942 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
946 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
953 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
955 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
956 int src_x = new_graphic_info[graphic].src_x;
957 int src_y = new_graphic_info[graphic].src_y;
958 int offset_x = new_graphic_info[graphic].offset_x;
959 int offset_y = new_graphic_info[graphic].offset_y;
961 src_x += frame * offset_x;
962 src_y += frame * offset_y;
965 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
968 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
971 if (!IN_SCR_FIELD(x, y))
973 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
974 printf("DrawGraphicThruMask(): This should never happen!\n");
979 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
984 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
992 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
993 drawing_gc = src_bitmap->stored_clip_gc;
995 GC drawing_gc = src_bitmap->stored_clip_gc;
996 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
997 int src_x = new_graphic_info[graphic].src_x;
998 int src_y = new_graphic_info[graphic].src_y;
999 int offset_x = new_graphic_info[graphic].offset_x;
1000 int offset_y = new_graphic_info[graphic].offset_y;
1002 src_x += frame * offset_x;
1003 src_y += frame * offset_y;
1007 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1008 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1011 void DrawMiniGraphic(int x, int y, int graphic)
1013 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1014 MarkTileDirty(x / 2, y / 2);
1017 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1019 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1020 int mini_startx = 0;
1021 int mini_starty = src_bitmap->height * 2 / 3;
1022 int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
1023 int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
1025 if (src_x + MINI_TILEX > src_bitmap->width ||
1026 src_y + MINI_TILEY > src_bitmap->height)
1028 /* graphic of desired size seems not to be contained in this image;
1029 dirty workaround: get it from the middle of the normal sized image */
1031 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1032 src_x += (TILEX / 2 - MINI_TILEX / 2);
1033 src_y += (TILEY / 2 - MINI_TILEY / 2);
1036 *bitmap = src_bitmap;
1041 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1046 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1047 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1050 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1051 int cut_mode, int mask_mode)
1060 int width = TILEX, height = TILEY;
1066 DrawGraphic(x, y, graphic, frame);
1070 if (dx || dy) /* shifted graphic */
1072 if (x < BX1) /* object enters playfield from the left */
1079 else if (x > BX2) /* object enters playfield from the right */
1085 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1091 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1093 else if (dx) /* general horizontal movement */
1094 MarkTileDirty(x + SIGN(dx), y);
1096 if (y < BY1) /* object enters playfield from the top */
1098 if (cut_mode==CUT_BELOW) /* object completely above top border */
1106 else if (y > BY2) /* object enters playfield from the bottom */
1112 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1118 else if (dy > 0 && cut_mode == CUT_ABOVE)
1120 if (y == BY2) /* object completely above bottom border */
1126 MarkTileDirty(x, y + 1);
1127 } /* object leaves playfield to the bottom */
1128 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1130 else if (dy) /* general vertical movement */
1131 MarkTileDirty(x, y + SIGN(dy));
1134 src_bitmap = new_graphic_info[graphic].bitmap;
1135 src_x = new_graphic_info[graphic].src_x;
1136 src_y = new_graphic_info[graphic].src_y;
1137 offset_x = new_graphic_info[graphic].offset_x;
1138 offset_y = new_graphic_info[graphic].offset_y;
1140 drawing_gc = src_bitmap->stored_clip_gc;
1142 src_x += frame * offset_x;
1143 src_y += frame * offset_y;
1148 dest_x = FX + x * TILEX + dx;
1149 dest_y = FY + y * TILEY + dy;
1152 if (!IN_SCR_FIELD(x,y))
1154 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1155 printf("DrawGraphicShifted(): This should never happen!\n");
1160 if (mask_mode == USE_MASKING)
1162 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1163 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1167 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1173 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1174 int frame, int cut_mode)
1176 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1180 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1181 int cut_mode, int mask_mode)
1183 int ux = LEVELX(x), uy = LEVELY(y);
1184 int graphic = el2gfx(element);
1185 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1186 int phase4 = phase8 / 2;
1187 int phase2 = phase8 / 4;
1188 int dir = MovDir[ux][uy];
1190 if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1192 graphic += 1 * !phase2;
1196 else if (dir == MV_LEFT)
1198 else if (dir == MV_DOWN)
1201 else if (element == EL_SP_SNIKSNAK)
1204 graphic = GFX_SP_SNIKSNAK_LEFT;
1205 else if (dir == MV_RIGHT)
1206 graphic = GFX_SP_SNIKSNAK_RIGHT;
1207 else if (dir == MV_UP)
1208 graphic = GFX_SP_SNIKSNAK_UP;
1210 graphic = GFX_SP_SNIKSNAK_DOWN;
1212 graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1214 else if (element == EL_SP_ELECTRON)
1216 graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1218 else if (element == EL_MOLE || element == EL_PENGUIN ||
1219 element == EL_PIG || element == EL_DRAGON)
1222 graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1223 element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1224 element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1225 else if (dir == MV_RIGHT)
1226 graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1227 element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1228 element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1229 else if (dir == MV_UP)
1230 graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1231 element == EL_PENGUIN ? GFX_PINGUIN_UP :
1232 element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1234 graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1235 element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1236 element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1240 else if (element == EL_SATELLITE)
1242 graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1244 else if (element == EL_ACID)
1246 graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1248 else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1252 else if (element == EL_BALLOON)
1256 else if ((element == EL_ROCK ||
1257 element == EL_SP_ZONK ||
1258 element == EL_BD_ROCK ||
1259 element == EL_SP_INFOTRON ||
1263 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1265 if (element == EL_ROCK ||
1266 element == EL_SP_ZONK ||
1267 element == EL_BD_ROCK)
1270 graphic += (4 - phase4) % 4;
1271 else if (dir == MV_RIGHT)
1274 graphic += phase2 * 2;
1276 else if (element != EL_SP_INFOTRON)
1280 else if (element == EL_MAGIC_WALL_ACTIVE ||
1281 element == EL_MAGIC_WALL_EMPTYING ||
1282 element == EL_BD_MAGIC_WALL_ACTIVE ||
1283 element == EL_BD_MAGIC_WALL_EMPTYING ||
1284 element == EL_MAGIC_WALL_FULL ||
1285 element == EL_BD_MAGIC_WALL_FULL)
1287 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1289 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1291 graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1292 graphic += (x + 2 * y + 4) % 4;
1294 else if (element == EL_WALL_GROWING)
1296 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1298 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1299 links_massiv = TRUE;
1300 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1301 rechts_massiv = TRUE;
1303 if (links_massiv && rechts_massiv)
1304 graphic = GFX_MAUERWERK;
1305 else if (links_massiv)
1306 graphic = GFX_MAUER_R;
1307 else if (rechts_massiv)
1308 graphic = GFX_MAUER_L;
1311 else if ((element == EL_INVISIBLE_STEELWALL ||
1312 element == EL_INVISIBLE_WALL ||
1313 element == EL_INVISIBLE_SAND) && game.light_time_left)
1315 graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1316 element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1317 GFX_SAND_INVISIBLE_ON);
1322 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1323 else if (mask_mode == USE_MASKING)
1324 DrawGraphicThruMask(x, y, graphic);
1326 DrawGraphic(x, y, graphic);
1330 inline static int getFramePosition(int x, int y)
1332 int frame_pos = -1; /* default: global synchronization */
1334 int element = Feld[x][y];
1336 if (element == EL_QUICKSAND_FULL ||
1337 element == EL_MAGIC_WALL_FULL ||
1338 element == EL_BD_MAGIC_WALL_FULL)
1340 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1341 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1344 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1346 frame_pos = GfxFrame[x][y];
1353 inline static int getGfxAction(int x, int y)
1355 int gfx_action = GFX_ACTION_DEFAULT;
1358 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1359 gfx_action = GfxAction[x][y];
1360 else if (IS_MOVING(x, y))
1361 gfx_action = GFX_ACTION_MOVING;
1363 gfx_action = GfxAction[x][y];
1368 printf("getGfxAction: THIS SHOULD NEVER HAPPEN: GfxAction[%d][%d] == %d\n",
1375 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1376 int cut_mode, int mask_mode)
1378 int ux = LEVELX(x), uy = LEVELY(y);
1382 if (IN_LEV_FIELD(ux, uy))
1384 int move_dir = MovDir[ux][uy];
1385 int move_pos = getFramePosition(ux, uy);
1386 int gfx_action = getGfxAction(ux, uy);
1388 graphic = el_dir_act2img(element, move_dir, gfx_action);
1389 frame = getGraphicAnimationFrame(graphic, move_pos);
1393 graphic = el2img(element);
1394 frame = getGraphicAnimationFrame(graphic, 0);
1397 if (element == EL_WALL_GROWING)
1399 boolean left_stopped = FALSE, right_stopped = FALSE;
1401 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1402 left_stopped = TRUE;
1403 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1404 right_stopped = TRUE;
1406 if (left_stopped && right_stopped)
1408 else if (left_stopped)
1410 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1411 frame = new_graphic_info[graphic].anim_frames - 1;
1413 else if (right_stopped)
1415 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1416 frame = new_graphic_info[graphic].anim_frames - 1;
1419 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1421 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1422 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1423 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1424 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1425 IMG_AMOEBA_DEAD_PART1);
1427 graphic += (x + 2 * y + 4) % 4;
1431 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1432 else if (mask_mode == USE_MASKING)
1433 DrawGraphicThruMask(x, y, graphic, frame);
1435 DrawGraphic(x, y, graphic, frame);
1438 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1439 int cut_mode, int mask_mode)
1441 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1442 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1443 cut_mode, mask_mode);
1446 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1449 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1452 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1455 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1459 void DrawOldScreenElementThruMask(int x, int y, int element)
1461 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1464 void DrawScreenElementThruMask(int x, int y, int element)
1466 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1470 void DrawLevelElementThruMask(int x, int y, int element)
1472 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1475 void DrawLevelFieldThruMask(int x, int y)
1477 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1480 void DrawCrumbledSand(int x, int y)
1484 int i, width, height, cx,cy;
1485 int ux = LEVELX(x), uy = LEVELY(y);
1486 int element, graphic;
1488 static int xy[4][2] =
1496 if (!IN_LEV_FIELD(ux, uy))
1499 element = Feld[ux][uy];
1501 if (element == EL_SAND ||
1502 element == EL_LANDMINE ||
1503 element == EL_TRAP ||
1504 element == EL_TRAP_ACTIVE)
1506 if (!IN_SCR_FIELD(x, y))
1509 graphic = IMG_SAND_CRUMBLED;
1511 src_bitmap = new_graphic_info[graphic].bitmap;
1512 src_x = new_graphic_info[graphic].src_x;
1513 src_y = new_graphic_info[graphic].src_y;
1519 uxx = ux + xy[i][0];
1520 uyy = uy + xy[i][1];
1521 if (!IN_LEV_FIELD(uxx, uyy))
1522 element = EL_STEELWALL;
1524 element = Feld[uxx][uyy];
1526 if (element == EL_SAND ||
1527 element == EL_LANDMINE ||
1528 element == EL_TRAP ||
1529 element == EL_TRAP_ACTIVE)
1532 if (i == 1 || i == 2)
1536 cx = (i == 2 ? TILEX - snip : 0);
1544 cy = (i == 3 ? TILEY - snip : 0);
1547 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1548 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1551 MarkTileDirty(x, y);
1555 graphic = IMG_SAND_CRUMBLED;
1557 src_bitmap = new_graphic_info[graphic].bitmap;
1558 src_x = new_graphic_info[graphic].src_x;
1559 src_y = new_graphic_info[graphic].src_y;
1563 int xx, yy, uxx, uyy;
1567 uxx = ux + xy[i][0];
1568 uyy = uy + xy[i][1];
1570 if (!IN_LEV_FIELD(uxx, uyy) ||
1571 (Feld[uxx][uyy] != EL_SAND &&
1572 Feld[uxx][uyy] != EL_LANDMINE &&
1573 Feld[uxx][uyy] != EL_TRAP &&
1574 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1575 !IN_SCR_FIELD(xx, yy))
1578 if (i == 1 || i == 2)
1582 cx = (i == 1 ? TILEX - snip : 0);
1590 cy = (i==0 ? TILEY-snip : 0);
1593 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1594 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1596 MarkTileDirty(xx, yy);
1601 void DrawScreenElement(int x, int y, int element)
1603 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1604 DrawCrumbledSand(x, y);
1607 void DrawLevelElement(int x, int y, int element)
1609 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1610 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1613 void DrawScreenField(int x, int y)
1615 int ux = LEVELX(x), uy = LEVELY(y);
1616 int element, content;
1618 if (!IN_LEV_FIELD(ux, uy))
1620 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1623 element = BorderElement;
1625 DrawScreenElement(x, y, element);
1629 element = Feld[ux][uy];
1630 content = Store[ux][uy];
1632 if (IS_MOVING(ux, uy))
1634 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1635 boolean cut_mode = NO_CUTTING;
1637 if (element == EL_QUICKSAND_EMPTYING ||
1638 element == EL_MAGIC_WALL_EMPTYING ||
1639 element == EL_BD_MAGIC_WALL_EMPTYING ||
1640 element == EL_AMOEBA_DRIPPING)
1641 cut_mode = CUT_ABOVE;
1642 else if (element == EL_QUICKSAND_FILLING ||
1643 element == EL_MAGIC_WALL_FILLING ||
1644 element == EL_BD_MAGIC_WALL_FILLING)
1645 cut_mode = CUT_BELOW;
1647 if (cut_mode == CUT_ABOVE)
1648 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1650 DrawScreenElement(x, y, EL_EMPTY);
1653 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1654 else if (cut_mode == NO_CUTTING)
1655 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1657 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1659 if (content == EL_ACID)
1660 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1662 else if (IS_BLOCKED(ux, uy))
1667 boolean cut_mode = NO_CUTTING;
1668 int element_old, content_old;
1670 Blocked2Moving(ux, uy, &oldx, &oldy);
1673 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1674 MovDir[oldx][oldy] == MV_RIGHT);
1676 element_old = Feld[oldx][oldy];
1677 content_old = Store[oldx][oldy];
1679 if (element_old == EL_QUICKSAND_EMPTYING ||
1680 element_old == EL_MAGIC_WALL_EMPTYING ||
1681 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1682 element_old == EL_AMOEBA_DRIPPING)
1683 cut_mode = CUT_ABOVE;
1685 DrawScreenElement(x, y, EL_EMPTY);
1688 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1690 else if (cut_mode == NO_CUTTING)
1691 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1694 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1697 else if (IS_DRAWABLE(element))
1698 DrawScreenElement(x, y, element);
1700 DrawScreenElement(x, y, EL_EMPTY);
1703 void DrawLevelField(int x, int y)
1705 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1706 DrawScreenField(SCREENX(x), SCREENY(y));
1707 else if (IS_MOVING(x, y))
1711 Moving2Blocked(x, y, &newx, &newy);
1712 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1713 DrawScreenField(SCREENX(newx), SCREENY(newy));
1715 else if (IS_BLOCKED(x, y))
1719 Blocked2Moving(x, y, &oldx, &oldy);
1720 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1721 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1725 void DrawMiniElement(int x, int y, int element)
1729 graphic = el2img(element);
1730 DrawMiniGraphic(x, y, graphic);
1733 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1735 int x = sx + scroll_x, y = sy + scroll_y;
1737 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1738 DrawMiniElement(sx, sy, EL_EMPTY);
1739 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1740 DrawMiniElement(sx, sy, Feld[x][y]);
1743 int steel_type, steel_position;
1746 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1747 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1748 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1749 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1750 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1751 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1754 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1755 steel_position = (x == -1 && y == -1 ? 0 :
1756 x == lev_fieldx && y == -1 ? 1 :
1757 x == -1 && y == lev_fieldy ? 2 :
1758 x == lev_fieldx && y == lev_fieldy ? 3 :
1759 x == -1 || x == lev_fieldx ? 4 :
1760 y == -1 || y == lev_fieldy ? 5 : -1);
1762 if (steel_position != -1)
1763 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1767 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1769 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1770 int mini_startx = src_bitmap->width * 3 / 4;
1771 int mini_starty = src_bitmap->height * 2 / 3;
1772 int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1773 int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1775 if (src_x + MICRO_TILEX > src_bitmap->width ||
1776 src_y + MICRO_TILEY > src_bitmap->height)
1778 /* graphic of desired size seems not to be contained in this image;
1779 dirty workaround: get it from the middle of the normal sized image */
1781 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1782 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1783 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1786 *bitmap = src_bitmap;
1791 void DrawMicroElement(int xpos, int ypos, int element)
1795 int graphic = el2img(element);
1797 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1798 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1806 SetDrawBackgroundMask(REDRAW_NONE);
1809 for(x=BX1; x<=BX2; x++)
1810 for(y=BY1; y<=BY2; y++)
1811 DrawScreenField(x, y);
1813 redraw_mask |= REDRAW_FIELD;
1816 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1820 for(x=0; x<size_x; x++)
1821 for(y=0; y<size_y; y++)
1822 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1824 redraw_mask |= REDRAW_FIELD;
1827 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1831 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1833 if (lev_fieldx < STD_LEV_FIELDX)
1834 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1835 if (lev_fieldy < STD_LEV_FIELDY)
1836 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1838 xpos += MICRO_TILEX;
1839 ypos += MICRO_TILEY;
1841 for(x=-1; x<=STD_LEV_FIELDX; x++)
1843 for(y=-1; y<=STD_LEV_FIELDY; y++)
1845 int lx = from_x + x, ly = from_y + y;
1847 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1848 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1850 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1851 && BorderElement != EL_EMPTY)
1852 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1857 redraw_mask |= REDRAW_MICROLEVEL;
1860 #define MICROLABEL_EMPTY 0
1861 #define MICROLABEL_LEVEL_NAME 1
1862 #define MICROLABEL_CREATED_BY 2
1863 #define MICROLABEL_LEVEL_AUTHOR 3
1864 #define MICROLABEL_IMPORTED_FROM 4
1865 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1867 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1869 static void DrawMicroLevelLabelExt(int mode)
1871 char label_text[MAX_MICROLABEL_SIZE + 1];
1873 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1875 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1876 mode == MICROLABEL_CREATED_BY ? "created by" :
1877 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1878 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1879 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1880 leveldir_current->imported_from : ""),
1881 MAX_MICROLABEL_SIZE);
1882 label_text[MAX_MICROLABEL_SIZE] = '\0';
1884 if (strlen(label_text) > 0)
1886 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1887 int lypos = MICROLABEL_YPOS;
1889 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1892 redraw_mask |= REDRAW_MICROLEVEL;
1895 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1897 static unsigned long scroll_delay = 0;
1898 static unsigned long label_delay = 0;
1899 static int from_x, from_y, scroll_direction;
1900 static int label_state, label_counter;
1904 from_x = from_y = 0;
1905 scroll_direction = MV_RIGHT;
1909 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1910 DrawMicroLevelLabelExt(label_state);
1912 /* initialize delay counters */
1913 DelayReached(&scroll_delay, 0);
1914 DelayReached(&label_delay, 0);
1919 /* scroll micro level, if needed */
1920 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1921 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1923 switch (scroll_direction)
1929 scroll_direction = MV_UP;
1933 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1936 scroll_direction = MV_DOWN;
1943 scroll_direction = MV_RIGHT;
1947 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1950 scroll_direction = MV_LEFT;
1957 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1960 /* redraw micro level label, if needed */
1961 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1962 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1963 strcmp(level.author, leveldir_current->name) != 0 &&
1964 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1966 int max_label_counter = 23;
1968 if (leveldir_current->imported_from != NULL)
1969 max_label_counter += 14;
1971 label_counter = (label_counter + 1) % max_label_counter;
1972 label_state = (label_counter >= 0 && label_counter <= 7 ?
1973 MICROLABEL_LEVEL_NAME :
1974 label_counter >= 9 && label_counter <= 12 ?
1975 MICROLABEL_CREATED_BY :
1976 label_counter >= 14 && label_counter <= 21 ?
1977 MICROLABEL_LEVEL_AUTHOR :
1978 label_counter >= 23 && label_counter <= 26 ?
1979 MICROLABEL_IMPORTED_FROM :
1980 label_counter >= 28 && label_counter <= 35 ?
1981 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1982 DrawMicroLevelLabelExt(label_state);
1986 int REQ_in_range(int x, int y)
1988 if (y > DY+249 && y < DY+278)
1990 if (x > DX+1 && x < DX+48)
1992 else if (x > DX+51 && x < DX+98)
1998 #define MAX_REQUEST_LINES 13
1999 #define MAX_REQUEST_LINE_LEN 7
2001 boolean Request(char *text, unsigned int req_state)
2003 int mx, my, ty, result = -1;
2004 unsigned int old_door_state;
2006 #if defined(PLATFORM_UNIX)
2007 /* pause network game while waiting for request to answer */
2008 if (options.network &&
2009 game_status == PLAYING &&
2010 req_state & REQUEST_WAIT_FOR)
2011 SendToServer_PausePlaying();
2014 old_door_state = GetDoorState();
2018 CloseDoor(DOOR_CLOSE_1);
2020 /* save old door content */
2021 BlitBitmap(bitmap_db_door, bitmap_db_door,
2022 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
2023 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
2025 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2027 /* clear door drawing field */
2028 DrawBackground(DX, DY, DXSIZE, DYSIZE);
2030 /* write text for request */
2031 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
2033 char text_line[MAX_REQUEST_LINE_LEN + 1];
2039 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
2042 if (!tc || tc == ' ')
2053 strncpy(text_line, text, tl);
2056 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
2057 text_line, FS_SMALL, FC_YELLOW);
2059 text += tl + (tc == ' ' ? 1 : 0);
2062 if (req_state & REQ_ASK)
2064 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2065 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2067 else if (req_state & REQ_CONFIRM)
2069 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2071 else if (req_state & REQ_PLAYER)
2073 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2074 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2075 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2076 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2079 /* copy request gadgets to door backbuffer */
2080 BlitBitmap(drawto, bitmap_db_door,
2081 DX, DY, DXSIZE, DYSIZE,
2082 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2084 OpenDoor(DOOR_OPEN_1);
2090 if (!(req_state & REQUEST_WAIT_FOR))
2092 SetDrawBackgroundMask(REDRAW_FIELD);
2097 if (game_status != MAINMENU)
2100 button_status = MB_RELEASED;
2102 request_gadget_id = -1;
2104 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
2116 case EVENT_BUTTONPRESS:
2117 case EVENT_BUTTONRELEASE:
2118 case EVENT_MOTIONNOTIFY:
2120 if (event.type == EVENT_MOTIONNOTIFY)
2122 if (!PointerInWindow(window))
2123 continue; /* window and pointer are on different screens */
2128 motion_status = TRUE;
2129 mx = ((MotionEvent *) &event)->x;
2130 my = ((MotionEvent *) &event)->y;
2134 motion_status = FALSE;
2135 mx = ((ButtonEvent *) &event)->x;
2136 my = ((ButtonEvent *) &event)->y;
2137 if (event.type == EVENT_BUTTONPRESS)
2138 button_status = ((ButtonEvent *) &event)->button;
2140 button_status = MB_RELEASED;
2143 /* this sets 'request_gadget_id' */
2144 HandleGadgets(mx, my, button_status);
2146 switch(request_gadget_id)
2148 case TOOL_CTRL_ID_YES:
2151 case TOOL_CTRL_ID_NO:
2154 case TOOL_CTRL_ID_CONFIRM:
2155 result = TRUE | FALSE;
2158 case TOOL_CTRL_ID_PLAYER_1:
2161 case TOOL_CTRL_ID_PLAYER_2:
2164 case TOOL_CTRL_ID_PLAYER_3:
2167 case TOOL_CTRL_ID_PLAYER_4:
2178 case EVENT_KEYPRESS:
2179 switch(GetEventKey((KeyEvent *)&event, TRUE))
2192 if (req_state & REQ_PLAYER)
2196 case EVENT_KEYRELEASE:
2197 ClearPlayerAction();
2201 HandleOtherEvents(&event);
2205 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2207 int joy = AnyJoystick();
2209 if (joy & JOY_BUTTON_1)
2211 else if (joy & JOY_BUTTON_2)
2217 /* don't eat all CPU time */
2221 if (game_status != MAINMENU)
2226 if (!(req_state & REQ_STAY_OPEN))
2228 CloseDoor(DOOR_CLOSE_1);
2230 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2232 BlitBitmap(bitmap_db_door, bitmap_db_door,
2233 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2234 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2235 OpenDoor(DOOR_OPEN_1);
2241 SetDrawBackgroundMask(REDRAW_FIELD);
2243 #if defined(PLATFORM_UNIX)
2244 /* continue network game after request */
2245 if (options.network &&
2246 game_status == PLAYING &&
2247 req_state & REQUEST_WAIT_FOR)
2248 SendToServer_ContinuePlaying();
2254 unsigned int OpenDoor(unsigned int door_state)
2256 unsigned int new_door_state;
2258 if (door_state & DOOR_COPY_BACK)
2260 BlitBitmap(bitmap_db_door, bitmap_db_door,
2261 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2262 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2263 door_state &= ~DOOR_COPY_BACK;
2266 new_door_state = MoveDoor(door_state);
2268 return(new_door_state);
2271 unsigned int CloseDoor(unsigned int door_state)
2273 unsigned int new_door_state;
2275 BlitBitmap(backbuffer, bitmap_db_door,
2276 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2277 BlitBitmap(backbuffer, bitmap_db_door,
2278 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2280 new_door_state = MoveDoor(door_state);
2282 return(new_door_state);
2285 unsigned int GetDoorState()
2287 return MoveDoor(DOOR_GET_STATE);
2290 unsigned int SetDoorState(unsigned int door_state)
2292 return MoveDoor(door_state | DOOR_SET_STATE);
2295 unsigned int MoveDoor(unsigned int door_state)
2297 static int door1 = DOOR_OPEN_1;
2298 static int door2 = DOOR_CLOSE_2;
2299 static unsigned long door_delay = 0;
2300 int x, start, stepsize = 2;
2301 unsigned long door_delay_value = stepsize * 5;
2303 if (door_state == DOOR_GET_STATE)
2304 return(door1 | door2);
2306 if (door_state & DOOR_SET_STATE)
2308 if (door_state & DOOR_ACTION_1)
2309 door1 = door_state & DOOR_ACTION_1;
2310 if (door_state & DOOR_ACTION_2)
2311 door2 = door_state & DOOR_ACTION_2;
2313 return(door1 | door2);
2316 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2317 door_state &= ~DOOR_OPEN_1;
2318 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2319 door_state &= ~DOOR_CLOSE_1;
2320 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2321 door_state &= ~DOOR_OPEN_2;
2322 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2323 door_state &= ~DOOR_CLOSE_2;
2325 if (setup.quick_doors)
2328 door_delay_value = 0;
2330 StopSound(SND_MENU_DOOR_OPENING);
2331 StopSound(SND_MENU_DOOR_CLOSING);
2334 if (global.autoplay_leveldir)
2336 door_state |= DOOR_NO_DELAY;
2337 door_state &= ~DOOR_CLOSE_ALL;
2340 if (door_state & DOOR_ACTION)
2342 if (!(door_state & DOOR_NO_DELAY))
2344 /* opening door sound has priority over simultaneously closing door */
2345 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2346 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2347 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2348 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2351 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2353 for(x=start; x<=DXSIZE; x+=stepsize)
2355 Bitmap *bitmap = new_graphic_info[IMG_GLOBAL_DOOR].bitmap;
2356 GC gc = bitmap->stored_clip_gc;
2358 if (!(door_state & DOOR_NO_DELAY))
2359 WaitUntilDelayReached(&door_delay, door_delay_value);
2361 if (door_state & DOOR_ACTION_1)
2363 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2364 int j = (DXSIZE - i) / 3;
2366 BlitBitmap(bitmap_db_door, drawto,
2367 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2368 DXSIZE,DYSIZE - i/2, DX, DY);
2370 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2372 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2373 BlitBitmapMasked(bitmap, drawto,
2374 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2375 DX + DXSIZE - i, DY + j);
2376 BlitBitmapMasked(bitmap, drawto,
2377 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2378 DX + DXSIZE - i, DY + 140 + j);
2379 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2380 BlitBitmapMasked(bitmap, drawto,
2381 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2383 BlitBitmapMasked(bitmap, drawto,
2384 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2387 BlitBitmapMasked(bitmap, drawto,
2388 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2390 BlitBitmapMasked(bitmap, drawto,
2391 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2393 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2394 BlitBitmapMasked(bitmap, drawto,
2395 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2396 DX + DXSIZE - i, DY + 77 + j);
2397 BlitBitmapMasked(bitmap, drawto,
2398 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2399 DX + DXSIZE - i, DY + 203 + j);
2401 redraw_mask |= REDRAW_DOOR_1;
2404 if (door_state & DOOR_ACTION_2)
2406 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2407 int j = (VXSIZE - i) / 3;
2409 BlitBitmap(bitmap_db_door, drawto,
2410 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2411 VXSIZE, VYSIZE - i/2, VX, VY);
2413 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2415 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2416 BlitBitmapMasked(bitmap, drawto,
2417 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2418 VX + VXSIZE-i, VY+j);
2419 SetClipOrigin(bitmap, gc,
2420 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2421 BlitBitmapMasked(bitmap, drawto,
2422 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2425 BlitBitmapMasked(bitmap, drawto,
2426 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2427 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2428 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2429 BlitBitmapMasked(bitmap, drawto,
2430 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2432 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2434 redraw_mask |= REDRAW_DOOR_2;
2439 if (game_status == MAINMENU)
2444 if (setup.quick_doors)
2446 StopSound(SND_MENU_DOOR_OPENING);
2447 StopSound(SND_MENU_DOOR_CLOSING);
2450 if (door_state & DOOR_ACTION_1)
2451 door1 = door_state & DOOR_ACTION_1;
2452 if (door_state & DOOR_ACTION_2)
2453 door2 = door_state & DOOR_ACTION_2;
2455 return (door1 | door2);
2458 void DrawSpecialEditorDoor()
2460 /* draw bigger toolbox window */
2461 BlitBitmap(new_graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2462 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2464 BlitBitmap(new_graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2465 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2468 redraw_mask |= REDRAW_ALL;
2471 void UndrawSpecialEditorDoor()
2473 /* draw normal tape recorder window */
2474 BlitBitmap(new_graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2475 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2478 redraw_mask |= REDRAW_ALL;
2482 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2484 XImage *pixel_image;
2485 unsigned long pixel_value;
2487 pixel_image = XGetImage(display, bitmap->drawable,
2488 x, y, 1, 1, AllPlanes, ZPixmap);
2489 pixel_value = XGetPixel(pixel_image, 0, 0);
2491 XDestroyImage(pixel_image);
2497 /* ---------- new tool button stuff ---------------------------------------- */
2499 /* graphic position values for tool buttons */
2500 #define TOOL_BUTTON_YES_XPOS 2
2501 #define TOOL_BUTTON_YES_YPOS 250
2502 #define TOOL_BUTTON_YES_GFX_YPOS 0
2503 #define TOOL_BUTTON_YES_XSIZE 46
2504 #define TOOL_BUTTON_YES_YSIZE 28
2505 #define TOOL_BUTTON_NO_XPOS 52
2506 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2507 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2508 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2509 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2510 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2511 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2512 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2513 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2514 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2515 #define TOOL_BUTTON_PLAYER_XSIZE 30
2516 #define TOOL_BUTTON_PLAYER_YSIZE 30
2517 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2518 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2519 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2520 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2521 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2522 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2523 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2524 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2525 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2526 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2527 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2528 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2529 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2530 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2531 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2532 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2533 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2534 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2535 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2536 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2545 } toolbutton_info[NUM_TOOL_BUTTONS] =
2548 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2549 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2550 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2555 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2556 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2557 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2562 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2563 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2564 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2565 TOOL_CTRL_ID_CONFIRM,
2569 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2570 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2571 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2572 TOOL_CTRL_ID_PLAYER_1,
2576 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2577 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2578 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2579 TOOL_CTRL_ID_PLAYER_2,
2583 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2584 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2585 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2586 TOOL_CTRL_ID_PLAYER_3,
2590 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2591 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2592 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2593 TOOL_CTRL_ID_PLAYER_4,
2598 void CreateToolButtons()
2602 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2604 Bitmap *gd_bitmap = new_graphic_info[IMG_GLOBAL_DOOR].bitmap;
2605 Bitmap *deco_bitmap = None;
2606 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2607 struct GadgetInfo *gi;
2608 unsigned long event_mask;
2609 int gd_xoffset, gd_yoffset;
2610 int gd_x1, gd_x2, gd_y;
2613 event_mask = GD_EVENT_RELEASED;
2615 gd_xoffset = toolbutton_info[i].xpos;
2616 gd_yoffset = toolbutton_info[i].ypos;
2617 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2618 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2619 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2621 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2623 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2625 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2626 &deco_bitmap, &deco_x, &deco_y);
2627 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2628 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2631 gi = CreateGadget(GDI_CUSTOM_ID, id,
2632 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2633 GDI_X, DX + toolbutton_info[i].x,
2634 GDI_Y, DY + toolbutton_info[i].y,
2635 GDI_WIDTH, toolbutton_info[i].width,
2636 GDI_HEIGHT, toolbutton_info[i].height,
2637 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2638 GDI_STATE, GD_BUTTON_UNPRESSED,
2639 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2640 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2641 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2642 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2643 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2644 GDI_DECORATION_SHIFTING, 1, 1,
2645 GDI_EVENT_MASK, event_mask,
2646 GDI_CALLBACK_ACTION, HandleToolButtons,
2650 Error(ERR_EXIT, "cannot create gadget");
2652 tool_gadget[id] = gi;
2656 void FreeToolButtons()
2660 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2661 FreeGadget(tool_gadget[i]);
2664 static void UnmapToolButtons()
2668 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2669 UnmapGadget(tool_gadget[i]);
2672 static void HandleToolButtons(struct GadgetInfo *gi)
2674 request_gadget_id = gi->custom_id;
2677 int get_next_element(int element)
2681 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2682 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2683 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2684 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2685 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2686 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2687 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2689 default: return element;
2693 int el2gfx_OLD(int element)
2697 case EL_EMPTY: return -1;
2698 case EL_SAND: return GFX_ERDREICH;
2699 case EL_WALL: return GFX_MAUERWERK;
2700 case EL_WALL_CRUMBLED: return GFX_FELSBODEN;
2701 case EL_ROCK: return GFX_FELSBROCKEN;
2702 case EL_EMERALD: return GFX_EDELSTEIN;
2703 case EL_EXIT_CLOSED: return GFX_AUSGANG_ZU;
2704 case EL_EXIT_OPENING: return GFX_AUSGANG_ACT;
2705 case EL_EXIT_OPEN: return GFX_AUSGANG_AUF;
2706 case EL_SP_EXIT_OPEN: return GFX_SP_EXIT;
2707 case EL_PLAYER1: return GFX_SPIELER1;
2708 case EL_PLAYER2: return GFX_SPIELER2;
2709 case EL_PLAYER3: return GFX_SPIELER3;
2710 case EL_PLAYER4: return GFX_SPIELER4;
2711 case EL_BUG: return GFX_KAEFER;
2712 case EL_BUG_RIGHT: return GFX_KAEFER_RIGHT;
2713 case EL_BUG_UP: return GFX_KAEFER_UP;
2714 case EL_BUG_LEFT: return GFX_KAEFER_LEFT;
2715 case EL_BUG_DOWN: return GFX_KAEFER_DOWN;
2716 case EL_SPACESHIP: return GFX_FLIEGER;
2717 case EL_SPACESHIP_RIGHT: return GFX_FLIEGER_RIGHT;
2718 case EL_SPACESHIP_UP: return GFX_FLIEGER_UP;
2719 case EL_SPACESHIP_LEFT: return GFX_FLIEGER_LEFT;
2720 case EL_SPACESHIP_DOWN: return GFX_FLIEGER_DOWN;
2721 case EL_BD_BUTTERFLY: return GFX_BUTTERFLY;
2722 case EL_BD_BUTTERFLY_RIGHT: return GFX_BUTTERFLY_RIGHT;
2723 case EL_BD_BUTTERFLY_UP: return GFX_BUTTERFLY_UP;
2724 case EL_BD_BUTTERFLY_LEFT: return GFX_BUTTERFLY_LEFT;
2725 case EL_BD_BUTTERFLY_DOWN: return GFX_BUTTERFLY_DOWN;
2726 case EL_BD_FIREFLY: return GFX_FIREFLY;
2727 case EL_BD_FIREFLY_RIGHT: return GFX_FIREFLY_RIGHT;
2728 case EL_BD_FIREFLY_UP: return GFX_FIREFLY_UP;
2729 case EL_BD_FIREFLY_LEFT: return GFX_FIREFLY_LEFT;
2730 case EL_BD_FIREFLY_DOWN: return GFX_FIREFLY_DOWN;
2731 case EL_YAMYAM: return GFX_MAMPFER;
2732 case EL_ROBOT: return GFX_ROBOT;
2733 case EL_STEELWALL: return GFX_BETON;
2734 case EL_DIAMOND: return GFX_DIAMANT;
2735 case EL_QUICKSAND_EMPTY: return GFX_MORAST_LEER;
2736 case EL_QUICKSAND_FULL: return GFX_MORAST_VOLL;
2737 case EL_QUICKSAND_EMPTYING: return GFX_MORAST_LEER;
2738 case EL_AMOEBA_DROP: return GFX_TROPFEN;
2739 case EL_BOMB: return GFX_BOMBE;
2740 case EL_MAGIC_WALL: return GFX_MAGIC_WALL_OFF;
2741 case EL_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_EMPTY;
2742 case EL_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_EMPTY;
2743 case EL_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_FULL;
2744 case EL_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_DEAD;
2745 case EL_ACID: return GFX_SALZSAEURE;
2746 case EL_AMOEBA_DEAD: return GFX_AMOEBE_TOT;
2747 case EL_AMOEBA_WET: return GFX_AMOEBE_NASS;
2748 case EL_AMOEBA_DRY: return GFX_AMOEBE_NORM;
2749 case EL_AMOEBA_FULL: return GFX_AMOEBE_VOLL;
2750 case EL_BD_AMOEBA: return GFX_AMOEBE_BD;
2751 case EL_AMOEBA_TO_DIAMOND: return GFX_AMOEBA2DIAM;
2752 case EL_AMOEBA_DRIPPING: return GFX_AMOEBE_NASS;
2753 case EL_NUT: return GFX_KOKOSNUSS;
2754 case EL_GAMEOFLIFE: return GFX_LIFE;
2755 case EL_BIOMAZE: return GFX_LIFE_ASYNC;
2756 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2757 case EL_STONEBLOCK: return GFX_BADEWANNE;
2758 case EL_ACIDPOOL_TOPLEFT: return GFX_BADEWANNE1;
2759 case EL_ACIDPOOL_TOPRIGHT: return GFX_BADEWANNE2;
2760 case EL_ACIDPOOL_BOTTOMLEFT: return GFX_BADEWANNE3;
2761 case EL_ACIDPOOL_BOTTOM: return GFX_BADEWANNE4;
2762 case EL_ACIDPOOL_BOTTOMRIGHT: return GFX_BADEWANNE5;
2763 case EL_ROBOT_WHEEL: return GFX_ABLENK_AUS;
2764 case EL_ROBOT_WHEEL_ACTIVE: return GFX_ABLENK_EIN;
2765 case EL_KEY1: return GFX_SCHLUESSEL1;
2766 case EL_KEY2: return GFX_SCHLUESSEL2;
2767 case EL_KEY3: return GFX_SCHLUESSEL3;
2768 case EL_KEY4: return GFX_SCHLUESSEL4;
2769 case EL_GATE1: return GFX_PFORTE1;
2770 case EL_GATE2: return GFX_PFORTE2;
2771 case EL_GATE3: return GFX_PFORTE3;
2772 case EL_GATE4: return GFX_PFORTE4;
2773 case EL_GATE1_GRAY: return GFX_PFORTE1X;
2774 case EL_GATE2_GRAY: return GFX_PFORTE2X;
2775 case EL_GATE3_GRAY: return GFX_PFORTE3X;
2776 case EL_GATE4_GRAY: return GFX_PFORTE4X;
2777 case EL_DYNAMITE: return GFX_DYNAMIT_AUS;
2778 case EL_PACMAN: return GFX_PACMAN;
2779 case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT;
2780 case EL_PACMAN_UP: return GFX_PACMAN_UP;
2781 case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT;
2782 case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN;
2783 case EL_INVISIBLE_WALL: return GFX_UNSICHTBAR;
2784 case EL_INVISIBLE_WALL_ACTIVE: return GFX_UNSICHTBAR_ON;
2785 case EL_WALL_EMERALD: return GFX_ERZ_EDEL;
2786 case EL_WALL_DIAMOND: return GFX_ERZ_DIAM;
2787 case EL_LAMP: return GFX_BIRNE_AUS;
2788 case EL_LAMP_ACTIVE: return GFX_BIRNE_EIN;
2789 case EL_TIME_ORB_FULL: return GFX_ZEIT_VOLL;
2790 case EL_TIME_ORB_EMPTY: return GFX_ZEIT_LEER;
2791 case EL_WALL_GROWING: return GFX_MAUER_LEBT;
2792 case EL_WALL_GROWING_X: return GFX_MAUER_X;
2793 case EL_WALL_GROWING_Y: return GFX_MAUER_Y;
2794 case EL_WALL_GROWING_XY: return GFX_MAUER_XY;
2795 case EL_BD_DIAMOND: return GFX_EDELSTEIN_BD;
2796 case EL_EMERALD_YELLOW: return GFX_EDELSTEIN_GELB;
2797 case EL_EMERALD_RED: return GFX_EDELSTEIN_ROT;
2798 case EL_EMERALD_PURPLE: return GFX_EDELSTEIN_LILA;
2799 case EL_WALL_BD_DIAMOND: return GFX_ERZ_EDEL_BD;
2800 case EL_WALL_EMERALD_YELLOW: return GFX_ERZ_EDEL_GELB;
2801 case EL_WALL_EMERALD_RED: return GFX_ERZ_EDEL_ROT;
2802 case EL_WALL_EMERALD_PURPLE: return GFX_ERZ_EDEL_LILA;
2803 case EL_DARK_YAMYAM: return GFX_MAMPFER2;
2804 case EL_BD_MAGIC_WALL: return GFX_MAGIC_WALL_BD_OFF;
2805 case EL_BD_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_BD_EMPTY;
2806 case EL_BD_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_BD_EMPTY;
2807 case EL_BD_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_BD_FULL;
2808 case EL_BD_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2809 case EL_DYNABOMB_PLAYER1_ACTIVE: return GFX_DYNABOMB;
2810 case EL_DYNABOMB_PLAYER2_ACTIVE: return GFX_DYNABOMB;
2811 case EL_DYNABOMB_PLAYER3_ACTIVE: return GFX_DYNABOMB;
2812 case EL_DYNABOMB_PLAYER4_ACTIVE: return GFX_DYNABOMB;
2813 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2814 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2815 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2816 case EL_SOKOBAN_OBJECT: return GFX_SOKOBAN_OBJEKT;
2817 case EL_SOKOBAN_FIELD_EMPTY: return GFX_SOKOBAN_FELD_LEER;
2818 case EL_SOKOBAN_FIELD_FULL: return GFX_SOKOBAN_FELD_VOLL;
2819 case EL_MOLE: return GFX_MOLE;
2820 case EL_PENGUIN: return GFX_PINGUIN;
2821 case EL_PIG: return GFX_SCHWEIN;
2822 case EL_DRAGON: return GFX_DRACHE;
2823 case EL_SATELLITE: return GFX_SONDE;
2824 case EL_ARROW_BLUE_LEFT: return GFX_PFEIL_LEFT;
2825 case EL_ARROW_BLUE_RIGHT: return GFX_PFEIL_RIGHT;
2826 case EL_ARROW_BLUE_UP: return GFX_PFEIL_UP;
2827 case EL_ARROW_BLUE_DOWN: return GFX_PFEIL_DOWN;
2828 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2829 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2830 case EL_SP_BUGGY_BASE_ACTIVE: return GFX_SP_BUG_ACTIVE;
2831 case EL_SP_ZONK: return GFX_SP_ZONK;
2832 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2833 case EL_INVISIBLE_STEELWALL: return GFX_INVISIBLE_STEEL;
2834 case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2835 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2836 case EL_EM_GATE1: return GFX_EM_GATE_1;
2837 case EL_EM_GATE2: return GFX_EM_GATE_2;
2838 case EL_EM_GATE3: return GFX_EM_GATE_3;
2839 case EL_EM_GATE4: return GFX_EM_GATE_4;
2840 case EL_EM_GATE1_GRAY: return GFX_EM_GATE_1X;
2841 case EL_EM_GATE2_GRAY: return GFX_EM_GATE_2X;
2842 case EL_EM_GATE3_GRAY: return GFX_EM_GATE_3X;
2843 case EL_EM_GATE4_GRAY: return GFX_EM_GATE_4X;
2844 case EL_EM_KEY1_FILE: return GFX_EM_KEY_1;
2845 case EL_EM_KEY2_FILE: return GFX_EM_KEY_2;
2846 case EL_EM_KEY3_FILE: return GFX_EM_KEY_3;
2847 case EL_EM_KEY4_FILE: return GFX_EM_KEY_4;
2848 case EL_EM_KEY1: return GFX_EM_KEY_1;
2849 case EL_EM_KEY2: return GFX_EM_KEY_2;
2850 case EL_EM_KEY3: return GFX_EM_KEY_3;
2851 case EL_EM_KEY4: return GFX_EM_KEY_4;
2852 case EL_PEARL: return GFX_PEARL;
2853 case EL_CRYSTAL: return GFX_CRYSTAL;
2854 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2855 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2856 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2857 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2858 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2859 case EL_SHIELD_NORMAL: return GFX_SHIELD_PASSIVE;
2860 case EL_SHIELD_DEADLY: return GFX_SHIELD_ACTIVE;
2861 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2862 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2863 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2864 case EL_SWITCHGATE_SWITCH_UP: return GFX_SWITCHGATE_SWITCH_1;
2865 case EL_SWITCHGATE_SWITCH_DOWN: return GFX_SWITCHGATE_SWITCH_2;
2866 case EL_CONVEYOR_BELT1_LEFT: return GFX_BELT1_LEFT;
2867 case EL_CONVEYOR_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2868 case EL_CONVEYOR_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2869 case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2870 case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2871 case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2872 case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2873 case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2874 case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2875 case EL_CONVEYOR_BELT2_LEFT: return GFX_BELT2_LEFT;
2876 case EL_CONVEYOR_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2877 case EL_CONVEYOR_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2878 case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2879 case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2880 case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2881 case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2882 case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2883 case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2884 case EL_CONVEYOR_BELT3_LEFT: return GFX_BELT3_LEFT;
2885 case EL_CONVEYOR_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2886 case EL_CONVEYOR_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2887 case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2888 case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2889 case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2890 case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2891 case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2892 case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2893 case EL_CONVEYOR_BELT4_LEFT: return GFX_BELT4_LEFT;
2894 case EL_CONVEYOR_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2895 case EL_CONVEYOR_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2896 case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2897 case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2898 case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2899 case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2900 case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2901 case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2902 case EL_LANDMINE: return GFX_LANDMINE;
2903 case EL_ENVELOPE: return GFX_ENVELOPE;
2904 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH_OFF;
2905 case EL_LIGHT_SWITCH_ACTIVE: return GFX_LIGHT_SWITCH_ON;
2906 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2907 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2908 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2909 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2910 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2911 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2912 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2913 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2914 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2915 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2916 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2917 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2918 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2919 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2920 case EL_MOLE_UP: return GFX_MOLE_UP;
2921 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2922 case EL_STEELWALL_SLANTED: return GFX_STEEL_SLANTED;
2923 case EL_INVISIBLE_SAND: return GFX_SAND_INVISIBLE;
2924 case EL_INVISIBLE_SAND_ACTIVE: return GFX_SAND_INVISIBLE_ON;
2925 case EL_DX_UNKNOWN_15: return GFX_DX_UNKNOWN_15;
2926 case EL_DX_UNKNOWN_42: return GFX_DX_UNKNOWN_42;
2927 case EL_TIMEGATE_OPEN: return GFX_TIMEGATE_OPEN;
2928 case EL_TIMEGATE_CLOSED: return GFX_TIMEGATE_CLOSED;
2929 case EL_TIMEGATE_SWITCH_ACTIVE: return GFX_TIMEGATE_SWITCH;
2930 case EL_TIMEGATE_SWITCH: return GFX_TIMEGATE_SWITCH;
2931 case EL_BALLOON: return GFX_BALLOON;
2932 case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
2933 case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2934 case EL_BALLOON_SEND_UP: return GFX_BALLOON_SEND_UP;
2935 case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
2936 case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2937 case EL_EMC_STEELWALL1: return GFX_EMC_STEEL_WALL_1;
2938 case EL_EMC_STEELWALL2: return GFX_EMC_STEEL_WALL_2;
2939 case EL_EMC_STEELWALL3: return GFX_EMC_STEEL_WALL_3;
2940 case EL_EMC_STEELWALL4: return GFX_EMC_STEEL_WALL_4;
2941 case EL_EMC_WALL_PILLAR_UPPER: return GFX_EMC_WALL_1;
2942 case EL_EMC_WALL_PILLAR_MIDDLE: return GFX_EMC_WALL_2;
2943 case EL_EMC_WALL_PILLAR_LOWER: return GFX_EMC_WALL_3;
2944 case EL_EMC_WALL4: return GFX_EMC_WALL_4;
2945 case EL_EMC_WALL5: return GFX_EMC_WALL_5;
2946 case EL_EMC_WALL6: return GFX_EMC_WALL_6;
2947 case EL_EMC_WALL7: return GFX_EMC_WALL_7;
2948 case EL_EMC_WALL8: return GFX_EMC_WALL_8;
2949 case EL_TUBE_ALL: return GFX_TUBE_CROSS;
2950 case EL_TUBE_VERTICAL: return GFX_TUBE_VERTICAL;
2951 case EL_TUBE_HORIZONTAL: return GFX_TUBE_HORIZONTAL;
2952 case EL_TUBE_VERTICAL_LEFT: return GFX_TUBE_VERT_LEFT;
2953 case EL_TUBE_VERTICAL_RIGHT: return GFX_TUBE_VERT_RIGHT;
2954 case EL_TUBE_HORIZONTAL_UP: return GFX_TUBE_HORIZ_UP;
2955 case EL_TUBE_HORIZONTAL_DOWN: return GFX_TUBE_HORIZ_DOWN;
2956 case EL_TUBE_LEFT_UP: return GFX_TUBE_LEFT_UP;
2957 case EL_TUBE_LEFT_DOWN: return GFX_TUBE_LEFT_DOWN;
2958 case EL_TUBE_RIGHT_UP: return GFX_TUBE_RIGHT_UP;
2959 case EL_TUBE_RIGHT_DOWN: return GFX_TUBE_RIGHT_DOWN;
2960 case EL_SPRING: return GFX_SPRING;
2961 case EL_TRAP: return GFX_TRAP_INACTIVE;
2962 case EL_TRAP_ACTIVE: return GFX_TRAP_ACTIVE;
2963 case EL_BD_WALL: return GFX_BD_WALL;
2964 case EL_BD_ROCK: return GFX_BD_ROCK;
2965 case EL_DX_SUPABOMB: return GFX_DX_SUPABOMB;
2966 case EL_SP_MURPHY_CLONE: return GFX_SP_MURPHY_CLONE;
2970 if (IS_CHAR(element))
2971 return GFX_CHAR_START + (element - EL_CHAR_START);
2972 else if (element >= EL_SP_START && element <= EL_SP_END)
2974 int nr_element = element - EL_SP_START;
2975 int gfx_per_line = 8;
2977 (nr_element / gfx_per_line) * SP_PER_LINE +
2978 (nr_element % gfx_per_line);
2980 return GFX_START_ROCKSSP + nr_graphic;
2988 int el2gfx(int element)
2991 int graphic_OLD = el2gfx_OLD(element);
2996 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2999 int graphic_OLD = el2gfx_OLD(element);
3001 if (element >= MAX_NUM_ELEMENTS)
3003 Error(ERR_WARN, "el2gfx: element == %d >= MAX_NUM_ELEMENTS", element);
3006 if (graphic_NEW != graphic_OLD)
3008 Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
3009 graphic_NEW, graphic_OLD);
3017 int el2img(int element)
3019 int graphic = element_info[element].graphic[GFX_ACTION_DEFAULT];
3023 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
3030 int el_dir2img(int element, int direction)
3032 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
3035 int el_dir_act2img(int element, int direction, int action)
3040 printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: element == %d\n",
3048 printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: action == %d\n",
3055 action = graphics_action_mapping[action];
3056 direction = MV_DIR_BIT(direction);
3058 return element_info[element].direction_graphic[action][direction];