rnd-20040323-1-src
[rocksndiamonds.git] / src / init.c
index 9871ed6cd8c3f0c5c0c4dc1ed5ad04a3edeb5837..6917ee0b1aabc04799fb382eff7feb95d0b7cdeb 100644 (file)
@@ -413,6 +413,9 @@ void InitElementGraphicInfo()
   int num_property_mappings = getImageListPropertyMappingSize();
   int i, act, dir;
 
+  if (graphic_info == NULL)            /* still at startup phase */
+    return;
+
   /* set values to -1 to identify later as "uninitialized" values */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -595,7 +598,7 @@ void InitElementGraphicInfo()
     int default_direction_crumbled[NUM_DIRECTIONS];
 
     if (default_graphic == -1)
-      default_graphic = IMG_CHAR_QUESTION;
+      default_graphic = IMG_UNKNOWN;
     if (default_crumbled == -1)
       default_crumbled = IMG_EMPTY;
 
@@ -614,9 +617,9 @@ void InitElementGraphicInfo()
 
     for (act = 0; act < NUM_ACTIONS; act++)
     {
-      boolean act_remove = (act == ACTION_DIGGING ||
-                           act == ACTION_SNAPPING ||
-                           act == ACTION_COLLECTING);
+      boolean act_remove = ((IS_DIGGABLE(i)    && act == ACTION_DIGGING)  ||
+                           (IS_SNAPPABLE(i)   && act == ACTION_SNAPPING) ||
+                           (IS_COLLECTIBLE(i) && act == ACTION_COLLECTING));
       boolean act_turning = (act == ACTION_TURNING_FROM_LEFT ||
                             act == ACTION_TURNING_FROM_RIGHT ||
                             act == ACTION_TURNING_FROM_UP ||
@@ -641,6 +644,15 @@ void InitElementGraphicInfo()
       if (IS_SB_ELEMENT(i) && element_info[EL_SB_DEFAULT].crumbled[act] != -1)
        default_action_crumbled = element_info[EL_SB_DEFAULT].crumbled[act];
 
+#if 1
+      /* !!! make this better !!! */
+      if (i == EL_EMPTY_SPACE)
+      {
+       default_action_graphic = element_info[EL_DEFAULT].graphic[act];
+       default_action_crumbled = element_info[EL_DEFAULT].crumbled[act];
+      }
+#endif
+
       if (default_action_graphic == -1)
        default_action_graphic = default_graphic;
       if (default_action_crumbled == -1)
@@ -720,8 +732,8 @@ void InitElementGraphicInfo()
   if (options.verbose)
   {
     for (i = 0; i < MAX_NUM_ELEMENTS; i++)
-      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_CHAR_QUESTION &&
-         i != EL_CHAR_QUESTION)
+      if (element_info[i].graphic[ACTION_DEFAULT] == IMG_UNKNOWN &&
+         i != EL_UNKNOWN)
        Error(ERR_RETURN, "warning: no graphic for element '%s' (%d)",
              element_info[i].token_name, i);
   }
@@ -1557,6 +1569,157 @@ static void ReinitializeMusic()
   InitGameModeMusicInfo();     /* game mode music mapping */
 }
 
