// (c) 1994-2017 by Artsoft Entertainment
// Holger Schemel
// info@artsoft.org
-// http://www.artsoft.org/
+// https://www.artsoft.org/
// ----------------------------------------------------------------------------
// mm_files.c
// ============================================================================
#include "mm_main.h"
-#define CHUNK_ID_LEN 4 /* IFF style chunk id length */
-#define CHUNK_SIZE_UNDEFINED 0 /* undefined chunk size == 0 */
-#define CHUNK_SIZE_NONE -1 /* do not write chunk size */
-#define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */
-#define LEVEL_HEADER_SIZE 80 /* size of level file header */
-#define LEVEL_HEADER_UNUSED 19 /* unused level header bytes */
+#define CHUNK_ID_LEN 4 // IFF style chunk id length
+#define CHUNK_SIZE_UNDEFINED 0 // undefined chunk size == 0
+#define CHUNK_SIZE_NONE -1 // do not write chunk size
+#define FILE_VERS_CHUNK_SIZE 8 // size of file version chunk
+#define LEVEL_HEADER_SIZE 80 // size of level file header
+#define LEVEL_HEADER_UNUSED 19 // unused level header bytes
-/* file identifier strings */
+// file identifier strings
#define LEVEL_COOKIE_TMPL "MIRRORMAGIC_LEVEL_FILE_VERSION_x.x"
#define SCORE_COOKIE "MIRRORMAGIC_SCORE_FILE_VERSION_1.4"
-/* ========================================================================= */
-/* level file functions */
-/* ========================================================================= */
+int default_score[LEVEL_SCORE_ELEMENTS] =
+{
+ [SC_COLLECTIBLE] = 10,
+ [SC_PACMAN] = 50,
+ [SC_KEY] = 10,
+ [SC_TIME_BONUS] = 1,
+ [SC_LIGHTBALL] = 10,
+};
+
+
+// ============================================================================
+// level file functions
+// ============================================================================
static void ReadChunk_MM_VERS(File *file, int *file_version, int *game_version)
{
file_version_major = getFile8Bit(file);
file_version_minor = getFile8Bit(file);
file_version_patch = getFile8Bit(file);
- getFile8Bit(file); /* not used */
+ getFile8Bit(file); // not used
game_version_major = getFile8Bit(file);
game_version_minor = getFile8Bit(file);
game_version_patch = getFile8Bit(file);
- getFile8Bit(file); /* not used */
+ getFile8Bit(file); // not used
*file_version = MM_VERSION_IDENT(file_version_major,
file_version_minor,
fputc(file_version_major, file);
fputc(file_version_minor, file);
fputc(file_version_patch, file);
- fputc(0, file); /* not used */
+ fputc(0, file); // not used
fputc(game_version_major, file);
fputc(game_version_minor, file);
fputc(game_version_patch, file);
- fputc(0, file); /* not used */
+ fputc(0, file); // not used
}
-void setLevelInfoToDefaults_MM()
+void setLevelInfoToDefaults_MM(void)
{
int i, x, y;
native_mm_level.file_version = MM_FILE_VERSION_ACTUAL;
native_mm_level.game_version = MM_GAME_VERSION_ACTUAL;
- native_mm_level.encoding_16bit_field = FALSE; /* default: only 8-bit elements */
+ native_mm_level.encoding_16bit_field = FALSE; // default: only 8-bit elements
- lev_fieldx = native_mm_level.fieldx = STD_LEV_FIELDX;
- lev_fieldy = native_mm_level.fieldy = STD_LEV_FIELDY;
+ native_mm_level.fieldx = STD_LEV_FIELDX;
+ native_mm_level.fieldy = STD_LEV_FIELDY;
for (x = 0; x < MAX_LEV_FIELDX; x++)
for (y = 0; y < MAX_LEV_FIELDY; y++)
- native_mm_level.field[x][y] = Feld[x][y] = Ur[x][y] = EL_EMPTY;
+ native_mm_level.field[x][y] = Ur[x][y] = EL_EMPTY;
native_mm_level.time = 100;
native_mm_level.kettles_needed = 0;
native_mm_level.auto_count_kettles = TRUE;
native_mm_level.amoeba_speed = 0;
- native_mm_level.time_fuse = 0;
- native_mm_level.laser_red = FALSE;
- native_mm_level.laser_green = FALSE;
- native_mm_level.laser_blue = TRUE;
+ native_mm_level.time_fuse = 25;
+ native_mm_level.time_bomb = 75;
+ native_mm_level.time_ball = 75;
+ native_mm_level.time_block = 75;
+ native_mm_level.mm_laser_red = FALSE;
+ native_mm_level.mm_laser_green = FALSE;
+ native_mm_level.mm_laser_blue = TRUE;
+ native_mm_level.df_laser_red = TRUE;
+ native_mm_level.df_laser_green = TRUE;
+ native_mm_level.df_laser_blue = FALSE;
for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
native_mm_level.name[i] = '\0';
for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
native_mm_level.score[i] = 10;
- native_mm_level.field[0][0] = Feld[0][0] = Ur[0][0] = EL_MCDUFFIN_RIGHT;
+ int ball_content[] =
+ {
+ EL_MIRROR_START,
+ EL_MIRROR_FIXED_START,
+ EL_POLAR_START,
+ EL_POLAR_CROSS_START,
+ EL_PACMAN_START,
+ EL_KETTLE,
+ EL_BOMB,
+ EL_PRISM
+ };
+ int num_ball_contents = sizeof(ball_content) / sizeof(int);
+
+ native_mm_level.num_ball_contents = num_ball_contents;
+ native_mm_level.ball_choice_mode = ANIM_RANDOM;
+
+ for (i = 0; i < num_ball_contents; i++)
+ native_mm_level.ball_content[i] = ball_content[i];
+
+ native_mm_level.field[0][0] = Ur[0][0] = EL_MCDUFFIN_RIGHT;
native_mm_level.field[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
- Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
}
{
if (element >= EL_FIRST_RUNTIME_EL)
{
- Error(ERR_WARN, "invalid level element %d", element);
+ Warn("invalid level element %d", element);
+
element = EL_CHAR_FRAGE;
}
int i;
int laser_color;
- lev_fieldx = level->fieldx = getFile8Bit(file);
- lev_fieldy = level->fieldy = getFile8Bit(file);
+ level->fieldx = getFile8Bit(file);
+ level->fieldy = getFile8Bit(file);
level->time = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
level->kettles_needed = getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN);
+ // one time unit was equivalent to four seconds in level files up to 2.0.x
+ if (level->file_version <= MM_FILE_VERSION_2_0)
+ level->time *= 4;
+
for (i = 0; i < MAX_LEVEL_NAME_LEN; i++)
level->name[i] = getFile8Bit(file);
level->name[MAX_LEVEL_NAME_LEN] = 0;
for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
level->score[i] = getFile8Bit(file);
+ // scores were 0 and hardcoded in game engine in level files up to 2.0.x
+ if (level->file_version <= MM_FILE_VERSION_2_0)
+ for (i = 0; i < LEVEL_SCORE_ELEMENTS; i++)
+ if (level->score[i] == 0)
+ level->score[i] = default_score[i];
+
level->auto_count_kettles = (getFile8Bit(file) == 1 ? TRUE : FALSE);
level->amoeba_speed = getFile8Bit(file);
level->time_fuse = getFile8Bit(file);
+ // fuse time was 0 and hardcoded in game engine in level files up to 2.0.x
+ if (level->file_version <= MM_FILE_VERSION_2_0)
+ level->time_fuse = 25;
+
laser_color = getFile8Bit(file);
- level->laser_red = (laser_color >> 2) & 0x01;
- level->laser_green = (laser_color >> 1) & 0x01;
- level->laser_blue = (laser_color >> 0) & 0x01;
+ level->mm_laser_red = (laser_color >> 2) & 0x01;
+ level->mm_laser_green = (laser_color >> 1) & 0x01;
+ level->mm_laser_blue = (laser_color >> 0) & 0x01;
level->encoding_16bit_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
for (y = 0; y < level->fieldy; y++)
for (x = 0; x < level->fieldx; x++)
- native_mm_level.field[x][y] = Feld[x][y] = Ur[x][y] =
+ native_mm_level.field[x][y] = Ur[x][y] =
checkLevelElement(level->encoding_16bit_field ?
getFile16BitInteger(file, BYTE_ORDER_BIG_ENDIAN) :
getFile8Bit(file));
{ NULL, 0, NULL }
};
- /* always start with reliable default values */
+ // always start with reliable default values
setLevelInfoToDefaults_MM();
if (!(file = openFile(filename, MODE_READ)))
{
if (!level_info_only)
- Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
+ Warn("cannot read level '%s' - creating new level", filename);
return FALSE;
}
getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
if (strcmp(chunk_name, "MMII") == 0)
{
- getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN); /* not used */
+ getFile32BitInteger(file, BYTE_ORDER_BIG_ENDIAN); // not used
getFileChunk(file, chunk_name, NULL, BYTE_ORDER_BIG_ENDIAN);
if (strcmp(chunk_name, "CAVE") != 0)
{
- Error(ERR_WARN, "unknown format of level file '%s'", filename);
+ Warn("unknown format of level file '%s'", filename);
closeFile(file);
return FALSE;
}
}
- else /* check for pre-2.0 file format with cookie string */
+ else // check for pre-2.0 file format with cookie string
{
strcpy(cookie, chunk_name);
getStringFromFile(file, &cookie[4], MAX_LINE_LEN - 4);
if (!checkCookieString(cookie, LEVEL_COOKIE_TMPL))
{
- Error(ERR_WARN, "unknown format of level file '%s'", filename);
+ Warn("unknown format of level file '%s'", filename);
closeFile(file);
if ((native_mm_level.file_version = getFileVersionFromCookieString(cookie))
== -1)
{
- Error(ERR_WARN, "unsupported version of level file '%s'", filename);
+ Warn("unsupported version of level file '%s'", filename);
closeFile(file);
if (chunk_info[i].name == NULL)
{
- Error(ERR_WARN, "unknown chunk '%s' in level file '%s'",
+ Warn("unknown chunk '%s' in level file '%s'",
chunk_name, filename);
ReadUnusedBytesFromFile(file, chunk_size);
else if (chunk_info[i].size != -1 &&
chunk_info[i].size != chunk_size)
{
- Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
+ Warn("wrong size (%d) of chunk '%s' in level file '%s'",
chunk_size, chunk_name, filename);
ReadUnusedBytesFromFile(file, chunk_size);
}
else
{
- /* call function to load this level chunk */
+ // call function to load this level chunk
int chunk_size_expected =
(chunk_info[i].loader)(file, chunk_size, &native_mm_level);
- /* the size of some chunks cannot be checked before reading other
- chunks first (like "HEAD" and "BODY") that contain some header
- information, so check them here */
+ // the size of some chunks cannot be checked before reading other
+ // chunks first (like "HEAD" and "BODY") that contain some header
+ // information, so check them here
if (chunk_size_expected != chunk_size)
- Error(ERR_WARN, "wrong size (%d) of chunk '%s' in level file '%s'",
+ Warn("wrong size (%d) of chunk '%s' in level file '%s'",
chunk_size, chunk_name, filename);
}
}
fputc(level->amoeba_speed, file);
fputc(level->time_fuse, file);
- laser_color = ((level->laser_red << 2) |
- (level->laser_green << 1) |
- (level->laser_blue << 0));
+ laser_color = ((level->mm_laser_red << 2) |
+ (level->mm_laser_green << 1) |
+ (level->mm_laser_blue << 0));
fputc(laser_color, file);
fputc((level->encoding_16bit_field ? 1 : 0), file);
if (!(file = fopen(filename, MODE_WRITE)))
{
- Error(ERR_WARN, "cannot save level file '%s'", filename);
+ Warn("cannot save level file '%s'", filename);
return;
}
- /* check level field for 16-bit elements */
+ // check level field for 16-bit elements
native_mm_level.encoding_16bit_field = FALSE;
for (y = 0; y < native_mm_level.fieldy; y++)