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