rnd-20030708-1-src
authorHolger Schemel <info@artsoft.org>
Tue, 8 Jul 2003 00:58:53 +0000 (02:58 +0200)
committerHolger Schemel <info@artsoft.org>
Sat, 30 Aug 2014 08:42:38 +0000 (10:42 +0200)
src/conftime.h
src/editor.c
src/files.c
src/files.h
src/game.c
src/init.c
src/libgame/gadgets.c
src/libgame/setup.c
src/main.c
src/main.h
src/tools.c

index 4e3308a148155088e87482902350d5c999bce856..23174c43d7fea2456c4d095556c05681fcf43a9a 100644 (file)
@@ -1 +1 @@
-#define COMPILE_DATE_STRING "[2003-07-07 16:41]"
+#define COMPILE_DATE_STRING "[2003-07-08 02:56]"
index bfea8ee4ecf41ee3fd9e44f09d0a9a3989e269f6..c3cf7a1236b5b12866d8fadb8f33f52435a75cd4 100644 (file)
 #define ED_TEXTINPUT_ID_LEVEL_LAST     ED_TEXTINPUT_ID_LEVEL_AUTHOR
 
 /* values for selectbox gadgets */
-#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  0
-#define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY     1
-#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      2
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     0
+#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    1
+#define ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION  2
 #define ED_SELECTBOX_ID_CUSTOM_MOVE_PATTERN    3
 #define ED_SELECTBOX_ID_CUSTOM_MOVE_DIRECTION  4
 #define ED_SELECTBOX_ID_CUSTOM_MOVE_STEPSIZE   5
 #define ED_SELECTBOX_ID_CUSTOM_SMASH_TARGETS   6
 #define ED_SELECTBOX_ID_CUSTOM_SLIPPERY_TYPE   7
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE     8
-#define ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER    9
+#define ED_SELECTBOX_ID_CUSTOM_DEADLINESS      8
+#define ED_SELECTBOX_ID_CUSTOM_CONSISTENCY     9
 #define ED_SELECTBOX_ID_CHANGE_TIME_UNITS      10
 #define ED_SELECTBOX_ID_CHANGE_PLAYER_ACTION   11
 #define ED_SELECTBOX_ID_CHANGE_COLLIDE_ACTION  12
 
 #define ED_NUM_SELECTBOX                       15
 
-#define ED_SELECTBOX_ID_CUSTOM_FIRST   ED_SELECTBOX_ID_CUSTOM_WALK_TO_ACTION
-#define ED_SELECTBOX_ID_CUSTOM_LAST    ED_SELECTBOX_ID_CUSTOM_ACCESS_LAYER
+#define ED_SELECTBOX_ID_CUSTOM_FIRST   ED_SELECTBOX_ID_CUSTOM_ACCESS_TYPE
+#define ED_SELECTBOX_ID_CUSTOM_LAST    ED_SELECTBOX_ID_CUSTOM_CONSISTENCY
 
 #define ED_SELECTBOX_ID_CHANGE_FIRST   ED_SELECTBOX_ID_CHANGE_TIME_UNITS
 #define ED_SELECTBOX_ID_CHANGE_LAST    ED_SELECTBOX_ID_CHANGE_POWER
 #define ED_CHECKBUTTON_ID_RANDOM_RESTRICTED    2
 #define ED_CHECKBUTTON_ID_STICK_ELEMENT                3
 #define ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS     4
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        5
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  6
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 7
-#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        8
-#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        9
-#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                10
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      11
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      12
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     13
-#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      14
-#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    15
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE    5
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT        6
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE      7
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL      8
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH     9
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY      10
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY                11
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT        12
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE  13
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 14
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT        15
 #define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC   16
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  17
-#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    18
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   19
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 20
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 21
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    22
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY         23
-#define ED_CHECKBUTTON_ID_CHANGE_BY_PLAYER     24
-#define ED_CHECKBUTTON_ID_CHANGE_BY_COLLISION  25
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER      26
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE    17
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY         18
+#define ED_CHECKBUTTON_ID_CHANGE_BY_PLAYER     19
+#define ED_CHECKBUTTON_ID_CHANGE_BY_COLLISION  20
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER      21
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 22
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT   23
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 24
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM    25
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE  26
 
 #define ED_NUM_CHECKBUTTONS                    27
 
 #define ED_CHECKBUTTON_ID_LEVEL_FIRST  ED_CHECKBUTTON_ID_DOUBLE_SPEED
 #define ED_CHECKBUTTON_ID_LEVEL_LAST   ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
 
-#define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT
-#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE
+#define ED_CHECKBUTTON_ID_CUSTOM_FIRST ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE
+#define ED_CHECKBUTTON_ID_CUSTOM_LAST  ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT
 
 #define ED_CHECKBUTTON_ID_CHANGE_FIRST ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC
-#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CHANGE_BY_OTHER
+#define ED_CHECKBUTTON_ID_CHANGE_LAST  ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE
 
 /* values for radiobutton gadgets */
 #define ED_RADIOBUTTON_ID_PERCENTAGE   0
@@ -1520,6 +1520,7 @@ static void ModifyEditorCounter(int, int);
 static void ModifyEditorCounterLimits(int, int, int);
 static void ModifyEditorSelectbox(int, int);
 static void ModifyEditorElementList();
+static void RedrawDrawingElements();
 static void DrawDrawingWindow();
 static void DrawLevelInfoWindow();
 static void DrawPropertiesWindow();