+static int get_special_property_bit(int element, int property_bit_nr)
+{
+  struct PropertyBitInfo
+  {
+    int element;
+    int bit_nr;
+  };
+
+  static struct PropertyBitInfo pb_can_move_into_acid[] =
+  {
+    /* the player may be able fall into acid when gravity is activated */
+    { EL_PLAYER_1,             0       },
+    { EL_PLAYER_2,             0       },
+    { EL_PLAYER_3,             0       },
+    { EL_PLAYER_4,             0       },
+    { EL_SP_MURPHY,            0       },
+
+    /* all element that can move may be able to also move into acid */
+    { EL_BUG,                  1       },
+    { EL_BUG_LEFT,             1       },
+    { EL_BUG_RIGHT,            1       },
+    { EL_BUG_UP,               1       },
+    { EL_BUG_DOWN,             1       },
+    { EL_SPACESHIP,            2       },
+    { EL_SPACESHIP_LEFT,       2       },
+    { EL_SPACESHIP_RIGHT,      2       },
+    { EL_SPACESHIP_UP,         2       },
+    { EL_SPACESHIP_DOWN,       2       },
+    { EL_BD_BUTTERFLY,         3       },
+    { EL_BD_BUTTERFLY_LEFT,    3       },
+    { EL_BD_BUTTERFLY_RIGHT,   3       },
+    { EL_BD_BUTTERFLY_UP,      3       },
+    { EL_BD_BUTTERFLY_DOWN,    3       },
+    { EL_BD_FIREFLY,           4       },
+    { EL_BD_FIREFLY_LEFT,      4       },
+    { EL_BD_FIREFLY_RIGHT,     4       },
+    { EL_BD_FIREFLY_UP,                4       },
+    { EL_BD_FIREFLY_DOWN,      4       },
+    { EL_YAMYAM,               5       },
+    { EL_DARK_YAMYAM,          6       },
+    { EL_ROBOT,                        7       },
+    { EL_PACMAN,               8       },
+    { EL_PACMAN_LEFT,          8       },
+    { EL_PACMAN_RIGHT,         8       },
+    { EL_PACMAN_UP,            8       },
+    { EL_PACMAN_DOWN,          8       },
+    { EL_MOLE,                 9       },
+    { EL_MOLE_LEFT,            9       },
+    { EL_MOLE_RIGHT,           9       },
+    { EL_MOLE_UP,              9       },
+    { EL_MOLE_DOWN,            9       },
+    { EL_PENGUIN,              10      },
+    { EL_PIG,                  11      },
+    { EL_DRAGON,               12      },
+    { EL_SATELLITE,            13      },
+    { EL_SP_SNIKSNAK,          14      },
+    { EL_SP_ELECTRON,          15      },
+    { EL_BALLOON,              16      },
+    { EL_SPRING,               17      },
+
+    { -1,                      -1      },
+  };
+
+  static struct PropertyBitInfo pb_dont_collide_with[] =
+  {
+    { EL_SP_SNIKSNAK,          0       },
+    { EL_SP_ELECTRON,          1       },
+
+    { -1,                      -1      },
+  };
+
+  static struct
+  {
+    int bit_nr;
+    struct PropertyBitInfo *pb_info;
+  } pb_definition[] =
+  {
+    { EP_CAN_MOVE_INTO_ACID,   pb_can_move_into_acid   },
+    { EP_DONT_COLLIDE_WITH,    pb_dont_collide_with    },
+
+    { -1,                      NULL                    },
+  };
+
+  struct PropertyBitInfo *pb_info = NULL;
+  int i;
+
+  for (i = 0; pb_definition[i].bit_nr != -1; i++)
+    if (pb_definition[i].bit_nr == property_bit_nr)
+      pb_info = pb_definition[i].pb_info;
+
+  if (pb_info == NULL)
+    return -1;
+
+  for (i = 0; pb_info[i].element != -1; i++)
+    if (pb_info[i].element == element)
+      return pb_info[i].bit_nr;
+
+  return -1;
+}
+
+#if 1
+void setBitfieldProperty(int *bitfield, int property_bit_nr, int element,
+                        boolean property_value)
+{
+  int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+  if (bit_nr > -1)
+  {
+    if (property_value)
+      *bitfield |=  (1 << bit_nr);
+    else
+      *bitfield &= ~(1 << bit_nr);
+  }
+}
+
+boolean getBitfieldProperty(int *bitfield, int property_bit_nr, int element)
+{
+  int bit_nr = get_special_property_bit(element, property_bit_nr);
+
+  if (bit_nr > -1)
+    return ((*bitfield & (1 << bit_nr)) != 0);
+
+  return FALSE;
+}
+
+#else
+
+void setMoveIntoAcidProperty(struct LevelInfo *level, int element, boolean set)
+{
+  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+  if (bit_nr > -1)
+  {
+    level->can_move_into_acid_bits &= ~(1 << bit_nr);
+
+    if (set)
+      level->can_move_into_acid_bits |= (1 << bit_nr);
+  }
+}
+
+boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element)
+{
+  int bit_nr = get_special_property_bit(element, EP_CAN_MOVE_INTO_ACID);
+
+  if (bit_nr > -1)
+    return ((level->can_move_into_acid_bits & (1 << bit_nr)) != 0);
+
+  return FALSE;
+}
+#endif
+
 void InitElementPropertiesStatic()
 {
   static int ep_diggable[] =
@@ -1814,6 +1977,7 @@ void InitElementPropertiesStatic()
 
   static int ep_can_move[] =
   {
+    /* same elements as in 'pb_can_move_into_acid' */
     EL_BUG,
     EL_SPACESHIP,
     EL_BD_BUTTERFLY,
@@ -1831,7 +1995,6 @@ void InitElementPropertiesStatic()
     EL_SP_ELECTRON,
     EL_BALLOON,
     EL_SPRING,
-    EL_MAZE_RUNNER,
     -1
   };
 
@@ -1934,6 +2097,9 @@ void InitElementPropertiesStatic()
     EL_SP_DISK_YELLOW,
     EL_SP_SNIKSNAK,
     EL_SP_ELECTRON,
+#if 0
+    EL_BLACK_ORB,
+#endif
     -1
   };
 
