From ac0b7706bf6edba12ba74f9962ff2e617f9ad41a Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Wed, 18 Feb 2004 03:22:59 +0100 Subject: [PATCH] =?utf8?q?rnd-20040218-1-src=20*=20fixed=20bug=20which=20c?= =?utf8?q?aused=20all=20CE=20change=20pages=20to=20be=20ignored=20which=20?= =?utf8?q?had=20=20=20the=20same=20change=20event,=20but=20used=20a=20diff?= =?utf8?q?erent=20element=20side=20=20=20(reported=20by=20Simon=20Forsberg?= =?utf8?q?)=20*=20fixed=20bug=20which=20caused=20elements=20that=20can=20m?= =?utf8?q?ove=20and=20fall=20and=20that=20are=20=20=20transported=20by=20a?= =?utf8?q?=20conveyor=20belt=20to=20continue=20moving=20into=20that=20dire?= =?utf8?q?ction=20=20=20after=20leaving=20the=20conveyor=20belt,=20regardl?= =?utf8?q?ess=20of=20their=20own=20movement=20=20=20type;=20only=20element?= =?utf8?q?s=20which=20can=20not=20move=20are=20transported=20now=20=20=20(?= =?utf8?q?reported=20by=20Simon=20Forsberg)=20*=20fixed=20bug=20which=20co?= =?utf8?q?uld=20cause=20an=20array=20overflow=20in=20RelocatePlayer()=20?= =?utf8?q?=20=20(reported=20by=20Niko=20B=F6hm)=20*=20changed=20Emerald=20?= =?utf8?q?Mine=20style=20"passable=20/=20over"=20elements=20to=20"protecte?= =?utf8?q?d"=20=20=20(fixing=20unsolvable=20level=2010=20of=20"Bondmine=20?= =?utf8?q?9"=20with=20bug=20beside=20gate)=20*=20added=20new=20option=20to?= =?utf8?q?=20select=20from=20which=20side=20a=20"walkable/passable"=20=20?= =?utf8?q?=20element=20can=20be=20entered=20*=20added=20explosion=20and=20?= =?utf8?q?ignition=20delay=20for=20elements=20that=20can=20explode=20*=20f?= =?utf8?q?ixed=20bug=20which=20caused=20player=20not=20being=20protected?= =?utf8?q?=20against=20enemies=20=20=20when=20a=20CE=20was=20"walkable=20/?= =?utf8?q?=20inside"=20and=20was=20not=20"indestructible"=20*=20added=20"w?= =?utf8?q?alkable/passable"=20fields=20to=20be=20"protected/unprotected"?= =?utf8?q?=20=20=20against=20enemies,=20even=20if=20not=20accessible=20"in?= =?utf8?q?side"=20but=20"over/under"?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit --- CHANGES | 2 +- ChangeLog | 30 ++++++++++++++++++++++ src/conf_e2g.c | 32 ++++++++++++++++++++++++ src/conftime.h | 2 +- src/editor.c | 60 ++++++++++++++++++++++++++------------------ src/files.c | 14 +++++++++-- src/game.c | 68 +++++++++++++++++++++++++++++++++++++++++++++----- src/init.c | 22 ++++++++++++++++ 8 files changed, 196 insertions(+), 34 deletions(-) diff --git a/CHANGES b/CHANGES index cb2335db..e949e68f 100644 --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,4 @@ -Release Version 3.0.9 [?? ??? ????] +Release Version 3.1.0 [?? ??? ????] ----------------------------------- Release Version 3.0.8 [14 DEC 2003] diff --git a/ChangeLog b/ChangeLog index 6e0badcc..e2a771a2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,32 @@ +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 @@ -6,6 +35,7 @@ 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) diff --git a/src/conf_e2g.c b/src/conf_e2g.c index 583c2c3e..1bbae6db 100644 --- a/src/conf_e2g.c +++ b/src/conf_e2g.c @@ -2525,6 +2525,38 @@ element_to_graphic[] = 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 diff --git a/src/conftime.h b/src/conftime.h index 52757080..3a1d4df0 100644 --- a/src/conftime.h +++ b/src/conftime.h @@ -1 +1 @@ -#define COMPILE_DATE_STRING "[2004-02-17 19:34]" +#define COMPILE_DATE_STRING "[2004-02-18 02:49]" diff --git a/src/editor.c b/src/editor.c index 51c842b9..9cd163a5 100644 --- a/src/editor.c +++ b/src/editor.c @@ -127,13 +127,14 @@ /* 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 */ @@ -1785,21 +1786,21 @@ static struct /* ---------- 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, @@ -2021,10 +2022,10 @@ static struct /* ---------- 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 --------------------------------------------- */ @@ -4835,8 +4836,10 @@ void FreeLevelEditorGadgets() 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]; @@ -4857,6 +4860,17 @@ static void MapCounterButtons(int id) 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); @@ -4868,9 +4882,9 @@ static void MapCounterButtons(int id) 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() @@ -6644,8 +6658,14 @@ static void DrawPropertiesConfig() { 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; @@ -6655,9 +6675,7 @@ static void DrawPropertiesConfig() 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); @@ -6692,9 +6710,7 @@ static void DrawPropertiesConfig() 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) { @@ -6748,9 +6764,7 @@ static void DrawPropertiesConfig() 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); @@ -6794,9 +6808,7 @@ static void DrawPropertiesChange() 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; diff --git a/src/files.c b/src/files.c index c7af57d1..356d8a4b 100644 --- a/src/files.c +++ b/src/files.c @@ -1011,8 +1011,13 @@ static int LoadLevel_CUS4(FILE *file, int chunk_size, struct LevelInfo *level) /* ... 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 */ @@ -2582,8 +2587,13 @@ static void SaveLevel_CUS4(FILE *file, struct LevelInfo *level, int element) /* ... 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 */ diff --git a/src/game.c b/src/game.c index 572758d9..77df179d 100644 --- a/src/game.c +++ b/src/game.c @@ -497,6 +497,28 @@ collect_count_list[] = { 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 & \ @@ -1157,6 +1179,18 @@ static void InitGameEngine() 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; } @@ -2731,8 +2765,10 @@ void Explode(int ex, int ey, int phase, int mode) 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)) { @@ -2741,8 +2777,10 @@ void Explode(int ex, int ey, int phase, int mode) 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) { @@ -2750,11 +2788,13 @@ void Explode(int ex, int ey, int phase, int mode) 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 @@ -7773,9 +7813,14 @@ static void CheckGravityMovement(struct PlayerInfo *player) 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; } } @@ -8901,6 +8946,7 @@ int DigField(struct PlayerInfo *player, 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) @@ -8923,6 +8969,8 @@ int DigField(struct PlayerInfo *player, 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 @@ -8959,8 +9007,15 @@ int DigField(struct PlayerInfo *player, 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]; @@ -9035,6 +9090,7 @@ int DigField(struct PlayerInfo *player, PlayLevelSound(x, y, SND_CLASS_SP_PORT_PASSING); break; +#if 0 case EL_TUBE_ANY: case EL_TUBE_VERTICAL: case EL_TUBE_HORIZONTAL: @@ -9077,6 +9133,7 @@ int DigField(struct PlayerInfo *player, PlayLevelSound(x, y, SND_CLASS_TUBE_WALKING); } break; +#endif default: @@ -9084,8 +9141,7 @@ int DigField(struct PlayerInfo *player, { 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) diff --git a/src/init.c b/src/init.c index cfb271b1..142c21bc 100644 --- a/src/init.c +++ b/src/init.c @@ -2089,6 +2089,16 @@ void InitElementPropertiesStatic() 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 }; @@ -3242,6 +3252,18 @@ 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,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 */ -- 2.34.1