From 5216f629803d5255919cadc2419fb1e798812ae2 Mon Sep 17 00:00:00 2001 From: Holger Schemel Date: Sat, 13 Mar 2004 11:01:25 +0100 Subject: [PATCH] rnd-20040313-1-src * "can move into acid" property now for all elements independently * "can fall into acid" property for player stored in same bitfield now * added option for deadliness for sp_sniksnak and sp_electron * version number set to 3.1.0 (finally!) --- ChangeLog | 67 +++++++++--------- src/conftime.h | 2 +- src/editor.c | 124 +++++++++++++++++++-------------- src/files.c | 25 +++---- src/game.c | 179 +++++++++++++++++++++++++++++------------------ src/init.c | 184 ++++++++++++++++++++++++++++++++++--------------- src/init.h | 21 ++++++ src/main.h | 26 +++---- 8 files changed, 394 insertions(+), 234 deletions(-) diff --git a/ChangeLog b/ChangeLog index ef2f8645..438cbfc3 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,11 @@ +2004-03-13 + * "can move into acid" property now for all elements independently + * "can fall into acid" property for player stored in same bitfield now + * added option for deadliness for sp_sniksnak and sp_electron + * version number set to 3.1.0 (finally!) + 2004-03-09 * changed tape recording to only record input, not programmed actions - * YET TO COME ... added option ... for sp_sniksnak and sp_electron 2004-03-08 * fixed totally broken (every 8th frame skipped) step-by-step recording @@ -154,10 +159,10 @@ * fixed bug with wrong "Murphy" graphics (when digging etc.) 2003-12-14 - * Version number set to 3.0.9. + * version number set to 3.0.9 2003-12-14 - * Version 3.0.8 released. + * version 3.0.8 released 2003-12-13 * added function checked_free() @@ -220,10 +225,10 @@ * enhanced sniksnak turning movement (two steps instead of only one) 2003-11-10 - * Version number set to 3.0.8. + * version number set to 3.0.8 2003-11-10 - * Version 3.0.7 released. + * version 3.0.7 released 2003-11-09 * fixed reset of player animation frame when, for example, @@ -270,10 +275,10 @@ * fixed bug with player not getting smashed by rock sometimes 2003-10-06 - * Version number set to 3.0.7. + * version number set to 3.0.7 2003-10-06 - * Version 3.0.6 released. + * version 3.0.6 released 2003-10-05 * added support for MP3 music for SDL version through SMPEG library @@ -292,10 +297,10 @@ * fixed element tokens for certain file elements with ".active" etc. 2003-09-29 - * Version number set to 3.0.6. + * version number set to 3.0.6 2003-09-29 - * Version 3.0.5 released. + * version 3.0.5 released 2003-09-28 * now four envelope elements available @@ -313,10 +318,10 @@ * enhanced (remaining low-resolution) Supaplex graphics 2003-09-13 - * Version number set to 3.0.5. + * version number set to 3.0.5 2003-09-13 - * Version 3.0.4 released. + * version 3.0.4 released 2003-09-12 src/tools.c * fixed bug in custom definition of crumbled element graphics @@ -325,10 +330,10 @@ * fixed bug in multiple config pages code that caused crashes 2003-09-08 - * Version number set to 3.0.4. + * version number set to 3.0.4 2003-09-08 - * Version 3.0.3 released. + * version 3.0.3 released 2003-09-07 * added music to Supaplex classic level set @@ -354,10 +359,10 @@ * fixed bug (missing array boundary check) which could crash the game 2003-08-23 - * Version number set to 3.0.3. + * version number set to 3.0.3 2003-08-22 - * Version 3.0.2 released. + * version 3.0.2 released 2003-08-21 src/game.c * fixed bug with creating inaccessible elements at player position @@ -370,10 +375,10 @@ * fixed bug with messing up custom element properties in 3.0.0 levels 2003-08-18 - * Version number set to 3.0.2. + * version number set to 3.0.2 2003-08-18 - * Version 3.0.1 released. + * version 3.0.1 released 2003-08-17 (no source files affected) * changed all "classic" PCX image files with 16 colors or less to @@ -420,18 +425,18 @@ * fixed bug with missing graphic for active red disk bomb 2003-08-07 src/files.c, src/editor.c src/game.c, src/main.h - * Extended variable "level.gravity" to "level.initial_gravity" and + * extended variable "level.gravity" to "level.initial_gravity" and "game.current_gravity" to prevent level setting from being changed - by playing the level (keeping the runtime value after playing). + by playing the level (keeping the runtime value after playing) - * Fixed graphics bug when digging element that has 'crumbled' graphic - definition, but not 'diggable' graphic definition. + * fixed graphics bug when digging element that has 'crumbled' graphic + definition, but not 'diggable' graphic definition 2003-08-06 - * Version number set to 3.0.1. + * version number set to 3.0.1 2003-08-05 - * Version 3.0.0 released. + * version 3.0.0 released 2003-08-05 * various bug fixes; among others: @@ -441,26 +446,26 @@ - allow Murphy player graphic in levels with non-Supaplex elements 2003-04-07 - * Various changes. - * I have forgotten to document changes for some time. + * various changes + * I have forgotten to document changes for some time 2002-12-31 - * Pre-Release Version 2.2.0rc1 released. + * pre-release version 2.2.0rc1 released 2002-08-25 - * Version number set to 2.1.2. + * version number set to 2.1.2 2002-08-13 - * Version 2.1.1 released. + * version 2.1.1 released 2002-08-10 - * Version number set to 2.1.1. + * version number set to 2.1.1 2002-08-05 - * Version 2.1.0 released. + * version 2.1.0 released 2002-05-19 - * Version number set to 2.1.0. + * version number set to 2.1.0 2002-04-03 to 2002-05-19 (various source files) * graphics, sounds and music now fully configurable diff --git a/src/conftime.h b/src/conftime.h index 8605b781..ff34cb78 100644 --- a/src/conftime.h +++ b/src/conftime.h @@ -1 +1 @@ -#define COMPILE_DATE_STRING "[2004-03-10 01:26]" +#define COMPILE_DATE_STRING "[2004-03-13 04:25]" diff --git a/src/editor.c b/src/editor.c index b20ff454..af251d33 100644 --- a/src/editor.c +++ b/src/editor.c @@ -513,30 +513,31 @@ #define GADGET_ID_SP_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 9) #define GADGET_ID_CAN_FALL_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 10) #define GADGET_ID_CAN_MOVE_INTO_ACID (GADGET_ID_CHECKBUTTON_FIRST + 11) -#define GADGET_ID_CUSTOM_EXPLODE_RESULT (GADGET_ID_CHECKBUTTON_FIRST + 12) -#define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 13) -#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 14) -#define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 15) -#define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 16) -#define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 17) -#define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 18) -#define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 19) -#define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 20) -#define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 21) -#define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 22) -#define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 23) -#define GADGET_ID_CUSTOM_USE_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 24) -#define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 25) -#define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 26) -#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 27) -#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 28) -#define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 29) -#define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 30) -#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 31) -#define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 32) +#define GADGET_ID_DONT_COLLIDE_WITH (GADGET_ID_CHECKBUTTON_FIRST + 12) +#define GADGET_ID_CUSTOM_EXPLODE_RESULT (GADGET_ID_CHECKBUTTON_FIRST + 13) +#define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 14) +#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 15) +#define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 16) +#define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 17) +#define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 18) +#define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 19) +#define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 20) +#define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 21) +#define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 22) +#define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 23) +#define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 24) +#define GADGET_ID_CUSTOM_USE_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 25) +#define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 26) +#define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 27) +#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 28) +#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 29) +#define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 30) +#define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 31) +#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 32) +#define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 33) /* gadgets for buttons in element list */ -#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 33) +#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 34) #define GADGET_ID_ELEMENTLIST_LAST (GADGET_ID_ELEMENTLIST_FIRST + \ ED_NUM_ELEMENTLIST_BUTTONS - 1) @@ -706,29 +707,30 @@ #define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD 7 #define ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID 8 #define ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID 9 -#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 10 -#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 11 -#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE 12 -#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 13 -#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE 14 -#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL 15 -#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH 16 -#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY 17 -#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY 18 -#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT 19 -#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE 20 -#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 21 -#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 22 -#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 23 -#define ED_CHECKBUTTON_ID_CHANGE_DELAY 24 -#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 25 -#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 26 -#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 27 -#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 28 -#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 29 -#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 30 - -#define ED_NUM_CHECKBUTTONS 31 +#define ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH 10 +#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 11 +#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 12 +#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE 13 +#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 14 +#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE 15 +#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL 16 +#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH 17 +#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY 18 +#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY 19 +#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT 20 +#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE 21 +#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 22 +#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 23 +#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 24 +#define ED_CHECKBUTTON_ID_CHANGE_DELAY 25 +#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 26 +#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 27 +#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 28 +#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 29 +#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 30 +#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 31 + +#define ED_NUM_CHECKBUTTONS 32 #define ED_CHECKBUTTON_ID_LEVEL_FIRST ED_CHECKBUTTON_ID_DOUBLE_SPEED #define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED @@ -1942,7 +1944,7 @@ static struct { ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(0), GADGET_ID_CAN_FALL_INTO_ACID, GADGET_ID_NONE, - &level.player_can_fall_into_acid, + &custom_element_properties[EP_CAN_MOVE_INTO_ACID], NULL, "can fall into acid (with gravity)","player can fall into acid pool" }, @@ -1953,6 +1955,13 @@ static struct NULL, "can move into acid", "element can move into acid pool" }, + { + ED_SETTINGS_XPOS(0), ED_SETTINGS_YPOS(1), + GADGET_ID_DONT_COLLIDE_WITH, GADGET_ID_NONE, + &custom_element_properties[EP_DONT_COLLIDE_WITH], + NULL, + "deadly when colliding with", "element is deadly when hitting player" + }, /* ---------- element settings: configure 1 (custom elements) ----------- */ @@ -5217,8 +5226,7 @@ static void MapCheckbuttonGadget(int id) int y; /* set after gadget position was modified */ /* set position for "stickybutton" and "can move into acid" gadgets */ - if (id == ED_CHECKBUTTON_ID_STICK_ELEMENT || - id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID) + if (id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID) ModifyGadget(gi, GDI_Y, SY + checkbutton_info[id].y, GDI_END); y = gi->y + yoffset; @@ -5790,10 +5798,13 @@ static void CopyGroupElementPropertiesToEditor(int element) static void CopyClassicElementPropertiesToEditor(int element) { #if 1 - if (COULD_MOVE_INTO_ACID(element)) + if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element)) custom_element_properties[EP_CAN_MOVE_INTO_ACID] = getMoveIntoAcidProperty(&level, element); + if (MAYBE_DONT_COLLIDE_WITH(element)) + custom_element_properties[EP_DONT_COLLIDE_WITH] = + getDontCollideWithProperty(&level, element); #else if (COULD_MOVE_INTO_ACID(element)) @@ -5966,10 +5977,13 @@ static void CopyGroupElementPropertiesToGame(int element) static void CopyClassicElementPropertiesToGame(int element) { #if 1 - if (COULD_MOVE_INTO_ACID(element)) + if (ELEM_IS_PLAYER(element) || COULD_MOVE_INTO_ACID(element)) setMoveIntoAcidProperty(&level, element, custom_element_properties[EP_CAN_MOVE_INTO_ACID]); + if (MAYBE_DONT_COLLIDE_WITH(element)) + setDontCollideWithProperty(&level, element, + custom_element_properties[EP_DONT_COLLIDE_WITH]); #else if (COULD_MOVE_INTO_ACID(element)) @@ -6836,7 +6850,7 @@ static boolean checkPropertiesConfig(int element) ELEM_IS_PLAYER(element) || HAS_CONTENT(element) || COULD_MOVE_INTO_ACID(element) || - element == EL_SPRING) + MAYBE_DONT_COLLIDE_WITH(element)) return TRUE; else for (i = 0; elements_with_counter[i].element != -1; i++) @@ -6866,6 +6880,7 @@ static void DrawPropertiesConfig() counterbutton_info[counter_id].y = ED_SETTINGS_YPOS((HAS_CONTENT(properties_element) ? 1 : 0) + + (MAYBE_DONT_COLLIDE_WITH(properties_element) ? 1 : 0)+ (COULD_MOVE_INTO_ACID(properties_element) ? 1 : 0)); counterbutton_info[counter_id].value = elements_with_counter[i].value; @@ -6911,6 +6926,9 @@ static void DrawPropertiesConfig() MapCheckbuttonGadget(ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID); } + if (MAYBE_DONT_COLLIDE_WITH(properties_element)) + MapCheckbuttonGadget(ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH); + if (properties_element == EL_SPRING) MapCheckbuttonGadget(ED_CHECKBUTTON_ID_USE_SPRING_BUG); @@ -8372,7 +8390,9 @@ static void HandleCheckbuttons(struct GadgetInfo *gi) *checkbutton_info[type_id].value ^= TRUE; - if (type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID || + if (type_id == ED_CHECKBUTTON_ID_CAN_FALL_INTO_ACID || + type_id == ED_CHECKBUTTON_ID_CAN_MOVE_INTO_ACID || + type_id == ED_CHECKBUTTON_ID_DONT_COLLIDE_WITH || (((type_id >= ED_CHECKBUTTON_ID_CUSTOM_FIRST && type_id <= ED_CHECKBUTTON_ID_CUSTOM_LAST) || (type_id >= ED_CHECKBUTTON_ID_CHANGE_FIRST && diff --git a/src/files.c b/src/files.c index 154d228e..cd56a7c5 100644 --- a/src/files.c +++ b/src/files.c @@ -29,7 +29,7 @@ #define CHUNK_SIZE_NONE -1 /* do not write chunk size */ #define FILE_VERS_CHUNK_SIZE 8 /* size of file version chunk */ #define LEVEL_HEADER_SIZE 80 /* size of level file header */ -#define LEVEL_HEADER_UNUSED 6 /* unused level header bytes */ +#define LEVEL_HEADER_UNUSED 4 /* unused level header bytes */ #define LEVEL_CHUNK_CNT2_SIZE 160 /* size of level CNT2 chunk */ #define LEVEL_CHUNK_CNT2_UNUSED 11 /* unused CNT2 chunk bytes */ #define LEVEL_CHUNK_CNT3_HEADER 16 /* size of level CNT3 header */ @@ -160,12 +160,10 @@ static void setLevelInfoToDefaults(struct LevelInfo *level) level->block_last_field = FALSE; level->sp_block_last_field = TRUE; - level->use_spring_bug = FALSE; - level->can_move_into_acid_bits = ~0; /* everything can move into acid */ + level->dont_collide_with_bits = ~0; /* always deadly when colliding */ - level->player_can_fall_into_acid = TRUE; - + level->use_spring_bug = FALSE; level->use_step_counter = FALSE; level->use_custom_template = FALSE; @@ -682,15 +680,12 @@ static int LoadLevel_HEAD(FILE *file, int chunk_size, struct LevelInfo *level) level->block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); level->sp_block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE); + level->can_move_into_acid_bits = getFile32BitBE(file); + level->dont_collide_with_bits = getFile8Bit(file); level->use_spring_bug = (getFile8Bit(file) == 1 ? TRUE : FALSE); - - level->can_move_into_acid_bits = getFile16BitBE(file); - level->use_step_counter = (getFile8Bit(file) == 1 ? TRUE : FALSE); - level->player_can_fall_into_acid = (getFile8Bit(file) == 1 ? TRUE : FALSE); - ReadUnusedBytesFromFile(file, LEVEL_HEADER_UNUSED); return chunk_size; @@ -2093,11 +2088,12 @@ static void LoadLevel_InitVersion(struct LevelInfo *level, char *filename) if (level->game_version < VERSION_IDENT(2,2,0,0)) level->use_spring_bug = TRUE; - if (level->game_version < VERSION_IDENT(3,0,9,0)) + if (level->game_version < VERSION_IDENT(3,1,0,0)) { int i, j; level->can_move_into_acid_bits = 0; /* nothing can move into acid */ + level->dont_collide_with_bits = 0; /* nothing is deadly when colliding */ setMoveIntoAcidProperty(level, EL_ROBOT, TRUE); setMoveIntoAcidProperty(level, EL_SATELLITE, TRUE); @@ -2418,15 +2414,12 @@ static void SaveLevel_HEAD(FILE *file, struct LevelInfo *level) putFile8Bit(file, (level->block_last_field ? 1 : 0)); putFile8Bit(file, (level->sp_block_last_field ? 1 : 0)); + putFile32BitBE(file, level->can_move_into_acid_bits); + putFile8Bit(file, level->dont_collide_with_bits); putFile8Bit(file, (level->use_spring_bug ? 1 : 0)); - - putFile16BitBE(file, level->can_move_into_acid_bits); - putFile8Bit(file, (level->use_step_counter ? 1 : 0)); - putFile8Bit(file, (level->player_can_fall_into_acid ? 1 : 0)); - WriteUnusedBytesToFile(file, LEVEL_HEADER_UNUSED); } diff --git a/src/game.c b/src/game.c index f5cf3d8e..d90ff0c3 100644 --- a/src/game.c +++ b/src/game.c @@ -103,96 +103,135 @@ #define GET_MAX_MOVE_DELAY(e) ( (element_info[e].move_delay_fixed) + \ (element_info[e].move_delay_random)) -#define ELEMENT_CAN_ENTER_FIELD_BASE(e, x, y, condition) \ +#define ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, condition) \ + (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ + (condition))) + +#define ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (condition))) -#if 0 -#define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \ +#define ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, condition) \ + (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ + (CAN_MOVE_INTO_ACID(e) && \ + Feld[x][y] == EL_ACID) || \ + (condition))) + +#define ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition) || \ + (CAN_MOVE_INTO_ACID(e) && \ + Feld[x][y] == EL_ACID) || \ (DONT_COLLIDE_WITH(e) && \ IS_PLAYER(x, y) && \ !PLAYER_ENEMY_PROTECTED(x, y)))) -#else + +#if 0 #define ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ (condition) || \ - (CAN_MOVE_INTO_ACID(e) && \ - Feld[x][y] == EL_ACID) || \ (DONT_COLLIDE_WITH(e) && \ IS_PLAYER(x, y) && \ !PLAYER_ENEMY_PROTECTED(x, y)))) #endif -#define ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, condition) \ - (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (condition))) - #define ELEMENT_CAN_ENTER_FIELD(e, x, y) \ - ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, 0) - -#define ELEMENT_CAN_ENTER_FIELD_OR_ACID(e, x, y) \ - ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, (Feld[x][y] == EL_ACID)) + ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, 0) -#define ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(x, y) \ - ELEMENT_CAN_ENTER_FIELD_GENERIC_2(x, y, (Feld[x][y] == EL_ACID)) +#if 1 +#define SATELLITE_CAN_ENTER_FIELD(x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_2(EL_SATELLITE, x, y, 0) +#else +#define SATELLITE_CAN_ENTER_FIELD(x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_X(x, y, Feld[x][y] == EL_ACID) +#endif #if 0 #define ENEMY_CAN_ENTER_FIELD(e, x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y)) -#else -#define ENEMY_CAN_ENTER_FIELD(e, x, y) ELEMENT_CAN_ENTER_FIELD_BASE(e, x, y, 0) #endif -#define YAMYAM_CAN_ENTER_FIELD(x, y) \ +#define ENEMY_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) + +#if 1 + +#define YAMYAM_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, Feld[x][y] == EL_DIAMOND) + +#define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x,y, IS_FOOD_DARK_YAMYAM(Feld[x][y])) + +#define PACMAN_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_3(e, x, y, IS_AMOEBOID(Feld[x][y])) + +#define PIG_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, IS_FOOD_PIG(Feld[x][y])) + +#define PENGUIN_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (Feld[x][y] == EL_EXIT_OPEN ||\ + IS_FOOD_PENGUIN(Feld[x][y]))) +#define DRAGON_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) + +#define MOLE_CAN_ENTER_FIELD(e, x, y, condition) \ + ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, (condition)) + +#define SPRING_CAN_ENTER_FIELD(e, x, y) \ + ELEMENT_CAN_ENTER_FIELD_BASE_2(e, x, y, 0) + +#else + +#define YAMYAM_CAN_ENTER_FIELD(e, x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_YAMYAM) && \ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ Feld[x][y] == EL_DIAMOND)) -#define DARK_YAMYAM_CAN_ENTER_FIELD(x, y) \ +#define DARK_YAMYAM_CAN_ENTER_FIELD(e, x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_DARK_YAMYAM) &&\ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ IS_FOOD_DARK_YAMYAM(Feld[x][y]))) -#define PACMAN_CAN_ENTER_FIELD(x, y) \ +#define PACMAN_CAN_ENTER_FIELD(e, x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE_OR_PLAYER(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_PACMAN) && \ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ IS_AMOEBOID(Feld[x][y]))) -#define PIG_CAN_ENTER_FIELD(x, y) \ +#define PIG_CAN_ENTER_FIELD(e, x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_PIG) && \ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ IS_FOOD_PIG(Feld[x][y]))) -#define PENGUIN_CAN_ENTER_FIELD(x, y) \ +#define PENGUIN_CAN_ENTER_FIELD(e, x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_PENGUIN) && \ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ IS_FOOD_PENGUIN(Feld[x][y]) || \ Feld[x][y] == EL_EXIT_OPEN)) -#define DRAGON_CAN_ENTER_FIELD(x, y) \ +#define DRAGON_CAN_ENTER_FIELD(e, x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_DRAGON) && \ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID))) -#define MOLE_CAN_ENTER_FIELD(x, y, condition) \ +#define MOLE_CAN_ENTER_FIELD(e, x, y, condition) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_MOLE) && \ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID) || \ (condition))) -#define SPRING_CAN_ENTER_FIELD(x, y) \ +#define SPRING_CAN_ENTER_FIELD(e, x, y) \ (IN_LEV_FIELD(x, y) && (IS_FREE(x, y) || \ - (CAN_MOVE_INTO_ACID(EL_SPRING) && \ + (CAN_MOVE_INTO_ACID(e) && \ Feld[x][y] == EL_ACID))) +#endif + #define GROUP_NR(e) ((e) - EL_GROUP_START) #define MOVE_ENTER_EL(e) (element_info[e].move_enter_element) #define IS_IN_GROUP(e, nr) (element_info[e].in_group[nr] == TRUE) @@ -213,7 +252,7 @@ #endif #define CUSTOM_ELEMENT_CAN_ENTER_FIELD(e, x, y) \ - ELEMENT_CAN_ENTER_FIELD_GENERIC(e, x, y, CE_ENTER_FIELD_COND(e, x, y)) + ELEMENT_CAN_ENTER_FIELD_BASE_4(e, x, y, CE_ENTER_FIELD_COND(e, x, y)) #define IN_LEV_FIELD_AND_IS_FREE(x, y) (IN_LEV_FIELD(x, y) && IS_FREE(x, y)) #define IN_LEV_FIELD_AND_NOT_FREE(x, y) (IN_LEV_FIELD(x, y) && !IS_FREE(x, y)) @@ -910,7 +949,7 @@ static inline void InitField_WithBug1(int x, int y, boolean init_game) InitField(x, y, init_game); /* not needed to call InitMovDir() -- already done by InitField()! */ - if (game.engine_version < VERSION_IDENT(3,0,9,0) && + if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(Feld[x][y])) InitMovDir(x, y); } @@ -922,7 +961,7 @@ static inline void InitField_WithBug2(int x, int y, boolean init_game) InitField(x, y, init_game); /* not needed to call InitMovDir() -- already done by InitField()! */ - if (game.engine_version < VERSION_IDENT(3,0,9,0) && + if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(old_element) && (old_element < EL_MOLE_LEFT || old_element > EL_MOLE_DOWN)) InitMovDir(x, y); @@ -1260,14 +1299,14 @@ static void InitGameEngine() } /* set push delay value for Supaplex elements for newer engine versions */ - if (game.engine_version >= VERSION_IDENT(3,0,9,0)) + if (game.engine_version >= VERSION_IDENT(3,1,0,0)) { for (i = 0; i < MAX_NUM_ELEMENTS; i++) { if (IS_SP_ELEMENT(i)) { - element_info[i].push_delay_fixed = 6; - element_info[i].push_delay_random = 0; + element_info[i].push_delay_fixed = 6; /* just enough to escape ... */ + element_info[i].push_delay_random = 0; /* ... from falling zonk */ } } } @@ -1391,6 +1430,7 @@ void InitGame() player->use_murphy_graphic = FALSE; player->block_last_field = FALSE; + player->can_fall_into_acid = CAN_MOVE_INTO_ACID(player->element_nr); player->actual_frame_counter = 0; @@ -3070,7 +3110,7 @@ void Explode(int ex, int ey, int phase, int mode) #if 1 /* !!! not needed !!! */ #if 1 - if (game.engine_version < VERSION_IDENT(3,0,9,0) && + if (game.engine_version < VERSION_IDENT(3,1,0,0) && CAN_MOVE(Feld[x][y]) && Feld[x][y] != EL_MOLE) InitMovDir(x, y); #else @@ -3985,9 +4025,9 @@ inline static void TurnRoundExt(int x, int y) { TestIfBadThingTouchesOtherBadThing(x, y); - if (ELEMENT_CAN_ENTER_FIELD_GENERIC(element, left_x, left_y, 0)) + if (ELEMENT_CAN_ENTER_FIELD_BASE_4(element, left_x, left_y, 0)) MovDir[x][y] = left_dir; - else if (!ELEMENT_CAN_ENTER_FIELD_GENERIC(element, move_x, move_y, 0)) + else if (!ELEMENT_CAN_ENTER_FIELD_BASE_4(element, move_x, move_y, 0)) MovDir[x][y] = right_dir; if (MovDir[x][y] != old_move_dir) @@ -3996,8 +4036,8 @@ inline static void TurnRoundExt(int x, int y) #endif else if (element == EL_YAMYAM) { - boolean can_turn_left = YAMYAM_CAN_ENTER_FIELD(left_x, left_y); - boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(right_x, right_y); + boolean can_turn_left = YAMYAM_CAN_ENTER_FIELD(element, left_x, left_y); + boolean can_turn_right = YAMYAM_CAN_ENTER_FIELD(element, right_x, right_y); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); @@ -4012,8 +4052,10 @@ inline static void TurnRoundExt(int x, int y) } else if (element == EL_DARK_YAMYAM) { - boolean can_turn_left = DARK_YAMYAM_CAN_ENTER_FIELD(left_x, left_y); - boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(right_x, right_y); + boolean can_turn_left = DARK_YAMYAM_CAN_ENTER_FIELD(element, + left_x, left_y); + boolean can_turn_right = DARK_YAMYAM_CAN_ENTER_FIELD(element, + right_x, right_y); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); @@ -4028,8 +4070,8 @@ inline static void TurnRoundExt(int x, int y) } else if (element == EL_PACMAN) { - boolean can_turn_left = PACMAN_CAN_ENTER_FIELD(left_x, left_y); - boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(right_x, right_y); + boolean can_turn_left = PACMAN_CAN_ENTER_FIELD(element, left_x, left_y); + boolean can_turn_right = PACMAN_CAN_ENTER_FIELD(element, right_x, right_y); if (can_turn_left && can_turn_right) MovDir[x][y] = (RND(3) ? (RND(2) ? left_dir : right_dir) : back_dir); @@ -4044,9 +4086,9 @@ inline static void TurnRoundExt(int x, int y) } else if (element == EL_PIG) { - boolean can_turn_left = PIG_CAN_ENTER_FIELD(left_x, left_y); - boolean can_turn_right = PIG_CAN_ENTER_FIELD(right_x, right_y); - boolean can_move_on = PIG_CAN_ENTER_FIELD(move_x, move_y); + boolean can_turn_left = PIG_CAN_ENTER_FIELD(element, left_x, left_y); + boolean can_turn_right = PIG_CAN_ENTER_FIELD(element, right_x, right_y); + boolean can_move_on = PIG_CAN_ENTER_FIELD(element, move_x, move_y); boolean should_turn_left, should_turn_right, should_move_on; int rnd_value = 24; int rnd = RND(rnd_value); @@ -4107,9 +4149,9 @@ inline static void TurnRoundExt(int x, int y) } else if (element == EL_DRAGON) { - boolean can_turn_left = DRAGON_CAN_ENTER_FIELD(left_x, left_y); - boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(right_x, right_y); - boolean can_move_on = DRAGON_CAN_ENTER_FIELD(move_x, move_y); + boolean can_turn_left = DRAGON_CAN_ENTER_FIELD(element, left_x, left_y); + boolean can_turn_right = DRAGON_CAN_ENTER_FIELD(element, right_x, right_y); + boolean can_move_on = DRAGON_CAN_ENTER_FIELD(element, move_x, move_y); int rnd_value = 24; int rnd = RND(rnd_value); @@ -4157,17 +4199,17 @@ inline static void TurnRoundExt(int x, int y) else if (element == EL_MOLE) { boolean can_move_on = - (MOLE_CAN_ENTER_FIELD(move_x, move_y, + (MOLE_CAN_ENTER_FIELD(element, move_x, move_y, IS_AMOEBOID(Feld[move_x][move_y]) || Feld[move_x][move_y] == EL_AMOEBA_SHRINKING)); if (!can_move_on) { boolean can_turn_left = - (MOLE_CAN_ENTER_FIELD(left_x, left_y, + (MOLE_CAN_ENTER_FIELD(element, left_x, left_y, IS_AMOEBOID(Feld[left_x][left_y]))); boolean can_turn_right = - (MOLE_CAN_ENTER_FIELD(right_x, right_y, + (MOLE_CAN_ENTER_FIELD(element, right_x, right_y, IS_AMOEBOID(Feld[right_x][right_y]))); if (can_turn_left && can_turn_right) @@ -4190,12 +4232,12 @@ inline static void TurnRoundExt(int x, int y) { #if 0 if (MovDir[x][y] & MV_HORIZONTAL && - !SPRING_CAN_ENTER_FIELD(move_x, move_y)) + !SPRING_CAN_ENTER_FIELD(element, move_x, move_y)) MovDir[x][y] = MV_NO_MOVING; #else if (MovDir[x][y] & MV_HORIZONTAL && - (!SPRING_CAN_ENTER_FIELD(move_x, move_y) || - SPRING_CAN_ENTER_FIELD(x, y + 1))) + (!SPRING_CAN_ENTER_FIELD(element, move_x, move_y) || + SPRING_CAN_ENTER_FIELD(element, x, y + 1))) MovDir[x][y] = MV_NO_MOVING; #endif @@ -4302,14 +4344,14 @@ inline static void TurnRoundExt(int x, int y) new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); - if (PENGUIN_CAN_ENTER_FIELD(newx, newy)) + if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); - if (PENGUIN_CAN_ENTER_FIELD(newx, newy)) + if (PENGUIN_CAN_ENTER_FIELD(EL_PENGUIN, newx, newy)) return; MovDir[x][y] = old_move_dir; @@ -4331,14 +4373,14 @@ inline static void TurnRoundExt(int x, int y) new_move_dir & (first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); - if (ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(newx, newy)) + if (SATELLITE_CAN_ENTER_FIELD(newx, newy)) return; MovDir[x][y] = new_move_dir & (!first_horiz ? MV_HORIZONTAL : MV_VERTICAL); Moving2Blocked(x, y, &newx, &newy); - if (ELEMENT_CAN_ENTER_FIELD_OR_ACID_2(newx, newy)) + if (SATELLITE_CAN_ENTER_FIELD(newx, newy)) return; MovDir[x][y] = old_move_dir; @@ -4944,7 +4986,7 @@ void StartMoving(int x, int y) #endif #if 1 - if (game.engine_version >= VERSION_IDENT(3,0,9,0) && + if (game.engine_version >= VERSION_IDENT(3,1,0,0) && WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) && (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy))) { @@ -5175,7 +5217,7 @@ void StartMoving(int x, int y) else if (CAN_MOVE_INTO_ACID(element) && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID && (MovDir[x][y] == MV_DOWN || - game.engine_version > VERSION_IDENT(3,0,8,0))) + game.engine_version >= VERSION_IDENT(3,1,0,0))) #else else if (CAN_MOVE_INTO_ACID(element) && MovDir[x][y] == MV_DOWN && IN_LEV_FIELD(newx, newy) && Feld[newx][newy] == EL_ACID) @@ -7520,6 +7562,7 @@ void GameActions() - rnd_equinox_tetrachloride 048 - rnd_equinox_tetrachloride_ii 096 - rnd_emanuel_schmieg 002 + - doctor_sloan_ww 020 */ if (stored_player[i].MovPos == 0) CheckGravityMovement(&stored_player[i]); @@ -8215,7 +8258,7 @@ static void CheckGravityMovement(struct PlayerInfo *player) boolean player_can_fall_down = (IN_LEV_FIELD(jx, jy + 1) && (IS_FREE(jx, jy + 1) || - (Feld[jx][jy + 1] == EL_ACID && level.player_can_fall_into_acid))); + (Feld[jx][jy + 1] == EL_ACID && player->can_fall_into_acid))); #else boolean player_can_fall_down = (IN_LEV_FIELD(jx, jy + 1) && diff --git a/src/init.c b/src/init.c index df191e0a..c4528006 100644 --- a/src/init.c +++ b/src/init.c @@ -1569,71 +1569,133 @@ static void ReinitializeMusic() InitGameModeMusicInfo(); /* game mode music mapping */ } -static int get_special_property_bit(int element, int base_property_bit) +static int get_special_property_bit(int element, int property_bit_nr) { - static struct + struct PropertyBitInfo { int element; int bit_nr; - } pb_can_move_into_acid[] = - { - /* all element that can move */ - { EL_BUG, 0 }, - { EL_BUG_LEFT, 0 }, - { EL_BUG_RIGHT, 0 }, - { EL_BUG_UP, 0 }, - { EL_BUG_DOWN, 0 }, - { EL_SPACESHIP, 0 }, - { EL_SPACESHIP_LEFT, 0 }, - { EL_SPACESHIP_RIGHT, 0 }, - { EL_SPACESHIP_UP, 0 }, - { EL_SPACESHIP_DOWN, 0 }, - { EL_BD_BUTTERFLY, 1 }, - { EL_BD_BUTTERFLY_LEFT, 1 }, - { EL_BD_BUTTERFLY_RIGHT, 1 }, - { EL_BD_BUTTERFLY_UP, 1 }, - { EL_BD_BUTTERFLY_DOWN, 1 }, - { EL_BD_FIREFLY, 1 }, - { EL_BD_FIREFLY_LEFT, 1 }, - { EL_BD_FIREFLY_RIGHT, 1 }, - { EL_BD_FIREFLY_UP, 1 }, - { EL_BD_FIREFLY_DOWN, 1 }, - { EL_YAMYAM, 2 }, - { EL_DARK_YAMYAM, 2 }, - { EL_ROBOT, 3 }, - { EL_PACMAN, 4 }, - { EL_PACMAN_LEFT, 4 }, - { EL_PACMAN_RIGHT, 4 }, - { EL_PACMAN_UP, 4 }, - { EL_PACMAN_DOWN, 4 }, - { EL_MOLE, 4 }, - { EL_MOLE_LEFT, 4 }, - { EL_MOLE_RIGHT, 4 }, - { EL_MOLE_UP, 4 }, - { EL_MOLE_DOWN, 4 }, - { EL_PENGUIN, 5 }, - { EL_PIG, 6 }, - { EL_DRAGON, 6 }, - { EL_SATELLITE, 7 }, - { EL_SP_SNIKSNAK, 8 }, - { EL_SP_ELECTRON, 8 }, - { EL_BALLOON, 9 }, - { EL_SPRING, 10 }, + }; + + 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; - if (base_property_bit != EP_CAN_MOVE_INTO_ACID) + 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_can_move_into_acid[i].element != -1; i++) - if (pb_can_move_into_acid[i].element == element) - return pb_can_move_into_acid[i].bit_nr; + 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); @@ -1656,6 +1718,7 @@ boolean getMoveIntoAcidProperty(struct LevelInfo *level, int element) return FALSE; } +#endif void InitElementPropertiesStatic() { @@ -3270,9 +3333,19 @@ void InitElementPropertiesEngine(int engine_version) SET_PROPERTY(i, EP_COULD_MOVE_INTO_ACID, (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 (!IS_CUSTOM_ELEMENT(i)) - SET_PROPERTY(i, EP_CAN_MOVE_INTO_ACID,getMoveIntoAcidProperty(&level,i)); + 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) && @@ -3366,7 +3439,7 @@ void InitElementPropertiesEngine(int engine_version) } /* set some other uninitialized values of custom elements in older levels */ - if (engine_version < VERSION_IDENT(3,0,9,0)) + if (engine_version < VERSION_IDENT(3,1,0,0)) { for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++) { @@ -3379,12 +3452,15 @@ void InitElementPropertiesEngine(int engine_version) } } +#if 0 /* set element properties that were handled incorrectly in older levels */ - if (engine_version < VERSION_IDENT(3,0,9,0)) + 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 */ diff --git a/src/init.h b/src/init.h index af5f3981..ca22ef6e 100644 --- a/src/init.h +++ b/src/init.h @@ -16,8 +16,29 @@ #include "main.h" +#if 1 +#define setMoveIntoAcidProperty(l, e, v) \ + (setBitfieldProperty(&(l)->can_move_into_acid_bits, \ + EP_CAN_MOVE_INTO_ACID, e, v)) +#define getMoveIntoAcidProperty(l, e) \ + (getBitfieldProperty(&(l)->can_move_into_acid_bits, \ + EP_CAN_MOVE_INTO_ACID, e)) +#define setDontCollideWithProperty(l, e, v) \ + (setBitfieldProperty(&(l)->can_move_into_acid_bits, \ + EP_DONT_COLLIDE_WITH, e, v)) +#define getDontCollideWithProperty(l, e) \ + (getBitfieldProperty(&(l)->can_move_into_acid_bits, \ + EP_DONT_COLLIDE_WITH, e)) + +void setBitfieldProperty(int *, int, int, boolean); +boolean getBitfieldProperty(int *, int, int); + +#else + void setMoveIntoAcidProperty(struct LevelInfo *, int, boolean); boolean getMoveIntoAcidProperty(struct LevelInfo *, int); +#endif + void InitElementPropertiesStatic(void); void InitElementPropertiesEngine(int); diff --git a/src/main.h b/src/main.h index e55db3cb..cb739c04 100644 --- a/src/main.h +++ b/src/main.h @@ -138,16 +138,17 @@ #define EP_CAN_EXPLODE 70 #define EP_CAN_EXPLODE_3X3 71 #define EP_SP_PORT 72 -#define EP_CAN_EXPLODE_BY_DRAGONFIRE 73 -#define EP_CAN_EXPLODE_BY_EXPLOSION 74 -#define EP_COULD_MOVE_INTO_ACID 75 +#define EP_CAN_EXPLODE_BY_DRAGONFIRE 73 +#define EP_CAN_EXPLODE_BY_EXPLOSION 74 +#define EP_COULD_MOVE_INTO_ACID 75 +#define EP_MAYBE_DONT_COLLIDE_WITH 76 /* values for internal purpose only (level editor) */ -#define EP_EXPLODE_RESULT 76 -#define EP_WALK_TO_OBJECT 77 -#define EP_DEADLY 78 +#define EP_EXPLODE_RESULT 77 +#define EP_WALK_TO_OBJECT 78 +#define EP_DEADLY 79 -#define NUM_ELEMENT_PROPERTIES 79 +#define NUM_ELEMENT_PROPERTIES 80 #define NUM_EP_BITFIELDS ((NUM_ELEMENT_PROPERTIES + 31) / 32) #define EP_BITFIELD_BASE 0 @@ -380,6 +381,7 @@ #define CAN_EXPLODE_BY_EXPLOSION(e) \ HAS_PROPERTY(e, EP_CAN_EXPLODE_BY_EXPLOSION) #define COULD_MOVE_INTO_ACID(e) HAS_PROPERTY(e, EP_COULD_MOVE_INTO_ACID) +#define MAYBE_DONT_COLLIDE_WITH(e) HAS_PROPERTY(e, EP_MAYBE_DONT_COLLIDE_WITH) /* special macros used in game engine */ #define IS_CUSTOM_ELEMENT(e) ((e) >= EL_CUSTOM_START && \ @@ -1200,8 +1202,8 @@ /* program information and versioning definitions */ #define PROGRAM_VERSION_MAJOR 3 -#define PROGRAM_VERSION_MINOR 0 -#define PROGRAM_VERSION_PATCH 9 +#define PROGRAM_VERSION_MINOR 1 +#define PROGRAM_VERSION_PATCH 0 #define PROGRAM_VERSION_BUILD 0 #define PROGRAM_TITLE_STRING "Rocks'n'Diamonds" @@ -1313,6 +1315,7 @@ struct PlayerInfo boolean use_murphy_graphic; boolean block_last_field; + boolean can_fall_into_acid; boolean LevelSolved, GameOver; @@ -1423,9 +1426,8 @@ struct LevelInfo int time_light; int time_timegate; - int can_move_into_acid_bits; /* bits indicate property for element groups */ - - boolean player_can_fall_into_acid; + int can_move_into_acid_bits; /* bitfield to store property for elements */ + int dont_collide_with_bits; /* bitfield to store property for elements */ boolean double_speed; boolean initial_gravity; -- 2.34.1