@@ -3590,6 +3591,9 @@ static void ResetUndoBuffer()
 
 static void DrawEditModeWindow()
 {
+  ModifyEditorElementList();
+  RedrawDrawingElements();
+
   if (edit_mode == ED_MODE_INFO)
     DrawLevelInfoWindow();
   else if (edit_mode == ED_MODE_PROPERTIES)
@@ -3605,7 +3609,7 @@ static boolean LevelChanged()
 
   for(y=0; y<lev_fieldy; y++) 
     for(x=0; x<lev_fieldx; x++)
-      if (Feld[x][y] != Ur[x][y])
+      if (Feld[x][y] != level.field[x][y])
        level_changed = TRUE;
 
   return level_changed;
@@ -3642,7 +3646,7 @@ static void CopyCustomElementPropertiesToEditor(int element)
   /* needed here to initialize combined element properties */
   InitElementPropertiesEngine(level.game_version);
 
-  custom_element = element_info[properties_element];
+  custom_element = element_info[element];
 
   for (i=0; i < NUM_ELEMENT_PROPERTIES; i++)
     custom_element_properties[i] = HAS_PROPERTY(element, i);
@@ -3750,7 +3754,23 @@ static void CopyCustomElementPropertiesToGame(int element)
   int i;
   int access_type_and_layer;
 
-  element_info[properties_element] = custom_element;
+  if (level.use_custom_template)
+  {
+    if (Request("Copy and modify level tem- plate ?", REQ_ASK))
+    {
+      level.use_custom_template = FALSE;
+      ModifyGadget(level_editor_gadget[GADGET_ID_CUSTOM_USE_TEMPLATE],
+                  GDI_CHECKED, FALSE, GDI_END);
+    }
+    else
+    {
+      LoadLevelTemplate(-1);
+
+      DrawEditModeWindow();
+    }
+  }
+
+  element_info[element] = custom_element;
 
   /* ---------- element settings: configure (custom elements) ------------- */
 
@@ -3842,7 +3862,7 @@ static void CopyCustomElementPropertiesToGame(int element)
     SET_CHANGE_EVENT(element, i, custom_element_change_events[i]);
 
   /* copy change events also to special level editor variable */
-  custom_element = element_info[properties_element];
+  custom_element = element_info[element];
 }
 
 void DrawLevelEd()
@@ -3852,8 +3872,8 @@ void DrawLevelEd()
 
   if (level_editor_test_game)
   {
-    CopyPlayfield(Ur, Feld);
-    CopyPlayfield(FieldBackup, Ur);
+    CopyPlayfield(level.field, Feld);
+    CopyPlayfield(FieldBackup, level.field);
 
     level_editor_test_game = FALSE;
   }
@@ -3872,16 +3892,10 @@ void DrawLevelEd()
   BlitBitmap(graphic_info[IMG_GLOBAL_DOOR].bitmap, drawto,
             DOOR_GFX_PAGEX6, DOOR_GFX_PAGEY1, DXSIZE, DYSIZE, DX, DY);
 
+#if 0
   /* draw mouse button brush elements */
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_LEFT_XPOS, DY + ED_WIN_MB_LEFT_YPOS,
-                    el2edimg(new_element1));
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_MIDDLE_XPOS, DY + ED_WIN_MB_MIDDLE_YPOS,
-                    el2edimg(new_element2));
-  DrawMiniGraphicExt(drawto,
-                    DX + ED_WIN_MB_RIGHT_XPOS, DY + ED_WIN_MB_RIGHT_YPOS,
-                    el2edimg(new_element3));
+  RedrawDrawingElements();
+#endif
 
   /* draw bigger door */
   DrawSpecialEditorDoor();
@@ -3893,17 +3907,19 @@ void DrawLevelEd()
   redraw_mask |= REDRAW_ALL;
 
   ReinitializeElementListButtons();    /* only needed after setup changes */
+#if 0
   ModifyEditorElementList();           /* may be needed for custom elements */
+#endif
 
   UnmapTapeButtons();
   MapControlButtons();
 
+  DrawEditModeWindow();
+
   /* copy actual editor door content to door double buffer for OpenDoor() */
   BlitBitmap(drawto, bitmap_db_door,
             DX, DY, DXSIZE, DYSIZE, DOOR_GFX_PAGEX1, DOOR_GFX_PAGEY1);
 
-  DrawEditModeWindow();
-
   OpenDoor(DOOR_OPEN_1);
 }
 
@@ -4981,6 +4997,16 @@ static void DrawPropertiesWindow()
     DrawPropertiesAdvanced();
 }
 
+static void UpdateCustomElementGraphicGadgets()
+{
+  ModifyEditorElementList();
+  RedrawDrawingElements();
+
+  if (edit_mode == ED_MODE_PROPERTIES &&
+      edit_mode_properties == ED_MODE_PROPERTIES_ADVANCED)
+    DrawPropertiesAdvancedDrawingAreas();
+}
+
 static void DrawLineElement(int sx, int sy, int element, boolean change_level)
 {
   int lx = sx + level_xpos;
@@ -5715,34 +5741,36 @@ static void HandleDrawingAreas(struct GadgetInfo *gi)
        {
          new_element = GFX_ELEMENT(new_element);
          custom_element.gfx_element = new_element;
-         element_info[properties_element] = custom_element;
 
-         ModifyEditorElementList();
-         RedrawDrawingElements();
+         CopyCustomElementPropertiesToGame(properties_element);
 
-         DrawPropertiesAdvancedDrawingAreas();
+         UpdateCustomElementGraphicGadgets();
 
          FrameCounter = 0;     /* restart animation frame counter */
        }
        else if (id == GADGET_ID_CUSTOM_CONTENT)
        {
          custom_element.content[sx][sy] = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_TARGET)
        {
          custom_element.change.target_element = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_CONTENT)
        {
          custom_element.change.content[sx][sy] = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_CUSTOM_CHANGE_TRIGGER)
        {
          custom_element.change.trigger_element = new_element;
-         element_info[properties_element] = custom_element;
+
+         CopyCustomElementPropertiesToGame(properties_element);
        }
        else if (id == GADGET_ID_RANDOM_BACKGROUND)
          random_placement_background_element = new_element;
@@ -5969,13 +5997,26 @@ static void HandleSelectboxGadgets(struct GadgetInfo *gi)
 
 static void HandleTextbuttonGadgets(struct GadgetInfo *gi)
 {
-  if (gi->custom_type_id >= ED_TEXTBUTTON_ID_PROPERTIES_INFO &&
-      gi->custom_type_id <= ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED)
+  int type_id = gi->custom_type_id;
+
+  if (type_id >= ED_TEXTBUTTON_ID_PROPERTIES_INFO &&
+      type_id <= ED_TEXTBUTTON_ID_PROPERTIES_ADVANCED)
   {
     edit_mode_properties = gi->custom_type_id;
 
     DrawPropertiesWindow();
   }
+  else if (type_id == ED_TEXTBUTTON_ID_SAVE_AS_TEMPLATE)
+  {
+    boolean new_template = (!LevelFileExists(-1));
+
+    if (new_template ||
+       Request("Save this tem- plate and kill the old ?", REQ_ASK))
+      SaveLevelTemplate();
+
+    if (new_template)
+      Request("Tem- plate saved !", REQ_CONFIRM);
+  }
 }
 
 static void HandleRadiobuttons(struct GadgetInfo *gi)
@@ -5993,15 +6034,31 @@ static void HandleCheckbuttons(struct GadgetInfo *gi)
   if ((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST &&
        type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) ||
       (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST &&
-       type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST))
+       type_id <= ED_CHECKBUTTON_ID_CHANGE_LAST &&
+       type_id != ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE))
+  {
     CopyCustomElementPropertiesToGame(properties_element);
+  }
 
   if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC)
   {
-    ModifyEditorElementList();
-    RedrawDrawingElements();
+    UpdateCustomElementGraphicGadgets();
+  }
+  else if (type_id == ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE)
+  {
+    if (level.use_custom_template && !LevelFileExists(-1))
+    {
+      Request("No level tem- plate found !", REQ_CONFIRM);
 
-    DrawPropertiesAdvancedDrawingAreas();
+      level.use_custom_template = FALSE;
+      ModifyGadget(gi, GDI_CHECKED, FALSE, GDI_END);
+
+      return;
+    }
+
+    LoadLevelTemplate(level.use_custom_template ? -1 : level_nr);
+
+    DrawEditModeWindow();
   }
 }
 
