static boolean CheckTriggeredElementChange(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 change_delay_list[] =
+static struct ChangingElementInfo changing_element_list[] =
{
{
EL_NUT_BREAKING,
{ EL_UNDEFINED, 0 },
};
+static boolean changing_element[MAX_NUM_ELEMENTS];
static unsigned long trigger_events[MAX_NUM_ELEMENTS];
-#define IS_AUTO_CHANGING(e) (element_info[e].change_events & \
- CH_EVENT_BIT(CE_DELAY))
+#define IS_AUTO_CHANGING(e) (changing_element[e])
#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()
{
static void InitGameEngine()
{
- int i, j, k;
+ int i;
/* set game engine from tape file when re-playing, else from level file */
game.engine_version = (tape.playing ? tape.engine_version :
/* ---------- initialize changing elements ------------------------------- */
/* initialize changing elements information */
- for (i=0; i < MAX_NUM_ELEMENTS; i++)
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
{
- struct ElementInfo *ei = &element_info[i];
-
- /* this pointer might have been changed in the level editor */
- ei->change = &ei->change_page[0];
+#if 1
+ element_info[i].change.pre_change_function = NULL;
+ element_info[i].change.change_function = NULL;
+ element_info[i].change.post_change_function = NULL;
if (!IS_CUSTOM_ELEMENT(i))
{
- ei->change->target_element = EL_EMPTY_SPACE;
- ei->change->delay_fixed = 0;
- ei->change->delay_random = 0;
- ei->change->delay_frames = 1;
+ 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_events = CE_BITMASK_DEFAULT;
- for (j=0; j < NUM_CHANGE_EVENTS; j++)
- {
- ei->event_page_num[j] = 0;
- ei->event_page[j] = &ei->change_page[0];
- }
+ changing_element[i] = FALSE;
+#else
+ changing_element[i].base_element = EL_UNDEFINED;
+ changing_element[i].next_element = EL_UNDEFINED;
+ changing_element[i].change_delay = -1;
+ changing_element[i].pre_change_function = NULL;
+ changing_element[i].change_function = NULL;
+ changing_element[i].post_change_function = NULL;
+#endif
}
/* add changing elements from pre-defined list */
- for (i=0; change_delay_list[i].element != EL_UNDEFINED; i++)
+ for (i=0; changing_element_list[i].element != EL_UNDEFINED; i++)
{
- 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);
- }
+ int element = changing_element_list[i].element;
+ struct ChangingElementInfo *ce = &changing_element_list[i];
+ struct ElementChangeInfo *change = &element_info[element].change;
#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];
-
- for (j=0; j < ei->num_change_pages; j++)
- {
- if (!ei->change_page[j].can_change)
- continue;
-
- 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_num[k] = j;
- ei->event_page[k] = &ei->change_page[j];
- }
- }
- }
- }
+ change->target_element = ce->target_element;
+ change->delay_fixed = ce->change_delay;
+ change->pre_change_function = ce->pre_change_function;
+ change->change_function = ce->change_function;
+ change->post_change_function = ce->post_change_function;
+ changing_element[element] = TRUE;
#else
+ changing_element[element].base_element = ce->base_element;
+ changing_element[element].next_element = ce->next_element;
+ changing_element[element].change_delay = ce->change_delay;
+ changing_element[element].pre_change_function = ce->pre_change_function;
+ changing_element[element].change_function = ce->change_function;
+ changing_element[element].post_change_function = ce->post_change_function;
+#endif
+ }
- /* add change events from custom element configuration */
+ /* add changing elements from custom element configuration */
for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
{
int element = EL_CUSTOM_START + i;
+#if 0
+ struct ElementChangeInfo *change = &element_info[element].change;
+#endif
/* only add custom elements that change after fixed/random frame delay */
- if (CAN_CHANGE(element) && HAS_CHANGE_EVENT(element, CE_DELAY))
- element_info[element].change_events |= CH_EVENT_BIT(CE_DELAY);
- }
+ if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, CE_DELAY))
+ continue;
+
+#if 1
+ changing_element[element] = TRUE;
+#else
+ changing_element[element].base_element = element;
+ changing_element[element].next_element = change->target_element;
+ changing_element[element].change_delay = (change->delay_fixed *
+ change->delay_frames);
#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))
- {
- 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))
- trigger_events[element_info[i].change->trigger_element] |=
- element_info[i].change->events;
-#endif
+ trigger_events[element_info[i].change.trigger_element] |=
+ element_info[i].change.events;
/* ---------- initialize push delay -------------------------------------- */
if (CAN_CHANGE(element))
{
- for (i=0; i < element_info[element].num_change_pages; i++)
- {
- content = element_info[element].change_page[i].target_element;
- is_player = ELEM_IS_PLAYER(content);
+ content = element_info[element].change.target_element;
+ is_player = ELEM_IS_PLAYER(content);
- if (is_player && (found_rating < 3 || element < found_element))
- {
- start_x = x;
- start_y = y;
+ if (is_player && (found_rating < 3 || element < found_element))
+ {
+ start_x = x;
+ start_y = y;
- found_rating = 3;
- found_element = element;
- }
+ found_rating = 3;
+ found_element = element;
}
}
if (!CAN_CHANGE(element))
continue;
- for (i=0; i < element_info[element].num_change_pages; i++)
- {
- content = element_info[element].change_page[i].content[xx][yy];
- is_player = ELEM_IS_PLAYER(content);
+ content = element_info[element].change.content[xx][yy];
+ is_player = ELEM_IS_PLAYER(content);
- if (is_player && (found_rating < 1 || element < found_element))
- {
- start_x = x + xx - 1;
- start_y = y + yy - 1;
+ 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;
- }
+ found_rating = 1;
+ found_element = element;
}
}
}
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
{
{
/* 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) && !PLAYER_PROTECTED(x, y) &&
+ if (IS_PLAYER(x, y) &&
IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element))
{
Bang(x, y);
RelocatePlayer(x, y, target_element);
}
-static void ChangeElementNow(int x, int y, int element, int page)
+static void ChangeElementNow(int x, int y, int element)
{
- struct ElementChangeInfo *change = &element_info[element].change_page[page];
+ struct ElementChangeInfo *change = &element_info[element].change;
+
+#if 0
+ if (element >= EL_CUSTOM_START + 17 && element <= EL_CUSTOM_START + 39)
+ printf("::: changing... [%d]\n", FrameCounter);
+#endif
+
+#if 0
+ /* prevent CheckTriggeredElementChange() from looping */
+ Changing[x][y] = TRUE;
+#endif
CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING);
+#if 0
+ Changing[x][y] = FALSE;
+#endif
+
if (change->explode)
{
Bang(x, y);
}
}
-static void ChangeElement(int x, int y, int page)
+static void ChangeElement(int x, int y)
{
+#if 1
int element = MovingOrBlocked2Element(x, y);
- struct ElementChangeInfo *change = &element_info[element].change_page[page];
+#else
+ int element = Feld[x][y];
+#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;
}
- ChangeElementNow(x, y, element, page);
+#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
}
}
static boolean CheckTriggeredElementChange(int lx, int ly, int trigger_element,
int trigger_event)
{
- int i, j, x, y;
+ int i, x, y;
if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
return FALSE;
if (trigger_event == CE_OTHER_IS_CHANGING)
Changing[lx][ly] = TRUE;
- for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
{
- int element = EL_CUSTOM_START + i;
-
-#if 1
- 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++)
- {
- if (element_info[element].change_page[j].trigger_element ==
- trigger_element)
- {
- change_element = TRUE;
- page = j;
-
- break;
- }
- }
-
- if (!change_element)
+ if (!CAN_CHANGE(i) || !HAS_CHANGE_EVENT(i, trigger_event) ||
+ element_info[i].change.trigger_element != trigger_element)
continue;
-#else
- if (!CAN_CHANGE(element) ||
- !HAS_ANY_CHANGE_EVENT(element, trigger_event) ||
- element_info[element].change->trigger_element != trigger_element)
- continue;
-#endif
-
for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
if (x == lx && y == ly) /* do not change trigger element itself */
if (Changing[x][y]) /* do not change just changing elements */
continue;
- if (Feld[x][y] == element)
+ if (Feld[x][y] == i)
{
ChangeDelay[x][y] = 1;
- ChangeElement(x, y, page);
+ ChangeElement(x, y);
Changing[x][y] = TRUE; /* do not change just changed elements */
}
return TRUE;
}
-static boolean CheckElementChangeExt(int x, int y, int element,
- int trigger_event, int page)
+static boolean CheckElementChange(int x, int y, int element, int trigger_event)
{
- if (!CAN_CHANGE(element) || !HAS_ANY_CHANGE_EVENT(element, trigger_event))
+ if (!CAN_CHANGE(element) || !HAS_CHANGE_EVENT(element, trigger_event))
return FALSE;
if (Feld[x][y] == EL_BLOCKED)
Blocked2Moving(x, y, &x, &y);
ChangeDelay[x][y] = 1;
- ChangeElement(x, y, page);
+ ChangeElement(x, y);
return TRUE;
}
-static boolean CheckElementChange(int x, int y, int element, int trigger_event)
-{
- int page = element_info[element].event_page_num[trigger_event];
-
- return CheckElementChangeExt(x, y, element, trigger_event, page);
-}
-
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;
/* this may take place after moving, so 'element' may have changed */
if (IS_CHANGING(x, y))
{
- ChangeElement(x, y, element_info[element].event_page_num[CE_DELAY]);
+ ChangeElement(x, y);
element = Feld[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
}
{ 0, +1 }
};
boolean change_center_element = FALSE;
- int center_element_change_page = 0;
int center_element = Feld[x][y];
- int i, j;
+ int i;
if (check_changing) /* prevent this function from running into a loop */
return;
/* check for change of center element (but change it only once) */
if (IS_CUSTOM_ELEMENT(center_element) &&
- element_info[center_element].change_events & 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 & CE_OTHER_IS_TOUCHING &&
- change->trigger_element == border_element)
- {
- change_center_element = TRUE;
- center_element_change_page = j;
-
- break;
- }
- }
- }
+ border_element == element_info[center_element].change.trigger_element)
+ change_center_element = TRUE;
/* check for change of border element */
if (IS_CUSTOM_ELEMENT(border_element) &&
- element_info[border_element].change_events & 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 & CE_OTHER_IS_TOUCHING &&
- change->trigger_element == center_element)
- {
- CheckElementChangeExt(xx,yy, border_element,CE_OTHER_IS_TOUCHING, j);
- break;
- }
- }
- }
+ center_element == element_info[border_element].change.trigger_element)
+ CheckElementChange(xx, yy, border_element, CE_OTHER_IS_TOUCHING);
}
if (change_center_element)
- CheckElementChangeExt(x, y, center_element, CE_OTHER_IS_TOUCHING,
- center_element_change_page);
+ CheckElementChange(x, y, center_element, CE_OTHER_IS_TOUCHING);
check_changing = FALSE;
}