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 element = Feld[x][y];
1277 if (element == EL_QUICKSAND_FULL ||
1278 element == EL_MAGIC_WALL_FULL ||
1279 element == EL_BD_MAGIC_WALL_FULL)
1281 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1282 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1287 inline static int getGfxAction(int x, int y)
1289 int gfx_action = GFX_ACTION_DEFAULT;
1291 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1292 gfx_action = GfxAction[x][y];
1293 else if (IS_MOVING(x, y))
1294 gfx_action = GFX_ACTION_MOVING;
1299 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1300 int cut_mode, int mask_mode)
1302 int ux = LEVELX(x), uy = LEVELY(y);
1303 int move_dir = MovDir[ux][uy];
1304 int move_pos = getFramePosition(ux, uy);
1305 int gfx_action = getGfxAction(ux, uy);
1306 int graphic = el_dir_act2img(element, move_dir, gfx_action);
1307 int frame = getGraphicAnimationFrame(graphic, move_pos);
1309 if (element == EL_WALL_GROWING)
1311 boolean left_stopped = FALSE, right_stopped = FALSE;
1313 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1314 left_stopped = TRUE;
1315 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1316 right_stopped = TRUE;
1318 if (left_stopped && right_stopped)
1320 else if (left_stopped)
1322 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1323 frame = new_graphic_info[graphic].anim_frames - 1;
1325 else if (right_stopped)
1327 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1328 frame = new_graphic_info[graphic].anim_frames - 1;
1332 else if ((element == EL_ROCK ||
1333 element == EL_SP_ZONK ||
1334 element == EL_BD_ROCK ||
1335 element == EL_SP_INFOTRON ||
1339 if (uy >= lev_fieldy-1 || !IS_BELT(Feld[ux][uy+1]))
1341 if (element == EL_ROCK ||
1342 element == EL_SP_ZONK ||
1343 element == EL_BD_ROCK)
1345 if (move_dir == MV_LEFT)
1346 graphic += (4 - phase4) % 4;
1347 else if (move_dir == MV_RIGHT)
1350 graphic += phase2 * 2;
1352 else if (element != EL_SP_INFOTRON)
1357 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1359 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1360 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1361 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1362 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1363 IMG_AMOEBA_DEAD_PART1);
1365 graphic += (x + 2 * y + 4) % 4;
1369 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1370 else if (mask_mode == USE_MASKING)
1371 DrawGraphicThruMask(x, y, graphic, frame);
1373 DrawGraphic(x, y, graphic, frame);
1376 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1377 int cut_mode, int mask_mode)
1379 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1380 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1381 cut_mode, mask_mode);
1384 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1387 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1390 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1393 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1397 void DrawOldScreenElementThruMask(int x, int y, int element)
1399 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1402 void DrawScreenElementThruMask(int x, int y, int element)
1404 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1408 void DrawLevelElementThruMask(int x, int y, int element)
1410 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1413 void DrawLevelFieldThruMask(int x, int y)
1415 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1418 void DrawCrumbledSand(int x, int y)
1422 int i, width, height, cx,cy;
1423 int ux = LEVELX(x), uy = LEVELY(y);
1424 int element, graphic;
1426 static int xy[4][2] =
1434 if (!IN_LEV_FIELD(ux, uy))
1437 element = Feld[ux][uy];
1439 if (element == EL_SAND ||
1440 element == EL_LANDMINE ||
1441 element == EL_TRAP ||
1442 element == EL_TRAP_ACTIVE)
1444 if (!IN_SCR_FIELD(x, y))
1447 graphic = IMG_SAND_CRUMBLED;
1449 src_bitmap = new_graphic_info[graphic].bitmap;
1450 src_x = new_graphic_info[graphic].src_x;
1451 src_y = new_graphic_info[graphic].src_y;
1457 uxx = ux + xy[i][0];
1458 uyy = uy + xy[i][1];
1459 if (!IN_LEV_FIELD(uxx, uyy))
1460 element = EL_STEELWALL;
1462 element = Feld[uxx][uyy];
1464 if (element == EL_SAND ||
1465 element == EL_LANDMINE ||
1466 element == EL_TRAP ||
1467 element == EL_TRAP_ACTIVE)
1470 if (i == 1 || i == 2)
1474 cx = (i == 2 ? TILEX - snip : 0);
1482 cy = (i == 3 ? TILEY - snip : 0);
1485 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1486 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1489 MarkTileDirty(x, y);
1493 graphic = IMG_SAND_CRUMBLED;
1495 src_bitmap = new_graphic_info[graphic].bitmap;
1496 src_x = new_graphic_info[graphic].src_x;
1497 src_y = new_graphic_info[graphic].src_y;
1501 int xx, yy, uxx, uyy;
1505 uxx = ux + xy[i][0];
1506 uyy = uy + xy[i][1];
1508 if (!IN_LEV_FIELD(uxx, uyy) ||
1509 (Feld[uxx][uyy] != EL_SAND &&
1510 Feld[uxx][uyy] != EL_LANDMINE &&
1511 Feld[uxx][uyy] != EL_TRAP &&
1512 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1513 !IN_SCR_FIELD(xx, yy))
1516 if (i == 1 || i == 2)
1520 cx = (i == 1 ? TILEX - snip : 0);
1528 cy = (i==0 ? TILEY-snip : 0);
1531 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1532 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1534 MarkTileDirty(xx, yy);
1539 void DrawScreenElement(int x, int y, int element)
1541 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1542 DrawCrumbledSand(x, y);
1545 void DrawLevelElement(int x, int y, int element)
1547 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1548 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1551 void DrawScreenField(int x, int y)
1553 int ux = LEVELX(x), uy = LEVELY(y);
1554 int element, content;
1556 if (!IN_LEV_FIELD(ux, uy))
1558 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1561 element = BorderElement;
1563 DrawScreenElement(x, y, element);
1567 element = Feld[ux][uy];
1568 content = Store[ux][uy];
1570 if (IS_MOVING(ux, uy))
1572 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1573 boolean cut_mode = NO_CUTTING;
1575 if (element == EL_QUICKSAND_EMPTYING ||
1576 element == EL_MAGIC_WALL_EMPTYING ||
1577 element == EL_BD_MAGIC_WALL_EMPTYING ||
1578 element == EL_AMOEBA_DRIPPING)
1579 cut_mode = CUT_ABOVE;
1580 else if (element == EL_QUICKSAND_FILLING ||
1581 element == EL_MAGIC_WALL_FILLING ||
1582 element == EL_BD_MAGIC_WALL_FILLING)
1583 cut_mode = CUT_BELOW;
1585 if (cut_mode == CUT_ABOVE)
1586 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1588 DrawScreenElement(x, y, EL_EMPTY);
1591 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1592 else if (cut_mode == NO_CUTTING)
1593 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1595 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1597 if (content == EL_ACID)
1598 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1600 else if (IS_BLOCKED(ux, uy))
1605 boolean cut_mode = NO_CUTTING;
1606 int element_old, content_old;
1608 Blocked2Moving(ux, uy, &oldx, &oldy);
1611 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1612 MovDir[oldx][oldy] == MV_RIGHT);
1614 element_old = Feld[oldx][oldy];
1615 content_old = Store[oldx][oldy];
1617 if (element_old == EL_QUICKSAND_EMPTYING ||
1618 element_old == EL_MAGIC_WALL_EMPTYING ||
1619 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1620 element_old == EL_AMOEBA_DRIPPING)
1621 cut_mode = CUT_ABOVE;
1623 DrawScreenElement(x, y, EL_EMPTY);
1626 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1628 else if (cut_mode == NO_CUTTING)
1629 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1632 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1635 else if (IS_DRAWABLE(element))
1636 DrawScreenElement(x, y, element);
1638 DrawScreenElement(x, y, EL_EMPTY);
1641 void DrawLevelField(int x, int y)
1643 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1644 DrawScreenField(SCREENX(x), SCREENY(y));
1645 else if (IS_MOVING(x, y))
1649 Moving2Blocked(x, y, &newx, &newy);
1650 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1651 DrawScreenField(SCREENX(newx), SCREENY(newy));
1653 else if (IS_BLOCKED(x, y))
1657 Blocked2Moving(x, y, &oldx, &oldy);
1658 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1659 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1663 void DrawMiniElement(int x, int y, int element)
1667 graphic = el2img(element);
1668 DrawMiniGraphic(x, y, graphic);
1671 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1673 int x = sx + scroll_x, y = sy + scroll_y;
1675 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1676 DrawMiniElement(sx, sy, EL_EMPTY);
1677 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1678 DrawMiniElement(sx, sy, Feld[x][y]);
1681 int steel_type, steel_position;
1684 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1685 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1686 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1687 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1688 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1689 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1692 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1693 steel_position = (x == -1 && y == -1 ? 0 :
1694 x == lev_fieldx && y == -1 ? 1 :
1695 x == -1 && y == lev_fieldy ? 2 :
1696 x == lev_fieldx && y == lev_fieldy ? 3 :
1697 x == -1 || x == lev_fieldx ? 4 :
1698 y == -1 || y == lev_fieldy ? 5 : -1);
1700 if (steel_position != -1)
1701 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1705 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1707 Bitmap *src_bitmap = new_graphic_info[graphic].bitmap;
1708 int mini_startx = src_bitmap->width * 3 / 4;
1709 int mini_starty = src_bitmap->height * 2 / 3;
1710 int src_x = mini_startx + new_graphic_info[graphic].src_x / 8;
1711 int src_y = mini_starty + new_graphic_info[graphic].src_y / 8;
1713 *bitmap = src_bitmap;
1718 void DrawMicroElement(int xpos, int ypos, int element)
1724 if (element == EL_EMPTY)
1727 graphic = el2img(element);
1729 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1730 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1740 for(x=BX1; x<=BX2; x++)
1741 for(y=BY1; y<=BY2; y++)
1742 DrawScreenField(x, y);
1744 redraw_mask |= REDRAW_FIELD;
1747 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1751 for(x=0; x<size_x; x++)
1752 for(y=0; y<size_y; y++)
1753 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1755 redraw_mask |= REDRAW_FIELD;
1758 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1762 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1764 if (lev_fieldx < STD_LEV_FIELDX)
1765 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1766 if (lev_fieldy < STD_LEV_FIELDY)
1767 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1769 xpos += MICRO_TILEX;
1770 ypos += MICRO_TILEY;
1772 for(x=-1; x<=STD_LEV_FIELDX; x++)
1774 for(y=-1; y<=STD_LEV_FIELDY; y++)
1776 int lx = from_x + x, ly = from_y + y;
1778 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1779 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1781 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1)
1782 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1787 redraw_mask |= REDRAW_MICROLEVEL;
1790 #define MICROLABEL_EMPTY 0
1791 #define MICROLABEL_LEVEL_NAME 1
1792 #define MICROLABEL_CREATED_BY 2
1793 #define MICROLABEL_LEVEL_AUTHOR 3
1794 #define MICROLABEL_IMPORTED_FROM 4
1795 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1797 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1799 static void DrawMicroLevelLabelExt(int mode)
1801 char label_text[MAX_MICROLABEL_SIZE + 1];
1803 ClearRectangle(drawto, SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1805 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1806 mode == MICROLABEL_CREATED_BY ? "created by" :
1807 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1808 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1809 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1810 leveldir_current->imported_from : ""),
1811 MAX_MICROLABEL_SIZE);
1812 label_text[MAX_MICROLABEL_SIZE] = '\0';
1814 if (strlen(label_text) > 0)
1816 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1817 int lypos = MICROLABEL_YPOS;
1819 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1822 redraw_mask |= REDRAW_MICROLEVEL;
1825 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1827 static unsigned long scroll_delay = 0;
1828 static unsigned long label_delay = 0;
1829 static int from_x, from_y, scroll_direction;
1830 static int label_state, label_counter;
1834 from_x = from_y = 0;
1835 scroll_direction = MV_RIGHT;
1839 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1840 DrawMicroLevelLabelExt(label_state);
1842 /* initialize delay counters */
1843 DelayReached(&scroll_delay, 0);
1844 DelayReached(&label_delay, 0);
1849 /* scroll micro level, if needed */
1850 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1851 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1853 switch (scroll_direction)
1859 scroll_direction = MV_UP;
1863 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1866 scroll_direction = MV_DOWN;
1873 scroll_direction = MV_RIGHT;
1877 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1880 scroll_direction = MV_LEFT;
1887 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1890 /* redraw micro level label, if needed */
1891 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1892 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1893 strcmp(level.author, leveldir_current->name) != 0 &&
1894 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1896 int max_label_counter = 23;
1898 if (leveldir_current->imported_from != NULL)
1899 max_label_counter += 14;
1901 label_counter = (label_counter + 1) % max_label_counter;
1902 label_state = (label_counter >= 0 && label_counter <= 7 ?
1903 MICROLABEL_LEVEL_NAME :
1904 label_counter >= 9 && label_counter <= 12 ?
1905 MICROLABEL_CREATED_BY :
1906 label_counter >= 14 && label_counter <= 21 ?
1907 MICROLABEL_LEVEL_AUTHOR :
1908 label_counter >= 23 && label_counter <= 26 ?
1909 MICROLABEL_IMPORTED_FROM :
1910 label_counter >= 28 && label_counter <= 35 ?
1911 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1912 DrawMicroLevelLabelExt(label_state);
1916 int REQ_in_range(int x, int y)
1918 if (y > DY+249 && y < DY+278)
1920 if (x > DX+1 && x < DX+48)
1922 else if (x > DX+51 && x < DX+98)
1928 #define MAX_REQUEST_LINES 13
1929 #define MAX_REQUEST_LINE_LEN 7
1931 boolean Request(char *text, unsigned int req_state)
1933 int mx, my, ty, result = -1;
1934 unsigned int old_door_state;
1936 #if defined(PLATFORM_UNIX)
1937 /* pause network game while waiting for request to answer */
1938 if (options.network &&
1939 game_status == PLAYING &&
1940 req_state & REQUEST_WAIT_FOR)
1941 SendToServer_PausePlaying();
1944 old_door_state = GetDoorState();
1948 CloseDoor(DOOR_CLOSE_1);
1950 /* save old door content */
1951 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
1952 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1953 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1955 /* clear door drawing field */
1956 ClearRectangle(drawto, DX, DY, DXSIZE, DYSIZE);
1958 /* write text for request */
1959 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1961 char text_line[MAX_REQUEST_LINE_LEN + 1];
1967 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1970 if (!tc || tc == ' ')
1981 strncpy(text_line, text, tl);
1984 DrawTextExt(drawto, DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1985 text_line, FS_SMALL, FC_YELLOW);
1987 text += tl + (tc == ' ' ? 1 : 0);
1990 if (req_state & REQ_ASK)
1992 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1993 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1995 else if (req_state & REQ_CONFIRM)
1997 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1999 else if (req_state & REQ_PLAYER)
2001 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
2002 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
2003 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
2004 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
2007 /* copy request gadgets to door backbuffer */
2008 BlitBitmap(drawto, pix[PIX_DB_DOOR],
2009 DX, DY, DXSIZE, DYSIZE,
2010 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2012 OpenDoor(DOOR_OPEN_1);
2018 if (!(req_state & REQUEST_WAIT_FOR))
2021 if (game_status != MAINMENU)
2024 button_status = MB_RELEASED;
2026 request_gadget_id = -1;
2038 case EVENT_BUTTONPRESS:
2039 case EVENT_BUTTONRELEASE:
2040 case EVENT_MOTIONNOTIFY:
2042 if (event.type == EVENT_MOTIONNOTIFY)
2044 if (!PointerInWindow(window))
2045 continue; /* window and pointer are on different screens */
2050 motion_status = TRUE;
2051 mx = ((MotionEvent *) &event)->x;
2052 my = ((MotionEvent *) &event)->y;
2056 motion_status = FALSE;
2057 mx = ((ButtonEvent *) &event)->x;
2058 my = ((ButtonEvent *) &event)->y;
2059 if (event.type == EVENT_BUTTONPRESS)
2060 button_status = ((ButtonEvent *) &event)->button;
2062 button_status = MB_RELEASED;
2065 /* this sets 'request_gadget_id' */
2066 HandleGadgets(mx, my, button_status);
2068 switch(request_gadget_id)
2070 case TOOL_CTRL_ID_YES:
2073 case TOOL_CTRL_ID_NO:
2076 case TOOL_CTRL_ID_CONFIRM:
2077 result = TRUE | FALSE;
2080 case TOOL_CTRL_ID_PLAYER_1:
2083 case TOOL_CTRL_ID_PLAYER_2:
2086 case TOOL_CTRL_ID_PLAYER_3:
2089 case TOOL_CTRL_ID_PLAYER_4:
2100 case EVENT_KEYPRESS:
2101 switch(GetEventKey((KeyEvent *)&event, TRUE))
2114 if (req_state & REQ_PLAYER)
2118 case EVENT_KEYRELEASE:
2119 ClearPlayerAction();
2123 HandleOtherEvents(&event);
2127 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
2129 int joy = AnyJoystick();
2131 if (joy & JOY_BUTTON_1)
2133 else if (joy & JOY_BUTTON_2)
2139 /* don't eat all CPU time */
2143 if (game_status != MAINMENU)
2148 if (!(req_state & REQ_STAY_OPEN))
2150 CloseDoor(DOOR_CLOSE_1);
2152 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2154 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2155 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2156 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2157 OpenDoor(DOOR_OPEN_1);
2163 #if defined(PLATFORM_UNIX)
2164 /* continue network game after request */
2165 if (options.network &&
2166 game_status == PLAYING &&
2167 req_state & REQUEST_WAIT_FOR)
2168 SendToServer_ContinuePlaying();
2174 unsigned int OpenDoor(unsigned int door_state)
2176 unsigned int new_door_state;
2178 if (door_state & DOOR_COPY_BACK)
2180 BlitBitmap(pix[PIX_DB_DOOR], pix[PIX_DB_DOOR],
2181 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2182 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2183 door_state &= ~DOOR_COPY_BACK;
2186 new_door_state = MoveDoor(door_state);
2188 return(new_door_state);
2191 unsigned int CloseDoor(unsigned int door_state)
2193 unsigned int new_door_state;
2195 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2196 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2197 BlitBitmap(backbuffer, pix[PIX_DB_DOOR],
2198 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2200 new_door_state = MoveDoor(door_state);
2202 return(new_door_state);
2205 unsigned int GetDoorState()
2207 return MoveDoor(DOOR_GET_STATE);
2210 unsigned int SetDoorState(unsigned int door_state)
2212 return MoveDoor(door_state | DOOR_SET_STATE);
2215 unsigned int MoveDoor(unsigned int door_state)
2217 static int door1 = DOOR_OPEN_1;
2218 static int door2 = DOOR_CLOSE_2;
2219 static unsigned long door_delay = 0;
2220 int x, start, stepsize = 2;
2221 unsigned long door_delay_value = stepsize * 5;
2223 if (door_state == DOOR_GET_STATE)
2224 return(door1 | door2);
2226 if (door_state & DOOR_SET_STATE)
2228 if (door_state & DOOR_ACTION_1)
2229 door1 = door_state & DOOR_ACTION_1;
2230 if (door_state & DOOR_ACTION_2)
2231 door2 = door_state & DOOR_ACTION_2;
2233 return(door1 | door2);
2236 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2237 door_state &= ~DOOR_OPEN_1;
2238 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2239 door_state &= ~DOOR_CLOSE_1;
2240 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2241 door_state &= ~DOOR_OPEN_2;
2242 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2243 door_state &= ~DOOR_CLOSE_2;
2245 if (setup.quick_doors)
2248 door_delay_value = 0;
2249 StopSound(SND_MENU_DOOR_OPENING);
2250 StopSound(SND_MENU_DOOR_CLOSING);
2253 if (door_state & DOOR_ACTION)
2255 if (!(door_state & DOOR_NO_DELAY))
2257 /* opening door sound has priority over simultaneously closing door */
2258 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2259 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2260 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2261 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2264 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2266 for(x=start; x<=DXSIZE; x+=stepsize)
2268 Bitmap *bitmap = pix[PIX_DOOR];
2269 GC gc = bitmap->stored_clip_gc;
2271 WaitUntilDelayReached(&door_delay, door_delay_value);
2273 if (door_state & DOOR_ACTION_1)
2275 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2276 int j = (DXSIZE - i) / 3;
2278 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2279 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2280 DXSIZE,DYSIZE - i/2, DX, DY);
2282 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2284 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2285 BlitBitmapMasked(bitmap, drawto,
2286 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2287 DX + DXSIZE - i, DY + j);
2288 BlitBitmapMasked(bitmap, drawto,
2289 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2290 DX + DXSIZE - i, DY + 140 + j);
2291 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2292 BlitBitmapMasked(bitmap, drawto,
2293 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2295 BlitBitmapMasked(bitmap, drawto,
2296 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2299 BlitBitmapMasked(bitmap, drawto,
2300 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2302 BlitBitmapMasked(bitmap, drawto,
2303 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2305 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2306 BlitBitmapMasked(bitmap, drawto,
2307 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2308 DX + DXSIZE - i, DY + 77 + j);
2309 BlitBitmapMasked(bitmap, drawto,
2310 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2311 DX + DXSIZE - i, DY + 203 + j);
2313 redraw_mask |= REDRAW_DOOR_1;
2316 if (door_state & DOOR_ACTION_2)
2318 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2319 int j = (VXSIZE - i) / 3;
2321 BlitBitmap(pix[PIX_DB_DOOR], drawto,
2322 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2323 VXSIZE, VYSIZE - i/2, VX, VY);
2325 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2327 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2328 BlitBitmapMasked(bitmap, drawto,
2329 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2330 VX + VXSIZE-i, VY+j);
2331 SetClipOrigin(bitmap, gc,
2332 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2333 BlitBitmapMasked(bitmap, drawto,
2334 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2337 BlitBitmapMasked(bitmap, drawto,
2338 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2339 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2340 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2341 BlitBitmapMasked(bitmap, drawto,
2342 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2344 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2346 redraw_mask |= REDRAW_DOOR_2;
2351 if (game_status == MAINMENU)
2356 if (setup.quick_doors)
2358 StopSound(SND_MENU_DOOR_OPENING);
2359 StopSound(SND_MENU_DOOR_CLOSING);
2362 if (door_state & DOOR_ACTION_1)
2363 door1 = door_state & DOOR_ACTION_1;
2364 if (door_state & DOOR_ACTION_2)
2365 door2 = door_state & DOOR_ACTION_2;
2367 return (door1 | door2);
2370 void DrawSpecialEditorDoor()
2372 /* draw bigger toolbox window */
2373 BlitBitmap(pix[PIX_DOOR], drawto,
2374 DOOR_GFX_PAGEX7, 0, 108, 56, EX - 4, EY - 12);
2376 redraw_mask |= REDRAW_ALL;
2379 void UndrawSpecialEditorDoor()
2381 /* draw normal tape recorder window */
2382 BlitBitmap(pix[PIX_BACK], drawto,
2383 562, 344, 108, 56, EX - 4, EY - 12);
2385 redraw_mask |= REDRAW_ALL;
2389 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2391 XImage *pixel_image;
2392 unsigned long pixel_value;
2394 pixel_image = XGetImage(display, bitmap->drawable,
2395 x, y, 1, 1, AllPlanes, ZPixmap);
2396 pixel_value = XGetPixel(pixel_image, 0, 0);
2398 XDestroyImage(pixel_image);
2404 /* ---------- new tool button stuff ---------------------------------------- */
2406 /* graphic position values for tool buttons */
2407 #define TOOL_BUTTON_YES_XPOS 2
2408 #define TOOL_BUTTON_YES_YPOS 250
2409 #define TOOL_BUTTON_YES_GFX_YPOS 0
2410 #define TOOL_BUTTON_YES_XSIZE 46
2411 #define TOOL_BUTTON_YES_YSIZE 28
2412 #define TOOL_BUTTON_NO_XPOS 52
2413 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2414 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2415 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2416 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2417 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2418 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2419 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2420 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2421 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2422 #define TOOL_BUTTON_PLAYER_XSIZE 30
2423 #define TOOL_BUTTON_PLAYER_YSIZE 30
2424 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2425 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2426 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2427 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2428 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2429 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2430 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2431 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2432 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2433 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2434 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2435 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2436 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2437 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2438 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2439 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2440 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2441 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2442 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2443 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2452 } toolbutton_info[NUM_TOOL_BUTTONS] =
2455 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2456 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2457 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2462 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2463 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2464 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2469 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2470 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2471 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2472 TOOL_CTRL_ID_CONFIRM,
2476 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2477 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2478 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2479 TOOL_CTRL_ID_PLAYER_1,
2483 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2484 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2485 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2486 TOOL_CTRL_ID_PLAYER_2,
2490 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2491 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2492 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2493 TOOL_CTRL_ID_PLAYER_3,
2497 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2498 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2499 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2500 TOOL_CTRL_ID_PLAYER_4,
2505 void CreateToolButtons()
2509 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2511 Bitmap *gd_bitmap = pix[PIX_DOOR];
2512 Bitmap *deco_bitmap = None;
2513 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2514 struct GadgetInfo *gi;
2515 unsigned long event_mask;
2516 int gd_xoffset, gd_yoffset;
2517 int gd_x1, gd_x2, gd_y;
2520 event_mask = GD_EVENT_RELEASED;
2522 gd_xoffset = toolbutton_info[i].xpos;
2523 gd_yoffset = toolbutton_info[i].ypos;
2524 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2525 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2526 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2528 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2530 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2532 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2533 &deco_bitmap, &deco_x, &deco_y);
2534 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2535 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2538 gi = CreateGadget(GDI_CUSTOM_ID, id,
2539 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2540 GDI_X, DX + toolbutton_info[i].x,
2541 GDI_Y, DY + toolbutton_info[i].y,
2542 GDI_WIDTH, toolbutton_info[i].width,
2543 GDI_HEIGHT, toolbutton_info[i].height,
2544 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2545 GDI_STATE, GD_BUTTON_UNPRESSED,
2546 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2547 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2548 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2549 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2550 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2551 GDI_DECORATION_SHIFTING, 1, 1,
2552 GDI_EVENT_MASK, event_mask,
2553 GDI_CALLBACK_ACTION, HandleToolButtons,
2557 Error(ERR_EXIT, "cannot create gadget");
2559 tool_gadget[id] = gi;
2563 static void UnmapToolButtons()
2567 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2568 UnmapGadget(tool_gadget[i]);
2571 static void HandleToolButtons(struct GadgetInfo *gi)
2573 request_gadget_id = gi->custom_id;
2576 int get_next_element(int element)
2580 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2581 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2582 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2583 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2584 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2585 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2586 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2588 default: return element;
2592 int el2gfx_OLD(int element)
2596 case EL_EMPTY: return -1;
2597 case EL_SAND: return GFX_ERDREICH;
2598 case EL_WALL: return GFX_MAUERWERK;
2599 case EL_WALL_CRUMBLED: return GFX_FELSBODEN;
2600 case EL_ROCK: return GFX_FELSBROCKEN;
2601 case EL_EMERALD: return GFX_EDELSTEIN;
2602 case EL_EXIT_CLOSED: return GFX_AUSGANG_ZU;
2603 case EL_EXIT_OPENING: return GFX_AUSGANG_ACT;
2604 case EL_EXIT_OPEN: return GFX_AUSGANG_AUF;
2605 case EL_SP_EXIT_OPEN: return GFX_SP_EXIT;
2606 case EL_PLAYER1: return GFX_SPIELER1;
2607 case EL_PLAYER2: return GFX_SPIELER2;
2608 case EL_PLAYER3: return GFX_SPIELER3;
2609 case EL_PLAYER4: return GFX_SPIELER4;
2610 case EL_BUG: return GFX_KAEFER;
2611 case EL_BUG_RIGHT: return GFX_KAEFER_RIGHT;
2612 case EL_BUG_UP: return GFX_KAEFER_UP;
2613 case EL_BUG_LEFT: return GFX_KAEFER_LEFT;
2614 case EL_BUG_DOWN: return GFX_KAEFER_DOWN;
2615 case EL_SPACESHIP: return GFX_FLIEGER;
2616 case EL_SPACESHIP_RIGHT: return GFX_FLIEGER_RIGHT;
2617 case EL_SPACESHIP_UP: return GFX_FLIEGER_UP;
2618 case EL_SPACESHIP_LEFT: return GFX_FLIEGER_LEFT;
2619 case EL_SPACESHIP_DOWN: return GFX_FLIEGER_DOWN;
2620 case EL_BD_BUTTERFLY: return GFX_BUTTERFLY;
2621 case EL_BD_BUTTERFLY_RIGHT: return GFX_BUTTERFLY_RIGHT;
2622 case EL_BD_BUTTERFLY_UP: return GFX_BUTTERFLY_UP;
2623 case EL_BD_BUTTERFLY_LEFT: return GFX_BUTTERFLY_LEFT;
2624 case EL_BD_BUTTERFLY_DOWN: return GFX_BUTTERFLY_DOWN;
2625 case EL_BD_FIREFLY: return GFX_FIREFLY;
2626 case EL_BD_FIREFLY_RIGHT: return GFX_FIREFLY_RIGHT;
2627 case EL_BD_FIREFLY_UP: return GFX_FIREFLY_UP;
2628 case EL_BD_FIREFLY_LEFT: return GFX_FIREFLY_LEFT;
2629 case EL_BD_FIREFLY_DOWN: return GFX_FIREFLY_DOWN;
2630 case EL_YAMYAM: return GFX_MAMPFER;
2631 case EL_ROBOT: return GFX_ROBOT;
2632 case EL_STEELWALL: return GFX_BETON;
2633 case EL_DIAMOND: return GFX_DIAMANT;
2634 case EL_QUICKSAND_EMPTY: return GFX_MORAST_LEER;
2635 case EL_QUICKSAND_FULL: return GFX_MORAST_VOLL;
2636 case EL_QUICKSAND_EMPTYING: return GFX_MORAST_LEER;
2637 case EL_AMOEBA_DROP: return GFX_TROPFEN;
2638 case EL_BOMB: return GFX_BOMBE;
2639 case EL_MAGIC_WALL: return GFX_MAGIC_WALL_OFF;
2640 case EL_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_EMPTY;
2641 case EL_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_EMPTY;
2642 case EL_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_FULL;
2643 case EL_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_DEAD;
2644 case EL_ACID: return GFX_SALZSAEURE;
2645 case EL_AMOEBA_DEAD: return GFX_AMOEBE_TOT;
2646 case EL_AMOEBA_WET: return GFX_AMOEBE_NASS;
2647 case EL_AMOEBA_DRY: return GFX_AMOEBE_NORM;
2648 case EL_AMOEBA_FULL: return GFX_AMOEBE_VOLL;
2649 case EL_BD_AMOEBA: return GFX_AMOEBE_BD;
2650 case EL_AMOEBA_TO_DIAMOND: return GFX_AMOEBA2DIAM;
2651 case EL_AMOEBA_DRIPPING: return GFX_AMOEBE_NASS;
2652 case EL_NUT: return GFX_KOKOSNUSS;
2653 case EL_GAMEOFLIFE: return GFX_LIFE;
2654 case EL_BIOMAZE: return GFX_LIFE_ASYNC;
2655 case EL_DYNAMITE_ACTIVE: return GFX_DYNAMIT;
2656 case EL_STONEBLOCK: return GFX_BADEWANNE;
2657 case EL_ACIDPOOL_TOPLEFT: return GFX_BADEWANNE1;
2658 case EL_ACIDPOOL_TOPRIGHT: return GFX_BADEWANNE2;
2659 case EL_ACIDPOOL_BOTTOMLEFT: return GFX_BADEWANNE3;
2660 case EL_ACIDPOOL_BOTTOM: return GFX_BADEWANNE4;
2661 case EL_ACIDPOOL_BOTTOMRIGHT: return GFX_BADEWANNE5;
2662 case EL_ROBOT_WHEEL: return GFX_ABLENK_AUS;
2663 case EL_ROBOT_WHEEL_ACTIVE: return GFX_ABLENK_EIN;
2664 case EL_KEY1: return GFX_SCHLUESSEL1;
2665 case EL_KEY2: return GFX_SCHLUESSEL2;
2666 case EL_KEY3: return GFX_SCHLUESSEL3;
2667 case EL_KEY4: return GFX_SCHLUESSEL4;
2668 case EL_GATE1: return GFX_PFORTE1;
2669 case EL_GATE2: return GFX_PFORTE2;
2670 case EL_GATE3: return GFX_PFORTE3;
2671 case EL_GATE4: return GFX_PFORTE4;
2672 case EL_GATE1_GRAY: return GFX_PFORTE1X;
2673 case EL_GATE2_GRAY: return GFX_PFORTE2X;
2674 case EL_GATE3_GRAY: return GFX_PFORTE3X;
2675 case EL_GATE4_GRAY: return GFX_PFORTE4X;
2676 case EL_DYNAMITE: return GFX_DYNAMIT_AUS;
2677 case EL_PACMAN: return GFX_PACMAN;
2678 case EL_PACMAN_RIGHT: return GFX_PACMAN_RIGHT;
2679 case EL_PACMAN_UP: return GFX_PACMAN_UP;
2680 case EL_PACMAN_LEFT: return GFX_PACMAN_LEFT;
2681 case EL_PACMAN_DOWN: return GFX_PACMAN_DOWN;
2682 case EL_INVISIBLE_WALL: return GFX_UNSICHTBAR;
2683 case EL_INVISIBLE_WALL_ACTIVE: return GFX_UNSICHTBAR_ON;
2684 case EL_WALL_EMERALD: return GFX_ERZ_EDEL;
2685 case EL_WALL_DIAMOND: return GFX_ERZ_DIAM;
2686 case EL_LAMP: return GFX_BIRNE_AUS;
2687 case EL_LAMP_ACTIVE: return GFX_BIRNE_EIN;
2688 case EL_TIME_ORB_FULL: return GFX_ZEIT_VOLL;
2689 case EL_TIME_ORB_EMPTY: return GFX_ZEIT_LEER;
2690 case EL_WALL_GROWING: return GFX_MAUER_LEBT;
2691 case EL_WALL_GROWING_X: return GFX_MAUER_X;
2692 case EL_WALL_GROWING_Y: return GFX_MAUER_Y;
2693 case EL_WALL_GROWING_XY: return GFX_MAUER_XY;
2694 case EL_BD_DIAMOND: return GFX_EDELSTEIN_BD;
2695 case EL_EMERALD_YELLOW: return GFX_EDELSTEIN_GELB;
2696 case EL_EMERALD_RED: return GFX_EDELSTEIN_ROT;
2697 case EL_EMERALD_PURPLE: return GFX_EDELSTEIN_LILA;
2698 case EL_WALL_BD_DIAMOND: return GFX_ERZ_EDEL_BD;
2699 case EL_WALL_EMERALD_YELLOW: return GFX_ERZ_EDEL_GELB;
2700 case EL_WALL_EMERALD_RED: return GFX_ERZ_EDEL_ROT;
2701 case EL_WALL_EMERALD_PURPLE: return GFX_ERZ_EDEL_LILA;
2702 case EL_DARK_YAMYAM: return GFX_MAMPFER2;
2703 case EL_BD_MAGIC_WALL: return GFX_MAGIC_WALL_BD_OFF;
2704 case EL_BD_MAGIC_WALL_ACTIVE: return GFX_MAGIC_WALL_BD_EMPTY;
2705 case EL_BD_MAGIC_WALL_EMPTYING: return GFX_MAGIC_WALL_BD_EMPTY;
2706 case EL_BD_MAGIC_WALL_FULL: return GFX_MAGIC_WALL_BD_FULL;
2707 case EL_BD_MAGIC_WALL_DEAD: return GFX_MAGIC_WALL_BD_DEAD;
2708 case EL_DYNABOMB_PLAYER1_ACTIVE: return GFX_DYNABOMB;
2709 case EL_DYNABOMB_PLAYER2_ACTIVE: return GFX_DYNABOMB;
2710 case EL_DYNABOMB_PLAYER3_ACTIVE: return GFX_DYNABOMB;
2711 case EL_DYNABOMB_PLAYER4_ACTIVE: return GFX_DYNABOMB;
2712 case EL_DYNABOMB_NR: return GFX_DYNABOMB_NR;
2713 case EL_DYNABOMB_SZ: return GFX_DYNABOMB_SZ;
2714 case EL_DYNABOMB_XL: return GFX_DYNABOMB_XL;
2715 case EL_SOKOBAN_OBJECT: return GFX_SOKOBAN_OBJEKT;
2716 case EL_SOKOBAN_FIELD_EMPTY: return GFX_SOKOBAN_FELD_LEER;
2717 case EL_SOKOBAN_FIELD_FULL: return GFX_SOKOBAN_FELD_VOLL;
2718 case EL_MOLE: return GFX_MOLE;
2719 case EL_PENGUIN: return GFX_PINGUIN;
2720 case EL_PIG: return GFX_SCHWEIN;
2721 case EL_DRAGON: return GFX_DRACHE;
2722 case EL_SATELLITE: return GFX_SONDE;
2723 case EL_ARROW_BLUE_LEFT: return GFX_PFEIL_LEFT;
2724 case EL_ARROW_BLUE_RIGHT: return GFX_PFEIL_RIGHT;
2725 case EL_ARROW_BLUE_UP: return GFX_PFEIL_UP;
2726 case EL_ARROW_BLUE_DOWN: return GFX_PFEIL_DOWN;
2727 case EL_SPEED_PILL: return GFX_SPEED_PILL;
2728 case EL_SP_TERMINAL_ACTIVE: return GFX_SP_TERMINAL;
2729 case EL_SP_BUGGY_BASE_ACTIVE: return GFX_SP_BUG_ACTIVE;
2730 case EL_SP_ZONK: return GFX_SP_ZONK;
2731 /* ^^^^^^^^^^ non-standard position in supaplex graphic set! */
2732 case EL_INVISIBLE_STEELWALL: return GFX_INVISIBLE_STEEL;
2733 case EL_INVISIBLE_STEELWALL_ACTIVE: return GFX_INVISIBLE_STEEL_ON;
2734 case EL_BLACK_ORB: return GFX_BLACK_ORB;
2735 case EL_EM_GATE1: return GFX_EM_GATE_1;
2736 case EL_EM_GATE2: return GFX_EM_GATE_2;
2737 case EL_EM_GATE3: return GFX_EM_GATE_3;
2738 case EL_EM_GATE4: return GFX_EM_GATE_4;
2739 case EL_EM_GATE1_GRAY: return GFX_EM_GATE_1X;
2740 case EL_EM_GATE2_GRAY: return GFX_EM_GATE_2X;
2741 case EL_EM_GATE3_GRAY: return GFX_EM_GATE_3X;
2742 case EL_EM_GATE4_GRAY: return GFX_EM_GATE_4X;
2743 case EL_EM_KEY1_FILE: return GFX_EM_KEY_1;
2744 case EL_EM_KEY2_FILE: return GFX_EM_KEY_2;
2745 case EL_EM_KEY3_FILE: return GFX_EM_KEY_3;
2746 case EL_EM_KEY4_FILE: return GFX_EM_KEY_4;
2747 case EL_EM_KEY1: return GFX_EM_KEY_1;
2748 case EL_EM_KEY2: return GFX_EM_KEY_2;
2749 case EL_EM_KEY3: return GFX_EM_KEY_3;
2750 case EL_EM_KEY4: return GFX_EM_KEY_4;
2751 case EL_PEARL: return GFX_PEARL;
2752 case EL_CRYSTAL: return GFX_CRYSTAL;
2753 case EL_WALL_PEARL: return GFX_WALL_PEARL;
2754 case EL_WALL_CRYSTAL: return GFX_WALL_CRYSTAL;
2755 case EL_DOOR_WHITE: return GFX_DOOR_WHITE;
2756 case EL_DOOR_WHITE_GRAY: return GFX_DOOR_WHITE_GRAY;
2757 case EL_KEY_WHITE: return GFX_KEY_WHITE;
2758 case EL_SHIELD_NORMAL: return GFX_SHIELD_PASSIVE;
2759 case EL_SHIELD_DEADLY: return GFX_SHIELD_ACTIVE;
2760 case EL_EXTRA_TIME: return GFX_EXTRA_TIME;
2761 case EL_SWITCHGATE_OPEN: return GFX_SWITCHGATE_OPEN;
2762 case EL_SWITCHGATE_CLOSED: return GFX_SWITCHGATE_CLOSED;
2763 case EL_SWITCHGATE_SWITCH_UP: return GFX_SWITCHGATE_SWITCH_1;
2764 case EL_SWITCHGATE_SWITCH_DOWN: return GFX_SWITCHGATE_SWITCH_2;
2765 case EL_CONVEYOR_BELT1_LEFT: return GFX_BELT1_LEFT;
2766 case EL_CONVEYOR_BELT1_MIDDLE: return GFX_BELT1_MIDDLE;
2767 case EL_CONVEYOR_BELT1_RIGHT: return GFX_BELT1_RIGHT;
2768 case EL_CONVEYOR_BELT1_LEFT_ACTIVE: return GFX_BELT1_LEFT;
2769 case EL_CONVEYOR_BELT1_MIDDLE_ACTIVE:return GFX_BELT1_MIDDLE;
2770 case EL_CONVEYOR_BELT1_RIGHT_ACTIVE:return GFX_BELT1_RIGHT;
2771 case EL_CONVEYOR_BELT1_SWITCH_LEFT: return GFX_BELT1_SWITCH_LEFT;
2772 case EL_CONVEYOR_BELT1_SWITCH_MIDDLE:return GFX_BELT1_SWITCH_MIDDLE;
2773 case EL_CONVEYOR_BELT1_SWITCH_RIGHT:return GFX_BELT1_SWITCH_RIGHT;
2774 case EL_CONVEYOR_BELT2_LEFT: return GFX_BELT2_LEFT;
2775 case EL_CONVEYOR_BELT2_MIDDLE: return GFX_BELT2_MIDDLE;
2776 case EL_CONVEYOR_BELT2_RIGHT: return GFX_BELT2_RIGHT;
2777 case EL_CONVEYOR_BELT2_LEFT_ACTIVE: return GFX_BELT2_LEFT;
2778 case EL_CONVEYOR_BELT2_MIDDLE_ACTIVE:return GFX_BELT2_MIDDLE;
2779 case EL_CONVEYOR_BELT2_RIGHT_ACTIVE:return GFX_BELT2_RIGHT;
2780 case EL_CONVEYOR_BELT2_SWITCH_LEFT: return GFX_BELT2_SWITCH_LEFT;
2781 case EL_CONVEYOR_BELT2_SWITCH_MIDDLE:return GFX_BELT2_SWITCH_MIDDLE;
2782 case EL_CONVEYOR_BELT2_SWITCH_RIGHT:return GFX_BELT2_SWITCH_RIGHT;
2783 case EL_CONVEYOR_BELT3_LEFT: return GFX_BELT3_LEFT;
2784 case EL_CONVEYOR_BELT3_MIDDLE: return GFX_BELT3_MIDDLE;
2785 case EL_CONVEYOR_BELT3_RIGHT: return GFX_BELT3_RIGHT;
2786 case EL_CONVEYOR_BELT3_LEFT_ACTIVE: return GFX_BELT3_LEFT;
2787 case EL_CONVEYOR_BELT3_MIDDLE_ACTIVE:return GFX_BELT3_MIDDLE;
2788 case EL_CONVEYOR_BELT3_RIGHT_ACTIVE:return GFX_BELT3_RIGHT;
2789 case EL_CONVEYOR_BELT3_SWITCH_LEFT: return GFX_BELT3_SWITCH_LEFT;
2790 case EL_CONVEYOR_BELT3_SWITCH_MIDDLE:return GFX_BELT3_SWITCH_MIDDLE;
2791 case EL_CONVEYOR_BELT3_SWITCH_RIGHT:return GFX_BELT3_SWITCH_RIGHT;
2792 case EL_CONVEYOR_BELT4_LEFT: return GFX_BELT4_LEFT;
2793 case EL_CONVEYOR_BELT4_MIDDLE: return GFX_BELT4_MIDDLE;
2794 case EL_CONVEYOR_BELT4_RIGHT: return GFX_BELT4_RIGHT;
2795 case EL_CONVEYOR_BELT4_LEFT_ACTIVE: return GFX_BELT4_LEFT;
2796 case EL_CONVEYOR_BELT4_MIDDLE_ACTIVE:return GFX_BELT4_MIDDLE;
2797 case EL_CONVEYOR_BELT4_RIGHT_ACTIVE:return GFX_BELT4_RIGHT;
2798 case EL_CONVEYOR_BELT4_SWITCH_LEFT: return GFX_BELT4_SWITCH_LEFT;
2799 case EL_CONVEYOR_BELT4_SWITCH_MIDDLE:return GFX_BELT4_SWITCH_MIDDLE;
2800 case EL_CONVEYOR_BELT4_SWITCH_RIGHT:return GFX_BELT4_SWITCH_RIGHT;
2801 case EL_LANDMINE: return GFX_LANDMINE;
2802 case EL_ENVELOPE: return GFX_ENVELOPE;
2803 case EL_LIGHT_SWITCH: return GFX_LIGHT_SWITCH_OFF;
2804 case EL_LIGHT_SWITCH_ACTIVE: return GFX_LIGHT_SWITCH_ON;
2805 case EL_SIGN_EXCLAMATION: return GFX_SIGN_EXCLAMATION;
2806 case EL_SIGN_RADIOACTIVITY: return GFX_SIGN_RADIOACTIVITY;
2807 case EL_SIGN_STOP: return GFX_SIGN_STOP;
2808 case EL_SIGN_WHEELCHAIR: return GFX_SIGN_WHEELCHAIR;
2809 case EL_SIGN_PARKING: return GFX_SIGN_PARKING;
2810 case EL_SIGN_ONEWAY: return GFX_SIGN_ONEWAY;
2811 case EL_SIGN_HEART: return GFX_SIGN_HEART;
2812 case EL_SIGN_TRIANGLE: return GFX_SIGN_TRIANGLE;
2813 case EL_SIGN_ROUND: return GFX_SIGN_ROUND;
2814 case EL_SIGN_EXIT: return GFX_SIGN_EXIT;
2815 case EL_SIGN_YINYANG: return GFX_SIGN_YINYANG;
2816 case EL_SIGN_OTHER: return GFX_SIGN_OTHER;
2817 case EL_MOLE_LEFT: return GFX_MOLE_LEFT;
2818 case EL_MOLE_RIGHT: return GFX_MOLE_RIGHT;
2819 case EL_MOLE_UP: return GFX_MOLE_UP;
2820 case EL_MOLE_DOWN: return GFX_MOLE_DOWN;
2821 case EL_STEELWALL_SLANTED: return GFX_STEEL_SLANTED;
2822 case EL_INVISIBLE_SAND: return GFX_SAND_INVISIBLE;
2823 case EL_INVISIBLE_SAND_ACTIVE: return GFX_SAND_INVISIBLE_ON;
2824 case EL_DX_UNKNOWN_15: return GFX_DX_UNKNOWN_15;
2825 case EL_DX_UNKNOWN_42: return GFX_DX_UNKNOWN_42;
2826 case EL_TIMEGATE_OPEN: return GFX_TIMEGATE_OPEN;
2827 case EL_TIMEGATE_CLOSED: return GFX_TIMEGATE_CLOSED;
2828 case EL_TIMEGATE_SWITCH_ACTIVE: return GFX_TIMEGATE_SWITCH;
2829 case EL_TIMEGATE_SWITCH: return GFX_TIMEGATE_SWITCH;
2830 case EL_BALLOON: return GFX_BALLOON;
2831 case EL_BALLOON_SEND_LEFT: return GFX_BALLOON_SEND_LEFT;
2832 case EL_BALLOON_SEND_RIGHT: return GFX_BALLOON_SEND_RIGHT;
2833 case EL_BALLOON_SEND_UP: return GFX_BALLOON_SEND_UP;
2834 case EL_BALLOON_SEND_DOWN: return GFX_BALLOON_SEND_DOWN;
2835 case EL_BALLOON_SEND_ANY_DIRECTION: return GFX_BALLOON_SEND_ANY;
2836 case EL_EMC_STEELWALL1: return GFX_EMC_STEEL_WALL_1;
2837 case EL_EMC_STEELWALL2: return GFX_EMC_STEEL_WALL_2;
2838 case EL_EMC_STEELWALL3: return GFX_EMC_STEEL_WALL_3;
2839 case EL_EMC_STEELWALL4: return GFX_EMC_STEEL_WALL_4;
2840 case EL_EMC_WALL_PILLAR_UPPER: return GFX_EMC_WALL_1;
2841 case EL_EMC_WALL_PILLAR_MIDDLE: return GFX_EMC_WALL_2;
2842 case EL_EMC_WALL_PILLAR_LOWER: return GFX_EMC_WALL_3;
2843 case EL_EMC_WALL4: return GFX_EMC_WALL_4;
2844 case EL_EMC_WALL5: return GFX_EMC_WALL_5;
2845 case EL_EMC_WALL6: return GFX_EMC_WALL_6;
2846 case EL_EMC_WALL7: return GFX_EMC_WALL_7;
2847 case EL_EMC_WALL8: return GFX_EMC_WALL_8;
2848 case EL_TUBE_ALL: return GFX_TUBE_CROSS;
2849 case EL_TUBE_VERTICAL: return GFX_TUBE_VERTICAL;
2850 case EL_TUBE_HORIZONTAL: return GFX_TUBE_HORIZONTAL;
2851 case EL_TUBE_VERTICAL_LEFT: return GFX_TUBE_VERT_LEFT;
2852 case EL_TUBE_VERTICAL_RIGHT: return GFX_TUBE_VERT_RIGHT;
2853 case EL_TUBE_HORIZONTAL_UP: return GFX_TUBE_HORIZ_UP;
2854 case EL_TUBE_HORIZONTAL_DOWN: return GFX_TUBE_HORIZ_DOWN;
2855 case EL_TUBE_LEFT_UP: return GFX_TUBE_LEFT_UP;
2856 case EL_TUBE_LEFT_DOWN: return GFX_TUBE_LEFT_DOWN;
2857 case EL_TUBE_RIGHT_UP: return GFX_TUBE_RIGHT_UP;
2858 case EL_TUBE_RIGHT_DOWN: return GFX_TUBE_RIGHT_DOWN;
2859 case EL_SPRING: return GFX_SPRING;
2860 case EL_SPRING_MOVING: return GFX_SPRING;
2861 case EL_TRAP: return GFX_TRAP_INACTIVE;
2862 case EL_TRAP_ACTIVE: return GFX_TRAP_ACTIVE;
2863 case EL_BD_WALL: return GFX_BD_WALL;
2864 case EL_BD_ROCK: return GFX_BD_ROCK;
2865 case EL_DX_SUPABOMB: return GFX_DX_SUPABOMB;
2866 case EL_SP_MURPHY_CLONE: return GFX_SP_MURPHY_CLONE;
2870 if (IS_CHAR(element))
2871 return GFX_CHAR_START + (element - EL_CHAR_START);
2872 else if (element >= EL_SP_START && element <= EL_SP_END)
2874 int nr_element = element - EL_SP_START;
2875 int gfx_per_line = 8;
2877 (nr_element / gfx_per_line) * SP_PER_LINE +
2878 (nr_element % gfx_per_line);
2880 return GFX_START_ROCKSSP + nr_graphic;
2888 int el2gfx(int element)
2891 int graphic_OLD = el2gfx_OLD(element);
2896 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2899 int graphic_OLD = el2gfx_OLD(element);
2901 if (element >= MAX_ELEMENTS)
2903 Error(ERR_WARN, "el2gfx: element == %d >= MAX_ELEMENTS", element);
2906 if (graphic_NEW != graphic_OLD)
2908 Error(ERR_WARN, "el2gfx: graphic_NEW (%d) != graphic_OLD (%d)",
2909 graphic_NEW, graphic_OLD);
2917 int el2img(int element)
2920 int graphic_NEW = element_info[element].graphic[GFX_ACTION_DEFAULT];
2923 if (graphic_NEW < 0)
2924 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2925 element, graphic_NEW);
2933 case EL_BD_BUTTERFLY: return IMG_BD_BUTTERFLY;
2934 case EL_BD_FIREFLY: return IMG_BD_FIREFLY;
2935 case EL_SP_ELECTRON: return IMG_SP_ELECTRON;
2945 int el_dir2img(int element, int direction)
2947 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2950 int el_dir_act2img(int element, int direction, int action)
2952 action = graphics_action_mapping[action];
2953 direction = MV_DIR_BIT(direction);
2955 return element_info[element].direction_graphic[action][direction];