replaced function to draw graphic animation (MM engine)
[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 void ClearWindow()
21 {
22   ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
23
24   SetDrawtoField(DRAW_BACKBUFFER);
25
26   redraw_mask |= REDRAW_FIELD;
27 }
28
29 void DrawGraphicAnimation_MM(int x, int y, int graphic, int frame)
30 {
31   Bitmap *bitmap;
32   int src_x, src_y;
33
34   getGraphicSource(graphic, frame, &bitmap, &src_x, &src_y);
35
36   BlitBitmap(bitmap, drawto_field, src_x, src_y, TILEX, TILEY,
37              FX + x * TILEX, FY + y * TILEY);
38 }
39
40 void DrawGraphic_MM(int x, int y, int graphic)
41 {
42 #if DEBUG
43   if (!IN_SCR_FIELD(x,y))
44   {
45     printf("DrawGraphic_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
46     printf("DrawGraphic_MM(): This should never happen!\n");
47     return;
48   }
49 #endif
50
51   DrawGraphicExt_MM(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
52   MarkTileDirty(x, y);
53 }
54
55 void DrawGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
56 {
57   Bitmap *bitmap;
58   int src_x, src_y;
59
60   getGraphicSource(graphic, 0, &bitmap, &src_x, &src_y);
61   BlitBitmap(bitmap, d, src_x, src_y, TILEX, TILEY, x, y);
62 }
63
64 void DrawGraphicThruMask_MM(int x, int y, int graphic)
65 {
66 #if DEBUG
67   if (!IN_SCR_FIELD(x,y))
68   {
69     printf("DrawGraphicThruMask_MM(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
70     printf("DrawGraphicThruMask_MM(): This should never happen!\n");
71     return;
72   }
73 #endif
74
75   DrawGraphicThruMaskExt_MM(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
76   MarkTileDirty(x,y);
77 }
78
79 void DrawGraphicThruMaskExt_MM(DrawBuffer *d, int dest_x, int dest_y,
80                                int graphic)
81 {
82   int src_x, src_y;
83   Bitmap *src_bitmap;
84
85   if (graphic == IMG_EMPTY)
86     return;
87
88   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
89
90   BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
91 }
92
93 void DrawMiniGraphic_MM(int x, int y, int graphic)
94 {
95   DrawMiniGraphicExt_MM(drawto, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
96   MarkTileDirty(x/2, y/2);
97 }
98
99 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
100 {
101   getSizedGraphicSource(graphic, 0, TILESIZE / 4, bitmap, x, y);
102 }
103
104 void DrawMiniGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
105 {
106   Bitmap *bitmap;
107   int src_x, src_y;
108
109   getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y);
110   BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
111 }
112
113 void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
114                         int cut_mode, int mask_mode)
115 {
116   int width = TILEX, height = TILEY;
117   int cx = 0, cy = 0;
118   int src_x, src_y, dest_x, dest_y;
119   Bitmap *src_bitmap;
120
121   if (graphic < 0)
122   {
123     DrawGraphic_MM(x, y, graphic);
124     return;
125   }
126
127   if (dx || dy)                 /* Verschiebung der Grafik? */
128   {
129     if (x < BX1)                /* Element kommt von links ins Bild */
130     {
131       x = BX1;
132       width = dx;
133       cx = TILEX - dx;
134       dx = 0;
135     }
136     else if (x > BX2)           /* Element kommt von rechts ins Bild */
137     {
138       x = BX2;
139       width = -dx;
140       dx = TILEX + dx;
141     }
142     else if (x==BX1 && dx < 0)  /* Element verläßt links das Bild */
143     {
144       width += dx;
145       cx = -dx;
146       dx = 0;
147     }
148     else if (x==BX2 && dx > 0)  /* Element verläßt rechts das Bild */
149       width -= dx;
150     else if (dx)                /* allg. Bewegung in x-Richtung */
151       MarkTileDirty(x + SIGN(dx), y);
152
153     if (y < BY1)                /* Element kommt von oben ins Bild */
154     {
155       if (cut_mode==CUT_BELOW)  /* Element oberhalb des Bildes */
156         return;
157
158       y = BY1;
159       height = dy;
160       cy = TILEY - dy;
161       dy = 0;
162     }
163     else if (y > BY2)           /* Element kommt von unten ins Bild */
164     {
165       y = BY2;
166       height = -dy;
167       dy = TILEY + dy;
168     }
169     else if (y==BY1 && dy < 0)  /* Element verläßt oben das Bild */
170     {
171       height += dy;
172       cy = -dy;
173       dy = 0;
174     }
175     else if (dy > 0 && cut_mode == CUT_ABOVE)
176     {
177       if (y == BY2)             /* Element unterhalb des Bildes */
178         return;
179
180       height = dy;
181       cy = TILEY - dy;
182       dy = TILEY;
183       MarkTileDirty(x, y + 1);
184     }                           /* Element verläßt unten das Bild */
185     else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
186       height -= dy;
187     else if (dy)                /* allg. Bewegung in y-Richtung */
188       MarkTileDirty(x, y + SIGN(dy));
189   }
190
191   getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
192
193   src_x += cx;
194   src_y += cy;
195
196   dest_x = FX + x * TILEX + dx;
197   dest_y = FY + y * TILEY + dy;
198
199 #if DEBUG
200   if (!IN_SCR_FIELD(x,y))
201   {
202     printf("DrawGraphicShifted_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
203     printf("DrawGraphicShifted_MM(): This should never happen!\n");
204     return;
205   }
206 #endif
207
208   if (mask_mode == USE_MASKING)
209   {
210     BlitBitmapMasked(src_bitmap, drawto_field,
211                      src_x, src_y, TILEX, TILEY, dest_x, dest_y);
212   }
213   else
214     BlitBitmap(src_bitmap, drawto_field,
215                src_x, src_y, width, height, dest_x, dest_y);
216
217   MarkTileDirty(x,y);
218 }
219
220 void DrawGraphicShiftedThruMask_MM(int x,int y, int dx,int dy, int graphic,
221                                 int cut_mode)
222 {
223   DrawGraphicShifted_MM(x,y, dx,dy, graphic, cut_mode, USE_MASKING);
224 }
225
226 void DrawScreenElementExt_MM(int x, int y, int dx, int dy, int element,
227                           int cut_mode, int mask_mode)
228 {
229   int ux = LEVELX(x), uy = LEVELY(y);
230   int graphic = el2gfx(element);
231   int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
232   int phase2  = phase8 / 4;
233   int dir = MovDir[ux][uy];
234
235   if (element == EL_PACMAN)
236   {
237     graphic = (phase2 ? IMG_MM_PACMAN_RIGHT : IMG_MM_PACMAN_EATING_RIGHT);
238
239     if (dir == MV_UP)
240       graphic += 1;
241     else if (dir == MV_LEFT)
242       graphic += 2;
243     else if (dir == MV_DOWN)
244       graphic += 3;
245   }
246
247   if (dx || dy)
248     DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, mask_mode);
249   else if (mask_mode == USE_MASKING)
250     DrawGraphicThruMask_MM(x, y, graphic);
251   else
252     DrawGraphic_MM(x, y, graphic);
253 }
254
255 void DrawLevelElementExt_MM(int x, int y, int dx, int dy, int element,
256                          int cut_mode, int mask_mode)
257 {
258   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
259     DrawScreenElementExt_MM(SCREENX(x), SCREENY(y), dx, dy, element,
260                          cut_mode, mask_mode);
261 }
262
263 void DrawScreenElementShifted_MM(int x, int y, int dx, int dy, int element,
264                               int cut_mode)
265 {
266   DrawScreenElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
267 }
268
269 void DrawLevelElementShifted_MM(int x, int y, int dx, int dy, int element,
270                              int cut_mode)
271 {
272   DrawLevelElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
273 }
274
275 void DrawScreenElementThruMask_MM(int x, int y, int element)
276 {
277   DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
278 }
279
280 void DrawLevelElementThruMask_MM(int x, int y, int element)
281 {
282   DrawLevelElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
283 }
284
285 void DrawLevelFieldThruMask_MM(int x, int y)
286 {
287   DrawLevelElementExt_MM(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
288 }
289
290 void DrawScreenElement_MM(int x, int y, int element)
291 {
292   DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
293 }
294
295 void DrawLevelElement_MM(int x, int y, int element)
296 {
297   if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
298     DrawScreenElement_MM(SCREENX(x), SCREENY(y), element);
299 }
300
301 void DrawScreenField_MM(int x, int y)
302 {
303   int element = Feld[x][y];
304
305   if (!IN_LEV_FIELD(x, y))
306     return;
307
308   if (IS_MOVING(x, y))
309   {
310     int horiz_move = (MovDir[x][y] == MV_LEFT || MovDir[x][y] == MV_RIGHT);
311
312     DrawScreenElement_MM(x, y, EL_EMPTY);
313
314     if (horiz_move)
315       DrawScreenElementShifted_MM(x, y, MovPos[x][y], 0, element, NO_CUTTING);
316     else
317       DrawScreenElementShifted_MM(x, y, 0, MovPos[x][y], element, NO_CUTTING);
318   }
319   else if (IS_BLOCKED(x, y))
320   {
321     int oldx, oldy;
322     int sx, sy;
323     int horiz_move;
324
325     Blocked2Moving(x, y, &oldx, &oldy);
326     sx = SCREENX(oldx);
327     sy = SCREENY(oldy);
328     horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
329                   MovDir[oldx][oldy] == MV_RIGHT);
330
331     DrawScreenElement_MM(x, y, EL_EMPTY);
332     element = Feld[oldx][oldy];
333
334     if (horiz_move)
335       DrawScreenElementShifted_MM(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
336     else
337       DrawScreenElementShifted_MM(sx,sy, 0,MovPos[oldx][oldy],element,NO_CUTTING);
338   }
339   else if (IS_DRAWABLE(element))
340     DrawScreenElement_MM(x, y, element);
341   else
342     DrawScreenElement_MM(x, y, EL_EMPTY);
343 }
344
345 void DrawLevelField_MM(int x, int y)
346 {
347   DrawScreenField_MM(x, y);
348 }
349
350 void DrawMiniElement_MM(int x, int y, int element)
351 {
352   int graphic;
353
354   if (!element)
355   {
356     DrawMiniGraphic_MM(x, y, IMG_EMPTY);
357     return;
358   }
359
360   graphic = el2gfx(element);
361   DrawMiniGraphic_MM(x, y, graphic);
362 }
363
364 void DrawMiniElementOrWall_MM(int sx, int sy, int scroll_x, int scroll_y)
365 {
366   int x = sx + scroll_x, y = sy + scroll_y;
367
368   if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
369     DrawMiniElement_MM(sx, sy, EL_EMPTY);
370   else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
371     DrawMiniElement_MM(sx, sy, Feld[x][y]);
372 }
373
374 void DrawField_MM(int x, int y)
375 {
376   int element = Feld[x][y];
377
378   DrawElement_MM(x, y, element);
379 }
380
381 void DrawLevel_MM()
382 {
383   int x,y;
384
385   ClearWindow();
386
387   for (x=0; x<lev_fieldx; x++)
388     for (y=0; y<lev_fieldy; y++)
389       DrawField_MM(x, y);
390
391   redraw_mask |= REDRAW_FIELD;
392 }
393
394 void DrawWallsExt_MM(int x, int y, int element, int draw_mask)
395 {
396   Bitmap *bitmap;
397   int graphic = el2gfx(WALL_BASE(element));
398   int gx, gy;
399   int i;
400
401   getMiniGraphicSource(graphic, &bitmap, &gx, &gy);
402
403   if (game_status != LEVELED || !editor.draw_walls_masked)
404     DrawGraphic_MM(x, y, IMG_EMPTY);
405
406   /*
407   if (IS_WALL_WOOD(element) || IS_WALL_AMOEBA(element) ||
408       IS_DF_WALL_WOOD(element))
409     gx += MINI_TILEX;
410   if (IS_WALL_ICE(element) || IS_WALL_AMOEBA(element))
411     gy += MINI_TILEY;
412   */
413
414   for(i=0; i<4; i++)
415   {
416     int dest_x = SX + x * TILEX + MINI_TILEX * (i % 2);
417     int dest_y = SY + y * TILEY + MINI_TILEY * (i / 2);
418
419     if (!((1 << i) & draw_mask))
420       continue;
421
422     if (element & (1 << i))
423       BlitBitmap(bitmap, drawto, gx, gy, MINI_TILEX, MINI_TILEY,
424                  dest_x, dest_y);
425     else if (!editor.draw_walls_masked)
426       ClearRectangle(drawto, dest_x, dest_y, MINI_TILEX, MINI_TILEY);
427   }
428
429   MarkTileDirty(x, y);
430 }
431
432 void DrawWalls_MM(int x, int y, int element)
433 {
434   DrawWallsExt_MM(x, y, element, HIT_MASK_ALL);
435 }
436
437 void DrawWallsAnimation_MM(int x, int y, int element, int phase, int bit_mask)
438 {
439   int i;
440
441   if (phase == 0)
442   {
443     DrawWalls_MM(x, y, element);
444
445     return;
446   }
447
448   for (i = 0; i < 4; i++)
449   {
450     if (element & (1 << i))
451     {
452       int graphic;
453       int frame;
454       Bitmap *bitmap;
455       int src_x, src_y;
456       int dst_x = SX + x * TILEX + (i % 2) * MINI_TILEX;
457       int dst_y = SY + y * TILEY + (i / 2) * MINI_TILEY;
458
459       if (bit_mask & (1 << i))
460       {
461         graphic = (IS_WALL_AMOEBA(element) ?
462                    IMG_MM_AMOEBA_WALL_GROWING :
463                    IMG_MM_ICE_WALL_SHRINKING);
464         frame = phase;
465       }
466       else
467       {
468         graphic = (IS_WALL_AMOEBA(element) ?
469                    IMG_MM_AMOEBA_WALL :
470                    IMG_MM_ICE_WALL);
471         frame = 0;
472       }
473
474       getSizedGraphicSource(graphic, frame, MINI_TILESIZE, &bitmap,
475                             &src_x, &src_y);
476
477       BlitBitmap(bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
478                  dst_x, dst_y);
479     }
480   }
481
482   MarkTileDirty(x, y);
483 }
484
485 void DrawElement_MM(int x, int y, int element)
486 {
487   if (element == EL_EMPTY)
488     DrawGraphic_MM(x, y, IMG_EMPTY);
489   else if (IS_WALL(element))
490     DrawWalls_MM(x, y, element);
491 #if 0
492   else if (IS_WALL_CHANGING(element) && IS_WALL_CHANGING(Feld[x][y]))
493   {
494     int wall_element = Feld[x][y] - EL_WALL_CHANGING + Store[x][y];
495
496     DrawWalls_MM(x, y, wall_element);
497   }
498 #endif
499   else if (element == EL_PACMAN)
500     DrawLevelField_MM(x, y);
501   else
502     DrawGraphic_MM(x, y, el2gfx(element));
503 }
504
505 void DrawMicroWalls_MM(int x, int y, int element)
506 {
507   Bitmap *bitmap;
508   int graphic = el2gfx(WALL_BASE(element));
509   int gx, gy;
510   int i;
511
512   getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
513
514   for (i=0; i<4; i++)
515   {
516     int xpos = MICROLEV_XPOS + x * MICRO_TILEX + MICRO_WALLX * (i % 2);
517     int ypos = MICROLEV_YPOS + y * MICRO_TILEY + MICRO_WALLY * (i / 2);
518
519     if (element & (1 << i))
520       BlitBitmap(bitmap, drawto, gx, gy, MICRO_WALLX, MICRO_WALLY, xpos, ypos);
521     else
522       ClearRectangle(drawto, xpos, ypos, MICRO_WALLX, MICRO_WALLY);
523   }
524 }
525
526 void DrawMicroElement_MM(int x, int y, int element)
527 {
528   Bitmap *bitmap;
529   int graphic = el2gfx(element);
530   int gx, gy;
531
532   if (element == EL_EMPTY)
533     return;
534
535   if (IS_WALL(element))
536   {
537     DrawMicroWalls_MM(x, y, element);
538     return;
539   }
540
541   getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
542
543   BlitBitmap(bitmap, drawto, gx, gy, MICRO_TILEX, MICRO_TILEY,
544              MICROLEV_XPOS + x * MICRO_TILEX, MICROLEV_YPOS + y * MICRO_TILEY);
545 }
546
547 void DrawMicroLevelExt_MM(int xpos, int ypos)
548 {
549   int x,y;
550
551   ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
552
553   for (x=0; x<STD_LEV_FIELDX; x++)
554     for (y=0; y<STD_LEV_FIELDY; y++)
555       DrawMicroElement_MM(x, y, Ur[x][y]);
556
557   redraw_mask |= REDRAW_FIELD;
558 }
559
560 void DrawMiniLevel_MM(int size_x, int size_y, int scroll_x, int scroll_y)
561 {
562   int x,y;
563
564   for(x=0; x<size_x; x++)
565     for(y=0; y<size_y; y++)
566       DrawMiniElementOrWall_MM(x, y, scroll_x, scroll_y);
567
568   redraw_mask |= REDRAW_FIELD;
569 }
570
571 int REQ_in_range(int x, int y)
572 {
573   if (y > DY+249 && y < DY+278)
574   {
575     if (x > DX+1 && x < DX+48)
576       return 1;
577     else if (x > DX+51 && x < DX+98)
578       return 2;
579   }
580   return 0;
581 }
582
583 Pixel ReadPixel(DrawBuffer *bitmap, int x, int y)
584 {
585   return GetPixel(bitmap, x, y);
586 }
587
588 void SetRGB(unsigned int pixel,
589             unsigned short red, unsigned short green, unsigned short blue)
590 {
591 }
592
593 int get_base_element(int element)
594 {
595   if (IS_MIRROR(element))
596     return EL_MIRROR_START;
597   else if (IS_MIRROR_FIXED(element))
598     return EL_MIRROR_FIXED_START;
599   else if (IS_POLAR(element))
600     return EL_POLAR_START;
601   else if (IS_POLAR_CROSS(element))
602     return EL_POLAR_CROSS_START;
603   else if (IS_BEAMER(element))
604     return EL_BEAMER_RED_START + BEAMER_NR(element) * 16;
605   else if (IS_FIBRE_OPTIC(element))
606     return EL_FIBRE_OPTIC_START + FIBRE_OPTIC_NR(element) * 2;
607   else if (IS_MCDUFFIN(element))
608     return EL_MCDUFFIN_START;
609   else if (IS_LASER(element))
610     return EL_LASER_START;
611   else if (IS_RECEIVER(element))
612     return EL_RECEIVER_START;
613   else if (IS_DF_MIRROR(element))
614     return EL_DF_MIRROR_START;
615   else if (IS_DF_MIRROR_AUTO(element))
616     return EL_DF_MIRROR_AUTO_START;
617   else if (IS_PACMAN(element))
618     return EL_PACMAN_START;
619   else if (IS_GRID_STEEL(element))
620     return EL_GRID_STEEL_START;
621   else if (IS_GRID_WOOD(element))
622     return EL_GRID_WOOD_START;
623   else if (IS_GRID_STEEL_FIXED(element))
624     return EL_GRID_STEEL_FIXED_START;
625   else if (IS_GRID_WOOD_FIXED(element))
626     return EL_GRID_WOOD_FIXED_START;
627   else if (IS_GRID_STEEL_AUTO(element))
628     return EL_GRID_STEEL_AUTO_START;
629   else if (IS_GRID_WOOD_AUTO(element))
630     return EL_GRID_WOOD_AUTO_START;
631   else if (IS_WALL_STEEL(element))
632     return EL_WALL_STEEL_START;
633   else if (IS_WALL_WOOD(element))
634     return EL_WALL_WOOD_START;
635   else if (IS_WALL_ICE(element))
636     return EL_WALL_ICE_START;
637   else if (IS_WALL_AMOEBA(element))
638     return EL_WALL_AMOEBA_START;
639   else if (IS_DF_WALL_STEEL(element))
640     return EL_DF_WALL_STEEL_START;
641   else if (IS_DF_WALL_WOOD(element))
642     return EL_DF_WALL_WOOD_START;
643   else if (IS_CHAR(element))
644     return EL_CHAR_START;
645   else
646     return element;
647 }
648
649 int get_element_phase(int element)
650 {
651   return element - get_base_element(element);
652 }
653
654 int get_num_elements(int element)
655 {
656   if (IS_MIRROR(element) ||
657       IS_POLAR(element) ||
658       IS_BEAMER(element) ||
659       IS_DF_MIRROR(element) ||
660       IS_DF_MIRROR_AUTO(element))
661     return 16;
662   else if (IS_GRID_STEEL_FIXED(element) ||
663            IS_GRID_WOOD_FIXED(element) ||
664            IS_GRID_STEEL_AUTO(element) ||
665            IS_GRID_WOOD_AUTO(element))
666     return 8;
667   else if (IS_MIRROR_FIXED(element) ||
668            IS_POLAR_CROSS(element) ||
669            IS_MCDUFFIN(element) ||
670            IS_LASER(element) ||
671            IS_RECEIVER(element) ||
672            IS_PACMAN(element) ||
673            IS_GRID_STEEL(element) ||
674            IS_GRID_WOOD(element))
675     return 4;
676   else
677     return 1;
678 }
679
680 int get_rotated_element(int element, int step)
681 {
682   int base_element = get_base_element(element);
683   int num_elements = get_num_elements(element);
684   int element_phase = element - base_element;
685
686   return base_element + (element_phase + step + num_elements) % num_elements;
687 }
688
689 static int map_element(int element)
690 {
691   switch (element)
692   {
693     case EL_WALL_STEEL:         return EL_STEEL_WALL;
694     case EL_WALL_WOOD:          return EL_WOODEN_WALL;
695     case EL_WALL_ICE:           return EL_ICE_WALL;
696     case EL_WALL_AMOEBA:        return EL_AMOEBA_WALL;
697     case EL_DF_WALL_STEEL:      return EL_DF_STEEL_WALL;
698     case EL_DF_WALL_WOOD:       return EL_DF_WOODEN_WALL;
699
700     default:                    return element;
701   }
702 }
703
704 int el2gfx(int element)
705 {
706   element = map_element(element);
707
708   switch (element)
709   {
710     case EL_LIGHTBALL:
711       return IMG_MM_LIGHTBALL_RED + RND(3);
712
713     default:
714       return el2img_mm(element);
715   }
716 }
717
718 void RedrawPlayfield_MM()
719 {
720   DrawLevel_MM();
721 }
722
723 void BlitScreenToBitmap_MM(Bitmap *target_bitmap)
724 {
725   BlitBitmap(drawto_field, target_bitmap,
726              REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);
727 }