return MM_MASK_CIRCLE;
}
+static int getPixelFromMask(int pos, int dx, int dy)
+{
+ return (mm_masks[pos][dy / 2][dx / 2] == 'X' ? 1 : 0);
+}
+
static int getLevelFromLaserX(int x)
{
return x / TILEX - (x < 0 ? 1 : 0); // correct negative values
{
int pos = getMaskFromElement(element);
- pixel = (mm_masks[pos][dy / 2][dx / 2] == 'X' ? 1 : 0);
+ pixel = getPixelFromMask(pos, dx, dy);
}
}
else
break;
}
- boolean diagonally_adjacent_hit = FALSE;
-
// 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)
{
- diagonally_adjacent_hit = TRUE;
-
// compare the two diagonally adjacent elements
int xoffset = 2;
int yoffset = 2 * (diag_1 ? -1 : +1);
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))
{
if (IS_DF_SLOPE(element))
{
- int mirrored_angle = get_mirrored_angle(laser.current_angle,
- get_element_angle(element));
+ // 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));
+ int element_angle = get_element_angle(element);
+ int mirrored_angle = get_mirrored_angle(laser.current_angle, element_angle);
int opposite_angle = get_opposite_angle(laser.current_angle);
+ // check if wall (horizontal or vertical) side of slope was hit
+ if (hit_mask == HIT_MASK_LEFT ||
+ hit_mask == HIT_MASK_RIGHT ||
+ hit_mask == HIT_MASK_TOP ||
+ hit_mask == HIT_MASK_BOTTOM)
+ {
+ boolean hit_slope_corner_in_laser_direction =
+ ((hit_mask == HIT_MASK_LEFT && (element == EL_DF_SLOPE_01 ||
+ element == EL_DF_SLOPE_02)) ||
+ (hit_mask == HIT_MASK_RIGHT && (element == EL_DF_SLOPE_00 ||
+ element == EL_DF_SLOPE_03)) ||
+ (hit_mask == HIT_MASK_TOP && (element == EL_DF_SLOPE_02 ||
+ element == EL_DF_SLOPE_03)) ||
+ (hit_mask == HIT_MASK_BOTTOM && (element == EL_DF_SLOPE_00 ||
+ element == EL_DF_SLOPE_01)));
+
+ boolean hit_slope_corner_in_laser_direction_double_checked =
+ (cross_x && cross_y &&
+ laser.current_angle == mirrored_angle &&
+ hit_slope_corner_in_laser_direction);
+
+ // check special case of laser hitting the corner of a slope and another
+ // element (either wall or another slope), following the diagonal side
+ // of the slope which has the same angle as the direction of the laser
+ if (!hit_slope_corner_in_laser_direction_double_checked)
+ return HitReflectingWalls(element, hit_mask);
+ }
+
+ // check if an edge was hit while crossing element borders
+ if (cross_x && cross_y && get_number_of_bits(hit_mask) == 1)
+ {
+ // check both sides of potentially diagonal side of slope
+ int dx1 = (LX + XS) % TILEX;
+ int dy1 = (LY + YS) % TILEY;
+ int dx2 = (LX + XS + 2) % TILEX;
+ int dy2 = (LY + YS + 2) % TILEY;
+ int pos = getMaskFromElement(element);
+
+ // check if we are entering empty space area after hitting edge
+ if (!getPixelFromMask(pos, dx1, dy1) &&
+ !getPixelFromMask(pos, dx2, dy2))
+ {
+ // we already know that we hit an edge, but use this function to go on
+ if (HitOnlyAnEdge(hit_mask))
+ return FALSE;
+ }
+ }
+
// 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;
XS = 2 * Step[laser.current_angle].x;
YS = 2 * Step[laser.current_angle].y;
- if (!IS_22_5_ANGLE(laser.current_angle)) // 90° or 45° angle
- step_size = 8;
- else
- step_size = 4;
+ if (through_center)
+ {
+ // start from center position for all game elements but slope
+ if (!IS_22_5_ANGLE(laser.current_angle)) // 90° or 45° angle
+ step_size = 8;
+ else
+ step_size = 4;
- LX += step_size * XS;
- LY += step_size * YS;
+ LX += step_size * XS;
+ LY += step_size * YS;
+ }
+ else
+ {
+ // advance laser position until reaching the next tile (slopes)
+ while (LX / TILEX == ELX && (LX + 2) / TILEX == ELX &&
+ LY / TILEY == ELY && (LY + 2) / TILEY == ELY)
+ {
+ LX += XS;
+ LY += YS;
+ }
+ }
// draw sparkles on mirror
if ((IS_MIRROR(element) ||
{
int elx, ely;
- elx = getLevelFromLaserX(LX);
- ely = getLevelFromLaserY(LY);
+ elx = getLevelFromLaserX(LX + XS);
+ ely = getLevelFromLaserY(LY + YS);
if (IN_LEV_FIELD(elx, ely))
{
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 == 1 ? (XS > 0 ? TILEX : 0) :
+ nr == 2 ? (XS > 0 ? TILEX : 0) :
nr == 3 ? (XS > 0 ? TILEX - 1 : -1) : 0);
int dy = (nr == 0 ? (YS > 0 ? TILEY - 1 : -1) :
nr == 1 ? (YS > 0 ? TILEY - 1 : -1) :
{
int pos = getMaskFromElement(element_side);
- if (mm_masks[pos][dx / 2][dx / 2] == 'X')
+ if (getPixelFromMask(pos, dx, dy))
laser.overloaded = TRUE;
}
}