+ else /* finish element change */
+ {
+ if (ChangePage[x][y] != -1) /* remember page from delayed change */
+ {
+ page = ChangePage[x][y];
+ ChangePage[x][y] = -1;
+
+ change = &ei->change_page[page];
+ }
+
+#if 0
+ if (IS_MOVING(x, y) && !change->explode)
+#else
+ if (IS_MOVING(x, y)) /* never change a running system ;-) */
+#endif
+ {
+ ChangeDelay[x][y] = 1; /* try change after next move step */
+ ChangePage[x][y] = page; /* remember page to use for change */
+
+ return;
+ }
+
+ if (ChangeElementNow(x, y, element, page))
+ {
+ if (change->post_change_function)
+ change->post_change_function(x, y);
+ }
+ }
+}
+
+static boolean CheckTriggeredElementChangeExt(int lx, int ly,
+ int trigger_element,
+ int trigger_event,
+ int trigger_player,
+ int trigger_side,
+ int trigger_page)
+{
+ int i, j, x, y;
+ int trigger_page_bits = (trigger_page < 0 ? CH_PAGE_ANY : 1 << trigger_page);
+
+ if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
+ return FALSE;
+
+ for (i = 0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ int element = EL_CUSTOM_START + i;
+
+ boolean change_element = FALSE;
+ int page = 0;
+
+ 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->can_change &&
+ change->events & CH_EVENT_BIT(trigger_event) &&
+ change->trigger_side & trigger_side &&
+ change->trigger_player & trigger_player &&
+ change->trigger_page & trigger_page_bits &&
+ IS_EQUAL_OR_IN_GROUP(trigger_element, change->trigger_element))
+ {
+#if 0
+ if (!(change->events & CH_EVENT_BIT(trigger_event)))
+ printf("::: !!! %d triggers %d: using wrong page %d [event %d]\n",
+ trigger_element-EL_CUSTOM_START+1, i+1, j, trigger_event);
+#endif
+
+ change_element = TRUE;
+ page = j;
+
+ change->actual_trigger_element = trigger_element;
+ change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+
+ 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 (Feld[x][y] == element)
+ {
+ ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeElement(x, y, page);
+ }
+ }
+ }
+
+ return TRUE;
+}
+
+static boolean CheckElementChangeExt(int x, int y,
+ int element,
+ int trigger_element,
+ int trigger_event,
+ int trigger_player,
+ int trigger_side,
+ int trigger_page)
+{
+ 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 1
+ if (Feld[x][y] != element) /* check if element has already changed */
+ {
+#if 0
+ printf("::: %d ('%s') != %d ('%s') [%d]\n",
+ Feld[x][y], element_info[Feld[x][y]].token_name,
+ element, element_info[element].token_name,
+ trigger_event);
+#endif
+
+ return FALSE;
+ }
+#endif
+
+#if 1
+ if (trigger_page < 0)
+ {
+ boolean change_element = FALSE;
+ int i;
+
+ for (i = 0; i < element_info[element].num_change_pages; i++)
+ {
+ struct ElementChangeInfo *change = &element_info[element].change_page[i];
+
+ if (change->can_change &&
+ change->events & CH_EVENT_BIT(trigger_event) &&
+ change->trigger_side & trigger_side &&
+ change->trigger_player & trigger_player)
+ {
+ change_element = TRUE;
+ trigger_page = i;
+
+ change->actual_trigger_element = trigger_element;
+ change->actual_trigger_player = EL_PLAYER_1 + log_2(trigger_player);
+
+ break;
+ }
+ }
+
+ if (!change_element)
+ return FALSE;
+ }
+ else
+ {
+ struct ElementInfo *ei = &element_info[element];
+ struct ElementChangeInfo *change = &ei->change_page[trigger_page];
+
+ change->actual_trigger_element = trigger_element;
+ change->actual_trigger_player = EL_PLAYER_1; /* unused */
+ }
+
+#else
+
+ /* !!! this check misses pages with same event, but different side !!! */
+
+ if (trigger_page < 0)
+ trigger_page = element_info[element].event_page_nr[trigger_event];
+
+ if (!(element_info[element].change_page[trigger_page].trigger_side & trigger_side))
+ return FALSE;
+#endif
+
+ ChangeDelay[x][y] = 1;
+ ChangeEvent[x][y] = CH_EVENT_BIT(trigger_event);
+ ChangeElement(x, y, trigger_page);
+
+ return TRUE;
+}
+
+static void PlayPlayerSound(struct PlayerInfo *player)
+{
+ int jx = player->jx, jy = player->jy;
+ int element = player->element_nr;
+ int last_action = player->last_action_waiting;
+ int action = player->action_waiting;
+
+ if (player->is_waiting)
+ {
+ if (action != last_action)
+ PlayLevelSoundElementAction(jx, jy, element, action);
+ else
+ PlayLevelSoundElementActionIfLoop(jx, jy, element, action);
+ }
+ else
+ {
+ if (action != last_action)
+ StopSound(element_info[element].sound[last_action]);
+
+ if (last_action == ACTION_SLEEPING)
+ PlayLevelSoundElementAction(jx, jy, element, ACTION_AWAKENING);
+ }
+}
+
+static void PlayAllPlayersSound()
+{
+ int i;
+
+ for (i = 0; i < MAX_PLAYERS; i++)
+ if (stored_player[i].active)
+ PlayPlayerSound(&stored_player[i]);
+}
+
+static void SetPlayerWaiting(struct PlayerInfo *player, boolean is_waiting)
+{
+ boolean last_waiting = player->is_waiting;
+ int move_dir = player->MovDir;
+
+ player->last_action_waiting = player->action_waiting;
+
+ if (is_waiting)
+ {
+ if (!last_waiting) /* not waiting -> waiting */
+ {
+ player->is_waiting = TRUE;
+
+ player->frame_counter_bored =
+ FrameCounter +
+ game.player_boring_delay_fixed +
+ SimpleRND(game.player_boring_delay_random);
+ player->frame_counter_sleeping =
+ FrameCounter +
+ game.player_sleeping_delay_fixed +
+ SimpleRND(game.player_sleeping_delay_random);
+
+ InitPlayerGfxAnimation(player, ACTION_WAITING, player->MovDir);
+ }
+
+ if (game.player_sleeping_delay_fixed +
+ game.player_sleeping_delay_random > 0 &&
+ player->anim_delay_counter == 0 &&
+ player->post_delay_counter == 0 &&
+ FrameCounter >= player->frame_counter_sleeping)
+ player->is_sleeping = TRUE;
+ else if (game.player_boring_delay_fixed +
+ game.player_boring_delay_random > 0 &&
+ FrameCounter >= player->frame_counter_bored)
+ player->is_bored = TRUE;
+
+ player->action_waiting = (player->is_sleeping ? ACTION_SLEEPING :
+ player->is_bored ? ACTION_BORING :
+ ACTION_WAITING);
+
+ if (player->is_sleeping)
+ {
+ if (player->num_special_action_sleeping > 0)
+ {
+ if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
+ {
+ int last_special_action = player->special_action_sleeping;
+ int num_special_action = player->num_special_action_sleeping;
+ int special_action =
+ (last_special_action == ACTION_DEFAULT ? ACTION_SLEEPING_1 :
+ last_special_action == ACTION_SLEEPING ? ACTION_SLEEPING :
+ last_special_action < ACTION_SLEEPING_1 + num_special_action - 1 ?
+ last_special_action + 1 : ACTION_SLEEPING);
+ int special_graphic =
+ el_act_dir2img(player->element_nr, special_action, move_dir);
+
+ player->anim_delay_counter =
+ graphic_info[special_graphic].anim_delay_fixed +
+ SimpleRND(graphic_info[special_graphic].anim_delay_random);
+ player->post_delay_counter =
+ graphic_info[special_graphic].post_delay_fixed +
+ SimpleRND(graphic_info[special_graphic].post_delay_random);
+
+ player->special_action_sleeping = special_action;
+ }
+
+ if (player->anim_delay_counter > 0)
+ {
+ player->action_waiting = player->special_action_sleeping;
+ player->anim_delay_counter--;
+ }
+ else if (player->post_delay_counter > 0)
+ {
+ player->post_delay_counter--;
+ }
+ }
+ }
+ else if (player->is_bored)
+ {
+ if (player->num_special_action_bored > 0)
+ {
+ if (player->anim_delay_counter == 0 && player->post_delay_counter == 0)
+ {
+ int special_action =
+ ACTION_BORING_1 + SimpleRND(player->num_special_action_bored);
+ int special_graphic =
+ el_act_dir2img(player->element_nr, special_action, move_dir);
+
+ player->anim_delay_counter =
+ graphic_info[special_graphic].anim_delay_fixed +
+ SimpleRND(graphic_info[special_graphic].anim_delay_random);
+ player->post_delay_counter =
+ graphic_info[special_graphic].post_delay_fixed +
+ SimpleRND(graphic_info[special_graphic].post_delay_random);
+
+ player->special_action_bored = special_action;
+ }
+
+ if (player->anim_delay_counter > 0)
+ {
+ player->action_waiting = player->special_action_bored;
+ player->anim_delay_counter--;
+ }
+ else if (player->post_delay_counter > 0)
+ {
+ player->post_delay_counter--;
+ }
+ }
+ }
+ }
+ else if (last_waiting) /* waiting -> not waiting */