// values for Explode_MM()
#define EX_PHASE_START 0
-#define EX_NORMAL 0
-#define EX_KETTLE 1
-#define EX_SHORT 2
+#define EX_TYPE_NONE 0
+#define EX_TYPE_NORMAL (1 << 0)
// special positions in the game control window (relative to control window)
#define XX_LEVEL 36
static DelayCounter energy_delay = { ENERGY_DELAY };
static DelayCounter overload_delay = { 0 };
+// element mask positions for scanning pixels of MM elements
+#define MM_MASK_MCDUFFIN_RIGHT 0
+#define MM_MASK_MCDUFFIN_UP 1
+#define MM_MASK_MCDUFFIN_LEFT 2
+#define MM_MASK_MCDUFFIN_DOWN 3
+#define MM_MASK_GRID_1 4
+#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 NUM_MM_MASKS 10
+
// element masks for scanning pixels of MM elements
-static const char mm_masks[10][16][16 + 1] =
+static const char mm_masks[NUM_MM_MASKS][16][16 + 1] =
{
{
" ",
PlayLevelSound_MM(exit_x, exit_y, exit_element, MM_ACTION_OPENING);
}
+static void SetLaserColor(int brightness)
+{
+ int color_min = 0x00;
+ int color_max = brightness; // (0x00 <= brightness <= 0xFF)
+ int color_up = color_max * laser.overload_value / MAX_LASER_OVERLOAD;
+ int color_down = color_max - color_up;
+
+ pen_ray =
+ GetPixelFromRGB(window,
+ (native_mm_level.laser_red ? color_max : color_up),
+ (native_mm_level.laser_green ? color_down : color_min),
+ (native_mm_level.laser_blue ? color_down : color_min));
+}
+
static void InitMovDir_MM(int x, int y)
{
int element = Tile[x][y];
AddLaserEdge(LX, LY); // set laser starting edge
- pen_ray = GetPixelFromRGB(window,
- native_mm_level.laser_red * 0xFF,
- native_mm_level.laser_green * 0xFF,
- native_mm_level.laser_blue * 0xFF);
+ SetLaserColor(0xFF);
}
void InitGameEngine_MM(void)
Angle[x][y] = 0;
MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
Store[x][y] = Store2[x][y] = 0;
- Frame[x][y] = 0;
Stop[x][y] = FALSE;
InitField(x, y);
SetTileCursorXY(laser.start_edge.x, laser.start_edge.y);
SetTileCursorActive(TRUE);
+
+ ResetFrameCounter(&energy_delay);
+}
+
+static void FadeOutLaser(void)
+{
+ int i;
+
+ for (i = 15; i >= 0; i--)
+ {
+ SetLaserColor(0x11 * i);
+
+ DrawLaser(0, DL_LASER_ENABLED);
+
+ BackToFront();
+ Delay_WithScreenUpdates(50);
+ }
+
+ DrawLaser(0, DL_LASER_DISABLED);
+
+ StopSound_MM(SND_MM_GAME_HEALTH_CHARGING);
+}
+
+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);
+
+ SetTileCursorActive(FALSE);
}
void AddLaserEdge(int lx, int ly)
static int getMaskFromElement(int element)
{
if (IS_GRID(element))
- return IMG_MM_MASK_GRID_1 + get_element_phase(element);
+ return MM_MASK_GRID_1 + get_element_phase(element);
else if (IS_MCDUFFIN(element))
- return IMG_MM_MASK_MCDUFFIN_RIGHT + get_element_phase(element);
+ return MM_MASK_MCDUFFIN_RIGHT + get_element_phase(element);
else if (IS_RECTANGLE(element) || IS_DF_GRID(element))
- return IMG_MM_MASK_RECTANGLE;
+ return MM_MASK_RECTANGLE;
else
- return IMG_MM_MASK_CIRCLE;
+ return MM_MASK_CIRCLE;
}
static int ScanPixel(void)
}
else
{
- int pos = getMaskFromElement(element) - IMG_MM_MASK_MCDUFFIN_RIGHT;
+ int pos = getMaskFromElement(element);
pixel = (mm_masks[pos][dy / 2][dx / 2] == 'X' ? 1 : 0);
}
Store[x][y] = EL_EMPTY;
Store2[x][y] = mode;
+
Tile[x][y] = EL_EXPLODING_OPAQUE;
+ GfxElement[x][y] = center_element;
+
MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
- Frame[x][y] = 1;
+
+ ExplodePhase[x][y] = 1;
return;
}
- Frame[x][y] = (phase < last_phase ? phase + 1 : 0);
+ if (phase == 1)
+ GfxFrame[x][y] = 0; // restart explosion animation
+
+ ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
if (phase == half_phase)
{
Bang_MM(laser.start_edge.x, laser.start_edge.y);
Store[x][y] = EL_EMPTY;
- game_mm.game_over = TRUE;
- game_mm.game_over_cause = GAME_OVER_BOMB;
-
- SetTileCursorActive(FALSE);
+ GameOver_MM(GAME_OVER_DELAYED);
laser.overloaded = FALSE;
}
{
Store[x][y] = EL_EMPTY;
- game.restart_game_message = "Bomb killed Mc Duffin! Play it again?";
+ GameOver_MM(GAME_OVER_BOMB);
}
Tile[x][y] = Store[x][y];
}
else if (!(phase % delay) && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
- int graphic = IMG_MM_DEFAULT_EXPLODING;
- int graphic_phase = (phase / delay - 1);
- Bitmap *bitmap;
- int src_x, src_y;
+ int graphic = el_act2gfx(GfxElement[x][y], MM_ACTION_EXPLODING);
+ int frame = getGraphicAnimationFrameXY(graphic, x, y);
- if (Store2[x][y] == EX_KETTLE)
- {
- if (graphic_phase < 3)
- {
- graphic = IMG_MM_KETTLE_EXPLODING;
- }
- else if (graphic_phase < 5)
- {
- graphic_phase += 3;
- }
- else
- {
- graphic = IMG_EMPTY;
- graphic_phase = 0;
- }
- }
- else if (Store2[x][y] == EX_SHORT)
- {
- if (graphic_phase < 4)
- {
- graphic_phase += 4;
- }
- else
- {
- graphic = IMG_EMPTY;
- graphic_phase = 0;
- }
- }
-
- getGraphicSource(graphic, graphic_phase, &bitmap, &src_x, &src_y);
-
- BlitBitmap(bitmap, drawto_field, src_x, src_y, TILEX, TILEY,
- cFX + x * TILEX, cFY + y * TILEY);
+ DrawGraphicAnimation_MM(x, y, graphic, frame);
MarkTileDirty(x, y);
}
static void Bang_MM(int x, int y)
{
int element = Tile[x][y];
- int mode = EX_NORMAL;
#if 0
DrawLaser(0, DL_LASER_ENABLED);
#endif
- switch (element)
- {
- case EL_KETTLE:
- mode = EX_KETTLE;
- break;
-
- case EL_GATE_STONE:
- case EL_GATE_WOOD:
- mode = EX_SHORT;
- break;
-
- default:
- mode = EX_NORMAL;
- break;
- }
-
if (IS_PACMAN(element))
PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
else if (element == EL_BOMB || IS_MCDUFFIN(element))
else
PlayLevelSound_MM(x, y, element, MM_ACTION_EXPLODING);
- Explode_MM(x, y, EX_PHASE_START, mode);
+ Explode_MM(x, y, EX_PHASE_START, EX_TYPE_NORMAL);
}
void TurnRound(int x, int y)
LX, LY, laser.beamer_edge, laser.beamer[1].num);
#endif
+#if 0
laser.num_edges--;
+#endif
}
ScanLaser();
else if (IS_MOVING(x, y))
ContinueMoving_MM(x, y);
else if (IS_EXPLODING(element))
- Explode_MM(x, y, Frame[x][y], EX_NORMAL);
+ Explode_MM(x, y, ExplodePhase[x][y], EX_TYPE_NORMAL);
else if (element == EL_EXIT_OPENING)
OpenExit(x, y);
else if (element == EL_GRAY_BALL_OPENING)
}
}
- if (FrameReached(&energy_delay))
- {
- if (game_mm.energy_left > 0)
- {
- game_mm.energy_left--;
-
- redraw_mask |= REDRAW_DOOR_1;
- }
- else if (game.time_limit && !game_mm.game_over)
- {
- int i;
-
- for (i = 15; i >= 0; i--)
- {
-#if 0
- SetRGB(pen_ray, 0x0000, 0x0000, i * color_scale);
-#endif
- pen_ray = GetPixelFromRGB(window,
- native_mm_level.laser_red * 0x11 * i,
- native_mm_level.laser_green * 0x11 * i,
- native_mm_level.laser_blue * 0x11 * i);
-
- DrawLaser(0, DL_LASER_ENABLED);
- BackToFront();
- Delay_WithScreenUpdates(50);
- }
+ // skip all following game actions if game is over
+ if (game_mm.game_over)
+ return;
- StopSound_MM(SND_MM_GAME_HEALTH_CHARGING);
-#if 0
- FadeMusic();
-#endif
+ if (game_mm.energy_left == 0 && !game.no_level_time_limit && game.time_limit)
+ {
+ FadeOutLaser();
- DrawLaser(0, DL_LASER_DISABLED);
- game_mm.game_over = TRUE;
- game_mm.game_over_cause = GAME_OVER_NO_ENERGY;
+ GameOver_MM(GAME_OVER_NO_ENERGY);
- SetTileCursorActive(FALSE);
+ return;
+ }
- game.restart_game_message = "Out of magic energy! Play it again?";
+ if (FrameReached(&energy_delay))
+ {
+ if (game_mm.energy_left > 0)
+ game_mm.energy_left--;
- return;
- }
+ // when out of energy, wait another frame to play "out of time" sound
}
element = laser.dest_element;
if (laser.overload_value < MAX_LASER_OVERLOAD - 8)
{
- int color_up = 0xFF * laser.overload_value / MAX_LASER_OVERLOAD;
- int color_down = 0xFF - color_up;
-
-#if 0
- SetRGB(pen_ray, (laser.overload_value / 6) * color_scale, 0x0000,
- (15 - (laser.overload_value / 6)) * color_scale);
-#endif
- pen_ray =
- GetPixelFromRGB(window,
- (native_mm_level.laser_red ? 0xFF : color_up),
- (native_mm_level.laser_green ? color_down : 0x00),
- (native_mm_level.laser_blue ? color_down : 0x00));
+ SetLaserColor(0xFF);
DrawLaser(0, DL_LASER_ENABLED);
}
if (laser.overload_value == MAX_LASER_OVERLOAD)
{
- int i;
-
UpdateAndDisplayGameControlValues();
- for (i = 15; i >= 0; i--)
- {
-#if 0
- SetRGB(pen_ray, i * color_scale, 0x0000, 0x0000);
-#endif
-
- pen_ray = GetPixelFromRGB(window, 0x11 * i, 0x00, 0x00);
-
- DrawLaser(0, DL_LASER_ENABLED);
- BackToFront();
- Delay_WithScreenUpdates(50);
- }
-
- DrawLaser(0, DL_LASER_DISABLED);
-
- game_mm.game_over = TRUE;
- game_mm.game_over_cause = GAME_OVER_OVERLOADED;
+ FadeOutLaser();
- SetTileCursorActive(FALSE);
-
- game.restart_game_message = "Magic spell hit Mc Duffin! Play it again?";
+ GameOver_MM(GAME_OVER_OVERLOADED);
return;
}
if (element == EL_FUEL_FULL && CT > 10)
{
- for (i = game_mm.energy_left; i <= MAX_LASER_ENERGY; i+=2)
+ int num_init_game_frames = INIT_GAME_ACTIONS_DELAY;
+ int start = num_init_game_frames * game_mm.energy_left / native_mm_level.time;
+
+ for (i = start; i <= num_init_game_frames; i++)
{
-#if 0
- BlitBitmap(pix[PIX_DOOR], drawto,
- DOOR_GFX_PAGEX4 + XX_ENERGY,
- DOOR_GFX_PAGEY1 + YY_ENERGY + ENERGY_YSIZE - i,
- ENERGY_XSIZE, i, DX_ENERGY,
- DY_ENERGY + ENERGY_YSIZE - i);
-#endif
+ if (i == num_init_game_frames)
+ StopSound_MM(SND_MM_GAME_LEVELTIME_CHARGING);
+ else if (setup.sound_loops)
+ PlaySoundLoop_MM(SND_MM_GAME_LEVELTIME_CHARGING);
+ else
+ PlaySound_MM(SND_MM_GAME_LEVELTIME_CHARGING);
- redraw_mask |= REDRAW_DOOR_1;
- BackToFront();
+ game_mm.energy_left = native_mm_level.time * i / num_init_game_frames;
- Delay_WithScreenUpdates(20);
+ UpdateAndDisplayGameControlValues();
+
+ BackToFront();
}
- game_mm.energy_left = MAX_LASER_ENERGY;
- Tile[ELX][ELY] = EL_FUEL_EMPTY;
+ Tile[ELX][ELY] = laser.dest_element = EL_FUEL_EMPTY;
+
DrawField_MM(ELX, ELY);
DrawLaser(0, DL_LASER_ENABLED);
engine_snapshot_mm.Hit[x][y] = Hit[x][y];
engine_snapshot_mm.Box[x][y] = Box[x][y];
engine_snapshot_mm.Angle[x][y] = Angle[x][y];
- engine_snapshot_mm.Frame[x][y] = Frame[x][y];
}
}
Hit[x][y] = engine_snapshot_mm.Hit[x][y];
Box[x][y] = engine_snapshot_mm.Box[x][y];
Angle[x][y] = engine_snapshot_mm.Angle[x][y];
- Frame[x][y] = engine_snapshot_mm.Frame[x][y];
}
}