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 /* forward declaration for internal use */
21 static int getGraphicAnimationPhase_MM(int, int, int);
25 ClearRectangle(backbuffer, REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE);
27 SetDrawtoField(DRAW_BACKBUFFER);
29 redraw_mask |= REDRAW_FIELD;
32 static int getGraphicAnimationPhase_MM(int frames, int delay, int mode)
36 if (mode == ANIM_PINGPONG)
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);
43 phase = (FrameCounter % (delay * frames)) / delay;
45 if (mode == ANIM_REVERSE)
51 void DrawGraphicAnimationExt_MM(int x, int y, int graphic,
52 int frames, int delay, int mode, int mask_mode)
54 int phase = getGraphicAnimationPhase_MM(frames, delay, mode);
56 if (!(FrameCounter % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
58 if (mask_mode == USE_MASKING)
59 DrawGraphicThruMask_MM(SCREENX(x), SCREENY(y), graphic + phase);
61 DrawGraphic_MM(SCREENX(x), SCREENY(y), graphic + phase);
65 void DrawGraphicAnimation_MM(int x, int y, int graphic,
66 int frames, int delay, int mode)
68 DrawGraphicAnimationExt_MM(x, y, graphic, frames, delay, mode, NO_MASKING);
71 void DrawGraphicAnimationThruMask_MM(int x, int y, int graphic,
72 int frames, int delay, int mode)
74 DrawGraphicAnimationExt_MM(x, y, graphic, frames, delay, mode, USE_MASKING);
77 void DrawGraphic_MM(int x, int y, int graphic)
80 if (!IN_SCR_FIELD(x,y))
82 printf("DrawGraphic_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
83 printf("DrawGraphic_MM(): This should never happen!\n");
88 DrawGraphicExt_MM(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
92 void DrawGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
97 getGraphicSource(graphic, 0, &bitmap, &src_x, &src_y);
98 BlitBitmap(bitmap, d, src_x, src_y, TILEX, TILEY, x, y);
101 void DrawGraphicThruMask_MM(int x, int y, int graphic)
104 if (!IN_SCR_FIELD(x,y))
106 printf("DrawGraphicThruMask_MM(): x = %d,y = %d, graphic = %d\n",x,y,graphic);
107 printf("DrawGraphicThruMask_MM(): This should never happen!\n");
112 DrawGraphicThruMaskExt_MM(drawto_field, FX + x*TILEX, FY + y*TILEY, graphic);
116 void DrawGraphicThruMaskExt_MM(DrawBuffer *d, int dest_x, int dest_y,
122 if (graphic == IMG_EMPTY)
125 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
127 BlitBitmapMasked(src_bitmap, d, src_x, src_y, TILEX, TILEY, dest_x, dest_y);
130 void DrawMiniGraphic_MM(int x, int y, int graphic)
132 DrawMiniGraphicExt_MM(drawto, SX + x*MINI_TILEX, SY + y*MINI_TILEY, graphic);
133 MarkTileDirty(x/2, y/2);
136 void getMicroGraphicSource(int graphic, Bitmap **bitmap, int *x, int *y)
138 getSizedGraphicSource(graphic, 0, TILESIZE / 4, bitmap, x, y);
141 void DrawMiniGraphicExt_MM(DrawBuffer *d, int x, int y, int graphic)
146 getMiniGraphicSource(graphic, &bitmap, &src_x, &src_y);
147 BlitBitmap(bitmap, d, src_x, src_y, MINI_TILEX, MINI_TILEY, x, y);
150 void DrawGraphicShifted_MM(int x,int y, int dx,int dy, int graphic,
151 int cut_mode, int mask_mode)
153 int width = TILEX, height = TILEY;
155 int src_x, src_y, dest_x, dest_y;
160 DrawGraphic_MM(x, y, graphic);
164 if (dx || dy) /* Verschiebung der Grafik? */
166 if (x < BX1) /* Element kommt von links ins Bild */
173 else if (x > BX2) /* Element kommt von rechts ins Bild */
179 else if (x==BX1 && dx < 0) /* Element verläßt links das Bild */
185 else if (x==BX2 && dx > 0) /* Element verläßt rechts das Bild */
187 else if (dx) /* allg. Bewegung in x-Richtung */
188 MarkTileDirty(x + SIGN(dx), y);
190 if (y < BY1) /* Element kommt von oben ins Bild */
192 if (cut_mode==CUT_BELOW) /* Element oberhalb des Bildes */
200 else if (y > BY2) /* Element kommt von unten ins Bild */
206 else if (y==BY1 && dy < 0) /* Element verläßt oben das Bild */
212 else if (dy > 0 && cut_mode == CUT_ABOVE)
214 if (y == BY2) /* Element unterhalb des Bildes */
220 MarkTileDirty(x, y + 1);
221 } /* Element verläßt unten das Bild */
222 else if (dy > 0 && (y == BY2 || cut_mode == CUT_BELOW))
224 else if (dy) /* allg. Bewegung in y-Richtung */
225 MarkTileDirty(x, y + SIGN(dy));
228 getGraphicSource(graphic, 0, &src_bitmap, &src_x, &src_y);
233 dest_x = FX + x * TILEX + dx;
234 dest_y = FY + y * TILEY + dy;
237 if (!IN_SCR_FIELD(x,y))
239 printf("DrawGraphicShifted_MM(): x = %d, y = %d, graphic = %d\n",x,y,graphic);
240 printf("DrawGraphicShifted_MM(): This should never happen!\n");
245 if (mask_mode == USE_MASKING)
247 BlitBitmapMasked(src_bitmap, drawto_field,
248 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 += 4 * !phase2;
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);
365 horiz_move = (MovDir[oldx][oldy] == MV_LEFT ||
366 MovDir[oldx][oldy] == MV_RIGHT);
368 DrawScreenElement_MM(x, y, EL_EMPTY);
369 element = Feld[oldx][oldy];
372 DrawScreenElementShifted_MM(sx,sy, MovPos[oldx][oldy],0,element,NO_CUTTING);
374 DrawScreenElementShifted_MM(sx,sy, 0,MovPos[oldx][oldy],element,NO_CUTTING);
376 else if (IS_DRAWABLE(element))
377 DrawScreenElement_MM(x, y, element);
379 DrawScreenElement_MM(x, y, EL_EMPTY);
382 void DrawLevelField_MM(int x, int y)
384 DrawScreenField_MM(x, y);
387 void DrawMiniElement_MM(int x, int y, int element)
393 DrawMiniGraphic_MM(x, y, IMG_EMPTY);
397 graphic = el2gfx(element);
398 DrawMiniGraphic_MM(x, y, graphic);
401 void DrawMiniElementOrWall_MM(int sx, int sy, int scroll_x, int scroll_y)
403 int x = sx + scroll_x, y = sy + scroll_y;
405 if (x < -1 || x > lev_fieldx || y < -1 || y > lev_fieldy)
406 DrawMiniElement_MM(sx, sy, EL_EMPTY);
407 else if (x > -1 && x < lev_fieldx && y > -1 && y < lev_fieldy)
408 DrawMiniElement_MM(sx, sy, Feld[x][y]);
411 void DrawField_MM(int x, int y)
413 int element = Feld[x][y];
415 DrawElement_MM(x, y, element);
424 for (x=0; x<lev_fieldx; x++)
425 for (y=0; y<lev_fieldy; y++)
428 redraw_mask |= REDRAW_FIELD;
431 void DrawWallsExt_MM(int x, int y, int element, int draw_mask)
434 int graphic = el2gfx(WALL_BASE(element));
438 getMiniGraphicSource(graphic, &bitmap, &gx, &gy);
440 if (game_status != LEVELED || !editor.draw_walls_masked)
441 DrawGraphic_MM(x, y, IMG_EMPTY);
444 if (IS_WALL_WOOD(element) || IS_WALL_AMOEBA(element) ||
445 IS_DF_WALL_WOOD(element))
447 if (IS_WALL_ICE(element) || IS_WALL_AMOEBA(element))
453 int dest_x = SX + x * TILEX + MINI_TILEX * (i % 2);
454 int dest_y = SY + y * TILEY + MINI_TILEY * (i / 2);
456 if (!((1 << i) & draw_mask))
459 if (element & (1 << i))
460 BlitBitmap(bitmap, drawto, gx, gy, MINI_TILEX, MINI_TILEY,
462 else if (!editor.draw_walls_masked)
463 ClearRectangle(drawto, dest_x, dest_y, MINI_TILEX, MINI_TILEY);
469 void DrawWalls_MM(int x, int y, int element)
471 DrawWallsExt_MM(x, y, element, HIT_MASK_ALL);
474 void DrawWallsAnimation_MM(int x, int y, int element, int phase, int bit_mask)
480 DrawWalls_MM(x, y, element);
485 for (i = 0; i < 4; i++)
487 if (element & (1 << i))
493 int dst_x = SX + x * TILEX + (i % 2) * MINI_TILEX;
494 int dst_y = SY + y * TILEY + (i / 2) * MINI_TILEY;
496 if (bit_mask & (1 << i))
498 graphic = (IS_WALL_AMOEBA(element) ?
499 IMG_MM_AMOEBA_WALL_GROWING :
500 IMG_MM_ICE_WALL_SHRINKING);
505 graphic = (IS_WALL_AMOEBA(element) ?
511 getGraphicSource(graphic, frame, &bitmap, &src_x, &src_y);
513 BlitBitmap(bitmap, drawto, src_x, src_y, MINI_TILEX, MINI_TILEY,
521 void DrawElement_MM(int x, int y, int element)
523 if (element == EL_EMPTY)
524 DrawGraphic_MM(x, y, IMG_EMPTY);
525 else if (IS_WALL(element))
526 DrawWalls_MM(x, y, element);
528 else if (IS_WALL_CHANGING(element) && IS_WALL_CHANGING(Feld[x][y]))
530 int wall_element = Feld[x][y] - EL_WALL_CHANGING + Store[x][y];
532 DrawWalls_MM(x, y, wall_element);
535 else if (element == EL_PACMAN)
536 DrawLevelField_MM(x, y);
538 DrawGraphic_MM(x, y, el2gfx(element));
541 void DrawMicroWalls_MM(int x, int y, int element)
544 int graphic = el2gfx(WALL_BASE(element));
548 getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
552 int xpos = MICROLEV_XPOS + x * MICRO_TILEX + MICRO_WALLX * (i % 2);
553 int ypos = MICROLEV_YPOS + y * MICRO_TILEY + MICRO_WALLY * (i / 2);
555 if (element & (1 << i))
556 BlitBitmap(bitmap, drawto, gx, gy, MICRO_WALLX, MICRO_WALLY, xpos, ypos);
558 ClearRectangle(drawto, xpos, ypos, MICRO_WALLX, MICRO_WALLY);
562 void DrawMicroElement_MM(int x, int y, int element)
565 int graphic = el2gfx(element);
568 if (element == EL_EMPTY)
571 if (IS_WALL(element))
573 DrawMicroWalls_MM(x, y, element);
577 getMicroGraphicSource(graphic, &bitmap, &gx, &gy);
579 BlitBitmap(bitmap, drawto, gx, gy, MICRO_TILEX, MICRO_TILEY,
580 MICROLEV_XPOS + x * MICRO_TILEX, MICROLEV_YPOS + y * MICRO_TILEY);
583 void DrawMicroLevelExt_MM(int xpos, int ypos)
587 ClearRectangle(drawto, xpos, ypos, MICROLEV_XSIZE, MICROLEV_YSIZE);
589 for (x=0; x<STD_LEV_FIELDX; x++)
590 for (y=0; y<STD_LEV_FIELDY; y++)
591 DrawMicroElement_MM(x, y, Ur[x][y]);
593 redraw_mask |= REDRAW_FIELD;
596 void DrawMiniLevel_MM(int size_x, int size_y, int scroll_x, int scroll_y)
600 for(x=0; x<size_x; x++)
601 for(y=0; y<size_y; y++)
602 DrawMiniElementOrWall_MM(x, y, scroll_x, scroll_y);
604 redraw_mask |= REDRAW_FIELD;
607 int REQ_in_range(int x, int y)
609 if (y > DY+249 && y < DY+278)
611 if (x > DX+1 && x < DX+48)
613 else if (x > DX+51 && x < DX+98)
619 Pixel ReadPixel(DrawBuffer *bitmap, int x, int y)
621 return GetPixel(bitmap, x, y);
624 void SetRGB(unsigned int pixel,
625 unsigned short red, unsigned short green, unsigned short blue)
629 int get_base_element(int element)
631 if (IS_MIRROR(element))
632 return EL_MIRROR_START;
633 else if (IS_MIRROR_FIXED(element))
634 return EL_MIRROR_FIXED_START;
635 else if (IS_POLAR(element))
636 return EL_POLAR_START;
637 else if (IS_POLAR_CROSS(element))
638 return EL_POLAR_CROSS_START;
639 else if (IS_BEAMER(element))
640 return EL_BEAMER_RED_START + BEAMER_NR(element) * 16;
641 else if (IS_FIBRE_OPTIC(element))
642 return EL_FIBRE_OPTIC_START + FIBRE_OPTIC_NR(element) * 2;
643 else if (IS_MCDUFFIN(element))
644 return EL_MCDUFFIN_START;
645 else if (IS_LASER(element))
646 return EL_LASER_START;
647 else if (IS_RECEIVER(element))
648 return EL_RECEIVER_START;
649 else if (IS_DF_MIRROR(element))
650 return EL_DF_MIRROR_START;
651 else if (IS_DF_MIRROR_AUTO(element))
652 return EL_DF_MIRROR_AUTO_START;
653 else if (IS_PACMAN(element))
654 return EL_PACMAN_START;
655 else if (IS_GRID_STEEL(element))
656 return EL_GRID_STEEL_START;
657 else if (IS_GRID_WOOD(element))
658 return EL_GRID_WOOD_START;
659 else if (IS_GRID_STEEL_FIXED(element))
660 return EL_GRID_STEEL_FIXED_START;
661 else if (IS_GRID_WOOD_FIXED(element))
662 return EL_GRID_WOOD_FIXED_START;
663 else if (IS_GRID_STEEL_AUTO(element))
664 return EL_GRID_STEEL_AUTO_START;
665 else if (IS_GRID_WOOD_AUTO(element))
666 return EL_GRID_WOOD_AUTO_START;
667 else if (IS_WALL_STEEL(element))
668 return EL_WALL_STEEL_START;
669 else if (IS_WALL_WOOD(element))
670 return EL_WALL_WOOD_START;
671 else if (IS_WALL_ICE(element))
672 return EL_WALL_ICE_START;
673 else if (IS_WALL_AMOEBA(element))
674 return EL_WALL_AMOEBA_START;
675 else if (IS_DF_WALL_STEEL(element))
676 return EL_DF_WALL_STEEL_START;
677 else if (IS_DF_WALL_WOOD(element))
678 return EL_DF_WALL_WOOD_START;
679 else if (IS_CHAR(element))
680 return EL_CHAR_START;
685 int get_element_phase(int element)
687 return element - get_base_element(element);
690 int get_num_elements(int element)
692 if (IS_MIRROR(element) ||
694 IS_BEAMER(element) ||
695 IS_DF_MIRROR(element) ||
696 IS_DF_MIRROR_AUTO(element))
698 else if (IS_GRID_STEEL_FIXED(element) ||
699 IS_GRID_WOOD_FIXED(element) ||
700 IS_GRID_STEEL_AUTO(element) ||
701 IS_GRID_WOOD_AUTO(element))
703 else if (IS_MIRROR_FIXED(element) ||
704 IS_POLAR_CROSS(element) ||
705 IS_MCDUFFIN(element) ||
707 IS_RECEIVER(element) ||
708 IS_PACMAN(element) ||
709 IS_GRID_STEEL(element) ||
710 IS_GRID_WOOD(element))
716 int get_rotated_element(int element, int step)
718 int base_element = get_base_element(element);
719 int num_elements = get_num_elements(element);
720 int element_phase = element - base_element;
722 return base_element + (element_phase + step + num_elements) % num_elements;
725 static int map_element(int element)
729 case EL_WALL_STEEL: return EL_STEEL_WALL;
730 case EL_WALL_WOOD: return EL_WOODEN_WALL;
731 case EL_WALL_ICE: return EL_ICE_WALL;
732 case EL_WALL_AMOEBA: return EL_AMOEBA_WALL;
733 case EL_DF_WALL_STEEL: return EL_DF_STEEL_WALL;
734 case EL_DF_WALL_WOOD: return EL_DF_WOODEN_WALL;
736 default: return element;
740 int el2gfx(int element)
742 element = map_element(element);
747 return IMG_MM_LIGHTBALL_RED + RND(3);
750 return el2img_mm(element);
754 void RedrawPlayfield_MM()
759 void BlitScreenToBitmap_MM(Bitmap *target_bitmap)
761 BlitBitmap(drawto_field, target_bitmap,
762 REAL_SX, REAL_SY, FULL_SXSIZE, FULL_SYSIZE, REAL_SX, REAL_SY);