removed unused code
[rocksndiamonds.git] / src / game_mm / mm_tools.c
1 /***********************************************************
2 * Mirror Magic -- McDuffin's Revenge                       *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment                      *
5 *               Holger Schemel                             *
6 *               Detmolder Strasse 189                      *
7 *               33604 Bielefeld                            *
8 *               Germany                                    *
9 *               e-mail: info@artsoft.org                   *
10 *----------------------------------------------------------*
11 * tools.c                                                  *
12 ***********************************************************/
13
14 #include "main_mm.h"
15
16 #include "mm_main.h"
17 #include "mm_tools.h"
18
19
20 /* forward declaration for internal use */
21 static int getGraphicAnimationPhase_MM(int, int, int);
22
23 void ClearWindow()
24 {
25   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
26
27   SetDrawtoField(DRAW_BACKBUFFER);
28
29   redraw_mask |= REDRAW_FIELD;
30 }
31
32 static int getGraphicAnimationPhase_MM(int frames, int delay, int mode)
33 {
34   int phase;
35
36   if (mode == ANIM_PINGPONG)
37   {
38     int max_anim_frames = 2 * frames - 2;
39     phase = (FrameCounter % (delay * max_anim_frames)) / delay;
40     phase = (phase < frames ? phase : max_anim_frames - phase);
41   }
42   else
43     phase = (FrameCounter % (delay * frames)) / delay;
44
45   if (mode == ANIM_REVERSE)
46     phase = -phase;
47
48   return(phase);
49 }
50
51 void DrawGraphicAnimationExt_MM(int x, int y, int graphic,
52                                  int frames, int delay, int mode, int mask_mode)
53 {
54   int phase = getGraphicAnimationPhase_MM(frames, delay, mode);
55
56   if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
57   {
58     if (mask_mode == USE_MASKING)
59       DrawGraphicThruMask_MM(SCREENX(x), SCREENY(y), graphic + phase);
60     else
61       DrawGraphic_MM(SCREENX(x), SCREENY(y), graphic + phase);
62   }
63 }
64
65 void DrawGraphicAnimation_MM(int x, int y, int graphic,
66                           int frames, int delay, int mode)
67 {
68   DrawGraphicAnimationExt_MM(x, y, graphic, frames, delay, mode, NO_MASKING);
69 }
70
71 void DrawGraphicAnimationThruMask_MM(int x, int y, int graphic,
72                                   int frames, int delay, int mode)
73 {
74   DrawGraphicAnimationExt_MM(x, y, graphic, frames, delay, mode, USE_MASKING);
75 }
76
77 void DrawGraphic_MM(int x, int y, int graphic)
78 {
79 #if DEBUG
80   if (!IN_SCR_FIELD(x,y))
81   {
82     printf("DrawGraphic_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
83     printf("DrawGraphic_MM(): This should never happen!\n");
84
85     return;
86   }
87 #endif
88
89   DrawGraphicExt_MM(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
90   MarkTileDirty(x, y);
91 }
92
93 void DrawGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
94 {
95   Bitmap *bitmap;
96   int src_x, src_y;
97
98   getGraphicSource(graphic, 0, &bitmap, &src_x, &src_y);
99   BlitBitmap(bitmap, d, src_x, src_y, TILEX, TILEY, x, y);
100 }
101
102 void DrawGraphicThruMask_MM(int x, int y, int graphic)
103 {
104 #if DEBUG
105   if (!IN_SCR_FIELD(x,y))
106   {
107     printf("DrawGraphicThruMask_MM(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
108     printf("DrawGraphicThruMask_MM(): This should never happen!\n");
109     return;
110   }
111 #endif
112
113   DrawGraphicThruMaskExt_MM(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
114   MarkTileDirty(x,y);
115 }
116
117 void DrawGraphicThruMaskExt_MM(DrawBuffer *d, int dest_x, int dest_y,
118                                int graphic)
119 {
120   int src_x, src_y;
121   Bitmap *src_bitmap;
122
123   if (graphic == GFX_EMPTY)
124     return;
125
126   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
127
128   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
129 }
130
131 void DrawMiniGraphic_MM(int x, int y, int graphic)
132 {
133   DrawMiniGraphicExt_MM(drawto, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
134   MarkTileDirty(x/2, y/2);
135 }
136
137 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
138 {
139   getSizedGraphicSource(graphic, 0, TILESIZE / 4, bitmap, x, y);
140 }
141
142 void DrawMiniGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
143 {
144   Bitmap *bitmap;
145   int src_x, src_y;
146
147   getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y);
148   BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
149 }
150
151 void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
152                         int cut_mode, int mask_mode)
153 {
154   int width = TILEX, height = TILEY;
155   int cx = 0, cy = 0;
156   int src_x, src_y, dest_x, dest_y;
157   Bitmap *src_bitmap;
158
159   if (graphic < 0)
160   {
161     DrawGraphic_MM(x, y, graphic);
162     return;
163   }
164
165   if (dx || dy)                 /* Verschiebung der Grafik? */
166   {
167     if (x < BX1)                /* Element kommt von links ins Bild */
168     {
169       x = BX1;
170       width = dx;
171       cx = TILEX - dx;
172       dx = 0;
173     }
174     else if (x > BX2)           /* Element kommt von rechts ins Bild */
175     {
176       x = BX2;
177       width = -dx;
178       dx = TILEX + dx;
179     }
180     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
181     {
182       width += dx;
183       cx = -dx;
184       dx = 0;
185     }
186     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
187       width -= dx;
188     else if (dx)                /* allg. Bewegung in x-Richtung */
189       MarkTileDirty(x + SIGN(dx), y);
190
191     if (y < BY1)                /* Element kommt von oben ins Bild */
192     {
193       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
194         return;
195
196       y = BY1;
197       height = dy;
198       cy = TILEY - dy;
199       dy = 0;
200     }
201     else if (y > BY2)           /* Element kommt von unten ins Bild */
202     {
203       y = BY2;
204       height = -dy;
205       dy = TILEY + dy;
206     }
207     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
208     {
209       height += dy;
210       cy = -dy;
211       dy = 0;
212     }
213     else if (dy > 0 && cut_mode == CUT_ABOVE)
214     {
215       if (y == BY2)             /* Element unterhalb des Bildes */
216         return;
217
218       height = dy;
219       cy = TILEY - dy;
220       dy = TILEY;
221       MarkTileDirty(x, y + 1);
222     }                           /* Element verläßt unten das Bild */
223     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
224       height -= dy;
225     else if (dy)                /* allg. Bewegung in y-Richtung */
226       MarkTileDirty(x, y + SIGN(dy));
227   }
228
229   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
230
231   src_x += cx;
232   src_y += cy;
233
234   dest_x = FX + x * TILEX + dx;
235   dest_y = FY + y * TILEY + dy;
236
237 #if DEBUG
238   if (!IN_SCR_FIELD(x,y))
239   {
240     printf("DrawGraphicShifted_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
241     printf("DrawGraphicShifted_MM(): This should never happen!\n");
242     return;
243   }
244 #endif
245
246   if (mask_mode == USE_MASKING)
247   {
248     BlitBitmapMasked(src_bitmap, drawto_field,
249                      src_x, src_y, TILEX, TILEY, dest_x, dest_y);
250   }
251   else
252     BlitBitmap(src_bitmap, drawto_field,
253                src_x, src_y, width, height, dest_x, dest_y);
254
255   MarkTileDirty(x,y);
256 }
257
258 void DrawGraphicShiftedThruMask_MM(int x,int y, int dx,int dy, int graphic,
259                                 int cut_mode)
260 {
261   DrawGraphicShifted_MM(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
262 }
263
264 void DrawScreenElementExt_MM(int x, int y, int dx, int dy, int element,
265                           int cut_mode, int mask_mode)
266 {
267   int ux = LEVELX(x), uy = LEVELY(y);
268   int graphic = el2gfx(element);
269   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
270   int phase2  = phase8 / 4;
271   int dir = MovDir[ux][uy];
272
273   if (element == EL_PACMAN)
274   {
275     graphic += 4 * !phase2;
276
277     if (dir == MV_UP)
278       graphic += 1;
279     else if (dir == MV_LEFT)
280       graphic += 2;
281     else if (dir == MV_DOWN)
282       graphic += 3;
283   }
284
285   if (dx || dy)
286     DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, mask_mode);
287   else if (mask_mode == USE_MASKING)
288     DrawGraphicThruMask_MM(x, y, graphic);
289   else
290     DrawGraphic_MM(x, y, graphic);
291 }
292
293 void DrawLevelElementExt_MM(int x, int y, int dx, int dy, int element,
294                          int cut_mode, int mask_mode)
295 {
296   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
297     DrawScreenElementExt_MM(SCREENX(x), SCREENY(y), dx, dy, element,
298                          cut_mode, mask_mode);
299 }
300
301 void DrawScreenElementShifted_MM(int x, int y, int dx, int dy, int element,
302                               int cut_mode)
303 {
304   DrawScreenElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
305 }
306
307 void DrawLevelElementShifted_MM(int x, int y, int dx, int dy, int element,
308                              int cut_mode)
309 {
310   DrawLevelElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
311 }
312
313 void DrawScreenElementThruMask_MM(int x, int y, int element)
314 {
315   DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
316 }
317
318 void DrawLevelElementThruMask_MM(int x, int y, int element)
319 {
320   DrawLevelElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
321 }
322
323 void DrawLevelFieldThruMask_MM(int x, int y)
324 {
325   DrawLevelElementExt_MM(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
326 }
327
328 void DrawScreenElement_MM(int x, int y, int element)
329 {
330   DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
331 }
332
333 void DrawLevelElement_MM(int x, int y, int element)
334 {
335   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
336     DrawScreenElement_MM(SCREENX(x), SCREENY(y), element);
337 }
338
339 void DrawScreenField_MM(int x, int y)
340 {
341   int element = Feld[x][y];
342
343   if (!IN_LEV_FIELD(x, y))
344     return;
345
346   if (IS_MOVING(x, y))
347   {
348     int horiz_move = (MovDir[x][y] == MV_LEFT || MovDir[x][y] == MV_RIGHT);
349
350     DrawScreenElement_MM(x, y, EL_EMPTY);
351
352     if (horiz_move)
353       DrawScreenElementShifted_MM(x, y, MovPos[x][y], 0, element, NO_CUTTING);
354     else
355       DrawScreenElementShifted_MM(x, y, 0, MovPos[x][y], element, NO_CUTTING);
356   }
357   else if (IS_BLOCKED(x, y))
358   {
359     int oldx, oldy;
360     int sx, sy;
361     int horiz_move;
362
363     Blocked2Moving(x, y, &oldx, &oldy);
364     sx = SCREENX(oldx);
365     sy = SCREENY(oldy);
366     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
367                   MovDir[oldx][oldy] == MV_RIGHT);
368
369     DrawScreenElement_MM(x, y, EL_EMPTY);
370     element = Feld[oldx][oldy];
371
372     if (horiz_move)
373       DrawScreenElementShifted_MM(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
374     else
375       DrawScreenElementShifted_MM(sx,sy, 0,MovPos[oldx][oldy],element,NO_CUTTING);
376   }
377   else if (IS_DRAWABLE(element))
378     DrawScreenElement_MM(x, y, element);
379   else
380     DrawScreenElement_MM(x, y, EL_EMPTY);
381 }
382
383 void DrawLevelField_MM(int x, int y)
384 {
385   DrawScreenField_MM(x, y);
386 }
387
388 void DrawMiniElement_MM(int x, int y, int element)
389 {
390   int graphic;
391
392   if (!element)
393   {
394     DrawMiniGraphic_MM(x, y, GFX_EMPTY);
395     return;
396   }
397
398   graphic = el2gfx(element);
399   DrawMiniGraphic_MM(x, y, graphic);
400 }
401
402 void DrawMiniElementOrWall_MM(int sx, int sy, int scroll_x, int scroll_y)
403 {
404   int x = sx + scroll_x, y = sy + scroll_y;
405
406   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
407     DrawMiniElement_MM(sx, sy, EL_EMPTY);
408   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
409     DrawMiniElement_MM(sx, sy, Feld[x][y]);
410 }
411
412 void DrawField_MM(int x, int y)
413 {
414   int element = Feld[x][y];
415
416   DrawElement_MM(x, y, element);
417 }
418
419 void DrawLevel_MM()
420 {
421   int x,y;
422
423   ClearWindow();
424
425   for (x=0; x<lev_fieldx; x++)
426     for (y=0; y<lev_fieldy; y++)
427       DrawField_MM(x, y);
428
429   redraw_mask |= REDRAW_FIELD;
430 }
431
432 void DrawWallsExt_MM(int x, int y, int element, int draw_mask)
433 {
434   Bitmap *bitmap;
435   int graphic = el2gfx(WALL_BASE(element));
436   int gx, gy;
437   int i;
438
439   getMiniGraphicSource(graphic, &bitmap, &gx, &gy);
440
441   if (game_status != LEVELED || !editor.draw_walls_masked)
442     DrawGraphic_MM(x, y, GFX_EMPTY);
443
444   /*
445   if (IS_WALL_WOOD(element) || IS_WALL_AMOEBA(element) ||
446       IS_DF_WALL_WOOD(element))
447     gx += MINI_TILEX;
448   if (IS_WALL_ICE(element) || IS_WALL_AMOEBA(element))
449     gy += MINI_TILEY;
450   */
451
452   for(i=0; i<4; i++)
453   {
454     int dest_x = SX + x * TILEX + MINI_TILEX * (i % 2);
455     int dest_y = SY + y * TILEY + MINI_TILEY * (i / 2);
456
457     if (!((1 << i) & draw_mask))
458       continue;
459
460     if (element & (1 << i))
461       BlitBitmap(bitmap, drawto, gx, gy, MINI_TILEX, MINI_TILEY,
462                  dest_x, dest_y);
463     else if (!editor.draw_walls_masked)
464       ClearRectangle(drawto, dest_x, dest_y, MINI_TILEX, MINI_TILEY);
465   }
466
467   MarkTileDirty(x, y);
468 }
469
470 void DrawWalls_MM(int x, int y, int element)
471 {
472   DrawWallsExt_MM(x, y, element, HIT_MASK_ALL);
473 }
474
475 void DrawWallsAnimation_MM(int x, int y, int element, int phase, int bit_mask)
476 {
477   int graphic = GFX_WALL_SEVERAL;
478   int graphic_anim = graphic + (phase + 1) / 2;
479   int dx = (IS_WALL_AMOEBA(element) ? MINI_TILEX : 0);
480   int dy = MINI_TILEY;
481   int dx_anim = dx;
482   int dy_anim = ((phase + 1) % 2) * MINI_TILEY;
483   int i;
484
485   Bitmap *bitmap, *bitmap_anim;
486   int src_x, src_y;
487   int src_x_anim, src_y_anim;
488
489   getGraphicSource(graphic, 0, &bitmap, &src_x, &src_y);
490   getGraphicSource(graphic_anim, 0, &bitmap_anim, &src_x_anim, &src_y_anim);
491
492   if (phase == 0)
493   {
494     DrawWalls_MM(x, y, element);
495     return;
496   }
497
498   for(i=0; i<4; i++)
499   {
500     if (element & (1 << i))
501     {
502       int dest_x = SX + x * TILEX + MINI_TILEX * (i % 2);
503       int dest_y = SY + y * TILEY + MINI_TILEY * (i / 2);
504       int gx, gy;
505
506       if (bit_mask & (1 << i))
507       {
508         gx = src_x_anim + dx_anim;
509         gy = src_y_anim + dy_anim;
510
511         BlitBitmap(bitmap_anim, drawto, gx, gy, MINI_TILEX, MINI_TILEY,
512                    dest_x, dest_y);
513       }
514       else
515       {
516         gx = src_x + dx;
517         gy = src_y + dy;
518
519         BlitBitmap(bitmap, drawto, gx, gy, MINI_TILEX, MINI_TILEY,
520                    dest_x, dest_y);
521       }
522     }
523   }
524
525   MarkTileDirty(x, y);
526 }
527
528 void DrawElement_MM(int x, int y, int element)
529 {
530   if (element == EL_EMPTY)
531     DrawGraphic_MM(x, y, GFX_EMPTY);
532   else if (IS_WALL(element))
533     DrawWalls_MM(x, y, element);
534 #if 0
535   else if (IS_WALL_CHANGING(element) && IS_WALL_CHANGING(Feld[x][y]))
536   {
537     int wall_element = Feld[x][y] - EL_WALL_CHANGING + Store[x][y];
538
539     DrawWalls_MM(x, y, wall_element);
540   }
541 #endif
542   else if (element == EL_PACMAN)
543     DrawLevelField_MM(x, y);
544   else
545     DrawGraphic_MM(x, y, el2gfx(element));
546 }
547
548 void DrawMicroWalls_MM(int x, int y, int element)
549 {
550   Bitmap *bitmap;
551   int graphic = el2gfx(WALL_BASE(element));
552   int gx, gy;
553   int i;
554
555   getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
556
557   for (i=0; i<4; i++)
558   {
559     int xpos = MICROLEV_XPOS + x * MICRO_TILEX + MICRO_WALLX * (i % 2);
560     int ypos = MICROLEV_YPOS + y * MICRO_TILEY + MICRO_WALLY * (i / 2);
561
562     if (element & (1 << i))
563       BlitBitmap(bitmap, drawto, gx, gy, MICRO_WALLX, MICRO_WALLY, xpos, ypos);
564     else
565       ClearRectangle(drawto, xpos, ypos, MICRO_WALLX, MICRO_WALLY);
566   }
567 }
568
569 void DrawMicroElement_MM(int x, int y, int element)
570 {
571   Bitmap *bitmap;
572   int graphic = el2gfx(element);
573   int gx, gy;
574
575   if (element == EL_EMPTY)
576     return;
577
578   if (IS_WALL(element))
579   {
580     DrawMicroWalls_MM(x, y, element);
581     return;
582   }
583
584   getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
585
586   BlitBitmap(bitmap, drawto, gx, gy, MICRO_TILEX, MICRO_TILEY,
587              MICROLEV_XPOS + x * MICRO_TILEX, MICROLEV_YPOS + y * MICRO_TILEY);
588 }
589
590 void DrawMicroLevelExt_MM(int xpos, int ypos)
591 {
592   int x,y;
593
594   ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
595
596   for (x=0; x<STD_LEV_FIELDX; x++)
597     for (y=0; y<STD_LEV_FIELDY; y++)
598       DrawMicroElement_MM(x, y, Ur[x][y]);
599
600   redraw_mask |= REDRAW_FIELD;
601 }
602
603 void DrawMiniLevel_MM(int size_x, int size_y, int scroll_x, int scroll_y)
604 {
605   int x,y;
606
607   for(x=0; x<size_x; x++)
608     for(y=0; y<size_y; y++)
609       DrawMiniElementOrWall_MM(x, y, scroll_x, scroll_y);
610
611   redraw_mask |= REDRAW_FIELD;
612 }
613
614 int REQ_in_range(int x, int y)
615 {
616   if (y > DY+249 && y < DY+278)
617   {
618     if (x > DX+1 && x < DX+48)
619       return 1;
620     else if (x > DX+51 && x < DX+98)
621       return 2;
622   }
623   return 0;
624 }
625
626 Pixel ReadPixel(DrawBuffer *bitmap, int x, int y)
627 {
628   return GetPixel(bitmap, x, y);
629 }
630
631 void SetRGB(unsigned int pixel,
632             unsigned short red, unsigned short green, unsigned short blue)
633 {
634 }
635
636 int get_base_element(int element)
637 {
638   if (IS_MIRROR(element))
639     return EL_MIRROR_START;
640   else if (IS_MIRROR_FIXED(element))
641     return EL_MIRROR_FIXED_START;
642   else if (IS_POLAR(element))
643     return EL_POLAR_START;
644   else if (IS_POLAR_CROSS(element))
645     return EL_POLAR_CROSS_START;
646   else if (IS_BEAMER(element))
647     return EL_BEAMER_RED_START + BEAMER_NR(element) * 16;
648   else if (IS_FIBRE_OPTIC(element))
649     return EL_FIBRE_OPTIC_START + FIBRE_OPTIC_NR(element) * 2;
650   else if (IS_MCDUFFIN(element))
651     return EL_MCDUFFIN_START;
652   else if (IS_LASER(element))
653     return EL_LASER_START;
654   else if (IS_RECEIVER(element))
655     return EL_RECEIVER_START;
656   else if (IS_DF_MIRROR(element))
657     return EL_DF_MIRROR_START;
658   else if (IS_DF_MIRROR_AUTO(element))
659     return EL_DF_MIRROR_AUTO_START;
660   else if (IS_PACMAN(element))
661     return EL_PACMAN_START;
662   else if (IS_GRID_STEEL(element))
663     return EL_GRID_STEEL_START;
664   else if (IS_GRID_WOOD(element))
665     return EL_GRID_WOOD_START;
666   else if (IS_GRID_STEEL_FIXED(element))
667     return EL_GRID_STEEL_FIXED_START;
668   else if (IS_GRID_WOOD_FIXED(element))
669     return EL_GRID_WOOD_FIXED_START;
670   else if (IS_GRID_STEEL_AUTO(element))
671     return EL_GRID_STEEL_AUTO_START;
672   else if (IS_GRID_WOOD_AUTO(element))
673     return EL_GRID_WOOD_AUTO_START;
674   else if (IS_WALL_STEEL(element))
675     return EL_WALL_STEEL_START;
676   else if (IS_WALL_WOOD(element))
677     return EL_WALL_WOOD_START;
678   else if (IS_WALL_ICE(element))
679     return EL_WALL_ICE_START;
680   else if (IS_WALL_AMOEBA(element))
681     return EL_WALL_AMOEBA_START;
682   else if (IS_DF_WALL_STEEL(element))
683     return EL_DF_WALL_STEEL_START;
684   else if (IS_DF_WALL_WOOD(element))
685     return EL_DF_WALL_WOOD_START;
686   else if (IS_CHAR(element))
687     return EL_CHAR_START;
688   else
689     return element;
690 }
691
692 int get_element_phase(int element)
693 {
694   return element - get_base_element(element);
695 }
696
697 int get_num_elements(int element)
698 {
699   if (IS_MIRROR(element) ||
700       IS_POLAR(element) ||
701       IS_BEAMER(element) ||
702       IS_DF_MIRROR(element) ||
703       IS_DF_MIRROR_AUTO(element))
704     return 16;
705   else if (IS_GRID_STEEL_FIXED(element) ||
706            IS_GRID_WOOD_FIXED(element) ||
707            IS_GRID_STEEL_AUTO(element) ||
708            IS_GRID_WOOD_AUTO(element))
709     return 8;
710   else if (IS_MIRROR_FIXED(element) ||
711            IS_POLAR_CROSS(element) ||
712            IS_MCDUFFIN(element) ||
713            IS_LASER(element) ||
714            IS_RECEIVER(element) ||
715            IS_PACMAN(element) ||
716            IS_GRID_STEEL(element) ||
717            IS_GRID_WOOD(element))
718     return 4;
719   else
720     return 1;
721 }
722
723 int get_rotated_element(int element, int step)
724 {
725   int base_element = get_base_element(element);
726   int num_elements = get_num_elements(element);
727   int element_phase = element - base_element;
728
729   return base_element + (element_phase + step + num_elements) % num_elements;
730 }
731
732 int el2gfx(int element)
733 {
734   switch(element)
735   {
736     case EL_EMPTY:              return -1;
737     case EL_GRID_STEEL_00:      return GFX_GRID_STEEL_00;
738     case EL_GRID_STEEL_01:      return GFX_GRID_STEEL_01;
739     case EL_GRID_STEEL_02:      return GFX_GRID_STEEL_02;
740     case EL_GRID_STEEL_03:      return GFX_GRID_STEEL_03;
741     case EL_MCDUFFIN_RIGHT:     return GFX_MCDUFFIN_RIGHT;
742     case EL_MCDUFFIN_UP:        return GFX_MCDUFFIN_UP;
743     case EL_MCDUFFIN_LEFT:      return GFX_MCDUFFIN_LEFT;
744     case EL_MCDUFFIN_DOWN:      return GFX_MCDUFFIN_DOWN;
745     case EL_EXIT_CLOSED:        return GFX_EXIT_CLOSED;
746     case EL_EXIT_OPENING_1:     return GFX_EXIT_OPENING_1;
747     case EL_EXIT_OPENING_2:     return GFX_EXIT_OPENING_2;
748     case EL_EXIT_OPEN:          return GFX_EXIT_OPEN;
749     case EL_KETTLE:             return GFX_KETTLE;
750     case EL_BOMB:               return GFX_BOMB;
751     case EL_PRISM:              return GFX_PRISM;
752     case EL_BLOCK_WOOD:         return GFX_BLOCK_WOOD;
753     case EL_BALL_GRAY:          return GFX_BALL_GRAY;
754     case EL_FUSE_ON:            return GFX_FUSE_ON;
755     case EL_PACMAN_RIGHT:       return GFX_PACMAN_RIGHT;
756     case EL_PACMAN_UP:          return GFX_PACMAN_UP;
757     case EL_PACMAN_LEFT:        return GFX_PACMAN_LEFT;
758     case EL_PACMAN_DOWN:        return GFX_PACMAN_DOWN;
759     case EL_POLAR_CROSS_00:     return GFX_POLAR_CROSS_00;
760     case EL_POLAR_CROSS_01:     return GFX_POLAR_CROSS_01;
761     case EL_POLAR_CROSS_02:     return GFX_POLAR_CROSS_02;
762     case EL_POLAR_CROSS_03:     return GFX_POLAR_CROSS_03;
763     case EL_MIRROR_FIXED_00:    return GFX_MIRROR_FIXED_00;
764     case EL_MIRROR_FIXED_01:    return GFX_MIRROR_FIXED_01;
765     case EL_MIRROR_FIXED_02:    return GFX_MIRROR_FIXED_02;
766     case EL_MIRROR_FIXED_03:    return GFX_MIRROR_FIXED_03;
767     case EL_GATE_STONE:         return GFX_GATE_STONE;
768     case EL_KEY:                return GFX_KEY;
769     case EL_LIGHTBULB_ON:       return GFX_LIGHTBULB_ON;
770     case EL_LIGHTBULB_OFF:      return GFX_LIGHTBULB_OFF;
771     case EL_LIGHTBALL:          return GFX_BALL_RED + RND(3);;
772     case EL_BLOCK_STONE:        return GFX_BLOCK_STONE;
773     case EL_GATE_WOOD:          return GFX_GATE_WOOD;
774     case EL_FUEL_FULL:          return GFX_FUEL_FULL;
775     case EL_GRID_WOOD_00:       return GFX_GRID_WOOD_00;
776     case EL_GRID_WOOD_01:       return GFX_GRID_WOOD_01;
777     case EL_GRID_WOOD_02:       return GFX_GRID_WOOD_02;
778     case EL_GRID_WOOD_03:       return GFX_GRID_WOOD_03;
779     case EL_FUEL_EMPTY:         return GFX_FUEL_EMPTY;
780     case EL_FUSE_OFF:           return GFX_FUSE_OFF;
781     case EL_PACMAN:             return GFX_PACMAN;
782     case EL_REFRACTOR:          return GFX_REFRACTOR;
783     case EL_CELL:               return GFX_CELL;
784     case EL_MINE:               return GFX_MINE;
785
786     /* pseudo-graphics; will be mapped to other graphics */
787     case EL_WALL_STEEL:         return GFX_WALL_STEEL;
788     case EL_WALL_WOOD:          return GFX_WALL_WOOD;
789     case EL_WALL_ICE:           return GFX_WALL_ICE;
790     case EL_WALL_AMOEBA:        return GFX_WALL_AMOEBA;
791     case EL_DF_WALL_STEEL:      return GFX_DF_WALL_STEEL;
792     case EL_DF_WALL_WOOD:       return GFX_DF_WALL_WOOD;
793
794     default:
795     {
796       boolean ed = (game_status == LEVELED);
797       int base_element = get_base_element(element);
798       int element_phase = element - base_element;
799       int base_graphic;
800
801       if (IS_BEAMER(element))
802         element_phase = element - EL_BEAMER_RED_START;
803       else if (IS_FIBRE_OPTIC(element))
804         element_phase = element - EL_FIBRE_OPTIC_START;
805
806       if (IS_MIRROR(element))
807         base_graphic = GFX_MIRROR_START;
808       else if (IS_BEAMER_OLD(element))
809         base_graphic = GFX_BEAMER_START;
810       else if (IS_POLAR(element))
811         base_graphic = GFX_POLAR_START;
812       else if (IS_CHAR(element))
813         base_graphic = GFX_CHAR_START;
814       else if (IS_GRID_WOOD_FIXED(element))
815         base_graphic = GFX_GRID_WOOD_FIXED_00;
816       else if (IS_GRID_STEEL_FIXED(element))
817         base_graphic = GFX_GRID_STEEL_FIXED_00;
818       else if (IS_DF_MIRROR(element))
819         base_graphic = GFX_DF_MIRROR_00;
820       else if (IS_LASER(element))
821         base_graphic = GFX_LASER_RIGHT;
822       else if (IS_RECEIVER(element))
823         base_graphic = GFX_RECEIVER_RIGHT;
824       else if (IS_DF_MIRROR(element))
825         base_graphic = GFX_DF_MIRROR_00;
826       else if (IS_FIBRE_OPTIC(element))
827         base_graphic = (ed ? GFX_FIBRE_OPTIC_ED_00 : GFX_FIBRE_OPTIC_00);
828       else if (IS_GRID_WOOD_AUTO(element))
829         base_graphic = (ed ? GFX_GRID_WOOD_AUTO_00 : GFX_GRID_WOOD_FIXED_00);
830       else if (IS_GRID_STEEL_AUTO(element))
831         base_graphic = (ed ? GFX_GRID_STEEL_AUTO_00 : GFX_GRID_STEEL_FIXED_00);
832       else if (IS_DF_MIRROR_AUTO(element))
833         base_graphic = (ed ? GFX_DF_MIRROR_AUTO_00 : GFX_DF_MIRROR_00);
834       else if (IS_BEAMER(element))
835         base_graphic = GFX_BEAMER_RED_START;
836       else
837         return GFX_EMPTY;
838
839       return base_graphic + element_phase;
840     }
841   }
842 }
843
844 void RedrawPlayfield_MM()
845 {
846   DrawLevel_MM();
847 }
848
849 void BlitScreenToBitmap_MM(Bitmap *target_bitmap)
850 {
851   BlitBitmap(drawto_field, target_bitmap, 0, 0, SXSIZE, SYSIZE, SX, SY);
852 }