1 /***********************************************************
2 * Mirror Magic -- McDuffin's Revenge *
3 *----------------------------------------------------------*
4 * (c) 1994-2001 Artsoft Entertainment *
6 * Detmolder Strasse 189 *
9 * e-mail: info@artsoft.org *
10 *----------------------------------------------------------*
12 ***********************************************************/
20 void SetDrawtoField_MM(int mode)
22 int full_xsize = lev_fieldx * TILESIZE_VAR;
23 int full_ysize = lev_fieldy * TILESIZE_VAR;
25 // distance (delta) from screen border (SX/SY) to centered level playfield
26 dSX = (full_xsize < SXSIZE ? (SXSIZE - full_xsize) / 2 : 0);
27 dSY = (full_ysize < SYSIZE ? (SYSIZE - full_ysize) / 2 : 0);
29 // for convenience, absolute screen position to centered level playfield
32 cSX2 = SX + dSX + 2; // including playfield border
33 cSY2 = SY + dSY + 2; // including playfield border
35 if (mode == DRAW_TO_BACKBUFFER)
41 SetTileCursorSXSY(cSX, cSY);
44 void ClearWindow(void)
46 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
48 SetDrawtoField(DRAW_TO_BACKBUFFER);
49 SetDrawtoField_MM(DRAW_TO_BACKBUFFER);
51 redraw_mask |= REDRAW_FIELD;
54 void DrawGraphicAnimation_MM(int x, int y, int graphic, int frame)
59 getGraphicSource(graphic, frame, &bitmap, &src_x, &src_y);
61 BlitBitmap(bitmap, drawto_field, src_x, src_y, TILEX, TILEY,
62 cFX + x * TILEX, cFY + y * TILEY);
65 void DrawGraphic_MM(int x, int y, int graphic)
68 if (!IN_SCR_FIELD(x,y))
70 printf("DrawGraphic_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
71 printf("DrawGraphic_MM(): This should never happen!\n");
76 DrawGraphicExt_MM(drawto_field, cFX + x * TILEX, cFY + y * TILEY, graphic);
81 void DrawGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
86 getGraphicSource(graphic, 0, &bitmap, &src_x, &src_y);
88 BlitBitmap(bitmap, d, src_x, src_y, TILEX, TILEY, x, y);
91 void DrawGraphicThruMask_MM(int x, int y, int graphic)
94 if (!IN_SCR_FIELD(x,y))
96 printf("DrawGraphicThruMask_MM(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
97 printf("DrawGraphicThruMask_MM(): This should never happen!\n");
102 DrawGraphicThruMaskExt_MM(drawto_field, cFX + x * TILEX, cFY + y * TILEY,
108 void DrawGraphicThruMaskExt_MM(DrawBuffer *d, int dest_x, int dest_y,
114 if (graphic == IMG_EMPTY)
117 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
119 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
122 void DrawMiniGraphic_MM(int x, int y, int graphic)
124 DrawMiniGraphicExt_MM(drawto, cSX + x * MINI_TILEX, cSY + y * MINI_TILEY,
127 MarkTileDirty(x / 2, y / 2);
131 static void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
133 getSizedGraphicSource(graphic, 0, TILESIZE / 4, bitmap, x, y);
137 void DrawMiniGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
142 getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y);
144 BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
147 void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
148 int cut_mode, int mask_mode)
150 int width = TILEX, height = TILEY;
152 int src_x, src_y, dest_x, dest_y;
157 DrawGraphic_MM(x, y, graphic);
162 if (dx || dy) /* Verschiebung der Grafik? */
164 if (x < BX1) /* Element kommt von links ins Bild */
171 else if (x > BX2) /* Element kommt von rechts ins Bild */
177 else if (x==BX1 && dx < 0) /* Element verläßt links das Bild */
183 else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */
185 else if (dx) /* allg. Bewegung in x-Richtung */
186 MarkTileDirty(x + SIGN(dx), y);
188 if (y < BY1) /* Element kommt von oben ins Bild */
190 if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */
198 else if (y > BY2) /* Element kommt von unten ins Bild */
204 else if (y==BY1 && dy < 0) /* Element verläßt oben das Bild */
210 else if (dy > 0 && cut_mode == CUT_ABOVE)
212 if (y == BY2) /* Element unterhalb des Bildes */
218 MarkTileDirty(x, y + 1);
219 } /* Element verläßt unten das Bild */
220 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
224 else if (dy) /* allg. Bewegung in y-Richtung */
226 MarkTileDirty(x, y + SIGN(dy));
230 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
235 dest_x = cFX + x * TILEX + dx;
236 dest_y = cFY + y * TILEY + dy;
239 if (!IN_SCR_FIELD(x,y))
241 printf("DrawGraphicShifted_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
242 printf("DrawGraphicShifted_MM(): This should never happen!\n");
247 if (mask_mode == USE_MASKING)
248 BlitBitmapMasked(src_bitmap, drawto_field,
249 src_x, src_y, TILEX, TILEY, dest_x, dest_y);
251 BlitBitmap(src_bitmap, drawto_field,
252 src_x, src_y, width, height, dest_x, dest_y);
257 void DrawGraphicShiftedThruMask_MM(int x,int y, int dx,int dy, int graphic,
260 DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, USE_MASKING);
263 void DrawScreenElementExt_MM(int x, int y, int dx, int dy, int element,
264 int cut_mode, int mask_mode)
266 int ux = LEVELX(x), uy = LEVELY(y);
267 int graphic = el2gfx(element);
268 int phase8 = ABS(MovPos[ux][uy]) / (TILEX / 8);
269 int phase2 = phase8 / 4;
270 int dir = MovDir[ux][uy];
272 if (element == EL_PACMAN)
274 graphic = (phase2 ? IMG_MM_PACMAN_RIGHT : IMG_MM_PACMAN_EATING_RIGHT);
278 else if (dir == MV_LEFT)
280 else if (dir == MV_DOWN)
285 DrawGraphicShifted_MM(x, y, dx, dy, graphic, cut_mode, mask_mode);
286 else if (mask_mode == USE_MASKING)
287 DrawGraphicThruMask_MM(x, y, graphic);
289 DrawGraphic_MM(x, y, graphic);
292 void DrawLevelElementExt_MM(int x, int y, int dx, int dy, int element,
293 int cut_mode, int mask_mode)
295 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
296 DrawScreenElementExt_MM(SCREENX(x), SCREENY(y), dx, dy, element,
297 cut_mode, mask_mode);
300 void DrawScreenElementShifted_MM(int x, int y, int dx, int dy, int element,
303 DrawScreenElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
306 void DrawLevelElementShifted_MM(int x, int y, int dx, int dy, int element,
309 DrawLevelElementExt_MM(x, y, dx, dy, element, cut_mode, NO_MASKING);
312 void DrawScreenElementThruMask_MM(int x, int y, int element)
314 DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
317 void DrawLevelElementThruMask_MM(int x, int y, int element)
319 DrawLevelElementExt_MM(x, y, 0, 0, element, NO_CUTTING, USE_MASKING);
322 void DrawLevelFieldThruMask_MM(int x, int y)
324 DrawLevelElementExt_MM(x, y, 0, 0, Feld[x][y], NO_CUTTING, USE_MASKING);
327 void DrawScreenElement_MM(int x, int y, int element)
329 DrawScreenElementExt_MM(x, y, 0, 0, element, NO_CUTTING, NO_MASKING);
332 void DrawLevelElement_MM(int x, int y, int element)
334 if (IN_LEV_FIELD(x, y) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
335 DrawScreenElement_MM(SCREENX(x), SCREENY(y), element);
338 void DrawScreenField_MM(int x, int y)
340 int element = Feld[x][y];
342 if (!IN_LEV_FIELD(x, y))
347 int horiz_move = (MovDir[x][y] == MV_LEFT || MovDir[x][y] == MV_RIGHT);
349 DrawScreenElement_MM(x, y, EL_EMPTY);
352 DrawScreenElementShifted_MM(x, y, MovPos[x][y], 0, element, NO_CUTTING);
354 DrawScreenElementShifted_MM(x, y, 0, MovPos[x][y], element, NO_CUTTING);
356 else if (IS_BLOCKED(x, y))
362 Blocked2Moving(x, y, &oldx, &oldy);
366 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
367 MovDir[oldx][oldy] == MV_RIGHT);
369 DrawScreenElement_MM(x, y, EL_EMPTY);
371 element = Feld[oldx][oldy];
374 DrawScreenElementShifted_MM(sx, sy, MovPos[oldx][oldy], 0, element,
377 DrawScreenElementShifted_MM(sx, sy, 0, MovPos[oldx][oldy], element,
380 else if (IS_DRAWABLE(element))
382 DrawScreenElement_MM(x, y, element);
386 DrawScreenElement_MM(x, y, EL_EMPTY);
390 void DrawLevelField_MM(int x, int y)
392 DrawScreenField_MM(x, y);
395 void DrawMiniElement_MM(int x, int y, int element)
401 DrawMiniGraphic_MM(x, y, IMG_EMPTY);
406 graphic = el2gfx(element);
408 DrawMiniGraphic_MM(x, y, graphic);
411 void DrawMiniElementOrWall_MM(int sx, int sy, int scroll_x, int scroll_y)
413 int x = sx + scroll_x, y = sy + scroll_y;
415 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
416 DrawMiniElement_MM(sx, sy, EL_EMPTY);
417 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
418 DrawMiniElement_MM(sx, sy, Feld[x][y]);
421 void DrawField_MM(int x, int y)
423 int element = Feld[x][y];
425 DrawElement_MM(x, y, element);
428 void DrawLevel_MM(void)
434 for (x = 0; x < lev_fieldx; x++)
435 for (y = 0; y < lev_fieldy; y++)
438 redraw_mask |= REDRAW_FIELD;
441 void DrawWallsExt_MM(int x, int y, int element, int draw_mask)
444 int graphic = el2gfx(WALL_BASE(element));
448 getMiniGraphicSource(graphic, &bitmap, &gx, &gy);
450 DrawGraphic_MM(x, y, IMG_EMPTY);
453 if (IS_WALL_WOOD(element) || IS_WALL_AMOEBA(element) ||
454 IS_DF_WALL_WOOD(element))
456 if (IS_WALL_ICE(element) || IS_WALL_AMOEBA(element))
460 for (i = 0; i < 4; i++)
462 int dest_x = cSX + x * TILEX + MINI_TILEX * (i % 2);
463 int dest_y = cSY + y * TILEY + MINI_TILEY * (i / 2);
465 if (!((1 << i) & draw_mask))
468 if (element & (1 << i))
469 BlitBitmap(bitmap, drawto, gx, gy, MINI_TILEX, MINI_TILEY,
472 ClearRectangle(drawto, dest_x, dest_y, MINI_TILEX, MINI_TILEY);
478 void DrawWalls_MM(int x, int y, int element)
480 DrawWallsExt_MM(x, y, element, HIT_MASK_ALL);
483 void DrawWallsAnimation_MM(int x, int y, int element, int phase, int bit_mask)
489 DrawWalls_MM(x, y, element);
494 for (i = 0; i < 4; i++)
496 if (element & (1 << i))
502 int dst_x = cSX + x * TILEX + (i % 2) * MINI_TILEX;
503 int dst_y = cSY + y * TILEY + (i / 2) * MINI_TILEY;
505 if (bit_mask & (1 << i))
507 graphic = (IS_WALL_AMOEBA(element) ?
508 IMG_MM_AMOEBA_WALL_GROWING :
509 IMG_MM_ICE_WALL_SHRINKING);
514 graphic = (IS_WALL_AMOEBA(element) ?
520 getSizedGraphicSource(graphic, frame, MINI_TILESIZE, &bitmap,
523 BlitBitmap(bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
531 void DrawElement_MM(int x, int y, int element)
533 if (element == EL_EMPTY)
534 DrawGraphic_MM(x, y, IMG_EMPTY);
535 else if (IS_WALL(element))
536 DrawWalls_MM(x, y, element);
538 else if (IS_WALL_CHANGING(element) && IS_WALL_CHANGING(Feld[x][y]))
540 int wall_element = Feld[x][y] - EL_WALL_CHANGING + Store[x][y];
542 DrawWalls_MM(x, y, wall_element);
545 else if (element == EL_PACMAN)
546 DrawLevelField_MM(x, y);
547 else if (element == EL_FUSE_ON &&
551 DrawGraphic_MM(x, y, IMG_MM_FUSE);
553 DrawGraphic_MM(x, y, el2gfx(element));
557 static void DrawMicroWalls_MM(int x, int y, int element)
560 int graphic = el2gfx(WALL_BASE(element));
564 getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
566 for (i = 0; i < 4; i++)
568 int xpos = MICROLEV_XPOS + x * MICRO_TILEX + MICRO_WALLX * (i % 2);
569 int ypos = MICROLEV_YPOS + y * MICRO_TILEY + MICRO_WALLY * (i / 2);
571 if (element & (1 << i))
572 BlitBitmap(bitmap, drawto, gx, gy, MICRO_WALLX, MICRO_WALLY, xpos, ypos);
574 ClearRectangle(drawto, xpos, ypos, MICRO_WALLX, MICRO_WALLY);
578 static void DrawMicroElement_MM(int x, int y, int element)
581 int graphic = el2gfx(element);
584 if (element == EL_EMPTY)
587 if (IS_WALL(element))
589 DrawMicroWalls_MM(x, y, element);
594 getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
596 BlitBitmap(bitmap, drawto, gx, gy, MICRO_TILEX, MICRO_TILEY,
597 MICROLEV_XPOS + x * MICRO_TILEX, MICROLEV_YPOS + y * MICRO_TILEY);
600 static void DrawMicroLevelExt_MM(int xpos, int ypos)
604 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
606 for (x = 0; x < STD_LEV_FIELDX; x++)
607 for (y = 0; y < STD_LEV_FIELDY; y++)
608 DrawMicroElement_MM(x, y, Ur[x][y]);
610 redraw_mask |= REDRAW_FIELD;
614 void DrawMiniLevel_MM(int size_x, int size_y, int scroll_x, int scroll_y)
618 for(x = 0; x < size_x; x++)
619 for(y = 0; y < size_y; y++)
620 DrawMiniElementOrWall_MM(x, y, scroll_x, scroll_y);
622 redraw_mask |= REDRAW_FIELD;
626 static int REQ_in_range(int x, int y)
628 if (y > DY + 249 && y < DY + 278)
630 if (x > DX + 1 && x < DX + 48)
632 else if (x > DX + 51 && x < DX + 98)
640 Pixel ReadPixel(DrawBuffer *bitmap, int x, int y)
642 return GetPixel(bitmap, x, y);
645 void SetRGB(unsigned int pixel,
646 unsigned short red, unsigned short green, unsigned short blue)
650 int get_base_element(int element)
652 if (IS_MIRROR(element))
653 return EL_MIRROR_START;
654 else if (IS_MIRROR_FIXED(element))
655 return EL_MIRROR_FIXED_START;
656 else if (IS_POLAR(element))
657 return EL_POLAR_START;
658 else if (IS_POLAR_CROSS(element))
659 return EL_POLAR_CROSS_START;
660 else if (IS_BEAMER(element))
661 return EL_BEAMER_RED_START + BEAMER_NR(element) * 16;
662 else if (IS_FIBRE_OPTIC(element))
663 return EL_FIBRE_OPTIC_START + FIBRE_OPTIC_NR(element) * 2;
664 else if (IS_MCDUFFIN(element))
665 return EL_MCDUFFIN_START;
666 else if (IS_LASER(element))
667 return EL_LASER_START;
668 else if (IS_RECEIVER(element))
669 return EL_RECEIVER_START;
670 else if (IS_DF_MIRROR(element))
671 return EL_DF_MIRROR_START;
672 else if (IS_DF_MIRROR_AUTO(element))
673 return EL_DF_MIRROR_AUTO_START;
674 else if (IS_PACMAN(element))
675 return EL_PACMAN_START;
676 else if (IS_GRID_STEEL(element))
677 return EL_GRID_STEEL_START;
678 else if (IS_GRID_WOOD(element))
679 return EL_GRID_WOOD_START;
680 else if (IS_GRID_STEEL_FIXED(element))
681 return EL_GRID_STEEL_FIXED_START;
682 else if (IS_GRID_WOOD_FIXED(element))
683 return EL_GRID_WOOD_FIXED_START;
684 else if (IS_GRID_STEEL_AUTO(element))
685 return EL_GRID_STEEL_AUTO_START;
686 else if (IS_GRID_WOOD_AUTO(element))
687 return EL_GRID_WOOD_AUTO_START;
688 else if (IS_WALL_STEEL(element))
689 return EL_WALL_STEEL_START;
690 else if (IS_WALL_WOOD(element))
691 return EL_WALL_WOOD_START;
692 else if (IS_WALL_ICE(element))
693 return EL_WALL_ICE_START;
694 else if (IS_WALL_AMOEBA(element))
695 return EL_WALL_AMOEBA_START;
696 else if (IS_DF_WALL_STEEL(element))
697 return EL_DF_WALL_STEEL_START;
698 else if (IS_DF_WALL_WOOD(element))
699 return EL_DF_WALL_WOOD_START;
700 else if (IS_CHAR(element))
701 return EL_CHAR_START;
706 int get_element_phase(int element)
708 return element - get_base_element(element);
711 int get_num_elements(int element)
713 if (IS_MIRROR(element) ||
715 IS_BEAMER(element) ||
716 IS_DF_MIRROR(element) ||
717 IS_DF_MIRROR_AUTO(element))
719 else if (IS_GRID_STEEL_FIXED(element) ||
720 IS_GRID_WOOD_FIXED(element) ||
721 IS_GRID_STEEL_AUTO(element) ||
722 IS_GRID_WOOD_AUTO(element))
724 else if (IS_MIRROR_FIXED(element) ||
725 IS_POLAR_CROSS(element) ||
726 IS_MCDUFFIN(element) ||
728 IS_RECEIVER(element) ||
729 IS_PACMAN(element) ||
730 IS_GRID_STEEL(element) ||
731 IS_GRID_WOOD(element))
737 int get_rotated_element(int element, int step)
739 int base_element = get_base_element(element);
740 int num_elements = get_num_elements(element);
741 int element_phase = element - base_element;
743 return base_element + (element_phase + step + num_elements) % num_elements;
746 static int map_element(int element)
750 case EL_WALL_STEEL: return EL_STEEL_WALL;
751 case EL_WALL_WOOD: return EL_WOODEN_WALL;
752 case EL_WALL_ICE: return EL_ICE_WALL;
753 case EL_WALL_AMOEBA: return EL_AMOEBA_WALL;
754 case EL_DF_WALL_STEEL: return EL_DF_STEEL_WALL;
755 case EL_DF_WALL_WOOD: return EL_DF_WOODEN_WALL;
757 default: return element;
761 int el2gfx(int element)
763 element = map_element(element);
768 return IMG_MM_LIGHTBALL_RED + RND(3);
771 return el2img_mm(element);
775 void RedrawPlayfield_MM(void)
781 void BlitScreenToBitmap_MM(Bitmap *target_bitmap)
783 BlitBitmap(drawto_field, target_bitmap,
784 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);