@@ -6249,12 +6306,18 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        Request("No Level without Gregor Mc Duffin please !", REQ_CONFIRM);
       else
       {
-       if (Request("Save this level and kill the old ?", REQ_ASK))
+       boolean new_level = (!LevelFileExists(level_nr));
+
+       if (new_level ||
+           Request("Save this level and kill the old ?", REQ_ASK))
        {
-         CopyPlayfield(Feld, Ur);
+         CopyPlayfield(Feld, level.field);
 
          SaveLevel(level_nr);
        }
+
+       if (new_level)
+         Request("Level saved !", REQ_CONFIRM);
       }
       break;
 
@@ -6266,8 +6329,8 @@ static void HandleControlButtons(struct GadgetInfo *gi)
        if (LevelChanged())
          level.game_version = GAME_VERSION_ACTUAL;
 
-       CopyPlayfield(Ur, FieldBackup);
-       CopyPlayfield(Feld, Ur);
+       CopyPlayfield(level.field, FieldBackup);
+       CopyPlayfield(Feld, level.field);
 
        UnmapLevelEditorGadgets();
        UndrawSpecialEditorDoor();
index 8fe110f24254cece6bd2d43f606229d665c35da3..f3d35adecbebdda6177e8ecd992fdd51317f0531 100644 (file)
 /* level file functions                                                      */
 /* ========================================================================= */
 
