X-Git-Url: https://git.artsoft.org/?a=blobdiff_plain;f=src%2Fgame_mm%2Fmm_game.c;h=8cc08bc47527ed8dd825ac912233a32b631f4d93;hb=c2507c62924b560ab4c0ad7330cd78fc562f16ce;hp=81bbe9d0ea577d63477bbf35129774f7687f19c2;hpb=049c39daf10cc5080e5e25a8d87ea3e8d8b26b50;p=rocksndiamonds.git diff --git a/src/game_mm/mm_game.c b/src/game_mm/mm_game.c index 81bbe9d0..8cc08bc4 100644 --- a/src/game_mm/mm_game.c +++ b/src/game_mm/mm_game.c @@ -570,6 +570,8 @@ static void InitField(int x, int y, boolean init_game) 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; @@ -662,6 +664,7 @@ void InitGameEngine_MM(void) 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; @@ -809,6 +812,10 @@ static void GameOver_MM(int game_over_cause) game_mm.game_over = TRUE; game_mm.game_over_cause = game_over_cause; + // do not ask to play again if game was never actually played + if (!game.GamePlayed) + return; + if (setup.ask_on_game_over) game.restart_game_message = (game_over_cause == GAME_OVER_BOMB ? "Bomb killed Mc Duffin! Play it again?" : @@ -909,6 +916,26 @@ static int ScanPixel(void) } #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; @@ -1049,24 +1076,51 @@ static void ScanLaser(void) 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 @@ -1975,10 +2029,16 @@ static boolean HitPolarizer(int element, int hit_mask) } 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); } @@ -2028,11 +2088,9 @@ static boolean HitBlock(int element, int 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); @@ -2071,11 +2129,9 @@ static boolean HitBlock(int element, int hit_mask) 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); @@ -2405,10 +2461,18 @@ static boolean HitAbsorbingWalls(int element, int hit_mask) 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)) @@ -2710,12 +2774,13 @@ static void Explode_MM(int x, int y, int phase, int mode) 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)) { @@ -2726,12 +2791,14 @@ static void Explode_MM(int x, int y, int phase, int mode) 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); @@ -2747,7 +2814,9 @@ static void Explode_MM(int x, int y, int phase, int mode) 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; @@ -2757,7 +2826,7 @@ static void Explode_MM(int x, int y, int phase, int mode) if (phase == last_phase) { - if (Store[x][y] == EL_BOMB_ACTIVE) + if (center_element == EL_BOMB_ACTIVE) { DrawLaser(0, DL_LASER_DISABLED); InitLaser(); @@ -2768,18 +2837,21 @@ static void Explode_MM(int x, int y, int phase, int mode) 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))) { @@ -3494,9 +3566,12 @@ static void GameActions_MM_Ext(void) 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; }