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 int getGraphicAnimationPhase(int, int, int);
36 static void UnmapToolButtons();
37 static void HandleToolButtons(struct GadgetInfo *);
39 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
40 static int request_gadget_id = -1;
42 void SetDrawtoField(int mode)
44 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
55 drawto_field = fieldbuffer;
57 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
68 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
72 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
74 if (game_status == PLAYING)
80 width = gfx.sxsize + 2 * TILEX;
81 height = gfx.sysize + 2 * TILEY;
84 if (force_redraw || setup.direct_draw)
87 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
88 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
90 if (setup.direct_draw)
91 SetDrawtoField(DRAW_BACKBUFFER);
93 for(xx=BX1; xx<=BX2; xx++)
94 for(yy=BY1; yy<=BY2; yy++)
95 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
96 DrawScreenField(xx, yy);
99 if (setup.direct_draw)
100 SetDrawtoField(DRAW_DIRECT);
103 if (setup.soft_scrolling)
105 int fx = FX, fy = FY;
107 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
108 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
110 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
114 BlitBitmap(drawto, window, x, y, width, height, x, y);
120 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
122 if (setup.direct_draw && game_status == PLAYING)
123 redraw_mask &= ~REDRAW_MAIN;
125 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
126 redraw_mask |= REDRAW_FIELD;
128 if (redraw_mask & REDRAW_FIELD)
129 redraw_mask &= ~REDRAW_TILES;
131 if (redraw_mask == REDRAW_NONE)
134 if (global.fps_slowdown && game_status == PLAYING)
136 static boolean last_frame_skipped = FALSE;
137 boolean skip_even_when_not_scrolling = TRUE;
138 boolean just_scrolling = (ScreenMovDir != 0);
139 boolean verbose = FALSE;
141 if (global.fps_slowdown_factor > 1 &&
142 (FrameCounter % global.fps_slowdown_factor) &&
143 (just_scrolling || skip_even_when_not_scrolling))
145 redraw_mask &= ~REDRAW_MAIN;
147 last_frame_skipped = TRUE;
150 printf("FRAME SKIPPED\n");
154 if (last_frame_skipped)
155 redraw_mask |= REDRAW_FIELD;
157 last_frame_skipped = FALSE;
160 printf("frame not skipped\n");
164 /* synchronize X11 graphics at this point; if we would synchronize the
165 display immediately after the buffer switching (after the XFlush),
166 this could mean that we have to wait for the graphics to complete,
167 although we could go on doing calculations for the next frame */
171 if (redraw_mask & REDRAW_ALL)
173 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
177 if (redraw_mask & REDRAW_FIELD)
179 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
181 BlitBitmap(backbuffer, window,
182 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
186 int fx = FX, fy = FY;
188 if (setup.soft_scrolling)
190 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
191 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
194 if (setup.soft_scrolling ||
195 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
196 ABS(ScreenMovPos) == ScrollStepSize ||
197 redraw_tiles > REDRAWTILES_THRESHOLD)
199 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
203 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
205 (setup.soft_scrolling ?
206 "setup.soft_scrolling" :
207 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
208 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
209 ABS(ScreenGfxPos) == ScrollStepSize ?
210 "ABS(ScreenGfxPos) == ScrollStepSize" :
211 "redraw_tiles > REDRAWTILES_THRESHOLD"));
217 redraw_mask &= ~REDRAW_MAIN;
220 if (redraw_mask & REDRAW_DOORS)
222 if (redraw_mask & REDRAW_DOOR_1)
223 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
224 if (redraw_mask & REDRAW_DOOR_2)
226 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
227 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
230 if (redraw_mask & REDRAW_VIDEO_1)
231 BlitBitmap(backbuffer, window,
232 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
233 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
234 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
235 if (redraw_mask & REDRAW_VIDEO_2)
236 BlitBitmap(backbuffer, window,
237 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
238 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
239 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
240 if (redraw_mask & REDRAW_VIDEO_3)
241 BlitBitmap(backbuffer, window,
242 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
243 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
244 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
247 if (redraw_mask & REDRAW_DOOR_3)
248 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
249 redraw_mask &= ~REDRAW_DOORS;
252 if (redraw_mask & REDRAW_MICROLEVEL)
254 BlitBitmap(backbuffer, window,
255 MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
256 MICROLEV_XPOS, MICROLEV_YPOS);
257 BlitBitmap(backbuffer, window,
258 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
259 SX, MICROLABEL_YPOS);
260 redraw_mask &= ~REDRAW_MICROLEVEL;
263 if (redraw_mask & REDRAW_TILES)
265 for(x=0; x<SCR_FIELDX; x++)
266 for(y=0; y<SCR_FIELDY; y++)
267 if (redraw[redraw_x1 + x][redraw_y1 + y])
268 BlitBitmap(buffer, window,
269 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
270 SX + x * TILEX, SY + y * TILEY);
273 if (redraw_mask & REDRAW_FPS) /* display frames per second */
278 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
279 if (!global.fps_slowdown)
282 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
283 DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW);
288 for(x=0; x<MAX_BUF_XSIZE; x++)
289 for(y=0; y<MAX_BUF_YSIZE; y++)
292 redraw_mask = REDRAW_NONE;
298 long fading_delay = 300;
300 if (setup.fading && (redraw_mask & REDRAW_FIELD))
307 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
310 for(i=0;i<2*FULL_SYSIZE;i++)
312 for(y=0;y<FULL_SYSIZE;y++)
314 BlitBitmap(backbuffer, window,
315 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
323 for(i=1;i<FULL_SYSIZE;i+=2)
324 BlitBitmap(backbuffer, window,
325 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
331 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
332 BlitBitmapMasked(backbuffer, window,
333 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
338 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
339 BlitBitmapMasked(backbuffer, window,
340 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
345 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
346 BlitBitmapMasked(backbuffer, window,
347 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
352 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
353 BlitBitmapMasked(backbuffer, window,
354 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
359 redraw_mask &= ~REDRAW_MAIN;
368 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
370 if (setup.soft_scrolling && game_status == PLAYING)
372 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
373 SetDrawtoField(DRAW_BUFFERED);
376 SetDrawtoField(DRAW_BACKBUFFER);
378 if (setup.direct_draw && game_status == PLAYING)
380 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
381 SetDrawtoField(DRAW_DIRECT);
384 redraw_mask |= REDRAW_FIELD;
387 void MarkTileDirty(int x, int y)
389 int xx = redraw_x1 + x;
390 int yy = redraw_y1 + y;
395 redraw[xx][yy] = TRUE;
396 redraw_mask |= REDRAW_TILES;
399 void SetBorderElement()
403 BorderElement = EL_EMPTY;
405 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
407 for(x=0; x<lev_fieldx; x++)
409 if (!IS_MASSIVE(Feld[x][y]))
410 BorderElement = EL_STEELWALL;
412 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
418 void DrawAllPlayers()
422 for(i=0; i<MAX_PLAYERS; i++)
423 if (stored_player[i].active)
424 DrawPlayer(&stored_player[i]);
427 void DrawPlayerField(int x, int y)
429 if (!IS_PLAYER(x, y))
432 DrawPlayer(PLAYERINFO(x, y));
435 void DrawPlayer(struct PlayerInfo *player)
437 int jx = player->jx, jy = player->jy;
438 int last_jx = player->last_jx, last_jy = player->last_jy;
439 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
440 int sx = SCREENX(jx), sy = SCREENY(jy);
441 int sxx = 0, syy = 0;
442 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
445 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
447 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
451 if (!IN_LEV_FIELD(jx,jy))
453 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
454 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
455 printf("DrawPlayerField(): This should never happen!\n");
460 if (element == EL_EXPLOSION)
463 /* draw things in the field the player is leaving, if needed */
465 if (player_is_moving)
467 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
469 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
471 if (last_element == EL_DYNAMITE_ACTIVE)
472 DrawDynamite(last_jx, last_jy);
474 DrawLevelFieldThruMask(last_jx, last_jy);
476 else if (last_element == EL_DYNAMITE_ACTIVE)
477 DrawDynamite(last_jx, last_jy);
479 DrawLevelField(last_jx, last_jy);
481 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
485 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
486 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
488 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
491 DrawLevelField(next_jx, next_jy);
495 if (!IN_SCR_FIELD(sx, sy))
498 if (setup.direct_draw)
499 SetDrawtoField(DRAW_BUFFERED);
501 /* draw things behind the player, if needed */
504 DrawLevelElement(jx, jy, Store[jx][jy]);
505 else if (!IS_ACTIVE_BOMB(element))
506 DrawLevelField(jx, jy);
508 DrawLevelElement(jx, jy, EL_EMPTY);
510 /* draw player himself */
512 if (game.emulation == EMU_SUPAPLEX)
514 static int last_dir = MV_LEFT;
515 int action = (player->programmed_action ? player->programmed_action :
517 boolean action_moving =
519 ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
520 !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
522 graphic = IMG_SP_MURPHY;
526 if (player->MovDir == MV_LEFT)
527 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
528 else if (player->MovDir == MV_RIGHT)
529 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
530 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
531 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
532 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
533 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
535 else if (player->snapped)
537 if (player->MovDir == MV_LEFT)
538 graphic = IMG_SP_MURPHY_LEFT_SNAPPING;
539 else if (player->MovDir == MV_RIGHT)
540 graphic = IMG_SP_MURPHY_RIGHT_SNAPPING;
541 else if (player->MovDir == MV_UP)
542 graphic = IMG_SP_MURPHY_UP_SNAPPING;
543 else if (player->MovDir == MV_DOWN)
544 graphic = IMG_SP_MURPHY_DOWN_SNAPPING;
546 else if (action_moving)
548 if (player->MovDir == MV_LEFT)
549 graphic = IMG_SP_MURPHY_LEFT_MOVING;
550 else if (player->MovDir == MV_RIGHT)
551 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
552 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
553 graphic = IMG_SP_MURPHY_LEFT_MOVING;
554 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
555 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
557 graphic = IMG_SP_MURPHY_LEFT_MOVING;
559 frame = getGraphicAnimationFrame(graphic, -1);
562 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
563 last_dir = player->MovDir;
567 if (player->MovDir == MV_LEFT)
568 graphic = (player->Pushing ? IMG_PLAYER1_LEFT_PUSHING :
569 player->is_moving ? IMG_PLAYER1_LEFT_MOVING :
571 else if (player->MovDir == MV_RIGHT)
572 graphic = (player->Pushing ? IMG_PLAYER1_RIGHT_PUSHING :
573 player->is_moving ? IMG_PLAYER1_RIGHT_MOVING :
575 else if (player->MovDir == MV_UP)
576 graphic = (player->Pushing ? IMG_PLAYER1_UP_PUSHING :
577 player->is_moving ? IMG_PLAYER1_UP_MOVING :
579 else /* MV_DOWN || MV_NO_MOVING */
580 graphic = (player->Pushing ? IMG_PLAYER1_DOWN_PUSHING :
581 player->is_moving ? IMG_PLAYER1_DOWN_MOVING :
584 graphic = PLAYER_NR_GFX(graphic, player->index_nr);
587 frame = player->Frame;
589 frame = getGraphicAnimationFrame(graphic, player->Frame);
595 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
596 sxx = player->GfxPos;
598 syy = player->GfxPos;
601 if (!setup.soft_scrolling && ScreenMovPos)
606 printf("-> %d\n", player->Frame);
609 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
611 if (SHIELD_ON(player))
613 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
614 IMG_SHIELD_NORMAL_ACTIVE);
615 int frame = getGraphicAnimationFrame(graphic, -1);
617 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
621 if (player->Pushing && player->GfxPos)
623 if (player->Pushing && player_is_moving)
626 int px = SCREENX(next_jx), py = SCREENY(next_jy);
628 if (element == EL_SOKOBAN_FIELD_EMPTY ||
629 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
630 DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT, 0,
634 int element = Feld[next_jx][next_jy];
635 int graphic = el2img(element);
640 if ((element == EL_ROCK ||
641 element == EL_BD_ROCK ||
642 element == EL_SP_ZONK) && sxx)
644 graphic = el_dir_act2img(element, player->MovDir, GFX_ACTION_MOVING);
646 frame = getGraphicAnimationFrame(graphic, player->GfxPos);
648 frame = getGraphicAnimationFrame(graphic, player->Frame);
652 printf("-> %d [%d]\n", player->Frame, player->GfxPos);
657 if (player->MovDir == MV_LEFT)
662 frame = (player->GfxPos / (TILEX / 4));
664 if (player->MovDir == MV_RIGHT)
665 frame = (frame + 4) % 4;
669 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
670 NO_CUTTING, NO_MASKING);
674 /* draw things in front of player (active dynamite or dynabombs) */
676 if (IS_ACTIVE_BOMB(element))
678 graphic = el2img(element);
681 if (element == EL_DYNAMITE_ACTIVE)
683 if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
688 if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
692 frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
695 if (game.emulation == EMU_SUPAPLEX)
696 DrawGraphic(sx, sy, GFX_SP_DISK_RED, 0);
698 DrawGraphicThruMask(sx, sy, graphic, frame);
701 if (player_is_moving && last_element == EL_EXPLOSION)
703 int stored = Store[last_jx][last_jy];
704 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
705 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
707 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
708 int phase = Frame[last_jx][last_jy] - 1;
709 int frame = getGraphicAnimationFrame(graphic, phase - delay);
712 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
715 /* draw elements that stay over the player */
716 /* handle the field the player is leaving ... */
717 if (player_is_moving && IS_OVER_PLAYER(last_element))
718 DrawLevelField(last_jx, last_jy);
720 /* ... and the field the player is entering */
721 if (IS_OVER_PLAYER(element))
722 DrawLevelField(jx, jy);
724 if (setup.direct_draw)
726 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
727 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
728 int x_size = TILEX * (1 + ABS(jx - last_jx));
729 int y_size = TILEY * (1 + ABS(jy - last_jy));
731 BlitBitmap(drawto_field, window,
732 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
733 SetDrawtoField(DRAW_DIRECT);
736 MarkTileDirty(sx,sy);
739 static int getGraphicAnimationPhase(int frames, int delay, int mode)
743 if (mode & ANIM_PINGPONG)
745 int max_anim_frames = 2 * frames - 2;
747 phase = (FrameCounter % (delay * max_anim_frames)) / delay;
748 phase = (phase < frames ? phase : max_anim_frames - phase);
751 phase = (FrameCounter % (delay * frames)) / delay;
753 if (mode & ANIM_REVERSE)
759 int getGraphicAnimationFrame(int graphic, int sync_frame)
761 int num_frames = new_graphic_info[graphic].anim_frames;
762 int delay = new_graphic_info[graphic].anim_delay;
763 int mode = new_graphic_info[graphic].anim_mode;
766 /* animation synchronized with global frame counter, not move position */
767 if (new_graphic_info[graphic].anim_global_sync || sync_frame < 0)
768 sync_frame = FrameCounter;
770 sync_frame += new_graphic_info[graphic].anim_start_frame * delay;
772 if (mode & ANIM_LOOP) /* normal, looping animation */
774 frame = (sync_frame % (delay * num_frames)) / delay;
776 else if (mode & ANIM_LINEAR) /* normal, non-looping animation */
778 frame = sync_frame / delay;
780 if (frame > num_frames - 1)
781 frame = num_frames - 1;
783 else if (mode & ANIM_PINGPONG) /* use border frames once */
785 int max_anim_frames = 2 * num_frames - 2;
787 frame = (sync_frame % (delay * max_anim_frames)) / delay;
788 frame = (frame < num_frames ? frame : max_anim_frames - frame);
790 else if (mode & ANIM_PINGPONG2) /* use border frames twice */
792 int max_anim_frames = 2 * num_frames;
794 frame = (sync_frame % (delay * max_anim_frames)) / delay;
795 frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
798 if (mode & ANIM_REVERSE) /* use reverse animation direction */
799 frame = num_frames - frame - 1;
804 void DrawGraphicAnimationExt(int x, int y, int graphic, int mask_mode)
807 int delay = new_graphic_info[graphic].anim_delay;
809 if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
811 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
814 int frame = getGraphicAnimationFrame(graphic, -1);
816 if (mask_mode == USE_MASKING)
817 DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
819 DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
824 void DrawOldGraphicAnimation(int x, int y, int graphic,
825 int frames, int delay, int mode)
827 DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
831 void DrawGraphicAnimation(int x, int y, int graphic)
833 DrawGraphicAnimationExt(x, y, graphic, NO_MASKING);
837 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
839 if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
841 *bitmap = graphic_info[graphic].bitmap;
842 *x = graphic_info[graphic].src_x;
843 *y = graphic_info[graphic].src_y;
845 else if (graphic >= GFX_START_ROCKSELEMENTS &&
846 graphic <= GFX_END_ROCKSELEMENTS)
848 graphic -= GFX_START_ROCKSELEMENTS;
849 *bitmap = new_graphic_info[IMG_OLD_PIX_ELEMENTS].bitmap;
850 *x = (graphic % GFX_PER_LINE) * TILEX;
851 *y = (graphic / GFX_PER_LINE) * TILEY;
853 else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
855 graphic -= GFX_START_ROCKSHEROES;
856 *bitmap = new_graphic_info[IMG_OLD_PIX_HEROES].bitmap;
857 *x = (graphic % HEROES_PER_LINE) * TILEX;
858 *y = (graphic / HEROES_PER_LINE) * TILEY;
860 else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
862 graphic -= GFX_START_ROCKSSP;
863 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
864 *x = (graphic % SP_PER_LINE) * TILEX;
865 *y = (graphic / SP_PER_LINE) * TILEY;
867 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
869 graphic -= GFX_START_ROCKSDC;
870 *bitmap = new_graphic_info[IMG_OLD_PIX_DC].bitmap;
871 *x = (graphic % DC_PER_LINE) * TILEX;
872 *y = (graphic / DC_PER_LINE) * TILEY;
874 else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
876 graphic -= GFX_START_ROCKSMORE;
877 *bitmap = new_graphic_info[IMG_OLD_PIX_MORE].bitmap;
878 *x = (graphic % MORE_PER_LINE) * TILEX;
879 *y = (graphic / MORE_PER_LINE) * TILEY;
881 else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
883 graphic -= GFX_START_ROCKSFONT;
884 *bitmap = new_graphic_info[IMG_OLD_PIX_FONT_EM].bitmap;
885 *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
886 *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
890 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
897 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
899 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
900 int offset_x = new_graphic_info[graphic].offset_x;
901 int offset_y = new_graphic_info[graphic].offset_y;
902 int src_x = new_graphic_info[graphic].src_x + frame * offset_x;
903 int src_y = new_graphic_info[graphic].src_y + frame * offset_y;
905 *bitmap = src_bitmap;
910 void DrawGraphic(int x, int y, int graphic, int frame)
913 if (!IN_SCR_FIELD(x, y))
915 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
916 printf("DrawGraphic(): This should never happen!\n");
921 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
926 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
931 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
932 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
936 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
943 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
945 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
946 int src_x = new_graphic_info[graphic].src_x;
947 int src_y = new_graphic_info[graphic].src_y;
948 int offset_x = new_graphic_info[graphic].offset_x;
949 int offset_y = new_graphic_info[graphic].offset_y;
951 src_x += frame * offset_x;
952 src_y += frame * offset_y;
955 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
958 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
961 if (!IN_SCR_FIELD(x, y))
963 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
964 printf("DrawGraphicThruMask(): This should never happen!\n");
969 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
974 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
982 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
983 drawing_gc = src_bitmap->stored_clip_gc;
985 GC drawing_gc = src_bitmap->stored_clip_gc;
986 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
987 int src_x = new_graphic_info[graphic].src_x;
988 int src_y = new_graphic_info[graphic].src_y;
989 int offset_x = new_graphic_info[graphic].offset_x;
990 int offset_y = new_graphic_info[graphic].offset_y;
992 src_x += frame * offset_x;
993 src_y += frame * offset_y;
997 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
998 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
1001 void DrawMiniGraphic(int x, int y, int graphic)
1003 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
1004 MarkTileDirty(x / 2, y / 2);
1007 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1009 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1010 int mini_startx = 0;
1011 int mini_starty = src_bitmap->height * 2 / 3;
1012 int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
1013 int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
1015 *bitmap = src_bitmap;
1020 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1025 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1026 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1029 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1030 int cut_mode, int mask_mode)
1039 int width = TILEX, height = TILEY;
1045 DrawGraphic(x, y, graphic, frame);
1049 if (dx || dy) /* shifted graphic */
1051 if (x < BX1) /* object enters playfield from the left */
1058 else if (x > BX2) /* object enters playfield from the right */
1064 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1070 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1072 else if (dx) /* general horizontal movement */
1073 MarkTileDirty(x + SIGN(dx), y);
1075 if (y < BY1) /* object enters playfield from the top */
1077 if (cut_mode==CUT_BELOW) /* object completely above top border */
1085 else if (y > BY2) /* object enters playfield from the bottom */
1091 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1097 else if (dy > 0 && cut_mode == CUT_ABOVE)
1099 if (y == BY2) /* object completely above bottom border */
1105 MarkTileDirty(x, y + 1);
1106 } /* object leaves playfield to the bottom */
1107 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1109 else if (dy) /* general vertical movement */
1110 MarkTileDirty(x, y + SIGN(dy));
1113 src_bitmap = new_graphic_info[graphic].bitmap;
1114 src_x = new_graphic_info[graphic].src_x;
1115 src_y = new_graphic_info[graphic].src_y;
1116 offset_x = new_graphic_info[graphic].offset_x;
1117 offset_y = new_graphic_info[graphic].offset_y;
1119 drawing_gc = src_bitmap->stored_clip_gc;
1121 src_x += frame * offset_x;
1122 src_y += frame * offset_y;
1127 dest_x = FX + x * TILEX + dx;
1128 dest_y = FY + y * TILEY + dy;
1131 if (!IN_SCR_FIELD(x,y))
1133 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1134 printf("DrawGraphicShifted(): This should never happen!\n");
1139 if (mask_mode == USE_MASKING)
1141 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1142 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1146 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1152 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1153 int frame, int cut_mode)
1155 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1159 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1160 int cut_mode, int mask_mode)
1162 int ux = LEVELX(x), uy = LEVELY(y);
1163 int graphic = el2gfx(element);
1164 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1165 int phase4 = phase8 / 2;
1166 int phase2 = phase8 / 4;
1167 int dir = MovDir[ux][uy];
1169 if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1171 graphic += 1 * !phase2;
1175 else if (dir == MV_LEFT)
1177 else if (dir == MV_DOWN)
1180 else if (element == EL_SP_SNIKSNAK)
1183 graphic = GFX_SP_SNIKSNAK_LEFT;
1184 else if (dir == MV_RIGHT)
1185 graphic = GFX_SP_SNIKSNAK_RIGHT;
1186 else if (dir == MV_UP)
1187 graphic = GFX_SP_SNIKSNAK_UP;
1189 graphic = GFX_SP_SNIKSNAK_DOWN;
1191 graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1193 else if (element == EL_SP_ELECTRON)
1195 graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1197 else if (element == EL_MOLE || element == EL_PENGUIN ||
1198 element == EL_PIG || element == EL_DRAGON)
1201 graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1202 element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1203 element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1204 else if (dir == MV_RIGHT)
1205 graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1206 element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1207 element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1208 else if (dir == MV_UP)
1209 graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1210 element == EL_PENGUIN ? GFX_PINGUIN_UP :
1211 element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1213 graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1214 element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1215 element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1219 else if (element == EL_SATELLITE)
1221 graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1223 else if (element == EL_ACID)
1225 graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1227 else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1231 else if (element == EL_BALLOON)
1235 else if ((element == EL_ROCK ||
1236 element == EL_SP_ZONK ||
1237 element == EL_BD_ROCK ||
1238 element == EL_SP_INFOTRON ||
1242 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1244 if (element == EL_ROCK ||
1245 element == EL_SP_ZONK ||
1246 element == EL_BD_ROCK)
1249 graphic += (4 - phase4) % 4;
1250 else if (dir == MV_RIGHT)
1253 graphic += phase2 * 2;
1255 else if (element != EL_SP_INFOTRON)
1259 else if (element == EL_MAGIC_WALL_ACTIVE ||
1260 element == EL_MAGIC_WALL_EMPTYING ||
1261 element == EL_BD_MAGIC_WALL_ACTIVE ||
1262 element == EL_BD_MAGIC_WALL_EMPTYING ||
1263 element == EL_MAGIC_WALL_FULL ||
1264 element == EL_BD_MAGIC_WALL_FULL)
1266 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1268 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1270 graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1271 graphic += (x + 2 * y + 4) % 4;
1273 else if (element == EL_WALL_GROWING)
1275 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1277 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1278 links_massiv = TRUE;
1279 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1280 rechts_massiv = TRUE;
1282 if (links_massiv && rechts_massiv)
1283 graphic = GFX_MAUERWERK;
1284 else if (links_massiv)
1285 graphic = GFX_MAUER_R;
1286 else if (rechts_massiv)
1287 graphic = GFX_MAUER_L;
1290 else if ((element == EL_INVISIBLE_STEELWALL ||
1291 element == EL_INVISIBLE_WALL ||
1292 element == EL_INVISIBLE_SAND) && game.light_time_left)
1294 graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1295 element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1296 GFX_SAND_INVISIBLE_ON);
1301 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1302 else if (mask_mode == USE_MASKING)
1303 DrawGraphicThruMask(x, y, graphic);
1305 DrawGraphic(x, y, graphic);
1309 inline static int getFramePosition(int x, int y)
1311 int frame_pos = -1; /* default: global synchronization */
1313 int element = Feld[x][y];
1315 if (element == EL_QUICKSAND_FULL ||
1316 element == EL_MAGIC_WALL_FULL ||
1317 element == EL_BD_MAGIC_WALL_FULL)
1319 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1320 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1322 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1328 inline static int getGfxAction(int x, int y)
1330 int gfx_action = GFX_ACTION_DEFAULT;
1333 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1334 gfx_action = GfxAction[x][y];
1335 else if (IS_MOVING(x, y))
1336 gfx_action = GFX_ACTION_MOVING;
1338 gfx_action = GfxAction[x][y];
1344 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1345 int cut_mode, int mask_mode)
1347 int ux = LEVELX(x), uy = LEVELY(y);
1348 int move_dir = MovDir[ux][uy];
1349 int move_pos = getFramePosition(ux, uy);
1350 int gfx_action = getGfxAction(ux, uy);
1351 int graphic = el_dir_act2img(element, move_dir, gfx_action);
1352 int frame = getGraphicAnimationFrame(graphic, move_pos);
1354 if (element == EL_WALL_GROWING)
1356 boolean left_stopped = FALSE, right_stopped = FALSE;
1358 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1359 left_stopped = TRUE;
1360 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1361 right_stopped = TRUE;
1363 if (left_stopped && right_stopped)
1365 else if (left_stopped)
1367 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1368 frame = new_graphic_info[graphic].anim_frames - 1;
1370 else if (right_stopped)
1372 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1373 frame = new_graphic_info[graphic].anim_frames - 1;
1376 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1378 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1379 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1380 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1381 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1382 IMG_AMOEBA_DEAD_PART1);
1384 graphic += (x + 2 * y + 4) % 4;
1388 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1389 else if (mask_mode == USE_MASKING)
1390 DrawGraphicThruMask(x, y, graphic, frame);
1392 DrawGraphic(x, y, graphic, frame);
1395 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1396 int cut_mode, int mask_mode)
1398 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1399 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1400 cut_mode, mask_mode);
1403 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1406 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1409 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1412 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1416 void DrawOldScreenElementThruMask(int x, int y, int element)
1418 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1421 void DrawScreenElementThruMask(int x, int y, int element)
1423 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1427 void DrawLevelElementThruMask(int x, int y, int element)
1429 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1432 void DrawLevelFieldThruMask(int x, int y)
1434 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1437 void DrawCrumbledSand(int x, int y)
1441 int i, width, height, cx,cy;
1442 int ux = LEVELX(x), uy = LEVELY(y);
1443 int element, graphic;
1445 static int xy[4][2] =
1453 if (!IN_LEV_FIELD(ux, uy))
1456 element = Feld[ux][uy];
1458 if (element == EL_SAND ||
1459 element == EL_LANDMINE ||
1460 element == EL_TRAP ||
1461 element == EL_TRAP_ACTIVE)
1463 if (!IN_SCR_FIELD(x, y))
1466 graphic = IMG_SAND_CRUMBLED;
1468 src_bitmap = new_graphic_info[graphic].bitmap;
1469 src_x = new_graphic_info[graphic].src_x;
1470 src_y = new_graphic_info[graphic].src_y;
1476 uxx = ux + xy[i][0];
1477 uyy = uy + xy[i][1];
1478 if (!IN_LEV_FIELD(uxx, uyy))
1479 element = EL_STEELWALL;
1481 element = Feld[uxx][uyy];
1483 if (element == EL_SAND ||
1484 element == EL_LANDMINE ||
1485 element == EL_TRAP ||
1486 element == EL_TRAP_ACTIVE)
1489 if (i == 1 || i == 2)
1493 cx = (i == 2 ? TILEX - snip : 0);
1501 cy = (i == 3 ? TILEY - snip : 0);
1504 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1505 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1508 MarkTileDirty(x, y);
1512 graphic = IMG_SAND_CRUMBLED;
1514 src_bitmap = new_graphic_info[graphic].bitmap;
1515 src_x = new_graphic_info[graphic].src_x;
1516 src_y = new_graphic_info[graphic].src_y;
1520 int xx, yy, uxx, uyy;
1524 uxx = ux + xy[i][0];
1525 uyy = uy + xy[i][1];
1527 if (!IN_LEV_FIELD(uxx, uyy) ||
1528 (Feld[uxx][uyy] != EL_SAND &&
1529 Feld[uxx][uyy] != EL_LANDMINE &&
1530 Feld[uxx][uyy] != EL_TRAP &&
1531 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1532 !IN_SCR_FIELD(xx, yy))
1535 if (i == 1 || i == 2)
1539 cx = (i == 1 ? TILEX - snip : 0);
1547 cy = (i==0 ? TILEY-snip : 0);
1550 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1551 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1553 MarkTileDirty(xx, yy);
1558 void DrawScreenElement(int x, int y, int element)
1560 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1561 DrawCrumbledSand(x, y);
1564 void DrawLevelElement(int x, int y, int element)
1566 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1567 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1570 void DrawScreenField(int x, int y)
1572 int ux = LEVELX(x), uy = LEVELY(y);
1573 int element, content;
1575 if (!IN_LEV_FIELD(ux, uy))
1577 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1580 element = BorderElement;
1582 DrawScreenElement(x, y, element);
1586 element = Feld[ux][uy];
1587 content = Store[ux][uy];
1589 if (IS_MOVING(ux, uy))
1591 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1592 boolean cut_mode = NO_CUTTING;
1594 if (element == EL_QUICKSAND_EMPTYING ||
1595 element == EL_MAGIC_WALL_EMPTYING ||
1596 element == EL_BD_MAGIC_WALL_EMPTYING ||
1597 element == EL_AMOEBA_DRIPPING)
1598 cut_mode = CUT_ABOVE;
1599 else if (element == EL_QUICKSAND_FILLING ||
1600 element == EL_MAGIC_WALL_FILLING ||
1601 element == EL_BD_MAGIC_WALL_FILLING)
1602 cut_mode = CUT_BELOW;
1604 if (cut_mode == CUT_ABOVE)
1605 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1607 DrawScreenElement(x, y, EL_EMPTY);
1610 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1611 else if (cut_mode == NO_CUTTING)
1612 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1614 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1616 if (content == EL_ACID)
1617 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1619 else if (IS_BLOCKED(ux, uy))
1624 boolean cut_mode = NO_CUTTING;
1625 int element_old, content_old;
1627 Blocked2Moving(ux, uy, &oldx, &oldy);
1630 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1631 MovDir[oldx][oldy] == MV_RIGHT);
1633 element_old = Feld[oldx][oldy];
1634 content_old = Store[oldx][oldy];
1636 if (element_old == EL_QUICKSAND_EMPTYING ||
1637 element_old == EL_MAGIC_WALL_EMPTYING ||
1638 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1639 element_old == EL_AMOEBA_DRIPPING)
1640 cut_mode = CUT_ABOVE;
1642 DrawScreenElement(x, y, EL_EMPTY);
1645 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1647 else if (cut_mode == NO_CUTTING)
1648 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1651 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1654 else if (IS_DRAWABLE(element))
1655 DrawScreenElement(x, y, element);
1657 DrawScreenElement(x, y, EL_EMPTY);
1660 void DrawLevelField(int x, int y)
1662 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1663 DrawScreenField(SCREENX(x), SCREENY(y));
1664 else if (IS_MOVING(x, y))
1668 Moving2Blocked(x, y, &newx, &newy);
1669 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1670 DrawScreenField(SCREENX(newx), SCREENY(newy));
1672 else if (IS_BLOCKED(x, y))
1676 Blocked2Moving(x, y, &oldx, &oldy);
1677 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1678 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1682 void DrawMiniElement(int x, int y, int element)
1686 graphic = el2img(element);
1687 DrawMiniGraphic(x, y, graphic);
1690 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1692 int x = sx + scroll_x, y = sy + scroll_y;
1694 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1695 DrawMiniElement(sx, sy, EL_EMPTY);
1696 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1697 DrawMiniElement(sx, sy, Feld[x][y]);
1700 int steel_type, steel_position;
1703 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1704 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1705 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1706 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1707 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1708 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1711 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1712 steel_position = (x == -1 && y == -1 ? 0 :
1713 x == lev_fieldx && y == -1 ? 1 :
1714 x == -1 && y == lev_fieldy ? 2 :
1715 x == lev_fieldx && y == lev_fieldy ? 3 :
1716 x == -1 || x == lev_fieldx ? 4 :
1717 y == -1 || y == lev_fieldy ? 5 : -1);
1719 if (steel_position != -1)
1720 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1724 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1726 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1727 int mini_startx = src_bitmap->width * 3 / 4;
1728 int mini_starty = src_bitmap->height * 2 / 3;
1729 int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1730 int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1732 *bitmap = src_bitmap;
1737 void DrawMicroElement(int xpos, int ypos, int element)
1743 if (element == EL_EMPTY)
1746 graphic = el2img(element);
1748 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1749 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1759 for(x=BX1; x<=BX2; x++)
1760 for(y=BY1; y<=BY2; y++)
1761 DrawScreenField(x, y);
1763 redraw_mask |= REDRAW_FIELD;
1766 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1770 for(x=0; x<size_x; x++)
1771 for(y=0; y<size_y; y++)
1772 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1774 redraw_mask |= REDRAW_FIELD;
1777 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1781 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1783 if (lev_fieldx < STD_LEV_FIELDX)
1784 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1785 if (lev_fieldy < STD_LEV_FIELDY)
1786 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1788 xpos += MICRO_TILEX;
1789 ypos += MICRO_TILEY;
1791 for(x=-1; x<=STD_LEV_FIELDX; x++)
1793 for(y=-1; y<=STD_LEV_FIELDY; y++)
1795 int lx = from_x + x, ly = from_y + y;
1797 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1798 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1800 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1801 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1806 redraw_mask |= REDRAW_MICROLEVEL;
1809 #define MICROLABEL_EMPTY 0
1810 #define MICROLABEL_LEVEL_NAME 1
1811 #define MICROLABEL_CREATED_BY 2
1812 #define MICROLABEL_LEVEL_AUTHOR 3
1813 #define MICROLABEL_IMPORTED_FROM 4
1814 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1816 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1818 static void DrawMicroLevelLabelExt(int mode)
1820 char label_text[MAX_MICROLABEL_SIZE + 1];
1822 ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1824 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1825 mode == MICROLABEL_CREATED_BY ? "created by" :
1826 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1827 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1828 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1829 leveldir_current->imported_from : ""),
1830 MAX_MICROLABEL_SIZE);
1831 label_text[MAX_MICROLABEL_SIZE] = '\0';
1833 if (strlen(label_text) > 0)
1835 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1836 int lypos = MICROLABEL_YPOS;
1838 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1841 redraw_mask |= REDRAW_MICROLEVEL;
1844 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1846 static unsigned long scroll_delay = 0;
1847 static unsigned long label_delay = 0;
1848 static int from_x, from_y, scroll_direction;
1849 static int label_state, label_counter;
1853 from_x = from_y = 0;
1854 scroll_direction = MV_RIGHT;
1858 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1859 DrawMicroLevelLabelExt(label_state);
1861 /* initialize delay counters */
1862 DelayReached(&scroll_delay, 0);
1863 DelayReached(&label_delay, 0);
1868 /* scroll micro level, if needed */
1869 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1870 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1872 switch (scroll_direction)
1878 scroll_direction = MV_UP;
1882 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1885 scroll_direction = MV_DOWN;
1892 scroll_direction = MV_RIGHT;
1896 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1899 scroll_direction = MV_LEFT;
1906 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1909 /* redraw micro level label, if needed */
1910 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1911 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1912 strcmp(level.author, leveldir_current->name) != 0 &&
1913 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1915 int max_label_counter = 23;
1917 if (leveldir_current->imported_from != NULL)
1918 max_label_counter += 14;
1920 label_counter = (label_counter + 1) % max_label_counter;
1921 label_state = (label_counter >= 0 && label_counter <= 7 ?
1922 MICROLABEL_LEVEL_NAME :
1923 label_counter >= 9 && label_counter <= 12 ?
1924 MICROLABEL_CREATED_BY :
1925 label_counter >= 14 && label_counter <= 21 ?
1926 MICROLABEL_LEVEL_AUTHOR :
1927 label_counter >= 23 && label_counter <= 26 ?
1928 MICROLABEL_IMPORTED_FROM :
1929 label_counter >= 28 && label_counter <= 35 ?
1930 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1931 DrawMicroLevelLabelExt(label_state);
1935 int REQ_in_range(int x, int y)
1937 if (y > DY+249 && y < DY+278)
1939 if (x > DX+1 && x < DX+48)
1941 else if (x > DX+51 && x < DX+98)
1947 #define MAX_REQUEST_LINES 13
1948 #define MAX_REQUEST_LINE_LEN 7
1950 boolean Request(char *text, unsigned int req_state)
1952 int mx, my, ty, result = -1;
1953 unsigned int old_door_state;
1955 #if defined(PLATFORM_UNIX)
1956 /* pause network game while waiting for request to answer */
1957 if (options.network &&
1958 game_status == PLAYING &&
1959 req_state & REQUEST_WAIT_FOR)
1960 SendToServer_PausePlaying();
1963 old_door_state = GetDoorState();
1967 CloseDoor(DOOR_CLOSE_1);
1969 /* save old door content */
1970 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
1971 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1972 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1974 /* clear door drawing field */
1975 ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1977 /* write text for request */
1978 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1980 char text_line[MAX_REQUEST_LINE_LEN + 1];
1986 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1989 if (!tc || tc == ' ')
2000 strncpy(text_line, text, tl);
2003 DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
2004 text_line, FS_SMALL, FC_YELLOW);
2006 text += tl + (tc == ' ' ? 1 : 0);
2009 if (req_state & REQ_ASK)
2011 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
2012 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2014 else if (req_state & REQ_CONFIRM)
2016 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2018 else if (req_state & REQ_PLAYER)
2020 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2021 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2022 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2023 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2026 /* copy request gadgets to door backbuffer */
2027 BlitBitmap(drawto, pix[PIX_DB_DOOR],
2028 DX, DY, DXSIZE, DYSIZE,
2029 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2031 OpenDoor(DOOR_OPEN_1);
2037 if (!(req_state & REQUEST_WAIT_FOR))
2040 if (game_status != MAINMENU)
2043 button_status = MB_RELEASED;
2045 request_gadget_id = -1;
2057 case EVENT_BUTTONPRESS:
2058 case EVENT_BUTTONRELEASE:
2059 case EVENT_MOTIONNOTIFY:
2061 if (event.type == EVENT_MOTIONNOTIFY)
2063 if (!PointerInWindow(window))
2064 continue; /* window and pointer are on different screens */
2069 motion_status = TRUE;
2070 mx = ((MotionEvent *) &event)->x;
2071 my = ((MotionEvent *) &event)->y;
2075 motion_status = FALSE;
2076 mx = ((ButtonEvent *) &event)->x;
2077 my = ((ButtonEvent *) &event)->y;
2078 if (event.type == EVENT_BUTTONPRESS)
2079 button_status = ((ButtonEvent *) &event)->button;
2081 button_status = MB_RELEASED;
2084 /* this sets 'request_gadget_id' */
2085 HandleGadgets(mx, my, button_status);
2087 switch(request_gadget_id)
2089 case TOOL_CTRL_ID_YES:
2092 case TOOL_CTRL_ID_NO:
2095 case TOOL_CTRL_ID_CONFIRM:
2096 result = TRUE | FALSE;
2099 case TOOL_CTRL_ID_PLAYER_1:
2102 case TOOL_CTRL_ID_PLAYER_2:
2105 case TOOL_CTRL_ID_PLAYER_3:
2108 case TOOL_CTRL_ID_PLAYER_4:
2119 case EVENT_KEYPRESS:
2120 switch(GetEventKey((KeyEvent *)&event, TRUE))
2133 if (req_state & REQ_PLAYER)
2137 case EVENT_KEYRELEASE:
2138 ClearPlayerAction();
2142 HandleOtherEvents(&event);
2146 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2148 int joy = AnyJoystick();
2150 if (joy & JOY_BUTTON_1)
2152 else if (joy & JOY_BUTTON_2)
2158 /* don't eat all CPU time */
2162 if (game_status != MAINMENU)
2167 if (!(req_state & REQ_STAY_OPEN))
2169 CloseDoor(DOOR_CLOSE_1);
2171 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2173 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2174 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2175 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2176 OpenDoor(DOOR_OPEN_1);
2182 #if defined(PLATFORM_UNIX)
2183 /* continue network game after request */
2184 if (options.network &&
2185 game_status == PLAYING &&
2186 req_state & REQUEST_WAIT_FOR)
2187 SendToServer_ContinuePlaying();
2193 unsigned int OpenDoor(unsigned int door_state)
2195 unsigned int new_door_state;
2197 if (door_state & DOOR_COPY_BACK)
2199 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2200 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2201 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2202 door_state &= ~DOOR_COPY_BACK;
2205 new_door_state = MoveDoor(door_state);
2207 return(new_door_state);
2210 unsigned int CloseDoor(unsigned int door_state)
2212 unsigned int new_door_state;
2214 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2215 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2216 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2217 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2219 new_door_state = MoveDoor(door_state);
2221 return(new_door_state);
2224 unsigned int GetDoorState()
2226 return MoveDoor(DOOR_GET_STATE);
2229 unsigned int SetDoorState(unsigned int door_state)
2231 return MoveDoor(door_state | DOOR_SET_STATE);
2234 unsigned int MoveDoor(unsigned int door_state)
2236 static int door1 = DOOR_OPEN_1;
2237 static int door2 = DOOR_CLOSE_2;
2238 static unsigned long door_delay = 0;
2239 int x, start, stepsize = 2;
2240 unsigned long door_delay_value = stepsize * 5;
2242 if (door_state == DOOR_GET_STATE)
2243 return(door1 | door2);
2245 if (door_state & DOOR_SET_STATE)
2247 if (door_state & DOOR_ACTION_1)
2248 door1 = door_state & DOOR_ACTION_1;
2249 if (door_state & DOOR_ACTION_2)
2250 door2 = door_state & DOOR_ACTION_2;
2252 return(door1 | door2);
2255 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2256 door_state &= ~DOOR_OPEN_1;
2257 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2258 door_state &= ~DOOR_CLOSE_1;
2259 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2260 door_state &= ~DOOR_OPEN_2;
2261 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2262 door_state &= ~DOOR_CLOSE_2;
2264 if (setup.quick_doors)
2267 door_delay_value = 0;
2268 StopSound(SND_MENU_DOOR_OPENING);
2269 StopSound(SND_MENU_DOOR_CLOSING);
2272 if (door_state & DOOR_ACTION)
2274 if (!(door_state & DOOR_NO_DELAY))
2276 /* opening door sound has priority over simultaneously closing door */
2277 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2278 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2279 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2280 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2283 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2285 for(x=start; x<=DXSIZE; x+=stepsize)
2287 Bitmap *bitmap = pix[PIX_DOOR];
2288 GC gc = bitmap->stored_clip_gc;
2290 WaitUntilDelayReached(&door_delay, door_delay_value);
2292 if (door_state & DOOR_ACTION_1)
2294 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2295 int j = (DXSIZE - i) / 3;
2297 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2298 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2299 DXSIZE,DYSIZE - i/2, DX, DY);
2301 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2303 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2304 BlitBitmapMasked(bitmap, drawto,
2305 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2306 DX + DXSIZE - i, DY + j);
2307 BlitBitmapMasked(bitmap, drawto,
2308 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2309 DX + DXSIZE - i, DY + 140 + j);
2310 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2311 BlitBitmapMasked(bitmap, drawto,
2312 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2314 BlitBitmapMasked(bitmap, drawto,
2315 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2318 BlitBitmapMasked(bitmap, drawto,
2319 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2321 BlitBitmapMasked(bitmap, drawto,
2322 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2324 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2325 BlitBitmapMasked(bitmap, drawto,
2326 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2327 DX + DXSIZE - i, DY + 77 + j);
2328 BlitBitmapMasked(bitmap, drawto,
2329 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2330 DX + DXSIZE - i, DY + 203 + j);
2332 redraw_mask |= REDRAW_DOOR_1;
2335 if (door_state & DOOR_ACTION_2)
2337 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2338 int j = (VXSIZE - i) / 3;
2340 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2341 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2342 VXSIZE, VYSIZE - i/2, VX, VY);
2344 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2346 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2347 BlitBitmapMasked(bitmap, drawto,
2348 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2349 VX + VXSIZE-i, VY+j);
2350 SetClipOrigin(bitmap, gc,
2351 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2352 BlitBitmapMasked(bitmap, drawto,
2353 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2356 BlitBitmapMasked(bitmap, drawto,
2357 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2358 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2359 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2360 BlitBitmapMasked(bitmap, drawto,
2361 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2363 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2365 redraw_mask |= REDRAW_DOOR_2;
2370 if (game_status == MAINMENU)
2375 if (setup.quick_doors)
2377 StopSound(SND_MENU_DOOR_OPENING);
2378 StopSound(SND_MENU_DOOR_CLOSING);
2381 if (door_state & DOOR_ACTION_1)
2382 door1 = door_state & DOOR_ACTION_1;
2383 if (door_state & DOOR_ACTION_2)
2384 door2 = door_state & DOOR_ACTION_2;
2386 return (door1 | door2);
2389 void DrawSpecialEditorDoor()
2391 /* draw bigger toolbox window */
2392 BlitBitmap(pix[PIX_DOOR], drawto,
2393 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2395 redraw_mask |= REDRAW_ALL;
2398 void UndrawSpecialEditorDoor()
2400 /* draw normal tape recorder window */
2401 BlitBitmap(pix[PIX_BACK], drawto,
2402 562, 344, 108, 56, EX - 4, EY - 12);
2404 redraw_mask |= REDRAW_ALL;
2408 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2410 XImage *pixel_image;
2411 unsigned long pixel_value;
2413 pixel_image = XGetImage(display, bitmap->drawable,
2414 x, y, 1, 1, AllPlanes, ZPixmap);
2415 pixel_value = XGetPixel(pixel_image, 0, 0);
2417 XDestroyImage(pixel_image);
2423 /* ---------- new tool button stuff ---------------------------------------- */
2425 /* graphic position values for tool buttons */
2426 #define TOOL_BUTTON_YES_XPOS 2
2427 #define TOOL_BUTTON_YES_YPOS 250
2428 #define TOOL_BUTTON_YES_GFX_YPOS 0
2429 #define TOOL_BUTTON_YES_XSIZE 46
2430 #define TOOL_BUTTON_YES_YSIZE 28
2431 #define TOOL_BUTTON_NO_XPOS 52
2432 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2433 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2434 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2435 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2436 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2437 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2438 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2439 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2440 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2441 #define TOOL_BUTTON_PLAYER_XSIZE 30
2442 #define TOOL_BUTTON_PLAYER_YSIZE 30
2443 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2444 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2445 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2446 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2447 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2448 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2449 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2450 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2451 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2452 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2453 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2454 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2455 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2456 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2457 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2458 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2459 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2460 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2461 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2462 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2471 } toolbutton_info[NUM_TOOL_BUTTONS] =
2474 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2475 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2476 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2481 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2482 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2483 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2488 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2489 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2490 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2491 TOOL_CTRL_ID_CONFIRM,
2495 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2496 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2497 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2498 TOOL_CTRL_ID_PLAYER_1,
2502 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2503 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2504 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2505 TOOL_CTRL_ID_PLAYER_2,
2509 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2510 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2511 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2512 TOOL_CTRL_ID_PLAYER_3,
2516 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2517 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2518 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2519 TOOL_CTRL_ID_PLAYER_4,
2524 void CreateToolButtons()
2528 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2530 Bitmap *gd_bitmap = pix[PIX_DOOR];
2531 Bitmap *deco_bitmap = None;
2532 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2533 struct GadgetInfo *gi;
2534 unsigned long event_mask;
2535 int gd_xoffset, gd_yoffset;
2536 int gd_x1, gd_x2, gd_y;
2539 event_mask = GD_EVENT_RELEASED;
2541 gd_xoffset = toolbutton_info[i].xpos;
2542 gd_yoffset = toolbutton_info[i].ypos;
2543 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2544 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2545 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2547 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2549 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2551 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2552 &deco_bitmap, &deco_x, &deco_y);
2553 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2554 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2557 gi = CreateGadget(GDI_CUSTOM_ID, id,
2558 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2559 GDI_X, DX + toolbutton_info[i].x,
2560 GDI_Y, DY + toolbutton_info[i].y,
2561 GDI_WIDTH, toolbutton_info[i].width,
2562 GDI_HEIGHT, toolbutton_info[i].height,
2563 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2564 GDI_STATE, GD_BUTTON_UNPRESSED,
2565 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2566 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2567 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2568 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2569 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2570 GDI_DECORATION_SHIFTING, 1, 1,
2571 GDI_EVENT_MASK, event_mask,
2572 GDI_CALLBACK_ACTION, HandleToolButtons,
2576 Error(ERR_EXIT, "cannot create gadget");
2578 tool_gadget[id] = gi;
2582 static void UnmapToolButtons()
2586 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2587 UnmapGadget(tool_gadget[i]);
2590 static void HandleToolButtons(struct GadgetInfo *gi)
2592 request_gadget_id = gi->custom_id;
2595 int get_next_element(int element)
2599 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2600 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2601 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2602 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2603 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2604 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2605 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2607 default: return element;
2611 int el2gfx_OLD(int element)
2615 case EL_EMPTY: return -1;
2616 case EL_SAND: return GFX_ERDREICH;
2617 case EL_WALL: return GFX_MAUERWERK;
2618 case EL_WALL_CRUMBLED: return GFX_FELSBODEN;
2619 case EL_ROCK: return GFX_FELSBROCKEN;
2620 case EL_EMERALD: return GFX_EDELSTEIN;
2621 case EL_EXIT_CLOSED: return GFX_AUSGANG_ZU;
2622 case EL_EXIT_OPENING: return GFX_AUSGANG_ACT;
2623 case EL_EXIT_OPEN: return GFX_AUSGANG_AUF;
2624 case EL_SP_EXIT_OPEN: return GFX_SP_EXIT;
2625 case EL_PLAYER1: return GFX_SPIELER1;
2626 case EL_PLAYER2: return GFX_SPIELER2;
2627 case EL_PLAYER3: return GFX_SPIELER3;
2628 case EL_PLAYER4: return GFX_SPIELER4;
2629 case EL_BUG: return GFX_KAEFER;
2630 case EL_BUG_RIGHT: return GFX_KAEFER_RIGHT;
2631 case EL_BUG_UP: return GFX_KAEFER_UP;
2632 case EL_BUG_LEFT: return GFX_KAEFER_LEFT;
2633 case EL_BUG_DOWN: return GFX_KAEFER_DOWN;
2634 case EL_SPACESHIP: return GFX_FLIEGER;
2635 case EL_SPACESHIP_RIGHT: return GFX_FLIEGER_RIGHT;
2636 case EL_SPACESHIP_UP: return GFX_FLIEGER_UP;
2637 case EL_SPACESHIP_LEFT: return GFX_FLIEGER_LEFT;
2638 case EL_SPACESHIP_DOWN: return GFX_FLIEGER_DOWN;
2639 case EL_BD_BUTTERFLY: return GFX_BUTTERFLY;
2640 case EL_BD_BUTTERFLY_RIGHT: return GFX_BUTTERFLY_RIGHT;
2641 case EL_BD_BUTTERFLY_UP: return GFX_BUTTERFLY_UP;
2642 case EL_BD_BUTTERFLY_LEFT: return GFX_BUTTERFLY_LEFT;
2643 case EL_BD_BUTTERFLY_DOWN: return GFX_BUTTERFLY_DOWN;
2644 case EL_BD_FIREFLY: return GFX_FIREFLY;
2645 case EL_BD_FIREFLY_RIGHT: return GFX_FIREFLY_RIGHT;
2646 case EL_BD_FIREFLY_UP: return GFX_FIREFLY_UP;
2647 case EL_BD_FIREFLY_LEFT: return GFX_FIREFLY_LEFT;
2648 case EL_BD_FIREFLY_DOWN: return GFX_FIREFLY_DOWN;
2649 case EL_YAMYAM: return GFX_MAMPFER;
2650 case EL_ROBOT: return GFX_ROBOT;
2651 case EL_STEELWALL: return GFX_BETON;
2652 case EL_DIAMOND: return GFX_DIAMANT;
2653 case EL_QUICKSAND_EMPTY: return GFX_MORAST_LEER;
2654 case EL_QUICKSAND_FULL: return GFX_MORAST_VOLL;
2655 case EL_QUICKSAND_EMPTYING: return GFX_MORAST_LEER;
2656 case EL_AMOEBA_DROP: return GFX_TROPFEN;
2657 case EL_BOMB: return GFX_BOMBE;
2658 case EL_MAGIC_WALL: return GFX_MAGIC_WALL_OFF;
2659 case EL_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_EMPTY;
2660 case EL_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_EMPTY;
2661 case EL_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_FULL;
2662 case EL_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_DEAD;
2663 case EL_ACID: return GFX_SALZSAEURE;
2664 case EL_AMOEBA_DEAD: return GFX_AMOEBE_TOT;
2665 case EL_AMOEBA_WET: return GFX_AMOEBE_NASS;
2666 case EL_AMOEBA_DRY: return GFX_AMOEBE_NORM;
2667 case EL_AMOEBA_FULL: return GFX_AMOEBE_VOLL;
2668 case EL_BD_AMOEBA: return GFX_AMOEBE_BD;
2669 case EL_AMOEBA_TO_DIAMOND: return GFX_AMOEBA2DIAM;
2670 case EL_AMOEBA_DRIPPING: return GFX_AMOEBE_NASS;
2671 case EL_NUT: return GFX_KOKOSNUSS;
2672 case EL_GAMEOFLIFE: return GFX_LIFE;
2673 case EL_BIOMAZE: return GFX_LIFE_ASYNC;
2674 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2675 case EL_STONEBLOCK: return GFX_BADEWANNE;
2676 case EL_ACIDPOOL_TOPLEFT: return GFX_BADEWANNE1;
2677 case EL_ACIDPOOL_TOPRIGHT: return GFX_BADEWANNE2;
2678 case EL_ACIDPOOL_BOTTOMLEFT: return GFX_BADEWANNE3;
2679 case EL_ACIDPOOL_BOTTOM: return GFX_BADEWANNE4;
2680 case EL_ACIDPOOL_BOTTOMRIGHT: return GFX_BADEWANNE5;
2681 case EL_ROBOT_WHEEL: return GFX_ABLENK_AUS;
2682 case EL_ROBOT_WHEEL_ACTIVE: return GFX_ABLENK_EIN;
2683 case EL_KEY1: return GFX_SCHLUESSEL1;
2684 case EL_KEY2: return GFX_SCHLUESSEL2;
2685 case EL_KEY3: return GFX_SCHLUESSEL3;
2686 case EL_KEY4: return GFX_SCHLUESSEL4;
2687 case EL_GATE1: return GFX_PFORTE1;
2688 case EL_GATE2: return GFX_PFORTE2;
2689 case EL_GATE3: return GFX_PFORTE3;
2690 case EL_GATE4: return GFX_PFORTE4;
2691 case EL_GATE1_GRAY: return GFX_PFORTE1X;
2692 case EL_GATE2_GRAY: return GFX_PFORTE2X;
2693 case EL_GATE3_GRAY: return GFX_PFORTE3X;
2694 case EL_GATE4_GRAY: return GFX_PFORTE4X;
2695 case EL_DYNAMITE: return GFX_DYNAMIT_AUS;
2696 case EL_PACMAN: return GFX_PACMAN;
2697 case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT;
2698 case EL_PACMAN_UP: return GFX_PACMAN_UP;
2699 case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT;
2700 case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN;
2701 case EL_INVISIBLE_WALL: return GFX_UNSICHTBAR;
2702 case EL_INVISIBLE_WALL_ACTIVE: return GFX_UNSICHTBAR_ON;
2703 case EL_WALL_EMERALD: return GFX_ERZ_EDEL;
2704 case EL_WALL_DIAMOND: return GFX_ERZ_DIAM;
2705 case EL_LAMP: return GFX_BIRNE_AUS;
2706 case EL_LAMP_ACTIVE: return GFX_BIRNE_EIN;
2707 case EL_TIME_ORB_FULL: return GFX_ZEIT_VOLL;
2708 case EL_TIME_ORB_EMPTY: return GFX_ZEIT_LEER;
2709 case EL_WALL_GROWING: return GFX_MAUER_LEBT;
2710 case EL_WALL_GROWING_X: return GFX_MAUER_X;
2711 case EL_WALL_GROWING_Y: return GFX_MAUER_Y;
2712 case EL_WALL_GROWING_XY: return GFX_MAUER_XY;
2713 case EL_BD_DIAMOND: return GFX_EDELSTEIN_BD;
2714 case EL_EMERALD_YELLOW: return GFX_EDELSTEIN_GELB;
2715 case EL_EMERALD_RED: return GFX_EDELSTEIN_ROT;
2716 case EL_EMERALD_PURPLE: return GFX_EDELSTEIN_LILA;
2717 case EL_WALL_BD_DIAMOND: return GFX_ERZ_EDEL_BD;
2718 case EL_WALL_EMERALD_YELLOW: return GFX_ERZ_EDEL_GELB;
2719 case EL_WALL_EMERALD_RED: return GFX_ERZ_EDEL_ROT;
2720 case EL_WALL_EMERALD_PURPLE: return GFX_ERZ_EDEL_LILA;
2721 case EL_DARK_YAMYAM: return GFX_MAMPFER2;
2722 case EL_BD_MAGIC_WALL: return GFX_MAGIC_WALL_BD_OFF;
2723 case EL_BD_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_BD_EMPTY;
2724 case EL_BD_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_BD_EMPTY;
2725 case EL_BD_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_BD_FULL;
2726 case EL_BD_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2727 case EL_DYNABOMB_PLAYER1_ACTIVE: return GFX_DYNABOMB;
2728 case EL_DYNABOMB_PLAYER2_ACTIVE: return GFX_DYNABOMB;
2729 case EL_DYNABOMB_PLAYER3_ACTIVE: return GFX_DYNABOMB;
2730 case EL_DYNABOMB_PLAYER4_ACTIVE: return GFX_DYNABOMB;
2731 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2732 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2733 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2734 case EL_SOKOBAN_OBJECT: return GFX_SOKOBAN_OBJEKT;
2735 case EL_SOKOBAN_FIELD_EMPTY: return GFX_SOKOBAN_FELD_LEER;
2736 case EL_SOKOBAN_FIELD_FULL: return GFX_SOKOBAN_FELD_VOLL;
2737 case EL_MOLE: return GFX_MOLE;
2738 case EL_PENGUIN: return GFX_PINGUIN;
2739 case EL_PIG: return GFX_SCHWEIN;
2740 case EL_DRAGON: return GFX_DRACHE;
2741 case EL_SATELLITE: return GFX_SONDE;
2742 case EL_ARROW_BLUE_LEFT: return GFX_PFEIL_LEFT;
2743 case EL_ARROW_BLUE_RIGHT: return GFX_PFEIL_RIGHT;
2744 case EL_ARROW_BLUE_UP: return GFX_PFEIL_UP;
2745 case EL_ARROW_BLUE_DOWN: return GFX_PFEIL_DOWN;
2746 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2747 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2748 case EL_SP_BUGGY_BASE_ACTIVE: return GFX_SP_BUG_ACTIVE;
2749 case EL_SP_ZONK: return GFX_SP_ZONK;
2750 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2751 case EL_INVISIBLE_STEELWALL: return GFX_INVISIBLE_STEEL;
2752 case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2753 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2754 case EL_EM_GATE1: return GFX_EM_GATE_1;
2755 case EL_EM_GATE2: return GFX_EM_GATE_2;
2756 case EL_EM_GATE3: return GFX_EM_GATE_3;
2757 case EL_EM_GATE4: return GFX_EM_GATE_4;
2758 case EL_EM_GATE1_GRAY: return GFX_EM_GATE_1X;
2759 case EL_EM_GATE2_GRAY: return GFX_EM_GATE_2X;
2760 case EL_EM_GATE3_GRAY: return GFX_EM_GATE_3X;
2761 case EL_EM_GATE4_GRAY: return GFX_EM_GATE_4X;
2762 case EL_EM_KEY1_FILE: return GFX_EM_KEY_1;
2763 case EL_EM_KEY2_FILE: return GFX_EM_KEY_2;
2764 case EL_EM_KEY3_FILE: return GFX_EM_KEY_3;
2765 case EL_EM_KEY4_FILE: return GFX_EM_KEY_4;
2766 case EL_EM_KEY1: return GFX_EM_KEY_1;
2767 case EL_EM_KEY2: return GFX_EM_KEY_2;
2768 case EL_EM_KEY3: return GFX_EM_KEY_3;
2769 case EL_EM_KEY4: return GFX_EM_KEY_4;
2770 case EL_PEARL: return GFX_PEARL;
2771 case EL_CRYSTAL: return GFX_CRYSTAL;
2772 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2773 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2774 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2775 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2776 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2777 case EL_SHIELD_NORMAL: return GFX_SHIELD_PASSIVE;
2778 case EL_SHIELD_DEADLY: return GFX_SHIELD_ACTIVE;
2779 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2780 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2781 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2782 case EL_SWITCHGATE_SWITCH_UP: return GFX_SWITCHGATE_SWITCH_1;
2783 case EL_SWITCHGATE_SWITCH_DOWN: return GFX_SWITCHGATE_SWITCH_2;
2784 case EL_CONVEYOR_BELT1_LEFT: return GFX_BELT1_LEFT;
2785 case EL_CONVEYOR_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2786 case EL_CONVEYOR_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2787 case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2788 case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2789 case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2790 case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2791 case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2792 case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2793 case EL_CONVEYOR_BELT2_LEFT: return GFX_BELT2_LEFT;
2794 case EL_CONVEYOR_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2795 case EL_CONVEYOR_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2796 case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2797 case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2798 case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2799 case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2800 case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2801 case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2802 case EL_CONVEYOR_BELT3_LEFT: return GFX_BELT3_LEFT;
2803 case EL_CONVEYOR_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2804 case EL_CONVEYOR_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2805 case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2806 case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2807 case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2808 case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2809 case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2810 case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2811 case EL_CONVEYOR_BELT4_LEFT: return GFX_BELT4_LEFT;
2812 case EL_CONVEYOR_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2813 case EL_CONVEYOR_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2814 case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2815 case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2816 case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2817 case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2818 case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2819 case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2820 case EL_LANDMINE: return GFX_LANDMINE;
2821 case EL_ENVELOPE: return GFX_ENVELOPE;
2822 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH_OFF;
2823 case EL_LIGHT_SWITCH_ACTIVE: return GFX_LIGHT_SWITCH_ON;
2824 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2825 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2826 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2827 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2828 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2829 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2830 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2831 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2832 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2833 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2834 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2835 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2836 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2837 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2838 case EL_MOLE_UP: return GFX_MOLE_UP;
2839 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2840 case EL_STEELWALL_SLANTED: return GFX_STEEL_SLANTED;
2841 case EL_INVISIBLE_SAND: return GFX_SAND_INVISIBLE;
2842 case EL_INVISIBLE_SAND_ACTIVE: return GFX_SAND_INVISIBLE_ON;
2843 case EL_DX_UNKNOWN_15: return GFX_DX_UNKNOWN_15;
2844 case EL_DX_UNKNOWN_42: return GFX_DX_UNKNOWN_42;
2845 case EL_TIMEGATE_OPEN: return GFX_TIMEGATE_OPEN;
2846 case EL_TIMEGATE_CLOSED: return GFX_TIMEGATE_CLOSED;
2847 case EL_TIMEGATE_SWITCH_ACTIVE: return GFX_TIMEGATE_SWITCH;
2848 case EL_TIMEGATE_SWITCH: return GFX_TIMEGATE_SWITCH;
2849 case EL_BALLOON: return GFX_BALLOON;
2850 case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
2851 case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2852 case EL_BALLOON_SEND_UP: return GFX_BALLOON_SEND_UP;
2853 case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
2854 case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2855 case EL_EMC_STEELWALL1: return GFX_EMC_STEEL_WALL_1;
2856 case EL_EMC_STEELWALL2: return GFX_EMC_STEEL_WALL_2;
2857 case EL_EMC_STEELWALL3: return GFX_EMC_STEEL_WALL_3;
2858 case EL_EMC_STEELWALL4: return GFX_EMC_STEEL_WALL_4;
2859 case EL_EMC_WALL_PILLAR_UPPER: return GFX_EMC_WALL_1;
2860 case EL_EMC_WALL_PILLAR_MIDDLE: return GFX_EMC_WALL_2;
2861 case EL_EMC_WALL_PILLAR_LOWER: return GFX_EMC_WALL_3;
2862 case EL_EMC_WALL4: return GFX_EMC_WALL_4;
2863 case EL_EMC_WALL5: return GFX_EMC_WALL_5;
2864 case EL_EMC_WALL6: return GFX_EMC_WALL_6;
2865 case EL_EMC_WALL7: return GFX_EMC_WALL_7;
2866 case EL_EMC_WALL8: return GFX_EMC_WALL_8;
2867 case EL_TUBE_ALL: return GFX_TUBE_CROSS;
2868 case EL_TUBE_VERTICAL: return GFX_TUBE_VERTICAL;
2869 case EL_TUBE_HORIZONTAL: return GFX_TUBE_HORIZONTAL;
2870 case EL_TUBE_VERTICAL_LEFT: return GFX_TUBE_VERT_LEFT;
2871 case EL_TUBE_VERTICAL_RIGHT: return GFX_TUBE_VERT_RIGHT;
2872 case EL_TUBE_HORIZONTAL_UP: return GFX_TUBE_HORIZ_UP;
2873 case EL_TUBE_HORIZONTAL_DOWN: return GFX_TUBE_HORIZ_DOWN;
2874 case EL_TUBE_LEFT_UP: return GFX_TUBE_LEFT_UP;
2875 case EL_TUBE_LEFT_DOWN: return GFX_TUBE_LEFT_DOWN;
2876 case EL_TUBE_RIGHT_UP: return GFX_TUBE_RIGHT_UP;
2877 case EL_TUBE_RIGHT_DOWN: return GFX_TUBE_RIGHT_DOWN;
2878 case EL_SPRING: return GFX_SPRING;
2879 case EL_TRAP: return GFX_TRAP_INACTIVE;
2880 case EL_TRAP_ACTIVE: return GFX_TRAP_ACTIVE;
2881 case EL_BD_WALL: return GFX_BD_WALL;
2882 case EL_BD_ROCK: return GFX_BD_ROCK;
2883 case EL_DX_SUPABOMB: return GFX_DX_SUPABOMB;
2884 case EL_SP_MURPHY_CLONE: return GFX_SP_MURPHY_CLONE;
2888 if (IS_CHAR(element))
2889 return GFX_CHAR_START + (element - EL_CHAR_START);
2890 else if (element >= EL_SP_START && element <= EL_SP_END)
2892 int nr_element = element - EL_SP_START;
2893 int gfx_per_line = 8;
2895 (nr_element / gfx_per_line) * SP_PER_LINE +
2896 (nr_element % gfx_per_line);
2898 return GFX_START_ROCKSSP + nr_graphic;
2906 int el2gfx(int element)
2909 int graphic_OLD = el2gfx_OLD(element);
2914 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2917 int graphic_OLD = el2gfx_OLD(element);
2919 if (element >= MAX_ELEMENTS)
2921 Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
2924 if (graphic_NEW != graphic_OLD)
2926 Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2927 graphic_NEW, graphic_OLD);
2935 int el2img(int element)
2937 int graphic = element_info[element].graphic[GFX_ACTION_DEFAULT];
2941 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2948 int el_dir2img(int element, int direction)
2950 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2953 int el_dir_act2img(int element, int direction, int action)
2955 action = graphics_action_mapping[action];
2956 direction = MV_DIR_BIT(direction);
2958 return element_info[element].direction_graphic[action][direction];