-static void setLevelInfoToDefaults()
+static void setLevelInfoToDefaults(struct LevelInfo *level)
 {
   int i, j, x, y;
 
-  level.file_version = FILE_VERSION_ACTUAL;
-  level.game_version = GAME_VERSION_ACTUAL;
+  level->file_version = FILE_VERSION_ACTUAL;
+  level->game_version = GAME_VERSION_ACTUAL;
 
-  level.encoding_16bit_field = FALSE;  /* default: only 8-bit elements */
-  level.encoding_16bit_yamyam = FALSE; /* default: only 8-bit elements */
-  level.encoding_16bit_amoeba = FALSE; /* default: only 8-bit elements */
+  level->encoding_16bit_field  = FALSE;        /* default: only 8-bit elements */
+  level->encoding_16bit_yamyam = FALSE;        /* default: only 8-bit elements */
+  level->encoding_16bit_amoeba = FALSE;        /* default: only 8-bit elements */
 
-  lev_fieldx = level.fieldx = STD_LEV_FIELDX;
-  lev_fieldy = level.fieldy = STD_LEV_FIELDY;
+  level->fieldx = STD_LEV_FIELDX;
+  level->fieldy = STD_LEV_FIELDY;
 
   for(x=0; x<MAX_LEV_FIELDX; x++)
     for(y=0; y<MAX_LEV_FIELDY; y++)
-      Feld[x][y] = Ur[x][y] = EL_SAND;
-
-  level.time = 100;
-  level.gems_needed = 0;
-  level.amoeba_speed = 10;
-  level.time_magic_wall = 10;
-  level.time_wheel = 10;
-  level.time_light = 10;
-  level.time_timegate = 10;
-  level.amoeba_content = EL_DIAMOND;
-  level.double_speed = FALSE;
-  level.gravity = FALSE;
-  level.em_slippery_gems = FALSE;
-
-  level.use_custom_template = FALSE;
+      level->field[x][y] = EL_SAND;
+
+  level->time = 100;
+  level->gems_needed = 0;
+  level->amoeba_speed = 10;
+  level->time_magic_wall = 10;
+  level->time_wheel = 10;
+  level->time_light = 10;
+  level->time_timegate = 10;
+  level->amoeba_content = EL_DIAMOND;
+  level->double_speed = FALSE;
+  level->gravity = FALSE;
+  level->em_slippery_gems = FALSE;
+
+  level->use_custom_template = FALSE;
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
-    level.name[i] = '\0';
+    level->name[i] = '\0';
   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
-    level.author[i] = '\0';
+    level->author[i] = '\0';
 
-  strcpy(level.name, NAMELESS_LEVEL_NAME);
-  strcpy(level.author, ANONYMOUS_NAME);
+  strcpy(level->name, NAMELESS_LEVEL_NAME);
+  strcpy(level->author, ANONYMOUS_NAME);
 
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
-    level.score[i] = 10;
+    level->score[i] = 10;
 
-  level.num_yamyam_contents = STD_ELEMENT_CONTENTS;
+  level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for(x=0; x<3; x++)
       for(y=0; y<3; y++)
-       level.yamyam_content[i][x][y] =
+       level->yamyam_content[i][x][y] =
          (i < STD_ELEMENT_CONTENTS ? EL_ROCK : EL_EMPTY);
 
-  Feld[0][0] = Ur[0][0] = EL_PLAYER_1;
-  Feld[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] =
-    Ur[STD_LEV_FIELDX-1][STD_LEV_FIELDY-1] = EL_EXIT_CLOSED;
+  level->field[0][0] = EL_PLAYER_1;
+  level->field[STD_LEV_FIELDX - 1][STD_LEV_FIELDY - 1] = EL_EXIT_CLOSED;
 
   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
   {
@@ -176,7 +175,7 @@ static void setLevelInfoToDefaults()
 
   BorderElement = EL_STEELWALL;
 
-  level.no_level_file = FALSE;
+  level->no_level_file = FALSE;
 
   if (leveldir_current == NULL)                /* only when dumping level */
     return;
@@ -184,25 +183,25 @@ static void setLevelInfoToDefaults()
   /* try to determine better author name than 'anonymous' */
   if (strcmp(leveldir_current->author, ANONYMOUS_NAME) != 0)
   {
-    strncpy(level.author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
-    level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
+    strncpy(level->author, leveldir_current->author, MAX_LEVEL_AUTHOR_LEN);
+    level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
   }
   else
   {
     switch (LEVELCLASS(leveldir_current))
     {
       case LEVELCLASS_TUTORIAL:
-       strcpy(level.author, PROGRAM_AUTHOR_STRING);
+       strcpy(level->author, PROGRAM_AUTHOR_STRING);
        break;
 
       case LEVELCLASS_CONTRIBUTION:
-       strncpy(level.author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
-       level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
+       strncpy(level->author, leveldir_current->name,MAX_LEVEL_AUTHOR_LEN);
+       level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
        break;
 
       case LEVELCLASS_USER:
-       strncpy(level.author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
-       level.author[MAX_LEVEL_AUTHOR_LEN] = '\0';
+       strncpy(level->author, getRealName(), MAX_LEVEL_AUTHOR_LEN);
+       level->author[MAX_LEVEL_AUTHOR_LEN] = '\0';
        break;
 
       default:
@@ -212,6 +211,20 @@ static void setLevelInfoToDefaults()
   }
 }
 
+static void ActivateLevelTemplate()
+{
+  /* Currently there is no special action needed to activate the template
+     data, because 'element_info' and 'Properties' overwrite the original
+     level data, while all other variables do not change. */
+}
+
+boolean LevelFileExists(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  return (access(filename, F_OK) == 0);
+}
+
 static int checkLevelElement(int element)
 {
   if (element >= NUM_FILE_ELEMENTS)
@@ -239,35 +252,35 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level)
 {
   int i, x, y;
 
-  lev_fieldx = level->fieldx = fgetc(file);
-  lev_fieldy = level->fieldy = fgetc(file);
+  level->fieldx = getFile8Bit(file);
+  level->fieldy = getFile8Bit(file);
 
   level->time          = getFile16BitBE(file);
   level->gems_needed   = getFile16BitBE(file);
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
-    level->name[i] = fgetc(file);
+    level->name[i] = getFile8Bit(file);
   level->name[MAX_LEVEL_NAME_LEN] = 0;
 
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
-    level->score[i] = fgetc(file);
+    level->score[i] = getFile8Bit(file);
 
   level->num_yamyam_contents = STD_ELEMENT_CONTENTS;
   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       level->yamyam_content[i][x][y] = checkLevelElement(fgetc(file));
+       level->yamyam_content[i][x][y] = checkLevelElement(getFile8Bit(file));
 
-  level->amoeba_speed          = fgetc(file);
-  level->time_magic_wall       = fgetc(file);
-  level->time_wheel            = fgetc(file);
-  level->amoeba_content                = checkLevelElement(fgetc(file));
-  level->double_speed          = (fgetc(file) == 1 ? TRUE : FALSE);
-  level->gravity               = (fgetc(file) == 1 ? TRUE : FALSE);
-  level->encoding_16bit_field  = (fgetc(file) == 1 ? TRUE : FALSE);
-  level->em_slippery_gems      = (fgetc(file) == 1 ? TRUE : FALSE);
+  level->amoeba_speed          = getFile8Bit(file);
+  level->time_magic_wall       = getFile8Bit(file);
+  level->time_wheel            = getFile8Bit(file);
+  level->amoeba_content                = checkLevelElement(getFile8Bit(file));
+  level->double_speed          = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->gravity               = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->encoding_16bit_field  = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+  level->em_slippery_gems      = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
-  level->use_custom_template   = (fgetc(file) == 1 ? TRUE : FALSE);
+  level->use_custom_template   = (getFile8Bit(file) == 1 ? TRUE : FALSE);
 
   ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED);
 
@@ -279,7 +292,7 @@ static int LoadLevel_AUTH(FILE *file, int chunk_size, struct LevelInfo *level)
   int i;
 
   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
-    level->author[i] = fgetc(file);
+    level->author[i] = getFile8Bit(file);
   level->author[MAX_LEVEL_NAME_LEN] = 0;
 
   return chunk_size;
@@ -306,9 +319,9 @@ static int LoadLevel_BODY(FILE *file, int chunk_size, struct LevelInfo *level)
 
   for(y=0; y<level->fieldy; y++)
     for(x=0; x<level->fieldx; x++)
-      Feld[x][y] = Ur[x][y] =
-       checkLevelElement(level->encoding_16bit_field ?
-                         getFile16BitBE(file) : fgetc(file));
+      level->field[x][y] =
+       checkLevelElement(level->encoding_16bit_field ? getFile16BitBE(file) :
+                         getFile8Bit(file));
   return chunk_size;
 }
 
@@ -333,10 +346,10 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
     return chunk_size_expected;
   }
 
-  fgetc(file);
-  level->num_yamyam_contents = fgetc(file);
-  fgetc(file);
-  fgetc(file);
+  getFile8Bit(file);
+  level->num_yamyam_contents = getFile8Bit(file);
+  getFile8Bit(file);
+  getFile8Bit(file);
 
   /* correct invalid number of content fields -- should never happen */
   if (level->num_yamyam_contents < 1 ||
@@ -348,7 +361,7 @@ static int LoadLevel_CONT(FILE *file, int chunk_size, struct LevelInfo *level)
       for(x=0; x<3; x++)
        level->yamyam_content[i][x][y] =
          checkLevelElement(level->encoding_16bit_field ?
-                           getFile16BitBE(file) : fgetc(file));
+                           getFile16BitBE(file) : getFile8Bit(file));
   return chunk_size;
 }
 
@@ -360,9 +373,9 @@ static int LoadLevel_CNT2(FILE *file, int chunk_size, struct LevelInfo *level)
   int content_array[MAX_ELEMENT_CONTENTS][3][3];
 
   element = checkLevelElement(getFile16BitBE(file));
-  num_contents = fgetc(file);
-  content_xsize = fgetc(file);
-  content_ysize = fgetc(file);
+  num_contents = getFile8Bit(file);
+  content_xsize = getFile8Bit(file);
+  content_ysize = getFile8Bit(file);
   ReadUnusedBytesFromFile(file, LEVEL_CHUNK_CNT2_UNUSED);
 
   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
@@ -534,7 +547,7 @@ static int LoadLevel_CUS3(FILE *file, int chunk_size, struct LevelInfo *level)
   return chunk_size;
 }
 
-void LoadLevelFromFilename(char *filename)
+void LoadLevelFromFilename(struct LevelInfo *level, char *filename)
 {
   char cookie[MAX_LINE_LEN];
   char chunk_name[CHUNK_ID_LEN + 1];
@@ -542,13 +555,15 @@ void LoadLevelFromFilename(char *filename)
   FILE *file;
 
   /* always start with reliable default values */
-  setLevelInfoToDefaults();
+  setLevelInfoToDefaults(level);
 
   if (!(file = fopen(filename, MODE_READ)))
   {
-    level.no_level_file = TRUE;
+    level->no_level_file = TRUE;
+
+    if (level != &level_template)
+      Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
 
-    Error(ERR_WARN, "cannot read level '%s' - creating new level", filename);
     return;
   }
 
@@ -579,7 +594,7 @@ void LoadLevelFromFilename(char *filename)
       return;
     }
 
-    if ((level.file_version = getFileVersionFromCookieString(cookie)) == -1)
+    if ((level->file_version = getFileVersionFromCookieString(cookie)) == -1)
     {
       Error(ERR_WARN, "unsupported version of level file '%s'", filename);
       fclose(file);
@@ -587,14 +602,14 @@ void LoadLevelFromFilename(char *filename)
     }
 
     /* pre-2.0 level files have no game version, so use file version here */
-    level.game_version = level.file_version;
+    level->game_version = level->file_version;
   }
 
