-Release Version 3.0.9 [?? ??? ????]
+Release Version 3.1.0 [?? ??? ????]
-----------------------------------
Release Version 3.0.8 [14 DEC 2003]
+2004-02-17
+ * fixed bug which caused all CE change pages to be ignored which had
+ the same change event, but used a different element side
+ (reported by Simon Forsberg)
+
+ * fixed bug which caused elements that can move and fall and that are
+ transported by a conveyor belt to continue moving into that direction
+ after leaving the conveyor belt, regardless of their own movement
+ type; only elements which can not move are transported now
+ (reported by Simon Forsberg)
+
+ * fixed bug which could cause an array overflow in RelocatePlayer()
+ (reported by Niko Böhm)
+
+ * changed Emerald Mine style "passable / over" elements to "protected"
+ (fixing unsolvable level 10 of "Bondmine 9" with bug beside gate)
+
+ * added new option to select from which side a "walkable/passable"
+ element can be entered
+
+2004-02-16
+ * added explosion and ignition delay for elements that can explode
+
+2004-02-05
+ * fixed bug which caused player not being protected against enemies
+ when a CE was "walkable / inside" and was not "indestructible"
+ * added "walkable/passable" fields to be "protected/unprotected"
+ against enemies, even if not accessible "inside" but "over/under"
+
2004-02-04
* corrected move pattern to 32 bit and initial move direction to 8 bit
2004-02-02
* added some special EMC mappings to Emerald Mine level loader
+ (also covering previously unknown element in level 0 of "Bondmine 8")
2004-01-30
* added option to block last field when player is moving (for Supaplex)
EL_UNKNOWN, -1, -1, FALSE,
IMG_UNKNOWN
},
+ {
+ EL_BD_BUTTERFLY_DOWN, -1, -1, FALSE,
+ IMG_BD_BUTTERFLY
+ },
+ {
+ EL_BD_BUTTERFLY_LEFT, -1, -1, FALSE,
+ IMG_BD_BUTTERFLY
+ },
+ {
+ EL_BD_BUTTERFLY_RIGHT, -1, -1, FALSE,
+ IMG_BD_BUTTERFLY
+ },
+ {
+ EL_BD_BUTTERFLY_UP, -1, -1, FALSE,
+ IMG_BD_BUTTERFLY
+ },
+ {
+ EL_BD_FIREFLY_DOWN, -1, -1, FALSE,
+ IMG_BD_FIREFLY
+ },
+ {
+ EL_BD_FIREFLY_LEFT, -1, -1, FALSE,
+ IMG_BD_FIREFLY
+ },
+ {
+ EL_BD_FIREFLY_RIGHT, -1, -1, FALSE,
+ IMG_BD_FIREFLY
+ },
+ {
+ EL_BD_FIREFLY_UP, -1, -1, FALSE,
+ IMG_BD_FIREFLY
+ },
{
EL_DOOR_WHITE, -1, -1, FALSE,
IMG_CHAR_QUESTION
-#define COMPILE_DATE_STRING "[2004-02-17 19:34]"
+#define COMPILE_DATE_STRING "[2004-02-18 02:49]"
/* values for element content drawing areas */
/* amoeba content */
-#define ED_AREA_ELEM_CONTENT_XPOS ( 2 * MINI_TILEX)
-#define ED_AREA_ELEM_CONTENT_YPOS (22 * MINI_TILEY)
+#define ED_AREA_AMOEBA_CONTENT_XPOS ED_SETTINGS_XPOS(0)
+#define ED_AREA_AMOEBA_CONTENT_YPOS (ED_SETTINGS_YPOS(2) + \
+ ED_GADGET_DISTANCE)
/* yamyam content */
-#define ED_AREA_YAMYAM_CONTENT_XPOS(n) (ED_AREA_ELEM_CONTENT_XPOS + \
+#define ED_AREA_YAMYAM_CONTENT_XPOS(n) (2 * MINI_TILEX + \
5 * (n % 4) * MINI_TILEX)
-#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (ED_AREA_ELEM_CONTENT_YPOS + \
+#define ED_AREA_YAMYAM_CONTENT_YPOS(n) (22 * MINI_TILEY + \
6 * (n / 4) * MINI_TILEY)
/* custom change target */
/* ---------- element settings: configure (various elements) ------------- */
{
- ED_SETTINGS_XPOS(0), 0, /* set at runtime */
+ ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(0),
GADGET_ID_STICK_ELEMENT, GADGET_ID_NONE,
&stick_element_properties_window,
NULL,
"stick this screen to edit content","stick this screen to edit content"
},
{
- ED_SETTINGS_XPOS(0), ED_COUNTER_YPOS(4),
+ ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(1),
GADGET_ID_EM_SLIPPERY_GEMS, GADGET_ID_NONE,
&level.em_slippery_gems,
NULL,
"slip down from certain flat walls","use EM style slipping behaviour"
},
{
- ED_SETTINGS_XPOS(0), ED_COUNTER_YPOS(4),
+ ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(0),
GADGET_ID_BLOCK_LAST_FIELD, GADGET_ID_NONE,
&level.block_last_field,
NULL,
/* ---------- amoeba content --------------------------------------------- */
{
- ED_AREA_ELEM_CONTENT_XPOS, ED_AREA_ELEM_CONTENT_YPOS,
+ ED_AREA_AMOEBA_CONTENT_XPOS, ED_AREA_AMOEBA_CONTENT_YPOS,
1, 1,
GADGET_ID_AMOEBA_CONTENT, GADGET_ID_NONE,
- NULL, "content of amoeba", NULL
+ "content:", NULL, NULL
},
/* ---------- custom graphic --------------------------------------------- */
static void MapCounterButtons(int id)
{
int gadget_id_down = counterbutton_info[id].gadget_id_down;
+ int gadget_id_text = counterbutton_info[id].gadget_id_text;
int gadget_id_up = counterbutton_info[id].gadget_id_up;
struct GadgetInfo *gi_down = level_editor_gadget[gadget_id_down];
+ struct GadgetInfo *gi_text = level_editor_gadget[gadget_id_text];
struct GadgetInfo *gi_up = level_editor_gadget[gadget_id_up];
#if 0
char infotext[MAX_OUTPUT_LINESIZE + 1];
int y = gi_up->y + yoffset;
#endif
+#if 1
+ /* special case needed for "score" counter gadget */
+ if (id == ED_COUNTER_ID_ELEMENT_SCORE)
+ {
+ ModifyGadget(gi_down, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
+ ModifyGadget(gi_text, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
+ ModifyGadget(gi_up, GDI_Y, SY + counterbutton_info[id].y, GDI_END);
+ y = gi_up->y + yoffset;
+ }
+#endif
+
if (counterbutton_info[id].text_above)
DrawText(x, y_above, counterbutton_info[id].text_above, FONT_TEXT_1);
ModifyEditorCounter(id, *counterbutton_info[id].value);
- MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_down]);
- MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_text]);
- MapGadget(level_editor_gadget[counterbutton_info[id].gadget_id_up]);
+ MapGadget(gi_down);
+ MapGadget(gi_text);
+ MapGadget(gi_up);
}
static void MapControlButtons()
{
int counter_id = ED_COUNTER_ID_ELEMENT_SCORE;
+ if (HAS_CONTENT(properties_element)) /* needs stickybutton */
+ counterbutton_info[counter_id].y = ED_SETTINGS_YPOS(1);
+ else
+ counterbutton_info[counter_id].y = ED_SETTINGS_YPOS(0);
+
counterbutton_info[counter_id].value = elements_with_counter[i].value;
counterbutton_info[counter_id].text_right= elements_with_counter[i].text;
+
MapCounterButtons(counter_id);
break;
if (HAS_CONTENT(properties_element))
{
/* draw stickybutton gadget */
- i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
- checkbutton_info[i].y = ED_COUNTER_YPOS(4);
- MapCheckbuttonGadget(i);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
if (IS_AMOEBOID(properties_element))
MapDrawingArea(ED_DRAWING_ID_AMOEBA_CONTENT);
if (IS_CUSTOM_ELEMENT(properties_element))
{
/* draw stickybutton gadget */
- i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
- checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
- MapCheckbuttonGadget(i);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
if (edit_mode_properties == ED_MODE_PROPERTIES_CONFIG_1)
{
else if (IS_GROUP_ELEMENT(properties_element))
{
/* draw stickybutton gadget */
- i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
- checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
- MapCheckbuttonGadget(i);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
/* draw checkbutton gadgets */
MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC);
int i;
/* draw stickybutton gadget */
- i = ED_CHECKBUTTON_ID_STICK_ELEMENT;
- checkbutton_info[i].y = ED_SETTINGS_YPOS(0);
- MapCheckbuttonGadget(i);
+ MapCheckbuttonGadget(ED_CHECKBUTTON_ID_STICK_ELEMENT);
/* draw checkbutton gadgets */
for (i = ED_CHECKBUTTON_ID_CHANGE_FIRST;
/* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
ei->move_pattern |= (getFile16BitBE(file) << 16);
+ ei->access_direction = getFile8Bit(file);
+
+ ei->explosion_delay = getFile8Bit(file);
+ ei->ignition_delay = getFile8Bit(file);
+
/* some free bytes for future custom property values and padding */
- ReadUnusedBytesFromFile(file, 5);
+ ReadUnusedBytesFromFile(file, 2);
/* read change property values */
/* ... bits 16 - 31 of "move_pattern" (not nice, but downward compatible) */
putFile16BitBE(file, (ei->move_pattern >> 16) & 0xffff);
+ putFile8Bit(file, ei->access_direction);
+
+ putFile8Bit(file, ei->explosion_delay);
+ putFile8Bit(file, ei->ignition_delay);
+
/* some free bytes for future custom property values and padding */
- WriteUnusedBytesToFile(file, 5);
+ WriteUnusedBytesToFile(file, 2);
/* write change property values */
{ EL_UNDEFINED, 0 },
};
+struct
+{
+ int element;
+ int direction;
+}
+tube_access[] =
+{
+ { EL_TUBE_ANY, MV_LEFT | MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_TUBE_VERTICAL, MV_UP | MV_DOWN },
+ { EL_TUBE_HORIZONTAL, MV_LEFT | MV_RIGHT },
+ { EL_TUBE_VERTICAL_LEFT, MV_LEFT | MV_UP | MV_DOWN },
+ { EL_TUBE_VERTICAL_RIGHT, MV_RIGHT | MV_UP | MV_DOWN },
+ { EL_TUBE_HORIZONTAL_UP, MV_LEFT | MV_RIGHT | MV_UP },
+ { EL_TUBE_HORIZONTAL_DOWN, MV_LEFT | MV_RIGHT | MV_DOWN },
+ { EL_TUBE_LEFT_UP, MV_LEFT | MV_UP },
+ { EL_TUBE_LEFT_DOWN, MV_LEFT | MV_DOWN },
+ { EL_TUBE_RIGHT_UP, MV_RIGHT | MV_UP },
+ { EL_TUBE_RIGHT_DOWN, MV_RIGHT | MV_DOWN },
+
+ { EL_UNDEFINED, 0 }
+};
+
static unsigned long trigger_events[MAX_NUM_ELEMENTS];
#define IS_AUTO_CHANGING(e) (element_info[e].change_events & \
for (i = 0; collect_count_list[i].element != EL_UNDEFINED; i++)
element_info[collect_count_list[i].element].collect_count =
collect_count_list[i].count;
+
+ /* ---------- initialize access direction -------------------------------- */
+
+ /* initialize access direction values to default */
+ for (i = 0; i < MAX_NUM_ELEMENTS; i++)
+ if (!IS_CUSTOM_ELEMENT(i))
+ element_info[i].access_direction = MV_ALL_DIRECTIONS;
+
+ /* set access direction value for certain elements from pre-defined list */
+ for (i = 0; tube_access[i].element != EL_UNDEFINED; i++)
+ element_info[tube_access[i].element].access_direction =
+ tube_access[i].direction;
}
KillHeroUnlessExplosionProtected(x, y);
border_explosion = TRUE;
+#if 0
if (phase == last_phase)
printf("::: IS_PLAYER\n");
+#endif
}
else if (CAN_EXPLODE_BY_EXPLOSION(border_element))
{
Bang(x, y);
border_explosion = TRUE;
+#if 0
if (phase == last_phase)
printf("::: CAN_EXPLODE_BY_EXPLOSION\n");
+#endif
}
else if (border_element == EL_AMOEBA_TO_DIAMOND)
{
Store2[x][y] = 0;
border_explosion = TRUE;
+#if 0
if (phase == last_phase)
printf("::: EL_AMOEBA_TO_DIAMOND [%d, %d] [%d]\n",
element_info[border_element].explosion_delay,
element_info[border_element].ignition_delay,
phase);
+#endif
}
#if 1
canEnterSupaplexPort(new_jx, new_jy, dx, dy))));
/* !!! extend EL_SAND to anything diggable !!! */
+ boolean player_is_standing_on_valid_field =
+ (IS_WALKABLE_INSIDE(Feld[jx][jy]) ||
+ (IS_WALKABLE(Feld[jx][jy]) &&
+ !(element_info[Feld[jx][jy]].access_direction & MV_DOWN)));
+
if (field_under_player_is_free &&
- !player_is_moving_to_valid_field &&
- !IS_WALKABLE_INSIDE(Feld[jx][jy]))
+ !player_is_standing_on_valid_field &&
+ !player_is_moving_to_valid_field)
player->programmed_action = MV_DOWN;
}
}
dy == +1 ? MV_DOWN : MV_NO_MOVING);
int opposite_direction = MV_DIR_OPPOSITE(move_direction);
int dig_side = change_sides[MV_DIR_BIT(move_direction)];
+ int old_element = Feld[jx][jy];
int element;
if (player->MovPos == 0)
if (IS_MOVING(x, y) || IS_PLAYER(x, y))
return MF_NO_ACTION;
+#if 0
+
#if 0
if (IS_TUBE(Feld[jx][jy]) || IS_TUBE(Back[jx][jy]))
#else
return MF_NO_ACTION; /* tube has no opening in this direction */
}
- if (IS_CUSTOM_ELEMENT(Feld[jx][jy]) && IS_WALKABLE(Feld[jx][jy]) &&
- !(element_info[Feld[jx][jy]].access_direction & move_direction))
+#else
+
+ if (IS_TUBE(Back[jx][jy]) && game.engine_version >= VERSION_IDENT(2,2,0,0))
+ old_element = Back[jx][jy];
+
+#endif
+
+ if (IS_WALKABLE(old_element) &&
+ !(element_info[old_element].access_direction & move_direction))
return MF_NO_ACTION; /* field has no opening in this direction */
element = Feld[x][y];
PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING);
break;
+#if 0
case EL_TUBE_ANY:
case EL_TUBE_VERTICAL:
case EL_TUBE_HORIZONTAL:
PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING);
}
break;
+#endif
default:
{
int sound_action = ACTION_WALKING;
- if (IS_CUSTOM_ELEMENT(element) &&
- !(element_info[element].access_direction & opposite_direction))
+ if (!(element_info[element].access_direction & opposite_direction))
return MF_NO_ACTION; /* field not accessible from this direction */
if (element >= EL_GATE_1 && element <= EL_GATE_4)
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
};
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,0,9,0))
+ {
+ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+
+ element_info[element].explosion_delay = 18;
+ element_info[element].ignition_delay = 8;
+ }
+ }
#endif
/* this is needed because some graphics depend on element properties */