{ CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]" },
{ CE_CLICKED_BY_MOUSE, "clicked by mouse" },
{ CE_PRESSED_BY_MOUSE, "pressed by mouse" },
+ { CE_UNDEFINED, " " },
+ { CE_HEADLINE_SPECIAL_EVENTS, "[static states]" },
+ { CE_NEXT_TO_PLAYER, "next to player" },
{ -1, NULL }
};
{ CE_HEADLINE_SPECIAL_EVENTS, "[mouse events]" },
{ CE_MOUSE_CLICKED_ON_X, "mouse clicked on" },
{ CE_MOUSE_PRESSED_ON_X, "mouse pressed on" },
+ { CE_UNDEFINED, " " },
+ { CE_HEADLINE_SPECIAL_EVENTS, "[static states]" },
+ { CE_PLAYER_NEXT_TO_X, "player next to" },
+ { CE_NEXT_TO_X, "next to" },
{ -1, NULL }
};
// set "change by direct action" selectbox help value
custom_element_change.direct_action =
- (HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
+ (HAS_CHANGE_EVENT(element, CE_NEXT_TO_PLAYER) ? CE_NEXT_TO_PLAYER :
+ HAS_CHANGE_EVENT(element, CE_TOUCHED_BY_PLAYER) ? CE_TOUCHED_BY_PLAYER :
HAS_CHANGE_EVENT(element, CE_PRESSED_BY_PLAYER) ? CE_PRESSED_BY_PLAYER :
HAS_CHANGE_EVENT(element, CE_SWITCHED_BY_PLAYER) ? CE_SWITCHED_BY_PLAYER :
HAS_CHANGE_EVENT(element, CE_SNAPPED_BY_PLAYER) ? CE_SNAPPED_BY_PLAYER :
// set "change by other element action" selectbox help value
custom_element_change.other_action =
- (HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
+ (HAS_CHANGE_EVENT(element, CE_PLAYER_NEXT_TO_X) ? CE_PLAYER_NEXT_TO_X :
+ HAS_CHANGE_EVENT(element, CE_PLAYER_TOUCHES_X) ? CE_PLAYER_TOUCHES_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_PRESSES_X) ? CE_PLAYER_PRESSES_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_SWITCHES_X) ? CE_PLAYER_SWITCHES_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_SNAPS_X) ? CE_PLAYER_SNAPS_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_DIGS_X) ? CE_PLAYER_DIGS_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_COLLECTS_X) ? CE_PLAYER_COLLECTS_X :
HAS_CHANGE_EVENT(element, CE_PLAYER_DROPS_X) ? CE_PLAYER_DROPS_X :
+ HAS_CHANGE_EVENT(element, CE_NEXT_TO_X) ? CE_NEXT_TO_X :
HAS_CHANGE_EVENT(element, CE_TOUCHING_X) ? CE_TOUCHING_X :
HAS_CHANGE_EVENT(element, CE_HITTING_X) ? CE_HITTING_X :
HAS_CHANGE_EVENT(element, CE_DIGGING_X) ? CE_DIGGING_X :
// ---------- element settings: advanced (custom elements) ------------------
// set player change event from checkbox and selectbox
+ custom_element_change_events[CE_NEXT_TO_PLAYER] = FALSE;
custom_element_change_events[CE_TOUCHED_BY_PLAYER] = FALSE;
custom_element_change_events[CE_PRESSED_BY_PLAYER] = FALSE;
custom_element_change_events[CE_SWITCHED_BY_PLAYER] = FALSE;
custom_element_change_events[CE_BY_DIRECT_ACTION];
// set other element action change event from checkbox and selectbox
+ custom_element_change_events[CE_PLAYER_NEXT_TO_X] = FALSE;
custom_element_change_events[CE_PLAYER_TOUCHES_X] = FALSE;
custom_element_change_events[CE_PLAYER_PRESSES_X] = FALSE;
custom_element_change_events[CE_PLAYER_SWITCHES_X] = FALSE;
custom_element_change_events[CE_PLAYER_DIGS_X] = FALSE;
custom_element_change_events[CE_PLAYER_COLLECTS_X] = FALSE;
custom_element_change_events[CE_PLAYER_DROPS_X] = FALSE;
+ custom_element_change_events[CE_NEXT_TO_X] = FALSE;
custom_element_change_events[CE_TOUCHING_X] = FALSE;
custom_element_change_events[CE_HITTING_X] = FALSE;
custom_element_change_events[CE_DIGGING_X] = FALSE;
static void KillPlayerUnlessEnemyProtected(int, int);
static void KillPlayerUnlessExplosionProtected(int, int);
+static void CheckNextToConditions(int, int);
+static void TestIfPlayerNextToCustomElement(int, int);
static void TestIfPlayerTouchesCustomElement(int, int);
+static void TestIfElementNextToCustomElement(int, int);
static void TestIfElementTouchesCustomElement(int, int);
static void TestIfElementHitsCustomElement(int, int, int);
different to element changes that affect other elements to change on the
whole playfield (which is handeld by CheckTriggeredElementChangeExt()) */
boolean check_trigger_element =
- (trigger_event == CE_TOUCHING_X ||
+ (trigger_event == CE_NEXT_TO_X ||
+ trigger_event == CE_TOUCHING_X ||
trigger_event == CE_HITTING_X ||
trigger_event == CE_HIT_BY_X ||
trigger_event == CE_DIGGING_X); // this one was forgotten until 3.2.3
graphic = el_act_dir2img(element, GfxAction[x][y], GfxDir[x][y]);
}
+ CheckNextToConditions(x, y);
+
if (!IS_MOVING(x, y) && (CAN_FALL(element) || CAN_MOVE(element)))
{
StartMoving(x, y);
ScreenMovDir = MV_NONE;
}
+void CheckNextToConditions(int x, int y)
+{
+ int element = Tile[x][y];
+
+ if (IS_PLAYER(x, y))
+ TestIfPlayerNextToCustomElement(x, y);
+
+ if (CAN_CHANGE_OR_HAS_ACTION(element) &&
+ HAS_ANY_CHANGE_EVENT(element, CE_NEXT_TO_X))
+ TestIfElementNextToCustomElement(x, y);
+}
+
+void TestIfPlayerNextToCustomElement(int x, int y)
+{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int trigger_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
+ };
+ int i;
+
+ if (!IS_PLAYER(x, y))
+ return;
+
+ struct PlayerInfo *player = PLAYERINFO(x, y);
+
+ if (player->is_moving)
+ return;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+ continue; // center and border element not connected
+
+ border_element = Tile[xx][yy];
+
+ CheckElementChangeByPlayer(xx, yy, border_element, CE_NEXT_TO_PLAYER,
+ player->index_bit, border_side);
+ CheckTriggeredElementChangeByPlayer(xx, yy, border_element,
+ CE_PLAYER_NEXT_TO_X,
+ player->index_bit, border_side);
+
+ /* use player element that is initially defined in the level playfield,
+ not the player element that corresponds to the runtime player number
+ (example: a level that contains EL_PLAYER_3 as the only player would
+ incorrectly give EL_PLAYER_1 for "player->element_nr") */
+
+ CheckElementChangeBySide(xx, yy, border_element, player->initial_element,
+ CE_NEXT_TO_X, border_side);
+ }
+}
+
void TestIfPlayerTouchesCustomElement(int x, int y)
{
static int xy[4][2] =
}
}
+void TestIfElementNextToCustomElement(int x, int y)
+{
+ static int xy[4][2] =
+ {
+ { 0, -1 },
+ { -1, 0 },
+ { +1, 0 },
+ { 0, +1 }
+ };
+ static int trigger_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
+ };
+ int center_element = Tile[x][y]; // should always be non-moving!
+ int i;
+
+ if (IS_MOVING(x, y) || IS_BLOCKED(x, y))
+ return;
+
+ for (i = 0; i < NUM_DIRECTIONS; i++)
+ {
+ int xx = x + xy[i][0];
+ int yy = y + xy[i][1];
+ int border_side = trigger_sides[i][1];
+ int border_element;
+
+ if (!IN_LEV_FIELD(xx, yy))
+ continue;
+
+ if (IS_MOVING(xx, yy) || IS_BLOCKED(xx, yy))
+ continue; // center and border element not connected
+
+ border_element = Tile[xx][yy];
+
+ // check for change of center element (but change it only once)
+ if (CheckElementChangeBySide(x, y, center_element, border_element,
+ CE_NEXT_TO_X, border_side))
+ break;
+ }
+}
+
void TestIfElementTouchesCustomElement(int x, int y)
{
static int xy[4][2] =