-  if (level.file_version < FILE_VERSION_1_2)
+  if (level->file_version < FILE_VERSION_1_2)
   {
     /* level files from versions before 1.2.0 without chunk structure */
-    LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,           &level);
-    LoadLevel_BODY(file, level.fieldx * level.fieldy, &level);
+    LoadLevel_HEAD(file, LEVEL_HEADER_SIZE,             level);
+    LoadLevel_BODY(file, level->fieldx * level->fieldy, level);
   }
   else
   {
@@ -643,7 +658,7 @@ void LoadLevelFromFilename(char *filename)
       {
        /* call function to load this level chunk */
        int chunk_size_expected =
-         (chunk_info[i].loader)(file, chunk_size, &level);
+         (chunk_info[i].loader)(file, chunk_size, level);
 
        /* the size of some chunks cannot be checked before reading other
           chunks first (like "HEAD" and "BODY") that contain some header
@@ -658,6 +673,11 @@ void LoadLevelFromFilename(char *filename)
   }
 
   fclose(file);
+}
+
+static void LoadLevel_InitLevel(struct LevelInfo *level, char *filename)
+{
+  int x, y;
 
   if (leveldir_current == NULL)                /* only when dumping level */
     return;
@@ -674,18 +694,18 @@ void LoadLevelFromFilename(char *filename)
        file format version used to store the level -- see above). */
 
     /* do some special adjustments to support older level versions */
-    if (level.file_version == FILE_VERSION_1_0)
+    if (level->file_version == FILE_VERSION_1_0)
     {
-      Error(ERR_WARN, "level file '%s' has version number 1.0", filename);
+      Error(ERR_WARN, "level file '%s'has version number 1.0", filename);
       Error(ERR_WARN, "using high speed movement for player");
 
       /* player was faster than monsters in (pre-)1.0 levels */
-      level.double_speed = TRUE;
+      level->double_speed = TRUE;
     }
 
     /* Default behaviour for EM style gems was "slippery" only in 2.0.1 */
-    if (level.game_version == VERSION_IDENT(2,0,1))
-      level.em_slippery_gems = TRUE;
+    if (level->game_version == VERSION_IDENT(2,0,1))
+      level->em_slippery_gems = TRUE;
   }
   else
   {
@@ -696,7 +716,7 @@ void LoadLevelFromFilename(char *filename)
        make the game emulation more accurate, while (hopefully) not
        breaking existing levels created from other players. */
 
-    level.game_version = GAME_VERSION_ACTUAL;
+    level->game_version = GAME_VERSION_ACTUAL;
 
     /* Set special EM style gems behaviour: EM style gems slip down from
        normal, steel and growing wall. As this is a more fundamental change,
@@ -705,21 +725,19 @@ void LoadLevelFromFilename(char *filename)
        of gem style elements). Already existing converted levels (neither
        private nor contributed levels) are changed to the new behaviour. */
 
-    if (level.file_version < FILE_VERSION_2_0)
-      level.em_slippery_gems = TRUE;
+    if (level->file_version < FILE_VERSION_2_0)
+      level->em_slippery_gems = TRUE;
   }
 
-  /* map some elements which have changed in newer versions */
-  if (level.game_version <= VERSION_IDENT(2,2,0))
+  /* map elements which have changed in newer versions */
+  if (level->game_version <= VERSION_IDENT(2,2,0))
   {
-    int x, y;
-
     /* map game font elements */
-    for(y=0; y<level.fieldy; y++)
+    for(y=0; y<level->fieldy; y++)
     {
-      for(x=0; x<level.fieldx; x++)
+      for(x=0; x<level->fieldx; x++)
       {
-       int element = Ur[x][y];
+       int element = level->field[x][y];
 
        if (element == EL_CHAR('['))
          element = EL_CHAR_AUMLAUT;
@@ -730,21 +748,46 @@ void LoadLevelFromFilename(char *filename)
        else if (element == EL_CHAR('^'))
          element = EL_CHAR_COPYRIGHT;
 
-       Feld[x][y] = Ur[x][y] = element;
+       level->field[x][y] = element;
       }
     }
   }
 
+  /* copy elements to runtime playfield array */
+  for(y=0; y<level->fieldy; y++)
+    for(x=0; x<level->fieldx; x++)
+      Feld[x][y] = level->field[x][y];
+
+  /* initialize level size variables for faster access */
+  lev_fieldx = level->fieldx;
+  lev_fieldy = level->fieldy;
+
   /* determine border element for this level */
   SetBorderElement();
+
+  /* initialize element properties for level editor etc. */
+  InitElementPropertiesEngine(level->game_version);
+}
+
+void LoadLevelTemplate(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  LoadLevelFromFilename(&level_template, filename);
+
+  ActivateLevelTemplate();
 }
 
 void LoadLevel(int level_nr)
 {
   char *filename = getLevelFilename(level_nr);
 
-  LoadLevelFromFilename(filename);
-  InitElementPropertiesEngine(level.game_version);
+  LoadLevelFromFilename(&level, filename);
+
+  if (level.use_custom_template)
+    LoadLevelTemplate(-1);
+
+  LoadLevel_InitLevel(&level, filename);
 }
 
 static void SaveLevel_VERS(FILE *file, struct LevelInfo *level)
