}
}
-static void InitField(int x, int y)
+static void InitField(int x, int y, boolean init_game)
{
int element = Tile[x][y];
case EL_KETTLE:
case EL_CELL:
- if (native_mm_level.auto_count_kettles)
+ if (init_game && native_mm_level.auto_count_kettles)
game_mm.kettles_still_needed++;
break;
}
else if (IS_MCDUFFIN(element) || IS_LASER(element))
{
- laser.start_edge.x = x;
- laser.start_edge.y = y;
- laser.start_angle = get_element_angle(element);
+ if (init_game)
+ {
+ laser.start_edge.x = x;
+ laser.start_edge.y = y;
+ laser.start_angle = get_element_angle(element);
+ }
if (IS_MCDUFFIN(element))
{
Store[x][y] = Store2[x][y] = 0;
Stop[x][y] = FALSE;
- InitField(x, y);
+ InitField(x, y, TRUE);
}
}
BackToFront();
- ColorCycling();
-
#ifdef DEBUG
if (setup.quick_doors)
continue;
{
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;
#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;
// this is more precise: check if laser would go through the center
if ((ELX * TILEX + 14 - LX) * YS != (ELY * TILEY + 14 - LY) * XS)
{
+ 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 (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);
laser.dest_element_last = Tile[ELX][ELY];
laser.dest_element_last_x = ELX;
}
}
-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, 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,
cSX + x * TILEX + dx, cSY + y * TILEY + dy);
{
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);
- ScanLaser();
+ ScanLaser_FromLastMirror();
}
}
}
if (!MovDelay[x][y])
{
- int i;
-
Tile[x][y] = real_element & (wall_mask ^ 0xFF);
Store[x][y] = Store2[x][y] = 0;
if (Tile[x][y] == EL_WALL_ICE)
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))
{
Tile[x][y] = center_element;
}
- if (center_element == EL_BOMB_ACTIVE || IS_MCDUFFIN(center_element))
- Store[x][y] = center_element;
- else
- Store[x][y] = EL_EMPTY;
-
+ Store[x][y] = center_element;
Store2[x][y] = mode;
Tile[x][y] = EL_EXPLODING_OPAQUE;
- GfxElement[x][y] = center_element;
+
+ GfxElement[x][y] = (center_element == EL_BOMB_ACTIVE ? EL_BOMB :
+ IS_MCDUFFIN(center_element) ? EL_MCDUFFIN :
+ center_element);
MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
InitLaser();
Bang_MM(laser.start_edge.x, laser.start_edge.y);
- Store[x][y] = EL_EMPTY;
GameOver_MM(GAME_OVER_DELAYED);
}
else if (IS_MCDUFFIN(Store[x][y]))
{
- Store[x][y] = EL_EMPTY;
-
GameOver_MM(GAME_OVER_BOMB);
}
- Tile[x][y] = Store[x][y];
+ Tile[x][y] = EL_EMPTY;
+
Store[x][y] = Store2[x][y] = 0;
MovDir[x][y] = MovPos[x][y] = MovDelay[x][y] = 0;
- InitField(x, y);
+ InitField(x, y, FALSE);
DrawField_MM(x, y);
}
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))
}
}
-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)
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_unmapped = unmap_element(new_element);
- // randomly rotate newly created game element, if needed
- if (native_mm_level.rotate_ball_content)
+ if (IS_WALL(new_element_unmapped))
+ {
+ // always use completely filled wall element
+ new_element = new_element_unmapped | 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);
- else
- DrawLaser(0, DL_LASER_DISABLED);
-#else
- DrawLaser(0, DL_LASER_DISABLED);
-#endif
-
- ScanLaser();
-#endif
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);
- }
+ Tile[ELX][ELY] = Tile[ELX][ELY] - EL_WALL_ICE + EL_WALL_CHANGING;
+ Store[ELX][ELY] = EL_WALL_ICE;
+ Store2[ELX][ELY] = laser.wall_mask;
- 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);
-
- 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);
-
- 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
+ int x = ELX, y = ELY;
+ int wall_mask = laser.wall_mask;
- DrawWallsAnimation_MM(dx, dy, de, 4, dm);
ScanLaser();
DrawLaser(0, DL_LASER_ENABLED);
- PlayLevelSound_MM(dx, dy, element, MM_ACTION_GROWING);
-
- for (i = 4; i >= 0; i--)
- {
- DrawWallsAnimation_MM(dx, dy, de, i, dm);
-
- BackToFront();
- Delay_WithScreenUpdates(20);
- }
+ PlayLevelSound_MM(x, y, element, MM_ACTION_GROWING);
- DrawLaser(0, DL_LASER_ENABLED);
+ Tile[x][y] = Tile[x][y] - EL_WALL_AMOEBA + EL_WALL_CHANGING;
+ Store[x][y] = EL_WALL_AMOEBA;
+ Store2[x][y] = wall_mask;
return;
}
return;
}
-
- return;
}
void GameActions_MM(struct MouseActionInfo action)
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;
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;