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 frame = Frame[last_jx][last_jy];
707 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), GFX_EXPLOSION,
708 ((frame - 1) / delay - 1));
711 /* draw elements that stay over the player */
712 /* handle the field the player is leaving ... */
713 if (player_is_moving && IS_OVER_PLAYER(last_element))
714 DrawLevelField(last_jx, last_jy);
715 /* ... and the field the player is entering */
716 if (IS_OVER_PLAYER(element))
717 DrawLevelField(jx, jy);
719 if (setup.direct_draw)
721 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
722 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
723 int x_size = TILEX * (1 + ABS(jx - last_jx));
724 int y_size = TILEY * (1 + ABS(jy - last_jy));
726 BlitBitmap(drawto_field, window,
727 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
728 SetDrawtoField(DRAW_DIRECT);
731 MarkTileDirty(sx,sy);
734 static int getGraphicAnimationPhase(int frames, int delay, int mode)
738 if (mode & ANIM_PINGPONG)
740 int max_anim_frames = 2 * frames - 2;
742 phase = (FrameCounter % (delay * max_anim_frames)) / delay;
743 phase = (phase < frames ? phase : max_anim_frames - phase);
746 phase = (FrameCounter % (delay * frames)) / delay;
748 if (mode & ANIM_REVERSE)
754 int getGraphicAnimationFrame(int graphic, int sync_frame)
756 int num_frames = new_graphic_info[graphic].anim_frames;
757 int delay = new_graphic_info[graphic].anim_delay;
758 int mode = new_graphic_info[graphic].anim_mode;
761 /* animation synchronized with global frame counter, not move position */
762 if (new_graphic_info[graphic].anim_global_sync || sync_frame < 0)
763 sync_frame = FrameCounter;
765 sync_frame += new_graphic_info[graphic].anim_start_frame * delay;
767 if (mode & ANIM_LOOP) /* normal, looping animation */
769 frame = (sync_frame % (delay * num_frames)) / delay;
771 else if (mode & ANIM_LINEAR) /* normal, non-looping animation */
773 frame = sync_frame / delay;
775 if (frame > num_frames - 1)
776 frame = num_frames - 1;
778 else if (mode & ANIM_PINGPONG) /* use border frames once */
780 int max_anim_frames = 2 * num_frames - 2;
782 frame = (sync_frame % (delay * max_anim_frames)) / delay;
783 frame = (frame < num_frames ? frame : max_anim_frames - frame);
785 else if (mode & ANIM_PINGPONG2) /* use border frames twice */
787 int max_anim_frames = 2 * num_frames;
789 frame = (sync_frame % (delay * max_anim_frames)) / delay;
790 frame = (frame < num_frames ? frame : max_anim_frames - frame - 1);
793 if (mode & ANIM_REVERSE) /* use reverse animation direction */
794 frame = num_frames - frame - 1;
799 void DrawGraphicAnimationExt(int x, int y, int graphic, int mask_mode)
802 int delay = new_graphic_info[graphic].anim_delay;
804 if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
806 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
809 int frame = getGraphicAnimationFrame(graphic, -1);
811 if (mask_mode == USE_MASKING)
812 DrawGraphicThruMask(SCREENX(x), SCREENY(y), graphic, frame);
814 DrawGraphic(SCREENX(x), SCREENY(y), graphic, frame);
819 void DrawOldGraphicAnimation(int x, int y, int graphic,
820 int frames, int delay, int mode)
822 DrawGraphicAnimationExt(x, y, graphic, frames, delay, mode, NO_MASKING);
826 void DrawGraphicAnimation(int x, int y, int graphic)
828 DrawGraphicAnimationExt(x, y, graphic, NO_MASKING);
832 void getOldGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
834 if (graphic >= 0 && graphic_info[graphic].bitmap != NULL)
836 *bitmap = graphic_info[graphic].bitmap;
837 *x = graphic_info[graphic].src_x;
838 *y = graphic_info[graphic].src_y;
840 else if (graphic >= GFX_START_ROCKSELEMENTS &&
841 graphic <= GFX_END_ROCKSELEMENTS)
843 graphic -= GFX_START_ROCKSELEMENTS;
844 *bitmap = pix[PIX_ELEMENTS];
845 *x = (graphic % GFX_PER_LINE) * TILEX;
846 *y = (graphic / GFX_PER_LINE) * TILEY;
848 else if (graphic >= GFX_START_ROCKSHEROES && graphic <= GFX_END_ROCKSHEROES)
850 graphic -= GFX_START_ROCKSHEROES;
851 *bitmap = pix[PIX_HEROES];
852 *x = (graphic % HEROES_PER_LINE) * TILEX;
853 *y = (graphic / HEROES_PER_LINE) * TILEY;
855 else if (graphic >= GFX_START_ROCKSSP && graphic <= GFX_END_ROCKSSP)
857 graphic -= GFX_START_ROCKSSP;
858 *bitmap = pix[PIX_SP];
859 *x = (graphic % SP_PER_LINE) * TILEX;
860 *y = (graphic / SP_PER_LINE) * TILEY;
862 else if (graphic >= GFX_START_ROCKSDC && graphic <= GFX_END_ROCKSDC)
864 graphic -= GFX_START_ROCKSDC;
865 *bitmap = pix[PIX_DC];
866 *x = (graphic % DC_PER_LINE) * TILEX;
867 *y = (graphic / DC_PER_LINE) * TILEY;
869 else if (graphic >= GFX_START_ROCKSMORE && graphic <= GFX_END_ROCKSMORE)
871 graphic -= GFX_START_ROCKSMORE;
872 *bitmap = pix[PIX_MORE];
873 *x = (graphic % MORE_PER_LINE) * TILEX;
874 *y = (graphic / MORE_PER_LINE) * TILEY;
876 else if (graphic >= GFX_START_ROCKSFONT && graphic <= GFX_END_ROCKSFONT)
878 graphic -= GFX_START_ROCKSFONT;
879 *bitmap = pix[PIX_FONT_EM];
880 *x = (graphic % FONT_CHARS_PER_LINE) * TILEX;
881 *y = (graphic / FONT_CHARS_PER_LINE) * TILEY;
885 *bitmap = pix[PIX_SP];
892 void DrawGraphic(int x, int y, int graphic, int frame)
895 if (!IN_SCR_FIELD(x, y))
897 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
898 printf("DrawGraphic(): This should never happen!\n");
903 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
907 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
912 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
913 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
916 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
919 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
920 int src_x = new_graphic_info[graphic].src_x;
921 int src_y = new_graphic_info[graphic].src_y;
922 int offset_x = new_graphic_info[graphic].offset_x;
923 int offset_y = new_graphic_info[graphic].offset_y;
925 src_x += frame * offset_x;
926 src_y += frame * offset_y;
928 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
931 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
934 if (!IN_SCR_FIELD(x, y))
936 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
937 printf("DrawGraphicThruMask(): This should never happen!\n");
942 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
947 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
950 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
951 GC drawing_gc = src_bitmap->stored_clip_gc;
952 int src_x = new_graphic_info[graphic].src_x;
953 int src_y = new_graphic_info[graphic].src_y;
954 int offset_x = new_graphic_info[graphic].offset_x;
955 int offset_y = new_graphic_info[graphic].offset_y;
957 src_x += frame * offset_x;
958 src_y += frame * offset_y;
960 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
961 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
964 void DrawMiniGraphic(int x, int y, int graphic)
966 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
967 MarkTileDirty(x / 2, y / 2);
970 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
972 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
974 int mini_starty = src_bitmap->height * 2 / 3;
975 int src_x = mini_startx + new_graphic_info[graphic].src_x / 2;
976 int src_y = mini_starty + new_graphic_info[graphic].src_y / 2;
978 *bitmap = src_bitmap;
983 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
988 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
989 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
992 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
993 int cut_mode, int mask_mode)
1002 int width = TILEX, height = TILEY;
1008 DrawGraphic(x, y, graphic, frame);
1012 if (dx || dy) /* shifted graphic */
1014 if (x < BX1) /* object enters playfield from the left */
1021 else if (x > BX2) /* object enters playfield from the right */
1027 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1033 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1035 else if (dx) /* general horizontal movement */
1036 MarkTileDirty(x + SIGN(dx), y);
1038 if (y < BY1) /* object enters playfield from the top */
1040 if (cut_mode==CUT_BELOW) /* object completely above top border */
1048 else if (y > BY2) /* object enters playfield from the bottom */
1054 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1060 else if (dy > 0 && cut_mode == CUT_ABOVE)
1062 if (y == BY2) /* object completely above bottom border */
1068 MarkTileDirty(x, y + 1);
1069 } /* object leaves playfield to the bottom */
1070 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1072 else if (dy) /* general vertical movement */
1073 MarkTileDirty(x, y + SIGN(dy));
1076 src_bitmap = new_graphic_info[graphic].bitmap;
1077 src_x = new_graphic_info[graphic].src_x;
1078 src_y = new_graphic_info[graphic].src_y;
1079 offset_x = new_graphic_info[graphic].offset_x;
1080 offset_y = new_graphic_info[graphic].offset_y;
1082 drawing_gc = src_bitmap->stored_clip_gc;
1084 src_x += frame * offset_x;
1085 src_y += frame * offset_y;
1090 dest_x = FX + x * TILEX + dx;
1091 dest_y = FY + y * TILEY + dy;
1094 if (!IN_SCR_FIELD(x,y))
1096 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1097 printf("DrawGraphicShifted(): This should never happen!\n");
1102 if (mask_mode == USE_MASKING)
1104 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1105 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1109 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1115 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1116 int frame, int cut_mode)
1118 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1122 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1123 int cut_mode, int mask_mode)
1125 int ux = LEVELX(x), uy = LEVELY(y);
1126 int graphic = el2gfx(element);
1127 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
1128 int phase4 = phase8 / 2;
1129 int phase2 = phase8 / 4;
1130 int dir = MovDir[ux][uy];
1132 if (element == EL_PACMAN || element == EL_BUG || element == EL_SPACESHIP)
1134 graphic += 1 * !phase2;
1138 else if (dir == MV_LEFT)
1140 else if (dir == MV_DOWN)
1143 else if (element == EL_SP_SNIKSNAK)
1146 graphic = GFX_SP_SNIKSNAK_LEFT;
1147 else if (dir == MV_RIGHT)
1148 graphic = GFX_SP_SNIKSNAK_RIGHT;
1149 else if (dir == MV_UP)
1150 graphic = GFX_SP_SNIKSNAK_UP;
1152 graphic = GFX_SP_SNIKSNAK_DOWN;
1154 graphic += (phase8 < 4 ? phase8 : 7 - phase8);
1156 else if (element == EL_SP_ELECTRON)
1158 graphic = GFX2_SP_ELECTRON + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1160 else if (element == EL_MOLE || element == EL_PENGUIN ||
1161 element == EL_PIG || element == EL_DRAGON)
1164 graphic = (element == EL_MOLE ? GFX_MOLE_LEFT :
1165 element == EL_PENGUIN ? GFX_PINGUIN_LEFT :
1166 element == EL_PIG ? GFX_SCHWEIN_LEFT : GFX_DRACHE_LEFT);
1167 else if (dir == MV_RIGHT)
1168 graphic = (element == EL_MOLE ? GFX_MOLE_RIGHT :
1169 element == EL_PENGUIN ? GFX_PINGUIN_RIGHT :
1170 element == EL_PIG ? GFX_SCHWEIN_RIGHT : GFX_DRACHE_RIGHT);
1171 else if (dir == MV_UP)
1172 graphic = (element == EL_MOLE ? GFX_MOLE_UP :
1173 element == EL_PENGUIN ? GFX_PINGUIN_UP :
1174 element == EL_PIG ? GFX_SCHWEIN_UP : GFX_DRACHE_UP);
1176 graphic = (element == EL_MOLE ? GFX_MOLE_DOWN :
1177 element == EL_PENGUIN ? GFX_PINGUIN_DOWN :
1178 element == EL_PIG ? GFX_SCHWEIN_DOWN : GFX_DRACHE_DOWN);
1182 else if (element == EL_SATELLITE)
1184 graphic = GFX_SONDE_START + getGraphicAnimationPhase(8, 2, ANIM_LOOP);
1186 else if (element == EL_ACID)
1188 graphic = GFX_GEBLUBBER + getGraphicAnimationPhase(4, 10, ANIM_LOOP);
1190 else if (element == EL_BD_BUTTERFLY || element == EL_BD_FIREFLY)
1194 else if (element == EL_BALLOON)
1198 else if ((element == EL_ROCK ||
1199 element == EL_SP_ZONK ||
1200 element == EL_BD_ROCK ||
1201 element == EL_SP_INFOTRON ||
1205 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1207 if (element == EL_ROCK ||
1208 element == EL_SP_ZONK ||
1209 element == EL_BD_ROCK)
1212 graphic += (4 - phase4) % 4;
1213 else if (dir == MV_RIGHT)
1216 graphic += phase2 * 2;
1218 else if (element != EL_SP_INFOTRON)
1222 else if (element == EL_MAGIC_WALL_ACTIVE ||
1223 element == EL_MAGIC_WALL_EMPTYING ||
1224 element == EL_BD_MAGIC_WALL_ACTIVE ||
1225 element == EL_BD_MAGIC_WALL_EMPTYING ||
1226 element == EL_MAGIC_WALL_FULL ||
1227 element == EL_BD_MAGIC_WALL_FULL)
1229 graphic += 3 + getGraphicAnimationPhase(4, 4, ANIM_REVERSE);
1231 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1233 graphic = (element == EL_AMOEBA_DEAD ? GFX_AMOEBE_TOT : GFX_AMOEBE_LEBT);
1234 graphic += (x + 2 * y + 4) % 4;
1236 else if (element == EL_WALL_GROWING)
1238 boolean links_massiv = FALSE, rechts_massiv = FALSE;
1240 if (!IN_LEV_FIELD(ux-1, uy) || IS_MAUER(Feld[ux-1][uy]))
1241 links_massiv = TRUE;
1242 if (!IN_LEV_FIELD(ux+1, uy) || IS_MAUER(Feld[ux+1][uy]))
1243 rechts_massiv = TRUE;
1245 if (links_massiv && rechts_massiv)
1246 graphic = GFX_MAUERWERK;
1247 else if (links_massiv)
1248 graphic = GFX_MAUER_R;
1249 else if (rechts_massiv)
1250 graphic = GFX_MAUER_L;
1253 else if ((element == EL_INVISIBLE_STEELWALL ||
1254 element == EL_INVISIBLE_WALL ||
1255 element == EL_INVISIBLE_SAND) && game.light_time_left)
1257 graphic = (element == EL_INVISIBLE_STEELWALL ? GFX_INVISIBLE_STEEL_ON :
1258 element == EL_INVISIBLE_WALL ? GFX_UNSICHTBAR_ON :
1259 GFX_SAND_INVISIBLE_ON);
1264 DrawGraphicShifted(x, y, dx, dy, graphic, cut_mode, mask_mode);
1265 else if (mask_mode == USE_MASKING)
1266 DrawGraphicThruMask(x, y, graphic);
1268 DrawGraphic(x, y, graphic);
1272 inline static int getFramePosition(int x, int y)
1274 int frame_pos = -1; /* default: global synchronization */
1276 int element = Feld[x][y];
1278 if (element == EL_QUICKSAND_FULL ||
1279 element == EL_MAGIC_WALL_FULL ||
1280 element == EL_BD_MAGIC_WALL_FULL)
1282 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1283 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1285 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1291 inline static int getGfxAction(int x, int y)
1293 int gfx_action = GFX_ACTION_DEFAULT;
1296 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1297 gfx_action = GfxAction[x][y];
1298 else if (IS_MOVING(x, y))
1299 gfx_action = GFX_ACTION_MOVING;
1301 gfx_action = GfxAction[x][y];
1307 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1308 int cut_mode, int mask_mode)
1310 int ux = LEVELX(x), uy = LEVELY(y);
1311 int move_dir = MovDir[ux][uy];
1312 int move_pos = getFramePosition(ux, uy);
1313 int gfx_action = getGfxAction(ux, uy);
1314 int graphic = el_dir_act2img(element, move_dir, gfx_action);
1315 int frame = getGraphicAnimationFrame(graphic, move_pos);
1317 if (element == EL_WALL_GROWING)
1319 boolean left_stopped = FALSE, right_stopped = FALSE;
1321 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1322 left_stopped = TRUE;
1323 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1324 right_stopped = TRUE;
1326 if (left_stopped && right_stopped)
1328 else if (left_stopped)
1330 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1331 frame = new_graphic_info[graphic].anim_frames - 1;
1333 else if (right_stopped)
1335 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1336 frame = new_graphic_info[graphic].anim_frames - 1;
1339 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1341 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1342 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1343 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1344 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1345 IMG_AMOEBA_DEAD_PART1);
1347 graphic += (x + 2 * y + 4) % 4;
1351 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1352 else if (mask_mode == USE_MASKING)
1353 DrawGraphicThruMask(x, y, graphic, frame);
1355 DrawGraphic(x, y, graphic, frame);
1358 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1359 int cut_mode, int mask_mode)
1361 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1362 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1363 cut_mode, mask_mode);
1366 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1369 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1372 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1375 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1379 void DrawOldScreenElementThruMask(int x, int y, int element)
1381 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1384 void DrawScreenElementThruMask(int x, int y, int element)
1386 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1390 void DrawLevelElementThruMask(int x, int y, int element)
1392 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1395 void DrawLevelFieldThruMask(int x, int y)
1397 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1400 void DrawCrumbledSand(int x, int y)
1404 int i, width, height, cx,cy;
1405 int ux = LEVELX(x), uy = LEVELY(y);
1406 int element, graphic;
1408 static int xy[4][2] =
1416 if (!IN_LEV_FIELD(ux, uy))
1419 element = Feld[ux][uy];
1421 if (element == EL_SAND ||
1422 element == EL_LANDMINE ||
1423 element == EL_TRAP ||
1424 element == EL_TRAP_ACTIVE)
1426 if (!IN_SCR_FIELD(x, y))
1429 graphic = IMG_SAND_CRUMBLED;
1431 src_bitmap = new_graphic_info[graphic].bitmap;
1432 src_x = new_graphic_info[graphic].src_x;
1433 src_y = new_graphic_info[graphic].src_y;
1439 uxx = ux + xy[i][0];
1440 uyy = uy + xy[i][1];
1441 if (!IN_LEV_FIELD(uxx, uyy))
1442 element = EL_STEELWALL;
1444 element = Feld[uxx][uyy];
1446 if (element == EL_SAND ||
1447 element == EL_LANDMINE ||
1448 element == EL_TRAP ||
1449 element == EL_TRAP_ACTIVE)
1452 if (i == 1 || i == 2)
1456 cx = (i == 2 ? TILEX - snip : 0);
1464 cy = (i == 3 ? TILEY - snip : 0);
1467 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1468 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1471 MarkTileDirty(x, y);
1475 graphic = IMG_SAND_CRUMBLED;
1477 src_bitmap = new_graphic_info[graphic].bitmap;
1478 src_x = new_graphic_info[graphic].src_x;
1479 src_y = new_graphic_info[graphic].src_y;
1483 int xx, yy, uxx, uyy;
1487 uxx = ux + xy[i][0];
1488 uyy = uy + xy[i][1];
1490 if (!IN_LEV_FIELD(uxx, uyy) ||
1491 (Feld[uxx][uyy] != EL_SAND &&
1492 Feld[uxx][uyy] != EL_LANDMINE &&
1493 Feld[uxx][uyy] != EL_TRAP &&
1494 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1495 !IN_SCR_FIELD(xx, yy))
1498 if (i == 1 || i == 2)
1502 cx = (i == 1 ? TILEX - snip : 0);
1510 cy = (i==0 ? TILEY-snip : 0);
1513 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1514 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1516 MarkTileDirty(xx, yy);
1521 void DrawScreenElement(int x, int y, int element)
1523 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1524 DrawCrumbledSand(x, y);
1527 void DrawLevelElement(int x, int y, int element)
1529 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1530 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1533 void DrawScreenField(int x, int y)
1535 int ux = LEVELX(x), uy = LEVELY(y);
1536 int element, content;
1538 if (!IN_LEV_FIELD(ux, uy))
1540 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1543 element = BorderElement;
1545 DrawScreenElement(x, y, element);
1549 element = Feld[ux][uy];
1550 content = Store[ux][uy];
1552 if (IS_MOVING(ux, uy))
1554 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1555 boolean cut_mode = NO_CUTTING;
1557 if (element == EL_QUICKSAND_EMPTYING ||
1558 element == EL_MAGIC_WALL_EMPTYING ||
1559 element == EL_BD_MAGIC_WALL_EMPTYING ||
1560 element == EL_AMOEBA_DRIPPING)
1561 cut_mode = CUT_ABOVE;
1562 else if (element == EL_QUICKSAND_FILLING ||
1563 element == EL_MAGIC_WALL_FILLING ||
1564 element == EL_BD_MAGIC_WALL_FILLING)
1565 cut_mode = CUT_BELOW;
1567 if (cut_mode == CUT_ABOVE)
1568 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1570 DrawScreenElement(x, y, EL_EMPTY);
1573 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1574 else if (cut_mode == NO_CUTTING)
1575 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1577 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1579 if (content == EL_ACID)
1580 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1582 else if (IS_BLOCKED(ux, uy))
1587 boolean cut_mode = NO_CUTTING;
1588 int element_old, content_old;
1590 Blocked2Moving(ux, uy, &oldx, &oldy);
1593 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1594 MovDir[oldx][oldy] == MV_RIGHT);
1596 element_old = Feld[oldx][oldy];
1597 content_old = Store[oldx][oldy];
1599 if (element_old == EL_QUICKSAND_EMPTYING ||
1600 element_old == EL_MAGIC_WALL_EMPTYING ||
1601 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1602 element_old == EL_AMOEBA_DRIPPING)
1603 cut_mode = CUT_ABOVE;
1605 DrawScreenElement(x, y, EL_EMPTY);
1608 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1610 else if (cut_mode == NO_CUTTING)
1611 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1614 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1617 else if (IS_DRAWABLE(element))
1618 DrawScreenElement(x, y, element);
1620 DrawScreenElement(x, y, EL_EMPTY);
1623 void DrawLevelField(int x, int y)
1625 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1626 DrawScreenField(SCREENX(x), SCREENY(y));
1627 else if (IS_MOVING(x, y))
1631 Moving2Blocked(x, y, &newx, &newy);
1632 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1633 DrawScreenField(SCREENX(newx), SCREENY(newy));
1635 else if (IS_BLOCKED(x, y))
1639 Blocked2Moving(x, y, &oldx, &oldy);
1640 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1641 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1645 void DrawMiniElement(int x, int y, int element)
1649 graphic = el2img(element);
1650 DrawMiniGraphic(x, y, graphic);
1653 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1655 int x = sx + scroll_x, y = sy + scroll_y;
1657 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1658 DrawMiniElement(sx, sy, EL_EMPTY);
1659 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1660 DrawMiniElement(sx, sy, Feld[x][y]);
1663 int steel_type, steel_position;
1666 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1667 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1668 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1669 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1670 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1671 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1674 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1675 steel_position = (x == -1 && y == -1 ? 0 :
1676 x == lev_fieldx && y == -1 ? 1 :
1677 x == -1 && y == lev_fieldy ? 2 :
1678 x == lev_fieldx && y == lev_fieldy ? 3 :
1679 x == -1 || x == lev_fieldx ? 4 :
1680 y == -1 || y == lev_fieldy ? 5 : -1);
1682 if (steel_position != -1)
1683 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1687 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1689 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1690 int mini_startx = src_bitmap->width * 3 / 4;
1691 int mini_starty = src_bitmap->height * 2 / 3;
1692 int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1693 int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1695 *bitmap = src_bitmap;
1700 void DrawMicroElement(int xpos, int ypos, int element)
1706 if (element == EL_EMPTY)
1709 graphic = el2img(element);
1711 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1712 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1722 for(x=BX1; x<=BX2; x++)
1723 for(y=BY1; y<=BY2; y++)
1724 DrawScreenField(x, y);
1726 redraw_mask |= REDRAW_FIELD;
1729 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1733 for(x=0; x<size_x; x++)
1734 for(y=0; y<size_y; y++)
1735 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1737 redraw_mask |= REDRAW_FIELD;
1740 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1744 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1746 if (lev_fieldx < STD_LEV_FIELDX)
1747 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1748 if (lev_fieldy < STD_LEV_FIELDY)
1749 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1751 xpos += MICRO_TILEX;
1752 ypos += MICRO_TILEY;
1754 for(x=-1; x<=STD_LEV_FIELDX; x++)
1756 for(y=-1; y<=STD_LEV_FIELDY; y++)
1758 int lx = from_x + x, ly = from_y + y;
1760 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1761 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1763 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1764 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1769 redraw_mask |= REDRAW_MICROLEVEL;
1772 #define MICROLABEL_EMPTY 0
1773 #define MICROLABEL_LEVEL_NAME 1
1774 #define MICROLABEL_CREATED_BY 2
1775 #define MICROLABEL_LEVEL_AUTHOR 3
1776 #define MICROLABEL_IMPORTED_FROM 4
1777 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1779 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1781 static void DrawMicroLevelLabelExt(int mode)
1783 char label_text[MAX_MICROLABEL_SIZE + 1];
1785 ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1787 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1788 mode == MICROLABEL_CREATED_BY ? "created by" :
1789 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1790 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1791 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1792 leveldir_current->imported_from : ""),
1793 MAX_MICROLABEL_SIZE);
1794 label_text[MAX_MICROLABEL_SIZE] = '\0';
1796 if (strlen(label_text) > 0)
1798 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1799 int lypos = MICROLABEL_YPOS;
1801 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1804 redraw_mask |= REDRAW_MICROLEVEL;
1807 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1809 static unsigned long scroll_delay = 0;
1810 static unsigned long label_delay = 0;
1811 static int from_x, from_y, scroll_direction;
1812 static int label_state, label_counter;
1816 from_x = from_y = 0;
1817 scroll_direction = MV_RIGHT;
1821 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1822 DrawMicroLevelLabelExt(label_state);
1824 /* initialize delay counters */
1825 DelayReached(&scroll_delay, 0);
1826 DelayReached(&label_delay, 0);
1831 /* scroll micro level, if needed */
1832 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1833 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1835 switch (scroll_direction)
1841 scroll_direction = MV_UP;
1845 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1848 scroll_direction = MV_DOWN;
1855 scroll_direction = MV_RIGHT;
1859 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1862 scroll_direction = MV_LEFT;
1869 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1872 /* redraw micro level label, if needed */
1873 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1874 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1875 strcmp(level.author, leveldir_current->name) != 0 &&
1876 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1878 int max_label_counter = 23;
1880 if (leveldir_current->imported_from != NULL)
1881 max_label_counter += 14;
1883 label_counter = (label_counter + 1) % max_label_counter;
1884 label_state = (label_counter >= 0 && label_counter <= 7 ?
1885 MICROLABEL_LEVEL_NAME :
1886 label_counter >= 9 && label_counter <= 12 ?
1887 MICROLABEL_CREATED_BY :
1888 label_counter >= 14 && label_counter <= 21 ?
1889 MICROLABEL_LEVEL_AUTHOR :
1890 label_counter >= 23 && label_counter <= 26 ?
1891 MICROLABEL_IMPORTED_FROM :
1892 label_counter >= 28 && label_counter <= 35 ?
1893 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1894 DrawMicroLevelLabelExt(label_state);
1898 int REQ_in_range(int x, int y)
1900 if (y > DY+249 && y < DY+278)
1902 if (x > DX+1 && x < DX+48)
1904 else if (x > DX+51 && x < DX+98)
1910 #define MAX_REQUEST_LINES 13
1911 #define MAX_REQUEST_LINE_LEN 7
1913 boolean Request(char *text, unsigned int req_state)
1915 int mx, my, ty, result = -1;
1916 unsigned int old_door_state;
1918 #if defined(PLATFORM_UNIX)
1919 /* pause network game while waiting for request to answer */
1920 if (options.network &&
1921 game_status == PLAYING &&
1922 req_state & REQUEST_WAIT_FOR)
1923 SendToServer_PausePlaying();
1926 old_door_state = GetDoorState();
1930 CloseDoor(DOOR_CLOSE_1);
1932 /* save old door content */
1933 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
1934 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1935 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1937 /* clear door drawing field */
1938 ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1940 /* write text for request */
1941 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1943 char text_line[MAX_REQUEST_LINE_LEN + 1];
1949 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1952 if (!tc || tc == ' ')
1963 strncpy(text_line, text, tl);
1966 DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1967 text_line, FS_SMALL, FC_YELLOW);
1969 text += tl + (tc == ' ' ? 1 : 0);
1972 if (req_state & REQ_ASK)
1974 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1975 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1977 else if (req_state & REQ_CONFIRM)
1979 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1981 else if (req_state & REQ_PLAYER)
1983 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1984 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1985 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1986 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1989 /* copy request gadgets to door backbuffer */
1990 BlitBitmap(drawto, pix[PIX_DB_DOOR],
1991 DX, DY, DXSIZE, DYSIZE,
1992 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1994 OpenDoor(DOOR_OPEN_1);
2000 if (!(req_state & REQUEST_WAIT_FOR))
2003 if (game_status != MAINMENU)
2006 button_status = MB_RELEASED;
2008 request_gadget_id = -1;
2020 case EVENT_BUTTONPRESS:
2021 case EVENT_BUTTONRELEASE:
2022 case EVENT_MOTIONNOTIFY:
2024 if (event.type == EVENT_MOTIONNOTIFY)
2026 if (!PointerInWindow(window))
2027 continue; /* window and pointer are on different screens */
2032 motion_status = TRUE;
2033 mx = ((MotionEvent *) &event)->x;
2034 my = ((MotionEvent *) &event)->y;
2038 motion_status = FALSE;
2039 mx = ((ButtonEvent *) &event)->x;
2040 my = ((ButtonEvent *) &event)->y;
2041 if (event.type == EVENT_BUTTONPRESS)
2042 button_status = ((ButtonEvent *) &event)->button;
2044 button_status = MB_RELEASED;
2047 /* this sets 'request_gadget_id' */
2048 HandleGadgets(mx, my, button_status);
2050 switch(request_gadget_id)
2052 case TOOL_CTRL_ID_YES:
2055 case TOOL_CTRL_ID_NO:
2058 case TOOL_CTRL_ID_CONFIRM:
2059 result = TRUE | FALSE;
2062 case TOOL_CTRL_ID_PLAYER_1:
2065 case TOOL_CTRL_ID_PLAYER_2:
2068 case TOOL_CTRL_ID_PLAYER_3:
2071 case TOOL_CTRL_ID_PLAYER_4:
2082 case EVENT_KEYPRESS:
2083 switch(GetEventKey((KeyEvent *)&event, TRUE))
2096 if (req_state & REQ_PLAYER)
2100 case EVENT_KEYRELEASE:
2101 ClearPlayerAction();
2105 HandleOtherEvents(&event);
2109 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2111 int joy = AnyJoystick();
2113 if (joy & JOY_BUTTON_1)
2115 else if (joy & JOY_BUTTON_2)
2121 /* don't eat all CPU time */
2125 if (game_status != MAINMENU)
2130 if (!(req_state & REQ_STAY_OPEN))
2132 CloseDoor(DOOR_CLOSE_1);
2134 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2136 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2137 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2138 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2139 OpenDoor(DOOR_OPEN_1);
2145 #if defined(PLATFORM_UNIX)
2146 /* continue network game after request */
2147 if (options.network &&
2148 game_status == PLAYING &&
2149 req_state & REQUEST_WAIT_FOR)
2150 SendToServer_ContinuePlaying();
2156 unsigned int OpenDoor(unsigned int door_state)
2158 unsigned int new_door_state;
2160 if (door_state & DOOR_COPY_BACK)
2162 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2163 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2164 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2165 door_state &= ~DOOR_COPY_BACK;
2168 new_door_state = MoveDoor(door_state);
2170 return(new_door_state);
2173 unsigned int CloseDoor(unsigned int door_state)
2175 unsigned int new_door_state;
2177 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2178 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2179 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2180 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2182 new_door_state = MoveDoor(door_state);
2184 return(new_door_state);
2187 unsigned int GetDoorState()
2189 return MoveDoor(DOOR_GET_STATE);
2192 unsigned int SetDoorState(unsigned int door_state)
2194 return MoveDoor(door_state | DOOR_SET_STATE);
2197 unsigned int MoveDoor(unsigned int door_state)
2199 static int door1 = DOOR_OPEN_1;
2200 static int door2 = DOOR_CLOSE_2;
2201 static unsigned long door_delay = 0;
2202 int x, start, stepsize = 2;
2203 unsigned long door_delay_value = stepsize * 5;
2205 if (door_state == DOOR_GET_STATE)
2206 return(door1 | door2);
2208 if (door_state & DOOR_SET_STATE)
2210 if (door_state & DOOR_ACTION_1)
2211 door1 = door_state & DOOR_ACTION_1;
2212 if (door_state & DOOR_ACTION_2)
2213 door2 = door_state & DOOR_ACTION_2;
2215 return(door1 | door2);
2218 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2219 door_state &= ~DOOR_OPEN_1;
2220 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2221 door_state &= ~DOOR_CLOSE_1;
2222 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2223 door_state &= ~DOOR_OPEN_2;
2224 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2225 door_state &= ~DOOR_CLOSE_2;
2227 if (setup.quick_doors)
2230 door_delay_value = 0;
2231 StopSound(SND_MENU_DOOR_OPENING);
2232 StopSound(SND_MENU_DOOR_CLOSING);
2235 if (door_state & DOOR_ACTION)
2237 if (!(door_state & DOOR_NO_DELAY))
2239 /* opening door sound has priority over simultaneously closing door */
2240 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2241 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2242 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2243 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2246 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2248 for(x=start; x<=DXSIZE; x+=stepsize)
2250 Bitmap *bitmap = pix[PIX_DOOR];
2251 GC gc = bitmap->stored_clip_gc;
2253 WaitUntilDelayReached(&door_delay, door_delay_value);
2255 if (door_state & DOOR_ACTION_1)
2257 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2258 int j = (DXSIZE - i) / 3;
2260 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2261 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2262 DXSIZE,DYSIZE - i/2, DX, DY);
2264 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2266 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2267 BlitBitmapMasked(bitmap, drawto,
2268 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2269 DX + DXSIZE - i, DY + j);
2270 BlitBitmapMasked(bitmap, drawto,
2271 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2272 DX + DXSIZE - i, DY + 140 + j);
2273 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2274 BlitBitmapMasked(bitmap, drawto,
2275 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2277 BlitBitmapMasked(bitmap, drawto,
2278 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2281 BlitBitmapMasked(bitmap, drawto,
2282 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2284 BlitBitmapMasked(bitmap, drawto,
2285 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2287 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2288 BlitBitmapMasked(bitmap, drawto,
2289 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2290 DX + DXSIZE - i, DY + 77 + j);
2291 BlitBitmapMasked(bitmap, drawto,
2292 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2293 DX + DXSIZE - i, DY + 203 + j);
2295 redraw_mask |= REDRAW_DOOR_1;
2298 if (door_state & DOOR_ACTION_2)
2300 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2301 int j = (VXSIZE - i) / 3;
2303 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2304 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2305 VXSIZE, VYSIZE - i/2, VX, VY);
2307 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2309 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2310 BlitBitmapMasked(bitmap, drawto,
2311 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2312 VX + VXSIZE-i, VY+j);
2313 SetClipOrigin(bitmap, gc,
2314 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2315 BlitBitmapMasked(bitmap, drawto,
2316 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2319 BlitBitmapMasked(bitmap, drawto,
2320 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2321 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2322 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2323 BlitBitmapMasked(bitmap, drawto,
2324 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2326 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2328 redraw_mask |= REDRAW_DOOR_2;
2333 if (game_status == MAINMENU)
2338 if (setup.quick_doors)
2340 StopSound(SND_MENU_DOOR_OPENING);
2341 StopSound(SND_MENU_DOOR_CLOSING);
2344 if (door_state & DOOR_ACTION_1)
2345 door1 = door_state & DOOR_ACTION_1;
2346 if (door_state & DOOR_ACTION_2)
2347 door2 = door_state & DOOR_ACTION_2;
2349 return (door1 | door2);
2352 void DrawSpecialEditorDoor()
2354 /* draw bigger toolbox window */
2355 BlitBitmap(pix[PIX_DOOR], drawto,
2356 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2358 redraw_mask |= REDRAW_ALL;
2361 void UndrawSpecialEditorDoor()
2363 /* draw normal tape recorder window */
2364 BlitBitmap(pix[PIX_BACK], drawto,
2365 562, 344, 108, 56, EX - 4, EY - 12);
2367 redraw_mask |= REDRAW_ALL;
2371 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2373 XImage *pixel_image;
2374 unsigned long pixel_value;
2376 pixel_image = XGetImage(display, bitmap->drawable,
2377 x, y, 1, 1, AllPlanes, ZPixmap);
2378 pixel_value = XGetPixel(pixel_image, 0, 0);
2380 XDestroyImage(pixel_image);
2386 /* ---------- new tool button stuff ---------------------------------------- */
2388 /* graphic position values for tool buttons */
2389 #define TOOL_BUTTON_YES_XPOS 2
2390 #define TOOL_BUTTON_YES_YPOS 250
2391 #define TOOL_BUTTON_YES_GFX_YPOS 0
2392 #define TOOL_BUTTON_YES_XSIZE 46
2393 #define TOOL_BUTTON_YES_YSIZE 28
2394 #define TOOL_BUTTON_NO_XPOS 52
2395 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2396 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2397 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2398 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2399 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2400 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2401 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2402 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2403 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2404 #define TOOL_BUTTON_PLAYER_XSIZE 30
2405 #define TOOL_BUTTON_PLAYER_YSIZE 30
2406 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2407 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2408 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2409 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2410 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2411 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2412 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2413 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2414 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2415 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2416 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2417 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2418 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2419 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2420 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2421 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2422 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2423 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2424 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2425 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2434 } toolbutton_info[NUM_TOOL_BUTTONS] =
2437 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2438 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2439 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2444 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2445 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2446 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2451 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2452 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2453 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2454 TOOL_CTRL_ID_CONFIRM,
2458 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2459 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2460 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2461 TOOL_CTRL_ID_PLAYER_1,
2465 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2466 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2467 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2468 TOOL_CTRL_ID_PLAYER_2,
2472 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2473 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2474 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2475 TOOL_CTRL_ID_PLAYER_3,
2479 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2480 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2481 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2482 TOOL_CTRL_ID_PLAYER_4,
2487 void CreateToolButtons()
2491 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2493 Bitmap *gd_bitmap = pix[PIX_DOOR];
2494 Bitmap *deco_bitmap = None;
2495 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2496 struct GadgetInfo *gi;
2497 unsigned long event_mask;
2498 int gd_xoffset, gd_yoffset;
2499 int gd_x1, gd_x2, gd_y;
2502 event_mask = GD_EVENT_RELEASED;
2504 gd_xoffset = toolbutton_info[i].xpos;
2505 gd_yoffset = toolbutton_info[i].ypos;
2506 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2507 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2508 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2510 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2512 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2514 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2515 &deco_bitmap, &deco_x, &deco_y);
2516 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2517 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2520 gi = CreateGadget(GDI_CUSTOM_ID, id,
2521 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2522 GDI_X, DX + toolbutton_info[i].x,
2523 GDI_Y, DY + toolbutton_info[i].y,
2524 GDI_WIDTH, toolbutton_info[i].width,
2525 GDI_HEIGHT, toolbutton_info[i].height,
2526 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2527 GDI_STATE, GD_BUTTON_UNPRESSED,
2528 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2529 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2530 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2531 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2532 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2533 GDI_DECORATION_SHIFTING, 1, 1,
2534 GDI_EVENT_MASK, event_mask,
2535 GDI_CALLBACK_ACTION, HandleToolButtons,
2539 Error(ERR_EXIT, "cannot create gadget");
2541 tool_gadget[id] = gi;
2545 static void UnmapToolButtons()
2549 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2550 UnmapGadget(tool_gadget[i]);
2553 static void HandleToolButtons(struct GadgetInfo *gi)
2555 request_gadget_id = gi->custom_id;
2558 int get_next_element(int element)
2562 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2563 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2564 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2565 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2566 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2567 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2568 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2570 default: return element;
2574 int el2gfx_OLD(int element)
2578 case EL_EMPTY: return -1;
2579 case EL_SAND: return GFX_ERDREICH;
2580 case EL_WALL: return GFX_MAUERWERK;
2581 case EL_WALL_CRUMBLED: return GFX_FELSBODEN;
2582 case EL_ROCK: return GFX_FELSBROCKEN;
2583 case EL_EMERALD: return GFX_EDELSTEIN;
2584 case EL_EXIT_CLOSED: return GFX_AUSGANG_ZU;
2585 case EL_EXIT_OPENING: return GFX_AUSGANG_ACT;
2586 case EL_EXIT_OPEN: return GFX_AUSGANG_AUF;
2587 case EL_SP_EXIT_OPEN: return GFX_SP_EXIT;
2588 case EL_PLAYER1: return GFX_SPIELER1;
2589 case EL_PLAYER2: return GFX_SPIELER2;
2590 case EL_PLAYER3: return GFX_SPIELER3;
2591 case EL_PLAYER4: return GFX_SPIELER4;
2592 case EL_BUG: return GFX_KAEFER;
2593 case EL_BUG_RIGHT: return GFX_KAEFER_RIGHT;
2594 case EL_BUG_UP: return GFX_KAEFER_UP;
2595 case EL_BUG_LEFT: return GFX_KAEFER_LEFT;
2596 case EL_BUG_DOWN: return GFX_KAEFER_DOWN;
2597 case EL_SPACESHIP: return GFX_FLIEGER;
2598 case EL_SPACESHIP_RIGHT: return GFX_FLIEGER_RIGHT;
2599 case EL_SPACESHIP_UP: return GFX_FLIEGER_UP;
2600 case EL_SPACESHIP_LEFT: return GFX_FLIEGER_LEFT;
2601 case EL_SPACESHIP_DOWN: return GFX_FLIEGER_DOWN;
2602 case EL_BD_BUTTERFLY: return GFX_BUTTERFLY;
2603 case EL_BD_BUTTERFLY_RIGHT: return GFX_BUTTERFLY_RIGHT;
2604 case EL_BD_BUTTERFLY_UP: return GFX_BUTTERFLY_UP;
2605 case EL_BD_BUTTERFLY_LEFT: return GFX_BUTTERFLY_LEFT;
2606 case EL_BD_BUTTERFLY_DOWN: return GFX_BUTTERFLY_DOWN;
2607 case EL_BD_FIREFLY: return GFX_FIREFLY;
2608 case EL_BD_FIREFLY_RIGHT: return GFX_FIREFLY_RIGHT;
2609 case EL_BD_FIREFLY_UP: return GFX_FIREFLY_UP;
2610 case EL_BD_FIREFLY_LEFT: return GFX_FIREFLY_LEFT;
2611 case EL_BD_FIREFLY_DOWN: return GFX_FIREFLY_DOWN;
2612 case EL_YAMYAM: return GFX_MAMPFER;
2613 case EL_ROBOT: return GFX_ROBOT;
2614 case EL_STEELWALL: return GFX_BETON;
2615 case EL_DIAMOND: return GFX_DIAMANT;
2616 case EL_QUICKSAND_EMPTY: return GFX_MORAST_LEER;
2617 case EL_QUICKSAND_FULL: return GFX_MORAST_VOLL;
2618 case EL_QUICKSAND_EMPTYING: return GFX_MORAST_LEER;
2619 case EL_AMOEBA_DROP: return GFX_TROPFEN;
2620 case EL_BOMB: return GFX_BOMBE;
2621 case EL_MAGIC_WALL: return GFX_MAGIC_WALL_OFF;
2622 case EL_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_EMPTY;
2623 case EL_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_EMPTY;
2624 case EL_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_FULL;
2625 case EL_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_DEAD;
2626 case EL_ACID: return GFX_SALZSAEURE;
2627 case EL_AMOEBA_DEAD: return GFX_AMOEBE_TOT;
2628 case EL_AMOEBA_WET: return GFX_AMOEBE_NASS;
2629 case EL_AMOEBA_DRY: return GFX_AMOEBE_NORM;
2630 case EL_AMOEBA_FULL: return GFX_AMOEBE_VOLL;
2631 case EL_BD_AMOEBA: return GFX_AMOEBE_BD;
2632 case EL_AMOEBA_TO_DIAMOND: return GFX_AMOEBA2DIAM;
2633 case EL_AMOEBA_DRIPPING: return GFX_AMOEBE_NASS;
2634 case EL_NUT: return GFX_KOKOSNUSS;
2635 case EL_GAMEOFLIFE: return GFX_LIFE;
2636 case EL_BIOMAZE: return GFX_LIFE_ASYNC;
2637 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2638 case EL_STONEBLOCK: return GFX_BADEWANNE;
2639 case EL_ACIDPOOL_TOPLEFT: return GFX_BADEWANNE1;
2640 case EL_ACIDPOOL_TOPRIGHT: return GFX_BADEWANNE2;
2641 case EL_ACIDPOOL_BOTTOMLEFT: return GFX_BADEWANNE3;
2642 case EL_ACIDPOOL_BOTTOM: return GFX_BADEWANNE4;
2643 case EL_ACIDPOOL_BOTTOMRIGHT: return GFX_BADEWANNE5;
2644 case EL_ROBOT_WHEEL: return GFX_ABLENK_AUS;
2645 case EL_ROBOT_WHEEL_ACTIVE: return GFX_ABLENK_EIN;
2646 case EL_KEY1: return GFX_SCHLUESSEL1;
2647 case EL_KEY2: return GFX_SCHLUESSEL2;
2648 case EL_KEY3: return GFX_SCHLUESSEL3;
2649 case EL_KEY4: return GFX_SCHLUESSEL4;
2650 case EL_GATE1: return GFX_PFORTE1;
2651 case EL_GATE2: return GFX_PFORTE2;
2652 case EL_GATE3: return GFX_PFORTE3;
2653 case EL_GATE4: return GFX_PFORTE4;
2654 case EL_GATE1_GRAY: return GFX_PFORTE1X;
2655 case EL_GATE2_GRAY: return GFX_PFORTE2X;
2656 case EL_GATE3_GRAY: return GFX_PFORTE3X;
2657 case EL_GATE4_GRAY: return GFX_PFORTE4X;
2658 case EL_DYNAMITE: return GFX_DYNAMIT_AUS;
2659 case EL_PACMAN: return GFX_PACMAN;
2660 case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT;
2661 case EL_PACMAN_UP: return GFX_PACMAN_UP;
2662 case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT;
2663 case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN;
2664 case EL_INVISIBLE_WALL: return GFX_UNSICHTBAR;
2665 case EL_INVISIBLE_WALL_ACTIVE: return GFX_UNSICHTBAR_ON;
2666 case EL_WALL_EMERALD: return GFX_ERZ_EDEL;
2667 case EL_WALL_DIAMOND: return GFX_ERZ_DIAM;
2668 case EL_LAMP: return GFX_BIRNE_AUS;
2669 case EL_LAMP_ACTIVE: return GFX_BIRNE_EIN;
2670 case EL_TIME_ORB_FULL: return GFX_ZEIT_VOLL;
2671 case EL_TIME_ORB_EMPTY: return GFX_ZEIT_LEER;
2672 case EL_WALL_GROWING: return GFX_MAUER_LEBT;
2673 case EL_WALL_GROWING_X: return GFX_MAUER_X;
2674 case EL_WALL_GROWING_Y: return GFX_MAUER_Y;
2675 case EL_WALL_GROWING_XY: return GFX_MAUER_XY;
2676 case EL_BD_DIAMOND: return GFX_EDELSTEIN_BD;
2677 case EL_EMERALD_YELLOW: return GFX_EDELSTEIN_GELB;
2678 case EL_EMERALD_RED: return GFX_EDELSTEIN_ROT;
2679 case EL_EMERALD_PURPLE: return GFX_EDELSTEIN_LILA;
2680 case EL_WALL_BD_DIAMOND: return GFX_ERZ_EDEL_BD;
2681 case EL_WALL_EMERALD_YELLOW: return GFX_ERZ_EDEL_GELB;
2682 case EL_WALL_EMERALD_RED: return GFX_ERZ_EDEL_ROT;
2683 case EL_WALL_EMERALD_PURPLE: return GFX_ERZ_EDEL_LILA;
2684 case EL_DARK_YAMYAM: return GFX_MAMPFER2;
2685 case EL_BD_MAGIC_WALL: return GFX_MAGIC_WALL_BD_OFF;
2686 case EL_BD_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_BD_EMPTY;
2687 case EL_BD_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_BD_EMPTY;
2688 case EL_BD_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_BD_FULL;
2689 case EL_BD_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2690 case EL_DYNABOMB_PLAYER1_ACTIVE: return GFX_DYNABOMB;
2691 case EL_DYNABOMB_PLAYER2_ACTIVE: return GFX_DYNABOMB;
2692 case EL_DYNABOMB_PLAYER3_ACTIVE: return GFX_DYNABOMB;
2693 case EL_DYNABOMB_PLAYER4_ACTIVE: return GFX_DYNABOMB;
2694 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2695 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2696 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2697 case EL_SOKOBAN_OBJECT: return GFX_SOKOBAN_OBJEKT;
2698 case EL_SOKOBAN_FIELD_EMPTY: return GFX_SOKOBAN_FELD_LEER;
2699 case EL_SOKOBAN_FIELD_FULL: return GFX_SOKOBAN_FELD_VOLL;
2700 case EL_MOLE: return GFX_MOLE;
2701 case EL_PENGUIN: return GFX_PINGUIN;
2702 case EL_PIG: return GFX_SCHWEIN;
2703 case EL_DRAGON: return GFX_DRACHE;
2704 case EL_SATELLITE: return GFX_SONDE;
2705 case EL_ARROW_BLUE_LEFT: return GFX_PFEIL_LEFT;
2706 case EL_ARROW_BLUE_RIGHT: return GFX_PFEIL_RIGHT;
2707 case EL_ARROW_BLUE_UP: return GFX_PFEIL_UP;
2708 case EL_ARROW_BLUE_DOWN: return GFX_PFEIL_DOWN;
2709 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2710 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2711 case EL_SP_BUGGY_BASE_ACTIVE: return GFX_SP_BUG_ACTIVE;
2712 case EL_SP_ZONK: return GFX_SP_ZONK;
2713 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2714 case EL_INVISIBLE_STEELWALL: return GFX_INVISIBLE_STEEL;
2715 case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2716 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2717 case EL_EM_GATE1: return GFX_EM_GATE_1;
2718 case EL_EM_GATE2: return GFX_EM_GATE_2;
2719 case EL_EM_GATE3: return GFX_EM_GATE_3;
2720 case EL_EM_GATE4: return GFX_EM_GATE_4;
2721 case EL_EM_GATE1_GRAY: return GFX_EM_GATE_1X;
2722 case EL_EM_GATE2_GRAY: return GFX_EM_GATE_2X;
2723 case EL_EM_GATE3_GRAY: return GFX_EM_GATE_3X;
2724 case EL_EM_GATE4_GRAY: return GFX_EM_GATE_4X;
2725 case EL_EM_KEY1_FILE: return GFX_EM_KEY_1;
2726 case EL_EM_KEY2_FILE: return GFX_EM_KEY_2;
2727 case EL_EM_KEY3_FILE: return GFX_EM_KEY_3;
2728 case EL_EM_KEY4_FILE: return GFX_EM_KEY_4;
2729 case EL_EM_KEY1: return GFX_EM_KEY_1;
2730 case EL_EM_KEY2: return GFX_EM_KEY_2;
2731 case EL_EM_KEY3: return GFX_EM_KEY_3;
2732 case EL_EM_KEY4: return GFX_EM_KEY_4;
2733 case EL_PEARL: return GFX_PEARL;
2734 case EL_CRYSTAL: return GFX_CRYSTAL;
2735 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2736 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2737 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2738 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2739 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2740 case EL_SHIELD_NORMAL: return GFX_SHIELD_PASSIVE;
2741 case EL_SHIELD_DEADLY: return GFX_SHIELD_ACTIVE;
2742 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2743 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2744 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2745 case EL_SWITCHGATE_SWITCH_UP: return GFX_SWITCHGATE_SWITCH_1;
2746 case EL_SWITCHGATE_SWITCH_DOWN: return GFX_SWITCHGATE_SWITCH_2;
2747 case EL_CONVEYOR_BELT1_LEFT: return GFX_BELT1_LEFT;
2748 case EL_CONVEYOR_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2749 case EL_CONVEYOR_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2750 case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2751 case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2752 case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2753 case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2754 case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2755 case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2756 case EL_CONVEYOR_BELT2_LEFT: return GFX_BELT2_LEFT;
2757 case EL_CONVEYOR_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2758 case EL_CONVEYOR_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2759 case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2760 case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2761 case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2762 case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2763 case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2764 case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2765 case EL_CONVEYOR_BELT3_LEFT: return GFX_BELT3_LEFT;
2766 case EL_CONVEYOR_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2767 case EL_CONVEYOR_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2768 case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2769 case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2770 case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2771 case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2772 case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2773 case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2774 case EL_CONVEYOR_BELT4_LEFT: return GFX_BELT4_LEFT;
2775 case EL_CONVEYOR_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2776 case EL_CONVEYOR_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2777 case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2778 case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2779 case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2780 case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2781 case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2782 case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2783 case EL_LANDMINE: return GFX_LANDMINE;
2784 case EL_ENVELOPE: return GFX_ENVELOPE;
2785 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH_OFF;
2786 case EL_LIGHT_SWITCH_ACTIVE: return GFX_LIGHT_SWITCH_ON;
2787 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2788 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2789 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2790 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2791 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2792 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2793 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2794 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2795 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2796 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2797 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2798 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2799 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2800 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2801 case EL_MOLE_UP: return GFX_MOLE_UP;
2802 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2803 case EL_STEELWALL_SLANTED: return GFX_STEEL_SLANTED;
2804 case EL_INVISIBLE_SAND: return GFX_SAND_INVISIBLE;
2805 case EL_INVISIBLE_SAND_ACTIVE: return GFX_SAND_INVISIBLE_ON;
2806 case EL_DX_UNKNOWN_15: return GFX_DX_UNKNOWN_15;
2807 case EL_DX_UNKNOWN_42: return GFX_DX_UNKNOWN_42;
2808 case EL_TIMEGATE_OPEN: return GFX_TIMEGATE_OPEN;
2809 case EL_TIMEGATE_CLOSED: return GFX_TIMEGATE_CLOSED;
2810 case EL_TIMEGATE_SWITCH_ACTIVE: return GFX_TIMEGATE_SWITCH;
2811 case EL_TIMEGATE_SWITCH: return GFX_TIMEGATE_SWITCH;
2812 case EL_BALLOON: return GFX_BALLOON;
2813 case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
2814 case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2815 case EL_BALLOON_SEND_UP: return GFX_BALLOON_SEND_UP;
2816 case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
2817 case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2818 case EL_EMC_STEELWALL1: return GFX_EMC_STEEL_WALL_1;
2819 case EL_EMC_STEELWALL2: return GFX_EMC_STEEL_WALL_2;
2820 case EL_EMC_STEELWALL3: return GFX_EMC_STEEL_WALL_3;
2821 case EL_EMC_STEELWALL4: return GFX_EMC_STEEL_WALL_4;
2822 case EL_EMC_WALL_PILLAR_UPPER: return GFX_EMC_WALL_1;
2823 case EL_EMC_WALL_PILLAR_MIDDLE: return GFX_EMC_WALL_2;
2824 case EL_EMC_WALL_PILLAR_LOWER: return GFX_EMC_WALL_3;
2825 case EL_EMC_WALL4: return GFX_EMC_WALL_4;
2826 case EL_EMC_WALL5: return GFX_EMC_WALL_5;
2827 case EL_EMC_WALL6: return GFX_EMC_WALL_6;
2828 case EL_EMC_WALL7: return GFX_EMC_WALL_7;
2829 case EL_EMC_WALL8: return GFX_EMC_WALL_8;
2830 case EL_TUBE_ALL: return GFX_TUBE_CROSS;
2831 case EL_TUBE_VERTICAL: return GFX_TUBE_VERTICAL;
2832 case EL_TUBE_HORIZONTAL: return GFX_TUBE_HORIZONTAL;
2833 case EL_TUBE_VERTICAL_LEFT: return GFX_TUBE_VERT_LEFT;
2834 case EL_TUBE_VERTICAL_RIGHT: return GFX_TUBE_VERT_RIGHT;
2835 case EL_TUBE_HORIZONTAL_UP: return GFX_TUBE_HORIZ_UP;
2836 case EL_TUBE_HORIZONTAL_DOWN: return GFX_TUBE_HORIZ_DOWN;
2837 case EL_TUBE_LEFT_UP: return GFX_TUBE_LEFT_UP;
2838 case EL_TUBE_LEFT_DOWN: return GFX_TUBE_LEFT_DOWN;
2839 case EL_TUBE_RIGHT_UP: return GFX_TUBE_RIGHT_UP;
2840 case EL_TUBE_RIGHT_DOWN: return GFX_TUBE_RIGHT_DOWN;
2841 case EL_SPRING: return GFX_SPRING;
2842 case EL_SPRING_MOVING: return GFX_SPRING;
2843 case EL_TRAP: return GFX_TRAP_INACTIVE;
2844 case EL_TRAP_ACTIVE: return GFX_TRAP_ACTIVE;
2845 case EL_BD_WALL: return GFX_BD_WALL;
2846 case EL_BD_ROCK: return GFX_BD_ROCK;
2847 case EL_DX_SUPABOMB: return GFX_DX_SUPABOMB;
2848 case EL_SP_MURPHY_CLONE: return GFX_SP_MURPHY_CLONE;
2852 if (IS_CHAR(element))
2853 return GFX_CHAR_START + (element - EL_CHAR_START);
2854 else if (element >= EL_SP_START && element <= EL_SP_END)
2856 int nr_element = element - EL_SP_START;
2857 int gfx_per_line = 8;
2859 (nr_element / gfx_per_line) * SP_PER_LINE +
2860 (nr_element % gfx_per_line);
2862 return GFX_START_ROCKSSP + nr_graphic;
2870 int el2gfx(int element)
2873 int graphic_OLD = el2gfx_OLD(element);
2878 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2881 int graphic_OLD = el2gfx_OLD(element);
2883 if (element >= MAX_ELEMENTS)
2885 Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
2888 if (graphic_NEW != graphic_OLD)
2890 Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2891 graphic_NEW, graphic_OLD);
2899 int el2img(int element)
2902 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2905 if (graphic_NEW < 0)
2906 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2907 element, graphic_NEW);
2915 case EL_BD_BUTTERFLY: return IMG_BD_BUTTERFLY;
2916 case EL_BD_FIREFLY: return IMG_BD_FIREFLY;
2917 case EL_SP_ELECTRON: return IMG_SP_ELECTRON;
2927 int el_dir2img(int element, int direction)
2929 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2932 int el_dir_act2img(int element, int direction, int action)
2934 action = graphics_action_mapping[action];
2935 direction = MV_DIR_BIT(direction);
2937 return element_info[element].direction_graphic[action][direction];