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;
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;
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_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);
SetTileCursorActive(FALSE);
}
}
#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;
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;
- }
+ // 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);
- if (hit_mask == (HIT_MASK_TOPLEFT | HIT_MASK_BOTTOMRIGHT))
+ // 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);
+
+ // 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;
+ // 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
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;
laser.dest_element_last_y = ELY;
}
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);
}
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);
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))
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();
laser.overloaded = FALSE;
}
- else if (IS_MCDUFFIN(Store[x][y]))
+ else if (IS_MCDUFFIN(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)))
{
Store2[ELX][ELY] = TRUE;
}
- Tile[ELX][ELY] = EL_GRAY_BALL_OPENING;
+ if (native_mm_level.explode_ball)
+ Bang_MM(ELX, ELY);
+ else
+ Tile[ELX][ELY] = EL_GRAY_BALL_OPENING;
- laser.dest_element_last = Tile[ELX][ELY];
+ laser.dest_element = laser.dest_element_last = Tile[ELX][ELY];
return;
}