@@ -2068,6 +2234,26 @@ void InitElementPropertiesStatic()
     -1
   };
 
+  static int ep_can_explode_cross[] =
+  {
+    -1
+  };
+
+  static int ep_protected[] =
+  {
+    EL_EM_GATE_1,
+    EL_EM_GATE_2,
+    EL_EM_GATE_3,
+    EL_EM_GATE_4,
+    EL_EM_GATE_1_GRAY,
+    EL_EM_GATE_2_GRAY,
+    EL_EM_GATE_3_GRAY,
+    EL_EM_GATE_4_GRAY,
+    EL_SWITCHGATE_OPEN,
+    EL_TIMEGATE_OPEN,
+    -1
+  };
+
   static int ep_player[] =
   {
     EL_PLAYER_1,
@@ -2148,6 +2334,7 @@ void InitElementPropertiesStatic()
     EL_BD_BUTTERFLY_4,
     EL_BD_AMOEBA,
     EL_CHAR_QUESTION,
+    EL_UNKNOWN,
     -1
   };
 
@@ -2643,6 +2830,12 @@ void InitElementPropertiesStatic()
     -1
   };
 
+  static int ep_can_turn_each_move[] =
+  {
+    /* !!! do something !!! */
+    -1
+  };
+
   static int ep_active_bomb[] =
   {
     EL_DYNAMITE_ACTIVE,
@@ -2839,6 +3032,8 @@ void InitElementPropertiesStatic()
     { ep_droppable,            EP_DROPPABLE            },
     { ep_can_explode_1x1,      EP_CAN_EXPLODE_1X1      },
     { ep_pushable,             EP_PUSHABLE             },
+    { ep_can_explode_cross,    EP_CAN_EXPLODE_CROSS    },
+    { ep_protected,            EP_PROTECTED            },
 
     { ep_player,               EP_PLAYER               },
     { ep_can_pass_magic_wall,  EP_CAN_PASS_MAGIC_WALL  },
@@ -2861,6 +3056,7 @@ void InitElementPropertiesStatic()
     { ep_amoeboid,             EP_AMOEBOID             },
     { ep_amoebalive,           EP_AMOEBALIVE           },
     { ep_has_content,          EP_HAS_CONTENT          },
+    { ep_can_turn_each_move,   EP_CAN_TURN_EACH_MOVE   },
     { ep_active_bomb,          EP_ACTIVE_BOMB          },
     { ep_inactive,             EP_INACTIVE             },
 
@@ -2898,6 +3094,11 @@ void InitElementPropertiesStatic()
       EL_PACMAN_LEFT,          EL_PACMAN_RIGHT,
       EL_PACMAN_UP,            EL_PACMAN_DOWN
     },
+    {
+      EL_MOLE,
+      EL_MOLE_LEFT,            EL_MOLE_RIGHT,
+      EL_MOLE_UP,              EL_MOLE_DOWN
+    },
     {
       -1,
       -1, -1, -1, -1
@@ -2984,6 +3185,7 @@ void InitElementPropertiesEngine(int engine_version)
     EP_ACTIVE_BOMB,
 
     EP_ACCESSIBLE,
+
     -1
   };
 
@@ -2993,6 +3195,12 @@ void InitElementPropertiesEngine(int engine_version)
   InitElementPropertiesStatic();
 #endif
 
