+2004-01-30
+ * added option to block last field when player is moving (for Supaplex)
+ * adjusted push delay of Supaplex elements
+ * removed delays for envelopes etc. when replaying with maximum speed
+ * fixed bug when dropping element on a field that just changed to empty
+
2004-01-29
* fixed bug: infotron can now smash yellow disks
* fixed bug: when gravity active, port above player can now be entered
-#define COMPILE_DATE_STRING "[2004-01-29 18:51]"
+#define COMPILE_DATE_STRING "[2004-01-30 19:50]"
#define GADGET_ID_SCROLL_LIST_DOWN (GADGET_ID_SCROLLING_LIST_FIRST + 1)
#define GADGET_ID_SCROLL_LIST_VERTICAL (GADGET_ID_SCROLLING_LIST_FIRST + 2)
-/* checkbuttons for level/element properties */
+/* checkbuttons/radiobuttons for level/element properties */
#define GADGET_ID_CHECKBUTTON_FIRST (GADGET_ID_SCROLLING_LIST_FIRST + 3)
#define GADGET_ID_RANDOM_PERCENTAGE (GADGET_ID_CHECKBUTTON_FIRST + 0)
#define GADGET_ID_GRAVITY (GADGET_ID_CHECKBUTTON_FIRST + 4)
#define GADGET_ID_STICK_ELEMENT (GADGET_ID_CHECKBUTTON_FIRST + 5)
#define GADGET_ID_EM_SLIPPERY_GEMS (GADGET_ID_CHECKBUTTON_FIRST + 6)
-#define GADGET_ID_CUSTOM_EXPLODE_RESULT (GADGET_ID_CHECKBUTTON_FIRST + 7)
-#define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 8)
-#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 9)
-#define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 10)
-#define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 11)
-#define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 12)
-#define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 13)
-#define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 14)
-#define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 15)
-#define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 16)
-#define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 17)
-#define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 18)
-#define GADGET_ID_CUSTOM_USE_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 19)
-#define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 20)
-#define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 21)
-#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 22)
-#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 23)
-#define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 24)
-#define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 25)
-#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 26)
-#define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 7)
+#define GADGET_ID_SP_BLOCK_LAST_FIELD (GADGET_ID_CHECKBUTTON_FIRST + 8)
+#define GADGET_ID_CUSTOM_EXPLODE_RESULT (GADGET_ID_CHECKBUTTON_FIRST + 9)
+#define GADGET_ID_CUSTOM_EXPLODE_FIRE (GADGET_ID_CHECKBUTTON_FIRST + 10)
+#define GADGET_ID_CUSTOM_EXPLODE_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 11)
+#define GADGET_ID_CUSTOM_EXPLODE_IMPACT (GADGET_ID_CHECKBUTTON_FIRST + 12)
+#define GADGET_ID_CUSTOM_WALK_TO_OBJECT (GADGET_ID_CHECKBUTTON_FIRST + 13)
+#define GADGET_ID_CUSTOM_DEADLY (GADGET_ID_CHECKBUTTON_FIRST + 14)
+#define GADGET_ID_CUSTOM_CAN_MOVE (GADGET_ID_CHECKBUTTON_FIRST + 15)
+#define GADGET_ID_CUSTOM_CAN_FALL (GADGET_ID_CHECKBUTTON_FIRST + 16)
+#define GADGET_ID_CUSTOM_CAN_SMASH (GADGET_ID_CHECKBUTTON_FIRST + 17)
+#define GADGET_ID_CUSTOM_SLIPPERY (GADGET_ID_CHECKBUTTON_FIRST + 18)
+#define GADGET_ID_CUSTOM_ACCESSIBLE (GADGET_ID_CHECKBUTTON_FIRST + 19)
+#define GADGET_ID_CUSTOM_USE_GRAPHIC (GADGET_ID_CHECKBUTTON_FIRST + 20)
+#define GADGET_ID_CUSTOM_USE_TEMPLATE (GADGET_ID_CHECKBUTTON_FIRST + 21)
+#define GADGET_ID_CUSTOM_CAN_CHANGE (GADGET_ID_CHECKBUTTON_FIRST + 22)
+#define GADGET_ID_CHANGE_USE_CONTENT (GADGET_ID_CHECKBUTTON_FIRST + 23)
+#define GADGET_ID_CHANGE_USE_EXPLOSION (GADGET_ID_CHECKBUTTON_FIRST + 24)
+#define GADGET_ID_CHANGE_ONLY_COMPLETE (GADGET_ID_CHECKBUTTON_FIRST + 25)
+#define GADGET_ID_CHANGE_USE_RANDOM (GADGET_ID_CHECKBUTTON_FIRST + 26)
+#define GADGET_ID_CHANGE_DELAY (GADGET_ID_CHECKBUTTON_FIRST + 27)
+#define GADGET_ID_CHANGE_BY_DIRECT_ACT (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_CHANGE_BY_OTHER_ACT (GADGET_ID_CHECKBUTTON_FIRST + 29)
/* gadgets for buttons in element list */
-#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 28)
+#define GADGET_ID_ELEMENTLIST_FIRST (GADGET_ID_CHECKBUTTON_FIRST + 30)
#define GADGET_ID_ELEMENTLIST_LAST (GADGET_ID_ELEMENTLIST_FIRST + \
ED_NUM_ELEMENTLIST_BUTTONS - 1)
#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_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_CAN_CHANGE 17
-#define ED_CHECKBUTTON_ID_CHANGE_DELAY 18
-#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 19
-#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 20
-#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 21
-#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 22
-#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 23
-#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 24
-#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 25
-
-#define ED_NUM_CHECKBUTTONS 26
+#define ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD 5
+#define ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD 6
+#define ED_CHECKBUTTON_ID_CUSTOM_ACCESSIBLE 7
+#define ED_CHECKBUTTON_ID_CUSTOM_WALK_TO_OBJECT 8
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_MOVE 9
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_FALL 10
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_SMASH 11
+#define ED_CHECKBUTTON_ID_CUSTOM_SLIPPERY 12
+#define ED_CHECKBUTTON_ID_CUSTOM_DEADLY 13
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_RESULT 14
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_FIRE 15
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_SMASH 16
+#define ED_CHECKBUTTON_ID_CUSTOM_EXPLODE_IMPACT 17
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_GRAPHIC 18
+#define ED_CHECKBUTTON_ID_CUSTOM_CAN_CHANGE 19
+#define ED_CHECKBUTTON_ID_CHANGE_DELAY 20
+#define ED_CHECKBUTTON_ID_CHANGE_BY_DIRECT_ACT 21
+#define ED_CHECKBUTTON_ID_CHANGE_BY_OTHER_ACT 22
+#define ED_CHECKBUTTON_ID_CHANGE_USE_EXPLOSION 23
+#define ED_CHECKBUTTON_ID_CHANGE_USE_CONTENT 24
+#define ED_CHECKBUTTON_ID_CHANGE_ONLY_COMPLETE 25
+#define ED_CHECKBUTTON_ID_CHANGE_USE_RANDOM 26
+#define ED_CHECKBUTTON_ID_CUSTOM_USE_TEMPLATE 27
+
+#define ED_NUM_CHECKBUTTONS 28
#define ED_CHECKBUTTON_ID_LEVEL_FIRST ED_CHECKBUTTON_ID_DOUBLE_SPEED
#define ED_CHECKBUTTON_ID_LEVEL_LAST ED_CHECKBUTTON_ID_RANDOM_RESTRICTED
NULL,
"slip down from certain flat walls","use EM style slipping behaviour"
},
+ {
+ ED_SETTINGS_XPOS(0), ED_COUNTER_YPOS(4),
+ GADGET_ID_BLOCK_LAST_FIELD, GADGET_ID_NONE,
+ &level.block_last_field,
+ NULL,
+ "block last field when moving", "player blocks last field when moving"
+ },
+ {
+ ED_SETTINGS_XPOS(0), ED_COUNTER_YPOS(4),
+ GADGET_ID_SP_BLOCK_LAST_FIELD, GADGET_ID_NONE,
+ &level.sp_block_last_field,
+ NULL,
+ "block last field when moving", "player blocks last field when moving"
+ },
/* ---------- element settings: configure (custom elements) ------------- */
IS_CUSTOM_ELEMENT(properties_element) ||
IS_GROUP_ELEMENT(properties_element) ||
IS_ENVELOPE(properties_element) ||
+ ELEM_IS_PLAYER(properties_element) ||
HAS_CONTENT(properties_element))
return TRUE;
else
if (IS_GEM(properties_element))
MapCheckbuttonGadget(ED_CHECKBUTTON_ID_EM_SLIPPERY_GEMS);
+ if (ELEM_IS_PLAYER(properties_element))
+ MapCheckbuttonGadget(properties_element == EL_SP_MURPHY ?
+ ED_CHECKBUTTON_ID_SP_BLOCK_LAST_FIELD :
+ ED_CHECKBUTTON_ID_BLOCK_LAST_FIELD);
+
if (IS_ENVELOPE(properties_element))
{
int counter1_id = ED_COUNTER_ID_ENVELOPE_XSIZE;
#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 13 /* unused level header bytes */
+#define LEVEL_HEADER_UNUSED 11 /* 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 */
level->double_speed = FALSE;
level->initial_gravity = FALSE;
level->em_slippery_gems = FALSE;
+ level->block_last_field = FALSE;
+ level->sp_block_last_field = TRUE;
level->use_custom_template = FALSE;
level->initial_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->block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
+ level->sp_block_last_field = (getFile8Bit(file) == 1 ? TRUE : FALSE);
level->use_custom_template = (getFile8Bit(file) == 1 ? TRUE : FALSE);
putFile8Bit(file, (level->initial_gravity ? 1 : 0));
putFile8Bit(file, (level->encoding_16bit_field ? 1 : 0));
putFile8Bit(file, (level->em_slippery_gems ? 1 : 0));
+ putFile8Bit(file, (level->block_last_field ? 1 : 0));
+ putFile8Bit(file, (level->sp_block_last_field ? 1 : 0));
putFile8Bit(file, (level->use_custom_template ? 1 : 0));
level->file_version, level->game_version);
printf_line("-", 79);
- printf("Level Author: '%s'\n", level->author);
- printf("Level Title: '%s'\n", level->name);
+ printf("Level author: '%s'\n", level->author);
+ printf("Level title: '%s'\n", level->name);
printf("\n");
- printf("Playfield Size: %d x %d\n", level->fieldx, level->fieldy);
+ printf("Playfield size: %d x %d\n", level->fieldx, level->fieldy);
printf("\n");
- printf("Level Time: %d seconds\n", level->time);
+ printf("Level time: %d seconds\n", level->time);
printf("Gems needed: %d\n", level->gems_needed);
printf("\n");
- printf("Time for Magic Wall: %d seconds\n", level->time_magic_wall);
- printf("Time for Wheel: %d seconds\n", level->time_wheel);
- printf("Time for Light: %d seconds\n", level->time_light);
- printf("Time for Timegate: %d seconds\n", level->time_timegate);
+ printf("Time for magic wall: %d seconds\n", level->time_magic_wall);
+ printf("Time for wheel: %d seconds\n", level->time_wheel);
+ printf("Time for light: %d seconds\n", level->time_light);
+ printf("Time for timegate: %d seconds\n", level->time_timegate);
printf("\n");
- printf("Amoeba Speed: %d\n", level->amoeba_speed);
+ printf("Amoeba speed: %d\n", level->amoeba_speed);
printf("\n");
- printf("Gravity: %s\n", (level->initial_gravity ? "yes" : "no"));
- printf("Double Speed Movement: %s\n", (level->double_speed ? "yes" : "no"));
- printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
+ printf("Initial gravity: %s\n", (level->initial_gravity ? "yes" : "no"));
+ printf("Double speed movement: %s\n", (level->double_speed ? "yes" : "no"));
+ printf("EM style slippery gems: %s\n", (level->em_slippery_gems ? "yes" : "no"));
+ printf("Player blocks last field: %s\n", (level->block_last_field ? "yes" : "no"));
+ printf("SP player blocks last field: %s\n", (level->sp_block_last_field ? "yes" : "no"));
printf_line("-", 79);
}
player->present = TRUE;
+ player->block_last_field = (element == EL_SP_MURPHY ?
+ level.sp_block_last_field :
+ level.block_last_field);
+
if (!options.network || player->connected)
{
player->active = TRUE;
element_info[e].push_delay_random = push_delay_list[i].push_delay_random;
}
+ /* set push delay value for Supaplex elements for newer engine versions */
+ if (game.engine_version >= VERSION_IDENT(3,0,9,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;
+ }
+ }
+ }
+
/* ---------- initialize move stepsize ----------------------------------- */
/* initialize move stepsize values to default */
player->use_murphy_graphic = FALSE;
+ player->block_last_field = FALSE;
+
player->actual_frame_counter = 0;
player->step_counter = 0;
void RelocatePlayer(int x, int y, int element)
{
struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1];
+ boolean ffwd_delay = (tape.playing && tape.fast_forward);
+ boolean no_delay = (tape.index_search);
+ int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+ int wait_delay_value = (no_delay ? 0 : frame_delay_value);
if (player->GameOver) /* do not reanimate dead player */
return;
DrawPlayer(player);
BackToFront();
- Delay(GAME_FRAME_DELAY);
+ Delay(wait_delay_value);
}
DrawPlayer(player); /* needed here only to cleanup last field */
/* scroll in two steps of half tile size to make things smoother */
BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
FlushDisplay();
- Delay(GAME_FRAME_DELAY);
+ Delay(wait_delay_value);
/* scroll second step to align at full tile size */
BackToFront();
- Delay(GAME_FRAME_DELAY);
+ Delay(wait_delay_value);
}
}
}
#if 0
DrawPlayer(player);
#endif
+
return;
}
else if (!FrameReached(&player->actual_frame_counter, 1))
player->MovPos += (player->MovPos > 0 ? -1 : 1) * move_stepsize;
player->GfxPos = move_stepsize * (player->MovPos / move_stepsize);
- if (Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
+ if (!player->block_last_field &&
+ Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
Feld[last_jx][last_jy] = EL_EMPTY;
/* before DrawPlayer() to draw correct player graphic for this case */
}
#endif
+ if (player->block_last_field &&
+ Feld[last_jx][last_jy] == EL_PLAYER_IS_LEAVING)
+ Feld[last_jx][last_jy] = EL_EMPTY;
+
player->last_jx = jx;
player->last_jy = jy;
PlayLevelSoundAction(jx, jy, ACTION_DROPPING);
+#if 1
+ /* needed if previous element just changed to "empty" in the last frame */
+ Changed[jx][jy] = 0; /* allow another change */
+#endif
+
CheckTriggeredElementChange(jx, jy, new_element, CE_OTHER_GETS_DROPPED);
CheckElementChange(jx, jy, new_element, CE_DROPPED_BY_PLAYER);
}
else
{
- Changed[jx][jy] = 0; /* allow another change */
+ Changed[jx][jy] = 0; /* allow another change */
#if 1
TestIfElementHitsCustomElement(jx, jy, direction);
/* fundamental game speed values */
+#define ONE_SECOND_DELAY 1000 /* delay value for one second */
#define GAME_FRAME_DELAY 20 /* frame delay in milliseconds */
#define FFWD_FRAME_DELAY 10 /* 200% speed for fast forward */
-#define FRAMES_PER_SECOND (1000 / GAME_FRAME_DELAY)
+#define FRAMES_PER_SECOND (ONE_SECOND_DELAY / GAME_FRAME_DELAY)
#define MICROLEVEL_SCROLL_DELAY 50 /* delay for scrolling micro level */
#define MICROLEVEL_LABEL_DELAY 250 /* delay for micro level label */
boolean use_murphy_graphic;
+ boolean block_last_field;
+
boolean LevelSolved, GameOver;
int last_move_dir;
boolean double_speed;
boolean initial_gravity;
boolean em_slippery_gems; /* EM style "gems slip from wall" behaviour */
+ boolean block_last_field; /* player blocks previous field while moving */
+ boolean sp_block_last_field; /* player blocks previous field while moving */
short field[MAX_LEV_FIELDX][MAX_LEV_FIELDY];
boolean draw_masked = graphic_info[graphic].draw_masked;
int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
boolean ffwd_delay = (tape.playing && tape.fast_forward);
+ boolean no_delay = (tape.index_search);
unsigned long anim_delay = 0;
- int anim_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+ int frame_delay_value = (ffwd_delay ? FfwdFrameDelay : GameFrameDelay);
+ int anim_delay_value = (no_delay ? 0 : frame_delay_value);
int font_nr = FONT_ENVELOPE_1 + envelope_nr;
int font_width = getFontWidth(font_nr);
int font_height = getFontHeight(font_nr);
int sound_opening = element_info[element].sound[ACTION_OPENING];
int sound_closing = element_info[element].sound[ACTION_CLOSING];
boolean ffwd_delay = (tape.playing && tape.fast_forward);
- int wait_delay_value = (ffwd_delay ? 500 : 1000);
+ boolean no_delay = (tape.index_search);
+ int normal_delay_value = ONE_SECOND_DELAY / (ffwd_delay ? 2 : 1);
+ int wait_delay_value = (no_delay ? 0 : normal_delay_value);
int anim_mode = graphic_info[graphic].anim_mode;
int main_anim_mode = (anim_mode == ANIM_NONE ? ANIM_VERTICAL|ANIM_HORIZONTAL:
anim_mode == ANIM_DEFAULT ? ANIM_VERTICAL : anim_mode);