1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
180 BlitBitmap(backbuffer, window,
181 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
185 int fx = FX, fy = FY;
187 if (setup.soft_scrolling)
189 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
190 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
193 if (setup.soft_scrolling ||
194 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
195 ABS(ScreenMovPos) == ScrollStepSize ||
196 redraw_tiles > REDRAWTILES_THRESHOLD)
198 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
202 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
204 (setup.soft_scrolling ?
205 "setup.soft_scrolling" :
206 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
207 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
208 ABS(ScreenGfxPos) == ScrollStepSize ?
209 "ABS(ScreenGfxPos) == ScrollStepSize" :
210 "redraw_tiles > REDRAWTILES_THRESHOLD"));
216 redraw_mask &= ~REDRAW_MAIN;
219 if (redraw_mask & REDRAW_DOORS)
221 if (redraw_mask & REDRAW_DOOR_1)
222 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
223 if (redraw_mask & REDRAW_DOOR_2)
225 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
226 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
229 if (redraw_mask & REDRAW_VIDEO_1)
230 BlitBitmap(backbuffer, window,
231 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
232 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
234 if (redraw_mask & REDRAW_VIDEO_2)
235 BlitBitmap(backbuffer, window,
236 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
237 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
239 if (redraw_mask & REDRAW_VIDEO_3)
240 BlitBitmap(backbuffer, window,
241 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
242 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
246 if (redraw_mask & REDRAW_DOOR_3)
247 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
248 redraw_mask &= ~REDRAW_DOORS;
251 if (redraw_mask & REDRAW_MICROLEVEL)
253 BlitBitmap(backbuffer, window,
254 MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
255 MICROLEV_XPOS, MICROLEV_YPOS);
256 BlitBitmap(backbuffer, window,
257 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
258 SX, MICROLABEL_YPOS);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
367 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
369 if (setup.soft_scrolling && game_status == PLAYING)
371 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
372 SetDrawtoField(DRAW_BUFFERED);
375 SetDrawtoField(DRAW_BACKBUFFER);
377 if (setup.direct_draw && game_status == PLAYING)
379 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
380 SetDrawtoField(DRAW_DIRECT);
383 redraw_mask |= REDRAW_FIELD;
386 static int getGraphicAnimationPhase(int frames, int delay, int mode)
390 if (mode & ANIM_PINGPONG)
392 int max_anim_frames = 2 * frames - 2;
394 phase = (FrameCounter % (delay * max_anim_frames)) / delay;
395 phase = (phase < frames ? phase : max_anim_frames - phase);
398 phase = (FrameCounter % (delay * frames)) / delay;
400 if (mode & ANIM_REVERSE)
406 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
408 /* animation synchronized with global frame counter, not move position */
409 if (new_graphic_info[graphic].anim_global_sync || sync_frame < 0)
410 sync_frame = FrameCounter;
412 return getAnimationFrame(new_graphic_info[graphic].anim_frames,
413 new_graphic_info[graphic].anim_delay,
414 new_graphic_info[graphic].anim_mode,
415 new_graphic_info[graphic].anim_start_frame,
419 void MarkTileDirty(int x, int y)
421 int xx = redraw_x1 + x;
422 int yy = redraw_y1 + y;
427 redraw[xx][yy] = TRUE;
428 redraw_mask |= REDRAW_TILES;
431 void SetBorderElement()
435 BorderElement = EL_EMPTY;
437 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
439 for(x=0; x<lev_fieldx; x++)
441 if (!IS_MASSIVE(Feld[x][y]))
442 BorderElement = EL_STEELWALL;
444 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
450 void DrawAllPlayers()
454 for(i=0; i<MAX_PLAYERS; i++)
455 if (stored_player[i].active)
456 DrawPlayer(&stored_player[i]);
459 void DrawPlayerField(int x, int y)
461 if (!IS_PLAYER(x, y))
464 DrawPlayer(PLAYERINFO(x, y));
467 void DrawPlayer(struct PlayerInfo *player)
469 int jx = player->jx, jy = player->jy;
470 int last_jx = player->last_jx, last_jy = player->last_jy;
471 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
472 int sx = SCREENX(jx), sy = SCREENY(jy);
473 int sxx = 0, syy = 0;
474 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
477 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
479 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
483 if (!IN_LEV_FIELD(jx,jy))
485 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
486 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
487 printf("DrawPlayerField(): This should never happen!\n");
492 if (element == EL_EXPLOSION)
495 /* draw things in the field the player is leaving, if needed */
497 if (player_is_moving)
499 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
501 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
503 if (last_element == EL_DYNAMITE_ACTIVE)
504 DrawDynamite(last_jx, last_jy);
506 DrawLevelFieldThruMask(last_jx, last_jy);
508 else if (last_element == EL_DYNAMITE_ACTIVE)
509 DrawDynamite(last_jx, last_jy);
511 DrawLevelField(last_jx, last_jy);
513 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
517 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
518 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
520 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
523 DrawLevelField(next_jx, next_jy);
527 if (!IN_SCR_FIELD(sx, sy))
530 if (setup.direct_draw)
531 SetDrawtoField(DRAW_BUFFERED);
533 /* draw things behind the player, if needed */
536 DrawLevelElement(jx, jy, Store[jx][jy]);
537 else if (!IS_ACTIVE_BOMB(element))
538 DrawLevelField(jx, jy);
540 DrawLevelElement(jx, jy, EL_EMPTY);
542 /* draw player himself */
544 if (game.emulation == EMU_SUPAPLEX)
546 static int last_dir = MV_LEFT;
547 int action = (player->programmed_action ? player->programmed_action :
549 boolean action_moving =
551 ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
552 !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
554 graphic = IMG_SP_MURPHY;
558 if (player->MovDir == MV_LEFT)
559 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
560 else if (player->MovDir == MV_RIGHT)
561 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
562 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
563 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
564 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
565 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
567 else if (player->snapped)
569 if (player->MovDir == MV_LEFT)
570 graphic = IMG_SP_MURPHY_LEFT_SNAPPING;
571 else if (player->MovDir == MV_RIGHT)
572 graphic = IMG_SP_MURPHY_RIGHT_SNAPPING;
573 else if (player->MovDir == MV_UP)
574 graphic = IMG_SP_MURPHY_UP_SNAPPING;
575 else if (player->MovDir == MV_DOWN)
576 graphic = IMG_SP_MURPHY_DOWN_SNAPPING;
578 else if (action_moving)
580 if (player->MovDir == MV_LEFT)
581 graphic = IMG_SP_MURPHY_LEFT_MOVING;
582 else if (player->MovDir == MV_RIGHT)
583 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
584 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
585 graphic = IMG_SP_MURPHY_LEFT_MOVING;
586 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
587 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
589 graphic = IMG_SP_MURPHY_LEFT_MOVING;
591 frame = getGraphicAnimationFrame(graphic, -1);
594 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
595 last_dir = player->MovDir;
599 if (player->MovDir == MV_LEFT)
600 graphic = (player->Pushing ? IMG_PLAYER1_LEFT_PUSHING :
601 player->is_moving ? IMG_PLAYER1_LEFT_MOVING :
603 else if (player->MovDir == MV_RIGHT)
604 graphic = (player->Pushing ? IMG_PLAYER1_RIGHT_PUSHING :
605 player->is_moving ? IMG_PLAYER1_RIGHT_MOVING :
607 else if (player->MovDir == MV_UP)
608 graphic = (player->Pushing ? IMG_PLAYER1_UP_PUSHING :
609 player->is_moving ? IMG_PLAYER1_UP_MOVING :
611 else /* MV_DOWN || MV_NO_MOVING */
612 graphic = (player->Pushing ? IMG_PLAYER1_DOWN_PUSHING :
613 player->is_moving ? IMG_PLAYER1_DOWN_MOVING :
616 graphic = PLAYER_NR_GFX(graphic, player->index_nr);
619 frame = player->Frame;
621 frame = getGraphicAnimationFrame(graphic, player->Frame);
627 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
628 sxx = player->GfxPos;
630 syy = player->GfxPos;
633 if (!setup.soft_scrolling && ScreenMovPos)
638 printf("-> %d\n", player->Frame);
641 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
643 if (SHIELD_ON(player))
645 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
646 IMG_SHIELD_NORMAL_ACTIVE);
647 int frame = getGraphicAnimationFrame(graphic, -1);
649 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
653 if (player->Pushing && player->GfxPos)
655 if (player->Pushing && player_is_moving)
658 int px = SCREENX(next_jx), py = SCREENY(next_jy);
660 if (element == EL_SOKOBAN_FIELD_EMPTY ||
661 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
662 DrawGraphicShiftedThruMask(px, py, sxx, syy, GFX_SOKOBAN_OBJEKT, 0,
666 int element = Feld[next_jx][next_jy];
667 int graphic = el2img(element);
672 if ((element == EL_ROCK ||
673 element == EL_BD_ROCK ||
674 element == EL_SP_ZONK) && sxx)
676 graphic = el_dir_act2img(element, player->MovDir, GFX_ACTION_MOVING);
678 frame = getGraphicAnimationFrame(graphic, player->GfxPos);
680 frame = getGraphicAnimationFrame(graphic, player->Frame);
684 printf("-> %d [%d]\n", player->Frame, player->GfxPos);
689 if (player->MovDir == MV_LEFT)
694 frame = (player->GfxPos / (TILEX / 4));
696 if (player->MovDir == MV_RIGHT)
697 frame = (frame + 4) % 4;
701 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
702 NO_CUTTING, NO_MASKING);
706 /* draw things in front of player (active dynamite or dynabombs) */
708 if (IS_ACTIVE_BOMB(element))
710 graphic = el2img(element);
713 if (element == EL_DYNAMITE_ACTIVE)
715 if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
720 if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
724 frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
727 if (game.emulation == EMU_SUPAPLEX)
728 DrawGraphic(sx, sy, GFX_SP_DISK_RED, 0);
730 DrawGraphicThruMask(sx, sy, graphic, frame);
733 if (player_is_moving && last_element == EL_EXPLOSION)
735 int stored = Store[last_jx][last_jy];
736 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
737 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
739 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
740 int phase = Frame[last_jx][last_jy] - 1;
741 int frame = getGraphicAnimationFrame(graphic, phase - delay);
744 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
747 /* draw elements that stay over the player */
748 /* handle the field the player is leaving ... */
749 if (player_is_moving && IS_OVER_PLAYER(last_element))
750 DrawLevelField(last_jx, last_jy);
752 /* ... and the field the player is entering */
753 if (IS_OVER_PLAYER(element))
754 DrawLevelField(jx, jy);
756 if (setup.direct_draw)
758 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
759 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
760 int x_size = TILEX * (1 + ABS(jx - last_jx));
761 int y_size = TILEY * (1 + ABS(jy - last_jy));
763 BlitBitmap(drawto_field, window,
764 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
765 SetDrawtoField(DRAW_DIRECT);
768 MarkTileDirty(sx,sy);
771 void DrawGraphicAnimationExt(int x, int y, int graphic, int mask_mode)
773 if (IN_SCR_FIELD(x, y) &&
774 (FrameCounter % new_graphic_info[graphic].anim_delay) == 0)
776 int frame = getGraphicAnimationFrame(graphic, -1);
778 if (mask_mode == USE_MASKING)
779 DrawGraphicThruMask(x, y, graphic, frame);
781 DrawGraphic(x, y, graphic, frame);
785 void DrawGraphicAnimation(int x, int y, int graphic)
787 DrawGraphicAnimationExt(x, y, graphic, NO_MASKING);
791 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
793 if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
795 *bitmap = graphic_info[graphic].bitmap;
796 *x = graphic_info[graphic].src_x;
797 *y = graphic_info[graphic].src_y;
799 else if (graphic >= GFX_START_ROCKSELEMENTS &&
800 graphic <= GFX_END_ROCKSELEMENTS)
802 graphic -= GFX_START_ROCKSELEMENTS;
803 *bitmap = new_graphic_info[IMG_OLD_PIX_ELEMENTS].bitmap;
804 *x = (graphic % GFX_PER_LINE) * TILEX;
805 *y = (graphic / GFX_PER_LINE) * TILEY;
807 else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
809 graphic -= GFX_START_ROCKSHEROES;
810 *bitmap = new_graphic_info[IMG_OLD_PIX_HEROES].bitmap;
811 *x = (graphic % HEROES_PER_LINE) * TILEX;
812 *y = (graphic / HEROES_PER_LINE) * TILEY;
814 else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
816 graphic -= GFX_START_ROCKSSP;
817 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
818 *x = (graphic % SP_PER_LINE) * TILEX;
819 *y = (graphic / SP_PER_LINE) * TILEY;
821 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
823 graphic -= GFX_START_ROCKSDC;
824 *bitmap = new_graphic_info[IMG_OLD_PIX_DC].bitmap;
825 *x = (graphic % DC_PER_LINE) * TILEX;
826 *y = (graphic / DC_PER_LINE) * TILEY;
828 else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
830 graphic -= GFX_START_ROCKSMORE;
831 *bitmap = new_graphic_info[IMG_OLD_PIX_MORE].bitmap;
832 *x = (graphic % MORE_PER_LINE) * TILEX;
833 *y = (graphic / MORE_PER_LINE) * TILEY;
835 else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
837 graphic -= GFX_START_ROCKSFONT;
838 *bitmap = new_graphic_info[IMG_OLD_PIX_FONT_EM].bitmap;
839 *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
840 *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
844 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
851 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
853 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
854 int offset_x = new_graphic_info[graphic].offset_x;
855 int offset_y = new_graphic_info[graphic].offset_y;
856 int src_x = new_graphic_info[graphic].src_x + frame * offset_x;
857 int src_y = new_graphic_info[graphic].src_y + frame * offset_y;
859 *bitmap = src_bitmap;
864 void DrawGraphic(int x, int y, int graphic, int frame)
867 if (!IN_SCR_FIELD(x, y))
869 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
870 printf("DrawGraphic(): This should never happen!\n");
875 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
880 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
885 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
886 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
890 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
897 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
899 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
900 int src_x = new_graphic_info[graphic].src_x;
901 int src_y = new_graphic_info[graphic].src_y;
902 int offset_x = new_graphic_info[graphic].offset_x;
903 int offset_y = new_graphic_info[graphic].offset_y;
905 src_x += frame * offset_x;
906 src_y += frame * offset_y;
909 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
912 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
915 if (!IN_SCR_FIELD(x, y))
917 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
918 printf("DrawGraphicThruMask(): This should never happen!\n");
923 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
928 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
936 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
937 drawing_gc = src_bitmap->stored_clip_gc;
939 GC drawing_gc = src_bitmap->stored_clip_gc;
940 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
941 int src_x = new_graphic_info[graphic].src_x;
942 int src_y = new_graphic_info[graphic].src_y;
943 int offset_x = new_graphic_info[graphic].offset_x;
944 int offset_y = new_graphic_info[graphic].offset_y;
946 src_x += frame * offset_x;
947 src_y += frame * offset_y;
951 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
952 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
955 void DrawMiniGraphic(int x, int y, int graphic)
957 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
958 MarkTileDirty(x / 2, y / 2);
961 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
963 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
965 int mini_starty = src_bitmap->height * 2 / 3;
966 int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
967 int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
969 if (src_x + MINI_TILEX > src_bitmap->width ||
970 src_y + MINI_TILEY > src_bitmap->height)
972 /* graphic of desired size seems not to be contained in this image;
973 dirty workaround: get it from the middle of the normal sized image */
975 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
976 src_x += (TILEX / 2 - MINI_TILEX / 2);
977 src_y += (TILEY / 2 - MINI_TILEY / 2);
980 *bitmap = src_bitmap;
985 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
990 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
991 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
994 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
995 int cut_mode, int mask_mode)
1004 int width = TILEX, height = TILEY;
1010 DrawGraphic(x, y, graphic, frame);
1014 if (dx || dy) /* shifted graphic */
1016 if (x < BX1) /* object enters playfield from the left */
1023 else if (x > BX2) /* object enters playfield from the right */
1029 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1035 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1037 else if (dx) /* general horizontal movement */
1038 MarkTileDirty(x + SIGN(dx), y);
1040 if (y < BY1) /* object enters playfield from the top */
1042 if (cut_mode==CUT_BELOW) /* object completely above top border */
1050 else if (y > BY2) /* object enters playfield from the bottom */
1056 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1062 else if (dy > 0 && cut_mode == CUT_ABOVE)
1064 if (y == BY2) /* object completely above bottom border */
1070 MarkTileDirty(x, y + 1);
1071 } /* object leaves playfield to the bottom */
1072 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1074 else if (dy) /* general vertical movement */
1075 MarkTileDirty(x, y + SIGN(dy));
1078 src_bitmap = new_graphic_info[graphic].bitmap;
1079 src_x = new_graphic_info[graphic].src_x;
1080 src_y = new_graphic_info[graphic].src_y;
1081 offset_x = new_graphic_info[graphic].offset_x;
1082 offset_y = new_graphic_info[graphic].offset_y;
1084 drawing_gc = src_bitmap->stored_clip_gc;
1086 src_x += frame * offset_x;
1087 src_y += frame * offset_y;
1092 dest_x = FX + x * TILEX + dx;
1093 dest_y = FY + y * TILEY + dy;
1096 if (!IN_SCR_FIELD(x,y))
1098 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1099 printf("DrawGraphicShifted(): This should never happen!\n");
1104 if (mask_mode == USE_MASKING)
1106 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1107 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1111 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1117 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1118 int frame, int cut_mode)
1120 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1124 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1125 int cut_mode, int mask_mode)
1127 int ux = LEVELX(x), uy = LEVELY(y);
1128 int graphic = el2gfx(element);
1129 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1130 int phase4 = phase8 / 2;
1131 int phase2 = phase8 / 4;
1132 int dir = MovDir[ux][uy];
1134 if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1136 graphic += 1 * !phase2;
1140 else if (dir == MV_LEFT)
1142 else if (dir == MV_DOWN)
1145 else if (element == EL_SP_SNIKSNAK)
1148 graphic = GFX_SP_SNIKSNAK_LEFT;
1149 else if (dir == MV_RIGHT)
1150 graphic = GFX_SP_SNIKSNAK_RIGHT;
1151 else if (dir == MV_UP)
1152 graphic = GFX_SP_SNIKSNAK_UP;
1154 graphic = GFX_SP_SNIKSNAK_DOWN;
1156 graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1158 else if (element == EL_SP_ELECTRON)
1160 graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1162 else if (element == EL_MOLE || element == EL_PENGUIN ||
1163 element == EL_PIG || element == EL_DRAGON)
1166 graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1167 element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1168 element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1169 else if (dir == MV_RIGHT)
1170 graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1171 element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1172 element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1173 else if (dir == MV_UP)
1174 graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1175 element == EL_PENGUIN ? GFX_PINGUIN_UP :
1176 element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1178 graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1179 element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1180 element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1184 else if (element == EL_SATELLITE)
1186 graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1188 else if (element == EL_ACID)
1190 graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1192 else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1196 else if (element == EL_BALLOON)
1200 else if ((element == EL_ROCK ||
1201 element == EL_SP_ZONK ||
1202 element == EL_BD_ROCK ||
1203 element == EL_SP_INFOTRON ||
1207 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1209 if (element == EL_ROCK ||
1210 element == EL_SP_ZONK ||
1211 element == EL_BD_ROCK)
1214 graphic += (4 - phase4) % 4;
1215 else if (dir == MV_RIGHT)
1218 graphic += phase2 * 2;
1220 else if (element != EL_SP_INFOTRON)
1224 else if (element == EL_MAGIC_WALL_ACTIVE ||
1225 element == EL_MAGIC_WALL_EMPTYING ||
1226 element == EL_BD_MAGIC_WALL_ACTIVE ||
1227 element == EL_BD_MAGIC_WALL_EMPTYING ||
1228 element == EL_MAGIC_WALL_FULL ||
1229 element == EL_BD_MAGIC_WALL_FULL)
1231 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1233 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1235 graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1236 graphic += (x + 2 * y + 4) % 4;
1238 else if (element == EL_WALL_GROWING)
1240 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1242 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1243 links_massiv = TRUE;
1244 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1245 rechts_massiv = TRUE;
1247 if (links_massiv && rechts_massiv)
1248 graphic = GFX_MAUERWERK;
1249 else if (links_massiv)
1250 graphic = GFX_MAUER_R;
1251 else if (rechts_massiv)
1252 graphic = GFX_MAUER_L;
1255 else if ((element == EL_INVISIBLE_STEELWALL ||
1256 element == EL_INVISIBLE_WALL ||
1257 element == EL_INVISIBLE_SAND) && game.light_time_left)
1259 graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1260 element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1261 GFX_SAND_INVISIBLE_ON);
1266 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1267 else if (mask_mode == USE_MASKING)
1268 DrawGraphicThruMask(x, y, graphic);
1270 DrawGraphic(x, y, graphic);
1274 inline static int getFramePosition(int x, int y)
1276 int frame_pos = -1; /* default: global synchronization */
1278 int element = Feld[x][y];
1280 if (element == EL_QUICKSAND_FULL ||
1281 element == EL_MAGIC_WALL_FULL ||
1282 element == EL_BD_MAGIC_WALL_FULL)
1284 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1285 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1287 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1293 inline static int getGfxAction(int x, int y)
1295 int gfx_action = GFX_ACTION_DEFAULT;
1298 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1299 gfx_action = GfxAction[x][y];
1300 else if (IS_MOVING(x, y))
1301 gfx_action = GFX_ACTION_MOVING;
1303 gfx_action = GfxAction[x][y];
1309 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1310 int cut_mode, int mask_mode)
1312 int ux = LEVELX(x), uy = LEVELY(y);
1313 int move_dir = MovDir[ux][uy];
1314 int move_pos = getFramePosition(ux, uy);
1315 int gfx_action = getGfxAction(ux, uy);
1316 int graphic = el_dir_act2img(element, move_dir, gfx_action);
1317 int frame = getGraphicAnimationFrame(graphic, move_pos);
1319 if (element == EL_WALL_GROWING)
1321 boolean left_stopped = FALSE, right_stopped = FALSE;
1323 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1324 left_stopped = TRUE;
1325 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1326 right_stopped = TRUE;
1328 if (left_stopped && right_stopped)
1330 else if (left_stopped)
1332 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1333 frame = new_graphic_info[graphic].anim_frames - 1;
1335 else if (right_stopped)
1337 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1338 frame = new_graphic_info[graphic].anim_frames - 1;
1341 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1343 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1344 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1345 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1346 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1347 IMG_AMOEBA_DEAD_PART1);
1349 graphic += (x + 2 * y + 4) % 4;
1353 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1354 else if (mask_mode == USE_MASKING)
1355 DrawGraphicThruMask(x, y, graphic, frame);
1357 DrawGraphic(x, y, graphic, frame);
1360 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1361 int cut_mode, int mask_mode)
1363 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1364 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1365 cut_mode, mask_mode);
1368 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1371 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1374 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1377 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1381 void DrawOldScreenElementThruMask(int x, int y, int element)
1383 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1386 void DrawScreenElementThruMask(int x, int y, int element)
1388 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1392 void DrawLevelElementThruMask(int x, int y, int element)
1394 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1397 void DrawLevelFieldThruMask(int x, int y)
1399 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1402 void DrawCrumbledSand(int x, int y)
1406 int i, width, height, cx,cy;
1407 int ux = LEVELX(x), uy = LEVELY(y);
1408 int element, graphic;
1410 static int xy[4][2] =
1418 if (!IN_LEV_FIELD(ux, uy))
1421 element = Feld[ux][uy];
1423 if (element == EL_SAND ||
1424 element == EL_LANDMINE ||
1425 element == EL_TRAP ||
1426 element == EL_TRAP_ACTIVE)
1428 if (!IN_SCR_FIELD(x, y))
1431 graphic = IMG_SAND_CRUMBLED;
1433 src_bitmap = new_graphic_info[graphic].bitmap;
1434 src_x = new_graphic_info[graphic].src_x;
1435 src_y = new_graphic_info[graphic].src_y;
1441 uxx = ux + xy[i][0];
1442 uyy = uy + xy[i][1];
1443 if (!IN_LEV_FIELD(uxx, uyy))
1444 element = EL_STEELWALL;
1446 element = Feld[uxx][uyy];
1448 if (element == EL_SAND ||
1449 element == EL_LANDMINE ||
1450 element == EL_TRAP ||
1451 element == EL_TRAP_ACTIVE)
1454 if (i == 1 || i == 2)
1458 cx = (i == 2 ? TILEX - snip : 0);
1466 cy = (i == 3 ? TILEY - snip : 0);
1469 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1470 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1473 MarkTileDirty(x, y);
1477 graphic = IMG_SAND_CRUMBLED;
1479 src_bitmap = new_graphic_info[graphic].bitmap;
1480 src_x = new_graphic_info[graphic].src_x;
1481 src_y = new_graphic_info[graphic].src_y;
1485 int xx, yy, uxx, uyy;
1489 uxx = ux + xy[i][0];
1490 uyy = uy + xy[i][1];
1492 if (!IN_LEV_FIELD(uxx, uyy) ||
1493 (Feld[uxx][uyy] != EL_SAND &&
1494 Feld[uxx][uyy] != EL_LANDMINE &&
1495 Feld[uxx][uyy] != EL_TRAP &&
1496 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1497 !IN_SCR_FIELD(xx, yy))
1500 if (i == 1 || i == 2)
1504 cx = (i == 1 ? TILEX - snip : 0);
1512 cy = (i==0 ? TILEY-snip : 0);
1515 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1516 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1518 MarkTileDirty(xx, yy);
1523 void DrawScreenElement(int x, int y, int element)
1525 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1526 DrawCrumbledSand(x, y);
1529 void DrawLevelElement(int x, int y, int element)
1531 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1532 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1535 void DrawScreenField(int x, int y)
1537 int ux = LEVELX(x), uy = LEVELY(y);
1538 int element, content;
1540 if (!IN_LEV_FIELD(ux, uy))
1542 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1545 element = BorderElement;
1547 DrawScreenElement(x, y, element);
1551 element = Feld[ux][uy];
1552 content = Store[ux][uy];
1554 if (IS_MOVING(ux, uy))
1556 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1557 boolean cut_mode = NO_CUTTING;
1559 if (element == EL_QUICKSAND_EMPTYING ||
1560 element == EL_MAGIC_WALL_EMPTYING ||
1561 element == EL_BD_MAGIC_WALL_EMPTYING ||
1562 element == EL_AMOEBA_DRIPPING)
1563 cut_mode = CUT_ABOVE;
1564 else if (element == EL_QUICKSAND_FILLING ||
1565 element == EL_MAGIC_WALL_FILLING ||
1566 element == EL_BD_MAGIC_WALL_FILLING)
1567 cut_mode = CUT_BELOW;
1569 if (cut_mode == CUT_ABOVE)
1570 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1572 DrawScreenElement(x, y, EL_EMPTY);
1575 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1576 else if (cut_mode == NO_CUTTING)
1577 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1579 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1581 if (content == EL_ACID)
1582 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1584 else if (IS_BLOCKED(ux, uy))
1589 boolean cut_mode = NO_CUTTING;
1590 int element_old, content_old;
1592 Blocked2Moving(ux, uy, &oldx, &oldy);
1595 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1596 MovDir[oldx][oldy] == MV_RIGHT);
1598 element_old = Feld[oldx][oldy];
1599 content_old = Store[oldx][oldy];
1601 if (element_old == EL_QUICKSAND_EMPTYING ||
1602 element_old == EL_MAGIC_WALL_EMPTYING ||
1603 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1604 element_old == EL_AMOEBA_DRIPPING)
1605 cut_mode = CUT_ABOVE;
1607 DrawScreenElement(x, y, EL_EMPTY);
1610 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1612 else if (cut_mode == NO_CUTTING)
1613 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1616 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1619 else if (IS_DRAWABLE(element))
1620 DrawScreenElement(x, y, element);
1622 DrawScreenElement(x, y, EL_EMPTY);
1625 void DrawLevelField(int x, int y)
1627 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1628 DrawScreenField(SCREENX(x), SCREENY(y));
1629 else if (IS_MOVING(x, y))
1633 Moving2Blocked(x, y, &newx, &newy);
1634 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1635 DrawScreenField(SCREENX(newx), SCREENY(newy));
1637 else if (IS_BLOCKED(x, y))
1641 Blocked2Moving(x, y, &oldx, &oldy);
1642 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1643 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1647 void DrawMiniElement(int x, int y, int element)
1651 graphic = el2img(element);
1652 DrawMiniGraphic(x, y, graphic);
1655 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1657 int x = sx + scroll_x, y = sy + scroll_y;
1659 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1660 DrawMiniElement(sx, sy, EL_EMPTY);
1661 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1662 DrawMiniElement(sx, sy, Feld[x][y]);
1665 int steel_type, steel_position;
1668 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1669 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1670 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1671 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1672 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1673 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1676 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1677 steel_position = (x == -1 && y == -1 ? 0 :
1678 x == lev_fieldx && y == -1 ? 1 :
1679 x == -1 && y == lev_fieldy ? 2 :
1680 x == lev_fieldx && y == lev_fieldy ? 3 :
1681 x == -1 || x == lev_fieldx ? 4 :
1682 y == -1 || y == lev_fieldy ? 5 : -1);
1684 if (steel_position != -1)
1685 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1689 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1691 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1692 int mini_startx = src_bitmap->width * 3 / 4;
1693 int mini_starty = src_bitmap->height * 2 / 3;
1694 int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1695 int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1697 if (src_x + MICRO_TILEX > src_bitmap->width ||
1698 src_y + MICRO_TILEY > src_bitmap->height)
1700 /* graphic of desired size seems not to be contained in this image;
1701 dirty workaround: get it from the middle of the normal sized image */
1703 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1704 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1705 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1708 *bitmap = src_bitmap;
1713 void DrawMicroElement(int xpos, int ypos, int element)
1719 if (element == EL_EMPTY)
1722 graphic = el2img(element);
1724 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1725 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1735 for(x=BX1; x<=BX2; x++)
1736 for(y=BY1; y<=BY2; y++)
1737 DrawScreenField(x, y);
1739 redraw_mask |= REDRAW_FIELD;
1742 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1746 for(x=0; x<size_x; x++)
1747 for(y=0; y<size_y; y++)
1748 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1750 redraw_mask |= REDRAW_FIELD;
1753 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1757 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1759 if (lev_fieldx < STD_LEV_FIELDX)
1760 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1761 if (lev_fieldy < STD_LEV_FIELDY)
1762 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1764 xpos += MICRO_TILEX;
1765 ypos += MICRO_TILEY;
1767 for(x=-1; x<=STD_LEV_FIELDX; x++)
1769 for(y=-1; y<=STD_LEV_FIELDY; y++)
1771 int lx = from_x + x, ly = from_y + y;
1773 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1774 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1776 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1777 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1782 redraw_mask |= REDRAW_MICROLEVEL;
1785 #define MICROLABEL_EMPTY 0
1786 #define MICROLABEL_LEVEL_NAME 1
1787 #define MICROLABEL_CREATED_BY 2
1788 #define MICROLABEL_LEVEL_AUTHOR 3
1789 #define MICROLABEL_IMPORTED_FROM 4
1790 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1792 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1794 static void DrawMicroLevelLabelExt(int mode)
1796 char label_text[MAX_MICROLABEL_SIZE + 1];
1798 ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1800 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1801 mode == MICROLABEL_CREATED_BY ? "created by" :
1802 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1803 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1804 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1805 leveldir_current->imported_from : ""),
1806 MAX_MICROLABEL_SIZE);
1807 label_text[MAX_MICROLABEL_SIZE] = '\0';
1809 if (strlen(label_text) > 0)
1811 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1812 int lypos = MICROLABEL_YPOS;
1814 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1817 redraw_mask |= REDRAW_MICROLEVEL;
1820 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1822 static unsigned long scroll_delay = 0;
1823 static unsigned long label_delay = 0;
1824 static int from_x, from_y, scroll_direction;
1825 static int label_state, label_counter;
1829 from_x = from_y = 0;
1830 scroll_direction = MV_RIGHT;
1834 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1835 DrawMicroLevelLabelExt(label_state);
1837 /* initialize delay counters */
1838 DelayReached(&scroll_delay, 0);
1839 DelayReached(&label_delay, 0);
1844 /* scroll micro level, if needed */
1845 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1846 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1848 switch (scroll_direction)
1854 scroll_direction = MV_UP;
1858 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1861 scroll_direction = MV_DOWN;
1868 scroll_direction = MV_RIGHT;
1872 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1875 scroll_direction = MV_LEFT;
1882 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1885 /* redraw micro level label, if needed */
1886 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1887 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1888 strcmp(level.author, leveldir_current->name) != 0 &&
1889 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1891 int max_label_counter = 23;
1893 if (leveldir_current->imported_from != NULL)
1894 max_label_counter += 14;
1896 label_counter = (label_counter + 1) % max_label_counter;
1897 label_state = (label_counter >= 0 && label_counter <= 7 ?
1898 MICROLABEL_LEVEL_NAME :
1899 label_counter >= 9 && label_counter <= 12 ?
1900 MICROLABEL_CREATED_BY :
1901 label_counter >= 14 && label_counter <= 21 ?
1902 MICROLABEL_LEVEL_AUTHOR :
1903 label_counter >= 23 && label_counter <= 26 ?
1904 MICROLABEL_IMPORTED_FROM :
1905 label_counter >= 28 && label_counter <= 35 ?
1906 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1907 DrawMicroLevelLabelExt(label_state);
1911 int REQ_in_range(int x, int y)
1913 if (y > DY+249 && y < DY+278)
1915 if (x > DX+1 && x < DX+48)
1917 else if (x > DX+51 && x < DX+98)
1923 #define MAX_REQUEST_LINES 13
1924 #define MAX_REQUEST_LINE_LEN 7
1926 boolean Request(char *text, unsigned int req_state)
1928 int mx, my, ty, result = -1;
1929 unsigned int old_door_state;
1931 #if defined(PLATFORM_UNIX)
1932 /* pause network game while waiting for request to answer */
1933 if (options.network &&
1934 game_status == PLAYING &&
1935 req_state & REQUEST_WAIT_FOR)
1936 SendToServer_PausePlaying();
1939 old_door_state = GetDoorState();
1943 CloseDoor(DOOR_CLOSE_1);
1945 /* save old door content */
1946 BlitBitmap(bitmap_db_door, bitmap_db_door,
1947 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1948 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1950 /* clear door drawing field */
1951 ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1953 /* write text for request */
1954 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1956 char text_line[MAX_REQUEST_LINE_LEN + 1];
1962 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1965 if (!tc || tc == ' ')
1976 strncpy(text_line, text, tl);
1979 DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1980 text_line, FS_SMALL, FC_YELLOW);
1982 text += tl + (tc == ' ' ? 1 : 0);
1985 if (req_state & REQ_ASK)
1987 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1988 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1990 else if (req_state & REQ_CONFIRM)
1992 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1994 else if (req_state & REQ_PLAYER)
1996 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1997 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1998 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1999 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2002 /* copy request gadgets to door backbuffer */
2003 BlitBitmap(drawto, bitmap_db_door,
2004 DX, DY, DXSIZE, DYSIZE,
2005 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2007 OpenDoor(DOOR_OPEN_1);
2013 if (!(req_state & REQUEST_WAIT_FOR))
2016 if (game_status != MAINMENU)
2019 button_status = MB_RELEASED;
2021 request_gadget_id = -1;
2033 case EVENT_BUTTONPRESS:
2034 case EVENT_BUTTONRELEASE:
2035 case EVENT_MOTIONNOTIFY:
2037 if (event.type == EVENT_MOTIONNOTIFY)
2039 if (!PointerInWindow(window))
2040 continue; /* window and pointer are on different screens */
2045 motion_status = TRUE;
2046 mx = ((MotionEvent *) &event)->x;
2047 my = ((MotionEvent *) &event)->y;
2051 motion_status = FALSE;
2052 mx = ((ButtonEvent *) &event)->x;
2053 my = ((ButtonEvent *) &event)->y;
2054 if (event.type == EVENT_BUTTONPRESS)
2055 button_status = ((ButtonEvent *) &event)->button;
2057 button_status = MB_RELEASED;
2060 /* this sets 'request_gadget_id' */
2061 HandleGadgets(mx, my, button_status);
2063 switch(request_gadget_id)
2065 case TOOL_CTRL_ID_YES:
2068 case TOOL_CTRL_ID_NO:
2071 case TOOL_CTRL_ID_CONFIRM:
2072 result = TRUE | FALSE;
2075 case TOOL_CTRL_ID_PLAYER_1:
2078 case TOOL_CTRL_ID_PLAYER_2:
2081 case TOOL_CTRL_ID_PLAYER_3:
2084 case TOOL_CTRL_ID_PLAYER_4:
2095 case EVENT_KEYPRESS:
2096 switch(GetEventKey((KeyEvent *)&event, TRUE))
2109 if (req_state & REQ_PLAYER)
2113 case EVENT_KEYRELEASE:
2114 ClearPlayerAction();
2118 HandleOtherEvents(&event);
2122 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2124 int joy = AnyJoystick();
2126 if (joy & JOY_BUTTON_1)
2128 else if (joy & JOY_BUTTON_2)
2134 /* don't eat all CPU time */
2138 if (game_status != MAINMENU)
2143 if (!(req_state & REQ_STAY_OPEN))
2145 CloseDoor(DOOR_CLOSE_1);
2147 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2149 BlitBitmap(bitmap_db_door, bitmap_db_door,
2150 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2151 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2152 OpenDoor(DOOR_OPEN_1);
2158 #if defined(PLATFORM_UNIX)
2159 /* continue network game after request */
2160 if (options.network &&
2161 game_status == PLAYING &&
2162 req_state & REQUEST_WAIT_FOR)
2163 SendToServer_ContinuePlaying();
2169 unsigned int OpenDoor(unsigned int door_state)
2171 unsigned int new_door_state;
2173 if (door_state & DOOR_COPY_BACK)
2175 BlitBitmap(bitmap_db_door, bitmap_db_door,
2176 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2177 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2178 door_state &= ~DOOR_COPY_BACK;
2181 new_door_state = MoveDoor(door_state);
2183 return(new_door_state);
2186 unsigned int CloseDoor(unsigned int door_state)
2188 unsigned int new_door_state;
2190 BlitBitmap(backbuffer, bitmap_db_door,
2191 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2192 BlitBitmap(backbuffer, bitmap_db_door,
2193 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2195 new_door_state = MoveDoor(door_state);
2197 return(new_door_state);
2200 unsigned int GetDoorState()
2202 return MoveDoor(DOOR_GET_STATE);
2205 unsigned int SetDoorState(unsigned int door_state)
2207 return MoveDoor(door_state | DOOR_SET_STATE);
2210 unsigned int MoveDoor(unsigned int door_state)
2212 static int door1 = DOOR_OPEN_1;
2213 static int door2 = DOOR_CLOSE_2;
2214 static unsigned long door_delay = 0;
2215 int x, start, stepsize = 2;
2216 unsigned long door_delay_value = stepsize * 5;
2218 if (door_state == DOOR_GET_STATE)
2219 return(door1 | door2);
2221 if (door_state & DOOR_SET_STATE)
2223 if (door_state & DOOR_ACTION_1)
2224 door1 = door_state & DOOR_ACTION_1;
2225 if (door_state & DOOR_ACTION_2)
2226 door2 = door_state & DOOR_ACTION_2;
2228 return(door1 | door2);
2231 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2232 door_state &= ~DOOR_OPEN_1;
2233 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2234 door_state &= ~DOOR_CLOSE_1;
2235 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2236 door_state &= ~DOOR_OPEN_2;
2237 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2238 door_state &= ~DOOR_CLOSE_2;
2240 if (setup.quick_doors)
2243 door_delay_value = 0;
2244 StopSound(SND_MENU_DOOR_OPENING);
2245 StopSound(SND_MENU_DOOR_CLOSING);
2248 if (door_state & DOOR_ACTION)
2250 if (!(door_state & DOOR_NO_DELAY))
2252 /* opening door sound has priority over simultaneously closing door */
2253 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2254 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2255 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2256 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2259 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2261 for(x=start; x<=DXSIZE; x+=stepsize)
2263 Bitmap *bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
2264 GC gc = bitmap->stored_clip_gc;
2266 WaitUntilDelayReached(&door_delay, door_delay_value);
2268 if (door_state & DOOR_ACTION_1)
2270 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2271 int j = (DXSIZE - i) / 3;
2273 BlitBitmap(bitmap_db_door, drawto,
2274 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2275 DXSIZE,DYSIZE - i/2, DX, DY);
2277 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2279 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2280 BlitBitmapMasked(bitmap, drawto,
2281 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2282 DX + DXSIZE - i, DY + j);
2283 BlitBitmapMasked(bitmap, drawto,
2284 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2285 DX + DXSIZE - i, DY + 140 + j);
2286 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2287 BlitBitmapMasked(bitmap, drawto,
2288 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2290 BlitBitmapMasked(bitmap, drawto,
2291 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2294 BlitBitmapMasked(bitmap, drawto,
2295 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2297 BlitBitmapMasked(bitmap, drawto,
2298 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2300 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2301 BlitBitmapMasked(bitmap, drawto,
2302 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2303 DX + DXSIZE - i, DY + 77 + j);
2304 BlitBitmapMasked(bitmap, drawto,
2305 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2306 DX + DXSIZE - i, DY + 203 + j);
2308 redraw_mask |= REDRAW_DOOR_1;
2311 if (door_state & DOOR_ACTION_2)
2313 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2314 int j = (VXSIZE - i) / 3;
2316 BlitBitmap(bitmap_db_door, drawto,
2317 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2318 VXSIZE, VYSIZE - i/2, VX, VY);
2320 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2322 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2323 BlitBitmapMasked(bitmap, drawto,
2324 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2325 VX + VXSIZE-i, VY+j);
2326 SetClipOrigin(bitmap, gc,
2327 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2328 BlitBitmapMasked(bitmap, drawto,
2329 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2332 BlitBitmapMasked(bitmap, drawto,
2333 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2334 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2335 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2336 BlitBitmapMasked(bitmap, drawto,
2337 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2339 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2341 redraw_mask |= REDRAW_DOOR_2;
2346 if (game_status == MAINMENU)
2351 if (setup.quick_doors)
2353 StopSound(SND_MENU_DOOR_OPENING);
2354 StopSound(SND_MENU_DOOR_CLOSING);
2357 if (door_state & DOOR_ACTION_1)
2358 door1 = door_state & DOOR_ACTION_1;
2359 if (door_state & DOOR_ACTION_2)
2360 door2 = door_state & DOOR_ACTION_2;
2362 return (door1 | door2);
2365 void DrawSpecialEditorDoor()
2367 /* draw bigger toolbox window */
2368 BlitBitmap(new_graphic_info[IMG_MENU_DOOR].bitmap, drawto,
2369 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2371 redraw_mask |= REDRAW_ALL;
2374 void UndrawSpecialEditorDoor()
2376 /* draw normal tape recorder window */
2377 BlitBitmap(new_graphic_info[IMG_MENU_BACK].bitmap, drawto,
2378 562, 344, 108, 56, EX - 4, EY - 12);
2380 redraw_mask |= REDRAW_ALL;
2384 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2386 XImage *pixel_image;
2387 unsigned long pixel_value;
2389 pixel_image = XGetImage(display, bitmap->drawable,
2390 x, y, 1, 1, AllPlanes, ZPixmap);
2391 pixel_value = XGetPixel(pixel_image, 0, 0);
2393 XDestroyImage(pixel_image);
2399 /* ---------- new tool button stuff ---------------------------------------- */
2401 /* graphic position values for tool buttons */
2402 #define TOOL_BUTTON_YES_XPOS 2
2403 #define TOOL_BUTTON_YES_YPOS 250
2404 #define TOOL_BUTTON_YES_GFX_YPOS 0
2405 #define TOOL_BUTTON_YES_XSIZE 46
2406 #define TOOL_BUTTON_YES_YSIZE 28
2407 #define TOOL_BUTTON_NO_XPOS 52
2408 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2409 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2410 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2411 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2412 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2413 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2414 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2415 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2416 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2417 #define TOOL_BUTTON_PLAYER_XSIZE 30
2418 #define TOOL_BUTTON_PLAYER_YSIZE 30
2419 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2420 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2421 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2422 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2423 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2424 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2425 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2426 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2427 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2428 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2429 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2430 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2431 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2432 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2433 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2434 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2435 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2436 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2437 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2438 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2447 } toolbutton_info[NUM_TOOL_BUTTONS] =
2450 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2451 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2452 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2457 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2458 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2459 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2464 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2465 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2466 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2467 TOOL_CTRL_ID_CONFIRM,
2471 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2472 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2473 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2474 TOOL_CTRL_ID_PLAYER_1,
2478 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2479 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2480 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2481 TOOL_CTRL_ID_PLAYER_2,
2485 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2486 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2487 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2488 TOOL_CTRL_ID_PLAYER_3,
2492 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2493 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2494 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2495 TOOL_CTRL_ID_PLAYER_4,
2500 void CreateToolButtons()
2504 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2506 Bitmap *gd_bitmap = new_graphic_info[IMG_MENU_DOOR].bitmap;
2507 Bitmap *deco_bitmap = None;
2508 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2509 struct GadgetInfo *gi;
2510 unsigned long event_mask;
2511 int gd_xoffset, gd_yoffset;
2512 int gd_x1, gd_x2, gd_y;
2515 event_mask = GD_EVENT_RELEASED;
2517 gd_xoffset = toolbutton_info[i].xpos;
2518 gd_yoffset = toolbutton_info[i].ypos;
2519 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2520 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2521 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2523 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2525 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2527 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2528 &deco_bitmap, &deco_x, &deco_y);
2529 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2530 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2533 gi = CreateGadget(GDI_CUSTOM_ID, id,
2534 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2535 GDI_X, DX + toolbutton_info[i].x,
2536 GDI_Y, DY + toolbutton_info[i].y,
2537 GDI_WIDTH, toolbutton_info[i].width,
2538 GDI_HEIGHT, toolbutton_info[i].height,
2539 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2540 GDI_STATE, GD_BUTTON_UNPRESSED,
2541 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2542 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2543 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2544 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2545 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2546 GDI_DECORATION_SHIFTING, 1, 1,
2547 GDI_EVENT_MASK, event_mask,
2548 GDI_CALLBACK_ACTION, HandleToolButtons,
2552 Error(ERR_EXIT, "cannot create gadget");
2554 tool_gadget[id] = gi;
2558 static void UnmapToolButtons()
2562 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2563 UnmapGadget(tool_gadget[i]);
2566 static void HandleToolButtons(struct GadgetInfo *gi)
2568 request_gadget_id = gi->custom_id;
2571 int get_next_element(int element)
2575 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2576 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2577 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2578 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2579 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2580 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2581 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2583 default: return element;
2587 int el2gfx_OLD(int element)
2591 case EL_EMPTY: return -1;
2592 case EL_SAND: return GFX_ERDREICH;
2593 case EL_WALL: return GFX_MAUERWERK;
2594 case EL_WALL_CRUMBLED: return GFX_FELSBODEN;
2595 case EL_ROCK: return GFX_FELSBROCKEN;
2596 case EL_EMERALD: return GFX_EDELSTEIN;
2597 case EL_EXIT_CLOSED: return GFX_AUSGANG_ZU;
2598 case EL_EXIT_OPENING: return GFX_AUSGANG_ACT;
2599 case EL_EXIT_OPEN: return GFX_AUSGANG_AUF;
2600 case EL_SP_EXIT_OPEN: return GFX_SP_EXIT;
2601 case EL_PLAYER1: return GFX_SPIELER1;
2602 case EL_PLAYER2: return GFX_SPIELER2;
2603 case EL_PLAYER3: return GFX_SPIELER3;
2604 case EL_PLAYER4: return GFX_SPIELER4;
2605 case EL_BUG: return GFX_KAEFER;
2606 case EL_BUG_RIGHT: return GFX_KAEFER_RIGHT;
2607 case EL_BUG_UP: return GFX_KAEFER_UP;
2608 case EL_BUG_LEFT: return GFX_KAEFER_LEFT;
2609 case EL_BUG_DOWN: return GFX_KAEFER_DOWN;
2610 case EL_SPACESHIP: return GFX_FLIEGER;
2611 case EL_SPACESHIP_RIGHT: return GFX_FLIEGER_RIGHT;
2612 case EL_SPACESHIP_UP: return GFX_FLIEGER_UP;
2613 case EL_SPACESHIP_LEFT: return GFX_FLIEGER_LEFT;
2614 case EL_SPACESHIP_DOWN: return GFX_FLIEGER_DOWN;
2615 case EL_BD_BUTTERFLY: return GFX_BUTTERFLY;
2616 case EL_BD_BUTTERFLY_RIGHT: return GFX_BUTTERFLY_RIGHT;
2617 case EL_BD_BUTTERFLY_UP: return GFX_BUTTERFLY_UP;
2618 case EL_BD_BUTTERFLY_LEFT: return GFX_BUTTERFLY_LEFT;
2619 case EL_BD_BUTTERFLY_DOWN: return GFX_BUTTERFLY_DOWN;
2620 case EL_BD_FIREFLY: return GFX_FIREFLY;
2621 case EL_BD_FIREFLY_RIGHT: return GFX_FIREFLY_RIGHT;
2622 case EL_BD_FIREFLY_UP: return GFX_FIREFLY_UP;
2623 case EL_BD_FIREFLY_LEFT: return GFX_FIREFLY_LEFT;
2624 case EL_BD_FIREFLY_DOWN: return GFX_FIREFLY_DOWN;
2625 case EL_YAMYAM: return GFX_MAMPFER;
2626 case EL_ROBOT: return GFX_ROBOT;
2627 case EL_STEELWALL: return GFX_BETON;
2628 case EL_DIAMOND: return GFX_DIAMANT;
2629 case EL_QUICKSAND_EMPTY: return GFX_MORAST_LEER;
2630 case EL_QUICKSAND_FULL: return GFX_MORAST_VOLL;
2631 case EL_QUICKSAND_EMPTYING: return GFX_MORAST_LEER;
2632 case EL_AMOEBA_DROP: return GFX_TROPFEN;
2633 case EL_BOMB: return GFX_BOMBE;
2634 case EL_MAGIC_WALL: return GFX_MAGIC_WALL_OFF;
2635 case EL_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_EMPTY;
2636 case EL_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_EMPTY;
2637 case EL_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_FULL;
2638 case EL_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_DEAD;
2639 case EL_ACID: return GFX_SALZSAEURE;
2640 case EL_AMOEBA_DEAD: return GFX_AMOEBE_TOT;
2641 case EL_AMOEBA_WET: return GFX_AMOEBE_NASS;
2642 case EL_AMOEBA_DRY: return GFX_AMOEBE_NORM;
2643 case EL_AMOEBA_FULL: return GFX_AMOEBE_VOLL;
2644 case EL_BD_AMOEBA: return GFX_AMOEBE_BD;
2645 case EL_AMOEBA_TO_DIAMOND: return GFX_AMOEBA2DIAM;
2646 case EL_AMOEBA_DRIPPING: return GFX_AMOEBE_NASS;
2647 case EL_NUT: return GFX_KOKOSNUSS;
2648 case EL_GAMEOFLIFE: return GFX_LIFE;
2649 case EL_BIOMAZE: return GFX_LIFE_ASYNC;
2650 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2651 case EL_STONEBLOCK: return GFX_BADEWANNE;
2652 case EL_ACIDPOOL_TOPLEFT: return GFX_BADEWANNE1;
2653 case EL_ACIDPOOL_TOPRIGHT: return GFX_BADEWANNE2;
2654 case EL_ACIDPOOL_BOTTOMLEFT: return GFX_BADEWANNE3;
2655 case EL_ACIDPOOL_BOTTOM: return GFX_BADEWANNE4;
2656 case EL_ACIDPOOL_BOTTOMRIGHT: return GFX_BADEWANNE5;
2657 case EL_ROBOT_WHEEL: return GFX_ABLENK_AUS;
2658 case EL_ROBOT_WHEEL_ACTIVE: return GFX_ABLENK_EIN;
2659 case EL_KEY1: return GFX_SCHLUESSEL1;
2660 case EL_KEY2: return GFX_SCHLUESSEL2;
2661 case EL_KEY3: return GFX_SCHLUESSEL3;
2662 case EL_KEY4: return GFX_SCHLUESSEL4;
2663 case EL_GATE1: return GFX_PFORTE1;
2664 case EL_GATE2: return GFX_PFORTE2;
2665 case EL_GATE3: return GFX_PFORTE3;
2666 case EL_GATE4: return GFX_PFORTE4;
2667 case EL_GATE1_GRAY: return GFX_PFORTE1X;
2668 case EL_GATE2_GRAY: return GFX_PFORTE2X;
2669 case EL_GATE3_GRAY: return GFX_PFORTE3X;
2670 case EL_GATE4_GRAY: return GFX_PFORTE4X;
2671 case EL_DYNAMITE: return GFX_DYNAMIT_AUS;
2672 case EL_PACMAN: return GFX_PACMAN;
2673 case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT;
2674 case EL_PACMAN_UP: return GFX_PACMAN_UP;
2675 case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT;
2676 case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN;
2677 case EL_INVISIBLE_WALL: return GFX_UNSICHTBAR;
2678 case EL_INVISIBLE_WALL_ACTIVE: return GFX_UNSICHTBAR_ON;
2679 case EL_WALL_EMERALD: return GFX_ERZ_EDEL;
2680 case EL_WALL_DIAMOND: return GFX_ERZ_DIAM;
2681 case EL_LAMP: return GFX_BIRNE_AUS;
2682 case EL_LAMP_ACTIVE: return GFX_BIRNE_EIN;
2683 case EL_TIME_ORB_FULL: return GFX_ZEIT_VOLL;
2684 case EL_TIME_ORB_EMPTY: return GFX_ZEIT_LEER;
2685 case EL_WALL_GROWING: return GFX_MAUER_LEBT;
2686 case EL_WALL_GROWING_X: return GFX_MAUER_X;
2687 case EL_WALL_GROWING_Y: return GFX_MAUER_Y;
2688 case EL_WALL_GROWING_XY: return GFX_MAUER_XY;
2689 case EL_BD_DIAMOND: return GFX_EDELSTEIN_BD;
2690 case EL_EMERALD_YELLOW: return GFX_EDELSTEIN_GELB;
2691 case EL_EMERALD_RED: return GFX_EDELSTEIN_ROT;
2692 case EL_EMERALD_PURPLE: return GFX_EDELSTEIN_LILA;
2693 case EL_WALL_BD_DIAMOND: return GFX_ERZ_EDEL_BD;
2694 case EL_WALL_EMERALD_YELLOW: return GFX_ERZ_EDEL_GELB;
2695 case EL_WALL_EMERALD_RED: return GFX_ERZ_EDEL_ROT;
2696 case EL_WALL_EMERALD_PURPLE: return GFX_ERZ_EDEL_LILA;
2697 case EL_DARK_YAMYAM: return GFX_MAMPFER2;
2698 case EL_BD_MAGIC_WALL: return GFX_MAGIC_WALL_BD_OFF;
2699 case EL_BD_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_BD_EMPTY;
2700 case EL_BD_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_BD_EMPTY;
2701 case EL_BD_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_BD_FULL;
2702 case EL_BD_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2703 case EL_DYNABOMB_PLAYER1_ACTIVE: return GFX_DYNABOMB;
2704 case EL_DYNABOMB_PLAYER2_ACTIVE: return GFX_DYNABOMB;
2705 case EL_DYNABOMB_PLAYER3_ACTIVE: return GFX_DYNABOMB;
2706 case EL_DYNABOMB_PLAYER4_ACTIVE: return GFX_DYNABOMB;
2707 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2708 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2709 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2710 case EL_SOKOBAN_OBJECT: return GFX_SOKOBAN_OBJEKT;
2711 case EL_SOKOBAN_FIELD_EMPTY: return GFX_SOKOBAN_FELD_LEER;
2712 case EL_SOKOBAN_FIELD_FULL: return GFX_SOKOBAN_FELD_VOLL;
2713 case EL_MOLE: return GFX_MOLE;
2714 case EL_PENGUIN: return GFX_PINGUIN;
2715 case EL_PIG: return GFX_SCHWEIN;
2716 case EL_DRAGON: return GFX_DRACHE;
2717 case EL_SATELLITE: return GFX_SONDE;
2718 case EL_ARROW_BLUE_LEFT: return GFX_PFEIL_LEFT;
2719 case EL_ARROW_BLUE_RIGHT: return GFX_PFEIL_RIGHT;
2720 case EL_ARROW_BLUE_UP: return GFX_PFEIL_UP;
2721 case EL_ARROW_BLUE_DOWN: return GFX_PFEIL_DOWN;
2722 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2723 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2724 case EL_SP_BUGGY_BASE_ACTIVE: return GFX_SP_BUG_ACTIVE;
2725 case EL_SP_ZONK: return GFX_SP_ZONK;
2726 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2727 case EL_INVISIBLE_STEELWALL: return GFX_INVISIBLE_STEEL;
2728 case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2729 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2730 case EL_EM_GATE1: return GFX_EM_GATE_1;
2731 case EL_EM_GATE2: return GFX_EM_GATE_2;
2732 case EL_EM_GATE3: return GFX_EM_GATE_3;
2733 case EL_EM_GATE4: return GFX_EM_GATE_4;
2734 case EL_EM_GATE1_GRAY: return GFX_EM_GATE_1X;
2735 case EL_EM_GATE2_GRAY: return GFX_EM_GATE_2X;
2736 case EL_EM_GATE3_GRAY: return GFX_EM_GATE_3X;
2737 case EL_EM_GATE4_GRAY: return GFX_EM_GATE_4X;
2738 case EL_EM_KEY1_FILE: return GFX_EM_KEY_1;
2739 case EL_EM_KEY2_FILE: return GFX_EM_KEY_2;
2740 case EL_EM_KEY3_FILE: return GFX_EM_KEY_3;
2741 case EL_EM_KEY4_FILE: return GFX_EM_KEY_4;
2742 case EL_EM_KEY1: return GFX_EM_KEY_1;
2743 case EL_EM_KEY2: return GFX_EM_KEY_2;
2744 case EL_EM_KEY3: return GFX_EM_KEY_3;
2745 case EL_EM_KEY4: return GFX_EM_KEY_4;
2746 case EL_PEARL: return GFX_PEARL;
2747 case EL_CRYSTAL: return GFX_CRYSTAL;
2748 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2749 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2750 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2751 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2752 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2753 case EL_SHIELD_NORMAL: return GFX_SHIELD_PASSIVE;
2754 case EL_SHIELD_DEADLY: return GFX_SHIELD_ACTIVE;
2755 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2756 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2757 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2758 case EL_SWITCHGATE_SWITCH_UP: return GFX_SWITCHGATE_SWITCH_1;
2759 case EL_SWITCHGATE_SWITCH_DOWN: return GFX_SWITCHGATE_SWITCH_2;
2760 case EL_CONVEYOR_BELT1_LEFT: return GFX_BELT1_LEFT;
2761 case EL_CONVEYOR_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2762 case EL_CONVEYOR_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2763 case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2764 case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2765 case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2766 case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2767 case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2768 case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2769 case EL_CONVEYOR_BELT2_LEFT: return GFX_BELT2_LEFT;
2770 case EL_CONVEYOR_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2771 case EL_CONVEYOR_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2772 case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2773 case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2774 case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2775 case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2776 case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2777 case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2778 case EL_CONVEYOR_BELT3_LEFT: return GFX_BELT3_LEFT;
2779 case EL_CONVEYOR_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2780 case EL_CONVEYOR_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2781 case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2782 case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2783 case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2784 case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2785 case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2786 case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2787 case EL_CONVEYOR_BELT4_LEFT: return GFX_BELT4_LEFT;
2788 case EL_CONVEYOR_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2789 case EL_CONVEYOR_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2790 case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2791 case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2792 case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2793 case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2794 case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2795 case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2796 case EL_LANDMINE: return GFX_LANDMINE;
2797 case EL_ENVELOPE: return GFX_ENVELOPE;
2798 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH_OFF;
2799 case EL_LIGHT_SWITCH_ACTIVE: return GFX_LIGHT_SWITCH_ON;
2800 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2801 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2802 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2803 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2804 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2805 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2806 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2807 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2808 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2809 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2810 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2811 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2812 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2813 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2814 case EL_MOLE_UP: return GFX_MOLE_UP;
2815 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2816 case EL_STEELWALL_SLANTED: return GFX_STEEL_SLANTED;
2817 case EL_INVISIBLE_SAND: return GFX_SAND_INVISIBLE;
2818 case EL_INVISIBLE_SAND_ACTIVE: return GFX_SAND_INVISIBLE_ON;
2819 case EL_DX_UNKNOWN_15: return GFX_DX_UNKNOWN_15;
2820 case EL_DX_UNKNOWN_42: return GFX_DX_UNKNOWN_42;
2821 case EL_TIMEGATE_OPEN: return GFX_TIMEGATE_OPEN;
2822 case EL_TIMEGATE_CLOSED: return GFX_TIMEGATE_CLOSED;
2823 case EL_TIMEGATE_SWITCH_ACTIVE: return GFX_TIMEGATE_SWITCH;
2824 case EL_TIMEGATE_SWITCH: return GFX_TIMEGATE_SWITCH;
2825 case EL_BALLOON: return GFX_BALLOON;
2826 case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
2827 case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2828 case EL_BALLOON_SEND_UP: return GFX_BALLOON_SEND_UP;
2829 case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
2830 case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2831 case EL_EMC_STEELWALL1: return GFX_EMC_STEEL_WALL_1;
2832 case EL_EMC_STEELWALL2: return GFX_EMC_STEEL_WALL_2;
2833 case EL_EMC_STEELWALL3: return GFX_EMC_STEEL_WALL_3;
2834 case EL_EMC_STEELWALL4: return GFX_EMC_STEEL_WALL_4;
2835 case EL_EMC_WALL_PILLAR_UPPER: return GFX_EMC_WALL_1;
2836 case EL_EMC_WALL_PILLAR_MIDDLE: return GFX_EMC_WALL_2;
2837 case EL_EMC_WALL_PILLAR_LOWER: return GFX_EMC_WALL_3;
2838 case EL_EMC_WALL4: return GFX_EMC_WALL_4;
2839 case EL_EMC_WALL5: return GFX_EMC_WALL_5;
2840 case EL_EMC_WALL6: return GFX_EMC_WALL_6;
2841 case EL_EMC_WALL7: return GFX_EMC_WALL_7;
2842 case EL_EMC_WALL8: return GFX_EMC_WALL_8;
2843 case EL_TUBE_ALL: return GFX_TUBE_CROSS;
2844 case EL_TUBE_VERTICAL: return GFX_TUBE_VERTICAL;
2845 case EL_TUBE_HORIZONTAL: return GFX_TUBE_HORIZONTAL;
2846 case EL_TUBE_VERTICAL_LEFT: return GFX_TUBE_VERT_LEFT;
2847 case EL_TUBE_VERTICAL_RIGHT: return GFX_TUBE_VERT_RIGHT;
2848 case EL_TUBE_HORIZONTAL_UP: return GFX_TUBE_HORIZ_UP;
2849 case EL_TUBE_HORIZONTAL_DOWN: return GFX_TUBE_HORIZ_DOWN;
2850 case EL_TUBE_LEFT_UP: return GFX_TUBE_LEFT_UP;
2851 case EL_TUBE_LEFT_DOWN: return GFX_TUBE_LEFT_DOWN;
2852 case EL_TUBE_RIGHT_UP: return GFX_TUBE_RIGHT_UP;
2853 case EL_TUBE_RIGHT_DOWN: return GFX_TUBE_RIGHT_DOWN;
2854 case EL_SPRING: return GFX_SPRING;
2855 case EL_TRAP: return GFX_TRAP_INACTIVE;
2856 case EL_TRAP_ACTIVE: return GFX_TRAP_ACTIVE;
2857 case EL_BD_WALL: return GFX_BD_WALL;
2858 case EL_BD_ROCK: return GFX_BD_ROCK;
2859 case EL_DX_SUPABOMB: return GFX_DX_SUPABOMB;
2860 case EL_SP_MURPHY_CLONE: return GFX_SP_MURPHY_CLONE;
2864 if (IS_CHAR(element))
2865 return GFX_CHAR_START + (element - EL_CHAR_START);
2866 else if (element >= EL_SP_START && element <= EL_SP_END)
2868 int nr_element = element - EL_SP_START;
2869 int gfx_per_line = 8;
2871 (nr_element / gfx_per_line) * SP_PER_LINE +
2872 (nr_element % gfx_per_line);
2874 return GFX_START_ROCKSSP + nr_graphic;
2882 int el2gfx(int element)
2885 int graphic_OLD = el2gfx_OLD(element);
2890 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2893 int graphic_OLD = el2gfx_OLD(element);
2895 if (element >= MAX_ELEMENTS)
2897 Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
2900 if (graphic_NEW != graphic_OLD)
2902 Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2903 graphic_NEW, graphic_OLD);
2911 int el2img(int element)
2913 int graphic = element_info[element].graphic[GFX_ACTION_DEFAULT];
2917 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2924 int el_dir2img(int element, int direction)
2926 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2929 int el_dir_act2img(int element, int direction, int action)
2931 action = graphics_action_mapping[action];
2932 direction = MV_DIR_BIT(direction);
2934 return element_info[element].direction_graphic[action][direction];