+  /* important: after initialization in InitElementPropertiesStatic(), the
+     elements are not again initialized to a default value; therefore all
+     changes have to make sure that they leave the element with a defined
+     property (which means that conditional property changes must be set to
+     a reliable default value before) */
+
   /* set all special, combined or engine dependent element properties */
   for (i = 0; i < MAX_NUM_ELEMENTS; i++)
   {
@@ -3002,8 +3210,7 @@ void InitElementPropertiesEngine(int engine_version)
 #endif
 
     /* ---------- INACTIVE ------------------------------------------------- */
-    if (i >= EL_CHAR_START && i <= EL_CHAR_END)
-      SET_PROPERTY(i, EP_INACTIVE, TRUE);
+    SET_PROPERTY(i, EP_INACTIVE, (i >= EL_CHAR_START && i <= EL_CHAR_END));
 
     /* ---------- WALKABLE, PASSABLE, ACCESSIBLE --------------------------- */
     SET_PROPERTY(i, EP_WALKABLE, (IS_WALKABLE_OVER(i) ||
@@ -3055,6 +3262,12 @@ void InitElementPropertiesEngine(int engine_version)
                                             !IS_DIGGABLE(i) &&
                                             !IS_COLLECTIBLE(i)));
 
+#if 1
+    /* ---------- PROTECTED ------------------------------------------------ */
+    if (IS_ACCESSIBLE_INSIDE(i))
+      SET_PROPERTY(i, EP_PROTECTED, TRUE);
+#endif
+
     /* ---------- DRAGONFIRE_PROOF ----------------------------------------- */
 
     if (IS_HISTORIC_SOLID(i) || i == EL_EXPLOSION)
@@ -3069,12 +3282,25 @@ void InitElementPropertiesEngine(int engine_version)
     else if (engine_version < VERSION_IDENT(2,2,0,0))
       SET_PROPERTY(i, EP_EXPLOSION_PROOF, IS_INDESTRUCTIBLE(i));
     else
+#if 1
+      SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
+                                          (!IS_WALKABLE(i) ||
+                                           IS_PROTECTED(i))));
+#else
+#if 1
       SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
                                           !IS_WALKABLE_OVER(i) &&
                                           !IS_WALKABLE_UNDER(i)));
+#else
+      SET_PROPERTY(i, EP_EXPLOSION_PROOF, (IS_INDESTRUCTIBLE(i) &&
+                                          IS_PROTECTED(i)));
+#endif
+#endif
 
     if (IS_CUSTOM_ELEMENT(i))
     {
+      /* these are additional properties which are initially false when set */
+
       /* ---------- DONT_COLLIDE_WITH / DONT_RUN_INTO ---------------------- */
       if (DONT_TOUCH(i))
        SET_PROPERTY(i, EP_DONT_COLLIDE_WITH, TRUE);
@@ -3100,7 +3326,47 @@ void InitElementPropertiesEngine(int engine_version)
 
     /* ---------- CAN_EXPLODE_3X3 ------------------------------------------ */
     SET_PROPERTY(i, EP_CAN_EXPLODE_3X3, (CAN_EXPLODE(i) &&
-                                        !CAN_EXPLODE_1X1(i)));
+                                        !CAN_EXPLODE_1X1(i) &&
+                                        !CAN_EXPLODE_CROSS(i)));
+
+    /* ---------- CAN_EXPLODE_BY_DRAGONFIRE -------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_BY_DRAGONFIRE, CAN_EXPLODE_BY_FIRE(i));
+
+    /* ---------- CAN_EXPLODE_BY_EXPLOSION --------------------------------- */
+    SET_PROPERTY(i, EP_CAN_EXPLODE_BY_EXPLOSION, (CAN_EXPLODE_BY_FIRE(i) ||
+                                                 i == EL_BLACK_ORB));
+
+    /* ---------- COULD_MOVE_INTO_ACID ------------------------------------- */
+    SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (ELEM_IS_PLAYER(i) ||
+                                             CAN_MOVE(i) ||
+                                             IS_CUSTOM_ELEMENT(i)));
+
+    /* ---------- MAYBE_DONT_COLLIDE_WITH ---------------------------------- */
+    SET_PROPERTY(i, EP_MAYBE_DONT_COLLIDE_WITH, (i == EL_SP_SNIKSNAK ||
+                                                i == EL_SP_ELECTRON));
+
+    /* ---------- CAN_MOVE_INTO_ACID --------------------------------------- */
+    if (COULD_MOVE_INTO_ACID(i) && !IS_CUSTOM_ELEMENT(i))
+      SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,
+                  getMoveIntoAcidProperty(&level, i));
+
+    /* ---------- DONT_COLLIDE_WITH ---------------------------------------- */
+    if (MAYBE_DONT_COLLIDE_WITH(i))
+      SET_PROPERTY(i, EP_DONT_COLLIDE_WITH,
+                  getDontCollideWithProperty(&level, i));
+
+    /* ---------- SP_PORT -------------------------------------------------- */
+    SET_PROPERTY(i, EP_SP_PORT, (IS_SP_ELEMENT(i) &&
+                                IS_PASSABLE_INSIDE(i)));
+
+#if 0
+    if (i == EL_CUSTOM_START + 253)
+      printf("::: %d, %d, %d -> %d\n",
+            CAN_EXPLODE_1X1(i),
+            CAN_EXPLODE_3X3(i),
+            CAN_EXPLODE_CROSS(i),
+            CAN_EXPLODE(i));
+#endif
 
     /* ---------- CAN_CHANGE ----------------------------------------------- */
     SET_PROPERTY(i, EP_CAN_CHANGE, FALSE);     /* default: cannot change */
