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 changing_element_list[] =
+static struct ChangingElementInfo change_delay_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) (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()
{
if (!audio.sound_available)
- setup.sound = FALSE;
+ setup.sound_simple = FALSE;
if (!audio.loops_available)
setup.sound_loops = FALSE;
if (!video.fullscreen_available)
setup.fullscreen = FALSE;
- setup.sound_simple = setup.sound;
+ setup.sound = (setup.sound_simple || setup.sound_loops || setup.sound_music);
SetAudioMode(setup.sound);
InitJoysticks();
return belt_move_dir[belt_dir_nr];
}
-static void InitField(int x, int y, boolean init_game)
+static void InitPlayerField(int x, int y, int element, boolean init_game)
{
- int element = Feld[x][y];
-
- switch (element)
+ if (element == EL_SP_MURPHY)
{
- case EL_SP_MURPHY:
- if (init_game)
+ if (init_game)
+ {
+ if (stored_player[0].present)
{
- if (stored_player[0].present)
- {
- Feld[x][y] = EL_SP_MURPHY_CLONE;
- break;
- }
- else
- {
- stored_player[0].use_murphy_graphic = TRUE;
- }
+ Feld[x][y] = EL_SP_MURPHY_CLONE;
- Feld[x][y] = EL_PLAYER_1;
+ return;
}
- /* no break! */
- case EL_PLAYER_1:
- case EL_PLAYER_2:
- case EL_PLAYER_3:
- case EL_PLAYER_4:
- if (init_game)
+ else
{
- struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
- int jx = player->jx, jy = player->jy;
+ stored_player[0].use_murphy_graphic = TRUE;
+ }
- player->present = TRUE;
+ Feld[x][y] = EL_PLAYER_1;
+ }
+ }
- if (!options.network || player->connected)
- {
- player->active = TRUE;
+ if (init_game)
+ {
+ struct PlayerInfo *player = &stored_player[Feld[x][y] - EL_PLAYER_1];
+ int jx = player->jx, jy = player->jy;
- /* remove potentially duplicate players */
- if (StorePlayer[jx][jy] == Feld[x][y])
- StorePlayer[jx][jy] = 0;
+ player->present = TRUE;
- StorePlayer[x][y] = Feld[x][y];
+ if (!options.network || player->connected)
+ {
+ player->active = TRUE;
- if (options.debug)
- {
- printf("Player %d activated.\n", player->element_nr);
- printf("[Local player is %d and currently %s.]\n",
- local_player->element_nr,
- local_player->active ? "active" : "not active");
- }
- }
+ /* remove potentially duplicate players */
+ if (StorePlayer[jx][jy] == Feld[x][y])
+ StorePlayer[jx][jy] = 0;
- Feld[x][y] = EL_EMPTY;
- player->jx = player->last_jx = x;
- player->jy = player->last_jy = y;
+ StorePlayer[x][y] = Feld[x][y];
+
+ if (options.debug)
+ {
+ printf("Player %d activated.\n", player->element_nr);
+ printf("[Local player is %d and currently %s.]\n",
+ local_player->element_nr,
+ local_player->active ? "active" : "not active");
}
+ }
+
+ Feld[x][y] = EL_EMPTY;
+ player->jx = player->last_jx = x;
+ player->jy = player->last_jy = y;
+ }
+}
+
+static void InitField(int x, int y, boolean init_game)
+{
+ int element = Feld[x][y];
+
+ switch (element)
+ {
+ case EL_SP_MURPHY:
+ case EL_PLAYER_1:
+ case EL_PLAYER_2:
+ case EL_PLAYER_3:
+ case EL_PLAYER_4:
+ InitPlayerField(x, y, element, init_game);
break;
case EL_STONEBLOCK:
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 ------------------------------- */
/* initialize changing elements information */
- for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ for (i=0; i < MAX_NUM_ELEMENTS; i++)
{
-#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;
+ struct ElementInfo *ei = &element_info[i];
+
+ /* this pointer might have been changed in the level editor */
+ 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;
-#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
+ 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];
+ }
}
/* 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);
+ }
#if 1
- 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;
+ /* add change events from custom element configuration */
+ for (i=0; i < NUM_CUSTOM_ELEMENTS; i++)
+ {
+ struct ElementInfo *ei = &element_info[EL_CUSTOM_START + i];
- 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
+ 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];
+ }
+ }
+ }
}
- /* 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;
-#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))
- 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
+ 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++)
- if (HAS_CHANGE_EVENT(i, CE_BY_OTHER))
- trigger_events[element_info[i].change.trigger_element] |=
- element_info[i].change.events;
+ {
+ 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_ACTION))
+ trigger_events[element_info[i].change->trigger_element] |=
+ element_info[i].change->events;
+#endif
/* ---------- initialize push delay -------------------------------------- */
JustStopped[x][y] = 0;
Stop[x][y] = FALSE;
Pushed[x][y] = FALSE;
- Changing[x][y] = FALSE;
+ Changed[x][y] = FALSE;
ExplodePhase[x][y] = 0;
ExplodeField[x][y] = EX_NO_EXPLOSION;
if (lev_fieldy + (SBY_Upper == -1 ? 2 : 0) <= SCR_FIELDY)
SBY_Upper = SBY_Lower = -1 * (SCR_FIELDY - lev_fieldy) / 2;
- scroll_x = SBX_Left;
- scroll_y = SBY_Upper;
- if (local_player->jx >= SBX_Left + MIDPOSX)
- scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
- local_player->jx - MIDPOSX :
- SBX_Right);
- if (local_player->jy >= SBY_Upper + MIDPOSY)
- scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
- local_player->jy - MIDPOSY :
- SBY_Lower);
+ /* if local player not found, look for custom element that might create
+ the player (make some assumptions about the right custom element) */
+ if (!local_player->present)
+ {
+ int start_x = 0, start_y = 0;
+ int found_rating = 0;
+ int found_element = EL_UNDEFINED;
+
+ for(y=0; y < lev_fieldy; y++) for(x=0; x < lev_fieldx; x++)
+ {
+ int element = Feld[x][y];
+ int content;
+ int xx, yy;
+ boolean is_player;
+
+ if (!IS_CUSTOM_ELEMENT(element))
+ continue;
+
+ 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);
+
+ if (is_player && (found_rating < 3 || element < found_element))
+ {
+ start_x = x;
+ start_y = y;
+
+ found_rating = 3;
+ found_element = element;
+ }
+ }
+ }
+
+ for(yy=0; yy < 3; yy++) for(xx=0; xx < 3; xx++)
+ {
+ content = element_info[element].content[xx][yy];
+ is_player = ELEM_IS_PLAYER(content);
+
+ if (is_player && (found_rating < 2 || element < found_element))
+ {
+ start_x = x + xx - 1;
+ start_y = y + yy - 1;
+
+ found_rating = 2;
+ 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);
+
+ 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;
+ }
+ }
+ }
+ }
+
+ scroll_x = (start_x < SBX_Left + MIDPOSX ? SBX_Left :
+ start_x > SBX_Right + MIDPOSX ? SBX_Right :
+ start_x - MIDPOSX);
+
+ scroll_y = (start_y < SBY_Upper + MIDPOSY ? SBY_Upper :
+ start_y > SBY_Lower + MIDPOSY ? SBY_Lower :
+ start_y - MIDPOSY);
+ }
+ else
+ {
+#if 1
+ scroll_x = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left :
+ local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+ local_player->jx - MIDPOSX);
+
+ scroll_y = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+ local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+ local_player->jy - MIDPOSY);
+#else
+ scroll_x = SBX_Left;
+ scroll_y = SBY_Upper;
+ if (local_player->jx >= SBX_Left + MIDPOSX)
+ scroll_x = (local_player->jx <= SBX_Right + MIDPOSX ?
+ local_player->jx - MIDPOSX :
+ SBX_Right);
+ if (local_player->jy >= SBY_Upper + MIDPOSY)
+ scroll_y = (local_player->jy <= SBY_Lower + MIDPOSY ?
+ local_player->jy - MIDPOSY :
+ SBY_Lower);
+#endif
+ }
CloseDoor(DOOR_CLOSE_1);
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;
Bang(x, y);
}
+void RelocatePlayer(int x, int y, int element)
+{
+ struct PlayerInfo *player = &stored_player[element - EL_PLAYER_1];
+
+ if (player->present)
+ {
+ while (player->MovPos)
+ {
+ ScrollFigure(player, SCROLL_GO_ON);
+ ScrollScreen(NULL, SCROLL_GO_ON);
+ FrameCounter++;
+ DrawAllPlayers();
+ BackToFront();
+ }
+
+ RemoveField(player->jx, player->jy);
+ DrawLevelField(player->jx, player->jy);
+ }
+
+ InitPlayerField(x, y, element, TRUE);
+
+ if (player == local_player)
+ {
+ int scroll_xx = -999, scroll_yy = -999;
+
+ while (scroll_xx != scroll_x || scroll_yy != scroll_y)
+ {
+ int dx = 0, dy = 0;
+ int fx = FX, fy = FY;
+
+ scroll_xx = (local_player->jx < SBX_Left + MIDPOSX ? SBX_Left :
+ local_player->jx > SBX_Right + MIDPOSX ? SBX_Right :
+ local_player->jx - MIDPOSX);
+
+ scroll_yy = (local_player->jy < SBY_Upper + MIDPOSY ? SBY_Upper :
+ local_player->jy > SBY_Lower + MIDPOSY ? SBY_Lower :
+ local_player->jy - MIDPOSY);
+
+ dx = (scroll_xx < scroll_x ? +1 : scroll_xx > scroll_x ? -1 : 0);
+ dy = (scroll_yy < scroll_y ? +1 : scroll_yy > scroll_y ? -1 : 0);
+
+ scroll_x -= dx;
+ scroll_y -= dy;
+
+ fx += dx * TILEX / 2;
+ fy += dy * TILEY / 2;
+
+ ScrollLevel(dx, dy);
+ DrawAllPlayers();
+
+ /* scroll in to steps of half tile size to make things smoother */
+ BlitBitmap(drawto_field, window, fx, fy, SXSIZE, SYSIZE, SX, SY);
+ FlushDisplay();
+ Delay(GAME_FRAME_DELAY);
+
+ /* scroll second step to align at full tile size */
+ BackToFront();
+ Delay(GAME_FRAME_DELAY);
+ }
+ }
+}
+
void Explode(int ex, int ey, int phase, int mode)
{
int x, y;
if (IS_PLAYER(x, y) && !PLAYERINFO(x,y)->present)
StorePlayer[x][y] = 0;
+
+ if (ELEM_IS_PLAYER(element))
+ RelocatePlayer(x, y, element);
}
else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
Explode(x, y, EX_PHASE_START, EX_CENTER);
break;
default:
- Explode(x, y, EX_PHASE_START, EX_NORMAL);
+ if (CAN_EXPLODE_1X1(element))
+ Explode(x, y, EX_PHASE_START, EX_CENTER);
+ else
+ Explode(x, y, EX_PHASE_START, EX_NORMAL);
break;
}
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
{
if (CAN_FALL(element) && y < lev_fieldy - 1)
{
- if ((x>0 && IS_PLAYER(x-1, y)) || (x<lev_fieldx-1 && IS_PLAYER(x+1, y)))
+ if ((x > 0 && IS_PLAYER(x - 1, y)) ||
+ (x < lev_fieldx-1 && IS_PLAYER(x + 1, y)))
if (JustBeingPushed(x, y))
return;
Moving2Blocked(x, y, &newx, &newy); /* get next screen position */
- if (DONT_COLLIDE_WITH(element) && IS_PLAYER(newx, newy) &&
+ if (DONT_COLLIDE_WITH(element) &&
+ IN_LEV_FIELD(newx, newy) && IS_PLAYER(newx, newy) &&
!PLAYER_PROTECTED(newx, newy))
{
#if 1
static void ChangeElementNowExt(int x, int y, int target_element)
{
-#if 0 /* !!! let the player exacpe from a suddenly unaccessible element */
- if (IS_PLAYER(x, y) && !IS_ACCESSIBLE(target_element))
+ /* 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) &&
+ IS_ACCESSIBLE(Feld[x][y]) && !IS_ACCESSIBLE(target_element))
{
Bang(x, y);
return;
}
-#endif
RemoveField(x, y);
Feld[x][y] = target_element;
+ Changed[x][y] = TRUE; /* no more changes in this frame */
+
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
TestIfBadThingTouchesHero(x, y);
TestIfPlayerTouchesCustomElement(x, y);
TestIfElementTouchesCustomElement(x, y);
+
+ if (ELEM_IS_PLAYER(target_element))
+ RelocatePlayer(x, y, target_element);
}
-static void ChangeElementNow(int x, int y, int element)
+static void 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];
- /* prevent CheckTriggeredElementChange() from looping */
- Changing[x][y] = TRUE;
+ Changed[x][y] = TRUE; /* no more changes in this frame */
CheckTriggeredElementChange(x, y, Feld[x][y], CE_OTHER_IS_CHANGING);
- Changing[x][y] = FALSE;
-
if (change->explode)
{
Bang(x, y);
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 */
}
}
}
}
-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];
-#endif
- struct ElementChangeInfo *change = &element_info[element].change;
+ struct ElementChangeInfo *change = &element_info[element].change_page[page];
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);
+ ChangeElementNow(x, y, element, page);
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, x, y;
+ int i, j, x, y;
if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
return FALSE;
- for (i=0; i<MAX_NUM_ELEMENTS; i++)
+#if 0
+ /* prevent this function from running into a loop */
+ if (trigger_event == CE_OTHER_IS_CHANGING)
+ Changed[lx][ly] = TRUE;
+#endif
+
+ 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;
+
+#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)
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 */
continue;
- if (Changing[x][y]) /* do not change just changing elements */
+ if (Changed[x][y]) /* do not change already changed elements */
continue;
- if (Feld[x][y] == i)
+ if (Feld[x][y] == element)
{
ChangeDelay[x][y] = 1;
- ChangeElement(x, y);
+ ChangeElement(x, y, page);
+
+#if 0
+ Changed[x][y] = TRUE; /* prevent element from being changed again */
+#endif
}
}
}
+#if 0
+ /* reset change prevention array */
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ Changed[x][y] = FALSE;
+#endif
+
return TRUE;
}
-static boolean CheckElementChange(int x, int y, int element, int trigger_event)
+static boolean CheckElementChangeExt(int x, int y, int element,
+ 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);
ChangeDelay[x][y] = 1;
- ChangeElement(x, y);
+ ChangeElement(x, y, page);
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;
for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
{
+ Changed[x][y] = FALSE;
+
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_num[CE_DELAY]);
element = Feld[x][y];
graphic = el_act_dir2img(element, GfxAction[x][y], MovDir[x][y]);
}
int x, y;
BlitBitmap(drawto_field, drawto_field,
- FX + TILEX*(dx == -1) - softscroll_offset,
- FY + TILEY*(dy == -1) - softscroll_offset,
- SXSIZE - TILEX*(dx!=0) + 2*softscroll_offset,
- SYSIZE - TILEY*(dy!=0) + 2*softscroll_offset,
- FX + TILEX*(dx == 1) - softscroll_offset,
- FY + TILEY*(dy == 1) - softscroll_offset);
+ FX + TILEX * (dx == -1) - softscroll_offset,
+ FY + TILEY * (dy == -1) - softscroll_offset,
+ SXSIZE - TILEX * (dx!=0) + 2 * softscroll_offset,
+ SYSIZE - TILEY * (dy!=0) + 2 * softscroll_offset,
+ FX + TILEX * (dx == 1) - softscroll_offset,
+ FY + TILEY * (dy == 1) - softscroll_offset);
if (dx)
{
x = (dx == 1 ? BX1 : BX2);
- for (y=BY1; y<=BY2; y++)
+ for (y=BY1; y <= BY2; y++)
DrawScreenField(x, y);
}
if (dy)
{
y = (dy == 1 ? BY1 : BY2);
- for (x=BX1; x<=BX2; x++)
+ for (x=BX1; x <= BX2; x++)
DrawScreenField(x, y);
}
if (can_move != MF_MOVING)
return can_move;
+ /* check if DigField() has caused relocation of the player */
+ if (player->jx != jx || player->jy != jy)
+ return MF_NO_ACTION;
+
StorePlayer[jx][jy] = 0;
player->last_jx = jx;
player->last_jy = jy;
player->last_move_dir = player->MovDir;
player->is_moving = TRUE;
+#if 1
+ player->snapped = FALSE;
+#endif
}
else
{
if (Feld[jx][jy] == EL_EXIT_OPEN ||
Feld[jx][jy] == EL_SP_EXIT_OPEN)
{
+ DrawPlayer(player); /* needed here only to cleanup last field */
RemoveHero(player);
if (local_player->friends_still_needed == 0 ||
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 },
{ 0, +1 }
};
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++)
{
/* 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->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->trigger_element == center_element)
+ {
+ CheckElementChangeExt(xx,yy, border_element,CE_OTHER_IS_TOUCHING, j);
+ break;
+ }
+ }
+ }
}
if (change_center_element)
- CheckElementChange(x, y, center_element, CE_OTHER_IS_TOUCHING);
+ CheckElementChangeExt(x, y, center_element, 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)
PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING);
+ CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_DIGGED);
+
+ TestIfElementTouchesCustomElement(x, y);
+
break;
}
else if (IS_COLLECTIBLE(element))
el2edimg(EL_KEY_1 + key_nr));
redraw_mask |= REDRAW_DOOR_1;
}
+ else if (element == EL_ENVELOPE)
+ {
+ ShowEnvelope();
+ }
else if (IS_DROPPABLE(element)) /* can be collected and dropped */
{
int i;
CheckTriggeredElementChange(x, y, element, CE_OTHER_GETS_COLLECTED);
+ TestIfElementTouchesCustomElement(x, y);
+
break;
}
else if (IS_PUSHABLE(element))
{
player->is_digging = FALSE;
player->is_collecting = FALSE;
+#if 1
+ player->is_moving = FALSE;
+#endif
}
+#if 0
+ printf("::: trying to snap...\n");
+#endif
+
return FALSE;
}
player->MovDir = snap_direction;
+#if 1
+ player->is_digging = FALSE;
+ player->is_collecting = FALSE;
+#if 1
+ player->is_moving = FALSE;
+#endif
+#endif
+
if (DigField(player, x, y, 0, 0, DF_SNAP) == MF_NO_ACTION)
return FALSE;
player->snapped = TRUE;
+#if 1
player->is_digging = FALSE;
player->is_collecting = FALSE;
+#if 1
+ player->is_moving = FALSE;
+#endif
+#endif
DrawLevelField(x, y);
BackToFront();
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 */
{