@@ -757,35 +800,34 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
 
-  fputc(level->fieldx, file);
-  fputc(level->fieldy, file);
+  putFile8Bit(file, level->fieldx);
+  putFile8Bit(file, level->fieldy);
 
   putFile16BitBE(file, level->time);
   putFile16BitBE(file, level->gems_needed);
 
   for(i=0; i<MAX_LEVEL_NAME_LEN; i++)
-    fputc(level->name[i], file);
+    putFile8Bit(file, level->name[i]);
 
   for(i=0; i<LEVEL_SCORE_ELEMENTS; i++)
-    fputc(level->score[i], file);
+    putFile8Bit(file, level->score[i]);
 
   for(i=0; i<STD_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       fputc((level->encoding_16bit_yamyam ? EL_EMPTY :
-              level->yamyam_content[i][x][y]),
-             file);
-  fputc(level->amoeba_speed, file);
-  fputc(level->time_magic_wall, file);
-  fputc(level->time_wheel, file);
-  fputc((level->encoding_16bit_amoeba ? EL_EMPTY : level->amoeba_content),
-       file);
-  fputc((level->double_speed ? 1 : 0), file);
-  fputc((level->gravity ? 1 : 0), file);
-  fputc((level->encoding_16bit_field ? 1 : 0), file);
-  fputc((level->em_slippery_gems ? 1 : 0), file);
-
-  fputc((level->use_custom_template ? 1 : 0), file);
+       putFile8Bit(file, (level->encoding_16bit_yamyam ? EL_EMPTY :
+                          level->yamyam_content[i][x][y]));
+  putFile8Bit(file, level->amoeba_speed);
+  putFile8Bit(file, level->time_magic_wall);
+  putFile8Bit(file, level->time_wheel);
+  putFile8Bit(file, (level->encoding_16bit_amoeba ? EL_EMPTY :
+                    level->amoeba_content));
+  putFile8Bit(file, (level->double_speed ? 1 : 0));
+  putFile8Bit(file, (level->gravity ? 1 : 0));
+  putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
+  putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
+
+  putFile8Bit(file, (level->use_custom_template ? 1 : 0));
 
   WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED);
 }
@@ -795,7 +837,7 @@ static void SaveLevel_AUTH(FILE *file, struct LevelInfo *level)
   int i;
 
   for(i=0; i<MAX_LEVEL_AUTHOR_LEN; i++)
-    fputc(level->author[i], file);
+    putFile8Bit(file, level->author[i]);
 }
 
 static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
@@ -805,9 +847,9 @@ static void SaveLevel_BODY(FILE *file, struct LevelInfo *level)
   for(y=0; y<level->fieldy; y++) 
     for(x=0; x<level->fieldx; x++) 
       if (level->encoding_16bit_field)
-       putFile16BitBE(file, Ur[x][y]);
+       putFile16BitBE(file, level->field[x][y]);
       else
-       fputc(Ur[x][y], file);
+       putFile8Bit(file, level->field[x][y]);
 }
 
 #if 0
@@ -815,10 +857,10 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
 {
   int i, x, y;
 
-  fputc(EL_YAMYAM, file);
-  fputc(level->num_yamyam_contents, file);
-  fputc(0, file);
-  fputc(0, file);
+  putFile8Bit(file, EL_YAMYAM);
+  putFile8Bit(file, level->num_yamyam_contents);
+  putFile8Bit(file, 0);
+  putFile8Bit(file, 0);
 
   for(i=0; i<MAX_ELEMENT_CONTENTS; i++)
     for(y=0; y<3; y++)
@@ -826,7 +868,7 @@ static void SaveLevel_CONT(FILE *file, struct LevelInfo *level)
        if (level->encoding_16bit_field)
          putFile16BitBE(file, level->yamyam_content[i][x][y]);
        else
-         fputc(level->yamyam_content[i][x][y], file);
+         putFile8Bit(file, level->yamyam_content[i][x][y]);
 }
 #endif
 
@@ -869,9 +911,9 @@ static void SaveLevel_CNT2(FILE *file, struct LevelInfo *level, int element)
   }
 
   putFile16BitBE(file, element);
-  fputc(num_contents, file);
-  fputc(content_xsize, file);
-  fputc(content_ysize, file);
+  putFile8Bit(file, num_contents);
+  putFile8Bit(file, content_xsize);
+  putFile8Bit(file, content_ysize);
 
   WriteUnusedBytesToFile(file, LEVEL_CHUNK_CNT2_UNUSED);
 
@@ -1019,9 +1061,8 @@ static void SaveLevel_CUS3(FILE *file, struct LevelInfo *level,
     Error(ERR_WARN, "inconsistent number of custom element properties");
 }
 
-void SaveLevel(int level_nr)
+static void SaveLevelFromFilename(struct LevelInfo *level, char *filename)
 {
-  char *filename = getLevelFilename(level_nr);
   int body_chunk_size;
   int num_changed_custom_elements = 0;
   int level_chunk_CUS3_size;
@@ -1034,32 +1075,32 @@ void SaveLevel(int level_nr)
     return;
   }
 
-  level.file_version = FILE_VERSION_ACTUAL;
-  level.game_version = GAME_VERSION_ACTUAL;
+  level->file_version = FILE_VERSION_ACTUAL;
+  level->game_version = GAME_VERSION_ACTUAL;
 
   /* check level field for 16-bit elements */
-  level.encoding_16bit_field = FALSE;
-  for(y=0; y<level.fieldy; y++) 
-    for(x=0; x<level.fieldx; x++) 
-      if (Ur[x][y] > 255)
-       level.encoding_16bit_field = TRUE;
+  level->encoding_16bit_field = FALSE;
+  for(y=0; y<level->fieldy; y++) 
+    for(x=0; x<level->fieldx; x++) 
+      if (level->field[x][y] > 255)
+       level->encoding_16bit_field = TRUE;
 
   /* check yamyam content for 16-bit elements */
-  level.encoding_16bit_yamyam = FALSE;
-  for(i=0; i<level.num_yamyam_contents; i++)
+  level->encoding_16bit_yamyam = FALSE;
+  for(i=0; i<level->num_yamyam_contents; i++)
     for(y=0; y<3; y++)
       for(x=0; x<3; x++)
-       if (level.yamyam_content[i][x][y] > 255)
-         level.encoding_16bit_yamyam = TRUE;
+       if (level->yamyam_content[i][x][y] > 255)
+         level->encoding_16bit_yamyam = TRUE;
 
   /* check amoeba content for 16-bit elements */
