static void CheckGravityMovement(struct PlayerInfo *);
static void KillHeroUnlessProtected(int, int);
+static void CheckTriggeredElementChange(int, int);
static void ChangeElementDoIt(int, int, int);
static void PlaySoundLevel(int, int, int);
};
static struct ChangingElementInfo changing_element[MAX_NUM_ELEMENTS];
+static unsigned long trigger_events[MAX_NUM_ELEMENTS];
#define IS_AUTO_CHANGING(e) (changing_element[e].base_element != EL_UNDEFINED)
+#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 TRIGGERS_BY_COLLECTING(e) (trigger_events[e] & CE_OTHER_COLLECTING)
void GetPlayerConfig()
changing_element[element].change_delay = (change->delay_fixed *
change->delay_frames);
}
+
+ /* initialize trigger events information */
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ trigger_events[i] = EP_BITMASK_DEFAULT;
+
+ /* 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_info[i].change.events;
}
}
Feld[x][y] = EL_EXPLOSION;
+#if 1
+ GfxElement[x][y] = center_element;
+#else
GfxElement[x][y] = EL_UNDEFINED;
+#endif
MovDir[x][y] = MovPos[x][y] = 0;
AmoebaNr[x][y] = 0;
ExplodePhase[x][y] = 1;
element = Feld[x][y] = Store[x][y];
Store[x][y] = Store2[x][y] = 0;
+ GfxElement[x][y] = EL_UNDEFINED;
if (Back[x][y] && IS_INDESTRUCTIBLE(Back[x][y]))
element = Feld[x][y] = Back[x][y];
}
else if (phase >= delay && IN_SCR_FIELD(SCREENX(x), SCREENY(y)))
{
+#if 1
+ int graphic = el_act2img(GfxElement[x][y], ACTION_EXPLODING);
+#else
int stored = Store[x][y];
int graphic = (game.emulation != EMU_SUPAPLEX ? IMG_EXPLOSION :
stored == EL_SP_INFOTRON ? IMG_SP_EXPLOSION_INFOTRON :
IMG_SP_EXPLOSION);
+#endif
int frame = getGraphicAnimationFrame(graphic, phase - delay);
if (phase == delay)
{
int element = Feld[x][y];
+ if (IS_PLAYER(x, y))
+ {
+ struct PlayerInfo *player = PLAYERINFO(x, y);
+
+ element = Feld[x][y] = (player->use_murphy_graphic ? EL_SP_MURPHY :
+ player->element_nr);
+ }
+
+#if 1
+ PlaySoundLevelAction(x, y, ACTION_EXPLODING);
+#else
if (game.emulation == EMU_SUPAPLEX)
PlaySoundLevel(x, y, SND_SP_ELEMENT_EXPLODING);
else
PlaySoundLevel(x, y, SND_ELEMENT_EXPLODING);
+#endif
#if 0
if (IS_PLAYER(x, y)) /* remove objects that might cause smaller explosion */
Explode(x, y, EX_PHASE_START, EX_NORMAL);
break;
}
+
+ CheckTriggeredElementChange(element, CE_OTHER_EXPLODING);
}
void SplashAcid(int x, int y)
DrawLevelFieldCrumbledSand(x, y);
}
-static void ChangeElementDoIt(int x, int y, int element)
+static void ChangeElementDoIt(int x, int y, int element_new)
{
+ CheckTriggeredElementChange(Feld[x][y], CE_OTHER_CHANGING);
+
RemoveField(x, y);
- Feld[x][y] = element;
+ Feld[x][y] = element_new;
ResetGfxAnimation(x, y);
ResetRandomAnimationValue(x, y);
}
else /* finish element change */
{
+ int next_element = changing_element[element].next_element;
+
if (IS_MOVING(x, y)) /* never change a running system ;-) */
{
ChangeDelay[x][y] = 1; /* try change after next move step */
return;
}
-#if 1
- ChangeElementDoIt(x, y, changing_element[element].next_element);
-#else
- RemoveField(x, y);
- Feld[x][y] = changing_element[element].next_element;
+ if (next_element != EL_UNDEFINED)
+ ChangeElementDoIt(x, y, next_element);
+ else
+ ChangeElementDoIt(x, y, element_info[element].change.successor);
- ResetGfxAnimation(x, y);
- ResetRandomAnimationValue(x, y);
+ if (changing_element[element].post_change_function)
+ changing_element[element].post_change_function(x, y);
+ }
+}
- InitField(x, y, FALSE);
- if (CAN_MOVE(Feld[x][y]))
- InitMovDir(x, y);
+static void CheckTriggeredElementChange(int trigger_element, int trigger_event)
+{
+ int i, x, y;
- DrawLevelField(x, y);
+ if (!(trigger_events[trigger_element] & CH_EVENT_BIT(trigger_event)))
+ return;
- if (CAN_BE_CRUMBLED(Feld[x][y]))
- {
- int sx = SCREENX(x), sy = SCREENY(y);
- static int xy[4][2] =
- {
- { 0, -1 },
- { -1, 0 },
- { +1, 0 },
- { 0, +1 }
- };
- int i;
+ for (i=0; i<MAX_NUM_ELEMENTS; i++)
+ {
+ if (!HAS_CHANGE_EVENT(i, trigger_event) ||
+ element_info[i].change.trigger != trigger_element)
+ continue;
- for(i=0; i<4; i++)
+ for (y=0; y<lev_fieldy; y++) for (x=0; x<lev_fieldx; x++)
+ {
+ if (Feld[x][y] == i)
{
- int xx = x + xy[i][0];
- int yy = y + xy[i][1];
- int sxx = sx + xy[i][0];
- int syy = sy + xy[i][1];
-
- if (!IN_LEV_FIELD(xx, yy) ||
- !IN_SCR_FIELD(sxx, syy) ||
- !CAN_BE_CRUMBLED(Feld[xx][yy]) ||
- IS_MOVING(xx, yy))
- continue;
-
- DrawLevelField(xx, yy);
+ ChangeDelay[x][y] = 1;
+ ChangeElement(x, y);
}
}
-#endif
-
- if (changing_element[element].post_change_function)
- changing_element[element].post_change_function(x, y);
}
}
#if 1
/* this may take place after moving, so 'element' may have changed */
- if (IS_AUTO_CHANGING(element))
+ if (IS_CHANGING(x, y))
{
ChangeElement(x, y);
element = Feld[x][y];
#endif
else if (element == EL_EXPLOSION)
; /* drawing of correct explosion animation is handled separately */
- else if (IS_ANIMATED(graphic) && !IS_AUTO_CHANGING(element))
+ else if (IS_ANIMATED(graphic) && !IS_CHANGING(x, y))
DrawLevelGraphicAnimationIfNeeded(x, y, graphic);
#if 0
if (!player->active)
return;
+#if 1
+ PlaySoundLevelElementAction(jx, jy, player->element_nr, ACTION_DYING);
+#else
PlaySoundLevel(jx, jy, SND_CLASS_PLAYER_DYING);
+#endif
PlaySoundLevel(jx, jy, SND_GAME_LOSING);
player->GameOver = TRUE;
switch (element)
{
+#if 0
case EL_EMPTY:
+ PlaySoundLevelElementAction(x, y, player->element_nr, ACTION_MOVING);
+ break;
+#endif
+
+#if 0
case EL_SAND:
case EL_INVISIBLE_SAND:
case EL_INVISIBLE_SAND_ACTIVE:
case EL_SP_BUGGY_BASE:
case EL_SP_BUGGY_BASE_ACTIVATING:
RemoveField(x, y);
-#if 1
+
if (mode != DF_SNAP && element != EL_EMPTY)
{
GfxElement[x][y] = (CAN_BE_CRUMBLED(element) ? EL_SAND : element);
player->is_digging = TRUE;
}
-#endif
+
PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING);
break;
+#endif
case EL_EMERALD:
case EL_BD_DIAMOND:
case EL_PEARL:
case EL_CRYSTAL:
RemoveField(x, y);
-#if 1
+
if (mode != DF_SNAP)
{
GfxElement[x][y] = element;
player->is_collecting = TRUE;
}
-#endif
+
local_player->gems_still_needed -= (element == EL_DIAMOND ? 3 :
element == EL_PEARL ? 5 :
element == EL_CRYSTAL ? 8 : 1);
DrawText(DX_EMERALDS, DY_EMERALDS,
int2str(local_player->gems_still_needed, 3), FONT_TEXT_2);
PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_SPEED_PILL:
RemoveField(x, y);
player->move_delay_value = MOVE_DELAY_HIGH_SPEED;
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_SPEED_PILL_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
+#if 0
case EL_ENVELOPE:
Feld[x][y] = EL_EMPTY;
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_ENVELOPE_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
+#endif
case EL_EXTRA_TIME:
RemoveField(x, y);
TimeLeft += 10;
DrawText(DX_TIME, DY_TIME, int2str(TimeLeft, 3), FONT_TEXT_2);
}
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundStereo(SND_EXTRA_TIME_COLLECTING, SOUND_MIDDLE);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_SHIELD_NORMAL:
RemoveField(x, y);
player->shield_normal_time_left += 10;
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_SHIELD_NORMAL_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_SHIELD_DEADLY:
RemoveField(x, y);
player->shield_normal_time_left += 10;
player->shield_deadly_time_left += 10;
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_SHIELD_DEADLY_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_DYNAMITE:
DrawText(DX_DYNAMITE, DY_DYNAMITE, int2str(local_player->dynamite, 3),
FONT_TEXT_2);
PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_DYNABOMB_INCREASE_NUMBER:
player->dynabomb_count++;
player->dynabombs_left++;
RaiseScoreElement(EL_DYNAMITE);
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_DYNABOMB_INCREASE_NUMBER_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_DYNABOMB_INCREASE_SIZE:
RemoveField(x, y);
player->dynabomb_size++;
RaiseScoreElement(EL_DYNAMITE);
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_DYNABOMB_INCREASE_SIZE_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_DYNABOMB_INCREASE_POWER:
RemoveField(x, y);
player->dynabomb_xl = TRUE;
RaiseScoreElement(EL_DYNAMITE);
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_DYNABOMB_INCREASE_POWER_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
case EL_KEY_1:
graphic);
DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
graphic);
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_CLASS_KEY_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
}
graphic);
DrawMiniGraphicExt(window, DX_KEYS + key_nr * MINI_TILEX, DY_KEYS,
graphic);
+#if 1
+ PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+#else
PlaySoundLevel(x, y, SND_CLASS_KEY_COLLECTING);
+#endif
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
break;
}
DrawLevelField(x + dx, y + dy);
PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
+
+ CheckTriggeredElementChange(element, CE_OTHER_PUSHING);
+
break;
case EL_GATE_1:
return MF_ACTION;
break;
+#if 0
case EL_SOKOBAN_FIELD_EMPTY:
break;
+#endif
case EL_SOKOBAN_OBJECT:
case EL_SOKOBAN_FIELD_FULL:
PlaySoundLevel(x, y, SND_GAME_SOKOBAN_SOLVING);
}
+ CheckTriggeredElementChange(element, CE_OTHER_PUSHING);
+
break;
case EL_PENGUIN:
if (IS_WALKABLE(element))
{
+ PlaySoundLevelElementAction(x, y, player->element_nr, ACTION_MOVING);
break;
}
else if (IS_DIGGABLE(element))
{
RemoveField(x, y);
-#if 1
+
if (mode != DF_SNAP)
{
GfxElement[x][y] =
(CAN_BE_CRUMBLED(element) ? EL_SAND : GFX_ELEMENT(element));
player->is_digging = TRUE;
}
-#endif
+
PlaySoundLevelElementAction(x, y, element, ACTION_DIGGING);
break;
else if (IS_COLLECTIBLE(element))
{
RemoveField(x, y);
-#if 1
+
if (mode != DF_SNAP)
{
GfxElement[x][y] = element;
player->is_collecting = TRUE;
}
-#endif
+
PlaySoundLevelElementAction(x, y, element, ACTION_COLLECTING);
+ CheckTriggeredElementChange(element, CE_OTHER_COLLECTING);
+
break;
}
else if (IS_PUSHABLE(element))
DrawLevelField(x + dx, y + dy);
PlaySoundLevelElementAction(x, y, element, ACTION_PUSHING);
+ CheckTriggeredElementChange(element, CE_OTHER_PUSHING);
+
break;
}