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)
806 if (IN_SCR_FIELD(x, y))
808 int frame = getGraphicAnimationFrame(graphic, -1);
810 if (mask_mode == USE_MASKING)
811 DrawGraphicThruMask(x, y, graphic, frame);
813 DrawGraphic(x, y, graphic, frame);
817 void DrawGraphicAnimation(int x, int y, int graphic)
819 DrawGraphicAnimationExt(x, y, graphic, NO_MASKING);
823 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
825 if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
827 *bitmap = graphic_info[graphic].bitmap;
828 *x = graphic_info[graphic].src_x;
829 *y = graphic_info[graphic].src_y;
831 else if (graphic >= GFX_START_ROCKSELEMENTS &&
832 graphic <= GFX_END_ROCKSELEMENTS)
834 graphic -= GFX_START_ROCKSELEMENTS;
835 *bitmap = new_graphic_info[IMG_OLD_PIX_ELEMENTS].bitmap;
836 *x = (graphic % GFX_PER_LINE) * TILEX;
837 *y = (graphic / GFX_PER_LINE) * TILEY;
839 else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
841 graphic -= GFX_START_ROCKSHEROES;
842 *bitmap = new_graphic_info[IMG_OLD_PIX_HEROES].bitmap;
843 *x = (graphic % HEROES_PER_LINE) * TILEX;
844 *y = (graphic / HEROES_PER_LINE) * TILEY;
846 else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
848 graphic -= GFX_START_ROCKSSP;
849 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
850 *x = (graphic % SP_PER_LINE) * TILEX;
851 *y = (graphic / SP_PER_LINE) * TILEY;
853 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
855 graphic -= GFX_START_ROCKSDC;
856 *bitmap = new_graphic_info[IMG_OLD_PIX_DC].bitmap;
857 *x = (graphic % DC_PER_LINE) * TILEX;
858 *y = (graphic / DC_PER_LINE) * TILEY;
860 else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
862 graphic -= GFX_START_ROCKSMORE;
863 *bitmap = new_graphic_info[IMG_OLD_PIX_MORE].bitmap;
864 *x = (graphic % MORE_PER_LINE) * TILEX;
865 *y = (graphic / MORE_PER_LINE) * TILEY;
867 else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
869 graphic -= GFX_START_ROCKSFONT;
870 *bitmap = new_graphic_info[IMG_OLD_PIX_FONT_EM].bitmap;
871 *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
872 *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
876 *bitmap = new_graphic_info[IMG_OLD_PIX_SP].bitmap;
883 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
885 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
886 int offset_x = new_graphic_info[graphic].offset_x;
887 int offset_y = new_graphic_info[graphic].offset_y;
888 int src_x = new_graphic_info[graphic].src_x + frame * offset_x;
889 int src_y = new_graphic_info[graphic].src_y + frame * offset_y;
891 *bitmap = src_bitmap;
896 void DrawGraphic(int x, int y, int graphic, int frame)
899 if (!IN_SCR_FIELD(x, y))
901 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
902 printf("DrawGraphic(): This should never happen!\n");
907 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);
922 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
929 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
931 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
932 int src_x = new_graphic_info[graphic].src_x;
933 int src_y = new_graphic_info[graphic].src_y;
934 int offset_x = new_graphic_info[graphic].offset_x;
935 int offset_y = new_graphic_info[graphic].offset_y;
937 src_x += frame * offset_x;
938 src_y += frame * offset_y;
941 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
944 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
947 if (!IN_SCR_FIELD(x, y))
949 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
950 printf("DrawGraphicThruMask(): This should never happen!\n");
955 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
960 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
968 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
969 drawing_gc = src_bitmap->stored_clip_gc;
971 GC drawing_gc = src_bitmap->stored_clip_gc;
972 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
973 int src_x = new_graphic_info[graphic].src_x;
974 int src_y = new_graphic_info[graphic].src_y;
975 int offset_x = new_graphic_info[graphic].offset_x;
976 int offset_y = new_graphic_info[graphic].offset_y;
978 src_x += frame * offset_x;
979 src_y += frame * offset_y;
983 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
984 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
987 void DrawMiniGraphic(int x, int y, int graphic)
989 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
990 MarkTileDirty(x / 2, y / 2);
993 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
995 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
997 int mini_starty = src_bitmap->height * 2 / 3;
998 int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
999 int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
1001 *bitmap = src_bitmap;
1006 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
1011 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1012 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
1015 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
1016 int cut_mode, int mask_mode)
1025 int width = TILEX, height = TILEY;
1031 DrawGraphic(x, y, graphic, frame);
1035 if (dx || dy) /* shifted graphic */
1037 if (x < BX1) /* object enters playfield from the left */
1044 else if (x > BX2) /* object enters playfield from the right */
1050 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1056 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1058 else if (dx) /* general horizontal movement */
1059 MarkTileDirty(x + SIGN(dx), y);
1061 if (y < BY1) /* object enters playfield from the top */
1063 if (cut_mode==CUT_BELOW) /* object completely above top border */
1071 else if (y > BY2) /* object enters playfield from the bottom */
1077 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1083 else if (dy > 0 && cut_mode == CUT_ABOVE)
1085 if (y == BY2) /* object completely above bottom border */
1091 MarkTileDirty(x, y + 1);
1092 } /* object leaves playfield to the bottom */
1093 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1095 else if (dy) /* general vertical movement */
1096 MarkTileDirty(x, y + SIGN(dy));
1099 src_bitmap = new_graphic_info[graphic].bitmap;
1100 src_x = new_graphic_info[graphic].src_x;
1101 src_y = new_graphic_info[graphic].src_y;
1102 offset_x = new_graphic_info[graphic].offset_x;
1103 offset_y = new_graphic_info[graphic].offset_y;
1105 drawing_gc = src_bitmap->stored_clip_gc;
1107 src_x += frame * offset_x;
1108 src_y += frame * offset_y;
1113 dest_x = FX + x * TILEX + dx;
1114 dest_y = FY + y * TILEY + dy;
1117 if (!IN_SCR_FIELD(x,y))
1119 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1120 printf("DrawGraphicShifted(): This should never happen!\n");
1125 if (mask_mode == USE_MASKING)
1127 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1128 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1132 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1138 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1139 int frame, int cut_mode)
1141 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1145 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1146 int cut_mode, int mask_mode)
1148 int ux = LEVELX(x), uy = LEVELY(y);
1149 int graphic = el2gfx(element);
1150 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1151 int phase4 = phase8 / 2;
1152 int phase2 = phase8 / 4;
1153 int dir = MovDir[ux][uy];
1155 if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1157 graphic += 1 * !phase2;
1161 else if (dir == MV_LEFT)
1163 else if (dir == MV_DOWN)
1166 else if (element == EL_SP_SNIKSNAK)
1169 graphic = GFX_SP_SNIKSNAK_LEFT;
1170 else if (dir == MV_RIGHT)
1171 graphic = GFX_SP_SNIKSNAK_RIGHT;
1172 else if (dir == MV_UP)
1173 graphic = GFX_SP_SNIKSNAK_UP;
1175 graphic = GFX_SP_SNIKSNAK_DOWN;
1177 graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1179 else if (element == EL_SP_ELECTRON)
1181 graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1183 else if (element == EL_MOLE || element == EL_PENGUIN ||
1184 element == EL_PIG || element == EL_DRAGON)
1187 graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1188 element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1189 element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1190 else if (dir == MV_RIGHT)
1191 graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1192 element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1193 element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1194 else if (dir == MV_UP)
1195 graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1196 element == EL_PENGUIN ? GFX_PINGUIN_UP :
1197 element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1199 graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1200 element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1201 element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1205 else if (element == EL_SATELLITE)
1207 graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1209 else if (element == EL_ACID)
1211 graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1213 else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1217 else if (element == EL_BALLOON)
1221 else if ((element == EL_ROCK ||
1222 element == EL_SP_ZONK ||
1223 element == EL_BD_ROCK ||
1224 element == EL_SP_INFOTRON ||
1228 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1230 if (element == EL_ROCK ||
1231 element == EL_SP_ZONK ||
1232 element == EL_BD_ROCK)
1235 graphic += (4 - phase4) % 4;
1236 else if (dir == MV_RIGHT)
1239 graphic += phase2 * 2;
1241 else if (element != EL_SP_INFOTRON)
1245 else if (element == EL_MAGIC_WALL_ACTIVE ||
1246 element == EL_MAGIC_WALL_EMPTYING ||
1247 element == EL_BD_MAGIC_WALL_ACTIVE ||
1248 element == EL_BD_MAGIC_WALL_EMPTYING ||
1249 element == EL_MAGIC_WALL_FULL ||
1250 element == EL_BD_MAGIC_WALL_FULL)
1252 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1254 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1256 graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1257 graphic += (x + 2 * y + 4) % 4;
1259 else if (element == EL_WALL_GROWING)
1261 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1263 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1264 links_massiv = TRUE;
1265 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1266 rechts_massiv = TRUE;
1268 if (links_massiv && rechts_massiv)
1269 graphic = GFX_MAUERWERK;
1270 else if (links_massiv)
1271 graphic = GFX_MAUER_R;
1272 else if (rechts_massiv)
1273 graphic = GFX_MAUER_L;
1276 else if ((element == EL_INVISIBLE_STEELWALL ||
1277 element == EL_INVISIBLE_WALL ||
1278 element == EL_INVISIBLE_SAND) && game.light_time_left)
1280 graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1281 element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1282 GFX_SAND_INVISIBLE_ON);
1287 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1288 else if (mask_mode == USE_MASKING)
1289 DrawGraphicThruMask(x, y, graphic);
1291 DrawGraphic(x, y, graphic);
1295 inline static int getFramePosition(int x, int y)
1297 int frame_pos = -1; /* default: global synchronization */
1299 int element = Feld[x][y];
1301 if (element == EL_QUICKSAND_FULL ||
1302 element == EL_MAGIC_WALL_FULL ||
1303 element == EL_BD_MAGIC_WALL_FULL)
1305 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1306 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1308 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1314 inline static int getGfxAction(int x, int y)
1316 int gfx_action = GFX_ACTION_DEFAULT;
1319 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1320 gfx_action = GfxAction[x][y];
1321 else if (IS_MOVING(x, y))
1322 gfx_action = GFX_ACTION_MOVING;
1324 gfx_action = GfxAction[x][y];
1330 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1331 int cut_mode, int mask_mode)
1333 int ux = LEVELX(x), uy = LEVELY(y);
1334 int move_dir = MovDir[ux][uy];
1335 int move_pos = getFramePosition(ux, uy);
1336 int gfx_action = getGfxAction(ux, uy);
1337 int graphic = el_dir_act2img(element, move_dir, gfx_action);
1338 int frame = getGraphicAnimationFrame(graphic, move_pos);
1340 if (element == EL_WALL_GROWING)
1342 boolean left_stopped = FALSE, right_stopped = FALSE;
1344 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1345 left_stopped = TRUE;
1346 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1347 right_stopped = TRUE;
1349 if (left_stopped && right_stopped)
1351 else if (left_stopped)
1353 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1354 frame = new_graphic_info[graphic].anim_frames - 1;
1356 else if (right_stopped)
1358 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1359 frame = new_graphic_info[graphic].anim_frames - 1;
1362 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1364 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1365 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1366 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1367 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1368 IMG_AMOEBA_DEAD_PART1);
1370 graphic += (x + 2 * y + 4) % 4;
1374 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1375 else if (mask_mode == USE_MASKING)
1376 DrawGraphicThruMask(x, y, graphic, frame);
1378 DrawGraphic(x, y, graphic, frame);
1381 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1382 int cut_mode, int mask_mode)
1384 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1385 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1386 cut_mode, mask_mode);
1389 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1392 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1395 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1398 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1402 void DrawOldScreenElementThruMask(int x, int y, int element)
1404 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1407 void DrawScreenElementThruMask(int x, int y, int element)
1409 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1413 void DrawLevelElementThruMask(int x, int y, int element)
1415 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1418 void DrawLevelFieldThruMask(int x, int y)
1420 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1423 void DrawCrumbledSand(int x, int y)
1427 int i, width, height, cx,cy;
1428 int ux = LEVELX(x), uy = LEVELY(y);
1429 int element, graphic;
1431 static int xy[4][2] =
1439 if (!IN_LEV_FIELD(ux, uy))
1442 element = Feld[ux][uy];
1444 if (element == EL_SAND ||
1445 element == EL_LANDMINE ||
1446 element == EL_TRAP ||
1447 element == EL_TRAP_ACTIVE)
1449 if (!IN_SCR_FIELD(x, y))
1452 graphic = IMG_SAND_CRUMBLED;
1454 src_bitmap = new_graphic_info[graphic].bitmap;
1455 src_x = new_graphic_info[graphic].src_x;
1456 src_y = new_graphic_info[graphic].src_y;
1462 uxx = ux + xy[i][0];
1463 uyy = uy + xy[i][1];
1464 if (!IN_LEV_FIELD(uxx, uyy))
1465 element = EL_STEELWALL;
1467 element = Feld[uxx][uyy];
1469 if (element == EL_SAND ||
1470 element == EL_LANDMINE ||
1471 element == EL_TRAP ||
1472 element == EL_TRAP_ACTIVE)
1475 if (i == 1 || i == 2)
1479 cx = (i == 2 ? TILEX - snip : 0);
1487 cy = (i == 3 ? TILEY - snip : 0);
1490 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1491 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1494 MarkTileDirty(x, y);
1498 graphic = IMG_SAND_CRUMBLED;
1500 src_bitmap = new_graphic_info[graphic].bitmap;
1501 src_x = new_graphic_info[graphic].src_x;
1502 src_y = new_graphic_info[graphic].src_y;
1506 int xx, yy, uxx, uyy;
1510 uxx = ux + xy[i][0];
1511 uyy = uy + xy[i][1];
1513 if (!IN_LEV_FIELD(uxx, uyy) ||
1514 (Feld[uxx][uyy] != EL_SAND &&
1515 Feld[uxx][uyy] != EL_LANDMINE &&
1516 Feld[uxx][uyy] != EL_TRAP &&
1517 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1518 !IN_SCR_FIELD(xx, yy))
1521 if (i == 1 || i == 2)
1525 cx = (i == 1 ? TILEX - snip : 0);
1533 cy = (i==0 ? TILEY-snip : 0);
1536 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1537 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1539 MarkTileDirty(xx, yy);
1544 void DrawScreenElement(int x, int y, int element)
1546 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1547 DrawCrumbledSand(x, y);
1550 void DrawLevelElement(int x, int y, int element)
1552 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1553 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1556 void DrawScreenField(int x, int y)
1558 int ux = LEVELX(x), uy = LEVELY(y);
1559 int element, content;
1561 if (!IN_LEV_FIELD(ux, uy))
1563 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1566 element = BorderElement;
1568 DrawScreenElement(x, y, element);
1572 element = Feld[ux][uy];
1573 content = Store[ux][uy];
1575 if (IS_MOVING(ux, uy))
1577 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1578 boolean cut_mode = NO_CUTTING;
1580 if (element == EL_QUICKSAND_EMPTYING ||
1581 element == EL_MAGIC_WALL_EMPTYING ||
1582 element == EL_BD_MAGIC_WALL_EMPTYING ||
1583 element == EL_AMOEBA_DRIPPING)
1584 cut_mode = CUT_ABOVE;
1585 else if (element == EL_QUICKSAND_FILLING ||
1586 element == EL_MAGIC_WALL_FILLING ||
1587 element == EL_BD_MAGIC_WALL_FILLING)
1588 cut_mode = CUT_BELOW;
1590 if (cut_mode == CUT_ABOVE)
1591 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1593 DrawScreenElement(x, y, EL_EMPTY);
1596 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1597 else if (cut_mode == NO_CUTTING)
1598 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1600 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1602 if (content == EL_ACID)
1603 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1605 else if (IS_BLOCKED(ux, uy))
1610 boolean cut_mode = NO_CUTTING;
1611 int element_old, content_old;
1613 Blocked2Moving(ux, uy, &oldx, &oldy);
1616 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1617 MovDir[oldx][oldy] == MV_RIGHT);
1619 element_old = Feld[oldx][oldy];
1620 content_old = Store[oldx][oldy];
1622 if (element_old == EL_QUICKSAND_EMPTYING ||
1623 element_old == EL_MAGIC_WALL_EMPTYING ||
1624 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1625 element_old == EL_AMOEBA_DRIPPING)
1626 cut_mode = CUT_ABOVE;
1628 DrawScreenElement(x, y, EL_EMPTY);
1631 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1633 else if (cut_mode == NO_CUTTING)
1634 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1637 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1640 else if (IS_DRAWABLE(element))
1641 DrawScreenElement(x, y, element);
1643 DrawScreenElement(x, y, EL_EMPTY);
1646 void DrawLevelField(int x, int y)
1648 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1649 DrawScreenField(SCREENX(x), SCREENY(y));
1650 else if (IS_MOVING(x, y))
1654 Moving2Blocked(x, y, &newx, &newy);
1655 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1656 DrawScreenField(SCREENX(newx), SCREENY(newy));
1658 else if (IS_BLOCKED(x, y))
1662 Blocked2Moving(x, y, &oldx, &oldy);
1663 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1664 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1668 void DrawMiniElement(int x, int y, int element)
1672 graphic = el2img(element);
1673 DrawMiniGraphic(x, y, graphic);
1676 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1678 int x = sx + scroll_x, y = sy + scroll_y;
1680 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1681 DrawMiniElement(sx, sy, EL_EMPTY);
1682 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1683 DrawMiniElement(sx, sy, Feld[x][y]);
1686 int steel_type, steel_position;
1689 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1690 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1691 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1692 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1693 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1694 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1697 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1698 steel_position = (x == -1 && y == -1 ? 0 :
1699 x == lev_fieldx && y == -1 ? 1 :
1700 x == -1 && y == lev_fieldy ? 2 :
1701 x == lev_fieldx && y == lev_fieldy ? 3 :
1702 x == -1 || x == lev_fieldx ? 4 :
1703 y == -1 || y == lev_fieldy ? 5 : -1);
1705 if (steel_position != -1)
1706 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1710 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1712 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1713 int mini_startx = src_bitmap->width * 3 / 4;
1714 int mini_starty = src_bitmap->height * 2 / 3;
1715 int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1716 int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1718 *bitmap = src_bitmap;
1723 void DrawMicroElement(int xpos, int ypos, int element)
1729 if (element == EL_EMPTY)
1732 graphic = el2img(element);
1734 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1735 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1745 for(x=BX1; x<=BX2; x++)
1746 for(y=BY1; y<=BY2; y++)
1747 DrawScreenField(x, y);
1749 redraw_mask |= REDRAW_FIELD;
1752 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1756 for(x=0; x<size_x; x++)
1757 for(y=0; y<size_y; y++)
1758 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1760 redraw_mask |= REDRAW_FIELD;
1763 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1767 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1769 if (lev_fieldx < STD_LEV_FIELDX)
1770 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1771 if (lev_fieldy < STD_LEV_FIELDY)
1772 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1774 xpos += MICRO_TILEX;
1775 ypos += MICRO_TILEY;
1777 for(x=-1; x<=STD_LEV_FIELDX; x++)
1779 for(y=-1; y<=STD_LEV_FIELDY; y++)
1781 int lx = from_x + x, ly = from_y + y;
1783 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1784 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1786 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1787 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1792 redraw_mask |= REDRAW_MICROLEVEL;
1795 #define MICROLABEL_EMPTY 0
1796 #define MICROLABEL_LEVEL_NAME 1
1797 #define MICROLABEL_CREATED_BY 2
1798 #define MICROLABEL_LEVEL_AUTHOR 3
1799 #define MICROLABEL_IMPORTED_FROM 4
1800 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1802 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1804 static void DrawMicroLevelLabelExt(int mode)
1806 char label_text[MAX_MICROLABEL_SIZE + 1];
1808 ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1810 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1811 mode == MICROLABEL_CREATED_BY ? "created by" :
1812 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1813 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1814 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1815 leveldir_current->imported_from : ""),
1816 MAX_MICROLABEL_SIZE);
1817 label_text[MAX_MICROLABEL_SIZE] = '\0';
1819 if (strlen(label_text) > 0)
1821 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1822 int lypos = MICROLABEL_YPOS;
1824 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1827 redraw_mask |= REDRAW_MICROLEVEL;
1830 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1832 static unsigned long scroll_delay = 0;
1833 static unsigned long label_delay = 0;
1834 static int from_x, from_y, scroll_direction;
1835 static int label_state, label_counter;
1839 from_x = from_y = 0;
1840 scroll_direction = MV_RIGHT;
1844 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1845 DrawMicroLevelLabelExt(label_state);
1847 /* initialize delay counters */
1848 DelayReached(&scroll_delay, 0);
1849 DelayReached(&label_delay, 0);
1854 /* scroll micro level, if needed */
1855 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1856 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1858 switch (scroll_direction)
1864 scroll_direction = MV_UP;
1868 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1871 scroll_direction = MV_DOWN;
1878 scroll_direction = MV_RIGHT;
1882 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1885 scroll_direction = MV_LEFT;
1892 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1895 /* redraw micro level label, if needed */
1896 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1897 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1898 strcmp(level.author, leveldir_current->name) != 0 &&
1899 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1901 int max_label_counter = 23;
1903 if (leveldir_current->imported_from != NULL)
1904 max_label_counter += 14;
1906 label_counter = (label_counter + 1) % max_label_counter;
1907 label_state = (label_counter >= 0 && label_counter <= 7 ?
1908 MICROLABEL_LEVEL_NAME :
1909 label_counter >= 9 && label_counter <= 12 ?
1910 MICROLABEL_CREATED_BY :
1911 label_counter >= 14 && label_counter <= 21 ?
1912 MICROLABEL_LEVEL_AUTHOR :
1913 label_counter >= 23 && label_counter <= 26 ?
1914 MICROLABEL_IMPORTED_FROM :
1915 label_counter >= 28 && label_counter <= 35 ?
1916 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1917 DrawMicroLevelLabelExt(label_state);
1921 int REQ_in_range(int x, int y)
1923 if (y > DY+249 && y < DY+278)
1925 if (x > DX+1 && x < DX+48)
1927 else if (x > DX+51 && x < DX+98)
1933 #define MAX_REQUEST_LINES 13
1934 #define MAX_REQUEST_LINE_LEN 7
1936 boolean Request(char *text, unsigned int req_state)
1938 int mx, my, ty, result = -1;
1939 unsigned int old_door_state;
1941 #if defined(PLATFORM_UNIX)
1942 /* pause network game while waiting for request to answer */
1943 if (options.network &&
1944 game_status == PLAYING &&
1945 req_state & REQUEST_WAIT_FOR)
1946 SendToServer_PausePlaying();
1949 old_door_state = GetDoorState();
1953 CloseDoor(DOOR_CLOSE_1);
1955 /* save old door content */
1956 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
1957 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1958 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1960 /* clear door drawing field */
1961 ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1963 /* write text for request */
1964 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1966 char text_line[MAX_REQUEST_LINE_LEN + 1];
1972 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1975 if (!tc || tc == ' ')
1986 strncpy(text_line, text, tl);
1989 DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1990 text_line, FS_SMALL, FC_YELLOW);
1992 text += tl + (tc == ' ' ? 1 : 0);
1995 if (req_state & REQ_ASK)
1997 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1998 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
2000 else if (req_state & REQ_CONFIRM)
2002 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
2004 else if (req_state & REQ_PLAYER)
2006 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2007 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2008 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2009 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2012 /* copy request gadgets to door backbuffer */
2013 BlitBitmap(drawto, pix[PIX_DB_DOOR],
2014 DX, DY, DXSIZE, DYSIZE,
2015 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2017 OpenDoor(DOOR_OPEN_1);
2023 if (!(req_state & REQUEST_WAIT_FOR))
2026 if (game_status != MAINMENU)
2029 button_status = MB_RELEASED;
2031 request_gadget_id = -1;
2043 case EVENT_BUTTONPRESS:
2044 case EVENT_BUTTONRELEASE:
2045 case EVENT_MOTIONNOTIFY:
2047 if (event.type == EVENT_MOTIONNOTIFY)
2049 if (!PointerInWindow(window))
2050 continue; /* window and pointer are on different screens */
2055 motion_status = TRUE;
2056 mx = ((MotionEvent *) &event)->x;
2057 my = ((MotionEvent *) &event)->y;
2061 motion_status = FALSE;
2062 mx = ((ButtonEvent *) &event)->x;
2063 my = ((ButtonEvent *) &event)->y;
2064 if (event.type == EVENT_BUTTONPRESS)
2065 button_status = ((ButtonEvent *) &event)->button;
2067 button_status = MB_RELEASED;
2070 /* this sets 'request_gadget_id' */
2071 HandleGadgets(mx, my, button_status);
2073 switch(request_gadget_id)
2075 case TOOL_CTRL_ID_YES:
2078 case TOOL_CTRL_ID_NO:
2081 case TOOL_CTRL_ID_CONFIRM:
2082 result = TRUE | FALSE;
2085 case TOOL_CTRL_ID_PLAYER_1:
2088 case TOOL_CTRL_ID_PLAYER_2:
2091 case TOOL_CTRL_ID_PLAYER_3:
2094 case TOOL_CTRL_ID_PLAYER_4:
2105 case EVENT_KEYPRESS:
2106 switch(GetEventKey((KeyEvent *)&event, TRUE))
2119 if (req_state & REQ_PLAYER)
2123 case EVENT_KEYRELEASE:
2124 ClearPlayerAction();
2128 HandleOtherEvents(&event);
2132 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2134 int joy = AnyJoystick();
2136 if (joy & JOY_BUTTON_1)
2138 else if (joy & JOY_BUTTON_2)
2144 /* don't eat all CPU time */
2148 if (game_status != MAINMENU)
2153 if (!(req_state & REQ_STAY_OPEN))
2155 CloseDoor(DOOR_CLOSE_1);
2157 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2159 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2160 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2161 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2162 OpenDoor(DOOR_OPEN_1);
2168 #if defined(PLATFORM_UNIX)
2169 /* continue network game after request */
2170 if (options.network &&
2171 game_status == PLAYING &&
2172 req_state & REQUEST_WAIT_FOR)
2173 SendToServer_ContinuePlaying();
2179 unsigned int OpenDoor(unsigned int door_state)
2181 unsigned int new_door_state;
2183 if (door_state & DOOR_COPY_BACK)
2185 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2186 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2187 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2188 door_state &= ~DOOR_COPY_BACK;
2191 new_door_state = MoveDoor(door_state);
2193 return(new_door_state);
2196 unsigned int CloseDoor(unsigned int door_state)
2198 unsigned int new_door_state;
2200 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2201 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2202 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2203 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2205 new_door_state = MoveDoor(door_state);
2207 return(new_door_state);
2210 unsigned int GetDoorState()
2212 return MoveDoor(DOOR_GET_STATE);
2215 unsigned int SetDoorState(unsigned int door_state)
2217 return MoveDoor(door_state | DOOR_SET_STATE);
2220 unsigned int MoveDoor(unsigned int door_state)
2222 static int door1 = DOOR_OPEN_1;
2223 static int door2 = DOOR_CLOSE_2;
2224 static unsigned long door_delay = 0;
2225 int x, start, stepsize = 2;
2226 unsigned long door_delay_value = stepsize * 5;
2228 if (door_state == DOOR_GET_STATE)
2229 return(door1 | door2);
2231 if (door_state & DOOR_SET_STATE)
2233 if (door_state & DOOR_ACTION_1)
2234 door1 = door_state & DOOR_ACTION_1;
2235 if (door_state & DOOR_ACTION_2)
2236 door2 = door_state & DOOR_ACTION_2;
2238 return(door1 | door2);
2241 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2242 door_state &= ~DOOR_OPEN_1;
2243 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2244 door_state &= ~DOOR_CLOSE_1;
2245 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2246 door_state &= ~DOOR_OPEN_2;
2247 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2248 door_state &= ~DOOR_CLOSE_2;
2250 if (setup.quick_doors)
2253 door_delay_value = 0;
2254 StopSound(SND_MENU_DOOR_OPENING);
2255 StopSound(SND_MENU_DOOR_CLOSING);
2258 if (door_state & DOOR_ACTION)
2260 if (!(door_state & DOOR_NO_DELAY))
2262 /* opening door sound has priority over simultaneously closing door */
2263 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2264 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2265 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2266 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2269 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2271 for(x=start; x<=DXSIZE; x+=stepsize)
2273 Bitmap *bitmap = pix[PIX_DOOR];
2274 GC gc = bitmap->stored_clip_gc;
2276 WaitUntilDelayReached(&door_delay, door_delay_value);
2278 if (door_state & DOOR_ACTION_1)
2280 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2281 int j = (DXSIZE - i) / 3;
2283 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2284 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2285 DXSIZE,DYSIZE - i/2, DX, DY);
2287 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2289 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2290 BlitBitmapMasked(bitmap, drawto,
2291 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2292 DX + DXSIZE - i, DY + j);
2293 BlitBitmapMasked(bitmap, drawto,
2294 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2295 DX + DXSIZE - i, DY + 140 + j);
2296 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2297 BlitBitmapMasked(bitmap, drawto,
2298 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2300 BlitBitmapMasked(bitmap, drawto,
2301 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2304 BlitBitmapMasked(bitmap, drawto,
2305 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2307 BlitBitmapMasked(bitmap, drawto,
2308 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2310 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2311 BlitBitmapMasked(bitmap, drawto,
2312 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2313 DX + DXSIZE - i, DY + 77 + j);
2314 BlitBitmapMasked(bitmap, drawto,
2315 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2316 DX + DXSIZE - i, DY + 203 + j);
2318 redraw_mask |= REDRAW_DOOR_1;
2321 if (door_state & DOOR_ACTION_2)
2323 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2324 int j = (VXSIZE - i) / 3;
2326 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2327 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2328 VXSIZE, VYSIZE - i/2, VX, VY);
2330 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2332 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2333 BlitBitmapMasked(bitmap, drawto,
2334 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2335 VX + VXSIZE-i, VY+j);
2336 SetClipOrigin(bitmap, gc,
2337 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2338 BlitBitmapMasked(bitmap, drawto,
2339 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2342 BlitBitmapMasked(bitmap, drawto,
2343 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2344 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2345 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2346 BlitBitmapMasked(bitmap, drawto,
2347 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2349 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2351 redraw_mask |= REDRAW_DOOR_2;
2356 if (game_status == MAINMENU)
2361 if (setup.quick_doors)
2363 StopSound(SND_MENU_DOOR_OPENING);
2364 StopSound(SND_MENU_DOOR_CLOSING);
2367 if (door_state & DOOR_ACTION_1)
2368 door1 = door_state & DOOR_ACTION_1;
2369 if (door_state & DOOR_ACTION_2)
2370 door2 = door_state & DOOR_ACTION_2;
2372 return (door1 | door2);
2375 void DrawSpecialEditorDoor()
2377 /* draw bigger toolbox window */
2378 BlitBitmap(pix[PIX_DOOR], drawto,
2379 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2381 redraw_mask |= REDRAW_ALL;
2384 void UndrawSpecialEditorDoor()
2386 /* draw normal tape recorder window */
2387 BlitBitmap(pix[PIX_BACK], drawto,
2388 562, 344, 108, 56, EX - 4, EY - 12);
2390 redraw_mask |= REDRAW_ALL;
2394 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2396 XImage *pixel_image;
2397 unsigned long pixel_value;
2399 pixel_image = XGetImage(display, bitmap->drawable,
2400 x, y, 1, 1, AllPlanes, ZPixmap);
2401 pixel_value = XGetPixel(pixel_image, 0, 0);
2403 XDestroyImage(pixel_image);
2409 /* ---------- new tool button stuff ---------------------------------------- */
2411 /* graphic position values for tool buttons */
2412 #define TOOL_BUTTON_YES_XPOS 2
2413 #define TOOL_BUTTON_YES_YPOS 250
2414 #define TOOL_BUTTON_YES_GFX_YPOS 0
2415 #define TOOL_BUTTON_YES_XSIZE 46
2416 #define TOOL_BUTTON_YES_YSIZE 28
2417 #define TOOL_BUTTON_NO_XPOS 52
2418 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2419 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2420 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2421 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2422 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2423 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2424 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2425 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2426 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2427 #define TOOL_BUTTON_PLAYER_XSIZE 30
2428 #define TOOL_BUTTON_PLAYER_YSIZE 30
2429 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2430 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2431 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2432 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2433 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2434 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2435 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2436 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2437 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2438 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2439 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2440 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2441 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2442 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2443 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2444 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2445 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2446 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2447 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2448 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2457 } toolbutton_info[NUM_TOOL_BUTTONS] =
2460 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2461 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2462 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2467 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2468 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2469 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2474 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2475 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2476 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2477 TOOL_CTRL_ID_CONFIRM,
2481 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2482 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2483 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2484 TOOL_CTRL_ID_PLAYER_1,
2488 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2489 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2490 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2491 TOOL_CTRL_ID_PLAYER_2,
2495 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2496 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2497 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2498 TOOL_CTRL_ID_PLAYER_3,
2502 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2503 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2504 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2505 TOOL_CTRL_ID_PLAYER_4,
2510 void CreateToolButtons()
2514 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2516 Bitmap *gd_bitmap = pix[PIX_DOOR];
2517 Bitmap *deco_bitmap = None;
2518 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2519 struct GadgetInfo *gi;
2520 unsigned long event_mask;
2521 int gd_xoffset, gd_yoffset;
2522 int gd_x1, gd_x2, gd_y;
2525 event_mask = GD_EVENT_RELEASED;
2527 gd_xoffset = toolbutton_info[i].xpos;
2528 gd_yoffset = toolbutton_info[i].ypos;
2529 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2530 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2531 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2533 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2535 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2537 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2538 &deco_bitmap, &deco_x, &deco_y);
2539 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2540 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2543 gi = CreateGadget(GDI_CUSTOM_ID, id,
2544 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2545 GDI_X, DX + toolbutton_info[i].x,
2546 GDI_Y, DY + toolbutton_info[i].y,
2547 GDI_WIDTH, toolbutton_info[i].width,
2548 GDI_HEIGHT, toolbutton_info[i].height,
2549 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2550 GDI_STATE, GD_BUTTON_UNPRESSED,
2551 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2552 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2553 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2554 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2555 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2556 GDI_DECORATION_SHIFTING, 1, 1,
2557 GDI_EVENT_MASK, event_mask,
2558 GDI_CALLBACK_ACTION, HandleToolButtons,
2562 Error(ERR_EXIT, "cannot create gadget");
2564 tool_gadget[id] = gi;
2568 static void UnmapToolButtons()
2572 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2573 UnmapGadget(tool_gadget[i]);
2576 static void HandleToolButtons(struct GadgetInfo *gi)
2578 request_gadget_id = gi->custom_id;
2581 int get_next_element(int element)
2585 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2586 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2587 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2588 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2589 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2590 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2591 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2593 default: return element;
2597 int el2gfx_OLD(int element)
2601 case EL_EMPTY: return -1;
2602 case EL_SAND: return GFX_ERDREICH;
2603 case EL_WALL: return GFX_MAUERWERK;
2604 case EL_WALL_CRUMBLED: return GFX_FELSBODEN;
2605 case EL_ROCK: return GFX_FELSBROCKEN;
2606 case EL_EMERALD: return GFX_EDELSTEIN;
2607 case EL_EXIT_CLOSED: return GFX_AUSGANG_ZU;
2608 case EL_EXIT_OPENING: return GFX_AUSGANG_ACT;
2609 case EL_EXIT_OPEN: return GFX_AUSGANG_AUF;
2610 case EL_SP_EXIT_OPEN: return GFX_SP_EXIT;
2611 case EL_PLAYER1: return GFX_SPIELER1;
2612 case EL_PLAYER2: return GFX_SPIELER2;
2613 case EL_PLAYER3: return GFX_SPIELER3;
2614 case EL_PLAYER4: return GFX_SPIELER4;
2615 case EL_BUG: return GFX_KAEFER;
2616 case EL_BUG_RIGHT: return GFX_KAEFER_RIGHT;
2617 case EL_BUG_UP: return GFX_KAEFER_UP;
2618 case EL_BUG_LEFT: return GFX_KAEFER_LEFT;
2619 case EL_BUG_DOWN: return GFX_KAEFER_DOWN;
2620 case EL_SPACESHIP: return GFX_FLIEGER;
2621 case EL_SPACESHIP_RIGHT: return GFX_FLIEGER_RIGHT;
2622 case EL_SPACESHIP_UP: return GFX_FLIEGER_UP;
2623 case EL_SPACESHIP_LEFT: return GFX_FLIEGER_LEFT;
2624 case EL_SPACESHIP_DOWN: return GFX_FLIEGER_DOWN;
2625 case EL_BD_BUTTERFLY: return GFX_BUTTERFLY;
2626 case EL_BD_BUTTERFLY_RIGHT: return GFX_BUTTERFLY_RIGHT;
2627 case EL_BD_BUTTERFLY_UP: return GFX_BUTTERFLY_UP;
2628 case EL_BD_BUTTERFLY_LEFT: return GFX_BUTTERFLY_LEFT;
2629 case EL_BD_BUTTERFLY_DOWN: return GFX_BUTTERFLY_DOWN;
2630 case EL_BD_FIREFLY: return GFX_FIREFLY;
2631 case EL_BD_FIREFLY_RIGHT: return GFX_FIREFLY_RIGHT;
2632 case EL_BD_FIREFLY_UP: return GFX_FIREFLY_UP;
2633 case EL_BD_FIREFLY_LEFT: return GFX_FIREFLY_LEFT;
2634 case EL_BD_FIREFLY_DOWN: return GFX_FIREFLY_DOWN;
2635 case EL_YAMYAM: return GFX_MAMPFER;
2636 case EL_ROBOT: return GFX_ROBOT;
2637 case EL_STEELWALL: return GFX_BETON;
2638 case EL_DIAMOND: return GFX_DIAMANT;
2639 case EL_QUICKSAND_EMPTY: return GFX_MORAST_LEER;
2640 case EL_QUICKSAND_FULL: return GFX_MORAST_VOLL;
2641 case EL_QUICKSAND_EMPTYING: return GFX_MORAST_LEER;
2642 case EL_AMOEBA_DROP: return GFX_TROPFEN;
2643 case EL_BOMB: return GFX_BOMBE;
2644 case EL_MAGIC_WALL: return GFX_MAGIC_WALL_OFF;
2645 case EL_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_EMPTY;
2646 case EL_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_EMPTY;
2647 case EL_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_FULL;
2648 case EL_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_DEAD;
2649 case EL_ACID: return GFX_SALZSAEURE;
2650 case EL_AMOEBA_DEAD: return GFX_AMOEBE_TOT;
2651 case EL_AMOEBA_WET: return GFX_AMOEBE_NASS;
2652 case EL_AMOEBA_DRY: return GFX_AMOEBE_NORM;
2653 case EL_AMOEBA_FULL: return GFX_AMOEBE_VOLL;
2654 case EL_BD_AMOEBA: return GFX_AMOEBE_BD;
2655 case EL_AMOEBA_TO_DIAMOND: return GFX_AMOEBA2DIAM;
2656 case EL_AMOEBA_DRIPPING: return GFX_AMOEBE_NASS;
2657 case EL_NUT: return GFX_KOKOSNUSS;
2658 case EL_GAMEOFLIFE: return GFX_LIFE;
2659 case EL_BIOMAZE: return GFX_LIFE_ASYNC;
2660 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2661 case EL_STONEBLOCK: return GFX_BADEWANNE;
2662 case EL_ACIDPOOL_TOPLEFT: return GFX_BADEWANNE1;
2663 case EL_ACIDPOOL_TOPRIGHT: return GFX_BADEWANNE2;
2664 case EL_ACIDPOOL_BOTTOMLEFT: return GFX_BADEWANNE3;
2665 case EL_ACIDPOOL_BOTTOM: return GFX_BADEWANNE4;
2666 case EL_ACIDPOOL_BOTTOMRIGHT: return GFX_BADEWANNE5;
2667 case EL_ROBOT_WHEEL: return GFX_ABLENK_AUS;
2668 case EL_ROBOT_WHEEL_ACTIVE: return GFX_ABLENK_EIN;
2669 case EL_KEY1: return GFX_SCHLUESSEL1;
2670 case EL_KEY2: return GFX_SCHLUESSEL2;
2671 case EL_KEY3: return GFX_SCHLUESSEL3;
2672 case EL_KEY4: return GFX_SCHLUESSEL4;
2673 case EL_GATE1: return GFX_PFORTE1;
2674 case EL_GATE2: return GFX_PFORTE2;
2675 case EL_GATE3: return GFX_PFORTE3;
2676 case EL_GATE4: return GFX_PFORTE4;
2677 case EL_GATE1_GRAY: return GFX_PFORTE1X;
2678 case EL_GATE2_GRAY: return GFX_PFORTE2X;
2679 case EL_GATE3_GRAY: return GFX_PFORTE3X;
2680 case EL_GATE4_GRAY: return GFX_PFORTE4X;
2681 case EL_DYNAMITE: return GFX_DYNAMIT_AUS;
2682 case EL_PACMAN: return GFX_PACMAN;
2683 case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT;
2684 case EL_PACMAN_UP: return GFX_PACMAN_UP;
2685 case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT;
2686 case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN;
2687 case EL_INVISIBLE_WALL: return GFX_UNSICHTBAR;
2688 case EL_INVISIBLE_WALL_ACTIVE: return GFX_UNSICHTBAR_ON;
2689 case EL_WALL_EMERALD: return GFX_ERZ_EDEL;
2690 case EL_WALL_DIAMOND: return GFX_ERZ_DIAM;
2691 case EL_LAMP: return GFX_BIRNE_AUS;
2692 case EL_LAMP_ACTIVE: return GFX_BIRNE_EIN;
2693 case EL_TIME_ORB_FULL: return GFX_ZEIT_VOLL;
2694 case EL_TIME_ORB_EMPTY: return GFX_ZEIT_LEER;
2695 case EL_WALL_GROWING: return GFX_MAUER_LEBT;
2696 case EL_WALL_GROWING_X: return GFX_MAUER_X;
2697 case EL_WALL_GROWING_Y: return GFX_MAUER_Y;
2698 case EL_WALL_GROWING_XY: return GFX_MAUER_XY;
2699 case EL_BD_DIAMOND: return GFX_EDELSTEIN_BD;
2700 case EL_EMERALD_YELLOW: return GFX_EDELSTEIN_GELB;
2701 case EL_EMERALD_RED: return GFX_EDELSTEIN_ROT;
2702 case EL_EMERALD_PURPLE: return GFX_EDELSTEIN_LILA;
2703 case EL_WALL_BD_DIAMOND: return GFX_ERZ_EDEL_BD;
2704 case EL_WALL_EMERALD_YELLOW: return GFX_ERZ_EDEL_GELB;
2705 case EL_WALL_EMERALD_RED: return GFX_ERZ_EDEL_ROT;
2706 case EL_WALL_EMERALD_PURPLE: return GFX_ERZ_EDEL_LILA;
2707 case EL_DARK_YAMYAM: return GFX_MAMPFER2;
2708 case EL_BD_MAGIC_WALL: return GFX_MAGIC_WALL_BD_OFF;
2709 case EL_BD_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_BD_EMPTY;
2710 case EL_BD_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_BD_EMPTY;
2711 case EL_BD_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_BD_FULL;
2712 case EL_BD_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2713 case EL_DYNABOMB_PLAYER1_ACTIVE: return GFX_DYNABOMB;
2714 case EL_DYNABOMB_PLAYER2_ACTIVE: return GFX_DYNABOMB;
2715 case EL_DYNABOMB_PLAYER3_ACTIVE: return GFX_DYNABOMB;
2716 case EL_DYNABOMB_PLAYER4_ACTIVE: return GFX_DYNABOMB;
2717 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2718 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2719 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2720 case EL_SOKOBAN_OBJECT: return GFX_SOKOBAN_OBJEKT;
2721 case EL_SOKOBAN_FIELD_EMPTY: return GFX_SOKOBAN_FELD_LEER;
2722 case EL_SOKOBAN_FIELD_FULL: return GFX_SOKOBAN_FELD_VOLL;
2723 case EL_MOLE: return GFX_MOLE;
2724 case EL_PENGUIN: return GFX_PINGUIN;
2725 case EL_PIG: return GFX_SCHWEIN;
2726 case EL_DRAGON: return GFX_DRACHE;
2727 case EL_SATELLITE: return GFX_SONDE;
2728 case EL_ARROW_BLUE_LEFT: return GFX_PFEIL_LEFT;
2729 case EL_ARROW_BLUE_RIGHT: return GFX_PFEIL_RIGHT;
2730 case EL_ARROW_BLUE_UP: return GFX_PFEIL_UP;
2731 case EL_ARROW_BLUE_DOWN: return GFX_PFEIL_DOWN;
2732 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2733 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2734 case EL_SP_BUGGY_BASE_ACTIVE: return GFX_SP_BUG_ACTIVE;
2735 case EL_SP_ZONK: return GFX_SP_ZONK;
2736 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2737 case EL_INVISIBLE_STEELWALL: return GFX_INVISIBLE_STEEL;
2738 case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2739 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2740 case EL_EM_GATE1: return GFX_EM_GATE_1;
2741 case EL_EM_GATE2: return GFX_EM_GATE_2;
2742 case EL_EM_GATE3: return GFX_EM_GATE_3;
2743 case EL_EM_GATE4: return GFX_EM_GATE_4;
2744 case EL_EM_GATE1_GRAY: return GFX_EM_GATE_1X;
2745 case EL_EM_GATE2_GRAY: return GFX_EM_GATE_2X;
2746 case EL_EM_GATE3_GRAY: return GFX_EM_GATE_3X;
2747 case EL_EM_GATE4_GRAY: return GFX_EM_GATE_4X;
2748 case EL_EM_KEY1_FILE: return GFX_EM_KEY_1;
2749 case EL_EM_KEY2_FILE: return GFX_EM_KEY_2;
2750 case EL_EM_KEY3_FILE: return GFX_EM_KEY_3;
2751 case EL_EM_KEY4_FILE: return GFX_EM_KEY_4;
2752 case EL_EM_KEY1: return GFX_EM_KEY_1;
2753 case EL_EM_KEY2: return GFX_EM_KEY_2;
2754 case EL_EM_KEY3: return GFX_EM_KEY_3;
2755 case EL_EM_KEY4: return GFX_EM_KEY_4;
2756 case EL_PEARL: return GFX_PEARL;
2757 case EL_CRYSTAL: return GFX_CRYSTAL;
2758 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2759 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2760 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2761 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2762 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2763 case EL_SHIELD_NORMAL: return GFX_SHIELD_PASSIVE;
2764 case EL_SHIELD_DEADLY: return GFX_SHIELD_ACTIVE;
2765 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2766 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2767 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2768 case EL_SWITCHGATE_SWITCH_UP: return GFX_SWITCHGATE_SWITCH_1;
2769 case EL_SWITCHGATE_SWITCH_DOWN: return GFX_SWITCHGATE_SWITCH_2;
2770 case EL_CONVEYOR_BELT1_LEFT: return GFX_BELT1_LEFT;
2771 case EL_CONVEYOR_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2772 case EL_CONVEYOR_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2773 case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2774 case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2775 case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2776 case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2777 case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2778 case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2779 case EL_CONVEYOR_BELT2_LEFT: return GFX_BELT2_LEFT;
2780 case EL_CONVEYOR_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2781 case EL_CONVEYOR_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2782 case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2783 case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2784 case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2785 case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2786 case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2787 case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2788 case EL_CONVEYOR_BELT3_LEFT: return GFX_BELT3_LEFT;
2789 case EL_CONVEYOR_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2790 case EL_CONVEYOR_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2791 case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2792 case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2793 case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2794 case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2795 case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2796 case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2797 case EL_CONVEYOR_BELT4_LEFT: return GFX_BELT4_LEFT;
2798 case EL_CONVEYOR_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2799 case EL_CONVEYOR_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2800 case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2801 case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2802 case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2803 case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2804 case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2805 case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2806 case EL_LANDMINE: return GFX_LANDMINE;
2807 case EL_ENVELOPE: return GFX_ENVELOPE;
2808 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH_OFF;
2809 case EL_LIGHT_SWITCH_ACTIVE: return GFX_LIGHT_SWITCH_ON;
2810 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2811 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2812 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2813 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2814 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2815 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2816 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2817 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2818 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2819 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2820 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2821 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2822 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2823 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2824 case EL_MOLE_UP: return GFX_MOLE_UP;
2825 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2826 case EL_STEELWALL_SLANTED: return GFX_STEEL_SLANTED;
2827 case EL_INVISIBLE_SAND: return GFX_SAND_INVISIBLE;
2828 case EL_INVISIBLE_SAND_ACTIVE: return GFX_SAND_INVISIBLE_ON;
2829 case EL_DX_UNKNOWN_15: return GFX_DX_UNKNOWN_15;
2830 case EL_DX_UNKNOWN_42: return GFX_DX_UNKNOWN_42;
2831 case EL_TIMEGATE_OPEN: return GFX_TIMEGATE_OPEN;
2832 case EL_TIMEGATE_CLOSED: return GFX_TIMEGATE_CLOSED;
2833 case EL_TIMEGATE_SWITCH_ACTIVE: return GFX_TIMEGATE_SWITCH;
2834 case EL_TIMEGATE_SWITCH: return GFX_TIMEGATE_SWITCH;
2835 case EL_BALLOON: return GFX_BALLOON;
2836 case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
2837 case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2838 case EL_BALLOON_SEND_UP: return GFX_BALLOON_SEND_UP;
2839 case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
2840 case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2841 case EL_EMC_STEELWALL1: return GFX_EMC_STEEL_WALL_1;
2842 case EL_EMC_STEELWALL2: return GFX_EMC_STEEL_WALL_2;
2843 case EL_EMC_STEELWALL3: return GFX_EMC_STEEL_WALL_3;
2844 case EL_EMC_STEELWALL4: return GFX_EMC_STEEL_WALL_4;
2845 case EL_EMC_WALL_PILLAR_UPPER: return GFX_EMC_WALL_1;
2846 case EL_EMC_WALL_PILLAR_MIDDLE: return GFX_EMC_WALL_2;
2847 case EL_EMC_WALL_PILLAR_LOWER: return GFX_EMC_WALL_3;
2848 case EL_EMC_WALL4: return GFX_EMC_WALL_4;
2849 case EL_EMC_WALL5: return GFX_EMC_WALL_5;
2850 case EL_EMC_WALL6: return GFX_EMC_WALL_6;
2851 case EL_EMC_WALL7: return GFX_EMC_WALL_7;
2852 case EL_EMC_WALL8: return GFX_EMC_WALL_8;
2853 case EL_TUBE_ALL: return GFX_TUBE_CROSS;
2854 case EL_TUBE_VERTICAL: return GFX_TUBE_VERTICAL;
2855 case EL_TUBE_HORIZONTAL: return GFX_TUBE_HORIZONTAL;
2856 case EL_TUBE_VERTICAL_LEFT: return GFX_TUBE_VERT_LEFT;
2857 case EL_TUBE_VERTICAL_RIGHT: return GFX_TUBE_VERT_RIGHT;
2858 case EL_TUBE_HORIZONTAL_UP: return GFX_TUBE_HORIZ_UP;
2859 case EL_TUBE_HORIZONTAL_DOWN: return GFX_TUBE_HORIZ_DOWN;
2860 case EL_TUBE_LEFT_UP: return GFX_TUBE_LEFT_UP;
2861 case EL_TUBE_LEFT_DOWN: return GFX_TUBE_LEFT_DOWN;
2862 case EL_TUBE_RIGHT_UP: return GFX_TUBE_RIGHT_UP;
2863 case EL_TUBE_RIGHT_DOWN: return GFX_TUBE_RIGHT_DOWN;
2864 case EL_SPRING: return GFX_SPRING;
2865 case EL_TRAP: return GFX_TRAP_INACTIVE;
2866 case EL_TRAP_ACTIVE: return GFX_TRAP_ACTIVE;
2867 case EL_BD_WALL: return GFX_BD_WALL;
2868 case EL_BD_ROCK: return GFX_BD_ROCK;
2869 case EL_DX_SUPABOMB: return GFX_DX_SUPABOMB;
2870 case EL_SP_MURPHY_CLONE: return GFX_SP_MURPHY_CLONE;
2874 if (IS_CHAR(element))
2875 return GFX_CHAR_START + (element - EL_CHAR_START);
2876 else if (element >= EL_SP_START && element <= EL_SP_END)
2878 int nr_element = element - EL_SP_START;
2879 int gfx_per_line = 8;
2881 (nr_element / gfx_per_line) * SP_PER_LINE +
2882 (nr_element % gfx_per_line);
2884 return GFX_START_ROCKSSP + nr_graphic;
2892 int el2gfx(int element)
2895 int graphic_OLD = el2gfx_OLD(element);
2900 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2903 int graphic_OLD = el2gfx_OLD(element);
2905 if (element >= MAX_ELEMENTS)
2907 Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
2910 if (graphic_NEW != graphic_OLD)
2912 Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2913 graphic_NEW, graphic_OLD);
2921 int el2img(int element)
2923 int graphic = element_info[element].graphic[GFX_ACTION_DEFAULT];
2927 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2934 int el_dir2img(int element, int direction)
2936 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2939 int el_dir_act2img(int element, int direction, int action)
2941 action = graphics_action_mapping[action];
2942 direction = MV_DIR_BIT(direction);
2944 return element_info[element].direction_graphic[action][direction];