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 = pix[PIX_ELEMENTS];
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 = pix[PIX_HEROES];
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 = pix[PIX_SP];
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 = pix[PIX_DC];
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 = pix[PIX_MORE];
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 = pix[PIX_FONT_EM];
885 *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
886 *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
890 *bitmap = pix[PIX_SP];
897 void DrawGraphic(int x, int y, int graphic, int frame)
900 if (!IN_SCR_FIELD(x, y))
902 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
903 printf("DrawGraphic(): This should never happen!\n");
908 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
912 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
917 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
918 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
921 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
924 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
925 int src_x = new_graphic_info[graphic].src_x;
926 int src_y = new_graphic_info[graphic].src_y;
927 int offset_x = new_graphic_info[graphic].offset_x;
928 int offset_y = new_graphic_info[graphic].offset_y;
930 src_x += frame * offset_x;
931 src_y += frame * offset_y;
933 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
936 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
939 if (!IN_SCR_FIELD(x, y))
941 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
942 printf("DrawGraphicThruMask(): This should never happen!\n");
947 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
952 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
955 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
956 GC drawing_gc = src_bitmap->stored_clip_gc;
957 int src_x = new_graphic_info[graphic].src_x;
958 int src_y = new_graphic_info[graphic].src_y;
959 int offset_x = new_graphic_info[graphic].offset_x;
960 int offset_y = new_graphic_info[graphic].offset_y;
962 src_x += frame * offset_x;
963 src_y += frame * offset_y;
965 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
966 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
969 void DrawMiniGraphic(int x, int y, int graphic)
971 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
972 MarkTileDirty(x / 2, y / 2);
975 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
977 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
979 int mini_starty = src_bitmap->height * 2 / 3;
980 int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
981 int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
983 *bitmap = src_bitmap;
988 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
993 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
994 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
997 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
998 int cut_mode, int mask_mode)
1007 int width = TILEX, height = TILEY;
1013 DrawGraphic(x, y, graphic, frame);
1017 if (dx || dy) /* shifted graphic */
1019 if (x < BX1) /* object enters playfield from the left */
1026 else if (x > BX2) /* object enters playfield from the right */
1032 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1038 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1040 else if (dx) /* general horizontal movement */
1041 MarkTileDirty(x + SIGN(dx), y);
1043 if (y < BY1) /* object enters playfield from the top */
1045 if (cut_mode==CUT_BELOW) /* object completely above top border */
1053 else if (y > BY2) /* object enters playfield from the bottom */
1059 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1065 else if (dy > 0 && cut_mode == CUT_ABOVE)
1067 if (y == BY2) /* object completely above bottom border */
1073 MarkTileDirty(x, y + 1);
1074 } /* object leaves playfield to the bottom */
1075 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1077 else if (dy) /* general vertical movement */
1078 MarkTileDirty(x, y + SIGN(dy));
1081 src_bitmap = new_graphic_info[graphic].bitmap;
1082 src_x = new_graphic_info[graphic].src_x;
1083 src_y = new_graphic_info[graphic].src_y;
1084 offset_x = new_graphic_info[graphic].offset_x;
1085 offset_y = new_graphic_info[graphic].offset_y;
1087 drawing_gc = src_bitmap->stored_clip_gc;
1089 src_x += frame * offset_x;
1090 src_y += frame * offset_y;
1095 dest_x = FX + x * TILEX + dx;
1096 dest_y = FY + y * TILEY + dy;
1099 if (!IN_SCR_FIELD(x,y))
1101 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1102 printf("DrawGraphicShifted(): This should never happen!\n");
1107 if (mask_mode == USE_MASKING)
1109 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1110 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1114 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1120 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1121 int frame, int cut_mode)
1123 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1127 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1128 int cut_mode, int mask_mode)
1130 int ux = LEVELX(x), uy = LEVELY(y);
1131 int graphic = el2gfx(element);
1132 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1133 int phase4 = phase8 / 2;
1134 int phase2 = phase8 / 4;
1135 int dir = MovDir[ux][uy];
1137 if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1139 graphic += 1 * !phase2;
1143 else if (dir == MV_LEFT)
1145 else if (dir == MV_DOWN)
1148 else if (element == EL_SP_SNIKSNAK)
1151 graphic = GFX_SP_SNIKSNAK_LEFT;
1152 else if (dir == MV_RIGHT)
1153 graphic = GFX_SP_SNIKSNAK_RIGHT;
1154 else if (dir == MV_UP)
1155 graphic = GFX_SP_SNIKSNAK_UP;
1157 graphic = GFX_SP_SNIKSNAK_DOWN;
1159 graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1161 else if (element == EL_SP_ELECTRON)
1163 graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1165 else if (element == EL_MOLE || element == EL_PENGUIN ||
1166 element == EL_PIG || element == EL_DRAGON)
1169 graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1170 element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1171 element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1172 else if (dir == MV_RIGHT)
1173 graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1174 element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1175 element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1176 else if (dir == MV_UP)
1177 graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1178 element == EL_PENGUIN ? GFX_PINGUIN_UP :
1179 element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1181 graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1182 element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1183 element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1187 else if (element == EL_SATELLITE)
1189 graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1191 else if (element == EL_ACID)
1193 graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1195 else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1199 else if (element == EL_BALLOON)
1203 else if ((element == EL_ROCK ||
1204 element == EL_SP_ZONK ||
1205 element == EL_BD_ROCK ||
1206 element == EL_SP_INFOTRON ||
1210 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1212 if (element == EL_ROCK ||
1213 element == EL_SP_ZONK ||
1214 element == EL_BD_ROCK)
1217 graphic += (4 - phase4) % 4;
1218 else if (dir == MV_RIGHT)
1221 graphic += phase2 * 2;
1223 else if (element != EL_SP_INFOTRON)
1227 else if (element == EL_MAGIC_WALL_ACTIVE ||
1228 element == EL_MAGIC_WALL_EMPTYING ||
1229 element == EL_BD_MAGIC_WALL_ACTIVE ||
1230 element == EL_BD_MAGIC_WALL_EMPTYING ||
1231 element == EL_MAGIC_WALL_FULL ||
1232 element == EL_BD_MAGIC_WALL_FULL)
1234 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1236 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1238 graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1239 graphic += (x + 2 * y + 4) % 4;
1241 else if (element == EL_WALL_GROWING)
1243 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1245 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1246 links_massiv = TRUE;
1247 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1248 rechts_massiv = TRUE;
1250 if (links_massiv && rechts_massiv)
1251 graphic = GFX_MAUERWERK;
1252 else if (links_massiv)
1253 graphic = GFX_MAUER_R;
1254 else if (rechts_massiv)
1255 graphic = GFX_MAUER_L;
1258 else if ((element == EL_INVISIBLE_STEELWALL ||
1259 element == EL_INVISIBLE_WALL ||
1260 element == EL_INVISIBLE_SAND) && game.light_time_left)
1262 graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1263 element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1264 GFX_SAND_INVISIBLE_ON);
1269 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1270 else if (mask_mode == USE_MASKING)
1271 DrawGraphicThruMask(x, y, graphic);
1273 DrawGraphic(x, y, graphic);
1277 inline static int getFramePosition(int x, int y)
1279 int frame_pos = -1; /* default: global synchronization */
1281 int element = Feld[x][y];
1283 if (element == EL_QUICKSAND_FULL ||
1284 element == EL_MAGIC_WALL_FULL ||
1285 element == EL_BD_MAGIC_WALL_FULL)
1287 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1288 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1290 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1296 inline static int getGfxAction(int x, int y)
1298 int gfx_action = GFX_ACTION_DEFAULT;
1301 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1302 gfx_action = GfxAction[x][y];
1303 else if (IS_MOVING(x, y))
1304 gfx_action = GFX_ACTION_MOVING;
1306 gfx_action = GfxAction[x][y];
1312 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1313 int cut_mode, int mask_mode)
1315 int ux = LEVELX(x), uy = LEVELY(y);
1316 int move_dir = MovDir[ux][uy];
1317 int move_pos = getFramePosition(ux, uy);
1318 int gfx_action = getGfxAction(ux, uy);
1319 int graphic = el_dir_act2img(element, move_dir, gfx_action);
1320 int frame = getGraphicAnimationFrame(graphic, move_pos);
1322 if (element == EL_WALL_GROWING)
1324 boolean left_stopped = FALSE, right_stopped = FALSE;
1326 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1327 left_stopped = TRUE;
1328 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1329 right_stopped = TRUE;
1331 if (left_stopped && right_stopped)
1333 else if (left_stopped)
1335 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1336 frame = new_graphic_info[graphic].anim_frames - 1;
1338 else if (right_stopped)
1340 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1341 frame = new_graphic_info[graphic].anim_frames - 1;
1344 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1346 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1347 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1348 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1349 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1350 IMG_AMOEBA_DEAD_PART1);
1352 graphic += (x + 2 * y + 4) % 4;
1356 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1357 else if (mask_mode == USE_MASKING)
1358 DrawGraphicThruMask(x, y, graphic, frame);
1360 DrawGraphic(x, y, graphic, frame);
1363 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1364 int cut_mode, int mask_mode)
1366 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1367 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1368 cut_mode, mask_mode);
1371 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1374 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1377 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1380 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1384 void DrawOldScreenElementThruMask(int x, int y, int element)
1386 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1389 void DrawScreenElementThruMask(int x, int y, int element)
1391 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1395 void DrawLevelElementThruMask(int x, int y, int element)
1397 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1400 void DrawLevelFieldThruMask(int x, int y)
1402 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1405 void DrawCrumbledSand(int x, int y)
1409 int i, width, height, cx,cy;
1410 int ux = LEVELX(x), uy = LEVELY(y);
1411 int element, graphic;
1413 static int xy[4][2] =
1421 if (!IN_LEV_FIELD(ux, uy))
1424 element = Feld[ux][uy];
1426 if (element == EL_SAND ||
1427 element == EL_LANDMINE ||
1428 element == EL_TRAP ||
1429 element == EL_TRAP_ACTIVE)
1431 if (!IN_SCR_FIELD(x, y))
1434 graphic = IMG_SAND_CRUMBLED;
1436 src_bitmap = new_graphic_info[graphic].bitmap;
1437 src_x = new_graphic_info[graphic].src_x;
1438 src_y = new_graphic_info[graphic].src_y;
1444 uxx = ux + xy[i][0];
1445 uyy = uy + xy[i][1];
1446 if (!IN_LEV_FIELD(uxx, uyy))
1447 element = EL_STEELWALL;
1449 element = Feld[uxx][uyy];
1451 if (element == EL_SAND ||
1452 element == EL_LANDMINE ||
1453 element == EL_TRAP ||
1454 element == EL_TRAP_ACTIVE)
1457 if (i == 1 || i == 2)
1461 cx = (i == 2 ? TILEX - snip : 0);
1469 cy = (i == 3 ? TILEY - snip : 0);
1472 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1473 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1476 MarkTileDirty(x, y);
1480 graphic = IMG_SAND_CRUMBLED;
1482 src_bitmap = new_graphic_info[graphic].bitmap;
1483 src_x = new_graphic_info[graphic].src_x;
1484 src_y = new_graphic_info[graphic].src_y;
1488 int xx, yy, uxx, uyy;
1492 uxx = ux + xy[i][0];
1493 uyy = uy + xy[i][1];
1495 if (!IN_LEV_FIELD(uxx, uyy) ||
1496 (Feld[uxx][uyy] != EL_SAND &&
1497 Feld[uxx][uyy] != EL_LANDMINE &&
1498 Feld[uxx][uyy] != EL_TRAP &&
1499 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1500 !IN_SCR_FIELD(xx, yy))
1503 if (i == 1 || i == 2)
1507 cx = (i == 1 ? TILEX - snip : 0);
1515 cy = (i==0 ? TILEY-snip : 0);
1518 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1519 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1521 MarkTileDirty(xx, yy);
1526 void DrawScreenElement(int x, int y, int element)
1528 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1529 DrawCrumbledSand(x, y);
1532 void DrawLevelElement(int x, int y, int element)
1534 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1535 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1538 void DrawScreenField(int x, int y)
1540 int ux = LEVELX(x), uy = LEVELY(y);
1541 int element, content;
1543 if (!IN_LEV_FIELD(ux, uy))
1545 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1548 element = BorderElement;
1550 DrawScreenElement(x, y, element);
1554 element = Feld[ux][uy];
1555 content = Store[ux][uy];
1557 if (IS_MOVING(ux, uy))
1559 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1560 boolean cut_mode = NO_CUTTING;
1562 if (element == EL_QUICKSAND_EMPTYING ||
1563 element == EL_MAGIC_WALL_EMPTYING ||
1564 element == EL_BD_MAGIC_WALL_EMPTYING ||
1565 element == EL_AMOEBA_DRIPPING)
1566 cut_mode = CUT_ABOVE;
1567 else if (element == EL_QUICKSAND_FILLING ||
1568 element == EL_MAGIC_WALL_FILLING ||
1569 element == EL_BD_MAGIC_WALL_FILLING)
1570 cut_mode = CUT_BELOW;
1572 if (cut_mode == CUT_ABOVE)
1573 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1575 DrawScreenElement(x, y, EL_EMPTY);
1578 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1579 else if (cut_mode == NO_CUTTING)
1580 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1582 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1584 if (content == EL_ACID)
1585 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1587 else if (IS_BLOCKED(ux, uy))
1592 boolean cut_mode = NO_CUTTING;
1593 int element_old, content_old;
1595 Blocked2Moving(ux, uy, &oldx, &oldy);
1598 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1599 MovDir[oldx][oldy] == MV_RIGHT);
1601 element_old = Feld[oldx][oldy];
1602 content_old = Store[oldx][oldy];
1604 if (element_old == EL_QUICKSAND_EMPTYING ||
1605 element_old == EL_MAGIC_WALL_EMPTYING ||
1606 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1607 element_old == EL_AMOEBA_DRIPPING)
1608 cut_mode = CUT_ABOVE;
1610 DrawScreenElement(x, y, EL_EMPTY);
1613 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1615 else if (cut_mode == NO_CUTTING)
1616 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1619 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1622 else if (IS_DRAWABLE(element))
1623 DrawScreenElement(x, y, element);
1625 DrawScreenElement(x, y, EL_EMPTY);
1628 void DrawLevelField(int x, int y)
1630 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1631 DrawScreenField(SCREENX(x), SCREENY(y));
1632 else if (IS_MOVING(x, y))
1636 Moving2Blocked(x, y, &newx, &newy);
1637 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1638 DrawScreenField(SCREENX(newx), SCREENY(newy));
1640 else if (IS_BLOCKED(x, y))
1644 Blocked2Moving(x, y, &oldx, &oldy);
1645 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1646 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1650 void DrawMiniElement(int x, int y, int element)
1654 graphic = el2img(element);
1655 DrawMiniGraphic(x, y, graphic);
1658 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1660 int x = sx + scroll_x, y = sy + scroll_y;
1662 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1663 DrawMiniElement(sx, sy, EL_EMPTY);
1664 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1665 DrawMiniElement(sx, sy, Feld[x][y]);
1668 int steel_type, steel_position;
1671 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1672 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1673 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1674 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1675 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1676 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1679 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1680 steel_position = (x == -1 && y == -1 ? 0 :
1681 x == lev_fieldx && y == -1 ? 1 :
1682 x == -1 && y == lev_fieldy ? 2 :
1683 x == lev_fieldx && y == lev_fieldy ? 3 :
1684 x == -1 || x == lev_fieldx ? 4 :
1685 y == -1 || y == lev_fieldy ? 5 : -1);
1687 if (steel_position != -1)
1688 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1692 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1694 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1695 int mini_startx = src_bitmap->width * 3 / 4;
1696 int mini_starty = src_bitmap->height * 2 / 3;
1697 int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1698 int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1700 *bitmap = src_bitmap;
1705 void DrawMicroElement(int xpos, int ypos, int element)
1711 if (element == EL_EMPTY)
1714 graphic = el2img(element);
1716 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1717 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1727 for(x=BX1; x<=BX2; x++)
1728 for(y=BY1; y<=BY2; y++)
1729 DrawScreenField(x, y);
1731 redraw_mask |= REDRAW_FIELD;
1734 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1738 for(x=0; x<size_x; x++)
1739 for(y=0; y<size_y; y++)
1740 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1742 redraw_mask |= REDRAW_FIELD;
1745 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1749 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1751 if (lev_fieldx < STD_LEV_FIELDX)
1752 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1753 if (lev_fieldy < STD_LEV_FIELDY)
1754 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1756 xpos += MICRO_TILEX;
1757 ypos += MICRO_TILEY;
1759 for(x=-1; x<=STD_LEV_FIELDX; x++)
1761 for(y=-1; y<=STD_LEV_FIELDY; y++)
1763 int lx = from_x + x, ly = from_y + y;
1765 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1766 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1768 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1769 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1774 redraw_mask |= REDRAW_MICROLEVEL;
1777 #define MICROLABEL_EMPTY 0
1778 #define MICROLABEL_LEVEL_NAME 1
1779 #define MICROLABEL_CREATED_BY 2
1780 #define MICROLABEL_LEVEL_AUTHOR 3
1781 #define MICROLABEL_IMPORTED_FROM 4
1782 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1784 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1786 static void DrawMicroLevelLabelExt(int mode)
1788 char label_text[MAX_MICROLABEL_SIZE + 1];
1790 ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1792 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1793 mode == MICROLABEL_CREATED_BY ? "created by" :
1794 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1795 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1796 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1797 leveldir_current->imported_from : ""),
1798 MAX_MICROLABEL_SIZE);
1799 label_text[MAX_MICROLABEL_SIZE] = '\0';
1801 if (strlen(label_text) > 0)
1803 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1804 int lypos = MICROLABEL_YPOS;
1806 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1809 redraw_mask |= REDRAW_MICROLEVEL;
1812 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1814 static unsigned long scroll_delay = 0;
1815 static unsigned long label_delay = 0;
1816 static int from_x, from_y, scroll_direction;
1817 static int label_state, label_counter;
1821 from_x = from_y = 0;
1822 scroll_direction = MV_RIGHT;
1826 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1827 DrawMicroLevelLabelExt(label_state);
1829 /* initialize delay counters */
1830 DelayReached(&scroll_delay, 0);
1831 DelayReached(&label_delay, 0);
1836 /* scroll micro level, if needed */
1837 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1838 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1840 switch (scroll_direction)
1846 scroll_direction = MV_UP;
1850 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1853 scroll_direction = MV_DOWN;
1860 scroll_direction = MV_RIGHT;
1864 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1867 scroll_direction = MV_LEFT;
1874 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1877 /* redraw micro level label, if needed */
1878 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1879 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1880 strcmp(level.author, leveldir_current->name) != 0 &&
1881 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1883 int max_label_counter = 23;
1885 if (leveldir_current->imported_from != NULL)
1886 max_label_counter += 14;
1888 label_counter = (label_counter + 1) % max_label_counter;
1889 label_state = (label_counter >= 0 && label_counter <= 7 ?
1890 MICROLABEL_LEVEL_NAME :
1891 label_counter >= 9 && label_counter <= 12 ?
1892 MICROLABEL_CREATED_BY :
1893 label_counter >= 14 && label_counter <= 21 ?
1894 MICROLABEL_LEVEL_AUTHOR :
1895 label_counter >= 23 && label_counter <= 26 ?
1896 MICROLABEL_IMPORTED_FROM :
1897 label_counter >= 28 && label_counter <= 35 ?
1898 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1899 DrawMicroLevelLabelExt(label_state);
1903 int REQ_in_range(int x, int y)
1905 if (y > DY+249 && y < DY+278)
1907 if (x > DX+1 && x < DX+48)
1909 else if (x > DX+51 && x < DX+98)
1915 #define MAX_REQUEST_LINES 13
1916 #define MAX_REQUEST_LINE_LEN 7
1918 boolean Request(char *text, unsigned int req_state)
1920 int mx, my, ty, result = -1;
1921 unsigned int old_door_state;
1923 #if defined(PLATFORM_UNIX)
1924 /* pause network game while waiting for request to answer */
1925 if (options.network &&
1926 game_status == PLAYING &&
1927 req_state & REQUEST_WAIT_FOR)
1928 SendToServer_PausePlaying();
1931 old_door_state = GetDoorState();
1935 CloseDoor(DOOR_CLOSE_1);
1937 /* save old door content */
1938 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
1939 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1940 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1942 /* clear door drawing field */
1943 ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1945 /* write text for request */
1946 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1948 char text_line[MAX_REQUEST_LINE_LEN + 1];
1954 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1957 if (!tc || tc == ' ')
1968 strncpy(text_line, text, tl);
1971 DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1972 text_line, FS_SMALL, FC_YELLOW);
1974 text += tl + (tc == ' ' ? 1 : 0);
1977 if (req_state & REQ_ASK)
1979 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1980 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1982 else if (req_state & REQ_CONFIRM)
1984 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1986 else if (req_state & REQ_PLAYER)
1988 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1989 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1990 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1991 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1994 /* copy request gadgets to door backbuffer */
1995 BlitBitmap(drawto, pix[PIX_DB_DOOR],
1996 DX, DY, DXSIZE, DYSIZE,
1997 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1999 OpenDoor(DOOR_OPEN_1);
2005 if (!(req_state & REQUEST_WAIT_FOR))
2008 if (game_status != MAINMENU)
2011 button_status = MB_RELEASED;
2013 request_gadget_id = -1;
2025 case EVENT_BUTTONPRESS:
2026 case EVENT_BUTTONRELEASE:
2027 case EVENT_MOTIONNOTIFY:
2029 if (event.type == EVENT_MOTIONNOTIFY)
2031 if (!PointerInWindow(window))
2032 continue; /* window and pointer are on different screens */
2037 motion_status = TRUE;
2038 mx = ((MotionEvent *) &event)->x;
2039 my = ((MotionEvent *) &event)->y;
2043 motion_status = FALSE;
2044 mx = ((ButtonEvent *) &event)->x;
2045 my = ((ButtonEvent *) &event)->y;
2046 if (event.type == EVENT_BUTTONPRESS)
2047 button_status = ((ButtonEvent *) &event)->button;
2049 button_status = MB_RELEASED;
2052 /* this sets 'request_gadget_id' */
2053 HandleGadgets(mx, my, button_status);
2055 switch(request_gadget_id)
2057 case TOOL_CTRL_ID_YES:
2060 case TOOL_CTRL_ID_NO:
2063 case TOOL_CTRL_ID_CONFIRM:
2064 result = TRUE | FALSE;
2067 case TOOL_CTRL_ID_PLAYER_1:
2070 case TOOL_CTRL_ID_PLAYER_2:
2073 case TOOL_CTRL_ID_PLAYER_3:
2076 case TOOL_CTRL_ID_PLAYER_4:
2087 case EVENT_KEYPRESS:
2088 switch(GetEventKey((KeyEvent *)&event, TRUE))
2101 if (req_state & REQ_PLAYER)
2105 case EVENT_KEYRELEASE:
2106 ClearPlayerAction();
2110 HandleOtherEvents(&event);
2114 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2116 int joy = AnyJoystick();
2118 if (joy & JOY_BUTTON_1)
2120 else if (joy & JOY_BUTTON_2)
2126 /* don't eat all CPU time */
2130 if (game_status != MAINMENU)
2135 if (!(req_state & REQ_STAY_OPEN))
2137 CloseDoor(DOOR_CLOSE_1);
2139 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2141 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2142 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2143 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2144 OpenDoor(DOOR_OPEN_1);
2150 #if defined(PLATFORM_UNIX)
2151 /* continue network game after request */
2152 if (options.network &&
2153 game_status == PLAYING &&
2154 req_state & REQUEST_WAIT_FOR)
2155 SendToServer_ContinuePlaying();
2161 unsigned int OpenDoor(unsigned int door_state)
2163 unsigned int new_door_state;
2165 if (door_state & DOOR_COPY_BACK)
2167 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2168 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2169 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2170 door_state &= ~DOOR_COPY_BACK;
2173 new_door_state = MoveDoor(door_state);
2175 return(new_door_state);
2178 unsigned int CloseDoor(unsigned int door_state)
2180 unsigned int new_door_state;
2182 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2183 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2184 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2185 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2187 new_door_state = MoveDoor(door_state);
2189 return(new_door_state);
2192 unsigned int GetDoorState()
2194 return MoveDoor(DOOR_GET_STATE);
2197 unsigned int SetDoorState(unsigned int door_state)
2199 return MoveDoor(door_state | DOOR_SET_STATE);
2202 unsigned int MoveDoor(unsigned int door_state)
2204 static int door1 = DOOR_OPEN_1;
2205 static int door2 = DOOR_CLOSE_2;
2206 static unsigned long door_delay = 0;
2207 int x, start, stepsize = 2;
2208 unsigned long door_delay_value = stepsize * 5;
2210 if (door_state == DOOR_GET_STATE)
2211 return(door1 | door2);
2213 if (door_state & DOOR_SET_STATE)
2215 if (door_state & DOOR_ACTION_1)
2216 door1 = door_state & DOOR_ACTION_1;
2217 if (door_state & DOOR_ACTION_2)
2218 door2 = door_state & DOOR_ACTION_2;
2220 return(door1 | door2);
2223 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2224 door_state &= ~DOOR_OPEN_1;
2225 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2226 door_state &= ~DOOR_CLOSE_1;
2227 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2228 door_state &= ~DOOR_OPEN_2;
2229 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2230 door_state &= ~DOOR_CLOSE_2;
2232 if (setup.quick_doors)
2235 door_delay_value = 0;
2236 StopSound(SND_MENU_DOOR_OPENING);
2237 StopSound(SND_MENU_DOOR_CLOSING);
2240 if (door_state & DOOR_ACTION)
2242 if (!(door_state & DOOR_NO_DELAY))
2244 /* opening door sound has priority over simultaneously closing door */
2245 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2246 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2247 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2248 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2251 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2253 for(x=start; x<=DXSIZE; x+=stepsize)
2255 Bitmap *bitmap = pix[PIX_DOOR];
2256 GC gc = bitmap->stored_clip_gc;
2258 WaitUntilDelayReached(&door_delay, door_delay_value);
2260 if (door_state & DOOR_ACTION_1)
2262 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2263 int j = (DXSIZE - i) / 3;
2265 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2266 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2267 DXSIZE,DYSIZE - i/2, DX, DY);
2269 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2271 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2272 BlitBitmapMasked(bitmap, drawto,
2273 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2274 DX + DXSIZE - i, DY + j);
2275 BlitBitmapMasked(bitmap, drawto,
2276 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2277 DX + DXSIZE - i, DY + 140 + j);
2278 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2279 BlitBitmapMasked(bitmap, drawto,
2280 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2282 BlitBitmapMasked(bitmap, drawto,
2283 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2286 BlitBitmapMasked(bitmap, drawto,
2287 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2289 BlitBitmapMasked(bitmap, drawto,
2290 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2292 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2293 BlitBitmapMasked(bitmap, drawto,
2294 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2295 DX + DXSIZE - i, DY + 77 + j);
2296 BlitBitmapMasked(bitmap, drawto,
2297 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2298 DX + DXSIZE - i, DY + 203 + j);
2300 redraw_mask |= REDRAW_DOOR_1;
2303 if (door_state & DOOR_ACTION_2)
2305 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2306 int j = (VXSIZE - i) / 3;
2308 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2309 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2310 VXSIZE, VYSIZE - i/2, VX, VY);
2312 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2314 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2315 BlitBitmapMasked(bitmap, drawto,
2316 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2317 VX + VXSIZE-i, VY+j);
2318 SetClipOrigin(bitmap, gc,
2319 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2320 BlitBitmapMasked(bitmap, drawto,
2321 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2324 BlitBitmapMasked(bitmap, drawto,
2325 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2326 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2327 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2328 BlitBitmapMasked(bitmap, drawto,
2329 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2331 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2333 redraw_mask |= REDRAW_DOOR_2;
2338 if (game_status == MAINMENU)
2343 if (setup.quick_doors)
2345 StopSound(SND_MENU_DOOR_OPENING);
2346 StopSound(SND_MENU_DOOR_CLOSING);
2349 if (door_state & DOOR_ACTION_1)
2350 door1 = door_state & DOOR_ACTION_1;
2351 if (door_state & DOOR_ACTION_2)
2352 door2 = door_state & DOOR_ACTION_2;
2354 return (door1 | door2);
2357 void DrawSpecialEditorDoor()
2359 /* draw bigger toolbox window */
2360 BlitBitmap(pix[PIX_DOOR], drawto,
2361 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2363 redraw_mask |= REDRAW_ALL;
2366 void UndrawSpecialEditorDoor()
2368 /* draw normal tape recorder window */
2369 BlitBitmap(pix[PIX_BACK], drawto,
2370 562, 344, 108, 56, EX - 4, EY - 12);
2372 redraw_mask |= REDRAW_ALL;
2376 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2378 XImage *pixel_image;
2379 unsigned long pixel_value;
2381 pixel_image = XGetImage(display, bitmap->drawable,
2382 x, y, 1, 1, AllPlanes, ZPixmap);
2383 pixel_value = XGetPixel(pixel_image, 0, 0);
2385 XDestroyImage(pixel_image);
2391 /* ---------- new tool button stuff ---------------------------------------- */
2393 /* graphic position values for tool buttons */
2394 #define TOOL_BUTTON_YES_XPOS 2
2395 #define TOOL_BUTTON_YES_YPOS 250
2396 #define TOOL_BUTTON_YES_GFX_YPOS 0
2397 #define TOOL_BUTTON_YES_XSIZE 46
2398 #define TOOL_BUTTON_YES_YSIZE 28
2399 #define TOOL_BUTTON_NO_XPOS 52
2400 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2401 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2402 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2403 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2404 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2405 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2406 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2407 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2408 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2409 #define TOOL_BUTTON_PLAYER_XSIZE 30
2410 #define TOOL_BUTTON_PLAYER_YSIZE 30
2411 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2412 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2413 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2414 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2415 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2416 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2417 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2418 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2419 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2420 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2421 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2422 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2423 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2424 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2425 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2426 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2427 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2428 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2429 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2430 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2439 } toolbutton_info[NUM_TOOL_BUTTONS] =
2442 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2443 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2444 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2449 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2450 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2451 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2456 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2457 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2458 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2459 TOOL_CTRL_ID_CONFIRM,
2463 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2464 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2465 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2466 TOOL_CTRL_ID_PLAYER_1,
2470 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2471 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2472 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2473 TOOL_CTRL_ID_PLAYER_2,
2477 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2478 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2479 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2480 TOOL_CTRL_ID_PLAYER_3,
2484 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2485 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2486 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2487 TOOL_CTRL_ID_PLAYER_4,
2492 void CreateToolButtons()
2496 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2498 Bitmap *gd_bitmap = pix[PIX_DOOR];
2499 Bitmap *deco_bitmap = None;
2500 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2501 struct GadgetInfo *gi;
2502 unsigned long event_mask;
2503 int gd_xoffset, gd_yoffset;
2504 int gd_x1, gd_x2, gd_y;
2507 event_mask = GD_EVENT_RELEASED;
2509 gd_xoffset = toolbutton_info[i].xpos;
2510 gd_yoffset = toolbutton_info[i].ypos;
2511 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2512 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2513 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2515 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2517 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2519 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2520 &deco_bitmap, &deco_x, &deco_y);
2521 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2522 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2525 gi = CreateGadget(GDI_CUSTOM_ID, id,
2526 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2527 GDI_X, DX + toolbutton_info[i].x,
2528 GDI_Y, DY + toolbutton_info[i].y,
2529 GDI_WIDTH, toolbutton_info[i].width,
2530 GDI_HEIGHT, toolbutton_info[i].height,
2531 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2532 GDI_STATE, GD_BUTTON_UNPRESSED,
2533 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2534 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2535 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2536 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2537 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2538 GDI_DECORATION_SHIFTING, 1, 1,
2539 GDI_EVENT_MASK, event_mask,
2540 GDI_CALLBACK_ACTION, HandleToolButtons,
2544 Error(ERR_EXIT, "cannot create gadget");
2546 tool_gadget[id] = gi;
2550 static void UnmapToolButtons()
2554 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2555 UnmapGadget(tool_gadget[i]);
2558 static void HandleToolButtons(struct GadgetInfo *gi)
2560 request_gadget_id = gi->custom_id;
2563 int get_next_element(int element)
2567 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2568 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2569 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2570 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2571 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2572 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2573 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2575 default: return element;
2579 int el2gfx_OLD(int element)
2583 case EL_EMPTY: return -1;
2584 case EL_SAND: return GFX_ERDREICH;
2585 case EL_WALL: return GFX_MAUERWERK;
2586 case EL_WALL_CRUMBLED: return GFX_FELSBODEN;
2587 case EL_ROCK: return GFX_FELSBROCKEN;
2588 case EL_EMERALD: return GFX_EDELSTEIN;
2589 case EL_EXIT_CLOSED: return GFX_AUSGANG_ZU;
2590 case EL_EXIT_OPENING: return GFX_AUSGANG_ACT;
2591 case EL_EXIT_OPEN: return GFX_AUSGANG_AUF;
2592 case EL_SP_EXIT_OPEN: return GFX_SP_EXIT;
2593 case EL_PLAYER1: return GFX_SPIELER1;
2594 case EL_PLAYER2: return GFX_SPIELER2;
2595 case EL_PLAYER3: return GFX_SPIELER3;
2596 case EL_PLAYER4: return GFX_SPIELER4;
2597 case EL_BUG: return GFX_KAEFER;
2598 case EL_BUG_RIGHT: return GFX_KAEFER_RIGHT;
2599 case EL_BUG_UP: return GFX_KAEFER_UP;
2600 case EL_BUG_LEFT: return GFX_KAEFER_LEFT;
2601 case EL_BUG_DOWN: return GFX_KAEFER_DOWN;
2602 case EL_SPACESHIP: return GFX_FLIEGER;
2603 case EL_SPACESHIP_RIGHT: return GFX_FLIEGER_RIGHT;
2604 case EL_SPACESHIP_UP: return GFX_FLIEGER_UP;
2605 case EL_SPACESHIP_LEFT: return GFX_FLIEGER_LEFT;
2606 case EL_SPACESHIP_DOWN: return GFX_FLIEGER_DOWN;
2607 case EL_BD_BUTTERFLY: return GFX_BUTTERFLY;
2608 case EL_BD_BUTTERFLY_RIGHT: return GFX_BUTTERFLY_RIGHT;
2609 case EL_BD_BUTTERFLY_UP: return GFX_BUTTERFLY_UP;
2610 case EL_BD_BUTTERFLY_LEFT: return GFX_BUTTERFLY_LEFT;
2611 case EL_BD_BUTTERFLY_DOWN: return GFX_BUTTERFLY_DOWN;
2612 case EL_BD_FIREFLY: return GFX_FIREFLY;
2613 case EL_BD_FIREFLY_RIGHT: return GFX_FIREFLY_RIGHT;
2614 case EL_BD_FIREFLY_UP: return GFX_FIREFLY_UP;
2615 case EL_BD_FIREFLY_LEFT: return GFX_FIREFLY_LEFT;
2616 case EL_BD_FIREFLY_DOWN: return GFX_FIREFLY_DOWN;
2617 case EL_YAMYAM: return GFX_MAMPFER;
2618 case EL_ROBOT: return GFX_ROBOT;
2619 case EL_STEELWALL: return GFX_BETON;
2620 case EL_DIAMOND: return GFX_DIAMANT;
2621 case EL_QUICKSAND_EMPTY: return GFX_MORAST_LEER;
2622 case EL_QUICKSAND_FULL: return GFX_MORAST_VOLL;
2623 case EL_QUICKSAND_EMPTYING: return GFX_MORAST_LEER;
2624 case EL_AMOEBA_DROP: return GFX_TROPFEN;
2625 case EL_BOMB: return GFX_BOMBE;
2626 case EL_MAGIC_WALL: return GFX_MAGIC_WALL_OFF;
2627 case EL_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_EMPTY;
2628 case EL_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_EMPTY;
2629 case EL_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_FULL;
2630 case EL_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_DEAD;
2631 case EL_ACID: return GFX_SALZSAEURE;
2632 case EL_AMOEBA_DEAD: return GFX_AMOEBE_TOT;
2633 case EL_AMOEBA_WET: return GFX_AMOEBE_NASS;
2634 case EL_AMOEBA_DRY: return GFX_AMOEBE_NORM;
2635 case EL_AMOEBA_FULL: return GFX_AMOEBE_VOLL;
2636 case EL_BD_AMOEBA: return GFX_AMOEBE_BD;
2637 case EL_AMOEBA_TO_DIAMOND: return GFX_AMOEBA2DIAM;
2638 case EL_AMOEBA_DRIPPING: return GFX_AMOEBE_NASS;
2639 case EL_NUT: return GFX_KOKOSNUSS;
2640 case EL_GAMEOFLIFE: return GFX_LIFE;
2641 case EL_BIOMAZE: return GFX_LIFE_ASYNC;
2642 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2643 case EL_STONEBLOCK: return GFX_BADEWANNE;
2644 case EL_ACIDPOOL_TOPLEFT: return GFX_BADEWANNE1;
2645 case EL_ACIDPOOL_TOPRIGHT: return GFX_BADEWANNE2;
2646 case EL_ACIDPOOL_BOTTOMLEFT: return GFX_BADEWANNE3;
2647 case EL_ACIDPOOL_BOTTOM: return GFX_BADEWANNE4;
2648 case EL_ACIDPOOL_BOTTOMRIGHT: return GFX_BADEWANNE5;
2649 case EL_ROBOT_WHEEL: return GFX_ABLENK_AUS;
2650 case EL_ROBOT_WHEEL_ACTIVE: return GFX_ABLENK_EIN;
2651 case EL_KEY1: return GFX_SCHLUESSEL1;
2652 case EL_KEY2: return GFX_SCHLUESSEL2;
2653 case EL_KEY3: return GFX_SCHLUESSEL3;
2654 case EL_KEY4: return GFX_SCHLUESSEL4;
2655 case EL_GATE1: return GFX_PFORTE1;
2656 case EL_GATE2: return GFX_PFORTE2;
2657 case EL_GATE3: return GFX_PFORTE3;
2658 case EL_GATE4: return GFX_PFORTE4;
2659 case EL_GATE1_GRAY: return GFX_PFORTE1X;
2660 case EL_GATE2_GRAY: return GFX_PFORTE2X;
2661 case EL_GATE3_GRAY: return GFX_PFORTE3X;
2662 case EL_GATE4_GRAY: return GFX_PFORTE4X;
2663 case EL_DYNAMITE: return GFX_DYNAMIT_AUS;
2664 case EL_PACMAN: return GFX_PACMAN;
2665 case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT;
2666 case EL_PACMAN_UP: return GFX_PACMAN_UP;
2667 case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT;
2668 case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN;
2669 case EL_INVISIBLE_WALL: return GFX_UNSICHTBAR;
2670 case EL_INVISIBLE_WALL_ACTIVE: return GFX_UNSICHTBAR_ON;
2671 case EL_WALL_EMERALD: return GFX_ERZ_EDEL;
2672 case EL_WALL_DIAMOND: return GFX_ERZ_DIAM;
2673 case EL_LAMP: return GFX_BIRNE_AUS;
2674 case EL_LAMP_ACTIVE: return GFX_BIRNE_EIN;
2675 case EL_TIME_ORB_FULL: return GFX_ZEIT_VOLL;
2676 case EL_TIME_ORB_EMPTY: return GFX_ZEIT_LEER;
2677 case EL_WALL_GROWING: return GFX_MAUER_LEBT;
2678 case EL_WALL_GROWING_X: return GFX_MAUER_X;
2679 case EL_WALL_GROWING_Y: return GFX_MAUER_Y;
2680 case EL_WALL_GROWING_XY: return GFX_MAUER_XY;
2681 case EL_BD_DIAMOND: return GFX_EDELSTEIN_BD;
2682 case EL_EMERALD_YELLOW: return GFX_EDELSTEIN_GELB;
2683 case EL_EMERALD_RED: return GFX_EDELSTEIN_ROT;
2684 case EL_EMERALD_PURPLE: return GFX_EDELSTEIN_LILA;
2685 case EL_WALL_BD_DIAMOND: return GFX_ERZ_EDEL_BD;
2686 case EL_WALL_EMERALD_YELLOW: return GFX_ERZ_EDEL_GELB;
2687 case EL_WALL_EMERALD_RED: return GFX_ERZ_EDEL_ROT;
2688 case EL_WALL_EMERALD_PURPLE: return GFX_ERZ_EDEL_LILA;
2689 case EL_DARK_YAMYAM: return GFX_MAMPFER2;
2690 case EL_BD_MAGIC_WALL: return GFX_MAGIC_WALL_BD_OFF;
2691 case EL_BD_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_BD_EMPTY;
2692 case EL_BD_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_BD_EMPTY;
2693 case EL_BD_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_BD_FULL;
2694 case EL_BD_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2695 case EL_DYNABOMB_PLAYER1_ACTIVE: return GFX_DYNABOMB;
2696 case EL_DYNABOMB_PLAYER2_ACTIVE: return GFX_DYNABOMB;
2697 case EL_DYNABOMB_PLAYER3_ACTIVE: return GFX_DYNABOMB;
2698 case EL_DYNABOMB_PLAYER4_ACTIVE: return GFX_DYNABOMB;
2699 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2700 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2701 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2702 case EL_SOKOBAN_OBJECT: return GFX_SOKOBAN_OBJEKT;
2703 case EL_SOKOBAN_FIELD_EMPTY: return GFX_SOKOBAN_FELD_LEER;
2704 case EL_SOKOBAN_FIELD_FULL: return GFX_SOKOBAN_FELD_VOLL;
2705 case EL_MOLE: return GFX_MOLE;
2706 case EL_PENGUIN: return GFX_PINGUIN;
2707 case EL_PIG: return GFX_SCHWEIN;
2708 case EL_DRAGON: return GFX_DRACHE;
2709 case EL_SATELLITE: return GFX_SONDE;
2710 case EL_ARROW_BLUE_LEFT: return GFX_PFEIL_LEFT;
2711 case EL_ARROW_BLUE_RIGHT: return GFX_PFEIL_RIGHT;
2712 case EL_ARROW_BLUE_UP: return GFX_PFEIL_UP;
2713 case EL_ARROW_BLUE_DOWN: return GFX_PFEIL_DOWN;
2714 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2715 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2716 case EL_SP_BUGGY_BASE_ACTIVE: return GFX_SP_BUG_ACTIVE;
2717 case EL_SP_ZONK: return GFX_SP_ZONK;
2718 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2719 case EL_INVISIBLE_STEELWALL: return GFX_INVISIBLE_STEEL;
2720 case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2721 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2722 case EL_EM_GATE1: return GFX_EM_GATE_1;
2723 case EL_EM_GATE2: return GFX_EM_GATE_2;
2724 case EL_EM_GATE3: return GFX_EM_GATE_3;
2725 case EL_EM_GATE4: return GFX_EM_GATE_4;
2726 case EL_EM_GATE1_GRAY: return GFX_EM_GATE_1X;
2727 case EL_EM_GATE2_GRAY: return GFX_EM_GATE_2X;
2728 case EL_EM_GATE3_GRAY: return GFX_EM_GATE_3X;
2729 case EL_EM_GATE4_GRAY: return GFX_EM_GATE_4X;
2730 case EL_EM_KEY1_FILE: return GFX_EM_KEY_1;
2731 case EL_EM_KEY2_FILE: return GFX_EM_KEY_2;
2732 case EL_EM_KEY3_FILE: return GFX_EM_KEY_3;
2733 case EL_EM_KEY4_FILE: return GFX_EM_KEY_4;
2734 case EL_EM_KEY1: return GFX_EM_KEY_1;
2735 case EL_EM_KEY2: return GFX_EM_KEY_2;
2736 case EL_EM_KEY3: return GFX_EM_KEY_3;
2737 case EL_EM_KEY4: return GFX_EM_KEY_4;
2738 case EL_PEARL: return GFX_PEARL;
2739 case EL_CRYSTAL: return GFX_CRYSTAL;
2740 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2741 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2742 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2743 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2744 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2745 case EL_SHIELD_NORMAL: return GFX_SHIELD_PASSIVE;
2746 case EL_SHIELD_DEADLY: return GFX_SHIELD_ACTIVE;
2747 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2748 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2749 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2750 case EL_SWITCHGATE_SWITCH_UP: return GFX_SWITCHGATE_SWITCH_1;
2751 case EL_SWITCHGATE_SWITCH_DOWN: return GFX_SWITCHGATE_SWITCH_2;
2752 case EL_CONVEYOR_BELT1_LEFT: return GFX_BELT1_LEFT;
2753 case EL_CONVEYOR_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2754 case EL_CONVEYOR_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2755 case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2756 case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2757 case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2758 case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2759 case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2760 case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2761 case EL_CONVEYOR_BELT2_LEFT: return GFX_BELT2_LEFT;
2762 case EL_CONVEYOR_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2763 case EL_CONVEYOR_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2764 case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2765 case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2766 case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2767 case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2768 case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2769 case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2770 case EL_CONVEYOR_BELT3_LEFT: return GFX_BELT3_LEFT;
2771 case EL_CONVEYOR_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2772 case EL_CONVEYOR_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2773 case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2774 case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2775 case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2776 case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2777 case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2778 case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2779 case EL_CONVEYOR_BELT4_LEFT: return GFX_BELT4_LEFT;
2780 case EL_CONVEYOR_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2781 case EL_CONVEYOR_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2782 case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2783 case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2784 case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2785 case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2786 case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2787 case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2788 case EL_LANDMINE: return GFX_LANDMINE;
2789 case EL_ENVELOPE: return GFX_ENVELOPE;
2790 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH_OFF;
2791 case EL_LIGHT_SWITCH_ACTIVE: return GFX_LIGHT_SWITCH_ON;
2792 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2793 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2794 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2795 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2796 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2797 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2798 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2799 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2800 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2801 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2802 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2803 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2804 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2805 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2806 case EL_MOLE_UP: return GFX_MOLE_UP;
2807 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2808 case EL_STEELWALL_SLANTED: return GFX_STEEL_SLANTED;
2809 case EL_INVISIBLE_SAND: return GFX_SAND_INVISIBLE;
2810 case EL_INVISIBLE_SAND_ACTIVE: return GFX_SAND_INVISIBLE_ON;
2811 case EL_DX_UNKNOWN_15: return GFX_DX_UNKNOWN_15;
2812 case EL_DX_UNKNOWN_42: return GFX_DX_UNKNOWN_42;
2813 case EL_TIMEGATE_OPEN: return GFX_TIMEGATE_OPEN;
2814 case EL_TIMEGATE_CLOSED: return GFX_TIMEGATE_CLOSED;
2815 case EL_TIMEGATE_SWITCH_ACTIVE: return GFX_TIMEGATE_SWITCH;
2816 case EL_TIMEGATE_SWITCH: return GFX_TIMEGATE_SWITCH;
2817 case EL_BALLOON: return GFX_BALLOON;
2818 case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
2819 case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2820 case EL_BALLOON_SEND_UP: return GFX_BALLOON_SEND_UP;
2821 case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
2822 case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2823 case EL_EMC_STEELWALL1: return GFX_EMC_STEEL_WALL_1;
2824 case EL_EMC_STEELWALL2: return GFX_EMC_STEEL_WALL_2;
2825 case EL_EMC_STEELWALL3: return GFX_EMC_STEEL_WALL_3;
2826 case EL_EMC_STEELWALL4: return GFX_EMC_STEEL_WALL_4;
2827 case EL_EMC_WALL_PILLAR_UPPER: return GFX_EMC_WALL_1;
2828 case EL_EMC_WALL_PILLAR_MIDDLE: return GFX_EMC_WALL_2;
2829 case EL_EMC_WALL_PILLAR_LOWER: return GFX_EMC_WALL_3;
2830 case EL_EMC_WALL4: return GFX_EMC_WALL_4;
2831 case EL_EMC_WALL5: return GFX_EMC_WALL_5;
2832 case EL_EMC_WALL6: return GFX_EMC_WALL_6;
2833 case EL_EMC_WALL7: return GFX_EMC_WALL_7;
2834 case EL_EMC_WALL8: return GFX_EMC_WALL_8;
2835 case EL_TUBE_ALL: return GFX_TUBE_CROSS;
2836 case EL_TUBE_VERTICAL: return GFX_TUBE_VERTICAL;
2837 case EL_TUBE_HORIZONTAL: return GFX_TUBE_HORIZONTAL;
2838 case EL_TUBE_VERTICAL_LEFT: return GFX_TUBE_VERT_LEFT;
2839 case EL_TUBE_VERTICAL_RIGHT: return GFX_TUBE_VERT_RIGHT;
2840 case EL_TUBE_HORIZONTAL_UP: return GFX_TUBE_HORIZ_UP;
2841 case EL_TUBE_HORIZONTAL_DOWN: return GFX_TUBE_HORIZ_DOWN;
2842 case EL_TUBE_LEFT_UP: return GFX_TUBE_LEFT_UP;
2843 case EL_TUBE_LEFT_DOWN: return GFX_TUBE_LEFT_DOWN;
2844 case EL_TUBE_RIGHT_UP: return GFX_TUBE_RIGHT_UP;
2845 case EL_TUBE_RIGHT_DOWN: return GFX_TUBE_RIGHT_DOWN;
2846 case EL_SPRING: return GFX_SPRING;
2847 case EL_TRAP: return GFX_TRAP_INACTIVE;
2848 case EL_TRAP_ACTIVE: return GFX_TRAP_ACTIVE;
2849 case EL_BD_WALL: return GFX_BD_WALL;
2850 case EL_BD_ROCK: return GFX_BD_ROCK;
2851 case EL_DX_SUPABOMB: return GFX_DX_SUPABOMB;
2852 case EL_SP_MURPHY_CLONE: return GFX_SP_MURPHY_CLONE;
2856 if (IS_CHAR(element))
2857 return GFX_CHAR_START + (element - EL_CHAR_START);
2858 else if (element >= EL_SP_START && element <= EL_SP_END)
2860 int nr_element = element - EL_SP_START;
2861 int gfx_per_line = 8;
2863 (nr_element / gfx_per_line) * SP_PER_LINE +
2864 (nr_element % gfx_per_line);
2866 return GFX_START_ROCKSSP + nr_graphic;
2874 int el2gfx(int element)
2877 int graphic_OLD = el2gfx_OLD(element);
2882 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2885 int graphic_OLD = el2gfx_OLD(element);
2887 if (element >= MAX_ELEMENTS)
2889 Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
2892 if (graphic_NEW != graphic_OLD)
2894 Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2895 graphic_NEW, graphic_OLD);
2903 int el2img(int element)
2906 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2909 if (graphic_NEW < 0)
2910 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2911 element, graphic_NEW);
2919 case EL_BD_BUTTERFLY: return IMG_BD_BUTTERFLY;
2920 case EL_BD_FIREFLY: return IMG_BD_FIREFLY;
2921 case EL_SP_ELECTRON: return IMG_SP_ELECTRON;
2931 int el_dir2img(int element, int direction)
2933 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2936 int el_dir_act2img(int element, int direction, int action)
2938 action = graphics_action_mapping[action];
2939 direction = MV_DIR_BIT(direction);
2941 return element_info[element].direction_graphic[action][direction];