-  level.encoding_16bit_amoeba = FALSE;
-  if (level.amoeba_content > 255)
-    level.encoding_16bit_amoeba = TRUE;
+  level->encoding_16bit_amoeba = FALSE;
+  if (level->amoeba_content > 255)
+    level->encoding_16bit_amoeba = TRUE;
 
   /* calculate size of "BODY" chunk */
   body_chunk_size =
-    level.fieldx * level.fieldy * (level.encoding_16bit_field ? 2 : 1);
+    level->fieldx * level->fieldy * (level->encoding_16bit_field ? 2 : 1);
 
   /* check for non-standard custom elements and calculate "CUS3" chunk size */
   for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
@@ -1071,34 +1112,34 @@ void SaveLevel(int level_nr)
   putFileChunkBE(file, "CAVE", CHUNK_SIZE_NONE);
 
   putFileChunkBE(file, "VERS", FILE_VERS_CHUNK_SIZE);
-  SaveLevel_VERS(file, &level);
+  SaveLevel_VERS(file, level);
 
   putFileChunkBE(file, "HEAD", LEVEL_HEADER_SIZE);
-  SaveLevel_HEAD(file, &level);
+  SaveLevel_HEAD(file, level);
 
   putFileChunkBE(file, "AUTH", MAX_LEVEL_AUTHOR_LEN);
-  SaveLevel_AUTH(file, &level);
+  SaveLevel_AUTH(file, level);
 
   putFileChunkBE(file, "BODY", body_chunk_size);
-  SaveLevel_BODY(file, &level);
+  SaveLevel_BODY(file, level);
 
-  if (level.encoding_16bit_yamyam ||
-      level.num_yamyam_contents != STD_ELEMENT_CONTENTS)
+  if (level->encoding_16bit_yamyam ||
+      level->num_yamyam_contents != STD_ELEMENT_CONTENTS)
   {
     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, &level, EL_YAMYAM);
+    SaveLevel_CNT2(file, level, EL_YAMYAM);
   }
 
-  if (level.encoding_16bit_amoeba)
+  if (level->encoding_16bit_amoeba)
   {
     putFileChunkBE(file, "CNT2", LEVEL_CHUNK_CNT2_SIZE);
-    SaveLevel_CNT2(file, &level, EL_BD_AMOEBA);
+    SaveLevel_CNT2(file, level, EL_BD_AMOEBA);
   }
 
-  if (num_changed_custom_elements > 0)
+  if (num_changed_custom_elements > 0 && !level->use_custom_template)
   {
     putFileChunkBE(file, "CUS3", level_chunk_CUS3_size);
-    SaveLevel_CUS3(file, &level, num_changed_custom_elements);
+    SaveLevel_CUS3(file, level, num_changed_custom_elements);
   }
 
   fclose(file);
@@ -1106,6 +1147,20 @@ void SaveLevel(int level_nr)
   SetFilePermissions(filename, PERMS_PRIVATE);
 }
 
+void SaveLevel(int level_nr)
+{
+  char *filename = getLevelFilename(level_nr);
+
+  SaveLevelFromFilename(&level, filename);
+}
+
+void SaveLevelTemplate()
+{
+  char *filename = getLevelFilename(-1);
+
+  SaveLevelFromFilename(&level, filename);
+}
+
 void DumpLevel(struct LevelInfo *level)
 {
   printf_line("-", 79);
@@ -1183,7 +1238,7 @@ static int LoadTape_HEAD(FILE *file, int chunk_size, struct TapeInfo *tape)
   /* read header fields that are new since version 1.2 */
   if (tape->file_version >= FILE_VERSION_1_2)
   {
-    byte store_participating_players = fgetc(file);
+    byte store_participating_players = getFile8Bit(file);
     int engine_version;
 
     /* since version 1.2, tapes store which players participate in the tape */
@@ -1220,7 +1275,7 @@ static int LoadTape_INFO(FILE *file, int chunk_size, struct TapeInfo *tape)
     checked_realloc(tape->level_identifier, level_identifier_size);
 
   for(i=0; i < level_identifier_size; i++)
-    tape->level_identifier[i] = fgetc(file);
+    tape->level_identifier[i] = getFile8Bit(file);
 
   tape->level_nr = getFile16BitBE(file);
 
@@ -1251,10 +1306,10 @@ static int LoadTape_BODY(FILE *file, int chunk_size, struct TapeInfo *tape)
       tape->pos[i].action[j] = MV_NO_MOVING;
 
       if (tape->player_participates[j])
-       tape->pos[i].action[j] = fgetc(file);
+       tape->pos[i].action[j] = getFile8Bit(file);
     }
 
-    tape->pos[i].delay = fgetc(file);
+    tape->pos[i].delay = getFile8Bit(file);
 
     if (tape->file_version == FILE_VERSION_1_0)
     {
@@ -1462,7 +1517,7 @@ static void SaveTape_HEAD(FILE *file, struct TapeInfo *tape)
   putFile32BitBE(file, tape->date);
   putFile32BitBE(file, tape->length);
 
-  fputc(store_participating_players, file);
+  putFile8Bit(file, store_participating_players);
 
   /* unused bytes not at the end here for 4-byte alignment of engine_version */
   WriteUnusedBytesToFile(file, TAPE_HEADER_UNUSED);
@@ -1478,7 +1533,7 @@ static void SaveTape_INFO(FILE *file, struct TapeInfo *tape)
   putFile16BitBE(file, level_identifier_size);
 
   for(i=0; i < level_identifier_size; i++)
-    fputc(tape->level_identifier[i], file);
+    putFile8Bit(file, tape->level_identifier[i]);
 
   putFile16BitBE(file, tape->level_nr);
 }
@@ -1491,9 +1546,9 @@ static void SaveTape_BODY(FILE *file, struct TapeInfo *tape)
   {
     for(j=0; j<MAX_PLAYERS; j++)
       if (tape->player_participates[j])
-       fputc(tape->pos[i].action[j], file);
+       putFile8Bit(file, tape->pos[i].action[j]);
 
-    fputc(tape->pos[i].delay, file);
+    putFile8Bit(file, tape->pos[i].delay);
   }
 }
 
index ff528997a38a2988dc9e2acf3127ddf1d604318b..5f5f67dc74cebda330e7159e949724e9e337a4b9 100644 (file)
 
 #include "main.h"
 
-void LoadLevelFromFilename(char *);
+boolean LevelFileExists(int);
+void LoadLevelFromFilename(struct LevelInfo *, char *);
 void LoadLevel(int);
