1 /***********************************************************
2 * Rocks'n'Diamonds -- McDuffin Strikes Back! *
3 *----------------------------------------------------------*
4 * (c) 1995-2002 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
14 #include "libgame/libgame.h"
23 /* tool button identifiers */
24 #define TOOL_CTRL_ID_YES 0
25 #define TOOL_CTRL_ID_NO 1
26 #define TOOL_CTRL_ID_CONFIRM 2
27 #define TOOL_CTRL_ID_PLAYER_1 3
28 #define TOOL_CTRL_ID_PLAYER_2 4
29 #define TOOL_CTRL_ID_PLAYER_3 5
30 #define TOOL_CTRL_ID_PLAYER_4 6
32 #define NUM_TOOL_BUTTONS 7
34 /* forward declaration for internal use */
35 static void UnmapToolButtons();
36 static void HandleToolButtons(struct GadgetInfo *);
38 static struct GadgetInfo *tool_gadget[NUM_TOOL_BUTTONS];
39 static int request_gadget_id = -1;
41 void SetDrawtoField(int mode)
43 if (mode == DRAW_BUFFERED && setup.soft_scrolling)
54 drawto_field = fieldbuffer;
56 else /* DRAW_DIRECT, DRAW_BACKBUFFER */
67 drawto_field = (mode == DRAW_DIRECT ? window : backbuffer);
71 void RedrawPlayfield(boolean force_redraw, int x, int y, int width, int height)
73 if (game_status == PLAYING)
79 width = gfx.sxsize + 2 * TILEX;
80 height = gfx.sysize + 2 * TILEY;
83 if (force_redraw || setup.direct_draw)
86 int x1 = (x - SX) / TILEX, y1 = (y - SY) / TILEY;
87 int x2 = (x - SX + width) / TILEX, y2 = (y - SY + height) / TILEY;
89 if (setup.direct_draw)
90 SetDrawtoField(DRAW_BACKBUFFER);
92 for(xx=BX1; xx<=BX2; xx++)
93 for(yy=BY1; yy<=BY2; yy++)
94 if (xx >= x1 && xx <= x2 && yy >= y1 && yy <= y2)
95 DrawScreenField(xx, yy);
98 if (setup.direct_draw)
99 SetDrawtoField(DRAW_DIRECT);
102 if (setup.soft_scrolling)
104 int fx = FX, fy = FY;
106 fx += (ScreenMovDir & (MV_LEFT|MV_RIGHT) ? ScreenGfxPos : 0);
107 fy += (ScreenMovDir & (MV_UP|MV_DOWN) ? ScreenGfxPos : 0);
109 BlitBitmap(fieldbuffer, backbuffer, fx,fy, SXSIZE,SYSIZE, SX,SY);
113 BlitBitmap(drawto, window, x, y, width, height, x, y);
119 DrawBuffer *buffer = (drawto_field == window ? backbuffer : drawto_field);
121 if (setup.direct_draw && game_status == PLAYING)
122 redraw_mask &= ~REDRAW_MAIN;
124 if (redraw_mask & REDRAW_TILES && redraw_tiles > REDRAWTILES_THRESHOLD)
125 redraw_mask |= REDRAW_FIELD;
127 if (redraw_mask & REDRAW_FIELD)
128 redraw_mask &= ~REDRAW_TILES;
130 if (redraw_mask == REDRAW_NONE)
133 if (global.fps_slowdown && game_status == PLAYING)
135 static boolean last_frame_skipped = FALSE;
136 boolean skip_even_when_not_scrolling = TRUE;
137 boolean just_scrolling = (ScreenMovDir != 0);
138 boolean verbose = FALSE;
140 if (global.fps_slowdown_factor > 1 &&
141 (FrameCounter % global.fps_slowdown_factor) &&
142 (just_scrolling || skip_even_when_not_scrolling))
144 redraw_mask &= ~REDRAW_MAIN;
146 last_frame_skipped = TRUE;
149 printf("FRAME SKIPPED\n");
153 if (last_frame_skipped)
154 redraw_mask |= REDRAW_FIELD;
156 last_frame_skipped = FALSE;
159 printf("frame not skipped\n");
163 /* synchronize X11 graphics at this point; if we would synchronize the
164 display immediately after the buffer switching (after the XFlush),
165 this could mean that we have to wait for the graphics to complete,
166 although we could go on doing calculations for the next frame */
170 if (redraw_mask & REDRAW_ALL)
172 BlitBitmap(backbuffer, window, 0, 0, WIN_XSIZE, WIN_YSIZE, 0, 0);
176 if (redraw_mask & REDRAW_FIELD)
178 if (game_status != PLAYING || redraw_mask & REDRAW_FROM_BACKBUFFER)
180 BlitBitmap(backbuffer, window,
181 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
185 int fx = FX, fy = FY;
187 if (setup.soft_scrolling)
189 fx += (ScreenMovDir & (MV_LEFT | MV_RIGHT) ? ScreenGfxPos : 0);
190 fy += (ScreenMovDir & (MV_UP | MV_DOWN) ? ScreenGfxPos : 0);
193 if (setup.soft_scrolling ||
194 ABS(ScreenMovPos) + ScrollStepSize == TILEX ||
195 ABS(ScreenMovPos) == ScrollStepSize ||
196 redraw_tiles > REDRAWTILES_THRESHOLD)
198 BlitBitmap(buffer, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
202 printf("redrawing all (ScreenGfxPos == %d) because %s\n",
204 (setup.soft_scrolling ?
205 "setup.soft_scrolling" :
206 ABS(ScreenGfxPos) + ScrollStepSize == TILEX ?
207 "ABS(ScreenGfxPos) + ScrollStepSize == TILEX" :
208 ABS(ScreenGfxPos) == ScrollStepSize ?
209 "ABS(ScreenGfxPos) == ScrollStepSize" :
210 "redraw_tiles > REDRAWTILES_THRESHOLD"));
216 redraw_mask &= ~REDRAW_MAIN;
219 if (redraw_mask & REDRAW_DOORS)
221 if (redraw_mask & REDRAW_DOOR_1)
222 BlitBitmap(backbuffer, window, DX, DY, DXSIZE, DYSIZE, DX, DY);
223 if (redraw_mask & REDRAW_DOOR_2)
225 if ((redraw_mask & REDRAW_DOOR_2) == REDRAW_DOOR_2)
226 BlitBitmap(backbuffer, window, VX,VY, VXSIZE,VYSIZE, VX,VY);
229 if (redraw_mask & REDRAW_VIDEO_1)
230 BlitBitmap(backbuffer, window,
231 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS,
232 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
233 VX+VIDEO_DISPLAY1_XPOS,VY+VIDEO_DISPLAY1_YPOS);
234 if (redraw_mask & REDRAW_VIDEO_2)
235 BlitBitmap(backbuffer, window,
236 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS,
237 VIDEO_DISPLAY_XSIZE,VIDEO_DISPLAY_YSIZE,
238 VX+VIDEO_DISPLAY2_XPOS,VY+VIDEO_DISPLAY2_YPOS);
239 if (redraw_mask & REDRAW_VIDEO_3)
240 BlitBitmap(backbuffer, window,
241 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS,
242 VIDEO_CONTROL_XSIZE,VIDEO_CONTROL_YSIZE,
243 VX+VIDEO_CONTROL_XPOS,VY+VIDEO_CONTROL_YPOS);
246 if (redraw_mask & REDRAW_DOOR_3)
247 BlitBitmap(backbuffer, window, EX, EY, EXSIZE, EYSIZE, EX, EY);
248 redraw_mask &= ~REDRAW_DOORS;
251 if (redraw_mask & REDRAW_MICROLEVEL)
253 BlitBitmap(backbuffer, window,
254 MICROLEV_XPOS, MICROLEV_YPOS, MICROLEV_XSIZE, MICROLEV_YSIZE,
255 MICROLEV_XPOS, MICROLEV_YPOS);
256 BlitBitmap(backbuffer, window,
257 SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE,
258 SX, MICROLABEL_YPOS);
259 redraw_mask &= ~REDRAW_MICROLEVEL;
262 if (redraw_mask & REDRAW_TILES)
264 for(x=0; x<SCR_FIELDX; x++)
265 for(y=0; y<SCR_FIELDY; y++)
266 if (redraw[redraw_x1 + x][redraw_y1 + y])
267 BlitBitmap(buffer, window,
268 FX + x * TILEX, FX + y * TILEY, TILEX, TILEY,
269 SX + x * TILEX, SY + y * TILEY);
272 if (redraw_mask & REDRAW_FPS) /* display frames per second */
277 sprintf(info1, " (only every %d. frame)", global.fps_slowdown_factor);
278 if (!global.fps_slowdown)
281 sprintf(text, "%.1f fps%s", global.frames_per_second, info1);
282 DrawTextExt(window, SX, SY, text, FS_SMALL, FC_YELLOW, FONT_OPAQUE);
287 for(x=0; x<MAX_BUF_XSIZE; x++)
288 for(y=0; y<MAX_BUF_YSIZE; y++)
291 redraw_mask = REDRAW_NONE;
297 long fading_delay = 300;
299 if (setup.fading && (redraw_mask & REDRAW_FIELD))
306 ClearRectangle(window, REAL_SX,REAL_SY,FULL_SXSIZE,FULL_SYSIZE);
309 for(i=0;i<2*FULL_SYSIZE;i++)
311 for(y=0;y<FULL_SYSIZE;y++)
313 BlitBitmap(backbuffer, window,
314 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
322 for(i=1;i<FULL_SYSIZE;i+=2)
323 BlitBitmap(backbuffer, window,
324 REAL_SX,REAL_SY+i, FULL_SXSIZE,1, REAL_SX,REAL_SY+i);
330 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, 0);
331 BlitBitmapMasked(backbuffer, window,
332 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
337 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, -1);
338 BlitBitmapMasked(backbuffer, window,
339 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
344 SetClipOrigin(clip_gc[PIX_FADEMASK], 0, -1);
345 BlitBitmapMasked(backbuffer, window,
346 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
351 SetClipOrigin(clip_gc[PIX_FADEMASK], -1, 0);
352 BlitBitmapMasked(backbuffer, window,
353 REAL_SX,REAL_SY, FULL_SXSIZE,FULL_SYSIZE,
358 redraw_mask &= ~REDRAW_MAIN;
365 void SetMainBackgroundImage(int graphic)
367 SetMainBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
368 graphic_info[graphic].bitmap ?
369 graphic_info[graphic].bitmap :
370 graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
373 void SetDoorBackgroundImage(int graphic)
375 SetDoorBackgroundBitmap(graphic == IMG_UNDEFINED ? NULL :
376 graphic_info[graphic].bitmap ?
377 graphic_info[graphic].bitmap :
378 graphic_info[IMG_BACKGROUND_DEFAULT].bitmap);
381 void DrawBackground(int dest_x, int dest_y, int width, int height)
383 ClearRectangleOnBackground(backbuffer, dest_x, dest_y, width, height);
385 redraw_mask |= REDRAW_FIELD;
390 DrawBackground(REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
392 if (setup.soft_scrolling && game_status == PLAYING)
394 ClearRectangle(fieldbuffer, 0, 0, FXSIZE, FYSIZE);
395 SetDrawtoField(DRAW_BUFFERED);
398 SetDrawtoField(DRAW_BACKBUFFER);
400 if (setup.direct_draw && game_status == PLAYING)
402 ClearRectangle(window, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
403 SetDrawtoField(DRAW_DIRECT);
407 void MarkTileDirty(int x, int y)
409 int xx = redraw_x1 + x;
410 int yy = redraw_y1 + y;
415 redraw[xx][yy] = TRUE;
416 redraw_mask |= REDRAW_TILES;
419 void SetBorderElement()
423 BorderElement = EL_EMPTY;
425 for(y=0; y<lev_fieldy && BorderElement == EL_EMPTY; y++)
427 for(x=0; x<lev_fieldx; x++)
429 if (!IS_MASSIVE(Feld[x][y]))
430 BorderElement = EL_STEELWALL;
432 if (y != 0 && y != lev_fieldy - 1 && x != lev_fieldx - 1)
438 static int getGraphicAnimationPhase(int frames, int delay, int mode)
442 if (mode & ANIM_PINGPONG)
444 int max_anim_frames = 2 * frames - 2;
446 phase = (FrameCounter % (delay * max_anim_frames)) / delay;
447 phase = (phase < frames ? phase : max_anim_frames - phase);
450 phase = (FrameCounter % (delay * frames)) / delay;
452 if (mode & ANIM_REVERSE)
458 inline int getGraphicAnimationFrame(int graphic, int sync_frame)
460 /* animation synchronized with global frame counter, not move position */
461 if (graphic_info[graphic].anim_global_sync || sync_frame < 0)
462 sync_frame = FrameCounter;
464 return getAnimationFrame(graphic_info[graphic].anim_frames,
465 graphic_info[graphic].anim_delay,
466 graphic_info[graphic].anim_mode,
467 graphic_info[graphic].anim_start_frame,
471 inline void DrawGraphicAnimationExt(DrawBuffer *dst_bitmap, int x, int y,
472 int graphic, int sync_frame, int mask_mode)
474 int frame = getGraphicAnimationFrame(graphic, sync_frame);
476 if (mask_mode == USE_MASKING)
477 DrawGraphicThruMaskExt(dst_bitmap, x, y, graphic, frame);
479 DrawGraphicExt(dst_bitmap, x, y, graphic, frame);
482 inline boolean checkDrawGraphicAnimation(int x, int y, int graphic)
484 int lx = LEVELX(x), ly = LEVELY(y);
486 return (IN_SCR_FIELD(x, y) &&
487 GfxFrame[lx][ly] % graphic_info[graphic].anim_delay == 0);
490 inline boolean checkDrawLevelGraphicAnimation(int x, int y, int graphic)
492 return (IN_SCR_FIELD(SCREENX(x), SCREENY(y)) &&
493 GfxFrame[x][y] % graphic_info[graphic].anim_delay == 0);
496 inline boolean DrawGraphicAnimation(int x, int y, int graphic)
498 int lx = LEVELX(x), ly = LEVELY(y);
500 if (!checkDrawGraphicAnimation(x, y, graphic))
503 DrawGraphicAnimationExt(drawto_field, FX + x * TILEX, FY + y * TILEY,
504 graphic, GfxFrame[lx][ly], NO_MASKING);
510 boolean DrawLevelGraphicAnimation(int x, int y, int graphic)
512 return DrawGraphicAnimation(SCREENX(x), SCREENY(y), graphic);
515 boolean DrawLevelElementAnimation(int x, int y, int element)
517 return DrawGraphicAnimation(SCREENX(x), SCREENY(y), el2img(element));
520 void DrawAllPlayers()
524 for(i=0; i<MAX_PLAYERS; i++)
525 if (stored_player[i].active)
526 DrawPlayer(&stored_player[i]);
529 void DrawPlayerField(int x, int y)
531 if (!IS_PLAYER(x, y))
534 DrawPlayer(PLAYERINFO(x, y));
537 void DrawPlayer(struct PlayerInfo *player)
539 int jx = player->jx, jy = player->jy;
540 int last_jx = player->last_jx, last_jy = player->last_jy;
541 int next_jx = jx + (jx - last_jx), next_jy = jy + (jy - last_jy);
542 int sx = SCREENX(jx), sy = SCREENY(jy);
543 int sxx = 0, syy = 0;
544 int element = Feld[jx][jy], last_element = Feld[last_jx][last_jy];
547 boolean player_is_moving = (last_jx != jx || last_jy != jy ? TRUE : FALSE);
549 if (!player->active || !IN_SCR_FIELD(SCREENX(last_jx), SCREENY(last_jy)))
553 if (!IN_LEV_FIELD(jx,jy))
555 printf("DrawPlayerField(): x = %d, y = %d\n",jx,jy);
556 printf("DrawPlayerField(): sx = %d, sy = %d\n",sx,sy);
557 printf("DrawPlayerField(): This should never happen!\n");
562 if (element == EL_EXPLOSION)
565 /* draw things in the field the player is leaving, if needed */
567 if (player_is_moving)
569 if (Store[last_jx][last_jy] && IS_DRAWABLE(last_element))
571 DrawLevelElement(last_jx, last_jy, Store[last_jx][last_jy]);
573 if (last_element == EL_DYNAMITE_ACTIVE)
574 DrawDynamite(last_jx, last_jy);
576 DrawLevelFieldThruMask(last_jx, last_jy);
578 else if (last_element == EL_DYNAMITE_ACTIVE)
579 DrawDynamite(last_jx, last_jy);
581 DrawLevelField(last_jx, last_jy);
583 if (player->Pushing && IN_SCR_FIELD(SCREENX(next_jx), SCREENY(next_jy)))
587 if (Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL)
588 DrawLevelElement(next_jx, next_jy, EL_SOKOBAN_FIELD_EMPTY);
590 DrawLevelElement(next_jx, next_jy, EL_EMPTY);
593 DrawLevelField(next_jx, next_jy);
597 if (!IN_SCR_FIELD(sx, sy))
600 if (setup.direct_draw)
601 SetDrawtoField(DRAW_BUFFERED);
603 /* draw things behind the player, if needed */
606 DrawLevelElement(jx, jy, Store[jx][jy]);
607 else if (!IS_ACTIVE_BOMB(element))
608 DrawLevelField(jx, jy);
610 DrawLevelElement(jx, jy, EL_EMPTY);
612 /* draw player himself */
614 if (game.emulation == EMU_SUPAPLEX)
616 static int last_dir = MV_LEFT;
617 int action = (player->programmed_action ? player->programmed_action :
619 boolean action_moving =
621 ((action & (MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN)) &&
622 !(action & ~(MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN))));
624 graphic = IMG_SP_MURPHY;
628 if (player->MovDir == MV_LEFT)
629 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
630 else if (player->MovDir == MV_RIGHT)
631 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
632 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
633 graphic = IMG_SP_MURPHY_LEFT_PUSHING;
634 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
635 graphic = IMG_SP_MURPHY_RIGHT_PUSHING;
637 else if (player->snapped)
639 if (player->MovDir == MV_LEFT)
640 graphic = IMG_SP_MURPHY_LEFT_SNAPPING;
641 else if (player->MovDir == MV_RIGHT)
642 graphic = IMG_SP_MURPHY_RIGHT_SNAPPING;
643 else if (player->MovDir == MV_UP)
644 graphic = IMG_SP_MURPHY_UP_SNAPPING;
645 else if (player->MovDir == MV_DOWN)
646 graphic = IMG_SP_MURPHY_DOWN_SNAPPING;
648 else if (action_moving)
650 if (player->MovDir == MV_LEFT)
651 graphic = IMG_SP_MURPHY_LEFT_MOVING;
652 else if (player->MovDir == MV_RIGHT)
653 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
654 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_LEFT)
655 graphic = IMG_SP_MURPHY_LEFT_MOVING;
656 else if (player->MovDir & (MV_UP | MV_DOWN) && last_dir == MV_RIGHT)
657 graphic = IMG_SP_MURPHY_RIGHT_MOVING;
659 graphic = IMG_SP_MURPHY_LEFT_MOVING;
661 frame = getGraphicAnimationFrame(graphic, -1);
664 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
665 last_dir = player->MovDir;
669 if (player->MovDir == MV_LEFT)
670 graphic = (player->Pushing ? IMG_PLAYER1_LEFT_PUSHING :
671 player->is_moving ? IMG_PLAYER1_LEFT_MOVING :
673 else if (player->MovDir == MV_RIGHT)
674 graphic = (player->Pushing ? IMG_PLAYER1_RIGHT_PUSHING :
675 player->is_moving ? IMG_PLAYER1_RIGHT_MOVING :
677 else if (player->MovDir == MV_UP)
678 graphic = (player->Pushing ? IMG_PLAYER1_UP_PUSHING :
679 player->is_moving ? IMG_PLAYER1_UP_MOVING :
681 else /* MV_DOWN || MV_NO_MOVING */
682 graphic = (player->Pushing ? IMG_PLAYER1_DOWN_PUSHING :
683 player->is_moving ? IMG_PLAYER1_DOWN_MOVING :
686 graphic = PLAYER_NR_GFX(graphic, player->index_nr);
689 frame = player->Frame;
691 frame = getGraphicAnimationFrame(graphic, player->Frame);
697 if (player->MovDir == MV_LEFT || player->MovDir == MV_RIGHT)
698 sxx = player->GfxPos;
700 syy = player->GfxPos;
703 if (!setup.soft_scrolling && ScreenMovPos)
708 printf("-> %d\n", player->Frame);
711 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
713 if (SHIELD_ON(player))
715 int graphic = (player->shield_deadly_time_left ? IMG_SHIELD_DEADLY_ACTIVE :
716 IMG_SHIELD_NORMAL_ACTIVE);
717 int frame = getGraphicAnimationFrame(graphic, -1);
719 DrawGraphicShiftedThruMask(sx, sy, sxx, syy, graphic, frame, NO_CUTTING);
723 if (player->Pushing && player->GfxPos)
725 if (player->Pushing && player_is_moving)
728 int px = SCREENX(next_jx), py = SCREENY(next_jy);
731 (element == EL_SOKOBAN_FIELD_EMPTY ||
732 Feld[next_jx][next_jy] == EL_SOKOBAN_FIELD_FULL))
733 DrawGraphicShiftedThruMask(px, py, sxx, syy, IMG_SOKOBAN_OBJECT, 0,
737 int element = Feld[next_jx][next_jy];
738 int graphic = el2img(element);
743 if ((sxx || syy) && IS_PUSHABLE(element))
745 graphic = el_dir_act2img(element, player->MovDir, GFX_ACTION_MOVING);
747 frame = getGraphicAnimationFrame(graphic, player->GfxPos);
749 frame = getGraphicAnimationFrame(graphic, player->Frame);
753 printf("-> %d [%d]\n", player->Frame, player->GfxPos);
758 if (player->MovDir == MV_LEFT)
763 frame = (player->GfxPos / (TILEX / 4));
765 if (player->MovDir == MV_RIGHT)
766 frame = (frame + 4) % 4;
770 DrawGraphicShifted(px, py, sxx, syy, graphic, frame,
771 NO_CUTTING, NO_MASKING);
775 /* draw things in front of player (active dynamite or dynabombs) */
777 if (IS_ACTIVE_BOMB(element))
779 graphic = el2img(element);
782 if (element == EL_DYNAMITE_ACTIVE)
784 if ((frame = (96 - MovDelay[jx][jy]) / 12) > 6)
789 if ((frame = ((96 - MovDelay[jx][jy]) / 6) % 8) > 3)
795 frame = getGraphicAnimationFrame(graphic, 96 - MovDelay[jx][jy]);
797 frame = getGraphicAnimationFrame(graphic, GfxFrame[jx][jy]);
802 if (game.emulation == EMU_SUPAPLEX)
803 DrawGraphic(sx, sy, IMG_SP_DISK_RED, frame);
805 DrawGraphicThruMask(sx, sy, graphic, frame);
808 if (player_is_moving && last_element == EL_EXPLOSION)
810 int stored = Store[last_jx][last_jy];
811 int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
812 stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
814 int delay = (game.emulation == EMU_SUPAPLEX ? 3 : 2);
815 int phase = ExplodePhase[last_jx][last_jy] - 1;
816 int frame = getGraphicAnimationFrame(graphic, phase - delay);
819 DrawGraphicThruMask(SCREENX(last_jx), SCREENY(last_jy), graphic, frame);
822 /* draw elements that stay over the player */
823 /* handle the field the player is leaving ... */
824 if (player_is_moving && IS_OVER_PLAYER(last_element))
825 DrawLevelField(last_jx, last_jy);
827 /* ... and the field the player is entering */
828 if (IS_OVER_PLAYER(element))
829 DrawLevelField(jx, jy);
831 if (setup.direct_draw)
833 int dest_x = SX + SCREENX(MIN(jx, last_jx)) * TILEX;
834 int dest_y = SY + SCREENY(MIN(jy, last_jy)) * TILEY;
835 int x_size = TILEX * (1 + ABS(jx - last_jx));
836 int y_size = TILEY * (1 + ABS(jy - last_jy));
838 BlitBitmap(drawto_field, window,
839 dest_x, dest_y, x_size, y_size, dest_x, dest_y);
840 SetDrawtoField(DRAW_DIRECT);
843 MarkTileDirty(sx,sy);
846 void getGraphicSource(int graphic, int frame, Bitmap **bitmap, int *x, int *y)
848 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
849 int offset_x = graphic_info[graphic].offset_x;
850 int offset_y = graphic_info[graphic].offset_y;
851 int src_x = graphic_info[graphic].src_x + frame * offset_x;
852 int src_y = graphic_info[graphic].src_y + frame * offset_y;
854 *bitmap = src_bitmap;
859 void DrawGraphic(int x, int y, int graphic, int frame)
862 if (!IN_SCR_FIELD(x, y))
864 printf("DrawGraphic(): x = %d, y = %d, graphic = %d\n", x, y, graphic);
865 printf("DrawGraphic(): This should never happen!\n");
870 DrawGraphicExt(drawto_field, FX + x * TILEX, FY + y * TILEY, graphic, frame);
875 void DrawOldGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic)
880 getOldGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
881 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
885 void DrawGraphicExt(DrawBuffer *dst_bitmap, int x, int y, int graphic,
892 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
894 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
895 int src_x = graphic_info[graphic].src_x;
896 int src_y = graphic_info[graphic].src_y;
897 int offset_x = graphic_info[graphic].offset_x;
898 int offset_y = graphic_info[graphic].offset_y;
900 src_x += frame * offset_x;
901 src_y += frame * offset_y;
904 BlitBitmap(src_bitmap, dst_bitmap, src_x, src_y, TILEX, TILEY, x, y);
907 void DrawGraphicThruMask(int x, int y, int graphic, int frame)
910 if (!IN_SCR_FIELD(x, y))
912 printf("DrawGraphicThruMask(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
913 printf("DrawGraphicThruMask(): This should never happen!\n");
918 DrawGraphicThruMaskExt(drawto_field, FX + x * TILEX, FY + y *TILEY, graphic,
923 void DrawGraphicThruMaskExt(DrawBuffer *d, int dest_x, int dest_y, int graphic,
931 getGraphicSource(graphic, frame, &src_bitmap, &src_x, &src_y);
932 drawing_gc = src_bitmap->stored_clip_gc;
934 GC drawing_gc = src_bitmap->stored_clip_gc;
935 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
936 int src_x = graphic_info[graphic].src_x;
937 int src_y = graphic_info[graphic].src_y;
938 int offset_x = graphic_info[graphic].offset_x;
939 int offset_y = graphic_info[graphic].offset_y;
941 src_x += frame * offset_x;
942 src_y += frame * offset_y;
946 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
947 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
950 void DrawMiniGraphic(int x, int y, int graphic)
952 DrawMiniGraphicExt(drawto, SX + x * MINI_TILEX,SY + y * MINI_TILEY, graphic);
953 MarkTileDirty(x / 2, y / 2);
956 void getMiniGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
958 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
960 int mini_starty = src_bitmap->height * 2 / 3;
961 int src_x = mini_startx + graphic_info[graphic].src_x / 2;
962 int src_y = mini_starty + graphic_info[graphic].src_y / 2;
964 if (src_x + MINI_TILEX > src_bitmap->width ||
965 src_y + MINI_TILEY > src_bitmap->height)
967 /* graphic of desired size seems not to be contained in this image;
968 dirty workaround: get it from the middle of the normal sized image */
970 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
971 src_x += (TILEX / 2 - MINI_TILEX / 2);
972 src_y += (TILEY / 2 - MINI_TILEY / 2);
975 *bitmap = src_bitmap;
980 void DrawMiniGraphicExt(DrawBuffer *d, int x, int y, int graphic)
985 getMiniGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
986 BlitBitmap(src_bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
989 void DrawGraphicShifted(int x,int y, int dx,int dy, int graphic, int frame,
990 int cut_mode, int mask_mode)
999 int width = TILEX, height = TILEY;
1005 DrawGraphic(x, y, graphic, frame);
1009 if (dx || dy) /* shifted graphic */
1011 if (x < BX1) /* object enters playfield from the left */
1018 else if (x > BX2) /* object enters playfield from the right */
1024 else if (x==BX1 && dx < 0) /* object leaves playfield to the left */
1030 else if (x==BX2 && dx > 0) /* object leaves playfield to the right */
1032 else if (dx) /* general horizontal movement */
1033 MarkTileDirty(x + SIGN(dx), y);
1035 if (y < BY1) /* object enters playfield from the top */
1037 if (cut_mode==CUT_BELOW) /* object completely above top border */
1045 else if (y > BY2) /* object enters playfield from the bottom */
1051 else if (y==BY1 && dy < 0) /* object leaves playfield to the top */
1057 else if (dy > 0 && cut_mode == CUT_ABOVE)
1059 if (y == BY2) /* object completely above bottom border */
1065 MarkTileDirty(x, y + 1);
1066 } /* object leaves playfield to the bottom */
1067 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
1069 else if (dy) /* general vertical movement */
1070 MarkTileDirty(x, y + SIGN(dy));
1073 src_bitmap = graphic_info[graphic].bitmap;
1074 src_x = graphic_info[graphic].src_x;
1075 src_y = graphic_info[graphic].src_y;
1076 offset_x = graphic_info[graphic].offset_x;
1077 offset_y = graphic_info[graphic].offset_y;
1079 drawing_gc = src_bitmap->stored_clip_gc;
1081 src_x += frame * offset_x;
1082 src_y += frame * offset_y;
1087 dest_x = FX + x * TILEX + dx;
1088 dest_y = FY + y * TILEY + dy;
1091 if (!IN_SCR_FIELD(x,y))
1093 printf("DrawGraphicShifted(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
1094 printf("DrawGraphicShifted(): This should never happen!\n");
1099 if (mask_mode == USE_MASKING)
1101 SetClipOrigin(src_bitmap, drawing_gc, dest_x - src_x, dest_y - src_y);
1102 BlitBitmapMasked(src_bitmap, drawto_field, src_x, src_y, width, height,
1106 BlitBitmap(src_bitmap, drawto_field, src_x, src_y, width, height,
1112 void DrawGraphicShiftedThruMask(int x,int y, int dx,int dy, int graphic,
1113 int frame, int cut_mode)
1115 DrawGraphicShifted(x,y, dx,dy, graphic, frame, cut_mode, USE_MASKING);
1118 inline static int getFramePosition(int x, int y)
1120 int frame_pos = -1; /* default: global synchronization */
1122 int element = Feld[x][y];
1124 if (element == EL_QUICKSAND_FULL ||
1125 element == EL_MAGIC_WALL_FULL ||
1126 element == EL_BD_MAGIC_WALL_FULL)
1128 else if (IS_MOVING(x, y) || CAN_MOVE(element) || CAN_FALL(element))
1129 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1132 frame_pos = ABS(MovPos[x][y]) / (TILEX / 8);
1134 frame_pos = GfxFrame[x][y];
1141 inline static int getGfxAction(int x, int y)
1143 int gfx_action = GFX_ACTION_DEFAULT;
1146 if (GfxAction[x][y] != GFX_ACTION_DEFAULT)
1147 gfx_action = GfxAction[x][y];
1148 else if (IS_MOVING(x, y))
1149 gfx_action = GFX_ACTION_MOVING;
1151 gfx_action = GfxAction[x][y];
1156 printf("getGfxAction: THIS SHOULD NEVER HAPPEN: GfxAction[%d][%d] == %d\n",
1163 void DrawScreenElementExt(int x, int y, int dx, int dy, int element,
1164 int cut_mode, int mask_mode)
1166 int ux = LEVELX(x), uy = LEVELY(y);
1170 if (IN_LEV_FIELD(ux, uy))
1172 int move_dir = MovDir[ux][uy];
1173 int move_pos = getFramePosition(ux, uy);
1174 int gfx_action = getGfxAction(ux, uy);
1176 graphic = el_dir_act2img(element, move_dir, gfx_action);
1177 frame = getGraphicAnimationFrame(graphic, move_pos);
1181 graphic = el2img(element);
1182 frame = getGraphicAnimationFrame(graphic, 0);
1185 if (element == EL_WALL_GROWING)
1187 boolean left_stopped = FALSE, right_stopped = FALSE;
1189 if (!IN_LEV_FIELD(ux - 1, uy) || IS_MAUER(Feld[ux - 1][uy]))
1190 left_stopped = TRUE;
1191 if (!IN_LEV_FIELD(ux + 1, uy) || IS_MAUER(Feld[ux + 1][uy]))
1192 right_stopped = TRUE;
1194 if (left_stopped && right_stopped)
1196 else if (left_stopped)
1198 graphic = IMG_WALL_GROWING_ACTIVE_RIGHT;
1199 frame = graphic_info[graphic].anim_frames - 1;
1201 else if (right_stopped)
1203 graphic = IMG_WALL_GROWING_ACTIVE_LEFT;
1204 frame = graphic_info[graphic].anim_frames - 1;
1207 else if (IS_AMOEBOID(element) || element == EL_AMOEBA_DRIPPING)
1209 graphic = (element == EL_BD_AMOEBA ? IMG_BD_AMOEBA_PART1 :
1210 element == EL_AMOEBA_WET ? IMG_AMOEBA_WET_PART1 :
1211 element == EL_AMOEBA_DRY ? IMG_AMOEBA_DRY_PART1 :
1212 element == EL_AMOEBA_FULL ? IMG_AMOEBA_FULL_PART1 :
1213 IMG_AMOEBA_DEAD_PART1);
1215 graphic += (x + 2 * y + 4) % 4;
1219 DrawGraphicShifted(x, y, dx, dy, graphic, frame, cut_mode, mask_mode);
1220 else if (mask_mode == USE_MASKING)
1221 DrawGraphicThruMask(x, y, graphic, frame);
1223 DrawGraphic(x, y, graphic, frame);
1226 void DrawLevelElementExt(int x, int y, int dx, int dy, int element,
1227 int cut_mode, int mask_mode)
1229 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1230 DrawScreenElementExt(SCREENX(x), SCREENY(y), dx, dy, element,
1231 cut_mode, mask_mode);
1234 void DrawScreenElementShifted(int x, int y, int dx, int dy, int element,
1237 DrawScreenElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1240 void DrawLevelElementShifted(int x, int y, int dx, int dy, int element,
1243 DrawLevelElementExt(x, y, dx, dy, element, cut_mode, NO_MASKING);
1247 void DrawOldScreenElementThruMask(int x, int y, int element)
1249 DrawOldScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1252 void DrawScreenElementThruMask(int x, int y, int element)
1254 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1258 void DrawLevelElementThruMask(int x, int y, int element)
1260 DrawLevelElementExt(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
1263 void DrawLevelFieldThruMask(int x, int y)
1265 DrawLevelElementExt(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
1268 void DrawCrumbledSand(int x, int y)
1272 int i, width, height, cx,cy;
1273 int ux = LEVELX(x), uy = LEVELY(y);
1274 int element, graphic;
1276 static int xy[4][2] =
1284 if (!IN_LEV_FIELD(ux, uy))
1287 element = Feld[ux][uy];
1289 if (element == EL_SAND ||
1290 element == EL_LANDMINE ||
1291 element == EL_TRAP ||
1292 element == EL_TRAP_ACTIVE)
1294 if (!IN_SCR_FIELD(x, y))
1297 graphic = IMG_SAND_CRUMBLED;
1299 src_bitmap = graphic_info[graphic].bitmap;
1300 src_x = graphic_info[graphic].src_x;
1301 src_y = graphic_info[graphic].src_y;
1307 uxx = ux + xy[i][0];
1308 uyy = uy + xy[i][1];
1309 if (!IN_LEV_FIELD(uxx, uyy))
1310 element = EL_STEELWALL;
1312 element = Feld[uxx][uyy];
1314 if (element == EL_SAND ||
1315 element == EL_LANDMINE ||
1316 element == EL_TRAP ||
1317 element == EL_TRAP_ACTIVE)
1320 if (i == 1 || i == 2)
1324 cx = (i == 2 ? TILEX - snip : 0);
1332 cy = (i == 3 ? TILEY - snip : 0);
1335 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1336 width, height, FX + x * TILEX + cx, FY + y * TILEY + cy);
1339 MarkTileDirty(x, y);
1343 graphic = IMG_SAND_CRUMBLED;
1345 src_bitmap = graphic_info[graphic].bitmap;
1346 src_x = graphic_info[graphic].src_x;
1347 src_y = graphic_info[graphic].src_y;
1351 int xx, yy, uxx, uyy;
1355 uxx = ux + xy[i][0];
1356 uyy = uy + xy[i][1];
1358 if (!IN_LEV_FIELD(uxx, uyy) ||
1359 (Feld[uxx][uyy] != EL_SAND &&
1360 Feld[uxx][uyy] != EL_LANDMINE &&
1361 Feld[uxx][uyy] != EL_TRAP &&
1362 Feld[uxx][uyy] != EL_TRAP_ACTIVE) ||
1363 !IN_SCR_FIELD(xx, yy))
1366 if (i == 1 || i == 2)
1370 cx = (i == 1 ? TILEX - snip : 0);
1378 cy = (i==0 ? TILEY-snip : 0);
1381 BlitBitmap(src_bitmap, drawto_field, src_x + cx, src_y + cy,
1382 width, height, FX + xx * TILEX + cx, FY + yy * TILEY + cy);
1384 MarkTileDirty(xx, yy);
1389 void DrawScreenElement(int x, int y, int element)
1391 DrawScreenElementExt(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
1392 DrawCrumbledSand(x, y);
1395 void DrawLevelElement(int x, int y, int element)
1397 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1398 DrawScreenElement(SCREENX(x), SCREENY(y), element);
1401 void DrawScreenField(int x, int y)
1403 int ux = LEVELX(x), uy = LEVELY(y);
1404 int element, content;
1406 if (!IN_LEV_FIELD(ux, uy))
1408 if (ux < -1 || ux > lev_fieldx || uy < -1 || uy > lev_fieldy)
1411 element = BorderElement;
1413 DrawScreenElement(x, y, element);
1417 element = Feld[ux][uy];
1418 content = Store[ux][uy];
1420 if (IS_MOVING(ux, uy))
1422 int horiz_move = (MovDir[ux][uy] == MV_LEFT || MovDir[ux][uy] == MV_RIGHT);
1423 boolean cut_mode = NO_CUTTING;
1425 if (element == EL_QUICKSAND_EMPTYING ||
1426 element == EL_MAGIC_WALL_EMPTYING ||
1427 element == EL_BD_MAGIC_WALL_EMPTYING ||
1428 element == EL_AMOEBA_DRIPPING)
1429 cut_mode = CUT_ABOVE;
1430 else if (element == EL_QUICKSAND_FILLING ||
1431 element == EL_MAGIC_WALL_FILLING ||
1432 element == EL_BD_MAGIC_WALL_FILLING)
1433 cut_mode = CUT_BELOW;
1435 if (cut_mode == CUT_ABOVE)
1436 DrawScreenElementShifted(x, y, 0, 0, element, NO_CUTTING);
1438 DrawScreenElement(x, y, EL_EMPTY);
1441 DrawScreenElementShifted(x, y, MovPos[ux][uy], 0, element, NO_CUTTING);
1442 else if (cut_mode == NO_CUTTING)
1443 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], element, cut_mode);
1445 DrawScreenElementShifted(x, y, 0, MovPos[ux][uy], content, cut_mode);
1447 if (content == EL_ACID)
1448 DrawLevelElementThruMask(ux, uy + 1, EL_ACID);
1450 else if (IS_BLOCKED(ux, uy))
1455 boolean cut_mode = NO_CUTTING;
1456 int element_old, content_old;
1458 Blocked2Moving(ux, uy, &oldx, &oldy);
1461 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
1462 MovDir[oldx][oldy] == MV_RIGHT);
1464 element_old = Feld[oldx][oldy];
1465 content_old = Store[oldx][oldy];
1467 if (element_old == EL_QUICKSAND_EMPTYING ||
1468 element_old == EL_MAGIC_WALL_EMPTYING ||
1469 element_old == EL_BD_MAGIC_WALL_EMPTYING ||
1470 element_old == EL_AMOEBA_DRIPPING)
1471 cut_mode = CUT_ABOVE;
1473 DrawScreenElement(x, y, EL_EMPTY);
1476 DrawScreenElementShifted(sx, sy, MovPos[oldx][oldy], 0, element_old,
1478 else if (cut_mode == NO_CUTTING)
1479 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], element_old,
1482 DrawScreenElementShifted(sx, sy, 0, MovPos[oldx][oldy], content_old,
1485 else if (IS_DRAWABLE(element))
1486 DrawScreenElement(x, y, element);
1488 DrawScreenElement(x, y, EL_EMPTY);
1491 void DrawLevelField(int x, int y)
1493 if (IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
1494 DrawScreenField(SCREENX(x), SCREENY(y));
1495 else if (IS_MOVING(x, y))
1499 Moving2Blocked(x, y, &newx, &newy);
1500 if (IN_SCR_FIELD(SCREENX(newx), SCREENY(newy)))
1501 DrawScreenField(SCREENX(newx), SCREENY(newy));
1503 else if (IS_BLOCKED(x, y))
1507 Blocked2Moving(x, y, &oldx, &oldy);
1508 if (IN_SCR_FIELD(SCREENX(oldx), SCREENY(oldy)))
1509 DrawScreenField(SCREENX(oldx), SCREENY(oldy));
1513 void DrawMiniElement(int x, int y, int element)
1517 graphic = el2img(element);
1518 DrawMiniGraphic(x, y, graphic);
1521 void DrawMiniElementOrWall(int sx, int sy, int scroll_x, int scroll_y)
1523 int x = sx + scroll_x, y = sy + scroll_y;
1525 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
1526 DrawMiniElement(sx, sy, EL_EMPTY);
1527 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
1528 DrawMiniElement(sx, sy, Feld[x][y]);
1531 int steel_type, steel_position;
1534 { IMG_STEELWALL_TOPLEFT, IMG_INVISIBLE_STEELWALL_TOPLEFT },
1535 { IMG_STEELWALL_TOPRIGHT, IMG_INVISIBLE_STEELWALL_TOPRIGHT },
1536 { IMG_STEELWALL_BOTTOMLEFT, IMG_INVISIBLE_STEELWALL_BOTTOMLEFT },
1537 { IMG_STEELWALL_BOTTOMRIGHT, IMG_INVISIBLE_STEELWALL_BOTTOMRIGHT },
1538 { IMG_STEELWALL_VERTICAL, IMG_INVISIBLE_STEELWALL_VERTICAL },
1539 { IMG_STEELWALL_HORIZONTAL, IMG_INVISIBLE_STEELWALL_HORIZONTAL }
1542 steel_type = (BorderElement == EL_STEELWALL ? 0 : 1);
1543 steel_position = (x == -1 && y == -1 ? 0 :
1544 x == lev_fieldx && y == -1 ? 1 :
1545 x == -1 && y == lev_fieldy ? 2 :
1546 x == lev_fieldx && y == lev_fieldy ? 3 :
1547 x == -1 || x == lev_fieldx ? 4 :
1548 y == -1 || y == lev_fieldy ? 5 : -1);
1550 if (steel_position != -1)
1551 DrawMiniGraphic(sx, sy, border[steel_position][steel_type]);
1555 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
1557 Bitmap *src_bitmap = graphic_info[graphic].bitmap;
1558 int mini_startx = src_bitmap->width * 3 / 4;
1559 int mini_starty = src_bitmap->height * 2 / 3;
1560 int src_x = mini_startx + graphic_info[graphic].src_x / 8;
1561 int src_y = mini_starty + graphic_info[graphic].src_y / 8;
1563 if (src_x + MICRO_TILEX > src_bitmap->width ||
1564 src_y + MICRO_TILEY > src_bitmap->height)
1566 /* graphic of desired size seems not to be contained in this image;
1567 dirty workaround: get it from the middle of the normal sized image */
1569 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
1570 src_x += (TILEX / 2 - MICRO_TILEX / 2);
1571 src_y += (TILEY / 2 - MICRO_TILEY / 2);
1574 *bitmap = src_bitmap;
1579 void DrawMicroElement(int xpos, int ypos, int element)
1583 int graphic = el2img(element);
1585 getMicroGraphicSource(graphic, &src_bitmap, &src_x, &src_y);
1586 BlitBitmap(src_bitmap, drawto, src_x, src_y, MICRO_TILEX, MICRO_TILEY,
1594 SetDrawBackgroundMask(REDRAW_NONE);
1597 for(x=BX1; x<=BX2; x++)
1598 for(y=BY1; y<=BY2; y++)
1599 DrawScreenField(x, y);
1601 redraw_mask |= REDRAW_FIELD;
1604 void DrawMiniLevel(int size_x, int size_y, int scroll_x, int scroll_y)
1608 for(x=0; x<size_x; x++)
1609 for(y=0; y<size_y; y++)
1610 DrawMiniElementOrWall(x, y, scroll_x, scroll_y);
1612 redraw_mask |= REDRAW_FIELD;
1615 static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
1619 DrawBackground(xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
1621 if (lev_fieldx < STD_LEV_FIELDX)
1622 xpos += (STD_LEV_FIELDX - lev_fieldx) / 2 * MICRO_TILEX;
1623 if (lev_fieldy < STD_LEV_FIELDY)
1624 ypos += (STD_LEV_FIELDY - lev_fieldy) / 2 * MICRO_TILEY;
1626 xpos += MICRO_TILEX;
1627 ypos += MICRO_TILEY;
1629 for(x=-1; x<=STD_LEV_FIELDX; x++)
1631 for(y=-1; y<=STD_LEV_FIELDY; y++)
1633 int lx = from_x + x, ly = from_y + y;
1635 if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
1636 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1638 else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
1639 && BorderElement != EL_EMPTY)
1640 DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
1645 redraw_mask |= REDRAW_MICROLEVEL;
1648 #define MICROLABEL_EMPTY 0
1649 #define MICROLABEL_LEVEL_NAME 1
1650 #define MICROLABEL_CREATED_BY 2
1651 #define MICROLABEL_LEVEL_AUTHOR 3
1652 #define MICROLABEL_IMPORTED_FROM 4
1653 #define MICROLABEL_LEVEL_IMPORT_INFO 5
1655 #define MAX_MICROLABEL_SIZE (SXSIZE / FONT4_XSIZE)
1657 static void DrawMicroLevelLabelExt(int mode)
1659 char label_text[MAX_MICROLABEL_SIZE + 1];
1661 DrawBackground(SX, MICROLABEL_YPOS, SXSIZE, FONT4_YSIZE);
1663 strncpy(label_text, (mode == MICROLABEL_LEVEL_NAME ? level.name :
1664 mode == MICROLABEL_CREATED_BY ? "created by" :
1665 mode == MICROLABEL_LEVEL_AUTHOR ? level.author :
1666 mode == MICROLABEL_IMPORTED_FROM ? "imported from" :
1667 mode == MICROLABEL_LEVEL_IMPORT_INFO ?
1668 leveldir_current->imported_from : ""),
1669 MAX_MICROLABEL_SIZE);
1670 label_text[MAX_MICROLABEL_SIZE] = '\0';
1672 if (strlen(label_text) > 0)
1674 int lxpos = SX + (SXSIZE - strlen(label_text) * FONT4_XSIZE) / 2;
1675 int lypos = MICROLABEL_YPOS;
1677 DrawText(lxpos, lypos, label_text, FS_SMALL, FC_SPECIAL2);
1680 redraw_mask |= REDRAW_MICROLEVEL;
1683 void DrawMicroLevel(int xpos, int ypos, boolean restart)
1685 static unsigned long scroll_delay = 0;
1686 static unsigned long label_delay = 0;
1687 static int from_x, from_y, scroll_direction;
1688 static int label_state, label_counter;
1692 from_x = from_y = 0;
1693 scroll_direction = MV_RIGHT;
1697 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1698 DrawMicroLevelLabelExt(label_state);
1700 /* initialize delay counters */
1701 DelayReached(&scroll_delay, 0);
1702 DelayReached(&label_delay, 0);
1707 /* scroll micro level, if needed */
1708 if ((lev_fieldx > STD_LEV_FIELDX || lev_fieldy > STD_LEV_FIELDY) &&
1709 DelayReached(&scroll_delay, MICROLEVEL_SCROLL_DELAY))
1711 switch (scroll_direction)
1717 scroll_direction = MV_UP;
1721 if (from_x < lev_fieldx - STD_LEV_FIELDX)
1724 scroll_direction = MV_DOWN;
1731 scroll_direction = MV_RIGHT;
1735 if (from_y < lev_fieldy - STD_LEV_FIELDY)
1738 scroll_direction = MV_LEFT;
1745 DrawMicroLevelExt(xpos, ypos, from_x, from_y);
1748 /* redraw micro level label, if needed */
1749 if (strcmp(level.name, NAMELESS_LEVEL_NAME) != 0 &&
1750 strcmp(level.author, ANONYMOUS_NAME) != 0 &&
1751 strcmp(level.author, leveldir_current->name) != 0 &&
1752 DelayReached(&label_delay, MICROLEVEL_LABEL_DELAY))
1754 int max_label_counter = 23;
1756 if (leveldir_current->imported_from != NULL)
1757 max_label_counter += 14;
1759 label_counter = (label_counter + 1) % max_label_counter;
1760 label_state = (label_counter >= 0 && label_counter <= 7 ?
1761 MICROLABEL_LEVEL_NAME :
1762 label_counter >= 9 && label_counter <= 12 ?
1763 MICROLABEL_CREATED_BY :
1764 label_counter >= 14 && label_counter <= 21 ?
1765 MICROLABEL_LEVEL_AUTHOR :
1766 label_counter >= 23 && label_counter <= 26 ?
1767 MICROLABEL_IMPORTED_FROM :
1768 label_counter >= 28 && label_counter <= 35 ?
1769 MICROLABEL_LEVEL_IMPORT_INFO : MICROLABEL_EMPTY);
1770 DrawMicroLevelLabelExt(label_state);
1774 int REQ_in_range(int x, int y)
1776 if (y > DY+249 && y < DY+278)
1778 if (x > DX+1 && x < DX+48)
1780 else if (x > DX+51 && x < DX+98)
1786 #define MAX_REQUEST_LINES 13
1787 #define MAX_REQUEST_LINE_LEN 7
1789 boolean Request(char *text, unsigned int req_state)
1791 int mx, my, ty, result = -1;
1792 unsigned int old_door_state;
1794 #if defined(PLATFORM_UNIX)
1795 /* pause network game while waiting for request to answer */
1796 if (options.network &&
1797 game_status == PLAYING &&
1798 req_state & REQUEST_WAIT_FOR)
1799 SendToServer_PausePlaying();
1802 old_door_state = GetDoorState();
1806 CloseDoor(DOOR_CLOSE_1);
1808 /* save old door content */
1809 BlitBitmap(bitmap_db_door, bitmap_db_door,
1810 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE,
1811 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1);
1813 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1815 /* clear door drawing field */
1816 DrawBackground(DX, DY, DXSIZE, DYSIZE);
1818 /* write text for request */
1819 for(ty=0; ty < MAX_REQUEST_LINES; ty++)
1821 char text_line[MAX_REQUEST_LINE_LEN + 1];
1827 for(tl=0,tx=0; tx < MAX_REQUEST_LINE_LEN; tl++,tx++)
1830 if (!tc || tc == ' ')
1841 strncpy(text_line, text, tl);
1844 DrawText(DX + 50 - (tl * 14)/2, DY + 8 + ty * 16,
1845 text_line, FS_SMALL, FC_YELLOW);
1847 text += tl + (tc == ' ' ? 1 : 0);
1850 if (req_state & REQ_ASK)
1852 MapGadget(tool_gadget[TOOL_CTRL_ID_YES]);
1853 MapGadget(tool_gadget[TOOL_CTRL_ID_NO]);
1855 else if (req_state & REQ_CONFIRM)
1857 MapGadget(tool_gadget[TOOL_CTRL_ID_CONFIRM]);
1859 else if (req_state & REQ_PLAYER)
1861 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_1]);
1862 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_2]);
1863 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_3]);
1864 MapGadget(tool_gadget[TOOL_CTRL_ID_PLAYER_4]);
1867 /* copy request gadgets to door backbuffer */
1868 BlitBitmap(drawto, bitmap_db_door,
1869 DX, DY, DXSIZE, DYSIZE,
1870 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
1872 OpenDoor(DOOR_OPEN_1);
1878 if (!(req_state & REQUEST_WAIT_FOR))
1880 SetDrawBackgroundMask(REDRAW_FIELD);
1885 if (game_status != MAINMENU)
1888 button_status = MB_RELEASED;
1890 request_gadget_id = -1;
1892 SetDrawBackgroundMask(REDRAW_FIELD | REDRAW_DOOR_1);
1904 case EVENT_BUTTONPRESS:
1905 case EVENT_BUTTONRELEASE:
1906 case EVENT_MOTIONNOTIFY:
1908 if (event.type == EVENT_MOTIONNOTIFY)
1910 if (!PointerInWindow(window))
1911 continue; /* window and pointer are on different screens */
1916 motion_status = TRUE;
1917 mx = ((MotionEvent *) &event)->x;
1918 my = ((MotionEvent *) &event)->y;
1922 motion_status = FALSE;
1923 mx = ((ButtonEvent *) &event)->x;
1924 my = ((ButtonEvent *) &event)->y;
1925 if (event.type == EVENT_BUTTONPRESS)
1926 button_status = ((ButtonEvent *) &event)->button;
1928 button_status = MB_RELEASED;
1931 /* this sets 'request_gadget_id' */
1932 HandleGadgets(mx, my, button_status);
1934 switch(request_gadget_id)
1936 case TOOL_CTRL_ID_YES:
1939 case TOOL_CTRL_ID_NO:
1942 case TOOL_CTRL_ID_CONFIRM:
1943 result = TRUE | FALSE;
1946 case TOOL_CTRL_ID_PLAYER_1:
1949 case TOOL_CTRL_ID_PLAYER_2:
1952 case TOOL_CTRL_ID_PLAYER_3:
1955 case TOOL_CTRL_ID_PLAYER_4:
1966 case EVENT_KEYPRESS:
1967 switch(GetEventKey((KeyEvent *)&event, TRUE))
1980 if (req_state & REQ_PLAYER)
1984 case EVENT_KEYRELEASE:
1985 ClearPlayerAction();
1989 HandleOtherEvents(&event);
1993 else if (AnyJoystickButton() == JOY_BUTTON_NEW_PRESSED)
1995 int joy = AnyJoystick();
1997 if (joy & JOY_BUTTON_1)
1999 else if (joy & JOY_BUTTON_2)
2005 /* don't eat all CPU time */
2009 if (game_status != MAINMENU)
2014 if (!(req_state & REQ_STAY_OPEN))
2016 CloseDoor(DOOR_CLOSE_1);
2018 if (!(req_state & REQ_STAY_CLOSED) && (old_door_state & DOOR_OPEN_1))
2020 BlitBitmap(bitmap_db_door, bitmap_db_door,
2021 DOOR_GFX_PAGEX2,DOOR_GFX_PAGEY1, DXSIZE,DYSIZE,
2022 DOOR_GFX_PAGEX1,DOOR_GFX_PAGEY1);
2023 OpenDoor(DOOR_OPEN_1);
2029 SetDrawBackgroundMask(REDRAW_FIELD);
2031 #if defined(PLATFORM_UNIX)
2032 /* continue network game after request */
2033 if (options.network &&
2034 game_status == PLAYING &&
2035 req_state & REQUEST_WAIT_FOR)
2036 SendToServer_ContinuePlaying();
2042 unsigned int OpenDoor(unsigned int door_state)
2044 unsigned int new_door_state;
2046 if (door_state & DOOR_COPY_BACK)
2048 BlitBitmap(bitmap_db_door, bitmap_db_door,
2049 DOOR_GFX_PAGEX2, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE + VYSIZE,
2050 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2051 door_state &= ~DOOR_COPY_BACK;
2054 new_door_state = MoveDoor(door_state);
2056 return(new_door_state);
2059 unsigned int CloseDoor(unsigned int door_state)
2061 unsigned int new_door_state;
2063 BlitBitmap(backbuffer, bitmap_db_door,
2064 DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
2065 BlitBitmap(backbuffer, bitmap_db_door,
2066 VX, VY, VXSIZE, VYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2);
2068 new_door_state = MoveDoor(door_state);
2070 return(new_door_state);
2073 unsigned int GetDoorState()
2075 return MoveDoor(DOOR_GET_STATE);
2078 unsigned int SetDoorState(unsigned int door_state)
2080 return MoveDoor(door_state | DOOR_SET_STATE);
2083 unsigned int MoveDoor(unsigned int door_state)
2085 static int door1 = DOOR_OPEN_1;
2086 static int door2 = DOOR_CLOSE_2;
2087 static unsigned long door_delay = 0;
2088 int x, start, stepsize = 2;
2089 unsigned long door_delay_value = stepsize * 5;
2091 if (door_state == DOOR_GET_STATE)
2092 return(door1 | door2);
2094 if (door_state & DOOR_SET_STATE)
2096 if (door_state & DOOR_ACTION_1)
2097 door1 = door_state & DOOR_ACTION_1;
2098 if (door_state & DOOR_ACTION_2)
2099 door2 = door_state & DOOR_ACTION_2;
2101 return(door1 | door2);
2104 if (door1 == DOOR_OPEN_1 && door_state & DOOR_OPEN_1)
2105 door_state &= ~DOOR_OPEN_1;
2106 else if (door1 == DOOR_CLOSE_1 && door_state & DOOR_CLOSE_1)
2107 door_state &= ~DOOR_CLOSE_1;
2108 if (door2 == DOOR_OPEN_2 && door_state & DOOR_OPEN_2)
2109 door_state &= ~DOOR_OPEN_2;
2110 else if (door2 == DOOR_CLOSE_2 && door_state & DOOR_CLOSE_2)
2111 door_state &= ~DOOR_CLOSE_2;
2113 if (setup.quick_doors)
2116 door_delay_value = 0;
2118 StopSound(SND_MENU_DOOR_OPENING);
2119 StopSound(SND_MENU_DOOR_CLOSING);
2122 if (global.autoplay_leveldir)
2124 door_state |= DOOR_NO_DELAY;
2125 door_state &= ~DOOR_CLOSE_ALL;
2128 if (door_state & DOOR_ACTION)
2130 if (!(door_state & DOOR_NO_DELAY))
2132 /* opening door sound has priority over simultaneously closing door */
2133 if (door_state & (DOOR_OPEN_1 | DOOR_OPEN_2))
2134 PlaySoundStereo(SND_MENU_DOOR_OPENING, SOUND_MAX_RIGHT);
2135 else if (door_state & (DOOR_CLOSE_1 | DOOR_CLOSE_2))
2136 PlaySoundStereo(SND_MENU_DOOR_CLOSING, SOUND_MAX_RIGHT);
2139 start = ((door_state & DOOR_NO_DELAY) ? DXSIZE : 0);
2141 for(x=start; x<=DXSIZE; x+=stepsize)
2143 Bitmap *bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2144 GC gc = bitmap->stored_clip_gc;
2146 if (!(door_state & DOOR_NO_DELAY))
2147 WaitUntilDelayReached(&door_delay, door_delay_value);
2149 if (door_state & DOOR_ACTION_1)
2151 int i = (door_state & DOOR_OPEN_1 ? DXSIZE-x : x);
2152 int j = (DXSIZE - i) / 3;
2154 BlitBitmap(bitmap_db_door, drawto,
2155 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1 + i/2,
2156 DXSIZE,DYSIZE - i/2, DX, DY);
2158 ClearRectangle(drawto, DX, DY + DYSIZE - i/2, DXSIZE,i/2);
2160 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2161 BlitBitmapMasked(bitmap, drawto,
2162 DXSIZE, DOOR_GFX_PAGEY1, i, 77,
2163 DX + DXSIZE - i, DY + j);
2164 BlitBitmapMasked(bitmap, drawto,
2165 DXSIZE, DOOR_GFX_PAGEY1 + 140, i, 63,
2166 DX + DXSIZE - i, DY + 140 + j);
2167 SetClipOrigin(bitmap, gc, DX - DXSIZE + i, DY - (DOOR_GFX_PAGEY1 + j));
2168 BlitBitmapMasked(bitmap, drawto,
2169 DXSIZE - i, DOOR_GFX_PAGEY1 + j, i, 77 - j,
2171 BlitBitmapMasked(bitmap, drawto,
2172 DXSIZE-i, DOOR_GFX_PAGEY1 + 140, i, 63,
2175 BlitBitmapMasked(bitmap, drawto,
2176 DXSIZE - i, DOOR_GFX_PAGEY1 + 77, i, 63,
2178 BlitBitmapMasked(bitmap, drawto,
2179 DXSIZE - i, DOOR_GFX_PAGEY1 + 203, i, 77,
2181 SetClipOrigin(bitmap, gc, DX - i, (DY + j) - DOOR_GFX_PAGEY1);
2182 BlitBitmapMasked(bitmap, drawto,
2183 DXSIZE, DOOR_GFX_PAGEY1 + 77, i, 63,
2184 DX + DXSIZE - i, DY + 77 + j);
2185 BlitBitmapMasked(bitmap, drawto,
2186 DXSIZE, DOOR_GFX_PAGEY1 + 203, i, 77 - j,
2187 DX + DXSIZE - i, DY + 203 + j);
2189 redraw_mask |= REDRAW_DOOR_1;
2192 if (door_state & DOOR_ACTION_2)
2194 int i = (door_state & DOOR_OPEN_2 ? VXSIZE - x : x);
2195 int j = (VXSIZE - i) / 3;
2197 BlitBitmap(bitmap_db_door, drawto,
2198 DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY2 + i/2,
2199 VXSIZE, VYSIZE - i/2, VX, VY);
2201 ClearRectangle(drawto, VX, VY + VYSIZE-i/2, VXSIZE, i/2);
2203 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2204 BlitBitmapMasked(bitmap, drawto,
2205 VXSIZE, DOOR_GFX_PAGEY2, i, VYSIZE / 2,
2206 VX + VXSIZE-i, VY+j);
2207 SetClipOrigin(bitmap, gc,
2208 VX - VXSIZE + i, VY - (DOOR_GFX_PAGEY2 + j));
2209 BlitBitmapMasked(bitmap, drawto,
2210 VXSIZE - i, DOOR_GFX_PAGEY2 + j, i, VYSIZE / 2 - j,
2213 BlitBitmapMasked(bitmap, drawto,
2214 VXSIZE - i, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2215 i, VYSIZE / 2, VX, VY + VYSIZE / 2 - j);
2216 SetClipOrigin(bitmap, gc, VX - i, (VY + j) - DOOR_GFX_PAGEY2);
2217 BlitBitmapMasked(bitmap, drawto,
2218 VXSIZE, DOOR_GFX_PAGEY2 + VYSIZE / 2,
2220 VX + VXSIZE - i, VY + VYSIZE / 2 + j);
2222 redraw_mask |= REDRAW_DOOR_2;
2227 if (game_status == MAINMENU)
2232 if (setup.quick_doors)
2234 StopSound(SND_MENU_DOOR_OPENING);
2235 StopSound(SND_MENU_DOOR_CLOSING);
2238 if (door_state & DOOR_ACTION_1)
2239 door1 = door_state & DOOR_ACTION_1;
2240 if (door_state & DOOR_ACTION_2)
2241 door2 = door_state & DOOR_ACTION_2;
2243 return (door1 | door2);
2246 void DrawSpecialEditorDoor()
2248 /* draw bigger toolbox window */
2249 BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
2250 DOOR_GFX_PAGEX7, 0, EXSIZE + 8, 8,
2252 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2253 EX - 4, VY - 4, EXSIZE + 8, EYSIZE - VYSIZE + 4,
2256 redraw_mask |= REDRAW_ALL;
2259 void UndrawSpecialEditorDoor()
2261 /* draw normal tape recorder window */
2262 BlitBitmap(graphic_info[IMG_GLOBAL_BORDER].bitmap, drawto,
2263 EX - 4, EY - 12, EXSIZE + 8, EYSIZE - VYSIZE + 12,
2266 redraw_mask |= REDRAW_ALL;
2270 int ReadPixel(DrawBuffer *bitmap, int x, int y)
2272 XImage *pixel_image;
2273 unsigned long pixel_value;
2275 pixel_image = XGetImage(display, bitmap->drawable,
2276 x, y, 1, 1, AllPlanes, ZPixmap);
2277 pixel_value = XGetPixel(pixel_image, 0, 0);
2279 XDestroyImage(pixel_image);
2285 /* ---------- new tool button stuff ---------------------------------------- */
2287 /* graphic position values for tool buttons */
2288 #define TOOL_BUTTON_YES_XPOS 2
2289 #define TOOL_BUTTON_YES_YPOS 250
2290 #define TOOL_BUTTON_YES_GFX_YPOS 0
2291 #define TOOL_BUTTON_YES_XSIZE 46
2292 #define TOOL_BUTTON_YES_YSIZE 28
2293 #define TOOL_BUTTON_NO_XPOS 52
2294 #define TOOL_BUTTON_NO_YPOS TOOL_BUTTON_YES_YPOS
2295 #define TOOL_BUTTON_NO_GFX_YPOS TOOL_BUTTON_YES_GFX_YPOS
2296 #define TOOL_BUTTON_NO_XSIZE TOOL_BUTTON_YES_XSIZE
2297 #define TOOL_BUTTON_NO_YSIZE TOOL_BUTTON_YES_YSIZE
2298 #define TOOL_BUTTON_CONFIRM_XPOS TOOL_BUTTON_YES_XPOS
2299 #define TOOL_BUTTON_CONFIRM_YPOS TOOL_BUTTON_YES_YPOS
2300 #define TOOL_BUTTON_CONFIRM_GFX_YPOS 30
2301 #define TOOL_BUTTON_CONFIRM_XSIZE 96
2302 #define TOOL_BUTTON_CONFIRM_YSIZE TOOL_BUTTON_YES_YSIZE
2303 #define TOOL_BUTTON_PLAYER_XSIZE 30
2304 #define TOOL_BUTTON_PLAYER_YSIZE 30
2305 #define TOOL_BUTTON_PLAYER_GFX_XPOS 5
2306 #define TOOL_BUTTON_PLAYER_GFX_YPOS 185
2307 #define TOOL_BUTTON_PLAYER_XPOS (5 + TOOL_BUTTON_PLAYER_XSIZE / 2)
2308 #define TOOL_BUTTON_PLAYER_YPOS (215 - TOOL_BUTTON_PLAYER_YSIZE / 2)
2309 #define TOOL_BUTTON_PLAYER1_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2310 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2311 #define TOOL_BUTTON_PLAYER2_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2312 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2313 #define TOOL_BUTTON_PLAYER3_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2314 + 0 * TOOL_BUTTON_PLAYER_XSIZE)
2315 #define TOOL_BUTTON_PLAYER4_XPOS (TOOL_BUTTON_PLAYER_XPOS \
2316 + 1 * TOOL_BUTTON_PLAYER_XSIZE)
2317 #define TOOL_BUTTON_PLAYER1_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2318 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2319 #define TOOL_BUTTON_PLAYER2_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2320 + 0 * TOOL_BUTTON_PLAYER_YSIZE)
2321 #define TOOL_BUTTON_PLAYER3_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2322 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2323 #define TOOL_BUTTON_PLAYER4_YPOS (TOOL_BUTTON_PLAYER_YPOS \
2324 + 1 * TOOL_BUTTON_PLAYER_YSIZE)
2333 } toolbutton_info[NUM_TOOL_BUTTONS] =
2336 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_GFX_YPOS,
2337 TOOL_BUTTON_YES_XPOS, TOOL_BUTTON_YES_YPOS,
2338 TOOL_BUTTON_YES_XSIZE, TOOL_BUTTON_YES_YSIZE,
2343 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_GFX_YPOS,
2344 TOOL_BUTTON_NO_XPOS, TOOL_BUTTON_NO_YPOS,
2345 TOOL_BUTTON_NO_XSIZE, TOOL_BUTTON_NO_YSIZE,
2350 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_GFX_YPOS,
2351 TOOL_BUTTON_CONFIRM_XPOS, TOOL_BUTTON_CONFIRM_YPOS,
2352 TOOL_BUTTON_CONFIRM_XSIZE, TOOL_BUTTON_CONFIRM_YSIZE,
2353 TOOL_CTRL_ID_CONFIRM,
2357 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2358 TOOL_BUTTON_PLAYER1_XPOS, TOOL_BUTTON_PLAYER1_YPOS,
2359 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2360 TOOL_CTRL_ID_PLAYER_1,
2364 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2365 TOOL_BUTTON_PLAYER2_XPOS, TOOL_BUTTON_PLAYER2_YPOS,
2366 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2367 TOOL_CTRL_ID_PLAYER_2,
2371 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2372 TOOL_BUTTON_PLAYER3_XPOS, TOOL_BUTTON_PLAYER3_YPOS,
2373 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2374 TOOL_CTRL_ID_PLAYER_3,
2378 TOOL_BUTTON_PLAYER_GFX_XPOS,TOOL_BUTTON_PLAYER_GFX_YPOS,
2379 TOOL_BUTTON_PLAYER4_XPOS, TOOL_BUTTON_PLAYER4_YPOS,
2380 TOOL_BUTTON_PLAYER_XSIZE, TOOL_BUTTON_PLAYER_YSIZE,
2381 TOOL_CTRL_ID_PLAYER_4,
2386 void CreateToolButtons()
2390 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2392 Bitmap *gd_bitmap = graphic_info[IMG_GLOBAL_DOOR].bitmap;
2393 Bitmap *deco_bitmap = None;
2394 int deco_x = 0, deco_y = 0, deco_xpos = 0, deco_ypos = 0;
2395 struct GadgetInfo *gi;
2396 unsigned long event_mask;
2397 int gd_xoffset, gd_yoffset;
2398 int gd_x1, gd_x2, gd_y;
2401 event_mask = GD_EVENT_RELEASED;
2403 gd_xoffset = toolbutton_info[i].xpos;
2404 gd_yoffset = toolbutton_info[i].ypos;
2405 gd_x1 = DOOR_GFX_PAGEX4 + gd_xoffset;
2406 gd_x2 = DOOR_GFX_PAGEX3 + gd_xoffset;
2407 gd_y = DOOR_GFX_PAGEY1 + gd_yoffset;
2409 if (id >= TOOL_CTRL_ID_PLAYER_1 && id <= TOOL_CTRL_ID_PLAYER_4)
2411 int player_nr = id - TOOL_CTRL_ID_PLAYER_1;
2413 getMiniGraphicSource(PLAYER_NR_GFX(IMG_PLAYER1, player_nr),
2414 &deco_bitmap, &deco_x, &deco_y);
2415 deco_xpos = (toolbutton_info[i].width - MINI_TILEX) / 2;
2416 deco_ypos = (toolbutton_info[i].height - MINI_TILEY) / 2;
2419 gi = CreateGadget(GDI_CUSTOM_ID, id,
2420 GDI_INFO_TEXT, toolbutton_info[i].infotext,
2421 GDI_X, DX + toolbutton_info[i].x,
2422 GDI_Y, DY + toolbutton_info[i].y,
2423 GDI_WIDTH, toolbutton_info[i].width,
2424 GDI_HEIGHT, toolbutton_info[i].height,
2425 GDI_TYPE, GD_TYPE_NORMAL_BUTTON,
2426 GDI_STATE, GD_BUTTON_UNPRESSED,
2427 GDI_DESIGN_UNPRESSED, gd_bitmap, gd_x1, gd_y,
2428 GDI_DESIGN_PRESSED, gd_bitmap, gd_x2, gd_y,
2429 GDI_DECORATION_DESIGN, deco_bitmap, deco_x, deco_y,
2430 GDI_DECORATION_POSITION, deco_xpos, deco_ypos,
2431 GDI_DECORATION_SIZE, MINI_TILEX, MINI_TILEY,
2432 GDI_DECORATION_SHIFTING, 1, 1,
2433 GDI_EVENT_MASK, event_mask,
2434 GDI_CALLBACK_ACTION, HandleToolButtons,
2438 Error(ERR_EXIT, "cannot create gadget");
2440 tool_gadget[id] = gi;
2444 void FreeToolButtons()
2448 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2449 FreeGadget(tool_gadget[i]);
2452 static void UnmapToolButtons()
2456 for (i=0; i<NUM_TOOL_BUTTONS; i++)
2457 UnmapGadget(tool_gadget[i]);
2460 static void HandleToolButtons(struct GadgetInfo *gi)
2462 request_gadget_id = gi->custom_id;
2465 int get_next_element(int element)
2469 case EL_QUICKSAND_FILLING: return EL_QUICKSAND_FULL;
2470 case EL_QUICKSAND_EMPTYING: return EL_QUICKSAND_EMPTY;
2471 case EL_MAGIC_WALL_FILLING: return EL_MAGIC_WALL_FULL;
2472 case EL_MAGIC_WALL_EMPTYING: return EL_MAGIC_WALL_ACTIVE;
2473 case EL_BD_MAGIC_WALL_FILLING: return EL_BD_MAGIC_WALL_FULL;
2474 case EL_BD_MAGIC_WALL_EMPTYING: return EL_BD_MAGIC_WALL_ACTIVE;
2475 case EL_AMOEBA_DRIPPING: return EL_AMOEBA_WET;
2477 default: return element;
2481 int el2img(int element)
2483 int graphic = element_info[element].graphic[GFX_ACTION_DEFAULT];
2487 Error(ERR_WARN, "element %d -> graphic %d -- probably crashing now...",
2494 int el_dir2img(int element, int direction)
2496 return el_dir_act2img(element, direction, GFX_ACTION_DEFAULT);
2499 int el_dir_act2img(int element, int direction, int action)
2504 printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: element == %d\n",
2512 printf("el_dir_act2img: THIS SHOULD NEVER HAPPEN: action == %d\n",
2519 action = graphics_action_mapping[action];
2520 direction = MV_DIR_BIT(direction);
2522 return element_info[element].direction_graphic[action][direction];