@@ -3179,7 +3445,35 @@ void InitElementPropertiesEngine(int engine_version)
     if (element_info[element].push_delay_random == -1)
       element_info[element].push_delay_random = game.default_push_delay_random;
   }
+
+  /* set some other uninitialized values of custom elements in older levels */
+  if (engine_version < VERSION_IDENT(3,1,0,0))
+  {
+    for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+    {
+      int element = EL_CUSTOM_START + i;
+
+      element_info[element].access_direction = MV_ALL_DIRECTIONS;
+
+      element_info[element].explosion_delay = 17;
+      element_info[element].ignition_delay = 8;
+    }
+  }
+
+#if 0
+  /* set element properties that were handled incorrectly in older levels */
+  if (engine_version < VERSION_IDENT(3,1,0,0))
+  {
+    SET_PROPERTY(EL_SP_SNIKSNAK, EP_DONT_COLLIDE_WITH, FALSE);
+    SET_PROPERTY(EL_SP_ELECTRON, EP_DONT_COLLIDE_WITH, FALSE);
+  }
 #endif
+
+#endif
+
+  /* this is needed because some graphics depend on element properties */
+  if (game_status == GAME_MODE_PLAYING)
+    InitElementGraphicInfo();
 }
 
 static void InitGlobal()
@@ -3795,14 +4089,17 @@ static char *getNewArtworkIdentifier(int type)
   return artwork_new_identifier;
 }
 
-void ReloadCustomArtwork()
+void ReloadCustomArtwork(int force_reload)
 {
   char *gfx_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_GRAPHICS);
   char *snd_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_SOUNDS);
   char *mus_new_identifier = getNewArtworkIdentifier(ARTWORK_TYPE_MUSIC);
+  boolean force_reload_gfx = (force_reload & (1 << ARTWORK_TYPE_GRAPHICS));
+  boolean force_reload_snd = (force_reload & (1 << ARTWORK_TYPE_SOUNDS));
+  boolean force_reload_mus = (force_reload & (1 << ARTWORK_TYPE_MUSIC));
   boolean redraw_screen = FALSE;
 
-  if (gfx_new_identifier != NULL)
+  if (gfx_new_identifier != NULL || force_reload_gfx)
   {
 #if 0
     printf("RELOADING GRAPHICS '%s' -> '%s' ['%s', '%s']\n",
@@ -3827,7 +4124,7 @@ void ReloadCustomArtwork()
     redraw_screen = TRUE;
   }
 
-  if (snd_new_identifier != NULL)
+  if (snd_new_identifier != NULL || force_reload_snd)
   {
     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);
 
@@ -3836,7 +4133,7 @@ void ReloadCustomArtwork()
     redraw_screen = TRUE;
   }
 
-  if (mus_new_identifier != NULL)
+  if (mus_new_identifier != NULL || force_reload_mus)
   {
     ClearRectangle(window, 0, 0, WIN_XSIZE, WIN_YSIZE);