+void LoadLevelTemplate(int);
 void SaveLevel(int);
+void SaveLevelTemplate();
 void DumpLevel(struct LevelInfo *);
 
 void LoadTapeFromFilename(char *);
@@ -29,8 +32,8 @@ void DumpTape(struct TapeInfo *);
 void LoadScore(int);
 void SaveScore(int);
 
-void LoadSetup(void);
-void SaveSetup(void);
+void LoadSetup();
+void SaveSetup();
 
 void LoadCustomElementDescriptions();
 void LoadSpecialMenuDesignSettings();
index 2774beba27e6f1417fcd1436fc60de97caa3e8ee..c52d16250d7ce2e7f3b412dd44e500cf0c94a3cf 100644 (file)
@@ -1046,7 +1046,7 @@ void InitGame()
   {
     for (y=0; y<lev_fieldy; y++)
     {
-      Feld[x][y] = Ur[x][y];
+      Feld[x][y] = level.field[x][y];
       MovPos[x][y] = MovDir[x][y] = MovDelay[x][y] = 0;
       ChangeDelay[x][y] = 0;
       Store[x][y] = Store2[x][y] = StorePlayer[x][y] = Back[x][y] = 0;
index 7e4b1727863b3c5ffd3b1cd59a9da024e5fdae19..45211a85d182f37c68dafc194fc6d3544052753b 100644 (file)
@@ -2749,7 +2749,7 @@ void Execute_Command(char *command)
     if (access(filename, F_OK) != 0)
       Error(ERR_EXIT, "cannot open file '%s'", filename);
 
-    LoadLevelFromFilename(filename);
+    LoadLevelFromFilename(&level, filename);
     DumpLevel(&level);
 
     exit(0);
index b80910d8822ec7ae12fc2503fe5b6355c8720f85..619039aa2b1114ddb6979f140d996a198242b77d 100644 (file)
@@ -1131,6 +1131,13 @@ void HandleGadgets(int mx, int my, int button)
   if (gadget_list_first_entry == NULL)
     return;
 
+  /* simulated release of mouse button over last gadget */
+  if (mx == -1 && my == -1 && button == 0)
+  {
+    mx = last_mx;
+    my = last_my;
+  }
+
   /* check which gadget is under the mouse pointer */
   new_gi = getGadgetInfoFromMousePosition(mx, my);
 
@@ -1547,6 +1554,10 @@ void HandleGadgets(int mx, int my, int button)
        gi->event_mask & GD_EVENT_OFF_BORDERS)
       gi->callback_action(gi);
   }
+
+  /* handle gadgets unmapped/mapped between pressing and releasing */
+  if (release_event && !gadget_released && new_gi)
+    new_gi->state = GD_BUTTON_UNPRESSED;
 }
 
 void HandleGadgetsKeyInput(Key key)
index 102d5fd13d92d0bd7fa1fa0ca494d7ecbe34994b..9b23e8afc9b3e9fe1c8bbc5cc3f7f51f0959c863 100644 (file)
@@ -361,7 +361,11 @@ char *getLevelFilename(int nr)
   if (filename != NULL)
     free(filename);
 
-  sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+  if (nr < 0)
+    sprintf(basename, "template.%s", LEVELFILE_EXTENSION);
+  else
+    sprintf(basename, "%03d.%s", nr, LEVELFILE_EXTENSION);
+
   filename = getPath2(getCurrentLevelDir(), basename);
 
   return filename;
index dc2c783438227082168a5dc1012e58895531d186..1df43610f1978c38e8e0dc8b6f787c6b60246aa6 100644 (file)
@@ -40,7 +40,6 @@ boolean                       redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
 int                    redraw_x1 = 0, redraw_y1 = 0;
 
 short                  Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-short                  Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 short                  MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
@@ -87,7 +86,7 @@ int                   TimeFrames, TimePlayed, TimeLeft;
 
 boolean                        network_player_action_received = FALSE;
 
-struct LevelInfo       level;
+struct LevelInfo       level, level_template;
 struct PlayerInfo      stored_player[MAX_PLAYERS], *local_player = NULL;
 struct HiScore         highscore[MAX_SCORE_ENTRIES];
 struct TapeInfo                tape;
index 340f8bebd4dceae0b7dbdf22418ef38143b774a4..86155b077cded23320bf9bfb257cf157f3f1a0d4 100644 (file)
@@ -1112,6 +1112,8 @@ struct LevelInfo
   boolean gravity;
   boolean em_slippery_gems;    /* EM style "gems slip from wall" behaviour */
 
+  short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
+
   boolean use_custom_template; /* use custom properties from template file */
 
   boolean no_level_file;
@@ -1367,7 +1369,6 @@ extern boolean                    redraw[MAX_BUF_XSIZE][MAX_BUF_YSIZE];
 extern int                     redraw_x1, redraw_y1;
 
 extern short                   Feld[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
-extern short                   Ur[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   MovPos[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   MovDir[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
 extern short                   MovDelay[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
@@ -1417,7 +1418,7 @@ extern boolean                    network_player_action_received;
 
 extern int                     graphics_action_mapping[];
 
-extern struct LevelInfo                level;
+extern struct LevelInfo                level, level_template;
 extern struct PlayerInfo       stored_player[], *local_player;
 extern struct HiScore          highscore[];
 extern struct TapeInfo         tape;
index e5d2985a3154f8bd972cd9c100d625831d943c38..cfbc85cc632c1c376fcd34dfd13a1b342747d03d 100644 (file)
@@ -1521,7 +1521,7 @@ static void DrawMicroLevelExt(int xpos, int ypos, int from_x, int from_y)
 
       if (lx >= 0 && lx < lev_fieldx && ly >= 0 && ly < lev_fieldy)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
-                        Ur[lx][ly]);
+                        level.field[lx][ly]);
       else if (lx >= -1 && lx < lev_fieldx+1 && ly >= -1 && ly < lev_fieldy+1
               && BorderElement != EL_EMPTY)
        DrawMicroElement(xpos + x * MICRO_TILEX, ypos + y * MICRO_TILEY,
@@ -1712,6 +1712,10 @@ boolean Request(char *text, unsigned int req_state)
 
   old_door_state = GetDoorState();
 
+  /* simulate releasing mouse button over last gadget, if still pressed */
+  if (button_status)
+    HandleGadgets(-1, -1, 0);
+
   UnmapAllGadgets();
 
   CloseDoor(DOOR_CLOSE_1);