NULL,
NULL
},
+ {
+ EL_EXIT_CLOSING,
+ EL_EXIT_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
{
EL_SWITCHGATE_OPENING,
EL_SWITCHGATE_OPEN,
InitElementPropertiesEngine(game.engine_version);
#if 0
- printf("level %d: level version == %06d\n", level_nr, level.game_version);
- printf(" tape version == %06d [%s] [file: %06d]\n",
- tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
- tape.file_version);
- printf(" => game.engine_version == %06d\n", game.engine_version);
+ printf("level %d: level version == %06d\n", level_nr, level.game_version);
+ printf(" tape version == %06d [%s] [file: %06d]\n",
+ tape.engine_version, (tape.playing ? "PLAYING" : "RECORDING"),
+ tape.file_version);
+ printf(" => game.engine_version == %06d\n", game.engine_version);
#endif
/* ---------- initialize player's initial move delay --------------------- */
ei->change_events |= CH_EVENT_BIT(CE_DELAY);
}
+ /* set summarized change event CE_TOUCHING_ANY_SIDE_OF */
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
+
+ for (j=0; j < ei->num_change_pages; j++)
+ {
+ if (!ei->change_page[j].can_change)
+ continue;
+
+ /* check for change event of touching other element on some side */
+ if (ei->change_page[j].events & (CH_EVENT_BIT(CE_TOUCHING_ANY_SIDE_OF |
+ CE_TOUCHING_LEFT_OF |
+ CE_TOUCHING_RIGHT_OF |
+ CE_TOUCHING_TOP_OF |
+ CE_TOUCHING_BOTTOM_OF)))
+ ei->change_page[j].events |= CH_EVENT_BIT(CE_TOUCHING_SOME_SIDE);
+
+ /* add change event for each side when event exists for any side */
+ if (ei->change_page[j].events & CH_EVENT_BIT(CE_TOUCHING_ANY_SIDE_OF))
+ ei->change_page[j].events |= (CH_EVENT_BIT(CE_TOUCHING_LEFT_OF) |
+ CH_EVENT_BIT(CE_TOUCHING_RIGHT_OF) |
+ CH_EVENT_BIT(CE_TOUCHING_TOP_OF) |
+ CH_EVENT_BIT(CE_TOUCHING_BOTTOM_OF));
+ }
+ }
+
#if 1
/* add change events from custom element configuration */
for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
player->is_digging = FALSE;
player->is_collecting = FALSE;
+ player->show_envelope = FALSE;
+
player->move_delay = game.initial_move_delay;
player->move_delay_value = game.initial_move_delay_value;
JustStopped[x][y] = 0;
Stop[x][y] = FALSE;
Pushed[x][y] = FALSE;
- Changed[x][y] = FALSE;
+
+ Changed[x][y] = CE_BITMASK_DEFAULT;
+ ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
+
ExplodePhase[x][y] = 0;
ExplodeField[x][y] = EX_NO_EXPLOSION;
if (local_player->MovPos)
return;
+#if 1
+ if (tape.auto_play) /* tape might already be stopped here */
+ tape.auto_play_level_solved = TRUE;
+#else
if (tape.playing && tape.auto_play)
tape.auto_play_level_solved = TRUE;
+#endif
local_player->LevelSolved = FALSE;
StopSound(SND_GAME_LEVELTIME_BONUS);
}
+ /* close exit door after last player */
+ if (Feld[ExitX][ExitY] == EL_EXIT_OPEN && AllPlayersGone)
+ {
+ Feld[ExitX][ExitY] = EL_EXIT_CLOSING;
+
+ PlaySoundLevelElementAction(ExitX, ExitY, EL_EXIT_OPEN, ACTION_CLOSING);
+ }
+
/* Hero disappears */
DrawLevelField(ExitX, ExitY);
BackToFront();
Bang(x, y);
}
-void ShowEnvelope()
-{
- int graphic = IMG_GAME_ENVELOPE_BACKGROUND;
- boolean draw_masked = graphic_info[graphic].draw_masked;
- int mask_mode = (draw_masked ? BLIT_MASKED : BLIT_ON_BACKGROUND);
- int font_nr = FONT_TEXT_1;
- int font_width = getFontWidth(font_nr);
- int font_height = getFontHeight(font_nr);
- int i, x, y;
-
- /* open envelope window horizontally */
- for (i = 2; i <= level.envelope_xsize + 2; i += 2)
- {
- int startx = (SXSIZE / font_width - i) / 2;
- int starty = (SYSIZE / font_height) / 2 - 1;
-
- SetDrawtoField(DRAW_BUFFERED);
-
- BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
-
- SetDrawtoField(DRAW_BACKBUFFER);
-
- for (y=0; y < 2; y++) for (x=0; x < i; x++)
- {
- int sx = SX + (startx + x) * font_width;
- int sy = SY + (starty + y) * font_height;
- int ex = (x == 0 ? -1 : x == i - 1 ? +1 : 0);
- int ey = (y == 0 ? -1 : y == 1 ? +1 : 0);
-
- DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
- }
-
- redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
- BackToFront();
-
- Delay(GAME_FRAME_DELAY);
-
- /* special case: envelope has odd width */
- if (level.envelope_xsize % 2 && i == 2)
- i--;
- }
-
- /* open envelope window vertically */
- for (i = 2; i <= level.envelope_ysize + 2; i += 2)
- {
- int xsize = level.envelope_xsize + 2;
- int startx = (SXSIZE / font_width - (xsize - 1)) / 2;
- int starty = (SYSIZE / font_height - i) / 2;
-
- SetDrawtoField(DRAW_BUFFERED);
-
- BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
-
- SetDrawtoField(DRAW_BACKBUFFER);
-
- for (y=0; y < i; y++) for (x=0; x < xsize; x++)
- {
- int sx = SX + (startx + x) * font_width;
- int sy = SY + (starty + y) * font_height;
- int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
- int ey = (y == 0 ? -1 : y == i - 1 ? +1 : 0);
-
- DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
- }
-
- DrawTextToTextArea(SX + (startx + 1) * font_width,
- SY + (starty + 1) * font_height, level.envelope,
- FONT_TEXT_1, level.envelope_xsize, i - 2, mask_mode);
-
- redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
- BackToFront();
-
- Delay(GAME_FRAME_DELAY);
-
- /* special case: envelope has odd height */
- if (level.envelope_ysize % 2 && i == 2)
- i--;
- }
-
- if (tape.playing)
- Delay(1000);
- else
- WaitForEventToContinue();
-
- /* close envelope window vertically */
- for (i = level.envelope_ysize + 2; i >= 2; i -= 2)
- {
- int xsize = level.envelope_xsize + 2;
- int startx = (SXSIZE / font_width - (xsize - 1)) / 2;
- int starty = (SYSIZE / font_height - i) / 2;
-
- SetDrawtoField(DRAW_BUFFERED);
-
- BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
-
- SetDrawtoField(DRAW_BACKBUFFER);
-
- for (y=0; y < i; y++) for (x=0; x < xsize; x++)
- {
- int sx = SX + (startx + x) * font_width;
- int sy = SY + (starty + y) * font_height;
- int ex = (x == 0 ? -1 : x == xsize - 1 ? +1 : 0);
- int ey = (y == 0 ? -1 : y == i - 1 ? +1 : 0);
-
- DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
- }
-
- DrawTextToTextArea(SX + (startx + 1) * font_width,
- SY + (starty + 1) * font_height, level.envelope,
- FONT_TEXT_1, level.envelope_xsize, i - 2, mask_mode);
-
- redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
- BackToFront();
-
- Delay(GAME_FRAME_DELAY);
-
- /* special case: envelope has odd height */
- if (level.envelope_ysize % 2 && i == level.envelope_ysize + 2)
- i++;
- }
-
- /* close envelope window horizontally */
- for (i = level.envelope_xsize + 2; i >= 2; i -= 2)
- {
- int startx = (SXSIZE / font_width - i) / 2;
- int starty = (SYSIZE / font_height) / 2 - 1;
-
- SetDrawtoField(DRAW_BUFFERED);
-
- BlitBitmap(fieldbuffer, backbuffer, FX, FY, SXSIZE, SYSIZE, SX, SY);
-
- SetDrawtoField(DRAW_BACKBUFFER);
-
- for (y=0; y < 2; y++) for (x=0; x < i; x++)
- {
- int sx = SX + (startx + x) * font_width;
- int sy = SY + (starty + y) * font_height;
- int ex = (x == 0 ? -1 : x == i - 1 ? +1 : 0);
- int ey = (y == 0 ? -1 : y == 1 ? +1 : 0);
-
- DrawEnvelopeBackground(sx, sy, ex, ey, font_nr);
- }
-
- redraw_mask |= REDRAW_FIELD | REDRAW_FROM_BACKBUFFER;
- BackToFront();
-
- Delay(GAME_FRAME_DELAY);
-
- /* special case: envelope has odd width */
- if (level.envelope_xsize % 2 && i == level.envelope_xsize + 2)
- i++;
- }
-
- SetDrawtoField(DRAW_BUFFERED);
-
- redraw_mask |= REDRAW_FIELD;
- BackToFront();
-}
-
void RelocatePlayer(int x, int y, int element)
{
struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1];
ExplodePhase[x][y] = (phase < last_phase ? phase + 1 : 0);
+#ifdef DEBUG
+
+ /* activate this even in non-DEBUG version until cause for crash in
+ getGraphicAnimationFrame() (see below) is found and eliminated */
+#endif
+#if 1
+
+ if (GfxElement[x][y] == EL_UNDEFINED)
+ {
+ printf("\n\n\n");
+ printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y);
+ printf("Explode(): This should never happen!\n");
+ printf("\n\n\n");
+
+ GfxElement[x][y] = EL_EMPTY;
+ }
+#endif
+
if (phase == first_phase_after_start)
{
int element = Store2[x][y];
InitMovDir(x, y);
DrawLevelField(x, y);
+ TestIfElementTouchesCustomElement(x, y);
+
if (CAN_BE_CRUMBLED(element))
DrawLevelFieldCrumbledSandNeighbours(x, y);
/* copy element change control values to new field */
ChangeDelay[newx][newy] = ChangeDelay[x][y];
+ Changed[newx][newy] = Changed[x][y];
+ ChangeEvent[newx][newy] = ChangeEvent[x][y];
+
+ ChangeDelay[x][y] = 0;
+ Changed[x][y] = CE_BITMASK_DEFAULT;
+ ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
/* copy animation control values to new field */
GfxFrame[newx][newy] = GfxFrame[x][y];
if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
CheckElementChange(newx, newy, element, CE_COLLISION);
+#if 1
+ TestIfElementTouchesCustomElement(x, y); /* for empty space */
+#endif
+
TestIfPlayerTouchesCustomElement(newx, newy);
TestIfElementTouchesCustomElement(newx, newy);
}
return;
}
+ if (AllPlayersGone) /* do not re-open exit door closed after last player */
+ return;
+
Feld[x][y] = EL_EXIT_OPENING;
PlaySoundLevelNearest(x, y, SND_CLASS_EXIT_OPENING);
RemoveField(x, y);
Feld[x][y] = target_element;
- Changed[x][y] = TRUE; /* no more changes in this frame */
+ Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
RelocatePlayer(x, y, target_element);
}
-static void ChangeElementNow(int x, int y, int element, int page)
+static boolean ChangeElementNow(int x, int y, int element, int page)
{
struct ElementChangeInfo *change = &element_info[element].change_page[page];
- Changed[x][y] = TRUE; /* no more changes in this frame */
+ /* always use default change event to prevent running into a loop */
+ if (ChangeEvent[x][y] == CE_BITMASK_DEFAULT)
+ ChangeEvent[x][y] = CH_EVENT_BIT(CE_DELAY);
+
+ /* do not change already changed elements with same change event */
+#if 0
+ if (Changed[x][y] & ChangeEvent[x][y])
+ return FALSE;
+#else
+ if (Changed[x][y])
+ return FALSE;
+#endif
+
+ Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING);
if (change->explode)
{
Bang(x, y);
- return;
+
+ return TRUE;
}
if (change->use_content)
if (change->only_complete && change->use_random_change &&
RND(100) < change->random)
- return;
+ return FALSE;
for (yy = 0; yy < 3; yy++) for(xx = 0; xx < 3 ; xx++)
{
PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING);
}
+
+ return TRUE;
}
static void ChangeElement(int x, int y, int page)
return;
}
- ChangeElementNow(x, y, element, page);
-
- if (change->post_change_function)
- change->post_change_function(x, y);
+ if (ChangeElementNow(x, y, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(x, y);
+ }
}
}
if (x == lx && y == ly) /* do not change trigger element itself */
continue;
+#if 0
if (Changed[x][y]) /* do not change already changed elements */
continue;
+#endif
if (Feld[x][y] == element)
{
ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
ChangeElement(x, y, page);
#if 0
Blocked2Moving(x, y, &x, &y);
ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
ChangeElement(x, y, page);
return TRUE;
for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
- Changed[x][y] = FALSE;
+ Changed[x][y] = CE_BITMASK_DEFAULT;
+ ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
Stop[x][y] = FALSE;
if (JustStopped[x][y] > 0)
stored_player[i].StepFrame += move_frames;
}
#endif
+
+#if 1
+ if (local_player->show_envelope && local_player->MovPos == 0)
+ {
+ ShowEnvelope();
+
+ local_player->show_envelope = FALSE;
+ }
+#endif
}
static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
DrawPlayer(player); /* needed here only to cleanup last field */
#endif
- if (player->MovPos == 0)
+ if (player->MovPos == 0) /* player reached destination field */
{
if (IS_PASSABLE(Feld[last_jx][last_jy]))
{
{ +1, 0 },
{ 0, +1 }
};
+ static int touching_side[4][2] =
+ {
+ { CE_TOUCHING_TOP_OF, CE_TOUCHING_BOTTOM_OF },
+ { CE_TOUCHING_LEFT_OF, CE_TOUCHING_RIGHT_OF },
+ { CE_TOUCHING_RIGHT_OF, CE_TOUCHING_LEFT_OF },
+ { CE_TOUCHING_BOTTOM_OF, CE_TOUCHING_TOP_OF }
+ };
boolean change_center_element = FALSE;
int center_element_change_page = 0;
+ int center_element_change_event = 0;
int center_element = Feld[x][y];
int i, j;
{
int xx = x + xy[i][0];
int yy = y + xy[i][1];
+ int change_event_center = touching_side[i][0];
+ int change_event_border = touching_side[i][1];
int border_element;
if (!IN_LEV_FIELD(xx, yy))
/* check for change of center element (but change it only once) */
if (IS_CUSTOM_ELEMENT(center_element) &&
- HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) &&
+ HAS_ANY_CHANGE_EVENT(center_element, change_event_border) &&
!change_center_element)
{
for (j=0; j < element_info[center_element].num_change_pages; j++)
struct ElementChangeInfo *change =
&element_info[center_element].change_page[j];
- if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ if (change->events & CH_EVENT_BIT(change_event_border) &&
change->trigger_element == border_element)
{
change_center_element = TRUE;
center_element_change_page = j;
+ center_element_change_event = change_event_border;
break;
}
/* check for change of border element */
if (IS_CUSTOM_ELEMENT(border_element) &&
- HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING))
+ HAS_ANY_CHANGE_EVENT(border_element, change_event_center))
{
for (j=0; j < element_info[border_element].num_change_pages; j++)
{
struct ElementChangeInfo *change =
&element_info[border_element].change_page[j];
- if (change->events & CH_EVENT_BIT(CE_OTHER_IS_TOUCHING) &&
+ if (change->events & CH_EVENT_BIT(change_event_center) &&
change->trigger_element == center_element)
{
- CheckElementChangeExt(xx,yy, border_element,CE_OTHER_IS_TOUCHING, j);
+ CheckElementChangeExt(xx,yy, border_element, change_event_center, j);
break;
}
}
}
if (change_center_element)
- CheckElementChangeExt(x, y, center_element, CE_OTHER_IS_TOUCHING,
+ CheckElementChangeExt(x, y, center_element, center_element_change_event,
center_element_change_page);
#if 0
CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED);
- TestIfElementTouchesCustomElement(x, y);
+ TestIfElementTouchesCustomElement(x, y); /* for empty space */
break;
}
}
else if (element == EL_ENVELOPE)
{
+#if 1
+ player->show_envelope = TRUE;
+#else
ShowEnvelope();
+#endif
}
else if (IS_DROPPABLE(element)) /* can be collected and dropped */
{
CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED);
- TestIfElementTouchesCustomElement(x, y);
+ TestIfElementTouchesCustomElement(x, y); /* for empty space */
break;
}