static void RemoveMovingField_MM(int, int);
static void InitMovingField_MM(int, int, int);
static void ContinueMoving_MM(int, int);
-static void Moving2Blocked_MM(int, int, int *, int *);
+
+static void AddLaserEdge(int, int);
+static void ScanLaser(void);
+static void DrawLaser(int, int);
+static boolean HitElement(int, int);
+static boolean HitOnlyAnEdge(int);
+static boolean HitPolarizer(int, int);
+static boolean HitBlock(int, int);
+static boolean HitLaserSource(int, int);
+static boolean HitLaserDestination(int, int);
+static boolean HitReflectingWalls(int, int);
+static boolean HitAbsorbingWalls(int, int);
+static void RotateMirror(int, int, int);
+static boolean ObjHit(int, int, int);
+static void DeletePacMan(int, int);
+static void MovePacMen(void);
// bitmap for laser beam detection
static Bitmap *laser_bitmap = NULL;
#define MM_MASK_GRID_2 5
#define MM_MASK_GRID_3 6
#define MM_MASK_GRID_4 7
-#define MM_MASK_RECTANGLE 8
-#define MM_MASK_CIRCLE 9
+#define MM_MASK_SLOPE_1 8
+#define MM_MASK_SLOPE_2 9
+#define MM_MASK_SLOPE_3 10
+#define MM_MASK_SLOPE_4 11
+#define MM_MASK_RECTANGLE 12
+#define MM_MASK_CIRCLE 13
-#define NUM_MM_MASKS 10
+#define NUM_MM_MASKS 14
// element masks for scanning pixels of MM elements
static const char mm_masks[NUM_MM_MASKS][16][16 + 1] =
" XXX XXXX ",
" XX XXXXX ",
},
+ {
+ " X",
+ " XX",
+ " XXX",
+ " XXXX",
+ " XXXXX",
+ " XXXXXX",
+ " XXXXXXX",
+ " XXXXXXXX",
+ " XXXXXXXXX",
+ " XXXXXXXXXX",
+ " XXXXXXXXXXX",
+ " XXXXXXXXXXXX",
+ " XXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXX",
+ "XXXXXXXXXXXXXXXX",
+ },
+ {
+ "X ",
+ "XX ",
+ "XXX ",
+ "XXXX ",
+ "XXXXX ",
+ "XXXXXX ",
+ "XXXXXXX ",
+ "XXXXXXXX ",
+ "XXXXXXXXX ",
+ "XXXXXXXXXX ",
+ "XXXXXXXXXXX ",
+ "XXXXXXXXXXXX ",
+ "XXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXXXX",
+ },
+ {
+ "XXXXXXXXXXXXXXXX",
+ "XXXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXXX ",
+ "XXXXXXXXXXXXX ",
+ "XXXXXXXXXXXX ",
+ "XXXXXXXXXXX ",
+ "XXXXXXXXXX ",
+ "XXXXXXXXX ",
+ "XXXXXXXX ",
+ "XXXXXXX ",
+ "XXXXXX ",
+ "XXXXX ",
+ "XXXX ",
+ "XXX ",
+ "XX ",
+ "X ",
+ },
+ {
+ "XXXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXXX",
+ " XXXXXXXXXXXXX",
+ " XXXXXXXXXXXX",
+ " XXXXXXXXXXX",
+ " XXXXXXXXXX",
+ " XXXXXXXXX",
+ " XXXXXXXX",
+ " XXXXXXX",
+ " XXXXXX",
+ " XXXXX",
+ " XXXX",
+ " XXX",
+ " XX",
+ " X",
+ },
{
"XXXXXXXXXXXXXXXX",
"XXXXXXXXXXXXXXXX",
IS_LASER(element) ||
IS_RECEIVER(element))
return 4 * element_phase;
+ else if (IS_DF_SLOPE(element))
+ return 4 + (element_phase % 2) * 8;
else
return element_phase;
}
Pixel pixel_drawto = (mode == DL_LASER_ENABLED ? pen_ray : pen_bg);
Pixel pixel_buffer = (mode == DL_LASER_ENABLED ? WHITE_PIXEL : BLACK_PIXEL);
- DrawLines(drawto, points, num_points, pixel_drawto);
+ DrawLines(drawto_mm, points, num_points, pixel_drawto);
BEGIN_NO_HEADLESS
{
game_mm.laser_green = native_mm_level.df_laser_green;
game_mm.laser_blue = native_mm_level.df_laser_blue;
}
+
+ game_mm.has_mcduffin = (IS_MCDUFFIN(element));
}
break;
BEGIN_NO_HEADLESS
{
// initialize laser bitmap to current playfield (screen) size
- ReCreateBitmap(&laser_bitmap, drawto->width, drawto->height);
- ClearRectangle(laser_bitmap, 0, 0, drawto->width, drawto->height);
+ ReCreateBitmap(&laser_bitmap, drawto_mm->width, drawto_mm->height);
+ ClearRectangle(laser_bitmap, 0, 0, drawto_mm->width, drawto_mm->height);
}
END_NO_HEADLESS
game_mm.laser_red = FALSE;
game_mm.laser_green = FALSE;
game_mm.laser_blue = TRUE;
+ game_mm.has_mcduffin = TRUE;
game_mm.level_solved = FALSE;
game_mm.game_over = FALSE;
game_mm.game_over_cause = 0;
+ game_mm.game_over_message = NULL;
game_mm.laser_overload_value = 0;
game_mm.laser_enabled = FALSE;
AdvanceFrameCounter();
AdvanceGfxFrame();
- DrawLevel_MM();
-
- BackToFront();
-
- ColorCycling();
-
#ifdef DEBUG
if (setup.quick_doors)
continue;
#endif
+
+ DrawLevel_MM();
+
+ BackToFront_MM();
}
+#ifdef DEBUG
+ if (setup.quick_doors)
+ DrawLevel_MM();
+#endif
+
ScanLaser();
if (game_mm.kettles_still_needed == 0)
DrawLaser(0, DL_LASER_ENABLED);
- BackToFront();
+ BackToFront_MM();
Delay_WithScreenUpdates(50);
}
static void GameOver_MM(int game_over_cause)
{
- // do not handle game over if request dialog is already active
- if (game.request_active)
- return;
-
game_mm.game_over = TRUE;
game_mm.game_over_cause = game_over_cause;
-
- if (setup.ask_on_game_over)
- game.restart_game_message = (game_over_cause == GAME_OVER_BOMB ?
- "Bomb killed Mc Duffin! Play it again?" :
- game_over_cause == GAME_OVER_NO_ENERGY ?
- "Out of magic energy! Play it again?" :
- game_over_cause == GAME_OVER_OVERLOADED ?
- "Magic spell hit Mc Duffin! Play it again?" :
- NULL);
+ game_mm.game_over_message = (game_mm.has_mcduffin ?
+ (game_over_cause == GAME_OVER_BOMB ?
+ "Bomb killed Mc Duffin!" :
+ game_over_cause == GAME_OVER_NO_ENERGY ?
+ "Out of magic energy!" :
+ game_over_cause == GAME_OVER_OVERLOADED ?
+ "Magic spell hit Mc Duffin!" :
+ NULL) :
+ (game_over_cause == GAME_OVER_BOMB ?
+ "Bomb destroyed laser cannon!" :
+ game_over_cause == GAME_OVER_NO_ENERGY ?
+ "Out of laser energy!" :
+ game_over_cause == GAME_OVER_OVERLOADED ?
+ "Laser beam hit laser cannon!" :
+ NULL));
SetTileCursorActive(FALSE);
}
-void AddLaserEdge(int lx, int ly)
+static void AddLaserEdge(int lx, int ly)
{
- int clx = dSX + lx;
- int cly = dSY + ly;
+ int full_sxsize = MAX(FULL_SXSIZE, lev_fieldx * TILEX);
+ int full_sysize = MAX(FULL_SYSIZE, lev_fieldy * TILEY);
- if (clx < -2 || cly < -2 || clx >= SXSIZE + 2 || cly >= SYSIZE + 2)
+ // check if laser is still inside visible playfield area (or inside level)
+ if (cSX + lx < REAL_SX || cSX + lx >= REAL_SX + full_sxsize ||
+ cSY + ly < REAL_SY || cSY + ly >= REAL_SY + full_sysize)
{
Warn("AddLaserEdge: out of bounds: %d, %d", lx, ly);
laser.redraw = TRUE;
}
-void AddDamagedField(int ex, int ey)
+static void AddDamagedField(int ex, int ey)
{
// prevent adding the same field position again
if (laser.num_damages > 0 &&
static int getMaskFromElement(int element)
{
- if (IS_GRID(element))
- return MM_MASK_GRID_1 + get_element_phase(element);
- else if (IS_MCDUFFIN(element))
+ if (IS_MCDUFFIN(element))
return MM_MASK_MCDUFFIN_RIGHT + get_element_phase(element);
- else if (IS_RECTANGLE(element) || IS_DF_GRID(element))
+ else if (IS_GRID(element))
+ return MM_MASK_GRID_1 + get_element_phase(element);
+ else if (IS_DF_GRID(element))
+ return MM_MASK_RECTANGLE;
+ else if (IS_DF_SLOPE(element))
+ return MM_MASK_SLOPE_1 + get_element_phase(element);
+ else if (IS_RECTANGLE(element))
return MM_MASK_RECTANGLE;
else
return MM_MASK_CIRCLE;
}
+static int getLevelFromLaserX(int x)
+{
+ return x / TILEX - (x < 0 ? 1 : 0); // correct negative values
+}
+
+static int getLevelFromLaserY(int y)
+{
+ return y / TILEY - (y < 0 ? 1 : 0); // correct negative values
+}
+
static int ScanPixel(void)
{
int hit_mask = 0;
}
#endif
+ // check if laser scan has crossed element boundaries (not just mini tiles)
+ boolean cross_x = (LX / TILEX != (LX + 2) / TILEX);
+ boolean cross_y = (LY / TILEY != (LY + 2) / TILEY);
+
+ if (cross_x && cross_y)
+ {
+ int elx1 = (LX - XS) / TILEX;
+ int ely1 = (LY + YS) / TILEY;
+ int elx2 = (LX + XS) / TILEX;
+ int ely2 = (LY - YS) / TILEY;
+
+ // add element corners left and right from the laser beam to damage list
+
+ if (IN_LEV_FIELD(elx1, ely1) && Tile[elx1][ely1] != EL_EMPTY)
+ AddDamagedField(elx1, ely1);
+
+ if (IN_LEV_FIELD(elx2, ely2) && Tile[elx2][ely2] != EL_EMPTY)
+ AddDamagedField(elx2, ely2);
+ }
+
for (i = 0; i < 4; i++)
{
int px = LX + (i % 2) * 2;
int py = LY + (i / 2) * 2;
int dx = px % TILEX;
int dy = py % TILEY;
- int lx = (px + TILEX) / TILEX - 1; // ...+TILEX...-1 to get correct
- int ly = (py + TILEY) / TILEY - 1; // negative values!
+ int lx = getLevelFromLaserX(px);
+ int ly = getLevelFromLaserY(py);
Pixel pixel;
if (IN_LEV_FIELD(lx, ly))
}
else
{
+ // check if laser is still inside visible playfield area
pixel = (cSX + px < REAL_SX || cSX + px >= REAL_SX + FULL_SXSIZE ||
cSY + py < REAL_SY || cSY + py >= REAL_SY + FULL_SYSIZE);
}
{
if (laser.dest_element_last == EL_BOMB_ACTIVE ||
laser.dest_element_last == EL_MINE_ACTIVE ||
+ laser.dest_element_last == EL_GRAY_BALL_ACTIVE ||
laser.dest_element_last == EL_GRAY_BALL_OPENING)
{
int x = laser.dest_element_last_x;
if (Tile[x][y] == element)
Tile[x][y] = (element == EL_BOMB_ACTIVE ? EL_BOMB :
- element == EL_MINE_ACTIVE ? EL_MINE : EL_BALL_GRAY);
+ element == EL_MINE_ACTIVE ? EL_MINE : EL_GRAY_BALL);
- if (Tile[x][y] == EL_BALL_GRAY)
+ if (Tile[x][y] == EL_GRAY_BALL)
MovDelay[x][y] = 0;
laser.dest_element_last = EL_EMPTY;
}
}
-void ScanLaser(void)
+static void ScanLaser(void)
{
int element = EL_EMPTY;
int last_element = EL_EMPTY;
LX, LY, XS, YS);
#endif
- // hit something -- check out what it was
- ELX = (LX + XS) / TILEX;
- ELY = (LY + YS) / TILEY;
+ // check if laser scan has hit two diagonally adjacent element corners
+ boolean diag_1 = ((hit_mask & HIT_MASK_DIAGONAL_1) == HIT_MASK_DIAGONAL_1);
+ boolean diag_2 = ((hit_mask & HIT_MASK_DIAGONAL_2) == HIT_MASK_DIAGONAL_2);
+
+ // check if laser scan has crossed element boundaries (not just mini tiles)
+ boolean cross_x = (getLevelFromLaserX(LX) != getLevelFromLaserX(LX + 2));
+ boolean cross_y = (getLevelFromLaserY(LY) != getLevelFromLaserY(LY + 2));
+
+ if (cross_x || cross_y)
+ {
+ // hit something at next tile -- check out what it was
+ ELX = getLevelFromLaserX(LX + XS);
+ ELY = getLevelFromLaserY(LY + YS);
+ }
+ else
+ {
+ // hit something at same tile -- check out what it was
+ ELX = getLevelFromLaserX(LX);
+ ELY = getLevelFromLaserY(LY);
+ }
#if 0
Debug("game:mm:ScanLaser", "hit_mask (1) == '%x' (%d, %d) (%d, %d)",
hit_mask, LX, LY, ELX, ELY);
#endif
- if (!IN_LEV_FIELD(ELX, ELY) || !IN_PIX_FIELD(LX, LY))
+ if (!IN_LEV_FIELD(ELX, ELY))
{
+ // laser next step position
+ int x = cSX + LX + XS;
+ int y = cSY + LY + YS;
+
+ // check if next step of laser is still inside visible playfield area
+ if (x >= REAL_SX && x < REAL_SX + FULL_SXSIZE &&
+ y >= REAL_SY && y < REAL_SY + FULL_SYSIZE)
+ {
+ // go on with another step
+ LX += XS;
+ LY += YS;
+
+ continue;
+ }
+
element = EL_EMPTY;
laser.dest_element = element;
break;
}
- if (hit_mask == (HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT))
- {
- /* we have hit the top-right and bottom-left element --
- choose the bottom-left one */
- /* !!! THIS CAN BE DONE MORE INTELLIGENTLY, FOR EXAMPLE, IF ONE
- ELEMENT WAS STEEL AND THE OTHER ONE WAS ICE => ALWAYS CHOOSE
- THE ICE AND MELT IT AWAY INSTEAD OF OVERLOADING LASER !!! */
- ELX = (LX - 2) / TILEX;
- ELY = (LY + 2) / TILEY;
- }
+ boolean diagonally_adjacent_hit = FALSE;
- if (hit_mask == (HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT))
+ // handle special case of laser hitting two diagonally adjacent elements
+ // (with or without a third corner element behind these two elements)
+ if ((diag_1 || diag_2) && cross_x && cross_y)
{
- /* we have hit the top-left and bottom-right element --
- choose the top-left one */
- // !!! SEE ABOVE !!!
- ELX = (LX - 2) / TILEX;
- ELY = (LY - 2) / TILEY;
+ diagonally_adjacent_hit = TRUE;
+
+ // compare the two diagonally adjacent elements
+ int xoffset = 2;
+ int yoffset = 2 * (diag_1 ? -1 : +1);
+ int elx1 = (LX - xoffset) / TILEX;
+ int ely1 = (LY + yoffset) / TILEY;
+ int elx2 = (LX + xoffset) / TILEX;
+ int ely2 = (LY - yoffset) / TILEY;
+ int e1 = Tile[elx1][ely1];
+ int e2 = Tile[elx2][ely2];
+ boolean use_element_1 = FALSE;
+
+ if (IS_WALL_ICE(e1) || IS_WALL_ICE(e2))
+ {
+ if (IS_WALL_ICE(e1) && IS_WALL_ICE(e2))
+ use_element_1 = (RND(2) ? TRUE : FALSE);
+ else if (IS_WALL_ICE(e1))
+ use_element_1 = TRUE;
+ }
+ else if (IS_WALL_AMOEBA(e1) || IS_WALL_AMOEBA(e2))
+ {
+ // if both tiles match, we can just select the first one
+ if (IS_WALL_AMOEBA(e1))
+ use_element_1 = TRUE;
+ }
+ else if (IS_ABSORBING_BLOCK(e1) || IS_ABSORBING_BLOCK(e2))
+ {
+ // if both tiles match, we can just select the first one
+ if (IS_ABSORBING_BLOCK(e1))
+ use_element_1 = TRUE;
+ }
+
+ ELX = (use_element_1 ? elx1 : elx2);
+ ELY = (use_element_1 ? ely1 : ely2);
}
#if 0
break;
}
}
+ else if (IS_DF_SLOPE(element))
+ {
+ if (diagonally_adjacent_hit)
+ {
+ laser.overloaded = TRUE;
+
+ break;
+ }
+
+ if (hit_mask == HIT_MASK_LEFT ||
+ hit_mask == HIT_MASK_RIGHT ||
+ hit_mask == HIT_MASK_TOP ||
+ hit_mask == HIT_MASK_BOTTOM)
+ {
+ if (HitReflectingWalls(element, hit_mask))
+ break;
+ }
+ else
+ {
+ if (HitElement(element, hit_mask))
+ break;
+ }
+ }
else
{
if (HitElement(element, hit_mask))
#endif
}
+static void ScanLaser_FromLastMirror(void)
+{
+ int start_pos = (laser.num_damages > 0 ? laser.num_damages - 1 : 0);
+ int i;
+
+ for (i = start_pos; i >= 0; i--)
+ if (laser.damage[i].is_mirror)
+ break;
+
+ int start_edge = (i > 0 ? laser.damage[i].edge - 1 : 0);
+
+ DrawLaser(start_edge, DL_LASER_DISABLED);
+
+ ScanLaser();
+}
+
static void DrawLaserExt(int start_edge, int num_edges, int mode)
{
int element;
DrawLaser(0, game_mm.laser_enabled);
}
-boolean HitElement(int element, int hit_mask)
+static boolean HitElement(int element, int hit_mask)
{
- if (HitOnlyAnEdge(hit_mask))
- return FALSE;
+ if (IS_DF_SLOPE(element))
+ {
+ int mirrored_angle = get_mirrored_angle(laser.current_angle,
+ get_element_angle(element));
+ int opposite_angle = get_opposite_angle(laser.current_angle);
+
+ // check if laser is reflected by slope by 180°
+ if (mirrored_angle == opposite_angle)
+ {
+ LX += XS;
+ LY += YS;
+
+ AddDamagedField(LX / TILEX, LY / TILEY);
+
+ laser.overloaded = TRUE;
+
+ return TRUE;
+ }
+ }
+ else
+ {
+ if (HitOnlyAnEdge(hit_mask))
+ return FALSE;
+ }
if (IS_MOVING(ELX, ELY) || IS_BLOCKED(ELX, ELY))
element = MovingOrBlocked2Element_MM(ELX, ELY);
AddDamagedField(ELX, ELY);
+ boolean through_center = ((ELX * TILEX + 14 - LX) * YS ==
+ (ELY * TILEY + 14 - LY) * XS);
+
// this is more precise: check if laser would go through the center
- if ((ELX * TILEX + 14 - LX) * YS != (ELY * TILEY + 14 - LY) * XS)
+ if (!IS_DF_SLOPE(element) && !through_center)
{
+ int skip_count = 0;
+
// prevent cutting through laser emitter with laser beam
if (IS_LASER(element))
return TRUE;
{
LX += XS;
LY += YS;
+
+ skip_count++;
}
while (ELX == LX/TILEX && ELY == LY/TILEY && LX > 0 && LY > 0);
- if (LX/TILEX > ELX || LY/TILEY > ELY)
+ if ((LX/TILEX > ELX || LY/TILEY > ELY) && skip_count > 1)
{
/* skipping scan positions to the right and down skips one scan
position too much, because this is only the top left scan position
of totally four scan positions (plus one to the right, one to the
bottom and one to the bottom right) */
+ /* ... but only roll back scan position if more than one step done */
LX -= XS;
LY -= YS;
return TRUE;
}
- if (!IS_BEAMER(element) &&
- !IS_FIBRE_OPTIC(element) &&
- !IS_GRID_WOOD(element) &&
- element != EL_FUEL_EMPTY)
+ if (IS_DF_SLOPE(element) && !through_center)
+ {
+ int correction = 2;
+
+ if (hit_mask == HIT_MASK_ALL)
+ {
+ // laser already inside slope -- go back half step
+ LX -= XS / 2;
+ LY -= YS / 2;
+
+ correction = 1;
+ }
+
+ AddLaserEdge(LX, LY);
+
+ LX -= (ABS(XS) < ABS(YS) ? correction * SIGN(XS) : 0);
+ LY -= (ABS(YS) < ABS(XS) ? correction * SIGN(YS) : 0);
+ }
+ else if (!IS_BEAMER(element) &&
+ !IS_FIBRE_OPTIC(element) &&
+ !IS_GRID_WOOD(element) &&
+ element != EL_FUEL_EMPTY)
{
#if 0
if ((ELX * TILEX + 14 - LX) * YS == (ELY * TILEY + 14 - LY) * XS)
IS_POLAR_CROSS(element) ||
IS_DF_MIRROR(element) ||
IS_DF_MIRROR_AUTO(element) ||
+ IS_DF_MIRROR_FIXED(element) ||
+ IS_DF_SLOPE(element) ||
element == EL_PRISM ||
element == EL_REFRACTOR)
{
if (IS_MIRROR(element) ||
IS_MIRROR_FIXED(element) ||
IS_DF_MIRROR(element) ||
- IS_DF_MIRROR_AUTO(element))
+ IS_DF_MIRROR_AUTO(element) ||
+ IS_DF_MIRROR_FIXED(element) ||
+ IS_DF_SLOPE(element))
laser.current_angle = get_mirrored_angle(laser.current_angle,
get_element_angle(element));
(get_opposite_angle(laser.current_angle) ==
laser.damage[laser.num_damages - 1].angle ? TRUE : FALSE);
+ if (IS_DF_SLOPE(element))
+ {
+ // handle special cases for slope element
+
+ if (IS_45_ANGLE(laser.current_angle))
+ {
+ int elx, ely;
+
+ elx = getLevelFromLaserX(LX);
+ ely = getLevelFromLaserY(LY);
+
+ if (IN_LEV_FIELD(elx, ely))
+ {
+ int element_next = Tile[elx][ely];
+
+ // check if slope is followed by slope with opposite orientation
+ if (IS_DF_SLOPE(element_next) && ABS(element - element_next) == 2)
+ laser.overloaded = TRUE;
+ }
+
+ int nr = element - EL_DF_SLOPE_START;
+ int dx = (nr == 0 ? (XS > 0 ? TILEX - 1 : -1) :
+ nr == 1 ? (XS > 0 ? TILEX : 1) :
+ nr == 2 ? (XS > 0 ? TILEX : 1) :
+ nr == 3 ? (XS > 0 ? TILEX - 1 : -1) : 0);
+ int dy = (nr == 0 ? (YS > 0 ? TILEY - 1 : -1) :
+ nr == 1 ? (YS > 0 ? TILEY - 1 : -1) :
+ nr == 2 ? (YS > 0 ? TILEY : 0) :
+ nr == 3 ? (YS > 0 ? TILEY : 0) : 0);
+
+ int px = ELX * TILEX + dx;
+ int py = ELY * TILEY + dy;
+
+ dx = px % TILEX;
+ dy = py % TILEY;
+
+ elx = getLevelFromLaserX(px);
+ ely = getLevelFromLaserY(py);
+
+ if (IN_LEV_FIELD(elx, ely))
+ {
+ int element_side = Tile[elx][ely];
+
+ // check if end of slope is blocked by other element
+ if (IS_WALL(element_side) || IS_WALL_CHANGING(element_side))
+ {
+ int pos = dy / MINI_TILEY * 2 + dx / MINI_TILEX;
+
+ if (element & (1 << pos))
+ laser.overloaded = TRUE;
+ }
+ else
+ {
+ int pos = getMaskFromElement(element_side);
+
+ if (mm_masks[pos][dx / 2][dx / 2] == 'X')
+ laser.overloaded = TRUE;
+ }
+ }
+ }
+ }
+
return (laser.overloaded ? TRUE : FALSE);
}
return TRUE;
}
- if (element == EL_BOMB || element == EL_MINE)
+ if (element == EL_BOMB || element == EL_MINE || element == EL_GRAY_BALL)
{
PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_HITTING);
- Tile[ELX][ELY] = (element == EL_BOMB ? EL_BOMB_ACTIVE : EL_MINE_ACTIVE);
+ Tile[ELX][ELY] = (element == EL_BOMB ? EL_BOMB_ACTIVE :
+ element == EL_MINE ? EL_MINE_ACTIVE :
+ EL_GRAY_BALL_ACTIVE);
+
+ GfxFrame[ELX][ELY] = 0; // restart animation
laser.dest_element_last = Tile[ELX][ELY];
laser.dest_element_last_x = ELX;
return TRUE;
}
-boolean HitOnlyAnEdge(int hit_mask)
+static boolean HitOnlyAnEdge(int hit_mask)
{
// check if the laser hit only the edge of an element and, if so, go on
return FALSE;
}
-boolean HitPolarizer(int element, int hit_mask)
+static boolean HitPolarizer(int element, int hit_mask)
{
if (HitOnlyAnEdge(hit_mask))
return FALSE;
}
else if (IS_GRID_STEEL(element))
{
+ // may be required if graphics for steel grid redefined
+ AddDamagedField(ELX, ELY);
+
return HitReflectingWalls(element, hit_mask);
}
else // IS_GRID_WOOD
{
+ // may be required if graphics for wooden grid redefined
+ AddDamagedField(ELX, ELY);
+
return HitAbsorbingWalls(element, hit_mask);
}
return TRUE;
}
-boolean HitBlock(int element, int hit_mask)
+static boolean HitBlock(int element, int hit_mask)
{
boolean check = FALSE;
if (element == EL_GATE_STONE || element == EL_GATE_WOOD)
{
int xs = XS / 2, ys = YS / 2;
- int hit_mask_diagonal1 = HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT;
- int hit_mask_diagonal2 = HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT;
- if ((hit_mask & hit_mask_diagonal1) == hit_mask_diagonal1 ||
- (hit_mask & hit_mask_diagonal2) == hit_mask_diagonal2)
+ if ((hit_mask & HIT_MASK_DIAGONAL_1) == HIT_MASK_DIAGONAL_1 ||
+ (hit_mask & HIT_MASK_DIAGONAL_2) == HIT_MASK_DIAGONAL_2)
{
laser.overloaded = (element == EL_GATE_STONE);
if (element == EL_BLOCK_STONE || element == EL_BLOCK_WOOD)
{
int xs = XS / 2, ys = YS / 2;
- int hit_mask_diagonal1 = HIT_MASK_TOPRIGHT | HIT_MASK_BOTTOMLEFT;
- int hit_mask_diagonal2 = HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT;
- if ((hit_mask & hit_mask_diagonal1) == hit_mask_diagonal1 ||
- (hit_mask & hit_mask_diagonal2) == hit_mask_diagonal2)
+ if ((hit_mask & HIT_MASK_DIAGONAL_1) == HIT_MASK_DIAGONAL_1 ||
+ (hit_mask & HIT_MASK_DIAGONAL_2) == HIT_MASK_DIAGONAL_2)
{
laser.overloaded = (element == EL_BLOCK_STONE);
return TRUE;
}
-boolean HitLaserSource(int element, int hit_mask)
+static boolean HitLaserSource(int element, int hit_mask)
{
if (HitOnlyAnEdge(hit_mask))
return FALSE;
return TRUE;
}
-boolean HitLaserDestination(int element, int hit_mask)
+static boolean HitLaserDestination(int element, int hit_mask)
{
if (HitOnlyAnEdge(hit_mask))
return FALSE;
return TRUE;
}
-boolean HitReflectingWalls(int element, int hit_mask)
+static boolean HitReflectingWalls(int element, int hit_mask)
{
// check if laser hits side of a wall with an angle that is not 90°
if (!IS_90_ANGLE(laser.current_angle) && (hit_mask == HIT_MASK_TOP ||
return FALSE;
}
-boolean HitAbsorbingWalls(int element, int hit_mask)
+static boolean HitAbsorbingWalls(int element, int hit_mask)
{
if (HitOnlyAnEdge(hit_mask))
return FALSE;
if (IS_WALL_ICE(element))
{
+ int lx = LX + XS;
+ int ly = LY + YS;
int mask;
- mask = (LX + XS) / MINI_TILEX - ELX * 2 + 1; // Quadrant (horizontal)
- mask <<= (((LY + YS) / MINI_TILEY - ELY * 2) > 0) * 2; // || (vertical)
+ // check if laser hit adjacent edges of two diagonal tiles
+ if (ELX != lx / TILEX)
+ lx = LX - XS;
+ if (ELY != ly / TILEY)
+ ly = LY - YS;
+
+ mask = lx / MINI_TILEX - ELX * 2 + 1; // Quadrant (horizontal)
+ mask <<= ((ly / MINI_TILEY - ELY * 2) > 0 ? 2 : 0); // || (vertical)
// check if laser hits wall with an angle of 90°
if (IS_90_ANGLE(laser.current_angle))
if (IS_90_ANGLE(laser.current_angle))
mask += mask * (2 + IS_HORIZ_ANGLE(laser.current_angle) * 2);
- laser.dest_element = element2 | EL_WALL_AMOEBA;
+ laser.dest_element = element2 | EL_WALL_AMOEBA_BASE;
laser.wall_mask = mask;
}
}
}
-static void OpenSurpriseBall(int x, int y)
+static void OpenGrayBall(int x, int y)
{
int delay = 2;
if (!MovDelay[x][y]) // next animation frame
+ {
+ if (IS_WALL(Store[x][y]))
+ {
+ DrawWalls_MM(x, y, Store[x][y]);
+
+ // copy wall tile to spare bitmap for "melting" animation
+ BlitBitmap(drawto_mm, bitmap_db_field, cSX + x * TILEX, cSY + y * TILEY,
+ TILEX, TILEY, x * TILEX, y * TILEY);
+
+ DrawElement_MM(x, y, EL_GRAY_BALL);
+ }
+
MovDelay[x][y] = 50 * delay;
+ }
if (MovDelay[x][y]) // wait some time before next frame
{
if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y))
{
Bitmap *bitmap;
- int graphic = el2gfx(Store[x][y]);
int gx, gy;
int dx = RND(26), dy = RND(26);
- getGraphicSource(graphic, 0, &bitmap, &gx, &gy);
+ if (IS_WALL(Store[x][y]))
+ {
+ // copy wall tile from spare bitmap for "melting" animation
+ bitmap = bitmap_db_field;
+ gx = x * TILEX;
+ gy = y * TILEY;
+ }
+ else
+ {
+ int graphic = el2gfx(Store[x][y]);
+
+ getGraphicSource(graphic, 0, &bitmap, &gx, &gy);
+ }
- BlitBitmap(bitmap, drawto, gx + dx, gy + dy, 6, 6,
+ BlitBitmap(bitmap, drawto_mm, gx + dx, gy + dy, 6, 6,
cSX + x * TILEX + dx, cSY + y * TILEY + dy);
laser.redraw = TRUE;
InitField(x, y, FALSE);
DrawField_MM(x, y);
- ScanLaser();
+ ScanLaser_FromLastMirror();
}
}
}
ScanLaser();
- ShowEnvelope_MM(nr);
+ ShowEnvelope(nr);
}
}
}
{
int phase;
int wall_mask = Store2[x][y];
- int real_element = Tile[x][y] - EL_WALL_CHANGING + EL_WALL_ICE;
+ int real_element = Tile[x][y] - EL_WALL_CHANGING_BASE + EL_WALL_ICE_BASE;
MovDelay[x][y]--;
phase = frames - MovDelay[x][y] / delay - 1;
if (!MovDelay[x][y])
{
- int i;
-
Tile[x][y] = real_element & (wall_mask ^ 0xFF);
Store[x][y] = Store2[x][y] = 0;
DrawWalls_MM(x, y, Tile[x][y]);
- if (Tile[x][y] == EL_WALL_ICE)
+ if (Tile[x][y] == EL_WALL_ICE_BASE)
Tile[x][y] = EL_EMPTY;
- for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i >= 0; i--)
- if (laser.damage[i].is_mirror)
- break;
-
- if (i > 0)
- DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED);
- else
- DrawLaser(0, DL_LASER_DISABLED);
-
- ScanLaser();
+ ScanLaser_FromLastMirror();
}
else if (!(MovDelay[x][y] % delay) && IN_SCR_FIELD(x, y))
{
{
int phase;
int wall_mask = Store2[x][y];
- int real_element = Tile[x][y] - EL_WALL_CHANGING + EL_WALL_AMOEBA;
+ int real_element = Tile[x][y] - EL_WALL_CHANGING_BASE + EL_WALL_AMOEBA_BASE;
MovDelay[x][y]--;
phase = MovDelay[x][y] / delay;
int num_phase = 9, delay = 2;
int last_phase = num_phase * delay;
int half_phase = (num_phase / 2) * delay;
+ int center_element;
laser.redraw = TRUE;
if (phase == EX_PHASE_START) // initialize 'Store[][]' field
{
- int center_element = Tile[x][y];
+ center_element = Tile[x][y];
if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
{
Tile[x][y] = center_element;
}
- Store[x][y] = center_element;
- Store2[x][y] = mode;
+ if (center_element != EL_GRAY_BALL_ACTIVE)
+ Store[x][y] = EL_EMPTY;
+ Store2[x][y] = center_element;
Tile[x][y] = EL_EXPLODING_OPAQUE;
GfxElement[x][y] = (center_element == EL_BOMB_ACTIVE ? EL_BOMB :
+ center_element == EL_GRAY_BALL_ACTIVE ? EL_GRAY_BALL :
IS_MCDUFFIN(center_element) ? EL_MCDUFFIN :
center_element);
ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
- if (phase == half_phase)
+ center_element = Store2[x][y];
+
+ if (phase == half_phase && Store[x][y] == EL_EMPTY)
{
Tile[x][y] = EL_EXPLODING_TRANSP;
if (phase == last_phase)
{
- if (Store[x][y] == EL_BOMB_ACTIVE)
+ if (center_element == EL_BOMB_ACTIVE)
{
DrawLaser(0, DL_LASER_DISABLED);
InitLaser();
Bang_MM(laser.start_edge.x, laser.start_edge.y);
- GameOver_MM(GAME_OVER_DELAYED);
-
laser.overloaded = FALSE;
}
- else if (IS_MCDUFFIN(Store[x][y]))
+ else if (IS_MCDUFFIN(center_element) || IS_LASER(center_element))
{
GameOver_MM(GAME_OVER_BOMB);
}
- Tile[x][y] = EL_EMPTY;
+ Tile[x][y] = Store[x][y];
Store[x][y] = Store2[x][y] = 0;
MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
InitField(x, y, FALSE);
DrawField_MM(x, y);
+
+ if (center_element == EL_GRAY_BALL_ACTIVE)
+ ScanLaser_FromLastMirror();
}
else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
{
int element = Tile[x][y];
-#if 0
- DrawLaser(0, DL_LASER_ENABLED);
-#endif
-
if (IS_PACMAN(element))
PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
else if (element == EL_BOMB_ACTIVE || IS_MCDUFFIN(element))
Explode_MM(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
}
-void TurnRound(int x, int y)
+static void TurnRound(int x, int y)
{
static struct
{
int x, y;
} move_xy[] =
{
- { 0, 0 },
- {-1, 0 },
- {+1, 0 },
- { 0, 0 },
- { 0, -1 },
- { 0, 0 }, { 0, 0 }, { 0, 0 },
- { 0, +1 }
+ { 0, 0 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, 0 },
+ { 0, -1 },
+ { 0, 0 }, { 0, 0 }, { 0, 0 },
+ { 0, +1 }
};
static struct
{
int left, right, back;
} turn[] =
{
- { 0, 0, 0 },
+ { 0, 0, 0 },
{ MV_DOWN, MV_UP, MV_RIGHT },
- { MV_UP, MV_DOWN, MV_LEFT },
- { 0, 0, 0 },
- { MV_LEFT, MV_RIGHT, MV_DOWN },
- { 0,0,0 }, { 0,0,0 }, { 0,0,0 },
- { MV_RIGHT, MV_LEFT, MV_UP }
+ { MV_UP, MV_DOWN, MV_LEFT },
+ { 0, 0, 0 },
+ { MV_LEFT, MV_RIGHT, MV_DOWN },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { 0, 0, 0 },
+ { MV_RIGHT, MV_LEFT, MV_UP }
};
int element = Tile[x][y];
// now make next step
- Moving2Blocked_MM(x, y, &newx, &newy); // get next screen position
+ Moving2Blocked(x, y, &newx, &newy); // get next screen position
if (element == EL_PACMAN &&
IN_LEV_FIELD(newx, newy) && IS_EATABLE4PACMAN(Tile[newx][newy]) &&
}
else if (IS_MCDUFFIN(element))
{
- if (!laser.fuse_off)
- {
- DrawLaser(0, DL_LASER_DISABLED);
+ boolean has_laser = (x == laser.start_edge.x && y == laser.start_edge.y);
- /*
- BackToFront();
- */
- }
+ if (has_laser && !laser.fuse_off)
+ DrawLaser(0, DL_LASER_DISABLED);
element = get_rotated_element(element, BUTTON_ROTATION(button));
- laser.start_angle = get_element_angle(element);
-
- InitLaser();
Tile[x][y] = element;
DrawField_MM(x, y);
- /*
- BackToFront();
- */
+ if (has_laser)
+ {
+ laser.start_angle = get_element_angle(element);
- if (!laser.fuse_off)
- ScanLaser();
+ InitLaser();
+
+ if (!laser.fuse_off)
+ ScanLaser();
+ }
element_clicked = TRUE;
}
return element_clicked;
}
-void RotateMirror(int x, int y, int button)
+static void RotateMirror(int x, int y, int button)
{
if (button == MB_RELEASED)
{
IS_GRID_WOOD_AUTO(element) ||
IS_GRID_STEEL_AUTO(element) ||
element == EL_REFRACTOR)
+ {
RotateMirror(x, y, MB_RIGHTBUTTON);
+
+ laser.redraw = TRUE;
+ }
}
}
}
-boolean ObjHit(int obx, int oby, int bits)
+static boolean ObjHit(int obx, int oby, int bits)
{
int i;
return FALSE;
}
-void DeletePacMan(int px, int py)
+static void DeletePacMan(int px, int py)
{
int i, j;
}
}
-void ColorCycling(void)
-{
- static int CC, Cc = 0;
-
- static int color, old = 0xF00, new = 0x010, mult = 1;
- static unsigned short red, green, blue;
-
- if (color_status == STATIC_COLORS)
- return;
-
- CC = FrameCounter;
-
- if (CC < Cc || CC > Cc + 2)
- {
- Cc = CC;
-
- color = old + new * mult;
- if (mult > 0)
- mult++;
- else
- mult--;
-
- if (ABS(mult) == 16)
- {
- mult =- mult / 16;
- old = color;
- new = new << 4;
-
- if (new > 0x100)
- new = 0x001;
- }
-
- red = 0x0e00 * ((color & 0xF00) >> 8);
- green = 0x0e00 * ((color & 0x0F0) >> 4);
- blue = 0x0e00 * ((color & 0x00F));
- SetRGB(pen_magicolor[0], red, green, blue);
-
- red = 0x1111 * ((color & 0xF00) >> 8);
- green = 0x1111 * ((color & 0x0F0) >> 4);
- blue = 0x1111 * ((color & 0x00F));
- SetRGB(pen_magicolor[1], red, green, blue);
- }
-}
-
static void GameActions_MM_Ext(void)
{
int element;
else if (element == EL_EXIT_OPENING)
OpenExit(x, y);
else if (element == EL_GRAY_BALL_OPENING)
- OpenSurpriseBall(x, y);
+ OpenGrayBall(x, y);
else if (IS_ENVELOPE_OPENING(element))
OpenEnvelope(x, y);
- else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_ICE)
+ else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_ICE_BASE)
MeltIce(x, y);
- else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_AMOEBA)
+ else if (IS_WALL_CHANGING(element) && Store[x][y] == EL_WALL_AMOEBA_BASE)
GrowAmoeba(x, y);
else if (IS_MIRROR(element) ||
IS_MIRROR_FIXED(element) ||
element == EL_PRISM)
DrawFieldTwinkle(x, y);
- else if (element == EL_GRAY_BALL_OPENING ||
+ else if (element == EL_GRAY_BALL_ACTIVE ||
element == EL_BOMB_ACTIVE ||
element == EL_MINE_ACTIVE)
DrawFieldAnimated_MM(x, y);
element != EL_BOMB_ACTIVE &&
element != EL_MINE &&
element != EL_MINE_ACTIVE &&
- element != EL_BALL_GRAY &&
+ element != EL_GRAY_BALL &&
+ element != EL_GRAY_BALL_ACTIVE &&
element != EL_BLOCK_STONE &&
element != EL_BLOCK_WOOD &&
element != EL_FUSE_ON &&
else
PlaySound_MM(SND_MM_GAME_HEALTH_CHARGING);
- if (laser.overloaded)
- {
-#if 0
- BlitBitmap(pix[PIX_DOOR], drawto,
- DOOR_GFX_PAGEX4 + XX_OVERLOAD,
- DOOR_GFX_PAGEY1 + YY_OVERLOAD + OVERLOAD_YSIZE
- - laser.overload_value,
- OVERLOAD_XSIZE, laser.overload_value,
- DX_OVERLOAD, DY_OVERLOAD + OVERLOAD_YSIZE
- - laser.overload_value);
-#endif
- redraw_mask |= REDRAW_DOOR_1;
- }
- else
- {
-#if 0
- BlitBitmap(pix[PIX_DOOR], drawto,
- DOOR_GFX_PAGEX5 + XX_OVERLOAD, DOOR_GFX_PAGEY1 + YY_OVERLOAD,
- OVERLOAD_XSIZE, OVERLOAD_YSIZE - laser.overload_value,
- DX_OVERLOAD, DY_OVERLOAD);
-#endif
- redraw_mask |= REDRAW_DOOR_1;
- }
-
if (laser.overload_value == MAX_LASER_OVERLOAD)
{
UpdateAndDisplayGameControlValues();
DrawGraphic_MM(ELX, ELY, IMG_MM_FUSE);
}
- if (element == EL_BALL_GRAY && CT > native_mm_level.time_ball)
+ if (element == EL_GRAY_BALL && CT > native_mm_level.time_ball)
{
if (!Store2[ELX][ELY]) // check if content element not yet determined
{
game_mm.ball_choice_pos++;
int new_element = native_mm_level.ball_content[element_pos];
+ int new_element_base = map_wall_to_base_element(new_element);
- // randomly rotate newly created game element, if needed
- if (native_mm_level.rotate_ball_content)
+ if (IS_WALL(new_element_base))
+ {
+ // always use completely filled wall element
+ new_element = new_element_base | 0x000f;
+ }
+ else if (native_mm_level.rotate_ball_content &&
+ get_num_elements(new_element) > 1)
+ {
+ // randomly rotate newly created game element
new_element = get_rotated_element(new_element, RND(16));
+ }
Store[ELX][ELY] = new_element;
Store2[ELX][ELY] = TRUE;
}
- Tile[ELX][ELY] = EL_GRAY_BALL_OPENING;
-
- // !!! CHECK AGAIN: Laser on Polarizer !!!
- ScanLaser();
-
- laser.dest_element_last = Tile[ELX][ELY];
- laser.dest_element_last_x = ELX;
- laser.dest_element_last_y = ELY;
-
- return;
-
-#if 0
- int graphic;
-
- switch (RND(5))
- {
- case 0:
- element = EL_MIRROR_START + RND(16);
- break;
- case 1:
- {
- int rnd = RND(3);
-
- element = (rnd == 0 ? EL_KETTLE : rnd == 1 ? EL_BOMB : EL_PRISM);
- }
- break;
- default:
- {
- int rnd = RND(3);
-
- element = (rnd == 0 ? EL_FUSE_ON :
- rnd >= 1 && rnd <= 4 ? EL_PACMAN_RIGHT + rnd - 1 :
- rnd >= 5 && rnd <= 20 ? EL_POLAR_START + rnd - 5 :
- rnd >= 21 && rnd <= 24 ? EL_POLAR_CROSS_START + rnd - 21 :
- EL_MIRROR_FIXED_START + rnd - 25);
- }
- break;
- }
-
- graphic = el2gfx(element);
-
- for (i = 0; i < 50; i++)
- {
- int x = RND(26);
- int y = RND(26);
-
-#if 0
- BlitBitmap(pix[PIX_BACK], drawto,
- SX + (graphic % GFX_PER_LINE) * TILEX + x,
- SY + (graphic / GFX_PER_LINE) * TILEY + y, 6, 6,
- SX + ELX * TILEX + x,
- SY + ELY * TILEY + y);
-#endif
- MarkTileDirty(ELX, ELY);
- BackToFront();
-
- DrawLaser(0, DL_LASER_ENABLED);
-
- Delay_WithScreenUpdates(50);
- }
-
- Tile[ELX][ELY] = element;
- DrawField_MM(ELX, ELY);
-
-#if 0
- Debug("game:mm:GameActions_MM_Ext", "NEW ELEMENT: (%d, %d)", ELX, ELY);
-#endif
-
- // above stuff: GRAY BALL -> PRISM !!!
-/*
- LX = ELX * TILEX + 14;
- LY = ELY * TILEY + 14;
- if (laser.current_angle == (laser.current_angle >> 1) << 1)
- OK = 8;
- else
- OK = 4;
- LX -= OK * XS;
- LY -= OK * YS;
-
- laser.num_edges -= 2;
- laser.num_damages--;
-*/
-
-#if 0
- for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i>=0; i--)
- if (laser.damage[i].is_mirror)
- break;
-
- if (i > 0)
- DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED);
+ if (native_mm_level.explode_ball)
+ Bang_MM(ELX, ELY);
else
- DrawLaser(0, DL_LASER_DISABLED);
-#else
- DrawLaser(0, DL_LASER_DISABLED);
-#endif
+ Tile[ELX][ELY] = EL_GRAY_BALL_OPENING;
- ScanLaser();
-#endif
+ laser.dest_element = laser.dest_element_last = Tile[ELX][ELY];
return;
}
{
PlayLevelSound_MM(ELX, ELY, element, MM_ACTION_SHRINKING);
- {
- Tile[ELX][ELY] = Tile[ELX][ELY] - EL_WALL_ICE + EL_WALL_CHANGING;
- Store[ELX][ELY] = EL_WALL_ICE;
- Store2[ELX][ELY] = laser.wall_mask;
-
- laser.dest_element = Tile[ELX][ELY];
-
- return;
- }
-
- for (i = 0; i < 5; i++)
- {
- int phase = i + 1;
-
- if (i == 4)
- {
- Tile[ELX][ELY] &= (laser.wall_mask ^ 0xFF);
- phase = 0;
- }
-
- DrawWallsAnimation_MM(ELX, ELY, Tile[ELX][ELY], phase, laser.wall_mask);
- BackToFront();
- Delay_WithScreenUpdates(100);
- }
-
- if (Tile[ELX][ELY] == EL_WALL_ICE)
- Tile[ELX][ELY] = EL_EMPTY;
-
-/*
- laser.num_edges--;
- LX = laser.edge[laser.num_edges].x - cSX2;
- LY = laser.edge[laser.num_edges].y - cSY2;
-*/
-
- for (i = (laser.num_damages > 0 ? laser.num_damages - 1 : 0); i >= 0; i--)
- if (laser.damage[i].is_mirror)
- break;
-
- if (i > 0)
- DrawLaser(laser.damage[i].edge - 1, DL_LASER_DISABLED);
- else
- DrawLaser(0, DL_LASER_DISABLED);
+ Tile[ELX][ELY] = Tile[ELX][ELY] - EL_WALL_ICE_BASE + EL_WALL_CHANGING_BASE;
+ Store[ELX][ELY] = EL_WALL_ICE_BASE;
+ Store2[ELX][ELY] = laser.wall_mask;
- ScanLaser();
+ laser.dest_element = Tile[ELX][ELY];
return;
}
if (IS_WALL_AMOEBA(element) && CT > 60)
{
- int k1, k2, k3, dx, dy, de, dm;
+ int k1, k2, k3;
int element2 = Tile[ELX][ELY];
if (element2 != EL_EMPTY && !IS_WALL_AMOEBA(element))
Tile[ELX][ELY] = element | laser.wall_mask;
- dx = ELX;
- dy = ELY;
- de = Tile[ELX][ELY];
- dm = laser.wall_mask;
-
-#if 1
- {
- int x = ELX, y = ELY;
- int wall_mask = laser.wall_mask;
-
- ScanLaser();
- DrawLaser(0, DL_LASER_ENABLED);
+ int x = ELX, y = ELY;
+ int wall_mask = laser.wall_mask;
- PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING);
-
- Tile[x][y] = Tile[x][y] - EL_WALL_AMOEBA + EL_WALL_CHANGING;
- Store[x][y] = EL_WALL_AMOEBA;
- Store2[x][y] = wall_mask;
-
- return;
- }
-#endif
-
- DrawWallsAnimation_MM(dx, dy, de, 4, dm);
ScanLaser();
DrawLaser(0, DL_LASER_ENABLED);
- PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING);
+ PlayLevelSound_MM(x, y, element, MM_ACTION_GROWING);
- for (i = 4; i >= 0; i--)
- {
- DrawWallsAnimation_MM(dx, dy, de, i, dm);
-
- BackToFront();
- Delay_WithScreenUpdates(20);
- }
-
- DrawLaser(0, DL_LASER_ENABLED);
+ Tile[x][y] = Tile[x][y] - EL_WALL_AMOEBA_BASE + EL_WALL_CHANGING_BASE;
+ Store[x][y] = EL_WALL_AMOEBA_BASE;
+ Store2[x][y] = wall_mask;
return;
}
UpdateAndDisplayGameControlValues();
- BackToFront();
+ BackToFront_MM();
}
Tile[ELX][ELY] = laser.dest_element = EL_FUEL_EMPTY;
return;
}
-
- return;
}
void GameActions_MM(struct MouseActionInfo action)
CheckSingleStepMode_MM(element_clicked, button_released);
}
-void MovePacMen(void)
+static void MovePacMen(void)
{
int mx, my, ox, oy, nx, ny;
int element;
}
DrawField_MM(nx, ny);
- BackToFront();
+ BackToFront_MM();
if (!laser.fuse_off)
{
Tile[newx][newy] = EL_BLOCKED;
}
-static void Moving2Blocked_MM(int x, int y, int *goes_to_x, int *goes_to_y)
-{
- int direction = MovDir[x][y];
- int newx = x + (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
- int newy = y + (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
-
- *goes_to_x = newx;
- *goes_to_y = newy;
-}
-
-static void Blocked2Moving_MM(int x, int y,
- int *comes_from_x, int *comes_from_y)
-{
- int oldx = x, oldy = y;
- int direction = MovDir[x][y];
-
- if (direction == MV_LEFT)
- oldx++;
- else if (direction == MV_RIGHT)
- oldx--;
- else if (direction == MV_UP)
- oldy++;
- else if (direction == MV_DOWN)
- oldy--;
-
- *comes_from_x = oldx;
- *comes_from_y = oldy;
-}
-
static int MovingOrBlocked2Element_MM(int x, int y)
{
int element = Tile[x][y];
{
int oldx, oldy;
- Blocked2Moving_MM(x, y, &oldx, &oldy);
+ Blocked2Moving(x, y, &oldx, &oldy);
return Tile[oldx][oldy];
}
return element;
}
-#if 0
-static void RemoveField(int x, int y)
-{
- Tile[x][y] = EL_EMPTY;
- MovPos[x][y] = 0;
- MovDir[x][y] = 0;
- MovDelay[x][y] = 0;
-}
-#endif
-
static void RemoveMovingField_MM(int x, int y)
{
int oldx = x, oldy = y, newx = x, newy = y;
if (IS_MOVING(x, y))
{
- Moving2Blocked_MM(x, y, &newx, &newy);
+ Moving2Blocked(x, y, &newx, &newy);
if (Tile[newx][newy] != EL_BLOCKED)
return;
}
else if (Tile[x][y] == EL_BLOCKED)
{
- Blocked2Moving_MM(x, y, &oldx, &oldy);
+ Blocked2Moving(x, y, &oldx, &oldy);
if (!IS_MOVING(oldx, oldy))
return;
}
DrawLevelField_MM(newx, newy);
}
-void PlaySoundLevel(int x, int y, int sound_nr)
-{
- int sx = SCREENX(x), sy = SCREENY(y);
- int volume, stereo;
- int silence_distance = 8;
-
- if ((!setup.sound_simple && !IS_LOOP_SOUND(sound_nr)) ||
- (!setup.sound_loops && IS_LOOP_SOUND(sound_nr)))
- return;
-
- if (!IN_LEV_FIELD(x, y) ||
- sx < -silence_distance || sx >= SCR_FIELDX+silence_distance ||
- sy < -silence_distance || sy >= SCR_FIELDY+silence_distance)
- return;
-
- volume = SOUND_MAX_VOLUME;
-
-#ifndef MSDOS
- stereo = (sx - SCR_FIELDX/2) * 12;
-#else
- stereo = SOUND_MIDDLE + (2 * sx - (SCR_FIELDX - 1)) * 5;
- if (stereo > SOUND_MAX_RIGHT)
- stereo = SOUND_MAX_RIGHT;
- if (stereo < SOUND_MAX_LEFT)
- stereo = SOUND_MAX_LEFT;
-#endif
-
- if (!IN_SCR_FIELD(sx, sy))
- {
- int dx = ABS(sx - SCR_FIELDX/2) - SCR_FIELDX/2;
- int dy = ABS(sy - SCR_FIELDY/2) - SCR_FIELDY/2;
-
- volume -= volume * (dx > dy ? dx : dy) / silence_distance;
- }
-
- PlaySoundExt(sound_nr, volume, stereo, SND_CTRL_PLAY_SOUND);
-}
-
static void RaiseScore_MM(int value)
{
game_mm.score += value;