static struct ValueTextInfo options_consistency[] =
{
{ EP_CAN_EXPLODE_3X3, "can explode 3x3" },
+ { EP_CAN_EXPLODE_DYNA, "can explode 3+3" },
{ EP_CAN_EXPLODE_1X1, "can explode 1x1" },
{ EP_INDESTRUCTIBLE, "indestructible" },
{ -1, NULL }
{ CE_LEFT_BY_PLAYER, "left by player ..." },
{ CE_DROPPED_BY_PLAYER, "dropped by player" },
{ CE_SWITCHED, "switched ..." },
-#if 0
- { CE_COLLISION_ACTIVE, "hitting something ..." },
- { CE_COLLISION_PASSIVE, "hit by something ..." },
+#if 1
+ { CE_HITTING_SOMETHING, "hitting something ..." },
+ { CE_HIT_BY_SOMETHING, "hit by something ..." },
#else
- { CE_COLLISION_ACTIVE, "collision ..." },
+ { CE_HITTING_SOMETHING, "collision ..." },
#endif
{ CE_IMPACT, "impact (on something)" },
{ CE_SMASHED, "smashed (from above)" },
{ CE_OTHER_GETS_COLLECTED, "player collects" },
{ CE_OTHER_GETS_DROPPED, "player drops" },
{ CE_OTHER_IS_TOUCHING, "touching ..." },
-#if 0
- { CE_OTHER_IS_COLL_ACTIVE, "hitting ..." },
- { CE_OTHER_IS_COLL_PASSIVE, "hit by ..." },
+#if 1
+ { CE_OTHER_IS_HITTING, "hitting ..." },
+ { CE_OTHER_GETS_HIT, "hit by ..." },
#endif
{ CE_OTHER_IS_SWITCHING, "switch of ..." },
{ CE_OTHER_IS_CHANGING, "change of" },
(IS_INDESTRUCTIBLE(element) ? EP_INDESTRUCTIBLE :
CAN_EXPLODE_1X1(element) ? EP_CAN_EXPLODE_1X1 :
CAN_EXPLODE_3X3(element) ? EP_CAN_EXPLODE_3X3 :
+ CAN_EXPLODE_DYNA(element) ? EP_CAN_EXPLODE_DYNA :
custom_element.consistency);
custom_element_properties[EP_EXPLODE_RESULT] =
(IS_INDESTRUCTIBLE(element) ||
CAN_EXPLODE_1X1(element) ||
- CAN_EXPLODE_3X3(element));
+ CAN_EXPLODE_3X3(element) ||
+ CAN_EXPLODE_DYNA(element));
/* special case: sub-settings dependent from main setting */
if (CAN_EXPLODE_BY_FIRE(element))
HAS_CHANGE_EVENT(element, CE_LEFT_BY_PLAYER) ? CE_LEFT_BY_PLAYER :
HAS_CHANGE_EVENT(element, CE_DROPPED_BY_PLAYER) ? CE_DROPPED_BY_PLAYER :
HAS_CHANGE_EVENT(element, CE_SWITCHED) ? CE_SWITCHED :
- HAS_CHANGE_EVENT(element, CE_COLLISION_ACTIVE) ? CE_COLLISION_ACTIVE :
- HAS_CHANGE_EVENT(element, CE_COLLISION_PASSIVE) ? CE_COLLISION_PASSIVE :
+ HAS_CHANGE_EVENT(element, CE_HITTING_SOMETHING) ? CE_HITTING_SOMETHING :
+ HAS_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING) ? CE_HIT_BY_SOMETHING :
HAS_CHANGE_EVENT(element, CE_IMPACT) ? CE_IMPACT :
HAS_CHANGE_EVENT(element, CE_SMASHED) ? CE_SMASHED :
custom_element_change.direct_action);
HAS_CHANGE_EVENT(element, CE_OTHER_GETS_COLLECTED) ? CE_OTHER_GETS_COLLECTED :
HAS_CHANGE_EVENT(element, CE_OTHER_GETS_DROPPED) ? CE_OTHER_GETS_DROPPED :
HAS_CHANGE_EVENT(element, CE_OTHER_IS_TOUCHING) ? CE_OTHER_IS_TOUCHING :
- HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_ACTIVE) ? CE_OTHER_IS_COLL_ACTIVE :
- HAS_CHANGE_EVENT(element, CE_OTHER_IS_COLL_PASSIVE) ? CE_OTHER_IS_COLL_PASSIVE :
+ HAS_CHANGE_EVENT(element, CE_OTHER_IS_HITTING) ? CE_OTHER_IS_HITTING :
+ HAS_CHANGE_EVENT(element, CE_OTHER_GETS_HIT) ? CE_OTHER_GETS_HIT :
HAS_CHANGE_EVENT(element, CE_OTHER_IS_SWITCHING) ? CE_OTHER_IS_SWITCHING :
HAS_CHANGE_EVENT(element, CE_OTHER_IS_CHANGING) ? CE_OTHER_IS_CHANGING :
HAS_CHANGE_EVENT(element, CE_OTHER_IS_EXPLODING) ? CE_OTHER_IS_EXPLODING :
custom_element_properties[EP_INDESTRUCTIBLE] = FALSE;
custom_element_properties[EP_CAN_EXPLODE_1X1] = FALSE;
custom_element_properties[EP_CAN_EXPLODE_3X3] = FALSE;
+ custom_element_properties[EP_CAN_EXPLODE_DYNA] = FALSE;
custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] = FALSE;
custom_element_properties[EP_CAN_EXPLODE_SMASHED] = FALSE;
custom_element_properties[EP_CAN_EXPLODE_IMPACT] = FALSE;
custom_element_properties[EP_EXPLODE_RESULT];
/* special case: sub-settings dependent from main setting */
- if (custom_element_properties[EP_CAN_EXPLODE_3X3] ||
- custom_element_properties[EP_CAN_EXPLODE_1X1])
+ if (custom_element_properties[EP_CAN_EXPLODE_1X1] ||
+ custom_element_properties[EP_CAN_EXPLODE_3X3] ||
+ custom_element_properties[EP_CAN_EXPLODE_DYNA])
{
custom_element_properties[EP_CAN_EXPLODE_BY_FIRE] =
custom_element.can_explode_by_fire;
custom_element_change_events[CE_LEFT_BY_PLAYER] = FALSE;
custom_element_change_events[CE_DROPPED_BY_PLAYER] = FALSE;
custom_element_change_events[CE_SWITCHED] = FALSE;
- custom_element_change_events[CE_COLLISION_ACTIVE] = FALSE;
- custom_element_change_events[CE_COLLISION_PASSIVE] = FALSE;
+ custom_element_change_events[CE_HITTING_SOMETHING] = FALSE;
+ custom_element_change_events[CE_HIT_BY_SOMETHING] = FALSE;
custom_element_change_events[CE_IMPACT] = FALSE;
custom_element_change_events[CE_SMASHED] = FALSE;
custom_element_change_events[custom_element_change.direct_action] =
custom_element_change_events[CE_OTHER_GETS_COLLECTED] = FALSE;
custom_element_change_events[CE_OTHER_GETS_DROPPED] = FALSE;
custom_element_change_events[CE_OTHER_IS_TOUCHING] = FALSE;
- custom_element_change_events[CE_OTHER_IS_COLL_ACTIVE] = FALSE;
- custom_element_change_events[CE_OTHER_IS_COLL_PASSIVE] = FALSE;
+ custom_element_change_events[CE_OTHER_IS_HITTING] = FALSE;
+ custom_element_change_events[CE_OTHER_GETS_HIT] = FALSE;
custom_element_change_events[CE_OTHER_IS_SWITCHING] = FALSE;
custom_element_change_events[CE_OTHER_IS_CHANGING] = FALSE;
custom_element_change_events[CE_OTHER_IS_EXPLODING] = FALSE;
static void TestIfPlayerTouchesCustomElement(int, int);
static void TestIfElementTouchesCustomElement(int, int);
+static void TestIfElementHitsCustomElement(int, int, int);
static void ChangeElement(int, int, int);
static boolean CheckTriggeredElementSideChange(int, int, int, int, int);
break;
case EL_DYNAMITE_ACTIVE:
+ case EL_SP_DISK_RED_ACTIVE:
+ case EL_DYNABOMB_PLAYER_1_ACTIVE:
+ case EL_DYNABOMB_PLAYER_2_ACTIVE:
+ case EL_DYNABOMB_PLAYER_3_ACTIVE:
+ case EL_DYNABOMB_PLAYER_4_ACTIVE:
MovDelay[x][y] = 96;
break;
void DynaExplode(int ex, int ey)
{
int i, j;
+ int dynabomb_element = Feld[ex][ey];
int dynabomb_size = 1;
boolean dynabomb_xl = FALSE;
struct PlayerInfo *player;
{ 0, +1 }
};
- if (IS_ACTIVE_BOMB(Feld[ex][ey]))
+ if (IS_ACTIVE_BOMB(dynabomb_element))
{
- player = &stored_player[Feld[ex][ey] - EL_DYNABOMB_PLAYER_1_ACTIVE];
+ player = &stored_player[dynabomb_element - EL_DYNABOMB_PLAYER_1_ACTIVE];
dynabomb_size = player->dynabomb_size;
dynabomb_xl = player->dynabomb_xl;
player->dynabombs_left++;
Explode(x, y, EX_PHASE_START, EX_CENTER);
break;
default:
- if (CAN_EXPLODE_1X1(element))
+ if (CAN_EXPLODE_DYNA(element))
+ DynaExplode(x, y);
+ else if (CAN_EXPLODE_1X1(element))
Explode(x, y, EX_PHASE_START, EX_CENTER);
else
Explode(x, y, EX_PHASE_START, EX_NORMAL);
int move_pattern = element_info[element].move_pattern;
int newx, newy;
+ Moving2Blocked(x, y, &newx, &newy);
+
#if 1
if (IS_PUSHABLE(element) && JustBeingPushed(x, y))
return;
return;
#endif
+#if 1
+ if (game.engine_version >= VERSION_IDENT(3,0,9,0) &&
+ WasJustMoving[x][y] && IN_LEV_FIELD(newx, newy) &&
+ (Feld[newx][newy] == EL_BLOCKED || IS_PLAYER(newx, newy)))
+ {
+#if 0
+ printf("::: element %d '%s' WasJustMoving %d [%d, %d, %d, %d]\n",
+ element, element_info[element].token_name,
+ WasJustMoving[x][y],
+ HAS_ANY_CHANGE_EVENT(element, CE_HITTING_SOMETHING),
+ HAS_ANY_CHANGE_EVENT(element, CE_HIT_BY_SOMETHING),
+ HAS_ANY_CHANGE_EVENT(element, CE_OTHER_IS_HITTING),
+ HAS_ANY_CHANGE_EVENT(element, CE_OTHER_GETS_HIT));
+#endif
+
+ TestIfElementHitsCustomElement(x, y, MovDir[x][y]);
+
+ if (Feld[x][y] != element) /* element has changed */
+ return;
+ }
+#endif
+
#if 0
#if 0
if (element == EL_SPRING && MovDir[x][y] == MV_DOWN)
int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
int newx = x + dx, newy = y + dy;
+#if 0
int nextx = newx + dx, nexty = newy + dy;
+#endif
boolean pushed = Pushed[x][y];
MovPos[x][y] += getElementMoveStepsize(x, y);
ChangeElement(newx, newy, ChangePage[newx][newy]);
#endif
+#if 1
+
+ TestIfElementHitsCustomElement(newx, newy, direction);
+
+#else
+
if (!IN_LEV_FIELD(nextx, nexty) || !IS_FREE(nextx, nexty))
{
int hitting_element = Feld[newx][newy];
/* !!! fix side (direction) orientation here and elsewhere !!! */
CheckElementSideChange(newx, newy, hitting_element,
- direction, CE_COLLISION_ACTIVE, -1);
+ direction, CE_HITTING_SOMETHING, -1);
#if 0
if (IN_LEV_FIELD(nextx, nexty))
int i;
CheckElementSideChange(nextx, nexty, touched_element,
- opposite_direction, CE_COLLISION_PASSIVE, -1);
+ opposite_direction, CE_HIT_BY_SOMETHING, -1);
if (IS_CUSTOM_ELEMENT(hitting_element) &&
- HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_COLL_ACTIVE))
+ HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
{
for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
{
&element_info[hitting_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_ACTIVE) &&
+ change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
change->sides & touched_side &&
change->trigger_element == touched_element)
{
CheckElementSideChange(newx, newy, hitting_element,
- CH_SIDE_ANY, CE_OTHER_IS_COLL_ACTIVE, i);
+ CH_SIDE_ANY, CE_OTHER_IS_HITTING, i);
break;
}
}
}
if (IS_CUSTOM_ELEMENT(touched_element) &&
- HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_IS_COLL_PASSIVE))
+ HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
{
for (i = 0; i < element_info[touched_element].num_change_pages; i++)
{
&element_info[touched_element].change_page[i];
if (change->can_change &&
- change->events & CH_EVENT_BIT(CE_OTHER_IS_COLL_PASSIVE) &&
+ change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
change->sides & hitting_side &&
change->trigger_element == hitting_element)
{
CheckElementSideChange(nextx, nexty, touched_element,
- CH_SIDE_ANY, CE_OTHER_IS_COLL_PASSIVE, i);
+ CH_SIDE_ANY, CE_OTHER_GETS_HIT, i);
break;
}
}
}
#endif
}
+#endif
TestIfPlayerTouchesCustomElement(newx, newy);
TestIfElementTouchesCustomElement(newx, newy);
CE_OTHER_IS_TOUCHING, center_element_change_page);
}
+void TestIfElementHitsCustomElement(int x, int y, int direction)
+{
+ int dx = (direction == MV_LEFT ? -1 : direction == MV_RIGHT ? +1 : 0);
+ int dy = (direction == MV_UP ? -1 : direction == MV_DOWN ? +1 : 0);
+ int hitx = x + dx, hity = y + dy;
+ int hitting_element = Feld[x][y];
+
+ if (IN_LEV_FIELD(hitx, hity) && IS_FREE(hitx, hity))
+ return;
+
+ CheckElementSideChange(x, y, hitting_element,
+ direction, CE_HITTING_SOMETHING, -1);
+
+ if (IN_LEV_FIELD(hitx, hity))
+ {
+ static int opposite_directions[] =
+ {
+ MV_RIGHT,
+ MV_LEFT,
+ MV_DOWN,
+ MV_UP
+ };
+ int move_dir_bit = MV_DIR_BIT(direction);
+ int opposite_direction = opposite_directions[move_dir_bit];
+ int hitting_side = direction;
+ int touched_side = opposite_direction;
+ int touched_element = MovingOrBlocked2Element(hitx, hity);
+ boolean object_hit = (!IS_MOVING(hitx, hity) ||
+ MovDir[hitx][hity] != direction ||
+ ABS(MovPos[hitx][hity]) <= TILEY / 2);
+
+ object_hit = TRUE;
+
+ if (object_hit)
+ {
+ int i;
+
+ CheckElementSideChange(hitx, hity, touched_element,
+ opposite_direction, CE_HIT_BY_SOMETHING, -1);
+
+ if (IS_CUSTOM_ELEMENT(hitting_element) &&
+ HAS_ANY_CHANGE_EVENT(hitting_element, CE_OTHER_IS_HITTING))
+ {
+ for (i = 0; i < element_info[hitting_element].num_change_pages; i++)
+ {
+ struct ElementChangeInfo *change =
+ &element_info[hitting_element].change_page[i];
+
+ if (change->can_change &&
+ change->events & CH_EVENT_BIT(CE_OTHER_IS_HITTING) &&
+ change->sides & touched_side &&
+ change->trigger_element == touched_element)
+ {
+ CheckElementSideChange(x, y, hitting_element,
+ CH_SIDE_ANY, CE_OTHER_IS_HITTING, i);
+ break;
+ }
+ }
+ }
+
+ if (IS_CUSTOM_ELEMENT(touched_element) &&
+ HAS_ANY_CHANGE_EVENT(touched_element, CE_OTHER_GETS_HIT))
+ {
+ for (i = 0; i < element_info[touched_element].num_change_pages; i++)
+ {
+ struct ElementChangeInfo *change =
+ &element_info[touched_element].change_page[i];
+
+ if (change->can_change &&
+ change->events & CH_EVENT_BIT(CE_OTHER_GETS_HIT) &&
+ change->sides & hitting_side &&
+ change->trigger_element == hitting_element)
+ {
+ CheckElementSideChange(hitx, hity, touched_element,
+ CH_SIDE_ANY, CE_OTHER_GETS_HIT, i);
+ break;
+ }
+ }
+ }
+ }
+ }
+}
+
void TestIfGoodThingHitsBadThing(int good_x, int good_y, int good_move_dir)
{
int i, kill_x = -1, kill_y = -1;
boolean DropElement(struct PlayerInfo *player)
{
int jx = player->jx, jy = player->jy;
- int old_element;
+ int old_element = Feld[jx][jy];
int new_element;
+ /* check if player is active, not moving and ready to drop */
if (!player->active || player->MovPos || player->drop_delay > 0)
return FALSE;
- old_element = Feld[jx][jy];
-
/* check if player has anything that can be dropped */
if (player->inventory_size == 0 && player->dynabombs_left == 0)
return FALSE;
if (old_element != EL_EMPTY)
Back[jx][jy] = old_element; /* store old element on this field */
-
-
- /* !!! CHANGE !!! CHANGE !!! */
-
-#if 0
- MovDelay[jx][jy] = 96;
-#endif
-
- /* !!! CHANGE !!! CHANGE !!! */
-
-
-
ResetGfxAnimation(jx, jy);
ResetRandomAnimationValue(jx, jy);
if (player->inventory_size > 0)
{
- new_element = player->inventory_element[--player->inventory_size];
+ player->inventory_size--;
+ new_element = player->inventory_element[player->inventory_size];
- Feld[jx][jy] = (new_element == EL_DYNAMITE ? EL_DYNAMITE_ACTIVE :
- new_element == EL_SP_DISK_RED ? EL_SP_DISK_RED_ACTIVE :
- new_element);
+ if (new_element == EL_DYNAMITE)
+ new_element = EL_DYNAMITE_ACTIVE;
+ else if (new_element == EL_SP_DISK_RED)
+ new_element = EL_SP_DISK_RED_ACTIVE;
+
+ Feld[jx][jy] = new_element;
DrawText(DX_DYNAMITE, DY_DYNAMITE,
int2str(local_player->inventory_size, 3), FONT_TEXT_2);
else /* player is dropping a dyna bomb */
{
player->dynabombs_left--;
+ new_element = EL_DYNABOMB_PLAYER_1_ACTIVE + player->index_nr;
- Feld[jx][jy] =
- EL_DYNABOMB_PLAYER_1_ACTIVE + (player->element_nr - EL_PLAYER_1);
+ Feld[jx][jy] = new_element;
if (IN_SCR_FIELD(SCREENX(jx), SCREENY(jy)))
DrawGraphicThruMask(SCREENX(jx), SCREENY(jy), el2img(Feld[jx][jy]), 0);
PlayLevelSoundAction(jx, jy, ACTION_DROPPING);
-
- MovDelay[jx][jy] = 96;
}
#if 1
- InitField(jx, jy, FALSE);
- if (CAN_MOVE(Feld[jx][jy]))
- InitMovDir(jx, jy);
+
+ if (Feld[jx][jy] == new_element) /* uninitialized unless CE change */
+ {
+ InitField(jx, jy, FALSE);
+ if (CAN_MOVE(Feld[jx][jy]))
+ InitMovDir(jx, jy);
+ }
new_element = Feld[jx][jy];
if (IS_CUSTOM_ELEMENT(new_element) && CAN_MOVE(new_element) &&
element_info[new_element].move_pattern == MV_PROJECTILE)
{
+ int move_stepsize = element_info[new_element].move_stepsize;
int direction, dx, dy, nextx, nexty;
if (element_info[new_element].move_direction_initial == MV_NO_MOVING)
if (IN_LEV_FIELD(nextx, nexty) && IS_FREE(nextx, nexty))
{
- InitMovingField(jx, jy, MovDir[jx][jy]);
+#if 0
+ WasJustMoving[jx][jy] = 3;
+#else
+ InitMovingField(jx, jy, direction);
ContinueMoving(jx, jy);
+#endif
}
else
{
Changed[jx][jy] = 0; /* allow another change */
+
+#if 1
+ TestIfElementHitsCustomElement(jx, jy, direction);
+#else
CheckElementSideChange(jx, jy, new_element,
- direction, CE_COLLISION_ACTIVE, -1);
+ direction, CE_HITTING_SOMETHING, -1);
+#endif
}
+
+ player->drop_delay = 2 * TILEX / move_stepsize + 1;
}
+#if 0
+ player->drop_delay = 8 + 8 + 8;
#endif
- player->drop_delay = 8 + 8 + 8;
+#endif