static void TestIfPlayerTouchesCustomElement(int, int);
static void TestIfElementTouchesCustomElement(int, int);
+static boolean CheckTriggeredElementSideChange(int, int, int, int, int);
static boolean CheckTriggeredElementChange(int, int, int, int);
+static boolean CheckElementSideChange(int, int, int, int, int, int);
static boolean CheckElementChange(int, int, int, int);
-static void ChangeElementNow(int, int, int);
static void PlaySoundLevel(int, int, int);
static void PlaySoundLevelNearest(int, int, int);
void (*post_change_function)(int x, int y);
};
-static struct ChangingElementInfo changing_element_list[] =
+static struct ChangingElementInfo change_delay_list[] =
{
{
EL_NUT_BREAKING,
NULL,
NULL
},
+ {
+ EL_EXIT_CLOSING,
+ EL_EXIT_CLOSED,
+ 29,
+ NULL,
+ NULL,
+ NULL
+ },
{
EL_SWITCHGATE_OPENING,
EL_SWITCHGATE_OPEN,
{ EL_UNDEFINED, 0 },
};
-static boolean changing_element[MAX_NUM_ELEMENTS];
static unsigned long trigger_events[MAX_NUM_ELEMENTS];
-#define IS_AUTO_CHANGING(e) (changing_element[e])
+#define IS_AUTO_CHANGING(e) (element_info[e].change_events & \
+ CH_EVENT_BIT(CE_DELAY))
#define IS_JUST_CHANGING(x, y) (ChangeDelay[x][y] != 0)
#define IS_CHANGING(x, y) (IS_AUTO_CHANGING(Feld[x][y]) || \
IS_JUST_CHANGING(x, y))
+#define CE_PAGE(e, ce) (element_info[e].event_page[ce])
+
void GetPlayerConfig()
{
MovDir[x][y] = 1 << RND(4);
break;
+#if 0
case EL_SP_EMPTY:
Feld[x][y] = EL_EMPTY;
break;
+#endif
+#if 0
case EL_EM_KEY_1_FILE:
Feld[x][y] = EL_EM_KEY_1;
break;
case EL_EM_KEY_4_FILE:
Feld[x][y] = EL_EM_KEY_4;
break;
+#endif
case EL_CONVEYOR_BELT_1_SWITCH_LEFT:
case EL_CONVEYOR_BELT_1_SWITCH_MIDDLE:
static void InitGameEngine()
{
- int i;
+ int i, j, k;
/* set game engine from tape file when re-playing, else from level file */
game.engine_version = (tape.playing ? tape.engine_version :
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 --------------------- */
/* initialize changing elements information */
for (i=0; i < MAX_NUM_ELEMENTS; i++)
{
+ struct ElementInfo *ei = &element_info[i];
+
/* this pointer might have been changed in the level editor */
- element_info[i].change = &element_info[i].change_page[0];
+ ei->change = &ei->change_page[0];
if (!IS_CUSTOM_ELEMENT(i))
{
- element_info[i].change->target_element = EL_EMPTY_SPACE;
- element_info[i].change->delay_fixed = 0;
- element_info[i].change->delay_random = 0;
- element_info[i].change->delay_frames = 1;
+ ei->change->target_element = EL_EMPTY_SPACE;
+ ei->change->delay_fixed = 0;
+ ei->change->delay_random = 0;
+ ei->change->delay_frames = 1;
}
- changing_element[i] = FALSE;
+ ei->change_events = CE_BITMASK_DEFAULT;
+ for (j=0; j < NUM_CHANGE_EVENTS; j++)
+ {
+ ei->event_page_nr[j] = 0;
+ ei->event_page[j] = &ei->change_page[0];
+ }
}
/* add changing elements from pre-defined list */
- for (i=0; changing_element_list[i].element != EL_UNDEFINED; i++)
+ for (i=0; change_delay_list[i].element != EL_UNDEFINED; i++)
{
- int element = changing_element_list[i].element;
- struct ChangingElementInfo *ce = &changing_element_list[i];
- struct ElementChangeInfo *change = element_info[element].change;
+ struct ChangingElementInfo *ch_delay = &change_delay_list[i];
+ struct ElementInfo *ei = &element_info[ch_delay->element];
+
+ ei->change->target_element = ch_delay->target_element;
+ ei->change->delay_fixed = ch_delay->change_delay;
+
+ ei->change->pre_change_function = ch_delay->pre_change_function;
+ ei->change->change_function = ch_delay->change_function;
+ ei->change->post_change_function = ch_delay->post_change_function;
+
+ ei->change_events |= CH_EVENT_BIT(CE_DELAY);
+ }
- change->target_element = ce->target_element;
- change->delay_fixed = ce->change_delay;
+#if 1
+ /* add change events from custom element configuration */
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
- change->pre_change_function = ce->pre_change_function;
- change->change_function = ce->change_function;
- change->post_change_function = ce->post_change_function;
+ for (j=0; j < ei->num_change_pages; j++)
+ {
+ if (!ei->change_page[j].can_change)
+ continue;
- changing_element[element] = TRUE;
+ for (k=0; k < NUM_CHANGE_EVENTS; k++)
+ {
+ /* only add event page for the first page found with this event */
+ if (ei->change_page[j].events & CH_EVENT_BIT(k) &&
+ !(ei->change_events & CH_EVENT_BIT(k)))
+ {
+ ei->change_events |= CH_EVENT_BIT(k);
+ ei->event_page_nr[k] = j;
+ ei->event_page[k] = &ei->change_page[j];
+ }
+ }
+ }
}
- /* add changing elements from custom element configuration */
+#else
+
+ /* add change events from custom element configuration */
for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
{
int element = EL_CUSTOM_START + i;
/* only add custom elements that change after fixed/random frame delay */
- if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, CE_DELAY))
- continue;
-
- changing_element[element] = TRUE;
+ if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
+ element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY);
}
+#endif
/* ---------- initialize trigger events ---------------------------------- */
for (i=0; i<MAX_NUM_ELEMENTS; i++)
trigger_events[i] = EP_BITMASK_DEFAULT;
+#if 1
+ /* add trigger events from element change event properties */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[i];
+
+ for (j=0; j < ei->num_change_pages; j++)
+ {
+ if (!ei->change_page->can_change)
+ continue;
+
+ if (ei->change_page[j].events & CH_EVENT_BIT(CE_BY_OTHER_ACTION))
+ {
+ int trigger_element = ei->change_page[j].trigger_element;
+
+ trigger_events[trigger_element] |= ei->change_page[j].events;
+ }
+ }
+ }
+#else
/* add trigger events from element change event properties */
for (i=0; i<MAX_NUM_ELEMENTS; i++)
- if (HAS_CHANGE_EVENT(i, CE_BY_OTHER))
+ if (HAS_CHANGE_EVENT(i, CE_BY_OTHER_ACTION))
trigger_events[element_info[i].change->trigger_element] |=
element_info[i].change->events;
+#endif
/* ---------- initialize push delay -------------------------------------- */
player->is_digging = FALSE;
player->is_collecting = FALSE;
+ player->show_envelope = 0;
+
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;
- Changing[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 (CAN_CHANGE(element))
{
- content = element_info[element].change->target_element;
- is_player = ELEM_IS_PLAYER(content);
-
- if (is_player && (found_rating < 3 || element < found_element))
+ for (i=0; i < element_info[element].num_change_pages; i++)
{
- start_x = x;
- start_y = y;
+ content = element_info[element].change_page[i].target_element;
+ is_player = ELEM_IS_PLAYER(content);
- found_rating = 3;
- found_element = element;
+ if (is_player && (found_rating < 3 || element < found_element))
+ {
+ start_x = x;
+ start_y = y;
+
+ found_rating = 3;
+ found_element = element;
+ }
}
}
if (!CAN_CHANGE(element))
continue;
- content = element_info[element].change->content[xx][yy];
- is_player = ELEM_IS_PLAYER(content);
-
- if (is_player && (found_rating < 1 || element < found_element))
+ for (i=0; i < element_info[element].num_change_pages; i++)
{
- start_x = x + xx - 1;
- start_y = y + yy - 1;
+ content = element_info[element].change_page[i].content[xx][yy];
+ is_player = ELEM_IS_PLAYER(content);
- found_rating = 1;
- found_element = element;
+ if (is_player && (found_rating < 1 || element < found_element))
+ {
+ start_x = x + xx - 1;
+ start_y = y + yy - 1;
+
+ found_rating = 1;
+ found_element = element;
+ }
}
}
}
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();
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");
+ printf("Explode(): x = %d, y = %d: GfxElement == EL_UNDEFINED\n", x, y);
+ printf("Explode(): This should never happen!\n");
+ printf("\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);
PlaySoundLevel(x, y, SND_PEARL_BREAKING);
return;
}
-#if 1
else if (impact && CheckElementChange(x, y, element, CE_IMPACT))
{
PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT);
return;
}
-#else
- else if (impact && CAN_CHANGE(element) &&
- HAS_CHANGE_EVENT(element, CE_IMPACT))
- {
- PlaySoundLevelElementAction(x, y, element, ACTION_IMPACT);
-
- ChangeElementNow(x, y, element);
-
- return;
- }
-#endif
if (impact && element == EL_AMOEBA_DROP)
{
{
ToggleLightSwitch(x, y + 1);
}
-#if 1
else
{
CheckElementChange(x, y + 1, smashed, CE_SMASHED);
}
-#else
- else if (CAN_CHANGE(smashed) && HAS_CHANGE_EVENT(smashed, CE_SMASHED))
- {
- ChangeElementNow(x, y + 1, smashed);
- }
-#endif
}
else
{
#endif
}
#if 1
+
+#if 0
+ else if (CAN_SMASH(element) &&
+ (Feld[x][y + 1] == EL_BLOCKED ||
+ IS_PLAYER(x, y + 1)) &&
+ JustStopped[x][y] && !Pushed[x][y + 1])
+
+#else
#if 1
else if (game.engine_version < RELEASE_IDENT(2,2,0,7) &&
CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
else if (CAN_SMASH(element) && Feld[x][y + 1] == EL_BLOCKED &&
JustStopped[x][y])
#endif
+#endif
+
{
/* calling "Impact()" here is not only completely unneccessary
(because it already gets called from "ContinueMoving()" in
/* 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);
{
/* check if element under player changes from accessible to unaccessible
(needed for special case of dropping element which then changes) */
- if (IS_PLAYER(x, y) &&
+ if (IS_PLAYER(x, y) && !PLAYER_PROTECTED(x, y) &&
IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element))
{
Bang(x, y);
RemoveField(x, y);
Feld[x][y] = target_element;
+ 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)
+static boolean ChangeElementNow(int x, int y, int element, int page)
{
- struct ElementChangeInfo *change = element_info[element].change;
+ struct ElementChangeInfo *change = &element_info[element].change_page[page];
-#if 0
- if (element >= EL_CUSTOM_START + 17 && element <= EL_CUSTOM_START + 39)
- printf("::: changing... [%d]\n", FrameCounter);
-#endif
+ /* 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
- /* prevent CheckTriggeredElementChange() from looping */
- Changing[x][y] = TRUE;
+ if (Changed[x][y] & ChangeEvent[x][y])
+ return FALSE;
+#else
+ if (Changed[x][y])
+ return FALSE;
#endif
- CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING);
+ Changed[x][y] |= ChangeEvent[x][y]; /* ignore same changes in this frame */
-#if 0
- Changing[x][y] = FALSE;
-#endif
+ 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++)
{
something_has_changed = TRUE;
- /* for symmetry reasons, stop newly created border elements */
+ /* for symmetry reasons, freeze newly created border elements */
if (ex != x || ey != y)
- Stop[ex][ey] = TRUE;
+ Stop[ex][ey] = TRUE; /* no more moving in this frame */
}
}
PlaySoundLevelElementAction(x, y, element, ACTION_CHANGING);
}
+
+ return TRUE;
}
-static void ChangeElement(int x, int y)
+static void ChangeElement(int x, int y, int page)
{
-#if 1
int element = MovingOrBlocked2Element(x, y);
-#else
- int element = Feld[x][y];
+ struct ElementChangeInfo *change = &element_info[element].change_page[page];
+
+#if 0
+#ifdef DEBUG
+ if (!CAN_CHANGE(element))
+ {
+ printf("\n\n");
+ printf("ChangeElement(): %d,%d: element = %d ('%s')\n",
+ x, y, element, element_info[element].token_name);
+ printf("ChangeElement(): This should never happen!\n");
+ printf("\n\n");
+ }
+#endif
#endif
- struct ElementChangeInfo *change = element_info[element].change;
if (ChangeDelay[x][y] == 0) /* initialize element change */
{
-#if 1
ChangeDelay[x][y] = ( change->delay_fixed * change->delay_frames +
RND(change->delay_random * change->delay_frames)) + 1;
-#else
- ChangeDelay[x][y] = changing_element[element].change_delay + 1;
-
- if (IS_CUSTOM_ELEMENT(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
- {
- int max_random_delay = element_info[element].change->delay_random;
- int delay_frames = element_info[element].change->delay_frames;
-
- ChangeDelay[x][y] += RND(max_random_delay * delay_frames);
- }
-#endif
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
-#if 1
if (change->pre_change_function)
change->pre_change_function(x, y);
-#else
- if (changing_element[element].pre_change_function)
- changing_element[element].pre_change_function(x, y);
-#endif
}
ChangeDelay[x][y]--;
if (IS_ANIMATED(graphic))
DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
-#if 1
if (change->change_function)
change->change_function(x, y);
-#else
- if (changing_element[element].change_function)
- changing_element[element].change_function(x, y);
-#endif
}
else /* finish element change */
{
-#if 0
- int next_element = changing_element[element].next_element;
-#endif
-
if (IS_MOVING(x, y)) /* never change a running system ;-) */
{
ChangeDelay[x][y] = 1; /* try change after next move step */
return;
}
-#if 1
- ChangeElementNow(x, y, element);
-
- if (change->post_change_function)
- change->post_change_function(x, y);
-#else
- if (next_element != EL_UNDEFINED)
- ChangeElementNow(x, y, next_element);
- else
- ChangeElementNow(x, y, element_info[element].change->target_element);
-
- if (changing_element[element].post_change_function)
- changing_element[element].post_change_function(x, y);
-#endif
+ if (ChangeElementNow(x, y, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(x, y);
+ }
}
}
-static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
- int trigger_event)
+static boolean CheckTriggeredElementSideChange(int lx, int ly,
+ int trigger_element,
+ int trigger_side,
+ int trigger_event)
{
- int i, x, y;
+ int i, j, x, y;
if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
return FALSE;
- /* prevent this function from running into a loop */
- if (trigger_event == CE_OTHER_IS_CHANGING)
- Changing[lx][ly] = TRUE;
-
- for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
{
- if (!CAN_CHANGE(i) || !HAS_CHANGE_EVENT(i, trigger_event) ||
- element_info[i].change->trigger_element != trigger_element)
+ int element = EL_CUSTOM_START + i;
+
+ boolean change_element = FALSE;
+ int page;
+
+ if (!CAN_CHANGE(element) ||
+ !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+ continue;
+
+ for (j=0; j < element_info[element].num_change_pages; j++)
+ {
+ struct ElementChangeInfo *change = &element_info[element].change_page[j];
+
+ if (change->sides & trigger_side &&
+ change->trigger_element == trigger_element)
+ {
+ change_element = TRUE;
+ page = j;
+
+ break;
+ }
+ }
+
+ if (!change_element)
continue;
for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
+#if 0
if (x == lx && y == ly) /* do not change trigger element itself */
continue;
+#endif
- if (Changing[x][y]) /* do not change just changing elements */
- continue;
-
- if (Feld[x][y] == i)
+ if (Feld[x][y] == element)
{
ChangeDelay[x][y] = 1;
- ChangeElement(x, y);
-
- Changing[x][y] = TRUE; /* do not change just changed elements */
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeElement(x, y, page);
}
}
}
- /* reset change prevention array */
- for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
- Changing[x][y] = FALSE;
-
return TRUE;
}
-static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
+ int trigger_event)
+{
+ return CheckTriggeredElementSideChange(lx, ly, trigger_element, CH_SIDE_ANY,
+ trigger_event);
+}
+
+static boolean CheckElementSideChange(int x, int y, int element, int side,
+ int trigger_event, int page)
{
- if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, trigger_event))
+ if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
return FALSE;
if (Feld[x][y] == EL_BLOCKED)
+ {
Blocked2Moving(x, y, &x, &y);
+ element = Feld[x][y];
+ }
+
+ if (page < 0)
+ page = element_info[element].event_page_nr[trigger_event];
+
+ if (!(element_info[element].change_page[page].sides & side))
+ return FALSE;
ChangeDelay[x][y] = 1;
- ChangeElement(x, y);
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeElement(x, y, page);
return TRUE;
}
+static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+{
+ return CheckElementSideChange(x, y, element, CH_SIDE_ANY, trigger_event, -1);
+}
+
static void PlayerActions(struct PlayerInfo *player, byte player_action)
{
static byte stored_player_action[MAX_PLAYERS];
CheckGravityMovement(player);
if (player->MovPos == 0)
- {
-#if 0
- printf("Trying... Player frame reset\n");
-#endif
-
InitPlayerGfxAnimation(player, ACTION_DEFAULT, player->MovDir);
- }
if (player->MovPos == 0) /* needed for tape.playing */
player->is_moving = FALSE;
for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
+ Changed[x][y] = CE_BITMASK_DEFAULT;
+ ChangeEvent[x][y] = CE_BITMASK_DEFAULT;
+
Stop[x][y] = FALSE;
if (JustStopped[x][y] > 0)
JustStopped[x][y]--;
#if 1
/* reset finished pushing action (not done in ContinueMoving() to allow
- continous pushing animation for elements without push delay) */
+ continous pushing animation for elements with zero push delay) */
if (GfxAction[x][y] == ACTION_PUSHING && !IS_MOVING(x, y))
{
ResetGfxAnimation(x, y);
/* this may take place after moving, so 'element' may have changed */
if (IS_CHANGING(x, y))
{
- ChangeElement(x, y);
+ ChangeElement(x, y, element_info[element].event_page_nr[CE_DELAY]);
element = Feld[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
}
stored_player[i].StepFrame += move_frames;
}
#endif
+
+#if 1
+ if (local_player->show_envelope != 0 && local_player->MovPos == 0)
+ {
+ ShowEnvelope(local_player->show_envelope - EL_ENVELOPE_1);
+
+ local_player->show_envelope = 0;
+ }
+#endif
}
static boolean AllPlayersInSight(struct PlayerInfo *player, int x, int y)
boolean MoveFigureOneStep(struct PlayerInfo *player,
int dx, int dy, int real_dx, int real_dy)
{
+ static int change_sides[4][2] =
+ {
+ /* enter side leave side */
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */
+ };
+ int move_direction = (dx == -1 ? MV_LEFT :
+ dx == +1 ? MV_RIGHT :
+ dy == -1 ? MV_UP :
+ dy == +1 ? MV_DOWN : MV_NO_MOVING);
+ int enter_side = change_sides[MV_DIR_BIT(move_direction)][0];
+ int leave_side = change_sides[MV_DIR_BIT(move_direction)][1];
int jx = player->jx, jy = player->jy;
- int new_jx = jx+dx, new_jy = jy+dy;
+ int new_jx = jx + dx, new_jy = jy + dy;
int element;
int can_move;
StorePlayer[jx][jy] = 0;
player->last_jx = jx;
player->last_jy = jy;
- jx = player->jx = new_jx;
- jy = player->jy = new_jy;
- StorePlayer[jx][jy] = player->element_nr;
+ player->jx = new_jx;
+ player->jy = new_jy;
+ StorePlayer[new_jx][new_jy] = player->element_nr;
player->MovPos =
(dx > 0 || dy > 0 ? -1 : 1) * (TILEX - TILEX / player->move_delay_value);
ScrollFigure(player, SCROLL_INIT);
+#if 1
+ if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
+ {
+ CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy], leave_side,
+ CE_OTHER_GETS_LEFT);
+ CheckElementSideChange(jx, jy, Feld[jx][jy], leave_side,
+ CE_LEFT_BY_PLAYER, -1);
+ }
+
+ if (IS_CUSTOM_ELEMENT(Feld[new_jx][new_jy]))
+ {
+ CheckTriggeredElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy],
+ enter_side, CE_OTHER_GETS_ENTERED);
+ CheckElementSideChange(new_jx, new_jy, Feld[new_jx][new_jy], enter_side,
+ CE_ENTERED_BY_PLAYER, -1);
+ }
+#endif
+
return MF_MOVING;
}
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]))
{
void TestIfPlayerTouchesCustomElement(int x, int y)
{
+#if 0
static boolean check_changing = FALSE;
+#endif
static int xy[4][2] =
{
{ 0, -1 },
};
int i;
+#if 0
if (check_changing) /* prevent this function from running into a loop */
return;
check_changing = TRUE;
+#endif
for (i=0; i<4; i++)
{
}
}
+#if 0
check_changing = FALSE;
+#endif
}
void TestIfElementTouchesCustomElement(int x, int y)
{
+#if 0
static boolean check_changing = FALSE;
+#endif
static int xy[4][2] =
{
{ 0, -1 },
{ +1, 0 },
{ 0, +1 }
};
+ static int change_sides[4][2] =
+ {
+ /* center side border side */
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM }, /* check top */
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* check left */
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* check right */
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP } /* check bottom */
+ };
boolean change_center_element = FALSE;
+ int center_element_change_page = 0;
int center_element = Feld[x][y];
- int i;
+ int i, j;
+#if 0
if (check_changing) /* prevent this function from running into a loop */
return;
check_changing = TRUE;
+#endif
for (i=0; i<4; i++)
{
int xx = x + xy[i][0];
int yy = y + xy[i][1];
+ int center_side = change_sides[i][0];
+ int border_side = change_sides[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) &&
- border_element == element_info[center_element].change->trigger_element)
- change_center_element = TRUE;
+ HAS_ANY_CHANGE_EVENT(center_element, CE_OTHER_IS_TOUCHING) &&
+ !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) &&
+ change->sides & border_side &&
+ change->trigger_element == border_element)
+ {
+ change_center_element = TRUE;
+ center_element_change_page = j;
+
+ break;
+ }
+ }
+ }
/* check for change of border element */
if (IS_CUSTOM_ELEMENT(border_element) &&
- center_element == element_info[border_element].change->trigger_element)
- CheckElementChange(xx, yy, border_element, CE_OTHER_IS_TOUCHING);
+ HAS_ANY_CHANGE_EVENT(border_element, CE_OTHER_IS_TOUCHING))
+ {
+ 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) &&
+ change->sides & center_side &&
+ change->trigger_element == center_element)
+ {
+ CheckElementSideChange(xx, yy, border_element, CH_SIDE_ANY,
+ CE_OTHER_IS_TOUCHING, j);
+ break;
+ }
+ }
+ }
}
if (change_center_element)
- CheckElementChange(x, y, center_element, CE_OTHER_IS_TOUCHING);
+ CheckElementSideChange(x, y, center_element, CH_SIDE_ANY,
+ CE_OTHER_IS_TOUCHING, center_element_change_page);
+#if 0
check_changing = FALSE;
+#endif
}
void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
int DigField(struct PlayerInfo *player,
int x, int y, int real_dx, int real_dy, int mode)
{
+#if 0
+ static int change_sides[4][2] =
+ {
+ /* enter side leave side */
+ { CH_SIDE_RIGHT, CH_SIDE_LEFT }, /* moving left */
+ { CH_SIDE_LEFT, CH_SIDE_RIGHT }, /* moving right */
+ { CH_SIDE_BOTTOM, CH_SIDE_TOP }, /* moving up */
+ { CH_SIDE_TOP, CH_SIDE_BOTTOM } /* moving down */
+ };
+#endif
boolean use_spring_bug = (game.engine_version < VERSION_IDENT(2,2,0));
int jx = player->jx, jy = player->jy;
int dx = x - jx, dy = y - jy;
dx == +1 ? MV_RIGHT :
dy == -1 ? MV_UP :
dy == +1 ? MV_DOWN : MV_NO_MOVING);
+#if 0
+ int enter_side = change_sides[MV_DIR_BIT(move_direction)][0];
+ int leave_side = change_sides[MV_DIR_BIT(move_direction)][1];
+#endif
int element;
if (player->MovPos == 0)
PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING);
+ CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED);
+
+ TestIfElementTouchesCustomElement(x, y); /* for empty space */
+
break;
}
else if (IS_COLLECTIBLE(element))
el2edimg(EL_KEY_1 + key_nr));
redraw_mask |= REDRAW_DOOR_1;
}
+ else if (IS_ENVELOPE(element))
+ {
+#if 1
+ player->show_envelope = element;
+#else
+ ShowEnvelope(element - EL_ENVELOPE_1);
+#endif
+ }
else if (IS_DROPPABLE(element)) /* can be collected and dropped */
{
int i;
CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED);
+ TestIfElementTouchesCustomElement(x, y); /* for empty space */
+
break;
}
else if (IS_PUSHABLE(element))
if (Feld[x][y] != element) /* really digged/collected something */
player->is_collecting = !player->is_digging;
+#if 0
+ if (IS_CUSTOM_ELEMENT(Feld[jx][jy]))
+ {
+ CheckTriggeredElementSideChange(jx, jy, Feld[jx][jy], leave_side,
+ CE_OTHER_GETS_LEFT);
+ CheckElementSideChange(jx, jy, Feld[jx][jy], leave_side,
+ CE_LEFT_BY_PLAYER, -1);
+ }
+
+ if (IS_CUSTOM_ELEMENT(Feld[x][y]))
+ {
+ CheckTriggeredElementSideChange(x, y, Feld[x][y], enter_side,
+ CE_OTHER_GETS_ENTERED);
+ CheckElementSideChange(x, y, Feld[x][y], enter_side,
+ CE_ENTERED_BY_PLAYER, -1);
+ }
+#endif
+
return MF_MOVING;
}
CheckTriggeredElementChange(jx, jy, new_element, CE_OTHER_GETS_DROPPED);
CheckElementChange(jx, jy, new_element, CE_DROPPED_BY_PLAYER);
+
+ TestIfElementTouchesCustomElement(jx, jy);
}
else /* player is dropping a dyna bomb */
{